@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.
Files changed (157) hide show
  1. package/dist/agents/skills/orkestrel-dispatch/scripts/bench.js +326 -91
  2. package/dist/agents/skills/orkestrel-dispatch/scripts/brief.js +110 -14
  3. package/dist/agents/skills/orkestrel-dispatch/scripts/chain.js +280 -0
  4. package/dist/agents/skills/orkestrel-dispatch/scripts/cite.js +188 -26
  5. package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +142 -43
  6. package/dist/agents/skills/orkestrel-dispatch/scripts/login.js +240 -62
  7. package/dist/agents/skills/orkestrel-dispatch/scripts/patch.js +323 -0
  8. package/dist/agents/skills/orkestrel-dispatch/scripts/result.js +169 -32
  9. package/dist/agents/skills/orkestrel-dispatch/scripts/sweep.js +290 -69
  10. package/dist/agents/skills/orkestrel-falsify/scripts/mutate.js +560 -0
  11. package/dist/agents/skills/orkestrel-harden/scripts/discovery.js +1052 -205
  12. package/dist/agents/skills/orkestrel-harden/scripts/measure.js +361 -0
  13. package/dist/agents/skills/orkestrel-harden/scripts/titles.js +455 -80
  14. package/dist/agents/skills/orkestrel-parallel/scripts/cases.js +327 -0
  15. package/dist/agents/skills/orkestrel-publish/scripts/compare.js +298 -51
  16. package/dist/agents/skills/orkestrel-publish/scripts/pins.js +170 -13
  17. package/dist/agents/skills/orkestrel-publish/scripts/swap.js +956 -191
  18. package/dist/agents/skills/orkestrel-publish/scripts/wave.js +707 -112
  19. package/dist/agents/skills/orkestrel-publish/scripts/window.js +235 -41
  20. package/dist/agents/skills/orkestrel-scout/scripts/map.js +341 -54
  21. package/dist/agents/templates/brief.md +1 -1
  22. package/dist/bin/main.js +51 -46
  23. package/dist/bin/main.js.map +1 -1
  24. package/dist/host/AGENTS.md +23 -21
  25. package/dist/host/agents/orchestration.md +43 -18
  26. package/dist/host/agents/platforms/windows.md +3 -3
  27. package/dist/host/agents/skills/orkestrel-align/SKILL.md +10 -13
  28. package/dist/host/agents/skills/orkestrel-align/references/fleet.md +4 -10
  29. package/dist/host/agents/skills/orkestrel-align/references/integration.md +1 -1
  30. package/dist/host/agents/skills/orkestrel-build/SKILL.md +16 -48
  31. package/dist/host/agents/skills/orkestrel-build/agents/openai.yaml +1 -1
  32. package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +19 -16
  33. package/dist/host/agents/skills/orkestrel-debrief/agents/openai.yaml +1 -1
  34. package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +15 -28
  35. package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +5 -6
  36. package/dist/host/agents/skills/orkestrel-debrief/references/retention.md +4 -6
  37. package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +31 -20
  38. package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +3 -4
  39. package/dist/host/agents/skills/orkestrel-dispatch/scripts/bench.ts +366 -75
  40. package/dist/host/agents/skills/orkestrel-dispatch/scripts/brief.ts +126 -16
  41. package/dist/host/agents/skills/orkestrel-dispatch/scripts/chain.ts +323 -0
  42. package/dist/host/agents/skills/orkestrel-dispatch/scripts/cite.ts +220 -31
  43. package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +176 -33
  44. package/dist/host/agents/skills/orkestrel-dispatch/scripts/login.ts +294 -59
  45. package/dist/host/agents/skills/orkestrel-dispatch/scripts/patch.ts +401 -0
  46. package/dist/host/agents/skills/orkestrel-dispatch/scripts/result.ts +199 -34
  47. package/dist/host/agents/skills/orkestrel-dispatch/scripts/sweep.ts +330 -69
  48. package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +10 -8
  49. package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +1 -5
  50. package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +1 -1
  51. package/dist/host/agents/skills/orkestrel-falsify/scripts/mutate.ts +701 -0
  52. package/dist/host/agents/skills/orkestrel-harden/SKILL.md +16 -12
  53. package/dist/host/agents/skills/orkestrel-harden/references/bindings.md +23 -81
  54. package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +4 -5
  55. package/dist/host/agents/skills/orkestrel-harden/references/contract.md +2 -0
  56. package/dist/host/agents/skills/orkestrel-harden/references/document.md +33 -0
  57. package/dist/host/agents/skills/orkestrel-harden/references/equivalence.md +6 -3
  58. package/dist/host/agents/skills/orkestrel-harden/references/hardening.md +8 -4
  59. package/dist/host/agents/skills/orkestrel-harden/references/research.md +2 -0
  60. package/dist/host/agents/skills/orkestrel-harden/scripts/discovery.ts +1272 -279
  61. package/dist/host/agents/skills/orkestrel-harden/scripts/measure.ts +425 -0
  62. package/dist/host/agents/skills/orkestrel-harden/scripts/titles.ts +603 -98
  63. package/dist/host/agents/skills/orkestrel-journey/SKILL.md +75 -98
  64. package/dist/host/agents/skills/orkestrel-journey/references/captures.md +54 -17
  65. package/dist/host/agents/skills/orkestrel-journey/references/decide.md +1 -20
  66. package/dist/host/agents/skills/orkestrel-journey/references/layer.md +21 -31
  67. package/dist/host/agents/skills/orkestrel-journey/references/styles.md +1 -1
  68. package/dist/host/agents/skills/orkestrel-parallel/SKILL.md +28 -24
  69. package/dist/host/agents/skills/orkestrel-parallel/references/claude.md +15 -13
  70. package/dist/host/agents/skills/orkestrel-parallel/references/codex.md +1 -0
  71. package/dist/host/agents/skills/orkestrel-parallel/references/cursor.md +13 -13
  72. package/dist/host/agents/skills/orkestrel-parallel/scripts/cases.ts +389 -0
  73. package/dist/host/agents/skills/orkestrel-polish/SKILL.md +16 -20
  74. package/dist/host/agents/skills/orkestrel-polish/references/capture-harness.md +16 -26
  75. package/dist/host/agents/skills/orkestrel-publish/SKILL.md +12 -26
  76. package/dist/host/agents/skills/orkestrel-publish/agents/openai.yaml +2 -2
  77. package/dist/host/agents/skills/orkestrel-publish/references/adopt.md +23 -0
  78. package/dist/host/agents/skills/orkestrel-publish/references/release.md +4 -4
  79. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +10 -9
  80. package/dist/host/agents/skills/orkestrel-publish/references/window.md +20 -25
  81. package/dist/host/agents/skills/orkestrel-publish/scripts/compare.ts +348 -59
  82. package/dist/host/agents/skills/orkestrel-publish/scripts/pins.ts +202 -22
  83. package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +1061 -191
  84. package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +812 -140
  85. package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +280 -38
  86. package/dist/host/agents/skills/orkestrel-scout/SKILL.md +3 -3
  87. package/dist/host/agents/skills/orkestrel-scout/scripts/map.ts +428 -70
  88. package/dist/host/agents/templates/brief.md +1 -1
  89. package/dist/host/agents/transports/claude-cli.md +3 -3
  90. package/dist/host/agents/transports/codex.md +2 -7
  91. package/dist/host/agents/transports/cursor.md +2 -3
  92. package/dist/host/claude/AGENTS.md +2 -2
  93. package/dist/host/claude/agents/analyst.md +3 -3
  94. package/dist/host/claude/agents/astra.md +3 -3
  95. package/dist/host/claude/agents/builder.md +1 -1
  96. package/dist/host/claude/agents/checker.md +1 -1
  97. package/dist/host/claude/agents/distiller.md +1 -1
  98. package/dist/host/claude/agents/grok.md +1 -1
  99. package/dist/host/claude/agents/opus.md +2 -2
  100. package/dist/host/claude/agents/orkestrel.md +57 -90
  101. package/dist/host/claude/agents/researcher.md +1 -1
  102. package/dist/host/claude/agents/reviewer.md +4 -0
  103. package/dist/host/claude/agents/scout.md +1 -1
  104. package/dist/host/claude/agents/verifier.md +1 -1
  105. package/dist/host/claude/rules/application.md +14 -21
  106. package/dist/host/claude/rules/architecture.md +34 -44
  107. package/dist/host/claude/rules/browser.md +3 -4
  108. package/dist/host/claude/rules/campaign.md +2 -2
  109. package/dist/host/claude/rules/documentation.md +25 -12
  110. package/dist/host/claude/rules/names.md +9 -4
  111. package/dist/host/claude/rules/patterns.md +6 -7
  112. package/dist/host/claude/rules/portability.md +1 -1
  113. package/dist/host/claude/rules/quality.md +4 -5
  114. package/dist/host/claude/rules/styles.md +2 -2
  115. package/dist/host/claude/rules/tests.md +57 -114
  116. package/dist/host/claude/rules/typescript.md +7 -9
  117. package/dist/host/claude/rules/workspace.md +21 -19
  118. package/dist/host/claude/rules/writing.md +2 -5
  119. package/dist/host/claude/skills/orkestrel-dispatch/SKILL.md +1 -1
  120. package/dist/host/claude/skills/orkestrel-harden/SKILL.md +1 -1
  121. package/dist/host/claude/skills/orkestrel-publish/SKILL.md +1 -1
  122. package/dist/host/claude/skills/orkestrel-scout/SKILL.md +1 -1
  123. package/dist/host/codex/agents/analyst.toml +9 -3
  124. package/dist/host/codex/agents/astra.toml +3 -4
  125. package/dist/host/codex/agents/builder.toml +1 -1
  126. package/dist/host/codex/agents/opus.toml +3 -4
  127. package/dist/host/codex/agents/orkestrel.toml +1 -1
  128. package/dist/host/codex/agents/researcher.toml +2 -2
  129. package/dist/host/codex/agents/verifier.toml +1 -1
  130. package/dist/host/configs/helpers.ts +21 -1
  131. package/dist/host/configs/policy.ts +299 -15
  132. package/dist/host/dotfiles/oxlintrc.json +137 -3
  133. package/dist/host/guides/agent.md +111 -134
  134. package/dist/host/guides/capture.md +801 -0
  135. package/dist/host/guides/probe.md +27 -8
  136. package/dist/host/guides/scaffold.md +96 -18
  137. package/dist/host/guides/study.md +534 -440
  138. package/dist/host/guides/test.md +111 -44
  139. package/dist/host/manifest.json +160 -240
  140. package/dist/host/tests/config.test.ts +971 -187
  141. package/dist/host/tests/policy.test.ts +127 -1
  142. package/dist/host/tests/setupPolicy.ts +893 -33
  143. package/dist/src/core/index.cjs +214 -86
  144. package/dist/src/core/index.cjs.map +1 -1
  145. package/dist/src/core/index.d.cts +122 -38
  146. package/dist/src/core/index.d.ts +122 -38
  147. package/dist/src/core/index.js +209 -85
  148. package/dist/src/core/index.js.map +1 -1
  149. package/dist/src/server/index.cjs +20 -27
  150. package/dist/src/server/index.cjs.map +1 -1
  151. package/dist/src/server/index.js +21 -28
  152. package/dist/src/server/index.js.map +1 -1
  153. package/package.json +11 -11
  154. package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +0 -283
  155. package/dist/host/agents/skills/orkestrel-dispatch/references/bench.md +0 -25
  156. package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +0 -333
  157. package/dist/host/guides/supervisor.md +0 -4890
