@orkestrel/scaffold 0.0.103 → 0.0.104

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 (88) hide show
  1. package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +84 -1
  2. package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +21 -6
  3. package/dist/agents/skills/orkestrel-harden/scripts/titles.js +338 -0
  4. package/dist/agents/skills/orkestrel-publish/scripts/swap.js +3 -39
  5. package/dist/agents/skills/orkestrel-publish/scripts/wave.js +433 -47
  6. package/dist/agents/skills/orkestrel-publish/scripts/window.js +2 -1
  7. package/dist/bin/main.js +16 -9
  8. package/dist/bin/main.js.map +1 -1
  9. package/dist/host/agents/orchestration.md +3 -3
  10. package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +2 -2
  11. package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +1 -1
  12. package/dist/host/agents/skills/orkestrel-build/SKILL.md +2 -2
  13. package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +2 -2
  14. package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +1 -1
  15. package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +3 -3
  16. package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +10 -10
  17. package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +1 -0
  18. package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +100 -1
  19. package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +27 -6
  20. package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +4 -4
  21. package/dist/host/agents/skills/orkestrel-falsify/agents/openai.yaml +1 -1
  22. package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +8 -7
  23. package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +6 -6
  24. package/dist/host/agents/skills/orkestrel-harden/SKILL.md +6 -1
  25. package/dist/host/agents/skills/orkestrel-harden/references/bindings.md +1700 -0
  26. package/dist/host/agents/skills/orkestrel-harden/references/contract.md +2 -2
  27. package/dist/host/agents/skills/orkestrel-harden/references/equivalence.md +48 -0
  28. package/dist/host/agents/skills/orkestrel-harden/references/hardening.md +4 -2
  29. package/dist/host/agents/skills/orkestrel-harden/scripts/titles.ts +425 -0
  30. package/dist/host/agents/skills/orkestrel-journey/SKILL.md +2 -2
  31. package/dist/host/agents/skills/orkestrel-journey/references/captures.md +9 -8
  32. package/dist/host/agents/skills/orkestrel-polish/SKILL.md +3 -3
  33. package/dist/host/agents/skills/orkestrel-publish/SKILL.md +2 -2
  34. package/dist/host/agents/skills/orkestrel-publish/references/release.md +1 -0
  35. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +56 -13
  36. package/dist/host/agents/skills/orkestrel-publish/references/window.md +6 -6
  37. package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +5 -49
  38. package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +646 -49
  39. package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +2 -1
  40. package/dist/host/agents/transports/codex.md +1 -1
  41. package/dist/host/claude/agents/orkestrel.md +54 -53
  42. package/dist/host/claude/agents/reviewer.md +4 -4
  43. package/dist/host/claude/rules/documentation.md +2 -1
  44. package/dist/host/claude/rules/patterns.md +1 -1
  45. package/dist/host/claude/rules/quality.md +2 -2
  46. package/dist/host/claude/rules/styles.md +1 -1
  47. package/dist/host/claude/rules/tests.md +34 -8
  48. package/dist/host/claude/rules/typescript.md +29 -0
  49. package/dist/host/claude/rules/workspace.md +32 -22
  50. package/dist/host/claude/rules/writing.md +34 -26
  51. package/dist/host/claude/settings.json +2 -0
  52. package/dist/host/claude/skills/orkestrel-debrief/SKILL.md +1 -1
  53. package/dist/host/claude/skills/orkestrel-falsify/SKILL.md +1 -1
  54. package/dist/host/codex/agents/analyst.toml +3 -3
  55. package/dist/host/codex/agents/reviewer.toml +4 -4
  56. package/dist/host/configs/policy.ts +13 -2
  57. package/dist/host/dotfiles/editorconfig +0 -1
  58. package/dist/host/dotfiles/gitattributes +0 -1
  59. package/dist/host/dotfiles/gitignore +0 -1
  60. package/dist/host/dotfiles/oxlintrc.json +24 -0
  61. package/dist/host/guides/agent.md +1638 -598
  62. package/dist/host/guides/budget.md +89 -29
  63. package/dist/host/guides/form.md +477 -91
  64. package/dist/host/guides/mcp.md +14 -2
  65. package/dist/host/guides/ollama.md +97 -73
  66. package/dist/host/guides/probe.md +1 -1
  67. package/dist/host/guides/scaffold.md +158 -101
  68. package/dist/host/guides/study.md +2635 -0
  69. package/dist/host/guides/table.md +225 -15
  70. package/dist/host/guides/terminal.md +22 -20
  71. package/dist/host/guides/test.md +689 -255
  72. package/dist/host/manifest.json +87 -63
  73. package/dist/host/tests/config.test.ts +136 -82
  74. package/dist/host/tests/policy.test.ts +39 -1
  75. package/dist/host/tests/setupPolicy.ts +86 -28
  76. package/dist/src/core/index.cjs +1387 -611
  77. package/dist/src/core/index.cjs.map +1 -1
  78. package/dist/src/core/index.d.cts +35 -20
  79. package/dist/src/core/index.d.ts +35 -20
  80. package/dist/src/core/index.js +1385 -612
  81. package/dist/src/core/index.js.map +1 -1
  82. package/dist/src/server/index.cjs +12 -12
  83. package/dist/src/server/index.cjs.map +1 -1
  84. package/dist/src/server/index.d.cts +12 -12
  85. package/dist/src/server/index.d.ts +12 -12
  86. package/dist/src/server/index.js +12 -12
  87. package/dist/src/server/index.js.map +1 -1
  88. package/package.json +4 -4
