anyclaude-sdk 0.1.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 (195) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/dist/agent.d.ts +110 -0
  4. package/dist/agent.js +897 -0
  5. package/dist/background/index.d.ts +3 -0
  6. package/dist/background/index.js +9 -0
  7. package/dist/background/manager.d.ts +32 -0
  8. package/dist/background/manager.js +108 -0
  9. package/dist/background/tools.d.ts +5 -0
  10. package/dist/background/tools.js +98 -0
  11. package/dist/background/worker.d.ts +19 -0
  12. package/dist/background/worker.js +30 -0
  13. package/dist/commands/builtins.d.ts +2 -0
  14. package/dist/commands/builtins.js +306 -0
  15. package/dist/commands/index.d.ts +21 -0
  16. package/dist/commands/index.js +56 -0
  17. package/dist/commands/types.d.ts +110 -0
  18. package/dist/commands/types.js +5 -0
  19. package/dist/compact.d.ts +22 -0
  20. package/dist/compact.js +67 -0
  21. package/dist/fs/dexie.d.ts +57 -0
  22. package/dist/fs/dexie.js +243 -0
  23. package/dist/fs/index.d.ts +4 -0
  24. package/dist/fs/index.js +13 -0
  25. package/dist/fs/linuxTree.d.ts +11 -0
  26. package/dist/fs/linuxTree.js +43 -0
  27. package/dist/fs/opfs.d.ts +23 -0
  28. package/dist/fs/opfs.js +112 -0
  29. package/dist/index.d.ts +26 -0
  30. package/dist/index.js +29 -0
  31. package/dist/llm/anthropic.d.ts +24 -0
  32. package/dist/llm/anthropic.js +280 -0
  33. package/dist/llm/index.d.ts +3 -0
  34. package/dist/llm/index.js +3 -0
  35. package/dist/llm/inlineTools.d.ts +11 -0
  36. package/dist/llm/inlineTools.js +72 -0
  37. package/dist/llm/openai.d.ts +29 -0
  38. package/dist/llm/openai.js +224 -0
  39. package/dist/llm/responses.d.ts +18 -0
  40. package/dist/llm/responses.js +256 -0
  41. package/dist/mcp/client.d.ts +20 -0
  42. package/dist/mcp/client.js +156 -0
  43. package/dist/mcp/index.d.ts +24 -0
  44. package/dist/mcp/index.js +157 -0
  45. package/dist/mcp/proxy.d.ts +3 -0
  46. package/dist/mcp/proxy.js +25 -0
  47. package/dist/mcp/sdkServer.d.ts +21 -0
  48. package/dist/mcp/sdkServer.js +28 -0
  49. package/dist/mcp/types.d.ts +92 -0
  50. package/dist/mcp/types.js +5 -0
  51. package/dist/memory/index.d.ts +4 -0
  52. package/dist/memory/index.js +5 -0
  53. package/dist/memory/render.d.ts +7 -0
  54. package/dist/memory/render.js +46 -0
  55. package/dist/memory/store.d.ts +20 -0
  56. package/dist/memory/store.js +79 -0
  57. package/dist/memory/tools.d.ts +5 -0
  58. package/dist/memory/tools.js +95 -0
  59. package/dist/memory/types.d.ts +15 -0
  60. package/dist/memory/types.js +4 -0
  61. package/dist/permissions/dangerous.d.ts +4 -0
  62. package/dist/permissions/dangerous.js +24 -0
  63. package/dist/permissions/gate.d.ts +21 -0
  64. package/dist/permissions/gate.js +66 -0
  65. package/dist/permissions/index.d.ts +5 -0
  66. package/dist/permissions/index.js +6 -0
  67. package/dist/permissions/match.d.ts +19 -0
  68. package/dist/permissions/match.js +104 -0
  69. package/dist/permissions/planMode.d.ts +3 -0
  70. package/dist/permissions/planMode.js +33 -0
  71. package/dist/permissions/types.d.ts +19 -0
  72. package/dist/permissions/types.js +2 -0
  73. package/dist/persist.d.ts +15 -0
  74. package/dist/persist.js +58 -0
  75. package/dist/prompt.d.ts +6 -0
  76. package/dist/prompt.js +34 -0
  77. package/dist/query.d.ts +105 -0
  78. package/dist/query.js +115 -0
  79. package/dist/queue.d.ts +23 -0
  80. package/dist/queue.js +43 -0
  81. package/dist/sandbox/cloudflare.d.ts +48 -0
  82. package/dist/sandbox/cloudflare.js +124 -0
  83. package/dist/sandbox/daytona.d.ts +48 -0
  84. package/dist/sandbox/daytona.js +79 -0
  85. package/dist/sandbox/e2b.d.ts +54 -0
  86. package/dist/sandbox/e2b.js +87 -0
  87. package/dist/sandbox/index.d.ts +8 -0
  88. package/dist/sandbox/index.js +19 -0
  89. package/dist/sandbox/local.d.ts +51 -0
  90. package/dist/sandbox/local.js +155 -0
  91. package/dist/sandbox/types.d.ts +18 -0
  92. package/dist/sandbox/types.js +27 -0
  93. package/dist/sandbox/util.d.ts +15 -0
  94. package/dist/sandbox/util.js +100 -0
  95. package/dist/sandbox/vercel.d.ts +48 -0
  96. package/dist/sandbox/vercel.js +130 -0
  97. package/dist/session/index.d.ts +2 -0
  98. package/dist/session/index.js +6 -0
  99. package/dist/session/store.d.ts +28 -0
  100. package/dist/session/store.js +122 -0
  101. package/dist/session/types.d.ts +22 -0
  102. package/dist/session/types.js +2 -0
  103. package/dist/settings/index.d.ts +3 -0
  104. package/dist/settings/index.js +3 -0
  105. package/dist/settings/load.d.ts +20 -0
  106. package/dist/settings/load.js +36 -0
  107. package/dist/settings/merge.d.ts +13 -0
  108. package/dist/settings/merge.js +65 -0
  109. package/dist/settings/types.d.ts +17 -0
  110. package/dist/settings/types.js +3 -0
  111. package/dist/skills/index.d.ts +4 -0
  112. package/dist/skills/index.js +5 -0
  113. package/dist/skills/load.d.ts +23 -0
  114. package/dist/skills/load.js +54 -0
  115. package/dist/skills/parse.d.ts +7 -0
  116. package/dist/skills/parse.js +40 -0
  117. package/dist/skills/tool.d.ts +2 -0
  118. package/dist/skills/tool.js +39 -0
  119. package/dist/skills/types.d.ts +10 -0
  120. package/dist/skills/types.js +4 -0
  121. package/dist/team/dispatch.d.ts +2 -0
  122. package/dist/team/dispatch.js +41 -0
  123. package/dist/team/index.d.ts +9 -0
  124. package/dist/team/index.js +11 -0
  125. package/dist/team/mailbox.d.ts +24 -0
  126. package/dist/team/mailbox.js +33 -0
  127. package/dist/team/prompt.d.ts +1 -0
  128. package/dist/team/prompt.js +12 -0
  129. package/dist/team/runner.d.ts +20 -0
  130. package/dist/team/runner.js +45 -0
  131. package/dist/team/taskBoard.d.ts +41 -0
  132. package/dist/team/taskBoard.js +73 -0
  133. package/dist/team/tools.d.ts +7 -0
  134. package/dist/team/tools.js +190 -0
  135. package/dist/tools/bash.d.ts +2 -0
  136. package/dist/tools/bash.js +45 -0
  137. package/dist/tools/config.d.ts +2 -0
  138. package/dist/tools/config.js +44 -0
  139. package/dist/tools/define.d.ts +18 -0
  140. package/dist/tools/define.js +21 -0
  141. package/dist/tools/delete_file.d.ts +2 -0
  142. package/dist/tools/delete_file.js +33 -0
  143. package/dist/tools/edit_file.d.ts +2 -0
  144. package/dist/tools/edit_file.js +93 -0
  145. package/dist/tools/fileTypes.d.ts +32 -0
  146. package/dist/tools/fileTypes.js +166 -0
  147. package/dist/tools/glob.d.ts +2 -0
  148. package/dist/tools/glob.js +53 -0
  149. package/dist/tools/grep.d.ts +2 -0
  150. package/dist/tools/grep.js +110 -0
  151. package/dist/tools/imageProcessor.d.ts +15 -0
  152. package/dist/tools/imageProcessor.js +83 -0
  153. package/dist/tools/index.d.ts +28 -0
  154. package/dist/tools/index.js +45 -0
  155. package/dist/tools/list_files.d.ts +2 -0
  156. package/dist/tools/list_files.js +42 -0
  157. package/dist/tools/multi_edit.d.ts +2 -0
  158. package/dist/tools/multi_edit.js +112 -0
  159. package/dist/tools/notebook_edit.d.ts +2 -0
  160. package/dist/tools/notebook_edit.js +118 -0
  161. package/dist/tools/plan_mode.d.ts +4 -0
  162. package/dist/tools/plan_mode.js +44 -0
  163. package/dist/tools/read_file.d.ts +2 -0
  164. package/dist/tools/read_file.js +193 -0
  165. package/dist/tools/task.d.ts +2 -0
  166. package/dist/tools/task.js +77 -0
  167. package/dist/tools/todo_write.d.ts +2 -0
  168. package/dist/tools/todo_write.js +104 -0
  169. package/dist/tools/tool_search.d.ts +2 -0
  170. package/dist/tools/tool_search.js +49 -0
  171. package/dist/tools/types.d.ts +82 -0
  172. package/dist/tools/types.js +1 -0
  173. package/dist/tools/walk.d.ts +29 -0
  174. package/dist/tools/walk.js +82 -0
  175. package/dist/tools/web_fetch.d.ts +2 -0
  176. package/dist/tools/web_fetch.js +76 -0
  177. package/dist/tools/web_search.d.ts +22 -0
  178. package/dist/tools/web_search.js +195 -0
  179. package/dist/tools/write_file.d.ts +2 -0
  180. package/dist/tools/write_file.js +39 -0
  181. package/dist/types/index.d.ts +363 -0
  182. package/dist/types/index.js +9 -0
  183. package/dist/util/ids.d.ts +3 -0
  184. package/dist/util/ids.js +22 -0
  185. package/dist/util/paths.d.ts +16 -0
  186. package/dist/util/paths.js +72 -0
  187. package/dist/util/pricing.d.ts +15 -0
  188. package/dist/util/pricing.js +81 -0
  189. package/dist/workspace/index.d.ts +2 -0
  190. package/dist/workspace/index.js +2 -0
  191. package/dist/workspace/memory.d.ts +28 -0
  192. package/dist/workspace/memory.js +97 -0
  193. package/dist/workspace/webcontainer.d.ts +65 -0
  194. package/dist/workspace/webcontainer.js +156 -0
  195. package/package.json +78 -0
