@orkestrel/scaffold 0.0.108 → 0.0.109
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/bench.js +326 -91
- package/dist/agents/skills/orkestrel-dispatch/scripts/brief.js +110 -14
- package/dist/agents/skills/orkestrel-dispatch/scripts/chain.js +280 -0
- package/dist/agents/skills/orkestrel-dispatch/scripts/cite.js +188 -26
- package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +142 -43
- package/dist/agents/skills/orkestrel-dispatch/scripts/login.js +240 -62
- package/dist/agents/skills/orkestrel-dispatch/scripts/patch.js +323 -0
- package/dist/agents/skills/orkestrel-dispatch/scripts/result.js +169 -32
- package/dist/agents/skills/orkestrel-dispatch/scripts/sweep.js +290 -69
- package/dist/agents/skills/orkestrel-falsify/scripts/mutate.js +560 -0
- package/dist/agents/skills/orkestrel-harden/scripts/discovery.js +1052 -205
- package/dist/agents/skills/orkestrel-harden/scripts/measure.js +361 -0
- package/dist/agents/skills/orkestrel-harden/scripts/titles.js +455 -80
- package/dist/agents/skills/orkestrel-parallel/scripts/cases.js +327 -0
- package/dist/agents/skills/orkestrel-publish/scripts/compare.js +298 -51
- package/dist/agents/skills/orkestrel-publish/scripts/pins.js +170 -13
- package/dist/agents/skills/orkestrel-publish/scripts/swap.js +956 -191
- package/dist/agents/skills/orkestrel-publish/scripts/wave.js +707 -112
- package/dist/agents/skills/orkestrel-publish/scripts/window.js +235 -41
- package/dist/agents/skills/orkestrel-scout/scripts/map.js +341 -54
- package/dist/agents/templates/brief.md +1 -1
- package/dist/bin/main.js +51 -46
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +23 -21
- package/dist/host/agents/orchestration.md +43 -18
- package/dist/host/agents/platforms/windows.md +3 -3
- package/dist/host/agents/skills/orkestrel-align/SKILL.md +10 -13
- package/dist/host/agents/skills/orkestrel-align/references/fleet.md +4 -10
- package/dist/host/agents/skills/orkestrel-align/references/integration.md +1 -1
- package/dist/host/agents/skills/orkestrel-build/SKILL.md +16 -48
- package/dist/host/agents/skills/orkestrel-build/agents/openai.yaml +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +19 -16
- package/dist/host/agents/skills/orkestrel-debrief/agents/openai.yaml +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +15 -28
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +5 -6
- package/dist/host/agents/skills/orkestrel-debrief/references/retention.md +4 -6
- package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +31 -20
- package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +3 -4
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/bench.ts +366 -75
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/brief.ts +126 -16
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/chain.ts +323 -0
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/cite.ts +220 -31
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +176 -33
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/login.ts +294 -59
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/patch.ts +401 -0
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/result.ts +199 -34
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/sweep.ts +330 -69
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +10 -8
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +1 -5
- package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +1 -1
- package/dist/host/agents/skills/orkestrel-falsify/scripts/mutate.ts +701 -0
- package/dist/host/agents/skills/orkestrel-harden/SKILL.md +16 -12
- package/dist/host/agents/skills/orkestrel-harden/references/bindings.md +23 -81
- package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +4 -5
- package/dist/host/agents/skills/orkestrel-harden/references/contract.md +2 -0
- package/dist/host/agents/skills/orkestrel-harden/references/document.md +33 -0
- package/dist/host/agents/skills/orkestrel-harden/references/equivalence.md +6 -3
- package/dist/host/agents/skills/orkestrel-harden/references/hardening.md +8 -4
- package/dist/host/agents/skills/orkestrel-harden/references/research.md +2 -0
- package/dist/host/agents/skills/orkestrel-harden/scripts/discovery.ts +1272 -279
- package/dist/host/agents/skills/orkestrel-harden/scripts/measure.ts +425 -0
- package/dist/host/agents/skills/orkestrel-harden/scripts/titles.ts +603 -98
- package/dist/host/agents/skills/orkestrel-journey/SKILL.md +75 -98
- package/dist/host/agents/skills/orkestrel-journey/references/captures.md +54 -17
- package/dist/host/agents/skills/orkestrel-journey/references/decide.md +1 -20
- package/dist/host/agents/skills/orkestrel-journey/references/layer.md +21 -31
- package/dist/host/agents/skills/orkestrel-journey/references/styles.md +1 -1
- package/dist/host/agents/skills/orkestrel-parallel/SKILL.md +28 -24
- package/dist/host/agents/skills/orkestrel-parallel/references/claude.md +15 -13
- package/dist/host/agents/skills/orkestrel-parallel/references/codex.md +1 -0
- package/dist/host/agents/skills/orkestrel-parallel/references/cursor.md +13 -13
- package/dist/host/agents/skills/orkestrel-parallel/scripts/cases.ts +389 -0
- package/dist/host/agents/skills/orkestrel-polish/SKILL.md +16 -20
- package/dist/host/agents/skills/orkestrel-polish/references/capture-harness.md +16 -26
- package/dist/host/agents/skills/orkestrel-publish/SKILL.md +12 -26
- package/dist/host/agents/skills/orkestrel-publish/agents/openai.yaml +2 -2
- package/dist/host/agents/skills/orkestrel-publish/references/adopt.md +23 -0
- package/dist/host/agents/skills/orkestrel-publish/references/release.md +4 -4
- package/dist/host/agents/skills/orkestrel-publish/references/wave.md +10 -9
- package/dist/host/agents/skills/orkestrel-publish/references/window.md +20 -25
- package/dist/host/agents/skills/orkestrel-publish/scripts/compare.ts +348 -59
- package/dist/host/agents/skills/orkestrel-publish/scripts/pins.ts +202 -22
- package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +1061 -191
- package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +812 -140
- package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +280 -38
- package/dist/host/agents/skills/orkestrel-scout/SKILL.md +3 -3
- package/dist/host/agents/skills/orkestrel-scout/scripts/map.ts +428 -70
- package/dist/host/agents/templates/brief.md +1 -1
- package/dist/host/agents/transports/claude-cli.md +3 -3
- package/dist/host/agents/transports/codex.md +2 -7
- package/dist/host/agents/transports/cursor.md +2 -3
- package/dist/host/claude/AGENTS.md +2 -2
- package/dist/host/claude/agents/analyst.md +3 -3
- package/dist/host/claude/agents/astra.md +3 -3
- package/dist/host/claude/agents/builder.md +1 -1
- package/dist/host/claude/agents/checker.md +1 -1
- package/dist/host/claude/agents/distiller.md +1 -1
- package/dist/host/claude/agents/grok.md +1 -1
- package/dist/host/claude/agents/opus.md +2 -2
- package/dist/host/claude/agents/orkestrel.md +57 -90
- package/dist/host/claude/agents/researcher.md +1 -1
- package/dist/host/claude/agents/reviewer.md +4 -0
- package/dist/host/claude/agents/scout.md +1 -1
- package/dist/host/claude/agents/verifier.md +1 -1
- package/dist/host/claude/rules/application.md +14 -21
- package/dist/host/claude/rules/architecture.md +34 -44
- package/dist/host/claude/rules/browser.md +3 -4
- package/dist/host/claude/rules/campaign.md +2 -2
- package/dist/host/claude/rules/documentation.md +25 -12
- package/dist/host/claude/rules/names.md +9 -4
- package/dist/host/claude/rules/patterns.md +6 -7
- package/dist/host/claude/rules/portability.md +1 -1
- package/dist/host/claude/rules/quality.md +4 -5
- package/dist/host/claude/rules/styles.md +2 -2
- package/dist/host/claude/rules/tests.md +57 -114
- package/dist/host/claude/rules/typescript.md +7 -9
- package/dist/host/claude/rules/workspace.md +21 -19
- package/dist/host/claude/rules/writing.md +2 -5
- package/dist/host/claude/skills/orkestrel-dispatch/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-harden/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-publish/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-scout/SKILL.md +1 -1
- package/dist/host/codex/agents/analyst.toml +9 -3
- package/dist/host/codex/agents/astra.toml +3 -4
- package/dist/host/codex/agents/builder.toml +1 -1
- package/dist/host/codex/agents/opus.toml +3 -4
- package/dist/host/codex/agents/orkestrel.toml +1 -1
- package/dist/host/codex/agents/researcher.toml +2 -2
- package/dist/host/codex/agents/verifier.toml +1 -1
- package/dist/host/configs/helpers.ts +21 -1
- package/dist/host/configs/policy.ts +299 -15
- package/dist/host/dotfiles/oxlintrc.json +137 -3
- package/dist/host/guides/agent.md +111 -134
- package/dist/host/guides/capture.md +801 -0
- package/dist/host/guides/probe.md +27 -8
- package/dist/host/guides/scaffold.md +96 -18
- package/dist/host/guides/study.md +534 -440
- package/dist/host/guides/test.md +111 -44
- package/dist/host/manifest.json +160 -240
- package/dist/host/tests/config.test.ts +971 -187
- package/dist/host/tests/policy.test.ts +127 -1
- package/dist/host/tests/setupPolicy.ts +893 -33
- package/dist/src/core/index.cjs +214 -86
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +122 -38
- package/dist/src/core/index.d.ts +122 -38
- package/dist/src/core/index.js +209 -85
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +20 -27
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.js +21 -28
- package/dist/src/server/index.js.map +1 -1
- package/package.json +11 -11
- package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +0 -283
- package/dist/host/agents/skills/orkestrel-dispatch/references/bench.md +0 -25
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +0 -333
- package/dist/host/guides/supervisor.md +0 -4890
|
@@ -1,28 +1,172 @@
|
|
|
1
1
|
// Map terrain before a brief, an absorption lane, or a rename. Run from the checkout root:
|
|
2
2
|
// node .agents/skills/orkestrel-scout/scripts/map.ts --tree PATH... [--headings PATH...] [--frontmatter PATH...] [--exports PATH...] [--census TERM...] [--refs PATH] [--anchors PATH...] [--paths a,b] [--ignore-case] [--json] [--out FILE]
|
|
3
3
|
// --tree lists every file under each path with its line count and size. --headings lists every
|
|
4
|
-
// Markdown heading with its line
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// Markdown heading with its line; a heading inside a fenced block is no heading, where a fence
|
|
5
|
+
// opens with a run of three or more backticks or tildes indented up to three spaces and closes with
|
|
6
|
+
// a run of the same character at least as long. --frontmatter lists every key of a Markdown
|
|
7
|
+
// frontmatter block, a TOML file, or a YAML file with its whole value, a nested key dotted under its
|
|
8
|
+
// parents (`interface.default_prompt`) and a TOML key under its table. --exports lists every
|
|
9
|
+
// `export` declaration line in a TypeScript file (a text reading, not the compiler's). --census
|
|
10
|
+
// lists every line carrying a term. --refs lists
|
|
8
11
|
// every line naming a path or its basename. --anchors lists every `§ Heading` reference whose
|
|
9
12
|
// heading the named file, or the same file, does not carry. Walks skip node_modules, .git, dist,
|
|
10
13
|
// tmp, .orkestrel, .idea, and host.json; --paths narrows a census or refs walk. Modes combine, each
|
|
11
14
|
// printing its section; --json prints one object; --out writes the output to FILE instead of the
|
|
12
15
|
// terminal. Give each flag once; a later duplicate is not read. A value that opens with `--` is a
|
|
13
|
-
// missing value, so census a custom property without its leading dashes.
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
// missing value, so census a custom property without its leading dashes. The script refuses a flag
|
|
17
|
+
// it does not read, the `--flag=value` form included, and names every unknown flag and every flag
|
|
18
|
+
// given with no value in one refusal. Exit 0, or 64 when no mode is given, a flag is given with no
|
|
19
|
+
// value, or a flag is unknown.
|
|
20
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, statSync, writeFileSync, } from 'node:fs';
|
|
21
|
+
import { basename, dirname, join } from 'node:path';
|
|
22
|
+
/** Matches an `export` declaration line and captures its kind and name. */
|
|
23
|
+
export const EXPORT = /^export\s+(?:default\s+)?(?:async\s+)?(?:abstract\s+)?(function\*?|const|let|class|interface|type|enum|namespace)\s+([A-Za-z_$][\w$]*)/u;
|
|
24
|
+
/** Matches a Markdown heading line and captures its marker and text. */
|
|
25
|
+
export const HEADING = /^(#{1,6})\s+(.+?)\s*#*\s*$/u;
|
|
26
|
+
/** Matches a `§ Heading` reference, with the backticked Markdown path that may precede it. */
|
|
27
|
+
export const ANCHOR = /(?:`([^`\n]+\.md)`\s*)?§\s*"?([^"`\n|;,.)]+?)"?(?=\s*(?:[,.;)|]|\s(?:and|or|names|fixes|owns|states|binds|governs|decides|before|after)\b|$))/gu;
|
|
28
|
+
/** Matches the extensions of the binary files a walk reads as no text. */
|
|
29
|
+
export const BINARY = /\.(png|jpg|jpeg|gif|webp|ico|woff2?|ttf|otf|eot|zip|tgz|gz|pdf|wasm)$/u;
|
|
30
|
+
/** Matches a line that can open or close a code fence and captures its run of backticks or tildes. */
|
|
31
|
+
export const FENCE = /^ {0,3}(`{3,}|~{3,})/u;
|
|
32
|
+
/** Names the directories a tree walk skips. */
|
|
33
|
+
export const SKIPPED_DIRECTORIES = new Set([
|
|
34
|
+
'node_modules',
|
|
35
|
+
'.git',
|
|
36
|
+
'dist',
|
|
37
|
+
'tmp',
|
|
38
|
+
'.orkestrel',
|
|
39
|
+
'.idea',
|
|
40
|
+
]);
|
|
41
|
+
/** Lists the flags that take a value. */
|
|
42
|
+
export const VALUE_FLAGS = [
|
|
43
|
+
'--tree',
|
|
44
|
+
'--headings',
|
|
45
|
+
'--frontmatter',
|
|
46
|
+
'--exports',
|
|
47
|
+
'--census',
|
|
48
|
+
'--refs',
|
|
49
|
+
'--anchors',
|
|
50
|
+
'--paths',
|
|
51
|
+
'--out',
|
|
52
|
+
];
|
|
53
|
+
/** Lists every flag the script reads, value flags and switches alike. */
|
|
54
|
+
export const FLAGS = [...VALUE_FLAGS, '--ignore-case', '--json'];
|
|
55
|
+
/** Holds the usage line printed when a call names no mode. */
|
|
56
|
+
export const USAGE = 'usage: map.ts [--tree PATH...] [--headings PATH...] [--frontmatter PATH...] [--exports PATH...] [--census TERM...] [--refs PATH] [--anchors PATH...] [--paths a,b] [--ignore-case] [--json] [--out FILE]';
|
|
57
|
+
/**
|
|
58
|
+
* Reads the value that follows a flag.
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* The first occurrence of a flag wins, a following value that opens with `--` is a missing value,
|
|
62
|
+
* and the `--flag=value` form is not read.
|
|
63
|
+
*
|
|
64
|
+
* @param argv - The arguments after the script path.
|
|
65
|
+
* @param name - The flag, such as `--paths`.
|
|
66
|
+
* @returns The value after the flag, or undefined when the flag is absent, last, or followed by
|
|
67
|
+
* another flag.
|
|
68
|
+
*/
|
|
69
|
+
export function readOption(argv, name) {
|
|
70
|
+
const index = argv.indexOf(name);
|
|
71
|
+
const value = index === -1 ? undefined : argv[index + 1];
|
|
72
|
+
return value === undefined || value.startsWith('--') ? undefined : value;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Names the value flags a caller gave with no value.
|
|
76
|
+
*
|
|
77
|
+
* @param argv - The arguments after the script path.
|
|
78
|
+
* @param names - The flags that take a value.
|
|
79
|
+
* @returns Each named flag that appears last or is followed by another flag, in argument order.
|
|
80
|
+
*/
|
|
81
|
+
export function readMissingFlags(argv, names) {
|
|
82
|
+
return names.filter((name) => argv.includes(name) && readOption(argv, name) === undefined);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Names the flags a caller gave that the script does not read.
|
|
86
|
+
*
|
|
87
|
+
* @remarks
|
|
88
|
+
* A `--flag=value` argument is unknown, because the script reads no such form. A bare `--` ends the
|
|
89
|
+
* scan.
|
|
90
|
+
*
|
|
91
|
+
* @param argv - The arguments after the script path.
|
|
92
|
+
* @param flags - Every flag the script reads, value flags and switches alike.
|
|
93
|
+
* @returns Each argument that opens with `--` and is not a read flag, in argument order.
|
|
94
|
+
*/
|
|
95
|
+
export function readUnknownFlags(argv, flags) {
|
|
96
|
+
const end = argv.indexOf('--');
|
|
97
|
+
return (end === -1 ? argv : argv.slice(0, end)).filter((argument) => argument.startsWith('--') && !flags.includes(argument));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reads the values that follow a flag up to the next flag.
|
|
101
|
+
*
|
|
102
|
+
* @param argv - The arguments after the script path.
|
|
103
|
+
* @param name - The flag, such as `--tree`.
|
|
104
|
+
* @returns The values between the flag and the next `--` argument, empty when the flag is absent.
|
|
105
|
+
*/
|
|
106
|
+
export function readList(argv, name) {
|
|
107
|
+
const index = argv.indexOf(name);
|
|
108
|
+
if (index === -1)
|
|
109
|
+
return [];
|
|
110
|
+
const rest = argv.slice(index + 1);
|
|
111
|
+
const end = rest.findIndex((argument) => argument.startsWith('--'));
|
|
112
|
+
return end === -1 ? rest : rest.slice(0, end);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Normalizes a host path to forward slashes.
|
|
116
|
+
*
|
|
117
|
+
* @param path - A host path.
|
|
118
|
+
* @returns The same path with every backslash replaced by a slash.
|
|
119
|
+
*/
|
|
120
|
+
export function normalizeSlashes(path) {
|
|
121
|
+
return path.split('\\').join('/');
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Lists every regular file beneath a directory, skipping the directories the script never reads.
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
127
|
+
* A skipped name matches a directory at any depth, exactly and case-sensitively.
|
|
128
|
+
*
|
|
129
|
+
* @param directory - The directory to walk.
|
|
130
|
+
* @param skipped - The directory names to skip. Default: the skipped directories.
|
|
131
|
+
* @returns Each file's forward-slash path and modification time, in walk order.
|
|
132
|
+
* @throws Thrown when `directory` does not exist or cannot be read.
|
|
133
|
+
*/
|
|
134
|
+
export function listFiles(directory, skipped = SKIPPED_DIRECTORIES) {
|
|
135
|
+
const files = [];
|
|
136
|
+
const pending = [directory];
|
|
137
|
+
while (pending.length > 0) {
|
|
138
|
+
const current = pending.pop();
|
|
139
|
+
if (current === undefined)
|
|
140
|
+
break;
|
|
141
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
142
|
+
if (skipped.has(entry.name))
|
|
143
|
+
continue;
|
|
144
|
+
const path = join(current, entry.name);
|
|
145
|
+
if (entry.isDirectory())
|
|
146
|
+
pending.push(path);
|
|
147
|
+
else if (entry.isFile()) {
|
|
148
|
+
files.push({ path: normalizeSlashes(path), modified: statSync(path).mtimeMs });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return files;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Checks whether a walk reads a file as text.
|
|
156
|
+
*
|
|
157
|
+
* @param path - The file path.
|
|
158
|
+
* @returns True if the path carries no binary extension and is not `host.json`; false otherwise.
|
|
159
|
+
*/
|
|
160
|
+
export function isText(path) {
|
|
23
161
|
return !BINARY.test(path) && basename(path) !== 'host.json';
|
|
24
162
|
}
|
|
25
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Expands paths into the files they name.
|
|
165
|
+
*
|
|
166
|
+
* @param paths - Files and directories; an absent path names nothing.
|
|
167
|
+
* @returns Each file, a directory expanded to the files beneath it.
|
|
168
|
+
*/
|
|
169
|
+
export function expandPaths(paths) {
|
|
26
170
|
return paths.flatMap((path) => {
|
|
27
171
|
if (!existsSync(path))
|
|
28
172
|
return [];
|
|
@@ -31,10 +175,22 @@ function expandPaths(paths) {
|
|
|
31
175
|
return [normalizeSlashes(path)];
|
|
32
176
|
});
|
|
33
177
|
}
|
|
34
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Reads a file as lines.
|
|
180
|
+
*
|
|
181
|
+
* @param path - The file to read.
|
|
182
|
+
* @returns The lines, split on either line ending.
|
|
183
|
+
*/
|
|
184
|
+
export function readLines(path) {
|
|
35
185
|
return readFileSync(path, 'utf8').split(/\r\n|\n/);
|
|
36
186
|
}
|
|
37
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Maps the files beneath paths with their line counts and sizes.
|
|
189
|
+
*
|
|
190
|
+
* @param paths - Files and directories.
|
|
191
|
+
* @returns A row per text file, sorted by path.
|
|
192
|
+
*/
|
|
193
|
+
export function mapTree(paths) {
|
|
38
194
|
return expandPaths(paths)
|
|
39
195
|
.filter(isText)
|
|
40
196
|
.map((path) => {
|
|
@@ -47,13 +203,48 @@ function mapTree(paths) {
|
|
|
47
203
|
})
|
|
48
204
|
.sort((left, right) => left.path.localeCompare(right.path));
|
|
49
205
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Finds the lines that can open or close a code fence.
|
|
208
|
+
*
|
|
209
|
+
* @param lines - The lines of a Markdown file.
|
|
210
|
+
* @returns Each line that opens with up to three spaces and a run of three or more backticks or tildes.
|
|
211
|
+
*/
|
|
212
|
+
export function findFenceLines(lines) {
|
|
213
|
+
return lines.flatMap((text, index) => {
|
|
214
|
+
const run = text.match(FENCE)?.[1];
|
|
215
|
+
return run === undefined ? [] : [{ index, run }];
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Marks the lines that sit inside a code fence.
|
|
220
|
+
*
|
|
221
|
+
* @remarks
|
|
222
|
+
* A fence opens on a run of three or more backticks or tildes, indented up to three spaces, and
|
|
223
|
+
* closes on a run of the same character at least as long; a fence-like line inside an open fence
|
|
224
|
+
* that does not close it is content, and a fence the file never closes runs to its end.
|
|
225
|
+
*
|
|
226
|
+
* @param lines - The lines of a Markdown file.
|
|
227
|
+
* @returns One flag per line: true for the fence lines and the lines between them.
|
|
228
|
+
*/
|
|
229
|
+
export function scanFences(lines) {
|
|
230
|
+
const { open, spans } = findFenceLines(lines).reduce((state, fence) => {
|
|
231
|
+
if (state.open === undefined)
|
|
232
|
+
return { open: fence, spans: state.spans };
|
|
233
|
+
const closes = fence.run.startsWith(state.open.run.charAt(0)) && fence.run.length >= state.open.run.length;
|
|
234
|
+
return closes
|
|
235
|
+
? { open: undefined, spans: [...state.spans, [state.open.index, fence.index]] }
|
|
236
|
+
: state;
|
|
237
|
+
}, { open: undefined, spans: [] });
|
|
238
|
+
const all = open === undefined ? spans : [...spans, [open.index, lines.length - 1]];
|
|
239
|
+
return [...lines.keys()].map((index) => all.some(([first, last]) => index >= first && index <= last));
|
|
55
240
|
}
|
|
56
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Maps the Markdown headings outside code fences.
|
|
243
|
+
*
|
|
244
|
+
* @param paths - Files and directories; only Markdown files are read.
|
|
245
|
+
* @returns A row per heading, its text the marker and the heading text.
|
|
246
|
+
*/
|
|
247
|
+
export function mapHeadings(paths) {
|
|
57
248
|
return expandPaths(paths)
|
|
58
249
|
.filter((candidate) => candidate.endsWith('.md'))
|
|
59
250
|
.flatMap((path) => {
|
|
@@ -69,7 +260,13 @@ function mapHeadings(paths) {
|
|
|
69
260
|
});
|
|
70
261
|
});
|
|
71
262
|
}
|
|
72
|
-
|
|
263
|
+
/**
|
|
264
|
+
* Maps the `export` declaration lines of TypeScript files.
|
|
265
|
+
*
|
|
266
|
+
* @param paths - Files and directories; only TypeScript files are read.
|
|
267
|
+
* @returns A row per declaration, its text the kind and name, or the whole `export * from` line.
|
|
268
|
+
*/
|
|
269
|
+
export function mapExports(paths) {
|
|
73
270
|
return expandPaths(paths)
|
|
74
271
|
.filter((candidate) => /\.[cm]?ts$/u.test(candidate))
|
|
75
272
|
.flatMap((path) => readLines(path).flatMap((text, index) => {
|
|
@@ -82,11 +279,26 @@ function mapExports(paths) {
|
|
|
82
279
|
: [];
|
|
83
280
|
}));
|
|
84
281
|
}
|
|
85
|
-
|
|
282
|
+
/**
|
|
283
|
+
* Builds the predicate a census applies to a line.
|
|
284
|
+
*
|
|
285
|
+
* @param term - The term to find.
|
|
286
|
+
* @param ignoreCase - If true, compares without regard to letter case; if false, compares exactly.
|
|
287
|
+
* @returns A predicate that is true for a line carrying the term.
|
|
288
|
+
*/
|
|
289
|
+
export function buildMatcher(term, ignoreCase) {
|
|
86
290
|
const needle = ignoreCase ? term.toLowerCase() : term;
|
|
87
291
|
return (text) => (ignoreCase ? text.toLowerCase() : text).includes(needle);
|
|
88
292
|
}
|
|
89
|
-
|
|
293
|
+
/**
|
|
294
|
+
* Maps the lines that carry each census term.
|
|
295
|
+
*
|
|
296
|
+
* @param terms - The terms to find.
|
|
297
|
+
* @param roots - The files and directories to read.
|
|
298
|
+
* @param ignoreCase - If true, compares without regard to letter case; if false, compares exactly.
|
|
299
|
+
* @returns The matching lines per term, each line's text trimmed and cut to its first 160 characters.
|
|
300
|
+
*/
|
|
301
|
+
export function mapCensus(terms, roots, ignoreCase) {
|
|
90
302
|
const files = expandPaths(roots).filter(isText);
|
|
91
303
|
return terms.map((term) => {
|
|
92
304
|
const matches = buildMatcher(term, ignoreCase);
|
|
@@ -96,7 +308,14 @@ function mapCensus(terms, roots, ignoreCase) {
|
|
|
96
308
|
};
|
|
97
309
|
});
|
|
98
310
|
}
|
|
99
|
-
|
|
311
|
+
/**
|
|
312
|
+
* Maps the lines that name a path or its basename.
|
|
313
|
+
*
|
|
314
|
+
* @param target - The path to find.
|
|
315
|
+
* @param roots - The files and directories to read; the target file itself is left out.
|
|
316
|
+
* @returns The lines that carry the path or its basename.
|
|
317
|
+
*/
|
|
318
|
+
export function mapRefs(target, roots) {
|
|
100
319
|
const needle = normalizeSlashes(target);
|
|
101
320
|
const name = basename(needle);
|
|
102
321
|
return expandPaths(roots)
|
|
@@ -106,7 +325,14 @@ function mapRefs(target, roots) {
|
|
|
106
325
|
? [{ path, line: index + 1, text: text.trim().slice(0, 160) }]
|
|
107
326
|
: []));
|
|
108
327
|
}
|
|
109
|
-
|
|
328
|
+
/**
|
|
329
|
+
* Classifies the lines of a YAML body.
|
|
330
|
+
*
|
|
331
|
+
* @param lines - The body lines.
|
|
332
|
+
* @param offset - The line number of the first body line.
|
|
333
|
+
* @returns Each non-blank, non-comment line with its indent, content, key, and inline value.
|
|
334
|
+
*/
|
|
335
|
+
export function classifyYamlLines(lines, offset) {
|
|
110
336
|
return lines.flatMap((text, index) => {
|
|
111
337
|
const content = text.trimStart();
|
|
112
338
|
if (content === '' || content.startsWith('#'))
|
|
@@ -123,7 +349,15 @@ function classifyYamlLines(lines, offset) {
|
|
|
123
349
|
];
|
|
124
350
|
});
|
|
125
351
|
}
|
|
126
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Steps the YAML reader over one classified line.
|
|
354
|
+
*
|
|
355
|
+
* @param state - The reader's state before the line.
|
|
356
|
+
* @param line - The classified line.
|
|
357
|
+
* @param position - The line's position among the classified lines.
|
|
358
|
+
* @returns The state after the line; a line with no key leaves it unchanged.
|
|
359
|
+
*/
|
|
360
|
+
export function stepYamlState(state, line, position) {
|
|
127
361
|
if (line.key === undefined)
|
|
128
362
|
return state;
|
|
129
363
|
// Indents strictly increase along the stack, so the entries at or past this indent are the tail.
|
|
@@ -134,7 +368,16 @@ function stepYamlState(state, line, position) {
|
|
|
134
368
|
heads: [...state.heads, { position, line, key }],
|
|
135
369
|
};
|
|
136
370
|
}
|
|
137
|
-
|
|
371
|
+
/**
|
|
372
|
+
* Reads every key of a YAML body with its whole value.
|
|
373
|
+
*
|
|
374
|
+
* @param path - The file the body came from.
|
|
375
|
+
* @param lines - The body lines.
|
|
376
|
+
* @param offset - The line number of the first body line.
|
|
377
|
+
* @returns A row per key, a nested key dotted under its parents and its value extended by the
|
|
378
|
+
* list items and wrapped lines indented under it.
|
|
379
|
+
*/
|
|
380
|
+
export function readYamlKeys(path, lines, offset) {
|
|
138
381
|
const classified = classifyYamlLines(lines, offset);
|
|
139
382
|
const { heads } = classified.reduce((state, line, position) => stepYamlState(state, line, position), { stack: [], heads: [] });
|
|
140
383
|
// A list item, a block scalar line, or a wrapped value extends the key line before it when it is
|
|
@@ -153,7 +396,16 @@ function readYamlKeys(path, lines, offset) {
|
|
|
153
396
|
.trimEnd(),
|
|
154
397
|
}));
|
|
155
398
|
}
|
|
156
|
-
|
|
399
|
+
/**
|
|
400
|
+
* Steps the TOML reader over one line.
|
|
401
|
+
*
|
|
402
|
+
* @param state - The reader's state before the line.
|
|
403
|
+
* @param text - The line.
|
|
404
|
+
* @param path - The file the line came from.
|
|
405
|
+
* @param line - The line's number.
|
|
406
|
+
* @returns The state after the line, with a row added for a key and the table set for a header.
|
|
407
|
+
*/
|
|
408
|
+
export function stepTomlState(state, text, path, line) {
|
|
157
409
|
if (state.fence !== undefined) {
|
|
158
410
|
// The body of a multi-line string carries no key.
|
|
159
411
|
return text.includes(state.fence) ? { ...state, fence: undefined } : state;
|
|
@@ -165,10 +417,10 @@ function stepTomlState(state, text, path, line) {
|
|
|
165
417
|
if (match?.[1] === undefined)
|
|
166
418
|
return state;
|
|
167
419
|
const value = (match[2] ?? '').trim();
|
|
168
|
-
const
|
|
420
|
+
const marker = value.match(/^("""|''')/u)?.[1];
|
|
169
421
|
return {
|
|
170
422
|
table: state.table,
|
|
171
|
-
fence:
|
|
423
|
+
fence: marker !== undefined && value.indexOf(marker, 3) === -1 ? marker : undefined,
|
|
172
424
|
rows: [
|
|
173
425
|
...state.rows,
|
|
174
426
|
{
|
|
@@ -179,10 +431,24 @@ function stepTomlState(state, text, path, line) {
|
|
|
179
431
|
],
|
|
180
432
|
};
|
|
181
433
|
}
|
|
182
|
-
|
|
434
|
+
/**
|
|
435
|
+
* Reads every key of a TOML body with its value.
|
|
436
|
+
*
|
|
437
|
+
* @param path - The file the body came from.
|
|
438
|
+
* @param lines - The body lines.
|
|
439
|
+
* @param offset - The line number of the first body line.
|
|
440
|
+
* @returns A row per key, a key under a table dotted beneath it; a multi-line string's body is no key.
|
|
441
|
+
*/
|
|
442
|
+
export function readTomlKeys(path, lines, offset) {
|
|
183
443
|
return lines.reduce((state, text, index) => stepTomlState(state, text, path, index + offset), { table: '', fence: undefined, rows: [] }).rows;
|
|
184
444
|
}
|
|
185
|
-
|
|
445
|
+
/**
|
|
446
|
+
* Maps the keys of Markdown frontmatter, TOML, and YAML files.
|
|
447
|
+
*
|
|
448
|
+
* @param paths - Files and directories; only Markdown, MDC, TOML, and YAML files are read.
|
|
449
|
+
* @returns A row per key; a Markdown file without a closed frontmatter block gives none.
|
|
450
|
+
*/
|
|
451
|
+
export function mapFrontmatter(paths) {
|
|
186
452
|
return expandPaths(paths)
|
|
187
453
|
.filter((candidate) => /\.(md|mdc|toml|ya?ml)$/u.test(candidate))
|
|
188
454
|
.flatMap((path) => {
|
|
@@ -198,10 +464,23 @@ function mapFrontmatter(paths) {
|
|
|
198
464
|
: readYamlKeys(path, body, offset);
|
|
199
465
|
});
|
|
200
466
|
}
|
|
201
|
-
|
|
467
|
+
/**
|
|
468
|
+
* Reads the heading texts of a Markdown file.
|
|
469
|
+
*
|
|
470
|
+
* @param path - The Markdown file.
|
|
471
|
+
* @returns Each heading's text without its marker, lowercased.
|
|
472
|
+
*/
|
|
473
|
+
export function readHeadingTexts(path) {
|
|
202
474
|
return new Set(mapHeadings([path]).map((row) => row.text.replace(/^#+\s+/u, '').toLowerCase()));
|
|
203
475
|
}
|
|
204
|
-
|
|
476
|
+
/**
|
|
477
|
+
* Maps the `§ Heading` references whose heading their target does not carry.
|
|
478
|
+
*
|
|
479
|
+
* @param paths - Files and directories; only Markdown files are read.
|
|
480
|
+
* @returns A row per unresolved reference. A reference with no backticked path before it targets
|
|
481
|
+
* the file that carries it, and a reference whose target file is absent is unresolved.
|
|
482
|
+
*/
|
|
483
|
+
export function mapAnchors(paths) {
|
|
205
484
|
const citations = expandPaths(paths)
|
|
206
485
|
.filter((candidate) => candidate.endsWith('.md'))
|
|
207
486
|
.flatMap((path) => readLines(path).flatMap((text, index) => [...text.matchAll(ANCHOR)].flatMap((match) => {
|
|
@@ -213,7 +492,13 @@ function mapAnchors(paths) {
|
|
|
213
492
|
const headings = new Map([...new Set(citations.map(({ target }) => target).filter((target) => existsSync(target)))].map((target) => [target, readHeadingTexts(target)]));
|
|
214
493
|
return citations.filter(({ target, heading }) => headings.get(target)?.has(heading.toLowerCase()) !== true);
|
|
215
494
|
}
|
|
216
|
-
|
|
495
|
+
/**
|
|
496
|
+
* Renders a map as text.
|
|
497
|
+
*
|
|
498
|
+
* @param report - The map.
|
|
499
|
+
* @returns One section per mode the map carries, each opened by a `##` heading, ending in a line feed.
|
|
500
|
+
*/
|
|
501
|
+
export function renderReport(report) {
|
|
217
502
|
const { tree, headings, frontmatter, exports, census, refs, anchors } = report;
|
|
218
503
|
const lines = [
|
|
219
504
|
...(tree === undefined
|
|
@@ -251,20 +536,20 @@ function renderReport(report) {
|
|
|
251
536
|
];
|
|
252
537
|
return `${lines.join('\n')}\n`;
|
|
253
538
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
539
|
+
/**
|
|
540
|
+
* Runs the script on its arguments.
|
|
541
|
+
*
|
|
542
|
+
* @param argv - The arguments after the script path.
|
|
543
|
+
* @returns The exit code: 0 on success, 64 on usage.
|
|
544
|
+
*/
|
|
545
|
+
export function main(argv) {
|
|
546
|
+
const unknown = readUnknownFlags(argv, FLAGS);
|
|
547
|
+
const missing = readMissingFlags(argv, VALUE_FLAGS);
|
|
548
|
+
if (unknown.length > 0 || missing.length > 0) {
|
|
549
|
+
console.error(`map: ${[
|
|
550
|
+
...(unknown.length > 0 ? [`${unknown.join(', ')} is not a flag this script reads`] : []),
|
|
551
|
+
...(missing.length > 0 ? [`${missing.join(', ')} given with no value`] : []),
|
|
552
|
+
].join('; ')}; ${USAGE}`);
|
|
268
553
|
return 64;
|
|
269
554
|
}
|
|
270
555
|
const roots = (readOption(argv, '--paths') ?? '.').split(',');
|
|
@@ -284,7 +569,7 @@ function main(argv) {
|
|
|
284
569
|
anchors.length ===
|
|
285
570
|
0 &&
|
|
286
571
|
refs === undefined) {
|
|
287
|
-
console.error(
|
|
572
|
+
console.error(USAGE);
|
|
288
573
|
return 64;
|
|
289
574
|
}
|
|
290
575
|
const report = {
|
|
@@ -307,4 +592,6 @@ function main(argv) {
|
|
|
307
592
|
}
|
|
308
593
|
return 0;
|
|
309
594
|
}
|
|
310
|
-
process.
|
|
595
|
+
if (process.argv[1] !== undefined && realpathSync(process.argv[1]) === import.meta.filename) {
|
|
596
|
+
process.exitCode = main(process.argv.slice(2));
|
|
597
|
+
}
|
|
@@ -27,7 +27,7 @@ UNKNOWN and how the unit reports it.
|
|
|
27
27
|
## Scope
|
|
28
28
|
|
|
29
29
|
- **Owned.** FILES, including the tests that pin the behavior, the fixtures derived from a constant, and the materialized copy of a template.
|
|
30
|
-
- **Shared (report-only).** FILES; return an exact patch.
|
|
30
|
+
- **Shared (report-only).** FILES; return an exact patch as an edit file: one `### <path>` block per edit, each with a `reason:` line and fenced `old:` and `new:` texts, that `.agents/skills/orkestrel-dispatch/scripts/patch.ts` applies.
|
|
31
31
|
- **Off-limits.** FILES. Never list `tmp/probes/` here.
|
|
32
32
|
- **Made false by this change.** FILES, derived by running the suite or by a named search bound.
|
|
33
33
|
- **Tools and limits.** ALLOWED_TOOLS; scoped validation only; no tree-wide source-mutating command. For a verifier, declare each permitted output path per `.agents/orchestration.md` § Permission floor.
|