release-skill 0.6.2 → 0.6.3
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.kimi-plugin/plugin.json +1 -1
- package/CHANGELOG.md +23 -0
- package/CONTRIBUTING.md +1 -1
- package/INSTALL.md +47 -2
- package/INSTALL.zh-CN.md +29 -2
- package/README.md +126 -9
- package/README.zh-CN.md +108 -9
- package/adapters/claude/.claude-plugin/marketplace.json +1 -1
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/claude/schemas/.render-manifest.json +10 -6
- package/adapters/claude/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/claude/schemas/release-plan.schema.json +65 -1
- package/adapters/claude/schemas/release-project.schema.json +73 -1
- package/adapters/claude/schemas/release-run.schema.json +11 -6
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/codex/schemas/.render-manifest.json +10 -6
- package/adapters/codex/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/codex/schemas/release-plan.schema.json +65 -1
- package/adapters/codex/schemas/release-project.schema.json +73 -1
- package/adapters/codex/schemas/release-run.schema.json +11 -6
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/kimi/schemas/.render-manifest.json +10 -6
- package/adapters/kimi/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/kimi/schemas/release-plan.schema.json +65 -1
- package/adapters/kimi/schemas/release-project.schema.json +73 -1
- package/adapters/kimi/schemas/release-run.schema.json +11 -6
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/workbuddy/schemas/.render-manifest.json +10 -6
- package/adapters/workbuddy/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/workbuddy/schemas/release-plan.schema.json +65 -1
- package/adapters/workbuddy/schemas/release-project.schema.json +73 -1
- package/adapters/workbuddy/schemas/release-run.schema.json +11 -6
- package/bin/release-skill-cli.mjs +181 -3
- package/bin/release-skill.bundle.mjs +6408 -1654
- package/package.json +2 -1
- package/platform-manifest.json +4 -4
- package/references/.render-manifest.json +5 -5
- package/references/01-state-machine.md +22 -2
- package/schemas/.render-manifest.json +10 -6
- package/schemas/postpublish-approval-record.schema.json +47 -0
- package/schemas/release-plan.schema.json +65 -1
- package/schemas/release-project.schema.json +73 -1
- package/schemas/release-run.schema.json +11 -6
- package/src/commands/approve.mjs +167 -1
- package/src/commands/distribute.mjs +411 -33
- package/src/commands/postverify.mjs +734 -0
- package/src/commands/prepare.mjs +280 -42
- package/src/commands/setup.mjs +715 -0
- package/src/commands/ship.mjs +152 -5
- package/src/commands/verify.mjs +92 -15
- package/src/core/approval.mjs +93 -68
- package/src/core/bounded-output.mjs +46 -0
- package/src/core/derived-artifact-gates.mjs +258 -0
- package/src/core/docs-refresh-preset.mjs +167 -0
- package/src/core/errors.mjs +4 -0
- package/src/core/hooks.mjs +28 -0
- package/src/core/marketplace-registry-entry.mjs +174 -0
- package/src/core/notify-handoff.mjs +76 -0
- package/src/core/postpublish-approval.mjs +110 -0
- package/src/core/postpublish.mjs +424 -7
- package/src/core/preset-executor.mjs +156 -0
- package/src/core/preset-gitwrite.mjs +463 -0
- package/src/core/presets.mjs +706 -0
- package/src/core/proposal-inbox.mjs +630 -0
- package/src/core/run.mjs +91 -6
package/src/core/run.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @module core/run
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { lstat, mkdir, readFile } from 'node:fs/promises';
|
|
15
|
+
import { lstat, mkdir, readFile, stat } from 'node:fs/promises';
|
|
16
16
|
import { realpathSync } from 'node:fs';
|
|
17
17
|
import { dirname, join, resolve, basename, relative, isAbsolute } from 'node:path';
|
|
18
18
|
import Ajv from 'ajv';
|
|
@@ -120,22 +120,107 @@ export function validateRun(run, options = {}) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Resolve a run path that may point at a run DIRECTORY (O6, 2026-08-18
|
|
125
|
+
* release-cycle investigation §3.2): verify `--run` ergonomically accepts a
|
|
126
|
+
* run directory and binds its `release-run.json`; a regular file input is
|
|
127
|
+
* returned unchanged so every existing file-path caller keeps its exact
|
|
128
|
+
* behaviour (compat).
|
|
129
|
+
*
|
|
130
|
+
* Fail-closed rules for the directory form:
|
|
131
|
+
* - a symlinked directory input is rejected (never silently dereferenced);
|
|
132
|
+
* - a directory without `release-run.json` names the expected file.
|
|
133
|
+
* A missing path is returned unchanged so the legacy readFile error surfaces.
|
|
134
|
+
*
|
|
135
|
+
* @param {string} runPath - Run file or run directory path.
|
|
136
|
+
* @returns {Promise<string>} The resolved run FILE path.
|
|
137
|
+
* @throws {ReleaseError} GATE_FAILED for symlinked or release-run.json-less
|
|
138
|
+
* directory inputs.
|
|
139
|
+
*/
|
|
140
|
+
export async function resolveRunPath(runPath) {
|
|
141
|
+
let stats;
|
|
142
|
+
try {
|
|
143
|
+
stats = await lstat(runPath);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
if (err?.code === 'ENOENT') return runPath; // legacy readFile error path
|
|
146
|
+
throw new ReleaseError(
|
|
147
|
+
GATE_FAILED,
|
|
148
|
+
`cannot inspect release run path: ${err.message}`,
|
|
149
|
+
{ runPath, cause: err.code },
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (stats.isFile()) return runPath; // unchanged file behaviour (compat)
|
|
154
|
+
|
|
155
|
+
if (stats.isSymbolicLink()) {
|
|
156
|
+
// A symlink that ultimately points at a directory would otherwise surface
|
|
157
|
+
// a raw EISDIR; resolve the target type and fail closed for directories.
|
|
158
|
+
let targetStats;
|
|
159
|
+
try {
|
|
160
|
+
targetStats = await stat(runPath);
|
|
161
|
+
} catch (err) {
|
|
162
|
+
if (err?.code === 'ENOENT') return runPath; // dangling: legacy error
|
|
163
|
+
throw new ReleaseError(
|
|
164
|
+
GATE_FAILED,
|
|
165
|
+
`cannot inspect release run path: ${err.message}`,
|
|
166
|
+
{ runPath, cause: err.code },
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (targetStats.isDirectory()) {
|
|
170
|
+
throw new ReleaseError(
|
|
171
|
+
GATE_FAILED,
|
|
172
|
+
'release run path is a symlinked directory; pass the run file (release-run.json) or the real run directory',
|
|
173
|
+
{ runPath },
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
return runPath; // symlinked FILE keeps the legacy readFile behaviour
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (stats.isDirectory()) {
|
|
180
|
+
const candidate = join(runPath, 'release-run.json');
|
|
181
|
+
try {
|
|
182
|
+
const candidateStats = await lstat(candidate);
|
|
183
|
+
if (!candidateStats.isFile()) {
|
|
184
|
+
throw new ReleaseError(
|
|
185
|
+
GATE_FAILED,
|
|
186
|
+
`release run directory does not contain a regular release-run.json: ${runPath}`,
|
|
187
|
+
{ runPath, expected: 'release-run.json' },
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
} catch (err) {
|
|
191
|
+
if (err instanceof ReleaseError) throw err;
|
|
192
|
+
throw new ReleaseError(
|
|
193
|
+
GATE_FAILED,
|
|
194
|
+
`release run directory must contain release-run.json: ${err.message}`,
|
|
195
|
+
{ runPath, expected: 'release-run.json', cause: err.code },
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return candidate;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return runPath; // anything else keeps the legacy readFile error path
|
|
202
|
+
}
|
|
203
|
+
|
|
123
204
|
/**
|
|
124
205
|
* Load, parse, and validate a run file from disk.
|
|
125
206
|
*
|
|
126
|
-
*
|
|
207
|
+
* Accepts either the run file itself or its containing run directory (O6);
|
|
208
|
+
* a directory input resolves to `<dir>/release-run.json` via resolveRunPath.
|
|
209
|
+
*
|
|
210
|
+
* @param {string} runPath - Absolute path to the run file or run directory.
|
|
127
211
|
* @returns {Promise<Object>} The validated run object.
|
|
128
212
|
* @throws {ReleaseError} GATE_FAILED if the file cannot be read, parsed, or validated.
|
|
129
213
|
*/
|
|
130
214
|
export async function loadRun(runPath, options = {}) {
|
|
215
|
+
const resolvedRunPath = await resolveRunPath(runPath);
|
|
131
216
|
let raw;
|
|
132
217
|
try {
|
|
133
|
-
raw = await readFile(
|
|
218
|
+
raw = await readFile(resolvedRunPath, 'utf8');
|
|
134
219
|
} catch (err) {
|
|
135
220
|
throw new ReleaseError(
|
|
136
221
|
GATE_FAILED,
|
|
137
222
|
`cannot read release run: ${err.message}`,
|
|
138
|
-
{ runPath, cause: err.code },
|
|
223
|
+
{ runPath: resolvedRunPath, cause: err.code },
|
|
139
224
|
);
|
|
140
225
|
}
|
|
141
226
|
|
|
@@ -146,13 +231,13 @@ export async function loadRun(runPath, options = {}) {
|
|
|
146
231
|
throw new ReleaseError(
|
|
147
232
|
GATE_FAILED,
|
|
148
233
|
`release run is not valid JSON: ${err.message}`,
|
|
149
|
-
{ runPath },
|
|
234
|
+
{ runPath: resolvedRunPath },
|
|
150
235
|
);
|
|
151
236
|
}
|
|
152
237
|
|
|
153
238
|
validateRun(run, options);
|
|
154
239
|
if (options.authorityPlanPath) {
|
|
155
|
-
assertImmutableRunAuthority(
|
|
240
|
+
assertImmutableRunAuthority(resolvedRunPath, options.authorityPlanPath, run);
|
|
156
241
|
}
|
|
157
242
|
return run;
|
|
158
243
|
}
|