@outerlayer/cli 0.18.0 → 0.19.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.
Files changed (102) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +21 -2
  3. package/dist/{agent-setup-RBTEACYU.js → agent-setup-TPR4BBFV.js} +15 -16
  4. package/dist/{artifact-link-cmd-AVM2EKTV.js → artifact-link-cmd-W7XF5BFB.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-UWQAL2MN.js} +44 -43
  8. package/dist/{chunk-S26M3YBJ.js → chunk-3UZTIRLF.js} +1 -1
  9. package/dist/{chunk-W5VPCONO.js → chunk-452TM7J4.js} +33 -227
  10. package/dist/{chunk-UYOYTKE2.js → chunk-5GHGAF6P.js} +3 -3
  11. package/dist/{chunk-QQM2UJ6T.js → chunk-5MYFOW5V.js} +182 -28
  12. package/dist/{chunk-Y5GE76XC.js → chunk-5TN7GLYX.js} +33 -81
  13. package/dist/{chunk-GOBOJMOJ.js → chunk-6D7GT22T.js} +4 -4
  14. package/dist/{chunk-3OFZM4X6.js → chunk-6U3MV7TZ.js} +151 -20
  15. package/dist/{chunk-F4XSVQJ4.js → chunk-6X4SQ5MY.js} +2 -2
  16. package/dist/{chunk-Y5MXET4M.js → chunk-7KSSBQTS.js} +11 -10
  17. package/dist/{chunk-JF42URPU.js → chunk-7SJPQWBM.js} +33 -9
  18. package/dist/{chunk-N3CUDFCW.js → chunk-7VUK5RFS.js} +15 -2
  19. package/dist/{chunk-SWCTGCSC.js → chunk-7YP7T6GV.js} +1 -1
  20. package/dist/{chunk-KDVIU23F.js → chunk-BWSUPRDK.js} +1 -1
  21. package/dist/{chunk-S76AYB4M.js → chunk-CG36IONK.js} +5 -5
  22. package/dist/chunk-CJJDJ7AT.js +56 -0
  23. package/dist/{chunk-FUB7LRUE.js → chunk-DADWEUH3.js} +5 -5
  24. package/dist/{chunk-RAZTWYZN.js → chunk-DJ3ZUSC3.js} +7 -8
  25. package/dist/{chunk-MQJSXHV7.js → chunk-G3IJ3N6F.js} +5 -3
  26. package/dist/{chunk-KK4VBOH6.js → chunk-HPJNLETG.js} +10 -11
  27. package/dist/{chunk-IP7BIBXJ.js → chunk-IF2OSI5T.js} +35 -1
  28. package/dist/{chunk-T4Y6SCG3.js → chunk-IXYZUUYQ.js} +2 -2
  29. package/dist/chunk-KYS3TQAG.js +296 -0
  30. package/dist/chunk-LLM3I5YU.js +89 -0
  31. package/dist/{chunk-B3UKB46N.js → chunk-LRG3ZMZD.js} +4 -5
  32. package/dist/{chunk-ULSIJGLS.js → chunk-NFIR3GEE.js} +56 -14
  33. package/dist/{chunk-MNTSH4CL.js → chunk-NNLA7LLQ.js} +1 -1
  34. package/dist/{chunk-WGAUY5LE.js → chunk-QEFKA2QD.js} +1 -1
  35. package/dist/{chunk-BMYGAGBJ.js → chunk-QNLX477Q.js} +155 -23
  36. package/dist/chunk-TUSYOL2O.js +113 -0
  37. package/dist/{chunk-ESC6UR76.js → chunk-TWF3RICI.js} +6 -6
  38. package/dist/{chunk-NL4XPC7W.js → chunk-UVG35MWF.js} +1 -1
  39. package/dist/{chunk-L2USZT6T.js → chunk-VMJPFQNE.js} +1 -1
  40. package/dist/chunk-VRRGENS4.js +144 -0
  41. package/dist/{chunk-X5N6KC6V.js → chunk-WFSUUUAN.js} +2 -3
  42. package/dist/{chunk-6CHIYEZZ.js → chunk-XSZD4AZ6.js} +9 -83
  43. package/dist/{chunk-LXAY4A2G.js → chunk-YQR6E6OV.js} +34 -49
  44. package/dist/{chunk-47TTLEDX.js → chunk-ZHAUSEEN.js} +35 -13
  45. package/dist/{claude-launcher-YVXI76NX.js → claude-launcher-FPPHZPMR.js} +20 -7
  46. package/dist/{cli-C77H54BV.js → cli-HROW5T7X.js} +203 -228
  47. package/dist/{command-H5CILO4S.js → command-OEAV7BVX.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-HSVYDGMI.js +9 -0
  51. package/dist/control-plane-launch-NYVDJESK.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-23BBJWBX.js} +32 -33
  55. package/dist/{emit-artifact-cmd-7MP63KXU.js → emit-artifact-cmd-O6SCM7TV.js} +17 -17
  56. package/dist/{emit-cmd-PPN4QQF2.js → emit-cmd-7SP3I6UZ.js} +6 -6
  57. package/dist/{emit-criteria-cmd-3RXPDLNK.js → emit-criteria-cmd-LQNERZRV.js} +11 -12
  58. package/dist/{emit-finding-cmd-OL7JB6H3.js → emit-finding-cmd-AJPKHIOV.js} +12 -13
  59. package/dist/{emit-result-cmd-UZVMOCF4.js → emit-result-cmd-RUICOKWQ.js} +17 -17
  60. package/dist/emit-step-cmd-347XNGPQ.js +26 -0
  61. package/dist/{governing-source-BUU4IABS.js → governing-source-V5EEGPTA.js} +21 -22
  62. package/dist/{hook-fast-W5MKHMJT.js → hook-fast-YAZG5MDX.js} +3 -3
  63. package/dist/{import-capture-cmd-ZO6KGHI2.js → import-capture-cmd-KKFFOGWP.js} +4 -4
  64. package/dist/{import-ruler-cmd-KJMWL5V6.js → import-ruler-cmd-5P6JOXQN.js} +2 -2
  65. package/dist/index.js +4 -4
  66. package/dist/{init-WNXXYMO7.js → init-LWHDMZQG.js} +30 -31
  67. package/dist/{init-VWXIZEAN.js → init-MOINY2DD.js} +30 -31
  68. package/dist/{init-cmd-WS6TIRYT.js → init-cmd-HSMRID6A.js} +67 -26
  69. package/dist/{init-update-E3J6TVIN.js → init-update-LWX5MPPR.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-SYYPVFYW.js} +44 -43
  73. package/dist/{machine-JOW4RNZ7.js → machine-6X63G2KH.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-276SJU5R.js} +30 -31
  77. package/dist/{session-sender-NNVPSPY7.js → session-sender-GGIY5OAX.js} +19 -15
  78. package/dist/shell-function-NRD4KVUK.js +6 -0
  79. package/dist/{spec-cmd-OWVTBB4J.js → spec-cmd-SIZBRN7D.js} +12 -13
  80. package/dist/{starter-pack-OPWUDOWX.js → starter-pack-6LQVLBIA.js} +5 -5
  81. package/dist/{status-TKCLLKFG.js → status-NAK6DYSF.js} +33 -32
  82. package/dist/{sync-cmd-Q6VYNPWG.js → sync-cmd-G7GF4UTW.js} +18 -14
  83. package/dist/{watch-ARAGADTF.js → watch-EVM5GSMP.js} +18 -14
  84. package/dist/{work-claim-cmd-34FERLYX.js → work-claim-cmd-3J3QW56U.js} +16 -17
  85. package/dist/{work-cmd-7S5B2H2P.js → work-cmd-5EPPD33Y.js} +12 -13
  86. package/dist/{work-comment-cmd-SZJSPM5S.js → work-comment-cmd-2ACOZQAE.js} +12 -13
  87. package/dist/work-logs-cmd-QDD2NMJL.js +60 -0
  88. package/dist/{work-open-pr-cmd-RPXKCBWS.js → work-open-pr-cmd-XNCEI4ZM.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-5TN7GLYX.js';
4
+ import './chunk-TWF3RICI.js';
5
+ import { verifiedTrackerNames, TRACKERS } from './chunk-HPJNLETG.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-NFIR3GEE.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-IXYZUUYQ.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
+ import './chunk-WFSUUUAN.js';
28
+ import './chunk-7VUK5RFS.js';
27
29
  import './chunk-EABW6AJQ.js';
30
+ import { cliInvocation, packageRunnerOf } from './chunk-CRB3POP4.js';
31
+ import { cloneIsGoverned } from './chunk-YQR6E6OV.js';
32
+ import { removeJournalHooks, removePreCommitGuardHook } from './chunk-TUSYOL2O.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-LWX5MPPR.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,19 @@ states under Starter files.
3917
3884
  fail(outcome.text);
3918
3885
  return;
3919
3886
  }
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
+ }
3920
3893
  if (opts.json) writeJson(outcome.result);
