fourmis-agents-sdk 0.3.0 → 0.4.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 (102) hide show
  1. package/dist/agent-loop.d.ts +21 -3
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +294 -90
  4. package/dist/agents/index.js +2798 -1857
  5. package/dist/agents/task-manager.js +15 -0
  6. package/dist/agents/tools.d.ts.map +1 -1
  7. package/dist/agents/tools.js +2798 -1857
  8. package/dist/agents/types.d.ts +4 -0
  9. package/dist/agents/types.d.ts.map +1 -1
  10. package/dist/api.d.ts +8 -5
  11. package/dist/api.d.ts.map +1 -1
  12. package/dist/api.js +2394 -886
  13. package/dist/auth/gemini-oauth.js +15 -0
  14. package/dist/auth/login-openai.js +15 -0
  15. package/dist/auth/openai-oauth.js +15 -0
  16. package/dist/hooks.d.ts +19 -1
  17. package/dist/hooks.d.ts.map +1 -1
  18. package/dist/hooks.js +42 -2
  19. package/dist/index.d.ts +10 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +2407 -887
  22. package/dist/mcp/client.d.ts +7 -0
  23. package/dist/mcp/client.d.ts.map +1 -1
  24. package/dist/mcp/client.js +146 -12
  25. package/dist/mcp/index.js +146 -12
  26. package/dist/mcp/server.js +15 -0
  27. package/dist/mcp/types.d.ts +19 -1
  28. package/dist/mcp/types.d.ts.map +1 -1
  29. package/dist/memory/index.js +15 -0
  30. package/dist/memory/memory-handler.js +15 -0
  31. package/dist/permissions.d.ts.map +1 -1
  32. package/dist/permissions.js +22 -3
  33. package/dist/providers/anthropic.d.ts.map +1 -1
  34. package/dist/providers/anthropic.js +56 -2
  35. package/dist/providers/gemini.js +15 -0
  36. package/dist/providers/openai.js +15 -0
  37. package/dist/providers/registry.js +56 -2
  38. package/dist/providers/types.d.ts +4 -1
  39. package/dist/providers/types.d.ts.map +1 -1
  40. package/dist/query.d.ts +21 -2
  41. package/dist/query.d.ts.map +1 -1
  42. package/dist/query.js +84 -1
  43. package/dist/settings.js +15 -0
  44. package/dist/skills/frontmatter.d.ts +15 -0
  45. package/dist/skills/frontmatter.d.ts.map +1 -0
  46. package/dist/skills/frontmatter.js +66 -0
  47. package/dist/skills/index.d.ts +8 -0
  48. package/dist/skills/index.d.ts.map +1 -0
  49. package/dist/skills/index.js +326 -0
  50. package/dist/skills/skills.d.ts +94 -0
  51. package/dist/skills/skills.d.ts.map +1 -0
  52. package/dist/skills/skills.js +324 -0
  53. package/dist/tools/ask-user-question.d.ts +7 -0
  54. package/dist/tools/ask-user-question.d.ts.map +1 -0
  55. package/dist/tools/ask-user-question.js +63 -0
  56. package/dist/tools/bash.d.ts.map +1 -1
  57. package/dist/tools/bash.js +62 -2
  58. package/dist/tools/config.d.ts +7 -0
  59. package/dist/tools/config.d.ts.map +1 -0
  60. package/dist/tools/config.js +129 -0
  61. package/dist/tools/edit.js +15 -0
  62. package/dist/tools/exit-plan-mode.d.ts +7 -0
  63. package/dist/tools/exit-plan-mode.d.ts.map +1 -0
  64. package/dist/tools/exit-plan-mode.js +49 -0
  65. package/dist/tools/glob.js +15 -0
  66. package/dist/tools/grep.js +15 -0
  67. package/dist/tools/index.d.ts +7 -0
  68. package/dist/tools/index.d.ts.map +1 -1
  69. package/dist/tools/index.js +521 -9
  70. package/dist/tools/mcp-resources.js +15 -0
  71. package/dist/tools/notebook-edit.d.ts +7 -0
  72. package/dist/tools/notebook-edit.d.ts.map +1 -0
  73. package/dist/tools/notebook-edit.js +98 -0
  74. package/dist/tools/presets.d.ts +2 -1
  75. package/dist/tools/presets.d.ts.map +1 -1
  76. package/dist/tools/presets.js +37 -4
  77. package/dist/tools/read.d.ts.map +1 -1
  78. package/dist/tools/read.js +27 -1
  79. package/dist/tools/registry.d.ts +2 -0
  80. package/dist/tools/registry.d.ts.map +1 -1
  81. package/dist/tools/registry.js +25 -0
  82. package/dist/tools/todo-write.d.ts +7 -0
  83. package/dist/tools/todo-write.d.ts.map +1 -0
  84. package/dist/tools/todo-write.js +84 -0
  85. package/dist/tools/web-fetch.d.ts +6 -0
  86. package/dist/tools/web-fetch.d.ts.map +1 -0
  87. package/dist/tools/web-fetch.js +100 -0
  88. package/dist/tools/web-search.d.ts +7 -0
  89. package/dist/tools/web-search.d.ts.map +1 -0
  90. package/dist/tools/web-search.js +93 -0
  91. package/dist/tools/write.js +15 -0
  92. package/dist/types.d.ts +360 -42
  93. package/dist/types.d.ts.map +1 -1
  94. package/dist/types.js +15 -0
  95. package/dist/utils/cost.js +15 -0
  96. package/dist/utils/session-store.d.ts +1 -1
  97. package/dist/utils/session-store.d.ts.map +1 -1
  98. package/dist/utils/session-store.js +64 -2
  99. package/dist/utils/system-prompt.d.ts +4 -0
  100. package/dist/utils/system-prompt.d.ts.map +1 -1
  101. package/dist/utils/system-prompt.js +326 -6
  102. package/package.json +4 -2
