@geminix/gxpm 0.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 (299) hide show
  1. package/AGENTS.md +148 -0
  2. package/CANON.md +53 -0
  3. package/CLAUDE.md +60 -0
  4. package/CONTEXT.md +49 -0
  5. package/DEBUG.md +59 -0
  6. package/ISSUE_CONTEXT.md +25 -0
  7. package/README.md +143 -0
  8. package/VERSION +1 -0
  9. package/agents/cleanup-auditor/cleanup-auditor.md +56 -0
  10. package/agents/grill-master.md +26 -0
  11. package/agents/implementer.md +32 -0
  12. package/agents/review-army/accessibility-reviewer.md +54 -0
  13. package/agents/review-army/code-quality-reviewer.md +54 -0
  14. package/agents/review-army/security-reviewer.md +56 -0
  15. package/agents/review-army/spec-compliance-reviewer.md +51 -0
  16. package/agents/review-army/test-reviewer.md +55 -0
  17. package/agents/reviewer.md +59 -0
  18. package/agents/ship-audit-army/docs-auditor.md +53 -0
  19. package/agents/ship-audit-army/performance-auditor.md +52 -0
  20. package/agents/ship-audit-army/security-auditor.md +52 -0
  21. package/agents/specifier.md +55 -0
  22. package/agents/triage-officer.md +27 -0
  23. package/bin/gxpm +17 -0
  24. package/bin/gxpm-browser +17 -0
  25. package/bin/gxpm-config +15 -0
  26. package/bin/gxpm-eval +13 -0
  27. package/bin/gxpm-global-discover +15 -0
  28. package/bin/gxpm-init +38 -0
  29. package/bin/gxpm-investigate +194 -0
  30. package/bin/gxpm-uninstall +15 -0
  31. package/bin/gxpm-update-check +165 -0
  32. package/commands/build.md +40 -0
  33. package/commands/help.md +53 -0
  34. package/commands/plan.md +34 -0
  35. package/commands/refine.md +46 -0
  36. package/commands/review.md +34 -0
  37. package/commands/ship.md +37 -0
  38. package/core/ac-check.ts +20 -0
  39. package/core/agent-runtime.ts +363 -0
  40. package/core/artifact-validator.ts +151 -0
  41. package/core/artifacts.ts +313 -0
  42. package/core/autopilot.ts +250 -0
  43. package/core/capabilities.ts +779 -0
  44. package/core/checkpoint.ts +370 -0
  45. package/core/cleanup.ts +32 -0
  46. package/core/command-probe.ts +82 -0
  47. package/core/config.ts +533 -0
  48. package/core/contracts/behavior-spec.schema.ts +38 -0
  49. package/core/contracts/converter.ts +61 -0
  50. package/core/contracts/host.ts +43 -0
  51. package/core/converters/converter.ts +93 -0
  52. package/core/converters/index.ts +8 -0
  53. package/core/converters/managed-artifact.ts +119 -0
  54. package/core/converters/parser.ts +159 -0
  55. package/core/converters/template-renderer.ts +35 -0
  56. package/core/converters/writer.ts +61 -0
  57. package/core/dag-executor.ts +426 -0
  58. package/core/dag-loader.ts +292 -0
  59. package/core/dag-schemas.ts +150 -0
  60. package/core/dispatch.ts +125 -0
  61. package/core/evidence.ts +148 -0
  62. package/core/gate.ts +269 -0
  63. package/core/hook-engine.ts +566 -0
  64. package/core/host-probe.ts +64 -0
  65. package/core/implement.ts +16 -0
  66. package/core/isolation-errors.ts +174 -0
  67. package/core/isolation-resolver.ts +921 -0
  68. package/core/issue-context.ts +381 -0
  69. package/core/issue-readiness.ts +457 -0
  70. package/core/issue-sync.ts +427 -0
  71. package/core/issues.ts +132 -0
  72. package/core/land.ts +108 -0
  73. package/core/orchestrator.ts +54 -0
  74. package/core/phase-artifact.ts +32 -0
  75. package/core/phase-gates.ts +130 -0
  76. package/core/phase-rewind.ts +94 -0
  77. package/core/plan-lint.ts +61 -0
  78. package/core/plan.ts +77 -0
  79. package/core/port-allocation.ts +50 -0
  80. package/core/pr-check.ts +15 -0
  81. package/core/preset-system/preset-resolver.ts +221 -0
  82. package/core/project-init-status.ts +127 -0
  83. package/core/qa.ts +15 -0
  84. package/core/resilience.ts +165 -0
  85. package/core/runs.ts +288 -0
  86. package/core/safe-path.test.ts +80 -0
  87. package/core/safe-path.ts +60 -0
  88. package/core/sdd-gate.test.ts +98 -0
  89. package/core/sdd-gate.ts +134 -0
  90. package/core/self-review.ts +62 -0
  91. package/core/session.ts +70 -0
  92. package/core/ship.ts +86 -0
  93. package/core/specify.ts +173 -0
  94. package/core/state.ts +1002 -0
  95. package/core/template-engine.ts +152 -0
  96. package/core/template-resolver.test.ts +70 -0
  97. package/core/template-resolver.ts +156 -0
  98. package/core/triage.ts +26 -0
  99. package/core/verify.ts +15 -0
  100. package/core/wiki-native.ts +2423 -0
  101. package/core/wiki.ts +27 -0
  102. package/core/workflow-event-emitter.ts +163 -0
  103. package/core/workflows/engine.ts +273 -0
  104. package/core/workflows/expressions.ts +76 -0
  105. package/core/workflows/index.ts +38 -0
  106. package/core/workflows/steps/command.ts +43 -0
  107. package/core/workflows/steps/gate.ts +47 -0
  108. package/core/workflows/steps/gxpm.ts +44 -0
  109. package/core/workflows/steps/linear.ts +31 -0
  110. package/core/workflows/steps/shell.ts +65 -0
  111. package/core/workflows/types.ts +62 -0
  112. package/core/workspace-runtime.ts +227 -0
  113. package/core/worktree-init-steps.ts +647 -0
  114. package/core/worktree-init.ts +330 -0
  115. package/core/worktree-owner.ts +143 -0
  116. package/docs/GXPM_VERIFY.md +98 -0
  117. package/docs/INSTALL_FOR_AGENTS.md +113 -0
  118. package/docs/README.md +57 -0
  119. package/docs/adr/adr-005-multi-platform-skill-converter.md +72 -0
  120. package/docs/agents/domain.md +30 -0
  121. package/docs/agents/issue-tracker.md +30 -0
  122. package/docs/agents/triage-labels.md +32 -0
  123. package/docs/architecture/gxpm-architecture-diagram.md +265 -0
  124. package/docs/architecture/gxpm-current-architecture.md +175 -0
  125. package/docs/architecture/gxpm-current-flow.md +278 -0
  126. package/docs/architecture/gxpm-replacement-architecture.md +211 -0
  127. package/docs/architecture/gxpm-target-architecture.md +449 -0
  128. package/docs/architecture/gxpm-v0-contract.md +311 -0
  129. package/docs/architecture/layered-workflow-boundaries.md +193 -0
  130. package/docs/architecture/preset-system.md +126 -0
  131. package/docs/architecture/scaffold-northstar.md +23 -0
  132. package/docs/brainstorms/2026-05-14-bdd-then-tdd-design.md +320 -0
  133. package/docs/brainstorms/README.md +22 -0
  134. package/docs/brainstorms/docs-knowledge-system-requirements.md +29 -0
  135. package/docs/governance/beta-skill-promotion.md +39 -0
  136. package/docs/governance/development-contract.md +144 -0
  137. package/docs/governance/gherkin-style.md +90 -0
  138. package/docs/governance/host-adapter.md +56 -0
  139. package/docs/governance/skill-authoring.md +87 -0
  140. package/docs/governance/skill-testing.md +356 -0
  141. package/docs/governance/template-authoring.md +53 -0
  142. package/docs/migrations/v0.2.md +51 -0
  143. package/docs/plans/README.md +23 -0
  144. package/docs/plans/bdd-then-tdd-plan.md +1767 -0
  145. package/docs/plans/docs-knowledge-system-plan.md +31 -0
  146. package/docs/plans/spec-kit-sdd-adoption-plan.md +305 -0
  147. package/docs/research/agents-md-best-practices.md +207 -0
  148. package/docs/research/archon-study.md +351 -0
  149. package/docs/research/claude-hooks-study.md +440 -0
  150. package/docs/research/codex-hooks-study.md +624 -0
  151. package/docs/research/everything-claude-code-study.md +252 -0
  152. package/docs/research/from-skills-to-layered-workflow.md +322 -0
  153. package/docs/research/gsd-study.md +69 -0
  154. package/docs/research/kimi-hooks-study.md +274 -0
  155. package/docs/research/mattpocock-skills-comparison.md +429 -0
  156. package/docs/research/mattpocock-skills-study.md +275 -0
  157. package/docs/research/oh-my-codex-study.md +279 -0
  158. package/docs/research/perplexity-agent-skills-design.md +168 -0
  159. package/docs/research/pmc-gstack-skill-study.md +122 -0
  160. package/docs/research/spec-kit-study.md +224 -0
  161. package/docs/research/superpowers-study.md +209 -0
  162. package/docs/roadmap/initial-roadmap.md +53 -0
  163. package/docs/solutions/README.md +45 -0
  164. package/docs/solutions/artifact-nesting-recovery.md +58 -0
  165. package/docs/solutions/session-context-restore-practice.md +67 -0
  166. package/docs/solutions/workflow/version-drift-recovery.md +49 -0
  167. package/docs/solutions/worktree-gate-recovery.md +62 -0
  168. package/docs/specs/README.md +28 -0
  169. package/docs/specs/claude.md +45 -0
  170. package/docs/specs/codex.md +44 -0
  171. package/docs/specs/cursor.md +44 -0
  172. package/hosts/adapters/claude.ts +29 -0
  173. package/hosts/adapters/codex.ts +27 -0
  174. package/hosts/adapters/cursor.ts +27 -0
  175. package/hosts/adapters/kimi.ts +27 -0
  176. package/hosts/claude.ts +23 -0
  177. package/hosts/codex.ts +26 -0
  178. package/hosts/cursor.ts +19 -0
  179. package/hosts/index.ts +33 -0
  180. package/hosts/registry.test.ts +52 -0
  181. package/hosts/registry.ts +57 -0
  182. package/hosts/schema.ts +58 -0
  183. package/package.json +52 -0
  184. package/scripts/browser.ts +185 -0
  185. package/scripts/cleanup.ts +142 -0
  186. package/scripts/commands/artifact.ts +115 -0
  187. package/scripts/commands/autopilot.ts +143 -0
  188. package/scripts/commands/capability.ts +57 -0
  189. package/scripts/commands/config.ts +69 -0
  190. package/scripts/commands/dag.ts +126 -0
  191. package/scripts/commands/feedback.ts +123 -0
  192. package/scripts/commands/gate.ts +291 -0
  193. package/scripts/commands/helpers.ts +126 -0
  194. package/scripts/commands/hook.ts +66 -0
  195. package/scripts/commands/init.ts +515 -0
  196. package/scripts/commands/issue.ts +825 -0
  197. package/scripts/commands/phase.ts +61 -0
  198. package/scripts/commands/preset.ts +159 -0
  199. package/scripts/commands/runtime.ts +199 -0
  200. package/scripts/commands/specify.ts +71 -0
  201. package/scripts/commands/upgrade.ts +243 -0
  202. package/scripts/commands/verify.ts +183 -0
  203. package/scripts/commands/wiki.ts +242 -0
  204. package/scripts/commands/workflow.ts +131 -0
  205. package/scripts/dev-skill.ts +55 -0
  206. package/scripts/discover-skills.ts +116 -0
  207. package/scripts/doctor.ts +410 -0
  208. package/scripts/dogfood-check.ts +125 -0
  209. package/scripts/eval-functional.ts +218 -0
  210. package/scripts/eval.ts +246 -0
  211. package/scripts/gen-skill-docs.ts +201 -0
  212. package/scripts/global-discover.ts +217 -0
  213. package/scripts/governance-check.ts +75 -0
  214. package/scripts/gxpm-check.ts +12 -0
  215. package/scripts/gxpm.ts +216 -0
  216. package/scripts/host-config.ts +62 -0
  217. package/scripts/install-claude-hooks.ts +138 -0
  218. package/scripts/install-codex-hooks.ts +271 -0
  219. package/scripts/install-hooks.ts +128 -0
  220. package/scripts/install-kimi-hooks.ts +92 -0
  221. package/scripts/install-skill.ts +184 -0
  222. package/scripts/phase-artifact-commands.ts +100 -0
  223. package/scripts/post-land-sync.ts +46 -0
  224. package/scripts/scaffold-check.ts +85 -0
  225. package/scripts/skill-naming-check.ts +78 -0
  226. package/scripts/skill-structure-check.ts +157 -0
  227. package/scripts/skills-lock-check.ts +60 -0
  228. package/scripts/sync-markdown-artifacts.ts +172 -0
  229. package/scripts/uninstall.ts +162 -0
  230. package/scripts/version.ts +47 -0
  231. package/scripts/wait-pr-ready.ts +407 -0
  232. package/skills/gxpm/SKILL.md +485 -0
  233. package/skills/gxpm/SKILL.md.tmpl +422 -0
  234. package/skills/gxpm/references/CANON.md +53 -0
  235. package/skills/gxpm/references/key-rules.md +130 -0
  236. package/skills/gxpm-architecture/SKILL.md +106 -0
  237. package/skills/gxpm-architecture/references/DEEPENING.md +37 -0
  238. package/skills/gxpm-architecture/references/INTERFACE-DESIGN.md +44 -0
  239. package/skills/gxpm-autopilot/SKILL.md +116 -0
  240. package/skills/gxpm-autopilot/SKILL.md.tmpl +107 -0
  241. package/skills/gxpm-browser/SKILL.md +105 -0
  242. package/skills/gxpm-browser/SKILL.md.tmpl +41 -0
  243. package/skills/gxpm-browser/references/commands.md +43 -0
  244. package/skills/gxpm-browser/references/evidence-path.md +20 -0
  245. package/skills/gxpm-build/SKILL.md +78 -0
  246. package/skills/gxpm-cleanup/SKILL.md +76 -0
  247. package/skills/gxpm-debug-issue/SKILL.md +39 -0
  248. package/skills/gxpm-diagnose/SKILL.md +220 -0
  249. package/skills/gxpm-diagnose/SKILL.md.tmpl +31 -0
  250. package/skills/gxpm-diagnose/references/feedback-loop.md +34 -0
  251. package/skills/gxpm-diagnose/references/feedback-loops.md +43 -0
  252. package/skills/gxpm-diagnose/references/phases.md +60 -0
  253. package/skills/gxpm-eval/SKILL.md +78 -0
  254. package/skills/gxpm-explore-codebase/SKILL.md +36 -0
  255. package/skills/gxpm-explore-codebase/scripts/summarize-communities.ts +51 -0
  256. package/skills/gxpm-feedback/SKILL.md +122 -0
  257. package/skills/gxpm-grill/SKILL.md +159 -0
  258. package/skills/gxpm-grill/SKILL.md.tmpl +77 -0
  259. package/skills/gxpm-grill/references/documentation-templates.md +56 -0
  260. package/skills/gxpm-grill/references/process.md +25 -0
  261. package/skills/gxpm-handoff/SKILL.md +112 -0
  262. package/skills/gxpm-hygiene/SKILL.md +69 -0
  263. package/skills/gxpm-implementer/SKILL.md +142 -0
  264. package/skills/gxpm-implementer/SKILL.md.tmpl +141 -0
  265. package/skills/gxpm-linear/SKILL.md +282 -0
  266. package/skills/gxpm-linear/SKILL.md.tmpl +86 -0
  267. package/skills/gxpm-linear/references/commands.md +75 -0
  268. package/skills/gxpm-linear/references/workflows.md +120 -0
  269. package/skills/gxpm-planning/SKILL.md +134 -0
  270. package/skills/gxpm-prototype/SKILL.md +64 -0
  271. package/skills/gxpm-refactor-safely/SKILL.md +62 -0
  272. package/skills/gxpm-review-army/SKILL.md +117 -0
  273. package/skills/gxpm-review-changes/SKILL.md +36 -0
  274. package/skills/gxpm-setup/SKILL.md +101 -0
  275. package/skills/gxpm-specifier/SKILL.md +135 -0
  276. package/skills/gxpm-tdd/SKILL.md +187 -0
  277. package/skills/gxpm-tdd/references/interface-design.md +23 -0
  278. package/skills/gxpm-tdd/references/mocking.md +27 -0
  279. package/skills/gxpm-tdd/references/red-green-refactor.md +61 -0
  280. package/skills/gxpm-tdd/references/troubleshooting.md +28 -0
  281. package/skills/gxpm-tdd/references/workflow.md +50 -0
  282. package/skills/gxpm-tdd/testing-anti-patterns.tmpl +304 -0
  283. package/skills/gxpm-triage/SKILL.md +160 -0
  284. package/skills/gxpm-verify/SKILL.md +107 -0
  285. package/skills/gxpm-write-skill/SKILL.md +131 -0
  286. package/skills/gxpm-zoom-out/SKILL.md +69 -0
  287. package/skills/maintain-hygiene-skills-lock/SKILL.md +54 -0
  288. package/skills/maintain-hygiene-skills-lock/SKILL.md.tmpl +53 -0
  289. package/templates/constitution-template.md +63 -0
  290. package/templates/hooks/gxpm-commit-msg +16 -0
  291. package/templates/hooks/gxpm-post-checkout +19 -0
  292. package/templates/hooks/gxpm-post-commit +7 -0
  293. package/templates/hooks/gxpm-post-merge +29 -0
  294. package/templates/hooks/gxpm-pre-commit +39 -0
  295. package/templates/hooks/gxpm-pre-push +33 -0
  296. package/templates/plan-template.md.tmpl +46 -0
  297. package/templates/spec-template.md.tmpl +63 -0
  298. package/templates/specify-stub.tmpl +22 -0
  299. package/templates/tasks-template.md.tmpl +32 -0
