prizmkit 1.1.153 → 1.1.155

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 (178) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/codex/skill-adapter.js +1 -1
  3. package/bundled/adapters/pi/skill-adapter.js +2 -1
  4. package/bundled/dev-pipeline/.env.example +2 -6
  5. package/bundled/dev-pipeline/README.md +120 -113
  6. package/bundled/dev-pipeline/assets/skill-subagent-integration.md +1 -1
  7. package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +355 -15
  8. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +189 -110
  9. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +146 -111
  10. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +4 -20
  11. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
  12. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +0 -1
  13. package/bundled/dev-pipeline/prizmkit_runtime/paths.py +0 -3
  14. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +122 -15
  15. package/bundled/dev-pipeline/prizmkit_runtime/reset_preserve.py +1 -1
  16. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
  17. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +1 -10
  18. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
  19. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +139 -74
  20. package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
  21. package/bundled/dev-pipeline/prizmkit_runtime/status.py +106 -1
  22. package/bundled/dev-pipeline/prizmkit_runtime/test_result.py +64 -11
  23. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +145 -367
  24. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +91 -62
  25. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +105 -69
  26. package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +2 -2
  27. package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
  28. package/bundled/dev-pipeline/scripts/update-bug-status.py +197 -71
  29. package/bundled/dev-pipeline/scripts/update-checkpoint.py +77 -16
  30. package/bundled/dev-pipeline/scripts/update-feature-status.py +46 -121
  31. package/bundled/dev-pipeline/scripts/update-refactor-status.py +46 -123
  32. package/bundled/dev-pipeline/scripts/utils.py +119 -0
  33. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +22 -27
  34. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +71 -104
  35. package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +3 -2
  36. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +59 -111
  37. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +37 -72
  38. package/bundled/dev-pipeline/templates/sections/artifact-manifest.md +39 -0
  39. package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +3 -1
  40. package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +8 -25
  41. package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +3 -3
  42. package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +2 -2
  43. package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +3 -3
  44. package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +2 -2
  45. package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +4 -4
  46. package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +0 -1
  47. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +7 -4
  48. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +14 -27
  49. package/bundled/dev-pipeline/templates/sections/feature-completion-summary.md +20 -0
  50. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -71
  51. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
  52. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +3 -3
  53. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -4
  54. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +5 -17
  55. package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +3 -1
  56. package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +10 -23
  57. package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +2 -2
  58. package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +2 -2
  59. package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +3 -3
  60. package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +2 -2
  61. package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +7 -7
  62. package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +0 -1
  63. package/bundled/dev-pipeline/templates/sections/retrospective.md +12 -0
  64. package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +35 -0
  65. package/bundled/dev-pipeline/templates/session-status-schema.json +45 -62
  66. package/bundled/dev-pipeline/tests/test_auto_skip.py +111 -32
  67. package/bundled/dev-pipeline/tests/test_checkpoint_state.py +617 -30
  68. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -194
  69. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +62 -23
  70. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +76 -28
  71. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +281 -206
  72. package/bundled/dev-pipeline/tests/test_recovery_workflow.py +322 -0
  73. package/bundled/dev-pipeline/tests/test_reset_modes.py +935 -0
  74. package/bundled/dev-pipeline/tests/test_reset_preserve.py +5 -7
  75. package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
  76. package/bundled/dev-pipeline/tests/test_unified_cli.py +617 -188
  77. package/bundled/skills/_metadata.json +9 -9
  78. package/bundled/skills/app-planner/SKILL.md +3 -3
  79. package/bundled/skills/app-planner/references/generated-plan-review.md +2 -1
  80. package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +56 -64
  81. package/bundled/skills/app-planner/references/rules/backend/fixed-rules.md +85 -240
  82. package/bundled/skills/app-planner/references/rules/backend/question-bank.md +25 -25
  83. package/bundled/skills/app-planner/references/rules/backend/question-manifest.json +16 -7
  84. package/bundled/skills/app-planner/references/rules/backend/template.md +74 -92
  85. package/bundled/skills/app-planner/references/rules/database/derivation-rules.md +93 -93
  86. package/bundled/skills/app-planner/references/rules/database/fixed-rules.md +66 -173
  87. package/bundled/skills/app-planner/references/rules/database/question-bank.md +31 -26
  88. package/bundled/skills/app-planner/references/rules/database/question-manifest.json +13 -4
  89. package/bundled/skills/app-planner/references/rules/database/template.md +76 -98
  90. package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +68 -95
  91. package/bundled/skills/app-planner/references/rules/frontend/fixed-rules.md +93 -166
  92. package/bundled/skills/app-planner/references/rules/frontend/question-bank.md +46 -36
  93. package/bundled/skills/app-planner/references/rules/frontend/question-manifest.json +11 -2
  94. package/bundled/skills/app-planner/references/rules/frontend/template.md +79 -257
  95. package/bundled/skills/app-planner/references/rules/mobile/derivation-rules.md +91 -99
  96. package/bundled/skills/app-planner/references/rules/mobile/fixed-rules.md +73 -246
  97. package/bundled/skills/app-planner/references/rules/mobile/question-bank.md +17 -17
  98. package/bundled/skills/app-planner/references/rules/mobile/question-manifest.json +17 -2
  99. package/bundled/skills/app-planner/references/rules/mobile/template.md +73 -85
  100. package/bundled/skills/app-planner/references/rules-configuration.md +133 -65
  101. package/bundled/skills/app-planner/scripts/validate-rules-configuration.py +291 -0
  102. package/bundled/skills/bug-planner/references/schema-validation.md +1 -1
  103. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +1 -1
  104. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +21 -13
  105. package/bundled/skills/feature-pipeline-launcher/SKILL.md +22 -14
  106. package/bundled/skills/prizmkit/SKILL.md +17 -18
  107. package/bundled/skills/prizmkit/references/workflow-state-protocol.md +22 -18
  108. package/bundled/skills/prizmkit-code-review/SKILL.md +22 -58
  109. package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +6 -6
  110. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +2 -2
  111. package/bundled/skills/prizmkit-committer/SKILL.md +82 -132
  112. package/bundled/skills/prizmkit-deploy/SKILL.md +27 -11
  113. package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +89 -0
  114. package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +44 -14
  115. package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +19 -3
  116. package/bundled/skills/prizmkit-deploy/references/database-setup.md +22 -12
  117. package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +3 -1
  118. package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +22 -6
  119. package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +49 -0
  120. package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +1 -1
  121. package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +164 -0
  122. package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +9 -8
  123. package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +6 -6
  124. package/bundled/skills/prizmkit-implement/SKILL.md +30 -66
  125. package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +4 -4
  126. package/bundled/skills/prizmkit-init/SKILL.md +4 -0
  127. package/bundled/skills/prizmkit-plan/SKILL.md +21 -64
  128. package/bundled/skills/prizmkit-plan/references/artifact-identity.md +38 -0
  129. package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +4 -4
  130. package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +5 -5
  131. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +11 -1
  132. package/bundled/skills/prizmkit-retrospective/SKILL.md +63 -77
  133. package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -3
  134. package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
  135. package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +17 -23
  136. package/bundled/skills/prizmkit-test/SKILL.md +64 -51
  137. package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +206 -0
  138. package/bundled/skills/prizmkit-test/references/independent-test-review.md +17 -9
  139. package/bundled/skills/prizmkit-test/references/test-coverage-model.md +45 -21
  140. package/bundled/skills/prizmkit-test/references/test-report-template.md +20 -13
  141. package/bundled/skills/prizmkit-workflow/SKILL.md +35 -37
  142. package/bundled/skills/prizmkit-workflow/references/artifact-identity.md +34 -0
  143. package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +22 -18
  144. package/bundled/skills/recovery-workflow/SKILL.md +9 -6
  145. package/bundled/skills/recovery-workflow/evals/evals.json +2 -2
  146. package/bundled/skills/recovery-workflow/references/detection.md +7 -6
  147. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +16 -6
  148. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +21 -13
  149. package/bundled/templates/project-memory-template.md +19 -11
  150. package/package.json +1 -1
  151. package/src/scaffold.js +33 -22
  152. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +0 -228
  153. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +0 -767
  154. package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +0 -16
  155. package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +0 -31
  156. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -7
  157. package/bundled/dev-pipeline/templates/sections/critical-paths-lite.md +0 -7
  158. package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +0 -9
  159. package/bundled/dev-pipeline/templates/sections/directory-convention-lite.md +0 -6
  160. package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +0 -15
  161. package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -61
  162. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -24
  163. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -12
  164. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -44
  165. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -25
  166. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +0 -20
  167. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +0 -20
  168. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -20
  169. package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +0 -17
  170. package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +0 -28
  171. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +0 -52
  172. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +0 -52
  173. package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +0 -174
  174. package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +0 -174
  175. package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +0 -174
  176. package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +0 -174
  177. package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +0 -174
  178. package/bundled/skills/prizmkit-test/references/external-contract-mock-guidance.md +0 -119
