@outerlayer/cli 0.16.1 → 0.18.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 +64 -0
- package/README.md +26 -11
- package/dist/agent-setup-RBTEACYU.js +28 -0
- package/dist/artifact-link-cmd-AVM2EKTV.js +25 -0
- package/dist/{build-BG2YENGK.js → build-TQ6X5PYN.js} +5 -4
- package/dist/build-info.json +1 -1
- package/dist/{builder-2D3WSOOY.js → builder-DUI2ZH2H.js} +5 -6
- package/dist/{check-CNTMSGOG.js → check-5C4YDZYV.js} +53 -50
- package/dist/{chunk-R7PF5OOU.js → chunk-3CWUOFV6.js} +21 -14
- package/dist/{chunk-R4ZQQ7U2.js → chunk-3OFZM4X6.js} +551 -72
- package/dist/{chunk-2MNPHL23.js → chunk-47TTLEDX.js} +6 -5
- package/dist/{chunk-PLMTLGYH.js → chunk-52NC2FIU.js} +4 -3
- package/dist/chunk-6CHIYEZZ.js +564 -0
- package/dist/{chunk-TI7B7UEO.js → chunk-AMFWYESY.js} +1 -1
- package/dist/{chunk-YRYMNBGQ.js → chunk-ANPNT6PM.js} +2 -1
- package/dist/{chunk-JJEGKEFV.js → chunk-B3UKB46N.js} +6 -6
- package/dist/{chunk-JXYVA45C.js → chunk-BMYGAGBJ.js} +1050 -304
- package/dist/{chunk-4Q7OMKAT.js → chunk-BQXFBI7T.js} +81 -5
- package/dist/chunk-CRB3POP4.js +34 -0
- package/dist/{chunk-F47JBIAW.js → chunk-DSF2FWAZ.js} +2 -1
- package/dist/{chunk-N5FOE5PS.js → chunk-ECODQ7II.js} +4 -33
- package/dist/{chunk-NBGDBTO2.js → chunk-ESC6UR76.js} +6 -5
- package/dist/{chunk-HHJDN6AU.js → chunk-ESVW4MJY.js} +1 -1
- package/dist/{chunk-42ZI52JW.js → chunk-F4XSVQJ4.js} +4 -3
- package/dist/{chunk-FWX735W7.js → chunk-FUB7LRUE.js} +7 -7
- package/dist/chunk-G2YNJIGF.js +44 -0
- package/dist/{chunk-QKFB4K7X.js → chunk-GGOMT6KF.js} +1 -1
- package/dist/{chunk-CA3XMYFN.js → chunk-GOBOJMOJ.js} +6 -6
- package/dist/{chunk-N6LURUEF.js → chunk-GOSFARMS.js} +1 -1
- package/dist/chunk-JBJTC3UU.js +35 -0
- package/dist/{chunk-U3HXXRTY.js → chunk-JF42URPU.js} +16 -15
- package/dist/{chunk-ADJRGVZC.js → chunk-KDVIU23F.js} +1 -1
- package/dist/{chunk-6QRMLNH3.js → chunk-KK4VBOH6.js} +93 -37
- package/dist/{chunk-KMDLFI4P.js → chunk-L2USZT6T.js} +1 -1
- package/dist/{chunk-WTE3MQML.js → chunk-LXAY4A2G.js} +3 -12
- package/dist/{chunk-V7NIVOFD.js → chunk-M2ZWWTWZ.js} +1 -1
- package/dist/{chunk-ERI5GBNI.js → chunk-MLAAT4S6.js} +3 -3
- package/dist/{chunk-POJMEEJJ.js → chunk-MNTSH4CL.js} +1 -1
- package/dist/{chunk-WUYTWNMA.js → chunk-MQJSXHV7.js} +1 -1
- package/dist/{chunk-O765JR4W.js → chunk-MTP2QEVO.js} +1 -1
- package/dist/{chunk-ZM2IMMYN.js → chunk-N2PXGQRL.js} +9 -1
- package/dist/{chunk-J5M7BSJQ.js → chunk-N3CUDFCW.js} +9 -3
- package/dist/{chunk-4KSQKQXE.js → chunk-NACDBXUG.js} +19 -15
- package/dist/{chunk-RSPXEVDX.js → chunk-NL4XPC7W.js} +1 -1
- package/dist/{chunk-EHAAPRWY.js → chunk-QQM2UJ6T.js} +31 -26
- package/dist/{chunk-5FEK6PNE.js → chunk-RAZTWYZN.js} +10 -9
- package/dist/{chunk-4NPZVMJU.js → chunk-S26M3YBJ.js} +60 -4
- package/dist/{chunk-UGP76IZ5.js → chunk-S5PCA3SN.js} +1 -1
- package/dist/{chunk-YDSMROTB.js → chunk-S76AYB4M.js} +25 -20
- package/dist/{chunk-RMWLBUCJ.js → chunk-SADUQSO4.js} +1 -1
- package/dist/{chunk-OZGHL5Y5.js → chunk-SWCTGCSC.js} +2 -2
- package/dist/{chunk-GQD22KKN.js → chunk-T2Q7ISPE.js} +2 -1
- package/dist/{chunk-C5Y5ZJJZ.js → chunk-T4Y6SCG3.js} +5 -4
- package/dist/{chunk-6JNURGOA.js → chunk-ULSIJGLS.js} +45 -13
- package/dist/{chunk-ONRCEE6D.js → chunk-UYOYTKE2.js} +4 -4
- package/dist/{chunk-PTW6W5NR.js → chunk-VYAL7PUE.js} +1 -1
- package/dist/{chunk-JEHRUE3F.js → chunk-W5VPCONO.js} +166 -196
- package/dist/{chunk-NPQWKGUA.js → chunk-WBT5X3NH.js} +5 -4
- package/dist/{chunk-RLYZLUQ7.js → chunk-WGAUY5LE.js} +2 -2
- package/dist/{chunk-RSNSZ2LJ.js → chunk-X5H2WYMB.js} +1 -1
- package/dist/{chunk-OHVJA253.js → chunk-X5N6KC6V.js} +47 -29
- package/dist/{chunk-22RMZBGW.js → chunk-XGP3VYOG.js} +1 -1
- package/dist/{chunk-HYZRY4KZ.js → chunk-XNGMQ27R.js} +16 -6
- package/dist/{chunk-W3EKCZSQ.js → chunk-Y5GE76XC.js} +180 -53
- package/dist/{chunk-EWORLJMO.js → chunk-Y5MXET4M.js} +277 -526
- package/dist/{chunk-XCK2YAY5.js → chunk-YVZJ6GKF.js} +3 -2
- package/dist/{chunk-YO4PSLVB.js → chunk-ZRL6HKBY.js} +1 -1
- package/dist/claude-launcher-YVXI76NX.js +102 -0
- package/dist/{cli-AEWH62UE.js → cli-C77H54BV.js} +489 -174
- package/dist/{command-HHPBR6CS.js → command-H5CILO4S.js} +40 -37
- package/dist/{config-N3C6DFQA.js → config-FXDG4NPJ.js} +2 -3
- package/dist/connect-cmd-ZW5FV3ZW.js +17 -0
- package/dist/{context-adopt-VMMGFRUZ.js → context-adopt-O5OFXMKI.js} +13 -12
- package/dist/context-materialize-Y5IJ4MQT.js +23 -0
- package/dist/{dist-LKDWQWZ7.js → dist-QTX4RSCL.js} +2 -2
- package/dist/{docker-4J77Q2BF.js → docker-RC3PRX3Q.js} +7 -8
- package/dist/{doctor-N6Y7HKK3.js → doctor-2NQQML6P.js} +47 -39
- package/dist/{emit-artifact-cmd-H5MH3AOP.js → emit-artifact-cmd-7MP63KXU.js} +25 -22
- package/dist/emit-cmd-PPN4QQF2.js +14 -0
- package/dist/{emit-criteria-cmd-HBP6XS5C.js → emit-criteria-cmd-3RXPDLNK.js} +16 -14
- package/dist/{emit-finding-cmd-ZXDRL6PG.js → emit-finding-cmd-OL7JB6H3.js} +18 -16
- package/dist/{emit-result-cmd-RFKALS5Z.js → emit-result-cmd-UZVMOCF4.js} +20 -17
- package/dist/{exec-client-CQV746UF.js → exec-client-7UMESIE2.js} +3 -4
- package/dist/governing-source-BUU4IABS.js +35 -0
- package/dist/guest-init-KPBQOFE5.js +9 -0
- package/dist/hidden-prompt-UXBFMQC5.js +68 -0
- package/dist/{hook-fast-D7HV4IXG.js → hook-fast-W5MKHMJT.js} +4 -1
- package/dist/host-key-U4B5QETR.js +8 -0
- package/dist/{import-capture-cmd-EQ35EARA.js → import-capture-cmd-ZO6KGHI2.js} +7 -5
- package/dist/{import-ruler-cmd-BGAZXCQM.js → import-ruler-cmd-KJMWL5V6.js} +5 -3
- package/dist/index.js +8 -4
- package/dist/init-VWXIZEAN.js +54 -0
- package/dist/{init-FBCA4DRA.js → init-WNXXYMO7.js} +80 -53
- package/dist/{init-cmd-CAG572UE.js → init-cmd-WS6TIRYT.js} +28 -24
- package/dist/{init-update-VDFF4K3B.js → init-update-E3J6TVIN.js} +27 -26
- package/dist/{install-HDBIPHTX.js → install-CBWIEF3R.js} +4 -5
- package/dist/{install-cmd-5HYMXLEW.js → install-cmd-QDOTR4OM.js} +5 -4
- package/dist/{login-browser-QZCS3WW6.js → login-browser-O63QZN7D.js} +4 -3
- package/dist/{logout-cmd-QAUFDJ6J.js → logout-cmd-5V5MMBSY.js} +3 -2
- package/dist/{logs-H55NWW4H.js → logs-AMLKC3VP.js} +3 -1
- package/dist/loop-UGI2BJOT.js +76 -0
- package/dist/machine-JOW4RNZ7.js +49 -0
- package/dist/{mcp-install-cmd-FDTPQQS6.js → mcp-install-cmd-GGWB3JJ2.js} +3 -2
- package/dist/{mcp-serve-cmd-3KVYEUXG.js → mcp-serve-cmd-DOTY5FKY.js} +10 -8
- package/dist/paths-7XP63OAX.js +7 -0
- package/dist/pending-532ABZYC.js +8 -0
- package/dist/{pidfile-UZRH774M.js → pidfile-3DM4OBKO.js} +4 -2
- package/dist/{record-C43U4PKS.js → record-3WP6V2K5.js} +3 -2
- package/dist/{runner-env-EN7YE7QX.js → runner-env-4NB2GA7O.js} +5 -6
- package/dist/runner-key-TC3NFWFV.js +177 -0
- package/dist/{session-sender-24L5EW25.js → session-sender-NNVPSPY7.js} +17 -14
- package/dist/spec-cmd-OWVTBB4J.js +116 -0
- package/dist/{starter-pack-KF66HGZR.js → starter-pack-OPWUDOWX.js} +7 -5
- package/dist/{status-XHSGEYO5.js → status-TKCLLKFG.js} +42 -39
- package/dist/{statusline-fast-SVTMBMD7.js → statusline-fast-KN3BX67H.js} +2 -1
- package/dist/{sync-cmd-5G5EIEHD.js → sync-cmd-Q6VYNPWG.js} +16 -13
- package/dist/{watch-UTOXO4SE.js → watch-ARAGADTF.js} +16 -13
- package/dist/{work-claim-cmd-RKHYFE5Y.js → work-claim-cmd-34FERLYX.js} +25 -27
- package/dist/work-cmd-7S5B2H2P.js +25 -0
- package/dist/{work-comment-cmd-A55CUSYE.js → work-comment-cmd-SZJSPM5S.js} +15 -13
- package/dist/{work-launch-R5HTAP6X.js → work-launch-LEQ2MPM3.js} +3 -1
- package/dist/{work-open-pr-cmd-E6O53IJD.js → work-open-pr-cmd-RPXKCBWS.js} +17 -15
- package/dist/work-pr-cmd-5LGANL32.js +26 -0
- package/package.json +3 -2
- package/skill-pack/maintained/outerlayer-amend/SKILL.md +6 -2
- package/skill-pack/maintained/outerlayer-cli/SKILL.md +2 -0
- package/skill-pack/maintained/outerlayer-evidence/SKILL.md +4 -2
- package/skill-pack/maintained/outerlayer-findings/SKILL.md +2 -0
- package/skill-pack/shipped.json +27 -5
- package/skill-pack/template/build/SKILL.md +25 -10
- package/skill-pack/template/build/references/agent-briefs.md +3 -1
- package/skill-pack/template/build/references/criteria-judge.md +27 -0
- package/skill-pack/template/build/references/release.md +27 -34
- 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 +37 -10
- package/skill-pack/validators/acceptance-criteria.yaml +25 -25
- package/skill-pack/validators/code-review.yaml +6 -5
- package/dist/agent-setup-K3ABU5NL.js +0 -27
- package/dist/chunk-BYT5O5RV.js +0 -61
- package/dist/connect-cmd-JUAW6MU4.js +0 -16
- package/dist/context-materialize-2WXTS4CW.js +0 -22
- package/dist/emit-cmd-IJ3GVRFD.js +0 -12
- package/dist/guest-init-LJP5GPZF.js +0 -9
- package/dist/host-key-YMLXY6QB.js +0 -7
- package/dist/init-MYX7YMIH.js +0 -51
- package/dist/loop-75J4YXLZ.js +0 -73
- package/dist/machine-A6ZCTUGS.js +0 -46
- package/dist/paths-OYKMVYJP.js +0 -6
- package/dist/pending-MXLSRYMO.js +0 -7
- package/dist/runner-key-W25ISHI3.js +0 -155
- package/dist/work-cmd-DJQJEZVB.js +0 -23
- package/dist/work-pr-cmd-L77K32WK.js +0 -24
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { gatherDoctorChecks, doctorExitCode, summarizeChecks, renderDoctorText, recordWrapped, recordUnwrapped, recordRemoval, readManifest, recordInstall, recordStatusline } from './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import './chunk-
|
|
3
|
+
import { gatherDoctorChecks, doctorExitCode, summarizeChecks, renderDoctorText, recordWrapped, recordUnwrapped, recordRemoval, readManifest, recordInstall, recordStatusline } from './chunk-Y5GE76XC.js';
|
|
4
|
+
import './chunk-ESC6UR76.js';
|
|
5
|
+
import { verifiedTrackerNames, TRACKERS } from './chunk-KK4VBOH6.js';
|
|
6
|
+
import './chunk-WBT5X3NH.js';
|
|
7
7
|
import './chunk-IP7BIBXJ.js';
|
|
8
|
-
import './chunk-
|
|
8
|
+
import './chunk-S76AYB4M.js';
|
|
9
|
+
import './chunk-MQJSXHV7.js';
|
|
10
|
+
import './chunk-DSF2FWAZ.js';
|
|
9
11
|
import './chunk-BKO6JEZI.js';
|
|
10
|
-
import './chunk-
|
|
11
|
-
import './chunk-
|
|
12
|
-
import './chunk-
|
|
13
|
-
import './chunk-
|
|
14
|
-
import './chunk-
|
|
15
|
-
import './chunk-
|
|
16
|
-
import './chunk-N6LURUEF.js';
|
|
17
|
-
import { C, NO_COLOR_FLAG, warnDeprecated, stripNoColor, API_KEY_FLAG_DEPRECATION } from './chunk-YRYMNBGQ.js';
|
|
12
|
+
import './chunk-BMYGAGBJ.js';
|
|
13
|
+
import './chunk-YVZJ6GKF.js';
|
|
14
|
+
import './chunk-F4XSVQJ4.js';
|
|
15
|
+
import './chunk-NACDBXUG.js';
|
|
16
|
+
import './chunk-GOSFARMS.js';
|
|
17
|
+
import { C, NO_COLOR_FLAG, warnDeprecated, stripNoColor, API_KEY_FLAG_DEPRECATION } from './chunk-ANPNT6PM.js';
|
|
18
18
|
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
19
19
|
import { settingsPath, readSettings, SettingsParseError, listHookCandidates, wrapHooks, writeSettings, unwrapHooks, REGISTERED_EVENTS, cliCommand, removeHooks, removeStatusline, cliBinResolvable, mergeHooks, repointWrappedHooks, AUTO_WRAP_EVENTS, mergeStatusline } from './chunk-5QRP3MVS.js';
|
|
20
|
-
import { pinExists } from './chunk-
|
|
21
|
-
import './chunk-
|
|
22
|
-
import './chunk-
|
|
23
|
-
import './chunk-
|
|
24
|
-
import './chunk-
|
|
25
|
-
import './chunk-
|
|
26
|
-
import './chunk-
|
|
20
|
+
import { pinExists } from './chunk-LXAY4A2G.js';
|
|
21
|
+
import './chunk-T4Y6SCG3.js';
|
|
22
|
+
import './chunk-ZRL6HKBY.js';
|
|
23
|
+
import './chunk-52NC2FIU.js';
|
|
24
|
+
import './chunk-MNTSH4CL.js';
|
|
25
|
+
import './chunk-X5N6KC6V.js';
|
|
26
|
+
import './chunk-N3CUDFCW.js';
|
|
27
27
|
import './chunk-EABW6AJQ.js';
|
|
28
28
|
import { resolveVersion } from './chunk-RA3O54FC.js';
|
|
29
|
-
import './chunk-
|
|
30
|
-
import './chunk-
|
|
31
|
-
import
|
|
29
|
+
import './chunk-M2ZWWTWZ.js';
|
|
30
|
+
import './chunk-N2PXGQRL.js';
|
|
31
|
+
import './chunk-BQXFBI7T.js';
|
|
32
|
+
import { hookFiredMarkerPath, installedCliDistDir } from './chunk-ULSIJGLS.js';
|
|
33
|
+
import './chunk-G2YNJIGF.js';
|
|
32
34
|
import { managedHookScripts, removeJournalHooks, installPreCommitGuardHook, removePreCommitGuardHook } from './chunk-XCCLFVXM.js';
|
|
35
|
+
import './chunk-ZJSNLVCE.js';
|
|
33
36
|
import './chunk-BJ3KTMDH.js';
|
|
37
|
+
import { cliInvocation, packageRunnerOf } from './chunk-CRB3POP4.js';
|
|
34
38
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
35
39
|
import './chunk-Z5GEFMRW.js';
|
|
36
40
|
import { EventEmitter } from 'events';
|
|
@@ -3400,7 +3404,7 @@ function useColor() {
|
|
|
3400
3404
|
// ../../node_modules/commander/index.js
|
|
3401
3405
|
new Command();
|
|
3402
3406
|
function isEphemeralBin(bin) {
|
|
3403
|
-
return bin
|
|
3407
|
+
return packageRunnerOf(bin) !== void 0;
|
|
3404
3408
|
}
|
|
3405
3409
|
function initHookBin(opts) {
|
|
3406
3410
|
const { runningBin } = opts;
|
|
@@ -3610,11 +3614,12 @@ function orgRolloutSnippet(cliBin) {
|
|
|
3610
3614
|
"managed-settings.json:",
|
|
3611
3615
|
managed,
|
|
3612
3616
|
"",
|
|
3613
|
-
|
|
3617
|
+
`Each developer still runs \`${cliInvocation()} login\` once to attribute sessions.`
|
|
3614
3618
|
].join("\n");
|
|
3615
3619
|
}
|
|
3616
3620
|
|
|
3617
3621
|
// src/cli.ts
|
|
3622
|
+
var TRACKER_OPTION_FLAG = `--tracker <${verifiedTrackerNames(TRACKERS).join("|")}>`;
|
|
3618
3623
|
function resolveCliBin() {
|
|
3619
3624
|
try {
|
|
3620
3625
|
return fileURLToPath(new URL("./index.js", import.meta.url));
|
|
@@ -3632,7 +3637,7 @@ function printLauncher(result, summary) {
|
|
|
3632
3637
|
const line = summary(result.launcher);
|
|
3633
3638
|
if (line !== void 0) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
|
|
3634
3639
|
`);
|
|
3635
|
-
for (const note of result.launcher.notes) process.stdout.write(`${C.yellow}
|
|
3640
|
+
for (const note of result.launcher.notes) process.stdout.write(`${C.yellow}!${C.reset} ${note}
|
|
3636
3641
|
`);
|
|
3637
3642
|
}
|
|
3638
3643
|
function writeJson(value) {
|
|
@@ -3640,13 +3645,13 @@ function writeJson(value) {
|
|
|
3640
3645
|
`);
|
|
3641
3646
|
}
|
|
3642
3647
|
function apiKeyOption() {
|
|
3643
|
-
return new Option("--api-key <key>",
|
|
3648
|
+
return new Option("--api-key <key>", `deprecated: use \`${cliInvocation()} login\` or OUTERLAYER_API_KEY`).hideHelp();
|
|
3644
3649
|
}
|
|
3645
3650
|
function warnIfApiKeyFlag(opts) {
|
|
3646
3651
|
if (opts.apiKey !== void 0) warnDeprecated(API_KEY_FLAG_DEPRECATION);
|
|
3647
3652
|
}
|
|
3648
3653
|
async function installStarterPackInRepo() {
|
|
3649
|
-
const { installStarterPack, formatStarterPackOutput } = await import('./starter-pack-
|
|
3654
|
+
const { installStarterPack, formatStarterPackOutput } = await import('./starter-pack-OPWUDOWX.js');
|
|
3650
3655
|
const cwd = process.cwd();
|
|
3651
3656
|
let repoRoot = cwd;
|
|
3652
3657
|
try {
|
|
@@ -3687,7 +3692,7 @@ ${C.dim} backup: ${result.backupPath}${C.reset}` : ""}
|
|
|
3687
3692
|
}
|
|
3688
3693
|
if (result.wrapped.length > 0) {
|
|
3689
3694
|
lines.push(
|
|
3690
|
-
`${C.green}\u2713${C.reset} Auto-wrapped ${result.wrapped.length} hook(s) for execution evidence (adds one spawn per firing \u2014 see ${C.yellow}
|
|
3695
|
+
`${C.green}\u2713${C.reset} Auto-wrapped ${result.wrapped.length} hook(s) for execution evidence (adds one spawn per firing \u2014 see ${C.yellow}${cliInvocation()} hooks unwrap${C.reset} to undo):
|
|
3691
3696
|
`
|
|
3692
3697
|
);
|
|
3693
3698
|
for (const w of result.wrapped) {
|
|
@@ -3729,9 +3734,12 @@ cannot be disabled.
|
|
|
3729
3734
|
(opts.next === false ? "\n" : `
|
|
3730
3735
|
Next: launch a session naming its work item, then sync it:
|
|
3731
3736
|
${C.yellow}OUTERLAYER_WORK=42 claude${C.reset}
|
|
3732
|
-
${C.yellow}
|
|
3737
|
+
${C.yellow}${cliInvocation()} sync${C.reset}
|
|
3733
3738
|
|
|
3734
|
-
`) + (opts.connected ? "This repository is connected to a factory, so launched sessions sync\nautomatically in the background after each agent turn and at the end\nof the session, at most once every five minutes.\n" :
|
|
3739
|
+
`) + (opts.connected ? "This repository is connected to a factory, so launched sessions sync\nautomatically in the background after each agent turn and at the end\nof the session, at most once every five minutes.\n" : `Once you have run ${cliInvocation()} login and ${cliInvocation()} init in this repository,
|
|
3740
|
+
launched sessions sync automatically in the background after each agent
|
|
3741
|
+
turn and at the end of the session, at most once every five minutes.
|
|
3742
|
+
`)
|
|
3735
3743
|
);
|
|
3736
3744
|
return lines.join("");
|
|
3737
3745
|
}
|
|
@@ -3748,7 +3756,7 @@ function formatGuardInstallOutput(guard) {
|
|
|
3748
3756
|
return {
|
|
3749
3757
|
lines: [
|
|
3750
3758
|
`${C.yellow}!${C.reset} a pre-commit hook we did not write already exists (${guard.path}) \u2014 left untouched.`,
|
|
3751
|
-
` Append the guard script yourself: ${C.yellow}
|
|
3759
|
+
` Append the guard script yourself: ${C.yellow}${cliInvocation()} hooks install-git --print${C.reset}`,
|
|
3752
3760
|
` Place it before any exit in the existing hook \u2014 code after an early exit never runs.`
|
|
3753
3761
|
],
|
|
3754
3762
|
exitCode: 1
|
|
@@ -3760,7 +3768,7 @@ function formatGuardInstallOutput(guard) {
|
|
|
3760
3768
|
return {
|
|
3761
3769
|
lines: [
|
|
3762
3770
|
`${C.yellow}!${C.reset} this repo manages hooks in its working tree (core.hooksPath) \u2014 nothing written.`,
|
|
3763
|
-
` Add the script to your hook manager instead: ${C.yellow}
|
|
3771
|
+
` Add the script to your hook manager instead: ${C.yellow}${cliInvocation()} hooks install-git --print${C.reset}`
|
|
3764
3772
|
],
|
|
3765
3773
|
exitCode: 1
|
|
3766
3774
|
};
|
|
@@ -3775,7 +3783,7 @@ async function installHooks(opts, resolvedBin, connected, starterTemplate, withN
|
|
|
3775
3783
|
cliBin = initHookBin({ home: homeFromEnv(), runningBin: resolvedBin, remove: opts.remove === true });
|
|
3776
3784
|
} catch (err) {
|
|
3777
3785
|
const text = `could not copy the CLI to ~/.outerlayer/cli: ${err instanceof Error ? err.message : String(err)}
|
|
3778
|
-
Hooks were not changed. Fix the permissions on ~/.outerlayer, then re-run ${C.yellow}
|
|
3786
|
+
Hooks were not changed. Fix the permissions on ~/.outerlayer, then re-run ${C.yellow}${cliInvocation()} init${C.reset}.`;
|
|
3779
3787
|
return { ok: false, text, detail: "could not copy the CLI to ~/.outerlayer/cli" };
|
|
3780
3788
|
}
|
|
3781
3789
|
try {
|
|
@@ -3789,7 +3797,7 @@ async function installHooks(opts, resolvedBin, connected, starterTemplate, withN
|
|
|
3789
3797
|
});
|
|
3790
3798
|
if (result.cliBinUnresolved) {
|
|
3791
3799
|
const text = `the resolved CLI path (${cliBin}) does not exist \u2014 refusing to write hook entries pointing at it.
|
|
3792
|
-
Reinstall OuterLayer, then re-run ${C.yellow}
|
|
3800
|
+
Reinstall OuterLayer, then re-run ${C.yellow}${cliInvocation()} init${C.reset}.`;
|
|
3793
3801
|
return { ok: false, text, detail: "the CLI path does not exist" };
|
|
3794
3802
|
}
|
|
3795
3803
|
const starter = starterTemplate === void 0 ? null : await installStarterPackInRepo();
|
|
@@ -3806,8 +3814,8 @@ ${starter.output}`),
|
|
|
3806
3814
|
}
|
|
3807
3815
|
}
|
|
3808
3816
|
async function realConnectDepsForCwd() {
|
|
3809
|
-
const { realConnectDeps } = await import('./connect-cmd-
|
|
3810
|
-
const { resolveRepoIdentity } = await import('./dist-
|
|
3817
|
+
const { realConnectDeps } = await import('./connect-cmd-ZW5FV3ZW.js');
|
|
3818
|
+
const { resolveRepoIdentity } = await import('./dist-QTX4RSCL.js');
|
|
3811
3819
|
return {
|
|
3812
3820
|
...realConnectDeps(),
|
|
3813
3821
|
home: homeFromEnv(),
|
|
@@ -3822,13 +3830,53 @@ function invokedCommandToken(argv) {
|
|
|
3822
3830
|
}
|
|
3823
3831
|
function buildProgram(argv = process.argv) {
|
|
3824
3832
|
const program2 = new Command();
|
|
3825
|
-
program2.name(
|
|
3826
|
-
program2.command("init").description("Connect this repository, install hooks and agent skills, run doctor").option("--user", "install into user settings [default]").option("--project", "install into project settings (./.claude/settings.json)").option("--org", "print a managed-settings.json snippet for MDM/GPO rollout").option("--remove", "uninstall OuterLayer hooks").option("--local", "install the hooks only: no connect step and no network call").option("--factory <org/factory>",
|
|
3833
|
+
program2.name(cliInvocation()).description("OuterLayer \u2014 see what your coding agents actually do").enablePositionalOptions().version(resolveVersion()).option(NO_COLOR_FLAG, "disable color (NO_COLOR=1 does the same)").addHelpText("after", SUPPORT_TEXT);
|
|
3834
|
+
program2.command("init").description("Connect this repository, install hooks and agent skills, run doctor").option("--user", "install into user settings [default]").option("--project", "install into project settings (./.claude/settings.json)").option("--org", "print a managed-settings.json snippet for MDM/GPO rollout").option("--remove", "uninstall OuterLayer hooks").option("--local", "install the hooks only: no connect step and no network call").option("--factory <org/factory>", `the factory to connect this repository to (see \`${cliInvocation()} connect\`)`).option("--gitignore", "also add .outerlayer/ to .gitignore (project scope)").option("--template <name>", "install the starter skills and a policy file (only: default)").option("--update", "update the files init wrote that you have not edited, and write missing ones").option("--dry-run", "with --update: print the plan and write nothing").option("--no-wrap-hooks", "leave PreToolUse/PostToolUse hooks unwrapped").option("--statusline", "install the status-line segment [default]").option("--no-statusline", "leave the statusLine slot untouched").option("--json", "machine-readable JSON output").addHelpText(
|
|
3827
3835
|
"after",
|
|
3828
|
-
|
|
3836
|
+
`
|
|
3837
|
+
In a repository, init runs four steps: connect the repository to a
|
|
3838
|
+
factory (\`${cliInvocation()} connect\`), install the hooks, set up the coding agent,
|
|
3839
|
+
and run \`${cliInvocation()} doctor\`. It never signs in and asks nothing. With no
|
|
3840
|
+
login it skips the connect step and says to run \`${cliInvocation()} login\`. With
|
|
3841
|
+
--json it prints one document naming the outcome of each step: done,
|
|
3842
|
+
skipped or failed. The exit code is 1 when a step failed.
|
|
3843
|
+
|
|
3844
|
+
The agent setup step installs the starter skills and the \`outerlayer\` skill
|
|
3845
|
+
into .outerlayer/skills/, writes .outerlayer/config.json for Claude Code when
|
|
3846
|
+
there is none, runs \`${cliInvocation()} context emit\` so the skills appear in
|
|
3847
|
+
.claude/skills/, and adds the outerlayer and outerlayer-docs MCP servers to
|
|
3848
|
+
.mcp.json. Nothing you wrote is changed: an existing config, policy, edited
|
|
3849
|
+
skill, MCP entry or root CLAUDE.md and AGENTS.md is left as it is, and a
|
|
3850
|
+
hand-written file the emit would replace is kept and listed. The files are
|
|
3851
|
+
left uncommitted.
|
|
3852
|
+
The step is skipped outside a git repository and in a repository whose
|
|
3853
|
+
context comes from a control plane, where it arrives at session start.
|
|
3854
|
+
|
|
3855
|
+
--local installs only the hooks: no connect step, no agent setup and no
|
|
3856
|
+
network call. Add \`--template default\` to also write the starter skills and
|
|
3857
|
+
a policy file into .outerlayer/ without compiling them; \`${cliInvocation()} context
|
|
3858
|
+
emit\` does that.
|
|
3859
|
+
|
|
3860
|
+
Idempotent: settings are backed up before any write, and a second run
|
|
3861
|
+
changes nothing. Wrapping adds one spawn per hook firing; undo it with
|
|
3862
|
+
\`${cliInvocation()} hooks unwrap\`. An occupied status-line slot is wrapped, never
|
|
3863
|
+
replaced.
|
|
3864
|
+
|
|
3865
|
+
Three of the starter skills are copied once and are yours to edit. The
|
|
3866
|
+
others are rewritten from this CLI on every \`context emit\`.
|
|
3867
|
+
|
|
3868
|
+
--update brings the files init wrote once up to this CLI's version: the
|
|
3869
|
+
template skills, the policy, the two starter checks and the two MCP
|
|
3870
|
+
entries. A file still equal to a version an earlier release wrote is
|
|
3871
|
+
replaced, and a missing one is written. A file you edited is never
|
|
3872
|
+
touched. It then runs \`${cliInvocation()} context emit\` and leaves the changes
|
|
3873
|
+
uncommitted. --dry-run prints the plan, with a command to compare each
|
|
3874
|
+
edited file, and writes nothing. \`${cliInvocation()} doctor\` reports the same
|
|
3875
|
+
states under Starter files.
|
|
3876
|
+
`
|
|
3829
3877
|
).action(async (opts) => {
|
|
3830
3878
|
if (opts.update || opts.dryRun) {
|
|
3831
|
-
const { runInitUpdate, formatInitUpdate, updateFlagProblem } = await import('./init-update-
|
|
3879
|
+
const { runInitUpdate, formatInitUpdate, updateFlagProblem } = await import('./init-update-E3J6TVIN.js');
|
|
3832
3880
|
const problem = updateFlagProblem(opts);
|
|
3833
3881
|
if (problem !== void 0) {
|
|
3834
3882
|
fail(problem);
|
|
@@ -3842,7 +3890,7 @@ function buildProgram(argv = process.argv) {
|
|
|
3842
3890
|
}
|
|
3843
3891
|
let starterTemplate;
|
|
3844
3892
|
if (opts.template !== void 0) {
|
|
3845
|
-
const { assertKnownTemplate, StarterPackError } = await import('./starter-pack-
|
|
3893
|
+
const { assertKnownTemplate, StarterPackError } = await import('./starter-pack-OPWUDOWX.js');
|
|
3846
3894
|
try {
|
|
3847
3895
|
assertKnownTemplate(opts.template);
|
|
3848
3896
|
} catch (err) {
|
|
@@ -3873,7 +3921,7 @@ function buildProgram(argv = process.argv) {
|
|
|
3873
3921
|
else process.stdout.write(outcome.text);
|
|
3874
3922
|
return;
|
|
3875
3923
|
}
|
|
3876
|
-
const { runInitCommand } = await import('./init-cmd-
|
|
3924
|
+
const { runInitCommand } = await import('./init-cmd-WS6TIRYT.js');
|
|
3877
3925
|
const code = await runInitCommand(
|
|
3878
3926
|
{ json: opts.json, factory: opts.factory },
|
|
3879
3927
|
{
|
|
@@ -3885,7 +3933,7 @@ function buildProgram(argv = process.argv) {
|
|
|
3885
3933
|
return { ok, text, detail };
|
|
3886
3934
|
},
|
|
3887
3935
|
runAgentSetup: async () => {
|
|
3888
|
-
const { runAgentSetup } = await import('./agent-setup-
|
|
3936
|
+
const { runAgentSetup } = await import('./agent-setup-RBTEACYU.js');
|
|
3889
3937
|
return runAgentSetup({ cwd: process.cwd() });
|
|
3890
3938
|
},
|
|
3891
3939
|
runDoctorChecks: gatherDoctorChecks
|
|
@@ -3895,9 +3943,29 @@ function buildProgram(argv = process.argv) {
|
|
|
3895
3943
|
});
|
|
3896
3944
|
program2.command("connect").description("Choose the factory this repository's work goes to").option("--factory <org/factory>", "the factory to use: <org>/<factory> as in its dashboard address, or a factory id").option("--json", "write one JSON document to stdout; the text goes to stderr").addHelpText(
|
|
3897
3945
|
"after",
|
|
3898
|
-
|
|
3946
|
+
`
|
|
3947
|
+
Run it in a repository, after \`${cliInvocation()} login\`. With a login, connect lists
|
|
3948
|
+
the factories you can use and takes the first rule that leaves one answer:
|
|
3949
|
+
1. --factory <org>/<factory>, or a factory id
|
|
3950
|
+
2. the factory this repository is already connected to
|
|
3951
|
+
3. the one factory this repository is linked to
|
|
3952
|
+
4. the one factory you can use
|
|
3953
|
+
5. on a terminal, ask; with no terminal, exit 1 and list each --factory value
|
|
3954
|
+
|
|
3955
|
+
It says what it chose and why. The choice is saved in this repository's git
|
|
3956
|
+
directory (outerlayer/connection.json), shared by every worktree of the
|
|
3957
|
+
clone and never committed. A factory key already belongs to one factory, so
|
|
3958
|
+
connect changes nothing for it. Connect never links a repository.
|
|
3959
|
+
|
|
3960
|
+
After it saves the choice, connect checks that this repository is linked to
|
|
3961
|
+
the factory. If it is not, connect says so, prints the factory's Work page
|
|
3962
|
+
link where you link it, and exits 2. The choice is saved either way. Run
|
|
3963
|
+
connect again once the repository is linked. With --json, the document has
|
|
3964
|
+
linked (true, false, or null when it could not be checked) and, when false,
|
|
3965
|
+
linkUrl.
|
|
3966
|
+
`
|
|
3899
3967
|
).action(async (opts) => {
|
|
3900
|
-
const { runConnectCommand } = await import('./connect-cmd-
|
|
3968
|
+
const { runConnectCommand } = await import('./connect-cmd-ZW5FV3ZW.js');
|
|
3901
3969
|
const code = await runConnectCommand({ factory: opts.factory, json: opts.json }, await realConnectDepsForCwd(), {
|
|
3902
3970
|
stdout: process.stdout,
|
|
3903
3971
|
stderr: process.stderr
|
|
@@ -3915,9 +3983,28 @@ function buildProgram(argv = process.argv) {
|
|
|
3915
3983
|
});
|
|
3916
3984
|
program2.command("login").description("Sign in to your account by browser approval, or save a piped factory key").option("--dashboard <address>", "the dashboard to sign in on (default: https://app.outerlayer.ai)").option("--no-browser", "print the approve link without opening a browser").option("--check <id>", "check a login that is still waiting for approval, once").option("--url <url>", "gateway base URL for a piped key (browser login gets it from the dashboard)").option("--app-id <id>", "factory id a piped key is bound to (Settings \u2192 General)").option("--no-input", "never wait on a person; fail if the key is not on stdin").option("--json", "machine-readable JSON output").addHelpText(
|
|
3917
3985
|
"after",
|
|
3918
|
-
|
|
3986
|
+
`
|
|
3987
|
+
With no key on stdin, login prints an approve link and a code. A signed-in
|
|
3988
|
+
person approves it on the dashboard. The login is a token for that person's
|
|
3989
|
+
account, made for this machine, saved here and never printed. It picks no
|
|
3990
|
+
factory: run \`${cliInvocation()} connect\` for that. \`${cliInvocation()} logout\` revokes it.
|
|
3991
|
+
|
|
3992
|
+
When stdout is not a terminal, login does not wait. It prints one JSON
|
|
3993
|
+
document with the link, the code and a \`login --check <id>\` command, and
|
|
3994
|
+
exits 75. Run the check until it stops exiting 75: 0 is signed in, 1 is
|
|
3995
|
+
denied or expired. A dropped connection or a 5xx also exits 75.
|
|
3996
|
+
|
|
3997
|
+
A factory key piped on stdin is saved as it always was, never as a flag and
|
|
3998
|
+
never printed back. A factory key always wins over the login, so CI and
|
|
3999
|
+
runners keep acting as their key.
|
|
4000
|
+
|
|
4001
|
+
echo "$OUTERLAYER_KEY" | ${cliInvocation()} login --url <gateway url> --app-id <factory id>
|
|
4002
|
+
|
|
4003
|
+
Every later command reads the saved file, so none of them needs a key on
|
|
4004
|
+
its command line. A saved key is checked for real on the first \`sync\`.
|
|
4005
|
+
`
|
|
3919
4006
|
).action(async (opts) => {
|
|
3920
|
-
const { runLoginCommand, realLoginDeps } = await import('./login-browser-
|
|
4007
|
+
const { runLoginCommand, realLoginDeps } = await import('./login-browser-O63QZN7D.js');
|
|
3921
4008
|
const code = await runLoginCommand(
|
|
3922
4009
|
{
|
|
3923
4010
|
browser: opts.browser !== false,
|
|
@@ -3934,18 +4021,30 @@ function buildProgram(argv = process.argv) {
|
|
|
3934
4021
|
});
|
|
3935
4022
|
program2.command("logout").description("Revoke this machine's login and remove it").addHelpText(
|
|
3936
4023
|
"after",
|
|
3937
|
-
|
|
4024
|
+
`
|
|
4025
|
+
Revokes the token \`${cliInvocation()} login\` saved, then deletes it from the config
|
|
4026
|
+
file. A factory key and the chosen factory are left alone. When the
|
|
4027
|
+
dashboard cannot be reached the local copy is still deleted and the exit
|
|
4028
|
+
code is 1: revoke the token on /profile/security.
|
|
4029
|
+
`
|
|
3938
4030
|
).action(async () => {
|
|
3939
|
-
const { runLogoutCommand, realLogoutDeps } = await import('./logout-cmd-
|
|
4031
|
+
const { runLogoutCommand, realLogoutDeps } = await import('./logout-cmd-5V5MMBSY.js');
|
|
3940
4032
|
const code = await runLogoutCommand(realLogoutDeps());
|
|
3941
4033
|
if (code !== 0) process.exitCode = code;
|
|
3942
4034
|
});
|
|
3943
|
-
program2.command("sync").description("Send local coding-agent sessions to OuterLayer cloud").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").option("--tier <tier>", "capture tier: metrics | redacted | full (default: full)").option("--dry-run", "print what would leave this machine, send nothing").option("--all", "ignore the sync checkpoint and re-send everything").option("--limit <n>", "only the N most recent sessions", (v) => parseInt(v, 10)).option("--json", "machine-readable JSON output").option("--quiet", "no output; exit code only").option("--root <dir>", "Claude Code transcript root (default ~/.claude/projects)").option("--codex-root <dir>", "Codex sessions root (default ~/.codex/sessions)").option("--cursor-root <dir>", "Cursor chats root (default ~/.cursor/chats)").addHelpText(
|
|
4035
|
+
program2.command("sync").description("Send local coding-agent sessions to OuterLayer cloud").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").option("--tier <tier>", "capture tier: metrics | redacted | full (default: full)").option("--dry-run", "print what would leave this machine, send nothing").option("--all", "ignore the sync checkpoint and re-send everything").option("--limit <n>", "only the N most recent sessions", (v) => parseInt(v, 10)).option("--json", "machine-readable JSON output").option("--quiet", "no output; exit code only").option("--link <artifactId>", "print the dashboard link of an artifact already uploaded; sends nothing").option("--root <dir>", "Claude Code transcript root (default ~/.claude/projects)").option("--codex-root <dir>", "Codex sessions root (default ~/.codex/sessions)").option("--cursor-root <dir>", "Cursor chats root (default ~/.cursor/chats)").addHelpText(
|
|
3944
4036
|
"after",
|
|
3945
4037
|
"\nIncremental: only sessions newer than the last checkpoint ship. The tier\nis applied on this machine before anything leaves it; `--dry-run` prints\nexactly what would. The hook-triggered background sync runs `--quiet`.\nExit 2 means the server rejected at least one session.\n"
|
|
3946
4038
|
).action(async (opts) => {
|
|
3947
4039
|
warnIfApiKeyFlag(opts);
|
|
3948
|
-
|
|
4040
|
+
if (opts.link !== void 0) {
|
|
4041
|
+
const { lookupArtifactLink } = await import('./artifact-link-cmd-AVM2EKTV.js');
|
|
4042
|
+
const found = lookupArtifactLink(opts.link);
|
|
4043
|
+
if (found.ok) process.stdout.write(found.url + "\n");
|
|
4044
|
+
else fail(found.reason);
|
|
4045
|
+
return;
|
|
4046
|
+
}
|
|
4047
|
+
const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-Q6VYNPWG.js');
|
|
3949
4048
|
try {
|
|
3950
4049
|
const result = await runSync({
|
|
3951
4050
|
url: opts.url,
|
|
@@ -3970,11 +4069,13 @@ function buildProgram(argv = process.argv) {
|
|
|
3970
4069
|
throw err;
|
|
3971
4070
|
}
|
|
3972
4071
|
});
|
|
3973
|
-
program2.command("daemon").alias("watch").description("Run the copy-out daemon that mirrors transcripts before they are deleted").option("--once", "do a single mirror sweep and exit").addHelpText("after",
|
|
4072
|
+
program2.command("daemon").alias("watch").description("Run the copy-out daemon that mirrors transcripts before they are deleted").option("--once", "do a single mirror sweep and exit").addHelpText("after", `
|
|
4073
|
+
\`${cliInvocation()} watch\` is the former name and still works, with a warning.
|
|
4074
|
+
`).action(async (opts) => {
|
|
3974
4075
|
if (invokedCommandToken(argv) === "watch") {
|
|
3975
|
-
warnDeprecated(
|
|
4076
|
+
warnDeprecated(`\`${cliInvocation()} watch\` is now \`${cliInvocation()} daemon\`; the old name will be removed in a future release.`);
|
|
3976
4077
|
}
|
|
3977
|
-
const { runWatch } = await import('./watch-
|
|
4078
|
+
const { runWatch } = await import('./watch-ARAGADTF.js');
|
|
3978
4079
|
await runWatch({ once: opts.once });
|
|
3979
4080
|
});
|
|
3980
4081
|
program2.command("hook <event>", { hidden: true }).description("capture-hook fast path, installed by `init`").action(() => {
|
|
@@ -3983,6 +4084,8 @@ function buildProgram(argv = process.argv) {
|
|
|
3983
4084
|
});
|
|
3984
4085
|
program2.command("hook-wrap", { hidden: true }).description("runs a hook wrapped by `hooks wrap`, recording exec evidence").option("--id <base64>", "the original hook command, base64-encoded").option("--capture-output", "tee stdout/stderr into a bounded tail").action(() => {
|
|
3985
4086
|
});
|
|
4087
|
+
program2.command("claude [args...]", { hidden: true }).description("start Claude Code with the repository's control plane attached").allowUnknownOption().helpOption(false).action(() => {
|
|
4088
|
+
});
|
|
3986
4089
|
program2.command("broker-relay", { hidden: true }).description("relay a build's loopback connections to the runner's tunnel and destinations").requiredOption("--port <port>", "the loopback port to listen on").requiredOption("--socket <path>", "the runner's tunnel socket").option("--forward <port=socket>", "also relay a loopback port to a destination's socket; repeatable", (value, previous) => [...previous, value], []).action(async (opts) => {
|
|
3987
4090
|
const { startRelay } = await import('./relay-L76HDX72.js');
|
|
3988
4091
|
const port = Number(opts.port);
|
|
@@ -4003,7 +4106,7 @@ function buildProgram(argv = process.argv) {
|
|
|
4003
4106
|
await startRelay({ port, socketPath: opts.socket, forwards });
|
|
4004
4107
|
});
|
|
4005
4108
|
program2.command("vm-exec", { hidden: true }).description("run a command in a microVM build's guest through its exec agent").requiredOption("--socket <path>", "the Unix socket Firecracker serves the build's vsock device on").option("--user <user>", "the user to run as", "").option("--cwd <dir>", "the working directory", "/").option("--env <NAME=value>", "an environment value the command line carries; repeatable", (value, previous) => [...previous, value], []).option("--pass <NAME>", "an environment variable whose value is read from this process; repeatable", (value, previous) => [...previous, value], []).argument("<argv...>", "the command and its arguments").action(async (argv2, opts) => {
|
|
4006
|
-
const { runVmExec } = await import('./exec-client-
|
|
4109
|
+
const { runVmExec } = await import('./exec-client-7UMESIE2.js');
|
|
4007
4110
|
const env = {};
|
|
4008
4111
|
for (const entry of opts.env) {
|
|
4009
4112
|
const eq = entry.indexOf("=");
|
|
@@ -4028,7 +4131,7 @@ function buildProgram(argv = process.argv) {
|
|
|
4028
4131
|
}
|
|
4029
4132
|
});
|
|
4030
4133
|
program2.command("session-sender", { hidden: true }).description("stream a runner build's sessions to its work item while the build runs").action(async () => {
|
|
4031
|
-
const { runSessionSender } = await import('./session-sender-
|
|
4134
|
+
const { runSessionSender } = await import('./session-sender-NNVPSPY7.js');
|
|
4032
4135
|
try {
|
|
4033
4136
|
await runSessionSender();
|
|
4034
4137
|
} catch (err) {
|
|
@@ -4036,7 +4139,7 @@ function buildProgram(argv = process.argv) {
|
|
|
4036
4139
|
}
|
|
4037
4140
|
});
|
|
4038
4141
|
program2.command("vm-init", { hidden: true }).description("lay out a microVM build's guest; the guest helper runs it").action(async () => {
|
|
4039
|
-
const { realGuestHost, runGuestInit } = await import('./guest-init-
|
|
4142
|
+
const { realGuestHost, runGuestInit } = await import('./guest-init-KPBQOFE5.js');
|
|
4040
4143
|
const { readFileSync: readFileSync3 } = await import('fs');
|
|
4041
4144
|
try {
|
|
4042
4145
|
runGuestInit(realGuestHost(), readFileSync3("/proc/cmdline", "utf8"));
|
|
@@ -4050,6 +4153,7 @@ function buildProgram(argv = process.argv) {
|
|
|
4050
4153
|
registerMcpCommands(program2);
|
|
4051
4154
|
registerContextCommands(program2);
|
|
4052
4155
|
registerWorkCommands(program2);
|
|
4156
|
+
registerSpecCommands(program2);
|
|
4053
4157
|
registerRunnerCommands(program2);
|
|
4054
4158
|
return program2;
|
|
4055
4159
|
}
|
|
@@ -4063,7 +4167,7 @@ async function runCli(processArgv) {
|
|
|
4063
4167
|
await buildProgram(argv).parseAsync(argv);
|
|
4064
4168
|
}
|
|
4065
4169
|
async function compileContext(opts) {
|
|
4066
|
-
const { runEmit, EmitError } = await import('./emit-cmd-
|
|
4170
|
+
const { runEmit, EmitError } = await import('./emit-cmd-PPN4QQF2.js');
|
|
4067
4171
|
try {
|
|
4068
4172
|
const result = runEmit({ cwd: opts.dir, check: opts.check, json: opts.json });
|
|
4069
4173
|
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
@@ -4078,15 +4182,39 @@ async function compileContext(opts) {
|
|
|
4078
4182
|
function registerEmitCommands(program2) {
|
|
4079
4183
|
const emitCmd = program2.command("emit").enablePositionalOptions().description("Record evidence for a work item: a named check result").argument("[name]", "the check name a validator declares (e.g. smoke.pass)").option("--link <url>", "proof link, usually the CI run URL").option("--body <text>", "one sentence recording your judgment").option("--body-file <path>", "read the sentence from a file; - reads standard input").option("--result <pass|fail>", "check outcome (default: pass)").option("--item <number>", "work item to record on directly, by its number in this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addOption(new Option("--check", "deprecated: use `context emit --check`").hideHelp()).addOption(new Option("--dir <path>", "deprecated: use `context emit --dir`").hideHelp()).addHelpText(
|
|
4080
4184
|
"after",
|
|
4081
|
-
|
|
4185
|
+
`
|
|
4186
|
+
${cliInvocation()} emit smoke.pass --item 412 --link https://ci.example.com/run/42
|
|
4187
|
+
${cliInvocation()} emit code-review --result fail --item 412 --body "The button should be red."
|
|
4188
|
+
|
|
4189
|
+
Records that a named check passed or failed, anchored to a work item.
|
|
4190
|
+
--item is always required, in or out of a recorded session \u2014 there is no
|
|
4191
|
+
session fallback. A check that ran carries the run URL as proof (--link);
|
|
4192
|
+
a judgment you are making yourself carries one sentence (--body, or
|
|
4193
|
+
--body-file to read it from a file or standard input). A fail needs at
|
|
4194
|
+
least one of the two. Run from inside a session, the check is stored as
|
|
4195
|
+
the session's; a session cannot record over a person's fail. With
|
|
4196
|
+
nothing to attach it to, the command refuses.
|
|
4197
|
+
|
|
4198
|
+
Who recorded a check is decided by your API key, never by what you send:
|
|
4199
|
+
a key bound to your membership records it as yours, and nothing automated
|
|
4200
|
+
can then clear it.
|
|
4201
|
+
|
|
4202
|
+
A person's pass or fail on one criterion's proof is recorded on that
|
|
4203
|
+
criterion's thread instead \u2014 see \`${cliInvocation()} work comment\`.
|
|
4204
|
+
|
|
4205
|
+
Subcommands: \`emit artifact <file>\` for screenshots, recordings, reports and
|
|
4206
|
+
logs; \`emit finding\` / \`emit findings <file>\` to record a problem in the factory;
|
|
4207
|
+
\`emit criteria <file>\` to record a work item's acceptance criteria.
|
|
4208
|
+
Compiling .outerlayer/ moved to \`${cliInvocation()} context emit\`.
|
|
4209
|
+
`
|
|
4082
4210
|
).action(async (name, opts) => {
|
|
4083
4211
|
if (name === void 0) {
|
|
4084
|
-
warnDeprecated(
|
|
4212
|
+
warnDeprecated(`\`${cliInvocation()} emit\` with no name now lives at \`${cliInvocation()} context emit\`; the bare form will be removed in a future release.`);
|
|
4085
4213
|
await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
|
|
4086
4214
|
return;
|
|
4087
4215
|
}
|
|
4088
4216
|
warnIfApiKeyFlag(opts);
|
|
4089
|
-
const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-
|
|
4217
|
+
const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-UZVMOCF4.js');
|
|
4090
4218
|
try {
|
|
4091
4219
|
const result = await runEmitResult({
|
|
4092
4220
|
name,
|
|
@@ -4116,10 +4244,10 @@ function registerEmitCommands(program2) {
|
|
|
4116
4244
|
).option("--replaces <ids>", "artifact id(s) this one corrects; comma-separate 2-20 to retire them all").option("--pr <number>", "pull request number to anchor to").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4117
4245
|
"after",
|
|
4118
4246
|
`
|
|
4119
|
-
|
|
4247
|
+
${cliInvocation()} emit artifact shot.png --caption "the dot row, current dot marked" --for LOGIN-01
|
|
4120
4248
|
|
|
4121
4249
|
Inside a recorded Claude Code session the artifact spools locally and ships,
|
|
4122
|
-
bound to that session, on the next
|
|
4250
|
+
bound to that session, on the next \`${cliInvocation()} sync\` \u2014 but only if that
|
|
4123
4251
|
session was launched with OUTERLAYER_WORK; without it nothing the session
|
|
4124
4252
|
produces may leave the machine, and the command refuses rather than queue an
|
|
4125
4253
|
artifact that can never ship. Otherwise it uploads immediately, anchored to a
|
|
@@ -4137,7 +4265,7 @@ locally so it never uploads. One correction can retire several duplicates.
|
|
|
4137
4265
|
`
|
|
4138
4266
|
).action(async (file, opts) => {
|
|
4139
4267
|
warnIfApiKeyFlag(opts);
|
|
4140
|
-
const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-
|
|
4268
|
+
const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-7MP63KXU.js');
|
|
4141
4269
|
let pr;
|
|
4142
4270
|
if (opts.pr !== void 0) {
|
|
4143
4271
|
pr = parseTrackerNumber(opts.pr);
|
|
@@ -4169,10 +4297,35 @@ locally so it never uploads. One correction can retire several duplicates.
|
|
|
4169
4297
|
});
|
|
4170
4298
|
emitCmd.command("finding").description("Record one finding: a problem you hit in the factory").requiredOption("--id <id>", "client id \u2014 re-emitting the same id replaces it").option("--category <context|flaky-test|tooling|environment|defect|other>", "what kind of problem this is").requiredOption("--title <text>", "one sentence").requiredOption("--file <path>", "the file the problem is in, or the instruction's own path").option("--line <number>", "line number in --file").option("--rule-path <path>", "the instruction's own path \u2014 required for a context finding").option("--rule-line <number>", "line number in --rule-path").option("--rule-quote <text>", "the instruction's quoted sentence \u2014 required unless --rule-relation is missing").option("--rule-relation <wrong|broken|missing>", "how the instruction fails \u2014 required for a context finding").requiredOption("--where <label>", 'where this was recorded, e.g. "build session"').option("--detail <text>", "what happened, a few paragraphs").option("--cause <text>", 'what is actually wrong, or "unknown"').option("--suggestion <text>", "what would help").option("--command <text>", "the command that misbehaved").option("--error <text>", "the first error line").option("--test <name>", "the test name, for a flaky test").option("--symbol <name>", "the function the problem is in, for a defect").option("--started-at <event>", "event id where you hit the problem (default: first output showing --error)").option("--ended-at <event>", "event id where you got past it (default: the newest event)").option("--untimed", "record no time, only when the problem cost none in this session").option("--find <text>", "list this session's events that contain the text, and record nothing").option("--problem <id>", "a problem this finding reports; repeat for each one (needs --link-reason)", (value, previous = []) => [...previous, value]).option("--link-reason <text>", "why the finding reports each --problem").option("--new", "record a new problem instead of linking an existing one").option("--trace-id <id>", "the session's trace id, when there is one").option("--turn <number>", "turn index within the session").option("--round <number>", "round number, when there is one").addOption(new Option("--subject <value>").hideHelp()).addOption(new Option("--kind <value>").hideHelp()).addOption(new Option("--severity <value>").hideHelp()).addOption(new Option("--verdict <value>").hideHelp()).addOption(new Option("--fixed").hideHelp()).addOption(new Option("--source <value>").hideHelp()).option("--head-sha <sha>", "the commit this batch was recorded against").option("--context-source-sha <sha>", "the context-source commit this batch was recorded against").option("--item <number>", "work item to record on directly, by its number in this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4171
4299
|
"after",
|
|
4172
|
-
|
|
4300
|
+
`
|
|
4301
|
+
${cliInvocation()} emit finding --id gate-skip --category tooling \\
|
|
4302
|
+
--title "The pre-push gate prints green when a step was skipped" \\
|
|
4303
|
+
--file scripts/git/pre-push-checks.mjs --where "build session"
|
|
4304
|
+
|
|
4305
|
+
Records one problem you hit in the factory: an instruction that is wrong or
|
|
4306
|
+
missing (context), a flaky test, a misbehaving script (tooling), a local
|
|
4307
|
+
setup trap (environment), a bug outside your own change (defect), or
|
|
4308
|
+
anything else. A problem in your own change is fixed, not recorded.
|
|
4309
|
+
A context finding needs --rule-path and --rule-relation, and --rule-quote
|
|
4310
|
+
unless the relation is missing. Add --cause, --detail and --suggestion, and
|
|
4311
|
+
--command, --error (first error line), --test or --symbol when there is one.
|
|
4312
|
+
|
|
4313
|
+
Every finding joins a factory-level problem. When one of its keys matches a
|
|
4314
|
+
known problem it joins that problem. Otherwise nothing is stored: the command
|
|
4315
|
+
prints the closest problems and exits with code 3. Run it again with
|
|
4316
|
+
--problem <id> --link-reason <why> (repeat --problem for each problem the
|
|
4317
|
+
finding reports), or with --new if none of them is the same problem.
|
|
4318
|
+
A finding records the time it cost, read from two events of your session or
|
|
4319
|
+
its subagents. The start is --started-at, else the first tool output that
|
|
4320
|
+
shows --error. The end is --ended-at, else the newest event. When the session
|
|
4321
|
+
has events and no start is found, nothing is stored: the command lists the
|
|
4322
|
+
recent events with their ids. --find <text> searches all of them.
|
|
4323
|
+
--item names the work item; without it, inside a recorded session, the
|
|
4324
|
+
item that session was launched for is used automatically.
|
|
4325
|
+
`
|
|
4173
4326
|
).action(async (opts) => {
|
|
4174
4327
|
warnIfApiKeyFlag(opts);
|
|
4175
|
-
const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-
|
|
4328
|
+
const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-OL7JB6H3.js');
|
|
4176
4329
|
try {
|
|
4177
4330
|
refuseRemovedFindingFlags(opts);
|
|
4178
4331
|
const result = await runEmitFinding({
|
|
@@ -4222,10 +4375,25 @@ locally so it never uploads. One correction can retire several duplicates.
|
|
|
4222
4375
|
});
|
|
4223
4376
|
emitCmd.command("findings <file>").description("Record a batch of findings from a FindingBatch JSON file (- for standard input)").option("--item <number>", "work item to record on directly, by its number in this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4224
4377
|
"after",
|
|
4225
|
-
|
|
4378
|
+
`
|
|
4379
|
+
${cliInvocation()} emit findings review.json --item 412
|
|
4380
|
+
|
|
4381
|
+
Records a whole batch at once \u2014 a FindingBatch JSON file (schemaVersion 3,
|
|
4382
|
+
optional headSha / contextSourceSha, and 1-500 findings), validated against
|
|
4383
|
+
the same contract \`emit finding\` uses before anything is sent. Re-emitting
|
|
4384
|
+
an id already on the item replaces that row rather than adding a second one.
|
|
4385
|
+
Findings that need a choice between candidate problems are listed and not
|
|
4386
|
+
stored; the rest are stored, and the exit code is 3.
|
|
4387
|
+
Each finding records its time as \`emit finding\` does: "startedAt" is an event
|
|
4388
|
+
id, else the first tool output that shows its "error"; "endedAt" defaults to
|
|
4389
|
+
the newest event. A finding with neither, in a session that has events, stops
|
|
4390
|
+
the whole batch. "untimed": true records one with no time on purpose.
|
|
4391
|
+
--item names the work item; without it, inside a recorded session, the item
|
|
4392
|
+
that session was launched for is used automatically.
|
|
4393
|
+
`
|
|
4226
4394
|
).action(async (file, opts) => {
|
|
4227
4395
|
warnIfApiKeyFlag(opts);
|
|
4228
|
-
const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-
|
|
4396
|
+
const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-OL7JB6H3.js');
|
|
4229
4397
|
try {
|
|
4230
4398
|
const result = await runEmitFindings({
|
|
4231
4399
|
file,
|
|
@@ -4247,7 +4415,7 @@ locally so it never uploads. One correction can retire several duplicates.
|
|
|
4247
4415
|
emitCmd.command("criteria <file>").description("Record a work item's acceptance criteria from a JSON file (- for stdin)").option("--item <number>", "work item to record on directly, by its number in this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4248
4416
|
"after",
|
|
4249
4417
|
`
|
|
4250
|
-
|
|
4418
|
+
${cliInvocation()} emit criteria criteria.json --item 412
|
|
4251
4419
|
|
|
4252
4420
|
Records the item's acceptance criteria as one list. The file is JSON:
|
|
4253
4421
|
{ "criteria": [ { "id": "AC-1", "text": "Given ...", "proof": null },
|
|
@@ -4265,7 +4433,7 @@ session was launched for is used automatically.
|
|
|
4265
4433
|
`
|
|
4266
4434
|
).action(async (file, opts) => {
|
|
4267
4435
|
warnIfApiKeyFlag(opts);
|
|
4268
|
-
const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-
|
|
4436
|
+
const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-3RXPDLNK.js');
|
|
4269
4437
|
try {
|
|
4270
4438
|
const result = await runEmitCriteria({
|
|
4271
4439
|
file,
|
|
@@ -4285,14 +4453,56 @@ session was launched for is used automatically.
|
|
|
4285
4453
|
}
|
|
4286
4454
|
});
|
|
4287
4455
|
}
|
|
4456
|
+
function registerSpecCommands(program2) {
|
|
4457
|
+
const specCmd = program2.command("spec").description("Find, file and edit the issue a spec lives in, in your factory's tracker");
|
|
4458
|
+
const credentialOptions = (command) => command.option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)");
|
|
4459
|
+
const run = async (opts, action) => {
|
|
4460
|
+
warnIfApiKeyFlag(opts);
|
|
4461
|
+
const { WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4462
|
+
try {
|
|
4463
|
+
await action(await import('./spec-cmd-OWVTBB4J.js'));
|
|
4464
|
+
} catch (err) {
|
|
4465
|
+
if (err instanceof WorkCommandError) {
|
|
4466
|
+
fail(err.message);
|
|
4467
|
+
return;
|
|
4468
|
+
}
|
|
4469
|
+
throw err;
|
|
4470
|
+
}
|
|
4471
|
+
};
|
|
4472
|
+
credentialOptions(
|
|
4473
|
+
specCmd.command("target").description("Say where a spec would be filed, and whether this factory can file there").option("--tracker <name>", "one connected tracker, when the factory has more than one")
|
|
4474
|
+
).action((opts) => run(opts, (spec) => spec.runSpecTarget(opts)));
|
|
4475
|
+
credentialOptions(
|
|
4476
|
+
specCmd.command("search").description("Find open and closed issues that match a query, before filing a duplicate").argument("<query>", "words from the title or body").option("--tracker <name>", "one connected tracker, when the factory has more than one")
|
|
4477
|
+
).action((query, opts) => run(opts, (spec) => spec.runSpecSearch({ ...opts, query })));
|
|
4478
|
+
credentialOptions(
|
|
4479
|
+
specCmd.command("file").description("File a spec as an issue and print its key, URL and the command that builds it").requiredOption("--title <text>", "the issue title").option("--body-file <path>", "the spec as Markdown; - reads standard input").option("--repo <owner/name>", "the repository to file in (GitHub), or the one the work lands in").option("--tracker <name>", "the tracker, when the factory files in more than one").option("--scope <key>", "the Linear team or Jira project, when the connection covers several")
|
|
4480
|
+
).action((opts) => run(opts, (spec) => spec.runSpecFile(opts)));
|
|
4481
|
+
credentialOptions(
|
|
4482
|
+
specCmd.command("edit").description("Replace the body of an issue that holds a spec").argument("<key>", "the issue key, such as acme/api#12 or ENG-142").option("--body-file <path>", "the new body as Markdown; - reads standard input").option("--updated-at <timestamp>", "the updatedAt you read; the edit is refused if the issue has changed since")
|
|
4483
|
+
).action((key, opts) => run(opts, (spec) => spec.runSpecEdit({ ...opts, key })));
|
|
4484
|
+
}
|
|
4288
4485
|
function registerWorkCommands(program2) {
|
|
4289
4486
|
const workCmd = program2.command("work").description("Start, remove, or read what the factory is working on (the Work page)");
|
|
4290
|
-
workCmd.command("build").description("Start work on an item: a host builds it, or with --local you do").option("--issue <number>", "issue number, or a Linear/Jira key like ENG-123 (adds it to Work first)").option(
|
|
4487
|
+
workCmd.command("build").description("Start work on an item: a host builds it, or with --local you do").option("--issue <number>", "issue number, or a Linear/Jira key like ENG-123 (adds it to Work first)").option(TRACKER_OPTION_FLAG, "tracker for a keyed --issue \u2014 required if more than one is connected").option("--item <number>", "the item's own number inside this factory \u2014 must already exist").option("--local", "you build it in a session you start; no host takes it").option("--repo <owner/name>", "repository \u2014 the checkout's remote for a number, never guessed for a key").option("--note <text>", "a short note stored with the request").option("--session-id <id>", "session id to record as-is, skipping detection").option("--retry <count>", "retries after a gateway answer worth trying again").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4291
4488
|
"after",
|
|
4292
|
-
|
|
4489
|
+
`
|
|
4490
|
+
${cliInvocation()} work build --issue 42 # a host builds it
|
|
4491
|
+
${cliInvocation()} work build --item 7 # retry an item already on Work
|
|
4492
|
+
${cliInvocation()} work build --issue 42 --local # you build it
|
|
4493
|
+
${cliInvocation()} work build --issue ENG-123 --tracker linear # a Linear issue
|
|
4494
|
+
|
|
4495
|
+
Without --local, records a build request: a host takes the item when it
|
|
4496
|
+
has a free slot. It never links the calling session and never takes a
|
|
4497
|
+
lease, even run from inside one.
|
|
4498
|
+
|
|
4499
|
+
With --local, puts the item on Work with no build request, so no host
|
|
4500
|
+
takes it, and prints the line that starts your session on it. That
|
|
4501
|
+
session links itself and holds the item's lease while it works.
|
|
4502
|
+
`
|
|
4293
4503
|
).action(async (opts) => {
|
|
4294
4504
|
warnIfApiKeyFlag(opts);
|
|
4295
|
-
const { runWorkBuild, WorkCommandError } = await import('./work-cmd-
|
|
4505
|
+
const { runWorkBuild, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4296
4506
|
try {
|
|
4297
4507
|
await runWorkBuild(opts);
|
|
4298
4508
|
} catch (err) {
|
|
@@ -4305,10 +4515,18 @@ function registerWorkCommands(program2) {
|
|
|
4305
4515
|
});
|
|
4306
4516
|
workCmd.command("link-session").description("Link the calling session to a work item that already exists").argument("<number>", "the item's number inside this factory").option("--session-id <id>", "session id to record as-is, skipping detection (used by the SessionStart hook)").option("--retry <count>", "resend after a failure that may pass, with backoff").option("--no-lease", "link only \u2014 ask for no session lease (used by a host's own job)").option("--ended", "release this session's lease instead of taking or renewing one").addOption(new Option("--log-failures", "append a failure to the hook error log (used by hooks)").hideHelp()).option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4307
4517
|
"after",
|
|
4308
|
-
|
|
4518
|
+
`
|
|
4519
|
+
${cliInvocation()} work link-session 42
|
|
4520
|
+
|
|
4521
|
+
Names an item that already exists on the calling session \u2014 it never
|
|
4522
|
+
creates one. Create one with \`${cliInvocation()} work build --local\`. Linking
|
|
4523
|
+
the same session to the same item twice is a no-op. Also takes or
|
|
4524
|
+
renews that session's own 20-minute lease, unless --no-lease or
|
|
4525
|
+
--ended is given, or another worker already holds a live one.
|
|
4526
|
+
`
|
|
4309
4527
|
).action(async (number, opts) => {
|
|
4310
4528
|
warnIfApiKeyFlag(opts);
|
|
4311
|
-
const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-
|
|
4529
|
+
const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4312
4530
|
try {
|
|
4313
4531
|
await runWorkLinkSession({ ...opts, number, noLease: opts.lease === false, logFailures: opts.logFailures === true });
|
|
4314
4532
|
} catch (err) {
|
|
@@ -4322,7 +4540,7 @@ function registerWorkCommands(program2) {
|
|
|
4322
4540
|
workCmd.command("comment").description("Post a comment on a work item's general thread or one of its criterion threads").requiredOption("--item <number>", "the item's number inside this factory").option("--criterion <id>", "the criterion thread to post on (default: the general thread)").option("--body <text>", "the comment's text").option("--artifact <id>", "artifact id \u2014 required with --attach, naming the criterion's new proof").option("--pass", "record a pass (a person's verdict; refused from an agent session or a key)").option("--fail", "record a fail (a person's verdict; refused from an agent session or a key)").option("--attach", "make --artifact the named criterion's proof").option("--ready", "hand the thread back to a person (refused from a person)").option("--session-id <id>", "session id to record as-is, skipping detection (used by the SessionStart hook)").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4323
4541
|
"after",
|
|
4324
4542
|
`
|
|
4325
|
-
|
|
4543
|
+
${cliInvocation()} work comment --item 7 --criterion AC-9-01 --body "fixed" --artifact 3f2a1c9d --attach
|
|
4326
4544
|
|
|
4327
4545
|
Posts one comment. Omitting --criterion posts on the general thread;
|
|
4328
4546
|
naming one posts on that criterion's own thread. --pass/--fail are a
|
|
@@ -4333,8 +4551,8 @@ most one action flag may be given.
|
|
|
4333
4551
|
`
|
|
4334
4552
|
).action(async (opts) => {
|
|
4335
4553
|
warnIfApiKeyFlag(opts);
|
|
4336
|
-
const { runWorkComment, WorkCommentCommandError } = await import('./work-comment-cmd-
|
|
4337
|
-
const { WorkCommandError } = await import('./work-cmd-
|
|
4554
|
+
const { runWorkComment, WorkCommentCommandError } = await import('./work-comment-cmd-SZJSPM5S.js');
|
|
4555
|
+
const { WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4338
4556
|
try {
|
|
4339
4557
|
await runWorkComment(opts);
|
|
4340
4558
|
} catch (err) {
|
|
@@ -4347,11 +4565,17 @@ most one action flag may be given.
|
|
|
4347
4565
|
});
|
|
4348
4566
|
workCmd.command("threads").description("Read a work item's general thread and its criterion threads").requiredOption("--item <number>", "the item's number inside this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4349
4567
|
"after",
|
|
4350
|
-
|
|
4568
|
+
`
|
|
4569
|
+
${cliInvocation()} work threads --item 7
|
|
4570
|
+
|
|
4571
|
+
Prints the item's general thread, then one thread per acceptance
|
|
4572
|
+
criterion that carries proof or a comment, each with who is waiting
|
|
4573
|
+
on whom next.
|
|
4574
|
+
`
|
|
4351
4575
|
).action(async (opts) => {
|
|
4352
4576
|
warnIfApiKeyFlag(opts);
|
|
4353
|
-
const { runWorkThreads, WorkCommentCommandError } = await import('./work-comment-cmd-
|
|
4354
|
-
const { WorkCommandError } = await import('./work-cmd-
|
|
4577
|
+
const { runWorkThreads, WorkCommentCommandError } = await import('./work-comment-cmd-SZJSPM5S.js');
|
|
4578
|
+
const { WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4355
4579
|
try {
|
|
4356
4580
|
await runWorkThreads(opts);
|
|
4357
4581
|
} catch (err) {
|
|
@@ -4362,10 +4586,10 @@ most one action flag may be given.
|
|
|
4362
4586
|
throw err;
|
|
4363
4587
|
}
|
|
4364
4588
|
});
|
|
4365
|
-
workCmd.command("remove").description("Withdraw a source's addition \u2014 never deletes the item").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number (default: named by --item instead)").option("--repo <owner/name>", "repository (default: the
|
|
4589
|
+
workCmd.command("remove").description("Withdraw a source's addition \u2014 never deletes the item").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number or Linear/Jira key (default: named by --item instead)").option(TRACKER_OPTION_FLAG, "tracker for a keyed --issue, when both hold the key").option("--repo <owner/name>", "repository for an issue number (default: the checkout's remote)").requiredOption("--reason <text>", "why this source is no longer working on it").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4366
4590
|
"after",
|
|
4367
4591
|
`
|
|
4368
|
-
|
|
4592
|
+
${cliInvocation()} work remove --item 42 --reason "done"
|
|
4369
4593
|
|
|
4370
4594
|
Withdraws the caller's own addition, recording the reason. Never
|
|
4371
4595
|
deletes anything \u2014 the item is removed from Work only once no
|
|
@@ -4373,7 +4597,7 @@ live addition remains on it.
|
|
|
4373
4597
|
`
|
|
4374
4598
|
).action(async (opts) => {
|
|
4375
4599
|
warnIfApiKeyFlag(opts);
|
|
4376
|
-
const { runWorkRemove, WorkCommandError } = await import('./work-cmd-
|
|
4600
|
+
const { runWorkRemove, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4377
4601
|
try {
|
|
4378
4602
|
await runWorkRemove(opts);
|
|
4379
4603
|
} catch (err) {
|
|
@@ -4384,9 +4608,9 @@ live addition remains on it.
|
|
|
4384
4608
|
throw err;
|
|
4385
4609
|
}
|
|
4386
4610
|
});
|
|
4387
|
-
workCmd.command("status").description("Show one item's stage, gate ledger, and additions").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number").option("--repo <owner/name>", "repository (default: the
|
|
4611
|
+
workCmd.command("status").description("Show one item's stage, gate ledger, and additions").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number, or a Linear/Jira key like ENG-123").option(TRACKER_OPTION_FLAG, "tracker for a keyed --issue, when both hold the key").option("--repo <owner/name>", "repository for an issue number (default: the checkout's remote)").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").action(async (opts) => {
|
|
4388
4612
|
warnIfApiKeyFlag(opts);
|
|
4389
|
-
const { runWorkStatus, WorkCommandError } = await import('./work-cmd-
|
|
4613
|
+
const { runWorkStatus, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4390
4614
|
try {
|
|
4391
4615
|
await runWorkStatus(opts);
|
|
4392
4616
|
} catch (err) {
|
|
@@ -4399,7 +4623,7 @@ live addition remains on it.
|
|
|
4399
4623
|
});
|
|
4400
4624
|
workCmd.command("list").description("List live work items for this factory").option("--stage <spec|build|review>", "filter by stage").option("--section <attention|waiting|flowing>", "filter by Queue section").option("--repo <owner/name>", "repository (default: the current checkout's remote)").option("--unclaimed", "only items with no live lease").option("--claimed", "only items with a live lease, held by a host or a local session").option("--startable", "only items a host can start: a build request, no open PR, no live lease").option("--needs <amend>", "only items with a thread waiting on an agent").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").action(async (opts) => {
|
|
4401
4625
|
warnIfApiKeyFlag(opts);
|
|
4402
|
-
const { runWorkList, WorkCommandError } = await import('./work-cmd-
|
|
4626
|
+
const { runWorkList, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4403
4627
|
try {
|
|
4404
4628
|
await runWorkList(opts);
|
|
4405
4629
|
} catch (err) {
|
|
@@ -4410,12 +4634,18 @@ live addition remains on it.
|
|
|
4410
4634
|
throw err;
|
|
4411
4635
|
}
|
|
4412
4636
|
});
|
|
4413
|
-
workCmd.command("claim").description("Claim a work item under a lease this API key holds before working on it").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number (default: named by --item instead)").option("--repo <owner/name>", "repository (default: the
|
|
4637
|
+
workCmd.command("claim").description("Claim a work item under a lease this API key holds before working on it").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number or Linear/Jira key (default: named by --item instead)").option(TRACKER_OPTION_FLAG, "tracker for a keyed --issue, when both hold the key").option("--repo <owner/name>", "repository for an issue number (default: the checkout's remote)").requiredOption("--kind <implement|amend>", "what this host is doing with the item").option("--host <name>", "the claiming host (default: this machine's hostname)").option("--seconds <n>", "lease length in seconds, clamped to 900 (default: 900)").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4414
4638
|
"after",
|
|
4415
|
-
|
|
4639
|
+
`
|
|
4640
|
+
${cliInvocation()} work claim --item 42 --kind implement
|
|
4641
|
+
|
|
4642
|
+
Records a lease held by the API key that sends it. A live lease held
|
|
4643
|
+
by a different key is refused; claiming again with the same key extends
|
|
4644
|
+
it. --host is a label only.
|
|
4645
|
+
`
|
|
4416
4646
|
).action(async (opts) => {
|
|
4417
4647
|
warnIfApiKeyFlag(opts);
|
|
4418
|
-
const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-
|
|
4648
|
+
const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
|
|
4419
4649
|
try {
|
|
4420
4650
|
await runWorkClaim(opts);
|
|
4421
4651
|
} catch (err) {
|
|
@@ -4426,12 +4656,17 @@ live addition remains on it.
|
|
|
4426
4656
|
throw err;
|
|
4427
4657
|
}
|
|
4428
4658
|
});
|
|
4429
|
-
workCmd.command("renew").description("Extend the lease this API key holds on a work item").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number (default: named by --item instead)").option("--repo <owner/name>", "repository (default: the
|
|
4659
|
+
workCmd.command("renew").description("Extend the lease this API key holds on a work item").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number or Linear/Jira key (default: named by --item instead)").option(TRACKER_OPTION_FLAG, "tracker for a keyed --issue, when both hold the key").option("--repo <owner/name>", "repository for an issue number (default: the checkout's remote)").option("--host <name>", "the claiming host (default: this machine's hostname)").option("--seconds <n>", "lease length in seconds, clamped to 900 (default: 900)").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4430
4660
|
"after",
|
|
4431
|
-
|
|
4661
|
+
`
|
|
4662
|
+
${cliInvocation()} work renew --item 42
|
|
4663
|
+
|
|
4664
|
+
Extends the live lease this API key holds. Refused with a 410 if the
|
|
4665
|
+
lease has expired, or a 403 if a different key holds it.
|
|
4666
|
+
`
|
|
4432
4667
|
).action(async (opts) => {
|
|
4433
4668
|
warnIfApiKeyFlag(opts);
|
|
4434
|
-
const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-
|
|
4669
|
+
const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
|
|
4435
4670
|
try {
|
|
4436
4671
|
await runWorkRenew(opts);
|
|
4437
4672
|
} catch (err) {
|
|
@@ -4442,15 +4677,29 @@ live addition remains on it.
|
|
|
4442
4677
|
throw err;
|
|
4443
4678
|
}
|
|
4444
4679
|
});
|
|
4445
|
-
workCmd.command("release").description("Release the lease this API key holds on a work item, or this session's own lease").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number (default: named by --item instead)").option("--repo <owner/name>", "repository (default: the
|
|
4680
|
+
workCmd.command("release").description("Release the lease this API key holds on a work item, or this session's own lease").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number or Linear/Jira key (default: named by --item instead)").option(TRACKER_OPTION_FLAG, "tracker for a keyed --issue, when both hold the key").option("--repo <owner/name>", "repository for an issue number (default: the checkout's remote)").option("--host <name>", "the claiming host (default: this machine's hostname); releases a host's lease").option("--session-id <id>", "the session whose lease to release, skipping detection").option(
|
|
4446
4681
|
"--outcome <ok|incomplete|failed|timed_out|idle|lease_lost|interrupted|stopped>",
|
|
4447
4682
|
"how a host's attempt ended (default: none)"
|
|
4448
4683
|
).option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4449
4684
|
"after",
|
|
4450
|
-
|
|
4685
|
+
`
|
|
4686
|
+
${cliInvocation()} work release --item 42 --outcome ok
|
|
4687
|
+
${cliInvocation()} work release --item 42
|
|
4688
|
+
|
|
4689
|
+
Marks the lease this API key holds released, optionally with an
|
|
4690
|
+
outcome. A lease held by a different key is refused. Releasing an
|
|
4691
|
+
already-released lease is a no-op that returns the recorded release
|
|
4692
|
+
time and outcome.
|
|
4693
|
+
|
|
4694
|
+
Run inside a session with no --host, it releases that session's own
|
|
4695
|
+
lease instead, so the item's review opens without ending the
|
|
4696
|
+
session. It never releases another session's lease. --outcome
|
|
4697
|
+
applies to a host's lease only. A later tool call in the session
|
|
4698
|
+
takes the lease again.
|
|
4699
|
+
`
|
|
4451
4700
|
).action(async (opts) => {
|
|
4452
4701
|
warnIfApiKeyFlag(opts);
|
|
4453
|
-
const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-
|
|
4702
|
+
const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
|
|
4454
4703
|
try {
|
|
4455
4704
|
await runWorkRelease(opts);
|
|
4456
4705
|
} catch (err) {
|
|
@@ -4463,10 +4712,22 @@ live addition remains on it.
|
|
|
4463
4712
|
});
|
|
4464
4713
|
workCmd.command("pr <number>").description("Declare a pull request onto the launched work item, or withdraw it").option("--repo <owner/name>", "repository (default: the current checkout's remote)").option("--session-id <id>", "session id to record as-is, skipping detection").option("--withdraw", "remove the declaration instead of making one (needs --item)").option("--item <number>", "with --withdraw, the item to remove the declaration from").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4465
4714
|
"after",
|
|
4466
|
-
|
|
4715
|
+
`
|
|
4716
|
+
${cliInvocation()} work pr 481
|
|
4717
|
+
${cliInvocation()} work pr 481 --withdraw --item 250
|
|
4718
|
+
|
|
4719
|
+
Run inside a session already on a work item. Records that pull
|
|
4720
|
+
request 481 in the checkout's repository belongs to the item named by
|
|
4721
|
+
OUTERLAYER_WORK, or refuses when the session is not on it. The same
|
|
4722
|
+
fact a \`pr-link\` in the session's own transcript records on sync.
|
|
4723
|
+
Idempotent: declaring the same pull request twice is a no-op.
|
|
4724
|
+
|
|
4725
|
+
--withdraw removes one item's declaration of the pull request. It
|
|
4726
|
+
needs your own login; an agent session or a factory key is refused.
|
|
4727
|
+
`
|
|
4467
4728
|
).action(async (number, opts) => {
|
|
4468
4729
|
warnIfApiKeyFlag(opts);
|
|
4469
|
-
const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-
|
|
4730
|
+
const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-5LGANL32.js');
|
|
4470
4731
|
try {
|
|
4471
4732
|
await runWorkPr({ ...opts, number });
|
|
4472
4733
|
} catch (err) {
|
|
@@ -4479,11 +4740,21 @@ live addition remains on it.
|
|
|
4479
4740
|
});
|
|
4480
4741
|
workCmd.command("open-pr").description("Open, or edit, the pull request for the work item this session is on").requiredOption("--title <title>", "the pull request's title").requiredOption("--body-file <path>", "a file holding the pull request's description").option("--repository <owner/name>", "repository to open the pull request in (default: the primary)").option("--repo <owner/name>", "same as --repository, on the gh path").option("--session-id <id>", "session id to record as-is, on the gh path, skipping detection").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
|
|
4481
4742
|
"after",
|
|
4482
|
-
|
|
4743
|
+
`
|
|
4744
|
+
${cliInvocation()} work open-pr --title "Add the thing" --body-file pr.md
|
|
4745
|
+
${cliInvocation()} work open-pr --repository acme/web --title "Add the thing" --body-file pr.md
|
|
4746
|
+
|
|
4747
|
+
In a host build, which holds an item key, the gateway opens the pull
|
|
4748
|
+
request as the factory's GitHub App, from the branch the claim named,
|
|
4749
|
+
or edits the one already open on that branch. No gh command runs.
|
|
4750
|
+
In your own session it runs \`gh pr create\` (or \`gh pr edit\`) under your
|
|
4751
|
+
login, then declares the pull request on the item, as \`work pr\` does.
|
|
4752
|
+
Run it again after a change to the title or description.
|
|
4753
|
+
`
|
|
4483
4754
|
).action(async (opts) => {
|
|
4484
4755
|
warnIfApiKeyFlag(opts);
|
|
4485
|
-
const { runWorkOpenPr, WorkOpenPrCommandError } = await import('./work-open-pr-cmd-
|
|
4486
|
-
const { WorkCommandError } = await import('./work-cmd-
|
|
4756
|
+
const { runWorkOpenPr, WorkOpenPrCommandError } = await import('./work-open-pr-cmd-RPXKCBWS.js');
|
|
4757
|
+
const { WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
|
|
4487
4758
|
try {
|
|
4488
4759
|
await runWorkOpenPr(opts);
|
|
4489
4760
|
} catch (err) {
|
|
@@ -4499,9 +4770,9 @@ function registerRunnerCommands(program2) {
|
|
|
4499
4770
|
const runnerCmd = program2.command("runner").description("Take work from the implement and amend queues on this machine");
|
|
4500
4771
|
const configOption = "the cloud config file to run against (default: ~/.outerlayer/config.json)";
|
|
4501
4772
|
runnerCmd.command("start").description("Run the loop: claim work, run it, report, clean up, repeat").option("--config <path>", configOption).action(async (opts) => {
|
|
4502
|
-
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-
|
|
4503
|
-
const { start, RunnerStartError } = await import('./loop-
|
|
4504
|
-
const { RunnerAlreadyRunningError } = await import('./pidfile-
|
|
4773
|
+
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-FXDG4NPJ.js');
|
|
4774
|
+
const { start, RunnerStartError } = await import('./loop-UGI2BJOT.js');
|
|
4775
|
+
const { RunnerAlreadyRunningError } = await import('./pidfile-3DM4OBKO.js');
|
|
4505
4776
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4506
4777
|
try {
|
|
4507
4778
|
const { realUpdateDeps } = await import('./real-deps-KNNBQC75.js');
|
|
@@ -4515,8 +4786,8 @@ function registerRunnerCommands(program2) {
|
|
|
4515
4786
|
}
|
|
4516
4787
|
});
|
|
4517
4788
|
runnerCmd.command("check").description("Validate the config, the hooks and the key, and print the effective settings").option("--config <path>", configOption).action(async (opts) => {
|
|
4518
|
-
const { defaultRunnerConfigPath } = await import('./config-
|
|
4519
|
-
const { runRunnerCheck } = await import('./check-
|
|
4789
|
+
const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
|
|
4790
|
+
const { runRunnerCheck } = await import('./check-5C4YDZYV.js');
|
|
4520
4791
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4521
4792
|
const result = await runRunnerCheck(configPath);
|
|
4522
4793
|
if (!result.ok) {
|
|
@@ -4532,8 +4803,8 @@ function registerRunnerCommands(program2) {
|
|
|
4532
4803
|
`);
|
|
4533
4804
|
});
|
|
4534
4805
|
runnerCmd.command("install").description("Put this CLI in the runner's install layout; --service adds its service").option("--config <path>", configOption).option("--service", "set up the service that keeps the runner running").option("--print", "with --service, print the unit and set up nothing").option("--user <account>", "with --service, the account the service runs as").option("--replace", "replace a unit or launcher file this command did not write").option("--allow-downgrade", "install this CLI even when it is older than the version the runner runs").option("--unit-name <name>", "with --service, the unit's name, to run a second runner beside the first").action(async (opts) => {
|
|
4535
|
-
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-
|
|
4536
|
-
const { runRunnerInstall, RunnerInstallError, launcherSummary, restartNote } = await import('./install-cmd-
|
|
4806
|
+
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-FXDG4NPJ.js');
|
|
4807
|
+
const { runRunnerInstall, RunnerInstallError, launcherSummary, restartNote } = await import('./install-cmd-QDOTR4OM.js');
|
|
4537
4808
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4538
4809
|
if (opts.service !== true) {
|
|
4539
4810
|
for (const flag of ["print", "user", "unitName"]) {
|
|
@@ -4545,7 +4816,7 @@ function registerRunnerCommands(program2) {
|
|
|
4545
4816
|
}
|
|
4546
4817
|
try {
|
|
4547
4818
|
if (opts.service === true) {
|
|
4548
|
-
const { installServiceCommand } = await import('./command-
|
|
4819
|
+
const { installServiceCommand } = await import('./command-H5CILO4S.js');
|
|
4549
4820
|
const result2 = await installServiceCommand({
|
|
4550
4821
|
configPath,
|
|
4551
4822
|
print: opts.print,
|
|
@@ -4583,7 +4854,7 @@ function registerRunnerCommands(program2) {
|
|
|
4583
4854
|
printLauncher(result, launcherSummary);
|
|
4584
4855
|
process.stdout.write(
|
|
4585
4856
|
`
|
|
4586
|
-
To keep it running, run ${C.yellow}
|
|
4857
|
+
To keep it running, run ${C.yellow}${cliInvocation()} runner install --service${C.reset}. To start the runner from the install layout yourself, use this line, then restart the service:
|
|
4587
4858
|
${C.yellow}${result.execStart}${C.reset}
|
|
4588
4859
|
`
|
|
4589
4860
|
);
|
|
@@ -4597,26 +4868,43 @@ To keep it running, run ${C.yellow}outerlayer runner install --service${C.reset}
|
|
|
4597
4868
|
});
|
|
4598
4869
|
runnerCmd.command("uninstall").description("Stop the runner's service and remove it (needs --service)").option("--config <path>", configOption).option("--service", "remove the service, and the launch agent or scheduled task").option("--unit-name <name>", "the unit's name, when it is not the default").action(async (opts) => {
|
|
4599
4870
|
if (opts.service !== true) {
|
|
4600
|
-
fail(
|
|
4871
|
+
fail(`pass --service: \`${cliInvocation()} runner uninstall --service\` removes the runner's service.`);
|
|
4601
4872
|
return;
|
|
4602
4873
|
}
|
|
4603
|
-
const { defaultRunnerConfigPath } = await import('./config-
|
|
4604
|
-
const { uninstallServiceCommand } = await import('./command-
|
|
4874
|
+
const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
|
|
4875
|
+
const { uninstallServiceCommand } = await import('./command-H5CILO4S.js');
|
|
4605
4876
|
const result = await uninstallServiceCommand({ configPath: opts.config ?? defaultRunnerConfigPath(), unitName: opts.unitName, home: homeFromEnv() });
|
|
4606
4877
|
if (result.ok) for (const line of result.lines) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
|
|
4607
4878
|
`);
|
|
4608
4879
|
else fail(result.lines.length > 0 ? result.lines.join("\n ") : "the service was not removed");
|
|
4609
4880
|
});
|
|
4610
|
-
runnerCmd.command("init").description("Write a runner block that fits this machine; on macOS, offers a Linux VM").option("--config <path>", configOption).option("--vm", "on macOS, run the runner in a Linux VM (Lima), with container builds").option("--no-vm", "on macOS, skip the VM and run builds as unisolated processes").option("--allow-process-builds", "where builds cannot be isolated, run them as processes anyway").addOption(new Option("--config-stdin", "the VM-side hand-off: read the whole config as JSON on stdin").hideHelp()).option("--vm-cli-package <path>", "with --vm, install this packed CLI tarball in the VM").option("--unit-name <name>", "the service unit's name, to run a second runner beside the first").option("--agent <name>", "write commands that start this agent (claude); its credential comes on stdin").option("--
|
|
4881
|
+
runnerCmd.command("init").description("Write a runner block that fits this machine; on macOS, offers a Linux VM").option("--config <path>", configOption).option("--vm", "on macOS, run the runner in a Linux VM (Lima), with container builds").option("--no-vm", "on macOS, skip the VM and run builds as unisolated processes").option("--allow-process-builds", "where builds cannot be isolated, run them as processes anyway").addOption(new Option("--config-stdin", "the VM-side hand-off: read the whole config as JSON on stdin").hideHelp()).option("--vm-cli-package <path>", "with --vm, install this packed CLI tarball in the VM").option("--unit-name <name>", "the service unit's name, to run a second runner beside the first").option("--agent <name>", "write commands that start this agent (claude); its credential comes on stdin").option("--factory <org/factory>", "factory to create the runner key on, as <org>/<factory>").option("--app-id <id>", "factory id, instead of --factory (Settings \u2192 General)").addHelpText(
|
|
4611
4882
|
"after",
|
|
4612
|
-
|
|
4883
|
+
`
|
|
4884
|
+
With no apiKey in the config file, and a login saved by \`${cliInvocation()} login\`,
|
|
4885
|
+
runner init names the factory the runner is for: --factory, then --app-id,
|
|
4886
|
+
OUTERLAYER_APP_ID, or this repository's connection. With none of those, a
|
|
4887
|
+
login that can use one factory uses it, and one that can use several lists
|
|
4888
|
+
them. It then prints the factory's API keys page, where you create a key with
|
|
4889
|
+
the Runner preset, and asks you to paste it. Nothing is shown as you paste.
|
|
4890
|
+
With no terminal to ask on, it stops and says what to put in the config file.
|
|
4891
|
+
|
|
4892
|
+
With --agent claude, the queue commands start Claude Code instead of the
|
|
4893
|
+
placeholder, and Claude's credential is read from stdin: a token from
|
|
4894
|
+
\`claude setup-token\` (sk-ant-oat...) or an API key (sk-ant-api...). It is
|
|
4895
|
+
never printed, and is stored in the runner.env beside the config with mode
|
|
4896
|
+
600. Other lines in the file are kept. With nothing piped, a credential
|
|
4897
|
+
already in runner.env is used.
|
|
4898
|
+
|
|
4899
|
+
printf '%s' "$CLAUDE_CODE_OAUTH_TOKEN" | ${cliInvocation()} runner init --agent claude --factory <org>/<factory>
|
|
4900
|
+
`
|
|
4613
4901
|
).action(async (opts) => {
|
|
4614
|
-
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-
|
|
4615
|
-
const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-
|
|
4616
|
-
const {
|
|
4617
|
-
const { detectMachine } = await import('./machine-
|
|
4618
|
-
const { chooseVm, runVmInit, VmInitError } = await import('./init-
|
|
4619
|
-
const { AGENT_COMMANDS, credentialFromStdin, isAgentName, restartForCredential, RunnerEnvError } = await import('./runner-env-
|
|
4902
|
+
const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-FXDG4NPJ.js');
|
|
4903
|
+
const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-VWXIZEAN.js');
|
|
4904
|
+
const { obtainRunnerKey, runnerKeyLogin } = await import('./runner-key-TC3NFWFV.js');
|
|
4905
|
+
const { detectMachine } = await import('./machine-JOW4RNZ7.js');
|
|
4906
|
+
const { chooseVm, runVmInit, VmInitError } = await import('./init-WNXXYMO7.js');
|
|
4907
|
+
const { AGENT_COMMANDS, credentialFromStdin, isAgentName, restartForCredential, RunnerEnvError } = await import('./runner-env-4NB2GA7O.js');
|
|
4620
4908
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4621
4909
|
if (opts.agent !== void 0 && !isAgentName(opts.agent)) {
|
|
4622
4910
|
fail(`--agent ${opts.agent}: runner init writes commands for ${Object.keys(AGENT_COMMANDS).join(", ")}. For another agent, leave --agent out and edit runner.commands.`);
|
|
@@ -4630,7 +4918,7 @@ To keep it running, run ${C.yellow}outerlayer runner install --service${C.reset}
|
|
|
4630
4918
|
try {
|
|
4631
4919
|
let credential;
|
|
4632
4920
|
if (agent !== void 0) {
|
|
4633
|
-
const { readPipedKey } = await import('./login-browser-
|
|
4921
|
+
const { readPipedKey } = await import('./login-browser-O63QZN7D.js');
|
|
4634
4922
|
credential = credentialFromStdin(
|
|
4635
4923
|
await readPipedKey(process.stdin, {
|
|
4636
4924
|
onWaiting: () => process.stderr.write(`runner init is waiting for Claude's credential on stdin; close stdin to use the one already in runner.env
|
|
@@ -4640,14 +4928,14 @@ To keep it running, run ${C.yellow}outerlayer runner install --service${C.reset}
|
|
|
4640
4928
|
}
|
|
4641
4929
|
const machine = detectMachine();
|
|
4642
4930
|
if (opts.configStdin === true) {
|
|
4643
|
-
if (opts.appId !== void 0 || opts.
|
|
4644
|
-
fail("the VM-side hand-off carries its runner key in its config on stdin; pass no --app-id or --
|
|
4931
|
+
if (opts.appId !== void 0 || opts.factory !== void 0) {
|
|
4932
|
+
fail("the VM-side hand-off carries its runner key in its config on stdin; pass no --app-id or --factory with it.");
|
|
4645
4933
|
return;
|
|
4646
4934
|
}
|
|
4647
4935
|
const chunks = [];
|
|
4648
4936
|
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
4649
4937
|
const result2 = runRunnerInit(configPath, { machine, configFromStdin: Buffer.concat(chunks).toString("utf8"), requireContainer: true });
|
|
4650
|
-
const { ensureHostKey: ensureHostKey2 } = await import('./host-key-
|
|
4938
|
+
const { ensureHostKey: ensureHostKey2 } = await import('./host-key-U4B5QETR.js');
|
|
4651
4939
|
const hostKey2 = await ensureHostKey2(configPath);
|
|
4652
4940
|
process.stdout.write(`host key ${hostKey2.fingerprint}
|
|
4653
4941
|
hooks: ${result2.hooks}
|
|
@@ -4656,14 +4944,13 @@ hooks: ${result2.hooks}
|
|
|
4656
4944
|
`);
|
|
4657
4945
|
return;
|
|
4658
4946
|
}
|
|
4659
|
-
const login = runnerKeyLogin(configPath, { appId: opts.appId });
|
|
4660
|
-
if (login
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
}
|
|
4666
|
-
const makeKey = login === void 0 ? void 0 : () => createRunnerKey(login, { name: opts.keyName });
|
|
4947
|
+
const login = await runnerKeyLogin(configPath, { appId: opts.appId, factory: opts.factory });
|
|
4948
|
+
if (login?.note !== void 0) process.stdout.write(`${login.note}
|
|
4949
|
+
`);
|
|
4950
|
+
const { terminalPrompt } = await import('./hidden-prompt-UXBFMQC5.js');
|
|
4951
|
+
const readKey = login === void 0 ? void 0 : terminalPrompt();
|
|
4952
|
+
if (login !== void 0 && readKey === void 0) await obtainRunnerKey(login, { configPath, readKey });
|
|
4953
|
+
const makeKey = login === void 0 ? void 0 : () => obtainRunnerKey(login, { configPath, readKey });
|
|
4667
4954
|
let declinedVm = opts.vm === false;
|
|
4668
4955
|
const useVm = await chooseVm({
|
|
4669
4956
|
platform: machine.platform,
|
|
@@ -4698,6 +4985,8 @@ hooks: ${result2.hooks}
|
|
|
4698
4985
|
`)
|
|
4699
4986
|
});
|
|
4700
4987
|
for (const line of result2.lines) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
|
|
4988
|
+
`);
|
|
4989
|
+
for (const line of result2.warnings) process.stdout.write(`${C.yellow}!${C.reset} ${line}
|
|
4701
4990
|
`);
|
|
4702
4991
|
return;
|
|
4703
4992
|
}
|
|
@@ -4705,10 +4994,10 @@ hooks: ${result2.hooks}
|
|
|
4705
4994
|
const prepared = prepareRunnerInit(configPath, { machine, allowProcess, agent, credential, keyFromLogin: makeKey !== void 0 });
|
|
4706
4995
|
const created = makeKey === void 0 ? void 0 : await makeKey();
|
|
4707
4996
|
const result = writeRunnerInit(prepared, created);
|
|
4708
|
-
const { ensureHostKey } = await import('./host-key-
|
|
4997
|
+
const { ensureHostKey } = await import('./host-key-U4B5QETR.js');
|
|
4709
4998
|
const hostKey = await ensureHostKey(configPath);
|
|
4710
4999
|
if (created !== void 0) {
|
|
4711
|
-
process.stdout.write(`${C.green}\u2713${C.reset}
|
|
5000
|
+
process.stdout.write(`${C.green}\u2713${C.reset} saved the runner key in ${result.configPath}
|
|
4712
5001
|
`);
|
|
4713
5002
|
}
|
|
4714
5003
|
process.stdout.write(`${C.green}\u2713${C.reset} wrote a runner block into ${result.configPath}
|
|
@@ -4730,10 +5019,10 @@ ${C.yellow}${result.note}${C.reset}
|
|
|
4730
5019
|
`);
|
|
4731
5020
|
if (machine.platform === "darwin" && opts.vm === void 0) {
|
|
4732
5021
|
process.stdout.write(`
|
|
4733
|
-
To isolate builds in containers instead, run ${C.yellow}
|
|
5022
|
+
To isolate builds in containers instead, run ${C.yellow}${cliInvocation()} runner init --vm${C.reset}.
|
|
4734
5023
|
`);
|
|
4735
5024
|
}
|
|
4736
|
-
const { runRunnerInstall, RunnerInstallError, RunnerDowngradeError, launcherSummary } = await import('./install-cmd-
|
|
5025
|
+
const { runRunnerInstall, RunnerInstallError, RunnerDowngradeError, launcherSummary } = await import('./install-cmd-QDOTR4OM.js');
|
|
4737
5026
|
let installedLayout = false;
|
|
4738
5027
|
let noService = "it starts the runner from the install layout, which needs a CLI installed with npm";
|
|
4739
5028
|
try {
|
|
@@ -4765,7 +5054,7 @@ ${C.yellow}The runner will not update itself: ${installErr.message}${C.reset}
|
|
|
4765
5054
|
let serviceUp = false;
|
|
4766
5055
|
let restart;
|
|
4767
5056
|
if (installedLayout) {
|
|
4768
|
-
const { installServiceCommand } = await import('./command-
|
|
5057
|
+
const { installServiceCommand } = await import('./command-H5CILO4S.js');
|
|
4769
5058
|
const service = await installServiceCommand({
|
|
4770
5059
|
configPath,
|
|
4771
5060
|
entryPath: process.argv[1] ?? "",
|
|
@@ -4787,14 +5076,14 @@ ${C.yellow}The runner will not update itself: ${installErr.message}${C.reset}
|
|
|
4787
5076
|
if (restart !== void 0) process.stdout.write(`
|
|
4788
5077
|
${C.yellow}${restart}${C.reset}
|
|
4789
5078
|
`);
|
|
4790
|
-
const steps = agent === void 0 ? [`Edit the command lines in ${result.configPath} to start your agent.`, `${C.yellow}
|
|
4791
|
-
if (!serviceUp) steps.push(`${C.yellow}
|
|
5079
|
+
const steps = agent === void 0 ? [`Edit the command lines in ${result.configPath} to start your agent.`, `${C.yellow}${cliInvocation()} runner check${C.reset}`] : [`${C.yellow}${cliInvocation()} runner check${C.reset}`];
|
|
5080
|
+
if (!serviceUp) steps.push(`${C.yellow}${cliInvocation()} runner start${C.reset}, or ${C.yellow}${cliInvocation()} runner install --service${C.reset} to keep it running.`);
|
|
4792
5081
|
process.stdout.write(
|
|
4793
5082
|
`
|
|
4794
5083
|
Next:
|
|
4795
5084
|
` + steps.map((step, i) => ` ${i + 1}. ${step}
|
|
4796
|
-
`).join("") + (serviceUp && agent === void 0 ? ` The runner service claims nothing until step 1 is done and a Claude credential is in ${join(dirname(configPath), "runner.env")}; ${C.yellow}
|
|
4797
|
-
` : serviceUp ? ` The runner service is running; ${C.yellow}
|
|
5085
|
+
`).join("") + (serviceUp && agent === void 0 ? ` The runner service claims nothing until step 1 is done and a Claude credential is in ${join(dirname(configPath), "runner.env")}; ${C.yellow}${cliInvocation()} runner status${C.reset} shows what it is doing.
|
|
5086
|
+
` : serviceUp ? ` The runner service is running; ${C.yellow}${cliInvocation()} runner status${C.reset} shows what it is doing.
|
|
4798
5087
|
` : "")
|
|
4799
5088
|
);
|
|
4800
5089
|
} catch (err) {
|
|
@@ -4805,29 +5094,42 @@ Next:
|
|
|
4805
5094
|
throw err;
|
|
4806
5095
|
}
|
|
4807
5096
|
});
|
|
4808
|
-
runnerCmd.command("image").description("Build a repository's image from its
|
|
5097
|
+
runnerCmd.command("image").description("Build a repository's image from its governing repository's devcontainer").requiredOption("--repository <owner/name>", "the repository to build the image for").option("--remote <url>", "where to fetch from (default: the repository's GitHub URL)").option("--config <path>", configOption).option("--json", "machine-readable JSON output").addHelpText(
|
|
4809
5098
|
"after",
|
|
4810
|
-
"\
|
|
5099
|
+
"\nA repository governed by a control plane builds the control plane's image, at the commit\nthe gateway has stored for it. A repository that governs itself fetches the head of its\ndefault branch into the runner's cache. Either way it reads .devcontainer/devcontainer.json\nand builds the image with the devcontainer CLI. Settings\nthat reach the host or widen the container's privileges are ignored and listed. The\nimage holds this CLI and a pinned Claude Code. Nothing runs inside the image.\n"
|
|
4811
5100
|
).action(async (opts) => {
|
|
4812
|
-
const { defaultRunnerConfigPath } = await import('./config-
|
|
4813
|
-
const { buildRepositoryImage, RecipeError } = await import('./build-
|
|
5101
|
+
const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
|
|
5102
|
+
const { buildRepositoryImage, RecipeError } = await import('./build-TQ6X5PYN.js');
|
|
4814
5103
|
const { currentCliBuild } = await import('./cli-build-K56DK4DS.js');
|
|
4815
|
-
const { createDockerHost } = await import('./docker-
|
|
4816
|
-
const { builderSpec } = await import('./builder-
|
|
4817
|
-
const { loadRunnerConfig } = await import('./config-
|
|
5104
|
+
const { createDockerHost } = await import('./docker-RC3PRX3Q.js');
|
|
5105
|
+
const { builderSpec } = await import('./builder-DUI2ZH2H.js');
|
|
5106
|
+
const { loadRunnerConfig } = await import('./config-FXDG4NPJ.js');
|
|
4818
5107
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4819
|
-
const
|
|
5108
|
+
const loaded = (() => {
|
|
4820
5109
|
try {
|
|
4821
|
-
return loadRunnerConfig(configPath)
|
|
5110
|
+
return loadRunnerConfig(configPath);
|
|
4822
5111
|
} catch {
|
|
4823
|
-
return
|
|
5112
|
+
return void 0;
|
|
4824
5113
|
}
|
|
4825
5114
|
})();
|
|
5115
|
+
const memory = loaded?.build?.memory ?? "8g";
|
|
4826
5116
|
try {
|
|
5117
|
+
const { imageTargetFor } = await import('./governing-source-BUU4IABS.js');
|
|
5118
|
+
const target = await imageTargetFor({ config: loaded, repository: opts.repository, fetchImpl: fetch });
|
|
5119
|
+
if (!target.ok) {
|
|
5120
|
+
if (opts.json) {
|
|
5121
|
+
writeJson({ error: { code: "governing_source_unavailable", message: target.reason } });
|
|
5122
|
+
process.exitCode = 1;
|
|
5123
|
+
return;
|
|
5124
|
+
}
|
|
5125
|
+
fail(target.reason);
|
|
5126
|
+
return;
|
|
5127
|
+
}
|
|
4827
5128
|
const result = await buildRepositoryImage(
|
|
4828
5129
|
{
|
|
4829
|
-
repository:
|
|
4830
|
-
|
|
5130
|
+
repository: target.repository,
|
|
5131
|
+
...target.pinned === void 0 ? {} : { pinned: target.pinned },
|
|
5132
|
+
remote: target.pinned === void 0 ? opts.remote : void 0,
|
|
4831
5133
|
configPath,
|
|
4832
5134
|
cli: currentCliBuild(),
|
|
4833
5135
|
log: (line) => {
|
|
@@ -4875,22 +5177,22 @@ Next:
|
|
|
4875
5177
|
}
|
|
4876
5178
|
});
|
|
4877
5179
|
runnerCmd.command("stop").description("Take no more work; wait for running jobs to finish, then exit").option("--config <path>", "the cloud config file naming the runner to stop").option("--now", "end running jobs immediately, with outcome stopped").action(async (opts) => {
|
|
4878
|
-
const { defaultRunnerConfigPath } = await import('./config-
|
|
4879
|
-
const { requestStop } = await import('./loop-
|
|
5180
|
+
const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
|
|
5181
|
+
const { requestStop } = await import('./loop-UGI2BJOT.js');
|
|
4880
5182
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4881
5183
|
await requestStop(configPath, Boolean(opts.now));
|
|
4882
5184
|
});
|
|
4883
5185
|
runnerCmd.command("status").description("List running jobs; with --recent, finished ones too").option("--config <path>", "the cloud config file naming the runner to inspect").option("--recent", "also list finished jobs, newest first, capped at 20").option("--json", "machine-readable JSON output").action(async (opts) => {
|
|
4884
|
-
const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-
|
|
4885
|
-
const { jobsDir, runnerDir } = await import('./paths-
|
|
4886
|
-
const { listJobFiles, runnerProcessState } = await import('./loop-
|
|
4887
|
-
const { renderStatus } = await import('./status-
|
|
4888
|
-
const { readHousekeepingRecord } = await import('./record-
|
|
5186
|
+
const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-FXDG4NPJ.js');
|
|
5187
|
+
const { jobsDir, runnerDir } = await import('./paths-7XP63OAX.js');
|
|
5188
|
+
const { listJobFiles, runnerProcessState } = await import('./loop-UGI2BJOT.js');
|
|
5189
|
+
const { renderStatus } = await import('./status-TKCLLKFG.js');
|
|
5190
|
+
const { readHousekeepingRecord } = await import('./record-3WP6V2K5.js');
|
|
4889
5191
|
const path2 = await import('path');
|
|
4890
5192
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4891
5193
|
const all = listJobFiles(configPath);
|
|
4892
5194
|
const housekeeping = readHousekeepingRecord(runnerDir(configPath));
|
|
4893
|
-
const { readPendingUpdate } = await import('./pending-
|
|
5195
|
+
const { readPendingUpdate } = await import('./pending-532ABZYC.js');
|
|
4894
5196
|
const pendingUpdate = readPendingUpdate(runnerDir(configPath));
|
|
4895
5197
|
let host = "unknown";
|
|
4896
5198
|
let concurrency = 1;
|
|
@@ -4904,7 +5206,7 @@ Next:
|
|
|
4904
5206
|
const service = await (async () => {
|
|
4905
5207
|
if (process.platform !== "linux" || !existsSync("/run/systemd/system")) return void 0;
|
|
4906
5208
|
const { inspectService, realInspectProbes } = await import('./inspect-6UYAAXH7.js');
|
|
4907
|
-
const { DEFAULT_UNIT_NAME } = await import('./install-
|
|
5209
|
+
const { DEFAULT_UNIT_NAME } = await import('./install-CBWIEF3R.js');
|
|
4908
5210
|
const facts = inspectService(DEFAULT_UNIT_NAME, path2.dirname(configPath), realInspectProbes());
|
|
4909
5211
|
return facts === void 0 ? void 0 : { unit: facts.unit, running: facts.mainPid !== void 0, delegated: facts.delegate };
|
|
4910
5212
|
})();
|
|
@@ -4939,9 +5241,9 @@ Next:
|
|
|
4939
5241
|
);
|
|
4940
5242
|
});
|
|
4941
5243
|
runnerCmd.command("logs").argument("<item>", "the work item's number in the factory").description("Print the newest attempt's log for one item").option("--config <path>", "the cloud config file naming the runner to inspect").option("-f, --follow", "keep printing as the log grows").action(async (itemArg, opts) => {
|
|
4942
|
-
const { defaultRunnerConfigPath } = await import('./config-
|
|
4943
|
-
const { listJobFiles } = await import('./loop-
|
|
4944
|
-
const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-
|
|
5244
|
+
const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
|
|
5245
|
+
const { listJobFiles } = await import('./loop-UGI2BJOT.js');
|
|
5246
|
+
const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-AMLKC3VP.js');
|
|
4945
5247
|
const configPath = opts.config ?? defaultRunnerConfigPath();
|
|
4946
5248
|
const item = parseTrackerNumber(itemArg);
|
|
4947
5249
|
if (item === void 0) {
|
|
@@ -5162,9 +5464,22 @@ function registerMcpCommands(program2) {
|
|
|
5162
5464
|
const mcpCmd = program2.command("mcp").description("Configure MCP clients against the OuterLayer gateway");
|
|
5163
5465
|
mcpCmd.command("install").description("Write or update the OuterLayer entry in .mcp.json or .outerlayer/mcp.json").option("--transport <stdio|http>", "how the client connects (default: stdio)").option("--command <exe>", "stdio only: executable the client spawns (default: outerlayer)").option("--url <url>", "gateway MCP endpoint (defaults to the gateway you logged in to)").option("--name <name>", 'mcpServers key to write under (default: "outerlayer")').option("--dir <path>", "repo root to write into (default: cwd)").option("--app-id <uuid>", "self-host only: factory id sent as X-Outerlayer-App-Id").option("--json", "machine-readable JSON output").addHelpText(
|
|
5164
5466
|
"after",
|
|
5165
|
-
|
|
5467
|
+
`
|
|
5468
|
+
The API key is never a flag and never written to .mcp.json as a literal value.
|
|
5469
|
+
stdio (default): the client spawns \`${cliInvocation()} mcp serve\`, which reads the key
|
|
5470
|
+
from ~/.outerlayer/config.json (or OUTERLAYER_API_KEY) on every connect, so a
|
|
5471
|
+
rotated key is picked up without rewriting the entry.
|
|
5472
|
+
http: the entry carries the \${OUTERLAYER_API_KEY} placeholder, which the client
|
|
5473
|
+
resolves from the environment it was launched with.
|
|
5474
|
+
|
|
5475
|
+
--command: use an absolute or \${HOME}-relative path when the CLI is not on PATH.
|
|
5476
|
+
--url: with stdio the endpoint resolves from OUTERLAYER_URL / the config file at
|
|
5477
|
+
connect time; for self-host pass your gateway-node origin + /v1/mcp.
|
|
5478
|
+
Self-host deployments also need --app-id: without a key service to resolve the
|
|
5479
|
+
caller from the bearer token, the gateway answers 401 without that header.
|
|
5480
|
+
`
|
|
5166
5481
|
).action(async (opts) => {
|
|
5167
|
-
const { runMcpInstall, handleMcpInstallError, McpInstallError } = await import('./mcp-install-cmd-
|
|
5482
|
+
const { runMcpInstall, handleMcpInstallError, McpInstallError } = await import('./mcp-install-cmd-GGWB3JJ2.js');
|
|
5168
5483
|
try {
|
|
5169
5484
|
if (opts.transport !== void 0 && opts.transport !== "stdio" && opts.transport !== "http") {
|
|
5170
5485
|
throw new McpInstallError(`--transport must be "stdio" or "http", got "${opts.transport}"`);
|
|
@@ -5186,7 +5501,7 @@ function registerMcpCommands(program2) {
|
|
|
5186
5501
|
"after",
|
|
5187
5502
|
"\nWhat the stdio .mcp.json entry spawns. Reads newline-delimited JSON-RPC 2.0 on\nstdin and writes responses on stdout. The API key comes from OUTERLAYER_API_KEY\nor ~/.outerlayer/config.json at start-up; with neither the command exits 1 and\nprints why, which the MCP client shows as the connect error.\n"
|
|
5188
5503
|
).action(async (opts) => {
|
|
5189
|
-
const { runMcpServe, handleMcpServeError } = await import('./mcp-serve-cmd-
|
|
5504
|
+
const { runMcpServe, handleMcpServeError } = await import('./mcp-serve-cmd-DOTY5FKY.js');
|
|
5190
5505
|
try {
|
|
5191
5506
|
await runMcpServe({ url: opts.url, appId: opts.appId });
|
|
5192
5507
|
} catch (err) {
|
|
@@ -5197,7 +5512,7 @@ function registerMcpCommands(program2) {
|
|
|
5197
5512
|
function registerImportCommands(program2) {
|
|
5198
5513
|
const importCmd = program2.command("import").description("Import an existing config format into .outerlayer/");
|
|
5199
5514
|
importCmd.command("ruler").description("Port a .ruler/ tree into the equivalent .outerlayer/ tree").option("--dir <path>", "repo root to read from (default: cwd)").option("--json", "machine-readable JSON output").addHelpText("after", "\nRuler: https://github.com/intellectronica/ruler. Mostly a rename.\n").action(async (opts) => {
|
|
5200
|
-
const { runImportRuler, ImportRulerError } = await import('./import-ruler-cmd-
|
|
5515
|
+
const { runImportRuler, ImportRulerError } = await import('./import-ruler-cmd-KJMWL5V6.js');
|
|
5201
5516
|
try {
|
|
5202
5517
|
const result = runImportRuler({ cwd: opts.dir, json: opts.json });
|
|
5203
5518
|
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
@@ -5213,7 +5528,7 @@ function registerImportCommands(program2) {
|
|
|
5213
5528
|
"after",
|
|
5214
5529
|
"\nInstalls the four maintained skills (outerlayer-evidence, outerlayer-amend,\nouterlayer-findings, outerlayer-cli) and an AGENTS.md snippet teaching agents to run\n`emit artifact`. A skill that differs from this CLI's bundle is rewritten to it, and the output says so.\n"
|
|
5215
5530
|
).action(async (opts) => {
|
|
5216
|
-
const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-
|
|
5531
|
+
const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-ZO6KGHI2.js');
|
|
5217
5532
|
try {
|
|
5218
5533
|
runImportCapture({ cwd: opts.dir, json: opts.json });
|
|
5219
5534
|
} catch (err) {
|
|
@@ -5256,7 +5571,7 @@ function registerContextCommands(program2) {
|
|
|
5256
5571
|
await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
|
|
5257
5572
|
});
|
|
5258
5573
|
contextCmd.command("adopt <stagedDir>", { hidden: true }).description("Copy context the runner staged into this checkout (container builds)").option("--json", "machine-readable JSON output").action(async (stagedDir) => {
|
|
5259
|
-
const { runContextAdopt } = await import('./context-adopt-
|
|
5574
|
+
const { runContextAdopt } = await import('./context-adopt-O5OFXMKI.js');
|
|
5260
5575
|
const { exitCode, stdout } = runContextAdopt(stagedDir, process.cwd());
|
|
5261
5576
|
process.stdout.write(stdout);
|
|
5262
5577
|
process.exitCode = exitCode;
|
|
@@ -5265,7 +5580,7 @@ function registerContextCommands(program2) {
|
|
|
5265
5580
|
"after",
|
|
5266
5581
|
"\nThe same flow SessionStart runs automatically, exposed for a manual retry or a\nfirst check outside a session. Writes AGENTS.md, .claude/**, and .outerlayer/**.\n"
|
|
5267
5582
|
).action(async (opts) => {
|
|
5268
|
-
const { materializeContext } = await import('./context-materialize-
|
|
5583
|
+
const { materializeContext } = await import('./context-materialize-Y5IJ4MQT.js');
|
|
5269
5584
|
const result = await materializeContext({ cwd: process.cwd(), sessionId: `manual-${Date.now()}` });
|
|
5270
5585
|
const output = formatContextMaterializeOutput(result);
|
|
5271
5586
|
if (output.exitCode !== void 0) process.exitCode = output.exitCode;
|