ultra-builder-pro-cli 0.11.0 → 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/architecture.md +54 -223
- package/.ultra-template/specs/discovery.md +41 -228
- package/.ultra-template/specs/product.md +44 -200
- package/.ultra-template/tasks/contexts/TEMPLATE.md +36 -0
- package/.ultra-template/tasks/tasks.json +6 -0
- package/CHANGELOG.md +94 -1
- package/README.md +37 -9
- package/adapters/_shared/codex-assets.cjs +1 -1
- package/adapters/_shared/handbook.cjs +5 -4
- package/adapters/_shared/tests/handbook.test.cjs +4 -0
- package/adapters/opencode.js +8 -2
- package/adapters/tests/codex.test.cjs +10 -2
- package/adapters/tests/kimi-hook.test.cjs +1 -1
- package/adapters/tests/opencode.test.cjs +36 -1
- package/commands/ultra-init.md +3 -3
- package/docs/AGENT-CONTEXT.md +17 -8
- package/docs/ARCHITECTURE.md +51 -8
- package/docs/PLAN.zh-CN.md +9 -6
- package/docs/ROADMAP.md +5 -3
- package/docs/RUNTIME-COMPAT-MATRIX.md +8 -5
- package/docs/STATE-DB-ACCESS-POLICY.md +19 -13
- package/docs/USER-HANDBOOK-CONTRACT.md +9 -5
- package/hooks/README.md +4 -3
- package/hooks/adapters/codex.py +1 -1
- package/hooks/adapters/kimi.py +1 -1
- package/hooks/context_spine.py +153 -16
- package/hooks/health_check.py +11 -0
- package/hooks/pre_stop_check.py +6 -5
- 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 +781 -0
- package/mcp-server/lib/baseline-workflow.test.cjs +477 -0
- package/mcp-server/lib/change-workflow.cjs +256 -85
- package/mcp-server/lib/change-workflow.test.cjs +436 -6
- package/mcp-server/lib/context-spine.cjs +74 -9
- package/mcp-server/lib/context-spine.test.cjs +20 -0
- package/mcp-server/lib/doctor.cjs +28 -1
- package/mcp-server/lib/doctor.test.cjs +63 -1
- package/mcp-server/lib/init-project.cjs +334 -16
- package/mcp-server/lib/provider-refs.cjs +42 -0
- package/mcp-server/lib/spec-learning.test.cjs +5 -0
- package/mcp-server/lib/state-authority.cjs +9 -3
- package/mcp-server/lib/state-db.cjs +202 -21
- package/mcp-server/lib/state-db.test.cjs +140 -3
- 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 +62 -6
- package/mcp-server/tests/init-project.test.cjs +216 -9
- package/mcp-server/tests/migrate.test.cjs +33 -0
- package/mcp-server/tests/server-contract.test.cjs +478 -3
- package/mcp-server/tests/state-db.test.cjs +23 -2
- package/mcp-server/tests/state-ops.test.cjs +108 -0
- package/package.json +1 -1
- package/skills/ultra-change/SKILL.md +32 -13
- package/skills/ultra-deliver/SKILL.md +19 -5
- package/skills/ultra-dev/SKILL.md +8 -2
- package/skills/ultra-doctor/SKILL.md +30 -9
- package/skills/ultra-init/SKILL.md +107 -66
- package/skills/ultra-init/references/brownfield-adoption.md +93 -0
- package/skills/ultra-plan/SKILL.md +15 -5
- package/skills/ultra-research/SKILL.md +17 -5
- package/skills/ultra-status/SKILL.md +15 -6
- package/spec/cli-protocol.md +15 -1
- package/spec/mcp-tools.yaml +316 -11
- package/spec/schemas/mcp-tools.schema.json +1 -1
- package/spec/schemas/state-db.sql +44 -2
- package/ultra-tools/cli.cjs +9 -5
- package/ultra-tools/commands/migrate.cjs +62 -36
- package/ultra-tools/commands/status.cjs +29 -2
- package/ultra-tools/commands/system.cjs +340 -6
- package/ultra-tools/commands/task.cjs +11 -2
- package/ultra-tools/status-command.test.cjs +49 -0
- package/ultra-tools/system-command.test.cjs +256 -0
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.
|
|
@@ -23,6 +23,7 @@ families:
|
|
|
23
23
|
- { name: task, description: 'authoritative task lifecycle on state.db', phase: '2' }
|
|
24
24
|
- { name: session, description: 'execution-unit lifecycle with single-active-lease admission (D33)', phase: '4.5' }
|
|
25
25
|
- { name: plan, description: 'execution-plan artifact export and query (D34)', phase: '8a' }
|
|
26
|
+
- { name: baseline, description: 'project adoption, baseline evidence, convergence, and drift authority', phase: '11' }
|
|
26
27
|
- { name: change, description: 'continuous post-delivery change lifecycle and convergence', phase: '9' }
|
|
27
28
|
- { name: system, description: 'read-only diagnostics and explicit backup-first repair', phase: '9' }
|
|
28
29
|
|
|
@@ -31,7 +32,7 @@ tools:
|
|
|
31
32
|
# ─────────────────────────── task family ────────────────────────────────
|
|
32
33
|
- name: task.create
|
|
33
34
|
family: task
|
|
34
|
-
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.
|
|
35
36
|
phase: '2'
|
|
36
37
|
writer_role: mcp
|
|
37
38
|
input_schema:
|
|
@@ -47,10 +48,10 @@ tools:
|
|
|
47
48
|
estimated_days: { type: number, exclusiveMinimum: 0, description: 'estimated implementation effort in days' }
|
|
48
49
|
deps: { type: array, items: { type: string } }
|
|
49
50
|
files_modified: { type: array, items: { type: string }, description: 'Phase 8A conflict detection' }
|
|
50
|
-
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' }
|
|
51
52
|
tag: { type: string, description: 'git branch tag (Phase 7.2)' }
|
|
52
53
|
trace_to: { type: string, description: 'spec anchor (e.g. spec/mcp-tools.yaml#task.create)' }
|
|
53
|
-
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' }
|
|
54
55
|
output_schema:
|
|
55
56
|
type: object
|
|
56
57
|
required: [id, status, created_at]
|
|
@@ -62,6 +63,11 @@ tools:
|
|
|
62
63
|
errors:
|
|
63
64
|
- { code: VALIDATION_ERROR, description: 'input failed schema validation' }
|
|
64
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' }
|
|
65
71
|
- { code: LEGACY_STATE_MIGRATION_REQUIRED, description: 'non-empty v4.4 projection must be migrated before state-backed tools can run' }
|
|
66
72
|
- { code: STATE_DB_LOCKED, description: 'database is locked', retriable: true }
|
|
67
73
|
cli_subcommand: task create
|
|
@@ -105,6 +111,9 @@ tools:
|
|
|
105
111
|
- { code: TASK_NOT_FOUND, description: 'no task with given id' }
|
|
106
112
|
- { code: ILLEGAL_STATUS_TRANSITION, description: 'transition rejected by state machine' }
|
|
107
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' }
|
|
108
117
|
- { code: LEGACY_STATE_MIGRATION_REQUIRED, description: 'non-empty v4.4 projection must be migrated before state-backed tools can run' }
|
|
109
118
|
cli_subcommand: task update
|
|
110
119
|
emits_events: [task_started, task_completed, task_blocked, task_stale_marked]
|
|
@@ -217,9 +226,9 @@ tools:
|
|
|
217
226
|
- name: task.init_project
|
|
218
227
|
family: task
|
|
219
228
|
description: |
|
|
220
|
-
Bootstrap
|
|
221
|
-
|
|
222
|
-
|
|
229
|
+
Bootstrap `.ultra/` and start an authoritative greenfield or brownfield
|
|
230
|
+
baseline. Auto mode detects meaningful existing project content before
|
|
231
|
+
copying specification templates and creating state.db.
|
|
223
232
|
phase: '3'
|
|
224
233
|
writer_role: mcp
|
|
225
234
|
input_schema:
|
|
@@ -240,6 +249,22 @@ tools:
|
|
|
240
249
|
stack:
|
|
241
250
|
type: string
|
|
242
251
|
description: optional tech stack descriptor (comma-separated for fullstack)
|
|
252
|
+
mode:
|
|
253
|
+
type: string
|
|
254
|
+
enum: [auto, greenfield, brownfield]
|
|
255
|
+
default: auto
|
|
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
|
|
243
268
|
overwrite:
|
|
244
269
|
type: boolean
|
|
245
270
|
default: false
|
|
@@ -249,7 +274,7 @@ tools:
|
|
|
249
274
|
description: override path to the template root (defaults to bundled templates/.ultra/)
|
|
250
275
|
output_schema:
|
|
251
276
|
type: object
|
|
252
|
-
required: [created_path, state_db_path, status, copied_files]
|
|
277
|
+
required: [created_path, state_db_path, status, mode, baseline, copied_files, repository_profile]
|
|
253
278
|
additionalProperties: false
|
|
254
279
|
properties:
|
|
255
280
|
created_path:
|
|
@@ -260,21 +285,38 @@ tools:
|
|
|
260
285
|
description: absolute path to the initialized authoritative SQLite database
|
|
261
286
|
status:
|
|
262
287
|
type: string
|
|
263
|
-
enum: [created, overwritten]
|
|
288
|
+
enum: [created, overwritten, resumed]
|
|
289
|
+
mode:
|
|
290
|
+
type: string
|
|
291
|
+
enum: [greenfield, brownfield]
|
|
292
|
+
baseline:
|
|
293
|
+
type: object
|
|
294
|
+
required: [id, mode, status, scope]
|
|
295
|
+
additionalProperties: true
|
|
264
296
|
copied_files:
|
|
265
297
|
type: array
|
|
266
298
|
items: { type: string }
|
|
267
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
|
|
268
303
|
backup_path:
|
|
269
304
|
type: string
|
|
270
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
|
|
271
309
|
errors:
|
|
272
310
|
- { code: ULTRA_DIR_EXISTS, description: '.ultra/ already exists and overwrite=false' }
|
|
273
311
|
- { code: TEMPLATE_MISSING, description: 'source_template path does not exist' }
|
|
274
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' }
|
|
275
317
|
- { code: IO_ERROR, description: 'filesystem write failed', retriable: true }
|
|
276
318
|
cli_subcommand: task init-project
|
|
277
|
-
emits_events: [project_initialized]
|
|
319
|
+
emits_events: [project_initialized, project_resumed]
|
|
278
320
|
trace_to: 'PLAN §6 Phase 3.1'
|
|
279
321
|
|
|
280
322
|
- name: task.expand
|
|
@@ -300,6 +342,9 @@ tools:
|
|
|
300
342
|
errors:
|
|
301
343
|
- { code: TASK_NOT_FOUND, description: 'parent id missing' }
|
|
302
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' }
|
|
303
348
|
cli_subcommand: task expand
|
|
304
349
|
emits_events: [task_expanded]
|
|
305
350
|
trace_to: '§7.3, D34'
|
|
@@ -316,6 +361,7 @@ tools:
|
|
|
316
361
|
prd_path: { type: string }
|
|
317
362
|
prd_text: { type: string }
|
|
318
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' }
|
|
319
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' }
|
|
320
366
|
output_schema:
|
|
321
367
|
type: object
|
|
@@ -327,6 +373,9 @@ tools:
|
|
|
327
373
|
errors:
|
|
328
374
|
- { code: NO_INPUT, description: 'one of prd_path or prd_text required' }
|
|
329
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' }
|
|
330
379
|
cli_subcommand: task parse-prd
|
|
331
380
|
emits_events: [task_created]
|
|
332
381
|
trace_to: '§7.3, D34'
|
|
@@ -629,6 +678,250 @@ tools:
|
|
|
629
678
|
emits_events: []
|
|
630
679
|
trace_to: '§7.3, D31'
|
|
631
680
|
|
|
681
|
+
# ───────────────────────── baseline family ─────────────────────────────
|
|
682
|
+
- name: baseline.start
|
|
683
|
+
family: baseline
|
|
684
|
+
description: Start a greenfield baseline or brownfield adoption without overwriting a ready baseline implicitly.
|
|
685
|
+
phase: '11'
|
|
686
|
+
writer_role: mcp
|
|
687
|
+
input_schema:
|
|
688
|
+
type: object
|
|
689
|
+
required: [project_name, mode]
|
|
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 } }
|
|
700
|
+
properties:
|
|
701
|
+
id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$', default: project-baseline }
|
|
702
|
+
project_name: { type: string, minLength: 1 }
|
|
703
|
+
project_type: { type: string, enum: [web, api, cli, fullstack, other] }
|
|
704
|
+
stack: { type: string }
|
|
705
|
+
mode: { type: string, enum: [greenfield, brownfield] }
|
|
706
|
+
scope: { type: array, minItems: 1, items: { type: string, minLength: 1 }, default: ['.'] }
|
|
707
|
+
repository_revision: { type: string, minLength: 1 }
|
|
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 }
|
|
718
|
+
provider_refs:
|
|
719
|
+
type: object
|
|
720
|
+
additionalProperties: false
|
|
721
|
+
properties:
|
|
722
|
+
memory:
|
|
723
|
+
type: object
|
|
724
|
+
required: [provider]
|
|
725
|
+
additionalProperties: false
|
|
726
|
+
properties:
|
|
727
|
+
provider: { type: string }
|
|
728
|
+
project: { type: string }
|
|
729
|
+
reference: { type: string }
|
|
730
|
+
revision: { type: string }
|
|
731
|
+
indexed_head: { type: string }
|
|
732
|
+
status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
|
|
733
|
+
code_graph:
|
|
734
|
+
type: object
|
|
735
|
+
required: [provider]
|
|
736
|
+
additionalProperties: false
|
|
737
|
+
properties:
|
|
738
|
+
provider: { type: string }
|
|
739
|
+
project: { type: string }
|
|
740
|
+
reference: { type: string }
|
|
741
|
+
revision: { type: string }
|
|
742
|
+
indexed_head: { type: string }
|
|
743
|
+
status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
|
|
744
|
+
output_schema:
|
|
745
|
+
type: object
|
|
746
|
+
required: [baseline]
|
|
747
|
+
additionalProperties: false
|
|
748
|
+
properties:
|
|
749
|
+
baseline: { type: object }
|
|
750
|
+
errors:
|
|
751
|
+
- { code: BASELINE_EXISTS, description: 'a ready baseline requires explicit replacement' }
|
|
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' }
|
|
756
|
+
- { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
|
|
757
|
+
cli_subcommand: baseline start
|
|
758
|
+
emits_events: [baseline_started]
|
|
759
|
+
|
|
760
|
+
- name: baseline.record
|
|
761
|
+
family: baseline
|
|
762
|
+
description: Replace the current adoption snapshot with bounded specification digests, evidence references, verification, unknowns, and provider metadata.
|
|
763
|
+
phase: '11'
|
|
764
|
+
writer_role: mcp
|
|
765
|
+
input_schema:
|
|
766
|
+
type: object
|
|
767
|
+
required: [id]
|
|
768
|
+
additionalProperties: false
|
|
769
|
+
properties:
|
|
770
|
+
id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$' }
|
|
771
|
+
repository_revision: { type: string, minLength: 1 }
|
|
772
|
+
scope: { type: array, minItems: 1, items: { type: string, minLength: 1 } }
|
|
773
|
+
spec_refs:
|
|
774
|
+
type: array
|
|
775
|
+
items:
|
|
776
|
+
type: object
|
|
777
|
+
required: [kind, path]
|
|
778
|
+
additionalProperties: false
|
|
779
|
+
properties:
|
|
780
|
+
kind: { type: string, enum: [discovery, product, architecture, quality, delivery, other] }
|
|
781
|
+
path: { type: string, minLength: 1 }
|
|
782
|
+
evidence:
|
|
783
|
+
type: array
|
|
784
|
+
items:
|
|
785
|
+
type: object
|
|
786
|
+
required: [kind, ref, summary]
|
|
787
|
+
additionalProperties: false
|
|
788
|
+
properties:
|
|
789
|
+
kind: { type: string, enum: [source, docs, runtime, test, deploy, external] }
|
|
790
|
+
ref: { type: string, minLength: 1 }
|
|
791
|
+
summary: { type: string, minLength: 1 }
|
|
792
|
+
verification:
|
|
793
|
+
type: array
|
|
794
|
+
items:
|
|
795
|
+
type: object
|
|
796
|
+
required: [name, command, status, evidence]
|
|
797
|
+
additionalProperties: false
|
|
798
|
+
properties:
|
|
799
|
+
name: { type: string, minLength: 1 }
|
|
800
|
+
command: { type: string, minLength: 1 }
|
|
801
|
+
status: { type: string, enum: [pass, known_red, not_run] }
|
|
802
|
+
evidence: { type: string, minLength: 1 }
|
|
803
|
+
rationale: { type: string, minLength: 1 }
|
|
804
|
+
unknowns:
|
|
805
|
+
type: array
|
|
806
|
+
items:
|
|
807
|
+
type: object
|
|
808
|
+
required: [summary, blocking]
|
|
809
|
+
additionalProperties: false
|
|
810
|
+
properties:
|
|
811
|
+
summary: { type: string, minLength: 1 }
|
|
812
|
+
blocking: { type: boolean }
|
|
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 }
|
|
830
|
+
provider_refs:
|
|
831
|
+
type: object
|
|
832
|
+
additionalProperties: false
|
|
833
|
+
properties:
|
|
834
|
+
memory:
|
|
835
|
+
type: object
|
|
836
|
+
required: [provider]
|
|
837
|
+
additionalProperties: false
|
|
838
|
+
properties:
|
|
839
|
+
provider: { type: string }
|
|
840
|
+
project: { type: string }
|
|
841
|
+
reference: { type: string }
|
|
842
|
+
revision: { type: string }
|
|
843
|
+
indexed_head: { type: string }
|
|
844
|
+
status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
|
|
845
|
+
code_graph:
|
|
846
|
+
type: object
|
|
847
|
+
required: [provider]
|
|
848
|
+
additionalProperties: false
|
|
849
|
+
properties:
|
|
850
|
+
provider: { type: string }
|
|
851
|
+
project: { type: string }
|
|
852
|
+
reference: { type: string }
|
|
853
|
+
revision: { type: string }
|
|
854
|
+
indexed_head: { type: string }
|
|
855
|
+
status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
|
|
856
|
+
output_schema:
|
|
857
|
+
type: object
|
|
858
|
+
required: [baseline]
|
|
859
|
+
additionalProperties: false
|
|
860
|
+
properties:
|
|
861
|
+
baseline: { type: object }
|
|
862
|
+
errors:
|
|
863
|
+
- { code: BASELINE_NOT_FOUND, description: 'baseline id does not exist' }
|
|
864
|
+
- { code: BASELINE_NOT_MUTABLE, description: 'ready and superseded baselines are immutable' }
|
|
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' }
|
|
867
|
+
- { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
|
|
868
|
+
cli_subcommand: baseline record
|
|
869
|
+
emits_events: [baseline_recorded]
|
|
870
|
+
|
|
871
|
+
- name: baseline.get
|
|
872
|
+
family: baseline
|
|
873
|
+
description: Read the current or named authoritative baseline with live digest and repository-revision health.
|
|
874
|
+
phase: '11'
|
|
875
|
+
readonly: true
|
|
876
|
+
input_schema:
|
|
877
|
+
type: object
|
|
878
|
+
additionalProperties: false
|
|
879
|
+
properties:
|
|
880
|
+
id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$' }
|
|
881
|
+
output_schema:
|
|
882
|
+
type: object
|
|
883
|
+
required: [baseline, health]
|
|
884
|
+
additionalProperties: false
|
|
885
|
+
properties:
|
|
886
|
+
baseline: { type: object }
|
|
887
|
+
health: { type: object }
|
|
888
|
+
errors:
|
|
889
|
+
- { code: BASELINE_NOT_FOUND, description: 'no matching baseline exists' }
|
|
890
|
+
cli_subcommand: baseline get
|
|
891
|
+
emits_events: []
|
|
892
|
+
|
|
893
|
+
- name: baseline.converge
|
|
894
|
+
family: baseline
|
|
895
|
+
description: Approve a baseline only when its revision, specification digests, evidence, verification, and blocking unknowns satisfy deterministic gates.
|
|
896
|
+
phase: '11'
|
|
897
|
+
writer_role: mcp
|
|
898
|
+
input_schema:
|
|
899
|
+
type: object
|
|
900
|
+
required: [id, expected_revision, approved_by, approval_note]
|
|
901
|
+
additionalProperties: false
|
|
902
|
+
properties:
|
|
903
|
+
id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$' }
|
|
904
|
+
expected_revision: { type: string, minLength: 1 }
|
|
905
|
+
approved_by: { type: string, minLength: 1 }
|
|
906
|
+
approval_note: { type: string, minLength: 3 }
|
|
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 }
|
|
909
|
+
output_schema:
|
|
910
|
+
type: object
|
|
911
|
+
required: [ready, status, blockers, baseline]
|
|
912
|
+
additionalProperties: false
|
|
913
|
+
properties:
|
|
914
|
+
ready: { type: boolean }
|
|
915
|
+
status: { type: string, enum: [blocked, ready] }
|
|
916
|
+
blockers: { type: array, items: { type: string } }
|
|
917
|
+
baseline: { type: object }
|
|
918
|
+
errors:
|
|
919
|
+
- { code: BASELINE_NOT_FOUND, description: 'baseline id does not exist' }
|
|
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' }
|
|
922
|
+
cli_subcommand: baseline converge
|
|
923
|
+
emits_events: [baseline_blocked, baseline_converged]
|
|
924
|
+
|
|
632
925
|
# ────────────────────────── change family ──────────────────────────────
|
|
633
926
|
- name: change.create
|
|
634
927
|
family: change
|
|
@@ -645,6 +938,14 @@ tools:
|
|
|
645
938
|
kind: { type: string, enum: [quick, standard, major, incident] }
|
|
646
939
|
intent: { type: string, minLength: 3 }
|
|
647
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
|
|
648
949
|
docs_impact:
|
|
649
950
|
type: object
|
|
650
951
|
additionalProperties: false
|
|
@@ -690,6 +991,8 @@ tools:
|
|
|
690
991
|
- { code: DUPLICATE_CHANGE_ID, description: 'change id already exists' }
|
|
691
992
|
- { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
|
|
692
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' }
|
|
693
996
|
cli_subcommand: change create
|
|
694
997
|
emits_events: [change_created, context_updated]
|
|
695
998
|
|
|
@@ -1048,6 +1351,8 @@ tools:
|
|
|
1048
1351
|
errors:
|
|
1049
1352
|
- { code: CHANGE_NOT_READY, description: 'change has not passed convergence' }
|
|
1050
1353
|
- { code: BASELINE_RECONCILIATION_REQUIRED, description: 'baseline update or explicit no-change reason required' }
|
|
1354
|
+
- { code: BASELINE_FILE_MISSING, description: 'a declared baseline update does not exist' }
|
|
1355
|
+
- { code: BASELINE_RECONCILIATION_INCOMPLETE, description: 'repository revision or tracked specification digests remain stale after reconciliation' }
|
|
1051
1356
|
- { code: ARCHIVE_EXISTS, description: 'archive target already exists' }
|
|
1052
1357
|
cli_subcommand: change archive
|
|
1053
1358
|
emits_events: [change_archived]
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
},
|
|
61
61
|
"family": {
|
|
62
62
|
"type": "string",
|
|
63
|
-
"enum": ["task", "memory", "review", "impact", "skill", "session", "ask", "plan", "change", "system"]
|
|
63
|
+
"enum": ["task", "memory", "review", "impact", "skill", "session", "ask", "plan", "baseline", "change", "system"]
|
|
64
64
|
},
|
|
65
65
|
"description": { "type": "string", "minLength": 10 },
|
|
66
66
|
"phase": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
-- Ultra Builder Pro — authoritative state schema
|
|
2
2
|
-- Phase 2 builds .ultra/state.db from this file. Source of truth for all
|
|
3
|
-
-- task / session / event / telemetry data. tasks.json and context md status
|
|
3
|
+
-- baseline / change / task / session / event / telemetry data. tasks.json and context md status
|
|
4
4
|
-- header are projections (PLAN §7.1, D18, D32).
|
|
5
5
|
--
|
|
6
|
-
-- Trace: docs/PLAN.zh-CN.md §7.1; decisions D18/D30/D31/D32/D37.
|
|
6
|
+
-- Trace: docs/PLAN.zh-CN.md §7.1; decisions D18/D30/D31/D32/D37/D52/D54.
|
|
7
7
|
--
|
|
8
8
|
-- PRAGMAs are applied by mcp-server/lib/state-db.ts on connection open;
|
|
9
9
|
-- they cannot be persisted in CREATE statements but are documented here.
|
|
@@ -12,6 +12,43 @@
|
|
|
12
12
|
-- PRAGMA busy_timeout=5000; -- block up to 5s on lock (R25)
|
|
13
13
|
-- PRAGMA foreign_keys=ON; -- enforce FK constraints
|
|
14
14
|
|
|
15
|
+
-- ──────────────────────────── project baseline ─────────────────────────────
|
|
16
|
+
-- The baseline is the approved, repository-scoped snapshot that every change
|
|
17
|
+
-- is measured against. It stores digests and evidence references, never source,
|
|
18
|
+
-- prompt, transcript, memory, or code-graph payloads.
|
|
19
|
+
CREATE TABLE IF NOT EXISTS baselines (
|
|
20
|
+
id TEXT PRIMARY KEY,
|
|
21
|
+
project_name TEXT NOT NULL,
|
|
22
|
+
project_type TEXT,
|
|
23
|
+
stack TEXT,
|
|
24
|
+
mode TEXT NOT NULL CHECK (mode IN ('greenfield', 'brownfield', 'migrated')),
|
|
25
|
+
status TEXT NOT NULL DEFAULT 'draft'
|
|
26
|
+
CHECK (status IN ('draft', 'adopting', 'blocked', 'ready', 'superseded')),
|
|
27
|
+
repository_root TEXT NOT NULL DEFAULT '.',
|
|
28
|
+
scope_json TEXT NOT NULL DEFAULT '["."]',
|
|
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)),
|
|
36
|
+
spec_refs_json TEXT NOT NULL DEFAULT '[]',
|
|
37
|
+
evidence_json TEXT NOT NULL DEFAULT '[]',
|
|
38
|
+
verification_json TEXT NOT NULL DEFAULT '[]',
|
|
39
|
+
unknowns_json TEXT NOT NULL DEFAULT '[]',
|
|
40
|
+
gaps_json TEXT NOT NULL DEFAULT '[]',
|
|
41
|
+
classification_json TEXT NOT NULL DEFAULT '{}',
|
|
42
|
+
provider_refs_json TEXT NOT NULL DEFAULT '{}',
|
|
43
|
+
approved_by TEXT,
|
|
44
|
+
approval_note TEXT,
|
|
45
|
+
started_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
46
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
47
|
+
converged_at TEXT
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
CREATE INDEX IF NOT EXISTS baselines_status ON baselines(status, updated_at);
|
|
51
|
+
|
|
15
52
|
-- ──────────────────────────── changes ─────────────────────────────────────
|
|
16
53
|
-- A project baseline is continuous; each feature, fix, incident, or redesign
|
|
17
54
|
-- is an independently converged change unit. Only changes become terminal.
|
|
@@ -24,6 +61,7 @@ CREATE TABLE IF NOT EXISTS changes (
|
|
|
24
61
|
intent TEXT NOT NULL,
|
|
25
62
|
docs_impact_json TEXT NOT NULL DEFAULT '{"status":"unknown","files":[],"rationale":null}',
|
|
26
63
|
provider_refs_json TEXT NOT NULL DEFAULT '{}',
|
|
64
|
+
baseline_bypass_json TEXT,
|
|
27
65
|
base_commit TEXT,
|
|
28
66
|
artifact_root TEXT NOT NULL,
|
|
29
67
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
@@ -305,3 +343,7 @@ INSERT OR IGNORE INTO schema_version (version, description)
|
|
|
305
343
|
VALUES ('9.1', 'Kimi runtime support in durable events and sessions');
|
|
306
344
|
INSERT OR IGNORE INTO schema_version (version, description)
|
|
307
345
|
VALUES ('10.0', 'Role-scoped context snapshots, deterministic breadcrumbs, and approval-gated specification learning');
|
|
346
|
+
INSERT OR IGNORE INTO schema_version (version, description)
|
|
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
|
|