@@ -9,136 +9,228 @@ from collections.abc import Sequence
9
9
  from .commands import CommandResult, handle_diagnostics, handle_runtime_command
10
10
  from .compat import UnsupportedPythonVersion, ensure_supported_python
11
11
  from .paths import resolve_runtime_paths
12
- from .runtime_helper import render_result, run_helper_command
13
12
 
14
13
  DESCRIPTION = (
15
14
  "PrizmKit canonical Python runtime CLI.\n"
16
- "Runs pipeline, reset, daemon, recovery, status, and diagnostics commands without shell wrappers."
15
+ "Runs operation-first pipeline, status, reset, daemon, diagnostics, and helper commands."
17
16
  )
18
17
 
18
+ _FAMILIES = ("feature", "bugfix", "refactor")
19
+ _GLOBAL_OPTIONS_WITH_VALUES = {"--project-root", "--pipeline-root"}
20
+ _LEAF_OPTIONS_WITH_VALUES = {
21
+ "--env",
22
+ "--features",
23
+ "--lines",
24
+ "-n",
25
+ "--max-retries",
26
+ "--max-infra-retries",
27
+ "--resume-phase",
28
+ }
29
+
30
+
31
+ def _set_handler(
32
+ parser: argparse.ArgumentParser,
33
+ group: str,
34
+ action: str,
35
+ target: str | None = None,
36
+ ) -> None:
37
+ parser.set_defaults(handler="runtime", group=group, action=action, target=target)
19
38
 
