@dynamicagents/plugins 0.11.1 → 0.12.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 (94) hide show
  1. package/README.md +12 -13
  2. package/dist/arc-agi/analysis.d.ts +16 -30
  3. package/dist/arc-agi/analysis.js +20 -47
  4. package/dist/arc-agi/game-tools.d.ts +5 -6
  5. package/dist/arc-agi/index.d.ts +6 -8
  6. package/dist/arc-agi/index.js +3 -3
  7. package/dist/arc-agi/main-agent.d.ts +5 -8
  8. package/dist/arc-agi/main-agent.js +5 -8
  9. package/dist/arc-agi/recipe.d.ts +17 -20
  10. package/dist/arc-agi/recipe.js +17 -20
  11. package/dist/arc-agi/soul.d.ts +16 -27
  12. package/dist/arc-agi/soul.js +16 -27
  13. package/dist/arc-agi/store.d.ts +4 -5
  14. package/dist/arc-agi/store.js +4 -5
  15. package/dist/arc-agi/tools.d.ts +1 -1
  16. package/dist/arc-agi/tools.js +10 -12
  17. package/dist/arc-agi/types.d.ts +6 -7
  18. package/dist/claude-code/config.d.ts +88 -11
  19. package/dist/claude-code/config.js +11 -2
  20. package/dist/claude-code/credentials.d.ts +21 -9
  21. package/dist/claude-code/credentials.js +43 -9
  22. package/dist/claude-code/egress.d.ts +7 -13
  23. package/dist/claude-code/egress.js +9 -10
  24. package/dist/claude-code/events.d.ts +47 -0
  25. package/dist/claude-code/events.js +96 -10
  26. package/dist/claude-code/index.d.ts +31 -13
  27. package/dist/claude-code/index.js +62 -15
  28. package/dist/claude-code/run.d.ts +135 -41
  29. package/dist/claude-code/run.js +366 -61
  30. package/dist/computer/advisory.d.ts +31 -18
  31. package/dist/computer/advisory.js +30 -5
  32. package/dist/computer/context.d.ts +23 -0
  33. package/dist/computer/context.js +225 -0
  34. package/dist/computer/file-lock.d.ts +5 -0
  35. package/dist/computer/file-lock.js +39 -0
  36. package/dist/computer/gate.d.ts +8 -8
  37. package/dist/computer/gate.js +7 -7
  38. package/dist/computer/host/ca-trust.d.ts +88 -0
  39. package/dist/computer/host/ca-trust.js +303 -0
  40. package/dist/computer/host/container-deps.d.ts +54 -0
  41. package/dist/computer/host/container-deps.js +224 -0
  42. package/dist/computer/host/container-fault.d.ts +38 -0
  43. package/dist/computer/host/container-fault.js +58 -0
  44. package/dist/computer/host/git-host.d.ts +62 -0
  45. package/dist/computer/host/git-host.js +156 -0
  46. package/dist/computer/host/git-identity.d.ts +57 -0
  47. package/dist/computer/host/git-identity.js +147 -0
  48. package/dist/computer/host/install-job.d.ts +121 -0
  49. package/dist/computer/host/install-job.js +766 -0
  50. package/dist/computer/host/sync.d.ts +111 -0
  51. package/dist/computer/host/sync.js +124 -0
  52. package/dist/computer/host/wake.d.ts +19 -0
  53. package/dist/computer/host/wake.js +10 -0
  54. package/dist/computer/host/workspace.d.ts +424 -0
  55. package/dist/computer/host/workspace.js +1258 -0
  56. package/dist/computer/index.d.ts +70 -50
  57. package/dist/computer/index.js +79 -767
  58. package/dist/computer/install.d.ts +8 -12
  59. package/dist/computer/install.js +6 -9
  60. package/dist/computer/paths.d.ts +21 -16
  61. package/dist/computer/paths.js +40 -38
  62. package/dist/computer/read.d.ts +18 -22
  63. package/dist/computer/read.js +24 -27
  64. package/dist/computer/render.d.ts +28 -0
  65. package/dist/computer/render.js +34 -1
  66. package/dist/computer/shell.d.ts +45 -0
  67. package/dist/computer/shell.js +80 -0
  68. package/dist/computer/tools-exec.d.ts +3 -0
  69. package/dist/computer/tools-exec.js +269 -0
  70. package/dist/computer/tools-file.d.ts +4 -0
  71. package/dist/computer/tools-file.js +124 -0
  72. package/dist/computer/tools-find.d.ts +3 -0
  73. package/dist/computer/tools-find.js +216 -0
  74. package/dist/recall/index.d.ts +9 -3
  75. package/dist/recall/index.js +22 -12
  76. package/dist/repo/checkout.d.ts +34 -4
  77. package/dist/repo/checkout.js +36 -1
  78. package/dist/repo/context.d.ts +109 -0
  79. package/dist/repo/context.js +530 -0
  80. package/dist/repo/index.d.ts +6 -29
  81. package/dist/repo/index.js +17 -1027
  82. package/dist/repo/tools-clone.d.ts +4 -0
  83. package/dist/repo/tools-clone.js +192 -0
  84. package/dist/repo/tools-forge.d.ts +4 -0
  85. package/dist/repo/tools-forge.js +179 -0
  86. package/dist/repo/tools-review.d.ts +3 -0
  87. package/dist/repo/tools-review.js +373 -0
  88. package/dist/repo/tools-worktree.d.ts +4 -0
  89. package/dist/repo/tools-worktree.js +221 -0
  90. package/dist/triage/index.d.ts +6 -1
  91. package/dist/triage/index.js +32 -23
  92. package/dist/workspace/index.d.ts +3 -3
  93. package/dist/workspace/index.js +3 -3
  94. package/package.json +21 -15
