release-skill 0.2.7 → 0.2.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/.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 +21 -0
- package/INSTALL.md +4 -4
- package/INSTALL.zh-CN.md +4 -4
- package/README.md +10 -10
- package/README.zh-CN.md +10 -10
- 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 +1116 -618
- package/adapters/claude/schemas/.render-manifest.json +2 -2
- package/adapters/claude/schemas/release-project.schema.json +60 -0
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +1116 -618
- package/adapters/codex/schemas/.render-manifest.json +2 -2
- package/adapters/codex/schemas/release-project.schema.json +60 -0
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +1116 -618
- package/adapters/kimi/schemas/.render-manifest.json +2 -2
- package/adapters/kimi/schemas/release-project.schema.json +60 -0
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +1116 -618
- package/adapters/workbuddy/schemas/.render-manifest.json +2 -2
- package/adapters/workbuddy/schemas/release-project.schema.json +60 -0
- package/bin/release-skill.bundle.mjs +1116 -618
- package/package.json +1 -1
- package/schemas/.render-manifest.json +2 -2
- package/schemas/release-project.schema.json +60 -0
- package/src/commands/prepare.mjs +46 -0
- package/src/core/config.mjs +48 -0
- package/src/core/public-surface.mjs +509 -0
package/package.json
CHANGED
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"bytes": 35256
|
|
27
27
|
},
|
|
28
28
|
"release-project.schema.json": {
|
|
29
|
-
"digest": "
|
|
30
|
-
"bytes":
|
|
29
|
+
"digest": "7ac18070ac41327a330ca35e32f466e3f2a8eb2b7df3a5755568e00f991ffdc1",
|
|
30
|
+
"bytes": 32497
|
|
31
31
|
},
|
|
32
32
|
"release-run.schema.json": {
|
|
33
33
|
"digest": "bf3c8fb4ca2fc078272a45a6ee6bf663fd2420a722b2f995dbaabf2635e2179e",
|
|
@@ -455,6 +455,9 @@
|
|
|
455
455
|
]
|
|
456
456
|
}
|
|
457
457
|
},
|
|
458
|
+
"expectedPublicSurface": {
|
|
459
|
+
"$ref": "#/definitions/expectedPublicSurface"
|
|
460
|
+
},
|
|
458
461
|
"publicFiles": {
|
|
459
462
|
"type": "array",
|
|
460
463
|
"minItems": 1,
|
|
@@ -761,6 +764,63 @@
|
|
|
761
764
|
}
|
|
762
765
|
},
|
|
763
766
|
"definitions": {
|
|
767
|
+
"expectedPublicSurface": {
|
|
768
|
+
"type": "object",
|
|
769
|
+
"additionalProperties": false,
|
|
770
|
+
"required": [
|
|
771
|
+
"scanRoots"
|
|
772
|
+
],
|
|
773
|
+
"properties": {
|
|
774
|
+
"scanRoots": {
|
|
775
|
+
"type": "array",
|
|
776
|
+
"minItems": 1,
|
|
777
|
+
"items": {
|
|
778
|
+
"$ref": "#/definitions/publicSurfaceScanRoot"
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
},
|
|
783
|
+
"publicSurfaceScanRoot": {
|
|
784
|
+
"type": "object",
|
|
785
|
+
"additionalProperties": false,
|
|
786
|
+
"required": [
|
|
787
|
+
"include",
|
|
788
|
+
"exclude"
|
|
789
|
+
],
|
|
790
|
+
"properties": {
|
|
791
|
+
"sourceScope": {
|
|
792
|
+
"type": "string",
|
|
793
|
+
"enum": [
|
|
794
|
+
"unit",
|
|
795
|
+
"workspace"
|
|
796
|
+
],
|
|
797
|
+
"default": "unit"
|
|
798
|
+
},
|
|
799
|
+
"root": {
|
|
800
|
+
"type": "string",
|
|
801
|
+
"minLength": 1,
|
|
802
|
+
"default": ".",
|
|
803
|
+
"pattern": "^(?:\\.$|(?!\\/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(?:\\/|$))(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/\\/$)(?!.*\\/$).*)$"
|
|
804
|
+
},
|
|
805
|
+
"include": {
|
|
806
|
+
"type": "array",
|
|
807
|
+
"minItems": 1,
|
|
808
|
+
"uniqueItems": true,
|
|
809
|
+
"items": {
|
|
810
|
+
"type": "string",
|
|
811
|
+
"minLength": 1
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
"exclude": {
|
|
815
|
+
"type": "array",
|
|
816
|
+
"uniqueItems": true,
|
|
817
|
+
"items": {
|
|
818
|
+
"type": "string",
|
|
819
|
+
"minLength": 1
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
},
|
|
764
824
|
"hook": {
|
|
765
825
|
"type": "object",
|
|
766
826
|
"required": [
|
package/src/commands/prepare.mjs
CHANGED
|
@@ -29,6 +29,7 @@ import { loadProjectConfig } from '../core/config.mjs';
|
|
|
29
29
|
import { captureBaseline } from '../core/baseline.mjs';
|
|
30
30
|
import { runHook } from '../core/hooks.mjs';
|
|
31
31
|
import { computeHookCacheKey, readHookCache, writeHookCache } from '../core/hook-cache.mjs';
|
|
32
|
+
import { assertExpectedPublicSurface } from '../core/public-surface.mjs';
|
|
32
33
|
import { runSnapshotVerificationGates } from '../core/verification-gates.mjs';
|
|
33
34
|
import { createEvidenceWriter } from '../core/evidence.mjs';
|
|
34
35
|
import { computePlanDigest, writePlanAtomic, writePlanImmutable } from '../core/plan.mjs';
|
|
@@ -1925,6 +1926,51 @@ export async function prepareRelease(options) {
|
|
|
1925
1926
|
});
|
|
1926
1927
|
}
|
|
1927
1928
|
|
|
1929
|
+
// --- Step 3b.1: Validate the post-build expected public surface ---
|
|
1930
|
+
// This gate runs after every declared hook (and the post-hook docs check)
|
|
1931
|
+
// but before source-authority closure, baseline, snapshots, remote reads,
|
|
1932
|
+
// and plan write. Therefore build-generated files must be explicitly
|
|
1933
|
+
// classified and every included source must already exist in publicFiles
|
|
1934
|
+
// before downstream authorities bind the release inputs.
|
|
1935
|
+
for (const unit of configUnits) {
|
|
1936
|
+
if (!unit?.expectedPublicSurface) continue;
|
|
1937
|
+
await evidence.append({
|
|
1938
|
+
phase: 'public-surface',
|
|
1939
|
+
status: 'started',
|
|
1940
|
+
unitId: unit.id,
|
|
1941
|
+
});
|
|
1942
|
+
try {
|
|
1943
|
+
const surface = await assertExpectedPublicSurface({
|
|
1944
|
+
root: realRoot,
|
|
1945
|
+
unit,
|
|
1946
|
+
});
|
|
1947
|
+
await evidence.append({
|
|
1948
|
+
phase: 'public-surface',
|
|
1949
|
+
status: 'completed',
|
|
1950
|
+
unitId: unit.id,
|
|
1951
|
+
...surface.summary,
|
|
1952
|
+
});
|
|
1953
|
+
} catch (error) {
|
|
1954
|
+
await evidence.append({
|
|
1955
|
+
phase: 'public-surface',
|
|
1956
|
+
status: 'failed',
|
|
1957
|
+
unitId: unit.id,
|
|
1958
|
+
reason: error.details?.reason ?? 'PUBLIC_SURFACE_CHECK_FAILED',
|
|
1959
|
+
error: {
|
|
1960
|
+
code: error.code,
|
|
1961
|
+
message: error.message,
|
|
1962
|
+
},
|
|
1963
|
+
diagnostics: {
|
|
1964
|
+
missingMappings: error.details?.missingMappings ?? [],
|
|
1965
|
+
unexpectedMappings: error.details?.unexpectedMappings ?? [],
|
|
1966
|
+
unclassifiedFiles: error.details?.unclassifiedFiles ?? [],
|
|
1967
|
+
ambiguousFiles: error.details?.ambiguousFiles ?? [],
|
|
1968
|
+
},
|
|
1969
|
+
});
|
|
1970
|
+
throw error;
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1928
1974
|
// --- Step 3c: Source authority content closure gate ---
|
|
1929
1975
|
// After hooks complete, compute the deterministic source-input closure
|
|
1930
1976
|
// and verify that closure inputs are clean (no staged/unstaged/untracked
|
package/src/core/config.mjs
CHANGED
|
@@ -23,6 +23,7 @@ import Ajv from 'ajv';
|
|
|
23
23
|
import addFormats from 'ajv-formats';
|
|
24
24
|
import { canonicalJson, sha256Hex } from './digest.mjs';
|
|
25
25
|
import { ReleaseError, CONFIG_INVALID } from './errors.mjs';
|
|
26
|
+
import { validatePublicSurfaceGlob } from './public-surface.mjs';
|
|
26
27
|
import { canonicalPublicPath, publicPathCollisionKey } from '../snapshot/public-path.mjs';
|
|
27
28
|
import { isReservedReleaseControlPath } from './baseline.mjs';
|
|
28
29
|
import { readTrustedPackageResource } from './trusted-resource.mjs';
|
|
@@ -294,6 +295,53 @@ export async function loadProjectConfig({ root, configPath } = {}) {
|
|
|
294
295
|
);
|
|
295
296
|
}
|
|
296
297
|
|
|
298
|
+
// Validate expected public-surface roots and the deliberately small glob
|
|
299
|
+
// language before generic schema validation so diagnostics identify the
|
|
300
|
+
// exact unit, scan root, and pattern.
|
|
301
|
+
const surface = unit.expectedPublicSurface;
|
|
302
|
+
if (surface && typeof surface === 'object' && Array.isArray(surface.scanRoots)) {
|
|
303
|
+
for (const [rootIndex, scanRoot] of surface.scanRoots.entries()) {
|
|
304
|
+
if (!scanRoot || typeof scanRoot !== 'object') continue;
|
|
305
|
+
if (typeof scanRoot.root === 'string') {
|
|
306
|
+
try {
|
|
307
|
+
canonicalPublicPath(scanRoot.root, { allowDot: true });
|
|
308
|
+
} catch (err) {
|
|
309
|
+
throw new ReleaseError(
|
|
310
|
+
CONFIG_INVALID,
|
|
311
|
+
`unit "${unit.id}" has invalid expectedPublicSurface scan root: ${err.message}`,
|
|
312
|
+
{
|
|
313
|
+
unitId: unit.id,
|
|
314
|
+
rootIndex,
|
|
315
|
+
root: scanRoot.root,
|
|
316
|
+
field: 'expectedPublicSurface.scanRoots[].root',
|
|
317
|
+
},
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
for (const field of ['include', 'exclude']) {
|
|
322
|
+
if (!Array.isArray(scanRoot[field])) continue;
|
|
323
|
+
for (const pattern of scanRoot[field]) {
|
|
324
|
+
if (typeof pattern !== 'string') continue;
|
|
325
|
+
try {
|
|
326
|
+
validatePublicSurfaceGlob(pattern);
|
|
327
|
+
} catch (err) {
|
|
328
|
+
throw new ReleaseError(
|
|
329
|
+
CONFIG_INVALID,
|
|
330
|
+
`unit "${unit.id}" has invalid expectedPublicSurface ${field} glob: ${err.message}`,
|
|
331
|
+
{
|
|
332
|
+
unitId: unit.id,
|
|
333
|
+
rootIndex,
|
|
334
|
+
pattern,
|
|
335
|
+
field: `expectedPublicSurface.scanRoots[].${field}`,
|
|
336
|
+
reason: err.details?.reason ?? 'PUBLIC_SURFACE_GLOB_INVALID',
|
|
337
|
+
},
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
297
345
|
// Validate publicFiles[].from and .to
|
|
298
346
|
if (Array.isArray(unit.publicFiles)) {
|
|
299
347
|
for (const mapping of unit.publicFiles) {
|