@brainervirus/workit-codex 8.9.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workit",
3
- "version": "8.9.0",
3
+ "version": "8.9.1",
4
4
  "description": "Adaptive engineering workflow rails for Codex",
5
5
  "author": {
6
6
  "name": "BrainerVirus"
@@ -17028,6 +17028,38 @@ var isNewerVersion = (candidate, current) => {
17028
17028
  return false;
17029
17029
  };
17030
17030
  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);
17031
+ var readText = (file) => {
17032
+ try {
17033
+ return fs7.readFileSync(file, "utf8");
17034
+ } catch {
17035
+ return "";
17036
+ }
17037
+ };
17038
+ var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
17039
+ var branchStart = (location, branch, aliases) => {
17040
+ const first = readText(path6.join(path6.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
17041
+ `, 1)[0];
17042
+ const created = REFLOG_LINE.exec(first);
17043
+ const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
17044
+ if (!created || !start)
17045
+ return null;
17046
+ if (start !== "HEAD")
17047
+ return start;
17048
+ if (!location.git)
17049
+ return null;
17050
+ for (const line of readText(path6.join(location.git.gitDir, "logs", "HEAD")).split(`
17051
+ `)) {
17052
+ const entry = REFLOG_LINE.exec(line);
17053
+ const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
17054
+ const seconds = entry ? Number(entry[2]) - Number(created[2]) : -1;
17055
+ if (moved && entry[1] === created[1] && seconds >= 0 && seconds <= 1 && aliases.includes(moved[2]))
17056
+ return moved[1];
17057
+ }
17058
+ return null;
17059
+ };
17060
+ var refExists = (common, ref) => fs7.existsSync(path6.join(common, ref)) || readText(path6.join(common, "packed-refs")).includes(` ${ref}
17061
+ `);
17062
+ var origins = new Map;
17031
17063
  var sameDirectoryIdentity = (left, right) => {
17032
17064
  if (!path6.isAbsolute(left) || !path6.isAbsolute(right))
17033
17065
  return false;
@@ -17280,6 +17312,66 @@ class TaskStore {
17280
17312
  return bound;
17281
17313
  return success(null, null, { key: key.data, bound: bound.data });
17282
17314
  }
17315
+ taskForWorker(workerId) {
17316
+ if (typeof workerId !== "string" || !validId(workerId))
17317
+ return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
17318
+ const listed = this.listTaskIndex();
17319
+ if (!listed.ok)
17320
+ return listed;
17321
+ for (const entry of listed.data) {
17322
+ if (entry.status === "closed")
17323
+ continue;
17324
+ const loaded = this.load(entry.id);
17325
+ if (!loaded.ok)
17326
+ return loaded;
17327
+ if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
17328
+ return success(null, null, entry.id);
17329
+ }
17330
+ return success(null, null, null);
17331
+ }
17332
+ originTaskEntry() {
17333
+ const key = this.currentKey();
17334
+ const location = this.location();
17335
+ const branch = key.ok ? key.data.branch : null;
17336
+ if (!branch || !location.ok)
17337
+ return success(null, null, null);
17338
+ const common = path6.dirname(location.data.dir);
17339
+ const heads = path6.join(common, "logs", "refs", "heads");
17340
+ const headLog = location.data.git ? path6.join(location.data.git.gitDir, "logs", "HEAD") : "";
17341
+ const signatures = [
17342
+ path6.join(heads, branch),
17343
+ headLog,
17344
+ heads,
17345
+ path6.join(common, "packed-refs")
17346
+ ].map((file) => fileSignature(file) ?? "-");
17347
+ const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
17348
+ let resolved = origins.get(slot);
17349
+ if (resolved?.signature !== signatures.join("|")) {
17350
+ const renames = branchRenames(location.data);
17351
+ const aliases = [branch];
17352
+ for (const rename of renames.toReversed())
17353
+ if (rename.to === aliases.at(-1))
17354
+ aliases.push(rename.from);
17355
+ const start = branchStart(location.data, branch, aliases);
17356
+ const slash = start?.indexOf("/") ?? -1;
17357
+ 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)}"]`));
17358
+ const name = start && (remote ? start.slice(slash + 1) : start);
17359
+ resolved = {
17360
+ signature: signatures.join("|"),
17361
+ name: name && !aliases.includes(name) ? name : null,
17362
+ renames
17363
+ };
17364
+ origins.set(slot, resolved);
17365
+ }
17366
+ const entry = resolved.name ? this.openTasksForKey(resolved.name, resolved.renames) : null;
17367
+ if (entry && !entry.ok)
17368
+ return entry;
17369
+ return success(null, null, entry?.data[0] ? { origin: `branch ${resolved.name}`, entry: entry.data[0] } : null);
17370
+ }
17371
+ readStoreTask(taskId) {
17372
+ const loaded = this.load(taskId);
17373
+ return loaded.ok ? success(null, null, loaded.data?.record ?? null) : loaded;
17374
+ }
17283
17375
  create(input, provenance, expectedWorkspaceRevision) {
17284
17376
  const value = "intent" in input ? input : {
17285
17377
  intent: input,
@@ -17949,12 +18041,12 @@ class TaskStore {
17949
18041
  return 0;
17950
18042
  }
17951
18043
  }
17952
- openTasksForKey(key) {
18044
+ openTasksForKey(key, known) {
17953
18045
  const all = this.listStoreIndex();
17954
18046
  if (!all.ok)
17955
18047
  return all;
17956
- const location = this.location();
17957
- const renames = location.ok ? branchRenames(location.data) : [];
18048
+ const location = known ? null : this.location();
18049
+ const renames = known ?? (location?.ok ? branchRenames(location.data) : []);
17958
18050
  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));
17959
18051
  }
