release-skill 0.2.7 → 0.2.9
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 +36 -0
- package/INSTALL.md +4 -4
- package/INSTALL.zh-CN.md +4 -4
- package/README.md +7 -13
- package/README.zh-CN.md +7 -13
- 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 +1153 -620
- 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 +1153 -620
- 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 +1153 -620
- 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 +1153 -620
- package/adapters/workbuddy/schemas/.render-manifest.json +2 -2
- package/adapters/workbuddy/schemas/release-project.schema.json +60 -0
- package/bin/release-skill-cli.mjs +4 -0
- package/bin/release-skill.bundle.mjs +1153 -620
- package/package.json +1 -1
- package/schemas/.render-manifest.json +2 -2
- package/schemas/release-project.schema.json +60 -0
- package/src/commands/assess.mjs +18 -5
- package/src/commands/prepare.mjs +59 -1
- package/src/core/config.mjs +48 -0
- package/src/core/public-surface.mjs +535 -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/assess.mjs
CHANGED
|
@@ -23,6 +23,7 @@ import { promisify } from 'node:util';
|
|
|
23
23
|
|
|
24
24
|
import { loadProjectConfig } from '../core/config.mjs';
|
|
25
25
|
import { ReleaseError, CONFIG_INVALID, GATE_FAILED } from '../core/errors.mjs';
|
|
26
|
+
import { collectExpectedPublicSurfaceAdoptionWarnings } from '../core/public-surface.mjs';
|
|
26
27
|
|
|
27
28
|
const execFile = promisify(execFileCb);
|
|
28
29
|
|
|
@@ -880,23 +881,35 @@ export async function assessProject(options) {
|
|
|
880
881
|
// --- 2. Topology identification ---
|
|
881
882
|
const topology = identifyTopology(config);
|
|
882
883
|
|
|
883
|
-
// --- 3.
|
|
884
|
+
// --- 3. Expected public-surface adoption ---
|
|
885
|
+
for (const warning of collectExpectedPublicSurfaceAdoptionWarnings(config)) {
|
|
886
|
+
allGaps.push(createGap({
|
|
887
|
+
scope: GapScope.PROJECT,
|
|
888
|
+
category: GapCategory.POLICY,
|
|
889
|
+
severity: Severity.WARNING,
|
|
890
|
+
code: warning.code,
|
|
891
|
+
message: warning.message,
|
|
892
|
+
file: '.release-skill/project.yaml',
|
|
893
|
+
}));
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// --- 4. Common docs check ---
|
|
884
897
|
const docGaps = await checkCommonDocs(root, config);
|
|
885
898
|
allGaps.push(...docGaps);
|
|
886
899
|
|
|
887
|
-
// ---
|
|
900
|
+
// --- 5. Plugin manifest check ---
|
|
888
901
|
const manifestGaps = await checkPluginManifests(root, config);
|
|
889
902
|
allGaps.push(...manifestGaps);
|
|
890
903
|
|
|
891
|
-
// ---
|
|
904
|
+
// --- 6. Package metadata check ---
|
|
892
905
|
const metadataGaps = await checkPackageMetadata(root, config);
|
|
893
906
|
allGaps.push(...metadataGaps);
|
|
894
907
|
|
|
895
|
-
// ---
|
|
908
|
+
// --- 7. Remote prerequisites ---
|
|
896
909
|
const remoteGaps = await checkRemotePrerequisites(root, config, offline);
|
|
897
910
|
allGaps.push(...remoteGaps);
|
|
898
911
|
|
|
899
|
-
// ---
|
|
912
|
+
// --- 8. README structure check ---
|
|
900
913
|
const readmeGaps = await checkReadmeStructure(root, config);
|
|
901
914
|
allGaps.push(...readmeGaps);
|
|
902
915
|
|
package/src/commands/prepare.mjs
CHANGED
|
@@ -29,6 +29,10 @@ 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 {
|
|
33
|
+
assertExpectedPublicSurface,
|
|
34
|
+
collectExpectedPublicSurfaceAdoptionWarnings,
|
|
35
|
+
} from '../core/public-surface.mjs';
|
|
32
36
|
import { runSnapshotVerificationGates } from '../core/verification-gates.mjs';
|
|
33
37
|
import { createEvidenceWriter } from '../core/evidence.mjs';
|
|
34
38
|
import { computePlanDigest, writePlanAtomic, writePlanImmutable } from '../core/plan.mjs';
|
|
@@ -1669,7 +1673,7 @@ export function buildExternalActions(unitResults, resolvedVersions, productionAs
|
|
|
1669
1673
|
* every declared hook runs in full and the incremental hook cache is neither
|
|
1670
1674
|
* read nor written.
|
|
1671
1675
|
*
|
|
1672
|
-
* @returns {Promise<{ planPath: string, planDigest: string, evidenceDir: string }>}
|
|
1676
|
+
* @returns {Promise<{ planPath: string, planDigest: string, evidenceDir: string, warnings: ReadonlyArray<object> }>}
|
|
1673
1677
|
*
|
|
1674
1678
|
* @throws {ReleaseError} on any gate failure. No PREPARED plan is written.
|
|
1675
1679
|
*/
|
|
@@ -1749,6 +1753,7 @@ export async function prepareRelease(options) {
|
|
|
1749
1753
|
await evidence.append({ phase: 'config', status: 'started' });
|
|
1750
1754
|
|
|
1751
1755
|
const { config, configPath, configDigest } = await loadProjectConfig({ root: realRoot });
|
|
1756
|
+
const adoptionWarnings = collectExpectedPublicSurfaceAdoptionWarnings(config);
|
|
1752
1757
|
|
|
1753
1758
|
await evidence.append({
|
|
1754
1759
|
phase: 'config',
|
|
@@ -1756,6 +1761,13 @@ export async function prepareRelease(options) {
|
|
|
1756
1761
|
configPath: relative(realRoot, configPath),
|
|
1757
1762
|
configDigest,
|
|
1758
1763
|
});
|
|
1764
|
+
for (const warning of adoptionWarnings) {
|
|
1765
|
+
await evidence.append({
|
|
1766
|
+
phase: 'public-surface-adoption',
|
|
1767
|
+
status: 'warning',
|
|
1768
|
+
...warning,
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1759
1771
|
|
|
1760
1772
|
// --- Step 1b: Resolve authoritative versions and gate release-document
|
|
1761
1773
|
// freshness BEFORE hook authorization ---
|
|
@@ -1925,6 +1937,51 @@ export async function prepareRelease(options) {
|
|
|
1925
1937
|
});
|
|
1926
1938
|
}
|
|
1927
1939
|
|
|
1940
|
+
// --- Step 3b.1: Validate the post-build expected public surface ---
|
|
1941
|
+
// This gate runs after every declared hook (and the post-hook docs check)
|
|
1942
|
+
// but before source-authority closure, baseline, snapshots, remote reads,
|
|
1943
|
+
// and plan write. Therefore build-generated files must be explicitly
|
|
1944
|
+
// classified and every included source must already exist in publicFiles
|
|
1945
|
+
// before downstream authorities bind the release inputs.
|
|
1946
|
+
for (const unit of configUnits) {
|
|
1947
|
+
if (!unit?.expectedPublicSurface) continue;
|
|
1948
|
+
await evidence.append({
|
|
1949
|
+
phase: 'public-surface',
|
|
1950
|
+
status: 'started',
|
|
1951
|
+
unitId: unit.id,
|
|
1952
|
+
});
|
|
1953
|
+
try {
|
|
1954
|
+
const surface = await assertExpectedPublicSurface({
|
|
1955
|
+
root: realRoot,
|
|
1956
|
+
unit,
|
|
1957
|
+
});
|
|
1958
|
+
await evidence.append({
|
|
1959
|
+
phase: 'public-surface',
|
|
1960
|
+
status: 'completed',
|
|
1961
|
+
unitId: unit.id,
|
|
1962
|
+
...surface.summary,
|
|
1963
|
+
});
|
|
1964
|
+
} catch (error) {
|
|
1965
|
+
await evidence.append({
|
|
1966
|
+
phase: 'public-surface',
|
|
1967
|
+
status: 'failed',
|
|
1968
|
+
unitId: unit.id,
|
|
1969
|
+
reason: error.details?.reason ?? 'PUBLIC_SURFACE_CHECK_FAILED',
|
|
1970
|
+
error: {
|
|
1971
|
+
code: error.code,
|
|
1972
|
+
message: error.message,
|
|
1973
|
+
},
|
|
1974
|
+
diagnostics: {
|
|
1975
|
+
missingMappings: error.details?.missingMappings ?? [],
|
|
1976
|
+
unexpectedMappings: error.details?.unexpectedMappings ?? [],
|
|
1977
|
+
unclassifiedFiles: error.details?.unclassifiedFiles ?? [],
|
|
1978
|
+
ambiguousFiles: error.details?.ambiguousFiles ?? [],
|
|
1979
|
+
},
|
|
1980
|
+
});
|
|
1981
|
+
throw error;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1928
1985
|
// --- Step 3c: Source authority content closure gate ---
|
|
1929
1986
|
// After hooks complete, compute the deterministic source-input closure
|
|
1930
1987
|
// and verify that closure inputs are clean (no staged/unstaged/untracked
|
|
@@ -2867,6 +2924,7 @@ export async function prepareRelease(options) {
|
|
|
2867
2924
|
planPath: writtenPath,
|
|
2868
2925
|
planDigest,
|
|
2869
2926
|
evidenceDir,
|
|
2927
|
+
warnings: adoptionWarnings,
|
|
2870
2928
|
};
|
|
2871
2929
|
} catch (err) {
|
|
2872
2930
|
// Record failure evidence
|
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) {
|