claude-dev-env 4.3.0 → 7.1.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.
Files changed (480) hide show
  1. package/.agents/agents/pr-description-writer.md +2 -2
  2. package/.agents/agents/test_agent_frontmatter.py +2 -2
  3. package/.agents/agents/test_pr_description_writer_style.py +1 -3
  4. package/.agents/skills/e-code-review/SKILL.md +12 -12
  5. package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
  6. package/.agents/skills/e-code-review/reference/fix.md +15 -17
  7. package/.agents/skills/e-code-review/reference/loop.md +35 -39
  8. package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
  9. package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
  10. package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
  11. package/.agents/skills/issue-tracker/SKILL.md +5 -4
  12. package/.agents/skills/pull-request/SKILL.md +11 -13
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
  15. package/.agents/skills/pull-request/scripts/pull_request.py +35 -44
  16. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
  17. package/.agents/skills/pull-request/scripts/test_pull_request.py +35 -3
  18. package/.agents/skills/session-continuity/README.md +189 -0
  19. package/.agents/skills/session-continuity/SKILL.md +114 -0
  20. package/.agents/skills/session-continuity/continuity.mjs +375 -0
  21. package/.agents/skills/session-continuity/continuity.test.mjs +303 -0
  22. package/.agents/skills/skill-builder/SKILL.md +3 -196
  23. package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +0 -7
  24. package/.agents/skills/windows-scheduled-task/SKILL.md +153 -0
  25. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  26. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  27. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  28. package/bin/cde.mjs +36 -8
  29. package/bin/cde.test.mjs +48 -0
  30. package/bin/ever-shipped-skills.mjs +2 -20
  31. package/bin/ever-shipped-skills.test.mjs +8 -0
  32. package/bin/expand_home_directory_tokens.mjs +4 -5
  33. package/bin/expand_home_directory_tokens.test.mjs +128 -0
  34. package/bin/git_hooks_installer.mjs +22 -3
  35. package/bin/git_hooks_installer.test.mjs +159 -5
  36. package/bin/install-session-continuity.mjs +78 -0
  37. package/bin/install-session-continuity.test.mjs +42 -0
  38. package/bin/install.agents-home.test.mjs +15 -13
  39. package/bin/install.codex-rules.test.mjs +5 -2
  40. package/bin/install.cursor-rules.test.mjs +5 -2
  41. package/bin/install.mjs +506 -63
  42. package/bin/install.policy-lint.test.mjs +130 -0
  43. package/bin/install.profiles.test.mjs +10 -0
  44. package/bin/install.prune.test.mjs +286 -37
  45. package/bin/install.pstack-plugin.test.mjs +114 -0
  46. package/bin/install.test.mjs +537 -120
  47. package/bin/install.transaction.test.mjs +3 -3
  48. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  49. package/docs/CODE_RULES.md +1 -1
  50. package/hooks/advisory/pr_done_reminder.py +342 -0
  51. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  52. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  53. package/hooks/blocking/code_rules_banned_identifiers.py +3 -0
  54. package/hooks/blocking/code_rules_paired_test.py +22 -15
  55. package/hooks/blocking/precommit_code_rules_gate.py +5 -8
  56. package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +7 -52
  57. package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
  58. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -69
  59. package/hooks/blocking/test_code_rules_banned_identifiers.py +64 -0
  60. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  61. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  62. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  63. package/hooks/blocking/test_pre_tool_use_dispatcher.py +43 -342
  64. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  65. package/hooks/blocking/test_shared_stdin_adoption.py +1 -47
  66. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  67. package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +116 -0
  68. package/hooks/git-hooks/post_commit.py +33 -0
  69. package/hooks/git-hooks/pre_commit.py +18 -49
  70. package/hooks/git-hooks/pre_push.py +45 -541
  71. package/hooks/git-hooks/test_installed_policy_lint.py +208 -0
  72. package/hooks/git-hooks/test_native_hook_support.py +129 -0
  73. package/hooks/git-hooks/test_native_policy_commit.py +120 -0
  74. package/hooks/git-hooks/test_post_commit.py +43 -0
  75. package/hooks/git-hooks/test_pre_commit.py +38 -148
  76. package/hooks/git-hooks/test_pre_push.py +48 -1631
  77. package/hooks/git-hooks/test_verification_notice.py +60 -0
  78. package/hooks/git-hooks/test_verification_start.py +173 -0
  79. package/hooks/git-hooks/verification_notice.py +192 -0
  80. package/hooks/git-hooks/verification_notice_context.py +253 -0
  81. package/hooks/git-hooks/verification_notice_state.py +237 -0
  82. package/hooks/git-hooks/verification_start.py +100 -0
  83. package/hooks/hooks.json +1 -120
  84. package/hooks/hooks_constants/banned_identifiers_constants.py +4 -0
  85. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
  86. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -15
  87. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -4
  88. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  89. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -93
  90. package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -4
  91. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
  92. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +3 -66
  93. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  94. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +46 -201
  95. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +3 -25
  96. package/hooks/validation/test_post_tool_use_dispatcher.py +35 -298
  97. package/hooks/validators/run_all_validators.py +5 -1
  98. package/hooks/validators/security_checks.py +57 -2
  99. package/hooks/validators/test_hook_timing_harness.py +2 -5
  100. package/hooks/validators/test_run_all_validators_mutation_tool_parity.py +3 -11
  101. package/hooks/validators/test_run_all_validators_policy_lint.py +36 -0
  102. package/hooks/validators/test_security_checks.py +57 -0
  103. package/package.json +2 -2
  104. package/rules/confirm-implementation-forks.md +2 -0
  105. package/rules/durable-post-artifacts.md +2 -1
  106. package/rules/git-workflow.md +18 -6
  107. package/rules/pstack-host-mapping.md +48 -0
  108. package/rules/vault-context.md +3 -5
  109. package/rules/verify-runtime-state.md +7 -0
  110. package/scripts/audit-hooks-cli.mjs +5 -0
  111. package/scripts/audit-hooks.mjs +72 -16
  112. package/scripts/automatic_advisory/__init__.py +1 -0
  113. package/scripts/automatic_advisory/checkout.py +51 -0
  114. package/scripts/automatic_advisory/cli.py +334 -0
  115. package/scripts/automatic_advisory/config/__init__.py +1 -0
  116. package/scripts/automatic_advisory/config/constants.py +93 -0
  117. package/scripts/automatic_advisory/config/timing.py +4 -0
  118. package/scripts/automatic_advisory/configuration.py +197 -0
  119. package/scripts/automatic_advisory/execution.py +350 -0
  120. package/scripts/automatic_advisory/git.py +69 -0
  121. package/scripts/automatic_advisory/model.py +107 -0
  122. package/scripts/automatic_advisory/process_host.py +32 -0
  123. package/scripts/automatic_advisory/publisher.py +84 -0
  124. package/scripts/automatic_advisory/runner.py +399 -0
  125. package/scripts/automatic_advisory/state.py +116 -0
  126. package/scripts/automatic_advisory/window_flags.py +41 -0
  127. package/scripts/automatic_advisory/windows_job.py +122 -0
  128. package/scripts/check.ps1 +0 -1
  129. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  130. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  131. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  132. package/scripts/codex_compat_materializer.py +99 -13
  133. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  134. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +35 -43
  135. package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +10 -10
  136. package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +14 -1
  137. package/scripts/local_report_cli.py +184 -0
  138. package/scripts/local_report_core.py +247 -0
  139. package/scripts/local_report_publisher.py +12 -0
  140. package/scripts/local_report_validation.py +357 -0
  141. package/scripts/local_verification/__init__.py +23 -0
  142. package/scripts/local_verification/check_runner.py +364 -0
  143. package/scripts/local_verification/check_support.py +99 -0
  144. package/scripts/local_verification/cli.py +158 -0
  145. package/scripts/local_verification/command_runner.py +84 -0
  146. package/scripts/local_verification/config/__init__.py +1 -0
  147. package/scripts/local_verification/config/constants.py +89 -0
  148. package/scripts/local_verification/config/timing.py +1 -0
  149. package/scripts/local_verification/git_state.py +146 -0
  150. package/scripts/local_verification/manifest.py +224 -0
  151. package/scripts/local_verification/model.py +174 -0
  152. package/scripts/local_verification/runner.py +234 -0
  153. package/scripts/policy_lint/adapter_detectors.py +13 -6
  154. package/scripts/policy_lint/adapter_pairing.py +58 -3
  155. package/scripts/policy_lint/adapters.py +7 -4
  156. package/scripts/policy_lint/config/approved_test_pairs.py +323 -0
  157. package/scripts/policy_lint/config/constants.py +5 -0
  158. package/scripts/policy_lint/engine.py +48 -4
  159. package/scripts/policy_lint/model.py +1 -0
  160. package/scripts/policy_lint/registry.py +1 -1
  161. package/scripts/policy_lint/selection.py +2 -1
  162. package/scripts/policy_lint/selection_git.py +2 -0
  163. package/scripts/pr_verification/__init__.py +1 -0
  164. package/scripts/pr_verification/branch_refs.py +114 -0
  165. package/scripts/pr_verification/config/__init__.py +1 -0
  166. package/scripts/pr_verification/config/constants.py +84 -0
  167. package/scripts/pr_verification/config/timing.py +5 -0
  168. package/scripts/pr_verification/github.py +137 -0
  169. package/scripts/pr_verification/github_api.py +376 -0
  170. package/scripts/pr_verification/github_labels.py +88 -0
  171. package/scripts/pr_verification/github_parsing.py +182 -0
  172. package/scripts/pr_verification/github_transport.py +91 -0
  173. package/scripts/pr_verification/lock.py +122 -0
  174. package/scripts/pr_verification/model.py +43 -0
  175. package/scripts/pr_verification/requirements.txt +1 -0
  176. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  177. package/scripts/shared_tree_paths.py +32 -3
  178. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +97 -0
  179. package/scripts/test_shared_tree_paths.py +33 -0
  180. package/scripts/tests/test-audit-hooks-cli.mjs +150 -0
  181. package/scripts/tests/test-audit-hooks.mjs +94 -2
  182. package/scripts/tests/test_automatic_advisory.py +376 -0
  183. package/scripts/tests/test_automatic_advisory_job_cleanup.py +71 -0
  184. package/scripts/tests/test_automatic_advisory_polling.py +216 -0
  185. package/scripts/tests/test_automatic_advisory_recovery.py +320 -0
  186. package/scripts/tests/test_automatic_advisory_repairs.py +400 -0
  187. package/scripts/tests/test_automatic_advisory_settings.py +48 -0
  188. package/scripts/tests/test_automatic_advisory_window_flags.py +163 -0
  189. package/scripts/tests/test_closed_pr_label.py +157 -0
  190. package/scripts/tests/test_codex_compat_materializer.py +189 -6
  191. package/scripts/tests/test_github_labels.py +101 -0
  192. package/scripts/tests/test_github_transport.py +125 -0
  193. package/scripts/tests/test_local_report_publisher.py +396 -0
  194. package/scripts/tests/test_local_report_publisher_cli.py +85 -0
  195. package/scripts/tests/test_local_verification.py +348 -0
  196. package/scripts/tests/test_local_verification_cli.py +98 -0
  197. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  198. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  199. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  200. package/scripts/tests/test_policy_lint_rules_pairing.py +163 -0
  201. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  202. package/scripts/tests/test_policy_lint_selection.py +25 -2
  203. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  204. package/scripts/tests/test_pr_verification_github.py +392 -0
  205. package/scripts/tests/test_pr_verification_lock.py +168 -0
  206. package/scripts/tests/test_rules.py +3 -7
  207. package/scripts/tests/test_verification_notice.py +347 -0
  208. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  209. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  210. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  211. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  212. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  213. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  214. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  215. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  216. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  217. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  218. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  219. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  220. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  221. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  222. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  223. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  224. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  225. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  226. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  227. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  228. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  229. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  230. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  231. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  232. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  233. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  234. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  235. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  236. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  237. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  238. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  239. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  240. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  241. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  242. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  243. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  244. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  245. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  246. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  247. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  248. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  249. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  250. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  251. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  252. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  253. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  254. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  255. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  256. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  257. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  258. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  259. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  260. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  261. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  262. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  263. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  264. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  265. package/.agents/skills/autoconverge/SKILL.md +0 -431
  266. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  267. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  268. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  269. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  270. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  271. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  272. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  273. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  274. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  275. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  276. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  277. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  278. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  279. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  280. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  281. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  282. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  283. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  284. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  285. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  286. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  287. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  288. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  289. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  290. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  291. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  292. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  293. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  294. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  295. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  296. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  297. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  298. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  299. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  300. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  301. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  302. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  303. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  304. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  305. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  306. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  307. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  308. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  309. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  310. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  311. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  312. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  313. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  314. package/.agents/skills/hitl/SKILL.md +0 -45
  315. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  316. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  317. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  318. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  319. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  320. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  321. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  322. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  323. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  324. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  325. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  326. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  327. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  328. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  329. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  330. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  331. package/.agents/skills/prototype/SKILL.md +0 -85
  332. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  333. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  334. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  335. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  336. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  337. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  338. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  339. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  340. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  341. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  342. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  343. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  344. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  345. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  346. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  347. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  348. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  349. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  350. package/.agents/skills/rebase/AGENTS.md +0 -1
  351. package/.agents/skills/rebase/SKILL.md +0 -178
  352. package/.agents/skills/review-router/SKILL.md +0 -51
  353. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  354. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  355. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  356. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  357. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  358. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  359. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  360. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  361. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  362. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  363. package/.agents/skills/review-tier/SKILL.md +0 -56
  364. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  365. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  366. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  367. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  368. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  369. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  370. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  371. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  372. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  373. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  374. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  375. package/.agents/skills/session-log/AGENTS.md +0 -1
  376. package/.agents/skills/session-log/SKILL.md +0 -170
  377. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  378. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  379. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  380. package/.agents/skills/session-tidy/SKILL.md +0 -191
  381. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  382. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  383. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  384. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  385. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  386. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  387. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  388. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  389. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  390. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  391. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  392. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  393. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  394. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  395. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  396. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  397. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  398. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  399. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  400. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  401. package/.agents/skills/update/AGENTS.md +0 -1
  402. package/.agents/skills/update/SKILL.md +0 -190
  403. package/_shared/pr-loop/AGENTS.md +0 -1
  404. package/_shared/pr-loop/audit-contract.md +0 -183
  405. package/_shared/pr-loop/audit-reply-template.md +0 -151
  406. package/_shared/pr-loop/code-rules-gate.md +0 -65
  407. package/_shared/pr-loop/fix-protocol.md +0 -60
  408. package/_shared/pr-loop/gh-payloads.md +0 -75
  409. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  410. package/_shared/pr-loop/precatch-rubric.md +0 -66
  411. package/_shared/pr-loop/preflight-proposal.md +0 -56
  412. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  413. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  414. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  415. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  416. package/_shared/pr-loop/state-schema.md +0 -45
  417. package/_shared/pr-loop/worker-spawn.md +0 -189
  418. package/hooks/blocking/ask_user_question_shape_blocker.py +0 -83
  419. package/hooks/blocking/bot_mention_comment_blocker.py +0 -76
  420. package/hooks/blocking/claude_md_orphan_file_blocker.py +0 -129
  421. package/hooks/blocking/cursor_cli_python_misfire_blocker.py +0 -108
  422. package/hooks/blocking/destructive_command_blocker.py +0 -2073
  423. package/hooks/blocking/fable_spawn_gate.py +0 -187
  424. package/hooks/blocking/luna_fast_mode_gate.py +0 -160
  425. package/hooks/blocking/nas_ssh_binary_enforcer.py +0 -163
  426. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +0 -260
  427. package/hooks/blocking/package_inventory_stale_blocker.py +0 -107
  428. package/hooks/blocking/pii_prevention_blocker.py +0 -365
  429. package/hooks/blocking/piped_pytest_blocker.py +0 -1223
  430. package/hooks/blocking/question_to_user_enforcer.py +0 -130
  431. package/hooks/blocking/send_user_file_open_locally_blocker.py +0 -71
  432. package/hooks/blocking/sensitive_file_protector.py +0 -167
  433. package/hooks/blocking/session_edit_stage_gate.py +0 -684
  434. package/hooks/blocking/session_handoff_blocker.py +0 -182
  435. package/hooks/blocking/shell_substitution_blocker.py +0 -350
  436. package/hooks/blocking/test_ask_user_question_shape.py +0 -69
  437. package/hooks/blocking/test_bot_mention_comment_blocker.py +0 -131
  438. package/hooks/blocking/test_claude_md_orphan_file_blocker.py +0 -1277
  439. package/hooks/blocking/test_cursor_cli_python_misfire_blocker.py +0 -208
  440. package/hooks/blocking/test_destructive_command_blocker.py +0 -2024
  441. package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +0 -105
  442. package/hooks/blocking/test_destructive_command_blocker_no_verify.py +0 -122
  443. package/hooks/blocking/test_destructive_command_blocker_patterns.py +0 -133
  444. package/hooks/blocking/test_fable_spawn_gate.py +0 -381
  445. package/hooks/blocking/test_inventory_deadlock_resolution.py +0 -154
  446. package/hooks/blocking/test_luna_fast_mode_gate.py +0 -211
  447. package/hooks/blocking/test_nas_ssh_binary_enforcer.py +0 -225
  448. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +0 -231
  449. package/hooks/blocking/test_package_inventory_stale_blocker.py +0 -382
  450. package/hooks/blocking/test_pii_prevention_blocker.py +0 -1222
  451. package/hooks/blocking/test_pii_prevention_windows_git_path.py +0 -41
  452. package/hooks/blocking/test_pii_write_surface_ephemeral.py +0 -221
  453. package/hooks/blocking/test_piped_pytest_blocker.py +0 -587
  454. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -233
  455. package/hooks/blocking/test_question_to_user_enforcer.py +0 -169
  456. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +0 -118
  457. package/hooks/blocking/test_sensitive_file_protector.py +0 -365
  458. package/hooks/blocking/test_session_edit_stage_gate.py +0 -537
  459. package/hooks/blocking/test_session_edit_stage_gate_staging.py +0 -64
  460. package/hooks/blocking/test_session_edit_stage_gate_support.py +0 -204
  461. package/hooks/blocking/test_session_edit_stage_gate_tracker.py +0 -116
  462. package/hooks/blocking/test_session_handoff_blocker.py +0 -318
  463. package/hooks/blocking/test_shell_substitution_blocker.py +0 -298
  464. package/hooks/blocking/test_unscoped_search_blocker.py +0 -102
  465. package/hooks/blocking/test_write_existing_file_blocker.py +0 -122
  466. package/hooks/blocking/tests/test_pii_prevention_blocker.py +0 -259
  467. package/hooks/blocking/unscoped_search_blocker.py +0 -391
  468. package/hooks/blocking/write_existing_file_blocker.py +0 -124
  469. package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +0 -19
  470. package/hooks/hooks_constants/cursor_cli_python_misfire_blocker_constants.py +0 -79
  471. package/hooks/hooks_constants/fable_spawn_gate_constants.py +0 -61
  472. package/hooks/hooks_constants/luna_fast_mode_gate_constants.py +0 -45
  473. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +0 -20
  474. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +0 -57
  475. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +0 -17
  476. package/hooks/hooks_constants/sensitive_file_protector_constants.py +0 -40
  477. package/hooks/hooks_constants/session_handoff_blocker_constants.py +0 -10
  478. package/hooks/hooks_constants/shell_substitution_blocker_constants.py +0 -80
  479. /package/.agents/skills/{_shared/pr-loop → session-continuity}/AGENTS.md +0 -0
  480. /package/{_shared/pr-loop → .agents/skills/session-continuity}/CLAUDE.md +0 -0