3921
3894
  else process.stdout.write(outcome.text);
3922
3895
  return;
3923
3896
  }
3924
- const { runInitCommand } = await import('./init-cmd-WS6TIRYT.js');
3897
+ const { runInitCommand } = await import('./init-cmd-HSMRID6A.js');
3925
3898
  const code = await runInitCommand(
3926
- { json: opts.json, factory: opts.factory },
3899
+ { json: opts.json, factory: opts.factory, shellFunction: opts.shellFunction },
3927
3900
  {
3928
3901
  connect: await realConnectDepsForCwd(),
3929
3902
  stdout: process.stdout,
@@ -3933,10 +3906,26 @@ states under Starter files.
3933
3906
  return { ok, text, detail };
3934
3907
  },
3935
3908
  runAgentSetup: async () => {
3936
- const { runAgentSetup } = await import('./agent-setup-RBTEACYU.js');
3909
+ const { runAgentSetup } = await import('./agent-setup-TPR4BBFV.js');
3937
3910
  return runAgentSetup({ cwd: process.cwd() });
3938
3911
  },
3939
- runDoctorChecks: gatherDoctorChecks
3912
+ runDoctorChecks: gatherDoctorChecks,
3913
+ shell: {
3914
+ home: homeFromEnv(),
3915
+ shellPath: process.env.SHELL,
3916
+ interactive: Boolean(process.stdin.isTTY && process.stderr.isTTY) && opts.json !== true,
3917
+ ask: async () => {
3918
+ const { promptOnTerminal } = await import('./connect-cmd-UNYKGDAL.js');
3919
+ const answer = await promptOnTerminal({
3920
+ 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.`,
3921
+ options: [
3922
+ { label: "Yes, add the block", value: "yes" },
3923
+ { label: "No, I will run outerlayer claude myself", value: "no" }
3924
+ ]
3925
+ });
3926
+ return answer === "yes";
3927
+ }
3928
+ }
3940
3929
  }
3941
3930
  );
3942
3931
  if (code !== 0) process.exitCode = code;
@@ -3965,7 +3954,7 @@ linked (true, false, or null when it could not be checked) and, when false,
3965
3954
  linkUrl.
3966
3955
  `
3967
3956
  ).action(async (opts) => {
3968
- const { runConnectCommand } = await import('./connect-cmd-ZW5FV3ZW.js');
3957
+ const { runConnectCommand } = await import('./connect-cmd-UNYKGDAL.js');
3969
3958
  const code = await runConnectCommand({ factory: opts.factory, json: opts.json }, await realConnectDepsForCwd(), {
3970
3959
  stdout: process.stdout,
3971
3960
  stderr: process.stderr
@@ -4004,7 +3993,7 @@ Every later command reads the saved file, so none of them needs a key on
4004
3993
  its command line. A saved key is checked for real on the first \`sync\`.
4005
3994
  `
4006
3995
  ).action(async (opts) => {
4007
- const { runLoginCommand, realLoginDeps } = await import('./login-browser-O63QZN7D.js');
3996
+ const { runLoginCommand, realLoginDeps } = await import('./login-browser-DX35MARZ.js');
4008
3997
  const code = await runLoginCommand(
4009
3998
  {
4010
3999
  browser: opts.browser !== false,
@@ -4036,15 +4025,14 @@ code is 1: revoke the token on /profile/security.
4036
4025
  "after",
4037
4026
  "\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
4027
  ).action(async (opts) => {
4039
- warnIfApiKeyFlag(opts);
4040
4028
  if (opts.link !== void 0) {
4041
- const { lookupArtifactLink } = await import('./artifact-link-cmd-AVM2EKTV.js');
4029
+ const { lookupArtifactLink } = await import('./artifact-link-cmd-W7XF5BFB.js');
4042
4030
  const found = lookupArtifactLink(opts.link);
4043
4031
  if (found.ok) process.stdout.write(found.url + "\n");
4044
4032
  else fail(found.reason);
4045
4033
  return;
4046
4034
  }
4047
- const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-Q6VYNPWG.js');
4035
+ const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-G7GF4UTW.js');
4048
4036
  try {
4049
4037
  const result = await runSync({
4050
4038
  url: opts.url,
@@ -4075,7 +4063,7 @@ code is 1: revoke the token on /profile/security.
4075
4063
  if (invokedCommandToken(argv) === "watch") {
4076
4064
  warnDeprecated(`\`${cliInvocation()} watch\` is now \`${cliInvocation()} daemon\`; the old name will be removed in a future release.`);
4077
4065
  }
4078
- const { runWatch } = await import('./watch-ARAGADTF.js');
4066
+ const { runWatch } = await import('./watch-EVM5GSMP.js');
4079
4067
  await runWatch({ once: opts.once });
4080
4068
  });
4081
4069
  program2.command("hook <event>", { hidden: true }).description("capture-hook fast path, installed by `init`").action(() => {
@@ -4084,7 +4072,7 @@ code is 1: revoke the token on /profile/security.
4084
4072
  });
4085
4073
  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
4074
  });
4087
- program2.command("claude [args...]", { hidden: true }).description("start Claude Code with the repository's control plane attached").allowUnknownOption().helpOption(false).action(() => {
4075
+ program2.command("claude [args...]").description("start Claude Code with the repository's control plane attached").allowUnknownOption().helpOption(false).action(() => {
4088
4076
  });
4089
4077
  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
4078
  const { startRelay } = await import('./relay-L76HDX72.js');
@@ -4131,7 +4119,7 @@ code is 1: revoke the token on /profile/security.
4131
4119
  }
4132
4120
  });
4133
4121
  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');
4122
+ const { runSessionSender } = await import('./session-sender-GGIY5OAX.js');
4135
4123
  try {
4136
4124
  await runSessionSender();
4137
4125
  } catch (err) {
@@ -4167,7 +4155,7 @@ async function runCli(processArgv) {
4167
4155
  await buildProgram(argv).parseAsync(argv);
4168
4156
  }
4169
4157
  async function compileContext(opts) {
4170
- const { runEmit, EmitError } = await import('./emit-cmd-PPN4QQF2.js');
4158
+ const { runEmit, EmitError } = await import('./emit-cmd-7SP3I6UZ.js');
4171
4159
  try {
4172
4160
  const result = runEmit({ cwd: opts.dir, check: opts.check, json: opts.json });
4173
4161
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
@@ -4204,7 +4192,8 @@ criterion's thread instead \u2014 see \`${cliInvocation()} work comment\`.
4204
4192
 
4205
4193
  Subcommands: \`emit artifact <file>\` for screenshots, recordings, reports and
4206
4194
  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.
4195
+ \`emit criteria <file>\` to record a work item's acceptance criteria;
4196
+ \`emit step <name>\` to report that you started a step.
4208
4197
  Compiling .outerlayer/ moved to \`${cliInvocation()} context emit\`.
4209
4198
  `
4210
4199
  ).action(async (name, opts) => {
@@ -4213,8 +4202,7 @@ Compiling .outerlayer/ moved to \`${cliInvocation()} context emit\`.
4213
4202
  await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
4214
4203
  return;
4215
4204
  }
4216
- warnIfApiKeyFlag(opts);
4217
- const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-UZVMOCF4.js');
4205
+ const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-RUICOKWQ.js');
4218
4206
  try {
4219
4207
  const result = await runEmitResult({
4220
4208
  name,
@@ -4264,8 +4252,7 @@ everywhere, bytes and deep link untouched; a still-queued one is cancelled
4264
4252
  locally so it never uploads. One correction can retire several duplicates.
4265
4253
  `
4266
4254
  ).action(async (file, opts) => {
4267
- warnIfApiKeyFlag(opts);
4268
- const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-7MP63KXU.js');
4255
+ const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-O6SCM7TV.js');
4269
4256
  let pr;
4270
4257
  if (opts.pr !== void 0) {
4271
4258
  pr = parseTrackerNumber(opts.pr);
@@ -4324,8 +4311,7 @@ recent events with their ids. --find <text> searches all of them.
4324
4311
  item that session was launched for is used automatically.
4325
4312
  `
4326
4313
  ).action(async (opts) => {
4327
- warnIfApiKeyFlag(opts);
4328
- const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-OL7JB6H3.js');
4314
+ const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-AJPKHIOV.js');
4329
4315
  try {
4330
4316
  refuseRemovedFindingFlags(opts);
4331
4317
  const result = await runEmitFinding({
@@ -4392,8 +4378,7 @@ the whole batch. "untimed": true records one with no time on purpose.
4392
4378
  that session was launched for is used automatically.
4393
4379
  `
4394
4380
  ).action(async (file, opts) => {
4395
- warnIfApiKeyFlag(opts);
4396
- const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-OL7JB6H3.js');
4381
+ const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-AJPKHIOV.js');
4397
4382
  try {
4398
4383
  const result = await runEmitFindings({
4399
4384
  file,
@@ -4412,6 +4397,40 @@ that session was launched for is used automatically.
4412
4397
  throw err;
4413
4398
  }
4414
4399
  });
4400
+ 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(
4401
+ "after",
4402
+ `
4403
+ ${cliInvocation()} emit step "Review round 2"
4404
+ ${cliInvocation()} emit step "Plan" --item 412
4405
+
4406
+ Run it when you start a step. The name is free text: 1 to 80 characters on one
4407
+ line. A step has a start and nothing else, so run it again for the next step.
4408
+ --item names the work item; without it, inside a recorded session, the item that
4409
+ session was launched for is used.
4410
+
4411
+ If the gateway cannot be reached, the step is queued with the time you ran the
4412
+ command, the command exits 0, and \`sync\` sends it later. If the gateway refuses
4413
+ the step, the command prints why and exits 1.
4414
+ `
4415
+ ).action(async (name, opts) => {
4416
+ const { runEmitStep, EmitStepError } = await import('./emit-step-cmd-347XNGPQ.js');
4417
+ try {
4418
+ await runEmitStep({
4419
+ name,
4420
+ item: opts.item,
4421
+ json: opts.json,
4422
+ url: opts.url,
4423
+ apiKey: opts.apiKey,
4424
+ appId: opts.appId
4425
+ });
4426
+ } catch (err) {
4427
+ if (err instanceof EmitStepError) {
4428
+ fail(err.message);
4429
+ return;
4430
+ }
4431
+ throw err;
4432
+ }
4433
+ });
4415
4434
  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
4435
  "after",
4417
4436
  `
@@ -4432,8 +4451,7 @@ agent session, with your own login. A key bound to no member cannot replace it e
4432
4451
  session was launched for is used automatically.
4433
4452
  `
4434
4453
  ).action(async (file, opts) => {
4435
- warnIfApiKeyFlag(opts);
4436
- const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-3RXPDLNK.js');
4454
+ const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-LQNERZRV.js');
4437
4455
  try {
4438
4456
  const result = await runEmitCriteria({
4439
4457
  file,
@@ -4456,11 +4474,10 @@ session was launched for is used automatically.
4456
4474
  function registerSpecCommands(program2) {
4457
4475
  const specCmd = program2.command("spec").description("Find, file and edit the issue a spec lives in, in your factory's tracker");
4458
4476
  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');
4477
+ const run = async (action) => {
4478
+ const { WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4462
4479
  try {
4463
- await action(await import('./spec-cmd-OWVTBB4J.js'));
4480
+ await action(await import('./spec-cmd-SIZBRN7D.js'));
4464
4481
  } catch (err) {
4465
4482
  if (err instanceof WorkCommandError) {
4466
4483
  fail(err.message);
@@ -4471,16 +4488,16 @@ function registerSpecCommands(program2) {
4471
4488
  };
4472
4489
  credentialOptions(
4473
4490
  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)));
4491
+ ).action((opts) => run((spec) => spec.runSpecTarget(opts)));
4475
4492
  credentialOptions(
4476
4493
  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 })));
4494
+ ).action((query, opts) => run((spec) => spec.runSpecSearch({ ...opts, query })));
4478
4495
  credentialOptions(
4479
4496
  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)));
4497
+ ).action((opts) => run((spec) => spec.runSpecFile(opts)));
4481
4498
  credentialOptions(
4482
4499
  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 })));
4500
+ ).action((key, opts) => run((spec) => spec.runSpecEdit({ ...opts, key })));
4484
4501
  }
4485
4502
  function registerWorkCommands(program2) {
4486
4503
  const workCmd = program2.command("work").description("Start, remove, or read what the factory is working on (the Work page)");
@@ -4501,8 +4518,7 @@ takes it, and prints the line that starts your session on it. That
4501
4518
  session links itself and holds the item's lease while it works.
4502
4519
  `
4503
4520
  ).action(async (opts) => {
4504
- warnIfApiKeyFlag(opts);
4505
- const { runWorkBuild, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4521
+ const { runWorkBuild, WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4506
4522
  try {
4507
4523
  await runWorkBuild(opts);
4508
4524
  } catch (err) {
@@ -4525,8 +4541,7 @@ renews that session's own 20-minute lease, unless --no-lease or
4525
4541
  --ended is given, or another worker already holds a live one.
4526
4542
  `
4527
4543
  ).action(async (number, opts) => {
4528
- warnIfApiKeyFlag(opts);
4529
- const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4544
+ const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4530
4545
  try {
4531
4546
  await runWorkLinkSession({ ...opts, number, noLease: opts.lease === false, logFailures: opts.logFailures === true });
4532
4547
  } catch (err) {
@@ -4550,9 +4565,8 @@ criterion's new proof; --ready hands the thread back to a person. At
4550
4565
  most one action flag may be given.
4551
4566
  `
4552
4567
  ).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');
4568
+ const { runWorkComment, WorkCommentCommandError } = await import('./work-comment-cmd-2ACOZQAE.js');
4569
+ const { WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4556
4570
  try {
4557
4571
  await runWorkComment(opts);
4558
4572
  } catch (err) {
@@ -4573,9 +4587,8 @@ criterion that carries proof or a comment, each with who is waiting
4573
4587
  on whom next.
4574
4588
  `
4575
4589
  ).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');
4590
+ const { runWorkThreads, WorkCommentCommandError } = await import('./work-comment-cmd-2ACOZQAE.js');
4591
+ const { WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4579
4592
  try {
4580
4593
  await runWorkThreads(opts);
4581
4594
  } catch (err) {
@@ -4586,6 +4599,31 @@ on whom next.
4586
4599
  throw err;
4587
4600
  }
4588
4601
  });
4602
+ 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(
4603
+ "after",
4604
+ `
4605
+ ${cliInvocation()} work logs --item 7
4606
+ ${cliInvocation()} work logs --item 7 --attempt 7b0a3c52-9f1e-4d6b-8a21-5c3e9d2f1a40
4607
+
4608
+ Prints what the runner did around the agent on that attempt, one line
4609
+ per event with its timestamp, with secrets removed on the host. The
4610
+ runner sends it when it releases the attempt, so an attempt that is
4611
+ still running, or that an older runner released, has no log and the
4612
+ command exits 1.
4613
+ `
4614
+ ).action(async (opts) => {
4615
+ const { runWorkLogs, WorkLogsCommandError } = await import('./work-logs-cmd-QDD2NMJL.js');
4616
+ const { WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4617
+ try {
4618
+ await runWorkLogs(opts);
4619
+ } catch (err) {
4620
+ if (err instanceof WorkLogsCommandError || err instanceof WorkCommandError) {
4621
+ fail(err.message);
4622
+ return;
4623
+ }
4624
+ throw err;
4625
+ }
4626
+ });
4589
4627
  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
4628
  "after",
4591
4629
  `
@@ -4596,8 +4634,7 @@ deletes anything \u2014 the item is removed from Work only once no
4596
4634
  live addition remains on it.
4597
4635
  `
4598
4636
  ).action(async (opts) => {
4599
- warnIfApiKeyFlag(opts);
4600
- const { runWorkRemove, WorkCommandError } = await import('./work-cmd-7S5B2H2P.js');
4637
+ const { runWorkRemove, WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4601
4638
  try {
4602
4639
  await runWorkRemove(opts);
4603
4640
  } catch (err) {
@@ -4609,8 +4646,7 @@ live addition remains on it.
4609
4646
  }
4610
4647
  });
4611
4648
  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');
4649
+ const { runWorkStatus, WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4614
4650
  try {
4615
4651
  await runWorkStatus(opts);
4616
4652
  } catch (err) {
@@ -4622,8 +4658,7 @@ live addition remains on it.
4622
4658
  }
4623
4659
  });
4624
4660
  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');
4661
+ const { runWorkList, WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4627
4662
  try {
4628
4663
  await runWorkList(opts);
4629
4664
  } catch (err) {
@@ -4644,8 +4679,7 @@ by a different key is refused; claiming again with the same key extends
4644
4679
  it. --host is a label only.
4645
4680
  `
4646
4681
  ).action(async (opts) => {
4647
- warnIfApiKeyFlag(opts);
4648
- const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
4682
+ const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-3J3QW56U.js');
4649
4683
  try {
4650
4684
  await runWorkClaim(opts);
4651
4685
  } catch (err) {
@@ -4665,8 +4699,7 @@ Extends the live lease this API key holds. Refused with a 410 if the
4665
4699
  lease has expired, or a 403 if a different key holds it.
4666
4700
  `
4667
4701
  ).action(async (opts) => {
4668
- warnIfApiKeyFlag(opts);
4669
- const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
4702
+ const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-3J3QW56U.js');
4670
4703
  try {
4671
4704
  await runWorkRenew(opts);
4672
4705
  } catch (err) {
@@ -4698,8 +4731,7 @@ applies to a host's lease only. A later tool call in the session
4698
4731
  takes the lease again.
4699
4732
  `
4700
4733
  ).action(async (opts) => {
4701
- warnIfApiKeyFlag(opts);
4702
- const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-34FERLYX.js');
4734
+ const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-3J3QW56U.js');
4703
4735
  try {
4704
4736
  await runWorkRelease(opts);
4705
4737
  } catch (err) {
@@ -4726,8 +4758,7 @@ Idempotent: declaring the same pull request twice is a no-op.
4726
4758
  needs your own login; an agent session or a factory key is refused.
4727
4759
  `
4728
4760
  ).action(async (number, opts) => {
4729
- warnIfApiKeyFlag(opts);
4730
- const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-5LGANL32.js');
4761
+ const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-H4OQR26N.js');
4731
4762
  try {
4732
4763
  await runWorkPr({ ...opts, number });
4733
4764
  } catch (err) {
@@ -4752,9 +4783,8 @@ login, then declares the pull request on the item, as \`work pr\` does.
4752
4783
  Run it again after a change to the title or description.
4753
4784
  `
4754
4785
  ).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');
4786
+ const { runWorkOpenPr, WorkOpenPrCommandError } = await import('./work-open-pr-cmd-XNCEI4ZM.js');
4787
+ const { WorkCommandError } = await import('./work-cmd-5EPPD33Y.js');
4758
4788
  try {
4759
4789
  await runWorkOpenPr(opts);
4760
4790
  } catch (err) {
@@ -4770,8 +4800,8 @@ function registerRunnerCommands(program2) {
4770
4800
  const runnerCmd = program2.command("runner").description("Take work from the implement and amend queues on this machine");
4771
4801
  const configOption = "the cloud config file to run against (default: ~/.outerlayer/config.json)";
4772
4802
  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');
4803
+ const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-CLSGABD5.js');
4804
+ const { start, RunnerStartError } = await import('./loop-SYYPVFYW.js');
4775
4805
  const { RunnerAlreadyRunningError } = await import('./pidfile-3DM4OBKO.js');
4776
4806
  const configPath = opts.config ?? defaultRunnerConfigPath();
4777
4807
  try {
@@ -4786,8 +4816,8 @@ function registerRunnerCommands(program2) {
4786
4816
  }
4787
4817
  });
4788
4818
  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');
4819
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
4820
+ const { runRunnerCheck } = await import('./check-UWQAL2MN.js');
4791
4821
  const configPath = opts.config ?? defaultRunnerConfigPath();
4792
4822
  const result = await runRunnerCheck(configPath);
4793
4823
  if (!result.ok) {
@@ -4803,7 +4833,7 @@ function registerRunnerCommands(program2) {
4803
4833
  `);
4804
4834
  });
4805
4835
  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');
4836
+ const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-CLSGABD5.js');
4807
4837
  const { runRunnerInstall, RunnerInstallError, launcherSummary, restartNote } = await import('./install-cmd-QDOTR4OM.js');
4808
4838
  const configPath = opts.config ?? defaultRunnerConfigPath();
4809
4839
  if (opts.service !== true) {
@@ -4816,7 +4846,7 @@ function registerRunnerCommands(program2) {
4816
4846
  }
4817
4847
  try {
4818
4848
  if (opts.service === true) {
4819
- const { installServiceCommand } = await import('./command-H5CILO4S.js');
4849
+ const { installServiceCommand } = await import('./command-OEAV7BVX.js');
4820
4850
  const result2 = await installServiceCommand({
4821
4851
  configPath,
4822
4852
  print: opts.print,
@@ -4871,8 +4901,8 @@ To keep it running, run ${C.yellow}${cliInvocation()} runner install --service${
4871
4901
  fail(`pass --service: \`${cliInvocation()} runner uninstall --service\` removes the runner's service.`);
4872
4902
  return;
4873
4903
  }
4874
- const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
4875
- const { uninstallServiceCommand } = await import('./command-H5CILO4S.js');
4904
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
4905
+ const { uninstallServiceCommand } = await import('./command-OEAV7BVX.js');
4876
4906
  const result = await uninstallServiceCommand({ configPath: opts.config ?? defaultRunnerConfigPath(), unitName: opts.unitName, home: homeFromEnv() });
4877
4907
  if (result.ok) for (const line of result.lines) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
4878
4908
  `);
@@ -4899,12 +4929,12 @@ already in runner.env is used.
4899
4929
  printf '%s' "$CLAUDE_CODE_OAUTH_TOKEN" | ${cliInvocation()} runner init --agent claude --factory <org>/<factory>
4900
4930
  `
4901
4931
  ).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');
4932
+ const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-CLSGABD5.js');
4933
+ const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-MOINY2DD.js');
4934
+ const { obtainRunnerKey, runnerKeyLogin } = await import('./runner-key-276SJU5R.js');
4935
+ const { detectMachine } = await import('./machine-6X63G2KH.js');
4936
+ const { chooseVm, runVmInit, VmInitError } = await import('./init-LWHDMZQG.js');
4937
+ const { AGENT_COMMANDS, credentialFromStdin, isAgentName, restartForCredential, RunnerEnvError } = await import('./runner-env-FRZFFHDF.js');
4908
4938
  const configPath = opts.config ?? defaultRunnerConfigPath();
4909
4939
  if (opts.agent !== void 0 && !isAgentName(opts.agent)) {
4910
4940
  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 +4948,7 @@ already in runner.env is used.
4918
4948
  try {
4919
4949
  let credential;
4920
4950
  if (agent !== void 0) {
4921
- const { readPipedKey } = await import('./login-browser-O63QZN7D.js');
4951
+ const { readPipedKey } = await import('./login-browser-DX35MARZ.js');
4922
4952
  credential = credentialFromStdin(
4923
4953
  await readPipedKey(process.stdin, {
4924
4954
  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 +5084,7 @@ ${C.yellow}The runner will not update itself: ${installErr.message}${C.reset}
5054
5084
  let serviceUp = false;
5055
5085
  let restart;
5056
5086
  if (installedLayout) {
5057
- const { installServiceCommand } = await import('./command-H5CILO4S.js');
5087
+ const { installServiceCommand } = await import('./command-OEAV7BVX.js');
5058
5088
  const service = await installServiceCommand({
5059
5089
  configPath,
5060
5090
  entryPath: process.argv[1] ?? "",
@@ -5098,12 +5128,12 @@ Next:
5098
5128
  "after",
5099
5129
  "\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
5130
  ).action(async (opts) => {
5101
- const { defaultRunnerConfigPath } = await import('./config-FXDG4NPJ.js');
5131
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
5102
5132
  const { buildRepositoryImage, RecipeError } = await import('./build-TQ6X5PYN.js');
5103
5133
  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');
5134
+ const { createDockerHost } = await import('./docker-BFU3AQGY.js');
5135
+ const { builderSpec } = await import('./builder-C4QNTYMS.js');
5136
+ const { loadRunnerConfig } = await import('./config-CLSGABD5.js');
5107
5137
  const configPath = opts.config ?? defaultRunnerConfigPath();
5108
5138
  const loaded = (() => {
5109
5139
  try {
@@ -5114,7 +5144,7 @@ Next:
5114
5144
  })();
5115
5145
  const memory = loaded?.build?.memory ?? "8g";
5116
5146
  try {
5117
- const { imageTargetFor } = await import('./governing-source-BUU4IABS.js');
5147
+ const { imageTargetFor } = await import('./governing-source-V5EEGPTA.js');
5118
5148
  const target = await imageTargetFor({ config: loaded, repository: opts.repository, fetchImpl: fetch });
5119
5149
  if (!target.ok) {
5120
5150
  if (opts.json) {
@@ -5177,16 +5207,16 @@ Next:
5177
5207
  }
5178
5208
  });
5179
5209
  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');
5210
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
5211
+ const { requestStop } = await import('./loop-SYYPVFYW.js');
5182
5212
  const configPath = opts.config ?? defaultRunnerConfigPath();
5183
5213
  await requestStop(configPath, Boolean(opts.now));
5184
5214
  });
5185
5215
  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');
5216
+ const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-CLSGABD5.js');
5187
5217
  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');
5218
+ const { listJobFiles, runnerProcessState } = await import('./loop-SYYPVFYW.js');
5219
+ const { renderStatus } = await import('./status-NAK6DYSF.js');
5190
5220
  const { readHousekeepingRecord } = await import('./record-3WP6V2K5.js');
5191
5221
  const path2 = await import('path');
5192
5222
  const configPath = opts.config ?? defaultRunnerConfigPath();
@@ -5206,7 +5236,7 @@ Next:
5206
5236
  const service = await (async () => {
5207
5237
  if (process.platform !== "linux" || !existsSync("/run/systemd/system")) return void 0;
5208
5238
  const { inspectService, realInspectProbes } = await import('./inspect-6UYAAXH7.js');
5209
- const { DEFAULT_UNIT_NAME } = await import('./install-CBWIEF3R.js');
5239
+ const { DEFAULT_UNIT_NAME } = await import('./install-4SEFIIW2.js');
5210
5240
  const facts = inspectService(DEFAULT_UNIT_NAME, path2.dirname(configPath), realInspectProbes());
5211
5241
  return facts === void 0 ? void 0 : { unit: facts.unit, running: facts.mainPid !== void 0, delegated: facts.delegate };
5212
5242
  })();
@@ -5241,8 +5271,8 @@ Next:
5241
5271
  );
5242
5272
  });
5243
5273
  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');
5274
+ const { defaultRunnerConfigPath } = await import('./config-CLSGABD5.js');
5275
+ const { listJobFiles } = await import('./loop-SYYPVFYW.js');
5246
5276
  const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-AMLKC3VP.js');
5247
5277
  const configPath = opts.config ?? defaultRunnerConfigPath();
5248
5278
  const item = parseTrackerNumber(itemArg);
@@ -5277,32 +5307,22 @@ function registerHooksCommands(program2) {
5277
5307
  "after",
5278
5308
  "\n`init` auto-wraps PreToolUse/PostToolUse hooks; these subcommands cover the\nrest: manual re-scans, other events, and undo.\n"
5279
5309
  );
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(
5310
+ hooksCmd.command("install-git").description("Remove the git hooks an earlier version installed in this repo").addHelpText(
5281
5311
  "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
- }
5312
+ "\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"
5313
+ ).action(() => {
5292
5314
  const removal = removeJournalHooks(process.cwd());
5293
5315
  if (removal.removed) {
5294
5316
  process.stdout.write(`${C.green}\u2713${C.reset} removed the commit journal hooks an earlier version installed \u2192 ${removal.path}
5295
5317
  `);
5296
5318
  }
5297
- const guard = installPreCommitGuardHook(process.cwd());
5298
- const report = formatGuardInstallOutput(guard);
5299
- if (report.error !== void 0) {
5300
- fail(report.error);
5301
- return;
5319
+ const guard = removePreCommitGuardHook(process.cwd());
5320
+ if (guard.removed) {
5321
+ process.stdout.write(`${C.green}\u2713${C.reset} removed the pre-commit guard an earlier version installed \u2192 ${guard.path}
5322
+ `);
5302
5323
  }
5303
- for (const line of report.lines) process.stdout.write(`${line}
5324
+ if (!removal.removed && !guard.removed) process.stdout.write(`${C.dim}No git hooks from an earlier version were found.${C.reset}
5304
5325
  `);
5305
- if (report.exitCode !== void 0) process.exitCode = report.exitCode;
5306
5326
  });
5307
5327
  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
5328
  const report = [];
@@ -5501,7 +5521,7 @@ caller from the bearer token, the gateway answers 401 without that header.
5501
5521
  "after",
5502
5522
  "\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
5523
  ).action(async (opts) => {
5504
- const { runMcpServe, handleMcpServeError } = await import('./mcp-serve-cmd-DOTY5FKY.js');
5524
+ const { runMcpServe, handleMcpServeError } = await import('./mcp-serve-cmd-N3UTY6EE.js');
5505
5525
  try {
5506
5526
  await runMcpServe({ url: opts.url, appId: opts.appId });
5507
5527
  } catch (err) {
@@ -5512,7 +5532,7 @@ caller from the bearer token, the gateway answers 401 without that header.
5512
5532
  function registerImportCommands(program2) {
5513
5533
  const importCmd = program2.command("import").description("Import an existing config format into .outerlayer/");
5514
5534
  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');
5535
+ const { runImportRuler, ImportRulerError } = await import('./import-ruler-cmd-5P6JOXQN.js');
5516
5536
  try {
5517
5537
  const result = runImportRuler({ cwd: opts.dir, json: opts.json });
5518
5538
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
@@ -5528,7 +5548,7 @@ function registerImportCommands(program2) {
5528
5548
  "after",
5529
5549
  "\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
5550
  ).action(async (opts) => {
5531
- const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-ZO6KGHI2.js');
5551
+ const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-KKFFOGWP.js');
5532
5552
  try {
5533
5553
  runImportCapture({ cwd: opts.dir, json: opts.json });
5534
5554
  } catch (err) {
@@ -5540,59 +5560,14 @@ function registerImportCommands(program2) {
5540
5560
  }
5541
5561
  });
5542
5562
  }
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
5563
  function registerContextCommands(program2) {
5566
- const contextCmd = program2.command("context").description("Compile and materialize agent context");
5564
+ const contextCmd = program2.command("context").description("Compile agent context");
5567
5565
  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
5566
  "after",
5569
5567
  '\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
5568
  ).action(async (opts) => {
5571
5569
  await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
5572
5570
  });
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
5571
  }
5597
5572
 
5598
- export { buildProgram, formatContextMaterializeOutput, formatGuardInstallOutput, formatInitOutput, runCli };
5573
+ export { buildProgram, formatInitOutput, runCli };