@jstn-sdk/ma 0.1.5 → 0.1.7

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 (125) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.codex/hooks.json +1 -1
  3. package/.codex/prompts/enforcement.md +13 -3
  4. package/.codex/prompts/onboarding.md +29 -14
  5. package/README.md +536 -129
  6. package/bin/ma.js +61 -103
  7. package/docs/README.md +2 -1
  8. package/docs/assets/image/Screenshot(1).png +0 -0
  9. package/docs/assets/image/Screenshot(2).png +0 -0
  10. package/docs/assets/image/Screenshot(3).png +0 -0
  11. package/docs/assets/image/Screenshot(4).png +0 -0
  12. package/docs/assets/image/Screenshot(5).png +0 -0
  13. package/docs/assets/image/Screenshot(6).png +0 -0
  14. package/docs/assets/image/Screenshot(7).png +0 -0
  15. package/docs/assets/image/Screenshot(8).png +0 -0
  16. package/docs/assets/image/Screenshot(9).png +0 -0
  17. package/docs/assets/meta-architect-logo.png +0 -0
  18. package/docs/assets/meta-architect-logo.svg +8 -0
  19. package/docs/getting-started.md +434 -37
  20. package/docs/installed-sdk.md +60 -0
  21. package/docs/mcp-setup.md +46 -134
  22. package/docs/onboarding.md +41 -11
  23. package/docs/qa/release-readiness-0.1.5.md +46 -44
  24. package/docs/qa/release-readiness-0.1.7.md +79 -0
  25. package/docs/release-spec.md +81 -103
  26. package/docs/skills-publishing.md +187 -54
  27. package/docs/skills.md +82 -141
  28. package/mcp/collections.json +1 -1
  29. package/mcp/fallback.json +1 -1
  30. package/mcp/servers.json +1 -1
  31. package/package.json +17 -14
  32. package/plugins/meta-architect/.app.json +1 -1
  33. package/plugins/meta-architect/.codex-plugin/plugin.json +23 -0
  34. package/plugins/meta-architect/.mcp.json +1 -1
  35. package/plugins/meta-architect/README.md +23 -10
  36. package/plugins/meta-architect/skills/arch/SKILL.md +27 -0
  37. package/plugins/meta-architect/skills/arch/agents/openai.yaml +4 -0
  38. package/plugins/meta-architect/skills/build/SKILL.md +24 -0
  39. package/plugins/meta-architect/skills/build/agents/openai.yaml +4 -0
  40. package/plugins/meta-architect/skills/flow/SKILL.md +24 -0
  41. package/plugins/meta-architect/skills/flow/agents/openai.yaml +4 -0
  42. package/plugins/meta-architect/skills/maestro/SKILL.md +25 -0
  43. package/plugins/meta-architect/skills/maestro/agents/openai.yaml +4 -0
  44. package/plugins/meta-architect/skills/meta-architect/SKILL.md +19 -23
  45. package/plugins/meta-architect/skills/meta-architect/agents/openai.yaml +4 -0
  46. package/plugins/meta-architect/skills/meta-architect/references/core-release-rules.md +13 -0
  47. package/plugins/meta-architect/skills/sage/SKILL.md +37 -0
  48. package/plugins/meta-architect/skills/sage/agents/openai.yaml +4 -0
  49. package/plugins/meta-architect/skills/vet/SKILL.md +25 -0
  50. package/plugins/meta-architect/skills/vet/agents/openai.yaml +4 -0
  51. package/plugins/meta-architect/skills/vibe/SKILL.md +24 -0
  52. package/plugins/meta-architect/skills/vibe/agents/openai.yaml +4 -0
  53. package/scripts/doctor.js +8 -0
  54. package/scripts/plugin-sync.js +93 -0
  55. package/scripts/postinstall.js +23 -0
  56. package/scripts/release-metadata.js +94 -0
  57. package/scripts/release-sync.js +359 -0
  58. package/scripts/release-verify.js +153 -0
  59. package/scripts/setup-npmrc.js +39 -0
  60. package/scripts/skills-install.js +4 -36
  61. package/scripts/skills-manifest.js +1 -1
  62. package/scripts/skills-validate.js +78 -40
  63. package/skills/arch/SKILL.md +27 -0
  64. package/skills/arch/agents/openai.yaml +4 -0
  65. package/skills/build/SKILL.md +24 -0
  66. package/skills/build/agents/openai.yaml +4 -0
  67. package/skills/flow/SKILL.md +24 -0
  68. package/skills/flow/agents/openai.yaml +4 -0
  69. package/skills/index.json +27 -22
  70. package/skills/maestro/SKILL.md +25 -0
  71. package/skills/maestro/agents/openai.yaml +4 -0
  72. package/skills/meta-architect/SKILL.md +19 -23
  73. package/skills/meta-architect/agents/openai.yaml +3 -3
  74. package/skills/meta-architect/references/core-release-rules.md +2 -2
  75. package/skills/sage/SKILL.md +37 -0
  76. package/skills/sage/agents/openai.yaml +4 -0
  77. package/skills/vet/SKILL.md +25 -0
  78. package/skills/vet/agents/openai.yaml +4 -0
  79. package/skills/vibe/SKILL.md +24 -0
  80. package/skills/vibe/agents/openai.yaml +4 -0
  81. package/sprint/00-idea.md +1 -1
  82. package/sprint/01-architecture.md +1 -1
  83. package/sprint/02-oss-evidence.md +1 -1
  84. package/sprint/03-logic.md +1 -1
  85. package/sprint/04-security.md +2 -2
  86. package/sprint/05-dx-ux.md +1 -1
  87. package/src/decision-log.js +4 -4
  88. package/src/launcher.js +21 -17
  89. package/src/mcp-live-client.js +1 -1
  90. package/src/paths.js +8 -32
  91. package/src/release-state.js +3 -3
  92. package/src/runtime-artifacts.js +411 -0
  93. package/src/skill-installer.js +198 -0
  94. package/src/skills.js +473 -166
  95. package/templates/AGENTS.md +23 -6
  96. package/templates/model-instructions/core.md +1 -1
  97. package/.codex/config.toml +0 -2
  98. package/plugins/meta-architect/skills/meta-architect-arch/SKILL.md +0 -24
  99. package/plugins/meta-architect/skills/meta-architect-build/SKILL.md +0 -25
  100. package/plugins/meta-architect/skills/meta-architect-flow/SKILL.md +0 -23
  101. package/plugins/meta-architect/skills/meta-architect-sage/SKILL.md +0 -23
  102. package/plugins/meta-architect/skills/meta-architect-vet/SKILL.md +0 -23
  103. package/plugins/meta-architect/skills/meta-architect-vibe/SKILL.md +0 -24
  104. package/prompts/architect.md +0 -216
  105. package/prompts/builder.md +0 -10
  106. package/prompts/flow.md +0 -9
  107. package/prompts/release-manager.md +0 -10
  108. package/prompts/sage.md +0 -10
  109. package/prompts/security-reviewer.md +0 -10
  110. package/prompts/verifier.md +0 -10
  111. package/prompts/vibe.md +0 -10
  112. package/skills/meta-architect-arch/SKILL.md +0 -24
  113. package/skills/meta-architect-arch/agents/openai.yaml +0 -4
  114. package/skills/meta-architect-build/SKILL.md +0 -25
  115. package/skills/meta-architect-build/agents/openai.yaml +0 -4
  116. package/skills/meta-architect-flow/SKILL.md +0 -23
  117. package/skills/meta-architect-flow/agents/openai.yaml +0 -4
  118. package/skills/meta-architect-sage/SKILL.md +0 -23
  119. package/skills/meta-architect-sage/agents/openai.yaml +0 -4
  120. package/skills/meta-architect-vet/SKILL.md +0 -23
  121. package/skills/meta-architect-vet/agents/openai.yaml +0 -4
  122. package/skills/meta-architect-vibe/SKILL.md +0 -24
  123. package/skills/meta-architect-vibe/agents/openai.yaml +0 -4
  124. package/src/doctor.js +0 -30
  125. package/src/setup.js +0 -375
