genesis-compiler 1.2.9 → 1.2.12
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/README.md +7 -4
- package/docs/stack-components.md +18 -1
- package/package.json +2 -1
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/src/index/agent-skills.js +88 -2
- package/src/index/code-index.js +13 -0
- package/src/index/codex-hooks.js +10 -1
- package/src/index/contracts.js +2 -1
- package/src/index/deployment.js +1 -0
- package/src/index/stack-deployment.js +59 -4
- package/src/index.js +10 -2
package/README.md
CHANGED
|
@@ -122,9 +122,12 @@ Genesis does not install substitute generic `nodejs`, `vue`, `php`, or similar
|
|
|
122
122
|
skills. Official, user, or host skills retain their normal names. A Stack piece
|
|
123
123
|
may instead name one authoritative technology skill; Genesis copies that
|
|
124
124
|
complete directory into `.agents/skills/`, including its `references/`,
|
|
125
|
-
`scripts/`, `assets/`, and agent metadata.
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
`scripts/`, `assets/`, and agent metadata. Every relative Markdown link and image
|
|
126
|
+
must resolve within that same Skill directory after relocation; a missing
|
|
127
|
+
target or path that escapes the Skill root makes the Skill invalid. The agent
|
|
128
|
+
loads valid resources only when the Skill requires them. For example, the
|
|
129
|
+
`genesis-stack` catalog's JSKIT piece installs the JSKIT package's own `jskit`
|
|
130
|
+
skill. A piece's optional
|
|
128
131
|
`## Guidance` is concise
|
|
129
132
|
supplemental project-work guidance; it does not create or replace a generic
|
|
130
133
|
technology skill.
|
|
@@ -510,7 +513,7 @@ executing or provisioning it.
|
|
|
510
513
|
|
|
511
514
|
Normalized operational results identify their stable public contract in the
|
|
512
515
|
`contract` field: `genesis.workspace-setup.v1`, `genesis.environment.v1`,
|
|
513
|
-
`genesis.launch.v1`, `genesis.deployment.
|
|
516
|
+
`genesis.launch.v1`, `genesis.deployment.v2`, or
|
|
514
517
|
`genesis.verification.v1`. Hosts validate that identity instead of
|
|
515
518
|
feature-detecting individual fields.
|
|
516
519
|
|
package/docs/stack-components.md
CHANGED
|
@@ -126,7 +126,10 @@ selects one complete [Agent Skills](https://agentskills.io) directory, either
|
|
|
126
126
|
from Genesis or from the declared npm package. Its `SKILL.md`, `references/`,
|
|
127
127
|
`scripts/`, `assets/`, and `agents/` metadata are copied together to
|
|
128
128
|
`.agents/skills/<skill-name>/`; the agent loads them progressively instead of
|
|
129
|
-
Genesis expanding every manual into every prompt.
|
|
129
|
+
Genesis expanding every manual into every prompt. Relative Markdown links and
|
|
130
|
+
images must resolve within that copied Skill root. Missing targets and paths
|
|
131
|
+
that escape the root are invalid, even if an escaped path happens to exist in
|
|
132
|
+
the source package or project. `Resources` declares generic
|
|
130
133
|
alternative environment-name sets reported by prompt generation and checked
|
|
131
134
|
before verification. `allowEmpty` may name a required variable whose empty
|
|
132
135
|
string is valid. `Environment defaults` declares public non-secret constants
|
|
@@ -257,6 +260,7 @@ complete form is:
|
|
|
257
260
|
|
|
258
261
|
- Workdir: `.`
|
|
259
262
|
- Runtimes: `nodejs`
|
|
263
|
+
- Recreate on restore: `node_modules`
|
|
260
264
|
- Ready when: `GET` `/api/health` returns `200`
|
|
261
265
|
- Prepare `Install production dependencies`: `npm` `install` `--omit=dev`
|
|
262
266
|
- Build `Build`: `npm` `run` `build`
|
|
@@ -270,6 +274,19 @@ Prepare, Build, and Migrate steps are optional and retain their declared order.
|
|
|
270
274
|
There is exactly one final Serve step and one exact HTTP readiness predicate
|
|
271
275
|
whose successful status is from 200 through 399. Runtime ids remain abstract.
|
|
272
276
|
|
|
277
|
+
`Recreate on restore` lists project-relative paths that a host may remove when
|
|
278
|
+
retaining an inactive release. Every listed path must be completely recreated
|
|
279
|
+
by the Deployment Prepare steps, which a host runs after restoring the release
|
|
280
|
+
and before Serve. Declaring these paths without a Prepare step is invalid.
|
|
281
|
+
An entry without `/` matches that path segment at every depth, so
|
|
282
|
+
`node_modules` covers root and nested workspace dependency trees. `*` stays
|
|
283
|
+
within one segment and `**` may cross path separators. A matched directory
|
|
284
|
+
includes its complete subtree.
|
|
285
|
+
This is application and Stack knowledge: for example, JSKIT declares
|
|
286
|
+
`node_modules`, while compiled output such as `dist` remains part of the
|
|
287
|
+
artifact because Prepare does not rebuild it. Genesis normalizes the paths but
|
|
288
|
+
does not remove, archive, restore, or reconstruct anything itself.
|
|
289
|
+
|
|
273
290
|
A project `## Deployment` section replaces every component recipe as one unit,
|
|
274
291
|
including with `- Nothing.`. Without a project section, exactly one selected
|
|
275
292
|
component recipe may apply; several are blocked as ambiguous and never merged.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genesis-compiler",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An agent-independent prompt, multi-language code-index, cleanup, and verification companion with optional Codex hooks.",
|
|
6
6
|
"repository": {
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"@ast-grep/lang-ruby": "^0.0.7",
|
|
58
58
|
"@ast-grep/lang-rust": "^0.0.7",
|
|
59
59
|
"@ast-grep/napi": "^0.45.1",
|
|
60
|
+
"mdast-util-from-markdown": "^2.0.3",
|
|
60
61
|
"yaml": "^2.9.0"
|
|
61
62
|
}
|
|
62
63
|
}
|
|
@@ -12,9 +12,10 @@ import {
|
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { fileURLToPath } from 'node:url';
|
|
14
14
|
|
|
15
|
+
import { fromMarkdown } from 'mdast-util-from-markdown';
|
|
15
16
|
import { parse as parseYaml } from 'yaml';
|
|
16
17
|
|
|
17
|
-
import { GenesisError } from './errors.js';
|
|
18
|
+
import { asDiagnostic, GenesisError } from './errors.js';
|
|
18
19
|
import { sha256, stableJson, writeFileAtomic } from './utils.js';
|
|
19
20
|
|
|
20
21
|
const packageRoot = fileURLToPath(new URL('../../', import.meta.url));
|
|
@@ -76,6 +77,90 @@ function frontmatter(source, location) {
|
|
|
76
77
|
return metadata;
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
function markdownDestinations(tree) {
|
|
81
|
+
const destinations = [];
|
|
82
|
+
const nodes = [tree];
|
|
83
|
+
while (nodes.length > 0) {
|
|
84
|
+
const node = nodes.pop();
|
|
85
|
+
if (['definition', 'image', 'link'].includes(node?.type) && typeof node.url === 'string') {
|
|
86
|
+
destinations.push({ line: node.position?.start?.line, url: node.url });
|
|
87
|
+
}
|
|
88
|
+
if (Array.isArray(node?.children)) nodes.push(...node.children);
|
|
89
|
+
}
|
|
90
|
+
return destinations.sort((left, right) => (left.line || 0) - (right.line || 0));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function localReferencePath(url) {
|
|
94
|
+
const value = String(url || '').trim();
|
|
95
|
+
if (
|
|
96
|
+
!value
|
|
97
|
+
|| value.startsWith('#')
|
|
98
|
+
|| value.startsWith('?')
|
|
99
|
+
|| value.startsWith('/')
|
|
100
|
+
|| /^[a-z][a-z\d+.-]*:/iu.test(value)
|
|
101
|
+
) return null;
|
|
102
|
+
const separator = value.search(/[?#]/u);
|
|
103
|
+
const encodedPath = separator === -1 ? value : value.slice(0, separator);
|
|
104
|
+
if (!encodedPath) return null;
|
|
105
|
+
try {
|
|
106
|
+
return { path: decodeURIComponent(encodedPath) };
|
|
107
|
+
} catch {
|
|
108
|
+
return { error: 'malformed', path: encodedPath };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function outsideDirectory(directory, target) {
|
|
113
|
+
const relative = path.relative(directory, target);
|
|
114
|
+
return relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function validateMarkdownReferences(directory, files) {
|
|
118
|
+
const root = path.resolve(directory);
|
|
119
|
+
const problems = [];
|
|
120
|
+
for (const file of files.filter(({ path: filePath }) => filePath.endsWith('.md'))) {
|
|
121
|
+
const location = path.join(root, file.path);
|
|
122
|
+
let tree;
|
|
123
|
+
try {
|
|
124
|
+
tree = fromMarkdown(await readFile(location, 'utf8'));
|
|
125
|
+
} catch (error) {
|
|
126
|
+
invalidSkill(`Agent Skill Markdown is invalid: ${location}.`, {
|
|
127
|
+
cause: error.message,
|
|
128
|
+
path: file.path,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
for (const destination of markdownDestinations(tree)) {
|
|
132
|
+
const local = localReferencePath(destination.url);
|
|
133
|
+
if (!local) continue;
|
|
134
|
+
const problem = {
|
|
135
|
+
path: file.path,
|
|
136
|
+
target: destination.url,
|
|
137
|
+
...(destination.line ? { line: destination.line } : {}),
|
|
138
|
+
};
|
|
139
|
+
if (local.error) {
|
|
140
|
+
problems.push({ ...problem, reason: local.error });
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const target = path.resolve(path.dirname(location), local.path);
|
|
144
|
+
if (outsideDirectory(root, target)) {
|
|
145
|
+
problems.push({ ...problem, reason: 'outside-skill' });
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
await lstat(target);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (!['ENOENT', 'ENOTDIR'].includes(error?.code)) throw error;
|
|
152
|
+
problems.push({ ...problem, reason: 'missing' });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (problems.length > 0) {
|
|
157
|
+
invalidSkill(
|
|
158
|
+
`Agent Skill contains ${problems.length} unresolved or non-portable local Markdown reference${problems.length === 1 ? '' : 's'}: ${directory}.`,
|
|
159
|
+
{ references: problems },
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
79
164
|
async function skillTree(directory, relative = '') {
|
|
80
165
|
const entries = await readdir(path.join(directory, relative), { withFileTypes: true });
|
|
81
166
|
const files = [];
|
|
@@ -146,6 +231,7 @@ async function describeSkill(directory, source) {
|
|
|
146
231
|
)
|
|
147
232
|
) invalidSkill(`Agent Skill metadata must map strings to strings: ${skillFile}.`);
|
|
148
233
|
const files = await skillTree(directory);
|
|
234
|
+
await validateMarkdownReferences(directory, files);
|
|
149
235
|
return {
|
|
150
236
|
name,
|
|
151
237
|
description,
|
|
@@ -395,7 +481,7 @@ export async function inspectProjectSkills({ projectRoot, stack } = {}) {
|
|
|
395
481
|
let installed;
|
|
396
482
|
try { installed = await describeSkill(target, `project:${expected.name}`); } catch (error) {
|
|
397
483
|
invalid = true;
|
|
398
|
-
diagnostics.push(
|
|
484
|
+
diagnostics.push(asDiagnostic(error));
|
|
399
485
|
continue;
|
|
400
486
|
}
|
|
401
487
|
if (!installed) {
|
package/src/index/code-index.js
CHANGED
|
@@ -15,6 +15,19 @@ import { sha256, stableJson, writeFileAtomic } from './utils.js';
|
|
|
15
15
|
export const MACHINE_CITY_PATH = '.genesis/machine-city.json';
|
|
16
16
|
export const PROGRAM_CITY_PATH = '.genesis/program-city.json';
|
|
17
17
|
|
|
18
|
+
export const GENESIS_DERIVED_ARTIFACTS = Object.freeze([
|
|
19
|
+
Object.freeze({
|
|
20
|
+
id: 'machine-city',
|
|
21
|
+
path: MACHINE_CITY_PATH,
|
|
22
|
+
recreator: 'index-codebase',
|
|
23
|
+
}),
|
|
24
|
+
Object.freeze({
|
|
25
|
+
id: 'program-city',
|
|
26
|
+
path: PROGRAM_CITY_PATH,
|
|
27
|
+
recreator: 'index-codebase',
|
|
28
|
+
}),
|
|
29
|
+
]);
|
|
30
|
+
|
|
18
31
|
const INDEXERS = astGrepCodeIndexers;
|
|
19
32
|
|
|
20
33
|
function directoryId(value) {
|
package/src/index/codex-hooks.js
CHANGED
|
@@ -250,10 +250,19 @@ async function changedProjectPaths(projectRoot, before, after) {
|
|
|
250
250
|
const dirtyChanges = [...new Set([...previous.keys(), ...current.keys()])].filter((file) => (
|
|
251
251
|
stableJson(previous.get(file)) !== stableJson(current.get(file))
|
|
252
252
|
));
|
|
253
|
-
|
|
253
|
+
const candidates = [...new Set([
|
|
254
254
|
...dirtyChanges,
|
|
255
255
|
...await committedPaths(projectRoot, before.head, after.head),
|
|
256
256
|
])].sort();
|
|
257
|
+
const changed = await Promise.all(candidates.map(async (file) => {
|
|
258
|
+
if (!previous.has(file)) return file;
|
|
259
|
+
// Moving pre-turn file bytes into HEAD is a save operation, not new implementation.
|
|
260
|
+
const finalState = current.has(file)
|
|
261
|
+
? current.get(file)
|
|
262
|
+
: await pathState(path.join(projectRoot, file));
|
|
263
|
+
return stableJson(previous.get(file)) === stableJson(finalState) ? null : file;
|
|
264
|
+
}));
|
|
265
|
+
return changed.filter(Boolean);
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
function changedPathLines(changedPaths) {
|
package/src/index/contracts.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const GENESIS_CONTRACTS = Object.freeze({
|
|
2
|
-
deployment: 'genesis.deployment.
|
|
2
|
+
deployment: 'genesis.deployment.v2',
|
|
3
|
+
derivedArtifacts: 'genesis.derived-artifacts.v1',
|
|
3
4
|
environment: 'genesis.environment.v1',
|
|
4
5
|
launch: 'genesis.launch.v1',
|
|
5
6
|
verification: 'genesis.verification.v1',
|
package/src/index/deployment.js
CHANGED
|
@@ -13,6 +13,7 @@ export async function inspectProjectDeployment({ projectRoot, stackPackages = []
|
|
|
13
13
|
else if (stack.deployment.steps.length > 0) status = 'ready';
|
|
14
14
|
const recipe = {
|
|
15
15
|
version: stack.deployment.version,
|
|
16
|
+
artifact: stack.deployment.artifact,
|
|
16
17
|
workdir: stack.deployment.workdir,
|
|
17
18
|
runtimeRequirements: stack.deployment.runtimeRequirements,
|
|
18
19
|
readiness: stack.deployment.readiness,
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
const RUNTIME_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
9
9
|
const STEP_LINE = /^- (Prepare|Build|Migrate|Serve) `([^`\r\n]+)`:[ \t]+(.+)$/u;
|
|
10
|
+
const RESTORE_PATHS_PREFIX = '- Recreate on restore: ';
|
|
10
11
|
const STEP_ROLE_ORDER = Object.freeze({
|
|
11
12
|
prepare: 0,
|
|
12
13
|
build: 1,
|
|
@@ -45,6 +46,36 @@ function parseRuntimes(source, deploymentPath, line) {
|
|
|
45
46
|
return values;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
function parseDisposablePaths(source, deploymentPath, line) {
|
|
50
|
+
const values = parseBacktickedArguments(source.slice(RESTORE_PATHS_PREFIX.length));
|
|
51
|
+
if (!values || values.length === 0) {
|
|
52
|
+
invalid(
|
|
53
|
+
deploymentPath,
|
|
54
|
+
'Deployment Recreate on restore paths must be separate non-empty backticked values.',
|
|
55
|
+
line,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const normalized = values.map((value) => String(value || '').trim());
|
|
59
|
+
if (normalized.some((value) => (
|
|
60
|
+
!value
|
|
61
|
+
|| value.startsWith('/')
|
|
62
|
+
|| value.includes('\\')
|
|
63
|
+
|| value.includes('***')
|
|
64
|
+
|| /[?\[\]{}!]/u.test(value)
|
|
65
|
+
|| value.split('/').some((segment) => !segment || ['.', '..'].includes(segment))
|
|
66
|
+
))) {
|
|
67
|
+
invalid(
|
|
68
|
+
deploymentPath,
|
|
69
|
+
'Deployment Recreate on restore paths must be canonical project-relative globs using only * and ** wildcards.',
|
|
70
|
+
line,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
74
|
+
invalid(deploymentPath, 'Deployment contains a duplicate Recreate on restore path.', line);
|
|
75
|
+
}
|
|
76
|
+
return normalized;
|
|
77
|
+
}
|
|
78
|
+
|
|
48
79
|
function parseUrlPath(value, deploymentPath, line) {
|
|
49
80
|
const normalized = String(value || '').trim();
|
|
50
81
|
if (!normalized.startsWith('/') || normalized.startsWith('//') || /[\\?#]/u.test(normalized)) {
|
|
@@ -103,10 +134,15 @@ export function parseStackDeploymentLines(lines, {
|
|
|
103
134
|
} = {}) {
|
|
104
135
|
if (lines === undefined) return null;
|
|
105
136
|
const entries = lines.map((line) => line.trim()).filter(Boolean);
|
|
106
|
-
if (entries.length === 1 && entries[0] === '- Nothing.')
|
|
137
|
+
if (entries.length === 1 && entries[0] === '- Nothing.') {
|
|
138
|
+
return { version: 2, artifact: { disposablePaths: [] }, steps: [] };
|
|
139
|
+
}
|
|
107
140
|
|
|
108
141
|
const result = {
|
|
109
|
-
version:
|
|
142
|
+
version: 2,
|
|
143
|
+
artifact: {
|
|
144
|
+
disposablePaths: [],
|
|
145
|
+
},
|
|
110
146
|
workdir: '.',
|
|
111
147
|
runtimeRequirements: [],
|
|
112
148
|
readiness: null,
|
|
@@ -133,6 +169,14 @@ export function parseStackDeploymentLines(lines, {
|
|
|
133
169
|
result.runtimeRequirements = parseRuntimes(source, deploymentPath, line);
|
|
134
170
|
continue;
|
|
135
171
|
}
|
|
172
|
+
if (source.startsWith(RESTORE_PATHS_PREFIX)) {
|
|
173
|
+
if (seen.has('restore-paths')) {
|
|
174
|
+
invalid(deploymentPath, 'Duplicate Deployment Recreate on restore entry.', line);
|
|
175
|
+
}
|
|
176
|
+
seen.add('restore-paths');
|
|
177
|
+
result.artifact.disposablePaths = parseDisposablePaths(source, deploymentPath, line);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
136
180
|
if (source.startsWith('- Ready when: ')) {
|
|
137
181
|
if (seen.has('readiness')) invalid(deploymentPath, 'Duplicate Deployment Ready when.', line);
|
|
138
182
|
seen.add('readiness');
|
|
@@ -164,6 +208,15 @@ export function parseStackDeploymentLines(lines, {
|
|
|
164
208
|
if (!result.readiness) {
|
|
165
209
|
invalid(deploymentPath, 'Deployment needs one Ready when entry.');
|
|
166
210
|
}
|
|
211
|
+
if (
|
|
212
|
+
result.artifact.disposablePaths.length > 0
|
|
213
|
+
&& !result.steps.some(({ role }) => role === 'prepare')
|
|
214
|
+
) {
|
|
215
|
+
invalid(
|
|
216
|
+
deploymentPath,
|
|
217
|
+
'Deployment may recreate paths on restore only when it declares a Prepare step.',
|
|
218
|
+
);
|
|
219
|
+
}
|
|
167
220
|
return result;
|
|
168
221
|
}
|
|
169
222
|
|
|
@@ -177,7 +230,8 @@ export function composeStackDeployment(components, projectDeployment) {
|
|
|
177
230
|
}));
|
|
178
231
|
if (declarations.length === 0) {
|
|
179
232
|
return {
|
|
180
|
-
version:
|
|
233
|
+
version: 2,
|
|
234
|
+
artifact: { disposablePaths: [] },
|
|
181
235
|
workdir: '.',
|
|
182
236
|
runtimeRequirements: [],
|
|
183
237
|
readiness: null,
|
|
@@ -189,7 +243,8 @@ export function composeStackDeployment(components, projectDeployment) {
|
|
|
189
243
|
if (declarations.length === 1) return { ...declarations[0], diagnostics: [] };
|
|
190
244
|
const sources = declarations.map(({ source }) => source).sort();
|
|
191
245
|
return {
|
|
192
|
-
version:
|
|
246
|
+
version: 2,
|
|
247
|
+
artifact: { disposablePaths: [] },
|
|
193
248
|
workdir: '.',
|
|
194
249
|
runtimeRequirements: [],
|
|
195
250
|
readiness: null,
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
3
|
import { checkProject } from './index/check.js';
|
|
4
|
-
import { buildProjectIndex } from './index/code-index.js';
|
|
4
|
+
import { buildProjectIndex, GENESIS_DERIVED_ARTIFACTS } from './index/code-index.js';
|
|
5
|
+
import { GENESIS_CONTRACTS } from './index/contracts.js';
|
|
5
6
|
import { contextForProjectPaths } from './index/context.js';
|
|
6
7
|
import { generateProjectPrompt } from './index/prompt.js';
|
|
7
8
|
import { initializeProject } from './index/init.js';
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
prepareProjectWorkspace,
|
|
18
19
|
} from './index/workspace-setup.js';
|
|
19
20
|
|
|
20
|
-
export { GENESIS_CONTRACTS }
|
|
21
|
+
export { GENESIS_CONTRACTS };
|
|
21
22
|
|
|
22
23
|
function withIndexResult(result, index) {
|
|
23
24
|
const changedFiles = [...new Set([...result.changedFiles, ...index.changedFiles])].sort();
|
|
@@ -131,6 +132,13 @@ export function indexCodebase({
|
|
|
131
132
|
return buildProjectIndex({ projectRoot, queries, stackPackages, write });
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
export function inspectDerivedArtifacts() {
|
|
136
|
+
return {
|
|
137
|
+
contract: GENESIS_CONTRACTS.derivedArtifacts,
|
|
138
|
+
artifacts: GENESIS_DERIVED_ARTIFACTS.map((artifact) => ({ ...artifact })),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
134
142
|
export function verify(options) {
|
|
135
143
|
return verifyProject(options);
|
|
136
144
|
}
|