@mikode13/harness 4.0.1 → 5.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 (170) hide show
  1. package/README.md +299 -17
  2. package/dist/agent/domain/agent.d.ts +32 -1
  3. package/dist/agent/domain/agent.js.map +1 -1
  4. package/dist/agent/domain/approval.d.ts +9 -0
  5. package/dist/agent/domain/approval.js.map +1 -1
  6. package/dist/agent/domain/runContext.d.ts +31 -0
  7. package/dist/agent/domain/runContext.js +47 -0
  8. package/dist/agent/domain/runContext.js.map +1 -0
  9. package/dist/diff/domain/unifiedDiff.d.ts +19 -0
  10. package/dist/diff/domain/unifiedDiff.js +166 -0
  11. package/dist/diff/domain/unifiedDiff.js.map +1 -0
  12. package/dist/engines/domain/model/historyFollower.d.ts +41 -0
  13. package/dist/engines/domain/model/historyFollower.js +158 -0
  14. package/dist/engines/domain/model/historyFollower.js.map +1 -0
  15. package/dist/engines/domain/model/llmAgent.d.ts +42 -4
  16. package/dist/engines/domain/model/llmAgent.js +287 -31
  17. package/dist/engines/domain/model/llmAgent.js.map +1 -1
  18. package/dist/factory/infrastructure/agentFactory.d.ts +14 -0
  19. package/dist/factory/infrastructure/agentFactory.js +20 -2
  20. package/dist/factory/infrastructure/agentFactory.js.map +1 -1
  21. package/dist/factory/infrastructure/agentLLMFactory.d.ts +119 -14
  22. package/dist/factory/infrastructure/agentLLMFactory.js +284 -57
  23. package/dist/factory/infrastructure/agentLLMFactory.js.map +1 -1
  24. package/dist/index.d.ts +13 -5
  25. package/dist/index.js +5 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/llm/domain/conversation.d.ts +44 -4
  28. package/dist/llm/domain/conversation.js +56 -7
  29. package/dist/llm/domain/conversation.js.map +1 -1
  30. package/dist/llm/domain/llm.d.ts +3 -1
  31. package/dist/llm/domain/llm.js.map +1 -1
  32. package/dist/llm/domain/tool.d.ts +13 -0
  33. package/dist/llm/domain/tool.js +12 -1
  34. package/dist/llm/domain/tool.js.map +1 -1
  35. package/dist/llm/infrastructure/claudeLLMClient.d.ts +3 -2
  36. package/dist/llm/infrastructure/claudeLLMClient.js +38 -10
  37. package/dist/llm/infrastructure/claudeLLMClient.js.map +1 -1
  38. package/dist/llm/infrastructure/openAILLMClient.d.ts +2 -1
  39. package/dist/llm/infrastructure/openAILLMClient.js +67 -17
  40. package/dist/llm/infrastructure/openAILLMClient.js.map +1 -1
  41. package/dist/orchestration/domain/model/orchestratorAgent.d.ts +17 -3
  42. package/dist/orchestration/domain/model/orchestratorAgent.js +65 -8
  43. package/dist/orchestration/domain/model/orchestratorAgent.js.map +1 -1
  44. package/dist/recovery/domain/fileChanges.d.ts +31 -0
  45. package/dist/recovery/domain/fileChanges.js +48 -0
  46. package/dist/recovery/domain/fileChanges.js.map +1 -0
  47. package/dist/recovery/domain/history.d.ts +114 -0
  48. package/dist/recovery/domain/history.js +62 -0
  49. package/dist/recovery/domain/history.js.map +1 -0
  50. package/dist/recovery/domain/recoveryStore.d.ts +233 -0
  51. package/dist/recovery/domain/recoveryStore.js +32 -0
  52. package/dist/recovery/domain/recoveryStore.js.map +1 -0
  53. package/dist/recovery/domain/retention.d.ts +33 -0
  54. package/dist/recovery/domain/retention.js +90 -0
  55. package/dist/recovery/domain/retention.js.map +1 -0
  56. package/dist/recovery/domain/runChanges.d.ts +37 -0
  57. package/dist/recovery/domain/runChanges.js +109 -0
  58. package/dist/recovery/domain/runChanges.js.map +1 -0
  59. package/dist/recovery/domain/runTree.d.ts +32 -0
  60. package/dist/recovery/domain/runTree.js +90 -0
  61. package/dist/recovery/domain/runTree.js.map +1 -0
  62. package/dist/recovery/infrastructure/createHistory.d.ts +11 -0
  63. package/dist/recovery/infrastructure/createHistory.js +17 -0
  64. package/dist/recovery/infrastructure/createHistory.js.map +1 -0
  65. package/dist/recovery/infrastructure/fileRecoveryStore.d.ts +133 -0
  66. package/dist/recovery/infrastructure/fileRecoveryStore.js +1043 -0
  67. package/dist/recovery/infrastructure/fileRecoveryStore.js.map +1 -0
  68. package/dist/recovery/infrastructure/workspaceFiles.d.ts +30 -0
  69. package/dist/recovery/infrastructure/workspaceFiles.js +125 -0
  70. package/dist/recovery/infrastructure/workspaceFiles.js.map +1 -0
  71. package/dist/tools/domain/accessPolicy.d.ts +30 -0
  72. package/dist/tools/domain/accessPolicy.js +11 -0
  73. package/dist/tools/domain/accessPolicy.js.map +1 -0
  74. package/dist/tools/domain/commands.d.ts +93 -0
  75. package/dist/tools/domain/commands.js +191 -0
  76. package/dist/tools/domain/commands.js.map +1 -0
  77. package/dist/tools/domain/editResponse.d.ts +14 -0
  78. package/dist/tools/domain/editResponse.js +79 -0
  79. package/dist/tools/domain/editResponse.js.map +1 -0
  80. package/dist/tools/domain/fileEdits.d.ts +64 -0
  81. package/dist/tools/domain/fileEdits.js +21 -0
  82. package/dist/tools/domain/fileEdits.js.map +1 -0
  83. package/dist/tools/domain/lineLength.d.ts +7 -0
  84. package/dist/tools/domain/lineLength.js +26 -0
  85. package/dist/tools/domain/lineLength.js.map +1 -0
  86. package/dist/tools/domain/preparedCall.d.ts +44 -0
  87. package/dist/tools/domain/preparedCall.js +26 -0
  88. package/dist/tools/domain/preparedCall.js.map +1 -0
  89. package/dist/tools/domain/readRegistry.d.ts +46 -0
  90. package/dist/tools/domain/readRegistry.js +62 -0
  91. package/dist/tools/domain/readRegistry.js.map +1 -0
  92. package/dist/tools/domain/textLines.d.ts +26 -0
  93. package/dist/tools/domain/textLines.js +44 -0
  94. package/dist/tools/domain/textLines.js.map +1 -0
  95. package/dist/tools/domain/tool.d.ts +14 -0
  96. package/dist/tools/domain/tool.js +7 -1
  97. package/dist/tools/domain/tool.js.map +1 -1
  98. package/dist/tools/domain/v4aPatch.d.ts +17 -0
  99. package/dist/tools/domain/v4aPatch.js +236 -0
  100. package/dist/tools/domain/v4aPatch.js.map +1 -0
  101. package/dist/tools/infrastructure/boundedWorkspace.d.ts +11 -2
  102. package/dist/tools/infrastructure/boundedWorkspace.js +9 -1
  103. package/dist/tools/infrastructure/boundedWorkspace.js.map +1 -1
  104. package/dist/tools/infrastructure/commandCheckpoint.d.ts +55 -0
  105. package/dist/tools/infrastructure/commandCheckpoint.js +178 -0
  106. package/dist/tools/infrastructure/commandCheckpoint.js.map +1 -0
  107. package/dist/tools/infrastructure/commandProcess.d.ts +47 -0
  108. package/dist/tools/infrastructure/commandProcess.js +217 -0
  109. package/dist/tools/infrastructure/commandProcess.js.map +1 -0
  110. package/dist/tools/infrastructure/commandTool.d.ts +36 -0
  111. package/dist/tools/infrastructure/commandTool.js +285 -0
  112. package/dist/tools/infrastructure/commandTool.js.map +1 -0
  113. package/dist/tools/infrastructure/createWorkspace.d.ts +10 -0
  114. package/dist/tools/infrastructure/createWorkspace.js +11 -3
  115. package/dist/tools/infrastructure/createWorkspace.js.map +1 -1
  116. package/dist/tools/infrastructure/defineTool.d.ts +18 -2
  117. package/dist/tools/infrastructure/defineTool.js +52 -6
  118. package/dist/tools/infrastructure/defineTool.js.map +1 -1
  119. package/dist/tools/infrastructure/editFormats.d.ts +22 -0
  120. package/dist/tools/infrastructure/editFormats.js +243 -0
  121. package/dist/tools/infrastructure/editFormats.js.map +1 -0
  122. package/dist/tools/infrastructure/fileEditor.d.ts +64 -0
  123. package/dist/tools/infrastructure/fileEditor.js +306 -0
  124. package/dist/tools/infrastructure/fileEditor.js.map +1 -0
  125. package/dist/tools/infrastructure/fileTools.d.ts +81 -0
  126. package/dist/tools/infrastructure/fileTools.js +152 -0
  127. package/dist/tools/infrastructure/fileTools.js.map +1 -0
  128. package/dist/tools/infrastructure/gitIgnoreRules.d.ts +15 -0
  129. package/dist/tools/infrastructure/gitIgnoreRules.js +74 -0
  130. package/dist/tools/infrastructure/gitIgnoreRules.js.map +1 -0
  131. package/dist/tools/infrastructure/gitWorkspace.d.ts +1 -1
  132. package/dist/tools/infrastructure/gitWorkspace.js +1 -1
  133. package/dist/tools/infrastructure/gitWorkspace.js.map +1 -1
  134. package/dist/tools/infrastructure/ignoreFileChanges.d.ts +14 -0
  135. package/dist/tools/infrastructure/ignoreFileChanges.js +62 -0
  136. package/dist/tools/infrastructure/ignoreFileChanges.js.map +1 -0
  137. package/dist/tools/infrastructure/policyWorkspace.d.ts +52 -0
  138. package/dist/tools/infrastructure/policyWorkspace.js +32 -0
  139. package/dist/tools/infrastructure/policyWorkspace.js.map +1 -0
  140. package/dist/tools/infrastructure/ripgrepWorkspace.d.ts +2 -1
  141. package/dist/tools/infrastructure/ripgrepWorkspace.js +1 -1
  142. package/dist/tools/infrastructure/ripgrepWorkspace.js.map +1 -1
  143. package/dist/tools/infrastructure/rootsAccessPolicy.d.ts +100 -0
  144. package/dist/tools/infrastructure/rootsAccessPolicy.js +301 -0
  145. package/dist/tools/infrastructure/rootsAccessPolicy.js.map +1 -0
  146. package/dist/tools/infrastructure/runProcess.d.ts +4 -1
  147. package/dist/tools/infrastructure/runProcess.js +4 -2
  148. package/dist/tools/infrastructure/runProcess.js.map +1 -1
  149. package/dist/tools/infrastructure/secretPaths.d.ts +8 -0
  150. package/dist/tools/infrastructure/secretPaths.js +76 -0
  151. package/dist/tools/infrastructure/secretPaths.js.map +1 -0
  152. package/dist/tools/infrastructure/showChangesTool.d.ts +12 -0
  153. package/dist/tools/infrastructure/showChangesTool.js +44 -0
  154. package/dist/tools/infrastructure/showChangesTool.js.map +1 -0
  155. package/dist/tools/infrastructure/trackedEdits.d.ts +33 -0
  156. package/dist/tools/infrastructure/trackedEdits.js +70 -0
  157. package/dist/tools/infrastructure/trackedEdits.js.map +1 -0
  158. package/dist/tools/infrastructure/trackedReadFile.d.ts +21 -0
  159. package/dist/tools/infrastructure/trackedReadFile.js +79 -0
  160. package/dist/tools/infrastructure/trackedReadFile.js.map +1 -0
  161. package/dist/tools/infrastructure/workspaceTools.d.ts +34 -0
  162. package/dist/tools/infrastructure/workspaceTools.js +69 -40
  163. package/dist/tools/infrastructure/workspaceTools.js.map +1 -1
  164. package/dist/tools/infrastructure/workspaceWrites.d.ts +23 -0
  165. package/dist/tools/infrastructure/workspaceWrites.js +42 -0
  166. package/dist/tools/infrastructure/workspaceWrites.js.map +1 -0
  167. package/dist/tools/infrastructure/writeSession.d.ts +35 -0
  168. package/dist/tools/infrastructure/writeSession.js +81 -0
  169. package/dist/tools/infrastructure/writeSession.js.map +1 -0
  170. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"workspaceTools.js","sourceRoot":"","sources":["../../../src/tools/infrastructure/workspaceTools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport type { Tool } from '../domain/tool.ts';\nimport type { Workspace } from '../domain/workspace.ts';\nimport { defineTool } from './defineTool.ts';\n\n// What one call may return. The model can ask for fewer lines, never for more.\nconst maxFiles = 200;\nconst maxMatches = 100;\nconst maxLines = 200;\n// One minified line can be larger than everything else the model has read.\nconst maxLineLength = 300;\n\n// Strict mode has no optional fields: an argument the model may leave out is nullable.\nconst scope = {\n\tpath: z.string().nullable().describe('A folder or file to stay inside, relative to the root.'),\n\tglob: z.string().nullable().describe('Only paths matching this glob, such as \"**/*.ts\".'),\n};\n\n/** One line as the model reads it: a minified bundle on a single line would flood its context. */\nfunction cutLine(text: string): string {\n\treturn text.length > maxLineLength ? `${text.slice(0, maxLineLength)}…` : text;\n}\n\nfunction assertPositiveInteger(name: string, value: number): void {\n\tif (!Number.isInteger(value) || value < 1) {\n\t\tthrow new Error(`${name} must be a whole number of at least 1; got ${String(value)}`);\n\t}\n}\n\n/** The three read-only tools an agent explores a repository with. */\nexport function createWorkspaceTools(workspace: Workspace): Tool[] {\n\treturn [\n\t\tdefineTool({\n\t\t\tname: 'listFiles',\n\t\t\tdescription:\n\t\t\t\t'Lists the files of the repository, sorted. Ignored files such as dependencies are left out.',\n\t\t\trisk: 'safe',\n\t\t\tinput: z.object(scope),\n\t\t\texecute: async ({ path, glob }, signal) => {\n\t\t\t\t// The port takes \"no scope\" as a missing field.\n\t\t\t\tconst { files, total, truncated } = await workspace.listFiles(\n\t\t\t\t\t{ path: path ?? undefined, glob: glob ?? undefined, limit: maxFiles },\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\n\t\t\t\t// Nothing found is an answer too, not an empty string.\n\t\t\t\tif (files.length === 0) {\n\t\t\t\t\treturn 'No files.';\n\t\t\t\t}\n\n\t\t\t\tconst notice = truncated\n\t\t\t\t\t? `\\n[Showing ${String(files.length)} of ${String(total)} files. Narrow the path or glob to see the rest.]`\n\t\t\t\t\t: '';\n\t\t\t\treturn files.join('\\n') + notice;\n\t\t\t},\n\t\t}),\n\n\t\tdefineTool({\n\t\t\tname: 'searchText',\n\t\t\tdescription:\n\t\t\t\t'Searches the repository for a regular expression and returns each matching line as path:line: text.',\n\t\t\trisk: 'safe',\n\t\t\tinput: z.object({\n\t\t\t\tpattern: z.string().describe('A regular expression.'),\n\t\t\t\tignoreCase: z.boolean().nullable().describe('Match regardless of case. Defaults to false.'),\n\t\t\t\t...scope,\n\t\t\t}),\n\t\t\texecute: async ({ path, glob, ignoreCase, pattern }, signal) => {\n\t\t\t\tconst { matches, total, truncated } = await workspace.searchText(\n\t\t\t\t\t{\n\t\t\t\t\t\tpath: path ?? undefined,\n\t\t\t\t\t\tglob: glob ?? undefined,\n\t\t\t\t\t\tignoreCase: ignoreCase ?? false,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tlimit: maxMatches,\n\t\t\t\t\t},\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\n\t\t\t\tif (matches.length === 0) {\n\t\t\t\t\treturn 'No matches.';\n\t\t\t\t}\n\n\t\t\t\tconst results = matches.map(\n\t\t\t\t\tmatch => `${match.path}:${String(match.line)}: ${cutLine(match.text)}`,\n\t\t\t\t);\n\n\t\t\t\tconst notice = truncated\n\t\t\t\t\t? `\\n[Showing ${String(results.length)} of ${String(total)} matches. Narrow the path or glob to see the rest.]`\n\t\t\t\t\t: '';\n\t\t\t\treturn results.join('\\n') + notice;\n\t\t\t},\n\t\t}),\n\n\t\tdefineTool({\n\t\t\tname: 'readFile',\n\t\t\tdescription: 'Reads lines of a file, each prefixed with its number.',\n\t\t\trisk: 'safe',\n\t\t\tinput: z.object({\n\t\t\t\tpath: z.string().describe('The file, relative to the root.'),\n\t\t\t\tfromLine: z.number().nullable().describe('The first line to read, from 1. Defaults to 1.'),\n\t\t\t\tlineCount: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.nullable()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t`How many lines to read, at most ${String(maxLines)}. Defaults to ${String(maxLines)}.`,\n\t\t\t\t\t),\n\t\t\t}),\n\t\t\texecute: async ({ fromLine, lineCount, path }, signal) => {\n\t\t\t\tconst from = fromLine ?? 1;\n\t\t\t\tconst requested = lineCount ?? maxLines;\n\t\t\t\t// Checked here, before reading, because strict mode allows the schema no minimum.\n\t\t\t\tassertPositiveInteger('fromLine', from);\n\t\t\t\tassertPositiveInteger('lineCount', requested);\n\n\t\t\t\tconst { lines, totalLines, truncated } = await workspace.readFile(\n\t\t\t\t\t{ path, fromLine: from, lineCount: Math.min(requested, maxLines) },\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\n\t\t\t\t// The file's length tells the model where its range went wrong.\n\t\t\t\tif (lines.length === 0) {\n\t\t\t\t\treturn `No lines from ${String(from)}: the file has ${String(totalLines)} lines.`;\n\t\t\t\t}\n\n\t\t\t\tconst numbered = lines.map((text, index) => `${String(from + index)}: ${cutLine(text)}`);\n\t\t\t\tconst cut = lines.filter(text => text.length > maxLineLength).length;\n\t\t\t\tconst notices = [\n\t\t\t\t\t...(cut > 0\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t`[${String(cut)} lines were longer than ${String(maxLineLength)} characters and were cut.]`,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t\t...(truncated\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t`[The file has ${String(totalLines)} lines. Read from line ${String(from + lines.length)} to continue.]`,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: []),\n\t\t\t\t];\n\t\t\t\treturn [...numbered, ...notices].join('\\n');\n\t\t\t},\n\t\t}),\n\t];\n}\n"]}