@@ -0,0 +1,61 @@
1
+ import { rewindPhase } from "../../core/phase-rewind";
2
+
3
+ function parseRewindArgs(argv: string[]): {
4
+ issueId: string;
5
+ toPhase: string;
6
+ reason: string;
7
+ } {
8
+ // Expected: gxpm phase rewind <issue-id> --to <phase> --reason "<text>"
9
+ // argv slice already starts after "phase rewind"
10
+ const issueId = argv[0];
11
+ if (!issueId) {
12
+ throw new Error(
13
+ 'usage: gxpm phase rewind <issue-id> --to <phase> --reason "<text>"',
14
+ );
15
+ }
16
+
17
+ let toPhase: string | undefined;
18
+ let reason: string | undefined;
19
+
20
+ for (let i = 1; i < argv.length; i++) {
21
+ const arg = argv[i];
22
+ if (arg === "--to") {
23
+ toPhase = argv[++i];
24
+ continue;
25
+ }
26
+ if (arg.startsWith("--to=")) {
27
+ toPhase = arg.slice("--to=".length);
28
+ continue;
29
+ }
30
+ if (arg === "--reason") {
31
+ reason = argv[++i];
32
+ continue;
33
+ }
34
+ if (arg.startsWith("--reason=")) {
35
+ reason = arg.slice("--reason=".length);
36
+ continue;
37
+ }
38
+ }
39
+
40
+ if (!toPhase) {
41
+ throw new Error("phase rewind requires --to <phase>");
42
+ }
43
+ if (!reason || !reason.trim()) {
44
+ throw new Error("phase rewind requires --reason \"<text>\"");
45
+ }
46
+
47
+ return { issueId, toPhase, reason };
48
+ }
49
+
50
+ export function runPhaseCommand(argv: string[], subcommand: string | undefined) {
51
+ if (subcommand !== "rewind") {
52
+ throw new Error(`unknown phase subcommand: ${subcommand ?? "<none>"}; expected rewind`);
53
+ }
54
+ // Strip "phase rewind" prefix; remaining argv has [<issue-id>, --to, <phase>, --reason, <text>]
55
+ const args = argv.slice(2);
56
+ const { issueId, toPhase, reason } = parseRewindArgs(args);
57
+ const result = rewindPhase({ issueId, toPhase, reason });
58
+ console.log(
59
+ `rewound ${issueId}: ${result.fromPhase} -> ${result.toPhase} (${result.timestamp})`,
60
+ );
61
+ }
@@ -0,0 +1,159 @@
1
+ // PRESET CLI — gxpm preset add/remove/list/show/init
2
+
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { PresetResolver } from "../../core/preset-system/preset-resolver";
6
+
7
+ const PRESET_DIR = ".gxpm/presets";
8
+ const REGISTRY_FILE = ".registry";
9
+
10
+ function getPresetDir(root: string): string {
11
+ return join(root, PRESET_DIR);
12
+ }
13
+
14
+ function readRegistry(root: string): { active: string[] } {
15
+ const path = join(getPresetDir(root), REGISTRY_FILE);
16
+ if (!existsSync(path)) return { active: [] };
17
+ try {
18
+ return JSON.parse(readFileSync(path, "utf8")) as { active: string[] };
19
+ } catch {
20
+ return { active: [] };
21
+ }
22
+ }
23
+
24
+ function writeRegistry(root: string, registry: { active: string[] }): void {
25
+ const dir = getPresetDir(root);
26
+ mkdirSync(dir, { recursive: true });
27
+ writeFileSync(join(dir, REGISTRY_FILE), JSON.stringify(registry, null, 2) + "\n");
28
+ }
29
+
30
+ function readManifest(root: string, id: string) {
31
+ const path = join(getPresetDir(root), id, "manifest.json");
32
+ if (!existsSync(path)) return null;
33
+ try {
34
+ return JSON.parse(readFileSync(path, "utf8")) as {
35
+ id: string;
36
+ name: string;
37
+ version: string;
38
+ description?: string;
39
+ rules: unknown[];
40
+ };
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ export function runPresetCommand(
47
+ _argv: string[],
48
+ subcommand: string | undefined,
49
+ id: string | undefined,
50
+ ): void {
51
+ const root = process.cwd();
52
+
53
+ switch (subcommand) {
54
+ case "list": {
55
+ const resolver = new PresetResolver(root);
56
+ resolver.load();
57
+ const active = resolver.listActive();
58
+ const all = resolver.listPresets();
59
+
60
+ if (all.length === 0) {
61
+ console.log("No presets found.");
62
+ return;
63
+ }
64
+
65
+ console.log("Presets:");
66
+ for (const presetId of all) {
67
+ const manifest = resolver.getPreset(presetId);
68
+ const isActive = active.includes(presetId);
69
+ const marker = isActive ? "*" : " ";
70
+ console.log(` [${marker}] ${presetId}: ${manifest?.name ?? "(unknown)"} (${manifest?.version ?? "?"})`);
71
+ }
72
+ if (active.length > 0) {
73
+ console.log(`\nActive order: ${active.join(" > ")}`);
74
+ }
75
+ return;
76
+ }
77
+
78
+ case "add": {
79
+ if (!id) {
80
+ throw new Error("Usage: gxpm preset add <preset-id>");
81
+ }
82
+ const manifest = readManifest(root, id);
83
+ if (!manifest) {
84
+ throw new Error(`Preset '${id}' not found. Run 'gxpm preset init ${id}' to create it.`);
85
+ }
86
+ const registry = readRegistry(root);
87
+ if (registry.active.includes(id)) {
88
+ console.log(`Preset '${id}' is already active.`);
89
+ return;
90
+ }
91
+ registry.active.push(id);
92
+ writeRegistry(root, registry);
93
+ console.log(`Added preset '${id}' to active list.`);
94
+ return;
95
+ }
96
+
97
+ case "remove": {
98
+ if (!id) {
99
+ throw new Error("Usage: gxpm preset remove <preset-id>");
100
+ }
101
+ const registry = readRegistry(root);
102
+ if (!registry.active.includes(id)) {
103
+ console.log(`Preset '${id}' is not active.`);
104
+ return;
105
+ }
106
+ registry.active = registry.active.filter((x) => x !== id);
107
+ writeRegistry(root, registry);
108
+ console.log(`Removed preset '${id}' from active list.`);
109
+ return;
110
+ }
111
+
112
+ case "show": {
113
+ if (!id) {
114
+ throw new Error("Usage: gxpm preset show <preset-id>");
115
+ }
116
+ const manifest = readManifest(root, id);
117
+ if (!manifest) {
118
+ throw new Error(`Preset '${id}' not found.`);
119
+ }
120
+ console.log(`ID: ${manifest.id}`);
121
+ console.log(`Name: ${manifest.name}`);
122
+ console.log(`Version: ${manifest.version}`);
123
+ if (manifest.description) console.log(`Description: ${manifest.description}`);
124
+ console.log(`Rules: ${manifest.rules.length}`);
125
+ for (const rule of manifest.rules) {
126
+ const r = rule as { target: string; strategy: string; source: string };
127
+ console.log(` - ${r.target} [${r.strategy}] <- ${r.source}`);
128
+ }
129
+ return;
130
+ }
131
+
132
+ case "init": {
133
+ if (!id) {
134
+ throw new Error("Usage: gxpm preset init <preset-id>");
135
+ }
136
+ const presetPath = join(getPresetDir(root), id);
137
+ if (existsSync(presetPath)) {
138
+ throw new Error(`Preset '${id}' already exists at ${presetPath}`);
139
+ }
140
+ mkdirSync(presetPath, { recursive: true });
141
+ const manifest = {
142
+ id,
143
+ name: id,
144
+ version: "1.0.0",
145
+ description: `Preset '${id}'`,
146
+ rules: [],
147
+ };
148
+ writeFileSync(join(presetPath, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n");
149
+ console.log(`Initialized preset '${id}' at ${presetPath}`);
150
+ console.log(`Edit ${join(presetPath, "manifest.json")} and add source files.`);
151
+ return;
152
+ }
153
+
154
+ default:
155
+ throw new Error(
156
+ `Unknown preset command: ${subcommand ?? ""}\nUsage: gxpm preset <list|add|remove|show|init> [id]`,
157
+ );
158
+ }
159
+ }
@@ -0,0 +1,199 @@
1
+ import { appendRunEvent, deleteRun, listRuns, readRun, RUN_STATUSES, startRun } from "../../core/runs";
2
+ import { cleanupIssueWorkspace, ensureIssueWorkspace, ensureIssueWorkspaceWithResolver, planIssueWorkspace } from "../../core/workspace-runtime";
3
+ import { dryRunOrchestratorTick } from "../../core/orchestrator";
4
+ import { claimIssue } from "../../core/issue-readiness";
5
+ import { optionValue, parsePositiveIntegerOption } from "./helpers";
6
+
7
+ export function runRunCommand(
8
+ argv: string[],
9
+ subcommand: string | undefined,
10
+ issueId: string | undefined,
11
+ runId: string | undefined,
12
+ ) {
13
+ if (!issueId) {
14
+ throw new Error("Usage: gxpm run start|list|status|event <issue-id> ...");
15
+ }
16
+
17
+ if (subcommand === "start") {
18
+ const status = optionValue(argv, "--status") ?? undefined;
19
+ if (status && !RUN_STATUSES.includes(status as (typeof RUN_STATUSES)[number])) {
20
+ throw new Error(`Invalid run status: ${status}`);
21
+ }
22
+ const attempt = parsePositiveIntegerOption(argv, "--attempt");
23
+ const workspacePath = optionValue(argv, "--workspace") ?? undefined;
24
+ const message = optionValue(argv, "--message") ?? undefined;
25
+ const shouldClaim = argv.includes("--claim");
26
+ let run = startRun({
27
+ issueId,
28
+ attempt,
29
+ status,
30
+ workspacePath,
31
+ message,
32
+ });
33
+ const claim = shouldClaim
34
+ ? claimRunOrRollback({
35
+ issueId,
36
+ runId: run.runId,
37
+ actor: optionValue(argv, "--actor") ?? undefined,
38
+ })
39
+ : null;
40
+ if (claim) {
41
+ run = appendRunEvent({
42
+ issueId,
43
+ runId: run.runId,
44
+ type: "run.claimed",
45
+ status: run.status,
46
+ payload: {
47
+ actor: claim.claim.actor,
48
+ claimedBySession: claim.claim.claimedBySession,
49
+ workspacePath: run.workspacePath,
50
+ },
51
+ });
52
+ }
53
+ if (argv.includes("--json")) {
54
+ console.log(JSON.stringify(claim ? { run, claim } : run, null, 2));
55
+ } else {
56
+ console.log(`started ${run.runId} for ${issueId}`);
57
+ console.log(`status: ${run.status}`);
58
+ if (claim) console.log("claim: claimed");
59
+ }
60
+ return;
61
+ }
62
+
63
+ if (subcommand === "list") {
64
+ const runs = listRuns({ issueId });
65
+ if (argv.includes("--json")) {
66
+ console.log(JSON.stringify(runs, null, 2));
67
+ return;
68
+ }
69
+ if (runs.length === 0) {
70
+ console.log("no runs");
71
+ return;
72
+ }
73
+ for (const run of runs) {
74
+ console.log(`${run.runId}\t${run.status}\tattempt=${run.attempt}\tupdated=${run.updatedAt}`);
75
+ }
76
+ return;
77
+ }
78
+
79
+ if (subcommand === "status") {
80
+ if (!runId) {
81
+ throw new Error("Usage: gxpm run status <issue-id> <run-id> [--json]");
82
+ }
83
+ const run = readRun({ issueId, runId });
84
+ if (argv.includes("--json")) {
85
+ console.log(JSON.stringify(run, null, 2));
86
+ } else {
87
+ console.log(`runId: ${run.runId}`);
88
+ console.log(`issueId: ${run.issueId}`);
89
+ console.log(`status: ${run.status}`);
90
+ console.log(`attempt: ${run.attempt}`);
91
+ console.log(`sessionId: ${run.sessionId}`);
92
+ if (run.workspacePath) console.log(`workspacePath: ${run.workspacePath}`);
93
+ if (run.failureReason) console.log(`failureReason: ${run.failureReason}`);
94
+ }
95
+ return;
96
+ }
97
+
98
+ if (subcommand === "event") {
99
+ if (!runId) {
100
+ throw new Error("Usage: gxpm run event <issue-id> <run-id> --type <event> [--status <status>] [--message <text>] [--reason <text>]");
101
+ }
102
+ const eventType = optionValue(argv, "--type");
103
+ if (!eventType) {
104
+ throw new Error("gxpm run event requires --type <event>");
105
+ }
106
+ const run = appendRunEvent({
107
+ issueId,
108
+ runId,
109
+ type: eventType,
110
+ status: optionValue(argv, "--status") ?? undefined,
111
+ message: optionValue(argv, "--message") ?? undefined,
112
+ failureReason: optionValue(argv, "--reason") ?? undefined,
113
+ });
114
+ if (argv.includes("--json")) {
115
+ console.log(JSON.stringify(run, null, 2));
116
+ } else {
117
+ console.log(`updated ${run.runId} for ${issueId}`);
118
+ console.log(`status: ${run.status}`);
119
+ }
120
+ return;
121
+ }
122
+
123
+ throw new Error(`Usage: gxpm run start <issue-id> [--attempt N] [--status ${RUN_STATUSES.join("|")}] [--workspace <path>] [--claim] [--actor <name>] [--json]
124
+ gxpm run list <issue-id> [--json]
125
+ gxpm run status <issue-id> <run-id> [--json]
126
+ gxpm run event <issue-id> <run-id> --type <event> [--status <status>] [--message <text>] [--reason <text>]`);
127
+ }
128
+
129
+ function claimRunOrRollback(input: { issueId: string; runId: string; actor?: string }) {
130
+ try {
131
+ const claim = claimIssue({
132
+ issueId: input.issueId,
133
+ actor: input.actor,
134
+ runId: input.runId,
135
+ });
136
+ if (!claim.claimed) {
137
+ deleteRun({ issueId: input.issueId, runId: input.runId });
138
+ throw new Error(`Issue already claimed: ${input.issueId}; no run started`);
139
+ }
140
+ return claim;
141
+ } catch (error) {
142
+ deleteRun({ issueId: input.issueId, runId: input.runId });
143
+ throw error;
144
+ }
145
+ }
146
+
147
+ export async function runWorkspaceCommand(argv: string[], subcommand: string | undefined, issueId: string | undefined) {
148
+ if (!issueId) {
149
+ throw new Error("Usage: gxpm workspace plan|ensure|cleanup <issue-id> [--root <path>] [--json]");
150
+ }
151
+ const workspaceRoot = optionValue(argv, "--root") ?? undefined;
152
+ const result =
153
+ subcommand === "plan"
154
+ ? planIssueWorkspace({ issueId, workspaceRoot })
155
+ : subcommand === "ensure"
156
+ ? await ensureIssueWorkspaceWithResolver({ issueId, workspaceRoot })
157
+ : subcommand === "cleanup"
158
+ ? cleanupIssueWorkspace({ issueId, workspaceRoot })
159
+ : null;
160
+
161
+ if (!result) {
162
+ throw new Error("Usage: gxpm workspace plan|ensure|cleanup <issue-id> [--root <path>] [--json]");
163
+ }
164
+ if (argv.includes("--json")) {
165
+ console.log(JSON.stringify(result, null, 2));
166
+ return;
167
+ }
168
+ console.log(`issueId: ${result.issueId}`);
169
+ console.log(`workspaceRoot: ${result.workspaceRoot}`);
170
+ console.log(`workspacePath: ${result.workspacePath}`);
171
+ console.log(`exists: ${result.exists}`);
172
+ if ("devPort" in result) console.log(`devPort: ${result.devPort}`);
173
+ if ("created" in result) console.log(`created: ${result.created}`);
174
+ if ("removed" in result) console.log(`removed: ${result.removed}`);
175
+ if ("method" in result && result.method) console.log(`method: ${result.method.type}`);
176
+ if ("warnings" in result && result.warnings) console.log(`warnings: ${result.warnings.join("; ")}`);
177
+ }
178
+
179
+ export function runOrchestratorCommand(argv: string[], subcommand: string | undefined) {
180
+ if (subcommand !== "tick" || !argv.includes("--dry-run")) {
181
+ throw new Error("Usage: gxpm orchestrator tick --dry-run [--json] [--include-all]");
182
+ }
183
+ const report = dryRunOrchestratorTick({ includeAll: argv.includes("--include-all") });
184
+ if (argv.includes("--json")) {
185
+ console.log(JSON.stringify(report, null, 2));
186
+ return;
187
+ }
188
+ console.log(`gxpm orchestrator dry-run ${report.generatedAt}`);
189
+ console.log(
190
+ `dispatchable=${report.summary.dispatchable} blocked=${report.summary.blocked} ignored=${report.summary.ignored}`,
191
+ );
192
+ if (report.issues.length === 0) {
193
+ console.log("no candidate issues");
194
+ return;
195
+ }
196
+ for (const issue of report.issues) {
197
+ console.log(`${issue.issueId}\t${issue.currentPhase}\t${issue.decision}\t${issue.reason}`);
198
+ }
199
+ }
@@ -0,0 +1,71 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { confirmSpecify, reviseSpecify } from "../../core/specify";
4
+
5
+ function specPath(issueId: string): string {
6
+ return join(process.cwd(), ".gxpm", "issues", issueId, "artifacts", "behavior-spec.json");
7
+ }
8
+
9
+ function runConfirm(issueId: string) {
10
+ if (!issueId) {
11
+ throw new Error("usage: gxpm specify confirm <issue-id>");
12
+ }
13
+ confirmSpecify({ issueId });
14
+ console.log(`confirmed behavior-spec for ${issueId}`);
15
+ }
16
+
17
+ function runRevise(issueId: string) {
18
+ if (!issueId) {
19
+ throw new Error("usage: gxpm specify revise <issue-id>");
20
+ }
21
+ reviseSpecify({ issueId });
22
+ console.log(`revised behavior-spec for ${issueId} (confirmedAt cleared)`);
23
+ }
24
+
25
+ function runShow(issueId: string) {
26
+ if (!issueId) {
27
+ throw new Error("usage: gxpm specify show <issue-id>");
28
+ }
29
+ const path = specPath(issueId);
30
+ if (!existsSync(path)) {
31
+ throw new Error(`behavior-spec.json not found for ${issueId}`);
32
+ }
33
+ const stored = JSON.parse(readFileSync(path, "utf8"));
34
+ const spec = stored.payload;
35
+ console.log(`Feature: ${spec.feature.title}`);
36
+ console.log(` As a ${spec.feature.asA}`);
37
+ console.log(` I want ${spec.feature.iWant}`);
38
+ console.log(` So that ${spec.feature.soThat}`);
39
+ console.log("");
40
+ for (const scn of spec.scenarios) {
41
+ console.log(`Scenario (${scn.id}): ${scn.name}`);
42
+ for (const g of scn.given) console.log(` Given ${g}`);
43
+ console.log(` When ${scn.when}`);
44
+ for (const t of scn.then) console.log(` Then ${t}`);
45
+ console.log(` Stub: ${scn.stubPath}`);
46
+ console.log("");
47
+ }
48
+ console.log(`confirmedAt: ${spec.confirmedAt ?? "(not confirmed)"}`);
49
+ }
50
+
51
+ export function runSpecifyCommand(
52
+ _argv: string[],
53
+ subcommand: string | undefined,
54
+ issueId: string | undefined,
55
+ ) {
56
+ switch (subcommand) {
57
+ case "confirm":
58
+ runConfirm(issueId ?? "");
59
+ return;
60
+ case "revise":
61
+ runRevise(issueId ?? "");
62
+ return;
63
+ case "show":
64
+ runShow(issueId ?? "");
65
+ return;
66
+ default:
67
+ throw new Error(
68
+ `unknown specify subcommand: ${subcommand ?? "<none>"}; expected confirm|revise|show`,
69
+ );
70
+ }
71
+ }