@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
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import process from "node:process";
5
+
6
+ function loadPackageJson() {
7
+ return JSON.parse(fs.readFileSync("package.json", "utf8"));
8
+ }
9
+
10
+ function parseVersion(version) {
11
+ const match = version.match(
12
+ /^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:-(?<prerelease>[0-9A-Za-z.-]+))?$/,
13
+ );
14
+ if (!match?.groups) {
15
+ throw new Error(`Invalid package.json version: ${version}`);
16
+ }
17
+ return match.groups;
18
+ }
19
+
20
+ function computeMetadata(version) {
21
+ const parsed = parseVersion(version);
22
+ const prerelease = parsed.prerelease ?? "";
23
+ const prereleaseIdentifiers = prerelease ? prerelease.split(".") : [];
24
+ const isPrerelease = prereleaseIdentifiers.length > 0;
25
+ const distTag = isPrerelease ? prereleaseIdentifiers[0] : "latest";
26
+
27
+ return {
28
+ version,
29
+ gitTag: `v${version}`,
30
+ isPrerelease,
31
+ distTag,
32
+ prerelease,
33
+ };
34
+ }
35
+
36
+ function parseArgs(argv) {
37
+ const args = {
38
+ field: "",
39
+ githubOutput: "",
40
+ };
41
+
42
+ for (let index = 0; index < argv.length; index += 1) {
43
+ const token = argv[index];
44
+ if (token === "--field") {
45
+ args.field = argv[index + 1] ?? "";
46
+ index += 1;
47
+ continue;
48
+ }
49
+ if (token === "--github-output") {
50
+ args.githubOutput = argv[index + 1] ?? "";
51
+ index += 1;
52
+ }
53
+ }
54
+
55
+ return args;
56
+ }
57
+
58
+ function writeGithubOutput(outputPath, metadata) {
59
+ const lines = [
60
+ `version=${metadata.version}`,
61
+ `git_tag=${metadata.gitTag}`,
62
+ `dist_tag=${metadata.distTag}`,
63
+ `is_prerelease=${metadata.isPrerelease}`,
64
+ ];
65
+ fs.appendFileSync(outputPath, `${lines.join("\n")}\n`);
66
+ }
67
+
68
+ function main() {
69
+ const args = parseArgs(process.argv.slice(2));
70
+ const pkg = loadPackageJson();
71
+ const metadata = computeMetadata(pkg.version);
72
+
73
+ if (args.githubOutput) {
74
+ writeGithubOutput(args.githubOutput, metadata);
75
+ }
76
+
77
+ if (args.field) {
78
+ const value = metadata[args.field];
79
+ if (value === undefined) {
80
+ throw new Error(`Unknown metadata field: ${args.field}`);
81
+ }
82
+ console.log(value);
83
+ return;
84
+ }
85
+
86
+ console.log(JSON.stringify(metadata, null, 2));
87
+ }
88
+
89
+ try {
90
+ main();
91
+ } catch (error) {
92
+ console.error(error.message);
93
+ process.exitCode = 1;
94
+ }
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from "node:child_process";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import process from "node:process";
7
+
8
+ const WATCHED_PREFIXES = [
9
+ "bin/",
10
+ "docs/",
11
+ "example/",
12
+ "mcp/",
13
+ "missions/",
14
+ "plugins/",
15
+ "prompts/",
16
+ ".codex/prompts/",
17
+ "sprint/",
18
+ "templates/",
19
+ "src/",
20
+ "skills/",
21
+ ];
22
+
23
+ const WATCHED_FILES = new Set([
24
+ "README.md",
25
+ "RELEASE.md",
26
+ "CHANGELOG.md",
27
+ "package.json",
28
+ "package-lock.json",
29
+ ]);
30
+
31
+ function parseArgs(argv) {
32
+ const args = {
33
+ bump: "",
34
+ fromRef: "",
35
+ toRef: "",
36
+ githubOutput: "",
37
+ force: false,
38
+ };
39
+
40
+ for (let index = 0; index < argv.length; index += 1) {
41
+ const token = argv[index];
42
+ if (token === "--bump") {
43
+ args.bump = argv[index + 1] ?? "";
44
+ index += 1;
45
+ continue;
46
+ }
47
+ if (token === "--from-ref") {
48
+ args.fromRef = argv[index + 1] ?? "";
49
+ index += 1;
50
+ continue;
51
+ }
52
+ if (token === "--to-ref") {
53
+ args.toRef = argv[index + 1] ?? "";
54
+ index += 1;
55
+ continue;
56
+ }
57
+ if (token === "--github-output") {
58
+ args.githubOutput = argv[index + 1] ?? "";
59
+ index += 1;
60
+ continue;
61
+ }
62
+ if (token === "--force") {
63
+ args.force = true;
64
+ }
65
+ }
66
+
67
+ return args;
68
+ }
69
+
70
+ function readJson(file) {
71
+ return JSON.parse(fs.readFileSync(file, "utf8"));
72
+ }
73
+
74
+ function writeJson(file, value) {
75
+ fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
76
+ }
77
+
78
+ function readText(file) {
79
+ return fs.readFileSync(file, "utf8");
80
+ }
81
+
82
+ function writeText(file, content) {
83
+ fs.writeFileSync(file, content);
84
+ }
85
+
86
+ function replaceRequired(text, search, replacement, label) {
87
+ if (!text.includes(search)) {
88
+ throw new Error(`Expected to find ${label}: ${search}`);
89
+ }
90
+ return text.replaceAll(search, replacement);
91
+ }
92
+
93
+ function parseVersion(version) {
94
+ const match = version.match(/^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$/);
95
+ if (!match?.groups) {
96
+ throw new Error(`Unsupported version for release-sync: ${version}`);
97
+ }
98
+ return {
99
+ major: Number(match.groups.major),
100
+ minor: Number(match.groups.minor),
101
+ patch: Number(match.groups.patch),
102
+ };
103
+ }
104
+
105
+ function bumpVersion(version, bumpKind) {
106
+ const parsed = parseVersion(version);
107
+ if (bumpKind === "major") {
108
+ return `${parsed.major + 1}.0.0`;
109
+ }
110
+ if (bumpKind === "minor") {
111
+ return `${parsed.major}.${parsed.minor + 1}.0`;
112
+ }
113
+ return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;
114
+ }
115
+
116
+ function git(args) {
117
+ return execFileSync("git", args, { encoding: "utf8" }).trim();
118
+ }
119
+
120
+ function getChangedFiles({ fromRef, toRef, force }) {
121
+ if (process.env.RELEASE_SYNC_CHANGED_FILES) {
122
+ return process.env.RELEASE_SYNC_CHANGED_FILES.split("\n")
123
+ .map((line) => line.trim())
124
+ .filter(Boolean);
125
+ }
126
+
127
+ if (force) {
128
+ return [];
129
+ }
130
+
131
+ if (fromRef && toRef && !/^0+$/.test(fromRef)) {
132
+ return git(["diff", "--name-only", fromRef, toRef])
133
+ .split("\n")
134
+ .map((line) => line.trim())
135
+ .filter(Boolean);
136
+ }
137
+
138
+ return git(["status", "--porcelain"])
139
+ .split("\n")
140
+ .map((line) => line.slice(3).trim())
141
+ .filter(Boolean);
142
+ }
143
+
144
+ function isWatchedPath(file) {
145
+ return WATCHED_FILES.has(file) || WATCHED_PREFIXES.some((prefix) => file.startsWith(prefix));
146
+ }
147
+
148
+ function prependChangelog(version) {
149
+ const changelogPath = "CHANGELOG.md";
150
+ const changelog = readText(changelogPath);
151
+ if (changelog.includes(`## v${version}`)) {
152
+ return;
153
+ }
154
+
155
+ const next = changelog.replace(
156
+ "# Changelog\n\n",
157
+ `# Changelog\n\n## v${version}\n\n- Release line prepared automatically for v${version}.\n\n`,
158
+ );
159
+ writeText(changelogPath, next);
160
+ }
161
+
162
+ function updateCurrentSurfaceFile(file, oldVersion, nextVersion) {
163
+ const oldTag = `v${oldVersion}`;
164
+ const nextTag = `v${nextVersion}`;
165
+ const oldQa = `release-readiness-${oldVersion}.md`;
166
+ const nextQa = `release-readiness-${nextVersion}.md`;
167
+ let content = readText(file);
168
+ if (content.includes(oldTag)) {
169
+ content = content.replaceAll(oldTag, nextTag);
170
+ }
171
+ if (content.includes(oldVersion)) {
172
+ content = content.replaceAll(oldVersion, nextVersion);
173
+ }
174
+ content = content.replaceAll(oldQa, nextQa);
175
+ writeText(file, content);
176
+ }
177
+
178
+ function syncPackageVersion(nextVersion) {
179
+ const pkg = readJson("package.json");
180
+ const lock = readJson("package-lock.json");
181
+ pkg.version = nextVersion;
182
+ lock.version = nextVersion;
183
+ if (lock.packages?.[""]) {
184
+ lock.packages[""].version = nextVersion;
185
+ }
186
+ writeJson("package.json", pkg);
187
+ writeJson("package-lock.json", lock);
188
+ }
189
+
190
+ function syncPluginVersions(nextVersion) {
191
+ for (const file of [
192
+ path.join("plugins", "meta-architect", ".app.json"),
193
+ path.join("plugins", "meta-architect", ".mcp.json"),
194
+ path.join("plugins", "meta-architect", ".codex-plugin", "plugin.json"),
195
+ ]) {
196
+ const value = readJson(file);
197
+ value.version = nextVersion;
198
+ writeJson(file, value);
199
+ }
200
+ }
201
+
202
+ function syncCurrentReleaseFiles(oldVersion, nextVersion) {
203
+ for (const file of [
204
+ "README.md",
205
+ "RELEASE.md",
206
+ path.join("docs", "README.md"),
207
+ path.join("docs", "getting-started.md"),
208
+ path.join("docs", "release-spec.md"),
209
+ path.join("plugins", "meta-architect", "README.md"),
210
+ ]) {
211
+ updateCurrentSurfaceFile(file, oldVersion, nextVersion);
212
+ }
213
+
214
+ const oldQa = path.join("docs", "qa", `release-readiness-${oldVersion}.md`);
215
+ const nextQa = path.join("docs", "qa", `release-readiness-${nextVersion}.md`);
216
+ fs.renameSync(oldQa, nextQa);
217
+ updateCurrentSurfaceFile(nextQa, oldVersion, nextVersion);
218
+ }
219
+
220
+ function syncSupportingCode(oldVersion, nextVersion) {
221
+ const replacements = [
222
+ {
223
+ file: path.join("src", "skills.js"),
224
+ search: `release-readiness-${oldVersion}.md`,
225
+ replacement: `release-readiness-${nextVersion}.md`,
226
+ label: "skills QA path",
227
+ },
228
+ {
229
+ file: path.join("src", "mcp-live-client.js"),
230
+ search: `version: "${oldVersion}"`,
231
+ replacement: `version: "${nextVersion}"`,
232
+ label: "mcp live client version",
233
+ },
234
+ {
235
+ file: path.join("test", "package-install-smoke.test.js"),
236
+ search: `jstn-sdk-ma-${oldVersion}.tgz`,
237
+ replacement: `jstn-sdk-ma-${nextVersion}.tgz`,
238
+ label: "tarball filename",
239
+ },
240
+ {
241
+ file: path.join("test", "policy.test.js"),
242
+ search: `release/${oldVersion}`,
243
+ replacement: `release/${nextVersion}`,
244
+ label: "release branch example",
245
+ },
246
+ ];
247
+
248
+ for (const entry of replacements) {
249
+ const content = readText(entry.file);
250
+ writeText(entry.file, replaceRequired(content, entry.search, entry.replacement, entry.label));
251
+ }
252
+ }
253
+
254
+ function rewriteReleaseState(nextVersion, previousVersion) {
255
+ const releasePath = "RELEASE.md";
256
+ const qaPath = path.join("docs", "qa", `release-readiness-${nextVersion}.md`);
257
+
258
+ let release = readText(releasePath);
259
+ release = release.replace(
260
+ /- npm package: `@jstn-sdk\/ma@[0-9]+\.[0-9]+\.[0-9]+`/,
261
+ `- npm package: \`@jstn-sdk/ma@${nextVersion}\``,
262
+ );
263
+ release = release.replace(
264
+ /- publishability note: .+/,
265
+ `- publishability note: \`${previousVersion}\` is already published, so \`${nextVersion}\` is the next publishable package line`,
266
+ );
267
+ release = release.replace(
268
+ /- GitHub release: .+/,
269
+ `- GitHub release: pending publish for \`v${nextVersion}\``,
270
+ );
271
+ release = release.replace(
272
+ /- npm publication has not been run yet for `@jstn-sdk\/ma@[0-9]+\.[0-9]+\.[0-9]+`/,
273
+ `- npm publication has not been run yet for \`@jstn-sdk/ma@${nextVersion}\``,
274
+ );
275
+ writeText(releasePath, release);
276
+
277
+ let qa = readText(qaPath);
278
+ qa = qa.replace(
279
+ /- npm package: `@jstn-sdk\/ma@[0-9]+\.[0-9]+\.[0-9]+`/,
280
+ `- npm package: \`@jstn-sdk/ma@${nextVersion}\``,
281
+ );
282
+ qa = qa.replace(
283
+ /- publishability note: .+/,
284
+ `- publishability note: \`${previousVersion}\` is already published, so \`${nextVersion}\` is the next publishable package line`,
285
+ );
286
+ qa = qa.replace(
287
+ /- GitHub release: .+/,
288
+ `- GitHub release: pending publish for \`v${nextVersion}\``,
289
+ );
290
+ writeText(qaPath, qa);
291
+ }
292
+
293
+ function writeGithubOutput(outputPath, { updated, version }) {
294
+ const lines = [`updated=${updated}`, `version=${version}`];
295
+ fs.appendFileSync(outputPath, `${lines.join("\n")}\n`);
296
+ }
297
+
298
+ function main() {
299
+ const args = parseArgs(process.argv.slice(2));
300
+ const pkg = readJson("package.json");
301
+ const currentVersion = pkg.version;
302
+ const changedFiles = getChangedFiles(args);
303
+ const relevantChanges = args.force ? ["<forced>"] : changedFiles.filter(isWatchedPath);
304
+
305
+ if (relevantChanges.length === 0 && !args.force) {
306
+ if (args.githubOutput) {
307
+ writeGithubOutput(args.githubOutput, { updated: "false", version: currentVersion });
308
+ }
309
+ console.log(
310
+ JSON.stringify(
311
+ {
312
+ updated: false,
313
+ forced: false,
314
+ version: currentVersion,
315
+ changedFiles,
316
+ },
317
+ null,
318
+ 2,
319
+ ),
320
+ );
321
+ return;
322
+ }
323
+
324
+ const bumpKind = args.bump || "patch";
325
+ const nextVersion = bumpVersion(currentVersion, bumpKind);
326
+
327
+ syncPackageVersion(nextVersion);
328
+ syncPluginVersions(nextVersion);
329
+ prependChangelog(nextVersion);
330
+ syncCurrentReleaseFiles(currentVersion, nextVersion);
331
+ syncSupportingCode(currentVersion, nextVersion);
332
+ rewriteReleaseState(nextVersion, currentVersion);
333
+
334
+ if (args.githubOutput) {
335
+ writeGithubOutput(args.githubOutput, { updated: "true", version: nextVersion });
336
+ }
337
+
338
+ console.log(
339
+ JSON.stringify(
340
+ {
341
+ updated: true,
342
+ forced: args.force,
343
+ bump: bumpKind,
344
+ previousVersion: currentVersion,
345
+ version: nextVersion,
346
+ changedFiles: relevantChanges,
347
+ },
348
+ null,
349
+ 2,
350
+ ),
351
+ );
352
+ }
353
+
354
+ try {
355
+ main();
356
+ } catch (error) {
357
+ console.error(error.message);
358
+ process.exitCode = 1;
359
+ }
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import process from "node:process";
6
+
7
+ const CANONICAL_PACKAGE = "@jstn-sdk/ma";
8
+ const CANONICAL_INSTALL = "npm i -g @openai/codex@latest @jstn-sdk/ma@latest";
9
+ const CANONICAL_LAUNCH = "ma --madmax --high";
10
+ const UNINSTALL_MA = "npm uninstall -g @jstn-sdk/ma";
11
+ const UNINSTALL_BOTH = "npm uninstall -g @jstn-sdk/ma @openai/codex";
12
+
13
+ function readJson(file) {
14
+ return JSON.parse(fs.readFileSync(file, "utf8"));
15
+ }
16
+
17
+ function readText(file) {
18
+ return fs.readFileSync(file, "utf8");
19
+ }
20
+
21
+ function fail(message) {
22
+ throw new Error(message);
23
+ }
24
+
25
+ function assert(condition, message) {
26
+ if (!condition) {
27
+ fail(message);
28
+ }
29
+ }
30
+
31
+ function parseVersion(version) {
32
+ const match = version.match(
33
+ /^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:-(?<prerelease>[0-9A-Za-z.-]+))?$/,
34
+ );
35
+ if (!match?.groups) {
36
+ fail(`Invalid package version: ${version}`);
37
+ }
38
+ return match.groups;
39
+ }
40
+
41
+ function verifyInstallBlock(file) {
42
+ const content = readText(file);
43
+ if (!content.includes(CANONICAL_INSTALL)) {
44
+ return;
45
+ }
46
+
47
+ assert(content.includes(CANONICAL_LAUNCH), `${file}: missing canonical launch command`);
48
+ assert(content.includes(UNINSTALL_MA), `${file}: missing uninstall Meta-Architect command`);
49
+ assert(
50
+ content.includes(UNINSTALL_BOTH),
51
+ `${file}: missing uninstall Meta-Architect + Codex command`,
52
+ );
53
+ }
54
+
55
+ function main() {
56
+ const pkg = readJson("package.json");
57
+ const lock = readJson("package-lock.json");
58
+ const version = pkg.version;
59
+ const gitTag = `v${version}`;
60
+ const parsed = parseVersion(version);
61
+ const isPrerelease = Boolean(parsed.prerelease);
62
+
63
+ assert(pkg.name === CANONICAL_PACKAGE, "package.json: wrong package name");
64
+ assert(lock.name === CANONICAL_PACKAGE, "package-lock.json: wrong package name");
65
+ assert(lock.version === version, "package-lock.json: version drift from package.json");
66
+ assert(lock.packages?.[""]?.version === version, "package-lock.json: root package version drift");
67
+ assert(
68
+ pkg.publishConfig?.access === "public",
69
+ "package.json: publishConfig.access must be public",
70
+ );
71
+
72
+ const changelog = readText("CHANGELOG.md");
73
+ assert(changelog.includes(`## ${gitTag}`), "CHANGELOG.md: missing current version heading");
74
+
75
+ const release = readText("RELEASE.md");
76
+ assert(release.includes(`# Meta-Architect ${gitTag}`), "RELEASE.md: wrong title version");
77
+
78
+ const releaseSpec = readText(path.join("docs", "release-spec.md"));
79
+ assert(
80
+ releaseSpec.includes(`# ${gitTag} Requirements & Rules`),
81
+ "docs/release-spec.md: wrong title version",
82
+ );
83
+ assert(
84
+ releaseSpec.includes(`package.json\` version \`${version}\``) ||
85
+ releaseSpec.includes(`package.json\` version \`${version}`),
86
+ "docs/release-spec.md: missing package version reference",
87
+ );
88
+ assert(
89
+ releaseSpec.includes(`git tag \`${gitTag}\``),
90
+ "docs/release-spec.md: missing git tag reference",
91
+ );
92
+
93
+ const qaPath = path.join("docs", "qa", `release-readiness-${version}.md`);
94
+ assert(fs.existsSync(qaPath), `Missing QA release-readiness file: ${qaPath}`);
95
+ const qa = readText(qaPath);
96
+ assert(qa.includes(`# Release Readiness ${version}`), `${qaPath}: wrong title version`);
97
+
98
+ const pluginApp = readJson(path.join("plugins", "meta-architect", ".app.json"));
99
+ const pluginMcp = readJson(path.join("plugins", "meta-architect", ".mcp.json"));
100
+ const pluginManifest = readJson(
101
+ path.join("plugins", "meta-architect", ".codex-plugin", "plugin.json"),
102
+ );
103
+ assert(pluginApp.version === version, "plugins/meta-architect/.app.json: version drift");
104
+ assert(pluginMcp.version === version, "plugins/meta-architect/.mcp.json: version drift");
105
+ assert(
106
+ pluginManifest.version === version,
107
+ "plugins/meta-architect/.codex-plugin/plugin.json: version drift",
108
+ );
109
+
110
+ for (const file of [
111
+ "README.md",
112
+ path.join("docs", "getting-started.md"),
113
+ path.join("docs", "onboarding.md"),
114
+ path.join("docs", "skills.md"),
115
+ path.join("plugins", "meta-architect", "README.md"),
116
+ ]) {
117
+ verifyInstallBlock(file);
118
+ }
119
+
120
+ const envTag =
121
+ process.env.RELEASE_TAG || process.env.GITHUB_REF_NAME || process.env.GIT_TAG || "";
122
+ if (envTag.startsWith("v")) {
123
+ assert(envTag === gitTag, `Release tag mismatch: expected ${gitTag}, got ${envTag}`);
124
+ }
125
+
126
+ if (isPrerelease) {
127
+ const prereleaseTag = parsed.prerelease.split(".")[0];
128
+ assert(
129
+ prereleaseTag && prereleaseTag !== "latest",
130
+ `Prerelease version ${version} must resolve to an explicit non-latest dist-tag`,
131
+ );
132
+ }
133
+
134
+ console.log(
135
+ JSON.stringify(
136
+ {
137
+ name: pkg.name,
138
+ version,
139
+ gitTag,
140
+ isPrerelease,
141
+ },
142
+ null,
143
+ 2,
144
+ ),
145
+ );
146
+ }
147
+
148
+ try {
149
+ main();
150
+ } catch (error) {
151
+ console.error(error.message);
152
+ process.exitCode = 1;
153
+ }
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import process from "node:process";
6
+
7
+ function normalizeRegistry(registryUrl) {
8
+ return registryUrl.endsWith("/") ? registryUrl : `${registryUrl}/`;
9
+ }
10
+
11
+ async function main() {
12
+ const token = process.env.NPM_TOKEN || process.env.NODE_AUTH_TOKEN;
13
+ if (!token) {
14
+ console.log("No npm token detected. Skipping .npmrc generation.");
15
+ return;
16
+ }
17
+
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
+ );
34
+ }
35
+
36
+ main().catch((error) => {
37
+ console.error(error.message);
38
+ process.exitCode = 1;
39
+ });
@@ -1,12 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import fs from "node:fs/promises";
4
- import os from "node:os";
5
- import path from "node:path";
6
3
  import process from "node:process";
