@jstn-sdk/ma 0.1.2 → 0.1.4

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
@@ -10,9 +10,9 @@
10
10
  </div>
11
11
 
12
12
  > [!IMPORTANT]
13
- > Meta-Architect `v0.1.2` is a production-grade skills line.
13
+ > Meta-Architect `v0.1.4` is a production-grade skills line.
14
14
  > It is not a lightweight demo branch.
15
- > From `v0.1.2` onward, the package is expected to ship with stable skill contracts, deterministic packaging, explicit release gates, and honest install and publish surfaces.
15
+ > From `v0.1.4` onward, the package is expected to ship with stable skill contracts, deterministic packaging, explicit release gates, and honest install and publish surfaces.
16
16
 
17
17
  ## Overview
18
18
 
@@ -44,7 +44,7 @@ It adds:
44
44
  </tr>
45
45
  <tr>
46
46
  <td><strong>Release line</strong></td>
47
- <td><code>v0.1.2</code></td>
47
+ <td><code>v0.1.4</code></td>
48
48
  </tr>
49
49
  <tr>
50
50
  <td><strong>License</strong></td>
@@ -193,7 +193,7 @@ Required output:
193
193
  5. Data model and storage choices
194
194
  6. Auth/security considerations
195
195
  7. DX/UX considerations
196
- 8. Delivery plan for v0.1.2
196
+ 8. Delivery plan for v0.1.4
197
197
  9. Risks and trade-offs
198
198
  10. Decision log
199
199
  11. Exact next trigger to run after this
@@ -447,6 +447,12 @@ Provenance note:
447
447
  - a local shell publish will fail with `Automatic provenance generation not supported for provider: null`
448
448
  - use the repository publish workflow when provenance is required
449
449
 
450
+ Release automation:
451
+ - `npm run release:sync` bumps and synchronizes the active release line only when watched release-relevant files changed
452
+ - `npm run release:advance` force-bumps the next patch line and rewrites the same version-bearing files
453
+ - `.github/workflows/release-sync.yml` runs the sync path on `main` pushes that touch watched release-relevant paths
454
+ - `.github/workflows/release-advance.yml` runs after a published GitHub release and advances the repo to the next patch line automatically
455
+
450
456
  > [!CAUTION]
451
457
  > Do not claim npm, GitHub release, or any other publish channel until that channel has actually succeeded.
452
458
  > Release documentation must match reality, not intent.
@@ -517,7 +523,7 @@ Provenance note:
517
523
  | [Plugin README](./plugins/meta-architect/README.md) | plugin distribution surface |
518
524
  | [Collaborative Whiteboard Mission](./missions/collaborative-whiteboard/mission.md) | concrete scenario walkthrough |
519
525
  | [Release Spec](./docs/release-spec.md) | release and gate policy |
520
- | [Release Readiness](./docs/qa/release-readiness-0.1.2.md) | QA evidence for the `v0.1.2` line |
526
+ | [Release Readiness](./docs/qa/release-readiness-0.1.4.md) | QA evidence for the `v0.1.4` line |
521
527
 
522
528
  ## Release Hygiene
