ultra-builder-pro-cli 0.10.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/.ultra-template/specs/architecture.md +54 -223
  2. package/.ultra-template/specs/discovery.md +34 -231
  3. package/.ultra-template/specs/product.md +44 -200
  4. package/.ultra-template/tasks/contexts/TEMPLATE.md +36 -0
  5. package/.ultra-template/tasks/tasks.json +6 -0
  6. package/CHANGELOG.md +86 -1
  7. package/README.md +21 -9
  8. package/adapters/_shared/codex-assets.cjs +24 -342
  9. package/adapters/_shared/handbook.cjs +4 -3
  10. package/adapters/_shared/runtime-assets.cjs +24 -0
  11. package/adapters/_shared/tests/handbook.test.cjs +4 -0
  12. package/adapters/_shared/tests/runtime-assets.test.cjs +11 -4
  13. package/adapters/claude.js +28 -5
  14. package/adapters/kimi.js +15 -138
  15. package/adapters/opencode.js +22 -49
  16. package/adapters/tests/claude.test.cjs +22 -8
  17. package/adapters/tests/codex.test.cjs +21 -8
  18. package/adapters/tests/kimi-hook.test.cjs +1 -1
  19. package/adapters/tests/kimi.test.cjs +11 -11
  20. package/adapters/tests/opencode.test.cjs +47 -8
  21. package/agents/code-reviewer.md +24 -85
  22. package/agents/debugger.md +30 -132
  23. package/agents/review-code.md +24 -104
  24. package/agents/review-comments.md +20 -83
  25. package/agents/review-coordinator.md +40 -137
  26. package/agents/review-design.md +21 -118
  27. package/agents/review-errors.md +22 -70
  28. package/agents/review-spec.md +36 -0
  29. package/agents/review-tests.md +20 -76
  30. package/agents/tdd-runner.md +26 -84
  31. package/commands/learn.md +5 -36
  32. package/commands/ultra-change.md +5 -43
  33. package/commands/ultra-deliver.md +4 -46
  34. package/commands/ultra-dev.md +4 -48
  35. package/commands/ultra-doctor.md +4 -30
  36. package/commands/ultra-init.md +5 -47
  37. package/commands/ultra-plan.md +5 -48
  38. package/commands/ultra-research.md +5 -54
  39. package/commands/ultra-status.md +5 -44
  40. package/commands/ultra-test.md +5 -45
  41. package/commands/ultra-think.md +5 -40
  42. package/docs/AGENT-CONTEXT.md +16 -8
  43. package/docs/ARCHITECTURE.md +32 -5
  44. package/docs/PLAN.zh-CN.md +8 -6
  45. package/docs/ROADMAP.md +5 -3
  46. package/docs/RUNTIME-COMPAT-MATRIX.md +8 -5
  47. package/docs/SKILL-AUTHORING.md +75 -0
  48. package/docs/STATE-DB-ACCESS-POLICY.md +17 -11
  49. package/docs/USER-HANDBOOK-CONTRACT.md +8 -5
  50. package/hooks/README.md +4 -3
  51. package/hooks/adapters/codex.py +1 -1
  52. package/hooks/adapters/kimi.py +1 -1
  53. package/hooks/context_spine.py +120 -16
  54. package/hooks/health_check.py +11 -0
  55. package/hooks/pre_stop_check.py +6 -5
  56. package/mcp-server/lib/baseline-workflow.cjs +415 -0
  57. package/mcp-server/lib/baseline-workflow.test.cjs +225 -0
  58. package/mcp-server/lib/change-workflow.cjs +24 -27
  59. package/mcp-server/lib/change-workflow.test.cjs +202 -6
  60. package/mcp-server/lib/context-spine.cjs +74 -9
  61. package/mcp-server/lib/context-spine.test.cjs +15 -0
  62. package/mcp-server/lib/doctor.cjs +14 -0
  63. package/mcp-server/lib/doctor.test.cjs +25 -1
  64. package/mcp-server/lib/init-project.cjs +49 -14
  65. package/mcp-server/lib/provider-refs.cjs +42 -0
  66. package/mcp-server/lib/spec-learning.test.cjs +5 -0
  67. package/mcp-server/lib/state-db.cjs +63 -4
  68. package/mcp-server/lib/state-db.test.cjs +8 -3
  69. package/mcp-server/server.cjs +48 -3
  70. package/mcp-server/tests/init-project.test.cjs +54 -8
  71. package/mcp-server/tests/server-contract.test.cjs +99 -2
  72. package/mcp-server/tests/state-db.test.cjs +11 -2
  73. package/package.json +3 -2
  74. package/skills/cc-collab/SKILL.md +16 -18
  75. package/skills/code-review-expert/SKILL.md +39 -114
  76. package/skills/code-review-expert/references/correctness-reliability.md +30 -0
  77. package/skills/code-review-expert/references/design-boundaries.md +26 -0
  78. package/skills/code-review-expert/references/removal-plan.md +17 -45
  79. package/skills/codex-collab/SKILL.md +23 -28
  80. package/skills/codex-collab/evals/evals.json +18 -23
  81. package/skills/integration-rules/SKILL.md +28 -67
  82. package/skills/learn/SKILL.md +46 -106
  83. package/skills/security-rules/SKILL.md +34 -56
  84. package/skills/testing-rules/SKILL.md +28 -52
  85. package/skills/ultra-change/SKILL.md +68 -114
  86. package/skills/ultra-deliver/SKILL.md +58 -86
  87. package/skills/ultra-dev/SKILL.md +46 -105
  88. package/skills/ultra-doctor/SKILL.md +45 -72
  89. package/skills/ultra-init/SKILL.md +62 -147
  90. package/skills/ultra-init/references/brownfield-adoption.md +65 -0
  91. package/skills/ultra-plan/SKILL.md +56 -89
  92. package/skills/ultra-research/SKILL.md +64 -152
  93. package/skills/ultra-research/references/architecture.md +38 -0
  94. package/skills/ultra-research/references/problem-product.md +39 -0
  95. package/skills/ultra-research/references/quality-delivery.md +34 -0
  96. package/skills/ultra-research/references/synthesis.md +38 -0
  97. package/skills/ultra-research/references/users-scope.md +40 -0
  98. package/skills/ultra-review/SKILL.md +54 -98
  99. package/skills/ultra-review/references/unified-schema.md +76 -101
  100. package/skills/ultra-review/scripts/review_wait.py +242 -77
  101. package/skills/ultra-status/SKILL.md +41 -56
  102. package/skills/ultra-test/SKILL.md +37 -72
  103. package/skills/ultra-think/SKILL.md +43 -102
  104. package/skills/ultra-verify/SKILL.md +44 -84
  105. package/skills/ultra-verify/evals/evals.json +24 -27
  106. package/spec/cli-protocol.md +4 -0
  107. package/spec/mcp-tools.yaml +223 -4
  108. package/spec/schemas/command-manifest.schema.json +7 -25
  109. package/spec/schemas/mcp-tools.schema.json +1 -1
  110. package/spec/schemas/skill-manifest.schema.json +9 -79
  111. package/spec/schemas/state-db.sql +33 -2
  112. package/ultra-tools/commands/status.cjs +20 -2
  113. package/ultra-tools/commands/task.cjs +4 -1
  114. package/ultra-tools/status-command.test.cjs +20 -0
  115. package/ultra-tools/system-command.test.cjs +5 -0
  116. package/skills/code-review-expert/references/code-quality-checklist.md +0 -112
  117. package/skills/code-review-expert/references/integration-checklist.md +0 -46
  118. package/skills/code-review-expert/references/security-checklist.md +0 -100
  119. package/skills/code-review-expert/references/solid-checklist.md +0 -65
  120. package/skills/ultra-research/steps/step-00-problem-validation.md +0 -154
  121. package/skills/ultra-research/steps/step-01-opportunity-discovery.md +0 -172
  122. package/skills/ultra-research/steps/step-02-market-assessment.md +0 -195
  123. package/skills/ultra-research/steps/step-03-competitive-landscape.md +0 -197
  124. package/skills/ultra-research/steps/step-04-product-strategy.md +0 -196
  125. package/skills/ultra-research/steps/step-05-assumptions-validation.md +0 -234
  126. package/skills/ultra-research/steps/step-10-user-personas.md +0 -169
  127. package/skills/ultra-research/steps/step-11-user-scenarios.md +0 -181
  128. package/skills/ultra-research/steps/step-20-user-stories.md +0 -156
  129. package/skills/ultra-research/steps/step-21-features-scope.md +0 -157
  130. package/skills/ultra-research/steps/step-22-success-metrics.md +0 -195
  131. package/skills/ultra-research/steps/step-30-architecture-context.md +0 -154
  132. package/skills/ultra-research/steps/step-31-solution-strategy.md +0 -172
  133. package/skills/ultra-research/steps/step-32-building-blocks.md +0 -188
  134. package/skills/ultra-research/steps/step-40-deployment.md +0 -123
  135. package/skills/ultra-research/steps/step-41-quality-risks.md +0 -135
  136. package/skills/ultra-research/steps/step-99-synthesis.md +0 -188
  137. package/skills/ultra-review/scripts/review_verdict_update.py +0 -99
