@outerlayer/cli 0.18.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +21 -2
- package/dist/{agent-setup-RBTEACYU.js → agent-setup-AM42SA2D.js} +15 -16
- package/dist/{artifact-link-cmd-AVM2EKTV.js → artifact-link-cmd-OWRI5AJX.js} +2 -2
- package/dist/build-info.json +1 -1
- package/dist/{builder-DUI2ZH2H.js → builder-C4QNTYMS.js} +3 -3
- package/dist/{check-5C4YDZYV.js → check-W2JGXN3B.js} +44 -43
- package/dist/{chunk-S26M3YBJ.js → chunk-3UZTIRLF.js} +1 -1
- package/dist/{chunk-Y5MXET4M.js → chunk-3ZR7Y23Y.js} +11 -10
- package/dist/{chunk-47TTLEDX.js → chunk-5VML45HH.js} +35 -13
- package/dist/{chunk-F4XSVQJ4.js → chunk-6X4SQ5MY.js} +2 -2
- package/dist/{chunk-T4Y6SCG3.js → chunk-7UWVLZXD.js} +2 -2
- package/dist/{chunk-N3CUDFCW.js → chunk-7VUK5RFS.js} +15 -2
- package/dist/{chunk-SWCTGCSC.js → chunk-7YP7T6GV.js} +1 -1
- package/dist/{chunk-3OFZM4X6.js → chunk-B6SCN5NY.js} +151 -20
- package/dist/{chunk-KDVIU23F.js → chunk-BWSUPRDK.js} +1 -1
- package/dist/{chunk-S76AYB4M.js → chunk-CG36IONK.js} +5 -5
- package/dist/{chunk-RAZTWYZN.js → chunk-CGGPS7SI.js} +7 -8
- package/dist/chunk-CJJDJ7AT.js +56 -0
- package/dist/{chunk-W5VPCONO.js → chunk-EAEELQVQ.js} +33 -227
- package/dist/{chunk-QQM2UJ6T.js → chunk-F2KXHIFI.js} +182 -28
- package/dist/{chunk-KK4VBOH6.js → chunk-FBTGMSQF.js} +10 -11
- package/dist/{chunk-MQJSXHV7.js → chunk-G3IJ3N6F.js} +5 -3
- package/dist/{chunk-FUB7LRUE.js → chunk-GEMQLBMW.js} +5 -5
- package/dist/{chunk-Y5GE76XC.js → chunk-HOKXGFDR.js} +33 -81
- package/dist/{chunk-IP7BIBXJ.js → chunk-IF2OSI5T.js} +35 -1
- package/dist/{chunk-UYOYTKE2.js → chunk-JHGEBPLE.js} +3 -3
- package/dist/chunk-KYS3TQAG.js +296 -0
- package/dist/chunk-LLM3I5YU.js +89 -0
- package/dist/{chunk-B3UKB46N.js → chunk-LRG3ZMZD.js} +4 -5
- package/dist/{chunk-NL4XPC7W.js → chunk-LW7G5TJB.js} +1 -1
- package/dist/{chunk-MNTSH4CL.js → chunk-NNLA7LLQ.js} +1 -1
- package/dist/{chunk-GOBOJMOJ.js → chunk-PIZRPNKR.js} +4 -4
- package/dist/{chunk-ULSIJGLS.js → chunk-PSN33ERW.js} +56 -14
- package/dist/{chunk-WGAUY5LE.js → chunk-QEFKA2QD.js} +1 -1
- package/dist/{chunk-BMYGAGBJ.js → chunk-QNLX477Q.js} +155 -23
- package/dist/{chunk-JF42URPU.js → chunk-R22NZSGA.js} +33 -9
- package/dist/chunk-TUSYOL2O.js +113 -0
- package/dist/{chunk-ESC6UR76.js → chunk-TWF3RICI.js} +6 -6
- package/dist/{chunk-L2USZT6T.js → chunk-VMJPFQNE.js} +1 -1
- package/dist/{chunk-X5N6KC6V.js → chunk-WFSUUUAN.js} +2 -3
- package/dist/{chunk-6CHIYEZZ.js → chunk-XZ4H4X5F.js} +9 -83
- package/dist/{chunk-LXAY4A2G.js → chunk-YQR6E6OV.js} +34 -49
- package/dist/chunk-Z7K3L4FC.js +174 -0
- package/dist/{claude-launcher-YVXI76NX.js → claude-launcher-J5M44PFS.js} +20 -7
- package/dist/{cli-C77H54BV.js → cli-EXX2R73G.js} +206 -230
- package/dist/{command-H5CILO4S.js → command-ZQNEPDS6.js} +29 -30
- package/dist/{config-FXDG4NPJ.js → config-CLSGABD5.js} +2 -2
- package/dist/{connect-cmd-ZW5FV3ZW.js → connect-cmd-UNYKGDAL.js} +7 -7
- package/dist/context-cleanup-CHEWNYU6.js +11 -0
- package/dist/control-plane-launch-34LNRJWR.js +216 -0
- package/dist/{dist-QTX4RSCL.js → dist-WO7NOJNG.js} +2 -2
- package/dist/{docker-RC3PRX3Q.js → docker-BFU3AQGY.js} +4 -4
- package/dist/{doctor-2NQQML6P.js → doctor-DHUM5DBB.js} +32 -33
- package/dist/{emit-artifact-cmd-7MP63KXU.js → emit-artifact-cmd-XBHM647X.js} +17 -17
- package/dist/{emit-cmd-PPN4QQF2.js → emit-cmd-W55AEBCA.js} +6 -6
- package/dist/{emit-criteria-cmd-3RXPDLNK.js → emit-criteria-cmd-CRTYEF7D.js} +11 -12
- package/dist/{emit-finding-cmd-OL7JB6H3.js → emit-finding-cmd-7JHVRYOP.js} +12 -13
- package/dist/{emit-result-cmd-UZVMOCF4.js → emit-result-cmd-5NZMLCJK.js} +17 -17
- package/dist/emit-step-cmd-347XNGPQ.js +26 -0
- package/dist/{governing-source-BUU4IABS.js → governing-source-HAA4OW57.js} +21 -22
- package/dist/{hook-fast-W5MKHMJT.js → hook-fast-RL5E5OXE.js} +3 -3
- package/dist/{import-capture-cmd-ZO6KGHI2.js → import-capture-cmd-TK4XY7RD.js} +4 -4
- package/dist/{import-ruler-cmd-KJMWL5V6.js → import-ruler-cmd-T6LLO6Q7.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/{init-WNXXYMO7.js → init-V6FOMD2V.js} +30 -31
- package/dist/{init-VWXIZEAN.js → init-XG47KCI4.js} +30 -31
- package/dist/{init-cmd-WS6TIRYT.js → init-cmd-Z4O4PPLZ.js} +70 -27
- package/dist/{init-update-E3J6TVIN.js → init-update-7DVAKWW3.js} +21 -22
- package/dist/{install-CBWIEF3R.js → install-4SEFIIW2.js} +3 -3
- package/dist/{login-browser-O63QZN7D.js → login-browser-DX35MARZ.js} +2 -2
- package/dist/{loop-UGI2BJOT.js → loop-TPUYUMSY.js} +44 -43
- package/dist/{machine-JOW4RNZ7.js → machine-TRHBT5NE.js} +26 -27
- package/dist/{mcp-serve-cmd-DOTY5FKY.js → mcp-serve-cmd-N3UTY6EE.js} +5 -5
- package/dist/{runner-env-4NB2GA7O.js → runner-env-FRZFFHDF.js} +4 -4
- package/dist/{runner-key-TC3NFWFV.js → runner-key-5FOWCW7J.js} +30 -31
- package/dist/{session-sender-NNVPSPY7.js → session-sender-U2BBUWNO.js} +19 -15
- package/dist/shell-function-NRD4KVUK.js +6 -0
- package/dist/{spec-cmd-OWVTBB4J.js → spec-cmd-FVLJOFGC.js} +12 -13
- package/dist/{starter-pack-OPWUDOWX.js → starter-pack-6LQVLBIA.js} +5 -5
- package/dist/{status-TKCLLKFG.js → status-BINH7MBG.js} +33 -32
- package/dist/{sync-cmd-Q6VYNPWG.js → sync-cmd-VXOUFS4I.js} +18 -14
- package/dist/{watch-ARAGADTF.js → watch-OH645CV2.js} +18 -14
- package/dist/{work-claim-cmd-34FERLYX.js → work-claim-cmd-ZRPSHMPT.js} +16 -17
- package/dist/{work-cmd-7S5B2H2P.js → work-cmd-5I3J2XQQ.js} +12 -13
- package/dist/{work-comment-cmd-SZJSPM5S.js → work-comment-cmd-UCCPWUSR.js} +12 -13
- package/dist/work-logs-cmd-7352CJPG.js +60 -0
- package/dist/{work-open-pr-cmd-RPXKCBWS.js → work-open-pr-cmd-LSH4VHJM.js} +13 -14
- package/dist/{work-pr-cmd-5LGANL32.js → work-pr-cmd-H4OQR26N.js} +12 -13
- package/package.json +2 -2
- package/skill-pack/maintained/outerlayer-cli/SKILL.md +9 -2
- package/skill-pack/maintained/outerlayer-cli/references/find-out-why-a-build-ended.md +76 -0
- package/skill-pack/shipped.json +1 -0
- package/skill-pack/template/build/references/release.md +3 -1
- package/dist/chunk-WBT5X3NH.js +0 -40
- package/dist/chunk-XCCLFVXM.js +0 -401
- package/dist/context-adopt-O5OFXMKI.js +0 -109
- package/dist/context-materialize-Y5IJ4MQT.js +0 -23
- package/dist/{chunk-NACDBXUG.js → chunk-BM63HB2M.js} +1 -1
- package/dist/{chunk-ZRL6HKBY.js → chunk-FVMYKL6L.js} +1 -1
- package/dist/{chunk-52NC2FIU.js → chunk-NTRCK4NH.js} +1 -1
- package/dist/{chunk-XGP3VYOG.js → chunk-P53VEAOF.js} +1 -1
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
+
import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-CG36IONK.js';
|
|
4
|
+
import { resolveRepoIdentity } from './chunk-QNLX477Q.js';
|
|
5
|
+
import { resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
|
|
6
|
+
import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
|
|
7
|
+
import { cliInvocation } from './chunk-CRB3POP4.js';
|
|
8
|
+
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
3
9
|
import { openSync, fstatSync, readSync, closeSync } from 'fs';
|
|
4
10
|
import { join } from 'path';
|
|
5
11
|
|
|
@@ -76,4 +82,32 @@ function transcriptPathForSession(sessionId, home, readTailImpl = readTail) {
|
|
|
76
82
|
return found;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
|
-
|
|
85
|
+
// src/auto-connect.ts
|
|
86
|
+
async function autoConnect(opts) {
|
|
87
|
+
const env = opts.env ?? process.env;
|
|
88
|
+
const home = opts.home ?? homeFromEnv(env);
|
|
89
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
90
|
+
const resolved = resolveGatewayCredentials({ url: opts.url, apiKey: opts.apiKey, appId: opts.appId, home, env, cwd });
|
|
91
|
+
if (resolved.ok || resolved.kind !== "login" || !resolved.credential || !resolved.url) return void 0;
|
|
92
|
+
const dirs = findGitDirs(cwd);
|
|
93
|
+
const repository = opts.repository ?? resolveRepoIdentity(cwd).gitRepo;
|
|
94
|
+
if (dirs === void 0 || repository === void 0) return void 0;
|
|
95
|
+
const listed = await fetchFactories(opts.fetchImpl ?? fetch, resolved.url, resolved.credential, repository);
|
|
96
|
+
if (!listed.ok || listed.factories.length === 0) return void 0;
|
|
97
|
+
const chosen = selectFactory(listed.factories, readRepoConnection(cwd), repository);
|
|
98
|
+
if (chosen.factory === void 0) {
|
|
99
|
+
return `you are logged in, but no factory is chosen for this repository, and more than one fits. Run \`${cliInvocation()} connect --factory <org>/<factory>\` with one of:
|
|
100
|
+
${chosen.text}
|
|
101
|
+
Or pass --app-id / set OUTERLAYER_APP_ID.`;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
saveFactoryConnection(dirs.gitCommonDir, void 0, chosen.factory, /* @__PURE__ */ new Date());
|
|
105
|
+
} catch {
|
|
106
|
+
return void 0;
|
|
107
|
+
}
|
|
108
|
+
process.stderr.write(`${autoConnectedLine(repository, chosen.factory, chosen.reason)}
|
|
109
|
+
`);
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { autoConnect, detectActiveSession, transcriptPathForSession };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { LiveUploader } from './chunk-
|
|
4
|
-
import {
|
|
3
|
+
import { LiveUploader } from './chunk-R22NZSGA.js';
|
|
4
|
+
import { spoolDir } from './chunk-PSN33ERW.js';
|
|
5
|
+
import { CaptureDaemon } from './chunk-QNLX477Q.js';
|
|
5
6
|
import { parseWorkItemEnv } from './chunk-T2Q7ISPE.js';
|
|
6
|
-
import { spoolDir } from './chunk-ULSIJGLS.js';
|
|
7
7
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
8
8
|
import { mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
9
9
|
import { join } from 'path';
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { launchRefusalForSession } from './chunk-ESVW4MJY.js';
|
|
4
|
+
import { autoConnect, detectActiveSession } from './chunk-IF2OSI5T.js';
|
|
5
|
+
import { acquireSpoolLockAt } from './chunk-G3IJ3N6F.js';
|
|
6
|
+
import { resolveRepoIdentity } from './chunk-QNLX477Q.js';
|
|
7
|
+
import { C } from './chunk-ANPNT6PM.js';
|
|
8
|
+
import { launchedItemForSession } from './chunk-T2Q7ISPE.js';
|
|
9
|
+
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
10
|
+
import { defaultFetch } from './chunk-FVMYKL6L.js';
|
|
11
|
+
import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-NTRCK4NH.js';
|
|
12
|
+
import { StepNameSchema, StepBodySchema } from './chunk-7VUK5RFS.js';
|
|
13
|
+
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
14
|
+
import { randomUUID } from 'crypto';
|
|
15
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, renameSync, appendFileSync } from 'fs';
|
|
16
|
+
import { join, dirname } from 'path';
|
|
17
|
+
|
|
18
|
+
createRequire(import.meta.url);
|
|
19
|
+
var STEP_RETRY_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
20
|
+
var STEP_STATE_RESOLVED_CAP = 5e3;
|
|
21
|
+
function stepsSpoolPath(home = homeFromEnv()) {
|
|
22
|
+
return join(home, ".outerlayer", "spool", "steps.jsonl");
|
|
23
|
+
}
|
|
24
|
+
function stepsStatePath(home = homeFromEnv()) {
|
|
25
|
+
return join(home, ".outerlayer", "spool", "steps.state.json");
|
|
26
|
+
}
|
|
27
|
+
function stepsLockPath(home = homeFromEnv()) {
|
|
28
|
+
return join(home, ".outerlayer", "spool", "steps.lock");
|
|
29
|
+
}
|
|
30
|
+
function appendStepRecord(record, home = homeFromEnv()) {
|
|
31
|
+
const path = stepsSpoolPath(home);
|
|
32
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
33
|
+
appendFileSync(path, JSON.stringify(record) + "\n");
|
|
34
|
+
}
|
|
35
|
+
function isRecord(value) {
|
|
36
|
+
if (value === null || typeof value !== "object") return false;
|
|
37
|
+
const r = value;
|
|
38
|
+
return typeof r.clientStepId === "string" && typeof r.name === "string" && typeof r.startedAt === "string" && typeof r.itemNumber === "number" && typeof r.appId === "string" && typeof r.cwd === "string" && typeof r.spooledAt === "string";
|
|
39
|
+
}
|
|
40
|
+
function readStepRecords(home = homeFromEnv()) {
|
|
41
|
+
const path = stepsSpoolPath(home);
|
|
42
|
+
if (!existsSync(path)) return { records: [], skipped: 0 };
|
|
43
|
+
const records = [];
|
|
44
|
+
let skipped = 0;
|
|
45
|
+
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
46
|
+
if (line.trim() === "") continue;
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(line);
|
|
49
|
+
if (isRecord(parsed)) records.push(parsed);
|
|
50
|
+
else skipped += 1;
|
|
51
|
+
} catch {
|
|
52
|
+
skipped += 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return { records, skipped };
|
|
56
|
+
}
|
|
57
|
+
function readStepState(home = homeFromEnv()) {
|
|
58
|
+
const state = /* @__PURE__ */ new Map();
|
|
59
|
+
let parsed;
|
|
60
|
+
try {
|
|
61
|
+
parsed = JSON.parse(readFileSync(stepsStatePath(home), "utf8"));
|
|
62
|
+
} catch {
|
|
63
|
+
return state;
|
|
64
|
+
}
|
|
65
|
+
const entries = parsed?.records;
|
|
66
|
+
if (!Array.isArray(entries)) return state;
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
const e = entry;
|
|
69
|
+
if (typeof e?.clientStepId !== "string") continue;
|
|
70
|
+
if (e.state === "pending" || e.state === "uploaded" || e.state === "dropped") state.set(e.clientStepId, e.state);
|
|
71
|
+
}
|
|
72
|
+
return state;
|
|
73
|
+
}
|
|
74
|
+
function writeStepState(state, home = homeFromEnv()) {
|
|
75
|
+
try {
|
|
76
|
+
const path = stepsStatePath(home);
|
|
77
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
78
|
+
const pending = [];
|
|
79
|
+
const resolved = [];
|
|
80
|
+
for (const pair of state.entries()) (pair[1] === "pending" ? pending : resolved).push(pair);
|
|
81
|
+
const kept = resolved.length > STEP_STATE_RESOLVED_CAP ? resolved.slice(-STEP_STATE_RESOLVED_CAP) : resolved;
|
|
82
|
+
const records = [...pending, ...kept].map(([clientStepId, disposition]) => ({ clientStepId, state: disposition }));
|
|
83
|
+
const tmp = `${path}.tmp`;
|
|
84
|
+
writeFileSync(tmp, JSON.stringify({ version: 1, records }));
|
|
85
|
+
renameSync(tmp, path);
|
|
86
|
+
return true;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/emit-step-cmd.ts
|
|
93
|
+
var EmitStepError = class extends Error {
|
|
94
|
+
};
|
|
95
|
+
function firstIssue(error) {
|
|
96
|
+
const issue = error.issues[0];
|
|
97
|
+
if (!issue) return "malformed";
|
|
98
|
+
const path = issue.path.join(".");
|
|
99
|
+
return path === "" || path === "name" ? issue.message : `${path}: ${issue.message}`;
|
|
100
|
+
}
|
|
101
|
+
function detectSessionId(opts) {
|
|
102
|
+
const identity = resolveRepoIdentity(opts.cwd);
|
|
103
|
+
return detectActiveSession({
|
|
104
|
+
env: opts.env,
|
|
105
|
+
home: opts.home,
|
|
106
|
+
cwds: identity.repoRoot !== void 0 ? [identity.repoRoot, opts.cwd] : [opts.cwd],
|
|
107
|
+
nowMs: opts.now().getTime()
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function resolveItem(opts) {
|
|
111
|
+
if (opts.sessionId !== void 0) {
|
|
112
|
+
const refusal = launchRefusalForSession(opts.sessionId, opts.home);
|
|
113
|
+
if (refusal !== void 0) throw new EmitStepError(refusal);
|
|
114
|
+
}
|
|
115
|
+
if (opts.item !== void 0) {
|
|
116
|
+
const number = parseTrackerNumber(opts.item);
|
|
117
|
+
if (number === void 0) throw new EmitStepError(trackerNumberError("--item", opts.item));
|
|
118
|
+
return number;
|
|
119
|
+
}
|
|
120
|
+
const launched = opts.sessionId !== void 0 ? launchedItemForSession(opts.sessionId, opts.home) : void 0;
|
|
121
|
+
if (launched !== void 0) return launched;
|
|
122
|
+
throw new EmitStepError(
|
|
123
|
+
"no work item to report this step on. Pass --item <number>, or run inside a recorded session launched with OUTERLAYER_WORK, whose launch record names the item."
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
async function refusalReason(response) {
|
|
127
|
+
let text = "";
|
|
128
|
+
try {
|
|
129
|
+
text = await response.text();
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const message = JSON.parse(text).error?.message;
|
|
134
|
+
if (typeof message === "string" && message !== "") return message;
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
return text.replace(/\s+/g, " ").trim().slice(0, 160);
|
|
138
|
+
}
|
|
139
|
+
function stepUrl(base) {
|
|
140
|
+
return new URL("/v1/work-items/steps", base).toString();
|
|
141
|
+
}
|
|
142
|
+
function stepHeaders(apiKey, appId) {
|
|
143
|
+
return { "content-type": "application/json", authorization: `Bearer ${apiKey}`, "x-outerlayer-app-id": appId };
|
|
144
|
+
}
|
|
145
|
+
async function runEmitStep(opts) {
|
|
146
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
147
|
+
const home = opts.home ?? homeFromEnv();
|
|
148
|
+
const env = opts.env ?? process.env;
|
|
149
|
+
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
150
|
+
const name = StepNameSchema.safeParse(opts.name);
|
|
151
|
+
if (!name.success) throw new EmitStepError(`invalid step name: ${firstIssue(name.error)}`);
|
|
152
|
+
const sessionId = detectSessionId({ cwd, home, env, now });
|
|
153
|
+
const itemNumber = resolveItem({ item: opts.item, sessionId, home });
|
|
154
|
+
const parsed = StepBodySchema.safeParse({
|
|
155
|
+
clientStepId: randomUUID(),
|
|
156
|
+
name: opts.name,
|
|
157
|
+
item: { number: itemNumber },
|
|
158
|
+
startedAt: now().toISOString()
|
|
159
|
+
});
|
|
160
|
+
if (!parsed.success) throw new EmitStepError(`invalid step: ${firstIssue(parsed.error)}`);
|
|
161
|
+
const body = parsed.data;
|
|
162
|
+
const refusal = await autoConnect({ ...opts, cwd, home, env });
|
|
163
|
+
if (refusal !== void 0) throw new EmitStepError(refusal);
|
|
164
|
+
const resolved = resolveGatewayCredentials({ ...opts, cwd, home, env });
|
|
165
|
+
if (!resolved.ok) throw new EmitStepError(resolved.message);
|
|
166
|
+
const { url, credential: apiKey, appId } = resolved;
|
|
167
|
+
const fetchImpl = opts.fetchImpl ?? defaultFetch;
|
|
168
|
+
const endpoint = stepUrl(url);
|
|
169
|
+
const spool = (why) => {
|
|
170
|
+
appendStepRecord(
|
|
171
|
+
{
|
|
172
|
+
clientStepId: body.clientStepId,
|
|
173
|
+
name: body.name,
|
|
174
|
+
startedAt: body.startedAt,
|
|
175
|
+
itemNumber,
|
|
176
|
+
appId,
|
|
177
|
+
cwd,
|
|
178
|
+
spooledAt: now().toISOString()
|
|
179
|
+
},
|
|
180
|
+
home
|
|
181
|
+
);
|
|
182
|
+
const output2 = `${C.yellow}!${C.reset} step "${body.name}" queued (${why}); \`outerlayer sync\` will send it`;
|
|
183
|
+
if (!opts.quiet) process.stdout.write(output2 + "\n");
|
|
184
|
+
return { data: { clientStepId: body.clientStepId, queued: true }, output: output2, exitCode: 0, queued: true };
|
|
185
|
+
};
|
|
186
|
+
let response;
|
|
187
|
+
try {
|
|
188
|
+
response = await fetchImpl(endpoint, { method: "POST", headers: stepHeaders(apiKey, appId), body: JSON.stringify(body) });
|
|
189
|
+
} catch (err) {
|
|
190
|
+
return spool(`could not reach ${new URL(endpoint).host}: ${String(err)}`);
|
|
191
|
+
}
|
|
192
|
+
if (response.status >= 500) return spool(`the gateway answered ${response.status}`);
|
|
193
|
+
if (response.status === 401) throw new EmitStepError(unauthorizedMessage(apiKey));
|
|
194
|
+
if (!response.ok) {
|
|
195
|
+
const reason = await refusalReason(response);
|
|
196
|
+
throw new EmitStepError(`step refused (${response.status})${reason ? `: ${reason}` : ""}`);
|
|
197
|
+
}
|
|
198
|
+
let data = {};
|
|
199
|
+
try {
|
|
200
|
+
data = (await response.json()).data ?? {};
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
const output = opts.json ? JSON.stringify(data) : `${C.green}\u2713${C.reset} step started: ${body.name} ${C.dim}\xB7${C.reset} item #${itemNumber}`;
|
|
204
|
+
if (!opts.quiet) process.stdout.write(output + "\n");
|
|
205
|
+
return { data, output, exitCode: 0, queued: false };
|
|
206
|
+
}
|
|
207
|
+
async function uploadSpooledSteps(opts) {
|
|
208
|
+
const { home } = opts;
|
|
209
|
+
const waiting = () => {
|
|
210
|
+
const state = readStepState(home);
|
|
211
|
+
return readStepRecords(home).records.filter((record) => {
|
|
212
|
+
const disposition = state.get(record.clientStepId);
|
|
213
|
+
return disposition !== "uploaded" && disposition !== "dropped";
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
if (waiting().length === 0) return void 0;
|
|
217
|
+
const lock = await acquireSpoolLockAt(stepsLockPath(home), { waitMs: opts.lockWaitMs });
|
|
218
|
+
if (!lock.ok) {
|
|
219
|
+
if (!opts.quiet) {
|
|
220
|
+
process.stderr.write(`${C.yellow}!${C.reset} steps not sent: ${lock.reason}; they stay queued for the next sync
|
|
221
|
+
`);
|
|
222
|
+
}
|
|
223
|
+
return { uploaded: 0, dropped: 0, pending: waiting().length };
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const fetchImpl = opts.fetchImpl ?? defaultFetch;
|
|
227
|
+
const nowMs = opts.nowMs ?? Date.now();
|
|
228
|
+
const state = readStepState(home);
|
|
229
|
+
const result = { uploaded: 0, dropped: 0, pending: 0 };
|
|
230
|
+
let stopped = false;
|
|
231
|
+
for (const record of readStepRecords(home).records) {
|
|
232
|
+
const saved = state.get(record.clientStepId);
|
|
233
|
+
if (saved === "uploaded" || saved === "dropped") continue;
|
|
234
|
+
const spooledMs = Date.parse(record.spooledAt);
|
|
235
|
+
if (Number.isFinite(spooledMs) && nowMs - spooledMs > STEP_RETRY_MAX_AGE_MS) {
|
|
236
|
+
state.set(record.clientStepId, "dropped");
|
|
237
|
+
result.dropped += 1;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const foreign = opts.kind === "key" && record.appId !== opts.appId || opts.onlyItem !== void 0 && record.itemNumber !== opts.onlyItem;
|
|
241
|
+
if (stopped || foreign) {
|
|
242
|
+
result.pending += 1;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
const body = {
|
|
246
|
+
clientStepId: record.clientStepId,
|
|
247
|
+
name: record.name,
|
|
248
|
+
item: { number: record.itemNumber },
|
|
249
|
+
startedAt: record.startedAt
|
|
250
|
+
};
|
|
251
|
+
let response;
|
|
252
|
+
try {
|
|
253
|
+
response = await fetchImpl(stepUrl(opts.url), {
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: stepHeaders(opts.apiKey, opts.kind === "login" ? record.appId : opts.appId),
|
|
256
|
+
body: JSON.stringify(body)
|
|
257
|
+
});
|
|
258
|
+
} catch {
|
|
259
|
+
stopped = true;
|
|
260
|
+
result.pending += 1;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (response.ok) {
|
|
264
|
+
state.set(record.clientStepId, "uploaded");
|
|
265
|
+
result.uploaded += 1;
|
|
266
|
+
} else if (response.status === 401) {
|
|
267
|
+
result.unauthorized = unauthorizedMessage(opts.apiKey);
|
|
268
|
+
stopped = true;
|
|
269
|
+
result.pending += 1;
|
|
270
|
+
} else if (response.status >= 500 || response.status === 408 || response.status === 429) {
|
|
271
|
+
result.pending += 1;
|
|
272
|
+
} else {
|
|
273
|
+
state.set(record.clientStepId, "dropped");
|
|
274
|
+
result.dropped += 1;
|
|
275
|
+
if (!opts.quiet) {
|
|
276
|
+
const reason = await refusalReason(response);
|
|
277
|
+
process.stderr.write(
|
|
278
|
+
`${C.yellow}!${C.reset} step "${record.name}" on item #${record.itemNumber} refused (${response.status}) and dropped${reason ? `: ${reason}` : ""}
|
|
279
|
+
`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (!writeStepState(state, opts.home) && !opts.quiet) {
|
|
285
|
+
process.stderr.write(
|
|
286
|
+
`${C.yellow}!${C.reset} failed to save ${stepsStatePath(home)}; steps sent this run may be sent again, which is harmless
|
|
287
|
+
`
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
return result;
|
|
291
|
+
} finally {
|
|
292
|
+
lock.release();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export { EmitStepError, runEmitStep, uploadSpooledSteps };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { rewriteControlPlanePaths, rewriteHookCommand } from './chunk-G2YNJIGF.js';
|
|
4
|
+
import { MAINTAINED_SKILLS } from './chunk-NNLA7LLQ.js';
|
|
5
|
+
import { existsSync, mkdirSync, copyFileSync, writeFileSync, readdirSync, lstatSync, readFileSync } from 'fs';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
|
+
|
|
8
|
+
createRequire(import.meta.url);
|
|
9
|
+
function deliverySection(dir) {
|
|
10
|
+
return `This repository's control plane is not in the checkout. Its files are in \`${dir}\`. When an instruction or skill names a path under \`.outerlayer/\` or \`.claude/\`, read it under \`${dir}\`.`;
|
|
11
|
+
}
|
|
12
|
+
function isFile(path) {
|
|
13
|
+
try {
|
|
14
|
+
return lstatSync(path).isFile();
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function filesUnder(dir, base = dir) {
|
|
20
|
+
if (!existsSync(dir) || !lstatSync(dir).isDirectory()) return [];
|
|
21
|
+
const out = [];
|
|
22
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
23
|
+
const abs = join(dir, entry.name);
|
|
24
|
+
if (entry.isDirectory()) out.push(...filesUnder(abs, base));
|
|
25
|
+
else if (entry.isFile()) out.push(abs.slice(base.length + 1));
|
|
26
|
+
}
|
|
27
|
+
return out.sort();
|
|
28
|
+
}
|
|
29
|
+
function readText(path) {
|
|
30
|
+
if (!isFile(path)) return void 0;
|
|
31
|
+
const content = readFileSync(path);
|
|
32
|
+
return content.includes(0) ? void 0 : content.toString("utf8");
|
|
33
|
+
}
|
|
34
|
+
function deliveredSettings(raw, dir) {
|
|
35
|
+
if (raw === void 0) return "{}\n";
|
|
36
|
+
const rewrite = (value) => {
|
|
37
|
+
if (typeof value === "string") return rewriteHookCommand(value, dir);
|
|
38
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
39
|
+
if (typeof value === "object" && value !== null) return Object.fromEntries(Object.entries(value).map(([key, inner]) => [key, rewrite(inner)]));
|
|
40
|
+
return value;
|
|
41
|
+
};
|
|
42
|
+
try {
|
|
43
|
+
return `${JSON.stringify(rewrite(JSON.parse(raw)), null, 2)}
|
|
44
|
+
`;
|
|
45
|
+
} catch {
|
|
46
|
+
return rewriteHookCommand(raw, dir);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function composeDelivery(input) {
|
|
50
|
+
const { tree, dir } = input;
|
|
51
|
+
const added = [];
|
|
52
|
+
const put = (rel, content) => {
|
|
53
|
+
mkdirSync(dirname(join(tree, rel)), { recursive: true });
|
|
54
|
+
writeFileSync(join(tree, rel), content);
|
|
55
|
+
added.push(rel);
|
|
56
|
+
};
|
|
57
|
+
for (const skill of MAINTAINED_SKILLS) {
|
|
58
|
+
for (const rel of filesUnder(join(tree, ".outerlayer/skills", skill))) {
|
|
59
|
+
const target = `.claude/skills/${skill}/${rel}`;
|
|
60
|
+
if (existsSync(join(tree, target))) continue;
|
|
61
|
+
mkdirSync(dirname(join(tree, target)), { recursive: true });
|
|
62
|
+
copyFileSync(join(tree, ".outerlayer/skills", skill, rel), join(tree, target));
|
|
63
|
+
added.push(target);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const rel of [...filesUnder(join(tree, ".claude/skills"), tree), ...filesUnder(join(tree, ".claude/agents"), tree)]) {
|
|
67
|
+
const text = readText(join(tree, rel));
|
|
68
|
+
if (text === void 0) continue;
|
|
69
|
+
const rewritten = rewriteControlPlanePaths(text, dir);
|
|
70
|
+
if (rewritten !== text) writeFileSync(join(tree, rel), rewritten);
|
|
71
|
+
}
|
|
72
|
+
const agents = readText(join(tree, "AGENTS.md"));
|
|
73
|
+
put("CLAUDE.md", agents === void 0 ? `${deliverySection(dir)}
|
|
74
|
+
` : `${deliverySection(dir)}
|
|
75
|
+
|
|
76
|
+
${rewriteControlPlanePaths(agents, dir)}`);
|
|
77
|
+
put("settings.json", deliveredSettings(readText(join(tree, ".claude/settings.json")), dir));
|
|
78
|
+
return added;
|
|
79
|
+
}
|
|
80
|
+
function sharedSkillNames(tree) {
|
|
81
|
+
const dir = join(tree, ".claude/skills");
|
|
82
|
+
if (!existsSync(dir)) return [];
|
|
83
|
+
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
84
|
+
}
|
|
85
|
+
function skillConflictMessage(input) {
|
|
86
|
+
return `.claude/skills/${input.skill} in ${input.repository} has the same name as the shared skill ${input.skill} from ${input.controlPlane}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { composeDelivery, sharedSkillNames, skillConflictMessage };
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { autoConnect } from './chunk-
|
|
4
|
-
import {
|
|
5
|
-
import { resolveRepoIdentity } from './chunk-BMYGAGBJ.js';
|
|
3
|
+
import { autoConnect, detectActiveSession } from './chunk-IF2OSI5T.js';
|
|
4
|
+
import { resolveRepoIdentity } from './chunk-QNLX477Q.js';
|
|
6
5
|
import { C } from './chunk-ANPNT6PM.js';
|
|
7
6
|
import { parseWorkItemEnv } from './chunk-T2Q7ISPE.js';
|
|
8
7
|
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
9
|
-
import { defaultFetch } from './chunk-
|
|
10
|
-
import { unauthorizedMessage, resolveGatewayCredentials } from './chunk-
|
|
8
|
+
import { defaultFetch } from './chunk-FVMYKL6L.js';
|
|
9
|
+
import { unauthorizedMessage, resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
|
|
11
10
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
12
11
|
|
|
13
12
|
createRequire(import.meta.url);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { MIN_ENGINE_MAJOR } from './chunk-
|
|
3
|
+
import { MIN_ENGINE_MAJOR } from './chunk-3ZR7Y23Y.js';
|
|
4
4
|
import { firecrackerArch, MICROVM_ARCHES, guestAssetsPinned } from './chunk-CX22S5BA.js';
|
|
5
5
|
import { spawnSync } from 'child_process';
|
|
6
6
|
import { existsSync, accessSync, constants, statSync, readFileSync } from 'fs';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { splitRawFile } from './chunk-
|
|
3
|
+
import { splitRawFile } from './chunk-WFSUUUAN.js';
|
|
4
4
|
import { resolvePackageVersion } from './chunk-RA3O54FC.js';
|
|
5
5
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
|
|
6
6
|
import { join, dirname } from 'path';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { runnerCredentialProblem } from './chunk-
|
|
3
|
+
import { hasStoredCredential, AGENT_COMMANDS, storeClaudeCredential, credentialFromStdin, isAgentName } from './chunk-7YP7T6GV.js';
|
|
4
|
+
import { detectMachine, supportsContainerBuilds, reachDockerStep, describeMachineDocker, supportsMicroVmBuilds } from './chunk-LW7G5TJB.js';
|
|
5
|
+
import { MIN_ENGINE_MAJOR } from './chunk-3ZR7Y23Y.js';
|
|
6
|
+
import { runnerCredentialProblem } from './chunk-P53VEAOF.js';
|
|
7
7
|
import { runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
|
|
8
8
|
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
9
9
|
import { dirname } from 'path';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { CONTROL_PLANE_DIR_VARIABLE } from './chunk-G2YNJIGF.js';
|
|
4
|
-
import { deadHooksState, huskyPrepareScript, preparePackageManagerCommand } from './chunk-XCCLFVXM.js';
|
|
5
3
|
import { appendContextProvenance } from './chunk-ZJSNLVCE.js';
|
|
6
4
|
import { readRepoConnection, findGitDirs } from './chunk-BJ3KTMDH.js';
|
|
5
|
+
import { CONTROL_PLANE_DIR_VARIABLE } from './chunk-G2YNJIGF.js';
|
|
7
6
|
import { cliInvocation } from './chunk-CRB3POP4.js';
|
|
7
|
+
import { deadHooksState, huskyPrepareScript, preparePackageManagerCommand } from './chunk-TUSYOL2O.js';
|
|
8
8
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
9
9
|
import { readFileSync, mkdirSync, writeFileSync, renameSync, existsSync, statSync, appendFileSync, opendirSync, unlinkSync } from 'fs';
|
|
10
10
|
import { spawn, execFileSync } from 'child_process';
|
|
@@ -502,15 +502,16 @@ function installedCliStalenessContext(home, cwd) {
|
|
|
502
502
|
return `The installed OuterLayer CLI (~/.outerlayer/cli) is behind the workspace build: installed ${installedLabel}, workspace ${workspaceLabel}.
|
|
503
503
|
${howToRefresh}`;
|
|
504
504
|
}
|
|
505
|
-
function writeSessionStartContext(event, home, cwd, write, extraParts = []) {
|
|
505
|
+
function writeSessionStartContext(event, home, cwd, write, systemMessage, extraParts = []) {
|
|
506
506
|
try {
|
|
507
507
|
if (event !== "SessionStart") return;
|
|
508
508
|
const parts = [syncHealthContext(home), installedCliStalenessContext(home, cwd), ...extraParts].filter(
|
|
509
509
|
(s) => s !== null
|
|
510
510
|
);
|
|
511
|
-
if (parts.length === 0) return;
|
|
511
|
+
if (parts.length === 0 && systemMessage === void 0) return;
|
|
512
512
|
write(
|
|
513
513
|
JSON.stringify({
|
|
514
|
+
...systemMessage === void 0 ? {} : { systemMessage },
|
|
514
515
|
hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: parts.join("\n\n") }
|
|
515
516
|
})
|
|
516
517
|
);
|
|
@@ -571,7 +572,6 @@ function deadHooksAutoHealContext(cwd, home) {
|
|
|
571
572
|
clearHealFailureMarker(home, state.repoRoot);
|
|
572
573
|
return null;
|
|
573
574
|
}
|
|
574
|
-
var PIN_FILENAME = ".outerlayer-pin.json";
|
|
575
575
|
function sourceCachePath(gitCommonDir) {
|
|
576
576
|
return join(gitCommonDir, "outerlayer", "source.json");
|
|
577
577
|
}
|
|
@@ -579,8 +579,8 @@ function contextPossiblyGoverned(cwd, home = homeFromEnv()) {
|
|
|
579
579
|
try {
|
|
580
580
|
const found = findGitDirs(cwd);
|
|
581
581
|
if (found === void 0) return false;
|
|
582
|
-
const {
|
|
583
|
-
if (existsSync(join(
|
|
582
|
+
const { gitCommonDir } = found;
|
|
583
|
+
if (existsSync(join(gitCommonDir, "outerlayer", "delivery.json"))) return true;
|
|
584
584
|
if (!existsSync(join(home, ".outerlayer", "config.json"))) return false;
|
|
585
585
|
let cache;
|
|
586
586
|
try {
|
|
@@ -620,6 +620,50 @@ function recordDeliveredContext(cwd, sessionId, home) {
|
|
|
620
620
|
home
|
|
621
621
|
);
|
|
622
622
|
}
|
|
623
|
+
async function missingControlPlane(cwd, sessionId, home, env) {
|
|
624
|
+
const dirs = findGitDirs(cwd);
|
|
625
|
+
if (dirs === void 0) return void 0;
|
|
626
|
+
if (existsSync(join(dirs.gitCommonDir, "outerlayer", "materialized.json")) || hasExcludeBlock(dirs.gitCommonDir)) {
|
|
627
|
+
const { cleanupEarlierCopies } = await import('./context-cleanup-CHEWNYU6.js');
|
|
628
|
+
cleanupEarlierCopies(dirs);
|
|
629
|
+
}
|
|
630
|
+
if (!contextPossiblyGoverned(cwd, home)) return void 0;
|
|
631
|
+
const { governanceOf } = await import('./control-plane-launch-34LNRJWR.js');
|
|
632
|
+
if (await governanceOf({ cwd, env, home }) !== "governed") return void 0;
|
|
633
|
+
recordMissingContext(dirs, sessionId, home);
|
|
634
|
+
const launcher = `${cliInvocation()} claude`;
|
|
635
|
+
return {
|
|
636
|
+
person: `This repository's shared instructions and skills are missing from this session, because it did not start through \`${launcher}\`. Start Claude Code with \`${launcher}\`, or run \`${cliInvocation()} init\` once to make plain \`claude\` do the same.`,
|
|
637
|
+
agent: `This repository is governed by a control plane, and this session did not start through \`${launcher}\`, so the control plane's shared instructions and skills are not loaded. Tell the person to start Claude Code with \`${launcher}\`.`
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function recordMissingContext(dirs, sessionId, home) {
|
|
641
|
+
let cache;
|
|
642
|
+
try {
|
|
643
|
+
cache = JSON.parse(readFileSync(sourceCachePath(dirs.gitCommonDir), "utf8"));
|
|
644
|
+
} catch {
|
|
645
|
+
cache = {};
|
|
646
|
+
}
|
|
647
|
+
appendContextProvenance(
|
|
648
|
+
{
|
|
649
|
+
t: (/* @__PURE__ */ new Date()).toISOString(),
|
|
650
|
+
sessionId,
|
|
651
|
+
repoRoot: dirs.repoRoot,
|
|
652
|
+
...typeof cache.repository === "string" ? { repository: cache.repository } : {},
|
|
653
|
+
...typeof cache.ref === "string" ? { ref: cache.ref } : {},
|
|
654
|
+
sha: null,
|
|
655
|
+
verification: "none"
|
|
656
|
+
},
|
|
657
|
+
home
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
function hasExcludeBlock(gitCommonDir) {
|
|
661
|
+
try {
|
|
662
|
+
return readFileSync(join(gitCommonDir, "info", "exclude"), "utf8").includes("# BEGIN outerlayer context materialization");
|
|
663
|
+
} catch {
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
623
667
|
async function runHookFast(event, home = homeFromEnv(), read = readStdin, env = process.env, spawnImpl = spawnDetached) {
|
|
624
668
|
try {
|
|
625
669
|
const stdin = read();
|
|
@@ -649,7 +693,7 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
|
|
|
649
693
|
const hookSessionId = typeof payload.session_id === "string" ? payload.session_id : void 0;
|
|
650
694
|
await maybeRenewWorkLease(resolvedEvent, hookSessionId, home, env, spawnImpl, Date.now(), sessionCwd);
|
|
651
695
|
await handleWorkSessionEnd(resolvedEvent, hookSessionId, home, env, spawnImpl, sessionCwd);
|
|
652
|
-
let
|
|
696
|
+
let missingPlane;
|
|
653
697
|
let deadHooksMessage;
|
|
654
698
|
let workLaunchMessage;
|
|
655
699
|
let hookErrorsMessage;
|
|
@@ -664,12 +708,9 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
|
|
|
664
708
|
} catch (err) {
|
|
665
709
|
logHookError(home, err);
|
|
666
710
|
}
|
|
667
|
-
} else
|
|
711
|
+
} else {
|
|
668
712
|
try {
|
|
669
|
-
|
|
670
|
-
const sessionId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
|
|
671
|
-
const result = await materialize({ cwd: sessionCwd, sessionId, home });
|
|
672
|
-
materializeMessage = result.message;
|
|
713
|
+
missingPlane = await missingControlPlane(sessionCwd, typeof payload.session_id === "string" ? payload.session_id : "unknown", home, env);
|
|
673
714
|
} catch (err) {
|
|
674
715
|
logHookError(home, err);
|
|
675
716
|
}
|
|
@@ -697,7 +738,8 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
|
|
|
697
738
|
home,
|
|
698
739
|
sessionCwd,
|
|
699
740
|
(out) => process.stdout.write(out),
|
|
700
|
-
|
|
741
|
+
missingPlane?.person,
|
|
742
|
+
[missingPlane?.agent, deadHooksMessage, workLaunchMessage, hookErrorsMessage, renewalHookMessage].filter(
|
|
701
743
|
(s) => s !== void 0
|
|
702
744
|
)
|
|
703
745
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { builtinKind } from './chunk-
|
|
3
|
+
import { builtinKind } from './chunk-P53VEAOF.js';
|
|
4
4
|
import { parseSize } from './chunk-7RQ73DLO.js';
|
|
5
5
|
import { runnerDir } from './chunk-N2PXGQRL.js';
|
|
6
6
|
import { dirname } from 'path';
|