@haposoft/cafekit 0.16.0-rc.2 → 0.16.0-rc.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/bin/__tests__/codex-hooks.test.js +355 -12
- package/bin/__tests__/codex-native.test.js +1 -1
- package/bin/__tests__/develop-contract.test.js +1374 -78
- package/bin/__tests__/installer-safety.test.js +43 -29
- package/bin/__tests__/opencode-spec-gate.test.js +791 -0
- package/bin/__tests__/package-inventory.test.js +157 -0
- package/bin/__tests__/validator-grounding.test.js +707 -2
- package/package.json +1 -1
- package/src/claude/agents/spec-maker.md +107 -200
- package/src/claude/hooks/__tests__/completion-authority.test.js +720 -0
- package/src/claude/hooks/__tests__/spec-gate.test.js +511 -38
- package/src/claude/hooks/completion-authority-check.cjs +307 -0
- package/src/claude/hooks/completion-authority-state.cjs +525 -0
- package/src/claude/hooks/completion-authority.cjs +148 -0
- package/src/claude/hooks/session.cjs +33 -19
- package/src/claude/hooks/spec-gate.cjs +173 -61
- package/src/claude/hooks/spec-state.cjs +104 -45
- package/src/claude/migration-manifest.json +6 -1
- package/src/claude/scripts/provenance.cjs +315 -0
- package/src/claude/scripts/spec-resolver.cjs +450 -0
- package/src/claude/scripts/spec-scaffold.cjs +716 -41
- package/src/claude/scripts/validate-spec-output.cjs +355 -53
- package/src/claude/scripts/workflow-policy.cjs +1529 -162
- package/src/claude/settings/settings.json +8 -0
- package/src/claude/skills/code-review/SKILL.md +85 -66
- package/src/claude/skills/develop/SKILL.md +153 -285
- package/src/claude/skills/develop/references/quality-gate.md +116 -148
- package/src/claude/skills/develop/references/subagent-patterns.md +42 -37
- package/src/claude/skills/specs/SKILL.md +170 -381
- package/src/claude/skills/specs/rules/task-scoring-rubric.md +45 -46
- package/src/claude/skills/specs/rules/tasks-generation.md +49 -20
- package/src/claude/skills/specs/templates/spec-state.json +23 -2
- package/src/claude/skills/specs/templates/task.md +20 -0
- package/src/claude/skills/sync/SKILL.md +15 -8
- package/src/claude/skills/sync/references/sync-protocols.md +4 -4
- package/src/claude/skills/test/SKILL.md +141 -167
- package/src/codex/hooks/completion-authority-check.cjs +260 -0
- package/src/codex/hooks/completion-authority-state.cjs +525 -0
- package/src/codex/hooks/completion-authority.cjs +100 -0
- package/src/codex/hooks/lib/hook-context.cjs +42 -2
- package/src/codex/hooks/lib/spec-receipt.cjs +76 -43
- package/src/codex/hooks/lib/spec-utils.cjs +53 -27
- package/src/codex/hooks/session.cjs +2 -0
- package/src/codex/hooks/spec-gate.cjs +132 -20
- package/src/codex/hooks/spec-state.cjs +56 -10
- package/src/codex/hooks.json +10 -0
- package/src/opencode/AGENTS.md +4 -2
- package/src/opencode/plugins/spec-gate.ts +296 -122
- package/src/opencode/plugins/spec-state.ts +183 -116
|
@@ -61,7 +61,9 @@
|
|
|
61
61
|
"generate-skill-catalog.cjs",
|
|
62
62
|
"validate-spec-output.cjs",
|
|
63
63
|
"scan-staged-secrets.cjs",
|
|
64
|
-
"workflow-policy.cjs"
|
|
64
|
+
"workflow-policy.cjs",
|
|
65
|
+
"spec-resolver.cjs",
|
|
66
|
+
"provenance.cjs"
|
|
65
67
|
]
|
|
66
68
|
},
|
|
67
69
|
"agentReferences": {
|
|
@@ -102,6 +104,9 @@
|
|
|
102
104
|
"hooks/rules.cjs",
|
|
103
105
|
"hooks/spec-state.cjs",
|
|
104
106
|
"hooks/spec-gate.cjs",
|
|
107
|
+
"hooks/completion-authority.cjs",
|
|
108
|
+
"hooks/completion-authority-check.cjs",
|
|
109
|
+
"hooks/completion-authority-state.cjs",
|
|
105
110
|
"hooks/state.cjs",
|
|
106
111
|
"hooks/lib/color.cjs",
|
|
107
112
|
"hooks/lib/parser.cjs",
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { spawnSync } = require('node:child_process');
|
|
7
|
+
|
|
8
|
+
const PROVENANCE_MODE = 'worktree-sha256-v1';
|
|
9
|
+
const CONTEXT_SCHEMA_VERSION = '1';
|
|
10
|
+
const trustedContexts = new WeakSet();
|
|
11
|
+
|
|
12
|
+
class ProvenanceError extends Error {
|
|
13
|
+
constructor(code, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'ProvenanceError';
|
|
16
|
+
this.code = code;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function fail(code, message) {
|
|
21
|
+
throw new ProvenanceError(code, message);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function valueOf(input, snake, camel) {
|
|
25
|
+
const hasSnake = Object.prototype.hasOwnProperty.call(input, snake);
|
|
26
|
+
const hasCamel = Object.prototype.hasOwnProperty.call(input, camel);
|
|
27
|
+
if (hasSnake && hasCamel && input[snake] !== input[camel]) {
|
|
28
|
+
fail('ambiguous_identity', `${snake} and ${camel} disagree`);
|
|
29
|
+
}
|
|
30
|
+
return hasSnake ? input[snake] : input[camel];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function text(value, field) {
|
|
34
|
+
if (typeof value !== 'string' || value.trim() !== value || value === '' || /[\0\r\n]/.test(value)) {
|
|
35
|
+
fail('malformed_input', `${field} must be a non-empty single-line string`);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function inside(root, candidate, field) {
|
|
41
|
+
const relative = path.relative(root, candidate);
|
|
42
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
43
|
+
fail('path_escape', `${field} escapes the project root`);
|
|
44
|
+
}
|
|
45
|
+
return relative;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function existingPath(value, field, kind, base = process.cwd()) {
|
|
49
|
+
const requested = text(value, field);
|
|
50
|
+
let canonical;
|
|
51
|
+
try { canonical = fs.realpathSync(path.resolve(base, requested)); } catch (error) {
|
|
52
|
+
fail('path_error', `${field} cannot be canonicalized (${error.code || error.message})`);
|
|
53
|
+
}
|
|
54
|
+
let stat;
|
|
55
|
+
try { stat = fs.lstatSync(canonical); } catch (error) {
|
|
56
|
+
fail('path_error', `${field} cannot be inspected (${error.code || error.message})`);
|
|
57
|
+
}
|
|
58
|
+
if ((kind === 'directory' && !stat.isDirectory()) || (kind === 'file' && !stat.isFile())) {
|
|
59
|
+
fail('malformed_input', `${field} is not a ${kind}`);
|
|
60
|
+
}
|
|
61
|
+
return canonical;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function runGit(root, args, label) {
|
|
65
|
+
const result = spawnSync('git', ['-C', root, ...args], { encoding: 'buffer', maxBuffer: 64 * 1024 * 1024 });
|
|
66
|
+
if (result.error || result.status !== 0 || result.signal) {
|
|
67
|
+
const detail = result.error?.message || String(result.stderr || '').trim() || `exit ${result.status}`;
|
|
68
|
+
fail('git_command_failed', `${label} failed: ${detail}`);
|
|
69
|
+
}
|
|
70
|
+
if (!Buffer.isBuffer(result.stdout)) fail('malformed_git_output', `${label} did not return bytes`);
|
|
71
|
+
return result.stdout;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function decode(value, label) {
|
|
75
|
+
const decoded = value.toString('utf8');
|
|
76
|
+
if (!Buffer.from(decoded, 'utf8').equals(value)) fail('malformed_git_output', `${label} is not valid UTF-8`);
|
|
77
|
+
return decoded;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function oneLine(value, label) {
|
|
81
|
+
const output = decode(value, label);
|
|
82
|
+
if (!/^[^\0\r\n]+\n?$/.test(output)) fail('malformed_git_output', `${label} is not a single line`);
|
|
83
|
+
return output.replace(/\n$/, '');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function gitBase(root) {
|
|
87
|
+
const output = oneLine(runGit(root, ['rev-parse', 'HEAD'], 'git rev-parse HEAD')).toLowerCase();
|
|
88
|
+
if (!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/.test(output)) fail('malformed_git_output', 'git rev-parse HEAD did not return a commit id');
|
|
89
|
+
return output;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function gitRoot(requested) {
|
|
93
|
+
const input = existingPath(requested, 'projectRoot', 'directory');
|
|
94
|
+
const reported = oneLine(runGit(input, ['rev-parse', '--show-toplevel'], 'git rev-parse --show-toplevel'));
|
|
95
|
+
const root = existingPath(reported, 'git project root', 'directory');
|
|
96
|
+
inside(root, input, 'projectRoot');
|
|
97
|
+
return root;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function splitNul(bytes, label) {
|
|
101
|
+
if (bytes.length && bytes[bytes.length - 1] !== 0) fail('malformed_git_output', `${label} is not NUL terminated`);
|
|
102
|
+
return bytes.length === 0 ? [] : bytes.subarray(0, -1).toString('binary').split('\0').map((entry) => {
|
|
103
|
+
const raw = Buffer.from(entry, 'binary');
|
|
104
|
+
return decode(raw, label);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function pathKey(root, relative, label) {
|
|
109
|
+
if (typeof relative !== 'string' || relative === '' || relative.includes('\0') || path.posix.isAbsolute(relative)) {
|
|
110
|
+
fail('malformed_git_output', `${label} contains an invalid path`);
|
|
111
|
+
}
|
|
112
|
+
const normalized = path.sep === '\\' ? relative.replaceAll('\\', '/') : relative;
|
|
113
|
+
if (normalized.split('/').includes('..')) fail('path_escape', `${label} escapes the project root`);
|
|
114
|
+
const absolute = path.resolve(root, ...normalized.split('/'));
|
|
115
|
+
inside(root, absolute, label);
|
|
116
|
+
return { relative: normalized, absolute };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function parseStatus(bytes) {
|
|
120
|
+
const values = splitNul(bytes, 'git status');
|
|
121
|
+
const entries = new Map();
|
|
122
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
123
|
+
const value = values[index];
|
|
124
|
+
if (value.length < 4 || value[2] !== ' ') fail('malformed_git_output', 'git status emitted an invalid porcelain record');
|
|
125
|
+
const xy = value.slice(0, 2);
|
|
126
|
+
const first = value.slice(3);
|
|
127
|
+
if (xy.includes('R') || xy.includes('C')) {
|
|
128
|
+
const next = values[++index];
|
|
129
|
+
if (!next) fail('malformed_git_output', 'git status rename record is incomplete');
|
|
130
|
+
entries.set(first, { xy, role: 'rename-source', counterpart: next });
|
|
131
|
+
entries.set(next, { xy, role: 'rename-target', counterpart: first });
|
|
132
|
+
} else {
|
|
133
|
+
entries.set(first, { xy, role: xy === '??' || xy === '!!' ? 'untracked' : 'tracked' });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return entries;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function excluded(root, absolute, specsRoot) {
|
|
140
|
+
const relative = path.relative(root, absolute).split(path.sep).join('/');
|
|
141
|
+
const specsRelative = path.relative(root, specsRoot);
|
|
142
|
+
// These roots are generated runtime state, not source evidence. The selected
|
|
143
|
+
// canonical specs root is excluded above to avoid receipt/state recursion.
|
|
144
|
+
const roots = [
|
|
145
|
+
'.git', 'node_modules', '.claude/hooks/.logs', '.codex/hooks/.logs',
|
|
146
|
+
'.claude/.logs', '.codex/.logs', '.claude/runtime.json', '.codex/runtime.json',
|
|
147
|
+
];
|
|
148
|
+
if (relative === specsRelative || relative.startsWith(`${specsRelative}/`)) return true;
|
|
149
|
+
return roots.some((entry) => relative === entry || relative.startsWith(`${entry}/`));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function manifest(root, specsRoot) {
|
|
153
|
+
const statuses = parseStatus(runGit(root, ['status', '--porcelain=v1', '-z', '--untracked-files=all'], 'git status'));
|
|
154
|
+
const tracked = [
|
|
155
|
+
...splitNul(runGit(root, ['ls-files', '-z', '--cached'], 'git ls-files'), 'git ls-files'),
|
|
156
|
+
...splitNul(runGit(root, ['ls-tree', '-r', '-z', '--name-only', 'HEAD'], 'git ls-tree'), 'git ls-tree'),
|
|
157
|
+
...statuses.keys(),
|
|
158
|
+
];
|
|
159
|
+
const paths = [...new Set(tracked)].map((entry) => pathKey(root, entry, 'worktree path'))
|
|
160
|
+
.filter(({ absolute }) => !excluded(root, absolute, specsRoot))
|
|
161
|
+
.sort((left, right) => left.relative < right.relative ? -1 : left.relative > right.relative ? 1 : 0);
|
|
162
|
+
const unique = new Map(paths.map((entry) => [entry.relative, entry]));
|
|
163
|
+
const records = [];
|
|
164
|
+
for (const { relative, absolute } of unique.values()) {
|
|
165
|
+
let before;
|
|
166
|
+
try { before = fs.lstatSync(absolute); } catch (error) {
|
|
167
|
+
if (error.code === 'ENOENT') { records.push({ path: relative, type: 'deleted', mode: '0000', status: statuses.get(relative) || null, content: null }); continue; }
|
|
168
|
+
fail('path_error', `cannot inspect ${relative} (${error.code || error.message})`);
|
|
169
|
+
}
|
|
170
|
+
const mode = (before.mode & 0o7777).toString(8).padStart(4, '0');
|
|
171
|
+
let content;
|
|
172
|
+
let type = 'file';
|
|
173
|
+
if (before.isSymbolicLink()) { type = 'symlink'; content = Buffer.from(fs.readlinkSync(absolute), 'utf8'); }
|
|
174
|
+
else if (before.isFile()) { content = fs.readFileSync(absolute); }
|
|
175
|
+
else { type = before.isDirectory() ? 'directory' : 'special'; content = Buffer.alloc(0); }
|
|
176
|
+
let after;
|
|
177
|
+
try { after = fs.lstatSync(absolute); } catch { fail('worktree_race', `${relative} changed during provenance capture`); }
|
|
178
|
+
if (before.ino !== after.ino || before.size !== after.size || before.mtimeMs !== after.mtimeMs || before.mode !== after.mode) {
|
|
179
|
+
fail('worktree_race', `${relative} changed during provenance capture`);
|
|
180
|
+
}
|
|
181
|
+
records.push({ path: relative, type, mode, status: statuses.get(relative) || null, content: content.toString('base64') });
|
|
182
|
+
}
|
|
183
|
+
return { status: [...statuses.entries()], records };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function manifestDigest(snapshot) {
|
|
187
|
+
const hash = crypto.createHash('sha256');
|
|
188
|
+
hash.update('cafekit-provenance\0');
|
|
189
|
+
for (const record of snapshot.records) hash.update(`${JSON.stringify(record)}\n`);
|
|
190
|
+
return hash.digest('hex');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function identity(input) {
|
|
194
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) fail('malformed_input', 'runtime provenance input must be an object');
|
|
195
|
+
const root = gitRoot(valueOf(input, 'project_root', 'projectRoot'));
|
|
196
|
+
const specsRoot = existingPath(valueOf(input, 'specs_root', 'specsRoot'), 'specsRoot', 'directory', root);
|
|
197
|
+
inside(root, specsRoot, 'specsRoot');
|
|
198
|
+
if (specsRoot === root) fail('ambiguous_identity', 'specsRoot must be a distinct project subdirectory');
|
|
199
|
+
const specFile = existingPath(valueOf(input, 'spec_file', 'specFile'), 'specFile', 'file', root);
|
|
200
|
+
inside(specsRoot, specFile, 'specFile');
|
|
201
|
+
const feature = text(valueOf(input, 'feature_name', 'featureName'), 'feature_name');
|
|
202
|
+
if (feature.includes('/') || feature.includes('\\') || feature === '.' || feature === '..') fail('ambiguous_identity', 'feature_name must be one path segment');
|
|
203
|
+
const featureDir = existingPath(path.join(specsRoot, feature), 'feature directory', 'directory');
|
|
204
|
+
if (path.dirname(specFile) !== featureDir) fail('ambiguous_identity', 'feature_name does not identify the selected spec file');
|
|
205
|
+
const session = text(valueOf(input, 'runtime_session', 'runtimeSession'), 'runtime_session');
|
|
206
|
+
const requestedMode = valueOf(input, 'provenance_mode', 'provenanceMode');
|
|
207
|
+
const mode = requestedMode === undefined ? PROVENANCE_MODE : text(requestedMode, 'provenance_mode');
|
|
208
|
+
if (mode !== PROVENANCE_MODE) fail('malformed_input', `unsupported provenance mode: ${mode}`);
|
|
209
|
+
return { root, specsRoot, specFile, feature, session, mode };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function deriveRuntimeProvenance(input) {
|
|
213
|
+
const current = identity(input);
|
|
214
|
+
const base = gitBase(current.root);
|
|
215
|
+
const first = manifest(current.root, current.specsRoot);
|
|
216
|
+
const head = manifestDigest(first);
|
|
217
|
+
const second = manifest(current.root, current.specsRoot);
|
|
218
|
+
if (JSON.stringify(first) !== JSON.stringify(second) || gitBase(current.root) !== base) fail('worktree_race', 'checkout changed during provenance capture');
|
|
219
|
+
const stable = {
|
|
220
|
+
schema_version: CONTEXT_SCHEMA_VERSION,
|
|
221
|
+
project_root: current.root,
|
|
222
|
+
specs_root: current.specsRoot,
|
|
223
|
+
spec_file: current.specFile,
|
|
224
|
+
feature_name: current.feature,
|
|
225
|
+
runtime_session: current.session,
|
|
226
|
+
provenance_mode: current.mode,
|
|
227
|
+
Base: base,
|
|
228
|
+
Head: head,
|
|
229
|
+
};
|
|
230
|
+
const contextId = crypto.createHash('sha256').update(JSON.stringify(stable)).digest('hex');
|
|
231
|
+
const context = Object.freeze({
|
|
232
|
+
...stable,
|
|
233
|
+
base,
|
|
234
|
+
head,
|
|
235
|
+
context_id: contextId,
|
|
236
|
+
contextId,
|
|
237
|
+
expected_provenance: Object.freeze({ base, head }),
|
|
238
|
+
});
|
|
239
|
+
trustedContexts.add(context);
|
|
240
|
+
return context;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function isTrustedRuntimeContext(value) {
|
|
244
|
+
return Boolean(value && typeof value === 'object' && trustedContexts.has(value));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function recomputeRuntimeProvenance(value) {
|
|
248
|
+
if (!isTrustedRuntimeContext(value)) fail('untrusted_context', 'runtime provenance context was not derived by the runtime helper');
|
|
249
|
+
return deriveRuntimeProvenance({
|
|
250
|
+
projectRoot: value.project_root,
|
|
251
|
+
specsRoot: value.specs_root,
|
|
252
|
+
specFile: value.spec_file,
|
|
253
|
+
featureName: value.feature_name,
|
|
254
|
+
runtimeSession: value.runtime_session,
|
|
255
|
+
provenanceMode: value.provenance_mode,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function createReceiptBinding(value) {
|
|
260
|
+
const context = recomputeRuntimeProvenance(value);
|
|
261
|
+
const binding = Object.freeze({
|
|
262
|
+
expectedProvenance: Object.freeze({ base: context.base, head: context.head }),
|
|
263
|
+
requireProvenanceBinding: true,
|
|
264
|
+
runtimeContext: context,
|
|
265
|
+
contextId: context.context_id,
|
|
266
|
+
});
|
|
267
|
+
return binding;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function parseArgs(argv) {
|
|
271
|
+
const result = { json: false };
|
|
272
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
273
|
+
const arg = argv[index];
|
|
274
|
+
if (arg === '--json') result.json = true;
|
|
275
|
+
else if (arg === '--project-root') result.projectRoot = argv[++index];
|
|
276
|
+
else if (arg === '--specs-root') result.specsRoot = argv[++index];
|
|
277
|
+
else if (arg === '--spec-file') result.specFile = argv[++index];
|
|
278
|
+
else if (arg === '--feature-name') result.featureName = argv[++index];
|
|
279
|
+
else if (arg === '--runtime-session' || arg === '--session') result.runtimeSession = argv[++index];
|
|
280
|
+
else if (arg === '--provenance-mode') result.provenanceMode = argv[++index];
|
|
281
|
+
else fail('malformed_input', `unknown option: ${arg}`);
|
|
282
|
+
}
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function runCli(argv = process.argv.slice(2)) {
|
|
287
|
+
let options;
|
|
288
|
+
try {
|
|
289
|
+
options = parseArgs(argv);
|
|
290
|
+
const context = deriveRuntimeProvenance(options);
|
|
291
|
+
const output = { ok: true, context, Base: context.base, Head: context.head, context_id: context.context_id };
|
|
292
|
+
process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
293
|
+
return 0;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
const output = { ok: false, error: { code: error.code || 'provenance_failed', message: error.message } };
|
|
296
|
+
if (options?.json) process.stdout.write(`${JSON.stringify(output)}\n`);
|
|
297
|
+
else process.stderr.write(`${output.error.code}: ${output.error.message}\n`);
|
|
298
|
+
return 2;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (require.main === module) process.exitCode = runCli();
|
|
303
|
+
|
|
304
|
+
module.exports = {
|
|
305
|
+
CONTEXT_SCHEMA_VERSION,
|
|
306
|
+
PROVENANCE_MODE,
|
|
307
|
+
ProvenanceError,
|
|
308
|
+
createReceiptBinding,
|
|
309
|
+
deriveRuntimeContext: deriveRuntimeProvenance,
|
|
310
|
+
deriveRuntimeProvenance,
|
|
311
|
+
isTrustedRuntimeContext,
|
|
312
|
+
recomputeRuntimeContext: recomputeRuntimeProvenance,
|
|
313
|
+
recomputeRuntimeProvenance,
|
|
314
|
+
runCli,
|
|
315
|
+
};
|