@outerlayer/cli 0.18.0 → 0.19.1

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.
Files changed (102) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +21 -2
  3. package/dist/{agent-setup-RBTEACYU.js → agent-setup-AM42SA2D.js} +15 -16
  4. package/dist/{artifact-link-cmd-AVM2EKTV.js → artifact-link-cmd-OWRI5AJX.js} +2 -2
  5. package/dist/build-info.json +1 -1
  6. package/dist/{builder-DUI2ZH2H.js → builder-C4QNTYMS.js} +3 -3
  7. package/dist/{check-5C4YDZYV.js → check-W2JGXN3B.js} +44 -43
  8. package/dist/{chunk-S26M3YBJ.js → chunk-3UZTIRLF.js} +1 -1
  9. package/dist/{chunk-Y5MXET4M.js → chunk-3ZR7Y23Y.js} +11 -10
  10. package/dist/{chunk-47TTLEDX.js → chunk-5VML45HH.js} +35 -13
  11. package/dist/{chunk-F4XSVQJ4.js → chunk-6X4SQ5MY.js} +2 -2
  12. package/dist/{chunk-T4Y6SCG3.js → chunk-7UWVLZXD.js} +2 -2
  13. package/dist/{chunk-N3CUDFCW.js → chunk-7VUK5RFS.js} +15 -2
  14. package/dist/{chunk-SWCTGCSC.js → chunk-7YP7T6GV.js} +1 -1
  15. package/dist/{chunk-3OFZM4X6.js → chunk-B6SCN5NY.js} +151 -20
  16. package/dist/{chunk-KDVIU23F.js → chunk-BWSUPRDK.js} +1 -1
  17. package/dist/{chunk-S76AYB4M.js → chunk-CG36IONK.js} +5 -5
  18. package/dist/{chunk-RAZTWYZN.js → chunk-CGGPS7SI.js} +7 -8
  19. package/dist/chunk-CJJDJ7AT.js +56 -0
  20. package/dist/{chunk-W5VPCONO.js → chunk-EAEELQVQ.js} +33 -227
  21. package/dist/{chunk-QQM2UJ6T.js → chunk-F2KXHIFI.js} +182 -28
  22. package/dist/{chunk-KK4VBOH6.js → chunk-FBTGMSQF.js} +10 -11
  23. package/dist/{chunk-MQJSXHV7.js → chunk-G3IJ3N6F.js} +5 -3
  24. package/dist/{chunk-FUB7LRUE.js → chunk-GEMQLBMW.js} +5 -5
  25. package/dist/{chunk-Y5GE76XC.js → chunk-HOKXGFDR.js} +33 -81
  26. package/dist/{chunk-IP7BIBXJ.js → chunk-IF2OSI5T.js} +35 -1
  27. package/dist/{chunk-UYOYTKE2.js → chunk-JHGEBPLE.js} +3 -3
  28. package/dist/chunk-KYS3TQAG.js +296 -0
  29. package/dist/chunk-LLM3I5YU.js +89 -0
  30. package/dist/{chunk-B3UKB46N.js → chunk-LRG3ZMZD.js} +4 -5
  31. package/dist/{chunk-NL4XPC7W.js → chunk-LW7G5TJB.js} +1 -1
  32. package/dist/{chunk-MNTSH4CL.js → chunk-NNLA7LLQ.js} +1 -1
  33. package/dist/{chunk-GOBOJMOJ.js → chunk-PIZRPNKR.js} +4 -4
  34. package/dist/{chunk-ULSIJGLS.js → chunk-PSN33ERW.js} +56 -14
  35. package/dist/{chunk-WGAUY5LE.js → chunk-QEFKA2QD.js} +1 -1
  36. package/dist/{chunk-BMYGAGBJ.js → chunk-QNLX477Q.js} +155 -23
  37. package/dist/{chunk-JF42URPU.js → chunk-R22NZSGA.js} +33 -9
  38. package/dist/chunk-TUSYOL2O.js +113 -0
  39. package/dist/{chunk-ESC6UR76.js → chunk-TWF3RICI.js} +6 -6
  40. package/dist/{chunk-L2USZT6T.js → chunk-VMJPFQNE.js} +1 -1
  41. package/dist/{chunk-X5N6KC6V.js → chunk-WFSUUUAN.js} +2 -3
  42. package/dist/{chunk-6CHIYEZZ.js → chunk-XZ4H4X5F.js} +9 -83
  43. package/dist/{chunk-LXAY4A2G.js → chunk-YQR6E6OV.js} +34 -49
  44. package/dist/chunk-Z7K3L4FC.js +174 -0
  45. package/dist/{claude-launcher-YVXI76NX.js → claude-launcher-J5M44PFS.js} +20 -7
  46. package/dist/{cli-C77H54BV.js → cli-EXX2R73G.js} +206 -230
  47. package/dist/{command-H5CILO4S.js → command-ZQNEPDS6.js} +29 -30
  48. package/dist/{config-FXDG4NPJ.js → config-CLSGABD5.js} +2 -2
  49. package/dist/{connect-cmd-ZW5FV3ZW.js → connect-cmd-UNYKGDAL.js} +7 -7
  50. package/dist/context-cleanup-CHEWNYU6.js +11 -0
  51. package/dist/control-plane-launch-34LNRJWR.js +216 -0
  52. package/dist/{dist-QTX4RSCL.js → dist-WO7NOJNG.js} +2 -2
  53. package/dist/{docker-RC3PRX3Q.js → docker-BFU3AQGY.js} +4 -4
  54. package/dist/{doctor-2NQQML6P.js → doctor-DHUM5DBB.js} +32 -33
  55. package/dist/{emit-artifact-cmd-7MP63KXU.js → emit-artifact-cmd-XBHM647X.js} +17 -17
  56. package/dist/{emit-cmd-PPN4QQF2.js → emit-cmd-W55AEBCA.js} +6 -6
  57. package/dist/{emit-criteria-cmd-3RXPDLNK.js → emit-criteria-cmd-CRTYEF7D.js} +11 -12
  58. package/dist/{emit-finding-cmd-OL7JB6H3.js → emit-finding-cmd-7JHVRYOP.js} +12 -13
  59. package/dist/{emit-result-cmd-UZVMOCF4.js → emit-result-cmd-5NZMLCJK.js} +17 -17
  60. package/dist/emit-step-cmd-347XNGPQ.js +26 -0
  61. package/dist/{governing-source-BUU4IABS.js → governing-source-HAA4OW57.js} +21 -22
  62. package/dist/{hook-fast-W5MKHMJT.js → hook-fast-RL5E5OXE.js} +3 -3
  63. package/dist/{import-capture-cmd-ZO6KGHI2.js → import-capture-cmd-TK4XY7RD.js} +4 -4
  64. package/dist/{import-ruler-cmd-KJMWL5V6.js → import-ruler-cmd-T6LLO6Q7.js} +2 -2
  65. package/dist/index.js +4 -4
  66. package/dist/{init-WNXXYMO7.js → init-V6FOMD2V.js} +30 -31
  67. package/dist/{init-VWXIZEAN.js → init-XG47KCI4.js} +30 -31
  68. package/dist/{init-cmd-WS6TIRYT.js → init-cmd-Z4O4PPLZ.js} +70 -27
  69. package/dist/{init-update-E3J6TVIN.js → init-update-7DVAKWW3.js} +21 -22
  70. package/dist/{install-CBWIEF3R.js → install-4SEFIIW2.js} +3 -3
  71. package/dist/{login-browser-O63QZN7D.js → login-browser-DX35MARZ.js} +2 -2
  72. package/dist/{loop-UGI2BJOT.js → loop-TPUYUMSY.js} +44 -43
  73. package/dist/{machine-JOW4RNZ7.js → machine-TRHBT5NE.js} +26 -27
  74. package/dist/{mcp-serve-cmd-DOTY5FKY.js → mcp-serve-cmd-N3UTY6EE.js} +5 -5
  75. package/dist/{runner-env-4NB2GA7O.js → runner-env-FRZFFHDF.js} +4 -4
  76. package/dist/{runner-key-TC3NFWFV.js → runner-key-5FOWCW7J.js} +30 -31
  77. package/dist/{session-sender-NNVPSPY7.js → session-sender-U2BBUWNO.js} +19 -15
  78. package/dist/shell-function-NRD4KVUK.js +6 -0
  79. package/dist/{spec-cmd-OWVTBB4J.js → spec-cmd-FVLJOFGC.js} +12 -13
  80. package/dist/{starter-pack-OPWUDOWX.js → starter-pack-6LQVLBIA.js} +5 -5
  81. package/dist/{status-TKCLLKFG.js → status-BINH7MBG.js} +33 -32
  82. package/dist/{sync-cmd-Q6VYNPWG.js → sync-cmd-VXOUFS4I.js} +18 -14
  83. package/dist/{watch-ARAGADTF.js → watch-OH645CV2.js} +18 -14
  84. package/dist/{work-claim-cmd-34FERLYX.js → work-claim-cmd-ZRPSHMPT.js} +16 -17
  85. package/dist/{work-cmd-7S5B2H2P.js → work-cmd-5I3J2XQQ.js} +12 -13
  86. package/dist/{work-comment-cmd-SZJSPM5S.js → work-comment-cmd-UCCPWUSR.js} +12 -13
  87. package/dist/work-logs-cmd-7352CJPG.js +60 -0
  88. package/dist/{work-open-pr-cmd-RPXKCBWS.js → work-open-pr-cmd-LSH4VHJM.js} +13 -14
  89. package/dist/{work-pr-cmd-5LGANL32.js → work-pr-cmd-H4OQR26N.js} +12 -13
  90. package/package.json +2 -2
  91. package/skill-pack/maintained/outerlayer-cli/SKILL.md +9 -2
  92. package/skill-pack/maintained/outerlayer-cli/references/find-out-why-a-build-ended.md +76 -0
  93. package/skill-pack/shipped.json +1 -0
  94. package/skill-pack/template/build/references/release.md +3 -1
  95. package/dist/chunk-WBT5X3NH.js +0 -40
  96. package/dist/chunk-XCCLFVXM.js +0 -401
  97. package/dist/context-adopt-O5OFXMKI.js +0 -109
  98. package/dist/context-materialize-Y5IJ4MQT.js +0 -23
  99. package/dist/{chunk-NACDBXUG.js → chunk-BM63HB2M.js} +1 -1
  100. package/dist/{chunk-ZRL6HKBY.js → chunk-FVMYKL6L.js} +1 -1
  101. package/dist/{chunk-52NC2FIU.js → chunk-NTRCK4NH.js} +1 -1
  102. package/dist/{chunk-XGP3VYOG.js → chunk-P53VEAOF.js} +1 -1