package/README.md CHANGED
@@ -80,17 +80,17 @@ needing per-caller state takes it the same way.
80
80
 
81
81
  ## The plugins
82
82
 
83
- | Subpath | What it adds | Needs |
84
- | ---------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------- |
85
- | [`/arc-agi`](src/arc-agi/) | Play ARC-AGI-3 games — a delegable subtask type, a catalogue tool, a scorecard ledger | `ARC_API_KEY` |
86
- | [`/browser`](src/browser/) | Read web pages via Browser Rendering Quick Actions | `BROWSER` (paid plan) |
87
- | [`/claude-code`](src/claude-code/) | Delegate a coding task to a Claude Code session in the workspace container | one or more `claude setup-token` credentials |
88
- | [`/computer`](src/computer/) | A Linux container whose filesystem outlives it: shell, package manager, unrestricted network | `@cloudflare/computer` (paid) |
89
- | [`/recall`](src/recall/) | Episodic memory over Vectorize — search history that compaction folded away | `VECTORIZE` (1024-dim/cosine) |
90
- | [`/repo`](src/repo/) | Clone, commit, push a branch, open a pull request — over any container | `GITHUB_TOKEN` |
91
- | [`/scratch`](src/scratch/) | A throwaway git repository with no remote, for work that needs a container but no checkout | — |
92
- | [`/triage`](src/triage/) | A pre-turn gate: is this message even for me? | — |
93
- | [`/workspace`](src/workspace/) | A durable file store for long subagent runs, plus tools over it | `@cloudflare/shell` |
83
+ | Subpath | What it adds | Needs |
84
+ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
85
+ | [`/arc-agi`](src/arc-agi/) | Play ARC-AGI-3 games — a delegable subtask type, a catalogue tool, a scorecard ledger | `ARC_API_KEY` |
86
+ | [`/browser`](src/browser/) | Read web pages via Browser Rendering Quick Actions | `BROWSER` (paid plan) |
87
+ | [`/claude-code`](src/claude-code/) | Delegate a coding task to a Claude Code session in the workspace container | one or more `claude setup-token` credentials |
88
+ | [`/computer`](src/computer/) | A Linux container whose filesystem outlives it — shell, package manager, network, and the Durable Object it runs in | `@cloudflare/computer`, `@platformatic/vfs` (paid) |
89
+ | [`/recall`](src/recall/) | Episodic memory over Vectorize — search history that compaction folded away | `VECTORIZE` (1024-dim/cosine) |
90
+ | [`/repo`](src/repo/) | Clone, commit, push a branch, open a pull request — over any container | `GITHUB_TOKEN` |
91
+ | [`/scratch`](src/scratch/) | A throwaway git repository with no remote, for work that needs a container but no checkout | — |
92
+ | [`/triage`](src/triage/) | A pre-turn gate: is this message even for me? | — |
93
+ | [`/workspace`](src/workspace/) | A durable file store for long subagent runs, plus tools over it | `@cloudflare/shell` |
94
94
 
95
95
  Each directory has its own README with the config shape and a paste-ready `wrangler.jsonc`
96
96
  snippet — a plugin cannot add its own binding, which is why it declares what it needs.
@@ -130,8 +130,7 @@ Specs run inside real workerd via `@cloudflare/vitest-plugin`, with the harness
130
130
 
131
131
  ```bash
132
132
  npm test # the whole suite, no credentials and no network
133
- npm run check # prettier + eslint + tsc + build
134
- npm run verify:exports
133
+ npm run check # prettier + eslint + tsc + build, then verify:exports over it
135
134
  ```
136
135
 
137
136
  ### Working against an unpublished core
@@ -84,11 +84,6 @@ export interface Component extends Box {
84
84
  color: number;
85
85
  size: number;
86
86
  }
87
- export interface ComponentSummary {
88
- color: number;
89
- components: number;
90
- largest: number;
91
- }
92
87
  /**
93
88
  * Every 4-connected same-color region, with its bounding box, largest first.
94
89
  * Skips {@link BACKGROUND_COLOR}.
@@ -99,19 +94,12 @@ export interface ComponentSummary {
99
94
  * visit every cell regardless, so tracking min/max row/col is free.
100
95
  */
101
96
  export declare function locateComponents(grid: number[][]): Component[];
