@jstn-sdk/ma 0.1.12 → 0.14.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/.codex/agents/Architect.toml +1 -2
- package/.codex/agents/Auditor.toml +1 -2
- package/.codex/agents/Builder.toml +1 -2
- package/.codex/agents/Flow.toml +1 -2
- package/.codex/agents/Sage.toml +1 -2
- package/.codex/agents/Vibe.toml +1 -2
- package/.codex/hooks.json +24 -13
- package/.codex/prompts/enforcement.md +4 -0
- package/.codex/prompts/onboarding.md +6 -1
- package/.codex/prompts/release-rules.md +0 -0
- package/.codex/prompts/skill-contract.md +4 -0
- package/COVERAGE.md +211 -0
- package/DEMO.md +274 -0
- package/LICENSE +0 -0
- package/README.md +132 -656
- package/bin/ma.js +748 -55
- package/data/clone-data.ledger.json +41 -0
- package/data/clone-data.proof.json +50 -0
- package/data/clone-data.rvf +37 -0
- package/docs/README.md +10 -1
- package/docs/autonomous-tasks.md +46 -0
- package/docs/codex-integration.md +16 -0
- package/docs/getting-started.md +62 -22
- package/docs/mcp-setup.md +64 -0
- package/docs/qa/release-issue-gates-0.14.0.json +644 -0
- package/docs/qa/release-readiness-0.1.5.md +1 -1
- package/docs/qa/{release-readiness-0.1.12.md → release-readiness-0.14.0.md} +25 -9
- package/docs/quality.md +24 -0
- package/docs/reference/native-security-playbooks.md +6 -0
- package/docs/reference/native-source-selection.md +6 -0
- package/docs/release-spec.md +39 -10
- package/docs/skills.md +14 -1
- package/index.js +295 -2
- package/mcp/collections.json +23 -6
- package/mcp/fallback.json +0 -0
- package/mcp/local/code-intel.js +179 -41
- package/mcp/local/context.js +180 -0
- package/mcp/local/memory.js +17 -6
- package/mcp/local/quality.js +39 -0
- package/mcp/local/state.js +7 -3
- package/mcp/local/team-run.js +56 -4
- package/mcp/local-capabilities.json +9 -0
- package/mcp/servers.json +24 -0
- package/package.json +29 -4
- package/plugins/meta-architect/.app.json +1 -1
- package/plugins/meta-architect/.codex-plugin/plugin.json +1 -1
- package/plugins/meta-architect/.mcp.json +1 -1
- package/plugins/meta-architect/README.md +8 -1
- package/plugins/meta-architect/obsidian/main.js +534 -0
- package/plugins/meta-architect/obsidian/manifest.json +9 -0
- package/plugins/meta-architect/obsidian/styles.css +7 -0
- package/plugins/meta-architect/skills/arch/SKILL.md +2 -0
- package/plugins/meta-architect/skills/build/SKILL.md +3 -0
- package/plugins/meta-architect/skills/flow/SKILL.md +2 -0
- package/plugins/meta-architect/skills/sage/SKILL.md +2 -0
- package/plugins/meta-architect/skills/sage/references/source-selection.md +8 -0
- package/plugins/meta-architect/skills/vet/SKILL.md +2 -0
- package/plugins/meta-architect/skills/vet/references/security-playbooks.md +7 -0
- package/plugins/meta-architect/skills/vibe/SKILL.md +2 -0
- package/schemas/autonomous-task-queue.schema.json +56 -0
- package/schemas/handoff-packet.schema.json +36 -0
- package/schemas/setup-receipt.schema.json +28 -0
- package/schemas/skill-frontmatter.schema.json +20 -0
- package/schemas/support-bundle.schema.json +37 -0
- package/schemas/task-contract.schema.json +31 -0
- package/scripts/active-autonomy-hook.mjs +226 -0
- package/scripts/build-linux-packages.mjs +7 -3
- package/scripts/cleanup-test-fixtures.sh +55 -0
- package/scripts/context-hydration-hook.mjs +89 -0
- package/scripts/demo-smoke.js +285 -0
- package/scripts/doctor.js +27 -12
- package/scripts/install.sh +57 -0
- package/scripts/install.sh.sha256 +1 -0
- package/scripts/linux-package-smoke.mjs +2 -2
- package/scripts/package-size-check.mjs +26 -0
- package/scripts/plugin-sync.js +83 -17
- package/scripts/postinstall.js +17 -10
- package/scripts/prepack.js +9 -0
- package/scripts/ralph/prompt.md +35 -0
- package/scripts/release-sync.js +72 -7
- package/scripts/release-verify.js +260 -2
- package/scripts/setup-npmrc.js +48 -23
- package/scripts/skills-install.js +9 -2
- package/scripts/skills-manifest.js +2 -21
- package/scripts/skills-pack.js +2 -2
- package/scripts/skills-validate.js +5 -55
- package/skills/arch/SKILL.md +2 -0
- package/skills/build/SKILL.md +3 -0
- package/skills/flow/SKILL.md +2 -0
- package/skills/index.json +0 -0
- package/skills/sage/SKILL.md +2 -0
- package/skills/sage/references/source-selection.md +8 -0
- package/skills/vet/SKILL.md +2 -0
- package/skills/vet/references/security-playbooks.md +7 -0
- package/skills/vibe/SKILL.md +2 -0
- package/sprint/00-idea.md +0 -0
- package/sprint/01-architecture.md +0 -0
- package/sprint/02-oss-evidence.md +0 -0
- package/sprint/03-logic.md +0 -0
- package/sprint/04-security.md +0 -0
- package/sprint/05-dx-ux.md +0 -0
- package/sprint/06-build-plan.md +0 -0
- package/sprint/07-release.md +0 -0
- package/src/agents.js +279 -0
- package/src/bootstrap.js +268 -62
- package/src/build-gate.js +2 -2
- package/src/codex-app-server.js +291 -0
- package/src/decision-log.js +0 -0
- package/src/fs-utils.js +175 -4
- package/src/launcher.js +28 -21
- package/src/mcp-config.js +9 -1
- package/src/mcp-live-client.js +422 -3
- package/src/paths.js +10 -1
- package/src/policy.js +3 -3
- package/src/prelaunch.js +189 -0
- package/src/quality/ai-quality-orchestrator.js +328 -0
- package/src/release-issue-gates.js +252 -0
- package/src/release-operations.js +62 -0
- package/src/release-state.js +0 -0
- package/src/runtime/active-autonomy-core.js +208 -0
- package/src/runtime/agent-compat.js +31 -0
- package/src/runtime/alignment-sentinel.js +165 -0
- package/src/runtime/architect-review.js +326 -0
- package/src/runtime/autonomous-tasks.js +408 -0
- package/src/runtime/build-readiness.js +28 -4
- package/src/runtime/code-graph-rehearse.js +113 -0
- package/src/runtime/codeburn-core.js +112 -0
- package/src/runtime/context-authority.js +40 -0
- package/src/runtime/context-economy-core.js +316 -0
- package/src/runtime/continuity-graph.js +201 -0
- package/src/runtime/continuity-notes.js +71 -26
- package/src/runtime/core-source-ingest.js +379 -0
- package/src/runtime/detached-provider.js +142 -0
- package/src/runtime/doctor-report.js +18 -0
- package/src/runtime/environment-awareness-core.js +460 -0
- package/src/runtime/exposure-catalog.js +276 -0
- package/src/runtime/graphify-core.js +167 -0
- package/src/runtime/guidance-stack.js +9 -2
- package/src/runtime/handoff-packets.js +92 -0
- package/src/runtime/headroom-core.js +104 -0
- package/src/runtime/helper-orchestration-core.js +307 -0
- package/src/runtime/hook-profiles.js +20 -0
- package/src/runtime/learning-loop-core.js +344 -0
- package/src/runtime/live-agent-verification.js +122 -0
- package/src/runtime/maestro-events.js +18 -0
- package/src/runtime/maestro-manager.js +19 -0
- package/src/runtime/maestro-output.js +58 -0
- package/src/runtime/maestro-state.js +125 -0
- package/src/runtime/managed-markdown.js +29 -0
- package/src/runtime/mcp-authority.js +147 -0
- package/src/runtime/mcp-policy.js +192 -0
- package/src/runtime/obsidian-integration-core.js +1089 -0
- package/src/runtime/obsidian-plugin-bridge.js +1045 -0
- package/src/runtime/pi-maestro-core.js +89 -0
- package/src/runtime/preferences.js +79 -0
- package/src/runtime/project-context.js +636 -0
- package/src/runtime/prompt-strategy-core.js +230 -0
- package/src/runtime/quorum-review.js +90 -0
- package/src/runtime/ralph-execution-core.js +217 -0
- package/src/runtime/redaction-gateway.js +373 -0
- package/src/runtime/runtime-state.js +935 -2
- package/src/runtime/schema-migrations.js +162 -0
- package/src/runtime/semantic-recording-core.js +147 -0
- package/src/runtime/signal-hooks.js +28 -0
- package/src/runtime/skills-registry-export.js +754 -0
- package/src/runtime/task-contracts.js +83 -0
- package/src/runtime/universal-plugin-broker-core.js +898 -0
- package/src/runtime/workspace-intelligence-runtime.js +674 -0
- package/src/runtime/workspace-virtualizer.js +102 -0
- package/src/runtime-artifacts.js +225 -62
- package/src/setup-lifecycle.js +359 -0
- package/src/skill-frontmatter.js +78 -0
- package/src/skill-installer.js +226 -71
- package/src/skills.js +1166 -96
- package/src/state-sync.js +0 -0
- package/src/test-fixtures.js +543 -0
- package/src/tui/grid.js +67 -0
- package/src/tui/status-grid.js +23 -0
- package/support-bundle.json +114 -0
- package/templates/AGENTS.md +6 -2
- package/templates/catalog-manifest.json +0 -0
- package/templates/model-instructions/core.md +0 -0
- package/templates/model-instructions/release.md +0 -0
- package/templates/model-instructions/security.md +0 -0
- package/templates/quality/ai-quality-rules.yml +37 -0
- package/docs/assets/image/Screenshot(1).png +0 -0
- package/docs/assets/image/Screenshot(2).png +0 -0
- package/docs/assets/image/Screenshot(3).png +0 -0
- package/docs/assets/image/Screenshot(4).png +0 -0
- package/docs/assets/image/Screenshot(5).png +0 -0
- package/docs/assets/image/Screenshot(6).png +0 -0
- package/docs/assets/image/Screenshot(7).png +0 -0
- package/docs/assets/image/Screenshot(8).png +0 -0
- package/docs/assets/image/Screenshot(9).png +0 -0
- package/docs/assets/meta-architect-logo.png +0 -0
- package/docs/assets/meta-architect-logo.svg +0 -8
- package/docs/onboarding.md +0 -65
- package/docs/skills-publishing.md +0 -255
package/src/skills.js
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { appendDecision } from "./decision-log.js";
|
|
4
|
-
import { readJson, writeFileIfMissing, writeJson } from "./fs-utils.js";
|
|
4
|
+
import { readJson, writeFileIfMissing, writeJson, writeTextAtomically } from "./fs-utils.js";
|
|
5
5
|
import { validateMcpServers } from "./mcp-config.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createMcpLiveClient, hasConfiguredMcpRemoteBridge } from "./mcp-live-client.js";
|
|
7
7
|
import { getRepoRoot, getRuntimeReadPath, getRuntimeWritePath, packageRoot } from "./paths.js";
|
|
8
|
+
import { resolveReleaseIssueGates, resolveReleaseReadiness } from "./release-issue-gates.js";
|
|
9
|
+
import {
|
|
10
|
+
evaluateAlignmentDrift,
|
|
11
|
+
saveAlignmentSentinelReport,
|
|
12
|
+
} from "./runtime/alignment-sentinel.js";
|
|
8
13
|
import { evaluateRuntimeBuildReadiness } from "./runtime/build-readiness.js";
|
|
14
|
+
import {
|
|
15
|
+
findIngestedCoreSourceForRepo,
|
|
16
|
+
loadCoreSourceIngest,
|
|
17
|
+
} from "./runtime/core-source-ingest.js";
|
|
18
|
+
import { launchDetachedTrack } from "./runtime/detached-provider.js";
|
|
19
|
+
import {
|
|
20
|
+
scanLockfilePackageExposure,
|
|
21
|
+
validateMcpPolicyExposure,
|
|
22
|
+
} from "./runtime/exposure-catalog.js";
|
|
23
|
+
import { getMergedGuidancePath } from "./runtime/guidance-stack.js";
|
|
24
|
+
import { createHandoffPacket, writeHandoffPacket } from "./runtime/handoff-packets.js";
|
|
25
|
+
import { createHelperReceipt } from "./runtime/helper-orchestration-core.js";
|
|
26
|
+
import { appendMaestroEvent } from "./runtime/maestro-events.js";
|
|
9
27
|
import {
|
|
10
28
|
buildHelperFailureMatrix,
|
|
11
29
|
chooseMaestroManagerAction,
|
|
@@ -14,12 +32,30 @@ import {
|
|
|
14
32
|
loadManagerRunRegistry,
|
|
15
33
|
saveManagerRunRegistry,
|
|
16
34
|
} from "./runtime/maestro-manager.js";
|
|
35
|
+
import {
|
|
36
|
+
beginMaestroOrchestration,
|
|
37
|
+
loadMaestroStateOrDefault,
|
|
38
|
+
saveMaestroState,
|
|
39
|
+
} from "./runtime/maestro-state.js";
|
|
40
|
+
import { embedProjectContext } from "./runtime/obsidian-integration-core.js";
|
|
17
41
|
import { submitTask } from "./runtime/orchestrator.js";
|
|
42
|
+
import { seedPreferences } from "./runtime/preferences.js";
|
|
43
|
+
import { refreshProjectIndex } from "./runtime/project-context.js";
|
|
44
|
+
import {
|
|
45
|
+
createQuorumReviewReceipt,
|
|
46
|
+
evaluateQuorumVotes,
|
|
47
|
+
quorumDecisions,
|
|
48
|
+
} from "./runtime/quorum-review.js";
|
|
49
|
+
import { writeRalphExecutionContract } from "./runtime/ralph-execution-core.js";
|
|
50
|
+
import { redactProviderBoundText, seedRedactionVault } from "./runtime/redaction-gateway.js";
|
|
18
51
|
import {
|
|
19
52
|
assertLeaderAuthority,
|
|
20
53
|
createRuntimeSummary,
|
|
21
54
|
loadRuntimeSnapshot,
|
|
55
|
+
repairRuntimeScratchpadArtifacts,
|
|
22
56
|
} from "./runtime/runtime-state.js";
|
|
57
|
+
import { migrateSchemas } from "./runtime/schema-migrations.js";
|
|
58
|
+
import { createTaskContract, writeTaskContract } from "./runtime/task-contracts.js";
|
|
23
59
|
import {
|
|
24
60
|
seedRuntimeArtifacts,
|
|
25
61
|
writeArchitectureArtifacts,
|
|
@@ -31,9 +67,29 @@ import {
|
|
|
31
67
|
writeProjectContext,
|
|
32
68
|
writeSecuritySpec,
|
|
33
69
|
} from "./runtime-artifacts.js";
|
|
70
|
+
import {
|
|
71
|
+
assertNoSymlinkComponents,
|
|
72
|
+
assertSetupReceiptHealthy,
|
|
73
|
+
compactRuntimeState,
|
|
74
|
+
listManagedArtifacts,
|
|
75
|
+
withSetupLock,
|
|
76
|
+
writeSetupReceipt,
|
|
77
|
+
} from "./setup-lifecycle.js";
|
|
34
78
|
import { syncStatusUpdates } from "./state-sync.js";
|
|
35
79
|
|
|
36
|
-
const skillNames = [
|
|
80
|
+
const skillNames = [
|
|
81
|
+
"$maestro",
|
|
82
|
+
"$arch",
|
|
83
|
+
"$sage",
|
|
84
|
+
"$flow",
|
|
85
|
+
"$vet",
|
|
86
|
+
"$vibe",
|
|
87
|
+
"$build",
|
|
88
|
+
"$align",
|
|
89
|
+
"$diagnose",
|
|
90
|
+
"$tdd",
|
|
91
|
+
"$cleanup",
|
|
92
|
+
];
|
|
37
93
|
const maestroWorkflowSequence = ["$arch", "$sage", "$flow", "$vet", "$vibe", "$build"];
|
|
38
94
|
const workflowTemplates = {
|
|
39
95
|
"maestro.skill.md":
|
|
@@ -181,6 +237,35 @@ function chooseMaestroRecommendation(releaseState, idea, buildReadiness = null)
|
|
|
181
237
|
};
|
|
182
238
|
}
|
|
183
239
|
|
|
240
|
+
if (releaseState.build_status === "READY") {
|
|
241
|
+
return {
|
|
242
|
+
nextStep: "Start the bounded build execution substep.",
|
|
243
|
+
why: "The build lane has prepared a narrow slice and verification plan, and the next safe move is to begin that bounded substep.",
|
|
244
|
+
primaryLane: "$build",
|
|
245
|
+
supportLane: "implementation",
|
|
246
|
+
assignments: [
|
|
247
|
+
"Run $build again to move the bounded build slice into active execution.",
|
|
248
|
+
"Keep the slice reversible and lane-owned.",
|
|
249
|
+
],
|
|
250
|
+
avoid: ["Do not merge or release before the bounded build slice is complete."],
|
|
251
|
+
nextTrigger: "`$build`",
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (releaseState.build_status === "RUNNING") {
|
|
256
|
+
return {
|
|
257
|
+
nextStep: "Finalize the bounded build execution substep.",
|
|
258
|
+
why: "The build lane is already running its bounded slice and now needs completion evidence before downstream promotion.",
|
|
259
|
+
primaryLane: "$build",
|
|
260
|
+
supportLane: "verification",
|
|
261
|
+
assignments: [
|
|
262
|
+
"Run $build again to finalize the bounded build substep and persist completion evidence.",
|
|
263
|
+
],
|
|
264
|
+
avoid: ["Do not merge or release before the build lane records DONE."],
|
|
265
|
+
nextTrigger: "`$build`",
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
184
269
|
if (releaseState.merge_status !== "MERGED_TO_DEVELOPMENT") {
|
|
185
270
|
return {
|
|
186
271
|
nextStep: "Finish the implementation slice and merge it into development.",
|
|
@@ -255,7 +340,144 @@ function stripBackticks(value) {
|
|
|
255
340
|
return value.replaceAll("`", "");
|
|
256
341
|
}
|
|
257
342
|
|
|
258
|
-
|
|
343
|
+
function isGitMcpDocumentationTool(tool, action) {
|
|
344
|
+
if (!tool || typeof tool.name !== "string") {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
if (!tool.name.startsWith(`${action}_`)) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
if (tool.name === "fetch_generic_url_content") {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const lowerName = tool.name.toLowerCase();
|
|
355
|
+
return (
|
|
356
|
+
lowerName.includes("_documentation") ||
|
|
357
|
+
lowerName.includes("_docs") ||
|
|
358
|
+
`${tool.description ?? ""}`.toLowerCase().includes("documentation")
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function createBoundedBuildSlice() {
|
|
363
|
+
return [
|
|
364
|
+
"Create or confirm the bounded implementation and verification slice for the current release-ready state.",
|
|
365
|
+
"Keep the slice reversible and owned by the $build lane.",
|
|
366
|
+
];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function createBuildVerificationPlan(nextTrigger = "$build") {
|
|
370
|
+
return [
|
|
371
|
+
"Confirm release gates and runtime control-plane artifacts are still green.",
|
|
372
|
+
`Use ${nextTrigger} as the bounded verification loop trigger for the current build slice.`,
|
|
373
|
+
];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function createBuildRepairPath() {
|
|
377
|
+
return [
|
|
378
|
+
"If the bounded build slice becomes invalid without upstream gate regression, return to READY and rerun `$build`.",
|
|
379
|
+
"If runtime or upstream gates regress, fail closed and repair those blockers before resuming.",
|
|
380
|
+
];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function updateMaestroLedgerForBuild({
|
|
384
|
+
buildStatus,
|
|
385
|
+
runtimeSummary,
|
|
386
|
+
blockers,
|
|
387
|
+
nextTriggers,
|
|
388
|
+
gateState,
|
|
389
|
+
trackStatus,
|
|
390
|
+
completionEvidence = [],
|
|
391
|
+
}) {
|
|
392
|
+
let maestroState = await loadMaestroStateOrDefault();
|
|
393
|
+
maestroState = beginMaestroOrchestration(maestroState, {
|
|
394
|
+
globalStatus: gateState,
|
|
395
|
+
});
|
|
396
|
+
maestroState.runtime_tracks.track_0_sync = {
|
|
397
|
+
active_gate: "$build",
|
|
398
|
+
status: trackStatus,
|
|
399
|
+
pid: null,
|
|
400
|
+
execution_pane: null,
|
|
401
|
+
exit_code: trackStatus === "COMPLETED" ? 0 : null,
|
|
402
|
+
blockers,
|
|
403
|
+
next_triggers: nextTriggers,
|
|
404
|
+
completion_evidence: completionEvidence,
|
|
405
|
+
build_status: buildStatus,
|
|
406
|
+
updated_at: new Date().toISOString(),
|
|
407
|
+
runtime_summary: {
|
|
408
|
+
pendingMailboxCount: runtimeSummary.pendingMailboxCount,
|
|
409
|
+
invalidArtifacts: runtimeSummary.invalidArtifacts,
|
|
410
|
+
missingArtifacts: runtimeSummary.missingArtifacts,
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
maestroState.downstream_lock_table.$build = {
|
|
414
|
+
is_locked: buildStatus !== "DONE",
|
|
415
|
+
locked_by: buildStatus === "DONE" ? [] : ["$build"],
|
|
416
|
+
unlock_criteria: "build_status == 'DONE'",
|
|
417
|
+
};
|
|
418
|
+
maestroState.timestamp = new Date().toISOString();
|
|
419
|
+
maestroState.global_status = gateState;
|
|
420
|
+
await saveMaestroState(maestroState);
|
|
421
|
+
await appendMaestroEvent({
|
|
422
|
+
record_type: "runtime:track_status",
|
|
423
|
+
gate: "$build",
|
|
424
|
+
global_status: gateState,
|
|
425
|
+
track_status: trackStatus,
|
|
426
|
+
build_status: buildStatus,
|
|
427
|
+
next_triggers: nextTriggers,
|
|
428
|
+
blockers,
|
|
429
|
+
});
|
|
430
|
+
await appendMaestroEvent({
|
|
431
|
+
record_type: "lock:downstream_circuit_breaker",
|
|
432
|
+
target_gate: "$build",
|
|
433
|
+
is_locked: buildStatus !== "DONE",
|
|
434
|
+
locked_by: buildStatus === "DONE" ? [] : ["$build"],
|
|
435
|
+
unlock_criteria: "build_status == 'DONE'",
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async function updateScratchpadTrackForLane({
|
|
440
|
+
gate,
|
|
441
|
+
trackStatus,
|
|
442
|
+
globalStatus,
|
|
443
|
+
blockers = [],
|
|
444
|
+
nextTriggers = [],
|
|
445
|
+
detached = null,
|
|
446
|
+
details = {},
|
|
447
|
+
}) {
|
|
448
|
+
let maestroState = await loadMaestroStateOrDefault();
|
|
449
|
+
maestroState = beginMaestroOrchestration(maestroState, {
|
|
450
|
+
globalStatus,
|
|
451
|
+
});
|
|
452
|
+
const trackKey = `track_${gate.replaceAll("$", "")}_sync`;
|
|
453
|
+
maestroState.runtime_tracks[trackKey] = {
|
|
454
|
+
active_gate: gate,
|
|
455
|
+
status: trackStatus,
|
|
456
|
+
pid: null,
|
|
457
|
+
execution_pane: detached?.executionPane ?? null,
|
|
458
|
+
provider: detached?.provider ?? "none",
|
|
459
|
+
log_path: detached?.logPath ?? null,
|
|
460
|
+
exit_code: trackStatus === "COMPLETED" ? 0 : null,
|
|
461
|
+
blockers,
|
|
462
|
+
next_triggers: nextTriggers,
|
|
463
|
+
updated_at: new Date().toISOString(),
|
|
464
|
+
...details,
|
|
465
|
+
};
|
|
466
|
+
maestroState.timestamp = new Date().toISOString();
|
|
467
|
+
maestroState.global_status = globalStatus;
|
|
468
|
+
await saveMaestroState(maestroState);
|
|
469
|
+
await appendMaestroEvent({
|
|
470
|
+
record_type: "runtime:track_status",
|
|
471
|
+
gate,
|
|
472
|
+
global_status: globalStatus,
|
|
473
|
+
track_status: trackStatus,
|
|
474
|
+
next_triggers: nextTriggers,
|
|
475
|
+
blockers,
|
|
476
|
+
provider: detached?.provider ?? "none",
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export async function runBuildLane({ actor = null, reviewMode = null, quorumVotes = [] } = {}) {
|
|
259
481
|
const authority = await assertLeaderAuthority(actor);
|
|
260
482
|
const runtimeSnapshot = await loadRuntimeSnapshot();
|
|
261
483
|
const runtimeSummary = createRuntimeSummary(runtimeSnapshot);
|
|
@@ -268,10 +490,22 @@ export async function runBuildLane({ actor = null } = {}) {
|
|
|
268
490
|
if (!evaluation.allowed) {
|
|
269
491
|
await writeBuildPlanArtifact({
|
|
270
492
|
allowed: false,
|
|
493
|
+
gateState: "LOCKED",
|
|
271
494
|
blockers: evaluation.blockers,
|
|
272
495
|
nextTriggers: evaluation.nextTriggers,
|
|
496
|
+
buildSlice: createBoundedBuildSlice(),
|
|
497
|
+
verificationPlan: createBuildVerificationPlan("`$build`"),
|
|
498
|
+
repairPath: createBuildRepairPath(),
|
|
273
499
|
runtimeSummary,
|
|
274
500
|
});
|
|
501
|
+
await updateMaestroLedgerForBuild({
|
|
502
|
+
buildStatus: runtimeSnapshot.release.build_status,
|
|
503
|
+
runtimeSummary,
|
|
504
|
+
blockers: evaluation.blockers,
|
|
505
|
+
nextTriggers: evaluation.nextTriggers,
|
|
506
|
+
gateState: "LOCKED",
|
|
507
|
+
trackStatus: "BLOCKED",
|
|
508
|
+
});
|
|
275
509
|
await appendDecision({
|
|
276
510
|
actor: authority.leaderActor,
|
|
277
511
|
kind: "skill",
|
|
@@ -290,30 +524,205 @@ export async function runBuildLane({ actor = null } = {}) {
|
|
|
290
524
|
}
|
|
291
525
|
|
|
292
526
|
const suggestedBranches = ["feature/implementation", "feature/verification"];
|
|
527
|
+
const buildSlice = createBoundedBuildSlice();
|
|
528
|
+
const verificationPlan = createBuildVerificationPlan("`$build`");
|
|
529
|
+
const repairPath = createBuildRepairPath();
|
|
530
|
+
const ralphContract = await writeRalphExecutionContract({
|
|
531
|
+
buildSlice,
|
|
532
|
+
verificationPlan,
|
|
533
|
+
runtimeSummary,
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
if (runtimeSnapshot.release.build_status === "LOCKED") {
|
|
537
|
+
await writeBuildPlanArtifact({
|
|
538
|
+
allowed: true,
|
|
539
|
+
gateState: "READY",
|
|
540
|
+
blockers: [],
|
|
541
|
+
nextTriggers: ["$build"],
|
|
542
|
+
suggestedBranches,
|
|
543
|
+
buildSlice,
|
|
544
|
+
verificationPlan,
|
|
545
|
+
repairPath,
|
|
546
|
+
runtimeSummary,
|
|
547
|
+
});
|
|
548
|
+
await appendDecision({
|
|
549
|
+
actor: authority.leaderActor,
|
|
550
|
+
kind: "skill",
|
|
551
|
+
skill: "$build",
|
|
552
|
+
decision: "Build gate ready",
|
|
553
|
+
status: "READY",
|
|
554
|
+
evidence: [
|
|
555
|
+
{ kind: "runtime-summary", value: runtimeSummary },
|
|
556
|
+
{ kind: "branches", value: suggestedBranches },
|
|
557
|
+
{ kind: "build-slice", value: buildSlice },
|
|
558
|
+
{ kind: "ralph-prd", value: ralphContract.prdPath },
|
|
559
|
+
],
|
|
560
|
+
blockers: [],
|
|
561
|
+
next_allowed_triggers: ["$build"],
|
|
562
|
+
});
|
|
563
|
+
await syncStatusUpdates({ build_status: "READY" }, { actor: authority.leaderActor });
|
|
564
|
+
await updateMaestroLedgerForBuild({
|
|
565
|
+
buildStatus: "READY",
|
|
566
|
+
runtimeSummary,
|
|
567
|
+
blockers: [],
|
|
568
|
+
nextTriggers: ["$build"],
|
|
569
|
+
gateState: "READY",
|
|
570
|
+
trackStatus: "READY",
|
|
571
|
+
});
|
|
572
|
+
return {
|
|
573
|
+
status: "READY",
|
|
574
|
+
nextTrigger: "$build",
|
|
575
|
+
blockers: [],
|
|
576
|
+
suggestedBranches,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (runtimeSnapshot.release.build_status === "READY") {
|
|
581
|
+
await writeBuildPlanArtifact({
|
|
582
|
+
allowed: true,
|
|
583
|
+
gateState: "RUNNING",
|
|
584
|
+
blockers: [],
|
|
585
|
+
nextTriggers: ["$build"],
|
|
586
|
+
suggestedBranches,
|
|
587
|
+
buildSlice,
|
|
588
|
+
verificationPlan,
|
|
589
|
+
repairPath,
|
|
590
|
+
runtimeSummary,
|
|
591
|
+
});
|
|
592
|
+
await appendDecision({
|
|
593
|
+
actor: authority.leaderActor,
|
|
594
|
+
kind: "skill",
|
|
595
|
+
skill: "$build",
|
|
596
|
+
decision: "Started the bounded build execution substep",
|
|
597
|
+
status: "RUNNING",
|
|
598
|
+
evidence: [
|
|
599
|
+
{ kind: "runtime-summary", value: runtimeSummary },
|
|
600
|
+
{ kind: "build-slice", value: buildSlice },
|
|
601
|
+
{ kind: "verification-plan", value: verificationPlan },
|
|
602
|
+
{ kind: "ralph-prd", value: ralphContract.prdPath },
|
|
603
|
+
],
|
|
604
|
+
blockers: [],
|
|
605
|
+
next_allowed_triggers: ["$build"],
|
|
606
|
+
});
|
|
607
|
+
await syncStatusUpdates({ build_status: "RUNNING" }, { actor: authority.leaderActor });
|
|
608
|
+
await updateMaestroLedgerForBuild({
|
|
609
|
+
buildStatus: "RUNNING",
|
|
610
|
+
runtimeSummary,
|
|
611
|
+
blockers: [],
|
|
612
|
+
nextTriggers: ["$build"],
|
|
613
|
+
gateState: "RUNNING",
|
|
614
|
+
trackStatus: "RUNNING",
|
|
615
|
+
});
|
|
616
|
+
return {
|
|
617
|
+
status: "RUNNING",
|
|
618
|
+
nextTrigger: "$build",
|
|
619
|
+
blockers: [],
|
|
620
|
+
suggestedBranches,
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const completionEvidence = [
|
|
625
|
+
"Build slice remained release-ready through the bounded verification substep.",
|
|
626
|
+
"Runtime control-plane artifacts remained valid at completion.",
|
|
627
|
+
];
|
|
628
|
+
if (reviewMode === "quorum") {
|
|
629
|
+
const quorum = evaluateQuorumVotes(quorumVotes);
|
|
630
|
+
const quorumReceipt = createQuorumReviewReceipt({ votes: quorumVotes, evaluation: quorum });
|
|
631
|
+
if (quorum.decision !== quorumDecisions.APPROVED) {
|
|
632
|
+
await writeBuildPlanArtifact({
|
|
633
|
+
allowed: true,
|
|
634
|
+
gateState: "READY",
|
|
635
|
+
blockers: quorum.blockers,
|
|
636
|
+
nextTriggers: ["$build"],
|
|
637
|
+
suggestedBranches,
|
|
638
|
+
buildSlice,
|
|
639
|
+
verificationPlan: [
|
|
640
|
+
...verificationPlan,
|
|
641
|
+
"Resolve quorum disagreement or provide a compatible majority fingerprint before promotion.",
|
|
642
|
+
],
|
|
643
|
+
repairPath,
|
|
644
|
+
runtimeSummary,
|
|
645
|
+
});
|
|
646
|
+
await appendDecision({
|
|
647
|
+
actor: authority.leaderActor,
|
|
648
|
+
kind: "skill",
|
|
649
|
+
skill: "$build",
|
|
650
|
+
decision: "Quorum review did not approve the current bounded build slice",
|
|
651
|
+
status: "READY",
|
|
652
|
+
evidence: [
|
|
653
|
+
{ kind: "runtime-summary", value: runtimeSummary },
|
|
654
|
+
{ kind: "quorum-votes", value: quorumVotes },
|
|
655
|
+
{ kind: "quorum-decision", value: quorum },
|
|
656
|
+
{ kind: "quorum-receipt", value: quorumReceipt },
|
|
657
|
+
{ kind: "ralph-prd", value: ralphContract.prdPath },
|
|
658
|
+
],
|
|
659
|
+
blockers: quorum.blockers,
|
|
660
|
+
next_allowed_triggers: ["$build"],
|
|
661
|
+
});
|
|
662
|
+
await syncStatusUpdates({ build_status: "READY" }, { actor: authority.leaderActor });
|
|
663
|
+
await updateMaestroLedgerForBuild({
|
|
664
|
+
buildStatus: "READY",
|
|
665
|
+
runtimeSummary,
|
|
666
|
+
blockers: quorum.blockers,
|
|
667
|
+
nextTriggers: ["$build"],
|
|
668
|
+
gateState: "READY",
|
|
669
|
+
trackStatus: "BLOCKED",
|
|
670
|
+
completionEvidence: ["Quorum review returned INDETERMINATE or non-approval."],
|
|
671
|
+
});
|
|
672
|
+
return {
|
|
673
|
+
status: "READY",
|
|
674
|
+
nextTrigger: "$build",
|
|
675
|
+
blockers: quorum.blockers,
|
|
676
|
+
suggestedBranches,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
completionEvidence.push(
|
|
680
|
+
"Quorum review approved the bounded build slice with a majority-compatible fingerprint.",
|
|
681
|
+
);
|
|
682
|
+
completionEvidence.push(
|
|
683
|
+
`Quorum confidence receipt recorded with ${quorumReceipt.reviewer_count} reviewers.`,
|
|
684
|
+
);
|
|
685
|
+
}
|
|
293
686
|
await writeBuildPlanArtifact({
|
|
294
687
|
allowed: true,
|
|
688
|
+
gateState: "DONE",
|
|
295
689
|
blockers: [],
|
|
296
|
-
nextTriggers: ["
|
|
690
|
+
nextTriggers: ["ma merge <feature/*> development"],
|
|
297
691
|
suggestedBranches,
|
|
692
|
+
buildSlice,
|
|
693
|
+
verificationPlan,
|
|
694
|
+
repairPath,
|
|
695
|
+
completionEvidence,
|
|
298
696
|
runtimeSummary,
|
|
299
697
|
});
|
|
300
698
|
await appendDecision({
|
|
301
699
|
actor: authority.leaderActor,
|
|
302
700
|
kind: "skill",
|
|
303
701
|
skill: "$build",
|
|
304
|
-
decision: "
|
|
305
|
-
status: "
|
|
702
|
+
decision: "Completed the bounded build execution substep",
|
|
703
|
+
status: "DONE",
|
|
306
704
|
evidence: [
|
|
307
705
|
{ kind: "runtime-summary", value: runtimeSummary },
|
|
308
706
|
{ kind: "branches", value: suggestedBranches },
|
|
707
|
+
{ kind: "completion-evidence", value: completionEvidence },
|
|
708
|
+
{ kind: "ralph-prd", value: ralphContract.prdPath },
|
|
309
709
|
],
|
|
310
710
|
blockers: [],
|
|
311
|
-
next_allowed_triggers: ["
|
|
711
|
+
next_allowed_triggers: ["ma merge <feature/*> development"],
|
|
712
|
+
});
|
|
713
|
+
await syncStatusUpdates({ build_status: "DONE" }, { actor: authority.leaderActor });
|
|
714
|
+
await updateMaestroLedgerForBuild({
|
|
715
|
+
buildStatus: "DONE",
|
|
716
|
+
runtimeSummary,
|
|
717
|
+
blockers: [],
|
|
718
|
+
nextTriggers: ["ma merge <feature/*> development"],
|
|
719
|
+
gateState: "COMPLETED",
|
|
720
|
+
trackStatus: "COMPLETED",
|
|
721
|
+
completionEvidence,
|
|
312
722
|
});
|
|
313
|
-
await syncStatusUpdates({ build_status: "READY" }, { actor: authority.leaderActor });
|
|
314
723
|
return {
|
|
315
|
-
status: "
|
|
316
|
-
nextTrigger: "
|
|
724
|
+
status: "DONE",
|
|
725
|
+
nextTrigger: "ma merge <feature/*> development",
|
|
317
726
|
blockers: [],
|
|
318
727
|
suggestedBranches,
|
|
319
728
|
};
|
|
@@ -396,10 +805,23 @@ function buildManagerDecisionBlockers(managerRun, runtimeSummary, buildReadiness
|
|
|
396
805
|
}
|
|
397
806
|
|
|
398
807
|
function executeManagerHelper(helper, { releaseState, runtimeSummary, recommendation }) {
|
|
808
|
+
const baseReceipt = ({ observedContext, result, nextTrigger }) => ({
|
|
809
|
+
helperId: helper.id,
|
|
810
|
+
...createHelperReceipt({
|
|
811
|
+
skill: helper.skill,
|
|
812
|
+
objective: helper.objective,
|
|
813
|
+
observedContext,
|
|
814
|
+
result,
|
|
815
|
+
nextTrigger: nextTrigger ?? recommendation.nextTrigger ?? "$maestro",
|
|
816
|
+
}),
|
|
817
|
+
});
|
|
818
|
+
|
|
399
819
|
if (helper.skill === "$align") {
|
|
400
820
|
return {
|
|
401
|
-
|
|
402
|
-
|
|
821
|
+
...baseReceipt({
|
|
822
|
+
observedContext: `build_status=${releaseState.build_status}; next=${recommendation.nextTrigger}`,
|
|
823
|
+
result: "Normalized the manager handoff around the current lane sequence and next trigger.",
|
|
824
|
+
}),
|
|
403
825
|
workflowSequence: maestroWorkflowSequence,
|
|
404
826
|
currentBuildStatus: releaseState.build_status,
|
|
405
827
|
recommendedNextTrigger: recommendation.nextTrigger,
|
|
@@ -408,8 +830,10 @@ function executeManagerHelper(helper, { releaseState, runtimeSummary, recommenda
|
|
|
408
830
|
|
|
409
831
|
if (helper.skill === "$diagnose") {
|
|
410
832
|
return {
|
|
411
|
-
|
|
412
|
-
|
|
833
|
+
...baseReceipt({
|
|
834
|
+
observedContext: `pending_mailbox=${runtimeSummary.pendingMailboxCount}; invalid_artifacts=${runtimeSummary.invalidArtifacts.length}; missing_artifacts=${runtimeSummary.missingArtifacts.length}`,
|
|
835
|
+
result: "Captured the smallest blocker slices before the manager resumes gated work.",
|
|
836
|
+
}),
|
|
413
837
|
pendingMailboxCount: runtimeSummary.pendingMailboxCount,
|
|
414
838
|
invalidArtifacts: runtimeSummary.invalidArtifacts,
|
|
415
839
|
missingArtifacts: runtimeSummary.missingArtifacts,
|
|
@@ -418,8 +842,10 @@ function executeManagerHelper(helper, { releaseState, runtimeSummary, recommenda
|
|
|
418
842
|
|
|
419
843
|
if (helper.skill === "$tdd") {
|
|
420
844
|
return {
|
|
421
|
-
|
|
422
|
-
|
|
845
|
+
...baseReceipt({
|
|
846
|
+
observedContext: `build_status=${releaseState.build_status}; next=${recommendation.nextTrigger}`,
|
|
847
|
+
result: "Defined the regression-first boundary for the owning implementation lane.",
|
|
848
|
+
}),
|
|
423
849
|
buildStatus: releaseState.build_status,
|
|
424
850
|
nextTrigger: recommendation.nextTrigger,
|
|
425
851
|
};
|
|
@@ -427,8 +853,10 @@ function executeManagerHelper(helper, { releaseState, runtimeSummary, recommenda
|
|
|
427
853
|
|
|
428
854
|
if (helper.skill === "$cleanup") {
|
|
429
855
|
return {
|
|
430
|
-
|
|
431
|
-
|
|
856
|
+
...baseReceipt({
|
|
857
|
+
observedContext: `merge_status=${releaseState.merge_status}; release_status=${releaseState.release_status}`,
|
|
858
|
+
result: "Prepared contract-preserving simplification without changing release authority.",
|
|
859
|
+
}),
|
|
432
860
|
mergeStatus: releaseState.merge_status,
|
|
433
861
|
releaseStatus: releaseState.release_status,
|
|
434
862
|
};
|
|
@@ -589,9 +1017,35 @@ export async function runArch() {
|
|
|
589
1017
|
throw new Error("Cannot run $arch before ma idea captures a project brief");
|
|
590
1018
|
}
|
|
591
1019
|
|
|
1020
|
+
const guidance = await readJson(getMergedGuidancePath()).catch(() => ({
|
|
1021
|
+
sources: [],
|
|
1022
|
+
content: "",
|
|
1023
|
+
}));
|
|
1024
|
+
const advisoryGuidance = guidance.sources
|
|
1025
|
+
.map((source) => `${source.label ?? source.id ?? "Guidance"}: ${source.content ?? ""}`)
|
|
1026
|
+
.filter(Boolean)
|
|
1027
|
+
.join(" ");
|
|
1028
|
+
|
|
592
1029
|
const blueprint = {
|
|
593
|
-
|
|
1030
|
+
decision: "Approve the first bounded architecture direction.",
|
|
1031
|
+
status: "APPROVED",
|
|
1032
|
+
summary: `Blueprint derived from idea: ${idea}. Runtime shell currently exposes ${runtimeSummary.workerCount} workers, ${runtimeSummary.workspaceCount} workspaces, and ${runtimeSummary.guidanceSourceCount} guidance sources. Advisory guidance: ${advisoryGuidance}`,
|
|
594
1033
|
suggestedStack: ["Node.js", "MCP", "GitMCP", "Git worktree", "File-backed runtime state"],
|
|
1034
|
+
workloadAssumptions: [
|
|
1035
|
+
"single-repo operator workflow",
|
|
1036
|
+
"gate-driven release discipline",
|
|
1037
|
+
"file-backed runtime state",
|
|
1038
|
+
],
|
|
1039
|
+
rejectedAlternatives: [
|
|
1040
|
+
"Standalone second umbrella runtime surface because it would weaken Meta-Architect ownership.",
|
|
1041
|
+
],
|
|
1042
|
+
evidence: [
|
|
1043
|
+
`Workers detected: ${runtimeSummary.workerCount}`,
|
|
1044
|
+
`Workspaces detected: ${runtimeSummary.workspaceCount}`,
|
|
1045
|
+
`Guidance sources detected: ${runtimeSummary.guidanceSourceCount}`,
|
|
1046
|
+
],
|
|
1047
|
+
blockers: [],
|
|
1048
|
+
nextAllowedTriggers: ["`$sage`"],
|
|
595
1049
|
outcome: "Produce a gated architecture and implementation plan backed by runtime state.",
|
|
596
1050
|
};
|
|
597
1051
|
|
|
@@ -608,6 +1062,16 @@ export async function runArch() {
|
|
|
608
1062
|
});
|
|
609
1063
|
|
|
610
1064
|
await syncStatusUpdates({ architecture_status: "APPROVED" });
|
|
1065
|
+
await updateScratchpadTrackForLane({
|
|
1066
|
+
gate: "$arch",
|
|
1067
|
+
trackStatus: "COMPLETED",
|
|
1068
|
+
globalStatus: "COMPLETED",
|
|
1069
|
+
nextTriggers: ["$sage"],
|
|
1070
|
+
details: {
|
|
1071
|
+
decision: blueprint.decision,
|
|
1072
|
+
rejected_alternatives: blueprint.rejectedAlternatives,
|
|
1073
|
+
},
|
|
1074
|
+
});
|
|
611
1075
|
}
|
|
612
1076
|
|
|
613
1077
|
export async function runSage() {
|
|
@@ -615,17 +1079,49 @@ export async function runSage() {
|
|
|
615
1079
|
const config = await validateMcpServers();
|
|
616
1080
|
const runtimeSummary = await readRuntimeSummary();
|
|
617
1081
|
assertControlPlaneReady(runtimeSummary);
|
|
1082
|
+
await seedRedactionVault();
|
|
1083
|
+
await seedPreferences();
|
|
1084
|
+
const disableLiveProbe = process.env.MA_DISABLE_LIVE_MCP === "1";
|
|
618
1085
|
const sourceEntries = config.servers.map((server) => ({
|
|
619
1086
|
repo: server.repo,
|
|
620
1087
|
endpoint: server.endpoint,
|
|
621
1088
|
category: server.category,
|
|
1089
|
+
exactUpstreamMapping: server.repo,
|
|
1090
|
+
evidenceGrade: disableLiveProbe ? "PARTIAL" : "MISSING",
|
|
622
1091
|
}));
|
|
623
1092
|
const blockers = [];
|
|
624
1093
|
const idea = (await readIdeaText()) ?? "software architecture";
|
|
625
|
-
|
|
626
|
-
let
|
|
1094
|
+
let verificationSuccessCount = 0;
|
|
1095
|
+
let coreSourceIngest = null;
|
|
1096
|
+
try {
|
|
1097
|
+
coreSourceIngest = await loadCoreSourceIngest();
|
|
1098
|
+
} catch {
|
|
1099
|
+
coreSourceIngest = null;
|
|
1100
|
+
}
|
|
627
1101
|
|
|
628
1102
|
for (const source of sourceEntries) {
|
|
1103
|
+
const ingestedSource = findIngestedCoreSourceForRepo(coreSourceIngest, source.repo);
|
|
1104
|
+
if (ingestedSource) {
|
|
1105
|
+
source.localSourceSnapshot = {
|
|
1106
|
+
status: ingestedSource.status,
|
|
1107
|
+
localPath: ingestedSource.local_path,
|
|
1108
|
+
capability: ingestedSource.capability,
|
|
1109
|
+
semanticRole: ingestedSource.semantic_role,
|
|
1110
|
+
fileCount: ingestedSource.file_count,
|
|
1111
|
+
contentSha256: ingestedSource.content_sha256,
|
|
1112
|
+
gitCommit: ingestedSource.git_commit,
|
|
1113
|
+
sampledFiles: ingestedSource.sampled_files,
|
|
1114
|
+
};
|
|
1115
|
+
source.liveProbe = {
|
|
1116
|
+
transport: "local-core-source-ingest",
|
|
1117
|
+
queryMode: "local-snapshot",
|
|
1118
|
+
sampleText: ingestedSource.sample_text?.slice(0, 400) ?? null,
|
|
1119
|
+
};
|
|
1120
|
+
source.evidenceGrade = "VERIFIED";
|
|
1121
|
+
verificationSuccessCount += 1;
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
629
1125
|
if (disableLiveProbe) {
|
|
630
1126
|
source.liveProbe = {
|
|
631
1127
|
skipped: true,
|
|
@@ -634,43 +1130,76 @@ export async function runSage() {
|
|
|
634
1130
|
continue;
|
|
635
1131
|
}
|
|
636
1132
|
|
|
637
|
-
const client =
|
|
1133
|
+
const client = createMcpLiveClient(source.endpoint);
|
|
638
1134
|
try {
|
|
639
1135
|
const init = await client.connect();
|
|
640
1136
|
const tools = await client.request("tools/list", {});
|
|
641
|
-
const searchTool = tools.tools?.find(
|
|
642
|
-
|
|
643
|
-
);
|
|
644
|
-
const fetchTool = tools.tools?.find(
|
|
645
|
-
(tool) => tool.name.includes("fetch_") && tool.name.endsWith("_documentation"),
|
|
646
|
-
);
|
|
1137
|
+
const searchTool = tools.tools?.find((tool) => isGitMcpDocumentationTool(tool, "search"));
|
|
1138
|
+
const fetchTool = tools.tools?.find((tool) => isGitMcpDocumentationTool(tool, "fetch"));
|
|
647
1139
|
|
|
648
1140
|
let evidence = null;
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
1141
|
+
let queryMode = "list-only";
|
|
1142
|
+
const callFailures = [];
|
|
1143
|
+
if (fetchTool) {
|
|
1144
|
+
try {
|
|
1145
|
+
evidence = await client.request("tools/call", {
|
|
1146
|
+
name: fetchTool.name,
|
|
1147
|
+
arguments: {},
|
|
1148
|
+
});
|
|
1149
|
+
queryMode = "fetch";
|
|
1150
|
+
} catch (error) {
|
|
1151
|
+
callFailures.push({
|
|
1152
|
+
tool: fetchTool.name,
|
|
1153
|
+
error: error.message,
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
if (!evidence && searchTool) {
|
|
1158
|
+
const redactedQuery = await redactProviderBoundText(idea, {
|
|
1159
|
+
kind: "sage-live-query",
|
|
1160
|
+
repo: source.repo,
|
|
658
1161
|
});
|
|
1162
|
+
try {
|
|
1163
|
+
evidence = await client.request("tools/call", {
|
|
1164
|
+
name: searchTool.name,
|
|
1165
|
+
arguments: { query: redactedQuery.sanitizedText },
|
|
1166
|
+
});
|
|
1167
|
+
queryMode = "search";
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
callFailures.push({
|
|
1170
|
+
tool: searchTool.name,
|
|
1171
|
+
error: error.message,
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
if ((fetchTool || searchTool) && !evidence) {
|
|
1176
|
+
throw new Error(
|
|
1177
|
+
`No GitMCP documentation call succeeded: ${callFailures
|
|
1178
|
+
.map((failure) => `${failure.tool}: ${failure.error}`)
|
|
1179
|
+
.join("; ")}`,
|
|
1180
|
+
);
|
|
659
1181
|
}
|
|
660
1182
|
|
|
661
1183
|
source.liveProbe = {
|
|
1184
|
+
transport: hasConfiguredMcpRemoteBridge() ? "stdio-bridge" : "direct-sse",
|
|
662
1185
|
serverName: init.serverInfo?.name ?? "unknown",
|
|
663
1186
|
serverVersion: init.serverInfo?.version ?? "unknown",
|
|
664
1187
|
toolsCount: tools.tools?.length ?? 0,
|
|
665
|
-
queryMode
|
|
1188
|
+
queryMode,
|
|
1189
|
+
callFailures,
|
|
666
1190
|
sampleText:
|
|
667
1191
|
evidence?.content?.find((item) => item.type === "text")?.text?.slice(0, 400) ?? null,
|
|
668
1192
|
};
|
|
669
|
-
|
|
1193
|
+
source.evidenceGrade = "VERIFIED";
|
|
1194
|
+
source.exactUpstreamMapping = source.repo;
|
|
1195
|
+
verificationSuccessCount += 1;
|
|
670
1196
|
} catch (error) {
|
|
671
1197
|
source.liveProbe = {
|
|
1198
|
+
transport: hasConfiguredMcpRemoteBridge() ? "stdio-bridge" : "direct-sse",
|
|
672
1199
|
error: error.message,
|
|
673
1200
|
};
|
|
1201
|
+
source.evidenceGrade = "PARTIAL";
|
|
1202
|
+
source.exactUpstreamMapping = source.repo;
|
|
674
1203
|
blockers.push(`Live MCP query failed for ${source.repo}: ${error.message}`);
|
|
675
1204
|
} finally {
|
|
676
1205
|
await client.close().catch(() => {});
|
|
@@ -681,8 +1210,7 @@ export async function runSage() {
|
|
|
681
1210
|
existing.items = sourceEntries;
|
|
682
1211
|
await writeJson(getRuntimeWritePath("evidence", "sources.json"), existing);
|
|
683
1212
|
|
|
684
|
-
const verified =
|
|
685
|
-
sourceEntries.length > 0 && !disableLiveProbe && liveSuccessCount === sourceEntries.length;
|
|
1213
|
+
const verified = sourceEntries.length > 0 && verificationSuccessCount === sourceEntries.length;
|
|
686
1214
|
if (sourceEntries.length > 0 && !verified && blockers.length === 0) {
|
|
687
1215
|
blockers.push(
|
|
688
1216
|
disableLiveProbe
|
|
@@ -694,7 +1222,8 @@ export async function runSage() {
|
|
|
694
1222
|
await appendDecision({
|
|
695
1223
|
kind: "skill",
|
|
696
1224
|
skill: "$sage",
|
|
697
|
-
decision:
|
|
1225
|
+
decision:
|
|
1226
|
+
"Bound architectural choices to approved sources using local core-source snapshots first, with GitMCP only as refresh/provenance fallback",
|
|
698
1227
|
status: verified ? "VERIFIED" : sourceEntries.length > 0 ? "PARTIAL" : "MISSING",
|
|
699
1228
|
evidence: sourceEntries,
|
|
700
1229
|
blockers: sourceEntries.length > 0 ? blockers : ["No approved GitMCP sources configured"],
|
|
@@ -704,6 +1233,17 @@ export async function runSage() {
|
|
|
704
1233
|
await syncStatusUpdates({
|
|
705
1234
|
evidence_status: verified ? "VERIFIED" : sourceEntries.length > 0 ? "PARTIAL" : "MISSING",
|
|
706
1235
|
});
|
|
1236
|
+
await updateScratchpadTrackForLane({
|
|
1237
|
+
gate: "$sage",
|
|
1238
|
+
trackStatus: verified ? "COMPLETED" : "BLOCKED",
|
|
1239
|
+
globalStatus: verified ? "COMPLETED" : "LOCKED",
|
|
1240
|
+
blockers: sourceEntries.length > 0 ? blockers : ["No approved GitMCP sources configured"],
|
|
1241
|
+
nextTriggers: verified ? ["$flow"] : ["$sage"],
|
|
1242
|
+
details: {
|
|
1243
|
+
evidence_grade: verified ? "VERIFIED" : sourceEntries.length > 0 ? "PARTIAL" : "MISSING",
|
|
1244
|
+
exact_upstream_mapping: sourceEntries.map((source) => source.repo),
|
|
1245
|
+
},
|
|
1246
|
+
});
|
|
707
1247
|
}
|
|
708
1248
|
|
|
709
1249
|
export async function runFlow() {
|
|
@@ -729,12 +1269,32 @@ export async function runFlow() {
|
|
|
729
1269
|
if (runtimeSummary.workerCount > 0 && runtimeSummary.workspaceCount === 0) {
|
|
730
1270
|
blockers.push("Workers exist without registered workspaces.");
|
|
731
1271
|
}
|
|
1272
|
+
const actors = ["leader", "worker", "guidance_stack", "hook_dispatcher", "workspace_manager"];
|
|
732
1273
|
const logicMap = {
|
|
733
|
-
actors
|
|
1274
|
+
actors,
|
|
1275
|
+
decision:
|
|
1276
|
+
blockers.length === 0
|
|
1277
|
+
? "Approve the current behavioral model for downstream review."
|
|
1278
|
+
: "Behavioral model remains blocked until the identified logic/runtime issues are resolved.",
|
|
1279
|
+
status: blockers.length === 0 ? "GREEN" : "RED",
|
|
734
1280
|
states: ["idea", "architecture", "evidence", "logic", "security", "experience", "build"],
|
|
1281
|
+
stateMap: [
|
|
1282
|
+
"idea -> architecture -> evidence -> logic -> security -> experience -> build",
|
|
1283
|
+
"logic review must stop if runtime artifacts are invalid or worker/workspace integrity breaks",
|
|
1284
|
+
],
|
|
1285
|
+
failureFlows:
|
|
1286
|
+
blockers.length > 0
|
|
1287
|
+
? blockers
|
|
1288
|
+
: ["No blocking failure flow detected in the current runtime snapshot."],
|
|
1289
|
+
evidence: [
|
|
1290
|
+
`actors observed: ${actors.length}`,
|
|
1291
|
+
`pending mailbox proposals: ${runtimeSummary.pendingMailboxCount}`,
|
|
1292
|
+
`registered workspaces: ${runtimeSummary.workspaceCount}`,
|
|
1293
|
+
],
|
|
735
1294
|
runtimeSummary,
|
|
736
1295
|
blockers,
|
|
737
1296
|
nextTrigger: blockers.length === 0 ? "`$vet`" : "`$flow`",
|
|
1297
|
+
nextAllowedTriggers: blockers.length === 0 ? ["`$vet`"] : ["`$flow`"],
|
|
738
1298
|
};
|
|
739
1299
|
const status = blockers.length === 0 ? "GREEN" : "RED";
|
|
740
1300
|
const nextAllowedTriggers = blockers.length === 0 ? ["$vet"] : ["$flow"];
|
|
@@ -752,6 +1312,18 @@ export async function runFlow() {
|
|
|
752
1312
|
});
|
|
753
1313
|
|
|
754
1314
|
await syncStatusUpdates({ logic_status: status });
|
|
1315
|
+
await updateScratchpadTrackForLane({
|
|
1316
|
+
gate: "$flow",
|
|
1317
|
+
trackStatus: status === "GREEN" ? "COMPLETED" : "BLOCKED",
|
|
1318
|
+
globalStatus: status === "GREEN" ? "COMPLETED" : "LOCKED",
|
|
1319
|
+
blockers,
|
|
1320
|
+
nextTriggers: nextAllowedTriggers,
|
|
1321
|
+
details: {
|
|
1322
|
+
failure_flows: logicMap.failureFlows,
|
|
1323
|
+
state_map: logicMap.stateMap,
|
|
1324
|
+
hardening_mode: runtimeSummary.pendingMailboxCount > 0 ? "STRICT" : "STANDARD",
|
|
1325
|
+
},
|
|
1326
|
+
});
|
|
755
1327
|
}
|
|
756
1328
|
|
|
757
1329
|
export async function runVet() {
|
|
@@ -760,36 +1332,103 @@ export async function runVet() {
|
|
|
760
1332
|
assertControlPlaneReady(runtimeSummary);
|
|
761
1333
|
const auditLog = await readJson(getRuntimeWritePath("evidence", "audits.json"));
|
|
762
1334
|
const cveLog = await readJson(getRuntimeWritePath("evidence", "cves.json"));
|
|
1335
|
+
const packageExposureFindings = await scanLockfilePackageExposure();
|
|
1336
|
+
const policyFindings = await validateMcpPolicyExposure();
|
|
1337
|
+
const criticalPackageExposure = packageExposureFindings.filter(
|
|
1338
|
+
(finding) => finding.severity === "critical",
|
|
1339
|
+
);
|
|
1340
|
+
const blockingPolicyFindings = policyFindings.filter((finding) =>
|
|
1341
|
+
["critical", "high"].includes(`${finding.severity}`.toLowerCase()),
|
|
1342
|
+
);
|
|
763
1343
|
const reviewApproved =
|
|
764
1344
|
auditLog.items.some((item) => item.source === "review" || item.approved === true) ||
|
|
765
1345
|
cveLog.items.some((item) => item.source === "review" || item.approved === true);
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
1346
|
+
const scanApproved = criticalPackageExposure.length === 0 && blockingPolicyFindings.length === 0;
|
|
1347
|
+
const finding =
|
|
1348
|
+
criticalPackageExposure.length > 0
|
|
1349
|
+
? {
|
|
1350
|
+
severity: criticalPackageExposure[0].severity.toUpperCase(),
|
|
1351
|
+
source: "package-exposure-scan",
|
|
1352
|
+
summary: criticalPackageExposure
|
|
1353
|
+
.map(
|
|
1354
|
+
(item) =>
|
|
1355
|
+
`${item.package_name}@${item.package_version}: ${item.diagnostic} (${item.advisory_reference})`,
|
|
1356
|
+
)
|
|
1357
|
+
.join(" "),
|
|
1358
|
+
unresolved: true,
|
|
1359
|
+
trustBoundaries: [
|
|
1360
|
+
"lockfile metadata vs provider-bound or build-unlocking execution",
|
|
1361
|
+
"repo-owned MCP config vs runtime-local scratchpad state",
|
|
1362
|
+
"published docs vs private `.ma` execution state",
|
|
1363
|
+
],
|
|
1364
|
+
acceptedRisks: ["No accepted risk: blocking package exposure must be remediated."],
|
|
1365
|
+
}
|
|
1366
|
+
: {
|
|
1367
|
+
severity: policyFindings.length > 0 ? "WARNING" : "INFO",
|
|
1368
|
+
source: policyFindings.length > 0 ? "mcp-policy-validation" : "runtime-review",
|
|
1369
|
+
summary:
|
|
1370
|
+
policyFindings.length > 0
|
|
1371
|
+
? policyFindings.map((item) => item.diagnostic).join(" ")
|
|
1372
|
+
: `No blocking package exposure was detected in the current bounded scan. Review still remains required after checking ${runtimeSummary.compatibilityHookCount} compatibility hooks and ${runtimeSummary.runtimeHookCount} runtime events.`,
|
|
1373
|
+
unresolved: !reviewApproved && !scanApproved,
|
|
1374
|
+
trustBoundaries: [
|
|
1375
|
+
"leader vs worker mutation authority",
|
|
1376
|
+
"repo-owned MCP config vs runtime-local scratchpad state",
|
|
1377
|
+
"published docs vs private `.ma` execution state",
|
|
1378
|
+
],
|
|
1379
|
+
acceptedRisks: scanApproved
|
|
1380
|
+
? ["No material unresolved risk remains for the current bounded step."]
|
|
1381
|
+
: [
|
|
1382
|
+
"Security evidence still requires explicit approval or remediation before promotion.",
|
|
1383
|
+
],
|
|
1384
|
+
};
|
|
1385
|
+
auditLog.items.push(finding, ...packageExposureFindings, ...policyFindings);
|
|
773
1386
|
await writeJson(getRuntimeWritePath("evidence", "audits.json"), auditLog);
|
|
774
|
-
cveLog.items.push(
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1387
|
+
cveLog.items.push(
|
|
1388
|
+
...packageExposureFindings.map((item) => ({
|
|
1389
|
+
id: item.advisory_reference ?? `${item.package_name}-${item.package_version}`,
|
|
1390
|
+
source: "package-exposure-scan",
|
|
1391
|
+
severity: item.severity.toUpperCase(),
|
|
1392
|
+
unresolved: true,
|
|
1393
|
+
package_name: item.package_name,
|
|
1394
|
+
package_version: item.package_version,
|
|
1395
|
+
})),
|
|
1396
|
+
{
|
|
1397
|
+
id: "baseline-review",
|
|
1398
|
+
source: packageExposureFindings.length > 0 ? "package-exposure-scan" : "runtime-review",
|
|
1399
|
+
severity: packageExposureFindings.length > 0 ? "CRITICAL" : "INFO",
|
|
1400
|
+
unresolved: !reviewApproved && !scanApproved,
|
|
1401
|
+
},
|
|
1402
|
+
);
|
|
780
1403
|
await writeJson(getRuntimeWritePath("evidence", "cves.json"), cveLog);
|
|
1404
|
+
for (const exposureFinding of packageExposureFindings) {
|
|
1405
|
+
await appendMaestroEvent(exposureFinding);
|
|
1406
|
+
}
|
|
1407
|
+
for (const policyFinding of policyFindings) {
|
|
1408
|
+
await appendMaestroEvent(policyFinding);
|
|
1409
|
+
}
|
|
781
1410
|
await writeSecuritySpec({
|
|
782
1411
|
finding,
|
|
783
1412
|
auditCount: auditLog.items.length,
|
|
784
1413
|
cveCount: cveLog.items.length,
|
|
785
1414
|
runtimeSummary,
|
|
786
|
-
nextTrigger:
|
|
1415
|
+
nextTrigger: scanApproved ? "`$vibe`" : "`$vet`",
|
|
787
1416
|
});
|
|
788
|
-
const status =
|
|
789
|
-
const blockers =
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
1417
|
+
const status = scanApproved ? "GREEN" : criticalPackageExposure.length > 0 ? "RED" : "PENDING";
|
|
1418
|
+
const blockers =
|
|
1419
|
+
criticalPackageExposure.length > 0
|
|
1420
|
+
? criticalPackageExposure.map(
|
|
1421
|
+
(item) =>
|
|
1422
|
+
`${item.package_name}@${item.package_version}: ${item.diagnostic} (${item.advisory_reference})`,
|
|
1423
|
+
)
|
|
1424
|
+
: reviewApproved
|
|
1425
|
+
? []
|
|
1426
|
+
: blockingPolicyFindings.map((finding) => finding.diagnostic);
|
|
1427
|
+
const nextAllowedTriggers = scanApproved
|
|
1428
|
+
? ["$vibe"]
|
|
1429
|
+
: criticalPackageExposure.length > 0
|
|
1430
|
+
? ["$vet"]
|
|
1431
|
+
: ["$vet"];
|
|
793
1432
|
|
|
794
1433
|
await appendDecision({
|
|
795
1434
|
kind: "skill",
|
|
@@ -802,6 +1441,25 @@ export async function runVet() {
|
|
|
802
1441
|
});
|
|
803
1442
|
|
|
804
1443
|
await syncStatusUpdates({ security_status: status });
|
|
1444
|
+
await updateScratchpadTrackForLane({
|
|
1445
|
+
gate: "$vet",
|
|
1446
|
+
trackStatus: status === "GREEN" ? "COMPLETED" : "BLOCKED",
|
|
1447
|
+
globalStatus:
|
|
1448
|
+
status === "GREEN" ? "COMPLETED" : status === "RED" ? "LOCKED" : "DEGRADED_HEALING",
|
|
1449
|
+
blockers,
|
|
1450
|
+
nextTriggers: nextAllowedTriggers,
|
|
1451
|
+
details: {
|
|
1452
|
+
trust_boundaries: finding.trustBoundaries,
|
|
1453
|
+
accepted_risks: finding.acceptedRisks,
|
|
1454
|
+
healing_ledger: reviewApproved
|
|
1455
|
+
? null
|
|
1456
|
+
: {
|
|
1457
|
+
current_attempt: 0,
|
|
1458
|
+
strategy_assigned: "BOUNDED_DIAGNOSTIC_REVIEW",
|
|
1459
|
+
status: "PENDING_OPERATOR_APPROVAL",
|
|
1460
|
+
},
|
|
1461
|
+
},
|
|
1462
|
+
});
|
|
805
1463
|
}
|
|
806
1464
|
|
|
807
1465
|
export async function runVibe() {
|
|
@@ -810,25 +1468,66 @@ export async function runVibe() {
|
|
|
810
1468
|
assertControlPlaneReady(runtimeSummary);
|
|
811
1469
|
const outcomes = await readJson(getRuntimeWritePath("evidence", "outcomes.json"));
|
|
812
1470
|
const reviewApproved = outcomes.items.some(
|
|
813
|
-
(item) =>
|
|
1471
|
+
(item) =>
|
|
1472
|
+
["review", "vibe-review", "dx-ux-review"].includes(item.source) && item.approved === true,
|
|
814
1473
|
);
|
|
1474
|
+
const automatedReviewChecks = [
|
|
1475
|
+
{
|
|
1476
|
+
name: "no_pending_mailbox_proposals",
|
|
1477
|
+
passed: runtimeSummary.pendingMailboxCount === 0,
|
|
1478
|
+
evidence: `${runtimeSummary.pendingMailboxCount} pending mailbox proposals`,
|
|
1479
|
+
},
|
|
1480
|
+
{
|
|
1481
|
+
name: "runtime_artifacts_valid",
|
|
1482
|
+
passed: runtimeSummary.invalidArtifacts.length === 0,
|
|
1483
|
+
evidence: `${runtimeSummary.invalidArtifacts.length} invalid runtime artifacts`,
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
name: "runtime_artifacts_present",
|
|
1487
|
+
passed: runtimeSummary.missingArtifacts.length === 0,
|
|
1488
|
+
evidence: `${runtimeSummary.missingArtifacts.length} missing runtime artifacts`,
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
name: "workspace_context_available",
|
|
1492
|
+
passed: runtimeSummary.workspaceCount > 0,
|
|
1493
|
+
evidence: `${runtimeSummary.workspaceCount} workspace context entries`,
|
|
1494
|
+
},
|
|
1495
|
+
];
|
|
1496
|
+
const runtimeApproved = automatedReviewChecks.every((check) => check.passed);
|
|
1497
|
+
const failedAutomatedReviewChecks = automatedReviewChecks
|
|
1498
|
+
.filter((check) => !check.passed)
|
|
1499
|
+
.map((check) => `${check.name}: ${check.evidence}`);
|
|
815
1500
|
const note = {
|
|
816
1501
|
area: "developer-experience",
|
|
817
|
-
source: "
|
|
818
|
-
summary: `
|
|
1502
|
+
source: "runtime-vibe-review",
|
|
1503
|
+
summary: `Runtime DX/UX review recorded from current coordination state: ${runtimeSummary.taskCount} tasks, ${runtimeSummary.workspaceCount} workspaces, and ${runtimeSummary.pendingMailboxCount} pending mailbox proposals.`,
|
|
1504
|
+
automatedReviewChecks,
|
|
1505
|
+
operatorFriction: [
|
|
1506
|
+
runtimeSummary.pendingMailboxCount > 0
|
|
1507
|
+
? "Pending mailbox proposals increase operator coordination overhead."
|
|
1508
|
+
: "Operator flow is bounded and clear in the current runtime state.",
|
|
1509
|
+
],
|
|
1510
|
+
userFriction: [
|
|
1511
|
+
"The gated sequence is explicit, but users still need clearer build-loop feedback once execution starts.",
|
|
1512
|
+
],
|
|
1513
|
+
approved: reviewApproved || runtimeApproved,
|
|
819
1514
|
};
|
|
820
1515
|
outcomes.items.push(note);
|
|
821
1516
|
await writeJson(getRuntimeWritePath("evidence", "outcomes.json"), outcomes);
|
|
822
|
-
const status = reviewApproved ? "GREEN" : "PENDING";
|
|
823
|
-
const blockers =
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
1517
|
+
const status = reviewApproved || runtimeApproved ? "GREEN" : "PENDING";
|
|
1518
|
+
const blockers =
|
|
1519
|
+
status === "GREEN"
|
|
1520
|
+
? []
|
|
1521
|
+
: [
|
|
1522
|
+
"Automated DX/UX review must pass all runtime evidence checks or receive explicit review approval.",
|
|
1523
|
+
...failedAutomatedReviewChecks,
|
|
1524
|
+
];
|
|
1525
|
+
const nextAllowedTriggers = status === "GREEN" ? ["$build"] : ["$vibe"];
|
|
827
1526
|
await writeExperienceSpec({
|
|
828
1527
|
note,
|
|
829
1528
|
outcomeCount: outcomes.items.length,
|
|
830
1529
|
runtimeSummary,
|
|
831
|
-
nextTrigger:
|
|
1530
|
+
nextTrigger: status === "GREEN" ? "`$build`" : "`$vibe`",
|
|
832
1531
|
});
|
|
833
1532
|
|
|
834
1533
|
await appendDecision({
|
|
@@ -842,10 +1541,65 @@ export async function runVibe() {
|
|
|
842
1541
|
});
|
|
843
1542
|
|
|
844
1543
|
await syncStatusUpdates({ experience_status: status });
|
|
1544
|
+
await updateScratchpadTrackForLane({
|
|
1545
|
+
gate: "$vibe",
|
|
1546
|
+
trackStatus: status === "GREEN" ? "COMPLETED" : "BLOCKED",
|
|
1547
|
+
globalStatus: status === "GREEN" ? "COMPLETED" : "LOCKED",
|
|
1548
|
+
blockers,
|
|
1549
|
+
nextTriggers: nextAllowedTriggers,
|
|
1550
|
+
details: {
|
|
1551
|
+
operator_friction: note.operatorFriction,
|
|
1552
|
+
user_friction: note.userFriction,
|
|
1553
|
+
},
|
|
1554
|
+
});
|
|
845
1555
|
}
|
|
846
1556
|
|
|
847
|
-
export async function runMaestro(
|
|
1557
|
+
export async function runMaestro({
|
|
1558
|
+
autoHeal = false,
|
|
1559
|
+
parallel = false,
|
|
1560
|
+
taskContract = {},
|
|
1561
|
+
handoff = {},
|
|
1562
|
+
} = {}) {
|
|
848
1563
|
await assertLeaderAuthority();
|
|
1564
|
+
const intakeContract = createTaskContract({
|
|
1565
|
+
goal: taskContract.goal ?? "Execute the next eligible Meta-Architect workflow step",
|
|
1566
|
+
contextUsed: taskContract.contextUsed ?? [
|
|
1567
|
+
".ma/context/project-index.json",
|
|
1568
|
+
".ma/context/agent-brief.md",
|
|
1569
|
+
],
|
|
1570
|
+
assumptions: taskContract.assumptions ?? [
|
|
1571
|
+
"Source files and fresh verification output outrank generated context",
|
|
1572
|
+
],
|
|
1573
|
+
constraints: taskContract.constraints ?? [
|
|
1574
|
+
"Do not mutate release state outside the owning lane",
|
|
1575
|
+
],
|
|
1576
|
+
risk: taskContract.risk ?? "medium",
|
|
1577
|
+
verification: taskContract.verification ?? ["ma doctor", "focused tests"],
|
|
1578
|
+
stopCondition:
|
|
1579
|
+
taskContract.stopCondition ??
|
|
1580
|
+
"Stop when the selected lane is complete, blocked, or requires review",
|
|
1581
|
+
persist: taskContract.persist !== false,
|
|
1582
|
+
});
|
|
1583
|
+
if (intakeContract.persist) {
|
|
1584
|
+
await writeTaskContract(`maestro-${Date.now()}`, intakeContract);
|
|
1585
|
+
}
|
|
1586
|
+
if (handoff.persist !== false) {
|
|
1587
|
+
await writeHandoffPacket(
|
|
1588
|
+
`maestro-${Date.now()}`,
|
|
1589
|
+
createHandoffPacket({
|
|
1590
|
+
goal: intakeContract.goal,
|
|
1591
|
+
currentState: "Manager intake accepted",
|
|
1592
|
+
contextUsed: intakeContract.context_used,
|
|
1593
|
+
decisions: handoff.decisions ?? [],
|
|
1594
|
+
blockers: handoff.blockers ?? [],
|
|
1595
|
+
risks: handoff.risks ?? [],
|
|
1596
|
+
changedFiles: handoff.changedFiles ?? [],
|
|
1597
|
+
verification: intakeContract.verification,
|
|
1598
|
+
nextAction: handoff.nextAction ?? "Continue the selected bounded workflow lane",
|
|
1599
|
+
status: handoff.status ?? "active",
|
|
1600
|
+
}),
|
|
1601
|
+
);
|
|
1602
|
+
}
|
|
849
1603
|
let runtimeSnapshot = await loadRuntimeSnapshot();
|
|
850
1604
|
let releaseState = runtimeSnapshot.release;
|
|
851
1605
|
let runtimeSummary = createRuntimeSummary(runtimeSnapshot);
|
|
@@ -854,6 +1608,133 @@ export async function runMaestro() {
|
|
|
854
1608
|
let buildReadiness = evaluateRuntimeBuildReadiness(releaseState, runtimeSummary);
|
|
855
1609
|
let recommendation = chooseMaestroRecommendation(releaseState, idea, buildReadiness);
|
|
856
1610
|
const helperFailureMatrix = buildHelperFailureMatrix();
|
|
1611
|
+
const alignmentReport = {
|
|
1612
|
+
...evaluateAlignmentDrift({
|
|
1613
|
+
releaseState,
|
|
1614
|
+
decisionLog: runtimeSnapshot.decisions,
|
|
1615
|
+
}),
|
|
1616
|
+
lastRunAt: new Date().toISOString(),
|
|
1617
|
+
baselineArtifacts: [
|
|
1618
|
+
".ma/release.json",
|
|
1619
|
+
".ma/decisions.json",
|
|
1620
|
+
".ma/state/manager-runs.json",
|
|
1621
|
+
".ma/state/maestro-state.json",
|
|
1622
|
+
],
|
|
1623
|
+
};
|
|
1624
|
+
await saveAlignmentSentinelReport(alignmentReport);
|
|
1625
|
+
if (alignmentReport.driftStatus === "DRIFTED") {
|
|
1626
|
+
await updateScratchpadTrackForLane({
|
|
1627
|
+
gate: "$maestro",
|
|
1628
|
+
trackStatus: "BLOCKED",
|
|
1629
|
+
globalStatus: "LOCKED",
|
|
1630
|
+
blockers: alignmentReport.findings.map(
|
|
1631
|
+
(finding) =>
|
|
1632
|
+
`${finding.skill} expects ${finding.releaseField} to remain in ${finding.expectedReleaseValues.join(" or ")}, but the current value is ${finding.actualReleaseValue}.`,
|
|
1633
|
+
),
|
|
1634
|
+
nextTriggers: ["$maestro"],
|
|
1635
|
+
details: {
|
|
1636
|
+
drift_status: alignmentReport.driftStatus,
|
|
1637
|
+
reboot_planned: alignmentReport.rebootPlanned,
|
|
1638
|
+
resume_trigger: alignmentReport.resumeTrigger,
|
|
1639
|
+
},
|
|
1640
|
+
});
|
|
1641
|
+
await appendMaestroEvent({
|
|
1642
|
+
record_type: "alignment:drift_detected",
|
|
1643
|
+
gate: "$maestro",
|
|
1644
|
+
findings: alignmentReport.findings,
|
|
1645
|
+
reboot_planned: alignmentReport.rebootPlanned,
|
|
1646
|
+
resume_trigger: alignmentReport.resumeTrigger,
|
|
1647
|
+
});
|
|
1648
|
+
const driftRecommendation = {
|
|
1649
|
+
nextStep: "Resolve alignment drift before manager dispatch continues.",
|
|
1650
|
+
why: alignmentReport.rebootReason,
|
|
1651
|
+
primaryLane: "$maestro",
|
|
1652
|
+
supportLane: "none",
|
|
1653
|
+
assignments: [
|
|
1654
|
+
"Review the persisted alignment report and conflicting lane-owned decisions.",
|
|
1655
|
+
"Rehydrate the next manager run from baseline `.ma/` artifacts after the conflicting state is repaired.",
|
|
1656
|
+
],
|
|
1657
|
+
avoid: [
|
|
1658
|
+
"Do not continue autonomous dispatch while release state contradicts approved lane decisions.",
|
|
1659
|
+
],
|
|
1660
|
+
nextTrigger: "`$maestro`",
|
|
1661
|
+
};
|
|
1662
|
+
await writeMaestroPlan({
|
|
1663
|
+
releaseState,
|
|
1664
|
+
recommendation: driftRecommendation,
|
|
1665
|
+
runtimeSummary,
|
|
1666
|
+
workflowSequence: maestroWorkflowSequence,
|
|
1667
|
+
managerRun: null,
|
|
1668
|
+
});
|
|
1669
|
+
await appendDecision({
|
|
1670
|
+
kind: "skill",
|
|
1671
|
+
skill: "$maestro",
|
|
1672
|
+
decision:
|
|
1673
|
+
"Alignment Sentinel blocked manager execution and requested a fresh worker rehydration path.",
|
|
1674
|
+
status: "BLOCKED",
|
|
1675
|
+
evidence: [alignmentReport],
|
|
1676
|
+
blockers: alignmentReport.findings.map(
|
|
1677
|
+
(finding) =>
|
|
1678
|
+
`${finding.skill} approved ${finding.expectedDecisionStatus}, but ${finding.releaseField} regressed to ${finding.actualReleaseValue}.`,
|
|
1679
|
+
),
|
|
1680
|
+
next_allowed_triggers: ["$maestro"],
|
|
1681
|
+
});
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
if (
|
|
1685
|
+
autoHeal &&
|
|
1686
|
+
buildReadiness.releaseBlockers.length === 0 &&
|
|
1687
|
+
buildReadiness.nextTriggers.includes("repair runtime artifacts")
|
|
1688
|
+
) {
|
|
1689
|
+
const repairedArtifacts = await repairRuntimeScratchpadArtifacts([
|
|
1690
|
+
...runtimeSummary.invalidArtifacts,
|
|
1691
|
+
...runtimeSummary.missingArtifacts,
|
|
1692
|
+
]);
|
|
1693
|
+
if (repairedArtifacts.length > 0) {
|
|
1694
|
+
const detached = await launchDetachedTrack({
|
|
1695
|
+
trackId: "heal-sync",
|
|
1696
|
+
title: "Meta-Architect bounded diagnostic sidecar",
|
|
1697
|
+
command: "/bin/sh",
|
|
1698
|
+
args: [
|
|
1699
|
+
"-lc",
|
|
1700
|
+
`printf '%s\n' "Repaired scratchpad artifacts: ${repairedArtifacts.join(", ")}"`,
|
|
1701
|
+
],
|
|
1702
|
+
});
|
|
1703
|
+
let maestroState = await loadMaestroStateOrDefault();
|
|
1704
|
+
maestroState = beginMaestroOrchestration(maestroState, {
|
|
1705
|
+
globalStatus: "DEGRADED_HEALING",
|
|
1706
|
+
configuration: {
|
|
1707
|
+
auto_heal: true,
|
|
1708
|
+
concurrency_limit: parallel ? 4 : 1,
|
|
1709
|
+
},
|
|
1710
|
+
});
|
|
1711
|
+
maestroState.runtime_tracks.track_heal_sync = {
|
|
1712
|
+
active_gate: "$maestro",
|
|
1713
|
+
status: "COMPLETED",
|
|
1714
|
+
pid: null,
|
|
1715
|
+
execution_pane: detached.executionPane,
|
|
1716
|
+
provider: detached.provider,
|
|
1717
|
+
log_path: detached.logPath,
|
|
1718
|
+
exit_code: 0,
|
|
1719
|
+
repaired_artifacts: repairedArtifacts,
|
|
1720
|
+
updated_at: new Date().toISOString(),
|
|
1721
|
+
};
|
|
1722
|
+
await saveMaestroState(maestroState);
|
|
1723
|
+
await appendMaestroEvent({
|
|
1724
|
+
record_type: "healing:attempt",
|
|
1725
|
+
gate: "$maestro",
|
|
1726
|
+
global_status: "DEGRADED_HEALING",
|
|
1727
|
+
track_status: "COMPLETED",
|
|
1728
|
+
repaired_artifacts: repairedArtifacts,
|
|
1729
|
+
repaired_count: repairedArtifacts.length,
|
|
1730
|
+
});
|
|
1731
|
+
runtimeSnapshot = await loadRuntimeSnapshot();
|
|
1732
|
+
releaseState = runtimeSnapshot.release;
|
|
1733
|
+
runtimeSummary = createRuntimeSummary(runtimeSnapshot);
|
|
1734
|
+
buildReadiness = evaluateRuntimeBuildReadiness(releaseState, runtimeSummary);
|
|
1735
|
+
recommendation = chooseMaestroRecommendation(releaseState, idea, buildReadiness);
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
857
1738
|
const registry = await loadManagerRunRegistry();
|
|
858
1739
|
const activeRun = getActiveManagerRun(registry);
|
|
859
1740
|
const managerAction = chooseMaestroManagerAction({
|
|
@@ -927,9 +1808,28 @@ export async function runMaestro() {
|
|
|
927
1808
|
continue;
|
|
928
1809
|
}
|
|
929
1810
|
|
|
1811
|
+
const detached =
|
|
1812
|
+
parallel && ["$flow", "$vet", "$vibe", "$build"].includes(gate.skill)
|
|
1813
|
+
? await launchDetachedTrack({
|
|
1814
|
+
trackId: `${managerRun.id}-${gate.skill.replaceAll("$", "")}`,
|
|
1815
|
+
title: `Meta-Architect detached track ${gate.skill}`,
|
|
1816
|
+
command: "/bin/sh",
|
|
1817
|
+
args: ["-lc", `printf '%s\n' "Detached scratchpad track for ${gate.skill}"`],
|
|
1818
|
+
})
|
|
1819
|
+
: null;
|
|
930
1820
|
gate.status = "running";
|
|
931
1821
|
updateManagerRunTimestamps(managerRun, { state: "running" });
|
|
932
1822
|
await saveManagerRunRegistry(registry);
|
|
1823
|
+
await updateScratchpadTrackForLane({
|
|
1824
|
+
gate: gate.skill,
|
|
1825
|
+
trackStatus: "RUNNING",
|
|
1826
|
+
globalStatus: "RUNNING",
|
|
1827
|
+
nextTriggers: [gate.skill],
|
|
1828
|
+
detached,
|
|
1829
|
+
details: {
|
|
1830
|
+
objective: gate.objective,
|
|
1831
|
+
},
|
|
1832
|
+
});
|
|
933
1833
|
await runner();
|
|
934
1834
|
gate.status = "completed";
|
|
935
1835
|
await saveManagerRunRegistry(registry);
|
|
@@ -964,18 +1864,6 @@ export async function runMaestro() {
|
|
|
964
1864
|
await saveManagerRunRegistry(registry);
|
|
965
1865
|
}
|
|
966
1866
|
|
|
967
|
-
if (
|
|
968
|
-
buildReadiness.nextTriggers.includes("$build") ||
|
|
969
|
-
buildReadiness.nextTriggers.includes("repair runtime artifacts")
|
|
970
|
-
) {
|
|
971
|
-
await writeBuildPlanArtifact({
|
|
972
|
-
allowed: buildReadiness.allowed,
|
|
973
|
-
blockers: buildReadiness.blockers,
|
|
974
|
-
nextTriggers: buildReadiness.nextTriggers,
|
|
975
|
-
runtimeSummary,
|
|
976
|
-
});
|
|
977
|
-
}
|
|
978
|
-
|
|
979
1867
|
await writeMaestroPlan({
|
|
980
1868
|
releaseState,
|
|
981
1869
|
recommendation,
|
|
@@ -995,8 +1883,18 @@ export async function runMaestro() {
|
|
|
995
1883
|
});
|
|
996
1884
|
}
|
|
997
1885
|
|
|
998
|
-
|
|
999
|
-
|
|
1886
|
+
async function runInitUnlocked({
|
|
1887
|
+
refresh = false,
|
|
1888
|
+
obsidianVault = process.env.MA_OBSIDIAN_VAULT,
|
|
1889
|
+
} = {}) {
|
|
1890
|
+
const repoRoot = getRepoRoot();
|
|
1891
|
+
const migrations = await migrateSchemas(repoRoot);
|
|
1892
|
+
const managedBefore = await listManagedArtifacts(repoRoot);
|
|
1893
|
+
const report = {
|
|
1894
|
+
directories: [],
|
|
1895
|
+
files: [],
|
|
1896
|
+
migrations,
|
|
1897
|
+
};
|
|
1000
1898
|
const targets = [
|
|
1001
1899
|
".codex/agents",
|
|
1002
1900
|
".codex/prompts",
|
|
@@ -1011,6 +1909,7 @@ export async function runInit() {
|
|
|
1011
1909
|
".ma/context",
|
|
1012
1910
|
".ma/specs",
|
|
1013
1911
|
".ma/plans",
|
|
1912
|
+
"scripts",
|
|
1014
1913
|
"mcp",
|
|
1015
1914
|
"docs",
|
|
1016
1915
|
"docs/qa",
|
|
@@ -1019,8 +1918,14 @@ export async function runInit() {
|
|
|
1019
1918
|
|
|
1020
1919
|
for (const relative of targets) {
|
|
1021
1920
|
const target = path.join(getRepoRoot(), relative);
|
|
1921
|
+
const existed = await pathExists(target);
|
|
1922
|
+
await assertNoSymlinkComponents(getRepoRoot(), target);
|
|
1022
1923
|
await fs.mkdir(target, { recursive: true });
|
|
1023
|
-
|
|
1924
|
+
report.directories.push({
|
|
1925
|
+
path: relative,
|
|
1926
|
+
kind: "directory",
|
|
1927
|
+
status: existed ? "existing" : "created",
|
|
1928
|
+
});
|
|
1024
1929
|
}
|
|
1025
1930
|
|
|
1026
1931
|
const templateCopies = [
|
|
@@ -1068,6 +1973,14 @@ export async function runInit() {
|
|
|
1068
1973
|
path.join(packageRoot, ".codex", "prompts", "onboarding.md"),
|
|
1069
1974
|
path.join(getRepoRoot(), ".codex", "prompts", "onboarding.md"),
|
|
1070
1975
|
],
|
|
1976
|
+
[
|
|
1977
|
+
path.join(packageRoot, "scripts", "active-autonomy-hook.mjs"),
|
|
1978
|
+
path.join(getRepoRoot(), "scripts", "active-autonomy-hook.mjs"),
|
|
1979
|
+
],
|
|
1980
|
+
[
|
|
1981
|
+
path.join(packageRoot, "scripts", "context-hydration-hook.mjs"),
|
|
1982
|
+
path.join(getRepoRoot(), "scripts", "context-hydration-hook.mjs"),
|
|
1983
|
+
],
|
|
1071
1984
|
[path.join(packageRoot, "docs", "README.md"), path.join(getRepoRoot(), "docs", "README.md")],
|
|
1072
1985
|
[
|
|
1073
1986
|
path.join(packageRoot, "docs", "getting-started.md"),
|
|
@@ -1083,8 +1996,16 @@ export async function runInit() {
|
|
|
1083
1996
|
path.join(getRepoRoot(), "docs", "release-spec.md"),
|
|
1084
1997
|
],
|
|
1085
1998
|
[
|
|
1086
|
-
|
|
1087
|
-
|
|
1999
|
+
resolveReleaseReadiness(packageRoot)?.path ??
|
|
2000
|
+
path.join(packageRoot, "docs", "qa", "release-readiness-missing.md"),
|
|
2001
|
+
resolveReleaseReadiness(getRepoRoot())?.path ??
|
|
2002
|
+
path.join(getRepoRoot(), "docs", "qa", "release-readiness-missing.md"),
|
|
2003
|
+
],
|
|
2004
|
+
[
|
|
2005
|
+
resolveReleaseIssueGates(packageRoot)?.path ??
|
|
2006
|
+
path.join(packageRoot, "docs", "qa", "release-issue-gates-missing.json"),
|
|
2007
|
+
resolveReleaseIssueGates(getRepoRoot())?.path ??
|
|
2008
|
+
path.join(getRepoRoot(), "docs", "qa", "release-issue-gates-missing.json"),
|
|
1088
2009
|
],
|
|
1089
2010
|
];
|
|
1090
2011
|
|
|
@@ -1119,14 +2040,46 @@ export async function runInit() {
|
|
|
1119
2040
|
}
|
|
1120
2041
|
|
|
1121
2042
|
for (const [src, dest] of templateCopies) {
|
|
1122
|
-
|
|
1123
|
-
await fs.access(dest);
|
|
1124
|
-
} catch {
|
|
1125
|
-
await fs.copyFile(src, dest);
|
|
1126
|
-
}
|
|
2043
|
+
report.files.push(await syncTemplateFile(src, dest, { refresh }));
|
|
1127
2044
|
}
|
|
1128
2045
|
|
|
1129
2046
|
await seedRuntimeArtifacts();
|
|
2047
|
+
const projectIndex = await refreshProjectIndex(repoRoot);
|
|
2048
|
+
report.context = {
|
|
2049
|
+
path: path.relative(repoRoot, getRuntimeWritePath("context", "project-index.json")),
|
|
2050
|
+
status: projectIndex.quality.confidence,
|
|
2051
|
+
completeness: projectIndex.quality.completeness,
|
|
2052
|
+
detected: {
|
|
2053
|
+
languages: projectIndex.languages,
|
|
2054
|
+
frameworks: projectIndex.frameworks,
|
|
2055
|
+
packageManager: projectIndex.packageManager,
|
|
2056
|
+
commands: projectIndex.commands,
|
|
2057
|
+
entrypoints: projectIndex.entrypoints,
|
|
2058
|
+
importantDocs: projectIndex.importantDocs,
|
|
2059
|
+
vendorIntegrations: projectIndex.vendorIntegrations,
|
|
2060
|
+
},
|
|
2061
|
+
unknown: projectIndex.quality.gaps,
|
|
2062
|
+
};
|
|
2063
|
+
|
|
2064
|
+
if (obsidianVault) {
|
|
2065
|
+
const embedded = await embedProjectContext({
|
|
2066
|
+
vaultPath: obsidianVault,
|
|
2067
|
+
projectIndex,
|
|
2068
|
+
});
|
|
2069
|
+
report.integrations = report.integrations ?? [];
|
|
2070
|
+
report.integrations.push({
|
|
2071
|
+
kind: "obsidian",
|
|
2072
|
+
status: embedded.noteStatus,
|
|
2073
|
+
vaultPath: embedded.vaultPath,
|
|
2074
|
+
notePath: embedded.notePath,
|
|
2075
|
+
indexPath: path.relative(
|
|
2076
|
+
repoRoot,
|
|
2077
|
+
getRuntimeWritePath("context", "obsidian-vault-index.json"),
|
|
2078
|
+
),
|
|
2079
|
+
records_as: "vault_context",
|
|
2080
|
+
build_evidence: false,
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
1130
2083
|
|
|
1131
2084
|
await writeFileIfMissing(
|
|
1132
2085
|
getRuntimeWritePath("decisions.json"),
|
|
@@ -1251,5 +2204,122 @@ export async function runInit() {
|
|
|
1251
2204
|
"# Onboarding\n\nMeta-Architect initializes the core scaffold, MCP config, and canonical .ma runtime files.\n",
|
|
1252
2205
|
);
|
|
1253
2206
|
|
|
1254
|
-
|
|
2207
|
+
const reported = new Set([
|
|
2208
|
+
...report.directories.map((entry) => entry.path),
|
|
2209
|
+
...report.files.map((entry) => entry.path),
|
|
2210
|
+
]);
|
|
2211
|
+
const managedAfter = await listManagedArtifacts(repoRoot);
|
|
2212
|
+
for (const [relative, kind] of managedAfter) {
|
|
2213
|
+
if (!managedBefore.has(relative) && !reported.has(relative)) {
|
|
2214
|
+
report.files.push({ path: relative, kind, status: "created" });
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
report.onboarding = {
|
|
2219
|
+
context: ".ma/context/project-index.json",
|
|
2220
|
+
future_agents_read: [
|
|
2221
|
+
".ma/context/agent-brief.md",
|
|
2222
|
+
".ma/context/project-index.json",
|
|
2223
|
+
"AGENTS.md",
|
|
2224
|
+
],
|
|
2225
|
+
integrations: {
|
|
2226
|
+
obsidian: report.integrations?.[0]?.status ?? "not configured",
|
|
2227
|
+
mcp: "local read-only context resources",
|
|
2228
|
+
hooks: ".codex/hooks.json",
|
|
2229
|
+
},
|
|
2230
|
+
freshness: report.context?.status ?? "unknown",
|
|
2231
|
+
next: ["ma doctor", "ma context refresh", "ma setup --rollback"],
|
|
2232
|
+
};
|
|
2233
|
+
|
|
2234
|
+
return report;
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
export async function runInit(options = {}) {
|
|
2238
|
+
const repoRoot = getRepoRoot();
|
|
2239
|
+
return withSetupLock(repoRoot, async () => {
|
|
2240
|
+
await assertSetupReceiptHealthy(repoRoot);
|
|
2241
|
+
const managedBefore = await listManagedArtifacts(repoRoot);
|
|
2242
|
+
let report;
|
|
2243
|
+
try {
|
|
2244
|
+
report = await runInitUnlocked(options);
|
|
2245
|
+
} catch (error) {
|
|
2246
|
+
const managedAfter = await listManagedArtifacts(repoRoot);
|
|
2247
|
+
const partialFiles = [...managedAfter]
|
|
2248
|
+
.filter(([relative]) => !managedBefore.has(relative))
|
|
2249
|
+
.map(([relative, kind]) => ({
|
|
2250
|
+
path: relative,
|
|
2251
|
+
kind,
|
|
2252
|
+
status: "created",
|
|
2253
|
+
}));
|
|
2254
|
+
try {
|
|
2255
|
+
await writeSetupReceipt(repoRoot, { files: partialFiles });
|
|
2256
|
+
} catch (receiptError) {
|
|
2257
|
+
error.message = `${error.message}; failed to persist partial setup receipt: ${receiptError.message}`;
|
|
2258
|
+
}
|
|
2259
|
+
throw error;
|
|
2260
|
+
}
|
|
2261
|
+
const receipt = await writeSetupReceipt(repoRoot, report);
|
|
2262
|
+
await compactRuntimeState(repoRoot);
|
|
2263
|
+
report.files.push({ ...receipt, kind: "file", status: "refreshed" });
|
|
2264
|
+
return report;
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
async function syncTemplateFile(src, dest, { refresh = false } = {}) {
|
|
2269
|
+
const relativePath = path.relative(getRepoRoot(), dest);
|
|
2270
|
+
try {
|
|
2271
|
+
const [sourceContent, destContent] = await Promise.all([
|
|
2272
|
+
fs.readFile(src, "utf8"),
|
|
2273
|
+
fs.readFile(dest, "utf8").catch((error) => {
|
|
2274
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
2275
|
+
return null;
|
|
2276
|
+
}
|
|
2277
|
+
throw error;
|
|
2278
|
+
}),
|
|
2279
|
+
]);
|
|
2280
|
+
|
|
2281
|
+
if (destContent === null) {
|
|
2282
|
+
await writeTextAtomically(dest, sourceContent);
|
|
2283
|
+
return {
|
|
2284
|
+
path: relativePath,
|
|
2285
|
+
kind: "file",
|
|
2286
|
+
status: "created",
|
|
2287
|
+
};
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
if (destContent !== sourceContent && refresh) {
|
|
2291
|
+
await writeTextAtomically(dest, sourceContent);
|
|
2292
|
+
return {
|
|
2293
|
+
path: relativePath,
|
|
2294
|
+
kind: "file",
|
|
2295
|
+
status: "refreshed",
|
|
2296
|
+
};
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
if (destContent !== sourceContent) {
|
|
2300
|
+
return {
|
|
2301
|
+
path: relativePath,
|
|
2302
|
+
kind: "file",
|
|
2303
|
+
status: "skipped",
|
|
2304
|
+
warning: "existing file differs; rerun with --refresh to update it",
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
|
|
2308
|
+
return {
|
|
2309
|
+
path: relativePath,
|
|
2310
|
+
kind: "file",
|
|
2311
|
+
status: "existing",
|
|
2312
|
+
};
|
|
2313
|
+
} catch (error) {
|
|
2314
|
+
throw new Error(`Unable to sync managed template ${relativePath}`, { cause: error });
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2318
|
+
async function pathExists(target) {
|
|
2319
|
+
try {
|
|
2320
|
+
await fs.access(target);
|
|
2321
|
+
return true;
|
|
2322
|
+
} catch {
|
|
2323
|
+
return false;
|
|
2324
|
+
}
|
|
1255
2325
|
}
|