@@ -1,63 +1,227 @@
1
- // Work the npm authentication window. Run from the checkout root:
2
- // node .agents/skills/orkestrel-publish/scripts/window.ts --whoami [--wait SECONDS]
3
- // node .agents/skills/orkestrel-publish/scripts/window.ts --login [--wait SECONDS]
4
- // node .agents/skills/orkestrel-publish/scripts/window.ts --publish DIR... --otp CODE [--json]
5
- // node .agents/skills/orkestrel-publish/scripts/window.ts --confirm NAME@VERSION... [--wait SECONDS]
6
- // --whoami reads `npm whoami` once, or polls it every 5 seconds until it answers or the wait ends.
7
- // --login prints the command the operator runs in a real terminal (npm offers its approval only to a
8
- // TTY, so no child of this script can hold it), then polls `npm whoami` until it answers or the wait
9
- // ends. --publish refuses linked worktrees and submodules found at a package or its ancestors,
10
- // and names a linked worktree's primary clone.
11
- // It then re-reads `npm whoami` immediately before the first upload and refuses when it
12
- // answers nothing, then runs `npm publish --ignore-scripts --browser=false --otp=CODE` in each
13
- // directory back to back under captured pipes (npm's non-TTY guard turns a refused code into
14
- // EOTP with no prompt, so the path needs no TTY), journals each upload to tmp/units/publish-<name>.log, reads the `+ name@version`
15
- // acceptance line, stops at the first refusal and names the package to resume from, then confirms
16
- // each accepted version against the registry. --confirm re-reads the registry for each name@version every 5
17
- // seconds until it serves the version or the wait (default 120 seconds) ends. Exit 0 when the mode
18
- // succeeded, 3 when it did not, 64 on usage.
19
- import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
1
+ import { spawnSync } from 'node:child_process';
2
+ import { existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
20
3
  import { dirname, join, resolve } from 'node:path';
21
- import { parseJsonRecord, readList, readMissingFlags, readOption, readString, runNpm, } from "../../orkestrel-dispatch/scripts/helpers.js";
22
- const POLL_MS = 5_000;
23
- const ACCEPTED = /^\+ (\S+)@(\S+)\s*$/mu;
24
- function waitFor(ms) {
4
+ /** Holds the milliseconds between two polls of the registry. */
5
+ export const POLL_MS = 5_000;
6
+ /** Matches the acceptance line `npm publish` prints and captures the name and the version. */
7
+ export const ACCEPTED = /^\+ (\S+)@(\S+)\s*$/mu;
8
+ /** Lists every flag the script reads, value flags and switches alike. */
9
+ export const FLAGS = [
10
+ '--whoami',
11
+ '--login',
12
+ '--publish',
13
+ '--confirm',
14
+ '--wait',
15
+ '--otp',
16
+ '--json',
17
+ ];
18
+ /** Holds the usage line the script prints when no mode or two modes were given. */
19
+ export const USAGE = 'usage: window.ts --whoami [--wait SECONDS] | --login [--wait SECONDS] | --publish DIR... --otp CODE [--json] | --confirm NAME@VERSION... [--wait SECONDS]';
20
+ /**
21
+ * Reads the value that follows a flag.
22
+ *
23
+ * @remarks
24
+ * Reads `--flag value` pairs: the first occurrence of a flag wins, a following value that opens
25
+ * with `--` is a missing value, and the `--flag=value` form is not read.
26
+ *
27
+ * @param argv - The arguments after the script path.
28
+ * @param name - The flag, such as `--otp`.
29
+ * @returns The value after the flag, or undefined when the flag is absent, last, or followed by
30
+ * another flag.
31
+ */
32
+ export function readOption(argv, name) {
33
+ const index = argv.indexOf(name);
34
+ const value = index === -1 ? undefined : argv[index + 1];
35
+ return value === undefined || value.startsWith('--') ? undefined : value;
36
+ }
37
+ /**
38
+ * Names the value flags a caller gave with no value.
39
+ *
40
+ * @param argv - The arguments after the script path.
41
+ * @param names - The flags that take a value.
42
+ * @returns Each named flag that appears last or is followed by another flag, in argument order.
43
+ */
44
+ export function readMissingFlags(argv, names) {
45
+ return names.filter((name) => argv.includes(name) && readOption(argv, name) === undefined);
46
+ }
47
+ /**
48
+ * Names the flags a caller gave that the script does not read.
49
+ *
50
+ * @remarks
51
+ * Reads the arguments before a bare `--`, which opens a command a script passes on. A `--flag=value`
52
+ * argument is unknown, because the script reads no such form.
53
+ *
54
+ * @param argv - The arguments after the script path.
55
+ * @param flags - Every flag the script reads, value flags and switches alike.
56
+ * @returns Each argument that opens with `--` and is not a read flag, in argument order.
57
+ */
58
+ export function readUnknownFlags(argv, flags) {
59
+ const end = argv.indexOf('--');
60
+ return (end === -1 ? argv : argv.slice(0, end)).filter((argument) => argument.startsWith('--') && !flags.includes(argument));
61
+ }
62
+ /**
63
+ * Reads the values that follow a flag up to the next flag.
64
+ *
65
+ * @param argv - The arguments after the script path.
66
+ * @param name - The flag, such as `--publish`.
67
+ * @returns The values between the flag and the next `--` argument, empty when the flag is absent.
68
+ */
69
+ export function readList(argv, name) {
70
+ const index = argv.indexOf(name);
71
+ if (index === -1)
72
+ return [];
73
+ const rest = argv.slice(index + 1);
74
+ const end = rest.findIndex((argument) => argument.startsWith('--'));
75
+ return end === -1 ? rest : rest.slice(0, end);
76
+ }
77
+ /**
78
+ * Parses a whole text as one JSON object.
79
+ *
80
+ * @param text - A JSON document, formatted or not, such as a manifest.
81
+ * @returns The parsed object, or undefined when the text is not a JSON object.
82
+ */
83
+ export function parseJsonRecord(text) {
84
+ try {
85
+ const parsed = JSON.parse(text);
86
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
87
+ return Object.fromEntries(Object.entries(parsed));
88
+ }
89
+ }
90
+ catch { }
91
+ return undefined;
92
+ }
93
+ /**
94
+ * Reads a string member of a record.
95
+ *
96
+ * @param record - The record, or undefined.
97
+ * @param key - The member name.
98
+ * @returns The string, or undefined when the member is absent or not a string.
99
+ */
100
+ export function readString(record, key) {
101
+ const value = record?.[key];
102
+ return typeof value === 'string' ? value : undefined;
103
+ }
104
+ /**
105
+ * Resolves the npm command for this host.
106
+ *
107
+ * @remarks
108
+ * The `npm-cli.js` entry beside the running Node binary spawns without a shell on every host; the
109
+ * `npm` shim on Windows is a `.cmd` file that needs one, so that path is the fallback alone.
110
+ *
111
+ * @returns The file to spawn, the arguments that precede npm's own, and whether a shell is needed.
112
+ */
113
+ export function resolveNpm() {
114
+ const cli = join(dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
115
+ if (existsSync(cli))
116
+ return { file: process.execPath, prefix: [cli], shell: false };
117
+ return { file: 'npm', prefix: [], shell: process.platform === 'win32' };
118
+ }
119
+ /**
120
+ * Runs npm with the given arguments and returns the finished child.
121
+ *
122
+ * @param args - The npm arguments, such as `['whoami']`.
123
+ * @param cwd - The working directory. Default: the current directory.
124
+ * @returns The spawn result with `utf8` stdout and stderr.
125
+ */
126
+ export function runNpm(args, cwd) {
127
+ const npm = resolveNpm();
128
+ return spawnSync(npm.file, [...npm.prefix, ...args], {
129
+ encoding: 'utf8',
130
+ windowsHide: true,
131
+ shell: npm.shell,
132
+ maxBuffer: 64 * 1024 * 1024,
133
+ ...(cwd === undefined ? {} : { cwd }),
134
+ });
135
+ }
136
+ /**
137
+ * Waits for a number of milliseconds.
138
+ *
139
+ * @param ms - The delay.
140
+ * @returns A promise that settles after the delay.
141
+ */
142
+ export function waitFor(ms) {
25
143
  return new Promise((settle) => {
26
144
  setTimeout(settle, ms);
27
145
  });
28
146
  }
29
- function readWhoami() {
147
+ /**
148
+ * Reads the account `npm whoami` names once.
149
+ *
150
+ * @returns The user name, or undefined when npm exited nonzero or printed nothing.
151
+ */
152
+ export function readWhoami() {
30
153
  const result = runNpm(['whoami']);
31
154
  const user = result.stdout.trim();
32
155
  return result.status === 0 && user !== '' ? user : undefined;
33
156
  }
34
- async function pollWhoami(waitSeconds, started = Date.now()) {
157
+ /**
158
+ * Polls `npm whoami` until it answers or the wait ends.
159
+ *
160
+ * @param waitSeconds - How long to keep polling; 0 reads once.
161
+ * @param started - The millisecond the polling began. Default: now.
162
+ * @returns The user name, or undefined when none answered within the wait.
163
+ */
164
+ export async function pollWhoami(waitSeconds, started = Date.now()) {
35
165
  const user = readWhoami();
36
166
  if (user !== undefined || Date.now() - started >= waitSeconds * 1000)
37
167
  return user;
38
168
  await waitFor(POLL_MS);
39
169
  return pollWhoami(waitSeconds, started);
40
170
  }
41
- function readServed(name, version) {
171
+ /**
172
+ * Checks whether the registry serves one version of a package.
173
+ *
174
+ * @param name - The package name.
175
+ * @param version - The version.
176
+ * @returns True if `npm view` reads exactly that version; false otherwise.
177
+ */
178
+ export function readServed(name, version) {
42
179
  const result = runNpm(['view', `${name}@${version}`, 'version', '--json']);
43
180
  return result.status === 0 && result.stdout.replace(/["\s]/gu, '') === version;
44
181
  }
45
- async function confirmServed(name, version, waitSeconds, started = Date.now()) {
182
+ /**
183
+ * Polls the registry until it serves one version or the wait ends.
184
+ *
185
+ * @param name - The package name.
186
+ * @param version - The version.
187
+ * @param waitSeconds - How long to keep polling; 0 reads once.
188
+ * @param started - The millisecond the polling began. Default: now.
189
+ * @returns True if the registry served the version within the wait; false otherwise.
190
+ */
191
+ export async function confirmServed(name, version, waitSeconds, started = Date.now()) {
46
192
  const served = readServed(name, version);
47
193
  if (served || Date.now() - started >= waitSeconds * 1000)
48
194
  return served;
49
195
  await waitFor(POLL_MS);
50
196
  return confirmServed(name, version, waitSeconds, started);
51
197
  }
52
- function findGitRoot(directory) {
198
+ /**
199
+ * Finds the nearest directory at or above one that holds a `.git` entry.
200
+ *
201
+ * @param directory - The directory to start from.
202
+ * @returns The nearest directory with a `.git` entry, or the filesystem root when none has one.
203
+ */
204
+ export function findGitRoot(directory) {
53
205
  return existsSync(join(directory, '.git')) || dirname(directory) === directory
54
206
  ? directory
55
207
  : findGitRoot(dirname(directory));
56
208
  }
57
- function readErrorCode(text) {
209
+ /**
210
+ * Reads the error code npm printed.
211
+ *
212
+ * @param text - npm's standard error.
213
+ * @returns The first `E` code in the text, such as `EOTP` or `E401`, or undefined when none appears.
214
+ */
215
+ export function readErrorCode(text) {
58
216
  return text.match(/\b(E[A-Z0-9]{3,}|EOTP|E401|E403|E404)\b/u)?.[1];
59
217
  }
60
- function readManifestName(directory) {
218
+ /**
219
+ * Reads the name and version a directory's package manifest declares.
220
+ *
221
+ * @param directory - The directory that holds `package.json`.
222
+ * @returns The name and version, each undefined when the manifest is absent, unreadable, or lacks it.
223
+ */
224
+ export function readManifestName(directory) {
61
225
  const path = join(directory, 'package.json');
62
226
  if (!existsSync(path))
63
227
  return { name: undefined, version: undefined };
@@ -69,7 +233,15 @@ function readManifestName(directory) {
69
233
  return { name: undefined, version: undefined };
70
234
  }
71
235
  }
72
- function publishPackage(directory, otp) {
236
+ /**
237
+ * Publishes one package directory and journals the upload.
238
+ *
239
+ * @param directory - The package directory.
240
+ * @param otp - The account's one-time code.
241
+ * @returns The upload: accepted when npm exited 0 and printed the acceptance line, else refused with
242
+ * the error code npm named.
243
+ */
244
+ export function publishPackage(directory, otp) {
73
245
  const manifest = readManifestName(directory);
74
246
  const journal = `tmp/units/publish-${(manifest.name ?? directory).replace(/[^A-Za-z0-9.-]+/gu, '-')}.log`;
75
247
  // The refusal code must survive an inherited silent npm log level.
@@ -97,7 +269,16 @@ function publishPackage(directory, otp) {
97
269
  }
98
270
  return upload;
99
271
  }
100
- async function publishAll(directories, otp, waitSeconds) {
272
+ /**
273
+ * Publishes a batch back to back and confirms each accepted version.
274
+ *
275
+ * @param directories - The package directories, in publish order.
276
+ * @param otp - The account's one-time code.
277
+ * @param waitSeconds - How long to wait for the registry to serve each accepted version.
278
+ * @returns One upload per directory published, ending at the first refusal; a directory after it is
279
+ * not published.
280
+ */
281
+ export async function publishAll(directories, otp, waitSeconds) {
101
282
  mkdirSync('tmp/units', { recursive: true });
102
283
  // A step after the first refusal returns the state unchanged, so nothing publishes past it.
103
284
  const { uploads } = directories.reduce((state, directory) => {
@@ -119,7 +300,18 @@ async function publishAll(directories, otp, waitSeconds) {
119
300
  }
120
301
  return confirmed;
121
302
  }
122
- async function main(argv) {
303
+ /**
304
+ * Runs the mode the arguments name.
305
+ *
306
+ * @param argv - The arguments after the script path.
307
+ * @returns The exit code: 0 when the mode succeeded, 3 when it did not, 64 on usage.
308
+ */
309
+ export async function main(argv) {
310
+ const unknown = readUnknownFlags(argv, FLAGS);
311
+ if (unknown.length > 0) {
312
+ console.error(`window: unknown flag ${unknown.join(', ')}; give each flag and its value as separate arguments\n${USAGE}`);
313
+ return 64;
314
+ }
123
315
  const missing = readMissingFlags(argv, ['--wait', '--otp']);
124
316
  if (missing.length > 0) {
125
317
  console.error(`window: ${missing.join(', ')} given with no value`);
@@ -199,20 +391,22 @@ async function main(argv) {
199
391
  console.error('usage: window.ts --confirm NAME@VERSION... [--wait SECONDS]');
200
392
  return 64;
201
393
  }
202
- const readings = [];
394
+ const results = [];
203
395
  for (const target of targets) {
204
396
  const at = target.lastIndexOf('@');
205
- readings.push({
397
+ results.push({
206
398
  target,
207
399
  served: await confirmServed(target.slice(0, at), target.slice(at + 1), wait),
208
400
  });
209
401
  }
210
- console.log(JSON.stringify({ mode: 'confirm', readings }));
211
- return readings.every((reading) => reading.served) ? 0 : 3;
402
+ console.log(JSON.stringify({ mode: 'confirm', results }));
403
+ return results.every((result) => result.served) ? 0 : 3;
212
404
  }
213
- console.error('usage: window.ts --whoami [--wait SECONDS] | --login [--wait SECONDS] | --publish DIR... --otp CODE [--json] | --confirm NAME@VERSION... [--wait SECONDS]');
405
+ console.error(USAGE);
214
406
  return 64;
215
407
  }
216
- main(process.argv.slice(2)).then((code) => {
217
- process.exitCode = code;
218
- });
408
+ if (process.argv[1] !== undefined && realpathSync(process.argv[1]) === import.meta.filename) {
409
+ main(process.argv.slice(2)).then((code) => {
410
+ process.exitCode = code;
411
+ });
412
+ }