@jstn-sdk/ma 0.1.13 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/.agents/plugins/marketplace.json +0 -0
  2. package/.codex/agents/Architect.toml +1 -0
  3. package/.codex/agents/Auditor.toml +1 -0
  4. package/.codex/agents/Builder.toml +1 -0
  5. package/.codex/agents/Flow.toml +1 -0
  6. package/.codex/agents/Sage.toml +1 -0
  7. package/.codex/agents/Vibe.toml +1 -0
  8. package/.codex/hooks.json +12 -2
  9. package/.codex/prompts/enforcement.md +0 -0
  10. package/.codex/prompts/onboarding.md +6 -1
  11. package/.codex/prompts/release-rules.md +0 -0
  12. package/.codex/prompts/skill-contract.md +0 -0
  13. package/COVERAGE.md +9 -9
  14. package/DEMO.md +15 -6
  15. package/LICENSE +0 -0
  16. package/README.md +127 -784
  17. package/bin/ma.js +591 -105
  18. package/data/clone-data.ledger.json +0 -0
  19. package/data/clone-data.proof.json +0 -0
  20. package/data/clone-data.rvf +0 -0
  21. package/docs/README.md +8 -2
  22. package/docs/assets/banner.png +0 -0
  23. package/docs/autonomous-tasks.md +46 -0
  24. package/docs/codex-integration.md +16 -0
  25. package/docs/getting-started.md +32 -8
  26. package/docs/installed-sdk.md +0 -0
  27. package/docs/mcp-setup.md +30 -1
  28. package/docs/qa/{release-issue-gates-0.1.13.json → release-issue-gates-0.14.1.json} +77 -77
  29. package/docs/qa/release-readiness-0.1.5.md +0 -0
  30. package/docs/qa/{release-readiness-0.1.13.md → release-readiness-0.14.1.md} +12 -12
  31. package/docs/quality.md +24 -0
  32. package/docs/reference/native-engineering-patterns.md +0 -0
  33. package/docs/reference/native-security-playbooks.md +0 -0
  34. package/docs/reference/native-source-selection.md +0 -0
  35. package/docs/reference/native-style-and-deslop.md +0 -0
  36. package/docs/release-spec.md +27 -14
  37. package/docs/skills.md +1 -1
  38. package/docs/vendor-plugin-publishing.md +49 -0
  39. package/index.js +73 -0
  40. package/mcp/collections.json +0 -0
  41. package/mcp/fallback.json +0 -0
  42. package/mcp/local/code-intel.js +185 -41
  43. package/mcp/local/context.js +180 -0
  44. package/mcp/local/memory.js +17 -6
  45. package/mcp/local/playbooks.js +0 -0
  46. package/mcp/local/quality.js +39 -0
  47. package/mcp/local/state.js +7 -3
  48. package/mcp/local/team-run.js +8 -3
  49. package/mcp/local/trace.js +0 -0
  50. package/mcp/local-capabilities.json +9 -0
  51. package/mcp/native-playbooks.json +0 -0
  52. package/mcp/servers.json +0 -0
  53. package/package.json +37 -6
  54. package/plugins/meta-architect/.app.json +1 -1
  55. package/plugins/meta-architect/.claude-plugin/plugin.json +12 -0
  56. package/plugins/meta-architect/.codex-plugin/plugin.json +1 -1
  57. package/plugins/meta-architect/.mcp.json +1 -1
  58. package/plugins/meta-architect/README.md +14 -2
  59. package/plugins/meta-architect/obsidian/main.js +137 -4
  60. package/plugins/meta-architect/obsidian/manifest.json +1 -1
  61. package/plugins/meta-architect/obsidian/styles.css +0 -0
  62. package/plugins/meta-architect/skills/align/SKILL.md +0 -0
  63. package/plugins/meta-architect/skills/align/agents/openai.yaml +0 -0
  64. package/plugins/meta-architect/skills/align/references/shared-language.md +0 -0
  65. package/plugins/meta-architect/skills/arch/SKILL.md +0 -0
  66. package/plugins/meta-architect/skills/arch/agents/openai.yaml +0 -0
  67. package/plugins/meta-architect/skills/build/SKILL.md +0 -0
  68. package/plugins/meta-architect/skills/build/agents/openai.yaml +0 -0
  69. package/plugins/meta-architect/skills/cleanup/SKILL.md +0 -0
  70. package/plugins/meta-architect/skills/cleanup/agents/openai.yaml +0 -0
  71. package/plugins/meta-architect/skills/cleanup/references/style-and-deslop.md +0 -0
  72. package/plugins/meta-architect/skills/diagnose/SKILL.md +0 -0
  73. package/plugins/meta-architect/skills/diagnose/agents/openai.yaml +0 -0
  74. package/plugins/meta-architect/skills/flow/SKILL.md +0 -0
  75. package/plugins/meta-architect/skills/flow/agents/openai.yaml +0 -0
  76. package/plugins/meta-architect/skills/maestro/SKILL.md +17 -1
  77. package/plugins/meta-architect/skills/maestro/agents/openai.yaml +0 -0
  78. package/plugins/meta-architect/skills/maestro/references/core-release-rules.md +2 -2
  79. package/plugins/meta-architect/skills/maestro/references/native-ingest-map.md +0 -0
  80. package/plugins/meta-architect/skills/sage/SKILL.md +0 -0
  81. package/plugins/meta-architect/skills/sage/agents/openai.yaml +0 -0
  82. package/plugins/meta-architect/skills/sage/references/source-selection.md +0 -0
  83. package/plugins/meta-architect/skills/tdd/SKILL.md +0 -0
  84. package/plugins/meta-architect/skills/tdd/agents/openai.yaml +0 -0
  85. package/plugins/meta-architect/skills/vet/SKILL.md +0 -0
  86. package/plugins/meta-architect/skills/vet/agents/openai.yaml +0 -0
  87. package/plugins/meta-architect/skills/vet/references/security-playbooks.md +0 -0
  88. package/plugins/meta-architect/skills/vibe/SKILL.md +0 -0
  89. package/plugins/meta-architect/skills/vibe/agents/openai.yaml +0 -0
  90. package/schemas/autonomous-task-queue.schema.json +58 -0
  91. package/schemas/handoff-packet.schema.json +36 -0
  92. package/schemas/setup-receipt.schema.json +28 -0
  93. package/schemas/skill-frontmatter.schema.json +20 -0
  94. package/schemas/support-bundle.schema.json +37 -0
  95. package/schemas/task-contract.schema.json +31 -0
  96. package/scripts/active-autonomy-hook.mjs +141 -11
  97. package/scripts/biome-staged.js +0 -0
  98. package/scripts/build-linux-packages.mjs +7 -3
  99. package/scripts/cleanup-test-fixtures.sh +55 -0
  100. package/scripts/context-hydration-hook.mjs +89 -0
  101. package/scripts/demo-smoke.js +285 -0
  102. package/scripts/doctor.js +10 -8
  103. package/scripts/install.sh +33 -4
  104. package/scripts/install.sh.sha256 +1 -0
  105. package/scripts/linux-package-lib.mjs +0 -0
  106. package/scripts/linux-package-smoke.mjs +2 -2
  107. package/scripts/package-size-check.mjs +26 -0
  108. package/scripts/plugin-build.js +314 -0
  109. package/scripts/plugin-publish.js +77 -0
  110. package/scripts/plugin-sync.js +83 -17
  111. package/scripts/prepack.js +9 -0
  112. package/scripts/ralph/prompt.md +0 -0
  113. package/scripts/release-metadata.js +0 -0
  114. package/scripts/release-sync.js +83 -7
  115. package/scripts/release-verify.js +131 -7
  116. package/scripts/setup-npmrc.js +48 -23
  117. package/scripts/skills-install.js +9 -2
  118. package/scripts/skills-manifest.js +2 -21
  119. package/scripts/skills-pack.js +2 -2
  120. package/scripts/skills-validate.js +5 -55
  121. package/skills/align/SKILL.md +0 -0
  122. package/skills/align/agents/openai.yaml +0 -0
  123. package/skills/align/references/shared-language.md +0 -0
  124. package/skills/arch/SKILL.md +0 -0
  125. package/skills/arch/agents/openai.yaml +0 -0
  126. package/skills/build/SKILL.md +0 -0
  127. package/skills/build/agents/openai.yaml +0 -0
  128. package/skills/cleanup/SKILL.md +0 -0
  129. package/skills/cleanup/agents/openai.yaml +0 -0
  130. package/skills/cleanup/references/style-and-deslop.md +0 -0
  131. package/skills/diagnose/SKILL.md +0 -0
  132. package/skills/diagnose/agents/openai.yaml +0 -0
  133. package/skills/flow/SKILL.md +0 -0
  134. package/skills/flow/agents/openai.yaml +0 -0
  135. package/skills/index.json +0 -0
  136. package/skills/maestro/SKILL.md +17 -1
  137. package/skills/maestro/agents/openai.yaml +0 -0
  138. package/skills/maestro/references/core-release-rules.md +2 -2
  139. package/skills/maestro/references/native-ingest-map.md +0 -0
  140. package/skills/sage/SKILL.md +0 -0
  141. package/skills/sage/agents/openai.yaml +0 -0
  142. package/skills/sage/references/source-selection.md +0 -0
  143. package/skills/tdd/SKILL.md +0 -0
  144. package/skills/tdd/agents/openai.yaml +0 -0
  145. package/skills/vet/SKILL.md +0 -0
  146. package/skills/vet/agents/openai.yaml +0 -0
  147. package/skills/vet/references/security-playbooks.md +0 -0
  148. package/skills/vibe/SKILL.md +0 -0
  149. package/skills/vibe/agents/openai.yaml +0 -0
  150. package/sprint/00-idea.md +0 -0
  151. package/sprint/01-architecture.md +0 -0
  152. package/sprint/02-oss-evidence.md +0 -0
  153. package/sprint/03-logic.md +0 -0
  154. package/sprint/04-security.md +0 -0
  155. package/sprint/05-dx-ux.md +0 -0
  156. package/sprint/06-build-plan.md +0 -0
  157. package/sprint/07-release.md +2 -2
  158. package/src/agents.js +281 -0
  159. package/src/bootstrap.js +272 -65
  160. package/src/build-gate.js +0 -0
  161. package/src/codex-app-server.js +291 -0
  162. package/src/decision-log.js +0 -0
  163. package/src/fs-utils.js +175 -4
  164. package/src/launcher.js +26 -23
  165. package/src/mcp-config.js +9 -1
  166. package/src/mcp-live-client.js +141 -8
  167. package/src/paths.js +6 -1
  168. package/src/policy.js +2 -2
  169. package/src/prelaunch.js +223 -0
  170. package/src/process-utils.js +62 -0
  171. package/src/quality/ai-quality-orchestrator.js +328 -0
  172. package/src/release-issue-gates.js +62 -0
  173. package/src/release-operations.js +72 -0
  174. package/src/release-state.js +0 -0
  175. package/src/runtime/active-autonomy-core.js +0 -0
  176. package/src/runtime/agent-compat.js +31 -0
  177. package/src/runtime/alignment-sentinel.js +0 -0
  178. package/src/runtime/architect-review.js +249 -11
  179. package/src/runtime/autonomous-tasks.js +585 -0
  180. package/src/runtime/build-readiness.js +0 -0
  181. package/src/runtime/code-graph-rehearse.js +0 -0
  182. package/src/runtime/codeburn-core.js +118 -0
  183. package/src/runtime/context-authority.js +40 -0
  184. package/src/runtime/context-economy-core.js +40 -0
  185. package/src/runtime/continuity-graph.js +201 -0
  186. package/src/runtime/continuity-notes.js +71 -26
  187. package/src/runtime/core-source-ingest.js +2 -2
  188. package/src/runtime/detached-provider.js +90 -13
  189. package/src/runtime/doctor-report.js +18 -0
  190. package/src/runtime/environment-awareness-core.js +0 -0
  191. package/src/runtime/exposure-catalog.js +0 -0
  192. package/src/runtime/graphify-core.js +167 -0
  193. package/src/runtime/guidance-stack.js +9 -2
  194. package/src/runtime/handoff-packets.js +92 -0
  195. package/src/runtime/headroom-core.js +104 -0
  196. package/src/runtime/helper-orchestration-core.js +0 -0
  197. package/src/runtime/hook-profiles.js +20 -0
  198. package/src/runtime/learning-loop-core.js +110 -4
  199. package/src/runtime/live-agent-verification.js +122 -0
  200. package/src/runtime/maestro-events.js +0 -0
  201. package/src/runtime/maestro-manager.js +0 -0
  202. package/src/runtime/maestro-output.js +58 -0
  203. package/src/runtime/maestro-state.js +0 -0
  204. package/src/runtime/managed-markdown.js +29 -0
  205. package/src/runtime/mcp-authority.js +147 -0
  206. package/src/runtime/mcp-policy.js +0 -0
  207. package/src/runtime/obsidian-integration-core.js +255 -17
  208. package/src/runtime/obsidian-plugin-bridge.js +344 -38
  209. package/src/runtime/orchestrator.js +0 -0
  210. package/src/runtime/pi-maestro-core.js +89 -0
  211. package/src/runtime/preferences.js +79 -0
  212. package/src/runtime/project-context.js +636 -0
  213. package/src/runtime/prompt-strategy-core.js +0 -0
  214. package/src/runtime/quorum-review.js +0 -0
  215. package/src/runtime/ralph-execution-core.js +0 -0
  216. package/src/runtime/redaction-gateway.js +218 -19
  217. package/src/runtime/runtime-state.js +94 -2
  218. package/src/runtime/schema-migrations.js +162 -0
  219. package/src/runtime/semantic-recording-core.js +0 -0
  220. package/src/runtime/signal-hooks.js +13 -0
  221. package/src/runtime/skills-registry-export.js +96 -8
  222. package/src/runtime/startup-path.js +0 -0
  223. package/src/runtime/task-contracts.js +83 -0
  224. package/src/runtime/universal-plugin-broker-core.js +373 -50
  225. package/src/runtime/workspace-intelligence-runtime.js +0 -0
  226. package/src/runtime/workspace-virtualizer.js +0 -0
  227. package/src/runtime/workspaces.js +0 -0
  228. package/src/runtime-artifacts.js +0 -0
  229. package/src/setup-lifecycle.js +359 -0
  230. package/src/skill-frontmatter.js +78 -0
  231. package/src/skill-installer.js +226 -71
  232. package/src/skills.js +309 -31
  233. package/src/state-sync.js +0 -0
  234. package/src/test-fixtures.js +543 -0
  235. package/src/tui/grid.js +67 -0
  236. package/src/tui/status-grid.js +23 -0
  237. package/support-bundle.json +114 -0
  238. package/templates/AGENTS.md +6 -2
  239. package/templates/catalog-manifest.json +0 -0
  240. package/templates/model-instructions/core.md +0 -0
  241. package/templates/model-instructions/release.md +0 -0
  242. package/templates/model-instructions/security.md +0 -0
  243. package/templates/quality/ai-quality-rules.yml +37 -0
  244. package/docs/assets/image/Screenshot(1).png +0 -0
  245. package/docs/assets/image/Screenshot(2).png +0 -0
  246. package/docs/assets/image/Screenshot(3).png +0 -0
  247. package/docs/assets/image/Screenshot(4).png +0 -0
  248. package/docs/assets/image/Screenshot(5).png +0 -0
  249. package/docs/assets/image/Screenshot(6).png +0 -0
  250. package/docs/assets/image/Screenshot(7).png +0 -0
  251. package/docs/assets/image/Screenshot(8).png +0 -0
  252. package/docs/assets/image/Screenshot(9).png +0 -0
  253. package/docs/assets/meta-architect-logo.png +0 -0
  254. package/docs/assets/meta-architect-logo.svg +0 -8
  255. package/docs/onboarding.md +0 -81
  256. package/docs/prompt-guidance-contract.md +0 -17
  257. package/docs/prompt-guidance-fragments/active-autonomy-core.md +0 -7
  258. package/docs/skills-publishing.md +0 -255
  259. package/scripts/postinstall.js +0 -23
