ultra-builder-pro-cli 0.5.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 (206) hide show
  1. package/.ultra-template/delivery-report.json +9 -0
  2. package/.ultra-template/docs/research/README.md +53 -0
  3. package/.ultra-template/specs/architecture.md +250 -0
  4. package/.ultra-template/specs/discovery.md +248 -0
  5. package/.ultra-template/specs/product.md +223 -0
  6. package/.ultra-template/tasks/contexts/TEMPLATE.md +57 -0
  7. package/.ultra-template/tasks/tasks.json +33 -0
  8. package/.ultra-template/test-report.json +8 -0
  9. package/CHANGELOG.md +194 -0
  10. package/LICENSE +21 -0
  11. package/README.md +187 -0
  12. package/adapters/_shared/codex-assets.cjs +1128 -0
  13. package/adapters/_shared/codex-ultra-tools-entry.cjs +11 -0
  14. package/adapters/_shared/file-ops.cjs +115 -0
  15. package/adapters/_shared/frontmatter.cjs +52 -0
  16. package/adapters/_shared/handbook.cjs +144 -0
  17. package/adapters/_shared/md-to-toml.cjs +54 -0
  18. package/adapters/_shared/path-rewrite.cjs +79 -0
  19. package/adapters/_shared/rtk-detect.cjs +86 -0
  20. package/adapters/_shared/runtime-assets.cjs +70 -0
  21. package/adapters/_shared/settings-merge.cjs +76 -0
  22. package/adapters/_shared/tests/file-ops.test.cjs +54 -0
  23. package/adapters/_shared/tests/frontmatter.test.cjs +47 -0
  24. package/adapters/_shared/tests/handbook.test.cjs +86 -0
  25. package/adapters/_shared/tests/md-to-toml.test.cjs +48 -0
  26. package/adapters/_shared/tests/path-rewrite.test.cjs +60 -0
  27. package/adapters/_shared/tests/resolve-target.test.cjs +85 -0
  28. package/adapters/_shared/tests/rtk-detect.test.cjs +116 -0
  29. package/adapters/_shared/tests/runtime-assets.test.cjs +107 -0
  30. package/adapters/_shared/tests/settings-merge.test.cjs +85 -0
  31. package/adapters/_shared/tests/validate.test.cjs +30 -0
  32. package/adapters/_shared/validate.cjs +24 -0
  33. package/adapters/claude.js +182 -0
  34. package/adapters/codex.js +385 -0
  35. package/adapters/gemini.js +204 -0
  36. package/adapters/opencode.js +506 -0
  37. package/adapters/tests/claude.test.cjs +117 -0
  38. package/adapters/tests/codex-hook.test.cjs +90 -0
  39. package/adapters/tests/codex.test.cjs +356 -0
  40. package/adapters/tests/gemini.test.cjs +112 -0
  41. package/adapters/tests/opencode.test.cjs +246 -0
  42. package/agents/code-reviewer.md +102 -0
  43. package/agents/debugger.md +127 -0
  44. package/agents/review-code.md +125 -0
  45. package/agents/review-comments.md +98 -0
  46. package/agents/review-coordinator.md +146 -0
  47. package/agents/review-design.md +133 -0
  48. package/agents/review-errors.md +87 -0
  49. package/agents/review-tests.md +93 -0
  50. package/agents/tdd-runner.md +92 -0
  51. package/bin/handbook.js +54 -0
  52. package/bin/install.js +254 -0
  53. package/bin/orchestrator.js +214 -0
  54. package/commands/learn.md +41 -0
  55. package/commands/ultra-deliver.md +45 -0
  56. package/commands/ultra-dev.md +50 -0
  57. package/commands/ultra-init.md +51 -0
  58. package/commands/ultra-plan.md +49 -0
  59. package/commands/ultra-research.md +59 -0
  60. package/commands/ultra-status.md +46 -0
  61. package/commands/ultra-test.md +48 -0
  62. package/commands/ultra-think.md +45 -0
  63. package/docs/AGENT-CONTEXT.md +143 -0
  64. package/docs/ARCHITECTURE.md +197 -0
  65. package/docs/COMMIT-HASH-BACKFILL.md +101 -0
  66. package/docs/LEGACY-HERMES.md +1175 -0
  67. package/docs/PLAN.zh-CN.md +1683 -0
  68. package/docs/ROADMAP.md +102 -0
  69. package/docs/RUNTIME-COMPAT-MATRIX.md +98 -0
  70. package/docs/STATE-DB-ACCESS-POLICY.md +109 -0
  71. package/docs/USER-HANDBOOK-CONTRACT.md +61 -0
  72. package/hooks/README.md +24 -0
  73. package/hooks/active_task_context.py +44 -0
  74. package/hooks/adapters/codex.py +302 -0
  75. package/hooks/health_check.py +61 -0
  76. package/hooks/pre_stop_check.py +56 -0
  77. package/hooks/subagent_tracker.py +116 -0
  78. package/hooks/workflow_checkpoint.py +56 -0
  79. package/hooks/workflow_context.py +63 -0
  80. package/hooks/workflow_resume.py +50 -0
  81. package/mcp-server/lib/init-project.cjs +162 -0
  82. package/mcp-server/lib/llm-client.cjs +157 -0
  83. package/mcp-server/lib/llm-client.test.cjs +156 -0
  84. package/mcp-server/lib/plan-store.cjs +96 -0
  85. package/mcp-server/lib/plan-store.test.cjs +132 -0
  86. package/mcp-server/lib/prd-parser.cjs +110 -0
  87. package/mcp-server/lib/prd-parser.test.cjs +171 -0
  88. package/mcp-server/lib/pricing.cjs +53 -0
  89. package/mcp-server/lib/projector.cjs +158 -0
  90. package/mcp-server/lib/state-db.cjs +113 -0
  91. package/mcp-server/lib/state-db.test.cjs +116 -0
  92. package/mcp-server/lib/state-ops.cjs +725 -0
  93. package/mcp-server/lib/task-expander.cjs +123 -0
  94. package/mcp-server/lib/task-expander.test.cjs +253 -0
  95. package/mcp-server/lib/telemetry.cjs +72 -0
  96. package/mcp-server/lib/topo.cjs +131 -0
  97. package/mcp-server/lib/topo.test.cjs +158 -0
  98. package/mcp-server/server.cjs +482 -0
  99. package/mcp-server/tests/circuit-breaker.test.cjs +125 -0
  100. package/mcp-server/tests/commit-hash-flow.test.cjs +117 -0
  101. package/mcp-server/tests/concurrency-update.test.cjs +96 -0
  102. package/mcp-server/tests/concurrency.test.cjs +112 -0
  103. package/mcp-server/tests/db-ops.test.cjs +117 -0
  104. package/mcp-server/tests/init-project.test.cjs +141 -0
  105. package/mcp-server/tests/migrate.test.cjs +144 -0
  106. package/mcp-server/tests/projector.test.cjs +130 -0
  107. package/mcp-server/tests/server-contract.test.cjs +750 -0
  108. package/mcp-server/tests/staleness.test.cjs +190 -0
  109. package/mcp-server/tests/state-ops.test.cjs +286 -0
  110. package/mcp-server/tests/tagged-tasks.test.cjs +163 -0
  111. package/mcp-server/tests/telemetry.test.cjs +205 -0
  112. package/orchestrator/auto-merge.cjs +109 -0
  113. package/orchestrator/code-graph-watcher.cjs +121 -0
  114. package/orchestrator/daemon.cjs +112 -0
  115. package/orchestrator/dispatch-rules.cjs +93 -0
  116. package/orchestrator/parallel-orchestrator.cjs +195 -0
  117. package/orchestrator/planner/expand-prompt.cjs +62 -0
  118. package/orchestrator/planner/expand-prompt.test.cjs +52 -0
  119. package/orchestrator/planner/plan-builder.cjs +116 -0
  120. package/orchestrator/planner/plan-builder.test.cjs +165 -0
  121. package/orchestrator/planner/prd-prompt.cjs +44 -0
  122. package/orchestrator/planner/prd-prompt.test.cjs +30 -0
  123. package/orchestrator/recovery.cjs +70 -0
  124. package/orchestrator/session-runner.cjs +224 -0
  125. package/orchestrator/skill-miner.cjs +133 -0
  126. package/orchestrator/tests/auto-merge.test.cjs +216 -0
  127. package/orchestrator/tests/code-graph-watcher.test.cjs +183 -0
  128. package/orchestrator/tests/daemon.test.cjs +260 -0
  129. package/orchestrator/tests/dispatch-rules.test.cjs +122 -0
  130. package/orchestrator/tests/parallel-orchestrator.test.cjs +233 -0
  131. package/orchestrator/tests/phase-8b-gate.test.cjs +183 -0
  132. package/orchestrator/tests/recovery.test.cjs +190 -0
  133. package/orchestrator/tests/session-runner.test.cjs +314 -0
  134. package/orchestrator/tests/skill-miner.test.cjs +147 -0
  135. package/orchestrator/tests/worktree-manager.test.cjs +148 -0
  136. package/orchestrator/worktree-manager.cjs +131 -0
  137. package/output-styles/coding-vibes.md +67 -0
  138. package/output-styles/structural-thinking.md +61 -0
  139. package/package.json +109 -0
  140. package/settings.json +8 -0
  141. package/skills/cc-collab/SKILL.md +41 -0
  142. package/skills/code-review-expert/SKILL.md +118 -0
  143. package/skills/code-review-expert/references/code-quality-checklist.md +112 -0
  144. package/skills/code-review-expert/references/integration-checklist.md +46 -0
  145. package/skills/code-review-expert/references/removal-plan.md +52 -0
  146. package/skills/code-review-expert/references/security-checklist.md +100 -0
  147. package/skills/code-review-expert/references/solid-checklist.md +65 -0
  148. package/skills/codex-collab/SKILL.md +52 -0
  149. package/skills/codex-collab/evals/evals.json +40 -0
  150. package/skills/gemini-collab/SKILL.md +51 -0
  151. package/skills/gemini-collab/evals/evals.json +42 -0
  152. package/skills/integration-rules/SKILL.md +71 -0
  153. package/skills/learn/SKILL.md +117 -0
  154. package/skills/security-rules/SKILL.md +60 -0
  155. package/skills/testing-rules/SKILL.md +56 -0
  156. package/skills/ultra-deliver/SKILL.md +171 -0
  157. package/skills/ultra-dev/SKILL.md +324 -0
  158. package/skills/ultra-init/SKILL.md +148 -0
  159. package/skills/ultra-plan/SKILL.md +314 -0
  160. package/skills/ultra-research/SKILL.md +156 -0
  161. package/skills/ultra-research/steps/step-00-problem-validation.md +154 -0
  162. package/skills/ultra-research/steps/step-01-opportunity-discovery.md +172 -0
  163. package/skills/ultra-research/steps/step-02-market-assessment.md +195 -0
  164. package/skills/ultra-research/steps/step-03-competitive-landscape.md +197 -0
  165. package/skills/ultra-research/steps/step-04-product-strategy.md +196 -0
  166. package/skills/ultra-research/steps/step-05-assumptions-validation.md +234 -0
  167. package/skills/ultra-research/steps/step-10-user-personas.md +169 -0
  168. package/skills/ultra-research/steps/step-11-user-scenarios.md +181 -0
  169. package/skills/ultra-research/steps/step-20-user-stories.md +156 -0
  170. package/skills/ultra-research/steps/step-21-features-scope.md +157 -0
  171. package/skills/ultra-research/steps/step-22-success-metrics.md +195 -0
  172. package/skills/ultra-research/steps/step-30-architecture-context.md +154 -0
  173. package/skills/ultra-research/steps/step-31-solution-strategy.md +172 -0
  174. package/skills/ultra-research/steps/step-32-building-blocks.md +188 -0
  175. package/skills/ultra-research/steps/step-40-deployment.md +123 -0
  176. package/skills/ultra-research/steps/step-41-quality-risks.md +135 -0
  177. package/skills/ultra-research/steps/step-99-synthesis.md +188 -0
  178. package/skills/ultra-review/SKILL.md +437 -0
  179. package/skills/ultra-review/references/unified-schema.md +127 -0
  180. package/skills/ultra-review/scripts/review_verdict_update.py +99 -0
  181. package/skills/ultra-review/scripts/review_wait.py +120 -0
  182. package/skills/ultra-status/SKILL.md +162 -0
  183. package/skills/ultra-test/SKILL.md +195 -0
  184. package/skills/ultra-think/SKILL.md +109 -0
  185. package/skills/ultra-verify/SKILL.md +111 -0
  186. package/skills/ultra-verify/evals/evals.json +51 -0
  187. package/skills/ultra-verify/references/confidence-system.md +38 -0
  188. package/skills/ultra-verify/references/cross-verify-modes.md +73 -0
  189. package/skills/ultra-verify/scripts/verify_wait.py +131 -0
  190. package/spec/cli-protocol.md +118 -0
  191. package/spec/mcp-tools.yaml +658 -0
  192. package/spec/schemas/command-manifest.schema.json +47 -0
  193. package/spec/schemas/context-file.v4.5.schema.json +54 -0
  194. package/spec/schemas/mcp-tools.schema.json +136 -0
  195. package/spec/schemas/skill-manifest.schema.json +94 -0
  196. package/spec/schemas/state-db.sql +154 -0
  197. package/spec/schemas/tasks.v4.5.schema.json +66 -0
  198. package/ultra-tools/cli.cjs +121 -0
  199. package/ultra-tools/commands/db.cjs +175 -0
  200. package/ultra-tools/commands/legacy-memory.cjs +159 -0
  201. package/ultra-tools/commands/migrate.cjs +354 -0
  202. package/ultra-tools/commands/session.cjs +180 -0
  203. package/ultra-tools/commands/status.cjs +158 -0
  204. package/ultra-tools/commands/task.cjs +95 -0
  205. package/ultra-tools/legacy-memory.test.cjs +80 -0
  206. package/ultra-tools/status-command.test.cjs +132 -0
