@dynamicagents/plugins 0.11.1 → 0.13.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 (134) hide show
  1. package/README.md +59 -79
  2. package/dist/browser/index.d.ts +0 -2
  3. package/dist/browser/index.js +21 -27
  4. package/dist/claude-code/cards.d.ts +53 -0
  5. package/dist/claude-code/cards.js +272 -0
  6. package/dist/claude-code/config.d.ts +73 -31
  7. package/dist/claude-code/config.js +0 -2
  8. package/dist/claude-code/credentials.d.ts +21 -9
  9. package/dist/claude-code/credentials.js +43 -9
  10. package/dist/claude-code/egress.d.ts +15 -14
  11. package/dist/claude-code/egress.js +51 -14
  12. package/dist/claude-code/events.d.ts +153 -9
  13. package/dist/claude-code/events.js +289 -58
  14. package/dist/claude-code/github.d.ts +39 -0
  15. package/dist/claude-code/github.js +82 -0
  16. package/dist/claude-code/index.d.ts +24 -80
  17. package/dist/claude-code/index.js +19 -234
  18. package/dist/claude-code/model.d.ts +152 -0
  19. package/dist/claude-code/model.js +342 -0
  20. package/dist/claude-code/run.d.ts +283 -92
  21. package/dist/claude-code/run.js +620 -114
  22. package/dist/claude-code/session.d.ts +131 -0
  23. package/dist/claude-code/session.js +285 -0
  24. package/dist/claude-code/spec.d.ts +46 -0
  25. package/dist/claude-code/spec.js +83 -0
  26. package/dist/claude-code/verified.d.ts +15 -0
  27. package/dist/claude-code/verified.js +15 -0
  28. package/dist/computer/context.d.ts +19 -0
  29. package/dist/computer/context.js +222 -0
  30. package/dist/computer/file-lock.d.ts +5 -0
  31. package/dist/computer/file-lock.js +40 -0
  32. package/dist/computer/gate.d.ts +12 -12
  33. package/dist/computer/gate.js +12 -12
  34. package/dist/computer/index.d.ts +57 -255
  35. package/dist/computer/index.js +98 -1039
  36. package/dist/computer/paths.d.ts +47 -22
  37. package/dist/computer/paths.js +64 -49
  38. package/dist/computer/proxy.d.ts +45 -0
  39. package/dist/computer/proxy.js +234 -0
  40. package/dist/computer/render.d.ts +27 -38
  41. package/dist/computer/render.js +32 -65
  42. package/dist/computer/tools-exec.d.ts +3 -0
  43. package/dist/computer/tools-exec.js +268 -0
  44. package/dist/computer/tools-file.d.ts +12 -0
  45. package/dist/computer/tools-file.js +64 -0
  46. package/dist/computer/tools-grep.d.ts +3 -0
  47. package/dist/computer/tools-grep.js +129 -0
  48. package/dist/repo/checkout.d.ts +35 -6
  49. package/dist/repo/checkout.js +64 -6
  50. package/dist/repo/context.d.ts +135 -0
  51. package/dist/repo/context.js +582 -0
  52. package/dist/repo/index.d.ts +79 -57
  53. package/dist/repo/index.js +118 -1112
  54. package/dist/repo/tools-checks.d.ts +3 -0
  55. package/dist/repo/tools-checks.js +112 -0
  56. package/dist/repo/tools-clone.d.ts +4 -0
  57. package/dist/repo/tools-clone.js +192 -0
  58. package/dist/repo/tools-pr.d.ts +14 -0
  59. package/dist/repo/tools-pr.js +196 -0
  60. package/dist/repo/tools-review.d.ts +12 -0
  61. package/dist/repo/tools-review.js +393 -0
  62. package/dist/repo/tools-worktree.d.ts +4 -0
  63. package/dist/repo/tools-worktree.js +305 -0
  64. package/dist/repo/tools-worktrees.d.ts +12 -0
  65. package/dist/repo/tools-worktrees.js +48 -0
  66. package/dist/repo/url.d.ts +2 -2
  67. package/dist/repo/url.js +7 -7
  68. package/dist/scratch/index.d.ts +4 -4
  69. package/dist/scratch/index.js +12 -11
  70. package/dist/{computer → workspace}/advisory.d.ts +33 -20
  71. package/dist/{computer → workspace}/advisory.js +32 -7
  72. package/dist/workspace/ca-trust.d.ts +95 -0
  73. package/dist/workspace/ca-trust.js +312 -0
  74. package/dist/workspace/container-deps.d.ts +54 -0
  75. package/dist/workspace/container-deps.js +224 -0
  76. package/dist/workspace/container-fault.d.ts +38 -0
  77. package/dist/workspace/container-fault.js +73 -0
  78. package/dist/workspace/exec.d.ts +94 -0
  79. package/dist/workspace/exec.js +153 -0
  80. package/dist/workspace/format.d.ts +36 -0
  81. package/dist/workspace/format.js +57 -0
  82. package/dist/workspace/git-host.d.ts +79 -0
  83. package/dist/workspace/git-host.js +226 -0
  84. package/dist/workspace/git-identity.d.ts +57 -0
  85. package/dist/workspace/git-identity.js +147 -0
  86. package/dist/workspace/index.d.ts +43 -47
  87. package/dist/workspace/index.js +52 -112
  88. package/dist/workspace/install-job.d.ts +121 -0
  89. package/dist/workspace/install-job.js +866 -0
  90. package/dist/{computer → workspace}/install.d.ts +15 -19
  91. package/dist/{computer → workspace}/install.js +8 -11
  92. package/dist/workspace/object.d.ts +502 -0
  93. package/dist/workspace/object.js +1427 -0
  94. package/dist/workspace/open.d.ts +95 -0
  95. package/dist/workspace/open.js +63 -0
  96. package/dist/workspace/read.d.ts +16 -0
  97. package/dist/workspace/read.js +22 -0
  98. package/dist/workspace/shell.d.ts +45 -0
  99. package/dist/workspace/shell.js +80 -0
  100. package/dist/workspace/sync.d.ts +111 -0
  101. package/dist/workspace/sync.js +124 -0
  102. package/dist/workspace/wake.d.ts +19 -0
  103. package/dist/workspace/wake.js +10 -0
  104. package/package.json +28 -42
  105. package/dist/arc-agi/analysis.d.ts +0 -336
  106. package/dist/arc-agi/analysis.js +0 -829
  107. package/dist/arc-agi/client.d.ts +0 -82
  108. package/dist/arc-agi/client.js +0 -113
  109. package/dist/arc-agi/game-tools.d.ts +0 -25
  110. package/dist/arc-agi/game-tools.js +0 -26
  111. package/dist/arc-agi/index.d.ts +0 -42
  112. package/dist/arc-agi/index.js +0 -175
  113. package/dist/arc-agi/main-agent.d.ts +0 -27
  114. package/dist/arc-agi/main-agent.js +0 -65
  115. package/dist/arc-agi/recipe.d.ts +0 -51
  116. package/dist/arc-agi/recipe.js +0 -100
  117. package/dist/arc-agi/scorecard.d.ts +0 -118
  118. package/dist/arc-agi/scorecard.js +0 -163
  119. package/dist/arc-agi/soul.d.ts +0 -40
  120. package/dist/arc-agi/soul.js +0 -90
  121. package/dist/arc-agi/store.d.ts +0 -154
  122. package/dist/arc-agi/store.js +0 -216
  123. package/dist/arc-agi/tools.d.ts +0 -36
  124. package/dist/arc-agi/tools.js +0 -576
  125. package/dist/arc-agi/types.d.ts +0 -212
  126. package/dist/arc-agi/types.js +0 -19
  127. package/dist/claude-code/recipe.d.ts +0 -53
  128. package/dist/claude-code/recipe.js +0 -100
  129. package/dist/computer/read.d.ts +0 -137
  130. package/dist/computer/read.js +0 -203
  131. package/dist/recall/index.d.ts +0 -99
  132. package/dist/recall/index.js +0 -171
  133. package/dist/triage/index.d.ts +0 -355
  134. package/dist/triage/index.js +0 -302