@@ -0,0 +1,167 @@
1
+ import { ensureDir, readJson, writeFileIfMissing, writeJson } from "../fs-utils.js";
2
+ import { getRuntimeSubsystemPath } from "../paths.js";
3
+
4
+ export const graphifySchemaVersion = "0.1.0";
5
+
6
+ export function getGraphifyRoot() {
7
+ return getRuntimeSubsystemPath("context", "graphify");
8
+ }
9
+
10
+ export function getGraphifyIndexPath() {
11
+ return getRuntimeSubsystemPath("context", "graphify", "index.json");
12
+ }
13
+
14
+ export function createDefaultGraphifyIndex() {
15
+ return {
16
+ schemaVersion: graphifySchemaVersion,
17
+ record_type: "derived_graph_index",
18
+ read_only: true,
19
+ nodes: [],
20
+ edges: [],
21
+ lastRebuiltAt: null,
22
+ };
23
+ }
24
+
25
+ export function validateGraphifyIndex(value) {
26
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
27
+ throw new Error("graphify index must be an object");
28
+ }
29
+ if (value.schemaVersion !== graphifySchemaVersion) {
30
+ throw new Error(`Unsupported graphify schemaVersion: ${value.schemaVersion}`);
31
+ }
32
+ if (value.record_type !== "derived_graph_index" || value.read_only !== true) {
33
+ throw new Error("graphify index must be a read-only derived_graph_index");
34
+ }
35
+ if (!Array.isArray(value.nodes) || !Array.isArray(value.edges)) {
36
+ throw new Error("graphify index requires nodes and edges arrays");
37
+ }
38
+ return value;
39
+ }
40
+
41
+ export async function seedGraphifyArtifacts() {
42
+ await ensureDir(getGraphifyRoot());
43
+ await writeFileIfMissing(
44
+ getGraphifyIndexPath(),
45
+ `${JSON.stringify(createDefaultGraphifyIndex(), null, 2)}\n`,
46
+ );
47
+ }
48
+
49
+ export async function loadGraphifyIndex() {
50
+ return validateGraphifyIndex(await readJson(getGraphifyIndexPath()));
51
+ }
52
+
53
+ function addNode(nodes, seen, id, kind, sourceSubsystem, label) {
54
+ if (!id || seen.has(id)) return;
55
+ seen.add(id);
56
+ nodes.push({ id, kind, sourceSubsystem, label: String(label ?? id) });
57
+ }
58
+
59
+ function addEdge(edges, seen, from, to, relation) {
60
+ if (!from || !to || from === to) return;
61
+ const key = `${from}\0${to}\0${relation}`;
62
+ if (seen.has(key)) return;
63
+ seen.add(key);
64
+ edges.push({ from, to, relation });
65
+ }
66
+
67
+ function addCollection(nodes, edges, nodeIds, edgeIds, sourceSubsystem, kind, entries, labelKey) {
68
+ for (const [index, entry] of (Array.isArray(entries) ? entries : []).entries()) {
69
+ if (!entry || typeof entry !== "object") continue;
70
+ const id = `${sourceSubsystem}:${kind}:${entry.id ?? entry.name ?? index}`;
71
+ addNode(
72
+ nodes,
73
+ nodeIds,
74
+ id,
75
+ kind,
76
+ sourceSubsystem,
77
+ entry[labelKey] ?? entry.name ?? entry.id ?? id,
78
+ );
79
+ if (entry.projectId) addEdge(edges, edgeIds, id, `project:${entry.projectId}`, "belongs_to");
80
+ }
81
+ }
82
+
83
+ export function rebuildGraphifyIndex(runtimeSnapshot = {}) {
84
+ const nodes = [];
85
+ const edges = [];
86
+ const nodeIds = new Set();
87
+ const edgeIds = new Set();
88
+ addNode(nodes, nodeIds, "project:root", "project", "project", "Project");
89
+
90
+ const continuity = runtimeSnapshot.continuityIndex;
91
+ if (continuity && typeof continuity === "object") {
92
+ addNode(nodes, nodeIds, "memory:continuity", "memory", "continuity", "Continuity memory");
93
+ addEdge(edges, edgeIds, "memory:continuity", "project:root", "supports");
94
+ }
95
+ const taskRegistry = runtimeSnapshot.taskRegistry ?? {};
96
+ addCollection(nodes, edges, nodeIds, edgeIds, "tasks", "task", taskRegistry.tasks, "title");
97
+ addCollection(nodes, edges, nodeIds, edgeIds, "tasks", "worker", taskRegistry.workers, "name");
98
+ for (const entry of runtimeSnapshot.mailboxEntries ?? []) {
99
+ if (typeof entry !== "string") continue;
100
+ const id = `tasks:mailbox:${entry}`;
101
+ addNode(nodes, nodeIds, id, "mailbox", "tasks", entry, entry);
102
+ addEdge(edges, edgeIds, id, "project:root", "supports");
103
+ }
104
+ addCollection(
105
+ nodes,
106
+ edges,
107
+ nodeIds,
108
+ edgeIds,
109
+ "workspaces",
110
+ "workspace",
111
+ runtimeSnapshot.workspaceIndex?.items,
112
+ "name",
113
+ );
114
+ addCollection(
115
+ nodes,
116
+ edges,
117
+ nodeIds,
118
+ edgeIds,
119
+ "manager",
120
+ "run",
121
+ runtimeSnapshot.managerRuns?.runs,
122
+ "state",
123
+ );
124
+ addCollection(
125
+ nodes,
126
+ edges,
127
+ nodeIds,
128
+ edgeIds,
129
+ "decisions",
130
+ "decision",
131
+ runtimeSnapshot.decisions?.decisions,
132
+ "title",
133
+ );
134
+
135
+ const vault = runtimeSnapshot.obsidianVaultIndex;
136
+ if (vault?.note_count > 0) {
137
+ addNode(
138
+ nodes,
139
+ nodeIds,
140
+ "obsidian:vault",
141
+ "vault",
142
+ "obsidian",
143
+ vault.vault_path || "Obsidian vault",
144
+ );
145
+ addEdge(edges, edgeIds, "obsidian:vault", "project:root", "context");
146
+ }
147
+
148
+ nodes.sort((a, b) => a.id.localeCompare(b.id));
149
+ edges.sort((a, b) =>
150
+ `${a.from}:${a.to}:${a.relation}`.localeCompare(`${b.from}:${b.to}:${b.relation}`),
151
+ );
152
+ return {
153
+ schemaVersion: graphifySchemaVersion,
154
+ record_type: "derived_graph_index",
155
+ read_only: true,
156
+ nodes,
157
+ edges,
158
+ lastRebuiltAt: new Date().toISOString(),
159
+ };
160
+ }
161
+
162
+ export async function writeGraphifyIndex(runtimeSnapshot) {
163
+ const index = validateGraphifyIndex(rebuildGraphifyIndex(runtimeSnapshot));
164
+ await ensureDir(getGraphifyRoot());
165
+ await writeJson(getGraphifyIndexPath(), index);
166
+ return index;
167
+ }
@@ -20,8 +20,8 @@ export async function seedGuidanceStackArtifacts() {
20
20
  `${JSON.stringify(
21
21
  {
22
22
  schemaVersion: "0.1.0",
23
- sources: [],
24
- content: "",
23
+ sources: [ponytailGuidanceSource],
24
+ content: ponytailGuidanceSource.content,
25
25
  },
26
26
  null,
27
27
  2,
@@ -40,3 +40,10 @@ export async function seedGuidanceStackArtifacts() {
40
40
  )}\n`,
41
41
  );
