@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
|
@@ -1,25 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
+
import { parseTrackerNumber } from './chunk-WZBHBH3J.js';
|
|
3
4
|
import { mkdirSync, appendFileSync, readFileSync } from 'fs';
|
|
4
5
|
import { join } from 'path';
|
|
5
6
|
|
|
6
7
|
createRequire(import.meta.url);
|
|
7
|
-
|
|
8
|
-
// src/tracker-number.ts
|
|
9
|
-
var MAX_TRACKER_NUMBER = Number.MAX_SAFE_INTEGER;
|
|
10
|
-
function parseTrackerNumber(raw) {
|
|
11
|
-
if (raw === void 0) return void 0;
|
|
12
|
-
const text = typeof raw === "number" ? String(raw) : raw;
|
|
13
|
-
if (!/^\d+$/.test(text)) return void 0;
|
|
14
|
-
const n = Number(text);
|
|
15
|
-
if (!Number.isSafeInteger(n) || n <= 0) return void 0;
|
|
16
|
-
return n;
|
|
17
|
-
}
|
|
18
|
-
function trackerNumberError(flag, raw) {
|
|
19
|
-
return `invalid ${flag} "${raw}" \u2014 expected a positive integer no larger than ${MAX_TRACKER_NUMBER}`;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// src/work-launch.ts
|
|
23
8
|
var HOW_TO_CREATE_AN_ITEM = "outerlayer work add";
|
|
24
9
|
function parseWorkItemEnv(raw) {
|
|
25
10
|
if (raw === void 0) return { reason: "OUTERLAYER_WORK is not set" };
|
|
@@ -93,4 +78,4 @@ function readLaunchSpoolState(home, readImpl = readLaunchSpool) {
|
|
|
93
78
|
return { ids, ...malformedLines > 0 ? { malformedLines } : {} };
|
|
94
79
|
}
|
|
95
80
|
|
|
96
|
-
export { appendLaunchRecord, launchStatusIsDecisive, launchedItemForSession, launchesPath,
|
|
81
|
+
export { appendLaunchRecord, launchStatusIsDecisive, launchedItemForSession, launchesPath, parseWorkItemEnv, readLaunchSpoolState };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { startTimeOf, isSameProcess } from './chunk-OZ7C3XUE.js';
|
|
4
4
|
import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-JJP7YLMN.js';
|
|
5
|
-
import { postJson, WorkCommandError } from './chunk-
|
|
5
|
+
import { postJson, WorkCommandError } from './chunk-Q6CL5THG.js';
|
|
6
6
|
import { relative, dirname, delimiter, join } from 'path';
|
|
7
7
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, openSync, statSync, closeSync, readdirSync } from 'fs';
|
|
8
8
|
import { spawn } from 'child_process';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
4
|
-
import {
|
|
4
|
+
import { readFileSync, readdirSync, existsSync, mkdirSync, writeFileSync, unlinkSync, chmodSync } from 'fs';
|
|
5
5
|
import { join, isAbsolute, dirname, basename, resolve } from 'path';
|
|
6
6
|
import { execFileSync } from 'child_process';
|
|
7
7
|
|
|
@@ -74,137 +74,7 @@ function contextExcludesPresent(gitCommonDir) {
|
|
|
74
74
|
if (beginIdx === -1) return false;
|
|
75
75
|
return BLOCK_LINES.every((l, i) => lines[beginIdx + i] === l);
|
|
76
76
|
}
|
|
77
|
-
var
|
|
78
|
-
var POST_REWRITE_VERSION = `${POST_REWRITE_MARKER} v1`;
|
|
79
|
-
var POST_REWRITE_HOOK_SCRIPT = `#!/bin/sh
|
|
80
|
-
${POST_REWRITE_VERSION}
|
|
81
|
-
# Appends exact old->new commit pairs (amend/rebase, incl. squashes) to the
|
|
82
|
-
# OuterLayer spool so rewritten history stays creditable to the recorded
|
|
83
|
-
# sessions that produced it. Always exits 0: journaling must never break a
|
|
84
|
-
# rebase.
|
|
85
|
-
# On a machine without OuterLayer (this hook can be committed into a repo
|
|
86
|
-
# and run for every contributor) there is nothing to journal and no reason
|
|
87
|
-
# to create ~/.outerlayer: bow out before touching the filesystem.
|
|
88
|
-
[ -n "$OUTERLAYER_SPOOL_DIR" ] || [ -d "$HOME/.outerlayer" ] || exit 0
|
|
89
|
-
SPOOL_DIR="\${OUTERLAYER_SPOOL_DIR:-$HOME/.outerlayer/spool}"
|
|
90
|
-
mkdir -p "$SPOOL_DIR" 2>/dev/null || exit 0
|
|
91
|
-
FILE="$SPOOL_DIR/rewrites.jsonl"
|
|
92
|
-
if [ -f "$FILE" ] && [ "$(wc -c < "$FILE" 2>/dev/null || echo 0)" -gt 5242880 ]; then
|
|
93
|
-
mv -f "$FILE" "$FILE.1" 2>/dev/null || true
|
|
94
|
-
fi
|
|
95
|
-
REPO="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)"
|
|
96
|
-
if [ -z "$REPO" ]; then
|
|
97
|
-
REPO="$(git rev-parse --git-common-dir 2>/dev/null)" || exit 0
|
|
98
|
-
case "$REPO" in /*) ;; *) REPO="$PWD/$REPO" ;; esac
|
|
99
|
-
fi
|
|
100
|
-
TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
101
|
-
awk -v repo="$REPO" -v ts="$TS" -v src="$1" '
|
|
102
|
-
NF >= 2 && $1 ~ /^[0-9a-f]+$/ && $2 ~ /^[0-9a-f]+$/ {
|
|
103
|
-
pairs = pairs (n ? "," : "") "[\\"" $1 "\\",\\"" $2 "\\"]"; n++
|
|
104
|
-
}
|
|
105
|
-
END {
|
|
106
|
-
if (n) {
|
|
107
|
-
gsub(/\\\\/, "\\\\\\\\", repo); gsub(/"/, "\\\\\\"", repo)
|
|
108
|
-
printf "{\\"t\\":\\"%s\\",\\"repo\\":\\"%s\\",\\"source\\":\\"%s\\",\\"pairs\\":[%s]}\\n", ts, repo, src, pairs
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
' >> "$FILE" 2>/dev/null || true
|
|
112
|
-
exit 0
|
|
113
|
-
`;
|
|
114
|
-
var POST_COMMIT_HOOK_SCRIPT = `#!/bin/sh
|
|
115
|
-
${POST_REWRITE_VERSION}
|
|
116
|
-
# Appends every commit's SHA to the OuterLayer spool the moment it exists,
|
|
117
|
-
# so a session whose transcript lost git's porcelain line (piped or muted
|
|
118
|
-
# output) can still be credited at sync time. Always exits 0.
|
|
119
|
-
# On a machine without OuterLayer (this hook can be committed into a repo
|
|
120
|
-
# and run for every contributor) there is nothing to journal and no reason
|
|
121
|
-
# to create ~/.outerlayer: bow out before touching the filesystem.
|
|
122
|
-
[ -n "$OUTERLAYER_SPOOL_DIR" ] || [ -d "$HOME/.outerlayer" ] || exit 0
|
|
123
|
-
SPOOL_DIR="\${OUTERLAYER_SPOOL_DIR:-$HOME/.outerlayer/spool}"
|
|
124
|
-
mkdir -p "$SPOOL_DIR" 2>/dev/null || exit 0
|
|
125
|
-
FILE="$SPOOL_DIR/commits.jsonl"
|
|
126
|
-
if [ -f "$FILE" ] && [ "$(wc -c < "$FILE" 2>/dev/null || echo 0)" -gt 5242880 ]; then
|
|
127
|
-
mv -f "$FILE" "$FILE.1" 2>/dev/null || true
|
|
128
|
-
fi
|
|
129
|
-
REPO="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)"
|
|
130
|
-
if [ -z "$REPO" ]; then
|
|
131
|
-
REPO="$(git rev-parse --git-common-dir 2>/dev/null)" || exit 0
|
|
132
|
-
case "$REPO" in /*) ;; *) REPO="$PWD/$REPO" ;; esac
|
|
133
|
-
fi
|
|
134
|
-
SHA="$(git rev-parse HEAD 2>/dev/null)" || exit 0
|
|
135
|
-
TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
136
|
-
case "$SHA" in
|
|
137
|
-
*[!0-9a-f]*) exit 0 ;;
|
|
138
|
-
esac
|
|
139
|
-
REPO_ESCAPED=$(printf '%s' "$REPO" | sed -e 's/\\\\/\\\\\\\\/g' -e 's/"/\\\\"/g')
|
|
140
|
-
printf '{"t":"%s","repo":"%s","sha":"%s"}
|
|
141
|
-
' "$TS" "$REPO_ESCAPED" "$SHA" >> "$FILE" 2>/dev/null || true
|
|
142
|
-
exit 0
|
|
143
|
-
`;
|
|
144
|
-
var PREPARE_COMMIT_MSG_HOOK_SCRIPT = `#!/bin/sh
|
|
145
|
-
${POST_REWRITE_VERSION}
|
|
146
|
-
# Appends "OuterLayer-Session: <id>" to commits made during a recorded agent
|
|
147
|
-
# session, so the commit itself carries the session identity through squash
|
|
148
|
-
# and cross-machine rebases (the server-side trailer tier parses it). Stamps
|
|
149
|
-
# NOTHING outside a session: the agent env marker is required, and the id
|
|
150
|
-
# comes from the shell's own session variable \u2014 exact, because the commit
|
|
151
|
-
# process is a child of the session that issued it \u2014 with the spool journal
|
|
152
|
-
# as the fallback for harnesses that don't export one. Always exits 0.
|
|
153
|
-
# The journal-fallback selection rules mirror detectActiveSession in
|
|
154
|
-
# packages/cli/src/session-detect.ts \u2014 keep them in step.
|
|
155
|
-
[ -n "$OUTERLAYER_NO_TRAILER" ] && exit 0
|
|
156
|
-
[ -n "$CLAUDECODE" ] || exit 0
|
|
157
|
-
MSG_FILE="$1"
|
|
158
|
-
[ -f "$MSG_FILE" ] || exit 0
|
|
159
|
-
grep -qi '^outerlayer-session:' "$MSG_FILE" 2>/dev/null && exit 0
|
|
160
|
-
SID="$CLAUDE_CODE_SESSION_ID"
|
|
161
|
-
case "$SID" in
|
|
162
|
-
*[!0-9a-fA-F-]*) SID="" ;;
|
|
163
|
-
esac
|
|
164
|
-
if [ -n "$SID" ]; then
|
|
165
|
-
printf '\\nOuterLayer-Session: %s\\n' "$SID" >> "$MSG_FILE" 2>/dev/null || true
|
|
166
|
-
exit 0
|
|
167
|
-
fi
|
|
168
|
-
SPOOL_DIR="\${OUTERLAYER_SPOOL_DIR:-$HOME/.outerlayer/spool}"
|
|
169
|
-
EVENTS="$SPOOL_DIR/events.jsonl"
|
|
170
|
-
[ -f "$EVENTS" ] || exit 0
|
|
171
|
-
TOP="$(git rev-parse --show-toplevel 2>/dev/null)" || exit 0
|
|
172
|
-
[ -n "$TOP" ] || exit 0
|
|
173
|
-
TOP_REAL="$(cd "$TOP" 2>/dev/null && pwd -P)" || TOP_REAL="$TOP"
|
|
174
|
-
CUTOFF="$(date -u -v-24H +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo 1970-01-01T00:00:00Z)"
|
|
175
|
-
SID="$(tail -c 65536 "$EVENTS" 2>/dev/null | awk -v top="$TOP" -v topr="$TOP_REAL" -v cutoff="$CUTOFF" '
|
|
176
|
-
function field(line, key, re, v) {
|
|
177
|
-
re = "\\"" key "\\":\\"[^\\"]*\\""
|
|
178
|
-
if (match(line, re) == 0) return ""
|
|
179
|
-
v = substr(line, RSTART, RLENGTH)
|
|
180
|
-
sub("^\\"" key "\\":\\"", "", v); sub("\\"$", "", v)
|
|
181
|
-
return v
|
|
182
|
-
}
|
|
183
|
-
# macOS spells one directory two ways (/var is a symlink to /private/var);
|
|
184
|
-
# git reports the resolved form while the session recorded the launch
|
|
185
|
-
# spelling, so both sides normalize before comparing.
|
|
186
|
-
function norm(p) { sub(/^\\/private\\//, "/", p); return p }
|
|
187
|
-
function cwdMatches(c, cn, tn, rn) {
|
|
188
|
-
cn = norm(c); tn = norm(top); rn = norm(topr)
|
|
189
|
-
return cn == tn || cn == rn || index(cn, tn "/") == 1 || index(cn, rn "/") == 1
|
|
190
|
-
}
|
|
191
|
-
/^\\{/ {
|
|
192
|
-
sid = field($0, "sessionId"); if (sid == "") next
|
|
193
|
-
ev = field($0, "event")
|
|
194
|
-
if (ev == "SessionEnd") { ended[sid] = 1; next }
|
|
195
|
-
t = field($0, "t"); c = field($0, "cwd")
|
|
196
|
-
if (t >= cutoff && cwdMatches(c)) { lastAt[sid] = NR }
|
|
197
|
-
}
|
|
198
|
-
END {
|
|
199
|
-
best = ""; bestNr = 0
|
|
200
|
-
for (sid in lastAt) if (!ended[sid] && lastAt[sid] > bestNr) { best = sid; bestNr = lastAt[sid] }
|
|
201
|
-
if (best != "" && best ~ /^[0-9a-fA-F-]+$/) print best
|
|
202
|
-
}
|
|
203
|
-
')"
|
|
204
|
-
[ -n "$SID" ] || exit 0
|
|
205
|
-
printf '\\nOuterLayer-Session: %s\\n' "$SID" >> "$MSG_FILE" 2>/dev/null || true
|
|
206
|
-
exit 0
|
|
207
|
-
`;
|
|
77
|
+
var JOURNAL_HOOK_MARKER = "# outerlayer post-rewrite journal";
|
|
208
78
|
var PRE_COMMIT_GUARD_MARKER = "# outerlayer materialized-context commit guard";
|
|
209
79
|
var PRE_COMMIT_GUARD_VERSION = `${PRE_COMMIT_GUARD_MARKER} v1`;
|
|
210
80
|
var PRE_COMMIT_GUARD_BODY_SIGNATURE = "outerlayer: refusing to commit materialized control-plane context";
|
|
@@ -242,12 +112,7 @@ echo " $REMEDY" >&2
|
|
|
242
112
|
exit 1
|
|
243
113
|
`;
|
|
244
114
|
function managedHookScripts() {
|
|
245
|
-
return [
|
|
246
|
-
["post-rewrite", printableHookScript(POST_REWRITE_HOOK_SCRIPT)],
|
|
247
|
-
["post-commit", printableHookScript(POST_COMMIT_HOOK_SCRIPT)],
|
|
248
|
-
["prepare-commit-msg", printableHookScript(PREPARE_COMMIT_MSG_HOOK_SCRIPT)],
|
|
249
|
-
["pre-commit", printableHookScript(PRE_COMMIT_GUARD_SCRIPT)]
|
|
250
|
-
];
|
|
115
|
+
return [["pre-commit", printableHookScript(PRE_COMMIT_GUARD_SCRIPT)]];
|
|
251
116
|
}
|
|
252
117
|
function printableHookScript(script) {
|
|
253
118
|
const lines = script.split("\n");
|
|
@@ -299,32 +164,6 @@ function installHookFile(dir, name, script, marker) {
|
|
|
299
164
|
chmodSync(path, 493);
|
|
300
165
|
return existing === void 0 ? "installed" : "updated";
|
|
301
166
|
}
|
|
302
|
-
function installPostRewriteHook(cwd, opts) {
|
|
303
|
-
const stampTrailers = opts?.stampTrailers ?? true;
|
|
304
|
-
const inRepo = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
305
|
-
if (inRepo !== "true") return { status: "not-a-repo" };
|
|
306
|
-
if ((git(cwd, ["config", "core.hooksPath"]) ?? "") !== "") {
|
|
307
|
-
return { status: "skipped-custom-hooks-path" };
|
|
308
|
-
}
|
|
309
|
-
const dir = hooksDir(cwd);
|
|
310
|
-
if (dir === void 0) return { status: "not-a-repo" };
|
|
311
|
-
const pairOutcomes = [
|
|
312
|
-
installHookFile(dir, "post-rewrite", POST_REWRITE_HOOK_SCRIPT, POST_REWRITE_MARKER),
|
|
313
|
-
installHookFile(dir, "post-commit", POST_COMMIT_HOOK_SCRIPT, POST_REWRITE_MARKER)
|
|
314
|
-
];
|
|
315
|
-
const outcomes = [...pairOutcomes];
|
|
316
|
-
if (stampTrailers) {
|
|
317
|
-
outcomes.push(installHookFile(dir, "prepare-commit-msg", PREPARE_COMMIT_MSG_HOOK_SCRIPT, POST_REWRITE_MARKER));
|
|
318
|
-
} else {
|
|
319
|
-
removeOurHookFile(join(dir, "prepare-commit-msg"), POST_REWRITE_MARKER);
|
|
320
|
-
}
|
|
321
|
-
const path = join(dir, "post-rewrite");
|
|
322
|
-
if (pairOutcomes.every((o) => o === "skipped-foreign")) return { status: "skipped-foreign", path };
|
|
323
|
-
if (outcomes.every((o) => o === "unchanged")) return { status: "unchanged", path };
|
|
324
|
-
if (outcomes.includes("updated")) return { status: "updated", path };
|
|
325
|
-
if (outcomes.includes("installed")) return { status: "installed", path };
|
|
326
|
-
return { status: "skipped-foreign", path };
|
|
327
|
-
}
|
|
328
167
|
function removeOurHookFile(path, marker) {
|
|
329
168
|
if (!existsSync(path)) return false;
|
|
330
169
|
let content;
|
|
@@ -341,33 +180,14 @@ function isOwnRecognitionLine(content, marker) {
|
|
|
341
180
|
const secondLine = content.split("\n", 2)[1];
|
|
342
181
|
return secondLine !== void 0 && secondLine.startsWith(marker);
|
|
343
182
|
}
|
|
344
|
-
function
|
|
183
|
+
function removeJournalHooks(cwd) {
|
|
345
184
|
const dir = hooksDir(cwd);
|
|
346
185
|
if (dir === void 0) return { removed: false };
|
|
347
186
|
let removed = false;
|
|
348
187
|
for (const name of ["post-rewrite", "post-commit", "prepare-commit-msg"]) {
|
|
349
|
-
if (removeOurHookFile(join(dir, name),
|
|
188
|
+
if (removeOurHookFile(join(dir, name), JOURNAL_HOOK_MARKER)) removed = true;
|
|
350
189
|
}
|
|
351
|
-
return { removed, path:
|
|
352
|
-
}
|
|
353
|
-
function postRewriteHookPresence(cwd) {
|
|
354
|
-
const inRepo = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
355
|
-
if (inRepo !== "true") return "not-a-repo";
|
|
356
|
-
if ((git(cwd, ["config", "core.hooksPath"]) ?? "") !== "") return "custom-hooks-path";
|
|
357
|
-
const dir = hooksDir(cwd);
|
|
358
|
-
if (dir === void 0) return "not-a-repo";
|
|
359
|
-
const states = ["post-rewrite", "post-commit"].map((name) => {
|
|
360
|
-
let content;
|
|
361
|
-
try {
|
|
362
|
-
content = readFileSync(join(dir, name), "utf8");
|
|
363
|
-
} catch {
|
|
364
|
-
return "absent";
|
|
365
|
-
}
|
|
366
|
-
return content.includes(POST_REWRITE_MARKER) ? "ours" : "foreign";
|
|
367
|
-
});
|
|
368
|
-
if (states.every((st) => st === "ours")) return "ours";
|
|
369
|
-
if (states.includes("foreign")) return "foreign";
|
|
370
|
-
return "absent";
|
|
190
|
+
return { removed, path: dir };
|
|
371
191
|
}
|
|
372
192
|
function installPreCommitGuardHook(cwd) {
|
|
373
193
|
const inRepo = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
@@ -469,4 +289,4 @@ function huskyPrepareScript(repoRoot) {
|
|
|
469
289
|
return null;
|
|
470
290
|
}
|
|
471
291
|
|
|
472
|
-
export { contextExcludesPresent, deadHooksState, ensureContextExcludes, ensurePreCommitGuardHook, huskyPrepareScript,
|
|
292
|
+
export { contextExcludesPresent, deadHooksState, ensureContextExcludes, ensurePreCommitGuardHook, huskyPrepareScript, installPreCommitGuardHook, managedHookScripts, preparePackageManagerCommand, removeJournalHooks, removePreCommitGuardHook };
|
|
@@ -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 } from 'fs';
|
|
6
6
|
import { spawn } from 'child_process';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { deadHooksState, huskyPrepareScript, preparePackageManagerCommand } from './chunk-
|
|
3
|
+
import { deadHooksState, huskyPrepareScript, preparePackageManagerCommand } from './chunk-I3ETLSNE.js';
|
|
4
4
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
5
5
|
import { readFileSync, mkdirSync, writeFileSync, renameSync, existsSync, statSync, appendFileSync, openSync, opendirSync, unlinkSync } from 'fs';
|
|
6
6
|
import { spawn, execFileSync } from 'child_process';
|
|
@@ -385,7 +385,7 @@ function hookErrorsContext(home, writtenBytes, seenBytes) {
|
|
|
385
385
|
}
|
|
386
386
|
async function handleWorkLaunch(sessionId, home, env, spawnImpl = spawnDetached) {
|
|
387
387
|
if (!sessionId || env.OUTERLAYER_WORK === void 0) return void 0;
|
|
388
|
-
const { parseWorkItemEnv, appendLaunchRecord } = await import('./work-launch-
|
|
388
|
+
const { parseWorkItemEnv, appendLaunchRecord } = await import('./work-launch-LT663PB3.js');
|
|
389
389
|
const parsed = parseWorkItemEnv(env.OUTERLAYER_WORK);
|
|
390
390
|
if ("reason" in parsed) {
|
|
391
391
|
logHookError(home, new Error(`OUTERLAYER_WORK ignored: ${parsed.reason}`));
|
|
@@ -597,7 +597,7 @@ async function runHookFast(event, home = homeFromEnv(), read = readStdin, env =
|
|
|
597
597
|
recordHookErrorsSeen(home, hookErrorsBytes);
|
|
598
598
|
if (contextPossiblyGoverned(sessionCwd, home)) {
|
|
599
599
|
try {
|
|
600
|
-
const { materializeContext: materialize } = await import('./context-materialize-
|
|
600
|
+
const { materializeContext: materialize } = await import('./context-materialize-6WKT3RBQ.js');
|
|
601
601
|
const sessionId = typeof payload.session_id === "string" ? payload.session_id : "unknown";
|
|
602
602
|
const result = await materialize({ cwd: sessionCwd, sessionId, home });
|
|
603
603
|
materializeMessage = result.message;
|
|
@@ -647,4 +647,4 @@ function logHookError(home, err) {
|
|
|
647
647
|
}
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
-
export { AUTO_SYNC_DEBOUNCE_MS, SYNC_STALE_AFTER_MS, WORK_ADD_RETRIES, assessSyncHealth, checkInstalledCliStaleness, contextPossiblyGoverned, formatAgo, handleWorkLaunch, hookFiredMarkerPath, maybeAutoSync, readSyncStatus, refreshCommand, runHookFast, sanitizeForContext, spoolDir, workspaceRootOf, writeSyncStatus };
|
|
650
|
+
export { AUTO_SYNC_DEBOUNCE_MS, SYNC_STALE_AFTER_MS, WORK_ADD_RETRIES, assessSyncHealth, checkInstalledCliStaleness, contextPossiblyGoverned, formatAgo, handleWorkLaunch, hookFiredMarkerPath, installedCliDistDir, maybeAutoSync, readSyncStatus, refreshCommand, runHookFast, sanitizeForContext, spoolDir, workspaceRootOf, writeSyncStatus };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { detectActiveSession } from './chunk-U32VSRLO.js';
|
|
4
|
+
import { resolveRepoIdentity } from './chunk-4TNZMO7V.js';
|
|
5
|
+
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
5
6
|
import { readCloudConfig } from './chunk-TFUIDMOB.js';
|
|
6
7
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
7
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
4
4
|
import { existsSync, readFileSync, mkdirSync, copyFileSync, writeFileSync } from 'fs';
|
|
5
|
-
import { join, dirname } from 'path';
|
|
5
|
+
import { join, dirname, isAbsolute } from 'path';
|
|
6
6
|
|
|
7
7
|
createRequire(import.meta.url);
|
|
8
8
|
var REGISTERED_EVENTS = ["SessionStart", "SessionEnd", "Stop"];
|
|
@@ -46,14 +46,20 @@ function quoteBin(bin) {
|
|
|
46
46
|
function isOurBin(bin, cliBin) {
|
|
47
47
|
if (cliBin !== void 0 && normalizeBinPath(bin) === normalizeBinPath(cliBin)) return true;
|
|
48
48
|
const parts = bin.replace(/\\/g, "/").split("/");
|
|
49
|
+
if (isPublishedPackageBin(parts)) return true;
|
|
49
50
|
const base = (parts.pop() ?? "").toLowerCase();
|
|
50
51
|
if (base === "outerlayer" || base === "outerlayer.exe" || base === "outerlayer.cmd") return true;
|
|
51
52
|
return parts.some((p) => p.toLowerCase() === ".outerlayer");
|
|
52
53
|
}
|
|
54
|
+
function isPublishedPackageBin(parts) {
|
|
55
|
+
const n = parts.length;
|
|
56
|
+
if (n === 2 && parts[0] === "@outerlayer" && /^cli(@[^/]+)?$/.test(parts[1])) return true;
|
|
57
|
+
return parts[n - 4] === "@outerlayer" && parts[n - 3] === "cli" && parts[n - 2] === "dist" && parts[n - 1] === "index.js";
|
|
58
|
+
}
|
|
53
59
|
function normalizeBinPath(bin) {
|
|
54
60
|
return bin.replace(/\\/g, "/");
|
|
55
61
|
}
|
|
56
|
-
function
|
|
62
|
+
function splitCliInvocation(command, cliBin) {
|
|
57
63
|
if (typeof command !== "string") return null;
|
|
58
64
|
const tokens = tokenizeCommand(command.trim());
|
|
59
65
|
if (!tokens) return null;
|
|
@@ -62,7 +68,25 @@ function parseCliInvocation(command, cliBin) {
|
|
|
62
68
|
if (launcher === "node" || launcher === "node.exe" || launcher === "npx") i = 1;
|
|
63
69
|
const bin = tokens[i];
|
|
64
70
|
if (!bin || !isOurBin(bin, cliBin)) return null;
|
|
65
|
-
return tokens.slice(i + 1);
|
|
71
|
+
return { bin, args: tokens.slice(i + 1), viaNpx: launcher === "npx" };
|
|
72
|
+
}
|
|
73
|
+
function parseCliInvocation(command, cliBin) {
|
|
74
|
+
return splitCliInvocation(command, cliBin)?.args ?? null;
|
|
75
|
+
}
|
|
76
|
+
function ourCommandBins(settings) {
|
|
77
|
+
const bins = [];
|
|
78
|
+
const add = (command) => {
|
|
79
|
+
const parsed = splitCliInvocation(command);
|
|
80
|
+
if (!parsed || parsed.viaNpx) return;
|
|
81
|
+
if (!["hook", "hook-wrap", "statusline"].includes(parsed.args[0] ?? "")) return;
|
|
82
|
+
if (parsed.bin.includes("$") || !isAbsolute(parsed.bin)) return;
|
|
83
|
+
if (!bins.includes(parsed.bin)) bins.push(parsed.bin);
|
|
84
|
+
};
|
|
85
|
+
for (const matchers of Object.values(settings?.hooks ?? {})) {
|
|
86
|
+
for (const matcher of matchers ?? []) for (const h of matcher.hooks ?? []) add(h.command);
|
|
87
|
+
}
|
|
88
|
+
add(settings?.statusLine?.command);
|
|
89
|
+
return bins;
|
|
66
90
|
}
|
|
67
91
|
function parseLifecycleHookCommand(command, cliBin) {
|
|
68
92
|
const args = parseCliInvocation(command, cliBin);
|
|
@@ -246,6 +270,28 @@ function wrapHooks(settings, cliBin, opts = {}) {
|
|
|
246
270
|
}
|
|
247
271
|
return { next, changed, wrapped };
|
|
248
272
|
}
|
|
273
|
+
function repointWrappedHooks(settings, cliBin) {
|
|
274
|
+
const next = settings ? structuredClone(settings) : {};
|
|
275
|
+
let changed = false;
|
|
276
|
+
if (!next.hooks || !cliBinResolvable(cliBin)) return { next, changed };
|
|
277
|
+
for (const matchers of Object.values(next.hooks)) {
|
|
278
|
+
for (const matcher of matchers ?? []) {
|
|
279
|
+
for (let hi = 0; hi < matcher.hooks.length; hi++) {
|
|
280
|
+
const h = matcher.hooks[hi];
|
|
281
|
+
const parsed = splitCliInvocation(h.command, cliBin);
|
|
282
|
+
if (!parsed || parsed.args[0] !== "hook-wrap") continue;
|
|
283
|
+
if (normalizeBinPath(parsed.bin) === normalizeBinPath(cliBin)) continue;
|
|
284
|
+
const original = wrappedOriginalCommand(h, cliBin);
|
|
285
|
+
if (original === null) continue;
|
|
286
|
+
const flag = parsed.args.includes("--capture-output") ? " --capture-output" : "";
|
|
287
|
+
const desired = `${quoteBin(cliBin)} hook-wrap --id ${encodeWrappedCommand(original)}${flag}`;
|
|
288
|
+
matcher.hooks[hi] = { ...h, command: desired, [WRAP_MARKER]: original };
|
|
289
|
+
changed = true;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return { next, changed };
|
|
294
|
+
}
|
|
249
295
|
function statuslineCommand(cliBin) {
|
|
250
296
|
return `${quoteBin(cliBin)} statusline`;
|
|
251
297
|
}
|
|
@@ -331,4 +377,4 @@ function unwrapHooks(settings, cliBin) {
|
|
|
331
377
|
return { next, changed, unwrapped };
|
|
332
378
|
}
|
|
333
379
|
|
|
334
|
-
export { AUTO_WRAP_EVENTS, REGISTERED_EVENTS, SettingsParseError, cliBinResolvable, decodeWrappedCommand, isOurHookCommand, isOurStatuslineSlot, listHookCandidates, mergeHooks, mergeStatusline, readSettings, removeHooks, removeStatusline, settingsPath, statuslineWrappedOriginal, unwrapHooks, wrapHooks, wrappedOriginalCommand, writeSettings };
|
|
380
|
+
export { AUTO_WRAP_EVENTS, REGISTERED_EVENTS, SettingsParseError, cliBinResolvable, decodeWrappedCommand, isOurHookCommand, isOurStatuslineSlot, listHookCandidates, mergeHooks, mergeStatusline, ourCommandBins, readSettings, removeHooks, removeStatusline, repointWrappedHooks, settingsPath, statuslineWrappedOriginal, unwrapHooks, wrapHooks, wrappedOriginalCommand, writeSettings };
|