@@ -9,10 +9,20 @@ prepare the next.
9
9
 
10
10
  `scripts/wave.ts --visit` runs these steps in this order and stops at the first one that fails; a
11
11
  step that reads generated or installed state is invalid before the step that writes it. Run a step
12
- by hand only to repair it, then resume with `--from <step>`.
13
-
14
- 1. Re-pin every `@orkestrel` range to the registry caret (peer ranges included) and install, so
15
- the overwrite runs the current vendored host.
12
+ by hand only to repair it, then resume with `--from <step>`. Read a failed step's journal, which
13
+ its row names under the target's `tmp/units/wave/`, before running the step again. Journals and
14
+ overwrite receipts are written only where the work tree ignores `tmp/`.
15
+
16
+ 1. Re-pin every range the audit's release readings name to the caret of its returned release,
17
+ and install before the overwrite. Read the audit population as the declared `@orkestrel`
18
+ dependencies in `dependencies` and `devDependencies`, plus declared foreign tools that the
19
+ blueprint plans in those sections; exclude the fixed showcase tool pair from ordinary release lookups.
20
+ Look up fleet releases with `*`; look up foreign tools with
21
+ a caret over the declared major when one can be extracted, otherwise with the declared range.
22
+ Do not treat a declared minor or patch bound as the lookup bound. Peer-only dependencies produce no release reading;
23
+ rewrite a peer range only when its name shares an audited release reading. For example, with
24
+ peer-only `@orkestrel/peer-only: ^0.0.1`, leave that peer unchanged; with a planned tool whose
25
+ registry serves `8.3.4`, apply `vite: ~8.2.0 -> ^8.3.4` even though the tilde excludes `8.3.4`.
16
26
  2. Commit the manifest and the lockfile as the preparation commit. `scaffold overwrite` refuses a
17
27
  tree carrying uncommitted changes, and the install left both dirty.
18
28
  3. Run `scaffold overwrite`. One run repairs the `AGENTS.md` and `CLAUDE.md` pointers and deletes
@@ -33,17 +43,24 @@ by hand only to repair it, then resume with `--from <step>`.
33
43
  rather than waiving past it.
34
44
  - A copy the target git-ignores stays a `foreign` finding, so that target never reaches exit `0`
35
45
  again. Keep a local MCP server registration outside the repository rather than at `.mcp.json`.
36
- 4. Force-verify every `@orkestrel` range against a registry sweep taken after the previous layer
37
- published.
46
+ 4. Force-verify the same audit population and lookup bounds against a registry sweep taken after
47
+ the previous layer published. Do not infer verification of peer-only declarations from that audit.
38
48
  5. Run the full install. The overwrite re-declares the toolchain ranges and declares each planned
39
49
  dependency the manifest lacks, so the lockfile the first install regenerated no longer matches the
40
50
  manifest.
41
51
  6. Sweep the self-pins, per § Sweep the self-pins: the re-pin moves the snapshot class.
42
52
  7. Run the mutating `format` script to converge generated writes.