@@ -100,6 +100,10 @@ as a fallback unless `ultra-tools <family> --help` lists it.
100
100
  | `session.admission_check` | `session admission` | 4.5 | any |
101
101
  | `session.heartbeat` | `session heartbeat` | 4.5 | mcp |
102
102
  | `session.subscribe_events`| `session subscribe` | 4.5 | any |
103
+ | `baseline.start` | `baseline start` | 11 | mcp |
104
+ | `baseline.record` | `baseline record` | 11 | mcp |
105
+ | `baseline.get` | `baseline get` | 11 | any |
106
+ | `baseline.converge` | `baseline converge` | 11 | mcp |
103
107
  | `change.create` | `change create` | 9 | mcp |
104
108
  | `change.update` | `change update` | 9 | mcp |
105
109
  | `change.get` | `change get` | 9 | any |
@@ -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
 
@@ -217,9 +218,9 @@ tools:
217
218
  - name: task.init_project
218
219
  family: task
219
220
  description: |
220
- Bootstrap a fresh `.ultra/` skeleton in target_dir from the bundled
221
- templates/.ultra/ source. Copies spec templates, tasks.json, context
222
- template, and report stubs. Phase 3.1 entry point for /ultra-init.
221
+ Bootstrap `.ultra/` and start an authoritative greenfield or brownfield
222
+ baseline. Auto mode detects meaningful existing project content before
223
+ copying specification templates and creating state.db.
223
224
  phase: '3'