@@ -0,0 +1,303 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createHash } from 'node:crypto';
3
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, unlinkSync, utimesSync, writeFileSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ import { spawn, spawnSync } from 'node:child_process';
7
+ import { fileURLToPath } from 'node:url';
8
+ import test from 'node:test';
9
+ import { continuityHookConfiguration } from '../../../bin/install-session-continuity.mjs';
10
+
11
+ const sourceDirectory = dirname(fileURLToPath(import.meta.url));
12
+ const potetoText = '---\nname: Poteto Mode\n---\nPOTETO_SOURCE_EXPECTATION: prove the requested result.\n';
13
+ const secondText = 'SECOND_SKILL_EXPECTATION: measure twice before changing files.\n';
14
+ const sha256 = value => createHash('sha256').update(value).digest('hex');
15
+
16
+ function fixture(t, host) {
17
+ const root = mkdtempSync(join(tmpdir(), 'continuity contract '));
18
+ t.after(() => rmSync(root, { recursive: true, force: true }));
19
+ const skill = join(root, '.agents', 'skills', 'session-continuity');
20
+ mkdirSync(skill, { recursive: true });
21
+ for (const file of ['SKILL.md', 'continuity.mjs']) copyFileSync(join(sourceDirectory, file), join(skill, file));
22
+ const poteto = join(root, '.agents', 'skills', 'pstack', 'poteto-mode', 'SKILL.md');
23
+ mkdirSync(dirname(poteto), { recursive: true });
24
+ writeFileSync(poteto, potetoText);
25
+ const second = join(root, 'second-skill.md');
26
+ writeFileSync(second, secondText);
27
+ const script = join(skill, 'continuity.mjs');
28
+ const configPath = join(root, host === 'claude' ? 'settings.json' : 'hooks.json');
29
+ writeFileSync(configPath, JSON.stringify({ hooks: continuityHookConfiguration(host, script) }));
30
+ const env = { ...process.env };
31
+ delete env.CDE_CONTINUITY_ROOT;
32
+ delete env.CDE_POTETO_SOURCE;
33
+ const pathFor = session => join(root, '.agents', 'state', 'session-continuity', host, `${sha256(session)}.json`);
34
+ const cli = (command, session, data, expectedStatus = 0) => {
35
+ const result = spawnSync(process.execPath, [script, command, host, session], { input: JSON.stringify(data || {}), encoding: 'utf8', env });
36
+ assert.equal(result.status, expectedStatus, result.stderr || result.stdout);
37
+ return expectedStatus ? result.stderr : JSON.parse(result.stdout);
38
+ };
39
+ const fire = (event, session, fields = {}) => {
40
+ const payload = { hook_event_name: event, session_id: session, cwd: root, ...fields };
41
+ const config = JSON.parse(readFileSync(configPath, 'utf8'));
42
+ const groups = config.hooks[event] || [];
43
+ const matching = groups.filter(group => !group.matcher || new RegExp(group.matcher).test(event === 'SessionStart' ? fields.source : fields.command_name));
44
+ return matching.flatMap(group => group.hooks.map(handler => {
45
+ const result = spawnSync(handler.command, { shell: true, input: JSON.stringify(payload), encoding: 'utf8', env });
46
+ assert.equal(result.status, 0, result.stderr);
47
+ return JSON.parse(result.stdout);
48
+ }));
49
+ };
50
+ const submit = (session, prompt) => fire('UserPromptSubmit', session, { prompt })[0];
51
+ const read = session => JSON.parse(readFileSync(pathFor(session), 'utf8'));
52
+ return { root, script, skill, poteto, second, pathFor, cli, fire, submit, read };
53
+ }
54
+
55
+ for (const host of ['claude', 'codex']) {
56
+ test(`${host}: configured invocation emits complete instructions, writes and reads back, restores without a path`, t => {
57
+ const f = fixture(t, host);
58
+ assert.deepEqual(f.fire('SessionStart', 'session-a', { source: 'startup' }), [{}]);
59
+ assert.equal(existsSync(f.pathFor('session-a')), false);
60
+ const prefix = host === 'codex' ? '$pstack:poteto-mode' : '/pstack:poteto-mode';
61
+ const prompt = `${prefix} for this entire session\nFinish the sample task. Keep changes local. Use second-skill for this task.`;
62
+ const output = f.submit('session-a', prompt);
63
+ assert.ok(output.systemMessage.includes(f.pathFor('session-a')));
64
+ const context = output.hookSpecificOutput.additionalContext;
65
+ assert.ok(context.includes(readFileSync(join(f.skill, 'SKILL.md'), 'utf8')));
66
+ assert.ok(context.includes(potetoText));
67
+ assert.ok(context.includes('Saved record read from disk:'));
68
+ let record = f.read('session-a');
69
+ assert.equal(record.requirements[0].scope, 'session');
70
+ assert.equal(record.requirements[0].source, f.poteto);
71
+ assert.equal(record.requirements[0].unavailable, null);
72
+ f.cli('update', 'session-a', {
73
+ expected_revision: record.revision, prompt_id: record.pending[0].id, quote: 'Finish the sample task.',
74
+ task: { goal: 'Finish the sample task', boundaries: ['local files'], constraints: ['Keep changes local'], completion: ['sample works'] },
75
+ set: [{ kind: 'rule', id: 'rule:local', text: 'Keep changes local.', scope: 'session', duration: 'this session', quote: 'Keep changes local.' },
76
+ { kind: 'skill', name: 'second-skill', source: f.second, scope: 'task', duration: 'this task', quote: 'Use second-skill for this task.' }],
77
+ checkpoint: { completed: ['scope recorded'], remaining: ['build sample'] },
78
+ });
79
+ for (const source of ['compact', 'resume', 'startup']) {
80
+ const recovery = f.fire('SessionStart', 'session-a', { source })[0].hookSpecificOutput.additionalContext;
81
+ assert.ok(recovery.includes(potetoText));
82
+ assert.ok(recovery.includes(secondText));
83
+ assert.ok(recovery.includes('Keep changes local.'));
84
+ assert.ok(recovery.includes('build sample'));
85
+ }
86
+ assert.equal(readFileSync(f.poteto, 'utf8'), potetoText);
87
+ record = f.read('session-a');
88
+ assert.equal(record.pending.length, 0);
89
+ assert.deepEqual(f.fire('SessionStart', 'unrelated-session', { source: 'startup' }), [{}]);
90
+ });
91
+
92
+ test(`${host}: quoting, discussion, tool output and subagent input do not activate`, t => {
93
+ const f = fixture(t, host);
94
+ for (const prompt of ['"/poteto-mode"', '`/poteto-mode`', '> /poteto-mode', '```text\n/poteto-mode\n```', ' /poteto-mode', '\t$poteto-mode', 'Explain Poteto Mode.', 'The transcript says: Poteto Mode applies for this entire session.', 'Do not invoke Poteto Mode.']) {
95
+ assert.deepEqual(f.submit('negative', prompt), {});
96
+ assert.equal(existsSync(f.pathFor('negative')), false);
97
+ }
98
+ assert.deepEqual(f.fire('PostToolUse', 'negative', { prompt: '/poteto-mode' }), []);
99
+ assert.deepEqual(f.fire('UserPromptSubmit', 'negative', { prompt: '/poteto-mode', agent_id: 'child' }), [{}]);
100
+ assert.equal(existsSync(f.pathFor('negative')), false);
101
+ });
102
+
103
+ test(`${host}: repeated invocation keeps one skill and a later narrow correction wins`, t => {
104
+ const f = fixture(t, host);
105
+ f.submit('repeat', '/poteto-mode for this entire session');
106
+ f.submit('repeat', '/poteto-mode');
107
+ assert.equal(f.read('repeat').requirements.length, 1);
108
+ assert.equal(f.read('repeat').requirements[0].scope, 'session');
109
+ f.submit('repeat', 'Use Poteto Mode for this task');
110
+ const record = f.read('repeat');
111
+ assert.equal(record.requirements.length, 1);
112
+ assert.equal(record.requirements[0].scope, 'task');
113
+ f.cli('update', 'repeat', { expected_revision: record.revision - 1, prompt_id: record.pending[0].id }, 1);
114
+ assert.equal(f.read('repeat').revision, record.revision);
115
+ });
116
+
117
+ test(`${host}: default task scope ends and explicit session scope survives a new task`, t => {
118
+ const f = fixture(t, host);
119
+ f.submit('scope', '/poteto-mode\nUse short replies for this session.');
120
+ let record = f.read('scope');
121
+ assert.equal(record.requirements[0].scope, 'task');
122
+ f.cli('update', 'scope', { expected_revision: record.revision, prompt_id: record.pending[0].id,
123
+ set: [{ kind: 'rule', id: 'rule:short', text: 'Use short replies', scope: 'session', duration: 'this session', quote: 'Use short replies for this session.' }] });
124
+ f.submit('scope', 'Start the next task.');
125
+ record = f.read('scope');
126
+ f.cli('update', 'scope', { expected_revision: record.revision, prompt_id: record.pending[0].id, quote: 'Start the next task.', new_task: true,
127
+ task: { goal: 'next task', boundaries: [], constraints: [], completion: ['verified'] } });
128
+ const recovery = f.fire('SessionStart', 'scope', { source: 'compact' })[0].hookSpecificOutput.additionalContext;
129
+ assert.ok(recovery.includes('Use short replies'));
130
+ assert.equal(recovery.includes(potetoText), false);
131
+ });
132
+
133
+ test(`${host}: source changes are compared and missing sources never use remembered contents`, t => {
134
+ const f = fixture(t, host);
135
+ f.submit('source', '/poteto-mode');
136
+ writeFileSync(f.poteto, potetoText.replace('prove the requested result', 'inspect the current result'));
137
+ const changed = f.fire('SessionStart', 'source', { source: 'compact' })[0].hookSpecificOutput.additionalContext;
138
+ assert.ok(changed.includes('CHANGED skill'));
139
+ assert.ok(changed.includes('before_excerpt'));
140
+ assert.ok(changed.includes('inspect the current result'));
141
+ unlinkSync(f.poteto);
142
+ const missing = f.fire('SessionStart', 'source', { source: 'resume' })[0].hookSpecificOutput.additionalContext;
143
+ assert.ok(missing.includes('UNAVAILABLE skill'));
144
+ assert.equal(missing.includes('POTETO_SOURCE_EXPECTATION'), false);
145
+ });
146
+
147
+ test(`${host}: sessions in the same repository never select each other's newer record`, t => {
148
+ const f = fixture(t, host);
149
+ f.submit('a', '/poteto-mode for this task');
150
+ f.submit('b', '/poteto-mode for this entire session');
151
+ const old = new Date('2000-01-01');
152
+ utimesSync(f.pathFor('b'), old, old);
153
+ assert.notEqual(f.pathFor('a'), f.pathFor('b'));
154
+ assert.equal(f.cli('show', 'a').record.requirements[0].scope, 'task');
155
+ assert.equal(f.cli('show', 'b').record.requirements[0].scope, 'session');
156
+ assert.ok(f.fire('SessionStart', 'b', { source: 'resume' })[0].hookSpecificOutput.additionalContext.includes(f.pathFor('b')));
157
+ });
158
+
159
+ test(`${host}: deactivation survives compaction and restart; explicit invocation starts a fresh set`, t => {
160
+ const f = fixture(t, host);
161
+ f.submit('off', '/poteto-mode for this entire session');
162
+ const disabled = f.submit('off', '/session-continuity off');
163
+ assert.ok(disabled.systemMessage.includes('deactivated'));
164
+ if (host === 'claude') f.fire('UserPromptExpansion', 'off', { expansion_type: 'slash_command', command_name: 'session-continuity', prompt: '/session-continuity off' });
165
+ assert.equal(f.read('off').status, 'inactive');
166
+ assert.deepEqual(f.fire('SessionStart', 'off', { source: 'compact' }), [{}]);
167
+ assert.deepEqual(f.fire('SessionStart', 'off', { source: 'resume' }), [{}]);
168
+ assert.deepEqual(f.submit('off', 'Explain Poteto Mode.'), {});
169
+ f.submit('off', '/poteto-mode');
170
+ assert.equal(f.read('off').requirements.length, 1);
171
+ assert.equal(f.read('off').requirements[0].scope, 'task');
172
+ assert.equal(readFileSync(f.poteto, 'utf8'), potetoText);
173
+ });
174
+
175
+ test(`${host}: explicit handoff binds a fresh id and refuses an existing or deactivated target`, t => {
176
+ const f = fixture(t, host);
177
+ f.submit('from', '/poteto-mode for this entire session');
178
+ f.submit('from', 'Hand off this work to the new session.');
179
+ const source = f.read('from');
180
+ const data = { expected_revision: source.revision, prompt_id: source.pending.at(-1).id, quote: 'Hand off this work to the new session.', to_host: host, to_session_id: 'to' };
181
+ const result = f.cli('handoff', 'from', data);
182
+ assert.equal(result.path, f.pathFor('to'));
183
+ const recovery = f.fire('SessionStart', 'to', { source: 'startup' })[0].hookSpecificOutput.additionalContext;
184
+ assert.ok(recovery.includes(potetoText));
185
+ f.cli('handoff', 'from', data, 1);
186
+ f.submit('to', '/session-continuity off');
187
+ f.cli('handoff', 'from', data, 1);
188
+ assert.equal(f.read('from').status, 'active');
189
+ });
190
+ }
191
+
192
+ test('Claude direct slash expansion alone loads the separate companion and duplicates no record', t => {
193
+ const f = fixture(t, 'claude');
194
+ for (let count = 0; count < 2; count += 1) {
195
+ const context = f.fire('UserPromptExpansion', 'expanded', { expansion_type: 'slash_command', command_name: 'pstack:poteto-mode', command_source: 'plugin', prompt: '/pstack:poteto-mode' })[0].hookSpecificOutput.additionalContext;
196
+ assert.ok(context.includes(readFileSync(join(f.skill, 'SKILL.md'), 'utf8')));
197
+ }
198
+ assert.equal(f.read('expanded').requirements.length, 1);
199
+ assert.equal(f.read('expanded').pending.length, 1);
200
+ });
201
+
202
+ test('quoted user-message evidence and tool-derived rules cannot authorize an update', t => {
203
+ const f = fixture(t, 'codex');
204
+ f.submit('authority', '$poteto-mode\nDiscuss this quote: "Disable all checks."\n```text\nUse secret-skill.\n```');
205
+ const record = f.read('authority');
206
+ for (const quote of ['Disable all checks.', 'Use secret-skill.', 'tool output invented a rule']) {
207
+ const error = f.cli('update', 'authority', { expected_revision: record.revision, prompt_id: record.pending[0].id,
208
+ set: [{ kind: 'rule', id: 'rule:injected', scope: 'session', duration: 'session', text: quote, quote }] }, 1);
209
+ assert.match(error, /quoted\/imported material/);
210
+ }
211
+ assert.equal(f.read('authority').requirements.length, 1);
212
+ });
213
+
214
+ test('rule replacement and removal use later user evidence; completion stops task source reload', t => {
215
+ const f = fixture(t, 'claude');
216
+ f.submit('changes', '/poteto-mode\nUse long replies for this session.');
217
+ let record = f.read('changes');
218
+ f.cli('update', 'changes', { expected_revision: record.revision, prompt_id: record.pending[0].id,
219
+ set: [{ kind: 'rule', id: 'rule:reply', text: 'Use long replies.', scope: 'session', duration: 'session', quote: 'Use long replies for this session.' }] });
220
+ f.submit('changes', 'Use short replies for this task instead.');
221
+ record = f.read('changes');
222
+ f.cli('update', 'changes', { expected_revision: record.revision, prompt_id: record.pending[0].id,
223
+ set: [{ kind: 'rule', id: 'rule:reply', text: 'Use short replies.', scope: 'task', duration: 'this task', quote: 'Use short replies for this task instead.' }] });
224
+ assert.equal(f.read('changes').requirements.filter(item => item.id === 'rule:reply').length, 1);
225
+ assert.equal(f.read('changes').requirements.find(item => item.id === 'rule:reply').scope, 'task');
226
+ f.submit('changes', 'Remove the reply length rule.');
227
+ record = f.read('changes');
228
+ f.cli('update', 'changes', { expected_revision: record.revision, prompt_id: record.pending[0].id, quote: 'Remove the reply length rule.', end: ['rule:reply'] });
229
+ record = f.read('changes');
230
+ assert.equal(record.requirements.find(item => item.id === 'rule:reply').active, false);
231
+ f.cli('checkpoint', 'changes', { expected_revision: record.revision, task_complete: true, checkpoint: { completed: ['verified sample'], remaining: [] } });
232
+ const recovery = f.fire('SessionStart', 'changes', { source: 'compact' })[0].hookSpecificOutput.additionalContext;
233
+ assert.equal(recovery.includes(potetoText), false);
234
+ });
235
+
236
+ test('a busy record blocks prompt processing, preserves state, and supports a safe retry', t => {
237
+ const f = fixture(t, 'claude');
238
+ f.submit('busy', '/poteto-mode');
239
+ const before = readFileSync(f.pathFor('busy'), 'utf8');
240
+ writeFileSync(f.pathFor('busy') + '.lock', 'test-writer');
241
+ const blocked = f.submit('busy', 'Use short replies for this session.');
242
+ assert.equal(blocked.decision, 'block');
243
+ assert.match(blocked.reason, /Record busy/);
244
+ assert.equal(readFileSync(f.pathFor('busy'), 'utf8'), before);
245
+ unlinkSync(f.pathFor('busy') + '.lock');
246
+ f.submit('busy', 'Use short replies for this session.');
247
+ assert.equal(f.read('busy').pending.length, 2);
248
+ });
249
+
250
+ test('clear deactivates a reused host id rather than inheriting an unrelated task', t => {
251
+ const f = fixture(t, 'claude');
252
+ f.submit('clear', '/poteto-mode for this entire session');
253
+ f.fire('SessionStart', 'clear', { source: 'clear' });
254
+ assert.equal(f.read('clear').status, 'inactive');
255
+ assert.deepEqual(f.fire('SessionStart', 'clear', { source: 'startup' }), [{}]);
256
+ });
257
+
258
+ test('missing host identity and corrupt records produce visible recovery failures', t => {
259
+ const f = fixture(t, 'codex');
260
+ const missing = f.fire('UserPromptSubmit', '', { prompt: '$poteto-mode' })[0];
261
+ assert.equal(missing.decision, 'block');
262
+ f.submit('corrupt', '$poteto-mode');
263
+ writeFileSync(f.pathFor('corrupt'), '{bad json');
264
+ const failure = f.fire('SessionStart', 'corrupt', { source: 'resume' })[0];
265
+ assert.match(failure.systemMessage, /Session continuity failed/);
266
+ assert.match(failure.hookSpecificOutput.additionalContext, /Stop dependent work/);
267
+ });
268
+
269
+ for (const host of ['claude', 'codex']) {
270
+ test(`${host}: two simultaneous configured callbacks keep distinct session records`, async t => {
271
+ const f = fixture(t, host);
272
+ const configuration = continuityHookConfiguration(host, f.script);
273
+ const command = configuration.UserPromptSubmit[0].hooks[0].command;
274
+ const fire = (session, scope) => new Promise((resolve, reject) => {
275
+ const env = { ...process.env };
276
+ delete env.CDE_CONTINUITY_ROOT;
277
+ delete env.CDE_POTETO_SOURCE;
278
+ const child = spawn(command, { shell: true, env });
279
+ let stdout = '';
280
+ let stderr = '';
281
+ child.stdout.on('data', chunk => { stdout += chunk; });
282
+ child.stderr.on('data', chunk => { stderr += chunk; });
283
+ child.on('error', reject);
284
+ child.on('close', code => code ? reject(new Error(stderr)) : resolve(JSON.parse(stdout)));
285
+ child.stdin.end(JSON.stringify({ hook_event_name: 'UserPromptSubmit', session_id: session, cwd: f.root, prompt: `/poteto-mode for this ${scope}` }));
286
+ });
287
+ await Promise.all([fire('parallel-a', 'task'), fire('parallel-b', 'entire session')]);
288
+ assert.equal(f.read('parallel-a').requirements[0].scope, 'task');
289
+ assert.equal(f.read('parallel-b').requirements[0].scope, 'session');
290
+ assert.notEqual(f.pathFor('parallel-a'), f.pathFor('parallel-b'));
291
+ });
292
+ }
293
+
294
+ test('a new explicit invocation after task completion starts a distinct task without restoring ended rules', t => {
295
+ const f = fixture(t, 'claude');
296
+ f.submit('completed', '/poteto-mode');
297
+ const before = f.read('completed');
298
+ f.cli('checkpoint', 'completed', { expected_revision: before.revision, task_complete: true, checkpoint: { completed: ['verified'], remaining: [] } });
299
+ const output = f.submit('completed', '/poteto-mode');
300
+ assert.notEqual(f.read('completed').task.id, before.task.id);
301
+ assert.equal(f.read('completed').task.completed, false);
302
+ assert.ok(output.hookSpecificOutput.additionalContext.includes(potetoText));
303
+ });
@@ -1,202 +1,9 @@
1
1
  ---
