@warlock.js/ai-workspace 5.30.0 → 5.31.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 (114) hide show
  1. package/CHANGELOG.md +46 -2
  2. package/README.md +34 -21
  3. package/cjs/index.cjs +3116 -309
  4. package/cjs/index.cjs.map +1 -1
  5. package/esm/backends/local.d.mts.map +1 -1
  6. package/esm/backends/local.mjs +165 -27
  7. package/esm/backends/local.mjs.map +1 -1
  8. package/esm/backends/mock.d.mts +11 -5
  9. package/esm/backends/mock.d.mts.map +1 -1
  10. package/esm/backends/mock.mjs +34 -0
  11. package/esm/backends/mock.mjs.map +1 -1
  12. package/esm/contracts/index.d.mts +3 -3
  13. package/esm/contracts/tool-io.type.d.mts +202 -4
  14. package/esm/contracts/tool-io.type.d.mts.map +1 -1
  15. package/esm/contracts/workspace-backend.contract.d.mts +61 -1
  16. package/esm/contracts/workspace-backend.contract.d.mts.map +1 -1
  17. package/esm/contracts/workspace-ops.contract.d.mts +32 -3
  18. package/esm/contracts/workspace-ops.contract.d.mts.map +1 -1
  19. package/esm/contracts/workspace-policy.type.d.mts +133 -12
  20. package/esm/contracts/workspace-policy.type.d.mts.map +1 -1
  21. package/esm/contracts/workspace.contract.d.mts +63 -9
  22. package/esm/contracts/workspace.contract.d.mts.map +1 -1
  23. package/esm/errors.d.mts +79 -5
  24. package/esm/errors.d.mts.map +1 -1
  25. package/esm/errors.mjs +22 -1
  26. package/esm/errors.mjs.map +1 -1
  27. package/esm/index.d.mts +13 -5
  28. package/esm/index.mjs +10 -2
  29. package/esm/ops.d.mts +21 -2
  30. package/esm/ops.d.mts.map +1 -1
  31. package/esm/ops.mjs +230 -64
  32. package/esm/ops.mjs.map +1 -1
  33. package/esm/policy/jail.mjs +73 -0
  34. package/esm/policy/jail.mjs.map +1 -0
  35. package/esm/policy/policy.d.mts +25 -15
  36. package/esm/policy/policy.d.mts.map +1 -1
  37. package/esm/policy/policy.mjs +61 -85
  38. package/esm/policy/policy.mjs.map +1 -1
  39. package/esm/policy/shell-check.d.mts +64 -0
  40. package/esm/policy/shell-check.d.mts.map +1 -0
  41. package/esm/policy/shell-check.mjs +627 -0
  42. package/esm/policy/shell-check.mjs.map +1 -0
  43. package/esm/policy/shell-parser.mjs +802 -0
  44. package/esm/policy/shell-parser.mjs.map +1 -0
  45. package/esm/policy/tokenize-command.d.mts +63 -0
  46. package/esm/policy/tokenize-command.d.mts.map +1 -0
  47. package/esm/policy/tokenize-command.mjs +75 -23
  48. package/esm/policy/tokenize-command.mjs.map +1 -1
  49. package/esm/shell-jobs.d.mts +45 -0
  50. package/esm/shell-jobs.d.mts.map +1 -0
  51. package/esm/shell-jobs.mjs +247 -0
  52. package/esm/shell-jobs.mjs.map +1 -0
  53. package/esm/todos.d.mts +22 -0
  54. package/esm/todos.d.mts.map +1 -0
  55. package/esm/todos.mjs +73 -0
  56. package/esm/todos.mjs.map +1 -0
  57. package/esm/tools/edit-file.d.mts.map +1 -1
  58. package/esm/tools/edit-file.mjs +2 -1
  59. package/esm/tools/edit-file.mjs.map +1 -1
  60. package/esm/tools/glob.d.mts.map +1 -1
  61. package/esm/tools/glob.mjs +2 -1
  62. package/esm/tools/glob.mjs.map +1 -1
  63. package/esm/tools/grep.d.mts.map +1 -1
  64. package/esm/tools/grep.mjs +2 -1
  65. package/esm/tools/grep.mjs.map +1 -1
  66. package/esm/tools/json-schemas.mjs +175 -0
  67. package/esm/tools/json-schemas.mjs.map +1 -0
  68. package/esm/tools/list-dir.d.mts +32 -0
  69. package/esm/tools/list-dir.d.mts.map +1 -0
  70. package/esm/tools/list-dir.mjs +50 -0
  71. package/esm/tools/list-dir.mjs.map +1 -0
  72. package/esm/tools/multi-edit.d.mts +38 -0
  73. package/esm/tools/multi-edit.d.mts.map +1 -0
  74. package/esm/tools/multi-edit.mjs +121 -0
  75. package/esm/tools/multi-edit.mjs.map +1 -0
  76. package/esm/tools/read-file.d.mts.map +1 -1
  77. package/esm/tools/read-file.mjs +2 -1
  78. package/esm/tools/read-file.mjs.map +1 -1
  79. package/esm/tools/run-shell.d.mts +34 -12
  80. package/esm/tools/run-shell.d.mts.map +1 -1
  81. package/esm/tools/run-shell.mjs +59 -53
  82. package/esm/tools/run-shell.mjs.map +1 -1
  83. package/esm/tools/run-tests.d.mts +8 -0
  84. package/esm/tools/run-tests.d.mts.map +1 -1
  85. package/esm/tools/run-tests.mjs +10 -3
  86. package/esm/tools/run-tests.mjs.map +1 -1
  87. package/esm/tools/schema.mjs +23 -18
  88. package/esm/tools/schema.mjs.map +1 -1
  89. package/esm/tools/shell-kill.d.mts +25 -0
  90. package/esm/tools/shell-kill.d.mts.map +1 -0
  91. package/esm/tools/shell-kill.mjs +36 -0
  92. package/esm/tools/shell-kill.mjs.map +1 -0
  93. package/esm/tools/shell-output.d.mts +30 -0
  94. package/esm/tools/shell-output.d.mts.map +1 -0
  95. package/esm/tools/shell-output.mjs +49 -0
  96. package/esm/tools/shell-output.mjs.map +1 -0
  97. package/esm/tools/todo.d.mts +43 -0
  98. package/esm/tools/todo.d.mts.map +1 -0
  99. package/esm/tools/todo.mjs +126 -0
  100. package/esm/tools/todo.mjs.map +1 -0
  101. package/esm/tools/write-file.d.mts.map +1 -1
  102. package/esm/tools/write-file.mjs +2 -1
  103. package/esm/tools/write-file.mjs.map +1 -1
  104. package/esm/workspace.d.mts +11 -8
  105. package/esm/workspace.d.mts.map +1 -1
  106. package/esm/workspace.mjs +108 -27
  107. package/esm/workspace.mjs.map +1 -1
  108. package/llms-full.txt +155 -34
  109. package/llms.txt +1 -1
  110. package/package.json +3 -3
  111. package/skills/README.md +2 -2
  112. package/skills/build-loop-agent/SKILL.md +7 -7
  113. package/skills/index.md +6 -1
  114. package/skills/use-a-workspace/SKILL.md +148 -27
