@orkestrel/scaffold 0.0.107 → 0.0.109
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/skills/orkestrel-dispatch/scripts/bench.js +326 -91
- package/dist/agents/skills/orkestrel-dispatch/scripts/brief.js +110 -14
- package/dist/agents/skills/orkestrel-dispatch/scripts/chain.js +280 -0
- package/dist/agents/skills/orkestrel-dispatch/scripts/cite.js +188 -26
- package/dist/agents/skills/orkestrel-dispatch/scripts/launch.js +142 -43
- package/dist/agents/skills/orkestrel-dispatch/scripts/login.js +240 -62
- package/dist/agents/skills/orkestrel-dispatch/scripts/patch.js +323 -0
- package/dist/agents/skills/orkestrel-dispatch/scripts/result.js +169 -32
- package/dist/agents/skills/orkestrel-dispatch/scripts/sweep.js +368 -27
- package/dist/agents/skills/orkestrel-falsify/scripts/mutate.js +560 -0
- package/dist/agents/skills/orkestrel-harden/scripts/discovery.js +1052 -205
- package/dist/agents/skills/orkestrel-harden/scripts/measure.js +361 -0
- package/dist/agents/skills/orkestrel-harden/scripts/titles.js +455 -80
- package/dist/agents/skills/orkestrel-parallel/scripts/cases.js +327 -0
- package/dist/agents/skills/orkestrel-publish/scripts/compare.js +298 -51
- package/dist/agents/skills/orkestrel-publish/scripts/pins.js +170 -13
- package/dist/agents/skills/orkestrel-publish/scripts/swap.js +956 -191
- package/dist/agents/skills/orkestrel-publish/scripts/wave.js +707 -112
- package/dist/agents/skills/orkestrel-publish/scripts/window.js +235 -41
- package/dist/agents/skills/orkestrel-scout/scripts/map.js +341 -54
- package/dist/agents/templates/brief.md +1 -1
- package/dist/bin/main.js +51 -46
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +26 -20
- package/dist/host/agents/orchestration.md +98 -58
- package/dist/host/agents/platforms/posix.md +15 -0
- package/dist/host/agents/platforms/windows.md +37 -0
- package/dist/host/agents/skills/orkestrel-align/SKILL.md +10 -13
- package/dist/host/agents/skills/orkestrel-align/references/fleet.md +4 -10
- package/dist/host/agents/skills/orkestrel-align/references/integration.md +1 -1
- package/dist/host/agents/skills/orkestrel-build/SKILL.md +16 -48
- package/dist/host/agents/skills/orkestrel-build/agents/openai.yaml +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +19 -16
- package/dist/host/agents/skills/orkestrel-debrief/agents/openai.yaml +1 -1
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +15 -28
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +5 -6
- package/dist/host/agents/skills/orkestrel-debrief/references/retention.md +12 -14
- package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +36 -24
- package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +14 -11
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/bench.ts +366 -75
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/brief.ts +126 -16
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/chain.ts +323 -0
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/cite.ts +220 -31
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/launch.ts +176 -33
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/login.ts +294 -59
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/patch.ts +401 -0
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/result.ts +199 -34
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/sweep.ts +428 -27
- package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +10 -8
- package/dist/host/agents/skills/orkestrel-falsify/references/brief.md +1 -5
- package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +1 -1
- package/dist/host/agents/skills/orkestrel-falsify/scripts/mutate.ts +701 -0
- package/dist/host/agents/skills/orkestrel-harden/SKILL.md +16 -12
- package/dist/host/agents/skills/orkestrel-harden/references/bindings.md +23 -81
- package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +4 -5
- package/dist/host/agents/skills/orkestrel-harden/references/contract.md +2 -0
- package/dist/host/agents/skills/orkestrel-harden/references/document.md +33 -0
- package/dist/host/agents/skills/orkestrel-harden/references/equivalence.md +6 -3
- package/dist/host/agents/skills/orkestrel-harden/references/hardening.md +8 -4
- package/dist/host/agents/skills/orkestrel-harden/references/research.md +2 -0
- package/dist/host/agents/skills/orkestrel-harden/scripts/discovery.ts +1272 -279
- package/dist/host/agents/skills/orkestrel-harden/scripts/measure.ts +425 -0
- package/dist/host/agents/skills/orkestrel-harden/scripts/titles.ts +603 -98
- package/dist/host/agents/skills/orkestrel-journey/SKILL.md +75 -98
- package/dist/host/agents/skills/orkestrel-journey/references/captures.md +54 -17
- package/dist/host/agents/skills/orkestrel-journey/references/decide.md +1 -20
- package/dist/host/agents/skills/orkestrel-journey/references/layer.md +21 -31
- package/dist/host/agents/skills/orkestrel-journey/references/styles.md +1 -1
- package/dist/host/agents/skills/orkestrel-parallel/SKILL.md +91 -30
- package/dist/host/agents/skills/orkestrel-parallel/agents/openai.yaml +2 -2
- package/dist/host/agents/skills/orkestrel-parallel/references/claude.md +34 -0
- package/dist/host/agents/skills/orkestrel-parallel/references/codex.md +29 -0
- package/dist/host/agents/skills/orkestrel-parallel/references/cursor.md +29 -0
- package/dist/host/agents/skills/orkestrel-parallel/references/t3.md +31 -0
- package/dist/host/agents/skills/orkestrel-parallel/scripts/cases.ts +389 -0
- package/dist/host/agents/skills/orkestrel-polish/SKILL.md +16 -20
- package/dist/host/agents/skills/orkestrel-polish/references/capture-harness.md +16 -26
- package/dist/host/agents/skills/orkestrel-publish/SKILL.md +12 -26
- package/dist/host/agents/skills/orkestrel-publish/agents/openai.yaml +2 -2
- package/dist/host/agents/skills/orkestrel-publish/references/adopt.md +23 -0
- package/dist/host/agents/skills/orkestrel-publish/references/release.md +4 -4
- package/dist/host/agents/skills/orkestrel-publish/references/wave.md +12 -10
- package/dist/host/agents/skills/orkestrel-publish/references/window.md +20 -25
- package/dist/host/agents/skills/orkestrel-publish/scripts/compare.ts +348 -59
- package/dist/host/agents/skills/orkestrel-publish/scripts/pins.ts +202 -22
- package/dist/host/agents/skills/orkestrel-publish/scripts/swap.ts +1061 -191
- package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +812 -140
- package/dist/host/agents/skills/orkestrel-publish/scripts/window.ts +280 -38
- package/dist/host/agents/skills/orkestrel-scout/SKILL.md +3 -3
- package/dist/host/agents/skills/orkestrel-scout/scripts/map.ts +428 -70
- package/dist/host/agents/templates/brief.md +1 -1
- package/dist/host/agents/transports/claude-cli.md +3 -3
- package/dist/host/agents/transports/codex.md +3 -8
- package/dist/host/agents/transports/cursor.md +2 -3
- package/dist/host/claude/AGENTS.md +7 -10
- package/dist/host/claude/agents/analyst.md +3 -3
- package/dist/host/claude/agents/astra.md +3 -3
- package/dist/host/claude/agents/builder.md +1 -1
- package/dist/host/claude/agents/checker.md +1 -1
- package/dist/host/claude/agents/distiller.md +1 -1
- package/dist/host/claude/agents/grok.md +1 -1
- package/dist/host/claude/agents/opus.md +2 -2
- package/dist/host/claude/agents/orkestrel.md +57 -90
- package/dist/host/claude/agents/researcher.md +1 -1
- package/dist/host/claude/agents/reviewer.md +4 -0
- package/dist/host/claude/agents/scout.md +1 -1
- package/dist/host/claude/agents/verifier.md +1 -1
- package/dist/host/claude/rules/application.md +14 -21
- package/dist/host/claude/rules/architecture.md +34 -44
- package/dist/host/claude/rules/browser.md +3 -4
- package/dist/host/claude/rules/campaign.md +55 -0
- package/dist/host/claude/rules/documentation.md +26 -11
- package/dist/host/claude/rules/names.md +9 -4
- package/dist/host/claude/rules/patterns.md +6 -7
- package/dist/host/claude/rules/portability.md +2 -3
- package/dist/host/claude/rules/quality.md +4 -5
- package/dist/host/claude/rules/styles.md +2 -2
- package/dist/host/claude/rules/tests.md +57 -114
- package/dist/host/claude/rules/typescript.md +8 -10
- package/dist/host/claude/rules/workspace.md +21 -19
- package/dist/host/claude/rules/writing.md +3 -3
- package/dist/host/claude/skills/orkestrel-dispatch/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-harden/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-parallel/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-publish/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-scout/SKILL.md +1 -1
- package/dist/host/codex/agents/analyst.toml +9 -3
- package/dist/host/codex/agents/astra.toml +3 -4
- package/dist/host/codex/agents/builder.toml +1 -1
- package/dist/host/codex/agents/opus.toml +3 -4
- package/dist/host/codex/agents/orkestrel.toml +1 -1
- package/dist/host/codex/agents/researcher.toml +2 -2
- package/dist/host/codex/agents/verifier.toml +1 -1
- package/dist/host/codex/config.toml +3 -3
- package/dist/host/configs/helpers.ts +21 -1
- package/dist/host/configs/policy.ts +405 -16
- package/dist/host/cursor/rules/orchestration.mdc +1 -0
- package/dist/host/dotfiles/oxlintrc.json +141 -5
- package/dist/host/guides/agent.md +111 -134
- package/dist/host/guides/capture.md +801 -0
- package/dist/host/guides/probe.md +27 -8
- package/dist/host/guides/scaffold.md +152 -19
- package/dist/host/guides/study.md +534 -440
- package/dist/host/guides/test.md +111 -44
- package/dist/host/manifest.json +199 -242
- package/dist/host/tests/config.test.ts +1558 -219
- package/dist/host/tests/policy.test.ts +127 -1
- package/dist/host/tests/setupPolicy.ts +1389 -39
- package/dist/src/core/index.cjs +239 -87
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +123 -39
- package/dist/src/core/index.d.ts +123 -39
- package/dist/src/core/index.js +234 -86
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +20 -27
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.js +21 -28
- package/dist/src/server/index.js.map +1 -1
- package/package.json +11 -11
- package/dist/agents/skills/orkestrel-dispatch/scripts/helpers.js +0 -283
- package/dist/host/agents/skills/orkestrel-dispatch/references/bench.md +0 -25
- package/dist/host/agents/skills/orkestrel-dispatch/scripts/helpers.ts +0 -333
- package/dist/host/agents/skills/orkestrel-parallel/references/harnesses.md +0 -19
- package/dist/host/guides/supervisor.md +0 -4890
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
// Check a Vitest JSON report against named red and green cases. Run from the checkout root:
|
|
2
|
+
// node .agents/skills/orkestrel-parallel/scripts/cases.ts --report FILE.json [--passed NAME ...] [--failed NAME ...]
|
|
3
|
+
// The report is Vitest's `--reporter=json` output. A name matches every case whose full name (its
|
|
4
|
+
// `describe` titles and its own title, joined by spaces) or whose own title equals it exactly; a name
|
|
5
|
+
// that opens with `--` cannot be given. Each `--passed NAME` requires every case it matches to have
|
|
6
|
+
// passed and each `--failed NAME` requires every one to have failed; a name that matches no case is
|
|
7
|
+
// missing. A failed case that no name matches is refused, so a run that fails more than the request
|
|
8
|
+
// expected reads as a difference. A test file that failed with no failed case (it did not collect,
|
|
9
|
+
// or a hook threw) is an unnamed failure named by its file, and a report whose `success` is false
|
|
10
|
+
// while no case and no file failed is a difference too. Name no case to require a report with no
|
|
11
|
+
// failure. Both flags repeat and a name may not be given to both. The script prints one summary
|
|
12
|
+
// line, one line per difference, and `ok` or `differences=N`. The script refuses a flag it does not
|
|
13
|
+
// read, the `--flag=value` form included, and names an unknown flag before a flag given with no
|
|
14
|
+
// value. Exit 0 when the report matches the names, 3 when it does not, 2 when the report cannot be
|
|
15
|
+
// read as a Vitest report, 64 on usage.
|
|
16
|
+
import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs'
|
|
17
|
+
import { relative } from 'node:path'
|
|
18
|
+
|
|
19
|
+
/** Lists the flags that take a value. */
|
|
20
|
+
export const VALUE_FLAGS: readonly string[] = ['--report', '--passed', '--failed']
|
|
21
|
+
|
|
22
|
+
/** Lists every flag the script reads, value flags and switches alike. */
|
|
23
|
+
export const FLAGS: readonly string[] = VALUE_FLAGS
|
|
24
|
+
|
|
25
|
+
/** Holds the usage line printed when a call names no report. */
|
|
26
|
+
export const USAGE =
|
|
27
|
+
'usage: cases.ts --report FILE.json [--passed NAME ...] [--failed NAME ...]; --passed and --failed repeat'
|
|
28
|
+
|
|
29
|
+
/** Describes one test case a report holds. */
|
|
30
|
+
export interface Case {
|
|
31
|
+
readonly file: string
|
|
32
|
+
readonly fullName: string
|
|
33
|
+
readonly title: string
|
|
34
|
+
readonly status: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Names the value flags a caller gave with no value, at any occurrence.
|
|
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(
|
|
45
|
+
argv: readonly string[],
|
|
46
|
+
names: readonly string[],
|
|
47
|
+
): readonly string[] {
|
|
48
|
+
return names.filter((name) =>
|
|
49
|
+
argv.some((argument, index) => argument === name && isMissingValue(argv, index)),
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Checks whether the argument after a flag is absent or is another flag.
|
|
55
|
+
*
|
|
56
|
+
* @param argv - The arguments after the script path.
|
|
57
|
+
* @param index - The position of the flag.
|
|
58
|
+
* @returns True when no value follows the flag; false otherwise.
|
|
59
|
+
*/
|
|
60
|
+
export function isMissingValue(argv: readonly string[], index: number): boolean {
|
|
61
|
+
const value = argv[index + 1]
|
|
62
|
+
return value === undefined || value.startsWith('--')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Names the flags a caller gave that the script does not read.
|
|
67
|
+
*
|
|
68
|
+
* @remarks
|
|
69
|
+
* A `--flag=value` argument is unknown, because the script reads no such form. A bare `--` ends the
|
|
70
|
+
* scan.
|
|
71
|
+
*
|
|
72
|
+
* @param argv - The arguments after the script path.
|
|
73
|
+
* @param flags - Every flag the script reads, value flags and switches alike.
|
|
74
|
+
* @returns Each argument that opens with `--` and is not a read flag, in argument order.
|
|
75
|
+
*/
|
|
76
|
+
export function readUnknownFlags(
|
|
77
|
+
argv: readonly string[],
|
|
78
|
+
flags: readonly string[],
|
|
79
|
+
): readonly string[] {
|
|
80
|
+
const end = argv.indexOf('--')
|
|
81
|
+
return (end === -1 ? argv : argv.slice(0, end)).filter(
|
|
82
|
+
(argument) => argument.startsWith('--') && !flags.includes(argument),
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Reads every value that follows a repeatable flag.
|
|
88
|
+
*
|
|
89
|
+
* @param argv - The arguments after the script path.
|
|
90
|
+
* @param name - The flag, such as `--passed`.
|
|
91
|
+
* @returns The values in order, empty when the flag never appears.
|
|
92
|
+
*/
|
|
93
|
+
export function readOptions(argv: readonly string[], name: string): readonly string[] {
|
|
94
|
+
return argv.flatMap((argument, index) => {
|
|
95
|
+
const value = argv[index + 1]
|
|
96
|
+
return argument === name && value !== undefined && !value.startsWith('--') ? [value] : []
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Reads the arguments that are neither a flag nor the value of a value flag.
|
|
102
|
+
*
|
|
103
|
+
* @param argv - The arguments after the script path.
|
|
104
|
+
* @param valueFlags - The flags that take a value.
|
|
105
|
+
* @returns The positional arguments in order.
|
|
106
|
+
*/
|
|
107
|
+
export function readPositionals(
|
|
108
|
+
argv: readonly string[],
|
|
109
|
+
valueFlags: readonly string[],
|
|
110
|
+
): readonly string[] {
|
|
111
|
+
return argv.filter(
|
|
112
|
+
(argument, index) => !argument.startsWith('--') && !valueFlags.includes(argv[index - 1] ?? ''),
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Checks whether a value is a non-null, non-array object.
|
|
118
|
+
*
|
|
119
|
+
* @param value - The value to inspect.
|
|
120
|
+
* @returns True if the value is an object other than null or an array; false otherwise.
|
|
121
|
+
*/
|
|
122
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
123
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Quotes an untrusted text for a diagnostic, JSON-encoded and cut to a bounded length.
|
|
128
|
+
*
|
|
129
|
+
* @param text - The text to quote.
|
|
130
|
+
* @returns The JSON string literal of the text, ending in an ellipsis inside the quotes when cut.
|
|
131
|
+
*/
|
|
132
|
+
export function quote(text: string): string {
|
|
133
|
+
return JSON.stringify(text.length > 120 ? `${text.slice(0, 120)}…` : text)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Reads one assertion result of a report as a case.
|
|
138
|
+
*
|
|
139
|
+
* @param file - The test file the result belongs to.
|
|
140
|
+
* @param result - The parsed JSON value of one assertion result.
|
|
141
|
+
* @returns The case as a one-member list, or an empty list when the result lacks a title or status.
|
|
142
|
+
*/
|
|
143
|
+
export function readCase(file: string, result: unknown): readonly Case[] {
|
|
144
|
+
if (!isRecord(result)) return []
|
|
145
|
+
const { title, status, fullName, ancestorTitles } = result
|
|
146
|
+
if (typeof title !== 'string' || typeof status !== 'string') return []
|
|
147
|
+
const ancestors = Array.isArray(ancestorTitles)
|
|
148
|
+
? ancestorTitles.filter((member) => typeof member === 'string')
|
|
149
|
+
: []
|
|
150
|
+
return [
|
|
151
|
+
{
|
|
152
|
+
file,
|
|
153
|
+
title,
|
|
154
|
+
status,
|
|
155
|
+
fullName: typeof fullName === 'string' ? fullName : [...ancestors, title].join(' '),
|
|
156
|
+
},
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Reads the cases of a Vitest JSON report.
|
|
162
|
+
*
|
|
163
|
+
* @param report - The parsed JSON value of the report.
|
|
164
|
+
* @returns Every case in file order, or undefined when the value is not a Vitest report: an object
|
|
165
|
+
* whose `testResults` is an array.
|
|
166
|
+
*/
|
|
167
|
+
export function readCases(report: unknown): readonly Case[] | undefined {
|
|
168
|
+
if (!isRecord(report) || !Array.isArray(report.testResults)) return undefined
|
|
169
|
+
return report.testResults.flatMap((suite): readonly Case[] => {
|
|
170
|
+
if (!isRecord(suite) || !Array.isArray(suite.assertionResults)) return []
|
|
171
|
+
const file = typeof suite.name === 'string' ? suite.name : ''
|
|
172
|
+
return suite.assertionResults.flatMap((result) => readCase(file, result))
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Reads the test files of a report that failed with no failed case.
|
|
178
|
+
*
|
|
179
|
+
* @param report - The parsed JSON value of the report.
|
|
180
|
+
* @returns The `name` of each `testResults` entry whose `status` is `failed` and whose assertion
|
|
181
|
+
* results hold no failed case, in file order; an empty text stands for an entry with no name.
|
|
182
|
+
*/
|
|
183
|
+
export function readFailedFiles(report: unknown): readonly string[] {
|
|
184
|
+
if (!isRecord(report) || !Array.isArray(report.testResults)) return []
|
|
185
|
+
return report.testResults.flatMap((suite): readonly string[] => {
|
|
186
|
+
if (!isRecord(suite) || suite.status !== 'failed') return []
|
|
187
|
+
const results = Array.isArray(suite.assertionResults) ? suite.assertionResults : []
|
|
188
|
+
if (results.some((result) => isRecord(result) && result.status === 'failed')) return []
|
|
189
|
+
return [typeof suite.name === 'string' ? suite.name : '']
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Checks whether a report states that the run did not succeed.
|
|
195
|
+
*
|
|
196
|
+
* @param report - The parsed JSON value of the report.
|
|
197
|
+
* @returns True when the report is an object whose `success` is `false`; false otherwise.
|
|
198
|
+
*/
|
|
199
|
+
export function isUnsuccessful(report: unknown): boolean {
|
|
200
|
+
return isRecord(report) && report.success === false
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Checks whether a name matches a case.
|
|
205
|
+
*
|
|
206
|
+
* @param entry - The case.
|
|
207
|
+
* @param name - The name from `--passed` or `--failed`.
|
|
208
|
+
* @returns True when the name equals the case's full name or its own title; false otherwise.
|
|
209
|
+
*/
|
|
210
|
+
export function matchesCase(entry: Case, name: string): boolean {
|
|
211
|
+
return entry.fullName === name || entry.title === name
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Judges the cases of a report against the names a caller gave.
|
|
216
|
+
*
|
|
217
|
+
* @param cases - The report's cases.
|
|
218
|
+
* @param passed - The names that must have passed.
|
|
219
|
+
* @param failed - The names that must have failed.
|
|
220
|
+
* @param base - The directory the file names in each difference are written relative to.
|
|
221
|
+
* @returns Each difference in order: missing names, wrong statuses, then failed cases no name
|
|
222
|
+
* matches; empty when the report matches.
|
|
223
|
+
*/
|
|
224
|
+
export function judgeCases(
|
|
225
|
+
cases: readonly Case[],
|
|
226
|
+
passed: readonly string[],
|
|
227
|
+
failed: readonly string[],
|
|
228
|
+
base: string,
|
|
229
|
+
): readonly string[] {
|
|
230
|
+
const expectations = [
|
|
231
|
+
...passed.map((name) => ({ name, status: 'passed' })),
|
|
232
|
+
...failed.map((name) => ({ name, status: 'failed' })),
|
|
233
|
+
]
|
|
234
|
+
const named = expectations.flatMap((expectation) => {
|
|
235
|
+
const matches = cases.filter((entry) => matchesCase(entry, expectation.name))
|
|
236
|
+
if (matches.length === 0) return [`missing: ${quote(expectation.name)} matches no case`]
|
|
237
|
+
return matches
|
|
238
|
+
.filter((entry) => entry.status !== expectation.status)
|
|
239
|
+
.map(
|
|
240
|
+
(entry) =>
|
|
241
|
+
`status: ${quote(entry.fullName)} is ${entry.status}, expected ${expectation.status}${describeFile(base, entry.file)}`,
|
|
242
|
+
)
|
|
243
|
+
})
|
|
244
|
+
const unnamed = cases
|
|
245
|
+
.filter(
|
|
246
|
+
(entry) =>
|
|
247
|
+
entry.status === 'failed' &&
|
|
248
|
+
!expectations.some((expectation) => matchesCase(entry, expectation.name)),
|
|
249
|
+
)
|
|
250
|
+
.map((entry) => `unnamed failure: ${quote(entry.fullName)}${describeFile(base, entry.file)}`)
|
|
251
|
+
return [...named, ...unnamed]
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Judges the failures a report holds outside its cases.
|
|
256
|
+
*
|
|
257
|
+
* @param cases - The report's cases.
|
|
258
|
+
* @param failedFiles - The test files that failed with no failed case, from {@link readFailedFiles}.
|
|
259
|
+
* @param unsuccessful - Whether the report states that the run did not succeed.
|
|
260
|
+
* @param base - The directory the file names in each difference are written relative to.
|
|
261
|
+
* @returns One unnamed failure per failed file; or, when no file and no case failed yet the report
|
|
262
|
+
* is not successful, one unnamed failure for the report; empty otherwise.
|
|
263
|
+
*/
|
|
264
|
+
export function judgeFailures(
|
|
265
|
+
cases: readonly Case[],
|
|
266
|
+
failedFiles: readonly string[],
|
|
267
|
+
unsuccessful: boolean,
|
|
268
|
+
base: string,
|
|
269
|
+
): readonly string[] {
|
|
270
|
+
if (failedFiles.length > 0) {
|
|
271
|
+
return failedFiles.map(
|
|
272
|
+
(file) =>
|
|
273
|
+
`unnamed failure: ${file === '' ? 'a test file' : quote(relativeFile(base, file))} failed with no failed case`,
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
return unsuccessful && cases.every((entry) => entry.status !== 'failed')
|
|
277
|
+
? ['unnamed failure: the report is not successful, yet no case and no file in it failed']
|
|
278
|
+
: []
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Writes a test file path relative to a directory.
|
|
283
|
+
*
|
|
284
|
+
* @param base - The directory the path is written relative to.
|
|
285
|
+
* @param file - The test file path from the report.
|
|
286
|
+
* @returns The relative path with forward slashes.
|
|
287
|
+
*/
|
|
288
|
+
export function relativeFile(base: string, file: string): string {
|
|
289
|
+
return relative(base, file).split('\\').join('/')
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Describes the file a case belongs to, written relative to a directory.
|
|
294
|
+
*
|
|
295
|
+
* @param base - The directory the path is written relative to.
|
|
296
|
+
* @param file - The test file path from the report.
|
|
297
|
+
* @returns ` in <path>` with forward slashes, or an empty text when the report names no file.
|
|
298
|
+
*/
|
|
299
|
+
export function describeFile(base: string, file: string): string {
|
|
300
|
+
return file === '' ? '' : ` in ${relativeFile(base, file)}`
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Counts the cases that carry a status.
|
|
305
|
+
*
|
|
306
|
+
* @param cases - The report's cases.
|
|
307
|
+
* @param status - The status, such as `passed`.
|
|
308
|
+
* @returns How many cases have exactly that status.
|
|
309
|
+
*/
|
|
310
|
+
export function countStatus(cases: readonly Case[], status: string): number {
|
|
311
|
+
return cases.filter((entry) => entry.status === status).length
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Reads a report file as JSON.
|
|
316
|
+
*
|
|
317
|
+
* @param path - The report file.
|
|
318
|
+
* @returns The parsed value, or undefined when the file is not readable JSON.
|
|
319
|
+
*/
|
|
320
|
+
export function readReport(path: string): unknown {
|
|
321
|
+
try {
|
|
322
|
+
return JSON.parse(readFileSync(path, 'utf8'))
|
|
323
|
+
} catch {
|
|
324
|
+
return undefined
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Runs the script on its arguments.
|
|
330
|
+
*
|
|
331
|
+
* @param argv - The arguments after the script path.
|
|
332
|
+
* @returns The exit code: 0 when the report matches the names, 3 when it does not, 2 when the report
|
|
333
|
+
* cannot be read as a Vitest report, 64 on usage.
|
|
334
|
+
*/
|
|
335
|
+
export function main(argv: readonly string[]): number {
|
|
336
|
+
const unknown = readUnknownFlags(argv, FLAGS)
|
|
337
|
+
if (unknown.length > 0) {
|
|
338
|
+
console.error(`cases: ${unknown.join(', ')} is not a flag this script reads; ${USAGE}`)
|
|
339
|
+
return 64
|
|
340
|
+
}
|
|
341
|
+
const missing = readMissingFlags(argv, VALUE_FLAGS)
|
|
342
|
+
if (missing.length > 0) {
|
|
343
|
+
console.error(`cases: ${missing.join(', ')} given with no value`)
|
|
344
|
+
return 64
|
|
345
|
+
}
|
|
346
|
+
const reports = readOptions(argv, '--report')
|
|
347
|
+
const path = reports[0]
|
|
348
|
+
const passed = readOptions(argv, '--passed')
|
|
349
|
+
const failed = readOptions(argv, '--failed')
|
|
350
|
+
if (path === undefined || readPositionals(argv, VALUE_FLAGS).length > 0) {
|
|
351
|
+
console.error(USAGE)
|
|
352
|
+
return 64
|
|
353
|
+
}
|
|
354
|
+
const both = passed.filter((name) => failed.includes(name))
|
|
355
|
+
if (both.length > 0) {
|
|
356
|
+
console.error(
|
|
357
|
+
`cases: ${both.map(quote).join(', ')} given to both --passed and --failed; ${USAGE}`,
|
|
358
|
+
)
|
|
359
|
+
return 64
|
|
360
|
+
}
|
|
361
|
+
if (!existsSync(path) || !statSync(path).isFile()) {
|
|
362
|
+
console.error(`cases: ${quote(path)} is not a readable file`)
|
|
363
|
+
return 2
|
|
364
|
+
}
|
|
365
|
+
const report = readReport(path)
|
|
366
|
+
const cases = readCases(report)
|
|
367
|
+
if (cases === undefined) {
|
|
368
|
+
console.error(
|
|
369
|
+
`cases: ${quote(path)} is not a Vitest JSON report; it needs a "testResults" array (run vitest with --reporter=json)`,
|
|
370
|
+
)
|
|
371
|
+
return 2
|
|
372
|
+
}
|
|
373
|
+
const differences = [
|
|
374
|
+
...judgeCases(cases, passed, failed, process.cwd()),
|
|
375
|
+
...judgeFailures(cases, readFailedFiles(report), isUnsuccessful(report), process.cwd()),
|
|
376
|
+
]
|
|
377
|
+
const green = countStatus(cases, 'passed')
|
|
378
|
+
const red = countStatus(cases, 'failed')
|
|
379
|
+
console.log(
|
|
380
|
+
`cases total=${String(cases.length)} passed=${String(green)} failed=${String(red)} other=${String(cases.length - green - red)}`,
|
|
381
|
+
)
|
|
382
|
+
for (const difference of differences) console.log(difference)
|
|
383
|
+
console.log(differences.length === 0 ? 'ok' : `differences=${String(differences.length)}`)
|
|
384
|
+
return differences.length === 0 ? 0 : 3
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (process.argv[1] !== undefined && realpathSync(process.argv[1]) === import.meta.filename) {
|
|
388
|
+
process.exitCode = main(process.argv.slice(2))
|
|
389
|
+
}
|
|
@@ -24,8 +24,8 @@ supposed to produce it. Source-reading review passes a component that renders no
|
|
|
24
24
|
accessibility snapshot, and an interaction log.
|
|
25
25
|
- Source is corroboration for a mechanism, never the proof that the surface shows it.
|
|
26
26
|
- A claim the portfolio cannot show is unproven, not passed. Say so.
|
|
27
|
-
-
|
|
28
|
-
|
|
27
|
+
- Prove an externally driven surface's compatibility claim per the `orkestrel-harden` skill's
|
|
28
|
+
Production hardening → Use real implementations.
|
|
29
29
|
|
|
30
30
|
## Select the scope
|
|
31
31
|
|
|
@@ -36,29 +36,25 @@ Choose the smallest scope that satisfies the request:
|
|
|
36
36
|
re-verdict on the repaired items → independent gates.
|
|
37
37
|
|
|
38
38
|
A narrow verdict request does not authorize fixes. A polish request authorizes fixing every
|
|
39
|
-
confirmed finding in scope and rebuilding the harness gaps the verdicts expose.
|
|
40
|
-
over the same surface needs an instruction from the user.
|
|
39
|
+
confirmed finding in scope and rebuilding the harness gaps the verdicts expose.
|
|
41
40
|
|
|
42
41
|
## Execute the round
|
|
43
42
|
|
|
44
43
|
1. **Build the portfolio.** Produce the full evidence set with the harness reference, then
|
|
45
|
-
eyeball every artifact yourself before spending a verdict round on it.
|
|
46
|
-
portfolio buys harness bugs at verdict prices.
|
|
44
|
+
eyeball every artifact yourself before spending a verdict round on it.
|
|
47
45
|
2. **Seed candidates.** Turn your own mid-integration observations into numbered
|
|
48
|
-
confirm-or-refute candidates inside the verdict brief.
|
|
49
|
-
head are neither evidence nor findings.
|
|
46
|
+
confirm-or-refute candidates inside the verdict brief.
|
|
50
47
|
3. **Take independent verdicts** on the SAME portfolio, in the shape
|
|
51
|
-
§ "Return the fixed verdict shape" fixes.
|
|
52
|
-
|
|
53
|
-
copy, classes, icons, and accessibility attributes
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
and stops.
|
|
48
|
+
§ "Return the fixed verdict shape" fixes. Judgment runs as the two lanes
|
|
49
|
+
`.agents/orchestration.md` § Parallelism names: subjective design fit and objective state
|
|
50
|
+
truth. The mechanical inventory of copy, classes, icons, and accessibility attributes runs as a
|
|
51
|
+
`checker` lane. This is the surface variant of the review in `.agents/orchestration.md`
|
|
52
|
+
§ Size gate, so its rules bind: each judgment lane is a fresh subagent with a clean context,
|
|
53
|
+
blind to the other until reconciliation, run once, and no lane is dropped because an engine is
|
|
54
|
+
dark. A narrow verdict request runs the selected lane once and stops.
|
|
58
55
|
4. **Reconcile.** Confirmed findings get carriers; refuted findings close on the record with
|
|
59
56
|
the evidence that refuted them; conflicts get a dated ruling. Then walk the reconciled
|
|
60
|
-
list once and name the fix-brief item carrying each finding
|
|
61
|
-
is a dropped finding, and it will cost the next round.
|
|
57
|
+
list once and name the fix-brief item carrying each finding.
|
|
62
58
|
5. **Dispatch serialized fix units,** objective lane first because it changes the ground
|
|
63
59
|
truth the subjective lane reads. Each unit records the failing proof before the
|
|
64
60
|
repair — the exact command and its red count — and the same command's green count
|
|
@@ -87,7 +83,7 @@ over the same surface needs an instruction from the user.
|
|
|
87
83
|
|
|
88
84
|
## Return the fixed verdict shape
|
|
89
85
|
|
|
90
|
-
|
|
86
|
+
Every verdict returns:
|
|
91
87
|
|
|
92
88
|
- one line per item, in the brief's numbering:
|
|
93
89
|
- `RENDERED-PROVEN(<capture>)` — the artifact shows it;
|
|
@@ -101,8 +97,8 @@ Triage it against the capture reference before it becomes a finding.
|
|
|
101
97
|
|
|
102
98
|
## Accept the result
|
|
103
99
|
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
Accept per `.agents/orchestration.md` § Acceptance. Refuse a source-only verdict, a self-audited
|
|
101
|
+
fix unit, and a round without a terminal line. Completion requires:
|
|
106
102
|
|
|
107
103
|
- every confirmed finding fixed or explicitly ruled out of scope on the record;
|
|
108
104
|
- a final portfolio whose captures show the accepted state;
|
|
@@ -17,9 +17,7 @@ journey-generated and part spawned.
|
|
|
17
17
|
Apply this section to a spawned harness only.
|
|
18
18
|
|
|
19
19
|
- Write the harness as one self-contained script that spawns its own children, waits for readiness,
|
|
20
|
-
does the capture, and kills them before returning.
|
|
21
|
-
- Never leave a child running across calls or expect one to survive its parent. A process started
|
|
22
|
-
inside one tool call dies with that call's process group.
|
|
20
|
+
does the capture, and kills them before returning. Spawn, capture, and tear down in one call.
|
|
23
21
|
- Give every child a pinned working directory. A process that resolves assets, configuration, or
|
|
24
22
|
fixtures relative to the current directory dies silently when launched from elsewhere.
|
|
25
23
|
- Pipe child standard error somewhere readable and print it on failure.
|
|
@@ -43,33 +41,26 @@ and `orkestrel-journey` fixes how it enters and what it may reach past.
|
|
|
43
41
|
|
|
44
42
|
## Capture the full portfolio
|
|
45
43
|
|
|
46
|
-
Produce
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
| Accessibility snapshot | `describeTree` and `describeFocus` | The rendered roles, names, and states, and the focus order the walk took |
|
|
55
|
-
| Interaction log | The journal's `steps` | Each interaction, its trigger, and the result observed after it |
|
|
56
|
-
| Console and error log | The journal's `output` | Everything the page emitted, including an uncaught error |
|
|
57
|
-
| Statechart outcome | The harness after a play-all run | The terminal status, the passed, failed, and total tallies, and each row's own result |
|
|
58
|
-
|
|
59
|
-
- Require the statechart outcome of every surface that declares the statechart family, and omit the
|
|
60
|
-
row only where the surface declares none.
|
|
61
|
-
- Read the journey run's per-variant written artifact for the accessibility snapshot and the logs,
|
|
62
|
-
and cite the statechart harness by its deep link where a lane must watch the widget move rather
|
|
63
|
-
than read a still of it. `orkestrel-journey` fixes what each holds and what each is named
|
|
64
|
-
for.
|
|
44
|
+
Produce each of the following every round, for every scenario in scope:
|
|
45
|
+
|
|
46
|
+
- Viewport captures at every breakpoint the surface declares, and theme captures for every theme it ships at every declared viewport. In the journey run, `place` across the declared variants produces them.
|
|
47
|
+
- The rendered artifact per variant, composed as the `orkestrel-journey` skill's Routing a question → The rendered artifact fixes: the accessibility snapshot, the focus order, the interaction log, and the console and error log.
|
|
48
|
+
- The statechart outcome of every surface that declares the statechart family: the terminal status, the passed, failed, and total tallies, and each row's own result. The harness produces it after a play-all run; cite its deep link where a lane must watch the widget move rather than read a still of it.
|
|
49
|
+
|
|
50
|
+
A spawned harness produces each artifact itself.
|
|
51
|
+
|
|
65
52
|
- Shoot the whole surface before selecting or focusing anything inside it. A capture taken after a
|
|
66
53
|
selection reports a duplicate or highlighted artifact that does not exist.
|
|
67
54
|
- Start a keyboard walk from a neutral state, never from an already-focused control, or the log will
|
|
68
55
|
report a broken order no person meets.
|
|
69
56
|
- Name a spawned harness's artifacts so a verdict cites one exactly: scenario, viewport, theme,
|
|
70
57
|
step. The journey run's filename law already does this.
|
|
71
|
-
- Keep the artifacts of each round beside its verdicts.
|
|
72
|
-
|
|
58
|
+
- Keep the artifacts of each round beside its verdicts.
|
|
59
|
+
- For a journey-generated portfolio, record the capture manifest snapshot the round judges beside
|
|
60
|
+
its verdicts. Require every judged frame to be current, with its recorded source digests equal
|
|
61
|
+
to the tree's; recapture every stale judged frame before dispatch. Apply this rule to sittings
|
|
62
|
+
and checkpoints alike. Admit
|
|
63
|
+
frames assembled from several runs only when every judged frame is current.
|
|
73
64
|
|
|
74
65
|
## Preflight before spending a round
|
|
75
66
|
|
|
@@ -84,8 +75,7 @@ Confirm each of the following:
|
|
|
84
75
|
to the total;
|
|
85
76
|
- nothing in the console log indicates the harness, rather than the surface, failed.
|
|
86
77
|
|
|
87
|
-
Repair a portfolio that fails preflight before dispatching it.
|
|
88
|
-
discovering a harness defect.
|
|
78
|
+
Repair a portfolio that fails preflight before dispatching it.
|
|
89
79
|
|
|
90
80
|
## Triage missing evidence to the harness first
|
|
91
81
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: orkestrel-publish
|
|
3
|
-
description: Run an Orkestrel release from layer order to registry confirmation. Use when the user asks to publish a package, to run a fleet-wide release wave,
|
|
3
|
+
description: Run an Orkestrel release from layer order to registry confirmation, or adopt a published scaffold release in one consumer. Use when the user asks to publish a package, to run a fleet-wide release wave, to recover a release that stalled at the npm approval, or to adopt a published scaffold release in one repository, and follow it for the per-repository visit, the bump ruling, the layer preparation, the login approval, the upload approval, and the adoption.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Publish an Orkestrel release
|
|
@@ -14,9 +14,10 @@ description: Run an Orkestrel release from layer order to registry confirmation.
|
|
|
14
14
|
here.
|
|
15
15
|
2. The reference the moment needs: [wave.md](references/wave.md) before visiting a repository,
|
|
16
16
|
ruling on a bump, or preparing a layer; [window.md](references/window.md) before running
|
|
17
|
-
`npm login` or any upload.
|
|
17
|
+
`npm login` or any upload; [adopt.md](references/adopt.md) before one consumer adopts a
|
|
18
|
+
published scaffold release outside a wave.
|
|
18
19
|
3. The live evidence: the registry's packument for every package in the round, each target's
|
|
19
|
-
manifest, and the catalog table
|
|
20
|
+
manifest, and the catalog table `references/release.md` names as the layer order.
|
|
20
21
|
|
|
21
22
|
## Scripts
|
|
22
23
|
|
|
@@ -26,35 +27,20 @@ description: Run an Orkestrel release from layer order to registry confirmation.
|
|
|
26
27
|
| `scripts/pins.ts` | `--version PRIOR [--range PRIOR_RANGE ...] [--paths src,tests] [--json]`, run from the package root: lists every line under the paths carrying the prior version literal or a prior range literal, once per line, sweeping a one-comparator range such as `^8.3.0` for its bare version in any form. Exit 0 with no hits, 3 with hits, 64 on usage (no literal, or a flag with no value). |
|
|
27
28
|
| `scripts/swap.ts` | One mode per run, from any directory: `--pin --consumer DIR --source DIR [--source DIR ...] [--override NAME ...] [--no-build] [--dry-run] [--json]` refuses a source whose packed manifest names a local dependency spec in any dependency field (a `file:` or `link:` prefix, a path start of `.`, `~/`, `/`, `\`, or a drive letter, or a protocol-free archive name ending in `.tgz`, `.tar.gz`, or `.tar` that is not a `user/repo` shorthand), builds and packs each source into `<consumer>/tmp/tarballs/` under a name carrying its SHA-256, records each replaced range in the ledger `pins.json` there, the record of which build the consumer runs, writes each tarball's absolute `file:` spec and each `--override` (repeatable, like `--source`) where oxfmt sorts it, installs, and proves that every pinned source, an override-only one included, is installed with the source's bytes; `--restore --consumer DIR [--package NAME ...] [--json]` puts back each recorded range and override, keeps an `overrides` block that existed before the pin, installs, proves the restored copy, and lists the re-pin arguments, and refuses with 64, before it writes anything, a ledger whose package or override keys are not package names or whose removal would leave `node_modules`; `--status --consumer DIR [--json]` writes nothing and reports drift between the ledger, the manifest, the tarballs, the installed bytes, and the source commits, a manifest spec holding its tarball only when it names the ledger archive's location. `--pin` and `--restore` write a receipt under `tmp/units/`. Exit 0 on success, 1 when a command or a proof failed, 3 when `--status` reports drift, 64 on usage. |
|
|
28
29
|
| `scripts/wave.ts` | `--visit [--target DIR] [--offline] [--regenerate] [--from STEP] [--to STEP] [--prior VERSION] [--dry-run] [--json] [--out FILE]` runs one repository's visit in the order [wave.md](references/wave.md) § Visit a repository fixes (pin, commit, overwrite, verify, install, pins, format, record, gates, compare), stops at the first failing step, journals each executed step's full output under the target's `tmp/units/wave/` when the work tree ignores `tmp/` and names the journal in its row, and prints each step's exit (a failed step names the `code: message` refusal or the `note` a JSON verb writes on stdout, else the last stderr lines), the bump ruling (the rebuilt dist against the published tarball, and the final runtime dependency set against the published manifest), and a row for `.orkestrel/release.md`; `--prior` names the version a pre-ruled bump replaced so the self-pin sweep finds it; `--plan` prints the packages by layer from the catalog table. An install that fails `ERESOLVE` names the rerun command, and `--regenerate` replaces the lockfile and `node_modules` from the manifest under the refusals and proof [wave.md](references/wave.md) § Regenerate a lock the install cannot move states; `record` commits the overwrite's writes as `Overwrite with scaffold VERSION`. Exit 0 when every step passed, 1 when one failed, 2 when a reading failed, 64 on usage, including `--regenerate` with `--plan`. |
|
|
29
|
-
| `scripts/window.ts` | `--whoami [--wait SECONDS]` reads or polls `npm whoami`; `--login` prints the operator's login command and polls `whoami` until it answers; `--publish DIR... --otp CODE` refuses a batch whose nearest `.git` entry is a file, including ancestor entries, with exit 3 before contacting npm; it names a linked worktree's primary clone or identifies a submodule, then uploads back to back with `npm publish --ignore-scripts --otp`, journals each upload under `tmp/units/`, stops at the first refusal naming where to resume, and confirms each accepted version against the registry; `--confirm NAME@VERSION...` re-reads the registry until it serves the version. Exit 0 on success, 3 when not.
|
|
30
|
+
| `scripts/window.ts` | `--whoami [--wait SECONDS]` reads or polls `npm whoami`; `--login` prints the operator's login command and polls `whoami` until it answers; `--publish DIR... --otp CODE` refuses a batch whose nearest `.git` entry is a file, including ancestor entries, with exit 3 before contacting npm; it names a linked worktree's primary clone or identifies a submodule, then uploads back to back with `npm publish --ignore-scripts --otp`, journals each upload under `tmp/units/`, stops at the first refusal naming where to resume, and confirms each accepted version against the registry; `--confirm NAME@VERSION...` re-reads the registry until it serves the version. Exit 0 on success, 3 when not, 64 on usage. |
|
|
30
31
|
|
|
31
|
-
The user's current instruction wins. `references/release.md`
|
|
32
|
-
and authorization law; nothing here weakens it.
|
|
33
|
-
|
|
34
|
-
## The boundary with the contract
|
|
35
|
-
|
|
36
|
-
`references/release.md` binds every release, and this skill does not
|
|
37
|
-
repeat it. Read that section for the credential and approval law, the long-running-command
|
|
38
|
-
binding, the serialization of uploads, the tarball swap that serves a consumer whose dependency
|
|
39
|
-
has not published, what a bump obliges downstream, and where the layer order comes from.
|
|
40
|
-
|
|
41
|
-
This skill carries what an operator needs while a release is running: the per-repository visit,
|
|
42
|
-
the bump ruling, the preparation order, the login and approval mechanics, and the window.
|
|
43
|
-
|
|
44
|
-
Where the skill and the contract disagree, the contract wins. Report the drift instead of
|
|
45
|
-
following the skill.
|
|
32
|
+
The user's current instruction wins. `references/release.md` binds every release: the credential and authorization law, the upload serialization, the tarball swap, what a bump obliges downstream, and the layer order. Nothing here weakens it. Where this skill disagrees with it, report the drift instead of following the skill.
|
|
46
33
|
|
|
47
34
|
## Run the release
|
|
48
35
|
|
|
49
36
|
1. **Name the round.** List the packages the release covers, and group them into layers with
|
|
50
|
-
`node .agents/skills/orkestrel-publish/scripts/wave.ts --plan`, which reads the
|
|
51
|
-
|
|
37
|
+
`node .agents/skills/orkestrel-publish/scripts/wave.ts --plan`, which reads the layer order
|
|
38
|
+
from the catalog table.
|
|
52
39
|
2. **Take the registry evidence.** Read what the registry serves for every package in the round.
|
|
53
40
|
Derive each pin from that reading, never from a local manifest.
|
|
54
41
|
3. **Visit each repository.** Run `node .agents/skills/orkestrel-publish/scripts/wave.ts --visit --target <repository>`,
|
|
55
42
|
which runs the visit in [wave.md](references/wave.md) in its stated order and stops at the first
|
|
56
|
-
failing step; repair that step by hand and re-run from it with `--from`; for an `ERESOLVE`, follow [wave.md](references/wave.md) § Regenerate a lock the install cannot move.
|
|
57
|
-
slices of disjoint repositories, each slice serial inside itself.
|
|
43
|
+
failing step; repair that step by hand and re-run from it with `--from`; for an `ERESOLVE`, follow [wave.md](references/wave.md) § Regenerate a lock the install cannot move.
|
|
58
44
|
4. **Rule on each package's bump.** Take the visit's comparison and range reading; repeat `compare.ts` only after the artifact changes or an unanswered result. Apply the triggers in [wave.md](references/wave.md) § Rule on
|
|
59
45
|
the bump; `references/release.md` § What a bump obliges owns the blast radius.
|
|
60
46
|
5. **Prepare the whole layer before authenticating**, in the order [wave.md](references/wave.md)
|
|
@@ -69,8 +55,8 @@ following the skill.
|
|
|
69
55
|
8. **Close the layer from the registry, then prepare the next**, per [wave.md](references/wave.md)
|
|
70
56
|
§ Prepare a layer.
|
|
71
57
|
|
|
72
|
-
Run that sequence for every layer, from the registry reading to the registry close
|
|
73
|
-
registry
|
|
58
|
+
Run that sequence for every layer, from the registry reading to the registry close;
|
|
59
|
+
[wave.md](references/wave.md) § Refresh the registry between layers owns the refresh.
|
|
74
60
|
|
|
75
61
|
## Accept the release
|
|
76
62
|
|
|
@@ -81,7 +67,7 @@ Completion requires:
|
|
|
81
67
|
- every obligation `references/release.md` § What a bump obliges places on a published package's dependents has closed as
|
|
82
68
|
that section requires;
|
|
83
69
|
- every tarball swap is restored per `references/release.md` § Fix a dependency before it publishes, and no target
|
|
84
|
-
repository is left holding an uncommitted bump or an unpushed commit;
|
|
70
|
+
repository is left holding an uncommitted bump or an unpushed commit the user has not held;
|
|
85
71
|
- every gate that proved a package ran outside the window and against the artifact that shipped;
|
|
86
72
|
- every gate red at a package's baseline for a cause `ROADMAP.md` already carries is recorded as a
|
|
87
73
|
standing reading beside the package's row with its carrier, and the release report names it. A
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: 'Publish Orkestrel Release'
|
|
3
|
-
short_description: 'Run a release in layer order through the npm approval
|
|
4
|
-
default_prompt: 'Use $orkestrel-publish to run the release - layer order, per-repository visit, bump ruling, layer preparation, login approval, upload
|
|
3
|
+
short_description: 'Run a release in layer order through the npm approval, or adopt a scaffold release in one consumer'
|
|
4
|
+
default_prompt: 'Use $orkestrel-publish to run the release - layer order, per-repository visit, bump ruling, layer preparation, login approval, upload approval, and registry confirmation - or to adopt a published scaffold release in one consumer.'
|