@outerlayer/cli 0.1.0 → 0.2.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 (33) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +15 -21
  3. package/dist/build-info.json +1 -1
  4. package/dist/{chunk-DEDV5V4U.js → chunk-4TNZMO7V.js} +1874 -3191
  5. package/dist/{chunk-RCQXYLMO.js → chunk-65WXAANR.js} +2 -17
  6. package/dist/{chunk-4H56Y7O6.js → chunk-DCNOXRMV.js} +1 -1
  7. package/dist/{chunk-IWIUYLDR.js → chunk-I3ETLSNE.js} +7 -187
  8. package/dist/{chunk-XN2XZFTK.js → chunk-NTTPJV35.js} +1 -1
  9. package/dist/{chunk-A6NNKRJU.js → chunk-NXLLURA4.js} +4 -4
  10. package/dist/{chunk-VU34RWDU.js → chunk-Q6CL5THG.js} +3 -2
  11. package/dist/{chunk-ECSYRPCC.js → chunk-R5KBGVII.js} +50 -4
  12. package/dist/chunk-U32VSRLO.js +2225 -0
  13. package/dist/chunk-WZBHBH3J.js +20 -0
  14. package/dist/{chunk-YMTXR7PJ.js → chunk-YOOSBOKS.js} +1 -1
  15. package/dist/{cli-3JYGL2OB.js → cli-G7DILYJY.js} +127 -138
  16. package/dist/{context-materialize-J6CRQ7O7.js → context-materialize-6WKT3RBQ.js} +1 -1
  17. package/dist/{emit-artifact-cmd-23F4YKQ3.js → emit-artifact-cmd-UQVT3OKW.js} +8 -6
  18. package/dist/{emit-finding-cmd-6K7ERPKG.js → emit-finding-cmd-FDOU2OPD.js} +8 -6
  19. package/dist/{emit-result-cmd-NDFHMJX7.js → emit-result-cmd-H2T4C2K3.js} +8 -6
  20. package/dist/{hook-fast-CBW4ZETX.js → hook-fast-J5LCDHUJ.js} +2 -2
  21. package/dist/{hook-wrap-fast-36WGE6EX.js → hook-wrap-fast-KXYNX3AD.js} +2 -2
  22. package/dist/index.js +4 -4
  23. package/dist/{loop-NFSOBUUJ.js → loop-ASZRX3CZ.js} +12 -10
  24. package/dist/{status-WGOJTXZF.js → status-I27IST4L.js} +10 -8
  25. package/dist/{statusline-fast-Z5U5CEC6.js → statusline-fast-3C5OXHDD.js} +2 -2
  26. package/dist/{sync-cmd-C5UGI4SF.js → sync-cmd-BBAUZ5JD.js} +8 -6
  27. package/dist/{watch-V3K4PESQ.js → watch-3DTPJETH.js} +8 -6
  28. package/dist/{work-claim-cmd-FQDWQVT2.js → work-claim-cmd-5AUNCLS2.js} +10 -8
  29. package/dist/{work-cmd-CW26EZZO.js → work-cmd-2P4BVX47.js} +9 -7
  30. package/dist/{work-launch-YNNCKIH3.js → work-launch-LT663PB3.js} +2 -1
  31. package/dist/{work-pr-cmd-W2QNMWXP.js → work-pr-cmd-AZQPWH4H.js} +8 -6
  32. package/package.json +1 -1
  33. package/dist/emit-commit-credit-cmd-2GX5M2BR.js +0 -121
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+
4
+ createRequire(import.meta.url);
5
+
6
+ // src/tracker-number.ts
7
+ var MAX_TRACKER_NUMBER = Number.MAX_SAFE_INTEGER;
8
+ function parseTrackerNumber(raw) {
9
+ if (raw === void 0) return void 0;
10
+ const text = typeof raw === "number" ? String(raw) : raw;
11
+ if (!/^\d+$/.test(text)) return void 0;
12
+ const n = Number(text);
13
+ if (!Number.isSafeInteger(n) || n <= 0) return void 0;
14
+ return n;
15
+ }
16
+ function trackerNumberError(flag, raw) {
17
+ return `invalid ${flag} "${raw}" \u2014 expected a positive integer no larger than ${MAX_TRACKER_NUMBER}`;
18
+ }
19
+
20
+ export { parseTrackerNumber, trackerNumberError };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { decodeWrappedCommand } from './chunk-ECSYRPCC.js';
3
+ import { decodeWrappedCommand } from './chunk-R5KBGVII.js';
4
4
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
5
5
  import { readFileSync, mkdirSync, appendFileSync, writeFileSync } from 'fs';
6
6
  import { spawn } from 'child_process';
@@ -2,22 +2,20 @@
2
2
  import { createRequire } from 'node:module';
3
3
  import { pinExists, readPin, readContextManifest, readDegraded, readSourceCache } from './chunk-A3WLZX2F.js';
4
4
  import './chunk-KFYJV2ZG.js';
5
- import { readStatuslineState, STATE_FRESH_MS } from './chunk-XN2XZFTK.js';
6
- import { compareVersions, SUPPORTED_VERSIONS, readSessionRepos } from './chunk-DEDV5V4U.js';
5
+ import { readStatuslineState, STATE_FRESH_MS } from './chunk-NTTPJV35.js';
6
+ import { compareVersions, SUPPORTED_VERSIONS } from './chunk-4TNZMO7V.js';
7
7
  import { C, NO_COLOR_FLAG, warnDeprecated, stripNoColor, API_KEY_FLAG_DEPRECATION } from './chunk-YRYMNBGQ.js';
