@orkestrel/scaffold 0.0.100 → 0.0.102
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/dist/agents/skills/orkestrel-dispatch/scripts/brief.js +6 -14
- package/dist/agents/skills/orkestrel-dispatch/scripts/cite.js +41 -28
- package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +5 -12
- package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +25 -13
- package/dist/agents/skills/orkestrel-dispatch/scripts/login.js +18 -25
- package/dist/agents/skills/orkestrel-dispatch/scripts/result.js +11 -9
- package/dist/agents/skills/orkestrel-harden/scripts/discovery.js +233 -232
- package/dist/agents/skills/orkestrel-publish/scripts/compare.js +95 -89
- package/dist/agents/skills/orkestrel-publish/scripts/pins.js +5 -7
- package/dist/agents/skills/orkestrel-publish/scripts/swap.js +1273 -0
- package/dist/agents/skills/orkestrel-publish/scripts/wave.js +99 -89
- package/dist/agents/skills/orkestrel-publish/scripts/window.js +54 -52
- package/dist/agents/skills/orkestrel-scout/scripts/map.js +160 -161
- package/dist/bin/main.js +483 -444
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +1 -0
- package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +10 -10
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/brief.ts +8 -11
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/cite.ts +58 -28
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +5 -10
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +31 -12
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/login.ts +28 -23
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/result.ts +12 -10
- package/dist/host/agents/skills/orkestrel-harden/scripts/discovery.ts +318 -237
- package/dist/host/agents/skills/orkestrel-journey/references/statechart.md +2 -5
- package/dist/host/agents/skills/orkestrel-publish/SKILL.md +7 -6
- package/dist/host/agents/skills/orkestrel-publish/references/release.md +12 -10
- package/dist/host/agents/skills/orkestrel-publish/references/wave.md +12 -5
- package/dist/host/agents/skills/orkestrel-publish/scripts/compare.ts +124 -82
- package/dist/host/agents/skills/orkestrel-publish/scripts/pins.ts +5 -7
- package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +1655 -0
- package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +128 -97
- package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +70 -55
- package/dist/host/agents/skills/orkestrel-scout/scripts/map.ts +215 -155
- package/dist/host/claude/rules/architecture.md +2 -2
- package/dist/host/claude/rules/tests.md +8 -2
- package/dist/host/claude/rules/typescript.md +130 -0
- package/dist/host/claude/rules/workspace.md +36 -12
- package/dist/host/configs/helpers.ts +214 -133
- package/dist/host/configs/policy.ts +110 -105
- package/dist/host/dotfiles/gitignore +1 -0
- package/dist/host/dotfiles/oxlintrc.json +10 -0
- package/dist/host/guides/scaffold.md +244 -170
- package/dist/host/manifest.json +37 -31
- package/dist/host/tests/config.test.ts +1305 -619
- package/dist/host/tests/policy.test.ts +19 -0
- package/dist/host/tests/setupPolicy.ts +1710 -995
- package/dist/src/core/index.cjs +1595 -1686
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +202 -18
- package/dist/src/core/index.d.ts +202 -18
- package/dist/src/core/index.js +1590 -1687
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +448 -392
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +1182 -1052
- package/dist/src/server/index.d.ts +1182 -1052
- package/dist/src/server/index.js +447 -395
- package/dist/src/server/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -47,37 +47,40 @@ function mapTree(paths) {
|
|
|
47
47
|
})
|
|
48
48
|
.sort((left, right) => left.path.localeCompare(right.path));
|
|
49
49
|
}
|
|
50
|
+
function scanFences(lines) {
|
|
51
|
+
const fenced = [];
|
|
52
|
+
for (const text of lines)
|
|
53
|
+
fenced.push((fenced.at(-1) ?? false) !== text.startsWith('```'));
|
|
54
|
+
return fenced;
|
|
55
|
+
}
|
|
50
56
|
function mapHeadings(paths) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
readLines(path)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (fenced)
|
|
58
|
-
return;
|
|
57
|
+
return expandPaths(paths)
|
|
58
|
+
.filter((candidate) => candidate.endsWith('.md'))
|
|
59
|
+
.flatMap((path) => {
|
|
60
|
+
const lines = readLines(path);
|
|
61
|
+
const fenced = scanFences(lines);
|
|
62
|
+
return lines.flatMap((text, index) => {
|
|
63
|
+
if (fenced[index] === true)
|
|
64
|
+
return [];
|
|
59
65
|
const match = text.match(HEADING);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
return match?.[1] !== undefined && match[2] !== undefined
|
|
67
|
+
? [{ path, line: index + 1, text: `${match[1]} ${match[2]}` }]
|
|
68
|
+
: [];
|
|
63
69
|
});
|
|
64
|
-
}
|
|
65
|
-
return rows;
|
|
70
|
+
});
|
|
66
71
|
}
|
|
67
72
|
function mapExports(paths) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
readLines(path).
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
return rows;
|
|
73
|
+
return expandPaths(paths)
|
|
74
|
+
.filter((candidate) => /\.[cm]?ts$/u.test(candidate))
|
|
75
|
+
.flatMap((path) => readLines(path).flatMap((text, index) => {
|
|
76
|
+
const match = text.match(EXPORT);
|
|
77
|
+
if (match?.[1] !== undefined && match[2] !== undefined) {
|
|
78
|
+
return [{ path, line: index + 1, text: `${match[1]} ${match[2]}` }];
|
|
79
|
+
}
|
|
80
|
+
return /^export\s+\*\s+from\s+/u.test(text)
|
|
81
|
+
? [{ path, line: index + 1, text: text.trim() }]
|
|
82
|
+
: [];
|
|
83
|
+
}));
|
|
81
84
|
}
|
|
82
85
|
function buildMatcher(term, ignoreCase) {
|
|
83
86
|
const needle = ignoreCase ? term.toLowerCase() : term;
|
|
@@ -87,169 +90,165 @@ function mapCensus(terms, roots, ignoreCase) {
|
|
|
87
90
|
const files = expandPaths(roots).filter(isText);
|
|
88
91
|
return terms.map((term) => {
|
|
89
92
|
const matches = buildMatcher(term, ignoreCase);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
readLines(path).
|
|
93
|
-
|
|
94
|
-
rows.push({ path, line: index + 1, text: text.trim().slice(0, 160) });
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
return { term, rows };
|
|
93
|
+
return {
|
|
94
|
+
term,
|
|
95
|
+
rows: files.flatMap((path) => readLines(path).flatMap((text, index) => matches(text) ? [{ path, line: index + 1, text: text.trim().slice(0, 160) }] : [])),
|
|
96
|
+
};
|
|
98
97
|
});
|
|
99
98
|
}
|
|
100
99
|
function mapRefs(target, roots) {
|
|
101
100
|
const needle = normalizeSlashes(target);
|
|
102
101
|
const name = basename(needle);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
rows.push({ path, line: index + 1, text: text.trim().slice(0, 160) });
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
return rows;
|
|
102
|
+
return expandPaths(roots)
|
|
103
|
+
.filter(isText)
|
|
104
|
+
.filter((path) => path !== needle)
|
|
105
|
+
.flatMap((path) => readLines(path).flatMap((text, index) => text.includes(needle) || text.includes(name)
|
|
106
|
+
? [{ path, line: index + 1, text: text.trim().slice(0, 160) }]
|
|
107
|
+
: []));
|
|
114
108
|
}
|
|
115
|
-
function
|
|
116
|
-
|
|
117
|
-
const stack = [];
|
|
118
|
-
lines.forEach((text, index) => {
|
|
109
|
+
function classifyYamlLines(lines, offset) {
|
|
110
|
+
return lines.flatMap((text, index) => {
|
|
119
111
|
const content = text.trimStart();
|
|
120
112
|
if (content === '' || content.startsWith('#'))
|
|
121
|
-
return;
|
|
122
|
-
const indent = text.length - content.length;
|
|
113
|
+
return [];
|
|
123
114
|
const match = content.match(/^([A-Za-z_][\w-]*)\s*:(?:\s+(.*))?$/u);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
stack.pop();
|
|
134
|
-
const key = [...stack.map((entry) => entry.key), match[1]].join('.');
|
|
135
|
-
stack.push({ indent, key: match[1] });
|
|
136
|
-
rows.push({ path, line: index + offset, text: `${key}: ${(match[2] ?? '').trim()}`.trimEnd() });
|
|
115
|
+
return [
|
|
116
|
+
{
|
|
117
|
+
line: index + offset,
|
|
118
|
+
indent: text.length - content.length,
|
|
119
|
+
content,
|
|
120
|
+
key: match?.[1],
|
|
121
|
+
value: (match?.[2] ?? '').trim(),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
137
124
|
});
|
|
138
|
-
|
|
125
|
+
}
|
|
126
|
+
function stepYamlState(state, line, position) {
|
|
127
|
+
if (line.key === undefined)
|
|
128
|
+
return state;
|
|
129
|
+
// Indents strictly increase along the stack, so the entries at or past this indent are the tail.
|
|
130
|
+
const stack = state.stack.filter((entry) => entry.indent < line.indent);
|
|
131
|
+
const key = [...stack.map((entry) => entry.key), line.key].join('.');
|
|
132
|
+
return {
|
|
133
|
+
stack: [...stack, { indent: line.indent, key: line.key }],
|
|
134
|
+
heads: [...state.heads, { position, line, key }],
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function readYamlKeys(path, lines, offset) {
|
|
138
|
+
const classified = classifyYamlLines(lines, offset);
|
|
139
|
+
const { heads } = classified.reduce((state, line, position) => stepYamlState(state, line, position), { stack: [], heads: [] });
|
|
140
|
+
// A list item, a block scalar line, or a wrapped value extends the key line before it when it is
|
|
141
|
+
// indented at least as far; between two key lines every classified line is a non-key line.
|
|
142
|
+
return heads.map((head, rank) => ({
|
|
143
|
+
path,
|
|
144
|
+
line: head.line.line,
|
|
145
|
+
text: [
|
|
146
|
+
`${head.key}: ${head.line.value}`.trimEnd(),
|
|
147
|
+
...classified
|
|
148
|
+
.slice(head.position + 1, heads[rank + 1]?.position ?? classified.length)
|
|
149
|
+
.filter((line) => line.indent >= head.line.indent)
|
|
150
|
+
.map((line) => line.content.trim()),
|
|
151
|
+
]
|
|
152
|
+
.join(' ')
|
|
153
|
+
.trimEnd(),
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
function stepTomlState(state, text, path, line) {
|
|
157
|
+
if (state.fence !== undefined) {
|
|
158
|
+
// The body of a multi-line string carries no key.
|
|
159
|
+
return text.includes(state.fence) ? { ...state, fence: undefined } : state;
|
|
160
|
+
}
|
|
161
|
+
const header = text.match(/^\s*\[\[?([^\]]+)\]\]?\s*$/u);
|
|
162
|
+
if (header?.[1] !== undefined)
|
|
163
|
+
return { ...state, table: header[1].trim() };
|
|
164
|
+
const match = text.match(/^\s*([A-Za-z0-9_.-]+|"[^"]+")\s*=\s*(.*)$/u);
|
|
165
|
+
if (match?.[1] === undefined)
|
|
166
|
+
return state;
|
|
167
|
+
const value = (match[2] ?? '').trim();
|
|
168
|
+
const opening = value.match(/^("""|''')/u)?.[1];
|
|
169
|
+
return {
|
|
170
|
+
table: state.table,
|
|
171
|
+
fence: opening !== undefined && value.indexOf(opening, 3) === -1 ? opening : undefined,
|
|
172
|
+
rows: [
|
|
173
|
+
...state.rows,
|
|
174
|
+
{
|
|
175
|
+
path,
|
|
176
|
+
line,
|
|
177
|
+
text: `${state.table === '' ? '' : `${state.table}.`}${match[1]}: ${value}`.trimEnd(),
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
};
|
|
139
181
|
}
|
|
140
182
|
function readTomlKeys(path, lines, offset) {
|
|
141
|
-
|
|
142
|
-
let table = '';
|
|
143
|
-
let fence;
|
|
144
|
-
lines.forEach((text, index) => {
|
|
145
|
-
if (fence !== undefined) {
|
|
146
|
-
// The body of a multi-line string carries no key.
|
|
147
|
-
if (text.includes(fence))
|
|
148
|
-
fence = undefined;
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
const header = text.match(/^\s*\[\[?([^\]]+)\]\]?\s*$/u);
|
|
152
|
-
if (header?.[1] !== undefined) {
|
|
153
|
-
table = header[1].trim();
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const match = text.match(/^\s*([A-Za-z0-9_.-]+|"[^"]+")\s*=\s*(.*)$/u);
|
|
157
|
-
if (match?.[1] === undefined)
|
|
158
|
-
return;
|
|
159
|
-
const value = (match[2] ?? '').trim();
|
|
160
|
-
const opening = value.match(/^("""|''')/u)?.[1];
|
|
161
|
-
if (opening !== undefined && value.indexOf(opening, 3) === -1)
|
|
162
|
-
fence = opening;
|
|
163
|
-
rows.push({
|
|
164
|
-
path,
|
|
165
|
-
line: index + offset,
|
|
166
|
-
text: `${table === '' ? '' : `${table}.`}${match[1]}: ${value}`.trimEnd(),
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
return rows;
|
|
183
|
+
return lines.reduce((state, text, index) => stepTomlState(state, text, path, index + offset), { table: '', fence: undefined, rows: [] }).rows;
|
|
170
184
|
}
|
|
171
185
|
function mapFrontmatter(paths) {
|
|
172
|
-
|
|
173
|
-
|
|
186
|
+
return expandPaths(paths)
|
|
187
|
+
.filter((candidate) => /\.(md|mdc|toml|ya?ml)$/u.test(candidate))
|
|
188
|
+
.flatMap((path) => {
|
|
174
189
|
const lines = readLines(path);
|
|
175
190
|
const markdown = /\.mdc?$/u.test(path);
|
|
176
191
|
const end = markdown ? lines.indexOf('---', 1) : lines.length;
|
|
177
192
|
if (markdown && (lines[0] !== '---' || end === -1))
|
|
178
|
-
|
|
193
|
+
return [];
|
|
179
194
|
const body = lines.slice(markdown ? 1 : 0, end);
|
|
180
195
|
const offset = markdown ? 2 : 1;
|
|
181
|
-
|
|
196
|
+
return path.endsWith('.toml')
|
|
182
197
|
? readTomlKeys(path, body, offset)
|
|
183
|
-
: readYamlKeys(path, body, offset)
|
|
184
|
-
}
|
|
185
|
-
return rows;
|
|
198
|
+
: readYamlKeys(path, body, offset);
|
|
199
|
+
});
|
|
186
200
|
}
|
|
187
201
|
function readHeadingTexts(path) {
|
|
188
202
|
return new Set(mapHeadings([path]).map((row) => row.text.replace(/^#+\s+/u, '').toLowerCase()));
|
|
189
203
|
}
|
|
190
204
|
function mapAnchors(paths) {
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
rows.push({ path, line: index + 1, target, heading });
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
const known = headings.get(target) ?? readHeadingTexts(target);
|
|
205
|
-
headings.set(target, known);
|
|
206
|
-
if (!known.has(heading.toLowerCase()))
|
|
207
|
-
rows.push({ path, line: index + 1, target, heading });
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
return rows;
|
|
205
|
+
const citations = expandPaths(paths)
|
|
206
|
+
.filter((candidate) => candidate.endsWith('.md'))
|
|
207
|
+
.flatMap((path) => readLines(path).flatMap((text, index) => [...text.matchAll(ANCHOR)].flatMap((match) => {
|
|
208
|
+
const target = match[1] === undefined ? path : normalizeSlashes(match[1]);
|
|
209
|
+
const heading = (match[2] ?? '').trim();
|
|
210
|
+
return heading === '' ? [] : [{ path, line: index + 1, target, heading }];
|
|
211
|
+
})));
|
|
212
|
+
// Each existing target is read once, in the order its first citation names it.
|
|
213
|
+
const headings = new Map([...new Set(citations.map(({ target }) => target).filter((target) => existsSync(target)))].map((target) => [target, readHeadingTexts(target)]));
|
|
214
|
+
return citations.filter(({ target, heading }) => headings.get(target)?.has(heading.toLowerCase()) !== true);
|
|
212
215
|
}
|
|
213
216
|
function renderReport(report) {
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
lines.push(`## Unresolved anchors (${report.anchors.length})`);
|
|
250
|
-
for (const row of report.anchors)
|
|
251
|
-
lines.push(`${row.path}:${row.line}\t${row.target} § ${row.heading}`);
|
|
252
|
-
}
|
|
217
|
+
const { tree, headings, frontmatter, exports, census, refs, anchors } = report;
|
|
218
|
+
const lines = [
|
|
219
|
+
...(tree === undefined
|
|
220
|
+
? []
|
|
221
|
+
: [
|
|
222
|
+
'## Tree',
|
|
223
|
+
...tree.map((row) => `${row.path}\t${row.lines} lines\t${row.bytes} bytes`),
|
|
224
|
+
`total\t${tree.length} files\t${tree.reduce((sum, row) => sum + row.lines, 0)} lines`,
|
|
225
|
+
]),
|
|
226
|
+
...(headings === undefined
|
|
227
|
+
? []
|
|
228
|
+
: ['## Headings', ...headings.map((row) => `${row.path}:${row.line}\t${row.text}`)]),
|
|
229
|
+
...(frontmatter === undefined
|
|
230
|
+
? []
|
|
231
|
+
: ['## Frontmatter', ...frontmatter.map((row) => `${row.path}:${row.line}\t${row.text}`)]),
|
|
232
|
+
...(exports === undefined
|
|
233
|
+
? []
|
|
234
|
+
: [
|
|
235
|
+
'## Exports (text reading)',
|
|
236
|
+
...exports.map((row) => `${row.path}:${row.line}\t${row.text}`),
|
|
237
|
+
]),
|
|
238
|
+
...(census ?? []).flatMap((entry) => [
|
|
239
|
+
`## Census: ${entry.term} (${entry.rows.length})`,
|
|
240
|
+
...entry.rows.map((row) => `${row.path}:${row.line}\t${row.text}`),
|
|
241
|
+
]),
|
|
242
|
+
...(refs === undefined
|
|
243
|
+
? []
|
|
244
|
+
: [`## Refs (${refs.length})`, ...refs.map((row) => `${row.path}:${row.line}\t${row.text}`)]),
|
|
245
|
+
...(anchors === undefined
|
|
246
|
+
? []
|
|
247
|
+
: [
|
|
248
|
+
`## Unresolved anchors (${anchors.length})`,
|
|
249
|
+
...anchors.map((row) => `${row.path}:${row.line}\t${row.target} § ${row.heading}`),
|
|
250
|
+
]),
|
|
251
|
+
];
|
|
253
252
|
return `${lines.join('\n')}\n`;
|
|
254
253
|
}
|
|
255
254
|
function main(argv) {
|