224
225
  writer_role: mcp
225
226
  input_schema:
@@ -240,6 +241,11 @@ tools:
240
241
  stack:
241
242
  type: string
242
243
  description: optional tech stack descriptor (comma-separated for fullstack)
244
+ mode:
245
+ type: string
246
+ enum: [auto, greenfield, brownfield]
247
+ default: auto
248
+ description: auto detects whether meaningful project content already exists
243
249
  overwrite:
244
250
  type: boolean
245
251
  default: false
@@ -249,7 +255,7 @@ tools:
249
255
  description: override path to the template root (defaults to bundled templates/.ultra/)
250
256
  output_schema:
251
257
  type: object
252
- required: [created_path, state_db_path, status, copied_files]
258
+ required: [created_path, state_db_path, status, mode, baseline, copied_files]
253
259
  additionalProperties: false
254
260
  properties:
255
261
  created_path:
@@ -261,6 +267,13 @@ tools:
261
267
  status:
262
268
  type: string
263
269
  enum: [created, overwritten]
270
+ mode:
271
+ type: string
272
+ enum: [greenfield, brownfield]
273
+ baseline:
274
+ type: object
275
+ required: [id, mode, status]
276
+ additionalProperties: true
264
277
  copied_files:
265
278
  type: array
266
279
  items: { type: string }
@@ -629,6 +642,210 @@ tools:
629
642
  emits_events: []
630
643
  trace_to: '§7.3, D31'
631
644
 