8
- import { parseTrackerNumber, trackerNumberError } from './chunk-RCQXYLMO.js';
9
- import './chunk-ZJSNLVCE.js';
10
- import { hookFiredMarkerPath, sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, refreshCommand } from './chunk-A6NNKRJU.js';
11
- import { managedHookScripts, installPostRewriteHook, installPreCommitGuardHook, removePostRewriteHook, removePreCommitGuardHook, deadHooksState, preparePackageManagerCommand, contextExcludesPresent, postRewriteHookPresence } from './chunk-IWIUYLDR.js';
12
- import './chunk-YMTXR7PJ.js';
13
- import { SettingsParseError, settingsPath, readSettings, listHookCandidates, wrapHooks, writeSettings, unwrapHooks, REGISTERED_EVENTS, removeHooks, removeStatusline, cliBinResolvable, mergeHooks, AUTO_WRAP_EVENTS, mergeStatusline, isOurStatuslineSlot, statuslineWrappedOriginal, isOurHookCommand, wrappedOriginalCommand } from './chunk-ECSYRPCC.js';
8
+ import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
9
+ import { hookFiredMarkerPath, installedCliDistDir, sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, refreshCommand } from './chunk-NXLLURA4.js';
10
+ import { managedHookScripts, removeJournalHooks, installPreCommitGuardHook, removePreCommitGuardHook, deadHooksState, preparePackageManagerCommand, contextExcludesPresent } from './chunk-I3ETLSNE.js';
11
+ import { SettingsParseError, settingsPath, readSettings, listHookCandidates, wrapHooks, writeSettings, unwrapHooks, REGISTERED_EVENTS, removeHooks, removeStatusline, cliBinResolvable, mergeHooks, repointWrappedHooks, AUTO_WRAP_EVENTS, mergeStatusline, isOurStatuslineSlot, statuslineWrappedOriginal, isOurHookCommand, ourCommandBins, wrappedOriginalCommand } from './chunk-R5KBGVII.js';
14
12
  import { readCloudConfig } from './chunk-TFUIDMOB.js';
15
13
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
16
14
  import './chunk-Z5GEFMRW.js';
17
15
  import { EventEmitter } from 'events';
18
16
  import childProcess, { execFileSync } from 'child_process';
19
- import path, { dirname, join } from 'path';
20
- import fs, { unlinkSync, existsSync, readFileSync, writeFileSync, accessSync, constants, statSync, readdirSync, mkdirSync, renameSync } from 'fs';
17
+ import path, { dirname, join, isAbsolute } from 'path';
18
+ import fs, { existsSync, unlinkSync, readFileSync, mkdirSync, cpSync, readdirSync, renameSync, statSync, rmSync, writeFileSync, accessSync, constants, realpathSync } from 'fs';
21
19
  import process2 from 'process';
22
20
  import { stripVTControlCharacters } from 'util';
23
21
  import { fileURLToPath } from 'url';