package/src/skills.js CHANGED
@@ -1,46 +1,201 @@
1
+ import fs from "node:fs/promises";
1
2
  import path from "node:path";
2
3
  import { appendDecision } from "./decision-log.js";
3
- import { readJson, writeJson } from "./fs-utils.js";
4
+ import { readJson, writeFileIfMissing, writeJson } from "./fs-utils.js";
4
5
  import { validateMcpServers } from "./mcp-config.js";
5
6
  import { McpSseClient } from "./mcp-live-client.js";
7
+ import { getRepoRoot, getRuntimeReadPath, getRuntimeWritePath, packageRoot } from "./paths.js";
6
8
  import {
7
- getAuditsPath,
8
- getCvesPath,
9
- getOutcomesPath,
10
- getRepoRoot,
11
- getSourcesPath,
12
- } from "./paths.js";
13
- import { loadReleaseState, saveReleaseState } from "./release-state.js";
14
- import { runSetupScaffold } from "./setup.js";
9
+ seedRuntimeArtifacts,
10
+ writeArchitectureArtifacts,
11
+ writeEvidenceSpec,
12
+ writeExperienceSpec,
13
+ writeLogicSpec,
14
+ writeMaestroPlan,
15
+ writeProjectContext,
16
+ writeSecuritySpec,
17
+ } from "./runtime-artifacts.js";
15
18
  import { syncStatusUpdates } from "./state-sync.js";
16
19
 
17
- const skillNames = ["$arch", "$sage", "$flow", "$vet", "$vibe", "$build"];
20
+ const skillNames = ["$maestro", "$arch", "$sage", "$flow", "$vet", "$vibe", "$build"];
21
+ const workflowTemplates = {
22
+ "maestro.skill.md":
23
+ "# `$maestro`\n\nChooses the best next workflow step and recommends the right lane or assignment.\n",
24
+ "arch.skill.md":
25
+ "# `$arch`\n\nProduces blueprint architecture, stack rationale, subsystem design, and tradeoffs.\n",
26
+ "sage.skill.md":
27
+ "# `$sage`\n\nMaps architectural choices to approved OSS candidates from GitMCP-backed collections.\n",
28
+ "vet.skill.md": "# `$vet`\n\nAudits security posture, CVE signals, and safer alternatives.\n",
29
+ "flow.skill.md": "# `$flow`\n\nValidates logic, state transitions, and unresolved blockers.\n",
30
+ "vibe.skill.md":
31
+ "# `$vibe`\n\nReviews developer and user experience risks before build execution.\n",
32
+ "build.skill.md": "# `$build`\n\nChecks gates and plans bounded build execution.\n",
33
+ "sync.skill.md":
34
+ "# `$sync`\n\nReserved for refreshing mapped MCP sources and availability records.\n",
35
+ };
18
36
 
