@orkestrel/scaffold 0.0.53 → 0.0.55
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/bin/main.js +2 -2
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +1 -0
- package/dist/host/agents/orchestration.md +6 -0
- package/dist/host/claude/agents/orkestrel.md +11 -10
- package/dist/host/claude/rules/architecture.md +11 -0
- package/dist/host/claude/rules/portability.md +98 -0
- package/dist/host/dotfiles/oxlintrc.json +1 -0
- package/dist/host/dotfiles/prettierignore +3 -0
- package/dist/host/guides/scaffold.md +19 -17
- package/dist/host/manifest.json +16 -10
- 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/policy.test.ts +84 -0
- package/dist/host/tests/setupPolicy.ts +540 -4
- package/dist/src/core/index.cjs +10 -10
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.js +10 -10
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.js.map +1 -1
- package/package.json +10 -10
package/dist/host/AGENTS.md
CHANGED
|
@@ -128,6 +128,7 @@ Every file in the following table is a normative extension of this root. Read ev
|
|
|
128
128
|
| `.claude/rules/application.md` | App composition, entries, manifest safety, lifecycle, integration |
|
|
129
129
|
| `.claude/rules/browser.md` | Vue/browser architecture and platform usage |
|
|
130
130
|
| `.claude/rules/styles.md` | SCSS/CSS centralization, tokens, mixins, layers, naming |
|
|
131
|
+
| `.claude/rules/portability.md` | Host branching, paths, line endings, processes, terminals, OS claims |
|
|
131
132
|
| `.claude/rules/documentation.md` | Guides, parity, roadmap, showcase, examples |
|
|
132
133
|
| `.claude/rules/writing.md` | Developer prose: reports, replies, vocabulary, claims, structure |
|
|
133
134
|
| `.claude/rules/quality.md` | Research, dependency reuse, hardening, completion, package inspection |
|
|
@@ -730,6 +730,12 @@ transport.
|
|
|
730
730
|
**When a brief assigns a bench unit a path outside the obvious source tree, name the write limit
|
|
731
731
|
in the brief.** If the sandbox rejects the patch, the unit stops and reports the rejection. Never
|
|
732
732
|
find another write mechanism.
|
|
733
|
+
**A bench unit writes only under its own `--cd` root and the system temporary directory.** A
|
|
734
|
+
report path in the orchestrator's repository is outside both, so the write is rejected after the
|
|
735
|
+
work is already done and the unit improvises a fallback the Orchestrator has to go find. Name the
|
|
736
|
+
report path inside the unit's own tree, or tell the unit to return the report as its final
|
|
737
|
+
message and take it from the `--output-last-message` file. Retention still lands the report in
|
|
738
|
+
`.orkestrel/<package>/` — the Orchestrator copies it there, and the unit never writes it there.
|
|
733
739
|
6. **Ephemeral streams, durable records.** A journal proves a bench is alive and recovers an
|
|
734
740
|
interrupted session. Keep journals under `tmp/`, never commit them, and sweep them at acceptance
|
|
735
741
|
after the final gate evidence is recorded. Durable retention — brief, distillate, verdict,
|
|
@@ -44,26 +44,27 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
44
44
|
| `@orkestrel/abort` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
45
45
|
| `@orkestrel/agent` | `0.0.18` | L5 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.11`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/queue` `^0.0.10`, `@orkestrel/timeout` `^0.0.7`, `@orkestrel/tool` `^0.0.11`, `@orkestrel/workflow` `^0.0.14`, `@orkestrel/workspace` `^0.0.5` |
|
|
46
46
|
| `@orkestrel/brief` | `0.0.6` | L4 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/interpret` `^0.0.11`, `@orkestrel/reason` `^0.0.8` |
|
|
47
|
-
| `@orkestrel/browser` | `0.0.
|
|
47
|
+
| `@orkestrel/browser` | `0.0.14` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/html` `^0.0.7`, `@orkestrel/websocket` `^0.0.10` |
|
|
48
48
|
| `@orkestrel/budget` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
49
|
-
| `@orkestrel/console` | `0.0.
|
|
49
|
+
| `@orkestrel/console` | `0.0.11` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
50
50
|
| `@orkestrel/contract` | `0.0.13` | L0 | |
|
|
51
51
|
| `@orkestrel/csv` | `0.0.5` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
52
52
|
| `@orkestrel/database` | `0.0.12` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/indexeddb` `^0.0.9`, `@orkestrel/sqlite` `^0.0.9` |
|
|
53
53
|
| `@orkestrel/emitter` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
54
54
|
| `@orkestrel/form` | `0.0.3` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
55
|
-
| `@orkestrel/guide` | `0.0.
|
|
56
|
-
| `@orkestrel/html` | `0.0.
|
|
55
|
+
| `@orkestrel/guide` | `0.0.14` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/markdown` `^0.0.11` |
|
|
56
|
+
| `@orkestrel/html` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
57
57
|
| `@orkestrel/indexeddb` | `0.0.9` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
58
58
|
| `@orkestrel/interpret` | `0.0.11` | L3 | `@orkestrel/reason` `^0.0.8`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/template` `^0.0.5` |
|
|
59
|
-
| `@orkestrel/
|
|
60
|
-
| `@orkestrel/
|
|
59
|
+
| `@orkestrel/lsp` | `0.0.3` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/process` `^0.0.6` |
|
|
60
|
+
| `@orkestrel/markdown` | `0.0.12` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/html` `^0.0.7` |
|
|
61
|
+
| `@orkestrel/mcp` | `0.0.25` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/process` `^0.0.6`, `@orkestrel/sse` `^0.0.5`, `@orkestrel/tool` `^0.0.12`, `@orkestrel/websocket` `^0.0.10` |
|
|
61
62
|
| `@orkestrel/middleware` | `0.0.17` | L2 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/timeout` `^0.0.7` |
|
|
62
63
|
| `@orkestrel/msg` | `0.0.8` | L0 | |
|
|
63
64
|
| `@orkestrel/ndjson` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
64
65
|
| `@orkestrel/ollama` | `0.0.12` | L6 | `@orkestrel/agent` `^0.0.18`, `@orkestrel/budget` `^0.0.8`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/ndjson` `^0.0.8`, `@orkestrel/timeout` `^0.0.8`, `@orkestrel/tool` `^0.0.12` |
|
|
65
66
|
| `@orkestrel/pool` | `0.0.8` | L2 | `@orkestrel/emitter` `^0.0.7` |
|
|
66
|
-
| `@orkestrel/probe` | `0.0.
|
|
67
|
+
| `@orkestrel/probe` | `0.0.9` | L4 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/lsp` `^0.0.3`, `@orkestrel/mcp` `^0.0.25`, `@orkestrel/queue` `^0.0.10`, `@orkestrel/timeout` `^0.0.8`, `@orkestrel/tool` `^0.0.12` |
|
|
67
68
|
| `@orkestrel/process` | `0.0.6` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7` |
|
|
68
69
|
| `@orkestrel/program` | `0.0.10` | L4 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/qualifier` `^0.0.11`, `@orkestrel/rater` `^0.0.11`, `@orkestrel/reason` `^0.0.7` |
|
|
69
70
|
| `@orkestrel/qualifier` | `0.0.11` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/reason` `^0.0.7` |
|
|
@@ -72,7 +73,7 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
72
73
|
| `@orkestrel/reason` | `0.0.8` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
73
74
|
| `@orkestrel/relation` | `0.0.10` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.12`, `@orkestrel/emitter` `^0.0.8` |
|
|
74
75
|
| `@orkestrel/router` | `0.0.11` | L2 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.7` |
|
|
75
|
-
| `@orkestrel/scaffold` | `0.0.
|
|
76
|
+
| `@orkestrel/scaffold` | `0.0.54` | L3 | `@orkestrel/console` `^0.0.10`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/markdown` `^0.0.12`, `@orkestrel/process` `^0.0.6`, `@orkestrel/template` `^0.0.5` |
|
|
76
77
|
| `@orkestrel/sea` | `0.0.11` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/process` `^0.0.6` |
|
|
77
78
|
| `@orkestrel/server` | `0.0.15` | L3 | `@orkestrel/abort` `^0.0.8`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/router` `^0.0.11`, `@orkestrel/timeout` `^0.0.8` |
|
|
78
79
|
| `@orkestrel/sqlite` | `0.0.9` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
@@ -80,14 +81,14 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
80
81
|
| `@orkestrel/supervisor` | `0.0.1` | L5 | `@orkestrel/contract` `^0.0.11`, `@orkestrel/database` `^0.0.9`, `@orkestrel/emitter` `^0.0.6`, `@orkestrel/workflow` `^0.0.12` |
|
|
81
82
|
| `@orkestrel/table` | `0.0.3` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
82
83
|
| `@orkestrel/template` | `0.0.5` | L2 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/emitter` `^0.0.8` |
|
|
83
|
-
| `@orkestrel/terminal` | `0.0.
|
|
84
|
+
| `@orkestrel/terminal` | `0.0.13` | L3 | `@orkestrel/console` `^0.0.11`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.12`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/form` `^0.0.3`, `@orkestrel/sse` `^0.0.5` |
|
|
84
85
|
| `@orkestrel/test` | `0.0.11` | L0 | |
|
|
85
86
|
| `@orkestrel/timeout` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
86
87
|
| `@orkestrel/tool` | `0.0.12` | L1 | `@orkestrel/contract` `^0.0.13` |
|
|
87
88
|
| `@orkestrel/toolbox` | `0.0.9` | L6 | `@orkestrel/agent` `^0.0.18`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.11`, `@orkestrel/form` `^0.0.2`, `@orkestrel/relation` `^0.0.9`, `@orkestrel/server` `^0.0.14`, `@orkestrel/terminal` `^0.0.11`, `@orkestrel/tool` `^0.0.11`, `@orkestrel/workflow` `^0.0.14`, `@orkestrel/workspace` `^0.0.5` |
|
|
88
89
|
| `@orkestrel/websocket` | `0.0.10` | L2 | `@orkestrel/emitter` `^0.0.8` |
|
|
89
90
|
| `@orkestrel/worker` | `0.0.9` | L4 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.11`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/pool` `^0.0.8`, `@orkestrel/queue` `^0.0.10` |
|
|
90
|
-
| `@orkestrel/workflow` | `0.0.
|
|
91
|
+
| `@orkestrel/workflow` | `0.0.15` | L4 | `@orkestrel/abort` `^0.0.8`, `@orkestrel/budget` `^0.0.8`, `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.12`, `@orkestrel/emitter` `^0.0.8`, `@orkestrel/queue` `^0.0.10`, `@orkestrel/timeout` `^0.0.8` |
|
|
91
92
|
| `@orkestrel/workspace` | `0.0.6` | L3 | `@orkestrel/contract` `^0.0.13`, `@orkestrel/database` `^0.0.12`, `@orkestrel/emitter` `^0.0.8` |
|
|
92
93
|
|
|
93
94
|
<!-- /orkestrel:catalog -->
|
|
@@ -106,6 +106,17 @@ kind. It reads declaration syntax and file name, never meaning.
|
|
|
106
106
|
no bare collection literal.
|
|
107
107
|
- It proves that no source, test, config, or script file carries an `eslint-disable` or
|
|
108
108
|
`oxlint-disable` directive.
|
|
109
|
+
- It proves that every `.claude/rules/*.md` file has a rule-map row in `AGENTS.md` and that every
|
|
110
|
+
row resolves to a file.
|
|
111
|
+
- It proves the host portability rules that are path- or text-shaped over the populations
|
|
112
|
+
`POLICY_PORTABILITY_GLOB` and `POLICY_PORTABILITY_SOURCE_GLOB` name: no path segment carries a
|
|
113
|
+
Windows reserved device name, a character Windows refuses, a trailing dot or space, or a sibling
|
|
114
|
+
differing only by case; no `package.json` script names a `.sh` file; and no source in the parsed
|
|
115
|
+
population trims a payload before splitting it on `'\n'`, reads `os.EOL`, or imports `EOL` from
|
|
116
|
+
`node:os`.
|
|
117
|
+
- It cannot write a filename the host refuses. A Windows host rejects `<`, folds a case collision
|
|
118
|
+
into one file, and turns `:` into an alternate data stream, so those boundaries are proven from a
|
|
119
|
+
path population rather than from written files.
|
|
109
120
|
- It does not prove a collection is frozen. It reads the declaration, never the value a call
|
|
110
121
|
returns, so `Object.freeze([…])` and any other call initializer are one syntax to it. The freeze
|
|
111
122
|
obligation in the earlier kind-purity rules binds regardless; only the bare literal is mechanical.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- 'src/**/*'
|
|
4
|
+
- 'app/**/*'
|
|
5
|
+
- 'configs/**/*'
|
|
6
|
+
- 'tests/**/*'
|
|
7
|
+
- 'scripts/**/*'
|
|
8
|
+
- 'guides/**/*'
|
|
9
|
+
- 'package.json'
|
|
10
|
+
- '.gitattributes'
|
|
11
|
+
- '.github/workflows/*'
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Host portability rules
|
|
15
|
+
|
|
16
|
+
Published source runs on Windows and Linux. Write one implementation that is correct on each host,
|
|
17
|
+
or gate the host-specific branch on the host that needs it.
|
|
18
|
+
|
|
19
|
+
Take the test half from `.claude/rules/tests.md`: it governs a host-varying property inside a test
|
|
20
|
+
and the form of a conditional skip.
|
|
21
|
+
|
|
22
|
+
## Host branching
|
|
23
|
+
|
|
24
|
+
- Branch on a capability a runtime probe answers — a returned value, a thrown code, a present
|
|
25
|
+
member — wherever the difference is detectable.
|
|
26
|
+
- Branch on `process.platform` only where the behavior is platform-defined, and name that fact in
|
|
27
|
+
the symbol's `@remarks`.
|
|
28
|
+
- Put a platform-literal table — install root, executable suffix, toolchain name — inside a
|
|
29
|
+
`process.platform` branch, and read it on that platform alone.
|
|
30
|
+
- Never flatten a correctly-gated host branch into a single path, and never relax a fail-closed
|
|
31
|
+
check to make one host pass.
|
|
32
|
+
|
|
33
|
+
## Line endings
|
|
34
|
+
|
|
35
|
+
- Split arrived text on `/\r\n|\n/`. Never split on `\n` alone, and never split on a bare `\r`.
|
|
36
|
+
- Split first, then trim each line; trimming the whole payload leaves a `\r` on every line but the
|
|
37
|
+
last.
|
|
38
|
+
- Frame a named protocol — HTTP, LSP, RFC 6455, NDJSON — with the terminator that protocol fixes,
|
|
39
|
+
and leave that terminator alone.
|
|
40
|
+
- Emit `\n` from code this package owns. Never emit `os.EOL`.
|
|
41
|
+
|
|
42
|
+
## Paths
|
|
43
|
+
|
|
44
|
+
- Normalize each operand of a path comparison with the same normalizer before comparing.
|
|
45
|
+
- Never case-fold a containment check. Fold a lookup key only by the file-name case sensitivity the
|
|
46
|
+
consumer declares, and fold the whole key when you fold at all.
|
|
47
|
+
- Compose, split, and relativize a host path with `node:path`. Never concatenate a separator
|
|
48
|
+
literal.
|
|
49
|
+
- Keep a storage key, an archive key, and a URI path slash-separated, and refuse `\` and a drive
|
|
50
|
+
prefix inside one.
|
|
51
|
+
- Refuse the Windows reserved device names and the filename characters Windows rejects, on every
|
|
52
|
+
host.
|
|
53
|
+
- Read the temporary directory from `os.tmpdir()`. Never write a `/tmp` literal in source.
|
|
54
|
+
- Build a `file:` URI with `pathToFileURL`. Never format one from a path string.
|
|
55
|
+
|
|
56
|
+
## Processes and executables
|
|
57
|
+
|
|
58
|
+
- Resolve, spawn, and terminate a child through `@orkestrel/process` where the package declares it.
|
|
59
|
+
- Where it is not declared, spawn `process.execPath` with a JavaScript entry. Never spawn a `.bin`
|
|
60
|
+
shim, and never add `shell: true` to reach one.
|
|
61
|
+
- Take a resolver's first match only after splitting its output into lines and trimming each one.
|
|
62
|
+
`where` prints a match per line and can name a file that is not an executable.
|
|
63
|
+
- Treat `fs.constants.X_OK` as an existence check on Windows, where `accessSync` passes on a plain
|
|
64
|
+
file. Confirm an executable by its name and its file type instead.
|
|
65
|
+
- Read an `fs.constants` member before putting it in a flag word. Windows leaves `O_NOFOLLOW`
|
|
66
|
+
undefined, so `O_WRONLY | O_NOFOLLOW` refuses nothing there. Never polyfill the missing member:
|
|
67
|
+
compensate with a check the host supports, or record the limit.
|
|
68
|
+
- Read `PROGRAMFILES`, `LOCALAPPDATA`, and `APPDATA` inside the win32 branch and `HOME` inside the
|
|
69
|
+
POSIX branch. Never read one host's root on the other.
|
|
70
|
+
- Terminate a Windows child by its process tree. A `SIGTERM` handler never runs there, so gate every
|
|
71
|
+
cooperative-shutdown path on POSIX.
|
|
72
|
+
- Treat a permission bit as advisory on Windows: a written mode does not round-trip
|
|
73
|
+
(`chmodSync(dir, 0o500)` reads back `0444` there), so assert modes only where a probe reports they
|
|
74
|
+
round-trip.
|
|
75
|
+
- Retry an `EBUSY`, `ENOTEMPTY`, or `EPERM` removal inside a bounded budget, and report the failure
|
|
76
|
+
when the budget ends.
|
|
77
|
+
|
|
78
|
+
## Terminals
|
|
79
|
+
|
|
80
|
+
- Gate styling and interactivity on `isTTY`, `NO_COLOR`, and `FORCE_COLOR`, never on the platform.
|
|
81
|
+
- Decode `\r`, `\n`, and `\r\n` from a key stream as the same key.
|
|
82
|
+
- Never call a Windows console-mode API. Node exposes none, so record the unreached behavior as a
|
|
83
|
+
limit.
|
|
84
|
+
|
|
85
|
+
## Scripts and packaging
|
|
86
|
+
|
|
87
|
+
- Write every `package.json` script as a portable command: a Node invocation or an installed binary.
|
|
88
|
+
Never name a `.sh` file there.
|
|
89
|
+
- Keep `#!/usr/bin/env node` on an npm bin. npm writes the Windows shim from it.
|
|
90
|
+
- Keep an agent hook under `scripts/` in bash, and keep `.gitattributes` `eol=lf`.
|
|
91
|
+
|
|
92
|
+
## Claims
|
|
93
|
+
|
|
94
|
+
- Never describe the suite, the host, or CI as POSIX. Name the host and the date behind a reading.
|
|
95
|
+
- Run the gate chain on each host a change claims, and record a reading that could not run as a
|
|
96
|
+
limit naming the host it needs.
|
|
97
|
+
- Keep a POSIX-shaped `file:///` literal in a guide only as an opaque fictional identifier. Build
|
|
98
|
+
any example a reader executes with `pathToFileURL`.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
|
|
3
|
+
"ignorePatterns": [".orkestrel/"],
|
|
3
4
|
"plugins": ["import", "typescript", "vitest"],
|
|
4
5
|
"jsPlugins": [{ "name": "policy", "specifier": "./configs/policy.ts" }],
|
|
5
6
|
"rules": {
|
|
@@ -456,16 +456,18 @@ package distributes; each operation reports one baseline word per surface. A sur
|
|
|
456
456
|
`floor` only where the package distributes a copy. The registry's organization membership ships
|
|
457
457
|
nowhere, so `catalog` refuses when that read fails.
|
|
458
458
|
|
|
459
|
-
For `new`, `repair`, `catalog`, and `overwrite`, authoritative absence
|
|
460
|
-
registry `404` or a packument with no admitted version stays a `FETCH` refusal,
|
|
461
|
-
version the registry says is absent produces an uninstallable manifest. `audit`
|
|
462
|
-
absence into questions and returns its audit result. Transport faults, timeouts, rate
|
|
463
|
-
byte-bound refusals, and integrity refusals can select the floor.
|
|
464
|
-
|
|
465
|
-
The guide surface is the per-row exception to whole-surface fallback
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
459
|
+
For `new`, `repair`, `catalog`, and `overwrite`, authoritative absence on a version surface never
|
|
460
|
+
selects `floor`. A registry `404` or a packument with no admitted version stays a `FETCH` refusal,
|
|
461
|
+
because writing a version the registry says is absent produces an uninstallable manifest. `audit`
|
|
462
|
+
turns release absence into questions and returns its audit result. Transport faults, timeouts, rate
|
|
463
|
+
refusals, byte-bound refusals, and integrity refusals can select the floor.
|
|
464
|
+
|
|
465
|
+
The guide surface is the per-row exception to whole-surface fallback, for absence as well as for
|
|
466
|
+
faults. A foreign guide the host could not serve — a failed read, or the `404` a published package
|
|
467
|
+
with a private repository answers with — keeps the target's existing mirror as its floor, while the
|
|
468
|
+
other guide rows can still update. When at least one selected guide keeps its mirror,
|
|
469
|
+
`provenance.guides` is `floor` for the result; it is `live` only when every selected guide resolved
|
|
470
|
+
live.
|
|
469
471
|
|
|
470
472
|
A value `Host` can carry live host-owned bytes beside installed floor bytes for deferred guide and
|
|
471
473
|
catalog paths. Each surface still contributes one baseline. Deferred paths are presence-only, and
|
|
@@ -1096,13 +1098,13 @@ Each verb resolves a surface's complete answer before it opens that surface's wr
|
|
|
1096
1098
|
a partial answer never becomes a partial pin set. `overwrite` keeps the repair and removal work it
|
|
1097
1099
|
committed before a later catalog refusal and records that refusal in `note`.
|
|
1098
1100
|
|
|
1099
|
-
| Verb | Reads live | When the network forces a floor
|
|
1100
|
-
| ----------- | ---------------------------------------------------------------- |
|
|
1101
|
-
| `new` | Declared versions and the vendored host | Writes the distributed version and host floors; exits `0` after creating the workspace
|
|
1102
|
-
| `audit` | Declared versions and the vendored host | Compares through the distributed floors and exits `1`
|
|
1103
|
-
| `repair` | Declared versions and the vendored host | Repairs from the distributed floors and exits `1`, even when the terminal audit is aligned
|
|
1104
|
-
| `catalog` | Organization membership, its packuments, and the selected guides | Refuses a membership or version failure with `FETCH` and exit `1`; preserves each failed
|
|
1105
|
-
| `overwrite` | Everything `repair` and `catalog` read | Keeps completed repair and deletion work, names each floor or refused catalog step in `note`, and exits `1`
|
|
1101
|
+
| Verb | Reads live | When the network forces a floor | With `--offline` |
|
|
1102
|
+
| ----------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
1103
|
+
| `new` | Declared versions and the vendored host | Writes the distributed version and host floors; exits `0` after creating the workspace | Reads no upstream surface, writes the same floors, and exits `0` after creating the workspace |
|
|
1104
|
+
| `audit` | Declared versions and the vendored host | Compares through the distributed floors and exits `1` | Compares through the floors; exits `0` for an aligned target or `1` for drift |
|
|
1105
|
+
| `repair` | Declared versions and the vendored host | Repairs from the distributed floors and exits `1`, even when the terminal audit is aligned | Repairs from the floors; the terminal audit decides exit `0` or `1` |
|
|
1106
|
+
| `catalog` | Organization membership, its packuments, and the selected guides | Refuses a membership or version failure with `FETCH` and exit `1`; preserves the local mirror of each guide that failed or is absent upstream and exits `1` | Is a usage error; exits `2` and writes nothing |
|
|
1107
|
+
| `overwrite` | Everything `repair` and `catalog` read | Keeps completed repair and deletion work, names each floor or refused catalog step in `note`, and exits `1` | Repairs, deletes, and writes version floors; skips `catalog`, records that refusal in `note`, and exits `1` |
|
|
1106
1108
|
|
|
1107
1109
|
A fleet row is compared exactly — `^0.1.0` is stale the moment the registry serves `0.1.2` — and
|
|
1108
1110
|
that inequality alone raises `audit` to exit `1`. A foreign row is compared inside its declared
|
package/dist/host/manifest.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"storage": "AGENTS.md",
|
|
5
5
|
"destination": "AGENTS.md",
|
|
6
6
|
"executable": false,
|
|
7
|
-
"digest": "
|
|
7
|
+
"digest": "43ce847aa96a525919dbe948a2311214c312d58069054800577e5aff89024f08"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"storage": "CLAUDE.md",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"storage": "agents/orchestration.md",
|
|
23
23
|
"destination": ".agents/orchestration.md",
|
|
24
24
|
"executable": false,
|
|
25
|
-
"digest": "
|
|
25
|
+
"digest": "db4414f1dc8eb2cc9e96cb920f08946d4be2507b081866839fea4112949b7505"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"storage": "agents/skills/enterprise-bootstrap/SKILL.md",
|
|
@@ -310,7 +310,7 @@
|
|
|
310
310
|
"storage": "claude/agents/orkestrel.md",
|
|
311
311
|
"destination": ".claude/agents/orkestrel.md",
|
|
312
312
|
"executable": false,
|
|
313
|
-
"digest": "
|
|
313
|
+
"digest": "eacfb94cd758ed202aba25ac759420223bae1e624a7baf208feaeb9c979e3c9f"
|
|
314
314
|
},
|
|
315
315
|
{
|
|
316
316
|
"storage": "claude/agents/planner.md",
|
|
@@ -358,7 +358,7 @@
|
|
|
358
358
|
"storage": "claude/rules/architecture.md",
|
|
359
359
|
"destination": ".claude/rules/architecture.md",
|
|
360
360
|
"executable": false,
|
|
361
|
-
"digest": "
|
|
361
|
+
"digest": "674bcc17f8127948e11391cbbedfd7396911d88c0e99cfefe718f718ed06a333"
|
|
362
362
|
},
|
|
363
363
|
{
|
|
364
364
|
"storage": "claude/rules/browser.md",
|
|
@@ -384,6 +384,12 @@
|
|
|
384
384
|
"executable": false,
|
|
385
385
|
"digest": "c128dace792fcc042446f3d35dce90ef3918d44449a424dbd6dcea4dfcab24f5"
|
|
386
386
|
},
|
|
387
|
+
{
|
|
388
|
+
"storage": "claude/rules/portability.md",
|
|
389
|
+
"destination": ".claude/rules/portability.md",
|
|
390
|
+
"executable": false,
|
|
391
|
+
"digest": "b948c92e3409efd01b45ed9e8d917f4713cda0ecd5ea343932613b2977a614ff"
|
|
392
|
+
},
|
|
387
393
|
{
|
|
388
394
|
"storage": "claude/rules/quality.md",
|
|
389
395
|
"destination": ".claude/rules/quality.md",
|
|
@@ -628,13 +634,13 @@
|
|
|
628
634
|
"storage": "dotfiles/oxlintrc.json",
|
|
629
635
|
"destination": ".oxlintrc.json",
|
|
630
636
|
"executable": false,
|
|
631
|
-
"digest": "
|
|
637
|
+
"digest": "c2d9715f5db07992601cf764532c9d9c7b11177a366d46d767ce07f50f49acad"
|
|
632
638
|
},
|
|
633
639
|
{
|
|
634
640
|
"storage": "dotfiles/prettierignore",
|
|
635
641
|
"destination": ".prettierignore",
|
|
636
642
|
"executable": false,
|
|
637
|
-
"digest": "
|
|
643
|
+
"digest": "6f8bd3b8a192c974ae6332f017c2e76179d15e2598fbd624f7cd4e9e57156ff2"
|
|
638
644
|
},
|
|
639
645
|
{
|
|
640
646
|
"storage": "guides/guide.md",
|
|
@@ -646,7 +652,7 @@
|
|
|
646
652
|
"storage": "guides/scaffold.md",
|
|
647
653
|
"destination": "guides/scaffold.md",
|
|
648
654
|
"executable": false,
|
|
649
|
-
"digest": "
|
|
655
|
+
"digest": "4b6e503d74188118ebba5ff4c9d76d9c9a933c0aec055ae600e02540e73c8c57"
|
|
650
656
|
},
|
|
651
657
|
{
|
|
652
658
|
"storage": "scripts/codex.sh",
|
|
@@ -682,13 +688,13 @@
|
|
|
682
688
|
"storage": "tests/policy.test.ts",
|
|
683
689
|
"destination": "tests/policy.test.ts",
|
|
684
690
|
"executable": false,
|
|
685
|
-
"digest": "
|
|
691
|
+
"digest": "6a2be29c887e90b976273f8ef9da9ac1c17ed8c1880c133eb8a67514ddf5b5c3"
|
|
686
692
|
},
|
|
687
693
|
{
|
|
688
694
|
"storage": "tests/setupPolicy.ts",
|
|
689
695
|
"destination": "tests/setupPolicy.ts",
|
|
690
696
|
"executable": false,
|
|
691
|
-
"digest": "
|
|
697
|
+
"digest": "e33cc2f49a5bc201e339f50c59d280d36d06a5b687bc080a00b41f09577fa7c7"
|
|
692
698
|
}
|
|
693
699
|
],
|
|
694
700
|
"roots": [
|
|
@@ -736,5 +742,5 @@
|
|
|
736
742
|
".codex/agents",
|
|
737
743
|
".cursor/rules"
|
|
738
744
|
],
|
|
739
|
-
"digest": "
|
|
745
|
+
"digest": "900545f6b4a0078f1ab0256867453576ade0fca62344a3fd258d249cc6853823"
|
|
740
746
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
FUNCTION_SOURCE_FILES,
|
|
6
6
|
GENERIC_POLICY_SOURCES,
|
|
7
7
|
inspectPolicyControl,
|
|
8
|
+
inspectPolicyFilenamePaths,
|
|
8
9
|
inspectPolicyMirrorPaths,
|
|
10
|
+
inspectPolicyPortability,
|
|
9
11
|
inspectPolicySources,
|
|
10
12
|
inspectPolicyWorkspace,
|
|
11
13
|
inspectSkillFamily,
|
|
@@ -14,7 +16,13 @@ import {
|
|
|
14
16
|
parseSkillFrontmatter,
|
|
15
17
|
POLICY_CONTROLS,
|
|
16
18
|
POLICY_SUPPRESSION_DIRECTIVE,
|
|
19
|
+
PORTABILITY_POLICY_CONTROLS,
|
|
20
|
+
PORTABILITY_POLICY_EXCLUSION,
|
|
21
|
+
PORTABILITY_POLICY_LOCAL,
|
|
22
|
+
PORTABILITY_POLICY_SPLIT,
|
|
23
|
+
readPolicyPaths,
|
|
17
24
|
readSkillFamily,
|
|
25
|
+
RULES_POLICY_CONTROLS,
|
|
18
26
|
SKILL_POLICY_APOSTROPHE,
|
|
19
27
|
SKILL_POLICY_BACKTICKED,
|
|
20
28
|
SKILL_POLICY_CONTROLS,
|
|
@@ -413,8 +421,84 @@ describe('skill bridge policy', () => {
|
|
|
413
421
|
}
|
|
414
422
|
})
|
|
415
423
|
|
|
424
|
+
describe('rule map policy', () => {
|
|
425
|
+
for (const control of RULES_POLICY_CONTROLS) {
|
|
426
|
+
it(`${control.label} [membership: ${control.membership}]`, () => {
|
|
427
|
+
const violations = inspectPolicyControl(control)
|
|
428
|
+
expect(violations).toHaveLength(1)
|
|
429
|
+
expect(violations[0]?.rule).toBe(control.rule)
|
|
430
|
+
expect(control.message === undefined || violations[0]?.message === control.message).toBe(true)
|
|
431
|
+
})
|
|
432
|
+
}
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
describe('portability policy', () => {
|
|
436
|
+
for (const control of PORTABILITY_POLICY_CONTROLS) {
|
|
437
|
+
it(`${control.label} [membership: ${control.membership}]`, () => {
|
|
438
|
+
const violations = inspectPolicyControl(control)
|
|
439
|
+
expect(violations).toHaveLength(1)
|
|
440
|
+
expect(violations[0]?.rule).toBe(control.rule)
|
|
441
|
+
expect(control.message === undefined || violations[0]?.message === control.message).toBe(true)
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
for (const control of [
|
|
446
|
+
PORTABILITY_POLICY_EXCLUSION,
|
|
447
|
+
PORTABILITY_POLICY_LOCAL,
|
|
448
|
+
PORTABILITY_POLICY_SPLIT,
|
|
449
|
+
]) {
|
|
450
|
+
it(`${control.label} [membership: ${control.membership}]`, () => {
|
|
451
|
+
expect(inspectPolicyControl(control)).toEqual([])
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
it('rejects a character Windows refuses inside a path segment', () => {
|
|
456
|
+
// A Windows host refuses to create this name, so the population itself is the control.
|
|
457
|
+
expect(inspectPolicyFilenamePaths(['src/worker/read<write>.ts'])).toEqual([
|
|
458
|
+
{
|
|
459
|
+
rule: 'portability',
|
|
460
|
+
path: 'src/worker/read<write>.ts',
|
|
461
|
+
message: 'path segments avoid the characters Windows refuses',
|
|
462
|
+
},
|
|
463
|
+
])
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
it('rejects sibling paths that differ by case alone', () => {
|
|
467
|
+
// A Windows host folds the pair into one file, so the population itself is the control.
|
|
468
|
+
expect(inspectPolicyFilenamePaths(['guides/Readme.md', 'guides/readme.md'])).toEqual([
|
|
469
|
+
{
|
|
470
|
+
rule: 'portability',
|
|
471
|
+
path: 'guides/readme.md',
|
|
472
|
+
message: 'path differs from guides/Readme.md by case alone',
|
|
473
|
+
},
|
|
474
|
+
])
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
it('accepts sibling paths that differ by more than case', () => {
|
|
478
|
+
expect(
|
|
479
|
+
inspectPolicyFilenamePaths([
|
|
480
|
+
'guides/readme.md',
|
|
481
|
+
'guides/readmes.md',
|
|
482
|
+
'src/worker/helpers.ts',
|
|
483
|
+
]),
|
|
484
|
+
).toEqual([])
|
|
485
|
+
})
|
|
486
|
+
})
|
|
487
|
+
|
|
416
488
|
describe('repository policy', () => {
|
|
417
489
|
it('enforces placement and mirrors over the real workspace', () => {
|
|
418
490
|
expect(inspectPolicyWorkspace(process.cwd())).toEqual([])
|
|
419
491
|
})
|
|
492
|
+
|
|
493
|
+
it('reaches every branch of the workspace-authored path population', () => {
|
|
494
|
+
const paths = readPolicyPaths(process.cwd())
|
|
495
|
+
expect(paths).toContain('tests/setupPolicy.ts')
|
|
496
|
+
expect(paths).toContain('.claude/rules/names.md')
|
|
497
|
+
expect(paths).toContain('package.json')
|
|
498
|
+
expect(paths).toContain('.gitattributes')
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
it('keeps every workspace path, script, and source portable', () => {
|
|
502
|
+
expect(inspectPolicyPortability(process.cwd())).toEqual([])
|
|
503
|
+
})
|
|
420
504
|
})
|