anyclaude-sdk 0.4.2 → 0.4.4

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.
package/README.md CHANGED
@@ -277,6 +277,28 @@ await fs.writeFile('/app/index.ts', 'export const x = 1')
277
277
  const workspace = composeWorkspace(fs, new NoopCommandExecutor())
278
278
  ```
279
279
 
280
+ ## Skills (programmatic)
281
+
282
+ Declare reusable prompt-skills inline — each becomes a `/name` slash command and is invokable by the agent through the `skill` tool. `$ARGUMENTS` is substituted at call time:
283
+
284
+ ```ts
285
+ import { query, defineSkill } from 'anyclaude-sdk'
286
+
287
+ query({
288
+ prompt, workspace, llm,
289
+ skills: [
290
+ defineSkill({
291
+ name: 'changelog',
292
+ description: 'Summarize git changes into a changelog entry',
293
+ instructions: 'Write a concise changelog entry for: $ARGUMENTS',
294
+ argumentHint: '<since>',
295
+ }),
296
+ ],
297
+ })
298
+ ```
299
+
300
+ You can also pass plain `Skill` objects, or `skills: true` to load `.claude/skills/*.md` from the workspace.
301
+
280
302
  ## Serverless & the "survivor"
281
303
 
282
304
  Run `query()` in a serverless function and stream `SDKMessage`s to the browser. For runs longer than the platform's time cap, checkpoint at a turn boundary and continue transparently in a fresh invocation:
package/dist/agent.js CHANGED
@@ -12,7 +12,7 @@ import { ALL_CLAUDE_CODE_TOOLS, toolByName, toolDefs } from './tools/index.js';
12
12
  import { task as taskTool } from './tools/task.js';
13
13
  import { askUserQuestion } from './tools/ask_user.js';
14
14
  import { loadMcpServers } from './mcp/index.js';
15
- import { runSlashCommand } from './commands/index.js';
15
+ import { runSlashCommand, BUILTIN_COMMANDS } from './commands/index.js';
16
16
  import { BackgroundTaskManager, BACKGROUND_TOOLS } from './background/index.js';
17
17
  import { Mailbox, TaskBoard, TEAM_TOOLS, TEAM_DISPATCH_TOOLS, coordinatorPrompt } from './team/index.js';
18
18
  import { MEMORY_TOOLS } from './memory/index.js';
@@ -395,9 +395,9 @@ export async function* runAgent(options) {
395
395
  mcp_servers: mcpStatuses,
396
396
  model: model ?? 'unknown',
397
397
  permissionMode,
398
- slash_commands: [],
398
+ slash_commands: [...new Set([...BUILTIN_COMMANDS, ...allCommands].map((c) => c.name.replace(/^\//, '')))],
399
399
  output_style: 'default',
400
- skills: [],
400
+ skills: skills.map((s) => s.name),
401
401
  agents: agents ? Object.keys(agents) : undefined,
402
402
  uuid: uuid(),
403
403
  session_id: sessionId,
@@ -22,11 +22,16 @@ export interface DexieFileSystemOptions {
22
22
  cwd?: string;
23
23
  /** Wipe all nodes on first open (fresh filesystem). */
24
24
  resetOnInit?: boolean;
25
+ /** Use an existing Dexie instance instead of opening one by name — lets the
26
+ * filesystem share a database your app already owns. It must declare a
27
+ * `nodes` table keyed by `path` (or be a fresh Dexie this FS can version). */
28
+ db?: unknown;
25
29
  }