102
- /**
103
- * Summarize components per color: how many, and the largest. Derived from
104
- * {@link locateComponents} so only one flood fill ever runs.
105
- */
106
- export declare function connectedComponents(grid: number[][]): ComponentSummary[];
107
97
  /**
108
98
  * How much of its bounding box a region actually occupies, 0–1.
109
99
  *
110
- * Boxes are well formed by construction wherever this is used: every caller
111
- * passes either a {@link Component} from {@link locateComponents} or a
112
- * {@link unionBox} of those, and a flood fill cannot produce `bottom < top`. So
113
- * `area` is always at least 1, and the zero-area branch below is unreachable —
114
- * kept only so a malformed box degrades to 0 instead of dividing by zero.
100
+ * Every caller passes a {@link Component} from {@link locateComponents} or a
101
+ * {@link unionBox} of those, and a flood fill cannot produce `bottom < top`, so
102
+ * `area` is at least 1 and there is nothing to guard against dividing by.
115
103
  *
116
104
  * The result is deliberately **not** clamped into 0–1. An out-of-range value here
117
105
  * could only mean a caller broke that invariant, and the way to learn that is a
@@ -154,12 +142,12 @@ export declare function renderSpans(bands: SpanBand[]): string;
154
142
  *
155
143
  * A bounding box describes a region only when the region roughly fills it. That
156
144
  * holds for the movable pieces and fails for exactly the two things a route
157
- * depends on: on a real `ls20` board the model was told `off-black: rows 0-63,
158
- * cols 0-63 (2129 cells)` for the whole maze and `neutral: rows 5-54, cols 9-58
159
- * (1354 cells)` for the whole floor, both a shade over half-filled. The first says
160
- * nothing; the second is worse, asserting a 50×50 open arena of which 46% is wall.
161
- * Blind to both, the play read its route off the boxes and walked into walls, then
162
- * spent a dozen turns rebuilding the maze through 11×11 `region` peepholes.
145
+ * depends on: on a real `ls20` board the maze boxes as `off-black: rows 0-63,
146
+ * cols 0-63 (2129 cells)` and the floor as `neutral: rows 5-54, cols 9-58 (1354
147
+ * cells)`, both a shade over half-filled. The first says nothing; the second is
148
+ * worse, asserting a 50×50 open arena of which 46% is wall — and a play reading
149
+ * its route off those boxes walks into walls, then spends a dozen turns
150
+ * rebuilding the maze through 11×11 `region` peepholes.
163
151
  *
164
152
  * So a region that sprawls is rendered as {@link colorSpans} instead — every row
165
153
  * band and the columns it occupies, which is the same fact at a resolution that
@@ -257,9 +245,8 @@ export declare function describeShift(dRow: number, dCol: number): string;
257
245
  * *blocked or refused*: it leads a step only when everything else the delta holds
258
246
  * is a {@link ShapeChange} of kind `resized`, which is a counter or a bar doing
259
247
  * its own bookkeeping. A step that repainted a block, or made one appear, changed
260
- * the board — no object travelled, and saying so as `nothing moved` told a logged
261
- * `ft09` play that twenty clicks which each toggled a 36-cell block had been
262
- * refused.
248
+ * the board — no object travelled, and reporting that as `nothing moved` tells a
249
+ * click game that twenty clicks which each toggled a 36-cell block were refused.
263
250
  *
264
251
  * Null means *this view has nothing to say* — either no shape can be paired
265
252
  * across the frames, or so many changed that they are a repaint
@@ -326,11 +313,10 @@ export declare function renderGrid(grid: number[][]): string;
326
313
  * `firstCol + i`. Padding off-grid columns with spaces instead would shift that
327
314
  * mapping by up to `radius` near the left edge.
328
315
  *
329
- * The header used to be the only thing to count from, on the reasoning that a
330
- * window this narrow does not need a ruler. Logs disagree: asked to place a cell
331
- * in an 11-wide window, the model counted the characters by hand and got them
332
- * wrong — "cols 34-38, 5 chars wait that's 10... hmm" — then reasoned on the wrong
333
- * columns. So the window is ruled too, at {@link REGION_RULER_STEP} rather than
334
- * {@link renderGrid}'s tens, which a window this size can miss entirely.
316
+ * **The window is ruled, not just headed.** A model asked to place a cell in an
317
+ * 11-wide window counts the characters by hand and gets them wrong, then reasons
318
+ * on the columns it miscounted — so narrow is exactly where the ruler is needed.
319
+ * It steps at {@link REGION_RULER_STEP} rather than {@link renderGrid}'s tens,
320
+ * which a window this size can miss entirely.
335
321
  */
336
322
  export declare function renderRegion(grid: number[][], centerRow: number, centerCol: number, radius?: number): string;
@@ -204,42 +204,19 @@ export function locateComponents(grid) {
204
204
  }
205
205
  return found.sort((x, y) => y.size - x.size);
206
206
  }
207
- /**
208
- * Summarize components per color: how many, and the largest. Derived from
209
- * {@link locateComponents} so only one flood fill ever runs.
210
- */
211
- export function connectedComponents(grid) {
212
- const perColor = new Map();
213
- for (const comp of locateComponents(grid)) {
214
- const entry = perColor.get(comp.color) ?? { components: 0, largest: 0 };
215
- entry.components++;
216
- entry.largest = Math.max(entry.largest, comp.size);
217
- perColor.set(comp.color, entry);
218
- }
219
- return [...perColor.entries()]
220
- .map(([color, v]) => ({
221
- color,
222
- components: v.components,
223
- largest: v.largest
224
- }))
225
- .sort((x, y) => y.components - x.components);
226
- }
227
207
  /**
228
208
  * How much of its bounding box a region actually occupies, 0–1.
229
209
  *
230
- * Boxes are well formed by construction wherever this is used: every caller
231
- * passes either a {@link Component} from {@link locateComponents} or a
232
- * {@link unionBox} of those, and a flood fill cannot produce `bottom < top`. So
233
- * `area` is always at least 1, and the zero-area branch below is unreachable —
234
- * kept only so a malformed box degrades to 0 instead of dividing by zero.
210
+ * Every caller passes a {@link Component} from {@link locateComponents} or a
211
+ * {@link unionBox} of those, and a flood fill cannot produce `bottom < top`, so
212
+ * `area` is at least 1 and there is nothing to guard against dividing by.
235
213
  *
236
214
  * The result is deliberately **not** clamped into 0–1. An out-of-range value here
237
215
  * could only mean a caller broke that invariant, and the way to learn that is a
238
216
  * region classified absurdly, not a number quietly corrected into looking sane.
239
217
  */
