@brainervirus/workit-opencode 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.
Files changed (2) hide show
  1. package/dist/plugin.js +174 -41
  2. package/package.json +2 -2
package/dist/plugin.js CHANGED
@@ -10564,6 +10564,38 @@ var isNewerVersion = (candidate, current) => {
10564
10564
  return false;
10565
10565
  };
10566
10566
  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);
10567
+ var readText = (file) => {
10568
+ try {
10569
+ return fs7.readFileSync(file, "utf8");
10570
+ } catch {
10571
+ return "";
10572
+ }
10573
+ };
10574
+ var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
10575
+ var branchStart = (location, branch, aliases) => {
10576
+ const first = readText(path6.join(path6.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
10577
+ `, 1)[0];
10578
+ const created = REFLOG_LINE.exec(first);
10579
+ const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
10580
+ if (!created || !start)
10581
+ return null;
10582
+ if (start !== "HEAD")
10583
+ return start;
10584
+ if (!location.git)
10585
+ return null;
10586
+ for (const line of readText(path6.join(location.git.gitDir, "logs", "HEAD")).split(`
10587
+ `)) {
10588
+ const entry = REFLOG_LINE.exec(line);
10589
+ const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
10590
+ const seconds = entry ? Number(entry[2]) - Number(created[2]) : -1;
10591
+ if (moved && entry[1] === created[1] && seconds >= 0 && seconds <= 1 && aliases.includes(moved[2]))
10592
+ return moved[1];
10593
+ }
10594
+ return null;
10595
+ };
10596
+ var refExists = (common, ref) => fs7.existsSync(path6.join(common, ref)) || readText(path6.join(common, "packed-refs")).includes(` ${ref}
10597
+ `);
10598
+ var origins = new Map;
10567
10599
  var sameDirectoryIdentity = (left, right) => {
10568
10600
  if (!path6.isAbsolute(left) || !path6.isAbsolute(right))
10569
10601
  return false;
@@ -10816,6 +10848,66 @@ class TaskStore {
10816
10848
  return bound;
10817
10849
  return success(null, null, { key: key.data, bound: bound.data });
10818
10850
  }
10851
+ taskForWorker(workerId) {
10852
+ if (typeof workerId !== "string" || !validId(workerId))
10853
+ return failure2("invalid_input", "needs a worker id: `workit worker cancel|report <workerId>`");
10854
+ const listed = this.listTaskIndex();
10855
+ if (!listed.ok)
10856
+ return listed;
10857
+ for (const entry of listed.data) {
10858
+ if (entry.status === "closed")
10859
+ continue;
10860
+ const loaded = this.load(entry.id);
10861
+ if (!loaded.ok)
10862
+ return loaded;
10863
+ if (loaded.data?.record.workers.some((worker) => worker.id === workerId))
10864
+ return success(null, null, entry.id);
10865
+ }
10866
+ return success(null, null, null);
10867
+ }
10868
+ originTaskEntry() {
10869
+ const key = this.currentKey();
10870
+ const location = this.location();
10871
+ const branch = key.ok ? key.data.branch : null;
10872
+ if (!branch || !location.ok)
10873
+ return success(null, null, null);
10874
+ const common = path6.dirname(location.data.dir);
10875
+ const heads = path6.join(common, "logs", "refs", "heads");
10876
+ const headLog = location.data.git ? path6.join(location.data.git.gitDir, "logs", "HEAD") : "";
10877
+ const signatures = [
10878
+ path6.join(heads, branch),
10879
+ headLog,
10880
+ heads,
10881
+ path6.join(common, "packed-refs")
10882
+ ].map((file) => fileSignature(file) ?? "-");
10883
+ const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
10884
+ let resolved = origins.get(slot);
10885
+ if (resolved?.signature !== signatures.join("|")) {
10886
+ const renames = branchRenames(location.data);
10887
+ const aliases = [branch];
10888
+ for (const rename of renames.toReversed())
10889
+ if (rename.to === aliases.at(-1))
10890
+ aliases.push(rename.from);
10891
+ const start = branchStart(location.data, branch, aliases);
10892
+ const slash = start?.indexOf("/") ?? -1;
10893
+ 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)}"]`));
10894
+ const name = start && (remote ? start.slice(slash + 1) : start);
10895
+ resolved = {
10896
+ signature: signatures.join("|"),
10897
+ name: name && !aliases.includes(name) ? name : null,
10898
+ renames
10899
+ };
10900
+ origins.set(slot, resolved);
10901
+ }
10902
+ const entry = resolved.name ? this.openTasksForKey(resolved.name, resolved.renames) : null;
10903
+ if (entry && !entry.ok)
10904
+ return entry;
10905
+ return success(null, null, entry?.data[0] ? { origin: `branch ${resolved.name}`, entry: entry.data[0] } : null);
10906
+ }
10907
+ readStoreTask(taskId) {
10908
+ const loaded = this.load(taskId);
10909
+ return loaded.ok ? success(null, null, loaded.data?.record ?? null) : loaded;
10910
+ }
10819
10911
  create(input, provenance, expectedWorkspaceRevision) {
10820
10912
  const value = "intent" in input ? input : {
10821
10913
  intent: input,
@@ -11485,12 +11577,12 @@ class TaskStore {
11485
11577
  return 0;
11486
11578
  }
11487
11579
  }
11488
- openTasksForKey(key) {
11580
+ openTasksForKey(key, known) {
11489
11581
  const all = this.listStoreIndex();
11490
11582
  if (!all.ok)
11491
11583
  return all;
11492
- const location = this.location();
11493
- const renames = location.ok ? branchRenames(location.data) : [];
11584
+ const location = known ? null : this.location();
11585
+ const renames = known ?? (location?.ok ? branchRenames(location.data) : []);
11494
11586
  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));
11495
11587
  }