43
- 8. Run the quality gates.
44
- 9. Run `node .agents/skills/orkestrel-publish/scripts/compare.ts` to compare the rebuilt `dist/`
45
- against the published tarball for material content. An exit of 2 is an unanswered comparison,
46
- never a moved dist: fetch and re-run rather than ruling a bump owed.
53
+ 8. Commit the overwrite's writes as `Overwrite with scaffold <version>`: every path the overwrite
54
+ wrote or removed, and the manifest and lockfile the install converged. The step refuses a dirty
55
+ path the overwrite did not write and names it. After committing an unrelated path, complete the intended overwrite commit by hand:
56
+ inspect the receipt's written and removed paths, stage those paths and the converged manifest
57
+ and lockfile, and commit them as `Overwrite with scaffold <version>`. Then resume with `--from gates`.
58
+ Treat the receipt as stale after any intervening commit; never use that receipt to authorize
59
+ another `record` commit. Skip this step for an offline overwrite and the `@orkestrel/scaffold` package.
60
+ 9. Run the quality gates.
61
+ 10. Run `node .agents/skills/orkestrel-publish/scripts/compare.ts` to compare the rebuilt `dist/`
62
+ against the published tarball for material content. An exit of 2 is an unanswered comparison,
63
+ never a moved dist: fetch and re-run rather than ruling a bump owed.
47
64
 
48
65
  Restore every pin the target holds with `scripts/swap.ts --restore` before the visit's first step, per
49
66
  [release.md](release.md) § Fix a dependency before it publishes, because the visit reads and
@@ -72,6 +89,30 @@ against that checkout.
72
89
  Run visits in parallel slices of disjoint repositories, each slice strictly serial inside itself,
73
90
  reporting per target. Refuse a failed target, name it, repair it, and re-run it alone.
74
91
 
92
+ ### Regenerate a lock the install cannot move
93
+
94
+ When the install in step 1 or step 5 fails with `ERESOLVE`, read its conflict and rerun command.
95
+ An exact-peer cluster, such as `vitest` with `@vitest/browser-playwright`, can prevent npm from
96
+ moving the lockfile in place. Without the flag, the step deletes nothing.
97
+
98
+ - Pass `--regenerate` only when the user's instruction for the visit names it: the regeneration is a
99
+ destructive command under `.agents/orchestration.md` § Permission floor. A unit whose brief does
100
+ not name it, or whose sandbox refused a deletion, stops at the refusal and reports it.
101
+ - With the flag, refuse before moving anything when `node_modules` is a link, the lockfile is
102
+ untracked or carries uncommitted changes, the manifest names a local dependency spec or declares
103
+ `workspaces`, `tmp/` is not git-ignored, or the target is not the root of its work tree.
104
+ - Validate the backup and journal paths' ancestry and physical containment before writing or moving,
105
+ and revalidate before cleanup. Refuse a linked ancestor while permitting ignored scratch beneath a real target.
106
+ - Otherwise copy the lockfile and move `node_modules` under `tmp/units/wave/<stamp>/`, delete the
107
+ lockfile, install from the manifest, and prove the result: the install exits `0`, the lockfile
108
+ exists, `npm ls --all` exits `0`, and the manifest bytes are unchanged. Read each package named
109
+ by the conflict with its installed version in the step's note. A proved result deletes the moved
110
+ tree; a failed result restores the copied lockfile and moved tree and names why the step failed.
111
+ Confirm a recoverable tree and lock backup before deleting the active tree. Attempt rollback at
112
+ most once. If rollback fails, retain both backup paths for recovery. If completion journaling or
113
+ backup cleanup fails, report that failure and retain the restored or proved installation.
114
+ - Resume a visit that stopped at the refusal with `--regenerate --from <step>`.
115
+
75
116
  ## Rule on the bump
76
117
 