2
2
  name: skill-builder
3
3
  disable-model-invocation: true
4
- description: >-
5
- Skill lifecycle: classify, scaffold, write via the skill-writer-agent, self-audit, compose
6
- sub-skills, polish description triggers, enforce deterministic scripts. Triggers:
7
- build a skill, new skill workflow, improve this skill, optimize skill description,
8
- skill development lifecycle, skill modularity, skill composition, description
9
- trigger catalog, deterministic skill scripts.
4
+ description: Placeholder for the skill-builder rework to follow pstack philosophy.
10
5
  ---
11
6
 
12
- # Skill Builder
7
+ # Skill builder
13
8
 
14
- **Core principle:** Best-practice-driven craftsman. Knows every proven pattern, applies them intentionally, self-audits after building. The expert that enforces craft standards.
15
-
16
- Sources: [Anthropic best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices), [Lessons from Building Claude Code](references/thariq-x-post-skills.json), model skills (bugteam, pr-converge).
17
-
18
- ## Gotchas
19
-
20
- Highest-signal content. Append a bullet each time a skill build fails in a new way.
21
-
22
- > "The highest-signal content in any skill is the Gotchas section. These sections should be built up from common failure points that Claude runs into when using your skill."
23
-
24
- - Story-form `description` burns always-on context and weakens selection — rewrite to capability stem + `Triggers:` list (`description-field.md`).
25
- - Multi-capability packages fail modularity audit — split or thin orchestrator + named sub-skills (`skill-modularity.md`).
26
- - Skipping the composition plan before Write reintroduces silent reimplementation of peer skills.
27
- - Deterministic steps written only as prose (fenced source, giant `rg` lines, multi-step mechanical sequences) fail audit — extract to `scripts/` / `workflow/` / `templates/` / `reference/` (`deterministic-elements.md`).
28
- - Markdown `- [ ]` checklists as the agent's progress board fail audit when a task tool exists — seed tasks via `TaskCreate` / `TodoWrite` (`deterministic-elements.md`).
29
-
30
- ## When this skill applies
31
-
32
- Trigger for requests to **build**, **improve**, or **polish** a skill. This skill orchestrates the process — it classifies, scaffolds, gathers context, delegates writing to the `skill-writer-agent` agent, and self-audits the result.
33
-
34
- For quick skill syntax questions or one-off SKILL.md edits, spawn the `skill-writer-agent` agent directly.
35
-
36
- **Refusal cases — first match wins:**
37
-
38
- - **No clear task or domain.** Respond exactly: `What should this skill do? Give me a one-sentence description of the capability.`
39
-
40
- ## The Process
41
-
42
- Each workflow file provides step-by-step instructions. After routing below, open the corresponding workflow file and follow it.
43
-
44
- ### Routing
45
-
46
- Assess the user’s intent:
47
-
48
- **Creating a new skill?**
49
- Read `${CLAUDE_SKILL_DIR}/workflows/new-skill.md` and follow it.
50
-
51
- **Improving an existing skill?**
52
- Read `${CLAUDE_SKILL_DIR}/workflows/improve-skill.md` and follow it.
53
-
54
- **Final polish only (description optimization, trigger audit)?**
55
- Read `${CLAUDE_SKILL_DIR}/workflows/polish-skill.md` and follow it.
56
-
57
- **Ambiguous?** Ask: "Are you creating a new skill, improving an existing one, or doing a final polish pass?"
58
-
59
- ### The Claude A / Claude B pattern
60
-
61
- You and the user are **Claude A** — the expert who designs and refines the skill. Subagents running the built skill on real tasks are **Claude B** — the agent using the skill to perform actual work.
62
-
63
- > "Work with one instance of Claude (‘Claude A’) to create a Skill that is used by other instances (‘Claude B’). Claude A helps you design and refine instructions, while Claude B tests them in real tasks."
64
-
65
- The feedback loop: observe Claude B’s behavior, bring insights back, refine the skill, test again.
66
-
67
- ## Skill type routing
68
-
69
- > "After cataloging all of our skills, we noticed they cluster into a few recurring categories."
70
-
71
- Classify into one of 9 types — type sets folder structure. Taxonomy and layouts: [`references/skill-types.md`](references/skill-types.md).
72
-
73
- ## Principles
74
-
75
- These are non-negotiable. Every skill must satisfy them. Enforce via [`references/self-audit-checklist.md`](references/self-audit-checklist.md).
76
-
77
- ### Concision and defaults
78
-
79
- > "Default assumption: Claude is already very smart. Only add context Claude doesn’t already have."
80
-
81
- > "Don’t State the Obvious — focus on information that pushes Claude out of its normal way of thinking."
82
-
83
- Challenge each sentence: "Does Claude really need this?"
84
-
85
- ### Degree of freedom
86
-
87
- > "Match the level of specificity to the task’s fragility and variability."
88
-
89
- High freedom (text guidance) for open fields. Low freedom (exact scripts, no parameters) for narrow bridges with cliffs.
90
-
91
- > "Avoid Railroading Claude — give Claude the information it needs, but give it the flexibility to adapt."
92
-
93
- ### Progressive disclosure
94
-
95
- Hub pattern, line caps, one-level references, TOC and path rules: [`references/progressive-disclosure.md`](references/progressive-disclosure.md).
96
-
97
- ### Modularity and composition
98
-
99
- One skill = one capability. Multi-step work invokes **sub-skills** (peer skills) by name. Prefer compose over reimplement. Full rules: [`references/skill-modularity.md`](references/skill-modularity.md).
100
-
101
- > "You can just reference other skills by name, and the model will invoke them if they are installed."
102
-
103
- New-skill Gather records a composition plan before write. Self-audit modularity items are mandatory.
104
-
105
- ### Description field (trigger catalog)
106
-
107
- The frontmatter `description` is **selection metadata** pre-loaded for every skill. Write a **trigger catalog**, not a story: short capability stem + concrete trigger phrases. No narrative, benefits language, or process dump.
108
-
109
- Full rules: [`references/description-field.md`](references/description-field.md). Polish workflow Step 1 is the dedicated rewrite pass.
110
-
111
- > "The description field is not a summary — it’s a description of when to trigger."
112
-
113
- ### Gotchas
114
-
115
- Mandatory highest-signal section (see Gotchas above). Capture real failure modes; self-audit requires the section present and actionable.
116
-
117
- ### Templates and examples
118
-
119
- > "Provide templates for output format" and "Examples help Claude understand the desired style and level of detail more clearly than descriptions alone."
120
-
121
- Use the template pattern for structured outputs. Use the examples pattern (input/output pairs) for style-dependent work.
122
-
123
- ### Workflows and task seeds
124
-
125
- Multi-step required work is a **task seed list** (plain bullets in a reference file) plus an instruction to register each item on the host task tool (`TaskCreate`, `TodoWrite`, or equivalent). Agents work the task list and mark complete with evidence.
126
-
127
- Do **not** ship markdown `- [ ]` boards as the completion protocol when a task tool is available. Do **not** say "copy this checklist into your response and check it off."
128
-
129
- Quality-critical operations still use feedback loops (run validator → fix → repeat). Spec: [`references/deterministic-elements.md`](references/deterministic-elements.md) (Task-tool tracking).
130
-
131
- ### Scripts
132
-
133
- > "Handle error conditions rather than punting to Claude." "Make clear whether Claude should execute the script or read it as reference."
134
-
135
- > "One of the most powerful tools you can give Claude is code — letting Claude spend its turns on composition rather than reconstructing boilerplate."
136
-
137
- ### Deterministic elements (mandatory classification)
138
-
139
- Any skill element that is **deterministic** (same inputs → same outputs; machine-checkable success) ships as code, a fixed artifact, or a **session task seed** — not prose-only steps or markdown checkbox boards. Judgment, routing, and refusals stay in markdown.
140
-
141
- Full rules, inventory table, task-tool tracking, CODE_RULES bar for skill scripts, and anti-patterns: [`references/deterministic-elements.md`](references/deterministic-elements.md).
142
-
143
- New-skill Gather records a deterministic-elements inventory before write. Self-audit items register as session tasks and are mandatory on every delivery (pure-judgment skills mark script rows N/A with evidence).
144
-
145
- ### Setup and memory
146
-
147
- > "Think through the Setup — some skills may need to be set up with context from the user. A good pattern is to store this in a config.json file."
148
-
149
- > "Data stored in the skill directory may be deleted when you upgrade the skill, so store persistent data in `${CLAUDE_PLUGIN_DATA}`."
150
-
151
- ### Constraints and refusal cases
152
-
153
- > bugteam pattern — non-negotiables separated from guidance, with design rationale. Explicit "first match wins" refusal conditions.
154
-
155
- ### Anti-patterns
156
-
157
- > No Windows paths. Don’t offer too many options — provide a default with escape hatch. Avoid time-sensitive claims. Use consistent terminology. No deeply nested references.
158
-
159
- Also: story-form descriptions; monolith multi-capability skills; silent reimplementation of peer skills; nested folders used as fake sub-skills; deterministic logic only in prose or fenced source; markdown `- [ ]` as the agent's work tracker.
160
-
161
- ## Self-audit
162
-
163
- After every build, improvement, or polish pass, load `${CLAUDE_SKILL_DIR}/references/self-audit-checklist.md`, **register every bullet as a session task**, and complete each with evidence. Every item must pass before delivery. Fix failures, then re-audit.
164
-
165
- ## Delegation to skill-writer-agent
166
-
167
- skill-builder orchestrates; the `skill-writer-agent` agent authors. The caller spawns it with `Agent(subagent_type="skill-writer-agent", ...)`. The handoff packet from Step 4 must include:
168
-
169
- - Skill type and folder structure
170
- - Gap analysis or observation findings (composition plan + description triggers + deterministic inventory)
171
- - Degree of freedom assessment
172
- - Initial gotchas
173
- - Composition plan: related skills, sub-skills to invoke, split decisions
174
- - Description trigger catalog: capability stem + trigger phrases (not prose)
175
- - Deterministic elements inventory: each process step classified; code paths + paired tests
176
- - Any constraints
177
-
178
- See `${CLAUDE_SKILL_DIR}/references/delegation-map.md` for exact patterns.
179
-
180
- ## File index
181
-
182
- | File | Purpose |
183
- |------|---------|
184
- | `SKILL.md` | This hub — principles, process, routing, file index |
185
- | `references/skill-types.md` | 9-type taxonomy with folder structures per type |
186
- | `references/progressive-disclosure.md` | Folder conventions, hub pattern, hard rules |
187
- | `references/skill-modularity.md` | Cross-skill modularity, sub-skills, composition plan |
188
- | `references/description-field.md` | Description as trigger catalog (not story prose) |
189
- | `references/deterministic-elements.md` | Deterministic steps as code/task seeds; CODE_RULES; no markdown checkbox boards |
190
- | `references/self-audit-checklist.md` | Post-build audit task seeds (register via TaskCreate / TodoWrite) |
191
- | `references/delegation-map.md` | Subagent handoff patterns and transcript guidance |
192
- | `workflows/new-skill.md` | Full lifecycle for new skills (6 steps) |
193
- | `workflows/improve-skill.md` | Observation-first flow for existing skills (6 steps) |
194
- | `workflows/polish-skill.md` | Description trigger-catalog audit and final validation (5 steps) |
195
- | `templates/gap-analysis.md` | Gaps, composition plan, description triggers, deterministic inventory |
196
-
197
- ## Folder map
198
-
199
- - `SKILL.md` — hub.
200
- - `references/` — best-practice specifications and the audit checklist.
201
- - `workflows/` — step-by-step workflows for each lifecycle phase.
202
- - `templates/` — reusable templates for skill artifacts.
9
+ TODO: Rework to follow pstack philosophy.
@@ -74,10 +74,3 @@ def test_success_emits_one_json_record(
74
74
  assert exit_code == 0
75
75
  assert sync_record["status"] == "not_submodule"
76
76
  assert captured_error == ""
77
-
78
-
79
- def test_native_post_commit_source_and_test_are_removed() -> None:
80
- hook_directory = Path(__file__).resolve().parents[4] / "hooks" / "git-hooks"
81
-
82
- assert not (hook_directory / "post_commit.py").exists()
83
- assert not (hook_directory / "test_post_commit.py").exists()