17960
18052
  openTaskForKey(key) {
@@ -22040,38 +22132,45 @@ var compactReference = (ref) => {
22040
22132
  };
22041
22133
  return { kind: ref.kind };
22042
22134
  };
22043
- function compactTaskContext(view) {
22044
- const decisions = view.task.decisions.slice().toSorted((left, right) => {
22045
- const leftAt = compactTimestamp(left.recordedAt);
22046
- const rightAt = compactTimestamp(right.recordedAt);
22047
- if (leftAt !== rightAt)
22048
- return leftAt > rightAt ? -1 : 1;
22049
- return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
22050
- }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
22051
- id: entry.id,
22052
- purpose: entry.data.purpose,
22053
- status: entry.data.response,
22054
- digest: entry.data.digest,
22055
- choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
22056
- references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
22057
- }));
22058
- const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
22135
+ var newestDecisionFirst = (left, right) => {
22136
+ const leftAt = compactTimestamp(left.recordedAt);
22137
+ const rightAt = compactTimestamp(right.recordedAt);
22138
+ if (leftAt !== rightAt)
22139
+ return leftAt > rightAt ? -1 : 1;
22140
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
22141
+ };
22142
+ var compactDecisions = (sources) => sources.flatMap((source) => source ? source.decisions.toSorted(newestDecisionFirst).map((entry) => ({
22143
+ id: entry.id,
22144
+ purpose: entry.data.purpose,
22145
+ status: entry.data.response,
22146
+ digest: entry.data.digest,
22147
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${source.taskId} view=full; decision=${entry.id}`,
22148
+ references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference),
22149
+ origin: source.origin ?? undefined
22150
+ })) : []).slice(0, COMPACT_MAX_ITEMS);
22151
+ function compactTaskContext(view, inherited = null) {
22152
+ const decisions = compactDecisions([
22153
+ view && { origin: null, taskId: view.task.id, decisions: view.task.decisions },
22154
+ inherited
22155
+ ]);
22156
+ const methods = view?.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
22059
22157
  id: method.id,
22060
22158
  assurance: method.assurance,
22061
22159
  reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
22062
22160
  })) : [];
22161
+ const stale = view?.evidence.filter((entry) => entry.status === "stale").length;
22063
22162
  const gaps = Array.from(new Set([
22064
- ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
22065
- ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
22066
- ...view.task.progress.blockers.map((entry) => entry.reason)
22163
+ ...stale ? [`stale evidence: ${stale}; workit task inspect --task ${view.task.id} --view full`] : [],
22164
+ ...(view?.requirements ?? []).filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
22165
+ ...(view?.task.progress.blockers ?? []).map((entry) => entry.reason)
22067
22166
  ])).toSorted().slice(0, COMPACT_MAX_ITEMS).map((gap) => compactText(gap, COMPACT_TEXT_BYTES));
22068
22167
  const context = {
22069
- objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
22070
- status: view.task.status,
22168
+ objective: view ? compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "" : "no task on this branch yet",
22169
+ status: view?.task.status ?? null,
22071
22170
  decisions,
22072
22171
  methods,
22073
22172
  gaps,
22074
- nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
22173
+ nextAction: compactText(view?.task.progress.nextAction ?? null, COMPACT_TEXT_BYTES)
22075
22174
  };
22076
22175
  let encoded = JSON.stringify(context);
22077
22176
  while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
@@ -22676,6 +22775,13 @@ var TASK_SCOPED_ACTIONS = new Set([
22676
22775
  "worker.cancel",
22677
22776
  "state.export"
22678
22777
  ]);
22778
+ var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
22779
+ var workerCommand = (taskId, request) => {
22780
+ const { action, workerId, reason, report } = request;
22781
+ const rest = JSON.stringify({ reason, report });
22782
+ const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
22783
+ return `workit worker ${String(action)} ${String(workerId)} --task ${taskId}${payload}`;
22784
+ };
22679
22785
  var CREATING_ACTIONS = new Set([
22680
22786
  "task.revise",
22681
22787
  "task.progress",
@@ -22926,6 +23032,17 @@ class WorkitCore {
22926
23032
  const root = this.contextRootError();
22927
23033
  if (!root.ok)
22928
23034
  return root;
23035
+ const addressed = WORKER_ADDRESSED_ACTIONS.has(action);
23036
+ const workerId = addressed ? value.workerId : this.context.workerId ?? null;
23037
+ if (workerId !== null) {
23038
+ const owner = this.store.taskForWorker(workerId);
23039
+ if (!owner.ok)
23040
+ return owner;
23041
+ if (owner.data)
23042
+ return success(null, null, { ...request, taskId: owner.data });
23043
+ if (addressed)
23044
+ 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)}\``);
23045
+ }
22929
23046
  const create = CREATING_ACTIONS.has(action) && (this.context.workerId ?? null) === null;
22930
23047
  const found = this.store.implicitTask({
22931
23048
  provenance: provenance(this.context),
@@ -23632,7 +23749,9 @@ class WorkitCore {
23632
23749
  if (!resolved.ok)
23633
23750
  return resolved;
23634
23751
  const value = resolved.data;
23635
- return this.retryOmittedRevisions(value, () => this.workerOnce(value));
23752
+ const result = this.retryOmittedRevisions(value, () => this.workerOnce(value));
23753
+ const { action, taskId } = value ?? {};
23754
+ 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)}\`` };
23636
23755
  }
23637
23756
  workerOnce(request) {
23638
23757
  const root = this.contextRootError();
@@ -23837,10 +23956,18 @@ class WorkitCore {
23837
23956
  requirements
23838
23957
  });
23839
23958
  }