@@ -0,0 +1,51 @@
1
+ {
2
+ "skill_name": "ultra-verify",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "/ultra-verify decision 'Should we use PostgreSQL or MongoDB for our new microservice?'",
7
+ "expected_output": "Claude answers first, then launches Gemini and Codex in parallel, collects all three analyses, and presents a synthesis with consensus scoring",
8
+ "assertions": [
9
+ "Claude writes its own analysis BEFORE reading external AI output",
10
+ "Launches Gemini and Codex in parallel (run_in_background)",
11
+ "Creates session directory under .ultra/collab/ with verify-decision in name",
12
+ "Reads all three output files with Read tool",
13
+ "Presents confidence level (consensus/majority/no consensus)",
14
+ "Includes per-AI recommendation summary and trade-off matrix"
15
+ ]
16
+ },
17
+ {
18
+ "id": 2,
19
+ "prompt": "/ultra-verify diagnose 'API returns 500 intermittently under load, logs show connection pool exhaustion'",
20
+ "expected_output": "Three sets of hypotheses collected and ranked by consensus count",
21
+ "assertions": [
22
+ "Each AI provides top-3 hypotheses",
23
+ "Hypotheses ranked by consensus count (3/3 > 2/3 > 1/3)",
24
+ "Each hypothesis includes evidence and verification steps",
25
+ "Recommended investigation order based on consensus"
26
+ ]
27
+ },
28
+ {
29
+ "id": 3,
30
+ "prompt": "/ultra-verify audit",
31
+ "expected_output": "Three-way code audit with findings graded by consensus (3=critical, 2=high, 1=investigate)",
32
+ "assertions": [
33
+ "Sends same audit prompt to all three AIs",
34
+ "Findings graded by how many AIs found them",
35
+ "3/3 findings marked Critical, 2/3 marked High, 1/3 marked Investigate",
36
+ "Action items prioritized by consensus count"
37
+ ]
38
+ },
39
+ {
40
+ "id": 4,
41
+ "prompt": "/ultra-verify estimate 'Implement OAuth2 login with Google and GitHub providers'",
42
+ "expected_output": "Three effort estimates compared for convergence",
43
+ "assertions": [
44
+ "Each AI provides estimate with breakdown and assumptions",
45
+ "Convergence analysis (within 20% = high confidence)",
46
+ "Outlier estimates investigated",
47
+ "Final recommended estimate with confidence level"
48
+ ]
49
+ }
50
+ ]
51
+ }
@@ -0,0 +1,38 @@
1
+ # Confidence System
2
+
3
+ Confidence scoring based on AI consensus for cross-verify results.
4
+
5
+ ## Levels
6
+
7
+ ### Consensus (3/3 Agree)
8
+ - **Confidence**: Highest
9
+ - **Action**: Strongly recommended — proceed with high confidence
10
+ - **Display**: `[CONSENSUS 3/3]`
11
+
12
+ ### Majority (2/3 Agree)
13
+ - **Confidence**: High
14
+ - **Action**: Recommended — investigate the dissenting view for edge cases or alternative perspectives
15
+ - **Display**: `[MAJORITY 2/3]` + note which AI dissented and why
16
+
17
+ ### No Consensus (All Differ)
18
+ - **Confidence**: Low
19
+ - **Action**: Decompose the problem into smaller questions, gather more data, or accept that the answer is genuinely ambiguous
20
+ - **Display**: `[NO CONSENSUS]` + summary of each position
21
+
22
+ ## Application by Mode
23
+
24
+ | Mode | Consensus | Majority | No Consensus |
25
+ |------|-----------|----------|--------------|
26
+ | decision | Strong recommendation | Recommended + dissent analysis | Present all options, suggest decomposition |
27
+ | diagnose | Investigate first | Investigate second | Check all, may need more data |
28
+ | audit | Critical — fix now | High — likely real | Investigate — may be false positive |
29
+ | estimate | Use average, high confidence | Investigate outlier | Decompose task further |
30
+
31
+ ## Degraded Confidence
32
+
33
+ When only 2 AIs respond (one failed):
34
+
35
+ - **2/2 Agree**: Equivalent to Majority (not Consensus — missing perspective)
36
+ - **2/2 Differ**: Low confidence — note missing third opinion
37
+
38
+ When only 1 AI responds: Claude-only analysis — explicitly mark as single-source, no consensus scoring.
@@ -0,0 +1,73 @@
1
+ # Ultra Verify Modes
2
+
3
+ Four modes for three-way AI verification. All modes follow the safe orchestration contract in the parent `SKILL.md`.
4
+
5
+ ## 1. Decision (`decision`)
6
+
7
+ For architecture decisions, technology choices, or design trade-offs.
8
+
9
+ **Flow:**
10
+ 1. Present the decision context, constraints, and options to all three AIs independently
11
+ 2. Each AI provides: recommendation, pros/cons, risks, trade-offs
12
+ 3. Synthesis ranks options by consensus:
13
+ - 3/3 recommend same → **Strong recommendation**
14
+ - 2/3 agree → **Recommended** with dissenting view analyzed
15
+ - All different → Present all three with trade-off matrix
16
+
17
+ **Output structure:**
18
+ - Per-AI recommendation summary
19
+ - Consensus matrix (which AI recommends what)
20
+ - Trade-off analysis
21
+ - Final recommendation with confidence level
22
+
23
+ ## 2. Diagnose (`diagnose`)
24
+
25
+ For bug diagnosis, root cause analysis, or troubleshooting.
26
+
27
+ **Flow:**
28
+ 1. Provide symptoms, error messages, relevant code, and recent changes to all three AIs
29
+ 2. Each AI provides its top-3 hypotheses with evidence and verification steps
30
+ 3. Synthesis:
31
+ - Hypotheses appearing in 3/3 lists → **Most likely** (investigate first)
32
+ - Hypotheses in 2/3 lists → **Probable** (investigate second)
33
+ - Unique hypotheses → **Worth checking** (may catch edge cases)
34
+
35
+ **Output structure:**
36
+ - Ranked hypothesis list (by consensus count)
37
+ - Per-hypothesis: description, evidence, verification steps, suggested fix
38
+ - Recommended investigation order
39
+
40
+ ## 3. Audit (`audit`)
41
+
42
+ For code review, security audit, or quality assessment.
43
+
44
+ **Flow:**
45
+ 1. Provide the code scope to all three AIs with the same audit prompt
46
+ 2. Each AI reports findings with severity and location
47
+ 3. Synthesis grades findings by consensus:
48
+ - Found by 3/3 → **Critical** — fix immediately
49
+ - Found by 2/3 → **High** — likely real, investigate
50
+ - Found by 1/3 → **Investigate** — may be false positive or edge case
51
+
52
+ **Output structure:**
53
+ - Findings table: description, severity, consensus count, which AIs found it
54
+ - Grouped by consensus level (Critical → High → Investigate)
55
+ - Action items prioritized by consensus
56
+
57
+ ## 4. Estimate (`estimate`)
58
+
59
+ For effort estimation, complexity assessment, or timeline planning.
60
+
61
+ **Flow:**
62
+ 1. Describe the task, requirements, and constraints to all three AIs
63
+ 2. Each AI provides: estimate (time/effort), breakdown, assumptions, risks
64
+ 3. Synthesis evaluates convergence:
65
+ - All within 20% of each other → **High confidence** estimate (use average)
66
+ - One outlier → **Moderate confidence** — investigate the outlier's reasoning
67
+ - All significantly different → **Low confidence** — task needs decomposition
68
+
69
+ **Output structure:**
70
+ - Per-AI estimate with breakdown and assumptions
71
+ - Convergence analysis
72
+ - Recommended estimate with confidence level
73
+ - Risk factors that could shift the estimate
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env python3
2
+ """Verify Wait - File-based completion waiter for /ultra-verify pipeline.
3
+
4
+ Polls the session directory for expected AI output files.
5
+ Blocks until both AIs produce output OR timeout. Returns structured JSON on stdout.
6
+
7
+ Two exit conditions only:
8
+ 1. Both AIs have output (non-empty + stable size) → exit 0, status="complete"
9
+ 2. Timeout → exit 0, status="timeout" (JSON status field tells the story)
10
+
11
+ Expected files:
12
+ - gemini-output.md (Gemini)
13
+ - codex-output.md (Codex)
14
+
15
+ Usage:
16
+ python3 verify_wait.py <session_path> [--timeout SECONDS]
17
+
18
+ Exit codes:
19
+ 0 - Always (result expressed via JSON status field)
20
+ 2 - Invalid arguments (missing path, bad --timeout)
21
+ """
22
+
23
+ import json
24
+ import sys
25
+ import time
26
+ from pathlib import Path
27
+
28
+ POLL_INTERVAL = 3 # seconds
29
+ DEFAULT_TIMEOUT = 1200 # 20 min — runs via run_in_background (no Bash 600s limit)
30
+
31
+ # Each AI produces exactly one output file
32
+ EXPECTED = {
33
+ "gemini": "gemini-output.md",
34
+ "codex": "codex-output.md",
35
+ }
36
+
37
+
38
+ def _file_size(path: Path) -> int:
39
+ """Return file size in bytes, or -1 if not found."""
40
+ try:
41
+ return path.stat().st_size
42
+ except (FileNotFoundError, OSError):
43
+ return -1
44
+
45
+
46
+ def _check_output(session_path: Path, name: str) -> dict:
47
+ """Check if an AI has produced non-empty output."""
48
+ output = session_path / EXPECTED[name]
49
+ if _file_size(output) > 0:
50
+ return {"name": name, "status": "complete", "file": str(output)}
51
+ return {"name": name, "status": "pending", "file": None}
52
+
53
+
54
+ def _timeout_status(session_path: Path, name: str) -> dict:
55
+ """Determine final status at timeout. Check error logs and empty files."""
56
+ output = session_path / EXPECTED[name]
57
+ error = session_path / f"{name}-error.log"
58
+ output_size = _file_size(output)
59
+ if output_size > 0:
60
+ return {"name": name, "status": "complete", "file": str(output)}
61
+ if _file_size(error) > 0:
62
+ return {"name": name, "status": "failed", "file": str(error)}
63
+ if output_size == 0:
64
+ return {"name": name, "status": "empty", "file": str(output)}
65
+ return {"name": name, "status": "pending", "file": None}
66
+
67
+
68
+ def main():
69
+ if len(sys.argv) < 2:
70
+ print(__doc__, file=sys.stderr)
71
+ sys.exit(2)
72
+
73
+ session_path = Path(sys.argv[1])
74
+ timeout = DEFAULT_TIMEOUT
75
+
76
+ if "--timeout" in sys.argv:
77
+ idx = sys.argv.index("--timeout")
78
+ if idx + 1 < len(sys.argv):
79
+ try:
80
+ timeout = int(sys.argv[idx + 1])
81
+ except ValueError:
82
+ print(f"Error: --timeout must be integer: {sys.argv[idx + 1]}", file=sys.stderr)
83
+ sys.exit(2)
84
+
85
+ if not session_path.is_dir():
86
+ print(f"Error: session directory not found: {session_path}", file=sys.stderr)
87
+ sys.exit(2)
88
+
89
+ deadline = time.monotonic() + timeout
90
+ prev_sizes = {name: _file_size(session_path / f) for name, f in EXPECTED.items()}
91
+
92
+ # Poll loop — exit condition 1: both outputs ready + stable
93
+ while time.monotonic() < deadline:
94
+ cur_sizes = {name: _file_size(session_path / f) for name, f in EXPECTED.items()}
95
+ gemini = _check_output(session_path, "gemini")
96
+ codex = _check_output(session_path, "codex")
97
+
98
+ gemini_done = gemini["status"] == "complete" and cur_sizes["gemini"] == prev_sizes["gemini"]
99
+ codex_done = codex["status"] == "complete" and cur_sizes["codex"] == prev_sizes["codex"]
100
+
101
+ if gemini_done and codex_done:
102
+ elapsed = int(timeout - (deadline - time.monotonic()))
103
+ print(json.dumps({"status": "complete", "gemini": gemini, "codex": codex, "elapsed_seconds": elapsed}))
104
+ sys.exit(0)
105
+
106
+ prev_sizes = cur_sizes
107
+
108
+ # Progress display
109
+ remaining = int(deadline - time.monotonic())
110
+ parts = []
111
+ for name, done, result in [("gemini", gemini_done, gemini), ("codex", codex_done, codex)]:
112
+ if done:
113
+ parts.append(f"{name}:complete")
114
+ elif result["status"] == "complete":
115
+ parts.append(f"{name}:stabilizing")
116
+ else:
117
+ parts.append(f"{name}:waiting")
118
+ done_count = int(gemini_done) + int(codex_done)
119
+ sys.stderr.write(f"\r [{done_count}/2] {' | '.join(parts)} ({remaining}s remaining) ")
120
+ sys.stderr.flush()
121
+ time.sleep(POLL_INTERVAL)
122
+
123
+ # Exit condition 2: timeout — check error logs NOW for final status
124
+ gemini = _timeout_status(session_path, "gemini")
125
+ codex = _timeout_status(session_path, "codex")
126
+ print(json.dumps({"status": "timeout", "gemini": gemini, "codex": codex, "elapsed_seconds": timeout}))
127
+ sys.exit(0)
128
+
129
+
130
+ if __name__ == "__main__":
131
+ main()
@@ -0,0 +1,118 @@
1
+ # `ultra-tools` CLI protocol
2
+
3
+ `ultra-tools` is the shell fallback for the live MCP state contract
4
+ (PLAN §4, D12). Every tool in `spec/mcp-tools.yaml` has a matching
5
+ `ultra-tools <subcommand>`; host-native review, impact discovery, skill
6
+ resolution, and human interaction are intentionally outside this protocol.
7
+
8
+ Trace: PLAN §6 Phase 1.4, decisions D12 / D29 / D33 / D37.
9
+
10
+ ## 1. Invocation
11
+
12
+ ```
13
+ ultra-tools <family> <verb> [--flag value] [positional ...]
14
+ ```
15
+
16
+ - `family` and `verb` together correspond to a `tool.name` in
17
+ `spec/mcp-tools.yaml` (e.g. `task create`, `session admission`).
18
+ - Flags map 1-to-1 to the `input_schema.properties` of the tool.
19
+ - Positional args are reserved for the **id-like primary key** of the tool,
20
+ if the tool has one (`task get <id>`, `session get <sid>`). All other
21
+ fields must be flags so machine callers do not depend on argument order.
22
+ - Boolean flags: `--takeover` for true; `--no-takeover` for false. Default
23
+ is whatever the schema declares.
24
+ - JSON values: pass with `--json '<inline json>'` or `--json-file <path>`
25
+ when an input field is itself an object/array.
26
+
27
+ ## 2. Output
28
+
29
+ The CLI may print human-readable lines to stdout while it runs. The **last
30
+ line of stdout MUST be a single JSON object** matching the tool's
31
+ `output_schema` on success, or an error envelope on failure:
32
+
33
+ ```json
34
+ // success
35
+ { "ok": true, "data": { ... output_schema ... } }
36
+ ```
37
+
38
+ ```json
39
+ // failure
40
+ { "ok": false, "error": { "code": "<ERROR_CODE>", "message": "...", "retriable": false } }
41
+ ```
42
+
43
+ `error.code` MUST be one of the `errors[].code` values declared for that
44
+ tool in `spec/mcp-tools.yaml`. Hooks parse this last line; any extra noise
45
+ must come **before** it.
46
+
47
+ Streaming subcommands (e.g. `task subscribe`) emit one JSON object per
48
+ line during the stream, and finish with the standard envelope on stdout's
49
+ last line.
50
+
51
+ ## 3. Exit codes
52
+
53
+ | Code | Meaning |
54
+ |-----:|---------------------------------------------------|
55
+ | `0` | success — `data` envelope is on stdout |
56
+ | `1` | user error (bad flags, missing required input) |
57
+ | `2` | system error (DB unavailable, IO failure) |
58
+ | `3` | lease conflict — see `error.code = ADMISSION_DENIED` (D33) |
59
+ | `4` | schema mismatch (input or output failed validation) |
60
+ | `5` | timeout — operation exceeded its budget |
61
+ | `124`| reserved for SIGTERM / killed by orchestrator |
62
+
63
+ Exit code is **the** ground truth for hooks; the JSON envelope is
64
+ informational. Never rely on stderr for status.
65
+
66
+ ## 4. Stdin / stdout / stderr discipline
67
+
68
+ - **stdin**: closed by default. Tools that accept large input
69
+ (`task parse-prd`) read from `--prd-file <path>` rather than stdin to
70
+ keep streaming pipelines deterministic.
71
+ - **stdout**: human-readable lines + the trailing JSON envelope.
72
+ - **stderr**: log lines only (structured JSON; `level / message / context`).
73
+ Never carry success data on stderr.
74
+
75
+ ## 5. Tool ↔ CLI mapping
76
+
77
+ The mapping below is generated from `spec/mcp-tools.yaml` by
78
+ `spec/scripts/check-cli-mapping.cjs` and asserted at gate time. This table
79
+ is the authoritative reference; do not duplicate it in command md files.
80
+
81
+ | MCP tool | CLI subcommand | Phase | Writer |
82
+ |---------------------------|-----------------------------|------:|---------|
83
+ | `task.create` | `task create` | 2 | mcp |
84
+ | `task.update` | `task update` | 2 | mcp |
85
+ | `task.list` | `task list` | 2 | any |
86
+ | `task.get` | `task get` | 2 | any |
87
+ | `task.delete` | `task delete` | 2 | mcp |
88
+ | `task.switch_tag` | `task switch-tag` | 7.2 | mcp |
89
+ | `task.init_project` | `task init-project` | 3 | mcp |
90
+ | `task.expand` | `task expand` | 8a | mcp |
91
+ | `task.parse_prd` | `task parse-prd` | 8a | mcp |
92
+ | `task.dependency_topo` | `task topo` | 8a | mcp |
93
+ | `task.append_event` | `task append-event` | 2 | any |
94
+ | `task.subscribe_events` | `task subscribe` | 2 | any |
95
+ | `session.spawn` | `session spawn` | 4.5 | mcp |
96
+ | `session.close` | `session close` | 4.5 | mcp |
97
+ | `session.get` | `session get` | 4.5 | any |
98
+ | `session.list` | `session list` | 4.5 | any |
99
+ | `session.admission_check` | `session admission` | 4.5 | any |
100
+ | `session.heartbeat` | `session heartbeat` | 4.5 | mcp |
101
+ | `session.subscribe_events`| `session subscribe` | 4.5 | any |
102
+ | `plan.export` | `plan export` | 8a | mcp |
103
+ | `plan.get` | `plan get` | 8a | any |
104
+
105
+ `Writer = mcp` rows go through the MCP server's single-writer connection;
106
+ the CLI shells out to the running MCP server over stdio rather than
107
+ touching `.ultra/state.db` directly. `Writer = any` rows are safe to
108
+ execute from any process — read-only queries and `events` appends fall
109
+ into this bucket because `events.id AUTOINCREMENT` makes concurrent
110
+ INSERTs collision-free under WAL + `busy_timeout`. The full policy lives
111
+ in `docs/STATE-DB-ACCESS-POLICY.md` (Phase 2.2 / R25).
112
+
113
+ ## 6. Versioning
114
+
115
+ The CLI follows the `version` field of `spec/mcp-tools.yaml`. Adding a new
116
+ flag is a minor bump; renaming or removing a flag, or changing exit-code
117
+ semantics, is a major bump. Major bumps require an entry in
118
+ `docs/PLAN.zh-CN.md §14 Decision log`.