@outerlayer/cli 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +11 -11
  3. package/dist/{agent-setup-CN2HUBEJ.js → agent-setup-T624CWPD.js} +8 -7
  4. package/dist/artifact-link-cmd-2F47LT7F.js +24 -0
  5. package/dist/build-info.json +1 -1
  6. package/dist/{check-2JSSXCKJ.js → check-5XE7XMC4.js} +22 -19
  7. package/dist/{chunk-HFKKFTXU.js → chunk-2MNPHL23.js} +19 -11
  8. package/dist/{chunk-YDSMROTB.js → chunk-3NSNIIBE.js} +8 -4
  9. package/dist/{chunk-FOJGZYFC.js → chunk-42ZI52JW.js} +1 -1
  10. package/dist/{chunk-NPQWKGUA.js → chunk-6Y5RUTHO.js} +1 -1
  11. package/dist/{chunk-PQUM37BK.js → chunk-BWQ66M6N.js} +1 -1
  12. package/dist/chunk-C5Y5ZJJZ.js +88 -0
  13. package/dist/{chunk-ASOSIKA4.js → chunk-G5NPRL2K.js} +27 -6
  14. package/dist/{chunk-QLTYTPYU.js → chunk-HGECYFEI.js} +64 -7
  15. package/dist/{chunk-SXWS25JC.js → chunk-KG5ECZGJ.js} +6 -6
  16. package/dist/{chunk-F7GBYX2P.js → chunk-LWSJQJC6.js} +18 -4
  17. package/dist/{chunk-UUDDPNRJ.js → chunk-MAK5LYRF.js} +33 -10
  18. package/dist/{chunk-MTF3PHVZ.js → chunk-NBGDBTO2.js} +3 -3
  19. package/dist/{chunk-KFRM23WD.js → chunk-NNRTPG7X.js} +2 -2
  20. package/dist/{chunk-MSASO5O4.js → chunk-NWQTTSBB.js} +1 -1
  21. package/dist/{chunk-2M63GG56.js → chunk-OHVJA253.js} +1 -1
  22. package/dist/{chunk-Z3NOIFDR.js → chunk-ONKJUM6R.js} +1 -1
  23. package/dist/{chunk-T5VPP6H7.js → chunk-OZGHL5Y5.js} +1 -1
  24. package/dist/{chunk-ZA5CHAFY.js → chunk-POJMEEJJ.js} +21 -4
  25. package/dist/{chunk-JR6ERP3M.js → chunk-S3NYLI2P.js} +3 -3
  26. package/dist/{chunk-HXLMZOKU.js → chunk-VQYBXPI7.js} +4 -4
  27. package/dist/{chunk-LCEXHCHD.js → chunk-WTE3MQML.js} +1 -1
  28. package/dist/{chunk-NXUH742G.js → chunk-WVUIRTWA.js} +10 -8
  29. package/dist/{chunk-JJEGKEFV.js → chunk-YU3VKZ5F.js} +1 -1
  30. package/dist/{chunk-3NLOVYJQ.js → chunk-YZ5F4PIS.js} +134 -38
  31. package/dist/{cli-RGGXQTWI.js → cli-A76AXELQ.js} +90 -79
  32. package/dist/{command-ETUAEXP2.js → command-R2QCVX55.js} +10 -9
  33. package/dist/{connect-cmd-JUAW6MU4.js → connect-cmd-JBKAQNSF.js} +1 -1
  34. package/dist/{context-adopt-PJUMW2EZ.js → context-adopt-NFHCLVUB.js} +5 -4
  35. package/dist/{context-materialize-FDHYKNDT.js → context-materialize-IV2TUUFO.js} +5 -4
  36. package/dist/{doctor-CORFPYY6.js → doctor-4TAIARIG.js} +15 -13
  37. package/dist/{emit-artifact-cmd-FOGNJXVR.js → emit-artifact-cmd-MPZVR56N.js} +4 -4
  38. package/dist/{emit-cmd-ZEYWLC2C.js → emit-cmd-IJ3GVRFD.js} +4 -3
  39. package/dist/{emit-criteria-cmd-HBP6XS5C.js → emit-criteria-cmd-EFGYI23V.js} +2 -2
  40. package/dist/{emit-finding-cmd-DLI4MKMN.js → emit-finding-cmd-5GF3V4LR.js} +160 -47
  41. package/dist/{emit-result-cmd-MUSL7GQA.js → emit-result-cmd-I4OADKMD.js} +4 -4
  42. package/dist/hidden-prompt-UXBFMQC5.js +68 -0
  43. package/dist/{hook-fast-WYQD6D7T.js → hook-fast-R4FVSZ2H.js} +1 -1
  44. package/dist/{import-capture-cmd-6QVCOIHK.js → import-capture-cmd-EQ35EARA.js} +3 -3
  45. package/dist/{import-ruler-cmd-KLRGRBCP.js → import-ruler-cmd-BGAZXCQM.js} +1 -1
  46. package/dist/index.js +3 -3
  47. package/dist/{init-OPB7HHXO.js → init-6XPDRDTC.js} +12 -11
  48. package/dist/{init-MIC37V6J.js → init-PWU5YVL7.js} +54 -29
  49. package/dist/{init-cmd-JR3RKNFB.js → init-cmd-XAVO7HYZ.js} +11 -10
  50. package/dist/{init-update-O5YYFGF4.js → init-update-CVCWD6VS.js} +10 -9
  51. package/dist/{loop-QNSM5GXS.js → loop-FK3LPMMZ.js} +19 -18
  52. package/dist/{machine-IT6GG7FF.js → machine-SQXEBAM2.js} +10 -9
  53. package/dist/{runner-env-XTC53CHN.js → runner-env-EN7YE7QX.js} +1 -1
  54. package/dist/runner-key-6SLBI7PP.js +174 -0
  55. package/dist/{session-sender-4M247XSV.js → session-sender-FO3LCREV.js} +3 -3
  56. package/dist/{starter-pack-IB4UUIX3.js → starter-pack-KF66HGZR.js} +3 -3
  57. package/dist/{status-7ZX57OFJ.js → status-7VNQN5PW.js} +13 -12
  58. package/dist/{sync-cmd-UWD5JOFU.js → sync-cmd-GVPPFZ3G.js} +2 -2
  59. package/dist/{watch-DBNB7R6X.js → watch-23HSAEI6.js} +2 -2
  60. package/dist/{work-claim-cmd-A6IS6CQ7.js → work-claim-cmd-LKL3GHFQ.js} +5 -5
  61. package/dist/{work-cmd-EQSW5DTD.js → work-cmd-Z2WXLZPH.js} +3 -3
  62. package/dist/{work-comment-cmd-7VLKI7FN.js → work-comment-cmd-AWHP56M2.js} +3 -3
  63. package/dist/{work-open-pr-cmd-JEVD4HMQ.js → work-open-pr-cmd-IOM4AVQQ.js} +4 -4
  64. package/dist/{work-pr-cmd-L77K32WK.js → work-pr-cmd-HNEUIEN7.js} +3 -3
  65. package/package.json +1 -1
  66. package/skill-pack/maintained/{amend → outerlayer-amend}/SKILL.md +4 -2
  67. package/skill-pack/maintained/{outerlayer → outerlayer-cli}/SKILL.md +5 -3
  68. package/skill-pack/maintained/{emitting-evidence → outerlayer-evidence}/SKILL.md +5 -3
  69. package/skill-pack/maintained/{reporting-findings → outerlayer-findings}/SKILL.md +26 -30
  70. package/skill-pack/shipped.json +20 -4
  71. package/skill-pack/template/build/SKILL.md +7 -1
  72. package/skill-pack/template/build/references/agent-briefs.md +7 -1
  73. package/skill-pack/template/build/references/evidence.md +1 -1
  74. package/skill-pack/template/build/references/release.md +14 -12
  75. package/skill-pack/template/build/references/review-briefs.md +6 -0
  76. package/skill-pack/template/build/scripts/criterion-citations.mjs +8 -3
  77. package/skill-pack/template/build/scripts/record-criteria.mjs +8 -2
  78. package/skill-pack/template/spec/SKILL.md +2 -0
  79. package/skill-pack/template/writing-specs/SKILL.md +1 -1
  80. package/skill-pack/validators/acceptance-criteria.yaml +6 -5
  81. package/skill-pack/validators/code-review.yaml +6 -5
  82. package/dist/runner-key-7SSNMUBQ.js +0 -154
  83. /package/skill-pack/maintained/{outerlayer → outerlayer-cli}/references/open-pull-request.md +0 -0
  84. /package/skill-pack/maintained/{emitting-evidence → outerlayer-evidence}/references/agents-snippet.md +0 -0