7
-
8
- const repoRoot = process.cwd();
9
- const skillsRoot = path.join(repoRoot, "skills");
4
+ import { installSkills } from "../src/skill-installer.js";
10
5
 
11
6
  function parseArgs(argv) {
12
7
  const args = { path: null };
@@ -20,38 +15,11 @@ function parseArgs(argv) {
20
15
  return args;
21
16
  }
22
17
 
23
- async function copyDir(src, dest) {
24
- await fs.mkdir(dest, { recursive: true });
25
- const entries = await fs.readdir(src, { withFileTypes: true });
26
- for (const entry of entries) {
27
- const srcPath = path.join(src, entry.name);
28
- const destPath = path.join(dest, entry.name);
29
- if (entry.isDirectory()) {
30
- await copyDir(srcPath, destPath);
31
- } else {
32
- await fs.copyFile(srcPath, destPath);
33
- }
34
- }
35
- }
36
-
37
18
  async function main() {
38
19
  const args = parseArgs(process.argv.slice(2));
39
- const targetRoot =
40
- args.path ?? path.join(process.env.CODEX_HOME ?? path.join(os.homedir(), ".codex"), "skills");
41
-
42
- await fs.mkdir(targetRoot, { recursive: true });
43
- const skillEntries = await fs.readdir(skillsRoot, { withFileTypes: true });
44
-
45
- for (const entry of skillEntries) {
46
- if (!entry.isDirectory()) {
47
- continue;
48
- }
49
-
50
- const src = path.join(skillsRoot, entry.name);
51
- const dest = path.join(targetRoot, entry.name);
52
- await fs.rm(dest, { recursive: true, force: true });
53
- await copyDir(src, dest);
54
- console.log(`installed ${entry.name} -> ${dest}`);
20
+ const { installed } = await installSkills({ targetRoot: args.path ?? undefined });
21
+ for (const skill of installed) {
22
+ console.log(`installed ${skill.name} -> ${skill.dest}`);
55
23
  }
56
24
  }
57
25
 
@@ -50,7 +50,7 @@ async function main() {
50
50
  skills.sort((left, right) => left.name.localeCompare(right.name));
51
51
  await fs.writeFile(
52
52
  manifestPath,
53
- `${JSON.stringify({ schemaVersion: "1.0.0", skills }, null, 2)}\n`,
53
+ `${JSON.stringify({ schemaVersion: "0.1.0", skills }, null, 2)}\n`,
54
54
  );
55
55
  console.log(manifestPath);
56
56
  }