240
218
  export function fillRatio(box, size) {
241
- const area = (box.bottom - box.top + 1) * (box.right - box.left + 1);
242
- return area === 0 ? 0 : size / area;
219
+ return size / ((box.bottom - box.top + 1) * (box.right - box.left + 1));
243
220
  }
244
221
  /**
245
222
  * The rectangle enclosing several boxes. Takes a **non-empty** list — the reduce
@@ -349,12 +326,12 @@ const SPRAWL_COLORS = 3;
349
326
  *
350
327
  * A bounding box describes a region only when the region roughly fills it. That
351
328
  * holds for the movable pieces and fails for exactly the two things a route
352
- * depends on: on a real `ls20` board the model was told `off-black: rows 0-63,
353
- * cols 0-63 (2129 cells)` for the whole maze and `neutral: rows 5-54, cols 9-58
354
- * (1354 cells)` for the whole floor, both a shade over half-filled. The first says
355
- * nothing; the second is worse, asserting a 50×50 open arena of which 46% is wall.
356
- * Blind to both, the play read its route off the boxes and walked into walls, then
357
- * spent a dozen turns rebuilding the maze through 11×11 `region` peepholes.
329
+ * depends on: on a real `ls20` board the maze boxes as `off-black: rows 0-63,
330
+ * cols 0-63 (2129 cells)` and the floor as `neutral: rows 5-54, cols 9-58 (1354
331
+ * cells)`, both a shade over half-filled. The first says nothing; the second is
332
+ * worse, asserting a 50×50 open arena of which 46% is wall — and a play reading
333
+ * its route off those boxes walks into walls, then spends a dozen turns
334
+ * rebuilding the maze through 11×11 `region` peepholes.
358
335
  *
359
336
  * So a region that sprawls is rendered as {@link colorSpans} instead — every row
360
337
  * band and the columns it occupies, which is the same fact at a resolution that
@@ -532,11 +509,9 @@ export function matchShapes(before, after) {
532
509
  *
533
510
  * A click game is the case this exists for. Nothing on such a board ever travels,
534
511
  * so both earlier passes — which pair within a color — leave every changed block
535
- * as a `gone` and an `appeared` at the same coordinates, and a whole play reads as
536
- * things vanishing and other things materializing where they stood. The logged
537
- * `ft09` play was told `blue 6×6 at rows 36-41, cols 36-41 is gone; red 6×6
538
- * appeared at rows 36-41, cols 36-41` twenty times and had to work out for itself,
539
- * across several turns, that a click toggles a block's color.
512
+ * as a `gone` and an `appeared` at the same coordinates: `blue 6×6 at rows 36-41,
513
+ * cols 36-41 is gone; red 6×6 appeared at rows 36-41, cols 36-41`, twenty times
514
+ * over, with the model left to work out for itself that a click toggles a colour.
540
515
  *
541
516
  * Box and size together are strong evidence and not proof — two different shapes
542
517
  * can share a bounding box and a cell count without sharing a cell — but the
@@ -595,9 +570,8 @@ function describeDestination(change) {
595
570
  * *blocked or refused*: it leads a step only when everything else the delta holds
596
571
  * is a {@link ShapeChange} of kind `resized`, which is a counter or a bar doing
597
572
  * its own bookkeeping. A step that repainted a block, or made one appear, changed
598
- * the board — no object travelled, and saying so as `nothing moved` told a logged
599
- * `ft09` play that twenty clicks which each toggled a 36-cell block had been
600
- * refused.
573
+ * the board — no object travelled, and reporting that as `nothing moved` tells a
574
+ * click game that twenty clicks which each toggled a 36-cell block were refused.
601
575
  *
602
576
  * Null means *this view has nothing to say* — either no shape can be paired
603
577
  * across the frames, or so many changed that they are a repaint
@@ -790,12 +764,11 @@ export function renderGrid(grid) {
790
764
  * `firstCol + i`. Padding off-grid columns with spaces instead would shift that
791
765
  * mapping by up to `radius` near the left edge.
792
766
  *
793
- * The header used to be the only thing to count from, on the reasoning that a
794
- * window this narrow does not need a ruler. Logs disagree: asked to place a cell
795
- * in an 11-wide window, the model counted the characters by hand and got them
796
- * wrong — "cols 34-38, 5 chars wait that's 10... hmm" — then reasoned on the wrong
797
- * columns. So the window is ruled too, at {@link REGION_RULER_STEP} rather than
798
- * {@link renderGrid}'s tens, which a window this size can miss entirely.
767
+ * **The window is ruled, not just headed.** A model asked to place a cell in an
768
+ * 11-wide window counts the characters by hand and gets them wrong, then reasons
769
+ * on the columns it miscounted — so narrow is exactly where the ruler is needed.
770
+ * It steps at {@link REGION_RULER_STEP} rather than {@link renderGrid}'s tens,
771
+ * which a window this size can miss entirely.
799
772
  */
