@jstn-sdk/ma 0.1.7 → 0.1.8

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.
package/README.md CHANGED
@@ -18,9 +18,9 @@
18
18
  </div>
19
19
 
20
20
  > [!IMPORTANT]
21
- > Meta-Architect `v0.1.7` is a production-grade skills line.
21
+ > Meta-Architect `v0.1.8` is a production-grade skills line.
22
22
  > It is not a lightweight demo branch.
23
- > From `v0.1.7` onward, the package is expected to ship with stable skill contracts, deterministic packaging, explicit release gates, and honest install and publish surfaces.
23
+ > From `v0.1.8` onward, the package is expected to ship with stable skill contracts, deterministic packaging, explicit release gates, and honest install and publish surfaces.
24
24
 
25
25
  ## Overview
26
26
 
@@ -57,7 +57,7 @@ It adds:
57
57
  </tr>
58
58
  <tr>
59
59
  <td><strong>Release line</strong></td>
60
- <td><code>v0.1.7</code></td>
60
+ <td><code>v0.1.8</code></td>
61
61
  </tr>
62
62
  <tr>
63
63
  <td><strong>License</strong></td>
@@ -230,7 +230,7 @@ Required output:
230
230
  5. Data model and storage choices
231
231
  6. Auth/security considerations
232
232
  7. DX/UX considerations
233
- 8. Delivery plan for v0.1.7
233
+ 8. Delivery plan for v0.1.8
234
234
  9. Risks and trade-offs
235
235
  10. Decision log
236
236
  11. Exact next trigger to run after this
@@ -256,10 +256,16 @@ See [example/usage-workflow.md](./example/usage-workflow.md) for the full prompt
256
256
  If you are working from a repository directly and need scaffolded local support files, use:
257
257
 
258
258
  ```bash
259
+ ma bootstrap
260
+ ma doctor
259
261
  ma setup
260
262
  ma
261
263
  ```
262
264
 
265
+ Recommended lazy-user path:
266
+ - run `ma bootstrap` first to repair packaged assets, scaffold local runtime files, and verify the environment
267
+ - use `ma doctor` later when you want a check-only readiness report without changing files
268
+
263
269
  Expected output for `ma setup`:
264
270
 
