ultra-builder-pro-cli 0.11.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 (63) 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 +42 -1
  7. package/README.md +21 -9
  8. package/adapters/_shared/codex-assets.cjs +1 -1
  9. package/adapters/_shared/handbook.cjs +4 -3
  10. package/adapters/_shared/tests/handbook.test.cjs +4 -0
  11. package/adapters/opencode.js +8 -2
  12. package/adapters/tests/codex.test.cjs +2 -2
  13. package/adapters/tests/kimi-hook.test.cjs +1 -1
  14. package/adapters/tests/opencode.test.cjs +36 -1
  15. package/commands/ultra-init.md +3 -3
  16. package/docs/AGENT-CONTEXT.md +16 -8
  17. package/docs/ARCHITECTURE.md +32 -5
  18. package/docs/PLAN.zh-CN.md +7 -5
  19. package/docs/ROADMAP.md +4 -2
  20. package/docs/RUNTIME-COMPAT-MATRIX.md +8 -5
  21. package/docs/STATE-DB-ACCESS-POLICY.md +17 -11
  22. package/docs/USER-HANDBOOK-CONTRACT.md +8 -5
  23. package/hooks/README.md +4 -3
  24. package/hooks/adapters/codex.py +1 -1
  25. package/hooks/adapters/kimi.py +1 -1
  26. package/hooks/context_spine.py +120 -16
  27. package/hooks/health_check.py +11 -0
  28. package/hooks/pre_stop_check.py +6 -5
  29. package/mcp-server/lib/baseline-workflow.cjs +415 -0
  30. package/mcp-server/lib/baseline-workflow.test.cjs +225 -0
  31. package/mcp-server/lib/change-workflow.cjs +24 -27
  32. package/mcp-server/lib/change-workflow.test.cjs +202 -6
  33. package/mcp-server/lib/context-spine.cjs +74 -9
  34. package/mcp-server/lib/context-spine.test.cjs +15 -0
  35. package/mcp-server/lib/doctor.cjs +14 -0
  36. package/mcp-server/lib/doctor.test.cjs +25 -1
  37. package/mcp-server/lib/init-project.cjs +49 -14
  38. package/mcp-server/lib/provider-refs.cjs +42 -0
  39. package/mcp-server/lib/spec-learning.test.cjs +5 -0
  40. package/mcp-server/lib/state-db.cjs +63 -4
  41. package/mcp-server/lib/state-db.test.cjs +8 -3
  42. package/mcp-server/server.cjs +48 -3
  43. package/mcp-server/tests/init-project.test.cjs +54 -8
  44. package/mcp-server/tests/server-contract.test.cjs +99 -2
  45. package/mcp-server/tests/state-db.test.cjs +11 -2
  46. package/package.json +1 -1
  47. package/skills/ultra-change/SKILL.md +24 -13
  48. package/skills/ultra-deliver/SKILL.md +15 -5
  49. package/skills/ultra-dev/SKILL.md +4 -0
  50. package/skills/ultra-doctor/SKILL.md +8 -2
  51. package/skills/ultra-init/SKILL.md +46 -50
  52. package/skills/ultra-init/references/brownfield-adoption.md +65 -0
  53. package/skills/ultra-plan/SKILL.md +9 -2
  54. package/skills/ultra-research/SKILL.md +10 -5
  55. package/skills/ultra-status/SKILL.md +13 -6
  56. package/spec/cli-protocol.md +4 -0
  57. package/spec/mcp-tools.yaml +223 -4
  58. package/spec/schemas/mcp-tools.schema.json +1 -1
  59. package/spec/schemas/state-db.sql +33 -2
  60. package/ultra-tools/commands/status.cjs +20 -2
  61. package/ultra-tools/commands/task.cjs +4 -1
  62. package/ultra-tools/status-command.test.cjs +20 -0
  63. package/ultra-tools/system-command.test.cjs +5 -0
@@ -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
  }