@brainervirus/workit-cursor 8.1.0 → 8.3.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/.cursor-plugin/plugin.json +1 -1
- package/dist/cursor-session-start.js +865 -125
- package/dist/mcp-server.js +161 -53
- package/dist/workit-hook.js +869 -99
- package/package.json +3 -3
- package/skills/workit-ship/SKILL.md +14 -14
|
@@ -8572,9 +8572,27 @@ function patchId(cwd, base, head) {
|
|
|
8572
8572
|
const id = git(cwd, ["patch-id", "--stable"], { input: diff.stdout });
|
|
8573
8573
|
return line(id)?.split(/\s+/u)[0] ?? null;
|
|
8574
8574
|
}
|
|
8575
|
+
function remoteNames(cwd) {
|
|
8576
|
+
return (git(cwd, ["remote"]).stdout ?? "").split(/\r?\n/u).map((value) => value.trim()).filter(Boolean);
|
|
8577
|
+
}
|
|
8575
8578
|
function currentBranch(cwd) {
|
|
8576
8579
|
return line(git(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
|
|
8577
8580
|
}
|
|
8581
|
+
function pushRemoteName(cwd, branch) {
|
|
8582
|
+
const name = branch ?? currentBranch(cwd);
|
|
8583
|
+
const remotes = remoteNames(cwd);
|
|
8584
|
+
const candidates = [
|
|
8585
|
+
name ? config2(cwd, `branch.${name}.pushRemote`) : null,
|
|
8586
|
+
config2(cwd, "remote.pushDefault"),
|
|
8587
|
+
name ? config2(cwd, `branch.${name}.remote`) : null
|
|
8588
|
+
];
|
|
8589
|
+
for (const candidate of candidates)
|
|
8590
|
+
if (candidate && candidate !== "." && remotes.includes(candidate))
|
|
8591
|
+
return candidate;
|
|
8592
|
+
if (remotes.includes("origin"))
|
|
8593
|
+
return "origin";
|
|
8594
|
+
return remotes.length === 1 ? remotes[0] : null;
|
|
8595
|
+
}
|
|
8578
8596
|
var MAX_BUFFER, GIT_TIMEOUTS, git = (cwd, args, options = {}) => {
|
|
8579
8597
|
const result = spawnSync("git", args, {
|
|
8580
8598
|
cwd,
|
|
@@ -8603,13 +8621,44 @@ var MAX_BUFFER, GIT_TIMEOUTS, git = (cwd, args, options = {}) => {
|
|
|
8603
8621
|
const { atimeNs, mtimeNs } = fs.statSync(from, { bigint: true });
|
|
8604
8622
|
const seconds = (ns) => (Number(ns / 1000n) - 1) / 1e6;
|
|
8605
8623
|
fs.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
|
|
8606
|
-
};
|
|
8624
|
+
}, config2 = (cwd, key) => line(git(cwd, ["config", "--get", key]));
|
|
8607
8625
|
var init_rev = __esm(() => {
|
|
8608
8626
|
MAX_BUFFER = 256 * 1024 * 1024;
|
|
8609
8627
|
GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
|
|
8610
8628
|
MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
|
|
8611
8629
|
});
|
|
8612
8630
|
|
|
8631
|
+
// packages/workit-core/src/host-session.ts
|
|
8632
|
+
function hostSessionFromEnv(env) {
|
|
8633
|
+
const value = (key) => env[key]?.trim() || null;
|
|
8634
|
+
let inner = null;
|
|
8635
|
+
for (const [key, host] of HOST_SESSION_VARS) {
|
|
8636
|
+
const session = value(key);
|
|
8637
|
+
if (session) {
|
|
8638
|
+
inner = { host: host(env), session };
|
|
8639
|
+
break;
|
|
8640
|
+
}
|
|
8641
|
+
}
|
|
8642
|
+
const declared = value("WORKIT_HOST");
|
|
8643
|
+
if (env.WORKIT_SESSION_ID !== undefined) {
|
|
8644
|
+
const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
|
|
8645
|
+
if (!inherited)
|
|
8646
|
+
return { host: declared, session: value("WORKIT_SESSION_ID") };
|
|
8647
|
+
}
|
|
8648
|
+
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
8649
|
+
}
|
|
8650
|
+
var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
|
|
8651
|
+
var init_host_session = __esm(() => {
|
|
8652
|
+
HOST_SESSION_VARS = [
|
|
8653
|
+
["OPENCODE_SESSION_ID", () => "opencode"],
|
|
8654
|
+
["PI_SESSION_ID", () => "pi"],
|
|
8655
|
+
[
|
|
8656
|
+
"CODEX_THREAD_ID",
|
|
8657
|
+
(env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
|
|
8658
|
+
]
|
|
8659
|
+
];
|
|
8660
|
+
});
|
|
8661
|
+
|
|
8613
8662
|
// packages/workit-core/src/store/paths.ts
|
|
8614
8663
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
8615
8664
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -8952,6 +9001,74 @@ function ledgerPath(cwd) {
|
|
|
8952
9001
|
const root = storeRoot(cwd);
|
|
8953
9002
|
return root.ok ? { ok: true, value: path3.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
8954
9003
|
}
|
|
9004
|
+
function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
9005
|
+
const lock = `${file}.lock`;
|
|
9006
|
+
const deadline = Date.now() + waitMs;
|
|
9007
|
+
let token = null;
|
|
9008
|
+
for (;; ) {
|
|
9009
|
+
token = ledgerLock.acquire(lock);
|
|
9010
|
+
if (token)
|
|
9011
|
+
break;
|
|
9012
|
+
const observed = lockToken(lock);
|
|
9013
|
+
const age = lockAgeMs(lock);
|
|
9014
|
+
if (age !== null && age > LOCK_STALE_MS && ledgerLock.reap(lock, observed))
|
|
9015
|
+
continue;
|
|
9016
|
+
if (Date.now() >= deadline)
|
|
9017
|
+
return null;
|
|
9018
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
|
|
9019
|
+
}
|
|
9020
|
+
try {
|
|
9021
|
+
return fn();
|
|
9022
|
+
} finally {
|
|
9023
|
+
ledgerLock.release(lock, token);
|
|
9024
|
+
}
|
|
9025
|
+
}
|
|
9026
|
+
function appendLine(file, line, options) {
|
|
9027
|
+
const write = () => {
|
|
9028
|
+
const fd = fs3.openSync(file, "a+");
|
|
9029
|
+
try {
|
|
9030
|
+
const size = fs3.fstatSync(fd).size;
|
|
9031
|
+
let fence = "";
|
|
9032
|
+
if (size > 0) {
|
|
9033
|
+
const last = Buffer.alloc(1);
|
|
9034
|
+
fs3.readSync(fd, last, 0, 1, size - 1);
|
|
9035
|
+
if (last[0] !== 10)
|
|
9036
|
+
fence = `
|
|
9037
|
+
`;
|
|
9038
|
+
}
|
|
9039
|
+
const bytes = Buffer.from(fence + line);
|
|
9040
|
+
const written = fs3.writeSync(fd, bytes);
|
|
9041
|
+
if (written !== bytes.length)
|
|
9042
|
+
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
9043
|
+
return { ok: true, value: undefined };
|
|
9044
|
+
} finally {
|
|
9045
|
+
fs3.closeSync(fd);
|
|
9046
|
+
}
|
|
9047
|
+
};
|
|
9048
|
+
try {
|
|
9049
|
+
fs3.mkdirSync(path3.dirname(file), { recursive: true });
|
|
9050
|
+
if (!options.forceLock && !onNetworkFs(path3.dirname(file)))
|
|
9051
|
+
return write();
|
|
9052
|
+
const locked = withLedgerLock(file, write);
|
|
9053
|
+
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
9054
|
+
} catch (error) {
|
|
9055
|
+
return err("unavailable", `cannot append to ${file}: ${error.message}`);
|
|
9056
|
+
}
|
|
9057
|
+
}
|
|
9058
|
+
function appendRaw(cwd, row, options) {
|
|
9059
|
+
const { full, line } = serialize(row, options.now ?? new Date);
|
|
9060
|
+
const bytes = Buffer.byteLength(line);
|
|
9061
|
+
if (bytes > MAX_LINE_BYTES)
|
|
9062
|
+
return err("invalid_input", `ledger row is ${bytes} bytes; the limit is ${MAX_LINE_BYTES}. Shorten the text and pass details by --ref <path|url>`);
|
|
9063
|
+
const file = ledgerPath(cwd);
|
|
9064
|
+
if (!file.ok)
|
|
9065
|
+
return file;
|
|
9066
|
+
const written = appendLine(file.value, line, options);
|
|
9067
|
+
return written.ok ? { ok: true, value: full } : written;
|
|
9068
|
+
}
|
|
9069
|
+
function appendHookObserved(cwd, row) {
|
|
9070
|
+
return appendRaw(cwd, { ...row, observer: "host_hook" }, {});
|
|
9071
|
+
}
|
|
8955
9072
|
function supersedeAllowed(by, target) {
|
|
8956
9073
|
if (by.type !== target.type)
|
|
8957
9074
|
return `a ${by.type} row cannot supersede a ${target.type} row`;
|
|
@@ -9169,7 +9286,7 @@ function checkVerdicts(cwd, branch, rows) {
|
|
|
9169
9286
|
authors: [...authors].toSorted()
|
|
9170
9287
|
};
|
|
9171
9288
|
}
|
|
9172
|
-
var LEDGER_VERSION = 1, PASSING, FAILING, STRONG_RESULTS, PR_ROW_TYPES, err = (code, error, unblock) => ({
|
|
9289
|
+
var LEDGER_VERSION = 1, MAX_LINE_BYTES = 4096, PASSING, FAILING, STRONG_RESULTS, PR_ROW_TYPES, err = (code, error, unblock) => ({
|
|
9173
9290
|
ok: false,
|
|
9174
9291
|
code,
|
|
9175
9292
|
error,
|
|
@@ -9199,7 +9316,32 @@ var LEDGER_VERSION = 1, PASSING, FAILING, STRONG_RESULTS, PR_ROW_TYPES, err = (c
|
|
|
9199
9316
|
const run = gitRun2(cwd, args);
|
|
9200
9317
|
const value = run.ok ? run.stdout.trim() : "";
|
|
9201
9318
|
return value ? value : null;
|
|
9202
|
-
}, safeRef = (value) => value.length > 0 && !value.startsWith("-"),
|
|
9319
|
+
}, safeRef = (value) => value.length > 0 && !value.startsWith("-"), newId2 = () => `${Date.now().toString(36)}-${randomBytes(6).toString("hex")}`, NETWORK_FS_TYPES, isNetworkFsType = (type) => NETWORK_FS_TYPES.has(type >>> 0), onNetworkFs = (dir) => {
|
|
9320
|
+
if (process.platform !== "linux")
|
|
9321
|
+
return false;
|
|
9322
|
+
try {
|
|
9323
|
+
return isNetworkFsType(fs3.statfsSync(dir).type);
|
|
9324
|
+
} catch {
|
|
9325
|
+
return false;
|
|
9326
|
+
}
|
|
9327
|
+
}, LOCK_WAIT_MS = 5000, LOCK_STALE_MS = 30000, LOCK_OWNER = "owner", lockToken = (lock) => {
|
|
9328
|
+
try {
|
|
9329
|
+
return fs3.readFileSync(path3.join(lock, LOCK_OWNER), "utf8");
|
|
9330
|
+
} catch {
|
|
9331
|
+
return null;
|
|
9332
|
+
}
|
|
9333
|
+
}, lockAgeMs = (lock) => {
|
|
9334
|
+
for (const target of [path3.join(lock, LOCK_OWNER), lock]) {
|
|
9335
|
+
try {
|
|
9336
|
+
return Date.now() - fs3.statSync(target).mtimeMs;
|
|
9337
|
+
} catch {}
|
|
9338
|
+
}
|
|
9339
|
+
return null;
|
|
9340
|
+
}, ledgerLock, serialize = (row, now) => {
|
|
9341
|
+
const full = { v: LEDGER_VERSION, id: newId2(), at: now.toISOString(), ...row };
|
|
9342
|
+
return { full, line: `${JSON.stringify(full)}
|
|
9343
|
+
` };
|
|
9344
|
+
}, isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value), str = (value) => typeof value === "string" ? value : null, normalizeActor = (value) => {
|
|
9203
9345
|
const actor = isRecord(value) ? value : {};
|
|
9204
9346
|
return {
|
|
9205
9347
|
host: str(actor.host) ?? "unknown",
|
|
@@ -9218,6 +9360,7 @@ var LEDGER_VERSION = 1, PASSING, FAILING, STRONG_RESULTS, PR_ROW_TYPES, err = (c
|
|
|
9218
9360
|
}, OBSERVED_ONLY;
|
|
9219
9361
|
var init_ledger = __esm(() => {
|
|
9220
9362
|
init_rev();
|
|
9363
|
+
init_host_session();
|
|
9221
9364
|
init_paths();
|
|
9222
9365
|
PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
|
|
9223
9366
|
FAILING = new Set(["failed", "blocked"]);
|
|
@@ -9235,6 +9378,57 @@ var init_ledger = __esm(() => {
|
|
|
9235
9378
|
1196443219,
|
|
9236
9379
|
198183888
|
|
9237
9380
|
]);
|
|
9381
|
+
ledgerLock = {
|
|
9382
|
+
acquire(lock) {
|
|
9383
|
+
try {
|
|
9384
|
+
fs3.mkdirSync(lock);
|
|
9385
|
+
} catch (error) {
|
|
9386
|
+
if (error.code === "EEXIST")
|
|
9387
|
+
return null;
|
|
9388
|
+
throw error;
|
|
9389
|
+
}
|
|
9390
|
+
const token = `${process.pid}-${randomBytes(8).toString("hex")}`;
|
|
9391
|
+
fs3.writeFileSync(path3.join(lock, LOCK_OWNER), token);
|
|
9392
|
+
return token;
|
|
9393
|
+
},
|
|
9394
|
+
release(lock, token) {
|
|
9395
|
+
if (lockToken(lock) !== token)
|
|
9396
|
+
return false;
|
|
9397
|
+
const tomb = `${lock}.release-${randomBytes(6).toString("hex")}`;
|
|
9398
|
+
try {
|
|
9399
|
+
fs3.renameSync(lock, tomb);
|
|
9400
|
+
} catch {
|
|
9401
|
+
return false;
|
|
9402
|
+
}
|
|
9403
|
+
if (lockToken(tomb) !== token) {
|
|
9404
|
+
try {
|
|
9405
|
+
fs3.renameSync(tomb, lock);
|
|
9406
|
+
} catch {}
|
|
9407
|
+
return false;
|
|
9408
|
+
}
|
|
9409
|
+
fs3.rmSync(tomb, { recursive: true, force: true });
|
|
9410
|
+
return true;
|
|
9411
|
+
},
|
|
9412
|
+
token: lockToken,
|
|
9413
|
+
reap(lock, observed) {
|
|
9414
|
+
const tomb = `${lock}.reap-${randomBytes(6).toString("hex")}`;
|
|
9415
|
+
try {
|
|
9416
|
+
fs3.renameSync(lock, tomb);
|
|
9417
|
+
} catch {
|
|
9418
|
+
return false;
|
|
9419
|
+
}
|
|
9420
|
+
if (lockToken(tomb) === observed) {
|
|
9421
|
+
fs3.rmSync(tomb, { recursive: true, force: true });
|
|
9422
|
+
return true;
|
|
9423
|
+
}
|
|
9424
|
+
try {
|
|
9425
|
+
fs3.renameSync(tomb, lock);
|
|
9426
|
+
} catch {
|
|
9427
|
+
fs3.rmSync(tomb, { recursive: true, force: true });
|
|
9428
|
+
}
|
|
9429
|
+
return false;
|
|
9430
|
+
}
|
|
9431
|
+
};
|
|
9238
9432
|
OBSERVED_ONLY = new Set(["check", "merge.unverified", ...PR_ROW_TYPES]);
|
|
9239
9433
|
});
|
|
9240
9434
|
|
|
@@ -10217,6 +10411,7 @@ var init_branch_policy = __esm(() => {
|
|
|
10217
10411
|
});
|
|
10218
10412
|
|
|
10219
10413
|
// packages/workit-core/src/core/workspaces.ts
|
|
10414
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
10220
10415
|
import { createHash as createHash5 } from "node:crypto";
|
|
10221
10416
|
import { readFileSync as readFileSync2, realpathSync } from "node:fs";
|
|
10222
10417
|
import path6 from "node:path";
|
|
@@ -10336,6 +10531,46 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
10336
10531
|
};
|
|
10337
10532
|
}
|
|
10338
10533
|
return { ok: true };
|
|
10534
|
+
}, WorkspaceConfigError, mainCheckouts, mainCheckoutOf = (cwd) => {
|
|
10535
|
+
const cached = mainCheckouts.get(cwd);
|
|
10536
|
+
if (cached !== undefined)
|
|
10537
|
+
return cached;
|
|
10538
|
+
const env = { ...process.env };
|
|
10539
|
+
for (const name of ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"])
|
|
10540
|
+
delete env[name];
|
|
10541
|
+
const git = (args) => {
|
|
10542
|
+
const run = spawnSync5("git", args, {
|
|
10543
|
+
cwd,
|
|
10544
|
+
env,
|
|
10545
|
+
encoding: "utf8",
|
|
10546
|
+
timeout: 5000,
|
|
10547
|
+
windowsHide: true
|
|
10548
|
+
});
|
|
10549
|
+
return run.status === 0 ? run.stdout : null;
|
|
10550
|
+
};
|
|
10551
|
+
let main = null;
|
|
10552
|
+
const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
|
|
10553
|
+
const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
|
|
10554
|
+
if (gitDir && common && path6.resolve(gitDir) !== path6.resolve(common)) {
|
|
10555
|
+
const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
|
|
10556
|
+
main = listed?.trim() || (path6.basename(common) === ".git" ? path6.dirname(common) : common);
|
|
10557
|
+
}
|
|
10558
|
+
mainCheckouts.set(cwd, main);
|
|
10559
|
+
return main;
|
|
10560
|
+
}, matchingEntries = (cwd, entries) => {
|
|
10561
|
+
const match = (where) => {
|
|
10562
|
+
const targets = [where, realpathOf(where)].map((value) => value.replaceAll("\\", "/"));
|
|
10563
|
+
return entries.filter((entry) => {
|
|
10564
|
+
const glob = entry.glob.replaceAll("\\", "/");
|
|
10565
|
+
const canonical = canonicalGlob(glob);
|
|
10566
|
+
return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
|
|
10567
|
+
});
|
|
10568
|
+
};
|
|
10569
|
+
const direct = match(cwd);
|
|
10570
|
+
if (direct.length)
|
|
10571
|
+
return direct;
|
|
10572
|
+
const main = mainCheckoutOf(cwd);
|
|
10573
|
+
return main ? match(main) : direct;
|
|
10339
10574
|
}, realpathOf = (p) => {
|
|
10340
10575
|
const real = realpathSync.native ?? realpathSync;
|
|
10341
10576
|
try {
|
|
@@ -10357,41 +10592,27 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
10357
10592
|
if (named.length === 1)
|
|
10358
10593
|
return named[0];
|
|
10359
10594
|
if (named.length > 1)
|
|
10360
|
-
throw new
|
|
10595
|
+
throw new WorkspaceConfigError(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
|
|
10361
10596
|
if (matches.length > 0) {
|
|
10362
|
-
throw new
|
|
10597
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
|
|
10363
10598
|
}
|
|
10364
|
-
throw new
|
|
10599
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
|
|
10365
10600
|
}
|
|
10366
10601
|
if (matches.length < 2)
|
|
10367
10602
|
return matches[0];
|
|
10368
10603
|
const highestSpecificity = Math.max(...matches.map((entry) => globSpecificity(entry.glob)));
|
|
10369
10604
|
const mostSpecific = matches.filter((entry) => globSpecificity(entry.glob) === highestSpecificity);
|
|
10370
10605
|
if (mostSpecific.length > 1) {
|
|
10371
|
-
throw new
|
|
10606
|
+
throw new WorkspaceConfigError(`ambiguous workspace for ${cwd}; choose one of: ${mostSpecific.map((entry) => entry.name).join(", ")}`);
|
|
10372
10607
|
}
|
|
10373
10608
|
return mostSpecific[0];
|
|
10374
10609
|
}, resolveWorkspaceFromEntries = (cwd, entries, workspaceName) => {
|
|
10375
|
-
const
|
|
10376
|
-
const matches = [];
|
|
10377
|
-
for (const ws of entries) {
|
|
10378
|
-
const glob = ws.glob.replaceAll("\\", "/");
|
|
10379
|
-
const canonical = canonicalGlob(glob);
|
|
10380
|
-
let matched = false;
|
|
10381
|
-
for (const target of targets) {
|
|
10382
|
-
if (matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target)) {
|
|
10383
|
-
matched = true;
|
|
10384
|
-
break;
|
|
10385
|
-
}
|
|
10386
|
-
}
|
|
10387
|
-
if (matched)
|
|
10388
|
-
matches.push(ws);
|
|
10389
|
-
}
|
|
10610
|
+
const matches = matchingEntries(cwd, entries);
|
|
10390
10611
|
return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
|
|
10391
10612
|
}, resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
|
|
10392
10613
|
const result = readWorkspacesResult(dir);
|
|
10393
10614
|
if (result.status === "malformed" || result.status === "invalid")
|
|
10394
|
-
throw new
|
|
10615
|
+
throw new WorkspaceConfigError(result.error);
|
|
10395
10616
|
return resolveWorkspaceFromEntries(cwd, result.entries, workspaceName);
|
|
10396
10617
|
}, runtimeWorkspacePolicySchema = (kind) => {
|
|
10397
10618
|
const key = kind === "branch" ? "branchPolicy" : kind === "commit" ? "commitPolicy" : "vcs";
|
|
@@ -10409,7 +10630,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
10409
10630
|
profiles: record(nonBlank, profileSchema).optional()
|
|
10410
10631
|
}).passthrough();
|
|
10411
10632
|
return entrySchema;
|
|
10412
|
-
}, runtimeWorkspaceIndexSchema, matchRuntimeWorkspace = (cwd) => {
|
|
10633
|
+
}, resolveRuntimeWorkspaceVcs = (cwd) => resolveRuntimeWorkspaceCandidate(cwd, "vcs"), runtimeWorkspaceIndexSchema, matchRuntimeWorkspace = (cwd) => {
|
|
10413
10634
|
const file = path6.join(configDir(), "workspaces.json");
|
|
10414
10635
|
let raw;
|
|
10415
10636
|
try {
|
|
@@ -10417,31 +10638,26 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
10417
10638
|
} catch (error) {
|
|
10418
10639
|
if (error.code === "ENOENT")
|
|
10419
10640
|
return null;
|
|
10420
|
-
throw new
|
|
10641
|
+
throw new WorkspaceConfigError(`${file} could not be read: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
10421
10642
|
}
|
|
10422
10643
|
let parsed;
|
|
10423
10644
|
try {
|
|
10424
10645
|
parsed = JSON.parse(raw);
|
|
10425
10646
|
} catch {
|
|
10426
|
-
throw new
|
|
10647
|
+
throw new WorkspaceConfigError(`${file} is not valid JSON`);
|
|
10427
10648
|
}
|
|
10428
10649
|
const validated = runtimeWorkspaceIndexSchema.safeParse(parsed);
|
|
10429
10650
|
if (!validated.success) {
|
|
10430
10651
|
const detail = validated.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspaces"}: ${issue.message}`).join("; ");
|
|
10431
|
-
throw new
|
|
10652
|
+
throw new WorkspaceConfigError(`${file} has invalid workspace matching data: ${detail}`);
|
|
10432
10653
|
}
|
|
10433
10654
|
const entries = validated.data.workspaces;
|
|
10434
10655
|
for (const entry of entries ?? []) {
|
|
10435
10656
|
const glob = validateWorkspaceGlob(entry.glob);
|
|
10436
10657
|
if (!glob.ok)
|
|
10437
|
-
throw new
|
|
10658
|
+
throw new WorkspaceConfigError(`${file} workspace ${entry.name}: ${glob.error}`);
|
|
10438
10659
|
}
|
|
10439
|
-
const
|
|
10440
|
-
const matches = (entries ?? []).filter((entry) => {
|
|
10441
|
-
const glob = entry.glob.replaceAll("\\", "/");
|
|
10442
|
-
const canonical = canonicalGlob(glob);
|
|
10443
|
-
return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
|
|
10444
|
-
});
|
|
10660
|
+
const matches = matchingEntries(cwd, entries ?? []);
|
|
10445
10661
|
const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
|
|
10446
10662
|
const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
|
|
10447
10663
|
return selected ? { file, selected } : null;
|
|
@@ -10456,7 +10672,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
10456
10672
|
const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
|
|
10457
10673
|
if (!policy.success) {
|
|
10458
10674
|
const detail = policy.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspace"}: ${issue.message}`).join("; ");
|
|
10459
|
-
throw new
|
|
10675
|
+
throw new WorkspaceConfigError(`${file} has invalid ${kind} policy configuration: ${detail}`);
|
|
10460
10676
|
}
|
|
10461
10677
|
return policy.data;
|
|
10462
10678
|
}, resolveRuntimeWorkspacePolicy = (cwd, kind, requestedProfile) => {
|
|
@@ -10466,10 +10682,10 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
10466
10682
|
const key = kind === "branch" ? "branchPolicy" : "commitPolicy";
|
|
10467
10683
|
const profileName = requestedProfile?.trim() || candidate.defaultProfile;
|
|
10468
10684
|
if (candidate.defaultProfile && !Object.hasOwn(candidate.profiles ?? {}, candidate.defaultProfile))
|
|
10469
|
-
throw new
|
|
10685
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(candidate.name)} has no profile ${JSON.stringify(candidate.defaultProfile)}`);
|
|
10470
10686
|
const profile = profileName ? candidate.profiles?.[profileName] : undefined;
|
|
10471
10687
|
if (profileName && !profile)
|
|
10472
|
-
throw new
|
|
10688
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(candidate.name)} has no profile ${JSON.stringify(profileName)}`);
|
|
10473
10689
|
const profilePolicy = profile?.[key];
|
|
10474
10690
|
const workspacePolicy = candidate[key];
|
|
10475
10691
|
return {
|
|
@@ -10600,6 +10816,10 @@ var init_workspaces = __esm(() => {
|
|
|
10600
10816
|
});
|
|
10601
10817
|
UNSUPPORTED_GLOB = /[?[\]{}]/;
|
|
10602
10818
|
UNSUPPORTED_EXTGLOB = /[@+*]\(|!/;
|
|
10819
|
+
WorkspaceConfigError = class WorkspaceConfigError extends Error {
|
|
10820
|
+
name = "WorkspaceConfigError";
|
|
10821
|
+
};
|
|
10822
|
+
mainCheckouts = new Map;
|
|
10603
10823
|
runtimeWorkspaceIndexSchema = object({
|
|
10604
10824
|
workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
10605
10825
|
}).passthrough();
|
|
@@ -11378,7 +11598,7 @@ var packageRoot = () => {
|
|
|
11378
11598
|
var init_package_root = () => {};
|
|
11379
11599
|
|
|
11380
11600
|
// packages/workit-core/src/core/store-lock.ts
|
|
11381
|
-
import { spawnSync as
|
|
11601
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
11382
11602
|
import fs7 from "node:fs";
|
|
11383
11603
|
import { hostname } from "node:os";
|
|
11384
11604
|
var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, RECLAIM_GUARD_TTL_MS = 30000, defaultLockTimeoutMs = 250, defaultLockTimeout = () => defaultLockTimeoutMs, parseMetadataLock = (raw) => {
|
|
@@ -11413,7 +11633,7 @@ var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, REC
|
|
|
11413
11633
|
}
|
|
11414
11634
|
if (process.platform === "darwin" || process.platform === "freebsd") {
|
|
11415
11635
|
try {
|
|
11416
|
-
const run =
|
|
11636
|
+
const run = spawnSync6("ps", ["-o", "lstart=", "-p", String(pid)], {
|
|
11417
11637
|
encoding: "utf8",
|
|
11418
11638
|
timeout: 1000
|
|
11419
11639
|
});
|
|
@@ -13507,14 +13727,16 @@ var MIGRATION_PENDING = "workit migration pending", STORE_FORMAT = 3, STORE_MIN_
|
|
|
13507
13727
|
heldInProcess.delete(lock);
|
|
13508
13728
|
}, envActor = () => {
|
|
13509
13729
|
const value = (key) => process.env[key]?.trim() || null;
|
|
13730
|
+
const acting = hostSessionFromEnv(process.env);
|
|
13510
13731
|
return {
|
|
13511
|
-
host:
|
|
13512
|
-
session:
|
|
13732
|
+
host: acting.host ?? "runtime",
|
|
13733
|
+
session: acting.session,
|
|
13513
13734
|
agentId: value("WORKIT_AGENT_ID")
|
|
13514
13735
|
};
|
|
13515
13736
|
};
|
|
13516
13737
|
var init_task_store = __esm(() => {
|
|
13517
13738
|
init_file_lock();
|
|
13739
|
+
init_host_session();
|
|
13518
13740
|
init_package_root();
|
|
13519
13741
|
init_task_contract();
|
|
13520
13742
|
init_store_lock();
|
|
@@ -13535,7 +13757,7 @@ var init_workers = __esm(() => {
|
|
|
13535
13757
|
});
|
|
13536
13758
|
|
|
13537
13759
|
// packages/workit-core/src/check-config.ts
|
|
13538
|
-
import { spawnSync as
|
|
13760
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
13539
13761
|
import fs10 from "node:fs";
|
|
13540
13762
|
import path13 from "node:path";
|
|
13541
13763
|
function splitCommand(command) {
|
|
@@ -13703,7 +13925,7 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
13703
13925
|
return onPath ? `workit check ${args}` : `npx -y @brainervirus/workit-cli@${version} check ${args}`;
|
|
13704
13926
|
}
|
|
13705
13927
|
var SCRIPT_CHECKS, CHECKS_FILE = "workit.checks.json", isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SHELL_META, git3 = (cwd, args) => {
|
|
13706
|
-
const run =
|
|
13928
|
+
const run = spawnSync7("git", args, {
|
|
13707
13929
|
cwd,
|
|
13708
13930
|
encoding: "utf8",
|
|
13709
13931
|
timeout: 20000,
|
|
@@ -13738,7 +13960,7 @@ var init_check_config = __esm(() => {
|
|
|
13738
13960
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
13739
13961
|
import { createHash as createHash8 } from "node:crypto";
|
|
13740
13962
|
import * as fs11 from "node:fs";
|
|
13741
|
-
import { spawnSync as
|
|
13963
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
13742
13964
|
import path14 from "node:path";
|
|
13743
13965
|
function captureCandidate(root, scope, environment = []) {
|
|
13744
13966
|
let checkout;
|
|
@@ -13816,7 +14038,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
13816
14038
|
const values = supplied.toSorted((left, right) => compareCodeUnits3(left.name, right.name)).map(({ name, value }) => ({ name, value, refs: [] }));
|
|
13817
14039
|
if (values.some(({ value }) => value === null))
|
|
13818
14040
|
completeness = "uncertain";
|
|
13819
|
-
const headResult =
|
|
14041
|
+
const headResult = spawnSync8("git", ["rev-parse", "HEAD"], { cwd: checkout, encoding: "utf8" });
|
|
13820
14042
|
if (headResult.status !== 0 && !/not a git repository/i.test(headResult.stderr ?? ""))
|
|
13821
14043
|
completeness = "uncertain";
|
|
13822
14044
|
const head = headResult.status === 0 ? headResult.stdout.trim() : null;
|
|
@@ -14189,7 +14411,7 @@ var digestBytes = (value) => createHash8("sha256").update(value).digest("hex"),
|
|
|
14189
14411
|
}
|
|
14190
14412
|
return left.length - right.length;
|
|
14191
14413
|
}, gitPaths = (root) => {
|
|
14192
|
-
const result =
|
|
14414
|
+
const result = spawnSync8("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
|
|
14193
14415
|
cwd: root,
|
|
14194
14416
|
encoding: "buffer"
|
|
14195
14417
|
});
|
|
@@ -14202,7 +14424,7 @@ var digestBytes = (value) => createHash8("sha256").update(value).digest("hex"),
|
|
|
14202
14424
|
};
|
|
14203
14425
|
}
|
|
14204
14426
|
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path14.sep).join("/")) : [];
|
|
14205
|
-
const stagedDeleted =
|
|
14427
|
+
const stagedDeleted = spawnSync8("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
14206
14428
|
if (stagedDeleted.status !== 0) {
|
|
14207
14429
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
14208
14430
|
if (!/not a git repository/i.test(stderr))
|
|
@@ -16594,7 +16816,7 @@ var withReleaseTracks = (workspaceRoot, policy) => {
|
|
|
16594
16816
|
error: `policy_unavailable: cannot validate branch ${JSON.stringify(name)} because ${error instanceof Error ? error.message : String(error)}; ${correction}`
|
|
16595
16817
|
};
|
|
16596
16818
|
}
|
|
16597
|
-
};
|
|
16819
|
+
}, resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
|
|
16598
16820
|
var init_branch = __esm(() => {
|
|
16599
16821
|
init_branch_policy();
|
|
16600
16822
|
init_commit_flavors();
|
|
@@ -16632,52 +16854,40 @@ var init_policy = __esm(() => {
|
|
|
16632
16854
|
init_route_intent();
|
|
16633
16855
|
});
|
|
16634
16856
|
|
|
16635
|
-
// packages/workit-core/src/hooks/
|
|
16636
|
-
|
|
16637
|
-
|
|
16638
|
-
|
|
16639
|
-
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
|
|
16643
|
-
|
|
16644
|
-
|
|
16645
|
-
|
|
16646
|
-
|
|
16647
|
-
|
|
16648
|
-
|
|
16649
|
-
|
|
16650
|
-
|
|
16651
|
-
|
|
16652
|
-
return NONE2;
|
|
16653
|
-
}
|
|
16654
|
-
}
|
|
16655
|
-
var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
16656
|
-
let rest = "";
|
|
16657
|
-
for (let dir = path16.resolve(file);; dir = path16.dirname(dir)) {
|
|
16658
|
-
try {
|
|
16659
|
-
return path16.join(realpathSync5(dir), rest);
|
|
16660
|
-
} catch {
|
|
16661
|
-
if (path16.dirname(dir) === dir)
|
|
16662
|
-
return path16.resolve(file);
|
|
16663
|
-
rest = rest ? path16.join(path16.basename(dir), rest) : path16.basename(dir);
|
|
16857
|
+
// packages/workit-core/src/hooks/shell-words.ts
|
|
16858
|
+
var closingQuote = (command, start, dialect) => {
|
|
16859
|
+
const quote = command[start];
|
|
16860
|
+
for (let index = start + 1;index < command.length; index++) {
|
|
16861
|
+
const char = command[index];
|
|
16862
|
+
if (quote === "'") {
|
|
16863
|
+
if (char !== "'")
|
|
16864
|
+
continue;
|
|
16865
|
+
if (dialect === "powershell" && command[index + 1] === "'") {
|
|
16866
|
+
index++;
|
|
16867
|
+
continue;
|
|
16868
|
+
}
|
|
16869
|
+
return index;
|
|
16870
|
+
}
|
|
16871
|
+
if (dialect === "posix" && char === "\\" || dialect === "powershell" && char === "`") {
|
|
16872
|
+
index++;
|
|
16873
|
+
continue;
|
|
16664
16874
|
}
|
|
16875
|
+
if (char === '"')
|
|
16876
|
+
return index;
|
|
16665
16877
|
}
|
|
16666
|
-
|
|
16667
|
-
|
|
16668
|
-
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
const segments = posix.split("/");
|
|
16673
|
-
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
16674
|
-
}, segmentsOf = (command) => {
|
|
16878
|
+
return -1;
|
|
16879
|
+
}, unquote = (body, quote, dialect) => {
|
|
16880
|
+
if (quote === "'")
|
|
16881
|
+
return dialect === "powershell" ? body.replaceAll("''", "'") : body;
|
|
16882
|
+
return dialect === "posix" ? body.replace(/\\(["\\$`])/g, "$1") : body.replace(/`(.)/g, "$1");
|
|
16883
|
+
}, segmentsOf = (command, dialect = "posix") => {
|
|
16675
16884
|
const segments = [];
|
|
16676
16885
|
let current = { words: [], redirects: [] };
|
|
16677
16886
|
let word = "";
|
|
16678
16887
|
let inWord = false;
|
|
16679
16888
|
let pending = null;
|
|
16680
16889
|
const heredocs = [];
|
|
16890
|
+
const escape = dialect === "posix" ? "\\" : "`";
|
|
16681
16891
|
const flushWord = () => {
|
|
16682
16892
|
if (!inWord)
|
|
16683
16893
|
return;
|
|
@@ -16701,11 +16911,11 @@ var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
|
16701
16911
|
for (let index = 0;index < command.length; index++) {
|
|
16702
16912
|
const char = command[index];
|
|
16703
16913
|
if (char === "'" || char === '"') {
|
|
16704
|
-
const end = command
|
|
16705
|
-
word += command.slice(index + 1, end < 0 ? undefined : end);
|
|
16914
|
+
const end = closingQuote(command, index, dialect);
|
|
16915
|
+
word += unquote(command.slice(index + 1, end < 0 ? undefined : end), char, dialect);
|
|
16706
16916
|
inWord = true;
|
|
16707
16917
|
index = end < 0 ? command.length : end;
|
|
16708
|
-
} else if (char ===
|
|
16918
|
+
} else if (char === escape && index + 1 < command.length) {
|
|
16709
16919
|
word += command[++index];
|
|
16710
16920
|
inWord = true;
|
|
16711
16921
|
} else if (char === `
|
|
@@ -16722,7 +16932,14 @@ var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
|
16722
16932
|
}
|
|
16723
16933
|
} else if (/\s/.test(char))
|
|
16724
16934
|
flushWord();
|
|
16725
|
-
else if ("
|
|
16935
|
+
else if (char === "(" || char === ")") {
|
|
16936
|
+
if (char === "(" && inWord && word.endsWith("$")) {
|
|
16937
|
+
word = word.slice(0, -1);
|
|
16938
|
+
inWord = word !== "";
|
|
16939
|
+
}
|
|
16940
|
+
flushSegment();
|
|
16941
|
+
segments.push({ words: [], redirects: [], group: char === "(" ? "open" : "close" });
|
|
16942
|
+
} else if (";&|".includes(char)) {
|
|
16726
16943
|
if (char === "&" && command[index + 1] === ">")
|
|
16727
16944
|
continue;
|
|
16728
16945
|
flushSegment();
|
|
@@ -16740,7 +16957,7 @@ var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
|
16740
16957
|
inWord = true;
|
|
16741
16958
|
}
|
|
16742
16959
|
pending = "redirect";
|
|
16743
|
-
} else if (char === "<") {
|
|
16960
|
+
} else if (char === "<" && dialect === "posix") {
|
|
16744
16961
|
flushWord();
|
|
16745
16962
|
if (command[index + 1] === "<") {
|
|
16746
16963
|
index++;
|
|
@@ -16756,6 +16973,47 @@ var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
|
16756
16973
|
}
|
|
16757
16974
|
flushSegment();
|
|
16758
16975
|
return segments;
|
|
16976
|
+
};
|
|
16977
|
+
|
|
16978
|
+
// packages/workit-core/src/hooks/write-gate.ts
|
|
16979
|
+
import { realpathSync as realpathSync5 } from "node:fs";
|
|
16980
|
+
import path16 from "node:path";
|
|
16981
|
+
function writeGate(cwd, paths) {
|
|
16982
|
+
try {
|
|
16983
|
+
const gate = gateFor(cwd);
|
|
16984
|
+
if (!gate || gate.blockers.length === 0)
|
|
16985
|
+
return NONE2;
|
|
16986
|
+
if (paths && paths.every((file) => exempt(cwd, gate.root, file, gate.plans)))
|
|
16987
|
+
return NONE2;
|
|
16988
|
+
const reasons = gate.blockers.map((item) => `${item.ruleId}: ${item.reason}`).join("; ");
|
|
16989
|
+
return {
|
|
16990
|
+
kind: "deny",
|
|
16991
|
+
reason: `workit before-write gate: ${reasons}. Markdown, docs/, plans/ and files outside the checkout stay writable.`,
|
|
16992
|
+
unblock: gate.blockers[0].reason
|
|
16993
|
+
};
|
|
16994
|
+
} catch {
|
|
16995
|
+
return NONE2;
|
|
16996
|
+
}
|
|
16997
|
+
}
|
|
16998
|
+
var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
16999
|
+
let rest = "";
|
|
17000
|
+
for (let dir = path16.resolve(file);; dir = path16.dirname(dir)) {
|
|
17001
|
+
try {
|
|
17002
|
+
return path16.join(realpathSync5(dir), rest);
|
|
17003
|
+
} catch {
|
|
17004
|
+
if (path16.dirname(dir) === dir)
|
|
17005
|
+
return path16.resolve(file);
|
|
17006
|
+
rest = rest ? path16.join(path16.basename(dir), rest) : path16.basename(dir);
|
|
17007
|
+
}
|
|
17008
|
+
}
|
|
17009
|
+
}, exempt = (cwd, root, file, plans) => {
|
|
17010
|
+
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
17011
|
+
const relative = path16.relative(fold(canonical2(root)), fold(canonical2(path16.resolve(cwd, file))));
|
|
17012
|
+
if (relative.startsWith("..") || path16.isAbsolute(relative))
|
|
17013
|
+
return true;
|
|
17014
|
+
const posix = relative.split(path16.sep).join("/");
|
|
17015
|
+
const segments = posix.split("/");
|
|
17016
|
+
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
16759
17017
|
}, PREFIXES2, operands = (words) => words.filter((item) => !item.startsWith("-")), editsOf = (input) => {
|
|
16760
17018
|
let words = input;
|
|
16761
17019
|
while (words.length && (PREFIXES2.has(words[0]) || /^\w+=/.test(words[0])))
|
|
@@ -16893,18 +17151,461 @@ var init_write_gate = __esm(() => {
|
|
|
16893
17151
|
cache2 = new Map;
|
|
16894
17152
|
});
|
|
16895
17153
|
|
|
17154
|
+
// packages/workit-core/src/hooks/raw-git.ts
|
|
17155
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
17156
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
17157
|
+
import fs12 from "node:fs";
|
|
17158
|
+
import os4 from "node:os";
|
|
17159
|
+
import path17 from "node:path";
|
|
17160
|
+
function rawInvocations(command, dialect = "posix", depth = 0) {
|
|
17161
|
+
const found = [];
|
|
17162
|
+
let dir = null;
|
|
17163
|
+
const groups = [];
|
|
17164
|
+
let stack = [];
|
|
17165
|
+
for (const segment of segmentsOf(command, dialect)) {
|
|
17166
|
+
if (segment.group === "open") {
|
|
17167
|
+
groups.push({ dir, stack: [...stack] });
|
|
17168
|
+
continue;
|
|
17169
|
+
}
|
|
17170
|
+
if (segment.group === "close") {
|
|
17171
|
+
const saved = groups.pop();
|
|
17172
|
+
if (saved)
|
|
17173
|
+
({ dir, stack } = saved);
|
|
17174
|
+
continue;
|
|
17175
|
+
}
|
|
17176
|
+
const words = stripPrefixes(segment.words);
|
|
17177
|
+
const name = commandName(words[0]);
|
|
17178
|
+
if (CD.has(name)) {
|
|
17179
|
+
const target = cdTarget(words);
|
|
17180
|
+
dir = target === null ? os4.homedir() : joinDir(dir, target);
|
|
17181
|
+
continue;
|
|
17182
|
+
}
|
|
17183
|
+
if (PUSHD.has(name)) {
|
|
17184
|
+
const target = cdTarget(words);
|
|
17185
|
+
stack.push(dir);
|
|
17186
|
+
dir = target === null || target === "-" ? undefined : joinDir(dir, target);
|
|
17187
|
+
continue;
|
|
17188
|
+
}
|
|
17189
|
+
if (POPD.has(name)) {
|
|
17190
|
+
dir = stack.length ? stack.pop() : undefined;
|
|
17191
|
+
continue;
|
|
17192
|
+
}
|
|
17193
|
+
if (SHELLS.has(name) && depth < 3) {
|
|
17194
|
+
const flag = words.findIndex((word, index) => index > 0 && SCRIPT_FLAG.test(word));
|
|
17195
|
+
const script = flag > 0 ? words[flag + 1] : undefined;
|
|
17196
|
+
if (script)
|
|
17197
|
+
for (const inner of rawInvocations(script, "posix", depth + 1))
|
|
17198
|
+
found.push({
|
|
17199
|
+
...inner,
|
|
17200
|
+
dir: inner.dir === null ? dir : inner.dir === undefined ? undefined : joinDir(dir, inner.dir)
|
|
17201
|
+
});
|
|
17202
|
+
continue;
|
|
17203
|
+
}
|
|
17204
|
+
if (name === "gh" || name === "glab") {
|
|
17205
|
+
found.push({ tool: name, dir, args: words.slice(1) });
|
|
17206
|
+
continue;
|
|
17207
|
+
}
|
|
17208
|
+
if (name !== "git")
|
|
17209
|
+
continue;
|
|
17210
|
+
let here = dir;
|
|
17211
|
+
let index = 1;
|
|
17212
|
+
for (;index < words.length; index++) {
|
|
17213
|
+
const word = words[index];
|
|
17214
|
+
if (word === "-C")
|
|
17215
|
+
here = words[index + 1] ? joinDir(here, words[++index]) : here;
|
|
17216
|
+
else if (GIT_VALUE_OPTIONS.has(word))
|
|
17217
|
+
index++;
|
|
17218
|
+
else if (!word.startsWith("-"))
|
|
17219
|
+
break;
|
|
17220
|
+
}
|
|
17221
|
+
found.push({ tool: "git", dir: here, args: words.slice(index) });
|
|
17222
|
+
}
|
|
17223
|
+
return found;
|
|
17224
|
+
}
|
|
17225
|
+
function rawAction(invocation) {
|
|
17226
|
+
const args = invocation.args;
|
|
17227
|
+
if (asksHelp(invocation))
|
|
17228
|
+
return null;
|
|
17229
|
+
const [first, second] = args;
|
|
17230
|
+
if (invocation.tool === "git") {
|
|
17231
|
+
if (first === "commit")
|
|
17232
|
+
return args.includes("--dry-run") ? null : { kind: "commit", amend: args.includes("--amend") };
|
|
17233
|
+
if (first === "push")
|
|
17234
|
+
return pushAction(args);
|
|
17235
|
+
return null;
|
|
17236
|
+
}
|
|
17237
|
+
const forge = invocation.tool;
|
|
17238
|
+
const noun = forge === "gh" ? "pr" : "mr";
|
|
17239
|
+
if (first !== noun)
|
|
17240
|
+
return null;
|
|
17241
|
+
if (second === "merge")
|
|
17242
|
+
return { kind: "merge", forge };
|
|
17243
|
+
if (second === "create")
|
|
17244
|
+
return { kind: "pr-create", forge };
|
|
17245
|
+
if (["view", "checks", "status", "ci", "list"].includes(second ?? ""))
|
|
17246
|
+
return { kind: "pr-read", forge };
|
|
17247
|
+
return null;
|
|
17248
|
+
}
|
|
17249
|
+
function rawGitPre(input, command) {
|
|
17250
|
+
try {
|
|
17251
|
+
if (!mentionsRawTool(command))
|
|
17252
|
+
return NONE3;
|
|
17253
|
+
const nudges = [];
|
|
17254
|
+
for (const { action, repo } of actionsIn(input.cwd, command, dialectOf(input))) {
|
|
17255
|
+
if (action.kind === "merge")
|
|
17256
|
+
return deny(refusal(action, null));
|
|
17257
|
+
if (action.kind === "push")
|
|
17258
|
+
for (const target of action.targets) {
|
|
17259
|
+
const branch = target ?? repo.branch;
|
|
17260
|
+
if (branch && guardedBranch(repo.dir, branch) && toPushRemote(repo, action.remote))
|
|
17261
|
+
return deny(refusal(action, branch));
|
|
17262
|
+
}
|
|
17263
|
+
const nudge = nudgeFor(action, input.host, input.session.id);
|
|
17264
|
+
if (nudge && !nudges.includes(nudge))
|
|
17265
|
+
nudges.push(nudge);
|
|
17266
|
+
}
|
|
17267
|
+
return nudges.length ? { kind: "context", text: nudges.join(`
|
|
17268
|
+
`) } : NONE3;
|
|
17269
|
+
} catch {
|
|
17270
|
+
return NONE3;
|
|
17271
|
+
}
|
|
17272
|
+
}
|
|
17273
|
+
function noteRawCommit(input, command, key) {
|
|
17274
|
+
try {
|
|
17275
|
+
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
17276
|
+
return;
|
|
17277
|
+
const at = Math.floor(Date.now() / 1000);
|
|
17278
|
+
for (const { action, repo } of actionsIn(input.cwd, command, dialectOf(input))) {
|
|
17279
|
+
if (action.kind !== "commit")
|
|
17280
|
+
continue;
|
|
17281
|
+
const file = markerFile(repo, input.session.id, key);
|
|
17282
|
+
fs12.mkdirSync(path17.dirname(file), { recursive: true });
|
|
17283
|
+
fs12.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
17284
|
+
`);
|
|
17285
|
+
}
|
|
17286
|
+
} catch {}
|
|
17287
|
+
}
|
|
17288
|
+
function rawGitPost(input, command, key) {
|
|
17289
|
+
try {
|
|
17290
|
+
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
17291
|
+
return;
|
|
17292
|
+
for (const { action, repo } of actionsIn(input.cwd, command, dialectOf(input)))
|
|
17293
|
+
if (action.kind === "commit")
|
|
17294
|
+
settle2(input, repo, markerFile(repo, input.session.id, key));
|
|
17295
|
+
} catch {}
|
|
17296
|
+
}
|
|
17297
|
+
function settlePendingCommit(input) {
|
|
17298
|
+
try {
|
|
17299
|
+
if (!input.session.id)
|
|
17300
|
+
return;
|
|
17301
|
+
const repo = repoAt(input.cwd);
|
|
17302
|
+
if (!repo)
|
|
17303
|
+
return;
|
|
17304
|
+
const file = markerFile(repo, input.session.id, NEXT_COMMAND);
|
|
17305
|
+
if (fs12.existsSync(file))
|
|
17306
|
+
settle2(input, repo, file);
|
|
17307
|
+
} catch {}
|
|
17308
|
+
}
|
|
17309
|
+
var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, isAbsolute = (value) => path17.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\"), joinDir = (base, next) => {
|
|
17310
|
+
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
17311
|
+
return;
|
|
17312
|
+
const expanded = next === "~" || next.startsWith("~/") ? path17.join(os4.homedir(), next.slice(1)) : next;
|
|
17313
|
+
return base === null || isAbsolute(expanded) ? expanded : path17.join(base, expanded);
|
|
17314
|
+
}, cdTarget = (words) => {
|
|
17315
|
+
const args = words.slice(1);
|
|
17316
|
+
const flag = args.findIndex((word) => /^-(?:literal)?path$/i.test(word));
|
|
17317
|
+
if (flag >= 0)
|
|
17318
|
+
return args[flag + 1] ?? null;
|
|
17319
|
+
return args.find((word) => word === "-" || !word.startsWith("-")) ?? null;
|
|
17320
|
+
}, stripPrefixes = (input) => {
|
|
17321
|
+
let words = input;
|
|
17322
|
+
for (;; ) {
|
|
17323
|
+
const first = words[0];
|
|
17324
|
+
if (first === undefined)
|
|
17325
|
+
return words;
|
|
17326
|
+
if (/^\w+=/.test(first))
|
|
17327
|
+
words = words.slice(1);
|
|
17328
|
+
else if (PREFIXES3.has(first)) {
|
|
17329
|
+
words = words.slice(1);
|
|
17330
|
+
while (words[0]?.startsWith("-"))
|
|
17331
|
+
words = words.slice(words[0] === "-u" ? 2 : 1);
|
|
17332
|
+
} else if (first === "timeout") {
|
|
17333
|
+
words = words.slice(1);
|
|
17334
|
+
while (words[0]?.startsWith("-"))
|
|
17335
|
+
words = words.slice(1);
|
|
17336
|
+
words = words.slice(1);
|
|
17337
|
+
} else
|
|
17338
|
+
return words;
|
|
17339
|
+
}
|
|
17340
|
+
}, commandName = (word) => (word?.split(/[\\/]/).at(-1) ?? "").toLowerCase().replace(/\.exe$/, ""), PUSH_VALUE_OPTIONS, pushAction = (args) => {
|
|
17341
|
+
let force = false;
|
|
17342
|
+
let lease = false;
|
|
17343
|
+
let wholesale = false;
|
|
17344
|
+
let remote = null;
|
|
17345
|
+
const positionals = [];
|
|
17346
|
+
for (let index = 1;index < args.length; index++) {
|
|
17347
|
+
const arg = args[index];
|
|
17348
|
+
if (arg === "--") {
|
|
17349
|
+
positionals.push(...args.slice(index + 1));
|
|
17350
|
+
break;
|
|
17351
|
+
}
|
|
17352
|
+
if (arg === "--dry-run" || /^-[a-zA-Z]*n[a-zA-Z]*$/.test(arg))
|
|
17353
|
+
return null;
|
|
17354
|
+
if (arg === "--repo")
|
|
17355
|
+
remote = args[++index] ?? null;
|
|
17356
|
+
else if (arg.startsWith("--repo="))
|
|
17357
|
+
remote = arg.slice("--repo=".length);
|
|
17358
|
+
else if (PUSH_VALUE_OPTIONS.has(arg))
|
|
17359
|
+
index++;
|
|
17360
|
+
else if (arg === "--force" || /^-[a-zA-Z]*f[a-zA-Z]*$/.test(arg))
|
|
17361
|
+
force = true;
|
|
17362
|
+
else if (arg.startsWith("--force-with-lease") || arg === "--force-if-includes")
|
|
17363
|
+
lease = true;
|
|
17364
|
+
else if (["--all", "--mirror", "--branches", "--tags"].includes(arg))
|
|
17365
|
+
wholesale = true;
|
|
17366
|
+
else if (!arg.startsWith("-"))
|
|
17367
|
+
positionals.push(arg);
|
|
17368
|
+
}
|
|
17369
|
+
const specs = remote === null ? positionals.slice(1) : positionals;
|
|
17370
|
+
remote ??= positionals[0] ?? null;
|
|
17371
|
+
const targets = [];
|
|
17372
|
+
for (const raw of specs) {
|
|
17373
|
+
if (raw.startsWith("+"))
|
|
17374
|
+
force = true;
|
|
17375
|
+
const spec = raw.replace(/^\+/, "");
|
|
17376
|
+
const colon = spec.indexOf(":");
|
|
17377
|
+
const destination = colon >= 0 ? spec.slice(colon + 1) : spec;
|
|
17378
|
+
if (!destination)
|
|
17379
|
+
continue;
|
|
17380
|
+
if (destination === "HEAD")
|
|
17381
|
+
targets.push(null);
|
|
17382
|
+
else if (destination.startsWith("refs/heads/"))
|
|
17383
|
+
targets.push(destination.slice(11));
|
|
17384
|
+
else if (!destination.startsWith("refs/"))
|
|
17385
|
+
targets.push(destination);
|
|
17386
|
+
}
|
|
17387
|
+
if (specs.length === 0 && !wholesale)
|
|
17388
|
+
targets.push(null);
|
|
17389
|
+
return { kind: "push", targets, blindForce: force && !lease, remote };
|
|
17390
|
+
}, VALUE_OPTIONS, asksHelp = (invocation) => {
|
|
17391
|
+
const { tool, args } = invocation;
|
|
17392
|
+
if (args[0] === "help" || tool !== "git" && args[1] === "help")
|
|
17393
|
+
return true;
|
|
17394
|
+
const values = VALUE_OPTIONS[tool];
|
|
17395
|
+
for (let index = 0;index < args.length; index++) {
|
|
17396
|
+
const arg = args[index];
|
|
17397
|
+
if (arg === "--")
|
|
17398
|
+
return false;
|
|
17399
|
+
if (arg === "--help" || arg === "-h")
|
|
17400
|
+
return true;
|
|
17401
|
+
if (values.has(arg))
|
|
17402
|
+
index++;
|
|
17403
|
+
}
|
|
17404
|
+
return false;
|
|
17405
|
+
}, repoAt = (dir) => {
|
|
17406
|
+
const location = resolveStore(dir);
|
|
17407
|
+
if (location instanceof Error || !location.shared)
|
|
17408
|
+
return null;
|
|
17409
|
+
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
17410
|
+
}, isWorkitWorkspace = (repo) => {
|
|
17411
|
+
if (fs12.existsSync(repo.location.dir))
|
|
17412
|
+
return true;
|
|
17413
|
+
try {
|
|
17414
|
+
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
17415
|
+
} catch {
|
|
17416
|
+
return false;
|
|
17417
|
+
}
|
|
17418
|
+
}, guardedBranch = (dir, branch) => {
|
|
17419
|
+
try {
|
|
17420
|
+
const policy = resolveBranchPolicyFor(dir);
|
|
17421
|
+
return policy.protected.has(branch.toLowerCase()) || policy.defaultTargetBranch.toLowerCase() === branch.toLowerCase();
|
|
17422
|
+
} catch {
|
|
17423
|
+
return false;
|
|
17424
|
+
}
|
|
17425
|
+
}, toPushRemote = (repo, remote) => {
|
|
17426
|
+
if (remote === null)
|
|
17427
|
+
return true;
|
|
17428
|
+
try {
|
|
17429
|
+
const pushRemote = pushRemoteName(repo.dir, repo.branch);
|
|
17430
|
+
return pushRemote === null || pushRemote === remote;
|
|
17431
|
+
} catch {
|
|
17432
|
+
return false;
|
|
17433
|
+
}
|
|
17434
|
+
}, headSha2 = (repo) => {
|
|
17435
|
+
const git = repo.location.git;
|
|
17436
|
+
if (!git || git.reftable)
|
|
17437
|
+
return null;
|
|
17438
|
+
try {
|
|
17439
|
+
const head = fs12.readFileSync(path17.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
17440
|
+
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
17441
|
+
return head;
|
|
17442
|
+
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
17443
|
+
if (!ref)
|
|
17444
|
+
return null;
|
|
17445
|
+
const common = path17.dirname(repo.location.dir);
|
|
17446
|
+
try {
|
|
17447
|
+
return fs12.readFileSync(path17.join(common, ref), "utf8").trim() || null;
|
|
17448
|
+
} catch {}
|
|
17449
|
+
const packed = fs12.readFileSync(path17.join(common, "packed-refs"), "utf8");
|
|
17450
|
+
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
17451
|
+
} catch {
|
|
17452
|
+
return null;
|
|
17453
|
+
}
|
|
17454
|
+
}, quote = (text) => `\`${text}\``, refusal = (action, branch) => {
|
|
17455
|
+
if (action.kind === "merge")
|
|
17456
|
+
return `workit: raw ${quote(action.forge === "gh" ? "gh pr merge" : "glab mr merge")} bypasses the merge grant and the verdict gate. Run ${quote("workit pr merge")} instead (it checks both; ${quote("workit help pr")}).`;
|
|
17457
|
+
return `workit: raw ${quote("git push")}${action.kind === "push" && action.blindForce ? " --force" : ""} onto ${branch}, a protected branch or the default target, bypasses workit's protected-branch check. Push your feature branch with ${quote("workit git push")} (${quote("workit git push --force-with-lease")} to rewrite it) and land it with ${quote("workit pr merge")}.`;
|
|
17458
|
+
}, nudgeFor = (action, host, session) => {
|
|
17459
|
+
switch (action.kind) {
|
|
17460
|
+
case "commit": {
|
|
17461
|
+
const prefix = host === "cursor" && session ? `WORKIT_SESSION_ID=${session} ` : "";
|
|
17462
|
+
return action.amend ? `workit: raw ${quote("git commit --amend")} is recorded for this session; for new commits prefer ${quote(`${prefix}workit git commit -m '<msg>'`)} (adds the Workit-Session trailer and checks branch and commit policy).` : `workit: prefer ${quote(`${prefix}workit git commit -m '<msg>' [--all | -- <paths>]`)}: it adds the Workit-Session trailer and checks branch and commit policy.`;
|
|
17463
|
+
}
|
|
17464
|
+
case "push":
|
|
17465
|
+
return action.blindForce ? `workit: ${quote("git push --force")} overwrites without a lease; use ${quote("workit git push --force-with-lease")}.` : `workit: prefer ${quote("workit git push")}: it refuses protected branches and verifies the remote tip.`;
|
|
17466
|
+
case "pr-create":
|
|
17467
|
+
return `workit: prefer ${quote("workit pr create --fill")} (or --title/--body): it records the PR the merge gate checks.`;
|
|
17468
|
+
case "pr-read":
|
|
17469
|
+
return `workit: ${quote("workit pr status")} shows the PR, its checks and the verdict state; ${quote("workit ci wait")} waits for checks.`;
|
|
17470
|
+
case "merge":
|
|
17471
|
+
return null;
|
|
17472
|
+
}
|
|
17473
|
+
}, actionsIn = (cwd, command, dialect) => {
|
|
17474
|
+
const out = [];
|
|
17475
|
+
const repos = new Map;
|
|
17476
|
+
for (const invocation of rawInvocations(command, dialect)) {
|
|
17477
|
+
if (invocation.dir === undefined)
|
|
17478
|
+
continue;
|
|
17479
|
+
const action = rawAction(invocation);
|
|
17480
|
+
if (!action)
|
|
17481
|
+
continue;
|
|
17482
|
+
const dir = path17.resolve(cwd, invocation.dir ?? ".");
|
|
17483
|
+
if (!repos.has(dir)) {
|
|
17484
|
+
const repo = repoAt(dir);
|
|
17485
|
+
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
17486
|
+
}
|
|
17487
|
+
const repo = repos.get(dir);
|
|
17488
|
+
if (repo)
|
|
17489
|
+
out.push({ action, repo });
|
|
17490
|
+
}
|
|
17491
|
+
return out;
|
|
17492
|
+
}, mentionsRawTool = (command) => /\b(?:git|gh|glab)\b/i.test(command), dialectOf = (input) => (input.event.kind === "shell.pre" || input.event.kind === "shell.post" ? input.event.dialect : undefined) ?? "posix", deny = (reason) => ({ kind: "deny", reason, unblock: null }), NEXT_COMMAND = "next", MARKER_TTL_SECONDS = 3600, markerFile = (repo, session, key) => path17.join(repo.location.dir, "hooks", `commit-${createHash10("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`), callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash10("sha256").update(command).digest("hex")}`, headCommit = (dir) => {
|
|
17493
|
+
const run = spawnSync9("git", [
|
|
17494
|
+
"log",
|
|
17495
|
+
"-1",
|
|
17496
|
+
"--format=%H%x1f%ct%x1f%s%x1f%(trailers:key=Workit-Session,valueonly,separator=%x2c)"
|
|
17497
|
+
], {
|
|
17498
|
+
cwd: dir,
|
|
17499
|
+
encoding: "utf8",
|
|
17500
|
+
timeout: 5000,
|
|
17501
|
+
windowsHide: true,
|
|
17502
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_OPTIONAL_LOCKS: "0", LC_ALL: "C" }
|
|
17503
|
+
});
|
|
17504
|
+
const [sha, committed, subject = "", trailer = ""] = (run.status === 0 ? run.stdout.trim() : "").split("\x1F");
|
|
17505
|
+
return sha && /^[0-9a-f]{40,64}$/.test(sha) ? { sha, committed: Number(committed), subject, trailer: trailer.trim() || null } : null;
|
|
17506
|
+
}, settle2 = (input, repo, file) => {
|
|
17507
|
+
let marker;
|
|
17508
|
+
try {
|
|
17509
|
+
marker = JSON.parse(fs12.readFileSync(file, "utf8"));
|
|
17510
|
+
} catch {
|
|
17511
|
+
return;
|
|
17512
|
+
}
|
|
17513
|
+
fs12.rmSync(file, { force: true });
|
|
17514
|
+
const session = input.session.id;
|
|
17515
|
+
const now = Date.now() / 1000;
|
|
17516
|
+
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
17517
|
+
return;
|
|
17518
|
+
if (!session || !repo.branch)
|
|
17519
|
+
return;
|
|
17520
|
+
const head = headCommit(repo.dir);
|
|
17521
|
+
if (!head || head.sha === marker.head || head.committed < marker.at)
|
|
17522
|
+
return;
|
|
17523
|
+
if (head.trailer && head.trailer !== session)
|
|
17524
|
+
return;
|
|
17525
|
+
const ledger = readLedger(repo.dir);
|
|
17526
|
+
if (!ledger.ok)
|
|
17527
|
+
return;
|
|
17528
|
+
const claimed = ledger.value.rows.some((row) => row.type === "commit.recorded" && (row.sha === head.sha || row.head === head.sha));
|
|
17529
|
+
if (claimed)
|
|
17530
|
+
return;
|
|
17531
|
+
appendHookObserved(repo.dir, {
|
|
17532
|
+
type: "commit.recorded",
|
|
17533
|
+
actor: { host: input.host, session, agentId: input.session.agentId },
|
|
17534
|
+
branch: repo.branch,
|
|
17535
|
+
head: head.sha,
|
|
17536
|
+
sha: head.sha,
|
|
17537
|
+
session,
|
|
17538
|
+
agentId: input.session.agentId,
|
|
17539
|
+
subject: head.subject.slice(0, 200),
|
|
17540
|
+
files: [],
|
|
17541
|
+
fileCount: null,
|
|
17542
|
+
via: "raw_shell"
|
|
17543
|
+
});
|
|
17544
|
+
};
|
|
17545
|
+
var init_raw_git = __esm(() => {
|
|
17546
|
+
init_branch();
|
|
17547
|
+
init_workspaces();
|
|
17548
|
+
init_rev();
|
|
17549
|
+
init_ledger();
|
|
17550
|
+
init_paths();
|
|
17551
|
+
NONE3 = { kind: "none" };
|
|
17552
|
+
SHELLS = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
|
|
17553
|
+
PREFIXES3 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "nice", "&"]);
|
|
17554
|
+
SCRIPT_FLAG = /^-[a-zA-Z]*c[a-zA-Z]*$/;
|
|
17555
|
+
CD = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
17556
|
+
PUSHD = new Set(["pushd", "push-location"]);
|
|
17557
|
+
POPD = new Set(["popd", "pop-location"]);
|
|
17558
|
+
GIT_VALUE_OPTIONS = new Set([
|
|
17559
|
+
"-c",
|
|
17560
|
+
"--git-dir",
|
|
17561
|
+
"--work-tree",
|
|
17562
|
+
"--namespace",
|
|
17563
|
+
"--exec-path",
|
|
17564
|
+
"--config-env",
|
|
17565
|
+
"--super-prefix"
|
|
17566
|
+
]);
|
|
17567
|
+
PUSH_VALUE_OPTIONS = new Set(["-o", "--push-option", "--receive-pack", "--exec", "--repo"]);
|
|
17568
|
+
VALUE_OPTIONS = {
|
|
17569
|
+
git: new Set([
|
|
17570
|
+
"-m",
|
|
17571
|
+
"--message",
|
|
17572
|
+
"-F",
|
|
17573
|
+
"--file",
|
|
17574
|
+
"-C",
|
|
17575
|
+
"-c",
|
|
17576
|
+
"--reuse-message",
|
|
17577
|
+
"--reedit-message",
|
|
17578
|
+
"--author",
|
|
17579
|
+
"--date",
|
|
17580
|
+
"--trailer",
|
|
17581
|
+
"-t",
|
|
17582
|
+
"--template",
|
|
17583
|
+
"--cleanup",
|
|
17584
|
+
"--fixup",
|
|
17585
|
+
"--squash",
|
|
17586
|
+
"-o",
|
|
17587
|
+
"--push-option",
|
|
17588
|
+
"--repo",
|
|
17589
|
+
"--receive-pack",
|
|
17590
|
+
"--exec"
|
|
17591
|
+
]),
|
|
17592
|
+
gh: new Set(["-b", "--body", "-F", "--body-file", "-t", "--title", "--subject", "-A", "--author-email"].concat(["-B", "--base", "-H", "--head", "-l", "--label", "-a", "--assignee"]).concat(["-r", "--reviewer", "-m", "--milestone", "-p", "--project", "-T", "--template"]).concat(["--match-head-commit", "-R", "--repo"])),
|
|
17593
|
+
glab: new Set(["-m", "--message", "--squash-message", "--sha", "-t", "--title", "-d", "--description"].concat(["-b", "--target-branch", "-s", "--source-branch", "-l", "--label"]).concat(["-a", "--assignee", "--reviewer", "-R", "--repo"]))
|
|
17594
|
+
};
|
|
17595
|
+
});
|
|
17596
|
+
|
|
16896
17597
|
// packages/workit-core/src/hooks/hosts/fields.ts
|
|
16897
17598
|
import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
|
|
16898
|
-
import
|
|
17599
|
+
import path18 from "node:path";
|
|
16899
17600
|
var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "", optionalText = (value) => typeof value === "string" ? value : null, existingDirectory = (value) => {
|
|
16900
|
-
if (!nonEmpty2(value) || !
|
|
17601
|
+
if (!nonEmpty2(value) || !path18.isAbsolute(value) || !existsSync6(value))
|
|
16901
17602
|
return null;
|
|
16902
17603
|
try {
|
|
16903
17604
|
return statSync2(value).isDirectory() ? realpathSync6(value) : null;
|
|
16904
17605
|
} catch {
|
|
16905
17606
|
return null;
|
|
16906
17607
|
}
|
|
16907
|
-
},
|
|
17608
|
+
}, SHELLS2, SCRIPT_FLAG2, quoteArg = (arg) => /^[\w@%+=:,./-]+$/.test(arg) ? arg : JSON.stringify(arg), commandText = (value) => {
|
|
16908
17609
|
if (nonEmpty2(value))
|
|
16909
17610
|
return value;
|
|
16910
17611
|
if (!Array.isArray(value) || value.length === 0)
|
|
@@ -16913,9 +17614,9 @@ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array
|
|
|
16913
17614
|
if (!argv.every((arg) => typeof arg === "string"))
|
|
16914
17615
|
return null;
|
|
16915
17616
|
const shell = argv[0].split(/[\\/]/).at(-1)?.replace(/\.exe$/i, "").toLowerCase() ?? "";
|
|
16916
|
-
if (
|
|
17617
|
+
if (SHELLS2.has(shell))
|
|
16917
17618
|
for (let index = 1;index < argv.length - 1; index++) {
|
|
16918
|
-
if (
|
|
17619
|
+
if (SCRIPT_FLAG2.test(argv[index]))
|
|
16919
17620
|
return nonEmpty2(argv[index + 1]) ? argv[index + 1] : null;
|
|
16920
17621
|
if (!/^[-/]/.test(argv[index]))
|
|
16921
17622
|
break;
|
|
@@ -16933,8 +17634,8 @@ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array
|
|
|
16933
17634
|
return [...new Set(paths)];
|
|
16934
17635
|
};
|
|
16935
17636
|
var init_fields = __esm(() => {
|
|
16936
|
-
|
|
16937
|
-
|
|
17637
|
+
SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
|
|
17638
|
+
SCRIPT_FLAG2 = /^(?:-\w*c|-command|\/c)$/i;
|
|
16938
17639
|
WRITE_TOOLS = new Set([
|
|
16939
17640
|
"write",
|
|
16940
17641
|
"edit",
|
|
@@ -16964,7 +17665,7 @@ function handleHook(input, deps) {
|
|
|
16964
17665
|
switch (event.kind) {
|
|
16965
17666
|
case "session.start": {
|
|
16966
17667
|
if (!usable2(descriptor.context.sessionStart))
|
|
16967
|
-
return
|
|
17668
|
+
return NONE4;
|
|
16968
17669
|
const key = input.session.id ? `${input.host}\x00${input.session.id}` : null;
|
|
16969
17670
|
const offer = event.source === "startup" && (key === null || !offered.has(key));
|
|
16970
17671
|
if (offer && key !== null)
|
|
@@ -16979,19 +17680,34 @@ function handleHook(input, deps) {
|
|
|
16979
17680
|
}
|
|
16980
17681
|
case "context.turn": {
|
|
16981
17682
|
if (!usable2(descriptor.context.perTurn))
|
|
16982
|
-
return
|
|
17683
|
+
return NONE4;
|
|
16983
17684
|
const text = turnContextText(input, descriptor);
|
|
16984
|
-
return text ? { kind: "context", text } :
|
|
17685
|
+
return text ? { kind: "context", text } : NONE4;
|
|
16985
17686
|
}
|
|
16986
17687
|
case "shell.pre": {
|
|
16987
|
-
const
|
|
16988
|
-
|
|
17688
|
+
const canDeny = usable2(descriptor.shellPolicy.deny);
|
|
17689
|
+
const policy = canDeny ? shellPolicy(input.cwd, event.command) : NONE4;
|
|
17690
|
+
if (policy.kind !== "none")
|
|
16989
17691
|
return policy;
|
|
16990
|
-
const
|
|
16991
|
-
|
|
17692
|
+
const postTool = usable2(descriptor.events["shell.post"].support);
|
|
17693
|
+
if (!postTool)
|
|
17694
|
+
settlePendingCommit(input);
|
|
17695
|
+
const raw = canDeny ? rawGitPre(input, event.command) : NONE4;
|
|
17696
|
+
if (raw.kind === "deny")
|
|
17697
|
+
return raw;
|
|
17698
|
+
const writes = usable2(descriptor.events["write.pre"].support) ? shellWrites(event.command) : { writes: false, targets: null };
|
|
17699
|
+
const gate = writes.writes ? writeGate(input.cwd, writes.targets) : NONE4;
|
|
17700
|
+
if (gate.kind === "deny")
|
|
17701
|
+
return gate;
|
|
17702
|
+
noteRawCommit(input, event.command, postTool ? callKey(event.toolUseId, event.command) : NEXT_COMMAND);
|
|
17703
|
+
return raw;
|
|
16992
17704
|
}
|
|
17705
|
+
case "shell.post":
|
|
17706
|
+
if (usable2(descriptor.events["shell.post"].support))
|
|
17707
|
+
rawGitPost(input, event.command, callKey(event.toolUseId, event.command));
|
|
17708
|
+
return NONE4;
|
|
16993
17709
|
case "write.pre":
|
|
16994
|
-
return usable2(descriptor.events["write.pre"].support) ? writeGate(input.cwd, event.paths) :
|
|
17710
|
+
return usable2(descriptor.events["write.pre"].support) ? writeGate(input.cwd, event.paths) : NONE4;
|
|
16995
17711
|
case "subagent.start":
|
|
16996
17712
|
return {
|
|
16997
17713
|
kind: "context",
|
|
@@ -17003,14 +17719,13 @@ function handleHook(input, deps) {
|
|
|
17003
17719
|
userMessage: "Workit context may be stale after compaction; re-run inspection or resume before acting."
|
|
17004
17720
|
};
|
|
17005
17721
|
case "tool.pre":
|
|
17006
|
-
case "shell.post":
|
|
17007
17722
|
case "subagent.stop":
|
|
17008
17723
|
case "prompt.submit":
|
|
17009
17724
|
case "stop":
|
|
17010
|
-
return
|
|
17725
|
+
return NONE4;
|
|
17011
17726
|
}
|
|
17012
17727
|
}
|
|
17013
|
-
var usable2 = (value) => value === "native" || value === "partial",
|
|
17728
|
+
var usable2 = (value) => value === "native" || value === "partial", NONE4, offered, CLAUDE_WORKTREE_IMPLEMENTER = "workit:implementer", CLAUDE_JUDGES, subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128), subagentStartText = (host, session, descriptor, event) => {
|
|
17014
17729
|
if (host === "claude_code" && event.agentType === CLAUDE_WORKTREE_IMPLEMENTER)
|
|
17015
17730
|
return `Workit observed ${descriptor.label} subagent ${event.agentId} (${event.agentType}) working in its own git worktree: it may edit and commit there, within its brief's scope. Before the first commit, switch to a policy-compliant branch with \`workit git branch <branch> --base <base>\` (e.g. feature/<slug>); branch policy hooks still deny protected or non-compliant branches. Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
|
|
17016
17731
|
const readOnly = `Workit observed ${descriptor.label} subagent ${event.agentId} (${event.agentType}) as read-only/agent-guided.`;
|
|
@@ -17019,10 +17734,10 @@ var usable2 = (value) => value === "native" || value === "partial", NONE3, offer
|
|
|
17019
17734
|
return readOnly;
|
|
17020
17735
|
}, failureDecision = (descriptor, event, error) => {
|
|
17021
17736
|
if (event === "shell.pre" || event === "tool.pre" || event === "write.pre")
|
|
17022
|
-
return descriptor.shellPolicy.failClosed ? { kind: "deny", reason: error, unblock: null } :
|
|
17737
|
+
return descriptor.shellPolicy.failClosed ? { kind: "deny", reason: error, unblock: null } : NONE4;
|
|
17023
17738
|
if (event === "session.start" || event === "subagent.start")
|
|
17024
17739
|
return { kind: "context", text: `[workit diagnostic: ${error}]` };
|
|
17025
|
-
return
|
|
17740
|
+
return NONE4;
|
|
17026
17741
|
}, dispatchHook = (adapter, raw, env = process.env) => {
|
|
17027
17742
|
const parsed = adapter.parse(raw, env);
|
|
17028
17743
|
if (!parsed.ok)
|
|
@@ -17048,14 +17763,15 @@ var usable2 = (value) => value === "native" || value === "partial", NONE3, offer
|
|
|
17048
17763
|
var init_handle = __esm(() => {
|
|
17049
17764
|
init_context();
|
|
17050
17765
|
init_policy();
|
|
17766
|
+
init_raw_git();
|
|
17051
17767
|
init_write_gate();
|
|
17052
|
-
|
|
17768
|
+
NONE4 = { kind: "none" };
|
|
17053
17769
|
offered = new Set;
|
|
17054
17770
|
CLAUDE_JUDGES = new Set(["workit:verifier", "workit:reviewer"]);
|
|
17055
17771
|
});
|
|
17056
17772
|
|
|
17057
17773
|
// packages/workit-core/src/hooks/hosts/claude-code.ts
|
|
17058
|
-
var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, toolCommand = (value) => isRecord4(value.tool_input) ? commandText(value.tool_input.command) : null, eventOf = (name, value) => {
|
|
17774
|
+
var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, dialectOf2 = (value) => value.tool_name === "PowerShell" ? "powershell" : "posix", toolCommand = (value) => isRecord4(value.tool_input) ? commandText(value.tool_input.command) : null, eventOf = (name, value) => {
|
|
17059
17775
|
const toolUseId = optionalText(value.tool_use_id);
|
|
17060
17776
|
switch (name) {
|
|
17061
17777
|
case "SessionStart":
|
|
@@ -17078,7 +17794,7 @@ var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, toolCommand = (value)
|
|
|
17078
17794
|
if (!SHELL_TOOLS.has(value.tool_name))
|
|
17079
17795
|
return { ok: true, event: { kind: "tool.pre", tool: value.tool_name, toolUseId } };
|
|
17080
17796
|
const command = toolCommand(value);
|
|
17081
|
-
return command ? { ok: true, event: { kind: "shell.pre", command, toolUseId } } : { ok: false, error: `tool_input.command is required for ${value.tool_name}` };
|
|
17797
|
+
return command ? { ok: true, event: { kind: "shell.pre", command, toolUseId, dialect: dialectOf2(value) } } : { ok: false, error: `tool_input.command is required for ${value.tool_name}` };
|
|
17082
17798
|
}
|
|
17083
17799
|
case "PostToolUse": {
|
|
17084
17800
|
const command = toolCommand(value);
|
|
@@ -17092,7 +17808,8 @@ var CLAUDE_CODE_DESCRIPTOR, EVENTS, SOURCES, SHELL_TOOLS, toolCommand = (value)
|
|
|
17092
17808
|
command,
|
|
17093
17809
|
stdout: optionalText(response.stdout) ?? "",
|
|
17094
17810
|
exitCode: typeof response.exit_code === "number" ? response.exit_code : null,
|
|
17095
|
-
toolUseId
|
|
17811
|
+
toolUseId,
|
|
17812
|
+
dialect: dialectOf2(value)
|
|
17096
17813
|
}
|
|
17097
17814
|
};
|
|
17098
17815
|
}
|
|
@@ -17255,7 +17972,13 @@ var init_claude_code = __esm(() => {
|
|
|
17255
17972
|
};
|
|
17256
17973
|
SOURCES = new Set(["startup", "resume", "clear", "compact", "fork"]);
|
|
17257
17974
|
SHELL_TOOLS = new Set(["Bash", "PowerShell"]);
|
|
17258
|
-
CONTEXT_EVENTS = new Set([
|
|
17975
|
+
CONTEXT_EVENTS = new Set([
|
|
17976
|
+
"SessionStart",
|
|
17977
|
+
"UserPromptSubmit",
|
|
17978
|
+
"SubagentStart",
|
|
17979
|
+
"PreToolUse",
|
|
17980
|
+
"PostToolUse"
|
|
17981
|
+
]);
|
|
17259
17982
|
claudeCodeAdapter = {
|
|
17260
17983
|
descriptor: CLAUDE_CODE_DESCRIPTOR,
|
|
17261
17984
|
parse(raw) {
|
|
@@ -17309,10 +18032,11 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
|
|
|
17309
18032
|
const cwd = existingDirectory(value.cwd);
|
|
17310
18033
|
if (!cwd)
|
|
17311
18034
|
return { ok: false, error: "cwd must be an existing absolute directory" };
|
|
17312
|
-
|
|
18035
|
+
const toolEvent = event === "PreToolUse" || event === "PostToolUse";
|
|
18036
|
+
if (toolEvent && !nonEmpty2(value.tool_name))
|
|
17313
18037
|
return { ok: false, error: "tool_name is required" };
|
|
17314
18038
|
const command = isRecord4(value.tool_input) ? commandText(value.tool_input.command) : null;
|
|
17315
|
-
if (
|
|
18039
|
+
if (toolEvent && isShellTool(value.tool_name) && !command)
|
|
17316
18040
|
return { ok: false, error: "tool_input.command is required for shell tools" };
|
|
17317
18041
|
if (event === "SubagentStart" && !nonEmpty2(value.agent_id))
|
|
17318
18042
|
return { ok: false, error: "agent_id is required" };
|
|
@@ -17328,7 +18052,8 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
|
|
|
17328
18052
|
...event === "SessionStart" ? { source: SOURCES2.has(String(value.source)) ? value.source : "resume" } : {},
|
|
17329
18053
|
...nonEmpty2(value.turn_id) ? { turn_id: value.turn_id } : {},
|
|
17330
18054
|
...nonEmpty2(value.tool_name) ? { tool_name: value.tool_name } : {},
|
|
17331
|
-
...
|
|
18055
|
+
...toolEvent ? { tool_input: value.tool_input } : {},
|
|
18056
|
+
...event === "PostToolUse" && typeof value.tool_response === "string" ? { tool_response: value.tool_response } : {},
|
|
17332
18057
|
...command ? { command } : {},
|
|
17333
18058
|
...nonEmpty2(value.tool_use_id) ? { tool_use_id: value.tool_use_id } : {},
|
|
17334
18059
|
...nonEmpty2(value.agent_id) ? { agent_id: value.agent_id } : {},
|
|
@@ -17352,6 +18077,16 @@ var undocumented, CODEX_DESCRIPTOR, EVENTS2, SHELL_TOOLS2, isShellTool = (name)
|
|
|
17352
18077
|
toolUseId
|
|
17353
18078
|
} : { kind: "tool.pre", tool: input.tool_name, toolUseId };
|
|
17354
18079
|
}
|
|
18080
|
+
case "PostToolUse": {
|
|
18081
|
+
const toolUseId = input.tool_use_id ?? null;
|
|
18082
|
+
return isShellTool(input.tool_name) ? {
|
|
18083
|
+
kind: "shell.post",
|
|
18084
|
+
command: input.command ?? "",
|
|
18085
|
+
stdout: input.tool_response ?? "",
|
|
18086
|
+
exitCode: null,
|
|
18087
|
+
toolUseId
|
|
18088
|
+
} : { kind: "tool.pre", tool: input.tool_name, toolUseId };
|
|
18089
|
+
}
|
|
17355
18090
|
case "SubagentStart":
|
|
17356
18091
|
return {
|
|
17357
18092
|
kind: "subagent.start",
|
|
@@ -17400,7 +18135,7 @@ var init_codex = __esm(() => {
|
|
|
17400
18135
|
"shell.pre": { support: "native", native: "PreToolUse" },
|
|
17401
18136
|
"tool.pre": { support: "native", native: "PreToolUse" },
|
|
17402
18137
|
"write.pre": { support: "undocumented", native: null },
|
|
17403
|
-
"shell.post":
|
|
18138
|
+
"shell.post": { support: "native", native: "PostToolUse" },
|
|
17404
18139
|
"subagent.start": { support: "native", native: "SubagentStart" },
|
|
17405
18140
|
"subagent.stop": { support: "native", native: "SubagentStop" },
|
|
17406
18141
|
"prompt.submit": undocumented,
|
|
@@ -17421,7 +18156,7 @@ var init_codex = __esm(() => {
|
|
|
17421
18156
|
worktreeIsolation: "undocumented",
|
|
17422
18157
|
maxConcurrency: "undocumented"
|
|
17423
18158
|
},
|
|
17424
|
-
provenance: { sessionId: "native", agentIdOnTool: "partial", postToolObserve: "
|
|
18159
|
+
provenance: { sessionId: "native", agentIdOnTool: "partial", postToolObserve: "native" },
|
|
17425
18160
|
interaction: { questions: "none", writeBoundary: "partial" },
|
|
17426
18161
|
stopControl: "undocumented",
|
|
17427
18162
|
shellAvailable: "native",
|
|
@@ -17487,6 +18222,7 @@ var init_codex = __esm(() => {
|
|
|
17487
18222
|
EVENTS2 = {
|
|
17488
18223
|
SessionStart: "session.start",
|
|
17489
18224
|
PreToolUse: "shell.pre",
|
|
18225
|
+
PostToolUse: "shell.post",
|
|
17490
18226
|
SubagentStart: "subagent.start",
|
|
17491
18227
|
SubagentStop: "subagent.stop"
|
|
17492
18228
|
};
|
|
@@ -17521,12 +18257,12 @@ var init_codex = __esm(() => {
|
|
|
17521
18257
|
};
|
|
17522
18258
|
},
|
|
17523
18259
|
render: render2,
|
|
17524
|
-
addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. A verifier or reviewer records workit ledger verdict under a session the lead assigns (WORKIT_SESSION_ID=<lead>-v<n>), never the author's. Merge and release need a workspace grant (workit grant show); a question answer is not host permission.</workit-codex-mutations>`
|
|
18260
|
+
addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. workit acts as this thread (CODEX_THREAD_ID${input.session.id ? `=${input.session.id}` : ""}) unless WORKIT_SESSION_ID is set. A verifier or reviewer records workit ledger verdict under a session the lead assigns (WORKIT_HOST=codex_cli WORKIT_SESSION_ID=<lead>-v<n>), never the author's. Merge and release need a workspace grant (workit grant show); a question answer is not host permission.</workit-codex-mutations>`
|
|
17525
18261
|
};
|
|
17526
18262
|
});
|
|
17527
18263
|
|
|
17528
18264
|
// packages/workit-core/src/hooks/hosts/cursor.ts
|
|
17529
|
-
import
|
|
18265
|
+
import path19 from "node:path";
|
|
17530
18266
|
var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (value) => {
|
|
17531
18267
|
if (!isRecord4(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
|
|
17532
18268
|
return { ok: false, error: "hook_event_name is required" };
|
|
@@ -17595,7 +18331,7 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
|
|
|
17595
18331
|
case "preCompact":
|
|
17596
18332
|
return { kind: "compact.pre", trigger: "auto" };
|
|
17597
18333
|
}
|
|
17598
|
-
}, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(
|
|
18334
|
+
}, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path19.sep) ? root : `${root}${path19.sep}`), hookCwd = (input) => {
|
|
17599
18335
|
const cwd = existingDirectory(input.cwd);
|
|
17600
18336
|
if (cwd && input.hook_event_name === "beforeShellExecution")
|
|
17601
18337
|
return cwd;
|
|
@@ -17613,6 +18349,8 @@ var undocumented2, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (val
|
|
|
17613
18349
|
json: cursorDeny(decision.reason),
|
|
17614
18350
|
exitCode: native !== null && BLOCKING.has(native) ? 2 : 0
|
|
17615
18351
|
};
|
|
18352
|
+
if (decision.kind === "context" && native === "beforeShellExecution")
|
|
18353
|
+
return { json: { permission: "allow", agent_message: decision.text }, exitCode: 0 };
|
|
17616
18354
|
if (decision.kind === "context")
|
|
17617
18355
|
return { json: { additional_context: decision.text }, exitCode: 0 };
|
|
17618
18356
|
if (decision.kind === "notice")
|
|
@@ -17762,7 +18500,8 @@ var init_cursor = __esm(() => {
|
|
|
17762
18500
|
}
|
|
17763
18501
|
};
|
|
17764
18502
|
},
|
|
17765
|
-
render: render3
|
|
18503
|
+
render: render3,
|
|
18504
|
+
addendum: (input) => input.session.id ? `<workit-session>Cursor puts no session id in the shell: prefix workit commands that record authorship with WORKIT_SESSION_ID=${input.session.id} (e.g. \`WORKIT_SESSION_ID=${input.session.id} workit git commit -m …\`). A verifier uses its own id, never this one.</workit-session>` : null
|
|
17766
18505
|
};
|
|
17767
18506
|
});
|
|
17768
18507
|
|
|
@@ -17812,6 +18551,7 @@ var init_hooks = __esm(async () => {
|
|
|
17812
18551
|
init_context();
|
|
17813
18552
|
init_policy();
|
|
17814
18553
|
init_write_gate();
|
|
18554
|
+
init_raw_git();
|
|
17815
18555
|
init_fields();
|
|
17816
18556
|
init_handle();
|
|
17817
18557
|
init_claude_code();
|