20
- def _add_passthrough_options(parser: argparse.ArgumentParser) -> None:
21
- parser.add_argument(
22
- "args",
23
- nargs=argparse.REMAINDER,
24
- help="Arguments forwarded to the selected Python runtime command.",
25
- )
39
+
40
+ def _non_negative_int(value: str) -> int:
41
+ try:
42
+ parsed = int(value)
43
+ except ValueError as exc:
44
+ raise argparse.ArgumentTypeError("must be an integer") from exc
45
+ if parsed < 0:
46
+ raise argparse.ArgumentTypeError("must be non-negative")
47
+ return parsed
48
+
49
+
50
+ def _add_runner_arguments(parser: argparse.ArgumentParser, family: str) -> None:
51
+ parser.add_argument("operand", nargs="?", help="Optional task ID or family plan path.")
52
+ parser.add_argument("second_operand", nargs="?", help="Optional family plan path or task ID.")
53
+ if family == "feature":
54
+ parser.add_argument("--features", help="Feature ID, range, or comma-separated selection.")
55
+ parser.add_argument("--max-retries", type=_non_negative_int)
56
+ parser.add_argument("--max-infra-retries", type=_non_negative_int)
57
+ parser.add_argument("--resume-phase")
58
+ parser.add_argument("--dry-run", action="store_true")
59
+ parser.add_argument("--clean", action="store_true")
60
+ parser.add_argument("--no-reset", action="store_true")
61
+
62
+
63
+ def _add_run_subparsers(
64
+ subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
65
+ ) -> None:
66
+ run_parser = subparsers.add_parser("run", help="Run a foreground pipeline family")
67
+ family_subparsers = run_parser.add_subparsers(dest="run_family", required=True)
68
+ for family in _FAMILIES:
69
+ family_parser = family_subparsers.add_parser(family, help=f"Run the {family} pipeline")
70
+ _add_runner_arguments(family_parser, family)
71
+ _set_handler(family_parser, "run", "run", family)
26
72
 