645
+ # ───────────────────────── baseline family ─────────────────────────────
646
+ - name: baseline.start
647
+ family: baseline
648
+ description: Start a greenfield baseline or brownfield adoption without overwriting a ready baseline implicitly.
649
+ phase: '11'
650
+ writer_role: mcp
651
+ input_schema:
652
+ type: object
653
+ required: [project_name, mode]
654
+ additionalProperties: false
655
+ properties:
656
+ id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$', default: project-baseline }
657
+ project_name: { type: string, minLength: 1 }
658
+ project_type: { type: string, enum: [web, api, cli, fullstack, other] }
659
+ stack: { type: string }
660
+ mode: { type: string, enum: [greenfield, brownfield] }
661
+ scope: { type: array, minItems: 1, items: { type: string, minLength: 1 }, default: ['.'] }
662
+ repository_revision: { type: string, minLength: 1 }
663
+ replace_ready: { type: boolean, default: false }
664
+ provider_refs:
665
+ type: object
666
+ additionalProperties: false
667
+ properties:
668
+ memory:
669
+ type: object
670
+ required: [provider]
671
+ additionalProperties: false
672
+ properties:
673
+ provider: { type: string }
674
+ project: { type: string }
675
+ reference: { type: string }
676
+ revision: { type: string }
677
+ indexed_head: { type: string }
678
+ status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
679
+ code_graph:
680
+ type: object
681
+ required: [provider]
682
+ additionalProperties: false
683
+ properties:
684
+ provider: { type: string }
685
+ project: { type: string }
686
+ reference: { type: string }
687
+ revision: { type: string }
688
+ indexed_head: { type: string }
689
+ status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
690
+ output_schema:
691
+ type: object
692
+ required: [baseline]
693
+ additionalProperties: false
694
+ properties:
695
+ baseline: { type: object }
696
+ errors:
697
+ - { code: BASELINE_EXISTS, description: 'a ready baseline requires explicit replacement' }
698
+ - { code: BASELINE_IN_PROGRESS, description: 'another adoption is already active' }
699
+ - { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
700
+ cli_subcommand: baseline start
701
+ emits_events: [baseline_started]
702
+
703
+ - name: baseline.record
704
+ family: baseline
705
+ description: Replace the current adoption snapshot with bounded specification digests, evidence references, verification, unknowns, and provider metadata.
706
+ phase: '11'
707
+ writer_role: mcp
708
+ input_schema:
709
+ type: object
710
+ required: [id]
711
+ additionalProperties: false
712
+ properties:
713
+ id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$' }
714
+ repository_revision: { type: string, minLength: 1 }
715
+ scope: { type: array, minItems: 1, items: { type: string, minLength: 1 } }
716
+ spec_refs:
717
+ type: array
718
+ items:
719
+ type: object
720
+ required: [kind, path]
721
+ additionalProperties: false
722
+ properties:
723
+ kind: { type: string, enum: [discovery, product, architecture, quality, delivery, other] }
724
+ path: { type: string, minLength: 1 }
725
+ evidence:
726
+ type: array
727
+ items:
728
+ type: object
729
+ required: [kind, ref, summary]
730
+ additionalProperties: false
731
+ properties:
732
+ kind: { type: string, enum: [source, docs, runtime, test, deploy, external] }
733
+ ref: { type: string, minLength: 1 }
734
+ summary: { type: string, minLength: 1 }
735
+ verification:
736
+ type: array
737
+ items:
738
+ type: object
739
+ required: [name, command, status, evidence]
740
+ additionalProperties: false
741
+ properties:
742
+ name: { type: string, minLength: 1 }
743
+ command: { type: string, minLength: 1 }
744
+ status: { type: string, enum: [pass, known_red, not_run] }
745
+ evidence: { type: string, minLength: 1 }
746
+ rationale: { type: string, minLength: 1 }
747
+ unknowns:
748
+ type: array
749
+ items:
750
+ type: object
751
+ required: [summary, blocking]
752
+ additionalProperties: false
753
+ properties:
754
+ summary: { type: string, minLength: 1 }
755
+ blocking: { type: boolean }
756
+ owner: { type: string, minLength: 1 }
757
+ provider_refs:
758
+ type: object
759
+ additionalProperties: false
760
+ properties:
761
+ memory:
762
+ type: object
763
+ required: [provider]
764
+ additionalProperties: false
765
+ properties:
766
+ provider: { type: string }
767
+ project: { type: string }
768
+ reference: { type: string }
769
+ revision: { type: string }
770
+ indexed_head: { type: string }
771
+ status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
772
+ code_graph:
773
+ type: object
774
+ required: [provider]
775
+ additionalProperties: false
776
+ properties:
777
+ provider: { type: string }
778
+ project: { type: string }
779
+ reference: { type: string }
780
+ revision: { type: string }
781
+ indexed_head: { type: string }
782
+ status: { type: string, enum: [available, unavailable, fresh, stale, unknown] }
783
+ output_schema:
784
+ type: object
785
+ required: [baseline]
786
+ additionalProperties: false
787
+ properties:
788
+ baseline: { type: object }
789
+ errors:
790
+ - { code: BASELINE_NOT_FOUND, description: 'baseline id does not exist' }
791
+ - { code: BASELINE_NOT_MUTABLE, description: 'ready and superseded baselines are immutable' }
792
+ - { code: BASELINE_SPEC_MISSING, description: 'a declared specification file does not exist' }
793
+ - { code: PROVIDER_CONTENT_FORBIDDEN, description: 'provider payload content must remain external' }
794
+ cli_subcommand: baseline record
795
+ emits_events: [baseline_recorded]
796
+
797
+ - name: baseline.get
798
+ family: baseline
799
+ description: Read the current or named authoritative baseline with live digest and repository-revision health.
800
+ phase: '11'
801
+ readonly: true
802
+ input_schema:
803
+ type: object
804
+ additionalProperties: false
805
+ properties:
806
+ id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$' }
807
+ output_schema:
808
+ type: object
809
+ required: [baseline, health]
810
+ additionalProperties: false
811
+ properties:
812
+ baseline: { type: object }
813
+ health: { type: object }
814
+ errors:
815
+ - { code: BASELINE_NOT_FOUND, description: 'no matching baseline exists' }
816
+ cli_subcommand: baseline get
817
+ emits_events: []
818
+
819
+ - name: baseline.converge
820
+ family: baseline
821
+ description: Approve a baseline only when its revision, specification digests, evidence, verification, and blocking unknowns satisfy deterministic gates.
822
+ phase: '11'
823
+ writer_role: mcp
824
+ input_schema:
825
+ type: object
826
+ required: [id, expected_revision, approved_by, approval_note]
827
+ additionalProperties: false
828
+ properties:
829
+ id: { type: string, pattern: '^[a-zA-Z0-9_\-]+$' }
830
+ expected_revision: { type: string, minLength: 1 }
831
+ approved_by: { type: string, minLength: 1 }
832
+ approval_note: { type: string, minLength: 3 }
833
+ accept_known_red: { type: boolean, default: false }
834
+ output_schema:
835
+ type: object
836
+ required: [ready, status, blockers, baseline]
837
+ additionalProperties: false
838
+ properties:
839
+ ready: { type: boolean }
840
+ status: { type: string, enum: [blocked, ready] }
841
+ blockers: { type: array, items: { type: string } }
842
+ baseline: { type: object }
843
+ errors:
844
+ - { code: BASELINE_NOT_FOUND, description: 'baseline id does not exist' }
845
+ - { code: BASELINE_NOT_CONVERGEABLE, description: 'baseline lifecycle does not allow convergence' }
846
+ cli_subcommand: baseline converge
847
+ emits_events: [baseline_blocked, baseline_converged]
848
+
632
849
  # ────────────────────────── change family ──────────────────────────────
633
850
  - name: change.create
634
851
  family: change
@@ -1048,6 +1265,8 @@ tools:
1048
1265
  errors:
1049
1266
  - { code: CHANGE_NOT_READY, description: 'change has not passed convergence' }
1050
1267
  - { code: BASELINE_RECONCILIATION_REQUIRED, description: 'baseline update or explicit no-change reason required' }
1268
+ - { code: BASELINE_FILE_MISSING, description: 'a declared baseline update does not exist' }
1269
+ - { code: BASELINE_RECONCILIATION_INCOMPLETE, description: 'repository revision or tracked specification digests remain stale after reconciliation' }
1051
1270
  - { code: ARCHIVE_EXISTS, description: 'archive target already exists' }
1052
1271
  cli_subcommand: change archive
1053
1272
  emits_events: [change_archived]
@@ -1,47 +1,29 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://ultra-builder-pro.dev/spec/command-manifest.schema.json",
4
- "title": "Command manifest (frontmatter)",
5
- "description": "YAML frontmatter contract for commands/ultra-*.md thin-shell files. Phase 3 薄壳化: 命令文件 ≤ 80 行正文,真实 workflow 放 skills/<name>/SKILL.md。additionalProperties=false (PLAN R19).",
4
+ "title": "Ultra command launcher frontmatter",
5
+ "description": "Portable source contract for a thin command launcher. Runtime metadata and workflow procedure belong outside the command file.",
6
6
  "type": "object",
7
- "required": ["description"],
7
+ "required": ["description", "workflow-ref"],
8
8
  "additionalProperties": false,
9
9
  "properties": {
10
10
  "description": {
11
11
  "type": "string",
12
12
  "minLength": 10,
13
- "description": "一句话触发描述; 给 runtime 的 skill router / 用户命令列表使用"
13
+ "maxLength": 240,
14
+ "description": "Concise user-visible action description."
14
15
  },
15
16
  "argument-hint": {
16
17
  "oneOf": [
17
18
  { "type": "string" },
18
19
  { "type": "array", "items": { "type": "string" }, "minItems": 1 }
19
20
  ],
20
- "description": "Claude Code convention: hint shown after slash-command name. Both `argument-hint: [foo]` (YAML array form) and `argument-hint: \"[foo]\"` (string form) are accepted."
21
- },
22
- "allowed-tools": {
23
- "type": "string",
24
- "description": "Claude Code convention: comma-separated tool allowlist"
25
- },
26
- "model": {
27
- "type": "string",
28
- "enum": ["haiku", "sonnet", "opus"],
29
- "description": "Claude Code convention: model routing hint"
21
+ "description": "Optional host launcher hint; it does not define argument semantics."
30
22
  },
31
23
  "workflow-ref": {
32
24
  "type": "string",
33
25
  "pattern": "^@skills/[a-z][a-z0-9\\-]*/SKILL\\.md$",
34
- "description": "Phase 3 薄壳关键字段: 指向 skills/<name>/SKILL.md; 存在即表示该命令已迁为薄壳"
35
- },
36
- "mcp_tools_required": {
37
- "type": "array",
38
- "items": { "type": "string", "pattern": "^[a-z]+\\.[a-z_]+$" },
39
- "uniqueItems": true,
40
- "description": "Phase 3+: 命令运行时会调用的 MCP tool 名单; 无 MCP 时走 cli_fallback"
41
- },
42
- "cli_fallback": {
43
- "type": "string",
44
- "description": "Phase 3+: MCP 不可达时回退的 ultra-tools 子命令 (e.g. 'init' -> 'ultra-tools init')"
26
+ "description": "The single Skill that owns this workflow."
45
27
  }
46
28
  }
47
29
  }
