release-skill 0.9.22 → 0.9.24
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/plugin.json +1 -1
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.cursor-plugin/plugin.json +1 -1
- package/.kimi-plugin/plugin.json +1 -1
- package/.qoder-plugin/plugin.json +1 -1
- package/CHANGELOG.md +61 -2
- package/INSTALL.md +4 -4
- package/INSTALL.zh-CN.md +4 -4
- package/README.md +53 -32
- package/README.zh-CN.md +44 -27
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/consumer-contract-vectors.json +7 -7
- package/adapters/claude/bin/error-codes.json +1 -1
- package/adapters/claude/bin/foundation-resource-binding.json +1 -1
- package/adapters/claude/bin/registry.json +50 -1
- package/adapters/claude/bin/release-skill.bundle.mjs +2680 -2180
- package/adapters/claude/bin/rules.json +1 -1
- package/adapters/claude/skills/release-assess/SKILL.md +17 -3
- package/adapters/claude/skills/release-config/SKILL.md +6 -0
- package/adapters/claude/skills/release-docs/SKILL.md +6 -0
- package/adapters/claude/skills/release-help/SKILL.md +7 -2
- package/adapters/claude/skills/release-marketplace/SKILL.md +6 -0
- package/adapters/claude/skills/release-prepare/SKILL.md +8 -2
- package/adapters/claude/skills/release-publish/SKILL.md +7 -1
- package/adapters/claude/skills/release-reconcile/SKILL.md +6 -0
- package/adapters/claude/skills/release-setup/SKILL.md +9 -1
- package/adapters/claude/skills/release-verify/SKILL.md +6 -0
- package/adapters/claude/src/schemas/file-set-apply-request.schema.json +78 -0
- package/adapters/claude/src/schemas/file-set-event-payload.schema.json +55 -0
- package/adapters/claude/src/schemas/file-set-prune-request.schema.json +17 -0
- package/adapters/claude/src/schemas/file-set-recovery-request.schema.json +29 -0
- package/adapters/claude/src/schemas/file-set-result.schema.json +79 -0
- package/adapters/claude/src/schemas/professional-conclusion.schema.json +132 -0
- package/adapters/claude/src/schemas/project-manifest.schema.json +91 -0
- package/adapters/claude/src/schemas/state-store-recovery-observation.schema.json +129 -0
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/consumer-contract-vectors.json +7 -7
- package/adapters/codex/bin/error-codes.json +1 -1
- package/adapters/codex/bin/foundation-resource-binding.json +1 -1
- package/adapters/codex/bin/registry.json +50 -1
- package/adapters/codex/bin/release-skill.bundle.mjs +2680 -2180
- package/adapters/codex/bin/rules.json +1 -1
- package/adapters/codex/skills/release-assess/SKILL.md +17 -3
- package/adapters/codex/skills/release-config/SKILL.md +6 -0
- package/adapters/codex/skills/release-docs/SKILL.md +6 -0
- package/adapters/codex/skills/release-help/SKILL.md +9 -3
- package/adapters/codex/skills/release-marketplace/SKILL.md +6 -0
- package/adapters/codex/skills/release-prepare/SKILL.md +8 -2
- package/adapters/codex/skills/release-publish/SKILL.md +7 -1
- package/adapters/codex/skills/release-reconcile/SKILL.md +6 -0
- package/adapters/codex/skills/release-setup/SKILL.md +9 -1
- package/adapters/codex/skills/release-verify/SKILL.md +6 -0
- package/adapters/codex/src/schemas/file-set-apply-request.schema.json +78 -0
- package/adapters/codex/src/schemas/file-set-event-payload.schema.json +55 -0
- package/adapters/codex/src/schemas/file-set-prune-request.schema.json +17 -0
- package/adapters/codex/src/schemas/file-set-recovery-request.schema.json +29 -0
- package/adapters/codex/src/schemas/file-set-result.schema.json +79 -0
- package/adapters/codex/src/schemas/professional-conclusion.schema.json +132 -0
- package/adapters/codex/src/schemas/project-manifest.schema.json +91 -0
- package/adapters/codex/src/schemas/state-store-recovery-observation.schema.json +129 -0
- package/adapters/cursor/.cursor-plugin/plugin.json +1 -1
- package/adapters/cursor/bin/consumer-contract-vectors.json +7 -7
- package/adapters/cursor/bin/error-codes.json +1 -1
- package/adapters/cursor/bin/foundation-resource-binding.json +1 -1
- package/adapters/cursor/bin/registry.json +50 -1
- package/adapters/cursor/bin/release-skill.bundle.mjs +2680 -2180
- package/adapters/cursor/bin/rules.json +1 -1
- package/adapters/cursor/skills/release-assess/SKILL.md +17 -3
- package/adapters/cursor/skills/release-config/SKILL.md +6 -0
- package/adapters/cursor/skills/release-docs/SKILL.md +6 -0
- package/adapters/cursor/skills/release-help/SKILL.md +9 -3
- package/adapters/cursor/skills/release-marketplace/SKILL.md +6 -0
- package/adapters/cursor/skills/release-prepare/SKILL.md +8 -2
- package/adapters/cursor/skills/release-publish/SKILL.md +7 -1
- package/adapters/cursor/skills/release-reconcile/SKILL.md +6 -0
- package/adapters/cursor/skills/release-setup/SKILL.md +9 -1
- package/adapters/cursor/skills/release-verify/SKILL.md +6 -0
- package/adapters/cursor/src/schemas/file-set-apply-request.schema.json +78 -0
- package/adapters/cursor/src/schemas/file-set-event-payload.schema.json +55 -0
- package/adapters/cursor/src/schemas/file-set-prune-request.schema.json +17 -0
- package/adapters/cursor/src/schemas/file-set-recovery-request.schema.json +29 -0
- package/adapters/cursor/src/schemas/file-set-result.schema.json +79 -0
- package/adapters/cursor/src/schemas/professional-conclusion.schema.json +132 -0
- package/adapters/cursor/src/schemas/project-manifest.schema.json +91 -0
- package/adapters/cursor/src/schemas/state-store-recovery-observation.schema.json +129 -0
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/consumer-contract-vectors.json +7 -7
- package/adapters/kimi/bin/error-codes.json +1 -1
- package/adapters/kimi/bin/foundation-resource-binding.json +1 -1
- package/adapters/kimi/bin/registry.json +50 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +2680 -2180
- package/adapters/kimi/bin/rules.json +1 -1
- package/adapters/kimi/skills/release-assess/SKILL.md +17 -3
- package/adapters/kimi/skills/release-config/SKILL.md +6 -0
- package/adapters/kimi/skills/release-docs/SKILL.md +6 -0
- package/adapters/kimi/skills/release-help/SKILL.md +9 -3
- package/adapters/kimi/skills/release-marketplace/SKILL.md +6 -0
- package/adapters/kimi/skills/release-prepare/SKILL.md +8 -2
- package/adapters/kimi/skills/release-publish/SKILL.md +7 -1
- package/adapters/kimi/skills/release-reconcile/SKILL.md +6 -0
- package/adapters/kimi/skills/release-setup/SKILL.md +9 -1
- package/adapters/kimi/skills/release-verify/SKILL.md +6 -0
- package/adapters/kimi/src/schemas/file-set-apply-request.schema.json +78 -0
- package/adapters/kimi/src/schemas/file-set-event-payload.schema.json +55 -0
- package/adapters/kimi/src/schemas/file-set-prune-request.schema.json +17 -0
- package/adapters/kimi/src/schemas/file-set-recovery-request.schema.json +29 -0
- package/adapters/kimi/src/schemas/file-set-result.schema.json +79 -0
- package/adapters/kimi/src/schemas/professional-conclusion.schema.json +132 -0
- package/adapters/kimi/src/schemas/project-manifest.schema.json +91 -0
- package/adapters/kimi/src/schemas/state-store-recovery-observation.schema.json +129 -0
- package/adapters/qoder/.qoder-plugin/plugin.json +1 -1
- package/adapters/qoder/bin/consumer-contract-vectors.json +7 -7
- package/adapters/qoder/bin/error-codes.json +1 -1
- package/adapters/qoder/bin/foundation-resource-binding.json +1 -1
- package/adapters/qoder/bin/registry.json +50 -1
- package/adapters/qoder/bin/release-skill.bundle.mjs +2680 -2180
- package/adapters/qoder/bin/rules.json +1 -1
- package/adapters/qoder/skills/release-assess/SKILL.md +17 -3
- package/adapters/qoder/skills/release-config/SKILL.md +6 -0
- package/adapters/qoder/skills/release-docs/SKILL.md +6 -0
- package/adapters/qoder/skills/release-help/SKILL.md +9 -3
- package/adapters/qoder/skills/release-marketplace/SKILL.md +6 -0
- package/adapters/qoder/skills/release-prepare/SKILL.md +8 -2
- package/adapters/qoder/skills/release-publish/SKILL.md +7 -1
- package/adapters/qoder/skills/release-reconcile/SKILL.md +6 -0
- package/adapters/qoder/skills/release-setup/SKILL.md +9 -1
- package/adapters/qoder/skills/release-verify/SKILL.md +6 -0
- package/adapters/qoder/src/schemas/file-set-apply-request.schema.json +78 -0
- package/adapters/qoder/src/schemas/file-set-event-payload.schema.json +55 -0
- package/adapters/qoder/src/schemas/file-set-prune-request.schema.json +17 -0
- package/adapters/qoder/src/schemas/file-set-recovery-request.schema.json +29 -0
- package/adapters/qoder/src/schemas/file-set-result.schema.json +79 -0
- package/adapters/qoder/src/schemas/professional-conclusion.schema.json +132 -0
- package/adapters/qoder/src/schemas/project-manifest.schema.json +91 -0
- package/adapters/qoder/src/schemas/state-store-recovery-observation.schema.json +129 -0
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/consumer-contract-vectors.json +7 -7
- package/adapters/workbuddy/bin/error-codes.json +1 -1
- package/adapters/workbuddy/bin/foundation-resource-binding.json +1 -1
- package/adapters/workbuddy/bin/registry.json +50 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +2680 -2180
- package/adapters/workbuddy/bin/rules.json +1 -1
- package/adapters/workbuddy/skills/release-assess/SKILL.md +17 -3
- package/adapters/workbuddy/skills/release-config/SKILL.md +6 -0
- package/adapters/workbuddy/skills/release-docs/SKILL.md +6 -0
- package/adapters/workbuddy/skills/release-help/SKILL.md +7 -2
- package/adapters/workbuddy/skills/release-marketplace/SKILL.md +6 -0
- package/adapters/workbuddy/skills/release-prepare/SKILL.md +8 -2
- package/adapters/workbuddy/skills/release-publish/SKILL.md +7 -1
- package/adapters/workbuddy/skills/release-reconcile/SKILL.md +6 -0
- package/adapters/workbuddy/skills/release-setup/SKILL.md +9 -1
- package/adapters/workbuddy/skills/release-verify/SKILL.md +6 -0
- package/adapters/workbuddy/src/schemas/file-set-apply-request.schema.json +78 -0
- package/adapters/workbuddy/src/schemas/file-set-event-payload.schema.json +55 -0
- package/adapters/workbuddy/src/schemas/file-set-prune-request.schema.json +17 -0
- package/adapters/workbuddy/src/schemas/file-set-recovery-request.schema.json +29 -0
- package/adapters/workbuddy/src/schemas/file-set-result.schema.json +79 -0
- package/adapters/workbuddy/src/schemas/professional-conclusion.schema.json +132 -0
- package/adapters/workbuddy/src/schemas/project-manifest.schema.json +91 -0
- package/adapters/workbuddy/src/schemas/state-store-recovery-observation.schema.json +129 -0
- package/bin/consumer-contract-vectors.json +7 -7
- package/bin/error-codes.json +1 -1
- package/bin/foundation-resource-binding.json +1 -1
- package/bin/registry.json +50 -1
- package/bin/release-skill-cli.mjs +80 -5
- package/bin/release-skill.bundle.mjs +2680 -2180
- package/bin/rules.json +1 -1
- package/package.json +4 -4
- package/platform-manifest.json +4 -4
- package/references/05-evidence-and-errors.md +2 -2
- package/scripts/build-bundle.mjs +2 -1
- package/scripts/sync-public-files.mjs +1 -1
- package/skills/release-assess/SKILL.md +17 -3
- package/skills/release-config/SKILL.md +6 -0
- package/skills/release-docs/SKILL.md +6 -0
- package/skills/release-help/SKILL.md +7 -2
- package/skills/release-marketplace/SKILL.md +6 -0
- package/skills/release-prepare/SKILL.md +8 -2
- package/skills/release-publish/SKILL.md +7 -1
- package/skills/release-reconcile/SKILL.md +6 -0
- package/skills/release-setup/SKILL.md +9 -1
- package/skills/release-verify/SKILL.md +6 -0
- package/skills-src/release-assess/SKILL.md +17 -3
- package/skills-src/release-config/SKILL.md +6 -0
- package/skills-src/release-docs/SKILL.md +6 -0
- package/skills-src/release-help/SKILL.md +7 -2
- package/skills-src/release-marketplace/SKILL.md +6 -0
- package/skills-src/release-prepare/SKILL.md +8 -2
- package/skills-src/release-publish/SKILL.md +7 -1
- package/skills-src/release-reconcile/SKILL.md +6 -0
- package/skills-src/release-setup/SKILL.md +9 -1
- package/skills-src/release-verify/SKILL.md +6 -0
- package/src/adapters/plugin-marketplace.mjs +7 -12
- package/src/artifacts/producer-registry.mjs +4 -3
- package/src/commands/assess.mjs +23 -3
- package/src/commands/post-release-local.mjs +2 -2
- package/src/commands/prepare.mjs +5 -30
- package/src/commands/professional-proof.mjs +506 -0
- package/src/commands/setup.mjs +16 -5
- package/src/commands/verify-records.mjs +14 -0
- package/src/core/baseline.mjs +9 -1
- package/src/core/derived-artifact-gates.mjs +38 -9
- package/src/core/redact.mjs +12 -5
- package/src/core/source-authority.mjs +28 -3
- package/src/npm/npm-entry-closure.mjs +71 -9
- package/src/producers/build-adapters.mjs +18 -5
- package/src/producers/foundation-resource-projection.mjs +3 -3
- package/src/producers/render-public-assets.mjs +2 -1
- package/src/producers/sync-skills.mjs +2 -1
- package/src/schemas/file-set-apply-request.schema.json +78 -0
- package/src/schemas/file-set-event-payload.schema.json +55 -0
- package/src/schemas/file-set-prune-request.schema.json +17 -0
- package/src/schemas/file-set-recovery-request.schema.json +29 -0
- package/src/schemas/file-set-result.schema.json +79 -0
- package/src/schemas/professional-conclusion.schema.json +132 -0
- package/src/schemas/project-manifest.schema.json +91 -0
- package/src/schemas/state-store-recovery-observation.schema.json +129 -0
- package/src/snapshot/frozen.mjs +19 -14
- package/src/core/run-retention.mjs +0 -227
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
* freshness gate:
|
|
11
11
|
*
|
|
12
12
|
* - adapter gate: runs `scripts/build-adapters.mjs --check` (drift list,
|
|
13
|
-
* exit 1 on drift — the same supported check the scripts surface offers)
|
|
13
|
+
* exit 1 on drift — the same supported check the scripts surface offers).
|
|
14
|
+
* Exit 2 and an explicit process start failure mean that check did not
|
|
15
|
+
* finish, so freshness is unknown. Timeout stays timeout. Other gates
|
|
16
|
+
* keep their existing numeric-exit mapping.
|
|
14
17
|
* - platform manifest gate: runs
|
|
15
18
|
* `scripts/generate-platform-manifest.mjs --check`;
|
|
16
19
|
* - fact-pin gate: runs the version fact pins of
|
|
@@ -193,13 +196,15 @@ export async function checkDerivedArtifactGate(kind, pkgRoot, options = {}) {
|
|
|
193
196
|
durationMs: Date.now() - startedAt,
|
|
194
197
|
};
|
|
195
198
|
} catch (err) {
|
|
196
|
-
// Timeout
|
|
199
|
+
// Timeout stays timeout. Adapter exit 2 and an explicit spawn failure
|
|
200
|
+
// mean the check did not finish. Every other non-zero result, including
|
|
201
|
+
// other gates' numeric exits, remains drift.
|
|
197
202
|
const stdoutTail = boundedOutputTail(err?.stdout ?? '');
|
|
198
203
|
const stderrTail = boundedOutputTail(err?.stderr ?? err?.message ?? '');
|
|
199
204
|
return {
|
|
200
205
|
applicable: true,
|
|
201
206
|
fresh: false,
|
|
202
|
-
reason:
|
|
207
|
+
reason: failureReason(kind, err),
|
|
203
208
|
artifact: gate.artifact,
|
|
204
209
|
exitCode: typeof err?.code === 'number' ? err.code : null,
|
|
205
210
|
stdoutTail,
|
|
@@ -209,6 +214,25 @@ export async function checkDerivedArtifactGate(kind, pkgRoot, options = {}) {
|
|
|
209
214
|
}
|
|
210
215
|
}
|
|
211
216
|
|
|
217
|
+
function failureReason(kind, err) {
|
|
218
|
+
if (err?.killed || err?.code === 'ETIMEDOUT') return 'timeout';
|
|
219
|
+
if (kind === 'adapters' && (isProcessStartFailure(err) || err?.code === 2)) {
|
|
220
|
+
return 'execution-failed';
|
|
221
|
+
}
|
|
222
|
+
return 'drift';
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function isProcessStartFailure(err) {
|
|
226
|
+
const syscall = err?.syscall;
|
|
227
|
+
if (syscall === 'spawn' || syscall === 'spawnSync') return true;
|
|
228
|
+
const executable = err?.path;
|
|
229
|
+
// Node 22 execFile sets syscall to "spawn <executable>" when the file cannot be started.
|
|
230
|
+
return typeof syscall === 'string'
|
|
231
|
+
&& typeof executable === 'string'
|
|
232
|
+
&& executable.length > 0
|
|
233
|
+
&& syscall === `spawn ${executable}`;
|
|
234
|
+
}
|
|
235
|
+
|
|
212
236
|
/** Adapter freshness decision (build-adapters --check). */
|
|
213
237
|
export function checkAdapterFreshness(pkgRoot, options = {}) {
|
|
214
238
|
return checkDerivedArtifactGate('adapters', pkgRoot, options);
|
|
@@ -230,14 +254,19 @@ async function assertGate(kind, pkgRoot, options = {}) {
|
|
|
230
254
|
return result;
|
|
231
255
|
}
|
|
232
256
|
const gate = GATES[kind];
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
257
|
+
const unfinishedAdapterCheck = kind === 'adapters'
|
|
258
|
+
&& (result.reason === 'execution-failed' || result.reason === 'timeout');
|
|
259
|
+
const subject = unfinishedAdapterCheck
|
|
260
|
+
? `adapter freshness cannot be determined because build-adapters --check did not finish (${result.reason})`
|
|
261
|
+
: kind === 'adapters'
|
|
262
|
+
? 'adapters/ is out of sync with its sources (build-adapters --check reported drift)'
|
|
263
|
+
: kind === 'platform-manifest'
|
|
264
|
+
? 'platform-manifest.json is out of sync with the current package tree (generate-platform-manifest --check reported drift)'
|
|
265
|
+
: 'the release-docs-self-bootstrap fact pins are stale (the hermetic fact-pin check failed)';
|
|
266
|
+
const remediation = unfinishedAdapterCheck ? '' : ` ${gate.remediation}`;
|
|
238
267
|
throw new ReleaseError(
|
|
239
268
|
DERIVED_ARTIFACT_STALE,
|
|
240
|
-
`${subject}. ${DERIVED_ARTIFACT_PREGATE_NOTE}
|
|
269
|
+
`${subject}. ${DERIVED_ARTIFACT_PREGATE_NOTE}${remediation}`,
|
|
241
270
|
{
|
|
242
271
|
artifact: result.artifact,
|
|
243
272
|
reason: result.reason,
|
package/src/core/redact.mjs
CHANGED
|
@@ -54,12 +54,19 @@ export const REDACTED_PATH_PLACEHOLDER = '<redacted-path>';
|
|
|
54
54
|
// (b) UNC paths (\\server\share...);
|
|
55
55
|
// (c) POSIX absolute paths: a '/' anchored at the start of the string or
|
|
56
56
|
// preceded by a delimiter (whitespace, quote, '=', ':', ',', '(', '[',
|
|
57
|
-
// '{', '<')
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
57
|
+
// '{', '<'). Non-final '/'-separated segments may contain spaces (a
|
|
58
|
+
// volume name such as /Volumes/Samsung 990 pro 4T/src/file), so the
|
|
59
|
+
// token continues across those spaces and stops before trailing prose
|
|
60
|
+
// ('plan.json rejected: ...'). The left boundary keeps redaction from
|
|
61
|
+
// firing inside relative fragments ('src/core/x.mjs'), fragment-anchored
|
|
62
|
+
// JSON pointers ('#/required'), or protocol-relative URLs ('https://x/y').
|
|
63
|
+
// Windows drive and UNC alternatives still stop at whitespace; only the
|
|
64
|
+
// POSIX alternative crosses spaces, and only in non-final segments.
|
|
65
|
+
// A segment starting with a space right after '/' (e.g. /Volumes/ 990/x)
|
|
66
|
+
// and Windows drive/UNC tokens still truncate at that whitespace (known
|
|
67
|
+
// limitation).
|
|
61
68
|
const PATH_TOKEN_RE =
|
|
62
|
-
/(?<=^|[\s'"=:,([{<])(?:[A-Za-z]:[\\/][^\s'"]*|\\\\[^\s'"]+|\/[
|
|
69
|
+
/(?<=^|[\s'"=:,([{<])(?:[A-Za-z]:[\\/][^\s'"]*|\\\\[^\s'"]+|\/(?:[^/\s'"]+(?:[ ]+[^/\s'"]+)*\/)*[^/\s'"]*)/g;
|
|
63
70
|
|
|
64
71
|
// Trailing prose punctuation that may cling to a token and must survive.
|
|
65
72
|
const TRAILING_PUNCT_RE = /^(.*?)([.!,;:)\]}>]*)$/;
|
|
@@ -272,6 +272,21 @@ function normalizeLocalGitMode(mode) {
|
|
|
272
272
|
return (mode & 0o111) === 0 ? '100644' : '100755';
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
function gitPathSegments(value) {
|
|
276
|
+
return String(value).replaceAll('\\', '/').replace(/\/+$/u, '').split('/').filter(Boolean);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function sharesDirectoryBoundary(recordPath, requestedPath) {
|
|
280
|
+
const recordSegments = gitPathSegments(recordPath);
|
|
281
|
+
const requestedSegments = gitPathSegments(requestedPath);
|
|
282
|
+
const limit = Math.min(recordSegments.length, requestedSegments.length);
|
|
283
|
+
if (limit === 0) return false;
|
|
284
|
+
for (let index = 0; index < limit; index += 1) {
|
|
285
|
+
if (recordSegments[index] !== requestedSegments[index]) return false;
|
|
286
|
+
}
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
|
|
275
290
|
/**
|
|
276
291
|
* Check only frozen source-input paths for staged, unstaged or untracked
|
|
277
292
|
* changes. Unrelated dirty files remain allowed.
|
|
@@ -310,11 +325,21 @@ export async function checkSourceInputDirty({ closure, root, execFn = execFile }
|
|
|
310
325
|
if (record.length < 4) continue;
|
|
311
326
|
const status = record.slice(0, 2);
|
|
312
327
|
const recordPath = record.slice(3);
|
|
328
|
+
let renamedPath = '';
|
|
329
|
+
if (status.startsWith('R') || status.startsWith('C')) {
|
|
330
|
+
renamedPath = records[index + 1] ?? '';
|
|
331
|
+
index += 1;
|
|
332
|
+
}
|
|
313
333
|
// Ignored inputs are still untracked inputs. A file explicitly selected
|
|
314
334
|
// for publication must not escape the prepare gate merely because a
|
|
315
|
-
// .gitignore rule hides it from ordinary status output.
|
|
316
|
-
|
|
317
|
-
|
|
335
|
+
// .gitignore rule hides it from ordinary status output. A porcelain row
|
|
336
|
+
// counts only when its path shares a full directory segment with a
|
|
337
|
+
// requested closure path. A character prefix is not a selection.
|
|
338
|
+
for (const candidate of [recordPath, renamedPath]) {
|
|
339
|
+
if (candidate && paths.some((requested) => sharesDirectoryBoundary(candidate, requested))) {
|
|
340
|
+
dirtyPaths.push(candidate);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
318
343
|
}
|
|
319
344
|
return {
|
|
320
345
|
dirty: dirtyPaths.length > 0,
|
|
@@ -84,6 +84,37 @@ function checkTarget({ field, target, fileIndex, requireDotSlash = false }) {
|
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// Identity mapping whose only star is the final character, for example
|
|
88
|
+
// "./schemas/*" -> "./schemas/*". Node replaces that star with any non-empty
|
|
89
|
+
// string, including "/". Other shapes stay rejected.
|
|
90
|
+
function isDirectTrailingStarMapping(key, value) {
|
|
91
|
+
return typeof value === 'string'
|
|
92
|
+
&& key === value
|
|
93
|
+
&& key.startsWith('./')
|
|
94
|
+
&& key.indexOf('*') === key.length - 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function validateTrailingStarPrefix(pattern) {
|
|
98
|
+
const head = pattern.slice(0, -1);
|
|
99
|
+
if (head === './') return {};
|
|
100
|
+
const staticTarget = head.endsWith('/') ? head.slice(0, -1) : head;
|
|
101
|
+
const validated = validateRelativeTarget(staticTarget, 'exports', { requireDotSlash: true });
|
|
102
|
+
if (validated.error) return validated;
|
|
103
|
+
return {};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function matchingIndexPaths(pattern, fileIndex) {
|
|
107
|
+
const prefix = pattern.slice(0, -1);
|
|
108
|
+
const matched = [];
|
|
109
|
+
for (const path of fileIndex.keys()) {
|
|
110
|
+
if (typeof path !== 'string') continue;
|
|
111
|
+
const subpath = `./${path}`;
|
|
112
|
+
if (subpath.startsWith(prefix) && subpath.length >= pattern.length) matched.push(path);
|
|
113
|
+
}
|
|
114
|
+
matched.sort();
|
|
115
|
+
return matched;
|
|
116
|
+
}
|
|
117
|
+
|
|
87
118
|
function collectExports(value, location, result) {
|
|
88
119
|
if (value === null) return;
|
|
89
120
|
if (typeof value === 'string') {
|
|
@@ -117,14 +148,18 @@ function collectExports(value, location, result) {
|
|
|
117
148
|
for (const [key, child] of Object.entries(value)) {
|
|
118
149
|
const childLocation = `${location}.${key}`;
|
|
119
150
|
if (key.includes('*')) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
151
|
+
if (isDirectTrailingStarMapping(key, child)) {
|
|
152
|
+
result.patterns.push({ location: childLocation, pattern: key });
|
|
153
|
+
} else {
|
|
154
|
+
result.errors.push(
|
|
155
|
+
entryError(
|
|
156
|
+
'exports',
|
|
157
|
+
key,
|
|
158
|
+
'unsupported_entry_shape',
|
|
159
|
+
`${childLocation} uses a wildcard subpath that the static gate cannot verify`,
|
|
160
|
+
),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
128
163
|
continue;
|
|
129
164
|
}
|
|
130
165
|
collectExports(child, childLocation, result);
|
|
@@ -166,7 +201,7 @@ export function checkNpmEntryClosure(manifest, fileIndex) {
|
|
|
166
201
|
}
|
|
167
202
|
|
|
168
203
|
if (manifest.exports !== undefined) {
|
|
169
|
-
const exportsResult = { targets: [], errors: [], diagnostics: [] };
|
|
204
|
+
const exportsResult = { targets: [], patterns: [], errors: [], diagnostics: [] };
|
|
170
205
|
collectExports(manifest.exports, 'exports', exportsResult);
|
|
171
206
|
result.errors.push(...exportsResult.errors);
|
|
172
207
|
result.diagnostics.push(...exportsResult.diagnostics);
|
|
@@ -180,6 +215,33 @@ export function checkNpmEntryClosure(manifest, fileIndex) {
|
|
|
180
215
|
result.entries.push(...checked.entries);
|
|
181
216
|
result.errors.push(...checked.errors);
|
|
182
217
|
}
|
|
218
|
+
for (const pattern of exportsResult.patterns) {
|
|
219
|
+
const validated = validateTrailingStarPrefix(pattern.pattern);
|
|
220
|
+
if (validated.error) {
|
|
221
|
+
result.errors.push(validated.error);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const matched = matchingIndexPaths(pattern.pattern, fileIndex);
|
|
225
|
+
if (matched.length === 0) {
|
|
226
|
+
result.errors.push(entryError(
|
|
227
|
+
'exports',
|
|
228
|
+
pattern.pattern,
|
|
229
|
+
'empty_pattern_match',
|
|
230
|
+
`${pattern.location} matched no files in the package file index`,
|
|
231
|
+
));
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
for (const path of matched) {
|
|
235
|
+
const checked = checkTarget({
|
|
236
|
+
field: 'exports',
|
|
237
|
+
target: `./${path}`,
|
|
238
|
+
fileIndex,
|
|
239
|
+
requireDotSlash: true,
|
|
240
|
+
});
|
|
241
|
+
result.entries.push(...checked.entries);
|
|
242
|
+
result.errors.push(...checked.errors);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
183
245
|
}
|
|
184
246
|
|
|
185
247
|
return result;
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import { readdir, mkdir, lstat, realpath, open, rm } from 'node:fs/promises';
|
|
23
23
|
import { constants as fsConstants } from 'node:fs';
|
|
24
24
|
import { join, dirname, relative, isAbsolute, sep, resolve, posix as pathPosix } from 'node:path';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
25
26
|
|
|
26
27
|
import { sha256Hex } from '../core/digest.mjs';
|
|
27
28
|
import { digestDocument } from 'skill-family-contracts';
|
|
@@ -392,11 +393,23 @@ function renderSkillForPlatform(content, platformName) {
|
|
|
392
393
|
'${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs',
|
|
393
394
|
'$RELEASE_SKILL_ENTRY',
|
|
394
395
|
);
|
|
395
|
-
const
|
|
396
|
-
|
|
396
|
+
const hasMainEntry = rendered.includes('$RELEASE_SKILL_ENTRY');
|
|
397
|
+
const hasFinishEntry = rendered.includes('$RELEASE_SKILL_LOCAL_FINISH_ENTRY');
|
|
398
|
+
const mainBindingLine = '> 令 `RELEASE_SKILL_ENTRY=PLUGIN_ROOT/bin/release-skill.mjs`,对入口执行 `realpath` containment、`lstat` 非符号链接且为普通文件校验。\n';
|
|
399
|
+
const finishBindingLine = '> 令 `RELEASE_SKILL_LOCAL_FINISH_ENTRY=PLUGIN_ROOT/bin/release-skill-local-finish.mjs`,对入口执行 `realpath` containment、`lstat` 非符号链接且为普通文件校验。\n';
|
|
400
|
+
const mainShellLine = '> 每一次 shell 工具调用都必须在同一个调用中用上述已验证绝对值设置 `RELEASE_SKILL_ENTRY`,然后执行 `node "$RELEASE_SKILL_ENTRY" ...`;不得依赖前一次 shell 的变量。\n';
|
|
401
|
+
const dualShellLine = '> 每一次 shell 工具调用都必须在同一个调用中用上述已验证绝对值设置 `RELEASE_SKILL_ENTRY` 与 `RELEASE_SKILL_LOCAL_FINISH_ENTRY`,然后执行 `node "$RELEASE_SKILL_ENTRY" ...` 或 `node "$RELEASE_SKILL_LOCAL_FINISH_ENTRY" ...`;不得依赖前一次 shell 的变量。\n';
|
|
402
|
+
let renderedPreamble = preamble;
|
|
403
|
+
if (hasFinishEntry && hasMainEntry) {
|
|
404
|
+
if (!preamble.includes(mainBindingLine) || !preamble.includes(mainShellLine)) {
|
|
405
|
+
throw new Error(`${hostLabel} dual-entry rendering requires the original main-entry protocol lines`);
|
|
406
|
+
}
|
|
407
|
+
renderedPreamble = preamble.replace(`${mainBindingLine}${mainShellLine}`, `${mainBindingLine}${finishBindingLine}${dualShellLine}`);
|
|
408
|
+
} else if (hasFinishEntry) {
|
|
409
|
+
renderedPreamble = preamble
|
|
397
410
|
.replaceAll('RELEASE_SKILL_ENTRY', 'RELEASE_SKILL_LOCAL_FINISH_ENTRY')
|
|
398
|
-
.replaceAll('release-skill.mjs', 'release-skill-local-finish.mjs')
|
|
399
|
-
|
|
411
|
+
.replaceAll('release-skill.mjs', 'release-skill-local-finish.mjs');
|
|
412
|
+
}
|
|
400
413
|
if (platformName === 'cursor' && /\$\{(?:CLAUDE|CURSOR|CODEBUDDY|KIMI)[A-Z_]*\}/u.test(rendered)) {
|
|
401
414
|
throw new Error('Cursor rendering contains a residual host-specific placeholder');
|
|
402
415
|
}
|
|
@@ -701,7 +714,7 @@ async function generateAdapterFiles(platform, skills, templateJson, root, market
|
|
|
701
714
|
* @param {string} [options.platformFilter] - Only generate for this platform name.
|
|
702
715
|
*/
|
|
703
716
|
export async function produceBuildAdapters({ inputs, output, outputRoots, platformFilter } = {}) {
|
|
704
|
-
const defaultRoot = new URL('../..', import.meta.url)
|
|
717
|
+
const defaultRoot = fileURLToPath(new URL('../..', import.meta.url));
|
|
705
718
|
const requestedRoot = inputs ?? defaultRoot;
|
|
706
719
|
|
|
707
720
|
// ── Phase 1: Validate input root is not a symlink ──
|
|
@@ -55,9 +55,9 @@ import { digestBytes, publishFileOrReplace, readFileStrict, withTemporaryWorkspa
|
|
|
55
55
|
import { canonicalJson } from '../core/digest.mjs';
|
|
56
56
|
|
|
57
57
|
export const FOUNDATION_PACKAGES = Object.freeze({
|
|
58
|
-
'skill-family-contracts': '0.
|
|
59
|
-
'skill-family-engineering-kit': '0.
|
|
60
|
-
'skill-family-harness-node': '0.
|
|
58
|
+
'skill-family-contracts': '0.22.0',
|
|
59
|
+
'skill-family-engineering-kit': '0.22.0',
|
|
60
|
+
'skill-family-harness-node': '0.22.0',
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
export const BINDING_RECORD_PATH = 'bin/foundation-resource-binding.json';
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { readFile, writeFile, readdir, stat, mkdir } from 'node:fs/promises';
|
|
15
15
|
import { join, relative } from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
16
17
|
|
|
17
18
|
import { canonicalJson, sha256Hex } from '../core/digest.mjs';
|
|
18
19
|
import { digestDocument } from 'skill-family-contracts';
|
|
@@ -111,7 +112,7 @@ async function renderDir(srcDir, outDir, pathPrefix) {
|
|
|
111
112
|
* @returns {Promise<{outputs: Array, outputManifestDigest: string}>}
|
|
112
113
|
*/
|
|
113
114
|
export async function produceRenderPublicAssets({ inputs, output } = {}) {
|
|
114
|
-
const defaultRoot = new URL('../../..', import.meta.url)
|
|
115
|
+
const defaultRoot = fileURLToPath(new URL('../../..', import.meta.url));
|
|
115
116
|
const root = inputs ?? defaultRoot;
|
|
116
117
|
|
|
117
118
|
const srcDirs = [
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { readdir, readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
14
15
|
|
|
15
16
|
import { canonicalJson, sha256Hex } from '../core/digest.mjs';
|
|
16
17
|
import { digestDocument } from 'skill-family-contracts';
|
|
@@ -44,7 +45,7 @@ export function computeSyncSkillsDigest(sourceBytes) {
|
|
|
44
45
|
* @param {string} options.output - Output directory path.
|
|
45
46
|
*/
|
|
46
47
|
export async function produceSyncSkills({ inputs, output } = {}) {
|
|
47
|
-
const defaultSrc = new URL('../../skills-src', import.meta.url)
|
|
48
|
+
const defaultSrc = fileURLToPath(new URL('../../skills-src', import.meta.url));
|
|
48
49
|
const srcDir = inputs ?? defaultSrc;
|
|
49
50
|
|
|
50
51
|
const skillDirs = [];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.skill-family.example/v1/file-set-apply-request.json",
|
|
4
|
+
"title": "File set apply request",
|
|
5
|
+
"description": "Frozen JSON projection. Runtime checks bind bytes, cumulative capacity, modes, canonical paths, filesystem identities and cooperative ownership before business writes.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "kind", "operationId", "root", "rootBinding", "recoveryRelPath", "allowAdjacentStaging", "environment", "validationTimeoutMs", "operations"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": { "const": 1 },
|
|
11
|
+
"kind": { "const": "skill-family.file-set-apply-request" },
|
|
12
|
+
"operationId": { "$ref": "#/$defs/operationId" },
|
|
13
|
+
"root": { "$ref": "#/$defs/root" },
|
|
14
|
+
"rootBinding": { "$ref": "https://contracts.skill-family.example/v1/filesystem-root-binding.json" },
|
|
15
|
+
"recoveryRelPath": { "const": ".foundation-file-apply" },
|
|
16
|
+
"allowAdjacentStaging": { "const": true },
|
|
17
|
+
"environment": { "$ref": "#/$defs/environment" },
|
|
18
|
+
"validationTimeoutMs": { "type": "integer", "minimum": 1, "maximum": 2147483647 },
|
|
19
|
+
"operations": {
|
|
20
|
+
"type": "array", "minItems": 1, "maxItems": 1024, "uniqueItems": true,
|
|
21
|
+
"items": { "$ref": "#/$defs/operation" }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"$defs": {
|
|
25
|
+
"operationId": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" },
|
|
26
|
+
"root": { "type": "string", "pattern": "^/(?!.*(?:^|/)(?:\\.|\\.\\.)(?:/|$))(?!.*//)(?!.*[\\\\\\u0000])(?:[^/]+(?:/[^/]+)*)?$" },
|
|
27
|
+
"path": { "type": "string", "minLength": 1, "pattern": "^(?!/)(?!.*(?:^|/)(?:\\.|\\.\\.|\\.git|\\.foundation-file-apply)(?:/|$))(?!.*[\\\\\\u0000])[^/]+(?:/[^/]+)*$" },
|
|
28
|
+
"environment": {
|
|
29
|
+
"type": "object", "additionalProperties": false,
|
|
30
|
+
"required": ["filesystem", "cooperativeWriters"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"filesystem": { "enum": ["apfs", "ext4"] },
|
|
33
|
+
"cooperativeWriters": { "const": true }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
|
|
37
|
+
"size": { "type": "integer", "minimum": 0, "maximum": 268435456 },
|
|
38
|
+
"mode": { "type": "integer", "minimum": 256, "maximum": 511 },
|
|
39
|
+
"next": {
|
|
40
|
+
"type": "object", "additionalProperties": false,
|
|
41
|
+
"required": ["sha256", "size", "mode"],
|
|
42
|
+
"properties": {
|
|
43
|
+
"sha256": { "$ref": "#/$defs/sha256" },
|
|
44
|
+
"size": { "$ref": "#/$defs/size" },
|
|
45
|
+
"mode": { "$ref": "#/$defs/mode" }
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"present": {
|
|
49
|
+
"type": "object", "additionalProperties": false,
|
|
50
|
+
"required": ["exists", "sha256", "size", "mode"],
|
|
51
|
+
"properties": {
|
|
52
|
+
"exists": { "const": true },
|
|
53
|
+
"sha256": { "$ref": "#/$defs/sha256" },
|
|
54
|
+
"size": { "$ref": "#/$defs/size" },
|
|
55
|
+
"mode": { "$ref": "#/$defs/mode" }
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"absent": {
|
|
59
|
+
"type": "object", "additionalProperties": false,
|
|
60
|
+
"required": ["exists"], "properties": { "exists": { "const": false } }
|
|
61
|
+
},
|
|
62
|
+
"operation": {
|
|
63
|
+
"type": "object", "additionalProperties": false,
|
|
64
|
+
"required": ["path", "action", "expected", "next"],
|
|
65
|
+
"properties": {
|
|
66
|
+
"path": { "$ref": "#/$defs/path" },
|
|
67
|
+
"action": { "enum": ["create", "replace", "delete"] },
|
|
68
|
+
"expected": { "oneOf": [{ "$ref": "#/$defs/absent" }, { "$ref": "#/$defs/present" }] },
|
|
69
|
+
"next": { "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/next" }] }
|
|
70
|
+
},
|
|
71
|
+
"allOf": [
|
|
72
|
+
{ "if": { "properties": { "action": { "const": "create" } }, "required": ["action"] }, "then": { "properties": { "expected": { "$ref": "#/$defs/absent" }, "next": { "$ref": "#/$defs/next" } } } },
|
|
73
|
+
{ "if": { "properties": { "action": { "const": "replace" } }, "required": ["action"] }, "then": { "properties": { "expected": { "$ref": "#/$defs/present" }, "next": { "$ref": "#/$defs/next" } } } },
|
|
74
|
+
{ "if": { "properties": { "action": { "const": "delete" } }, "required": ["action"] }, "then": { "properties": { "expected": { "$ref": "#/$defs/present" }, "next": { "type": "null" } } } }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.skill-family.example/v1/file-set-event-payload.json",
|
|
4
|
+
"title": "File set event payload",
|
|
5
|
+
"description": "File recovery facts within the existing state-event envelope. Event order, request and path bindings are checked by Harness; no second sequence or hash chain is introduced.",
|
|
6
|
+
"type": "object", "additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "kind", "operationId", "type"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": { "const": 1 }, "kind": { "const": "skill-family.file-set-event-payload" },
|
|
10
|
+
"operationId": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/operationId" },
|
|
11
|
+
"type": { "enum": ["prepared", "apply-intent", "applied", "restore-intent", "restored", "validation-started", "validation-finished", "committed", "rolled-back", "recovery-required", "prune-intent", "pruned"] },
|
|
12
|
+
"request": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json" },
|
|
13
|
+
"requestDigest": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/sha256" },
|
|
14
|
+
"rootBinding": { "$ref": "https://contracts.skill-family.example/v1/filesystem-root-binding.json" },
|
|
15
|
+
"materialIdentity": { "$ref": "#/$defs/directoryIdentity" },
|
|
16
|
+
"entries": { "type": "array", "minItems": 1, "maxItems": 1024, "items": { "$ref": "#/$defs/materialEntry" } },
|
|
17
|
+
"index": { "type": "integer", "minimum": 0, "maximum": 1023 },
|
|
18
|
+
"current": { "enum": ["original", "expected-new"] },
|
|
19
|
+
"validation": { "$ref": "https://contracts.skill-family.example/v1/file-set-result.json#/$defs/validation" },
|
|
20
|
+
"paths": { "$ref": "https://contracts.skill-family.example/v1/file-set-result.json#/$defs/paths" },
|
|
21
|
+
"errorKinds": { "$ref": "https://contracts.skill-family.example/v1/file-set-result.json#/$defs/errorKinds" }
|
|
22
|
+
},
|
|
23
|
+
"allOf": [
|
|
24
|
+
{ "if": { "properties": { "type": { "const": "prepared" } }, "required": ["type"] },
|
|
25
|
+
"then": { "properties": { "request": {}, "requestDigest": {}, "rootBinding": {}, "materialIdentity": {}, "entries": {} }, "required": ["request", "requestDigest", "rootBinding", "materialIdentity", "entries"] },
|
|
26
|
+
"else": { "properties": { "request": false, "requestDigest": false, "rootBinding": false, "materialIdentity": false, "entries": false } } },
|
|
27
|
+
{ "if": { "properties": { "type": { "enum": ["apply-intent", "applied", "restore-intent", "restored"] } }, "required": ["type"] },
|
|
28
|
+
"then": { "properties": { "index": {} }, "required": ["index"] }, "else": { "properties": { "index": false } } },
|
|
29
|
+
{ "if": { "properties": { "type": { "enum": ["applied", "restored"] } }, "required": ["type"] },
|
|
30
|
+
"then": { "properties": { "current": {} }, "required": ["current"] }, "else": { "properties": { "current": false } } },
|
|
31
|
+
{ "if": { "properties": { "type": { "const": "applied" } }, "required": ["type"] },
|
|
32
|
+
"then": { "properties": { "current": { "const": "expected-new" } } } },
|
|
33
|
+
{ "if": { "properties": { "type": { "const": "restored" } }, "required": ["type"] },
|
|
34
|
+
"then": { "properties": { "current": { "const": "original" } } } },
|
|
35
|
+
{ "if": { "properties": { "type": { "const": "validation-finished" } }, "required": ["type"] },
|
|
36
|
+
"then": { "properties": { "validation": {} }, "required": ["validation"] }, "else": { "properties": { "validation": false } } },
|
|
37
|
+
{ "if": { "properties": { "type": { "enum": ["committed", "rolled-back", "recovery-required"] } }, "required": ["type"] },
|
|
38
|
+
"then": { "properties": { "paths": {}, "errorKinds": {} }, "required": ["paths", "errorKinds"] }, "else": { "properties": { "paths": false, "errorKinds": false } } }
|
|
39
|
+
],
|
|
40
|
+
"$defs": {
|
|
41
|
+
"directoryIdentity": {
|
|
42
|
+
"$ref": "https://contracts.skill-family.example/v1/state-store-recovery-observation.json#/$defs/identity",
|
|
43
|
+
"type": "object", "properties": { "type": { "const": "directory" } }
|
|
44
|
+
},
|
|
45
|
+
"materialEntry": {
|
|
46
|
+
"type": "object", "additionalProperties": false,
|
|
47
|
+
"required": ["before", "after", "parentIdentity"],
|
|
48
|
+
"properties": {
|
|
49
|
+
"before": { "anyOf": [{ "type": "null" }, { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/next" }] },
|
|
50
|
+
"after": { "anyOf": [{ "type": "null" }, { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/next" }] },
|
|
51
|
+
"parentIdentity": { "$ref": "#/$defs/directoryIdentity" }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.skill-family.example/v1/file-set-prune-request.json",
|
|
4
|
+
"title": "File set prune request",
|
|
5
|
+
"type": "object", "additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "kind", "operationId", "root", "rootBinding", "recoveryRelPath", "environment"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "const": 1 },
|
|
9
|
+
"kind": { "const": "skill-family.file-set-prune-request" },
|
|
10
|
+
"operationId": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/operationId" },
|
|
11
|
+
"root": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/root" },
|
|
12
|
+
"rootBinding": { "$ref": "https://contracts.skill-family.example/v1/filesystem-root-binding.json" },
|
|
13
|
+
"recoveryRelPath": { "const": ".foundation-file-apply" },
|
|
14
|
+
"environment": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/environment" },
|
|
15
|
+
"maintenance": { "$ref": "https://contracts.skill-family.example/v1/file-set-recovery-request.json#/$defs/maintenance" }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.skill-family.example/v1/file-set-recovery-request.json",
|
|
4
|
+
"title": "File set recovery request",
|
|
5
|
+
"type": "object", "additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "kind", "operationId", "root", "rootBinding", "recoveryRelPath", "environment", "allowAdjacentStaging", "maintenance"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "const": 1 },
|
|
9
|
+
"kind": { "const": "skill-family.file-set-recovery-request" },
|
|
10
|
+
"operationId": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/operationId" },
|
|
11
|
+
"root": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/root" },
|
|
12
|
+
"rootBinding": { "$ref": "https://contracts.skill-family.example/v1/filesystem-root-binding.json" },
|
|
13
|
+
"recoveryRelPath": { "const": ".foundation-file-apply" },
|
|
14
|
+
"environment": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/environment" },
|
|
15
|
+
"allowAdjacentStaging": { "const": true },
|
|
16
|
+
"maintenance": { "$ref": "#/$defs/maintenance" }
|
|
17
|
+
},
|
|
18
|
+
"$defs": {
|
|
19
|
+
"maintenance": {
|
|
20
|
+
"type": "object", "additionalProperties": false,
|
|
21
|
+
"required": ["observation", "confirmAllParticipantsStopped", "confirmExclusiveMaintenance"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"observation": { "$ref": "https://contracts.skill-family.example/v1/state-store-recovery-observation.json" },
|
|
24
|
+
"confirmAllParticipantsStopped": { "const": true },
|
|
25
|
+
"confirmExclusiveMaintenance": { "const": true }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://contracts.skill-family.example/v1/file-set-result.json",
|
|
4
|
+
"title": "File set result",
|
|
5
|
+
"type": "object", "additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "kind", "operationId", "operation", "outcome", "preflight", "businessWrite", "validation", "recovery", "paths", "errors", "materials"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "const": 1 }, "kind": { "const": "skill-family.file-set-result" },
|
|
9
|
+
"operationId": { "anyOf": [{ "type": "null" }, { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/operationId" }] },
|
|
10
|
+
"operation": { "enum": ["apply", "recover", "prune"] },
|
|
11
|
+
"outcome": { "enum": ["committed", "commit-unconfirmed", "rejected", "rolled-back", "recovery-required", "already-committed", "already-rolled-back", "pruned", "already-pruned"] },
|
|
12
|
+
"preflight": { "enum": ["not-run", "failed", "passed"] },
|
|
13
|
+
"businessWrite": { "enum": ["none", "started", "unknown"] },
|
|
14
|
+
"validation": { "$ref": "#/$defs/validation" },
|
|
15
|
+
"recovery": {
|
|
16
|
+
"type": "object", "additionalProperties": false, "required": ["attempted", "status"],
|
|
17
|
+
"properties": { "attempted": { "type": "boolean" }, "status": { "enum": ["not-needed", "complete", "partial", "blocked"] } }
|
|
18
|
+
},
|
|
19
|
+
"paths": { "$ref": "#/$defs/paths" },
|
|
20
|
+
"errors": { "type": "array", "items": { "$ref": "#/$defs/error" } },
|
|
21
|
+
"materials": {
|
|
22
|
+
"type": "object", "additionalProperties": false,
|
|
23
|
+
"required": ["relPath", "status", "durable", "adjacentStaging"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"relPath": { "const": ".foundation-file-apply" },
|
|
26
|
+
"status": { "enum": ["none", "retained", "partial", "pruned"] },
|
|
27
|
+
"durable": { "type": "boolean" },
|
|
28
|
+
"adjacentStaging": { "enum": ["none-observed", "possible-unknown"] }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"allOf": [{
|
|
33
|
+
"if": { "properties": { "operationId": { "type": "null" } }, "required": ["operationId"] },
|
|
34
|
+
"then": { "properties": { "paths": { "type": "array", "maxItems": 0 } } }
|
|
35
|
+
}],
|
|
36
|
+
"$defs": {
|
|
37
|
+
"errorKind": { "enum": ["invalid-request", "unsupported-environment", "unsafe-path", "precondition-mismatch", "locked", "unfinished-operation", "operation-id-reused", "commit-unconfirmed", "persistence-failed", "apply-failed", "validation-failed", "validation-incomplete", "restore-conflict", "restore-failed", "recovery-corrupt", "root-changed", "ownership-lost", "operation-not-found", "prune-refused", "lock-release-failed"] },
|
|
38
|
+
"errorKinds": { "type": "array", "items": { "$ref": "#/$defs/errorKind" } },
|
|
39
|
+
"error": {
|
|
40
|
+
"type": "object", "additionalProperties": false, "required": ["code", "message", "details"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"code": { "const": "SFC2004" }, "message": { "type": "string", "minLength": 1 },
|
|
43
|
+
"details": {
|
|
44
|
+
"type": "object", "additionalProperties": false, "required": ["kind", "phase"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"kind": { "$ref": "#/$defs/errorKind" },
|
|
47
|
+
"phase": { "enum": ["input", "preflight", "prepare", "apply", "validate", "restore", "finalize", "prune"] },
|
|
48
|
+
"path": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/path" }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"validation": {
|
|
54
|
+
"type": "object", "additionalProperties": false, "required": ["status", "reason"],
|
|
55
|
+
"properties": {
|
|
56
|
+
"status": { "enum": ["not-run", "passed", "failed", "incomplete"] },
|
|
57
|
+
"reason": { "enum": [null, "returned-false", "exception", "timeout", "invalid-result", "interrupted"] }
|
|
58
|
+
},
|
|
59
|
+
"allOf": [
|
|
60
|
+
{ "if": { "properties": { "status": { "enum": ["not-run", "passed"] } }, "required": ["status"] }, "then": { "properties": { "reason": { "type": "null" } } }, "else": { "properties": { "reason": { "type": "string" } } } },
|
|
61
|
+
{ "if": { "properties": { "status": { "const": "failed" } }, "required": ["status"] }, "then": { "properties": { "reason": { "const": "returned-false" } } } },
|
|
62
|
+
{ "if": { "properties": { "status": { "const": "incomplete" } }, "required": ["status"] }, "then": { "properties": { "reason": { "enum": ["exception", "timeout", "invalid-result", "interrupted"] } } } }
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"paths": { "type": "array", "maxItems": 1024, "items": { "$ref": "#/$defs/pathResult" } },
|
|
66
|
+
"pathResult": {
|
|
67
|
+
"type": "object", "additionalProperties": false,
|
|
68
|
+
"required": ["path", "action", "apply", "restore", "current", "errorKinds"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"path": { "$ref": "https://contracts.skill-family.example/v1/file-set-apply-request.json#/$defs/path" },
|
|
71
|
+
"action": { "enum": ["create", "replace", "delete"] },
|
|
72
|
+
"apply": { "enum": ["not-started", "intent-recorded", "applied", "unknown"] },
|
|
73
|
+
"restore": { "enum": ["not-needed", "restored", "already-original", "conflict", "failed", "unknown"] },
|
|
74
|
+
"current": { "enum": ["original", "expected-new", "other", "unknown"] },
|
|
75
|
+
"errorKinds": { "$ref": "#/$defs/errorKinds" }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|