@jstn-sdk/ma 0.14.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/COVERAGE.md +9 -9
  2. package/DEMO.md +4 -4
  3. package/README.md +80 -70
  4. package/bin/ma.js +6 -8
  5. package/docs/README.md +2 -2
  6. package/docs/assets/banner.png +0 -0
  7. package/docs/getting-started.md +9 -9
  8. package/docs/qa/{release-issue-gates-0.14.0.json → release-issue-gates-0.14.1.json} +77 -77
  9. package/docs/qa/{release-readiness-0.14.0.md → release-readiness-0.14.1.md} +12 -12
  10. package/docs/release-spec.md +12 -12
  11. package/docs/vendor-plugin-publishing.md +49 -0
  12. package/mcp/local/code-intel.js +9 -3
  13. package/package.json +12 -3
  14. package/plugins/meta-architect/.app.json +1 -1
  15. package/plugins/meta-architect/.claude-plugin/plugin.json +12 -0
  16. package/plugins/meta-architect/.codex-plugin/plugin.json +1 -1
  17. package/plugins/meta-architect/.mcp.json +1 -1
  18. package/plugins/meta-architect/README.md +13 -1
  19. package/plugins/meta-architect/obsidian/manifest.json +1 -1
  20. package/plugins/meta-architect/skills/maestro/SKILL.md +17 -1
  21. package/plugins/meta-architect/skills/maestro/references/core-release-rules.md +2 -2
  22. package/schemas/autonomous-task-queue.schema.json +2 -0
  23. package/scripts/install.sh +1 -1
  24. package/scripts/install.sh.sha256 +1 -1
  25. package/scripts/plugin-build.js +314 -0
  26. package/scripts/plugin-publish.js +77 -0
  27. package/scripts/release-sync.js +11 -0
  28. package/scripts/release-verify.js +35 -4
  29. package/skills/maestro/SKILL.md +17 -1
  30. package/skills/maestro/references/core-release-rules.md +2 -2
  31. package/sprint/07-release.md +2 -2
  32. package/src/agents.js +4 -2
  33. package/src/bootstrap.js +20 -2
  34. package/src/codex-app-server.js +4 -4
  35. package/src/launcher.js +2 -2
  36. package/src/mcp-live-client.js +2 -2
  37. package/src/prelaunch.js +34 -0
  38. package/src/process-utils.js +62 -0
  39. package/src/quality/ai-quality-orchestrator.js +2 -2
  40. package/src/release-operations.js +14 -4
  41. package/src/runtime/architect-review.js +2 -2
  42. package/src/runtime/autonomous-tasks.js +220 -43
  43. package/src/runtime/codeburn-core.js +9 -3
  44. package/src/runtime/core-source-ingest.js +2 -2
  45. package/src/runtime/detached-provider.js +17 -8
  46. package/src/runtime/live-agent-verification.js +2 -2
  47. package/src/runtime/project-context.js +2 -2
  48. package/src/runtime/skills-registry-export.js +7 -3
  49. package/src/skills.js +12 -12
  50. package/src/test-fixtures.js +4 -4
  51. package/support-bundle.json +1 -1
  52. package/scripts/postinstall.js +0 -30
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "meta-architect",
3
+ "description": "Meta-Architect gated workflow skills for Claude Code.",
4
+ "version": "0.14.1",
5
+ "author": {
6
+ "name": "JustineDevs",
7
+ "url": "https://github.com/JustineDevs"
8
+ },
9
+ "homepage": "https://github.com/JustineDevs/meta-architect",
10
+ "repository": "https://github.com/JustineDevs/meta-architect.git",
11
+ "license": "MIT"
12
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meta-architect",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "Skills-first workflow layer for Codex with a bounded autonomous manager, architecture, evidence, review, and gated build guidance.",
5
5
  "author": {
6
6
  "name": "JustineDevs",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meta-architect",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "collections": [
5
5
  "sindresorhus/awesome",
6
6
  "dzharii/awesome-typescript",
@@ -48,6 +48,17 @@ Use the core repo when you want to develop Meta-Architect itself. Use the plugin
48
48
 
49
49
  The plugin-facing bundle should be consumed alongside the repository’s documented packaging/install flow.
50
50
 
51
+ ### Claude Code marketplace
52
+
53
+ This repository is the hosted marketplace. In Claude Code, add it and install the existing plugin:
54
+
55
+ ```text
56
+ /plugin marketplace add JustineDevs/meta-architect
57
+ /plugin install meta-architect@meta-architect
58
+ ```
59
+
60
+ The same plugin can be tested locally with `claude --plugin-dir ./plugins/meta-architect`.
61
+
51
62
  Recommended CLI install for macOS, Linux, WSL, and Git-Bash:
52
63
 
53
64
  ```bash
@@ -138,7 +149,7 @@ When consuming the plugin:
138
149
  The plugin version should track the release scope of the core repo.
139
150
 
140
151
  For this repository:
141
- - plugin scope is aligned to Meta-Architect `v0.14.0`
152
+ - plugin scope is aligned to Meta-Architect `v0.14.1`
142
153
  - any breaking contract change should be versioned intentionally
143
154
 
144
155
  The plugin is one distribution surface of the same product, not a separate product line.
@@ -151,4 +162,5 @@ The plugin is one distribution surface of the same product, not a separate produ
151
162
  - [docs/mcp-setup.md](../../docs/mcp-setup.md)
152
163
  - [.app.json](./.app.json)
153
164
  - [.codex-plugin/plugin.json](./.codex-plugin/plugin.json)
165
+ - [.claude-plugin/plugin.json](./.claude-plugin/plugin.json)
154
166
  - [.mcp.json](./.mcp.json)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "meta-architect",
3
3
  "name": "Meta-Architect",
4
- "version": "0.14.0",
4
+ "version": "0.14.1",
5
5
  "minAppVersion": "1.5.0",
6
6
  "description": "Connects active Obsidian notes, selections, graph metadata, canvases, attachments, and request queues to Meta-Architect vault context.",
7
7
  "author": "JustineDevs",
@@ -7,7 +7,7 @@ description: "Use when the user wants the singular Meta-Architect in-session aut
7
7
 
8
8
  ## Overview
9
9
 
10
- Use this skill inside Codex as the singular Meta-Architect umbrella surface and bounded autonomous manager. It inspects workflow state, chooses the smallest safe next step, manages the fixed gated design-and-review sequence one lane at a time, and routes helper handoffs when they are enough. There is no separate shipped `$meta-architect` skill.
10
+ Use this skill inside Codex as the singular Meta-Architect umbrella surface and persistent autonomous manager. It accepts one task or a durable batch, inspects workflow state, chooses the smallest safe next step, manages the fixed gated design-and-review sequence, and keeps resuming eligible work until each task is completed, blocked, cancelled, or failed. It never invents a second umbrella command. There is no separate shipped `$meta-architect` skill.
11
11
 
12
12
  ## Workflow
13
13
 
@@ -30,6 +30,19 @@ Use this skill inside Codex as the singular Meta-Architect umbrella surface and
30
30
  - `$build`
31
31
  5. End with a clear result shape: decision, evidence, blockers, the lane assignment if any, and the exact next trigger.
32
32
 
33
+ ## Autonomous task loop
34
+
35
+ For a task or batch, keep the manager loop active across turns:
36
+
37
+ 1. Normalize the request into the durable `.ma` task contract before dispatch.
38
+ 2. Discover the selected host, available skills, and required lane syntax without taking ownership of user-installed assets.
39
+ 3. Dispatch independent tasks with bounded concurrency and preserve dependency order for dependent tasks.
40
+ 4. Inspect, implement, test, review, repair, and verify. Route a failure back to its owning lane with the failure evidence attached.
41
+ 5. Persist checkpoints, receipts, and the next trigger after every transition so an interrupted process can resume safely.
42
+ 6. Continue unaffected batch tasks when one task is blocked, then return a batch summary with terminal states and unresolved blockers.
43
+
44
+ Routine local work continues without asking for another prompt. Stop only for credentials, destructive actions, production or external mutations, explicit approval gates, unsafe commands, unavailable required providers, or missing verification evidence.
45
+
33
46
  ## Output
34
47
 
35
48
  Produce:
@@ -43,6 +56,9 @@ Produce:
43
56
  ## Rules
44
57
 
45
58
  - Prefer the smallest next step that moves the workflow forward safely.
59
+ - Continue eligible work until the current task or batch reaches a terminal state; do not stop after a single successful lane.
60
+ - Treat persisted `.ma` state as the source for resume, deduplication, dependency ordering, cancellation, and bounded retries.
61
+ - Keep autonomous execution bounded by task dependencies, concurrency limits, deadlines, retry limits, and explicit safety gates.
46
62
  - Respect current gate state before recommending implementation or release work.
47
63
  - Be explicit when more evidence, planning, or validation is still needed.
48
64
  - Treat the in-session skill flow as primary. Use `ma ...` terminal helpers only when repo-local setup, inspection, or scripted state automation is explicitly the better support path.
@@ -8,6 +8,6 @@
8
8
  - `logic_status = GREEN`
9
9
  - `security_status = GREEN`
10
10
  - `experience_status = GREEN` or `WAIVED`
11
- - Feature work merges into `development`, never directly into `prod`.
12
- - Release promotion is allowed only from `development` or approved `release/*`.
11
+ - Feature work merges into `dev`, never directly into `main`.
12
+ - Release promotion is allowed only from `dev` or approved `release/*`.
13
13
  - Use the helper command path only when repo-local state automation is explicitly needed; otherwise stay inside Codex and carry the gate decisions in the session.
@@ -46,6 +46,8 @@
46
46
  "completedAt": { "type": ["string", "null"], "format": "date-time" },
47
47
  "error": { "type": ["string", "null"] },
48
48
  "blocker": { "type": ["string", "null"] },
49
+ "runnerPid": { "type": ["integer", "null"], "minimum": 1 },
50
+ "runnerId": { "type": ["string", "null"], "minLength": 1 },
49
51
  "evidence": { "type": "array", "items": {} },
50
52
  "selectedCapabilities": { "type": "array", "items": { "type": "object" } },
51
53
  "invocation": { "type": ["string", "null"] }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env sh
2
2
  set -eu
3
3
 
4
- MA_PACKAGE="${MA_PACKAGE:-@jstn-sdk/ma@0.14.0}"
4
+ MA_PACKAGE="${MA_PACKAGE:-@jstn-sdk/ma@0.14.1}"
5
5
  CODEX_PACKAGE="${CODEX_PACKAGE:-@openai/codex@latest}"
6
6
  NO_SETUP=0
7
7
  NO_SKILLS=0
@@ -1 +1 @@
1
- 0a18d94ded8872eae750cd2cc4a5b6ab05a6c48796def3634bc2414b3d48f7f7 scripts/install.sh
1
+ 3ffac1b709bceb6343181fef3402fa3bed6a9d9067299a2938489a4d3458ad41 scripts/install.sh
@@ -0,0 +1,314 @@
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
+ import { fileURLToPath } from "node:url";
7
+
8
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
9
+ const skillsRoot = path.join(repoRoot, "skills");
10
+ const sourcePluginRoot = path.join(repoRoot, "plugins", "meta-architect");
11
+ const packageJson = JSON.parse(await fs.readFile(path.join(repoRoot, "package.json"), "utf8"));
12
+
13
+ const TARGETS = {
14
+ codex: {
15
+ support: "native",
16
+ description: "Codex plugin bundle with native skills, app metadata, and MCP metadata.",
17
+ install:
18
+ "Copy this directory to a Codex plugin location or load it with the host plugin loader.",
19
+ publish: "Publish the generated directory through the Codex plugin distribution flow.",
20
+ },
21
+ "claude-code": {
22
+ support: "native",
23
+ description: "Claude Code marketplace repository containing a native plugin source.",
24
+ install:
25
+ "/plugin marketplace add <owner>/<marketplace-repository> then /plugin install meta-architect@<marketplace>",
26
+ publish: "Commit this directory to a Git repository, then add it as a Claude Code marketplace.",
27
+ },
28
+ cursor: {
29
+ support: "native",
30
+ description: "Cursor marketplace repository containing native skills and rules.",
31
+ install: "Install the generated marketplace repository through Cursor's plugin flow.",
32
+ publish:
33
+ "Commit this directory to a Git repository and submit or distribute it as a Cursor marketplace.",
34
+ },
35
+ antigravity: {
36
+ support: "native",
37
+ description: "Antigravity plugin directory with native rules and skills.",
38
+ install:
39
+ "Copy this directory into .agents/plugins/ in the workspace or the host plugin directory.",
40
+ publish: "Distribute the generated plugin directory through the Antigravity plugin flow.",
41
+ },
42
+ "gemini-cli": {
43
+ support: "native",
44
+ description: "Gemini CLI extension with a context file and Agent Skills.",
45
+ install: "gemini extensions install <github-url-or-local-path>",
46
+ publish: "Push this directory to GitHub, then install it with gemini extensions install.",
47
+ },
48
+ opencode: {
49
+ support: "native",
50
+ description: "OpenCode project package using its native .opencode/skills surface.",
51
+ install: "Copy .opencode/skills into the OpenCode project.",
52
+ publish: "Distribute this directory through Git or the OpenCode package mechanism.",
53
+ },
54
+ pi: {
55
+ support: "native",
56
+ description: "Pi package surface distributed by the @jstn-sdk/ma package.",
57
+ install:
58
+ "pi install npm:@jstn-sdk/ma@<version> or pi install git:github.com/JustineDevs/meta-architect@v<version>",
59
+ publish: "Publish @jstn-sdk/ma once; no separate Pi package is created.",
60
+ },
61
+ openclaw: {
62
+ support: "portable",
63
+ description:
64
+ "OpenClaw-compatible skills bundle. No runtime plugin is invented for a skills-only source.",
65
+ install: "Copy skills/ into the OpenClaw workspace and load the generated AGENTS.md context.",
66
+ publish:
67
+ "Publish the bundle through the OpenClaw skills or ClawHub flow after adding a real runtime entrypoint.",
68
+ },
69
+ cline: {
70
+ support: "native",
71
+ description: "Cline project rules and native skills bundle.",
72
+ install: "Copy .clinerules and .cline/skills into the Cline project.",
73
+ publish: "Distribute the generated project bundle through Git or the Cline host flow.",
74
+ },
75
+ continue: {
76
+ support: "portable",
77
+ description: "Continue-compatible rules bundle with the portable Agent Skills baseline.",
78
+ install: "Copy .continue/rules and skills into the Continue project.",
79
+ publish: "Distribute the generated bundle through Git or the Continue configuration flow.",
80
+ },
81
+ goose: {
82
+ support: "portable",
83
+ description: "Goose-compatible portable context and skills bundle.",
84
+ install: "Copy AGENTS.md and skills/ into the Goose workspace.",
85
+ publish: "Distribute the generated bundle through Git or the Goose extension flow.",
86
+ },
87
+ };
88
+
89
+ export const supportedPluginTargets = Object.freeze(Object.keys(TARGETS));
90
+
91
+ function parseArgs(argv) {
92
+ const targets = [];
93
+ let output = path.join(repoRoot, "dist", "vendor-plugins");
94
+ for (let index = 0; index < argv.length; index += 1) {
95
+ const arg = argv[index];
96
+ if (arg === "--target" || arg === "--targets") {
97
+ targets.push(...(argv[index + 1] ?? "").split(",").filter(Boolean));
98
+ index += 1;
99
+ } else if (arg === "--output") {
100
+ output = path.resolve(argv[index + 1] ?? output);
101
+ index += 1;
102
+ } else if (arg === "--help" || arg === "-h") {
103
+ console.log("Usage: npm run plugin:build -- --targets all [--output DIR]");
104
+ process.exit(0);
105
+ }
106
+ }
107
+ const selected = targets.length === 0 || targets.includes("all") ? Object.keys(TARGETS) : targets;
108
+ for (const target of selected) {
109
+ if (!Object.hasOwn(TARGETS, target)) throw new Error(`Unknown plugin target: ${target}`);
110
+ }
111
+ return { output, targets: [...new Set(selected)] };
112
+ }
113
+
114
+ async function copyTree(source, destination) {
115
+ const stat = await fs.lstat(source);
116
+ if (stat.isSymbolicLink()) return copyTree(await fs.realpath(source), destination);
117
+ if (stat.isDirectory()) {
118
+ await fs.mkdir(destination, { recursive: true });
119
+ for (const entry of await fs.readdir(source)) {
120
+ await copyTree(path.join(source, entry), path.join(destination, entry));
121
+ }
122
+ return;
123
+ }
124
+ await fs.mkdir(path.dirname(destination), { recursive: true });
125
+ await fs.copyFile(source, destination);
126
+ await fs.chmod(destination, stat.mode & 0o777);
127
+ }
128
+
129
+ async function writeJson(filePath, value) {
130
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
131
+ await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
132
+ }
133
+
134
+ async function writeText(filePath, content) {
135
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
136
+ await fs.writeFile(filePath, content.endsWith("\n") ? content : `${content}\n`, "utf8");
137
+ }
138
+
139
+ async function copySkills(destination) {
140
+ await copyTree(skillsRoot, destination);
141
+ }
142
+
143
+ function baselineInstructions(target) {
144
+ return `# Meta-Architect (${target})\n\nUse the bundled Meta-Architect lanes as the canonical workflow contract:\n\n\`$arch\` -> \`$sage\` -> \`$flow\` -> \`$vet\` -> \`$vibe\` -> \`$build\`\n\nRun each lane through this host's native skill or rule loader. Do not claim a gate passed without fresh evidence.\n`;
145
+ }
146
+
147
+ function cursorRule() {
148
+ return `---\ndescription: Meta-Architect gated workflow\nglobs:\n - "**/*"\nalwaysApply: false\n---\n\nUse the Meta-Architect skills in this plugin in order: $arch, $sage, $flow, $vet, $vibe, then $build. Keep build and release work blocked until the earlier lanes have fresh evidence.\n`;
149
+ }
150
+
151
+ async function buildCodex(output) {
152
+ await copyTree(path.join(sourcePluginRoot, ".codex-plugin"), path.join(output, ".codex-plugin"));
153
+ await copySkills(path.join(output, "skills"));
154
+ for (const file of [".app.json", ".mcp.json", "README.md"]) {
155
+ await copyTree(path.join(sourcePluginRoot, file), path.join(output, file));
156
+ }
157
+ }
158
+
159
+ async function buildClaude(output) {
160
+ const plugin = path.join(output, "plugins", "meta-architect");
161
+ await writeJson(path.join(output, ".claude-plugin", "marketplace.json"), {
162
+ name: "meta-architect",
163
+ owner: { name: "JustineDevs", url: "https://github.com/JustineDevs" },
164
+ metadata: { description: "Meta-Architect gated workflow plugin", version: packageJson.version },
165
+ plugins: [
166
+ {
167
+ name: "meta-architect",
168
+ source: "./plugins/meta-architect",
169
+ description: TARGETS["claude-code"].description,
170
+ },
171
+ ],
172
+ });
173
+ await writeJson(path.join(plugin, ".claude-plugin", "plugin.json"), {
174
+ name: "meta-architect",
175
+ description: "Meta-Architect gated workflow skills for Claude Code.",
176
+ version: packageJson.version,
177
+ author: { name: "JustineDevs", url: "https://github.com/JustineDevs" },
178
+ license: "MIT",
179
+ });
180
+ await copySkills(path.join(plugin, "skills"));
181
+ await writeText(path.join(plugin, "AGENTS.md"), baselineInstructions("Claude Code"));
182
+ }
183
+
184
+ async function buildCursor(output) {
185
+ const plugin = path.join(output, "plugins", "meta-architect");
186
+ await writeJson(path.join(output, ".cursor-plugin", "marketplace.json"), {
187
+ name: "meta-architect",
188
+ owner: { name: "JustineDevs", email: "justinedevs@jstn.site" },
189
+ metadata: { description: "Meta-Architect gated workflow plugin", version: packageJson.version },
190
+ plugins: [
191
+ {
192
+ name: "meta-architect",
193
+ source: "./plugins/meta-architect",
194
+ description: TARGETS.cursor.description,
195
+ },
196
+ ],
197
+ });
198
+ await writeJson(path.join(plugin, ".cursor-plugin", "plugin.json"), {
199
+ name: "meta-architect",
200
+ displayName: "Meta-Architect",
201
+ version: packageJson.version,
202
+ description: "Gated workflow skills for Cursor.",
203
+ author: { name: "JustineDevs", email: "justinedevs@jstn.site" },
204
+ license: "MIT",
205
+ keywords: ["cursor", "plugin", "skills", "workflow"],
206
+ });
207
+ await copySkills(path.join(plugin, "skills"));
208
+ await writeText(path.join(plugin, "rules", "meta-architect.mdc"), cursorRule());
209
+ }
210
+
211
+ async function buildAntigravity(output) {
212
+ await writeJson(path.join(output, "plugin.json"), {
213
+ name: "meta-architect",
214
+ version: packageJson.version,
215
+ });
216
+ await copySkills(path.join(output, "skills"));
217
+ await writeText(
218
+ path.join(output, "rules", "meta-architect.md"),
219
+ baselineInstructions("Antigravity"),
220
+ );
221
+ }
222
+
223
+ async function buildGemini(output) {
224
+ await writeJson(path.join(output, "gemini-extension.json"), {
225
+ name: "meta-architect",
226
+ version: packageJson.version,
227
+ description: "Meta-Architect gated workflow skills for Gemini CLI.",
228
+ contextFileName: "GEMINI.md",
229
+ });
230
+ await writeText(path.join(output, "GEMINI.md"), baselineInstructions("Gemini CLI"));
231
+ await copySkills(path.join(output, "skills"));
232
+ }
233
+
234
+ async function buildOpenCode(output) {
235
+ await copySkills(path.join(output, ".opencode", "skills"));
236
+ await writeText(path.join(output, "AGENTS.md"), baselineInstructions("OpenCode"));
237
+ }
238
+
239
+ async function buildPi(output) {
240
+ await copySkills(path.join(output, "skills"));
241
+ }
242
+
243
+ async function buildOpenClaw(output) {
244
+ await copySkills(path.join(output, "skills"));
245
+ await writeText(path.join(output, "AGENTS.md"), baselineInstructions("OpenClaw"));
246
+ }
247
+
248
+ async function buildCline(output) {
249
+ await writeText(path.join(output, ".clinerules"), baselineInstructions("Cline"));
250
+ await copySkills(path.join(output, ".cline", "skills"));
251
+ }
252
+
253
+ async function buildContinue(output) {
254
+ await copySkills(path.join(output, "skills"));
255
+ await writeText(
256
+ path.join(output, ".continue", "rules", "meta-architect.md"),
257
+ baselineInstructions("Continue"),
258
+ );
259
+ }
260
+
261
+ async function buildGoose(output) {
262
+ await copySkills(path.join(output, "skills"));
263
+ await writeText(path.join(output, "AGENTS.md"), baselineInstructions("Goose"));
264
+ }
265
+
266
+ const builders = {
267
+ codex: buildCodex,
268
+ "claude-code": buildClaude,
269
+ cursor: buildCursor,
270
+ antigravity: buildAntigravity,
271
+ "gemini-cli": buildGemini,
272
+ opencode: buildOpenCode,
273
+ pi: buildPi,
274
+ openclaw: buildOpenClaw,
275
+ cline: buildCline,
276
+ continue: buildContinue,
277
+ goose: buildGoose,
278
+ };
279
+
280
+ async function buildTarget(target, root) {
281
+ const output = path.join(root, target);
282
+ await fs.rm(output, { recursive: true, force: true });
283
+ await builders[target](output);
284
+ await writeJson(path.join(output, "BUILD-MANIFEST.json"), {
285
+ schemaVersion: "1.0",
286
+ name: "meta-architect",
287
+ version: packageJson.version,
288
+ target,
289
+ support: TARGETS[target].support,
290
+ source: "skills/",
291
+ description: TARGETS[target].description,
292
+ install: TARGETS[target].install,
293
+ publish: TARGETS[target].publish,
294
+ });
295
+ return output;
296
+ }
297
+
298
+ export async function buildPlugins({ output, targets }) {
299
+ await fs.mkdir(output, { recursive: true });
300
+ return Promise.all(targets.map((target) => buildTarget(target, output)));
301
+ }
302
+
303
+ async function main() {
304
+ const args = parseArgs(process.argv.slice(2));
305
+ const outputs = await buildPlugins(args);
306
+ console.log(outputs.join("\n"));
307
+ }
308
+
309
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
310
+ main().catch((error) => {
311
+ console.error(error.message);
312
+ process.exitCode = 1;
313
+ });
314
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from "node:child_process";
4
+ import path from "node:path";
5
+ import process from "node:process";
6
+ import { buildPlugins, supportedPluginTargets } from "./plugin-build.js";
7
+
8
+ const repoRoot = process.cwd();
9
+ const output = path.join(repoRoot, "dist", "vendor-plugins");
10
+ const publishers = {};
11
+
12
+ function parseArgs(argv) {
13
+ const targets = [];
14
+ let execute = false;
15
+ for (let index = 0; index < argv.length; index += 1) {
16
+ const arg = argv[index];
17
+ if (arg === "--target" || arg === "--targets") {
18
+ targets.push(...(argv[index + 1] ?? "").split(",").filter(Boolean));
19
+ index += 1;
20
+ } else if (arg === "--execute") {
21
+ execute = true;
22
+ } else if (arg === "--help" || arg === "-h") {
23
+ console.log("Usage: npm run plugin:publish -- --target pi [--execute]");
24
+ process.exit(0);
25
+ }
26
+ }
27
+ if (targets.length !== 1) throw new Error("plugin:publish requires exactly one --target");
28
+ if (targets[0] === "all")
29
+ throw new Error("Publishing all hosts at once is unsafe; publish one target at a time");
30
+ if (!supportedPluginTargets.includes(targets[0]))
31
+ throw new Error(`Unknown plugin target: ${targets[0]}`);
32
+ return { target: targets[0], execute };
33
+ }
34
+
35
+ async function main() {
36
+ const { target, execute } = parseArgs(process.argv.slice(2));
37
+ const [targetRoot] = await buildPlugins({ output, targets: [target] });
38
+ const publisher = publishers[target];
39
+ if (!publisher) {
40
+ console.log(
41
+ JSON.stringify(
42
+ {
43
+ target,
44
+ status: "prepared",
45
+ path: targetRoot,
46
+ next: "Commit the generated directory to the host marketplace or repository required by this host.",
47
+ },
48
+ null,
49
+ 2,
50
+ ),
51
+ );
52
+ return;
53
+ }
54
+
55
+ if (!execute) {
56
+ console.log(
57
+ JSON.stringify(
58
+ {
59
+ target,
60
+ status: "dry-run",
61
+ path: targetRoot,
62
+ command: [publisher.command, ...publisher.args].join(" "),
63
+ },
64
+ null,
65
+ 2,
66
+ ),
67
+ );
68
+ return;
69
+ }
70
+
71
+ execFileSync(publisher.command, publisher.args, { cwd: targetRoot, stdio: "inherit" });
72
+ }
73
+
74
+ main().catch((error) => {
75
+ console.error(error.message);
76
+ process.exitCode = 1;
77
+ });
@@ -226,6 +226,7 @@ function syncPluginVersions(nextVersion) {
226
226
  for (const file of [
227
227
  path.join("plugins", "meta-architect", ".app.json"),
228
228
  path.join("plugins", "meta-architect", ".mcp.json"),
229
+ path.join("plugins", "meta-architect", "obsidian", "manifest.json"),
229
230
  ]) {
230
231
  const value = readJson(file);
231
232
  value.version = nextVersion;
@@ -236,6 +237,16 @@ function syncPluginVersions(nextVersion) {
236
237
  const pluginManifest = readJson(pluginManifestFile);
237
238
  pluginManifest.version = nextVersion;
238
239
  writePluginManifestJson(pluginManifestFile, pluginManifest);
240
+
241
+ const claudePluginFile = path.join("plugins", "meta-architect", ".claude-plugin", "plugin.json");
242
+ const claudePlugin = readJson(claudePluginFile);
243
+ claudePlugin.version = nextVersion;
244
+ writeJson(claudePluginFile, claudePlugin);
245
+
246
+ const claudeMarketplaceFile = path.join(".claude-plugin", "marketplace.json");
247
+ const claudeMarketplace = readJson(claudeMarketplaceFile);
248
+ claudeMarketplace.metadata.version = nextVersion;
249
+ writeJson(claudeMarketplaceFile, claudeMarketplace);
239
250
  }
240
251
 
241
252
  function syncCurrentReleaseFiles(oldVersion, nextVersion) {
@@ -48,11 +48,22 @@ function latestCdnInstall() {
48
48
  function verifyInstallBlock(file) {
49
49
  const content = readText(file);
50
50
  const cdnInstall = latestCdnInstall();
51
- if (!content.includes(CANONICAL_INSTALL) && !content.includes(cdnInstall)) {
51
+ const htmlCdnInstall = cdnInstall.replaceAll("&&", "&amp;&amp;");
52
+ const normalizedContent = content.replaceAll("\\|", "|");
53
+ const splitCdnInstall = [
54
+ "curl -fsSLo install.sh https://cdn.jsdelivr.net/gh/JustineDevs/meta-architect@latest/scripts/install.sh",
55
+ "curl -fsSLo install.sh.sha256 https://cdn.jsdelivr.net/gh/JustineDevs/meta-architect@latest/scripts/install.sh.sha256",
56
+ "sed 's#scripts/install.sh#install.sh#' install.sh.sha256 | sha256sum -c -",
57
+ "sh install.sh",
58
+ ].every((command) => normalizedContent.includes(command));
59
+ if (!content.includes(CANONICAL_INSTALL) && !content.includes(cdnInstall) && !splitCdnInstall) {
52
60
  return;
53
61
  }
54
62
 
55
- assert(content.includes(cdnInstall), `${file}: missing jsDelivr POSIX installer command`);
63
+ assert(
64
+ content.includes(cdnInstall) || content.includes(htmlCdnInstall) || splitCdnInstall,
65
+ `${file}: missing jsDelivr POSIX installer command`,
66
+ );
56
67
  assert(content.includes(CANONICAL_INSTALL), `${file}: missing canonical npm install command`);
57
68
  assert(content.includes(CANONICAL_LAUNCH), `${file}: missing canonical launch command`);
58
69
  assert(content.includes(UNINSTALL_MA), `${file}: missing uninstall Meta-Architect command`);
@@ -156,7 +167,7 @@ function verifyCoverageDoc({ version, gitTag }) {
156
167
  function verifyReadmeReleaseSurface({ gitTag }) {
157
168
  const content = readText("README.md");
158
169
  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">`;
170
+ const bannerImage = `<img src="./docs/assets/banner.png" alt="Meta-Architect: quality gates and evidence verification for AI coding agents" width="1000">`;
160
171
  assert(content.includes("> [!NOTE]"), "README.md: missing product-positioning note admonition");
161
172
  assert(
162
173
  content.includes(
@@ -185,7 +196,11 @@ function verifyReadmeReleaseSurface({ gitTag }) {
185
196
  ),
186
197
  "README.md: missing GitHub release badge",
187
198
  );
188
- assert(content.includes(logoImage), "README.md: release-pinned logo missing");
199
+ assert(
200
+ fs.existsSync(path.join("docs", "assets", "banner.png")),
201
+ "docs/assets/banner.png: missing",
202
+ );
203
+ assert(content.includes(bannerImage), "README.md: banner image missing");
189
204
  assert(
190
205
  !content.includes("raw.githubusercontent.com/JustineDevs/meta-architect/main/"),
191
206
  "README.md: stable docs must not reference mutable main",
@@ -356,12 +371,28 @@ function main() {
356
371
  const pluginManifest = readJson(
357
372
  path.join("plugins", "meta-architect", ".codex-plugin", "plugin.json"),
358
373
  );
374
+ const claudeMarketplace = readJson(path.join(".claude-plugin", "marketplace.json"));
375
+ const claudePlugin = readJson(
376
+ path.join("plugins", "meta-architect", ".claude-plugin", "plugin.json"),
377
+ );
359
378
  assert(pluginApp.version === version, "plugins/meta-architect/.app.json: version drift");
360
379
  assert(pluginMcp.version === version, "plugins/meta-architect/.mcp.json: version drift");
361
380
  assert(
362
381
  pluginManifest.version === version,
363
382
  "plugins/meta-architect/.codex-plugin/plugin.json: version drift",
364
383
  );
384
+ assert(
385
+ claudeMarketplace.metadata?.version === version,
386
+ ".claude-plugin/marketplace.json: version drift",
387
+ );
388
+ assert(
389
+ claudeMarketplace.plugins?.some((plugin) => plugin.source === "./plugins/meta-architect"),
390
+ ".claude-plugin/marketplace.json: missing Meta-Architect plugin source",
391
+ );
392
+ assert(
393
+ claudePlugin.version === version,
394
+ "plugins/meta-architect/.claude-plugin/plugin.json: version drift",
395
+ );
365
396
 
366
397
  for (const file of [
367
398
  "README.md",