@brainervirus/workit-codex 8.13.0 → 8.14.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/.codex-plugin/plugin.json +1 -1
- package/agents/workit-reviewer.toml +2 -2
- package/agents/workit-verifier.toml +2 -2
- package/dist/launch-mcp.js +688 -401
- package/dist/{workit-hook-sc45d7h1.js → workit-hook-s8c0mzcq.js} +687 -65
- package/dist/workit-hook.js +1 -1
- package/package.json +4 -4
- package/skills/workit-fanout/SKILL.md +4 -4
- package/skills/workit-fanout/references/orchestration.md +8 -5
- package/skills/workit-review/SKILL.md +1 -1
package/dist/launch-mcp.js
CHANGED
|
@@ -6622,13 +6622,13 @@ var require_dist = __commonJS(function(exports, module) {
|
|
|
6622
6622
|
|
|
6623
6623
|
// packages/workit-codex/scripts/launch-mcp.ts
|
|
6624
6624
|
import { existsSync as existsSync10, realpathSync as realpathSync7, statSync as statSync3 } from "node:fs";
|
|
6625
|
-
import
|
|
6625
|
+
import path24 from "node:path";
|
|
6626
6626
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6627
6627
|
|
|
6628
6628
|
// packages/workit-core/src/core.ts
|
|
6629
6629
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
6630
6630
|
import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
|
|
6631
|
-
import
|
|
6631
|
+
import path21 from "node:path";
|
|
6632
6632
|
|
|
6633
6633
|
// packages/workit-core/src/core/task-contract.ts
|
|
6634
6634
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -15456,9 +15456,9 @@ function parseAdvertisedOperation(family, input, host) {
|
|
|
15456
15456
|
});
|
|
15457
15457
|
}
|
|
15458
15458
|
// packages/workit-core/src/core/task-store.ts
|
|
15459
|
-
import { createHash as
|
|
15460
|
-
import * as
|
|
15461
|
-
import
|
|
15459
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
15460
|
+
import * as fs8 from "node:fs";
|
|
15461
|
+
import path8 from "node:path";
|
|
15462
15462
|
|
|
15463
15463
|
// node_modules/@openclaw/fs-safe/dist/errors.js
|
|
15464
15464
|
var OPERATIONAL_CODES = new Set([
|
|
@@ -16061,8 +16061,14 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
16061
16061
|
}
|
|
16062
16062
|
}
|
|
16063
16063
|
}
|
|
16064
|
+
// packages/workit-core/src/host-session.ts
|
|
16065
|
+
import { createHash as createHash3, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
|
|
16066
|
+
import fs5 from "node:fs";
|
|
16067
|
+
import path5 from "node:path";
|
|
16068
|
+
|
|
16064
16069
|
// packages/workit-core/src/core/logger.ts
|
|
16065
16070
|
import os from "node:os";
|
|
16071
|
+
import path3 from "node:path";
|
|
16066
16072
|
var REDACTED = "[REDACTED]";
|
|
16067
16073
|
var SECRET_VALUE = /\b(?:Bearer|Basic|Digest|Token)\s+\S+/gi;
|
|
16068
16074
|
var KEY_EQ_VALUE = /\b([A-Za-z0-9_-]*(?:token|secret|password|passwd|apikey|api[_-]?key|authorization|credential|bearer)[A-Za-z0-9_-]*)([:=]\s*).+/gi;
|
|
@@ -16105,6 +16111,22 @@ var SENSITIVE_WORDS = new Set([
|
|
|
16105
16111
|
]);
|
|
16106
16112
|
var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
16107
16113
|
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16114
|
+
var resolveStateDir = () => {
|
|
16115
|
+
const override = process.env.WORKFLOW_TOOLKIT_STATE;
|
|
16116
|
+
if (override)
|
|
16117
|
+
return override;
|
|
16118
|
+
const home = os.homedir();
|
|
16119
|
+
if (process.env.XDG_STATE_HOME)
|
|
16120
|
+
return path3.join(process.env.XDG_STATE_HOME, "workit");
|
|
16121
|
+
switch (os.platform()) {
|
|
16122
|
+
case "darwin":
|
|
16123
|
+
return path3.join(home, "Library", "Application Support", "workit");
|
|
16124
|
+
case "win32":
|
|
16125
|
+
return path3.join(process.env.LOCALAPPDATA ?? path3.join(home, "AppData", "Local"), "workit");
|
|
16126
|
+
default:
|
|
16127
|
+
return path3.join(process.env.HOME ?? home, ".local", "state", "workit");
|
|
16128
|
+
}
|
|
16129
|
+
};
|
|
16108
16130
|
var homePattern = new RegExp(`${escapeRegExp(os.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
16109
16131
|
var applyPatterns = (value) => {
|
|
16110
16132
|
let out = value;
|
|
@@ -16122,7 +16144,7 @@ var redactSecrets = (value) => applyPatterns(value);
|
|
|
16122
16144
|
import { spawnSync } from "node:child_process";
|
|
16123
16145
|
import { createHash as createHash2 } from "node:crypto";
|
|
16124
16146
|
import fs4 from "node:fs";
|
|
16125
|
-
import
|
|
16147
|
+
import path4 from "node:path";
|
|
16126
16148
|
var NOT_A_REPO = /not a git repository \(or any (of the parent directories|parent up to)/u;
|
|
16127
16149
|
var gitRun = (cwd, args) => {
|
|
16128
16150
|
const run = spawnSync("git", args, {
|
|
@@ -16164,14 +16186,14 @@ var DISCOVERY_ENV = [
|
|
|
16164
16186
|
];
|
|
16165
16187
|
var isGitDir = (dir) => {
|
|
16166
16188
|
try {
|
|
16167
|
-
return fs4.statSync(
|
|
16189
|
+
return fs4.statSync(path4.join(dir, "HEAD")).isFile() && fs4.statSync(path4.join(dir, "objects")).isDirectory() && fs4.statSync(path4.join(dir, "refs")).isDirectory();
|
|
16168
16190
|
} catch {
|
|
16169
16191
|
return false;
|
|
16170
16192
|
}
|
|
16171
16193
|
};
|
|
16172
16194
|
var reftableRefs = (common) => {
|
|
16173
16195
|
try {
|
|
16174
|
-
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(
|
|
16196
|
+
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path4.join(common, "config"), "utf8"));
|
|
16175
16197
|
} catch {
|
|
16176
16198
|
return false;
|
|
16177
16199
|
}
|
|
@@ -16191,7 +16213,7 @@ function fastGit(root) {
|
|
|
16191
16213
|
if (device !== null && stat.dev !== device)
|
|
16192
16214
|
return { kind: "none" };
|
|
16193
16215
|
device = stat.dev;
|
|
16194
|
-
const dotGit =
|
|
16216
|
+
const dotGit = path4.join(dir, ".git");
|
|
16195
16217
|
let entry = null;
|
|
16196
16218
|
try {
|
|
16197
16219
|
entry = fs4.statSync(dotGit);
|
|
@@ -16212,19 +16234,19 @@ function fastGit(root) {
|
|
|
16212
16234
|
const match = /^gitdir: (.+)$/mu.exec(text);
|
|
16213
16235
|
if (!match)
|
|
16214
16236
|
return null;
|
|
16215
|
-
gitDir =
|
|
16237
|
+
gitDir = path4.resolve(dir, match[1].trim());
|
|
16216
16238
|
} else
|
|
16217
16239
|
return null;
|
|
16218
|
-
if (!fs4.existsSync(
|
|
16240
|
+
if (!fs4.existsSync(path4.join(gitDir, "HEAD")))
|
|
16219
16241
|
return null;
|
|
16220
16242
|
} else if (isGitDir(dir))
|
|
16221
16243
|
gitDir = dir;
|
|
16222
16244
|
if (gitDir) {
|
|
16223
16245
|
let common = gitDir;
|
|
16224
16246
|
try {
|
|
16225
|
-
common =
|
|
16247
|
+
common = path4.resolve(gitDir, fs4.readFileSync(path4.join(gitDir, "commondir"), "utf8").trim());
|
|
16226
16248
|
} catch {}
|
|
16227
|
-
if (!fs4.existsSync(
|
|
16249
|
+
if (!fs4.existsSync(path4.join(common, "objects")))
|
|
16228
16250
|
return null;
|
|
16229
16251
|
return {
|
|
16230
16252
|
kind: "repo",
|
|
@@ -16234,26 +16256,26 @@ function fastGit(root) {
|
|
|
16234
16256
|
reftable: reftableRefs(common)
|
|
16235
16257
|
};
|
|
16236
16258
|
}
|
|
16237
|
-
const parent =
|
|
16259
|
+
const parent = path4.dirname(dir);
|
|
16238
16260
|
if (parent === dir)
|
|
16239
16261
|
return { kind: "none" };
|
|
16240
16262
|
dir = parent;
|
|
16241
16263
|
}
|
|
16242
16264
|
}
|
|
16243
16265
|
function resolveStore(root) {
|
|
16244
|
-
root =
|
|
16266
|
+
root = path4.resolve(root);
|
|
16245
16267
|
let directory = false;
|
|
16246
16268
|
try {
|
|
16247
16269
|
directory = fs4.statSync(root).isDirectory();
|
|
16248
16270
|
} catch {}
|
|
16249
16271
|
if (!directory)
|
|
16250
|
-
return { dir:
|
|
16272
|
+
return { dir: path4.join(root, ".workit"), shared: false, top: null };
|
|
16251
16273
|
const fast = fastGit(root);
|
|
16252
16274
|
if (fast?.kind === "none")
|
|
16253
|
-
return { dir:
|
|
16275
|
+
return { dir: path4.join(root, ".workit"), shared: false, top: null };
|
|
16254
16276
|
if (fast?.kind === "repo")
|
|
16255
16277
|
return {
|
|
16256
|
-
dir:
|
|
16278
|
+
dir: path4.join(fast.common, "workit"),
|
|
16257
16279
|
shared: true,
|
|
16258
16280
|
top: fast.top,
|
|
16259
16281
|
git: { gitDir: fast.gitDir, top: fast.top, reftable: fast.reftable }
|
|
@@ -16263,20 +16285,20 @@ function resolveStore(root) {
|
|
|
16263
16285
|
if (run.ok && common) {
|
|
16264
16286
|
const top = gitRun(root, ["rev-parse", "--path-format=absolute", "--show-toplevel"]);
|
|
16265
16287
|
return {
|
|
16266
|
-
dir:
|
|
16288
|
+
dir: path4.join(real(path4.resolve(root, common)), "workit"),
|
|
16267
16289
|
shared: true,
|
|
16268
16290
|
top: top.ok && top.stdout.trim() ? real(top.stdout.trim()) : null
|
|
16269
16291
|
};
|
|
16270
16292
|
}
|
|
16271
16293
|
if (run.missing || !run.ok && NOT_A_REPO.test(run.stderr))
|
|
16272
|
-
return { dir:
|
|
16294
|
+
return { dir: path4.join(root, ".workit"), shared: false, top: null };
|
|
16273
16295
|
return new Error(`cannot locate the workit store: git rev-parse failed (${run.stderr.trim().split(`
|
|
16274
16296
|
`)[0] || "no output"}); fix the repository (git status should work here)`);
|
|
16275
16297
|
}
|
|
16276
16298
|
var rebasingBranch = (gitDir) => {
|
|
16277
16299
|
for (const state of ["rebase-merge", "rebase-apply"]) {
|
|
16278
16300
|
try {
|
|
16279
|
-
const ref = fs4.readFileSync(
|
|
16301
|
+
const ref = fs4.readFileSync(path4.join(gitDir, state, "head-name"), "utf8").trim();
|
|
16280
16302
|
const match = /^refs\/heads\/(.+)$/u.exec(ref);
|
|
16281
16303
|
if (match)
|
|
16282
16304
|
return match[1];
|
|
@@ -16291,7 +16313,7 @@ function resolveTaskKey(root, location) {
|
|
|
16291
16313
|
if (location.git && !location.git.reftable) {
|
|
16292
16314
|
let head = "";
|
|
16293
16315
|
try {
|
|
16294
|
-
head = fs4.readFileSync(
|
|
16316
|
+
head = fs4.readFileSync(path4.join(location.git.gitDir, "HEAD"), "utf8").trim();
|
|
16295
16317
|
} catch {}
|
|
16296
16318
|
const ref = /^ref: refs\/heads\/(.+)$/u.exec(head);
|
|
16297
16319
|
if (ref && ref[1] !== ".invalid")
|
|
@@ -16322,7 +16344,7 @@ function resolveTaskKey(root, location) {
|
|
|
16322
16344
|
return { key: `detached-${shortHash(real(worktree))}`, kind: "detached", branch: null };
|
|
16323
16345
|
}
|
|
16324
16346
|
function checkoutRootOf(root, location) {
|
|
16325
|
-
const resolved =
|
|
16347
|
+
const resolved = path4.resolve(root);
|
|
16326
16348
|
let canonical = resolved;
|
|
16327
16349
|
try {
|
|
16328
16350
|
canonical = fs4.realpathSync(resolved);
|
|
@@ -16353,13 +16375,13 @@ function branchRenames(location) {
|
|
|
16353
16375
|
}
|
|
16354
16376
|
for (const entry of entries)
|
|
16355
16377
|
if (entry.isDirectory())
|
|
16356
|
-
walk(
|
|
16378
|
+
walk(path4.join(dir, entry.name));
|
|
16357
16379
|
else
|
|
16358
|
-
files.push(
|
|
16380
|
+
files.push(path4.join(dir, entry.name));
|
|
16359
16381
|
};
|
|
16360
|
-
walk(
|
|
16382
|
+
walk(path4.join(path4.dirname(location.dir), "logs", "refs", "heads"));
|
|
16361
16383
|
if (location.git)
|
|
16362
|
-
files.push(
|
|
16384
|
+
files.push(path4.join(location.git.gitDir, "logs", "HEAD"));
|
|
16363
16385
|
const seen = new Set;
|
|
16364
16386
|
const renames = [];
|
|
16365
16387
|
for (const file of files) {
|
|
@@ -16394,7 +16416,7 @@ var checkoutSlug = (root) => {
|
|
|
16394
16416
|
let canonical = real(root);
|
|
16395
16417
|
if (process.platform === "win32")
|
|
16396
16418
|
canonical = canonical.toLowerCase();
|
|
16397
|
-
const base =
|
|
16419
|
+
const base = path4.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
|
|
16398
16420
|
return `${base}-${shortHash(canonical)}`;
|
|
16399
16421
|
};
|
|
16400
16422
|
|
|
@@ -16426,30 +16448,113 @@ function hostSessionFromEnv(env) {
|
|
|
16426
16448
|
}
|
|
16427
16449
|
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
16428
16450
|
}
|
|
16451
|
+
var hash = (value) => createHash3("sha256").update(value).digest("hex").slice(0, 32);
|
|
16452
|
+
var userIssuedRoot = () => path5.join(resolveStateDir(), "issued");
|
|
16453
|
+
var userTokenRoot = () => path5.join(resolveStateDir(), "issued-tokens");
|
|
16454
|
+
function migrateRepoIssued(cwd) {
|
|
16455
|
+
if (cwd === undefined)
|
|
16456
|
+
return;
|
|
16457
|
+
let old;
|
|
16458
|
+
try {
|
|
16459
|
+
const location = resolveStore(cwd);
|
|
16460
|
+
if (location instanceof Error)
|
|
16461
|
+
return;
|
|
16462
|
+
old = path5.join(location.dir, "hooks", "issued");
|
|
16463
|
+
if (!fs5.existsSync(old))
|
|
16464
|
+
return;
|
|
16465
|
+
} catch {
|
|
16466
|
+
return;
|
|
16467
|
+
}
|
|
16468
|
+
for (const lead of safeList(old)) {
|
|
16469
|
+
try {
|
|
16470
|
+
const from = path5.join(old, lead);
|
|
16471
|
+
if (!fs5.statSync(from).isDirectory())
|
|
16472
|
+
continue;
|
|
16473
|
+
const to = path5.join(userIssuedRoot(), lead);
|
|
16474
|
+
fs5.mkdirSync(to, { recursive: true, mode: 448 });
|
|
16475
|
+
for (const id of fs5.readdirSync(from)) {
|
|
16476
|
+
try {
|
|
16477
|
+
fs5.copyFileSync(path5.join(from, id), path5.join(to, id), fs5.constants.COPYFILE_EXCL);
|
|
16478
|
+
} catch (error) {
|
|
16479
|
+
if (error.code !== "EEXIST")
|
|
16480
|
+
throw error;
|
|
16481
|
+
}
|
|
16482
|
+
fs5.rmSync(path5.join(from, id), { force: true });
|
|
16483
|
+
}
|
|
16484
|
+
removeIfEmpty(from);
|
|
16485
|
+
} catch {}
|
|
16486
|
+
}
|
|
16487
|
+
removeIfEmpty(old);
|
|
16488
|
+
}
|
|
16489
|
+
var safeList = (dir) => {
|
|
16490
|
+
try {
|
|
16491
|
+
return fs5.readdirSync(dir);
|
|
16492
|
+
} catch {
|
|
16493
|
+
return [];
|
|
16494
|
+
}
|
|
16495
|
+
};
|
|
16496
|
+
var removeIfEmpty = (dir) => {
|
|
16497
|
+
try {
|
|
16498
|
+
fs5.rmdirSync(dir);
|
|
16499
|
+
} catch {}
|
|
16500
|
+
};
|
|
16501
|
+
var issuedRecord = (cwd, claimed) => {
|
|
16502
|
+
const cut = claimed.lastIndexOf(":");
|
|
16503
|
+
if (cut <= 0)
|
|
16504
|
+
return null;
|
|
16505
|
+
migrateRepoIssued(cwd);
|
|
16506
|
+
try {
|
|
16507
|
+
return fs5.readFileSync(path5.join(userIssuedRoot(), hash(claimed.slice(0, cut)), hash(claimed)), "utf8");
|
|
16508
|
+
} catch {
|
|
16509
|
+
return null;
|
|
16510
|
+
}
|
|
16511
|
+
};
|
|
16512
|
+
var TOKEN_HASH = /^([0-9a-f]{64})$/mu;
|
|
16513
|
+
var issuedToken = (claimed) => {
|
|
16514
|
+
const cut = claimed.lastIndexOf(":");
|
|
16515
|
+
if (cut <= 0)
|
|
16516
|
+
return { stored: null, leadBound: false };
|
|
16517
|
+
const dir = path5.join(userTokenRoot(), hash(claimed.slice(0, cut)));
|
|
16518
|
+
try {
|
|
16519
|
+
const text = fs5.readFileSync(path5.join(dir, hash(claimed)), "utf8");
|
|
16520
|
+
return { stored: TOKEN_HASH.exec(text)?.[1] ?? null, leadBound: true };
|
|
16521
|
+
} catch {
|
|
16522
|
+
return { stored: null, leadBound: safeList(dir).length > 0 };
|
|
16523
|
+
}
|
|
16524
|
+
};
|
|
16525
|
+
function issuedBinding(cwd, claimed) {
|
|
16526
|
+
const record = issuedRecord(cwd, claimed);
|
|
16527
|
+
const { stored, leadBound } = issuedToken(claimed);
|
|
16528
|
+
if (stored)
|
|
16529
|
+
return "token";
|
|
16530
|
+
if (record === null)
|
|
16531
|
+
return null;
|
|
16532
|
+
return leadBound ? "token" : "legacy";
|
|
16533
|
+
}
|
|
16429
16534
|
var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
|
|
16430
16535
|
|
|
16431
16536
|
// packages/workit-core/src/core/package-root.ts
|
|
16432
16537
|
import { existsSync } from "node:fs";
|
|
16433
|
-
import
|
|
16538
|
+
import path6 from "node:path";
|
|
16434
16539
|
import { fileURLToPath } from "node:url";
|
|
16435
16540
|
var packageRoot = () => {
|
|
16436
|
-
let dir =
|
|
16541
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
16437
16542
|
while (true) {
|
|
16438
|
-
const parent =
|
|
16439
|
-
if (existsSync(
|
|
16543
|
+
const parent = path6.dirname(dir);
|
|
16544
|
+
if (existsSync(path6.join(dir, "package.json")) || parent === dir)
|
|
16440
16545
|
return dir;
|
|
16441
16546
|
dir = parent;
|
|
16442
16547
|
}
|
|
16443
16548
|
};
|
|
16444
16549
|
var assetRoot = () => {
|
|
16445
16550
|
const root = packageRoot();
|
|
16446
|
-
const assets =
|
|
16551
|
+
const assets = path6.join(root, "assets");
|
|
16447
16552
|
return existsSync(assets) ? assets : root;
|
|
16448
16553
|
};
|
|
16449
16554
|
|
|
16450
16555
|
// packages/workit-core/src/core/store-lock.ts
|
|
16451
16556
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
16452
|
-
import
|
|
16557
|
+
import fs6 from "node:fs";
|
|
16453
16558
|
import { hostname } from "node:os";
|
|
16454
16559
|
var metadataLockSchema = object({
|
|
16455
16560
|
pid: number2().int().nonnegative().safe(),
|
|
@@ -16461,8 +16566,10 @@ var metadataLockSchema = object({
|
|
|
16461
16566
|
var FOREIGN_LOCK_TTL_MS = 10 * 60000;
|
|
16462
16567
|
var UNREADABLE_LOCK_TTL_MS = 30000;
|
|
16463
16568
|
var RECLAIM_GUARD_TTL_MS = 30000;
|
|
16464
|
-
var
|
|
16569
|
+
var IN_PROCESS_LOCK_TIMEOUT_MS = 250;
|
|
16570
|
+
var defaultLockTimeoutMs = IN_PROCESS_LOCK_TIMEOUT_MS;
|
|
16465
16571
|
var defaultLockTimeout = () => defaultLockTimeoutMs;
|
|
16572
|
+
var hostAwareLockTimeout = (cliMs) => defaultLockTimeoutMs > IN_PROCESS_LOCK_TIMEOUT_MS ? cliMs : IN_PROCESS_LOCK_TIMEOUT_MS;
|
|
16466
16573
|
var parseMetadataLock = (raw) => {
|
|
16467
16574
|
let value;
|
|
16468
16575
|
try {
|
|
@@ -16491,7 +16598,7 @@ var parseProcStatStart = (stat) => {
|
|
|
16491
16598
|
var processStartOf = (pid) => {
|
|
16492
16599
|
if (process.platform === "linux") {
|
|
16493
16600
|
try {
|
|
16494
|
-
return parseProcStatStart(
|
|
16601
|
+
return parseProcStatStart(fs6.readFileSync(`/proc/${pid}/stat`, "utf8"));
|
|
16495
16602
|
} catch {
|
|
16496
16603
|
return null;
|
|
16497
16604
|
}
|
|
@@ -16512,7 +16619,7 @@ var processStartOf = (pid) => {
|
|
|
16512
16619
|
};
|
|
16513
16620
|
var readTrimmed = (file) => {
|
|
16514
16621
|
try {
|
|
16515
|
-
return
|
|
16622
|
+
return fs6.readFileSync(file, "utf8").trim() || null;
|
|
16516
16623
|
} catch {
|
|
16517
16624
|
return null;
|
|
16518
16625
|
}
|
|
@@ -16523,7 +16630,7 @@ var localLockHost = () => {
|
|
|
16523
16630
|
return cachedLockHost;
|
|
16524
16631
|
let pidns = null;
|
|
16525
16632
|
try {
|
|
16526
|
-
pidns = /\[(\d+)\]/.exec(
|
|
16633
|
+
pidns = /\[(\d+)\]/.exec(fs6.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
|
|
16527
16634
|
} catch {}
|
|
16528
16635
|
const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
|
|
16529
16636
|
cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
|
|
@@ -16569,7 +16676,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
|
|
|
16569
16676
|
};
|
|
16570
16677
|
var ageOf = (file, nowMs) => {
|
|
16571
16678
|
try {
|
|
16572
|
-
return nowMs -
|
|
16679
|
+
return nowMs - fs6.lstatSync(file).mtimeMs;
|
|
16573
16680
|
} catch {
|
|
16574
16681
|
return null;
|
|
16575
16682
|
}
|
|
@@ -16580,7 +16687,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
16580
16687
|
if (age === null || age <= RECLAIM_GUARD_TTL_MS)
|
|
16581
16688
|
return false;
|
|
16582
16689
|
try {
|
|
16583
|
-
|
|
16690
|
+
fs6.rmdirSync(guard);
|
|
16584
16691
|
return true;
|
|
16585
16692
|
} catch {
|
|
16586
16693
|
return false;
|
|
@@ -16589,8 +16696,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
16589
16696
|
|
|
16590
16697
|
// packages/workit-core/src/store/event-log.ts
|
|
16591
16698
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
16592
|
-
import
|
|
16593
|
-
import
|
|
16699
|
+
import fs7 from "node:fs";
|
|
16700
|
+
import path7 from "node:path";
|
|
16594
16701
|
var EVENT_VERSION = 1;
|
|
16595
16702
|
|
|
16596
16703
|
class LogDamage extends Error {
|
|
@@ -16619,7 +16726,7 @@ var parseEvent = (line, file, offset) => {
|
|
|
16619
16726
|
function readLog(file, from = 0, expectSeq = null) {
|
|
16620
16727
|
let fd;
|
|
16621
16728
|
try {
|
|
16622
|
-
fd =
|
|
16729
|
+
fd = fs7.openSync(file, "r");
|
|
16623
16730
|
} catch (error) {
|
|
16624
16731
|
if (error.code === "ENOENT")
|
|
16625
16732
|
return null;
|
|
@@ -16628,13 +16735,13 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
16628
16735
|
let bytes;
|
|
16629
16736
|
let size;
|
|
16630
16737
|
try {
|
|
16631
|
-
size =
|
|
16738
|
+
size = fs7.fstatSync(fd).size;
|
|
16632
16739
|
if (from > size)
|
|
16633
16740
|
throw new LogDamage(`${file}: shorter than its snapshot`);
|
|
16634
16741
|
bytes = Buffer.alloc(size - from);
|
|
16635
16742
|
let read = 0;
|
|
16636
16743
|
while (read < bytes.length) {
|
|
16637
|
-
const got =
|
|
16744
|
+
const got = fs7.readSync(fd, bytes, read, bytes.length - read, from + read);
|
|
16638
16745
|
if (got === 0)
|
|
16639
16746
|
break;
|
|
16640
16747
|
read += got;
|
|
@@ -16642,7 +16749,7 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
16642
16749
|
bytes = bytes.subarray(0, read);
|
|
16643
16750
|
size = from + read;
|
|
16644
16751
|
} finally {
|
|
16645
|
-
|
|
16752
|
+
fs7.closeSync(fd);
|
|
16646
16753
|
}
|
|
16647
16754
|
const events = [];
|
|
16648
16755
|
let start = 0;
|
|
@@ -16667,11 +16774,11 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
16667
16774
|
}
|
|
16668
16775
|
var fsyncDirectory = (dir) => {
|
|
16669
16776
|
try {
|
|
16670
|
-
const fd =
|
|
16777
|
+
const fd = fs7.openSync(dir, "r");
|
|
16671
16778
|
try {
|
|
16672
|
-
|
|
16779
|
+
fs7.fsyncSync(fd);
|
|
16673
16780
|
} finally {
|
|
16674
|
-
|
|
16781
|
+
fs7.closeSync(fd);
|
|
16675
16782
|
}
|
|
16676
16783
|
} catch (error) {
|
|
16677
16784
|
if (process.platform !== "win32")
|
|
@@ -16681,46 +16788,46 @@ var fsyncDirectory = (dir) => {
|
|
|
16681
16788
|
function appendEvent(file, event, validEnd) {
|
|
16682
16789
|
const line = Buffer.from(`${JSON.stringify(event)}
|
|
16683
16790
|
`, "utf8");
|
|
16684
|
-
const created = !
|
|
16685
|
-
if (!created &&
|
|
16686
|
-
const cut =
|
|
16791
|
+
const created = !fs7.existsSync(file);
|
|
16792
|
+
if (!created && fs7.statSync(file).size !== validEnd) {
|
|
16793
|
+
const cut = fs7.openSync(file, "r+");
|
|
16687
16794
|
try {
|
|
16688
|
-
|
|
16689
|
-
|
|
16795
|
+
fs7.ftruncateSync(cut, validEnd);
|
|
16796
|
+
fs7.fsyncSync(cut);
|
|
16690
16797
|
} finally {
|
|
16691
|
-
|
|
16798
|
+
fs7.closeSync(cut);
|
|
16692
16799
|
}
|
|
16693
16800
|
}
|
|
16694
|
-
const fd =
|
|
16801
|
+
const fd = fs7.openSync(file, "a", 384);
|
|
16695
16802
|
try {
|
|
16696
16803
|
let written = 0;
|
|
16697
16804
|
while (written < line.length)
|
|
16698
|
-
written +=
|
|
16699
|
-
|
|
16805
|
+
written += fs7.writeSync(fd, line, written, line.length - written);
|
|
16806
|
+
fs7.fsyncSync(fd);
|
|
16700
16807
|
} finally {
|
|
16701
|
-
|
|
16808
|
+
fs7.closeSync(fd);
|
|
16702
16809
|
}
|
|
16703
16810
|
if (created)
|
|
16704
|
-
fsyncDirectory(
|
|
16811
|
+
fsyncDirectory(path7.dirname(file));
|
|
16705
16812
|
return validEnd;
|
|
16706
16813
|
}
|
|
16707
16814
|
function replaceFile(file, bytes, durable) {
|
|
16708
16815
|
const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
|
|
16709
16816
|
try {
|
|
16710
|
-
const fd =
|
|
16817
|
+
const fd = fs7.openSync(temporary, "wx", 384);
|
|
16711
16818
|
try {
|
|
16712
|
-
|
|
16819
|
+
fs7.writeSync(fd, bytes);
|
|
16713
16820
|
if (durable)
|
|
16714
|
-
|
|
16821
|
+
fs7.fsyncSync(fd);
|
|
16715
16822
|
} finally {
|
|
16716
|
-
|
|
16823
|
+
fs7.closeSync(fd);
|
|
16717
16824
|
}
|
|
16718
16825
|
renameWithRetry(temporary, file);
|
|
16719
16826
|
if (durable)
|
|
16720
|
-
fsyncDirectory(
|
|
16827
|
+
fsyncDirectory(path7.dirname(file));
|
|
16721
16828
|
} catch (error) {
|
|
16722
16829
|
try {
|
|
16723
|
-
|
|
16830
|
+
fs7.unlinkSync(temporary);
|
|
16724
16831
|
} catch {}
|
|
16725
16832
|
throw error;
|
|
16726
16833
|
}
|
|
@@ -16745,7 +16852,7 @@ var retryTransient = (run) => {
|
|
|
16745
16852
|
}
|
|
16746
16853
|
}
|
|
16747
16854
|
};
|
|
16748
|
-
var renameWithRetry = (from, to) => retryTransient(() =>
|
|
16855
|
+
var renameWithRetry = (from, to) => retryTransient(() => fs7.renameSync(from, to));
|
|
16749
16856
|
|
|
16750
16857
|
// packages/workit-core/src/store/patch.ts
|
|
16751
16858
|
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -16858,7 +16965,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
|
|
|
16858
16965
|
});
|
|
16859
16966
|
|
|
16860
16967
|
// packages/workit-core/src/store/reduce.ts
|
|
16861
|
-
import { createHash as
|
|
16968
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
16862
16969
|
var OPENING_TYPES = new Set([
|
|
16863
16970
|
"task.opened",
|
|
16864
16971
|
"task.imported",
|
|
@@ -16887,7 +16994,7 @@ var isObject4 = (value) => typeof value === "object" && value !== null && !Array
|
|
|
16887
16994
|
var isKey = (value) => isObject4(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
|
|
16888
16995
|
var BLOB_REF = "$blob";
|
|
16889
16996
|
var blobRef = (value) => isObject4(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
|
|
16890
|
-
var blobDigest = (value) =>
|
|
16997
|
+
var blobDigest = (value) => createHash4("sha256").update(JSON.stringify(value)).digest("hex");
|
|
16891
16998
|
var toBlob = (value, blobs) => {
|
|
16892
16999
|
if (!isObject4(value))
|
|
16893
17000
|
return value;
|
|
@@ -17042,7 +17149,7 @@ var indexEntry = (task, key, legacy, file) => {
|
|
|
17042
17149
|
};
|
|
17043
17150
|
var fileSignature = (file) => {
|
|
17044
17151
|
try {
|
|
17045
|
-
const stat =
|
|
17152
|
+
const stat = fs8.statSync(file, { bigint: true });
|
|
17046
17153
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
17047
17154
|
} catch {
|
|
17048
17155
|
return null;
|
|
@@ -17060,7 +17167,7 @@ var cachedRuntimeVersion = null;
|
|
|
17060
17167
|
var runtimeVersion = () => {
|
|
17061
17168
|
if (cachedRuntimeVersion === null) {
|
|
17062
17169
|
try {
|
|
17063
|
-
const pkg = JSON.parse(
|
|
17170
|
+
const pkg = JSON.parse(fs8.readFileSync(path8.join(packageRoot(), "package.json"), "utf8"));
|
|
17064
17171
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
17065
17172
|
} catch {
|
|
17066
17173
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -17086,14 +17193,14 @@ var isNewerVersion = (candidate, current) => {
|
|
|
17086
17193
|
var validId = (value) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(value);
|
|
17087
17194
|
var readText = (file) => {
|
|
17088
17195
|
try {
|
|
17089
|
-
return
|
|
17196
|
+
return fs8.readFileSync(file, "utf8");
|
|
17090
17197
|
} catch {
|
|
17091
17198
|
return "";
|
|
17092
17199
|
}
|
|
17093
17200
|
};
|
|
17094
17201
|
var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
17095
17202
|
var branchStart = (location, branch, aliases) => {
|
|
17096
|
-
const first = readText(
|
|
17203
|
+
const first = readText(path8.join(path8.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
17097
17204
|
`, 1)[0];
|
|
17098
17205
|
const created = REFLOG_LINE.exec(first);
|
|
17099
17206
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -17103,7 +17210,7 @@ var branchStart = (location, branch, aliases) => {
|
|
|
17103
17210
|
return start;
|
|
17104
17211
|
if (!location.git)
|
|
17105
17212
|
return null;
|
|
17106
|
-
for (const line of readText(
|
|
17213
|
+
for (const line of readText(path8.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
17107
17214
|
`)) {
|
|
17108
17215
|
const entry = REFLOG_LINE.exec(line);
|
|
17109
17216
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -17113,23 +17220,23 @@ var branchStart = (location, branch, aliases) => {
|
|
|
17113
17220
|
}
|
|
17114
17221
|
return null;
|
|
17115
17222
|
};
|
|
17116
|
-
var refExists = (common, ref) =>
|
|
17223
|
+
var refExists = (common, ref) => fs8.existsSync(path8.join(common, ref)) || readText(path8.join(common, "packed-refs")).includes(` ${ref}
|
|
17117
17224
|
`);
|
|
17118
17225
|
var origins = new Map;
|
|
17119
17226
|
var sameDirectoryIdentity = (left, right) => {
|
|
17120
|
-
if (!
|
|
17227
|
+
if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
|
|
17121
17228
|
return false;
|
|
17122
|
-
const normalizedLeft =
|
|
17123
|
-
const normalizedRight =
|
|
17229
|
+
const normalizedLeft = path8.resolve(left);
|
|
17230
|
+
const normalizedRight = path8.resolve(right);
|
|
17124
17231
|
try {
|
|
17125
|
-
const a =
|
|
17126
|
-
const b =
|
|
17232
|
+
const a = fs8.statSync(normalizedLeft, { bigint: true });
|
|
17233
|
+
const b = fs8.statSync(normalizedRight, { bigint: true });
|
|
17127
17234
|
if (!a.isDirectory() || !b.isDirectory())
|
|
17128
17235
|
return false;
|
|
17129
17236
|
if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
|
|
17130
17237
|
return true;
|
|
17131
|
-
const canonicalLeft =
|
|
17132
|
-
const canonicalRight =
|
|
17238
|
+
const canonicalLeft = fs8.realpathSync(normalizedLeft);
|
|
17239
|
+
const canonicalRight = fs8.realpathSync(normalizedRight);
|
|
17133
17240
|
if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
|
|
17134
17241
|
return true;
|
|
17135
17242
|
return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
|
|
@@ -17166,8 +17273,8 @@ class TaskStore {
|
|
|
17166
17273
|
migrationChecked = false;
|
|
17167
17274
|
compactDue = new Set;
|
|
17168
17275
|
constructor(root, options = {}) {
|
|
17169
|
-
const resolved =
|
|
17170
|
-
this.origin =
|
|
17276
|
+
const resolved = path8.resolve(root);
|
|
17277
|
+
this.origin = fs8.existsSync(resolved) ? fs8.realpathSync(resolved) : resolved;
|
|
17171
17278
|
this.located = resolveStore(this.origin);
|
|
17172
17279
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
17173
17280
|
this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
|
|
@@ -17175,7 +17282,7 @@ class TaskStore {
|
|
|
17175
17282
|
this.migrateOnRead = options.migrateOnRead;
|
|
17176
17283
|
}
|
|
17177
17284
|
location() {
|
|
17178
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared &&
|
|
17285
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs8.existsSync(path8.join(this.root, ".git"))) {
|
|
17179
17286
|
this.located = undefined;
|
|
17180
17287
|
this.migrationChecked = false;
|
|
17181
17288
|
}
|
|
@@ -17239,7 +17346,7 @@ class TaskStore {
|
|
|
17239
17346
|
const tasksDir = this.paths().tasks;
|
|
17240
17347
|
let names;
|
|
17241
17348
|
try {
|
|
17242
|
-
names =
|
|
17349
|
+
names = fs8.existsSync(tasksDir) ? fs8.readdirSync(tasksDir).filter((name) => validId(name)) : [];
|
|
17243
17350
|
} catch (error) {
|
|
17244
17351
|
return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
|
|
17245
17352
|
path: tasksDir
|
|
@@ -17280,7 +17387,7 @@ class TaskStore {
|
|
|
17280
17387
|
const file = this.paths().workspace;
|
|
17281
17388
|
let bytes;
|
|
17282
17389
|
try {
|
|
17283
|
-
bytes = retryTransient(() =>
|
|
17390
|
+
bytes = retryTransient(() => fs8.readFileSync(file, "utf8"));
|
|
17284
17391
|
} catch (error) {
|
|
17285
17392
|
if (error.code === "ENOENT")
|
|
17286
17393
|
return success(null, null, null);
|
|
@@ -17331,7 +17438,7 @@ class TaskStore {
|
|
|
17331
17438
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
17332
17439
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
17333
17440
|
}
|
|
17334
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
17441
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path8.basename(this.root) || this.root;
|
|
17335
17442
|
const intent = {
|
|
17336
17443
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
17337
17444
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -17391,14 +17498,14 @@ class TaskStore {
|
|
|
17391
17498
|
const branch = key.ok ? key.data.branch : null;
|
|
17392
17499
|
if (!branch || !location.ok)
|
|
17393
17500
|
return success(null, null, null);
|
|
17394
|
-
const common =
|
|
17395
|
-
const heads =
|
|
17396
|
-
const headLog = location.data.git ?
|
|
17501
|
+
const common = path8.dirname(location.data.dir);
|
|
17502
|
+
const heads = path8.join(common, "logs", "refs", "heads");
|
|
17503
|
+
const headLog = location.data.git ? path8.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
17397
17504
|
const signatures = [
|
|
17398
|
-
|
|
17505
|
+
path8.join(heads, branch),
|
|
17399
17506
|
headLog,
|
|
17400
17507
|
heads,
|
|
17401
|
-
|
|
17508
|
+
path8.join(common, "packed-refs")
|
|
17402
17509
|
].map((file) => fileSignature(file) ?? "-");
|
|
17403
17510
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
17404
17511
|
let resolved = origins.get(slot);
|
|
@@ -17410,7 +17517,7 @@ class TaskStore {
|
|
|
17410
17517
|
aliases.push(rename.from);
|
|
17411
17518
|
const start = branchStart(location.data, branch, aliases);
|
|
17412
17519
|
const slash = start?.indexOf("/") ?? -1;
|
|
17413
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
17520
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path8.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
17414
17521
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
17415
17522
|
resolved = {
|
|
17416
17523
|
signature: signatures.join("|"),
|
|
@@ -17648,13 +17755,13 @@ class TaskStore {
|
|
|
17648
17755
|
if (!ready.ok)
|
|
17649
17756
|
return ready;
|
|
17650
17757
|
const dirs = this.paths();
|
|
17651
|
-
const recovery =
|
|
17652
|
-
if (
|
|
17758
|
+
const recovery = path8.join(this.root, ".workit", "recovery");
|
|
17759
|
+
if (fs8.existsSync(recovery)) {
|
|
17653
17760
|
let files = 0;
|
|
17654
17761
|
let bytes = 0;
|
|
17655
17762
|
try {
|
|
17656
|
-
for (const name of
|
|
17657
|
-
const stat =
|
|
17763
|
+
for (const name of fs8.readdirSync(recovery)) {
|
|
17764
|
+
const stat = fs8.lstatSync(path8.join(recovery, name));
|
|
17658
17765
|
if (!stat.isFile())
|
|
17659
17766
|
continue;
|
|
17660
17767
|
files += 1;
|
|
@@ -17663,17 +17770,17 @@ class TaskStore {
|
|
|
17663
17770
|
} catch {}
|
|
17664
17771
|
const remove = options.pruneRecovery === true && !dryRun;
|
|
17665
17772
|
if (remove)
|
|
17666
|
-
|
|
17773
|
+
fs8.rmSync(recovery, { recursive: true, force: true });
|
|
17667
17774
|
report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
|
|
17668
17775
|
}
|
|
17669
|
-
if (!
|
|
17776
|
+
if (!fs8.existsSync(dirs.tasks))
|
|
17670
17777
|
return success(null, null, report);
|
|
17671
|
-
const names =
|
|
17778
|
+
const names = fs8.readdirSync(dirs.tasks).filter((name) => validId(name));
|
|
17672
17779
|
for (const name of names) {
|
|
17673
17780
|
const file = this.eventsPath(name);
|
|
17674
17781
|
let size = 0;
|
|
17675
17782
|
try {
|
|
17676
|
-
size =
|
|
17783
|
+
size = fs8.statSync(file).size;
|
|
17677
17784
|
} catch {
|
|
17678
17785
|
continue;
|
|
17679
17786
|
}
|
|
@@ -17701,16 +17808,16 @@ class TaskStore {
|
|
|
17701
17808
|
const references = new Set;
|
|
17702
17809
|
for (const name of names)
|
|
17703
17810
|
try {
|
|
17704
|
-
for (const match of
|
|
17811
|
+
for (const match of fs8.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
|
|
17705
17812
|
references.add(match[1]);
|
|
17706
17813
|
} catch {}
|
|
17707
|
-
if (
|
|
17708
|
-
for (const name of
|
|
17814
|
+
if (fs8.existsSync(dirs.blobs))
|
|
17815
|
+
for (const name of fs8.readdirSync(dirs.blobs)) {
|
|
17709
17816
|
const digest = name.replace(/\.json$/, "");
|
|
17710
|
-
const file =
|
|
17817
|
+
const file = path8.join(dirs.blobs, name);
|
|
17711
17818
|
let stat;
|
|
17712
17819
|
try {
|
|
17713
|
-
stat =
|
|
17820
|
+
stat = fs8.lstatSync(file);
|
|
17714
17821
|
} catch {
|
|
17715
17822
|
continue;
|
|
17716
17823
|
}
|
|
@@ -17721,11 +17828,11 @@ class TaskStore {
|
|
|
17721
17828
|
report.blobs.removed += 1;
|
|
17722
17829
|
report.blobs.removedBytes += stat.size;
|
|
17723
17830
|
if (!dryRun)
|
|
17724
|
-
|
|
17831
|
+
fs8.rmSync(file, { force: true });
|
|
17725
17832
|
}
|
|
17726
17833
|
return success(null, null, null);
|
|
17727
17834
|
};
|
|
17728
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
17835
|
+
const swept = dryRun ? sweep() : this.withLock(path8.join(dirs.dir, "gc.lock"), sweep);
|
|
17729
17836
|
if (!swept.ok)
|
|
17730
17837
|
return swept;
|
|
17731
17838
|
const temporaryDirs = [
|
|
@@ -17733,17 +17840,17 @@ class TaskStore {
|
|
|
17733
17840
|
dirs.tasks,
|
|
17734
17841
|
dirs.blobs,
|
|
17735
17842
|
dirs.checkout,
|
|
17736
|
-
...names.map((name) =>
|
|
17843
|
+
...names.map((name) => path8.join(dirs.tasks, name))
|
|
17737
17844
|
];
|
|
17738
17845
|
for (const directory of temporaryDirs) {
|
|
17739
|
-
if (!
|
|
17846
|
+
if (!fs8.existsSync(directory))
|
|
17740
17847
|
continue;
|
|
17741
|
-
for (const name of
|
|
17848
|
+
for (const name of fs8.readdirSync(directory)) {
|
|
17742
17849
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
17743
17850
|
continue;
|
|
17744
|
-
const file =
|
|
17851
|
+
const file = path8.join(directory, name);
|
|
17745
17852
|
try {
|
|
17746
|
-
const stat =
|
|
17853
|
+
const stat = fs8.lstatSync(file);
|
|
17747
17854
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
17748
17855
|
continue;
|
|
17749
17856
|
} catch {
|
|
@@ -17751,37 +17858,37 @@ class TaskStore {
|
|
|
17751
17858
|
}
|
|
17752
17859
|
report.temporary.removed += 1;
|
|
17753
17860
|
if (!dryRun)
|
|
17754
|
-
|
|
17861
|
+
fs8.rmSync(file, { force: true });
|
|
17755
17862
|
}
|
|
17756
17863
|
}
|
|
17757
17864
|
return success(null, null, report);
|
|
17758
17865
|
}
|
|
17759
17866
|
paths() {
|
|
17760
17867
|
const location = this.location();
|
|
17761
|
-
const dir = location.ok ? location.data.dir :
|
|
17762
|
-
const checkout =
|
|
17868
|
+
const dir = location.ok ? location.data.dir : path8.join(this.root, ".workit");
|
|
17869
|
+
const checkout = path8.join(dir, "checkouts", checkoutSlug(this.root));
|
|
17763
17870
|
return {
|
|
17764
17871
|
dir,
|
|
17765
17872
|
shared: location.ok ? location.data.shared : false,
|
|
17766
|
-
marker:
|
|
17873
|
+
marker: path8.join(dir, "store.json"),
|
|
17767
17874
|
checkout,
|
|
17768
|
-
workspace:
|
|
17769
|
-
checkoutLock:
|
|
17770
|
-
tasks:
|
|
17771
|
-
index:
|
|
17772
|
-
blobs:
|
|
17773
|
-
legacy:
|
|
17774
|
-
v2:
|
|
17875
|
+
workspace: path8.join(checkout, "workspace.json"),
|
|
17876
|
+
checkoutLock: path8.join(checkout, "metadata.lock"),
|
|
17877
|
+
tasks: path8.join(dir, "tasks"),
|
|
17878
|
+
index: path8.join(dir, "task-index.json"),
|
|
17879
|
+
blobs: path8.join(dir, "blobs", "candidates"),
|
|
17880
|
+
legacy: path8.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
17881
|
+
v2: path8.join(this.root, ".workit")
|
|
17775
17882
|
};
|
|
17776
17883
|
}
|
|
17777
17884
|
eventsPath(taskId) {
|
|
17778
|
-
return
|
|
17885
|
+
return path8.join(this.paths().tasks, taskId, "events.jsonl");
|
|
17779
17886
|
}
|
|
17780
17887
|
snapshotPath(taskId) {
|
|
17781
|
-
return
|
|
17888
|
+
return path8.join(this.paths().tasks, taskId, "snapshot.json");
|
|
17782
17889
|
}
|
|
17783
17890
|
taskLockPath(taskId) {
|
|
17784
|
-
return
|
|
17891
|
+
return path8.join(this.paths().tasks, taskId, "lock");
|
|
17785
17892
|
}
|
|
17786
17893
|
ready(write = false) {
|
|
17787
17894
|
const location = this.location();
|
|
@@ -17791,7 +17898,7 @@ class TaskStore {
|
|
|
17791
17898
|
return success(null, null, null);
|
|
17792
17899
|
const dirs = this.paths();
|
|
17793
17900
|
try {
|
|
17794
|
-
const marker = JSON.parse(
|
|
17901
|
+
const marker = JSON.parse(fs8.readFileSync(dirs.marker, "utf8"));
|
|
17795
17902
|
if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
|
|
17796
17903
|
return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
|
|
17797
17904
|
} catch {}
|
|
@@ -17820,21 +17927,21 @@ class TaskStore {
|
|
|
17820
17927
|
return {
|
|
17821
17928
|
read: (digest) => {
|
|
17822
17929
|
try {
|
|
17823
|
-
return JSON.parse(
|
|
17930
|
+
return JSON.parse(fs8.readFileSync(path8.join(dir, `${digest}.json`), "utf8"));
|
|
17824
17931
|
} catch (error) {
|
|
17825
17932
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
17826
17933
|
}
|
|
17827
17934
|
},
|
|
17828
17935
|
write: (digest, value) => {
|
|
17829
|
-
const file =
|
|
17830
|
-
if (
|
|
17936
|
+
const file = path8.join(dir, `${digest}.json`);
|
|
17937
|
+
if (fs8.existsSync(file)) {
|
|
17831
17938
|
const stamp = new Date;
|
|
17832
17939
|
try {
|
|
17833
|
-
|
|
17940
|
+
fs8.utimesSync(file, stamp, stamp);
|
|
17834
17941
|
return;
|
|
17835
17942
|
} catch {}
|
|
17836
17943
|
}
|
|
17837
|
-
|
|
17944
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
17838
17945
|
replaceFile(file, JSON.stringify(value), true);
|
|
17839
17946
|
}
|
|
17840
17947
|
};
|
|
@@ -17916,7 +18023,7 @@ class TaskStore {
|
|
|
17916
18023
|
}
|
|
17917
18024
|
readSnapshot(taskId) {
|
|
17918
18025
|
try {
|
|
17919
|
-
const value = JSON.parse(
|
|
18026
|
+
const value = JSON.parse(fs8.readFileSync(this.snapshotPath(taskId), "utf8"));
|
|
17920
18027
|
if (!isObject5(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject5(value.record))
|
|
17921
18028
|
return null;
|
|
17922
18029
|
return value;
|
|
@@ -18018,8 +18125,8 @@ class TaskStore {
|
|
|
18018
18125
|
}
|
|
18019
18126
|
}
|
|
18020
18127
|
openTask(record, type, key, legacy = null) {
|
|
18021
|
-
const dir =
|
|
18022
|
-
|
|
18128
|
+
const dir = path8.join(this.paths().tasks, record.id);
|
|
18129
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
18023
18130
|
const blobs = this.blobStore();
|
|
18024
18131
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
18025
18132
|
const event = this.event(record.id, 1, type, {
|
|
@@ -18071,11 +18178,11 @@ class TaskStore {
|
|
|
18071
18178
|
} catch {}
|
|
18072
18179
|
if (!latest || latest.events[0]?.id !== last.id)
|
|
18073
18180
|
return failure2("busy", "the task log changed during compaction; retry", { taskId });
|
|
18074
|
-
const appended =
|
|
18181
|
+
const appended = fs8.readFileSync(file).subarray(log.end, latest.end);
|
|
18075
18182
|
const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
|
|
18076
18183
|
replaceFile(file, bytes.toString("utf8"), true);
|
|
18077
18184
|
try {
|
|
18078
|
-
|
|
18185
|
+
fs8.rmSync(this.snapshotPath(taskId), { force: true });
|
|
18079
18186
|
} catch {}
|
|
18080
18187
|
const reloaded = this.load(taskId);
|
|
18081
18188
|
if (reloaded.ok && reloaded.data)
|
|
@@ -18088,7 +18195,7 @@ class TaskStore {
|
|
|
18088
18195
|
}
|
|
18089
18196
|
countEvents(file) {
|
|
18090
18197
|
try {
|
|
18091
|
-
const bytes =
|
|
18198
|
+
const bytes = fs8.readFileSync(file);
|
|
18092
18199
|
let count = 0;
|
|
18093
18200
|
for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
|
|
18094
18201
|
count += 1;
|
|
@@ -18110,8 +18217,8 @@ class TaskStore {
|
|
|
18110
18217
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
18111
18218
|
}
|
|
18112
18219
|
withKeyLock(key, operation) {
|
|
18113
|
-
const digest =
|
|
18114
|
-
return this.withLock(
|
|
18220
|
+
const digest = createHash5("sha256").update(key).digest("hex").slice(0, 32);
|
|
18221
|
+
return this.withLock(path8.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
18115
18222
|
}
|
|
18116
18223
|
bindLocked(taskId, key, timestamp) {
|
|
18117
18224
|
const current = this.readWorkspace();
|
|
@@ -18252,7 +18359,7 @@ class TaskStore {
|
|
|
18252
18359
|
writeWorkspace(record) {
|
|
18253
18360
|
const file = this.paths().workspace;
|
|
18254
18361
|
try {
|
|
18255
|
-
|
|
18362
|
+
fs8.mkdirSync(path8.dirname(file), { recursive: true });
|
|
18256
18363
|
replaceFile(file, `${canonicalJson(record)}
|
|
18257
18364
|
`, true);
|
|
18258
18365
|
return success(null, null, null);
|
|
@@ -18262,7 +18369,7 @@ class TaskStore {
|
|
|
18262
18369
|
}
|
|
18263
18370
|
readIndex() {
|
|
18264
18371
|
try {
|
|
18265
|
-
const value = JSON.parse(
|
|
18372
|
+
const value = JSON.parse(fs8.readFileSync(this.paths().index, "utf8"));
|
|
18266
18373
|
if (!isObject5(value) || value.version !== INDEX_VERSION || !isObject5(value.tasks))
|
|
18267
18374
|
return {};
|
|
18268
18375
|
const tasks = {};
|
|
@@ -18276,7 +18383,7 @@ class TaskStore {
|
|
|
18276
18383
|
}
|
|
18277
18384
|
writeIndex(entries) {
|
|
18278
18385
|
try {
|
|
18279
|
-
|
|
18386
|
+
fs8.mkdirSync(this.paths().tasks, { recursive: true });
|
|
18280
18387
|
replaceFile(this.paths().index, JSON.stringify({
|
|
18281
18388
|
version: INDEX_VERSION,
|
|
18282
18389
|
tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
|
|
@@ -18330,23 +18437,23 @@ class TaskStore {
|
|
|
18330
18437
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
18331
18438
|
}
|
|
18332
18439
|
v2Dirs() {
|
|
18333
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
18440
|
+
return [...new Set([this.root, this.origin])].map((dir) => path8.join(dir, ".workit"));
|
|
18334
18441
|
}
|
|
18335
18442
|
pendingMigrations() {
|
|
18336
18443
|
return this.v2Dirs().filter((dir) => {
|
|
18337
|
-
const raw = this.readV2Workspace(
|
|
18444
|
+
const raw = this.readV2Workspace(path8.join(dir, "workspace.json"));
|
|
18338
18445
|
return raw !== null && raw !== TOMBSTONE;
|
|
18339
18446
|
});
|
|
18340
18447
|
}
|
|
18341
18448
|
migrateV2(v2) {
|
|
18342
18449
|
const dirs = this.paths();
|
|
18343
|
-
const v2Workspace =
|
|
18344
|
-
const v2Tasks =
|
|
18345
|
-
const legacy =
|
|
18450
|
+
const v2Workspace = path8.join(v2, "workspace.json");
|
|
18451
|
+
const v2Tasks = path8.join(v2, "tasks");
|
|
18452
|
+
const legacy = path8.join(dirs.dir, "legacy", checkoutSlug(path8.dirname(v2)), "v2");
|
|
18346
18453
|
const raw = this.readV2Workspace(v2Workspace);
|
|
18347
18454
|
if (raw === null || raw === TOMBSTONE)
|
|
18348
18455
|
return success(null, null, null);
|
|
18349
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
18456
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path8.join(v2, "metadata.lock"), () => {
|
|
18350
18457
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
18351
18458
|
if (workspace === null || workspace === TOMBSTONE)
|
|
18352
18459
|
return success(null, null, null);
|
|
@@ -18355,7 +18462,7 @@ class TaskStore {
|
|
|
18355
18462
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
18356
18463
|
let files = [];
|
|
18357
18464
|
try {
|
|
18358
|
-
files =
|
|
18465
|
+
files = fs8.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path8.join(v2Tasks, name)));
|
|
18359
18466
|
} catch {}
|
|
18360
18467
|
const current = this.readWorkspace();
|
|
18361
18468
|
if (!current.ok)
|
|
@@ -18373,22 +18480,22 @@ class TaskStore {
|
|
|
18373
18480
|
let skipped = 0;
|
|
18374
18481
|
const done = new Map;
|
|
18375
18482
|
try {
|
|
18376
|
-
|
|
18483
|
+
fs8.mkdirSync(path8.join(legacy, "tasks"), { recursive: true });
|
|
18377
18484
|
for (const name of ["workspace.json", "index.json"])
|
|
18378
|
-
if (
|
|
18379
|
-
|
|
18485
|
+
if (fs8.existsSync(path8.join(v2, name)))
|
|
18486
|
+
fs8.copyFileSync(path8.join(v2, name), path8.join(legacy, name));
|
|
18380
18487
|
for (const name of files) {
|
|
18381
18488
|
const id = name.slice(0, -5);
|
|
18382
|
-
const file =
|
|
18383
|
-
const bytes =
|
|
18489
|
+
const file = path8.join(v2Tasks, name);
|
|
18490
|
+
const bytes = fs8.readFileSync(file, "utf8");
|
|
18384
18491
|
const digest = sha256(bytes);
|
|
18385
|
-
|
|
18492
|
+
fs8.writeFileSync(path8.join(legacy, "tasks", name), bytes);
|
|
18386
18493
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
18387
18494
|
if (!parsed.ok || parsed.data.id !== id)
|
|
18388
18495
|
return failure2("recovery_required", `cannot migrate 2.x task ${id}: ${parsed.ok ? "file name and record ID differ" : parsed.error}; move ${file} aside to continue`, { path: file });
|
|
18389
18496
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
18390
|
-
const origin = { path:
|
|
18391
|
-
if (!
|
|
18497
|
+
const origin = { path: path8.join(legacy, "tasks", name), digest };
|
|
18498
|
+
if (!fs8.existsSync(this.eventsPath(id))) {
|
|
18392
18499
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
18393
18500
|
migrated += 1;
|
|
18394
18501
|
} else {
|
|
@@ -18423,8 +18530,8 @@ class TaskStore {
|
|
|
18423
18530
|
try {
|
|
18424
18531
|
let complete = true;
|
|
18425
18532
|
for (const [name, digest] of done) {
|
|
18426
|
-
const file =
|
|
18427
|
-
if (sha256(
|
|
18533
|
+
const file = path8.join(v2Tasks, name);
|
|
18534
|
+
if (sha256(fs8.readFileSync(file, "utf8")) !== digest) {
|
|
18428
18535
|
complete = false;
|
|
18429
18536
|
continue;
|
|
18430
18537
|
}
|
|
@@ -18434,7 +18541,7 @@ class TaskStore {
|
|
|
18434
18541
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
18435
18542
|
path: v2
|
|
18436
18543
|
});
|
|
18437
|
-
|
|
18544
|
+
fs8.rmSync(path8.join(v2, "index.json"), { force: true });
|
|
18438
18545
|
this.writeTombstone(v2, target.id);
|
|
18439
18546
|
} catch (error) {
|
|
18440
18547
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -18454,45 +18561,45 @@ class TaskStore {
|
|
|
18454
18561
|
}
|
|
18455
18562
|
adoptLocalStore() {
|
|
18456
18563
|
const dirs = this.paths();
|
|
18457
|
-
const marker =
|
|
18458
|
-
if (!dirs.shared || !
|
|
18564
|
+
const marker = path8.join(dirs.v2, "store.json");
|
|
18565
|
+
if (!dirs.shared || !fs8.existsSync(marker))
|
|
18459
18566
|
return success(null, null, null);
|
|
18460
18567
|
return this.withLock(dirs.checkoutLock, () => {
|
|
18461
|
-
if (!
|
|
18568
|
+
if (!fs8.existsSync(marker))
|
|
18462
18569
|
return success(null, null, null);
|
|
18463
18570
|
let tasks = 0;
|
|
18464
18571
|
try {
|
|
18465
18572
|
const merge = (from, to) => {
|
|
18466
|
-
if (!
|
|
18467
|
-
|
|
18573
|
+
if (!fs8.existsSync(to)) {
|
|
18574
|
+
fs8.mkdirSync(path8.dirname(to), { recursive: true });
|
|
18468
18575
|
try {
|
|
18469
|
-
|
|
18576
|
+
fs8.renameSync(from, to);
|
|
18470
18577
|
} catch {
|
|
18471
|
-
|
|
18472
|
-
|
|
18578
|
+
fs8.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
|
|
18579
|
+
fs8.rmSync(from, { recursive: true, force: true });
|
|
18473
18580
|
}
|
|
18474
18581
|
return;
|
|
18475
18582
|
}
|
|
18476
|
-
if (
|
|
18477
|
-
for (const name of
|
|
18478
|
-
merge(
|
|
18583
|
+
if (fs8.lstatSync(from).isDirectory() && fs8.lstatSync(to).isDirectory())
|
|
18584
|
+
for (const name of fs8.readdirSync(from))
|
|
18585
|
+
merge(path8.join(from, name), path8.join(to, name));
|
|
18479
18586
|
};
|
|
18480
18587
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
18481
|
-
const from =
|
|
18482
|
-
if (!
|
|
18588
|
+
const from = path8.join(dirs.v2, sub);
|
|
18589
|
+
if (!fs8.existsSync(from))
|
|
18483
18590
|
continue;
|
|
18484
18591
|
if (sub === "tasks") {
|
|
18485
|
-
for (const name of
|
|
18486
|
-
if (validId(name) && !
|
|
18592
|
+
for (const name of fs8.readdirSync(from))
|
|
18593
|
+
if (validId(name) && !fs8.existsSync(path8.join(dirs.dir, sub, name)))
|
|
18487
18594
|
tasks += 1;
|
|
18488
18595
|
}
|
|
18489
|
-
merge(from,
|
|
18596
|
+
merge(from, path8.join(dirs.dir, sub));
|
|
18490
18597
|
}
|
|
18491
|
-
const ledger =
|
|
18492
|
-
if (
|
|
18493
|
-
merge(ledger,
|
|
18494
|
-
|
|
18495
|
-
|
|
18598
|
+
const ledger = path8.join(dirs.v2, "ledger");
|
|
18599
|
+
if (fs8.existsSync(ledger) && !fs8.existsSync(path8.join(dirs.dir, "ledger")))
|
|
18600
|
+
merge(ledger, path8.join(dirs.dir, "ledger"));
|
|
18601
|
+
fs8.rmSync(path8.join(dirs.v2, "task-index.json"), { force: true });
|
|
18602
|
+
fs8.renameSync(marker, path8.join(dirs.v2, "store.moved.json"));
|
|
18496
18603
|
} catch (error) {
|
|
18497
18604
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
18498
18605
|
path: dirs.v2
|
|
@@ -18512,7 +18619,7 @@ class TaskStore {
|
|
|
18512
18619
|
readV2Workspace(file) {
|
|
18513
18620
|
let bytes;
|
|
18514
18621
|
try {
|
|
18515
|
-
bytes =
|
|
18622
|
+
bytes = fs8.readFileSync(file, "utf8");
|
|
18516
18623
|
} catch {
|
|
18517
18624
|
return null;
|
|
18518
18625
|
}
|
|
@@ -18530,7 +18637,7 @@ class TaskStore {
|
|
|
18530
18637
|
schemaVersion: SCHEMA_VERSION,
|
|
18531
18638
|
id: workspaceId ?? newId(),
|
|
18532
18639
|
revision: newRevision(),
|
|
18533
|
-
root:
|
|
18640
|
+
root: path8.dirname(v2),
|
|
18534
18641
|
runtime: { createdWith: version, updatedWith: version },
|
|
18535
18642
|
writer: null,
|
|
18536
18643
|
store: {
|
|
@@ -18541,12 +18648,12 @@ class TaskStore {
|
|
|
18541
18648
|
},
|
|
18542
18649
|
critical: ["store"]
|
|
18543
18650
|
};
|
|
18544
|
-
|
|
18545
|
-
const ignore =
|
|
18546
|
-
if (!
|
|
18547
|
-
|
|
18651
|
+
fs8.mkdirSync(v2, { recursive: true });
|
|
18652
|
+
const ignore = path8.join(v2, ".gitignore");
|
|
18653
|
+
if (!fs8.existsSync(ignore))
|
|
18654
|
+
fs8.writeFileSync(ignore, `*
|
|
18548
18655
|
`);
|
|
18549
|
-
replaceFile(
|
|
18656
|
+
replaceFile(path8.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
18550
18657
|
`, true);
|
|
18551
18658
|
}
|
|
18552
18659
|
stubFor(taskId) {
|
|
@@ -18562,7 +18669,7 @@ class TaskStore {
|
|
|
18562
18669
|
}
|
|
18563
18670
|
isStub(file) {
|
|
18564
18671
|
try {
|
|
18565
|
-
const value = JSON.parse(
|
|
18672
|
+
const value = JSON.parse(fs8.readFileSync(file, "utf8"));
|
|
18566
18673
|
return isObject5(value) && isObject5(value.store) && value.store.format === "workit-store";
|
|
18567
18674
|
} catch {
|
|
18568
18675
|
return false;
|
|
@@ -18570,32 +18677,32 @@ class TaskStore {
|
|
|
18570
18677
|
}
|
|
18571
18678
|
writeTombstoneIfMissing() {
|
|
18572
18679
|
try {
|
|
18573
|
-
const v2 =
|
|
18574
|
-
if (
|
|
18680
|
+
const v2 = path8.join(this.root, ".workit");
|
|
18681
|
+
if (fs8.existsSync(path8.join(v2, "workspace.json")))
|
|
18575
18682
|
return;
|
|
18576
18683
|
let id = null;
|
|
18577
18684
|
try {
|
|
18578
|
-
id = JSON.parse(
|
|
18685
|
+
id = JSON.parse(fs8.readFileSync(this.paths().workspace, "utf8")).id ?? null;
|
|
18579
18686
|
} catch {}
|
|
18580
18687
|
this.writeTombstone(v2, id);
|
|
18581
18688
|
} catch {}
|
|
18582
18689
|
}
|
|
18583
18690
|
initializeStorage() {
|
|
18584
18691
|
const dirs = this.paths();
|
|
18585
|
-
retryTransient(() =>
|
|
18586
|
-
retryTransient(() =>
|
|
18587
|
-
if (!
|
|
18692
|
+
retryTransient(() => fs8.mkdirSync(dirs.checkout, { recursive: true }));
|
|
18693
|
+
retryTransient(() => fs8.mkdirSync(dirs.tasks, { recursive: true }));
|
|
18694
|
+
if (!fs8.existsSync(dirs.marker))
|
|
18588
18695
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
18589
18696
|
`, false);
|
|
18590
18697
|
if (!dirs.shared) {
|
|
18591
|
-
const ignore =
|
|
18698
|
+
const ignore = path8.join(dirs.dir, ".gitignore");
|
|
18592
18699
|
let current = null;
|
|
18593
18700
|
try {
|
|
18594
|
-
current =
|
|
18701
|
+
current = fs8.readFileSync(ignore, "utf8");
|
|
18595
18702
|
} catch {}
|
|
18596
18703
|
if (current !== `*
|
|
18597
18704
|
`)
|
|
18598
|
-
retryTransient(() =>
|
|
18705
|
+
retryTransient(() => fs8.writeFileSync(ignore, `*
|
|
18599
18706
|
`));
|
|
18600
18707
|
}
|
|
18601
18708
|
this.writeTombstoneIfMissing();
|
|
@@ -18611,7 +18718,7 @@ class TaskStore {
|
|
|
18611
18718
|
shouldReclaim: ({ payload, nowMs }) => {
|
|
18612
18719
|
let ageMs = null;
|
|
18613
18720
|
try {
|
|
18614
|
-
ageMs = nowMs -
|
|
18721
|
+
ageMs = nowMs - fs8.lstatSync(lockPath).mtimeMs;
|
|
18615
18722
|
} catch {}
|
|
18616
18723
|
return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
|
|
18617
18724
|
},
|
|
@@ -18648,7 +18755,7 @@ class TaskStore {
|
|
|
18648
18755
|
withLock(lockPath, operation) {
|
|
18649
18756
|
try {
|
|
18650
18757
|
this.initializeStorage();
|
|
18651
|
-
|
|
18758
|
+
fs8.mkdirSync(path8.dirname(lockPath), { recursive: true });
|
|
18652
18759
|
} catch (error) {
|
|
18653
18760
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
18654
18761
|
path: this.paths().dir
|
|
@@ -18688,18 +18795,18 @@ class TaskStore {
|
|
|
18688
18795
|
lockDirWritable(lockPath) {
|
|
18689
18796
|
const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
|
|
18690
18797
|
try {
|
|
18691
|
-
|
|
18798
|
+
fs8.closeSync(fs8.openSync(probe, "wx", 384));
|
|
18692
18799
|
} catch {
|
|
18693
18800
|
return false;
|
|
18694
18801
|
}
|
|
18695
18802
|
try {
|
|
18696
|
-
|
|
18803
|
+
fs8.rmSync(probe, { force: true });
|
|
18697
18804
|
} catch {}
|
|
18698
18805
|
return true;
|
|
18699
18806
|
}
|
|
18700
18807
|
lockHolderPresent(lockPath) {
|
|
18701
18808
|
try {
|
|
18702
|
-
|
|
18809
|
+
fs8.lstatSync(lockPath);
|
|
18703
18810
|
return true;
|
|
18704
18811
|
} catch (error) {
|
|
18705
18812
|
return error?.code !== "ENOENT";
|
|
@@ -18711,12 +18818,12 @@ class TaskStore {
|
|
|
18711
18818
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
18712
18819
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
18713
18820
|
path: lockPath,
|
|
18714
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
18821
|
+
guidance: `Check permissions and the read-only attribute on ${path8.dirname(lockPath)}.`
|
|
18715
18822
|
});
|
|
18716
18823
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
18717
18824
|
let lock = null;
|
|
18718
18825
|
try {
|
|
18719
|
-
lock = parseMetadataLockOrNull(
|
|
18826
|
+
lock = parseMetadataLockOrNull(fs8.readFileSync(lockPath, "utf8"));
|
|
18720
18827
|
} catch {}
|
|
18721
18828
|
return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
|
|
18722
18829
|
outcome: "not_started",
|
|
@@ -18734,15 +18841,15 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
|
|
|
18734
18841
|
var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
|
|
18735
18842
|
|
|
18736
18843
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
18737
|
-
import { createHash as
|
|
18738
|
-
import * as
|
|
18844
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
18845
|
+
import * as fs13 from "node:fs";
|
|
18739
18846
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
18740
|
-
import
|
|
18847
|
+
import path16 from "node:path";
|
|
18741
18848
|
|
|
18742
18849
|
// packages/workit-core/src/check-config.ts
|
|
18743
18850
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
18744
|
-
import
|
|
18745
|
-
import
|
|
18851
|
+
import fs9 from "node:fs";
|
|
18852
|
+
import path9 from "node:path";
|
|
18746
18853
|
var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
|
|
18747
18854
|
var CHECKS_FILE = "workit.checks.json";
|
|
18748
18855
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -18795,10 +18902,10 @@ var git = (cwd, args) => {
|
|
|
18795
18902
|
return value || null;
|
|
18796
18903
|
};
|
|
18797
18904
|
function checkRoot(cwd) {
|
|
18798
|
-
return
|
|
18905
|
+
return path9.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
18799
18906
|
}
|
|
18800
18907
|
var packageManager = (root) => {
|
|
18801
|
-
const has = (file) =>
|
|
18908
|
+
const has = (file) => fs9.existsSync(path9.join(root, file));
|
|
18802
18909
|
if (has("bun.lock") || has("bun.lockb"))
|
|
18803
18910
|
return "bun";
|
|
18804
18911
|
if (has("pnpm-lock.yaml"))
|
|
@@ -18818,7 +18925,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
|
|
|
18818
18925
|
function detectedChecks(root) {
|
|
18819
18926
|
const read = (file) => {
|
|
18820
18927
|
try {
|
|
18821
|
-
return
|
|
18928
|
+
return fs9.readFileSync(path9.join(root, file), "utf8");
|
|
18822
18929
|
} catch {
|
|
18823
18930
|
return null;
|
|
18824
18931
|
}
|
|
@@ -18857,7 +18964,7 @@ function detectedChecks(root) {
|
|
|
18857
18964
|
var GATES = ["testing", "verification"];
|
|
18858
18965
|
function loadCheckConfig(cwd) {
|
|
18859
18966
|
const root = checkRoot(cwd);
|
|
18860
|
-
const file =
|
|
18967
|
+
const file = path9.join(root, CHECKS_FILE);
|
|
18861
18968
|
const none = (error = null) => ({
|
|
18862
18969
|
source: error ? CHECKS_FILE : "none",
|
|
18863
18970
|
root,
|
|
@@ -18867,7 +18974,7 @@ function loadCheckConfig(cwd) {
|
|
|
18867
18974
|
});
|
|
18868
18975
|
let text = null;
|
|
18869
18976
|
try {
|
|
18870
|
-
text =
|
|
18977
|
+
text = fs9.readFileSync(file, "utf8");
|
|
18871
18978
|
} catch (error) {
|
|
18872
18979
|
if (error.code !== "ENOENT")
|
|
18873
18980
|
return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
|
|
@@ -18930,10 +19037,10 @@ function workitAvailable(env = process.env) {
|
|
|
18930
19037
|
return workitOnPath;
|
|
18931
19038
|
const windows = process.platform === "win32";
|
|
18932
19039
|
const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
18933
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
19040
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path9.delimiter).filter(Boolean);
|
|
18934
19041
|
workitOnPath = dirs.some((dir) => exts.some((ext) => {
|
|
18935
19042
|
try {
|
|
18936
|
-
return
|
|
19043
|
+
return fs9.statSync(path9.join(dir, `workit${ext}`)).isFile();
|
|
18937
19044
|
} catch {
|
|
18938
19045
|
return false;
|
|
18939
19046
|
}
|
|
@@ -18946,10 +19053,10 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
18946
19053
|
|
|
18947
19054
|
// packages/workit-core/src/git/rev.ts
|
|
18948
19055
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
18949
|
-
import { createHash as
|
|
18950
|
-
import
|
|
19056
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
19057
|
+
import fs10 from "node:fs";
|
|
18951
19058
|
import os2 from "node:os";
|
|
18952
|
-
import
|
|
19059
|
+
import path10 from "node:path";
|
|
18953
19060
|
var MAX_BUFFER = 256 * 1024 * 1024;
|
|
18954
19061
|
var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
|
|
18955
19062
|
var git2 = (cwd, args, options = {}) => {
|
|
@@ -18984,10 +19091,10 @@ function headSha(cwd) {
|
|
|
18984
19091
|
var emptyTree = (cwd) => line(git2(cwd, ["mktree"], { input: "" }));
|
|
18985
19092
|
var MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
|
|
18986
19093
|
var seedIndex = (from, to) => {
|
|
18987
|
-
|
|
18988
|
-
const { atimeNs, mtimeNs } =
|
|
19094
|
+
fs10.copyFileSync(from, to);
|
|
19095
|
+
const { atimeNs, mtimeNs } = fs10.statSync(from, { bigint: true });
|
|
18989
19096
|
const seconds = (ns) => (Number(ns / 1000n) - 1) / 1e6;
|
|
18990
|
-
|
|
19097
|
+
fs10.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
|
|
18991
19098
|
};
|
|
18992
19099
|
function worktreeTree(cwd, options = {}) {
|
|
18993
19100
|
const top = line(git2(cwd, ["rev-parse", "--show-toplevel"]));
|
|
@@ -18996,10 +19103,10 @@ function worktreeTree(cwd, options = {}) {
|
|
|
18996
19103
|
return null;
|
|
18997
19104
|
const cap = options.maxUntrackedBytes ?? MAX_UNTRACKED_BYTES;
|
|
18998
19105
|
const timeoutMs = options.timeoutMs ?? GIT_TIMEOUTS.worktree;
|
|
18999
|
-
const scratch =
|
|
19106
|
+
const scratch = fs10.mkdtempSync(path10.join(os2.tmpdir(), "workit-tree-"));
|
|
19000
19107
|
try {
|
|
19001
|
-
const tempIndex =
|
|
19002
|
-
if (
|
|
19108
|
+
const tempIndex = path10.join(scratch, "index");
|
|
19109
|
+
if (fs10.existsSync(indexPath))
|
|
19003
19110
|
seedIndex(indexPath, tempIndex);
|
|
19004
19111
|
const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
|
|
19005
19112
|
const untracked = git2(top, ["ls-files", "--others", "--exclude-standard", "-z"], {
|
|
@@ -19011,7 +19118,7 @@ function worktreeTree(cwd, options = {}) {
|
|
|
19011
19118
|
const skipped = [];
|
|
19012
19119
|
for (const file of untracked.stdout.split("\x00").filter(Boolean)) {
|
|
19013
19120
|
try {
|
|
19014
|
-
const stat =
|
|
19121
|
+
const stat = fs10.statSync(path10.join(top, file));
|
|
19015
19122
|
if (stat.isFile() && stat.size > cap)
|
|
19016
19123
|
skipped.push({ path: file, size: stat.size, mtimeMs: Math.trunc(stat.mtimeMs) });
|
|
19017
19124
|
} catch {}
|
|
@@ -19028,10 +19135,10 @@ function worktreeTree(cwd, options = {}) {
|
|
|
19028
19135
|
if (!tree)
|
|
19029
19136
|
return null;
|
|
19030
19137
|
const base = line(git2(top, ["rev-parse", "--verify", "-q", "HEAD^{tree}"])) ?? emptyTree(top);
|
|
19031
|
-
const key = skipped.length ? `sha256:${
|
|
19138
|
+
const key = skipped.length ? `sha256:${createHash6("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
|
|
19032
19139
|
return { tree, key, dirty: tree !== base || skipped.length > 0, skipped };
|
|
19033
19140
|
} finally {
|
|
19034
|
-
|
|
19141
|
+
fs10.rmSync(scratch, { recursive: true, force: true });
|
|
19035
19142
|
}
|
|
19036
19143
|
}
|
|
19037
19144
|
function worktreeSignal(cwd, options = {}) {
|
|
@@ -19051,16 +19158,16 @@ function worktreeSignal(cwd, options = {}) {
|
|
|
19051
19158
|
});
|
|
19052
19159
|
if (!status.ok)
|
|
19053
19160
|
return null;
|
|
19054
|
-
const hash =
|
|
19161
|
+
const hash = createHash6("sha256");
|
|
19055
19162
|
hash.update(`${headSha(top) ?? "unborn"}\x00`);
|
|
19056
19163
|
for (const entry of status.stdout.split("\x00")) {
|
|
19057
19164
|
if (entry.length < 4)
|
|
19058
19165
|
continue;
|
|
19059
19166
|
const file = entry.slice(3);
|
|
19060
|
-
const absolute =
|
|
19167
|
+
const absolute = path10.join(top, file);
|
|
19061
19168
|
let stat = "-";
|
|
19062
19169
|
try {
|
|
19063
|
-
const info =
|
|
19170
|
+
const info = fs10.lstatSync(absolute, { bigint: true });
|
|
19064
19171
|
stat = `${info.mode.toString(8)}:${info.size}:${info.mtimeNs}`;
|
|
19065
19172
|
if (info.isDirectory())
|
|
19066
19173
|
stat += `:${headSha(absolute) ?? "-"}`;
|
|
@@ -19127,17 +19234,17 @@ function pushRemoteName(cwd, branch) {
|
|
|
19127
19234
|
|
|
19128
19235
|
// packages/workit-core/src/core/policy/derive.ts
|
|
19129
19236
|
import { existsSync as existsSync4 } from "node:fs";
|
|
19130
|
-
import
|
|
19237
|
+
import path15 from "node:path";
|
|
19131
19238
|
|
|
19132
19239
|
// packages/workit-core/src/ledger.ts
|
|
19133
19240
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
19134
|
-
import { createHash as
|
|
19135
|
-
import
|
|
19136
|
-
import
|
|
19241
|
+
import { createHash as createHash9, randomBytes as randomBytes3 } from "node:crypto";
|
|
19242
|
+
import fs12 from "node:fs";
|
|
19243
|
+
import path14 from "node:path";
|
|
19137
19244
|
|
|
19138
19245
|
// packages/workit-core/src/core/vcs-config.ts
|
|
19139
|
-
import
|
|
19140
|
-
import
|
|
19246
|
+
import fs11 from "node:fs";
|
|
19247
|
+
import path13 from "node:path";
|
|
19141
19248
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
19142
19249
|
|
|
19143
19250
|
// packages/workit-core/src/core/config.ts
|
|
@@ -19151,7 +19258,7 @@ import {
|
|
|
19151
19258
|
writeFileSync as writeFileSync2
|
|
19152
19259
|
} from "node:fs";
|
|
19153
19260
|
import os3 from "node:os";
|
|
19154
|
-
import
|
|
19261
|
+
import path11 from "node:path";
|
|
19155
19262
|
|
|
19156
19263
|
// packages/workit-core/src/core/boundary.ts
|
|
19157
19264
|
import { statSync as statSync2 } from "node:fs";
|
|
@@ -19210,7 +19317,7 @@ var mergePreset = (preset, input = {}, current = {
|
|
|
19210
19317
|
protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
|
|
19211
19318
|
};
|
|
19212
19319
|
};
|
|
19213
|
-
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
19320
|
+
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workit");
|
|
19214
19321
|
var migratedDir = null;
|
|
19215
19322
|
var migrationFailed = false;
|
|
19216
19323
|
var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
@@ -19220,7 +19327,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
19220
19327
|
migratedDir = dir;
|
|
19221
19328
|
return dir;
|
|
19222
19329
|
}
|
|
19223
|
-
const legacy =
|
|
19330
|
+
const legacy = path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workflow-toolkit");
|
|
19224
19331
|
if (!existsSync3(legacy)) {
|
|
19225
19332
|
migratedDir = dir;
|
|
19226
19333
|
return dir;
|
|
@@ -19233,8 +19340,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
19233
19340
|
mkdirSync2(dir, { recursive: true });
|
|
19234
19341
|
diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
|
|
19235
19342
|
for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
|
|
19236
|
-
const src =
|
|
19237
|
-
const dest =
|
|
19343
|
+
const src = path11.join(legacy, entry.name);
|
|
19344
|
+
const dest = path11.join(dir, entry.name);
|
|
19238
19345
|
if (existsSync3(dest))
|
|
19239
19346
|
continue;
|
|
19240
19347
|
try {
|
|
@@ -19306,7 +19413,7 @@ var parseConfigResult = (raw, file) => {
|
|
|
19306
19413
|
return { status: "valid", path: file, config };
|
|
19307
19414
|
};
|
|
19308
19415
|
var readConfigTyped = (dir) => {
|
|
19309
|
-
const file =
|
|
19416
|
+
const file = path11.join(dir ?? configDir(), "config.json");
|
|
19310
19417
|
return parseConfigResult(readSafe(file), file);
|
|
19311
19418
|
};
|
|
19312
19419
|
var readConfig = () => {
|
|
@@ -19315,7 +19422,7 @@ var readConfig = () => {
|
|
|
19315
19422
|
throw new Error(result.error);
|
|
19316
19423
|
return result.config ?? DEFAULTS;
|
|
19317
19424
|
};
|
|
19318
|
-
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ??
|
|
19425
|
+
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path11.join(configDir(), "vcs.json");
|
|
19319
19426
|
var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
|
|
19320
19427
|
var resolveBranchPolicy = (config, workspace, repoPreset) => {
|
|
19321
19428
|
const wp = workspace?.branchPolicy ?? {};
|
|
@@ -19347,9 +19454,9 @@ var COMMIT_PRESETS = [
|
|
|
19347
19454
|
|
|
19348
19455
|
// packages/workit-core/src/core/workspaces.ts
|
|
19349
19456
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
19350
|
-
import { createHash as
|
|
19457
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
19351
19458
|
import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
19352
|
-
import
|
|
19459
|
+
import path12 from "node:path";
|
|
19353
19460
|
|
|
19354
19461
|
// packages/workit-core/src/core/branch-policy.ts
|
|
19355
19462
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
@@ -19474,7 +19581,7 @@ var releaseTrackSchema = object({
|
|
|
19474
19581
|
context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
|
|
19475
19582
|
}
|
|
19476
19583
|
}
|
|
19477
|
-
if (track.versionSource?.kind === "package-json" && (
|
|
19584
|
+
if (track.versionSource?.kind === "package-json" && (path12.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
|
|
19478
19585
|
context.addIssue({
|
|
19479
19586
|
code: "custom",
|
|
19480
19587
|
path: ["versionSource", "path"],
|
|
@@ -19495,6 +19602,8 @@ var workspaceConfigSchema = object({
|
|
|
19495
19602
|
defaultEndpoint: unknown().optional(),
|
|
19496
19603
|
verification: _enum(["self", "independent"]).optional(),
|
|
19497
19604
|
trailers: boolean2().optional(),
|
|
19605
|
+
liveSessionGuard: boolean2().optional(),
|
|
19606
|
+
fanout: object({ tierModels: unknown().optional() }).passthrough().optional(),
|
|
19498
19607
|
autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
|
|
19499
19608
|
kind,
|
|
19500
19609
|
union([boolean2(), literal("verified")]).optional()
|
|
@@ -19535,7 +19644,7 @@ var workspacesFileSchema = object({ workspaces: array(workspaceConfigSchema).opt
|
|
|
19535
19644
|
names.add(workspace.name);
|
|
19536
19645
|
}
|
|
19537
19646
|
});
|
|
19538
|
-
var workspacesRevision = (contents) =>
|
|
19647
|
+
var workspacesRevision = (contents) => createHash7("sha256").update(contents ?? "<missing>").digest("hex");
|
|
19539
19648
|
var validateWorkspacesDocument = (parsed, file) => {
|
|
19540
19649
|
if (!isConfigObject(parsed)) {
|
|
19541
19650
|
return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
|
|
@@ -19573,7 +19682,7 @@ var validateWorkspacesDocument = (parsed, file) => {
|
|
|
19573
19682
|
};
|
|
19574
19683
|
};
|
|
19575
19684
|
var readWorkspacesResult = (dir = configDir()) => {
|
|
19576
|
-
const file =
|
|
19685
|
+
const file = path12.join(dir, "workspaces.json");
|
|
19577
19686
|
let raw;
|
|
19578
19687
|
try {
|
|
19579
19688
|
raw = readFileSync3(file, "utf8");
|
|
@@ -19684,9 +19793,9 @@ var mainCheckoutOf = (cwd) => {
|
|
|
19684
19793
|
let main = null;
|
|
19685
19794
|
const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
|
|
19686
19795
|
const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
|
|
19687
|
-
if (gitDir && common &&
|
|
19796
|
+
if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
|
|
19688
19797
|
const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
|
|
19689
|
-
main = listed?.trim() || (
|
|
19798
|
+
main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
|
|
19690
19799
|
}
|
|
19691
19800
|
mainCheckouts.set(cwd, main);
|
|
19692
19801
|
return main;
|
|
@@ -19777,7 +19886,7 @@ var runtimeWorkspaceIndexSchema = object({
|
|
|
19777
19886
|
workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
19778
19887
|
}).passthrough();
|
|
19779
19888
|
var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
|
|
19780
|
-
const file =
|
|
19889
|
+
const file = path12.join(dir, "workspaces.json");
|
|
19781
19890
|
let raw;
|
|
19782
19891
|
try {
|
|
19783
19892
|
raw = readFileSync3(file, "utf8");
|
|
@@ -19812,6 +19921,17 @@ var resolveRuntimeReleaseTracks = (cwd) => {
|
|
|
19812
19921
|
const matched = matchRuntimeWorkspace(cwd);
|
|
19813
19922
|
return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
|
|
19814
19923
|
};
|
|
19924
|
+
var TIER_KEYS = new Set(["mundane", "standard", "hard"]);
|
|
19925
|
+
var TIER_HOSTS = new Set([
|
|
19926
|
+
"claude_code",
|
|
19927
|
+
"opencode",
|
|
19928
|
+
"codex",
|
|
19929
|
+
"codex_cli",
|
|
19930
|
+
"codex_desktop",
|
|
19931
|
+
"cursor",
|
|
19932
|
+
"pi",
|
|
19933
|
+
"default"
|
|
19934
|
+
]);
|
|
19815
19935
|
var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
|
|
19816
19936
|
const matched = matchRuntimeWorkspace(cwd);
|
|
19817
19937
|
if (!matched)
|
|
@@ -19852,7 +19972,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
|
|
|
19852
19972
|
}
|
|
19853
19973
|
|
|
19854
19974
|
// packages/workit-core/src/core/release-tracks.ts
|
|
19855
|
-
import { createHash as
|
|
19975
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
19856
19976
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
19857
19977
|
var KNOWN_FIELDS = new Set([
|
|
19858
19978
|
"strategy",
|
|
@@ -20222,7 +20342,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
20222
20342
|
]) ?? "",
|
|
20223
20343
|
git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
|
|
20224
20344
|
] : [];
|
|
20225
|
-
key =
|
|
20345
|
+
key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
|
|
20226
20346
|
const hit = memo2.get(key);
|
|
20227
20347
|
if (hit)
|
|
20228
20348
|
return hit;
|
|
@@ -20237,7 +20357,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
20237
20357
|
}
|
|
20238
20358
|
|
|
20239
20359
|
// packages/workit-core/src/core/vcs-config.ts
|
|
20240
|
-
var workspacesPath = () =>
|
|
20360
|
+
var workspacesPath = () => path13.join(configDir(), "workspaces.json");
|
|
20241
20361
|
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
20242
20362
|
var remoteProvider = (cwd) => {
|
|
20243
20363
|
const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
@@ -20327,7 +20447,7 @@ var readVcsConfig = () => {
|
|
|
20327
20447
|
const file = vcsConfigPath();
|
|
20328
20448
|
let raw;
|
|
20329
20449
|
try {
|
|
20330
|
-
raw =
|
|
20450
|
+
raw = fs11.readFileSync(file, "utf8");
|
|
20331
20451
|
} catch {
|
|
20332
20452
|
return { status: "missing", path: file, config: {} };
|
|
20333
20453
|
}
|
|
@@ -20412,7 +20532,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
20412
20532
|
const prov = cfg[provider] ?? {};
|
|
20413
20533
|
const out = {
|
|
20414
20534
|
ok: true,
|
|
20415
|
-
configPath:
|
|
20535
|
+
configPath: path13.resolve(cfgPath),
|
|
20416
20536
|
provider,
|
|
20417
20537
|
defaultTargetBranch: workspaceDefault,
|
|
20418
20538
|
pr: cfg.pr ?? {},
|
|
@@ -20623,7 +20743,7 @@ function diffHash(cwd, base, head) {
|
|
|
20623
20743
|
], GIT_TIMEOUTS.worktree);
|
|
20624
20744
|
if (!diff.ok || !diff.stdout)
|
|
20625
20745
|
return null;
|
|
20626
|
-
const hash =
|
|
20746
|
+
const hash = createHash9("sha256");
|
|
20627
20747
|
for (const line of diff.stdout.split(`
|
|
20628
20748
|
`)) {
|
|
20629
20749
|
if (line.startsWith("index "))
|
|
@@ -20635,16 +20755,16 @@ function diffHash(cwd, base, head) {
|
|
|
20635
20755
|
return `sha256:${hash.digest("hex")}`;
|
|
20636
20756
|
}
|
|
20637
20757
|
function storeRoot(cwd) {
|
|
20638
|
-
const location = resolveStore(
|
|
20758
|
+
const location = resolveStore(path14.resolve(cwd));
|
|
20639
20759
|
if (location instanceof Error)
|
|
20640
20760
|
return err("unavailable", location.message.replace(/; fix the repository.*$/u, ""), "fix the repository (git status should work here) or run from a non-git directory");
|
|
20641
20761
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
20642
20762
|
}
|
|
20643
20763
|
function ledgerPath(cwd) {
|
|
20644
20764
|
const root = storeRoot(cwd);
|
|
20645
|
-
return root.ok ? { ok: true, value:
|
|
20765
|
+
return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
20646
20766
|
}
|
|
20647
|
-
var newId2 = () => `${Date.now().toString(36)}-${
|
|
20767
|
+
var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
|
|
20648
20768
|
var NETWORK_FS_TYPES = new Set([
|
|
20649
20769
|
26985,
|
|
20650
20770
|
20859,
|
|
@@ -20662,7 +20782,7 @@ var onNetworkFs = (dir) => {
|
|
|
20662
20782
|
if (process.platform !== "linux")
|
|
20663
20783
|
return false;
|
|
20664
20784
|
try {
|
|
20665
|
-
return isNetworkFsType(
|
|
20785
|
+
return isNetworkFsType(fs12.statfsSync(dir).type);
|
|
20666
20786
|
} catch {
|
|
20667
20787
|
return false;
|
|
20668
20788
|
}
|
|
@@ -20672,15 +20792,15 @@ var LOCK_STALE_MS = 30000;
|
|
|
20672
20792
|
var LOCK_OWNER = "owner";
|
|
20673
20793
|
var lockToken = (lock) => {
|
|
20674
20794
|
try {
|
|
20675
|
-
return
|
|
20795
|
+
return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
|
|
20676
20796
|
} catch {
|
|
20677
20797
|
return null;
|
|
20678
20798
|
}
|
|
20679
20799
|
};
|
|
20680
20800
|
var lockAgeMs = (lock) => {
|
|
20681
|
-
for (const target of [
|
|
20801
|
+
for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
|
|
20682
20802
|
try {
|
|
20683
|
-
return Date.now() -
|
|
20803
|
+
return Date.now() - fs12.statSync(target).mtimeMs;
|
|
20684
20804
|
} catch {}
|
|
20685
20805
|
}
|
|
20686
20806
|
return null;
|
|
@@ -20688,55 +20808,55 @@ var lockAgeMs = (lock) => {
|
|
|
20688
20808
|
var ledgerLock = {
|
|
20689
20809
|
acquire(lock) {
|
|
20690
20810
|
try {
|
|
20691
|
-
|
|
20811
|
+
fs12.mkdirSync(lock);
|
|
20692
20812
|
} catch (error) {
|
|
20693
20813
|
if (error.code === "EEXIST")
|
|
20694
20814
|
return null;
|
|
20695
20815
|
throw error;
|
|
20696
20816
|
}
|
|
20697
|
-
const token = `${process.pid}-${
|
|
20698
|
-
|
|
20817
|
+
const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
|
|
20818
|
+
fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
|
|
20699
20819
|
return token;
|
|
20700
20820
|
},
|
|
20701
20821
|
release(lock, token) {
|
|
20702
20822
|
if (lockToken(lock) !== token)
|
|
20703
20823
|
return false;
|
|
20704
|
-
const tomb = `${lock}.release-${
|
|
20824
|
+
const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
|
|
20705
20825
|
try {
|
|
20706
|
-
|
|
20826
|
+
fs12.renameSync(lock, tomb);
|
|
20707
20827
|
} catch {
|
|
20708
20828
|
return false;
|
|
20709
20829
|
}
|
|
20710
20830
|
if (lockToken(tomb) !== token) {
|
|
20711
20831
|
try {
|
|
20712
|
-
|
|
20832
|
+
fs12.renameSync(tomb, lock);
|
|
20713
20833
|
} catch {}
|
|
20714
20834
|
return false;
|
|
20715
20835
|
}
|
|
20716
|
-
|
|
20836
|
+
fs12.rmSync(tomb, { recursive: true, force: true });
|
|
20717
20837
|
return true;
|
|
20718
20838
|
},
|
|
20719
20839
|
token: lockToken,
|
|
20720
20840
|
reap(lock, observed) {
|
|
20721
|
-
const tomb = `${lock}.reap-${
|
|
20841
|
+
const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
|
|
20722
20842
|
try {
|
|
20723
|
-
|
|
20843
|
+
fs12.renameSync(lock, tomb);
|
|
20724
20844
|
} catch {
|
|
20725
20845
|
return false;
|
|
20726
20846
|
}
|
|
20727
20847
|
if (lockToken(tomb) === observed) {
|
|
20728
|
-
|
|
20848
|
+
fs12.rmSync(tomb, { recursive: true, force: true });
|
|
20729
20849
|
return true;
|
|
20730
20850
|
}
|
|
20731
20851
|
try {
|
|
20732
|
-
|
|
20852
|
+
fs12.renameSync(tomb, lock);
|
|
20733
20853
|
} catch {
|
|
20734
|
-
|
|
20854
|
+
fs12.rmSync(tomb, { recursive: true, force: true });
|
|
20735
20855
|
}
|
|
20736
20856
|
return false;
|
|
20737
20857
|
}
|
|
20738
20858
|
};
|
|
20739
|
-
function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
20859
|
+
function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
|
|
20740
20860
|
const lock = `${file}.lock`;
|
|
20741
20861
|
const deadline = Date.now() + waitMs;
|
|
20742
20862
|
let token = null;
|
|
@@ -20758,14 +20878,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
|
20758
20878
|
ledgerLock.release(lock, token);
|
|
20759
20879
|
}
|
|
20760
20880
|
}
|
|
20761
|
-
var sha2562 = (text) =>
|
|
20881
|
+
var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
|
|
20762
20882
|
var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
20763
20883
|
${body}`);
|
|
20764
20884
|
var TAIL_BYTES = 64 * 1024;
|
|
20765
20885
|
var lastLine = (fd, size) => {
|
|
20766
20886
|
for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
|
|
20767
20887
|
const buffer = Buffer.alloc(span);
|
|
20768
|
-
|
|
20888
|
+
fs12.readSync(fd, buffer, 0, span, size - span);
|
|
20769
20889
|
const end = buffer.lastIndexOf(10);
|
|
20770
20890
|
if (end < 0) {
|
|
20771
20891
|
if (span === size)
|
|
@@ -20794,15 +20914,23 @@ var lastLine = (fd, size) => {
|
|
|
20794
20914
|
}
|
|
20795
20915
|
return null;
|
|
20796
20916
|
};
|
|
20917
|
+
var tighten = (fd) => {
|
|
20918
|
+
try {
|
|
20919
|
+
if ((fs12.fstatSync(fd).mode & 63) !== 0)
|
|
20920
|
+
fs12.fchmodSync(fd, 384);
|
|
20921
|
+
} catch {}
|
|
20922
|
+
};
|
|
20797
20923
|
function appendLine(file, build, options) {
|
|
20798
20924
|
const write = () => {
|
|
20799
|
-
const fd =
|
|
20925
|
+
const fd = fs12.openSync(file, "a+", 384);
|
|
20800
20926
|
try {
|
|
20801
|
-
|
|
20927
|
+
if (process.platform !== "win32")
|
|
20928
|
+
tighten(fd);
|
|
20929
|
+
const size = fs12.fstatSync(fd).size;
|
|
20802
20930
|
let fence = "";
|
|
20803
20931
|
if (size > 0) {
|
|
20804
20932
|
const last = Buffer.alloc(1);
|
|
20805
|
-
|
|
20933
|
+
fs12.readSync(fd, last, 0, 1, size - 1);
|
|
20806
20934
|
if (last[0] !== 10)
|
|
20807
20935
|
fence = `
|
|
20808
20936
|
`;
|
|
@@ -20811,17 +20939,17 @@ function appendLine(file, build, options) {
|
|
|
20811
20939
|
if (!line.ok)
|
|
20812
20940
|
return line;
|
|
20813
20941
|
const bytes = Buffer.from(fence + line.value);
|
|
20814
|
-
const written =
|
|
20942
|
+
const written = fs12.writeSync(fd, bytes);
|
|
20815
20943
|
if (written !== bytes.length)
|
|
20816
20944
|
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
20817
20945
|
return { ok: true, value: undefined };
|
|
20818
20946
|
} finally {
|
|
20819
|
-
|
|
20947
|
+
fs12.closeSync(fd);
|
|
20820
20948
|
}
|
|
20821
20949
|
};
|
|
20822
20950
|
try {
|
|
20823
|
-
|
|
20824
|
-
if (!options.forceLock && !onNetworkFs(
|
|
20951
|
+
fs12.mkdirSync(path14.dirname(file), { recursive: true });
|
|
20952
|
+
if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
|
|
20825
20953
|
return write();
|
|
20826
20954
|
const locked = withLedgerLock(file, write);
|
|
20827
20955
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -20889,8 +21017,10 @@ function readLedger(cwd, options = {}) {
|
|
|
20889
21017
|
if (!file.ok)
|
|
20890
21018
|
return file;
|
|
20891
21019
|
let text = "";
|
|
21020
|
+
let stat = null;
|
|
20892
21021
|
try {
|
|
20893
|
-
|
|
21022
|
+
stat = fs12.statSync(file.value);
|
|
21023
|
+
text = fs12.readFileSync(file.value, "utf8");
|
|
20894
21024
|
} catch (error) {
|
|
20895
21025
|
if (error.code === "ENOENT")
|
|
20896
21026
|
return {
|
|
@@ -20909,6 +21039,7 @@ function readLedger(cwd, options = {}) {
|
|
|
20909
21039
|
const integrity = { chained: 0, legacy: 0, unverified: [] };
|
|
20910
21040
|
const earlier = new Set([null]);
|
|
20911
21041
|
let chainStarted = false;
|
|
21042
|
+
const ids = new Set;
|
|
20912
21043
|
for (const raw of text.split(`
|
|
20913
21044
|
`)) {
|
|
20914
21045
|
const trimmed = raw.trim();
|
|
@@ -20942,6 +21073,10 @@ function readLedger(cwd, options = {}) {
|
|
|
20942
21073
|
reason = "unsigned";
|
|
20943
21074
|
else
|
|
20944
21075
|
rowIntegrity = "legacy";
|
|
21076
|
+
if (options.integrity && !reason && ids.has(parsed.id))
|
|
21077
|
+
reason = "duplicate_id";
|
|
21078
|
+
if (options.integrity)
|
|
21079
|
+
ids.add(parsed.id);
|
|
20945
21080
|
if (reason)
|
|
20946
21081
|
rowIntegrity = "unverified";
|
|
20947
21082
|
const pr = typeof parsed.pr === "number" && Number.isInteger(parsed.pr) ? parsed.pr : undefined;
|
|
@@ -20965,7 +21100,8 @@ function readLedger(cwd, options = {}) {
|
|
|
20965
21100
|
seq: rows.length + 1,
|
|
20966
21101
|
superseded: false,
|
|
20967
21102
|
supersedeIgnored: false,
|
|
20968
|
-
...rowIntegrity ? { integrity: rowIntegrity } : {}
|
|
21103
|
+
...rowIntegrity ? { integrity: rowIntegrity } : {},
|
|
21104
|
+
...reason ? { integrityReason: reason } : {}
|
|
20969
21105
|
};
|
|
20970
21106
|
rows.push(row);
|
|
20971
21107
|
if (!options.integrity)
|
|
@@ -20993,18 +21129,48 @@ function readLedger(cwd, options = {}) {
|
|
|
20993
21129
|
const byId = new Map;
|
|
20994
21130
|
for (const row of rows) {
|
|
20995
21131
|
const target = row.supersedes ? byId.get(row.supersedes) : undefined;
|
|
20996
|
-
if (target && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
|
|
21132
|
+
if (target && row.integrity !== "unverified" && supersedeAllowed(row, target, renameAwareBranch(scopeOf, row.branch)) === null)
|
|
20997
21133
|
target.superseded = true;
|
|
20998
21134
|
else if (row.supersedes)
|
|
20999
21135
|
row.supersedeIgnored = true;
|
|
21000
21136
|
if (!byId.has(row.id))
|
|
21001
21137
|
byId.set(row.id, row);
|
|
21002
21138
|
}
|
|
21139
|
+
if (options.integrity && stat && Buffer.byteLength(text) === stat.size)
|
|
21140
|
+
tamperCache.set(file.value, {
|
|
21141
|
+
size: stat.size,
|
|
21142
|
+
stamp: fileStamp(stat),
|
|
21143
|
+
breaks: integrity.unverified.filter((row) => TAMPER_REASONS.has(row.reason))
|
|
21144
|
+
});
|
|
21003
21145
|
return {
|
|
21004
21146
|
ok: true,
|
|
21005
21147
|
value: { path: file.value, rows, skipped, integrity: options.integrity ? integrity : null }
|
|
21006
21148
|
};
|
|
21007
21149
|
}
|
|
21150
|
+
var TAMPER_REASONS = new Set(["hash_mismatch", "broken_link"]);
|
|
21151
|
+
var tamperCache = new Map;
|
|
21152
|
+
var fileStamp = (stat) => `${stat.ino}:${stat.mtimeMs}:${stat.ctimeMs}`;
|
|
21153
|
+
function ledgerTampering(cwd) {
|
|
21154
|
+
const file = ledgerPath(cwd);
|
|
21155
|
+
if (!file.ok)
|
|
21156
|
+
return [];
|
|
21157
|
+
try {
|
|
21158
|
+
const stat = fs12.statSync(file.value);
|
|
21159
|
+
const cached = tamperCache.get(file.value);
|
|
21160
|
+
if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
|
|
21161
|
+
return cached.breaks;
|
|
21162
|
+
} catch {
|
|
21163
|
+
return [];
|
|
21164
|
+
}
|
|
21165
|
+
const read = readLedger(cwd, { integrity: true });
|
|
21166
|
+
return read.ok ? (read.value.integrity?.unverified ?? []).filter((row) => TAMPER_REASONS.has(row.reason)) : [];
|
|
21167
|
+
}
|
|
21168
|
+
function tamperedUnblock(cwd) {
|
|
21169
|
+
const file = ledgerPath(cwd);
|
|
21170
|
+
const where = file.ok ? file.value : "the ledger file";
|
|
21171
|
+
return `workit ledger verify-integrity # lists the edited or missing rows; if the edit is understood, move ${where} aside (mv ${where} ${where}.tampered-<date>) and record the verdicts again`;
|
|
21172
|
+
}
|
|
21173
|
+
var tamperedWarning = (cwd, breaks) => `the ledger was edited, or a row was removed or moved (${breaks.slice(0, 3).map((row) => `${row.reason} at row ${row.seq}`).join(", ")}${breaks.length > 3 ? ", …" : ""}): no verdict is accepted until it is repaired. ${tamperedUnblock(cwd)}`;
|
|
21008
21174
|
function verdictBasis(verdict, current) {
|
|
21009
21175
|
if (verdict.head && verdict.head === current.head)
|
|
21010
21176
|
return "fresh";
|
|
@@ -21012,7 +21178,7 @@ function verdictBasis(verdict, current) {
|
|
|
21012
21178
|
return "carried";
|
|
21013
21179
|
return "stale";
|
|
21014
21180
|
}
|
|
21015
|
-
var isLiveVerdict = (row) => row.type === "verdict" && typeof row.result === "string" && !row.
|
|
21181
|
+
var isLiveVerdict = (row, retired) => row.type === "verdict" && typeof row.result === "string" && !retired.has(row.id);
|
|
21016
21182
|
function trailerSessions(cwd, base, head) {
|
|
21017
21183
|
if (!base || !head || !safeRef(base) || !safeRef(head))
|
|
21018
21184
|
return [];
|
|
@@ -21093,6 +21259,56 @@ var authoredBy = (authors, session) => {
|
|
|
21093
21259
|
return true;
|
|
21094
21260
|
return false;
|
|
21095
21261
|
};
|
|
21262
|
+
var TRUST_REASONS = new Set([
|
|
21263
|
+
"unsigned",
|
|
21264
|
+
"hash_mismatch",
|
|
21265
|
+
"broken_link",
|
|
21266
|
+
"duplicate_id",
|
|
21267
|
+
"unissued_session",
|
|
21268
|
+
"unbound_session"
|
|
21269
|
+
]);
|
|
21270
|
+
var SHELL_VOUCHED_HOSTS = new Set([
|
|
21271
|
+
"cli",
|
|
21272
|
+
"opencode",
|
|
21273
|
+
"pi",
|
|
21274
|
+
"codex_cli",
|
|
21275
|
+
"codex_desktop"
|
|
21276
|
+
]);
|
|
21277
|
+
function sessionTrust(cwd, row) {
|
|
21278
|
+
const session = row.actor.session;
|
|
21279
|
+
if (!session || row.self === true)
|
|
21280
|
+
return null;
|
|
21281
|
+
const source = typeof row.sessionSource === "string" ? row.sessionSource : "env";
|
|
21282
|
+
const host = row.actor.host;
|
|
21283
|
+
const issuedOnly = source === "flag" ? host !== "cli" : source === "env" && session.includes(":") && !SHELL_VOUCHED_HOSTS.has(host);
|
|
21284
|
+
if (!issuedOnly)
|
|
21285
|
+
return null;
|
|
21286
|
+
const binding = issuedBinding(cwd, session);
|
|
21287
|
+
if (binding === null)
|
|
21288
|
+
return "unissued_session";
|
|
21289
|
+
return binding === "token" && row.sessionBound !== true ? "unbound_session" : null;
|
|
21290
|
+
}
|
|
21291
|
+
function trustReasons(cwd, row) {
|
|
21292
|
+
if (row.integrity === "unverified")
|
|
21293
|
+
return [row.integrityReason ?? "unsigned"];
|
|
21294
|
+
if (row.integrity !== "verified")
|
|
21295
|
+
return ["unsigned"];
|
|
21296
|
+
const session = sessionTrust(cwd, row);
|
|
21297
|
+
return session ? [session] : [];
|
|
21298
|
+
}
|
|
21299
|
+
function withIntegrity(cwd, rows) {
|
|
21300
|
+
if (rows.every((row) => row.integrity !== undefined))
|
|
21301
|
+
return rows;
|
|
21302
|
+
const read = readLedger(cwd, { integrity: true });
|
|
21303
|
+
const bySeq = new Map(read.ok ? read.value.rows.map((row) => [row.seq, row]) : []);
|
|
21304
|
+
return rows.map((row) => {
|
|
21305
|
+
if (row.integrity !== undefined)
|
|
21306
|
+
return row;
|
|
21307
|
+
const fresh = bySeq.get(row.seq);
|
|
21308
|
+
return fresh && fresh.id === row.id && fresh.at === row.at ? fresh : row;
|
|
21309
|
+
});
|
|
21310
|
+
}
|
|
21311
|
+
var untrusted = (reasons) => reasons.some((reason) => TRUST_REASONS.has(reason));
|
|
21096
21312
|
var independenceReasons = (row, authors) => {
|
|
21097
21313
|
const reasons = [];
|
|
21098
21314
|
if (!row.actor.session)
|
|
@@ -21103,15 +21319,17 @@ var independenceReasons = (row, authors) => {
|
|
|
21103
21319
|
reasons.push("self");
|
|
21104
21320
|
return reasons;
|
|
21105
21321
|
};
|
|
21106
|
-
function effectiveOf(rows,
|
|
21322
|
+
function effectiveOf(rows, reasonsOf, sameCode, isCurrent) {
|
|
21107
21323
|
let effective = null;
|
|
21108
21324
|
for (const row of rows) {
|
|
21109
21325
|
if (!effective) {
|
|
21110
21326
|
effective = row;
|
|
21111
21327
|
continue;
|
|
21112
21328
|
}
|
|
21113
|
-
|
|
21114
|
-
|
|
21329
|
+
if (untrusted(reasonsOf(row)) && !untrusted(reasonsOf(effective)))
|
|
21330
|
+
continue;
|
|
21331
|
+
const rowIndependent = reasonsOf(row).length === 0;
|
|
21332
|
+
const effIndependent = reasonsOf(effective).length === 0;
|
|
21115
21333
|
if (effIndependent && !rowIndependent && isCurrent(effective))
|
|
21116
21334
|
continue;
|
|
21117
21335
|
if (effIndependent && FAILING.has(String(effective.result)) && row.actor.session === effective.actor.session && sameCode(effective, row))
|
|
@@ -21125,7 +21343,7 @@ function restackCarries(rows, branch, from, to) {
|
|
|
21125
21343
|
return false;
|
|
21126
21344
|
const edges = new Map;
|
|
21127
21345
|
for (const row of rows)
|
|
21128
|
-
if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
|
|
21346
|
+
if (row.type === "stack.restacked" && row.observer === "workit_cli" && row.integrity === "verified" && row.branch === branch && row.patchEqual === true && typeof row.fromHead === "string" && row.head)
|
|
21129
21347
|
edges.set(row.fromHead, [...edges.get(row.fromHead) ?? [], row.head]);
|
|
21130
21348
|
const seen = new Set([from]);
|
|
21131
21349
|
const queue = [from];
|
|
@@ -21141,7 +21359,8 @@ function restackCarries(rows, branch, from, to) {
|
|
|
21141
21359
|
}
|
|
21142
21360
|
return false;
|
|
21143
21361
|
}
|
|
21144
|
-
function checkVerdicts(cwd, branch,
|
|
21362
|
+
function checkVerdicts(cwd, branch, ledgerRows) {
|
|
21363
|
+
const rows = withIntegrity(cwd, ledgerRows);
|
|
21145
21364
|
const head = branchHead(cwd, branch);
|
|
21146
21365
|
const fallbackBase = defaultBase(cwd);
|
|
21147
21366
|
const scope = branchScope(cwd, branch);
|
|
@@ -21171,21 +21390,47 @@ function checkVerdicts(cwd, branch, rows) {
|
|
|
21171
21390
|
return verdictBasis(failed, { head: row.head, ...keys }) !== "stale" || restackCarries(rows, branch, failed.head, row.head);
|
|
21172
21391
|
};
|
|
21173
21392
|
const authors = authorSessions(cwd, rows, branch, { base: fallbackBase, head }, scope);
|
|
21393
|
+
const failureAuthorCache = new Map;
|
|
21394
|
+
const failureAuthors = (row) => {
|
|
21395
|
+
let set = failureAuthorCache.get(row.seq);
|
|
21396
|
+
if (!set) {
|
|
21397
|
+
set = authorSessions(cwd, rows.filter((other) => other.integrity === "verified" && other.seq < row.seq), branch, { base: null, head: null }, scope);
|
|
21398
|
+
failureAuthorCache.set(row.seq, set);
|
|
21399
|
+
}
|
|
21400
|
+
return set;
|
|
21401
|
+
};
|
|
21402
|
+
const reasonCache = new Map;
|
|
21403
|
+
const reasonsOf = (row) => {
|
|
21404
|
+
let reasons = reasonCache.get(row);
|
|
21405
|
+
if (!reasons) {
|
|
21406
|
+
const failing = FAILING.has(String(row.result));
|
|
21407
|
+
reasons = [
|
|
21408
|
+
...trustReasons(cwd, row),
|
|
21409
|
+
...independenceReasons(row, failing ? failureAuthors(row) : authors)
|
|
21410
|
+
];
|
|
21411
|
+
reasonCache.set(row, reasons);
|
|
21412
|
+
}
|
|
21413
|
+
return reasons;
|
|
21414
|
+
};
|
|
21415
|
+
const retired = new Set;
|
|
21416
|
+
for (const row of rows)
|
|
21417
|
+
if (row.type === "verdict" && row.supersedes && !row.supersedeIgnored && trustReasons(cwd, row).length === 0)
|
|
21418
|
+
retired.add(row.supersedes);
|
|
21174
21419
|
const byKind = new Map;
|
|
21175
21420
|
for (const row of rows)
|
|
21176
|
-
if (isLiveVerdict(row) && scope(row)) {
|
|
21421
|
+
if (isLiveVerdict(row, retired) && scope(row)) {
|
|
21177
21422
|
const kind = typeof row.kind === "string" ? row.kind : "review";
|
|
21178
21423
|
byKind.set(kind, [...byKind.get(kind) ?? [], row]);
|
|
21179
21424
|
}
|
|
21180
21425
|
const verdicts = [];
|
|
21181
21426
|
const warnings = [];
|
|
21182
21427
|
for (const [kind, list] of byKind) {
|
|
21183
|
-
const row = effectiveOf(list,
|
|
21428
|
+
const row = effectiveOf(list, reasonsOf, sameCode, (candidate) => basisOf(candidate) !== "stale");
|
|
21184
21429
|
if (!row)
|
|
21185
21430
|
continue;
|
|
21186
21431
|
const basis = basisOf(row);
|
|
21187
21432
|
const current = basis !== "stale";
|
|
21188
|
-
const independence =
|
|
21433
|
+
const independence = reasonsOf(row);
|
|
21189
21434
|
const reasons = [
|
|
21190
21435
|
...current ? [] : ["stale"],
|
|
21191
21436
|
...PASSING.has(String(row.result)) ? [] : ["not_passing"],
|
|
@@ -21202,23 +21447,31 @@ function checkVerdicts(cwd, branch, rows) {
|
|
|
21202
21447
|
});
|
|
21203
21448
|
if (reasons.length === 0) {
|
|
21204
21449
|
for (const later of list)
|
|
21205
|
-
if (later.seq > row.seq &&
|
|
21450
|
+
if (later.seq > row.seq && reasonsOf(later).length > 0 && !untrusted(reasonsOf(later)) && FAILING.has(String(later.result)) && basisOf(later) !== "stale")
|
|
21206
21451
|
warnings.push(`the author's own (self) ${String(later.result)} ${kind} verdict ${later.id} by ${later.actor.session ?? "no session"} on the current code is newer than the accepted pass ${row.id}: read it before merging`);
|
|
21207
21452
|
}
|
|
21208
21453
|
}
|
|
21209
21454
|
for (const row of rows)
|
|
21210
21455
|
if (row.integrity === "unverified" && scope(row))
|
|
21211
21456
|
warnings.push(`ledger row ${row.id} (${row.type}) on ${row.branch ?? branch} is unverified: the workit CLI did not write it or it changed afterwards (workit ledger verify-integrity)`);
|
|
21457
|
+
const tampered = ledgerTampering(cwd);
|
|
21458
|
+
if (tampered.length) {
|
|
21459
|
+
warnings.push(tamperedWarning(cwd, tampered));
|
|
21460
|
+
for (const entry of verdicts) {
|
|
21461
|
+
entry.accepted = false;
|
|
21462
|
+
entry.reasons = [...entry.reasons, "ledger_tampered"];
|
|
21463
|
+
}
|
|
21464
|
+
}
|
|
21212
21465
|
verdicts.sort((a, b) => a.verdict.seq - b.verdict.seq);
|
|
21213
21466
|
const newestCurrent = verdicts.findLast((entry) => entry.current) ?? verdicts.at(-1) ?? null;
|
|
21214
21467
|
const failing = verdicts.find((entry) => entry.current && entry.independent && FAILING.has(String(entry.verdict.result)));
|
|
21215
21468
|
const newestAccepted = verdicts.findLast((entry) => entry.accepted && STRONG_RESULTS.has(String(entry.verdict.result))) ?? null;
|
|
21216
|
-
const accepted = newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
|
|
21469
|
+
const accepted = tampered.length ? { accepted: false, verdict: null, reasons: ["ledger_tampered"] } : newestAccepted && !failing ? { accepted: true, verdict: newestAccepted.verdict, reasons: [] } : {
|
|
21217
21470
|
accepted: false,
|
|
21218
21471
|
verdict: failing?.verdict ?? null,
|
|
21219
21472
|
reasons: failing ? ["failing_verdict"] : !newestCurrent ? ["no_verdict"] : newestCurrent.reasons.length ? newestCurrent.reasons : ["type_check_only"]
|
|
21220
21473
|
};
|
|
21221
|
-
const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && STRONG_RESULTS.has(String(entry.verdict.result)));
|
|
21474
|
+
const selfEntry = failing ? undefined : verdicts.findLast((entry) => entry.current && !entry.independent && !untrusted(entry.reasons) && STRONG_RESULTS.has(String(entry.verdict.result)));
|
|
21222
21475
|
return {
|
|
21223
21476
|
branch,
|
|
21224
21477
|
head,
|
|
@@ -21381,7 +21634,7 @@ var productDecision = (task, ledger) => {
|
|
|
21381
21634
|
};
|
|
21382
21635
|
};
|
|
21383
21636
|
var planRecorded = (task, root) => {
|
|
21384
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(
|
|
21637
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
|
|
21385
21638
|
if (cited)
|
|
21386
21639
|
return {
|
|
21387
21640
|
met: true,
|
|
@@ -21429,15 +21682,15 @@ function derivedRuleStatus(task, requirement, root, ledger) {
|
|
|
21429
21682
|
}
|
|
21430
21683
|
|
|
21431
21684
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
21432
|
-
var digestBytes = (value) =>
|
|
21433
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
21434
|
-
var relative = (root, candidate) =>
|
|
21685
|
+
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
21686
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
|
|
21687
|
+
var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
|
|
21435
21688
|
var canonicalPath = (value) => {
|
|
21436
21689
|
if (typeof value !== "string" || !value)
|
|
21437
21690
|
return null;
|
|
21438
21691
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
21439
21692
|
return null;
|
|
21440
|
-
const normalized =
|
|
21693
|
+
const normalized = path16.posix.normalize(value);
|
|
21441
21694
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
21442
21695
|
return null;
|
|
21443
21696
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -21485,21 +21738,21 @@ var gitPaths = (root) => {
|
|
|
21485
21738
|
git: !/not a git repository/i.test(stderr)
|
|
21486
21739
|
};
|
|
21487
21740
|
}
|
|
21488
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
21741
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
|
|
21489
21742
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
21490
21743
|
if (stagedDeleted.status !== 0) {
|
|
21491
21744
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
21492
21745
|
if (!/not a git repository/i.test(stderr))
|
|
21493
21746
|
return { paths, uncertain: true, git: true };
|
|
21494
21747
|
} else if (stagedDeleted.stdout) {
|
|
21495
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
21748
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
|
|
21496
21749
|
}
|
|
21497
21750
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
21498
21751
|
};
|
|
21499
21752
|
var walk = (root, directory, output) => {
|
|
21500
21753
|
let names;
|
|
21501
21754
|
try {
|
|
21502
|
-
names =
|
|
21755
|
+
names = fs13.readdirSync(directory);
|
|
21503
21756
|
} catch {
|
|
21504
21757
|
return true;
|
|
21505
21758
|
}
|
|
@@ -21507,10 +21760,10 @@ var walk = (root, directory, output) => {
|
|
|
21507
21760
|
for (const name of names) {
|
|
21508
21761
|
if (name === ".git" || name === ".workit")
|
|
21509
21762
|
continue;
|
|
21510
|
-
const target =
|
|
21763
|
+
const target = path16.join(directory, name);
|
|
21511
21764
|
let stat;
|
|
21512
21765
|
try {
|
|
21513
|
-
stat =
|
|
21766
|
+
stat = fs13.lstatSync(target);
|
|
21514
21767
|
} catch {
|
|
21515
21768
|
uncertain = true;
|
|
21516
21769
|
continue;
|
|
@@ -21525,14 +21778,14 @@ var walk = (root, directory, output) => {
|
|
|
21525
21778
|
var scopeRoots = (root, scope) => {
|
|
21526
21779
|
const roots = [];
|
|
21527
21780
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
21528
|
-
const target =
|
|
21781
|
+
const target = path16.resolve(root, item);
|
|
21529
21782
|
if (!inside(root, target))
|
|
21530
21783
|
return failure2("invalid_input", `candidate scope escapes checkout: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} is outside the checkout` }] });
|
|
21531
21784
|
let ancestor = target;
|
|
21532
|
-
while (!
|
|
21533
|
-
ancestor =
|
|
21785
|
+
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
21786
|
+
ancestor = path16.dirname(ancestor);
|
|
21534
21787
|
try {
|
|
21535
|
-
if (!inside(root,
|
|
21788
|
+
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
21536
21789
|
return failure2("invalid_input", `candidate scope escapes checkout through a symlink: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} resolves outside the checkout` }] });
|
|
21537
21790
|
} catch {
|
|
21538
21791
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -21544,7 +21797,7 @@ var scopeRoots = (root, scope) => {
|
|
|
21544
21797
|
function captureCandidate(root, scope, environment = []) {
|
|
21545
21798
|
let checkout;
|
|
21546
21799
|
try {
|
|
21547
|
-
checkout =
|
|
21800
|
+
checkout = fs13.realpathSync(root);
|
|
21548
21801
|
} catch {
|
|
21549
21802
|
return failure2("invalid_input", "candidate root does not exist");
|
|
21550
21803
|
}
|
|
@@ -21562,11 +21815,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
21562
21815
|
if (item === ".git" || item === ".workit")
|
|
21563
21816
|
continue;
|
|
21564
21817
|
names.add(item);
|
|
21565
|
-
if (!
|
|
21818
|
+
if (!fs13.existsSync(target))
|
|
21566
21819
|
continue;
|
|
21567
21820
|
let stat;
|
|
21568
21821
|
try {
|
|
21569
|
-
stat =
|
|
21822
|
+
stat = fs13.lstatSync(target);
|
|
21570
21823
|
} catch {
|
|
21571
21824
|
uncertain = true;
|
|
21572
21825
|
continue;
|
|
@@ -21582,17 +21835,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
21582
21835
|
for (const item of [...names].toSorted()) {
|
|
21583
21836
|
if (!scopeMatches(item, normalizedScope))
|
|
21584
21837
|
continue;
|
|
21585
|
-
const target =
|
|
21838
|
+
const target = path16.join(checkout, item);
|
|
21586
21839
|
try {
|
|
21587
|
-
const stat =
|
|
21840
|
+
const stat = fs13.lstatSync(target);
|
|
21588
21841
|
if (stat.isSymbolicLink()) {
|
|
21589
|
-
const link =
|
|
21842
|
+
const link = fs13.readlinkSync(target);
|
|
21590
21843
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
21591
21844
|
} else if (stat.isFile()) {
|
|
21592
21845
|
files.push({
|
|
21593
21846
|
path: item,
|
|
21594
21847
|
kind: "file",
|
|
21595
|
-
digest: digestBytes(
|
|
21848
|
+
digest: digestBytes(fs13.readFileSync(target)),
|
|
21596
21849
|
executable: (stat.mode & 73) !== 0
|
|
21597
21850
|
});
|
|
21598
21851
|
} else if (!stat.isDirectory()) {
|
|
@@ -21757,7 +22010,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
|
|
|
21757
22010
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
21758
22011
|
let root;
|
|
21759
22012
|
try {
|
|
21760
|
-
root =
|
|
22013
|
+
root = fs13.realpathSync(checkoutRoot);
|
|
21761
22014
|
} catch {
|
|
21762
22015
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
21763
22016
|
}
|
|
@@ -21766,23 +22019,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
21766
22019
|
continue;
|
|
21767
22020
|
if (!reference.digest)
|
|
21768
22021
|
return failure2("invalid_input", "document references require a byte digest");
|
|
21769
|
-
const target =
|
|
21770
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
22022
|
+
const target = path16.resolve(root, reference.path);
|
|
22023
|
+
if (target !== root && !target.startsWith(`${root}${path16.sep}`))
|
|
21771
22024
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
21772
22025
|
fields: [
|
|
21773
22026
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
21774
22027
|
]
|
|
21775
22028
|
});
|
|
21776
22029
|
try {
|
|
21777
|
-
const below =
|
|
22030
|
+
const below = path16.relative(root, target);
|
|
21778
22031
|
let current = root;
|
|
21779
|
-
for (const segment of below.split(
|
|
22032
|
+
for (const segment of below.split(path16.sep)) {
|
|
21780
22033
|
if (!segment)
|
|
21781
22034
|
continue;
|
|
21782
|
-
current =
|
|
21783
|
-
const stat =
|
|
21784
|
-
const real =
|
|
21785
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
22035
|
+
current = path16.join(current, segment);
|
|
22036
|
+
const stat = fs13.lstatSync(current);
|
|
22037
|
+
const real = fs13.realpathSync(current);
|
|
22038
|
+
if (real !== root && !real.startsWith(`${root}${path16.sep}`))
|
|
21786
22039
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
21787
22040
|
fields: [
|
|
21788
22041
|
{
|
|
@@ -21798,7 +22051,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
21798
22051
|
if (current !== target && !stat.isDirectory())
|
|
21799
22052
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
21800
22053
|
}
|
|
21801
|
-
if (digestBytes(
|
|
22054
|
+
if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
|
|
21802
22055
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
21803
22056
|
} catch {
|
|
21804
22057
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -22656,7 +22909,7 @@ var judgeInputSummary = (raw) => {
|
|
|
22656
22909
|
|
|
22657
22910
|
// packages/workit-core/src/autonomy.ts
|
|
22658
22911
|
import os4 from "node:os";
|
|
22659
|
-
import
|
|
22912
|
+
import path17 from "node:path";
|
|
22660
22913
|
var accountHome = () => {
|
|
22661
22914
|
try {
|
|
22662
22915
|
return os4.userInfo().homedir;
|
|
@@ -22665,10 +22918,10 @@ var accountHome = () => {
|
|
|
22665
22918
|
}
|
|
22666
22919
|
};
|
|
22667
22920
|
var grantsHome = { resolve: accountHome };
|
|
22668
|
-
var grantsDir = () =>
|
|
22921
|
+
var grantsDir = () => path17.join(grantsHome.resolve(), ".config", "workit");
|
|
22669
22922
|
var grantsOverride = () => {
|
|
22670
|
-
const configured =
|
|
22671
|
-
return configured ===
|
|
22923
|
+
const configured = path17.resolve(resolveConfigDir());
|
|
22924
|
+
return configured === path17.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path17.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
22672
22925
|
};
|
|
22673
22926
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
22674
22927
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -24440,7 +24693,7 @@ class WorkitCore {
|
|
|
24440
24693
|
// packages/workit-core/src/core/repo-context.ts
|
|
24441
24694
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
24442
24695
|
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
|
|
24443
|
-
import
|
|
24696
|
+
import path18 from "node:path";
|
|
24444
24697
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
24445
24698
|
try {
|
|
24446
24699
|
gitRevisionParts(value);
|
|
@@ -24574,7 +24827,7 @@ var findPrTemplate = (cwd) => {
|
|
|
24574
24827
|
]) {
|
|
24575
24828
|
const parts = rel.split("/");
|
|
24576
24829
|
const base = parts[parts.length - 1];
|
|
24577
|
-
const dir = parts.length > 1 ?
|
|
24830
|
+
const dir = parts.length > 1 ? path18.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
24578
24831
|
const actual = probeCaseInsensitive(dir, base);
|
|
24579
24832
|
if (actual)
|
|
24580
24833
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -24605,7 +24858,7 @@ var diffStatForRange = (cwd, range) => {
|
|
|
24605
24858
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
24606
24859
|
};
|
|
24607
24860
|
var packageScripts = (cwd, keys) => {
|
|
24608
|
-
const pkgPath =
|
|
24861
|
+
const pkgPath = path18.join(cwd, "package.json");
|
|
24609
24862
|
if (!existsSync6(pkgPath))
|
|
24610
24863
|
return [];
|
|
24611
24864
|
try {
|
|
@@ -24631,9 +24884,9 @@ var documentationFiles = (cwd) => {
|
|
|
24631
24884
|
if (entry.isDirectory()) {
|
|
24632
24885
|
if (excluded.has(entry.name))
|
|
24633
24886
|
continue;
|
|
24634
|
-
walk(
|
|
24887
|
+
walk(path18.join(dir, entry.name), depth + 1);
|
|
24635
24888
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
24636
|
-
matches.push("./" +
|
|
24889
|
+
matches.push("./" + path18.relative(cwd, path18.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
24637
24890
|
}
|
|
24638
24891
|
}
|
|
24639
24892
|
};
|
|
@@ -24649,7 +24902,7 @@ var readTrimmed2 = (file, maxLines) => {
|
|
|
24649
24902
|
`);
|
|
24650
24903
|
};
|
|
24651
24904
|
function prReadyContext(root, range) {
|
|
24652
|
-
const cwd =
|
|
24905
|
+
const cwd = path18.resolve(repoRoot(root));
|
|
24653
24906
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
24654
24907
|
return invalidRange(cwd);
|
|
24655
24908
|
let stdout = "";
|
|
@@ -24707,7 +24960,7 @@ ${status.stderr}` : "");
|
|
|
24707
24960
|
stdout += `template_path: ${template}
|
|
24708
24961
|
|
|
24709
24962
|
`;
|
|
24710
|
-
stdout += readTrimmed2(
|
|
24963
|
+
stdout += readTrimmed2(path18.join(cwd, template), 220);
|
|
24711
24964
|
} else {
|
|
24712
24965
|
stdout += `template_path: none
|
|
24713
24966
|
|
|
@@ -24717,7 +24970,7 @@ ${status.stderr}` : "");
|
|
|
24717
24970
|
stdout += `
|
|
24718
24971
|
`;
|
|
24719
24972
|
stdout += printSection("Recent Validation Signals");
|
|
24720
|
-
if (existsSync6(
|
|
24973
|
+
if (existsSync6(path18.join(cwd, "package.json"))) {
|
|
24721
24974
|
stdout += `package.json detected. Common scripts:
|
|
24722
24975
|
`;
|
|
24723
24976
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -24726,7 +24979,7 @@ ${status.stderr}` : "");
|
|
|
24726
24979
|
`) + `
|
|
24727
24980
|
`;
|
|
24728
24981
|
}
|
|
24729
|
-
if (existsSync6(
|
|
24982
|
+
if (existsSync6(path18.join(cwd, "Cargo.toml")) || existsSync6(path18.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
24730
24983
|
stdout += `Rust project detected.
|
|
24731
24984
|
`;
|
|
24732
24985
|
}
|
|
@@ -24759,7 +25012,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
24759
25012
|
- Apply with the host-native editor, preserving the repository changelog conventions.
|
|
24760
25013
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
24761
25014
|
function changelogContext(root, range) {
|
|
24762
|
-
const cwd =
|
|
25015
|
+
const cwd = path18.resolve(repoRoot(root));
|
|
24763
25016
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
24764
25017
|
return invalidRange(cwd);
|
|
24765
25018
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -24777,7 +25030,7 @@ function changelogContext(root, range) {
|
|
|
24777
25030
|
stdout += CHANGELOG_RULES + `
|
|
24778
25031
|
`;
|
|
24779
25032
|
stdout += printSection("Existing CHANGELOG.md");
|
|
24780
|
-
const changelogPath =
|
|
25033
|
+
const changelogPath = path18.join(cwd, "CHANGELOG.md");
|
|
24781
25034
|
if (existsSync6(changelogPath)) {
|
|
24782
25035
|
stdout += readTrimmed2(changelogPath, 260) + `
|
|
24783
25036
|
`;
|
|
@@ -24797,7 +25050,7 @@ function changelogContext(root, range) {
|
|
|
24797
25050
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
24798
25051
|
}
|
|
24799
25052
|
function docsRefreshContext(root, range) {
|
|
24800
|
-
const cwd =
|
|
25053
|
+
const cwd = path18.resolve(repoRoot(root));
|
|
24801
25054
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
24802
25055
|
return invalidRange(cwd);
|
|
24803
25056
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -24819,7 +25072,7 @@ function docsRefreshContext(root, range) {
|
|
|
24819
25072
|
`) + `
|
|
24820
25073
|
`;
|
|
24821
25074
|
stdout += printSection("README Preview");
|
|
24822
|
-
const readme =
|
|
25075
|
+
const readme = path18.join(cwd, "README.md");
|
|
24823
25076
|
if (existsSync6(readme)) {
|
|
24824
25077
|
stdout += readTrimmed2(readme, 220) + `
|
|
24825
25078
|
`;
|
|
@@ -24828,7 +25081,7 @@ function docsRefreshContext(root, range) {
|
|
|
24828
25081
|
`;
|
|
24829
25082
|
}
|
|
24830
25083
|
stdout += printSection("Package Scripts");
|
|
24831
|
-
const pkgPath =
|
|
25084
|
+
const pkgPath = path18.join(cwd, "package.json");
|
|
24832
25085
|
if (existsSync6(pkgPath)) {
|
|
24833
25086
|
try {
|
|
24834
25087
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
@@ -24842,7 +25095,7 @@ function docsRefreshContext(root, range) {
|
|
|
24842
25095
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
24843
25096
|
}
|
|
24844
25097
|
function releaseNotesContext(root, rangeOrTag) {
|
|
24845
|
-
const cwd =
|
|
25098
|
+
const cwd = path18.resolve(repoRoot(root));
|
|
24846
25099
|
if (!rangeOrTag) {
|
|
24847
25100
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
24848
25101
|
`, exitCode: 1, cwd };
|
|
@@ -24880,7 +25133,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
24880
25133
|
`;
|
|
24881
25134
|
stdout += printSection("Existing Release Files");
|
|
24882
25135
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
24883
|
-
if (existsSync6(
|
|
25136
|
+
if (existsSync6(path18.join(cwd, rel)))
|
|
24884
25137
|
stdout += rel + `
|
|
24885
25138
|
`;
|
|
24886
25139
|
}
|
|
@@ -24911,8 +25164,8 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
24911
25164
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
24912
25165
|
|
|
24913
25166
|
// packages/workit-core/src/core/pr-create.ts
|
|
24914
|
-
import
|
|
24915
|
-
import
|
|
25167
|
+
import fs14 from "node:fs";
|
|
25168
|
+
import path19 from "node:path";
|
|
24916
25169
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
24917
25170
|
// packages/workit-core/src/forge/pr-body.ts
|
|
24918
25171
|
function parseGhIssue(value) {
|
|
@@ -24923,13 +25176,13 @@ function parseGhIssue(value) {
|
|
|
24923
25176
|
// packages/workit-core/src/core/pr-create.ts
|
|
24924
25177
|
function whichOnPath(tool) {
|
|
24925
25178
|
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
24926
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
25179
|
+
for (const dir of (process.env.PATH ?? "").split(path19.delimiter)) {
|
|
24927
25180
|
if (!dir)
|
|
24928
25181
|
continue;
|
|
24929
25182
|
for (const name of names) {
|
|
24930
|
-
const candidate =
|
|
25183
|
+
const candidate = path19.join(dir, name);
|
|
24931
25184
|
try {
|
|
24932
|
-
|
|
25185
|
+
fs14.accessSync(candidate, fs14.constants.X_OK);
|
|
24933
25186
|
return candidate;
|
|
24934
25187
|
} catch {}
|
|
24935
25188
|
}
|
|
@@ -25047,8 +25300,8 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
|
25047
25300
|
};
|
|
25048
25301
|
|
|
25049
25302
|
// packages/workit-core/src/core/youtrack.ts
|
|
25050
|
-
import
|
|
25051
|
-
import
|
|
25303
|
+
import fs15 from "node:fs";
|
|
25304
|
+
import path20 from "node:path";
|
|
25052
25305
|
|
|
25053
25306
|
// packages/workit-core/src/core/templates.ts
|
|
25054
25307
|
var repoRoot2 = assetRoot();
|
|
@@ -25061,22 +25314,22 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
25061
25314
|
// packages/workit-core/src/core/youtrack.ts
|
|
25062
25315
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
25063
25316
|
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
25064
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
25065
|
-
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
25317
|
+
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(configDir(), "youtrack.json");
|
|
25318
|
+
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path20.join(resolveConfigDir(), "youtrack.json");
|
|
25066
25319
|
var youTrackTokenModeOk = (p) => {
|
|
25067
25320
|
if (process.platform === "win32")
|
|
25068
25321
|
return true;
|
|
25069
|
-
const mode =
|
|
25322
|
+
const mode = fs15.statSync(p).mode & 511;
|
|
25070
25323
|
return mode === 384;
|
|
25071
25324
|
};
|
|
25072
25325
|
function readYouTrackConfig(required) {
|
|
25073
25326
|
const cfgPath = youTrackConfigPath();
|
|
25074
|
-
if (!
|
|
25327
|
+
if (!fs15.existsSync(cfgPath)) {
|
|
25075
25328
|
return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
|
|
25076
25329
|
}
|
|
25077
25330
|
let parsed;
|
|
25078
25331
|
try {
|
|
25079
|
-
parsed = JSON.parse(
|
|
25332
|
+
parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
|
|
25080
25333
|
} catch {
|
|
25081
25334
|
return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
|
|
25082
25335
|
}
|
|
@@ -25087,11 +25340,11 @@ function readYouTrackConfig(required) {
|
|
|
25087
25340
|
}
|
|
25088
25341
|
var readYouTrackContextConfig = () => {
|
|
25089
25342
|
const cfgPath = youTrackReadOnlyConfigPath();
|
|
25090
|
-
if (!
|
|
25343
|
+
if (!fs15.existsSync(cfgPath))
|
|
25091
25344
|
return { data: {} };
|
|
25092
25345
|
let parsed;
|
|
25093
25346
|
try {
|
|
25094
|
-
parsed = JSON.parse(
|
|
25347
|
+
parsed = JSON.parse(fs15.readFileSync(cfgPath, "utf8"));
|
|
25095
25348
|
} catch {
|
|
25096
25349
|
return { error: "YouTrack configuration is unavailable" };
|
|
25097
25350
|
}
|
|
@@ -25130,12 +25383,12 @@ var youTrackToken = () => {
|
|
|
25130
25383
|
if ("error" in loaded)
|
|
25131
25384
|
return loaded;
|
|
25132
25385
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
25133
|
-
const tokenPath = tokenFile ?
|
|
25134
|
-
if (!tokenPath || !
|
|
25386
|
+
const tokenPath = tokenFile ? path20.isAbsolute(tokenFile) ? path20.resolve(tokenFile) : path20.resolve(process.cwd(), tokenFile) : "";
|
|
25387
|
+
if (!tokenPath || !fs15.existsSync(tokenPath))
|
|
25135
25388
|
return { error: "missing youtrack.token" };
|
|
25136
25389
|
if (!youTrackTokenModeOk(tokenPath))
|
|
25137
25390
|
return { error: "youtrack.token mode must be 0600" };
|
|
25138
|
-
const token =
|
|
25391
|
+
const token = fs15.readFileSync(tokenPath, "utf8").trim();
|
|
25139
25392
|
if (!token)
|
|
25140
25393
|
return { error: "empty token file" };
|
|
25141
25394
|
if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
|
|
@@ -25200,9 +25453,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
|
|
|
25200
25453
|
} catch {
|
|
25201
25454
|
continue;
|
|
25202
25455
|
}
|
|
25203
|
-
if (!
|
|
25456
|
+
if (!fs15.existsSync(full))
|
|
25204
25457
|
continue;
|
|
25205
|
-
const text =
|
|
25458
|
+
const text = fs15.readFileSync(full, "utf8");
|
|
25206
25459
|
const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
|
|
25207
25460
|
if (m)
|
|
25208
25461
|
return m[1];
|
|
@@ -25472,15 +25725,15 @@ function resolveGitRevision(root, value) {
|
|
|
25472
25725
|
}
|
|
25473
25726
|
function resolveInside(root, candidate) {
|
|
25474
25727
|
const base = realpathSync5(root);
|
|
25475
|
-
const target =
|
|
25476
|
-
if (target !== base && !target.startsWith(base +
|
|
25728
|
+
const target = path21.resolve(base, candidate);
|
|
25729
|
+
if (target !== base && !target.startsWith(base + path21.sep)) {
|
|
25477
25730
|
throw new Error("path must stay inside repository root");
|
|
25478
25731
|
}
|
|
25479
25732
|
let ancestor = target;
|
|
25480
25733
|
while (!existsSync7(ancestor))
|
|
25481
|
-
ancestor =
|
|
25734
|
+
ancestor = path21.dirname(ancestor);
|
|
25482
25735
|
const canonicalAncestor = realpathSync5(ancestor);
|
|
25483
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
25736
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path21.sep)) {
|
|
25484
25737
|
throw new Error("path must stay inside repository root");
|
|
25485
25738
|
}
|
|
25486
25739
|
return target;
|
|
@@ -25512,7 +25765,7 @@ var SUPPORT_MATRIX = {
|
|
|
25512
25765
|
|
|
25513
25766
|
// packages/workit-mcp/src/server.ts
|
|
25514
25767
|
import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync6 } from "node:fs";
|
|
25515
|
-
import
|
|
25768
|
+
import path22 from "node:path";
|
|
25516
25769
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
25517
25770
|
function isZ4Schema(s) {
|
|
25518
25771
|
const schema = s;
|
|
@@ -27926,13 +28179,13 @@ var rootVariants = (workspaceRoot) => {
|
|
|
27926
28179
|
if (!workspaceRoot)
|
|
27927
28180
|
return [];
|
|
27928
28181
|
const roots = new Set;
|
|
27929
|
-
for (const candidate of [workspaceRoot,
|
|
27930
|
-
if (
|
|
28182
|
+
for (const candidate of [workspaceRoot, path22.resolve(workspaceRoot)]) {
|
|
28183
|
+
if (path22.isAbsolute(candidate) && candidate !== path22.parse(candidate).root)
|
|
27931
28184
|
roots.add(candidate);
|
|
27932
28185
|
}
|
|
27933
28186
|
try {
|
|
27934
28187
|
const canonical = realpathSync6(workspaceRoot);
|
|
27935
|
-
if (canonical !==
|
|
28188
|
+
if (canonical !== path22.parse(canonical).root)
|
|
27936
28189
|
roots.add(canonical);
|
|
27937
28190
|
} catch {}
|
|
27938
28191
|
return [...roots].toSorted((left, right) => right.length - left.length);
|
|
@@ -28014,11 +28267,11 @@ var thrownResult = (tool, error, workspaceRoot) => {
|
|
|
28014
28267
|
};
|
|
28015
28268
|
function createMcpServer(host, contextProvider) {
|
|
28016
28269
|
assertMcpHost(host);
|
|
28017
|
-
const here =
|
|
28270
|
+
const here = path22.dirname(fileURLToPath2(import.meta.url));
|
|
28018
28271
|
const sourceMarker = markSourcesLoaded([
|
|
28019
|
-
|
|
28020
|
-
|
|
28021
|
-
|
|
28272
|
+
path22.join(here, "server.ts"),
|
|
28273
|
+
path22.join(here, "..", "..", "workit-core", "src", "core", "task-contract.ts"),
|
|
28274
|
+
path22.join(here, "..", "..", "workit-core", "src", "core", "task-engine.ts")
|
|
28022
28275
|
].filter((file) => existsSync8(file)));
|
|
28023
28276
|
let staleWarned = false;
|
|
28024
28277
|
const server = new Server({ name: "workit", version: VERSION }, { capabilities: { tools: {}, resources: {} } });
|
|
@@ -28211,10 +28464,44 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
28211
28464
|
var signals = new Map;
|
|
28212
28465
|
var cache = new Map;
|
|
28213
28466
|
var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
28467
|
+
// packages/workit-core/src/core/live-session.ts
|
|
28468
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
28469
|
+
var LIVE_SESSION_TTL_MS = 15 * 60000;
|
|
28470
|
+
var liveProbe = {
|
|
28471
|
+
platform: process.platform,
|
|
28472
|
+
run: (args) => spawnSync15("ps", args, { encoding: "utf8", timeout: 2000 }).stdout ?? "",
|
|
28473
|
+
start: (pid) => processStartOf(pid)
|
|
28474
|
+
};
|
|
28475
|
+
var PIDS = new Map;
|
|
28476
|
+
|
|
28214
28477
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
28215
28478
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
28216
28479
|
var PREFIXES2 = new Set(["sudo", "command", "env", "nohup", "time", "exec", "xargs"]);
|
|
28217
28480
|
var cache2 = new Map;
|
|
28481
|
+
var MUTATING_GIT = new Set([
|
|
28482
|
+
"add",
|
|
28483
|
+
"am",
|
|
28484
|
+
"apply",
|
|
28485
|
+
"checkout",
|
|
28486
|
+
"cherry-pick",
|
|
28487
|
+
"clean",
|
|
28488
|
+
"commit",
|
|
28489
|
+
"merge",
|
|
28490
|
+
"mv",
|
|
28491
|
+
"pull",
|
|
28492
|
+
"rebase",
|
|
28493
|
+
"reset",
|
|
28494
|
+
"restore",
|
|
28495
|
+
"revert",
|
|
28496
|
+
"rm",
|
|
28497
|
+
"stash",
|
|
28498
|
+
"switch"
|
|
28499
|
+
]);
|
|
28500
|
+
var DRY_N = new Set(["add", "clean", "rm", "mv"]);
|
|
28501
|
+
var MUTATING_WORKIT_GIT = new Set(["commit", "branch"]);
|
|
28502
|
+
var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
28503
|
+
var PUSHD2 = new Set(["pushd", "push-location"]);
|
|
28504
|
+
var POPD2 = new Set(["popd", "pop-location"]);
|
|
28218
28505
|
// packages/workit-core/src/core/skill-manifests.ts
|
|
28219
28506
|
if (false) {}
|
|
28220
28507
|
|
|
@@ -28401,14 +28688,14 @@ import {
|
|
|
28401
28688
|
writeFileSync as writeFileSync3
|
|
28402
28689
|
} from "node:fs";
|
|
28403
28690
|
import os5 from "node:os";
|
|
28404
|
-
import
|
|
28691
|
+
import path23 from "node:path";
|
|
28405
28692
|
var CODEX_AGENT_MARKER = "# Generated by Workit";
|
|
28406
28693
|
var codexHomeOfInstall = (pluginRoot) => {
|
|
28407
|
-
const parts =
|
|
28694
|
+
const parts = path23.resolve(pluginRoot).split(path23.sep);
|
|
28408
28695
|
const cache = parts.length - 4;
|
|
28409
|
-
return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(
|
|
28696
|
+
return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path23.sep) || path23.sep : null;
|
|
28410
28697
|
};
|
|
28411
|
-
var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME ||
|
|
28698
|
+
var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path23.join(env.HOME || os5.homedir(), ".codex"));
|
|
28412
28699
|
var MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
28413
28700
|
var agentMarkerVersion = (text) => MARKER_VERSION.exec(text)?.[1] ?? null;
|
|
28414
28701
|
var stampCodexAgent = (content, version) => version && content.startsWith(CODEX_AGENT_MARKER) && !agentMarkerVersion(content) ? `${CODEX_AGENT_MARKER} ${version}${content.slice(CODEX_AGENT_MARKER.length)}` : content;
|
|
@@ -28422,7 +28709,7 @@ var versionAtLeast = (version, min) => {
|
|
|
28422
28709
|
};
|
|
28423
28710
|
var pluginVersion = (pluginRoot) => {
|
|
28424
28711
|
try {
|
|
28425
|
-
const version = JSON.parse(readFileSync7(
|
|
28712
|
+
const version = JSON.parse(readFileSync7(path23.join(pluginRoot, "package.json"), "utf8")).version;
|
|
28426
28713
|
return typeof version === "string" && /^\d+\.\d+\.\d+/.test(version) ? version.match(/^\d+\.\d+\.\d+/)[0] : null;
|
|
28427
28714
|
} catch {
|
|
28428
28715
|
return null;
|
|
@@ -28436,15 +28723,15 @@ var lstatOrNull = (file) => {
|
|
|
28436
28723
|
}
|
|
28437
28724
|
};
|
|
28438
28725
|
var installCodexAgents = (pluginRoot, codexHome) => {
|
|
28439
|
-
const source =
|
|
28726
|
+
const source = path23.join(pluginRoot, "agents");
|
|
28440
28727
|
if (!existsSync9(source))
|
|
28441
28728
|
return [];
|
|
28442
28729
|
const version = pluginVersion(pluginRoot);
|
|
28443
|
-
const target =
|
|
28730
|
+
const target = path23.join(codexHome, "agents");
|
|
28444
28731
|
const results = [];
|
|
28445
28732
|
for (const file of readdirSync5(source).filter((name) => name.endsWith(".toml")).toSorted()) {
|
|
28446
|
-
const content = stampCodexAgent(readFileSync7(
|
|
28447
|
-
const dest =
|
|
28733
|
+
const content = stampCodexAgent(readFileSync7(path23.join(source, file), "utf8"), version);
|
|
28734
|
+
const dest = path23.join(target, file);
|
|
28448
28735
|
const stat = lstatOrNull(dest);
|
|
28449
28736
|
if (stat?.isSymbolicLink()) {
|
|
28450
28737
|
results.push({ file: dest, action: "skipped-symlink" });
|
|
@@ -28480,7 +28767,7 @@ var installCodexAgents = (pluginRoot, codexHome) => {
|
|
|
28480
28767
|
results.push({ file: dest, action: "kept-newer-version" });
|
|
28481
28768
|
continue;
|
|
28482
28769
|
}
|
|
28483
|
-
const temp =
|
|
28770
|
+
const temp = path23.join(target, `.${file}.${process.pid}.${Date.now()}.tmp`);
|
|
28484
28771
|
writeFileSync3(temp, content, { flag: "wx" });
|
|
28485
28772
|
try {
|
|
28486
28773
|
renameSync2(temp, dest);
|
|
@@ -28502,8 +28789,8 @@ var codexQualification = (host) => host === "codex_cli" ? { surface: host, cli:
|
|
|
28502
28789
|
var resolveCodexWorkspaceRoot = (pluginRoot, env) => {
|
|
28503
28790
|
const explicit = env.WORKFLOW_WORKSPACE_ROOT;
|
|
28504
28791
|
const inherited = env.PWD;
|
|
28505
|
-
const candidate = explicit ?? (inherited &&
|
|
28506
|
-
if (!candidate || !
|
|
28792
|
+
const candidate = explicit ?? (inherited && path24.resolve(inherited) !== path24.resolve(pluginRoot) ? inherited : undefined);
|
|
28793
|
+
if (!candidate || !path24.isAbsolute(candidate) || !existsSync10(candidate))
|
|
28507
28794
|
return null;
|
|
28508
28795
|
try {
|
|
28509
28796
|
if (!statSync3(candidate).isDirectory())
|
|
@@ -28542,7 +28829,7 @@ var codexContextProvider = (host = detectCodexSurface(process.env), root) => ({
|
|
|
28542
28829
|
};
|
|
28543
28830
|
}
|
|
28544
28831
|
});
|
|
28545
|
-
var pluginRoot = () =>
|
|
28832
|
+
var pluginRoot = () => path24.resolve(path24.dirname(fileURLToPath3(import.meta.url)), "..");
|
|
28546
28833
|
var syncCodexAgents = (root) => {
|
|
28547
28834
|
const codexHome = codexHomeOfInstall(root);
|
|
28548
28835
|
if (!codexHome)
|