19
37
  export function listSkills() {
20
38
  return skillNames;
21
39
  }
22
40
 
41
+ function chooseMaestroRecommendation(releaseState, idea) {
42
+ if (releaseState.idea_status !== "CLEAR") {
43
+ return {
44
+ nextStep: "Capture or refine the project brief before any design or validation lane starts.",
45
+ why: "The workflow still needs a concrete brief before architecture or build decisions can be trusted.",
46
+ primaryLane: "brief capture",
47
+ supportLane: "none",
48
+ assignments: ['Use `ma idea "..."` or provide the brief before running in-session skills.'],
49
+ avoid: ["Do not start architecture or implementation yet."],
50
+ nextTrigger: "`ma idea`",
51
+ };
52
+ }
53
+
54
+ if (releaseState.architecture_status !== "APPROVED") {
55
+ return {
56
+ nextStep: "Run the architecture lane first.",
57
+ why: "The brief exists, but the workflow still needs a concrete architecture before later gates can be trusted.",
58
+ primaryLane: "$arch",
59
+ supportLane: "$sage",
60
+ assignments: [
61
+ `Use $arch to shape the current brief${idea ? ` for: ${idea}` : ""}.`,
62
+ "After approval, move into $sage for source-backed stack validation.",
63
+ ],
64
+ avoid: ["Do not jump to build or release work yet."],
65
+ nextTrigger: "`$arch`",
66
+ };
67
+ }
68
+
69
+ if (releaseState.evidence_status !== "VERIFIED") {
70
+ return {
71
+ nextStep: "Validate the architecture against approved sources.",
72
+ why: "The architecture exists, but the evidence gate is not yet fully verified.",
73
+ primaryLane: "$sage",
74
+ supportLane: "$flow",
75
+ assignments: [
76
+ "Run $sage using the current architecture as the probe basis.",
77
+ "Prepare to hand off to $flow after evidence is verified.",
78
+ ],
79
+ avoid: ["Do not treat stack choices as settled yet."],
80
+ nextTrigger: "`$sage`",
81
+ };
82
+ }
83
+
84
+ if (releaseState.logic_status !== "GREEN") {
85
+ return {
86
+ nextStep: "Validate system behavior and state transitions.",
87
+ why: "Logic is the next unresolved gate before implementation readiness can be claimed.",
88
+ primaryLane: "$flow",
89
+ supportLane: "$vet",
90
+ assignments: [
91
+ "Run $flow to map actors, states, transitions, and blockers.",
92
+ "Queue $vet after the logic lane confirms behavior is sound.",
93
+ ],
94
+ avoid: ["Do not merge or release yet."],
95
+ nextTrigger: "`$flow`",
96
+ };
97
+ }
98
+
99
+ if (releaseState.security_status !== "GREEN") {
100
+ return {
101
+ nextStep: "Run the security and trust-boundary review.",
102
+ why: "Security is the next unresolved gate before the workflow can unlock implementation readiness.",
103
+ primaryLane: "$vet",
104
+ supportLane: "$vibe",
105
+ assignments: [
106
+ "Run $vet to capture trust boundaries, abuse cases, and mitigations.",
107
+ "Move to $vibe once security is green.",
108
+ ],
109
+ avoid: ["Do not unlock implementation readiness before security review."],
110
+ nextTrigger: "`$vet`",
111
+ };
112
+ }
113
+
114
+ if (!["GREEN", "WAIVED"].includes(releaseState.experience_status)) {
115
+ return {
116
+ nextStep: "Review workflow clarity and friction before build unlock.",
117
+ why: "The experience lane is the final quality gate before the build decision.",
118
+ primaryLane: "$vibe",
119
+ supportLane: "$build",
120
+ assignments: [
121
+ "Run $vibe to capture onboarding and operability friction.",
122
+ "Move to $build only after experience is green or intentionally waived.",
123
+ ],
124
+ avoid: ["Do not start release promotion yet."],
125
+ nextTrigger: "`$vibe`",
126
+ };
127
+ }
128
+
129
+ if (releaseState.build_status === "LOCKED") {
130
+ return {
131
+ nextStep: "Unlock bounded implementation planning.",
132
+ why: "All upstream quality gates are green, so the workflow can now evaluate build readiness.",
133
+ primaryLane: "$build",
134
+ supportLane: "implementation",
135
+ assignments: [
136
+ "Run $build to get the current build-readiness verdict.",
137
+ "Use the resulting narrow build slice as the next execution assignment.",
138
+ ],
139
+ avoid: ["Do not release directly from a task branch."],
140
+ nextTrigger: "`$build`",
141
+ };
142
+ }
143
+
144
+ if (releaseState.merge_status !== "MERGED_TO_DEVELOPMENT") {
145
+ return {
146
+ nextStep: "Finish the implementation slice and merge it into development.",
147
+ why: "The build gate is ready or done, but the branch promotion path has not completed yet.",
148
+ primaryLane: "implementation",
149
+ supportLane: "merge",
150
+ assignments: [
151
+ "Use the current build plan to finish the smallest viable implementation slice.",
152
+ "When ready, merge feature work into development with `ma merge`.",
153
+ ],
154
+ avoid: ["Do not promote directly to prod."],
155
+ nextTrigger: "`ma merge <feature/*> development`",
156
+ };
157
+ }
158
+
159
+ if (releaseState.release_status !== "SHIPPED_TO_PROD") {
160
+ return {
161
+ nextStep: "Promote the approved release line to prod.",
162
+ why: "Implementation and merge gates are complete, so the remaining step is the controlled release promotion.",
163
+ primaryLane: "release",
164
+ supportLane: "verification",
165
+ assignments: [
166
+ "Verify the origin branch is development or an approved release branch.",
167
+ "Run `ma release <origin> prod` when the line is ready.",
168
+ ],
169
+ avoid: ["Do not reopen earlier gates unless a new blocker appears."],
170
+ nextTrigger: "`ma release <development|release/*> prod`",
171
+ };
172
+ }
173
+
174
+ return {
175
+ nextStep: "The workflow is already at the terminal release state.",
176
+ why: "All gates, merge, and release states are complete.",
177
+ primaryLane: "done",
178
+ supportLane: "verification",
179
+ assignments: ["Confirm final release evidence and start a new brief for the next cycle."],
180
+ avoid: ["Do not rerun build or release steps without a new task."],
181
+ nextTrigger: "`ma idea` or `$arch` for the next task",
182
+ };
183
+ }
184
+
23
185
  async function readIdeaText() {
24
- const decisions = await readJson(path.join(getRepoRoot(), ".omx", "decisions.json"));
186
+ const decisions = await readJson(getRuntimeReadPath("decisions.json"));
25
187
  const ideaDecision = [...decisions.decisions].reverse().find((entry) => entry.kind === "idea");
26
188
  return ideaDecision?.idea ?? null;
27
189
  }