1
+ {"version":3,"file":"workspaceTools.js","sourceRoot":"","sources":["../../../src/tools/infrastructure/workspaceTools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport type { Tool } from '../domain/tool.ts';\nimport type { Workspace } from '../domain/workspace.ts';\nimport { defineTool } from './defineTool.ts';\nimport { cutLine, maxLineLength } from '../domain/lineLength.ts';\n\n// What one call may return. The model can ask for fewer lines, never for more.\nconst maxFiles = 200;\nconst maxMatches = 100;\nconst maxLines = 200;\n// One minified line can be larger than everything else the model has read.\n\n// Strict mode has no optional fields: an argument the model may leave out is nullable.\nconst scope = {\n\tpath: z.string().nullable().describe('A folder or file to stay inside, relative to the root.'),\n\tglob: z\n\t\t.string()\n\t\t.nullable()\n\t\t.describe(\n\t\t\t'Only paths matching this glob, relative to the root. \"*\" stays inside one folder and \"**\" crosses folders: \"**/*.ts\" is every TypeScript file, \"*.ts\" only those at the top.',\n\t\t),\n};\n\n/**\n * Lines of a file as the model reads them: each numbered, a line too long cut, and a notice for\n * what was cut or lies beyond.\n */\nexport function renderLines({\n\tpath,\n\tlines,\n\tfrom,\n\ttotalLines,\n\ttruncated,\n}: {\n\t/** The file, which decides how long a line may be. */\n\tpath: string;\n\tlines: string[];\n\tfrom: number;\n\ttotalLines: number;\n\ttruncated: boolean;\n}): string {\n\t// The file's length tells the model where its range went wrong.\n\tif (lines.length === 0) {\n\t\treturn `No lines from ${String(from)}: the file has ${String(totalLines)} lines.`;\n\t}\n\n\tconst numbered = lines.map((text, index) => `${String(from + index)}: ${cutLine(path, text)}`);\n\tconst max = maxLineLength(path);\n\tconst cut = lines.filter(text => text.length > max).length;\n\tconst notices = [\n\t\t...(cut > 0\n\t\t\t? [`[${String(cut)} lines were longer than ${String(max)} characters and were cut.]`]\n\t\t\t: []),\n\t\t...(truncated\n\t\t\t? [\n\t\t\t\t\t`[The file has ${String(totalLines)} lines. Read from line ${String(from + lines.length)} to continue.]`,\n\t\t\t\t]\n\t\t\t: []),\n\t];\n\treturn [...numbered, ...notices].join('\\n');\n}\n\n/** What `readFile` takes, shared with the harness's own version of it. */\nexport const readFileDescription = 'Reads lines of a file, each prefixed with its number.';\nexport const readFileInput = z.object({\n\tpath: z.string().describe('The file, relative to the root.'),\n\tfromLine: z.number().nullable().describe('The first line to read, from 1. Defaults to 1.'),\n\tlineCount: z\n\t\t.number()\n\t\t.nullable()\n\t\t.describe(\n\t\t\t`How many lines to read, at most ${String(maxLines)}. Defaults to ${String(maxLines)}.`,\n\t\t),\n});\n\n/** The range a `readFile` call asks for, checked: strict mode allows the schema no minimum. */\nexport function readRange({\n\tfromLine,\n\tlineCount,\n}: {\n\tfromLine: number | null;\n\tlineCount: number | null;\n}): { from: number; count: number } {\n\tconst from = fromLine ?? 1;\n\tconst requested = lineCount ?? maxLines;\n\tassertPositiveInteger('fromLine', from);\n\tassertPositiveInteger('lineCount', requested);\n\treturn { from, count: Math.min(requested, maxLines) };\n}\n\n/** A stable description of a read request, using only the range the model supplied. */\nexport function readFileSummary({\n\tpath,\n\tfromLine,\n\tlineCount,\n}: {\n\tpath: string;\n\tfromLine: number | null;\n\tlineCount: number | null;\n}): string {\n\tconst suppliedFrom = fromLine ?? 1;\n\tconst from = Number.isInteger(suppliedFrom) && suppliedFrom > 0 ? suppliedFrom : 1;\n\tconst suppliedCount = lineCount ?? maxLines;\n\tconst requested = Number.isInteger(suppliedCount) && suppliedCount > 0 ? suppliedCount : maxLines;\n\tconst count = Math.min(requested, maxLines);\n\treturn `${path}:${String(from)}-${String(from + count - 1)}`;\n}\n\nfunction scopeSummary(path: string | null, glob: string | null): string {\n\tconst scopePath = path ?? '.';\n\treturn glob ? `${scopePath === '.' ? '' : `${scopePath}/`}${glob}` : scopePath;\n}\n\nfunction assertPositiveInteger(name: string, value: number): void {\n\tif (!Number.isInteger(value) || value < 1) {\n\t\tthrow new Error(`${name} must be a whole number of at least 1; got ${String(value)}`);\n\t}\n}\n\n/** The three read-only tools an agent explores a repository with. */\nexport function createWorkspaceTools(workspace: Workspace): Tool[] {\n\treturn [\n\t\tdefineTool({\n\t\t\tname: 'listFiles',\n\t\t\tdescription:\n\t\t\t\t'Lists the files of the repository, sorted. Ignored files such as dependencies are left out.',\n\t\t\trisk: 'safe',\n\t\t\tinput: z.object(scope),\n\t\t\tsummarize: ({ path, glob }) => scopeSummary(path, glob),\n\t\t\texecute: async ({ path, glob }, signal) => {\n\t\t\t\t// The port takes \"no scope\" as a missing field.\n\t\t\t\tconst { files, total, truncated } = await workspace.listFiles(\n\t\t\t\t\t{ path: path ?? undefined, glob: glob ?? undefined, limit: maxFiles },\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\n\t\t\t\t// Nothing found is an answer too, not an empty string.\n\t\t\t\tif (files.length === 0) {\n\t\t\t\t\treturn 'No files.';\n\t\t\t\t}\n\n\t\t\t\tconst notice = truncated\n\t\t\t\t\t? `\\n[Showing ${String(files.length)} of ${String(total)} files. Narrow the path or glob to see the rest.]`\n\t\t\t\t\t: '';\n\t\t\t\treturn files.join('\\n') + notice;\n\t\t\t},\n\t\t}),\n\n\t\tdefineTool({\n\t\t\tname: 'searchText',\n\t\t\tdescription:\n\t\t\t\t'Searches the repository for a regular expression and returns each matching line as path:line: text.',\n\t\t\trisk: 'safe',\n\t\t\tinput: z.object({\n\t\t\t\tpattern: z.string().describe('A regular expression.'),\n\t\t\t\tignoreCase: z.boolean().nullable().describe('Match regardless of case. Defaults to false.'),\n\t\t\t\t...scope,\n\t\t\t}),\n\t\t\tsummarize: ({ path, glob, pattern }) => `\"${pattern}\" in ${scopeSummary(path, glob)}`,\n\t\t\texecute: async ({ path, glob, ignoreCase, pattern }, signal) => {\n\t\t\t\tconst { matches, total, truncated } = await workspace.searchText(\n\t\t\t\t\t{\n\t\t\t\t\t\tpath: path ?? undefined,\n\t\t\t\t\t\tglob: glob ?? undefined,\n\t\t\t\t\t\tignoreCase: ignoreCase ?? false,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tlimit: maxMatches,\n\t\t\t\t\t},\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\n\t\t\t\tif (matches.length === 0) {\n\t\t\t\t\treturn 'No matches.';\n\t\t\t\t}\n\n\t\t\t\tconst results = matches.map(\n\t\t\t\t\tmatch => `${match.path}:${String(match.line)}: ${cutLine(match.path, match.text)}`,\n\t\t\t\t);\n\n\t\t\t\tconst notice = truncated\n\t\t\t\t\t? `\\n[Showing ${String(results.length)} of ${String(total)} matches. Narrow the path or glob to see the rest.]`\n\t\t\t\t\t: '';\n\t\t\t\treturn results.join('\\n') + notice;\n\t\t\t},\n\t\t}),\n\n\t\tdefineTool({\n\t\t\tname: 'readFile',\n\t\t\tdescription: readFileDescription,\n\t\t\trisk: 'safe',\n\t\t\tinput: readFileInput,\n\t\t\tsummarize: readFileSummary,\n\t\t\texecute: async ({ fromLine, lineCount, path }, signal) => {\n\t\t\t\t// Checked before reading.\n\t\t\t\tconst { from, count } = readRange({ fromLine, lineCount });\n\t\t\t\tconst { lines, totalLines, truncated } = await workspace.readFile(\n\t\t\t\t\t{ path, fromLine: from, lineCount: count },\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\t\t\t\treturn renderLines({ path, lines, from, totalLines, truncated });\n\t\t\t},\n\t\t}),\n\t];\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import type { RunContext } from '#src/agent/domain/runContext';
2
+ import type { RecoveryStore } from '#src/recovery/domain/recoveryStore';
3
+ import type { AccessPolicy } from '../domain/accessPolicy.ts';
4
+ import { FileEditor } from './fileEditor.ts';
5
+ import { WriteSession } from './writeSession.ts';
6
+ /**
7
+ * The writing side of a workspace, shared by every write tool built over it: one policy and
8
+ * one recovery store, and one `WriteSession` per run, ended with that run. A session lives
9
+ * only as long as its run's context, so nothing here outlives a run.
10
+ */
11
+ export declare class WorkspaceWrites {
12
+ private readonly policy;
13
+ private readonly store;
14
+ private readonly sessions;
15
+ constructor({ policy, store }: {
16
+ policy: AccessPolicy;
17
+ store: RecoveryStore;
18
+ });
19
+ /** An editor over this run's session, created on the run's first write tool call. */
20
+ editorFor(context: RunContext): FileEditor;
21
+ /** Everything this run writes, its commands' changes included, created on its first write. */
22
+ sessionFor(context: RunContext): WriteSession;
23
+ }
@@ -0,0 +1,42 @@
1
+ import { FileEditor } from "./fileEditor.js";
2
+ import { WriteSession } from "./writeSession.js";
3
+ /**
4
+ * The writing side of a workspace, shared by every write tool built over it: one policy and
5
+ * one recovery store, and one `WriteSession` per run, ended with that run. A session lives
6
+ * only as long as its run's context, so nothing here outlives a run.
7
+ */
8
+ export class WorkspaceWrites {
9
+ policy;
10
+ store;
11
+ sessions = new WeakMap();
12
+ constructor({ policy, store }) {
13
+ this.policy = policy;
14
+ this.store = store;
15
+ }
16
+ /** An editor over this run's session, created on the run's first write tool call. */
17
+ editorFor(context) {
18
+ return new FileEditor({ policy: this.policy, session: this.sessionFor(context) });
19
+ }
20
+ /** Everything this run writes, its commands' changes included, created on its first write. */
21
+ sessionFor(context) {
22
+ let session = this.sessions.get(context);
23
+ if (!session) {
24
+ const created = new WriteSession({
25
+ store: this.store,
26
+ // So every turn of the run, in every role, can be tied to what it wrote.
27
+ onStart: runId => {
28
+ context.historyRun.runId = runId;
29
+ },
30
+ // A run that changed nothing is not in the history, so its turns wrote nothing.
31
+ onDiscard: () => {
32
+ delete context.historyRun.runId;
33
+ },
34
+ });
35
+ context.onFinish(end => created.finish(end));
36
+ this.sessions.set(context, created);
37
+ session = created;
38
+ }
39
+ return session;
40
+ }
41
+ }
42
+ //# sourceMappingURL=workspaceWrites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaceWrites.js","sourceRoot":"","sources":["../../../src/tools/infrastructure/workspaceWrites.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,OAAO,eAAe;IACV,MAAM,CAAe;IACrB,KAAK,CAAgB;IACrB,QAAQ,GAAG,IAAI,OAAO,EAA4B,CAAC;IAEpE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAkD;QAC5E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,qFAAqF;IACrF,SAAS,CAAC,OAAmB;QAC5B,OAAO,IAAI,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,8FAA8F;IAC9F,UAAU,CAAC,OAAmB;QAC7B,IAAI,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;gBAChC,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,yEAAyE;gBACzE,OAAO,EAAE,KAAK,CAAC,EAAE;oBAChB,OAAO,CAAC,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;gBAClC,CAAC;gBACD,gFAAgF;gBAChF,SAAS,EAAE,GAAG,EAAE;oBACf,OAAO,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;gBACjC,CAAC;aACD,CAAC,CAAC;YACH,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACpC,OAAO,GAAG,OAAO,CAAC;QACnB,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;CACD","sourcesContent":["import type { RunContext } from '#src/agent/domain/runContext';\nimport type { RecoveryStore } from '#src/recovery/domain/recoveryStore';\nimport type { AccessPolicy } from '../domain/accessPolicy.ts';\nimport { FileEditor } from './fileEditor.ts';\nimport { WriteSession } from './writeSession.ts';\n\n/**\n * The writing side of a workspace, shared by every write tool built over it: one policy and\n * one recovery store, and one `WriteSession` per run, ended with that run. A session lives\n * only as long as its run's context, so nothing here outlives a run.\n */\nexport class WorkspaceWrites {\n\tprivate readonly policy: AccessPolicy;\n\tprivate readonly store: RecoveryStore;\n\tprivate readonly sessions = new WeakMap<RunContext, WriteSession>();\n\n\tconstructor({ policy, store }: { policy: AccessPolicy; store: RecoveryStore }) {\n\t\tthis.policy = policy;\n\t\tthis.store = store;\n\t}\n\n\t/** An editor over this run's session, created on the run's first write tool call. */\n\teditorFor(context: RunContext): FileEditor {\n\t\treturn new FileEditor({ policy: this.policy, session: this.sessionFor(context) });\n\t}\n\n\t/** Everything this run writes, its commands' changes included, created on its first write. */\n\tsessionFor(context: RunContext): WriteSession {\n\t\tlet session = this.sessions.get(context);\n\t\tif (!session) {\n\t\t\tconst created = new WriteSession({\n\t\t\t\tstore: this.store,\n\t\t\t\t// So every turn of the run, in every role, can be tied to what it wrote.\n\t\t\t\tonStart: runId => {\n\t\t\t\t\tcontext.historyRun.runId = runId;\n\t\t\t\t},\n\t\t\t\t// A run that changed nothing is not in the history, so its turns wrote nothing.\n\t\t\t\tonDiscard: () => {\n\t\t\t\t\tdelete context.historyRun.runId;\n\t\t\t\t},\n\t\t\t});\n\t\t\tcontext.onFinish(end => created.finish(end));\n\t\t\tthis.sessions.set(context, created);\n\t\t\tsession = created;\n\t\t}\n\t\treturn session;\n\t}\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import { type RecoveryStore, type RunJournal, type RunStatus } from '#src/recovery/domain/recoveryStore';
2
+ /**
3
+ * Everything one top-level run writes, across all its roles and rounds. Its journal starts on
4
+ * the first write, so a run that only reads never holds the workspace, and ends with the run.
5
+ * Once a change could not be confirmed, the session refuses every further write: the record of
6
+ * what the run did must stay complete.
7
+ */
8
+ export declare class WriteSession {
9
+ private readonly store;
10
+ private readonly maxChanges;
11
+ private readonly onStart;
12
+ private readonly onDiscard;
13
+ private journal;
14
+ private changes;
15
+ private stopped;
16
+ constructor({ store, maxChanges, onStart, onDiscard, }: {
17
+ store: RecoveryStore;
18
+ maxChanges?: number;
19
+ /** Told the run's id once its journal has started, before its first change is recorded. */
20
+ onStart?: (runId: string) => void;
21
+ /** Told when the run ended having changed nothing, so the history no longer has it. */
22
+ onDiscard?: () => void;
23
+ });
24
+ /** The journal for one more change, counted against the run's limit. */
25
+ journalForChange(): Promise<RunJournal>;
26
+ /** Refuses every further write, for this reason. The first reason given is kept. */
27
+ stop(reason: string): void;
28
+ /** The run's id once it has written, which is what an undo needs. */
29
+ runId(): Promise<string | undefined>;
30
+ /**
31
+ * Ends the run's record and releases the workspace. A run that never wrote has nothing to end,
32
+ * and one whose every change was abandoned leaves the history.
33
+ */
34
+ finish(status: Exclude<RunStatus, 'running' | 'interrupted'>): Promise<void>;
35
+ }
@@ -0,0 +1,81 @@
1
+ import { WorkspaceBusyError, } from '#src/recovery/domain/recoveryStore';
2
+ import { EditRefusedError } from "../domain/fileEdits.js";
3
+ // Far more than a task needs; a run past it is more likely looping than working.
4
+ const defaultMaxChanges = 500;
5
+ /**
6
+ * Everything one top-level run writes, across all its roles and rounds. Its journal starts on
7
+ * the first write, so a run that only reads never holds the workspace, and ends with the run.
8
+ * Once a change could not be confirmed, the session refuses every further write: the record of
9
+ * what the run did must stay complete.
10
+ */
11
+ export class WriteSession {
12
+ store;
13
+ maxChanges;
14
+ onStart;
15
+ onDiscard;
16
+ journal;
17
+ changes = 0;
18
+ stopped;
19
+ constructor({ store, maxChanges = defaultMaxChanges, onStart, onDiscard, }) {
20
+ this.store = store;
21
+ this.maxChanges = maxChanges;
22
+ this.onStart = onStart;
23
+ this.onDiscard = onDiscard;
24
+ }
25
+ /** The journal for one more change, counted against the run's limit. */
26
+ async journalForChange() {
27
+ if (this.stopped !== undefined)
28
+ throw new EditRefusedError(this.stopped);
29
+ if (this.changes >= this.maxChanges) {
30
+ throw new EditRefusedError(`This run has made ${String(this.maxChanges)} changes, the most one run may make`);
31
+ }
32
+ this.journal ??= this.store.startRun().then(started => {
33
+ this.onStart?.(started.runId);
34
+ return started;
35
+ });
36
+ let journal;
37
+ try {
38
+ journal = await this.journal;
39
+ }
40
+ catch (error) {
41
+ // A failed start is not kept, so the next change tries again.
42
+ this.journal = undefined;
43
+ if (error instanceof WorkspaceBusyError) {
44
+ throw new EditRefusedError('Another run, or a move through its history, holds this workspace, so nothing was changed', {
45
+ cause: error,
46
+ });
47
+ }
48
+ throw new EditRefusedError('The harness could not start recording this run, so nothing was changed', { cause: error });
49
+ }
50
+ this.changes++;
51
+ return journal;
52
+ }
53
+ /** Refuses every further write, for this reason. The first reason given is kept. */
54
+ stop(reason) {
55
+ this.stopped ??= reason;
56
+ }
57
+ /** The run's id once it has written, which is what an undo needs. */
58
+ async runId() {
59
+ const journal = await this.journal?.catch(() => undefined);
60
+ return journal?.runId;
61
+ }
62
+ /**
63
+ * Ends the run's record and releases the workspace. A run that never wrote has nothing to end,
64
+ * and one whose every change was abandoned leaves the history.
65
+ */
66
+ async finish(status) {
67
+ const journal = await this.journal?.catch(() => undefined);
68
+ this.journal = undefined;
69
+ if (!journal)
70
+ return;
71
+ try {
72
+ await journal.finish(status);
73
+ }
74
+ finally {
75
+ // Even when finishing failed: a run that changed nothing is out of the history either way.
76
+ if (!journal.changed)
77
+ this.onDiscard?.();
78
+ }
79
+ }
80
+ }
81
+ //# sourceMappingURL=writeSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeSession.js","sourceRoot":"","sources":["../../../src/tools/infrastructure/writeSession.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype RecoveryStore,\n\ttype RunJournal,\n\ttype RunStatus,\n\tWorkspaceBusyError,\n} from '#src/recovery/domain/recoveryStore';\nimport { EditRefusedError } from '../domain/fileEdits.ts';\n\n// Far more than a task needs; a run past it is more likely looping than working.\nconst defaultMaxChanges = 500;\n\n/**\n * Everything one top-level run writes, across all its roles and rounds. Its journal starts on\n * the first write, so a run that only reads never holds the workspace, and ends with the run.\n * Once a change could not be confirmed, the session refuses every further write: the record of\n * what the run did must stay complete.\n */\nexport class WriteSession {\n\tprivate readonly store: RecoveryStore;\n\tprivate readonly maxChanges: number;\n\tprivate readonly onStart: ((runId: string) => void) | undefined;\n\tprivate readonly onDiscard: (() => void) | undefined;\n\tprivate journal: Promise<RunJournal> | undefined;\n\tprivate changes = 0;\n\tprivate stopped: string | undefined;\n\n\tconstructor({\n\t\tstore,\n\t\tmaxChanges = defaultMaxChanges,\n\t\tonStart,\n\t\tonDiscard,\n\t}: {\n\t\tstore: RecoveryStore;\n\t\tmaxChanges?: number;\n\t\t/** Told the run's id once its journal has started, before its first change is recorded. */\n\t\tonStart?: (runId: string) => void;\n\t\t/** Told when the run ended having changed nothing, so the history no longer has it. */\n\t\tonDiscard?: () => void;\n\t}) {\n\t\tthis.store = store;\n\t\tthis.maxChanges = maxChanges;\n\t\tthis.onStart = onStart;\n\t\tthis.onDiscard = onDiscard;\n\t}\n\n\t/** The journal for one more change, counted against the run's limit. */\n\tasync journalForChange(): Promise<RunJournal> {\n\t\tif (this.stopped !== undefined) throw new EditRefusedError(this.stopped);\n\t\tif (this.changes >= this.maxChanges) {\n\t\t\tthrow new EditRefusedError(\n\t\t\t\t`This run has made ${String(this.maxChanges)} changes, the most one run may make`,\n\t\t\t);\n\t\t}\n\n\t\tthis.journal ??= this.store.startRun().then(started => {\n\t\t\tthis.onStart?.(started.runId);\n\t\t\treturn started;\n\t\t});\n\t\tlet journal: RunJournal;\n\t\ttry {\n\t\t\tjournal = await this.journal;\n\t\t} catch (error) {\n\t\t\t// A failed start is not kept, so the next change tries again.\n\t\t\tthis.journal = undefined;\n\t\t\tif (error instanceof WorkspaceBusyError) {\n\t\t\t\tthrow new EditRefusedError(\n\t\t\t\t\t'Another run, or a move through its history, holds this workspace, so nothing was changed',\n\t\t\t\t\t{\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new EditRefusedError(\n\t\t\t\t'The harness could not start recording this run, so nothing was changed',\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\t\tthis.changes++;\n\t\treturn journal;\n\t}\n\n\t/** Refuses every further write, for this reason. The first reason given is kept. */\n\tstop(reason: string): void {\n\t\tthis.stopped ??= reason;\n\t}\n\n\t/** The run's id once it has written, which is what an undo needs. */\n\tasync runId(): Promise<string | undefined> {\n\t\tconst journal = await this.journal?.catch(() => undefined);\n\t\treturn journal?.runId;\n\t}\n\n\t/**\n\t * Ends the run's record and releases the workspace. A run that never wrote has nothing to end,\n\t * and one whose every change was abandoned leaves the history.\n\t */\n\tasync finish(status: Exclude<RunStatus, 'running' | 'interrupted'>): Promise<void> {\n\t\tconst journal = await this.journal?.catch(() => undefined);\n\t\tthis.journal = undefined;\n\t\tif (!journal) return;\n\t\ttry {\n\t\t\tawait journal.finish(status);\n\t\t} finally {\n\t\t\t// Even when finishing failed: a run that changed nothing is out of the history either way.\n\t\t\tif (!journal.changed) this.onDiscard?.();\n\t\t}\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikode13/harness",
3
- "version": "4.0.1",
3
+ "version": "5.1.0",
4
4
  "description": "Test/agent harness utility",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",