77
118
  Bump on either trigger: `scripts/compare.ts` exits 3 (the rebuilt dist differs materially from the
@@ -100,6 +141,8 @@ registry copy over any staged tip, so every consumer stays red until that tip is
100
141
 
101
142
  ## Prepare a layer
102
143
 
144
+ - When the manifest's `engines.node` names a floor below the `DEFAULT_ENGINES` a generated workspace declares, raise it to that floor and move the package's CI floor row with it.
145
+ - Before the release, rule the package's guide and source comments against `.claude/rules/writing.md` § Substitutions and reword each hit its rows name; identifiers stay.
103
146
  - Compare release packs between hosts by paths, sizes, and content hashes, and report executable-mode differences separately; a pack made on Windows records `0644` for an entry git tracks as `100755`.
104
147
 
105
148
  An unpublished package's first version is `0.0.1`. Do not bump it before that first publish. The
@@ -117,9 +160,9 @@ Prepare a published package's layer in this order, after the visit has ruled the
117
160
  bumped manifest.
118
161
  3. **Sweep the self-pins**, per the following section: the bump moves the version class.
119
162
  4. **Run each package's own `prepublishOnly` script to green.**
120
- When the host npm is below the `MINIMUM_NPM_VERSION` floor a generated workspace declares in
121
- `devEngines`, prepend a local npm 11 install's `node_modules/.bin` to `PATH` for the visit and
122
- this script.
163
+ Run the visit and this script on a Node whose bundled npm meets the `MINIMUM_NPM_VERSION` floor a
164
+ generated workspace declares in `devEngines`: the scripts spawn the npm CLI beside the running
165
+ Node binary when one is there, so a `PATH` change reaches them only where none is.
123
166
  5. **Write the release commit and push before the window opens.** The preparation commit inside
124
167
  the visit is a different commit at a different moment.
125
168
 
@@ -128,7 +128,7 @@ rest of the layer either fits inside it or takes another approval.
128
128
  its own URL.
129
129
  - Relay every new URL to the user the moment it appears, through a journal watcher, and never
130
130
  pause the chain to wait for a click: a poll outlives the relay.
131
- - Tell the user to click only the URL last in log order. A click on a superseded URL poisons the
131
+ - Tell the user to click only the URL last in log order. A click on a superseded URL invalidates the
132
132
  live attempt, and the current poll then fails `403 Forbidden - GET /-/v1/done` mid-flight.
133
133
  § Read a `403` on the poll owns the recovery.
134
134
  - **Never retry a publish that is still waiting for its authorization.** Each `npm publish`
@@ -151,7 +151,7 @@ the same status. Rule from the evidence, never from which cause reads likelier.
151
151
 
152
152
  - Nobody clicked inside the session's life. The poll ran out its 45 seconds against a URL no one
153
153
  opened, and the registry closed the session.
154
- - The user clicked a superseded URL and poisoned the live attempt. The poll fails mid-flight while
154
+ - The user clicked a superseded URL and invalidated the live attempt. The poll fails mid-flight while
155
155
  the user is looking at a page that reports success.
156
156
  - The registry refused the attempt's first poll, seconds after the mint and before anyone could
157
157
  click, because the poll left from an egress address other than the one that minted the session.
@@ -160,7 +160,7 @@ the same status. Rule from the evidence, never from which cause reads likelier.
160
160
  survives its first poll and relaying that one alone, per § Reach the approval.
161
161
  - Tell those causes apart from the log and the user, never from the status alone. A single minted
162
162
  URL that nobody opened in time is the abandon. A log carrying a URL the running attempt
163
- superseded, with the user reporting a click, is the poisoned attempt. A drop within seconds of
163
+ superseded, with the user reporting a click, is the invalidated attempt. A drop within seconds of
164
164
  the mint, before any relay, is the egress refusal.
165
165
  - Recover the same way whichever it was: read the registry for the version, confirm no publish
166
166
  process is live, then mint exactly one fresh attempt with the user at the keyboard.
@@ -178,9 +178,9 @@ the same status. Rule from the evidence, never from which cause reads likelier.
178
178
  status of the pipeline, and a CDN read straight after a publish can still serve the previous
179
179
  version.
180
180
  - Treat a `404` after a first publish as pending rather than failed. A first publish creates the
181
- packument and can serve `404` for minutes after success, so for a package with no prior version
182
- re-read on an interval before reporting either way. A bump serving the old version is CDN lag,
183
- same rule.
181
+ packument and can serve `404` for minutes after success. For a first publish, rerun
182
+ `window.ts --confirm NAME@VERSION` with a `--wait` long enough for a first publish before reporting
183
+ either way. A bump serving the old version is CDN lag, same rule.
184
184
  - Rule on a pack-time manifest-rewriting warning by fetching the registry's copy of the manifest,
185
185
  never by the warning's own text.
186
186
  - Re-read the registry before telling the user a package failed. A chain still running, a retry
@@ -45,18 +45,20 @@ import {
45
45
  readFileSync,
46
46
  realpathSync,
47
47
  renameSync,
48
- rmSync,
49
48
  writeFileSync,
50
49
  } from 'node:fs'
51
50
  import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path'
52
51
  import {
52
+ isRecord,
53
53
  normalizeSlashes,
54
54
  parseJsonRecord,
55
55
  readMissingFlags,
56
56
  readOption,
57
57
  readOptions,
58
58
  readString,
59
+ removeTree,
59
60
  runNpm,
61
+ scanLocalSpecs,
60
62
  } from '../../orkestrel-dispatch/scripts/helpers.ts'
61
63
 
62
64
  type Manifest = Readonly<Record<string, unknown>>
@@ -256,25 +258,6 @@ const OVERRIDE_PRECEDERS: readonly string[] = [
256
258
  'resolutions',
257
259
  ]
258
260
 
259
- // The manifest blocks whose values are dependency specs; `overrides` nests records of them.
260
- const SPEC_BLOCKS: readonly string[] = [
261
- 'dependencies',
262
- 'devDependencies',
263
- 'peerDependencies',
264
- 'optionalDependencies',
265
- 'overrides',
266
- ]
267
-
268
- // npm-package-arg reads a spec as local when it carries a `file:` or `link:` prefix or begins like a
269
- // path: a dot, `~/`, a separator, or a drive letter.
270
- const LOCAL_SPEC_PATTERN = /^(?:file:|link:|\.|~[\\/]|[\\/]|[A-Za-z]:)/iu
271
-
272
- // It also reads a spec as local when the spec ends in an archive extension and carries no protocol...
273
- const ARCHIVE_SPEC_PATTERN = /^[^:]+\.(?:tgz|tar\.gz|tar)$/iu
274
-
275
- // ...unless the spec is a `user/repo` shorthand, which names a hosted repository whatever it ends in.
276
- const SHORTHAND_SPEC_PATTERN = /^[^:@%/\s.-][^:@%/\s]*\/[^:@\s/%]+$/u
277
-
278
261
  // An optional `@scope/` and a name of the characters a registry URL carries untouched; a path
279
262
  // separator beyond the scope's one `/`, an absolute form, and a drive form fall outside it.
280
263
  const PACKAGE_NAME_PATTERN = /^(?:@[A-Za-z0-9~-][A-Za-z0-9._~-]*\/)?[A-Za-z0-9~-][A-Za-z0-9._~-]*$/u
@@ -287,18 +270,6 @@ const USAGE = [
287
270
  ' swap.ts --status --consumer DIR [--json]',
288
271
  ].join('\n')
289
272
 
290
- function isRecord(value: unknown): value is Record<string, unknown> {
291
- return typeof value === 'object' && value !== null && !Array.isArray(value)
292
- }
293
-
294
- function isLocalSpec(spec: string): boolean {
295
- const text = spec.trimStart()
296
- return (
297
- LOCAL_SPEC_PATTERN.test(text) ||
298
- (ARCHIVE_SPEC_PATTERN.test(text) && !SHORTHAND_SPEC_PATTERN.test(text))
299
- )
300
- }
301
-
302
273
  function isPackageName(name: string): boolean {
303
274
  return (
304
275
  name.length <= PACKAGE_NAME_LIMIT && !name.includes('..') && PACKAGE_NAME_PATTERN.test(name)
@@ -899,10 +870,6 @@ function replaceFile(path: string, text: string): void {
899
870
  renameSync(temporary, path)
900
871
  }
901
872
 
902
- function removeTree(path: string): void {
903
- rmSync(path, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })
904
- }
905
-
906
873
  // Vite keys its pre-bundle on the installed version, so a same-version tarball would serve stale bytes.
907
874
  function installConsumer(consumer: string): void {
908
875
  invokeNpm(['install', '--ignore-scripts', '--no-audit', '--no-fund'], consumer)
@@ -1146,22 +1113,11 @@ function readPackedManifest(directory: string): string | undefined {
1146
1113
  // or not a ledger recorded the spec.
1147
1114
  function scanPackedSpecs(source: Source): readonly string[] {
1148
1115
  const manifest = loadPackedManifest(source.directory)
1149
- return SPEC_BLOCKS.flatMap((block) =>
1150
- collectSpecs(block, manifest[block]).flatMap(([path, spec]) =>
1151
- isLocalSpec(spec)
1152
- ? [`${source.name} would pack a local dependency spec: ${path} is ${spec}`]
1153
- : [],
1154
- ),
1116
+ return scanLocalSpecs(manifest).map(
1117
+ ([path, spec]) => `${source.name} would pack a local dependency spec: ${path} is ${spec}`,
1155
1118
  )
1156
1119
  }
1157
1120
 
1158
- // An `overrides` value can nest records, so the path names every key down to the spec.
1159
- function collectSpecs(path: string, value: unknown): ReadonlyArray<readonly [string, string]> {
1160
- if (typeof value === 'string') return [[path, value]]
1161
- if (!isRecord(value)) return []
1162
- return Object.entries(value).flatMap(([key, child]) => collectSpecs(`${path}.${key}`, child))
1163
- }
1164
-
1165
1121
  // A source that carries a ledger of its own has its manifest rewritten to the recorded ranges for the
1166
1122
  // pack and restored byte for byte whether the pack succeeds or throws, so a consumer never receives a
1167
1123
  // tarball spec that resolves only inside the source.