11496
11588
  openTaskForKey(key) {
@@ -15687,38 +15779,45 @@ var compactReference = (ref) => {
15687
15779
  };
15688
15780
  return { kind: ref.kind };
15689
15781
  };
15690
- function compactTaskContext(view) {
15691
- const decisions = view.task.decisions.slice().toSorted((left, right) => {
15692
- const leftAt = compactTimestamp(left.recordedAt);
15693
- const rightAt = compactTimestamp(right.recordedAt);
15694
- if (leftAt !== rightAt)
15695
- return leftAt > rightAt ? -1 : 1;
15696
- return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15697
- }).slice(0, COMPACT_MAX_ITEMS).map((entry) => ({
15698
- id: entry.id,
15699
- purpose: entry.data.purpose,
15700
- status: entry.data.response,
15701
- digest: entry.data.digest,
15702
- choice: compactDecisionChoice(entry) || `task.inspect taskId=${view.task.id} view=full; decision=${entry.id}`,
15703
- references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference)
15704
- }));
15705
- const methods = view.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15782
+ var newestDecisionFirst = (left, right) => {
15783
+ const leftAt = compactTimestamp(left.recordedAt);
15784
+ const rightAt = compactTimestamp(right.recordedAt);
15785
+ if (leftAt !== rightAt)
15786
+ return leftAt > rightAt ? -1 : 1;
15787
+ return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;
15788
+ };
15789
+ var compactDecisions = (sources) => sources.flatMap((source) => source ? source.decisions.toSorted(newestDecisionFirst).map((entry) => ({
15790
+ id: entry.id,
15791
+ purpose: entry.data.purpose,
15792
+ status: entry.data.response,
15793
+ digest: entry.data.digest,
15794
+ choice: compactDecisionChoice(entry) || `task.inspect taskId=${source.taskId} view=full; decision=${entry.id}`,
15795
+ references: entry.data.binding.contentRefs.slice(0, 1).map(compactReference),
15796
+ origin: source.origin ?? undefined
15797
+ })) : []).slice(0, COMPACT_MAX_ITEMS);
15798
+ function compactTaskContext(view, inherited = null) {
15799
+ const decisions = compactDecisions([
15800
+ view && { origin: null, taskId: view.task.id, decisions: view.task.decisions },
15801
+ inherited
15802
+ ]);
15803
+ const methods = view?.task.policy ? selectMethods(view.task.policy, view.capabilities).map((method) => ({
15706
15804
  id: method.id,
15707
15805
  assurance: method.assurance,
15708
15806
  reason: compactText(method.reason, COMPACT_TEXT_BYTES) ?? ""
15709
15807
  })) : [];
15808
+ const stale = view?.evidence.filter((entry) => entry.status === "stale").length;
15710
15809
  const gaps = Array.from(new Set([
15711
- ...view.evidence.filter((entry) => entry.status === "stale").map((entry) => `stale evidence: ${entry.evidenceId}`),
15712
- ...view.requirements.filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15713
- ...view.task.progress.blockers.map((entry) => entry.reason)
15810
+ ...stale ? [`stale evidence: ${stale}; workit task inspect --task ${view.task.id} --view full`] : [],
15811
+ ...(view?.requirements ?? []).filter((entry) => entry.status !== "satisfied").map((entry) => entry.reason),
15812
+ ...(view?.task.progress.blockers ?? []).map((entry) => entry.reason)
15714
15813
  ])).toSorted().slice(0, COMPACT_MAX_ITEMS).map((gap) => compactText(gap, COMPACT_TEXT_BYTES));
15715
15814
  const context = {
15716
- objective: compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "",
15717
- status: view.task.status,
15815
+ objective: view ? compactText(view.task.intent.data.objective, COMPACT_TEXT_BYTES) ?? "" : "no task on this branch yet",
15816
+ status: view?.task.status ?? null,
15718
15817
  decisions,
15719
15818
  methods,
15720
15819
  gaps,
15721
- nextAction: compactText(view.task.progress.nextAction, COMPACT_TEXT_BYTES)
15820
+ nextAction: compactText(view?.task.progress.nextAction ?? null, COMPACT_TEXT_BYTES)
15722
15821
  };
15723
15822
  let encoded = JSON.stringify(context);
15724
15823
  while (compactBytes(encoded) > COMPACT_MAX_BYTES && (context.decisions.length || context.methods.length || context.gaps.length)) {
@@ -16461,6 +16560,13 @@ var TASK_SCOPED_ACTIONS = new Set([
16461
16560
  "worker.cancel",
16462
16561
  "state.export"
16463
16562
  ]);
16563
+ var WORKER_ADDRESSED_ACTIONS = new Set(["worker.cancel", "worker.report"]);
16564
+ var workerCommand = (taskId, request) => {
16565
+ const { action, workerId, reason, report } = request;
16566
+ const rest = JSON.stringify({ reason, report });
16567
+ const payload = rest === "{}" ? "" : ` --payload '${rest.replace(/'/gu, "'\\''")}'`;
16568
+ return `workit worker ${String(action)} ${String(workerId)} --task ${taskId}${payload}`;
16569
+ };
16464
16570
  var CREATING_ACTIONS = new Set([
16465
16571
  "task.revise",
16466
16572
  "task.progress",
@@ -16711,6 +16817,17 @@ class WorkitCore {
16711
16817
  const root = this.contextRootError();
16712
16818
  if (!root.ok)
16713
16819
  return root;
16820
+ const addressed = WORKER_ADDRESSED_ACTIONS.has(action);
16821
+ const workerId = addressed ? value.workerId : this.context.workerId ?? null;
16822
+ if (workerId !== null) {
16823
+ const owner = this.store.taskForWorker(workerId);
16824
+ if (!owner.ok)
16825
+ return owner;
16826
+ if (owner.data)
16827
+ return success(null, null, { ...request, taskId: owner.data });
16828
+ if (addressed)
16829
+ 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)}\``);
16830
+ }
16714
16831
  const create = CREATING_ACTIONS.has(action) && (this.context.workerId ?? null) === null;
16715
16832
  const found = this.store.implicitTask({
16716
16833
  provenance: provenance(this.context),
@@ -17417,7 +17534,9 @@ class WorkitCore {
17417
17534
  if (!resolved.ok)
17418
17535
  return resolved;
17419
17536
  const value = resolved.data;
17420
- return this.retryOmittedRevisions(value, () => this.workerOnce(value));
17537
+ const result = this.retryOmittedRevisions(value, () => this.workerOnce(value));
17538
+ const { action, taskId } = value ?? {};
17539
+ 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)}\`` };
17421
17540
  }
17422
17541
  workerOnce(request) {
17423
17542
  const root = this.contextRootError();
@@ -17622,10 +17741,18 @@ class WorkitCore {
17622
17741
  requirements
17623
17742
  });
17624
17743
  }
