@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,291 @@
1
+ import fs from "node:fs";
2
+ import { safeSpawn } from "./process-utils.js";
3
+
4
+ const PACKAGE_VERSION = JSON.parse(
5
+ fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
6
+ ).version;
7
+
8
+ const DEFAULT_TIMEOUT_MS = 30_000;
9
+
10
+ export class CodexRpcError extends Error {
11
+ constructor(message, error) {
12
+ super(message);
13
+ this.name = "CodexRpcError";
14
+ this.code = error?.code;
15
+ this.data = error?.data;
16
+ }
17
+ }
18
+
19
+ export class CodexAppServerClient {
20
+ constructor({ transport, command = "codex", timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
21
+ this.transport = transport ?? createStdioTransport(command);
22
+ this.timeoutMs = timeoutMs;
23
+ this.nextId = 1;
24
+ this.pending = new Map();
25
+ this.notifications = new Set();
26
+ this.serverRequests = new Set();
27
+ this.transport.onMessage((message) => this.#receive(message));
28
+ }
29
+
30
+ async request(method, params = {}, timeoutMs = this.timeoutMs) {
31
+ const id = this.nextId++;
32
+ const message = { jsonrpc: "2.0", id, method, params };
33
+ return new Promise((resolve, reject) => {
34
+ const timer = setTimeout(() => {
35
+ this.pending.delete(id);
36
+ reject(new Error(`Codex app-server request timed out: ${method}`));
37
+ }, timeoutMs);
38
+ this.pending.set(id, { resolve, reject, timer, method });
39
+ try {
40
+ this.transport.send(message);
41
+ } catch (error) {
42
+ clearTimeout(timer);
43
+ this.pending.delete(id);
44
+ reject(error);
45
+ }
46
+ });
47
+ }
48
+
49
+ notify(method, params = {}) {
50
+ this.transport.send({ jsonrpc: "2.0", method, params });
51
+ }
52
+
53
+ onNotification(listener) {
54
+ this.notifications.add(listener);
55
+ return () => this.notifications.delete(listener);
56
+ }
57
+
58
+ onServerRequest(listener) {
59
+ this.serverRequests.add(listener);
60
+ return () => this.serverRequests.delete(listener);
61
+ }
62
+
63
+ async initialize(clientInfo = { name: "meta-architect", version: PACKAGE_VERSION }) {
64
+ const result = await this.request("initialize", {
65
+ clientInfo,
66
+ capabilities: {},
67
+ });
68
+ this.notify("initialized", {});
69
+ return result;
70
+ }
71
+
72
+ startThread(params = {}) {
73
+ return this.request("thread/start", params);
74
+ }
75
+
76
+ resumeThread(params) {
77
+ return this.request("thread/resume", params);
78
+ }
79
+
80
+ forkThread(params) {
81
+ return this.request("thread/fork", params);
82
+ }
83
+
84
+ listThreads(params = {}) {
85
+ return this.request("thread/list", params);
86
+ }
87
+
88
+ archiveThread(params) {
89
+ return this.request("thread/archive", params);
90
+ }
91
+
92
+ startTurn(params) {
93
+ return this.request("turn/start", params);
94
+ }
95
+
96
+ interruptTurn(params) {
97
+ return this.request("turn/interrupt", params);
98
+ }
99
+
100
+ readConfig(params = {}) {
101
+ return this.request("config/read", params);
102
+ }
103
+
104
+ writeConfig(params = {}) {
105
+ return this.request("config/batchWrite", params);
106
+ }
107
+
108
+ close() {
109
+ for (const pending of this.pending.values()) {
110
+ clearTimeout(pending.timer);
111
+ pending.reject(new Error("Codex app-server client closed"));
112
+ }
113
+ this.pending.clear();
114
+ return this.transport.close?.();
115
+ }
116
+
117
+ #receive(message) {
118
+ if (message && Object.hasOwn(message, "id")) {
119
+ const pending = this.pending.get(message.id);
120
+ if (!pending) {
121
+ if (message.method) {
122
+ for (const listener of this.serverRequests)
123
+ listener(message, (result) => this.#respond(message.id, result));
124
+ } else {
125
+ this.#respond(message.id, undefined, { code: -32600, message: "Unknown response id" });
126
+ }
127
+ return;
128
+ }
129
+ clearTimeout(pending.timer);
130
+ this.pending.delete(message.id);
131
+ if (message.error)
132
+ pending.reject(
133
+ new CodexRpcError(`Codex app-server ${pending.method} failed`, message.error),
134
+ );
135
+ else pending.resolve(message.result);
136
+ return;
137
+ }
138
+ for (const listener of this.notifications) listener(message);
139
+ }
140
+
141
+ #respond(id, result, error) {
142
+ this.transport.send({ jsonrpc: "2.0", id, ...(error ? { error } : { result }) });
143
+ }
144
+ }
145
+
146
+ export function createStdioTransport(command = "codex") {
147
+ const child = safeSpawn(command, ["app-server", "--stdio"], {
148
+ stdio: ["pipe", "pipe", "inherit"],
149
+ shell: false,
150
+ });
151
+ let buffer = "";
152
+ const listeners = new Set();
153
+ child.stdout.on("data", (chunk) => {
154
+ buffer += chunk.toString();
155
+ for (;;) {
156
+ const newline = buffer.indexOf("\n");
157
+ if (newline < 0) break;
158
+ const line = buffer.slice(0, newline).trim();
159
+ buffer = buffer.slice(newline + 1);
160
+ if (!line) continue;
161
+ let message;
162
+ try {
163
+ message = JSON.parse(line);
164
+ } catch {
165
+ continue;
166
+ }
167
+ for (const listener of listeners) listener(message);
168
+ }
169
+ });
170
+ return {
171
+ send(message) {
172
+ if (!child.stdin.writable) throw new Error("Codex app-server stdin is closed");
173
+ child.stdin.write(`${JSON.stringify(message)}\n`);
174
+ },
175
+ onMessage(listener) {
176
+ listeners.add(listener);
177
+ },
178
+ close() {
179
+ child.kill();
180
+ },
181
+ child,
182
+ };
183
+ }
184
+
185
+ export function parseCodexJsonl(text) {
186
+ return text
187
+ .split(/\r?\n/)
188
+ .map((line) => line.trim())
189
+ .filter(Boolean)
190
+ .map((line, index) => {
191
+ try {
192
+ return JSON.parse(line);
193
+ } catch (error) {
194
+ throw new Error(`Invalid Codex exec JSONL at line ${index + 1}: ${error.message}`);
195
+ }
196
+ });
197
+ }
198
+
199
+ export function runCodexExec({
200
+ prompt,
201
+ args = [],
202
+ command = "codex",
203
+ cwd,
204
+ timeoutMs = DEFAULT_TIMEOUT_MS,
205
+ } = {}) {
206
+ if (typeof prompt !== "string" || !prompt.trim()) throw new Error("Codex exec requires a prompt");
207
+ return new Promise((resolve, reject) => {
208
+ const child = safeSpawn(command, ["exec", "--json", ...args, prompt], {
209
+ cwd,
210
+ stdio: ["ignore", "pipe", "pipe"],
211
+ shell: false,
212
+ });
213
+ let stdout = "";
214
+ let stderr = "";
215
+ const timer = setTimeout(() => {
216
+ child.kill("SIGTERM");
217
+ reject(new Error("Codex exec timed out"));
218
+ }, timeoutMs);
219
+ child.stdout.on("data", (chunk) => (stdout += chunk));
220
+ child.stderr.on("data", (chunk) => (stderr += chunk));
221
+ child.on("error", (error) => {
222
+ clearTimeout(timer);
223
+ reject(error);
224
+ });
225
+ child.on("close", (code) => {
226
+ clearTimeout(timer);
227
+ let events;
228
+ try {
229
+ events = parseCodexJsonl(stdout);
230
+ } catch (error) {
231
+ reject(error);
232
+ return;
233
+ }
234
+ if (code !== 0) {
235
+ reject(new Error(`Codex exec failed with exit code ${code}: ${stderr.trim()}`));
236
+ return;
237
+ }
238
+ resolve({ code, events, stderr: stderr.trim() });
239
+ });
240
+ });
241
+ }
242
+
243
+ export function generateCodexBindings({
244
+ kind = "ts",
245
+ outDir,
246
+ command = "codex",
247
+ cwd,
248
+ timeoutMs = DEFAULT_TIMEOUT_MS,
249
+ } = {}) {
250
+ if (!outDir) throw new Error("Codex binding generation requires an output directory");
251
+ const generator = kind === "json-schema" ? "generate-json-schema" : "generate-ts";
252
+ return new Promise((resolve, reject) => {
253
+ const child = safeSpawn(command, ["app-server", generator, "--out", outDir], {
254
+ cwd,
255
+ stdio: ["ignore", "pipe", "pipe"],
256
+ shell: false,
257
+ });
258
+ let stderr = "";
259
+ const timer = setTimeout(() => {
260
+ child.kill("SIGTERM");
261
+ reject(new Error("Codex binding generation timed out"));
262
+ }, timeoutMs);
263
+ child.stderr.on("data", (chunk) => (stderr += chunk));
264
+ child.on("error", (error) => {
265
+ clearTimeout(timer);
266
+ reject(error);
267
+ });
268
+ child.on("close", (code) => {
269
+ clearTimeout(timer);
270
+ if (code !== 0)
271
+ reject(
272
+ new Error(`Codex binding generation failed with exit code ${code}: ${stderr.trim()}`),
273
+ );
274
+ else resolve({ code: code ?? 0, output: outDir, kind });
275
+ });
276
+ });
277
+ }
278
+
279
+ export function validateStructuredResult(value, schema) {
280
+ if (!schema || typeof schema !== "object") throw new Error("Output schema is required");
281
+ if (schema.type === "object" && (!value || typeof value !== "object" || Array.isArray(value)))
282
+ return false;
283
+ for (const required of schema.required ?? []) if (!Object.hasOwn(value, required)) return false;
284
+ for (const [key, rule] of Object.entries(schema.properties ?? {})) {
285
+ if (!Object.hasOwn(value, key)) continue;
286
+ if (rule.type === "string" && typeof value[key] !== "string") return false;
287
+ if (rule.type === "number" && typeof value[key] !== "number") return false;
288
+ if (rule.type === "boolean" && typeof value[key] !== "boolean") return false;
289
+ }
290
+ return true;
291
+ }
File without changes
package/src/fs-utils.js CHANGED
@@ -1,5 +1,10 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import fs from "node:fs/promises";
2
3
  import path from "node:path";
4
+ import { writeJsonAtomically } from "./setup-lifecycle.js";
5
+
6
+ export const RUNTIME_STATE_MAX_BYTES = 50 * 1024 * 1024;
7
+ const localRuntimeLocks = new Map();
3
8
 
4
9
  export async function readJson(filePath) {
5
10
  const raw = await fs.readFile(filePath, "utf8");
@@ -7,8 +12,175 @@ export async function readJson(filePath) {
7
12
  }
8
13
 
9
14
  export async function writeJson(filePath, value) {
10
- await fs.mkdir(path.dirname(filePath), { recursive: true });
11
- await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
15
+ await withRuntimeStateLock(filePath, () => writeJsonAtomically(filePath, value), { wait: true });
16
+ }
17
+
18
+ export async function writeTextAtomically(filePath, content) {
19
+ await withRuntimeStateLock(filePath, () => writeTextAtomicallyUnlocked(filePath, content), {
20
+ wait: true,
21
+ });
22
+ }
23
+
24
+ async function writeTextAtomicallyUnlocked(filePath, content) {
25
+ const temporary = `${filePath}.tmp-${randomUUID()}`;
26
+ try {
27
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
28
+ await fs.writeFile(temporary, content);
29
+ await fs.rename(temporary, filePath);
30
+ } catch (error) {
31
+ await fs.rm(temporary, { force: true }).catch(() => {});
32
+ throw error;
33
+ }
34
+ }
35
+
36
+ function runtimeStateRoot(filePath) {
37
+ const absolute = path.resolve(filePath);
38
+ const parts = absolute.split(path.sep);
39
+ const maIndex = parts.lastIndexOf(".ma");
40
+ if (maIndex < 0) return null;
41
+ return path.join(path.sep, ...parts.slice(0, maIndex + 1));
42
+ }
43
+
44
+ function runtimeStateLockName(filePath, root) {
45
+ const relative = path.relative(root, path.resolve(filePath));
46
+ const subsystem = relative.split(path.sep)[0] || "root";
47
+ return `.runtime-${subsystem.replace(/[^a-zA-Z0-9_.-]/g, "_")}.lock`;
48
+ }
49
+
50
+ async function writeRecoveryReceipt(root, reason, details) {
51
+ const receiptPath = path.join(
52
+ root,
53
+ "state",
54
+ "recovery-receipts",
55
+ `runtime-${Date.now()}-${randomUUID()}.json`,
56
+ );
57
+ await writeJsonAtomically(receiptPath, {
58
+ schemaVersion: "0.1.0",
59
+ record_type: "runtime_recovery_receipt",
60
+ generatedAt: new Date().toISOString(),
61
+ reason,
62
+ ...details,
63
+ });
64
+ }
65
+
66
+ export async function withRuntimeStateLock(filePath, action, options = {}) {
67
+ const root = runtimeStateRoot(filePath);
68
+ if (!root) return action();
69
+ const lockPath = path.join(root, "state", runtimeStateLockName(filePath, root));
70
+ if (localRuntimeLocks.has(lockPath) && !options.wait) {
71
+ throw new Error(`Meta-Architect runtime state is busy: ${path.relative(root, filePath)}`);
72
+ }
73
+ const previous = localRuntimeLocks.get(lockPath) ?? Promise.resolve();
74
+ let release;
75
+ const current = new Promise((resolve) => {
76
+ release = resolve;
77
+ });
78
+ localRuntimeLocks.set(lockPath, current);
79
+ await previous;
80
+ try {
81
+ return await withExternalRuntimeStateLock(lockPath, filePath, root, action, options);
82
+ } finally {
83
+ release();
84
+ if (localRuntimeLocks.get(lockPath) === current) localRuntimeLocks.delete(lockPath);
85
+ }
86
+ }
87
+
88
+ async function withExternalRuntimeStateLock(lockPath, filePath, root, action, options) {
89
+ const staleMs = options.staleMs ?? 60 * 60 * 1000;
90
+ await fs.mkdir(path.dirname(lockPath), { recursive: true });
91
+ let recovered = false;
92
+ for (;;) {
93
+ try {
94
+ await fs.mkdir(lockPath);
95
+ await fs.writeFile(
96
+ path.join(lockPath, "owner.json"),
97
+ `${JSON.stringify({ pid: process.pid, createdAt: Date.now(), filePath: path.resolve(filePath) })}\n`,
98
+ { mode: 0o600 },
99
+ );
100
+ break;
101
+ } catch (error) {
102
+ if (error?.code !== "EEXIST") throw error;
103
+ const ownerPath = path.join(lockPath, "owner.json");
104
+ const ownerText = await fs.readFile(ownerPath, "utf8").catch(() => null);
105
+ const stat = await fs.stat(lockPath).catch(() => null);
106
+ let owner;
107
+ try {
108
+ owner = ownerText ? JSON.parse(ownerText) : null;
109
+ } catch {
110
+ throw new Error(
111
+ "Meta-Architect runtime lock is corrupt; remove it only after confirming no writer is running",
112
+ );
113
+ }
114
+ const alive =
115
+ Number.isInteger(owner?.pid) &&
116
+ (() => {
117
+ try {
118
+ process.kill(owner.pid, 0);
119
+ return true;
120
+ } catch {
121
+ return false;
122
+ }
123
+ })();
124
+ const stale = owner ? !alive : Boolean(stat && Date.now() - stat.mtimeMs > staleMs);
125
+ if (!stale) {
126
+ if (!options.wait)
127
+ throw new Error(`Meta-Architect runtime state is busy: ${path.relative(root, filePath)}`);
128
+ if (stat && Date.now() - stat.mtimeMs < staleMs) {
129
+ await new Promise((resolve) => setTimeout(resolve, 5));
130
+ continue;
131
+ }
132
+ throw new Error(
133
+ `Meta-Architect runtime state lock timed out: ${path.relative(root, filePath)}`,
134
+ );
135
+ }
136
+ await fs.rm(lockPath, { recursive: true, force: true });
137
+ recovered = true;
138
+ }
139
+ }
140
+ try {
141
+ if (recovered)
142
+ await writeRecoveryReceipt(root, "stale-runtime-lock", {
143
+ filePath: path.relative(root, filePath),
144
+ });
145
+ return await action();
146
+ } finally {
147
+ await fs.rm(lockPath, { recursive: true, force: true });
148
+ }
149
+ }
150
+
151
+ export async function inspectRuntimeStateHealth(root) {
152
+ const stateRoot = path.join(path.resolve(root), ".ma");
153
+ const findings = [];
154
+ let totalBytes = 0;
155
+ async function walk(current) {
156
+ const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => []);
157
+ for (const entry of entries) {
158
+ const target = path.join(current, entry.name);
159
+ if (entry.isDirectory()) {
160
+ if (entry.name.endsWith(".lock"))
161
+ findings.push({ type: "lock", path: path.relative(root, target) });
162
+ else await walk(target);
163
+ continue;
164
+ }
165
+ totalBytes += (await fs.stat(target).catch(() => ({ size: 0 }))).size;
166
+ if (entry.name.includes(".tmp-")) {
167
+ findings.push({ type: "temporary", path: path.relative(root, target) });
168
+ continue;
169
+ }
170
+ if (entry.name.endsWith(".json")) {
171
+ try {
172
+ JSON.parse(await fs.readFile(target, "utf8"));
173
+ } catch {
174
+ findings.push({ type: "corrupt-json", path: path.relative(root, target) });
175
+ }
176
+ }
177
+ }
178
+ }
179
+ await walk(stateRoot);
180
+ if (totalBytes > RUNTIME_STATE_MAX_BYTES) {
181
+ findings.push({ type: "oversized", path: path.relative(root, stateRoot), bytes: totalBytes });
182
+ }
183
+ return findings;
12
184
  }
13
185
 
14
186
  export async function ensureDir(dirPath) {
@@ -19,7 +191,6 @@ export async function writeFileIfMissing(filePath, content) {
19
191
  try {
20
192
  await fs.access(filePath);
21
193
  } catch {
22
- await fs.mkdir(path.dirname(filePath), { recursive: true });
23
- await fs.writeFile(filePath, content);
194
+ await writeTextAtomically(filePath, content);
24
195
  }
25
196
  }
package/src/launcher.js CHANGED
@@ -1,14 +1,17 @@
1
- import { spawnSync } from "node:child_process";
2
1
  import path from "node:path";
2
+ import { getAgent, resolveAgentCommand } from "./agents.js";
3
+ import { safeSpawnSync } from "./process-utils.js";
3
4
 
4
5
  const nativeCommands = new Set([
5
6
  "bootstrap",
6
7
  "doctor",
7
8
  "setup",
9
+ "migrate",
8
10
  "init",
9
11
  "idea",
10
12
  "skills",
11
13
  "core-ingest",
14
+ "agent-compat",
12
15
  "obsidian",
13
16
  "obsidian-index",
14
17
  "sdk-path",
@@ -17,9 +20,11 @@ const nativeCommands = new Set([
17
20
  "merge",
18
21
  "release",
19
22
  "run",
23
+ "task",
24
+ "hook",
20
25
  ]);
21
26
 
22
- export function shouldDelegateToCodex(args) {
27
+ export function shouldDelegateToAgent(args) {
23
28
  if (args.length === 0) {
24
29
  return true;
25
30
  }
@@ -27,36 +32,34 @@ export function shouldDelegateToCodex(args) {
27
32
  return !nativeCommands.has(args[0]);
28
33
  }
29
34
 
30
- function normalizeCodexArgs(args) {
35
+ function normalizeAgentArgs(args) {
31
36
  return args.filter((arg) => arg !== "--madmax" && arg !== "--high");
32
37
  }
33
38
 
34
- function resolveCodexCommand() {
35
- if (process.env.MA_CODEX_BIN) {
36
- return process.env.MA_CODEX_BIN;
37
- }
38
-
39
- return "codex";
40
- }
41
-
42
- export function runCodex(args) {
43
- const codexCommand = resolveCodexCommand();
44
- const codexArgs = normalizeCodexArgs(args);
45
- const commandArgs =
46
- path.extname(codexCommand) === ".js" || path.extname(codexCommand) === ".mjs"
47
- ? [codexCommand, ...codexArgs]
48
- : codexArgs;
49
- const command = commandArgs[0] === codexCommand ? process.execPath : codexCommand;
50
- const finalArgs = command === process.execPath ? commandArgs : codexArgs;
51
- const result = spawnSync(command, finalArgs, { stdio: "inherit" });
39
+ export function runAgent(args, agentType = process.env.MA_AGENT || "codex") {
40
+ const agent = getAgent(agentType);
41
+ const agentCommand = resolveAgentCommand(agent.id);
42
+ if (!agentCommand) throw new Error(`Agent "${agent.id}" has no executable command`);
43
+ const agentArgs = normalizeAgentArgs(args);
44
+ const commandArgs = [".js", ".mjs", ".cjs"].includes(path.extname(agentCommand))
45
+ ? [agentCommand, ...agentArgs]
46
+ : agentArgs;
47
+ const command = commandArgs[0] === agentCommand ? process.execPath : agentCommand;
48
+ const finalArgs = command === process.execPath ? commandArgs : agentArgs;
49
+ const result = safeSpawnSync(command, finalArgs, { stdio: "inherit" });
52
50
 
53
51
  if (result.error) {
54
52
  if (result.error.code === "ENOENT") {
55
- throw new Error("Codex not found. Install it with: npm install -g @openai/codex");
53
+ throw new Error(`${agent.displayName} not found. Install the selected agent and retry.`);
56
54
  }
57
55
 
58
- throw new Error(`Failed to start Codex: ${result.error.message}`);
56
+ throw new Error(`Failed to start ${agent.displayName}: ${result.error.message}`);
59
57
  }
60
58
 
61
59
  return typeof result.status === "number" ? result.status : 1;
62
60
  }
61
+
62
+ export const shouldDelegateToCodex = shouldDelegateToAgent;
63
+ export function runCodex(args) {
64
+ return runAgent(args, "codex");
65
+ }
package/src/mcp-config.js CHANGED
@@ -4,7 +4,15 @@ import { pathToFileURL } from "node:url";
4
4
  import { getBundledMcpPath, getMcpLocalCapabilitiesPath, getMcpServersPath } from "./paths.js";
5
5
 
6
6
  const gitMcpRepoPattern = /^https:\/\/gitmcp\.io\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
7
- const localCapabilityNames = ["_state", "memory", "trace", "team_run", "code_intel", "playbooks"];
7
+ const localCapabilityNames = [
8
+ "_state",
9
+ "memory",
10
+ "trace",
11
+ "team_run",
12
+ "code_intel",
13
+ "playbooks",
14
+ "context",
15
+ ];
8
16
  const localCapabilityNameSet = new Set(localCapabilityNames);
9
17
 
10
18
  function validateObjectWithArray(parsed, arrayField, label) {