ultra-builder-pro-cli 0.25.1 → 0.26.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 (243) hide show
  1. package/.ultra-template/changes/abandoned/.gitkeep +0 -0
  2. package/.ultra-template/contexts/TEMPLATE.md +94 -0
  3. package/.ultra-template/decisions/.gitkeep +1 -0
  4. package/.ultra-template/evidence/.gitkeep +1 -0
  5. package/.ultra-template/north-star.md +46 -0
  6. package/.ultra-template/research/.gitkeep +1 -0
  7. package/.ultra-template/specs/discovery.md +2 -2
  8. package/.ultra-template/tasks.json +3 -0
  9. package/.ultra-template/test-report.json +27 -0
  10. package/CHANGELOG.md +107 -1
  11. package/README.md +217 -579
  12. package/adapters/_shared/delegate-profiles/kimi-read-only.md +15 -0
  13. package/adapters/_shared/delegate-profiles/kimi-write.md +17 -0
  14. package/adapters/_shared/file-ops.cjs +76 -2
  15. package/adapters/_shared/host-profile.cjs +97 -0
  16. package/adapters/_shared/plugin-core.cjs +204 -0
  17. package/adapters/_shared/runtime-assets.cjs +31 -96
  18. package/adapters/claude.js +92 -291
  19. package/adapters/codex.js +309 -842
  20. package/adapters/grok.js +143 -1469
  21. package/adapters/kimi.js +124 -1053
  22. package/adapters/opencode.js +230 -742
  23. package/bin/delegate-worker.cjs +328 -0
  24. package/bin/delegate.cjs +463 -0
  25. package/bin/install.js +38 -11
  26. package/docs/ARCHITECTURE.md +125 -216
  27. package/docs/ARTIFACT-AUTHORITY.md +90 -268
  28. package/docs/DECISIONS.md +77 -87
  29. package/docs/PHILOSOPHY.md +208 -0
  30. package/docs/PLUGIN-ISOLATION-CONTRACT.md +65 -39
  31. package/docs/RUNTIME-COMPAT-MATRIX.md +140 -155
  32. package/docs/SKILL-AUTHORING.md +94 -73
  33. package/docs/WORKFLOW-LIFECYCLE.md +97 -189
  34. package/hooks/README.md +19 -37
  35. package/hooks/_common.py +113 -0
  36. package/hooks/adapters/codex.py +9 -16
  37. package/hooks/adapters/grok.py +5 -5
  38. package/hooks/adapters/kimi.py +8 -14
  39. package/hooks/block_dangerous_commands.py +201 -0
  40. package/hooks/compact_context.py +65 -0
  41. package/hooks/mid_workflow_recall.py +25 -0
  42. package/hooks/post_edit_guard.py +105 -0
  43. package/hooks/session_context.py +30 -0
  44. package/package.json +17 -52
  45. package/skills/ultra-change/SKILL.md +115 -50
  46. package/skills/ultra-change/references/change-contract.md +68 -3
  47. package/skills/ultra-delegate/SKILL.md +89 -0
  48. package/skills/ultra-delegate/references/delegation-contract.md +59 -0
  49. package/skills/ultra-delegate/scripts/delegate_wait.py +86 -0
  50. package/skills/ultra-deliver/SKILL.md +98 -42
  51. package/skills/ultra-deliver/references/baseline-reconciliation.md +39 -20
  52. package/skills/ultra-dev/SKILL.md +115 -62
  53. package/skills/ultra-dev/references/debugging.md +22 -0
  54. package/skills/ultra-domain-modeling/SKILL.md +79 -0
  55. package/skills/ultra-grilling/SKILL.md +118 -0
  56. package/skills/ultra-grilling/references/reframing.md +72 -0
  57. package/skills/ultra-init/SKILL.md +102 -37
  58. package/skills/ultra-init/references/brownfield-adoption.md +33 -83
  59. package/skills/ultra-init/scripts/init_project.cjs +84 -0
  60. package/skills/ultra-plan/SKILL.md +101 -68
  61. package/skills/ultra-research/SKILL.md +68 -48
  62. package/skills/ultra-research/references/00-problem-validation.md +5 -5
  63. package/skills/ultra-research/references/01-opportunity-discovery.md +3 -3
  64. package/skills/ultra-research/references/02-market-assessment.md +5 -4
  65. package/skills/ultra-research/references/03-competitive-landscape.md +3 -3
  66. package/skills/ultra-research/references/04-product-strategy.md +3 -3
  67. package/skills/ultra-research/references/05-assumptions-validation.md +5 -5
  68. package/skills/ultra-research/references/10-user-personas.md +3 -2
  69. package/skills/ultra-research/references/11-user-scenarios.md +3 -3
  70. package/skills/ultra-research/references/20-user-stories.md +4 -3
  71. package/skills/ultra-research/references/21-features-scope.md +3 -2
  72. package/skills/ultra-research/references/22-success-metrics.md +3 -3
  73. package/skills/ultra-research/references/30-architecture-context.md +3 -3
  74. package/skills/ultra-research/references/31-solution-strategy.md +3 -3
  75. package/skills/ultra-research/references/32-building-blocks.md +3 -3
  76. package/skills/ultra-research/references/40-deployment.md +3 -3
  77. package/skills/ultra-research/references/41-quality-risks.md +3 -3
  78. package/skills/ultra-research/references/99-synthesis.md +7 -7
  79. package/skills/ultra-review/SKILL.md +84 -32
  80. package/skills/ultra-review/references/code.md +17 -0
  81. package/skills/ultra-review/references/comments.md +12 -0
  82. package/skills/ultra-review/references/design.md +12 -0
  83. package/skills/ultra-review/references/errors.md +13 -0
  84. package/skills/ultra-review/references/spec.md +13 -0
  85. package/skills/ultra-review/references/tests.md +12 -0
  86. package/skills/ultra-review/references/worker-packet.md +40 -0
  87. package/skills/ultra-review/scripts/review_wait.py +26 -15
  88. package/skills/ultra-status/SKILL.md +61 -36
  89. package/skills/ultra-tdd/SKILL.md +81 -0
  90. package/skills/ultra-tdd/references/templates/README.md +20 -0
  91. package/skills/ultra-tdd/references/templates/feature-flag-default-audit.sh +79 -0
  92. package/skills/ultra-tdd/references/templates/persistence-real.ts +78 -0
  93. package/skills/ultra-tdd/references/templates/testcontainer-postgres.py +78 -0
  94. package/skills/ultra-tdd/references/templates/testcontainer-postgres.ts +73 -0
  95. package/skills/ultra-tdd/references/templates/vertical-slice.ts +66 -0
  96. package/skills/ultra-tdd/references/test-execution.md +18 -0
  97. package/skills/ultra-test/SKILL.md +75 -30
  98. package/skills/ultra-test/references/export-syntax.md +18 -0
  99. package/skills/ultra-test/scripts/worktree_digest.cjs +54 -0
  100. package/skills/ultra-think/SKILL.md +49 -27
  101. package/skills/ultra-think/references/autonomy-boundary.md +48 -0
  102. package/skills/ultra-think/references/interaction-boundary.md +18 -33
  103. package/.ultra-template/docs/research/README.md +0 -55
  104. package/.ultra-template/reports/templates/delivery-report.json +0 -17
  105. package/.ultra-template/reports/templates/test-report.json +0 -18
  106. package/.ultra-template/tasks/tasks.json +0 -15
  107. package/.ultra-template/templates/task-context.md +0 -19
  108. package/adapters/_shared/codex-assets.cjs +0 -725
  109. package/adapters/_shared/codex-ultra-tools-entry.cjs +0 -11
  110. package/adapters/_shared/interaction-contract.cjs +0 -129
  111. package/adapters/_shared/path-rewrite.cjs +0 -79
  112. package/adapters/_shared/runtime-native.cjs +0 -132
  113. package/adapters/_shared/settings-merge.cjs +0 -76
  114. package/agents/code-reviewer.md +0 -42
  115. package/agents/debugger.md +0 -40
  116. package/agents/review-code.md +0 -49
  117. package/agents/review-comments.md +0 -38
  118. package/agents/review-coordinator.md +0 -56
  119. package/agents/review-design.md +0 -40
  120. package/agents/review-errors.md +0 -43
  121. package/agents/review-spec.md +0 -39
  122. package/agents/review-tests.md +0 -40
  123. package/agents/tdd-runner.md +0 -38
  124. package/bin/orchestrator.js +0 -383
  125. package/commands/ultra-change.md +0 -10
  126. package/commands/ultra-deliver.md +0 -10
  127. package/commands/ultra-dev.md +0 -10
  128. package/commands/ultra-doctor.md +0 -10
  129. package/commands/ultra-init.md +0 -10
  130. package/commands/ultra-plan.md +0 -10
  131. package/commands/ultra-research.md +0 -10
  132. package/commands/ultra-review.md +0 -10
  133. package/commands/ultra-status.md +0 -10
  134. package/commands/ultra-test.md +0 -10
  135. package/commands/ultra-think.md +0 -10
  136. package/docs/AGENT-CONTEXT.md +0 -191
  137. package/docs/COMMIT-HASH-BACKFILL.md +0 -51
  138. package/docs/LEGACY-CLI-CROSSWALK.md +0 -175
  139. package/docs/ROADMAP.md +0 -101
  140. package/docs/STATE-DB-ACCESS-POLICY.md +0 -161
  141. package/hooks/active_task_context.py +0 -152
  142. package/hooks/context_envelope.py +0 -100
  143. package/hooks/health_check.py +0 -196
  144. package/hooks/pre_stop_check.py +0 -66
  145. package/hooks/runtime_paths.py +0 -396
  146. package/hooks/subagent_tracker.py +0 -88
  147. package/hooks/workflow_checkpoint.py +0 -76
  148. package/hooks/workflow_context.py +0 -48
  149. package/hooks/workflow_resume.py +0 -84
  150. package/mcp-server/hook-context.cjs +0 -38
  151. package/mcp-server/hook-event.cjs +0 -34
  152. package/mcp-server/lib/archive-journal.cjs +0 -1119
  153. package/mcp-server/lib/archive-mutation-worker.py +0 -365
  154. package/mcp-server/lib/artifact-registry.cjs +0 -1232
  155. package/mcp-server/lib/baseline-workflow.cjs +0 -1193
  156. package/mcp-server/lib/canonical-json.cjs +0 -19
  157. package/mcp-server/lib/change-authority.cjs +0 -26
  158. package/mcp-server/lib/change-packet.cjs +0 -790
  159. package/mcp-server/lib/change-workflow.cjs +0 -65
  160. package/mcp-server/lib/context-envelope.cjs +0 -581
  161. package/mcp-server/lib/context-paths.cjs +0 -142
  162. package/mcp-server/lib/decision-records.cjs +0 -423
  163. package/mcp-server/lib/delivery-transaction.cjs +0 -471
  164. package/mcp-server/lib/doctor-backup-worker.cjs +0 -328
  165. package/mcp-server/lib/doctor.cjs +0 -627
  166. package/mcp-server/lib/git-bootstrap.cjs +0 -651
  167. package/mcp-server/lib/init-project.cjs +0 -1021
  168. package/mcp-server/lib/kernel-change-workflow.cjs +0 -2029
  169. package/mcp-server/lib/legacy-change-workflow.cjs +0 -3032
  170. package/mcp-server/lib/managed-file-write.cjs +0 -172
  171. package/mcp-server/lib/plan-checkpoint.cjs +0 -177
  172. package/mcp-server/lib/plan-publication-worker.cjs +0 -830
  173. package/mcp-server/lib/plan-store.cjs +0 -794
  174. package/mcp-server/lib/prd-parser.cjs +0 -83
  175. package/mcp-server/lib/pricing.cjs +0 -44
  176. package/mcp-server/lib/project-context.cjs +0 -178
  177. package/mcp-server/lib/projector.cjs +0 -386
  178. package/mcp-server/lib/provider-refs.cjs +0 -42
  179. package/mcp-server/lib/runtime-paths.cjs +0 -1714
  180. package/mcp-server/lib/runtime-state.cjs +0 -222
  181. package/mcp-server/lib/safe-project-file.cjs +0 -385
  182. package/mcp-server/lib/stage-checkpoints.cjs +0 -463
  183. package/mcp-server/lib/state-authority.cjs +0 -95
  184. package/mcp-server/lib/state-db.cjs +0 -1580
  185. package/mcp-server/lib/state-ops.cjs +0 -1428
  186. package/mcp-server/lib/task-contract.cjs +0 -404
  187. package/mcp-server/lib/task-expander.cjs +0 -105
  188. package/mcp-server/lib/task-ledger.cjs +0 -1964
  189. package/mcp-server/lib/telemetry.cjs +0 -85
  190. package/mcp-server/lib/topo.cjs +0 -131
  191. package/mcp-server/lib/ultra-facade.cjs +0 -2684
  192. package/mcp-server/lib/worker-packet.cjs +0 -358
  193. package/mcp-server/server.cjs +0 -437
  194. package/orchestrator/auto-merge.cjs +0 -128
  195. package/orchestrator/daemon.cjs +0 -264
  196. package/orchestrator/dispatch-rules.cjs +0 -78
  197. package/orchestrator/parallel-orchestrator.cjs +0 -903
  198. package/orchestrator/planner/plan-builder.cjs +0 -125
  199. package/orchestrator/recovery.cjs +0 -188
  200. package/orchestrator/session-close-journal-worker.cjs +0 -5
  201. package/orchestrator/session-close-journal.cjs +0 -1014
  202. package/orchestrator/session-runner.cjs +0 -1153
  203. package/orchestrator/worktree-manager.cjs +0 -282
  204. package/settings.json +0 -7
  205. package/skills/cc-collab/SKILL.md +0 -42
  206. package/skills/code-review-expert/SKILL.md +0 -43
  207. package/skills/code-review-expert/references/correctness-reliability.md +0 -30
  208. package/skills/code-review-expert/references/design-boundaries.md +0 -26
  209. package/skills/code-review-expert/references/removal-plan.md +0 -24
  210. package/skills/codex-collab/SKILL.md +0 -49
  211. package/skills/codex-collab/evals/evals.json +0 -35
  212. package/skills/integration-rules/SKILL.md +0 -32
  213. package/skills/security-rules/SKILL.md +0 -38
  214. package/skills/testing-rules/SKILL.md +0 -32
  215. package/skills/ultra-doctor/SKILL.md +0 -41
  216. package/skills/ultra-plan/references/semantic-preflight.md +0 -20
  217. package/skills/ultra-verify/SKILL.md +0 -46
  218. package/skills/ultra-verify/evals/evals.json +0 -46
  219. package/skills/ultra-verify/references/cross-verify-modes.md +0 -28
  220. package/skills/ultra-verify/references/evidence-status.md +0 -21
  221. package/skills/ultra-verify/scripts/verify_wait.py +0 -94
  222. package/spec/cli-protocol.md +0 -102
  223. package/spec/mcp-tools.yaml +0 -312
  224. package/spec/schemas/baseline-reconciliation.v1.schema.json +0 -73
  225. package/spec/schemas/change-delta.v1.schema.json +0 -153
  226. package/spec/schemas/command-manifest.schema.json +0 -29
  227. package/spec/schemas/context-file.v4.5.schema.json +0 -54
  228. package/spec/schemas/delivery-report.v1.schema.json +0 -66
  229. package/spec/schemas/documentation-reconciliation.v1.schema.json +0 -106
  230. package/spec/schemas/mcp-tools.schema.json +0 -136
  231. package/spec/schemas/skill-manifest.schema.json +0 -24
  232. package/spec/schemas/state-db.sql +0 -641
  233. package/spec/schemas/task-ledger.v2.schema.json +0 -296
  234. package/spec/schemas/tasks.v4.5.schema.json +0 -96
  235. package/spec/schemas/test-report.v1.schema.json +0 -225
  236. package/ultra-tools/cli.cjs +0 -129
  237. package/ultra-tools/commands/db.cjs +0 -226
  238. package/ultra-tools/commands/legacy-memory.cjs +0 -159
  239. package/ultra-tools/commands/migrate.cjs +0 -1386
  240. package/ultra-tools/commands/session.cjs +0 -213
  241. package/ultra-tools/commands/status.cjs +0 -559
  242. package/ultra-tools/commands/system.cjs +0 -498
  243. package/ultra-tools/commands/task.cjs +0 -105
