ultra-builder-pro-cli 0.25.0 → 0.26.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/contexts/TEMPLATE.md +87 -0
- package/.ultra-template/decisions/.gitkeep +1 -0
- package/.ultra-template/evidence/.gitkeep +1 -0
- package/.ultra-template/north-star.md +46 -0
- package/.ultra-template/research/.gitkeep +1 -0
- package/.ultra-template/specs/discovery.md +2 -2
- package/.ultra-template/tasks.json +3 -0
- package/.ultra-template/test-report.json +27 -0
- package/CHANGELOG.md +49 -0
- package/README.md +217 -579
- package/adapters/_shared/delegate-profiles/kimi-read-only.md +15 -0
- package/adapters/_shared/delegate-profiles/kimi-write.md +17 -0
- package/adapters/_shared/file-ops.cjs +76 -2
- package/adapters/_shared/host-profile.cjs +97 -0
- package/adapters/_shared/plugin-core.cjs +204 -0
- package/adapters/_shared/runtime-assets.cjs +31 -96
- package/adapters/claude.js +92 -291
- package/adapters/codex.js +309 -842
- package/adapters/grok.js +143 -1469
- package/adapters/kimi.js +124 -1053
- package/adapters/opencode.js +230 -742
- package/bin/delegate-worker.cjs +323 -0
- package/bin/delegate.cjs +456 -0
- package/bin/install.js +38 -11
- package/docs/ARCHITECTURE.md +122 -216
- package/docs/ARTIFACT-AUTHORITY.md +90 -268
- package/docs/DECISIONS.md +75 -87
- package/docs/PHILOSOPHY.md +177 -0
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +62 -39
- package/docs/RUNTIME-COMPAT-MATRIX.md +99 -156
- package/docs/SKILL-AUTHORING.md +94 -73
- package/docs/WORKFLOW-LIFECYCLE.md +93 -189
- package/hooks/README.md +17 -37
- package/hooks/_common.py +113 -0
- package/hooks/adapters/codex.py +9 -16
- package/hooks/adapters/grok.py +5 -5
- package/hooks/adapters/kimi.py +8 -14
- package/hooks/block_dangerous_commands.py +95 -0
- package/hooks/compact_context.py +65 -0
- package/hooks/mid_workflow_recall.py +25 -0
- package/hooks/post_edit_guard.py +105 -0
- package/hooks/session_context.py +30 -0
- package/package.json +17 -52
- package/skills/ultra-change/SKILL.md +97 -50
- package/skills/ultra-change/references/change-contract.md +40 -1
- package/skills/ultra-delegate/SKILL.md +82 -0
- package/skills/ultra-delegate/references/delegation-contract.md +51 -0
- package/skills/ultra-delegate/scripts/delegate_wait.py +86 -0
- package/skills/ultra-deliver/SKILL.md +61 -42
- package/skills/ultra-deliver/references/baseline-reconciliation.md +39 -20
- package/skills/ultra-dev/SKILL.md +96 -62
- package/skills/ultra-dev/references/debugging.md +22 -0
- package/skills/ultra-domain-modeling/SKILL.md +79 -0
- package/skills/ultra-grilling/SKILL.md +79 -0
- package/skills/ultra-init/SKILL.md +94 -37
- package/skills/ultra-init/references/brownfield-adoption.md +33 -83
- package/skills/ultra-init/scripts/init_project.cjs +84 -0
- package/skills/ultra-plan/SKILL.md +88 -68
- package/skills/ultra-research/SKILL.md +62 -48
- package/skills/ultra-research/references/00-problem-validation.md +5 -5
- package/skills/ultra-research/references/01-opportunity-discovery.md +3 -3
- package/skills/ultra-research/references/02-market-assessment.md +5 -4
- package/skills/ultra-research/references/03-competitive-landscape.md +3 -3
- package/skills/ultra-research/references/04-product-strategy.md +3 -3
- package/skills/ultra-research/references/05-assumptions-validation.md +5 -5
- package/skills/ultra-research/references/10-user-personas.md +3 -2
- package/skills/ultra-research/references/11-user-scenarios.md +3 -3
- package/skills/ultra-research/references/20-user-stories.md +4 -3
- package/skills/ultra-research/references/21-features-scope.md +3 -2
- package/skills/ultra-research/references/22-success-metrics.md +3 -3
- package/skills/ultra-research/references/30-architecture-context.md +3 -3
- package/skills/ultra-research/references/31-solution-strategy.md +3 -3
- package/skills/ultra-research/references/32-building-blocks.md +3 -3
- package/skills/ultra-research/references/40-deployment.md +3 -3
- package/skills/ultra-research/references/41-quality-risks.md +3 -3
- package/skills/ultra-research/references/99-synthesis.md +7 -7
- package/skills/ultra-review/SKILL.md +59 -32
- package/skills/ultra-review/references/code.md +17 -0
- package/skills/ultra-review/references/comments.md +12 -0
- package/skills/ultra-review/references/design.md +12 -0
- package/skills/ultra-review/references/errors.md +13 -0
- package/skills/ultra-review/references/spec.md +13 -0
- package/skills/ultra-review/references/tests.md +12 -0
- package/skills/ultra-review/references/worker-packet.md +40 -0
- package/skills/ultra-review/scripts/review_wait.py +26 -15
- package/skills/ultra-status/SKILL.md +61 -36
- package/skills/ultra-tdd/SKILL.md +81 -0
- package/skills/ultra-tdd/references/templates/README.md +20 -0
- package/skills/ultra-tdd/references/templates/feature-flag-default-audit.sh +79 -0
- package/skills/ultra-tdd/references/templates/persistence-real.ts +78 -0
- package/skills/ultra-tdd/references/templates/testcontainer-postgres.py +78 -0
- package/skills/ultra-tdd/references/templates/testcontainer-postgres.ts +73 -0
- package/skills/ultra-tdd/references/templates/vertical-slice.ts +66 -0
- package/skills/ultra-tdd/references/test-execution.md +18 -0
- package/skills/ultra-test/SKILL.md +70 -30
- package/skills/ultra-test/references/export-syntax.md +18 -0
- package/skills/ultra-test/scripts/worktree_digest.cjs +54 -0
- package/skills/ultra-think/SKILL.md +49 -27
- package/skills/ultra-think/references/autonomy-boundary.md +48 -0
- package/skills/ultra-think/references/interaction-boundary.md +18 -33
- package/.ultra-template/docs/research/README.md +0 -55
- package/.ultra-template/reports/templates/delivery-report.json +0 -17
- package/.ultra-template/reports/templates/test-report.json +0 -18
- package/.ultra-template/tasks/tasks.json +0 -15
- package/.ultra-template/templates/task-context.md +0 -19
- package/adapters/_shared/codex-assets.cjs +0 -725
- package/adapters/_shared/codex-ultra-tools-entry.cjs +0 -11
- package/adapters/_shared/interaction-contract.cjs +0 -129
- package/adapters/_shared/path-rewrite.cjs +0 -79
- package/adapters/_shared/runtime-native.cjs +0 -132
- package/adapters/_shared/settings-merge.cjs +0 -76
- package/agents/code-reviewer.md +0 -42
- package/agents/debugger.md +0 -40
- package/agents/review-code.md +0 -49
- package/agents/review-comments.md +0 -38
- package/agents/review-coordinator.md +0 -56
- package/agents/review-design.md +0 -40
- package/agents/review-errors.md +0 -43
- package/agents/review-spec.md +0 -39
- package/agents/review-tests.md +0 -40
- package/agents/tdd-runner.md +0 -38
- package/bin/orchestrator.js +0 -383
- package/commands/ultra-change.md +0 -10
- package/commands/ultra-deliver.md +0 -10
- package/commands/ultra-dev.md +0 -10
- package/commands/ultra-doctor.md +0 -10
- package/commands/ultra-init.md +0 -10
- package/commands/ultra-plan.md +0 -10
- package/commands/ultra-research.md +0 -10
- package/commands/ultra-review.md +0 -10
- package/commands/ultra-status.md +0 -10
- package/commands/ultra-test.md +0 -10
- package/commands/ultra-think.md +0 -10
- package/docs/AGENT-CONTEXT.md +0 -191
- package/docs/COMMIT-HASH-BACKFILL.md +0 -51
- package/docs/LEGACY-CLI-CROSSWALK.md +0 -175
- package/docs/ROADMAP.md +0 -101
- package/docs/STATE-DB-ACCESS-POLICY.md +0 -161
- package/hooks/active_task_context.py +0 -152
- package/hooks/context_envelope.py +0 -100
- package/hooks/health_check.py +0 -196
- package/hooks/pre_stop_check.py +0 -66
- package/hooks/runtime_paths.py +0 -396
- package/hooks/subagent_tracker.py +0 -88
- package/hooks/workflow_checkpoint.py +0 -76
- package/hooks/workflow_context.py +0 -48
- package/hooks/workflow_resume.py +0 -84
- package/mcp-server/hook-context.cjs +0 -38
- package/mcp-server/hook-event.cjs +0 -34
- package/mcp-server/lib/archive-journal.cjs +0 -1119
- package/mcp-server/lib/archive-mutation-worker.py +0 -365
- package/mcp-server/lib/artifact-registry.cjs +0 -1232
- package/mcp-server/lib/baseline-workflow.cjs +0 -1193
- package/mcp-server/lib/canonical-json.cjs +0 -19
- package/mcp-server/lib/change-authority.cjs +0 -26
- package/mcp-server/lib/change-packet.cjs +0 -790
- package/mcp-server/lib/change-workflow.cjs +0 -65
- package/mcp-server/lib/context-envelope.cjs +0 -581
- package/mcp-server/lib/context-paths.cjs +0 -142
- package/mcp-server/lib/decision-records.cjs +0 -423
- package/mcp-server/lib/delivery-transaction.cjs +0 -471
- package/mcp-server/lib/doctor-backup-worker.cjs +0 -328
- package/mcp-server/lib/doctor.cjs +0 -627
- package/mcp-server/lib/git-bootstrap.cjs +0 -651
- package/mcp-server/lib/init-project.cjs +0 -1021
- package/mcp-server/lib/kernel-change-workflow.cjs +0 -2029
- package/mcp-server/lib/legacy-change-workflow.cjs +0 -3032
- package/mcp-server/lib/managed-file-write.cjs +0 -172
- package/mcp-server/lib/plan-checkpoint.cjs +0 -177
- package/mcp-server/lib/plan-publication-worker.cjs +0 -830
- package/mcp-server/lib/plan-store.cjs +0 -794
- package/mcp-server/lib/prd-parser.cjs +0 -83
- package/mcp-server/lib/pricing.cjs +0 -44
- package/mcp-server/lib/project-context.cjs +0 -178
- package/mcp-server/lib/projector.cjs +0 -386
- package/mcp-server/lib/provider-refs.cjs +0 -42
- package/mcp-server/lib/runtime-paths.cjs +0 -1687
- package/mcp-server/lib/runtime-state.cjs +0 -222
- package/mcp-server/lib/safe-project-file.cjs +0 -385
- package/mcp-server/lib/stage-checkpoints.cjs +0 -463
- package/mcp-server/lib/state-authority.cjs +0 -95
- package/mcp-server/lib/state-db.cjs +0 -1580
- package/mcp-server/lib/state-ops.cjs +0 -1428
- package/mcp-server/lib/task-contract.cjs +0 -404
- package/mcp-server/lib/task-expander.cjs +0 -105
- package/mcp-server/lib/task-ledger.cjs +0 -1964
- package/mcp-server/lib/telemetry.cjs +0 -85
- package/mcp-server/lib/topo.cjs +0 -131
- package/mcp-server/lib/ultra-facade.cjs +0 -2684
- package/mcp-server/lib/worker-packet.cjs +0 -358
- package/mcp-server/server.cjs +0 -437
- package/orchestrator/auto-merge.cjs +0 -128
- package/orchestrator/daemon.cjs +0 -264
- package/orchestrator/dispatch-rules.cjs +0 -78
- package/orchestrator/parallel-orchestrator.cjs +0 -903
- package/orchestrator/planner/plan-builder.cjs +0 -125
- package/orchestrator/recovery.cjs +0 -188
- package/orchestrator/session-close-journal-worker.cjs +0 -5
- package/orchestrator/session-close-journal.cjs +0 -1014
- package/orchestrator/session-runner.cjs +0 -1153
- package/orchestrator/worktree-manager.cjs +0 -282
- package/settings.json +0 -7
- package/skills/cc-collab/SKILL.md +0 -42
- package/skills/code-review-expert/SKILL.md +0 -43
- package/skills/code-review-expert/references/correctness-reliability.md +0 -30
- package/skills/code-review-expert/references/design-boundaries.md +0 -26
- package/skills/code-review-expert/references/removal-plan.md +0 -24
- package/skills/codex-collab/SKILL.md +0 -49
- package/skills/codex-collab/evals/evals.json +0 -35
- package/skills/integration-rules/SKILL.md +0 -32
- package/skills/security-rules/SKILL.md +0 -38
- package/skills/testing-rules/SKILL.md +0 -32
- package/skills/ultra-doctor/SKILL.md +0 -41
- package/skills/ultra-plan/references/semantic-preflight.md +0 -20
- package/skills/ultra-verify/SKILL.md +0 -46
- package/skills/ultra-verify/evals/evals.json +0 -46
- package/skills/ultra-verify/references/cross-verify-modes.md +0 -28
- package/skills/ultra-verify/references/evidence-status.md +0 -21
- package/skills/ultra-verify/scripts/verify_wait.py +0 -94
- package/spec/cli-protocol.md +0 -102
- package/spec/mcp-tools.yaml +0 -312
- package/spec/schemas/baseline-reconciliation.v1.schema.json +0 -73
- package/spec/schemas/change-delta.v1.schema.json +0 -153
- package/spec/schemas/command-manifest.schema.json +0 -29
- package/spec/schemas/context-file.v4.5.schema.json +0 -54
- package/spec/schemas/delivery-report.v1.schema.json +0 -66
- package/spec/schemas/documentation-reconciliation.v1.schema.json +0 -106
- package/spec/schemas/mcp-tools.schema.json +0 -136
- package/spec/schemas/skill-manifest.schema.json +0 -24
- package/spec/schemas/state-db.sql +0 -641
- package/spec/schemas/task-ledger.v2.schema.json +0 -296
- package/spec/schemas/tasks.v4.5.schema.json +0 -96
- package/spec/schemas/test-report.v1.schema.json +0 -225
- package/ultra-tools/cli.cjs +0 -129
- package/ultra-tools/commands/db.cjs +0 -226
- package/ultra-tools/commands/legacy-memory.cjs +0 -159
- package/ultra-tools/commands/migrate.cjs +0 -1386
- package/ultra-tools/commands/session.cjs +0 -213
- package/ultra-tools/commands/status.cjs +0 -559
- package/ultra-tools/commands/system.cjs +0 -498
- package/ultra-tools/commands/task.cjs +0 -105
package/mcp-server/server.cjs
DELETED
|
@@ -1,437 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
|
|
6
|
-
const Ajv = require('ajv/dist/2020');
|
|
7
|
-
const addFormats = require('ajv-formats');
|
|
8
|
-
const yaml = require('js-yaml');
|
|
9
|
-
const { Server } = require('@modelcontextprotocol/server');
|
|
10
|
-
const { StdioServerTransport } = require('@modelcontextprotocol/server/stdio');
|
|
11
|
-
|
|
12
|
-
const { version: PACKAGE_VERSION } = require('../package.json');
|
|
13
|
-
const {
|
|
14
|
-
closeStateDb,
|
|
15
|
-
ensureSchemaVersion,
|
|
16
|
-
initStateDb,
|
|
17
|
-
openStateDb,
|
|
18
|
-
} = require('./lib/state-db.cjs');
|
|
19
|
-
const { assertStateAuthority } = require('./lib/state-authority.cjs');
|
|
20
|
-
const gitBootstrap = require('./lib/git-bootstrap.cjs');
|
|
21
|
-
const ops = require('./lib/state-ops.cjs');
|
|
22
|
-
const planStore = require('./lib/plan-store.cjs');
|
|
23
|
-
const projector = require('./lib/projector.cjs');
|
|
24
|
-
const {
|
|
25
|
-
readProjectContextEnvelope,
|
|
26
|
-
renderProjectContextEnvelope,
|
|
27
|
-
} = require('./lib/project-context.cjs');
|
|
28
|
-
const runtimePaths = require('./lib/runtime-paths.cjs');
|
|
29
|
-
const runtimeState = require('./lib/runtime-state.cjs');
|
|
30
|
-
const taskLedger = require('./lib/task-ledger.cjs');
|
|
31
|
-
const telemetry = require('./lib/telemetry.cjs');
|
|
32
|
-
const ultraFacade = require('./lib/ultra-facade.cjs');
|
|
33
|
-
|
|
34
|
-
const REPO_ROOT = process.env.UBP_RUNTIME_ROOT
|
|
35
|
-
? path.resolve(process.env.UBP_RUNTIME_ROOT)
|
|
36
|
-
: path.resolve(__dirname, '..');
|
|
37
|
-
const TOOLS_FILE = path.join(REPO_ROOT, 'spec', 'mcp-tools.yaml');
|
|
38
|
-
const PUBLIC_TOOLS = ultraFacade.PUBLIC_TOOLS;
|
|
39
|
-
const REGISTERED_TOOLS = PUBLIC_TOOLS;
|
|
40
|
-
|
|
41
|
-
function loadToolContracts() {
|
|
42
|
-
const manifest = yaml.load(fs.readFileSync(TOOLS_FILE, 'utf8'));
|
|
43
|
-
const names = manifest.tools.map((tool) => tool.name).sort();
|
|
44
|
-
const expected = [...PUBLIC_TOOLS].sort();
|
|
45
|
-
if (JSON.stringify(names) !== JSON.stringify(expected)) {
|
|
46
|
-
const error = new Error('published MCP manifest does not match the seven-tool kernel');
|
|
47
|
-
error.code = 'PUBLIC_CONTRACT_DRIFT';
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
50
|
-
return manifest.tools;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function buildAjv() {
|
|
54
|
-
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
55
|
-
addFormats(ajv);
|
|
56
|
-
return ajv;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function errorResponse(code, message, retriable = false, details = undefined) {
|
|
60
|
-
const error = { code, message, retriable };
|
|
61
|
-
if (details !== undefined) error.details = details;
|
|
62
|
-
return {
|
|
63
|
-
isError: true,
|
|
64
|
-
content: [{
|
|
65
|
-
type: 'text',
|
|
66
|
-
text: JSON.stringify({ ok: false, error }),
|
|
67
|
-
}],
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function publicToolError(error) {
|
|
72
|
-
const code = String(error?.code || 'STATE_DB_ERROR');
|
|
73
|
-
if (code.startsWith('SQLITE_')) {
|
|
74
|
-
return {
|
|
75
|
-
code: 'STATE_DB_ERROR',
|
|
76
|
-
message: 'Ultra state persistence failed',
|
|
77
|
-
retriable: code === 'SQLITE_BUSY' || code === 'SQLITE_LOCKED',
|
|
78
|
-
details: undefined,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
return {
|
|
82
|
-
code,
|
|
83
|
-
message: error?.message || 'Ultra state operation failed',
|
|
84
|
-
retriable: Boolean(error?.retriable),
|
|
85
|
-
details: error?.details,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function isInitializeCall(name, input = {}) {
|
|
90
|
-
return name === 'ultra.record'
|
|
91
|
-
&& Array.isArray(input.entries)
|
|
92
|
-
&& input.entries.length === 1
|
|
93
|
-
&& input.entries[0]?.kind === 'baseline'
|
|
94
|
-
&& input.entries[0]?.action === 'initialize';
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function isMutation(name, input = {}) {
|
|
98
|
-
if (name === 'ultra.record' || name === 'ultra.checkpoint' || name === 'ultra.archive') {
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
if (name === 'ultra.sync') return input.action !== 'inspect';
|
|
102
|
-
if (name === 'ultra.session') {
|
|
103
|
-
return ['acquire', 'heartbeat', 'release'].includes(input.action);
|
|
104
|
-
}
|
|
105
|
-
return name === 'ultra.doctor' && input.repair === true;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function requiresTeamSync(name, input = {}) {
|
|
109
|
-
return name === 'ultra.record'
|
|
110
|
-
|| name === 'ultra.checkpoint'
|
|
111
|
-
|| name === 'ultra.archive'
|
|
112
|
-
|| (name === 'ultra.session' && input.action === 'acquire');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function ownsTeamAuthorityInspection(name) {
|
|
116
|
-
return ['ultra.context', 'ultra.sync', 'ultra.doctor'].includes(name);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function startServer({
|
|
120
|
-
dbPath,
|
|
121
|
-
rootDir,
|
|
122
|
-
sessionId = null,
|
|
123
|
-
projectOnWrite = true,
|
|
124
|
-
project = projector.projectAll,
|
|
125
|
-
runtime = process.env.UBP_RUNTIME || 'unknown',
|
|
126
|
-
}) {
|
|
127
|
-
let db = null;
|
|
128
|
-
let authorityDbPath = path.resolve(dbPath);
|
|
129
|
-
let planRecovery = null;
|
|
130
|
-
|
|
131
|
-
const markPlanRecoveryRequired = (details) => {
|
|
132
|
-
planRecovery = {
|
|
133
|
-
recovered: Number(details?.recovered || 0),
|
|
134
|
-
finalized: Number(details?.finalized || 0),
|
|
135
|
-
pending: Math.max(1, Number(details?.pending || 0)),
|
|
136
|
-
issues: Array.isArray(details?.issues) ? details.issues : [],
|
|
137
|
-
};
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const getDb = (toolName, input = {}) => {
|
|
141
|
-
if (!db) {
|
|
142
|
-
const projectPaths = runtimePaths.pathsFor(rootDir);
|
|
143
|
-
const usesProjectAuthority = [
|
|
144
|
-
projectPaths.legacyStateDbPath,
|
|
145
|
-
projectPaths.stateDbPath,
|
|
146
|
-
].includes(authorityDbPath);
|
|
147
|
-
const projectExists = fs.existsSync(path.join(rootDir, '.ultra'));
|
|
148
|
-
|
|
149
|
-
if (!projectExists) {
|
|
150
|
-
const error = new Error(
|
|
151
|
-
'Ultra authority is not initialized; invoke ultra-init before using project tools',
|
|
152
|
-
);
|
|
153
|
-
error.code = 'STATE_DB_MISSING';
|
|
154
|
-
throw error;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (usesProjectAuthority) {
|
|
158
|
-
authorityDbPath = runtimePaths.ensureRuntimeState(rootDir, {
|
|
159
|
-
admitStorageBoundary: () => (
|
|
160
|
-
gitBootstrap.ensureExistingProjectStorageBoundary(rootDir)
|
|
161
|
-
),
|
|
162
|
-
}).stateDbPath;
|
|
163
|
-
} else {
|
|
164
|
-
runtimePaths.locateStateDb(rootDir, {
|
|
165
|
-
env: { UBP_DB_PATH: authorityDbPath },
|
|
166
|
-
});
|
|
167
|
-
runtimePaths.ensureRuntimeState(rootDir, {
|
|
168
|
-
env: { UBP_DB_PATH: authorityDbPath },
|
|
169
|
-
allowConfiguredRuntimeLink: true,
|
|
170
|
-
migrateState: false,
|
|
171
|
-
admitStorageBoundary: () => (
|
|
172
|
-
gitBootstrap.ensureExistingProjectStorageBoundary(rootDir)
|
|
173
|
-
),
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (['ultra.context', 'ultra.doctor'].includes(toolName)
|
|
178
|
-
&& !fs.existsSync(authorityDbPath)) {
|
|
179
|
-
const error = new Error('Ultra runtime state is missing');
|
|
180
|
-
error.code = 'STATE_DB_MISSING';
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
db = fs.existsSync(authorityDbPath)
|
|
185
|
-
? openStateDb(authorityDbPath)
|
|
186
|
-
: initStateDb(authorityDbPath).db;
|
|
187
|
-
ensureSchemaVersion(db);
|
|
188
|
-
|
|
189
|
-
if (!ownsTeamAuthorityInspection(toolName)) {
|
|
190
|
-
const teamSync = assertStateAuthority(db, rootDir, {
|
|
191
|
-
importTeamLedger: toolName !== 'ultra.context',
|
|
192
|
-
});
|
|
193
|
-
if (teamSync?.status === 'imported') {
|
|
194
|
-
const job = runtimeState.enqueueProjection(db, { tool_name: 'ultra.sync' });
|
|
195
|
-
runtimeState.processProjectionJobs(db, {
|
|
196
|
-
rootDir,
|
|
197
|
-
project,
|
|
198
|
-
limit: 500,
|
|
199
|
-
});
|
|
200
|
-
if (!job?.id) {
|
|
201
|
-
const error = new Error('team authority import projection was not scheduled');
|
|
202
|
-
error.code = 'STATE_CORRUPT';
|
|
203
|
-
throw error;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
planRecovery = planStore.recoverPlanPublications(db, { rootDir });
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (!['ultra.context', 'ultra.doctor'].includes(toolName)
|
|
211
|
-
&& (planRecovery?.pending > 0 || planRecovery?.issues?.length > 0)) {
|
|
212
|
-
planRecovery = planStore.recoverPlanPublications(db, { rootDir });
|
|
213
|
-
if (planRecovery.pending > 0 || planRecovery.issues.length > 0) {
|
|
214
|
-
const error = new Error(
|
|
215
|
-
'plan publication recovery is incomplete; run ultra.doctor with repair=true',
|
|
216
|
-
);
|
|
217
|
-
error.code = 'PLAN_RECOVERY_REQUIRED';
|
|
218
|
-
error.details = planRecovery;
|
|
219
|
-
throw error;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return db;
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const toolContracts = loadToolContracts();
|
|
226
|
-
const ajv = buildAjv();
|
|
227
|
-
const inputValidators = new Map();
|
|
228
|
-
const outputValidators = new Map();
|
|
229
|
-
for (const tool of toolContracts) {
|
|
230
|
-
inputValidators.set(tool.name, ajv.compile(tool.input_schema));
|
|
231
|
-
outputValidators.set(tool.name, ajv.compile(tool.output_schema));
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const server = new Server(
|
|
235
|
-
{ name: 'ultra-builder-pro-mcp', version: PACKAGE_VERSION },
|
|
236
|
-
{ capabilities: { tools: {} } },
|
|
237
|
-
);
|
|
238
|
-
|
|
239
|
-
server.setRequestHandler('tools/list', async () => ({
|
|
240
|
-
tools: toolContracts.map((tool) => ({
|
|
241
|
-
name: tool.name,
|
|
242
|
-
description: tool.description,
|
|
243
|
-
inputSchema: tool.input_schema,
|
|
244
|
-
})),
|
|
245
|
-
}));
|
|
246
|
-
|
|
247
|
-
server.setRequestHandler('tools/call', async (request) => {
|
|
248
|
-
const { name, arguments: input = {} } = request.params;
|
|
249
|
-
const startedAt = Date.now();
|
|
250
|
-
let toolError = null;
|
|
251
|
-
let toolDb = null;
|
|
252
|
-
|
|
253
|
-
const emitTelemetry = () => {
|
|
254
|
-
if (!toolDb) return;
|
|
255
|
-
try {
|
|
256
|
-
telemetry.appendTelemetry(toolDb, {
|
|
257
|
-
event_type: 'tool_call',
|
|
258
|
-
tool_name: name,
|
|
259
|
-
session_id: input.scope?.sid || null,
|
|
260
|
-
rootDir,
|
|
261
|
-
payload: {
|
|
262
|
-
duration_ms: Date.now() - startedAt,
|
|
263
|
-
task_id: input.scope?.task_id || null,
|
|
264
|
-
error: toolError,
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
} catch (error) {
|
|
268
|
-
process.stderr.write(`telemetry warning: ${error.message}\n`);
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
if (!REGISTERED_TOOLS.includes(name)) {
|
|
273
|
-
return errorResponse('UNKNOWN_TOOL', `tool ${name} is not registered on this server`);
|
|
274
|
-
}
|
|
275
|
-
const validateInput = inputValidators.get(name);
|
|
276
|
-
if (!validateInput(input)) {
|
|
277
|
-
return errorResponse('VALIDATION_ERROR', ajv.errorsText(validateInput.errors));
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
try {
|
|
281
|
-
toolDb = isInitializeCall(name, input) ? null : getDb(name, input);
|
|
282
|
-
if (toolDb && requiresTeamSync(name, input)) {
|
|
283
|
-
taskLedger.syncTaskLedger(toolDb, { rootDir });
|
|
284
|
-
}
|
|
285
|
-
const result = await ultraFacade.dispatch(name, input, toolDb, {
|
|
286
|
-
rootDir,
|
|
287
|
-
runtime,
|
|
288
|
-
sessionId,
|
|
289
|
-
projector: project,
|
|
290
|
-
markPlanRecoveryRequired,
|
|
291
|
-
});
|
|
292
|
-
if (name === 'ultra.doctor' && input.repair === true) {
|
|
293
|
-
planRecovery = result.repair?.plan_publications || null;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
let runtimeMeta = null;
|
|
297
|
-
if (toolDb && projectOnWrite && isMutation(name, input)) {
|
|
298
|
-
const job = runtimeState.enqueueProjection(toolDb, { tool_name: name });
|
|
299
|
-
const processed = runtimeState.processProjectionJobs(
|
|
300
|
-
toolDb,
|
|
301
|
-
{ rootDir, project, limit: 500 },
|
|
302
|
-
);
|
|
303
|
-
const own = processed.jobs.find((item) => item.id === job.id);
|
|
304
|
-
runtimeMeta = {
|
|
305
|
-
projection_commit: 'committed',
|
|
306
|
-
projection_status: own?.status || 'failed',
|
|
307
|
-
projection_job_id: job.id,
|
|
308
|
-
};
|
|
309
|
-
if (own?.incident_id) runtimeMeta.incident_id = own.incident_id;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const validateOutput = outputValidators.get(name);
|
|
313
|
-
if (!validateOutput(result)) {
|
|
314
|
-
toolError = 'OUTPUT_SCHEMA_DRIFT';
|
|
315
|
-
emitTelemetry();
|
|
316
|
-
return errorResponse(
|
|
317
|
-
'OUTPUT_SCHEMA_DRIFT',
|
|
318
|
-
ajv.errorsText(validateOutput.errors),
|
|
319
|
-
false,
|
|
320
|
-
runtimeMeta ? { _ultra: runtimeMeta } : undefined,
|
|
321
|
-
);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
emitTelemetry();
|
|
325
|
-
const visible = runtimeMeta ? { ...result, _ultra: runtimeMeta } : result;
|
|
326
|
-
return {
|
|
327
|
-
content: [{ type: 'text', text: JSON.stringify(visible) }],
|
|
328
|
-
structuredContent: result,
|
|
329
|
-
...(runtimeMeta ? { _meta: { ultra: runtimeMeta } } : {}),
|
|
330
|
-
};
|
|
331
|
-
} catch (error) {
|
|
332
|
-
toolError = error.code || 'STATE_DB_ERROR';
|
|
333
|
-
emitTelemetry();
|
|
334
|
-
const visibleError = publicToolError(error);
|
|
335
|
-
return errorResponse(
|
|
336
|
-
visibleError.code,
|
|
337
|
-
visibleError.message,
|
|
338
|
-
visibleError.retriable,
|
|
339
|
-
visibleError.details,
|
|
340
|
-
);
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
return {
|
|
345
|
-
server,
|
|
346
|
-
get db() { return db; },
|
|
347
|
-
tools: toolContracts,
|
|
348
|
-
async close() { closeStateDb(db); },
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
async function main() {
|
|
353
|
-
const rootDir = process.env.UBP_ROOT_DIR
|
|
354
|
-
? path.resolve(process.env.UBP_ROOT_DIR)
|
|
355
|
-
: path.resolve('.');
|
|
356
|
-
const configuredDb = String(process.env.UBP_DB_PATH || '').trim();
|
|
357
|
-
const dbPath = configuredDb
|
|
358
|
-
? path.resolve(configuredDb)
|
|
359
|
-
: runtimePaths.pathsFor(rootDir).stateDbPath;
|
|
360
|
-
const handle = startServer({
|
|
361
|
-
dbPath,
|
|
362
|
-
rootDir,
|
|
363
|
-
sessionId: process.env.UBP_SESSION_ID || null,
|
|
364
|
-
});
|
|
365
|
-
const transport = new StdioServerTransport();
|
|
366
|
-
await handle.server.connect(transport);
|
|
367
|
-
const cleanup = () => handle.close().finally(() => process.exit(0));
|
|
368
|
-
process.on('SIGTERM', cleanup);
|
|
369
|
-
process.on('SIGINT', cleanup);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function hookMetadata(value, fallback = 'unknown', maxLength = 256) {
|
|
373
|
-
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
374
|
-
return (normalized || fallback).slice(0, maxLength);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function appendHookLifecycleEvent({ rootDir, action, hookInput = {} } = {}) {
|
|
378
|
-
if (!['start', 'stop'].includes(action)) {
|
|
379
|
-
const error = new Error('hook lifecycle action must be start or stop');
|
|
380
|
-
error.code = 'VALIDATION_ERROR';
|
|
381
|
-
throw error;
|
|
382
|
-
}
|
|
383
|
-
const root = path.resolve(rootDir || process.cwd());
|
|
384
|
-
const dbPath = runtimePaths.locateStateDb(root);
|
|
385
|
-
if (!fs.existsSync(dbPath)) return { recorded: false, reason: 'STATE_DB_MISSING' };
|
|
386
|
-
|
|
387
|
-
const db = openStateDb(dbPath);
|
|
388
|
-
try {
|
|
389
|
-
ensureSchemaVersion(db);
|
|
390
|
-
const change = db.prepare(
|
|
391
|
-
`SELECT id FROM changes
|
|
392
|
-
WHERE status = 'active'
|
|
393
|
-
ORDER BY updated_at DESC, rowid DESC LIMIT 1`,
|
|
394
|
-
).get();
|
|
395
|
-
if (!change) return { recorded: false, reason: 'NO_ACTIVE_CHANGE' };
|
|
396
|
-
const task = db.prepare(
|
|
397
|
-
`SELECT id FROM tasks
|
|
398
|
-
WHERE change_id = ? AND status IN ('in_progress', 'pending', 'blocked')
|
|
399
|
-
ORDER BY CASE status WHEN 'in_progress' THEN 0 WHEN 'blocked' THEN 1 ELSE 2 END,
|
|
400
|
-
updated_at DESC, rowid DESC LIMIT 1`,
|
|
401
|
-
).get(change.id);
|
|
402
|
-
const payload = {
|
|
403
|
-
agent_id: hookMetadata(hookInput.agent_id),
|
|
404
|
-
agent_type: hookMetadata(hookInput.agent_type),
|
|
405
|
-
host_session_id: hookMetadata(hookInput.session_id, '', 256),
|
|
406
|
-
};
|
|
407
|
-
const hookRuntime = hookMetadata(hookInput.runtime, '', 64) || null;
|
|
408
|
-
ops.appendEvent(db, {
|
|
409
|
-
type: action === 'start' ? 'subagent_started' : 'subagent_stopped',
|
|
410
|
-
change_id: change.id,
|
|
411
|
-
task_id: task?.id || null,
|
|
412
|
-
runtime: hookRuntime,
|
|
413
|
-
payload,
|
|
414
|
-
});
|
|
415
|
-
return { recorded: true, change_id: change.id, task_id: task?.id || null };
|
|
416
|
-
} finally {
|
|
417
|
-
closeStateDb(db);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (require.main === module) {
|
|
422
|
-
main().catch((error) => {
|
|
423
|
-
process.stderr.write(`mcp-server fatal: ${error.message}\n`);
|
|
424
|
-
process.exit(1);
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
module.exports = {
|
|
429
|
-
main,
|
|
430
|
-
startServer,
|
|
431
|
-
REGISTERED_TOOLS,
|
|
432
|
-
PUBLIC_TOOLS,
|
|
433
|
-
appendHookLifecycleEvent,
|
|
434
|
-
findProjectRoot: runtimePaths.findProjectRoot,
|
|
435
|
-
readProjectContextEnvelope,
|
|
436
|
-
renderProjectContextEnvelope,
|
|
437
|
-
};
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// Phase 8B.4 — Auto-merge session worktree back onto baseBranch.
|
|
4
|
-
//
|
|
5
|
-
// Called by session-runner.closeSession when autoMerge=true. Three outcomes:
|
|
6
|
-
// 1. session HEAD === base HEAD → { merged:false, reason:'no_changes' }
|
|
7
|
-
// 2. git merge --no-ff clean → { merged:true } + merged_back event
|
|
8
|
-
// 3. conflict → { merged:false, reason:'conflict',
|
|
9
|
-
// conflict_paths[] } + merge_conflict event
|
|
10
|
-
// (caller keeps the worktree so a human can resolve)
|
|
11
|
-
//
|
|
12
|
-
// Note: git worktree add --detach shares the .git dir, so the session commit
|
|
13
|
-
// is already reachable from the repo root. No fetch / push is needed.
|
|
14
|
-
|
|
15
|
-
const { execFileSync } = require('node:child_process');
|
|
16
|
-
|
|
17
|
-
const ops = require('../mcp-server/lib/state-ops.cjs');
|
|
18
|
-
|
|
19
|
-
function runGit(args, opts = {}) {
|
|
20
|
-
return execFileSync('git', args, {
|
|
21
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
22
|
-
encoding: 'utf8',
|
|
23
|
-
...opts,
|
|
24
|
-
}).trim();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function listConflictPaths(repoRoot) {
|
|
28
|
-
try {
|
|
29
|
-
const out = execFileSync('git', ['diff', '--name-only', '--diff-filter=U'], {
|
|
30
|
-
cwd: repoRoot, stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8',
|
|
31
|
-
});
|
|
32
|
-
return out.split('\n').filter(Boolean);
|
|
33
|
-
} catch (err) {
|
|
34
|
-
process.stderr.write(`auto-merge: listConflictPaths failed: ${err.message}\n`);
|
|
35
|
-
return [];
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function autoMerge({ repoRoot, worktreePath, baseBranch = 'main', sid, task_id = null, db = null }) {
|
|
40
|
-
if (!repoRoot) throw new Error('autoMerge: repoRoot required');
|
|
41
|
-
if (!worktreePath) throw new Error('autoMerge: worktreePath required');
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const status = runGit(['status', '--porcelain=v1'], { cwd: worktreePath });
|
|
45
|
-
if (status) {
|
|
46
|
-
return {
|
|
47
|
-
merged: false,
|
|
48
|
-
reason: 'uncommitted_changes',
|
|
49
|
-
session_sha: null,
|
|
50
|
-
base_sha: null,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
} catch (err) {
|
|
54
|
-
return {
|
|
55
|
-
merged: false,
|
|
56
|
-
reason: 'worktree_status_failed',
|
|
57
|
-
session_sha: null,
|
|
58
|
-
base_sha: null,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let sessionSha;
|
|
63
|
-
let baseSha;
|
|
64
|
-
try {
|
|
65
|
-
sessionSha = runGit(['rev-parse', 'HEAD'], { cwd: worktreePath });
|
|
66
|
-
baseSha = runGit(['rev-parse', baseBranch], { cwd: repoRoot });
|
|
67
|
-
} catch (err) {
|
|
68
|
-
// Base branch missing or worktree malformed — surface but don't throw.
|
|
69
|
-
process.stderr.write(`auto-merge: rev-parse failed: ${err.message}\n`);
|
|
70
|
-
return { merged: false, reason: 'rev_parse_failed', session_sha: null, base_sha: null };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (sessionSha === baseSha) {
|
|
74
|
-
return { merged: false, reason: 'no_changes', session_sha: sessionSha, base_sha: baseSha };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Make sure repoRoot is checked out on baseBranch before we merge into it.
|
|
78
|
-
try { runGit(['checkout', baseBranch], { cwd: repoRoot }); }
|
|
79
|
-
catch (err) {
|
|
80
|
-
process.stderr.write(`auto-merge: checkout ${baseBranch} failed: ${err.message}\n`);
|
|
81
|
-
return { merged: false, reason: 'checkout_failed', session_sha: sessionSha, base_sha: baseSha };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
try {
|
|
85
|
-
runGit(
|
|
86
|
-
['merge', '--no-ff', '-m', `ubp: merge session ${sid}`, sessionSha],
|
|
87
|
-
{ cwd: repoRoot },
|
|
88
|
-
);
|
|
89
|
-
if (db) {
|
|
90
|
-
ops.appendEvent(db, {
|
|
91
|
-
type: 'merged_back',
|
|
92
|
-
task_id,
|
|
93
|
-
session_id: sid,
|
|
94
|
-
payload: { session_sha: sessionSha, base_sha: baseSha, base_branch: baseBranch },
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
return { merged: true, session_sha: sessionSha, base_sha: baseSha };
|
|
98
|
-
} catch (err) {
|
|
99
|
-
// Collect conflict info BEFORE aborting — abort resets the index.
|
|
100
|
-
const conflictPaths = listConflictPaths(repoRoot);
|
|
101
|
-
try { runGit(['merge', '--abort'], { cwd: repoRoot }); }
|
|
102
|
-
catch (abortErr) {
|
|
103
|
-
process.stderr.write(`auto-merge: merge --abort failed: ${abortErr.message}\n`);
|
|
104
|
-
}
|
|
105
|
-
if (db) {
|
|
106
|
-
ops.appendEvent(db, {
|
|
107
|
-
type: 'merge_conflict',
|
|
108
|
-
task_id,
|
|
109
|
-
session_id: sid,
|
|
110
|
-
payload: {
|
|
111
|
-
session_sha: sessionSha,
|
|
112
|
-
base_sha: baseSha,
|
|
113
|
-
base_branch: baseBranch,
|
|
114
|
-
conflict_paths: conflictPaths,
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
return {
|
|
119
|
-
merged: false,
|
|
120
|
-
reason: 'conflict',
|
|
121
|
-
session_sha: sessionSha,
|
|
122
|
-
base_sha: baseSha,
|
|
123
|
-
conflict_paths: conflictPaths,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
module.exports = { autoMerge };
|