800
773
  export function renderRegion(grid, centerRow, centerCol, radius = 5) {
801
774
  if (grid.length === 0)
@@ -3,12 +3,11 @@ import type { ArcClient } from "./client.js";
3
3
  /**
4
4
  * The **main agent's** ARC tool: the game catalogue, and nothing else.
5
5
  *
6
- * It used to also own the scorecard lifecycle — open a card, name it in each
7
- * play's params, close it for the score. That modelled a lifecycle the API
8
- * already manages (it auto-closes an idle card), and made every play depend on
9
- * the model getting the bookkeeping right. The card is now leased by the recipe
10
- * (see {@link file://./scorecard.ts}) and never named here, so the only thing the
11
- * main agent still needs from ARC is the exact game id to delegate a play with.
6
+ * **No scorecard lifecycle here.** The API retires an idle card itself, so a
7
+ * card opened, named and closed by the model is a lifecycle modelled twice with
8
+ * every play depending on the model's bookkeeping. The card is leased by the
9
+ * recipe (see {@link file://./scorecard.ts}) and never named here, so the only
10
+ * thing the main agent needs from ARC is the exact game id to delegate with.
12
11
  *
13
12
  * Handlers are exported separately from the `tool()` wiring so they unit-test
14
13
  * without an LLM, and the client is closed over so it is never model input.
@@ -6,15 +6,13 @@ import type { ArcRuntime } from "./types.js";
6
6
  /**
7
7
  * `@dynamicagents/plugins/arc-agi` — play ARC-AGI-3 games.
8
8
  *
9
- * The stress test for the whole plugin contract, and the reason three of its
10
- * hooks exist. In the predecessor these were four leaks in the agent's Durable
11
- * Object — `resolveRuntime`, `arcScorecardDeps`, `leaseScorecard`/`leasePlay`,
12
- * and `enrichResult` — each a piece of ARC-specific policy living in code that
13
- * had no other reason to know what a scorecard was. Inverted, they are this
14
- * file.
9
+ * The stress test for the whole plugin contract, and the reason `resolveRuntime`,
10
+ * the lease hooks and `enrichResult` exist on it: every one of them is a piece of
11
+ * ARC-specific policy that would otherwise sit in an agent's Durable Object,
12
+ * which has no other reason to know what a scorecard is.
15
13
  *
16
- * What the split makes visible: the *only* thing the agent still knows is that
17
- * it installed a plugin. Nothing in a loop, a workflow, or a DO names a card, a
14
+ * The line that keeps it honest: the *only* thing the agent knows is that it
15
+ * installed a plugin. Nothing in a loop, a workflow, or a DO names a card, a
18
16
  * guid, or a game.
19
17
  */
20
18
  /** Everything this plugin needs from its host. */
@@ -18,9 +18,9 @@ export function arcAgi(config) {
18
18
  /**
19
19
  * In-flight leases, collapsed so concurrent branches share one call.
20
20
  *
21
- * These were DO instance fields in the predecessor, and the plugin is built
22
- * per DO instance, so this closure is the same scope — but it is now the scope
23
- * of the thing that *cares*, rather than of the agent that merely hosted it.
21
+ * The plugin is built once per DO instance, so this closure is per-instance
22
+ * scope — held by the thing that cares about a card rather than by the agent
23
+ * that merely hosts it.
24
24
  *
25
25
  * Load-bearing, not an optimization. All of a round's ready Subtasks execute
26
26
  * concurrently, and opening a card is a `fetch`, which opens the DO's input
@@ -3,14 +3,11 @@ import type { DelegationNames } from "@dynamicagents/core";
3
3
  * Everything the **main agent** is told about ARC-AGI-3 — the counterpart to
4
4
  * {@link file://./soul.ts}, which is what the *subagent* playing a game is told.
5
5
  *
6
- * Both blocks used to be hand-written inside `agent/` (`prompt.ts`'s
7
- * `ARC_CAPABILITY` and a `## Playing an ARC-AGI-3 game` section of
8
- * `turn.ts`'s round contract). The main agent's system prompt is soul +
9
- * round contract concatenated, so it read ARC advice twice per round from two
10
- * files with no reason to agree — and they had stopped agreeing: one said to
11
- * delegate a subtask per game, the other said to delegate exactly one subtask and
12
- * nothing else. They are one file now, and the guidance below follows the
13
- * capability block.
6
+ * **The capability block and the delegation guidance stay in this one file.** A
7
+ * main agent's system prompt is soul plus round contract concatenated, so split
8
+ * across two files they are two statements of the same advice with no reason to
9
+ * agree — and the way they disagree is one telling the model to delegate a
10
+ * subtask per game while the other allows exactly one.
14
11
  */
15
12
  /**
16
13
  * The capability block: what the agent can do, and what to do with a result that
@@ -2,14 +2,11 @@
2
2
  * Everything the **main agent** is told about ARC-AGI-3 — the counterpart to
3
3
  * {@link file://./soul.ts}, which is what the *subagent* playing a game is told.
4
4
  *
5
- * Both blocks used to be hand-written inside `agent/` (`prompt.ts`'s
6
- * `ARC_CAPABILITY` and a `## Playing an ARC-AGI-3 game` section of
7
- * `turn.ts`'s round contract). The main agent's system prompt is soul +
8
- * round contract concatenated, so it read ARC advice twice per round from two
9
- * files with no reason to agree — and they had stopped agreeing: one said to
10
- * delegate a subtask per game, the other said to delegate exactly one subtask and
11
- * nothing else. They are one file now, and the guidance below follows the
12
- * capability block.
5
+ * **The capability block and the delegation guidance stay in this one file.** A
6
+ * main agent's system prompt is soul plus round contract concatenated, so split
7
+ * across two files they are two statements of the same advice with no reason to
8
+ * agree — and the way they disagree is one telling the model to delegate a
9
+ * subtask per game while the other allows exactly one.
13
10
  */
14
11
  /**
15
12
  * The capability block: what the agent can do, and what to do with a result that
@@ -8,19 +8,18 @@ export declare const ARC_GAME_TYPE = "arc-game";
8
8
  * a turn budget twice the baseline — a play is a long sequence of cheap decisions,
9
9
  * and 20 turns bought roughly ten game actions once inspection was paid for.
10
10
  *
11
- * It used to be "the long recipe", budgeted at 1,000 turns on the reasoning that
12
- * 25 turns per chunk made 40 durable chunks. That arithmetic assumed a turn under
13
- * ten seconds. A turn here is a reasoning model plus an ARC HTTP round trip, so
14
- * real runs took 70-100 chunks, blew the per-branch cap, and were *failed* after
15
- * hours of unattended play rather than being asked to report. The budget is now
16
- * time and turns, both enforced directly, and a play ends through the graceful
17
- * summary — a terminal report with the metrics footer.
11
+ * **Budget the turns, never the chunks.** A turn here is a reasoning model plus
12
+ * an ARC HTTP round trip, nothing like the sub-ten-second turn a chunk count is
13
+ * implicitly sized against: 1,000 turns sliced 25 to a chunk is 40 chunks on
14
+ * paper and 70-100 in a real run, which blows the per-branch cap and *fails* a
15
+ * play after hours rather than asking it to report. Time and turns are both
16
+ * enforced directly, and a play ends through the graceful summary — a terminal
17
+ * report with the metrics footer.
18
18
  *
19
- * - `historyWindow` bounds context, and it is now the model's *only* memory: the
20
- * workspace tools are gone (see below), so a plan that scrolls out of it is
21
- * gone. Note it counts *assistant messages* — one per tool call, not one per
22
- * game action — so a play spends it several times faster than the number
23
- * suggests.
19
+ * - `historyWindow` bounds context, and it is the model's *only* memory: with no
20
+ * workspace tools (see below) a plan that scrolls out of it is gone. Note it
21
+ * counts *assistant messages* — one per tool call, not one per game action —
22
+ * so a play spends it several times faster than the number suggests.
24
23
  * - `reportMetrics` appends the turns/model-calls/wall-clock footer the user
25
24
  * asked to see.
26
25
  *
@@ -28,14 +27,12 @@ export declare const ARC_GAME_TYPE = "arc-game";
28
27
  * state kept in the workspace), code-validated by
29
28
  * `validateRecipe`/`buildRecipeTools`.
30
29
  *
31
- * It used to also carry `workspace`, on the theory that a small history window
32
- * needs a file store behind it. Two logged plays say otherwise: `ws_read` was
33
- * never called once, and the three `ws_write` calls between them were a
34
- * scratchpad for arithmetic — a use that costs a turn per note and now belongs in
35
- * `arc_act`'s `note` field, which costs none and stays in the model's own history.
36
- * The session file is unaffected: the family reaches the workspace through its
37
- * {@link file://../../agent/tools.ts ToolFamilyContext}, not through the tools the
38
- * model can see.
30
+ * **No `workspace` family, despite the small history window.** Across two logged
31
+ * plays `ws_read` was never called and the three `ws_write` calls were a
32
+ * scratchpad for arithmetic — a note costing a turn apiece, which `arc_act`'s
33
+ * `note` field carries for free and keeps in the model's own history. The
34
+ * session file is unaffected: the family reaches the workspace through the
35
+ * `ToolFamilyContext` core hands it, not through tools the model can see.
39
36
  */
40
37
  export declare const ARC_GAME_RECIPE: ResolvedRecipe;
41
38
  /**
@@ -10,19 +10,18 @@ export const ARC_GAME_TYPE = "arc-game";
10
10
  * a turn budget twice the baseline — a play is a long sequence of cheap decisions,
11
11
  * and 20 turns bought roughly ten game actions once inspection was paid for.
12
12
  *
13
- * It used to be "the long recipe", budgeted at 1,000 turns on the reasoning that
14
- * 25 turns per chunk made 40 durable chunks. That arithmetic assumed a turn under
15
- * ten seconds. A turn here is a reasoning model plus an ARC HTTP round trip, so
16
- * real runs took 70-100 chunks, blew the per-branch cap, and were *failed* after
17
- * hours of unattended play rather than being asked to report. The budget is now
18
- * time and turns, both enforced directly, and a play ends through the graceful
19
- * summary — a terminal report with the metrics footer.
13
+ * **Budget the turns, never the chunks.** A turn here is a reasoning model plus
14
+ * an ARC HTTP round trip, nothing like the sub-ten-second turn a chunk count is
15
+ * implicitly sized against: 1,000 turns sliced 25 to a chunk is 40 chunks on
16
+ * paper and 70-100 in a real run, which blows the per-branch cap and *fails* a
17
+ * play after hours rather than asking it to report. Time and turns are both
18
+ * enforced directly, and a play ends through the graceful summary — a terminal
19
+ * report with the metrics footer.
20
20
  *
21
- * - `historyWindow` bounds context, and it is now the model's *only* memory: the
22
- * workspace tools are gone (see below), so a plan that scrolls out of it is
23
- * gone. Note it counts *assistant messages* — one per tool call, not one per
24
- * game action — so a play spends it several times faster than the number
25
- * suggests.
21
+ * - `historyWindow` bounds context, and it is the model's *only* memory: with no
22
+ * workspace tools (see below) a plan that scrolls out of it is gone. Note it
23
+ * counts *assistant messages* — one per tool call, not one per game action —
24
+ * so a play spends it several times faster than the number suggests.
26
25
  * - `reportMetrics` appends the turns/model-calls/wall-clock footer the user
27
26
  * asked to see.
28
27
  *
@@ -30,14 +29,12 @@ export const ARC_GAME_TYPE = "arc-game";
30
29
  * state kept in the workspace), code-validated by
31
30
  * `validateRecipe`/`buildRecipeTools`.
32
31
  *
33
- * It used to also carry `workspace`, on the theory that a small history window
34
- * needs a file store behind it. Two logged plays say otherwise: `ws_read` was
35
- * never called once, and the three `ws_write` calls between them were a
36
- * scratchpad for arithmetic — a use that costs a turn per note and now belongs in
37
- * `arc_act`'s `note` field, which costs none and stays in the model's own history.
38
- * The session file is unaffected: the family reaches the workspace through its
39
- * {@link file://../../agent/tools.ts ToolFamilyContext}, not through the tools the
40
- * model can see.
32
+ * **No `workspace` family, despite the small history window.** Across two logged
33
+ * plays `ws_read` was never called and the three `ws_write` calls were a
34
+ * scratchpad for arithmetic — a note costing a turn apiece, which `arc_act`'s
35
+ * `note` field carries for free and keeps in the model's own history. The
36
+ * session file is unaffected: the family reaches the workspace through the
37
+ * `ToolFamilyContext` core hands it, not through tools the model can see.
41
38
  */
42
39
  export const ARC_GAME_RECIPE = {
43
40
  key: ARC_GAME_TYPE,
@@ -7,34 +7,23 @@
7
7
  * Subtask param and the card is resolved runtime state, so the tools close over
8
8
  * both and the model never names, chooses, or copies either id.
9
9
  *
10
- * Three sections here are written against specific, logged failures rather than
11
- * against a theory of good play, and each says so where it sits:
10
+ * Sections written against logged failures rather than a theory of good play,
11
+ * and the constraints they carry:
12
12
  *
13
- * - **Memory** used to be workspace discipline ("write your notes to a file").
14
- * Two plays never read a note back, so the notes are gone and what replaces
15
- * them is `arc_act`'s `note` field, which costs no turn.
16
- * - **Finishing** used to ask for the rules "in prose", and got a final report
17
- * whose central claim its own last tool result contradicted. It now asks for
18
- * provenance: observed, inferred, or untested.
19
- * - **Inherited knowledge** is new. A play handed a route from an earlier play
20
- * executed it faithfully while the board disagreed, because nothing told it
21
- * that what it was given was a guess about a level nobody had finished.
22
- * - **Reading a step's result** used to teach one phrase, `nothing moved`, as the
23
- * whole vocabulary of a step that achieved nothing. That is a movement game's
24
- * vocabulary: a click game moves nothing ever, and the play that found this out
25
- * was told its every click had been "refused or blocked" while each was toggling
26
- * a 36-cell block. The registers are now named separately here and rendered
27
- * separately in {@link file://./analysis.ts}.
28
- * - **Where the views stand** was rewritten against measurements. It used to sell
29
- * `shapes` as cheap and `grid` as the expensive last resort; three logged plays
30
- * answered by calling `region` twelve times and `grid` not once, mapping a maze
31
- * through 11×11 peepholes because the one line `shapes` gave them for the wall
32
- * was its full-board bounding box. `shapes` now carries the terrain itself, and
33
- * the full grid of a real board is 35 collapsed lines — so the ordering here is
13
+ * - **Reading a step's result** names each register separately — refused,
14
+ * nothing moved, changed but did not travel — because `nothing moved` is a
15
+ * movement game's vocabulary and a click game moves nothing ever. The wording
16
+ * here is paired with the rendering in {@link file://./analysis.ts}: teach a
17
+ * register the prompt does not name, or name one the renderer never emits, and
18
+ * the model reads every click as refused.
19
+ * - **Where the views stand** is ordered by measurement, not by cost intuition:
34
20
  * `shapes` for the map, `grid` for exact cells, `region` for fine detail only.
35
- * The batching section gained the step that follows from it: a route is checked
36
- * against those bands before it is sent. That check lives here rather than in
37
- * the tool because it is a judgement about the game's rules — what blocks what —
38
- * and a tool that made it would be guessing on the model's behalf.
21
+ * The full grid of a real board is 35 collapsed lines, so `grid` is not the
22
+ * expensive last resort it reads as; rank it as one and the model maps a
23
+ * maze through `region` peepholes rather than reading the board whole.
24
+ * - **Batching** requires a route to be walked against those bands before it is
25
+ * sent. That check is here rather than in the tool because it is a judgement
26
+ * about the game's rules — what blocks what — and a tool making it would be
27
+ * guessing on the model's behalf.
39
28
  */
40
29
  export declare const ARC_GAME_SOUL: string;
@@ -7,35 +7,24 @@
7
7
  * Subtask param and the card is resolved runtime state, so the tools close over
8
8
  * both and the model never names, chooses, or copies either id.
9
9
  *
10
- * Three sections here are written against specific, logged failures rather than
11
- * against a theory of good play, and each says so where it sits:
10
+ * Sections written against logged failures rather than a theory of good play,
11
+ * and the constraints they carry:
12
12
  *
13
- * - **Memory** used to be workspace discipline ("write your notes to a file").
14
- * Two plays never read a note back, so the notes are gone and what replaces
15
- * them is `arc_act`'s `note` field, which costs no turn.
16
- * - **Finishing** used to ask for the rules "in prose", and got a final report
17
- * whose central claim its own last tool result contradicted. It now asks for
18
- * provenance: observed, inferred, or untested.
19
- * - **Inherited knowledge** is new. A play handed a route from an earlier play
20
- * executed it faithfully while the board disagreed, because nothing told it
21
- * that what it was given was a guess about a level nobody had finished.
22
- * - **Reading a step's result** used to teach one phrase, `nothing moved`, as the
23
- * whole vocabulary of a step that achieved nothing. That is a movement game's
24
- * vocabulary: a click game moves nothing ever, and the play that found this out
25
- * was told its every click had been "refused or blocked" while each was toggling
26
- * a 36-cell block. The registers are now named separately here and rendered
27
- * separately in {@link file://./analysis.ts}.
28
- * - **Where the views stand** was rewritten against measurements. It used to sell
29
- * `shapes` as cheap and `grid` as the expensive last resort; three logged plays
30
- * answered by calling `region` twelve times and `grid` not once, mapping a maze
31
- * through 11×11 peepholes because the one line `shapes` gave them for the wall
32
- * was its full-board bounding box. `shapes` now carries the terrain itself, and
33
- * the full grid of a real board is 35 collapsed lines — so the ordering here is
13
+ * - **Reading a step's result** names each register separately — refused,
14
+ * nothing moved, changed but did not travel — because `nothing moved` is a
15
+ * movement game's vocabulary and a click game moves nothing ever. The wording
16
+ * here is paired with the rendering in {@link file://./analysis.ts}: teach a
17
+ * register the prompt does not name, or name one the renderer never emits, and
18
+ * the model reads every click as refused.
19
+ * - **Where the views stand** is ordered by measurement, not by cost intuition:
34
20
  * `shapes` for the map, `grid` for exact cells, `region` for fine detail only.
35
- * The batching section gained the step that follows from it: a route is checked
36
- * against those bands before it is sent. That check lives here rather than in
37
- * the tool because it is a judgement about the game's rules — what blocks what —
38
- * and a tool that made it would be guessing on the model's behalf.
21
+ * The full grid of a real board is 35 collapsed lines, so `grid` is not the
22
+ * expensive last resort it reads as; rank it as one and the model maps a
23
+ * maze through `region` peepholes rather than reading the board whole.
24
+ * - **Batching** requires a route to be walked against those bands before it is
25
+ * sent. That check is here rather than in the tool because it is a judgement
26
+ * about the game's rules — what blocks what — and a tool making it would be
27
+ * guessing on the model's behalf.
39
28
  */
40
29
  export const ARC_GAME_SOUL = [
41
30
  "You are playing an ARC-AGI-3 game: a visual-reasoning puzzle on a 64×64 grid of colored cells. You discover the game's hidden rules by acting and observing, and progress through levels toward a win.",
@@ -14,11 +14,10 @@ import type { ScorecardStore } from "./scorecard.js";
14
14
  *
15
15
  * A plugin must never run drizzle's durable-sqlite **migrator**: it keeps one
16
16
  * flat integer journal and one global `__drizzle_migrations` table, which two
17
- * independently-versioned packages cannot share — the two predecessor agents,
18
- * both consuming the same `notify_tasks` module, had already forked that journal
19
- * at index 1. And `drizzle-kit generate` diffs against a snapshot in a single
20
- * output directory, so a plugin shipping from its own repo cannot produce a
21
- * correct diff at all.
17
+ * independently-versioned packages cannot share: two agents consuming the same
18
+ * module fork that journal at the first index they disagree on. And
19
+ * `drizzle-kit generate` diffs against a snapshot in a single output directory,
20
+ * so a plugin shipping from its own repo cannot produce a correct diff at all.
22
21
  *
23
22
  * None of that touches the **query builder**, which is a typed wrapper over the
24
23
  * same `DurableObjectStorage` holding no journal and no connection state. So the