@brainervirus/workit-opencode 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/assets/skills/workit-ship/SKILL.md +14 -14
- package/dist/plugin.js +918 -141
- package/package.json +2 -2
package/dist/plugin.js
CHANGED
|
@@ -4,7 +4,7 @@ function define(plugin) {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
// packages/workit-core/src/core.ts
|
|
7
|
-
import { spawnSync as
|
|
7
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
8
8
|
import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
|
|
9
9
|
import path19 from "node:path";
|
|
10
10
|
|
|
@@ -9597,6 +9597,35 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
9597
9597
|
}
|
|
9598
9598
|
}
|
|
9599
9599
|
}
|
|
9600
|
+
// packages/workit-core/src/host-session.ts
|
|
9601
|
+
var HOST_SESSION_VARS = [
|
|
9602
|
+
["OPENCODE_SESSION_ID", () => "opencode"],
|
|
9603
|
+
["PI_SESSION_ID", () => "pi"],
|
|
9604
|
+
[
|
|
9605
|
+
"CODEX_THREAD_ID",
|
|
9606
|
+
(env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
|
|
9607
|
+
]
|
|
9608
|
+
];
|
|
9609
|
+
var family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
|
|
9610
|
+
function hostSessionFromEnv(env) {
|
|
9611
|
+
const value = (key) => env[key]?.trim() || null;
|
|
9612
|
+
let inner = null;
|
|
9613
|
+
for (const [key, host] of HOST_SESSION_VARS) {
|
|
9614
|
+
const session = value(key);
|
|
9615
|
+
if (session) {
|
|
9616
|
+
inner = { host: host(env), session };
|
|
9617
|
+
break;
|
|
9618
|
+
}
|
|
9619
|
+
}
|
|
9620
|
+
const declared = value("WORKIT_HOST");
|
|
9621
|
+
if (env.WORKIT_SESSION_ID !== undefined) {
|
|
9622
|
+
const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
|
|
9623
|
+
if (!inherited)
|
|
9624
|
+
return { host: declared, session: value("WORKIT_SESSION_ID") };
|
|
9625
|
+
}
|
|
9626
|
+
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
9627
|
+
}
|
|
9628
|
+
|
|
9600
9629
|
// packages/workit-core/src/core/package-root.ts
|
|
9601
9630
|
import { existsSync } from "node:fs";
|
|
9602
9631
|
import path3 from "node:path";
|
|
@@ -10561,9 +10590,10 @@ var drop = (lock) => {
|
|
|
10561
10590
|
};
|
|
10562
10591
|
var envActor = () => {
|
|
10563
10592
|
const value = (key) => process.env[key]?.trim() || null;
|
|
10593
|
+
const acting = hostSessionFromEnv(process.env);
|
|
10564
10594
|
return {
|
|
10565
|
-
host:
|
|
10566
|
-
session:
|
|
10595
|
+
host: acting.host ?? "runtime",
|
|
10596
|
+
session: acting.session,
|
|
10567
10597
|
agentId: value("WORKIT_AGENT_ID")
|
|
10568
10598
|
};
|
|
10569
10599
|
};
|
|
@@ -12487,6 +12517,7 @@ import { createHash as createHash6, randomBytes as randomBytes2 } from "node:cry
|
|
|
12487
12517
|
import fs10 from "node:fs";
|
|
12488
12518
|
import path9 from "node:path";
|
|
12489
12519
|
var LEDGER_VERSION = 1;
|
|
12520
|
+
var MAX_LINE_BYTES = 4096;
|
|
12490
12521
|
var PASSING = new Set(["verified", "tests-verified", "type-check-only"]);
|
|
12491
12522
|
var FAILING = new Set(["failed", "blocked"]);
|
|
12492
12523
|
var STRONG_RESULTS = new Set(["verified", "tests-verified"]);
|
|
@@ -12586,6 +12617,7 @@ function ledgerPath(cwd) {
|
|
|
12586
12617
|
const root = storeRoot(cwd);
|
|
12587
12618
|
return root.ok ? { ok: true, value: path9.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
12588
12619
|
}
|
|
12620
|
+
var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
|
|
12589
12621
|
var NETWORK_FS_TYPES = new Set([
|
|
12590
12622
|
26985,
|
|
12591
12623
|
20859,
|
|
@@ -12598,6 +12630,158 @@ var NETWORK_FS_TYPES = new Set([
|
|
|
12598
12630
|
1196443219,
|
|
12599
12631
|
198183888
|
|
12600
12632
|
]);
|
|
12633
|
+
var isNetworkFsType = (type) => NETWORK_FS_TYPES.has(type >>> 0);
|
|
12634
|
+
var onNetworkFs = (dir) => {
|
|
12635
|
+
if (process.platform !== "linux")
|
|
12636
|
+
return false;
|
|
12637
|
+
try {
|
|
12638
|
+
return isNetworkFsType(fs10.statfsSync(dir).type);
|
|
12639
|
+
} catch {
|
|
12640
|
+
return false;
|
|
12641
|
+
}
|
|
12642
|
+
};
|
|
12643
|
+
var LOCK_WAIT_MS = 5000;
|
|
12644
|
+
var LOCK_STALE_MS = 30000;
|
|
12645
|
+
var LOCK_OWNER = "owner";
|
|
12646
|
+
var lockToken = (lock) => {
|
|
12647
|
+
try {
|
|
12648
|
+
return fs10.readFileSync(path9.join(lock, LOCK_OWNER), "utf8");
|
|
12649
|
+
} catch {
|
|
12650
|
+
return null;
|
|
12651
|
+
}
|
|
12652
|
+
};
|
|
12653
|
+
var lockAgeMs = (lock) => {
|
|
12654
|
+
for (const target of [path9.join(lock, LOCK_OWNER), lock]) {
|
|
12655
|
+
try {
|
|
12656
|
+
return Date.now() - fs10.statSync(target).mtimeMs;
|
|
12657
|
+
} catch {}
|
|
12658
|
+
}
|
|
12659
|
+
return null;
|
|
12660
|
+
};
|
|
12661
|
+
var ledgerLock = {
|
|
12662
|
+
acquire(lock) {
|
|
12663
|
+
try {
|
|
12664
|
+
fs10.mkdirSync(lock);
|
|
12665
|
+
} catch (error) {
|
|
12666
|
+
if (error.code === "EEXIST")
|
|
12667
|
+
return null;
|
|
12668
|
+
throw error;
|
|
12669
|
+
}
|
|
12670
|
+
const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
|
|
12671
|
+
fs10.writeFileSync(path9.join(lock, LOCK_OWNER), token);
|
|
12672
|
+
return token;
|
|
12673
|
+
},
|
|
12674
|
+
release(lock, token) {
|
|
12675
|
+
if (lockToken(lock) !== token)
|
|
12676
|
+
return false;
|
|
12677
|
+
const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
|
|
12678
|
+
try {
|
|
12679
|
+
fs10.renameSync(lock, tomb);
|
|
12680
|
+
} catch {
|
|
12681
|
+
return false;
|
|
12682
|
+
}
|
|
12683
|
+
if (lockToken(tomb) !== token) {
|
|
12684
|
+
try {
|
|
12685
|
+
fs10.renameSync(tomb, lock);
|
|
12686
|
+
} catch {}
|
|
12687
|
+
return false;
|
|
12688
|
+
}
|
|
12689
|
+
fs10.rmSync(tomb, { recursive: true, force: true });
|
|
12690
|
+
return true;
|
|
12691
|
+
},
|
|
12692
|
+
token: lockToken,
|
|
12693
|
+
reap(lock, observed) {
|
|
12694
|
+
const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
|
|
12695
|
+
try {
|
|
12696
|
+
fs10.renameSync(lock, tomb);
|
|
12697
|
+
} catch {
|
|
12698
|
+
return false;
|
|
12699
|
+
}
|
|
12700
|
+
if (lockToken(tomb) === observed) {
|
|
12701
|
+
fs10.rmSync(tomb, { recursive: true, force: true });
|
|
12702
|
+
return true;
|
|
12703
|
+
}
|
|
12704
|
+
try {
|
|
12705
|
+
fs10.renameSync(tomb, lock);
|
|
12706
|
+
} catch {
|
|
12707
|
+
fs10.rmSync(tomb, { recursive: true, force: true });
|
|
12708
|
+
}
|
|
12709
|
+
return false;
|
|
12710
|
+
}
|
|
12711
|
+
};
|
|
12712
|
+
function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
12713
|
+
const lock = `${file}.lock`;
|
|
12714
|
+
const deadline = Date.now() + waitMs;
|
|
12715
|
+
let token = null;
|
|
12716
|
+
for (;; ) {
|
|
12717
|
+
token = ledgerLock.acquire(lock);
|
|
12718
|
+
if (token)
|
|
12719
|
+
break;
|
|
12720
|
+
const observed = lockToken(lock);
|
|
12721
|
+
const age = lockAgeMs(lock);
|
|
12722
|
+
if (age !== null && age > LOCK_STALE_MS && ledgerLock.reap(lock, observed))
|
|
12723
|
+
continue;
|
|
12724
|
+
if (Date.now() >= deadline)
|
|
12725
|
+
return null;
|
|
12726
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
|
|
12727
|
+
}
|
|
12728
|
+
try {
|
|
12729
|
+
return fn();
|
|
12730
|
+
} finally {
|
|
12731
|
+
ledgerLock.release(lock, token);
|
|
12732
|
+
}
|
|
12733
|
+
}
|
|
12734
|
+
function appendLine(file, line, options) {
|
|
12735
|
+
const write = () => {
|
|
12736
|
+
const fd = fs10.openSync(file, "a+");
|
|
12737
|
+
try {
|
|
12738
|
+
const size = fs10.fstatSync(fd).size;
|
|
12739
|
+
let fence = "";
|
|
12740
|
+
if (size > 0) {
|
|
12741
|
+
const last = Buffer.alloc(1);
|
|
12742
|
+
fs10.readSync(fd, last, 0, 1, size - 1);
|
|
12743
|
+
if (last[0] !== 10)
|
|
12744
|
+
fence = `
|
|
12745
|
+
`;
|
|
12746
|
+
}
|
|
12747
|
+
const bytes = Buffer.from(fence + line);
|
|
12748
|
+
const written = fs10.writeSync(fd, bytes);
|
|
12749
|
+
if (written !== bytes.length)
|
|
12750
|
+
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
12751
|
+
return { ok: true, value: undefined };
|
|
12752
|
+
} finally {
|
|
12753
|
+
fs10.closeSync(fd);
|
|
12754
|
+
}
|
|
12755
|
+
};
|
|
12756
|
+
try {
|
|
12757
|
+
fs10.mkdirSync(path9.dirname(file), { recursive: true });
|
|
12758
|
+
if (!options.forceLock && !onNetworkFs(path9.dirname(file)))
|
|
12759
|
+
return write();
|
|
12760
|
+
const locked = withLedgerLock(file, write);
|
|
12761
|
+
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
12762
|
+
} catch (error) {
|
|
12763
|
+
return err("unavailable", `cannot append to ${file}: ${error.message}`);
|
|
12764
|
+
}
|
|
12765
|
+
}
|
|
12766
|
+
var serialize = (row, now) => {
|
|
12767
|
+
const full = { v: LEDGER_VERSION, id: newId2(), at: now.toISOString(), ...row };
|
|
12768
|
+
return { full, line: `${JSON.stringify(full)}
|
|
12769
|
+
` };
|
|
12770
|
+
};
|
|
12771
|
+
function appendRaw(cwd, row, options) {
|
|
12772
|
+
const { full, line } = serialize(row, options.now ?? new Date);
|
|
12773
|
+
const bytes = Buffer.byteLength(line);
|
|
12774
|
+
if (bytes > MAX_LINE_BYTES)
|
|
12775
|
+
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>`);
|
|
12776
|
+
const file = ledgerPath(cwd);
|
|
12777
|
+
if (!file.ok)
|
|
12778
|
+
return file;
|
|
12779
|
+
const written = appendLine(file.value, line, options);
|
|
12780
|
+
return written.ok ? { ok: true, value: full } : written;
|
|
12781
|
+
}
|
|
12782
|
+
function appendHookObserved(cwd, row) {
|
|
12783
|
+
return appendRaw(cwd, { ...row, observer: "host_hook" }, {});
|
|
12784
|
+
}
|
|
12601
12785
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12602
12786
|
var str2 = (value) => typeof value === "string" ? value : null;
|
|
12603
12787
|
var normalizeActor = (value) => {
|
|
@@ -14291,6 +14475,7 @@ var gitContext = (workspaceRoot, paths = []) => {
|
|
|
14291
14475
|
};
|
|
14292
14476
|
|
|
14293
14477
|
// packages/workit-core/src/core/workspaces.ts
|
|
14478
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
14294
14479
|
import { createHash as createHash8 } from "node:crypto";
|
|
14295
14480
|
import { readFileSync as readFileSync4, realpathSync as realpathSync3 } from "node:fs";
|
|
14296
14481
|
import path13 from "node:path";
|
|
@@ -14535,6 +14720,53 @@ var validateWorkspaceGlob = (glob) => {
|
|
|
14535
14720
|
}
|
|
14536
14721
|
return { ok: true };
|
|
14537
14722
|
};
|
|
14723
|
+
|
|
14724
|
+
class WorkspaceConfigError extends Error {
|
|
14725
|
+
name = "WorkspaceConfigError";
|
|
14726
|
+
}
|
|
14727
|
+
var mainCheckouts = new Map;
|
|
14728
|
+
var mainCheckoutOf = (cwd) => {
|
|
14729
|
+
const cached = mainCheckouts.get(cwd);
|
|
14730
|
+
if (cached !== undefined)
|
|
14731
|
+
return cached;
|
|
14732
|
+
const env = { ...process.env };
|
|
14733
|
+
for (const name of ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"])
|
|
14734
|
+
delete env[name];
|
|
14735
|
+
const git = (args) => {
|
|
14736
|
+
const run = spawnSync8("git", args, {
|
|
14737
|
+
cwd,
|
|
14738
|
+
env,
|
|
14739
|
+
encoding: "utf8",
|
|
14740
|
+
timeout: 5000,
|
|
14741
|
+
windowsHide: true
|
|
14742
|
+
});
|
|
14743
|
+
return run.status === 0 ? run.stdout : null;
|
|
14744
|
+
};
|
|
14745
|
+
let main = null;
|
|
14746
|
+
const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
|
|
14747
|
+
const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
|
|
14748
|
+
if (gitDir && common && path13.resolve(gitDir) !== path13.resolve(common)) {
|
|
14749
|
+
const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
|
|
14750
|
+
main = listed?.trim() || (path13.basename(common) === ".git" ? path13.dirname(common) : common);
|
|
14751
|
+
}
|
|
14752
|
+
mainCheckouts.set(cwd, main);
|
|
14753
|
+
return main;
|
|
14754
|
+
};
|
|
14755
|
+
var matchingEntries = (cwd, entries) => {
|
|
14756
|
+
const match = (where) => {
|
|
14757
|
+
const targets = [where, realpathOf(where)].map((value) => value.replaceAll("\\", "/"));
|
|
14758
|
+
return entries.filter((entry) => {
|
|
14759
|
+
const glob = entry.glob.replaceAll("\\", "/");
|
|
14760
|
+
const canonical = canonicalGlob(glob);
|
|
14761
|
+
return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
|
|
14762
|
+
});
|
|
14763
|
+
};
|
|
14764
|
+
const direct = match(cwd);
|
|
14765
|
+
if (direct.length)
|
|
14766
|
+
return direct;
|
|
14767
|
+
const main = mainCheckoutOf(cwd);
|
|
14768
|
+
return main ? match(main) : direct;
|
|
14769
|
+
};
|
|
14538
14770
|
var realpathOf = (p) => {
|
|
14539
14771
|
const real = realpathSync3.native ?? realpathSync3;
|
|
14540
14772
|
try {
|
|
@@ -14559,43 +14791,29 @@ var selectWorkspaceMatch = (matches, cwd, workspaceName) => {
|
|
|
14559
14791
|
if (named.length === 1)
|
|
14560
14792
|
return named[0];
|
|
14561
14793
|
if (named.length > 1)
|
|
14562
|
-
throw new
|
|
14794
|
+
throw new WorkspaceConfigError(`ambiguous workspace ${JSON.stringify(workspaceName)} for ${cwd}`);
|
|
14563
14795
|
if (matches.length > 0) {
|
|
14564
|
-
throw new
|
|
14796
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}; matching choices: ${matches.map((entry) => entry.name).join(", ")}`);
|
|
14565
14797
|
}
|
|
14566
|
-
throw new
|
|
14798
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(workspaceName)} does not match ${cwd}`);
|
|
14567
14799
|
}
|
|
14568
14800
|
if (matches.length < 2)
|
|
14569
14801
|
return matches[0];
|
|
14570
14802
|
const highestSpecificity = Math.max(...matches.map((entry) => globSpecificity(entry.glob)));
|
|
14571
14803
|
const mostSpecific = matches.filter((entry) => globSpecificity(entry.glob) === highestSpecificity);
|
|
14572
14804
|
if (mostSpecific.length > 1) {
|
|
14573
|
-
throw new
|
|
14805
|
+
throw new WorkspaceConfigError(`ambiguous workspace for ${cwd}; choose one of: ${mostSpecific.map((entry) => entry.name).join(", ")}`);
|
|
14574
14806
|
}
|
|
14575
14807
|
return mostSpecific[0];
|
|
14576
14808
|
};
|
|
14577
14809
|
var resolveWorkspaceFromEntries = (cwd, entries, workspaceName) => {
|
|
14578
|
-
const
|
|
14579
|
-
const matches = [];
|
|
14580
|
-
for (const ws of entries) {
|
|
14581
|
-
const glob = ws.glob.replaceAll("\\", "/");
|
|
14582
|
-
const canonical = canonicalGlob(glob);
|
|
14583
|
-
let matched = false;
|
|
14584
|
-
for (const target of targets) {
|
|
14585
|
-
if (matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target)) {
|
|
14586
|
-
matched = true;
|
|
14587
|
-
break;
|
|
14588
|
-
}
|
|
14589
|
-
}
|
|
14590
|
-
if (matched)
|
|
14591
|
-
matches.push(ws);
|
|
14592
|
-
}
|
|
14810
|
+
const matches = matchingEntries(cwd, entries);
|
|
14593
14811
|
return selectWorkspaceMatch(matches, cwd, workspaceName) ?? null;
|
|
14594
14812
|
};
|
|
14595
14813
|
var resolveWorkspaceFrom = (cwd, dir, workspaceName) => {
|
|
14596
14814
|
const result = readWorkspacesResult(dir);
|
|
14597
14815
|
if (result.status === "malformed" || result.status === "invalid")
|
|
14598
|
-
throw new
|
|
14816
|
+
throw new WorkspaceConfigError(result.error);
|
|
14599
14817
|
return resolveWorkspaceFromEntries(cwd, result.entries, workspaceName);
|
|
14600
14818
|
};
|
|
14601
14819
|
var runtimeWorkspacePolicySchema = (kind) => {
|
|
@@ -14627,31 +14845,26 @@ var matchRuntimeWorkspace = (cwd) => {
|
|
|
14627
14845
|
} catch (error) {
|
|
14628
14846
|
if (error.code === "ENOENT")
|
|
14629
14847
|
return null;
|
|
14630
|
-
throw new
|
|
14848
|
+
throw new WorkspaceConfigError(`${file} could not be read: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
14631
14849
|
}
|
|
14632
14850
|
let parsed;
|
|
14633
14851
|
try {
|
|
14634
14852
|
parsed = JSON.parse(raw);
|
|
14635
14853
|
} catch {
|
|
14636
|
-
throw new
|
|
14854
|
+
throw new WorkspaceConfigError(`${file} is not valid JSON`);
|
|
14637
14855
|
}
|
|
14638
14856
|
const validated = runtimeWorkspaceIndexSchema.safeParse(parsed);
|
|
14639
14857
|
if (!validated.success) {
|
|
14640
14858
|
const detail = validated.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspaces"}: ${issue.message}`).join("; ");
|
|
14641
|
-
throw new
|
|
14859
|
+
throw new WorkspaceConfigError(`${file} has invalid workspace matching data: ${detail}`);
|
|
14642
14860
|
}
|
|
14643
14861
|
const entries = validated.data.workspaces;
|
|
14644
14862
|
for (const entry of entries ?? []) {
|
|
14645
14863
|
const glob = validateWorkspaceGlob(entry.glob);
|
|
14646
14864
|
if (!glob.ok)
|
|
14647
|
-
throw new
|
|
14865
|
+
throw new WorkspaceConfigError(`${file} workspace ${entry.name}: ${glob.error}`);
|
|
14648
14866
|
}
|
|
14649
|
-
const
|
|
14650
|
-
const matches = (entries ?? []).filter((entry) => {
|
|
14651
|
-
const glob = entry.glob.replaceAll("\\", "/");
|
|
14652
|
-
const canonical = canonicalGlob(glob);
|
|
14653
|
-
return targets.some((target) => matchWorkspace(glob, target) || canonical !== glob && matchWorkspace(canonical, target));
|
|
14654
|
-
});
|
|
14867
|
+
const matches = matchingEntries(cwd, entries ?? []);
|
|
14655
14868
|
const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
|
|
14656
14869
|
const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
|
|
14657
14870
|
return selected ? { file, selected } : null;
|
|
@@ -14668,7 +14881,7 @@ var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
|
|
|
14668
14881
|
const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
|
|
14669
14882
|
if (!policy.success) {
|
|
14670
14883
|
const detail = policy.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspace"}: ${issue.message}`).join("; ");
|
|
14671
|
-
throw new
|
|
14884
|
+
throw new WorkspaceConfigError(`${file} has invalid ${kind} policy configuration: ${detail}`);
|
|
14672
14885
|
}
|
|
14673
14886
|
return policy.data;
|
|
14674
14887
|
};
|
|
@@ -14679,10 +14892,10 @@ var resolveRuntimeWorkspacePolicy = (cwd, kind, requestedProfile) => {
|
|
|
14679
14892
|
const key = kind === "branch" ? "branchPolicy" : "commitPolicy";
|
|
14680
14893
|
const profileName = requestedProfile?.trim() || candidate.defaultProfile;
|
|
14681
14894
|
if (candidate.defaultProfile && !Object.hasOwn(candidate.profiles ?? {}, candidate.defaultProfile))
|
|
14682
|
-
throw new
|
|
14895
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(candidate.name)} has no profile ${JSON.stringify(candidate.defaultProfile)}`);
|
|
14683
14896
|
const profile = profileName ? candidate.profiles?.[profileName] : undefined;
|
|
14684
14897
|
if (profileName && !profile)
|
|
14685
|
-
throw new
|
|
14898
|
+
throw new WorkspaceConfigError(`workspace ${JSON.stringify(candidate.name)} has no profile ${JSON.stringify(profileName)}`);
|
|
14686
14899
|
const profilePolicy = profile?.[key];
|
|
14687
14900
|
const workspacePolicy = candidate[key];
|
|
14688
14901
|
return {
|
|
@@ -14702,11 +14915,11 @@ function workspaceDefaultTarget(cwd, globalDefault) {
|
|
|
14702
14915
|
// packages/workit-core/src/core/vcs-config.ts
|
|
14703
14916
|
import fs12 from "node:fs";
|
|
14704
14917
|
import path14 from "node:path";
|
|
14705
|
-
import { spawnSync as
|
|
14918
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
14706
14919
|
|
|
14707
14920
|
// packages/workit-core/src/core/release-tracks.ts
|
|
14708
14921
|
import { createHash as createHash9 } from "node:crypto";
|
|
14709
|
-
import { spawnSync as
|
|
14922
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
14710
14923
|
class ReleaseTrackError extends Error {
|
|
14711
14924
|
}
|
|
14712
14925
|
var KNOWN_FIELDS = new Set([
|
|
@@ -14991,7 +15204,7 @@ function resolveReleaseTrack(input) {
|
|
|
14991
15204
|
return fallback(`${branch} has the same or unrelated fork points with ${[...new Set(newest.map((fork) => `${fork.ref} (${fork.track.name === IMPLICIT ? "workspace default" : fork.track.name})`))].join(" and ")}`);
|
|
14992
15205
|
}
|
|
14993
15206
|
var git4 = (cwd, args) => {
|
|
14994
|
-
const run =
|
|
15207
|
+
const run = spawnSync9("git", args, {
|
|
14995
15208
|
cwd,
|
|
14996
15209
|
encoding: "utf8",
|
|
14997
15210
|
timeout: 20000,
|
|
@@ -15106,7 +15319,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
15106
15319
|
var workspacesPath = () => path14.join(configDir(), "workspaces.json");
|
|
15107
15320
|
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
15108
15321
|
var remoteProvider = (cwd) => {
|
|
15109
|
-
const r =
|
|
15322
|
+
const r = spawnSync10("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
15110
15323
|
if (r.status !== 0)
|
|
15111
15324
|
return null;
|
|
15112
15325
|
const url = (r.stdout ?? "").trim();
|
|
@@ -15143,7 +15356,7 @@ var remoteEndpoint = (remote) => {
|
|
|
15143
15356
|
var configuredSshEndpoint = (host) => {
|
|
15144
15357
|
if (host.startsWith("-"))
|
|
15145
15358
|
return null;
|
|
15146
|
-
const resolved =
|
|
15359
|
+
const resolved = spawnSync10("ssh", ["-G", host], {
|
|
15147
15360
|
encoding: "utf8",
|
|
15148
15361
|
timeout: 5000,
|
|
15149
15362
|
maxBuffer: 1024 * 1024,
|
|
@@ -15316,7 +15529,7 @@ function mergedPrStyle(limit = 6, cwd) {
|
|
|
15316
15529
|
`).filter((l) => l.startsWith("## ")).map((l) => l.trim()),
|
|
15317
15530
|
descriptionPreview: desc.slice(0, 600)
|
|
15318
15531
|
});
|
|
15319
|
-
const remoteResult =
|
|
15532
|
+
const remoteResult = spawnSync10("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
15320
15533
|
cwd,
|
|
15321
15534
|
encoding: "utf8"
|
|
15322
15535
|
});
|
|
@@ -15332,7 +15545,7 @@ function mergedPrStyle(limit = 6, cwd) {
|
|
|
15332
15545
|
if (!hostingApiHostMatches(remote, host))
|
|
15333
15546
|
return { ok: false, error: "PR style target does not match the provider host" };
|
|
15334
15547
|
if (provider === "gitlab") {
|
|
15335
|
-
const run = (args) =>
|
|
15548
|
+
const run = (args) => spawnSync10("glab", ["api", ...args], {
|
|
15336
15549
|
cwd,
|
|
15337
15550
|
encoding: "utf8",
|
|
15338
15551
|
env
|
|
@@ -15352,7 +15565,7 @@ function mergedPrStyle(limit = 6, cwd) {
|
|
|
15352
15565
|
});
|
|
15353
15566
|
}
|
|
15354
15567
|
} else if (provider === "github") {
|
|
15355
|
-
const r =
|
|
15568
|
+
const r = spawnSync10("gh", [
|
|
15356
15569
|
"pr",
|
|
15357
15570
|
"list",
|
|
15358
15571
|
"--repo",
|
|
@@ -15476,6 +15689,7 @@ var validateBranchNameFor = (workspaceRoot, name) => {
|
|
|
15476
15689
|
};
|
|
15477
15690
|
}
|
|
15478
15691
|
};
|
|
15692
|
+
var resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
|
|
15479
15693
|
|
|
15480
15694
|
// packages/workit-core/src/core/route-intent.ts
|
|
15481
15695
|
var shellBranchTarget = (command) => {
|
|
@@ -17423,7 +17637,7 @@ class WorkitCore {
|
|
|
17423
17637
|
}
|
|
17424
17638
|
}
|
|
17425
17639
|
// packages/workit-core/src/core/repo-context.ts
|
|
17426
|
-
import { spawnSync as
|
|
17640
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
17427
17641
|
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
|
|
17428
17642
|
import path16 from "node:path";
|
|
17429
17643
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
@@ -17452,7 +17666,7 @@ var invalidRange = (cwd) => ({
|
|
|
17452
17666
|
cwd
|
|
17453
17667
|
});
|
|
17454
17668
|
var runGit = (cwd, args) => {
|
|
17455
|
-
const result =
|
|
17669
|
+
const result = spawnSync11("git", args, { cwd, encoding: "utf8" });
|
|
17456
17670
|
return {
|
|
17457
17671
|
stdout: (result.stdout ?? "").trimEnd(),
|
|
17458
17672
|
stderr: (result.stderr ?? "").trimEnd(),
|
|
@@ -17893,12 +18107,12 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
17893
18107
|
}
|
|
17894
18108
|
|
|
17895
18109
|
// packages/workit-core/src/core/tracker-issues.ts
|
|
17896
|
-
import { spawnSync as
|
|
18110
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
17897
18111
|
|
|
17898
18112
|
// packages/workit-core/src/core/pr-create.ts
|
|
17899
18113
|
import fs13 from "node:fs";
|
|
17900
18114
|
import path17 from "node:path";
|
|
17901
|
-
import { spawnSync as
|
|
18115
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
17902
18116
|
// packages/workit-core/src/forge/pr-body.ts
|
|
17903
18117
|
function parseGhIssue(value) {
|
|
17904
18118
|
const m = /issues\/(\d+)/.exec(value);
|
|
@@ -17923,7 +18137,7 @@ function whichOnPath(tool) {
|
|
|
17923
18137
|
}
|
|
17924
18138
|
var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
|
|
17925
18139
|
var pushRemote = (cwd) => {
|
|
17926
|
-
const result =
|
|
18140
|
+
const result = spawnSync12("git", ["remote", "get-url", "--push", "--all", "origin"], {
|
|
17927
18141
|
cwd,
|
|
17928
18142
|
encoding: "utf8"
|
|
17929
18143
|
});
|
|
@@ -17954,7 +18168,7 @@ var defaultCli = (bin, available) => {
|
|
|
17954
18168
|
if (!available)
|
|
17955
18169
|
return null;
|
|
17956
18170
|
return (args, root) => {
|
|
17957
|
-
const out =
|
|
18171
|
+
const out = spawnSync13(bin, args, {
|
|
17958
18172
|
cwd: root,
|
|
17959
18173
|
encoding: "utf8",
|
|
17960
18174
|
env: { ...process.env, PATH: process.env.PATH ?? "" }
|
|
@@ -18530,7 +18744,7 @@ function resolveInside(root, candidate) {
|
|
|
18530
18744
|
}
|
|
18531
18745
|
function run2(root, executable, args, env = {}) {
|
|
18532
18746
|
const cwd = realpathSync5(root);
|
|
18533
|
-
const result =
|
|
18747
|
+
const result = spawnSync14(executable, args, {
|
|
18534
18748
|
cwd,
|
|
18535
18749
|
encoding: "utf8",
|
|
18536
18750
|
env: { ...process.env, ...env }
|
|
@@ -18671,36 +18885,43 @@ var shellPolicy = (cwd, command) => {
|
|
|
18671
18885
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
18672
18886
|
import { realpathSync as realpathSync6 } from "node:fs";
|
|
18673
18887
|
import path21 from "node:path";
|
|
18674
|
-
|
|
18675
|
-
|
|
18676
|
-
var
|
|
18677
|
-
|
|
18678
|
-
for (let
|
|
18679
|
-
|
|
18680
|
-
|
|
18681
|
-
|
|
18682
|
-
|
|
18683
|
-
|
|
18684
|
-
|
|
18888
|
+
|
|
18889
|
+
// packages/workit-core/src/hooks/shell-words.ts
|
|
18890
|
+
var closingQuote = (command, start, dialect) => {
|
|
18891
|
+
const quote = command[start];
|
|
18892
|
+
for (let index = start + 1;index < command.length; index++) {
|
|
18893
|
+
const char = command[index];
|
|
18894
|
+
if (quote === "'") {
|
|
18895
|
+
if (char !== "'")
|
|
18896
|
+
continue;
|
|
18897
|
+
if (dialect === "powershell" && command[index + 1] === "'") {
|
|
18898
|
+
index++;
|
|
18899
|
+
continue;
|
|
18900
|
+
}
|
|
18901
|
+
return index;
|
|
18685
18902
|
}
|
|
18903
|
+
if (dialect === "posix" && char === "\\" || dialect === "powershell" && char === "`") {
|
|
18904
|
+
index++;
|
|
18905
|
+
continue;
|
|
18906
|
+
}
|
|
18907
|
+
if (char === '"')
|
|
18908
|
+
return index;
|
|
18686
18909
|
}
|
|
18910
|
+
return -1;
|
|
18687
18911
|
};
|
|
18688
|
-
var
|
|
18689
|
-
|
|
18690
|
-
|
|
18691
|
-
|
|
18692
|
-
return true;
|
|
18693
|
-
const posix = relative.split(path21.sep).join("/");
|
|
18694
|
-
const segments = posix.split("/");
|
|
18695
|
-
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
18912
|
+
var unquote = (body, quote, dialect) => {
|
|
18913
|
+
if (quote === "'")
|
|
18914
|
+
return dialect === "powershell" ? body.replaceAll("''", "'") : body;
|
|
18915
|
+
return dialect === "posix" ? body.replace(/\\(["\\$`])/g, "$1") : body.replace(/`(.)/g, "$1");
|
|
18696
18916
|
};
|
|
18697
|
-
var segmentsOf = (command) => {
|
|
18917
|
+
var segmentsOf = (command, dialect = "posix") => {
|
|
18698
18918
|
const segments = [];
|
|
18699
18919
|
let current = { words: [], redirects: [] };
|
|
18700
18920
|
let word = "";
|
|
18701
18921
|
let inWord = false;
|
|
18702
18922
|
let pending = null;
|
|
18703
18923
|
const heredocs = [];
|
|
18924
|
+
const escape = dialect === "posix" ? "\\" : "`";
|
|
18704
18925
|
const flushWord = () => {
|
|
18705
18926
|
if (!inWord)
|
|
18706
18927
|
return;
|
|
@@ -18724,11 +18945,11 @@ var segmentsOf = (command) => {
|
|
|
18724
18945
|
for (let index = 0;index < command.length; index++) {
|
|
18725
18946
|
const char = command[index];
|
|
18726
18947
|
if (char === "'" || char === '"') {
|
|
18727
|
-
const end = command
|
|
18728
|
-
word += command.slice(index + 1, end < 0 ? undefined : end);
|
|
18948
|
+
const end = closingQuote(command, index, dialect);
|
|
18949
|
+
word += unquote(command.slice(index + 1, end < 0 ? undefined : end), char, dialect);
|
|
18729
18950
|
inWord = true;
|
|
18730
18951
|
index = end < 0 ? command.length : end;
|
|
18731
|
-
} else if (char ===
|
|
18952
|
+
} else if (char === escape && index + 1 < command.length) {
|
|
18732
18953
|
word += command[++index];
|
|
18733
18954
|
inWord = true;
|
|
18734
18955
|
} else if (char === `
|
|
@@ -18745,7 +18966,14 @@ var segmentsOf = (command) => {
|
|
|
18745
18966
|
}
|
|
18746
18967
|
} else if (/\s/.test(char))
|
|
18747
18968
|
flushWord();
|
|
18748
|
-
else if ("
|
|
18969
|
+
else if (char === "(" || char === ")") {
|
|
18970
|
+
if (char === "(" && inWord && word.endsWith("$")) {
|
|
18971
|
+
word = word.slice(0, -1);
|
|
18972
|
+
inWord = word !== "";
|
|
18973
|
+
}
|
|
18974
|
+
flushSegment();
|
|
18975
|
+
segments.push({ words: [], redirects: [], group: char === "(" ? "open" : "close" });
|
|
18976
|
+
} else if (";&|".includes(char)) {
|
|
18749
18977
|
if (char === "&" && command[index + 1] === ">")
|
|
18750
18978
|
continue;
|
|
18751
18979
|
flushSegment();
|
|
@@ -18763,7 +18991,7 @@ var segmentsOf = (command) => {
|
|
|
18763
18991
|
inWord = true;
|
|
18764
18992
|
}
|
|
18765
18993
|
pending = "redirect";
|
|
18766
|
-
} else if (char === "<") {
|
|
18994
|
+
} else if (char === "<" && dialect === "posix") {
|
|
18767
18995
|
flushWord();
|
|
18768
18996
|
if (command[index + 1] === "<") {
|
|
18769
18997
|
index++;
|
|
@@ -18780,6 +19008,31 @@ var segmentsOf = (command) => {
|
|
|
18780
19008
|
flushSegment();
|
|
18781
19009
|
return segments;
|
|
18782
19010
|
};
|
|
19011
|
+
|
|
19012
|
+
// packages/workit-core/src/hooks/write-gate.ts
|
|
19013
|
+
var NONE2 = { kind: "none" };
|
|
19014
|
+
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
19015
|
+
var canonical2 = (file) => {
|
|
19016
|
+
let rest = "";
|
|
19017
|
+
for (let dir = path21.resolve(file);; dir = path21.dirname(dir)) {
|
|
19018
|
+
try {
|
|
19019
|
+
return path21.join(realpathSync6(dir), rest);
|
|
19020
|
+
} catch {
|
|
19021
|
+
if (path21.dirname(dir) === dir)
|
|
19022
|
+
return path21.resolve(file);
|
|
19023
|
+
rest = rest ? path21.join(path21.basename(dir), rest) : path21.basename(dir);
|
|
19024
|
+
}
|
|
19025
|
+
}
|
|
19026
|
+
};
|
|
19027
|
+
var exempt = (cwd, root, file, plans) => {
|
|
19028
|
+
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
19029
|
+
const relative = path21.relative(fold(canonical2(root)), fold(canonical2(path21.resolve(cwd, file))));
|
|
19030
|
+
if (relative.startsWith("..") || path21.isAbsolute(relative))
|
|
19031
|
+
return true;
|
|
19032
|
+
const posix = relative.split(path21.sep).join("/");
|
|
19033
|
+
const segments = posix.split("/");
|
|
19034
|
+
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
19035
|
+
};
|
|
18783
19036
|
var PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs"]);
|
|
18784
19037
|
var operands = (words) => words.filter((item) => !item.startsWith("-"));
|
|
18785
19038
|
var editsOf = (input) => {
|
|
@@ -18929,8 +19182,454 @@ function writeGate(cwd, paths) {
|
|
|
18929
19182
|
return NONE2;
|
|
18930
19183
|
}
|
|
18931
19184
|
}
|
|
19185
|
+
// packages/workit-core/src/hooks/raw-git.ts
|
|
19186
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
19187
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
19188
|
+
import fs15 from "node:fs";
|
|
19189
|
+
import os4 from "node:os";
|
|
19190
|
+
import path22 from "node:path";
|
|
19191
|
+
var NONE3 = { kind: "none" };
|
|
19192
|
+
var SHELLS = new Set(["sh", "bash", "zsh", "dash", "ksh"]);
|
|
19193
|
+
var PREFIXES3 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "nice", "&"]);
|
|
19194
|
+
var SCRIPT_FLAG = /^-[a-zA-Z]*c[a-zA-Z]*$/;
|
|
19195
|
+
var CD = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
19196
|
+
var PUSHD = new Set(["pushd", "push-location"]);
|
|
19197
|
+
var POPD = new Set(["popd", "pop-location"]);
|
|
19198
|
+
var GIT_VALUE_OPTIONS = new Set([
|
|
19199
|
+
"-c",
|
|
19200
|
+
"--git-dir",
|
|
19201
|
+
"--work-tree",
|
|
19202
|
+
"--namespace",
|
|
19203
|
+
"--exec-path",
|
|
19204
|
+
"--config-env",
|
|
19205
|
+
"--super-prefix"
|
|
19206
|
+
]);
|
|
19207
|
+
var isAbsolute = (value) => path22.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
19208
|
+
var joinDir = (base, next) => {
|
|
19209
|
+
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
19210
|
+
return;
|
|
19211
|
+
const expanded = next === "~" || next.startsWith("~/") ? path22.join(os4.homedir(), next.slice(1)) : next;
|
|
19212
|
+
return base === null || isAbsolute(expanded) ? expanded : path22.join(base, expanded);
|
|
19213
|
+
};
|
|
19214
|
+
var cdTarget = (words) => {
|
|
19215
|
+
const args = words.slice(1);
|
|
19216
|
+
const flag = args.findIndex((word) => /^-(?:literal)?path$/i.test(word));
|
|
19217
|
+
if (flag >= 0)
|
|
19218
|
+
return args[flag + 1] ?? null;
|
|
19219
|
+
return args.find((word) => word === "-" || !word.startsWith("-")) ?? null;
|
|
19220
|
+
};
|
|
19221
|
+
var stripPrefixes = (input) => {
|
|
19222
|
+
let words = input;
|
|
19223
|
+
for (;; ) {
|
|
19224
|
+
const first = words[0];
|
|
19225
|
+
if (first === undefined)
|
|
19226
|
+
return words;
|
|
19227
|
+
if (/^\w+=/.test(first))
|
|
19228
|
+
words = words.slice(1);
|
|
19229
|
+
else if (PREFIXES3.has(first)) {
|
|
19230
|
+
words = words.slice(1);
|
|
19231
|
+
while (words[0]?.startsWith("-"))
|
|
19232
|
+
words = words.slice(words[0] === "-u" ? 2 : 1);
|
|
19233
|
+
} else if (first === "timeout") {
|
|
19234
|
+
words = words.slice(1);
|
|
19235
|
+
while (words[0]?.startsWith("-"))
|
|
19236
|
+
words = words.slice(1);
|
|
19237
|
+
words = words.slice(1);
|
|
19238
|
+
} else
|
|
19239
|
+
return words;
|
|
19240
|
+
}
|
|
19241
|
+
};
|
|
19242
|
+
var commandName = (word) => (word?.split(/[\\/]/).at(-1) ?? "").toLowerCase().replace(/\.exe$/, "");
|
|
19243
|
+
function rawInvocations(command, dialect = "posix", depth = 0) {
|
|
19244
|
+
const found = [];
|
|
19245
|
+
let dir = null;
|
|
19246
|
+
const groups = [];
|
|
19247
|
+
let stack = [];
|
|
19248
|
+
for (const segment of segmentsOf(command, dialect)) {
|
|
19249
|
+
if (segment.group === "open") {
|
|
19250
|
+
groups.push({ dir, stack: [...stack] });
|
|
19251
|
+
continue;
|
|
19252
|
+
}
|
|
19253
|
+
if (segment.group === "close") {
|
|
19254
|
+
const saved = groups.pop();
|
|
19255
|
+
if (saved)
|
|
19256
|
+
({ dir, stack } = saved);
|
|
19257
|
+
continue;
|
|
19258
|
+
}
|
|
19259
|
+
const words = stripPrefixes(segment.words);
|
|
19260
|
+
const name = commandName(words[0]);
|
|
19261
|
+
if (CD.has(name)) {
|
|
19262
|
+
const target = cdTarget(words);
|
|
19263
|
+
dir = target === null ? os4.homedir() : joinDir(dir, target);
|
|
19264
|
+
continue;
|
|
19265
|
+
}
|
|
19266
|
+
if (PUSHD.has(name)) {
|
|
19267
|
+
const target = cdTarget(words);
|
|
19268
|
+
stack.push(dir);
|
|
19269
|
+
dir = target === null || target === "-" ? undefined : joinDir(dir, target);
|
|
19270
|
+
continue;
|
|
19271
|
+
}
|
|
19272
|
+
if (POPD.has(name)) {
|
|
19273
|
+
dir = stack.length ? stack.pop() : undefined;
|
|
19274
|
+
continue;
|
|
19275
|
+
}
|
|
19276
|
+
if (SHELLS.has(name) && depth < 3) {
|
|
19277
|
+
const flag = words.findIndex((word, index) => index > 0 && SCRIPT_FLAG.test(word));
|
|
19278
|
+
const script = flag > 0 ? words[flag + 1] : undefined;
|
|
19279
|
+
if (script)
|
|
19280
|
+
for (const inner of rawInvocations(script, "posix", depth + 1))
|
|
19281
|
+
found.push({
|
|
19282
|
+
...inner,
|
|
19283
|
+
dir: inner.dir === null ? dir : inner.dir === undefined ? undefined : joinDir(dir, inner.dir)
|
|
19284
|
+
});
|
|
19285
|
+
continue;
|
|
19286
|
+
}
|
|
19287
|
+
if (name === "gh" || name === "glab") {
|
|
19288
|
+
found.push({ tool: name, dir, args: words.slice(1) });
|
|
19289
|
+
continue;
|
|
19290
|
+
}
|
|
19291
|
+
if (name !== "git")
|
|
19292
|
+
continue;
|
|
19293
|
+
let here = dir;
|
|
19294
|
+
let index = 1;
|
|
19295
|
+
for (;index < words.length; index++) {
|
|
19296
|
+
const word = words[index];
|
|
19297
|
+
if (word === "-C")
|
|
19298
|
+
here = words[index + 1] ? joinDir(here, words[++index]) : here;
|
|
19299
|
+
else if (GIT_VALUE_OPTIONS.has(word))
|
|
19300
|
+
index++;
|
|
19301
|
+
else if (!word.startsWith("-"))
|
|
19302
|
+
break;
|
|
19303
|
+
}
|
|
19304
|
+
found.push({ tool: "git", dir: here, args: words.slice(index) });
|
|
19305
|
+
}
|
|
19306
|
+
return found;
|
|
19307
|
+
}
|
|
19308
|
+
var PUSH_VALUE_OPTIONS = new Set(["-o", "--push-option", "--receive-pack", "--exec", "--repo"]);
|
|
19309
|
+
var pushAction = (args) => {
|
|
19310
|
+
let force = false;
|
|
19311
|
+
let lease = false;
|
|
19312
|
+
let wholesale = false;
|
|
19313
|
+
let remote = null;
|
|
19314
|
+
const positionals = [];
|
|
19315
|
+
for (let index = 1;index < args.length; index++) {
|
|
19316
|
+
const arg = args[index];
|
|
19317
|
+
if (arg === "--") {
|
|
19318
|
+
positionals.push(...args.slice(index + 1));
|
|
19319
|
+
break;
|
|
19320
|
+
}
|
|
19321
|
+
if (arg === "--dry-run" || /^-[a-zA-Z]*n[a-zA-Z]*$/.test(arg))
|
|
19322
|
+
return null;
|
|
19323
|
+
if (arg === "--repo")
|
|
19324
|
+
remote = args[++index] ?? null;
|
|
19325
|
+
else if (arg.startsWith("--repo="))
|
|
19326
|
+
remote = arg.slice("--repo=".length);
|
|
19327
|
+
else if (PUSH_VALUE_OPTIONS.has(arg))
|
|
19328
|
+
index++;
|
|
19329
|
+
else if (arg === "--force" || /^-[a-zA-Z]*f[a-zA-Z]*$/.test(arg))
|
|
19330
|
+
force = true;
|
|
19331
|
+
else if (arg.startsWith("--force-with-lease") || arg === "--force-if-includes")
|
|
19332
|
+
lease = true;
|
|
19333
|
+
else if (["--all", "--mirror", "--branches", "--tags"].includes(arg))
|
|
19334
|
+
wholesale = true;
|
|
19335
|
+
else if (!arg.startsWith("-"))
|
|
19336
|
+
positionals.push(arg);
|
|
19337
|
+
}
|
|
19338
|
+
const specs = remote === null ? positionals.slice(1) : positionals;
|
|
19339
|
+
remote ??= positionals[0] ?? null;
|
|
19340
|
+
const targets = [];
|
|
19341
|
+
for (const raw of specs) {
|
|
19342
|
+
if (raw.startsWith("+"))
|
|
19343
|
+
force = true;
|
|
19344
|
+
const spec = raw.replace(/^\+/, "");
|
|
19345
|
+
const colon = spec.indexOf(":");
|
|
19346
|
+
const destination = colon >= 0 ? spec.slice(colon + 1) : spec;
|
|
19347
|
+
if (!destination)
|
|
19348
|
+
continue;
|
|
19349
|
+
if (destination === "HEAD")
|
|
19350
|
+
targets.push(null);
|
|
19351
|
+
else if (destination.startsWith("refs/heads/"))
|
|
19352
|
+
targets.push(destination.slice(11));
|
|
19353
|
+
else if (!destination.startsWith("refs/"))
|
|
19354
|
+
targets.push(destination);
|
|
19355
|
+
}
|
|
19356
|
+
if (specs.length === 0 && !wholesale)
|
|
19357
|
+
targets.push(null);
|
|
19358
|
+
return { kind: "push", targets, blindForce: force && !lease, remote };
|
|
19359
|
+
};
|
|
19360
|
+
var VALUE_OPTIONS = {
|
|
19361
|
+
git: new Set([
|
|
19362
|
+
"-m",
|
|
19363
|
+
"--message",
|
|
19364
|
+
"-F",
|
|
19365
|
+
"--file",
|
|
19366
|
+
"-C",
|
|
19367
|
+
"-c",
|
|
19368
|
+
"--reuse-message",
|
|
19369
|
+
"--reedit-message",
|
|
19370
|
+
"--author",
|
|
19371
|
+
"--date",
|
|
19372
|
+
"--trailer",
|
|
19373
|
+
"-t",
|
|
19374
|
+
"--template",
|
|
19375
|
+
"--cleanup",
|
|
19376
|
+
"--fixup",
|
|
19377
|
+
"--squash",
|
|
19378
|
+
"-o",
|
|
19379
|
+
"--push-option",
|
|
19380
|
+
"--repo",
|
|
19381
|
+
"--receive-pack",
|
|
19382
|
+
"--exec"
|
|
19383
|
+
]),
|
|
19384
|
+
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"])),
|
|
19385
|
+
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"]))
|
|
19386
|
+
};
|
|
19387
|
+
var asksHelp = (invocation) => {
|
|
19388
|
+
const { tool, args } = invocation;
|
|
19389
|
+
if (args[0] === "help" || tool !== "git" && args[1] === "help")
|
|
19390
|
+
return true;
|
|
19391
|
+
const values = VALUE_OPTIONS[tool];
|
|
19392
|
+
for (let index = 0;index < args.length; index++) {
|
|
19393
|
+
const arg = args[index];
|
|
19394
|
+
if (arg === "--")
|
|
19395
|
+
return false;
|
|
19396
|
+
if (arg === "--help" || arg === "-h")
|
|
19397
|
+
return true;
|
|
19398
|
+
if (values.has(arg))
|
|
19399
|
+
index++;
|
|
19400
|
+
}
|
|
19401
|
+
return false;
|
|
19402
|
+
};
|
|
19403
|
+
function rawAction(invocation) {
|
|
19404
|
+
const args = invocation.args;
|
|
19405
|
+
if (asksHelp(invocation))
|
|
19406
|
+
return null;
|
|
19407
|
+
const [first, second] = args;
|
|
19408
|
+
if (invocation.tool === "git") {
|
|
19409
|
+
if (first === "commit")
|
|
19410
|
+
return args.includes("--dry-run") ? null : { kind: "commit", amend: args.includes("--amend") };
|
|
19411
|
+
if (first === "push")
|
|
19412
|
+
return pushAction(args);
|
|
19413
|
+
return null;
|
|
19414
|
+
}
|
|
19415
|
+
const forge = invocation.tool;
|
|
19416
|
+
const noun = forge === "gh" ? "pr" : "mr";
|
|
19417
|
+
if (first !== noun)
|
|
19418
|
+
return null;
|
|
19419
|
+
if (second === "merge")
|
|
19420
|
+
return { kind: "merge", forge };
|
|
19421
|
+
if (second === "create")
|
|
19422
|
+
return { kind: "pr-create", forge };
|
|
19423
|
+
if (["view", "checks", "status", "ci", "list"].includes(second ?? ""))
|
|
19424
|
+
return { kind: "pr-read", forge };
|
|
19425
|
+
return null;
|
|
19426
|
+
}
|
|
19427
|
+
var repoAt = (dir) => {
|
|
19428
|
+
const location = resolveStore(dir);
|
|
19429
|
+
if (location instanceof Error || !location.shared)
|
|
19430
|
+
return null;
|
|
19431
|
+
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
19432
|
+
};
|
|
19433
|
+
var isWorkitWorkspace = (repo) => {
|
|
19434
|
+
if (fs15.existsSync(repo.location.dir))
|
|
19435
|
+
return true;
|
|
19436
|
+
try {
|
|
19437
|
+
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
19438
|
+
} catch {
|
|
19439
|
+
return false;
|
|
19440
|
+
}
|
|
19441
|
+
};
|
|
19442
|
+
var guardedBranch = (dir, branch) => {
|
|
19443
|
+
try {
|
|
19444
|
+
const policy = resolveBranchPolicyFor(dir);
|
|
19445
|
+
return policy.protected.has(branch.toLowerCase()) || policy.defaultTargetBranch.toLowerCase() === branch.toLowerCase();
|
|
19446
|
+
} catch {
|
|
19447
|
+
return false;
|
|
19448
|
+
}
|
|
19449
|
+
};
|
|
19450
|
+
var toPushRemote = (repo, remote) => {
|
|
19451
|
+
if (remote === null)
|
|
19452
|
+
return true;
|
|
19453
|
+
try {
|
|
19454
|
+
const pushRemote = pushRemoteName(repo.dir, repo.branch);
|
|
19455
|
+
return pushRemote === null || pushRemote === remote;
|
|
19456
|
+
} catch {
|
|
19457
|
+
return false;
|
|
19458
|
+
}
|
|
19459
|
+
};
|
|
19460
|
+
var headSha2 = (repo) => {
|
|
19461
|
+
const git = repo.location.git;
|
|
19462
|
+
if (!git || git.reftable)
|
|
19463
|
+
return null;
|
|
19464
|
+
try {
|
|
19465
|
+
const head = fs15.readFileSync(path22.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
19466
|
+
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
19467
|
+
return head;
|
|
19468
|
+
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
19469
|
+
if (!ref)
|
|
19470
|
+
return null;
|
|
19471
|
+
const common = path22.dirname(repo.location.dir);
|
|
19472
|
+
try {
|
|
19473
|
+
return fs15.readFileSync(path22.join(common, ref), "utf8").trim() || null;
|
|
19474
|
+
} catch {}
|
|
19475
|
+
const packed = fs15.readFileSync(path22.join(common, "packed-refs"), "utf8");
|
|
19476
|
+
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
19477
|
+
} catch {
|
|
19478
|
+
return null;
|
|
19479
|
+
}
|
|
19480
|
+
};
|
|
19481
|
+
var quote = (text) => `\`${text}\``;
|
|
19482
|
+
var refusal = (action, branch) => {
|
|
19483
|
+
if (action.kind === "merge")
|
|
19484
|
+
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")}).`;
|
|
19485
|
+
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")}.`;
|
|
19486
|
+
};
|
|
19487
|
+
var nudgeFor = (action, host, session) => {
|
|
19488
|
+
switch (action.kind) {
|
|
19489
|
+
case "commit": {
|
|
19490
|
+
const prefix = host === "cursor" && session ? `WORKIT_SESSION_ID=${session} ` : "";
|
|
19491
|
+
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.`;
|
|
19492
|
+
}
|
|
19493
|
+
case "push":
|
|
19494
|
+
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.`;
|
|
19495
|
+
case "pr-create":
|
|
19496
|
+
return `workit: prefer ${quote("workit pr create --fill")} (or --title/--body): it records the PR the merge gate checks.`;
|
|
19497
|
+
case "pr-read":
|
|
19498
|
+
return `workit: ${quote("workit pr status")} shows the PR, its checks and the verdict state; ${quote("workit ci wait")} waits for checks.`;
|
|
19499
|
+
case "merge":
|
|
19500
|
+
return null;
|
|
19501
|
+
}
|
|
19502
|
+
};
|
|
19503
|
+
var actionsIn = (cwd, command, dialect) => {
|
|
19504
|
+
const out = [];
|
|
19505
|
+
const repos = new Map;
|
|
19506
|
+
for (const invocation of rawInvocations(command, dialect)) {
|
|
19507
|
+
if (invocation.dir === undefined)
|
|
19508
|
+
continue;
|
|
19509
|
+
const action = rawAction(invocation);
|
|
19510
|
+
if (!action)
|
|
19511
|
+
continue;
|
|
19512
|
+
const dir = path22.resolve(cwd, invocation.dir ?? ".");
|
|
19513
|
+
if (!repos.has(dir)) {
|
|
19514
|
+
const repo = repoAt(dir);
|
|
19515
|
+
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
19516
|
+
}
|
|
19517
|
+
const repo = repos.get(dir);
|
|
19518
|
+
if (repo)
|
|
19519
|
+
out.push({ action, repo });
|
|
19520
|
+
}
|
|
19521
|
+
return out;
|
|
19522
|
+
};
|
|
19523
|
+
var mentionsRawTool = (command) => /\b(?:git|gh|glab)\b/i.test(command);
|
|
19524
|
+
var dialectOf = (input) => (input.event.kind === "shell.pre" || input.event.kind === "shell.post" ? input.event.dialect : undefined) ?? "posix";
|
|
19525
|
+
function rawGitPre(input, command) {
|
|
19526
|
+
try {
|
|
19527
|
+
if (!mentionsRawTool(command))
|
|
19528
|
+
return NONE3;
|
|
19529
|
+
const nudges = [];
|
|
19530
|
+
for (const { action, repo } of actionsIn(input.cwd, command, dialectOf(input))) {
|
|
19531
|
+
if (action.kind === "merge")
|
|
19532
|
+
return deny(refusal(action, null));
|
|
19533
|
+
if (action.kind === "push")
|
|
19534
|
+
for (const target of action.targets) {
|
|
19535
|
+
const branch = target ?? repo.branch;
|
|
19536
|
+
if (branch && guardedBranch(repo.dir, branch) && toPushRemote(repo, action.remote))
|
|
19537
|
+
return deny(refusal(action, branch));
|
|
19538
|
+
}
|
|
19539
|
+
const nudge = nudgeFor(action, input.host, input.session.id);
|
|
19540
|
+
if (nudge && !nudges.includes(nudge))
|
|
19541
|
+
nudges.push(nudge);
|
|
19542
|
+
}
|
|
19543
|
+
return nudges.length ? { kind: "context", text: nudges.join(`
|
|
19544
|
+
`) } : NONE3;
|
|
19545
|
+
} catch {
|
|
19546
|
+
return NONE3;
|
|
19547
|
+
}
|
|
19548
|
+
}
|
|
19549
|
+
var deny = (reason) => ({ kind: "deny", reason, unblock: null });
|
|
19550
|
+
var MARKER_TTL_SECONDS = 3600;
|
|
19551
|
+
var markerFile = (repo, session, key) => path22.join(repo.location.dir, "hooks", `commit-${createHash11("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
19552
|
+
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash11("sha256").update(command).digest("hex")}`;
|
|
19553
|
+
function noteRawCommit(input, command, key) {
|
|
19554
|
+
try {
|
|
19555
|
+
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
19556
|
+
return;
|
|
19557
|
+
const at = Math.floor(Date.now() / 1000);
|
|
19558
|
+
for (const { action, repo } of actionsIn(input.cwd, command, dialectOf(input))) {
|
|
19559
|
+
if (action.kind !== "commit")
|
|
19560
|
+
continue;
|
|
19561
|
+
const file = markerFile(repo, input.session.id, key);
|
|
19562
|
+
fs15.mkdirSync(path22.dirname(file), { recursive: true });
|
|
19563
|
+
fs15.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
19564
|
+
`);
|
|
19565
|
+
}
|
|
19566
|
+
} catch {}
|
|
19567
|
+
}
|
|
19568
|
+
var headCommit = (dir) => {
|
|
19569
|
+
const run = spawnSync15("git", [
|
|
19570
|
+
"log",
|
|
19571
|
+
"-1",
|
|
19572
|
+
"--format=%H%x1f%ct%x1f%s%x1f%(trailers:key=Workit-Session,valueonly,separator=%x2c)"
|
|
19573
|
+
], {
|
|
19574
|
+
cwd: dir,
|
|
19575
|
+
encoding: "utf8",
|
|
19576
|
+
timeout: 5000,
|
|
19577
|
+
windowsHide: true,
|
|
19578
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_OPTIONAL_LOCKS: "0", LC_ALL: "C" }
|
|
19579
|
+
});
|
|
19580
|
+
const [sha, committed, subject = "", trailer = ""] = (run.status === 0 ? run.stdout.trim() : "").split("\x1F");
|
|
19581
|
+
return sha && /^[0-9a-f]{40,64}$/.test(sha) ? { sha, committed: Number(committed), subject, trailer: trailer.trim() || null } : null;
|
|
19582
|
+
};
|
|
19583
|
+
var settle2 = (input, repo, file) => {
|
|
19584
|
+
let marker;
|
|
19585
|
+
try {
|
|
19586
|
+
marker = JSON.parse(fs15.readFileSync(file, "utf8"));
|
|
19587
|
+
} catch {
|
|
19588
|
+
return;
|
|
19589
|
+
}
|
|
19590
|
+
fs15.rmSync(file, { force: true });
|
|
19591
|
+
const session = input.session.id;
|
|
19592
|
+
const now = Date.now() / 1000;
|
|
19593
|
+
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
19594
|
+
return;
|
|
19595
|
+
if (!session || !repo.branch)
|
|
19596
|
+
return;
|
|
19597
|
+
const head = headCommit(repo.dir);
|
|
19598
|
+
if (!head || head.sha === marker.head || head.committed < marker.at)
|
|
19599
|
+
return;
|
|
19600
|
+
if (head.trailer && head.trailer !== session)
|
|
19601
|
+
return;
|
|
19602
|
+
const ledger = readLedger(repo.dir);
|
|
19603
|
+
if (!ledger.ok)
|
|
19604
|
+
return;
|
|
19605
|
+
const claimed = ledger.value.rows.some((row) => row.type === "commit.recorded" && (row.sha === head.sha || row.head === head.sha));
|
|
19606
|
+
if (claimed)
|
|
19607
|
+
return;
|
|
19608
|
+
appendHookObserved(repo.dir, {
|
|
19609
|
+
type: "commit.recorded",
|
|
19610
|
+
actor: { host: input.host, session, agentId: input.session.agentId },
|
|
19611
|
+
branch: repo.branch,
|
|
19612
|
+
head: head.sha,
|
|
19613
|
+
sha: head.sha,
|
|
19614
|
+
session,
|
|
19615
|
+
agentId: input.session.agentId,
|
|
19616
|
+
subject: head.subject.slice(0, 200),
|
|
19617
|
+
files: [],
|
|
19618
|
+
fileCount: null,
|
|
19619
|
+
via: "raw_shell"
|
|
19620
|
+
});
|
|
19621
|
+
};
|
|
19622
|
+
function rawGitPost(input, command, key) {
|
|
19623
|
+
try {
|
|
19624
|
+
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
19625
|
+
return;
|
|
19626
|
+
for (const { action, repo } of actionsIn(input.cwd, command, dialectOf(input)))
|
|
19627
|
+
if (action.kind === "commit")
|
|
19628
|
+
settle2(input, repo, markerFile(repo, input.session.id, key));
|
|
19629
|
+
} catch {}
|
|
19630
|
+
}
|
|
18932
19631
|
// packages/workit-core/src/hooks/hosts/fields.ts
|
|
18933
|
-
var
|
|
19632
|
+
var SHELLS2 = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
|
|
18934
19633
|
var WRITE_TOOLS = new Set([
|
|
18935
19634
|
"write",
|
|
18936
19635
|
"edit",
|
|
@@ -18956,7 +19655,13 @@ var CLAUDE_JUDGES = new Set(["workit:verifier", "workit:reviewer"]);
|
|
|
18956
19655
|
// packages/workit-core/src/hooks/hosts/claude-code.ts
|
|
18957
19656
|
var SOURCES = new Set(["startup", "resume", "clear", "compact", "fork"]);
|
|
18958
19657
|
var SHELL_TOOLS = new Set(["Bash", "PowerShell"]);
|
|
18959
|
-
var CONTEXT_EVENTS = new Set([
|
|
19658
|
+
var CONTEXT_EVENTS = new Set([
|
|
19659
|
+
"SessionStart",
|
|
19660
|
+
"UserPromptSubmit",
|
|
19661
|
+
"SubagentStart",
|
|
19662
|
+
"PreToolUse",
|
|
19663
|
+
"PostToolUse"
|
|
19664
|
+
]);
|
|
18960
19665
|
|
|
18961
19666
|
// packages/workit-core/src/hooks/hosts/codex.ts
|
|
18962
19667
|
var SHELL_TOOLS2 = new Set(["bash", "unified-exec"]);
|
|
@@ -19034,11 +19739,11 @@ var OPENCODE_DESCRIPTOR = {
|
|
|
19034
19739
|
]
|
|
19035
19740
|
};
|
|
19036
19741
|
// packages/workit-opencode/src/shared/init-apply.ts
|
|
19037
|
-
import
|
|
19742
|
+
import path27 from "node:path";
|
|
19038
19743
|
|
|
19039
19744
|
// packages/workit-core/src/core/gitignore.ts
|
|
19040
19745
|
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
19041
|
-
import
|
|
19746
|
+
import path23 from "node:path";
|
|
19042
19747
|
var GITIGNORE_ENTRIES = [
|
|
19043
19748
|
"# workit: SDD working state (never commit)",
|
|
19044
19749
|
"docs/*/sdd/",
|
|
@@ -19058,7 +19763,7 @@ var GITIGNORE_ENTRIES = [
|
|
|
19058
19763
|
var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
19059
19764
|
if (!confirmed)
|
|
19060
19765
|
return { ok: false, error: "confirmed: true required" };
|
|
19061
|
-
const file =
|
|
19766
|
+
const file = path23.join(workspaceRoot, ".gitignore");
|
|
19062
19767
|
const existing = existsSync8(file) ? readFileSync6(file, "utf8") : "";
|
|
19063
19768
|
const existingLines = new Set(existing.split(`
|
|
19064
19769
|
`).map((l) => l.trim()).filter(Boolean));
|
|
@@ -19086,25 +19791,25 @@ var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
|
19086
19791
|
|
|
19087
19792
|
// packages/workit-core/src/core/hygiene.ts
|
|
19088
19793
|
import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
19089
|
-
import
|
|
19794
|
+
import path24 from "node:path";
|
|
19090
19795
|
var repoRoot3 = assetRoot();
|
|
19091
|
-
var templatesDir = () =>
|
|
19796
|
+
var templatesDir = () => path24.join(repoRoot3, "templates", "hygiene");
|
|
19092
19797
|
var packageJson = (root) => {
|
|
19093
|
-
if (!existsSync9(
|
|
19798
|
+
if (!existsSync9(path24.join(root, "package.json")))
|
|
19094
19799
|
return null;
|
|
19095
19800
|
try {
|
|
19096
|
-
return JSON.parse(readFileSync7(
|
|
19801
|
+
return JSON.parse(readFileSync7(path24.join(root, "package.json"), "utf8"));
|
|
19097
19802
|
} catch {
|
|
19098
19803
|
return null;
|
|
19099
19804
|
}
|
|
19100
19805
|
};
|
|
19101
19806
|
var isOpenSource = (root) => {
|
|
19102
|
-
if (existsSync9(
|
|
19807
|
+
if (existsSync9(path24.join(root, "LICENSE")))
|
|
19103
19808
|
return true;
|
|
19104
19809
|
const pkg = packageJson(root);
|
|
19105
19810
|
if (pkg && !pkg.private)
|
|
19106
19811
|
return true;
|
|
19107
|
-
return
|
|
19812
|
+
return path24.basename(root) === "workflow-toolkit";
|
|
19108
19813
|
};
|
|
19109
19814
|
var licenseHolder = (root) => {
|
|
19110
19815
|
const pkg = packageJson(root);
|
|
@@ -19127,13 +19832,13 @@ var planHygieneFiles = (root, opts = {}) => {
|
|
|
19127
19832
|
files.push("LICENSE", "CONTRIBUTING.md");
|
|
19128
19833
|
const planned = [];
|
|
19129
19834
|
for (const file of files) {
|
|
19130
|
-
if (existsSync9(
|
|
19835
|
+
if (existsSync9(path24.join(root, file)))
|
|
19131
19836
|
continue;
|
|
19132
|
-
const tpl =
|
|
19837
|
+
const tpl = path24.join(templatesDir(), file);
|
|
19133
19838
|
if (!existsSync9(tpl))
|
|
19134
19839
|
continue;
|
|
19135
|
-
const content = readFileSync7(tpl, "utf8").replace(/<PROJECT>/g,
|
|
19136
|
-
planned.push({ path:
|
|
19840
|
+
const content = readFileSync7(tpl, "utf8").replace(/<PROJECT>/g, path24.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
|
|
19841
|
+
planned.push({ path: path24.join(root, file), content });
|
|
19137
19842
|
}
|
|
19138
19843
|
return planned;
|
|
19139
19844
|
};
|
|
@@ -19143,19 +19848,19 @@ var ensureHygieneFiles = (root, opts) => {
|
|
|
19143
19848
|
const created = [];
|
|
19144
19849
|
for (const planned of planHygieneFiles(root, opts)) {
|
|
19145
19850
|
writeFileSync5(planned.path, planned.content, "utf8");
|
|
19146
|
-
created.push(
|
|
19851
|
+
created.push(path24.basename(planned.path));
|
|
19147
19852
|
}
|
|
19148
19853
|
return { ok: true, created };
|
|
19149
19854
|
};
|
|
19150
19855
|
|
|
19151
19856
|
// packages/workit-core/src/core/init.ts
|
|
19152
|
-
import
|
|
19153
|
-
import
|
|
19154
|
-
import { spawnSync as
|
|
19857
|
+
import fs16 from "node:fs";
|
|
19858
|
+
import path26 from "node:path";
|
|
19859
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
19155
19860
|
|
|
19156
19861
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
19157
19862
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
19158
|
-
import
|
|
19863
|
+
import path25 from "node:path";
|
|
19159
19864
|
import { isDeepStrictEqual } from "node:util";
|
|
19160
19865
|
var readFileSafe = (p) => {
|
|
19161
19866
|
try {
|
|
@@ -19166,7 +19871,7 @@ var readFileSafe = (p) => {
|
|
|
19166
19871
|
};
|
|
19167
19872
|
function applyWorkspaceBranchPolicy(opts) {
|
|
19168
19873
|
const { workspace_root, env = process.env } = opts;
|
|
19169
|
-
const dir =
|
|
19874
|
+
const dir = path25.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
19170
19875
|
const {
|
|
19171
19876
|
status,
|
|
19172
19877
|
path: wsPath,
|
|
@@ -19178,7 +19883,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
19178
19883
|
if (status === "malformed" || status === "invalid")
|
|
19179
19884
|
return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
|
|
19180
19885
|
const detection = detectBranchPolicy(workspace_root);
|
|
19181
|
-
const name = String(env.WORKFLOW_BP_NAME ??
|
|
19886
|
+
const name = String(env.WORKFLOW_BP_NAME ?? path25.basename(workspace_root));
|
|
19182
19887
|
const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
|
|
19183
19888
|
const policy = {
|
|
19184
19889
|
preset: detection.preset,
|
|
@@ -19227,7 +19932,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
19227
19932
|
ok: false,
|
|
19228
19933
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
19229
19934
|
};
|
|
19230
|
-
mkdirSync4(
|
|
19935
|
+
mkdirSync4(path25.dirname(wsPath), { recursive: true });
|
|
19231
19936
|
const tmp = `${wsPath}.${process.pid}.tmp`;
|
|
19232
19937
|
try {
|
|
19233
19938
|
writeFileSync6(tmp, JSON.stringify({ ...document, workspaces: next }, null, 2) + `
|
|
@@ -19262,7 +19967,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
19262
19967
|
var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE";
|
|
19263
19968
|
var readJson = (p) => {
|
|
19264
19969
|
try {
|
|
19265
|
-
const parsed = JSON.parse(
|
|
19970
|
+
const parsed = JSON.parse(fs16.readFileSync(p, "utf8"));
|
|
19266
19971
|
return isConfigObject(parsed) ? parsed : null;
|
|
19267
19972
|
} catch {
|
|
19268
19973
|
return null;
|
|
@@ -19274,7 +19979,7 @@ var resolveInitProvider = (cwd) => {
|
|
|
19274
19979
|
return env.toLowerCase();
|
|
19275
19980
|
const root = cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
19276
19981
|
try {
|
|
19277
|
-
const out =
|
|
19982
|
+
const out = spawnSync16("git", ["remote", "get-url", "origin"], {
|
|
19278
19983
|
cwd: root,
|
|
19279
19984
|
encoding: "utf8"
|
|
19280
19985
|
});
|
|
@@ -19292,7 +19997,7 @@ var youtrackJsonContent = (dir) => {
|
|
|
19292
19997
|
const meetingIssue = process.env.WORKFLOW_YT_MEETING_ISSUE;
|
|
19293
19998
|
return {
|
|
19294
19999
|
baseUrl: process.env.WORKFLOW_YT_BASE_URL ?? "https://youtrack.example.com",
|
|
19295
|
-
tokenFile: process.env.WORKFLOW_YT_TOKEN_FILE ??
|
|
20000
|
+
tokenFile: process.env.WORKFLOW_YT_TOKEN_FILE ?? path26.join(dir, "youtrack.token"),
|
|
19296
20001
|
...meetingIssue ? {
|
|
19297
20002
|
meetingIssue,
|
|
19298
20003
|
meetingIssues: { general: { issue: meetingIssue, label: "General meetings" } }
|
|
@@ -19322,19 +20027,19 @@ var vcsJsonContent = () => {
|
|
|
19322
20027
|
};
|
|
19323
20028
|
function initApplyData(action, env = process.env) {
|
|
19324
20029
|
const dir = String(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
19325
|
-
|
|
20030
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
19326
20031
|
switch (action) {
|
|
19327
20032
|
case "youtrack_json": {
|
|
19328
|
-
const out =
|
|
19329
|
-
|
|
20033
|
+
const out = path26.join(dir, "youtrack.json");
|
|
20034
|
+
fs16.writeFileSync(out, JSON.stringify(youtrackJsonContent(dir), null, 2) + `
|
|
19330
20035
|
`, "utf8");
|
|
19331
20036
|
return { action, ok: true, path: out };
|
|
19332
20037
|
}
|
|
19333
20038
|
case "youtrack_token_placeholder": {
|
|
19334
|
-
const p =
|
|
20039
|
+
const p = path26.join(dir, "youtrack.token");
|
|
19335
20040
|
const preserved = writeFileExclusive(p, TOKEN_PLACEHOLDER2 + `
|
|
19336
20041
|
`, 384) === "preserved";
|
|
19337
|
-
const abs =
|
|
20042
|
+
const abs = path26.resolve(p);
|
|
19338
20043
|
return {
|
|
19339
20044
|
action,
|
|
19340
20045
|
ok: true,
|
|
@@ -19346,14 +20051,14 @@ function initApplyData(action, env = process.env) {
|
|
|
19346
20051
|
};
|
|
19347
20052
|
}
|
|
19348
20053
|
case "youtrack_scaffold": {
|
|
19349
|
-
const jsonOut =
|
|
19350
|
-
const tokenOut =
|
|
19351
|
-
|
|
20054
|
+
const jsonOut = path26.join(dir, "youtrack.json");
|
|
20055
|
+
const tokenOut = path26.join(dir, "youtrack.token");
|
|
20056
|
+
fs16.writeFileSync(jsonOut, JSON.stringify(youtrackJsonContent(dir), null, 2) + `
|
|
19352
20057
|
`, "utf8");
|
|
19353
20058
|
const preserved = writeFileExclusive(tokenOut, TOKEN_PLACEHOLDER2 + `
|
|
19354
20059
|
`, 384) === "preserved";
|
|
19355
|
-
const configPath =
|
|
19356
|
-
const tokenPath =
|
|
20060
|
+
const configPath = path26.resolve(jsonOut);
|
|
20061
|
+
const tokenPath = path26.resolve(tokenOut);
|
|
19357
20062
|
const prev = process.env.WORKFLOW_YOUTRACK_CONFIG;
|
|
19358
20063
|
process.env.WORKFLOW_YOUTRACK_CONFIG = configPath;
|
|
19359
20064
|
let tokenCreate = {};
|
|
@@ -19405,10 +20110,10 @@ function initApplyData(action, env = process.env) {
|
|
|
19405
20110
|
}
|
|
19406
20111
|
}
|
|
19407
20112
|
case "vcs_scaffold": {
|
|
19408
|
-
const jsonOut =
|
|
19409
|
-
|
|
20113
|
+
const jsonOut = path26.join(dir, "vcs.json");
|
|
20114
|
+
fs16.writeFileSync(jsonOut, JSON.stringify(vcsJsonContent(), null, 2) + `
|
|
19410
20115
|
`, "utf8");
|
|
19411
|
-
const configPath =
|
|
20116
|
+
const configPath = path26.resolve(jsonOut);
|
|
19412
20117
|
const prev = process.env.WORKFLOW_VCS_CONFIG;
|
|
19413
20118
|
process.env.WORKFLOW_VCS_CONFIG = configPath;
|
|
19414
20119
|
try {
|
|
@@ -19527,7 +20232,7 @@ var executeInitApply = (args, directory, runtime) => {
|
|
|
19527
20232
|
protectedNames: args.branch_policy_protected
|
|
19528
20233
|
}, current);
|
|
19529
20234
|
writeConfig(next);
|
|
19530
|
-
return output(ok({ action: "config", path:
|
|
20235
|
+
return output(ok({ action: "config", path: path27.join(configDir(), "config.json"), ...next }));
|
|
19531
20236
|
}
|
|
19532
20237
|
const env = Object.fromEntries(Object.entries({
|
|
19533
20238
|
WORKFLOW_YT_BASE_URL: args.base_url,
|
|
@@ -19544,14 +20249,14 @@ var executeInitApply = (args, directory, runtime) => {
|
|
|
19544
20249
|
|
|
19545
20250
|
// packages/workit-opencode/src/shared/session.ts
|
|
19546
20251
|
import { realpathSync as realpathSync7 } from "node:fs";
|
|
19547
|
-
import
|
|
20252
|
+
import path28 from "node:path";
|
|
19548
20253
|
var sameWorkspace = (expected, observed) => {
|
|
19549
20254
|
if (typeof observed !== "string" || !observed)
|
|
19550
20255
|
return false;
|
|
19551
20256
|
try {
|
|
19552
20257
|
return realpathSync7(expected) === realpathSync7(observed);
|
|
19553
20258
|
} catch {
|
|
19554
|
-
return
|
|
20259
|
+
return path28.resolve(expected) === path28.resolve(observed);
|
|
19555
20260
|
}
|
|
19556
20261
|
};
|
|
19557
20262
|
|
|
@@ -19623,7 +20328,7 @@ var workitFamilyOf = (toolName) => {
|
|
|
19623
20328
|
|
|
19624
20329
|
// packages/workit-opencode/src/tools/context.ts
|
|
19625
20330
|
import { realpathSync as realpathSync8 } from "node:fs";
|
|
19626
|
-
import
|
|
20331
|
+
import path29 from "node:path";
|
|
19627
20332
|
var createContextTool = () => ({
|
|
19628
20333
|
description: "Read Git, pull request, YouTrack, issue, changelog, release, or affected-file context.",
|
|
19629
20334
|
execute: async (args, context) => {
|
|
@@ -19633,7 +20338,7 @@ var createContextTool = () => ({
|
|
|
19633
20338
|
let root;
|
|
19634
20339
|
try {
|
|
19635
20340
|
const cwd = parsed.data.cwd;
|
|
19636
|
-
root = realpathSync8(cwd ?
|
|
20341
|
+
root = realpathSync8(cwd ? path29.resolve(context.directory, cwd) : context.directory);
|
|
19637
20342
|
} catch {
|
|
19638
20343
|
return JSON.stringify(failure2("invalid_input", "context target directory cannot be resolved"), null, 2);
|
|
19639
20344
|
}
|
|
@@ -20156,7 +20861,7 @@ var injectCompactionContext = (root, sessionID, system) => {
|
|
|
20156
20861
|
|
|
20157
20862
|
// packages/workit-opencode/src/v2/permissions.ts
|
|
20158
20863
|
var WRITE_ACTIONS = new Set(["edit", "write", "patch"]);
|
|
20159
|
-
var evaluateShellPermission = (root, event) => {
|
|
20864
|
+
var evaluateShellPermission = (root, event, workdirs = new Map) => {
|
|
20160
20865
|
if (event.effect === "deny")
|
|
20161
20866
|
return;
|
|
20162
20867
|
const deny = (reason) => {
|
|
@@ -20176,6 +20881,17 @@ var evaluateShellPermission = (root, event) => {
|
|
|
20176
20881
|
const decision = shellPolicy(root, resource);
|
|
20177
20882
|
if (decision.kind === "deny")
|
|
20178
20883
|
return deny(decision.reason);
|
|
20884
|
+
const cwd = event.sessionID && workdirs.get(event.sessionID) || root;
|
|
20885
|
+
const raw = rawGitPre({
|
|
20886
|
+
host: "opencode",
|
|
20887
|
+
cwd,
|
|
20888
|
+
session: { id: event.sessionID ?? "", agentId: null, agentType: null, parentId: null },
|
|
20889
|
+
permissionMode: null,
|
|
20890
|
+
transcriptPath: null,
|
|
20891
|
+
event: { kind: "shell.pre", command: resource, toolUseId: null }
|
|
20892
|
+
}, resource);
|
|
20893
|
+
if (raw.kind === "deny")
|
|
20894
|
+
return deny(raw.reason);
|
|
20179
20895
|
const writes = shellWrites(resource);
|
|
20180
20896
|
const gated = writes.writes ? writeGate(root, writes.targets) : null;
|
|
20181
20897
|
if (gated?.kind === "deny")
|
|
@@ -20183,9 +20899,65 @@ var evaluateShellPermission = (root, event) => {
|
|
|
20183
20899
|
}
|
|
20184
20900
|
};
|
|
20185
20901
|
|
|
20902
|
+
// packages/workit-opencode/src/v2/shell.ts
|
|
20903
|
+
import path30 from "node:path";
|
|
20904
|
+
var commandOf = (input) => {
|
|
20905
|
+
if (input === null || typeof input !== "object")
|
|
20906
|
+
return null;
|
|
20907
|
+
const { command, workdir } = input;
|
|
20908
|
+
return typeof command === "string" && command.trim() ? { command, workdir: typeof workdir === "string" && workdir.trim() ? workdir : null } : null;
|
|
20909
|
+
};
|
|
20910
|
+
var hookInput = (root, sessionID, id, shell) => ({
|
|
20911
|
+
host: "opencode",
|
|
20912
|
+
cwd: shell.workdir ? path30.resolve(root, shell.workdir) : root,
|
|
20913
|
+
session: { id: sessionID, agentId: null, agentType: null, parentId: null },
|
|
20914
|
+
permissionMode: null,
|
|
20915
|
+
transcriptPath: null,
|
|
20916
|
+
event: { kind: "shell.pre", command: shell.command, toolUseId: id }
|
|
20917
|
+
});
|
|
20918
|
+
var observeShellBefore = (root, event, workdirs) => {
|
|
20919
|
+
try {
|
|
20920
|
+
if (event.tool !== "shell")
|
|
20921
|
+
return;
|
|
20922
|
+
const shell = commandOf(event.input);
|
|
20923
|
+
if (!shell)
|
|
20924
|
+
return;
|
|
20925
|
+
const sessionID = String(event.sessionID);
|
|
20926
|
+
const input = hookInput(root, sessionID, String(event.id), shell);
|
|
20927
|
+
workdirs.set(sessionID, input.cwd);
|
|
20928
|
+
if (workdirs.size > 256)
|
|
20929
|
+
workdirs.delete(workdirs.keys().next().value);
|
|
20930
|
+
noteRawCommit(input, shell.command, callKey(String(event.id), shell.command));
|
|
20931
|
+
} catch {}
|
|
20932
|
+
};
|
|
20933
|
+
var observeShellResult = (root, event) => {
|
|
20934
|
+
try {
|
|
20935
|
+
if (event.tool !== "shell" || event.status !== "completed")
|
|
20936
|
+
return;
|
|
20937
|
+
const shell = commandOf(event.input);
|
|
20938
|
+
if (!shell)
|
|
20939
|
+
return;
|
|
20940
|
+
const input = hookInput(root, String(event.sessionID), String(event.id), shell);
|
|
20941
|
+
rawGitPost(input, shell.command, callKey(String(event.id), shell.command));
|
|
20942
|
+
const nudge = rawGitPre(input, shell.command);
|
|
20943
|
+
const result = event.result;
|
|
20944
|
+
if (nudge.kind !== "context" || !result)
|
|
20945
|
+
return;
|
|
20946
|
+
if (typeof result.content === "string")
|
|
20947
|
+
event.result = { ...result, content: `${result.content}
|
|
20948
|
+
|
|
20949
|
+
${nudge.text}` };
|
|
20950
|
+
else if (Array.isArray(result.content))
|
|
20951
|
+
event.result = {
|
|
20952
|
+
...result,
|
|
20953
|
+
content: [...result.content, { type: "text", text: nudge.text }]
|
|
20954
|
+
};
|
|
20955
|
+
} catch {}
|
|
20956
|
+
};
|
|
20957
|
+
|
|
20186
20958
|
// packages/workit-opencode/src/v2/registry.ts
|
|
20187
20959
|
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "node:fs";
|
|
20188
|
-
import
|
|
20960
|
+
import path32 from "node:path";
|
|
20189
20961
|
|
|
20190
20962
|
// packages/workit-core/src/core/skill-manifests.ts
|
|
20191
20963
|
var WORKIT_METHOD_SKILLS = [
|
|
@@ -20234,33 +21006,33 @@ if (false) {}
|
|
|
20234
21006
|
|
|
20235
21007
|
// packages/workit-opencode/src/shared/assets.ts
|
|
20236
21008
|
import { existsSync as existsSync10, realpathSync as realpathSync9 } from "node:fs";
|
|
20237
|
-
import
|
|
21009
|
+
import path31 from "node:path";
|
|
20238
21010
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20239
21011
|
var moduleDir = () => {
|
|
20240
21012
|
try {
|
|
20241
|
-
return realpathSync9(
|
|
21013
|
+
return realpathSync9(path31.dirname(fileURLToPath2(import.meta.url)));
|
|
20242
21014
|
} catch {
|
|
20243
|
-
return
|
|
21015
|
+
return path31.dirname(fileURLToPath2(import.meta.url));
|
|
20244
21016
|
}
|
|
20245
21017
|
};
|
|
20246
21018
|
var packageRoot2 = () => {
|
|
20247
21019
|
const dir = moduleDir();
|
|
20248
21020
|
for (const candidate of [
|
|
20249
|
-
|
|
20250
|
-
|
|
20251
|
-
|
|
21021
|
+
path31.resolve(dir, ".."),
|
|
21022
|
+
path31.resolve(dir, "..", ".."),
|
|
21023
|
+
path31.resolve(dir, "..", "..", "..")
|
|
20252
21024
|
]) {
|
|
20253
|
-
if (existsSync10(
|
|
21025
|
+
if (existsSync10(path31.join(candidate, "package.json")))
|
|
20254
21026
|
return candidate;
|
|
20255
21027
|
}
|
|
20256
|
-
return
|
|
21028
|
+
return path31.resolve(dir, "..");
|
|
20257
21029
|
};
|
|
20258
21030
|
var skillsRoot = () => {
|
|
20259
21031
|
const root = packageRoot2();
|
|
20260
|
-
const canonical =
|
|
20261
|
-
if (existsSync10(
|
|
21032
|
+
const canonical = path31.resolve(root, "..", "workit-core", "skills");
|
|
21033
|
+
if (existsSync10(path31.join(root, "src")) && existsSync10(canonical))
|
|
20262
21034
|
return canonical;
|
|
20263
|
-
return
|
|
21035
|
+
return path31.join(root, "assets", "skills");
|
|
20264
21036
|
};
|
|
20265
21037
|
|
|
20266
21038
|
// packages/workit-opencode/src/v2/registry.ts
|
|
@@ -20287,11 +21059,11 @@ var registerSkills = async (ctx) => {
|
|
|
20287
21059
|
if (!existsSync11(skillsDir))
|
|
20288
21060
|
return new Set;
|
|
20289
21061
|
const listed = await ctx.skill.list().catch(() => ({ data: [] }));
|
|
20290
|
-
const own = (skill) => typeof skill.path === "string" &&
|
|
21062
|
+
const own = (skill) => typeof skill.path === "string" && path32.resolve(skill.path).startsWith(skillsDir + path32.sep);
|
|
20291
21063
|
const userSkills = new Set((listed?.data ?? []).filter((skill) => !own(skill)).map((skill) => skill.id));
|
|
20292
21064
|
const packaged = new Map;
|
|
20293
21065
|
for (const id of WORKIT_METHOD_SKILLS) {
|
|
20294
|
-
const file =
|
|
21066
|
+
const file = path32.join(skillsDir, id, "SKILL.md");
|
|
20295
21067
|
if (!userSkills.has(id) && existsSync11(file))
|
|
20296
21068
|
packaged.set(id, file);
|
|
20297
21069
|
}
|
|
@@ -20339,22 +21111,22 @@ var registerCommands = async (ctx, registeredSkills) => {
|
|
|
20339
21111
|
|
|
20340
21112
|
// packages/workit-opencode/src/stale-sources.ts
|
|
20341
21113
|
import { existsSync as existsSync12, readdirSync as readdirSync5 } from "node:fs";
|
|
20342
|
-
import
|
|
21114
|
+
import path33 from "node:path";
|
|
20343
21115
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
20344
21116
|
var typescriptFiles = (directory) => {
|
|
20345
21117
|
if (!existsSync12(directory))
|
|
20346
21118
|
return [];
|
|
20347
21119
|
return readdirSync5(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
20348
|
-
const file =
|
|
21120
|
+
const file = path33.join(directory, entry.name);
|
|
20349
21121
|
return entry.isDirectory() ? typescriptFiles(file) : entry.isFile() && file.endsWith(".ts") ? [file] : [];
|
|
20350
21122
|
});
|
|
20351
21123
|
};
|
|
20352
21124
|
var pluginSourceFiles = [
|
|
20353
21125
|
...new Set([
|
|
20354
21126
|
fileURLToPath3(import.meta.url),
|
|
20355
|
-
...typescriptFiles(
|
|
20356
|
-
|
|
20357
|
-
...typescriptFiles(
|
|
21127
|
+
...typescriptFiles(path33.join(packageRoot2(), "src")),
|
|
21128
|
+
path33.join(packageRoot2(), "..", "workit-core", "src", "core.ts"),
|
|
21129
|
+
...typescriptFiles(path33.join(packageRoot2(), "..", "workit-core", "src", "core"))
|
|
20358
21130
|
])
|
|
20359
21131
|
].filter((file) => existsSync12(file)).toSorted();
|
|
20360
21132
|
|
|
@@ -20455,7 +21227,10 @@ var setup = async (ctx) => {
|
|
|
20455
21227
|
});
|
|
20456
21228
|
}
|
|
20457
21229
|
});
|
|
21230
|
+
const shellWorkdirs = new Map;
|
|
20458
21231
|
await ctx.tool.hook("execute.before", async (event) => {
|
|
21232
|
+
if (event.tool === "shell")
|
|
21233
|
+
return observeShellBefore(root, event, shellWorkdirs);
|
|
20459
21234
|
if (event.tool !== "subagent")
|
|
20460
21235
|
return;
|
|
20461
21236
|
await lifecycle.executeBefore({
|
|
@@ -20466,6 +21241,8 @@ var setup = async (ctx) => {
|
|
|
20466
21241
|
});
|
|
20467
21242
|
});
|
|
20468
21243
|
await ctx.tool.hook("execute.after", async (event) => {
|
|
21244
|
+
if (event.tool === "shell")
|
|
21245
|
+
return observeShellResult(root, event);
|
|
20469
21246
|
if (event.tool !== "subagent")
|
|
20470
21247
|
return;
|
|
20471
21248
|
await lifecycle.executeAfter({
|
|
@@ -20477,7 +21254,7 @@ var setup = async (ctx) => {
|
|
|
20477
21254
|
});
|
|
20478
21255
|
});
|
|
20479
21256
|
await ctx.permission.hook("evaluate", (event) => {
|
|
20480
|
-
evaluateShellPermission(root, event);
|
|
21257
|
+
evaluateShellPermission(root, event, shellWorkdirs);
|
|
20481
21258
|
});
|
|
20482
21259
|
await ctx.session.hook("context", async (event) => {
|
|
20483
21260
|
const session = await sessionFacts(ctx, String(event.sessionID));
|