@brainervirus/workit-cli 8.8.0 → 8.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1145 -601
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@brainervirus/workit-cli",
|
|
68
|
-
version: "8.
|
|
68
|
+
version: "8.9.1",
|
|
69
69
|
private: false,
|
|
70
70
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
71
71
|
keywords: [
|
|
@@ -103,9 +103,9 @@ var init_package = __esm(() => {
|
|
|
103
103
|
},
|
|
104
104
|
dependencies: {
|
|
105
105
|
"@babel/parser": "7.29.9",
|
|
106
|
-
"@brainervirus/workit-core": "^8.
|
|
107
|
-
"@brainervirus/workit-cursor": "^8.
|
|
108
|
-
"@brainervirus/workit-opencode": "^8.
|
|
106
|
+
"@brainervirus/workit-core": "^8.9.1",
|
|
107
|
+
"@brainervirus/workit-cursor": "^8.9.1",
|
|
108
|
+
"@brainervirus/workit-opencode": "^8.9.1",
|
|
109
109
|
"@inkjs/ui": "2.0.0",
|
|
110
110
|
ink: "7.1.1",
|
|
111
111
|
react: "19.2.8"
|
|
@@ -11079,6 +11079,66 @@ class TaskStore {
|
|
|
11079
11079
|
return bound;
|
|
11080
11080
|
return success(null, null, { key: key.data, bound: bound.data });
|
|
11081
11081
|
}
|
|
11082
|
+
taskForWorker(workerId) {
|
|
11083
|
+
if (typeof workerId !== "string" || !validId(workerId))
|
|
11084
|
+
return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
|
|
11085
|
+
const listed = this.listTaskIndex();
|
|
11086
|
+
if (!listed.ok)
|
|
11087
|
+
return listed;
|
|
11088
|
+
for (const entry of listed.data) {
|
|
11089
|
+
if (entry.status === "closed")
|
|
11090
|
+
continue;
|
|
11091
|
+
const loaded = this.load(entry.id);
|
|
11092
|
+
if (!loaded.ok)
|
|
11093
|
+
return loaded;
|
|
11094
|
+
if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
|
|
11095
|
+
return success(null, null, entry.id);
|
|
11096
|
+
}
|
|
11097
|
+
return success(null, null, null);
|
|
11098
|
+
}
|
|
11099
|
+
originTaskEntry() {
|
|
11100
|
+
const key = this.currentKey();
|
|
11101
|
+
const location = this.location();
|
|
11102
|
+
const branch = key.ok ? key.data.branch : null;
|
|
11103
|
+
if (!branch || !location.ok)
|
|
11104
|
+
return success(null, null, null);
|
|
11105
|
+
const common = path8.dirname(location.data.dir);
|
|
11106
|
+
const heads = path8.join(common, "logs", "refs", "heads");
|
|
11107
|
+
const headLog = location.data.git ? path8.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
11108
|
+
const signatures = [
|
|
11109
|
+
path8.join(heads, branch),
|
|
11110
|
+
headLog,
|
|
11111
|
+
heads,
|
|
11112
|
+
path8.join(common, "packed-refs")
|
|
11113
|
+
].map((file) => fileSignature(file) ?? "-");
|
|
11114
|
+
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
11115
|
+
let resolved = origins.get(slot);
|
|
11116
|
+
if (resolved?.signature !== signatures.join("|")) {
|
|
11117
|
+
const renames = branchRenames(location.data);
|
|
11118
|
+
const aliases = [branch];
|
|
11119
|
+
for (const rename of renames.toReversed())
|
|
11120
|
+
if (rename.to === aliases.at(-1))
|
|
11121
|
+
aliases.push(rename.from);
|
|
11122
|
+
const start = branchStart(location.data, branch, aliases);
|
|
11123
|
+
const slash = start?.indexOf("/") ?? -1;
|
|
11124
|
+
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)}"]`));
|
|
11125
|
+
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
11126
|
+
resolved = {
|
|
11127
|
+
signature: signatures.join("|"),
|
|
11128
|
+
name: name && !aliases.includes(name) ? name : null,
|
|
11129
|
+
renames
|
|
11130
|
+
};
|
|
11131
|
+
origins.set(slot, resolved);
|
|
11132
|
+
}
|
|
11133
|
+
const entry = resolved.name ? this.openTasksForKey(resolved.name, resolved.renames) : null;
|
|
11134
|
+
if (entry && !entry.ok)
|
|
11135
|
+
return entry;
|
|
11136
|
+
return success(null, null, entry?.data[0] ? { origin: `branch ${resolved.name}`, entry: entry.data[0] } : null);
|
|
11137
|
+
}
|
|
11138
|
+
readStoreTask(taskId) {
|
|
11139
|
+
const loaded = this.load(taskId);
|
|
11140
|
+
return loaded.ok ? success(null, null, loaded.data?.record ?? null) : loaded;
|
|
11141
|
+
}
|
|
11082
11142
|
create(input, provenance, expectedWorkspaceRevision) {
|
|
11083
11143
|
const value = "intent" in input ? input : {
|
|
11084
11144
|
intent: input,
|
|
@@ -11748,12 +11808,12 @@ class TaskStore {
|
|
|
11748
11808
|
return 0;
|
|
11749
11809
|
}
|
|
11750
11810
|
}
|
|
11751
|
-
openTasksForKey(key) {
|
|
11811
|
+
openTasksForKey(key, known) {
|
|
11752
11812
|
const all = this.listStoreIndex();
|
|
11753
11813
|
if (!all.ok)
|
|
11754
11814
|
return all;
|
|
11755
|
-
const location = this.location();
|
|
11756
|
-
const renames = location
|
|
11815
|
+
const location = known ? null : this.location();
|
|
11816
|
+
const renames = known ?? (location?.ok ? branchRenames(location.data) : []);
|
|
11757
11817
|
return success(null, null, all.data.filter((entry) => entry.key !== null && entry.status !== "closed").filter((entry) => (renames.length ? followRenames(entry.key, entry.boundAt ?? entry.createdAt, renames) : entry.key) === key).toSorted(oldestFirst));
|
|
11758
11818
|
}
|
|
11759
11819
|
openTaskForKey(key) {
|
|
@@ -12440,7 +12500,34 @@ var MIGRATION_PENDING = "workit migration pending", STORE_FORMAT = 3, STORE_MIN_
|
|
|
12440
12500
|
return left > right;
|
|
12441
12501
|
}
|
|
12442
12502
|
return false;
|
|
12443
|
-
}, 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),
|
|
12503
|
+
}, 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), readText = (file) => {
|
|
12504
|
+
try {
|
|
12505
|
+
return fs8.readFileSync(file, "utf8");
|
|
12506
|
+
} catch {
|
|
12507
|
+
return "";
|
|
12508
|
+
}
|
|
12509
|
+
}, REFLOG_LINE, branchStart = (location, branch, aliases) => {
|
|
12510
|
+
const first = readText(path8.join(path8.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
12511
|
+
`, 1)[0];
|
|
12512
|
+
const created = REFLOG_LINE.exec(first);
|
|
12513
|
+
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
12514
|
+
if (!created || !start)
|
|
12515
|
+
return null;
|
|
12516
|
+
if (start !== "HEAD")
|
|
12517
|
+
return start;
|
|
12518
|
+
if (!location.git)
|
|
12519
|
+
return null;
|
|
12520
|
+
for (const line of readText(path8.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
12521
|
+
`)) {
|
|
12522
|
+
const entry = REFLOG_LINE.exec(line);
|
|
12523
|
+
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
12524
|
+
const seconds = entry ? Number(entry[2]) - Number(created[2]) : -1;
|
|
12525
|
+
if (moved && entry[1] === created[1] && seconds >= 0 && seconds <= 1 && aliases.includes(moved[2]))
|
|
12526
|
+
return moved[1];
|
|
12527
|
+
}
|
|
12528
|
+
return null;
|
|
12529
|
+
}, refExists = (common, ref) => fs8.existsSync(path8.join(common, ref)) || readText(path8.join(common, "packed-refs")).includes(` ${ref}
|
|
12530
|
+
`), origins, sameDirectoryIdentity = (left, right) => {
|
|
12444
12531
|
if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
|
|
12445
12532
|
return false;
|
|
12446
12533
|
const normalizedLeft = path8.resolve(left);
|
|
@@ -12488,6 +12575,8 @@ var init_task_store = __esm(() => {
|
|
|
12488
12575
|
AUTO_COMPACT_BYTES = 2 * 1024 * 1024;
|
|
12489
12576
|
TOMBSTONE = Symbol("tombstone");
|
|
12490
12577
|
STALE_TEMPORARY_MS = 60 * 60000;
|
|
12578
|
+
REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
12579
|
+
origins = new Map;
|
|
12491
12580
|
heldInProcess = new Map;
|
|
12492
12581
|
});
|
|
12493
12582
|
|
|
@@ -16442,38 +16531,29 @@ function reconcileResume(view, observations = []) {
|
|
|
16442
16531
|
reassessmentRequired: view.task.policy?.policyVersion !== POLICY_VERSION
|
|
16443
16532
|
});
|
|
16444
16533
|
}
|
|
16445
|
-
function compactTaskContext(view) {
|
|
16446
|
-
const decisions =
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
|
|
16452
|
-
}).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
|
|
16453
|
-
id: entry.id,
|
|
16454
|
-
purpose: entry.data.purpose,
|
|
16455
|
-
status: entry.data.response,
|
|
16456
|
-
digest: entry.data.digest,
|
|
16457
|
-
choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
|
|
16458
|
-
references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
|
|
16459
|
-
}));
|
|
16460
|
-
const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
|
|
16534
|
+
function compactTaskContext(view, inherited = null) {
|
|
16535
|
+
const decisions = compactDecisions([
|
|
16536
|
+
view && { origin: null, taskId: view.task.id, decisions: view.task.decisions },
|
|
16537
|
+
inherited
|
|
16538
|
+
]);
|
|
16539
|
+
const methods = view?.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
|
|
16461
16540
|
id: method.id,
|
|
16462
16541
|
assurance: method.assurance,
|
|
16463
16542
|
reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
|
|
16464
16543
|
})) : [];
|
|
16544
|
+
const stale = view?.evidence.filter((entry) => entry.status === "stale").length;
|
|
16465
16545
|
const gaps = Array.from(new Set([
|
|
16466
|
-
...
|
|
16467
|
-
...view
|
|
16468
|
-
...view
|
|
16546
|
+
...stale ? [`stale evidence: ${stale}; workit task inspect --task ${view.task.id} --view full`] : [],
|
|
16547
|
+
...(view?.requirements ?? []).filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
|
|
16548
|
+
...(view?.task.progress.blockers ?? []).map((entry) => entry.reason)
|
|
16469
16549
|
])).toSorted().slice(0, COMPACT_MAX_ITEMS).map((gap) => compactText(gap, COMPACT_TEXT_BYTES));
|
|
16470
16550
|
const context = {
|
|
16471
|
-
objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
|
|
16472
|
-
status: view
|
|
16551
|
+
objective: view ? compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "" : "no task on this branch yet",
|
|
16552
|
+
status: view?.task.status ?? null,
|
|
16473
16553
|
decisions,
|
|
16474
16554
|
methods,
|
|
16475
16555
|
gaps,
|
|
16476
|
-
nextAction: compactText(view
|
|
16556
|
+
nextAction: compactText(view?.task.progress.nextAction ?? null, COMPACT_TEXT_BYTES)
|
|
16477
16557
|
};
|
|
16478
16558
|
let encoded = JSON.stringify(context);
|
|
16479
16559
|
while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
|
|
@@ -16516,7 +16596,21 @@ var COMPACT_MAX_BYTES = 4096, COMPACT_MAX_ITEMS = 8, COMPACT_TEXT_BYTES = 128, s
|
|
|
16516
16596
|
id: ref.id
|
|
16517
16597
|
};
|
|
16518
16598
|
return { kind: ref.kind };
|
|
16519
|
-
},
|
|
16599
|
+
}, newestDecisionFirst = (left, right) => {
|
|
16600
|
+
const leftAt = compactTimestamp(left.recordedAt);
|
|
16601
|
+
const rightAt = compactTimestamp(right.recordedAt);
|
|
16602
|
+
if (leftAt !== rightAt)
|
|
16603
|
+
return leftAt > rightAt ? -1 : 1;
|
|
16604
|
+
return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
|
|
16605
|
+
}, compactDecisions = (sources) => sources.flatMap((source) => source ? source.decisions.toSorted(newestDecisionFirst).map((entry) => ({
|
|
16606
|
+
id: entry.id,
|
|
16607
|
+
purpose: entry.data.purpose,
|
|
16608
|
+
status: entry.data.response,
|
|
16609
|
+
digest: entry.data.digest,
|
|
16610
|
+
choice: compactDecisionChoice(entry) || `task.inspect taskId=${source.taskId} view=full; decision=${entry.id}`,
|
|
16611
|
+
references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference),
|
|
16612
|
+
origin: source.origin ?? undefined
|
|
16613
|
+
})) : []).slice(0, COMPACT_MAX_ITEMS), exportDigest = (bundle) => sha256({
|
|
16520
16614
|
schemaVersion: bundle.schemaVersion,
|
|
16521
16615
|
exportedAt: bundle.exportedAt,
|
|
16522
16616
|
sourceWorkspaceId: bundle.sourceWorkspaceId,
|
|
@@ -17256,6 +17350,17 @@ class WorkitCore {
|
|
|
17256
17350
|
const root = this.contextRootError();
|
|
17257
17351
|
if (!root.ok)
|
|
17258
17352
|
return root;
|
|
17353
|
+
const addressed = WORKER_ADDRESSED_ACTIONS.has(action);
|
|
17354
|
+
const workerId = addressed ? value.workerId : this.context.workerId ?? null;
|
|
17355
|
+
if (workerId !== null) {
|
|
17356
|
+
const owner = this.store.taskForWorker(workerId);
|
|
17357
|
+
if (!owner.ok)
|
|
17358
|
+
return owner;
|
|
17359
|
+
if (owner.data)
|
|
17360
|
+
return success(null, null, { ...request, taskId: owner.data });
|
|
17361
|
+
if (addressed)
|
|
17362
|
+
return failure2("not_found", `worker ${workerId} is on no open task; find its task with \`workit task status --all\`, then run \`${workerCommand("<task-id>", request)}\``);
|
|
17363
|
+
}
|
|
17259
17364
|
const create = CREATING_ACTIONS.has(action) && (this.context.workerId ?? null) === null;
|
|
17260
17365
|
const found = this.store.implicitTask({
|
|
17261
17366
|
provenance: provenance(this.context),
|
|
@@ -17962,7 +18067,9 @@ class WorkitCore {
|
|
|
17962
18067
|
if (!resolved.ok)
|
|
17963
18068
|
return resolved;
|
|
17964
18069
|
const value = resolved.data;
|
|
17965
|
-
|
|
18070
|
+
const result = this.retryOmittedRevisions(value, () => this.workerOnce(value));
|
|
18071
|
+
const { action, taskId } = value ?? {};
|
|
18072
|
+
return result.ok || request?.taskId !== undefined || typeof taskId !== "string" || !WORKER_ADDRESSED_ACTIONS.has(`worker.${String(action)}`) ? result : { ...result, error: `${result.error}; run \`${workerCommand(taskId, value)}\`` };
|
|
17966
18073
|
}
|
|
17967
18074
|
workerOnce(request) {
|
|
17968
18075
|
const root = this.contextRootError();
|
|
@@ -18167,10 +18274,18 @@ class WorkitCore {
|
|
|
18167
18274
|
requirements
|
|
18168
18275
|
});
|
|
18169
18276
|
}
|
|
18170
|
-
compactContext(taskId, freshness) {
|
|
18277
|
+
compactContext(taskId, freshness, origin = null) {
|
|
18171
18278
|
const root = this.contextRootError();
|
|
18172
18279
|
if (!root.ok)
|
|
18173
18280
|
return root;
|
|
18281
|
+
const base = origin && this.store.readStoreTask(origin.taskId);
|
|
18282
|
+
const inherited = base?.ok && base.data ? {
|
|
18283
|
+
origin: origin.origin,
|
|
18284
|
+
taskId: base.data.id,
|
|
18285
|
+
decisions: base.data.decisions.filter((entry) => entry.data.revoked === null)
|
|
18286
|
+
} : null;
|
|
18287
|
+
if (taskId === null)
|
|
18288
|
+
return success(null, null, inherited?.decisions.length ? compactTaskContext(null, inherited) : "");
|
|
18174
18289
|
const task = this.store.readTask(taskId);
|
|
18175
18290
|
if (!task.ok)
|
|
18176
18291
|
return task;
|
|
@@ -18180,7 +18295,7 @@ class WorkitCore {
|
|
|
18180
18295
|
const view = this.view(task.data, false, freshness ?? signalFreshness(this.store.root));
|
|
18181
18296
|
if (!view.ok)
|
|
18182
18297
|
return view;
|
|
18183
|
-
return success(view.revision, view.workspaceRevision, compactTaskContext(view.data));
|
|
18298
|
+
return success(view.revision, view.workspaceRevision, compactTaskContext(view.data, inherited));
|
|
18184
18299
|
}
|
|
18185
18300
|
view(task, capture = true, freshness = treeFreshness(this.store.root)) {
|
|
18186
18301
|
const workspace = this.store.readWorkspace();
|
|
@@ -18591,7 +18706,12 @@ var MAX_JUDGED_REFS = 5, workspaceVerification = (root) => {
|
|
|
18591
18706
|
return changed;
|
|
18592
18707
|
const updated = changed.data.task.workers.find((candidate) => candidate.id === input.workerId);
|
|
18593
18708
|
return updated ? success(changed.data.task.revision, changed.data.workspace.revision, updated) : failure2("recovery_required", "worker disappeared during lifecycle observation");
|
|
18594
|
-
}, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || scopeCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), TASK_SCOPED_ACTIONS,
|
|
18709
|
+
}, refsWithinScope = (refs, scope) => refs.every((ref) => ref.kind !== "file" || scopeCovers(scope, { description: "", paths: [ref.path], exclusions: [] })), TASK_SCOPED_ACTIONS, WORKER_ADDRESSED_ACTIONS, workerCommand = (taskId, request) => {
|
|
18710
|
+
const { action, workerId, reason, report } = request;
|
|
18711
|
+
const rest = JSON.stringify({ reason, report });
|
|
18712
|
+
const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
|
|
18713
|
+
return `workit worker ${String(action)} ${String(workerId)} --task ${taskId}${payload}`;
|
|
18714
|
+
}, CREATING_ACTIONS, REVISION_RETRY_ATTEMPTS = 8, retryPause, filledRevisions = (request) => {
|
|
18595
18715
|
const value = typeof request === "object" && request !== null ? request : {};
|
|
18596
18716
|
return {
|
|
18597
18717
|
task: value.expectedRevision === undefined,
|
|
@@ -18813,6 +18933,7 @@ var init_task_engine = __esm(() => {
|
|
|
18813
18933
|
"worker.cancel",
|
|
18814
18934
|
"state.export"
|
|
18815
18935
|
]);
|
|
18936
|
+
WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
|
|
18816
18937
|
CREATING_ACTIONS = new Set([
|
|
18817
18938
|
"task.revise",
|
|
18818
18939
|
"task.progress",
|
|
@@ -19533,9 +19654,10 @@ async function payloadValue(raw, deps) {
|
|
|
19533
19654
|
}
|
|
19534
19655
|
}
|
|
19535
19656
|
function inject(request, key, value) {
|
|
19657
|
+
const given = key === "workerId" ? "positional worker id" : "explicit flag";
|
|
19536
19658
|
if (key in request && !same(request[key], value))
|
|
19537
|
-
return failure2("invalid_input", `payload ${key} conflicts with the
|
|
19538
|
-
fields: [{ path: key, reason:
|
|
19659
|
+
return failure2("invalid_input", `payload ${key} conflicts with the ${given}`, {
|
|
19660
|
+
fields: [{ path: key, reason: `${given} conflicts with payload` }]
|
|
19539
19661
|
});
|
|
19540
19662
|
request[key] = value;
|
|
19541
19663
|
return success(null, null, null);
|
|
@@ -19558,12 +19680,18 @@ async function parseTaskArgs(argv, deps) {
|
|
|
19558
19680
|
let workspaceRevision;
|
|
19559
19681
|
let view;
|
|
19560
19682
|
let actor;
|
|
19683
|
+
let workerId;
|
|
19684
|
+
const takesWorkerId = family === "worker" && (action === "cancel" || action === "report");
|
|
19561
19685
|
let json = jsonRequested;
|
|
19562
19686
|
const judge = [];
|
|
19563
19687
|
const seen = new Set;
|
|
19564
19688
|
for (let i = 2;i < argv.length; i += 1) {
|
|
19565
19689
|
if (argv[i] === "--") {
|
|
19566
19690
|
const extra = argv.slice(i + 1);
|
|
19691
|
+
if (takesWorkerId && workerId === undefined && extra.length === 1) {
|
|
19692
|
+
workerId = extra[0];
|
|
19693
|
+
break;
|
|
19694
|
+
}
|
|
19567
19695
|
if (extra.length)
|
|
19568
19696
|
return parseUsage(`${family} ${actionName} takes no positional arguments (got: ${extra.join(" ")})`, json);
|
|
19569
19697
|
break;
|
|
@@ -19593,6 +19721,10 @@ async function parseTaskArgs(argv, deps) {
|
|
|
19593
19721
|
json = true;
|
|
19594
19722
|
continue;
|
|
19595
19723
|
}
|
|
19724
|
+
if (takesWorkerId && workerId === undefined && !argv[i].startsWith("-")) {
|
|
19725
|
+
workerId = argv[i];
|
|
19726
|
+
continue;
|
|
19727
|
+
}
|
|
19596
19728
|
if (!["--payload", "--task", "--revision", "--workspace-revision", "--view", "--actor"].includes(token))
|
|
19597
19729
|
return parseUsage(`unknown argument: ${argv[i]}`, json);
|
|
19598
19730
|
const value = inline ?? argv[++i];
|
|
@@ -19628,6 +19760,7 @@ async function parseTaskArgs(argv, deps) {
|
|
|
19628
19760
|
for (const [key, value] of [
|
|
19629
19761
|
["action", action],
|
|
19630
19762
|
...taskId === undefined ? [] : [["taskId", taskId]],
|
|
19763
|
+
...workerId === undefined ? [] : [["workerId", workerId]],
|
|
19631
19764
|
...revision === undefined ? [] : [["expectedRevision", revision]],
|
|
19632
19765
|
...workspaceRevision === undefined ? [] : [["expectedWorkspaceRevision", workspaceRevision]],
|
|
19633
19766
|
...view === undefined ? [] : [["view", view]]
|
|
@@ -63938,30 +64071,353 @@ var init_skill_manifests = __esm(() => {
|
|
|
63938
64071
|
if (false) {}
|
|
63939
64072
|
});
|
|
63940
64073
|
|
|
63941
|
-
// packages/workit-
|
|
64074
|
+
// packages/workit-core/src/git/session-hook.ts
|
|
63942
64075
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
63943
|
-
import { createHash as createHash13 } from "node:crypto";
|
|
63944
64076
|
import {
|
|
64077
|
+
chmodSync,
|
|
63945
64078
|
existsSync as existsSync13,
|
|
63946
64079
|
lstatSync as lstatSync4,
|
|
63947
64080
|
mkdirSync as mkdirSync5,
|
|
63948
|
-
mkdtempSync,
|
|
63949
|
-
readdirSync as readdirSync7,
|
|
63950
64081
|
readFileSync as readFileSync13,
|
|
63951
|
-
|
|
64082
|
+
renameSync as renameSync3,
|
|
63952
64083
|
rmSync as rmSync2,
|
|
63953
64084
|
statSync as statSync4,
|
|
63954
|
-
unlinkSync as unlinkSync3,
|
|
63955
64085
|
writeFileSync as writeFileSync6
|
|
63956
64086
|
} from "node:fs";
|
|
63957
|
-
import os8 from "node:os";
|
|
63958
64087
|
import path30 from "node:path";
|
|
64088
|
+
function inspectSessionHook(cwd, env = process.env) {
|
|
64089
|
+
const none = { hooksDir: null, hookPath: null, helperPath: null, helperCurrent: false };
|
|
64090
|
+
if (!existsSync13(cwd))
|
|
64091
|
+
return { state: "not_git", ...none };
|
|
64092
|
+
const top = run2(cwd, ["rev-parse", "--show-toplevel"], env);
|
|
64093
|
+
if (!top.ok || !top.out)
|
|
64094
|
+
return { state: "not_git", ...none };
|
|
64095
|
+
const paths = run2(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir", "--git-path", "hooks"], env);
|
|
64096
|
+
const [commonDir, hooksDir] = paths.out.split(/\r?\n/);
|
|
64097
|
+
if (!paths.ok || !commonDir || !hooksDir)
|
|
64098
|
+
return { state: "not_git", ...none };
|
|
64099
|
+
const hookPath = path30.join(hooksDir, SESSION_HOOK_NAME);
|
|
64100
|
+
const helperPath = path30.join(commonDir, ...HELPER);
|
|
64101
|
+
const helperCurrent = readText2(helperPath) === SESSION_TRAILER_SCRIPT;
|
|
64102
|
+
const leftover = leftoverOf(hooksDir);
|
|
64103
|
+
const base = { hooksDir, hookPath, helperPath, helperCurrent, ...leftover ? { leftover } : {} };
|
|
64104
|
+
const blocked = (reason, owner, text = "") => {
|
|
64105
|
+
const old = `${hookPath}.old`;
|
|
64106
|
+
const displaced = readText2(old)?.includes(SESSION_HOOK_MARKER) ? old : null;
|
|
64107
|
+
const input = { owner, text, hooksDir, hookPath, top: top.out, displaced };
|
|
64108
|
+
const manualTarget = manualTargetOf(input);
|
|
64109
|
+
const owned = text ? { owner } : {};
|
|
64110
|
+
if (manualInPlace(input, manualTarget))
|
|
64111
|
+
return {
|
|
64112
|
+
state: "manual",
|
|
64113
|
+
...base,
|
|
64114
|
+
...owned,
|
|
64115
|
+
manualTarget,
|
|
64116
|
+
via: owner === "other" ? "existing hook" : owner
|
|
64117
|
+
};
|
|
64118
|
+
return {
|
|
64119
|
+
state: "blocked",
|
|
64120
|
+
...base,
|
|
64121
|
+
...owned,
|
|
64122
|
+
reason: displaced ? `${reason} (Workit's earlier hook was moved to ${old})` : reason,
|
|
64123
|
+
manual: manualFor(input),
|
|
64124
|
+
manualTarget
|
|
64125
|
+
};
|
|
64126
|
+
};
|
|
64127
|
+
if (!inside2(hooksDir, commonDir) && !inside2(hooksDir, top.out))
|
|
64128
|
+
return blocked(`core.hooksPath ${hooksDir} is outside the repository; a hook there runs in every repository that uses it`, "other");
|
|
64129
|
+
const text = exists(hookPath) ? readText2(hookPath) ?? "" : null;
|
|
64130
|
+
if (text !== null) {
|
|
64131
|
+
if (text === SESSION_HOOK_SCRIPT)
|
|
64132
|
+
return { state: helperCurrent ? "installed" : "outdated", ...base };
|
|
64133
|
+
if (text.includes(SESSION_HOOK_MARKER))
|
|
64134
|
+
return { state: "outdated", ...base };
|
|
64135
|
+
const owner = ownerOf(text, hooksDir, top.out);
|
|
64136
|
+
return blocked(`${hookPath} belongs to ${owner === "other" ? "another hook" : owner}; Workit never replaces it`, owner, text);
|
|
64137
|
+
}
|
|
64138
|
+
if (!inside2(hooksDir, commonDir)) {
|
|
64139
|
+
const rel = path30.relative(top.out, hookPath).split(path30.sep).join("/");
|
|
64140
|
+
if (!run2(top.out, ["check-ignore", "-q", "--", rel], env).ok)
|
|
64141
|
+
return blocked(`${hooksDir} is in the working tree and not ignored; the hook would show up as a new file`, "other");
|
|
64142
|
+
}
|
|
64143
|
+
return { state: "missing", ...base };
|
|
64144
|
+
}
|
|
64145
|
+
function installSessionHook(cwd, env = process.env) {
|
|
64146
|
+
const status = inspectSessionHook(cwd, env);
|
|
64147
|
+
if (status.state === "not_git")
|
|
64148
|
+
return {
|
|
64149
|
+
action: "skipped",
|
|
64150
|
+
helperWritten: false,
|
|
64151
|
+
status,
|
|
64152
|
+
detail: "not inside a git work tree"
|
|
64153
|
+
};
|
|
64154
|
+
const helperWritten = !status.helperCurrent;
|
|
64155
|
+
if (helperWritten)
|
|
64156
|
+
writeExecutable(status.helperPath, SESSION_TRAILER_SCRIPT);
|
|
64157
|
+
const helper = helperWritten ? `; wrote ${status.helperPath}` : "";
|
|
64158
|
+
if (status.state === "installed")
|
|
64159
|
+
return {
|
|
64160
|
+
action: "unchanged",
|
|
64161
|
+
helperWritten,
|
|
64162
|
+
status,
|
|
64163
|
+
detail: `hook already at ${status.hookPath}`
|
|
64164
|
+
};
|
|
64165
|
+
if (status.state === "manual")
|
|
64166
|
+
return {
|
|
64167
|
+
action: "unchanged",
|
|
64168
|
+
helperWritten,
|
|
64169
|
+
status: inspectSessionHook(cwd, env),
|
|
64170
|
+
detail: `${status.manualTarget} already runs the helper (via ${status.via})${helper}`
|
|
64171
|
+
};
|
|
64172
|
+
if (status.state === "blocked")
|
|
64173
|
+
return {
|
|
64174
|
+
action: "skipped",
|
|
64175
|
+
helperWritten,
|
|
64176
|
+
status: inspectSessionHook(cwd, env),
|
|
64177
|
+
detail: `${status.reason}${helper}`
|
|
64178
|
+
};
|
|
64179
|
+
const fresh = status.state === "missing";
|
|
64180
|
+
const slotCurrent = readText2(status.hookPath) === SESSION_HOOK_SCRIPT;
|
|
64181
|
+
if (!slotCurrent)
|
|
64182
|
+
writeExecutable(status.hookPath, SESSION_HOOK_SCRIPT);
|
|
64183
|
+
const verb = fresh ? "installed" : "updated";
|
|
64184
|
+
return {
|
|
64185
|
+
action: verb,
|
|
64186
|
+
helperWritten,
|
|
64187
|
+
status: inspectSessionHook(cwd, env),
|
|
64188
|
+
detail: `${verb} the Workit ${SESSION_HOOK_NAME} hook at ${status.hookPath}${helper}`
|
|
64189
|
+
};
|
|
64190
|
+
}
|
|
64191
|
+
var SESSION_HOOK_NAME = "prepare-commit-msg", SESSION_HOOK_MARKER = "# workit-session-trailer-hook", HELPER, LEGACY_CHAINED = "commit-msg.workit-chained", SESSION_TRAILER_SCRIPT = `#!/bin/sh
|
|
64192
|
+
# Workit (https://github.com/BrainerVirus/workit) wrote this file with
|
|
64193
|
+
# \`workit doctor --fix\`. A prepare-commit-msg hook runs it with its own
|
|
64194
|
+
# arguments to add a Workit-Session trailer to commits made in an agent session.
|
|
64195
|
+
# Not a hook itself; delete it together with the line that runs it.
|
|
64196
|
+
# lefthook passes a missing argument as its literal placeholder.
|
|
64197
|
+
case "\${2-}" in "" | "{2}" | template) exit 0 ;; esac
|
|
64198
|
+
gitdir=$(git rev-parse --git-dir) || exit 0
|
|
64199
|
+
if [ -d "$gitdir/rebase-merge" ] || [ -d "$gitdir/rebase-apply" ] || [ -f "$gitdir/CHERRY_PICK_HEAD" ]; then
|
|
64200
|
+
exit 0
|
|
64201
|
+
fi
|
|
64202
|
+
trim() { printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'; }
|
|
64203
|
+
inner=$(trim "\${OPENCODE_SESSION_ID-}"); inner_host=opencode
|
|
64204
|
+
if [ -z "$inner" ]; then inner=$(trim "\${PI_SESSION_ID-}"); inner_host=pi; fi
|
|
64205
|
+
if [ -z "$inner" ]; then inner=$(trim "\${CODEX_THREAD_ID-}"); inner_host=codex; fi
|
|
64206
|
+
[ -n "$inner" ] || inner_host=
|
|
64207
|
+
declared=$(trim "\${WORKIT_HOST-}")
|
|
64208
|
+
family=$(printf '%s' "$declared" | sed 's/_cli$//;s/_desktop$//')
|
|
64209
|
+
session=$inner
|
|
64210
|
+
if [ "\${WORKIT_SESSION_ID+set}" = set ]; then
|
|
64211
|
+
if [ -z "$inner" ] || [ -z "$declared" ] || [ "$family" = "$inner_host" ]; then
|
|
64212
|
+
session=$(trim "$WORKIT_SESSION_ID")
|
|
64213
|
+
fi
|
|
64214
|
+
fi
|
|
64215
|
+
[ -n "$session" ] || exit 0
|
|
64216
|
+
[ \${#session} -le 128 ] || exit 0
|
|
64217
|
+
case "$session" in *[!A-Za-z0-9_.:@/+-]*) exit 0 ;; esac
|
|
64218
|
+
add_trailer() {
|
|
64219
|
+
[ -f "$1" ] && [ -r "$1" ] || return 0
|
|
64220
|
+
body=$(sed '/^# -\\{24\\} >8 -\\{24\\}$/,$d' "$1" | git stripspace --strip-comments)
|
|
64221
|
+
[ -n "$body" ] || return 0
|
|
64222
|
+
# A merge message has no final newline; interpret-trailers would glue the
|
|
64223
|
+
# trailer to the subject line.
|
|
64224
|
+
[ -z "$(tail -c 1 "$1")" ] || printf '\\n' >> "$1"
|
|
64225
|
+
git -c trailer.separators=: -c trailer.where=end interpret-trailers --in-place \\
|
|
64226
|
+
--no-divider --if-exists addIfDifferent --trailer "Workit-Session: $session" "$1" || return 0
|
|
64227
|
+
}
|
|
64228
|
+
# $1 is the message file. lefthook cannot quote a path it pastes in, so its
|
|
64229
|
+
# job passes '' and the file is found here: git hands the hook COMMIT_EDITMSG,
|
|
64230
|
+
# except \`git merge\`, which hands it MERGE_MSG. With source "merge" both are
|
|
64231
|
+
# updated: the one git did not hand over is stale or removed after the commit.
|
|
64232
|
+
case "\${1-}" in "" | "{1}") ;; *) add_trailer "$1"; exit 0 ;; esac
|
|
64233
|
+
add_trailer "$(git rev-parse --git-path COMMIT_EDITMSG)"
|
|
64234
|
+
[ "$2" != merge ] || add_trailer "$(git rev-parse --git-path MERGE_MSG)"
|
|
64235
|
+
exit 0
|
|
64236
|
+
`, manualTrailerLine = () => `h="$(git rev-parse --git-common-dir 2>/dev/null)/${HELPER.join("/")}"; [ ! -f "$h" ] || sh "$h" "$@" || true`, lefthookTrailerRun = () => `set -f; IFS=; h=$(git rev-parse --git-common-dir 2>/dev/null)/${HELPER.join("/")}; [ ! -f $h ] || sh $h '' {2} {3} || true`, HELPER_REF, SESSION_HOOK_SCRIPT, run2 = (cwd, args, env) => {
|
|
64237
|
+
const r = spawnSync13("git", args, {
|
|
64238
|
+
cwd,
|
|
64239
|
+
encoding: "utf8",
|
|
64240
|
+
timeout: GIT_TIMEOUTS.local,
|
|
64241
|
+
windowsHide: true,
|
|
64242
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
64243
|
+
env: { ...env, GIT_TERMINAL_PROMPT: "0" }
|
|
64244
|
+
});
|
|
64245
|
+
return { ok: r.status === 0, out: (r.stdout ?? "").trim() };
|
|
64246
|
+
}, inside2 = (child, parent) => {
|
|
64247
|
+
const rel = path30.relative(path30.resolve(parent), path30.resolve(child));
|
|
64248
|
+
return rel === "" || !rel.startsWith("..") && !path30.isAbsolute(rel);
|
|
64249
|
+
}, readText2 = (file) => {
|
|
64250
|
+
try {
|
|
64251
|
+
return readFileSync13(file, "utf8");
|
|
64252
|
+
} catch {
|
|
64253
|
+
return null;
|
|
64254
|
+
}
|
|
64255
|
+
}, exists = (file) => {
|
|
64256
|
+
try {
|
|
64257
|
+
lstatSync4(file);
|
|
64258
|
+
return true;
|
|
64259
|
+
} catch {
|
|
64260
|
+
return false;
|
|
64261
|
+
}
|
|
64262
|
+
}, LEFTHOOK_CONFIGS, lefthookConfig = (top) => LEFTHOOK_CONFIGS.map((name) => path30.join(top, name)).find((file) => existsSync13(file)) ?? null, isComment = (line) => /^\s*#/.test(line), COMMAND_SH, DIRECT_CALL, VAR_CALL, runsHelperText = (text) => {
|
|
64263
|
+
const lines = text.split(/\r?\n/).filter((line) => !isComment(line));
|
|
64264
|
+
const assigned = lines.some((line) => /(?:^|[\s;])h=/.test(line) && line.includes(HELPER_REF));
|
|
64265
|
+
return lines.some((line) => DIRECT_CALL.test(line) || assigned && VAR_CALL.test(line));
|
|
64266
|
+
}, LEFTHOOK_YAML, indentOf = (line) => line.length - line.trimStart().length, lefthookRunsHelper = (text) => {
|
|
64267
|
+
const lines = text.split(/\r?\n/);
|
|
64268
|
+
const start = lines.findIndex((line) => /^prepare-commit-msg:\s*(?:#.*)?$/.test(line));
|
|
64269
|
+
if (start < 0)
|
|
64270
|
+
return false;
|
|
64271
|
+
const block = [];
|
|
64272
|
+
for (const line of lines.slice(start + 1)) {
|
|
64273
|
+
if (line.trim() && !isComment(line) && indentOf(line) === 0)
|
|
64274
|
+
break;
|
|
64275
|
+
block.push(line);
|
|
64276
|
+
}
|
|
64277
|
+
return block.some((line, i) => {
|
|
64278
|
+
if (isComment(line))
|
|
64279
|
+
return false;
|
|
64280
|
+
const runKey = /^(\s*)(?:-\s+)?run:\s*(.*)$/.exec(line);
|
|
64281
|
+
if (!runKey)
|
|
64282
|
+
return false;
|
|
64283
|
+
let value = runKey[2] ?? "";
|
|
64284
|
+
if (/^[|>][-+]?\s*$/.test(value)) {
|
|
64285
|
+
const body = [];
|
|
64286
|
+
for (const next of block.slice(i + 1)) {
|
|
64287
|
+
if (next.trim() && indentOf(next) <= indentOf(line))
|
|
64288
|
+
break;
|
|
64289
|
+
body.push(next);
|
|
64290
|
+
}
|
|
64291
|
+
value = body.join(`
|
|
64292
|
+
`);
|
|
64293
|
+
}
|
|
64294
|
+
return runsHelperText(value);
|
|
64295
|
+
});
|
|
64296
|
+
}, isExecutable = (file) => {
|
|
64297
|
+
if (process.platform === "win32")
|
|
64298
|
+
return true;
|
|
64299
|
+
try {
|
|
64300
|
+
return (statSync4(file).mode & 73) !== 0;
|
|
64301
|
+
} catch {
|
|
64302
|
+
return false;
|
|
64303
|
+
}
|
|
64304
|
+
}, manualInPlace = (input, target) => {
|
|
64305
|
+
if (input.owner === "lefthook")
|
|
64306
|
+
return LEFTHOOK_YAML.some((name) => {
|
|
64307
|
+
const text = readText2(path30.join(input.top, name));
|
|
64308
|
+
return text !== null && lefthookRunsHelper(text);
|
|
64309
|
+
});
|
|
64310
|
+
const text = readText2(target);
|
|
64311
|
+
if (text === null || !runsHelperText(text))
|
|
64312
|
+
return false;
|
|
64313
|
+
return input.owner === "husky" && target !== input.hookPath || isExecutable(target);
|
|
64314
|
+
}, isHuskyV9 = (text, hooksDir) => /\$\(dirname (?:-- )?"\$0"\)\/h"/.test(text) && existsSync13(path30.join(hooksDir, "h")), ownerOf = (text, hooksDir, top) => {
|
|
64315
|
+
if (text.includes("husky.sh") || isHuskyV9(text, hooksDir))
|
|
64316
|
+
return "husky";
|
|
64317
|
+
if (/lefthook/i.test(text) || lefthookConfig(top))
|
|
64318
|
+
return "lefthook";
|
|
64319
|
+
return "other";
|
|
64320
|
+
}, manualTargetOf = ({ owner, text, hooksDir, hookPath, top }) => {
|
|
64321
|
+
if (owner === "husky" && isHuskyV9(text, hooksDir))
|
|
64322
|
+
return path30.join(path30.dirname(hooksDir), SESSION_HOOK_NAME);
|
|
64323
|
+
if (owner === "lefthook")
|
|
64324
|
+
return lefthookConfig(top) ?? path30.join(top, "lefthook.yml");
|
|
64325
|
+
return hookPath;
|
|
64326
|
+
}, manualFor = (input) => {
|
|
64327
|
+
const { owner, displaced } = input;
|
|
64328
|
+
const target = manualTargetOf(input);
|
|
64329
|
+
const stale = displaced ? `; delete the stale ${displaced} (nothing runs it)` : "";
|
|
64330
|
+
if (owner === "husky")
|
|
64331
|
+
return `add this line to ${target} (create it if missing; husky runs it)${stale}: ${manualTrailerLine()}`;
|
|
64332
|
+
if (owner === "lefthook")
|
|
64333
|
+
return [
|
|
64334
|
+
`merge this job into ${target} (add it to an existing \`${SESSION_HOOK_NAME}:\` \`jobs:\` list rather than a second \`${SESSION_HOOK_NAME}:\` key), then run \`lefthook install\`${stale}:`,
|
|
64335
|
+
`${SESSION_HOOK_NAME}:`,
|
|
64336
|
+
" jobs:",
|
|
64337
|
+
" - name: workit-session",
|
|
64338
|
+
` run: ${lefthookTrailerRun()}`
|
|
64339
|
+
].join(`
|
|
64340
|
+
`);
|
|
64341
|
+
return `add this line to ${target} (a new file needs \`#!/bin/sh\` as its first line and \`chmod +x\`)${stale}: ${manualTrailerLine()}`;
|
|
64342
|
+
}, leftoverOf = (hooksDir) => {
|
|
64343
|
+
const chained = path30.join(hooksDir, LEGACY_CHAINED);
|
|
64344
|
+
const commitMsg = path30.join(hooksDir, "commit-msg");
|
|
64345
|
+
const oldOurs = readText2(commitMsg)?.includes(SESSION_HOOK_MARKER) ?? false;
|
|
64346
|
+
if (exists(chained))
|
|
64347
|
+
return oldOurs ? `${chained} was left by an earlier Workit build: move it back to ${commitMsg} (replacing Workit's old hook there)` : `${chained} was left by an earlier Workit build and nothing runs it: if it is your original commit-msg hook, move it back to ${commitMsg}; otherwise delete it`;
|
|
64348
|
+
if (oldOurs)
|
|
64349
|
+
return `${commitMsg} is a hook from an earlier Workit build; delete it (the trailer now comes from ${SESSION_HOOK_NAME})`;
|
|
64350
|
+
return;
|
|
64351
|
+
}, writeExecutable = (file, content) => {
|
|
64352
|
+
mkdirSync5(path30.dirname(file), { recursive: true });
|
|
64353
|
+
const staged = `${file}.workit-new`;
|
|
64354
|
+
try {
|
|
64355
|
+
writeFileSync6(staged, content, { mode: 493 });
|
|
64356
|
+
chmodSync(staged, 493);
|
|
64357
|
+
renameSync3(staged, file);
|
|
64358
|
+
} finally {
|
|
64359
|
+
rmSync2(staged, { force: true });
|
|
64360
|
+
}
|
|
64361
|
+
};
|
|
64362
|
+
var init_session_hook = __esm(() => {
|
|
64363
|
+
init_rev();
|
|
64364
|
+
HELPER = ["workit", "session-trailer.sh"];
|
|
64365
|
+
HELPER_REF = HELPER.join("/");
|
|
64366
|
+
SESSION_HOOK_SCRIPT = `#!/bin/sh
|
|
64367
|
+
${SESSION_HOOK_MARKER} v4
|
|
64368
|
+
# Workit (https://github.com/BrainerVirus/workit) installed this hook with
|
|
64369
|
+
# \`workit doctor --fix\`: it runs Workit's session-trailer helper, which adds a
|
|
64370
|
+
# Workit-Session trailer to commits made in an agent session. To remove it,
|
|
64371
|
+
# delete this file.
|
|
64372
|
+
${manualTrailerLine()}
|
|
64373
|
+
`;
|
|
64374
|
+
LEFTHOOK_CONFIGS = [
|
|
64375
|
+
"lefthook.yml",
|
|
64376
|
+
"lefthook.yaml",
|
|
64377
|
+
".lefthook.yml",
|
|
64378
|
+
".lefthook.yaml",
|
|
64379
|
+
"lefthook.json",
|
|
64380
|
+
"lefthook.toml"
|
|
64381
|
+
];
|
|
64382
|
+
COMMAND_SH = String.raw`(?:^|[;&|(!]|\b(?:then|do|else)\s)\s*sh\s+`;
|
|
64383
|
+
DIRECT_CALL = new RegExp(String.raw`${COMMAND_SH}(?:"[^"]*|\S*)${HELPER_REF.replaceAll(".", String.raw`\.`)}`);
|
|
64384
|
+
VAR_CALL = new RegExp(String.raw`${COMMAND_SH}"?\$h\b`);
|
|
64385
|
+
LEFTHOOK_YAML = [
|
|
64386
|
+
"lefthook.yml",
|
|
64387
|
+
"lefthook.yaml",
|
|
64388
|
+
".lefthook.yml",
|
|
64389
|
+
".lefthook.yaml",
|
|
64390
|
+
"lefthook-local.yml",
|
|
64391
|
+
"lefthook-local.yaml",
|
|
64392
|
+
".lefthook-local.yml",
|
|
64393
|
+
".lefthook-local.yaml"
|
|
64394
|
+
];
|
|
64395
|
+
});
|
|
64396
|
+
|
|
64397
|
+
// packages/workit-cli/src/admin/doctor.ts
|
|
64398
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
64399
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
64400
|
+
import {
|
|
64401
|
+
existsSync as existsSync14,
|
|
64402
|
+
lstatSync as lstatSync5,
|
|
64403
|
+
mkdirSync as mkdirSync6,
|
|
64404
|
+
mkdtempSync,
|
|
64405
|
+
readdirSync as readdirSync7,
|
|
64406
|
+
readFileSync as readFileSync14,
|
|
64407
|
+
readlinkSync as readlinkSync2,
|
|
64408
|
+
rmSync as rmSync3,
|
|
64409
|
+
statSync as statSync5,
|
|
64410
|
+
unlinkSync as unlinkSync3,
|
|
64411
|
+
writeFileSync as writeFileSync7
|
|
64412
|
+
} from "node:fs";
|
|
64413
|
+
import os8 from "node:os";
|
|
64414
|
+
import path31 from "node:path";
|
|
63959
64415
|
var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
63960
|
-
let dir =
|
|
64416
|
+
let dir = path31.resolve(cwd);
|
|
63961
64417
|
while (true) {
|
|
63962
|
-
if (
|
|
64418
|
+
if (existsSync14(path31.join(dir, "packages", "workit-core", "package.json")))
|
|
63963
64419
|
return dir;
|
|
63964
|
-
const parent =
|
|
64420
|
+
const parent = path31.dirname(dir);
|
|
63965
64421
|
if (parent === dir)
|
|
63966
64422
|
return null;
|
|
63967
64423
|
dir = parent;
|
|
@@ -63969,8 +64425,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63969
64425
|
}, resolve = (options) => {
|
|
63970
64426
|
const env = options.env ?? process.env;
|
|
63971
64427
|
const home = options.home ?? env.HOME ?? os8.homedir();
|
|
63972
|
-
const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
63973
|
-
const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ??
|
|
64428
|
+
const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path31.join(home, ".config", "workit");
|
|
64429
|
+
const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path31.join(home, ".local", "state", "workit");
|
|
63974
64430
|
const cwd = options.cwd ?? process.cwd();
|
|
63975
64431
|
const dev = options.dev ?? env.WORKFLOW_TOOLKIT_DEV ?? findDevFromCwd(cwd);
|
|
63976
64432
|
return {
|
|
@@ -63981,11 +64437,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63981
64437
|
cwd,
|
|
63982
64438
|
workspaceRoot: options.workspaceRoot ?? env.WORKFLOW_WORKSPACE_ROOT ?? cwd,
|
|
63983
64439
|
dev,
|
|
63984
|
-
opencodeConfig: options.opencodeConfig ??
|
|
63985
|
-
opencodePackageCacheDir: options.opencodePackageCacheDir ??
|
|
63986
|
-
cursorSettings: options.cursorSettings ??
|
|
63987
|
-
cursorMcp: options.cursorMcp ??
|
|
63988
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
64440
|
+
opencodeConfig: options.opencodeConfig ?? path31.join(home, ".config", "opencode", "opencode.json"),
|
|
64441
|
+
opencodePackageCacheDir: options.opencodePackageCacheDir ?? path31.join(home, ".cache", "opencode", "packages", "@brainervirus", "workit-opencode@latest"),
|
|
64442
|
+
cursorSettings: options.cursorSettings ?? path31.join(home, ".cursor", "settings.json"),
|
|
64443
|
+
cursorMcp: options.cursorMcp ?? path31.join(home, ".cursor", "mcp.json"),
|
|
64444
|
+
cursorPluginDir: options.cursorPluginDir ?? path31.join(home, ".cursor", "plugins", "local", "workit"),
|
|
63989
64445
|
cursorHeartbeatDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
|
|
63990
64446
|
codexHome: options.codexHome,
|
|
63991
64447
|
piAgentDir: options.piAgentDir,
|
|
@@ -63995,14 +64451,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63995
64451
|
};
|
|
63996
64452
|
}, readJson = (p) => {
|
|
63997
64453
|
try {
|
|
63998
|
-
const parsed = JSON.parse(
|
|
64454
|
+
const parsed = JSON.parse(readFileSync14(p, "utf8"));
|
|
63999
64455
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
64000
64456
|
} catch {
|
|
64001
64457
|
return null;
|
|
64002
64458
|
}
|
|
64003
64459
|
}, parsesAsConfigObject = (p) => {
|
|
64004
64460
|
try {
|
|
64005
|
-
return isConfigObject(JSON.parse(
|
|
64461
|
+
return isConfigObject(JSON.parse(readFileSync14(p, "utf8")));
|
|
64006
64462
|
} catch {
|
|
64007
64463
|
return false;
|
|
64008
64464
|
}
|
|
@@ -64012,14 +64468,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64012
64468
|
...new Set(entries.filter((entry) => typeof entry === "string" && isWorkitPlugin(entry)))
|
|
64013
64469
|
];
|
|
64014
64470
|
}, commandOnPath = (name, env) => findOnPath(process.platform === "win32" ? [name, `${name}.exe`] : [name], env) !== null, pathextNames = (name, env) => process.platform === "win32" ? (env.PATHEXT ?? process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean).map((ext) => `${name}${ext.toLowerCase()}`) : [name], findOnPath = (names, env) => {
|
|
64015
|
-
const dirs = (env.PATH ?? process.env.PATH ?? "").split(
|
|
64471
|
+
const dirs = (env.PATH ?? process.env.PATH ?? "").split(path31.delimiter);
|
|
64016
64472
|
for (const dir of dirs) {
|
|
64017
64473
|
if (!dir)
|
|
64018
64474
|
continue;
|
|
64019
64475
|
for (const candidateName of names) {
|
|
64020
|
-
const candidate =
|
|
64476
|
+
const candidate = path31.join(dir, candidateName);
|
|
64021
64477
|
try {
|
|
64022
|
-
const st =
|
|
64478
|
+
const st = statSync5(candidate);
|
|
64023
64479
|
if (process.platform !== "win32" && (st.mode & 73) === 0)
|
|
64024
64480
|
continue;
|
|
64025
64481
|
return candidate;
|
|
@@ -64028,7 +64484,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64028
64484
|
}
|
|
64029
64485
|
return null;
|
|
64030
64486
|
}, versionOf = (bin, env, timeout) => {
|
|
64031
|
-
const r =
|
|
64487
|
+
const r = spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout });
|
|
64032
64488
|
if (r.error)
|
|
64033
64489
|
return null;
|
|
64034
64490
|
return (r.stdout ?? "").trim();
|
|
@@ -64043,14 +64499,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64043
64499
|
}
|
|
64044
64500
|
return true;
|
|
64045
64501
|
}, resolveBun = (env) => {
|
|
64046
|
-
if (env.BUN &&
|
|
64502
|
+
if (env.BUN && existsSync14(env.BUN))
|
|
64047
64503
|
return env.BUN;
|
|
64048
64504
|
for (const candidate of [
|
|
64049
|
-
|
|
64505
|
+
path31.join(os8.homedir(), ".bun/bin/bun"),
|
|
64050
64506
|
"/usr/local/bin/bun",
|
|
64051
64507
|
"/usr/bin/bun"
|
|
64052
64508
|
]) {
|
|
64053
|
-
if (
|
|
64509
|
+
if (existsSync14(candidate))
|
|
64054
64510
|
return candidate;
|
|
64055
64511
|
}
|
|
64056
64512
|
return commandOnPath("bun", env) ? "bun" : null;
|
|
@@ -64098,7 +64554,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64098
64554
|
detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping version parity"
|
|
64099
64555
|
};
|
|
64100
64556
|
}
|
|
64101
|
-
const corePkg = readJson(
|
|
64557
|
+
const corePkg = readJson(path31.join(res.dev, "packages/workit-core/package.json"));
|
|
64102
64558
|
if (!corePkg) {
|
|
64103
64559
|
return {
|
|
64104
64560
|
id: "versions",
|
|
@@ -64108,7 +64564,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64108
64564
|
}
|
|
64109
64565
|
const refs = new Set;
|
|
64110
64566
|
for (const name of ["workit-opencode", "workit-cursor", "workit-cli"]) {
|
|
64111
|
-
const pkg = readJson(
|
|
64567
|
+
const pkg = readJson(path31.join(res.dev, "packages", name, "package.json"));
|
|
64112
64568
|
const dep = pkg?.dependencies?.["@brainervirus/workit-core"];
|
|
64113
64569
|
if (typeof dep === "string")
|
|
64114
64570
|
refs.add(dep);
|
|
@@ -64124,7 +64580,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64124
64580
|
if (refs.size > 1) {
|
|
64125
64581
|
problems.push(`adapters pin different core versions: ${[...refs].join(", ")}`);
|
|
64126
64582
|
}
|
|
64127
|
-
const opencodePkg = readJson(
|
|
64583
|
+
const opencodePkg = readJson(path31.join(res.dev, "packages/workit-opencode/package.json"));
|
|
64128
64584
|
const sdk = opencodePkg?.dependencies?.["@opencode/plugin"] ?? opencodePkg?.devDependencies?.["@opencode/plugin"];
|
|
64129
64585
|
const sdkVersion = typeof sdk === "string" ? (sdk.match(/^\d+(?:\.\d+){0,2}/) ?? [])[0] : null;
|
|
64130
64586
|
if (sdkVersion && !semverAtLeast(sdkVersion, SUPPORT_MATRIX.opencode.minimum)) {
|
|
@@ -64151,17 +64607,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64151
64607
|
status: "pass",
|
|
64152
64608
|
detail: "opencode CLI not on PATH — skipping version check"
|
|
64153
64609
|
};
|
|
64154
|
-
const scratch = mkdtempSync(
|
|
64610
|
+
const scratch = mkdtempSync(path31.join(os8.tmpdir(), "workit-doctor-opencode-"));
|
|
64155
64611
|
let raw;
|
|
64156
64612
|
try {
|
|
64157
64613
|
raw = versionOf("opencode", {
|
|
64158
64614
|
...res.env,
|
|
64159
|
-
XDG_DATA_HOME:
|
|
64160
|
-
XDG_STATE_HOME:
|
|
64161
|
-
XDG_CACHE_HOME:
|
|
64615
|
+
XDG_DATA_HOME: path31.join(scratch, "data"),
|
|
64616
|
+
XDG_STATE_HOME: path31.join(scratch, "state"),
|
|
64617
|
+
XDG_CACHE_HOME: path31.join(scratch, "cache")
|
|
64162
64618
|
}, 5000);
|
|
64163
64619
|
} finally {
|
|
64164
|
-
|
|
64620
|
+
rmSync3(scratch, { recursive: true, force: true });
|
|
64165
64621
|
}
|
|
64166
64622
|
const installed = raw ? (raw.match(/\d+\.\d+\.\d+/) ?? [])[0] ?? null : null;
|
|
64167
64623
|
if (installed === null)
|
|
@@ -64216,7 +64672,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64216
64672
|
const tables = new Map;
|
|
64217
64673
|
let text;
|
|
64218
64674
|
try {
|
|
64219
|
-
text =
|
|
64675
|
+
text = readFileSync14(file, "utf8");
|
|
64220
64676
|
} catch {
|
|
64221
64677
|
return tables;
|
|
64222
64678
|
}
|
|
@@ -64254,19 +64710,19 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64254
64710
|
current[unquote(pair[1])] = value === "true" ? true : value === "false" ? false : unquote(value);
|
|
64255
64711
|
}
|
|
64256
64712
|
return tables;
|
|
64257
|
-
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME ||
|
|
64713
|
+
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path31.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
|
|
64258
64714
|
const codexHome = codexHomeOf(res);
|
|
64259
|
-
const configFile =
|
|
64715
|
+
const configFile = path31.join(codexHome, "config.toml");
|
|
64260
64716
|
const installs = [];
|
|
64261
64717
|
for (const [key, table] of readTomlTables(configFile)) {
|
|
64262
64718
|
const [kind, id, ...rest] = key.split("\x00");
|
|
64263
64719
|
if (kind !== "plugins" || rest.length > 0 || !id?.startsWith("workit@") || table.enabled === false)
|
|
64264
64720
|
continue;
|
|
64265
64721
|
const marketplace = id.slice("workit@".length);
|
|
64266
|
-
const dir =
|
|
64722
|
+
const dir = path31.join(codexHome, "plugins", "cache", marketplace, "workit");
|
|
64267
64723
|
let versions = [];
|
|
64268
64724
|
try {
|
|
64269
|
-
versions = readdirSync7(dir).filter((v) =>
|
|
64725
|
+
versions = readdirSync7(dir).filter((v) => existsSync14(path31.join(dir, v, ".codex-plugin")));
|
|
64270
64726
|
} catch {
|
|
64271
64727
|
versions = [];
|
|
64272
64728
|
}
|
|
@@ -64274,7 +64730,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64274
64730
|
installs.push({
|
|
64275
64731
|
id,
|
|
64276
64732
|
marketplace,
|
|
64277
|
-
root: version ?
|
|
64733
|
+
root: version ? path31.join(dir, version) : null,
|
|
64278
64734
|
version,
|
|
64279
64735
|
configFile
|
|
64280
64736
|
});
|
|
@@ -64296,7 +64752,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64296
64752
|
};
|
|
64297
64753
|
return `sha256:${createHash13("sha256").update(JSON.stringify(body)).digest("hex")}`;
|
|
64298
64754
|
}, codexHookTrust = (install, tables) => {
|
|
64299
|
-
const hooks = install.root ? readJson(
|
|
64755
|
+
const hooks = install.root ? readJson(path31.join(install.root, "hooks", "hooks.json"))?.hooks : null;
|
|
64300
64756
|
if (!hooks || typeof hooks !== "object")
|
|
64301
64757
|
return null;
|
|
64302
64758
|
const result = [];
|
|
@@ -64369,28 +64825,28 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64369
64825
|
status: "pass",
|
|
64370
64826
|
detail: "no Workit Codex plugin enabled — skipping"
|
|
64371
64827
|
};
|
|
64372
|
-
const agentsDir =
|
|
64828
|
+
const agentsDir = path31.join(codexHomeOf(res), "agents");
|
|
64373
64829
|
const problems = [];
|
|
64374
64830
|
const fixes = [];
|
|
64375
64831
|
const installed = [];
|
|
64376
64832
|
for (const install of installs) {
|
|
64377
|
-
const source = install.root ?
|
|
64378
|
-
const files = source &&
|
|
64833
|
+
const source = install.root ? path31.join(install.root, "agents") : null;
|
|
64834
|
+
const files = source && existsSync14(source) ? readdirSync7(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
|
|
64379
64835
|
if (files.length === 0) {
|
|
64380
64836
|
problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
|
|
64381
64837
|
fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
|
|
64382
64838
|
continue;
|
|
64383
64839
|
}
|
|
64384
|
-
const install_fix = `node ${JSON.stringify(
|
|
64385
|
-
const pluginVersion = readJson(
|
|
64840
|
+
const install_fix = `node ${JSON.stringify(path31.join(install.root, "dist", "launch-mcp.js"))} --install-agents, then start a new Codex session`;
|
|
64841
|
+
const pluginVersion = readJson(path31.join(install.root, "package.json"))?.version;
|
|
64386
64842
|
const version = typeof pluginVersion === "string" ? pluginVersion.match(SEMVER)?.[0] ?? null : null;
|
|
64387
64843
|
let stale = false;
|
|
64388
64844
|
for (const file of files) {
|
|
64389
|
-
const dest =
|
|
64390
|
-
const want = stampCodexAgent(
|
|
64845
|
+
const dest = path31.join(agentsDir, file);
|
|
64846
|
+
const want = stampCodexAgent(readFileSync14(path31.join(source, file), "utf8"), version);
|
|
64391
64847
|
let link = false;
|
|
64392
64848
|
try {
|
|
64393
|
-
link =
|
|
64849
|
+
link = lstatSync5(dest).isSymbolicLink();
|
|
64394
64850
|
} catch {
|
|
64395
64851
|
link = false;
|
|
64396
64852
|
}
|
|
@@ -64401,7 +64857,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64401
64857
|
}
|
|
64402
64858
|
let have = null;
|
|
64403
64859
|
try {
|
|
64404
|
-
have =
|
|
64860
|
+
have = readFileSync14(dest, "utf8");
|
|
64405
64861
|
} catch {
|
|
64406
64862
|
have = null;
|
|
64407
64863
|
}
|
|
@@ -64440,7 +64896,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64440
64896
|
const env = res.env.PI_CODING_AGENT_DIR;
|
|
64441
64897
|
if (env)
|
|
64442
64898
|
return env === "~" ? res.home : env.replace(/^~(?=\/|\\)/, res.home);
|
|
64443
|
-
return
|
|
64899
|
+
return path31.join(res.home, ".pi", "agent");
|
|
64444
64900
|
}, npmSpecName = (spec) => {
|
|
64445
64901
|
const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
|
|
64446
64902
|
return at > 0 ? { name: spec.slice(0, at), pinned: true } : { name: spec, pinned: false };
|
|
@@ -64448,10 +64904,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64448
64904
|
const scopes = [
|
|
64449
64905
|
{
|
|
64450
64906
|
scope: "project",
|
|
64451
|
-
settingsFile:
|
|
64452
|
-
base:
|
|
64907
|
+
settingsFile: path31.join(res.cwd, ".pi", "settings.json"),
|
|
64908
|
+
base: path31.join(res.cwd, ".pi")
|
|
64453
64909
|
},
|
|
64454
|
-
{ scope: "user", settingsFile:
|
|
64910
|
+
{ scope: "user", settingsFile: path31.join(agentDir, "settings.json"), base: agentDir }
|
|
64455
64911
|
];
|
|
64456
64912
|
for (const { scope, settingsFile, base } of scopes) {
|
|
64457
64913
|
const packages = readJson(settingsFile)?.packages;
|
|
@@ -64466,13 +64922,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64466
64922
|
const spec = npmSpecName(source.slice(4).trim());
|
|
64467
64923
|
if (spec.name !== PI_PACKAGE)
|
|
64468
64924
|
continue;
|
|
64469
|
-
const root =
|
|
64925
|
+
const root = path31.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
|
|
64470
64926
|
return { scope, settingsFile, source, filter, root, npm: { pinned: spec.pinned } };
|
|
64471
64927
|
}
|
|
64472
64928
|
if (/^(git:|https?:|ssh:|git@)/.test(source))
|
|
64473
64929
|
continue;
|
|
64474
|
-
const local =
|
|
64475
|
-
if (readJson(
|
|
64930
|
+
const local = path31.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
|
|
64931
|
+
if (readJson(path31.join(local, "package.json"))?.name === PI_PACKAGE)
|
|
64476
64932
|
return { scope, settingsFile, source, filter, root: local, npm: null };
|
|
64477
64933
|
}
|
|
64478
64934
|
}
|
|
@@ -64483,7 +64939,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64483
64939
|
const list = patterns.filter((p) => typeof p === "string");
|
|
64484
64940
|
if (list.length === 0)
|
|
64485
64941
|
return false;
|
|
64486
|
-
const name =
|
|
64942
|
+
const name = path31.posix.basename(file);
|
|
64487
64943
|
const matches = (p) => {
|
|
64488
64944
|
const re = globToRegExp3(p);
|
|
64489
64945
|
return re.test(file) || re.test(name);
|
|
@@ -64500,7 +64956,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64500
64956
|
return kept;
|
|
64501
64957
|
}, checkPiExtension = (res) => {
|
|
64502
64958
|
const agentDir = piAgentDirOf(res);
|
|
64503
|
-
if (!
|
|
64959
|
+
if (!existsSync14(agentDir) && !commandOnPath("pi", res.env))
|
|
64504
64960
|
return { id: "pi_extension", status: "pass", detail: "Pi not installed — skipping" };
|
|
64505
64961
|
const installCmd = (scope, spec = `npm:${PI_PACKAGE}`) => `pi install ${spec}${scope === "project" ? " -l" : ""}`;
|
|
64506
64962
|
const entry = findPiEntry(res, agentDir);
|
|
@@ -64508,12 +64964,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64508
64964
|
return {
|
|
64509
64965
|
id: "pi_extension",
|
|
64510
64966
|
status: "warn",
|
|
64511
|
-
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${
|
|
64967
|
+
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${path31.join(agentDir, "settings.json")} or ${path31.join(res.cwd, ".pi", "settings.json")}`,
|
|
64512
64968
|
fix: installCmd("user")
|
|
64513
64969
|
};
|
|
64514
64970
|
const where = `${entry.source} (${entry.scope}, ${entry.settingsFile})`;
|
|
64515
64971
|
const rebuild = `cd ${JSON.stringify(entry.root)} && bun run build`;
|
|
64516
|
-
const pkg = readJson(
|
|
64972
|
+
const pkg = readJson(path31.join(entry.root, "package.json"));
|
|
64517
64973
|
if (!pkg)
|
|
64518
64974
|
return {
|
|
64519
64975
|
id: "pi_extension",
|
|
@@ -64522,7 +64978,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64522
64978
|
fix: entry.npm ? installCmd(entry.scope, entry.source) : `restore ${entry.root}, then ${rebuild}`
|
|
64523
64979
|
};
|
|
64524
64980
|
const declared = Array.isArray(pkg.pi?.extensions) ? pkg.pi.extensions.some((e) => typeof e === "string" && e.replace(/^\.\//, "") === PI_EXTENSION) : false;
|
|
64525
|
-
if (!declared || !
|
|
64981
|
+
if (!declared || !existsSync14(path31.join(entry.root, PI_EXTENSION)))
|
|
64526
64982
|
return {
|
|
64527
64983
|
id: "pi_extension",
|
|
64528
64984
|
status: "warn",
|
|
@@ -64575,25 +65031,25 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64575
65031
|
detail: `Workit Pi extension ${version ?? "?"} from ${where} loads ${PI_EXTENSION}`
|
|
64576
65032
|
};
|
|
64577
65033
|
}, assetPathsFor = (host, dev) => {
|
|
64578
|
-
const pkg =
|
|
65034
|
+
const pkg = path31.join(dev, "packages", `workit-${host}`);
|
|
64579
65035
|
switch (host) {
|
|
64580
65036
|
case "opencode": {
|
|
64581
|
-
const packaged =
|
|
64582
|
-
const root =
|
|
64583
|
-
return WORKIT_METHOD_SKILLS.map((skill) =>
|
|
65037
|
+
const packaged = path31.join(pkg, "assets", "skills");
|
|
65038
|
+
const root = existsSync14(packaged) ? packaged : path31.join(dev, "packages", "workit-core", "skills");
|
|
65039
|
+
return WORKIT_METHOD_SKILLS.map((skill) => path31.join(root, skill, "SKILL.md"));
|
|
64584
65040
|
}
|
|
64585
65041
|
case "cursor":
|
|
64586
65042
|
return [
|
|
64587
|
-
|
|
64588
|
-
|
|
64589
|
-
|
|
65043
|
+
path31.join(pkg, "assets", "templates", "workit-contract.md"),
|
|
65044
|
+
path31.join(pkg, "mcp.json"),
|
|
65045
|
+
path31.join(pkg, ".cursor-plugin")
|
|
64590
65046
|
];
|
|
64591
65047
|
case "cli":
|
|
64592
|
-
return [
|
|
65048
|
+
return [path31.join(pkg, "assets", "templates", "spec-template.md")];
|
|
64593
65049
|
}
|
|
64594
65050
|
}, hostsFor = (host) => host === "cli" ? ["opencode", "cursor", "cli"] : [host], checkAssets = (res) => {
|
|
64595
65051
|
const dev = res.dev;
|
|
64596
|
-
const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !
|
|
65052
|
+
const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !existsSync14(p)).map((p) => `${h}: ${p}`)) : [];
|
|
64597
65053
|
if (res.host === "cursor" || res.host === "cli") {
|
|
64598
65054
|
const cursorError = validateCursorSkills(res.cursorPluginDir, WORKIT_METHOD_SKILLS);
|
|
64599
65055
|
if (cursorError)
|
|
@@ -64620,31 +65076,31 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64620
65076
|
fix: "Reinstall or rebuild the workit package (missing assets under packages/workit-<host>)"
|
|
64621
65077
|
};
|
|
64622
65078
|
}, launcherSlotsFor = (host, dev) => {
|
|
64623
|
-
const pkg =
|
|
65079
|
+
const pkg = path31.join(dev, "packages", `workit-${host}`);
|
|
64624
65080
|
switch (host) {
|
|
64625
65081
|
case "opencode":
|
|
64626
|
-
return [[
|
|
65082
|
+
return [[path31.join(pkg, "src", "plugin.ts"), path31.join(pkg, "dist", "plugin.js")]];
|
|
64627
65083
|
case "cursor":
|
|
64628
65084
|
return [
|
|
64629
|
-
[
|
|
64630
|
-
[
|
|
65085
|
+
[path31.join(pkg, "dist", "mcp-server.js")],
|
|
65086
|
+
[path31.join(pkg, "dist", "cursor-session-start.js")]
|
|
64631
65087
|
];
|
|
64632
65088
|
case "cli":
|
|
64633
|
-
return [[
|
|
65089
|
+
return [[path31.join(pkg, "src", "index.tsx"), path31.join(pkg, "dist", "index.js")]];
|
|
64634
65090
|
}
|
|
64635
65091
|
}, validNodeEntry = (entry, runtime, env) => {
|
|
64636
65092
|
try {
|
|
64637
|
-
const stat =
|
|
64638
|
-
if (!stat.isFile() || stat.size === 0 || !
|
|
65093
|
+
const stat = statSync5(entry);
|
|
65094
|
+
if (!stat.isFile() || stat.size === 0 || !readFileSync14(entry, "utf8").startsWith(`#!/usr/bin/env node
|
|
64639
65095
|
`)) {
|
|
64640
65096
|
return false;
|
|
64641
65097
|
}
|
|
64642
|
-
return
|
|
65098
|
+
return spawnSync14(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
|
|
64643
65099
|
} catch {
|
|
64644
65100
|
return false;
|
|
64645
65101
|
}
|
|
64646
65102
|
}, registeredCursorLauncher = (res) => {
|
|
64647
|
-
if (!
|
|
65103
|
+
if (!existsSync14(res.cursorMcp))
|
|
64648
65104
|
return "invalid";
|
|
64649
65105
|
const config = readJson(res.cursorMcp);
|
|
64650
65106
|
if (!config)
|
|
@@ -64657,7 +65113,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64657
65113
|
if (typeof command !== "string" || !Array.isArray(args) || typeof args[0] !== "string") {
|
|
64658
65114
|
return "invalid";
|
|
64659
65115
|
}
|
|
64660
|
-
const executable =
|
|
65116
|
+
const executable = path31.basename(command).toLowerCase();
|
|
64661
65117
|
const canonical = cursorMcpServerEntry("").args;
|
|
64662
65118
|
if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
|
|
64663
65119
|
if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
|
|
@@ -64669,11 +65125,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64669
65125
|
return {
|
|
64670
65126
|
kind: "node",
|
|
64671
65127
|
runtime: command,
|
|
64672
|
-
entry:
|
|
65128
|
+
entry: path31.isAbsolute(args[0]) ? args[0] : path31.resolve(path31.dirname(res.cursorMcp), args[0])
|
|
64673
65129
|
};
|
|
64674
65130
|
}, canonicalCursorHook, isCanonicalCursorHook = (command, res) => command === canonicalCursorHook || command === cursorHooksEntry(res.cursorPluginDir).command, registeredCursorHook = (res) => {
|
|
64675
|
-
const hooksFile =
|
|
64676
|
-
if (!
|
|
65131
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
65132
|
+
if (!existsSync14(hooksFile))
|
|
64677
65133
|
return "invalid";
|
|
64678
65134
|
const config = readJson(hooksFile);
|
|
64679
65135
|
if (!config)
|
|
@@ -64690,9 +65146,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64690
65146
|
if (!m)
|
|
64691
65147
|
return false;
|
|
64692
65148
|
const entry = m[1].trim();
|
|
64693
|
-
if (!
|
|
65149
|
+
if (!path31.isAbsolute(entry))
|
|
64694
65150
|
return false;
|
|
64695
|
-
if (
|
|
65151
|
+
if (path31.resolve(entry) !== path31.resolve(path31.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
|
|
64696
65152
|
return false;
|
|
64697
65153
|
}
|
|
64698
65154
|
return validNodeEntry(entry, "node", res.env);
|
|
@@ -64701,7 +65157,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64701
65157
|
const hosts = hostsFor(res.host);
|
|
64702
65158
|
const registered = hosts.includes("cursor") ? registeredCursorLauncher(res) : null;
|
|
64703
65159
|
const runtime = registered && registered !== "invalid" && registered.kind === "node" ? registered.runtime : "node";
|
|
64704
|
-
const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) =>
|
|
65160
|
+
const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) => path31.join(res.cursorPluginDir, rel)).filter((p) => !validNodeEntry(p, runtime, res.env)).map((p) => `cursor: ${p}`) : [];
|
|
64705
65161
|
if (hosts.includes("cursor")) {
|
|
64706
65162
|
if (registered === "invalid") {
|
|
64707
65163
|
missing.push(`cursor: canonical workit MCP launcher in ${res.cursorMcp}`);
|
|
@@ -64710,13 +65166,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64710
65166
|
}
|
|
64711
65167
|
const hook = registeredCursorHook(res);
|
|
64712
65168
|
if (hook === "invalid") {
|
|
64713
|
-
missing.push(`cursor: canonical session-start hook in ${
|
|
65169
|
+
missing.push(`cursor: canonical session-start hook in ${path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")}`);
|
|
64714
65170
|
} else if (hook !== null && !isCanonicalCursorHook(hook, res) && !validLocalDistHook(hook, res)) {
|
|
64715
|
-
missing.push(`cursor: canonical session-start hook in ${
|
|
65171
|
+
missing.push(`cursor: canonical session-start hook in ${path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")} (registered ${hook})`);
|
|
64716
65172
|
}
|
|
64717
65173
|
}
|
|
64718
65174
|
if (dev) {
|
|
64719
|
-
missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) =>
|
|
65175
|
+
missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) => existsSync14(p))).map((slot) => `${h}: ${slot.join(" or ")}`)));
|
|
64720
65176
|
}
|
|
64721
65177
|
if (missing.length > 0) {
|
|
64722
65178
|
return {
|
|
@@ -64741,21 +65197,21 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64741
65197
|
}, CURSOR_HOOK_FIX = "Run `workit init` and select Cursor to install the bundled hook", checkCursorHook = (res) => {
|
|
64742
65198
|
if (!hostsFor(res.host).includes("cursor"))
|
|
64743
65199
|
return { id: "cursor_hook", status: "pass", detail: "cursor hook not inspected on this host" };
|
|
64744
|
-
if (!
|
|
65200
|
+
if (!existsSync14(res.cursorPluginDir))
|
|
64745
65201
|
return {
|
|
64746
65202
|
id: "cursor_hook",
|
|
64747
65203
|
status: "pass",
|
|
64748
65204
|
detail: "no Cursor plugin install — hook launcher not inspected"
|
|
64749
65205
|
};
|
|
64750
|
-
const launcher =
|
|
64751
|
-
if (!
|
|
65206
|
+
const launcher = path31.join(res.cursorPluginDir, "hooks", "launch.mjs");
|
|
65207
|
+
if (!existsSync14(launcher))
|
|
64752
65208
|
return {
|
|
64753
65209
|
id: "cursor_hook",
|
|
64754
65210
|
status: "warn",
|
|
64755
65211
|
detail: `cursor hook launcher mode: missing — ${launcher} is absent (an install from before the pinned launcher)`,
|
|
64756
65212
|
fix: CURSOR_HOOK_FIX
|
|
64757
65213
|
};
|
|
64758
|
-
const hooksFile =
|
|
65214
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
64759
65215
|
const registered = readJson(hooksFile);
|
|
64760
65216
|
const sessionCommand = registered?.hooks?.sessionStart?.[0]?.command;
|
|
64761
65217
|
const offLauncher = [
|
|
@@ -64770,7 +65226,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64770
65226
|
fix: "Re-run install-cursor-plugin.sh (or `workit init` with Cursor) to rewrite the hook entries"
|
|
64771
65227
|
};
|
|
64772
65228
|
const started = performance.now();
|
|
64773
|
-
const probe =
|
|
65229
|
+
const probe = spawnSync14("node", [launcher, "--probe", "workit-cursor-hook"], {
|
|
64774
65230
|
encoding: "utf8",
|
|
64775
65231
|
env: { ...res.env, WORKIT_CURSOR_HOOK_NPX_OFFLINE: "1" },
|
|
64776
65232
|
timeout: 40000,
|
|
@@ -64817,15 +65273,15 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64817
65273
|
return { id: "cursor_hook", status: "pass", detail: `${label}; probe ${ms} ms` };
|
|
64818
65274
|
}, SILENT_HOOK_GRACE_MS, mtimeMs = (file) => {
|
|
64819
65275
|
try {
|
|
64820
|
-
return
|
|
65276
|
+
return statSync5(file).mtimeMs;
|
|
64821
65277
|
} catch {
|
|
64822
65278
|
return null;
|
|
64823
65279
|
}
|
|
64824
65280
|
}, silentCursorHooks = (res) => {
|
|
64825
|
-
const session = mtimeMs(
|
|
65281
|
+
const session = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-session-last-start"));
|
|
64826
65282
|
if (session === null || Date.now() - session < SILENT_HOOK_GRACE_MS)
|
|
64827
65283
|
return null;
|
|
64828
|
-
const hook = mtimeMs(
|
|
65284
|
+
const hook = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-hook-last-run"));
|
|
64829
65285
|
if (hook !== null && hook >= session)
|
|
64830
65286
|
return null;
|
|
64831
65287
|
return `Cursor started the Workit MCP server at ${new Date(session).toISOString()} but no Workit hook has run since${hook === null ? " (none ever)" : ""} — if the agent ran in that window, Cursor is not running the plugin hooks and Workit enforcement is off`;
|
|
@@ -64866,7 +65322,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64866
65322
|
return "fragile-cache";
|
|
64867
65323
|
if (entry.startsWith("file:")) {
|
|
64868
65324
|
const target = entry.replace(/^file:\/\//, "").replace(/^file:/, "");
|
|
64869
|
-
return
|
|
65325
|
+
return existsSync14(target) ? "ok" : "missing-file";
|
|
64870
65326
|
}
|
|
64871
65327
|
return "ok";
|
|
64872
65328
|
}, checkStalePin = (res) => {
|
|
@@ -64877,7 +65333,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64877
65333
|
detail: "opencode pin not inspected on the cursor host"
|
|
64878
65334
|
};
|
|
64879
65335
|
}
|
|
64880
|
-
if (!
|
|
65336
|
+
if (!existsSync14(res.opencodeConfig)) {
|
|
64881
65337
|
return {
|
|
64882
65338
|
id: "stale_pin",
|
|
64883
65339
|
status: "pass",
|
|
@@ -64921,8 +65377,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64921
65377
|
}
|
|
64922
65378
|
return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
|
|
64923
65379
|
}, pluginMcpSelectors = (res) => {
|
|
64924
|
-
const p =
|
|
64925
|
-
if (!
|
|
65380
|
+
const p = path31.join(res.cursorPluginDir, "mcp.json");
|
|
65381
|
+
if (!existsSync14(p))
|
|
64926
65382
|
return null;
|
|
64927
65383
|
const cfg = readJson(p);
|
|
64928
65384
|
const server = cfg?.mcpServers?.workit;
|
|
@@ -64944,7 +65400,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64944
65400
|
if (!cmd)
|
|
64945
65401
|
return null;
|
|
64946
65402
|
try {
|
|
64947
|
-
const r =
|
|
65403
|
+
const r = spawnSync14(cmd, ["view", pkgName, "version"], {
|
|
64948
65404
|
encoding: "utf8",
|
|
64949
65405
|
timeout: 20000,
|
|
64950
65406
|
env: res.env
|
|
@@ -64955,13 +65411,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64955
65411
|
return null;
|
|
64956
65412
|
}
|
|
64957
65413
|
}, installedPluginVersion = (res) => {
|
|
64958
|
-
const pkg = readJson(
|
|
65414
|
+
const pkg = readJson(path31.join(res.cursorPluginDir, "package.json"));
|
|
64959
65415
|
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
64960
65416
|
}, installedOpenCodeCacheVersion = (res) => {
|
|
64961
|
-
const pkg = readJson(
|
|
65417
|
+
const pkg = readJson(path31.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
|
|
64962
65418
|
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
64963
65419
|
}, checkOpenCodePackageCache = (res) => {
|
|
64964
|
-
if (!
|
|
65420
|
+
if (!existsSync14(res.opencodeConfig)) {
|
|
64965
65421
|
return {
|
|
64966
65422
|
id: "stale_install",
|
|
64967
65423
|
status: "pass",
|
|
@@ -65035,7 +65491,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65035
65491
|
detail: "cursor plugin not inspected on this host"
|
|
65036
65492
|
};
|
|
65037
65493
|
}
|
|
65038
|
-
if (
|
|
65494
|
+
if (existsSync14(res.cursorPluginDir) && lstatSync5(res.cursorPluginDir).isSymbolicLink()) {
|
|
65039
65495
|
let target = "";
|
|
65040
65496
|
try {
|
|
65041
65497
|
target = readlinkSync2(res.cursorPluginDir);
|
|
@@ -65061,7 +65517,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65061
65517
|
fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
|
|
65062
65518
|
};
|
|
65063
65519
|
}
|
|
65064
|
-
const hooksFile =
|
|
65520
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
65065
65521
|
const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
|
|
65066
65522
|
const canonicalHook = canonicalCursorHook;
|
|
65067
65523
|
const staleHook = hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
|
|
@@ -65073,7 +65529,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65073
65529
|
fix: "Re-run install-cursor-plugin.sh — it rewrites the sessionStart hook to the canonical pinned launcher"
|
|
65074
65530
|
};
|
|
65075
65531
|
}
|
|
65076
|
-
const hookDrift =
|
|
65532
|
+
const hookDrift = existsSync14(hooksFile) ? cursorHookDrift(readJson(hooksFile), res.cursorPluginDir) : [];
|
|
65077
65533
|
if (hookDrift.length > 0) {
|
|
65078
65534
|
return {
|
|
65079
65535
|
id: "stale_install",
|
|
@@ -65083,7 +65539,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65083
65539
|
};
|
|
65084
65540
|
}
|
|
65085
65541
|
const installed = installedPluginVersion(res);
|
|
65086
|
-
const source = res.dev ? readJson(
|
|
65542
|
+
const source = res.dev ? readJson(path31.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path31.join(packageRoot(), "package.json"))?.version ?? null;
|
|
65087
65543
|
const localDist = mcpSelectors === null && hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && hookCmd.startsWith("node ");
|
|
65088
65544
|
if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
|
|
65089
65545
|
return {
|
|
@@ -65095,7 +65551,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65095
65551
|
}
|
|
65096
65552
|
if (localDist && installed !== null && source !== null && res.dev) {
|
|
65097
65553
|
const entry = /^node\s+(.+)$/.exec((hookCmd ?? "").trim())?.[1]?.trim() ?? "";
|
|
65098
|
-
const sourceBundle = entry &&
|
|
65554
|
+
const sourceBundle = entry && path31.isAbsolute(entry) ? path31.join(res.dev, "packages", "workit-cursor", "dist", path31.basename(entry)) : "";
|
|
65099
65555
|
if (entry && sourceBundle) {
|
|
65100
65556
|
const installedHash = bundleHashOfFile(entry);
|
|
65101
65557
|
const sourceHash = bundleHashOfFile(sourceBundle);
|
|
@@ -65103,7 +65559,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65103
65559
|
return {
|
|
65104
65560
|
id: "stale_install",
|
|
65105
65561
|
status: "fail",
|
|
65106
|
-
detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${
|
|
65562
|
+
detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${path31.basename(entry)} hash mismatch)`,
|
|
65107
65563
|
fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
|
|
65108
65564
|
};
|
|
65109
65565
|
}
|
|
@@ -65157,13 +65613,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65157
65613
|
const problems = [];
|
|
65158
65614
|
const opencodeHost = res.host !== "cursor";
|
|
65159
65615
|
const cursorHost = res.host !== "opencode";
|
|
65160
|
-
if (opencodeHost &&
|
|
65616
|
+
if (opencodeHost && existsSync14(res.opencodeConfig)) {
|
|
65161
65617
|
const cfg = readJson(res.opencodeConfig);
|
|
65162
65618
|
const entries = pluginEntries(cfg);
|
|
65163
65619
|
if (entries.length > 1)
|
|
65164
65620
|
problems.push(`opencode registers ${entries.length} workit plugin entries`);
|
|
65165
65621
|
}
|
|
65166
|
-
if (cursorHost &&
|
|
65622
|
+
if (cursorHost && existsSync14(res.cursorSettings)) {
|
|
65167
65623
|
const settings = readJson(res.cursorSettings);
|
|
65168
65624
|
const enabled = settings?.enabled_plugins;
|
|
65169
65625
|
if (enabled && typeof enabled === "object") {
|
|
@@ -65178,7 +65634,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65178
65634
|
if (dirs.length > 1)
|
|
65179
65635
|
problems.push(`cursor plugin_dirs has ${dirs.length} workit entries`);
|
|
65180
65636
|
}
|
|
65181
|
-
if (cursorHost &&
|
|
65637
|
+
if (cursorHost && existsSync14(res.cursorMcp)) {
|
|
65182
65638
|
const mcp = readJson(res.cursorMcp);
|
|
65183
65639
|
const servers = mcp?.mcpServers ?? {};
|
|
65184
65640
|
if (servers && typeof servers === "object") {
|
|
@@ -65203,17 +65659,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65203
65659
|
}, checkMalformedConfig = (res) => {
|
|
65204
65660
|
const files = [];
|
|
65205
65661
|
for (const name of ["config.json", "youtrack.json", "vcs.json", "workspaces.json"]) {
|
|
65206
|
-
const p =
|
|
65207
|
-
if (
|
|
65662
|
+
const p = path31.join(res.configDir, name);
|
|
65663
|
+
if (existsSync14(p))
|
|
65208
65664
|
files.push(p);
|
|
65209
65665
|
}
|
|
65210
65666
|
const opencodeHost = res.host !== "cursor";
|
|
65211
65667
|
const cursorHost = res.host !== "opencode";
|
|
65212
|
-
if (opencodeHost &&
|
|
65668
|
+
if (opencodeHost && existsSync14(res.opencodeConfig))
|
|
65213
65669
|
files.push(res.opencodeConfig);
|
|
65214
|
-
if (cursorHost &&
|
|
65670
|
+
if (cursorHost && existsSync14(res.cursorSettings))
|
|
65215
65671
|
files.push(res.cursorSettings);
|
|
65216
|
-
if (cursorHost &&
|
|
65672
|
+
if (cursorHost && existsSync14(res.cursorMcp))
|
|
65217
65673
|
files.push(res.cursorMcp);
|
|
65218
65674
|
const bad = files.filter((p) => !parsesAsConfigObject(p));
|
|
65219
65675
|
if (bad.length === 0)
|
|
@@ -65292,19 +65748,90 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65292
65748
|
detail: `current directory ${res.cwd} does not match any configured workspace`,
|
|
65293
65749
|
fix: `Add a workspace glob matching this directory to ${file} or run /wk-init`
|
|
65294
65750
|
};
|
|
65751
|
+
}, matchedWorkspace = (res) => {
|
|
65752
|
+
try {
|
|
65753
|
+
return resolveWorkspaceFrom(res.cwd, res.configDir, res.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
|
|
65754
|
+
} catch {
|
|
65755
|
+
return null;
|
|
65756
|
+
}
|
|
65757
|
+
}, SESSION_HOOK_FIX = "workit doctor --fix", sessionHookFinding = (hook) => {
|
|
65758
|
+
const slot = `${SESSION_HOOK_NAME} hook`;
|
|
65759
|
+
switch (hook.state) {
|
|
65760
|
+
case "not_git":
|
|
65761
|
+
return { status: "pass", detail: `not inside a git work tree — skipping the ${slot}` };
|
|
65762
|
+
case "installed":
|
|
65763
|
+
return {
|
|
65764
|
+
status: "pass",
|
|
65765
|
+
detail: `${slot} ${hook.hookPath} adds the Workit-Session trailer to plain git commits`
|
|
65766
|
+
};
|
|
65767
|
+
case "manual":
|
|
65768
|
+
return hook.helperCurrent ? {
|
|
65769
|
+
status: "pass",
|
|
65770
|
+
detail: `${hook.manualTarget} adds the Workit-Session trailer to plain git commits (via ${hook.via})`
|
|
65771
|
+
} : {
|
|
65772
|
+
status: "warn",
|
|
65773
|
+
detail: `${hook.manualTarget} runs the Workit helper (via ${hook.via}), but ${hook.helperPath} is missing or an older version`,
|
|
65774
|
+
fix: SESSION_HOOK_FIX
|
|
65775
|
+
};
|
|
65776
|
+
case "missing":
|
|
65777
|
+
return {
|
|
65778
|
+
status: "warn",
|
|
65779
|
+
detail: `no ${slot} at ${hook.hookPath}: plain git commits from an agent session get no Workit-Session trailer`,
|
|
65780
|
+
fix: SESSION_HOOK_FIX
|
|
65781
|
+
};
|
|
65782
|
+
case "outdated":
|
|
65783
|
+
return {
|
|
65784
|
+
status: "warn",
|
|
65785
|
+
detail: `the Workit ${slot} at ${hook.hookPath} or its helper ${hook.helperPath} is missing or an older version`,
|
|
65786
|
+
fix: SESSION_HOOK_FIX
|
|
65787
|
+
};
|
|
65788
|
+
case "blocked":
|
|
65789
|
+
return {
|
|
65790
|
+
status: "warn",
|
|
65791
|
+
detail: `plain git commits get no Workit-Session trailer and --fix will not install the ${slot}: ${hook.reason}`,
|
|
65792
|
+
fix: hook.helperCurrent ? hook.manual : `${SESSION_HOOK_FIX} (writes ${hook.helperPath}), then ${hook.manual}`
|
|
65793
|
+
};
|
|
65794
|
+
}
|
|
65795
|
+
}, checkSessionHook = (res) => {
|
|
65796
|
+
if (!matchedWorkspace(res))
|
|
65797
|
+
return {
|
|
65798
|
+
id: "session_hook",
|
|
65799
|
+
status: "pass",
|
|
65800
|
+
detail: `not in a Workit workspace — skipping the ${SESSION_HOOK_NAME} session hook`
|
|
65801
|
+
};
|
|
65802
|
+
const hook = inspectSessionHook(res.cwd, res.env);
|
|
65803
|
+
const finding = sessionHookFinding(hook);
|
|
65804
|
+
if (!hook.leftover)
|
|
65805
|
+
return { id: "session_hook", ...finding };
|
|
65806
|
+
return {
|
|
65807
|
+
id: "session_hook",
|
|
65808
|
+
status: "warn",
|
|
65809
|
+
detail: `${finding.detail}; ${hook.leftover}`,
|
|
65810
|
+
fix: finding.fix ? `${finding.fix}; ${hook.leftover}` : hook.leftover
|
|
65811
|
+
};
|
|
65812
|
+
}, fixSessionHook = (options = {}) => {
|
|
65813
|
+
const res = resolve(options);
|
|
65814
|
+
const workspace = matchedWorkspace(res);
|
|
65815
|
+
if (!workspace)
|
|
65816
|
+
return {
|
|
65817
|
+
action: "skipped",
|
|
65818
|
+
detail: `${res.cwd} is not in a Workit workspace; no hook installed`,
|
|
65819
|
+
workspace: null
|
|
65820
|
+
};
|
|
65821
|
+
return { ...installSessionHook(res.cwd, res.env), workspace: workspace.name };
|
|
65295
65822
|
}, isPlaceholder = (p) => {
|
|
65296
65823
|
try {
|
|
65297
|
-
return
|
|
65824
|
+
return readFileSync14(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
|
|
65298
65825
|
} catch {
|
|
65299
65826
|
return false;
|
|
65300
65827
|
}
|
|
65301
65828
|
}, checkCredentialMetadata = (res) => {
|
|
65302
65829
|
const tokenPaths = [];
|
|
65303
|
-
const youtrackJson = readJson(
|
|
65830
|
+
const youtrackJson = readJson(path31.join(res.configDir, "youtrack.json"));
|
|
65304
65831
|
if (youtrackJson) {
|
|
65305
|
-
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile :
|
|
65306
|
-
} else if (
|
|
65307
|
-
tokenPaths.push(
|
|
65832
|
+
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path31.join(res.configDir, "youtrack.token"));
|
|
65833
|
+
} else if (existsSync14(path31.join(res.configDir, "youtrack.token"))) {
|
|
65834
|
+
tokenPaths.push(path31.join(res.configDir, "youtrack.token"));
|
|
65308
65835
|
}
|
|
65309
65836
|
if (tokenPaths.length === 0) {
|
|
65310
65837
|
return {
|
|
@@ -65315,13 +65842,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65315
65842
|
}
|
|
65316
65843
|
const problems = [];
|
|
65317
65844
|
for (const raw of tokenPaths) {
|
|
65318
|
-
const p =
|
|
65319
|
-
if (!
|
|
65845
|
+
const p = path31.isAbsolute(raw) ? raw : path31.resolve(res.configDir, raw);
|
|
65846
|
+
if (!existsSync14(p)) {
|
|
65320
65847
|
problems.push(`${p} is missing`);
|
|
65321
65848
|
continue;
|
|
65322
65849
|
}
|
|
65323
65850
|
if (process.platform !== "win32") {
|
|
65324
|
-
const mode =
|
|
65851
|
+
const mode = statSync5(p).mode & 511;
|
|
65325
65852
|
if (mode !== 384)
|
|
65326
65853
|
problems.push(`${p} must be mode 0600 (found ${mode.toString(8)})`);
|
|
65327
65854
|
}
|
|
@@ -65383,7 +65910,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65383
65910
|
}, defaultIdentityProbes = (env) => ({
|
|
65384
65911
|
origin: (cwd) => {
|
|
65385
65912
|
try {
|
|
65386
|
-
const out =
|
|
65913
|
+
const out = spawnSync14("git", ["remote", "get-url", "origin"], {
|
|
65387
65914
|
cwd,
|
|
65388
65915
|
encoding: "utf8",
|
|
65389
65916
|
env
|
|
@@ -65395,7 +65922,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65395
65922
|
},
|
|
65396
65923
|
ghLogin: (e) => {
|
|
65397
65924
|
try {
|
|
65398
|
-
const out =
|
|
65925
|
+
const out = spawnSync14("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
|
|
65399
65926
|
const login = (out.stdout ?? "").trim();
|
|
65400
65927
|
return out.status === 0 && login ? login : null;
|
|
65401
65928
|
} catch {
|
|
@@ -65404,7 +65931,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65404
65931
|
},
|
|
65405
65932
|
glabLogin: (e) => {
|
|
65406
65933
|
try {
|
|
65407
|
-
const out =
|
|
65934
|
+
const out = spawnSync14("glab", ["api", "user", "--jq", ".username"], {
|
|
65408
65935
|
encoding: "utf8",
|
|
65409
65936
|
env: e
|
|
65410
65937
|
});
|
|
@@ -65416,7 +65943,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65416
65943
|
},
|
|
65417
65944
|
sshLogin: (host) => {
|
|
65418
65945
|
try {
|
|
65419
|
-
const out =
|
|
65946
|
+
const out = spawnSync14("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
|
|
65420
65947
|
encoding: "utf8",
|
|
65421
65948
|
env
|
|
65422
65949
|
});
|
|
@@ -65431,7 +65958,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65431
65958
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
65432
65959
|
if (!remoteHost)
|
|
65433
65960
|
return { id: "github_identity", status: "pass", detail: "no GitHub remote configured" };
|
|
65434
|
-
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ??
|
|
65961
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
|
|
65435
65962
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
65436
65963
|
if (workspace.error)
|
|
65437
65964
|
return {
|
|
@@ -65459,7 +65986,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65459
65986
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
65460
65987
|
if (!remoteHost)
|
|
65461
65988
|
return { id: "gitlab_identity", status: "pass", detail: "no GitLab remote configured" };
|
|
65462
|
-
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ??
|
|
65989
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
|
|
65463
65990
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
65464
65991
|
if (workspace.error)
|
|
65465
65992
|
return {
|
|
@@ -65485,11 +66012,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65485
66012
|
{ surface: "SSH", login: probes.sshLogin(remoteHost) }
|
|
65486
66013
|
]);
|
|
65487
66014
|
}, checkLogWritable = (res) => {
|
|
65488
|
-
const logsDir =
|
|
65489
|
-
const probe =
|
|
66015
|
+
const logsDir = path31.join(res.stateDir, "logs");
|
|
66016
|
+
const probe = path31.join(logsDir, "doctor-probe.tmp");
|
|
65490
66017
|
try {
|
|
65491
|
-
|
|
65492
|
-
|
|
66018
|
+
mkdirSync6(logsDir, { recursive: true, mode: 448 });
|
|
66019
|
+
writeFileSync7(probe, `{"probe":true}
|
|
65493
66020
|
`, { mode: 384 });
|
|
65494
66021
|
return {
|
|
65495
66022
|
id: "log_writable",
|
|
@@ -65576,7 +66103,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65576
66103
|
}, CLI_PACKAGE = "@brainervirus/workit-cli", SEMVER, WORKIT_PROBE_TIMEOUT_MS = 1e4, workitVersions, workitVersionAt = (bin, env) => {
|
|
65577
66104
|
let key;
|
|
65578
66105
|
try {
|
|
65579
|
-
const st =
|
|
66106
|
+
const st = statSync5(bin);
|
|
65580
66107
|
key = `${bin}:${st.ino}:${st.size}:${st.mtimeMs}`;
|
|
65581
66108
|
} catch {
|
|
65582
66109
|
return { version: null, timedOut: false };
|
|
@@ -65585,12 +66112,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65585
66112
|
if (cached)
|
|
65586
66113
|
return cached;
|
|
65587
66114
|
const viaShell = process.platform === "win32" && /\.(?:cmd|bat)$/i.test(bin);
|
|
65588
|
-
const r = viaShell ?
|
|
66115
|
+
const r = viaShell ? spawnSync14(`"${bin}" --version`, {
|
|
65589
66116
|
encoding: "utf8",
|
|
65590
66117
|
env,
|
|
65591
66118
|
timeout: WORKIT_PROBE_TIMEOUT_MS,
|
|
65592
66119
|
shell: true
|
|
65593
|
-
}) :
|
|
66120
|
+
}) : spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout: WORKIT_PROBE_TIMEOUT_MS });
|
|
65594
66121
|
const timedOut = r.error !== undefined && "code" in r.error && r.error.code === "ETIMEDOUT";
|
|
65595
66122
|
const version = r.status === 0 ? (r.stdout ?? "").match(SEMVER)?.[0] ?? null : null;
|
|
65596
66123
|
const probe = { version: timedOut ? null : version, timedOut };
|
|
@@ -65680,6 +66207,7 @@ var init_doctor = __esm(() => {
|
|
|
65680
66207
|
init_workspaces();
|
|
65681
66208
|
init_host_install();
|
|
65682
66209
|
init_skill_manifests();
|
|
66210
|
+
init_session_hook();
|
|
65683
66211
|
OPENCODE_V1_FIX = `OpenCode < ${SUPPORT_MATRIX.opencode.minimum} cannot load Workit 3 (V2 plugin API only): upgrade OpenCode to ${SUPPORT_MATRIX.opencode.minimum}+, or stay on Workit 2.x by pinning "@brainervirus/workit-opencode@2" in the opencode.json "plugin" array`;
|
|
65684
66212
|
AGENT_MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
65685
66213
|
canonicalCursorHook = cursorHooksEntry().command;
|
|
@@ -65706,6 +66234,7 @@ var init_doctor = __esm(() => {
|
|
|
65706
66234
|
checkMalformedConfig,
|
|
65707
66235
|
checkWorkspaceMismatch,
|
|
65708
66236
|
checkWorkspaceLock,
|
|
66237
|
+
checkSessionHook,
|
|
65709
66238
|
checkCredentialMetadata,
|
|
65710
66239
|
checkGithubIdentity,
|
|
65711
66240
|
checkGitLabIdentity,
|
|
@@ -65727,20 +66256,20 @@ var init_doctor = __esm(() => {
|
|
|
65727
66256
|
import {
|
|
65728
66257
|
copyFileSync as copyFileSync4,
|
|
65729
66258
|
cpSync as cpSync4,
|
|
65730
|
-
existsSync as
|
|
65731
|
-
lstatSync as
|
|
65732
|
-
mkdirSync as
|
|
66259
|
+
existsSync as existsSync15,
|
|
66260
|
+
lstatSync as lstatSync6,
|
|
66261
|
+
mkdirSync as mkdirSync7,
|
|
65733
66262
|
mkdtempSync as mkdtempSync2,
|
|
65734
|
-
readFileSync as
|
|
66263
|
+
readFileSync as readFileSync15,
|
|
65735
66264
|
readdirSync as readdirSync8,
|
|
65736
66265
|
realpathSync as realpathSync7,
|
|
65737
|
-
renameSync as
|
|
65738
|
-
rmSync as
|
|
65739
|
-
statSync as
|
|
65740
|
-
writeFileSync as
|
|
66266
|
+
renameSync as renameSync4,
|
|
66267
|
+
rmSync as rmSync4,
|
|
66268
|
+
statSync as statSync6,
|
|
66269
|
+
writeFileSync as writeFileSync8
|
|
65741
66270
|
} from "node:fs";
|
|
65742
66271
|
import os9 from "node:os";
|
|
65743
|
-
import
|
|
66272
|
+
import path32 from "node:path";
|
|
65744
66273
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
65745
66274
|
function parseList(raw) {
|
|
65746
66275
|
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -65784,7 +66313,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65784
66313
|
const current = readConfigFromDir(state.configDir);
|
|
65785
66314
|
mutations.push({
|
|
65786
66315
|
type: "merge-json",
|
|
65787
|
-
path:
|
|
66316
|
+
path: path32.join(state.configDir, "config.json"),
|
|
65788
66317
|
value: {
|
|
65789
66318
|
locale: values.locale,
|
|
65790
66319
|
localeOptions: current.localeOptions,
|
|
@@ -65810,17 +66339,17 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65810
66339
|
if (blocked.length === 0) {
|
|
65811
66340
|
mutations.push({
|
|
65812
66341
|
type: "update-workspaces",
|
|
65813
|
-
path:
|
|
66342
|
+
path: path32.join(state.configDir, "workspaces.json"),
|
|
65814
66343
|
entries: values.workspaces,
|
|
65815
66344
|
expectedRevision: diskWorkspaceResult.revision
|
|
65816
66345
|
});
|
|
65817
66346
|
}
|
|
65818
66347
|
}
|
|
65819
66348
|
if (values.baseUrl.trim()) {
|
|
65820
|
-
const ytPath =
|
|
66349
|
+
const ytPath = path32.join(state.configDir, "youtrack.json");
|
|
65821
66350
|
const ytExisting = readConfigRecord(ytPath);
|
|
65822
66351
|
const ytConfigured = configuredTokenPath(ytExisting, "tokenFile");
|
|
65823
|
-
const tokenPath = resolveTokenPath(ytConfigured,
|
|
66352
|
+
const tokenPath = resolveTokenPath(ytConfigured, path32.join(state.configDir, "youtrack.token"), values.tokenPaths?.youtrack);
|
|
65824
66353
|
const draft = youtrackDraft(values, tokenPath);
|
|
65825
66354
|
if (ytConfigured !== null && tokenPath !== ytConfigured) {
|
|
65826
66355
|
delete draft.tokenFile;
|
|
@@ -65836,7 +66365,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65836
66365
|
path: ytPath,
|
|
65837
66366
|
value: draft
|
|
65838
66367
|
});
|
|
65839
|
-
if (
|
|
66368
|
+
if (existsSync15(tokenPath))
|
|
65840
66369
|
preserved.push(tokenPath);
|
|
65841
66370
|
else
|
|
65842
66371
|
mutations.push({
|
|
@@ -65848,7 +66377,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65848
66377
|
});
|
|
65849
66378
|
}
|
|
65850
66379
|
if (values.vcsProvider !== "skip") {
|
|
65851
|
-
const vcsPath =
|
|
66380
|
+
const vcsPath = path32.join(state.configDir, "vcs.json");
|
|
65852
66381
|
mutations.push({
|
|
65853
66382
|
type: "merge-json",
|
|
65854
66383
|
path: vcsPath,
|
|
@@ -65877,7 +66406,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65877
66406
|
mutations.push({
|
|
65878
66407
|
type: "install-host",
|
|
65879
66408
|
platform: "cursor",
|
|
65880
|
-
path:
|
|
66409
|
+
path: path32.join(paths.home, ".cursor", "plugins", "local", ".workit-package-bootstrap"),
|
|
65881
66410
|
commands
|
|
65882
66411
|
});
|
|
65883
66412
|
}
|
|
@@ -65890,7 +66419,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65890
66419
|
mutations.push({
|
|
65891
66420
|
type: "install-host",
|
|
65892
66421
|
platform,
|
|
65893
|
-
path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ?
|
|
66422
|
+
path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ? path32.join(env.CODEX_HOME ?? path32.join(paths.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : path32.join(env.PI_CODING_AGENT_DIR ?? path32.join(paths.home, ".pi", "agent"), "settings.json"),
|
|
65894
66423
|
commands
|
|
65895
66424
|
});
|
|
65896
66425
|
}
|
|
@@ -65898,9 +66427,9 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65898
66427
|
}
|
|
65899
66428
|
}
|
|
65900
66429
|
if (values.applyProject) {
|
|
65901
|
-
const root =
|
|
65902
|
-
const gitignorePath =
|
|
65903
|
-
const existing =
|
|
66430
|
+
const root = path32.resolve(opts.cwd ?? process.cwd());
|
|
66431
|
+
const gitignorePath = path32.join(root, ".gitignore");
|
|
66432
|
+
const existing = existsSync15(gitignorePath) ? readFileSync15(gitignorePath, "utf8") : "";
|
|
65904
66433
|
const existingLines = new Set(existing.split(`
|
|
65905
66434
|
`).map((l) => l.trim()).filter(Boolean));
|
|
65906
66435
|
const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
|
|
@@ -65936,10 +66465,10 @@ function deepMerge(base, patch) {
|
|
|
65936
66465
|
return out;
|
|
65937
66466
|
}
|
|
65938
66467
|
function applyMutation(m) {
|
|
65939
|
-
const dir =
|
|
66468
|
+
const dir = path32.dirname(m.path);
|
|
65940
66469
|
switch (m.type) {
|
|
65941
66470
|
case "create-file": {
|
|
65942
|
-
|
|
66471
|
+
mkdirSync7(dir, { recursive: true });
|
|
65943
66472
|
const res = writeFileExclusive(m.path, m.content, m.mode);
|
|
65944
66473
|
return res === "created" ? { platform: "core", file: m.path, status: "Installed" } : {
|
|
65945
66474
|
platform: "core",
|
|
@@ -65962,8 +66491,8 @@ function applyMutation(m) {
|
|
|
65962
66491
|
if (existing.kind === "record" && JSON.stringify(existing.value) === JSON.stringify(merged)) {
|
|
65963
66492
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
65964
66493
|
}
|
|
65965
|
-
|
|
65966
|
-
|
|
66494
|
+
mkdirSync7(dir, { recursive: true });
|
|
66495
|
+
writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
|
|
65967
66496
|
`, "utf8");
|
|
65968
66497
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
65969
66498
|
}
|
|
@@ -66004,12 +66533,12 @@ function applyMutation(m) {
|
|
|
66004
66533
|
`;
|
|
66005
66534
|
if (prev === next)
|
|
66006
66535
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
66007
|
-
|
|
66536
|
+
mkdirSync7(dir, { recursive: true });
|
|
66008
66537
|
const tmp = `${m.path}.${process.pid}.tmp`;
|
|
66009
66538
|
try {
|
|
66010
|
-
|
|
66539
|
+
writeFileSync8(tmp, next, "utf8");
|
|
66011
66540
|
if (workspacesRevision(readFileSafe(m.path)) !== m.expectedRevision) {
|
|
66012
|
-
|
|
66541
|
+
rmSync4(tmp, { force: true });
|
|
66013
66542
|
return {
|
|
66014
66543
|
platform: "core",
|
|
66015
66544
|
file: m.path,
|
|
@@ -66017,9 +66546,9 @@ function applyMutation(m) {
|
|
|
66017
66546
|
detail: "workspace config changed while applying the preview; rebuild and review it"
|
|
66018
66547
|
};
|
|
66019
66548
|
}
|
|
66020
|
-
|
|
66549
|
+
renameSync4(tmp, m.path);
|
|
66021
66550
|
} catch (error) {
|
|
66022
|
-
|
|
66551
|
+
rmSync4(tmp, { force: true });
|
|
66023
66552
|
return {
|
|
66024
66553
|
platform: "core",
|
|
66025
66554
|
file: m.path,
|
|
@@ -66042,11 +66571,11 @@ function applyMutation(m) {
|
|
|
66042
66571
|
detail: "all entries already present"
|
|
66043
66572
|
};
|
|
66044
66573
|
}
|
|
66045
|
-
|
|
66574
|
+
mkdirSync7(dir, { recursive: true });
|
|
66046
66575
|
const separator = existing && !existing.endsWith(`
|
|
66047
66576
|
`) ? `
|
|
66048
66577
|
` : "";
|
|
66049
|
-
|
|
66578
|
+
writeFileSync8(m.path, existing + separator + (existing ? `
|
|
66050
66579
|
` : "") + add.join(`
|
|
66051
66580
|
`) + `
|
|
66052
66581
|
`, "utf8");
|
|
@@ -66085,8 +66614,8 @@ function applyMutation(m) {
|
|
|
66085
66614
|
detail: "already configured"
|
|
66086
66615
|
};
|
|
66087
66616
|
}
|
|
66088
|
-
|
|
66089
|
-
|
|
66617
|
+
mkdirSync7(path32.dirname(m.path), { recursive: true });
|
|
66618
|
+
writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
|
|
66090
66619
|
`, "utf8");
|
|
66091
66620
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
66092
66621
|
}
|
|
@@ -66094,23 +66623,23 @@ function applyMutation(m) {
|
|
|
66094
66623
|
}
|
|
66095
66624
|
function adapterRoot(platform, res, preferInstalledAdapter = false) {
|
|
66096
66625
|
const candidates = [];
|
|
66097
|
-
const stagedCursor =
|
|
66626
|
+
const stagedCursor = path32.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap", "node_modules", "@brainervirus", "workit-cursor");
|
|
66098
66627
|
if (platform === "cursor" && preferInstalledAdapter)
|
|
66099
66628
|
candidates.push(stagedCursor);
|
|
66100
66629
|
if (res.dev) {
|
|
66101
|
-
candidates.push(
|
|
66630
|
+
candidates.push(path32.join(res.dev, "packages", `workit-${platform}`));
|
|
66102
66631
|
} else {
|
|
66103
|
-
candidates.push(
|
|
66104
|
-
let dir =
|
|
66632
|
+
candidates.push(path32.join(packageRoot(), "..", `workit-${platform}`));
|
|
66633
|
+
let dir = path32.resolve(res.cwd);
|
|
66105
66634
|
while (true) {
|
|
66106
|
-
candidates.push(
|
|
66107
|
-
const parent =
|
|
66635
|
+
candidates.push(path32.join(dir, "packages", `workit-${platform}`));
|
|
66636
|
+
const parent = path32.dirname(dir);
|
|
66108
66637
|
if (parent === dir)
|
|
66109
66638
|
break;
|
|
66110
66639
|
dir = parent;
|
|
66111
66640
|
}
|
|
66112
66641
|
}
|
|
66113
|
-
candidates.push(
|
|
66642
|
+
candidates.push(path32.join(res.home, ".local", "share", "workit", "packages", `workit-${platform}`));
|
|
66114
66643
|
if (platform === "cursor")
|
|
66115
66644
|
candidates.push(stagedCursor);
|
|
66116
66645
|
for (const candidate of candidates) {
|
|
@@ -66129,7 +66658,7 @@ function applyOpenCode(root, res) {
|
|
|
66129
66658
|
detail: "workit-opencode package has no loadable plugin entry (src/plugin.ts or dist/plugin.js)"
|
|
66130
66659
|
};
|
|
66131
66660
|
}
|
|
66132
|
-
|
|
66661
|
+
mkdirSync7(path32.dirname(res.opencodeConfig), { recursive: true });
|
|
66133
66662
|
const existing = readExisting(res.opencodeConfig);
|
|
66134
66663
|
if (existing.kind === "malformed") {
|
|
66135
66664
|
return {
|
|
@@ -66158,7 +66687,7 @@ function applyOpenCode(root, res) {
|
|
|
66158
66687
|
detail: "already registered"
|
|
66159
66688
|
};
|
|
66160
66689
|
}
|
|
66161
|
-
|
|
66690
|
+
writeFileSync8(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
|
|
66162
66691
|
`, "utf8");
|
|
66163
66692
|
return existing.kind === "record" ? {
|
|
66164
66693
|
platform: "opencode",
|
|
@@ -66174,54 +66703,54 @@ function applyOpenCode(root, res) {
|
|
|
66174
66703
|
}
|
|
66175
66704
|
function copyPluginDir(src, dest) {
|
|
66176
66705
|
const realSrc = realpathSync7(src);
|
|
66177
|
-
const marker =
|
|
66178
|
-
const destIsLink =
|
|
66706
|
+
const marker = path32.join(dest, ".workit-root");
|
|
66707
|
+
const destIsLink = existsSync15(dest) && lstatSync6(dest).isSymbolicLink();
|
|
66179
66708
|
const synced = !destIsLink && readFileSafe(marker)?.trim() === realSrc && samePluginContent(realSrc, dest, dest);
|
|
66180
66709
|
if (synced)
|
|
66181
66710
|
return "Skipped";
|
|
66182
|
-
const hadDir =
|
|
66711
|
+
const hadDir = existsSync15(dest);
|
|
66183
66712
|
const rules = preservedCursorRules(realSrc, dest);
|
|
66184
|
-
const parent =
|
|
66185
|
-
|
|
66186
|
-
const swap = mkdtempSync2(
|
|
66187
|
-
const stage =
|
|
66188
|
-
const backup =
|
|
66713
|
+
const parent = path32.dirname(dest);
|
|
66714
|
+
mkdirSync7(parent, { recursive: true });
|
|
66715
|
+
const swap = mkdtempSync2(path32.join(parent, `.${path32.basename(dest)}.swap-`));
|
|
66716
|
+
const stage = path32.join(swap, "stage");
|
|
66717
|
+
const backup = path32.join(swap, "backup");
|
|
66189
66718
|
try {
|
|
66190
66719
|
cpSync4(realSrc, stage, {
|
|
66191
66720
|
recursive: true,
|
|
66192
|
-
filter: (entry) => !
|
|
66721
|
+
filter: (entry) => !path32.relative(realSrc, entry).split(path32.sep).includes("node_modules")
|
|
66193
66722
|
});
|
|
66194
|
-
const stagedHooks =
|
|
66195
|
-
if (
|
|
66196
|
-
|
|
66723
|
+
const stagedHooks = path32.join(stage, CURSOR_HOOKS_FILE);
|
|
66724
|
+
if (existsSync15(stagedHooks))
|
|
66725
|
+
writeFileSync8(stagedHooks, localizedCursorHooks(readFileSync15(stagedHooks), dest));
|
|
66197
66726
|
for (const [name, content] of rules) {
|
|
66198
|
-
|
|
66199
|
-
|
|
66727
|
+
mkdirSync7(path32.join(stage, "rules"), { recursive: true });
|
|
66728
|
+
writeFileSync8(path32.join(stage, "rules", name), content);
|
|
66200
66729
|
}
|
|
66201
|
-
|
|
66730
|
+
writeFileSync8(path32.join(stage, ".workit-root"), realSrc + `
|
|
66202
66731
|
`, "utf8");
|
|
66203
66732
|
if (!samePluginContent(realSrc, stage, dest))
|
|
66204
66733
|
throw new Error("staged adapter content is incomplete");
|
|
66205
|
-
if (
|
|
66734
|
+
if (lstatSync6(stage).isSymbolicLink()) {
|
|
66206
66735
|
throw new Error("staged adapter resolved to a symlink — refusing fragile cache install");
|
|
66207
66736
|
}
|
|
66208
66737
|
if (hadDir)
|
|
66209
|
-
|
|
66738
|
+
renameSync4(dest, backup);
|
|
66210
66739
|
try {
|
|
66211
|
-
|
|
66740
|
+
renameSync4(stage, dest);
|
|
66212
66741
|
} catch (error) {
|
|
66213
|
-
if (hadDir && !
|
|
66214
|
-
|
|
66742
|
+
if (hadDir && !existsSync15(dest))
|
|
66743
|
+
renameSync4(backup, dest);
|
|
66215
66744
|
throw error;
|
|
66216
66745
|
}
|
|
66217
|
-
|
|
66746
|
+
rmSync4(backup, { recursive: true, force: true });
|
|
66218
66747
|
} finally {
|
|
66219
|
-
|
|
66748
|
+
rmSync4(swap, { recursive: true, force: true });
|
|
66220
66749
|
}
|
|
66221
66750
|
return hadDir ? "Configured" : "Installed";
|
|
66222
66751
|
}
|
|
66223
66752
|
function applyCursorSettings(root, res) {
|
|
66224
|
-
|
|
66753
|
+
mkdirSync7(path32.dirname(res.cursorSettings), { recursive: true });
|
|
66225
66754
|
const settingsExisting = readExisting(res.cursorSettings);
|
|
66226
66755
|
if (settingsExisting.kind === "malformed") {
|
|
66227
66756
|
return {
|
|
@@ -66240,7 +66769,7 @@ function applyCursorSettings(root, res) {
|
|
|
66240
66769
|
detail: "already registered"
|
|
66241
66770
|
};
|
|
66242
66771
|
}
|
|
66243
|
-
|
|
66772
|
+
writeFileSync8(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
|
|
66244
66773
|
`, "utf8");
|
|
66245
66774
|
return {
|
|
66246
66775
|
platform: "cursor",
|
|
@@ -66249,7 +66778,7 @@ function applyCursorSettings(root, res) {
|
|
|
66249
66778
|
};
|
|
66250
66779
|
}
|
|
66251
66780
|
function applyCursorMcp(root, res) {
|
|
66252
|
-
|
|
66781
|
+
mkdirSync7(path32.dirname(res.cursorMcp), { recursive: true });
|
|
66253
66782
|
const mcpExisting = readExisting(res.cursorMcp);
|
|
66254
66783
|
if (mcpExisting.kind === "malformed") {
|
|
66255
66784
|
return {
|
|
@@ -66279,7 +66808,7 @@ function applyCursorMcp(root, res) {
|
|
|
66279
66808
|
detail: "already registered"
|
|
66280
66809
|
};
|
|
66281
66810
|
}
|
|
66282
|
-
|
|
66811
|
+
writeFileSync8(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
|
|
66283
66812
|
`, "utf8");
|
|
66284
66813
|
return {
|
|
66285
66814
|
platform: "cursor",
|
|
@@ -66288,9 +66817,9 @@ function applyCursorMcp(root, res) {
|
|
|
66288
66817
|
};
|
|
66289
66818
|
}
|
|
66290
66819
|
function verifyPlatform(platform, res) {
|
|
66291
|
-
if (platform === "opencode" && !
|
|
66820
|
+
if (platform === "opencode" && !existsSync15(res.opencodeConfig))
|
|
66292
66821
|
return null;
|
|
66293
|
-
if (platform === "cursor" && !
|
|
66822
|
+
if (platform === "cursor" && !existsSync15(res.cursorSettings) && !existsSync15(res.cursorMcp)) {
|
|
66294
66823
|
return null;
|
|
66295
66824
|
}
|
|
66296
66825
|
return runDoctor({
|
|
@@ -66355,7 +66884,7 @@ function applySetupPreview(preview, options = {}) {
|
|
|
66355
66884
|
let cursorCopyOk = false;
|
|
66356
66885
|
for (const mutation of preview.mutations) {
|
|
66357
66886
|
if (mutation.type === "install-host") {
|
|
66358
|
-
const expectedPath = mutation.platform === "cursor" ?
|
|
66887
|
+
const expectedPath = mutation.platform === "cursor" ? path32.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap") : mutation.platform === "codex" ? path32.join(res.env.CODEX_HOME ?? path32.join(res.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : mutation.platform === "pi" ? path32.join(res.env.PI_CODING_AGENT_DIR ?? path32.join(res.home, ".pi", "agent"), "settings.json") : mutation.platform === "claude-code" ? claudeInstallRecord(res.home, res.env) : "";
|
|
66359
66888
|
if (mutation.path !== expectedPath) {
|
|
66360
66889
|
entries.push({
|
|
66361
66890
|
platform: mutation.platform,
|
|
@@ -66536,12 +67065,12 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66536
67065
|
return configured ?? fallback;
|
|
66537
67066
|
}, readConfigRecord = (file) => {
|
|
66538
67067
|
try {
|
|
66539
|
-
const value = JSON.parse(
|
|
67068
|
+
const value = JSON.parse(readFileSync15(file, "utf8"));
|
|
66540
67069
|
return isRecord5(value) ? value : null;
|
|
66541
67070
|
} catch {
|
|
66542
67071
|
return null;
|
|
66543
67072
|
}
|
|
66544
|
-
}, claudeInstallRecord = (home, env) =>
|
|
67073
|
+
}, claudeInstallRecord = (home, env) => path32.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json"), resolveSetupPaths = (options, resolvedConfigDir) => {
|
|
66545
67074
|
const env = options.env ?? process.env;
|
|
66546
67075
|
const home = options.home ?? env.HOME ?? os9.homedir();
|
|
66547
67076
|
return {
|
|
@@ -66549,17 +67078,17 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66549
67078
|
configDir: resolvedConfigDir,
|
|
66550
67079
|
cwd: options.cwd ?? process.cwd(),
|
|
66551
67080
|
env,
|
|
66552
|
-
opencodeConfig: options.opencodeConfig ??
|
|
66553
|
-
cursorSettings: options.cursorSettings ??
|
|
66554
|
-
cursorMcp: options.cursorMcp ??
|
|
66555
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
67081
|
+
opencodeConfig: options.opencodeConfig ?? path32.join(home, ".config", "opencode", "opencode.json"),
|
|
67082
|
+
cursorSettings: options.cursorSettings ?? path32.join(home, ".cursor", "settings.json"),
|
|
67083
|
+
cursorMcp: options.cursorMcp ?? path32.join(home, ".cursor", "mcp.json"),
|
|
67084
|
+
cursorPluginDir: options.cursorPluginDir ?? path32.join(home, ".cursor", "plugins", "local", "workit")
|
|
66556
67085
|
};
|
|
66557
67086
|
}, isRecord5 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
|
|
66558
67087
|
let raw;
|
|
66559
67088
|
try {
|
|
66560
|
-
raw =
|
|
67089
|
+
raw = readFileSync15(p, "utf8");
|
|
66561
67090
|
} catch {
|
|
66562
|
-
if (
|
|
67091
|
+
if (existsSync15(p))
|
|
66563
67092
|
return { kind: "malformed", error: `${p} is not readable` };
|
|
66564
67093
|
return { kind: "missing" };
|
|
66565
67094
|
}
|
|
@@ -66574,7 +67103,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66574
67103
|
return { kind: "malformed", error: `${p} is not a JSON object` };
|
|
66575
67104
|
}, readFileSafe = (p) => {
|
|
66576
67105
|
try {
|
|
66577
|
-
return
|
|
67106
|
+
return readFileSync15(p, "utf8");
|
|
66578
67107
|
} catch {
|
|
66579
67108
|
return null;
|
|
66580
67109
|
}
|
|
@@ -66589,7 +67118,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66589
67118
|
}
|
|
66590
67119
|
}, isAdapter = (root, platform) => {
|
|
66591
67120
|
try {
|
|
66592
|
-
const pkg = JSON.parse(
|
|
67121
|
+
const pkg = JSON.parse(readFileSync15(path32.join(root, "package.json"), "utf8"));
|
|
66593
67122
|
return pkg.name === `@brainervirus/workit-${platform}`;
|
|
66594
67123
|
} catch {
|
|
66595
67124
|
return false;
|
|
@@ -66603,8 +67132,8 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66603
67132
|
if (!isDevOpenCodeAdapterRoot(root, opts.dev))
|
|
66604
67133
|
return OPENCODE_NPM_PIN;
|
|
66605
67134
|
for (const rel of ["src/plugin.ts", "dist/plugin.js"]) {
|
|
66606
|
-
const entry =
|
|
66607
|
-
if (
|
|
67135
|
+
const entry = path32.join(root, rel);
|
|
67136
|
+
if (existsSync15(entry))
|
|
66608
67137
|
return `file://${entry}`;
|
|
66609
67138
|
}
|
|
66610
67139
|
return null;
|
|
@@ -66621,22 +67150,22 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66621
67150
|
for (const entry of readdirSync8(src, { withFileTypes: true })) {
|
|
66622
67151
|
if (entry.name === "node_modules")
|
|
66623
67152
|
continue;
|
|
66624
|
-
const source =
|
|
66625
|
-
const installed =
|
|
66626
|
-
const rel =
|
|
67153
|
+
const source = path32.join(src, entry.name);
|
|
67154
|
+
const installed = path32.join(dest, entry.name);
|
|
67155
|
+
const rel = path32.join(relative, entry.name);
|
|
66627
67156
|
if (entry.isDirectory()) {
|
|
66628
|
-
if (!
|
|
67157
|
+
if (!statSync6(installed).isDirectory() || !samePluginContent(source, installed, pluginDir, rel))
|
|
66629
67158
|
return false;
|
|
66630
67159
|
} else {
|
|
66631
|
-
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(
|
|
66632
|
-
if (!expected.equals(
|
|
67160
|
+
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync15(source), pluginDir) : readFileSync15(source);
|
|
67161
|
+
if (!expected.equals(readFileSync15(installed)))
|
|
66633
67162
|
return false;
|
|
66634
67163
|
}
|
|
66635
67164
|
}
|
|
66636
67165
|
for (const entry of readdirSync8(dest, { withFileTypes: true })) {
|
|
66637
|
-
if (
|
|
67166
|
+
if (existsSync15(path32.join(src, entry.name)))
|
|
66638
67167
|
continue;
|
|
66639
|
-
const rel =
|
|
67168
|
+
const rel = path32.join(relative, entry.name);
|
|
66640
67169
|
if (rel === ".workit-root")
|
|
66641
67170
|
continue;
|
|
66642
67171
|
if (relative === "rules" && entry.isFile() && entry.name.endsWith(".mdc"))
|
|
@@ -66649,36 +67178,36 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66649
67178
|
}
|
|
66650
67179
|
}, preservedCursorRules = (src, dest) => {
|
|
66651
67180
|
const preserved = new Map;
|
|
66652
|
-
const sourceRules =
|
|
66653
|
-
const installedRules =
|
|
67181
|
+
const sourceRules = path32.join(src, "rules");
|
|
67182
|
+
const installedRules = path32.join(dest, "rules");
|
|
66654
67183
|
try {
|
|
66655
67184
|
for (const entry of readdirSync8(installedRules, { withFileTypes: true })) {
|
|
66656
67185
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66657
67186
|
continue;
|
|
66658
|
-
if (
|
|
67187
|
+
if (existsSync15(path32.join(sourceRules, entry.name)))
|
|
66659
67188
|
continue;
|
|
66660
|
-
preserved.set(entry.name,
|
|
67189
|
+
preserved.set(entry.name, readFileSync15(path32.join(installedRules, entry.name)));
|
|
66661
67190
|
}
|
|
66662
67191
|
} catch {}
|
|
66663
67192
|
return preserved;
|
|
66664
67193
|
}, removeLegacyCursorDir = (res) => {
|
|
66665
|
-
const legacy =
|
|
66666
|
-
if (legacy === res.cursorPluginDir || !
|
|
67194
|
+
const legacy = path32.join(res.home, ".cursor", "plugins", "local", "workflow-toolkit");
|
|
67195
|
+
if (legacy === res.cursorPluginDir || !existsSync15(legacy))
|
|
66667
67196
|
return;
|
|
66668
|
-
const legacyRules =
|
|
66669
|
-
if (
|
|
67197
|
+
const legacyRules = path32.join(legacy, "rules");
|
|
67198
|
+
if (existsSync15(legacyRules)) {
|
|
66670
67199
|
try {
|
|
66671
|
-
|
|
67200
|
+
mkdirSync7(path32.join(res.cursorPluginDir, "rules"), { recursive: true });
|
|
66672
67201
|
for (const entry of readdirSync8(legacyRules, { withFileTypes: true })) {
|
|
66673
67202
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66674
67203
|
continue;
|
|
66675
|
-
const target =
|
|
66676
|
-
if (!
|
|
66677
|
-
copyFileSync4(
|
|
67204
|
+
const target = path32.join(res.cursorPluginDir, "rules", entry.name);
|
|
67205
|
+
if (!existsSync15(target))
|
|
67206
|
+
copyFileSync4(path32.join(legacyRules, entry.name), target);
|
|
66678
67207
|
}
|
|
66679
67208
|
} catch {}
|
|
66680
67209
|
}
|
|
66681
|
-
|
|
67210
|
+
rmSync4(legacy, { recursive: true, force: true });
|
|
66682
67211
|
}, failedDetail = (report) => report.checks.filter((c) => c.status === "fail").map((c) => `${c.id}: ${c.detail}`).join("; "), setupCompletionGuidance = () => [
|
|
66683
67212
|
"Run `workit doctor` to verify your installation.",
|
|
66684
67213
|
"Run /wk-status in OpenCode to review token setup steps."
|
|
@@ -66708,16 +67237,16 @@ var init_setup = __esm(() => {
|
|
|
66708
67237
|
{ envKey: "WORKFLOW_GITHUB_HOST", affects: "vcs.json github.host" }
|
|
66709
67238
|
];
|
|
66710
67239
|
SETUP_OVERRIDES = [...YT_OVERRIDES, ...VCS_OVERRIDES];
|
|
66711
|
-
CURSOR_HOOKS_FILE =
|
|
67240
|
+
CURSOR_HOOKS_FILE = path32.join("hooks", "hooks-cursor.json");
|
|
66712
67241
|
});
|
|
66713
67242
|
|
|
66714
67243
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
66715
|
-
import { mkdirSync as
|
|
66716
|
-
import
|
|
67244
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync16, renameSync as renameSync5, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "node:fs";
|
|
67245
|
+
import path33 from "node:path";
|
|
66717
67246
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
|
|
66718
67247
|
function applyWorkspaceBranchPolicy(opts) {
|
|
66719
67248
|
const { workspace_root, env = process.env } = opts;
|
|
66720
|
-
const dir =
|
|
67249
|
+
const dir = path33.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
66721
67250
|
const {
|
|
66722
67251
|
status,
|
|
66723
67252
|
path: wsPath,
|
|
@@ -66729,7 +67258,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66729
67258
|
if (status === "malformed" || status === "invalid")
|
|
66730
67259
|
return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
|
|
66731
67260
|
const detection = detectBranchPolicy(workspace_root);
|
|
66732
|
-
const name = String(env.WORKFLOW_BP_NAME ??
|
|
67261
|
+
const name = String(env.WORKFLOW_BP_NAME ?? path33.basename(workspace_root));
|
|
66733
67262
|
const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
|
|
66734
67263
|
const policy = {
|
|
66735
67264
|
preset: detection.preset,
|
|
@@ -66778,22 +67307,22 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66778
67307
|
ok: false,
|
|
66779
67308
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
66780
67309
|
};
|
|
66781
|
-
|
|
67310
|
+
mkdirSync8(path33.dirname(wsPath), { recursive: true });
|
|
66782
67311
|
const tmp = `${wsPath}.${process.pid}.tmp`;
|
|
66783
67312
|
try {
|
|
66784
|
-
|
|
67313
|
+
writeFileSync9(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
|
|
66785
67314
|
`, "utf8");
|
|
66786
67315
|
if (workspacesRevision(readFileSafe2(wsPath)) !== revision) {
|
|
66787
|
-
|
|
67316
|
+
rmSync5(tmp, { force: true });
|
|
66788
67317
|
return {
|
|
66789
67318
|
ok: false,
|
|
66790
67319
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
66791
67320
|
};
|
|
66792
67321
|
}
|
|
66793
|
-
|
|
67322
|
+
renameSync5(tmp, wsPath);
|
|
66794
67323
|
} catch (error) {
|
|
66795
67324
|
try {
|
|
66796
|
-
|
|
67325
|
+
rmSync5(tmp, { force: true });
|
|
66797
67326
|
} catch {}
|
|
66798
67327
|
return {
|
|
66799
67328
|
ok: false,
|
|
@@ -66810,7 +67339,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66810
67339
|
}
|
|
66811
67340
|
var readFileSafe2 = (p) => {
|
|
66812
67341
|
try {
|
|
66813
|
-
return
|
|
67342
|
+
return readFileSync16(p, "utf8");
|
|
66814
67343
|
} catch {
|
|
66815
67344
|
return null;
|
|
66816
67345
|
}
|
|
@@ -67062,8 +67591,8 @@ var init_logic = __esm(() => {
|
|
|
67062
67591
|
});
|
|
67063
67592
|
|
|
67064
67593
|
// packages/workit-cli/src/wizard-state.ts
|
|
67065
|
-
import { existsSync as
|
|
67066
|
-
import
|
|
67594
|
+
import { existsSync as existsSync16, statSync as statSync7 } from "node:fs";
|
|
67595
|
+
import path34 from "node:path";
|
|
67067
67596
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
|
|
67068
67597
|
function resolveBasePath(values, env = process.env) {
|
|
67069
67598
|
return env.WORKFLOW_WORKSPACE_ROOT?.trim() || values.basePath.trim();
|
|
@@ -67582,7 +68111,7 @@ function workspaceDraftText(draft, field, value) {
|
|
|
67582
68111
|
}
|
|
67583
68112
|
var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllowed" || screen === "branchProtected") && preset !== "custom", skipsYoutrack = (screen, tracker) => screen === "youtrack" && tracker !== "youtrack", skipsBasePath = (screen, basePath) => screen === "basePath" && basePath !== "", isDirectory = (p) => {
|
|
67584
68113
|
try {
|
|
67585
|
-
return
|
|
68114
|
+
return statSync7(p).isDirectory();
|
|
67586
68115
|
} catch {
|
|
67587
68116
|
return false;
|
|
67588
68117
|
}
|
|
@@ -67590,8 +68119,8 @@ var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllow
|
|
|
67590
68119
|
const p = value.trim();
|
|
67591
68120
|
if (!p)
|
|
67592
68121
|
return "workspace root path is required";
|
|
67593
|
-
return !
|
|
67594
|
-
}, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !
|
|
68122
|
+
return !path34.isAbsolute(p) || !isDirectory(p) ? `invalid workspace root "${p}" — enter an existing absolute directory` : null;
|
|
68123
|
+
}, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync16(path34.join(basePath, ".git")), decodeBranchPreset = (value, fallback) => value === "gitflow" || value === "github-flow" || value === "trunk-based" || value === "custom" ? value : fallback, decodeVcsProvider = (value, fallback) => value === "gitlab" || value === "github" || value === "skip" ? value : fallback, decodeIssueTracker = (value, fallback) => value === "youtrack" || value === "github" || value === "gitlab" || value === "none" ? value : fallback, GITHUB_ISSUES, withGithubIssues = (draft, tracker) => tracker === "github" ? { ...draft, issues: { ...GITHUB_ISSUES } } : draft;
|
|
67595
68124
|
var init_wizard_state = __esm(() => {
|
|
67596
68125
|
init_config();
|
|
67597
68126
|
init_workspaces();
|
|
@@ -67650,9 +68179,9 @@ var init_wizard_state = __esm(() => {
|
|
|
67650
68179
|
});
|
|
67651
68180
|
|
|
67652
68181
|
// packages/workit-cli/src/admin/uninstall.ts
|
|
67653
|
-
import { existsSync as
|
|
68182
|
+
import { existsSync as existsSync17, readFileSync as readFileSync17, realpathSync as realpathSync8, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
|
|
67654
68183
|
import os10 from "node:os";
|
|
67655
|
-
import
|
|
68184
|
+
import path35 from "node:path";
|
|
67656
68185
|
function cleanCursorSettings(settings, pluginDir) {
|
|
67657
68186
|
const next = { ...settings };
|
|
67658
68187
|
let changed = false;
|
|
@@ -67752,7 +68281,7 @@ function planUninstall(paths = {}) {
|
|
|
67752
68281
|
const mcpExisting = readJsonRecord(res.cursorMcp);
|
|
67753
68282
|
const settingsDirty = settingsExisting.kind === "malformed" || settingsExisting.kind === "record" && cleanCursorSettings(settingsExisting.value, res.cursorPluginDir).changed;
|
|
67754
68283
|
const mcpDirty = mcpExisting.kind === "malformed" || mcpExisting.kind === "record" && cleanCursorMcp(mcpExisting.value).changed;
|
|
67755
|
-
const dirExists =
|
|
68284
|
+
const dirExists = existsSync17(res.cursorPluginDir);
|
|
67756
68285
|
const actions = [];
|
|
67757
68286
|
if (settingsDirty) {
|
|
67758
68287
|
actions.push({
|
|
@@ -67780,7 +68309,7 @@ function planUninstall(paths = {}) {
|
|
|
67780
68309
|
installed: settingsDirty || mcpDirty || dirExists,
|
|
67781
68310
|
actions
|
|
67782
68311
|
};
|
|
67783
|
-
const codexInstalled =
|
|
68312
|
+
const codexInstalled = existsSync17(res.codexPluginDir);
|
|
67784
68313
|
const codex = {
|
|
67785
68314
|
host: "codex",
|
|
67786
68315
|
installed: codexInstalled,
|
|
@@ -67827,17 +68356,17 @@ function applyUninstall(plan, paths = {}) {
|
|
|
67827
68356
|
status = outcome.status;
|
|
67828
68357
|
detail = outcome.detail;
|
|
67829
68358
|
} else if (action.kind === "remove-dir") {
|
|
67830
|
-
const resolved =
|
|
67831
|
-
const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved ===
|
|
68359
|
+
const resolved = path35.resolve(action.path);
|
|
68360
|
+
const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved === path35.resolve(res.codexPluginDir) && path35.basename(resolved) === "workit" && path35.basename(path35.dirname(resolved)) === "plugins";
|
|
67832
68361
|
if (!allowed) {
|
|
67833
68362
|
status = "failed";
|
|
67834
68363
|
detail = `refusing to remove non-canonical plugin directory: ${resolved}`;
|
|
67835
|
-
} else if (!
|
|
68364
|
+
} else if (!existsSync17(resolved)) {
|
|
67836
68365
|
status = "skipped";
|
|
67837
68366
|
detail = "directory already absent";
|
|
67838
68367
|
} else {
|
|
67839
68368
|
try {
|
|
67840
|
-
|
|
68369
|
+
rmSync6(resolved, { recursive: true, force: true });
|
|
67841
68370
|
status = "removed";
|
|
67842
68371
|
} catch (error) {
|
|
67843
68372
|
status = "failed";
|
|
@@ -67863,19 +68392,19 @@ function applyUninstall(plan, paths = {}) {
|
|
|
67863
68392
|
var resolveUninstallPaths = (options = {}) => {
|
|
67864
68393
|
const home = options.home ?? options.env?.HOME ?? os10.homedir();
|
|
67865
68394
|
return {
|
|
67866
|
-
opencodeConfig: options.opencodeConfig ??
|
|
67867
|
-
cursorSettings: options.cursorSettings ??
|
|
67868
|
-
cursorMcp: options.cursorMcp ??
|
|
67869
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
67870
|
-
codexPluginDir:
|
|
67871
|
-
piConfig:
|
|
68395
|
+
opencodeConfig: options.opencodeConfig ?? path35.join(home, ".config", "opencode", "opencode.json"),
|
|
68396
|
+
cursorSettings: options.cursorSettings ?? path35.join(home, ".cursor", "settings.json"),
|
|
68397
|
+
cursorMcp: options.cursorMcp ?? path35.join(home, ".cursor", "mcp.json"),
|
|
68398
|
+
cursorPluginDir: options.cursorPluginDir ?? path35.join(home, ".cursor", "plugins", "local", "workit"),
|
|
68399
|
+
codexPluginDir: path35.join(home, ".codex", "plugins", "workit"),
|
|
68400
|
+
piConfig: path35.join(home, ".pi", "config.json")
|
|
67872
68401
|
};
|
|
67873
68402
|
}, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
|
|
67874
68403
|
let raw;
|
|
67875
68404
|
try {
|
|
67876
|
-
raw =
|
|
68405
|
+
raw = readFileSync17(file, "utf8");
|
|
67877
68406
|
} catch {
|
|
67878
|
-
if (
|
|
68407
|
+
if (existsSync17(file))
|
|
67879
68408
|
return { kind: "malformed", error: `${file} is not readable` };
|
|
67880
68409
|
return { kind: "missing" };
|
|
67881
68410
|
}
|
|
@@ -67886,8 +68415,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67886
68415
|
return { kind: "malformed", error: `${file} is not valid JSON` };
|
|
67887
68416
|
}
|
|
67888
68417
|
}, stripTrailingSep = (p) => {
|
|
67889
|
-
const j =
|
|
67890
|
-
return
|
|
68418
|
+
const j = path35.join(p);
|
|
68419
|
+
return path35.dirname(j) === j ? j : j.replace(/[\\/]+$/, "");
|
|
67891
68420
|
}, CURSOR_LEGACY_IDENTITIES, jsonCleanerFor = (target, res) => {
|
|
67892
68421
|
if (target === res.opencodeConfig)
|
|
67893
68422
|
return cleanOpenCodeConfig;
|
|
@@ -67899,8 +68428,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67899
68428
|
return cleanPiConfig;
|
|
67900
68429
|
return null;
|
|
67901
68430
|
}, canonicalRemoveDirAllowed = (actionPath, res) => {
|
|
67902
|
-
const expected =
|
|
67903
|
-
if (!(actionPath === expected &&
|
|
68431
|
+
const expected = path35.resolve(res.cursorPluginDir);
|
|
68432
|
+
if (!(actionPath === expected && path35.basename(expected) === "workit" && path35.basename(path35.dirname(expected)) === "local" && path35.basename(path35.dirname(path35.dirname(expected))) === "plugins")) {
|
|
67904
68433
|
return false;
|
|
67905
68434
|
}
|
|
67906
68435
|
try {
|
|
@@ -67923,7 +68452,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67923
68452
|
`;
|
|
67924
68453
|
let current;
|
|
67925
68454
|
try {
|
|
67926
|
-
current =
|
|
68455
|
+
current = readFileSync17(target, "utf8");
|
|
67927
68456
|
} catch (error) {
|
|
67928
68457
|
return {
|
|
67929
68458
|
status: "failed",
|
|
@@ -67934,7 +68463,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67934
68463
|
return { status: "skipped", detail: "already clean" };
|
|
67935
68464
|
}
|
|
67936
68465
|
try {
|
|
67937
|
-
|
|
68466
|
+
writeFileSync10(target, serialized, "utf8");
|
|
67938
68467
|
} catch (error) {
|
|
67939
68468
|
return {
|
|
67940
68469
|
status: "failed",
|
|
@@ -67952,7 +68481,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67952
68481
|
};
|
|
67953
68482
|
const home = paths.home ?? paths.env?.HOME ?? os10.homedir();
|
|
67954
68483
|
const env = paths.env ?? process.env;
|
|
67955
|
-
const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null :
|
|
68484
|
+
const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null : path35.resolve(install.projectPath) === path35.resolve(action.cwd ?? "")));
|
|
67956
68485
|
if (!recorded)
|
|
67957
68486
|
return { status: "skipped", detail: `${id} (${scope} scope) is no longer installed` };
|
|
67958
68487
|
const executable = findHostExecutable("claude", { home, env });
|
|
@@ -70431,9 +70960,9 @@ var init_src2 = __esm(async () => {
|
|
|
70431
70960
|
// packages/workit-cli/src/verbs/init.ts
|
|
70432
70961
|
var exports_init = {};
|
|
70433
70962
|
__export(exports_init, {
|
|
70434
|
-
run: () =>
|
|
70963
|
+
run: () => run3
|
|
70435
70964
|
});
|
|
70436
|
-
async function
|
|
70965
|
+
async function run3(_argv, io) {
|
|
70437
70966
|
if (io.json)
|
|
70438
70967
|
return emit(io, fail("invalid_input", "workit init is an interactive wizard and has no --json output", {
|
|
70439
70968
|
unblock: "run `workit init` in a terminal without --json"
|
|
@@ -70447,19 +70976,19 @@ var init_init = __esm(() => {
|
|
|
70447
70976
|
});
|
|
70448
70977
|
|
|
70449
70978
|
// packages/workit-cli/src/upgrade.ts
|
|
70450
|
-
import { spawnSync as
|
|
70979
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
70451
70980
|
import {
|
|
70452
|
-
existsSync as
|
|
70981
|
+
existsSync as existsSync18,
|
|
70453
70982
|
mkdtempSync as mkdtempSync3,
|
|
70454
|
-
rmSync as
|
|
70455
|
-
readFileSync as
|
|
70456
|
-
mkdirSync as
|
|
70983
|
+
rmSync as rmSync7,
|
|
70984
|
+
readFileSync as readFileSync18,
|
|
70985
|
+
mkdirSync as mkdirSync9,
|
|
70457
70986
|
copyFileSync as copyFileSync5,
|
|
70458
|
-
chmodSync,
|
|
70987
|
+
chmodSync as chmodSync2,
|
|
70459
70988
|
cpSync as cpSync5,
|
|
70460
|
-
lstatSync as
|
|
70989
|
+
lstatSync as lstatSync7
|
|
70461
70990
|
} from "node:fs";
|
|
70462
|
-
import
|
|
70991
|
+
import path36 from "node:path";
|
|
70463
70992
|
import os12 from "node:os";
|
|
70464
70993
|
import { createHash as createHash14 } from "node:crypto";
|
|
70465
70994
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
@@ -70483,9 +71012,9 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70483
71012
|
for (const file of [
|
|
70484
71013
|
paths.opencodeConfig,
|
|
70485
71014
|
paths.opencodeConfig + "c",
|
|
70486
|
-
|
|
70487
|
-
|
|
70488
|
-
|
|
71015
|
+
path36.join(home, ".cursor/settings.json"),
|
|
71016
|
+
path36.join(home, ".cursor/mcp.json"),
|
|
71017
|
+
path36.join(home, ".cursor/plugins/local/workit/package.json"),
|
|
70489
71018
|
paths.codexConfig,
|
|
70490
71019
|
paths.piSettings
|
|
70491
71020
|
])
|
|
@@ -70500,20 +71029,20 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70500
71029
|
});
|
|
70501
71030
|
const installedSources = sources(paths, run, hosts);
|
|
70502
71031
|
if (installedSources.some((source) => source.host === "opencode")) {
|
|
70503
|
-
const scratch = mkdtempSync3(
|
|
71032
|
+
const scratch = mkdtempSync3(path36.join(os12.tmpdir(), "workit-upgrade-opencode-"));
|
|
70504
71033
|
let probe;
|
|
70505
71034
|
try {
|
|
70506
71035
|
probe = runner({
|
|
70507
71036
|
...deps,
|
|
70508
71037
|
env: {
|
|
70509
71038
|
...deps.env,
|
|
70510
|
-
XDG_DATA_HOME:
|
|
70511
|
-
XDG_STATE_HOME:
|
|
70512
|
-
XDG_CACHE_HOME:
|
|
71039
|
+
XDG_DATA_HOME: path36.join(scratch, "data"),
|
|
71040
|
+
XDG_STATE_HOME: path36.join(scratch, "state"),
|
|
71041
|
+
XDG_CACHE_HOME: path36.join(scratch, "cache")
|
|
70513
71042
|
}
|
|
70514
71043
|
})("opencode", ["--version"]);
|
|
70515
71044
|
} finally {
|
|
70516
|
-
|
|
71045
|
+
rmSync7(scratch, { recursive: true, force: true });
|
|
70517
71046
|
}
|
|
70518
71047
|
const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
|
|
70519
71048
|
if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
|
|
@@ -70555,7 +71084,7 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70555
71084
|
env: deps.env,
|
|
70556
71085
|
cwd: home,
|
|
70557
71086
|
packageVersion: latest.stdout.trim(),
|
|
70558
|
-
targetDir:
|
|
71087
|
+
targetDir: path36.join(home, ".cursor/plugins/local/workit")
|
|
70559
71088
|
});
|
|
70560
71089
|
plan.entries.push({
|
|
70561
71090
|
host: source.host,
|
|
@@ -70585,13 +71114,13 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70585
71114
|
ok: false,
|
|
70586
71115
|
error: "Stop the selected running hosts before upgrading their loaded plugins"
|
|
70587
71116
|
};
|
|
70588
|
-
const backup =
|
|
70589
|
-
|
|
71117
|
+
const backup = path36.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
|
|
71118
|
+
mkdirSync9(backup, { recursive: true, mode: 448 });
|
|
70590
71119
|
for (const file of Object.keys(plan.configDigests))
|
|
70591
|
-
if (
|
|
70592
|
-
const target =
|
|
71120
|
+
if (existsSync18(file)) {
|
|
71121
|
+
const target = path36.join(backup, createHash14("sha256").update(file).digest("hex").slice(0, 12) + "-" + path36.basename(file));
|
|
70593
71122
|
copyFileSync5(file, target);
|
|
70594
|
-
|
|
71123
|
+
chmodSync2(target, 384);
|
|
70595
71124
|
}
|
|
70596
71125
|
for (const migration of plan.migrations) {
|
|
70597
71126
|
const value = object2(migration.file);
|
|
@@ -70606,9 +71135,9 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70606
71135
|
`, 384);
|
|
70607
71136
|
}
|
|
70608
71137
|
const run = runner(deps);
|
|
70609
|
-
const cursorRoot =
|
|
70610
|
-
if (plan.entries.some((entry) => entry.host === "cursor") &&
|
|
70611
|
-
cpSync5(cursorRoot,
|
|
71138
|
+
const cursorRoot = path36.join(home, ".cursor/plugins/local/workit");
|
|
71139
|
+
if (plan.entries.some((entry) => entry.host === "cursor") && existsSync18(cursorRoot))
|
|
71140
|
+
cpSync5(cursorRoot, path36.join(backup, "cursor-package"), { recursive: true });
|
|
70612
71141
|
for (const entry of plan.entries) {
|
|
70613
71142
|
if (entry.host === "opencode")
|
|
70614
71143
|
return {
|
|
@@ -70628,7 +71157,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70628
71157
|
{
|
|
70629
71158
|
type: "install-host",
|
|
70630
71159
|
platform: "cursor",
|
|
70631
|
-
path:
|
|
71160
|
+
path: path36.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
|
|
70632
71161
|
commands: entry.commands.map((command) => ({
|
|
70633
71162
|
...command,
|
|
70634
71163
|
purpose: command.purpose ?? "Upgrade Cursor"
|
|
@@ -70637,7 +71166,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70637
71166
|
{
|
|
70638
71167
|
type: "install-adapter",
|
|
70639
71168
|
platform: "cursor",
|
|
70640
|
-
path:
|
|
71169
|
+
path: path36.join(home, ".cursor/plugins/local/workit")
|
|
70641
71170
|
}
|
|
70642
71171
|
]
|
|
70643
71172
|
};
|
|
@@ -70651,7 +71180,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70651
71180
|
return { exitCode: outcome.status ?? 1, stdout: outcome.stdout, stderr: "" };
|
|
70652
71181
|
}
|
|
70653
71182
|
});
|
|
70654
|
-
const pkg = object2(
|
|
71183
|
+
const pkg = object2(path36.join(home, ".cursor/plugins/local/workit/package.json"));
|
|
70655
71184
|
if (!result.ok || pkg?.version !== entry.latest)
|
|
70656
71185
|
return {
|
|
70657
71186
|
ok: false,
|
|
@@ -70685,15 +71214,15 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70685
71214
|
const currentRoot = run("npm", ["root", "--global"]);
|
|
70686
71215
|
if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== plan.cli.root)
|
|
70687
71216
|
return { ok: false, backup, error: "Global npm location changed; preview again" };
|
|
70688
|
-
const cliBackup =
|
|
70689
|
-
cpSync5(
|
|
71217
|
+
const cliBackup = path36.join(backup, "cli-package");
|
|
71218
|
+
cpSync5(path36.join(plan.cli.root, "@brainervirus/workit-cli"), cliBackup, { recursive: true });
|
|
70690
71219
|
if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${plan.cli.latest}`]).status !== 0)
|
|
70691
71220
|
return {
|
|
70692
71221
|
ok: false,
|
|
70693
71222
|
backup,
|
|
70694
|
-
error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${
|
|
71223
|
+
error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path36.join(cliBackup, "dist/index.js")}`
|
|
70695
71224
|
};
|
|
70696
|
-
const installed = object2(
|
|
71225
|
+
const installed = object2(path36.join(plan.cli.root, "@brainervirus/workit-cli/package.json"));
|
|
70697
71226
|
if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== plan.cli.latest)
|
|
70698
71227
|
return {
|
|
70699
71228
|
ok: false,
|
|
@@ -70718,12 +71247,12 @@ async function runUpgradeCommand(argv, deps = {}) {
|
|
|
70718
71247
|
if (flags.has("--cli")) {
|
|
70719
71248
|
const run = runner(deps);
|
|
70720
71249
|
const root = run("npm", ["root", "--global"]);
|
|
70721
|
-
if (root.status !== 0 || !
|
|
71250
|
+
if (root.status !== 0 || !path36.isAbsolute(root.stdout.trim())) {
|
|
70722
71251
|
plan.blocked.push("Global npm location could not be verified");
|
|
70723
71252
|
} else {
|
|
70724
|
-
const packageFile =
|
|
71253
|
+
const packageFile = path36.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
|
|
70725
71254
|
const pkg = object2(packageFile);
|
|
70726
|
-
if (pkg?.name !== "@brainervirus/workit-cli" ||
|
|
71255
|
+
if (pkg?.name !== "@brainervirus/workit-cli" || lstatSync7(path36.dirname(packageFile)).isSymbolicLink()) {
|
|
70727
71256
|
plan.skipped.push({
|
|
70728
71257
|
host: "cli",
|
|
70729
71258
|
reason: "No managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
|
|
@@ -70803,7 +71332,7 @@ async function runLaunchCommand(argv, deps = {}) {
|
|
|
70803
71332
|
}
|
|
70804
71333
|
if (deps.run)
|
|
70805
71334
|
return deps.run(host, hostArgs).status ?? 1;
|
|
70806
|
-
return
|
|
71335
|
+
return spawnSync15(launch.command, launch.args, {
|
|
70807
71336
|
stdio: "inherit",
|
|
70808
71337
|
env
|
|
70809
71338
|
}).status ?? 1;
|
|
@@ -70814,37 +71343,37 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70814
71343
|
...process.env,
|
|
70815
71344
|
...deps.home || deps.env?.HOME ? {
|
|
70816
71345
|
HOME: home,
|
|
70817
|
-
CODEX_HOME:
|
|
70818
|
-
PI_CODING_AGENT_DIR:
|
|
70819
|
-
XDG_CONFIG_HOME:
|
|
71346
|
+
CODEX_HOME: path36.join(home, ".codex"),
|
|
71347
|
+
PI_CODING_AGENT_DIR: path36.join(home, ".pi/agent"),
|
|
71348
|
+
XDG_CONFIG_HOME: path36.join(home, ".config"),
|
|
70820
71349
|
WORKFLOW_TOOLKIT_CONFIG: undefined,
|
|
70821
71350
|
WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
|
|
70822
71351
|
} : {},
|
|
70823
71352
|
...deps.env,
|
|
70824
71353
|
HOME: home
|
|
70825
71354
|
};
|
|
70826
|
-
const xdg = env.XDG_CONFIG_HOME ||
|
|
71355
|
+
const xdg = env.XDG_CONFIG_HOME || path36.join(home, ".config");
|
|
70827
71356
|
return {
|
|
70828
71357
|
home,
|
|
70829
71358
|
env,
|
|
70830
|
-
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
70831
|
-
opencodeConfig:
|
|
70832
|
-
piSettings:
|
|
70833
|
-
codexConfig:
|
|
71359
|
+
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path36.join(xdg, "workit"),
|
|
71360
|
+
opencodeConfig: path36.join(xdg, "opencode/opencode.json"),
|
|
71361
|
+
piSettings: path36.join(env.PI_CODING_AGENT_DIR ?? path36.join(home, ".pi/agent"), "settings.json"),
|
|
71362
|
+
codexConfig: path36.join(env.CODEX_HOME ?? path36.join(home, ".codex"), "config.toml")
|
|
70834
71363
|
};
|
|
70835
71364
|
}, object2 = (file) => {
|
|
70836
|
-
if (!
|
|
71365
|
+
if (!existsSync18(file))
|
|
70837
71366
|
return null;
|
|
70838
71367
|
let data;
|
|
70839
71368
|
try {
|
|
70840
|
-
data = JSON.parse(
|
|
71369
|
+
data = JSON.parse(readFileSync18(file, "utf8"));
|
|
70841
71370
|
} catch {
|
|
70842
71371
|
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
70843
71372
|
}
|
|
70844
71373
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
70845
71374
|
throw new Error(`${file} is not a configuration object`);
|
|
70846
71375
|
return data;
|
|
70847
|
-
}, digest2 = (file) =>
|
|
71376
|
+
}, digest2 = (file) => existsSync18(file) ? createHash14("sha256").update(readFileSync18(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
70848
71377
|
const { home, env } = upgradePaths(deps);
|
|
70849
71378
|
let step;
|
|
70850
71379
|
try {
|
|
@@ -70861,7 +71390,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70861
71390
|
}), sources = (paths, run, hosts) => {
|
|
70862
71391
|
const { home, opencodeConfig, piSettings } = paths;
|
|
70863
71392
|
const result = [];
|
|
70864
|
-
if (hosts.includes("opencode") &&
|
|
71393
|
+
if (hosts.includes("opencode") && existsSync18(opencodeConfig + "c"))
|
|
70865
71394
|
throw new Error("OpenCode JSONC config is present; inspect effective native configuration before updating");
|
|
70866
71395
|
const oc = hosts.includes("opencode") ? object2(opencodeConfig) : null;
|
|
70867
71396
|
if (oc && [oc.plugins, oc.plugin].some((value) => value !== undefined && !Array.isArray(value)))
|
|
@@ -70870,9 +71399,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70870
71399
|
for (const pin of plugins)
|
|
70871
71400
|
if (typeof pin === "string" && isWorkitPlugin(pin))
|
|
70872
71401
|
result.push(classify("opencode", pin));
|
|
70873
|
-
const cursor = hosts.includes("cursor") ? object2(
|
|
71402
|
+
const cursor = hosts.includes("cursor") ? object2(path36.join(home, ".cursor/plugins/local/workit/package.json")) : null;
|
|
70874
71403
|
if (cursor?.name === "@brainervirus/workit-cursor") {
|
|
70875
|
-
const mcp = object2(
|
|
71404
|
+
const mcp = object2(path36.join(home, ".cursor/mcp.json"));
|
|
70876
71405
|
const args = mcp?.mcpServers?.workit?.args ?? [];
|
|
70877
71406
|
const selector = args.find((arg) => typeof arg === "string" && arg.startsWith("--package="));
|
|
70878
71407
|
result.push(classify("cursor", typeof selector === "string" ? selector.slice(10) : "local"));
|
|
@@ -70885,7 +71414,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70885
71414
|
if (typeof source !== "string")
|
|
70886
71415
|
continue;
|
|
70887
71416
|
const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
|
|
70888
|
-
const local =
|
|
71417
|
+
const local = path36.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path36.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
|
|
70889
71418
|
if (npm || local)
|
|
70890
71419
|
result.push(classify("pi", source));
|
|
70891
71420
|
}
|
|
@@ -70896,7 +71425,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70896
71425
|
hostCommand("codex", [], { home, env: paths.env });
|
|
70897
71426
|
available = true;
|
|
70898
71427
|
} catch {}
|
|
70899
|
-
if (available ||
|
|
71428
|
+
if (available || existsSync18(paths.codexConfig))
|
|
70900
71429
|
throw new Error("Codex plugin inventory failed; inspect the native host before upgrading");
|
|
70901
71430
|
}
|
|
70902
71431
|
if (listing.status === 0) {
|
|
@@ -70932,9 +71461,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70932
71461
|
}, piInstalledVersion = (listing, selector) => {
|
|
70933
71462
|
const lines = listing.split(/\r?\n/).map((line) => line.trim());
|
|
70934
71463
|
const index = lines.indexOf(selector);
|
|
70935
|
-
if (index < 0 || !lines[index + 1] || !
|
|
71464
|
+
if (index < 0 || !lines[index + 1] || !path36.isAbsolute(lines[index + 1]))
|
|
70936
71465
|
return;
|
|
70937
|
-
const pkg = object2(
|
|
71466
|
+
const pkg = object2(path36.join(lines[index + 1], "package.json"));
|
|
70938
71467
|
return pkg?.name === "@brainervirus/workit-pi" ? pkg.version : undefined;
|
|
70939
71468
|
}, versionAtLeast = (installed, latest) => {
|
|
70940
71469
|
if (!/^\d+\.\d+\.\d+$/.test(installed))
|
|
@@ -70967,9 +71496,9 @@ var init_upgrade = __esm(() => {
|
|
|
70967
71496
|
// packages/workit-cli/src/verbs/upgrade.ts
|
|
70968
71497
|
var exports_upgrade = {};
|
|
70969
71498
|
__export(exports_upgrade, {
|
|
70970
|
-
run: () =>
|
|
71499
|
+
run: () => run4
|
|
70971
71500
|
});
|
|
70972
|
-
var
|
|
71501
|
+
var run4 = (argv) => runUpgradeCommand(argv);
|
|
70973
71502
|
var init_upgrade2 = __esm(() => {
|
|
70974
71503
|
init_upgrade();
|
|
70975
71504
|
});
|
|
@@ -70977,17 +71506,17 @@ var init_upgrade2 = __esm(() => {
|
|
|
70977
71506
|
// packages/workit-cli/src/verbs/launch.ts
|
|
70978
71507
|
var exports_launch = {};
|
|
70979
71508
|
__export(exports_launch, {
|
|
70980
|
-
run: () =>
|
|
71509
|
+
run: () => run5
|
|
70981
71510
|
});
|
|
70982
|
-
var
|
|
71511
|
+
var run5 = (argv) => runLaunchCommand(argv);
|
|
70983
71512
|
var init_launch = __esm(() => {
|
|
70984
71513
|
init_upgrade();
|
|
70985
71514
|
});
|
|
70986
71515
|
|
|
70987
71516
|
// packages/workit-core/src/knowledge.ts
|
|
70988
|
-
import { spawnSync as
|
|
71517
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
70989
71518
|
import fs17 from "node:fs";
|
|
70990
|
-
import
|
|
71519
|
+
import path37 from "node:path";
|
|
70991
71520
|
function lintKnowledge(root) {
|
|
70992
71521
|
const seen = new Set;
|
|
70993
71522
|
const unreadable = [];
|
|
@@ -71091,7 +71620,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71091
71620
|
const end = lines.indexOf("---", 1);
|
|
71092
71621
|
return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
|
|
71093
71622
|
}, read = (root, file) => {
|
|
71094
|
-
const full =
|
|
71623
|
+
const full = path37.join(root, file);
|
|
71095
71624
|
try {
|
|
71096
71625
|
fs17.lstatSync(full);
|
|
71097
71626
|
} catch {
|
|
@@ -71106,7 +71635,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71106
71635
|
return "unreadable";
|
|
71107
71636
|
}
|
|
71108
71637
|
}, trackedTopLevel = (root) => {
|
|
71109
|
-
const run =
|
|
71638
|
+
const run = spawnSync16("git", ["ls-files", "-z", "--cached"], {
|
|
71110
71639
|
cwd: root,
|
|
71111
71640
|
encoding: "utf8",
|
|
71112
71641
|
maxBuffer: 256 * 1024 * 1024,
|
|
@@ -71116,7 +71645,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71116
71645
|
if (run.status !== 0)
|
|
71117
71646
|
return null;
|
|
71118
71647
|
return new Set(run.stdout.split("\x00").filter(Boolean).map((file) => file.split("/")[0]));
|
|
71119
|
-
},
|
|
71648
|
+
}, exists2 = (target) => {
|
|
71120
71649
|
try {
|
|
71121
71650
|
fs17.statSync(target);
|
|
71122
71651
|
return true;
|
|
@@ -71132,7 +71661,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71132
71661
|
}
|
|
71133
71662
|
}, brokenLinks = (root, doc, tracked) => {
|
|
71134
71663
|
const findings = [];
|
|
71135
|
-
const base =
|
|
71664
|
+
const base = path37.dirname(path37.join(root, doc.file));
|
|
71136
71665
|
const missing = (target, line, how) => findings.push({
|
|
71137
71666
|
rule: "broken-link",
|
|
71138
71667
|
file: doc.file,
|
|
@@ -71151,8 +71680,8 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71151
71680
|
const local = localTarget(target);
|
|
71152
71681
|
if (!local)
|
|
71153
71682
|
continue;
|
|
71154
|
-
const resolved = local.startsWith("/") ?
|
|
71155
|
-
if (!
|
|
71683
|
+
const resolved = local.startsWith("/") ? path37.join(root, local) : path37.resolve(base, local);
|
|
71684
|
+
if (!exists2(resolved))
|
|
71156
71685
|
missing(target, index + 1, "link");
|
|
71157
71686
|
}
|
|
71158
71687
|
for (const [, span] of text.matchAll(CODE_SPAN)) {
|
|
@@ -71161,10 +71690,10 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71161
71690
|
continue;
|
|
71162
71691
|
const relative = /^\.\.?\//.test(candidate);
|
|
71163
71692
|
const first = candidate.split("/")[0];
|
|
71164
|
-
if (!relative && !(tracked ? tracked.has(first) :
|
|
71693
|
+
if (!relative && !(tracked ? tracked.has(first) : exists2(path37.join(root, first))))
|
|
71165
71694
|
continue;
|
|
71166
|
-
const resolved = relative ?
|
|
71167
|
-
if (!
|
|
71695
|
+
const resolved = relative ? path37.resolve(base, candidate) : path37.join(root, candidate);
|
|
71696
|
+
if (!exists2(resolved))
|
|
71168
71697
|
missing(span, index + 1, "pointer");
|
|
71169
71698
|
}
|
|
71170
71699
|
}
|
|
@@ -71289,7 +71818,7 @@ var init_prompt = () => {};
|
|
|
71289
71818
|
// packages/workit-cli/src/verbs/doctor.ts
|
|
71290
71819
|
var exports_doctor = {};
|
|
71291
71820
|
__export(exports_doctor, {
|
|
71292
|
-
run: () =>
|
|
71821
|
+
run: () => run6
|
|
71293
71822
|
});
|
|
71294
71823
|
async function confirmForcedLockClear(root, args, io) {
|
|
71295
71824
|
const lock = inspectMetadataLock(root);
|
|
@@ -71312,7 +71841,7 @@ async function confirmForcedLockClear(root, args, io) {
|
|
|
71312
71841
|
return "cancelled";
|
|
71313
71842
|
return /^y(es)?$/i.test(answer.trim());
|
|
71314
71843
|
}
|
|
71315
|
-
async function
|
|
71844
|
+
async function run6(argv, io) {
|
|
71316
71845
|
const root = workspaceRootFor();
|
|
71317
71846
|
const force = argv.includes("--force");
|
|
71318
71847
|
let fixLock = null;
|
|
@@ -71330,6 +71859,18 @@ async function run5(argv, io) {
|
|
|
71330
71859
|
}
|
|
71331
71860
|
fixLock = clearStaleMetadataLock(root, { force });
|
|
71332
71861
|
}
|
|
71862
|
+
let sessionHook = null;
|
|
71863
|
+
if (argv.includes("--fix")) {
|
|
71864
|
+
try {
|
|
71865
|
+
const fixed = fixSessionHook({ host: "cli", cwd: io.cwd, workspaceRoot: root });
|
|
71866
|
+
sessionHook = { action: fixed.action, detail: fixed.detail };
|
|
71867
|
+
} catch (error) {
|
|
71868
|
+
sessionHook = {
|
|
71869
|
+
action: "failed",
|
|
71870
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
71871
|
+
};
|
|
71872
|
+
}
|
|
71873
|
+
}
|
|
71333
71874
|
const report = runDoctor({
|
|
71334
71875
|
host: "cli",
|
|
71335
71876
|
cwd: io.cwd,
|
|
@@ -71352,7 +71893,7 @@ async function run5(argv, io) {
|
|
|
71352
71893
|
budget: knowledge.budget,
|
|
71353
71894
|
findings: knowledge.findings.length
|
|
71354
71895
|
} : { unavailable: true };
|
|
71355
|
-
io.stdout(`${JSON.stringify({ ...report, ...fixLock ? { fixLock } : {}, knowledge: summary }, null, 2)}
|
|
71896
|
+
io.stdout(`${JSON.stringify({ ...report, ...fixLock ? { fixLock } : {}, ...sessionHook ? { sessionHook } : {}, knowledge: summary }, null, 2)}
|
|
71356
71897
|
`);
|
|
71357
71898
|
return report.exitCode;
|
|
71358
71899
|
}
|
|
@@ -71361,6 +71902,9 @@ async function run5(argv, io) {
|
|
|
71361
71902
|
io.stdout(`fix-lock: ${what}${fixLock.guardCleared ? "; removed abandoned reclaim guard" : ""}
|
|
71362
71903
|
`);
|
|
71363
71904
|
}
|
|
71905
|
+
if (sessionHook)
|
|
71906
|
+
io.stdout(`fix: session hook ${sessionHook.action}: ${sessionHook.detail}
|
|
71907
|
+
`);
|
|
71364
71908
|
io.stdout(`workit doctor — ${report.ok ? "healthy" : "problems found"} (${report.offline ? "offline" : "online"})
|
|
71365
71909
|
`);
|
|
71366
71910
|
for (const check of report.checks) {
|
|
@@ -71493,11 +72037,11 @@ var init_redact = __esm(() => {
|
|
|
71493
72037
|
});
|
|
71494
72038
|
|
|
71495
72039
|
// packages/workit-core/src/checks.ts
|
|
71496
|
-
import { spawn, spawnSync as
|
|
72040
|
+
import { spawn, spawnSync as spawnSync17 } from "node:child_process";
|
|
71497
72041
|
import { createHash as createHash15 } from "node:crypto";
|
|
71498
72042
|
import fs18 from "node:fs";
|
|
71499
72043
|
import os13 from "node:os";
|
|
71500
|
-
import
|
|
72044
|
+
import path38 from "node:path";
|
|
71501
72045
|
import { StringDecoder } from "node:string_decoder";
|
|
71502
72046
|
function tailLines(text, lines = TAIL_LINES) {
|
|
71503
72047
|
const all = text.replace(/\r\n?/gu, `
|
|
@@ -71617,7 +72161,7 @@ function planSpawn(argv, options) {
|
|
|
71617
72161
|
return { file: argv[0], args: [], verbatim: false, shell: true };
|
|
71618
72162
|
if (options.platform !== "win32")
|
|
71619
72163
|
return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
|
|
71620
|
-
const win =
|
|
72164
|
+
const win = path38.win32;
|
|
71621
72165
|
const isFile = options.isFile ?? ((file) => {
|
|
71622
72166
|
try {
|
|
71623
72167
|
return fs18.statSync(file).isFile();
|
|
@@ -71672,7 +72216,7 @@ function runCheckCommand(argv, options) {
|
|
|
71672
72216
|
if (!child?.pid)
|
|
71673
72217
|
return;
|
|
71674
72218
|
if (windows)
|
|
71675
|
-
|
|
72219
|
+
spawnSync17("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
71676
72220
|
stdio: "ignore",
|
|
71677
72221
|
windowsHide: true
|
|
71678
72222
|
});
|
|
@@ -71774,10 +72318,10 @@ function runCheckCommand(argv, options) {
|
|
|
71774
72318
|
function storeLog(storeRoot, log) {
|
|
71775
72319
|
const digest = logDigest(log);
|
|
71776
72320
|
const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
|
|
71777
|
-
const file =
|
|
72321
|
+
const file = path38.join(storeRoot, ref);
|
|
71778
72322
|
try {
|
|
71779
72323
|
if (!fs18.existsSync(file)) {
|
|
71780
|
-
fs18.mkdirSync(
|
|
72324
|
+
fs18.mkdirSync(path38.dirname(file), { recursive: true });
|
|
71781
72325
|
const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
71782
72326
|
fs18.writeFileSync(temp, log, { mode: 384 });
|
|
71783
72327
|
fs18.renameSync(temp, file);
|
|
@@ -71790,7 +72334,7 @@ function storeLog(storeRoot, log) {
|
|
|
71790
72334
|
function pruneCheckLogs(storeRoot, options = {}) {
|
|
71791
72335
|
const limits = { ...LOG_RETENTION, ...options.retention };
|
|
71792
72336
|
const now = options.now ?? Date.now();
|
|
71793
|
-
const dir =
|
|
72337
|
+
const dir = path38.join(storeRoot, "blobs", "logs");
|
|
71794
72338
|
const report = { removed: 0, removedBytes: 0, kept: 0 };
|
|
71795
72339
|
let names;
|
|
71796
72340
|
try {
|
|
@@ -71800,7 +72344,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71800
72344
|
}
|
|
71801
72345
|
const files = names.flatMap((name) => {
|
|
71802
72346
|
try {
|
|
71803
|
-
const stat = fs18.statSync(
|
|
72347
|
+
const stat = fs18.statSync(path38.join(dir, name));
|
|
71804
72348
|
return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
|
|
71805
72349
|
} catch {
|
|
71806
72350
|
return [];
|
|
@@ -71819,7 +72363,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71819
72363
|
continue;
|
|
71820
72364
|
if (!options.dryRun)
|
|
71821
72365
|
try {
|
|
71822
|
-
fs18.rmSync(
|
|
72366
|
+
fs18.rmSync(path38.join(dir, file.name), { force: true });
|
|
71823
72367
|
} catch {
|
|
71824
72368
|
continue;
|
|
71825
72369
|
}
|
|
@@ -71850,9 +72394,9 @@ var init_checks3 = __esm(() => {
|
|
|
71850
72394
|
// packages/workit-cli/src/verbs/gc.ts
|
|
71851
72395
|
var exports_gc = {};
|
|
71852
72396
|
__export(exports_gc, {
|
|
71853
|
-
run: () =>
|
|
72397
|
+
run: () => run7
|
|
71854
72398
|
});
|
|
71855
|
-
async function
|
|
72399
|
+
async function run7(argv, io) {
|
|
71856
72400
|
const dryRun = argv.includes("--dry-run");
|
|
71857
72401
|
const pruneRecovery = argv.includes("--prune-recovery");
|
|
71858
72402
|
if (pruneRecovery && !dryRun && !argv.includes("--yes"))
|
|
@@ -71896,9 +72440,9 @@ var init_gc = __esm(() => {
|
|
|
71896
72440
|
// packages/workit-cli/src/verbs/uninstall.ts
|
|
71897
72441
|
var exports_uninstall = {};
|
|
71898
72442
|
__export(exports_uninstall, {
|
|
71899
|
-
run: () =>
|
|
72443
|
+
run: () => run8
|
|
71900
72444
|
});
|
|
71901
|
-
async function
|
|
72445
|
+
async function run8(_argv, io) {
|
|
71902
72446
|
if (io.json)
|
|
71903
72447
|
return emit(io, fail("invalid_input", "workit uninstall is interactive and has no --json output", {
|
|
71904
72448
|
unblock: "run `workit uninstall` in a terminal without --json"
|
|
@@ -71914,7 +72458,7 @@ var init_uninstall2 = __esm(() => {
|
|
|
71914
72458
|
// packages/workit-cli/src/verbs/grant.ts
|
|
71915
72459
|
var exports_grant = {};
|
|
71916
72460
|
__export(exports_grant, {
|
|
71917
|
-
run: () =>
|
|
72461
|
+
run: () => run9,
|
|
71918
72462
|
runGrant: () => runGrant
|
|
71919
72463
|
});
|
|
71920
72464
|
function show(argv, io) {
|
|
@@ -72035,7 +72579,7 @@ var USAGE2 = "workit grant show [<workspace>] [--all] | grant set <workspace> <k
|
|
|
72035
72579
|
...endpoint.endpointIssue ? [` note: ${endpoint.endpointIssue}`] : [],
|
|
72036
72580
|
` verification: ${verification} (${verification === "independent" ? "a normal-risk behavior change needs a non-author verdict" : "a normal-risk behavior change needs a passing check and the author's --self verdict, shown as self-reviewed"})`
|
|
72037
72581
|
], usage2 = (io, message) => emit(io, fail("invalid_input", `${message}
|
|
72038
|
-
usage: ${USAGE2}`)),
|
|
72582
|
+
usage: ${USAGE2}`)), run9 = (argv, io) => runGrant(argv, io);
|
|
72039
72583
|
var init_grant = __esm(() => {
|
|
72040
72584
|
init_autonomy();
|
|
72041
72585
|
init_release_tracks();
|
|
@@ -72064,9 +72608,9 @@ var init_grant = __esm(() => {
|
|
|
72064
72608
|
// packages/workit-cli/src/verbs/check.ts
|
|
72065
72609
|
var exports_check = {};
|
|
72066
72610
|
__export(exports_check, {
|
|
72067
|
-
run: () =>
|
|
72611
|
+
run: () => run10
|
|
72068
72612
|
});
|
|
72069
|
-
import
|
|
72613
|
+
import path39 from "node:path";
|
|
72070
72614
|
function parse5(argv) {
|
|
72071
72615
|
const split = argv.indexOf("--");
|
|
72072
72616
|
const head = split >= 0 ? argv.slice(0, split) : [...argv];
|
|
@@ -72215,7 +72759,7 @@ function boundedArgv(argv) {
|
|
|
72215
72759
|
const truncated = cut.length !== argv.length || cut.some((item, index) => item !== argv[index]);
|
|
72216
72760
|
return { argv: cut, truncated };
|
|
72217
72761
|
}
|
|
72218
|
-
async function
|
|
72762
|
+
async function run10(argv, io) {
|
|
72219
72763
|
const options = parse5(argv);
|
|
72220
72764
|
if (options instanceof Error)
|
|
72221
72765
|
return emit(io, fail("invalid_input", options.message, { unblock: USAGE3 }));
|
|
@@ -72249,7 +72793,7 @@ async function run9(argv, io) {
|
|
|
72249
72793
|
if (options.shell && command.length !== 1)
|
|
72250
72794
|
return emit(io, fail("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
|
|
72251
72795
|
}
|
|
72252
|
-
const relCwd = posix(
|
|
72796
|
+
const relCwd = posix(path39.relative(top, runCwd));
|
|
72253
72797
|
const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
|
|
72254
72798
|
const actor = actorFromEnv(io.env);
|
|
72255
72799
|
const branchKey = codeKey(io.cwd, { base: options.base });
|
|
@@ -72373,7 +72917,7 @@ async function run9(argv, io) {
|
|
|
72373
72917
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
72374
72918
|
return 0;
|
|
72375
72919
|
}
|
|
72376
|
-
var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(
|
|
72920
|
+
var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path39.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS;
|
|
72377
72921
|
var init_check = __esm(() => {
|
|
72378
72922
|
init_check_config();
|
|
72379
72923
|
init_checks3();
|
|
@@ -72395,9 +72939,9 @@ var init_check = __esm(() => {
|
|
|
72395
72939
|
var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
72396
72940
|
|
|
72397
72941
|
// packages/workit-core/src/git/ops.ts
|
|
72398
|
-
import { spawnSync as
|
|
72399
|
-
import { existsSync as
|
|
72400
|
-
import
|
|
72942
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
72943
|
+
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
|
|
72944
|
+
import path40 from "node:path";
|
|
72401
72945
|
function operationInProgress(cwd) {
|
|
72402
72946
|
const markers = [
|
|
72403
72947
|
["rebase-merge", "rebase"],
|
|
@@ -72410,18 +72954,18 @@ function operationInProgress(cwd) {
|
|
|
72410
72954
|
if (!run.ok)
|
|
72411
72955
|
return null;
|
|
72412
72956
|
const found = run.stdout.split(`
|
|
72413
|
-
`).map((line) =>
|
|
72957
|
+
`).map((line) => path40.resolve(cwd, line.trim()));
|
|
72414
72958
|
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
72415
72959
|
for (const [index, [, operation]] of markers.entries()) {
|
|
72416
72960
|
const marker = found[index];
|
|
72417
|
-
if (!marker || !
|
|
72961
|
+
if (!marker || !existsSync19(marker))
|
|
72418
72962
|
continue;
|
|
72419
|
-
if (index === 1 &&
|
|
72963
|
+
if (index === 1 && existsSync19(path40.join(marker, "applying")))
|
|
72420
72964
|
return { operation: "am", commitAllowed: false, branch: null };
|
|
72421
|
-
if (index === 0 &&
|
|
72965
|
+
if (index === 0 && existsSync19(path40.join(marker, "amend")) && !conflicted()) {
|
|
72422
72966
|
let headName = "";
|
|
72423
72967
|
try {
|
|
72424
|
-
headName =
|
|
72968
|
+
headName = readFileSync19(path40.join(marker, "head-name"), "utf8").trim();
|
|
72425
72969
|
} catch {}
|
|
72426
72970
|
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
72427
72971
|
return { operation, commitAllowed: branch !== null, branch };
|
|
@@ -72671,7 +73215,7 @@ function gitCommit(cwd, input) {
|
|
|
72671
73215
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
72672
73216
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
72673
73217
|
const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
|
|
72674
|
-
const addable = paths.filter((value) =>
|
|
73218
|
+
const addable = paths.filter((value) => existsSync19(path40.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
|
|
72675
73219
|
if (addable.length) {
|
|
72676
73220
|
const added = git5(cwd, ["add", "-A", "--", ...addable]);
|
|
72677
73221
|
if (!added.ok)
|
|
@@ -72950,7 +73494,7 @@ ${run.stdout}`;
|
|
|
72950
73494
|
} : { ok: false, lease: false, error: gitError(run) };
|
|
72951
73495
|
}
|
|
72952
73496
|
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
|
|
72953
|
-
const result =
|
|
73497
|
+
const result = spawnSync18("git", args, {
|
|
72954
73498
|
cwd,
|
|
72955
73499
|
encoding: "utf8",
|
|
72956
73500
|
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
@@ -73004,10 +73548,10 @@ var init_ops = __esm(() => {
|
|
|
73004
73548
|
|
|
73005
73549
|
// packages/workit-core/src/forge/reruns.ts
|
|
73006
73550
|
import fs19 from "node:fs";
|
|
73007
|
-
import
|
|
73551
|
+
import path41 from "node:path";
|
|
73008
73552
|
function rerunLogPath(cwd) {
|
|
73009
73553
|
const common = gitCommonDir(cwd);
|
|
73010
|
-
return common ?
|
|
73554
|
+
return common ? path41.join(common, "workit", "ci-reruns.jsonl") : null;
|
|
73011
73555
|
}
|
|
73012
73556
|
function rerunCounts(cwd, key) {
|
|
73013
73557
|
const counts = new Map;
|
|
@@ -73042,7 +73586,7 @@ function recordReruns(cwd, rows) {
|
|
|
73042
73586
|
if (!file)
|
|
73043
73587
|
return false;
|
|
73044
73588
|
try {
|
|
73045
|
-
fs19.mkdirSync(
|
|
73589
|
+
fs19.mkdirSync(path41.dirname(file), { recursive: true });
|
|
73046
73590
|
fs19.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
|
|
73047
73591
|
`).join(""));
|
|
73048
73592
|
return true;
|
|
@@ -73055,7 +73599,7 @@ function withRerunLock(cwd, fn) {
|
|
|
73055
73599
|
if (!file)
|
|
73056
73600
|
return fn();
|
|
73057
73601
|
const lock = `${file.slice(0, -".jsonl".length)}.lock`;
|
|
73058
|
-
fs19.mkdirSync(
|
|
73602
|
+
fs19.mkdirSync(path41.dirname(lock), { recursive: true });
|
|
73059
73603
|
const until = Date.now() + LOCK_WAIT_MS2;
|
|
73060
73604
|
for (;; ) {
|
|
73061
73605
|
try {
|
|
@@ -73478,7 +74022,7 @@ var init_report = __esm(() => {
|
|
|
73478
74022
|
});
|
|
73479
74023
|
|
|
73480
74024
|
// packages/workit-core/src/forge/pr-ops.ts
|
|
73481
|
-
import { spawnSync as
|
|
74025
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73482
74026
|
function fillFromCommits(cwd, resolved, base) {
|
|
73483
74027
|
const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
|
|
73484
74028
|
if (!base.startsWith("-"))
|
|
@@ -73486,7 +74030,7 @@ function fillFromCommits(cwd, resolved, base) {
|
|
|
73486
74030
|
const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
|
|
73487
74031
|
if (!from)
|
|
73488
74032
|
return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
|
|
73489
|
-
const log =
|
|
74033
|
+
const log = spawnSync19("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
|
|
73490
74034
|
cwd,
|
|
73491
74035
|
encoding: "utf8",
|
|
73492
74036
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -73842,10 +74386,10 @@ var init_pr_ops = __esm(() => {
|
|
|
73842
74386
|
});
|
|
73843
74387
|
|
|
73844
74388
|
// packages/workit-core/src/stack.ts
|
|
73845
|
-
import { spawnSync as
|
|
74389
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
73846
74390
|
import { createHash as createHash16, randomBytes as randomBytes3 } from "node:crypto";
|
|
73847
74391
|
import fs20 from "node:fs";
|
|
73848
|
-
import
|
|
74392
|
+
import path42 from "node:path";
|
|
73849
74393
|
function worktreeOf(cwd, branch) {
|
|
73850
74394
|
const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
|
|
73851
74395
|
if (!list.ok)
|
|
@@ -73889,7 +74433,7 @@ function gitRestack(cwd, input) {
|
|
|
73889
74433
|
if (!scratch)
|
|
73890
74434
|
return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
|
|
73891
74435
|
fs20.mkdirSync(scratch, { recursive: true });
|
|
73892
|
-
dir =
|
|
74436
|
+
dir = path42.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
|
|
73893
74437
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
73894
74438
|
if (!added.ok)
|
|
73895
74439
|
return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
|
|
@@ -73930,7 +74474,7 @@ function pruneScratch(cwd) {
|
|
|
73930
74474
|
if (!scratch || !fs20.existsSync(scratch))
|
|
73931
74475
|
return;
|
|
73932
74476
|
for (const name of fs20.readdirSync(scratch)) {
|
|
73933
|
-
const dir =
|
|
74477
|
+
const dir = path42.join(scratch, name);
|
|
73934
74478
|
if (!rebaseInProgress(dir) && !trackedDirt(dir))
|
|
73935
74479
|
gitRun3(cwd, ["worktree", "remove", "--force", dir]);
|
|
73936
74480
|
}
|
|
@@ -73940,7 +74484,7 @@ function stacksDir(cwd) {
|
|
|
73940
74484
|
const root = storeRoot(cwd);
|
|
73941
74485
|
if (!root.ok)
|
|
73942
74486
|
return stackFail(root.code, root.error, root.unblock);
|
|
73943
|
-
return { ok: true, data:
|
|
74487
|
+
return { ok: true, data: path42.join(root.value.root, "stacks") };
|
|
73944
74488
|
}
|
|
73945
74489
|
function parseStack(raw) {
|
|
73946
74490
|
if (!isRecord7(raw) || !Array.isArray(raw.branches))
|
|
@@ -73992,7 +74536,7 @@ function readStack(cwd, name) {
|
|
|
73992
74536
|
const dir = stacksDir(cwd);
|
|
73993
74537
|
if (!dir.ok)
|
|
73994
74538
|
return dir;
|
|
73995
|
-
const file =
|
|
74539
|
+
const file = path42.join(dir.data, fileFor(name));
|
|
73996
74540
|
let text;
|
|
73997
74541
|
try {
|
|
73998
74542
|
text = fs20.readFileSync(file, "utf8");
|
|
@@ -74013,7 +74557,7 @@ function writeStack(cwd, stack, now = new Date) {
|
|
|
74013
74557
|
const dir = stacksDir(cwd);
|
|
74014
74558
|
if (!dir.ok)
|
|
74015
74559
|
return dir;
|
|
74016
|
-
const file =
|
|
74560
|
+
const file = path42.join(dir.data, fileFor(stack.name));
|
|
74017
74561
|
const temp = `${file}.${process.pid}.tmp`;
|
|
74018
74562
|
try {
|
|
74019
74563
|
fs20.mkdirSync(dir.data, { recursive: true });
|
|
@@ -74041,7 +74585,7 @@ function listStacks(cwd) {
|
|
|
74041
74585
|
for (const name of names) {
|
|
74042
74586
|
let parsed = null;
|
|
74043
74587
|
try {
|
|
74044
|
-
parsed = parseStack(JSON.parse(fs20.readFileSync(
|
|
74588
|
+
parsed = parseStack(JSON.parse(fs20.readFileSync(path42.join(dir.data, name), "utf8")));
|
|
74045
74589
|
} catch {
|
|
74046
74590
|
parsed = null;
|
|
74047
74591
|
}
|
|
@@ -74100,7 +74644,7 @@ function takeLock(lock) {
|
|
|
74100
74644
|
host: localLockHost(),
|
|
74101
74645
|
nonce: randomBytes3(8).toString("hex")
|
|
74102
74646
|
};
|
|
74103
|
-
fs20.writeFileSync(
|
|
74647
|
+
fs20.writeFileSync(path42.join(lock, OWNER), JSON.stringify(owner));
|
|
74104
74648
|
return owner;
|
|
74105
74649
|
}
|
|
74106
74650
|
function reapLock(lock, observed) {
|
|
@@ -74137,7 +74681,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74137
74681
|
return dir;
|
|
74138
74682
|
if (!validName(name))
|
|
74139
74683
|
return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
|
|
74140
|
-
const lock =
|
|
74684
|
+
const lock = path42.join(dir.data, `${fileFor(name)}.lock`);
|
|
74141
74685
|
try {
|
|
74142
74686
|
fs20.mkdirSync(dir.data, { recursive: true });
|
|
74143
74687
|
} catch (error) {
|
|
@@ -74167,7 +74711,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74167
74711
|
const touch = () => {
|
|
74168
74712
|
try {
|
|
74169
74713
|
const now = new Date;
|
|
74170
|
-
fs20.utimesSync(
|
|
74714
|
+
fs20.utimesSync(path42.join(lock, OWNER), now, now);
|
|
74171
74715
|
} catch {}
|
|
74172
74716
|
};
|
|
74173
74717
|
const beat = setInterval(touch, HEARTBEAT_MS);
|
|
@@ -74355,7 +74899,7 @@ function commitKeys(cwd, range) {
|
|
|
74355
74899
|
const patches = new Map;
|
|
74356
74900
|
const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
|
|
74357
74901
|
if (diff.ok && diff.stdout.trim()) {
|
|
74358
|
-
const ids =
|
|
74902
|
+
const ids = spawnSync20("git", ["patch-id", "--stable"], {
|
|
74359
74903
|
cwd,
|
|
74360
74904
|
input: diff.stdout,
|
|
74361
74905
|
encoding: "utf8",
|
|
@@ -74979,7 +75523,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74979
75523
|
...unblock ? { unblock } : {},
|
|
74980
75524
|
...data ? { data } : {}
|
|
74981
75525
|
}), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
74982
|
-
const run =
|
|
75526
|
+
const run = spawnSync20("git", args, {
|
|
74983
75527
|
cwd,
|
|
74984
75528
|
encoding: "utf8",
|
|
74985
75529
|
timeout: timeoutMs,
|
|
@@ -75007,7 +75551,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
75007
75551
|
return !status.ok || status.stdout.trim() !== "";
|
|
75008
75552
|
}, scratchDir = (cwd) => {
|
|
75009
75553
|
const dir = stacksDir(cwd);
|
|
75010
|
-
return dir.ok ?
|
|
75554
|
+
return dir.ok ? path42.join(dir.data, "worktrees") : null;
|
|
75011
75555
|
}, firstLine = (run) => (`${run.stderr}
|
|
75012
75556
|
${run.stdout}`.split(`
|
|
75013
75557
|
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash16("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
|
|
@@ -75022,12 +75566,12 @@ ${run.stdout}`.split(`
|
|
|
75022
75566
|
}, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), str3 = (value) => typeof value === "string" && value ? value : null, LOCK_WAIT_MS3 = 2000, HEARTBEAT_MS = 20000, HEARTBEAT_STALE_MS, OWNERLESS_STALE_MS = 30000, OWNER = "owner", readOwner = (lock) => {
|
|
75023
75567
|
let raw = null;
|
|
75024
75568
|
try {
|
|
75025
|
-
raw = fs20.readFileSync(
|
|
75569
|
+
raw = fs20.readFileSync(path42.join(lock, OWNER), "utf8");
|
|
75026
75570
|
} catch {
|
|
75027
75571
|
raw = null;
|
|
75028
75572
|
}
|
|
75029
75573
|
let age = null;
|
|
75030
|
-
for (const target of [
|
|
75574
|
+
for (const target of [path42.join(lock, OWNER), lock])
|
|
75031
75575
|
try {
|
|
75032
75576
|
age = Date.now() - fs20.statSync(target).mtimeMs;
|
|
75033
75577
|
break;
|
|
@@ -75060,7 +75604,7 @@ var init_stack = __esm(() => {
|
|
|
75060
75604
|
});
|
|
75061
75605
|
|
|
75062
75606
|
// packages/workit-core/src/forge/pr-edit.ts
|
|
75063
|
-
import { spawnSync as
|
|
75607
|
+
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
75064
75608
|
function openPr(cwd, resolved, pr) {
|
|
75065
75609
|
const grant = requireGrant(cwd, "pr");
|
|
75066
75610
|
if (!grant.allowed)
|
|
@@ -75225,7 +75769,7 @@ function replyToThread(cwd, resolved, input) {
|
|
|
75225
75769
|
});
|
|
75226
75770
|
}
|
|
75227
75771
|
var label = (resolved, number) => `${resolved.forge.kind === "github" ? "PR #" : "MR !"}${number}`, git6 = (cwd, args) => {
|
|
75228
|
-
const run =
|
|
75772
|
+
const run = spawnSync21("git", args, {
|
|
75229
75773
|
cwd,
|
|
75230
75774
|
encoding: "utf8",
|
|
75231
75775
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -75245,15 +75789,15 @@ var init_pr_edit = __esm(() => {
|
|
|
75245
75789
|
});
|
|
75246
75790
|
|
|
75247
75791
|
// packages/workit-core/src/forge/exec.ts
|
|
75248
|
-
import { spawnSync as
|
|
75792
|
+
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
75249
75793
|
import fs21 from "node:fs";
|
|
75250
|
-
import
|
|
75794
|
+
import path43 from "node:path";
|
|
75251
75795
|
function findExecutable(bin, env) {
|
|
75252
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
75796
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path43.delimiter).filter(Boolean);
|
|
75253
75797
|
const exts = process.platform === "win32" ? [".exe"] : [""];
|
|
75254
75798
|
for (const dir of dirs)
|
|
75255
75799
|
for (const ext of exts) {
|
|
75256
|
-
const candidate =
|
|
75800
|
+
const candidate = path43.join(dir, `${bin}${ext}`);
|
|
75257
75801
|
try {
|
|
75258
75802
|
const stat = fs21.statSync(candidate);
|
|
75259
75803
|
if (stat.isFile())
|
|
@@ -75280,7 +75824,7 @@ function systemRunner(kind, apiHost, env = process.env) {
|
|
|
75280
75824
|
if (!exe)
|
|
75281
75825
|
return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
|
|
75282
75826
|
const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
|
|
75283
|
-
const result =
|
|
75827
|
+
const result = spawnSync22(exe, [...args], {
|
|
75284
75828
|
encoding: "utf8",
|
|
75285
75829
|
env: { ...childEnv, ...token },
|
|
75286
75830
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -76444,7 +76988,7 @@ var init_duration = __esm(() => {
|
|
|
76444
76988
|
});
|
|
76445
76989
|
|
|
76446
76990
|
// packages/workit-cli/src/verbs/forge-common.ts
|
|
76447
|
-
import { readFileSync as
|
|
76991
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
76448
76992
|
function parseFlags(argv, spec) {
|
|
76449
76993
|
const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
|
|
76450
76994
|
for (let index = 0;index < argv.length; index += 1) {
|
|
@@ -76588,7 +77132,7 @@ var init_forge_common = __esm(() => {
|
|
|
76588
77132
|
forgeDeps = {
|
|
76589
77133
|
runner: undefined,
|
|
76590
77134
|
npm: undefined,
|
|
76591
|
-
readStdin: () =>
|
|
77135
|
+
readStdin: () => readFileSync20(0, "utf8"),
|
|
76592
77136
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
76593
77137
|
now: () => Date.now()
|
|
76594
77138
|
};
|
|
@@ -76597,14 +77141,14 @@ var init_forge_common = __esm(() => {
|
|
|
76597
77141
|
// packages/workit-cli/src/verbs/pr.ts
|
|
76598
77142
|
var exports_pr = {};
|
|
76599
77143
|
__export(exports_pr, {
|
|
76600
|
-
run: () =>
|
|
77144
|
+
run: () => run11
|
|
76601
77145
|
});
|
|
76602
|
-
import { readFileSync as
|
|
76603
|
-
import
|
|
77146
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
77147
|
+
import path44 from "node:path";
|
|
76604
77148
|
function readBodyFile(io, file) {
|
|
76605
77149
|
try {
|
|
76606
77150
|
return {
|
|
76607
|
-
body: file === "-" ? forgeDeps.readStdin() :
|
|
77151
|
+
body: file === "-" ? forgeDeps.readStdin() : readFileSync21(path44.resolve(io.cwd, file), "utf8")
|
|
76608
77152
|
};
|
|
76609
77153
|
} catch {
|
|
76610
77154
|
return `cannot read --body-file ${file}`;
|
|
@@ -76931,7 +77475,7 @@ async function reply(argv, io) {
|
|
|
76931
77475
|
`${[data.replied ? "replied to" : null, data.resolved ? "resolved" : null].filter(Boolean).join(" and ")} thread ${data.thread} on ${prLabel(kind, data.number)}${data.replyUrl ? ` ${data.replyUrl}` : ""}`
|
|
76932
77476
|
]);
|
|
76933
77477
|
}
|
|
76934
|
-
async function
|
|
77478
|
+
async function run11(argv, io) {
|
|
76935
77479
|
const [sub, ...rest] = argv;
|
|
76936
77480
|
if (sub === "status")
|
|
76937
77481
|
return status(rest, io);
|
|
@@ -76966,7 +77510,7 @@ var init_pr = __esm(() => {
|
|
|
76966
77510
|
// packages/workit-cli/src/verbs/ci.ts
|
|
76967
77511
|
var exports_ci = {};
|
|
76968
77512
|
__export(exports_ci, {
|
|
76969
|
-
run: () =>
|
|
77513
|
+
run: () => run12
|
|
76970
77514
|
});
|
|
76971
77515
|
async function wait(argv, io) {
|
|
76972
77516
|
const flags = parseFlags(argv, {
|
|
@@ -77135,7 +77679,7 @@ async function rerun(argv, io) {
|
|
|
77135
77679
|
"next: workit ci wait"
|
|
77136
77680
|
]);
|
|
77137
77681
|
}
|
|
77138
|
-
async function
|
|
77682
|
+
async function run12(argv, io) {
|
|
77139
77683
|
const [sub, ...rest] = argv;
|
|
77140
77684
|
if (sub === "wait")
|
|
77141
77685
|
return wait(rest, io);
|
|
@@ -77183,10 +77727,10 @@ var init_implicit_task = __esm(() => {
|
|
|
77183
77727
|
// packages/workit-cli/src/verbs/git.ts
|
|
77184
77728
|
var exports_git = {};
|
|
77185
77729
|
__export(exports_git, {
|
|
77186
|
-
run: () =>
|
|
77730
|
+
run: () => run13
|
|
77187
77731
|
});
|
|
77188
|
-
import { readFileSync as
|
|
77189
|
-
import
|
|
77732
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
77733
|
+
import path45 from "node:path";
|
|
77190
77734
|
async function branch(argv, io) {
|
|
77191
77735
|
const flags = parseFlags(argv, {
|
|
77192
77736
|
base: "value",
|
|
@@ -77277,7 +77821,7 @@ function commitMessage(parsed, io) {
|
|
|
77277
77821
|
|
|
77278
77822
|
`);
|
|
77279
77823
|
try {
|
|
77280
|
-
return file === "-" ?
|
|
77824
|
+
return file === "-" ? readFileSync22(0, "utf8") : readFileSync22(path45.resolve(io.cwd, file), "utf8");
|
|
77281
77825
|
} catch (error) {
|
|
77282
77826
|
return {
|
|
77283
77827
|
error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -77380,7 +77924,7 @@ async function push(argv, io) {
|
|
|
77380
77924
|
...data.upstream ? [`upstream: ${data.remote}/${data.branch}`] : []
|
|
77381
77925
|
]);
|
|
77382
77926
|
}
|
|
77383
|
-
async function
|
|
77927
|
+
async function run13(argv, io) {
|
|
77384
77928
|
const [sub, ...rest] = argv;
|
|
77385
77929
|
if (sub === "branch")
|
|
77386
77930
|
return branch(rest, io);
|
|
@@ -77408,7 +77952,7 @@ var init_git2 = __esm(() => {
|
|
|
77408
77952
|
});
|
|
77409
77953
|
|
|
77410
77954
|
// packages/workit-core/src/forge/verify.ts
|
|
77411
|
-
import { spawnSync as
|
|
77955
|
+
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
77412
77956
|
function finish(cwd, report, actor) {
|
|
77413
77957
|
const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
|
|
77414
77958
|
const out = { ...report, delivered };
|
|
@@ -77621,7 +78165,7 @@ var NPM_NAME, SEMVER2, SAFE_ARG, systemNpm = (args) => {
|
|
|
77621
78165
|
};
|
|
77622
78166
|
const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
|
|
77623
78167
|
const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
|
|
77624
|
-
const result = process.platform === "win32" ?
|
|
78168
|
+
const result = process.platform === "win32" ? spawnSync23(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync23("npm", [...args], options);
|
|
77625
78169
|
return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
77626
78170
|
}, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
|
|
77627
78171
|
try {
|
|
@@ -77646,9 +78190,9 @@ var init_verify = __esm(() => {
|
|
|
77646
78190
|
// packages/workit-cli/src/verbs/verify-delivery.ts
|
|
77647
78191
|
var exports_verify_delivery = {};
|
|
77648
78192
|
__export(exports_verify_delivery, {
|
|
77649
|
-
run: () =>
|
|
78193
|
+
run: () => run14
|
|
77650
78194
|
});
|
|
77651
|
-
async function
|
|
78195
|
+
async function run14(argv, io) {
|
|
77652
78196
|
const flags = parseFlags(argv, {
|
|
77653
78197
|
expect: "value",
|
|
77654
78198
|
branch: "value",
|
|
@@ -77730,7 +78274,7 @@ var init_verify_delivery = __esm(() => {
|
|
|
77730
78274
|
// packages/workit-cli/src/verbs/stack.ts
|
|
77731
78275
|
var exports_stack = {};
|
|
77732
78276
|
__export(exports_stack, {
|
|
77733
|
-
run: () =>
|
|
78277
|
+
run: () => run15
|
|
77734
78278
|
});
|
|
77735
78279
|
async function plan(argv, io) {
|
|
77736
78280
|
const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
|
|
@@ -77912,7 +78456,7 @@ async function land(argv, io) {
|
|
|
77912
78456
|
unblock: ${data.stoppedAt.unblock}` : data.complete ? "stack complete" : ""
|
|
77913
78457
|
].filter(Boolean));
|
|
77914
78458
|
}
|
|
77915
|
-
async function
|
|
78459
|
+
async function run15(argv, io) {
|
|
77916
78460
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
77917
78461
|
if (sub === "plan")
|
|
77918
78462
|
return plan(rest, io);
|
|
@@ -77942,10 +78486,10 @@ var init_stack2 = __esm(() => {
|
|
|
77942
78486
|
});
|
|
77943
78487
|
|
|
77944
78488
|
// packages/workit-core/src/fanout.ts
|
|
77945
|
-
import { spawnSync as
|
|
78489
|
+
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
77946
78490
|
import { createHash as createHash17 } from "node:crypto";
|
|
77947
78491
|
import fs23 from "node:fs";
|
|
77948
|
-
import
|
|
78492
|
+
import path46 from "node:path";
|
|
77949
78493
|
function expandBraces(pattern, limit = 64) {
|
|
77950
78494
|
for (let index = 0;index < pattern.length; index += 1) {
|
|
77951
78495
|
if (pattern[index] === "\\") {
|
|
@@ -78179,7 +78723,7 @@ function parsePlan(raw, defaults, name) {
|
|
|
78179
78723
|
id,
|
|
78180
78724
|
branch,
|
|
78181
78725
|
base: optional("base") ?? "",
|
|
78182
|
-
worktree:
|
|
78726
|
+
worktree: path46.resolve(defaults.root, optional("worktree") ?? path46.join(defaults.worktreeRoot, id)),
|
|
78183
78727
|
tier,
|
|
78184
78728
|
dependsOn: [...new Set(dependsOn ?? [])],
|
|
78185
78729
|
scope,
|
|
@@ -78408,11 +78952,11 @@ function defaultTrunk(cwd) {
|
|
|
78408
78952
|
}
|
|
78409
78953
|
function mainCheckout(cwd) {
|
|
78410
78954
|
const common = gitCommonDir(cwd);
|
|
78411
|
-
return common &&
|
|
78955
|
+
return common && path46.basename(common) === ".git" ? path46.dirname(common) : path46.resolve(cwd);
|
|
78412
78956
|
}
|
|
78413
78957
|
function worktreeRoot(cwd) {
|
|
78414
78958
|
const main = mainCheckout(cwd);
|
|
78415
|
-
return
|
|
78959
|
+
return path46.join(path46.dirname(main), `${path46.basename(main)}-wt`);
|
|
78416
78960
|
}
|
|
78417
78961
|
function sliceHash(slice) {
|
|
78418
78962
|
const {
|
|
@@ -78430,7 +78974,7 @@ function fanoutsDir(cwd) {
|
|
|
78430
78974
|
const root = storeRoot(cwd);
|
|
78431
78975
|
if (!root.ok)
|
|
78432
78976
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
78433
|
-
return { ok: true, data:
|
|
78977
|
+
return { ok: true, data: path46.join(root.value.root, "fanouts") };
|
|
78434
78978
|
}
|
|
78435
78979
|
function parseStored(raw) {
|
|
78436
78980
|
if (!isRecord8(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -78496,7 +79040,7 @@ function readFanout(cwd, name) {
|
|
|
78496
79040
|
const dir = fanoutsDir(cwd);
|
|
78497
79041
|
if (!dir.ok)
|
|
78498
79042
|
return dir;
|
|
78499
|
-
const file =
|
|
79043
|
+
const file = path46.join(dir.data, stackFileName(name));
|
|
78500
79044
|
let parsed = null;
|
|
78501
79045
|
try {
|
|
78502
79046
|
parsed = parseStored(JSON.parse(fs23.readFileSync(file, "utf8")));
|
|
@@ -78521,7 +79065,7 @@ function listFanouts(cwd) {
|
|
|
78521
79065
|
for (const entry of names) {
|
|
78522
79066
|
let parsed = null;
|
|
78523
79067
|
try {
|
|
78524
|
-
parsed = parseStored(JSON.parse(fs23.readFileSync(
|
|
79068
|
+
parsed = parseStored(JSON.parse(fs23.readFileSync(path46.join(dir.data, entry), "utf8")));
|
|
78525
79069
|
} catch {
|
|
78526
79070
|
parsed = null;
|
|
78527
79071
|
}
|
|
@@ -78551,7 +79095,7 @@ function writeFanout(cwd, plan) {
|
|
|
78551
79095
|
const dir = fanoutsDir(cwd);
|
|
78552
79096
|
if (!dir.ok)
|
|
78553
79097
|
return dir;
|
|
78554
|
-
const file =
|
|
79098
|
+
const file = path46.join(dir.data, stackFileName(plan.name));
|
|
78555
79099
|
const temp = `${file}.${process.pid}.tmp`;
|
|
78556
79100
|
try {
|
|
78557
79101
|
fs23.mkdirSync(dir.data, { recursive: true });
|
|
@@ -78715,7 +79259,7 @@ var FANOUT_VERSION = 1, TIERS, FAN_IN_MODES, fanoutFail = (code, error, unblock,
|
|
|
78715
79259
|
text: edges.map((edge) => `add "${edge.dependsOn}" to "dependsOn" of slice ${edge.slice}`).join("; ")
|
|
78716
79260
|
};
|
|
78717
79261
|
}, gitRun4 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
78718
|
-
const run =
|
|
79262
|
+
const run = spawnSync24("git", args, {
|
|
78719
79263
|
cwd,
|
|
78720
79264
|
encoding: "utf8",
|
|
78721
79265
|
timeout: timeoutMs,
|
|
@@ -78755,7 +79299,7 @@ var init_fanout = __esm(() => {
|
|
|
78755
79299
|
// packages/workit-core/src/fanout-worktree.ts
|
|
78756
79300
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
78757
79301
|
import fs24 from "node:fs";
|
|
78758
|
-
import
|
|
79302
|
+
import path47 from "node:path";
|
|
78759
79303
|
function rowSample(lines) {
|
|
78760
79304
|
const out = [];
|
|
78761
79305
|
let bytes = 0;
|
|
@@ -78815,7 +79359,7 @@ function adminDir(worktree) {
|
|
|
78815
79359
|
const file = dir.stdout.trim();
|
|
78816
79360
|
let token = null;
|
|
78817
79361
|
try {
|
|
78818
|
-
token = fs24.readFileSync(
|
|
79362
|
+
token = fs24.readFileSync(path47.join(file, TOKEN_FILE), "utf8").trim() || null;
|
|
78819
79363
|
} catch {
|
|
78820
79364
|
token = null;
|
|
78821
79365
|
}
|
|
@@ -78823,7 +79367,7 @@ function adminDir(worktree) {
|
|
|
78823
79367
|
const stat = worktreeDeps.stat(file);
|
|
78824
79368
|
return {
|
|
78825
79369
|
path: file,
|
|
78826
|
-
id:
|
|
79370
|
+
id: path47.basename(file),
|
|
78827
79371
|
ino: stat.ino.toString(),
|
|
78828
79372
|
token,
|
|
78829
79373
|
birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
|
|
@@ -78839,7 +79383,7 @@ function markAdminDir(worktree) {
|
|
|
78839
79383
|
return null;
|
|
78840
79384
|
const token = randomBytes4(16).toString("hex");
|
|
78841
79385
|
try {
|
|
78842
|
-
fs24.writeFileSync(
|
|
79386
|
+
fs24.writeFileSync(path47.join(admin.path, TOKEN_FILE), `${token}
|
|
78843
79387
|
`);
|
|
78844
79388
|
} catch {
|
|
78845
79389
|
return null;
|
|
@@ -78854,7 +79398,7 @@ function excludeScratch(cwd) {
|
|
|
78854
79398
|
const common = gitCommonDir(cwd);
|
|
78855
79399
|
if (!common)
|
|
78856
79400
|
return;
|
|
78857
|
-
const file =
|
|
79401
|
+
const file = path47.join(common, "info", "exclude");
|
|
78858
79402
|
let text = "";
|
|
78859
79403
|
try {
|
|
78860
79404
|
text = fs24.readFileSync(file, "utf8");
|
|
@@ -78863,7 +79407,7 @@ function excludeScratch(cwd) {
|
|
|
78863
79407
|
}
|
|
78864
79408
|
if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
|
|
78865
79409
|
return;
|
|
78866
|
-
fs24.mkdirSync(
|
|
79410
|
+
fs24.mkdirSync(path47.dirname(file), { recursive: true });
|
|
78867
79411
|
fs24.appendFileSync(file, `${text && !text.endsWith(`
|
|
78868
79412
|
`) ? `
|
|
78869
79413
|
` : ""}# workit fanout: per-worker scratch dirs
|
|
@@ -78871,7 +79415,7 @@ ${EXCLUDE_LINE}
|
|
|
78871
79415
|
`);
|
|
78872
79416
|
}
|
|
78873
79417
|
function ensureScratch(worktree) {
|
|
78874
|
-
const scratch =
|
|
79418
|
+
const scratch = path47.join(worktree, SCRATCH_DIR);
|
|
78875
79419
|
fs24.mkdirSync(scratch, { recursive: true });
|
|
78876
79420
|
return scratch;
|
|
78877
79421
|
}
|
|
@@ -79007,7 +79551,7 @@ function releaseSliceWorktree(cwd, plan, input) {
|
|
|
79007
79551
|
const entry = worktrees[index];
|
|
79008
79552
|
if (index === 0)
|
|
79009
79553
|
return fanoutFail("blocked", `${target} is the main checkout; it is never released`);
|
|
79010
|
-
if (
|
|
79554
|
+
if (inside3(cwd, entry.path))
|
|
79011
79555
|
return fanoutFail("blocked", `this command runs inside ${entry.path}`, `run it from the main checkout: workit --cwd <main checkout> fanout worktree release ${slice.id}`);
|
|
79012
79556
|
if (entry.branch !== null && entry.branch !== `refs/heads/${slice.branch}`)
|
|
79013
79557
|
return fanoutFail("blocked", `${entry.path} is on ${entry.branch.replace(/^refs\/heads\//u, "")}, not slice ${slice.id}'s ${slice.branch}; nothing was removed`);
|
|
@@ -79089,7 +79633,7 @@ function unpushedCount(cwd, branch) {
|
|
|
79089
79633
|
return count.ok ? Number(count.stdout.trim()) : null;
|
|
79090
79634
|
}
|
|
79091
79635
|
function removeScratch(worktree) {
|
|
79092
|
-
const scratch =
|
|
79636
|
+
const scratch = path47.join(worktree, SCRATCH_DIR);
|
|
79093
79637
|
let stat;
|
|
79094
79638
|
try {
|
|
79095
79639
|
stat = fs24.lstatSync(scratch);
|
|
@@ -79105,16 +79649,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
79105
79649
|
try {
|
|
79106
79650
|
return fs24.realpathSync.native(target);
|
|
79107
79651
|
} catch {
|
|
79108
|
-
return
|
|
79652
|
+
return path47.resolve(target);
|
|
79109
79653
|
}
|
|
79110
79654
|
}, samePath = (a, b) => {
|
|
79111
79655
|
const left = canonical2(a);
|
|
79112
79656
|
const right = canonical2(b);
|
|
79113
79657
|
return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
79114
|
-
},
|
|
79115
|
-
const relative =
|
|
79116
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
79117
|
-
}, slicePath = (cwd, slice) =>
|
|
79658
|
+
}, inside3 = (child, parent) => {
|
|
79659
|
+
const relative = path47.relative(canonical2(parent), canonical2(child));
|
|
79660
|
+
return relative === "" || !relative.startsWith("..") && !path47.isAbsolute(relative);
|
|
79661
|
+
}, slicePath = (cwd, slice) => path47.isAbsolute(slice.worktree) ? slice.worktree : path47.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, TOKEN_FILE = "workit-fanout-token", worktreeDeps, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
|
|
79118
79662
|
`)[0] || "unknown error"}`);
|
|
79119
79663
|
var init_fanout_worktree = __esm(() => {
|
|
79120
79664
|
init_ops();
|
|
@@ -79235,7 +79779,7 @@ var init_fanout_brief = __esm(() => {
|
|
|
79235
79779
|
});
|
|
79236
79780
|
|
|
79237
79781
|
// packages/workit-core/src/fanout-landed.ts
|
|
79238
|
-
import { spawnSync as
|
|
79782
|
+
import { spawnSync as spawnSync25 } from "node:child_process";
|
|
79239
79783
|
function forgeBreaker(resolved) {
|
|
79240
79784
|
if (!resolved)
|
|
79241
79785
|
return { forge: null, down: () => null };
|
|
@@ -79326,7 +79870,7 @@ function trunkPatchIds(ctx, fork) {
|
|
|
79326
79870
|
"--"
|
|
79327
79871
|
]);
|
|
79328
79872
|
if (log.ok && log.stdout.trim()) {
|
|
79329
|
-
const run =
|
|
79873
|
+
const run = spawnSync25("git", ["patch-id", "--stable"], {
|
|
79330
79874
|
cwd: ctx.cwd,
|
|
79331
79875
|
input: log.stdout,
|
|
79332
79876
|
encoding: "utf8",
|
|
@@ -79887,10 +80431,10 @@ var init_fanout_status = __esm(() => {
|
|
|
79887
80431
|
// packages/workit-cli/src/verbs/fanout.ts
|
|
79888
80432
|
var exports_fanout = {};
|
|
79889
80433
|
__export(exports_fanout, {
|
|
79890
|
-
run: () =>
|
|
80434
|
+
run: () => run16
|
|
79891
80435
|
});
|
|
79892
80436
|
import fs25 from "node:fs";
|
|
79893
|
-
import
|
|
80437
|
+
import path48 from "node:path";
|
|
79894
80438
|
function forgeFor(io, offline) {
|
|
79895
80439
|
if (offline)
|
|
79896
80440
|
return { forge: null, error: "--offline" };
|
|
@@ -79951,7 +80495,7 @@ function plan2(argv, io) {
|
|
|
79951
80495
|
return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
|
|
79952
80496
|
if (flags.positionals.length !== 1)
|
|
79953
80497
|
return usage3(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
|
|
79954
|
-
const file =
|
|
80498
|
+
const file = path48.resolve(io.cwd, flags.positionals[0]);
|
|
79955
80499
|
let raw;
|
|
79956
80500
|
try {
|
|
79957
80501
|
raw = JSON.parse(fs25.readFileSync(file, "utf8"));
|
|
@@ -80107,7 +80651,7 @@ function worktree(argv, io) {
|
|
|
80107
80651
|
...data.notes.map((note) => `note: ${note}`)
|
|
80108
80652
|
]);
|
|
80109
80653
|
}
|
|
80110
|
-
async function
|
|
80654
|
+
async function run16(argv, io) {
|
|
80111
80655
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
80112
80656
|
if (sub === "plan")
|
|
80113
80657
|
return plan2(rest, io);
|
|
@@ -80173,7 +80717,7 @@ var init_fanout2 = __esm(() => {
|
|
|
80173
80717
|
// packages/workit-cli/src/verbs/ledger.ts
|
|
80174
80718
|
var exports_ledger = {};
|
|
80175
80719
|
__export(exports_ledger, {
|
|
80176
|
-
run: () =>
|
|
80720
|
+
run: () => run17
|
|
80177
80721
|
});
|
|
80178
80722
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
80179
80723
|
import { parseArgs } from "node:util";
|
|
@@ -80197,7 +80741,7 @@ function targetBranch(io, rows, branch, pr) {
|
|
|
80197
80741
|
}
|
|
80198
80742
|
return { ok: true, value: branch ?? null };
|
|
80199
80743
|
}
|
|
80200
|
-
async function
|
|
80744
|
+
async function run17(argv, io) {
|
|
80201
80745
|
let parsed;
|
|
80202
80746
|
try {
|
|
80203
80747
|
parsed = parseArgs({ args: argv, options: OPTIONS, allowPositionals: true, strict: true });
|
|
@@ -95434,7 +95978,7 @@ var init_ast = __esm(() => {
|
|
|
95434
95978
|
|
|
95435
95979
|
// packages/workit-cli/src/test-audit/rules.ts
|
|
95436
95980
|
import { builtinModules } from "node:module";
|
|
95437
|
-
import
|
|
95981
|
+
import path49 from "node:path";
|
|
95438
95982
|
function testCallee(call) {
|
|
95439
95983
|
let callee = call.callee;
|
|
95440
95984
|
if (callee.type === "CallExpression")
|
|
@@ -95927,12 +96471,12 @@ function checkConstantsOnly(ctx, emit) {
|
|
|
95927
96471
|
}
|
|
95928
96472
|
function checkOverMocking(ctx, emit) {
|
|
95929
96473
|
const { program } = ctx.parsed;
|
|
95930
|
-
const unit =
|
|
96474
|
+
const unit = path49.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
|
|
95931
96475
|
const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
|
|
95932
96476
|
const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
|
|
95933
96477
|
for (const call of mocked) {
|
|
95934
96478
|
const spec = call.arguments[0].value;
|
|
95935
|
-
const base =
|
|
96479
|
+
const base = path49.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
95936
96480
|
if (base === unit)
|
|
95937
96481
|
emit({
|
|
95938
96482
|
rule: "over-mocking",
|
|
@@ -96320,11 +96864,11 @@ var init_rules = __esm(() => {
|
|
|
96320
96864
|
});
|
|
96321
96865
|
|
|
96322
96866
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
96323
|
-
import { spawnSync as
|
|
96324
|
-
import { existsSync as
|
|
96325
|
-
import
|
|
96867
|
+
import { spawnSync as spawnSync26 } from "node:child_process";
|
|
96868
|
+
import { existsSync as existsSync20, readdirSync as readdirSync9, readFileSync as readFileSync23, statSync as statSync8 } from "node:fs";
|
|
96869
|
+
import path50 from "node:path";
|
|
96326
96870
|
function git7(cwd, args) {
|
|
96327
|
-
const run =
|
|
96871
|
+
const run = spawnSync26("git", ["-c", "core.quotepath=off", ...args], {
|
|
96328
96872
|
cwd,
|
|
96329
96873
|
encoding: "utf8",
|
|
96330
96874
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -96335,7 +96879,7 @@ function walkTests(dir, out) {
|
|
|
96335
96879
|
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
96336
96880
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
96337
96881
|
continue;
|
|
96338
|
-
const full =
|
|
96882
|
+
const full = path50.join(dir, entry.name);
|
|
96339
96883
|
if (entry.isDirectory()) {
|
|
96340
96884
|
if (!SKIP_DIRS.has(entry.name))
|
|
96341
96885
|
walkTests(full, out);
|
|
@@ -96347,10 +96891,10 @@ function expandPaths(cwd, inputs) {
|
|
|
96347
96891
|
const files = [];
|
|
96348
96892
|
const missing = [];
|
|
96349
96893
|
for (const input of inputs.length > 0 ? inputs : ["."]) {
|
|
96350
|
-
const full =
|
|
96351
|
-
if (!
|
|
96894
|
+
const full = path50.resolve(cwd, input);
|
|
96895
|
+
if (!existsSync20(full))
|
|
96352
96896
|
missing.push(input);
|
|
96353
|
-
else if (
|
|
96897
|
+
else if (statSync8(full).isDirectory())
|
|
96354
96898
|
walkTests(full, files);
|
|
96355
96899
|
else
|
|
96356
96900
|
files.push(full);
|
|
@@ -96384,11 +96928,11 @@ function changedLines(cwd, base) {
|
|
|
96384
96928
|
for (let offset = 0;offset < count; offset += 1)
|
|
96385
96929
|
lines.add(start + offset);
|
|
96386
96930
|
}
|
|
96387
|
-
changed.set(
|
|
96931
|
+
changed.set(path50.join(root, file), lines);
|
|
96388
96932
|
}
|
|
96389
96933
|
const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
96390
96934
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
96391
|
-
changed.set(
|
|
96935
|
+
changed.set(path50.join(root, file), "all");
|
|
96392
96936
|
return changed;
|
|
96393
96937
|
}
|
|
96394
96938
|
function auditFiles(files, display) {
|
|
@@ -96401,7 +96945,7 @@ function auditFiles(files, display) {
|
|
|
96401
96945
|
const shown = display(file);
|
|
96402
96946
|
let parsed;
|
|
96403
96947
|
try {
|
|
96404
|
-
parsed = parseSource(
|
|
96948
|
+
parsed = parseSource(readFileSync23(file, "utf8"), file);
|
|
96405
96949
|
} catch (error) {
|
|
96406
96950
|
parseErrors.push({
|
|
96407
96951
|
file: shown,
|
|
@@ -96450,7 +96994,7 @@ function auditFiles(files, display) {
|
|
|
96450
96994
|
durationMs: Math.round(performance.now() - started)
|
|
96451
96995
|
};
|
|
96452
96996
|
}
|
|
96453
|
-
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(
|
|
96997
|
+
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path50.sep).join("/"), SEVERITY_ORDER, ruleIds;
|
|
96454
96998
|
var init_audit = __esm(() => {
|
|
96455
96999
|
init_ast();
|
|
96456
97000
|
init_rules();
|
|
@@ -96464,23 +97008,23 @@ var init_audit = __esm(() => {
|
|
|
96464
97008
|
// packages/workit-cli/src/test-audit/mutate.ts
|
|
96465
97009
|
import { spawn as spawn2 } from "node:child_process";
|
|
96466
97010
|
import {
|
|
96467
|
-
existsSync as
|
|
96468
|
-
lstatSync as
|
|
96469
|
-
mkdirSync as
|
|
97011
|
+
existsSync as existsSync21,
|
|
97012
|
+
lstatSync as lstatSync8,
|
|
97013
|
+
mkdirSync as mkdirSync10,
|
|
96470
97014
|
mkdtempSync as mkdtempSync4,
|
|
96471
97015
|
readdirSync as readdirSync10,
|
|
96472
|
-
readFileSync as
|
|
97016
|
+
readFileSync as readFileSync24,
|
|
96473
97017
|
readlinkSync as readlinkSync3,
|
|
96474
97018
|
realpathSync as realpathSync9,
|
|
96475
|
-
renameSync as
|
|
96476
|
-
rmSync as
|
|
96477
|
-
statSync as
|
|
97019
|
+
renameSync as renameSync6,
|
|
97020
|
+
rmSync as rmSync8,
|
|
97021
|
+
statSync as statSync9,
|
|
96478
97022
|
symlinkSync,
|
|
96479
|
-
writeFileSync as
|
|
97023
|
+
writeFileSync as writeFileSync11,
|
|
96480
97024
|
copyFileSync as copyFileSync6
|
|
96481
97025
|
} from "node:fs";
|
|
96482
97026
|
import os14 from "node:os";
|
|
96483
|
-
import
|
|
97027
|
+
import path51 from "node:path";
|
|
96484
97028
|
function mutantsFor(source, file, lines) {
|
|
96485
97029
|
const parsed = parseSource(source, file);
|
|
96486
97030
|
const out = [];
|
|
@@ -96553,7 +97097,7 @@ function relatedTests(source, testFiles) {
|
|
|
96553
97097
|
for (const match of text.matchAll(SPECIFIER)) {
|
|
96554
97098
|
const spec = match[1];
|
|
96555
97099
|
if (spec.startsWith(".")) {
|
|
96556
|
-
if (stripExt(
|
|
97100
|
+
if (stripExt(path51.posix.join(path51.posix.dirname(file), spec)) === target)
|
|
96557
97101
|
return true;
|
|
96558
97102
|
} else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
|
|
96559
97103
|
return true;
|
|
@@ -96573,12 +97117,12 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96573
97117
|
for (const name of names) {
|
|
96574
97118
|
if (!name.startsWith(TEMP_PREFIX))
|
|
96575
97119
|
continue;
|
|
96576
|
-
const dir =
|
|
97120
|
+
const dir = path51.join(tmp, name);
|
|
96577
97121
|
try {
|
|
96578
|
-
const stat =
|
|
97122
|
+
const stat = lstatSync8(dir);
|
|
96579
97123
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
96580
97124
|
continue;
|
|
96581
|
-
const pid = Number(
|
|
97125
|
+
const pid = Number(readFileSync24(path51.join(dir, PID_FILE), "utf8"));
|
|
96582
97126
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
96583
97127
|
continue;
|
|
96584
97128
|
} catch (error) {
|
|
@@ -96586,23 +97130,23 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96586
97130
|
continue;
|
|
96587
97131
|
}
|
|
96588
97132
|
try {
|
|
96589
|
-
|
|
97133
|
+
rmSync8(dir, { recursive: true, force: true });
|
|
96590
97134
|
removed += 1;
|
|
96591
97135
|
} catch {}
|
|
96592
97136
|
}
|
|
96593
97137
|
return removed;
|
|
96594
97138
|
}
|
|
96595
97139
|
function linkNodeModules(origin, target, repo, copy) {
|
|
96596
|
-
|
|
97140
|
+
mkdirSync10(target, { recursive: true });
|
|
96597
97141
|
for (const entry of readdirSync10(origin, { withFileTypes: true })) {
|
|
96598
|
-
const from =
|
|
96599
|
-
const to =
|
|
97142
|
+
const from = path51.join(origin, entry.name);
|
|
97143
|
+
const to = path51.join(target, entry.name);
|
|
96600
97144
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
96601
97145
|
linkNodeModules(from, to, repo, copy);
|
|
96602
97146
|
continue;
|
|
96603
97147
|
}
|
|
96604
97148
|
if (entry.name.startsWith(".") && entry.name !== ".bin" && entry.isDirectory()) {
|
|
96605
|
-
|
|
97149
|
+
mkdirSync10(to, { recursive: true });
|
|
96606
97150
|
continue;
|
|
96607
97151
|
}
|
|
96608
97152
|
if (entry.isSymbolicLink()) {
|
|
@@ -96612,9 +97156,9 @@ function linkNodeModules(origin, target, repo, copy) {
|
|
|
96612
97156
|
} catch {
|
|
96613
97157
|
continue;
|
|
96614
97158
|
}
|
|
96615
|
-
const relative =
|
|
96616
|
-
if (!relative.startsWith("..") && !
|
|
96617
|
-
symlinkSync(
|
|
97159
|
+
const relative = path51.relative(repo, real);
|
|
97160
|
+
if (!relative.startsWith("..") && !path51.isAbsolute(relative) && !relative.split(path51.sep).includes("node_modules")) {
|
|
97161
|
+
symlinkSync(path51.join(copy, relative), to, "junction");
|
|
96618
97162
|
continue;
|
|
96619
97163
|
}
|
|
96620
97164
|
}
|
|
@@ -96629,33 +97173,33 @@ function copySymlink(repo, tree, from, to) {
|
|
|
96629
97173
|
real = null;
|
|
96630
97174
|
}
|
|
96631
97175
|
const realRepo = realpathSync9(repo);
|
|
96632
|
-
if (real &&
|
|
96633
|
-
symlinkSync(
|
|
97176
|
+
if (real && inside4(realRepo, real)) {
|
|
97177
|
+
symlinkSync(path51.relative(path51.dirname(to), path51.join(tree, path51.relative(realRepo, real))), to);
|
|
96634
97178
|
return;
|
|
96635
97179
|
}
|
|
96636
|
-
if (real &&
|
|
97180
|
+
if (real && statSync9(real).isFile())
|
|
96637
97181
|
copyFileSync6(real, to);
|
|
96638
97182
|
else
|
|
96639
97183
|
symlinkSync(readlinkSync3(from), to);
|
|
96640
97184
|
}
|
|
96641
97185
|
function writeInside(copy, file, content) {
|
|
96642
|
-
const target =
|
|
97186
|
+
const target = path51.join(copy, file);
|
|
96643
97187
|
try {
|
|
96644
|
-
const stat =
|
|
96645
|
-
if (!stat.isFile() || !
|
|
97188
|
+
const stat = lstatSync8(target);
|
|
97189
|
+
if (!stat.isFile() || !inside4(realpathSync9(copy), realpathSync9(path51.dirname(target))))
|
|
96646
97190
|
return false;
|
|
96647
97191
|
} catch {
|
|
96648
97192
|
return false;
|
|
96649
97193
|
}
|
|
96650
97194
|
const temp = `${target}.workit-mutant-${process.pid}`;
|
|
96651
|
-
|
|
96652
|
-
|
|
97195
|
+
writeFileSync11(temp, content);
|
|
97196
|
+
renameSync6(temp, target);
|
|
96653
97197
|
return true;
|
|
96654
97198
|
}
|
|
96655
97199
|
function copyWorkingTree(repo) {
|
|
96656
|
-
const dir = mkdtempSync4(
|
|
96657
|
-
|
|
96658
|
-
const tree =
|
|
97200
|
+
const dir = mkdtempSync4(path51.join(os14.tmpdir(), TEMP_PREFIX));
|
|
97201
|
+
writeFileSync11(path51.join(dir, PID_FILE), String(process.pid));
|
|
97202
|
+
const tree = path51.join(dir, "tree");
|
|
96659
97203
|
const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
96660
97204
|
if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
96661
97205
|
const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
@@ -96666,35 +97210,35 @@ function copyWorkingTree(repo) {
|
|
|
96666
97210
|
git7(tree, ["update-ref", "--no-deref", "HEAD", head]);
|
|
96667
97211
|
git7(tree, ["reset", "-q"]);
|
|
96668
97212
|
} else
|
|
96669
|
-
|
|
97213
|
+
mkdirSync10(tree, { recursive: true });
|
|
96670
97214
|
const listed = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00");
|
|
96671
97215
|
const dirs = new Set([""]);
|
|
96672
97216
|
for (const relative of listed) {
|
|
96673
97217
|
if (!relative)
|
|
96674
97218
|
continue;
|
|
96675
|
-
const from =
|
|
97219
|
+
const from = path51.join(repo, relative);
|
|
96676
97220
|
let stat;
|
|
96677
97221
|
try {
|
|
96678
|
-
stat =
|
|
97222
|
+
stat = lstatSync8(from);
|
|
96679
97223
|
} catch {
|
|
96680
97224
|
continue;
|
|
96681
97225
|
}
|
|
96682
|
-
const to =
|
|
96683
|
-
|
|
97226
|
+
const to = path51.join(tree, relative);
|
|
97227
|
+
mkdirSync10(path51.dirname(to), { recursive: true });
|
|
96684
97228
|
if (stat.isSymbolicLink())
|
|
96685
97229
|
copySymlink(repo, tree, from, to);
|
|
96686
97230
|
else if (stat.isFile())
|
|
96687
97231
|
copyFileSync6(from, to);
|
|
96688
|
-
let parent =
|
|
97232
|
+
let parent = path51.dirname(relative);
|
|
96689
97233
|
while (parent !== "." && !dirs.has(parent)) {
|
|
96690
97234
|
dirs.add(parent);
|
|
96691
|
-
parent =
|
|
97235
|
+
parent = path51.dirname(parent);
|
|
96692
97236
|
}
|
|
96693
97237
|
}
|
|
96694
97238
|
for (const parent of dirs) {
|
|
96695
|
-
const modules =
|
|
96696
|
-
if (
|
|
96697
|
-
linkNodeModules(modules,
|
|
97239
|
+
const modules = path51.join(repo, parent, "node_modules");
|
|
97240
|
+
if (existsSync21(modules) && !existsSync21(path51.join(tree, parent, "node_modules")))
|
|
97241
|
+
linkNodeModules(modules, path51.join(tree, parent, "node_modules"), repo, tree);
|
|
96698
97242
|
}
|
|
96699
97243
|
return { dir, tree };
|
|
96700
97244
|
}
|
|
@@ -96733,20 +97277,20 @@ async function runMutation(options) {
|
|
|
96733
97277
|
const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
96734
97278
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
96735
97279
|
try {
|
|
96736
|
-
return { file, text:
|
|
97280
|
+
return { file, text: readFileSync24(path51.join(repo, file), "utf8") };
|
|
96737
97281
|
} catch {
|
|
96738
97282
|
return { file, text: "" };
|
|
96739
97283
|
}
|
|
96740
97284
|
});
|
|
96741
97285
|
const candidates = [];
|
|
96742
97286
|
for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
96743
|
-
const relative = toPosix(
|
|
97287
|
+
const relative = toPosix(path51.relative(repo, absolute));
|
|
96744
97288
|
if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
|
|
96745
97289
|
continue;
|
|
96746
|
-
if (NOT_SOURCE.test(relative) || !
|
|
97290
|
+
if (NOT_SOURCE.test(relative) || !existsSync21(absolute))
|
|
96747
97291
|
continue;
|
|
96748
97292
|
try {
|
|
96749
|
-
candidates.push(...mutantsFor(
|
|
97293
|
+
candidates.push(...mutantsFor(readFileSync24(absolute, "utf8"), relative, lines));
|
|
96750
97294
|
} catch {}
|
|
96751
97295
|
}
|
|
96752
97296
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -96754,9 +97298,9 @@ async function runMutation(options) {
|
|
|
96754
97298
|
for (const mutant of mutants)
|
|
96755
97299
|
if (!related.has(mutant.file))
|
|
96756
97300
|
related.set(mutant.file, relatedTests(mutant.file, testFiles));
|
|
96757
|
-
const cwdRelative =
|
|
97301
|
+
const cwdRelative = path51.relative(repo, options.cwd);
|
|
96758
97302
|
const asArg = (file) => {
|
|
96759
|
-
const relative = toPosix(
|
|
97303
|
+
const relative = toPosix(path51.relative(cwdRelative, file));
|
|
96760
97304
|
return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
|
|
96761
97305
|
};
|
|
96762
97306
|
const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
|
|
@@ -96791,7 +97335,7 @@ async function runMutation(options) {
|
|
|
96791
97335
|
return finish2(options, 0, results, counts, started);
|
|
96792
97336
|
removeStaleCopies();
|
|
96793
97337
|
const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
|
|
96794
|
-
const copyCwd =
|
|
97338
|
+
const copyCwd = path51.join(copy, cwdRelative);
|
|
96795
97339
|
let current = null;
|
|
96796
97340
|
const restore = () => {
|
|
96797
97341
|
if (current)
|
|
@@ -96802,7 +97346,7 @@ async function runMutation(options) {
|
|
|
96802
97346
|
for (const child of active)
|
|
96803
97347
|
killTree(child);
|
|
96804
97348
|
restore();
|
|
96805
|
-
|
|
97349
|
+
rmSync8(copyDir, { recursive: true, force: true });
|
|
96806
97350
|
};
|
|
96807
97351
|
const onSignal = (signal) => {
|
|
96808
97352
|
cleanup();
|
|
@@ -96826,7 +97370,7 @@ async function runMutation(options) {
|
|
|
96826
97370
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
96827
97371
|
continue;
|
|
96828
97372
|
}
|
|
96829
|
-
const original =
|
|
97373
|
+
const original = readFileSync24(path51.join(copy, mutant.file), "utf8");
|
|
96830
97374
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
96831
97375
|
current = { file: mutant.file, original };
|
|
96832
97376
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -96882,9 +97426,9 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
|
|
|
96882
97426
|
} catch (error) {
|
|
96883
97427
|
return error.code === "EPERM";
|
|
96884
97428
|
}
|
|
96885
|
-
},
|
|
96886
|
-
const relative =
|
|
96887
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
97429
|
+
}, inside4 = (root, file) => {
|
|
97430
|
+
const relative = path51.relative(root, file);
|
|
97431
|
+
return relative === "" || !relative.startsWith("..") && !path51.isAbsolute(relative);
|
|
96888
97432
|
}, active, killTree = (child) => {
|
|
96889
97433
|
try {
|
|
96890
97434
|
if (child.pid && process.platform !== "win32")
|
|
@@ -96930,10 +97474,10 @@ var init_mutate = __esm(() => {
|
|
|
96930
97474
|
// packages/workit-cli/src/verbs/test-audit.ts
|
|
96931
97475
|
var exports_test_audit = {};
|
|
96932
97476
|
__export(exports_test_audit, {
|
|
96933
|
-
run: () =>
|
|
97477
|
+
run: () => run18
|
|
96934
97478
|
});
|
|
96935
|
-
import { existsSync as
|
|
96936
|
-
import
|
|
97479
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
97480
|
+
import path52 from "node:path";
|
|
96937
97481
|
function parse7(argv) {
|
|
96938
97482
|
const options = {
|
|
96939
97483
|
paths: [],
|
|
@@ -97031,14 +97575,14 @@ function human(data) {
|
|
|
97031
97575
|
}
|
|
97032
97576
|
return lines;
|
|
97033
97577
|
}
|
|
97034
|
-
async function
|
|
97578
|
+
async function run18(argv, io) {
|
|
97035
97579
|
const options = parse7(argv);
|
|
97036
97580
|
if (typeof options === "string")
|
|
97037
97581
|
return emit(io, fail("invalid_input", `${options}
|
|
97038
97582
|
usage: ${USAGE10}`));
|
|
97039
97583
|
const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
97040
|
-
const repo = top.ok ?
|
|
97041
|
-
const display = (file) => toPosix(
|
|
97584
|
+
const repo = top.ok ? path52.resolve(top.stdout.trim()) : null;
|
|
97585
|
+
const display = (file) => toPosix(path52.relative(io.cwd, file) || file);
|
|
97042
97586
|
let base = null;
|
|
97043
97587
|
let changed = null;
|
|
97044
97588
|
if (options.diff || options.mutate) {
|
|
@@ -97055,7 +97599,7 @@ usage: ${USAGE10}`));
|
|
|
97055
97599
|
}
|
|
97056
97600
|
let files;
|
|
97057
97601
|
if (options.diff && changed)
|
|
97058
|
-
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) &&
|
|
97602
|
+
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync22(file)).toSorted();
|
|
97059
97603
|
else {
|
|
97060
97604
|
const expanded = expandPaths(io.cwd, options.paths);
|
|
97061
97605
|
if (expanded.missing.length > 0)
|
|
@@ -97142,9 +97686,9 @@ var init_test_audit = __esm(() => {
|
|
|
97142
97686
|
// packages/workit-cli/src/verbs/knowledge.ts
|
|
97143
97687
|
var exports_knowledge = {};
|
|
97144
97688
|
__export(exports_knowledge, {
|
|
97145
|
-
run: () =>
|
|
97689
|
+
run: () => run19
|
|
97146
97690
|
});
|
|
97147
|
-
async function
|
|
97691
|
+
async function run19(argv, io) {
|
|
97148
97692
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
97149
97693
|
if (sub !== "lint" || rest.length > 0)
|
|
97150
97694
|
return emit(io, fail("invalid_input", `usage: ${USAGE11}`));
|
|
@@ -97278,11 +97822,11 @@ var init_youtrack_writes = __esm(() => {
|
|
|
97278
97822
|
// packages/workit-cli/src/verbs/youtrack.ts
|
|
97279
97823
|
var exports_youtrack = {};
|
|
97280
97824
|
__export(exports_youtrack, {
|
|
97281
|
-
run: () =>
|
|
97825
|
+
run: () => run20
|
|
97282
97826
|
});
|
|
97283
|
-
import { readFileSync as
|
|
97284
|
-
import
|
|
97285
|
-
async function
|
|
97827
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
97828
|
+
import path53 from "node:path";
|
|
97829
|
+
async function run20(argv, io) {
|
|
97286
97830
|
const [sub, ...rest] = argv;
|
|
97287
97831
|
if (sub !== "note" && sub !== "time" && sub !== "meeting")
|
|
97288
97832
|
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE12);
|
|
@@ -97327,7 +97871,7 @@ async function run19(argv, io) {
|
|
|
97327
97871
|
let markdown = flags.values.markdown ?? "";
|
|
97328
97872
|
if (flags.values.file)
|
|
97329
97873
|
try {
|
|
97330
|
-
markdown =
|
|
97874
|
+
markdown = readFileSync25(path53.resolve(io.cwd, flags.values.file), "utf8");
|
|
97331
97875
|
} catch (error) {
|
|
97332
97876
|
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE12);
|
|
97333
97877
|
}
|
|
@@ -97393,11 +97937,11 @@ var init_youtrack2 = __esm(() => {
|
|
|
97393
97937
|
// packages/workit-cli/src/verbs/changelog.ts
|
|
97394
97938
|
var exports_changelog = {};
|
|
97395
97939
|
__export(exports_changelog, {
|
|
97396
|
-
run: () =>
|
|
97940
|
+
run: () => run21
|
|
97397
97941
|
});
|
|
97398
|
-
import { readFileSync as
|
|
97399
|
-
import
|
|
97400
|
-
async function
|
|
97942
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
97943
|
+
import path54 from "node:path";
|
|
97944
|
+
async function run21(argv, io) {
|
|
97401
97945
|
const [sub, ...rest] = argv;
|
|
97402
97946
|
if (sub !== "apply")
|
|
97403
97947
|
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE13);
|
|
@@ -97442,7 +97986,7 @@ async function run20(argv, io) {
|
|
|
97442
97986
|
]);
|
|
97443
97987
|
}
|
|
97444
97988
|
var USAGE13 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
97445
|
-
const text = raw === "-" ?
|
|
97989
|
+
const text = raw === "-" ? readFileSync26(0, "utf8") : raw.startsWith("@") ? readFileSync26(path54.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
97446
97990
|
return JSON.parse(text);
|
|
97447
97991
|
};
|
|
97448
97992
|
var init_changelog2 = __esm(() => {
|
|
@@ -97454,7 +97998,7 @@ var init_changelog2 = __esm(() => {
|
|
|
97454
97998
|
// packages/workit-cli/src/verbs/handoff.ts
|
|
97455
97999
|
var exports_handoff = {};
|
|
97456
98000
|
__export(exports_handoff, {
|
|
97457
|
-
run: () =>
|
|
98001
|
+
run: () => run22
|
|
97458
98002
|
});
|
|
97459
98003
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
97460
98004
|
function human2(brief) {
|
|
@@ -97524,7 +98068,7 @@ async function resumeBrief(argv, io) {
|
|
|
97524
98068
|
}
|
|
97525
98069
|
return emit(io, ok({ ...data, recorded }), human2);
|
|
97526
98070
|
}
|
|
97527
|
-
async function
|
|
98071
|
+
async function run22(argv, io) {
|
|
97528
98072
|
if (!argv.some((arg) => arg === "--task" || arg.startsWith("--task=")))
|
|
97529
98073
|
return resumeBrief(argv, io);
|
|
97530
98074
|
await Promise.resolve().then(() => init_task());
|
|
@@ -97538,7 +98082,7 @@ var init_handoff = __esm(() => {
|
|
|
97538
98082
|
|
|
97539
98083
|
// packages/workit-cli/src/main.ts
|
|
97540
98084
|
init_package();
|
|
97541
|
-
import
|
|
98085
|
+
import path55 from "node:path";
|
|
97542
98086
|
|
|
97543
98087
|
// packages/workit-cli/src/help.ts
|
|
97544
98088
|
var HELP_FLAGS = new Set(["--help", "-h"]);
|
|
@@ -97700,7 +98244,7 @@ var familySubcommands = (name) => {
|
|
|
97700
98244
|
const implicit = name === "task" ? TASK_IMPLICIT : [];
|
|
97701
98245
|
const grammar = Object.entries(FAMILY_ACTIONS[name]).filter(([action]) => !implicit.some((entry) => entry.name === action)).map(([action, summary]) => ({
|
|
97702
98246
|
name: action,
|
|
97703
|
-
usage: name === "policy" && action !== "explain" ? `workit policy ${action} ${POLICY_JUDGE} ${FAMILY_OPTIONS}` : `workit ${name} ${action} ${FAMILY_OPTIONS}`,
|
|
98247
|
+
usage: name === "policy" && action !== "explain" ? `workit policy ${action} ${POLICY_JUDGE} ${FAMILY_OPTIONS}` : name === "worker" && action !== "assign" ? `workit worker ${action} [<workerId>] ${FAMILY_OPTIONS}` : `workit ${name} ${action} ${FAMILY_OPTIONS}`,
|
|
97704
98248
|
summary
|
|
97705
98249
|
}));
|
|
97706
98250
|
return [...implicit, ...grammar];
|
|
@@ -97757,8 +98301,8 @@ var VERBS = [
|
|
|
97757
98301
|
{
|
|
97758
98302
|
name: "doctor",
|
|
97759
98303
|
group: "setup",
|
|
97760
|
-
usage: "workit doctor [--fix-lock [--force [--yes]]]",
|
|
97761
|
-
summary: "Verify the offline installation health (--fix-lock clears a stale workit store lock)",
|
|
98304
|
+
usage: "workit doctor [--fix] [--fix-lock [--force [--yes]]]",
|
|
98305
|
+
summary: "Verify the offline installation health (--fix installs the session trailer hook; --fix-lock clears a stale workit store lock)",
|
|
97762
98306
|
load: () => Promise.resolve().then(() => (init_doctor2(), exports_doctor))
|
|
97763
98307
|
},
|
|
97764
98308
|
{
|
|
@@ -98184,7 +98728,7 @@ var defaultIo = (json) => ({
|
|
|
98184
98728
|
});
|
|
98185
98729
|
async function main(argv, overrides = {}, options = {}) {
|
|
98186
98730
|
const parsed = parseGlobals(argv);
|
|
98187
|
-
const cwd =
|
|
98731
|
+
const cwd = path55.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
98188
98732
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
98189
98733
|
if (parsed.error)
|
|
98190
98734
|
return emit(io, fail("invalid_input", parsed.error));
|