23840
- compactContext(taskId, freshness) {
23959
+ compactContext(taskId, freshness, origin = null) {
23841
23960
  const root = this.contextRootError();
23842
23961
  if (!root.ok)
23843
23962
  return root;
23963
+ const base = origin && this.store.readStoreTask(origin.taskId);
23964
+ const inherited = base?.ok && base.data ? {
23965
+ origin: origin.origin,
23966
+ taskId: base.data.id,
23967
+ decisions: base.data.decisions.filter((entry) => entry.data.revoked === null)
23968
+ } : null;
23969
+ if (taskId === null)
23970
+ return success(null, null, inherited?.decisions.length ? compactTaskContext(null, inherited) : "");
23844
23971
  const task = this.store.readTask(taskId);
23845
23972
  if (!task.ok)
23846
23973
  return task;
@@ -23850,7 +23977,7 @@ class WorkitCore {
23850
23977
  const view = this.view(task.data, false, freshness ?? signalFreshness(this.store.root));
23851
23978
  if (!view.ok)
23852
23979
  return view;
23853
- return success(view.revision, view.workspaceRevision, compactTaskContext(view.data));
23980
+ return success(view.revision, view.workspaceRevision, compactTaskContext(view.data, inherited));
23854
23981
  }
23855
23982
  view(task, capture = true, freshness = treeFreshness(this.store.root)) {
23856
23983
  const workspace = this.store.readWorkspace();
@@ -10464,6 +10464,38 @@ var isNewerVersion = (candidate, current) => {
10464
10464
  return false;
10465
10465
  };
10466
10466
  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);
10467
+ var readText = (file) => {
10468
+ try {
10469
+ return fs9.readFileSync(file, "utf8");
10470
+ } catch {
10471
+ return "";
10472
+ }
10473
+ };
10474
+ var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
10475
+ var branchStart = (location, branch, aliases) => {
10476
+ const first = readText(path8.join(path8.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
10477
+ `, 1)[0];
10478
+ const created = REFLOG_LINE.exec(first);
10479
+ const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
10480
+ if (!created || !start)
10481
+ return null;
10482
+ if (start !== "HEAD")
10483
+ return start;
10484
+ if (!location.git)
10485
+ return null;
10486
+ for (const line of readText(path8.join(location.git.gitDir, "logs", "HEAD")).split(`
10487
+ `)) {
10488
+ const entry = REFLOG_LINE.exec(line);
10489
+ const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
10490
+ const seconds = entry ? Number(entry[2]) - Number(created[2]) : -1;
10491
+ if (moved && entry[1] === created[1] && seconds >= 0 && seconds <= 1 && aliases.includes(moved[2]))
10492
+ return moved[1];
10493
+ }
10494
+ return null;
10495
+ };
10496
+ var refExists = (common, ref) => fs9.existsSync(path8.join(common, ref)) || readText(path8.join(common, "packed-refs")).includes(` ${ref}
10497
+ `);
10498
+ var origins = new Map;
10467
10499
  var sameDirectoryIdentity = (left, right) => {
10468
10500
  if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
10469
10501
  return false;
@@ -10716,6 +10748,66 @@ class TaskStore {
10716
10748
  return bound;
10717
10749
  return success(null, null, { key: key.data, bound: bound.data });
10718
10750
  }
10751
+ taskForWorker(workerId) {
10752
+ if (typeof workerId !== "string" || !validId(workerId))
10753
+ return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
10754
+ const listed = this.listTaskIndex();
10755
+ if (!listed.ok)
10756
+ return listed;
10757
+ for (const entry of listed.data) {
10758
+ if (entry.status === "closed")
10759
+ continue;
10760
+ const loaded = this.load(entry.id);
10761
+ if (!loaded.ok)
10762
+ return loaded;
10763
+ if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
10764
+ return success(null, null, entry.id);
10765
+ }
10766
+ return success(null, null, null);
10767
+ }
10768
+ originTaskEntry() {
10769
+ const key = this.currentKey();
10770
+ const location = this.location();
10771
+ const branch = key.ok ? key.data.branch : null;
10772
+ if (!branch || !location.ok)
10773
+ return success(null, null, null);
10774
+ const common = path8.dirname(location.data.dir);
10775
+ const heads = path8.join(common, "logs", "refs", "heads");
10776
+ const headLog = location.data.git ? path8.join(location.data.git.gitDir, "logs", "HEAD") : "";
10777
+ const signatures = [
10778
+ path8.join(heads, branch),
10779
+ headLog,
10780
+ heads,
10781
+ path8.join(common, "packed-refs")
10782
+ ].map((file) => fileSignature(file) ?? "-");
10783
+ const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
10784
+ let resolved = origins.get(slot);
10785
+ if (resolved?.signature !== signatures.join("|")) {
10786
+ const renames = branchRenames(location.data);
10787
+ const aliases = [branch];
10788
+ for (const rename of renames.toReversed())
10789
+ if (rename.to === aliases.at(-1))
10790
+ aliases.push(rename.from);
10791
+ const start = branchStart(location.data, branch, aliases);
10792
+ const slash = start?.indexOf("/") ?? -1;
10793
+ 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)}"]`));
10794
+ const name = start && (remote ? start.slice(slash + 1) : start);
10795
+ resolved = {
10796
+ signature: signatures.join("|"),
10797
+ name: name && !aliases.includes(name) ? name : null,
10798
+ renames
10799
+ };
10800
+ origins.set(slot, resolved);
10801
+ }
10802
+ const entry = resolved.name ? this.openTasksForKey(resolved.name, resolved.renames) : null;
10803
+ if (entry && !entry.ok)
10804
+ return entry;
10805
+ return success(null, null, entry?.data[0] ? { origin: `branch ${resolved.name}`, entry: entry.data[0] } : null);
10806
+ }
10807
+ readStoreTask(taskId) {
10808
+ const loaded = this.load(taskId);
10809
+ return loaded.ok ? success(null, null, loaded.data?.record ?? null) : loaded;
10810
+ }
10719
10811
  create(input, provenance, expectedWorkspaceRevision) {
10720
10812
  const value = "intent" in input ? input : {
10721
10813
  intent: input,
@@ -11385,12 +11477,12 @@ class TaskStore {
11385
11477
  return 0;
11386
11478
  }
11387
11479
  }
11388
- openTasksForKey(key) {
11480
+ openTasksForKey(key, known) {
11389
11481
  const all = this.listStoreIndex();
11390
11482
  if (!all.ok)
11391
11483
  return all;
11392
- const location = this.location();
11393
- const renames = location.ok ? branchRenames(location.data) : [];
11484
+ const location = known ? null : this.location();
11485
+ const renames = known ?? (location?.ok ? branchRenames(location.data) : []);
11394
11486
  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));
11395
11487
  }
11396
11488
  openTaskForKey(key) {
@@ -15599,38 +15691,45 @@ var compactReference = (ref) => {
15599
15691
  };
15600
15692
  return { kind: ref.kind };
15601
15693
  };
15602
- function compactTaskContext(view) {
15603
- const decisions = view.task.decisions.slice().toSorted((left, right) => {
15604
- const leftAt = compactTimestamp(left.recordedAt);
15605
- const rightAt = compactTimestamp(right.recordedAt);
15606
- if (leftAt !== rightAt)
15607
- return leftAt > rightAt ? -1 : 1;
15608
- return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15609
- }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
15610
- id: entry.id,
15611
- purpose: entry.data.purpose,
15612
- status: entry.data.response,
15613
- digest: entry.data.digest,
15614
- choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
15615
- references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
15616
- }));
15617
- const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15694
+ var newestDecisionFirst = (left, right) => {
15695
+ const leftAt = compactTimestamp(left.recordedAt);
15696
+ const rightAt = compactTimestamp(right.recordedAt);
15697
+ if (leftAt !== rightAt)
15698
+ return leftAt > rightAt ? -1 : 1;
15699
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15700
+ };
15701
+ var compactDecisions = (sources) => sources.flatMap((source) => source ? source.decisions.toSorted(newestDecisionFirst).map((entry) => ({
15702
+ id: entry.id,
15703
+ purpose: entry.data.purpose,
15704
+ status: entry.data.response,
15705
+ digest: entry.data.digest,
15706
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${source.taskId} view=full; decision=${entry.id}`,
15707
+ references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference),
15708
+ origin: source.origin ?? undefined
15709
+ })) : []).slice(0, COMPACT_MAX_ITEMS);
15710
+ function compactTaskContext(view, inherited = null) {
15711
+ const decisions = compactDecisions([
15712
+ view && { origin: null, taskId: view.task.id, decisions: view.task.decisions },
15713
+ inherited
15714
+ ]);
15715
+ const methods = view?.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15618
15716
  id: method.id,
15619
15717
  assurance: method.assurance,
15620
15718
  reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
15621
15719
  })) : [];
15720
+ const stale = view?.evidence.filter((entry) => entry.status === "stale").length;
15622
15721
  const gaps = Array.from(new Set([
15623
- ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
15624
- ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15625
- ...view.task.progress.blockers.map((entry) => entry.reason)
15722
+ ...stale ? [`stale evidence: ${stale}; workit task inspect --task ${view.task.id} --view full`] : [],
15723
+ ...(view?.requirements ?? []).filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15724
+ ...(view?.task.progress.blockers ?? []).map((entry) => entry.reason)
15626
15725
  ])).toSorted().slice(0, COMPACT_MAX_ITEMS).map((gap) => compactText(gap, COMPACT_TEXT_BYTES));
15627
15726
  const context = {
15628
- objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
15629
- status: view.task.status,
15727
+ objective: view ? compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "" : "no task on this branch yet",
15728
+ status: view?.task.status ?? null,
15630
15729
  decisions,
15631
15730
  methods,
15632
15731
  gaps,
15633
- nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
15732
+ nextAction: compactText(view?.task.progress.nextAction ?? null, COMPACT_TEXT_BYTES)
15634
15733
  };
15635
15734
  let encoded = JSON.stringify(context);
15636
15735
  while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
@@ -15819,6 +15918,13 @@ var TASK_SCOPED_ACTIONS = new Set([
15819
15918
  "worker.cancel",
15820
15919
  "state.export"
15821
15920
  ]);
15921
+ var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
15922
+ var workerCommand = (taskId, request) => {
15923
+ const { action, workerId, reason, report } = request;
15924
+ const rest = JSON.stringify({ reason, report });
15925
+ const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
15926
+ return `workit worker ${String(action)} ${String(workerId)} --task ${taskId}${payload}`;
15927
+ };
15822
15928
  var CREATING_ACTIONS = new Set([
15823
15929
  "task.revise",
15824
15930
  "task.progress",
@@ -16069,6 +16175,17 @@ class WorkitCore {
16069
16175
  const root = this.contextRootError();
16070
16176
  if (!root.ok)
16071
16177
  return root;
16178
+ const addressed = WORKER_ADDRESSED_ACTIONS.has(action);
16179
+ const workerId = addressed ? value.workerId : this.context.workerId ?? null;
16180
+ if (workerId !== null) {
16181
+ const owner = this.store.taskForWorker(workerId);
16182
+ if (!owner.ok)
16183
+ return owner;
16184
+ if (owner.data)
16185
+ return success(null, null, { ...request, taskId: owner.data });
16186
+ if (addressed)
16187
+ 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)}\``);
16188
+ }
16072
16189
  const create = CREATING_ACTIONS.has(action) && (this.context.workerId ?? null) === null;
16073
16190
  const found = this.store.implicitTask({
16074
16191
  provenance: provenance(this.context),
@@ -16775,7 +16892,9 @@ class WorkitCore {
16775
16892
  if (!resolved.ok)
16776
16893
  return resolved;
16777
16894
  const value = resolved.data;
16778
- return this.retryOmittedRevisions(value, () => this.workerOnce(value));
16895
+ const result = this.retryOmittedRevisions(value, () => this.workerOnce(value));
16896
+ const { action, taskId } = value ?? {};
16897
+ 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)}\`` };
16779
16898
  }
16780
16899
  workerOnce(request) {
16781
16900
  const root = this.contextRootError();
@@ -16980,10 +17099,18 @@ class WorkitCore {
16980
17099
  requirements
16981
17100
  });
16982
17101
  }