17625
- compactContext(taskId, freshness) {
17744
+ compactContext(taskId, freshness, origin = null) {
17626
17745
  const root = this.contextRootError();
17627
17746
  if (!root.ok)
17628
17747
  return root;
17748
+ const base = origin && this.store.readStoreTask(origin.taskId);
17749
+ const inherited = base?.ok && base.data ? {
17750
+ origin: origin.origin,
17751
+ taskId: base.data.id,
17752
+ decisions: base.data.decisions.filter((entry) => entry.data.revoked === null)
17753
+ } : null;
17754
+ if (taskId === null)
17755
+ return success(null, null, inherited?.decisions.length ? compactTaskContext(null, inherited) : "");
17629
17756
  const task = this.store.readTask(taskId);
17630
17757
  if (!task.ok)
17631
17758
  return task;
@@ -17635,7 +17762,7 @@ class WorkitCore {
17635
17762
  const view = this.view(task.data, false, freshness ?? signalFreshness(this.store.root));
17636
17763
  if (!view.ok)
17637
17764
  return view;
17638
- return success(view.revision, view.workspaceRevision, compactTaskContext(view.data));
17765
+ return success(view.revision, view.workspaceRevision, compactTaskContext(view.data, inherited));
17639
17766
  }
17640
17767
  view(task, capture = true, freshness = treeFreshness(this.store.root)) {
17641
17768
  const workspace = this.store.readWorkspace();
@@ -19074,8 +19201,9 @@ var currentTaskEntry = (entries, session, selection) => {
19074
19201
  const active = entries.filter((entry) => entry.status === "active");
19075
19202
  return active.length === 1 ? active[0] : null;
19076
19203
  };
19204
+ var otherConversation = (entry, session) => entry.sessions.some((item) => item.host !== "workit_cli" && !(item.host === session.host && item.handle === session.handle));
19077
19205
  var implicitTaskEntry = (store, entries, session) => {
19078
- 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)));
19206
+ const open = entries.filter((entry) => entry.key !== null && entry.status !== "closed" && !otherConversation(entry, session));
19079
19207
  if (open.length === 0)
19080
19208
  return null;
19081
19209
  const key = store.currentKey();
@@ -19116,18 +19244,23 @@ function sessionCompactContext(store, session, context, selection = "session-bou
19116
19244
  if (!listed.ok)
19117
19245
  return migrationPending(listed) ? MIGRATION_PENDING_NOTE : null;
19118
19246
  const entry = currentTaskEntry(listed.data, session, selection) ?? implicitTaskEntry(store, listed.data, session);
19119
- return entry ? entryCompactContext(store, entry, session, context) : null;
19247
+ return entryCompactContext(store, entry, session, context);
19120
19248
  }
19121
19249
  function entryCompactContext(store, entry, session, context) {
19250
+ const found = store.originTaskEntry();
19251
+ const origin = found.ok && found.data && found.data.entry.id !== entry?.id && !otherConversation(found.data.entry, session) ? found.data : null;
19252
+ if (!entry && !origin)
19253
+ return null;
19122
19254
  const workspace = store.readWorkspace();
19123
- if (!workspace.ok || !workspace.data)
19255
+ if (!workspace.ok || entry && !workspace.data)
19124
19256
  return null;
19125
19257
  const slot = `${store.root}\x00${session.host}\x00${session.handle}`;
19126
19258
  const key = canonicalJson({
19127
- task: entry.id,
19128
- revision: entry.revision,
19129
- file: entry.file,
19130
- workspace: workspace.data.revision,
19259
+ task: entry?.id ?? null,
19260
+ revision: entry?.revision ?? null,
19261
+ file: entry?.file ?? null,
19262
+ origin: origin && origin.entry.file,
19263
+ workspace: workspace.data?.revision ?? null,
19131
19264
  caller: context.caller,
19132
19265
  workerId: context.workerId ?? null,
19133
19266
  capabilities: context.capabilities
@@ -19135,15 +19268,15 @@ function entryCompactContext(store, entry, session, context) {
19135
19268
  const hit = cache.get(slot);
19136
19269
  if (hit && hit.key === key && hit.filesKey !== null && hit.filesKey === filesKey(hit.files) && (hit.signal === null || hit.signal === recentSignal(store.root)))
19137
19270
  return hit.value;
19138
- const task = store.readTask(entry.id);
19139
- if (!task.ok)
19271
+ const task = entry ? store.readTask(entry.id) : null;
19272
+ if (task && !task.ok)
19140
19273
  return null;
19141
19274
  const freshness = { mode: "signal", current: () => recentSignal(store.root) };
19142
- const observed = task.data.evidence.some(isObservedCheck);
19143
- const files = task.data.decisions.flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path20.resolve(store.root, ref.path)] : []));
19275
+ const observed = task?.data.evidence.some(isObservedCheck) ?? false;
19276
+ const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path20.resolve(store.root, ref.path)] : []));
19144
19277
  const observedFiles = filesKey(files);
19145
- const compact = new WorkitCore(store, context).compactContext(entry.id, freshness);
19146
- if (!compact.ok)
19278
+ const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
19279
+ if (!compact.ok || !compact.data)
19147
19280
  return null;
19148
19281
  cache.delete(slot);
19149
19282
  cache.set(slot, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-opencode",
3
- "version": "8.9.0",
3
+ "version": "8.9.1",
4
4
  "private": false,
5
5
  "description": "Workit OpenCode plugin — native tools, adaptive policy, and sixteen method skills",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  "typecheck": "tsc --noEmit"
40
40
  },
41
41
  "dependencies": {
42
- "@brainervirus/workit-core": "^8.9.0"
42
+ "@brainervirus/workit-core": "^8.9.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@opencode/plugin": "2.0.18"