@@ -1,129 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * ultra-tools — runtime-agnostic state engine for Ultra Builder Pro.
5
- *
6
- * Maintenance CLI for Ultra initialization, status, database operations,
7
- * migration, and explicit legacy-memory cleanup. Authoritative task mutations
8
- * stay on the live MCP server; this CLI is not a task-state fallback.
9
- *
10
- * Usage:
11
- * ultra-tools <subcommand> [...]
12
- * ultra-tools --help
13
- * ultra-tools --version
14
- */
15
-
16
- 'use strict';
17
-
18
- const fs = require('node:fs');
19
- const path = require('node:path');
20
- const runtimePaths = require('../mcp-server/lib/runtime-paths.cjs');
21
-
22
- const VERSION = (() => {
23
- try {
24
- const pkg = require('../package.json');
25
- return pkg.version;
26
- } catch (_err) {
27
- return '0.1.0';
28
- }
29
- })();
30
-
31
- const USAGE = `ultra-tools v${VERSION}
32
-
33
- USAGE:
34
- ultra-tools <subcommand> [args]
35
-
36
- SUBCOMMANDS:
37
- task init-project
38
- session close | get | list | admission | heartbeat | subscribe | reap
39
- system doctor [--repair] | restore | rebaseline
40
- status [--cost] [--since <duration>] [--json]
41
- db init | checkpoint | vacuum | integrity | backup (Phase 2)
42
- migrate --from=<4.4|4.5> --to=<4.5|20.0> [--dry|--rollback]
43
- legacy-memory inspect | archive | prune --confirm DELETE_ULTRA_LEGACY_MEMORY
44
-
45
- --help / -h show this message
46
- --version / -v show version
47
-
48
- All state lives under .ultra/ in the project root.
49
- `;
50
-
51
- function readJsonIfExists(p) {
52
- if (!fs.existsSync(p)) return null;
53
- try { return JSON.parse(fs.readFileSync(p, 'utf8')); }
54
- catch (err) {
55
- fail(`malformed JSON at ${p}: ${err.message}`);
56
- }
57
- }
58
-
59
- function fail(msg, code) {
60
- process.stderr.write(`ultra-tools: ${msg}\n`);
61
- process.exit(code || 1);
62
- }
63
-
64
- const dbCommand = require('./commands/db.cjs');
65
- const migrateCommand = require('./commands/migrate.cjs');
66
- const taskCommand = require('./commands/task.cjs');
67
- const sessionCommand = require('./commands/session.cjs');
68
- const statusCommand = require('./commands/status.cjs');
69
- const legacyMemoryCommand = require('./commands/legacy-memory.cjs');
70
- const systemCommand = require('./commands/system.cjs');
71
-
72
- // Session commands run only against healthy authority and may emit best-effort
73
- // telemetry. Initialization, diagnosis, migration, and recovery commands must
74
- // never open state.db before their own evidence-preserving checks.
75
- const TELEMETRY_SUBCOMMANDS = new Set(['session']);
76
-
77
- function emitCliTelemetry(sub, rest) {
78
- try {
79
- const dbPath = runtimePaths.locateStateDb(process.cwd());
80
- if (!fs.existsSync(dbPath)) return;
81
- const Database = require('better-sqlite3');
82
- const db = new Database(dbPath);
83
- try {
84
- const telemetry = require('../mcp-server/lib/telemetry.cjs');
85
- telemetry.appendTelemetry(db, {
86
- event_type: 'tool_call',
87
- tool_name: `cli.${sub}`,
88
- session_id: process.env.UBP_SESSION_ID || null,
89
- rootDir: process.cwd(),
90
- payload: { args: Array.isArray(rest) ? rest.slice(0, 4) : [] },
91
- });
92
- } finally { db.close(); }
93
- } catch (_) { /* telemetry is opt-in side channel; never crash the CLI */ }
94
- }
95
-
96
- const SUBCOMMANDS = {
97
- task: (args) => process.exit(taskCommand.dispatch(args)),
98
- session: (args) => process.exit(sessionCommand.dispatch(args)),
99
- status: (args) => process.exit(statusCommand.dispatch(args)),
100
- db: (args) => process.exit(dbCommand.dispatch(args)),
101
- migrate: (args) => process.exit(migrateCommand.dispatch(args)),
102
- 'legacy-memory': (args) => process.exit(legacyMemoryCommand.dispatch(args)),
103
- system: (args) => systemCommand.dispatch(args).then((code) => process.exit(code)),
104
- };
105
-
106
- function main(argv) {
107
- const args = argv.slice(2);
108
- if (args.length === 0 || args[0] === '-h' || args[0] === '--help') {
109
- process.stdout.write(USAGE);
110
- return;
111
- }
112
- if (args[0] === '-v' || args[0] === '--version') {
113
- process.stdout.write(`${VERSION}\n`);
114
- return;
115
- }
116
-
117
- const [sub, ...rest] = args;
118
- const handler = SUBCOMMANDS[sub];
119
- if (!handler) fail(`unknown subcommand: ${sub}\n\n${USAGE}`);
120
- if (TELEMETRY_SUBCOMMANDS.has(sub)) emitCliTelemetry(sub, rest);
121
- handler(rest);
122
- }
123
-
124
- // exports kept for unit tests (Phase 1+)
125
- module.exports = { USAGE, SUBCOMMANDS, readJsonIfExists, VERSION, main };
126
-
127
- if (require.main === module) {
128
- main(process.argv);
129
- }
@@ -1,226 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
- const { randomUUID } = require('node:crypto');
6
- const Database = require('better-sqlite3');
7
-
8
- const { initStateDb, openStateDb, closeStateDb } = require('../../mcp-server/lib/state-db.cjs');
9
- const runtimePaths = require('../../mcp-server/lib/runtime-paths.cjs');
10
-
11
- const DEFAULT_DB_PATH = runtimePaths.STATE_DB_RELATIVE_PATH;
12
- const DEFAULT_BACKUP_DIR = path.join(runtimePaths.RUNTIME_RELATIVE_DIR, 'backups');
13
-
14
- function parseFlags(args) {
15
- const flags = { _: [] };
16
- for (let i = 0; i < args.length; i++) {
17
- const a = args[i];
18
- if (a === '--path') {
19
- flags.path = args[++i];
20
- } else if (a === '--to') {
21
- flags.to = args[++i];
22
- } else if (a === '--help' || a === '-h') {
23
- flags.help = true;
24
- } else {
25
- flags._.push(a);
26
- }
27
- }
28
- return flags;
29
- }
30
-
31
- function emit(envelope) {
32
- process.stdout.write(`${JSON.stringify(envelope)}\n`);
33
- }
34
-
35
- function dispatch(args) {
36
- const [verb, ...rest] = args;
37
- const flags = parseFlags(rest);
38
-
39
- if (!verb || flags.help) {
40
- process.stdout.write(USAGE);
41
- return 0;
42
- }
43
-
44
- switch (verb) {
45
- case 'init': return cmdInit(flags);
46
- case 'checkpoint': return cmdCheckpoint(flags);
47
- case 'vacuum': return cmdVacuum(flags);
48
- case 'integrity': return cmdIntegrity(flags);
49
- case 'backup': return cmdBackup(flags);
50
- default:
51
- emit({ ok: false, error: { code: 'UNKNOWN_VERB', message: `unknown db verb '${verb}'; supported: init, checkpoint, vacuum, integrity, backup` } });
52
- return 1;
53
- }
54
- }
55
-
56
- function resolveAuthorityPath(flags, { migrateLegacy = true } = {}) {
57
- const env = flags.path
58
- ? { UBP_DB_PATH: path.resolve(flags.path) }
59
- : process.env;
60
- return runtimePaths.resolveConfiguredStateDb(process.cwd(), {
61
- env,
62
- migrateLegacy,
63
- }).stateDbPath;
64
- }
65
-
66
- function cmdInit(flags) {
67
- try {
68
- const dbPath = resolveAuthorityPath(flags, { migrateLegacy: true });
69
- const { db, schema_version, created, tables, path: actualPath } = initStateDb(dbPath);
70
- closeStateDb(db);
71
- emit({
72
- ok: true,
73
- data: {
74
- path: actualPath,
75
- schema_version,
76
- created,
77
- tables,
78
- size_bytes: fs.statSync(actualPath).size,
79
- },
80
- });
81
- return 0;
82
- } catch (err) {
83
- emit({
84
- ok: false,
85
- error: {
86
- code: 'INIT_FAILED',
87
- message: err.message,
88
- retriable: false,
89
- },
90
- });
91
- return 2;
92
- }
93
- }
94
-
95
- function withOpenDb(flags, fn, errorCode) {
96
- let db;
97
- try {
98
- const dbPath = resolveAuthorityPath(flags, { migrateLegacy: true });
99
- if (!fs.existsSync(dbPath)) {
100
- emit({ ok: false, error: { code: 'DB_NOT_FOUND', message: `state.db missing at ${dbPath}; run 'db init' first` } });
101
- return 2;
102
- }
103
- db = openStateDb(dbPath);
104
- const data = fn(db, dbPath);
105
- emit({ ok: true, data: { path: dbPath, ...data } });
106
- return 0;
107
- } catch (err) {
108
- emit({ ok: false, error: { code: errorCode, message: err.message, retriable: false } });
109
- return 2;
110
- } finally {
111
- if (db) closeStateDb(db);
112
- }
113
- }
114
-
115
- function cmdCheckpoint(flags) {
116
- return withOpenDb(flags, (db) => {
117
- const result = db.pragma('wal_checkpoint(TRUNCATE)');
118
- // better-sqlite3 returns [{ busy, log, checkpointed }]
119
- const row = Array.isArray(result) && result[0] ? result[0] : { busy: 0, log: 0, checkpointed: 0 };
120
- return { busy: row.busy, log: row.log, checkpointed: row.checkpointed };
121
- }, 'CHECKPOINT_FAILED');
122
- }
123
-
124
- function cmdVacuum(flags) {
125
- return withOpenDb(flags, (db) => {
126
- const before = db.prepare('SELECT page_count * page_size AS bytes FROM pragma_page_count(), pragma_page_size()').get();
127
- db.prepare('VACUUM').run();
128
- const after = db.prepare('SELECT page_count * page_size AS bytes FROM pragma_page_count(), pragma_page_size()').get();
129
- return { bytes_before: before.bytes, bytes_after: after.bytes, reclaimed_bytes: before.bytes - after.bytes };
130
- }, 'VACUUM_FAILED');
131
- }
132
-
133
- function cmdIntegrity(flags) {
134
- return withOpenDb(flags, (db) => {
135
- const result = db.pragma('integrity_check');
136
- const messages = result.map((r) => r.integrity_check);
137
- const ok = messages.length === 1 && messages[0] === 'ok';
138
- return { integrity_ok: ok, messages };
139
- }, 'INTEGRITY_FAILED');
140
- }
141
-
142
- function defaultBackupPath() {
143
- const ts = new Date().toISOString().replace(/[:.]/g, '-');
144
- return path.join(DEFAULT_BACKUP_DIR, `state-db-${ts}.db`);
145
- }
146
-
147
- function quoteSqlString(value) {
148
- return `'${String(value).replaceAll("'", "''")}'`;
149
- }
150
-
151
- function createOnlineBackup(db, targetPath, {
152
- beforeSnapshot = null,
153
- } = {}) {
154
- const stage = path.join(
155
- path.dirname(targetPath),
156
- `.${path.basename(targetPath)}.snapshot-${process.pid}-${randomUUID()}`,
157
- );
158
- try {
159
- if (beforeSnapshot) beforeSnapshot();
160
- // VACUUM INTO is SQLite's synchronous, transactionally consistent
161
- // snapshot primitive. It reads committed pages through SQLite rather than
162
- // copying a main file that may lag committed WAL frames.
163
- db.exec(`VACUUM INTO ${quoteSqlString(stage)}`);
164
- const snapshot = new Database(stage, { readonly: true, fileMustExist: true });
165
- try {
166
- const integrity = snapshot.pragma('integrity_check');
167
- if (integrity.length !== 1 || integrity[0].integrity_check !== 'ok') {
168
- throw new Error('SQLite backup snapshot failed integrity_check');
169
- }
170
- } finally {
171
- snapshot.close();
172
- }
173
- fs.renameSync(stage, targetPath);
174
- return fs.statSync(targetPath).size;
175
- } finally {
176
- fs.rmSync(stage, { force: true });
177
- }
178
- }
179
-
180
- function cmdBackup(flags) {
181
- let db;
182
- try {
183
- const dbPath = resolveAuthorityPath(flags, { migrateLegacy: true });
184
- const targetPath = runtimePaths.assertManagedBackupDestination(
185
- process.cwd(),
186
- flags.to || defaultBackupPath(),
187
- ).targetPath;
188
- if (!fs.existsSync(dbPath)) {
189
- emit({ ok: false, error: { code: 'DB_NOT_FOUND', message: `state.db missing at ${dbPath}` } });
190
- return 2;
191
- }
192
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
193
- db = openStateDb(dbPath);
194
- const size = createOnlineBackup(db, targetPath);
195
- emit({ ok: true, data: { source: dbPath, target: targetPath, size_bytes: size } });
196
- return 0;
197
- } catch (err) {
198
- emit({ ok: false, error: { code: 'BACKUP_FAILED', message: err.message, retriable: true } });
199
- return 2;
200
- } finally {
201
- if (db) closeStateDb(db);
202
- }
203
- }
204
-
205
- const USAGE = `ultra-tools db <verb> [flags]
206
-
207
- Verbs (Phase 2):
208
- init [--path <db>] create or open state.db, apply schema
209
- checkpoint [--path <db>] run PRAGMA wal_checkpoint(TRUNCATE)
210
- vacuum [--path <db>] run VACUUM and report reclaimed bytes
211
- integrity [--path <db>] run PRAGMA integrity_check
212
- backup [--path <db>] [--to <out>] online .backup() to a file
213
-
214
- Default db: .ultra/.runtime/state.db
215
- Default backup: .ultra/.runtime/backups/state-db-{iso}.db
216
- `;
217
-
218
- module.exports = {
219
- dispatch,
220
- USAGE,
221
- DEFAULT_DB_PATH,
222
- DEFAULT_BACKUP_DIR,
223
- _internal: {
224
- createOnlineBackup,
225
- },
226
- };
@@ -1,159 +0,0 @@
1
- 'use strict';
2
-
3
- /** Explicit migration boundary for retired Ultra memory stores. */
4
-
5
- const fs = require('node:fs');
6
- const path = require('node:path');
7
- const Database = require('better-sqlite3');
8
-
9
- const CONFIRMATION = 'DELETE_ULTRA_LEGACY_MEMORY';
10
-
11
- function tableExists(db, name) {
12
- return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type IN ('table', 'view') AND name = ?").get(name);
13
- }
14
-
15
- function inspectLegacy(sourceDir = '.') {
16
- const root = path.resolve(sourceDir);
17
- const ultra = path.join(root, '.ultra');
18
- const hookMemory = path.join(ultra, 'memory');
19
- const dbPath = path.join(ultra, 'state.db');
20
- let stateMemoryTable = false;
21
- let stateMemoryEntries = 0;
22
- if (fs.existsSync(dbPath)) {
23
- const db = new Database(dbPath, { readonly: true, fileMustExist: true });
24
- try {
25
- stateMemoryTable = tableExists(db, 'memory_entries');
26
- if (stateMemoryTable) {
27
- stateMemoryEntries = db.prepare('SELECT COUNT(*) AS count FROM memory_entries').get().count;
28
- }
29
- } finally {
30
- db.close();
31
- }
32
- }
33
- return {
34
- source_dir: root,
35
- hook_memory_dir: fs.existsSync(hookMemory),
36
- hook_memory_path: hookMemory,
37
- state_db_path: dbPath,
38
- state_memory_table: stateMemoryTable,
39
- state_memory_entries: stateMemoryEntries,
40
- };
41
- }
42
-
43
- function archiveLegacy(sourceDir = '.', { timestamp } = {}) {
44
- const status = inspectLegacy(sourceDir);
45
- if (!status.hook_memory_dir && !status.state_memory_table) {
46
- return { ...status, archived: false, archive_dir: null };
47
- }
48
- const stamp = timestamp || new Date().toISOString().replace(/[:.]/g, '-');
49
- const archiveDir = path.join(status.source_dir, '.ultra', `legacy-memory-archive-${stamp}`);
50
- if (fs.existsSync(archiveDir)) throw new Error(`legacy memory archive already exists: ${archiveDir}`);
51
- fs.mkdirSync(archiveDir, { recursive: true });
52
-
53
- if (status.hook_memory_dir) {
54
- fs.cpSync(status.hook_memory_path, path.join(archiveDir, 'hook-memory'), {
55
- recursive: true,
56
- dereference: false,
57
- errorOnExist: true,
58
- });
59
- }
60
-
61
- if (status.state_memory_table) {
62
- const db = new Database(status.state_db_path, { readonly: true, fileMustExist: true });
63
- let entries;
64
- try {
65
- entries = db.prepare('SELECT * FROM memory_entries ORDER BY id ASC').all();
66
- } finally {
67
- db.close();
68
- }
69
- fs.writeFileSync(
70
- path.join(archiveDir, 'state-memory-entries.json'),
71
- JSON.stringify({ schema: 1, source: status.state_db_path, entries }, null, 2) + '\n',
72
- { encoding: 'utf8', flag: 'wx' },
73
- );
74
- }
75
-
76
- fs.writeFileSync(
77
- path.join(archiveDir, 'manifest.json'),
78
- JSON.stringify({ schema: 1, archived_at: new Date().toISOString(), ...status }, null, 2) + '\n',
79
- { encoding: 'utf8', flag: 'wx' },
80
- );
81
- return { ...status, archived: true, archive_dir: archiveDir };
82
- }
83
-
84
- function pruneLegacy(sourceDir = '.', { confirm, timestamp } = {}) {
85
- if (confirm !== CONFIRMATION) {
86
- throw new Error(`prune requires --confirm ${CONFIRMATION}`);
87
- }
88
- const archived = archiveLegacy(sourceDir, { timestamp });
89
- if (!archived.archived) return { ...archived, pruned: false };
90
-
91
- if (archived.hook_memory_dir) {
92
- fs.rmSync(archived.hook_memory_path, { recursive: true, force: false });
93
- }
94
- if (archived.state_memory_table) {
95
- const db = new Database(archived.state_db_path, { fileMustExist: true });
96
- try {
97
- db.transaction(() => {
98
- db.exec('DROP TRIGGER IF EXISTS memory_ai');
99
- db.exec('DROP TRIGGER IF EXISTS memory_ad');
100
- db.exec('DROP TRIGGER IF EXISTS memory_au');
101
- db.exec('DROP TABLE IF EXISTS memory_fts');
102
- db.exec('DROP TABLE IF EXISTS memory_entries');
103
- })();
104
- } finally {
105
- db.close();
106
- }
107
- }
108
- return { ...archived, pruned: true };
109
- }
110
-
111
- function parseFlags(args) {
112
- const flags = { _: [] };
113
- for (let i = 0; i < args.length; i += 1) {
114
- const token = args[i];
115
- if (token === '--source-dir') {
116
- flags.sourceDir = args[i + 1];
117
- i += 1;
118
- } else if (token.startsWith('--source-dir=')) {
119
- flags.sourceDir = token.slice('--source-dir='.length);
120
- } else if (token === '--confirm') {
121
- flags.confirm = args[i + 1];
122
- i += 1;
123
- } else if (token.startsWith('--confirm=')) {
124
- flags.confirm = token.slice('--confirm='.length);
125
- } else {
126
- flags._.push(token);
127
- }
128
- }
129
- return flags;
130
- }
131
-
132
- function dispatch(args) {
133
- const flags = parseFlags(args);
134
- const action = flags._[0] || 'inspect';
135
- try {
136
- let data;
137
- if (action === 'inspect') data = inspectLegacy(flags.sourceDir);
138
- else if (action === 'archive') data = archiveLegacy(flags.sourceDir);
139
- else if (action === 'prune') data = pruneLegacy(flags.sourceDir, { confirm: flags.confirm });
140
- else throw new Error(`unknown legacy-memory action: ${action}`);
141
- process.stdout.write(`${JSON.stringify({ ok: true, data })}\n`);
142
- return 0;
143
- } catch (error) {
144
- process.stdout.write(`${JSON.stringify({
145
- ok: false,
146
- error: { code: 'LEGACY_MEMORY_MIGRATION_FAILED', message: error.message, retriable: false },
147
- })}\n`);
148
- return 2;
149
- }
150
- }
151
-
152
- module.exports = {
153
- CONFIRMATION,
154
- inspectLegacy,
155
- archiveLegacy,
156
- pruneLegacy,
157
- parseFlags,
158
- dispatch,
159
- };