@jstn-sdk/ma 0.1.12 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/.codex/agents/Architect.toml +1 -2
  2. package/.codex/agents/Auditor.toml +1 -2
  3. package/.codex/agents/Builder.toml +1 -2
  4. package/.codex/agents/Flow.toml +1 -2
  5. package/.codex/agents/Sage.toml +1 -2
  6. package/.codex/agents/Vibe.toml +1 -2
  7. package/.codex/hooks.json +24 -13
  8. package/.codex/prompts/enforcement.md +4 -0
  9. package/.codex/prompts/onboarding.md +6 -1
  10. package/.codex/prompts/release-rules.md +0 -0
  11. package/.codex/prompts/skill-contract.md +4 -0
  12. package/COVERAGE.md +211 -0
  13. package/DEMO.md +274 -0
  14. package/LICENSE +0 -0
  15. package/README.md +132 -656
  16. package/bin/ma.js +748 -55
  17. package/data/clone-data.ledger.json +41 -0
  18. package/data/clone-data.proof.json +50 -0
  19. package/data/clone-data.rvf +37 -0
  20. package/docs/README.md +10 -1
  21. package/docs/autonomous-tasks.md +46 -0
  22. package/docs/codex-integration.md +16 -0
  23. package/docs/getting-started.md +62 -22
  24. package/docs/mcp-setup.md +64 -0
  25. package/docs/qa/release-issue-gates-0.14.0.json +644 -0
  26. package/docs/qa/release-readiness-0.1.5.md +1 -1
  27. package/docs/qa/{release-readiness-0.1.12.md → release-readiness-0.14.0.md} +25 -9
  28. package/docs/quality.md +24 -0
  29. package/docs/reference/native-security-playbooks.md +6 -0
  30. package/docs/reference/native-source-selection.md +6 -0
  31. package/docs/release-spec.md +39 -10
  32. package/docs/skills.md +14 -1
  33. package/index.js +295 -2
  34. package/mcp/collections.json +23 -6
  35. package/mcp/fallback.json +0 -0
  36. package/mcp/local/code-intel.js +179 -41
  37. package/mcp/local/context.js +180 -0
  38. package/mcp/local/memory.js +17 -6
  39. package/mcp/local/quality.js +39 -0
  40. package/mcp/local/state.js +7 -3
  41. package/mcp/local/team-run.js +56 -4
  42. package/mcp/local-capabilities.json +9 -0
  43. package/mcp/servers.json +24 -0
  44. package/package.json +29 -4
  45. package/plugins/meta-architect/.app.json +1 -1
  46. package/plugins/meta-architect/.codex-plugin/plugin.json +1 -1
  47. package/plugins/meta-architect/.mcp.json +1 -1
  48. package/plugins/meta-architect/README.md +8 -1
  49. package/plugins/meta-architect/obsidian/main.js +534 -0
  50. package/plugins/meta-architect/obsidian/manifest.json +9 -0
  51. package/plugins/meta-architect/obsidian/styles.css +7 -0
  52. package/plugins/meta-architect/skills/arch/SKILL.md +2 -0
  53. package/plugins/meta-architect/skills/build/SKILL.md +3 -0
  54. package/plugins/meta-architect/skills/flow/SKILL.md +2 -0
  55. package/plugins/meta-architect/skills/sage/SKILL.md +2 -0
  56. package/plugins/meta-architect/skills/sage/references/source-selection.md +8 -0
  57. package/plugins/meta-architect/skills/vet/SKILL.md +2 -0
  58. package/plugins/meta-architect/skills/vet/references/security-playbooks.md +7 -0
  59. package/plugins/meta-architect/skills/vibe/SKILL.md +2 -0
  60. package/schemas/autonomous-task-queue.schema.json +56 -0
  61. package/schemas/handoff-packet.schema.json +36 -0
  62. package/schemas/setup-receipt.schema.json +28 -0
  63. package/schemas/skill-frontmatter.schema.json +20 -0
  64. package/schemas/support-bundle.schema.json +37 -0
  65. package/schemas/task-contract.schema.json +31 -0
  66. package/scripts/active-autonomy-hook.mjs +226 -0
  67. package/scripts/build-linux-packages.mjs +7 -3
  68. package/scripts/cleanup-test-fixtures.sh +55 -0
  69. package/scripts/context-hydration-hook.mjs +89 -0
  70. package/scripts/demo-smoke.js +285 -0
  71. package/scripts/doctor.js +27 -12
  72. package/scripts/install.sh +57 -0
  73. package/scripts/install.sh.sha256 +1 -0
  74. package/scripts/linux-package-smoke.mjs +2 -2
  75. package/scripts/package-size-check.mjs +26 -0
  76. package/scripts/plugin-sync.js +83 -17
  77. package/scripts/postinstall.js +17 -10
  78. package/scripts/prepack.js +9 -0
  79. package/scripts/ralph/prompt.md +35 -0
  80. package/scripts/release-sync.js +72 -7
  81. package/scripts/release-verify.js +260 -2
  82. package/scripts/setup-npmrc.js +48 -23
  83. package/scripts/skills-install.js +9 -2
  84. package/scripts/skills-manifest.js +2 -21
  85. package/scripts/skills-pack.js +2 -2
  86. package/scripts/skills-validate.js +5 -55
  87. package/skills/arch/SKILL.md +2 -0
  88. package/skills/build/SKILL.md +3 -0
  89. package/skills/flow/SKILL.md +2 -0
  90. package/skills/index.json +0 -0
  91. package/skills/sage/SKILL.md +2 -0
  92. package/skills/sage/references/source-selection.md +8 -0
  93. package/skills/vet/SKILL.md +2 -0
  94. package/skills/vet/references/security-playbooks.md +7 -0
  95. package/skills/vibe/SKILL.md +2 -0
  96. package/sprint/00-idea.md +0 -0
  97. package/sprint/01-architecture.md +0 -0
  98. package/sprint/02-oss-evidence.md +0 -0
  99. package/sprint/03-logic.md +0 -0
  100. package/sprint/04-security.md +0 -0
  101. package/sprint/05-dx-ux.md +0 -0
  102. package/sprint/06-build-plan.md +0 -0
  103. package/sprint/07-release.md +0 -0
  104. package/src/agents.js +279 -0
  105. package/src/bootstrap.js +268 -62
  106. package/src/build-gate.js +2 -2
  107. package/src/codex-app-server.js +291 -0
  108. package/src/decision-log.js +0 -0
  109. package/src/fs-utils.js +175 -4
  110. package/src/launcher.js +28 -21
  111. package/src/mcp-config.js +9 -1
  112. package/src/mcp-live-client.js +422 -3
  113. package/src/paths.js +10 -1
  114. package/src/policy.js +3 -3
  115. package/src/prelaunch.js +189 -0
  116. package/src/quality/ai-quality-orchestrator.js +328 -0
  117. package/src/release-issue-gates.js +252 -0
  118. package/src/release-operations.js +62 -0
  119. package/src/release-state.js +0 -0
  120. package/src/runtime/active-autonomy-core.js +208 -0
  121. package/src/runtime/agent-compat.js +31 -0
  122. package/src/runtime/alignment-sentinel.js +165 -0
  123. package/src/runtime/architect-review.js +326 -0
  124. package/src/runtime/autonomous-tasks.js +408 -0
  125. package/src/runtime/build-readiness.js +28 -4
  126. package/src/runtime/code-graph-rehearse.js +113 -0
  127. package/src/runtime/codeburn-core.js +112 -0
  128. package/src/runtime/context-authority.js +40 -0
  129. package/src/runtime/context-economy-core.js +316 -0
  130. package/src/runtime/continuity-graph.js +201 -0
  131. package/src/runtime/continuity-notes.js +71 -26
  132. package/src/runtime/core-source-ingest.js +379 -0
  133. package/src/runtime/detached-provider.js +142 -0
  134. package/src/runtime/doctor-report.js +18 -0
  135. package/src/runtime/environment-awareness-core.js +460 -0
  136. package/src/runtime/exposure-catalog.js +276 -0
  137. package/src/runtime/graphify-core.js +167 -0
  138. package/src/runtime/guidance-stack.js +9 -2
  139. package/src/runtime/handoff-packets.js +92 -0
  140. package/src/runtime/headroom-core.js +104 -0
  141. package/src/runtime/helper-orchestration-core.js +307 -0
  142. package/src/runtime/hook-profiles.js +20 -0
  143. package/src/runtime/learning-loop-core.js +344 -0
  144. package/src/runtime/live-agent-verification.js +122 -0
  145. package/src/runtime/maestro-events.js +18 -0
  146. package/src/runtime/maestro-manager.js +19 -0
  147. package/src/runtime/maestro-output.js +58 -0
  148. package/src/runtime/maestro-state.js +125 -0
  149. package/src/runtime/managed-markdown.js +29 -0
  150. package/src/runtime/mcp-authority.js +147 -0
  151. package/src/runtime/mcp-policy.js +192 -0
  152. package/src/runtime/obsidian-integration-core.js +1089 -0
  153. package/src/runtime/obsidian-plugin-bridge.js +1045 -0
  154. package/src/runtime/pi-maestro-core.js +89 -0
  155. package/src/runtime/preferences.js +79 -0
  156. package/src/runtime/project-context.js +636 -0
  157. package/src/runtime/prompt-strategy-core.js +230 -0
  158. package/src/runtime/quorum-review.js +90 -0
  159. package/src/runtime/ralph-execution-core.js +217 -0
  160. package/src/runtime/redaction-gateway.js +373 -0
  161. package/src/runtime/runtime-state.js +935 -2
  162. package/src/runtime/schema-migrations.js +162 -0
  163. package/src/runtime/semantic-recording-core.js +147 -0
  164. package/src/runtime/signal-hooks.js +28 -0
  165. package/src/runtime/skills-registry-export.js +754 -0
  166. package/src/runtime/task-contracts.js +83 -0
  167. package/src/runtime/universal-plugin-broker-core.js +898 -0
  168. package/src/runtime/workspace-intelligence-runtime.js +674 -0
  169. package/src/runtime/workspace-virtualizer.js +102 -0
  170. package/src/runtime-artifacts.js +225 -62
  171. package/src/setup-lifecycle.js +359 -0
  172. package/src/skill-frontmatter.js +78 -0
  173. package/src/skill-installer.js +226 -71
  174. package/src/skills.js +1166 -96
  175. package/src/state-sync.js +0 -0
  176. package/src/test-fixtures.js +543 -0
  177. package/src/tui/grid.js +67 -0
  178. package/src/tui/status-grid.js +23 -0
  179. package/support-bundle.json +114 -0
  180. package/templates/AGENTS.md +6 -2
  181. package/templates/catalog-manifest.json +0 -0
  182. package/templates/model-instructions/core.md +0 -0
  183. package/templates/model-instructions/release.md +0 -0
  184. package/templates/model-instructions/security.md +0 -0
  185. package/templates/quality/ai-quality-rules.yml +37 -0
  186. package/docs/assets/image/Screenshot(1).png +0 -0
  187. package/docs/assets/image/Screenshot(2).png +0 -0
  188. package/docs/assets/image/Screenshot(3).png +0 -0
  189. package/docs/assets/image/Screenshot(4).png +0 -0
  190. package/docs/assets/image/Screenshot(5).png +0 -0
  191. package/docs/assets/image/Screenshot(6).png +0 -0
  192. package/docs/assets/image/Screenshot(7).png +0 -0
  193. package/docs/assets/image/Screenshot(8).png +0 -0
  194. package/docs/assets/image/Screenshot(9).png +0 -0
  195. package/docs/assets/meta-architect-logo.png +0 -0
  196. package/docs/assets/meta-architect-logo.svg +0 -8
  197. package/docs/onboarding.md +0 -65
  198. package/docs/skills-publishing.md +0 -255
