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.
- package/.ultra-template/delivery-report.json +9 -0
- package/.ultra-template/docs/research/README.md +53 -0
- package/.ultra-template/specs/architecture.md +250 -0
- package/.ultra-template/specs/discovery.md +248 -0
- package/.ultra-template/specs/product.md +223 -0
- package/.ultra-template/tasks/contexts/TEMPLATE.md +57 -0
- package/.ultra-template/tasks/tasks.json +33 -0
- package/.ultra-template/test-report.json +8 -0
- package/CHANGELOG.md +194 -0
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/adapters/_shared/codex-assets.cjs +1128 -0
- package/adapters/_shared/codex-ultra-tools-entry.cjs +11 -0
- package/adapters/_shared/file-ops.cjs +115 -0
- package/adapters/_shared/frontmatter.cjs +52 -0
- package/adapters/_shared/handbook.cjs +144 -0
- package/adapters/_shared/md-to-toml.cjs +54 -0
- package/adapters/_shared/path-rewrite.cjs +79 -0
- package/adapters/_shared/rtk-detect.cjs +86 -0
- package/adapters/_shared/runtime-assets.cjs +70 -0
- package/adapters/_shared/settings-merge.cjs +76 -0
- package/adapters/_shared/tests/file-ops.test.cjs +54 -0
- package/adapters/_shared/tests/frontmatter.test.cjs +47 -0
- package/adapters/_shared/tests/handbook.test.cjs +86 -0
- package/adapters/_shared/tests/md-to-toml.test.cjs +48 -0
- package/adapters/_shared/tests/path-rewrite.test.cjs +60 -0
- package/adapters/_shared/tests/resolve-target.test.cjs +85 -0
- package/adapters/_shared/tests/rtk-detect.test.cjs +116 -0
- package/adapters/_shared/tests/runtime-assets.test.cjs +107 -0
- package/adapters/_shared/tests/settings-merge.test.cjs +85 -0
- package/adapters/_shared/tests/validate.test.cjs +30 -0
- package/adapters/_shared/validate.cjs +24 -0
- package/adapters/claude.js +182 -0
- package/adapters/codex.js +385 -0
- package/adapters/gemini.js +204 -0
- package/adapters/opencode.js +506 -0
- package/adapters/tests/claude.test.cjs +117 -0
- package/adapters/tests/codex-hook.test.cjs +90 -0
- package/adapters/tests/codex.test.cjs +356 -0
- package/adapters/tests/gemini.test.cjs +112 -0
- package/adapters/tests/opencode.test.cjs +246 -0
- package/agents/code-reviewer.md +102 -0
- package/agents/debugger.md +127 -0
- package/agents/review-code.md +125 -0
- package/agents/review-comments.md +98 -0
- package/agents/review-coordinator.md +146 -0
- package/agents/review-design.md +133 -0
- package/agents/review-errors.md +87 -0
- package/agents/review-tests.md +93 -0
- package/agents/tdd-runner.md +92 -0
- package/bin/handbook.js +54 -0
- package/bin/install.js +254 -0
- package/bin/orchestrator.js +214 -0
- package/commands/learn.md +41 -0
- package/commands/ultra-deliver.md +45 -0
- package/commands/ultra-dev.md +50 -0
- package/commands/ultra-init.md +51 -0
- package/commands/ultra-plan.md +49 -0
- package/commands/ultra-research.md +59 -0
- package/commands/ultra-status.md +46 -0
- package/commands/ultra-test.md +48 -0
- package/commands/ultra-think.md +45 -0
- package/docs/AGENT-CONTEXT.md +143 -0
- package/docs/ARCHITECTURE.md +197 -0
- package/docs/COMMIT-HASH-BACKFILL.md +101 -0
- package/docs/LEGACY-HERMES.md +1175 -0
- package/docs/PLAN.zh-CN.md +1683 -0
- package/docs/ROADMAP.md +102 -0
- package/docs/RUNTIME-COMPAT-MATRIX.md +98 -0
- package/docs/STATE-DB-ACCESS-POLICY.md +109 -0
- package/docs/USER-HANDBOOK-CONTRACT.md +61 -0
- package/hooks/README.md +24 -0
- package/hooks/active_task_context.py +44 -0
- package/hooks/adapters/codex.py +302 -0
- package/hooks/health_check.py +61 -0
- package/hooks/pre_stop_check.py +56 -0
- package/hooks/subagent_tracker.py +116 -0
- package/hooks/workflow_checkpoint.py +56 -0
- package/hooks/workflow_context.py +63 -0
- package/hooks/workflow_resume.py +50 -0
- package/mcp-server/lib/init-project.cjs +162 -0
- package/mcp-server/lib/llm-client.cjs +157 -0
- package/mcp-server/lib/llm-client.test.cjs +156 -0
- package/mcp-server/lib/plan-store.cjs +96 -0
- package/mcp-server/lib/plan-store.test.cjs +132 -0
- package/mcp-server/lib/prd-parser.cjs +110 -0
- package/mcp-server/lib/prd-parser.test.cjs +171 -0
- package/mcp-server/lib/pricing.cjs +53 -0
- package/mcp-server/lib/projector.cjs +158 -0
- package/mcp-server/lib/state-db.cjs +113 -0
- package/mcp-server/lib/state-db.test.cjs +116 -0
- package/mcp-server/lib/state-ops.cjs +725 -0
- package/mcp-server/lib/task-expander.cjs +123 -0
- package/mcp-server/lib/task-expander.test.cjs +253 -0
- package/mcp-server/lib/telemetry.cjs +72 -0
- package/mcp-server/lib/topo.cjs +131 -0
- package/mcp-server/lib/topo.test.cjs +158 -0
- package/mcp-server/server.cjs +482 -0
- package/mcp-server/tests/circuit-breaker.test.cjs +125 -0
- package/mcp-server/tests/commit-hash-flow.test.cjs +117 -0
- package/mcp-server/tests/concurrency-update.test.cjs +96 -0
- package/mcp-server/tests/concurrency.test.cjs +112 -0
- package/mcp-server/tests/db-ops.test.cjs +117 -0
- package/mcp-server/tests/init-project.test.cjs +141 -0
- package/mcp-server/tests/migrate.test.cjs +144 -0
- package/mcp-server/tests/projector.test.cjs +130 -0
- package/mcp-server/tests/server-contract.test.cjs +750 -0
- package/mcp-server/tests/staleness.test.cjs +190 -0
- package/mcp-server/tests/state-ops.test.cjs +286 -0
- package/mcp-server/tests/tagged-tasks.test.cjs +163 -0
- package/mcp-server/tests/telemetry.test.cjs +205 -0
- package/orchestrator/auto-merge.cjs +109 -0
- package/orchestrator/code-graph-watcher.cjs +121 -0
- package/orchestrator/daemon.cjs +112 -0
- package/orchestrator/dispatch-rules.cjs +93 -0
- package/orchestrator/parallel-orchestrator.cjs +195 -0
- package/orchestrator/planner/expand-prompt.cjs +62 -0
- package/orchestrator/planner/expand-prompt.test.cjs +52 -0
- package/orchestrator/planner/plan-builder.cjs +116 -0
- package/orchestrator/planner/plan-builder.test.cjs +165 -0
- package/orchestrator/planner/prd-prompt.cjs +44 -0
- package/orchestrator/planner/prd-prompt.test.cjs +30 -0
- package/orchestrator/recovery.cjs +70 -0
- package/orchestrator/session-runner.cjs +224 -0
- package/orchestrator/skill-miner.cjs +133 -0
- package/orchestrator/tests/auto-merge.test.cjs +216 -0
- package/orchestrator/tests/code-graph-watcher.test.cjs +183 -0
- package/orchestrator/tests/daemon.test.cjs +260 -0
- package/orchestrator/tests/dispatch-rules.test.cjs +122 -0
- package/orchestrator/tests/parallel-orchestrator.test.cjs +233 -0
- package/orchestrator/tests/phase-8b-gate.test.cjs +183 -0
- package/orchestrator/tests/recovery.test.cjs +190 -0
- package/orchestrator/tests/session-runner.test.cjs +314 -0
- package/orchestrator/tests/skill-miner.test.cjs +147 -0
- package/orchestrator/tests/worktree-manager.test.cjs +148 -0
- package/orchestrator/worktree-manager.cjs +131 -0
- package/output-styles/coding-vibes.md +67 -0
- package/output-styles/structural-thinking.md +61 -0
- package/package.json +109 -0
- package/settings.json +8 -0
- package/skills/cc-collab/SKILL.md +41 -0
- package/skills/code-review-expert/SKILL.md +118 -0
- package/skills/code-review-expert/references/code-quality-checklist.md +112 -0
- package/skills/code-review-expert/references/integration-checklist.md +46 -0
- package/skills/code-review-expert/references/removal-plan.md +52 -0
- package/skills/code-review-expert/references/security-checklist.md +100 -0
- package/skills/code-review-expert/references/solid-checklist.md +65 -0
- package/skills/codex-collab/SKILL.md +52 -0
- package/skills/codex-collab/evals/evals.json +40 -0
- package/skills/gemini-collab/SKILL.md +51 -0
- package/skills/gemini-collab/evals/evals.json +42 -0
- package/skills/integration-rules/SKILL.md +71 -0
- package/skills/learn/SKILL.md +117 -0
- package/skills/security-rules/SKILL.md +60 -0
- package/skills/testing-rules/SKILL.md +56 -0
- package/skills/ultra-deliver/SKILL.md +171 -0
- package/skills/ultra-dev/SKILL.md +324 -0
- package/skills/ultra-init/SKILL.md +148 -0
- package/skills/ultra-plan/SKILL.md +314 -0
- package/skills/ultra-research/SKILL.md +156 -0
- package/skills/ultra-research/steps/step-00-problem-validation.md +154 -0
- package/skills/ultra-research/steps/step-01-opportunity-discovery.md +172 -0
- package/skills/ultra-research/steps/step-02-market-assessment.md +195 -0
- package/skills/ultra-research/steps/step-03-competitive-landscape.md +197 -0
- package/skills/ultra-research/steps/step-04-product-strategy.md +196 -0
- package/skills/ultra-research/steps/step-05-assumptions-validation.md +234 -0
- package/skills/ultra-research/steps/step-10-user-personas.md +169 -0
- package/skills/ultra-research/steps/step-11-user-scenarios.md +181 -0
- package/skills/ultra-research/steps/step-20-user-stories.md +156 -0
- package/skills/ultra-research/steps/step-21-features-scope.md +157 -0
- package/skills/ultra-research/steps/step-22-success-metrics.md +195 -0
- package/skills/ultra-research/steps/step-30-architecture-context.md +154 -0
- package/skills/ultra-research/steps/step-31-solution-strategy.md +172 -0
- package/skills/ultra-research/steps/step-32-building-blocks.md +188 -0
- package/skills/ultra-research/steps/step-40-deployment.md +123 -0
- package/skills/ultra-research/steps/step-41-quality-risks.md +135 -0
- package/skills/ultra-research/steps/step-99-synthesis.md +188 -0
- package/skills/ultra-review/SKILL.md +437 -0
- package/skills/ultra-review/references/unified-schema.md +127 -0
- package/skills/ultra-review/scripts/review_verdict_update.py +99 -0
- package/skills/ultra-review/scripts/review_wait.py +120 -0
- package/skills/ultra-status/SKILL.md +162 -0
- package/skills/ultra-test/SKILL.md +195 -0
- package/skills/ultra-think/SKILL.md +109 -0
- package/skills/ultra-verify/SKILL.md +111 -0
- package/skills/ultra-verify/evals/evals.json +51 -0
- package/skills/ultra-verify/references/confidence-system.md +38 -0
- package/skills/ultra-verify/references/cross-verify-modes.md +73 -0
- package/skills/ultra-verify/scripts/verify_wait.py +131 -0
- package/spec/cli-protocol.md +118 -0
- package/spec/mcp-tools.yaml +658 -0
- package/spec/schemas/command-manifest.schema.json +47 -0
- package/spec/schemas/context-file.v4.5.schema.json +54 -0
- package/spec/schemas/mcp-tools.schema.json +136 -0
- package/spec/schemas/skill-manifest.schema.json +94 -0
- package/spec/schemas/state-db.sql +154 -0
- package/spec/schemas/tasks.v4.5.schema.json +66 -0
- package/ultra-tools/cli.cjs +121 -0
- package/ultra-tools/commands/db.cjs +175 -0
- package/ultra-tools/commands/legacy-memory.cjs +159 -0
- package/ultra-tools/commands/migrate.cjs +354 -0
- package/ultra-tools/commands/session.cjs +180 -0
- package/ultra-tools/commands/status.cjs +158 -0
- package/ultra-tools/commands/task.cjs +95 -0
- package/ultra-tools/legacy-memory.test.cjs +80 -0
- 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`.
|