claude-dev-env 4.3.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents/pr-description-writer.md +2 -2
- package/.agents/agents/test_agent_frontmatter.py +2 -2
- package/.agents/agents/test_pr_description_writer_style.py +1 -3
- package/.agents/skills/e-code-review/SKILL.md +12 -12
- package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
- package/.agents/skills/e-code-review/reference/fix.md +15 -17
- package/.agents/skills/e-code-review/reference/loop.md +35 -39
- package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
- package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
- package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
- package/.agents/skills/issue-tracker/SKILL.md +5 -4
- package/.agents/skills/pull-request/SKILL.md +11 -13
- package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
- package/.agents/skills/pull-request/scripts/pull_request.py +33 -44
- package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
- package/.agents/skills/pull-request/scripts/test_pull_request.py +1 -3
- package/.agents/skills/skill-builder/SKILL.md +3 -196
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
- package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
- package/bin/install.agents-home.test.mjs +15 -13
- package/bin/install.mjs +28 -0
- package/bin/install.policy-lint.test.mjs +78 -0
- package/bin/install.prune.test.mjs +59 -20
- package/bin/install.pstack-plugin.test.mjs +114 -0
- package/bin/install.test.mjs +37 -0
- package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
- package/hooks/advisory/pr_done_reminder.py +342 -0
- package/hooks/advisory/test_pr_done_reminder.py +249 -0
- package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
- package/hooks/blocking/code_rules_paired_test.py +22 -15
- package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
- package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
- package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
- package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
- package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
- package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
- package/hooks/git-hooks/pre_commit.py +52 -11
- package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
- package/hooks/git-hooks/test_native_policy_commit.py +87 -0
- package/hooks/git-hooks/test_pre_commit.py +246 -0
- package/hooks/hooks.json +1 -1
- package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
- package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
- package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
- package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
- package/package.json +2 -2
- package/rules/durable-post-artifacts.md +2 -1
- package/rules/git-workflow.md +6 -6
- package/scripts/check.ps1 +0 -1
- package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
- package/scripts/ci/installer-lifecycle.test.mjs +26 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
- package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
- package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +5 -41
- package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +0 -10
- package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +1 -1
- package/scripts/policy_lint/adapter_detectors.py +13 -6
- package/scripts/policy_lint/adapters.py +7 -4
- package/scripts/policy_lint/config/constants.py +5 -0
- package/scripts/policy_lint/engine.py +48 -4
- package/scripts/policy_lint/model.py +1 -0
- package/scripts/policy_lint/registry.py +1 -1
- package/scripts/policy_lint/selection.py +2 -1
- package/scripts/policy_lint/selection_git.py +2 -0
- package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
- package/scripts/shared_tree_paths.py +32 -3
- package/scripts/test_shared_tree_paths.py +33 -0
- package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
- package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
- package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
- package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
- package/scripts/tests/test_policy_lint_selection.py +25 -2
- package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
- package/scripts/tests/test_rules.py +3 -7
- package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
- package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
- package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
- package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
- package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
- package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
- package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
- package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
- package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
- package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
- package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
- package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
- package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
- package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
- package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
- package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
- package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
- package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
- package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
- package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
- package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
- package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
- package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
- package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
- package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
- package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
- package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
- package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
- package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
- package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
- package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
- package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
- package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
- package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
- package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
- package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
- package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
- package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
- package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/SKILL.md +0 -431
- package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
- package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
- package/.agents/skills/autoconverge/reference/convergence.md +0 -219
- package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
- package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
- package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
- package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
- package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
- package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
- package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
- package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
- package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
- package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
- package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
- package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
- package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
- package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
- package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
- package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
- package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
- package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
- package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
- package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
- package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
- package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
- package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
- package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
- package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
- package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
- package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
- package/.agents/skills/hitl/SKILL.md +0 -45
- package/.agents/skills/pr-cleanup/SKILL.md +0 -140
- package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
- package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
- package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
- package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
- package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
- package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
- package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
- package/.agents/skills/pr-refinement/SKILL.md +0 -31
- package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
- package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
- package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
- package/.agents/skills/pr-small-cl/SKILL.md +0 -52
- package/.agents/skills/pr-title-description/SKILL.md +0 -96
- package/.agents/skills/prototype/SKILL.md +0 -85
- package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
- package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
- package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
- package/.agents/skills/prototype/scripts/conftest.py +0 -15
- package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
- package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
- package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
- package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
- package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
- package/.agents/skills/prototype/workflows/promotion.md +0 -25
- package/.agents/skills/prototype/workflows/sandbox.md +0 -35
- package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
- package/.agents/skills/rebase/AGENTS.md +0 -1
- package/.agents/skills/rebase/SKILL.md +0 -178
- package/.agents/skills/review-router/SKILL.md +0 -51
- package/.agents/skills/review-router/reference/route-policy.json +0 -7
- package/.agents/skills/review-router/reference/task-seeds.md +0 -1
- package/.agents/skills/review-router/scripts/conftest.py +0 -4
- package/.agents/skills/review-router/scripts/review_router.py +0 -50
- package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
- package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
- package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
- package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
- package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
- package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
- package/.agents/skills/review-tier/SKILL.md +0 -56
- package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
- package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
- package/.agents/skills/review-tier/scripts/conftest.py +0 -4
- package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
- package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
- package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
- package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
- package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
- package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-log/AGENTS.md +0 -1
- package/.agents/skills/session-log/SKILL.md +0 -170
- package/.agents/skills/session-log/templates/frontmatter.md +0 -40
- package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-tidy/AGENTS.md +0 -1
- package/.agents/skills/session-tidy/SKILL.md +0 -191
- package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
- package/.agents/skills/skill-builder/references/description-field.md +0 -111
- package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
- package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
- package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
- package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
- package/.agents/skills/skill-builder/references/skill-types.md +0 -232
- package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
- package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
- package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
- package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
- package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
- package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
- package/.agents/skills/update/.claude/CLAUDE.md +0 -1
- package/.agents/skills/update/AGENTS.md +0 -1
- package/.agents/skills/update/SKILL.md +0 -190
- package/_shared/pr-loop/AGENTS.md +0 -1
- package/_shared/pr-loop/CLAUDE.md +0 -1
- package/_shared/pr-loop/audit-contract.md +0 -183
- package/_shared/pr-loop/audit-reply-template.md +0 -151
- package/_shared/pr-loop/code-rules-gate.md +0 -65
- package/_shared/pr-loop/fix-protocol.md +0 -60
- package/_shared/pr-loop/gh-payloads.md +0 -75
- package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
- package/_shared/pr-loop/precatch-rubric.md +0 -66
- package/_shared/pr-loop/preflight-proposal.md +0 -56
- package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
- package/_shared/pr-loop/state-schema.md +0 -45
- package/_shared/pr-loop/worker-spawn.md +0 -189
- /package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +0 -0
|
@@ -32,6 +32,8 @@ const INSTALLER_PATH = join(THIS_DIRECTORY, 'install.mjs');
|
|
|
32
32
|
const PACKAGE_DIRECTORY = dirname(THIS_DIRECTORY);
|
|
33
33
|
const SHIPPED_SKILL_NAME = 'privacy-hygiene';
|
|
34
34
|
const ELI5_SKILL_NAME = 'eli5';
|
|
35
|
+
const E_CODE_REVIEW_SKILL_NAME = 'e-code-review';
|
|
36
|
+
const REFERENCE_DIRECTORY_NAME = 'reference';
|
|
35
37
|
const SHIPPED_AGENT_FILE_NAME = 'clean-coder.md';
|
|
36
38
|
const SHIPPED_AGENT_FILE_NAMES = [
|
|
37
39
|
SHIPPED_AGENT_FILE_NAME,
|
|
@@ -69,10 +71,7 @@ const CLEAN_CODER_POLICY_REFERENCES = [
|
|
|
69
71
|
],
|
|
70
72
|
];
|
|
71
73
|
const PERSONAL_SKILL_NAME = 'my-notes';
|
|
72
|
-
const SHARED_DIRECTORY_NAME = '_shared';
|
|
73
|
-
const PR_LOOP_DIRECTORY_NAME = 'pr-loop';
|
|
74
74
|
const PREFLIGHT_PROPOSAL_FILE_NAME = 'preflight-proposal.md';
|
|
75
|
-
const PREFLIGHT_PROPOSAL_POINTER = '@~/.claude/_shared/pr-loop/preflight-proposal.md';
|
|
76
75
|
|
|
77
76
|
/**
|
|
78
77
|
* @param {string} homeDirectory
|
|
@@ -100,20 +99,23 @@ function runInstaller(homeDirectory, extraArguments, environmentOverrides = {})
|
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
/**
|
|
103
|
-
* @param {{
|
|
102
|
+
* @param {{ skillsInstallDirectory: string }} installationPaths
|
|
104
103
|
*/
|
|
105
104
|
function assertProposalContractInstallation(installationPaths) {
|
|
106
|
-
const {
|
|
105
|
+
const { skillsInstallDirectory } = installationPaths;
|
|
107
106
|
const allContractPathSegments = [
|
|
108
|
-
|
|
107
|
+
E_CODE_REVIEW_SKILL_NAME,
|
|
108
|
+
REFERENCE_DIRECTORY_NAME,
|
|
109
|
+
PREFLIGHT_PROPOSAL_FILE_NAME,
|
|
109
110
|
];
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
const installedContractPath = join(skillsInstallDirectory, ...allContractPathSegments);
|
|
112
|
+
const sourceSkillsDirectory = resolvePackageManagedDirectory(
|
|
113
|
+
PACKAGE_DIRECTORY,
|
|
114
|
+
MANAGED_SKILLS_DIRECTORY_NAME,
|
|
115
|
+
);
|
|
116
|
+
const sourceContractPath = join(sourceSkillsDirectory, ...allContractPathSegments);
|
|
115
117
|
|
|
116
|
-
assert.equal(
|
|
118
|
+
assert.equal(existsSync(installedContractPath), true);
|
|
117
119
|
assert.equal(readFileSync(installedContractPath, 'utf8'), readFileSync(sourceContractPath, 'utf8'));
|
|
118
120
|
}
|
|
119
121
|
|
|
@@ -197,7 +199,7 @@ test('a full install writes skills and agents under .agents and points .claude a
|
|
|
197
199
|
);
|
|
198
200
|
assert.equal(realpathSync(lookupSkillFile), realpathSync(canonicalSkillFile));
|
|
199
201
|
assert.equal(realpathSync(lookupEli5SkillFile), realpathSync(canonicalEli5SkillFile));
|
|
200
|
-
assertProposalContractInstallation({
|
|
202
|
+
assertProposalContractInstallation({ skillsInstallDirectory });
|
|
201
203
|
assert.equal(
|
|
202
204
|
readFileSync(lookupAgentFile, 'utf8'),
|
|
203
205
|
readFileSync(canonicalAgentFile, 'utf8'),
|
package/bin/install.mjs
CHANGED
|
@@ -35,6 +35,11 @@ import {
|
|
|
35
35
|
WINDOWS_PYTHON_LAUNCHER_COMMAND,
|
|
36
36
|
PYTHON_PROBE_TIMEOUT_MILLISECONDS,
|
|
37
37
|
} from './install-constants.mjs';
|
|
38
|
+
import {
|
|
39
|
+
PSTACK_PLUGIN_DIRECTORY_NAME,
|
|
40
|
+
PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH,
|
|
41
|
+
refreshPstackPluginManifest,
|
|
42
|
+
} from '../scripts/refresh_pstack_plugin_skills.mjs';
|
|
38
43
|
import {
|
|
39
44
|
resolveInstallRoot,
|
|
40
45
|
parseExplicitTargetFromArgv,
|
|
@@ -429,6 +434,26 @@ export function runCursorRuleSync(pythonCommand, scriptPath, claudeRoot, cursorR
|
|
|
429
434
|
);
|
|
430
435
|
}
|
|
431
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Refresh the pstack plugin manifest Claude Code reads, when this home has one.
|
|
439
|
+
*
|
|
440
|
+
* Claude Code loads a skills-directory folder as a plugin when it holds
|
|
441
|
+
* `.claude-plugin/plugin.json`, and namespaces its skills as `pstack:how`.
|
|
442
|
+
* Without the manifest, a folder of skill folders loads nothing.
|
|
443
|
+
*
|
|
444
|
+
* @param {string} [skillsRoot] The skills root to read. Defaults to the root
|
|
445
|
+
* this run installs into.
|
|
446
|
+
* @returns {string|null} The manifest path when this run wrote it, else null.
|
|
447
|
+
*/
|
|
448
|
+
export function refreshInstalledPstackPluginManifest(
|
|
449
|
+
skillsRoot = join(CLAUDE_HOME, MANAGED_SKILLS_DIRECTORY_NAME),
|
|
450
|
+
) {
|
|
451
|
+
const pluginRoot = join(skillsRoot, PSTACK_PLUGIN_DIRECTORY_NAME);
|
|
452
|
+
const outcome = refreshPstackPluginManifest(pluginRoot);
|
|
453
|
+
if (!outcome.didWrite) return null;
|
|
454
|
+
return join(pluginRoot, PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH);
|
|
455
|
+
}
|
|
456
|
+
|
|
432
457
|
function seedCodexPstackPreferences() {
|
|
433
458
|
const preferenceDirectory = join(AGENTS_HOME, CURSOR_RULES_DIRECTORY_NAME);
|
|
434
459
|
const preferencePath = join(
|
|
@@ -2320,6 +2345,9 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
|
|
|
2320
2345
|
}
|
|
2321
2346
|
summary.skills = { created: skillsCreated, updated: skillsUpdated, pruned: 0, paths: skillPaths };
|
|
2322
2347
|
allInstalledFiles.push(...skillPaths);
|
|
2348
|
+
const pstackManifestPath = refreshInstalledPstackPluginManifest();
|
|
2349
|
+
if (pstackManifestPath) allInstalledFiles.push(pstackManifestPath);
|
|
2350
|
+
summary.pstackPlugin = { manifestPath: pstackManifestPath };
|
|
2323
2351
|
syncWrittenPaths([...allInstalledFiles, ...publishedPointerPaths]);
|
|
2324
2352
|
throwIfFault(FAULT_PHASES.AFTER_FILE_STAGING);
|
|
2325
2353
|
throwIfFault(FAULT_PHASES.BEFORE_DURABLE_PROMOTION);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import {
|
|
5
|
+
FOLDED_HOOK_RELATIVE_PATHS,
|
|
6
|
+
mergeHooksIntoSettings,
|
|
7
|
+
} from './install.mjs';
|
|
8
|
+
|
|
9
|
+
const allRetiredWriteHooks = [
|
|
10
|
+
'blocking/code_rules_enforcer.py',
|
|
11
|
+
'blocking/tdd_enforcer.py',
|
|
12
|
+
'blocking/windows_rmtree_blocker.py',
|
|
13
|
+
'blocking/state_description_blocker.py',
|
|
14
|
+
'blocking/subprocess_budget_completeness.py',
|
|
15
|
+
'blocking/hook_prose_detector_consistency.py',
|
|
16
|
+
'blocking/workflow_substitution_slot_blocker.py',
|
|
17
|
+
];
|
|
18
|
+
const sourceHooks = JSON.parse(readFileSync(new URL('../hooks/hooks.json', import.meta.url), 'utf8'));
|
|
19
|
+
const installedRoot = '/fixture-home/.claude';
|
|
20
|
+
const foreignCommand = 'python /unmanaged/keep_this_hook.py';
|
|
21
|
+
const foreignSessionCommand = 'node /unmanaged/session.js';
|
|
22
|
+
|
|
23
|
+
function legacySettings() {
|
|
24
|
+
return {
|
|
25
|
+
permissions: { allow: ['Read'] },
|
|
26
|
+
hooks: {
|
|
27
|
+
PreToolUse: [{
|
|
28
|
+
matcher: 'Write|Edit|MultiEdit|apply_patch',
|
|
29
|
+
hooks: [
|
|
30
|
+
{ type: 'command', command: foreignCommand, timeout: 17 },
|
|
31
|
+
...allRetiredWriteHooks.map(relativePath => ({
|
|
32
|
+
type: 'command',
|
|
33
|
+
command: `python ${installedRoot}/hooks/${relativePath}`,
|
|
34
|
+
timeout: 10,
|
|
35
|
+
})),
|
|
36
|
+
],
|
|
37
|
+
}],
|
|
38
|
+
SessionStart: [{
|
|
39
|
+
matcher: '',
|
|
40
|
+
hooks: [{ type: 'command', command: foreignSessionCommand, timeout: 9 }],
|
|
41
|
+
}],
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function allCommands(settings) {
|
|
47
|
+
return Object.values(settings.hooks).flatMap(groups =>
|
|
48
|
+
groups.flatMap(group => group.hooks.map(hook => hook.command)));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
test('every retired write registration already has an installer-owned prune path', () => {
|
|
52
|
+
for (const relativePath of allRetiredWriteHooks) {
|
|
53
|
+
assert.ok(FOLDED_HOOK_RELATIVE_PATHS.has(relativePath), relativePath);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('upgrade prunes legacy direct file checks while retaining foreign hooks', () => {
|
|
58
|
+
const settings = legacySettings();
|
|
59
|
+
mergeHooksIntoSettings(settings, sourceHooks, installedRoot, 'python3');
|
|
60
|
+
const commands = allCommands(settings);
|
|
61
|
+
for (const relativePath of allRetiredWriteHooks) {
|
|
62
|
+
assert.ok(!commands.some(command => command.includes(relativePath)), relativePath);
|
|
63
|
+
}
|
|
64
|
+
assert.ok(commands.includes(foreignCommand));
|
|
65
|
+
assert.ok(commands.includes(foreignSessionCommand));
|
|
66
|
+
assert.deepEqual(settings.permissions, { allow: ['Read'] });
|
|
67
|
+
assert.ok(commands.some(command => command.includes('/blocking/pre_tool_use_dispatcher.py')));
|
|
68
|
+
assert.ok(commands.some(command => command.includes('/blocking/bash_pre_tool_use_dispatcher.py')));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('reinstall does not restore retired direct checks or duplicate foreign hooks', () => {
|
|
72
|
+
const settings = legacySettings();
|
|
73
|
+
mergeHooksIntoSettings(settings, sourceHooks, installedRoot, 'python3');
|
|
74
|
+
const firstInstall = structuredClone(settings);
|
|
75
|
+
mergeHooksIntoSettings(settings, sourceHooks, installedRoot, 'python3');
|
|
76
|
+
assert.deepEqual(settings, firstInstall);
|
|
77
|
+
assert.equal(allCommands(settings).filter(command => command === foreignCommand).length, 1);
|
|
78
|
+
});
|
|
@@ -25,16 +25,43 @@ const RETIRED_SKILL_DIRECTORIES = [
|
|
|
25
25
|
'post-audit-findings',
|
|
26
26
|
'pr-consistency-audit',
|
|
27
27
|
'bdd-protocol',
|
|
28
|
+
'hitl',
|
|
29
|
+
'autoconverge',
|
|
30
|
+
'pr-cleanup',
|
|
31
|
+
'pr-name-by-capability',
|
|
32
|
+
'pr-plain-language-cleanup',
|
|
33
|
+
'pr-refinement',
|
|
34
|
+
'pr-shared-extraction',
|
|
35
|
+
'pr-small-cl',
|
|
36
|
+
'pr-title-description',
|
|
37
|
+
'prototype',
|
|
38
|
+
'rebase',
|
|
39
|
+
'review-router',
|
|
40
|
+
'review-tier',
|
|
41
|
+
'run-claude-dev-env',
|
|
42
|
+
'session-log',
|
|
43
|
+
'session-tidy',
|
|
44
|
+
'source-command-sr-loop',
|
|
45
|
+
'update',
|
|
28
46
|
];
|
|
29
47
|
const PERSONAL_SKILL_DIRECTORIES = ['credit-card-picker', 'midjourney-sref'];
|
|
30
|
-
const SHIPPED_SKILL_DIRECTORY = '
|
|
48
|
+
const SHIPPED_SKILL_DIRECTORY = 'e-code-review';
|
|
31
49
|
const PRUNED_BACKUP_DIRECTORY_NAME = '.claude-dev-env-pruned';
|
|
32
50
|
const SKIP_PRUNE_NOTICE_MARKER = 'Skipping retired-skill and stale-file prune';
|
|
33
51
|
const STALE_SKILL_FILE_RELATIVE_SEGMENTS = ['scripts', 'retired_module.py'];
|
|
34
52
|
const RUNTIME_ARTIFACT_RELATIVE_SEGMENTS = ['scripts', '__pycache__', 'helper.cpython-312.pyc'];
|
|
35
53
|
const SCOPED_GROUP_SKILL_DIRECTORY = 'orchestrator';
|
|
36
|
-
const
|
|
37
|
-
'
|
|
54
|
+
const CORE_SKILL_DIRECTORIES = [
|
|
55
|
+
'orchestrator',
|
|
56
|
+
'orchestrator-refresh',
|
|
57
|
+
'team-advisor',
|
|
58
|
+
'grok-spawn',
|
|
59
|
+
'everything-search',
|
|
60
|
+
'test-runner',
|
|
61
|
+
'privacy-hygiene',
|
|
62
|
+
'issue-tracker',
|
|
63
|
+
'task-build',
|
|
64
|
+
'eli5',
|
|
38
65
|
];
|
|
39
66
|
const PRIOR_RUN_BACKUP_DIRECTORY_NAMES = [
|
|
40
67
|
'2020-01-01T00-00-00-000Z',
|
|
@@ -693,25 +720,33 @@ test('a scoped --only install leaves retired skills in place because prune runs
|
|
|
693
720
|
}
|
|
694
721
|
});
|
|
695
722
|
|
|
696
|
-
test('a full reinstall keeps
|
|
723
|
+
test('a full reinstall keeps the skill-builder stub and archives its obsolete support files', () => {
|
|
697
724
|
const sandbox = createSandbox();
|
|
698
725
|
try {
|
|
699
|
-
|
|
700
|
-
|
|
726
|
+
const skillName = 'skill-builder';
|
|
727
|
+
plantSkillDirectory(sandbox.skillsDirectory, skillName, true);
|
|
728
|
+
const stubPath = join(sandbox.skillsDirectory, skillName, 'SKILL.md');
|
|
729
|
+
const obsoleteReferencePath = join(sandbox.skillsDirectory, skillName, 'references', 'retired.md');
|
|
730
|
+
writeFileWithParents(obsoleteReferencePath, 'obsolete skill-builder guidance\n');
|
|
731
|
+
writeFileSync(sandbox.manifestPath, JSON.stringify({
|
|
732
|
+
package: 'claude-dev-env',
|
|
733
|
+
version: '0.0.0',
|
|
734
|
+
installedAt: new Date().toISOString(),
|
|
735
|
+
files: [stubPath, obsoleteReferencePath],
|
|
736
|
+
skills: [skillName],
|
|
737
|
+
}, null, 2) + '\n');
|
|
701
738
|
|
|
702
739
|
const installerOutput = runInstaller(sandbox.homeDirectory, []);
|
|
703
740
|
|
|
741
|
+
assert.equal(installerOutput.includes(SKIP_PRUNE_NOTICE_MARKER), false);
|
|
742
|
+
assert.equal(existsSync(stubPath), true, 'the requested stub stays installed');
|
|
743
|
+
assert.match(readFileSync(stubPath, 'utf8'), /TODO: Rework to follow pstack philosophy\./);
|
|
744
|
+
assert.ok(readManifest(sandbox.manifestPath).skills.includes(skillName));
|
|
745
|
+
assert.equal(existsSync(obsoleteReferencePath), false);
|
|
704
746
|
assert.equal(
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
'
|
|
708
|
-
);
|
|
709
|
-
const restoredSkillPath = join(sandbox.skillsDirectory, 'autoconverge', 'SKILL.md');
|
|
710
|
-
assert.equal(existsSync(restoredSkillPath), true, 'autoconverge survives and is reinstalled');
|
|
711
|
-
assert.notEqual(
|
|
712
|
-
readFileSync(restoredSkillPath, 'utf8'),
|
|
713
|
-
'stale seeded copy\n',
|
|
714
|
-
'the shipped autoconverge overwrites the stale seeded copy',
|
|
747
|
+
prunedSkillBackupContains(sandbox.claudeDirectory, join(skillName, 'references', 'retired.md')),
|
|
748
|
+
true,
|
|
749
|
+
'old implementation files move to the recovery backup while the stub stays',
|
|
715
750
|
);
|
|
716
751
|
} finally {
|
|
717
752
|
rmSync(sandbox.homeDirectory, { recursive: true, force: true });
|
|
@@ -739,20 +774,24 @@ test('a scoped --only install records the skill names it installed', () => {
|
|
|
739
774
|
}
|
|
740
775
|
});
|
|
741
776
|
|
|
742
|
-
test('a scoped core install ships
|
|
777
|
+
test('a fresh scoped core install ships active skills and omits retired skills', () => {
|
|
743
778
|
const sandbox = createSandbox();
|
|
744
779
|
try {
|
|
745
780
|
runInstaller(sandbox.homeDirectory, ['--only', 'core']);
|
|
746
781
|
|
|
747
|
-
const
|
|
782
|
+
const missingSkillNames = CORE_SKILL_DIRECTORIES.filter(
|
|
748
783
|
eachSkillName => !existsSync(join(sandbox.skillsDirectory, eachSkillName, 'SKILL.md')),
|
|
749
784
|
);
|
|
750
|
-
assert.deepEqual(
|
|
785
|
+
assert.deepEqual(missingSkillNames, []);
|
|
751
786
|
|
|
752
787
|
const recordedSkillNames = new Set(readManifest(sandbox.manifestPath).skills);
|
|
753
|
-
for (const eachSkillName of
|
|
788
|
+
for (const eachSkillName of CORE_SKILL_DIRECTORIES) {
|
|
754
789
|
assert.equal(recordedSkillNames.has(eachSkillName), true);
|
|
755
790
|
}
|
|
791
|
+
for (const eachSkillName of RETIRED_SKILL_DIRECTORIES) {
|
|
792
|
+
assert.equal(existsSync(join(sandbox.skillsDirectory, eachSkillName)), false);
|
|
793
|
+
assert.equal(recordedSkillNames.has(eachSkillName), false);
|
|
794
|
+
}
|
|
756
795
|
} finally {
|
|
757
796
|
rmSync(sandbox.homeDirectory, { recursive: true, force: true });
|
|
758
797
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import { strict as assert } from 'node:assert';
|
|
3
|
+
import {
|
|
4
|
+
mkdtempSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
existsSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
} from 'node:fs';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import { dirname, join } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { execFileSync } from 'node:child_process';
|
|
15
|
+
import { resolveInstallRoot } from './resolve-install-root.mjs';
|
|
16
|
+
import { PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH } from '../scripts/refresh_pstack_plugin_skills.mjs';
|
|
17
|
+
|
|
18
|
+
const THIS_DIRECTORY = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const INSTALLER_PATH = join(THIS_DIRECTORY, 'install.mjs');
|
|
20
|
+
const PACKAGE_DIRECTORY = dirname(THIS_DIRECTORY);
|
|
21
|
+
|
|
22
|
+
function runInstaller(homeDirectory, extraArguments) {
|
|
23
|
+
return execFileSync('node', [INSTALLER_PATH, ...extraArguments], {
|
|
24
|
+
cwd: PACKAGE_DIRECTORY,
|
|
25
|
+
encoding: 'utf8',
|
|
26
|
+
env: {
|
|
27
|
+
...process.env,
|
|
28
|
+
HOME: homeDirectory,
|
|
29
|
+
USERPROFILE: homeDirectory,
|
|
30
|
+
CODEX_HOME: join(homeDirectory, '.codex'),
|
|
31
|
+
CLAUDE_CONFIG_DIR: join(homeDirectory, '.claude'),
|
|
32
|
+
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function seedPstackSkills(agentsHome, skillNames) {
|
|
38
|
+
const pluginRoot = join(agentsHome, 'skills', 'pstack');
|
|
39
|
+
for (const eachSkillName of skillNames) {
|
|
40
|
+
const skillDirectory = join(pluginRoot, eachSkillName);
|
|
41
|
+
mkdirSync(skillDirectory, { recursive: true });
|
|
42
|
+
writeFileSync(join(skillDirectory, 'SKILL.md'), '---\nname: ' + eachSkillName + '\n---\n');
|
|
43
|
+
}
|
|
44
|
+
return pluginRoot;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function withTemporaryHome(runAssertions) {
|
|
48
|
+
const homeDirectory = mkdtempSync(join(tmpdir(), 'cdev-pstack-plugin-'));
|
|
49
|
+
try {
|
|
50
|
+
const resolution = resolveInstallRoot({
|
|
51
|
+
homeDirectory,
|
|
52
|
+
environment: {},
|
|
53
|
+
explicitTarget: null,
|
|
54
|
+
});
|
|
55
|
+
runAssertions(homeDirectory, resolution);
|
|
56
|
+
} finally {
|
|
57
|
+
rmSync(homeDirectory, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
test('a pstack folder the user installed gains a plugin manifest', () => {
|
|
62
|
+
withTemporaryHome((homeDirectory, resolution) => {
|
|
63
|
+
const pluginRoot = seedPstackSkills(resolution.agentsHome, ['how', 'why']);
|
|
64
|
+
|
|
65
|
+
runInstaller(homeDirectory, ['--only', 'core']);
|
|
66
|
+
|
|
67
|
+
const manifestPath = join(pluginRoot, PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH);
|
|
68
|
+
assert.equal(existsSync(manifestPath), true);
|
|
69
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
70
|
+
assert.equal(manifest.name, 'pstack');
|
|
71
|
+
assert.deepEqual(manifest.skills, ['./how', './why']);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('a second install leaves an unchanged manifest byte for byte', () => {
|
|
76
|
+
withTemporaryHome((homeDirectory, resolution) => {
|
|
77
|
+
const pluginRoot = seedPstackSkills(resolution.agentsHome, ['how']);
|
|
78
|
+
|
|
79
|
+
runInstaller(homeDirectory, ['--only', 'core']);
|
|
80
|
+
const manifestPath = join(pluginRoot, PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH);
|
|
81
|
+
const afterFirstInstall = readFileSync(manifestPath, 'utf8');
|
|
82
|
+
runInstaller(homeDirectory, ['--only', 'core']);
|
|
83
|
+
|
|
84
|
+
assert.equal(readFileSync(manifestPath, 'utf8'), afterFirstInstall);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('a later install lists a skill a pstack update added', () => {
|
|
89
|
+
withTemporaryHome((homeDirectory, resolution) => {
|
|
90
|
+
const pluginRoot = seedPstackSkills(resolution.agentsHome, ['how']);
|
|
91
|
+
runInstaller(homeDirectory, ['--only', 'core']);
|
|
92
|
+
|
|
93
|
+
seedPstackSkills(resolution.agentsHome, ['why']);
|
|
94
|
+
runInstaller(homeDirectory, ['--only', 'core']);
|
|
95
|
+
|
|
96
|
+
const manifestPath = join(pluginRoot, PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH);
|
|
97
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
98
|
+
assert.deepEqual(manifest.skills, ['./how', './why']);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('an install with no pstack folder writes no manifest and does not fail', () => {
|
|
103
|
+
withTemporaryHome((homeDirectory, resolution) => {
|
|
104
|
+
runInstaller(homeDirectory, ['--only', 'core']);
|
|
105
|
+
|
|
106
|
+
const manifestPath = join(
|
|
107
|
+
resolution.agentsHome,
|
|
108
|
+
'skills',
|
|
109
|
+
'pstack',
|
|
110
|
+
PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH,
|
|
111
|
+
);
|
|
112
|
+
assert.equal(existsSync(manifestPath), false);
|
|
113
|
+
});
|
|
114
|
+
});
|
package/bin/install.test.mjs
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
retiredManagedHookRelativePaths,
|
|
44
44
|
pruneRetiredHookEntriesFromSettings,
|
|
45
45
|
retainNewestRunBackupOnly,
|
|
46
|
+
refreshInstalledPstackPluginManifest,
|
|
46
47
|
} from './install.mjs';
|
|
47
48
|
import { EVER_SHIPPED_SKILL_NAMES } from './ever-shipped-skills.mjs';
|
|
48
49
|
import {
|
|
@@ -2541,3 +2542,39 @@ test('pruneStaleInstalledFiles leaves the run backup root standing when the rena
|
|
|
2541
2542
|
rmSync(sandbox.root, { recursive: true, force: true });
|
|
2542
2543
|
}
|
|
2543
2544
|
});
|
|
2545
|
+
|
|
2546
|
+
test('the pstack step writes a manifest for a skills root that carries pstack', () => {
|
|
2547
|
+
const skillsRoot = mkdtempSync(join(tmpdir(), 'cdev-pstack-step-'));
|
|
2548
|
+
try {
|
|
2549
|
+
const skillDirectory = join(skillsRoot, 'pstack', 'how');
|
|
2550
|
+
mkdirSync(skillDirectory, { recursive: true });
|
|
2551
|
+
writeFileSync(join(skillDirectory, 'SKILL.md'), '---\nname: how\n---\n');
|
|
2552
|
+
|
|
2553
|
+
const manifestPath = refreshInstalledPstackPluginManifest(skillsRoot);
|
|
2554
|
+
|
|
2555
|
+
assert.equal(
|
|
2556
|
+
manifestPath,
|
|
2557
|
+
join(skillsRoot, 'pstack', '.claude-plugin', 'plugin.json'),
|
|
2558
|
+
'the step reports the manifest it wrote so the run records the path',
|
|
2559
|
+
);
|
|
2560
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
2561
|
+
assert.deepEqual(manifest.skills, ['./how']);
|
|
2562
|
+
assert.equal(
|
|
2563
|
+
refreshInstalledPstackPluginManifest(skillsRoot),
|
|
2564
|
+
null,
|
|
2565
|
+
'a second run writes nothing and reports no path',
|
|
2566
|
+
);
|
|
2567
|
+
} finally {
|
|
2568
|
+
rmSync(skillsRoot, { recursive: true, force: true });
|
|
2569
|
+
}
|
|
2570
|
+
});
|
|
2571
|
+
|
|
2572
|
+
test('the pstack step reports no path for a skills root without pstack', () => {
|
|
2573
|
+
const skillsRoot = mkdtempSync(join(tmpdir(), 'cdev-pstack-absent-'));
|
|
2574
|
+
try {
|
|
2575
|
+
assert.equal(refreshInstalledPstackPluginManifest(skillsRoot), null);
|
|
2576
|
+
assert.equal(existsSync(join(skillsRoot, 'pstack')), false);
|
|
2577
|
+
} finally {
|
|
2578
|
+
rmSync(skillsRoot, { recursive: true, force: true });
|
|
2579
|
+
}
|
|
2580
|
+
});
|