@orkestrel/scaffold 0.0.44 → 0.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/bin/main.js +31 -31
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +7 -2
- package/dist/host/agents/orchestration.md +232 -56
- package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +7 -7
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +11 -9
- package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +3 -3
- package/dist/host/agents/skills/enterprise-bootstrap/references/frontend-design.md +3 -3
- package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +1 -1
- package/dist/host/agents/skills/orkestrel-align-packages/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +8 -8
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +16 -14
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +3 -3
- package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +14 -14
- package/dist/host/agents/skills/orkestrel-harden-package/SKILL.md +1 -1
- package/dist/host/agents/skills/orkestrel-human-journey/SKILL.md +3 -3
- package/dist/host/agents/skills/orkestrel-human-journey/references/captures.md +3 -3
- package/dist/host/agents/skills/orkestrel-human-journey/references/layer.md +3 -3
- package/dist/host/agents/skills/orkestrel-polish-surface/SKILL.md +3 -3
- package/dist/host/claude/agents/analyst.md +2 -2
- package/dist/host/claude/agents/checker.md +2 -2
- package/dist/host/claude/agents/codex.md +5 -5
- package/dist/host/claude/agents/orkestrel.md +9 -8
- package/dist/host/claude/agents/planner.md +1 -1
- package/dist/host/claude/agents/researcher.md +2 -2
- package/dist/host/claude/agents/reviewer.md +1 -1
- package/dist/host/claude/agents/scout.md +2 -2
- package/dist/host/claude/agents/sol.md +3 -3
- package/dist/host/claude/agents/verifier.md +8 -0
- package/dist/host/claude/rules/application.md +7 -7
- package/dist/host/claude/rules/architecture.md +6 -6
- package/dist/host/claude/rules/documentation.md +1 -0
- package/dist/host/claude/rules/patterns.md +3 -3
- package/dist/host/claude/rules/quality.md +3 -3
- package/dist/host/claude/rules/tests.md +9 -2
- package/dist/host/claude/rules/workspace.md +7 -7
- package/dist/host/claude/rules/writing.md +12 -2
- package/dist/host/codex/agents/planner.toml +1 -1
- package/dist/host/configs/helpers.ts +21 -1
- package/dist/host/cursor/rules/orchestration.mdc +1 -1
- package/dist/host/dotfiles/gitignore +4 -1
- package/dist/host/guides/scaffold.md +134 -119
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/host/tests/config.test.ts +40 -1
- package/dist/host/tests/policy.test.ts +2 -2
- package/dist/host/tests/setupPolicy.ts +8 -5
- package/dist/src/core/index.cjs +143 -149
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1624 -1643
- package/dist/src/core/index.d.ts +1624 -1643
- package/dist/src/core/index.js +144 -149
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +82 -97
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +1844 -1871
- package/dist/src/server/index.d.ts +1844 -1871
- package/dist/src/server/index.js +83 -96
- package/dist/src/server/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -39,7 +39,7 @@ var RESERVED_SEGMENT_PATTERN = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9]|conin\$|co
|
|
|
39
39
|
*
|
|
40
40
|
* @remarks
|
|
41
41
|
* Fixed length, unlike the core byte encoding, because a digest is one value of
|
|
42
|
-
* one algorithm rather than a variable run of bytes. Lowercase only, so
|
|
42
|
+
* one algorithm rather than a variable run of bytes. Lowercase only, so separate
|
|
43
43
|
* spellings of one digest can never compare unequal.
|
|
44
44
|
*/
|
|
45
45
|
var DIGEST_PATTERN = /^[0-9a-f]{64}$/;
|
|
@@ -131,7 +131,7 @@ var MANIFEST_NAME = "manifest.json";
|
|
|
131
131
|
* the byte ceiling. The character ceiling is read first so an oversized string is
|
|
132
132
|
* refused before it is split.
|
|
133
133
|
*
|
|
134
|
-
* The
|
|
134
|
+
* The spellings of an empty segment are answered differently. A trailing
|
|
135
135
|
* separator terminates a directory rather than opening a segment, and every
|
|
136
136
|
* supported filesystem and every Node path API reads `project/` and `project` as
|
|
137
137
|
* one location, so it is admitted. A doubled separator is a genuine empty
|
|
@@ -199,7 +199,7 @@ var isDigest = (0, _orkestrel_contract.stringOf)({ pattern: DIGEST_PATTERN });
|
|
|
199
199
|
* composed, and for the same reason: the item count is settled before anything
|
|
200
200
|
* walks the items, and a hostile `length` accessor answers `false` rather than
|
|
201
201
|
* escaping as a throw. It exists beside that guard rather than reusing it
|
|
202
|
-
* because
|
|
202
|
+
* because they bound different things — one bounds what a caller may hand a
|
|
203
203
|
* public method, this one bounds what a checkout may contain.
|
|
204
204
|
*
|
|
205
205
|
* @example
|
|
@@ -367,8 +367,8 @@ var isMaterializerOptions = (0, _orkestrel_contract.recordOf)({
|
|
|
367
367
|
* Narrow a value to the upstream reader's initial listener record.
|
|
368
368
|
*
|
|
369
369
|
* @remarks
|
|
370
|
-
* Closed to the reader's own
|
|
371
|
-
* record is closed to its
|
|
370
|
+
* Closed to the reader's own events for the same reason the materializer's
|
|
371
|
+
* record is closed to its own.
|
|
372
372
|
*/
|
|
373
373
|
var isUpstreamHooks = (0, _orkestrel_contract.recordOf)({
|
|
374
374
|
release: _orkestrel_contract.isFunction,
|
|
@@ -384,7 +384,7 @@ var isUpstreamHooks = (0, _orkestrel_contract.recordOf)({
|
|
|
384
384
|
* the wrong entity is refused rather than ignored. Every numeric leaf is a whole
|
|
385
385
|
* number inside a ceiling: an unbounded concurrency, retry count, response
|
|
386
386
|
* limit, or call budget is a way to exhaust the caller, so the ceiling is stated
|
|
387
|
-
* here rather than left to the reader. The
|
|
387
|
+
* here rather than left to the reader. The byte ceilings are the core
|
|
388
388
|
* artifact and total-artifact limits, because a fetched guide is an artifact and
|
|
389
389
|
* a whole call retains no more than a whole plan.
|
|
390
390
|
*
|
|
@@ -424,7 +424,7 @@ var isUpstreamOptions = (0, _orkestrel_contract.recordOf)({
|
|
|
424
424
|
* @remarks
|
|
425
425
|
* The one place absence is told apart from failure. Every read here answers
|
|
426
426
|
* `undefined` or an empty result for a path that is not there and reports a path
|
|
427
|
-
* that is there but unreadable, so
|
|
427
|
+
* that is there but unreadable, so they must never be read from the same
|
|
428
428
|
* caught value by eye. Total for any caught value, including a hostile one.
|
|
429
429
|
*
|
|
430
430
|
* @example
|
|
@@ -445,7 +445,7 @@ function matchesMissingPath(error) {
|
|
|
445
445
|
* @returns `true` for `.git` and for anything beneath it.
|
|
446
446
|
*
|
|
447
447
|
* @remarks
|
|
448
|
-
* The one home of the `.git` membership rule, read
|
|
448
|
+
* The one home of the `.git` membership rule, read in either direction. A target
|
|
449
449
|
* holding nothing but this directory is still vacant, because a checkout of an
|
|
450
450
|
* empty repository is where a fresh workspace legitimately starts. A path
|
|
451
451
|
* beneath it is never removed and never vendored, because deleting a target's
|
|
@@ -472,11 +472,13 @@ function matchesGitPath(path) {
|
|
|
472
472
|
* @remarks
|
|
473
473
|
* The deletion deny-list, stated as a rule over paths rather than as a list of
|
|
474
474
|
* directories. It is the inversion the contract asks for: the candidate set
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
* because losing history is not a repair,
|
|
478
|
-
*
|
|
479
|
-
*
|
|
475
|
+
* is re-derived from the plan and narrowed by what git tracks, and the audit
|
|
476
|
+
* must agree with that derivation rather than supply the set itself.
|
|
477
|
+
* Repository metadata is protected because losing history is not a repair,
|
|
478
|
+
* and a target's own `src` and `app` trees are protected because a
|
|
479
|
+
* workspace's source is the one thing scaffold never plans and never owns. A
|
|
480
|
+
* plan the compiler emits never maps a protected root, so this guard exists
|
|
481
|
+
* for the caller-authored plan a consumer can still supply.
|
|
480
482
|
*
|
|
481
483
|
* @example
|
|
482
484
|
* ```ts
|
|
@@ -611,7 +613,7 @@ function computeDigest(content) {
|
|
|
611
613
|
* detect a membership edit that did not update it. Order is part of the claim
|
|
612
614
|
* rather than normalized away, because a staged manifest sorts its entries and
|
|
613
615
|
* roots once and a reordered copy is a different file. Each entry is projected
|
|
614
|
-
* to exactly the
|
|
616
|
+
* to exactly the declared fields, so a hand-added property cannot ride
|
|
615
617
|
* into the digest and cannot change it either.
|
|
616
618
|
*
|
|
617
619
|
* @example
|
|
@@ -700,8 +702,8 @@ function isExactCaseFile(path) {
|
|
|
700
702
|
* @returns `true` only for a directory that is not a link.
|
|
701
703
|
*
|
|
702
704
|
* @remarks
|
|
703
|
-
* A junction and a directory symbolic link both report as directories
|
|
704
|
-
* followed, so the inspection deliberately does not follow: a redirected
|
|
705
|
+
* A junction and a directory symbolic link both report as directories after
|
|
706
|
+
* they are followed, so the inspection deliberately does not follow: a redirected
|
|
705
707
|
* directory is refused here rather than silently accepted as the one the caller
|
|
706
708
|
* named.
|
|
707
709
|
*
|
|
@@ -1125,7 +1127,7 @@ function listDirectories(root) {
|
|
|
1125
1127
|
* snapshot all compare as the same digits. The file's identity and size are
|
|
1126
1128
|
* measured before and after the read, and one extra byte is requested past the
|
|
1127
1129
|
* declared size, so a file that grew or was replaced mid-read answers
|
|
1128
|
-
* `undefined` rather than half of
|
|
1130
|
+
* `undefined` rather than half of one file and half of another.
|
|
1129
1131
|
*
|
|
1130
1132
|
* @example
|
|
1131
1133
|
* ```ts
|
|
@@ -1214,7 +1216,7 @@ function readFileText(root, path, limit = _src_core.MAX_ARTIFACT_BYTES) {
|
|
|
1214
1216
|
* The one door from a real directory into the vocabulary an audit compares in.
|
|
1215
1217
|
* Absence is omission rather than an empty value, because core reads a missing
|
|
1216
1218
|
* key as a missing destination and an empty string as a present directory; the
|
|
1217
|
-
*
|
|
1219
|
+
* they are different verdicts. A path that is there but unreadable throws instead
|
|
1218
1220
|
* of being omitted, because omission would report it as missing and a repair
|
|
1219
1221
|
* would then overwrite whatever is actually sitting there.
|
|
1220
1222
|
*
|
|
@@ -1274,7 +1276,7 @@ function readSnapshot(target, paths) {
|
|
|
1274
1276
|
* read, is not the declared shape, or does not match its own membership.
|
|
1275
1277
|
*
|
|
1276
1278
|
* @remarks
|
|
1277
|
-
* The
|
|
1279
|
+
* The failures are held apart deliberately. A host with no manifest is a
|
|
1278
1280
|
* raw checkout, and a caller reads it by mapping each path one to one. A host
|
|
1279
1281
|
* with a manifest that does not verify is a staged host that has been edited,
|
|
1280
1282
|
* and answering `undefined` there would degrade it to that same one-to-one
|
|
@@ -1322,8 +1324,8 @@ function readHostManifest(host) {
|
|
|
1322
1324
|
* package will vendor or carries more bytes than one artifact may.
|
|
1323
1325
|
*
|
|
1324
1326
|
* @remarks
|
|
1325
|
-
* The one place the
|
|
1326
|
-
*
|
|
1327
|
+
* The one place the declared fields are decided together, because they are
|
|
1328
|
+
* readings of one path: {@link pathToStorage} decides where it is stored,
|
|
1327
1329
|
* the destination is the path it answers for, and {@link matchesExecutablePath}
|
|
1328
1330
|
* decides whether a target receives it executable.
|
|
1329
1331
|
*
|
|
@@ -1372,7 +1374,7 @@ function readManifestEntry(destination, source) {
|
|
|
1372
1374
|
* every destination to what the caller observed, and rolls a failed commit back.
|
|
1373
1375
|
* This reads this package's own checkout at build time and fills its own build
|
|
1374
1376
|
* output. Different direction, different lifetime, no consumer target involved,
|
|
1375
|
-
* so
|
|
1377
|
+
* so they do not overlap and neither one belongs inside the other.
|
|
1376
1378
|
*
|
|
1377
1379
|
* Staging is plain rather than transactional for the same reason. A
|
|
1378
1380
|
* `WriteTransaction` exists to hold a directory that already holds work
|
|
@@ -1546,7 +1548,7 @@ function readAnchor(path) {
|
|
|
1546
1548
|
* @remarks
|
|
1547
1549
|
* This binds location rather than history. `true` means the path still resolves
|
|
1548
1550
|
* to the same physical directory on the same device, so the next write lands
|
|
1549
|
-
* where the last one did. A path
|
|
1551
|
+
* where the last one did. A path holding nothing, a file, or a symlink
|
|
1550
1552
|
* answers `false`; a directory swapped in by `rename` also answers `false`
|
|
1551
1553
|
* because the replacement carries its own inode. A directory deleted and made
|
|
1552
1554
|
* again under the same name can receive the old inode back and answers `true`,
|
|
@@ -1617,7 +1619,7 @@ function readExpectation(path) {
|
|
|
1617
1619
|
* Test whether a destination still holds what was captured of it.
|
|
1618
1620
|
*
|
|
1619
1621
|
* @param expectation - The state captured earlier.
|
|
1620
|
-
* @returns `true` when re-reading the destination
|
|
1622
|
+
* @returns `true` when re-reading the destination produces that same state.
|
|
1621
1623
|
*
|
|
1622
1624
|
* @remarks
|
|
1623
1625
|
* Compared field for field against a fresh {@link readExpectation}, so an
|
|
@@ -1678,7 +1680,7 @@ function matchesPrecondition(precondition) {
|
|
|
1678
1680
|
* has not touched the target at all. Commit is the only step that mutates the
|
|
1679
1681
|
* target, and it is the only step that can need rolling back.
|
|
1680
1682
|
*
|
|
1681
|
-
*
|
|
1683
|
+
* A precondition and an expectation hold a destination still. A **precondition** is what the caller
|
|
1682
1684
|
* observed earlier and is checked once, at construction, so a target that moved
|
|
1683
1685
|
* between the caller's read and this transaction fails before anything is
|
|
1684
1686
|
* created. An **expectation** is captured here, at construction, and re-checked
|
|
@@ -1702,7 +1704,7 @@ function matchesPrecondition(precondition) {
|
|
|
1702
1704
|
* elsewhere, or nothing is refused. An ancestor deleted and recreated under
|
|
1703
1705
|
* the same name can receive its old inode back and is indistinguishable here
|
|
1704
1706
|
* from one that never moved.
|
|
1705
|
-
* - **No crash atomicity across destinations.** A process killed between
|
|
1707
|
+
* - **No crash atomicity across destinations.** A process killed between
|
|
1706
1708
|
* promotions leaves the target holding some new files and some old ones, and
|
|
1707
1709
|
* leaves the private root behind. Nothing here is a journal, and the private
|
|
1708
1710
|
* root's name is the only record a later run could read.
|
|
@@ -1835,7 +1837,7 @@ var WriteTransaction = class {
|
|
|
1835
1837
|
* Stage one text file.
|
|
1836
1838
|
*
|
|
1837
1839
|
* @param path - The target-relative path to write.
|
|
1838
|
-
* @param content - The exact UTF-8 text the destination
|
|
1840
|
+
* @param content - The exact UTF-8 text the destination must hold.
|
|
1839
1841
|
* @returns Nothing.
|
|
1840
1842
|
* @throws {@link ScaffoldError} coded `INVALID` when the path is not one this
|
|
1841
1843
|
* transaction opened or is already staged, `TARGET` when the destination holds
|
|
@@ -1867,7 +1869,7 @@ var WriteTransaction = class {
|
|
|
1867
1869
|
*
|
|
1868
1870
|
* @param path - The target-relative path to write.
|
|
1869
1871
|
* @param source - The resolved absolute path to copy the bytes from.
|
|
1870
|
-
* @param executable -
|
|
1872
|
+
* @param executable - If `true`, the destination carries the executable bit; if `false`, it does not.
|
|
1871
1873
|
* @returns Nothing.
|
|
1872
1874
|
* @throws {@link ScaffoldError} coded `INVALID` when the path is not one this
|
|
1873
1875
|
* transaction opened or is already staged, `TARGET` when the destination holds
|
|
@@ -1917,7 +1919,7 @@ var WriteTransaction = class {
|
|
|
1917
1919
|
* created segment is captured by device and inode, so a segment swapped
|
|
1918
1920
|
* underneath the transaction is detected rather than written into.
|
|
1919
1921
|
*/
|
|
1920
|
-
|
|
1922
|
+
establish(path) {
|
|
1921
1923
|
this.#assertOpen();
|
|
1922
1924
|
if (this.#expectation(path).shape === "file") throw new _src_core.ScaffoldError("TARGET", `The destination at ${path} holds a file.`, { path });
|
|
1923
1925
|
const established = (0, _orkestrel_contract.attempt)(() => this.#establish(this.#resolve(this.#target, path)));
|
|
@@ -2180,7 +2182,7 @@ var WriteTransaction = class {
|
|
|
2180
2182
|
* The mutation spine: read the vendored host, re-derive the target, stage, swap.
|
|
2181
2183
|
*
|
|
2182
2184
|
* @remarks
|
|
2183
|
-
* Every verb runs the same
|
|
2185
|
+
* Every verb runs the same steps. It snapshots each caller-supplied value
|
|
2184
2186
|
* and guards the snapshot, so a property backed by an accessor never reaches a
|
|
2185
2187
|
* decision. It re-derives what it is about to touch and compares that against
|
|
2186
2188
|
* the observation the caller handed in, refusing the whole call when anything
|
|
@@ -2403,7 +2405,7 @@ var Materializer = class Materializer {
|
|
|
2403
2405
|
/**
|
|
2404
2406
|
* Rewrite the marker-bounded package table in the target's catalog agent file.
|
|
2405
2407
|
*
|
|
2406
|
-
* @param entries - The published packages the table
|
|
2408
|
+
* @param entries - The published packages the table must list.
|
|
2407
2409
|
* @param target - The directory to write into.
|
|
2408
2410
|
* @returns The catalog path, written when the region's bytes moved and skipped otherwise.
|
|
2409
2411
|
* @throws {@link ScaffoldError} coded `INVALID` when an argument is not the
|
|
@@ -2412,7 +2414,7 @@ var Materializer = class Materializer {
|
|
|
2412
2414
|
* `DESTROYED` after teardown.
|
|
2413
2415
|
*
|
|
2414
2416
|
* @remarks
|
|
2415
|
-
* Only the text between the
|
|
2417
|
+
* Only the text between the markers is replaced, so every word a consumer
|
|
2416
2418
|
* wrote around the table survives the call. A row whose lookup produced no
|
|
2417
2419
|
* version prints the cause it carries instead, because dropping the row would
|
|
2418
2420
|
* hide a package the organization publishes behind one failed request.
|
|
@@ -2426,7 +2428,7 @@ var Materializer = class Materializer {
|
|
|
2426
2428
|
/**
|
|
2427
2429
|
* Rewrite the `@orkestrel/*` range set in the target's manifest.
|
|
2428
2430
|
*
|
|
2429
|
-
* @param dependencies - The names and ranges the manifest
|
|
2431
|
+
* @param dependencies - The names and ranges the manifest must declare.
|
|
2430
2432
|
* @param target - The directory to write into.
|
|
2431
2433
|
* @returns The manifest path, written when a declared range moved and skipped otherwise.
|
|
2432
2434
|
* @throws {@link ScaffoldError} coded `INVALID` when an argument is not the
|
|
@@ -2448,9 +2450,10 @@ var Materializer = class Materializer {
|
|
|
2448
2450
|
return this.#rewrite(directory, "package.json", _src_core.MAX_MANIFEST_BYTES, this.#redeclare(accepted));
|
|
2449
2451
|
}
|
|
2450
2452
|
/**
|
|
2451
|
-
*
|
|
2453
|
+
* Re-derive and delete the tracked files the plan does not own.
|
|
2452
2454
|
*
|
|
2453
|
-
* @param
|
|
2455
|
+
* @param plan - The compiled plan that decides which paths are foreign.
|
|
2456
|
+
* @param audit - The preview returned by this materializer's `audit` method; it must agree with the candidate set this call re-derives.
|
|
2454
2457
|
* @param repository - The target's git state; only a tracked path is ever deleted.
|
|
2455
2458
|
* @param target - The directory to delete from.
|
|
2456
2459
|
* @returns The paths removed.
|
|
@@ -2467,9 +2470,14 @@ var Materializer = class Materializer {
|
|
|
2467
2470
|
* the audit reports, and neither is anything git does not track: git is the
|
|
2468
2471
|
* recovery mechanism, so a path it cannot restore is not one this verb takes.
|
|
2469
2472
|
* A tree carrying uncommitted work is refused whole for the same reason.
|
|
2473
|
+
*
|
|
2474
|
+
* The whole call refuses when the preview disagrees with the re-derivation on
|
|
2475
|
+
* any foreign finding, including one the deletion itself would skip, because a
|
|
2476
|
+
* preview stale anywhere is stale evidence.
|
|
2470
2477
|
*/
|
|
2471
|
-
remove(audit, repository, target) {
|
|
2478
|
+
remove(plan, audit, repository, target) {
|
|
2472
2479
|
this.#assertAlive();
|
|
2480
|
+
const accepted = this.#accept(plan, _src_core.isPlan, "plan");
|
|
2473
2481
|
const preview = this.#accept(audit, _src_core.isAudit, "audit");
|
|
2474
2482
|
const state = this.#accept(repository, isRepository, "repository");
|
|
2475
2483
|
const directory = this.#accept(target, isFilesystemPath, "target");
|
|
@@ -2477,28 +2485,21 @@ var Materializer = class Materializer {
|
|
|
2477
2485
|
target: directory,
|
|
2478
2486
|
dirty: state.dirty.length
|
|
2479
2487
|
});
|
|
2488
|
+
const derived = this.#derive(accepted, directory);
|
|
2489
|
+
this.#reconfirmCandidates(derived.findings, preview.findings, directory);
|
|
2480
2490
|
const tracked = new Set(state.tracked);
|
|
2481
|
-
const observed = /* @__PURE__ */ new Map();
|
|
2482
2491
|
const removals = [];
|
|
2483
2492
|
const skipped = [];
|
|
2484
|
-
for (const finding of
|
|
2493
|
+
for (const finding of derived.findings) {
|
|
2485
2494
|
if (finding.drift !== "foreign") continue;
|
|
2486
2495
|
if (!tracked.has(finding.path) || matchesProtectedPath(finding.path)) {
|
|
2487
2496
|
skipped.push(finding.path);
|
|
2488
2497
|
continue;
|
|
2489
2498
|
}
|
|
2490
|
-
observed.set(finding.path, finding.observed);
|
|
2491
2499
|
removals.push(finding.path);
|
|
2492
2500
|
}
|
|
2493
|
-
const current = readSnapshot(directory, removals);
|
|
2494
2501
|
const preconditions = [];
|
|
2495
|
-
for (const path of removals)
|
|
2496
|
-
if (current[path] !== observed.get(path)) throw this.#error("TARGET", `The path ${path} moved since its audit.`, {
|
|
2497
|
-
target: directory,
|
|
2498
|
-
path
|
|
2499
|
-
});
|
|
2500
|
-
preconditions.push(this.#bind(directory, path, false));
|
|
2501
|
-
}
|
|
2502
|
+
for (const path of removals) preconditions.push(this.#bind(directory, path, false));
|
|
2502
2503
|
return this.#purge(directory, removals, skipped, preconditions);
|
|
2503
2504
|
}
|
|
2504
2505
|
/**
|
|
@@ -2729,6 +2730,35 @@ var Materializer = class Materializer {
|
|
|
2729
2730
|
});
|
|
2730
2731
|
}
|
|
2731
2732
|
}
|
|
2733
|
+
#reconfirmCandidates(derived, preview, target) {
|
|
2734
|
+
const current = derived.filter((finding) => finding.drift === "foreign");
|
|
2735
|
+
const supplied = preview.filter((finding) => finding.drift === "foreign");
|
|
2736
|
+
const candidates = new Map(current.map((finding) => [finding.path, finding]));
|
|
2737
|
+
const previewed = new Map(supplied.map((finding) => [finding.path, finding]));
|
|
2738
|
+
if (candidates.size !== current.length || previewed.size !== supplied.length) throw this.#error("TARGET", "The audit repeats a deletion candidate.", { target });
|
|
2739
|
+
for (const finding of supplied) {
|
|
2740
|
+
const candidate = candidates.get(finding.path);
|
|
2741
|
+
if (candidate === void 0) throw this.#error("TARGET", `The path ${finding.path} is not a deletion candidate for this plan.`, {
|
|
2742
|
+
target,
|
|
2743
|
+
path: finding.path
|
|
2744
|
+
});
|
|
2745
|
+
if (candidate.group !== finding.group) throw this.#error("TARGET", `The path ${finding.path} carries a group this plan does not derive.`, {
|
|
2746
|
+
target,
|
|
2747
|
+
path: finding.path
|
|
2748
|
+
});
|
|
2749
|
+
if (candidate.observed !== finding.observed) throw this.#error("TARGET", `The path ${finding.path} moved since its audit.`, {
|
|
2750
|
+
target,
|
|
2751
|
+
path: finding.path
|
|
2752
|
+
});
|
|
2753
|
+
}
|
|
2754
|
+
for (const finding of current) {
|
|
2755
|
+
if (previewed.has(finding.path)) continue;
|
|
2756
|
+
throw this.#error("TARGET", `The path ${finding.path} is not covered by its audit.`, {
|
|
2757
|
+
target,
|
|
2758
|
+
path: finding.path
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2732
2762
|
#bind(target, path, absent) {
|
|
2733
2763
|
const destination = resolveContainedPath(target, path);
|
|
2734
2764
|
if (destination === void 0) throw this.#error("INVALID", `The path ${path} is off contract or leaves its target.`, {
|
|
@@ -2783,7 +2813,7 @@ var Materializer = class Materializer {
|
|
|
2783
2813
|
const staged = (0, _orkestrel_contract.attempt)(() => {
|
|
2784
2814
|
for (const artifact of writes) if (artifact.origin === "host") this.#copy(transaction, artifact);
|
|
2785
2815
|
else transaction.write(artifact.path, artifact.content);
|
|
2786
|
-
for (const path of directories) transaction.
|
|
2816
|
+
for (const path of directories) transaction.establish(path);
|
|
2787
2817
|
});
|
|
2788
2818
|
const written = this.#close(transaction, staged, target);
|
|
2789
2819
|
for (const path of written) this.#emitter.emit("write", path);
|
|
@@ -2961,7 +2991,7 @@ var Materializer = class Materializer {
|
|
|
2961
2991
|
* This is the package's only network reader, and it never writes. Every call
|
|
2962
2992
|
* opens one byte allowance and spends it across every read the call makes, so a
|
|
2963
2993
|
* caller is bounded twice over: `limit` refuses one oversized answer and
|
|
2964
|
-
* `budget` refuses many small ones.
|
|
2994
|
+
* `budget` refuses many small ones. They are separate exhaustion routes and
|
|
2965
2995
|
* neither bound covers the other.
|
|
2966
2996
|
*
|
|
2967
2997
|
* A per-package failure never escapes as a throw. It is projected into the
|
|
@@ -3017,7 +3047,7 @@ var Upstream = class Upstream {
|
|
|
3017
3047
|
/**
|
|
3018
3048
|
* Construct a reader over one guide host and one registry.
|
|
3019
3049
|
*
|
|
3020
|
-
* @param options - The
|
|
3050
|
+
* @param options - The endpoints, the request bounds, the initial
|
|
3021
3051
|
* listeners, and the listener-error handler.
|
|
3022
3052
|
* @throws {@link ScaffoldError} coded `INVALID` when `options` is present but
|
|
3023
3053
|
* is not an option bag this reader accepts, or when either endpoint names a
|
|
@@ -3027,7 +3057,7 @@ var Upstream = class Upstream {
|
|
|
3027
3057
|
* `isEndpoint` bounds an endpoint's length and nothing else, so the scheme and
|
|
3028
3058
|
* host law is settled here, where a refusal can say which endpoint was refused
|
|
3029
3059
|
* and why. An endpoint must be HTTPS, or HTTP to a loopback host — the one
|
|
3030
|
-
* place an unencrypted request has no network between
|
|
3060
|
+
* place an unencrypted request has no network between its ends. That
|
|
3031
3061
|
* refuses `file:`, `data:`, and plain HTTP to a real host, and it is what
|
|
3032
3062
|
* keeps a fixture reachable without weakening transport security anywhere a
|
|
3033
3063
|
* real request goes. An endpoint carrying credentials, a query, or a fragment
|
|
@@ -3099,7 +3129,7 @@ var Upstream = class Upstream {
|
|
|
3099
3129
|
* always answers for the file it names. `observed` is carried through from
|
|
3100
3130
|
* `current` whatever the lookup produced, because it is the precondition the
|
|
3101
3131
|
* later write is held to and a failed fetch does not change what the target
|
|
3102
|
-
*
|
|
3132
|
+
* holds.
|
|
3103
3133
|
*
|
|
3104
3134
|
* @example
|
|
3105
3135
|
* ```ts
|
|
@@ -3459,49 +3489,6 @@ var Upstream = class Upstream {
|
|
|
3459
3489
|
}
|
|
3460
3490
|
};
|
|
3461
3491
|
//#endregion
|
|
3462
|
-
//#region src/server/factories.ts
|
|
3463
|
-
/**
|
|
3464
|
-
* Construct a {@link Materializer}.
|
|
3465
|
-
*
|
|
3466
|
-
* @param options - The vendored host root, the initial listeners, and the listener-error handler.
|
|
3467
|
-
* @returns The materializer, typed as the contract consumers program against.
|
|
3468
|
-
* @throws {@link ScaffoldError} coded `INVALID` when `options` is present but is
|
|
3469
|
-
* not an option bag the materializer accepts, and `TARGET` when the host carries
|
|
3470
|
-
* a manifest that cannot be read or does not match what it stores.
|
|
3471
|
-
*
|
|
3472
|
-
* @example
|
|
3473
|
-
* ```ts
|
|
3474
|
-
* import { createMaterializer } from '@orkestrel/scaffold/server'
|
|
3475
|
-
*
|
|
3476
|
-
* const materializer = createMaterializer({ host: './dist/host' })
|
|
3477
|
-
* materializer.destroy()
|
|
3478
|
-
* ```
|
|
3479
|
-
*/
|
|
3480
|
-
function createMaterializer(options) {
|
|
3481
|
-
return new Materializer(options);
|
|
3482
|
-
}
|
|
3483
|
-
/**
|
|
3484
|
-
* Construct an {@link Upstream}.
|
|
3485
|
-
*
|
|
3486
|
-
* @param options - The two endpoints, the request bounds, the initial listeners,
|
|
3487
|
-
* and the listener-error handler.
|
|
3488
|
-
* @returns The reader, typed as the contract consumers program against.
|
|
3489
|
-
* @throws {@link ScaffoldError} coded `INVALID` when `options` is present but is
|
|
3490
|
-
* not an option bag the reader accepts, or when either endpoint names a scheme,
|
|
3491
|
-
* host, or form the reader will not request.
|
|
3492
|
-
*
|
|
3493
|
-
* @example
|
|
3494
|
-
* ```ts
|
|
3495
|
-
* import { createUpstream } from '@orkestrel/scaffold/server'
|
|
3496
|
-
*
|
|
3497
|
-
* const upstream = createUpstream({ guides: { branch: 'main' } })
|
|
3498
|
-
* upstream.destroy()
|
|
3499
|
-
* ```
|
|
3500
|
-
*/
|
|
3501
|
-
function createUpstream(options) {
|
|
3502
|
-
return new Upstream(options);
|
|
3503
|
-
}
|
|
3504
|
-
//#endregion
|
|
3505
3492
|
exports.BRANCH_PATTERN = BRANCH_PATTERN;
|
|
3506
3493
|
exports.DIGEST_PATTERN = DIGEST_PATTERN;
|
|
3507
3494
|
exports.DRIVE_PATTERN = DRIVE_PATTERN;
|
|
@@ -3522,8 +3509,6 @@ exports.WriteTransaction = WriteTransaction;
|
|
|
3522
3509
|
exports.computeDigest = computeDigest;
|
|
3523
3510
|
exports.computeFileDigest = computeFileDigest;
|
|
3524
3511
|
exports.computeManifestDigest = computeManifestDigest;
|
|
3525
|
-
exports.createMaterializer = createMaterializer;
|
|
3526
|
-
exports.createUpstream = createUpstream;
|
|
3527
3512
|
exports.isBranch = isBranch;
|
|
3528
3513
|
exports.isCatalogEntries = isCatalogEntries;
|
|
3529
3514
|
exports.isDependencies = isDependencies;
|