@@ -1,41 +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-Y5GE76XC.js';
4
- import './chunk-ESC6UR76.js';
5
- import { verifiedTrackerNames, TRACKERS } from './chunk-KK4VBOH6.js';
6
- import './chunk-WBT5X3NH.js';
7
- import './chunk-IP7BIBXJ.js';
8
- import './chunk-S76AYB4M.js';
9
- import './chunk-MQJSXHV7.js';
3
+ import { gatherDoctorChecks, doctorExitCode, summarizeChecks, renderDoctorText, recordWrapped, recordUnwrapped, recordRemoval, readManifest, recordInstall, recordStatusline } from './chunk-HOKXGFDR.js';
4
+ import './chunk-TWF3RICI.js';
5
+ import { verifiedTrackerNames, TRACKERS } from './chunk-FBTGMSQF.js';
6
+ import './chunk-IF2OSI5T.js';
7
+ import './chunk-CG36IONK.js';
8
+ import './chunk-G3IJ3N6F.js';
9
+ import './chunk-BM63HB2M.js';
10
+ import { hookFiredMarkerPath, installedCliDistDir } from './chunk-PSN33ERW.js';
10
11
  import './chunk-DSF2FWAZ.js';
11
12
  import './chunk-BKO6JEZI.js';
12
- import './chunk-BMYGAGBJ.js';
13
+ import './chunk-QNLX477Q.js';
13
14
  import './chunk-YVZJ6GKF.js';
14
- import './chunk-F4XSVQJ4.js';
15
- import './chunk-NACDBXUG.js';
15
+ import './chunk-6X4SQ5MY.js';
16
16
  import './chunk-GOSFARMS.js';
17
- import { C, NO_COLOR_FLAG, warnDeprecated, stripNoColor, API_KEY_FLAG_DEPRECATION } from './chunk-ANPNT6PM.js';
17
+ import { C, warnDeprecated, API_KEY_FLAG_DEPRECATION, NO_COLOR_FLAG, stripNoColor } 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-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';
20
+ import './chunk-7UWVLZXD.js';
21
+ import './chunk-FVMYKL6L.js';
22
+ import './chunk-NTRCK4NH.js';
23
+ import './chunk-ZJSNLVCE.js';
24
+ import { findGitDirs } from './chunk-BJ3KTMDH.js';
25
+ import './chunk-G2YNJIGF.js';
26
+ import './chunk-NNLA7LLQ.js';
27
27
  import './chunk-EABW6AJQ.js';
28
+ import { cliInvocation, packageRunnerOf } from './chunk-CRB3POP4.js';
29
+ import { cloneIsGoverned } from './chunk-YQR6E6OV.js';
30
+ import { removeJournalHooks, removePreCommitGuardHook } from './chunk-TUSYOL2O.js';
31
+ import './chunk-WFSUUUAN.js';
32
+ import './chunk-7VUK5RFS.js';
33
+ import { homeFromEnv } from './chunk-VNVZDWO3.js';
28
34
  import { resolveVersion } from './chunk-RA3O54FC.js';
29
35
  import './chunk-M2ZWWTWZ.js';
30
36
  import './chunk-N2PXGQRL.js';
31
37
  import './chunk-BQXFBI7T.js';
32
- import { hookFiredMarkerPath, installedCliDistDir } from './chunk-ULSIJGLS.js';
33
- import './chunk-G2YNJIGF.js';
34
- import { managedHookScripts, removeJournalHooks, installPreCommitGuardHook, removePreCommitGuardHook } from './chunk-XCCLFVXM.js';
35
- import './chunk-ZJSNLVCE.js';
36
- import './chunk-BJ3KTMDH.js';
37
- import { cliInvocation, packageRunnerOf } from './chunk-CRB3POP4.js';
38
- import { homeFromEnv } from './chunk-VNVZDWO3.js';
39
38
  import './chunk-Z5GEFMRW.js';
40
39
  import { EventEmitter } from 'events';
41
40
  import childProcess, { execFileSync } from 'child_process';
@@ -3548,7 +3547,6 @@ function runInit(opts) {
3548
3547
  recordStatusline(manifestHome, path2, statuslineWrappedCommand !== void 0 ? "wrapped" : "installed", statuslineWrappedCommand);
3549
3548
  }
3550
3549
  const gitHookRemoval = removeJournalHooks(opts.cwd ?? process.cwd());
3551
- const guardHook = installPreCommitGuardHook(opts.cwd ?? process.cwd());
3552
3550
  let gitignoreUpdated = false;