42
42
  }
43
+
44
+ export const ponytailGuidanceSource = {
45
+ id: "ponytail",
46
+ label: "Minimal-diff bias",
47
+ content:
48
+ "Apply a minimal-diff bias: prefer reuse over new abstractions, the smallest coherent diff, and deletion before addition. Preserve existing behavior and add complexity only when verification proves it is needed.",
49
+ };
@@ -0,0 +1,92 @@
1
+ import path from "node:path";
2
+ import { ensureDir, readJson, writeJson } from "../fs-utils.js";
3
+ import { getRuntimeSubsystemPath } from "../paths.js";
4
+
5
+ export const handoffPacketSchemaVersion = "0.1.0";
6
+
7
+ export function getHandoffPacketRoot() {
8
+ return getRuntimeSubsystemPath("tasks", "handoffs");
9
+ }
10
+
11
+ function safePacketId(id) {
12
+ if (String(id ?? "").includes("/") || String(id ?? "").includes("\\"))
13
+ throw new Error("handoff packet id is required");
14
+ const safe = String(id ?? "")
15
+ .trim()
16
+ .replace(/[^a-zA-Z0-9._-]/g, "-");
17
+ if (!safe || safe === "." || safe === "..") throw new Error("handoff packet id is required");
18
+ return safe;
19
+ }
20
+
21
+ export function createHandoffPacket({
22
+ goal,
23
+ currentState,
24
+ contextUsed = [],
25
+ decisions = [],
26
+ blockers = [],
27
+ risks = [],
28
+ changedFiles = [],
29
+ verification = [],
30
+ nextAction,
31
+ status = "active",
32
+ }) {
33
+ if (!goal || !currentState || !nextAction)
34
+ throw new Error("handoff packet requires goal, currentState, and nextAction");
35
+ return validateHandoffPacket({
36
+ schemaVersion: handoffPacketSchemaVersion,
37
+ record_type: "handoff_packet",
38
+ goal,
39
+ current_state: currentState,
40
+ context_used: contextUsed,
41
+ decisions,
42
+ blockers,
43
+ risks,
44
+ changed_files: changedFiles,
45
+ verification,
46
+ next_action: nextAction,
47
+ status,
48
+ created_at: new Date().toISOString(),
49
+ });
50
+ }
51
+
52
+ export function validateHandoffPacket(packet) {
53
+ if (
54
+ !packet ||
55
+ packet.schemaVersion !== handoffPacketSchemaVersion ||
56
+ packet.record_type !== "handoff_packet"
57
+ )
58
+ throw new Error("invalid handoff packet schema");
59
+ for (const field of ["goal", "current_state", "next_action"]) {
60
+ if (typeof packet[field] !== "string" || packet[field].trim() === "")
61
+ throw new Error(`handoff packet requires ${field}`);
62
+ }
63
+ for (const field of [
64
+ "context_used",
65
+ "decisions",
66
+ "blockers",
67
+ "risks",
68
+ "changed_files",
69
+ "verification",
70
+ ]) {
71
+ if (!Array.isArray(packet[field]) || packet[field].some((value) => typeof value !== "string"))
72
+ throw new Error(`handoff packet requires string array: ${field}`);
73
+ }
74
+ if (!["active", "blocked", "verified"].includes(packet.status))
75
+ throw new Error(`Unsupported handoff packet status: ${packet.status}`);
76
+ return packet;
77
+ }
78
+
79
+ export async function writeHandoffPacket(id, packet) {
80
+ const packetId = safePacketId(id);
81
+ const validated = validateHandoffPacket(packet);
82
+ await ensureDir(getHandoffPacketRoot());
83
+ const packetPath = path.join(getHandoffPacketRoot(), `${packetId}.json`);
84
+ await writeJson(packetPath, validated);
85
+ return packetPath;
86
+ }
87
+
88
+ export async function loadHandoffPacket(id) {
89
+ return validateHandoffPacket(
90
+ await readJson(path.join(getHandoffPacketRoot(), `${safePacketId(id)}.json`)),
91
+ );
92
+ }
@@ -0,0 +1,104 @@
1
+ import { ensureDir, readJson, writeFileIfMissing, writeJson } from "../fs-utils.js";
2
+ import { getRuntimeSubsystemPath } from "../paths.js";
3
+
4
+ export const headroomSchemaVersion = "0.1.0";
5
+
6
+ const defaultBudgets = {
7
+ pendingMailboxCount: { warn: 3, critical: 8 },
8
+ taskCount: { warn: 10, critical: 25 },
9
+ activeManagerRunCount: { warn: 2, critical: 5 },
10
+ waitingReviewManagerRunCount: { warn: 1, critical: 3 },
11
+ };
12
+
13
+ export function getHeadroomRoot() {
14
+ return getRuntimeSubsystemPath("headroom");
15
+ }
16
+
17
+ export function getHeadroomBudgetsPath() {
18
+ return getRuntimeSubsystemPath("headroom", "budgets.json");
19
+ }
20
+
21
+ export function getHeadroomStatusPath() {
22
+ return getRuntimeSubsystemPath("headroom", "status.json");
23
+ }
24
+
25
+ export function createDefaultHeadroomBudgets() {
26
+ return { schemaVersion: headroomSchemaVersion, budgets: structuredClone(defaultBudgets) };
27
+ }
28
+
29
+ export function createDefaultHeadroomStatus() {
30
+ return { schemaVersion: headroomSchemaVersion, evaluatedAt: null, signals: [] };
31
+ }
32
+
33
+ export function validateHeadroomBudgets(value) {
34
+ if (!value || typeof value !== "object" || value.schemaVersion !== headroomSchemaVersion) {
35
+ throw new Error("headroom budgets require the current schemaVersion");
36
+ }
37
+ if (!value.budgets || typeof value.budgets !== "object" || Array.isArray(value.budgets)) {
38
+ throw new Error("headroom budgets require a budgets object");
39
+ }
40
+ for (const [counter, budget] of Object.entries(value.budgets)) {
41
+ if (
42
+ !budget ||
43
+ !Number.isFinite(budget.warn) ||
44
+ !Number.isFinite(budget.critical) ||
45
+ budget.warn < 0 ||
46
+ budget.critical < budget.warn
47
+ ) {
48
+ throw new Error(`Invalid headroom budget for ${counter}`);
49
+ }
50
+ }
51
+ return value;
52
+ }
53
+
54
+ export function validateHeadroomStatus(value) {
55
+ if (!value || typeof value !== "object" || value.schemaVersion !== headroomSchemaVersion) {
56
+ throw new Error("headroom status requires the current schemaVersion");
57
+ }
58
+ if (!Array.isArray(value.signals)) throw new Error("headroom status requires signals");
59
+ return value;
60
+ }
61
+
62
+ export async function seedHeadroomArtifacts() {
63
+ await ensureDir(getHeadroomRoot());
64
+ await writeFileIfMissing(
65
+ getHeadroomBudgetsPath(),
66
+ `${JSON.stringify(createDefaultHeadroomBudgets(), null, 2)}\n`,
67
+ );
68
+ await writeFileIfMissing(
69
+ getHeadroomStatusPath(),
70
+ `${JSON.stringify(createDefaultHeadroomStatus(), null, 2)}\n`,
71
+ );
72
+ }
73
+
74
+ export async function loadHeadroomBudgets() {
75
+ return validateHeadroomBudgets(await readJson(getHeadroomBudgetsPath()));
76
+ }
77
+
78
+ export async function loadHeadroomStatus() {
79
+ return validateHeadroomStatus(await readJson(getHeadroomStatusPath()));
80
+ }
81
+
82
+ export function evaluateHeadroom(
83
+ runtimeSummary = {},
84
+ budgetConfig = createDefaultHeadroomBudgets(),
85
+ ) {
86
+ const config = validateHeadroomBudgets(budgetConfig);
87
+ const signals = Object.entries(config.budgets).map(([counter, budget]) => {
88
+ const value = Number(runtimeSummary[counter] ?? 0);
89
+ const level = value >= budget.critical ? "critical" : value >= budget.warn ? "warn" : "ok";
90
+ return { counter, value, warn: budget.warn, critical: budget.critical, level };
91
+ });
92
+ return {
93
+ schemaVersion: headroomSchemaVersion,
94
+ evaluatedAt: new Date().toISOString(),
95
+ signals,
96
+ };
97
+ }
98
+
99
+ export async function writeHeadroomStatus(runtimeSummary, budgetConfig) {
100
+ const status = validateHeadroomStatus(evaluateHeadroom(runtimeSummary, budgetConfig));
101
+ await ensureDir(getHeadroomRoot());
102
+ await writeJson(getHeadroomStatusPath(), status);
103
+ return status;
104
+ }
File without changes
@@ -0,0 +1,20 @@
1
+ export const hookProfiles = {
2
+ local: { scanScope: "active-project", block: true, writeReceipts: true, readOnly: false },
3
+ ci: { scanScope: "active-project", block: true, writeReceipts: true, readOnly: false },
4
+ pr: {
5
+ scanScope: "active-project",
6
+ block: true,
7
+ writeReceipts: true,
8
+ readOnly: false,
9
+ requireFreshness: true,
10
+ },
11
+ audit: { scanScope: "broad", block: false, writeReceipts: false, readOnly: true },
12
+ };
13
+
14
+ export function resolveHookProfile(
15
+ value = process.env.MA_HOOK_PROFILE ?? process.env.MA_PROFILE ?? "local",
16
+ ) {
17
+ return hookProfiles[value]
18
+ ? { id: value, ...hookProfiles[value] }
19
+ : { id: "local", ...hookProfiles.local };
20
+ }
@@ -1,5 +1,9 @@
1
+ import fs from "node:fs/promises";
1
2
  import { ensureDir, readJson, writeFileIfMissing } from "../fs-utils.js";