@@ -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,94 +1,24 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://ultra-builder-pro.dev/spec/skill-manifest.schema.json",
4
- "title": "Skill manifest (frontmatter)",
5
- "description": "YAML frontmatter contract for skills/*/SKILL.md. Strict additionalProperties=false: any new field must be added here AND propagated through validate-skills.cjs (PLAN R19 single-source rule).",
4
+ "title": "Portable Agent Skill frontmatter",
5
+ "description": "Canonical source contract for skills/*/SKILL.md. Host invocation policy, UI metadata, runtime dependencies, and command hints belong in adapters or host-native metadata, not model instructions.",
6
6
  "type": "object",
7
7
  "required": ["name", "description"],
8
8
  "additionalProperties": false,
9
9
  "properties": {
10
10
  "name": {
11
11
  "type": "string",
12
- "pattern": "^[a-z][a-z0-9\\-]*$",
13
- "description": "kebab-case slug; matches the directory name"
12
+ "minLength": 1,
13
+ "maxLength": 64,
14
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
15
+ "description": "Portable Agent Skills name; must match the parent directory."
14
16
  },
15
17
  "description": {
16
18
  "type": "string",
17
19
  "minLength": 10,
18
- "description": "human-readable trigger sentence consumed by the runtime's skill router"
19
- },
20
- "runtime": {
21
- "oneOf": [
22
- { "type": "string", "enum": ["claude", "opencode", "codex", "kimi", "all"] },
23
- {
24
- "type": "array",
25
- "items": { "type": "string", "enum": ["claude", "opencode", "codex", "kimi"] },
26
- "minItems": 1,
27
- "uniqueItems": true
28
- }
29
- ],
30
- "description": "v4.5 — which runtime(s) this skill targets. Defaults to 'all' when absent (Phase 4 adapter installs everywhere)."
31
- },
32
- "mcp_tools_required": {
33
- "type": "array",
34
- "items": { "type": "string", "pattern": "^[a-z]+\\.[a-z_]+$" },
35
- "uniqueItems": true,
36
- "description": "v4.5 — MCP tool names this skill calls; Phase 3+ generators verify availability"
37
- },
38
- "cli_fallback": {
39
- "type": "string",
40
- "description": "v4.5 — ultra-tools subcommand to fall back to when MCP unreachable"
41
- },
42
- "complexity_hint": {
43
- "type": "string",
44
- "enum": ["haiku", "sonnet", "opus"],
45
- "description": "v4.5 — model routing hint (Phase 7+)"
46
- },
47
- "argument-hint": {
48
- "type": "string",
49
- "description": "Claude Code convention: hint shown after slash-command name"
50
- },
51
- "allowed-tools": {
52
- "type": "string",
53
- "description": "Claude Code convention: comma-separated tool allowlist"
54
- },
55
- "user-invocable": {
56
- "type": "boolean",
57
- "description": "Claude Code convention: can the user call this via slash command"
58
- },
59
- "disable-model-invocation": {
60
- "type": "boolean",
61
- "description": "Claude Code convention: skill is not auto-invoked by the model"
62
- },
63
- "context": {
64
- "type": "string",
65
- "enum": ["fork", "main"],
66
- "description": "Claude Code convention: 'fork' isolates skill output from main conversation"
67
- },
68
- "license": {
69
- "type": "string",
70
- "description": "third-party skill license (e.g. MIT)"
71
- },
72
- "metadata": {
73
- "type": "object",
74
- "additionalProperties": true,
75
- "properties": {
76
- "author": { "type": "string" },
77
- "version": { "type": "string" }
78
- },
79
- "description": "third-party metadata block (vercel skills, etc.)"
80
- }
81
- },
82
- "allOf": [
83
- {
84
- "if": { "required": ["user-invocable"], "properties": { "user-invocable": { "const": true } } },
85
- "then": {
86
- "not": {
87
- "required": ["disable-model-invocation"],
88
- "properties": { "disable-model-invocation": { "const": true } }
89
- },
90
- "errorMessage": "user-invocable=true cannot coexist with disable-model-invocation=true"
91
- }
20
+ "maxLength": 1024,
21
+ "description": "Concise discovery metadata that states both what the skill does and when to use it."
92
22
  }
93
- ]
23
+ }
94
24
  }
