@coool/opencode-adaptive 1.4.0 → 1.5.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 (48) hide show
  1. package/README.md +2 -1
  2. package/dist/adapters/opencode/index.d.ts +2 -0
  3. package/dist/adapters/opencode/index.js +2 -0
  4. package/dist/adapters/opencode/index.js.map +1 -1
  5. package/dist/adapters/opencode/process-ledger.d.ts +56 -0
  6. package/dist/adapters/opencode/process-ledger.js +143 -0
  7. package/dist/adapters/opencode/process-ledger.js.map +1 -0
  8. package/dist/adapters/opencode/session-ops.d.ts +2 -0
  9. package/dist/adapters/opencode/session-ops.js +15 -9
  10. package/dist/adapters/opencode/session-ops.js.map +1 -1
  11. package/dist/adapters/opencode/timer.d.ts +5 -0
  12. package/dist/adapters/opencode/timer.js +12 -0
  13. package/dist/adapters/opencode/timer.js.map +1 -0
  14. package/dist/execution/parking/index.d.ts +2 -1
  15. package/dist/execution/parking/index.js +2 -1
  16. package/dist/execution/parking/index.js.map +1 -1
  17. package/dist/execution/parking/wake.d.ts +52 -0
  18. package/dist/execution/parking/wake.js +95 -0
  19. package/dist/execution/parking/wake.js.map +1 -0
  20. package/dist/gui-experimental.cjs +3 -3
  21. package/dist/gui.d.ts +2 -2
  22. package/dist/gui.js +37 -3
  23. package/dist/gui.js.map +1 -1
  24. package/dist/health/classifier/classify.js +9 -0
  25. package/dist/health/classifier/classify.js.map +1 -1
  26. package/dist/index.js +33 -20
  27. package/dist/index.js.map +1 -1
  28. package/dist/rpc/status.d.ts +9 -0
  29. package/dist/rpc/status.js +1 -0
  30. package/dist/rpc/status.js.map +1 -1
  31. package/dist/state/parked-work/store.d.ts +5 -0
  32. package/dist/state/parked-work/store.js +24 -0
  33. package/dist/state/parked-work/store.js.map +1 -1
  34. package/dist/supervisor/supervisor.d.ts +2 -0
  35. package/dist/supervisor/supervisor.js +475 -106
  36. package/dist/supervisor/supervisor.js.map +1 -1
  37. package/dist/supervisor/types.d.ts +5 -0
  38. package/dist/supervisor/types.js.map +1 -1
  39. package/dist/tui.d.ts +13 -0
  40. package/dist/tui.js +62 -16
  41. package/dist/tui.js.map +1 -1
  42. package/dist/ui/flow/waiting.d.ts +11 -0
  43. package/dist/ui/flow/waiting.js +40 -0
  44. package/dist/ui/flow/waiting.js.map +1 -0
  45. package/dist/ui/gui/api.d.ts +2 -0
  46. package/dist/ui/gui/api.js +6 -2
  47. package/dist/ui/gui/api.js.map +1 -1
  48. package/package.json +1 -1
@@ -5,6 +5,11 @@ export declare class ParkedWorkStore {
5
5
  constructor(storage: ParkedStorage);
6
6
  /** Rebuild from storage (restart behavior). A read failure yields an empty store. */
7
7
  load(): Promise<void>;
8
+ /**
9
+ * Re-read storage without the load-time failure policy: a read failure
10
+ * keeps the current records instead of forgetting parked work.
11
+ */
12
+ refresh(): Promise<void>;
8
13
  /** All parked records, insertion order. */
9
14
  list(): readonly ParkedRecord[];
10
15
  count(): number;
@@ -6,6 +6,11 @@
6
6
  * failures propagate to the caller (fail-open is the wiring layer's call), and
7
7
  * the in-memory list is only advanced after a successful write — memory and
8
8
  * disk never diverge.
9
+ *
10
+ * Storage is shared: the host may load the plugin twice in one process, and
11
+ * only one instance's store changes on each event. Every mutation therefore
12
+ * re-reads storage first, so a stale instance can neither resurrect a record
13
+ * another instance resumed nor resume it a second time.
9
14
  */
10
15
  import { parseParkedPayload } from "./parse.js";
11
16
  import { MAX_PARKED, MAX_PARKED_TEXT, PARKED_VERSION } from "./types.js";
@@ -34,6 +39,23 @@ export class ParkedWorkStore {
34
39
  }
35
40
  this.#records = parseParkedPayload(raw);
36
41
  }
42
+ /**
43
+ * Re-read storage without the load-time failure policy: a read failure
44
+ * keeps the current records instead of forgetting parked work.
45
+ */
46
+ refresh() {
47
+ return this.#serialize(() => this.#refresh());
48
+ }
49
+ async #refresh() {
50
+ let raw;
51
+ try {
52
+ raw = await this.storage.read();
53
+ }
54
+ catch {
55
+ return;
56
+ }
57
+ this.#records = parseParkedPayload(raw);
58
+ }
37
59
  /** All parked records, insertion order. */
