ultra-builder-pro-cli 0.12.1 → 0.13.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/docs/research/README.md +21 -44
- package/.ultra-template/specs/discovery.md +10 -0
- package/CHANGELOG.md +53 -1
- package/README.md +25 -9
- package/adapters/_shared/handbook.cjs +2 -2
- package/adapters/tests/codex.test.cjs +8 -0
- package/commands/ultra-init.md +1 -1
- package/docs/AGENT-CONTEXT.md +4 -3
- package/docs/ARCHITECTURE.md +32 -16
- package/docs/PLAN.zh-CN.md +5 -4
- package/docs/ROADMAP.md +1 -1
- package/docs/STATE-DB-ACCESS-POLICY.md +3 -3
- package/docs/USER-HANDBOOK-CONTRACT.md +5 -4
- package/hooks/context_spine.py +37 -4
- package/mcp-server/lib/archive-journal.cjs +192 -0
- package/mcp-server/lib/archive-journal.test.cjs +35 -0
- package/mcp-server/lib/baseline-workflow.cjs +404 -38
- package/mcp-server/lib/baseline-workflow.test.cjs +252 -0
- package/mcp-server/lib/change-workflow.cjs +249 -75
- package/mcp-server/lib/change-workflow.test.cjs +235 -1
- package/mcp-server/lib/context-spine.test.cjs +5 -0
- package/mcp-server/lib/doctor.cjs +14 -1
- package/mcp-server/lib/doctor.test.cjs +42 -4
- package/mcp-server/lib/init-project.cjs +292 -9
- package/mcp-server/lib/spec-learning.test.cjs +1 -1
- package/mcp-server/lib/state-authority.cjs +9 -3
- package/mcp-server/lib/state-db.cjs +154 -32
- package/mcp-server/lib/state-db.test.cjs +136 -4
- package/mcp-server/lib/state-ops.cjs +68 -6
- package/mcp-server/lib/task-expander.cjs +7 -1
- package/mcp-server/lib/task-expander.test.cjs +71 -0
- package/mcp-server/server.cjs +14 -3
- package/mcp-server/tests/init-project.test.cjs +162 -1
- package/mcp-server/tests/migrate.test.cjs +33 -0
- package/mcp-server/tests/server-contract.test.cjs +384 -6
- package/mcp-server/tests/state-db.test.cjs +14 -2
- package/mcp-server/tests/state-ops.test.cjs +108 -0
- package/package.json +1 -1
- package/skills/ultra-change/SKILL.md +18 -10
- package/skills/ultra-deliver/SKILL.md +13 -9
- package/skills/ultra-dev/SKILL.md +6 -4
- package/skills/ultra-doctor/SKILL.md +22 -7
- package/skills/ultra-init/SKILL.md +104 -59
- package/skills/ultra-init/references/brownfield-adoption.md +65 -37
- package/skills/ultra-plan/SKILL.md +8 -5
- package/skills/ultra-research/SKILL.md +12 -5
- package/skills/ultra-status/SKILL.md +6 -4
- package/spec/cli-protocol.md +11 -1
- package/spec/mcp-tools.yaml +95 -9
- package/spec/schemas/state-db.sql +11 -0
- package/ultra-tools/cli.cjs +9 -5
- package/ultra-tools/commands/migrate.cjs +62 -36
- package/ultra-tools/commands/status.cjs +18 -9
- package/ultra-tools/commands/system.cjs +340 -6
- package/ultra-tools/commands/task.cjs +7 -1
- package/ultra-tools/status-command.test.cjs +29 -0
- package/ultra-tools/system-command.test.cjs +252 -1
|
@@ -51,11 +51,18 @@ default.
|
|
|
51
51
|
5. Validate cross-document consistency and trace each required behavior from problem
|
|
52
52
|
or constraint to acceptance and architecture.
|
|
53
53
|
6. Use `references/synthesis.md` for the completion check.
|
|
54
|
-
7.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
7. Record unresolved evidence as the baseline gap ledger: `baseline_blocker`,
|
|
55
|
+
`documentation_drift`, `known_defect`, `technical_debt`, `unknown`, or
|
|
56
|
+
`future_change`. Keep accepted non-blocking work out of the implementation backlog
|
|
57
|
+
until the owner selects it.
|
|
58
|
+
8. Call `baseline.record` with the complete current specification list, bounded evidence
|
|
59
|
+
references, actual verification results, provider metadata, explicit unknowns,
|
|
60
|
+
classification, and the full gap ledger. Use the returned repository revision for
|
|
61
|
+
convergence.
|
|
62
|
+
9. Present the baseline, open gaps, dirty-worktree state, and any known-red verification
|
|
63
|
+
to the owner. After explicit approval, call `baseline.converge`, setting acceptance
|
|
64
|
+
flags only for the exact known-red or dirty snapshot approved by the owner. Resolve
|
|
65
|
+
deterministic blockers before routing.
|
|
59
66
|
|
|
60
67
|
## Completion gate
|
|
61
68
|
|
|
@@ -12,8 +12,8 @@ authoritative; reports and Markdown are evidence or projections.
|
|
|
12
12
|
|
|
13
13
|
1. Call `system.doctor` in read-only mode. If authority is unhealthy, route only to
|
|
14
14
|
`ultra-doctor` and include the blocking diagnostic.
|
|
15
|
-
2. Call `baseline.get` for mode, lifecycle status, repository revision,
|
|
16
|
-
digest health,
|
|
15
|
+
2. Call `baseline.get` for mode, lifecycle status, repository revision, branch,
|
|
16
|
+
worktree snapshot, specification digest health, gap ledger, and adoption blockers.
|
|
17
17
|
3. Call `change.breadcrumb` for the active change, task, role, gate, readiness,
|
|
18
18
|
blockers, advisory warnings, staleness, and next action.
|
|
19
19
|
4. Call `task.list` and `session.list` for progress and active execution details.
|
|
@@ -30,7 +30,9 @@ Follow the breadcrumb's primary route and return one action, not a menu:
|
|
|
30
30
|
|
|
31
31
|
- unhealthy authority: `ultra-doctor`;
|
|
32
32
|
- missing Ultra project: `ultra-init`;
|
|
33
|
-
-
|
|
33
|
+
- projection-only authority conflict: run the exact supported import command from the
|
|
34
|
+
MCP error, then `ultra-init`;
|
|
35
|
+
- migrated or missing baseline evidence with no active change: `ultra-init`, then
|
|
34
36
|
`ultra-research` or `ultra-plan` according to the gap;
|
|
35
37
|
- baseline or context-budget warning during an active change: keep the current route
|
|
36
38
|
and surface the warning; do not turn it into a refusal;
|
|
@@ -50,7 +52,7 @@ Use a compact shape:
|
|
|
50
52
|
```text
|
|
51
53
|
Ultra: <healthy|degraded> · <branch>@<head> · worktree <clean|dirty>
|
|
52
54
|
Position: change=<id|none> task=<id|none> role=<role> gate=<gate>
|
|
53
|
-
Baseline: <greenfield|brownfield|migrated>/<status> revision=<revision|none>
|
|
55
|
+
Baseline: <greenfield|brownfield|migrated>/<status> revision=<revision|none> gaps=<open>/<blocking>
|
|
54
56
|
Readiness: <ready|blocked|stale> — <blockers or none>
|
|
55
57
|
Warnings: <advisory conditions or none>
|
|
56
58
|
Progress: <completed>/<total>; sessions=<active count>
|
package/spec/cli-protocol.md
CHANGED
|
@@ -120,10 +120,20 @@ as a fallback unless `ultra-tools <family> --help` lists it.
|
|
|
120
120
|
|
|
121
121
|
Current executable maintenance surfaces are `task init-project`,
|
|
122
122
|
`session close|get|list|admission|heartbeat|subscribe|reap`, `status`, `db`,
|
|
123
|
-
`migrate`, and `legacy-memory`. In particular, `task create|update|list|get`
|
|
123
|
+
`migrate`, `system doctor|restore|rebaseline`, and `legacy-memory`. In particular, `task create|update|list|get`
|
|
124
124
|
and all `change` lifecycle verbs are not CLI fallbacks. Change state must use
|
|
125
125
|
the live MCP server; `system doctor` may additionally be exposed by the
|
|
126
126
|
maintenance CLI because it is the recovery path when MCP startup is degraded.
|
|
127
|
+
`task init-project --resume` preserves existing `.ultra` files and installs only
|
|
128
|
+
missing current scaffold assets. Projection-only state uses the supported
|
|
129
|
+
`migrate --from=4.4 --to=4.5` or `--from=4.5 --to=12.0` transition before resume.
|
|
130
|
+
`system doctor --repair` applies supported schema upgrades with a pre-migration
|
|
131
|
+
backup before mechanical recovery.
|
|
132
|
+
`system restore` requires the exact `REPLACE_CORRUPT_ULTRA_STATE` confirmation and a
|
|
133
|
+
verified database inside `.ultra/backups`; it quarantines the corrupt state before
|
|
134
|
+
atomic replacement. `system rebaseline` requires the exact
|
|
135
|
+
`REBASELINE_CORRUPT_ULTRA_STATE` confirmation and preserves corrupt state plus the
|
|
136
|
+
legacy task projection before starting a new brownfield adoption.
|
|
127
137
|
The full access policy lives in
|
|
128
138
|
`docs/STATE-DB-ACCESS-POLICY.md` (Phase 2.2 / R25).
|
|
129
139
|
|
package/spec/mcp-tools.yaml
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
# Validated by spec/schemas/mcp-tools.schema.json (run `npm run test:spec`).
|
|
4
4
|
# Trace: PLAN §7.3, decisions D12 / D29 / D31-D34.
|
|
5
5
|
|
|
6
|
-
version: '1.
|
|
6
|
+
version: '1.2'
|
|
7
7
|
|
|
8
8
|
info:
|
|
9
9
|
title: Ultra Builder Pro MCP tool contracts
|
|
10
|
-
phase: '1.
|
|
10
|
+
phase: '1.2'
|
|
11
11
|
trace_to: 'PLAN docs/PLAN.zh-CN.md §7.3'
|
|
12
12
|
notes: |
|
|
13
13
|
This published contract contains only tools registered by the MCP server.
|
|
@@ -32,7 +32,7 @@ tools:
|
|
|
32
32
|
# ─────────────────────────── task family ────────────────────────────────
|
|
33
33
|
- name: task.create
|
|
34
34
|
family: task
|
|
35
|
-
description: Create a new task in state.db. Emits task_created event. If `id` is omitted the server mints a uuid.
|
|
35
|
+
description: Create a new task in state.db. Emits task_created event. If `id` is omitted the server mints a uuid. Child tasks inherit the parent's change ownership; conflicting ownership is rejected.
|
|
36
36
|
phase: '2'
|
|
37
37
|
writer_role: mcp
|
|
38
38
|
input_schema:
|
|
@@ -48,10 +48,10 @@ tools:
|
|
|
48
48
|
estimated_days: { type: number, exclusiveMinimum: 0, description: 'estimated implementation effort in days' }
|
|
49
49
|
deps: { type: array, items: { type: string } }
|
|
50
50
|
files_modified: { type: array, items: { type: string }, description: 'Phase 8A conflict detection' }
|
|
51
|
-
parent_id: { type: string, description: 'Phase 8A.3 parent reference
|
|
51
|
+
parent_id: { type: string, description: 'Phase 8A.3 parent reference; the child inherits this task change ownership' }
|
|
52
52
|
tag: { type: string, description: 'git branch tag (Phase 7.2)' }
|
|
53
53
|
trace_to: { type: string, description: 'spec anchor (e.g. spec/mcp-tools.yaml#task.create)' }
|
|
54
|
-
change_id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$', description: 'continuous change unit owning this task' }
|
|
54
|
+
change_id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$', description: 'active or blocked continuous change unit owning this task; inherited from parent_id when omitted' }
|
|
55
55
|
output_schema:
|
|
56
56
|
type: object
|
|
57
57
|
required: [id, status, created_at]
|
|
@@ -63,6 +63,11 @@ tools:
|
|
|
63
63
|
errors:
|
|
64
64
|
- { code: VALIDATION_ERROR, description: 'input failed schema validation' }
|
|
65
65
|
- { code: DUPLICATE_TASK_ID, description: 'task id already exists' }
|
|
66
|
+
- { code: TASK_NOT_FOUND, description: 'parent task does not exist' }
|
|
67
|
+
- { code: CHANGE_NOT_FOUND, description: 'assigned change does not exist' }
|
|
68
|
+
- { code: CHANGE_NOT_MUTABLE, description: 'assigned change no longer accepts tasks' }
|
|
69
|
+
- { code: TASK_CHANGE_OWNERSHIP_MISMATCH, description: 'child ownership conflicts with its parent change' }
|
|
70
|
+
- { code: BASELINE_NOT_READY, description: 'ordinary task creation requires a ready baseline or an already-authorized active change' }
|
|
66
71
|
- { code: LEGACY_STATE_MIGRATION_REQUIRED, description: 'non-empty v4.4 projection must be migrated before state-backed tools can run' }
|
|
67
72
|
- { code: STATE_DB_LOCKED, description: 'database is locked', retriable: true }
|
|
68
73
|
cli_subcommand: task create
|
|
@@ -106,6 +111,9 @@ tools:
|
|
|
106
111
|
- { code: TASK_NOT_FOUND, description: 'no task with given id' }
|
|
107
112
|
- { code: ILLEGAL_STATUS_TRANSITION, description: 'transition rejected by state machine' }
|
|
108
113
|
- { code: VALIDATION_ERROR, description: 'patch failed schema validation' }
|
|
114
|
+
- { code: CHANGE_NOT_FOUND, description: 'assigned change does not exist' }
|
|
115
|
+
- { code: CHANGE_NOT_MUTABLE, description: 'assigned change no longer accepts task updates' }
|
|
116
|
+
- { code: TASK_CHANGE_OWNERSHIP_MISMATCH, description: 'task ownership conflicts with its parent or children' }
|
|
109
117
|
- { code: LEGACY_STATE_MIGRATION_REQUIRED, description: 'non-empty v4.4 projection must be migrated before state-backed tools can run' }
|
|
110
118
|
cli_subcommand: task update
|
|
111
119
|
emits_events: [task_started, task_completed, task_blocked, task_stale_marked]
|
|
@@ -246,6 +254,17 @@ tools:
|
|
|
246
254
|
enum: [auto, greenfield, brownfield]
|
|
247
255
|
default: auto
|
|
248
256
|
description: auto detects whether meaningful project content already exists
|
|
257
|
+
resume:
|
|
258
|
+
type: boolean
|
|
259
|
+
default: false
|
|
260
|
+
description: preserve an existing `.ultra/`, upgrade its schema, and install only missing current scaffold files
|
|
261
|
+
scope:
|
|
262
|
+
type: array
|
|
263
|
+
minItems: 1
|
|
264
|
+
uniqueItems: true
|
|
265
|
+
items: { type: string, minLength: 1 }
|
|
266
|
+
default: ['.']
|
|
267
|
+
description: project-relative repository roots governed by the initial baseline
|
|
249
268
|
overwrite:
|
|
250
269
|
type: boolean
|
|
251
270
|
default: false
|
|
@@ -255,7 +274,7 @@ tools:
|
|
|
255
274
|
description: override path to the template root (defaults to bundled templates/.ultra/)
|
|
256
275
|
output_schema:
|
|
257
276
|
type: object
|
|
258
|
-
required: [created_path, state_db_path, status, mode, baseline, copied_files]
|
|
277
|
+
required: [created_path, state_db_path, status, mode, baseline, copied_files, repository_profile]
|
|
259
278
|
additionalProperties: false
|
|
260
279
|
properties:
|
|
261
280
|
created_path:
|
|
@@ -266,28 +285,38 @@ tools:
|
|
|
266
285
|
description: absolute path to the initialized authoritative SQLite database
|
|
267
286
|
status:
|
|
268
287
|
type: string
|
|
269
|
-
enum: [created, overwritten]
|
|
288
|
+
enum: [created, overwritten, resumed]
|
|
270
289
|
mode:
|
|
271
290
|
type: string
|
|
272
291
|
enum: [greenfield, brownfield]
|
|
273
292
|
baseline:
|
|
274
293
|
type: object
|
|
275
|
-
required: [id, mode, status]
|
|
294
|
+
required: [id, mode, status, scope]
|
|
276
295
|
additionalProperties: true
|
|
277
296
|
copied_files:
|
|
278
297
|
type: array
|
|
279
298
|
items: { type: string }
|
|
280
299
|
description: paths relative to created_path
|
|
300
|
+
repository_profile:
|
|
301
|
+
type: object
|
|
302
|
+
description: bounded classification evidence used to route greenfield or brownfield adoption
|
|
281
303
|
backup_path:
|
|
282
304
|
type: string
|
|
283
305
|
description: set only when status=overwritten
|
|
306
|
+
migration_backup_path:
|
|
307
|
+
type: string
|
|
308
|
+
description: pre-migration database backup created while resuming an older schema
|
|
284
309
|
errors:
|
|
285
310
|
- { code: ULTRA_DIR_EXISTS, description: '.ultra/ already exists and overwrite=false' }
|
|
286
311
|
- { code: TEMPLATE_MISSING, description: 'source_template path does not exist' }
|
|
287
312
|
- { code: TARGET_NOT_DIR, description: 'target_dir is not a directory' }
|
|
313
|
+
- { code: BASELINE_SCOPE_MISSING, description: 'a selected baseline scope does not exist' }
|
|
314
|
+
- { code: LEGACY_STATE_MIGRATION_REQUIRED, description: 'projection-only tasks must be imported before resume' }
|
|
315
|
+
- { code: STATE_AUTHORITY_CONFLICT, description: 'projection tasks and authoritative state cannot be reconciled automatically' }
|
|
316
|
+
- { code: STATE_PROJECTION_INVALID, description: 'the existing task projection is malformed' }
|
|
288
317
|
- { code: IO_ERROR, description: 'filesystem write failed', retriable: true }
|
|
289
318
|
cli_subcommand: task init-project
|
|
290
|
-
emits_events: [project_initialized]
|
|
319
|
+
emits_events: [project_initialized, project_resumed]
|
|
291
320
|
trace_to: 'PLAN §6 Phase 3.1'
|
|
292
321
|
|
|
293
322
|
- name: task.expand
|
|
@@ -313,6 +342,9 @@ tools:
|
|
|
313
342
|
errors:
|
|
314
343
|
- { code: TASK_NOT_FOUND, description: 'parent id missing' }
|
|
315
344
|
- { code: ALREADY_EXPANDED, description: 'task is already expanded' }
|
|
345
|
+
- { code: CHANGE_NOT_FOUND, description: 'the parent task change does not exist' }
|
|
346
|
+
- { code: CHANGE_NOT_MUTABLE, description: 'the parent task change no longer accepts children' }
|
|
347
|
+
- { code: BASELINE_NOT_READY, description: 'child creation requires a ready baseline or the parent task to belong to an already-authorized active change' }
|
|
316
348
|
cli_subcommand: task expand
|
|
317
349
|
emits_events: [task_expanded]
|
|
318
350
|
trace_to: '§7.3, D34'
|
|
@@ -329,6 +361,7 @@ tools:
|
|
|
329
361
|
prd_path: { type: string }
|
|
330
362
|
prd_text: { type: string }
|
|
331
363
|
tag: { type: string }
|
|
364
|
+
change_id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$', description: 'continuous change unit that will own every persisted parsed task' }
|
|
332
365
|
dry_run: { type: boolean, default: false, description: 'when true, do not persist to state.db — used by ultra-plan gate to preview before approve' }
|
|
333
366
|
output_schema:
|
|
334
367
|
type: object
|
|
@@ -340,6 +373,9 @@ tools:
|
|
|
340
373
|
errors:
|
|
341
374
|
- { code: NO_INPUT, description: 'one of prd_path or prd_text required' }
|
|
342
375
|
- { code: PARSE_FAILED, description: 'PRD could not be parsed into tasks' }
|
|
376
|
+
- { code: CHANGE_NOT_FOUND, description: 'assigned change does not exist' }
|
|
377
|
+
- { code: CHANGE_NOT_MUTABLE, description: 'assigned change no longer accepts tasks' }
|
|
378
|
+
- { code: BASELINE_NOT_READY, description: 'persisting parsed tasks requires a ready baseline or an already-authorized active change' }
|
|
343
379
|
cli_subcommand: task parse-prd
|
|
344
380
|
emits_events: [task_created]
|
|
345
381
|
trace_to: '§7.3, D34'
|
|
@@ -652,6 +688,15 @@ tools:
|
|
|
652
688
|
type: object
|
|
653
689
|
required: [project_name, mode]
|
|
654
690
|
additionalProperties: false
|
|
691
|
+
allOf:
|
|
692
|
+
- if:
|
|
693
|
+
required: [replace_ready]
|
|
694
|
+
properties: { replace_ready: { const: true } }
|
|
695
|
+
then: { required: [replacement_authorization] }
|
|
696
|
+
- if: { required: [replacement_authorization] }
|
|
697
|
+
then:
|
|
698
|
+
required: [replace_ready]
|
|
699
|
+
properties: { replace_ready: { const: true } }
|
|
655
700
|
properties:
|
|
656
701
|
id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$', default: project-baseline }
|
|
657
702
|
project_name: { type: string, minLength: 1 }
|
|
@@ -661,6 +706,15 @@ tools:
|
|
|
661
706
|
scope: { type: array, minItems: 1, items: { type: string, minLength: 1 }, default: ['.'] }
|
|
662
707
|
repository_revision: { type: string, minLength: 1 }
|
|
663
708
|
replace_ready: { type: boolean, default: false }
|
|
709
|
+
replacement_authorization:
|
|
710
|
+
type: object
|
|
711
|
+
required: [approved_by, reason]
|
|
712
|
+
additionalProperties: false
|
|
713
|
+
properties:
|
|
714
|
+
approved_by: { type: string, minLength: 1 }
|
|
715
|
+
reason: { type: string, minLength: 3 }
|
|
716
|
+
replace_migrated: { type: boolean, default: false, description: explicitly supersede a compatibility-only migrated baseline and start evidence-backed adoption }
|
|
717
|
+
classification: { type: object, description: bounded repository classification evidence; content is limited to 32 KiB }
|
|
664
718
|
provider_refs:
|
|
665
719
|
type: object
|
|
666
720
|
additionalProperties: false
|
|
@@ -696,6 +750,9 @@ tools:
|
|
|
696
750
|
errors:
|
|
697
751
|
- { code: BASELINE_EXISTS, description: 'a ready baseline requires explicit replacement' }
|
|
698
752
|
- { code: BASELINE_IN_PROGRESS, description: 'another adoption is already active' }
|
|
753
|
+
- { code: BASELINE_REPLACEMENT_AUTHORIZATION_REQUIRED, description: 'ready-baseline replacement lacks durable owner approval and rationale' }
|
|
754
|
+
- { code: BASELINE_REPLACEMENT_INVALID, description: 'replacement flags do not match the current baseline lifecycle or authorization payload' }
|
|
755
|
+
- { code: BASELINE_SCOPE_MISSING, description: 'a selected baseline scope does not exist' }
|
|
699
756
|
- { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
|
|
700
757
|
cli_subcommand: baseline start
|
|
701
758
|
emits_events: [baseline_started]
|
|
@@ -754,6 +811,22 @@ tools:
|
|
|
754
811
|
summary: { type: string, minLength: 1 }
|
|
755
812
|
blocking: { type: boolean }
|
|
756
813
|
owner: { type: string, minLength: 1 }
|
|
814
|
+
gaps:
|
|
815
|
+
type: array
|
|
816
|
+
items:
|
|
817
|
+
type: object
|
|
818
|
+
required: [id, category, summary]
|
|
819
|
+
additionalProperties: false
|
|
820
|
+
properties:
|
|
821
|
+
id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$' }
|
|
822
|
+
category: { type: string, enum: [baseline_blocker, documentation_drift, known_defect, technical_debt, unknown, future_change] }
|
|
823
|
+
status: { type: string, enum: [open, accepted, resolved, deferred], default: open }
|
|
824
|
+
blocking: { type: boolean, default: false }
|
|
825
|
+
summary: { type: string, minLength: 1 }
|
|
826
|
+
evidence_refs: { type: array, uniqueItems: true, items: { type: string, minLength: 1 }, default: [] }
|
|
827
|
+
owner: { type: ['string', 'null'], minLength: 1 }
|
|
828
|
+
resolution: { type: string, minLength: 1 }
|
|
829
|
+
classification: { type: object, description: bounded repository classification evidence; content is limited to 32 KiB }
|
|
757
830
|
provider_refs:
|
|
758
831
|
type: object
|
|
759
832
|
additionalProperties: false
|
|
@@ -790,6 +863,7 @@ tools:
|
|
|
790
863
|
- { code: BASELINE_NOT_FOUND, description: 'baseline id does not exist' }
|
|
791
864
|
- { code: BASELINE_NOT_MUTABLE, description: 'ready and superseded baselines are immutable' }
|
|
792
865
|
- { code: BASELINE_SPEC_MISSING, description: 'a declared specification file does not exist' }
|
|
866
|
+
- { code: BASELINE_SCOPE_MISSING, description: 'a selected baseline scope does not exist' }
|
|
793
867
|
- { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
|
|
794
868
|
cli_subcommand: baseline record
|
|
795
869
|
emits_events: [baseline_recorded]
|
|
@@ -831,6 +905,7 @@ tools:
|
|
|
831
905
|
approved_by: { type: string, minLength: 1 }
|
|
832
906
|
approval_note: { type: string, minLength: 3 }
|
|
833
907
|
accept_known_red: { type: boolean, default: false }
|
|
908
|
+
accept_dirty_worktree: { type: boolean, default: false, description: explicitly freeze the exact recorded dirty-worktree digest into the baseline }
|
|
834
909
|
output_schema:
|
|
835
910
|
type: object
|
|
836
911
|
required: [ready, status, blockers, baseline]
|
|
@@ -843,6 +918,7 @@ tools:
|
|
|
843
918
|
errors:
|
|
844
919
|
- { code: BASELINE_NOT_FOUND, description: 'baseline id does not exist' }
|
|
845
920
|
- { code: BASELINE_NOT_CONVERGEABLE, description: 'baseline lifecycle does not allow convergence' }
|
|
921
|
+
- { code: BASELINE_NOT_READY, description: 'baseline evidence, gaps, revision, branch, worktree, or verification still blocks convergence' }
|
|
846
922
|
cli_subcommand: baseline converge
|
|
847
923
|
emits_events: [baseline_blocked, baseline_converged]
|
|
848
924
|
|
|
@@ -862,6 +938,14 @@ tools:
|
|
|
862
938
|
kind: { type: string, enum: [quick, standard, major, incident] }
|
|
863
939
|
intent: { type: string, minLength: 3 }
|
|
864
940
|
base_commit: { type: string, pattern: '^[0-9a-f]{7,40}$' }
|
|
941
|
+
baseline_bypass:
|
|
942
|
+
type: object
|
|
943
|
+
required: [reason, approved_by]
|
|
944
|
+
additionalProperties: false
|
|
945
|
+
properties:
|
|
946
|
+
reason: { type: string, minLength: 3 }
|
|
947
|
+
approved_by: { type: string, minLength: 1 }
|
|
948
|
+
description: incident-only break-glass approval when the project baseline is unhealthy
|
|
865
949
|
docs_impact:
|
|
866
950
|
type: object
|
|
867
951
|
additionalProperties: false
|
|
@@ -907,6 +991,8 @@ tools:
|
|
|
907
991
|
- { code: DUPLICATE_CHANGE_ID, description: 'change id already exists' }
|
|
908
992
|
- { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
|
|
909
993
|
- { code: VALIDATION_ERROR, description: 'change input failed validation' }
|
|
994
|
+
- { code: BASELINE_NOT_READY, description: 'ordinary work is blocked until the project baseline is healthy' }
|
|
995
|
+
- { code: BASELINE_BYPASS_REQUIRED, description: 'an incident on an unhealthy baseline requires explicit break-glass approval' }
|
|
910
996
|
cli_subcommand: change create
|
|
911
997
|
emits_events: [change_created, context_updated]
|
|
912
998
|
|
|
@@ -27,10 +27,18 @@ CREATE TABLE IF NOT EXISTS baselines (
|
|
|
27
27
|
repository_root TEXT NOT NULL DEFAULT '.',
|
|
28
28
|
scope_json TEXT NOT NULL DEFAULT '["."]',
|
|
29
29
|
repository_revision TEXT,
|
|
30
|
+
repository_branch TEXT,
|
|
31
|
+
worktree_state TEXT NOT NULL DEFAULT 'unavailable'
|
|
32
|
+
CHECK (worktree_state IN ('clean', 'dirty', 'unavailable')),
|
|
33
|
+
worktree_digest TEXT,
|
|
34
|
+
worktree_files_json TEXT NOT NULL DEFAULT '[]',
|
|
35
|
+
worktree_accepted INTEGER NOT NULL DEFAULT 0 CHECK (worktree_accepted IN (0, 1)),
|
|
30
36
|
spec_refs_json TEXT NOT NULL DEFAULT '[]',
|
|
31
37
|
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
32
38
|
verification_json TEXT NOT NULL DEFAULT '[]',
|
|
33
39
|
unknowns_json TEXT NOT NULL DEFAULT '[]',
|
|
40
|
+
gaps_json TEXT NOT NULL DEFAULT '[]',
|
|
41
|
+
classification_json TEXT NOT NULL DEFAULT '{}',
|
|
34
42
|
provider_refs_json TEXT NOT NULL DEFAULT '{}',
|
|
35
43
|
approved_by TEXT,
|
|
36
44
|
approval_note TEXT,
|
|
@@ -53,6 +61,7 @@ CREATE TABLE IF NOT EXISTS changes (
|
|
|
53
61
|
intent TEXT NOT NULL,
|
|
54
62
|
docs_impact_json TEXT NOT NULL DEFAULT '{"status":"unknown","files":[],"rationale":null}',
|
|
55
63
|
provider_refs_json TEXT NOT NULL DEFAULT '{}',
|
|
64
|
+
baseline_bypass_json TEXT,
|
|
56
65
|
base_commit TEXT,
|
|
57
66
|
artifact_root TEXT NOT NULL,
|
|
58
67
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
@@ -336,3 +345,5 @@ INSERT OR IGNORE INTO schema_version (version, description)
|
|
|
336
345
|
VALUES ('10.0', 'Role-scoped context snapshots, deterministic breadcrumbs, and approval-gated specification learning');
|
|
337
346
|
INSERT OR IGNORE INTO schema_version (version, description)
|
|
338
347
|
VALUES ('11.0', 'Greenfield and brownfield baseline adoption, convergence, and drift authority');
|
|
348
|
+
INSERT OR IGNORE INTO schema_version (version, description)
|
|
349
|
+
VALUES ('12.0', 'Evidence-backed repository snapshots, gap ledger, safe re-adoption, and incident break-glass governance');
|
package/ultra-tools/cli.cjs
CHANGED
|
@@ -20,7 +20,7 @@ const path = require('node:path');
|
|
|
20
20
|
|
|
21
21
|
const VERSION = (() => {
|
|
22
22
|
try {
|
|
23
|
-
const pkg = require(
|
|
23
|
+
const pkg = require('../package.json');
|
|
24
24
|
return pkg.version;
|
|
25
25
|
} catch (_err) {
|
|
26
26
|
return '0.1.0';
|
|
@@ -35,10 +35,10 @@ USAGE:
|
|
|
35
35
|
SUBCOMMANDS:
|
|
36
36
|
task init-project
|
|
37
37
|
session close | get | list | admission | heartbeat | subscribe | reap
|
|
38
|
-
system doctor [--repair]
|
|
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
|
|
41
|
+
migrate --from=<4.4|4.5> --to=<4.5|12.0> [--dry|--rollback]
|
|
42
42
|
legacy-memory inspect | archive | prune --confirm DELETE_ULTRA_LEGACY_MEMORY
|
|
43
43
|
|
|
44
44
|
--help / -h show this message
|
|
@@ -68,7 +68,11 @@ const statusCommand = require('./commands/status.cjs');
|
|
|
68
68
|
const legacyMemoryCommand = require('./commands/legacy-memory.cjs');
|
|
69
69
|
const systemCommand = require('./commands/system.cjs');
|
|
70
70
|
|
|
71
|
-
//
|
|
71
|
+
// Session commands run only against healthy authority and may emit best-effort
|
|
72
|
+
// telemetry. Initialization, diagnosis, migration, and recovery commands must
|
|
73
|
+
// never open state.db before their own evidence-preserving checks.
|
|
74
|
+
const TELEMETRY_SUBCOMMANDS = new Set(['session']);
|
|
75
|
+
|
|
72
76
|
function emitCliTelemetry(sub, rest) {
|
|
73
77
|
try {
|
|
74
78
|
const dbPath = path.resolve('.ultra', 'state.db');
|
|
@@ -112,7 +116,7 @@ function main(argv) {
|
|
|
112
116
|
const [sub, ...rest] = args;
|
|
113
117
|
const handler = SUBCOMMANDS[sub];
|
|
114
118
|
if (!handler) fail(`unknown subcommand: ${sub}\n\n${USAGE}`);
|
|
115
|
-
emitCliTelemetry(sub, rest);
|
|
119
|
+
if (TELEMETRY_SUBCOMMANDS.has(sub)) emitCliTelemetry(sub, rest);
|
|
116
120
|
handler(rest);
|
|
117
121
|
}
|
|
118
122
|
|