@@ -0,0 +1,175 @@
1
+ //#region ../../packages/ai-workspace/src/tools/json-schemas.ts
2
+ /**
3
+ * The JSON Schemas the workspace tools publish for their input (read by
4
+ * `extractJsonSchema` and sent to the provider with each tool), kept short
5
+ * because they ride along on every model call. They describe what the
6
+ * hand-rolled validators accept; the validators remain the authority.
7
+ */
8
+ const string = (description) => ({
9
+ type: "string",
10
+ description
11
+ });
12
+ const integer = (description) => ({
13
+ type: "integer",
14
+ description
15
+ });
16
+ const boolean = (description) => ({
17
+ type: "boolean",
18
+ description
19
+ });
20
+ /** `read_file`. */
21
+ const READ_FILE_JSON_SCHEMA = {
22
+ type: "object",
23
+ properties: {
24
+ path: string("Workspace-relative file path."),
25
+ startLine: integer("1-based first line to return."),
26
+ limit: integer("Most lines to return.")
27
+ },
28
+ required: ["path"]
29
+ };
30
+ /** `edit_file`. */
31
+ const EDIT_FILE_JSON_SCHEMA = {
32
+ type: "object",
33
+ properties: {
34
+ path: string("Workspace-relative file path."),
35
+ oldString: string("Exact text to replace; must be unique unless replaceAll."),
36
+ newString: string("Replacement text."),
37
+ replaceAll: boolean("Replace every occurrence."),
38
+ expectHash: string("Hash from read_file; rejects the edit if the file changed.")
39
+ },
40
+ required: [
41
+ "path",
42
+ "oldString",
43
+ "newString"
44
+ ]
45
+ };
46
+ /** `multi_edit`. */
47
+ const MULTI_EDIT_JSON_SCHEMA = {
48
+ type: "object",
49
+ properties: {
50
+ path: string("Workspace-relative file path."),
51
+ edits: {
52
+ type: "array",
53
+ description: "Replacements applied in order, each to the result of the previous; all or none.",
54
+ minItems: 1,
55
+ maxItems: 100,
56
+ items: {
57
+ type: "object",
58
+ properties: {
59
+ oldString: string("Exact text to replace; must be unique unless replaceAll."),
60
+ newString: string("Replacement text."),
61
+ replaceAll: boolean("Replace every occurrence.")
62
+ },
63
+ required: ["oldString", "newString"]
64
+ }
65
+ },
66
+ expectHash: string("Hash from read_file; rejects every edit if the file changed.")
67
+ },
68
+ required: ["path", "edits"]
69
+ };
70
+ /** `write_file`. */
71
+ const WRITE_FILE_JSON_SCHEMA = {
72
+ type: "object",
73
+ properties: {
74
+ path: string("Workspace-relative file path."),
75
+ content: string("Full file content.")
76
+ },
77
+ required: ["path", "content"]
78
+ };
79
+ /** `list_dir`. */
80
+ const LIST_DIR_JSON_SCHEMA = {
81
+ type: "object",
82
+ properties: {
83
+ path: string("Workspace-relative directory (default \".\")."),
84
+ depth: integer("Levels to list; 1 = direct children (default)."),
85
+ ignore: {
86
+ type: "array",
87
+ items: { type: "string" },
88
+ description: "Extra globs to leave out."
89
+ }
90
+ }
91
+ };
92
+ /** `run_shell` (the `background` property is only listed when background commands are enabled). */
93
+ function runShellJsonSchema(background) {
94
+ return {
95
+ type: "object",
96
+ properties: {
97
+ command: string("The command line to run."),
98
+ timeoutMs: integer("Wall-clock cap in ms (can only lower the workspace limit)."),
99
+ ...background ? { background: boolean("Start it in the background and return its id at once (dev servers, watchers).") } : {}
100
+ },
101
+ required: ["command"]
102
+ };
103
+ }
104
+ /** `shell_output`. */
105
+ const SHELL_OUTPUT_JSON_SCHEMA = {
106
+ type: "object",
107
+ properties: {
108
+ id: string("Background command id from run_shell."),
109
+ since: integer("A cursor from an earlier result; omit for output since the last read."),
110
+ waitMs: integer("Wait up to this long (max 30000) for new output.")
111
+ },
112
+ required: ["id"]
113
+ };
114
+ /** `shell_kill`. */
115
+ const SHELL_KILL_JSON_SCHEMA = {
116
+ type: "object",
117
+ properties: { id: string("Background command id from run_shell.") },
118
+ required: ["id"]
119
+ };
120
+ /** `run_tests`. */
121
+ const RUN_TESTS_JSON_SCHEMA = {
122
+ type: "object",
123
+ properties: { pattern: string("Optional test path or name filter.") }
124
+ };
125
+ /** `grep`. */
126
+ const GREP_JSON_SCHEMA = {
127
+ type: "object",
128
+ properties: {
129
+ pattern: string("Regular expression to search for."),
130
+ glob: string("Only search files matching this glob (e.g. \"src/**/*.ts\")."),
131
+ ignoreCase: boolean("Case-insensitive match.")
132
+ },
133
+ required: ["pattern"]
134
+ };
135
+ /** `glob`. */
136
+ const GLOB_JSON_SCHEMA = {
137
+ type: "object",
138
+ properties: { pattern: string("Glob such as \"src/**/*.ts\".") },
139
+ required: ["pattern"]
140
+ };
141
+ /** `todo_write`. */
142
+ const TODO_WRITE_JSON_SCHEMA = {
143
+ type: "object",
144
+ properties: { todos: {
145
+ type: "array",
146
+ description: "The complete updated list (replaces the old one).",
147
+ maxItems: 100,
148
+ items: {
149
+ type: "object",
150
+ properties: {
151
+ id: string("Stable id; omit to number items by position."),
152
+ content: string("The step."),
153
+ status: {
154
+ type: "string",
155
+ enum: [
156
+ "pending",
157
+ "in_progress",
158
+ "completed"
159
+ ]
160
+ }
161
+ },
162
+ required: ["content", "status"]
163
+ }
164
+ } },
165
+ required: ["todos"]
166
+ };
167
+ /** `todo_read`. */
168
+ const TODO_READ_JSON_SCHEMA = {
169
+ type: "object",
170
+ properties: {}
171
+ };
172
+
173
+ //#endregion
174
+ export { EDIT_FILE_JSON_SCHEMA, GLOB_JSON_SCHEMA, GREP_JSON_SCHEMA, LIST_DIR_JSON_SCHEMA, MULTI_EDIT_JSON_SCHEMA, READ_FILE_JSON_SCHEMA, RUN_TESTS_JSON_SCHEMA, SHELL_KILL_JSON_SCHEMA, SHELL_OUTPUT_JSON_SCHEMA, TODO_READ_JSON_SCHEMA, TODO_WRITE_JSON_SCHEMA, WRITE_FILE_JSON_SCHEMA, runShellJsonSchema };
175
+ //# sourceMappingURL=json-schemas.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schemas.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/json-schemas.ts"],"sourcesContent":["import type { JsonSchemaObject } from \"./schema\";\n\n/**\n * The JSON Schemas the workspace tools publish for their input (read by\n * `extractJsonSchema` and sent to the provider with each tool), kept short\n * because they ride along on every model call. They describe what the\n * hand-rolled validators accept; the validators remain the authority.\n */\n\nconst string = (description: string): JsonSchemaObject => ({ type: \"string\", description });\nconst integer = (description: string): JsonSchemaObject => ({ type: \"integer\", description });\nconst boolean = (description: string): JsonSchemaObject => ({ type: \"boolean\", description });\n\n/** `read_file`. */\nexport const READ_FILE_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n path: string(\"Workspace-relative file path.\"),\n startLine: integer(\"1-based first line to return.\"),\n limit: integer(\"Most lines to return.\"),\n },\n required: [\"path\"],\n};\n\n/** `edit_file`. */\nexport const EDIT_FILE_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n path: string(\"Workspace-relative file path.\"),\n oldString: string(\"Exact text to replace; must be unique unless replaceAll.\"),\n newString: string(\"Replacement text.\"),\n replaceAll: boolean(\"Replace every occurrence.\"),\n expectHash: string(\"Hash from read_file; rejects the edit if the file changed.\"),\n },\n required: [\"path\", \"oldString\", \"newString\"],\n};\n\n/** `multi_edit`. */\nexport const MULTI_EDIT_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n path: string(\"Workspace-relative file path.\"),\n edits: {\n type: \"array\",\n description:\n \"Replacements applied in order, each to the result of the previous; all or none.\",\n minItems: 1,\n maxItems: 100,\n items: {\n type: \"object\",\n properties: {\n oldString: string(\"Exact text to replace; must be unique unless replaceAll.\"),\n newString: string(\"Replacement text.\"),\n replaceAll: boolean(\"Replace every occurrence.\"),\n },\n required: [\"oldString\", \"newString\"],\n },\n },\n expectHash: string(\"Hash from read_file; rejects every edit if the file changed.\"),\n },\n required: [\"path\", \"edits\"],\n};\n\n/** `write_file`. */\nexport const WRITE_FILE_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n path: string(\"Workspace-relative file path.\"),\n content: string(\"Full file content.\"),\n },\n required: [\"path\", \"content\"],\n};\n\n/** `list_dir`. */\nexport const LIST_DIR_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n path: string('Workspace-relative directory (default \".\").'),\n depth: integer(\"Levels to list; 1 = direct children (default).\"),\n ignore: { type: \"array\", items: { type: \"string\" }, description: \"Extra globs to leave out.\" },\n },\n};\n\n/** `run_shell` (the `background` property is only listed when background commands are enabled). */\nexport function runShellJsonSchema(background: boolean): JsonSchemaObject {\n return {\n type: \"object\",\n properties: {\n command: string(\"The command line to run.\"),\n timeoutMs: integer(\"Wall-clock cap in ms (can only lower the workspace limit).\"),\n ...(background\n ? {\n background: boolean(\n \"Start it in the background and return its id at once (dev servers, watchers).\",\n ),\n }\n : {}),\n },\n required: [\"command\"],\n };\n}\n\n/** `shell_output`. */\nexport const SHELL_OUTPUT_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n id: string(\"Background command id from run_shell.\"),\n since: integer(\"A cursor from an earlier result; omit for output since the last read.\"),\n waitMs: integer(\"Wait up to this long (max 30000) for new output.\"),\n },\n required: [\"id\"],\n};\n\n/** `shell_kill`. */\nexport const SHELL_KILL_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: { id: string(\"Background command id from run_shell.\") },\n required: [\"id\"],\n};\n\n/** `run_tests`. */\nexport const RUN_TESTS_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: { pattern: string(\"Optional test path or name filter.\") },\n};\n\n/** `grep`. */\nexport const GREP_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n pattern: string(\"Regular expression to search for.\"),\n glob: string('Only search files matching this glob (e.g. \"src/**/*.ts\").'),\n ignoreCase: boolean(\"Case-insensitive match.\"),\n },\n required: [\"pattern\"],\n};\n\n/** `glob`. */\nexport const GLOB_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: { pattern: string('Glob such as \"src/**/*.ts\".') },\n required: [\"pattern\"],\n};\n\n/** `todo_write`. */\nexport const TODO_WRITE_JSON_SCHEMA: JsonSchemaObject = {\n type: \"object\",\n properties: {\n todos: {\n type: \"array\",\n description: \"The complete updated list (replaces the old one).\",\n maxItems: 100,\n items: {\n type: \"object\",\n properties: {\n id: string(\"Stable id; omit to number items by position.\"),\n content: string(\"The step.\"),\n status: { type: \"string\", enum: [\"pending\", \"in_progress\", \"completed\"] },\n },\n required: [\"content\", \"status\"],\n },\n },\n },\n required: [\"todos\"],\n};\n\n/** `todo_read`. */\nexport const TODO_READ_JSON_SCHEMA: JsonSchemaObject = { type: \"object\", properties: {} };\n"],"mappings":";;;;;;;AASA,MAAM,UAAU,iBAA2C;CAAE,MAAM;CAAU;AAAY;AACzF,MAAM,WAAW,iBAA2C;CAAE,MAAM;CAAW;AAAY;AAC3F,MAAM,WAAW,iBAA2C;CAAE,MAAM;CAAW;AAAY;;AAG3F,MAAa,wBAA0C;CACrD,MAAM;CACN,YAAY;EACV,MAAM,OAAO,+BAA+B;EAC5C,WAAW,QAAQ,+BAA+B;EAClD,OAAO,QAAQ,uBAAuB;CACxC;CACA,UAAU,CAAC,MAAM;AACnB;;AAGA,MAAa,wBAA0C;CACrD,MAAM;CACN,YAAY;EACV,MAAM,OAAO,+BAA+B;EAC5C,WAAW,OAAO,0DAA0D;EAC5E,WAAW,OAAO,mBAAmB;EACrC,YAAY,QAAQ,2BAA2B;EAC/C,YAAY,OAAO,4DAA4D;CACjF;CACA,UAAU;EAAC;EAAQ;EAAa;CAAW;AAC7C;;AAGA,MAAa,yBAA2C;CACtD,MAAM;CACN,YAAY;EACV,MAAM,OAAO,+BAA+B;EAC5C,OAAO;GACL,MAAM;GACN,aACE;GACF,UAAU;GACV,UAAU;GACV,OAAO;IACL,MAAM;IACN,YAAY;KACV,WAAW,OAAO,0DAA0D;KAC5E,WAAW,OAAO,mBAAmB;KACrC,YAAY,QAAQ,2BAA2B;IACjD;IACA,UAAU,CAAC,aAAa,WAAW;GACrC;EACF;EACA,YAAY,OAAO,8DAA8D;CACnF;CACA,UAAU,CAAC,QAAQ,OAAO;AAC5B;;AAGA,MAAa,yBAA2C;CACtD,MAAM;CACN,YAAY;EACV,MAAM,OAAO,+BAA+B;EAC5C,SAAS,OAAO,oBAAoB;CACtC;CACA,UAAU,CAAC,QAAQ,SAAS;AAC9B;;AAGA,MAAa,uBAAyC;CACpD,MAAM;CACN,YAAY;EACV,MAAM,OAAO,+CAA6C;EAC1D,OAAO,QAAQ,gDAAgD;EAC/D,QAAQ;GAAE,MAAM;GAAS,OAAO,EAAE,MAAM,SAAS;GAAG,aAAa;EAA4B;CAC/F;AACF;;AAGA,SAAgB,mBAAmB,YAAuC;CACxE,OAAO;EACL,MAAM;EACN,YAAY;GACV,SAAS,OAAO,0BAA0B;GAC1C,WAAW,QAAQ,4DAA4D;GAC/E,GAAI,aACA,EACE,YAAY,QACV,+EACF,EACF,IACA,CAAC;EACP;EACA,UAAU,CAAC,SAAS;CACtB;AACF;;AAGA,MAAa,2BAA6C;CACxD,MAAM;CACN,YAAY;EACV,IAAI,OAAO,uCAAuC;EAClD,OAAO,QAAQ,uEAAuE;EACtF,QAAQ,QAAQ,kDAAkD;CACpE;CACA,UAAU,CAAC,IAAI;AACjB;;AAGA,MAAa,yBAA2C;CACtD,MAAM;CACN,YAAY,EAAE,IAAI,OAAO,uCAAuC,EAAE;CAClE,UAAU,CAAC,IAAI;AACjB;;AAGA,MAAa,wBAA0C;CACrD,MAAM;CACN,YAAY,EAAE,SAAS,OAAO,oCAAoC,EAAE;AACtE;;AAGA,MAAa,mBAAqC;CAChD,MAAM;CACN,YAAY;EACV,SAAS,OAAO,mCAAmC;EACnD,MAAM,OAAO,8DAA4D;EACzE,YAAY,QAAQ,yBAAyB;CAC/C;CACA,UAAU,CAAC,SAAS;AACtB;;AAGA,MAAa,mBAAqC;CAChD,MAAM;CACN,YAAY,EAAE,SAAS,OAAO,+BAA6B,EAAE;CAC7D,UAAU,CAAC,SAAS;AACtB;;AAGA,MAAa,yBAA2C;CACtD,MAAM;CACN,YAAY,EACV,OAAO;EACL,MAAM;EACN,aAAa;EACb,UAAU;EACV,OAAO;GACL,MAAM;GACN,YAAY;IACV,IAAI,OAAO,8CAA8C;IACzD,SAAS,OAAO,WAAW;IAC3B,QAAQ;KAAE,MAAM;KAAU,MAAM;MAAC;MAAW;MAAe;KAAW;IAAE;GAC1E;GACA,UAAU,CAAC,WAAW,QAAQ;EAChC;CACF,EACF;CACA,UAAU,CAAC,OAAO;AACpB;;AAGA,MAAa,wBAA0C;CAAE,MAAM;CAAU,YAAY,CAAC;AAAE"}
@@ -0,0 +1,32 @@
1
+ import { ListDirInput, ListDirResult } from "../contracts/tool-io.type.mjs";
2
+ import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import { ToolContract } from "@warlock.js/ai";
4
+
5
+ //#region ../../packages/ai-workspace/src/tools/list-dir.d.ts
6
+ /**
7
+ * Build the agent-facing `list_dir` tool over a workspace's policy-enforced
8
+ * {@link WorkspaceOps}: a bounded, jailed listing of one directory.
9
+ *
10
+ * Entries come back breadth-first (each level sorted by name) with their
11
+ * type and — for files — size, down to `depth` levels (capped by
12
+ * `list.maxDepth`) and at most `list.maxEntries` entries (`truncated` says
13
+ * when the cap hit). `denyPaths` are always left out, as are the
14
+ * `list.ignore` globs (default `node_modules`, `.git`) and any `ignore`
15
+ * globs the model passes. Symlinks are reported as `"symlink"` and never
16
+ * followed. A path outside the jail surfaces as a `WorkspacePolicyError` in
17
+ * the result's `error` field.
18
+ *
19
+ * @param ops - The shared, policy-enforced operation layer.
20
+ * @param options - Optional overrides; `name` renames the LLM-visible tool.
21
+ *
22
+ * @example
23
+ * const listDir = makeListDirTool(ops);
24
+ * const { data } = await listDir.invoke({ path: "src", depth: 2 });
25
+ * for (const entry of data?.entries ?? []) console.log(entry.type, entry.path, entry.size);
26
+ */
27
+ declare function makeListDirTool(ops: WorkspaceOps, options?: {
28
+ name?: string;
29
+ }): ToolContract<ListDirInput, ListDirResult>;
30
+ //#endregion
31
+ export { makeListDirTool };
32
+ //# sourceMappingURL=list-dir.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-dir.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/list-dir.ts"],"mappings":";;;;;;;;;AA4CA;;;;;;;;;;;;;;;;;iBAAgB,eAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,YAAA,EAAc,aAAA"}
@@ -0,0 +1,50 @@
1
+ import { objectSchema, optionalNumberField, optionalStringArrayField, optionalStringField } from "./schema.mjs";
2
+ import { LIST_DIR_JSON_SCHEMA } from "./json-schemas.mjs";
3
+ import { tool } from "@warlock.js/ai";
4
+
5
+ //#region ../../packages/ai-workspace/src/tools/list-dir.ts
6
+ /** Default tool name exposed to the LLM. */
7
+ const DEFAULT_NAME = "list_dir";
8
+ /** Input schema for the `list_dir` tool. */
9
+ const inputSchema = objectSchema({
10
+ path: optionalStringField(),
11
+ depth: optionalNumberField(),
12
+ ignore: optionalStringArrayField()
13
+ }, LIST_DIR_JSON_SCHEMA);
14
+ /**
15
+ * Build the agent-facing `list_dir` tool over a workspace's policy-enforced
16
+ * {@link WorkspaceOps}: a bounded, jailed listing of one directory.
17
+ *
18
+ * Entries come back breadth-first (each level sorted by name) with their
19
+ * type and — for files — size, down to `depth` levels (capped by
20
+ * `list.maxDepth`) and at most `list.maxEntries` entries (`truncated` says
21
+ * when the cap hit). `denyPaths` are always left out, as are the
22
+ * `list.ignore` globs (default `node_modules`, `.git`) and any `ignore`
23
+ * globs the model passes. Symlinks are reported as `"symlink"` and never
24
+ * followed. A path outside the jail surfaces as a `WorkspacePolicyError` in
25
+ * the result's `error` field.
26
+ *
27
+ * @param ops - The shared, policy-enforced operation layer.
28
+ * @param options - Optional overrides; `name` renames the LLM-visible tool.
29
+ *
30
+ * @example
31
+ * const listDir = makeListDirTool(ops);
32
+ * const { data } = await listDir.invoke({ path: "src", depth: 2 });
33
+ * for (const entry of data?.entries ?? []) console.log(entry.type, entry.path, entry.size);
34
+ */
35
+ function makeListDirTool(ops, options) {
36
+ return tool({
37
+ name: options?.name ?? DEFAULT_NAME,
38
+ description: "List a workspace directory: entries with their type and file size, breadth-first, `depth` levels deep (default 1). Dependency and VCS folders are left out unless you list them directly.",
39
+ action: (input) => `Listing ${typeof input.path === "string" ? input.path : "."}`,
40
+ input: inputSchema,
41
+ execute: (input) => ops.listDir(input.path ?? ".", {
42
+ ...input.depth !== void 0 ? { depth: input.depth } : {},
43
+ ...input.ignore !== void 0 ? { ignore: input.ignore } : {}
44
+ })
45
+ });
46
+ }
47
+
48
+ //#endregion
49
+ export { makeListDirTool };
50
+ //# sourceMappingURL=list-dir.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-dir.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/list-dir.ts"],"sourcesContent":["import { tool, type ToolContract } from \"@warlock.js/ai\";\nimport type { ListDirInput, ListDirResult, WorkspaceOps } from \"../contracts\";\nimport { LIST_DIR_JSON_SCHEMA } from \"./json-schemas\";\nimport {\n objectSchema,\n optionalNumberField,\n optionalStringArrayField,\n optionalStringField,\n} from \"./schema\";\n\n/** Default tool name exposed to the LLM. */\nconst DEFAULT_NAME = \"list_dir\";\n\n/** Input schema for the `list_dir` tool. */\nconst inputSchema = objectSchema<ListDirInput>(\n {\n path: optionalStringField(),\n depth: optionalNumberField(),\n ignore: optionalStringArrayField(),\n },\n LIST_DIR_JSON_SCHEMA,\n);\n\n/**\n * Build the agent-facing `list_dir` tool over a workspace's policy-enforced\n * {@link WorkspaceOps}: a bounded, jailed listing of one directory.\n *\n * Entries come back breadth-first (each level sorted by name) with their\n * type and — for files — size, down to `depth` levels (capped by\n * `list.maxDepth`) and at most `list.maxEntries` entries (`truncated` says\n * when the cap hit). `denyPaths` are always left out, as are the\n * `list.ignore` globs (default `node_modules`, `.git`) and any `ignore`\n * globs the model passes. Symlinks are reported as `\"symlink\"` and never\n * followed. A path outside the jail surfaces as a `WorkspacePolicyError` in\n * the result's `error` field.\n *\n * @param ops - The shared, policy-enforced operation layer.\n * @param options - Optional overrides; `name` renames the LLM-visible tool.\n *\n * @example\n * const listDir = makeListDirTool(ops);\n * const { data } = await listDir.invoke({ path: \"src\", depth: 2 });\n * for (const entry of data?.entries ?? []) console.log(entry.type, entry.path, entry.size);\n */\nexport function makeListDirTool(\n ops: WorkspaceOps,\n options?: { name?: string },\n): ToolContract<ListDirInput, ListDirResult> {\n return tool<ListDirInput, ListDirResult>({\n name: options?.name ?? DEFAULT_NAME,\n description:\n \"List a workspace directory: entries with their type and file size, \" +\n \"breadth-first, `depth` levels deep (default 1). Dependency and VCS \" +\n \"folders are left out unless you list them directly.\",\n action: (input) => `Listing ${typeof input.path === \"string\" ? input.path : \".\"}`,\n input: inputSchema,\n execute: (input) =>\n ops.listDir(input.path ?? \".\", {\n ...(input.depth !== undefined ? { depth: input.depth } : {}),\n ...(input.ignore !== undefined ? { ignore: input.ignore } : {}),\n }),\n });\n}\n"],"mappings":";;;;;;AAWA,MAAM,eAAe;;AAGrB,MAAM,cAAc,aAClB;CACE,MAAM,oBAAoB;CAC1B,OAAO,oBAAoB;CAC3B,QAAQ,yBAAyB;AACnC,GACA,oBACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,gBACd,KACA,SAC2C;CAC3C,OAAO,KAAkC;EACvC,MAAM,SAAS,QAAQ;EACvB,aACE;EAGF,SAAS,UAAU,WAAW,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;EAC5E,OAAO;EACP,UAAU,UACR,IAAI,QAAQ,MAAM,QAAQ,KAAK;GAC7B,GAAI,MAAM,UAAU,SAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;GAC1D,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;EAC/D,CAAC;CACL,CAAC;AACH"}
@@ -0,0 +1,38 @@
1
+ import { MultiEditInput, MultiEditResult } from "../contracts/tool-io.type.mjs";
2
+ import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import { ToolContract } from "@warlock.js/ai";
4
+
5
+ //#region ../../packages/ai-workspace/src/tools/multi-edit.d.ts
6
+ /**
7
+ * Build the agent-facing `multi_edit` tool over a workspace's policy-
8
+ * enforced {@link WorkspaceOps}: several exact-string replacements in one
9
+ * file, **atomic** — every edit applies, in order (each against the result
10
+ * of the previous ones), and the file is written once; or one edit fails
11
+ * and nothing is written.
12
+ *
13
+ * Each edit follows the `edit_file` rules: `oldString` must be found, and
14
+ * found exactly once unless `replaceAll`. An optional `expectHash` (from
15
+ * `read_file`) rejects the whole call when the file changed since it was
16
+ * read. A failure surfaces as a `WorkspaceEditError` in the result's
17
+ * `error` field, with `editIndex` naming the failing edit.
18
+ *
19
+ * @param ops - The shared, policy-enforced operation layer.
20
+ * @param options - Optional overrides; `name` renames the LLM-visible tool.
21
+ *
22
+ * @example
23
+ * const multiEdit = makeMultiEditTool(ops);
24
+ * const { data, error } = await multiEdit.invoke({
25
+ * path: "src/cart.ts",
26
+ * expectHash,
27
+ * edits: [
28
+ * { oldString: "let total = 0;", newString: "let total = 0n;" },
29
+ * { oldString: "total += price;", newString: "total += BigInt(price);" },
30
+ * ],
31
+ * });
32
+ */
33
+ declare function makeMultiEditTool(ops: WorkspaceOps, options?: {
34
+ name?: string;
35
+ }): ToolContract<MultiEditInput, MultiEditResult>;
36
+ //#endregion
37
+ export { makeMultiEditTool };
38
+ //# sourceMappingURL=multi-edit.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-edit.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/multi-edit.ts"],"mappings":";;;;;;;;;AA8JA;;;;;;;;;;;;;;;;;AAG+C;;;;;;iBAH/B,iBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,cAAA,EAAgB,eAAA"}
@@ -0,0 +1,121 @@
1
+ import "../ops.mjs";
2
+ import { withJsonSchema } from "./schema.mjs";
3
+ import { MULTI_EDIT_JSON_SCHEMA } from "./json-schemas.mjs";
4
+ import { tool } from "@warlock.js/ai";
5
+
6
+ //#region ../../packages/ai-workspace/src/tools/multi-edit.ts
7
+ /** Default tool name exposed to the LLM. */
8
+ const DEFAULT_NAME = "multi_edit";
9
+ /** Validate one element of `edits`. */
10
+ function validateEdit(value, index) {
11
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return { issues: [{
12
+ message: `edits[${index}] must be an object`,
13
+ path: ["edits", index]
14
+ }] };
15
+ const candidate = value;
16
+ const issues = [];
17
+ if (typeof candidate.oldString !== "string" || candidate.oldString === "") issues.push({
18
+ message: `edits[${index}].oldString must be a non-empty string`,
19
+ path: [
20
+ "edits",
21
+ index,
22
+ "oldString"
23
+ ]
24
+ });
25
+ if (typeof candidate.newString !== "string") issues.push({
26
+ message: `edits[${index}].newString must be a string`,
27
+ path: [
28
+ "edits",
29
+ index,
30
+ "newString"
31
+ ]
32
+ });
33
+ if (candidate.replaceAll !== void 0 && typeof candidate.replaceAll !== "boolean") issues.push({
34
+ message: `edits[${index}].replaceAll must be a boolean when provided`,
35
+ path: [
36
+ "edits",
37
+ index,
38
+ "replaceAll"
39
+ ]
40
+ });
41
+ if (issues.length > 0 || typeof candidate.oldString !== "string" || typeof candidate.newString !== "string") return { issues };
42
+ return { edit: {
43
+ oldString: candidate.oldString,
44
+ newString: candidate.newString,
45
+ ...candidate.replaceAll === true ? { replaceAll: true } : {}
46
+ } };
47
+ }
48
+ /** Input schema for the `multi_edit` tool. */
49
+ const inputSchema = withJsonSchema({ "~standard": {
50
+ version: 1,
51
+ vendor: "ai-workspace",
52
+ validate(value) {
53
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return { issues: [{ message: "input must be an object" }] };
54
+ const candidate = value;
55
+ const issues = [];
56
+ const edits = [];
57
+ if (typeof candidate.path !== "string" || candidate.path === "") issues.push({
58
+ message: "\"path\" must be a non-empty string",
59
+ path: ["path"]
60
+ });
61
+ if (candidate.expectHash !== void 0 && typeof candidate.expectHash !== "string") issues.push({
62
+ message: "\"expectHash\" must be a string when provided",
63
+ path: ["expectHash"]
64
+ });
65
+ if (!Array.isArray(candidate.edits) || candidate.edits.length === 0 || candidate.edits.length > 100) issues.push({
66
+ message: `"edits" must be an array of 1 to ${100} edits`,
67
+ path: ["edits"]
68
+ });
69
+ else candidate.edits.forEach((item, index) => {
70
+ const outcome = validateEdit(item, index);
71
+ if ("issues" in outcome) issues.push(...outcome.issues);
72
+ else edits.push(outcome.edit);
73
+ });
74
+ if (issues.length > 0 || typeof candidate.path !== "string") return { issues };
75
+ return { value: {
76
+ path: candidate.path,
77
+ edits,
78
+ ...typeof candidate.expectHash === "string" ? { expectHash: candidate.expectHash } : {}
79
+ } };
80
+ }
81
+ } }, MULTI_EDIT_JSON_SCHEMA);
82
+ /**
83
+ * Build the agent-facing `multi_edit` tool over a workspace's policy-
84
+ * enforced {@link WorkspaceOps}: several exact-string replacements in one
85
+ * file, **atomic** — every edit applies, in order (each against the result
86
+ * of the previous ones), and the file is written once; or one edit fails
87
+ * and nothing is written.
88
+ *
89
+ * Each edit follows the `edit_file` rules: `oldString` must be found, and
90
+ * found exactly once unless `replaceAll`. An optional `expectHash` (from
91
+ * `read_file`) rejects the whole call when the file changed since it was
92
+ * read. A failure surfaces as a `WorkspaceEditError` in the result's
93
+ * `error` field, with `editIndex` naming the failing edit.
94
+ *
95
+ * @param ops - The shared, policy-enforced operation layer.
96
+ * @param options - Optional overrides; `name` renames the LLM-visible tool.
97
+ *
98
+ * @example
99
+ * const multiEdit = makeMultiEditTool(ops);
100
+ * const { data, error } = await multiEdit.invoke({
101
+ * path: "src/cart.ts",
102
+ * expectHash,
103
+ * edits: [
104
+ * { oldString: "let total = 0;", newString: "let total = 0n;" },
105
+ * { oldString: "total += price;", newString: "total += BigInt(price);" },
106
+ * ],
107
+ * });
108
+ */
109
+ function makeMultiEditTool(ops, options) {
110
+ return tool({
111
+ name: options?.name ?? DEFAULT_NAME,
112
+ description: "Make several exact-string replacements in one workspace file at once. Edits apply in order, each to the result of the previous; if any edit fails (text not found, or not unique without replaceAll) none are applied. Pass expectHash (from read_file) to reject the call if the file changed since you read it.",
113
+ action: (input) => `Editing ${typeof input.path === "string" ? input.path : "a file"}`,
114
+ input: inputSchema,
115
+ execute: (input) => ops.multiEdit(input)
116
+ });
117
+ }
118
+
119
+ //#endregion
120
+ export { makeMultiEditTool };
121
+ //# sourceMappingURL=multi-edit.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-edit.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/multi-edit.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { tool, type ToolContract } from \"@warlock.js/ai\";\nimport { MAX_MULTI_EDITS } from \"../ops\";\nimport type {\n MultiEditInput,\n MultiEditOperation,\n MultiEditResult,\n WorkspaceOps,\n} from \"../contracts\";\nimport { MULTI_EDIT_JSON_SCHEMA } from \"./json-schemas\";\nimport { withJsonSchema } from \"./schema\";\n\n/** Default tool name exposed to the LLM. */\nconst DEFAULT_NAME = \"multi_edit\";\n\n/** Validate one element of `edits`. */\nfunction validateEdit(\n value: unknown,\n index: number,\n): { edit: MultiEditOperation } | { issues: StandardSchemaV1.Issue[] } {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return { issues: [{ message: `edits[${index}] must be an object`, path: [\"edits\", index] }] };\n }\n\n const candidate = value as Record<string, unknown>;\n const issues: StandardSchemaV1.Issue[] = [];\n\n if (typeof candidate.oldString !== \"string\" || candidate.oldString === \"\") {\n issues.push({\n message: `edits[${index}].oldString must be a non-empty string`,\n path: [\"edits\", index, \"oldString\"],\n });\n }\n\n if (typeof candidate.newString !== \"string\") {\n issues.push({\n message: `edits[${index}].newString must be a string`,\n path: [\"edits\", index, \"newString\"],\n });\n }\n\n if (candidate.replaceAll !== undefined && typeof candidate.replaceAll !== \"boolean\") {\n issues.push({\n message: `edits[${index}].replaceAll must be a boolean when provided`,\n path: [\"edits\", index, \"replaceAll\"],\n });\n }\n\n if (\n issues.length > 0 ||\n typeof candidate.oldString !== \"string\" ||\n typeof candidate.newString !== \"string\"\n ) {\n return { issues };\n }\n\n return {\n edit: {\n oldString: candidate.oldString,\n newString: candidate.newString,\n ...(candidate.replaceAll === true ? { replaceAll: true } : {}),\n },\n };\n}\n\n/** Input schema for the `multi_edit` tool. */\nconst inputSchema = withJsonSchema<MultiEditInput>(\n {\n \"~standard\": {\n version: 1,\n vendor: \"ai-workspace\",\n validate(value) {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return { issues: [{ message: \"input must be an object\" }] };\n }\n\n const candidate = value as Record<string, unknown>;\n const issues: StandardSchemaV1.Issue[] = [];\n const edits: MultiEditOperation[] = [];\n\n if (typeof candidate.path !== \"string\" || candidate.path === \"\") {\n issues.push({ message: '\"path\" must be a non-empty string', path: [\"path\"] });\n }\n\n if (candidate.expectHash !== undefined && typeof candidate.expectHash !== \"string\") {\n issues.push({\n message: '\"expectHash\" must be a string when provided',\n path: [\"expectHash\"],\n });\n }\n\n if (\n !Array.isArray(candidate.edits) ||\n candidate.edits.length === 0 ||\n candidate.edits.length > MAX_MULTI_EDITS\n ) {\n issues.push({\n message: `\"edits\" must be an array of 1 to ${MAX_MULTI_EDITS} edits`,\n path: [\"edits\"],\n });\n } else {\n candidate.edits.forEach((item: unknown, index: number) => {\n const outcome = validateEdit(item, index);\n\n if (\"issues\" in outcome) {\n issues.push(...outcome.issues);\n } else {\n edits.push(outcome.edit);\n }\n });\n }\n\n if (issues.length > 0 || typeof candidate.path !== \"string\") {\n return { issues };\n }\n\n return {\n value: {\n path: candidate.path,\n edits,\n ...(typeof candidate.expectHash === \"string\"\n ? { expectHash: candidate.expectHash }\n : {}),\n },\n };\n },\n },\n },\n MULTI_EDIT_JSON_SCHEMA,\n);\n\n/**\n * Build the agent-facing `multi_edit` tool over a workspace's policy-\n * enforced {@link WorkspaceOps}: several exact-string replacements in one\n * file, **atomic** — every edit applies, in order (each against the result\n * of the previous ones), and the file is written once; or one edit fails\n * and nothing is written.\n *\n * Each edit follows the `edit_file` rules: `oldString` must be found, and\n * found exactly once unless `replaceAll`. An optional `expectHash` (from\n * `read_file`) rejects the whole call when the file changed since it was\n * read. A failure surfaces as a `WorkspaceEditError` in the result's\n * `error` field, with `editIndex` naming the failing edit.\n *\n * @param ops - The shared, policy-enforced operation layer.\n * @param options - Optional overrides; `name` renames the LLM-visible tool.\n *\n * @example\n * const multiEdit = makeMultiEditTool(ops);\n * const { data, error } = await multiEdit.invoke({\n * path: \"src/cart.ts\",\n * expectHash,\n * edits: [\n * { oldString: \"let total = 0;\", newString: \"let total = 0n;\" },\n * { oldString: \"total += price;\", newString: \"total += BigInt(price);\" },\n * ],\n * });\n */\nexport function makeMultiEditTool(\n ops: WorkspaceOps,\n options?: { name?: string },\n): ToolContract<MultiEditInput, MultiEditResult> {\n return tool<MultiEditInput, MultiEditResult>({\n name: options?.name ?? DEFAULT_NAME,\n description:\n \"Make several exact-string replacements in one workspace file at once. \" +\n \"Edits apply in order, each to the result of the previous; if any \" +\n \"edit fails (text not found, or not unique without replaceAll) none \" +\n \"are applied. Pass expectHash (from read_file) to reject the call if \" +\n \"the file changed since you read it.\",\n action: (input) => `Editing ${typeof input.path === \"string\" ? input.path : \"a file\"}`,\n input: inputSchema,\n execute: (input) => ops.multiEdit(input),\n });\n}\n"],"mappings":";;;;;;;AAaA,MAAM,eAAe;;AAGrB,SAAS,aACP,OACA,OACqE;CACrE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACpE,OAAO,EAAE,QAAQ,CAAC;EAAE,SAAS,SAAS,MAAM;EAAsB,MAAM,CAAC,SAAS,KAAK;CAAE,CAAC,EAAE;CAG9F,MAAM,YAAY;CAClB,MAAM,SAAmC,CAAC;CAE1C,IAAI,OAAO,UAAU,cAAc,YAAY,UAAU,cAAc,IACrE,OAAO,KAAK;EACV,SAAS,SAAS,MAAM;EACxB,MAAM;GAAC;GAAS;GAAO;EAAW;CACpC,CAAC;CAGH,IAAI,OAAO,UAAU,cAAc,UACjC,OAAO,KAAK;EACV,SAAS,SAAS,MAAM;EACxB,MAAM;GAAC;GAAS;GAAO;EAAW;CACpC,CAAC;CAGH,IAAI,UAAU,eAAe,UAAa,OAAO,UAAU,eAAe,WACxE,OAAO,KAAK;EACV,SAAS,SAAS,MAAM;EACxB,MAAM;GAAC;GAAS;GAAO;EAAY;CACrC,CAAC;CAGH,IACE,OAAO,SAAS,KAChB,OAAO,UAAU,cAAc,YAC/B,OAAO,UAAU,cAAc,UAE/B,OAAO,EAAE,OAAO;CAGlB,OAAO,EACL,MAAM;EACJ,WAAW,UAAU;EACrB,WAAW,UAAU;EACrB,GAAI,UAAU,eAAe,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;CAC9D,EACF;AACF;;AAGA,MAAM,cAAc,eAClB,EACE,aAAa;CACX,SAAS;CACT,QAAQ;CACR,SAAS,OAAO;EACd,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACpE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,0BAA0B,CAAC,EAAE;EAG5D,MAAM,YAAY;EAClB,MAAM,SAAmC,CAAC;EAC1C,MAAM,QAA8B,CAAC;EAErC,IAAI,OAAO,UAAU,SAAS,YAAY,UAAU,SAAS,IAC3D,OAAO,KAAK;GAAE,SAAS;GAAqC,MAAM,CAAC,MAAM;EAAE,CAAC;EAG9E,IAAI,UAAU,eAAe,UAAa,OAAO,UAAU,eAAe,UACxE,OAAO,KAAK;GACV,SAAS;GACT,MAAM,CAAC,YAAY;EACrB,CAAC;EAGH,IACE,CAAC,MAAM,QAAQ,UAAU,KAAK,KAC9B,UAAU,MAAM,WAAW,KAC3B,UAAU,MAAM,cAEhB,OAAO,KAAK;GACV,SAAS,wCAAoD;GAC7D,MAAM,CAAC,OAAO;EAChB,CAAC;OAED,UAAU,MAAM,SAAS,MAAe,UAAkB;GACxD,MAAM,UAAU,aAAa,MAAM,KAAK;GAExC,IAAI,YAAY,SACd,OAAO,KAAK,GAAG,QAAQ,MAAM;QAE7B,MAAM,KAAK,QAAQ,IAAI;EAE3B,CAAC;EAGH,IAAI,OAAO,SAAS,KAAK,OAAO,UAAU,SAAS,UACjD,OAAO,EAAE,OAAO;EAGlB,OAAO,EACL,OAAO;GACL,MAAM,UAAU;GAChB;GACA,GAAI,OAAO,UAAU,eAAe,WAChC,EAAE,YAAY,UAAU,WAAW,IACnC,CAAC;EACP,EACF;CACF;AACF,EACF,GACA,sBACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,kBACd,KACA,SAC+C;CAC/C,OAAO,KAAsC;EAC3C,MAAM,SAAS,QAAQ;EACvB,aACE;EAKF,SAAS,UAAU,WAAW,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;EAC5E,OAAO;EACP,UAAU,UAAU,IAAI,UAAU,KAAK;CACzC,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"read-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/read-file.ts"],"mappings":";;;;;;;;;AAsCA;;;;;;;;;;;;;;;;;AAG6C;;;iBAH7B,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,aAAA,EAAe,cAAA"}
1
+ {"version":3,"file":"read-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/read-file.ts"],"mappings":";;;;;;;;;AA0CA;;;;;;;;;;;;;;;;;AAG6C;;;iBAH7B,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,aAAA,EAAe,cAAA"}
@@ -1,4 +1,5 @@
1
1
  import { objectSchema, optionalNumberField, stringField } from "./schema.mjs";
