release-skill 0.1.1
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/.agents/plugins/marketplace.json +23 -0
- package/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +10 -0
- package/.codex-plugin/plugin.json +26 -0
- package/CHANGELOG.md +68 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/CONTRIBUTING.md +49 -0
- package/INSTALL.md +182 -0
- package/LICENSE +21 -0
- package/NOTICE +25 -0
- package/README.md +501 -0
- package/README.zh-CN.md +463 -0
- package/SECURITY.md +48 -0
- package/adapters/claude/.claude-plugin/marketplace.json +16 -0
- package/adapters/claude/.claude-plugin/plugin.json +10 -0
- package/adapters/claude/skills/release-assess/SKILL.md +52 -0
- package/adapters/claude/skills/release-help/SKILL.md +60 -0
- package/adapters/claude/skills/release-prepare/SKILL.md +71 -0
- package/adapters/claude/skills/release-publish/SKILL.md +55 -0
- package/adapters/claude/skills/release-reconcile/SKILL.md +73 -0
- package/adapters/claude/skills/release-verify/SKILL.md +70 -0
- package/adapters/codex/.codex-plugin/plugin.json +26 -0
- package/adapters/codex/skills/release-assess/SKILL.md +52 -0
- package/adapters/codex/skills/release-help/SKILL.md +60 -0
- package/adapters/codex/skills/release-prepare/SKILL.md +71 -0
- package/adapters/codex/skills/release-publish/SKILL.md +55 -0
- package/adapters/codex/skills/release-reconcile/SKILL.md +73 -0
- package/adapters/codex/skills/release-verify/SKILL.md +70 -0
- package/bin/release-skill.mjs +743 -0
- package/native/safe-write/binding.gyp +40 -0
- package/native/safe-write/prebuilds.json +4 -0
- package/native/safe-write/src/safe_write.cc +2023 -0
- package/package.json +75 -0
- package/references/.render-manifest.json +33 -0
- package/references/00-target-state.md +124 -0
- package/references/01-state-machine.md +155 -0
- package/references/02-project-config.md +217 -0
- package/references/03-readme-quality.md +136 -0
- package/references/04-supply-chain.md +147 -0
- package/references/05-evidence-and-errors.md +164 -0
- package/references/06-adapter-contract.md +178 -0
- package/schemas/.render-manifest.json +37 -0
- package/schemas/approval-record.schema.json +115 -0
- package/schemas/artifact-lock.schema.json +111 -0
- package/schemas/artifact-plan.schema.json +52 -0
- package/schemas/artifact-policy.schema.json +76 -0
- package/schemas/evidence-event.schema.json +89 -0
- package/schemas/release-plan.schema.json +369 -0
- package/schemas/release-project.schema.json +359 -0
- package/schemas/release-run.schema.json +195 -0
- package/skills/release-assess/SKILL.md +52 -0
- package/skills/release-help/SKILL.md +60 -0
- package/skills/release-prepare/SKILL.md +71 -0
- package/skills/release-publish/SKILL.md +55 -0
- package/skills/release-reconcile/SKILL.md +73 -0
- package/skills/release-verify/SKILL.md +70 -0
- package/skills-src/release-assess/SKILL.md +52 -0
- package/skills-src/release-help/SKILL.md +60 -0
- package/skills-src/release-prepare/SKILL.md +71 -0
- package/skills-src/release-publish/SKILL.md +55 -0
- package/skills-src/release-reconcile/SKILL.md +73 -0
- package/skills-src/release-verify/SKILL.md +70 -0
- package/src/adapters/contract.mjs +214 -0
- package/src/adapters/git-github.mjs +214 -0
- package/src/adapters/npm.mjs +947 -0
- package/src/adapters/plugin-marketplace.mjs +1365 -0
- package/src/adapters/push-snapshot.mjs +216 -0
- package/src/artifacts/adoption.mjs +743 -0
- package/src/artifacts/artifact-plan.mjs +162 -0
- package/src/artifacts/entry.mjs +240 -0
- package/src/artifacts/git-authority.mjs +637 -0
- package/src/artifacts/graph.mjs +189 -0
- package/src/artifacts/inspect.mjs +520 -0
- package/src/artifacts/inventory.mjs +192 -0
- package/src/artifacts/merge/binary.mjs +77 -0
- package/src/artifacts/merge/entry-merge.mjs +228 -0
- package/src/artifacts/merge/json.mjs +641 -0
- package/src/artifacts/merge/markdown.mjs +246 -0
- package/src/artifacts/merge/regions.mjs +156 -0
- package/src/artifacts/merge/text.mjs +432 -0
- package/src/artifacts/merge/tree.mjs +202 -0
- package/src/artifacts/merge/yaml.mjs +669 -0
- package/src/artifacts/path-key.mjs +94 -0
- package/src/artifacts/policy.mjs +319 -0
- package/src/artifacts/producer-registry.mjs +439 -0
- package/src/artifacts/project-lock.mjs +732 -0
- package/src/artifacts/resolution.mjs +658 -0
- package/src/artifacts/safe-fs-backend-internal.mjs +680 -0
- package/src/artifacts/safe-fs.mjs +72 -0
- package/src/artifacts/state.mjs +495 -0
- package/src/artifacts/transaction-journal.mjs +983 -0
- package/src/artifacts/transaction.mjs +1361 -0
- package/src/commands/approve.mjs +280 -0
- package/src/commands/artifacts.mjs +627 -0
- package/src/commands/assess.mjs +838 -0
- package/src/commands/prepare.mjs +1377 -0
- package/src/commands/publish.mjs +883 -0
- package/src/commands/reconcile.mjs +1255 -0
- package/src/commands/verify.mjs +915 -0
- package/src/core/approval.mjs +332 -0
- package/src/core/baseline.mjs +272 -0
- package/src/core/blackbox-hard-gates.mjs +142 -0
- package/src/core/config.mjs +448 -0
- package/src/core/digest.mjs +90 -0
- package/src/core/errors.mjs +113 -0
- package/src/core/evidence.mjs +167 -0
- package/src/core/hooks.mjs +241 -0
- package/src/core/node-version.mjs +64 -0
- package/src/core/plan.mjs +735 -0
- package/src/core/previous-public-baseline.mjs +204 -0
- package/src/core/run.mjs +681 -0
- package/src/core/state-machine.mjs +76 -0
- package/src/core/version-consistency.mjs +111 -0
- package/src/producers/build-adapters.mjs +231 -0
- package/src/producers/render-public-assets.mjs +152 -0
- package/src/producers/sync-skills.mjs +96 -0
- package/src/readme/contract.mjs +297 -0
- package/src/readme/examples.mjs +288 -0
- package/src/readme/parity.mjs +122 -0
- package/src/snapshot/export.mjs +99 -0
- package/src/snapshot/frozen.mjs +401 -0
- package/src/snapshot/manifest.mjs +207 -0
- package/src/snapshot/public-map.mjs +1459 -0
- package/src/snapshot/public-path.mjs +110 -0
- package/src/snapshot/scan.mjs +419 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { execFile as execFileCb } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
ActionStatus,
|
|
6
|
+
ActionType,
|
|
7
|
+
assertWritesAuthorized,
|
|
8
|
+
createResult,
|
|
9
|
+
matchObservation,
|
|
10
|
+
} from './contract.mjs';
|
|
11
|
+
import { verifyFrozenGitRepository, verifyFrozenSnapshot } from '../snapshot/frozen.mjs';
|
|
12
|
+
|
|
13
|
+
const execFile = promisify(execFileCb);
|
|
14
|
+
const NAME = 'push-snapshot';
|
|
15
|
+
|
|
16
|
+
async function run(command, args, options = {}) {
|
|
17
|
+
return execFile(command, args, {
|
|
18
|
+
shell: false,
|
|
19
|
+
encoding: 'utf8',
|
|
20
|
+
timeout: 120_000,
|
|
21
|
+
...options,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function githubRepositoryUrl(repo, host = 'github.com') {
|
|
26
|
+
if (typeof repo !== 'string' || !/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/.test(repo)) {
|
|
27
|
+
throw new Error('repo must use owner/name format');
|
|
28
|
+
}
|
|
29
|
+
if (
|
|
30
|
+
typeof host !== 'string' || !/^[A-Za-z0-9.-]+$/.test(host) ||
|
|
31
|
+
host.startsWith('.') || host.endsWith('.') || host.includes('..')
|
|
32
|
+
) {
|
|
33
|
+
throw new Error('githubHost must be a valid hostname');
|
|
34
|
+
}
|
|
35
|
+
return `https://${host}/${repo}.git`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function validateOid(value, label) {
|
|
39
|
+
if (typeof value !== 'string' || !/^[a-f0-9]{40,64}$/.test(value)) {
|
|
40
|
+
throw new Error(`${label} must be a full hexadecimal git object id`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function validateAction(action) {
|
|
45
|
+
const required = ['snapshotPath', 'manifestDigest', 'gitObjectDir', 'branch', 'repo', 'commit', 'tree'];
|
|
46
|
+
for (const key of required) {
|
|
47
|
+
if (!action[key] || typeof action[key] !== 'string') {
|
|
48
|
+
throw new Error(`push-snapshot requires ${key}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (!/^[a-f0-9]{64}$/.test(action.manifestDigest)) {
|
|
52
|
+
throw new Error('manifestDigest must be a lowercase SHA-256 digest');
|
|
53
|
+
}
|
|
54
|
+
validateOid(action.commit, 'commit');
|
|
55
|
+
validateOid(action.tree, 'tree');
|
|
56
|
+
githubRepositoryUrl(action.repo, action.githubHost);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function inspectLocalObjects(action, context, exec) {
|
|
60
|
+
const { gitDir } = await verifyFrozenGitRepository({
|
|
61
|
+
root: context.root,
|
|
62
|
+
gitObjectDir: action.gitObjectDir,
|
|
63
|
+
commit: action.commit,
|
|
64
|
+
tree: action.tree,
|
|
65
|
+
exec,
|
|
66
|
+
});
|
|
67
|
+
await exec('git', ['check-ref-format', `refs/heads/${action.branch}`], { shell: false });
|
|
68
|
+
return gitDir;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function createPushSnapshotAdapter(deps = {}) {
|
|
72
|
+
const exec = deps.exec ?? run;
|
|
73
|
+
|
|
74
|
+
return Object.freeze({
|
|
75
|
+
name: NAME,
|
|
76
|
+
actionTypes: Object.freeze([ActionType.PUSH_SNAPSHOT]),
|
|
77
|
+
|
|
78
|
+
async preflight(action, context) {
|
|
79
|
+
try {
|
|
80
|
+
if (action.actionType !== ActionType.PUSH_SNAPSHOT) throw new Error('unsupported action type');
|
|
81
|
+
validateAction(action);
|
|
82
|
+
await verifyFrozenSnapshot({
|
|
83
|
+
root: context.root,
|
|
84
|
+
snapshotPath: action.snapshotPath,
|
|
85
|
+
expectedDigest: action.manifestDigest,
|
|
86
|
+
});
|
|
87
|
+
await inspectLocalObjects(action, context, exec);
|
|
88
|
+
const remoteUrl = githubRepositoryUrl(action.repo, action.githubHost);
|
|
89
|
+
const { stdout } = await exec(
|
|
90
|
+
'git',
|
|
91
|
+
['ls-remote', '--heads', remoteUrl, `refs/heads/${action.branch}`],
|
|
92
|
+
{ shell: false },
|
|
93
|
+
);
|
|
94
|
+
if (stdout.trim()) {
|
|
95
|
+
return createResult({
|
|
96
|
+
actionType: action.actionType,
|
|
97
|
+
status: ActionStatus.PREFLIGHT_FAILED,
|
|
98
|
+
error: `remote branch already exists: ${action.branch}; human intervention required`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return createResult({ actionType: action.actionType, status: ActionStatus.PREFLIGHT_PASSED });
|
|
102
|
+
} catch (err) {
|
|
103
|
+
return createResult({
|
|
104
|
+
actionType: action.actionType,
|
|
105
|
+
status: ActionStatus.PREFLIGHT_FAILED,
|
|
106
|
+
error: err.message,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
async execute(action, context) {
|
|
112
|
+
assertWritesAuthorized(context, action.actionType);
|
|
113
|
+
try {
|
|
114
|
+
validateAction(action);
|
|
115
|
+
await verifyFrozenSnapshot({
|
|
116
|
+
root: context.root,
|
|
117
|
+
snapshotPath: action.snapshotPath,
|
|
118
|
+
expectedDigest: action.manifestDigest,
|
|
119
|
+
});
|
|
120
|
+
const gitDir = await inspectLocalObjects(action, context, exec);
|
|
121
|
+
const remoteUrl = githubRepositoryUrl(action.repo, action.githubHost);
|
|
122
|
+
await exec(
|
|
123
|
+
'git',
|
|
124
|
+
[
|
|
125
|
+
'--git-dir', gitDir,
|
|
126
|
+
'push',
|
|
127
|
+
`--force-with-lease=refs/heads/${action.branch}:`,
|
|
128
|
+
remoteUrl,
|
|
129
|
+
`${action.commit}:refs/heads/${action.branch}`,
|
|
130
|
+
],
|
|
131
|
+
{ shell: false },
|
|
132
|
+
);
|
|
133
|
+
return createResult({ actionType: action.actionType, status: ActionStatus.EXECUTED });
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return createResult({
|
|
136
|
+
actionType: action.actionType,
|
|
137
|
+
status: ActionStatus.EXECUTE_FAILED,
|
|
138
|
+
error: err.message,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
async observe(action, context) {
|
|
144
|
+
try {
|
|
145
|
+
validateAction(action);
|
|
146
|
+
const frozen = await verifyFrozenSnapshot({
|
|
147
|
+
root: context.root,
|
|
148
|
+
snapshotPath: action.snapshotPath,
|
|
149
|
+
expectedDigest: action.manifestDigest,
|
|
150
|
+
});
|
|
151
|
+
const gitDir = await inspectLocalObjects(action, context, exec);
|
|
152
|
+
const remoteUrl = githubRepositoryUrl(action.repo, action.githubHost);
|
|
153
|
+
const { stdout } = await exec(
|
|
154
|
+
'git',
|
|
155
|
+
['ls-remote', '--heads', remoteUrl, `refs/heads/${action.branch}`],
|
|
156
|
+
{ shell: false },
|
|
157
|
+
);
|
|
158
|
+
const commit = stdout.trim().split(/\s+/)[0] ?? '';
|
|
159
|
+
if (!commit) {
|
|
160
|
+
return createResult({
|
|
161
|
+
actionType: action.actionType,
|
|
162
|
+
status: ActionStatus.OBSERVED,
|
|
163
|
+
observation: { branch: action.branch, exists: false },
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
await exec(
|
|
167
|
+
'git',
|
|
168
|
+
['--git-dir', gitDir, 'fetch', '--no-tags', remoteUrl, `refs/heads/${action.branch}`],
|
|
169
|
+
{ shell: false },
|
|
170
|
+
);
|
|
171
|
+
const { stdout: treeOut } = await exec(
|
|
172
|
+
'git',
|
|
173
|
+
['--git-dir', gitDir, 'rev-parse', 'FETCH_HEAD^{tree}'],
|
|
174
|
+
{ shell: false },
|
|
175
|
+
);
|
|
176
|
+
return createResult({
|
|
177
|
+
actionType: action.actionType,
|
|
178
|
+
status: ActionStatus.OBSERVED,
|
|
179
|
+
observation: {
|
|
180
|
+
branch: action.branch,
|
|
181
|
+
commit,
|
|
182
|
+
tree: treeOut.trim(),
|
|
183
|
+
manifestDigest: frozen.digest,
|
|
184
|
+
exists: true,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
} catch (err) {
|
|
188
|
+
return createResult({
|
|
189
|
+
actionType: action.actionType,
|
|
190
|
+
status: ActionStatus.OBSERVED,
|
|
191
|
+
observation: {},
|
|
192
|
+
error: err.message,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
async verify(action, context) {
|
|
198
|
+
const observed = await this.observe(action, context);
|
|
199
|
+
if (observed.error) {
|
|
200
|
+
return createResult({
|
|
201
|
+
actionType: action.actionType,
|
|
202
|
+
status: ActionStatus.VERIFY_FAILED,
|
|
203
|
+
observation: observed.observation,
|
|
204
|
+
error: observed.error,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
const comparison = matchObservation(action.expected ?? {}, observed.observation);
|
|
208
|
+
return createResult({
|
|
209
|
+
actionType: action.actionType,
|
|
210
|
+
status: comparison.matches ? ActionStatus.VERIFIED : ActionStatus.VERIFY_FAILED,
|
|
211
|
+
observation: observed.observation,
|
|
212
|
+
error: comparison.matches ? null : comparison.mismatches.join('; '),
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
}
|