@@ -1,15 +1,15 @@
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-QLTYTPYU.js';
4
- import './chunk-MTF3PHVZ.js';
5
- import './chunk-JR6ERP3M.js';
6
- import './chunk-NPQWKGUA.js';
3
+ import { gatherDoctorChecks, doctorExitCode, summarizeChecks, renderDoctorText, recordWrapped, recordUnwrapped, recordRemoval, readManifest, recordInstall, recordStatusline } from './chunk-HGECYFEI.js';
4
+ import './chunk-NBGDBTO2.js';
5
+ import './chunk-S3NYLI2P.js';
6
+ import './chunk-6Y5RUTHO.js';
7
7
  import './chunk-IP7BIBXJ.js';
8
8
  import './chunk-F47JBIAW.js';
9
9
  import './chunk-BKO6JEZI.js';
10
10
  import './chunk-XCK2YAY5.js';
11
- import './chunk-FOJGZYFC.js';
12
- import './chunk-YDSMROTB.js';
11
+ import './chunk-42ZI52JW.js';
12
+ import './chunk-3NSNIIBE.js';
13
13
  import './chunk-WUYTWNMA.js';
14
14
  import './chunk-JXYVA45C.js';
15
15
  import './chunk-4KSQKQXE.js';
@@ -17,17 +17,18 @@ import './chunk-N6LURUEF.js';
17
17
  import { C, NO_COLOR_FLAG, warnDeprecated, stripNoColor, API_KEY_FLAG_DEPRECATION } from './chunk-YRYMNBGQ.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-LCEXHCHD.js';
20
+ import { pinExists } from './chunk-WTE3MQML.js';
21
+ import './chunk-C5Y5ZJJZ.js';
21
22
  import './chunk-YO4PSLVB.js';
22
- import './chunk-ZA5CHAFY.js';
23
- import './chunk-2M63GG56.js';
23
+ import './chunk-POJMEEJJ.js';
24
+ import './chunk-OHVJA253.js';
24
25
  import './chunk-PLMTLGYH.js';
25
26
  import './chunk-J5M7BSJQ.js';
26
27
  import './chunk-EABW6AJQ.js';
27
28
  import { resolveVersion } from './chunk-RA3O54FC.js';
28
29
  import './chunk-V7NIVOFD.js';
29
30
  import './chunk-ZM2IMMYN.js';
30
- import { hookFiredMarkerPath, installedCliDistDir } from './chunk-PQUM37BK.js';
31
+ import { hookFiredMarkerPath, installedCliDistDir } from './chunk-BWQ66M6N.js';
31
32
  import { managedHookScripts, removeJournalHooks, installPreCommitGuardHook, removePreCommitGuardHook } from './chunk-XCCLFVXM.js';
32
33
  import './chunk-BJ3KTMDH.js';
33
34
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -3631,7 +3632,7 @@ function printLauncher(result, summary) {
3631
3632
  const line = summary(result.launcher);
3632
3633
  if (line !== void 0) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
3633
3634
  `);
3634
- for (const note of result.launcher.notes) process.stdout.write(`${C.yellow}${note}${C.reset}
3635
+ for (const note of result.launcher.notes) process.stdout.write(`${C.yellow}!${C.reset} ${note}
3635
3636
  `);
3636
3637
  }