@@ -0,0 +1,2 @@
1
+ // Session persistence types.
2
+ export {};
@@ -0,0 +1,3 @@
1
+ export type { Settings, SettingsSource } from './types.js';
2
+ export { parseSettings, mergeSettings } from './merge.js';
3
+ export { loadSettings, settingsToPermissionRuleSet } from './load.js';
@@ -0,0 +1,3 @@
1
+ // Settings cascade for browser-claude-sdk (user < project < local).
2
+ export { parseSettings, mergeSettings } from './merge.js';
3
+ export { loadSettings, settingsToPermissionRuleSet } from './load.js';
@@ -0,0 +1,20 @@
1
+ import type { Settings } from './types.js';
2
+ type ReadableFs = {
3
+ readFile(path: string): Promise<string | null>;
4
+ };
5
+ /**
6
+ * Load and cascade settings from the workspace. Reads `.claude/settings.json`
7
+ * (project) then `.claude/settings.local.json` (local) relative to `cwd`,
8
+ * merging project < local. (No home dir in the browser, so user-scope is
9
+ * omitted.) Never throws — missing/invalid files contribute {}.
10
+ */
11
+ export declare function loadSettings(fs: ReadableFs, opts?: {
12
+ cwd?: string;
13
+ }): Promise<Settings>;
14
+ /** Extract raw permission-rule strings for the permissions module to parse. */
15
+ export declare function settingsToPermissionRuleSet(s: Settings): {
16
+ allow: string[];
17
+ deny: string[];
18
+ ask: string[];
19
+ };
20
+ export {};
@@ -0,0 +1,36 @@
1
+ // Load + cascade settings from the workspace filesystem.
2
+ import { mergeSettings, parseSettings } from './merge.js';
3
+ function join(cwd, rel) {
4
+ if (!cwd)
5
+ return rel;
6
+ return cwd.endsWith('/') ? cwd + rel : cwd + '/' + rel;
7
+ }
8
+ /**
9
+ * Load and cascade settings from the workspace. Reads `.claude/settings.json`
10
+ * (project) then `.claude/settings.local.json` (local) relative to `cwd`,
11
+ * merging project < local. (No home dir in the browser, so user-scope is
12
+ * omitted.) Never throws — missing/invalid files contribute {}.
13
+ */
14
+ export async function loadSettings(fs, opts = {}) {
15
+ const cwd = opts.cwd ?? '';
16
+ const read = async (rel) => {
17
+ try {
18
+ const txt = await fs.readFile(join(cwd, rel));
19
+ return txt ? parseSettings(txt) : {};
20
+ }
21
+ catch {
22
+ return {};
23
+ }
24
+ };
25
+ const project = await read('.claude/settings.json');
26
+ const local = await read('.claude/settings.local.json');
27
+ return mergeSettings(project, local);
28
+ }
29
+ /** Extract raw permission-rule strings for the permissions module to parse. */
30
+ export function settingsToPermissionRuleSet(s) {
31
+ return {
32
+ allow: s.allow ?? [],
33
+ deny: s.deny ?? [],
34
+ ask: s.ask ?? [],
35
+ };
36
+ }
@@ -0,0 +1,13 @@
1
+ import type { Settings } from './types.js';
2
+ /**
3
+ * Parse a settings.json string. Tolerant: returns {} on invalid JSON. Accepts
4
+ * Claude Code's nested `permissions: { allow, deny, ask }` shape and hoists it
5
+ * to top-level allow/deny/ask.
6
+ */
7
+ export declare function parseSettings(json: string): Settings;
8
+ /**
9
+ * Merge settings sources. Later sources win for scalars; array keys are
10
+ * concatenated + deduped; `env` is shallow-merged. Pass lowest → highest
11
+ * precedence (e.g. user, project, local).
12
+ */
13
+ export declare function mergeSettings(...sources: Settings[]): Settings;
@@ -0,0 +1,65 @@
1
+ // Parsing + cascading merge for settings sources.
2
+ /** Array-valued keys are concatenated + deduped across sources. */
3
+ const ARRAY_KEYS = ['allow', 'deny', 'ask', 'allowedTools', 'disallowedTools'];
4
+ /**
5
+ * Parse a settings.json string. Tolerant: returns {} on invalid JSON. Accepts
6
+ * Claude Code's nested `permissions: { allow, deny, ask }` shape and hoists it
7
+ * to top-level allow/deny/ask.
8
+ */
9
+ export function parseSettings(json) {
10
+ let raw;
11
+ try {
12
+ raw = JSON.parse(json);
13
+ }
14
+ catch {
15
+ return {};
16
+ }
17
+ if (!raw || typeof raw !== 'object')
18
+ return {};
19
+ const obj = raw;
20
+ const out = { ...obj };
21
+ const perms = obj.permissions;
22
+ if (perms && typeof perms === 'object') {
23
+ const p = perms;
24
+ for (const key of ['allow', 'deny', 'ask']) {
25
+ if (Array.isArray(p[key])) {
26
+ const existing = Array.isArray(out[key]) ? out[key] : [];
27
+ out[key] = dedupe([...existing, ...p[key]]);
28
+ }
29
+ }
30
+ if (typeof p.defaultMode === 'string') {
31
+ out.permissionMode = (out.permissionMode ?? p.defaultMode);
32
+ }
33
+ }
34
+ return out;
35
+ }
36
+ /**
37
+ * Merge settings sources. Later sources win for scalars; array keys are
38
+ * concatenated + deduped; `env` is shallow-merged. Pass lowest → highest
39
+ * precedence (e.g. user, project, local).
40
+ */
41
+ export function mergeSettings(...sources) {
42
+ const out = {};
43
+ for (const src of sources) {
44
+ if (!src)
45
+ continue;
46
+ for (const [key, val] of Object.entries(src)) {
47
+ if (val === undefined)
48
+ continue;
49
+ if (ARRAY_KEYS.includes(key)) {
50
+ const existing = Array.isArray(out[key]) ? out[key] : [];
51
+ out[key] = dedupe([...existing, ...(Array.isArray(val) ? val : [val])]);
52
+ }
53
+ else if (key === 'env' && val && typeof val === 'object') {
54
+ out.env = { ...(out.env ?? {}), ...val };
55
+ }
56
+ else {
57
+ out[key] = val;
58
+ }
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+ function dedupe(arr) {
64
+ return [...new Set(arr)];
65
+ }
@@ -0,0 +1,17 @@
1
+ export type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan' | 'dontAsk';
2
+ export type SettingsSource = 'user' | 'project' | 'local';
3
+ export type Settings = {
4
+ model?: string;
5
+ permissionMode?: PermissionMode;
6
+ /** Permission rule strings (e.g. "Bash(rm *)", "Read"). */
7
+ allow?: string[];
8
+ deny?: string[];
9
+ ask?: string[];
10
+ /** Tool name allow/deny lists. */
11
+ allowedTools?: string[];
12
+ disallowedTools?: string[];
13
+ appendSystemPrompt?: string;
14
+ maxTurns?: number;
15
+ env?: Record<string, string>;
16
+ [key: string]: unknown;
17
+ };
@@ -0,0 +1,3 @@
1
+ // Settings types — a browser-friendly port of Claude Code's settings.json.
2
+ // Sources cascade user < project < local (highest precedence last).
3
+ export {};
@@ -0,0 +1,4 @@
1
+ export type { Skill } from './types.js';
2
+ export { parseSkill } from './parse.js';
3
+ export { loadSkillsFromFs, skillsToCommands, applySkillArgs } from './load.js';
4
+ export { skill } from './tool.js';
@@ -0,0 +1,5 @@
1
+ // Skills system: load .claude/skills/*.md markdown skills and expose them as
2
+ // slash commands and via the `skill` tool.
3
+ export { parseSkill } from './parse.js';
4
+ export { loadSkillsFromFs, skillsToCommands, applySkillArgs } from './load.js';
5
+ export { skill } from './tool.js';
@@ -0,0 +1,23 @@
1
+ import type { SlashCommand } from '../commands/types.js';
2
+ import type { Skill } from './types.js';
3
+ interface SkillFs {
4
+ readFile(path: string): Promise<string | null>;
5
+ readdir(path: string): Promise<Array<{
6
+ name: string;
7
+ isDir: boolean;
8
+ }> | null>;
9
+ }
10
+ /** Substitute $ARGUMENTS in a skill body with the invocation args. */
11
+ export declare function applySkillArgs(body: string, args: string): string;
12
+ /**
13
+ * Load skills from `<dir>`. Supports both flat `<dir>/<name>.md` files and
14
+ * nested `<dir>/<name>/SKILL.md`. Never throws — returns [] on any failure.
15
+ */
16
+ export declare function loadSkillsFromFs(fs: SkillFs, dir?: string): Promise<Skill[]>;
17
+ /**
18
+ * Turn skills into slash commands. Invoking `/skillName args` expands the
19
+ * skill body (with $ARGUMENTS substituted) into a prompt. Built inline to avoid
20
+ * a dependency cycle with the commands module.
21
+ */
22
+ export declare function skillsToCommands(skills: Skill[]): SlashCommand[];
23
+ export {};
@@ -0,0 +1,54 @@
1
+ // Discover and load skills from a FileSystem, and turn them into slash commands.
2
+ import { parseSkill } from './parse.js';
3
+ /** Substitute $ARGUMENTS in a skill body with the invocation args. */
4
+ export function applySkillArgs(body, args) {
5
+ return body.includes('$ARGUMENTS') ? body.split('$ARGUMENTS').join(args) : body;
6
+ }
7
+ /**
8
+ * Load skills from `<dir>`. Supports both flat `<dir>/<name>.md` files and
9
+ * nested `<dir>/<name>/SKILL.md`. Never throws — returns [] on any failure.
10
+ */
11
+ export async function loadSkillsFromFs(fs, dir = '.claude/skills') {
12
+ const entries = await fs.readdir(dir).catch(() => null);
13
+ if (!entries)
14
+ return [];
15
+ const skills = [];
16
+ for (const entry of entries) {
17
+ try {
18
+ if (entry.isDir) {
19
+ // Nested form: <dir>/<name>/SKILL.md (or skill.md).
20
+ for (const file of ['SKILL.md', 'skill.md']) {
21
+ const md = await fs.readFile(`${dir}/${entry.name}/${file}`);
22
+ if (md != null) {
23
+ skills.push(parseSkill(md, entry.name));
24
+ break;
25
+ }
26
+ }
27
+ }
28
+ else if (entry.name.toLowerCase().endsWith('.md')) {
29
+ const md = await fs.readFile(`${dir}/${entry.name}`);
30
+ if (md != null)
31
+ skills.push(parseSkill(md, entry.name.replace(/\.md$/i, '')));
32
+ }
33
+ }
34
+ catch {
35
+ // skip unreadable entries
36
+ }
37
+ }
38
+ return skills;
39
+ }
40
+ /**
41
+ * Turn skills into slash commands. Invoking `/skillName args` expands the
42
+ * skill body (with $ARGUMENTS substituted) into a prompt. Built inline to avoid
43
+ * a dependency cycle with the commands module.
44
+ */
45
+ export function skillsToCommands(skills) {
46
+ return skills.map((skill) => ({
47
+ name: skill.name,
48
+ description: skill.description,
49
+ argumentHint: skill.argumentHint,
50
+ run(args) {
51
+ return { expandedPrompt: applySkillArgs(skill.body, args.trim()) };
52
+ },
53
+ }));
54
+ }
@@ -0,0 +1,7 @@
1
+ import type { Skill } from './types.js';
2
+ /**
3
+ * Parse a markdown skill. Recognizes a leading `---`-delimited frontmatter
4
+ * block with `name`, `description`, and `argument-hint`/`argumentHint` keys.
5
+ * Falls back to `fallbackName` and the first non-empty body line when absent.
6
+ */
7
+ export declare function parseSkill(markdown: string, fallbackName?: string): Skill;
@@ -0,0 +1,40 @@
1
+ // Parse a skill markdown document into a Skill. Hand-parses a simple
2
+ // `key: value` YAML-ish frontmatter block (no yaml dependency).
3
+ const FRONTMATTER = /^?---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
4
+ /** Strip surrounding single/double quotes from a frontmatter value. */
5
+ function unquote(v) {
6
+ const t = v.trim();
7
+ if (t.length >= 2 && ((t[0] === '"' && t.endsWith('"')) || (t[0] === "'" && t.endsWith("'")))) {
8
+ return t.slice(1, -1);
9
+ }
10
+ return t;
11
+ }
12
+ /**
13
+ * Parse a markdown skill. Recognizes a leading `---`-delimited frontmatter
14
+ * block with `name`, `description`, and `argument-hint`/`argumentHint` keys.
15
+ * Falls back to `fallbackName` and the first non-empty body line when absent.
16
+ */
17
+ export function parseSkill(markdown, fallbackName = 'skill') {
18
+ const src = markdown ?? '';
19
+ const m = src.match(FRONTMATTER);
20
+ let meta = {};
21
+ let body = src;
22
+ if (m) {
23
+ body = m[2] ?? '';
24
+ for (const line of m[1].split(/\r?\n/)) {
25
+ const idx = line.indexOf(':');
26
+ if (idx <= 0)
27
+ continue;
28
+ const key = line.slice(0, idx).trim().toLowerCase();
29
+ meta[key] = unquote(line.slice(idx + 1));
30
+ }
31
+ }
32
+ const firstLine = body
33
+ .split(/\r?\n/)
34
+ .map((l) => l.replace(/^#+\s*/, '').trim())
35
+ .find((l) => l.length > 0);
36
+ const name = (meta['name'] || fallbackName).trim();
37
+ const description = (meta['description'] || firstLine || name).trim();
38
+ const argumentHint = (meta['argument-hint'] || meta['argumenthint'] || '').trim() || undefined;
39
+ return { name, description, body: body.trim(), argumentHint };
40
+ }
@@ -0,0 +1,2 @@
1
+ import type { Tool } from '../tools/types.js';
2
+ export declare const skill: Tool;
@@ -0,0 +1,39 @@
1
+ // The `skill` tool: load a named skill's instructions so the model can follow
2
+ // them. Skills are made available on the tool context as `ctx.skills`.
3
+ import { applySkillArgs } from './load.js';
4
+ const DESCRIPTION = `Loads a named skill's instructions and returns them so you can follow the skill.
5
+
6
+ Use this when a task matches an available skill. Pass the skill \`name\` and optional \`arguments\`; the skill's full instructions are returned as the result.`;
7
+ export const skill = {
8
+ def: {
9
+ type: 'function',
10
+ function: {
11
+ name: 'skill',
12
+ description: DESCRIPTION,
13
+ parameters: {
14
+ type: 'object',
15
+ properties: {
16
+ name: { type: 'string', description: 'The skill name to invoke.' },
17
+ arguments: { type: 'string', description: 'Arguments to pass to the skill (substituted for $ARGUMENTS).' },
18
+ },
19
+ required: ['name'],
20
+ },
21
+ },
22
+ },
23
+ async run(input, ctx) {
24
+ const skills = ctx.skills;
25
+ if (!skills || !skills.length) {
26
+ return { content: 'No skills are available in this session.', isError: true };
27
+ }
28
+ const name = String(input.name ?? '').trim();
29
+ const found = skills.find((s) => s.name === name) ?? skills.find((s) => s.name.toLowerCase() === name.toLowerCase());
30
+ if (!found) {
31
+ return {
32
+ content: `Unknown skill "${name}". Available: ${skills.map((s) => s.name).join(', ')}`,
33
+ isError: true,
34
+ };
35
+ }
36
+ const args = input.arguments != null ? String(input.arguments) : '';
37
+ return { content: `# Skill: ${found.name}\n\n${applySkillArgs(found.body, args)}` };
38
+ },
39
+ };
@@ -0,0 +1,10 @@
1
+ export type Skill = {
2
+ /** Skill name (used as the slash-command name and tool lookup key). */
3
+ name: string;
4
+ /** One-line description of what the skill does. */
5
+ description: string;
6
+ /** The skill body — instructions/prompt template ($ARGUMENTS is substituted). */
7
+ body: string;
8
+ /** Optional hint for the skill's arguments (e.g. "<file>"). */
9
+ argumentHint?: string;
10
+ };
@@ -0,0 +1,4 @@
1
+ // Skill types for browser-claude-sdk. A skill is a markdown document with
2
+ // optional frontmatter; it becomes an invokable slash command and is reachable
3
+ // via the `skill` tool.
4
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { Tool } from '../tools/types.js';
2
+ export declare const dispatchTasks: Tool;
@@ -0,0 +1,41 @@
1
+ // `dispatch_tasks` tool: the coordinator calls this to execute the board. It
2
+ // runs the teammate idle-loop, spawning worker sub-agents for each pending,
3
+ // unblocked task (dependencies respected, bounded parallelism). Reads
4
+ // `ctx.board` + `ctx.runSubagent` (both injected by the agent loop).
5
+ import { runTeamLoop } from './runner.js';
6
+ export const dispatchTasks = {
7
+ def: {
8
+ type: 'function',
9
+ function: {
10
+ name: 'dispatch_tasks',
11
+ description: 'Execute the task board: spawn worker sub-agents for every pending, unblocked task (dependencies respected, run in parallel), looping until the board drains. Call this after creating tasks with task_create.',
12
+ parameters: {
13
+ type: 'object',
14
+ properties: {
15
+ concurrency: { type: 'number', description: 'Max workers in parallel (default 3).' },
16
+ },
17
+ },
18
+ },
19
+ },
20
+ async run(input, ctx) {
21
+ const board = ctx.board;
22
+ const runSubagent = ctx.runSubagent;
23
+ if (!board || !runSubagent) {
24
+ return { content: 'Teammates/sub-agents are not enabled for this session.', isError: true };
25
+ }
26
+ const spawn = (task) => runSubagent({
27
+ description: task.subject,
28
+ prompt: `Complete this task:\n# ${task.subject}\n${task.description ?? ''}\n\n` +
29
+ 'When done, your final message should report exactly what you did.',
30
+ });
31
+ const summary = await runTeamLoop(board, spawn, {
32
+ concurrency: typeof input.concurrency === 'number' ? input.concurrency : undefined,
33
+ signal: ctx.signal,
34
+ });
35
+ const lines = board.list().map((t) => ` ${t.id} [${t.status}] — ${t.subject}`);
36
+ return {
37
+ content: `Dispatched the board — completed: ${summary.completed.length}, failed: ${summary.failed.length}, rounds: ${summary.rounds}\n` +
38
+ lines.join('\n'),
39
+ };
40
+ },
41
+ };
@@ -0,0 +1,9 @@
1
+ export { Mailbox, type AgentMessage } from './mailbox.js';
2
+ export { TaskBoard, type BoardTask, type TaskStatus } from './taskBoard.js';
3
+ export { TEAM_TOOLS, sendMessage, taskCreate, taskUpdate, taskGet, boardList, } from './tools.js';
4
+ export { coordinatorPrompt } from './prompt.js';
5
+ export { runTeamLoop, type SpawnWorker, type TeamLoopOptions, type TeamLoopResult, } from './runner.js';
6
+ export { dispatchTasks } from './dispatch.js';
7
+ import type { Tool } from '../tools/types.js';
8
+ /** The dispatch tool, kept separate from TEAM_TOOLS so the agent can merge it in. */
9
+ export declare const TEAM_DISPATCH_TOOLS: Tool[];
@@ -0,0 +1,11 @@
1
+ // Teammate/coordinator MVP: shared in-memory mailbox + task board, the tools
2
+ // the coordinator uses to delegate, and the coordinator system-prompt addendum.
3
+ export { Mailbox } from './mailbox.js';
4
+ export { TaskBoard } from './taskBoard.js';
5
+ export { TEAM_TOOLS, sendMessage, taskCreate, taskUpdate, taskGet, boardList, } from './tools.js';
6
+ export { coordinatorPrompt } from './prompt.js';
7
+ export { runTeamLoop, } from './runner.js';
8
+ export { dispatchTasks } from './dispatch.js';
9
+ import { dispatchTasks } from './dispatch.js';
10
+ /** The dispatch tool, kept separate from TEAM_TOOLS so the agent can merge it in. */
11
+ export const TEAM_DISPATCH_TOOLS = [dispatchTasks];
@@ -0,0 +1,24 @@
1
+ export type AgentMessage = {
2
+ id: string;
3
+ from: string;
4
+ to: string;
5
+ text: string;
6
+ ts: number;
7
+ read: boolean;
8
+ };
9
+ export declare class Mailbox {
10
+ private messages;
11
+ private counter;
12
+ /** Deliver a message; returns the message id. */
13
+ send(from: string, to: string, text: string): string;
14
+ /** Messages addressed to `agentId`, oldest first. */
15
+ inbox(agentId: string, opts?: {
16
+ unreadOnly?: boolean;
17
+ }): AgentMessage[];
18
+ /** Mark every message addressed to `agentId` as read. */
19
+ markRead(agentId: string): void;
20
+ /** Send the same text to several recipients; returns the ids. */
21
+ broadcast(from: string, text: string, recipients: string[]): string[];
22
+ /** Every message, in send order. */
23
+ all(): AgentMessage[];
24
+ }
@@ -0,0 +1,33 @@
1
+ // In-memory inter-agent mailbox, shared across the coordinator and the workers
2
+ // it spawns. Each message is addressed to a teammate by name; recipients drain
3
+ // their inbox to receive. Browser-safe: no timers/fs; ids are monotonic.
4
+ export class Mailbox {
5
+ constructor() {
6
+ this.messages = [];
7
+ this.counter = 0;
8
+ }
9
+ /** Deliver a message; returns the message id. */
10
+ send(from, to, text) {
11
+ const id = `msg_${++this.counter}`;
12
+ this.messages.push({ id, from, to, text, ts: Date.now(), read: false });
13
+ return id;
14
+ }
15
+ /** Messages addressed to `agentId`, oldest first. */
16
+ inbox(agentId, opts) {
17
+ return this.messages.filter((m) => m.to === agentId && (!opts?.unreadOnly || !m.read));
18
+ }
19
+ /** Mark every message addressed to `agentId` as read. */
20
+ markRead(agentId) {
21
+ for (const m of this.messages)
22
+ if (m.to === agentId)
23
+ m.read = true;
24
+ }
25
+ /** Send the same text to several recipients; returns the ids. */
26
+ broadcast(from, text, recipients) {
27
+ return recipients.map((to) => this.send(from, to, text));
28
+ }
29
+ /** Every message, in send order. */
30
+ all() {
31
+ return [...this.messages];
32
+ }
33
+ }
@@ -0,0 +1 @@
1
+ export declare function coordinatorPrompt(): string;
@@ -0,0 +1,12 @@
1
+ // Coordinator system-prompt addendum, appended when teammates are enabled.
2
+ export function coordinatorPrompt() {
3
+ return `# Coordinating a team
4
+
5
+ You are the coordinator of a team of agents. Plan and delegate rather than doing everything yourself.
6
+
7
+ - Decompose the work into discrete tasks on the shared board with \`task_create\`. When a task depends on another, set \`blocked_by\` to the prerequisite task ids so execution is correctly gated.
8
+ - Spawn workers with the \`task\` tool to execute board tasks — give each worker a focused prompt and, when useful, run independent workers in parallel. Prefer parallelism over sequential work whenever tasks are independent.
9
+ - Use \`send_message\` to direct workers, hand off context, or coordinate between teammates. Check the board with \`board_list\` and \`task_get\` to track progress, and keep task status current with \`task_update\` (mark in_progress when started, completed/failed when done).
10
+ - Synthesize workers' results yourself before continuing. NEVER fabricate or assume a worker's output — rely only on what they actually returned.
11
+ - Keep the board the source of truth: every meaningful unit of work should be a task with an owner and a status.`;
12
+ }
@@ -0,0 +1,20 @@
1
+ import type { BoardTask, TaskBoard } from './taskBoard.js';
2
+ export type SpawnWorker = (task: BoardTask) => Promise<{
3
+ text: string;
4
+ isError?: boolean;
5
+ }>;
6
+ export interface TeamLoopOptions {
7
+ /** Max tasks executed in parallel per round. Default 3. */
8
+ concurrency?: number;
9
+ /** Safety cap on rounds (each round runs one parallel batch). Default 25. */
10
+ maxIterations?: number;
11
+ /** Owner label recorded when claiming. Default 'worker'. */
12
+ worker?: string;
13
+ signal?: AbortSignal;
14
+ }
15
+ export interface TeamLoopResult {
16
+ completed: string[];
17
+ failed: string[];
18
+ rounds: number;
19
+ }
20
+ export declare function runTeamLoop(board: TaskBoard, spawn: SpawnWorker, opts?: TeamLoopOptions): Promise<TeamLoopResult>;
@@ -0,0 +1,45 @@
1
+ // Teammate idle-loop: auto-claim pending, unblocked tasks from the shared board
2
+ // and execute them via worker sub-agents, respecting dependencies. Loops until
3
+ // nothing is claimable (all done, or remaining tasks blocked by failed
4
+ // prerequisites), a max-iteration cap, or an abort.
5
+ export async function runTeamLoop(board, spawn, opts = {}) {
6
+ const concurrency = Math.max(1, opts.concurrency ?? 3);
7
+ const maxIterations = opts.maxIterations ?? 25;
8
+ const worker = opts.worker || 'worker';
9
+ const signal = opts.signal;
10
+ const completed = [];
11
+ const failed = [];
12
+ let rounds = 0;
13
+ while (rounds < maxIterations) {
14
+ if (signal?.aborted)
15
+ break;
16
+ // Claimable = pending and not blocked by an incomplete prerequisite.
17
+ const claimable = board.list({ status: 'pending' }).filter((t) => !board.isBlocked(t.id));
18
+ if (!claimable.length)
19
+ break;
20
+ // Atomically claim up to `concurrency` of them for this round.
21
+ const batch = [];
22
+ for (const t of claimable) {
23
+ if (batch.length >= concurrency)
24
+ break;
25
+ const claimed = board.claim(t.id, worker);
26
+ if (claimed)
27
+ batch.push(claimed);
28
+ }
29
+ if (!batch.length)
30
+ break;
31
+ rounds++;
32
+ await Promise.all(batch.map(async (task) => {
33
+ try {
34
+ const res = await spawn(task);
35
+ board.update(task.id, { status: res.isError ? 'failed' : 'completed' });
36
+ (res.isError ? failed : completed).push(task.id);
37
+ }
38
+ catch {
39
+ board.update(task.id, { status: 'failed' });
40
+ failed.push(task.id);
41
+ }
42
+ }));
43
+ }
44
+ return { completed, failed, rounds };
45
+ }
@@ -0,0 +1,41 @@
1
+ export type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
2
+ export type BoardTask = {
3
+ id: string;
4
+ subject: string;
5
+ description?: string;
6
+ owner?: string;
7
+ status: TaskStatus;
8
+ /** Tasks that depend on this one. */
9
+ blocks: string[];
10
+ /** Tasks that must complete before this one can start. */
11
+ blockedBy: string[];
12
+ createdAt: number;
13
+ updatedAt: number;
14
+ };
15
+ export declare class TaskBoard {
16
+ private tasks;
17
+ private counter;
18
+ create(input: {
19
+ subject: string;
20
+ description?: string;
21
+ owner?: string;
22
+ blockedBy?: string[];
23
+ }): BoardTask;
24
+ update(id: string, patch: Partial<{
25
+ subject: string;
26
+ description: string;
27
+ owner: string;
28
+ status: TaskStatus;
29
+ blocks: string[];
30
+ blockedBy: string[];
31
+ }>): BoardTask | null;
32
+ get(id: string): BoardTask | null;
33
+ list(filter?: {
34
+ status?: TaskStatus;
35
+ owner?: string;
36
+ }): BoardTask[];
37
+ /** Atomically claim an unowned/pending task. Null if already claimed. */
38
+ claim(id: string, owner: string): BoardTask | null;
39
+ /** True if any prerequisite is not yet completed. */
40
+ isBlocked(id: string): boolean;
41
+ }