@outerlayer/cli 0.15.0 → 0.17.0
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/CHANGELOG.md +34 -0
- package/README.md +11 -11
- package/dist/{agent-setup-CN2HUBEJ.js → agent-setup-T624CWPD.js} +8 -7
- package/dist/artifact-link-cmd-2F47LT7F.js +24 -0
- package/dist/build-info.json +1 -1
- package/dist/{check-2JSSXCKJ.js → check-5XE7XMC4.js} +22 -19
- package/dist/{chunk-HFKKFTXU.js → chunk-2MNPHL23.js} +19 -11
- package/dist/{chunk-YDSMROTB.js → chunk-3NSNIIBE.js} +8 -4
- package/dist/{chunk-FOJGZYFC.js → chunk-42ZI52JW.js} +1 -1
- package/dist/{chunk-NPQWKGUA.js → chunk-6Y5RUTHO.js} +1 -1
- package/dist/{chunk-PQUM37BK.js → chunk-BWQ66M6N.js} +1 -1
- package/dist/chunk-C5Y5ZJJZ.js +88 -0
- package/dist/{chunk-ASOSIKA4.js → chunk-G5NPRL2K.js} +27 -6
- package/dist/{chunk-QLTYTPYU.js → chunk-HGECYFEI.js} +64 -7
- package/dist/{chunk-SXWS25JC.js → chunk-KG5ECZGJ.js} +6 -6
- package/dist/{chunk-F7GBYX2P.js → chunk-LWSJQJC6.js} +18 -4
- package/dist/{chunk-UUDDPNRJ.js → chunk-MAK5LYRF.js} +33 -10
- package/dist/{chunk-MTF3PHVZ.js → chunk-NBGDBTO2.js} +3 -3
- package/dist/{chunk-KFRM23WD.js → chunk-NNRTPG7X.js} +2 -2
- package/dist/{chunk-MSASO5O4.js → chunk-NWQTTSBB.js} +1 -1
- package/dist/{chunk-2M63GG56.js → chunk-OHVJA253.js} +1 -1
- package/dist/{chunk-Z3NOIFDR.js → chunk-ONKJUM6R.js} +1 -1
- package/dist/{chunk-T5VPP6H7.js → chunk-OZGHL5Y5.js} +1 -1
- package/dist/{chunk-ZA5CHAFY.js → chunk-POJMEEJJ.js} +21 -4
- package/dist/{chunk-JR6ERP3M.js → chunk-S3NYLI2P.js} +3 -3
- package/dist/{chunk-HXLMZOKU.js → chunk-VQYBXPI7.js} +4 -4
- package/dist/{chunk-LCEXHCHD.js → chunk-WTE3MQML.js} +1 -1
- package/dist/{chunk-NXUH742G.js → chunk-WVUIRTWA.js} +10 -8
- package/dist/{chunk-JJEGKEFV.js → chunk-YU3VKZ5F.js} +1 -1
- package/dist/{chunk-3NLOVYJQ.js → chunk-YZ5F4PIS.js} +134 -38
- package/dist/{cli-RGGXQTWI.js → cli-A76AXELQ.js} +90 -79
- package/dist/{command-ETUAEXP2.js → command-R2QCVX55.js} +10 -9
- package/dist/{connect-cmd-JUAW6MU4.js → connect-cmd-JBKAQNSF.js} +1 -1
- package/dist/{context-adopt-PJUMW2EZ.js → context-adopt-NFHCLVUB.js} +5 -4
- package/dist/{context-materialize-FDHYKNDT.js → context-materialize-IV2TUUFO.js} +5 -4
- package/dist/{doctor-CORFPYY6.js → doctor-4TAIARIG.js} +15 -13
- package/dist/{emit-artifact-cmd-FOGNJXVR.js → emit-artifact-cmd-MPZVR56N.js} +4 -4
- package/dist/{emit-cmd-ZEYWLC2C.js → emit-cmd-IJ3GVRFD.js} +4 -3
- package/dist/{emit-criteria-cmd-HBP6XS5C.js → emit-criteria-cmd-EFGYI23V.js} +2 -2
- package/dist/{emit-finding-cmd-DLI4MKMN.js → emit-finding-cmd-5GF3V4LR.js} +160 -47
- package/dist/{emit-result-cmd-MUSL7GQA.js → emit-result-cmd-I4OADKMD.js} +4 -4
- package/dist/hidden-prompt-UXBFMQC5.js +68 -0
- package/dist/{hook-fast-WYQD6D7T.js → hook-fast-R4FVSZ2H.js} +1 -1
- package/dist/{import-capture-cmd-6QVCOIHK.js → import-capture-cmd-EQ35EARA.js} +3 -3
- package/dist/{import-ruler-cmd-KLRGRBCP.js → import-ruler-cmd-BGAZXCQM.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/{init-OPB7HHXO.js → init-6XPDRDTC.js} +12 -11
- package/dist/{init-MIC37V6J.js → init-PWU5YVL7.js} +54 -29
- package/dist/{init-cmd-JR3RKNFB.js → init-cmd-XAVO7HYZ.js} +11 -10
- package/dist/{init-update-O5YYFGF4.js → init-update-CVCWD6VS.js} +10 -9
- package/dist/{loop-QNSM5GXS.js → loop-FK3LPMMZ.js} +19 -18
- package/dist/{machine-IT6GG7FF.js → machine-SQXEBAM2.js} +10 -9
- package/dist/{runner-env-XTC53CHN.js → runner-env-EN7YE7QX.js} +1 -1
- package/dist/runner-key-6SLBI7PP.js +174 -0
- package/dist/{session-sender-4M247XSV.js → session-sender-FO3LCREV.js} +3 -3
- package/dist/{starter-pack-IB4UUIX3.js → starter-pack-KF66HGZR.js} +3 -3
- package/dist/{status-7ZX57OFJ.js → status-7VNQN5PW.js} +13 -12
- package/dist/{sync-cmd-UWD5JOFU.js → sync-cmd-GVPPFZ3G.js} +2 -2
- package/dist/{watch-DBNB7R6X.js → watch-23HSAEI6.js} +2 -2
- package/dist/{work-claim-cmd-A6IS6CQ7.js → work-claim-cmd-LKL3GHFQ.js} +5 -5
- package/dist/{work-cmd-EQSW5DTD.js → work-cmd-Z2WXLZPH.js} +3 -3
- package/dist/{work-comment-cmd-7VLKI7FN.js → work-comment-cmd-AWHP56M2.js} +3 -3
- package/dist/{work-open-pr-cmd-JEVD4HMQ.js → work-open-pr-cmd-IOM4AVQQ.js} +4 -4
- package/dist/{work-pr-cmd-L77K32WK.js → work-pr-cmd-HNEUIEN7.js} +3 -3
- package/package.json +1 -1
- package/skill-pack/maintained/{amend → outerlayer-amend}/SKILL.md +4 -2
- package/skill-pack/maintained/{outerlayer → outerlayer-cli}/SKILL.md +5 -3
- package/skill-pack/maintained/{emitting-evidence → outerlayer-evidence}/SKILL.md +5 -3
- package/skill-pack/maintained/{reporting-findings → outerlayer-findings}/SKILL.md +26 -30
- package/skill-pack/shipped.json +20 -4
- package/skill-pack/template/build/SKILL.md +7 -1
- package/skill-pack/template/build/references/agent-briefs.md +7 -1
- package/skill-pack/template/build/references/evidence.md +1 -1
- package/skill-pack/template/build/references/release.md +14 -12
- package/skill-pack/template/build/references/review-briefs.md +6 -0
- package/skill-pack/template/build/scripts/criterion-citations.mjs +8 -3
- package/skill-pack/template/build/scripts/record-criteria.mjs +8 -2
- package/skill-pack/template/spec/SKILL.md +2 -0
- package/skill-pack/template/writing-specs/SKILL.md +1 -1
- package/skill-pack/validators/acceptance-criteria.yaml +6 -5
- package/skill-pack/validators/code-review.yaml +6 -5
- package/dist/runner-key-7SSNMUBQ.js +0 -154
- /package/skill-pack/maintained/{outerlayer → outerlayer-cli}/references/open-pull-request.md +0 -0
- /package/skill-pack/maintained/{emitting-evidence → outerlayer-evidence}/references/agents-snippet.md +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @outerlayer/cli
|
|
2
2
|
|
|
3
|
+
## 0.17.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 420b0db: `outerlayer runner init` takes `--factory <org>/<factory>`, the same name `outerlayer init --factory` takes, so a runner host no longer needs the Factory Id copied from the dashboard. With no factory named, a login that can use exactly one factory uses it and says which. A login that can use several is refused with each `--factory` value listed. `--app-id` still works, and a `--factory` and `--app-id` that name different factories are refused.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- a3ac4ae: Count a test title such as `WC-01: counts words` as citing criterion WC-01. The starter `/build` skill's `criterion-citations.mjs` linked no test whose title put a colon straight after the id, so a build could report 0 of 4 criteria linked. A longer id such as `WC-010`, `WC-01a` or `WC-01:b` still does not cite WC-01.
|
|
12
|
+
- a897c68: The README says to install the CLI globally with `npm install -g @outerlayer/cli`, because `/build` and the other skills run the `outerlayer` command.
|
|
13
|
+
- 2a59794: Fix review results never being recorded on a new factory. The starter code-review and acceptance-criteria checks and the starter `/build` skill told agents to copy each report's link from the pull request's evidence comment, which a factory never posts until comments are turned on. They now take the link from the line `outerlayer sync` prints. A new `outerlayer sync --link <artifact id>` prints the link of an artifact an earlier sync already uploaded.
|
|
14
|
+
- 8196dc9: `outerlayer runner init` names the factory once when it picks the only one the login can use. A refused pasted key no longer repeats the gateway's "Mint a fresh key" advice beside its own step to create a new key with the Runner preset.
|
|
15
|
+
- 8196dc9: `outerlayer runner init` no longer tries to create the runner key with your login, which the gateway never allows. With no key in the config file, it prints the link to the factory's API keys page, asks you to paste a key made with the Runner preset (nothing is shown as you paste), checks it, and goes on. With no terminal it stops and prints the link and the config-file lines to use. `--key-name` is removed. Its output now marks warnings with `!` instead of a tick, no longer doubles ticks for lines from the VM, drops the PATH note about the VM's shell, and says whether capture on the Mac is affected when the runner key moves into the VM.
|
|
16
|
+
- 3ba60cd: No change in behaviour: the runner's wait for a stopped session sender's exit is simplified, and its tests check that the wait ends when the exit is logged.
|
|
17
|
+
- 0b7e87c: The starter skills run the CLI through `npx @outerlayer/cli` when `outerlayer` is not on PATH.
|
|
18
|
+
- f7553df: `outerlayer context materialize` and a container build now fetch the control plane and commit that OuterLayer stores for a repository, and read no `governs` list for it. `outerlayer doctor` reports which control plane governs the repository, its ref and the stored commit. `outerlayer connect` picks the factory that owns a repository linked to two factories, the one with the oldest connection, without asking.
|
|
19
|
+
|
|
20
|
+
## 0.16.1
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- 8f583f5: A build's log now always says the session sender exited before it says sync started. The runner waited only until the sender's process was gone, and Node can report the exit a moment later, so the two lines could swap.
|
|
25
|
+
|
|
26
|
+
## 0.16.0
|
|
27
|
+
|
|
28
|
+
### Minor Changes
|
|
29
|
+
|
|
30
|
+
- 87c8154: `outerlayer emit finding` and `emit findings` now record the time every finding cost. The start is `--started-at`, else the first tool output that contains the finding's `--error` text. The end is `--ended-at`, else the newest event. When the session has events and no start is found, nothing is stored, and the command lists the recent events with their ids. Events now include the session's subagents, with ids such as `a4962c00:e23`. `--find <text>` searches every event and records nothing. `--untimed` records a finding with no time on purpose. A session with no transcript on the machine records findings as before. The starter `/build` skill now tells its agents to record the factory problems they hit; `outerlayer init --update` brings it to repositories set up earlier.
|
|
31
|
+
- a076be0: The maintained skills now start with `outerlayer-`, so none can land on a skill of your own: `amend` is `outerlayer-amend`, `emitting-evidence` is `outerlayer-evidence`, `reporting-findings` is `outerlayer-findings`, and `outerlayer` is `outerlayer-cli`. `outerlayer context emit` writes each under its new name and deletes the old copies, so run it and commit. `--check` reports old copies as `retired`. A skill of your own with an earlier name is left alone. Governed checkouts show each skill once, under its new name, before the control plane is updated. The runner runs `/outerlayer-amend` for a command that still says `/amend`, and says so; change `runner.commands.amend` to match. `outerlayer doctor` lists skill files that still use an earlier name. See https://docs.outerlayer.ai/upgrade.
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- 7b425ca: A runner build now gives the gateway 10 seconds, and one retry, to say which control plane governs the item's repository. When the lookup still fails, `context_unavailable` says whether it timed out, what status the gateway answered, or what network error occurred. Session starts keep their 2-second limit.
|
|
36
|
+
|
|
3
37
|
## 0.15.0
|
|
4
38
|
|
|
5
39
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -13,12 +13,13 @@ network, and when, is below.
|
|
|
13
13
|
Launch a session naming the work it's for, then sync:
|
|
14
14
|
|
|
15
15
|
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
npm install -g @outerlayer/cli # puts `outerlayer` on your PATH, once per machine
|
|
17
|
+
outerlayer login # sign in, once per machine
|
|
18
|
+
outerlayer init # connect this repository to a factory, install the capture hooks
|
|
19
|
+
outerlayer work build --issue 42 --local # create the work item; prints its number
|
|
20
|
+
OUTERLAYER_WORK=7 claude # launch a session naming that number
|
|
21
|
+
outerlayer sync --dry-run # see exactly what would leave your machine
|
|
22
|
+
outerlayer sync # upload sessions launched that way
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
## Privacy, stated plainly
|
|
@@ -144,10 +145,9 @@ content:
|
|
|
144
145
|
to it.
|
|
145
146
|
- **`outerlayer runner init`** makes no network call when the config file
|
|
146
147
|
already holds a runner key. With no key there and a saved login, it
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
`GET /v1/runner/host-key`. `runner init --vm` on a Mac also runs `limactl`,
|
|
148
|
+
asks the gateway which factories the login can use (`GET /v1/me/factories`)
|
|
149
|
+
and prints the factory's API keys page. You create the key there and paste
|
|
150
|
+
it. It checks the pasted key, unsigned, with `GET /v1/runner/host-key`. `runner init --vm` on a Mac also runs `limactl`,
|
|
151
151
|
and Lima downloads a Linux VM image. Inside the VM, `apt` downloads Node and
|
|
152
152
|
`npm` downloads this CLI. Your runner key goes to the VM on the standard
|
|
153
153
|
input of a `limactl shell` command and is never a file or an argument on the
|
|
@@ -391,7 +391,7 @@ before it gives up.
|
|
|
391
391
|
| `outerlayer work claim --item <n>\|--issue <n> --kind implement\|amend [--repo] [--host] [--seconds]` | Records a lease for this host (default: its own hostname), so two hosts never build the same item at once. The lease belongs to the runner key that claimed it: a live lease held by a different key is refused, even under the same host name, and claiming again with the same key extends it. The first claim creates the host key (`host-key.pem` beside the config file) and binds the runner key to it; from then on every request made with that key is signed. Lease length defaults to 900 seconds, the server's own cap. |
|
|
392
392
|
| `outerlayer work renew --item <n>\|--issue <n> [--repo] [--host] [--seconds]` | Extends this host's own live lease. Refused if the lease has expired, or if a different runner key holds it (403 `claim_not_held`). |
|
|
393
393
|
| `outerlayer work release --item <n>\|--issue <n> [--repo] [--host] [--session-id] [--outcome]` | Marks the lease this API key holds released, optionally recording how the attempt ended. Releasing an already-released lease is a no-op that returns the recorded release time and outcome. Run inside a session with no `--host`, it releases that session's own lease instead (`--session-id` names the session when it cannot be detected), so the item's review opens without ending the session. |
|
|
394
|
-
| `outerlayer runner init [--vm\|--no-vm] [--
|
|
394
|
+
| `outerlayer runner init [--vm\|--no-vm] [--factory <org>/<factory>] [--app-id <id>] [--config <path>]` | Writes a `runner` block with defaults, keeping every key the config already had. With no `apiKey` in the config and a saved login, it prints the API keys page of the factory `--factory` or `--app-id` names (the only factory the login can use, when neither is given), asks you to paste a runner key made with the Runner preset, and checks it before anything else changes. With no terminal it stops and says what to put in the config. It names `builtin:vm` on a Linux machine where the user can use `/dev/kvm` and Docker Engine can build images once the guest kernel and helper are published (not yet), `builtin:container` on that machine until then, `builtin:container` on any other machine with Docker Engine, and `builtin:process` on one without, and writes no hook script. Refuses rather than overwriting an existing block. On macOS it asks whether to create a Linux VM with Lima, installs Docker Engine and the runner in it, and starts both at login; `--vm` answers yes and `--no-vm` answers no, and a run with no terminal answers no. The runner key and the host key then live only in the VM: the Mac's config loses `apiKey` and `runner` and gains a `runnerVm` note, which `outerlayer doctor` reads. |
|
|
395
395
|
| `outerlayer runner check [--config <path>]` | Validates the config, the hooks and the key, prints the settings the runner would use, and exits non-zero on a problem. Takes no work and writes no pid file. |
|
|
396
396
|
| `outerlayer runner start [--config <path>]` | Runs the loop: claim work, run it, sync, clean up, report, release with an outcome. Repeat. Reads the `runner` block from the config file (default `~/.outerlayer/config.json`). Refuses to start on a bad config, an unrunnable hook, or a refused key. |
|
|
397
397
|
| `outerlayer runner image --repository <owner/name> [--remote <url>] [--config <path>] [--json]` | Builds the image a repository's builds run in. Fetches the head of the default branch into the runner's cache, builds its `.devcontainer/devcontainer.json` with the devcontainer CLI, ignores every setting that reaches the host or widens the container's privileges, and adds this CLI and a pinned Claude Code. Reuses the image until the recipe or the tools change, keeps the newest three, and writes `recipe.json` beside the image record. Refuses a Compose recipe (`recipe_needs_docker`) and a repository with only named configurations (`recipe_ambiguous`). |
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
export { keepHandWritten, runAgentSetup } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
export { keepHandWritten, runAgentSetup } from './chunk-KG5ECZGJ.js';
|
|
4
|
+
import './chunk-2MNPHL23.js';
|
|
5
5
|
import './chunk-XCK2YAY5.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-42ZI52JW.js';
|
|
7
7
|
import './chunk-YRYMNBGQ.js';
|
|
8
|
-
import './chunk-
|
|
9
|
-
import './chunk-
|
|
8
|
+
import './chunk-YZ5F4PIS.js';
|
|
9
|
+
import './chunk-WTE3MQML.js';
|
|
10
|
+
import './chunk-C5Y5ZJJZ.js';
|
|
10
11
|
import './chunk-ZJSNLVCE.js';
|
|
11
12
|
import './chunk-YO4PSLVB.js';
|
|
12
13
|
import './chunk-BYT5O5RV.js';
|
|
13
|
-
import './chunk-
|
|
14
|
-
import './chunk-
|
|
14
|
+
import './chunk-POJMEEJJ.js';
|
|
15
|
+
import './chunk-OHVJA253.js';
|
|
15
16
|
import './chunk-PLMTLGYH.js';
|
|
16
17
|
import './chunk-J5M7BSJQ.js';
|
|
17
18
|
import './chunk-EABW6AJQ.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { sanitizeTerminal, readEffectiveArtifactSpoolState } from './chunk-WUYTWNMA.js';
|
|
4
|
+
import './chunk-J5M7BSJQ.js';
|
|
5
|
+
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
6
|
+
import './chunk-Z5GEFMRW.js';
|
|
7
|
+
|
|
8
|
+
createRequire(import.meta.url);
|
|
9
|
+
|
|
10
|
+
// src/artifact-link-cmd.ts
|
|
11
|
+
function lookupArtifactLink(artifactId, home = homeFromEnv()) {
|
|
12
|
+
const shown = sanitizeTerminal(artifactId);
|
|
13
|
+
const entry = readEffectiveArtifactSpoolState(home).state.get(artifactId);
|
|
14
|
+
if (entry === void 0) return { ok: false, reason: `no artifact ${shown} is queued or uploaded on this machine` };
|
|
15
|
+
if (entry.state !== "uploaded") {
|
|
16
|
+
return { ok: false, reason: `artifact ${shown} is ${entry.state}, not uploaded yet \u2014 run \`outerlayer sync\` first` };
|
|
17
|
+
}
|
|
18
|
+
if (entry.url === void 0) {
|
|
19
|
+
return { ok: false, reason: `artifact ${shown} uploaded, but the gateway returned no link for it` };
|
|
20
|
+
}
|
|
21
|
+
return { ok: true, url: entry.url };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { lookupArtifactLink };
|
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"id":"2026-10-
|
|
1
|
+
{"id":"2026-10-09T21:24:47.045Z+8773e8e","root":"/home/runner/_work/outerlayer/outerlayer","pkg":"outerlayer"}
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { probeCredentials } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { probeCredentials } from './chunk-WVUIRTWA.js';
|
|
4
|
+
import './chunk-G5NPRL2K.js';
|
|
5
|
+
import './chunk-RMWLBUCJ.js';
|
|
5
6
|
import './chunk-O765JR4W.js';
|
|
6
7
|
import './chunk-UGP76IZ5.js';
|
|
7
8
|
import './chunk-3JVYMD4G.js';
|
|
8
9
|
import './chunk-YETTWTAY.js';
|
|
9
|
-
import './chunk-RMWLBUCJ.js';
|
|
10
10
|
import './chunk-I2UOAV7X.js';
|
|
11
|
+
import './chunk-NNRTPG7X.js';
|
|
11
12
|
import './chunk-HYZRY4KZ.js';
|
|
12
13
|
import './chunk-ADJRGVZC.js';
|
|
13
|
-
import './chunk-
|
|
14
|
-
import './chunk-MSASO5O4.js';
|
|
14
|
+
import './chunk-NWQTTSBB.js';
|
|
15
15
|
import './chunk-HHJDN6AU.js';
|
|
16
|
-
import { placeholderQueues, placeholderProblem, permissionModeProblems, permissionModeProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem } from './chunk-
|
|
16
|
+
import { placeholderQueues, placeholderProblem, permissionModeProblems, permissionModeProblem, needsClaudeCredential, claudeCredentialCheck, claimPermissionProblem, formerSkillQueues, formerSkillProblem } from './chunk-LWSJQJC6.js';
|
|
17
17
|
import './chunk-YYYRBYWG.js';
|
|
18
18
|
import './chunk-TI7B7UEO.js';
|
|
19
19
|
import './chunk-TBT347UY.js';
|
|
20
|
-
import './chunk-
|
|
21
|
-
import './chunk-
|
|
22
|
-
import './chunk-
|
|
20
|
+
import './chunk-VQYBXPI7.js';
|
|
21
|
+
import './chunk-ONKJUM6R.js';
|
|
22
|
+
import './chunk-MAK5LYRF.js';
|
|
23
23
|
import './chunk-KMDLFI4P.js';
|
|
24
24
|
import './chunk-QKFB4K7X.js';
|
|
25
25
|
import './chunk-RSNSZ2LJ.js';
|
|
26
|
-
import './chunk-
|
|
26
|
+
import './chunk-OZGHL5Y5.js';
|
|
27
27
|
import './chunk-RLYZLUQ7.js';
|
|
28
28
|
import { parseRunnerEnv } from './chunk-6MZSX4M7.js';
|
|
29
|
-
import './chunk-
|
|
30
|
-
import './chunk-
|
|
29
|
+
import './chunk-S3NYLI2P.js';
|
|
30
|
+
import './chunk-6Y5RUTHO.js';
|
|
31
31
|
import './chunk-IP7BIBXJ.js';
|
|
32
32
|
import { loadRunnerConfig, RunnerConfigError, checkHooks } from './chunk-22RMZBGW.js';
|
|
33
33
|
import './chunk-UXYLWVTQ.js';
|
|
@@ -41,7 +41,7 @@ import './chunk-4Q7OMKAT.js';
|
|
|
41
41
|
import './chunk-CX22S5BA.js';
|
|
42
42
|
import './chunk-F7CU5ABH.js';
|
|
43
43
|
import './chunk-BKO6JEZI.js';
|
|
44
|
-
import './chunk-
|
|
44
|
+
import './chunk-3NSNIIBE.js';
|
|
45
45
|
import './chunk-WUYTWNMA.js';
|
|
46
46
|
import './chunk-JXYVA45C.js';
|
|
47
47
|
import './chunk-4KSQKQXE.js';
|
|
@@ -50,20 +50,21 @@ import './chunk-YRYMNBGQ.js';
|
|
|
50
50
|
import './chunk-GQD22KKN.js';
|
|
51
51
|
import './chunk-WZBHBH3J.js';
|
|
52
52
|
import './chunk-5QRP3MVS.js';
|
|
53
|
-
import './chunk-
|
|
54
|
-
import './chunk-
|
|
53
|
+
import './chunk-YZ5F4PIS.js';
|
|
54
|
+
import './chunk-WTE3MQML.js';
|
|
55
|
+
import './chunk-C5Y5ZJJZ.js';
|
|
55
56
|
import './chunk-ZJSNLVCE.js';
|
|
56
57
|
import './chunk-YO4PSLVB.js';
|
|
57
58
|
import './chunk-BYT5O5RV.js';
|
|
58
|
-
import './chunk-
|
|
59
|
-
import './chunk-
|
|
59
|
+
import './chunk-POJMEEJJ.js';
|
|
60
|
+
import './chunk-OHVJA253.js';
|
|
60
61
|
import './chunk-PLMTLGYH.js';
|
|
61
62
|
import './chunk-J5M7BSJQ.js';
|
|
62
63
|
import './chunk-EABW6AJQ.js';
|
|
63
64
|
import './chunk-RA3O54FC.js';
|
|
64
65
|
import './chunk-V7NIVOFD.js';
|
|
65
66
|
import './chunk-ZM2IMMYN.js';
|
|
66
|
-
import './chunk-
|
|
67
|
+
import './chunk-BWQ66M6N.js';
|
|
67
68
|
import './chunk-XCCLFVXM.js';
|
|
68
69
|
import './chunk-BJ3KTMDH.js';
|
|
69
70
|
import './chunk-VNVZDWO3.js';
|
|
@@ -130,6 +131,7 @@ async function runRunnerCheck(configPath, deps = {}) {
|
|
|
130
131
|
return { ok: false, check: "claim permission", message: `${configPath}: ${claimProblem.problem}` };
|
|
131
132
|
}
|
|
132
133
|
const unverifiedReason = probe.ok ? claimProblem.reason : probe.reason;
|
|
134
|
+
const formerSkill = formerSkillQueues(config);
|
|
133
135
|
const lines = [
|
|
134
136
|
`config ${configPath}`,
|
|
135
137
|
`host ${config.host}`,
|
|
@@ -145,7 +147,8 @@ async function runRunnerCheck(configPath, deps = {}) {
|
|
|
145
147
|
`hook cleanup ${config.hooks.cleanup}`,
|
|
146
148
|
`hook report ${config.hooks.report ?? "(none)"}`,
|
|
147
149
|
`repos include ${config.repos?.include?.join(", ") ?? "(all)"}`,
|
|
148
|
-
`repos exclude ${config.repos?.exclude?.join(", ") ?? "(none)"}
|
|
150
|
+
`repos exclude ${config.repos?.exclude?.join(", ") ?? "(none)"}`,
|
|
151
|
+
...formerSkill.length > 0 ? [`note ${formerSkillProblem(formerSkill)}`] : []
|
|
149
152
|
];
|
|
150
153
|
return { ok: true, lines, unverifiedReason, summary: `${config.url} \xB7 app ${config.appId}` };
|
|
151
154
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { C } from './chunk-YRYMNBGQ.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { retiredSkillPaths, removeRetiredSkills } from './chunk-C5Y5ZJJZ.js';
|
|
5
|
+
import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-POJMEEJJ.js';
|
|
6
|
+
import { emitTree, parseOuterlayerConfig, classifyTree, generatedHeaderSource, CONTEXT_PIN_FILENAME, normalizePath } from './chunk-OHVJA253.js';
|
|
6
7
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, readdirSync } from 'fs';
|
|
7
8
|
import { join, dirname, relative, sep } from 'path';
|
|
8
9
|
|
|
@@ -49,9 +50,9 @@ function walk(dir, repoRoot, insideOuterlayer, out) {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
function buildEmitInput(repoRoot, targets, maintained) {
|
|
53
|
+
function buildEmitInput(repoRoot, targets, maintained, excluded = /* @__PURE__ */ new Set()) {
|
|
53
54
|
const bundled = new Map(maintained.map((f) => [f.path, f.content]));
|
|
54
|
-
const discovered = [.../* @__PURE__ */ new Set([...discoverOuterlayerPaths(repoRoot), ...bundled.keys()])].sort();
|
|
55
|
+
const discovered = [.../* @__PURE__ */ new Set([...discoverOuterlayerPaths(repoRoot).filter((p) => !excluded.has(p)), ...bundled.keys()])].sort();
|
|
55
56
|
const { entries } = classifyTree(discovered);
|
|
56
57
|
const classified = new Set(entries.map((e) => e.path));
|
|
57
58
|
const contents = /* @__PURE__ */ new Map();
|
|
@@ -80,12 +81,13 @@ function writeOutputs(repoRoot, result, maintained) {
|
|
|
80
81
|
}
|
|
81
82
|
return { files, copies, maintained: [...changedMaintained.created, ...changedMaintained.rewritten] };
|
|
82
83
|
}
|
|
83
|
-
function renderSuccess(targets, files, copies, maintained) {
|
|
84
|
+
function renderSuccess(targets, files, copies, maintained, retired) {
|
|
84
85
|
const copySuffix = copies.length > 0 ? `, ${copies.length} ${copies.length === 1 ? "copy" : "copies"}` : "";
|
|
85
86
|
const lines = [
|
|
86
87
|
`${C.green}\u2713${C.reset} emitted ${files.length} file${files.length === 1 ? "" : "s"}${copySuffix} for ${C.dim}${targets.join(", ")}${C.reset}`
|
|
87
88
|
];
|
|
88
89
|
for (const path of maintained) lines.push(` ${C.dim}updated ${path} to this CLI's version${C.reset}`);
|
|
90
|
+
for (const path of retired) lines.push(` ${C.dim}removed ${path}: this skill has a new name${C.reset}`);
|
|
89
91
|
return lines.join("\n");
|
|
90
92
|
}
|
|
91
93
|
function renderFailure(errors) {
|
|
@@ -179,21 +181,24 @@ function runEmit(opts = {}) {
|
|
|
179
181
|
if (!existsSync(cwd)) throw new EmitError(`no such directory: ${cwd}`);
|
|
180
182
|
const targets = resolveTargetsFromConfig(cwd);
|
|
181
183
|
const maintained = maintainedFilesForExistingSkills(cwd, loadMaintainedFiles());
|
|
182
|
-
const
|
|
184
|
+
const retired = retiredSkillPaths(cwd);
|
|
185
|
+
const built = buildEmitInput(cwd, targets, maintained, new Set(retired));
|
|
183
186
|
const emitted = emitTree(built.input);
|
|
184
187
|
const { result, kept } = withholdKept(cwd, emitted, opts.keep);
|
|
185
188
|
const hasErrors = result.errors.length > 0;
|
|
186
|
-
if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, built.sourcePaths, maintained, kept);
|
|
189
|
+
if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, built.sourcePaths, maintained, kept, retired);
|
|
187
190
|
const written = hasErrors ? { files: [], copies: [], maintained: [] } : writeOutputs(cwd, result, maintained);
|
|
191
|
+
const removed = hasErrors ? [] : removeRetiredSkills(cwd);
|
|
188
192
|
const exitCode = hasErrors ? 1 : 0;
|
|
189
193
|
const output = opts.json ? JSON.stringify({
|
|
190
194
|
targets,
|
|
191
195
|
files: written.files,
|
|
192
196
|
copies: written.copies,
|
|
193
197
|
maintained: written.maintained,
|
|
198
|
+
retired: removed,
|
|
194
199
|
warnings: result.warnings,
|
|
195
200
|
errors: result.errors
|
|
196
|
-
}) : hasErrors ? renderFailure(result.errors) : renderSuccess(targets, written.files, written.copies, written.maintained);
|
|
201
|
+
}) : hasErrors ? renderFailure(result.errors) : renderSuccess(targets, written.files, written.copies, written.maintained, removed);
|
|
197
202
|
if (!opts.quiet) {
|
|
198
203
|
if (opts.json) {
|
|
199
204
|
process.stdout.write(output + "\n");
|
|
@@ -211,15 +216,17 @@ function runEmit(opts = {}) {
|
|
|
211
216
|
copies: written.copies,
|
|
212
217
|
maintained: written.maintained,
|
|
213
218
|
kept,
|
|
219
|
+
retired: removed,
|
|
214
220
|
warnings: result.warnings,
|
|
215
221
|
errors: result.errors,
|
|
216
222
|
output,
|
|
217
223
|
exitCode
|
|
218
224
|
};
|
|
219
225
|
}
|
|
220
|
-
function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained, kept) {
|
|
226
|
+
function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained, kept, retired) {
|
|
221
227
|
const drift = [];
|
|
222
228
|
if (!hasErrors) {
|
|
229
|
+
for (const path of retired) drift.push({ kind: "retired", path });
|
|
223
230
|
for (const file of maintained) {
|
|
224
231
|
const d = compareFile(cwd, file.path, file.content);
|
|
225
232
|
if (d) drift.push(d);
|
|
@@ -233,7 +240,8 @@ function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained
|
|
|
233
240
|
const d = compareCopy(cwd, copy);
|
|
234
241
|
if (d) drift.push(d);
|
|
235
242
|
}
|
|
236
|
-
|
|
243
|
+
const retiredPaths = new Set(retired);
|
|
244
|
+
drift.push(...findOrphans(cwd, computedFiles, sourcePaths).filter((d) => !retiredPaths.has(d.path)));
|
|
237
245
|
drift.sort((a, b) => a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind));
|
|
238
246
|
}
|
|
239
247
|
const exitCode = hasErrors || drift.length > 0 ? 1 : 0;
|
|
@@ -249,7 +257,7 @@ function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained
|
|
|
249
257
|
`);
|
|
250
258
|
}
|
|
251
259
|
}
|
|
252
|
-
return { targets, files: [], copies: [], maintained: [], kept, warnings: result.warnings, errors: result.errors, drift, output, exitCode };
|
|
260
|
+
return { targets, files: [], copies: [], maintained: [], kept, retired: [], warnings: result.warnings, errors: result.errors, drift, output, exitCode };
|
|
253
261
|
}
|
|
254
262
|
|
|
255
263
|
export { EmitError, runEmit };
|
|
@@ -78,6 +78,7 @@ var REASON_TEXT = {
|
|
|
78
78
|
flag: "you passed --factory",
|
|
79
79
|
saved: "already connected",
|
|
80
80
|
linked: "the repository is linked to it",
|
|
81
|
+
owner: "it owns this repository",
|
|
81
82
|
only: "the only factory you can use",
|
|
82
83
|
prompt: "you chose it"
|
|
83
84
|
};
|
|
@@ -128,18 +129,19 @@ function parseFactories(body) {
|
|
|
128
129
|
name: sanitizeTerminal(org.name),
|
|
129
130
|
displayName: sanitizeTerminal(typeof org.displayName === "string" ? org.displayName : org.name)
|
|
130
131
|
},
|
|
131
|
-
linked: typeof row.linked === "boolean" ? row.linked : null
|
|
132
|
+
linked: typeof row.linked === "boolean" ? row.linked : null,
|
|
133
|
+
owner: row.owner === true
|
|
132
134
|
});
|
|
133
135
|
}
|
|
134
136
|
return out;
|
|
135
137
|
}
|
|
136
138
|
function listText(factories, repository) {
|
|
137
|
-
return factories.map((f) => ` ${slug(f)} ${f.displayName}${f.linked === true ? ` (linked to ${repository})` : ""}`).join("\n");
|
|
139
|
+
return factories.map((f) => ` ${slug(f)} ${f.displayName}${f.linked === true && repository !== void 0 ? ` (linked to ${repository})` : ""}`).join("\n");
|
|
138
140
|
}
|
|
139
141
|
async function fetchFactories(fetchImpl, url, token, repository) {
|
|
140
142
|
let res;
|
|
141
143
|
try {
|
|
142
|
-
res = await fetchImpl(`${url.replace(/\/+$/, "")}/v1/me/factories
|
|
144
|
+
res = await fetchImpl(`${url.replace(/\/+$/, "")}/v1/me/factories${repository === void 0 ? "" : `?${new URLSearchParams({ repository }).toString()}`}`, {
|
|
143
145
|
method: "GET",
|
|
144
146
|
headers: { authorization: `Bearer ${token}` },
|
|
145
147
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
@@ -168,6 +170,8 @@ function selectFactory(factories, saved, repository) {
|
|
|
168
170
|
if (remembered) return { factory: remembered, reason: "saved" };
|
|
169
171
|
const linked = factories.filter((f) => f.linked === true);
|
|
170
172
|
if (linked.length === 1) return { factory: linked[0], reason: "linked" };
|
|
173
|
+
const owners = factories.filter((f) => f.owner);
|
|
174
|
+
if (owners.length === 1) return { factory: owners[0], reason: "owner" };
|
|
171
175
|
if (factories.length === 1) return { factory: factories[0], reason: "only" };
|
|
172
176
|
return { factory: void 0, values: factories.map(slug), text: listText(factories, repository) };
|
|
173
177
|
}
|
|
@@ -310,4 +314,4 @@ ${COMMIT_LINE}
|
|
|
310
314
|
return r.code;
|
|
311
315
|
}
|
|
312
316
|
|
|
313
|
-
export { COMMIT_LINE, autoConnectedLine, fetchFactories, isLinkedRepository, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory, workPageUrl };
|
|
317
|
+
export { COMMIT_LINE, autoConnectedLine, dashboardBase, fetchFactories, isLinkedRepository, listText, promptOnTerminal, realConnectDeps, runConnect, runConnectCommand, saveFactoryConnection, selectFactory, slug, workPageUrl };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { C } from './chunk-YRYMNBGQ.js';
|
|
4
|
-
import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-
|
|
4
|
+
import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-POJMEEJJ.js';
|
|
5
5
|
import { resolvePackageVersion } from './chunk-RA3O54FC.js';
|
|
6
6
|
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
7
7
|
import { join, dirname } from 'path';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-
|
|
3
|
+
import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-3NSNIIBE.js';
|
|
4
4
|
import { resolveRepoIdentity } from './chunk-JXYVA45C.js';
|
|
5
5
|
import { resolveGatewayCredentials } from './chunk-PLMTLGYH.js';
|
|
6
6
|
import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
|
|
@@ -634,7 +634,7 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
|
|
|
634
634
|
recordHookErrorsSeen(home, hookErrorsBytes);
|
|
635
635
|
if (contextPossiblyGoverned(sessionCwd, home)) {
|
|
636
636
|
try {
|
|
637
|
-
const { materializeContext: materialize } = await import('./context-materialize-
|
|
637
|
+
const { materializeContext: materialize } = await import('./context-materialize-IV2TUUFO.js');
|
|
638
638
|
const sessionId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
|
|
639
639
|
const result = await materialize({ cwd: sessionCwd, sessionId, home });
|
|
640
640
|
materializeMessage = result.message;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { skillDir, FORMER_MAINTAINED_NAMES, isMaintainedCopy } from './chunk-POJMEEJJ.js';
|
|
4
|
+
import { emitTree, ALL_TARGET_IDS, classifyTree } from './chunk-OHVJA253.js';
|
|
5
|
+
import { readFileSync, existsSync, unlinkSync, rmdirSync, readdirSync } from 'fs';
|
|
6
|
+
import { join, dirname, relative, sep } from 'path';
|
|
7
|
+
|
|
8
|
+
createRequire(import.meta.url);
|
|
9
|
+
function filesUnder(repoRoot, rel) {
|
|
10
|
+
try {
|
|
11
|
+
return readdirSync(join(repoRoot, rel), { recursive: true, withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => relative(repoRoot, join(entry.parentPath, entry.name)).split(sep).join("/"));
|
|
12
|
+
} catch {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function retiredSkillsPresent(repoRoot) {
|
|
17
|
+
return Object.keys(FORMER_MAINTAINED_NAMES).filter((former) => isMaintainedCopy(repoRoot, former));
|
|
18
|
+
}
|
|
19
|
+
function retiredSkillPaths(repoRoot, retired = retiredSkillsPresent(repoRoot)) {
|
|
20
|
+
const paths = /* @__PURE__ */ new Set();
|
|
21
|
+
for (const former of retired) {
|
|
22
|
+
const sources = filesUnder(repoRoot, skillDir(former));
|
|
23
|
+
const compiled = emitTree({
|
|
24
|
+
entries: classifyTree(sources).entries,
|
|
25
|
+
contents: new Map(sources.map((path) => [path, readFileSync(join(repoRoot, path), "utf8")])),
|
|
26
|
+
// A superset is safe: targets ignore a path that is not a skill asset.
|
|
27
|
+
assetPaths: sources,
|
|
28
|
+
targets: [...ALL_TARGET_IDS]
|
|
29
|
+
});
|
|
30
|
+
for (const path of [...sources, ...compiled.files.map((f) => f.path), ...compiled.copies.map((c) => c.toPath)]) paths.add(path);
|
|
31
|
+
}
|
|
32
|
+
return [...paths].filter((path) => existsSync(join(repoRoot, path))).sort();
|
|
33
|
+
}
|
|
34
|
+
function removeRetiredSkills(repoRoot, unsafe) {
|
|
35
|
+
const removed = retiredSkillPaths(repoRoot).filter((path) => !unsafe?.(path));
|
|
36
|
+
for (const path of removed) {
|
|
37
|
+
unlinkSync(join(repoRoot, path));
|
|
38
|
+
for (let dir = dirname(path); dir !== "."; dir = dirname(dir)) {
|
|
39
|
+
try {
|
|
40
|
+
rmdirSync(join(repoRoot, dir));
|
|
41
|
+
} catch {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return removed;
|
|
47
|
+
}
|
|
48
|
+
function filesNamingFormerSkills(repoRoot) {
|
|
49
|
+
const patterns = [
|
|
50
|
+
["emitting-evidence", /\bemitting-evidence\b/],
|
|
51
|
+
["reporting-findings", /\breporting-findings\b/],
|
|
52
|
+
["amend", /`amend` skill|(^|[\s"'`(])\/amend(?![\w-])/m],
|
|
53
|
+
["outerlayer", /`outerlayer` skill|skills\/outerlayer\//]
|
|
54
|
+
];
|
|
55
|
+
const retired = retiredSkillsPresent(repoRoot).map((former) => `${skillDir(former)}/`);
|
|
56
|
+
const hits = [];
|
|
57
|
+
for (const path of filesUnder(repoRoot, ".outerlayer/skills").sort()) {
|
|
58
|
+
if (retired.some((dir) => path.startsWith(dir))) continue;
|
|
59
|
+
const text = readFileSync(join(repoRoot, path), "utf8");
|
|
60
|
+
const formers = patterns.filter(([, pattern]) => pattern.test(text)).map(([former]) => former);
|
|
61
|
+
if (formers.length > 0) hits.push({ path, formers });
|
|
62
|
+
}
|
|
63
|
+
return hits;
|
|
64
|
+
}
|
|
65
|
+
function checkFormerSkillNames(repoRoot) {
|
|
66
|
+
const checks = [];
|
|
67
|
+
const retired = retiredSkillsPresent(repoRoot);
|
|
68
|
+
if (retired.length > 0) {
|
|
69
|
+
checks.push({
|
|
70
|
+
name: "Renamed skills",
|
|
71
|
+
status: "warn",
|
|
72
|
+
detail: `copies under earlier names: ${retired.map(skillDir).join(", ")}`,
|
|
73
|
+
fix: "Run `outerlayer context emit` to replace them with the current names, then commit."
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const hits = filesNamingFormerSkills(repoRoot);
|
|
77
|
+
if (hits.length > 0) {
|
|
78
|
+
checks.push({
|
|
79
|
+
name: "Skill names",
|
|
80
|
+
status: "warn",
|
|
81
|
+
detail: `${hits.map((h) => `${h.path} (${h.formers.join(", ")})`).join("; ")} still ${hits.length === 1 ? "names" : "name"} a skill by an earlier name`,
|
|
82
|
+
fix: `Replace each earlier name with the current one: ${Object.entries(FORMER_MAINTAINED_NAMES).map(([former, current]) => `${former} \u2192 ${current}`).join(", ")}. \`outerlayer init --update\` does this for a file you have not edited.`
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return checks;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { checkFormerSkillNames, removeRetiredSkills, retiredSkillPaths };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { writeJobFile, readJobFile } from './chunk-RMWLBUCJ.js';
|
|
4
|
+
import { senderPidfile } from './chunk-NNRTPG7X.js';
|
|
4
5
|
import { DOCKERD_LOG } from './chunk-HYZRY4KZ.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { AssetError, describeCallFailure, obtainImage, ensureRootfs, gitRemoteFor, startServicesFor, createBuildDisk, machineConfig, refusalCode, resolveAgentUser, AgentUserError, runBuildSteps, removeStagedContext, stageGovernedContext, shellQuote, createRunnerLog, createContainerRuntime, stopContainer, cleanupContainer, outOfMemoryReason, formatDuration, retrySend, formatClock, containerSenderCommand, syncInContainer, copyTranscriptsFromContainer, GH_CONFIG_YML, ghHostsYml, ADDED_USER, isLiteralAddress, signalInContainer, deleteBuildDisk, startCheckContainer, lifecycleSteps, lifecycleFailureReason, writeEvalInput, EVAL_INPUT_NAME, copyTranscripts, senderSignalScript } from './chunk-UUDDPNRJ.js';
|
|
6
|
+
import { installScrubContext } from './chunk-NWQTTSBB.js';
|
|
7
|
+
import { AssetError, describeCallFailure, obtainImage, ensureRootfs, gitRemoteFor, startServicesFor, createBuildDisk, machineConfig, refusalCode, resolveAgentUser, AgentUserError, runBuildSteps, removeStagedContext, stageGovernedContext, shellQuote, createRunnerLog, createContainerRuntime, stopContainer, cleanupContainer, outOfMemoryReason, formatDuration, retrySend, formatClock, containerSenderCommand, syncInContainer, copyTranscriptsFromContainer, GH_CONFIG_YML, ghHostsYml, ADDED_USER, isLiteralAddress, signalInContainer, deleteBuildDisk, startCheckContainer, lifecycleSteps, lifecycleFailureReason, writeEvalInput, EVAL_INPUT_NAME, copyTranscripts, senderSignalScript } from './chunk-MAK5LYRF.js';
|
|
8
8
|
import { childEnvironment } from './chunk-KMDLFI4P.js';
|
|
9
9
|
import { waitForAgent, vmExecArgs } from './chunk-QKFB4K7X.js';
|
|
10
10
|
import { socketPathProblem, vsockLinks, linkVsockSockets } from './chunk-RSNSZ2LJ.js';
|
|
11
|
-
import { WorkCommandError, postJson, isSignatureRefusal, getJson } from './chunk-
|
|
11
|
+
import { WorkCommandError, postJson, isSignatureRefusal, getJson } from './chunk-S3NYLI2P.js';
|
|
12
12
|
import { isBuiltinContainer, isBuiltinProcess, isBuiltinVm, DEFAULT_CHECK_TIME_LIMIT_MINUTES } from './chunk-22RMZBGW.js';
|
|
13
13
|
import { readBranchHead, diffBetween, fetchCommit } from './chunk-R7PF5OOU.js';
|
|
14
14
|
import { isSameProcess, startTimeOf } from './chunk-N5FOE5PS.js';
|
|
@@ -18,7 +18,7 @@ import { CLAUDE_CODE_VERSION } from './chunk-CX22S5BA.js';
|
|
|
18
18
|
import { planArtifactUpload } from './chunk-WUYTWNMA.js';
|
|
19
19
|
import { scrubText } from './chunk-JXYVA45C.js';
|
|
20
20
|
import { withHooksPath, authorEnvironment, commitIdentityRecord } from './chunk-BYT5O5RV.js';
|
|
21
|
-
import { parsePolicy } from './chunk-
|
|
21
|
+
import { parsePolicy } from './chunk-OHVJA253.js';
|
|
22
22
|
import { readCloudConfig } from './chunk-EABW6AJQ.js';
|
|
23
23
|
import { resolveVersion } from './chunk-RA3O54FC.js';
|
|
24
24
|
import { signerFor } from './chunk-V7NIVOFD.js';
|
|
@@ -2062,6 +2062,8 @@ async function recoverLostJobs(jobsDirPath, config, deps) {
|
|
|
2062
2062
|
// src/runner/sender.ts
|
|
2063
2063
|
var STOP_WAIT_MS = 3e4;
|
|
2064
2064
|
var POLL_MS = 200;
|
|
2065
|
+
var EXIT_REPORT_WAIT_MS = 2e3;
|
|
2066
|
+
var exitsLogged = /* @__PURE__ */ new Map();
|
|
2065
2067
|
var BUILD_HOME = "/build/home";
|
|
2066
2068
|
async function startSender(input) {
|
|
2067
2069
|
const { config, job, jobDir, deps } = input;
|
|
@@ -2072,10 +2074,16 @@ async function startSender(input) {
|
|
|
2072
2074
|
const launch = launchFor(config, job, jobDir, deps);
|
|
2073
2075
|
const fd = openSync(join(jobDir, "sender.log"), "a", RUNNER_FILE_MODE);
|
|
2074
2076
|
let pid;
|
|
2077
|
+
let exitLogged;
|
|
2075
2078
|
try {
|
|
2076
2079
|
const child = spawnFn(launch.command, launch.args, { env: launch.env, cwd: launch.cwd, detached: true, stdio: ["ignore", fd, fd] });
|
|
2077
2080
|
child.on("error", (err) => deps.log.error(`${tag} session sender failed: ${describeCallFailure(err)}`));
|
|
2078
|
-
|
|
2081
|
+
exitLogged = new Promise((resolve) => {
|
|
2082
|
+
child.on("exit", (code, signal) => {
|
|
2083
|
+
deps.log.line(`${tag} session sender exited \xB7 ${signal ?? `code ${code}`} \xB7 see sender.log`);
|
|
2084
|
+
resolve();
|
|
2085
|
+
});
|
|
2086
|
+
});
|
|
2079
2087
|
child.unref?.();
|
|
2080
2088
|
pid = child.pid;
|
|
2081
2089
|
} finally {
|
|
@@ -2085,6 +2093,7 @@ async function startSender(input) {
|
|
|
2085
2093
|
deps.log.line(`${tag} session sender did not start: no pid`);
|
|
2086
2094
|
return void 0;
|
|
2087
2095
|
}
|
|
2096
|
+
exitsLogged.set(pid, exitLogged);
|
|
2088
2097
|
deps.log.line(`${tag} session sender started \xB7 pid ${pid}`);
|
|
2089
2098
|
return { pid, start: startTimeOf(pid) ?? void 0 };
|
|
2090
2099
|
} catch (err) {
|
|
@@ -2137,6 +2146,17 @@ async function signalInGuest(runtime, state, pidfile, signal) {
|
|
|
2137
2146
|
env: { PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" }
|
|
2138
2147
|
});
|
|
2139
2148
|
}
|
|
2149
|
+
async function exitReported(pid) {
|
|
2150
|
+
const logged = exitsLogged.get(pid);
|
|
2151
|
+
let timer;
|
|
2152
|
+
const bound = new Promise((resolve) => {
|
|
2153
|
+
timer = setTimeout(resolve, EXIT_REPORT_WAIT_MS);
|
|
2154
|
+
timer.unref?.();
|
|
2155
|
+
});
|
|
2156
|
+
await Promise.race([logged, bound]);
|
|
2157
|
+
clearTimeout(timer);
|
|
2158
|
+
exitsLogged.delete(pid);
|
|
2159
|
+
}
|
|
2140
2160
|
async function stopSender(input) {
|
|
2141
2161
|
const { job, deps } = input;
|
|
2142
2162
|
const sender = job.sender;
|
|
@@ -2159,6 +2179,7 @@ async function stopSender(input) {
|
|
|
2159
2179
|
await signalInside("KILL");
|
|
2160
2180
|
signalHost(sender, "SIGKILL");
|
|
2161
2181
|
}
|
|
2182
|
+
await exitReported(sender.pid);
|
|
2162
2183
|
} catch (err) {
|
|
2163
2184
|
deps.log.error(`${tag} stopping the session sender failed: ${describeCallFailure(err)} \xB7 continuing`);
|
|
2164
2185
|
}
|