3637
3638
  function writeJson(value) {
@@ -3645,7 +3646,7 @@ function warnIfApiKeyFlag(opts) {
3645
3646
  if (opts.apiKey !== void 0) warnDeprecated(API_KEY_FLAG_DEPRECATION);
3646
3647
  }
3647
3648
  async function installStarterPackInRepo() {
3648
- const { installStarterPack, formatStarterPackOutput } = await import('./starter-pack-IB4UUIX3.js');
3649
+ const { installStarterPack, formatStarterPackOutput } = await import('./starter-pack-KF66HGZR.js');
3649
3650
  const cwd = process.cwd();
3650
3651
  let repoRoot = cwd;
3651
3652
  try {
@@ -3805,7 +3806,7 @@ ${starter.output}`),
3805
3806
  }
3806
3807
  }
3807
3808
  async function realConnectDepsForCwd() {
3808
- const { realConnectDeps } = await import('./connect-cmd-JUAW6MU4.js');
3809
+ const { realConnectDeps } = await import('./connect-cmd-JBKAQNSF.js');
3809
3810
  const { resolveRepoIdentity } = await import('./dist-LKDWQWZ7.js');
3810
3811
  return {
3811
3812
  ...realConnectDeps(),
@@ -3827,7 +3828,7 @@ function buildProgram(argv = process.argv) {
3827
3828
  "\nIn a repository, init runs four steps: connect the repository to a\nfactory (`outerlayer connect`), install the hooks, set up the coding agent,\nand run `outerlayer doctor`. It never signs in and asks nothing. With no\nlogin it skips the connect step and says to run `outerlayer login`. With\n--json it prints one document naming the outcome of each step: done,\nskipped or failed. The exit code is 1 when a step failed.\n\nThe agent setup step installs the starter skills and the `outerlayer` skill\ninto .outerlayer/skills/, writes .outerlayer/config.json for Claude Code when\nthere is none, runs `outerlayer context emit` so the skills appear in\n.claude/skills/, and adds the outerlayer and outerlayer-docs MCP servers to\n.mcp.json. Nothing you wrote is changed: an existing config, policy, edited\nskill, MCP entry or root CLAUDE.md and AGENTS.md is left as it is, and a\nhand-written file the emit would replace is kept and listed. The files are\nleft uncommitted.\nThe step is skipped outside a git repository and in a repository whose\ncontext comes from a control plane, where it arrives at session start.\n\n--local installs only the hooks: no connect step, no agent setup and no\nnetwork call. Add `--template default` to also write the starter skills and\na policy file into .outerlayer/ without compiling them; `outerlayer context\nemit` does that.\n\nIdempotent: settings are backed up before any write, and a second run\nchanges nothing. Wrapping adds one spawn per hook firing; undo it with\n`outerlayer hooks unwrap`. An occupied status-line slot is wrapped, never\nreplaced.\n\nThree of the starter skills are copied once and are yours to edit. The\nothers are rewritten from this CLI on every `context emit`.\n\n--update brings the files init wrote once up to this CLI's version: the\ntemplate skills, the policy, the two starter checks and the two MCP\nentries. A file still equal to a version an earlier release wrote is\nreplaced, and a missing one is written. A file you edited is never\ntouched. It then runs `outerlayer context emit` and leaves the changes\nuncommitted. --dry-run prints the plan, with a command to compare each\nedited file, and writes nothing. `outerlayer doctor` reports the same\nstates under Starter files.\n"
3828
3829
  ).action(async (opts) => {
3829
3830
  if (opts.update || opts.dryRun) {
3830
- const { runInitUpdate, formatInitUpdate, updateFlagProblem } = await import('./init-update-O5YYFGF4.js');
3831
+ const { runInitUpdate, formatInitUpdate, updateFlagProblem } = await import('./init-update-CVCWD6VS.js');
3831
3832
  const problem = updateFlagProblem(opts);
3832
3833
  if (problem !== void 0) {
3833
3834
  fail(problem);
@@ -3841,7 +3842,7 @@ function buildProgram(argv = process.argv) {
3841
3842
  }
3842
3843
  let starterTemplate;
3843
3844
  if (opts.template !== void 0) {
3844
- const { assertKnownTemplate, StarterPackError } = await import('./starter-pack-IB4UUIX3.js');
3845
+ const { assertKnownTemplate, StarterPackError } = await import('./starter-pack-KF66HGZR.js');
3845
3846
  try {
3846
3847
  assertKnownTemplate(opts.template);
3847
3848
  } catch (err) {
@@ -3872,7 +3873,7 @@ function buildProgram(argv = process.argv) {
3872
3873
  else process.stdout.write(outcome.text);
3873
3874
  return;
3874
3875
  }
3875
- const { runInitCommand } = await import('./init-cmd-JR3RKNFB.js');
3876
+ const { runInitCommand } = await import('./init-cmd-XAVO7HYZ.js');
3876
3877
  const code = await runInitCommand(
3877
3878
  { json: opts.json, factory: opts.factory },
3878
3879
  {
@@ -3884,7 +3885,7 @@ function buildProgram(argv = process.argv) {
3884
3885
  return { ok, text, detail };
3885
3886
  },
3886
3887
  runAgentSetup: async () => {
3887
- const { runAgentSetup } = await import('./agent-setup-CN2HUBEJ.js');
3888
+ const { runAgentSetup } = await import('./agent-setup-T624CWPD.js');
3888
3889
  return runAgentSetup({ cwd: process.cwd() });
3889
3890
  },
3890
3891
  runDoctorChecks: gatherDoctorChecks
@@ -3896,7 +3897,7 @@ function buildProgram(argv = process.argv) {
3896
3897
  "after",
3897
3898
  "\nRun it in a repository, after `outerlayer login`. With a login, connect lists\nthe factories you can use and takes the first rule that leaves one answer:\n 1. --factory <org>/<factory>, or a factory id\n 2. the factory this repository is already connected to\n 3. the one factory this repository is linked to\n 4. the one factory you can use\n 5. on a terminal, ask; with no terminal, exit 1 and list each --factory value\n\nIt says what it chose and why. The choice is saved in this repository's git\ndirectory (outerlayer/connection.json), shared by every worktree of the\nclone and never committed. A factory key already belongs to one factory, so\nconnect changes nothing for it. Connect never links a repository.\n\nAfter it saves the choice, connect checks that this repository is linked to\nthe factory. If it is not, connect says so, prints the factory's Work page\nlink where you link it, and exits 2. The choice is saved either way. Run\nconnect again once the repository is linked. With --json, the document has\nlinked (true, false, or null when it could not be checked) and, when false,\nlinkUrl.\n"
3898
3899
  ).action(async (opts) => {
3899
- const { runConnectCommand } = await import('./connect-cmd-JUAW6MU4.js');
3900
+ const { runConnectCommand } = await import('./connect-cmd-JBKAQNSF.js');
3900
3901
  const code = await runConnectCommand({ factory: opts.factory, json: opts.json }, await realConnectDepsForCwd(), {
3901
3902
  stdout: process.stdout,
3902
3903
  stderr: process.stderr
@@ -3939,12 +3940,19 @@ function buildProgram(argv = process.argv) {
3939
3940
  const code = await runLogoutCommand(realLogoutDeps());
3940
3941
  if (code !== 0) process.exitCode = code;
3941
3942
  });
3942
- program2.command("sync").description("Send local coding-agent sessions to OuterLayer cloud").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").option("--tier <tier>", "capture tier: metrics | redacted | full (default: full)").option("--dry-run", "print what would leave this machine, send nothing").option("--all", "ignore the sync checkpoint and re-send everything").option("--limit <n>", "only the N most recent sessions", (v) => parseInt(v, 10)).option("--json", "machine-readable JSON output").option("--quiet", "no output; exit code only").option("--root <dir>", "Claude Code transcript root (default ~/.claude/projects)").option("--codex-root <dir>", "Codex sessions root (default ~/.codex/sessions)").option("--cursor-root <dir>", "Cursor chats root (default ~/.cursor/chats)").addHelpText(
3943
+ program2.command("sync").description("Send local coding-agent sessions to OuterLayer cloud").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").option("--tier <tier>", "capture tier: metrics | redacted | full (default: full)").option("--dry-run", "print what would leave this machine, send nothing").option("--all", "ignore the sync checkpoint and re-send everything").option("--limit <n>", "only the N most recent sessions", (v) => parseInt(v, 10)).option("--json", "machine-readable JSON output").option("--quiet", "no output; exit code only").option("--link <artifactId>", "print the dashboard link of an artifact already uploaded; sends nothing").option("--root <dir>", "Claude Code transcript root (default ~/.claude/projects)").option("--codex-root <dir>", "Codex sessions root (default ~/.codex/sessions)").option("--cursor-root <dir>", "Cursor chats root (default ~/.cursor/chats)").addHelpText(
3943
3944
  "after",
3944
3945
  "\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"
3945
3946
  ).action(async (opts) => {
3946
3947
  warnIfApiKeyFlag(opts);
3947
- const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-UWD5JOFU.js');
3948
+ if (opts.link !== void 0) {
3949
+ const { lookupArtifactLink } = await import('./artifact-link-cmd-2F47LT7F.js');
3950
+ const found = lookupArtifactLink(opts.link);
3951
+ if (found.ok) process.stdout.write(found.url + "\n");
3952
+ else fail(found.reason);
3953
+ return;
3954
+ }
3955
+ const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-GVPPFZ3G.js');
3948
3956
  try {
3949
3957
  const result = await runSync({
3950
3958
  url: opts.url,
@@ -3973,7 +3981,7 @@ function buildProgram(argv = process.argv) {
3973
3981
  if (invokedCommandToken(argv) === "watch") {
3974
3982
  warnDeprecated("`outerlayer watch` is now `outerlayer daemon`; the old name will be removed in a future release.");
3975
3983
  }
3976
- const { runWatch } = await import('./watch-DBNB7R6X.js');
3984
+ const { runWatch } = await import('./watch-23HSAEI6.js');
3977
3985
  await runWatch({ once: opts.once });
3978
3986
  });
3979
3987
  program2.command("hook <event>", { hidden: true }).description("capture-hook fast path, installed by `init`").action(() => {
@@ -4027,7 +4035,7 @@ function buildProgram(argv = process.argv) {
4027
4035
  }
4028
4036
  });
4029
4037
  program2.command("session-sender", { hidden: true }).description("stream a runner build's sessions to its work item while the build runs").action(async () => {
4030
- const { runSessionSender } = await import('./session-sender-4M247XSV.js');
4038
+ const { runSessionSender } = await import('./session-sender-FO3LCREV.js');
4031
4039
  try {
4032
4040
  await runSessionSender();
4033
4041
  } catch (err) {
@@ -4062,7 +4070,7 @@ async function runCli(processArgv) {
4062
4070
  await buildProgram(argv).parseAsync(argv);
4063
4071
  }
4064
4072
  async function compileContext(opts) {
4065
- const { runEmit, EmitError } = await import('./emit-cmd-ZEYWLC2C.js');
4073
+ const { runEmit, EmitError } = await import('./emit-cmd-IJ3GVRFD.js');
4066
4074
  try {
4067
4075
  const result = runEmit({ cwd: opts.dir, check: opts.check, json: opts.json });
4068
4076
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
@@ -4085,7 +4093,7 @@ function registerEmitCommands(program2) {
4085
4093
  return;
4086
4094
  }
4087
4095
  warnIfApiKeyFlag(opts);
4088
- const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-MUSL7GQA.js');
4096
+ const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-I4OADKMD.js');
4089
4097
  try {
4090
4098
  const result = await runEmitResult({
4091
4099
  name,
@@ -4136,7 +4144,7 @@ locally so it never uploads. One correction can retire several duplicates.
4136
4144
  `
4137
4145
  ).action(async (file, opts) => {
4138
4146
  warnIfApiKeyFlag(opts);
4139
- const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-FOGNJXVR.js');
4147
+ const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-MPZVR56N.js');
4140
4148
  let pr;
4141
4149
  if (opts.pr !== void 0) {
4142
4150
  pr = parseTrackerNumber(opts.pr);
@@ -4166,12 +4174,12 @@ locally so it never uploads. One correction can retire several duplicates.
4166
4174
  throw err;
4167
4175
  }
4168
4176
  });
4169
- emitCmd.command("finding").description("Record one finding: a problem you hit in the factory").requiredOption("--id <id>", "client id \u2014 re-emitting the same id replaces it").option("--category <context|flaky-test|tooling|environment|defect|other>", "what kind of problem this is").requiredOption("--title <text>", "one sentence").requiredOption("--file <path>", "the file the problem is in, or the instruction's own path").option("--line <number>", "line number in --file").option("--rule-path <path>", "the instruction's own path \u2014 required for a context finding").option("--rule-line <number>", "line number in --rule-path").option("--rule-quote <text>", "the instruction's quoted sentence \u2014 required unless --rule-relation is missing").option("--rule-relation <wrong|broken|missing>", "how the instruction fails \u2014 required for a context finding").requiredOption("--where <label>", 'where this was recorded, e.g. "build session"').option("--detail <text>", "what happened, a few paragraphs").option("--cause <text>", 'what is actually wrong, or "unknown"').option("--suggestion <text>", "what would help").option("--command <text>", "the command that misbehaved").option("--error <text>", "the first error line").option("--test <name>", "the test name, for a flaky test").option("--symbol <name>", "the function the problem is in, for a defect").option("--started-at <event>", "event id where you first hit the problem (ids are listed when you omit this)").option("--ended-at <event>", "event id where you got past it").option("--problem <id>", "a problem this finding reports; repeat for each one (needs --link-reason)", (value, previous = []) => [...previous, value]).option("--link-reason <text>", "why the finding reports each --problem").option("--new", "record a new problem instead of linking an existing one").option("--trace-id <id>", "the session's trace id, when there is one").option("--turn <number>", "turn index within the session").option("--round <number>", "round number, when there is one").addOption(new Option("--subject <value>").hideHelp()).addOption(new Option("--kind <value>").hideHelp()).addOption(new Option("--severity <value>").hideHelp()).addOption(new Option("--verdict <value>").hideHelp()).addOption(new Option("--fixed").hideHelp()).addOption(new Option("--source <value>").hideHelp()).option("--head-sha <sha>", "the commit this batch was recorded against").option("--context-source-sha <sha>", "the context-source commit this batch was recorded against").option("--item <number>", "work item to record on directly, by its number in this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
4177
+ emitCmd.command("finding").description("Record one finding: a problem you hit in the factory").requiredOption("--id <id>", "client id \u2014 re-emitting the same id replaces it").option("--category <context|flaky-test|tooling|environment|defect|other>", "what kind of problem this is").requiredOption("--title <text>", "one sentence").requiredOption("--file <path>", "the file the problem is in, or the instruction's own path").option("--line <number>", "line number in --file").option("--rule-path <path>", "the instruction's own path \u2014 required for a context finding").option("--rule-line <number>", "line number in --rule-path").option("--rule-quote <text>", "the instruction's quoted sentence \u2014 required unless --rule-relation is missing").option("--rule-relation <wrong|broken|missing>", "how the instruction fails \u2014 required for a context finding").requiredOption("--where <label>", 'where this was recorded, e.g. "build session"').option("--detail <text>", "what happened, a few paragraphs").option("--cause <text>", 'what is actually wrong, or "unknown"').option("--suggestion <text>", "what would help").option("--command <text>", "the command that misbehaved").option("--error <text>", "the first error line").option("--test <name>", "the test name, for a flaky test").option("--symbol <name>", "the function the problem is in, for a defect").option("--started-at <event>", "event id where you hit the problem (default: first output showing --error)").option("--ended-at <event>", "event id where you got past it (default: the newest event)").option("--untimed", "record no time, only when the problem cost none in this session").option("--find <text>", "list this session's events that contain the text, and record nothing").option("--problem <id>", "a problem this finding reports; repeat for each one (needs --link-reason)", (value, previous = []) => [...previous, value]).option("--link-reason <text>", "why the finding reports each --problem").option("--new", "record a new problem instead of linking an existing one").option("--trace-id <id>", "the session's trace id, when there is one").option("--turn <number>", "turn index within the session").option("--round <number>", "round number, when there is one").addOption(new Option("--subject <value>").hideHelp()).addOption(new Option("--kind <value>").hideHelp()).addOption(new Option("--severity <value>").hideHelp()).addOption(new Option("--verdict <value>").hideHelp()).addOption(new Option("--fixed").hideHelp()).addOption(new Option("--source <value>").hideHelp()).option("--head-sha <sha>", "the commit this batch was recorded against").option("--context-source-sha <sha>", "the context-source commit this batch was recorded against").option("--item <number>", "work item to record on directly, by its number in this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
4170
4178
  "after",
4171
- '\n outerlayer emit finding --id gate-skip --category tooling \\\n --title "The pre-push gate prints green when a step was skipped" \\\n --file scripts/git/pre-push-checks.mjs --where "build session"\n\nRecords one problem you hit in the factory: an instruction that is wrong or\nmissing (context), a flaky test, a misbehaving script (tooling), a local\nsetup trap (environment), a bug outside your own change (defect), or\nanything else. A problem in your own change is fixed, not recorded.\nA context finding needs --rule-path and --rule-relation, and --rule-quote\nunless the relation is missing. Add --cause, --detail and --suggestion, and\n--command, --error (first error line), --test or --symbol when there is one.\n\nEvery finding joins a factory-level problem. When one of its keys matches a\nknown problem it joins that problem. Otherwise nothing is stored: the command\nprints the closest problems and exits with code 3. Run it again with\n--problem <id> --link-reason <why> (repeat --problem for each problem the\nfinding reports), or with --new if none of them is the same problem.\nWithout --started-at and --ended-at it lists your recent session events with\nids and times; name the event where you hit the problem and the one where\nyou got past it to record the time it cost.\n--item names the work item; without it, inside a recorded session, the\nitem that session was launched for is used automatically.\n'
4179
+ '\n outerlayer emit finding --id gate-skip --category tooling \\\n --title "The pre-push gate prints green when a step was skipped" \\\n --file scripts/git/pre-push-checks.mjs --where "build session"\n\nRecords one problem you hit in the factory: an instruction that is wrong or\nmissing (context), a flaky test, a misbehaving script (tooling), a local\nsetup trap (environment), a bug outside your own change (defect), or\nanything else. A problem in your own change is fixed, not recorded.\nA context finding needs --rule-path and --rule-relation, and --rule-quote\nunless the relation is missing. Add --cause, --detail and --suggestion, and\n--command, --error (first error line), --test or --symbol when there is one.\n\nEvery finding joins a factory-level problem. When one of its keys matches a\nknown problem it joins that problem. Otherwise nothing is stored: the command\nprints the closest problems and exits with code 3. Run it again with\n--problem <id> --link-reason <why> (repeat --problem for each problem the\nfinding reports), or with --new if none of them is the same problem.\nA finding records the time it cost, read from two events of your session or\nits subagents. The start is --started-at, else the first tool output that\nshows --error. The end is --ended-at, else the newest event. When the session\nhas events and no start is found, nothing is stored: the command lists the\nrecent events with their ids. --find <text> searches all of them.\n--item names the work item; without it, inside a recorded session, the\nitem that session was launched for is used automatically.\n'
4172
4180
  ).action(async (opts) => {
4173
4181
  warnIfApiKeyFlag(opts);
4174
- const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-DLI4MKMN.js');
4182
+ const { runEmitFinding, refuseRemovedFindingFlags, EmitFindingError } = await import('./emit-finding-cmd-5GF3V4LR.js');
4175
4183
  try {
4176
4184
  refuseRemovedFindingFlags(opts);
4177
4185
  const result = await runEmitFinding({
@@ -4194,6 +4202,8 @@ locally so it never uploads. One correction can retire several duplicates.
4194
4202
  symbol: opts.symbol,
4195
4203
  startedAt: opts.startedAt,
4196
4204
  endedAt: opts.endedAt,
4205
+ untimed: opts.untimed,
4206
+ find: opts.find,
4197
4207
  problem: opts.problem,
4198
4208
  linkReason: opts.linkReason,
4199
4209
  new: opts.new,
@@ -4219,10 +4229,10 @@ locally so it never uploads. One correction can retire several duplicates.
4219
4229
  });
4220
4230
  emitCmd.command("findings <file>").description("Record a batch of findings from a FindingBatch JSON file (- for standard input)").option("--item <number>", "work item to record on directly, by its number in this factory").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "factory id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
4221
4231
  "after",
4222
- "\n outerlayer emit findings review.json --item 412\n\nRecords a whole batch at once \u2014 a FindingBatch JSON file (schemaVersion 3,\noptional headSha / contextSourceSha, and 1-500 findings), validated against\nthe same contract `emit finding` uses before anything is sent. Re-emitting\nan id already on the item replaces that row rather than adding a second one.\nFindings that need a choice between candidate problems are listed and not\nstored; the rest are stored, and the exit code is 3.\n--item names the work item; without it, inside a recorded session, the item\nthat session was launched for is used automatically.\n"
4232
+ '\n outerlayer emit findings review.json --item 412\n\nRecords a whole batch at once \u2014 a FindingBatch JSON file (schemaVersion 3,\noptional headSha / contextSourceSha, and 1-500 findings), validated against\nthe same contract `emit finding` uses before anything is sent. Re-emitting\nan id already on the item replaces that row rather than adding a second one.\nFindings that need a choice between candidate problems are listed and not\nstored; the rest are stored, and the exit code is 3.\nEach finding records its time as `emit finding` does: "startedAt" is an event\nid, else the first tool output that shows its "error"; "endedAt" defaults to\nthe newest event. A finding with neither, in a session that has events, stops\nthe whole batch. "untimed": true records one with no time on purpose.\n--item names the work item; without it, inside a recorded session, the item\nthat session was launched for is used automatically.\n'
4223
4233
  ).action(async (file, opts) => {
4224
4234
  warnIfApiKeyFlag(opts);
4225
- const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-DLI4MKMN.js');
4235
+ const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-5GF3V4LR.js');
4226
4236
  try {
4227
4237
  const result = await runEmitFindings({
4228
4238
  file,
@@ -4262,7 +4272,7 @@ session was launched for is used automatically.
4262
4272
  `
4263
4273
  ).action(async (file, opts) => {
4264
4274
  warnIfApiKeyFlag(opts);
4265
- const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-HBP6XS5C.js');
4275
+ const { runEmitCriteria, EmitCriteriaError } = await import('./emit-criteria-cmd-EFGYI23V.js');
4266
4276
  try {
4267
4277
  const result = await runEmitCriteria({
4268
4278
  file,
@@ -4289,7 +4299,7 @@ function registerWorkCommands(program2) {
4289
4299
  "\n outerlayer work build --issue 42 # a host builds it\n outerlayer work build --item 7 # retry an item already on Work\n outerlayer work build --issue 42 --local # you build it\n outerlayer work build --issue ENG-123 --tracker linear # a Linear issue\n\nWithout --local, records a build request: a host takes the item when it\nhas a free slot. It never links the calling session and never takes a\nlease, even run from inside one.\n\nWith --local, puts the item on Work with no build request, so no host\ntakes it, and prints the line that starts your session on it. That\nsession links itself and holds the item's lease while it works.\n"
4290
4300
  ).action(async (opts) => {
4291
4301
  warnIfApiKeyFlag(opts);
4292
- const { runWorkBuild, WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4302
+ const { runWorkBuild, WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4293
4303
  try {
4294
4304
  await runWorkBuild(opts);
4295
4305
  } catch (err) {
@@ -4305,7 +4315,7 @@ function registerWorkCommands(program2) {
4305
4315
  "\n outerlayer work link-session 42\n\nNames an item that already exists on the calling session \u2014 it never\ncreates one. Create one with `outerlayer work build --local`. Linking\nthe same session to the same item twice is a no-op. Also takes or\nrenews that session's own 20-minute lease, unless --no-lease or\n--ended is given, or another worker already holds a live one.\n"
4306
4316
  ).action(async (number, opts) => {
4307
4317
  warnIfApiKeyFlag(opts);
4308
- const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4318
+ const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4309
4319
  try {
4310
4320
  await runWorkLinkSession({ ...opts, number, noLease: opts.lease === false, logFailures: opts.logFailures === true });
4311
4321
  } catch (err) {
@@ -4330,8 +4340,8 @@ most one action flag may be given.
4330
4340
  `
4331
4341
  ).action(async (opts) => {
4332
4342
  warnIfApiKeyFlag(opts);
4333
- const { runWorkComment, WorkCommentCommandError } = await import('./work-comment-cmd-7VLKI7FN.js');
4334
- const { WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4343
+ const { runWorkComment, WorkCommentCommandError } = await import('./work-comment-cmd-AWHP56M2.js');
4344
+ const { WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4335
4345
  try {
4336
4346
  await runWorkComment(opts);
4337
4347
  } catch (err) {
@@ -4347,8 +4357,8 @@ most one action flag may be given.
4347
4357
  "\n outerlayer work threads --item 7\n\nPrints the item's general thread, then one thread per acceptance\ncriterion that carries proof or a comment, each with who is waiting\non whom next.\n"
4348
4358
  ).action(async (opts) => {
4349
4359
  warnIfApiKeyFlag(opts);
4350
- const { runWorkThreads, WorkCommentCommandError } = await import('./work-comment-cmd-7VLKI7FN.js');
4351
- const { WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4360
+ const { runWorkThreads, WorkCommentCommandError } = await import('./work-comment-cmd-AWHP56M2.js');
4361
+ const { WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4352
4362
  try {
4353
4363
  await runWorkThreads(opts);
4354
4364
  } catch (err) {
@@ -4370,7 +4380,7 @@ live addition remains on it.
4370
4380
  `
4371
4381
  ).action(async (opts) => {
4372
4382
  warnIfApiKeyFlag(opts);
4373
- const { runWorkRemove, WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4383
+ const { runWorkRemove, WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4374
4384
  try {
4375
4385
  await runWorkRemove(opts);
4376
4386
  } catch (err) {
@@ -4383,7 +4393,7 @@ live addition remains on it.
4383
4393
  });
4384
4394
  workCmd.command("status").description("Show one item's stage, gate ledger, and additions").option("--item <number>", "the item's number inside this factory").option("--issue <number>", "issue number").option("--repo <owner/name>", "repository (default: the current 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) => {
4385
4395
  warnIfApiKeyFlag(opts);
4386
- const { runWorkStatus, WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4396
+ const { runWorkStatus, WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4387
4397
  try {
4388
4398
  await runWorkStatus(opts);
4389
4399
  } catch (err) {
@@ -4396,7 +4406,7 @@ live addition remains on it.
4396
4406
  });
4397
4407
  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) => {
4398
4408
  warnIfApiKeyFlag(opts);
4399
- const { runWorkList, WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4409
+ const { runWorkList, WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4400
4410
  try {
4401
4411
  await runWorkList(opts);
4402
4412
  } catch (err) {
@@ -4412,7 +4422,7 @@ live addition remains on it.
4412
4422
  "\n outerlayer work claim --item 42 --kind implement\n\nRecords a lease held by the API key that sends it. A live lease held\nby a different key is refused; claiming again with the same key extends\nit. --host is a label only.\n"
4413
4423
  ).action(async (opts) => {
4414
4424
  warnIfApiKeyFlag(opts);
4415
- const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-A6IS6CQ7.js');
4425
+ const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-LKL3GHFQ.js');
4416
4426
  try {
4417
4427
  await runWorkClaim(opts);
4418
4428
  } catch (err) {
@@ -4428,7 +4438,7 @@ live addition remains on it.
4428
4438
  "\n outerlayer work renew --item 42\n\nExtends the live lease this API key holds. Refused with a 410 if the\nlease has expired, or a 403 if a different key holds it.\n"
4429
4439
  ).action(async (opts) => {
4430
4440
  warnIfApiKeyFlag(opts);
4431
- const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-A6IS6CQ7.js');
4441
+ const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-LKL3GHFQ.js');
4432
4442
  try {
4433
4443
  await runWorkRenew(opts);
4434
4444
  } catch (err) {
@@ -4447,7 +4457,7 @@ live addition remains on it.
4447
4457
  "\n outerlayer work release --item 42 --outcome ok\n outerlayer work release --item 42\n\nMarks the lease this API key holds released, optionally with an\noutcome. A lease held by a different key is refused. Releasing an\nalready-released lease is a no-op that returns the recorded release\ntime and outcome.\n\nRun inside a session with no --host, it releases that session's own\nlease instead, so the item's review opens without ending the\nsession. It never releases another session's lease. --outcome\napplies to a host's lease only. A later tool call in the session\ntakes the lease again.\n"
4448
4458
  ).action(async (opts) => {
4449
4459
  warnIfApiKeyFlag(opts);
4450
- const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-A6IS6CQ7.js');
4460
+ const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-LKL3GHFQ.js');
4451
4461
  try {
4452
4462
  await runWorkRelease(opts);
4453
4463
  } catch (err) {
@@ -4463,7 +4473,7 @@ live addition remains on it.
4463
4473
  "\n outerlayer work pr 481\n outerlayer work pr 481 --withdraw --item 250\n\nRun inside a session already on a work item. Records that pull\nrequest 481 in the checkout's repository belongs to the item named by\nOUTERLAYER_WORK, or refuses when the session is not on it. The same\nfact a `pr-link` in the session's own transcript records on sync.\nIdempotent: declaring the same pull request twice is a no-op.\n\n--withdraw removes one item's declaration of the pull request. It\nneeds your own login; an agent session or a factory key is refused.\n"
4464
4474
  ).action(async (number, opts) => {
4465
4475
  warnIfApiKeyFlag(opts);
4466
- const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-L77K32WK.js');
4476
+ const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-HNEUIEN7.js');
4467
4477
  try {
4468
4478
  await runWorkPr({ ...opts, number });
4469
4479
  } catch (err) {
@@ -4479,8 +4489,8 @@ live addition remains on it.
4479
4489
  '\n outerlayer work open-pr --title "Add the thing" --body-file pr.md\n outerlayer work open-pr --repository acme/web --title "Add the thing" --body-file pr.md\n\nIn a host build, which holds an item key, the gateway opens the pull\nrequest as the factory\'s GitHub App, from the branch the claim named,\nor edits the one already open on that branch. No gh command runs.\nIn your own session it runs `gh pr create` (or `gh pr edit`) under your\nlogin, then declares the pull request on the item, as `work pr` does.\nRun it again after a change to the title or description.\n'
4480
4490
  ).action(async (opts) => {
4481
4491
  warnIfApiKeyFlag(opts);
4482
- const { runWorkOpenPr, WorkOpenPrCommandError } = await import('./work-open-pr-cmd-JEVD4HMQ.js');
4483
- const { WorkCommandError } = await import('./work-cmd-EQSW5DTD.js');
4492
+ const { runWorkOpenPr, WorkOpenPrCommandError } = await import('./work-open-pr-cmd-IOM4AVQQ.js');
4493
+ const { WorkCommandError } = await import('./work-cmd-Z2WXLZPH.js');
4484
4494
  try {
4485
4495
  await runWorkOpenPr(opts);
4486
4496
  } catch (err) {
@@ -4497,7 +4507,7 @@ function registerRunnerCommands(program2) {
4497
4507
  const configOption = "the cloud config file to run against (default: ~/.outerlayer/config.json)";
4498
4508
  runnerCmd.command("start").description("Run the loop: claim work, run it, report, clean up, repeat").option("--config <path>", configOption).action(async (opts) => {
4499
4509
  const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-N3C6DFQA.js');
4500
- const { start, RunnerStartError } = await import('./loop-QNSM5GXS.js');
4510
+ const { start, RunnerStartError } = await import('./loop-FK3LPMMZ.js');
4501
4511
  const { RunnerAlreadyRunningError } = await import('./pidfile-UZRH774M.js');
4502
4512
  const configPath = opts.config ?? defaultRunnerConfigPath();
4503
4513
  try {
@@ -4513,7 +4523,7 @@ function registerRunnerCommands(program2) {
4513
4523
  });
4514
4524
  runnerCmd.command("check").description("Validate the config, the hooks and the key, and print the effective settings").option("--config <path>", configOption).action(async (opts) => {
4515
4525
  const { defaultRunnerConfigPath } = await import('./config-N3C6DFQA.js');
4516
- const { runRunnerCheck } = await import('./check-2JSSXCKJ.js');
4526
+ const { runRunnerCheck } = await import('./check-5XE7XMC4.js');
4517
4527
  const configPath = opts.config ?? defaultRunnerConfigPath();
4518
4528
  const result = await runRunnerCheck(configPath);
4519
4529
  if (!result.ok) {
@@ -4542,7 +4552,7 @@ function registerRunnerCommands(program2) {
4542
4552
  }
4543
4553
  try {
4544
4554
  if (opts.service === true) {
4545
- const { installServiceCommand } = await import('./command-ETUAEXP2.js');
4555
+ const { installServiceCommand } = await import('./command-R2QCVX55.js');
4546
4556
  const result2 = await installServiceCommand({
4547
4557
  configPath,
4548
4558
  print: opts.print,
@@ -4598,22 +4608,22 @@ To keep it running, run ${C.yellow}outerlayer runner install --service${C.reset}
4598
4608
  return;
4599
4609
  }
4600
4610
  const { defaultRunnerConfigPath } = await import('./config-N3C6DFQA.js');
4601
- const { uninstallServiceCommand } = await import('./command-ETUAEXP2.js');
4611
+ const { uninstallServiceCommand } = await import('./command-R2QCVX55.js');
4602
4612
  const result = await uninstallServiceCommand({ configPath: opts.config ?? defaultRunnerConfigPath(), unitName: opts.unitName, home: homeFromEnv() });
4603
4613
  if (result.ok) for (const line of result.lines) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
4604
4614
  `);
4605
4615
  else fail(result.lines.length > 0 ? result.lines.join("\n ") : "the service was not removed");
4606
4616
  });
4607
- runnerCmd.command("init").description("Write a runner block that fits this machine; on macOS, offers a Linux VM").option("--config <path>", configOption).option("--vm", "on macOS, run the runner in a Linux VM (Lima), with container builds").option("--no-vm", "on macOS, skip the VM and run builds as unisolated processes").option("--allow-process-builds", "where builds cannot be isolated, run them as processes anyway").addOption(new Option("--config-stdin", "the VM-side hand-off: read the whole config as JSON on stdin").hideHelp()).option("--vm-cli-package <path>", "with --vm, install this packed CLI tarball in the VM").option("--unit-name <name>", "the service unit's name, to run a second runner beside the first").option("--agent <name>", "write commands that start this agent (claude); its credential comes on stdin").option("--app-id <id>", "factory id to create the runner key on, when it comes from your login").option("--key-name <name>", "name of the runner key created from your login (default: machine name)").addHelpText(
4617
+ runnerCmd.command("init").description("Write a runner block that fits this machine; on macOS, offers a Linux VM").option("--config <path>", configOption).option("--vm", "on macOS, run the runner in a Linux VM (Lima), with container builds").option("--no-vm", "on macOS, skip the VM and run builds as unisolated processes").option("--allow-process-builds", "where builds cannot be isolated, run them as processes anyway").addOption(new Option("--config-stdin", "the VM-side hand-off: read the whole config as JSON on stdin").hideHelp()).option("--vm-cli-package <path>", "with --vm, install this packed CLI tarball in the VM").option("--unit-name <name>", "the service unit's name, to run a second runner beside the first").option("--agent <name>", "write commands that start this agent (claude); its credential comes on stdin").option("--factory <org/factory>", "factory to create the runner key on, as <org>/<factory>").option("--app-id <id>", "factory id, instead of --factory (Settings \u2192 General)").addHelpText(
4608
4618
  "after",
4609
- "\nWith no apiKey in the config file, and a login saved by `outerlayer login`,\nrunner init creates the runner key itself, with the Runner preset, on the\nfactory --app-id names (or OUTERLAYER_APP_ID, or this repository's\nconnection). Your login needs factory_keys.insert on that factory.\n\nWith --agent claude, the queue commands start Claude Code instead of the\nplaceholder, and Claude's credential is read from stdin: a token from\n`claude setup-token` (sk-ant-oat...) or an API key (sk-ant-api...). It is\nnever printed, and is stored in the runner.env beside the config with mode\n600. Other lines in the file are kept. With nothing piped, a credential\nalready in runner.env is used.\n\n printf '%s' \"$CLAUDE_CODE_OAUTH_TOKEN\" | outerlayer runner init --agent claude\n"
4619
+ "\nWith no apiKey in the config file, and a login saved by `outerlayer login`,\nrunner init names the factory the runner is for: --factory, then --app-id,\nOUTERLAYER_APP_ID, or this repository's connection. With none of those, a\nlogin that can use one factory uses it, and one that can use several lists\nthem. It then prints the factory's API keys page, where you create a key with\nthe Runner preset, and asks you to paste it. Nothing is shown as you paste.\nWith no terminal to ask on, it stops and says what to put in the config file.\n\nWith --agent claude, the queue commands start Claude Code instead of the\nplaceholder, and Claude's credential is read from stdin: a token from\n`claude setup-token` (sk-ant-oat...) or an API key (sk-ant-api...). It is\nnever printed, and is stored in the runner.env beside the config with mode\n600. Other lines in the file are kept. With nothing piped, a credential\nalready in runner.env is used.\n\n printf '%s' \"$CLAUDE_CODE_OAUTH_TOKEN\" | outerlayer runner init --agent claude --factory <org>/<factory>\n"
4610
4620
  ).action(async (opts) => {
4611
4621
  const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-N3C6DFQA.js');
4612
- const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-OPB7HHXO.js');
4613
- const { createRunnerKey, runnerKeyLogin } = await import('./runner-key-7SSNMUBQ.js');
4614
- const { detectMachine } = await import('./machine-IT6GG7FF.js');
4615
- const { chooseVm, runVmInit, VmInitError } = await import('./init-MIC37V6J.js');
4616
- const { AGENT_COMMANDS, credentialFromStdin, isAgentName, restartForCredential, RunnerEnvError } = await import('./runner-env-XTC53CHN.js');
4622
+ const { prepareRunnerInit, runRunnerInit, RunnerInitError, writeRunnerInit } = await import('./init-6XPDRDTC.js');
4623
+ const { obtainRunnerKey, runnerKeyLogin } = await import('./runner-key-6SLBI7PP.js');
4624
+ const { detectMachine } = await import('./machine-SQXEBAM2.js');
4625
+ const { chooseVm, runVmInit, VmInitError } = await import('./init-PWU5YVL7.js');
4626
+ const { AGENT_COMMANDS, credentialFromStdin, isAgentName, restartForCredential, RunnerEnvError } = await import('./runner-env-EN7YE7QX.js');
4617
4627
  const configPath = opts.config ?? defaultRunnerConfigPath();
4618
4628
  if (opts.agent !== void 0 && !isAgentName(opts.agent)) {
4619
4629
  fail(`--agent ${opts.agent}: runner init writes commands for ${Object.keys(AGENT_COMMANDS).join(", ")}. For another agent, leave --agent out and edit runner.commands.`);
@@ -4637,8 +4647,8 @@ To keep it running, run ${C.yellow}outerlayer runner install --service${C.reset}
4637
4647
  }
4638
4648
  const machine = detectMachine();
4639
4649
  if (opts.configStdin === true) {
4640
- if (opts.appId !== void 0 || opts.keyName !== void 0) {
4641
- fail("the VM-side hand-off carries its runner key in its config on stdin; pass no --app-id or --key-name with it.");
4650
+ if (opts.appId !== void 0 || opts.factory !== void 0) {
4651
+ fail("the VM-side hand-off carries its runner key in its config on stdin; pass no --app-id or --factory with it.");
4642
4652
  return;
4643
4653
  }
4644
4654
  const chunks = [];
@@ -4653,14 +4663,13 @@ hooks: ${result2.hooks}
4653
4663
  `);
4654
4664
  return;
4655
4665
  }
4656
- const login = runnerKeyLogin(configPath, { appId: opts.appId });
4657
- if (login === void 0 && opts.keyName !== void 0) {
4658
- fail(
4659
- `--key-name names the runner key runner init creates from your login, and it creates none here: ${configPath} already has an apiKey, or no login is saved. Run \`outerlayer login\` first, or leave --key-name out.`
4660
- );
4661
- return;
4662
- }
4663
- const makeKey = login === void 0 ? void 0 : () => createRunnerKey(login, { name: opts.keyName });
4666
+ const login = await runnerKeyLogin(configPath, { appId: opts.appId, factory: opts.factory });
4667
+ if (login?.note !== void 0) process.stdout.write(`${login.note}
4668
+ `);
4669
+ const { terminalPrompt } = await import('./hidden-prompt-UXBFMQC5.js');
4670
+ const readKey = login === void 0 ? void 0 : terminalPrompt();
4671
+ if (login !== void 0 && readKey === void 0) await obtainRunnerKey(login, { configPath, readKey });
4672
+ const makeKey = login === void 0 ? void 0 : () => obtainRunnerKey(login, { configPath, readKey });
4664
4673
  let declinedVm = opts.vm === false;
4665
4674
  const useVm = await chooseVm({
4666
4675
  platform: machine.platform,
@@ -4695,6 +4704,8 @@ hooks: ${result2.hooks}
4695
4704
  `)
4696
4705
  });
4697
4706
  for (const line of result2.lines) process.stdout.write(`${C.green}\u2713${C.reset} ${line}
4707
+ `);
4708
+ for (const line of result2.warnings) process.stdout.write(`${C.yellow}!${C.reset} ${line}
4698
4709
  `);
4699
4710
  return;
4700
4711
  }
@@ -4705,7 +4716,7 @@ hooks: ${result2.hooks}
4705
4716
  const { ensureHostKey } = await import('./host-key-YMLXY6QB.js');
4706
4717
  const hostKey = await ensureHostKey(configPath);
4707
4718
  if (created !== void 0) {
4708
- process.stdout.write(`${C.green}\u2713${C.reset} created the runner key ${created.name} from your login, with the Runner preset, and saved it in ${result.configPath}
4719
+ process.stdout.write(`${C.green}\u2713${C.reset} saved the runner key in ${result.configPath}
4709
4720
  `);
4710
4721
  }
4711
4722
  process.stdout.write(`${C.green}\u2713${C.reset} wrote a runner block into ${result.configPath}
@@ -4762,7 +4773,7 @@ ${C.yellow}The runner will not update itself: ${installErr.message}${C.reset}
4762
4773
  let serviceUp = false;
4763
4774
  let restart;
4764
4775
  if (installedLayout) {
4765
- const { installServiceCommand } = await import('./command-ETUAEXP2.js');
4776
+ const { installServiceCommand } = await import('./command-R2QCVX55.js');
4766
4777
  const service = await installServiceCommand({
4767
4778
  configPath,
4768
4779
  entryPath: process.argv[1] ?? "",
@@ -4873,15 +4884,15 @@ Next:
4873
4884
  });
4874
4885
  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) => {
4875
4886
  const { defaultRunnerConfigPath } = await import('./config-N3C6DFQA.js');
4876
- const { requestStop } = await import('./loop-QNSM5GXS.js');
4887
+ const { requestStop } = await import('./loop-FK3LPMMZ.js');
4877
4888
  const configPath = opts.config ?? defaultRunnerConfigPath();
4878
4889
  await requestStop(configPath, Boolean(opts.now));
4879
4890
  });
4880
4891
  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) => {
4881
4892
  const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-N3C6DFQA.js');
4882
4893
  const { jobsDir, runnerDir } = await import('./paths-OYKMVYJP.js');
4883
- const { listJobFiles, runnerProcessState } = await import('./loop-QNSM5GXS.js');
4884
- const { renderStatus } = await import('./status-7ZX57OFJ.js');
4894
+ const { listJobFiles, runnerProcessState } = await import('./loop-FK3LPMMZ.js');
4895
+ const { renderStatus } = await import('./status-7VNQN5PW.js');
4885
4896
  const { readHousekeepingRecord } = await import('./record-C43U4PKS.js');
4886
4897
  const path2 = await import('path');
4887
4898
  const configPath = opts.config ?? defaultRunnerConfigPath();
@@ -4937,7 +4948,7 @@ Next:
4937
4948
  });
4938
4949
  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) => {
4939
4950
  const { defaultRunnerConfigPath } = await import('./config-N3C6DFQA.js');
4940
- const { listJobFiles } = await import('./loop-QNSM5GXS.js');
4951
+ const { listJobFiles } = await import('./loop-FK3LPMMZ.js');
4941
4952
  const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-H55NWW4H.js');
4942
4953
  const configPath = opts.config ?? defaultRunnerConfigPath();
4943
4954
  const item = parseTrackerNumber(itemArg);
@@ -5194,7 +5205,7 @@ function registerMcpCommands(program2) {
5194
5205
  function registerImportCommands(program2) {
5195
5206
  const importCmd = program2.command("import").description("Import an existing config format into .outerlayer/");
5196
5207
  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) => {
5197
- const { runImportRuler, ImportRulerError } = await import('./import-ruler-cmd-KLRGRBCP.js');
5208
+ const { runImportRuler, ImportRulerError } = await import('./import-ruler-cmd-BGAZXCQM.js');
5198
5209
  try {
5199
5210
  const result = runImportRuler({ cwd: opts.dir, json: opts.json });
5200
5211
  if (result.exitCode !== 0) process.exitCode = result.exitCode;
@@ -5208,9 +5219,9 @@ function registerImportCommands(program2) {
5208
5219
  });
5209
5220
  importCmd.command("capture").description("Install the maintained skills into .outerlayer/").option("--dir <path>", "repo root to write into (default: cwd)").option("--json", "machine-readable JSON output").addHelpText(
5210
5221
  "after",
5211
- "\nInstalls the four maintained skills (emitting-evidence, amend,\nreporting-findings, outerlayer) 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"
5222
+ "\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"
5212
5223
  ).action(async (opts) => {
5213
- const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-6QVCOIHK.js');
5224
+ const { runImportCapture, ImportCaptureError } = await import('./import-capture-cmd-EQ35EARA.js');
5214
5225
  try {
5215
5226
  runImportCapture({ cwd: opts.dir, json: opts.json });
5216
5227
  } catch (err) {
@@ -5248,12 +5259,12 @@ function registerContextCommands(program2) {
5248
5259
  const contextCmd = program2.command("context").description("Compile and materialize agent context");
5249
5260
  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(
5250
5261
  "after",
5251
- '\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 (emitting-evidence, amend, reporting-findings, outerlayer)\nfollow this CLI: emit rewrites one that differs from its bundle, and --check reports it as\ndrift. Templates (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'
5262
+ '\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'
5252
5263
  ).action(async (opts) => {
5253
5264
  await compileContext({ dir: opts.dir, check: opts.check, json: opts.json });
5254
5265
  });
5255
5266
  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) => {
5256
- const { runContextAdopt } = await import('./context-adopt-PJUMW2EZ.js');
5267
+ const { runContextAdopt } = await import('./context-adopt-NFHCLVUB.js');
5257
5268
  const { exitCode, stdout } = runContextAdopt(stagedDir, process.cwd());
5258
5269
  process.stdout.write(stdout);
5259
5270
  process.exitCode = exitCode;
@@ -5262,7 +5273,7 @@ function registerContextCommands(program2) {
5262
5273
  "after",
5263
5274
  "\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"
5264
5275
  ).action(async (opts) => {
5265
- const { materializeContext } = await import('./context-materialize-FDHYKNDT.js');
5276
+ const { materializeContext } = await import('./context-materialize-IV2TUUFO.js');
5266
5277
  const result = await materializeContext({ cwd: process.cwd(), sessionId: `manual-${Date.now()}` });
5267
5278
  const output = formatContextMaterializeOutput(result);
5268
5279
  if (output.exitCode !== void 0) process.exitCode = output.exitCode;
@@ -5,14 +5,14 @@ import { runRunnerInstall, launcherSummary, restartNote } from './chunk-ERI5GBNI
5
5
  import './chunk-I2UOAV7X.js';
6
6
  import './chunk-PTW6W5NR.js';
7
7
  import { currentLink, execStartCommand } from './chunk-TI7B7UEO.js';
8
- import { detectMachine } from './chunk-Z3NOIFDR.js';
9
- import './chunk-UUDDPNRJ.js';
8
+ import { detectMachine } from './chunk-ONKJUM6R.js';
9
+ import './chunk-MAK5LYRF.js';
10
10
  import './chunk-KMDLFI4P.js';
11
11
  import './chunk-QKFB4K7X.js';
12
12
  import './chunk-RSNSZ2LJ.js';
13
13
  import { installService, uninstallService, realTaskScheduler } from './chunk-RLYZLUQ7.js';
14
- import './chunk-JR6ERP3M.js';
15
- import './chunk-NPQWKGUA.js';
14
+ import './chunk-S3NYLI2P.js';
15
+ import './chunk-6Y5RUTHO.js';
16
16
  import './chunk-IP7BIBXJ.js';
17
17
  import { runnerVmOf, loadRunnerConfig } from './chunk-22RMZBGW.js';
18
18
  import './chunk-UXYLWVTQ.js';
@@ -26,20 +26,21 @@ import './chunk-4NPZVMJU.js';
26
26
  import './chunk-7RQ73DLO.js';
27
27
  import './chunk-4Q7OMKAT.js';
28
28
  import './chunk-CX22S5BA.js';
29
- import './chunk-YDSMROTB.js';
29
+ import './chunk-3NSNIIBE.js';
30
30
  import './chunk-WUYTWNMA.js';
31
31
  import './chunk-JXYVA45C.js';
32
32
  import './chunk-4KSQKQXE.js';
33
33
  import './chunk-N6LURUEF.js';
34
34
  import './chunk-YRYMNBGQ.js';
35
35
  import './chunk-WZBHBH3J.js';
36
- import './chunk-3NLOVYJQ.js';
37
- import './chunk-LCEXHCHD.js';
36
+ import './chunk-YZ5F4PIS.js';
37
+ import './chunk-WTE3MQML.js';
38
+ import './chunk-C5Y5ZJJZ.js';
38
39
  import './chunk-ZJSNLVCE.js';
39
40
  import './chunk-YO4PSLVB.js';
40
41
  import './chunk-BYT5O5RV.js';
41
- import './chunk-ZA5CHAFY.js';
42
- import './chunk-2M63GG56.js';
42
+ import './chunk-POJMEEJJ.js';
43
+ import './chunk-OHVJA253.js';
43
44
  import './chunk-PLMTLGYH.js';
44
45
  import './chunk-J5M7BSJQ.js';
45
46
  import './chunk-EABW6AJQ.js';