16983
- compactContext(taskId, freshness) {
17102
+ compactContext(taskId, freshness, origin = null) {
16984
17103
  const root = this.contextRootError();
16985
17104
  if (!root.ok)
16986
17105
  return root;
17106
+ const base = origin && this.store.readStoreTask(origin.taskId);
17107
+ const inherited = base?.ok && base.data ? {
17108
+ origin: origin.origin,
17109
+ taskId: base.data.id,
17110
+ decisions: base.data.decisions.filter((entry) => entry.data.revoked === null)
17111
+ } : null;
17112
+ if (taskId === null)
17113
+ return success(null, null, inherited?.decisions.length ? compactTaskContext(null, inherited) : "");
16987
17114
  const task = this.store.readTask(taskId);
16988
17115
  if (!task.ok)
16989
17116
  return task;
@@ -16993,7 +17120,7 @@ class WorkitCore {
16993
17120
  const view = this.view(task.data, false, freshness ?? signalFreshness(this.store.root));
16994
17121
  if (!view.ok)
16995
17122
  return view;
16996
- return success(view.revision, view.workspaceRevision, compactTaskContext(view.data));
17123
+ return success(view.revision, view.workspaceRevision, compactTaskContext(view.data, inherited));
16997
17124
  }
16998
17125
  view(task, capture = true, freshness = treeFreshness(this.store.root)) {
16999
17126
  const workspace = this.store.readWorkspace();
@@ -17288,8 +17415,9 @@ var currentTaskEntry = (entries, session, selection) => {
17288
17415
  const active = entries.filter((entry) => entry.status === "active");
17289
17416
  return active.length === 1 ? active[0] : null;
17290
17417
  };
17418
+ var otherConversation = (entry, session) => entry.sessions.some((item) => item.host !== "workit_cli" && !(item.host === session.host && item.handle === session.handle));
17291
17419
  var implicitTaskEntry = (store, entries, session) => {
17292
- const open = entries.filter((entry) => entry.key !== null && entry.status !== "closed" && !entry.sessions.some((item) => item.host !== "workit_cli" && !(item.host === session.host && item.handle === session.handle)));
17420
+ const open = entries.filter((entry) => entry.key !== null && entry.status !== "closed" && !otherConversation(entry, session));
17293
17421
  if (open.length === 0)
17294
17422
  return null;
17295
17423
  const key = store.currentKey();
@@ -17330,18 +17458,23 @@ function sessionCompactContext(store, session, context, selection = "session-bou
17330
17458
  if (!listed.ok)
17331
17459
  return migrationPending(listed) ? MIGRATION_PENDING_NOTE : null;
17332
17460
  const entry = currentTaskEntry(listed.data, session, selection) ?? implicitTaskEntry(store, listed.data, session);
17333
- return entry ? entryCompactContext(store, entry, session, context) : null;
17461
+ return entryCompactContext(store, entry, session, context);
17334
17462
  }
17335
17463
  function entryCompactContext(store, entry, session, context) {
17464
+ const found = store.originTaskEntry();
17465
+ const origin = found.ok && found.data && found.data.entry.id !== entry?.id && !otherConversation(found.data.entry, session) ? found.data : null;
17466
+ if (!entry && !origin)
17467
+ return null;
17336
17468
  const workspace = store.readWorkspace();
17337
- if (!workspace.ok || !workspace.data)
17469
+ if (!workspace.ok || entry && !workspace.data)
17338
17470
  return null;
17339
17471
  const slot = `${store.root}\x00${session.host}\x00${session.handle}`;
17340
17472
  const key = canonicalJson({
17341
- task: entry.id,
17342
- revision: entry.revision,
17343
- file: entry.file,
17344
- workspace: workspace.data.revision,
17473
+ task: entry?.id ?? null,
17474
+ revision: entry?.revision ?? null,
17475
+ file: entry?.file ?? null,
17476
+ origin: origin && origin.entry.file,
17477
+ workspace: workspace.data?.revision ?? null,
17345
17478
  caller: context.caller,
17346
17479
  workerId: context.workerId ?? null,
17347
17480
  capabilities: context.capabilities
@@ -17349,15 +17482,15 @@ function entryCompactContext(store, entry, session, context) {
17349
17482
  const hit = cache.get(slot);
17350
17483
  if (hit && hit.key === key && hit.filesKey !== null && hit.filesKey === filesKey(hit.files) && (hit.signal === null || hit.signal === recentSignal(store.root)))
17351
17484
  return hit.value;
17352
- const task = store.readTask(entry.id);
17353
- if (!task.ok)
17485
+ const task = entry ? store.readTask(entry.id) : null;
17486
+ if (task && !task.ok)
17354
17487
  return null;
17355
17488
  const freshness = { mode: "signal", current: () => recentSignal(store.root) };
17356
- const observed = task.data.evidence.some(isObservedCheck);
17357
- const files = task.data.decisions.flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path16.resolve(store.root, ref.path)] : []));
17489
+ const observed = task?.data.evidence.some(isObservedCheck) ?? false;
17490
+ const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path16.resolve(store.root, ref.path)] : []));
17358
17491
  const observedFiles = filesKey(files);
17359
- const compact = new WorkitCore(store, context).compactContext(entry.id, freshness);
17360
- if (!compact.ok)
17492
+ const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
17493
+ if (!compact.ok || !compact.data)
17361
17494
  return null;
17362
17495
  cache.delete(slot);
17363
17496
  cache.set(slot, {
@@ -17396,7 +17529,7 @@ ${options.addendum}` : ""}
17396
17529
  if (!listed.ok)
17397
17530
  throw new Error(listed.error);
17398
17531
  const entry = currentTaskEntry(listed.data, session, descriptor.context.task) ?? implicitTaskEntry(store, listed.data, session);
17399
- const text = entry ? entryCompactContext(store, entry, session, hookOperationContext(input, descriptor)) : null;
17532
+ const text = entryCompactContext(store, entry, session, hookOperationContext(input, descriptor));
17400
17533
  if (text)
17401
17534
  compact = `
17402
17535
  <workit-task-context>${text}</workit-task-context>`;
@@ -37,6 +37,6 @@ if (quiet)
37
37
  process.stdout.write(`${JSON.stringify({ hookSpecificOutput: { hookEventName: quiet } })}
38
38
  `);
39
39
  else {
40
- const { runCodexHook } = await import("./workit-hook-aw8j630z.js");
40
+ const { runCodexHook } = await import("./workit-hook-vjkepg0b.js");
41
41
  await runCodexHook([payload]);
42
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-codex",
3
- "version": "8.9.0",
3
+ "version": "8.9.1",
4
4
  "private": false,
5
5
  "description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, method skills, and verifier/reviewer/implementer agents",
6
6
  "keywords": [
@@ -39,8 +39,8 @@
39
39
  "build": "bun scripts/build.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@brainervirus/workit-core": "^8.9.0",
43
- "@brainervirus/workit-mcp": "^8.9.0"
42
+ "@brainervirus/workit-core": "^8.9.1",
43
+ "@brainervirus/workit-mcp": "^8.9.1"
44
44
  },
45
45
  "engines": {
46
46
  "node": ">=24"