265
271
  ```text
@@ -408,10 +414,22 @@ What `ma setup` and `ma init` do:
408
414
  - they prepare `.ma/` runtime files such as context, specs, plans, evidence, and runbook files
409
415
  - they do not run the skill workflow by themselves
410
416
 
417
+ What `ma bootstrap` does:
418
+ - checks whether `codex` is callable
419
+ - repairs installed skills and support-bundle assets when possible
420
+ - runs local scaffold setup
421
+ - reports `READY`, `READY_WITH_WARNINGS`, or `BLOCKED`
422
+
423
+ What `ma doctor` does:
424
+ - runs the same environment checks without changing files
425
+ - prints the current readiness state and exact next step
426
+
411
427
  What to use when:
412
428
  - use Codex and run the skills in-session
413
429
  - use `$maestro` when you want Meta-Architect to choose the best next step for you
414
430
  - use `$arch -> $sage -> $flow -> $vet -> $vibe -> $build` inside the Codex session
431
+ - use `ma bootstrap` when you want the lazy-user setup path
432
+ - use `ma doctor` when you want a check-only environment report
415
433
  - use `ma setup` or `ma init` only when you want local scaffolding or scripted helper automation from the terminal
416
434
  - use `ma sdk-path` when you need the exact installed support-bundle path for packaged prompts, MCP files, sprint files, scripts, plugin metadata, or templates
417
435
 
@@ -587,7 +605,7 @@ Release automation:
587
605
  | [Plugin README](./plugins/meta-architect/README.md) | plugin distribution surface |
588
606
  | [Collaborative Whiteboard Mission](./missions/collaborative-whiteboard/mission.md) | concrete scenario walkthrough |
589
607
  | [Release Spec](./docs/release-spec.md) | release and gate policy |
590
- | [Release Readiness](./docs/qa/release-readiness-0.1.7.md) | QA evidence for the `v0.1.7` line |
608
+ | [Release Readiness](./docs/qa/release-readiness-0.1.8.md) | QA evidence for the `v0.1.8` line |
591
609
 
592
610
  ## Release Hygiene
593
611
 
package/bin/ma.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { runBootstrap, runDoctor } from "../src/bootstrap.js";
3
4
  import {
4
5
  evaluateBuildGate,
5
6
  formatBuildBlockers,
@@ -36,6 +37,8 @@ import { syncStatusUpdates } from "../src/state-sync.js";
36
37
  function printUsage() {
37
38
  console.error("Secondary helper commands:");
38
39
  console.error(" ma");
40
+ console.error(" ma bootstrap");
41
+ console.error(" ma doctor");
39
42
  console.error(" ma setup");
40
43
  console.error(" ma init");
41
44
  console.error(' ma idea "..."');
@@ -220,6 +223,18 @@ async function main() {
220
223
  return;
221
224
  }
222
225
 
226
+ if (command === "bootstrap") {
227
+ const outcome = await runBootstrap();
228
+ process.exitCode = outcome.result === "BLOCKED" ? 1 : 0;
229
+ return;
230
+ }
231
+
232
+ if (command === "doctor") {
233
+ const outcome = await runDoctor();
234
+ process.exitCode = outcome.result === "BLOCKED" ? 1 : 0;
235
+ return;
236
+ }
237
+
223
238
  if (command === "init") {
224
239
  const created = await runInit();
225
240
  console.log("meta-architect init");
package/docs/README.md CHANGED
@@ -17,7 +17,7 @@ Meta-Architect documentation is organized by operator task.
17
17
 
18
18
  ## QA and readiness
19
19
 
20
- - [Release Readiness 0.1.7](./qa/release-readiness-0.1.7.md)
20
+ - [Release Readiness 0.1.8](./qa/release-readiness-0.1.8.md)
21
21
 
22
22
  ## Repo structure references
23
23
 
@@ -74,7 +74,7 @@ Required output:
74
74
  5. Data model and storage choices
75
75
  6. Auth/security considerations
76
76
  7. DX/UX considerations
77
- 8. Delivery plan for v0.1.7
77
+ 8. Delivery plan for v0.1.8
78
78
  9. Risks and trade-offs
79
79
  10. Decision log
80
80
  11. Exact next trigger to run after this
@@ -181,6 +181,16 @@ Easy rule:
181
181
  - they prepare context, specs, plans, evidence, and runbook files
182
182
  - they do not automatically run the skill workflow
183
183
 
184
+ `ma bootstrap` is the lazy-user path:
185
+ - it checks whether `codex` is callable
186
+ - it repairs installed skills and support-bundle assets when possible
187
+ - it runs local scaffold setup
188
+ - it reports `READY`, `READY_WITH_WARNINGS`, or `BLOCKED`
189
+
190
+ `ma doctor` is the check-only path:
191
+ - it runs the same environment checks without changing files
192
+ - it prints the current readiness state and exact next step
193
+
184
194
  `ma sdk-path` prints the installed packaged support-bundle root for relevant files such as prompts, MCP files, sprint files, scripts, plugin metadata, and templates.
185
195
 
186
196
  ## 5. Configure MCP / GitMCP
@@ -1,25 +1,25 @@
1
- # Release Readiness 0.1.7
1
+ # Release Readiness 0.1.8
2
2
 
3
3
  ## Production bar
4
4
 
5
- `v0.1.7` is treated as production only when:
5
+ `v0.1.8` is treated as production only when:
6
6
  - the package installs cleanly from the canonical public install command
7
7
  - the Codex-hosted runtime path works end to end
8
8
  - the helper flow remains valid for scripted verification
9
- - release docs, package metadata, and workflows all agree on `0.1.7`
9
+ - release docs, package metadata, and workflows all agree on `0.1.8`
10
10
 
11
11
  Target release state:
12
- - npm package: `@jstn-sdk/ma@0.1.7`
12
+ - npm package: `@jstn-sdk/ma@0.1.8`
13
13
  - npm registry state: pending publish
14
- - publishability note: `0.1.6` is already published, so `0.1.7` is the next publishable package line
15
- - git tag: `v0.1.7`
16
- - GitHub release: pending publish for `v0.1.7`
14
+ - publishability note: `0.1.7` is already published, so `0.1.8` is the next publishable package line
15
+ - git tag: `v0.1.8`
16
+ - GitHub release: pending publish for `v0.1.8`
17
17
 
18
18
  ## Production checklist
19
19
 
20
20
  - skills-first product identity: PASS
21
21
  - package/plugin identity aligned to `@jstn-sdk/ma`: PASS
22
- - version/tag alignment `0.1.7` / `v0.1.7`: PASS
22
+ - version/tag alignment `0.1.8` / `v0.1.8`: PASS
23
23
  - install/uninstall docs aligned: PASS
24
24
  - onboarding is concise and sequential: PASS
25
25
  - helper command documented as secondary: PASS
@@ -1,13 +1,13 @@
1
- # v0.1.7 Requirements & Rules
1
+ # v0.1.8 Requirements & Rules
2
2
 
3
3
  ## Production definition
4
4
 
5
- Meta-Architect `v0.1.7` is production only when:
5
+ Meta-Architect `v0.1.8` is production only when:
6
6
  1. the package/install surface works
7
7
  2. the in-session skill workflow from `$arch` through `$build` works
8
8
  3. the release evidence matches the actual package and git tag
9
9
 
10
- ## What `v0.1.7` must have
10
+ ## What `v0.1.8` must have
11
11
 
12
12
  ### 1. Canonical package/runtime path
13
13
 
@@ -49,11 +49,11 @@ Canonical state files:
49
49
 
50
50
  ### 4. Required release evidence
51
51
 
52
- - `package.json` version `0.1.7`
53
- - git tag `v0.1.7`
52
+ - `package.json` version `0.1.8`
53
+ - git tag `v0.1.8`
54
54
  - `RELEASE.md`
55
55
  - `CHANGELOG.md`
56
- - `docs/qa/release-readiness-0.1.7.md`
56
+ - `docs/qa/release-readiness-0.1.8.md`
57
57
  - green `npm run release:check`
58
58
 
59
59
  ### 5. Dist-tag discipline
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jstn-sdk/ma",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Codex-native skills system for architecture, evidence, review, and gated build guidance.",
5
5
  "license": "MIT",
6
6
  "author": "JustineDevs",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "meta-architect",
3
3
  "displayName": "Meta-Architect",
4
- "version": "0.1.7",
4
+ "version": "0.1.8",
5
5
  "description": "Programmatic architecture and verified engineering skills for Codex-native workflows.",
6
6
  "entry": "./README.md",
7
7
  "skillsDir": "./skills"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "meta-architect",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Skills-first workflow layer for Codex with 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.1.7",
3
+ "version": "0.1.8",
4
4
  "collections": [
5
5
  "sindresorhus/awesome",
6
6
  "dzharii/awesome-typescript",
@@ -105,7 +105,7 @@ When consuming the plugin:
105
105
  The plugin version should track the release scope of the core repo.
106
106
 
107
107
  For this repository:
108
- - plugin scope is aligned to Meta-Architect `v0.1.7`
108
+ - plugin scope is aligned to Meta-Architect `v0.1.8`
109
109
  - any breaking contract change should be versioned intentionally
110
110
 
111
111
  The plugin is one distribution surface of the same product, not a separate product line.
@@ -0,0 +1,313 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { loadMcpServers } from "./mcp-config.js";
6
+ import { getRepoRoot, getRuntimeWritePath } from "./paths.js";
7
+ import {
8
+ areSkillsInstalled,
9
+ ensureSkillsInstalled,
10
+ ensureSupportBundleInstalled,
11
+ getSkillInstallRoot,
12
+ getSupportBundleRoot,
13
+ isSupportBundleInstalled,
14
+ } from "./skill-installer.js";
15
+ import { runInit } from "./skills.js";
16
+
17
+ function makeStatus(kind, label, detail = "") {
18
+ return { kind, label, detail };
19
+ }
20
+
21
+ function resolveCodexCommand() {
22
+ return process.env.MA_CODEX_BIN ?? "codex";
23
+ }
24
+
25
+ function runCommand(command, args) {
26
+ const isNodeScript = [".js", ".mjs", ".cjs"].includes(path.extname(command));
27
+ const finalCommand = isNodeScript ? process.execPath : command;
28
+ const finalArgs = isNodeScript ? [command, ...args] : args;
29
+ return spawnSync(finalCommand, finalArgs, { encoding: "utf8" });
30
+ }
31
+
32
+ function inspectCodex() {
33
+ const command = resolveCodexCommand();
34
+ const result = runCommand(command, ["--version"]);
35
+ if (result.error || result.status !== 0) {
36
+ const detail = result.error?.message ?? result.stderr.trim() ?? result.stdout.trim();
37
+ return {
38
+ ok: false,
39
+ command,
40
+ detail: detail || "Codex command failed",
41
+ version: "",
42
+ };
43
+ }
44
+
45
+ return {
46
+ ok: true,
47
+ command,
48
+ detail: "",
49
+ version: result.stdout.trim(),
50
+ };
51
+ }
52
+
53
+ function listCodexPaths() {
54
+ const result = spawnSync("which", ["-a", "codex"], { encoding: "utf8" });
55
+ if (result.error || result.status !== 0) {
56
+ return [];
57
+ }
58
+
59
+ return result.stdout
60
+ .split("\n")
61
+ .map((line) => line.trim())
62
+ .filter(Boolean);
63
+ }
64
+
65
+ function isWindowsPathInWsl(value) {
66
+ return value.startsWith("/mnt/") && value.includes("/AppData/Roaming/npm/");
67
+ }
68
+
69
+ async function writeCodexWrapper() {
70
+ const wrapperDir = path.join(os.homedir(), ".local", "bin");
71
+ const wrapperPath = path.join(wrapperDir, "codex");
72
+ const content = `#!/usr/bin/env bash
73
+ set -euo pipefail
74
+
75
+ if command -v node >/dev/null 2>&1; then
76
+ NODE_BIN="$(command -v node)"
77
+ NODE_DIR="$(dirname "$NODE_BIN")"
78
+ if [ -x "$NODE_DIR/codex" ] && [ "$NODE_DIR/codex" != "$0" ]; then
79
+ exec "$NODE_DIR/codex" "$@"
80
+ fi
81
+ fi
82
+
83
+ while IFS= read -r candidate; do
84
+ [ -n "$candidate" ] || continue
85
+ if [ "$candidate" = "$0" ]; then
86
+ continue
87
+ fi
88
+ case "$candidate" in
89
+ /mnt/*) continue ;;
90
+ esac
91
+ exec "$candidate" "$@"
92
+ done < <(which -a codex 2>/dev/null || true)
93
+
94
+ echo "Unable to locate a Linux Codex binary. Reinstall with: npm install -g @openai/codex@latest" >&2
95
+ exit 1
96
+ `;
97
+
98
+ await fs.mkdir(wrapperDir, { recursive: true });
99
+ await fs.writeFile(wrapperPath, content, { mode: 0o755 });
100
+ await fs.chmod(wrapperPath, 0o755);
101
+ const pathEntries = (process.env.PATH ?? "").split(path.delimiter).filter(Boolean);
102
+ if (!pathEntries.includes(wrapperDir)) {
103
+ process.env.PATH = [wrapperDir, ...pathEntries].join(path.delimiter);
104
+ }
105
+ return wrapperPath;
106
+ }
107
+
108
+ async function inspectCodexResolution({ fix }) {
109
+ if (process.platform !== "linux") {
110
+ return null;
111
+ }
112
+
113
+ const paths = listCodexPaths();
114
+ if (paths.length === 0) {
115
+ return null;
116
+ }
117
+
118
+ const first = paths[0];
119
+ const linuxAlternative = paths.find((candidate) => !isWindowsPathInWsl(candidate));
120
+ if (!isWindowsPathInWsl(first) || !linuxAlternative) {
121
+ return null;
122
+ }
123
+
124
+ if (!fix) {
125
+ return makeStatus(
126
+ "WARN",
127
+ "codex path points at a Windows npm install inside WSL",
128
+ `Preferred path is ${first}; Linux alternative exists at ${linuxAlternative}`,
129
+ );
130
+ }
131
+
132
+ const wrapperPath = await writeCodexWrapper();
133
+ return makeStatus(
134
+ "FIXED",
135
+ "codex path will prefer a Linux wrapper inside WSL",
136
+ `Installed wrapper at ${wrapperPath}`,
137
+ );
138
+ }
139
+
140
+ async function inspectLocalScaffold() {
141
+ const requiredFiles = [
142
+ getRuntimeWritePath("decisions.json"),
143
+ getRuntimeWritePath("release.json"),
144
+ path.join(getRepoRoot(), "mcp", "servers.json"),
145
+ ];
146
+
147
+ for (const file of requiredFiles) {
148
+ try {
149
+ await fs.access(file);
150
+ } catch {
151
+ return false;
152
+ }
153
+ }
154
+
155
+ return true;
156
+ }
157
+
158
+ async function inspectMcpState() {
159
+ try {
160
+ const servers = await loadMcpServers();
161
+ if (servers.servers.length === 0) {
162
+ return makeStatus(
163
+ "WARN",
164
+ "mcp/servers.json exists but contains no approved repo-backed sources",
165
+ "Add exact upstream GitMCP repo endpoints before claiming VERIFIED evidence.",
166
+ );
167
+ }
168
+
169
+ return makeStatus(
170
+ "OK",
171
+ "mcp/servers.json has approved starter sources",
172
+ `${servers.servers.length} configured source(s)`,
173
+ );
174
+ } catch (error) {
175
+ return makeStatus("WARN", "mcp/servers.json is not ready for evidence binding", error.message);
176
+ }
177
+ }
178
+
179
+ async function runEnvironmentFlow({ fix }) {
180
+ const statuses = [];
181
+
182
+ const codexResolution = await inspectCodexResolution({ fix });
183
+ if (codexResolution) {
184
+ statuses.push(codexResolution);
185
+ }
186
+
187
+ const codex = inspectCodex();
188
+ if (codex.ok) {
189
+ statuses.push(makeStatus("OK", "codex command is available", codex.version));
190
+ } else {
191
+ statuses.push(
192
+ makeStatus(
193
+ "BLOCKED",
194
+ "codex command is not usable",
195
+ "Install or repair Codex with: npm install -g @openai/codex@latest",
196
+ ),
197
+ );
198
+ }
199
+
200
+ const skillInstallRoot = getSkillInstallRoot();
201
+ if (fix) {
202
+ const result = await ensureSkillsInstalled();
203
+ statuses.push(
204
+ makeStatus(
205
+ result.installed.length > 0 ? "FIXED" : "OK",
206
+ "Codex skills are installed",
207
+ skillInstallRoot,
208
+ ),
209
+ );
210
+ } else {
211
+ statuses.push(
212
+ makeStatus(
213
+ (await areSkillsInstalled()) ? "OK" : "WARN",
214
+ "Codex skills install state",
215
+ skillInstallRoot,
216
+ ),
217
+ );
218
+ }
219
+
220
+ const supportBundleRoot = getSupportBundleRoot();
221
+ if (fix) {
222
+ const result = await ensureSupportBundleInstalled();
223
+ statuses.push(
224
+ makeStatus(
225
+ result.installed.length > 0 ? "FIXED" : "OK",
226
+ "support bundle is installed",
227
+ supportBundleRoot,
228
+ ),
229
+ );
230
+ } else {
231
+ statuses.push(
232
+ makeStatus(
233
+ (await isSupportBundleInstalled()) ? "OK" : "WARN",
234
+ "support bundle install state",
235
+ supportBundleRoot,
236
+ ),
237
+ );
238
+ }
239
+
240
+ if (fix) {
241
+ await runInit();
242
+ statuses.push(
243
+ makeStatus(
244
+ "FIXED",
245
+ "local Meta-Architect scaffold is ready",
246
+ path.join(getRepoRoot(), ".ma"),
247
+ ),
248
+ );
249
+ } else {
250
+ statuses.push(
251
+ makeStatus(
252
+ (await inspectLocalScaffold()) ? "OK" : "WARN",
253
+ "local Meta-Architect scaffold state",
254
+ path.join(getRepoRoot(), ".ma"),
255
+ ),
256
+ );
257
+ }
258
+
259
+ statuses.push(await inspectMcpState());
260
+ return statuses;
261
+ }
262
+
263
+ function summarizeStatuses(statuses) {
264
+ const hasBlocked = statuses.some((status) => status.kind === "BLOCKED");
265
+ const hasWarn = statuses.some((status) => status.kind === "WARN");
266
+ if (hasBlocked) {
267
+ return "BLOCKED";
268
+ }
269
+ if (hasWarn) {
270
+ return "READY_WITH_WARNINGS";
271
+ }
272
+ return "READY";
273
+ }
274
+
275
+ function printStatuses(title, statuses) {
276
+ console.log(title);
277
+ console.log("=".repeat(title.length));
278
+ for (const status of statuses) {
279
+ const label = status.kind.padEnd(7, " ");
280
+ if (status.detail) {
281
+ console.log(`${label} ${status.label}: ${status.detail}`);
282
+ } else {
283
+ console.log(`${label} ${status.label}`);
284
+ }
285
+ }
286
+ const result = summarizeStatuses(statuses);
287
+ console.log();
288
+ console.log(`Result: ${result}`);
289
+ if (result === "BLOCKED") {
290
+ console.log("Next: install or repair blocked prerequisites, then rerun `ma bootstrap`.");
291
+ } else if (result === "READY_WITH_WARNINGS") {
292
+ console.log("Next: review warnings, then start Codex or run `ma run '$maestro'`.");
293
+ } else {
294
+ console.log("Next: start Codex or run `ma run '$maestro'`.");
295
+ }
296
+ return result;
297
+ }
298
+
299
+ export async function runDoctor() {
300
+ const statuses = await runEnvironmentFlow({ fix: false });
301
+ return {
302
+ statuses,
303
+ result: printStatuses("Meta-Architect Doctor", statuses),
304
+ };
305
+ }
306
+
307
+ export async function runBootstrap() {
308
+ const statuses = await runEnvironmentFlow({ fix: true });
309
+ return {
310
+ statuses,
311
+ result: printStatuses("Meta-Architect Bootstrap", statuses),
312
+ };
313
+ }
package/src/launcher.js CHANGED
@@ -2,6 +2,8 @@ import { spawnSync } from "node:child_process";
2
2
  import path from "node:path";
3
3
 
4
4
  const nativeCommands = new Set([
5
+ "bootstrap",
6
+ "doctor",
5
7
  "setup",
6
8
  "init",
7
9
  "idea",
@@ -38,7 +38,7 @@ export class McpSseClient {
38
38
  capabilities: {},
39
39
  clientInfo: {
40
40
  name: "meta-architect",
41
- version: "0.1.7",
41
+ version: "0.1.8",
42
42
  },
43
43
  });
44
44
 
package/src/skills.js CHANGED
@@ -508,8 +508,8 @@ export async function runInit() {
508
508
  path.join(getRepoRoot(), "docs", "release-spec.md"),
509
509
  ],
510
510
  [
511
- path.join(packageRoot, "docs", "qa", "release-readiness-0.1.7.md"),
512
- path.join(getRepoRoot(), "docs", "qa", "release-readiness-0.1.7.md"),
511
+ path.join(packageRoot, "docs", "qa", "release-readiness-0.1.8.md"),
512
+ path.join(getRepoRoot(), "docs", "qa", "release-readiness-0.1.8.md"),
513
513
  ],
514
514
  ];
515
515