3553
3551
  if (scope === "project" && opts.addGitignore) {
3554
3552
  gitignoreUpdated = ensureGitignore(opts.cwd ?? process.cwd());
@@ -3560,7 +3558,6 @@ function runInit(opts) {
3560
3558
  events: REGISTERED_EVENTS,
3561
3559
  gitignoreUpdated,
3562
3560
  ...gitHookRemoval.removed ? { gitHookRemoved: true } : {},
3563
- guardHook,
3564
3561
  wrapped,
3565
3562
  ...statusline ? { statusline } : {},
3566
3563
  ...statuslineWrappedCommand ? { statuslineWrappedCommand } : {}
@@ -3578,8 +3575,12 @@ function tracksOwnOuterlayerDir(cwd) {
3578
3575
  return false;
3579
3576
  }
3580
3577
  }
3578
+ function isGovernedCheckout(cwd) {
3579
+ const dirs = findGitDirs(cwd);
3580
+ return dirs !== void 0 && cloneIsGoverned(dirs.gitCommonDir);
3581
+ }
3581
3582
  function ensureGitignore(cwd) {
3582
- if (tracksOwnOuterlayerDir(cwd) || pinExists(cwd)) return false;
3583
+ if (tracksOwnOuterlayerDir(cwd) || isGovernedCheckout(cwd)) return false;
3583
3584
  const gitignore = join(cwd, ".gitignore");
3584
3585
  const entry = ".outerlayer/";
3585
3586
  let contents = "";
@@ -3647,11 +3648,8 @@ function writeJson(value) {
3647
3648
  function apiKeyOption() {
3648
3649
  return new Option("--api-key <key>", `deprecated: use \`${cliInvocation()} login\` or OUTERLAYER_API_KEY`).hideHelp();
3649
3650
  }
3650
- function warnIfApiKeyFlag(opts) {
3651
- if (opts.apiKey !== void 0) warnDeprecated(API_KEY_FLAG_DEPRECATION);
3652
- }
3653
3651
  async function installStarterPackInRepo() {
3654
- const { installStarterPack, formatStarterPackOutput } = await import('./starter-pack-OPWUDOWX.js');
3652
+ const { installStarterPack, formatStarterPackOutput } = await import('./starter-pack-6LQVLBIA.js');
3655
3653
  const cwd = process.cwd();
3656
3654
  let repoRoot = cwd;
3657
3655
  try {
@@ -3743,39 +3741,6 @@ turn and at the end of the session, at most once every five minutes.
3743
3741
  );
3744
3742
  return lines.join("");
3745
3743
  }
3746
- function formatGuardInstallOutput(guard) {
3747
- switch (guard.status) {
3748
- case "installed":
3749
- case "updated":
3750
- case "unchanged":
3751
- return { lines: [`${C.green}\u2713${C.reset} materialized-context commit guard ${guard.status} \u2192 ${guard.path}`] };
3752
- case "skipped-foreign":
3753
- if (guard.adopted) {
3754
- return { lines: [`${C.green}\u2713${C.reset} materialized-context commit guard hand-adopted into ${guard.path} \u2014 left untouched.`] };
3755
- }
3756
- return {
3757
- lines: [
3758
- `${C.yellow}!${C.reset} a pre-commit hook we did not write already exists (${guard.path}) \u2014 left untouched.`,
3759
- ` Append the guard script yourself: ${C.yellow}${cliInvocation()} hooks install-git --print${C.reset}`,
3760
- ` Place it before any exit in the existing hook \u2014 code after an early exit never runs.`
3761
- ],
3762
- exitCode: 1
3763
- };
3764
- case "skipped-custom-hooks-path":
3765
- if (guard.adopted) {
3766
- return { lines: [`${C.green}\u2713${C.reset} materialized-context commit guard hand-adopted at ${guard.path} (core.hooksPath) \u2014 left untouched.`] };
3767
- }
3768
- return {
3769
- lines: [
3770
- `${C.yellow}!${C.reset} this repo manages hooks in its working tree (core.hooksPath) \u2014 nothing written.`,
3771
- ` Add the script to your hook manager instead: ${C.yellow}${cliInvocation()} hooks install-git --print${C.reset}`
3772
- ],
3773
- exitCode: 1
3774
- };
3775
- case "not-a-repo":
3776
- return { lines: [], error: "not inside a git repository." };
3777
- }
3778
- }
3779
3744
  async function installHooks(opts, resolvedBin, connected, starterTemplate, withNext = true) {
3780
3745
  const scope = opts.project ? "project" : "user";
3781
3746
  let cliBin;
@@ -3814,8 +3779,8 @@ ${starter.output}`),
3814
3779
  }
3815
3780
  }
3816
3781
  async function realConnectDepsForCwd() {
3817
- const { realConnectDeps } = await import('./connect-cmd-ZW5FV3ZW.js');
3818
- const { resolveRepoIdentity } = await import('./dist-QTX4RSCL.js');
3782
+ const { realConnectDeps } = await import('./connect-cmd-UNYKGDAL.js');
3783
+ const { resolveRepoIdentity } = await import('./dist-WO7NOJNG.js');
3819
3784
  return {
3820
3785
  ...realConnectDeps(),
3821
3786
  home: homeFromEnv(),
@@ -3830,13 +3795,15 @@ function invokedCommandToken(argv) {
3830
3795
  }
3831
3796
  function buildProgram(argv = process.argv) {
3832
3797
  const program2 = new Command();
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(
3798
+ program2.name(cliInvocation()).description("OuterLayer \u2014 see what your coding agents actually do").enablePositionalOptions().version(resolveVersion()).hook("preAction", (_root, command) => {
3799
+ if (command.opts().apiKey !== void 0) warnDeprecated(API_KEY_FLAG_DEPRECATION);
3800
+ }).option(NO_COLOR_FLAG, "disable color (NO_COLOR=1 does the same)").addHelpText("after", SUPPORT_TEXT);
3801
+ 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("--shell-function", "make plain claude run `outerlayer claude` (edits ~/.zshrc or ~/.bashrc)").option("--no-shell-function", "do not set up the shell function, and remove it if it is there").option("--json", "machine-readable JSON output").addHelpText(
3835
3802
  "after",
3836
3803
  `
3837
3804
  In a repository, init runs four steps: connect the repository to a
3838
3805
  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
3806
+ and run \`${cliInvocation()} doctor\`. It never signs in. With no
3840
3807
  login it skips the connect step and says to run \`${cliInvocation()} login\`. With
3841
3808
  --json it prints one document naming the outcome of each step: done,
3842
3809
  skipped or failed. The exit code is 1 when a step failed.
@@ -3876,7 +3843,7 @@ states under Starter files.
3876
3843
  `
3877
3844
  ).action(async (opts) => {
3878
3845
  if (opts.update || opts.dryRun) {
3879
- const { runInitUpdate, formatInitUpdate, updateFlagProblem } = await import('./init-update-E3J6TVIN.js');
3846
+ const { runInitUpdate, formatInitUpdate, updateFlagProblem } = await import('./init-update-7DVAKWW3.js');
3880
3847
  const problem = updateFlagProblem(opts);
3881
3848
  if (problem !== void 0) {
3882
3849
  fail(problem);
@@ -3890,7 +3857,7 @@ states under Starter files.
3890
3857
  }
3891
3858
  let starterTemplate;
3892
3859
  if (opts.template !== void 0) {
3893
- const { assertKnownTemplate, StarterPackError } = await import('./starter-pack-OPWUDOWX.js');
3860
+ const { assertKnownTemplate, StarterPackError } = await import('./starter-pack-6LQVLBIA.js');
3894
3861
  try {
3895
3862
  assertKnownTemplate(opts.template);
3896
3863
  } catch (err) {
@@ -3917,13 +3884,20 @@ states under Starter files.
3917
3884
  fail(outcome.text);
3918
3885
  return;
3919
3886
  }
3920
- if (opts.json) writeJson(outcome.result);
3921
- else process.stdout.write(outcome.text);
3887
+ if (opts.remove) {
3888
+ const { removeShellFunction } = await import('./shell-function-NRD4KVUK.js');
3889
+ const changed = removeShellFunction({ home: homeFromEnv() });
3890
+ if (changed.length > 0 && !opts.json) process.stdout.write(`Removed the claude function from ${changed.join(", ")}.
3891
+ `);
3892
+ }
3893
+ const shell = !opts.remove && opts.shellFunction !== void 0 ? (await import('./init-cmd-Z4O4PPLZ.js')).applyShellFunctionFlag(opts.shellFunction, { home: homeFromEnv(), shellPath: process.env.SHELL }) : void 0;
3894
+ if (opts.json) writeJson(shell === void 0 ? outcome.result : { ...outcome.result, shellFunction: { outcome: shell.outcome, reason: shell.reason } });
3895
+ else process.stdout.write(outcome.text + (shell?.text ?? ""));
3922
3896
  return;
3923
3897
  }
3924
- const { runInitCommand } = await import('./init-cmd-WS6TIRYT.js');
3898
+ const { runInitCommand } = await import('./init-cmd-Z4O4PPLZ.js');
3925
3899
  const code = await runInitCommand(
3926
- { json: opts.json, factory: opts.factory },
3900
+ { json: opts.json, factory: opts.factory, shellFunction: opts.shellFunction },
3927
3901
  {
3928
3902
  connect: await realConnectDepsForCwd(),
3929
3903
  stdout: process.stdout,
@@ -3933,10 +3907,26 @@ states under Starter files.
3933
3907
  return { ok, text, detail };
3934
3908
  },
3935
3909
  runAgentSetup: async () => {
3936
- const { runAgentSetup } = await import('./agent-setup-RBTEACYU.js');
3910
+ const { runAgentSetup } = await import('./agent-setup-AM42SA2D.js');
3937
3911
  return runAgentSetup({ cwd: process.cwd() });
3938
3912
  },
3939
- runDoctorChecks: gatherDoctorChecks
3913
+ runDoctorChecks: gatherDoctorChecks,
3914
+ shell: {
3915
+ home: homeFromEnv(),
3916
+ shellPath: process.env.SHELL,
3917
+ interactive: Boolean(process.stdin.isTTY && process.stderr.isTTY) && opts.json !== true,
3918
+ ask: async () => {
3919
+ const { promptOnTerminal } = await import('./connect-cmd-UNYKGDAL.js');
3920
+ const answer = await promptOnTerminal({
3921
+ message: `Should plain claude start Claude Code through ${cliInvocation()} claude? That is how a session in a governed repository gets its control plane. It adds one block to your zsh or bash startup file.`,
3922
+ options: [
3923
+ { label: "Yes, add the block", value: "yes" },
3924
+ { label: "No, I will run outerlayer claude myself", value: "no" }
3925
+ ]
3926
+ });
3927
+ return answer === "yes";
3928
+ }
3929
+ }
3940
3930
  }
3941
3931
  );
3942
3932
  if (code !== 0) process.exitCode = code;
@@ -3965,7 +3955,7 @@ linked (true, false, or null when it could not be checked) and, when false,
3965
3955
  linkUrl.
3966
3956
  `
3967
3957
  ).action(async (opts) => {
3968
- const { runConnectCommand } = await import('./connect-cmd-ZW5FV3ZW.js');
3958
+ const { runConnectCommand } = await import('./connect-cmd-UNYKGDAL.js');
3969
3959
  const code = await runConnectCommand({ factory: opts.factory, json: opts.json }, await realConnectDepsForCwd(), {
3970
3960
  stdout: process.stdout,
3971
3961
  stderr: process.stderr
@@ -4004,7 +3994,7 @@ Every later command reads the saved file, so none of them needs a key on
4004
3994
  its command line. A saved key is checked for real on the first \`sync\`.
4005
3995
  `
4006
3996
  ).action(async (opts) => {
4007
- const { runLoginCommand, realLoginDeps } = await import('./login-browser-O63QZN7D.js');
3997
+ const { runLoginCommand, realLoginDeps } = await import('./login-browser-DX35MARZ.js');
4008
3998
  const code = await runLoginCommand(
4009
3999
  {
4010
4000
  browser: opts.browser !== false,
@@ -4036,15 +4026,14 @@ code is 1: revoke the token on /profile/security.
4036
4026
  "after",
4037
4027
  "\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"
4038
4028
  ).action(async (opts) => {
4039
- warnIfApiKeyFlag(opts);
4040
4029
  if (opts.link !== void 0) {
4041
- const { lookupArtifactLink } = await import('./artifact-link-cmd-AVM2EKTV.js');
4030
+ const { lookupArtifactLink } = await import('./artifact-link-cmd-OWRI5AJX.js');
4042
4031
  const found = lookupArtifactLink(opts.link);
4043
4032
  if (found.ok) process.stdout.write(found.url + "\n");
4044
4033
  else fail(found.reason);
4045
4034
  return;
4046
4035
  }
4047
- const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-Q6VYNPWG.js');
4036
+ const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-VXOUFS4I.js');
4048
4037
  try {
4049
4038
  const result = await runSync({
4050
4039
  url: opts.url,
@@ -4075,7 +4064,7 @@ code is 1: revoke the token on /profile/security.
4075
4064
  if (invokedCommandToken(argv) === "watch") {
4076
4065
  warnDeprecated(`\`${cliInvocation()} watch\` is now \`${cliInvocation()} daemon\`; the old name will be removed in a future release.`);
4077
4066
  }
4078
- const { runWatch } = await import('./watch-ARAGADTF.js');
4067
+ const { runWatch } = await import('./watch-OH645CV2.js');
4079
4068
  await runWatch({ once: opts.once });
4080
4069
  });
4081
4070
  program2.command("hook <event>", { hidden: true }).description("capture-hook fast path, installed by `init`").action(() => {
@@ -4084,7 +4073,7 @@ code is 1: revoke the token on /profile/security.
4084
4073
  });
4085
4074
  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(() => {
4086
4075
  });
4087
- program2.command("claude [args...]", { hidden: true }).description("start Claude Code with the repository's control plane attached").allowUnknownOption().helpOption(false).action(() => {
4076
+ program2.command("claude [args...]").description("start Claude Code with the repository's control plane attached").allowUnknownOption().helpOption(false).action(() => {
4088
4077
  });
4089
4078
  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) => {
4090
4079
  const { startRelay } = await import('./relay-L76HDX72.js');
@@ -4131,7 +4120,7 @@ code is 1: revoke the token on /profile/security.
4131
4120
  }
4132
4121
  });
4133
4122
  program2.command("session-sender", { hidden: true }).description("stream a runner build's sessions to its work item while the build runs").action(async () => {
4134
- const { runSessionSender } = await import('./session-sender-NNVPSPY7.js');
4123
+ const { runSessionSender } = await import('./session-sender-U2BBUWNO.js');
4135
4124
  try {
4136
4125
  await runSessionSender();
4137
4126
  } catch (err) {
@@ -4167,7 +4156,7 @@ async function runCli(processArgv) {
4167
4156
  await buildProgram(argv).parseAsync(argv);
4168
4157
  }
4169
4158
  async function compileContext(opts) {
4170
- const { runEmit, EmitError } = await import('./emit-cmd-PPN4QQF2.js');
4159
+ const { runEmit, EmitError } = await import('./emit-cmd-W55AEBCA.js');
4171
4160
  try {
4172
4161
  const result = runEmit({ cwd: opts.dir, check: opts.check, json: opts.json });
4173
4162
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
@@ -4204,7 +4193,8 @@ criterion's thread instead \u2014 see \`${cliInvocation()} work comment\`.
4204
4193
 
4205
4194
  Subcommands: \`emit artifact <file>\` for screenshots, recordings, reports and
4206
4195
  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.
4196
+ \`emit criteria <file>\` to record a work item's acceptance criteria;
4197
+ \`emit step <name>\` to report that you started a step.
4208
4198
  Compiling .outerlayer/ moved to \`${cliInvocation()} context emit\`.
4209
4199
  `
4210
4200
  ).action(async (name, opts) => {
@@ -4213,8 +4203,7 @@ Compiling .outerlayer/ moved to \`${cliInvocation()} context emit\`.
4213
4203
  await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
4214
4204
  return;
4215
4205
  }
4216
- warnIfApiKeyFlag(opts);
4217
- const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-UZVMOCF4.js');
4206
+ const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-5NZMLCJK.js');
4218
4207
  try {
4219
4208
  const result = await runEmitResult({
4220
4209
  name,
@@ -4264,8 +4253,7 @@ everywhere, bytes and deep link untouched; a still-queued one is cancelled
4264
4253
  locally so it never uploads. One correction can retire several duplicates.
4265
4254
  `
4266
4255
  ).action(async (file, opts) => {
4267
- warnIfApiKeyFlag(opts);
4268
- const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-7MP63KXU.js');
4256
+ const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-XBHM647X.js');
4269
4257
  let pr;
4270
4258
  if (opts.pr !== void 0) {
4271
4259
  pr = parseTrackerNumber(opts.pr);
@@ -4324,8 +4312,7 @@ recent events with their ids. --find <text> searches all of them.
4324
4312
  item that session was launched for is used automatically.
4325
4313
  `
4326
4314
  ).action(async (opts) => {
4327
- warnIfApiKeyFlag(opts);
4328
- const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-OL7JB6H3.js');
4315
+ const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-7JHVRYOP.js');
4329
4316
  try {
4330
4317
  refuseRemovedFindingFlags(opts);
4331
4318
  const result = await runEmitFinding({
@@ -4392,8 +4379,7 @@ the whole batch. "untimed": true records one with no time on purpose.
4392
4379
  that session was launched for is used automatically.
4393
4380
  `
4394
4381
  ).action(async (file, opts) => {
4395
- warnIfApiKeyFlag(opts);
4396
- const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-OL7JB6H3.js');
4382
+ const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-7JHVRYOP.js');
4397
4383
  try {
4398
4384
  const result = await runEmitFindings({
4399
4385
  file,
@@ -4412,6 +4398,40 @@ that session was launched for is used automatically.
4412
4398
  throw err;
4413
4399
  }
4414
4400
  });
4401
+ emitCmd.command("step <name>").description("Report that you started a step; the work item's Activity tab shows it").option("--item <number>", "work item to report on, 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(
4402
+ "after",
4403
+ `
4404
+ ${cliInvocation()} emit step "Review round 2"
4405
+ ${cliInvocation()} emit step "Plan" --item 412
4406
+
4407
+ Run it when you start a step. The name is free text: 1 to 80 characters on one
4408
+ line. A step has a start and nothing else, so run it again for the next step.
4409
+ --item names the work item; without it, inside a recorded session, the item that
4410
+ session was launched for is used.
4411
+
4412
+ If the gateway cannot be reached, the step is queued with the time you ran the
4413
+ command, the command exits 0, and \`sync\` sends it later. If the gateway refuses
4414
+ the step, the command prints why and exits 1.
4415
+ `
4416
+ ).action(async (name, opts) => {
4417
+ const { runEmitStep, EmitStepError } = await import('./emit-step-cmd-347XNGPQ.js');
4418
+ try {
4419
+ await runEmitStep({
4420
+ name,
4421
+ item: opts.item,
4422
+ json: opts.json,
4423
+ url: opts.url,
4424
+ apiKey: opts.apiKey,
4425
+ appId: opts.appId
4426
+ });
4427
+ } catch (err) {
4428
+ if (err instanceof EmitStepError) {
4429
+ fail(err.message);
4430
+ return;
4431
+ }
4432
+ throw err;
4433
+ }
4434
+ });
4415
4435
  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(
4416
4436
  "after",
4417
4437
  `
@@ -4432,8 +4452,7 @@ agent session, with your own login. A key bound to no member cannot replace it e
4432
4452
  session was launched for is used automatically.
4433
4453
  `
4434
4454
  ).action(async (file, opts) => {
4435
- warnIfApiKeyFlag(opts);
4436
- const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-3RXPDLNK.js');
4455
+ const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-CRTYEF7D.js');
4437
4456
  try {
4438
4457
  const result = await runEmitCriteria({
4439
4458
  file,
@@ -4456,11 +4475,10 @@ session was launched for is used automatically.
4456
4475
  function registerSpecCommands(program2) {
4457
4476
  const specCmd = program2.command("spec").description("Find, file and edit the issue a spec lives in, in your factory's tracker");
4458
4477
  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');
4478
+ const run = async (action) => {
4479
+ const { WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4462
4480
  try {
4463
- await action(await import('./spec-cmd-OWVTBB4J.js'));
4481
+ await action(await import('./spec-cmd-FVLJOFGC.js'));
4464
4482
  } catch (err) {
4465
4483
  if (err instanceof WorkCommandError) {
4466
4484
  fail(err.message);
@@ -4471,16 +4489,16 @@ function registerSpecCommands(program2) {
4471
4489
  };
4472
4490
  credentialOptions(
4473
4491
  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)));
4492
+ ).action((opts) => run((spec) => spec.runSpecTarget(opts)));
4475
4493
  credentialOptions(
4476
4494
  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 })));
4495
+ ).action((query, opts) => run((spec) => spec.runSpecSearch({ ...opts, query })));
4478
4496
  credentialOptions(
4479
4497
  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)));
4498
+ ).action((opts) => run((spec) => spec.runSpecFile(opts)));
4481
4499
  credentialOptions(
4482
4500
  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 })));
4501
+ ).action((key, opts) => run((spec) => spec.runSpecEdit({ ...opts, key })));
4484
4502
  }
4485
4503
  function registerWorkCommands(program2) {
4486
4504
  const workCmd = program2.command("work").description("Start, remove, or read what the factory is working on (the Work page)");
@@ -4501,8 +4519,7 @@ takes it, and prints the line that starts your session on it. That
4501
4519
  session links itself and holds the item's lease while it works.
4502
4520
  `
4503
4521
  ).action(async (opts) => {
4504
- warnIfApiKeyFlag(opts);
4505
- const { runWorkBuild, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4522
+ const { runWorkBuild, WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4506
4523
  try {
4507
4524
  await runWorkBuild(opts);
4508
4525
  } catch (err) {
@@ -4525,8 +4542,7 @@ renews that session's own 20-minute lease, unless --no-lease or
4525
4542
  --ended is given, or another worker already holds a live one.
4526
4543
  `
4527
4544
  ).action(async (number, opts) => {
4528
- warnIfApiKeyFlag(opts);
4529
- const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4545
+ const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4530
4546
  try {
4531
4547
  await runWorkLinkSession({ ...opts, number, noLease: opts.lease === false, logFailures: opts.logFailures === true });
4532
4548
  } catch (err) {
@@ -4550,9 +4566,8 @@ criterion's new proof; --ready hands the thread back to a person. At
4550
4566
  most one action flag may be given.
4551
4567
  `
4552
4568
  ).action(async (opts) => {
4553
- warnIfApiKeyFlag(opts);
4554
- const { runWorkComment, WorkCommentCommandError } = await import('./work-comment-cmd-SZJSPM5S.js');
4555
- const { WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4569
+ const { runWorkComment, WorkCommentCommandError } = await import('./work-comment-cmd-UCCPWUSR.js');
4570
+ const { WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4556
4571
  try {
4557
4572
  await runWorkComment(opts);
4558
4573
  } catch (err) {
@@ -4573,9 +4588,8 @@ criterion that carries proof or a comment, each with who is waiting
4573
4588
  on whom next.
4574
4589
  `
4575
4590
  ).action(async (opts) => {
4576
- warnIfApiKeyFlag(opts);
4577
- const { runWorkThreads, WorkCommentCommandError } = await import('./work-comment-cmd-SZJSPM5S.js');
4578
- const { WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4591
+ const { runWorkThreads, WorkCommentCommandError } = await import('./work-comment-cmd-UCCPWUSR.js');
4592
+ const { WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4579
4593
  try {
4580
4594
  await runWorkThreads(opts);
4581
4595
  } catch (err) {
@@ -4586,6 +4600,31 @@ on whom next.
4586
4600
  throw err;
4587
4601
  }
4588
4602
  });
4603
+ workCmd.command("logs").description("Read the runner's log for a host attempt on a work item").requiredOption("--item <number>", "the item's number inside this factory").option("--attempt <claim id>", "an attempt's id, from `work status --json` (default: the newest)").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(
4604
+ "after",
4605
+ `
4606
+ ${cliInvocation()} work logs --item 7
4607
+ ${cliInvocation()} work logs --item 7 --attempt 7b0a3c52-9f1e-4d6b-8a21-5c3e9d2f1a40
4608
+
4609
+ Prints what the runner did around the agent on that attempt, one line
4610
+ per event with its timestamp, with secrets removed on the host. The
4611
+ runner sends it when it releases the attempt, so an attempt that is
4612
+ still running, or that an older runner released, has no log and the
4613
+ command exits 1.
4614
+ `
4615
+ ).action(async (opts) => {
4616
+ const { runWorkLogs, WorkLogsCommandError } = await import('./work-logs-cmd-7352CJPG.js');
4617
+ const { WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4618
+ try {
4619
+ await runWorkLogs(opts);
4620
+ } catch (err) {
4621
+ if (err instanceof WorkLogsCommandError || err instanceof WorkCommandError) {
4622
+ fail(err.message);
4623
+ return;
4624
+ }
4625
+ throw err;
4626
+ }
4627
+ });
4589
4628
  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(
4590
4629
  "after",
4591
4630
  `
@@ -4596,8 +4635,7 @@ deletes anything \u2014 the item is removed from Work only once no
4596
4635
  live addition remains on it.
4597
4636
  `
4598
4637
  ).action(async (opts) => {
4599
- warnIfApiKeyFlag(opts);
4600
- const { runWorkRemove, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4638
+ const { runWorkRemove, WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4601
4639
  try {
4602
4640
  await runWorkRemove(opts);
4603
4641
  } catch (err) {
@@ -4609,8 +4647,7 @@ live addition remains on it.
4609
4647
  }
4610
4648
  });
4611
4649
  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) => {
4612
- warnIfApiKeyFlag(opts);
4613
- const { runWorkStatus, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4650
+ const { runWorkStatus, WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4614
4651
  try {
4615
4652
  await runWorkStatus(opts);
4616
4653
  } catch (err) {
@@ -4622,8 +4659,7 @@ live addition remains on it.
4622
4659
  }
4623
4660
  });
4624
4661
  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) => {
4625
- warnIfApiKeyFlag(opts);
4626
- const { runWorkList, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4662
+ const { runWorkList, WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4627
4663
  try {
4628
4664
  await runWorkList(opts);
4629
4665
  } catch (err) {
@@ -4644,8 +4680,7 @@ by a different key is refused; claiming again with the same key extends
4644
4680
  it. --host is a label only.
4645
4681
  `
4646
4682
  ).action(async (opts) => {
4647
- warnIfApiKeyFlag(opts);
4648
- const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
4683
+ const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-ZRPSHMPT.js');
4649
4684
  try {
4650
4685
  await runWorkClaim(opts);
4651
4686
  } catch (err) {
@@ -4665,8 +4700,7 @@ Extends the live lease this API key holds. Refused with a 410 if the
4665
4700
  lease has expired, or a 403 if a different key holds it.
4666
4701
  `
4667
4702
  ).action(async (opts) => {
4668
- warnIfApiKeyFlag(opts);
4669
- const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
4703
+ const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-ZRPSHMPT.js');
4670
4704
  try {
4671
4705
  await runWorkRenew(opts);
4672
4706
  } catch (err) {
@@ -4698,8 +4732,7 @@ applies to a host's lease only. A later tool call in the session
4698
4732
  takes the lease again.
4699
4733
  `
4700
4734
  ).action(async (opts) => {
4701
- warnIfApiKeyFlag(opts);
4702
- const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
4735
+ const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-ZRPSHMPT.js');
4703
4736
  try {
4704
4737
  await runWorkRelease(opts);
4705
4738
  } catch (err) {
@@ -4726,8 +4759,7 @@ Idempotent: declaring the same pull request twice is a no-op.
4726
4759
  needs your own login; an agent session or a factory key is refused.
4727
4760
  `
4728
4761
  ).action(async (number, opts) => {
4729
- warnIfApiKeyFlag(opts);
4730
- const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-5LGANL32.js');
4762
+ const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-H4OQR26N.js');
4731
4763
  try {
4732
4764
  await runWorkPr({ ...opts, number });
4733
4765
  } catch (err) {
@@ -4752,9 +4784,8 @@ login, then declares the pull request on the item, as \`work pr\` does.
4752
4784
  Run it again after a change to the title or description.
4753
4785
  `
4754
4786
  ).action(async (opts) => {
4755
- warnIfApiKeyFlag(opts);
4756
- const { runWorkOpenPr, WorkOpenPrCommandError } = await import('./work-open-pr-cmd-RPXKCBWS.js');
4757
- const { WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4787
+ const { runWorkOpenPr, WorkOpenPrCommandError } = await import('./work-open-pr-cmd-LSH4VHJM.js');
4788
+ const { WorkCommandError } = await import('./work-cmd-5I3J2XQQ.js');
4758
4789
  try {
4759
4790
  await runWorkOpenPr(opts);
4760
4791
  } catch (err) {
@@ -4770,8 +4801,8 @@ function registerRunnerCommands(program2) {
4770
4801
  const runnerCmd = program2.command("runner").description("Take work from the implement and amend queues on this machine");
4771
4802
  const configOption = "the cloud config file to run against (default: ~/.outerlayer/config.json)";
4772
4803
  runnerCmd.command("start").description("Run the loop: claim work, run it, report, clean up, repeat").option("--config <path>", configOption).action(async (opts) => {
4773
- const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-FXDG4NPJ.js');
4774
- const { start, RunnerStartError } = await import('./loop-UGI2BJOT.js');
4804
+ const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-CLSGABD5.js');
4805
+ const { start, RunnerStartError } = await import('./loop-TPUYUMSY.js');
4775
4806
  const { RunnerAlreadyRunningError } = await import('./pidfile-3DM4OBKO.js');
4776
4807
  const configPath = opts.config ?? defaultRunnerConfigPath();
4777
4808
  try {
@@ -4786,8 +4817,8 @@ function registerRunnerCommands(program2) {
4786
4817
  }
4787
4818
  });
4788
4819
  runnerCmd.command("check").description("Validate the config, the hooks and the key, and print the effective settings").option("--config <path>", configOption).action(async (opts) => {
4789
- const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
4790
- const { runRunnerCheck } = await import('./check-5C4YDZYV.js');
4820
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
4821
+ const { runRunnerCheck } = await import('./check-W2JGXN3B.js');
4791
4822
  const configPath = opts.config ?? defaultRunnerConfigPath();
4792
4823
  const result = await runRunnerCheck(configPath);
4793
4824
  if (!result.ok) {
@@ -4803,7 +4834,7 @@ function registerRunnerCommands(program2) {
4803
4834
  `);
4804
4835
  });
4805
4836
  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) => {
4806
- const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-FXDG4NPJ.js');
4837
+ const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-CLSGABD5.js');
4807
4838
  const { runRunnerInstall, RunnerInstallError, launcherSummary, restartNote } = await import('./install-cmd-QDOTR4OM.js');
4808
4839
  const configPath = opts.config ?? defaultRunnerConfigPath();
4809
4840
  if (opts.service !== true) {
@@ -4816,7 +4847,7 @@ function registerRunnerCommands(program2) {
4816
4847
  }
4817
4848
  try {
4818
4849
  if (opts.service === true) {
4819
- const { installServiceCommand } = await import('./command-H5CILO4S.js');
4850
+ const { installServiceCommand } = await import('./command-ZQNEPDS6.js');
4820
4851
  const result2 = await installServiceCommand({
4821
4852
  configPath,
4822
4853
  print: opts.print,
@@ -4871,8 +4902,8 @@ To keep it running, run ${C.yellow}${cliInvocation()} runner install --service${
4871
4902
  fail(`pass --service: \`${cliInvocation()} runner uninstall --service\` removes the runner's service.`);
4872
4903
  return;
4873
4904
  }
4874
- const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
4875
- const { uninstallServiceCommand } = await import('./command-H5CILO4S.js');
4905
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
4906
+ const { uninstallServiceCommand } = await import('./command-ZQNEPDS6.js');
4876
4907
  const result = await uninstallServiceCommand({ configPath: opts.config ?? defaultRunnerConfigPath(), unitName: opts.unitName, home: homeFromEnv() });
4877
4908
  if (result.ok) for (const line of result.lines) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
4878
4909
  `);
@@ -4899,12 +4930,12 @@ already in runner.env is used.
4899
4930
  printf '%s' "$CLAUDE_CODE_OAUTH_TOKEN" | ${cliInvocation()} runner init --agent claude --factory <org>/<factory>
4900
4931
  `
4901
4932
  ).action(async (opts) => {
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');
4933
+ const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-CLSGABD5.js');
4934
+ const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-XG47KCI4.js');
4935
+ const { obtainRunnerKey, runnerKeyLogin } = await import('./runner-key-5FOWCW7J.js');
4936
+ const { detectMachine } = await import('./machine-TRHBT5NE.js');
4937
+ const { chooseVm, runVmInit, VmInitError } = await import('./init-V6FOMD2V.js');
4938
+ const { AGENT_COMMANDS, credentialFromStdin, isAgentName, restartForCredential, RunnerEnvError } = await import('./runner-env-FRZFFHDF.js');
4908
4939
  const configPath = opts.config ?? defaultRunnerConfigPath();
4909
4940
  if (opts.agent !== void 0 && !isAgentName(opts.agent)) {
4910
4941
  fail(`--agent ${opts.agent}: runner init writes commands for ${Object.keys(AGENT_COMMANDS).join(", ")}. For another agent, leave --agent out and edit runner.commands.`);
@@ -4918,7 +4949,7 @@ already in runner.env is used.
4918
4949
  try {
4919
4950
  let credential;
4920
4951
  if (agent !== void 0) {
4921
- const { readPipedKey } = await import('./login-browser-O63QZN7D.js');
4952
+ const { readPipedKey } = await import('./login-browser-DX35MARZ.js');
4922
4953
  credential = credentialFromStdin(
4923
4954
  await readPipedKey(process.stdin, {
4924
4955
  onWaiting: () => process.stderr.write(`runner init is waiting for Claude's credential on stdin; close stdin to use the one already in runner.env
@@ -5054,7 +5085,7 @@ ${C.yellow}The runner will not update itself: ${installErr.message}${C.reset}
5054
5085
  let serviceUp = false;
5055
5086
  let restart;
5056
5087
  if (installedLayout) {
5057
- const { installServiceCommand } = await import('./command-H5CILO4S.js');
5088
+ const { installServiceCommand } = await import('./command-ZQNEPDS6.js');
5058
5089
  const service = await installServiceCommand({
5059
5090
  configPath,
5060
5091
  entryPath: process.argv[1] ?? "",
@@ -5098,12 +5129,12 @@ Next:
5098
5129
  "after",
5099
5130
  "\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"
5100
5131
  ).action(async (opts) => {
5101
- const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
5132
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
5102
5133
  const { buildRepositoryImage, RecipeError } = await import('./build-TQ6X5PYN.js');
5103
5134
  const { currentCliBuild } = await import('./cli-build-K56DK4DS.js');
5104
- const { createDockerHost } = await import('./docker-RC3PRX3Q.js');
5105
- const { builderSpec } = await import('./builder-DUI2ZH2H.js');
5106
- const { loadRunnerConfig } = await import('./config-FXDG4NPJ.js');
5135
+ const { createDockerHost } = await import('./docker-BFU3AQGY.js');
5136
+ const { builderSpec } = await import('./builder-C4QNTYMS.js');
5137
+ const { loadRunnerConfig } = await import('./config-CLSGABD5.js');
5107
5138
  const configPath = opts.config ?? defaultRunnerConfigPath();
5108
5139
  const loaded = (() => {
5109
5140
  try {
@@ -5114,7 +5145,7 @@ Next:
5114
5145
  })();
5115
5146
  const memory = loaded?.build?.memory ?? "8g";
5116
5147
  try {
5117
- const { imageTargetFor } = await import('./governing-source-BUU4IABS.js');
5148
+ const { imageTargetFor } = await import('./governing-source-HAA4OW57.js');
5118
5149
  const target = await imageTargetFor({ config: loaded, repository: opts.repository, fetchImpl: fetch });
5119
5150
  if (!target.ok) {
5120
5151
  if (opts.json) {
@@ -5177,16 +5208,16 @@ Next:
5177
5208
  }
5178
5209
  });
5179
5210
  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) => {
5180
- const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
5181
- const { requestStop } = await import('./loop-UGI2BJOT.js');
5211
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
5212
+ const { requestStop } = await import('./loop-TPUYUMSY.js');
5182
5213
  const configPath = opts.config ?? defaultRunnerConfigPath();
5183
5214
  await requestStop(configPath, Boolean(opts.now));
5184
5215
  });
5185
5216
  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) => {
5186
- const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-FXDG4NPJ.js');
5217
+ const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-CLSGABD5.js');
5187
5218
  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');
5219
+ const { listJobFiles, runnerProcessState } = await import('./loop-TPUYUMSY.js');
5220
+ const { renderStatus } = await import('./status-BINH7MBG.js');
5190
5221
  const { readHousekeepingRecord } = await import('./record-3WP6V2K5.js');
5191
5222
  const path2 = await import('path');
5192
5223
  const configPath = opts.config ?? defaultRunnerConfigPath();
@@ -5206,7 +5237,7 @@ Next:
5206
5237
  const service = await (async () => {
5207
5238
  if (process.platform !== "linux" || !existsSync("/run/systemd/system")) return void 0;
5208
5239
  const { inspectService, realInspectProbes } = await import('./inspect-6UYAAXH7.js');
5209
- const { DEFAULT_UNIT_NAME } = await import('./install-CBWIEF3R.js');
5240
+ const { DEFAULT_UNIT_NAME } = await import('./install-4SEFIIW2.js');
5210
5241
  const facts = inspectService(DEFAULT_UNIT_NAME, path2.dirname(configPath), realInspectProbes());
5211
5242
  return facts === void 0 ? void 0 : { unit: facts.unit, running: facts.mainPid !== void 0, delegated: facts.delegate };
5212
5243
  })();
@@ -5241,8 +5272,8 @@ Next:
5241
5272
  );
5242
5273
  });
5243
5274
  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) => {
5244
- const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
5245
- const { listJobFiles } = await import('./loop-UGI2BJOT.js');
5275
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
5276
+ const { listJobFiles } = await import('./loop-TPUYUMSY.js');
5246
5277
  const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-AMLKC3VP.js');
5247
5278
  const configPath = opts.config ?? defaultRunnerConfigPath();
5248
5279
  const item = parseTrackerNumber(itemArg);
@@ -5277,32 +5308,22 @@ function registerHooksCommands(program2) {
5277
5308
  "after",
5278
5309
  "\n`init` auto-wraps PreToolUse/PostToolUse hooks; these subcommands cover the\nrest: manual re-scans, other events, and undo.\n"
5279
5310
  );
5280
- hooksCmd.command("install-git").description("Install the commit-guard git hook in this repo").option("--print", "print the hook scripts instead of installing").addHelpText(
5311
+ hooksCmd.command("install-git").description("Remove the git hooks an earlier version installed in this repo").addHelpText(
5281
5312
  "after",
5282
- "\nThe same install `init` performs. `--print` writes the script to stdout for\nrepositories that manage hooks in-tree (husky and friends).\n"
5283
- ).action((opts) => {
5284
- if (opts.print) {
5285
- for (const [name, script] of managedHookScripts()) {
5286
- process.stdout.write(`# ==== ${name} ====
5287
- ${script}
5288
- `);
5289
- }
5290
- return;
5291
- }
5313
+ "\nEarlier versions installed a pre-commit guard and commit journal hooks. This removes\nthe ones OuterLayer wrote and leaves any hook it did not write untouched.\n"
5314
+ ).action(() => {
5292
5315
  const removal = removeJournalHooks(process.cwd());
5293
5316
  if (removal.removed) {
5294
5317
  process.stdout.write(`${C.green}\u2713${C.reset} removed the commit journal hooks an earlier version installed \u2192 ${removal.path}
5295
5318
  `);
5296
5319
  }
5297
- const guard = installPreCommitGuardHook(process.cwd());
5298
- const report = formatGuardInstallOutput(guard);
5299
- if (report.error !== void 0) {
5300
- fail(report.error);
5301
- return;
5320
+ const guard = removePreCommitGuardHook(process.cwd());
5321
+ if (guard.removed) {
5322
+ process.stdout.write(`${C.green}\u2713${C.reset} removed the pre-commit guard an earlier version installed \u2192 ${guard.path}
5323
+ `);
5302
5324
  }
5303
- for (const line of report.lines) process.stdout.write(`${line}
5325
+ if (!removal.removed && !guard.removed) process.stdout.write(`${C.dim}No git hooks from an earlier version were found.${C.reset}
5304
5326
  `);
5305
- if (report.exitCode !== void 0) process.exitCode = report.exitCode;
5306
5327
  });
5307
5328
  hooksCmd.command("status").description("List hook entries in user and project settings, marking the wrapped ones").option("--json", "machine-readable JSON output").action((opts) => {
5308
5329
  const report = [];
@@ -5501,7 +5522,7 @@ caller from the bearer token, the gateway answers 401 without that header.
5501
5522
  "after",
5502
5523
  "\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"
5503
5524
  ).action(async (opts) => {
5504
- const { runMcpServe, handleMcpServeError } = await import('./mcp-serve-cmd-DOTY5FKY.js');
5525
+ const { runMcpServe, handleMcpServeError } = await import('./mcp-serve-cmd-N3UTY6EE.js');
5505
5526
  try {
5506
5527
  await runMcpServe({ url: opts.url, appId: opts.appId });
5507
5528
  } catch (err) {
@@ -5512,7 +5533,7 @@ caller from the bearer token, the gateway answers 401 without that header.
5512
5533
  function registerImportCommands(program2) {
5513
5534
  const importCmd = program2.command("import").description("Import an existing config format into .outerlayer/");
5514
5535
  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) => {
5515
- const { runImportRuler, ImportRulerError } = await import('./import-ruler-cmd-KJMWL5V6.js');
5536
+ const { runImportRuler, ImportRulerError } = await import('./import-ruler-cmd-T6LLO6Q7.js');
5516
5537
  try {
5517
5538
  const result = runImportRuler({ cwd: opts.dir, json: opts.json });
5518
5539
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
@@ -5528,7 +5549,7 @@ function registerImportCommands(program2) {
5528
5549
  "after",
5529
5550
  "\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"
5530
5551
  ).action(async (opts) => {
5531
- const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-ZO6KGHI2.js');
5552
+ const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-TK4XY7RD.js');
5532
5553
  try {
5533
5554
  runImportCapture({ cwd: opts.dir, json: opts.json });
5534
5555
  } catch (err) {
@@ -5540,59 +5561,14 @@ function registerImportCommands(program2) {
5540
5561
  }
5541
5562
  });
5542
5563
  }
5543
- function formatContextMaterializeOutput(result) {
5544
- switch (result.status) {
5545
- case "not-a-repo":
5546
- return { stdout: [], stderr: [`${C.red}\u2717${C.reset} not inside a git repository.`], exitCode: 1 };
5547
- case "self":
5548
- return { stdout: [`${C.dim}This repository is self-sourced \u2014 nothing to materialize.${C.reset}`], stderr: [] };
5549
- case "materialized": {
5550
- const stdout = [`${C.green}\u2713${C.reset} Materialized context at ${C.dim}${result.sha?.slice(0, 7)}${C.reset}`];
5551
- if (result.message) stdout.push(`${C.yellow}!${C.reset} ${result.message}`);
5552
- return { stdout, stderr: [] };
5553
- }
5554
- case "debounced": {
5555
- const stdout = [`${C.green}\u2713${C.reset} Already current at ${C.dim}${result.sha?.slice(0, 7)}${C.reset} (verification: ${result.verification})`];
5556
- if (result.message) stdout.push(`${C.yellow}!${C.reset} ${result.message}`);
5557
- return { stdout, stderr: [] };
5558
- }
5559
- case "adoption-conflict":
5560
- return { stdout: [`${C.yellow}!${C.reset} ${result.message}`], stderr: [], exitCode: 1 };
5561
- default:
5562
- return { stdout: [`${C.yellow}!${C.reset} ${result.message ?? result.status}`], stderr: [], exitCode: 1 };
5563
- }
5564
- }
5565
5564
  function registerContextCommands(program2) {
5566
- const contextCmd = program2.command("context").description("Compile and materialize agent context");
5565
+ const contextCmd = program2.command("context").description("Compile agent context");
5567
5566
  contextCmd.command("emit").description("Compile .outerlayer/ into each configured target tool's native files").option("--check", "compare against disk, write nothing, exit 1 on drift (CI mode)").option("--dir <path>", "repo root to read from (default: cwd)").option("--json", "machine-readable JSON output").addHelpText(
5568
5567
  "after",
5569
5568
  '\nTargets come from .outerlayer/config.json only; there is no --target flag.\nMissing or empty config: {"targets": [...]}, e.g. {"targets": ["claude-code"]}.\nKnown targets: claude-code, cursor, codex, copilot, factory.\n\nThe maintained skills (outerlayer-evidence, outerlayer-amend, outerlayer-findings,\nouterlayer-cli) follow this CLI: emit rewrites one that differs from its bundle, and --check\nreports it as drift. A copy under an earlier name (amend, emitting-evidence,\nreporting-findings, outerlayer) is deleted, and --check reports it as retired.\nTemplates (spec, writing-specs, writing-tests, build) are never rewritten or reported.\n\nOrphan detection (--check) only covers header-carrying outputs: every markdown\ntarget file gets a generated-by comment, but .mcp.json and .cursor/mcp.json are\nJSON with no comment syntax, so they can never be flagged as orphaned; missing\nand content drift still apply to them.\n'
5570
5569
  ).action(async (opts) => {
5571
5570
  await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
5572
5571
  });
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) => {
5574
- const { runContextAdopt } = await import('./context-adopt-O5OFXMKI.js');
5575
- const { exitCode, stdout } = runContextAdopt(stagedDir, process.cwd());
5576
- process.stdout.write(stdout);
5577
- process.exitCode = exitCode;
5578
- });
5579
- contextCmd.command("materialize").description("Materialize this repository's governed context from its control plane").option("--json", "machine-readable JSON output").addHelpText(
5580
- "after",
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"
5582
- ).action(async (opts) => {
5583
- const { materializeContext } = await import('./context-materialize-Y5IJ4MQT.js');
5584
- const result = await materializeContext({ cwd: process.cwd(), sessionId: `manual-${Date.now()}` });
5585
- const output = formatContextMaterializeOutput(result);
5586
- if (output.exitCode !== void 0) process.exitCode = output.exitCode;
5587
- if (opts.json) {
5588
- writeJson(result);
5589
- return;
5590
- }
5591
- for (const line of output.stdout) process.stdout.write(`${line}
5592
- `);
5593
- for (const line of output.stderr) process.stderr.write(`${line}
5594
- `);
5595
- });
5596
5572
  }
5597
5573
 
5598
- export { buildProgram, formatContextMaterializeOutput, formatGuardInstallOutput, formatInitOutput, runCli };
5574
+ export { buildProgram, formatInitOutput, runCli };