2
+ import { READ_FILE_JSON_SCHEMA } from "./json-schemas.mjs";
2
3
  import { tool } from "@warlock.js/ai";
3
4
 
4
5
  //#region ../../packages/ai-workspace/src/tools/read-file.ts
@@ -9,7 +10,7 @@ const inputSchema = objectSchema({
9
10
  path: stringField(),
10
11
  startLine: optionalNumberField(),
11
12
  limit: optionalNumberField()
12
- });
13
+ }, READ_FILE_JSON_SCHEMA);
13
14
  /**
14
15
  * Build the agent-facing `read_file` tool over a workspace's policy-
15
16
  * enforced {@link WorkspaceOps}.
@@ -1 +1 @@
1
- {"version":3,"file":"read-file.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/read-file.ts"],"sourcesContent":["import { tool, type ToolContract } from \"@warlock.js/ai\";\nimport { objectSchema, optionalNumberField, stringField } from \"./schema\";\nimport type { ReadFileInput, ReadFileResult, WorkspaceOps } from \"../contracts\";\n\n/** Default tool name exposed to the LLM. */\nconst DEFAULT_NAME = \"read_file\";\n\n/** Input schema for the `read_file` tool. */\nconst inputSchema = objectSchema<ReadFileInput>({\n path: stringField(),\n startLine: optionalNumberField(),\n limit: optionalNumberField(),\n});\n\n/**\n * Build the agent-facing `read_file` tool over a workspace's policy-\n * enforced {@link WorkspaceOps}.\n *\n * The tool validates `{ path, startLine?, limit? }` against a Standard\n * Schema, then delegates to `ops.readFile`, mapping the result into the\n * agent wire shape {@link ReadFileResult} — the full file's `hash` an\n * agent must carry into a later `edit_file` (read-before-edit), plus the\n * `startLine` / `endLine` / `truncated` / `bytesCapped` window metadata.\n * The returned `content` never exceeds the policy's `read.maxBytes`.\n *\n * **Errors flow as data.** Policy violations (a jail escape) are thrown\n * by `ops`; the `tool()` wrapper catches them and surfaces them in the\n * returned `{ error }` field — `invoke()` never throws — so the agent can\n * read the failure and self-correct.\n *\n * @param ops - The shared, policy-enforced operation layer.\n * @param options - Optional overrides; `name` renames the LLM-visible tool.\n *\n * @example\n * const readTool = makeReadFileTool(ops);\n * const { data, error } = await readTool.invoke({ path: \"src/index.ts\" });\n * if (!error) console.log(data.hash); // feed into edit_file's expectHash\n */\nexport function makeReadFileTool(\n ops: WorkspaceOps,\n options?: { name?: string },\n): ToolContract<ReadFileInput, ReadFileResult> {\n return tool<ReadFileInput, ReadFileResult>({\n name: options?.name ?? DEFAULT_NAME,\n description:\n \"Read a file from the workspace, returning a numbered line window plus \" +\n \"the file's content hash. Pass the hash to edit_file's expectHash to \" +\n \"guard against editing a stale version. Use startLine/limit to page \" +\n \"through large files. Output is byte-capped by the workspace policy; \" +\n \"when bytesCapped is true the last returned line may be cut short.\",\n input: inputSchema,\n async execute(input) {\n // The ops layer owns the window and byte-cap arithmetic, so the tool\n // and the direct `readFile()` return identical results for the same\n // arguments.\n return ops.readFile(input.path, {\n offset: input.startLine !== undefined ? Math.max(1, input.startLine) : 1,\n limit: input.limit,\n });\n },\n });\n}\n"],"mappings":";;;;;AAKA,MAAM,eAAe;;AAGrB,MAAM,cAAc,aAA4B;CAC9C,MAAM,YAAY;CAClB,WAAW,oBAAoB;CAC/B,OAAO,oBAAoB;AAC7B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;AA0BD,SAAgB,iBACd,KACA,SAC6C;CAC7C,OAAO,KAAoC;EACzC,MAAM,SAAS,QAAQ;EACvB,aACE;EAKF,OAAO;EACP,MAAM,QAAQ,OAAO;GAInB,OAAO,IAAI,SAAS,MAAM,MAAM;IAC9B,QAAQ,MAAM,cAAc,SAAY,KAAK,IAAI,GAAG,MAAM,SAAS,IAAI;IACvE,OAAO,MAAM;GACf,CAAC;EACH;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"read-file.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/read-file.ts"],"sourcesContent":["import { tool, type ToolContract } from \"@warlock.js/ai\";\nimport { objectSchema, optionalNumberField, stringField } from \"./schema\";\nimport { READ_FILE_JSON_SCHEMA } from \"./json-schemas\";\nimport type { ReadFileInput, ReadFileResult, WorkspaceOps } from \"../contracts\";\n\n/** Default tool name exposed to the LLM. */\nconst DEFAULT_NAME = \"read_file\";\n\n/** Input schema for the `read_file` tool. */\nconst inputSchema = objectSchema<ReadFileInput>(\n {\n path: stringField(),\n startLine: optionalNumberField(),\n limit: optionalNumberField(),\n },\n READ_FILE_JSON_SCHEMA,\n);\n\n/**\n * Build the agent-facing `read_file` tool over a workspace's policy-\n * enforced {@link WorkspaceOps}.\n *\n * The tool validates `{ path, startLine?, limit? }` against a Standard\n * Schema, then delegates to `ops.readFile`, mapping the result into the\n * agent wire shape {@link ReadFileResult} — the full file's `hash` an\n * agent must carry into a later `edit_file` (read-before-edit), plus the\n * `startLine` / `endLine` / `truncated` / `bytesCapped` window metadata.\n * The returned `content` never exceeds the policy's `read.maxBytes`.\n *\n * **Errors flow as data.** Policy violations (a jail escape) are thrown\n * by `ops`; the `tool()` wrapper catches them and surfaces them in the\n * returned `{ error }` field — `invoke()` never throws — so the agent can\n * read the failure and self-correct.\n *\n * @param ops - The shared, policy-enforced operation layer.\n * @param options - Optional overrides; `name` renames the LLM-visible tool.\n *\n * @example\n * const readTool = makeReadFileTool(ops);\n * const { data, error } = await readTool.invoke({ path: \"src/index.ts\" });\n * if (!error) console.log(data.hash); // feed into edit_file's expectHash\n */\nexport function makeReadFileTool(\n ops: WorkspaceOps,\n options?: { name?: string },\n): ToolContract<ReadFileInput, ReadFileResult> {\n return tool<ReadFileInput, ReadFileResult>({\n name: options?.name ?? DEFAULT_NAME,\n description:\n \"Read a file from the workspace, returning a numbered line window plus \" +\n \"the file's content hash. Pass the hash to edit_file's expectHash to \" +\n \"guard against editing a stale version. Use startLine/limit to page \" +\n \"through large files. Output is byte-capped by the workspace policy; \" +\n \"when bytesCapped is true the last returned line may be cut short.\",\n input: inputSchema,\n async execute(input) {\n // The ops layer owns the window and byte-cap arithmetic, so the tool\n // and the direct `readFile()` return identical results for the same\n // arguments.\n return ops.readFile(input.path, {\n offset: input.startLine !== undefined ? Math.max(1, input.startLine) : 1,\n limit: input.limit,\n });\n },\n });\n}\n"],"mappings":";;;;;;AAMA,MAAM,eAAe;;AAGrB,MAAM,cAAc,aAClB;CACE,MAAM,YAAY;CAClB,WAAW,oBAAoB;CAC/B,OAAO,oBAAoB;AAC7B,GACA,qBACF;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,iBACd,KACA,SAC6C;CAC7C,OAAO,KAAoC;EACzC,MAAM,SAAS,QAAQ;EACvB,aACE;EAKF,OAAO;EACP,MAAM,QAAQ,OAAO;GAInB,OAAO,IAAI,SAAS,MAAM,MAAM;IAC9B,QAAQ,MAAM,cAAc,SAAY,KAAK,IAAI,GAAG,MAAM,SAAS,IAAI;IACvE,OAAO,MAAM;GACf,CAAC;EACH;CACF,CAAC;AACH"}
@@ -1,4 +1,4 @@
1
- import { RunShellInput, RunShellResult } from "../contracts/tool-io.type.mjs";
1
+ import { RunShellBackgroundResult, RunShellInput, RunShellResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
3
  import { ToolContract } from "@warlock.js/ai";
4
4
 
@@ -7,25 +7,41 @@ import { ToolContract } from "@warlock.js/ai";
7
7
  interface MakeRunShellToolOptions {
8
8
  /** Override the tool name exposed to the LLM (default `"run_shell"`). */
9
9
  name?: string;
10
+ /**
11
+ * Upper bound for a model-supplied `timeoutMs` on a foreground command —
12
+ * the model can lower the timeout, never raise it past this. The
13
+ * workspace passes its `shell.timeoutMs`.
14
+ */
15
+ maxTimeoutMs?: number;
16
+ /**
17
+ * Accept `background: true` and start the command as a background job
18
+ * (`ops.startShell`), returning a {@link RunShellBackgroundResult}. The
19
+ * workspace sets it when the policy has `shell.background`. Default
20
+ * `false`: a background request is refused.
21
+ */
22
+ background?: boolean;
10
23
  }
11
24
  /**
12
- * Build the `run_shell` tool — a {@link ToolContract} that runs a single
13
- * shell command through the policy-enforced {@link WorkspaceOps} layer.
25
+ * Build the `run_shell` tool — a {@link ToolContract} that runs a command
26
+ * line through the policy-enforced {@link WorkspaceOps} layer.
14
27
  *
15
- * The command's leading executable basename is gated against the shell
16
- * allow/deny policy by `ops.exec`; a blocked command throws a
17
- * `WorkspacePolicyError` which the `tool()` runtime catches and surfaces
18
- * in the result's `error` field (never a thrown run-killer), so the agent
19
- * reads the refusal as tool data and self-corrects. A command that runs
20
- * but exits non-zero is *not* an error — its `exitCode`/`stderr` come back
21
- * in `data` for the agent to inspect.
28
+ * Every command in the line is checked against the shell policy by
29
+ * `ops.exec`; a refused line throws a `WorkspacePolicyError` (with a
30
+ * `reason` and a message that says how to fix the command) which the
31
+ * `tool()` runtime catches and surfaces in the result's `error` field
32
+ * (never a thrown run-killer), so the agent reads the refusal as tool data
33
+ * and self-corrects. A command that runs but exits non-zero is *not* an
34
+ * error — its `exitCode`/`stderr` come back in `data` for the agent to
35
+ * inspect.
22
36
  *
23
37
  * The agent run's cancellation `signal` (from the dispatch `ctx`) is passed
24
38
  * to `ops.exec` per invocation: a cancelled run never starts the command,
25
39
  * and one cancelled mid-command kills its process tree (`cancelled: true`).
40
+ * A background command (`background: true`, when enabled) belongs to the
41
+ * workspace instead and keeps running after the call returns.
26
42
  *
27
43
  * @param ops - The policy-enforced operation layer to delegate `exec` to.
28
- * @param options - Optional tool-name override.
44
+ * @param options - Tool-name override, timeout cap and background support.
29
45
  *
30
46
  * @example
31
47
  * const runShell = makeRunShellTool(ops);
@@ -33,7 +49,13 @@ interface MakeRunShellToolOptions {
33
49
  * if (error) handleDenied(error);
34
50
  * else console.log(data.exitCode, data.stdout);
35
51
  */
36
- declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions): ToolContract<RunShellInput, RunShellResult>;
52
+ declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions & {
53
+ background?: false;
54
+ }): ToolContract<RunShellInput, RunShellResult>;
55
+ declare function makeRunShellTool(ops: WorkspaceOps, options: MakeRunShellToolOptions & {
56
+ background: true;
57
+ }): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;
58
+ declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;
37
59
  //#endregion