@@ -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,35 @@
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
+ spec_refs_json TEXT NOT NULL DEFAULT '[]',
31
+ evidence_json TEXT NOT NULL DEFAULT '[]',
32
+ verification_json TEXT NOT NULL DEFAULT '[]',
33
+ unknowns_json TEXT NOT NULL DEFAULT '[]',
34
+ provider_refs_json TEXT NOT NULL DEFAULT '{}',
35
+ approved_by TEXT,
36
+ approval_note TEXT,
37
+ started_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
38
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
39
+ converged_at TEXT
40
+ );
41
+
42
+ CREATE INDEX IF NOT EXISTS baselines_status ON baselines(status, updated_at);
43
+
15
44
  -- ──────────────────────────── changes ─────────────────────────────────────
16
45
  -- A project baseline is continuous; each feature, fix, incident, or redesign
17
46
  -- is an independently converged change unit. Only changes become terminal.
@@ -305,3 +334,5 @@ INSERT OR IGNORE INTO schema_version (version, description)
305
334
  VALUES ('9.1', 'Kimi runtime support in durable events and sessions');
306
335
  INSERT OR IGNORE INTO schema_version (version, description)
307
336
  VALUES ('10.0', 'Role-scoped context snapshots, deterministic breadcrumbs, and approval-gated specification learning');
