feat(rpgkit): v0.1.3 — global install, home-side runtime store, hook & scripts refactor#56
feat(rpgkit): v0.1.3 — global install, home-side runtime store, hook & scripts refactor#56HuYaSen wants to merge 29 commits into
Conversation
Ship scripts/ and templates/commands/ as packaged assets inside the wheel
(rpgkit_cli/core_pack/) via hatch force-include, so 'rpgkit init' works
offline (air-gapped / corporate-proxy / enterprise environments).
Replace the build-time <AI_CLI_CMD> placeholder substitution with a
runtime resolver in scripts/common/llm_client.py that reads .rpgkit/config.toml
per workspace. This decouples scripts from the chosen AI agent and is
forward-compatible with running scripts from a shared installation in
the future.
Key changes:
* pyproject.toml: bump to 0.1.3 + force-include scripts/ and templates/commands/
* src/rpgkit_cli/_assets.py (new): importlib.resources access to core_pack
* src/rpgkit_cli/__init__.py:
- _AI_TO_CLI_CMD authoritative map (mirrors release-zip CI)
- _install_from_bundle() + _materialise_commands_for_agent()
- _write_workspace_config() materialises .rpgkit/config.toml
- .rpgkit/.source marker so 'rpgkit update' honours the user's channel
- download_and_extract_template() dispatches: bundle by default, falls
back to legacy release zip when --legacy-download is passed (or --pre,
or when the bundle is unavailable / --script ps is requested)
- 'rpgkit init': new --legacy-download flag
- 'rpgkit update': new --legacy-download and --pull flags
- _detect_install_method() + _upgrade_command() power --pull
* scripts/common/llm_client.py:
- _load_ai_cli_cmd() with P1-P4 priority chain (constructor arg → env var
→ workspace config.toml → release-zip-baked-in fallback)
- detect_agent_type() now resolves at call time, not module import
- LLMClient.__init__ tolerates empty tool; generate() raises lazily with
an actionable error message when the workspace is unconfigured
* scripts/__init__.py (new, empty): marker for hatch force-include
* .gitignore: un-ignore .rpgkit/config.toml so teams can commit the
workspace default
Behavioural guarantees (7a route):
* Scripts still land under <workspace>/.rpgkit/scripts/
* No slash-command template was modified
* MCP config generation unchanged
* Hook installation logic unchanged
* All 27 pipeline scripts unchanged
* No new tests; the 11 pre-existing test failures on main remain unchanged
Design notes live in plans/01-package-bundle-and-ai-config.md (gitignored;
local reference only).
…/config.toml * README: add Updating section explaining the three update flavours (default offline, --pull, --legacy-download) + note that bundle mode is the new default since 0.1.3. * docs/cli-reference: list --legacy-download (init + update) and --pull (update), plus a Provisioning sources table summarising the two channels and the .rpgkit/.source marker. * docs/configuration: new Workspace Configuration section covering .rpgkit/config.toml, the P1-P4 resolution priority chain, and the authoritative --ai → ai_cli_cmd mapping. * docs/project-structure: surface config.toml and .source in the workspace tree.
Eight issues surfaced during a second-pass review of the bundle / config work landed in commit 1c47c1d. All fixes are local to src/rpgkit_cli/__init__.py; no scripts, templates, hooks, or MCP logic were touched. 1. _detect_install_method() reordered editable detection before uv. Previously an editable install placed in a uv-managed venv would be reported as 'uv' and 'rpgkit update --pull' would run 'uv tool upgrade' instead of telling the user to git pull. 2. --script ps fallback notice was guarded by 'if tracker is None and verbose:' which is never True in the actual init()/update() call path, so users never saw the message. Emit it through the tracker as a skipped 'ps-fallback' step so it shows up in the live status report. 3. --pull self-upgrade is now executed BEFORE constructing rich.Live instead of from inside the Live context. Mixing subprocess output (and the subsequent os.execvp) with Live's terminal control left a corrupted screen state. 4. --pull no longer continues the update flow with stale in-memory code after upgrading the wheel. On successful upgrade we os.execvp() the rpgkit binary (with --pull stripped) so the new logic runs against the freshly-installed core_pack. 5. .rpgkit/.source provisioning marker is now written by whichever path actually ran (_install_from_bundle for bundle, _download_and_extract_release_zip for legacy zip). The previous init/update logic decided based on flag state, which gave wrong results in the --script ps fallback case (bundle attempt → ps fallback to legacy zip → marker incorrectly left absent). 6. Removed redundant _install_command_templates_from_bundle wrapper. _materialise_commands_for_agent now also produces the rpgkit.<name>.md filename for unknown agents, matching the supported-agent paths. 7. _install_from_bundle no longer re-adds tracker step keys ('download', 'cleanup') that init()/update() had already registered; it just transitions them with .skip() to keep the live status report coherent. 8. Update()'s 'effective_legacy' boolean was the OR of three terms one of which redundantly re-checked another flag, followed by a no-op reassignment. Simplified to a single OR. No behaviour change for the offline-bundle happy path; smoke tests continue to show 883 passed / 11 pre-existing failures (no regression).
Three more bugs surfaced in a deeper review of the 0.1.3 plumbing. All fixes are local; existing test suite still shows the same 11 pre-existing failures from main (no regression). 1. .rpgkit/config.toml was still gitignored in user workspaces. 1c47c1d but the gitignore content that rpgkit init/update WRITES into user workspaces (_GITIGNORE_RPGKIT_COMMON) did not. As a result, the config a team would want to commit was still hidden from git. Fixed by adding the un-ignore line to the embedded block. 2. LLMClient.generate_with_memory() silently swallowed the 'AI CLI not configured' RuntimeError and returned None. The caller then sees a generic LLM failure with no hint to run rpgkit init. Now pre-validates self.tool and re-raises the configuration error; genuine LLM-call failures continue to surface as None as before. 3. P4 (release-zip baked-in fallback) was broken by sed. The new resolver introduced two module-level constants: _PLACEHOLDER_LITERAL = '<AI_CLI_CMD>' _BAKED_IN_VALUE = _PLACEHOLDER_LITERAL The release-zip CI runs 'sed s|<AI_CLI_CMD>|<cmd>|g' on every script file, which would have rewritten BOTH constants to the same substituted value, making the _BAKED_IN_VALUE != _PLACEHOLDER_LITERAL guard tautologically false and the P4 fallback effectively dead. Now _PLACEHOLDER_LITERAL is built with string concatenation ("<" + "AI_CLI_CMD" + ">") so sed leaves it alone and the guard does the right thing on legacy-download workspaces. Plus: * Tightened --pre help text in both init() and update() to say 'Implies --legacy-download', matching the new dispatcher behaviour. * Updated the two gitignore-related tests in tests/test_hooks_install.py to count exact lines rather than substrings — the embedded block now contains both '.rpgkit/' and '!.rpgkit/config.toml', so the previous substring count would always be 2. This is the only test edit introduced by the 0.1.3 work.
… hints
Previously `rpgkit version` listed both the local CLI version and the
latest GitHub release tag but did NOT tell the user which was which or
whether action was needed. Combined with `uv tool upgrade rpgkit-cli`
silently printing 'Nothing to upgrade' (with no version context), users
had to mentally diff two version strings to figure out their status.
Now the output adds:
* 'Latest Release' (was 'Template Version' — clearer naming).
* 'Status' row with one of:
- [green]up to date[/] local == remote
- [yellow]outdated → X.Y.Z[/] local < remote
- [cyan]ahead of release (X.Y.Z)[/] local > remote (dev build)
- [yellow]offline[/] GitHub query failed
* When relevant, a second panel ('Upgrade tip') with actionable advice:
- outdated → list of upgrade commands (uv / pipx / pip) + reminder
to follow up with `rpgkit update` in each existing workspace.
- ahead → reassure the user nothing is broken (dev build).
- offline → show the underlying error and suggest retrying online.
Version comparison goes through packaging.version.Version so PEP 440
pre-release / dev / post suffixes (eg 0.1.4.dev0, 0.1.3rc1, 0.1.3.post1)
sort correctly. Falls back to plain comparison when packaging is
unavailable.
No new dependencies (packaging ships with setuptools / pip).
Test baseline unchanged: 883 passed, 11 pre-existing failures.
Plan 02 Batch A: build dispatcher infrastructure and convert MCP + hooks to use the globally-installed rpgkit CLI rather than workspace-local script copies. - Add 'rpgkit script <relpath> [args...]' dispatcher with --list/--where. - Add 'rpgkit-mcp' console script (rpgkit_cli.entries:mcp_main). - _assets: add list_scripts() + dev-mode fallback to repo scripts/. - mcp_server.py: extract main() function for console-script reuse. - Rewrite MCP config writer: command='rpgkit-mcp', no absolute paths. - Rewrite pre-commit / post-merge / post-commit / Claude SessionStart hooks to invoke 'rpgkit script update_graphs.py ...', with a PATH fallback line for GUI-launched commits. - PATH self-check at end of 'rpgkit init' (warns when rpgkit-mcp missing from PATH). - Update test_hooks_install.py assertions for the new contract. - Batch B (templates + drop workspace scripts copy) to follow. Refs: plans/02-route-scripts-via-cli.md (local)
…-1/2)
Plan 02 Batch B step 1+2: introduce cmd_for() helper and rewrite all
hardcoded 'python3 .rpgkit/scripts/X.py' references inside the
pipeline scripts.
- common/paths.py: re-anchor SCRIPTS_DIR to Path(__file__).parent.parent
so it points at the actual filesystem location regardless of whether
scripts are run from a workspace copy (pre-0.1.3) or the packaged
rpgkit_cli/core_pack/scripts/ dir (post-0.1.3).
- common/paths.py: add cmd_for(relpath) helper returning the canonical
'rpgkit script <relpath>' invocation.
- Sweep 12 script files: replace 21 hardcoded invocation strings in
next_action messages, inter-script spawn commands, and error hints
with cmd_for() calls. Files: init_codebase.py, smoke_test.py,
check_skeleton.py, check_code_gen.py, run_batch.py, update_graphs.py,
code_gen/result_builders.py, rpg_encoder/run_update_rpg.py,
rpg_encoder/run_encode.py, rpg_edit/{validate,review,code}.py.
Workspace .rpgkit/scripts/ copy still happens (templates not yet
converted); next commit removes both.
…/4/5) Plan 02 Batch B steps 3-5: complete the migration to globally-installed scripts. - Rewrite 13 slash-command templates: 'python3 .rpgkit/scripts/X.py' → 'rpgkit script X.py' (64 substitutions via sed). - _install_from_bundle: stop copying scripts to .rpgkit/scripts/; only materialise slash-command templates and the .source marker. - _download_and_extract_release_zip (legacy --legacy-download): strip the extracted .rpgkit/scripts/ after extraction; legacy channel now delivers commands only (D7). - ensure_executable_scripts: collapse to a deprecated no-op stub. - .gitignore: drop the obsolete .rpgkit/scripts/**/__pycache__/ rule (covered by the blanket .rpgkit/ ignore anyway). After init the workspace contains only data/, logs/, config.toml, .source — no scripts/ dir. All pipeline scripts run from the wheel via 'rpgkit script <name>'. Test baseline unchanged (11 failed / 883 passed, all pre-existing failures).
Plan 02 Batch B step 8: rewrite documentation to match the new contract. - docs/cli-reference.md: add full 'rpgkit script' section (synopsis, options --list/--where, examples, rpgkit-mcp companion mention). - docs/commands.md: rewrite 13 inline references from '.rpgkit/scripts/X.py' → 'rpgkit script X.py'. - docs/project-structure.md: drop the obsolete .rpgkit/scripts/ subtree from the workspace layout diagram; add a callout explaining the packaged-scripts model. Plan 02 self-repo agent prompt regeneration (Batch B-6) is gitignored in this repo so changes there are not part of this commit; the next 'rpgkit init/update' on the RPG-Kit dev workspace picks up the new template content automatically.
Audit pass on Plan 02 surface; address loose ends.
- templates/commands: sed prose backtick refs (5 files, 5 sites) —
'Run the script `.rpgkit/scripts/X.py`' was missed by the previous
python3-prefix sed pass and would mislead AI agents into trying a
filesystem path that no longer exists.
- scripts/**.py: change all 'cmd_for("X.py")' inside f-strings to
'cmd_for(\'X.py\')'. PEP 701 nested same-kind quotes work on
Python 3.12+ but trip many syntax highlighters / linters and are
fragile. Single quotes inside the f-string is the safer style.
- scripts/mcp_server.py: refresh module docstring to mention the
rpgkit-mcp console-script entry instead of the legacy workspace
path.
- scripts/feature_spec_to_json.py: usage docstring uses 'rpgkit
script' form.
- src/rpgkit_cli/__init__.py: drop the deprecated
'ensure_executable_scripts' no-op (no remaining callers); update
one stale prose reference in _has_python_files docstring.
E2E + full test suite pass at baseline (11 pre-existing failures,
883 passing).
Two follow-ups from running 'rpgkit init .' on a real workspace: 1. Optional initial-encode kickoff (the 'Run the encoder now?' prompt at end of 'rpgkit init') still resolved the encoder via '$workspace/.rpgkit/scripts/rpg_encoder/run_encode.py'. After plan 02 the workspace no longer has that subtree, so the kickoff always printed 'Encoder script not found' and aborted. Fall back to '_assets.scripts_dir()' (the packaged location) when the workspace copy is absent. 2. The VS Code 'folderOpen' task in .vscode/tasks.json was still invoking sys.executable against the workspace 'update_graphs.py' path. Rewrite to 'command: rpgkit, args: [script, update_graphs.py, status]' so it works against the globally-installed CLI. Updated test_install_copilot_hooks_writes_folder_open_task assertions for the new task shape.
…strings)
Full audit pass turned up a few more cases that needed updating after
'rpgkit init .' on a real workspace exposed gaps.
Functional bugs:
- scripts/rpg_edit/review.py: the review-stage prompt embedded
'$WORKSPACE_ROOT/.rpgkit/scripts/tools/{browser,gui}.py' paths
into the LLM instructions. Since the workspace no longer hosts
the scripts dir, the AI would invoke a non-existent file. Switch
to 'cmd_for("tools/browser.py")' / 'cmd_for("tools/gui.py")'
and drop the leading 'python' from each invocation in the prompt
template (it's already rooted by 'rpgkit script').
- scripts/code_gen/batch_prompts.py: the sub-agent guard-rail rule
'You MUST NOT run any .rpgkit/scripts/*.py commands' now reads
'run any rpgkit script ... or rpgkit-mcp commands' so the rule
still covers what it intended to prohibit.
Docstring / comment cleanup:
- scripts/rpg_edit/__init__.py: module docstring example.
- scripts/update_graphs.py: post-commit lock comment example.
- Removed unused 'WORKSPACE_ROOT' import from rpg_edit/review.py.
Tests baseline preserved (11 pre-existing failures, 883 passing).
Every successful (or failed) 'rpgkit script <X>' invocation now
commits the current state of .rpgkit/ to a dedicated repo at
.rpgkit/.git/, giving users (and the e2e test runner) a free
'git log' / 'git diff' between any two pipeline stages.
New module rpgkit_cli._inner_git holds all the logic:
- find_workspace_root() walk up from cwd for .rpgkit/
- ensure_inner_git() create .rpgkit/.git + initial commit
- auto_commit_after_script() snapshot after a 'rpgkit script' call
- categorise_script() derive [<category>] prefix
- should_skip_script() skip check_* / *_validation* / mcp_server
- snapshot_count() for 'rpgkit version' display
CLI surface:
- rpgkit init gains --no-rpgkit-git (default OFF = inner git ON)
- rpgkit update gains --no-rpgkit-git; backfills inner git for
pre-plan-03 workspaces, leaves pre-existing repos
untouched.
- rpgkit script auto-commits after the child exits; commit
message: '[<category>] <relpath> <args>' with a
' — FAILED (exit N)' suffix when the child failed.
- rpgkit version gains 'Inner git: N snapshots' line when present.
Commit identity uses per-call -c user.email/user.name (rpgkit-snapshot
<rpgkit@local>) — never writes to global git config. Concurrent locks
(post-commit hook background worker) trigger a 1s retry then silent
skip; the next successful commit folds in any missed changes.
Plan: plans/03-auto-snapshot-inner-git.md (local)
Test baseline preserved (11 pre-existing failures, 883 passing).
The GitHub Copilot CLI (`copilot`) does NOT read workspace-local
`.vscode/mcp.json`; it only reads `~/.copilot/mcp-config.json` (or
accepts inline JSON via `--additional-mcp-config`).
To make `copilot` find `rpg-tools` automatically in any
rpgkit-initialised workspace, we now register the server globally on
`rpgkit init --ai copilot` and `rpgkit update --ai copilot`. This is
safe because rpgkit-mcp is cwd-aware (walks up for rpg.json) and
stateless across workspaces — one global registration serves every
workspace the user cd-s into. In workspaces without rpg.json the server
starts in degraded mode and tool calls return a rpg_unavailable hint
instructing the user to run /rpgkit.encode.
Safety rules baked into _register_copilot_cli_global_mcp():
- No-op when in-sync: if the file already contains exactly our
desired entry, we don't touch it (no mtime bump, no .bak).
- Refuse to wipe a malformed config: file exists but isn't valid
JSON -> abort with a clear error; user fixes it or passes
--no-copilot-cli-mcp. Without this a stray comma would let us
silently drop every non-rpg-tools server.
- Atomic write: serialise to mcp-config.json.tmp then os.replace()
into place, so Ctrl-C mid-write can't leave the file half-written.
- Respect user-customised entries: existing rpg-tools whose
`command` is not `rpgkit-mcp` is left alone (user has pointed it
elsewhere, e.g. a dev checkout).
- One-shot .bak: only created on the first modification we actually
perform; never on no-op runs, never overwritten.
New flag: --no-copilot-cli-mcp on both `init` and `update` to opt out.
Wired into the StepTracker plan so the tree output shows the step.
Verified against five scenarios (fresh, idempotent no-op, preserve
other-servers + update outdated entry, refuse malformed JSON, respect
user-customised command) — all PASS, no stray .tmp files.
VS Code Copilot's custom-agents schema (the rename of the old
chatmode format) no longer recognises the `mode:` frontmatter field.
Three of our prompt templates still carried `mode: agent` from the
chatmode era, producing this on load:
Custom Agents — The following agents have warnings:
• rpgkit.code_gen.agent.md: unknown field ignored: mode
• rpgkit.design_interfaces.agent.md: unknown field ignored: mode
• rpgkit.plan_tasks.agent.md: unknown field ignored: mode
Fix: replace `mode: agent` with the canonical `name:` field so
the three files match the frontmatter convention already used by
the other ten prompts (`name:` + `description:`).
Files: code_gen.md, design_interfaces.md, plan_tasks.md.
No behavioural change — `mode:` was already being silently ignored;
this just clears the warnings so the diagnostics view stays clean.
Ref: https://code.visualstudio.com/docs/copilot/customization/custom-agents#_are-custom-agents-different-from-chat-modes
Per-workspace data, logs and the inner-git snapshot repo now live at ~/.rpgkit/workspaces/<hash>/ (hash = sha256(realpath(workspace))[:12]) so the user's repository stays clean. Only the workspace marker (.rpgkit/config.toml) and small user-facing reports (.rpgkit/reports/) stay in the workspace; rpg.html lives there too so it can be browsed next to the code. Scripts: - common/paths.py: derive DATA_DIR/LOGS_DIR/RPG_FILE/RPG_HTML_FILE from the new home-side helpers. RPG_HTML_FILE points to REPORTS_DIR. - feature_spec_to_json.py defaults to FEATURE_SPEC_FILE; the encoder, update_graphs.py and rpg_edit/* read and write through the new common.paths constants. - New common/rpg_io.py with atomic_write_rpg and safe_load_rpg. When rpg.json is truncated or invalid, scan the inner-git snapshot repo for the most recent valid copy, rewrite atomically and continue. - New rpg_edit/save_plan.py so prompts can pipe EditPlan JSON into the home-side data store via the CLI rather than the Write tool. - init_codebase.py: drop dead 'scripts = get_scripts_dir()' assignments and the now-unused import. Prompt templates & docs: - README.md and docs/* describe the new layout and point users at 'rpgkit view-graph' to open rpg.html without computing the hash. - templates/commands/*.md drop shell '> .rpgkit/logs/X.log 2>&1' redirections (scripts log internally) and remove every reference to '~/.rpgkit/workspaces/<hash>/' from agent-facing prompts. The agent only reads stdout, and '<hash>' was often misread as a literal placeholder. Tests: - New tests/test_storage.py: workspace id, meta read/write, path helpers, WorkspaceMetaMismatch guard. - New tests/test_rpg_io.py: atomic-write, unicode roundtrip, inner-git restore on corruption. - test_e2e.py: assertion no longer hard-codes '.rpgkit/data/'. Comment-style cleanup: - Drop internal codename references (Plan B, Plan 03, plan A2/A3, plan B3/B4, plan E2/E3, plans/*.md, plan §2.5). - Drop emphasis adverbs (deliberately, the single most, carve-out, Defensive:), version narration (pre-0.1.3, Pre-v4) and caps emphasis (MUST NOT, do NOT) from docstrings and inline comments.
src/rpgkit_cli/_storage.py (new):
- workspace_id = sha256(realpath(workspace))[:12]; helpers for home
dir, data/, logs/, inner-git/, reports/, meta.toml.
- ensure_workspace_storage creates the layout idempotently and raises
WorkspaceMetaMismatch on a hash collision against a different
recorded workspace path.
- find_workspace_root_from walks up from cwd, but only accepts a
candidate when its home-side dir exists AND meta.workspace_path
matches. Stale .rpgkit/config.toml markers (workspace deleted,
moved, or renamed) are skipped instead of being silently adopted.
src/rpgkit_cli/__init__.py:
- Wire init/update through ensure_workspace_storage; logs and the
inner-git dir are home-side, reports stay workspace-side.
- 'rpgkit version' prints the resolved workspace path, data/logs
dirs and inner-git snapshot count, tagged '(not created yet)' when
home-side storage hasn't been bootstrapped.
- New hidden 'rpgkit hook <name>' command. The on-disk hooks under
.git/hooks/ are now 3-line stubs that exec into this command, so
path resolution, logging, locking and the detached background
worker live in one Python place; upgrading the CLI takes effect
without reinstalling hooks.
- post-commit: phase-1 'update_graphs.py sync' foreground, phase-2
'update_graphs.py update-rpg --json' detached via
Popen(start_new_session=True), with an mkdir-based directory lock
and 60-min stale-lock recovery.
- pre-commit and post-merge: same dispatcher, sync only.
src/rpgkit_cli/_inner_git.py:
- Set RPGKIT_HOOK / RPGKIT_HOOK_SHA in 'rpgkit hook' so inner-git
snapshot messages tag automated commits:
[hook:post-commit @ a1b2c3d] update-rpg --json
[hook:pre-commit @ 9f8e7d6] sync --staged-only
[decoder] feature_build.py --mode step1 (manual)
- _INNER_GIT_IGNORE now only excludes logs/copilot/ (MB-scale LLM
session traces). Other per-stage logs are tracked so users can
'git -C ~/.rpgkit/workspaces/<hash> log -p logs/<stage>.log' to
inspect how a stage's output evolved across snapshots.
- _ensure_gitignore_current rewrites the inner-git .gitignore before
each commit if it has drifted from the current policy, so existing
inner repos upgrade silently on the next snapshot.
src/rpgkit_cli/_assets.py, entries.py:
- Comment-style cleanup (drop emphasis adverbs, internal codenames,
version narration).
When the outer repo's git commit runs a hook, git exports GIT_INDEX_FILE pointing at the outer .git/index.lock. If we leak that into the inner-git subprocess, the inner-git add -A writes entries (from $HOME/.rpgkit/...) into the outer index.lock, corrupting the outer commit ("error: invalid object ... Error building trees"). Strip GIT_INDEX_FILE / GIT_DIR / GIT_WORK_TREE / GIT_OBJECT_DIRECTORY before invoking the inner-git so the two repos stay isolated.
Several scripts logged absolute paths like '/home/user/proj/data/X.json' on success. When run via 'rpgkit script' under an LLM agent, those paths reveal the workspace layout (and home-side .rpgkit/ paths) to the agent, which then tries to access them and fails. Switch all 'saved to: {path}' messages to use path.name so stdout stays workspace-independent. Files touched: build_data_flow, build_skeleton, design_base_classes, design_interfaces, feature_spec_to_json, plan_tasks, summary_skeleton.
Per-stage script invocations now persist their stdout into the workspace logs directory (resolved via _storage.workspace_logs_dir). If the home-side dir doesn't exist yet (rpgkit init hasn't run), fall back to the previous behaviour (no log, direct passthrough).
Claude writes session traces under $HOME/.claude/projects/<hash>/sessions/ which is outside the rpgkit workspace. The metadata bookkeeping line called Path.relative_to(workspace_root) and raised ValueError, aborting the whole LLM call (and all retries) even after a successful response. Catch ValueError and fall back to the absolute path — session_trace is informational metadata and must never break the LLM call.
The pre-commit hook ran 'update_graphs.py sync --staged-only' and was followed ~1 sec later by the full post-commit sync that overwrote its output. Net effect: extra latency on every git commit and noisy [hook:pre-commit] entries in inner-git history, with no observable benefit (its writes never reach user's commit because all RPG state lives home-side).
Drop the install path; replace with idempotent _uninstall_git_pre_commit_hook so existing workspaces are cleaned on the next 'rpgkit init' / 'rpgkit update'. Keep 'rpgkit hook pre-commit' dispatcher branch as a deliberate no-op for backward compat with old hook files that haven't been stripped yet.
Also update MCP rpg-tools description ("pre-commit hook" -> "post-commit hook").
README.zh-CN.md: switch to 'Coding Agent' / 'workflow' English terminology (avoids translation drift to ja/ko/hi); rewrite '快速开始:已有仓库' to not require copying the repo; rewrite 'rpgkit init 之后会发生什么' with workspace-side vs home-side split, three-bullet rationale, multi-project parallelism callout; add troubleshooting entries for finding the home-side hash, cleaning home-side space, and full reset; split platform tables (Agent x Surface and OS x Shell) with legend. docs/project-structure.md: fix self-contradiction (reports stay inside workspace, not outside); fix stale '.rpgkit/data/' path reference; add '.git/hooks/' (post-commit + post-merge only) and '.rpgkit/reports/' to the workspace file tree; replace the Python hashlib one-liner with 'rpgkit version' guidance; add 'Quick reference: where does each file live?' table covering workspace-side vs home-side artefacts.
markdownlint-cli2 only walks up from each linted file; running it from RPG-Kit/ never reached the workspace-root config. Add a sibling config that disables MD013 / MD041 / MD060 (line length, first-line H1, double-width column alignment — all false positives on slash-command templates and CJK docs) and ignores .venv/, plans/, workspace/ as non-published trees.
Remove the view-graph CLI command and update docs to direct users to rpgkit version and the generated reports path instead. This avoids noisy browser-launch failures in headless and WSL environments while keeping the graph report discoverable.
Use the current zh-CN README as the source structure and sync English, Japanese, Korean, and Hindi variants. Update installation, runtime storage, update workflow, platform support, and troubleshooting sections consistently across the localized READMEs.
…tall # Conflicts: # RPG-Kit/src/rpgkit_cli/__init__.py
|
@HuYaSen please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
Contributor License AgreementContribution License AgreementThis Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
|
There was a problem hiding this comment.
Pull request overview
Updates RPG-Kit to the v0.1.3 “global CLI + home-side runtime store” architecture, moving runtime artifacts out of the workspace, consolidating script/hook invocation through rpgkit script / rpgkit-mcp, and syncing templates/docs/tests to the new layout.
Changes:
- Add home-directory workspace storage (
~/.rpgkit/workspaces/<hash>/...) plus inner-git snapshotting and MCP console-script entrypoint. - Refactor scripts/templates/docs/tests to invoke pipeline stages via the global
rpgkitdispatcher and to avoid leaking absolute paths. - Add atomic JSON writes + corruption recovery from inner-git history (
common.rpg_io), and switch key readers/writers to use it.
Reviewed changes
Copilot reviewed 76 out of 77 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| RPG-Kit/tests/test_workspace_unified_layout.py | Docstring alignment tweak. |
| RPG-Kit/tests/test_storage.py | New tests for home-side storage API. |
| RPG-Kit/tests/test_step3_polish.py | Hook script expectation update. |
| RPG-Kit/tests/test_rpg_io.py | New tests for atomic write + recovery. |
| RPG-Kit/tests/test_hooks_install.py | Tests updated for global rpgkit hooks/tasks. |
| RPG-Kit/tests/test_e2e.py | E2E path expectation updated for home store. |
| RPG-Kit/tests/test_dep_graph_incremental.py | Test header text tweak. |
| RPG-Kit/templates/commands/update_rpg.md | Use rpgkit script and new log guidance. |
| RPG-Kit/templates/commands/rpg_edit.md | Update workflow to rpgkit script + saved artifacts. |
| RPG-Kit/templates/commands/plan_tasks.md | Remove deprecated frontmatter; use rpgkit script. |
| RPG-Kit/templates/commands/feature_spec.md | Switch to rpgkit script invocation. |
| RPG-Kit/templates/commands/feature_refactor.md | Switch to rpgkit script invocation/log guidance. |
| RPG-Kit/templates/commands/feature_edit.md | Switch to rpgkit script invocation/log guidance. |
| RPG-Kit/templates/commands/feature_build.md | Switch to rpgkit script; stdout/log instructions. |
| RPG-Kit/templates/commands/encode.md | Switch to rpgkit script; stdout/log instructions. |
| RPG-Kit/templates/commands/design_interfaces.md | Remove deprecated frontmatter; use rpgkit script. |
| RPG-Kit/templates/commands/design_base_classes.md | Switch to rpgkit script invocation. |
| RPG-Kit/templates/commands/code_gen.md | Remove deprecated frontmatter; use rpgkit script. |
| RPG-Kit/templates/commands/build_skeleton.md | Switch to rpgkit script; home-store outputs. |
| RPG-Kit/templates/commands/build_data_flow.md | Switch to rpgkit script; home-store outputs. |
| RPG-Kit/src/rpgkit_cli/entries.py | Add rpgkit-mcp console-script entry. |
| RPG-Kit/src/rpgkit_cli/_storage.py | New home-side workspace storage layout + meta. |
| RPG-Kit/src/rpgkit_cli/_inner_git.py | New inner-git snapshotting for home workspace dir. |
| RPG-Kit/src/rpgkit_cli/_assets.py | Locate bundled scripts/templates inside wheel. |
| RPG-Kit/scripts/update_graphs.py | Use home-store paths, safe load, reports dir HTML. |
| RPG-Kit/scripts/summary_skeleton.py | Avoid printing absolute output paths. |
| RPG-Kit/scripts/smoke_test.py | Use cmd_for() in user guidance. |
| RPG-Kit/scripts/run_batch.py | Use cmd_for() in retry guidance. |
| RPG-Kit/scripts/rpg/models.py | Comment refinement (type inference docs). |
| RPG-Kit/scripts/rpg/graph_query.py | Switch JSON loads to safe_load_rpg. |
| RPG-Kit/scripts/rpg_encoder/workflow.py | Use atomic_write_rpg for rpg.json writes. |
| RPG-Kit/scripts/rpg_encoder/version_control.py | Use atomic_write_rpg during rollback writes. |
| RPG-Kit/scripts/rpg_encoder/run_update_rpg.py | Update usage docs to rpgkit script. |
| RPG-Kit/scripts/rpg_encoder/run_encode.py | Write rpg.html to workspace reports dir. |
| RPG-Kit/scripts/rpg_edit/validate.py | Update guidance to rpgkit script form. |
| RPG-Kit/scripts/rpg_edit/save_plan.py | New helper to save plan into home-store data dir. |
| RPG-Kit/scripts/rpg_edit/review.py | Default plan/impact paths; use cmd_for() tools. |
| RPG-Kit/scripts/rpg_edit/locate.py | Remove plan-doc references in comments. |
| RPG-Kit/scripts/rpg_edit/impact.py | Add --save to persist impact JSON. |
| RPG-Kit/scripts/rpg_edit/code.py | Default plan path; use cmd_for() for smoke test. |
| RPG-Kit/scripts/rpg_edit/apply.py | Default plan path; home-store plan default. |
| RPG-Kit/scripts/rpg_edit/init.py | Update invocation docs to rpgkit script. |
| RPG-Kit/scripts/plan_tasks.py | Avoid printing absolute output paths. |
| RPG-Kit/scripts/mcp_server.py | Make MCP runnable via rpgkit-mcp; doc updates. |
| RPG-Kit/scripts/init_codebase.py | Use cmd_for() in next-action guidance. |
| RPG-Kit/scripts/feature_spec_to_json.py | Output to canonical home-store path; avoid path leaks. |
| RPG-Kit/scripts/feature_build_validation.py | Log message cleanup. |
| RPG-Kit/scripts/design_interfaces.py | Avoid printing absolute output paths. |
| RPG-Kit/scripts/design_base_classes.py | Avoid printing absolute output paths. |
| RPG-Kit/scripts/common/rpg_io.py | New atomic write + inner-git recovery helpers. |
| RPG-Kit/scripts/common/project_types.py | Remove plan-doc references in comments. |
| RPG-Kit/scripts/common/paths.py | New home-store path resolution + cmd_for(). |
| RPG-Kit/scripts/common/llm_client.py | Resolve AI CLI cmd via env/config; better trace handling. |
| RPG-Kit/scripts/common/execution_state.py | Comment cleanups (remove plan refs). |
| RPG-Kit/scripts/code_gen/rpg_updater.py | Comment cleanup (remove plan refs). |
| RPG-Kit/scripts/code_gen/result_builders.py | Use cmd_for() in next-action hints. |
| RPG-Kit/scripts/code_gen/global_review.py | Comment cleanup (remove plan refs). |
| RPG-Kit/scripts/code_gen/batch_prompts.py | Update “must not run” guidance to global CLI. |
| RPG-Kit/scripts/code_gen/init.py | Comment cleanup. |
| RPG-Kit/scripts/check_skeleton.py | Update next_action to rpgkit script. |
| RPG-Kit/scripts/check_code_gen.py | Use cmd_for() in next-action hints. |
| RPG-Kit/scripts/build_skeleton.py | Avoid printing absolute output paths. |
| RPG-Kit/scripts/build_data_flow.py | Avoid printing absolute output paths. |
| RPG-Kit/scripts/init.py | Add marker file for hatch bundling. |
| RPG-Kit/README.zh-CN.md | Sync docs for v0.1.3 architecture. |
| RPG-Kit/README.md | Sync docs for v0.1.3 architecture. |
| RPG-Kit/README.ko-KR.md | Sync docs for v0.1.3 architecture. |
| RPG-Kit/README.ja-JP.md | Sync docs for v0.1.3 architecture. |
| RPG-Kit/README.hi-IN.md | Sync docs for v0.1.3 architecture. |
| RPG-Kit/pyproject.toml | Bump to 0.1.3; add bundled assets + rpgkit-mcp. |
| RPG-Kit/docs/project-structure.md | Document new home-side runtime store + reports. |
| RPG-Kit/docs/configuration.md | Document .rpgkit/config.toml + AI CLI resolution. |
| RPG-Kit/docs/commands.md | Update command docs for rpgkit script + paths note. |
| RPG-Kit/docs/cli-reference.md | Document script, legacy-download, auto-upgrade flags. |
| RPG-Kit/.markdownlint-cli2.jsonc | Add local markdownlint config mirror. |
| RPG-Kit/.gitignore | Unignore .rpgkit/config.toml; update patterns. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- _storage.find_workspace_root_from: drop home-side dir guard so fresh marker-only workspaces are discovered before any state is written; rely on .meta.toml workspace_path for stale-marker protection (moved/renamed dirs). Add regression test. - scripts/common/rpg_io: strip GIT_INDEX_FILE / GIT_DIR / GIT_WORK_TREE / GIT_OBJECT_DIRECTORY from env before running inner-git recovery subprocesses so hook contexts don't bleed the outer repo's git state into recovery queries. - scripts/__init__.py: refresh docstring to describe the 'rpgkit script <name>' dispatcher path (no longer copied into the workspace). - entries.mcp_main: remove unreachable 'scripts_dir is None' branch (_assets.scripts_dir always returns Path). - templates/commands/feature_build.md: rewrite broken / duplicated Step 2 sentence into a single coherent paragraph. - docs/project-structure.md: drop retired 'pre-commit' from the installed-hooks quick-reference row.
c9cb889 to
ea05e7d
Compare
| # working when a script ever renames data files in the future. | ||
| try: | ||
| log = subprocess.run( | ||
| ["git", "-C", str(git_dir), "log", "--format=%H", "--", relpath], |
| When a fresh repo is created we also drop a ``.gitignore`` that | ||
| excludes ``logs/`` (too noisy), then commit the current state of | ||
| ``data/`` + ``.meta.toml`` so ``git log`` has a starting point. |
| def test_cli_encode_helpers(self, sample_repo, tmp_path): | ||
| """RPG_FILE path constant points to correct location.""" | ||
| """RPG_FILE path constant points to the home-dir runtime location. | ||
|
|
||
| Workspace state lives under ``~/.rpgkit/workspaces/<hash>/``, | ||
| so ``RPG_FILE`` resolves to ``<home-state>/data/rpg.json`` rather than the | ||
| legacy ``<workspace>/.rpgkit/data/rpg.json``. We just assert the trailing | ||
| path components so the test is independent of any specific hash. | ||
| """ | ||
| from common.paths import RPG_FILE | ||
|
|
||
| assert str(RPG_FILE).endswith(os.path.join(".rpgkit", "data", "rpg.json")) | ||
| assert str(RPG_FILE).endswith(os.path.join("data", "rpg.json")) | ||
|
|
- scripts/common/rpg_io.py: add `--follow` to inner-git `git log` recovery call so the rename-tracking promise in the surrounding comment is actually delivered (works because the call uses a single path) - src/rpgkit_cli/_inner_git.py: correct `ensure_inner_git` docstring to say the dropped `.gitignore` excludes `logs/copilot/` (not `logs/`), matching the actual `_INNER_GIT_IGNORE` content and the file's own earlier comment - tests/test_e2e.py: drop `test_cli_encode_helpers` — it was a misnamed path-constant shape check (no encode helpers exercised, fixtures unused) whose responsibilities are already covered by tests/test_storage.py
Summary
Brings RPG-Kit to the 0.1.3 architecture: a globally-installed CLI with all
runtime artifacts kept outside the user's workspace, plus consolidated
hook/script plumbing and refreshed multilingual docs.
origin/mainhas already been merged into this branch; PR should beconflict-free.
Highlights
CLI / packaging (v0.1.3)
rpgkit initships templates and scripts from the installedpackage; workspace no longer needs a local scripts copy.
~/.rpgkit/...) for state, logs and theprivate inner-git snapshot — workspaces stay clean.
rpgkit script <stage>dispatcher routes all stage scripts via the globalCLI; stdout is tee'd into
logs/<stage>.log.rpgkit versioncompares local vs latest and prints upgrade hints.rpg-toolsin the Copilot CLI global MCP config..rpgkit/via a private inner git (isolated from user repo).rpgkitcommand.Hooks
pre-commithook; rely onpost-commit+post-mergeonly.GIT_*env to avoid leaking outer state.Robustness / fixes
CLI cleanup
view-graphcommand and its references inscripts and docs; users should run
rpgkit versionfrom inside theworkspace to see the resolved Data / Logs paths.
Docs
README.md,README.zh-CN.md,README.ja-JP.md,README.ko-KR.md,README.hi-IN.md) — identical structure and updatedinstall / quick-start / update / troubleshooting sections.
docs/for the home-side runtime store, retired pre-commithook, bundle mode,
--legacy-download/--pull, and.rpgkit/config.toml.RPG-Kit/for local runs.Templates
mode: agentfield from 3 prompt templates.Merge resolution
The only conflict with
mainwasRPG-Kit/src/rpgkit_cli/__init__.py(signature drift around
download_and_extract_template). Resolved bykeeping this branch's 0.1.3 implementation; main's
--source/.venv_rpgkitadditions were intentionally dropped as they are incompatiblewith the new home-side runtime store. All other incoming files from main
(release workflow scripts, root
.gitignore, rootREADME.md) mergedcleanly.
Validation
python3 -m compileall -q RPG-Kit/src/rpgkit_cli RPG-Kit/scripts— okmarkdownlint-cli2 "RPG-Kit/README*.md"— 0 errorsgit merge-tree main HEAD— no conflicts