@@ -3380,6 +3378,52 @@ function useColor() {
3380
3378
 
3381
3379
  // ../../node_modules/commander/index.js
3382
3380
  new Command();
3381
+ function isEphemeralBin(bin) {
3382
+ return bin.replace(/\\/g, "/").split("/").some((p) => p === "_npx" || p === "dlx" || p.startsWith("dlx-") || p.startsWith("bunx-"));
3383
+ }
3384
+ function initHookBin(opts) {
3385
+ const { runningBin } = opts;
3386
+ if (opts.remove || !isAbsolute(runningBin) || !isEphemeralBin(runningBin) || !existsSync(runningBin)) return runningBin;
3387
+ return installCliCopy({ home: opts.home, sourceBin: runningBin }).bin;
3388
+ }
3389
+ var STALE_FILE_MS = 7 * 24 * 60 * 60 * 1e3;
3390
+ function samePath(a, b) {
3391
+ try {
3392
+ return realpathSync(a) === realpathSync(b);
3393
+ } catch {
3394
+ return false;
3395
+ }
3396
+ }
3397
+ function installCliCopy(opts) {
3398
+ const rename = opts.rename ?? renameSync;
3399
+ const now = opts.now ?? Date.now;
3400
+ const targetDist = installedCliDistDir(opts.home);
3401
+ const targetRoot = dirname(targetDist);
3402
+ const bin = join(targetDist, "index.js");
3403
+ const sourceDist = dirname(opts.sourceBin);
3404
+ if (samePath(sourceDist, targetDist)) return { bin, copied: false };
3405
+ mkdirSync(targetDist, { recursive: true });
3406
+ const staged = join(targetRoot, `.staging-${process.pid}-${now()}`);
3407
+ try {
3408
+ cpSync(sourceDist, join(staged, "dist"), { recursive: true });
3409
+ const sourcePkg = join(dirname(sourceDist), "package.json");
3410
+ if (existsSync(sourcePkg)) cpSync(sourcePkg, join(staged, "package.json"));
3411
+ const incoming = readdirSync(join(staged, "dist"));
3412
+ for (const name of incoming) {
3413
+ if (name !== "index.js") rename(join(staged, "dist", name), join(targetDist, name));
3414
+ }
3415
+ if (existsSync(join(staged, "package.json"))) rename(join(staged, "package.json"), join(targetRoot, "package.json"));
3416
+ rename(join(staged, "dist", "index.js"), bin);
3417
+ const shipped = new Set(incoming);
3418
+ for (const name of readdirSync(targetDist)) {
3419
+ const path2 = join(targetDist, name);
3420
+ if (!shipped.has(name) && now() - statSync(path2).mtimeMs > STALE_FILE_MS) rmSync(path2, { recursive: true, force: true });
3421
+ }
3422
+ } finally {
3423
+ rmSync(staged, { recursive: true, force: true });
3424
+ }
3425
+ return { bin, copied: true };
3426
+ }
3383
3427
  function manifestPath(home = homeFromEnv()) {
3384
3428
  return join(home, ".outerlayer", "hooks-manifest.json");
3385
3429
  }
@@ -3481,7 +3525,7 @@ function runInit(opts) {
3481
3525
  const statuslineRemoved = removeStatusline(hooksUnwrapped.next, opts.cliBin);
3482
3526
  const changed2 = hooksRemoved.changed || hooksUnwrapped.changed || statuslineRemoved.changed;
3483
3527
  const backupPath2 = changed2 ? writeSettings(path2, statuslineRemoved.next) : void 0;
3484
- const gitHookRemoval = removePostRewriteHook(opts.cwd ?? process.cwd());
3528
+ const gitHookRemoval2 = removeJournalHooks(opts.cwd ?? process.cwd());
3485
3529
  const guardHookRemoval = removePreCommitGuardHook(opts.cwd ?? process.cwd());
3486
3530
  recordRemoval(manifestHome, path2);
3487
3531
  const remaining = readManifest(manifestHome);
@@ -3499,7 +3543,7 @@ function runInit(opts) {
3499
3543
  backupPath: backupPath2,
3500
3544
  events: REGISTERED_EVENTS,
3501
3545
  removed: true,
3502
- gitHookRemoved: gitHookRemoval.removed,
3546
+ gitHookRemoved: gitHookRemoval2.removed,
3503
3547
  guardHookRemoved: guardHookRemoval.removed,
3504
3548
  wrapped: [],
3505
3549
  unwrappedCount: hooksUnwrapped.unwrapped,
@@ -3510,8 +3554,9 @@ function runInit(opts) {
3510
3554
  return { path: path2, changed: false, events: REGISTERED_EVENTS, wrapped: [], cliBinUnresolved: true };
3511
3555
  }
3512
3556
  const merged = mergeHooks(current, opts.cliBin);
3513
- let next = merged.next;
3514
- let changed = merged.changed;
3557
+ const repointed = repointWrappedHooks(merged.next, opts.cliBin);
3558
+ let next = repointed.next;
3559
+ let changed = merged.changed || repointed.changed;
3515
3560
  let wrapped = [];
3516
3561
  if (opts.wrapHooks ?? true) {
3517
3562
  const wrapResult = wrapHooks(next, opts.cliBin, { events: [...AUTO_WRAP_EVENTS] });
@@ -3538,9 +3583,7 @@ function runInit(opts) {
3538
3583
  if (statusline && statusline !== "skipped") {
3539
3584
  recordStatusline(manifestHome, path2, statuslineWrappedCommand !== void 0 ? "wrapped" : "installed", statuslineWrappedCommand);
3540
3585
  }
3541
- const gitHook = installPostRewriteHook(opts.cwd ?? process.cwd(), {
3542
- stampTrailers: readCloudConfig().gitHooks?.stampTrailers !== false
3543
- });
3586
+ const gitHookRemoval = removeJournalHooks(opts.cwd ?? process.cwd());
3544
3587
  const guardHook = installPreCommitGuardHook(opts.cwd ?? process.cwd());
3545
3588
  let gitignoreUpdated = false;
3546
3589
  if (scope === "project" && opts.addGitignore) {
@@ -3552,7 +3595,7 @@ function runInit(opts) {
3552
3595
  backupPath,
3553
3596
  events: REGISTERED_EVENTS,
3554
3597
  gitignoreUpdated,
3555
- gitHook,
3598
+ ...gitHookRemoval.removed ? { gitHookRemoved: true } : {},
3556
3599
  guardHook,
3557
3600
  wrapped,
3558
3601
  ...statusline ? { statusline } : {},
@@ -3799,48 +3842,8 @@ function checkHooks(home, cwd, transcripts, now) {
3799
3842
  if (firing) checks.push(firing);
3800
3843
  const wrapped = checkWrappedHooks(home, cwd);
3801
3844
  if (wrapped) checks.push(wrapped);
3802
- const journal = checkJournalHookCoverage(home);
3803
- if (journal) checks.push(journal);
3804
3845
  return checks;
3805
3846
  }
3806
- function checkJournalHookCoverage(home) {
3807
- const name = "Rewrite journal hooks";
3808
- const repos = readSessionRepos(home).filter((r) => existsSync(r.repoRoot));
3809
- if (repos.length === 0) return null;
3810
- let ours = 0;
3811
- let managed = 0;
3812
- let foreign = 0;
3813
- const absentRepos = [];
3814
- for (const r of repos) {
3815
- switch (postRewriteHookPresence(r.repoRoot)) {
3816
- case "ours":
3817
- ours += 1;
3818
- break;
3819
- case "custom-hooks-path":
3820
- managed += 1;
3821
- break;
3822
- case "foreign":
3823
- foreign += 1;
3824
- break;
3825
- case "absent":
3826
- absentRepos.push(r.gitRepo || r.repoRoot);
3827
- break;
3828
- }
3829
- }
3830
- const parts = [`${ours}/${repos.length} synced repos covered`];
3831
- if (managed > 0) parts.push(`${managed} hook-managed (README has the snippet)`);
3832
- if (foreign > 0) parts.push(`${foreign} foreign hook`);
3833
- if (absentRepos.length > 0) {
3834
- const sample = absentRepos.slice(0, 3).join(", ") + (absentRepos.length > 3 ? ", \u2026" : "");
3835
- return {
3836
- name,
3837
- status: "warn",
3838
- detail: `${parts.join(", ")} \u2014 ${absentRepos.length} without rewrite journaling: ${sample}`,
3839
- fix: 'Run `outerlayer hooks install-git` in each repo, or set {"gitHooks":{"autoInstall":true}} in ~/.outerlayer/config.json.'
3840
- };
3841
- }
3842
- return { name, status: "pass", detail: parts.join(", ") };
3843
- }
3844
3847
  function checkHooksInstalled(home, cwd, firingFresh) {
3845
3848
  const name = "Hooks installed";
3846
3849
  const readablePaths = [];
@@ -3858,6 +3861,15 @@ function checkHooksInstalled(home, cwd, firingFresh) {
3858
3861
  (event) => (settings.hooks?.[event] ?? []).some((b) => (b.hooks ?? []).some(isOurHookCommand))
3859
3862
  );
3860
3863
  if (installed.length === REGISTERED_EVENTS.length) {
3864
+ const missing = ourCommandBins(settings).filter((bin) => !cliBinResolvable(bin));
3865
+ if (missing.length > 0) {
3866
+ return {
3867
+ name,
3868
+ status: "fail",
3869
+ detail: `hooks in ${path2} run ${missing.join(", ")}, which no longer exists \u2014 no session is being captured`,
3870
+ fix: "Run `npx @outerlayer/cli init` to reinstall."
3871
+ };
3872
+ }
3861
3873
  return { name, status: "pass", detail: `${installed.join(", ")} (${scope})` };
3862
3874
  }
3863
3875
  if (installed.length > 0) {
@@ -4346,9 +4358,15 @@ function formatGuardInstallOutput(guard) {
4346
4358
  if (guard.adopted) {
4347
4359
  return { lines: [`${C.green}\u2713${C.reset} materialized-context commit guard hand-adopted at ${guard.path} (core.hooksPath) \u2014 left untouched.`] };
4348
4360
  }
4349
- return { lines: [] };
4361
+ return {
4362
+ lines: [
4363
+ `${C.yellow}!${C.reset} this repo manages hooks in its working tree (core.hooksPath) \u2014 nothing written.`,
4364
+ ` Add the script to your hook manager instead: ${C.yellow}outerlayer hooks install-git --print${C.reset}`
4365
+ ],
4366
+ exitCode: 1
4367
+ };
4350
4368
  case "not-a-repo":
4351
- return { lines: [] };
4369
+ return { lines: [], error: "not inside a git repository." };
4352
4370
  }
4353
4371
  }
4354
4372
  function invokedCommandToken(argv) {
@@ -4361,12 +4379,21 @@ function buildProgram(argv = process.argv) {
4361
4379
  "after",
4362
4380
  "\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"
4363
4381
  ).action((opts) => {
4364
- const cliBin = resolveCliBin();
4382
+ let cliBin = resolveCliBin();
4365
4383
  if (opts.org) {
4366
4384
  process.stdout.write(orgRolloutSnippet(cliBin) + "\n");
4367
4385
  return;
4368
4386
  }
4369
4387
  const scope = opts.project ? "project" : "user";
4388
+ try {
4389
+ cliBin = initHookBin({ home: homeFromEnv(), runningBin: cliBin, remove: opts.remove === true });
4390
+ } catch (err) {
4391
+ fail(
4392
+ `could not copy the CLI to ~/.outerlayer/cli: ${err instanceof Error ? err.message : String(err)}
4393
+ Hooks were not changed. Fix the permissions on ~/.outerlayer, then re-run ${C.yellow}outerlayer init${C.reset}.`
4394
+ );
4395
+ return;
4396
+ }
4370
4397
  try {
4371
4398
  const result = runInit({
4372
4399
  scope,
@@ -4445,7 +4472,7 @@ ${fails === 0 ? `${C.green}\u2713${C.reset}` : `${C.red}\u2717${C.reset}`} ${pas
4445
4472
  "\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"
4446
4473
  ).action(async (opts) => {
4447
4474
  warnIfApiKeyFlag(opts);
4448
- const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-C5UGI4SF.js');
4475
+ const { runSync, SyncConfigError, SyncTransportError } = await import('./sync-cmd-BBAUZ5JD.js');
4449
4476
  try {
4450
4477
  const result = await runSync({
4451
4478
  url: opts.url,
@@ -4474,7 +4501,7 @@ ${fails === 0 ? `${C.green}\u2713${C.reset}` : `${C.red}\u2717${C.reset}`} ${pas
4474
4501
  if (invokedCommandToken(argv) === "watch") {
4475
4502
  warnDeprecated("`outerlayer watch` is now `outerlayer daemon`; the old name will be removed in a future release.");
4476
4503
  }
4477
- const { runWatch } = await import('./watch-V3K4PESQ.js');
4504
+ const { runWatch } = await import('./watch-3DTPJETH.js');
4478
4505
  await runWatch({ once: opts.once });
4479
4506
  });
4480
4507
  program2.command("hook <event>", { hidden: true }).description("capture-hook fast path, installed by `init`").action(() => {
@@ -4513,7 +4540,7 @@ async function compileContext(opts) {
4513
4540
  function registerEmitCommands(program2) {
4514
4541
  const emitCmd = program2.command("emit").enablePositionalOptions().description("Record evidence for a work item: a named check result").argument("[name]", "the check name a validator declares (e.g. smoke.pass)").option("--link <url>", "proof link, usually the CI run URL").option("--body <text>", "one sentence recording your judgment").option("--body-file <path>", "read the sentence from a file; - reads standard input").option("--result <pass|fail>", "check outcome (default: pass)").option("--item <number>", "work item to record on directly, by its number in this factory").option("--artifact <id>", "artifact this verdict is on \u2014 only with the artifact-review check name").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "app id the key is bound to (or OUTERLAYER_APP_ID / config)").addOption(new Option("--check", "deprecated: use `context emit --check`").hideHelp()).addOption(new Option("--dir <path>", "deprecated: use `context emit --dir`").hideHelp()).addHelpText(
4515
4542
  "after",
4516
- '\n outerlayer emit smoke.pass --item 412 --link https://ci.example.com/run/42\n outerlayer emit code-review --result fail --item 412 --body "The button should be red."\n outerlayer emit artifact-review --result fail --artifact a1b2c3d4 --body "Wrong state."\n\nRecords that a named check passed or failed, anchored to a work item.\n--item is always required, in or out of a recorded session \u2014 there is no\nsession fallback. A check that ran carries the run URL as proof (--link);\na judgment you are making yourself carries one sentence (--body, or\n--body-file to read it from a file or standard input). A fail needs at\nleast one of the two. Run from inside a session, --item can only name a\nwork item that session was NOT launched for \u2014 a session cannot record a\ncheck on its own item. With nothing to attach it to, the command refuses.\n\nWho recorded a check is decided by your API key, never by what you send:\na key bound to your membership records it as yours, and nothing automated\ncan then clear it.\n\nThe check name `artifact-review` is a different act: a person\'s own pass\nor fail on one artifact, named with --artifact instead of --item, refused\nfrom inside a recorded session \u2014 an artifact verdict is a person\'s act.\n--link is refused in this mode; a fail needs --body / --body-file.\n\nSubcommands: `emit artifact <file>` for screenshots, recordings, reports and\nlogs; `emit commit-credit` to attest a commit belongs to a pull request;\n`emit finding` / `emit findings <file>` to record what was found wrong about\nthe change or about a rule.\nCompiling .outerlayer/ moved to `outerlayer context emit`.\n'
4543
+ '\n outerlayer emit smoke.pass --item 412 --link https://ci.example.com/run/42\n outerlayer emit code-review --result fail --item 412 --body "The button should be red."\n outerlayer emit artifact-review --result fail --artifact a1b2c3d4 --body "Wrong state."\n\nRecords that a named check passed or failed, anchored to a work item.\n--item is always required, in or out of a recorded session \u2014 there is no\nsession fallback. A check that ran carries the run URL as proof (--link);\na judgment you are making yourself carries one sentence (--body, or\n--body-file to read it from a file or standard input). A fail needs at\nleast one of the two. Run from inside a session, --item can only name a\nwork item that session was NOT launched for \u2014 a session cannot record a\ncheck on its own item. With nothing to attach it to, the command refuses.\n\nWho recorded a check is decided by your API key, never by what you send:\na key bound to your membership records it as yours, and nothing automated\ncan then clear it.\n\nThe check name `artifact-review` is a different act: a person\'s own pass\nor fail on one artifact, named with --artifact instead of --item, refused\nfrom inside a recorded session \u2014 an artifact verdict is a person\'s act.\n--link is refused in this mode; a fail needs --body / --body-file.\n\nSubcommands: `emit artifact <file>` for screenshots, recordings, reports and\nlogs; `emit finding` / `emit findings <file>` to record what was found wrong\nabout the change or about a rule.\nCompiling .outerlayer/ moved to `outerlayer context emit`.\n'
4517
4544
  ).action(async (name, opts) => {
4518
4545
  if (name === void 0) {
4519
4546
  warnDeprecated("`outerlayer emit` with no name now lives at `outerlayer context emit`; the bare form will be removed in a future release.");
@@ -4521,7 +4548,7 @@ function registerEmitCommands(program2) {
4521
4548
  return;
4522
4549
  }
4523
4550
  warnIfApiKeyFlag(opts);
4524
- const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-NDFHMJX7.js');
4551
+ const { runEmitResult, EmitResultError } = await import('./emit-result-cmd-H2T4C2K3.js');
4525
4552
  try {
4526
4553
  const result = await runEmitResult({
4527
4554
  name,
@@ -4550,7 +4577,7 @@ function registerEmitCommands(program2) {
4550
4577
  '\n outerlayer emit artifact shot.png --caption "the dot row, current dot marked" --for LOGIN-01\n\nInside a recorded Claude Code session the artifact spools locally and ships,\nbound to that session, on the next `outerlayer sync` \u2014 but only if that\nsession was launched with OUTERLAYER_WORK; without it nothing the session\nproduces may leave the machine, and the command refuses rather than queue an\nartifact that can never ship. Otherwise it uploads immediately, anchored to a\npull request (--pr, or CI\'s PR context) or to the current git checkout. With\nnothing to attach it to, the command refuses.\n\n--replaces: an already-uploaded target is marked superseded and hidden\neverywhere, bytes and deep link untouched; a still-queued one is cancelled\nlocally so it never uploads. One correction can retire several duplicates.\n'
4551
4578
  ).action(async (file, opts) => {
4552
4579
  warnIfApiKeyFlag(opts);
4553
- const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-23F4YKQ3.js');
4580
+ const { runEmitArtifact, EmitArtifactError } = await import('./emit-artifact-cmd-UQVT3OKW.js');
4554
4581
  let pr;
4555
4582
  if (opts.pr !== void 0) {
4556
4583
  pr = parseTrackerNumber(opts.pr);
@@ -4584,7 +4611,7 @@ function registerEmitCommands(program2) {
4584
4611
  '\n outerlayer emit finding --id r1-f1 --subject change --title "Off-by-one" \\\n --file src/loop.ts --line 42 --severity major --kind behavior \\\n --verdict confirmed --source reviewer --where "review pass 1"\n\nRecords one finding \u2014 what an agent noticed was wrong about the change, or\nabout a rule it ran on. Validated against the same contract the gateway\nchecks before anything is sent; a subject of context needs --rule-path,\n--rule-quote and --rule-relation together \u2014 all three are required, not\njust --rule-path.\n--item names the work item; without it, inside a recorded session, the\nitem that session was launched for is used automatically \u2014 a session may\nrecord findings on its own item, unlike `outerlayer emit <name>`.\n'
4585
4612
  ).action(async (opts) => {
4586
4613
  warnIfApiKeyFlag(opts);
4587
- const { runEmitFinding, EmitFindingError } = await import('./emit-finding-cmd-6K7ERPKG.js');
4614
+ const { runEmitFinding, EmitFindingError } = await import('./emit-finding-cmd-FDOU2OPD.js');
4588
4615
  try {
4589
4616
  const result = await runEmitFinding({
4590
4617
  id: opts.id,
@@ -4627,7 +4654,7 @@ function registerEmitCommands(program2) {
4627
4654
  "\n outerlayer emit findings review.json --item 412\n\nRecords a whole batch at once \u2014 a FindingBatch JSON file (schemaVersion,\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.\n--item names the work item; without it, inside a recorded session, the item\nthat session was launched for is used automatically.\n"
4628
4655
  ).action(async (file, opts) => {
4629
4656
  warnIfApiKeyFlag(opts);
4630
- const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-6K7ERPKG.js');
4657
+ const { runEmitFindings, EmitFindingError } = await import('./emit-finding-cmd-FDOU2OPD.js');
4631
4658
  try {
4632
4659
  const result = await runEmitFindings({
4633
4660
  file,
@@ -4646,29 +4673,6 @@ function registerEmitCommands(program2) {
4646
4673
  throw err;
4647
4674
  }
4648
4675
  });
4649
- emitCmd.command("commit-credit").description("Attest that a commit belongs to a pull request").requiredOption("--sha <sha>", "full 40-character hex commit SHA").requiredOption("--pr <number>", "pull request number to anchor to").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "app id the key is bound to (or OUTERLAYER_APP_ID / config)").addHelpText(
4650
- "after",
4651
- '\nThe escape hatch for a checkout, and reflog, that no longer exists. Records\none explicit human attestation, uploaded immediately \u2014 no session detection,\nno spool. The attesting identity is the dashboard member the control plane\nresolves from the API key; it renders as "attested by <name>" in the PR\nevidence comment, distinct from recorded or recovered credit. Refused, with\nnothing stored, for a malformed SHA, an unknown PR, or a machine key with no\nmember to attest as.\n'
4652
- ).action(async (opts) => {
4653
- warnIfApiKeyFlag(opts);
4654
- const { runEmitCommitCredit, EmitCommitCreditError } = await import('./emit-commit-credit-cmd-2GX5M2BR.js');
4655
- try {
4656
- await runEmitCommitCredit({
4657
- sha: opts.sha,
4658
- pr: opts.pr,
4659
- json: opts.json,
4660
- url: opts.url,
4661
- apiKey: opts.apiKey,
4662
- appId: opts.appId
4663
- });
4664
- } catch (err) {
4665
- if (err instanceof EmitCommitCreditError) {
4666
- fail(err.message);
4667
- return;
4668
- }
4669
- throw err;
4670
- }
4671
- });
4672
4676
  }
4673
4677
  function registerWorkCommands(program2) {
4674
4678
  const workCmd = program2.command("work").description("Add, remove, or read what the factory is working on (the Floor)");
@@ -4677,7 +4681,7 @@ function registerWorkCommands(program2) {
4677
4681
  "\n outerlayer work add --issue 42\n\nRecords that a named source \u2014 a recorded session, a CI run, or the API\nkey's bound member \u2014 is working on an issue or pull request. This is\nthe only way an item becomes visible on the Floor. A second add of the\nsame subject by the same source is a no-op.\n"
4678
4682
  ).action(async (opts) => {
4679
4683
  warnIfApiKeyFlag(opts);
4680
- const { runWorkAdd, WorkCommandError } = await import('./work-cmd-CW26EZZO.js');
4684
+ const { runWorkAdd, WorkCommandError } = await import('./work-cmd-2P4BVX47.js');
4681
4685
  try {
4682
4686
  await runWorkAdd(opts);
4683
4687
  } catch (err) {
@@ -4693,7 +4697,7 @@ function registerWorkCommands(program2) {
4693
4697
  "\n outerlayer work link-session 42\n\nNames an item that already exists on the calling session \u2014 it never\ncreates one. Create an item first with `outerlayer work add`. Linking\nthe same session to the same item twice is a no-op.\n"
4694
4698
  ).action(async (number, opts) => {
4695
4699
  warnIfApiKeyFlag(opts);
4696
- const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-CW26EZZO.js');
4700
+ const { runWorkLinkSession, WorkCommandError } = await import('./work-cmd-2P4BVX47.js');
4697
4701
  try {
4698
4702
  await runWorkLinkSession({ ...opts, number });
4699
4703
  } catch (err) {
@@ -4715,7 +4719,7 @@ live addition remains on it.
4715
4719
  `
4716
4720
  ).action(async (opts) => {
4717
4721
  warnIfApiKeyFlag(opts);
4718
- const { runWorkRemove, WorkCommandError } = await import('./work-cmd-CW26EZZO.js');
4722
+ const { runWorkRemove, WorkCommandError } = await import('./work-cmd-2P4BVX47.js');
4719
4723
  try {
4720
4724
  await runWorkRemove(opts);
4721
4725
  } catch (err) {
@@ -4728,7 +4732,7 @@ live addition remains on it.
4728
4732
  });
4729
4733
  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>", "app id the key is bound to (or OUTERLAYER_APP_ID / config)").action(async (opts) => {
4730
4734
  warnIfApiKeyFlag(opts);
4731
- const { runWorkStatus, WorkCommandError } = await import('./work-cmd-CW26EZZO.js');
4735
+ const { runWorkStatus, WorkCommandError } = await import('./work-cmd-2P4BVX47.js');
4732
4736
  try {
4733
4737
  await runWorkStatus(opts);
4734
4738
  } catch (err) {
@@ -4741,7 +4745,7 @@ live addition remains on it.
4741
4745
  });
4742
4746
  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 claim").option("--startable", "only items with no live claim, linked session, or linked pull request").option("--needs <amend>", "only items an open artifact fail is waiting on").option("--json", "machine-readable JSON output").option("--url <url>", "cloud base URL (or OUTERLAYER_URL / config)").addOption(apiKeyOption()).option("--app-id <id>", "app id the key is bound to (or OUTERLAYER_APP_ID / config)").action(async (opts) => {
4743
4747
  warnIfApiKeyFlag(opts);
4744
- const { runWorkList, WorkCommandError } = await import('./work-cmd-CW26EZZO.js');
4748
+ const { runWorkList, WorkCommandError } = await import('./work-cmd-2P4BVX47.js');
4745
4749
  try {
4746
4750
  await runWorkList(opts);
4747
4751
  } catch (err) {
@@ -4757,7 +4761,7 @@ live addition remains on it.
4757
4761
  "\n outerlayer work claim --item 42 --kind implement\n\nRecords a lease for this host. A live lease already held by a\ndifferent host is refused; claiming again under the same host extends\nit.\n"
4758
4762
  ).action(async (opts) => {
4759
4763
  warnIfApiKeyFlag(opts);
4760
- const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-FQDWQVT2.js');
4764
+ const { runWorkClaim, WorkCommandError } = await import('./work-claim-cmd-5AUNCLS2.js');
4761
4765
  try {
4762
4766
  await runWorkClaim(opts);
4763
4767
  } catch (err) {
@@ -4773,7 +4777,7 @@ live addition remains on it.
4773
4777
  "\n outerlayer work renew --item 42\n\nExtends this host's own live lease. Refused with a 410 if the lease\nhas expired, or a 403 if a different host holds it.\n"
4774
4778
  ).action(async (opts) => {
4775
4779
  warnIfApiKeyFlag(opts);
4776
- const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-FQDWQVT2.js');
4780
+ const { runWorkRenew, WorkCommandError } = await import('./work-claim-cmd-5AUNCLS2.js');
4777
4781
  try {
4778
4782
  await runWorkRenew(opts);
4779
4783
  } catch (err) {
@@ -4792,7 +4796,7 @@ live addition remains on it.
4792
4796
  "\n outerlayer work release --item 42 --outcome ok\n\nMarks this host's lease released, optionally with an outcome.\nReleasing an already-released lease is a no-op that returns the\nrecorded release time and outcome.\n"
4793
4797
  ).action(async (opts) => {
4794
4798
  warnIfApiKeyFlag(opts);
4795
- const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-FQDWQVT2.js');
4799
+ const { runWorkRelease, WorkCommandError } = await import('./work-claim-cmd-5AUNCLS2.js');
4796
4800
  try {
4797
4801
  await runWorkRelease(opts);
4798
4802
  } catch (err) {
@@ -4808,7 +4812,7 @@ live addition remains on it.
4808
4812
  "\n outerlayer work pr 481\n\nRun inside a session already on a work item. Records that pull\nrequest 481 in the checkout's repository belongs to that item \u2014 the\nsame fact a `pr-link` in the session's own transcript records on\nsync. Idempotent: declaring the same pull request twice is a no-op.\n"
4809
4813
  ).action(async (number, opts) => {
4810
4814
  warnIfApiKeyFlag(opts);
4811
- const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-W2QNMWXP.js');
4815
+ const { runWorkPr, WorkPrCommandError } = await import('./work-pr-cmd-AZQPWH4H.js');
4812
4816
  try {
4813
4817
  await runWorkPr({ ...opts, number });
4814
4818
  } catch (err) {
@@ -4825,7 +4829,7 @@ function registerRunnerCommands(program2) {
4825
4829
  const configOption = "the cloud config file to run against (default: ~/.outerlayer/config.json)";
4826
4830
  runnerCmd.command("start").description("Run the loop: claim work, run it, report, clean up, repeat").option("--config <path>", configOption).action(async (opts) => {
4827
4831
  const { defaultRunnerConfigPath, RunnerConfigError } = await import('./config-POF7DEQW.js');
4828
- const { start, RunnerStartError } = await import('./loop-NFSOBUUJ.js');
4832
+ const { start, RunnerStartError } = await import('./loop-ASZRX3CZ.js');
4829
4833
  const { RunnerAlreadyRunningError } = await import('./pidfile-PTW76F56.js');
4830
4834
  const configPath = opts.config ?? defaultRunnerConfigPath();
4831
4835
  try {
@@ -4840,7 +4844,7 @@ function registerRunnerCommands(program2) {
4840
4844
  });
4841
4845
  runnerCmd.command("check").description("Validate the config, the hooks and the key, and print the effective settings").option("--config <path>", configOption).action(async (opts) => {
4842
4846
  const { defaultRunnerConfigPath, loadRunnerConfig, checkHooks: checkHooks2, RunnerConfigError } = await import('./config-POF7DEQW.js');
4843
- const { probeCredentials } = await import('./loop-NFSOBUUJ.js');
4847
+ const { probeCredentials } = await import('./loop-ASZRX3CZ.js');
4844
4848
  const configPath = opts.config ?? defaultRunnerConfigPath();
4845
4849
  let config;
4846
4850
  try {
@@ -4913,15 +4917,15 @@ Next:
4913
4917
  });
4914
4918
  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) => {
4915
4919
  const { defaultRunnerConfigPath } = await import('./config-POF7DEQW.js');
4916
- const { requestStop } = await import('./loop-NFSOBUUJ.js');
4920
+ const { requestStop } = await import('./loop-ASZRX3CZ.js');
4917
4921
  const configPath = opts.config ?? defaultRunnerConfigPath();
4918
4922
  await requestStop(configPath, Boolean(opts.now));
4919
4923
  });
4920
4924
  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) => {
4921
4925
  const { defaultRunnerConfigPath, loadRunnerConfig } = await import('./config-POF7DEQW.js');
4922
4926
  const { jobsDir } = await import('./paths-D2VGWWFI.js');
4923
- const { listJobFiles, runnerProcessState } = await import('./loop-NFSOBUUJ.js');
4924
- const { renderStatus } = await import('./status-WGOJTXZF.js');
4927
+ const { listJobFiles, runnerProcessState } = await import('./loop-ASZRX3CZ.js');
4928
+ const { renderStatus } = await import('./status-I27IST4L.js');
4925
4929
  const path2 = await import('path');
4926
4930
  const configPath = opts.config ?? defaultRunnerConfigPath();
4927
4931
  const all = listJobFiles(configPath);
@@ -4959,7 +4963,7 @@ Next:
4959
4963
  });
4960
4964
  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) => {
4961
4965
  const { defaultRunnerConfigPath } = await import('./config-POF7DEQW.js');
4962
- const { listJobFiles } = await import('./loop-NFSOBUUJ.js');
4966
+ const { listJobFiles } = await import('./loop-ASZRX3CZ.js');
4963
4967
  const { newestAttempt, logPathFor, tail, RunnerLogsError } = await import('./logs-TRNPQM42.js');
4964
4968
  const configPath = opts.config ?? defaultRunnerConfigPath();
4965
4969
  const item = parseTrackerNumber(itemArg);
@@ -4994,9 +4998,9 @@ function registerHooksCommands(program2) {
4994
4998
  "after",
4995
4999
  "\n`init` auto-wraps PreToolUse/PostToolUse hooks; these subcommands cover the\nrest: manual re-scans, other events, and undo.\n"
4996
5000
  );
4997
- hooksCmd.command("install-git").description("Install the rewrite-journal and commit-guard git hooks in this repo").option("--print", "print the hook scripts instead of installing").addHelpText(
5001
+ hooksCmd.command("install-git").description("Install the commit-guard git hook in this repo").option("--print", "print the hook scripts instead of installing").addHelpText(
4998
5002
  "after",
4999
- "\nThe same install `init` performs. `--print` writes the scripts to stdout for\nrepositories that manage hooks in-tree (husky and friends).\n"
5003
+ "\nThe same install `init` performs. `--print` writes the script to stdout for\nrepositories that manage hooks in-tree (husky and friends).\n"
5000
5004
  ).action((opts) => {
5001
5005
  if (opts.print) {
5002
5006
  for (const [name, script] of managedHookScripts()) {
@@ -5006,38 +5010,17 @@ ${script}
5006
5010
  }
5007
5011
  return;
5008
5012
  }
5009
- const { status, path: path2 } = installPostRewriteHook(process.cwd(), {
5010
- stampTrailers: readCloudConfig().gitHooks?.stampTrailers !== false
5011
- });
5012
- switch (status) {
5013
- case "installed":
5014
- case "updated":
5015
- case "unchanged":
5016
- process.stdout.write(`${C.green}\u2713${C.reset} post-rewrite journal hook ${status} \u2192 ${path2}
5013
+ const removal = removeJournalHooks(process.cwd());
5014
+ if (removal.removed) {
5015
+ process.stdout.write(`${C.green}\u2713${C.reset} removed the commit journal hooks an earlier version installed \u2192 ${removal.path}
5017
5016
  `);
5018
- break;
5019
- case "skipped-foreign":
5020
- process.stdout.write(
5021
- `${C.yellow}!${C.reset} a post-rewrite hook we did not write already exists (${path2}) \u2014 left untouched.
5022
- Append the journal script yourself: ${C.yellow}outerlayer hooks install-git --print${C.reset}
5023
- `
5024
- );
5025
- process.exitCode = 1;
5026
- break;
5027
- case "skipped-custom-hooks-path":
5028
- process.stdout.write(
5029
- `${C.yellow}!${C.reset} this repo manages hooks in its working tree (core.hooksPath) \u2014 nothing written.
5030
- Add the script to your hook manager instead: ${C.yellow}outerlayer hooks install-git --print${C.reset}
5031
- `
5032
- );
5033
- process.exitCode = 1;
5034
- break;
5035
- case "not-a-repo":
5036
- fail("not inside a git repository.");
5037
- break;
5038
5017
  }
5039
5018
  const guard = installPreCommitGuardHook(process.cwd());
5040
5019
  const report = formatGuardInstallOutput(guard);
5020
+ if (report.error !== void 0) {
5021
+ fail(report.error);
5022
+ return;
5023
+ }
5041
5024
  for (const line of report.lines) process.stdout.write(`${line}
5042
5025
  `);
5043
5026
  if (report.exitCode !== void 0) process.exitCode = report.exitCode;
@@ -5100,7 +5083,13 @@ ${C.dim}${file.path}${C.reset}
5100
5083
  fail("--no-input forbids prompting; pass --all to wrap every candidate without being asked.");
5101
5084
  return;
5102
5085
  }
5103
- const cliBin = resolveCliBin();
5086
+ let cliBin;
5087
+ try {
5088
+ cliBin = initHookBin({ home: homeFromEnv(), runningBin: resolveCliBin(), remove: false });
5089
+ } catch (err) {
5090
+ fail(`could not copy the CLI to ~/.outerlayer/cli: ${err instanceof Error ? err.message : String(err)}`);
5091
+ return;
5092
+ }
5104
5093
  const scope = opts.project ? "project" : "user";
5105
5094
  const path2 = settingsPath(scope);
5106
5095
  let settings;
@@ -5293,7 +5282,7 @@ function registerContextCommands(program2) {
5293
5282
  "after",
5294
5283
  "\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"
5295
5284
  ).action(async (opts) => {
5296
- const { materializeContext } = await import('./context-materialize-J6CRQ7O7.js');
5285
+ const { materializeContext } = await import('./context-materialize-6WKT3RBQ.js');
5297
5286
  const result = await materializeContext({ cwd: process.cwd(), sessionId: `manual-${Date.now()}` });
5298
5287
  const output = formatContextMaterializeOutput(result);
5299
5288
  if (output.exitCode !== void 0) process.exitCode = output.exitCode;
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module';
3
3
  import { readPin, pinExists, writeDegraded, writeSourceCache, SOURCE_CACHE_TTL_RETRY_MS, SOURCE_CACHE_TTL_SUCCESS_MS, readContextManifest, isLastCheckFresh, manifestFilesPresent, readDegraded, touchLastCheck, clearDegraded, writeContextManifest, writePinIfChanged, readSourceCache, isSourceCacheFresh } from './chunk-A3WLZX2F.js';
4
4
  import { parseGoverns, normalizeRepoName, CONTEXT_SOURCE_CONFIG_PATH } from './chunk-KFYJV2ZG.js';
5
5
  import { appendContextProvenance } from './chunk-ZJSNLVCE.js';
6
- import { ensureContextExcludes, ensurePreCommitGuardHook } from './chunk-IWIUYLDR.js';
6
+ import { ensureContextExcludes, ensurePreCommitGuardHook } from './chunk-I3ETLSNE.js';
7
7
  import { readCloudConfig } from './chunk-TFUIDMOB.js';
8
8
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
9
9
  import './chunk-Z5GEFMRW.js';
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { staleBuildRefusal, staleBuildWarning, ARTIFACT_MAX_CAPTION_LENGTH, ArtifactCriterionIdSchema, ARTIFACT_MAX_FILENAME_LENGTH, readEffectiveArtifactSpoolState, localArtifactIds, isArtifactTombstoned, mediaTypeForArtifactPath, inferArtifactKind, resolveRepoIdentity, detectActiveSession, launchRefusalForSession, artifactBlobsDir, appendArtifactRecord, artifactsSpoolPath, findPendingArtifactRecord, detectCi, appendArtifactTombstone, ARTIFACT_MAX_REPLACES_TARGETS } from './chunk-DEDV5V4U.js';
3
+ import { staleBuildRefusal, staleBuildWarning, readEffectiveArtifactSpoolState, localArtifactIds, isArtifactTombstoned, detectActiveSession, launchRefusalForSession, artifactBlobsDir, appendArtifactRecord, artifactsSpoolPath, findPendingArtifactRecord, detectCi, appendArtifactTombstone } from './chunk-U32VSRLO.js';
4
+ import { ARTIFACT_MAX_CAPTION_LENGTH, ArtifactCriterionIdSchema, ARTIFACT_MAX_FILENAME_LENGTH, mediaTypeForArtifactPath, inferArtifactKind, resolveRepoIdentity, ARTIFACT_MAX_REPLACES_TARGETS } from './chunk-4TNZMO7V.js';
4
5
  import './chunk-YRYMNBGQ.js';
5
- import { parseTrackerNumber, trackerNumberError } from './chunk-RCQXYLMO.js';
6
+ import './chunk-65WXAANR.js';
7
+ import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
6
8
  import './chunk-ZJSNLVCE.js';
7
- import './chunk-A6NNKRJU.js';
8
- import './chunk-IWIUYLDR.js';
9
- import './chunk-YMTXR7PJ.js';
10
- import './chunk-ECSYRPCC.js';
9
+ import './chunk-NXLLURA4.js';
10
+ import './chunk-I3ETLSNE.js';
11
+ import './chunk-YOOSBOKS.js';
12
+ import './chunk-R5KBGVII.js';
11
13
  import { readCloudConfig } from './chunk-TFUIDMOB.js';
12
14
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
13
15
  import './chunk-Z5GEFMRW.js';
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { FindingBatchSchema, resolveRepoIdentity, detectActiveSession, launchRefusalForSession } from './chunk-DEDV5V4U.js';
3
+ import { detectActiveSession, launchRefusalForSession } from './chunk-U32VSRLO.js';
4
+ import { FindingBatchSchema, resolveRepoIdentity } from './chunk-4TNZMO7V.js';
4
5
  import './chunk-YRYMNBGQ.js';
5
- import { launchedItemForSession, parseTrackerNumber, trackerNumberError } from './chunk-RCQXYLMO.js';
6
+ import { launchedItemForSession } from './chunk-65WXAANR.js';
7
+ import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
6
8
  import { readLatestProvenanceForSession } from './chunk-ZJSNLVCE.js';
7
- import './chunk-A6NNKRJU.js';
8
- import './chunk-IWIUYLDR.js';
9
- import './chunk-YMTXR7PJ.js';
10
- import './chunk-ECSYRPCC.js';
9
+ import './chunk-NXLLURA4.js';
10
+ import './chunk-I3ETLSNE.js';
11
+ import './chunk-YOOSBOKS.js';
12
+ import './chunk-R5KBGVII.js';
11
13
  import { readCloudConfig } from './chunk-TFUIDMOB.js';
12
14
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
13
15
  import './chunk-Z5GEFMRW.js';