@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.
- package/CHANGELOG.md +16 -0
- package/README.md +15 -21
- package/dist/build-info.json +1 -1
- package/dist/{chunk-DEDV5V4U.js → chunk-4TNZMO7V.js} +1874 -3191
- package/dist/{chunk-RCQXYLMO.js → chunk-65WXAANR.js} +2 -17
- package/dist/{chunk-4H56Y7O6.js → chunk-DCNOXRMV.js} +1 -1
- package/dist/{chunk-IWIUYLDR.js → chunk-I3ETLSNE.js} +7 -187
- package/dist/{chunk-XN2XZFTK.js → chunk-NTTPJV35.js} +1 -1
- package/dist/{chunk-A6NNKRJU.js → chunk-NXLLURA4.js} +4 -4
- package/dist/{chunk-VU34RWDU.js → chunk-Q6CL5THG.js} +3 -2
- package/dist/{chunk-ECSYRPCC.js → chunk-R5KBGVII.js} +50 -4
- package/dist/chunk-U32VSRLO.js +2225 -0
- package/dist/chunk-WZBHBH3J.js +20 -0
- package/dist/{chunk-YMTXR7PJ.js → chunk-YOOSBOKS.js} +1 -1
- package/dist/{cli-3JYGL2OB.js → cli-G7DILYJY.js} +127 -138
- package/dist/{context-materialize-J6CRQ7O7.js → context-materialize-6WKT3RBQ.js} +1 -1
- package/dist/{emit-artifact-cmd-23F4YKQ3.js → emit-artifact-cmd-UQVT3OKW.js} +8 -6
- package/dist/{emit-finding-cmd-6K7ERPKG.js → emit-finding-cmd-FDOU2OPD.js} +8 -6
- package/dist/{emit-result-cmd-NDFHMJX7.js → emit-result-cmd-H2T4C2K3.js} +8 -6
- package/dist/{hook-fast-CBW4ZETX.js → hook-fast-J5LCDHUJ.js} +2 -2
- package/dist/{hook-wrap-fast-36WGE6EX.js → hook-wrap-fast-KXYNX3AD.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/{loop-NFSOBUUJ.js → loop-ASZRX3CZ.js} +12 -10
- package/dist/{status-WGOJTXZF.js → status-I27IST4L.js} +10 -8
- package/dist/{statusline-fast-Z5U5CEC6.js → statusline-fast-3C5OXHDD.js} +2 -2
- package/dist/{sync-cmd-C5UGI4SF.js → sync-cmd-BBAUZ5JD.js} +8 -6
- package/dist/{watch-V3K4PESQ.js → watch-3DTPJETH.js} +8 -6
- package/dist/{work-claim-cmd-FQDWQVT2.js → work-claim-cmd-5AUNCLS2.js} +10 -8
- package/dist/{work-cmd-CW26EZZO.js → work-cmd-2P4BVX47.js} +9 -7
- package/dist/{work-launch-YNNCKIH3.js → work-launch-LT663PB3.js} +2 -1
- package/dist/{work-pr-cmd-W2QNMWXP.js → work-pr-cmd-AZQPWH4H.js} +8 -6
- package/package.json +1 -1
- 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-
|
|
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-
|
|
6
|
-
import { compareVersions, SUPPORTED_VERSIONS
|
|
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-
|
|
9
|
-
import './chunk-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
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, {
|
|
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
|
|
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:
|
|
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
|
-
|
|
3514
|
-
let
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
4924
|
-
const { renderStatus } = await import('./status-
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
5010
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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,
|
|
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
|
|
6
|
+
import './chunk-65WXAANR.js';
|
|
7
|
+
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
6
8
|
import './chunk-ZJSNLVCE.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
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 {
|
|
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
|
|
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-
|
|
8
|
-
import './chunk-
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
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';
|