337
+ INSERT OR IGNORE INTO schema_version (version, description)
338
+ VALUES ('11.0', 'Greenfield and brownfield baseline adoption, convergence, and drift authority');
@@ -10,6 +10,7 @@ const fs = require('node:fs');
10
10
  const path = require('node:path');
11
11
 
12
12
  const ops = require('../../mcp-server/lib/state-ops.cjs');
13
+ const baselines = require('../../mcp-server/lib/baseline-workflow.cjs');
13
14
 
14
15
  const USAGE = `ultra-tools status [flags]
15
16
 
@@ -64,12 +65,23 @@ function parseFlags(args) {
64
65
  return out;
65
66
  }
66
67
 
67
- function buildCostPanel(db, { since = null, limit = 3 } = {}) {
68
+ function buildCostPanel(db, { since = null, limit = 3, rootDir = process.cwd() } = {}) {
68
69
  const by_runtime = ops.aggregateTelemetryByRuntime(db, { since });
69
70
  const top_tasks = ops.aggregateTelemetryByTask(db, { since, limit });
70
71
  const total_cost_usd = by_runtime.reduce((acc, r) => acc + (r.cost_usd || 0), 0);
72
+ const baselineHealth = baselines.inspectBaseline(db, { rootDir });
73
+ const current = baselineHealth.baseline;
71
74
  return {
72
75
  period: { since: since || 'all-time' },
76
+ baseline: {
77
+ id: current?.id || null,
78
+ mode: current?.mode || null,
79
+ status: current?.status || 'missing',
80
+ health: baselineHealth.status,
81
+ repository_revision: current?.repository_revision || null,
82
+ blockers: baselineHealth.blockers,
83
+ warnings: baselineHealth.warnings,
84
+ },
73
85
  by_runtime,
74
86
  top_tasks,
75
87
  total_cost_usd,
@@ -84,6 +96,11 @@ function formatCost(n) {
84
96
 
85
97
  function renderHuman(panel) {
86
98
  const lines = [];
99
+ const baseline = panel.baseline;
100
+ lines.push(
101
+ `Baseline: ${baseline.mode || 'none'}/${baseline.status} · ${baseline.health === 'pass' ? 'ready' : 'blocked'}`,
102
+ );
103
+ if (baseline.blockers.length > 0) lines.push(`Baseline blockers: ${baseline.blockers.join(', ')}`);
87
104
  lines.push(`Period: ${panel.period.since}`);
88
105
  lines.push(`Total cost: ${formatCost(panel.total_cost_usd)}`);
89
106
  lines.push('');
@@ -136,7 +153,8 @@ function dispatch(args) {
136
153
  const Database = require('better-sqlite3');
137
154
  const db = new Database(dbPath, { readonly: true });
138
155
  try {
139
- const panel = buildCostPanel(db, { since, limit: flags.limit });
156
+ const rootDir = path.dirname(path.dirname(dbPath));
157
+ const panel = buildCostPanel(db, { since, limit: flags.limit, rootDir });
140
158
  if (flags.json) {
141
159
  emit({ ok: true, data: panel });
142
160
  } else {
@@ -9,13 +9,14 @@ const { initProject, InitProjectError } = require('../../mcp-server/lib/init-pro
9
9
  const USAGE = `ultra-tools task <verb> [flags]
