@brainervirus/workit-mcp 8.9.0 → 8.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +240 -105
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -18436,64 +18436,11 @@ function acquireFileLockSync(targetPath, options) {
18436
18436
  }
18437
18437
  }
18438
18438
  }
18439
- // packages/workit-core/src/host-session.ts
18440
- var HOST_SESSION_VARS = [
18441
- ["OPENCODE_SESSION_ID", () => "opencode"],
18442
- ["PI_SESSION_ID", () => "pi"],
18443
- [
18444
- "CODEX_THREAD_ID",
18445
- (env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
18446
- ]
18447
- ];
18448
- var family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
18449
- function hostSessionFromEnv(env) {
18450
- const value = (key) => env[key]?.trim() || null;
18451
- let inner = null;
18452
- for (const [key, host] of HOST_SESSION_VARS) {
18453
- const session = value(key);
18454
- if (session) {
18455
- inner = { host: host(env), session };
18456
- break;
18457
- }
18458
- }
18459
- const declared = value("WORKIT_HOST");
18460
- if (env.WORKIT_SESSION_ID !== undefined) {
18461
- const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
18462
- if (!inherited)
18463
- return { host: declared, session: value("WORKIT_SESSION_ID") };
18464
- }
18465
- return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
18466
- }
18467
-
18468
- // packages/workit-core/src/core/package-root.ts
18469
- import { existsSync } from "node:fs";
18470
- import path3 from "node:path";
18471
- import { fileURLToPath } from "node:url";
18472
- var packageRoot = () => {
18473
- let dir = path3.dirname(fileURLToPath(import.meta.url));
18474
- while (true) {
18475
- const parent = path3.dirname(dir);
18476
- if (existsSync(path3.join(dir, "package.json")) || parent === dir)
18477
- return dir;
18478
- dir = parent;
18479
- }
18480
- };
18481
- var assetRoot = () => {
18482
- const root = packageRoot();
18483
- const assets = path3.join(root, "assets");
18484
- return existsSync(assets) ? assets : root;
18485
- };
18486
-
18487
- // packages/workit-core/src/core/store-lock.ts
18488
- import { spawnSync as spawnSync2 } from "node:child_process";
18489
- import fs5 from "node:fs";
18490
- import { hostname } from "node:os";
18491
-
18492
18439
  // packages/workit-core/src/store/paths.ts
18493
18440
  import { spawnSync } from "node:child_process";
18494
18441
  import { createHash as createHash2 } from "node:crypto";
18495
18442
  import fs4 from "node:fs";
18496
- import path4 from "node:path";
18443
+ import path3 from "node:path";
18497
18444
  var NOT_A_REPO = /not a git repository \(or any (of the parent directories|parent up to)/u;
18498
18445
  var gitRun = (cwd, args) => {
18499
18446
  const run = spawnSync("git", args, {
@@ -18535,14 +18482,14 @@ var DISCOVERY_ENV = [
18535
18482
  ];
18536
18483
  var isGitDir = (dir) => {
18537
18484
  try {
18538
- return fs4.statSync(path4.join(dir, "HEAD")).isFile() && fs4.statSync(path4.join(dir, "objects")).isDirectory() && fs4.statSync(path4.join(dir, "refs")).isDirectory();
18485
+ return fs4.statSync(path3.join(dir, "HEAD")).isFile() && fs4.statSync(path3.join(dir, "objects")).isDirectory() && fs4.statSync(path3.join(dir, "refs")).isDirectory();
18539
18486
  } catch {
18540
18487
  return false;
18541
18488
  }
18542
18489
  };
18543
18490
  var reftableRefs = (common) => {
18544
18491
  try {
18545
- return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path4.join(common, "config"), "utf8"));
18492
+ return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path3.join(common, "config"), "utf8"));
18546
18493
  } catch {
18547
18494
  return false;
18548
18495
  }
@@ -18562,7 +18509,7 @@ function fastGit(root) {
18562
18509
  if (device !== null && stat.dev !== device)
18563
18510
  return { kind: "none" };
18564
18511
  device = stat.dev;
18565
- const dotGit = path4.join(dir, ".git");
18512
+ const dotGit = path3.join(dir, ".git");
18566
18513
  let entry = null;
18567
18514
  try {
18568
18515
  entry = fs4.statSync(dotGit);
@@ -18583,19 +18530,19 @@ function fastGit(root) {
18583
18530
  const match = /^gitdir: (.+)$/mu.exec(text);
18584
18531
  if (!match)
18585
18532
  return null;
18586
- gitDir = path4.resolve(dir, match[1].trim());
18533
+ gitDir = path3.resolve(dir, match[1].trim());
18587
18534
  } else
18588
18535
  return null;
18589
- if (!fs4.existsSync(path4.join(gitDir, "HEAD")))
18536
+ if (!fs4.existsSync(path3.join(gitDir, "HEAD")))
18590
18537
  return null;
18591
18538
  } else if (isGitDir(dir))
18592
18539
  gitDir = dir;
18593
18540
  if (gitDir) {
18594
18541
  let common = gitDir;
18595
18542
  try {
18596
- common = path4.resolve(gitDir, fs4.readFileSync(path4.join(gitDir, "commondir"), "utf8").trim());
18543
+ common = path3.resolve(gitDir, fs4.readFileSync(path3.join(gitDir, "commondir"), "utf8").trim());
18597
18544
  } catch {}
18598
- if (!fs4.existsSync(path4.join(common, "objects")))
18545
+ if (!fs4.existsSync(path3.join(common, "objects")))
18599
18546
  return null;
18600
18547
  return {
18601
18548
  kind: "repo",
@@ -18605,26 +18552,26 @@ function fastGit(root) {
18605
18552
  reftable: reftableRefs(common)
18606
18553
  };
18607
18554
  }
18608
- const parent = path4.dirname(dir);
18555
+ const parent = path3.dirname(dir);
18609
18556
  if (parent === dir)
18610
18557
  return { kind: "none" };
18611
18558
  dir = parent;
18612
18559
  }
18613
18560
  }
18614
18561
  function resolveStore(root) {
18615
- root = path4.resolve(root);
18562
+ root = path3.resolve(root);
18616
18563
  let directory = false;
18617
18564
  try {
18618
18565
  directory = fs4.statSync(root).isDirectory();
18619
18566
  } catch {}
18620
18567
  if (!directory)
18621
- return { dir: path4.join(root, ".workit"), shared: false, top: null };
18568
+ return { dir: path3.join(root, ".workit"), shared: false, top: null };
18622
18569
  const fast = fastGit(root);
18623
18570
  if (fast?.kind === "none")
18624
- return { dir: path4.join(root, ".workit"), shared: false, top: null };
18571
+ return { dir: path3.join(root, ".workit"), shared: false, top: null };
18625
18572
  if (fast?.kind === "repo")
18626
18573
  return {
18627
- dir: path4.join(fast.common, "workit"),
18574
+ dir: path3.join(fast.common, "workit"),
18628
18575
  shared: true,
18629
18576
  top: fast.top,
18630
18577
  git: { gitDir: fast.gitDir, top: fast.top, reftable: fast.reftable }
@@ -18634,20 +18581,20 @@ function resolveStore(root) {
18634
18581
  if (run.ok && common) {
18635
18582
  const top = gitRun(root, ["rev-parse", "--path-format=absolute", "--show-toplevel"]);
18636
18583
  return {
18637
- dir: path4.join(real(path4.resolve(root, common)), "workit"),
18584
+ dir: path3.join(real(path3.resolve(root, common)), "workit"),
18638
18585
  shared: true,
18639
18586
  top: top.ok && top.stdout.trim() ? real(top.stdout.trim()) : null
18640
18587
  };
18641
18588
  }
18642
18589
  if (run.missing || !run.ok && NOT_A_REPO.test(run.stderr))
18643
- return { dir: path4.join(root, ".workit"), shared: false, top: null };
18590
+ return { dir: path3.join(root, ".workit"), shared: false, top: null };
18644
18591
  return new Error(`cannot locate the workit store: git rev-parse failed (${run.stderr.trim().split(`
18645
18592
  `)[0] || "no output"}); fix the repository (git status should work here)`);
18646
18593
  }
18647
18594
  var rebasingBranch = (gitDir) => {
18648
18595
  for (const state of ["rebase-merge", "rebase-apply"]) {
18649
18596
  try {
18650
- const ref = fs4.readFileSync(path4.join(gitDir, state, "head-name"), "utf8").trim();
18597
+ const ref = fs4.readFileSync(path3.join(gitDir, state, "head-name"), "utf8").trim();
18651
18598
  const match = /^refs\/heads\/(.+)$/u.exec(ref);
18652
18599
  if (match)
18653
18600
  return match[1];
@@ -18662,7 +18609,7 @@ function resolveTaskKey(root, location) {
18662
18609
  if (location.git && !location.git.reftable) {
18663
18610
  let head = "";
18664
18611
  try {
18665
- head = fs4.readFileSync(path4.join(location.git.gitDir, "HEAD"), "utf8").trim();
18612
+ head = fs4.readFileSync(path3.join(location.git.gitDir, "HEAD"), "utf8").trim();
18666
18613
  } catch {}
18667
18614
  const ref = /^ref: refs\/heads\/(.+)$/u.exec(head);
18668
18615
  if (ref && ref[1] !== ".invalid")
@@ -18693,7 +18640,7 @@ function resolveTaskKey(root, location) {
18693
18640
  return { key: `detached-${shortHash(real(worktree))}`, kind: "detached", branch: null };
18694
18641
  }
18695
18642
  function checkoutRootOf(root, location) {
18696
- const resolved = path4.resolve(root);
18643
+ const resolved = path3.resolve(root);
18697
18644
  let canonical = resolved;
18698
18645
  try {
18699
18646
  canonical = fs4.realpathSync(resolved);
@@ -18724,13 +18671,13 @@ function branchRenames(location) {
18724
18671
  }
18725
18672
  for (const entry of entries)
18726
18673
  if (entry.isDirectory())
18727
- walk(path4.join(dir, entry.name));
18674
+ walk(path3.join(dir, entry.name));
18728
18675
  else
18729
- files.push(path4.join(dir, entry.name));
18676
+ files.push(path3.join(dir, entry.name));
18730
18677
  };
18731
- walk(path4.join(path4.dirname(location.dir), "logs", "refs", "heads"));
18678
+ walk(path3.join(path3.dirname(location.dir), "logs", "refs", "heads"));
18732
18679
  if (location.git)
18733
- files.push(path4.join(location.git.gitDir, "logs", "HEAD"));
18680
+ files.push(path3.join(location.git.gitDir, "logs", "HEAD"));
18734
18681
  const seen = new Set;
18735
18682
  const renames = [];
18736
18683
  for (const file of files) {
@@ -18765,11 +18712,63 @@ var checkoutSlug = (root) => {
18765
18712
  let canonical = real(root);
18766
18713
  if (process.platform === "win32")
18767
18714
  canonical = canonical.toLowerCase();
18768
- const base = path4.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
18715
+ const base = path3.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
18769
18716
  return `${base}-${shortHash(canonical)}`;
18770
18717
  };
18771
18718
 
18719
+ // packages/workit-core/src/host-session.ts
18720
+ var HOST_SESSION_VARS = [
18721
+ ["OPENCODE_SESSION_ID", () => "opencode"],
18722
+ ["PI_SESSION_ID", () => "pi"],
18723
+ [
18724
+ "CODEX_THREAD_ID",
18725
+ (env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
18726
+ ]
18727
+ ];
18728
+ var family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
18729
+ function hostSessionFromEnv(env) {
18730
+ const value = (key) => env[key]?.trim() || null;
18731
+ let inner = null;
18732
+ for (const [key, host] of HOST_SESSION_VARS) {
18733
+ const session = value(key);
18734
+ if (session) {
18735
+ inner = { host: host(env), session };
18736
+ break;
18737
+ }
18738
+ }
18739
+ const declared = value("WORKIT_HOST");
18740
+ if (env.WORKIT_SESSION_ID !== undefined) {
18741
+ const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
18742
+ if (!inherited)
18743
+ return { host: declared, session: value("WORKIT_SESSION_ID") };
18744
+ }
18745
+ return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
18746
+ }
18747
+ var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
18748
+
18749
+ // packages/workit-core/src/core/package-root.ts
18750
+ import { existsSync } from "node:fs";
18751
+ import path4 from "node:path";
18752
+ import { fileURLToPath } from "node:url";
18753
+ var packageRoot = () => {
18754
+ let dir = path4.dirname(fileURLToPath(import.meta.url));
18755
+ while (true) {
18756
+ const parent = path4.dirname(dir);
18757
+ if (existsSync(path4.join(dir, "package.json")) || parent === dir)
18758
+ return dir;
18759
+ dir = parent;
18760
+ }
18761
+ };
18762
+ var assetRoot = () => {
18763
+ const root = packageRoot();
18764
+ const assets = path4.join(root, "assets");
18765
+ return existsSync(assets) ? assets : root;
18766
+ };
18767
+
18772
18768
  // packages/workit-core/src/core/store-lock.ts
18769
+ import { spawnSync as spawnSync2 } from "node:child_process";
18770
+ import fs5 from "node:fs";
18771
+ import { hostname } from "node:os";
18773
18772
  var metadataLockSchema = object2({
18774
18773
  pid: number2().int().nonnegative().safe(),
18775
18774
  processStart: string2().nullable(),
@@ -19403,6 +19402,38 @@ var isNewerVersion = (candidate, current) => {
19403
19402
  return false;
19404
19403
  };
19405
19404
  var validId = (value) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(value);
19405
+ var readText = (file) => {
19406
+ try {
19407
+ return fs7.readFileSync(file, "utf8");
19408
+ } catch {
19409
+ return "";
19410
+ }
19411
+ };
19412
+ var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
19413
+ var branchStart = (location, branch, aliases) => {
19414
+ const first = readText(path6.join(path6.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
19415
+ `, 1)[0];
19416
+ const created = REFLOG_LINE.exec(first);
19417
+ const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
19418
+ if (!created || !start)
19419
+ return null;
19420
+ if (start !== "HEAD")
19421
+ return start;
19422
+ if (!location.git)
19423
+ return null;
19424
+ for (const line of readText(path6.join(location.git.gitDir, "logs", "HEAD")).split(`
19425
+ `)) {
19426
+ const entry = REFLOG_LINE.exec(line);
19427
+ const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
19428
+ const seconds = entry ? Number(entry[2]) - Number(created[2]) : -1;
19429
+ if (moved && entry[1] === created[1] && seconds >= 0 && seconds <= 1 && aliases.includes(moved[2]))
19430
+ return moved[1];
19431
+ }
19432
+ return null;
19433
+ };
19434
+ var refExists = (common, ref) => fs7.existsSync(path6.join(common, ref)) || readText(path6.join(common, "packed-refs")).includes(` ${ref}
19435
+ `);
19436
+ var origins = new Map;
19406
19437
  var sameDirectoryIdentity = (left, right) => {
19407
19438
  if (!path6.isAbsolute(left) || !path6.isAbsolute(right))
19408
19439
  return false;
@@ -19655,6 +19686,66 @@ class TaskStore {
19655
19686
  return bound;
19656
19687
  return success(null, null, { key: key.data, bound: bound.data });
19657
19688
  }
19689
+ taskForWorker(workerId) {
19690
+ if (typeof workerId !== "string" || !validId(workerId))
19691
+ return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
19692
+ const listed = this.listTaskIndex();
19693
+ if (!listed.ok)
19694
+ return listed;
19695
+ for (const entry of listed.data) {
19696
+ if (entry.status === "closed")
19697
+ continue;
19698
+ const loaded = this.load(entry.id);
19699
+ if (!loaded.ok)
19700
+ return loaded;
19701
+ if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
19702
+ return success(null, null, entry.id);
19703
+ }
19704
+ return success(null, null, null);
19705
+ }
19706
+ originTaskEntry() {
19707
+ const key = this.currentKey();
19708
+ const location = this.location();
19709
+ const branch = key.ok ? key.data.branch : null;
19710
+ if (!branch || !location.ok)
19711
+ return success(null, null, null);
19712
+ const common = path6.dirname(location.data.dir);
19713
+ const heads = path6.join(common, "logs", "refs", "heads");
19714
+ const headLog = location.data.git ? path6.join(location.data.git.gitDir, "logs", "HEAD") : "";
19715
+ const signatures = [
19716
+ path6.join(heads, branch),
19717
+ headLog,
19718
+ heads,
19719
+ path6.join(common, "packed-refs")
19720
+ ].map((file) => fileSignature(file) ?? "-");
19721
+ const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
19722
+ let resolved = origins.get(slot);
19723
+ if (resolved?.signature !== signatures.join("|")) {
19724
+ const renames = branchRenames(location.data);
19725
+ const aliases = [branch];
19726
+ for (const rename of renames.toReversed())
19727
+ if (rename.to === aliases.at(-1))
19728
+ aliases.push(rename.from);
19729
+ const start = branchStart(location.data, branch, aliases);
19730
+ const slash = start?.indexOf("/") ?? -1;
19731
+ const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path6.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
19732
+ const name = start && (remote ? start.slice(slash + 1) : start);
19733
+ resolved = {
19734
+ signature: signatures.join("|"),
19735
+ name: name && !aliases.includes(name) ? name : null,
19736
+ renames
19737
+ };
19738
+ origins.set(slot, resolved);
19739
+ }
19740
+ const entry = resolved.name ? this.openTasksForKey(resolved.name, resolved.renames) : null;
19741
+ if (entry && !entry.ok)
19742
+ return entry;
19743
+ return success(null, null, entry?.data[0] ? { origin: `branch ${resolved.name}`, entry: entry.data[0] } : null);
19744
+ }
19745
+ readStoreTask(taskId) {
19746
+ const loaded = this.load(taskId);
19747
+ return loaded.ok ? success(null, null, loaded.data?.record ?? null) : loaded;
19748
+ }
19658
19749
  create(input, provenance, expectedWorkspaceRevision) {
19659
19750
  const value = "intent" in input ? input : {
19660
19751
  intent: input,
@@ -20324,12 +20415,12 @@ class TaskStore {
20324
20415
  return 0;
20325
20416
  }
20326
20417
  }
20327
- openTasksForKey(key) {
20418
+ openTasksForKey(key, known) {
20328
20419
  const all = this.listStoreIndex();
20329
20420
  if (!all.ok)
20330
20421
  return all;
20331
- const location = this.location();
20332
- const renames = location.ok ? branchRenames(location.data) : [];
20422
+ const location = known ? null : this.location();
20423
+ const renames = known ?? (location?.ok ? branchRenames(location.data) : []);
20333
20424
  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));
20334
20425
  }
20335
20426
  openTaskForKey(key) {
@@ -23310,11 +23401,20 @@ function authorSessions(cwd, rows, branch, range = { base: null, head: null }, s
23310
23401
  sessions.add(session);
23311
23402
  return sessions;
23312
23403
  }
23404
+ var derivesFrom = (derived, bare) => !bare.includes(":") && derived.endsWith(`:${bare}`);
23405
+ var authoredBy = (authors, session) => {
23406
+ if (authors.has(session))
23407
+ return true;
23408
+ for (const author of authors)
23409
+ if (derivesFrom(author, session) || derivesFrom(session, author))
23410
+ return true;
23411
+ return false;
23412
+ };
23313
23413
  var independenceReasons = (row, authors) => {
23314
23414
  const reasons = [];
23315
23415
  if (!row.actor.session)
23316
23416
  reasons.push("no_session");
23317
- else if (authors.has(row.actor.session))
23417
+ else if (authoredBy(authors, row.actor.session))
23318
23418
  reasons.push("author_session");
23319
23419
  if (row.self === true && !reasons.includes("no_session"))
23320
23420
  reasons.push("self");
@@ -24415,38 +24515,45 @@ var compactReference = (ref) => {
24415
24515
  };
24416
24516
  return { kind: ref.kind };
24417
24517
  };
24418
- function compactTaskContext(view) {
24419
- const decisions = view.task.decisions.slice().toSorted((left, right) => {
24420
- const leftAt = compactTimestamp(left.recordedAt);
24421
- const rightAt = compactTimestamp(right.recordedAt);
24422
- if (leftAt !== rightAt)
24423
- return leftAt > rightAt ? -1 : 1;
24424
- return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
24425
- }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
24426
- id: entry.id,
24427
- purpose: entry.data.purpose,
24428
- status: entry.data.response,
24429
- digest: entry.data.digest,
24430
- choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
24431
- references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
24432
- }));
24433
- const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
24518
+ var newestDecisionFirst = (left, right) => {
24519
+ const leftAt = compactTimestamp(left.recordedAt);
24520
+ const rightAt = compactTimestamp(right.recordedAt);
24521
+ if (leftAt !== rightAt)
24522
+ return leftAt > rightAt ? -1 : 1;
24523
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
24524
+ };
24525
+ var compactDecisions = (sources) => sources.flatMap((source) => source ? source.decisions.toSorted(newestDecisionFirst).map((entry) => ({
24526
+ id: entry.id,
24527
+ purpose: entry.data.purpose,
24528
+ status: entry.data.response,
24529
+ digest: entry.data.digest,
24530
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${source.taskId} view=full; decision=${entry.id}`,
24531
+ references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference),
24532
+ origin: source.origin ?? undefined
24533
+ })) : []).slice(0, COMPACT_MAX_ITEMS);
24534
+ function compactTaskContext(view, inherited = null) {
24535
+ const decisions = compactDecisions([
24536
+ view && { origin: null, taskId: view.task.id, decisions: view.task.decisions },
24537
+ inherited
24538
+ ]);
24539
+ const methods = view?.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
24434
24540
  id: method.id,
24435
24541
  assurance: method.assurance,
24436
24542
  reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
24437
24543
  })) : [];
24544
+ const stale = view?.evidence.filter((entry) => entry.status === "stale").length;
24438
24545
  const gaps = Array.from(new Set([
24439
- ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
24440
- ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
24441
- ...view.task.progress.blockers.map((entry) => entry.reason)
24546
+ ...stale ? [`stale evidence: ${stale}; workit task inspect --task ${view.task.id} --view full`] : [],
24547
+ ...(view?.requirements ?? []).filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
24548
+ ...(view?.task.progress.blockers ?? []).map((entry) => entry.reason)
24442
24549
  ])).toSorted().slice(0, COMPACT_MAX_ITEMS).map((gap) => compactText(gap, COMPACT_TEXT_BYTES));
24443
24550
  const context = {
24444
- objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
24445
- status: view.task.status,
24551
+ objective: view ? compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "" : "no task on this branch yet",
24552
+ status: view?.task.status ?? null,
24446
24553
  decisions,
24447
24554
  methods,
24448
24555
  gaps,
24449
- nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
24556
+ nextAction: compactText(view?.task.progress.nextAction ?? null, COMPACT_TEXT_BYTES)
24450
24557
  };
24451
24558
  let encoded = JSON.stringify(context);
24452
24559
  while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
@@ -25051,6 +25158,13 @@ var TASK_SCOPED_ACTIONS = new Set([
25051
25158
  "worker.cancel",
25052
25159
  "state.export"
25053
25160
  ]);
25161
+ var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
25162
+ var workerCommand = (taskId, request) => {
25163
+ const { action, workerId, reason, report } = request;
25164
+ const rest = JSON.stringify({ reason, report });
25165
+ const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
25166
+ return `workit worker ${String(action)} ${String(workerId)} --task ${taskId}${payload}`;
25167
+ };
25054
25168
  var CREATING_ACTIONS = new Set([
25055
25169
  "task.revise",
25056
25170
  "task.progress",
@@ -25301,6 +25415,17 @@ class WorkitCore {
25301
25415
  const root = this.contextRootError();
25302
25416
  if (!root.ok)
25303
25417
  return root;
25418
+ const addressed = WORKER_ADDRESSED_ACTIONS.has(action);
25419
+ const workerId = addressed ? value.workerId : this.context.workerId ?? null;
25420
+ if (workerId !== null) {
25421
+ const owner = this.store.taskForWorker(workerId);
25422
+ if (!owner.ok)
25423
+ return owner;
25424
+ if (owner.data)
25425
+ return success(null, null, { ...request, taskId: owner.data });
25426
+ if (addressed)
25427
+ 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)}\``);
25428
+ }
25304
25429
  const create = CREATING_ACTIONS.has(action) && (this.context.workerId ?? null) === null;
25305
25430
  const found = this.store.implicitTask({
25306
25431
  provenance: provenance(this.context),
@@ -26007,7 +26132,9 @@ class WorkitCore {
26007
26132
  if (!resolved.ok)
26008
26133
  return resolved;
26009
26134
  const value = resolved.data;
26010
- return this.retryOmittedRevisions(value, () => this.workerOnce(value));
26135
+ const result = this.retryOmittedRevisions(value, () => this.workerOnce(value));
26136
+ const { action, taskId } = value ?? {};
26137
+ 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)}\`` };
26011
26138
  }
26012
26139
  workerOnce(request) {
26013
26140
  const root = this.contextRootError();
@@ -26212,10 +26339,18 @@ class WorkitCore {
26212
26339
  requirements
26213
26340
  });
26214
26341
  }
26215
- compactContext(taskId, freshness) {
26342
+ compactContext(taskId, freshness, origin = null) {
26216
26343
  const root = this.contextRootError();
26217
26344
  if (!root.ok)
26218
26345
  return root;
26346
+ const base = origin && this.store.readStoreTask(origin.taskId);
26347
+ const inherited = base?.ok && base.data ? {
26348
+ origin: origin.origin,
26349
+ taskId: base.data.id,
26350
+ decisions: base.data.decisions.filter((entry) => entry.data.revoked === null)
26351
+ } : null;
26352
+ if (taskId === null)
26353
+ return success(null, null, inherited?.decisions.length ? compactTaskContext(null, inherited) : "");
26219
26354
  const task = this.store.readTask(taskId);
26220
26355
  if (!task.ok)
26221
26356
  return task;
@@ -26225,7 +26360,7 @@ class WorkitCore {
26225
26360
  const view = this.view(task.data, false, freshness ?? signalFreshness(this.store.root));
26226
26361
  if (!view.ok)
26227
26362
  return view;
26228
- return success(view.revision, view.workspaceRevision, compactTaskContext(view.data));
26363
+ return success(view.revision, view.workspaceRevision, compactTaskContext(view.data, inherited));
26229
26364
  }
26230
26365
  view(task, capture = true, freshness = treeFreshness(this.store.root)) {
26231
26366
  const workspace = this.store.readWorkspace();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-mcp",
3
- "version": "8.9.0",
3
+ "version": "8.10.0",
4
4
  "private": false,
5
5
  "description": "Workit shared MCP transport for the eight task and policy operation families",
6
6
  "keywords": [
@@ -42,7 +42,7 @@
42
42
  "build": "bun scripts/build.ts"
43
43
  },
44
44
  "dependencies": {
45
- "@brainervirus/workit-core": "^8.9.0",
45
+ "@brainervirus/workit-core": "^8.10.0",
46
46
  "@modelcontextprotocol/sdk": "1.32.0",
47
47
  "zod": "4.6.5"
48
48
  },