38
60
  list() {
39
61
  return this.#records;
@@ -45,6 +67,7 @@ export class ParkedWorkStore {
45
67
  return this.#serialize(() => this.#park(record));
46
68
  }
47
69
  async #park(record) {
70
+ await this.#refresh();
48
71
  const bounded = {
49
72
  ...record,
50
73
  ...(record.detail !== undefined ? { detail: boundDetail(record.detail) } : {}),
@@ -64,6 +87,7 @@ export class ParkedWorkStore {
64
87
  return this.#serialize(() => this.#resume(id));
65
88
  }
66
89
  async #resume(id) {
90
+ await this.#refresh();
67
91
  const record = this.#records.find((entry) => entry.id === id);
68
92
  if (record === undefined)
69
93
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/state/parked-work/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Parked-work store (ADP-024). Records are keyed by unit id — parking the\n * same unit again replaces the record (latest park wins). The cap\n * `MAX_PARKED` evicts the oldest `parkedAt` first: parked work is waiting\n * work, and unbounded growth would mean recovery never happens. Write\n * failures propagate to the caller (fail-open is the wiring layer's call), and\n * the in-memory list is only advanced after a successful write — memory and\n * disk never diverge.\n */\nimport { parseParkedPayload } from \"./parse.js\"\nimport { MAX_PARKED, MAX_PARKED_TEXT, PARKED_VERSION } from \"./types.js\"\nimport type { ParkedPayload, ParkedRecord, ParkedStorage } from \"./types.js\"\n\nfunction boundDetail(raw: string): string {\n return raw.length > MAX_PARKED_TEXT ? raw.slice(0, MAX_PARKED_TEXT) : raw\n}\n\nexport class ParkedWorkStore {\n #records: ParkedRecord[] = []\n #queue: Promise<unknown> = Promise.resolve()\n\n constructor(private readonly storage: ParkedStorage) {}\n\n /** Rebuild from storage (restart behavior). A read failure yields an empty store. */\n load(): Promise<void> {\n return this.#serialize(() => this.#load())\n }\n\n async #load(): Promise<void> {\n let raw: unknown\n try {\n raw = await this.storage.read()\n } catch {\n this.#records = []\n return\n }\n this.#records = parseParkedPayload(raw)\n }\n\n /** All parked records, insertion order. */\n list(): readonly ParkedRecord[] {\n return this.#records\n }\n\n count(): number {\n return this.#records.length\n }\n\n park(record: ParkedRecord): Promise<void> {\n return this.#serialize(() => this.#park(record))\n }\n\n async #park(record: ParkedRecord): Promise<void> {\n const bounded: ParkedRecord = {\n ...record,\n ...(record.detail !== undefined ? { detail: boundDetail(record.detail) } : {}),\n }\n const withoutId = this.#records.filter((entry) => entry.id !== bounded.id)\n const next = this.#evictOldest([...withoutId, bounded])\n // Persist BEFORE committing memory: a failed resume must not silently\n // drop the parked unit (memory and disk stay consistent on failure).\n await this.#persist(next)\n this.#records = next\n }\n\n /**\n * Remove a parked record and return it so the execution layer knows what\n * to continue. `undefined` (no record, no write) when the id is unknown.\n */\n resume(id: string): Promise<ParkedRecord | undefined> {\n return this.#serialize(() => this.#resume(id))\n }\n\n async #resume(id: string): Promise<ParkedRecord | undefined> {\n const record = this.#records.find((entry) => entry.id === id)\n if (record === undefined) return undefined\n const next = this.#records.filter((entry) => entry.id !== id)\n await this.#persist(next)\n this.#records = next\n return record\n }\n\n #evictOldest(records: ParkedRecord[]): ParkedRecord[] {\n if (records.length <= MAX_PARKED) return records\n const byOldest = [...records].sort((a, b) => a.parkedAt - b.parkedAt)\n const dropped = new Set(byOldest.slice(0, records.length - MAX_PARKED).map((r) => r.id))\n return records.filter((record) => !dropped.has(record.id))\n }\n\n // Reads share the queue so reloads cannot overwrite newer commits. Recover\n // the queue after rejection while preserving the failing caller's promise.\n #serialize<T>(operation: () => Promise<T>): Promise<T> {\n const run = this.#queue.then(operation)\n this.#queue = run.catch(() => undefined)\n return run\n }\n\n /** Writes the given next state; the caller commits memory only on success. */\n async #persist(parked: readonly ParkedRecord[]): Promise<void> {\n const payload: ParkedPayload = {\n version: PARKED_VERSION,\n parked,\n }\n await this.storage.write(payload)\n }\n}\n"]}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/state/parked-work/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Parked-work store (ADP-024). Records are keyed by unit id — parking the\n * same unit again replaces the record (latest park wins). The cap\n * `MAX_PARKED` evicts the oldest `parkedAt` first: parked work is waiting\n * work, and unbounded growth would mean recovery never happens. Write\n * failures propagate to the caller (fail-open is the wiring layer's call), and\n * the in-memory list is only advanced after a successful write — memory and\n * disk never diverge.\n *\n * Storage is shared: the host may load the plugin twice in one process, and\n * only one instance's store changes on each event. Every mutation therefore\n * re-reads storage first, so a stale instance can neither resurrect a record\n * another instance resumed nor resume it a second time.\n */\nimport { parseParkedPayload } from \"./parse.js\"\nimport { MAX_PARKED, MAX_PARKED_TEXT, PARKED_VERSION } from \"./types.js\"\nimport type { ParkedPayload, ParkedRecord, ParkedStorage } from \"./types.js\"\n\nfunction boundDetail(raw: string): string {\n return raw.length > MAX_PARKED_TEXT ? raw.slice(0, MAX_PARKED_TEXT) : raw\n}\n\nexport class ParkedWorkStore {\n #records: ParkedRecord[] = []\n #queue: Promise<unknown> = Promise.resolve()\n\n constructor(private readonly storage: ParkedStorage) {}\n\n /** Rebuild from storage (restart behavior). A read failure yields an empty store. */\n load(): Promise<void> {\n return this.#serialize(() => this.#load())\n }\n\n async #load(): Promise<void> {\n let raw: unknown\n try {\n raw = await this.storage.read()\n } catch {\n this.#records = []\n return\n }\n this.#records = parseParkedPayload(raw)\n }\n\n /**\n * Re-read storage without the load-time failure policy: a read failure\n * keeps the current records instead of forgetting parked work.\n */\n refresh(): Promise<void> {\n return this.#serialize(() => this.#refresh())\n }\n\n async #refresh(): Promise<void> {\n let raw: unknown\n try {\n raw = await this.storage.read()\n } catch {\n return\n }\n this.#records = parseParkedPayload(raw)\n }\n\n /** All parked records, insertion order. */\n list(): readonly ParkedRecord[] {\n return this.#records\n }\n\n count(): number {\n return this.#records.length\n }\n\n park(record: ParkedRecord): Promise<void> {\n return this.#serialize(() => this.#park(record))\n }\n\n async #park(record: ParkedRecord): Promise<void> {\n await this.#refresh()\n const bounded: ParkedRecord = {\n ...record,\n ...(record.detail !== undefined ? { detail: boundDetail(record.detail) } : {}),\n }\n const withoutId = this.#records.filter((entry) => entry.id !== bounded.id)\n const next = this.#evictOldest([...withoutId, bounded])\n // Persist BEFORE committing memory: a failed resume must not silently\n // drop the parked unit (memory and disk stay consistent on failure).\n await this.#persist(next)\n this.#records = next\n }\n\n /**\n * Remove a parked record and return it so the execution layer knows what\n * to continue. `undefined` (no record, no write) when the id is unknown.\n */\n resume(id: string): Promise<ParkedRecord | undefined> {\n return this.#serialize(() => this.#resume(id))\n }\n\n async #resume(id: string): Promise<ParkedRecord | undefined> {\n await this.#refresh()\n const record = this.#records.find((entry) => entry.id === id)\n if (record === undefined) return undefined\n const next = this.#records.filter((entry) => entry.id !== id)\n await this.#persist(next)\n this.#records = next\n return record\n }\n\n #evictOldest(records: ParkedRecord[]): ParkedRecord[] {\n if (records.length <= MAX_PARKED) return records\n const byOldest = [...records].sort((a, b) => a.parkedAt - b.parkedAt)\n const dropped = new Set(byOldest.slice(0, records.length - MAX_PARKED).map((r) => r.id))\n return records.filter((record) => !dropped.has(record.id))\n }\n\n // Reads share the queue so reloads cannot overwrite newer commits. Recover\n // the queue after rejection while preserving the failing caller's promise.\n #serialize<T>(operation: () => Promise<T>): Promise<T> {\n const run = this.#queue.then(operation)\n this.#queue = run.catch(() => undefined)\n return run\n }\n\n /** Writes the given next state; the caller commits memory only on success. */\n async #persist(parked: readonly ParkedRecord[]): Promise<void> {\n const payload: ParkedPayload = {\n version: PARKED_VERSION,\n parked,\n }\n await this.storage.write(payload)\n }\n}\n"]}
@@ -28,6 +28,8 @@ export declare class Supervisor {
28
28
  */
29
29
  static readonly MAX_MANUAL_SELECTIONS = 1024;
30
30
  constructor(options: SupervisorOptions);
31
+ /** Stop the wake timer; a disposed supervisor never re-arms it. */
32
+ dispose(): void;
31
33
  /** Handle one host report (event pump or session hook). */
32
34
  handleReport(report: EventReport): Promise<void>;
33
35
  /**