38
60
  export { MakeRunShellToolOptions, makeRunShellTool };
39
61
  //# sourceMappingURL=run-shell.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-shell.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-shell.ts"],"mappings":";;;;;;UAsDiB,uBAAA;;EAEf,IAAI;AAAA;;;;AAAA;AA4BN;;;;;;;;;;;;;;;;;;AAG6C;;;iBAH7B,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA,GACT,YAAA,CAAa,aAAA,EAAe,cAAA"}
1
+ {"version":3,"file":"run-shell.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-shell.ts"],"mappings":";;;;;;UA2EiB,uBAAA;;EAEf,IAAA;EAFe;;;;;EAQf,YAAA;EAOA;;AAAU;AAwCZ;;;EAxCE,UAAA;AAAA;;;;;;;;;;;;;;;AA2C2C;AAC7C;;;;;;;;;;;;;iBAJgB,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA;EAA4B,UAAA;AAAA,IACrC,YAAA,CAAa,aAAA,EAAe,cAAA;AAAA,iBACf,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,EAAS,uBAAA;EAA4B,UAAA;AAAA,IACpC,YAAA,CAAa,aAAA,EAAe,cAAA,GAAiB,wBAAA;AAAA,iBAChC,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA,GACT,YAAA,CAAa,aAAA,EAAe,cAAA,GAAiB,wBAAA"}