ultra-builder-pro-cli 0.15.0 → 0.17.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/specs/research-distillate.md +4 -3
- package/CHANGELOG.md +120 -1
- package/README.md +67 -30
- package/adapters/_shared/codex-assets.cjs +10 -5
- package/adapters/_shared/handbook.cjs +3 -2
- package/adapters/_shared/interaction-contract.cjs +61 -0
- package/adapters/claude.js +1 -1
- package/adapters/opencode.js +1 -1
- package/bin/orchestrator.js +175 -19
- package/commands/ultra-change.md +1 -1
- package/commands/ultra-deliver.md +3 -3
- package/commands/ultra-init.md +1 -1
- package/commands/ultra-plan.md +1 -1
- package/commands/ultra-research.md +2 -2
- package/commands/ultra-review.md +10 -0
- package/commands/ultra-status.md +1 -1
- package/commands/ultra-test.md +1 -1
- package/commands/ultra-think.md +2 -2
- package/docs/AGENT-CONTEXT.md +38 -18
- package/docs/ARCHITECTURE.md +91 -13
- package/docs/LEGACY-CLI-CROSSWALK.md +163 -0
- package/docs/PLAN.zh-CN.md +19 -12
- package/docs/ROADMAP.md +5 -3
- package/docs/RUNTIME-COMPAT-MATRIX.md +4 -4
- package/docs/STATE-DB-ACCESS-POLICY.md +8 -6
- package/docs/USER-HANDBOOK-CONTRACT.md +8 -2
- package/docs/WORKFLOW-LIFECYCLE.md +179 -39
- package/hooks/pre_stop_check.py +3 -2
- package/mcp-server/lib/baseline-workflow.cjs +84 -16
- package/mcp-server/lib/change-workflow.cjs +107 -39
- package/mcp-server/lib/context-spine.cjs +215 -87
- package/mcp-server/lib/decision-dialogue.cjs +713 -0
- package/mcp-server/lib/doctor.cjs +9 -0
- package/mcp-server/lib/git-bootstrap.cjs +240 -0
- package/mcp-server/lib/init-project.cjs +178 -41
- package/mcp-server/lib/project-breadcrumb.cjs +23 -14
- package/mcp-server/lib/state-db.cjs +279 -9
- package/mcp-server/lib/state-ops.cjs +64 -1
- package/mcp-server/lib/workflow-state.cjs +313 -205
- package/mcp-server/server.cjs +112 -34
- package/orchestrator/auto-merge.cjs +19 -0
- package/orchestrator/daemon.cjs +104 -0
- package/orchestrator/parallel-orchestrator.cjs +371 -49
- package/orchestrator/session-runner.cjs +354 -25
- package/package.json +2 -1
- package/skills/ultra-change/SKILL.md +69 -65
- package/skills/ultra-deliver/SKILL.md +37 -58
- package/skills/ultra-dev/SKILL.md +55 -49
- package/skills/ultra-doctor/SKILL.md +44 -49
- package/skills/ultra-init/SKILL.md +78 -100
- package/skills/ultra-plan/SKILL.md +78 -79
- package/skills/ultra-research/SKILL.md +99 -98
- package/skills/ultra-review/SKILL.md +38 -47
- package/skills/ultra-review/references/review-modes.md +5 -3
- package/skills/ultra-review/references/unified-schema.md +26 -6
- package/skills/ultra-review/scripts/review_wait.py +12 -0
- package/skills/ultra-status/SKILL.md +34 -40
- package/skills/ultra-test/SKILL.md +61 -48
- package/skills/ultra-think/SKILL.md +47 -47
- package/skills/ultra-think/references/decision-dialogue.md +106 -0
- package/spec/cli-protocol.md +46 -2
- package/spec/mcp-tools.yaml +444 -29
- package/spec/schemas/delivery-report.v1.schema.json +1 -46
- package/spec/schemas/mcp-tools.schema.json +1 -1
- package/spec/schemas/state-db.sql +66 -2
- package/spec/schemas/test-report.v1.schema.json +45 -14
- package/ultra-tools/cli.cjs +1 -1
- package/ultra-tools/commands/session.cjs +10 -3
- package/ultra-tools/commands/status.cjs +34 -14
- package/ultra-tools/commands/system.cjs +2 -2
- package/ultra-tools/commands/task.cjs +3 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": [
|
|
7
7
|
"$schema", "change_id", "archive_status", "baseline_id", "baseline_status",
|
|
8
|
-
"git_commit", "worktree_digest", "context_digest", "checks", "
|
|
8
|
+
"git_commit", "worktree_digest", "context_digest", "checks", "rollback", "timestamp"
|
|
9
9
|
],
|
|
10
10
|
"additionalProperties": false,
|
|
11
11
|
"properties": {
|
|
@@ -41,51 +41,6 @@
|
|
|
41
41
|
]
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
|
-
"release": {
|
|
45
|
-
"type": "object",
|
|
46
|
-
"required": ["authorized", "performed", "evidence"],
|
|
47
|
-
"additionalProperties": false,
|
|
48
|
-
"properties": {
|
|
49
|
-
"authorized": { "type": "boolean" },
|
|
50
|
-
"performed": { "type": "boolean" },
|
|
51
|
-
"evidence": {
|
|
52
|
-
"type": "array",
|
|
53
|
-
"items": {
|
|
54
|
-
"type": "object",
|
|
55
|
-
"required": ["kind", "reference", "status", "evidence"],
|
|
56
|
-
"additionalProperties": false,
|
|
57
|
-
"properties": {
|
|
58
|
-
"kind": { "enum": ["commit", "push", "tag", "registry", "deploy", "release", "other"] },
|
|
59
|
-
"reference": { "type": "string", "minLength": 1 },
|
|
60
|
-
"status": { "const": "pass" },
|
|
61
|
-
"evidence": { "type": "string", "minLength": 1 }
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
"version": { "type": "string" },
|
|
66
|
-
"tag": { "type": "string" },
|
|
67
|
-
"commit": { "type": "string" },
|
|
68
|
-
"registry": { "type": "string" },
|
|
69
|
-
"remote": { "type": "string" }
|
|
70
|
-
},
|
|
71
|
-
"allOf": [
|
|
72
|
-
{
|
|
73
|
-
"if": { "properties": { "authorized": { "const": true } } },
|
|
74
|
-
"then": {
|
|
75
|
-
"properties": {
|
|
76
|
-
"performed": { "const": true },
|
|
77
|
-
"evidence": { "minItems": 1 }
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
"else": {
|
|
81
|
-
"properties": {
|
|
82
|
-
"performed": { "const": false },
|
|
83
|
-
"evidence": { "maxItems": 0 }
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
},
|
|
89
44
|
"rollback": { "type": ["string", "null"] },
|
|
90
45
|
"timestamp": { "type": ["string", "null"], "format": "date-time" }
|
|
91
46
|
},
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
},
|
|
61
61
|
"family": {
|
|
62
62
|
"type": "string",
|
|
63
|
-
"enum": ["task", "memory", "review", "impact", "skill", "session", "ask", "plan", "baseline", "change", "workflow", "system"]
|
|
63
|
+
"enum": ["task", "memory", "review", "impact", "skill", "session", "ask", "plan", "baseline", "change", "decision", "workflow", "system"]
|
|
64
64
|
},
|
|
65
65
|
"description": { "type": "string", "minLength": 10 },
|
|
66
66
|
"phase": {
|
|
@@ -29,7 +29,7 @@ CREATE TABLE IF NOT EXISTS baselines (
|
|
|
29
29
|
repository_revision TEXT,
|
|
30
30
|
repository_branch TEXT,
|
|
31
31
|
worktree_state TEXT NOT NULL DEFAULT 'unavailable'
|
|
32
|
-
CHECK (worktree_state IN ('clean', 'dirty', 'unavailable')),
|
|
32
|
+
CHECK (worktree_state IN ('clean', 'dirty', 'unborn', 'unavailable')),
|
|
33
33
|
worktree_digest TEXT,
|
|
34
34
|
worktree_files_json TEXT NOT NULL DEFAULT '[]',
|
|
35
35
|
worktree_accepted INTEGER NOT NULL DEFAULT 0 CHECK (worktree_accepted IN (0, 1)),
|
|
@@ -67,6 +67,7 @@ CREATE TABLE IF NOT EXISTS changes (
|
|
|
67
67
|
contract_json TEXT NOT NULL DEFAULT '{}',
|
|
68
68
|
classification_json TEXT NOT NULL DEFAULT '{}',
|
|
69
69
|
research_disposition_json TEXT NOT NULL DEFAULT '{}',
|
|
70
|
+
alignment_thread_id TEXT REFERENCES decision_threads(id) ON DELETE SET NULL,
|
|
70
71
|
base_commit TEXT,
|
|
71
72
|
artifact_root TEXT NOT NULL,
|
|
72
73
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
@@ -251,7 +252,9 @@ CREATE TABLE IF NOT EXISTS context_snapshots (
|
|
|
251
252
|
CHECK (role IN ('plan', 'implement', 'check', 'review')),
|
|
252
253
|
gate TEXT NOT NULL DEFAULT 'alignment'
|
|
253
254
|
CHECK (gate IN ('alignment', 'planning', 'implementation', 'verification', 'review', 'convergence', 'recovery')),
|
|
254
|
-
next_action TEXT NOT NULL DEFAULT '
|
|
255
|
+
next_action TEXT NOT NULL DEFAULT '',
|
|
256
|
+
allowed_transitions_json TEXT NOT NULL DEFAULT '[]',
|
|
257
|
+
required_transition TEXT,
|
|
255
258
|
readiness TEXT NOT NULL DEFAULT 'ready'
|
|
256
259
|
CHECK (readiness IN ('ready', 'blocked')),
|
|
257
260
|
blockers_json TEXT NOT NULL DEFAULT '[]',
|
|
@@ -403,6 +406,61 @@ CREATE UNIQUE INDEX IF NOT EXISTS workflow_steps_position
|
|
|
403
406
|
CREATE INDEX IF NOT EXISTS workflow_steps_status
|
|
404
407
|
ON workflow_steps(run_id, status, position);
|
|
405
408
|
|
|
409
|
+
-- ──────────────────────────── decision dialogue ─────────────────────────
|
|
410
|
+
-- The host owns reasoning and normalized decision content. MCP owns one-at-a-
|
|
411
|
+
-- time presentation, durable authority, checkpoints, and recovery. Raw prompts
|
|
412
|
+
-- and transcripts never belong in these tables.
|
|
413
|
+
CREATE TABLE IF NOT EXISTS decision_threads (
|
|
414
|
+
id TEXT PRIMARY KEY,
|
|
415
|
+
purpose TEXT NOT NULL,
|
|
416
|
+
mode TEXT NOT NULL DEFAULT 'guided'
|
|
417
|
+
CHECK (mode IN ('guided', 'fast', 'autonomous', 'diagnostic')),
|
|
418
|
+
status TEXT NOT NULL DEFAULT 'active'
|
|
419
|
+
CHECK (status IN ('active', 'checkpoint_ready', 'confirmed', 'cancelled')),
|
|
420
|
+
baseline_id TEXT REFERENCES baselines(id) ON DELETE SET NULL,
|
|
421
|
+
change_id TEXT REFERENCES changes(id) ON DELETE CASCADE,
|
|
422
|
+
workflow_run_id TEXT REFERENCES workflow_runs(id) ON DELETE CASCADE,
|
|
423
|
+
summary_json TEXT NOT NULL DEFAULT '{}',
|
|
424
|
+
checkpoint_json TEXT NOT NULL DEFAULT '{}',
|
|
425
|
+
started_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
426
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
427
|
+
confirmed_at TEXT,
|
|
428
|
+
CHECK (baseline_id IS NOT NULL OR change_id IS NOT NULL OR workflow_run_id IS NOT NULL)
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
CREATE INDEX IF NOT EXISTS decision_threads_status
|
|
432
|
+
ON decision_threads(status, updated_at);
|
|
433
|
+
CREATE INDEX IF NOT EXISTS decision_threads_authority
|
|
434
|
+
ON decision_threads(baseline_id, change_id, workflow_run_id, status);
|
|
435
|
+
|
|
436
|
+
CREATE TABLE IF NOT EXISTS decision_items (
|
|
437
|
+
id TEXT PRIMARY KEY,
|
|
438
|
+
thread_id TEXT NOT NULL REFERENCES decision_threads(id) ON DELETE CASCADE,
|
|
439
|
+
sequence INTEGER NOT NULL CHECK (sequence > 0),
|
|
440
|
+
phase TEXT NOT NULL,
|
|
441
|
+
question TEXT NOT NULL,
|
|
442
|
+
why_now TEXT NOT NULL,
|
|
443
|
+
recommendation TEXT NOT NULL,
|
|
444
|
+
options_json TEXT NOT NULL DEFAULT '[]',
|
|
445
|
+
evidence_refs_json TEXT NOT NULL DEFAULT '[]',
|
|
446
|
+
dependency_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
447
|
+
effects_json TEXT NOT NULL DEFAULT '{}',
|
|
448
|
+
blocking INTEGER NOT NULL DEFAULT 1 CHECK (blocking IN (0, 1)),
|
|
449
|
+
status TEXT NOT NULL DEFAULT 'open'
|
|
450
|
+
CHECK (status IN ('open', 'answered', 'delegated', 'deferred', 'superseded')),
|
|
451
|
+
resolution_json TEXT NOT NULL DEFAULT '{}',
|
|
452
|
+
supersedes_id TEXT REFERENCES decision_items(id) ON DELETE SET NULL,
|
|
453
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
454
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
455
|
+
resolved_at TEXT,
|
|
456
|
+
UNIQUE (thread_id, sequence)
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
CREATE UNIQUE INDEX IF NOT EXISTS decision_items_one_open
|
|
460
|
+
ON decision_items(thread_id) WHERE status = 'open';
|
|
461
|
+
CREATE INDEX IF NOT EXISTS decision_items_status
|
|
462
|
+
ON decision_items(thread_id, status, sequence);
|
|
463
|
+
|
|
406
464
|
-- ──────────────────────────── seed: schema_version ────────────────────────
|
|
407
465
|
INSERT OR IGNORE INTO schema_version (version, description)
|
|
408
466
|
VALUES ('4.5', 'Phase 2 initial — tasks/events/sessions/schema_version/migration_history/telemetry/specs_refs');
|
|
@@ -428,3 +486,9 @@ INSERT OR IGNORE INTO schema_version (version, description)
|
|
|
428
486
|
VALUES ('14.0', 'Continuously revalidated baseline authority and persisted known-red acceptance');
|
|
429
487
|
INSERT OR IGNORE INTO schema_version (version, description)
|
|
430
488
|
VALUES ('15.0', 'Typed research semantics, complete change contracts, verified learning application, and reconciliation provenance');
|
|
489
|
+
INSERT OR IGNORE INTO schema_version (version, description)
|
|
490
|
+
VALUES ('16.0', 'Durable one-question decision dialogue, owner checkpoints, and workflow alignment gates');
|
|
491
|
+
INSERT OR IGNORE INTO schema_version (version, description)
|
|
492
|
+
VALUES ('17.0', 'Explicit unborn Git authority and owner-authorized baseline checkpoints');
|
|
493
|
+
INSERT OR IGNORE INTO schema_version (version, description)
|
|
494
|
+
VALUES ('18.0', 'Adaptive capability transitions, independent initialization, and recoverable workflow migration');
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"required": [
|
|
7
7
|
"$schema", "change_id", "task_ids", "git_commit", "worktree_digest",
|
|
8
8
|
"context_digest", "acceptance", "commands", "public_seams", "failures",
|
|
9
|
-
"recovery", "verification_dimensions", "regression_signal", "passed", "run_count",
|
|
9
|
+
"recovery", "verification_profile", "verification_dimensions", "regression_signal", "passed", "run_count",
|
|
10
10
|
"timestamp", "blocking_issues"
|
|
11
11
|
],
|
|
12
12
|
"additionalProperties": false,
|
|
@@ -93,12 +93,36 @@
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
|
+
"verification_profile": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"required": ["rationale", "selected_dimensions", "excluded_dimensions"],
|
|
99
|
+
"additionalProperties": false,
|
|
100
|
+
"properties": {
|
|
101
|
+
"rationale": { "type": "string", "minLength": 3 },
|
|
102
|
+
"selected_dimensions": {
|
|
103
|
+
"type": "array",
|
|
104
|
+
"minItems": 1,
|
|
105
|
+
"uniqueItems": true,
|
|
106
|
+
"contains": { "const": "acceptance" },
|
|
107
|
+
"items": { "$ref": "#/$defs/verificationDimensionName" }
|
|
108
|
+
},
|
|
109
|
+
"excluded_dimensions": {
|
|
110
|
+
"type": "array",
|
|
111
|
+
"items": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"required": ["dimension", "rationale"],
|
|
114
|
+
"additionalProperties": false,
|
|
115
|
+
"properties": {
|
|
116
|
+
"dimension": { "$ref": "#/$defs/verificationDimensionName" },
|
|
117
|
+
"rationale": { "type": "string", "minLength": 3 }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
96
123
|
"verification_dimensions": {
|
|
97
124
|
"type": "object",
|
|
98
|
-
"required": [
|
|
99
|
-
"acceptance", "regression", "integration", "static_analysis",
|
|
100
|
-
"build", "performance", "security", "recovery"
|
|
101
|
-
],
|
|
125
|
+
"required": ["acceptance"],
|
|
102
126
|
"additionalProperties": false,
|
|
103
127
|
"properties": {
|
|
104
128
|
"acceptance": { "$ref": "#/$defs/verificationDimension" },
|
|
@@ -131,12 +155,19 @@
|
|
|
131
155
|
"blocking_issues": { "type": "array", "items": { "type": "string" } }
|
|
132
156
|
},
|
|
133
157
|
"$defs": {
|
|
158
|
+
"verificationDimensionName": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"enum": [
|
|
161
|
+
"acceptance", "regression", "integration", "static_analysis",
|
|
162
|
+
"build", "performance", "security", "recovery"
|
|
163
|
+
]
|
|
164
|
+
},
|
|
134
165
|
"verificationDimension": {
|
|
135
166
|
"type": "object",
|
|
136
167
|
"required": ["status", "evidence", "rationale"],
|
|
137
168
|
"additionalProperties": false,
|
|
138
169
|
"properties": {
|
|
139
|
-
"status": { "enum": ["pass", "fail", "not_run"
|
|
170
|
+
"status": { "enum": ["pass", "fail", "not_run"] },
|
|
140
171
|
"evidence": {
|
|
141
172
|
"type": "array",
|
|
142
173
|
"items": { "type": "string", "minLength": 1 }
|
|
@@ -174,14 +205,14 @@
|
|
|
174
205
|
"recovery": { "items": { "properties": { "status": { "const": "pass" } } } },
|
|
175
206
|
"verification_dimensions": {
|
|
176
207
|
"properties": {
|
|
177
|
-
"acceptance": { "properties": { "status": { "
|
|
178
|
-
"regression": { "properties": { "status": { "
|
|
179
|
-
"integration": { "properties": { "status": { "
|
|
180
|
-
"static_analysis": { "properties": { "status": { "
|
|
181
|
-
"build": { "properties": { "status": { "
|
|
182
|
-
"performance": { "properties": { "status": { "
|
|
183
|
-
"security": { "properties": { "status": { "
|
|
184
|
-
"recovery": { "properties": { "status": { "
|
|
208
|
+
"acceptance": { "properties": { "status": { "const": "pass" } } },
|
|
209
|
+
"regression": { "properties": { "status": { "const": "pass" } } },
|
|
210
|
+
"integration": { "properties": { "status": { "const": "pass" } } },
|
|
211
|
+
"static_analysis": { "properties": { "status": { "const": "pass" } } },
|
|
212
|
+
"build": { "properties": { "status": { "const": "pass" } } },
|
|
213
|
+
"performance": { "properties": { "status": { "const": "pass" } } },
|
|
214
|
+
"security": { "properties": { "status": { "const": "pass" } } },
|
|
215
|
+
"recovery": { "properties": { "status": { "const": "pass" } } }
|
|
185
216
|
}
|
|
186
217
|
},
|
|
187
218
|
"run_count": { "minimum": 1 },
|
package/ultra-tools/cli.cjs
CHANGED
|
@@ -38,7 +38,7 @@ SUBCOMMANDS:
|
|
|
38
38
|
system doctor [--repair] | restore | rebaseline
|
|
39
39
|
status [--cost] [--since <duration>] [--json]
|
|
40
40
|
db init | checkpoint | vacuum | integrity | backup (Phase 2)
|
|
41
|
-
migrate --from=<4.4|4.5> --to=<4.5|
|
|
41
|
+
migrate --from=<4.4|4.5> --to=<4.5|18.0> [--dry|--rollback]
|
|
42
42
|
legacy-memory inspect | archive | prune --confirm DELETE_ULTRA_LEGACY_MEMORY
|
|
43
43
|
|
|
44
44
|
--help / -h show this message
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
const path = require('node:path');
|
|
10
10
|
const { initStateDb, closeStateDb } = require('../../mcp-server/lib/state-db.cjs');
|
|
11
11
|
const ops = require('../../mcp-server/lib/state-ops.cjs');
|
|
12
|
+
const sessionRunner = require('../../orchestrator/session-runner.cjs');
|
|
12
13
|
|
|
13
14
|
const DEFAULT_DB_PATH = path.join('.ultra', 'state.db');
|
|
14
15
|
|
|
@@ -20,11 +21,12 @@ VERBS:
|
|
|
20
21
|
reap [--grace-seconds <n>] orphan sweeper (Phase 4.5.6)
|
|
21
22
|
get --sid <sid>
|
|
22
23
|
heartbeat --sid <sid>
|
|
23
|
-
close --sid <sid> --status completed|crashed|orphan
|
|
24
|
+
close --sid <sid> --status completed|crashed|orphan [--remove-worktree]
|
|
24
25
|
subscribe --since-id <n> [--sid <sid>] [--limit <n>]
|
|
25
26
|
|
|
26
27
|
GLOBAL FLAGS:
|
|
27
28
|
--db <path> path to state.db (default: .ultra/state.db)
|
|
29
|
+
--repo-root <path> repository root for verified worktree cleanup (default: cwd)
|
|
28
30
|
-h, --help show this message
|
|
29
31
|
`;
|
|
30
32
|
|
|
@@ -44,6 +46,8 @@ function parseFlags(args) {
|
|
|
44
46
|
case '--limit': flags.limit = Number(args[++i]); break;
|
|
45
47
|
case '--since-id': flags.since_id = Number(args[++i]); break;
|
|
46
48
|
case '--grace-seconds': flags.grace_seconds = Number(args[++i]); break;
|
|
49
|
+
case '--repo-root': flags.repo_root = args[++i]; break;
|
|
50
|
+
case '--remove-worktree': flags.remove_worktree = true; break;
|
|
47
51
|
case '-h': case '--help': flags.help = true; break;
|
|
48
52
|
default: flags._.push(a);
|
|
49
53
|
}
|
|
@@ -127,8 +131,11 @@ function cmdClose(flags) {
|
|
|
127
131
|
if (!flags.sid || !flags.status) { emit({ ok: false, error: { code: 'VALIDATION_ERROR', message: 'missing --sid or --status' } }); return 1; }
|
|
128
132
|
return withDb(flags, (db) => {
|
|
129
133
|
try {
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
const result = sessionRunner.closeSession(
|
|
135
|
+
{ db, repoRoot: path.resolve(flags.repo_root || process.cwd()), sid: flags.sid },
|
|
136
|
+
{ status: flags.status, remove_worktree: flags.remove_worktree === true },
|
|
137
|
+
);
|
|
138
|
+
emit({ ok: true, data: result });
|
|
132
139
|
return 0;
|
|
133
140
|
} catch (err) {
|
|
134
141
|
emit({ ok: false, error: { code: err.code || 'STATE_DB_ERROR', message: err.message } });
|
|
@@ -12,11 +12,12 @@ const path = require('node:path');
|
|
|
12
12
|
const ops = require('../../mcp-server/lib/state-ops.cjs');
|
|
13
13
|
const baselines = require('../../mcp-server/lib/baseline-workflow.cjs');
|
|
14
14
|
const workflowState = require('../../mcp-server/lib/workflow-state.cjs');
|
|
15
|
+
const decisionDialogue = require('../../mcp-server/lib/decision-dialogue.cjs');
|
|
15
16
|
const { readBreadcrumb } = require('../../mcp-server/lib/context-spine.cjs');
|
|
16
17
|
|
|
17
18
|
const USAGE = `ultra-tools status [flags]
|
|
18
19
|
|
|
19
|
-
Reads .ultra/state.db and prints baseline, workflow, task, session,
|
|
20
|
+
Reads .ultra/state.db and prints baseline, workflow, task, session, valid transitions, and
|
|
20
21
|
cost-observability status.
|
|
21
22
|
|
|
22
23
|
FLAGS:
|
|
@@ -167,20 +168,25 @@ function buildStatusPanel(db, { since = null, limit = 3, rootDir = process.cwd()
|
|
|
167
168
|
};
|
|
168
169
|
}
|
|
169
170
|
if (!Array.isArray(workflows.current)) workflows.current = [];
|
|
170
|
-
|
|
171
|
+
const decisions = tables.has('decision_threads') && tables.has('decision_items')
|
|
172
|
+
? decisionDialogue.inspectDecisionHealth(db, { rootDir })
|
|
173
|
+
: {
|
|
174
|
+
status: 'unavailable', active: 0, awaiting_owner: 0, checkpoint_ready: 0,
|
|
175
|
+
deferred_blocking: 0, stale_artifacts: [], current: null, current_thread_id: null,
|
|
176
|
+
};
|
|
177
|
+
let transitions;
|
|
171
178
|
let breadcrumb = null;
|
|
172
179
|
try {
|
|
173
180
|
if (!tables.has('baselines')) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
recommended_workflow: 'ultra-init', readiness: 'blocked',
|
|
181
|
+
transitions = {
|
|
182
|
+
allowed: ['ultra-init', 'ultra-status'], required: 'ultra-init', readiness: 'blocked',
|
|
177
183
|
blockers: ['BASELINE_SCHEMA_MIGRATION_REQUIRED'], warnings: [],
|
|
178
184
|
};
|
|
179
185
|
} else {
|
|
180
186
|
breadcrumb = readBreadcrumb(db, {}, { rootDir });
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
transitions = {
|
|
188
|
+
allowed: breadcrumb.allowed_transitions,
|
|
189
|
+
required: breadcrumb.required_transition,
|
|
184
190
|
readiness: breadcrumb.readiness,
|
|
185
191
|
blockers: breadcrumb.blockers,
|
|
186
192
|
warnings: breadcrumb.warnings,
|
|
@@ -190,9 +196,8 @@ function buildStatusPanel(db, { since = null, limit = 3, rootDir = process.cwd()
|
|
|
190
196
|
};
|
|
191
197
|
}
|
|
192
198
|
} catch (error) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
recommended_workflow: 'ultra-doctor', readiness: 'blocked',
|
|
199
|
+
transitions = {
|
|
200
|
+
allowed: ['ultra-doctor', 'ultra-status'], required: 'ultra-doctor', readiness: 'blocked',
|
|
196
201
|
blockers: [`STATUS_AUTHORITY_UNAVAILABLE:${error.code || 'unknown'}`], warnings: [],
|
|
197
202
|
};
|
|
198
203
|
}
|
|
@@ -242,13 +247,14 @@ function buildStatusPanel(db, { since = null, limit = 3, rootDir = process.cwd()
|
|
|
242
247
|
period: { since: since || 'all-time' },
|
|
243
248
|
baseline,
|
|
244
249
|
workflows,
|
|
250
|
+
decisions,
|
|
245
251
|
current_change: currentChange,
|
|
246
252
|
current_task: currentTask,
|
|
247
253
|
evidence,
|
|
248
254
|
changes,
|
|
249
255
|
tasks: taskCounts,
|
|
250
256
|
sessions,
|
|
251
|
-
|
|
257
|
+
transitions,
|
|
252
258
|
by_runtime,
|
|
253
259
|
top_tasks,
|
|
254
260
|
total_cost_usd,
|
|
@@ -287,6 +293,13 @@ function renderHuman(panel) {
|
|
|
287
293
|
`Workflow: ${current.id} (${current.kind}/${current.status}) · step=${current.current_step || 'finalize'} · outputs=${current.output_health}`,
|
|
288
294
|
);
|
|
289
295
|
}
|
|
296
|
+
if (panel.decisions.current) {
|
|
297
|
+
lines.push(
|
|
298
|
+
`Decision: ${panel.decisions.current.id} (${panel.decisions.current.phase}) — ${panel.decisions.current.question}`,
|
|
299
|
+
);
|
|
300
|
+
} else if (panel.decisions.checkpoint_ready > 0) {
|
|
301
|
+
lines.push(`Decision checkpoint: ${panel.decisions.current_thread_id} awaits confirmation`);
|
|
302
|
+
}
|
|
290
303
|
lines.push(
|
|
291
304
|
`Changes: active=${panel.changes.active} blocked=${panel.changes.blocked} ready=${panel.changes.ready} archived=${panel.changes.archived}`,
|
|
292
305
|
);
|
|
@@ -300,7 +313,8 @@ function renderHuman(panel) {
|
|
|
300
313
|
lines.push(
|
|
301
314
|
`Sessions: running=${panel.sessions.running} crashed=${panel.sessions.crashed} orphan=${panel.sessions.orphan}`,
|
|
302
315
|
);
|
|
303
|
-
lines.push(`
|
|
316
|
+
lines.push(`Allowed transitions: ${panel.transitions.allowed.join(', ') || 'none'}`);
|
|
317
|
+
if (panel.transitions.required) lines.push(`Required transition: ${panel.transitions.required}`);
|
|
304
318
|
lines.push(
|
|
305
319
|
`Evidence: test=${panel.evidence.test.status} review=${panel.evidence.review.status} delivery=${panel.evidence.delivery.status}`,
|
|
306
320
|
);
|
|
@@ -345,6 +359,11 @@ function resolveDbPath() {
|
|
|
345
359
|
return path.resolve('.ultra', 'state.db');
|
|
346
360
|
}
|
|
347
361
|
|
|
362
|
+
function resolveRootDir(dbPath) {
|
|
363
|
+
if (process.env.UBP_ROOT_DIR) return path.resolve(process.env.UBP_ROOT_DIR);
|
|
364
|
+
return path.dirname(path.dirname(dbPath));
|
|
365
|
+
}
|
|
366
|
+
|
|
348
367
|
function dispatch(args) {
|
|
349
368
|
let flags;
|
|
350
369
|
try { flags = parseFlags(args); } catch (err) { return fail('USAGE_ERROR', err.message); }
|
|
@@ -362,7 +381,7 @@ function dispatch(args) {
|
|
|
362
381
|
const Database = require('better-sqlite3');
|
|
363
382
|
const db = new Database(dbPath, { readonly: true });
|
|
364
383
|
try {
|
|
365
|
-
const rootDir =
|
|
384
|
+
const rootDir = resolveRootDir(dbPath);
|
|
366
385
|
const panel = buildStatusPanel(db, { since, limit: flags.limit, rootDir });
|
|
367
386
|
if (flags.json) {
|
|
368
387
|
emit({ ok: true, data: panel });
|
|
@@ -383,4 +402,5 @@ module.exports = {
|
|
|
383
402
|
renderHuman,
|
|
384
403
|
parseSince,
|
|
385
404
|
parseFlags,
|
|
405
|
+
resolveRootDir,
|
|
386
406
|
};
|
|
@@ -213,7 +213,7 @@ async function dispatchRestore(args) {
|
|
|
213
213
|
quarantined_state_path: path.join(recoveryDir, 'state.db'),
|
|
214
214
|
schema_version: initialized.schema_version,
|
|
215
215
|
schema_migration_backup_path: initialized.backup_path || null,
|
|
216
|
-
|
|
216
|
+
recovery_guidance: 'Run ultra-tools system doctor, then ultra-init to inspect baseline readiness.',
|
|
217
217
|
},
|
|
218
218
|
});
|
|
219
219
|
return 0;
|
|
@@ -284,7 +284,7 @@ async function dispatchRebaseline(args) {
|
|
|
284
284
|
: null,
|
|
285
285
|
baseline: initialized.baseline,
|
|
286
286
|
copied_files: initialized.copied_files,
|
|
287
|
-
|
|
287
|
+
recovery_guidance: 'Inspect the preserved evidence, run explicit adoption research, record the brownfield baseline, and obtain owner approval before convergence.',
|
|
288
288
|
},
|
|
289
289
|
});
|
|
290
290
|
return 0;
|
|
@@ -17,6 +17,7 @@ FLAGS (init-project):
|
|
|
17
17
|
--project-type <type> web | api | cli | fullstack | other
|
|
18
18
|
--stack <stack> tech stack descriptor (comma-separated ok)
|
|
19
19
|
--mode <mode> auto | greenfield | brownfield (default: auto)
|
|
20
|
+
--git-mode <mode> auto | initialize | skip (default: auto)
|
|
20
21
|
--scope <path> baseline scope; repeat for multiple paths (default: .)
|
|
21
22
|
--resume preserve existing .ultra/ and install only missing assets
|
|
22
23
|
--overwrite replace existing .ultra/ (backup created)
|
|
@@ -38,6 +39,7 @@ function parseInitFlags(args) {
|
|
|
38
39
|
case '--project-type': flags.project_type = args[++i]; break;
|
|
39
40
|
case '--stack': flags.stack = args[++i]; break;
|
|
40
41
|
case '--mode': flags.mode = args[++i]; break;
|
|
42
|
+
case '--git-mode': flags.git_mode = args[++i]; break;
|
|
41
43
|
case '--scope': flags.scope.push(args[++i]); break;
|
|
42
44
|
case '--resume': flags.resume = true; break;
|
|
43
45
|
case '--source-template': flags.source_template = args[++i]; break;
|
|
@@ -66,6 +68,7 @@ function dispatchInitProject(rawArgs) {
|
|
|
66
68
|
project_type: flags.project_type,
|
|
67
69
|
stack: flags.stack,
|
|
68
70
|
mode: flags.mode || 'auto',
|
|
71
|
+
git_mode: flags.git_mode || 'auto',
|
|
69
72
|
scope: flags.scope.length > 0 ? flags.scope : undefined,
|
|
70
73
|
resume: !!flags.resume,
|
|
71
74
|
overwrite: !!flags.overwrite,
|