27
73
 
28
- def _set_handler(parser: argparse.ArgumentParser, group: str, action: str, target: str | None = None) -> None:
29
- parser.set_defaults(handler="runtime", group=group, action=action, target=target)
74
+ def _add_status_subparsers(
75
+ subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
76
+ ) -> None:
77
+ status_parser = subparsers.add_parser("status", help="Inspect pipeline task state")
78
+ target_subparsers = status_parser.add_subparsers(dest="status_target", required=True)
79
+ for family in _FAMILIES:
80
+ family_parser = target_subparsers.add_parser(family, help=f"Show {family} status")
81
+ _add_runner_arguments(family_parser, family)
82
+ _set_handler(family_parser, "status", "status", family)
83
+ all_parser = target_subparsers.add_parser(
84
+ "all",
85
+ help="Show read-only status for every configured family",
86
+ )
87
+ _set_handler(all_parser, "status", "status", "all")
30
88
 
31
89
 
32
- def _add_action_subparsers(
90
+ def _add_reset_subparsers(
91
+ subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
92
+ ) -> None:
93
+ reset_parser = subparsers.add_parser("reset", help="Apply one explicit reset mode")
94
+ family_subparsers = reset_parser.add_subparsers(dest="reset_family", required=True)
95
+ for family in _FAMILIES:
96
+ family_parser = family_subparsers.add_parser(family, help=f"Reset {family} task state")
97
+ family_parser.add_argument("operand", nargs="?", help="Task ID, range, or family plan path.")
98
+ family_parser.add_argument("second_operand", nargs="?", help="Optional family plan path.")
99
+ family_parser.add_argument("--state-only", action="store_true")
100
+ family_parser.add_argument("--fresh-checkout", action="store_true")
101
+ family_parser.add_argument("--clean", action="store_true")
102
+ family_parser.add_argument("--preserve-runtime", action="store_true")
103
+ family_parser.add_argument("--all", action="store_true")
104
+ family_parser.add_argument("--auto-skipped", action="store_true")
105
+ family_parser.add_argument("--failed", action="store_true")
106
+ family_parser.add_argument("--stalled", action="store_true")
107
+ _set_handler(family_parser, "reset", "reset", family)
108
+
109
+
110
+ def _add_daemon_start_arguments(parser: argparse.ArgumentParser, family: str) -> None:
111
+ parser.add_argument("list_path", nargs="?", help="Optional family plan path.")
112
+ parser.add_argument("--env", help="Quoted KEY=VALUE daemon environment overrides.")
113
+ if family == "feature":
114
+ parser.add_argument("--features", help="Feature ID, range, or comma-separated selection.")
115
+
116
+
117
+ def _add_daemon_subparsers(
118
+ subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
119
+ ) -> None:
120
+ daemon_parser = subparsers.add_parser("daemon", help="Manage background pipeline processes")
121
+ family_subparsers = daemon_parser.add_subparsers(dest="daemon_family", required=True)
122
+ for family in _FAMILIES:
123
+ family_parser = family_subparsers.add_parser(family, help=f"Manage the {family} daemon")
124
+ action_subparsers = family_parser.add_subparsers(dest="daemon_action", required=True)
125
+ for action in ("start", "stop", "status", "logs", "restart"):
126
+ action_parser = action_subparsers.add_parser(action, help=f"{action.title()} the {family} daemon")
127
+ if action in {"start", "restart"}:
128
+ _add_daemon_start_arguments(action_parser, family)
129
+ elif action == "logs":
130
+ action_parser.add_argument("--lines", "-n", type=_non_negative_int, default=50)
131
+ action_parser.add_argument("--follow", "-f", action="store_true")
132
+ _set_handler(action_parser, "daemon", action, family)
133
+
134
+
135
+ def _add_diagnostics_subparsers(
33
136
  subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
34
- group: str,
35
- actions: Sequence[str],
36
137
  ) -> None:
37
- group_parser = subparsers.add_parser(group, help=f"{group} pipeline commands")
38
- action_subparsers = group_parser.add_subparsers(dest="action_name", required=True)
39
- for action in actions:
40
- action_parser = action_subparsers.add_parser(action, help=f"Run {group} {action}")
41
- _add_passthrough_options(action_parser)
42
- _set_handler(action_parser, group, action)
43
-
44
-
45
- def _add_reset_subparsers(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
46
- reset_parser = subparsers.add_parser("reset", help="Explicit reset commands")
47
- reset_subparsers = reset_parser.add_subparsers(dest="reset_target", required=True)
48
- for target in ("feature", "bugfix", "refactor"):
49
- target_parser = reset_subparsers.add_parser(target, help=f"Run {target} reset")
50
- _add_passthrough_options(target_parser)
51
- _set_handler(target_parser, "reset", "reset", target)
52
- describe_parser = reset_subparsers.add_parser("describe", help="Describe reset command boundaries")
53
- _set_handler(describe_parser, "reset", "describe")
54
-
55
-
56
- def _add_daemon_subparsers(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
57
- daemon_parser = subparsers.add_parser("daemon", help="Daemon lifecycle commands")
58
- target_subparsers = daemon_parser.add_subparsers(dest="daemon_target", required=True)
59
- for target in ("feature", "bugfix", "refactor"):
60
- target_parser = target_subparsers.add_parser(target, help=f"{target} daemon commands")
61
- action_subparsers = target_parser.add_subparsers(dest="daemon_action", required=True)
62
- for action in ("start", "stop", "status", "logs", "restart", "describe"):
63
- action_parser = action_subparsers.add_parser(action, help=f"Run daemon {target} {action}")
64
- _add_passthrough_options(action_parser)
65
- _set_handler(action_parser, "daemon", action, target)
66
-
67
-
68
- def _add_status_subparsers(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
69
- status_parser = subparsers.add_parser("status", help="Status commands")
70
- status_subparsers = status_parser.add_subparsers(dest="status_target", required=True)
71
- for target in ("feature", "bugfix", "refactor", "all"):
72
- target_parser = status_subparsers.add_parser(target, help=f"Show {target} status")
73
- _add_passthrough_options(target_parser)
74
- _set_handler(target_parser, "status", "status", target)
75
-
76
-
77
- def _add_diagnostics_subparsers(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
78
- diagnostics_parser = subparsers.add_parser("diagnostics", help="Python runtime diagnostics")
79
- diagnostics_subparsers = diagnostics_parser.add_subparsers(dest="diagnostics_action", required=True)
80
- for action in ("paths", "entrypoints", "version"):
81
- action_parser = diagnostics_subparsers.add_parser(action, help=f"Show {action} diagnostics")
138
+ diagnostics_parser = subparsers.add_parser("diagnostics", help="Inspect Python runtime configuration")
139
+ action_subparsers = diagnostics_parser.add_subparsers(dest="diagnostics_action", required=True)
140
+ for action in ("paths", "entrypoints", "version", "ai-cli"):
141
+ action_parser = action_subparsers.add_parser(action, help=f"Show {action} diagnostics")
82
142
  action_parser.set_defaults(handler="diagnostics", action=action)
83
143
 
84
144
 
85
- def _add_helper_subparser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
86
- helper_parser = subparsers.add_parser("helper", help="Cross-platform prompt runtime helper commands")
145
+ def _add_helper_subparser(
146
+ subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
147
+ ) -> None:
148
+ helper_parser = subparsers.add_parser("helper", help="Run low-level cross-platform helper commands")
149
+ helper_parser.add_argument("helper_command", nargs="?", help="Helper command namespace.")
87
150
  helper_parser.add_argument(
88
- "args",
151
+ "helper_args",
89
152
  nargs=argparse.REMAINDER,
90
153
  help="Arguments forwarded to prizmkit-runtime-helper.",
91
154
  )
92
- helper_parser.set_defaults(handler="helper", group="helper", action="run", target=None)
93
-
94
-
95
- _PIPELINE_GROUPS = {"feature", "bugfix", "refactor", "recovery"}
96
- _GLOBAL_OPTIONS_WITH_VALUES = {"--project-root", "--pipeline-root"}
155
+ _set_handler(helper_parser, "helper", "run")
97
156
 
98
157
 
99
- def _split_passthrough_args(argv: Sequence[str]) -> tuple[list[str], tuple[str, ...]]:
100
- """Split parser-owned command tokens from legacy args while preserving exact arg order."""
158
+ def _parser_argv(argv: Sequence[str]) -> list[str]:
159
+ """Normalize interspersed leaf operands for argparse validation only."""
101
160
  tokens = [str(arg) for arg in argv]
102
- prefix: list[str] = []
103
161
  index = 0
104
162
  while index < len(tokens):
105
163
  token = tokens[index]
106
164
  if token in _GLOBAL_OPTIONS_WITH_VALUES:
107
- prefix.append(token)
108
- index += 1
109
- if index < len(tokens):
110
- prefix.append(tokens[index])
111
- index += 1
165
+ index += 2
112
166
  continue
113
167
  if any(token.startswith(f"{option}=") for option in _GLOBAL_OPTIONS_WITH_VALUES):
114
- prefix.append(token)
115
168
  index += 1
116
169
  continue
117
170
  break
171
+ if index >= len(tokens):
172
+ return tokens
118
173
 
174
+ group = tokens[index]
175
+ depth = {"run": 2, "status": 2, "reset": 2, "daemon": 3}.get(group)
176
+ if depth is None or len(tokens) <= index + depth:
177
+ return tokens
178
+
179
+ command_end = index + depth
180
+ operands: list[str] = []
181
+ options: list[str] = []
182
+ tail = tokens[command_end:]
183
+ tail_index = 0
184
+ while tail_index < len(tail):
185
+ token = tail[tail_index]
186
+ option_name = token.split("=", 1)[0]
187
+ if token.startswith("-"):
188
+ options.append(token)
189
+ if (
190
+ "=" not in token
191
+ and option_name in _LEAF_OPTIONS_WITH_VALUES
192
+ and tail_index + 1 < len(tail)
193
+ ):
194
+ tail_index += 1
195
+ options.append(tail[tail_index])
196
+ else:
197
+ operands.append(token)
198
+ tail_index += 1
199
+ return [*tokens[:command_end], *operands, *options]
200
+
201
+
202
+ def _runtime_action_args(argv: Sequence[str]) -> tuple[str, ...]:
203
+ """Return the original validated leaf arguments in their exact order."""
204
+ tokens = [str(arg) for arg in argv]
205
+ index = 0
206
+ while index < len(tokens):
207
+ token = tokens[index]
208
+ if token in _GLOBAL_OPTIONS_WITH_VALUES:
209
+ index += 2
210
+ continue
211
+ if any(token.startswith(f"{option}=") for option in _GLOBAL_OPTIONS_WITH_VALUES):
212
+ index += 1
213
+ continue
214
+ break
119
215
  if index >= len(tokens):
120
- return tokens, ()
216
+ return ()
121
217
 
122
218
  group = tokens[index]
123
- if group in _PIPELINE_GROUPS:
124
- required_parts = 2
125
- elif group in {"reset", "status", "diagnostics"}:
126
- required_parts = 2
127
- elif group == "daemon":
128
- required_parts = 3
129
- else:
130
- return tokens, ()
131
-
132
- command_end = min(len(tokens), index + required_parts)
133
- prefix.extend(tokens[index:command_end])
134
- passthrough = tuple(tokens[command_end:])
135
- if group == "diagnostics":
136
- return tokens, ()
137
- return prefix, passthrough
219
+ depth = {
220
+ "run": 2,
221
+ "status": 2,
222
+ "reset": 2,
223
+ "daemon": 3,
224
+ "diagnostics": 2,
225
+ "helper": 1,
226
+ }.get(group)
227
+ if depth is None:
228
+ return ()
229
+ return tuple(tokens[index + depth :])
138
230
 
139
231
 
140
232
  def build_parser() -> argparse.ArgumentParser:
141
- """Build the standard-library argparse command tree."""
233
+ """Build the standard-library operation-first argparse command tree."""
142
234
  parser = argparse.ArgumentParser(
143
235
  prog="prizmkit-runtime",
144
236
  description=DESCRIPTION,
@@ -154,13 +246,10 @@ def build_parser() -> argparse.ArgumentParser:
154
246
  )
155
247
  subparsers = parser.add_subparsers(dest="command_group", required=True)
156
248
 
157
- _add_action_subparsers(subparsers, "feature", ("run", "status", "reset", "unskip", "test-cli", "describe"))
158
- _add_action_subparsers(subparsers, "bugfix", ("run", "status", "reset", "unskip", "describe"))
159
- _add_action_subparsers(subparsers, "refactor", ("run", "status", "reset", "unskip", "describe"))
160
- _add_action_subparsers(subparsers, "recovery", ("run", "detect", "describe"))
249
+ _add_run_subparsers(subparsers)
250
+ _add_status_subparsers(subparsers)
161
251
  _add_reset_subparsers(subparsers)
162
252
  _add_daemon_subparsers(subparsers)
163
- _add_status_subparsers(subparsers)
164
253
  _add_diagnostics_subparsers(subparsers)
165
254
  _add_helper_subparser(subparsers)
166
255
  return parser
@@ -174,14 +263,6 @@ def _dispatch(args: argparse.Namespace) -> CommandResult:
174
263
  paths = _runtime_paths_from_args(args)
175
264
  if args.handler == "diagnostics":
176
265
  return handle_diagnostics(args.action, paths)
177
- if args.handler == "helper":
178
- helper_result = run_helper_command(tuple(getattr(args, "args", ()) or ()))
179
- return CommandResult(
180
- helper_result.exit_code,
181
- "Python runtime helper",
182
- "Cross-platform prompt runtime helper result.",
183
- stdout=render_result(helper_result, json_output="--json" in tuple(getattr(args, "args", ()) or ())),
184
- )
185
266
  return handle_runtime_command(
186
267
  args.group,
187
268
  args.action,
@@ -192,7 +273,7 @@ def _dispatch(args: argparse.Namespace) -> CommandResult:
192
273
 
193
274
 
194
275
  def main(argv: Sequence[str] | None = None) -> int:
195
- """Run the unified runtime CLI."""
276
+ """Run the canonical operation-first runtime CLI."""
196
277
  try:
197
278
  ensure_supported_python()
198
279
  except UnsupportedPythonVersion as exc:
@@ -201,10 +282,8 @@ def main(argv: Sequence[str] | None = None) -> int:
201
282
 
202
283
  parser = build_parser()
203
284
  parse_argv = list(sys.argv[1:] if argv is None else argv)
204
- parser_argv, passthrough_args = _split_passthrough_args(parse_argv)
205
- args = parser.parse_args(parser_argv)
206
- if passthrough_args:
207
- args.args = tuple(getattr(args, "args", ()) or ()) + passthrough_args
285
+ args = parser.parse_args(_parser_argv(parse_argv))
286
+ args.args = _runtime_action_args(parse_argv)
208
287
  result = _dispatch(args)
209
288
  if result.stderr:
210
289
  print(result.stderr, file=sys.stderr)