@@ -1,5 +1,20 @@
1
1
  // @bun
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
2
4
  var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
3
18
  var __export = (target, all) => {
4
19
  for (var name in all)
5
20
  __defProp(target, name, {
@@ -18,6 +33,16 @@ class ToolRegistry {
18
33
  register(tool) {
19
34
  this.tools.set(tool.name, tool);
20
35
  }
36
+ unregister(name) {
37
+ this.tools.delete(name);
38
+ }
39
+ clearByPrefix(prefix) {
40
+ for (const name of this.tools.keys()) {
41
+ if (name.startsWith(prefix)) {
42
+ this.tools.delete(name);
43
+ }
44
+ }
45
+ }
21
46
  get(name) {
22
47
  return this.tools.get(name);
23
48
  }
@@ -51,16 +76,34 @@ class ToolRegistry {
51
76
  // src/tools/presets.ts
52
77
  var PRESETS = {
53
78
  coding: ["Bash", "Read", "Write", "Edit", "Glob", "Grep"],
79
+ claude_code: [
80
+ "Bash",
81
+ "Read",
82
+ "Write",
83
+ "Edit",
84
+ "Glob",
85
+ "Grep",
86
+ "NotebookEdit",
87
+ "WebFetch",
88
+ "WebSearch",
89
+ "TodoWrite",
90
+ "Config",
91
+ "AskUserQuestion",
92
+ "ExitPlanMode"
93
+ ],
54
94
  readonly: ["Read", "Glob", "Grep"],
55
95
  minimal: ["Read", "Write", "Edit", "Glob", "Grep"]
56
96
  };
57
97
  function resolveToolNames(tools) {
58
98
  if (!tools)
59
- return PRESETS.coding;
60
- if (typeof tools === "string") {
61
- return PRESETS[tools] ?? [tools];
99
+ return PRESETS.claude_code;
100
+ if (Array.isArray(tools)) {
101
+ return tools;
62
102
  }
63
- return tools;
103
+ if (tools.type === "preset") {
104
+ return PRESETS[tools.preset] ?? PRESETS.claude_code;
105
+ }
106
+ throw new Error("Invalid tools option. Expected string[] or { type: 'preset', preset: 'claude_code' }.");
64
107
  }
65
108
 
66
109
  // src/tools/bash.ts
@@ -84,17 +127,58 @@ var BashTool = {
84
127
  timeout: {
85
128
  type: "number",
86
129
  description: "Timeout in milliseconds (max 600000)"
130
+ },
131
+ run_in_background: {
132
+ type: "boolean",
133
+ description: "Run command asynchronously and return immediately."
134
+ },
135
+ dangerouslyDisableSandbox: {
136
+ type: "boolean",
137
+ description: "If true, explicitly request unsandboxed execution."
138
+ },
139
+ _simulatedSedEdit: {
140
+ type: "object",
141
+ properties: {
142
+ filePath: { type: "string" },
143
+ newContent: { type: "string" }
144
+ },
145
+ description: "Internal field for precomputed edit previews."
87
146
  }
88
147
  },
89
148
  required: ["command"]
90
149
  },
91
150
  async execute(input, ctx) {
92
- const { command, timeout: timeoutMs, description } = input;
151
+ const {
152
+ command,
153
+ timeout: timeoutMs,
154
+ run_in_background,
155
+ description,
156
+ dangerouslyDisableSandbox,
157
+ _simulatedSedEdit
158
+ } = input;
93
159
  if (!command || typeof command !== "string") {
94
160
  return { content: "Error: command is required", isError: true };
95
161
  }
96
162
  const timeout = Math.min(timeoutMs ?? DEFAULT_TIMEOUT, MAX_TIMEOUT);
97
163
  try {
164
+ if (run_in_background) {
165
+ const proc2 = Bun.spawn(["bash", "-c", command], {
166
+ cwd: ctx.cwd,
167
+ stdout: "ignore",
168
+ stderr: "ignore",
169
+ stdin: "ignore",
170
+ env: { ...process.env, ...ctx.env }
171
+ });
172
+ return {
173
+ content: `Background command started (pid ${proc2.pid ?? "unknown"}).`,
174
+ metadata: {
175
+ pid: proc2.pid ?? null,
176
+ run_in_background: true,
177
+ dangerouslyDisableSandbox: dangerouslyDisableSandbox === true,
178
+ hasSimulatedSedEdit: !!_simulatedSedEdit
179
+ }
180
+ };
181
+ }
98
182
  const proc = Bun.spawn(["bash", "-c", command], {
99
183
  cwd: ctx.cwd,
100
184
  stdout: "pipe",
@@ -126,7 +210,11 @@ var BashTool = {
126
210
  return {
127
211
  content: output,
128
212
  isError: exitCode !== 0 ? true : undefined,
129
- metadata: { exitCode }
213
+ metadata: {
214
+ exitCode,
215
+ dangerouslyDisableSandbox: dangerouslyDisableSandbox === true,
216
+ hasSimulatedSedEdit: !!_simulatedSedEdit
217
+ }
130
218
  };
131
219
  } catch (err) {
132
220
  const message = err instanceof Error ? err.message : String(err);
@@ -155,12 +243,17 @@ var ReadTool = {
155
243
  limit: {
156
244
  type: "number",
157
245
  description: "Number of lines to read"
246
+ },
247
+ pages: {
248
+ type: "array",
249
+ items: { type: "number" },
250
+ description: "Optional PDF page numbers (1-based)."
158
251
  }
159
252
  },
160
253
  required: ["file_path"]
161
254
  },
162
255
  async execute(input, ctx) {
163
- const { file_path, offset, limit } = input;
256
+ const { file_path, offset, limit, pages } = input;
164
257
  if (!file_path) {
165
258
  return { content: "Error: file_path is required", isError: true };
166
259
  }
@@ -171,6 +264,12 @@ var ReadTool = {
171
264
  if (!exists) {
172
265
  return { content: `Error: File not found: ${resolvedPath}`, isError: true };
173
266
  }
267
+ if (Array.isArray(pages) && pages.length > 0 && resolvedPath.toLowerCase().endsWith(".pdf")) {
268
+ return {
269
+ content: "Error: PDF page extraction is not implemented in this runtime.",
270
+ isError: true
271
+ };
272
+ }
174
273
  const text = await file.text();
175
274
  const lines = text.split(`
176
275
  `);
@@ -558,6 +657,405 @@ async function collectFiles(dir, globPattern) {
558
657
  }
559
658
  return files;
560
659
  }
660
+
661
+ // src/tools/notebook-edit.ts
662
+ import { readFile, writeFile } from "fs/promises";
663
+ function toSourceLines(text) {
664
+ const lines = text.split(`
665
+ `);
666
+ return lines.map((line, idx) => idx < lines.length - 1 ? `${line}
667
+ ` : line);
668
+ }
669
+ var NotebookEditTool = {
670
+ name: "NotebookEdit",
671
+ description: "Edit a specific Jupyter notebook cell by id or index.",
672
+ inputSchema: {
673
+ type: "object",
674
+ properties: {
675
+ notebook_path: { type: "string", description: "Path to .ipynb file." },
676
+ cell_id: { type: "string", description: "Cell id to edit." },
677
+ cell_index: { type: "number", description: "Cell index to edit if id is not provided." },
678
+ new_source: { type: "string", description: "New cell source content." }
679
+ },
680
+ required: ["notebook_path", "new_source"]
681
+ },
682
+ async execute(input, ctx) {
683
+ const {
684
+ notebook_path,
685
+ cell_id,
686
+ cell_index,
687
+ new_source
688
+ } = input ?? {};
689
+ if (!notebook_path)
690
+ return { content: "Error: notebook_path is required", isError: true };
691
+ if (new_source === undefined)
692
+ return { content: "Error: new_source is required", isError: true };
693
+ const filePath = notebook_path.startsWith("/") ? notebook_path : `${ctx.cwd}/${notebook_path}`;
694
+ try {
695
+ const raw = await readFile(filePath, "utf-8");
696
+ const notebook = JSON.parse(raw);
697
+ if (!Array.isArray(notebook.cells)) {
698
+ return { content: "Error: notebook has no cells array", isError: true };
699
+ }
700
+ let targetIndex = -1;
701
+ if (cell_id) {
702
+ targetIndex = notebook.cells.findIndex((c) => c.id === cell_id);
703
+ } else if (typeof cell_index === "number") {
704
+ targetIndex = cell_index;
705
+ } else {
706
+ targetIndex = 0;
707
+ }
708
+ if (targetIndex < 0 || targetIndex >= notebook.cells.length) {
709
+ return {
710
+ content: `Error: cell not found (id=${cell_id ?? "n/a"}, index=${String(cell_index ?? "n/a")})`,
711
+ isError: true
712
+ };
713
+ }
714
+ const cell = notebook.cells[targetIndex];
715
+ cell.source = toSourceLines(new_source);
716
+ await writeFile(filePath, JSON.stringify(notebook, null, 2) + `
717
+ `, "utf-8");
718
+ return {
719
+ content: `Updated notebook cell ${targetIndex} in ${filePath}`
720
+ };
721
+ } catch (err) {
722
+ const message = err instanceof Error ? err.message : String(err);
723
+ return { content: `Error editing notebook: ${message}`, isError: true };
724
+ }
725
+ }
726
+ };
727
+
728
+ // src/tools/web-fetch.ts
729
+ var DEFAULT_TIMEOUT_MS = 20000;
730
+ var MAX_OUTPUT = 80000;
731
+ var WebFetchTool = {
732
+ name: "WebFetch",
733
+ description: "Fetches a URL and returns response text.",
734
+ inputSchema: {
735
+ type: "object",
736
+ properties: {
737
+ url: {
738
+ type: "string",
739
+ description: "The URL to fetch."
740
+ },
741
+ prompt: {
742
+ type: "string",
743
+ description: "Optional fetch intent/instructions."
744
+ },
745
+ timeout_ms: {
746
+ type: "number",
747
+ description: "Timeout in milliseconds (default 20000)."
748
+ },
749
+ max_length: {
750
+ type: "number",
751
+ description: "Maximum output length (default 80000)."
752
+ }
753
+ },
754
+ required: ["url"]
755
+ },
756
+ async execute(input) {
757
+ const { url, timeout_ms, max_length } = input ?? {};
758
+ if (!url)
759
+ return { content: "Error: url is required", isError: true };
760
+ const timeout = Math.max(1000, timeout_ms ?? DEFAULT_TIMEOUT_MS);
761
+ const outLimit = Math.max(1000, max_length ?? MAX_OUTPUT);
762
+ const controller = new AbortController;
763
+ const timer = setTimeout(() => controller.abort(), timeout);
764
+ try {
765
+ const res = await fetch(url, {
766
+ method: "GET",
767
+ signal: controller.signal,
768
+ headers: {
769
+ "user-agent": "fourmis-agent-sdk/1.0"
770
+ }
771
+ });
772
+ const contentType = res.headers.get("content-type") ?? "unknown";
773
+ let body = await res.text();
774
+ if (body.length > outLimit) {
775
+ body = body.slice(0, outLimit) + `
776
+ ... (truncated)`;
777
+ }
778
+ return {
779
+ content: [
780
+ `Status: ${res.status} ${res.statusText}`,
781
+ `Content-Type: ${contentType}`,
782
+ "",
783
+ body
784
+ ].join(`
785
+ `),
786
+ isError: res.ok ? undefined : true
787
+ };
788
+ } catch (err) {
789
+ const message = err instanceof Error ? err.message : String(err);
790
+ return { content: `Error fetching URL: ${message}`, isError: true };
791
+ } finally {
792
+ clearTimeout(timer);
793
+ }
794
+ }
795
+ };
796
+
797
+ // src/tools/web-search.ts
798
+ var SEARCH_ENDPOINT = "https://duckduckgo.com/html/";
799
+ function stripTags(input) {
800
+ return input.replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").trim();
801
+ }
802
+ var WebSearchTool = {
803
+ name: "WebSearch",
804
+ description: "Searches the web and returns top result links.",
805
+ inputSchema: {
806
+ type: "object",
807
+ properties: {
808
+ query: {
809
+ type: "string",
810
+ description: "Search query."
811
+ },
812
+ max_results: {
813
+ type: "number",
814
+ description: "Maximum results to return (default 5)."
815
+ }
816
+ },
817
+ required: ["query"]
818
+ },
819
+ async execute(input) {
820
+ const { query, max_results } = input ?? {};
821
+ if (!query) {
822
+ return { content: "Error: query is required", isError: true };
823
+ }
824
+ const limit = Math.max(1, Math.min(20, max_results ?? 5));
825
+ try {
826
+ const url = `${SEARCH_ENDPOINT}?q=${encodeURIComponent(query)}`;
827
+ const res = await fetch(url, {
828
+ headers: {
829
+ "user-agent": "fourmis-agent-sdk/1.0"
830
+ }
831
+ });
832
+ if (!res.ok) {
833
+ return {
834
+ content: `Error searching web: ${res.status} ${res.statusText}`,
835
+ isError: true
836
+ };
837
+ }
838
+ const html = await res.text();
839
+ const matches = [...html.matchAll(/<a[^>]*class="result__a"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/g)];
840
+ if (matches.length === 0) {
841
+ return { content: "No search results found." };
842
+ }
843
+ const lines = [];
844
+ for (let i = 0;i < Math.min(limit, matches.length); i++) {
845
+ const href = stripTags(matches[i][1]);
846
+ const title = stripTags(matches[i][2]);
847
+ lines.push(`${i + 1}. ${title}
848
+ ${href}`);
849
+ }
850
+ return { content: lines.join(`
851
+ `) };
852
+ } catch (err) {
853
+ const message = err instanceof Error ? err.message : String(err);
854
+ return { content: `Error searching web: ${message}`, isError: true };
855
+ }
856
+ }
857
+ };
858
+
859
+ // src/tools/ask-user-question.ts
860
+ var AskUserQuestionTool = {
861
+ name: "AskUserQuestion",
862
+ description: "Ask the user a clarifying question and wait for their response.",
863
+ inputSchema: {
864
+ type: "object",
865
+ properties: {
866
+ question: {
867
+ type: "string",
868
+ description: "Question to ask the user."
869
+ },
870
+ options: {
871
+ type: "array",
872
+ items: { type: "string" },
873
+ description: "Optional fixed choices."
874
+ }
875
+ },
876
+ required: ["question"]
877
+ },
878
+ async execute(input) {
879
+ const { question, options } = input ?? {};
880
+ if (!question) {
881
+ return { content: "Error: question is required", isError: true };
882
+ }
883
+ const choices = Array.isArray(options) && options.length > 0 ? ` Choices: ${options.join(" | ")}` : "";
884
+ return {
885
+ content: `User interaction is not available in this runtime. Unanswered question: ${question}.${choices}`,
886
+ isError: true
887
+ };
888
+ }
889
+ };
890
+
891
+ // src/tools/todo-write.ts
892
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
893
+ import { dirname as dirname2, join } from "path";
894
+ var TodoWriteTool = {
895
+ name: "TodoWrite",
896
+ description: "Write/update task todo items for the current session.",
897
+ inputSchema: {
898
+ type: "object",
899
+ properties: {
900
+ todos: {
901
+ type: "array",
902
+ items: {
903
+ type: "object",
904
+ properties: {
905
+ content: { type: "string" },
906
+ status: { type: "string", enum: ["pending", "in_progress", "completed"] },
907
+ activeForm: { type: "string" }
908
+ },
909
+ required: ["content", "status"]
910
+ }
911
+ }
912
+ },
913
+ required: ["todos"]
914
+ },
915
+ async execute(input, ctx) {
916
+ const { todos } = input ?? {};
917
+ if (!Array.isArray(todos)) {
918
+ return { content: "Error: todos must be an array", isError: true };
919
+ }
920
+ for (const todo of todos) {
921
+ if (!todo?.content || !todo?.status) {
922
+ return { content: "Error: each todo requires content and status", isError: true };
923
+ }
924
+ }
925
+ const filePath = join(ctx.cwd, ".claude", "todos.json");
926
+ try {
927
+ await mkdir2(dirname2(filePath), { recursive: true });
928
+ const payload = {
929
+ updatedAt: new Date().toISOString(),
930
+ todos
931
+ };
932
+ await writeFile2(filePath, JSON.stringify(payload, null, 2) + `
933
+ `, "utf-8");
934
+ return {
935
+ content: `Saved ${todos.length} todo item(s) to ${filePath}`
936
+ };
937
+ } catch (err) {
938
+ const message = err instanceof Error ? err.message : String(err);
939
+ return { content: `Error writing todos: ${message}`, isError: true };
940
+ }
941
+ }
942
+ };
943
+
944
+ // src/tools/config.ts
945
+ import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
946
+ import { join as join2, dirname as dirname3 } from "path";
947
+ function scopePath(cwd, scope) {
948
+ if (scope === "project")
949
+ return join2(cwd, ".claude", "settings.json");
950
+ return join2(cwd, ".claude", "settings.local.json");
951
+ }
952
+ function setByPath(obj, keyPath, value) {
953
+ const keys = keyPath.split(".").filter(Boolean);
954
+ if (keys.length === 0)
955
+ return;
956
+ let current = obj;
957
+ for (let i = 0;i < keys.length - 1; i++) {
958
+ const key = keys[i];
959
+ const next = current[key];
960
+ if (!next || typeof next !== "object" || Array.isArray(next)) {
961
+ current[key] = {};
962
+ }
963
+ current = current[key];
964
+ }
965
+ current[keys[keys.length - 1]] = value;
966
+ }
967
+ function getByPath(obj, keyPath) {
968
+ const keys = keyPath.split(".").filter(Boolean);
969
+ let current = obj;
970
+ for (const key of keys) {
971
+ if (!current || typeof current !== "object" || Array.isArray(current))
972
+ return;
973
+ current = current[key];
974
+ }
975
+ return current;
976
+ }
977
+ var ConfigTool = {
978
+ name: "Config",
979
+ description: "Read or update .claude settings values.",
980
+ inputSchema: {
981
+ type: "object",
982
+ properties: {
983
+ action: {
984
+ type: "string",
985
+ enum: ["get", "set", "list"]
986
+ },
987
+ key: {
988
+ type: "string",
989
+ description: "Dot-path key (for get/set)."
990
+ },
991
+ value: {
992
+ description: "Value for set action."
993
+ },
994
+ scope: {
995
+ type: "string",
996
+ enum: ["local", "project"]
997
+ }
998
+ },
999
+ required: ["action"]
1000
+ },
1001
+ async execute(input, ctx) {
1002
+ const {
1003
+ action,
1004
+ key,
1005
+ value,
1006
+ scope = "local"
1007
+ } = input ?? {};
1008
+ if (!action) {
1009
+ return { content: "Error: action is required", isError: true };
1010
+ }
1011
+ const filePath = scopePath(ctx.cwd, scope);
1012
+ let data = {};
1013
+ try {
1014
+ const raw = await readFile2(filePath, "utf-8");
1015
+ data = JSON.parse(raw);
1016
+ } catch {
1017
+ data = {};
1018
+ }
1019
+ if (action === "list") {
1020
+ return { content: JSON.stringify(data, null, 2) };
1021
+ }
1022
+ if (!key) {
1023
+ return { content: "Error: key is required for get/set", isError: true };
1024
+ }
1025
+ if (action === "get") {
1026
+ const out = getByPath(data, key);
1027
+ return { content: out === undefined ? "undefined" : JSON.stringify(out, null, 2) };
1028
+ }
1029
+ setByPath(data, key, value);
1030
+ try {
1031
+ await mkdir3(dirname3(filePath), { recursive: true });
1032
+ await writeFile3(filePath, JSON.stringify(data, null, 2) + `
1033
+ `, "utf-8");
1034
+ return { content: `Updated ${key} in ${filePath}` };
1035
+ } catch (err) {
1036
+ const message = err instanceof Error ? err.message : String(err);
1037
+ return { content: `Error writing config: ${message}`, isError: true };
1038
+ }
1039
+ }
1040
+ };
1041
+
1042
+ // src/tools/exit-plan-mode.ts
1043
+ var ExitPlanModeTool = {
1044
+ name: "ExitPlanMode",
1045
+ description: "Exit plan mode and resume normal execution permissions.",
1046
+ inputSchema: {
1047
+ type: "object",
1048
+ properties: {}
1049
+ },
1050
+ async execute() {
1051
+ return {
1052
+ content: "Exiting plan mode.",
1053
+ metadata: {
1054
+ setPermissionMode: "default"
1055
+ }
1056
+ };
1057
+ }
1058
+ };
561
1059
  // src/tools/index.ts
562
1060
  var ALL_TOOLS = {
563
1061
  Bash: BashTool,
@@ -565,7 +1063,14 @@ var ALL_TOOLS = {
565
1063
  Write: WriteTool,
566
1064
  Edit: EditTool,
567
1065
  Glob: GlobTool,
568
- Grep: GrepTool
1066
+ Grep: GrepTool,
1067
+ NotebookEdit: NotebookEditTool,
1068
+ WebFetch: WebFetchTool,
1069
+ WebSearch: WebSearchTool,
1070
+ AskUserQuestion: AskUserQuestionTool,
1071
+ TodoWrite: TodoWriteTool,
1072
+ Config: ConfigTool,
1073
+ ExitPlanMode: ExitPlanModeTool
569
1074
  };
570
1075
  function buildToolRegistry(toolNames, allowedTools, disallowedTools) {
571
1076
  const registry = new ToolRegistry;
@@ -583,11 +1088,18 @@ export {
583
1088
  resolveToolNames,
584
1089
  buildToolRegistry,
585
1090
  WriteTool,
1091
+ WebSearchTool,
1092
+ WebFetchTool,
586
1093
  ToolRegistry,
1094
+ TodoWriteTool,
587
1095
  ReadTool,
588
1096
  PRESETS,
1097
+ NotebookEditTool,
589
1098
  GrepTool,
590
1099
  GlobTool,
1100
+ ExitPlanModeTool,
591
1101
  EditTool,
592
- BashTool
1102
+ ConfigTool,
1103
+ BashTool,
1104
+ AskUserQuestionTool
593
1105
  };
@@ -1,5 +1,20 @@
1
1
  // @bun
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
2
4
  var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
3
18
  var __export = (target, all) => {
4
19
  for (var name in all)
5
20
  __defProp(target, name, {
@@ -0,0 +1,7 @@
1
+ /**
2
+ * NotebookEdit tool.
3
+ * Edits code/markdown cell content in a .ipynb notebook.
4
+ */
5
+ import type { ToolImplementation } from "./registry.js";
6
+ export declare const NotebookEditTool: ToolImplementation;
7
+ //# sourceMappingURL=notebook-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notebook-edit.d.ts","sourceRoot":"","sources":["../../src/tools/notebook-edit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAA2B,MAAM,eAAe,CAAC;AAkBjF,eAAO,MAAM,gBAAgB,EAAE,kBAqE9B,CAAC"}