10
10
 
11
11
  VERBS:
12
- init-project Bootstrap a fresh .ultra/ skeleton (Phase 3.1)
12
+ init-project Initialize or adopt a project with authoritative Ultra state
13
13
 
14
14
  FLAGS (init-project):
15
15
  --target-dir <path> target project root (default: cwd)
16
16
  --project-name <name> project name (required)
17
17
  --project-type <type> web | api | cli | fullstack | other
18
18
  --stack <stack> tech stack descriptor (comma-separated ok)
19
+ --mode <mode> auto | greenfield | brownfield (default: auto)
19
20
  --overwrite replace existing .ultra/ (backup created)
20
21
  --source-template <path> override bundled template source
21
22
  -h, --help show this message
@@ -34,6 +35,7 @@ function parseInitFlags(args) {
34
35
  case '--project-name': flags.project_name = args[++i]; break;
35
36
  case '--project-type': flags.project_type = args[++i]; break;
36
37
  case '--stack': flags.stack = args[++i]; break;
38
+ case '--mode': flags.mode = args[++i]; break;
37
39
  case '--source-template': flags.source_template = args[++i]; break;
38
40
  case '--overwrite': flags.overwrite = true; break;
39
41
  case '--no-overwrite': flags.overwrite = false; break;
@@ -59,6 +61,7 @@ function dispatchInitProject(rawArgs) {
59
61
  project_name: flags.project_name,
60
62
  project_type: flags.project_type,
61
63
  stack: flags.stack,
64
+ mode: flags.mode || 'auto',
62
65
  overwrite: !!flags.overwrite,
63
66
  source_template: flags.source_template,
64
67
  };
@@ -63,6 +63,26 @@ test('buildCostPanel: empty db → zero totals, empty arrays', () => {
63
63
  assert.equal(out.total_cost_usd, 0);
64
64
  assert.equal(out.by_runtime.length, 0);
65
65
  assert.equal(out.top_tasks.length, 0);
66
+ assert.deepEqual(out.baseline, {
67
+ id: null, mode: null, status: 'missing', health: 'fail',
68
+ repository_revision: null, blockers: ['BASELINE_MISSING'], warnings: [],
69
+ });
70
+ } finally { teardown(dir, db); }
71
+ });
72
+
73
+ test('status exposes an in-progress brownfield baseline from authoritative state', () => {
74
+ const { dir, db } = freshFixture();
75
+ try {
76
+ db.prepare(
77
+ `INSERT INTO baselines (id, project_name, mode, status)
78
+ VALUES ('adoption', 'legacy', 'brownfield', 'adopting')`,
79
+ ).run();
80
+ const out = statusCmd.buildCostPanel(db, { rootDir: dir });
81
+ assert.equal(out.baseline.id, 'adoption');
82
+ assert.equal(out.baseline.mode, 'brownfield');
83
+ assert.equal(out.baseline.status, 'adopting');
84
+ assert.deepEqual(out.baseline.blockers, ['BASELINE_NOT_READY:adopting']);
85
+ assert.match(statusCmd.renderHuman(out), /Baseline: brownfield\/adopting.*blocked/i);
66
86
  } finally { teardown(dir, db); }
67
87
  });
68
88
 
@@ -14,6 +14,11 @@ const CLI = path.join(__dirname, 'cli.cjs');
14
14
  function fixture() {
15
15
  const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ubp-system-cli-'));
16
16
  const { db } = initStateDb(path.join(rootDir, '.ultra', 'state.db'));
17
+ db.prepare(
18
+ `INSERT INTO baselines
19
+ (id, project_name, mode, status, approved_by, approval_note, converged_at)
20
+ VALUES ('test-baseline', 'fixture', 'migrated', 'ready', 'test', 'legacy fixture', ?)`,
21
+ ).run(new Date().toISOString());
17
22
  closeStateDb(db);
18
23
  return rootDir;
19
24
  }