26
30
  export declare class DexieFileSystem implements FileSystem {
27
31
  readonly cwd: string;
28
32
  private readonly dbName;
29
33
  private readonly resetOnInit;
34
+ private readonly injectedDb;
30
35
  private db;
31
36
  private opening;
32
37
  constructor(dbName?: string, options?: DexieFileSystemOptions);
package/dist/fs/dexie.js CHANGED
@@ -20,6 +20,7 @@ export class DexieFileSystem {
20
20
  this.dbName = dbName;
21
21
  this.cwd = options.cwd ?? '/';
22
22
  this.resetOnInit = options.resetOnInit ?? false;
23
+ this.injectedDb = options.db ?? null;
23
24
  }
24
25
  // ---- lifecycle ----
25
26
  async open() {
@@ -28,14 +29,25 @@ export class DexieFileSystem {
28
29
  if (this.opening)
29
30
  return this.opening;
30
31
  this.opening = (async () => {
31
- // @ts-ignore optional peer dependency, resolved at runtime
32
- const mod = await import('dexie');
33
- const Dexie = mod.default ?? mod;
34
- const db = new Dexie(this.dbName);
35
- db.version(1).stores({
36
- // primary key `path`, secondary index `parent`
37
- nodes: 'path, parent',
38
- });
32
+ let db;
33
+ if (this.injectedDb) {
34
+ // Use the caller's Dexie instance. Declare our schema if it isn't open
35
+ // yet; an already-open db is assumed to carry a compatible `nodes` table.
36
+ db = this.injectedDb;
37
+ if (!db.isOpen?.()) {
38
+ db.version(1).stores({ nodes: 'path, parent' });
39
+ }
40
+ }
41
+ else {
42
+ // @ts-ignore optional peer dependency, resolved at runtime
43
+ const mod = await import('dexie');
44
+ const Dexie = mod.default ?? mod;
45
+ db = new Dexie(this.dbName);
46
+ db.version(1).stores({
47
+ // primary key `path`, secondary index `parent`
48
+ nodes: 'path, parent',
49
+ });
50
+ }
39
51
  this.db = db;
40
52
  if (this.resetOnInit)
41
53
  await db.nodes.clear();
@@ -0,0 +1,24 @@
1
+ import type { Skill } from './types.js';
2
+ export interface DefineSkillSpec {
3
+ /** Skill name — used as the slash-command name and the `skill` tool lookup key. */
4
+ name: string;
5
+ /** One-line description of what the skill does (shown to the model + in /help). */
6
+ description: string;
7
+ /** The skill's instructions / prompt template. `$ARGUMENTS` is substituted at call time. */
8
+ instructions: string;
9
+ /** Optional argument hint, e.g. "<file>" or "<topic>". */
10
+ argumentHint?: string;
11
+ }
12
+ /**
13
+ * Define a skill programmatically:
14
+ *
15
+ * query({ skills: [defineSkill({
16
+ * name: 'changelog',
17
+ * description: 'Summarize git changes into a changelog entry',
18
+ * instructions: 'Write a concise changelog entry for: $ARGUMENTS',
19
+ * })] })
20
+ *
21
+ * It is registered as a `/changelog` slash command and is invokable by the agent
22
+ * through the `skill` tool. (You can also pass plain `Skill` objects directly.)
23
+ */
24
+ export declare function defineSkill(spec: DefineSkillSpec): Skill;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Define a skill programmatically:
3
+ *
4
+ * query({ skills: [defineSkill({
5
+ * name: 'changelog',
6
+ * description: 'Summarize git changes into a changelog entry',
7
+ * instructions: 'Write a concise changelog entry for: $ARGUMENTS',
8
+ * })] })
9
+ *
10
+ * It is registered as a `/changelog` slash command and is invokable by the agent
11
+ * through the `skill` tool. (You can also pass plain `Skill` objects directly.)
12
+ */
13
+ export function defineSkill(spec) {
14
+ const name = String(spec.name ?? '').trim();
15
+ if (!name)
16
+ throw new Error('defineSkill: `name` is required.');
17
+ if (!/^[A-Za-z0-9][\w:-]*$/.test(name)) {
18
+ throw new Error(`defineSkill: invalid name "${name}" (use letters, digits, _ - :).`);
19
+ }
20
+ const instructions = String(spec.instructions ?? '');
21
+ if (!instructions.trim())
22
+ throw new Error(`defineSkill("${name}"): \`instructions\` is required.`);
23
+ return {
24
+ name,
25
+ description: String(spec.description ?? '').trim(),
26
+ body: instructions,
27
+ ...(spec.argumentHint ? { argumentHint: String(spec.argumentHint) } : {}),
28
+ };
29
+ }
@@ -2,3 +2,4 @@ export type { Skill } from './types.js';
2
2
  export { parseSkill } from './parse.js';
3
3
  export { loadSkillsFromFs, skillsToCommands, applySkillArgs } from './load.js';
4
4
  export { skill } from './tool.js';
5
+ export { defineSkill, type DefineSkillSpec } from './define.js';
@@ -3,3 +3,4 @@
3
3
  export { parseSkill } from './parse.js';
4
4
  export { loadSkillsFromFs, skillsToCommands, applySkillArgs } from './load.js';
5
5
  export { skill } from './tool.js';
6
+ export { defineSkill } from './define.js';
@@ -23,6 +23,11 @@ export { defineTool, type DefineToolSpec } from './define.js';
23
23
  export { askUserQuestion } from './ask_user.js';
24
24
  /** Every built-in Claude Code tool, ready to pass to `query()`. */
25
25
  export declare const ALL_CLAUDE_CODE_TOOLS: Tool[];
26
+ /** Built-in tools that operate on the workspace (filesystem + shell). Pass as
27
+ * `query({ clientTools: WORKSPACE_TOOL_NAMES })` to execute them on the HOST
28
+ * (e.g. a browser WebContainer or IndexedDB FS) instead of server-side. Pair
29
+ * with anyclaude-react's `createWorkspaceClientTools(workspace)`. */
30
+ export declare const WORKSPACE_TOOL_NAMES: readonly ["bash", "write_file", "read_file", "edit_file", "multi_edit", "delete_file", "list_files", "glob", "grep"];
26
31
  /** Extract the OpenAI-shape definitions to send to the LLM. */
27
32
  export declare function toolDefs(tools: Tool[]): ToolDef[];
28
33
  /** Build a name→tool lookup for dispatching tool calls. */
@@ -36,6 +36,21 @@ export const ALL_CLAUDE_CODE_TOOLS = [
36
36
  toolSearch,
37
37
  config,
38
38
  ];
39
+ /** Built-in tools that operate on the workspace (filesystem + shell). Pass as
40
+ * `query({ clientTools: WORKSPACE_TOOL_NAMES })` to execute them on the HOST
41
+ * (e.g. a browser WebContainer or IndexedDB FS) instead of server-side. Pair
42
+ * with anyclaude-react's `createWorkspaceClientTools(workspace)`. */
43
+ export const WORKSPACE_TOOL_NAMES = [
44
+ 'bash',
45
+ 'write_file',
46
+ 'read_file',
47
+ 'edit_file',
48
+ 'multi_edit',
49
+ 'delete_file',
50
+ 'list_files',
51
+ 'glob',
52
+ 'grep',
53
+ ];
39
54
  /** Extract the OpenAI-shape definitions to send to the LLM. */
40
55
  export function toolDefs(tools) {
41
56
  return tools.map((t) => t.def);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anyclaude-sdk",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Standalone, browser-compatible SDK providing Claude Code agent capabilities (tools, tool loop, multi-turn, MCP, sub-agents, sessions) against any OpenAI/Anthropic-compatible LLM endpoint. Runs in the browser (WebContainer), Node, and Bun — no backend required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",