codebase-cli 2.0.0-pre.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 (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +266 -0
  3. package/bin/codebase +2 -0
  4. package/dist/agent/agent.js +198 -0
  5. package/dist/agent/agent.js.map +1 -0
  6. package/dist/agent/config.js +117 -0
  7. package/dist/agent/config.js.map +1 -0
  8. package/dist/agent/events.js +153 -0
  9. package/dist/agent/events.js.map +1 -0
  10. package/dist/agent/router.js +35 -0
  11. package/dist/agent/router.js.map +1 -0
  12. package/dist/agent/system-prompt.js +21 -0
  13. package/dist/agent/system-prompt.js.map +1 -0
  14. package/dist/auth/cli.js +138 -0
  15. package/dist/auth/cli.js.map +1 -0
  16. package/dist/auth/credentials.js +105 -0
  17. package/dist/auth/credentials.js.map +1 -0
  18. package/dist/auth/flow.js +222 -0
  19. package/dist/auth/flow.js.map +1 -0
  20. package/dist/auth/pkce.js +46 -0
  21. package/dist/auth/pkce.js.map +1 -0
  22. package/dist/cli.js +69 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/clipboard/copy.js +106 -0
  25. package/dist/clipboard/copy.js.map +1 -0
  26. package/dist/commands/builtins.js +203 -0
  27. package/dist/commands/builtins.js.map +1 -0
  28. package/dist/commands/registry.js +65 -0
  29. package/dist/commands/registry.js.map +1 -0
  30. package/dist/commands/types.js +2 -0
  31. package/dist/commands/types.js.map +1 -0
  32. package/dist/compaction/engine.js +209 -0
  33. package/dist/compaction/engine.js.map +1 -0
  34. package/dist/compaction/tokens.js +79 -0
  35. package/dist/compaction/tokens.js.map +1 -0
  36. package/dist/compaction/types.js +2 -0
  37. package/dist/compaction/types.js.map +1 -0
  38. package/dist/diagnostics/checkers.js +211 -0
  39. package/dist/diagnostics/checkers.js.map +1 -0
  40. package/dist/diagnostics/engine.js +71 -0
  41. package/dist/diagnostics/engine.js.map +1 -0
  42. package/dist/diagnostics/types.js +2 -0
  43. package/dist/diagnostics/types.js.map +1 -0
  44. package/dist/dotenv/loader.js +115 -0
  45. package/dist/dotenv/loader.js.map +1 -0
  46. package/dist/glue/client.js +47 -0
  47. package/dist/glue/client.js.map +1 -0
  48. package/dist/glue/intent.js +78 -0
  49. package/dist/glue/intent.js.map +1 -0
  50. package/dist/glue/narration.js +55 -0
  51. package/dist/glue/narration.js.map +1 -0
  52. package/dist/headless/run.js +89 -0
  53. package/dist/headless/run.js.map +1 -0
  54. package/dist/hooks/manager.js +158 -0
  55. package/dist/hooks/manager.js.map +1 -0
  56. package/dist/hooks/runner.js +70 -0
  57. package/dist/hooks/runner.js.map +1 -0
  58. package/dist/hooks/types.js +2 -0
  59. package/dist/hooks/types.js.map +1 -0
  60. package/dist/memory/inject.js +12 -0
  61. package/dist/memory/inject.js.map +1 -0
  62. package/dist/memory/store.js +178 -0
  63. package/dist/memory/store.js.map +1 -0
  64. package/dist/memory/types.js +10 -0
  65. package/dist/memory/types.js.map +1 -0
  66. package/dist/permissions/store.js +172 -0
  67. package/dist/permissions/store.js.map +1 -0
  68. package/dist/plan/flow.js +214 -0
  69. package/dist/plan/flow.js.map +1 -0
  70. package/dist/plan/prompts.js +69 -0
  71. package/dist/plan/prompts.js.map +1 -0
  72. package/dist/plan/store.js +37 -0
  73. package/dist/plan/store.js.map +1 -0
  74. package/dist/plan/types.js +3 -0
  75. package/dist/plan/types.js.map +1 -0
  76. package/dist/sessions/store.js +105 -0
  77. package/dist/sessions/store.js.map +1 -0
  78. package/dist/skills/loader.js +41 -0
  79. package/dist/skills/loader.js.map +1 -0
  80. package/dist/skills/platform-loader.js +63 -0
  81. package/dist/skills/platform-loader.js.map +1 -0
  82. package/dist/skills/types.js +21 -0
  83. package/dist/skills/types.js.map +1 -0
  84. package/dist/tools/ask-user.js +61 -0
  85. package/dist/tools/ask-user.js.map +1 -0
  86. package/dist/tools/dispatch-agent.js +178 -0
  87. package/dist/tools/dispatch-agent.js.map +1 -0
  88. package/dist/tools/edit-file.js +80 -0
  89. package/dist/tools/edit-file.js.map +1 -0
  90. package/dist/tools/errors.js +89 -0
  91. package/dist/tools/errors.js.map +1 -0
  92. package/dist/tools/file-ops.js +136 -0
  93. package/dist/tools/file-ops.js.map +1 -0
  94. package/dist/tools/file-state-cache.js +92 -0
  95. package/dist/tools/file-state-cache.js.map +1 -0
  96. package/dist/tools/git/branch.js +84 -0
  97. package/dist/tools/git/branch.js.map +1 -0
  98. package/dist/tools/git/commit.js +83 -0
  99. package/dist/tools/git/commit.js.map +1 -0
  100. package/dist/tools/git/diff.js +72 -0
  101. package/dist/tools/git/diff.js.map +1 -0
  102. package/dist/tools/git/git-helpers.js +58 -0
  103. package/dist/tools/git/git-helpers.js.map +1 -0
  104. package/dist/tools/git/log.js +70 -0
  105. package/dist/tools/git/log.js.map +1 -0
  106. package/dist/tools/git/status.js +97 -0
  107. package/dist/tools/git/status.js.map +1 -0
  108. package/dist/tools/git/worktree.js +132 -0
  109. package/dist/tools/git/worktree.js.map +1 -0
  110. package/dist/tools/glob.js +128 -0
  111. package/dist/tools/glob.js.map +1 -0
  112. package/dist/tools/grep.js +199 -0
  113. package/dist/tools/grep.js.map +1 -0
  114. package/dist/tools/list-files.js +120 -0
  115. package/dist/tools/list-files.js.map +1 -0
  116. package/dist/tools/memory-tools.js +127 -0
  117. package/dist/tools/memory-tools.js.map +1 -0
  118. package/dist/tools/multi-edit.js +87 -0
  119. package/dist/tools/multi-edit.js.map +1 -0
  120. package/dist/tools/notebook-edit.js +147 -0
  121. package/dist/tools/notebook-edit.js.map +1 -0
  122. package/dist/tools/permission.js +168 -0
  123. package/dist/tools/permission.js.map +1 -0
  124. package/dist/tools/plan-mode.js +76 -0
  125. package/dist/tools/plan-mode.js.map +1 -0
  126. package/dist/tools/read-file.js +135 -0
  127. package/dist/tools/read-file.js.map +1 -0
  128. package/dist/tools/registry.js +52 -0
  129. package/dist/tools/registry.js.map +1 -0
  130. package/dist/tools/shell.js +216 -0
  131. package/dist/tools/shell.js.map +1 -0
  132. package/dist/tools/task-store.js +70 -0
  133. package/dist/tools/task-store.js.map +1 -0
  134. package/dist/tools/tasks.js +131 -0
  135. package/dist/tools/tasks.js.map +1 -0
  136. package/dist/tools/types.js +2 -0
  137. package/dist/tools/types.js.map +1 -0
  138. package/dist/tools/web-fetch.js +152 -0
  139. package/dist/tools/web-fetch.js.map +1 -0
  140. package/dist/tools/web-search.js +169 -0
  141. package/dist/tools/web-search.js.map +1 -0
  142. package/dist/tools/write-file.js +70 -0
  143. package/dist/tools/write-file.js.map +1 -0
  144. package/dist/types.js +9 -0
  145. package/dist/types.js.map +1 -0
  146. package/dist/ui/App.js +216 -0
  147. package/dist/ui/App.js.map +1 -0
  148. package/dist/ui/Input.js +90 -0
  149. package/dist/ui/Input.js.map +1 -0
  150. package/dist/ui/Message.js +89 -0
  151. package/dist/ui/Message.js.map +1 -0
  152. package/dist/ui/MessageList.js +35 -0
  153. package/dist/ui/MessageList.js.map +1 -0
  154. package/dist/ui/Permission.js +39 -0
  155. package/dist/ui/Permission.js.map +1 -0
  156. package/dist/ui/Status.js +34 -0
  157. package/dist/ui/Status.js.map +1 -0
  158. package/dist/ui/TaskPanel.js +43 -0
  159. package/dist/ui/TaskPanel.js.map +1 -0
  160. package/dist/ui/Throbber.js +20 -0
  161. package/dist/ui/Throbber.js.map +1 -0
  162. package/dist/ui/ToolPanel.js +83 -0
  163. package/dist/ui/ToolPanel.js.map +1 -0
  164. package/dist/ui/UserQuery.js +38 -0
  165. package/dist/ui/UserQuery.js.map +1 -0
  166. package/dist/ui/input-state.js +210 -0
  167. package/dist/ui/input-state.js.map +1 -0
  168. package/dist/ui/wrap.js +30 -0
  169. package/dist/ui/wrap.js.map +1 -0
  170. package/dist/user-queries/store.js +60 -0
  171. package/dist/user-queries/store.js.map +1 -0
  172. package/package.json +76 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Merge results from N loaders. Override semantics:
3
+ * platform > bundled > user (later loaders win)
4
+ *
5
+ * Why this order: platform-shipped assets are curated by the team
6
+ * that maintains the CLI; bundled comes with the binary; user is
7
+ * the local override. If the user wants to shadow a platform skill,
8
+ * they can ship a local file with the same id — the user version
9
+ * loses by default, but a future config switch can flip the priority.
10
+ */
11
+ export class AssetRegistry {
12
+ loaders = [];
13
+ register(loader) {
14
+ this.loaders.push(loader);
15
+ }
16
+ async listAll() {
17
+ const merged = new Map();
18
+ for (const loader of this.loaders) {
19
+ const skills = await loader.listSkills();
20
+ const templates = await loader.listTemplates();
21
+ const prompts = await loader.listPrompts();
22
+ for (const asset of [...skills, ...templates, ...prompts]) {
23
+ merged.set(`${asset.kind}:${asset.id}`, asset);
24
+ }
25
+ }
26
+ return Array.from(merged.values());
27
+ }
28
+ async listSkills() {
29
+ const all = await this.listAll();
30
+ return all.filter((a) => a.kind === "skill");
31
+ }
32
+ async listTemplates() {
33
+ const all = await this.listAll();
34
+ return all.filter((a) => a.kind === "template");
35
+ }
36
+ async listPrompts() {
37
+ const all = await this.listAll();
38
+ return all.filter((a) => a.kind === "prompt");
39
+ }
40
+ }
41
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"AAmBA;;;;;;;;;GASG;AACH,MAAM,OAAO,aAAa;IACR,OAAO,GAAkB,EAAE,CAAC;IAE7C,QAAQ,CAAC,MAAmB;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;QACxC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;YAC/C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAC3C,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;gBAC3D,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;YAChD,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,UAAU;QACf,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAmB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,aAAa;QAClB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAsB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,WAAW;QAChB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IACjE,CAAC;CACD"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Loader that fetches the user's curated skills, templates, and
3
+ * prompts from their codebase.foundation account.
4
+ *
5
+ * NOT YET IMPLEMENTED. This file exists as a contract anchor so the
6
+ * AssetRegistry already knows about the platform path: when the
7
+ * Phase 7+ implementation lands, it slots in here without further
8
+ * surgery to the agent or App layer.
9
+ *
10
+ * Wire format (planned):
11
+ *
12
+ * GET https://codebase.foundation/api/cli/skills
13
+ * Authorization: Bearer <accessToken>
14
+ *
15
+ * 200 OK
16
+ * { "skills": [ { id, name, description, systemPrompt, tags?, preferredModel? }, … ],
17
+ * "templates": [ { id, name, description, body, files?, tags? }, … ],
18
+ * "prompts": [ { id, name, description, body, tags? }, … ] }
19
+ *
20
+ * Cache the response under ~/.codebase/cache/platform-assets.json with
21
+ * an ETag header so subsequent CLI launches don't pay the round trip.
22
+ * Refresh on `codebase auth refresh` or after 1 hour, whichever is
23
+ * sooner. Refresh failures fall back to the cached response — never
24
+ * leave a session stranded because the platform is briefly down.
25
+ *
26
+ * Not authenticated → returns empty lists, never throws. The user just
27
+ * sees their bundled + local assets, which is the correct
28
+ * unauthenticated UX.
29
+ */
30
+ export class PlatformLoader {
31
+ credentials;
32
+ baseUrl;
33
+ source = "platform";
34
+ constructor(credentials, baseUrl = "https://codebase.foundation/api/cli") {
35
+ this.credentials = credentials;
36
+ this.baseUrl = baseUrl;
37
+ }
38
+ async listSkills() {
39
+ void this.fetchOrEmpty;
40
+ return [];
41
+ }
42
+ async listTemplates() {
43
+ return [];
44
+ }
45
+ async listPrompts() {
46
+ return [];
47
+ }
48
+ /**
49
+ * Placeholder for the real fetch path. Implementation steps:
50
+ * 1. Read credentials; if absent or expired, return null.
51
+ * 2. GET ${baseUrl}/skills with Authorization: Bearer …
52
+ * 3. On 401, trigger refresh via OAuthFlow.refreshAccessToken.
53
+ * 4. On success, cache under ~/.codebase/cache/platform-assets.json.
54
+ * 5. On any failure post-401-retry, return cached response if any
55
+ * and log a one-line warning.
56
+ */
57
+ async fetchOrEmpty() {
58
+ void this.credentials;
59
+ void this.baseUrl;
60
+ return null;
61
+ }
62
+ }
63
+ //# sourceMappingURL=platform-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-loader.js","sourceRoot":"","sources":["../../src/skills/platform-loader.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAO,cAAc;IAIR;IACA;IAJT,MAAM,GAAG,UAAmB,CAAC;IAEtC,YACkB,WAA6B,EAC7B,UAAkB,qCAAqC;QADvD,gBAAW,GAAX,WAAW,CAAkB;QAC7B,YAAO,GAAP,OAAO,CAAgD;IACtE,CAAC;IAEJ,KAAK,CAAC,UAAU;QACf,KAAK,IAAI,CAAC,YAAY,CAAC;QACvB,OAAO,EAAE,CAAC;IACX,CAAC;IAED,KAAK,CAAC,aAAa;QAClB,OAAO,EAAE,CAAC;IACX,CAAC;IAED,KAAK,CAAC,WAAW;QAChB,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,YAAY;QACzB,KAAK,IAAI,CAAC,WAAW,CAAC;QACtB,KAAK,IAAI,CAAC,OAAO,CAAC;QAClB,OAAO,IAAI,CAAC;IACb,CAAC;CACD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * User-curated assets that augment a codebase-cli session. Three
3
+ * shapes share the same "named, described, named-by-id" pattern but
4
+ * play different roles:
5
+ *
6
+ * - Skill — slash-invocable prompt prefix. `/optimize` expands
7
+ * to the skill's systemPrompt before the agent runs.
8
+ * - Template — multi-file scaffold for new projects/components.
9
+ * "Spin up a Next.js app with auth wired" — the
10
+ * template emits the file tree, the agent customizes.
11
+ * - Prompt — a saved prompt snippet the user reuses ad hoc.
12
+ *
13
+ * Each asset has a `source` so the UI can show provenance (bundled
14
+ * with the CLI, in your local ~/.codebase/, or pulled from your
15
+ * codebase.foundation account when you're OAuth'd in). Same id +
16
+ * different source means platform overrides bundled overrides local
17
+ * — surprising but matches how npm scopes work and gives users a way
18
+ * to opt out of a platform-shipped skill by overriding it locally.
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/skills/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
@@ -0,0 +1,61 @@
1
+ import { Type } from "typebox";
2
+ const Params = Type.Object({
3
+ question: Type.String({
4
+ minLength: 1,
5
+ maxLength: 1000,
6
+ description: "Question to ask the user. Be specific — the user types a free-form answer.",
7
+ }),
8
+ options: Type.Optional(Type.Array(Type.String(), {
9
+ minItems: 2,
10
+ maxItems: 8,
11
+ description: "Optional list of choices. The user can type the option text, the option number (1-based), or anything else as a free-form answer.",
12
+ })),
13
+ placeholder: Type.Optional(Type.String({
14
+ description: "Hint shown in the input row, e.g. 'y/n' or 'tag name'.",
15
+ })),
16
+ });
17
+ const DESCRIPTION = `Ask the user a question and wait for a typed answer.
18
+
19
+ When to use:
20
+ - Genuine ambiguity that affects the next step ("which deploy target?"). Don't use it for things you can figure out from the code.
21
+ - Confirming destructive operations beyond what the permission gate already covers (rare).
22
+ - Multiple-choice selection: pass options[] and the UI will offer 1/2/3-style shortcuts.
23
+
24
+ Behavior:
25
+ - The agent loop blocks until the user types something and submits.
26
+ - If options are supplied and the user types a 1-based number that matches one, the matched option text is returned in matchedOption; the original typed text is in answer.
27
+ - Aborting the agent (Ctrl-C) cancels the question and the tool errors out so the agent can decide what to do next.`;
28
+ export function createAskUser(ctx) {
29
+ return {
30
+ name: "ask_user",
31
+ label: "Ask",
32
+ description: DESCRIPTION,
33
+ parameters: Params,
34
+ executionMode: "sequential",
35
+ execute: async (_id, params) => {
36
+ const answer = await ctx.userQueries.ask({
37
+ question: params.question,
38
+ options: params.options,
39
+ placeholder: params.placeholder,
40
+ });
41
+ let matchedOption = null;
42
+ if (params.options && params.options.length > 0) {
43
+ const trimmed = answer.trim();
44
+ const idx = Number.parseInt(trimmed, 10);
45
+ if (Number.isFinite(idx) && idx >= 1 && idx <= params.options.length) {
46
+ matchedOption = params.options[idx - 1];
47
+ }
48
+ else {
49
+ const exact = params.options.find((o) => o.toLowerCase() === trimmed.toLowerCase());
50
+ if (exact)
51
+ matchedOption = exact;
52
+ }
53
+ }
54
+ return {
55
+ content: [{ type: "text", text: matchedOption ? `${matchedOption} (typed: ${answer})` : answer }],
56
+ details: { question: params.question, answer, matchedOption },
57
+ };
58
+ },
59
+ };
60
+ }
61
+ //# sourceMappingURL=ask-user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-user.js","sourceRoot":"","sources":["../../src/tools/ask-user.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC1B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC;QACrB,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,4EAA4E;KACzF,CAAC;IACF,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;QACzB,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,CAAC;QACX,WAAW,EACV,mIAAmI;KACpI,CAAC,CACF;IACD,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EAAE,wDAAwD;KACrE,CAAC,CACF;CACD,CAAC,CAAC;AAUH,MAAM,WAAW,GAAG;;;;;;;;;;oHAUgG,CAAC;AAErH,MAAM,UAAU,aAAa,CAAC,GAAgB;IAC7C,OAAO;QACN,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE,WAAW;QACxB,UAAU,EAAE,MAAM;QAClB,aAAa,EAAE,YAAY;QAC3B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;YAC9B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC;gBACxC,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,WAAW,EAAE,MAAM,CAAC,WAAW;aAC/B,CAAC,CAAC;YAEH,IAAI,aAAa,GAAkB,IAAI,CAAC;YACxC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACzC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;oBACtE,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;gBACzC,CAAC;qBAAM,CAAC;oBACP,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;oBACpF,IAAI,KAAK;wBAAE,aAAa,GAAG,KAAK,CAAC;gBAClC,CAAC;YACF,CAAC;YAED,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,YAAY,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;gBACjG,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE;aAC7D,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,178 @@
1
+ import { Type } from "typebox";
2
+ import { createGitDiff } from "./git/diff.js";
3
+ import { createGitLog } from "./git/log.js";
4
+ import { createGitStatus } from "./git/status.js";
5
+ import { createGlob } from "./glob.js";
6
+ import { createGrep } from "./grep.js";
7
+ import { createListFiles } from "./list-files.js";
8
+ import { createReadFile } from "./read-file.js";
9
+ import { createGetTask, createListTasks } from "./tasks.js";
10
+ import { createWebFetch } from "./web-fetch.js";
11
+ import { createWebSearch } from "./web-search.js";
12
+ const Params = Type.Object({
13
+ task: Type.String({
14
+ minLength: 1,
15
+ maxLength: 4000,
16
+ description: "What you want the subagent to investigate. Be specific — the subagent gets read-only tools and a fixed budget, so vague tasks waste turns.",
17
+ }),
18
+ max_turns: Type.Optional(Type.Integer({
19
+ minimum: 1,
20
+ maximum: 50,
21
+ description: "Cap on subagent turns. Default 25.",
22
+ })),
23
+ });
24
+ const DEFAULT_MAX_TURNS = 25;
25
+ const DESCRIPTION = `Spawn a read-only subagent to investigate a specific question without polluting the main conversation.
26
+
27
+ When to use:
28
+ - "Find every place we call X and summarize the call patterns."
29
+ - "Read these 8 files and tell me which one matches my mental model best."
30
+ - Long tail searches where the noise of intermediate tool output isn't useful in the main transcript.
31
+
32
+ Behavior:
33
+ - Subagent has only read tools: read_file, list_files, glob, grep, web_search, web_fetch, git_status/diff/log, list_tasks, get_task. No writes, no shell, no recursion.
34
+ - Default budget is 25 turns; raise via max_turns up to 50.
35
+ - Returns the subagent's final text answer; tool calls happen invisibly.
36
+ - Aborts cleanly if the parent agent is aborted.
37
+
38
+ Don't use for tasks that need to write files or run commands — call those tools directly. Don't use for trivial single-shot reads — call read_file directly.`;
39
+ const EMPTY_USAGE = {
40
+ input: 0,
41
+ output: 0,
42
+ cacheRead: 0,
43
+ cacheWrite: 0,
44
+ totalTokens: 0,
45
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
46
+ };
47
+ export function createDispatchAgent(ctx) {
48
+ return {
49
+ name: "dispatch_agent",
50
+ label: "Subagent",
51
+ description: DESCRIPTION,
52
+ parameters: Params,
53
+ executionMode: "sequential",
54
+ execute: async (_toolCallId, params, parentSignal, onUpdate) => {
55
+ const maxTurns = params.max_turns ?? DEFAULT_MAX_TURNS;
56
+ let turns = 0;
57
+ let maxTurnsReached = false;
58
+ const toolsUsed = [];
59
+ let lastAssistantText = "";
60
+ let usage = EMPTY_USAGE;
61
+ const subagent = ctx.spawnSubagent({
62
+ systemPrompt: subagentSystemPrompt(params.task, ctx.cwd),
63
+ tools: buildSubagentTools(ctx),
64
+ });
65
+ const onParentAbort = () => subagent.abort();
66
+ parentSignal?.addEventListener("abort", onParentAbort);
67
+ const unsubscribe = subagent.subscribe((event) => {
68
+ if (event.type === "tool_execution_start") {
69
+ toolsUsed.push(event.toolName);
70
+ onUpdate?.({
71
+ content: [{ type: "text", text: `subagent → ${event.toolName}` }],
72
+ details: { task: params.task, turns, maxTurnsReached, toolsUsed, usage },
73
+ });
74
+ }
75
+ else if (event.type === "message_end" && event.message.role === "assistant") {
76
+ const text = extractAssistantText(event.message);
77
+ if (text)
78
+ lastAssistantText = text;
79
+ const eventUsage = event.message.usage;
80
+ if (eventUsage)
81
+ usage = mergeUsage(usage, eventUsage);
82
+ }
83
+ else if (event.type === "turn_end") {
84
+ turns++;
85
+ if (turns >= maxTurns) {
86
+ maxTurnsReached = true;
87
+ subagent.abort();
88
+ }
89
+ }
90
+ });
91
+ try {
92
+ await subagent.prompt(params.task);
93
+ }
94
+ catch (err) {
95
+ if (parentSignal?.aborted)
96
+ throw err;
97
+ if (!lastAssistantText) {
98
+ const reason = err instanceof Error ? err.message : String(err);
99
+ throw new Error(`subagent failed: ${reason}`);
100
+ }
101
+ // Fall through with whatever text we collected.
102
+ }
103
+ finally {
104
+ unsubscribe();
105
+ parentSignal?.removeEventListener("abort", onParentAbort);
106
+ }
107
+ const finalText = lastAssistantText || "(subagent completed without producing a summary)";
108
+ const summary = maxTurnsReached
109
+ ? `${finalText}\n\n[subagent stopped at ${turns} turns; raise max_turns if more depth is needed]`
110
+ : finalText;
111
+ return {
112
+ content: [{ type: "text", text: summary }],
113
+ details: { task: params.task, turns, maxTurnsReached, toolsUsed, usage },
114
+ };
115
+ },
116
+ };
117
+ }
118
+ function buildSubagentTools(ctx) {
119
+ return [
120
+ createReadFile(ctx),
121
+ createListFiles(ctx),
122
+ createGlob(ctx),
123
+ createGrep(ctx),
124
+ createWebFetch(ctx),
125
+ createWebSearch(ctx),
126
+ createGitStatus(ctx),
127
+ createGitDiff(ctx),
128
+ createGitLog(ctx),
129
+ createListTasks(ctx),
130
+ createGetTask(ctx),
131
+ ];
132
+ }
133
+ function subagentSystemPrompt(task, cwd) {
134
+ return [
135
+ "You are a focused research subagent for codebase, a CLI coding agent. You investigate one specific question and report back.",
136
+ "",
137
+ "Tools: read_file, list_files, glob, grep, web_search, web_fetch, git_status, git_diff, git_log, list_tasks, get_task. Read-only.",
138
+ "You CANNOT write files, run shell commands, or spawn further subagents. Don't try.",
139
+ "",
140
+ "Approach:",
141
+ "- Investigate efficiently. Cite file:line when answering questions about code.",
142
+ "- Stop when you've answered the task. Don't keep exploring tangents.",
143
+ "- Your final assistant message is what gets returned. Make it self-contained.",
144
+ "",
145
+ `Working directory: ${cwd}`,
146
+ "",
147
+ "Task:",
148
+ task,
149
+ ].join("\n");
150
+ }
151
+ function extractAssistantText(message) {
152
+ if (!message || typeof message !== "object" || !("content" in message))
153
+ return "";
154
+ const content = message.content;
155
+ if (!Array.isArray(content))
156
+ return "";
157
+ return content
158
+ .filter((b) => b.type === "text" && typeof b.text === "string")
159
+ .map((b) => b.text)
160
+ .join("");
161
+ }
162
+ function mergeUsage(a, b) {
163
+ return {
164
+ input: a.input + b.input,
165
+ output: a.output + b.output,
166
+ cacheRead: a.cacheRead + b.cacheRead,
167
+ cacheWrite: a.cacheWrite + b.cacheWrite,
168
+ totalTokens: a.totalTokens + b.totalTokens,
169
+ cost: {
170
+ input: a.cost.input + b.cost.input,
171
+ output: a.cost.output + b.cost.output,
172
+ cacheRead: a.cost.cacheRead + b.cost.cacheRead,
173
+ cacheWrite: a.cost.cacheWrite + b.cost.cacheWrite,
174
+ total: a.cost.total + b.cost.total,
175
+ },
176
+ };
177
+ }
178
+ //# sourceMappingURL=dispatch-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-agent.js","sourceRoot":"","sources":["../../src/tools/dispatch-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { statSync } from "node:fs";
2
+ import { Type } from "typebox";
3
+ import { applyEdit, atomicWrite, resolveInsideCwd, validateForOverwrite } from "./file-ops.js";
4
+ const Params = Type.Object({
5
+ path: Type.String({
6
+ description: "File path (absolute or relative to the project root). Must be read with read_file first.",
7
+ }),
8
+ old_string: Type.String({
9
+ description: "Exact text to replace. Must match including indentation, trailing spaces, and newline style.",
10
+ }),
11
+ new_string: Type.String({
12
+ description: "Replacement text. Will be written with the file's existing line ending and BOM preserved.",
13
+ }),
14
+ replace_all: Type.Optional(Type.Boolean({
15
+ description: "Replace every occurrence. Default false (errors on multiple matches).",
16
+ })),
17
+ });
18
+ const DESCRIPTION = `Replace exact text in a file. Single-match by default; set replace_all to substitute every occurrence.
19
+
20
+ Hard rules:
21
+ - The file must have been read with read_file in the current turn. Otherwise this errors with "not read first".
22
+ - If the file changed on disk between the last read and this edit, this errors with "file unexpectedly modified" — read it again.
23
+ - old_string must match exactly: indentation, trailing whitespace, and the file's line endings (LF or CRLF).
24
+ - BOM and line endings are preserved on write — Windows-authored files stay Windows-formatted.
25
+ - File permissions (mode) are preserved.
26
+
27
+ Errors are deliberately specific so you can self-correct:
28
+ - "not read first" → call read_file first.
29
+ - "unexpectedly modified" → read_file again before retrying.
30
+ - "old_string not found" → the file may have changed; re-read.
31
+ - "appears N times" → quote more surrounding context, or use replace_all.
32
+
33
+ To create a new file, use write_file. To append, read then edit with the new content appended.`;
34
+ export function createEditFile(ctx) {
35
+ return {
36
+ name: "edit_file",
37
+ label: "Edit",
38
+ description: DESCRIPTION,
39
+ parameters: Params,
40
+ executionMode: "sequential",
41
+ execute: async (_toolCallId, params) => {
42
+ const absPath = resolveInsideCwd(ctx.cwd, params.path);
43
+ const snap = validateForOverwrite(absPath, ctx.fileStateCache);
44
+ const { content: nextContent, replacements } = applyEdit(snap.content, {
45
+ oldString: params.old_string,
46
+ newString: params.new_string,
47
+ replaceAll: params.replace_all ?? false,
48
+ path: params.path,
49
+ });
50
+ const mode = statSync(absPath).mode & 0o777;
51
+ const { mtimeMs, size } = atomicWrite(absPath, nextContent, {
52
+ hasBOM: snap.hasBOM,
53
+ eol: snap.eol,
54
+ mode,
55
+ });
56
+ ctx.fileStateCache.record({
57
+ path: absPath,
58
+ content: nextContent,
59
+ mtimeMs,
60
+ size,
61
+ hasBOM: snap.hasBOM,
62
+ eol: snap.eol,
63
+ isPartialView: false,
64
+ storedAt: Date.now(),
65
+ });
66
+ return {
67
+ content: [
68
+ {
69
+ type: "text",
70
+ text: replacements === 1
71
+ ? `Edited ${params.path}.`
72
+ : `Edited ${params.path} (${replacements} replacements).`,
73
+ },
74
+ ],
75
+ details: { path: absPath, replacements, bytes: size },
76
+ };
77
+ },
78
+ };
79
+ }
80
+ //# sourceMappingURL=edit-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-file.js","sourceRoot":"","sources":["../../src/tools/edit-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAG/F,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC1B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;QACjB,WAAW,EAAE,0FAA0F;KACvG,CAAC;IACF,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;QACvB,WAAW,EAAE,8FAA8F;KAC3G,CAAC;IACF,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;QACvB,WAAW,EAAE,2FAA2F;KACxG,CAAC;IACF,WAAW,EAAE,IAAI,CAAC,QAAQ,CACzB,IAAI,CAAC,OAAO,CAAC;QACZ,WAAW,EAAE,uEAAuE;KACpF,CAAC,CACF;CACD,CAAC,CAAC;AAUH,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;+FAe2E,CAAC;AAEhG,MAAM,UAAU,cAAc,CAAC,GAAgB;IAC9C,OAAO;QACN,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,WAAW;QACxB,UAAU,EAAE,MAAM;QAClB,aAAa,EAAE,YAAY;QAC3B,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE;YACtC,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACvD,MAAM,IAAI,GAAG,oBAAoB,CAAC,OAAO,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;YAE/D,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE;gBACtE,SAAS,EAAE,MAAM,CAAC,UAAU;gBAC5B,SAAS,EAAE,MAAM,CAAC,UAAU;gBAC5B,UAAU,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;gBACvC,IAAI,EAAE,MAAM,CAAC,IAAI;aACjB,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;YAC5C,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE;gBAC3D,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,IAAI;aACJ,CAAC,CAAC;YAEH,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC;gBACzB,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,WAAW;gBACpB,OAAO;gBACP,IAAI;gBACJ,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,aAAa,EAAE,KAAK;gBACpB,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;aACpB,CAAC,CAAC;YAEH,OAAO;gBACN,OAAO,EAAE;oBACR;wBACC,IAAI,EAAE,MAAM;wBACZ,IAAI,EACH,YAAY,KAAK,CAAC;4BACjB,CAAC,CAAC,UAAU,MAAM,CAAC,IAAI,GAAG;4BAC1B,CAAC,CAAC,UAAU,MAAM,CAAC,IAAI,KAAK,YAAY,iBAAiB;qBAC3D;iBACD;gBACD,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE;aACrD,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Typed errors thrown by tools. Messages are addressed to the LLM —
3
+ * actionable, no internal codes leaked. The agent loop converts these into
4
+ * tool-result errors that the model sees directly.
5
+ */
6
+ export class FileUnexpectedlyModifiedError extends Error {
7
+ path;
8
+ constructor(path) {
9
+ super(`${path} changed on disk since I last read it. Read it again before editing.`);
10
+ this.path = path;
11
+ this.name = "FileUnexpectedlyModifiedError";
12
+ }
13
+ }
14
+ export class FileNotReadFirstError extends Error {
15
+ path;
16
+ constructor(path) {
17
+ super(`${path} was not read in this turn. Use read_file before edit_file or write_file.`);
18
+ this.path = path;
19
+ this.name = "FileNotReadFirstError";
20
+ }
21
+ }
22
+ export class PartialViewEditError extends Error {
23
+ path;
24
+ constructor(path) {
25
+ super(`${path} was only partially read (offset/limit). Read the full file before editing, ` +
26
+ "or use multi_edit with all the segments you intend to change.");
27
+ this.path = path;
28
+ this.name = "PartialViewEditError";
29
+ }
30
+ }
31
+ export class AmbiguousMatchError extends Error {
32
+ path;
33
+ count;
34
+ constructor(path, count) {
35
+ super(`old_string appears ${count} times in ${path}. Provide more context to uniquely identify ` +
36
+ "the match, or set replace_all: true.");
37
+ this.path = path;
38
+ this.count = count;
39
+ this.name = "AmbiguousMatchError";
40
+ }
41
+ }
42
+ export class NoMatchError extends Error {
43
+ path;
44
+ constructor(path) {
45
+ super(`old_string not found in ${path}. Read the file again — it may have changed.`);
46
+ this.path = path;
47
+ this.name = "NoMatchError";
48
+ }
49
+ }
50
+ export class FileTooLargeError extends Error {
51
+ path;
52
+ size;
53
+ limit;
54
+ constructor(path, size, limit) {
55
+ super(`${path} is ${size} bytes (limit: ${limit}). Read with offset+limit to page through it, ` +
56
+ "or run head/tail via shell.");
57
+ this.path = path;
58
+ this.size = size;
59
+ this.limit = limit;
60
+ this.name = "FileTooLargeError";
61
+ }
62
+ }
63
+ export class PathOutsideCwdError extends Error {
64
+ path;
65
+ constructor(path) {
66
+ super(`${path} is outside the project root. Tools only operate within the cwd.`);
67
+ this.path = path;
68
+ this.name = "PathOutsideCwdError";
69
+ }
70
+ }
71
+ export class TimeoutError extends Error {
72
+ seconds;
73
+ tool;
74
+ constructor(seconds, tool) {
75
+ super(`${tool} timed out after ${seconds}s.`);
76
+ this.seconds = seconds;
77
+ this.tool = tool;
78
+ this.name = "TimeoutError";
79
+ }
80
+ }
81
+ export class BinaryFileError extends Error {
82
+ path;
83
+ constructor(path) {
84
+ super(`${path} appears to be binary. Tools that read text won't help here.`);
85
+ this.path = path;
86
+ this.name = "BinaryFileError";
87
+ }
88
+ }
89
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/tools/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,OAAO,6BAA8B,SAAQ,KAAK;IAC3B;IAA5B,YAA4B,IAAY;QACvC,KAAK,CAAC,GAAG,IAAI,sEAAsE,CAAC,CAAC;QAD1D,SAAI,GAAJ,IAAI,CAAQ;QAEvC,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC7C,CAAC;CACD;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IACnB;IAA5B,YAA4B,IAAY;QACvC,KAAK,CAAC,GAAG,IAAI,2EAA2E,CAAC,CAAC;QAD/D,SAAI,GAAJ,IAAI,CAAQ;QAEvC,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACrC,CAAC;CACD;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAClB;IAA5B,YAA4B,IAAY;QACvC,KAAK,CACJ,GAAG,IAAI,8EAA8E;YACpF,+DAA+D,CAChE,CAAC;QAJyB,SAAI,GAAJ,IAAI,CAAQ;QAKvC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACpC,CAAC;CACD;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAE5B;IACA;IAFjB,YACiB,IAAY,EACZ,KAAa;QAE7B,KAAK,CACJ,sBAAsB,KAAK,aAAa,IAAI,8CAA8C;YACzF,sCAAsC,CACvC,CAAC;QANc,SAAI,GAAJ,IAAI,CAAQ;QACZ,UAAK,GAAL,KAAK,CAAQ;QAM7B,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACnC,CAAC;CACD;AAED,MAAM,OAAO,YAAa,SAAQ,KAAK;IACV;IAA5B,YAA4B,IAAY;QACvC,KAAK,CAAC,2BAA2B,IAAI,8CAA8C,CAAC,CAAC;QAD1D,SAAI,GAAJ,IAAI,CAAQ;QAEvC,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC5B,CAAC;CACD;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAE1B;IACA;IACA;IAHjB,YACiB,IAAY,EACZ,IAAY,EACZ,KAAa;QAE7B,KAAK,CACJ,GAAG,IAAI,OAAO,IAAI,kBAAkB,KAAK,gDAAgD;YACxF,6BAA6B,CAC9B,CAAC;QAPc,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAQ;QACZ,UAAK,GAAL,KAAK,CAAQ;QAM7B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IACjC,CAAC;CACD;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACjB;IAA5B,YAA4B,IAAY;QACvC,KAAK,CAAC,GAAG,IAAI,kEAAkE,CAAC,CAAC;QADtD,SAAI,GAAJ,IAAI,CAAQ;QAEvC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACnC,CAAC;CACD;AAED,MAAM,OAAO,YAAa,SAAQ,KAAK;IAErB;IACA;IAFjB,YACiB,OAAe,EACf,IAAY;QAE5B,KAAK,CAAC,GAAG,IAAI,oBAAoB,OAAO,IAAI,CAAC,CAAC;QAH9B,YAAO,GAAP,OAAO,CAAQ;QACf,SAAI,GAAJ,IAAI,CAAQ;QAG5B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC5B,CAAC;CACD;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACb;IAA5B,YAA4B,IAAY;QACvC,KAAK,CAAC,GAAG,IAAI,8DAA8D,CAAC,CAAC;QADlD,SAAI,GAAJ,IAAI,CAAQ;QAEvC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAC/B,CAAC;CACD"}