@@ -21,8 +21,8 @@ interface RefreshOutcome {
21
21
  /**
22
22
  * What this module needs back from a git command.
23
23
  *
24
- * A structural subset of `index.ts`'s `RunResult` rather than an import of it,
25
- * so the dependency runs one way: `index.ts` knows about this file, and this file
24
+ * A structural subset of `context.ts`'s `RunResult` rather than an import of it,
25
+ * so the dependency runs one way: the tools know about this file, and this file
26
26
  * knows only about the shape of an answer. `unreachable` is the field that earns
27
27
  * the type — a command that *ran and failed* has answered the question it was
28
28
  * asked, and one that never ran has answered nothing, which two refusals below
@@ -34,7 +34,7 @@ export interface GitAnswer {
34
34
  stderr: string;
35
35
  unreachable?: true;
36
36
  }
37
- /** The two runners `refreshCheckout` borrows from `repoSurface`. */
37
+ /** The two runners `refreshCheckout` borrows from `repoContext`. */
38
38
  export interface GitRunners {
39
39
  plain: (args: string, cwd: string, vars?: Record<string, string>) => Promise<GitAnswer>;
40
40
  /**
@@ -64,23 +64,52 @@ export declare function resolveDefaultBranch(plain: GitRunners["plain"], dir: st
64
64
  branch?: string;
65
65
  unreachable?: string;
66
66
  }>;
67
+ /**
68
+ * Write the identity this checkout's commits carry into its own config.
69
+ *
70
+ * **Repo-local, and repeated on every clone and every refresh.** The workspace
71
+ * outlives the deployment's configuration: written once, at the clone, it is
72
+ * frozen — change the configured name and every checkout that already exists
73
+ * goes on committing under the old one, with nothing in the tree saying why.
74
+ * Rewriting costs two commands against a checkout that is being set up anyway.
75
+ *
76
+ * It is the *nearest* answer, not the only one. `repo_commit` names the identity
77
+ * on the commit itself, which is the one layer a stale config cannot outrank.
78
+ * Underneath, a repository this plugin never cloned falls back to whatever the
79
+ * shell's own git is configured with — which is an identity rather than nothing
80
+ * only where `exec` is backed by `/workspace`, whose object writes one per
81
+ * container; see {@link file://../workspace/git-identity.ts}. `exec` is an arbitrary
82
+ * runner, so that is a property of a deployment, not of this plugin.
83
+ *
84
+ * Unchecked, like the config pins at the clone: git's identity is needed by the
85
+ * first commit, and a failure to write it fails that commit with a sentence far
86
+ * clearer than anything this could report from here.
87
+ */
88
+ export declare function writeGitIdentity(plain: GitRunners["plain"], dir: string, author: {
89
+ name: string;
90
+ email: string;
91
+ }): Promise<void>;
67
92
  /**
68
93
  * Bring an existing checkout back to a clean, current state.
69
94
  *
70
95
  * The workspace outlives the task, so a clone target may already hold one —
71
96
  * where `git clone` fails with "destination path already exists and is not an
72
- * empty directory" and the round has to improvise from an error that reads like
97
+ * empty directory" and the model has to improvise from an error that reads like
73
98
  * a bug.
74
99
  *
75
100
  * The refusal on a dirty tree is the important half. Uncommitted changes there
76
101
  * are a *previous task's work* — possibly the thing a human is waiting on — and
77
102
  * silently `reset --hard`ing them away to make a fresh clone look clean is the
78
- * one outcome nobody could recover from. Refusing costs a round; discarding
103
+ * one outcome nobody could recover from. Refusing costs a tool call; discarding
79
104
  * costs the work.
80
105
  */
81
- export declare function refreshCheckout({ dir, url, branch, plain, fetchOrigin }: GitRunners & {
106
+ export declare function refreshCheckout({ dir, url, branch, author, plain, fetchOrigin }: GitRunners & {
82
107
  dir: string;
83
108
  url: string;
84
109
  branch: string | undefined;
110
+ author: {
111
+ name: string;
112
+ email: string;
113
+ };
85
114
  }): Promise<RefreshOutcome>;
86
115
  export {};
@@ -21,21 +21,50 @@ export async function resolveDefaultBranch(plain, dir) {
21
21
  ? { branch: head.stdout.trim().replace(/^origin\//, "") }
22
22
  : {};
23
23
  }
24
+ /**
25
+ * Write the identity this checkout's commits carry into its own config.
26
+ *
27
+ * **Repo-local, and repeated on every clone and every refresh.** The workspace
28
+ * outlives the deployment's configuration: written once, at the clone, it is
29
+ * frozen — change the configured name and every checkout that already exists
30
+ * goes on committing under the old one, with nothing in the tree saying why.
31
+ * Rewriting costs two commands against a checkout that is being set up anyway.
32
+ *
33
+ * It is the *nearest* answer, not the only one. `repo_commit` names the identity
34
+ * on the commit itself, which is the one layer a stale config cannot outrank.
35
+ * Underneath, a repository this plugin never cloned falls back to whatever the
36
+ * shell's own git is configured with — which is an identity rather than nothing
37
+ * only where `exec` is backed by `/workspace`, whose object writes one per
38
+ * container; see {@link file://../workspace/git-identity.ts}. `exec` is an arbitrary
39
+ * runner, so that is a property of a deployment, not of this plugin.
40
+ *
41
+ * Unchecked, like the config pins at the clone: git's identity is needed by the
42
+ * first commit, and a failure to write it fails that commit with a sentence far
43
+ * clearer than anything this could report from here.
44
+ */
45
+ export async function writeGitIdentity(plain, dir, author) {
46
+ // Through the environment, so a configured name containing a quote stays a
47
+ // value rather than becoming shell.
48
+ await plain(`config user.name "$GIT_NAME"`, dir, { GIT_NAME: author.name });
49
+ await plain(`config user.email "$GIT_EMAIL"`, dir, {
50
+ GIT_EMAIL: author.email
51
+ });
52
+ }
24
53
  /**
25
54
  * Bring an existing checkout back to a clean, current state.
26
55
  *
27
56
  * The workspace outlives the task, so a clone target may already hold one —
28
57
  * where `git clone` fails with "destination path already exists and is not an
29
- * empty directory" and the round has to improvise from an error that reads like
58
+ * empty directory" and the model has to improvise from an error that reads like
30
59
  * a bug.
31
60
  *
32
61
  * The refusal on a dirty tree is the important half. Uncommitted changes there
33
62
  * are a *previous task's work* — possibly the thing a human is waiting on — and
34
63
  * silently `reset --hard`ing them away to make a fresh clone look clean is the
35
- * one outcome nobody could recover from. Refusing costs a round; discarding
64
+ * one outcome nobody could recover from. Refusing costs a tool call; discarding
36
65
  * costs the work.
37
66
  */
38
- export async function refreshCheckout({ dir, url, branch, plain, fetchOrigin }) {
67
+ export async function refreshCheckout({ dir, url, branch, author, plain, fetchOrigin }) {
39
68
  const remote = await plain("remote get-url origin", dir);
40
69
  // Interrogated, for the same reason the `status` below is: a question that went
41
70
  // unanswered is not the answer "some other repository". Read as one, an
@@ -59,12 +88,24 @@ export async function refreshCheckout({ dir, url, branch, plain, fetchOrigin })
59
88
  `not ${url}. Pick a different directory or work with the checkout that is there.`
60
89
  };
61
90
  }
91
+ // Ahead of every refusal below, and deliberately: a refusal leaves the *tree*
92
+ // untouched, which is what those sentences promise. An identity is not tree
93
+ // state, and a dirty tree is the case where somebody is about to commit —
94
+ // exactly when a stale name would be spent.
95
+ await writeGitIdentity(plain, dir, author);
62
96
  // Interrogated, not assumed. Empty stdout from a `status` that *failed* is not
63
97
  // a clean tree, it is no answer at all — and the next two commands are `fetch`
64
98
  // and `reset --hard`. Conflating the two lets a permissions error or a
65
99
  // half-written index discard a tree nobody established was clean, which is the
66
100
  // one loss in this file that cannot be undone.
67
- const dirty = await plain("status --porcelain", dir);
101
+ //
102
+ // Submodules are left out of the question. Neither `checkout` nor
103
+ // `reset --hard` below touches a submodule's tree without
104
+ // `--recurse-submodules`, so a submodule that has moved past its pin — which
105
+ // is what a superproject looks like after its own sync — is not work this
106
+ // refresh could lose. Counted as dirty, it would refuse every refresh of such
107
+ // a checkout, and a host's `afterCheckout` would never learn it is there.
108
+ const dirty = await plain("status --porcelain --ignore-submodules=all", dir);
68
109
  if (!dirty.success) {
69
110
  return {
70
111
  message: `could not read the state of the checkout at ${dir}: ` +
@@ -86,9 +127,26 @@ export async function refreshCheckout({ dir, url, branch, plain, fetchOrigin })
86
127
  `Nothing was fetched or reset.`
87
128
  };
88
129
  }
130
+ /**
131
+ * A failed fetch leaves a checkout that is still there, still clean and still
132
+ * on its branch — only not updated. So it is still reported, on the branch it
133
+ * is on: a host that records checkouts would otherwise lose sight of one that
134
+ * exists because its remote could not be reached, and a clone taken from the
135
+ * recorded url goes to the remote itself. Nothing below — no checkout, no
136
+ * reset — runs against a tree whose remote state is unknown.
137
+ */
89
138
  const fetched = await fetchOrigin(dir, url);
90
- if (!fetched.success)
91
- return { message: `fetch failed: ${fetched.stderr || fetched.stdout}` };
139
+ if (!fetched.success) {
140
+ const failure = `fetch failed: ${fetched.stderr || fetched.stdout}`;
141
+ const current = await plain("symbolic-ref --quiet --short HEAD", dir);
142
+ const on = current.success ? current.stdout.trim() : "";
143
+ if (!on)
144
+ return { message: failure };
145
+ return {
146
+ message: `${failure}\nThe checkout was left on ${on}, clean but not updated from the remote.`,
147
+ branch: on
148
+ };
149
+ }
92
150
  // The branch to land on: the one asked for, else the remote's own default.
93
151
  let target = branch;
94
152
  if (!target) {
@@ -0,0 +1,135 @@
1
+ import type { ActionContext } from "@cloudflare/think";
2
+ import type { RepoCheckout, RepoConfig, RepoExec, RepoGitResult } from "./index.js";
3
+ /**
4
+ * How many items one GitHub list call asks for. GitHub's maximum, and its default
5
+ * without this is 30.
6
+ *
7
+ * One page, never a Link-header walk: an unbounded fetch loop does not belong
8
+ * inside a model turn, and the render is bounded by `maxOutputChars` anyway. What
9
+ * matters is that a full page is *reported* as possibly partial rather than
10
+ * presented as the whole answer — a pull request's newest review comments are on
11
+ * the last page, and those are exactly the ones an agent was sent to act on.
12
+ */
13
+ export declare const GITHUB_PAGE_SIZE = 100;
14
+ /**
15
+ * Where GraphQL lives, given where REST does.
16
+ *
17
+ * On github.com they share an origin and `/graphql` hangs off it. On GitHub
18
+ * Enterprise — which {@link RepoConfig.apiBase} exists for — REST is under
19
+ * `/api/v3` and GraphQL is its **sibling** at `/api/graphql`, not a path beneath
20
+ * it. Appending blindly yields `/api/v3/graphql`, which is a 404 on every
21
+ * Enterprise install and no failure at all on the public API, so the mistake
22
+ * survives every test written against github.com.
23
+ */
24
+ export declare function graphqlEndpoint(apiBase: string): string;
25
+ /**
26
+ * Middle-out truncation, so both the head of a diff and its tail survive.
27
+ *
28
+ * Deliberately a **copy** of `/workspace`'s function of the same name, not an
29
+ * import. `npm run verify:exports` fails any subpath whose module graph
30
+ * reaches a sibling's directory, and its own advice for a shared helper is to
31
+ * duplicate it — installing `repo` must not drag `/workspace` (and therefore
32
+ * `@cloudflare/computer`) into a consumer's bundle. Fifteen lines is a cheaper
33
+ * price than that coupling, and it is the same reason `exec` is injected here
34
+ * rather than imported.
35
+ *
36
+ * The `half < 1` guard is not padding: without it a small `max` makes `half`
37
+ * zero or negative, and `slice(-0)` is `slice(0)` — the whole string — so the
38
+ * function would return *more* than it was given.
39
+ */
40
+ export declare function truncateOutput(text: string, max: number): string;
41
+ /**
42
+ * What one container command produced — plus one bit the container did not.
43
+ *
44
+ * `exec` does not only *return* failures, it throws them: `@cloudflare/computer`
45
+ * throws `EEXEC_LOST` when a container is replaced mid-command, and any call to a
46
+ * Durable Object can fail outright. Both are caught at the seam
47
+ * ({@link repoContext}'s `run`) and turned into a failed result, so every tool
48
+ * answers in its own `!success` branch — "could not read the status of /w/r: …"
49
+ * is a better sentence than any wrapper one level up could write, and a seventh
50
+ * tool calling `plain` gets it without being told.
51
+ *
52
+ * `unreachable` is for the branches that must tell the two apart. A command that
53
+ * ran and failed has answered the question it was asked; a command that never ran
54
+ * has answered nothing, and three places here read a failure as an answer.
55
+ */
56
+ export type RunResult = Awaited<ReturnType<RepoExec>> & {
57
+ unreachable?: true;
58
+ };
59
+ /** What {@link repoContext} hands each group of tools. */
60
+ export interface RepoContext {
61
+ config: RepoConfig;
62
+ workdir: string;
63
+ author: {
64
+ name: string;
65
+ email: string;
66
+ };
67
+ allowedHosts: string[];
68
+ bounded: (text: string) => string;
69
+ notifyCheckout: (checkout: RepoCheckout) => Promise<void>;
70
+ logFailure: (tool: string, detail: {
71
+ exitCode?: number;
72
+ stderr?: string;
73
+ stdout?: string;
74
+ }) => void;
75
+ plain: (args: string, cwd: string, vars?: Record<string, string>) => Promise<RunResult>;
76
+ runGit: (op: () => Promise<RepoGitResult>) => Promise<RunResult>;
77
+ fetchOrigin: (dir: string, url: string) => Promise<RunResult>;
78
+ pushBranch: (dir: string, url: string, branch: string) => Promise<RunResult>;
79
+ origin: (dir: string) => Promise<{
80
+ remote?: {
81
+ host: string;
82
+ url: string;
83
+ };
84
+ unreachable?: string;
85
+ }>;
86
+ github: (tool: string, path: string, init?: {
87
+ method: string;
88
+ body: unknown;
89
+ }) => Promise<{
90
+ ok: true;
91
+ data: unknown;
92
+ } | {
93
+ ok: false;
94
+ message: string;
95
+ }>;
96
+ githubGraphql: (tool: string, query: string, variables: Record<string, unknown>) => Promise<{
97
+ ok: true;
98
+ data: unknown;
99
+ } | {
100
+ ok: false;
101
+ message: string;
102
+ }>;
103
+ githubRepo: (dir: string) => Promise<{
104
+ owner: string;
105
+ repo: string;
106
+ } | {
107
+ refusal: string;
108
+ }>;
109
+ }
110
+ /**
111
+ * How long an action that calls GitHub may run before Think gives up on it.
112
+ *
113
+ * An action's default is thirty seconds, which is {@link GITHUB_TIMEOUT_MS}
114
+ * alone — and a thread reply is three GitHub calls, after an `origin` read that
115
+ * waits its turn in the git queue.
116
+ */
117
+ export declare const GITHUB_ACTION_TIMEOUT_MS = 120000;
118
+ /**
119
+ * The task an action runs for, which leads its idempotency key.
120
+ *
121
+ * Think replays a settled key for as long as it keeps the row
122
+ * (`actionLedgerRetention`), so a key without the task would replay, not post,
123
+ * the same comment in a later task. Every turn core runs carries a task id, so
124
+ * a missing one is a wiring fault — and keying without it would be the silent
125
+ * version of that fault.
126
+ */
127
+ export declare function actionTask(ctx: ActionContext): string;
128
+ /** A hex SHA-256, so a key names a body without carrying it. */
129
+ export declare function sha256(text: string): Promise<string>;
130
+ export declare function repoContext(config: RepoConfig,
131
+ /**
132
+ * The running sub-agent's `runtime()`, read per command. Forwarded to every
133
+ * `exec`; see {@link RepoExec}'s `runtime` option.
134
+ */
135
+ runtime?: () => unknown): RepoContext;