2
3
  import { getRuntimeSubsystemPath } from "../paths.js";
4
+ import { createFreshness } from "./context-authority.js";
5
+ import { appendObsidianLearningRecord } from "./obsidian-integration-core.js";
6
+ import { maskSensitiveText } from "./redaction-gateway.js";
3
7
 
4
8
  export const learningLoopCoreSchemaVersion = "0.1.0";
5
9
 
@@ -19,6 +23,10 @@ export function getLearningLoopCorePath() {
19
23
  return getRuntimeSubsystemPath("context", "learning-loop-core.json");
20
24
  }
21
25
 
26
+ export function getLearningRecordsPath() {
27
+ return getRuntimeSubsystemPath("learning", "records.jsonl");
28
+ }
29
+
22
30
  export function createDefaultLearningLoopCore() {
23
31
  return {
24
32
  schemaVersion: learningLoopCoreSchemaVersion,
@@ -113,11 +121,13 @@ export function createDefaultLearningLoopCore() {
113
121
  evidence: ["path_or_command_or_receipt"],
114
122
  status: "candidate | verified | rejected | superseded",
115
123
  applies_to: ["agent_or_role_or_lane"],
124
+ fact_ids: ["canonical_project_fact_id"],
116
125
  cannot_mutate: ["release_state_without_owning_lane", "source_evidence", "security_boundary"],
117
126
  next_verification: "string",
118
127
  },
119
128
  hard_rules: [
120
129
  "Learning records require domain, claim, source, evidence, status, applies_to, and next_verification.",
130
+ "fact_ids may reference only canonical source-truth project facts.",
121
131
  "Candidate learnings can inform context but cannot mutate gates, release state, or durable policy.",
122
132
  "Verified learnings must preserve lane authority and semantic channel boundaries.",
123
133
  "Obsidian and memory context can inform planning but do not become build evidence without owning-lane promotion.",
@@ -169,9 +179,17 @@ export function createLearningRecord({
169
179
  claim,
170
180
  source,
171
181
  evidence = [],
182
+ filesInvolved = [],
183
+ decisionsMade = [],
184
+ knownRisks = [],
185
+ userPreferences = {},
172
186
  status = "candidate",
173
187
  appliesTo = ["all_applicable_agents", "all_applicable_roles"],
174
188
  nextVerification,
189
+ factIds = [],
190
+ failureState,
191
+ attemptedFixes = [],
192
+ resolutionStatus,
175
193
  }) {
176
194
  if (!learningLoopDomains.includes(domain)) {
177
195
  throw new Error(`Unsupported learning domain: ${domain}`);
@@ -179,19 +197,54 @@ export function createLearningRecord({
179
197
  if (!claim || !source || !nextVerification) {
180
198
  throw new Error("Learning record requires domain, claim, source, and nextVerification");
181
199
  }
200
+ if (
201
+ !Array.isArray(factIds) ||
202
+ factIds.some((entry) => typeof entry !== "string" || !/^fact-[a-f0-9]{16}$/.test(entry))
203
+ ) {
204
+ throw new Error("Learning record factIds must use canonical fact IDs");
205
+ }
206
+ const createdAt = new Date().toISOString();
182
207
  return {
183
208
  domain,
184
- claim,
185
- source,
186
- evidence: evidence.filter((entry) => typeof entry === "string" && entry.trim()),
209
+ claim: sanitizeLearningText(claim),
210
+ source: sanitizeLearningText(source),
211
+ evidence: evidence
212
+ .filter((entry) => typeof entry === "string" && entry.trim())
213
+ .map(sanitizeLearningText),
214
+ files_involved: filesInvolved
215
+ .filter((entry) => typeof entry === "string" && entry.trim())
216
+ .map(sanitizeLearningText),
217
+ decisions_made: decisionsMade
218
+ .filter((entry) => typeof entry === "string" && entry.trim())
219
+ .map(sanitizeLearningText),
220
+ known_risks: knownRisks
221
+ .filter((entry) => typeof entry === "string" && entry.trim())
222
+ .map(sanitizeLearningText),
223
+ user_preferences: userPreferences && typeof userPreferences === "object" ? userPreferences : {},
187
224
  status,
225
+ authority: "learning_memory",
226
+ freshness: createFreshness({ checkedAt: createdAt }),
188
227
  applies_to: appliesTo.filter((entry) => typeof entry === "string" && entry.trim()),
228
+ fact_ids: factIds.filter((entry) => typeof entry === "string" && entry.trim()),
189
229
  cannot_mutate: ["release_state_without_owning_lane", "source_evidence", "security_boundary"],
190
230
  next_verification: nextVerification,
191
- created_at: new Date().toISOString(),
231
+ created_at: createdAt,
232
+ ...(failureState
233
+ ? {
234
+ failure_state: failureState,
235
+ attempted_fixes: attemptedFixes
236
+ .filter((entry) => typeof entry === "string")
237
+ .map(sanitizeLearningText),
238
+ resolution_status: resolutionStatus ?? "active",
239
+ }
240
+ : {}),
192
241
  };
193
242
  }
194
243
 
244
+ function sanitizeLearningText(value) {
245
+ return maskSensitiveText(String(value)).sanitizedText;
246
+ }
247
+
195
248
  export function addLearningRecord(core, record) {
196
249
  const validated = validateLearningLoopCore(core);
197
250
  if (!learningLoopDomains.includes(record.domain)) {
@@ -236,3 +289,56 @@ export async function seedLearningLoopCoreArtifacts() {
236
289
  export async function loadLearningLoopCore() {
237
290
  return validateLearningLoopCore(await readJson(getLearningLoopCorePath()));
238
291
  }
292
+
293
+ export async function appendLearningRecord(record) {
294
+ const validated = createLearningRecord(record);
295
+ await ensureDir(getRuntimeSubsystemPath("learning"));
296
+ await fs.appendFile(getLearningRecordsPath(), `${JSON.stringify(validated)}\n`, "utf8");
297
+ return validated;
298
+ }
299
+
300
+ export async function recordWorkLearning({ vaultPath, ...record }) {
301
+ const validated = await appendLearningRecord(record);
302
+ if (vaultPath) await appendObsidianLearningRecord({ vaultPath, record: validated });
303
+ return validated;
304
+ }
305
+
306
+ export async function recordFailureMemory({
307
+ cause,
308
+ source = "workflow",
309
+ evidence = [],
310
+ attemptedFixes = [],
311
+ resolutionStatus = "active",
312
+ filesInvolved = [],
313
+ vaultPath,
314
+ } = {}) {
315
+ if (!cause) throw new Error("failure memory requires cause");
316
+ if (!["active", "resolved", "stale"].includes(resolutionStatus)) {
317
+ throw new Error(`Unsupported failure resolution status: ${resolutionStatus}`);
318
+ }
319
+ return recordWorkLearning({
320
+ vaultPath,
321
+ domain: "code_quality_testing",
322
+ claim: `Failure: ${cause}`,
323
+ source,
324
+ evidence,
325
+ filesInvolved,
326
+ knownRisks: [cause],
327
+ status: resolutionStatus === "resolved" ? "verified" : "candidate",
328
+ nextVerification:
329
+ resolutionStatus === "resolved" ? "Monitor for recurrence" : "Re-run the failing workflow",
330
+ failureState: resolutionStatus,
331
+ attemptedFixes,
332
+ resolutionStatus,
333
+ });
334
+ }
335
+
336
+ export async function loadLearningRecords({ limit = 20 } = {}) {
337
+ const raw = await fs.readFile(getLearningRecordsPath(), "utf8").catch(() => "");
338
+ return raw
339
+ .split("\n")
340
+ .filter(Boolean)
341
+ .map((line) => JSON.parse(line))
342
+ .slice(-Math.max(1, Math.min(100, limit)))
343
+ .reverse();
344
+ }
@@ -0,0 +1,122 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { agentRegistry as executableAgents, resolveAgentCommand } from "../agents.js";
5
+ import { safeSpawn } from "../process-utils.js";
6
+ import {
7
+ agentRegistry,
8
+ createSkillCompatibilityPayload,
9
+ verifyCrossAgentInstallMatrix,
10
+ } from "./skills-registry-export.js";
11
+
12
+ const defaultTimeoutMs = 5000;
13
+
14
+ function runVersionProbe(command, timeoutMs, args = ["--version"]) {
15
+ return new Promise((resolve) => {
16
+ const child = safeSpawn(command, args, {
17
+ shell: false,
18
+ stdio: ["ignore", "pipe", "pipe"],
19
+ });
20
+ let stdout = "";
21
+ let stderr = "";
22
+ let settled = false;
23
+ const finish = (result) => {
24
+ if (settled) return;
25
+ settled = true;
26
+ clearTimeout(timer);
27
+ resolve(result);
28
+ };
29
+ const timer = setTimeout(() => {
30
+ child.kill("SIGTERM");
31
+ finish({ ok: false, reason: "version probe timed out" });
32
+ }, timeoutMs);
33
+ child.stdout.on("data", (chunk) => {
34
+ stdout += chunk.toString();
35
+ });
36
+ child.stderr.on("data", (chunk) => {
37
+ stderr += chunk.toString();
38
+ });
39
+ child.once("error", (error) => finish({ ok: false, reason: error.message }));
40
+ child.once("close", (code) =>
41
+ finish({
42
+ ok: code === 0,
43
+ version: stdout.trim(),
44
+ reason: code === 0 ? null : stderr.trim() || `exited with code ${code}`,
45
+ }),
46
+ );
47
+ });
48
+ }
49
+
50
+ function normalizeProbeCommand(command) {
51
+ return [".js", ".mjs", ".cjs"].includes(path.extname(command))
52
+ ? { command: process.execPath, args: [command, "--version"] }
53
+ : { command, args: ["--version"] };
54
+ }
55
+
56
+ export async function verifyLiveAgentMatrix({
57
+ cwd = process.cwd(),
58
+ targets = Object.keys(agentRegistry),
59
+ timeoutMs = defaultTimeoutMs,
60
+ } = {}) {
61
+ const root = path.resolve(cwd);
62
+ const tempRoot = await fsTempDirectory();
63
+ try {
64
+ const payload = createSkillCompatibilityPayload({
65
+ name: "live-agent-verification",
66
+ capabilities: ["maestro", "agent-compatibility"],
67
+ });
68
+ const distribution = await verifyCrossAgentInstallMatrix({
69
+ payload,
70
+ cwd: tempRoot,
71
+ targets,
72
+ existingAgentRoots: targets,
73
+ });
74
+ const results = [];
75
+ for (const [index, target] of targets.entries()) {
76
+ const distributionResult = distribution.results[index];
77
+ const command = executableAgents[target]?.probeable ? resolveAgentCommand(target) : null;
78
+ if (!command) {
79
+ results.push({
80
+ target,
81
+ status: distributionResult?.ok ? "distribution-only" : "blocked",
82
+ version: null,
83
+ command: null,
84
+ distribution: distributionResult?.ok === true,
85
+ reason: "No safe non-interactive host command is registered for this target.",
86
+ });
87
+ continue;
88
+ }
89
+ const normalized = normalizeProbeCommand(command);
90
+ const probe = await runVersionProbe(normalized.command, timeoutMs, normalized.args);
91
+ results.push({
92
+ target,
93
+ status: probe.ok && distributionResult?.ok ? "runtime-verified" : "blocked",
94
+ version: probe.version ?? null,
95
+ command,
96
+ distribution: distributionResult?.ok === true,
97
+ reason: probe.ok ? null : probe.reason,
98
+ });
99
+ }
100
+ return {
101
+ schemaVersion: "0.1.0",
102
+ record_type: "live_agent_verification",
103
+ cwd: root,
104
+ target_count: results.length,
105
+ runtime_verified: results.filter((result) => result.status === "runtime-verified").length,
106
+ distribution_only: results.filter((result) => result.status === "distribution-only").length,
107
+ blocked: results.filter((result) => result.status === "blocked").length,
108
+ results,
109
+ production_evidence: false,
110
+ };
111
+ } finally {
112
+ await fsTempRemove(tempRoot);
113
+ }
114
+ }
115
+
116
+ async function fsTempDirectory() {
117
+ return fs.mkdtemp(path.join(os.tmpdir(), "ma-live-agents-"));
118
+ }
119
+
120
+ async function fsTempRemove(directory) {
121
+ await fs.rm(directory, { recursive: true, force: true });
122
+ }