@@ -1,20 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import fs from "node:fs/promises";
3
4
  import process from "node:process";
4
- import { installSkills, installSupportBundle } from "../src/skill-installer.js";
5
5
 
6
6
  async function main() {
7
- if (process.env.MA_SKIP_AUTO_INSTALL === "1") {
8
- console.log("meta-architect: skipped Codex skill auto-install");
7
+ const dryRun = process.env.MA_POSTINSTALL_DRY_RUN === "1";
8
+ const skipSkills = process.env.MA_SKIP_SKILLS === "1";
9
+ const receiptPath = process.env.MA_POSTINSTALL_RECEIPT;
10
+ console.log(
11
+ `meta-architect: postinstall skills=${skipSkills ? "disabled" : "enabled"} dry-run=${dryRun ? "yes" : "no"}`,
12
+ );
13
+ if (dryRun || skipSkills || process.env.MA_SKIP_AUTO_INSTALL === "1") {
14
+ console.log("meta-architect: deferred host selection until first interactive launch");
9
15
  return;
10
16
  }
11
-
12
- const [
13
- { targetRoot: skillRoot, installed: skills },
14
- { targetRoot: bundleRoot, installed: assets },
15
- ] = await Promise.all([installSkills(), installSupportBundle()]);
16
- console.log(`meta-architect: installed ${skills.length} Codex skills into ${skillRoot}`);
17
- console.log(`meta-architect: installed ${assets.length} support assets into ${bundleRoot}`);
17
+ console.log("meta-architect: host selection deferred until first interactive launch");
18
+ if (receiptPath) {
19
+ await fs.writeFile(
20
+ receiptPath,
21
+ `${JSON.stringify({ schemaVersion: "0.1.0", deferred: true }, null, 2)}\n`,
22
+ );
23
+ console.log(`meta-architect: receipt ${receiptPath}`);
24
+ }
18
25
  }
19
26
 
20
27
  main().catch((error) => {
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from "node:child_process";
4
+ import process from "node:process";
5
+
6
+ execFileSync(process.execPath, ["./scripts/plugin-sync.js"], {
7
+ stdio: "inherit",
8
+ env: { ...process.env, MA_PLUGIN_SYNC_MODE: "copy" },
9
+ });
@@ -0,0 +1,35 @@
1
+ # Meta-Architect Ralph Execution Core
2
+
3
+ You are executing a Meta-Architect story contract, not an independent release authority.
4
+
5
+ ## Required Inputs
6
+
7
+ 1. Read `.ma/plans/prd.json`.
8
+ 2. Read `.ma/plans/progress.txt`.
9
+ 3. Pick the highest-priority story where `passes` is `false`.
10
+ 4. Execute exactly one bounded story per iteration.
11
+
12
+ ## MA Quality Gates
13
+
14
+ Before marking a story passed, verify:
15
+
16
+ - `$arch` architecture constraints remain satisfied.
17
+ - `$sage` evidence and source claims remain valid.
18
+ - `$flow` logic/state invariants remain valid.
19
+ - `$vet` security blockers are absent or explicitly owned.
20
+ - `$vibe` DX/UX constraints remain acceptable.
21
+ - `$build` real-workspace checks pass for the changed slice.
22
+
23
+ ## Authority Boundaries
24
+
25
+ - Do not mutate `.ma/release.json` or `.ma/decisions.json` directly.
26
+ - Return authoritative status through `$maestro`, `$build`, or the owning lane.
27
+ - Treat Obsidian/vault context as `vault_context`, never `build_evidence`.
28
+ - Treat virtual workspace output as context only, never production proof.
29
+ - Treat code-graph rehearsal as a read-only trajectory preview.
30
+
31
+ ## Completion Contract
32
+
33
+ Update story `passes` only after fresh verification evidence exists.
34
+ Append progress to `.ma/plans/progress.txt`.
35
+ Record reusable learnings in scoped guidance without overwriting the base workspace contract.
@@ -31,6 +31,8 @@ const WATCHED_FILES = new Set([
31
31
  function parseArgs(argv) {
32
32
  const args = {
33
33
  bump: "",
34
+ version: "",
35
+ refreshFrom: "",
34
36
  fromRef: "",
35
37
  toRef: "",
36
38
  githubOutput: "",
@@ -44,6 +46,16 @@ function parseArgs(argv) {
44
46
  index += 1;
45
47
  continue;
46
48
  }
49
+ if (token === "--version") {
50
+ args.version = argv[index + 1] ?? "";
51
+ index += 1;
52
+ continue;
53
+ }
54
+ if (token === "--refresh-from") {
55
+ args.refreshFrom = argv[index + 1] ?? "";
56
+ index += 1;
57
+ continue;
58
+ }
47
59
  if (token === "--from-ref") {
48
60
  args.fromRef = argv[index + 1] ?? "";
49
61
  index += 1;
@@ -184,6 +196,12 @@ function updateCurrentSurfaceFile(file, oldVersion, nextVersion) {
184
196
  writeText(file, content);
185
197
  }
186
198
 
199
+ function syncReadmeReleaseSurface(_nextVersion) {
200
+ const readmePath = "README.md";
201
+ // The README uses a dynamic GitHub release badge; no version replacement is needed.
202
+ writeText(readmePath, readText(readmePath));
203
+ }
204
+
187
205
  function syncPackageVersion(nextVersion) {
188
206
  const pkg = readJson("package.json");
189
207
  const lock = readJson("package-lock.json");
@@ -196,6 +214,14 @@ function syncPackageVersion(nextVersion) {
196
214
  writeJson("package-lock.json", lock);
197
215
  }
198
216
 
217
+ function syncSupportBundleVersion(nextVersion) {
218
+ const manifestPath = "support-bundle.json";
219
+ if (!fs.existsSync(manifestPath)) return;
220
+ const manifest = readJson(manifestPath);
221
+ manifest.bundleVersion = nextVersion;
222
+ writeJson(manifestPath, manifest);
223
+ }
224
+
199
225
  function syncPluginVersions(nextVersion) {
200
226
  for (const file of [
201
227
  path.join("plugins", "meta-architect", ".app.json"),
@@ -215,9 +241,13 @@ function syncPluginVersions(nextVersion) {
215
241
  function syncCurrentReleaseFiles(oldVersion, nextVersion) {
216
242
  for (const file of [
217
243
  "README.md",
244
+ "DEMO.md",
245
+ "COVERAGE.md",
218
246
  "RELEASE.md",
219
247
  path.join("docs", "README.md"),
220
248
  path.join("docs", "getting-started.md"),
249
+ path.join("docs", "onboarding.md"),
250
+ path.join("docs", "skills.md"),
221
251
  path.join("docs", "release-spec.md"),
222
252
  path.join("plugins", "meta-architect", "README.md"),
223
253
  ]) {
@@ -228,16 +258,17 @@ function syncCurrentReleaseFiles(oldVersion, nextVersion) {
228
258
  const nextQa = path.join("docs", "qa", `release-readiness-${nextVersion}.md`);
229
259
  fs.renameSync(oldQa, nextQa);
230
260
  updateCurrentSurfaceFile(nextQa, oldVersion, nextVersion);
261
+
262
+ const oldIssueGates = path.join("docs", "qa", `release-issue-gates-${oldVersion}.json`);
263
+ const nextIssueGates = path.join("docs", "qa", `release-issue-gates-${nextVersion}.json`);
264
+ if (fs.existsSync(oldIssueGates)) {
265
+ fs.renameSync(oldIssueGates, nextIssueGates);
266
+ updateCurrentSurfaceFile(nextIssueGates, oldVersion, nextVersion);
267
+ }
231
268
  }
232
269
 
233
270
  function syncSupportingCode(oldVersion, nextVersion) {
234
271
  const replacements = [
235
- {
236
- file: path.join("src", "skills.js"),
237
- search: `release-readiness-${oldVersion}.md`,
238
- replacement: `release-readiness-${nextVersion}.md`,
239
- label: "skills QA path",
240
- },
241
272
  {
242
273
  file: path.join("test", "package-install-smoke.test.js"),
243
274
  search: `jstn-sdk-ma-${oldVersion}.tgz`,
@@ -259,6 +290,9 @@ function syncSupportingCode(oldVersion, nextVersion) {
259
290
 
260
291
  const mcpLiveClientFile = path.join("src", "mcp-live-client.js");
261
292
  const mcpLiveClient = readText(mcpLiveClientFile);
293
+ if (/resolveMcpClientVersion\(packageMetadata\)/.test(mcpLiveClient)) {
294
+ return;
295
+ }
262
296
  if (!/version: "[0-9]+\.[0-9]+\.[0-9]+(?:-dev)?"/.test(mcpLiveClient)) {
263
297
  throw new Error("Expected to find mcp live client version declaration");
264
298
  }
@@ -271,6 +305,27 @@ function syncSupportingCode(oldVersion, nextVersion) {
271
305
  );
272
306
  }
273
307
 
308
+ function refreshCurrentReleaseFiles(oldVersion, currentVersion) {
309
+ for (const file of [
310
+ "README.md",
311
+ "DEMO.md",
312
+ "COVERAGE.md",
313
+ "RELEASE.md",
314
+ path.join("docs", "README.md"),
315
+ path.join("docs", "getting-started.md"),
316
+ path.join("docs", "onboarding.md"),
317
+ path.join("docs", "skills.md"),
318
+ path.join("docs", "release-spec.md"),
319
+ path.join("plugins", "meta-architect", "README.md"),
320
+ path.join("docs", "qa", `release-readiness-${currentVersion}.md`),
321
+ path.join("docs", "qa", `release-issue-gates-${currentVersion}.json`),
322
+ path.join("scripts", "install.sh"),
323
+ path.join("plugins", "meta-architect", "obsidian", "manifest.json"),
324
+ ]) {
325
+ if (fs.existsSync(file)) updateCurrentSurfaceFile(file, oldVersion, currentVersion);
326
+ }
327
+ }
328
+
274
329
  function rewriteReleaseState(nextVersion, previousVersion) {
275
330
  const releasePath = "RELEASE.md";
276
331
  const qaPath = path.join("docs", "qa", `release-readiness-${nextVersion}.md`);
@@ -319,6 +374,13 @@ function main() {
319
374
  const args = parseArgs(process.argv.slice(2));
320
375
  const pkg = readJson("package.json");
321
376
  const currentVersion = pkg.version;
377
+ if (args.refreshFrom) {
378
+ refreshCurrentReleaseFiles(args.refreshFrom, currentVersion);
379
+ console.log(
380
+ JSON.stringify({ updated: true, refreshed: true, version: currentVersion }, null, 2),
381
+ );
382
+ return;
383
+ }
322
384
  const changedFiles = getChangedFiles(args);
323
385
  const relevantChanges = args.force ? ["<forced>"] : changedFiles.filter(isWatchedPath);
324
386
 
@@ -342,12 +404,15 @@ function main() {
342
404
  }
343
405
 
344
406
  const bumpKind = args.bump || "patch";
345
- const nextVersion = bumpVersion(currentVersion, bumpKind);
407
+ const nextVersion = args.version || bumpVersion(currentVersion, bumpKind);
408
+ parseVersion(nextVersion);
346
409
 
347
410
  syncPackageVersion(nextVersion);
411
+ syncSupportBundleVersion(nextVersion);
348
412
  syncPluginVersions(nextVersion);
349
413
  prependChangelog(nextVersion);
350
414
  syncCurrentReleaseFiles(currentVersion, nextVersion);
415
+ syncReadmeReleaseSurface(nextVersion);
351
416
  syncSupportingCode(currentVersion, nextVersion);
352
417
  rewriteReleaseState(nextVersion, currentVersion);
353
418
 
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { execFileSync } from "node:child_process";
4
+ import crypto from "node:crypto";
3
5
  import fs from "node:fs";
4
6
  import path from "node:path";
5
7
  import process from "node:process";
8
+ import { validateReleaseIssueGates } from "../src/release-issue-gates.js";
6
9
 
7
10
  const CANONICAL_PACKAGE = "@jstn-sdk/ma";
8
11
  const CANONICAL_INSTALL = "npm i -g @openai/codex@latest @jstn-sdk/ma@latest";
@@ -38,12 +41,19 @@ function parseVersion(version) {
38
41
  return match.groups;
39
42
  }
40
43
 
44
+ function latestCdnInstall() {
45
+ return "curl -fsSLo install.sh https://cdn.jsdelivr.net/gh/JustineDevs/meta-architect@latest/scripts/install.sh && curl -fsSLo install.sh.sha256 https://cdn.jsdelivr.net/gh/JustineDevs/meta-architect@latest/scripts/install.sh.sha256 && sed 's#scripts/install.sh#install.sh#' install.sh.sha256 | sha256sum -c - && sh install.sh";
46
+ }
47
+
41
48
  function verifyInstallBlock(file) {
42
49
  const content = readText(file);
43
- if (!content.includes(CANONICAL_INSTALL)) {
50
+ const cdnInstall = latestCdnInstall();
51
+ if (!content.includes(CANONICAL_INSTALL) && !content.includes(cdnInstall)) {
44
52
  return;
45
53
  }
46
54
 
55
+ assert(content.includes(cdnInstall), `${file}: missing jsDelivr POSIX installer command`);
56
+ assert(content.includes(CANONICAL_INSTALL), `${file}: missing canonical npm install command`);
47
57
  assert(content.includes(CANONICAL_LAUNCH), `${file}: missing canonical launch command`);
48
58
  assert(content.includes(UNINSTALL_MA), `${file}: missing uninstall Meta-Architect command`);
49
59
  assert(
@@ -52,6 +62,230 @@ function verifyInstallBlock(file) {
52
62
  );
53
63
  }
54
64
 
65
+ function verifyNpmIgnore() {
66
+ assert(fs.existsSync(".npmignore"), ".npmignore: missing production package ignore file");
67
+ const content = readText(".npmignore");
68
+ for (const requiredPattern of [
69
+ ".ma/",
70
+ ".omx/",
71
+ "node_modules/",
72
+ ".npm-cache/",
73
+ "dist/",
74
+ "test/",
75
+ ".github/",
76
+ "*.tgz",
77
+ ]) {
78
+ assert(
79
+ content.includes(requiredPattern),
80
+ `.npmignore: missing required production ignore pattern ${requiredPattern}`,
81
+ );
82
+ }
83
+ }
84
+
85
+ function verifyDistPolicy() {
86
+ const tracked = execFileSync("git", ["ls-files", "dist/"], { encoding: "utf8" }).trim();
87
+ assert(!tracked, `dist/: generated release artifacts must not be tracked:\n${tracked}`);
88
+ }
89
+
90
+ function verifyInstallerIntegrity() {
91
+ const installer = readText("scripts/install.sh");
92
+ const checksum = readText("scripts/install.sh.sha256").trim().split(/\s+/)[0];
93
+ const actual = crypto.createHash("sha256").update(installer).digest("hex");
94
+ assert(checksum === actual, "scripts/install.sh.sha256: checksum does not match installer");
95
+ assert(
96
+ !installer.includes("raw.githubusercontent.com") && !installer.includes("jsdelivr"),
97
+ "scripts/install.sh: must not fetch mutable installer sources at runtime",
98
+ );
99
+ }
100
+
101
+ function verifyDemoDoc({ version, gitTag }) {
102
+ const cdnInstall = latestCdnInstall();
103
+ assert(fs.existsSync("DEMO.md"), "DEMO.md: missing demo guide");
104
+ const content = readText("DEMO.md");
105
+ assert(content.includes(`Release line: \`${gitTag}\``), "DEMO.md: wrong release line");
106
+ assert(content.includes("Package: `@jstn-sdk/ma`"), "DEMO.md: missing package name");
107
+ assert(content.includes(cdnInstall), "DEMO.md: missing versioned installer");
108
+ assert(content.includes(CANONICAL_INSTALL), "DEMO.md: missing canonical npm install");
109
+ assert(content.includes(CANONICAL_LAUNCH), "DEMO.md: missing canonical launch");
110
+ assert(content.includes(UNINSTALL_MA), "DEMO.md: missing MA uninstall command");
111
+ assert(content.includes(UNINSTALL_BOTH), "DEMO.md: missing MA + Codex uninstall command");
112
+ assert(content.includes("npm run release:check"), "DEMO.md: missing full release demo command");
113
+ assert(
114
+ content.includes("Learning Loop Core") || content.includes("learning loop"),
115
+ "DEMO.md: missing learning loop coverage",
116
+ );
117
+ assert(content.includes("Obsidian"), "DEMO.md: missing Obsidian coverage");
118
+ assert(content.includes("Ralph"), "DEMO.md: missing Ralph execution coverage");
119
+ assert(content.includes("data/clone-data.proof.json"), "DEMO.md: missing clone-data proof");
120
+ assert(content.includes("COVERAGE.md"), "DEMO.md: missing coverage artifact");
121
+ assert(content.includes(`version line is \`${version}\``), "DEMO.md: missing current version");
122
+ }
123
+
124
+ function verifyCoverageDoc({ version, gitTag }) {
125
+ assert(fs.existsSync("COVERAGE.md"), "COVERAGE.md: missing coverage matrix");
126
+ const content = readText("COVERAGE.md");
127
+ assert(content.includes(`Target release: \`${gitTag}\``), "COVERAGE.md: wrong target release");
128
+ assert(
129
+ content.includes(`Package: \`@jstn-sdk/ma@${version}\``),
130
+ "COVERAGE.md: wrong package version",
131
+ );
132
+ assert(content.includes("Learning Loop Core"), "COVERAGE.md: missing learning-loop coverage");
133
+ assert(
134
+ content.includes("Helper Orchestration Core"),
135
+ "COVERAGE.md: missing helper orchestration coverage",
136
+ );
137
+ assert(
138
+ content.includes("Environment Awareness Core"),
139
+ "COVERAGE.md: missing environment awareness coverage",
140
+ );
141
+ assert(
142
+ content.includes("Universal Plugin Broker Core"),
143
+ "COVERAGE.md: missing universal plugin broker coverage",
144
+ );
145
+ assert(content.includes("Obsidian Integration Core"), "COVERAGE.md: missing Obsidian coverage");
146
+ assert(content.includes("Ralph Execution Core"), "COVERAGE.md: missing Ralph coverage");
147
+ assert(content.includes("36/36 passing"), "COVERAGE.md: missing current test count");
148
+ assert(
149
+ content.includes("This repository is not a toy demo."),
150
+ "COVERAGE.md: missing truth statement",
151
+ );
152
+ assert(!content.includes("@jstn-sdk/ma@0.1.0"), "COVERAGE.md: stale npm package version");
153
+ assert(!content.includes("v0.1.0 release bar"), "COVERAGE.md: stale release bar");
154
+ }
155
+
156
+ function verifyReadmeReleaseSurface({ gitTag }) {
157
+ const content = readText("README.md");
158
+ const demoImage = `<img src="https://raw.githubusercontent.com/JustineDevs/meta-architect/${gitTag}/docs/assets/DEMO_VIDEO.gif" alt="Meta-Architect demo video" width="800">`;
159
+ const logoImage = `<img src="https://raw.githubusercontent.com/JustineDevs/meta-architect/${gitTag}/docs/assets/meta-architect-logo.svg" alt="Meta-Architect: quality gates and evidence verification for AI coding agents" width="1024" height="240">`;
160
+ assert(content.includes("> [!NOTE]"), "README.md: missing product-positioning note admonition");
161
+ assert(
162
+ content.includes(
163
+ "> Meta-Architect is a workflow layer for teams that want architecture, evidence, review, and release discipline before build execution.",
164
+ ),
165
+ "README.md: missing workflow-layer positioning note",
166
+ );
167
+ assert(
168
+ content.includes("> Meta-Architect does not replace your coding runtime."),
169
+ "README.md: missing runtime-wrapper boundary note",
170
+ );
171
+ assert(
172
+ content.includes(
173
+ "> It wraps that runtime with architecture, evidence, gate enforcement, and release-sensitive workflow control.",
174
+ ),
175
+ "README.md: missing runtime-wrapper behavior note",
176
+ );
177
+ assert(content.includes(demoImage), "README.md: missing requested 800px demo GIF");
178
+ assert(
179
+ content.includes("<summary><strong>🔌 All 33 plugins & features</strong></summary>"),
180
+ "README.md: missing all 33 plugins/features toggle",
181
+ );
182
+ assert(
183
+ content.includes(
184
+ "https://img.shields.io/github/v/release/JustineDevs/meta-architect?display_name=tag&sort=semver",
185
+ ),
186
+ "README.md: missing GitHub release badge",
187
+ );
188
+ assert(content.includes(logoImage), "README.md: release-pinned logo missing");
189
+ assert(
190
+ !content.includes("raw.githubusercontent.com/JustineDevs/meta-architect/main/"),
191
+ "README.md: stable docs must not reference mutable main",
192
+ );
193
+ }
194
+
195
+ function verifyRealDemoKit() {
196
+ const runbook = readText(path.join("docs", "demo", "REAL_DEMO_RUNBOOK.md"));
197
+ const story = readText(path.join("docs", "demo", "DEMO_STORY.md"));
198
+ const checklist = readText(path.join("docs", "demo", "PROSPECT_CHECKLIST.md"));
199
+ assert(fs.existsSync(path.join("scripts", "demo-smoke.js")), "scripts/demo-smoke.js: missing");
200
+ assert(
201
+ runbook.includes("npm run demo:smoke"),
202
+ "REAL_DEMO_RUNBOOK.md: missing demo smoke command",
203
+ );
204
+ assert(runbook.includes("$maestro"), "REAL_DEMO_RUNBOOK.md: missing maestro scenario");
205
+ assert(
206
+ runbook.includes("vault_context"),
207
+ "REAL_DEMO_RUNBOOK.md: missing Obsidian context boundary",
208
+ );
209
+ assert(story.includes("Northstar Logistics"), "DEMO_STORY.md: missing realistic buyer story");
210
+ assert(story.includes("npm run release:verify"), "DEMO_STORY.md: missing release proof close");
211
+ assert(
212
+ checklist.includes("Remove `Demo Account`, `Test Company`, `Sample Co`"),
213
+ "PROSPECT_CHECKLIST.md: missing no-test-branding check",
214
+ );
215
+ for (const forbidden of ["Demo Account", "Test Company", "Sample Co"]) {
216
+ assert(
217
+ !runbook.includes(forbidden) && !story.includes(forbidden),
218
+ `demo docs: forbidden visible demo branding ${forbidden}`,
219
+ );
220
+ }
221
+ }
222
+
223
+ function verifyCanonicalSemanticSurfaces({ version, gitTag }) {
224
+ const usageWorkflow = readText(path.join("example", "usage-workflow.md"));
225
+ assert(
226
+ usageWorkflow.includes(`$maestro I want to harden Meta-Architect ${gitTag}`),
227
+ "example/usage-workflow.md: missing current $maestro release-hardening scenario",
228
+ );
229
+ for (const requiredTerm of ["Obsidian", "Ralph", "Caveman", "learning-loop"]) {
230
+ assert(
231
+ usageWorkflow.includes(requiredTerm),
232
+ `example/usage-workflow.md: missing ${requiredTerm} semantic-core term`,
233
+ );
234
+ }
235
+ for (const staleTerm of [
236
+ "Build a demo",
237
+ "demo app",
238
+ "collaborative whiteboard",
239
+ "smart contract security review",
240
+ "Timeline: 4 weeks",
241
+ "Delivery plan for v0.1.0",
242
+ "@jstn-sdk/ma@0.1.0",
243
+ ]) {
244
+ assert(
245
+ !usageWorkflow.includes(staleTerm),
246
+ `example/usage-workflow.md: stale current-facing term ${staleTerm}`,
247
+ );
248
+ }
249
+
250
+ const mission = readText(path.join("missions", "collaborative-whiteboard", "mission.md"));
251
+ assert(
252
+ mission.includes("# Mission: Semantic Release Hardening"),
253
+ "missions/collaborative-whiteboard/mission.md: stale mission title",
254
+ );
255
+ assert(
256
+ mission.includes("Obsidian is core vault-context infrastructure"),
257
+ "missions/collaborative-whiteboard/mission.md: missing Obsidian core mission contract",
258
+ );
259
+ assert(
260
+ mission.includes("Ralph is the execution loop"),
261
+ "missions/collaborative-whiteboard/mission.md: missing Ralph core mission contract",
262
+ );
263
+ assert(
264
+ !mission.toLowerCase().includes("real-time collaborative whiteboard"),
265
+ "missions/collaborative-whiteboard/mission.md: stale whiteboard mission text",
266
+ );
267
+
268
+ const currentQa = readText(path.join("docs", "qa", `release-readiness-${version}.md`));
269
+ assert(
270
+ currentQa.includes(`Harden Meta-Architect ${gitTag} semantic core`),
271
+ `docs/qa/release-readiness-${version}.md: missing realistic semantic smoke idea`,
272
+ );
273
+ assert(
274
+ !currentQa.includes('ma idea "Build a demo app"'),
275
+ `docs/qa/release-readiness-${version}.md: stale demo-app helper path`,
276
+ );
277
+
278
+ const archPrompt = readText(path.join("prompts", "architect.md"));
279
+ assert(
280
+ !archPrompt.includes("v0.1.0` skills library"),
281
+ "prompts/architect.md: stale v0.1.0 skills-library wording",
282
+ );
283
+ assert(
284
+ archPrompt.includes("current Meta-Architect skills library"),
285
+ "prompts/architect.md: missing current library wording",
286
+ );
287
+ }
288
+
55
289
  function main() {
56
290
  const pkg = readJson("package.json");
57
291
  const lock = readJson("package-lock.json");
@@ -68,6 +302,17 @@ function main() {
68
302
  pkg.publishConfig?.access === "public",
69
303
  "package.json: publishConfig.access must be public",
70
304
  );
305
+ assert(pkg.files?.includes("DEMO.md"), "package.json: files must include DEMO.md");
306
+ assert(pkg.files?.includes("COVERAGE.md"), "package.json: files must include COVERAGE.md");
307
+
308
+ verifyNpmIgnore();
309
+ verifyDistPolicy();
310
+ verifyInstallerIntegrity();
311
+ verifyDemoDoc({ version, gitTag });
312
+ verifyCoverageDoc({ version, gitTag });
313
+ verifyReadmeReleaseSurface({ gitTag });
314
+ verifyRealDemoKit();
315
+ verifyCanonicalSemanticSurfaces({ version, gitTag });
71
316
 
72
317
  const changelog = readText("CHANGELOG.md");
73
318
  assert(changelog.includes(`## ${gitTag}`), "CHANGELOG.md: missing current version heading");
@@ -95,6 +340,17 @@ function main() {
95
340
  const qa = readText(qaPath);
96
341
  assert(qa.includes(`# Release Readiness ${version}`), `${qaPath}: wrong title version`);
97
342
 
343
+ const issueGatesPath = path.join("docs", "qa", `release-issue-gates-${version}.json`);
344
+ assert(fs.existsSync(issueGatesPath), `Missing release issue gate file: ${issueGatesPath}`);
345
+ const issueGates = validateReleaseIssueGates(readJson(issueGatesPath), {
346
+ version,
347
+ requirePassed: true,
348
+ });
349
+ assert(
350
+ issueGates.valid,
351
+ `${issueGatesPath}: release issue gates are not production-passed\n- ${issueGates.errors.join("\n- ")}`,
352
+ );
353
+
98
354
  const pluginApp = readJson(path.join("plugins", "meta-architect", ".app.json"));
99
355
  const pluginMcp = readJson(path.join("plugins", "meta-architect", ".mcp.json"));
100
356
  const pluginManifest = readJson(
@@ -109,12 +365,14 @@ function main() {
109
365
 
110
366
  for (const file of [
111
367
  "README.md",
368
+ "DEMO.md",
369
+ "COVERAGE.md",
112
370
  path.join("docs", "getting-started.md"),
113
371
  path.join("docs", "onboarding.md"),
114
372
  path.join("docs", "skills.md"),
115
373
  path.join("plugins", "meta-architect", "README.md"),
116
374
  ]) {
117
- verifyInstallBlock(file);
375
+ verifyInstallBlock(file, gitTag);
118
376
  }
119
377
 
120
378
  const envTag =
@@ -1,39 +1,64 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { randomUUID } from "node:crypto";
3
4
  import fs from "node:fs/promises";
5
+ import os from "node:os";
4
6
  import path from "node:path";
5
7
  import process from "node:process";
8
+ import { fileURLToPath } from "node:url";
6
9
 
7
- function normalizeRegistry(registryUrl) {
8
- return registryUrl.endsWith("/") ? registryUrl : `${registryUrl}/`;
10
+ export async function createTemporaryNpmConfig({
11
+ token,
12
+ registry = "https://registry.npmjs.org/",
13
+ scope = "",
14
+ tempRoot = process.env.RUNNER_TEMP || os.tmpdir(),
15
+ } = {}) {
16
+ if (!token) return null;
17
+ const normalizedRegistry = registry.endsWith("/") ? registry : `${registry}/`;
18
+ const host = new URL(normalizedRegistry).host;
19
+ const configPath = path.join(tempRoot, `meta-architect-npmrc-${randomUUID()}`);
20
+ const content = [
21
+ `registry=${normalizedRegistry}`,
22
+ ...(scope ? [`${scope}:registry=${normalizedRegistry}`] : []),
23
+ `//${host}/:_authToken=${token}`,
24
+ "",
25
+ ].join("\n");
26
+
27
+ await fs.writeFile(configPath, content, { encoding: "utf8", mode: 0o600 });
28
+ await fs.chmod(configPath, 0o600);
29
+ return configPath;
30
+ }
31
+
32
+ export async function cleanupTemporaryNpmConfig(configPath) {
33
+ if (!configPath) return false;
34
+ await fs.rm(configPath, { force: true });
35
+ return true;
9
36
  }
10
37
 
11
38
  async function main() {
12
39
  const token = process.env.NPM_TOKEN || process.env.NODE_AUTH_TOKEN;
13
40
  if (!token) {
14
- console.log("No npm token detected. Skipping .npmrc generation.");
41
+ console.log("No npm token detected. Skipping temporary npm auth config.");
15
42
  return;
16
43
  }
17
44
 
18
- const registry = normalizeRegistry(process.env.NPM_REGISTRY_URL || "https://registry.npmjs.org/");
19
- const scope = process.env.NPM_SCOPE || "";
20
- const host = new URL(registry).host;
21
- const npmrcPath = path.join(process.cwd(), ".npmrc");
22
-
23
- const content = [
24
- `registry=${registry}`,
25
- ...(scope ? [`${scope}:registry=${registry}`] : []),
26
- `//${host}/:_authToken=${token}`,
27
- "",
28
- ].join("\n");
29
-
30
- await fs.writeFile(npmrcPath, content, "utf8");
31
- console.log(
32
- `Wrote CI .npmrc for ${scope ? `scope ${scope}` : "the canonical unscoped package"}.`,
33
- );
45
+ const configPath = await createTemporaryNpmConfig({
46
+ token,
47
+ registry: process.env.NPM_REGISTRY_URL || "https://registry.npmjs.org/",
48
+ scope: process.env.NPM_SCOPE || "",
49
+ });
50
+ if (process.env.GITHUB_ENV) {
51
+ await fs.appendFile(process.env.GITHUB_ENV, `NPM_CONFIG_USERCONFIG=${configPath}\n`);
52
+ }
53
+ console.log("Created temporary npm auth config outside the workspace.");
54
+ if (!process.env.GITHUB_ENV) {
55
+ console.log(`Use NPM_CONFIG_USERCONFIG=${configPath} for the current command.`);
56
+ }
34
57
  }
35
58
 
36
- main().catch((error) => {
37
- console.error(error.message);
38
- process.exitCode = 1;
39
- });
59
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
60
+ main().catch((error) => {
61
+ console.error(error.message);
62
+ process.exitCode = 1;
63
+ });
64
+ }
@@ -1,22 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import process from "node:process";
4
- import { installSkills } from "../src/skill-installer.js";
4
+ import { installSkills, rollbackInstalledAssets } from "../src/skill-installer.js";
5
5
 
6
6
  function parseArgs(argv) {
7
- const args = { path: null };
7
+ const args = { path: null, rollback: false };
8
8
  for (let index = 0; index < argv.length; index += 1) {
9
9
  const token = argv[index];
10
10
  if (token === "--path") {
11
11
  args.path = argv[index + 1];
12
12
  index += 1;
13
13
  }
14
+ if (token === "--rollback") args.rollback = true;
14
15
  }
15
16
  return args;
16
17
  }
17
18
 
18
19
  async function main() {
19
20
  const args = parseArgs(process.argv.slice(2));
21
+ if (args.rollback) {
22
+ console.log(
23
+ JSON.stringify(await rollbackInstalledAssets({ targetRoot: args.path ?? undefined })),
24
+ );
25
+ return;
26
+ }
20
27
  const { installed } = await installSkills({ targetRoot: args.path ?? undefined });
21
28
  for (const skill of installed) {
22
29
  console.log(`installed ${skill.name} -> ${skill.dest}`);