523
529
 
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.2](./qa/release-readiness-0.1.2.md)
20
+ - [Release Readiness 0.1.4](./qa/release-readiness-0.1.4.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.2
77
+ 8. Delivery plan for v0.1.4
78
78
  9. Risks and trade-offs
79
79
  10. Decision log
80
80
  11. Exact next trigger to run after this
@@ -1,25 +1,25 @@
1
- # Release Readiness 0.1.2
1
+ # Release Readiness 0.1.4
2
2
 
3
3
  ## Production bar
4
4
 
5
- `v0.1.2` is treated as production only when:
5
+ `v0.1.4` 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.2`
9
+ - release docs, package metadata, and workflows all agree on `0.1.4`
10
10
 
11
11
  Target release state:
12
- - npm package: `@jstn-sdk/ma@0.1.2`
12
+ - npm package: `@jstn-sdk/ma@0.1.4`
13
13
  - npm registry state: pending publish
14
- - publishability note: `0.1.1` is already published, so `0.1.2` is the next publishable package line
15
- - git tag: `v0.1.2`
16
- - GitHub release: pending publish for `v0.1.2`
14
+ - publishability note: `0.1.3` is already published, so `0.1.4` is the next publishable package line
15
+ - git tag: `v0.1.4`
16
+ - GitHub release: pending publish for `v0.1.4`
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.2` / `v0.1.2`: PASS
22
+ - version/tag alignment `0.1.4` / `v0.1.4`: 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.2 Requirements & Rules
1
+ # v0.1.4 Requirements & Rules
2
2
 
3
3
  ## Production definition
4
4
 
5
- Meta-Architect `v0.1.2` is production only when:
5
+ Meta-Architect `v0.1.4` 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.2` must have
10
+ ## What `v0.1.4` 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.2`
53
- - git tag `v0.1.2`
52
+ - `package.json` version `0.1.4`
53
+ - git tag `v0.1.4`
54
54
  - `RELEASE.md`
55
55
  - `CHANGELOG.md`
56
- - `docs/qa/release-readiness-0.1.2.md`
56
+ - `docs/qa/release-readiness-0.1.4.md`
57
57
  - green `npm run release:check`
58
58
 
59
59
  ### 5. Dist-tag discipline
@@ -79,6 +79,13 @@ Canonical state files:
79
79
  - Prerelease publish: `npm publish --access public --tag <lane>`
80
80
  10. Verify dist-tags with `npm view @jstn-sdk/ma version dist-tags time --json`
81
81
 
82
+ ### 6.1 Release automation
83
+
84
+ - `npm run release:sync` updates the active release line when watched release-relevant files changed
85
+ - `npm run release:advance` force-bumps the next patch line after a completed release
86
+ - `.github/workflows/release-sync.yml` automates the sync path on `main`
87
+ - `.github/workflows/release-advance.yml` advances the repo to the next patch line after a published release
88
+
82
89
  ### 7. Provenance rule
83
90
 
84
91
  - `npm publish --provenance` is valid only from a supported cloud CI/CD provider
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jstn-sdk/ma",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Codex-native skills system for architecture, evidence, review, and gated build guidance.",
5
5
  "license": "MIT",
6
6
  "author": "JustineDevs",
@@ -60,6 +60,8 @@
60
60
  "status": "node ./bin/ma.js status",
61
61
  "build:gate": "node ./bin/ma.js run '$build'",
62
62
  "release:meta": "node ./scripts/release-metadata.js",
63
+ "release:sync": "node ./scripts/release-sync.js",
64
+ "release:advance": "node ./scripts/release-sync.js --force --bump patch",
63
65
  "release:verify": "node ./scripts/release-verify.js",
64
66
  "release:check": "npm run release:verify && npm run skills:manifest && npm run plugin:sync && npm run skills:validate && npm run plugin:verify && npm run skills:pack && npm run check && npm test && npm run pack:inspect",
65
67
  "skills:manifest": "node ./scripts/skills-manifest.js",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "meta-architect",
3
3
  "displayName": "Meta-Architect",
4
- "version": "0.1.2",
4
+ "version": "0.1.4",
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.2",
3
+ "version": "0.1.4",
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.2",
3
+ "version": "0.1.4",
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.2`
108
+ - plugin scope is aligned to Meta-Architect `v0.1.4`
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,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
+ }
@@ -38,7 +38,7 @@ export class McpSseClient {
38
38
  capabilities: {},
39
39
  clientInfo: {
40
40
  name: "meta-architect",
41
- version: "0.1.2",
41
+ version: "0.1.4",
42
42
  },
43
43
  });
44
44
 
package/src/skills.js CHANGED
@@ -344,8 +344,8 @@ export async function runInit() {
344
344
  path.join(getRepoRoot(), "docs", "release-spec.md"),
345
345
  ],
346
346
  [
347
- path.join(packageRoot, "docs", "qa", "release-readiness-0.1.2.md"),
348
- path.join(getRepoRoot(), "docs", "qa", "release-readiness-0.1.2.md"),
347
+ path.join(packageRoot, "docs", "qa", "release-readiness-0.1.4.md"),
348
+ path.join(getRepoRoot(), "docs", "qa", "release-readiness-0.1.4.md"),
349
349
  ],
350
350
  ];
351
351