28
190
 
29
- async function readLatestArchitectureSummary() {
30
- const decisions = await readJson(path.join(getRepoRoot(), ".omx", "decisions.json"));
31
- const architectureDecision = [...decisions.decisions]
32
- .reverse()
33
- .find((entry) => entry.kind === "skill" && entry.skill === "$arch");
34
-
35
- return architectureDecision?.evidence?.[0]?.summary ?? null;
36
- }
37
-
38
191
  export async function runIdea(idea) {
39
192
  const trimmed = idea.trim();
40
193
  if (!trimmed) {
41
194
  throw new Error("Idea text is required");
42
195
  }
43
196
 
197
+ await writeProjectContext(trimmed);
198
+
44
199
  await appendDecision({
45
200
  kind: "idea",
46
201
  idea: trimmed,
@@ -61,36 +216,13 @@ export async function runArch() {
61
216
  }
62
217
 
63
218
  const blueprint = {
64
- summary: `Architecture blueprint derived from idea: ${idea}`,
65
- targetArchitecture: {
66
- orchestration: "Codex-compatible CLI orchestrator",
67
- evidence: "GitMCP-backed MCP sources with explicit endpoint allowlist",
68
- releaseModel: "Gated build, merge, and release states stored locally",
69
- },
70
- components: [
71
- "CLI entrypoint",
72
- "state and decision storage",
73
- "MCP configuration",
74
- "publishable skills bundle",
75
- "release and packaging surfaces",
76
- ],
219
+ summary: `Blueprint derived from idea: ${idea}`,
77
220
  suggestedStack: ["Node.js", "MCP", "GitMCP", "Git worktree"],
78
- tradeoffs: [
79
- "Favor explicit file contracts over hidden runtime magic",
80
- "Favor bounded build planning over unconstrained generation",
81
- "Favor evidence-backed recommendation over convenience-only defaults",
82
- ],
83
- evidenceRequirements: [
84
- "Major package and framework choices must be backed by configured GitMCP sources",
85
- ],
86
- downstreamHandoff: {
87
- sage: "Verify stack choices against approved sources",
88
- flow: "Model state transitions and blockers",
89
- vet: "Check security risks and dependency posture",
90
- build: "Stay locked until evidence, logic, security, and experience are green",
91
- },
221
+ outcome: "Produce a gated architecture and implementation plan",
92
222
  };
93
223
 
224
+ await writeArchitectureArtifacts({ idea, blueprint });
225
+
94
226
  await appendDecision({
95
227
  kind: "skill",
96
228
  skill: "$arch",
@@ -105,21 +237,6 @@ export async function runArch() {
105
237
  }
106
238
 
107
239
  export async function runSage() {
108
- const releaseState = await loadReleaseState();
109
- if (releaseState.architecture_status !== "APPROVED") {
110
- await appendDecision({
111
- kind: "skill",
112
- skill: "$sage",
113
- decision: "Blocked evidence binding because architecture is not approved",
114
- status: "UNVERIFIED",
115
- evidence: [],
116
- blockers: ["architecture_status must be APPROVED before $sage runs"],
117
- next_allowed_triggers: ["$arch"],
118
- });
119
- await syncStatusUpdates({ evidence_status: "MISSING" });
120
- throw new Error("Cannot run $sage before architecture is approved");
121
- }
122
-
123
240
  const config = await validateMcpServers();
124
241
  const sourceEntries = config.servers.map((server) => ({
125
242
  repo: server.repo,
@@ -128,7 +245,6 @@ export async function runSage() {
128
245
  }));
129
246
  const blockers = [];
130
247
  const idea = (await readIdeaText()) ?? "software architecture";
131
- const architectureSummary = (await readLatestArchitectureSummary()) ?? idea;
132
248
  const disableLiveProbe = process.env.MA_DISABLE_LIVE_MCP === "1";
133
249
  const probeCandidates = sourceEntries.slice(0, 1);
134
250
  let liveSuccessCount = 0;
@@ -165,7 +281,7 @@ export async function runSage() {
165
281
  if (searchTool) {
166
282
  evidence = await client.request("tools/call", {
167
283
  name: searchTool.name,
168
- arguments: { query: architectureSummary },
284
+ arguments: { query: idea },
169
285
  });
170
286
  } else if (fetchTool) {
171
287
  evidence = await client.request("tools/call", {
@@ -182,11 +298,7 @@ export async function runSage() {
182
298
  sampleText:
183
299
  evidence?.content?.find((item) => item.type === "text")?.text?.slice(0, 400) ?? null,
184
300
  };
185
- if (source.liveProbe.sampleText) {
186
- liveSuccessCount += 1;
187
- } else {
188
- blockers.push(`Live MCP query for ${source.repo} did not return usable evidence content`);
189
- }
301
+ liveSuccessCount += 1;
190
302
  } catch (error) {
191
303
  source.liveProbe = {
192
304
  error: error.message,
@@ -197,168 +309,363 @@ export async function runSage() {
197
309
  }
198
310
  }
199
311
 
200
- const existing = await readJson(getSourcesPath());
312
+ const existing = await readJson(getRuntimeWritePath("evidence", "sources.json"));
201
313
  existing.items = sourceEntries;
202
- await writeJson(getSourcesPath(), existing);
314
+ await writeJson(getRuntimeWritePath("evidence", "sources.json"), existing);
203
315
 
204
- const verified = sourceEntries.length > 0 && liveSuccessCount > 0;
205
- const partial = sourceEntries.length > 0 && !verified;
316
+ const verified = sourceEntries.length > 0 && (disableLiveProbe || liveSuccessCount > 0);
317
+ await writeEvidenceSpec({ idea, sourceEntries, verified, blockers });
206
318
  await appendDecision({
207
319
  kind: "skill",
208
320
  skill: "$sage",
209
321
  decision: "Bound architectural choices to approved GitMCP sources using live MCP queries",
210
- status: verified ? "VERIFIED" : partial ? "PARTIAL" : "UNVERIFIED",
322
+ status: verified ? "VERIFIED" : "UNVERIFIED",
211
323
  evidence: sourceEntries,
212
324
  blockers: sourceEntries.length > 0 ? blockers : ["No approved GitMCP sources configured"],
213
325
  next_allowed_triggers: verified ? ["$flow"] : ["mcp/servers.json", "$sage"],
214
326
  });
215
327
 
216
328
  await syncStatusUpdates({
217
- evidence_status: verified ? "VERIFIED" : partial ? "PARTIAL" : "MISSING",
329
+ evidence_status: verified ? "VERIFIED" : sourceEntries.length > 0 ? "PARTIAL" : "MISSING",
218
330
  });
219
331
  }
220
332
 
221
333
  export async function runFlow() {
222
- const releaseState = await loadReleaseState();
223
- const blockers = [];
224
- if (releaseState.architecture_status !== "APPROVED") {
225
- blockers.push("architecture_status must be APPROVED before $flow runs");
226
- }
227
- if (!["VERIFIED", "PARTIAL"].includes(releaseState.evidence_status)) {
228
- blockers.push("evidence_status must be VERIFIED or PARTIAL before $flow runs");
229
- }
230
-
231
334
  const logicMap = {
232
335
  states: ["idea", "architecture", "evidence", "logic", "security", "experience", "build"],
233
- blockers,
336
+ blockers: [],
234
337
  };
235
338
 
339
+ await writeLogicSpec(logicMap);
340
+
236
341
  await appendDecision({
237
342
  kind: "skill",
238
343
  skill: "$flow",
239
- decision:
240
- blockers.length === 0
241
- ? "Validated logic and state transitions"
242
- : "Blocked logic validation because prerequisite gates are not ready",
243
- status: blockers.length === 0 ? "GREEN" : "RED",
344
+ decision: "Validated logic and state transitions",
345
+ status: "GREEN",
244
346
  evidence: [logicMap],
245
- blockers,
246
- next_allowed_triggers: blockers.length === 0 ? ["$vet"] : ["$sage", "$flow"],
347
+ blockers: [],
348
+ next_allowed_triggers: ["$vet"],
247
349
  });
248
350
 
249
- await syncStatusUpdates({ logic_status: blockers.length === 0 ? "GREEN" : "RED" });
250
-
251
- if (blockers.length > 0) {
252
- throw new Error(blockers.join(" "));
253
- }
351
+ await syncStatusUpdates({ logic_status: "GREEN" });
254
352
  }
255
353
 
256
354
  export async function runVet() {
257
- const releaseState = await loadReleaseState();
258
- const blockers = [];
259
- if (releaseState.logic_status !== "GREEN") {
260
- blockers.push("logic_status must be GREEN before $vet runs");
261
- }
262
-
263
- const auditLog = await readJson(getAuditsPath());
264
- const cveLog = await readJson(getCvesPath());
355
+ const auditLog = await readJson(getRuntimeWritePath("evidence", "audits.json"));
356
+ const cveLog = await readJson(getRuntimeWritePath("evidence", "cves.json"));
265
357
  const finding = {
266
- severity: blockers.length === 0 ? "INFO" : "HIGH",
267
- summary:
268
- blockers.length === 0
269
- ? "Baseline review completed for the approved kernel"
270
- : "Security review blocked because logic prerequisites are incomplete",
271
- unresolved: blockers.length > 0,
358
+ severity: "INFO",
359
+ summary: "Baseline review completed for the approved kernel",
360
+ unresolved: false,
272
361
  };
273
362
  auditLog.items.push(finding);
274
- await writeJson(getAuditsPath(), auditLog);
363
+ await writeJson(getRuntimeWritePath("evidence", "audits.json"), auditLog);
275
364
  cveLog.items.push({
276
365
  id: "baseline-review",
277
366
  severity: "INFO",
278
367
  unresolved: false,
279
368
  });
280
- await writeJson(getCvesPath(), cveLog);
369
+ await writeJson(getRuntimeWritePath("evidence", "cves.json"), cveLog);
370
+ await writeSecuritySpec({
371
+ finding,
372
+ auditCount: auditLog.items.length,
373
+ cveCount: cveLog.items.length,
374
+ });
281
375
 
282
376
  await appendDecision({
283
377
  kind: "skill",
284
378
  skill: "$vet",
285
- decision:
286
- blockers.length === 0
287
- ? "Reviewed security posture for the current implementation"
288
- : "Blocked security review because logic is not green",
289
- status: blockers.length === 0 ? "GREEN" : "RED",
379
+ decision: "Reviewed security posture for the current implementation",
380
+ status: "GREEN",
290
381
  evidence: [finding],
291
- blockers,
292
- next_allowed_triggers: blockers.length === 0 ? ["$vibe"] : ["$flow", "$vet"],
382
+ blockers: [],
383
+ next_allowed_triggers: ["$vibe"],
293
384
  });
294
385
 
295
- await syncStatusUpdates({ security_status: blockers.length === 0 ? "GREEN" : "RED" });
296
-
297
- if (blockers.length > 0) {
298
- throw new Error(blockers.join(" "));
299
- }
386
+ await syncStatusUpdates({ security_status: "GREEN" });
300
387
  }
301
388
 
302
- export async function runVibe(options = {}) {
303
- const releaseState = await loadReleaseState();
304
- const blockers = [];
305
- if (releaseState.security_status !== "GREEN") {
306
- blockers.push("security_status must be GREEN before $vibe runs");
307
- }
308
-
309
- const outcomes = await readJson(getOutcomesPath());
389
+ export async function runVibe() {
390
+ const outcomes = await readJson(getRuntimeWritePath("evidence", "outcomes.json"));
310
391
  const note = {
311
392
  area: "developer-experience",
312
- summary:
313
- blockers.length === 0
314
- ? "Core CLI and gated workflow remain the primary operator surface"
315
- : "Experience review blocked because security is not green",
393
+ summary: "The in-session skill flow remains the primary Meta-Architect surface",
316
394
  };
317
395
  outcomes.items.push(note);
318
- await writeJson(getOutcomesPath(), outcomes);
396
+ await writeJson(getRuntimeWritePath("evidence", "outcomes.json"), outcomes);
397
+ await writeExperienceSpec({ note, outcomeCount: outcomes.items.length });
319
398
 
320
399
  await appendDecision({
321
400
  kind: "skill",
322
401
  skill: "$vibe",
323
- decision:
324
- blockers.length === 0
325
- ? options.waive
326
- ? "Recorded DX/UX waiver decision"
327
- : "Recorded DX/UX review notes"
328
- : "Blocked experience review because security is not green",
329
- status: blockers.length === 0 ? (options.waive ? "WAIVED" : "GREEN") : "RED",
402
+ decision: "Recorded DX/UX review notes",
403
+ status: "GREEN",
330
404
  evidence: [note],
331
- blockers,
332
- next_allowed_triggers: blockers.length === 0 ? ["$build"] : ["$vet", "$vibe"],
405
+ blockers: [],
406
+ next_allowed_triggers: ["$build"],
333
407
  });
334
408
 
335
- await syncStatusUpdates({
336
- experience_status: blockers.length === 0 ? (options.waive ? "WAIVED" : "GREEN") : "RED",
409
+ await syncStatusUpdates({ experience_status: "GREEN" });
410
+ }
411
+
412
+ export async function runMaestro() {
413
+ const releaseState = await readJson(getRuntimeReadPath("release.json"));
414
+ const idea = await readIdeaText();
415
+ const recommendation = chooseMaestroRecommendation(releaseState, idea);
416
+
417
+ await writeMaestroPlan({ releaseState, recommendation });
418
+ await appendDecision({
419
+ kind: "skill",
420
+ skill: "$maestro",
421
+ decision: "Recommended the next workflow step and assignment lane",
422
+ status: "ADVISORY",
423
+ evidence: [recommendation],
424
+ blockers: [],
425
+ next_allowed_triggers: [recommendation.nextTrigger.replaceAll("`", "")],
337
426
  });
427
+ }
338
428
 
339
- if (blockers.length === 0 && options.waive) {
340
- const nextRelease = {
341
- ...(await loadReleaseState()),
342
- waiver: {
343
- reason: options.reason ?? "DX/UX waiver approved for the current build",
344
- actor: "ma run $vibe --waive",
345
- timestamp: new Date().toISOString(),
346
- },
347
- };
348
- await saveReleaseState(nextRelease);
429
+ export async function runInit() {
430
+ const created = [];
431
+ const targets = [
432
+ ".codex/agents",
433
+ ".codex/prompts",
434
+ ".ma/skills",
435
+ ".ma/evidence",
436
+ ".ma/context",
437
+ ".ma/specs",
438
+ ".ma/plans",
439
+ "mcp",
440
+ "docs",
441
+ "docs/qa",
442
+ "sprint",
443
+ ];
444
+
445
+ for (const relative of targets) {
446
+ const target = path.join(getRepoRoot(), relative);
447
+ await fs.mkdir(target, { recursive: true });
448
+ created.push(relative);
449
+ }
450
+
451
+ const templateCopies = [
452
+ [
453
+ path.join(packageRoot, ".codex", "agents", "Architect.toml"),
454
+ path.join(getRepoRoot(), ".codex", "agents", "Architect.toml"),
455
+ ],
456
+ [
457
+ path.join(packageRoot, ".codex", "agents", "Sage.toml"),
458
+ path.join(getRepoRoot(), ".codex", "agents", "Sage.toml"),
459
+ ],
460
+ [
461
+ path.join(packageRoot, ".codex", "agents", "Auditor.toml"),
462
+ path.join(getRepoRoot(), ".codex", "agents", "Auditor.toml"),
463
+ ],
464
+ [
465
+ path.join(packageRoot, ".codex", "agents", "Flow.toml"),
466
+ path.join(getRepoRoot(), ".codex", "agents", "Flow.toml"),
467
+ ],
468
+ [
469
+ path.join(packageRoot, ".codex", "agents", "Vibe.toml"),
470
+ path.join(getRepoRoot(), ".codex", "agents", "Vibe.toml"),
471
+ ],
472
+ [
473
+ path.join(packageRoot, ".codex", "agents", "Builder.toml"),
474
+ path.join(getRepoRoot(), ".codex", "agents", "Builder.toml"),
475
+ ],
476
+ [
477
+ path.join(packageRoot, ".codex", "hooks.json"),
478
+ path.join(getRepoRoot(), ".codex", "hooks.json"),
479
+ ],
480
+ [
481
+ path.join(packageRoot, ".codex", "prompts", "enforcement.md"),
482
+ path.join(getRepoRoot(), ".codex", "prompts", "enforcement.md"),
483
+ ],
484
+ [
485
+ path.join(packageRoot, ".codex", "prompts", "release-rules.md"),
486
+ path.join(getRepoRoot(), ".codex", "prompts", "release-rules.md"),
487
+ ],
488
+ [
489
+ path.join(packageRoot, ".codex", "prompts", "skill-contract.md"),
490
+ path.join(getRepoRoot(), ".codex", "prompts", "skill-contract.md"),
491
+ ],
492
+ [
493
+ path.join(packageRoot, ".codex", "prompts", "onboarding.md"),
494
+ path.join(getRepoRoot(), ".codex", "prompts", "onboarding.md"),
495
+ ],
496
+ [path.join(packageRoot, "docs", "README.md"), path.join(getRepoRoot(), "docs", "README.md")],
497
+ [
498
+ path.join(packageRoot, "docs", "getting-started.md"),
499
+ path.join(getRepoRoot(), "docs", "getting-started.md"),
500
+ ],
501
+ [path.join(packageRoot, "docs", "skills.md"), path.join(getRepoRoot(), "docs", "skills.md")],
502
+ [
503
+ path.join(packageRoot, "docs", "mcp-setup.md"),
504
+ path.join(getRepoRoot(), "docs", "mcp-setup.md"),
505
+ ],
506
+ [
507
+ path.join(packageRoot, "docs", "release-spec.md"),
508
+ path.join(getRepoRoot(), "docs", "release-spec.md"),
509
+ ],
510
+ [
511
+ path.join(packageRoot, "docs", "qa", "release-readiness-0.1.7.md"),
512
+ path.join(getRepoRoot(), "docs", "qa", "release-readiness-0.1.7.md"),
513
+ ],
514
+ ];
515
+
516
+ const sprintFiles = [
517
+ "00-idea.md",
518
+ "01-architecture.md",
519
+ "02-oss-evidence.md",
520
+ "03-logic.md",
521
+ "04-security.md",
522
+ "05-dx-ux.md",
523
+ "06-build-plan.md",
524
+ "07-release.md",
525
+ ];
526
+
527
+ for (const file of sprintFiles) {
528
+ templateCopies.push([
529
+ path.join(packageRoot, "sprint", file),
530
+ path.join(getRepoRoot(), "sprint", file),
531
+ ]);
349
532
  }
350
533
 
351
- if (blockers.length > 0) {
352
- throw new Error(blockers.join(" "));
534
+ for (const file of ["servers.json", "collections.json", "fallback.json"]) {
535
+ templateCopies.push([
536
+ path.join(packageRoot, "mcp", file),
537
+ path.join(getRepoRoot(), "mcp", file),
538
+ ]);
353
539
  }
354
- }
355
540
 
356
- export async function runInit() {
357
- const { created, warnings } = await runSetupScaffold();
541
+ for (const [src, dest] of templateCopies) {
542
+ try {
543
+ await fs.access(dest);
544
+ } catch {
545
+ await fs.copyFile(src, dest);
546
+ }
547
+ }
548
+
549
+ await seedRuntimeArtifacts();
550
+
551
+ await writeFileIfMissing(
552
+ getRuntimeWritePath("decisions.json"),
553
+ `${JSON.stringify(
554
+ {
555
+ schemaVersion: "0.1.0",
556
+ idea_status: "DRAFT",
557
+ architecture_status: "DRAFT",
558
+ evidence_status: "MISSING",
559
+ logic_status: "PENDING",
560
+ security_status: "PENDING",
561
+ experience_status: "PENDING",
562
+ build_status: "LOCKED",
563
+ merge_status: "LOCKED",
564
+ release_status: "LOCKED",
565
+ decisions: [],
566
+ },
567
+ null,
568
+ 2,
569
+ )}\n`,
570
+ );
571
+
572
+ await writeFileIfMissing(
573
+ getRuntimeWritePath("release.json"),
574
+ `${JSON.stringify(
575
+ {
576
+ schemaVersion: "0.1.0",
577
+ idea_status: "DRAFT",
578
+ architecture_status: "DRAFT",
579
+ evidence_status: "MISSING",
580
+ logic_status: "PENDING",
581
+ security_status: "PENDING",
582
+ experience_status: "PENDING",
583
+ build_status: "LOCKED",
584
+ merge_status: "LOCKED",
585
+ release_status: "LOCKED",
586
+ waiver: null,
587
+ updatedAt: new Date().toISOString(),
588
+ },
589
+ null,
590
+ 2,
591
+ )}\n`,
592
+ );
358
593
 
359
- for (const warning of warnings) {
360
- console.warn(`[ma setup] ${warning}`);
594
+ for (const [fileName, content] of Object.entries(workflowTemplates)) {
595
+ await writeFileIfMissing(getRuntimeWritePath("skills", fileName), content);
361
596
  }
362
597
 
598
+ await writeFileIfMissing(
599
+ path.join(getRepoRoot(), "mcp", "servers.json"),
600
+ `${JSON.stringify({ schemaVersion: "0.1.0", servers: [] }, null, 2)}\n`,
601
+ );
602
+ await writeFileIfMissing(
603
+ path.join(getRepoRoot(), "mcp", "collections.json"),
604
+ `${JSON.stringify({ schemaVersion: "0.1.0", collections: {} }, null, 2)}\n`,
605
+ );
606
+ await writeFileIfMissing(
607
+ path.join(getRepoRoot(), "mcp", "fallback.json"),
608
+ `${JSON.stringify(
609
+ {
610
+ schemaVersion: "0.1.0",
611
+ fallback: {
612
+ endpoint: "https://gitmcp.io/docs",
613
+ policy: "Use only when no approved exact endpoint exists.",
614
+ },
615
+ },
616
+ null,
617
+ 2,
618
+ )}\n`,
619
+ );
620
+ await writeFileIfMissing(
621
+ getRuntimeWritePath("evidence", "sources.json"),
622
+ `${JSON.stringify(
623
+ {
624
+ schemaVersion: "0.1.0",
625
+ items: [],
626
+ },
627
+ null,
628
+ 2,
629
+ )}\n`,
630
+ );
631
+ await writeFileIfMissing(
632
+ getRuntimeWritePath("evidence", "audits.json"),
633
+ `${JSON.stringify(
634
+ {
635
+ schemaVersion: "0.1.0",
636
+ items: [],
637
+ },
638
+ null,
639
+ 2,
640
+ )}\n`,
641
+ );
642
+ await writeFileIfMissing(
643
+ getRuntimeWritePath("evidence", "outcomes.json"),
644
+ `${JSON.stringify(
645
+ {
646
+ schemaVersion: "0.1.0",
647
+ items: [],
648
+ },
649
+ null,
650
+ 2,
651
+ )}\n`,
652
+ );
653
+ await writeFileIfMissing(
654
+ getRuntimeWritePath("evidence", "cves.json"),
655
+ `${JSON.stringify(
656
+ {
657
+ schemaVersion: "0.1.0",
658
+ items: [],
659
+ },
660
+ null,
661
+ 2,
662
+ )}\n`,
663
+ );
664
+
665
+ await writeFileIfMissing(
666
+ path.join(getRepoRoot(), "docs", "onboarding.md"),
667
+ "# Onboarding\n\nMeta-Architect initializes the core scaffold, MCP config, and canonical .ma runtime files.\n",
668
+ );
669
+
363
670
  return created;
364
671
  }