@posthog/agent 1.30.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +221 -219
- package/dist/adapters/claude/conversion/tool-use-to-acp.d.ts +21 -0
- package/dist/adapters/claude/conversion/tool-use-to-acp.js +547 -0
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -0
- package/dist/adapters/claude/permissions/permission-options.d.ts +13 -0
- package/dist/adapters/claude/permissions/permission-options.js +117 -0
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -0
- package/dist/adapters/claude/questions/utils.d.ts +132 -0
- package/dist/adapters/claude/questions/utils.js +63 -0
- package/dist/adapters/claude/questions/utils.js.map +1 -0
- package/dist/adapters/claude/tools.d.ts +18 -0
- package/dist/adapters/claude/tools.js +95 -0
- package/dist/adapters/claude/tools.js.map +1 -0
- package/dist/agent-DBQY1BfC.d.ts +123 -0
- package/dist/agent.d.ts +5 -0
- package/dist/agent.js +3656 -0
- package/dist/agent.js.map +1 -0
- package/dist/claude-cli/cli.js +3695 -2746
- package/dist/claude-cli/vendor/ripgrep/COPYING +3 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-darwin/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-linux/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/arm64-linux/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-darwin/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-darwin/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-linux/rg +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-linux/ripgrep.node +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-win32/rg.exe +0 -0
- package/dist/claude-cli/vendor/ripgrep/x64-win32/ripgrep.node +0 -0
- package/dist/gateway-models.d.ts +24 -0
- package/dist/gateway-models.js +93 -0
- package/dist/gateway-models.js.map +1 -0
- package/dist/index.d.ts +172 -1203
- package/dist/index.js +3704 -6826
- package/dist/index.js.map +1 -1
- package/dist/logger-DDBiMOOD.d.ts +24 -0
- package/dist/posthog-api.d.ts +40 -0
- package/dist/posthog-api.js +175 -0
- package/dist/posthog-api.js.map +1 -0
- package/dist/server/agent-server.d.ts +41 -0
- package/dist/server/agent-server.js +4451 -0
- package/dist/server/agent-server.js.map +1 -0
- package/dist/server/bin.d.ts +1 -0
- package/dist/server/bin.js +4507 -0
- package/dist/server/bin.js.map +1 -0
- package/dist/types.d.ts +129 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +66 -14
- package/src/acp-extensions.ts +93 -61
- package/src/adapters/acp-connection.ts +494 -0
- package/src/adapters/base-acp-agent.ts +150 -0
- package/src/adapters/claude/claude-agent.ts +596 -0
- package/src/adapters/claude/conversion/acp-to-sdk.ts +102 -0
- package/src/adapters/claude/conversion/sdk-to-acp.ts +571 -0
- package/src/adapters/claude/conversion/tool-use-to-acp.ts +618 -0
- package/src/adapters/claude/hooks.ts +64 -0
- package/src/adapters/claude/mcp/tool-metadata.ts +102 -0
- package/src/adapters/claude/permissions/permission-handlers.ts +433 -0
- package/src/adapters/claude/permissions/permission-options.ts +103 -0
- package/src/adapters/claude/plan/utils.ts +56 -0
- package/src/adapters/claude/questions/utils.ts +92 -0
- package/src/adapters/claude/session/commands.ts +38 -0
- package/src/adapters/claude/session/mcp-config.ts +37 -0
- package/src/adapters/claude/session/models.ts +12 -0
- package/src/adapters/claude/session/options.ts +236 -0
- package/src/adapters/claude/tool-meta.ts +143 -0
- package/src/adapters/claude/tools.ts +53 -611
- package/src/adapters/claude/types.ts +61 -0
- package/src/adapters/codex/spawn.ts +130 -0
- package/src/agent.ts +97 -734
- package/src/execution-mode.ts +43 -0
- package/src/gateway-models.ts +135 -0
- package/src/index.ts +79 -0
- package/src/otel-log-writer.test.ts +105 -0
- package/src/otel-log-writer.ts +94 -0
- package/src/posthog-api.ts +75 -235
- package/src/resume.ts +115 -0
- package/src/sagas/apply-snapshot-saga.test.ts +690 -0
- package/src/sagas/apply-snapshot-saga.ts +88 -0
- package/src/sagas/capture-tree-saga.test.ts +892 -0
- package/src/sagas/capture-tree-saga.ts +141 -0
- package/src/sagas/resume-saga.test.ts +558 -0
- package/src/sagas/resume-saga.ts +332 -0
- package/src/sagas/test-fixtures.ts +250 -0
- package/src/server/agent-server.test.ts +220 -0
- package/src/server/agent-server.ts +748 -0
- package/src/server/bin.ts +88 -0
- package/src/server/jwt.ts +65 -0
- package/src/server/schemas.ts +47 -0
- package/src/server/types.ts +13 -0
- package/src/server/utils/retry.test.ts +122 -0
- package/src/server/utils/retry.ts +61 -0
- package/src/server/utils/sse-parser.test.ts +93 -0
- package/src/server/utils/sse-parser.ts +46 -0
- package/src/session-log-writer.test.ts +140 -0
- package/src/session-log-writer.ts +137 -0
- package/src/test/assertions.ts +114 -0
- package/src/test/controllers/sse-controller.ts +107 -0
- package/src/test/fixtures/api.ts +111 -0
- package/src/test/fixtures/config.ts +33 -0
- package/src/test/fixtures/notifications.ts +92 -0
- package/src/test/mocks/claude-sdk.ts +251 -0
- package/src/test/mocks/msw-handlers.ts +48 -0
- package/src/test/setup.ts +114 -0
- package/src/test/wait.ts +41 -0
- package/src/tree-tracker.ts +173 -0
- package/src/types.ts +51 -154
- package/src/utils/acp-content.ts +58 -0
- package/src/utils/async-mutex.test.ts +104 -0
- package/src/utils/async-mutex.ts +31 -0
- package/src/utils/common.ts +15 -0
- package/src/utils/gateway.ts +9 -6
- package/src/utils/logger.ts +0 -30
- package/src/utils/streams.ts +220 -0
- package/CLAUDE.md +0 -331
- package/dist/templates/plan-template.md +0 -41
- package/src/adapters/claude/claude.ts +0 -1543
- package/src/adapters/claude/mcp-server.ts +0 -810
- package/src/adapters/claude/utils.ts +0 -267
- package/src/agents/execution.ts +0 -37
- package/src/agents/planning.ts +0 -60
- package/src/agents/research.ts +0 -160
- package/src/file-manager.ts +0 -306
- package/src/git-manager.ts +0 -577
- package/src/prompt-builder.ts +0 -499
- package/src/schemas.ts +0 -241
- package/src/session-store.ts +0 -259
- package/src/task-manager.ts +0 -163
- package/src/template-manager.ts +0 -236
- package/src/templates/plan-template.md +0 -41
- package/src/todo-manager.ts +0 -180
- package/src/tools/registry.ts +0 -129
- package/src/tools/types.ts +0 -127
- package/src/utils/tapped-stream.ts +0 -60
- package/src/workflow/config.ts +0 -53
- package/src/workflow/steps/build.ts +0 -135
- package/src/workflow/steps/finalize.ts +0 -241
- package/src/workflow/steps/plan.ts +0 -167
- package/src/workflow/steps/research.ts +0 -223
- package/src/workflow/types.ts +0 -62
- package/src/workflow/utils.ts +0 -53
- package/src/worktree-manager.ts +0 -928
package/src/template-manager.ts
DELETED
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import { existsSync, promises as fs } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { Logger } from "./utils/logger";
|
|
5
|
-
|
|
6
|
-
const logger = new Logger({ prefix: "[TemplateManager]" });
|
|
7
|
-
|
|
8
|
-
export interface TemplateVariables {
|
|
9
|
-
task_id: string;
|
|
10
|
-
task_title: string;
|
|
11
|
-
task_description?: string;
|
|
12
|
-
date: string;
|
|
13
|
-
repository?: string;
|
|
14
|
-
[key: string]: string | undefined;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class TemplateManager {
|
|
18
|
-
private templatesDir: string;
|
|
19
|
-
|
|
20
|
-
constructor() {
|
|
21
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
-
const __dirname = dirname(__filename);
|
|
23
|
-
|
|
24
|
-
// Exhaustive list of possible template locations
|
|
25
|
-
const candidateDirs = [
|
|
26
|
-
// Standard build output (dist/src/template-manager.js -> dist/templates)
|
|
27
|
-
join(__dirname, "..", "templates"),
|
|
28
|
-
|
|
29
|
-
// If preserveModules creates nested structure (dist/src/template-manager.js -> dist/src/templates)
|
|
30
|
-
join(__dirname, "templates"),
|
|
31
|
-
|
|
32
|
-
// Development scenarios (src/template-manager.ts -> src/templates)
|
|
33
|
-
join(__dirname, "..", "..", "src", "templates"),
|
|
34
|
-
|
|
35
|
-
// Package root templates directory
|
|
36
|
-
join(__dirname, "..", "..", "templates"),
|
|
37
|
-
|
|
38
|
-
// When node_modules symlink or installed (node_modules/@posthog/agent/dist/src/... -> node_modules/@posthog/agent/dist/templates)
|
|
39
|
-
join(__dirname, "..", "..", "dist", "templates"),
|
|
40
|
-
|
|
41
|
-
// When consumed from node_modules deep in tree
|
|
42
|
-
join(__dirname, "..", "..", "..", "templates"),
|
|
43
|
-
join(__dirname, "..", "..", "..", "dist", "templates"),
|
|
44
|
-
join(__dirname, "..", "..", "..", "src", "templates"),
|
|
45
|
-
|
|
46
|
-
// When bundled by Vite/Webpack (e.g., .vite/build/index.js -> node_modules/@posthog/agent/dist/templates)
|
|
47
|
-
// Try to find node_modules from current location
|
|
48
|
-
join(
|
|
49
|
-
__dirname,
|
|
50
|
-
"..",
|
|
51
|
-
"node_modules",
|
|
52
|
-
"@posthog",
|
|
53
|
-
"agent",
|
|
54
|
-
"dist",
|
|
55
|
-
"templates",
|
|
56
|
-
),
|
|
57
|
-
join(
|
|
58
|
-
__dirname,
|
|
59
|
-
"..",
|
|
60
|
-
"..",
|
|
61
|
-
"node_modules",
|
|
62
|
-
"@posthog",
|
|
63
|
-
"agent",
|
|
64
|
-
"dist",
|
|
65
|
-
"templates",
|
|
66
|
-
),
|
|
67
|
-
join(
|
|
68
|
-
__dirname,
|
|
69
|
-
"..",
|
|
70
|
-
"..",
|
|
71
|
-
"..",
|
|
72
|
-
"node_modules",
|
|
73
|
-
"@posthog",
|
|
74
|
-
"agent",
|
|
75
|
-
"dist",
|
|
76
|
-
"templates",
|
|
77
|
-
),
|
|
78
|
-
];
|
|
79
|
-
|
|
80
|
-
const resolvedDir = candidateDirs.find((dir) => existsSync(dir));
|
|
81
|
-
|
|
82
|
-
if (!resolvedDir) {
|
|
83
|
-
logger.error("Could not find templates directory.");
|
|
84
|
-
logger.error(`Current file: ${__filename}`);
|
|
85
|
-
logger.error(`Current dir: ${__dirname}`);
|
|
86
|
-
logger.error(
|
|
87
|
-
`Tried: ${candidateDirs.map((d) => `\n - ${d} (exists: ${existsSync(d)})`).join("")}`,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
this.templatesDir = resolvedDir ?? candidateDirs[0];
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
private async loadTemplate(templateName: string): Promise<string> {
|
|
95
|
-
try {
|
|
96
|
-
const templatePath = join(this.templatesDir, templateName);
|
|
97
|
-
return await fs.readFile(templatePath, "utf8");
|
|
98
|
-
} catch (error) {
|
|
99
|
-
throw new Error(
|
|
100
|
-
`Failed to load template ${templateName} from ${this.templatesDir}: ${error}`,
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
private substituteVariables(
|
|
106
|
-
template: string,
|
|
107
|
-
variables: TemplateVariables,
|
|
108
|
-
): string {
|
|
109
|
-
let result = template;
|
|
110
|
-
|
|
111
|
-
for (const [key, value] of Object.entries(variables)) {
|
|
112
|
-
if (value !== undefined) {
|
|
113
|
-
const placeholder = new RegExp(`{{${key}}}`, "g");
|
|
114
|
-
result = result.replace(placeholder, value);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
result = result.replace(/{{[^}]+}}/g, "[PLACEHOLDER]");
|
|
119
|
-
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async generatePlan(variables: TemplateVariables): Promise<string> {
|
|
124
|
-
const template = await this.loadTemplate("plan-template.md");
|
|
125
|
-
return this.substituteVariables(template, {
|
|
126
|
-
...variables,
|
|
127
|
-
date: variables.date || new Date().toISOString().split("T")[0],
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async generateCustomFile(
|
|
132
|
-
templateName: string,
|
|
133
|
-
variables: TemplateVariables,
|
|
134
|
-
): Promise<string> {
|
|
135
|
-
const template = await this.loadTemplate(templateName);
|
|
136
|
-
return this.substituteVariables(template, {
|
|
137
|
-
...variables,
|
|
138
|
-
date: variables.date || new Date().toISOString().split("T")[0],
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async createTaskStructure(
|
|
143
|
-
taskId: string,
|
|
144
|
-
taskTitle: string,
|
|
145
|
-
options?: {
|
|
146
|
-
includePlan?: boolean;
|
|
147
|
-
additionalFiles?: Array<{
|
|
148
|
-
name: string;
|
|
149
|
-
template?: string;
|
|
150
|
-
content?: string;
|
|
151
|
-
}>;
|
|
152
|
-
},
|
|
153
|
-
): Promise<
|
|
154
|
-
Array<{
|
|
155
|
-
name: string;
|
|
156
|
-
content: string;
|
|
157
|
-
type: "plan" | "context" | "reference" | "output";
|
|
158
|
-
}>
|
|
159
|
-
> {
|
|
160
|
-
const files: Array<{
|
|
161
|
-
name: string;
|
|
162
|
-
content: string;
|
|
163
|
-
type: "plan" | "context" | "reference" | "output";
|
|
164
|
-
}> = [];
|
|
165
|
-
|
|
166
|
-
const variables: TemplateVariables = {
|
|
167
|
-
task_id: taskId,
|
|
168
|
-
task_title: taskTitle,
|
|
169
|
-
date: new Date().toISOString().split("T")[0],
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
// Generate plan file if requested
|
|
173
|
-
if (options?.includePlan !== false) {
|
|
174
|
-
const planContent = await this.generatePlan(variables);
|
|
175
|
-
files.push({
|
|
176
|
-
name: "plan.md",
|
|
177
|
-
content: planContent,
|
|
178
|
-
type: "plan",
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (options?.additionalFiles) {
|
|
183
|
-
for (const file of options.additionalFiles) {
|
|
184
|
-
let content: string;
|
|
185
|
-
|
|
186
|
-
if (file.template) {
|
|
187
|
-
content = await this.generateCustomFile(file.template, variables);
|
|
188
|
-
} else if (file.content) {
|
|
189
|
-
content = this.substituteVariables(file.content, variables);
|
|
190
|
-
} else {
|
|
191
|
-
content = `# ${file.name}\n\nPlaceholder content for ${file.name}`;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
files.push({
|
|
195
|
-
name: file.name,
|
|
196
|
-
content,
|
|
197
|
-
type: file.name.includes("context") ? "context" : "reference",
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return files;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
generatePostHogReadme(): string {
|
|
206
|
-
return `# PostHog Task Files
|
|
207
|
-
|
|
208
|
-
This directory contains task-related files.
|
|
209
|
-
|
|
210
|
-
## Structure
|
|
211
|
-
|
|
212
|
-
Each task has its own subdirectory: \`.posthog/{task-id}/\`
|
|
213
|
-
|
|
214
|
-
### Common Files
|
|
215
|
-
|
|
216
|
-
- **plan.md** - Implementation plan generated during planning phase
|
|
217
|
-
- **Supporting files** - Any additional files added for task context
|
|
218
|
-
- **artifacts/** - Generated files, outputs, and temporary artifacts
|
|
219
|
-
|
|
220
|
-
### Usage
|
|
221
|
-
|
|
222
|
-
These files are:
|
|
223
|
-
- Version controlled alongside your code
|
|
224
|
-
- Used for task context and planning
|
|
225
|
-
- Available for review in pull requests
|
|
226
|
-
- Organized by task ID for easy reference
|
|
227
|
-
|
|
228
|
-
### Gitignore
|
|
229
|
-
|
|
230
|
-
Customize \`.posthog/.gitignore\` to control which files are committed:
|
|
231
|
-
- Include plans and documentation by default
|
|
232
|
-
- Exclude temporary files and sensitive data
|
|
233
|
-
- Customize based on your team's needs
|
|
234
|
-
`;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Implementation Plan: {{task_title}}
|
|
2
|
-
|
|
3
|
-
**Task ID:** {{task_id}}
|
|
4
|
-
**Generated:** {{date}}
|
|
5
|
-
|
|
6
|
-
## Summary
|
|
7
|
-
|
|
8
|
-
Brief description of what will be implemented and the overall approach.
|
|
9
|
-
|
|
10
|
-
## Implementation Steps
|
|
11
|
-
|
|
12
|
-
### 1. Analysis
|
|
13
|
-
- [ ] Identify relevant files and components
|
|
14
|
-
- [ ] Review existing patterns and constraints
|
|
15
|
-
|
|
16
|
-
### 2. Changes Required
|
|
17
|
-
- [ ] Files to create/modify
|
|
18
|
-
- [ ] Dependencies to add/update
|
|
19
|
-
|
|
20
|
-
### 3. Implementation
|
|
21
|
-
- [ ] Core functionality changes
|
|
22
|
-
- [ ] Tests and validation
|
|
23
|
-
- [ ] Documentation updates
|
|
24
|
-
|
|
25
|
-
## File Changes
|
|
26
|
-
|
|
27
|
-
### New Files
|
|
28
|
-
```
|
|
29
|
-
path/to/new/file.ts - Purpose
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
### Modified Files
|
|
33
|
-
```
|
|
34
|
-
path/to/existing/file.ts - Changes needed
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Considerations
|
|
38
|
-
|
|
39
|
-
- Key architectural decisions
|
|
40
|
-
- Potential risks and mitigation
|
|
41
|
-
- Testing approach
|
package/src/todo-manager.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import type { PostHogFileManager } from "./file-manager.js";
|
|
2
|
-
import { Logger } from "./utils/logger.js";
|
|
3
|
-
|
|
4
|
-
export interface TodoItem {
|
|
5
|
-
content: string;
|
|
6
|
-
status: "pending" | "in_progress" | "completed";
|
|
7
|
-
activeForm: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface TodoList {
|
|
11
|
-
items: TodoItem[];
|
|
12
|
-
metadata: {
|
|
13
|
-
total: number;
|
|
14
|
-
pending: number;
|
|
15
|
-
in_progress: number;
|
|
16
|
-
completed: number;
|
|
17
|
-
last_updated: string;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class TodoManager {
|
|
22
|
-
private fileManager: PostHogFileManager;
|
|
23
|
-
private logger: Logger;
|
|
24
|
-
|
|
25
|
-
constructor(fileManager: PostHogFileManager, logger?: Logger) {
|
|
26
|
-
this.fileManager = fileManager;
|
|
27
|
-
this.logger =
|
|
28
|
-
logger || new Logger({ debug: false, prefix: "[TodoManager]" });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async readTodos(taskId: string): Promise<TodoList | null> {
|
|
32
|
-
try {
|
|
33
|
-
const content = await this.fileManager.readTaskFile(taskId, "todos.json");
|
|
34
|
-
if (!content) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const parsed = JSON.parse(content) as TodoList;
|
|
39
|
-
this.logger.debug("Loaded todos", {
|
|
40
|
-
taskId,
|
|
41
|
-
total: parsed.metadata.total,
|
|
42
|
-
pending: parsed.metadata.pending,
|
|
43
|
-
in_progress: parsed.metadata.in_progress,
|
|
44
|
-
completed: parsed.metadata.completed,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
return parsed;
|
|
48
|
-
} catch (error) {
|
|
49
|
-
this.logger.debug("Failed to read todos.json", {
|
|
50
|
-
taskId,
|
|
51
|
-
error: error instanceof Error ? error.message : String(error),
|
|
52
|
-
});
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async writeTodos(taskId: string, todos: TodoList): Promise<void> {
|
|
58
|
-
this.logger.debug("Writing todos", {
|
|
59
|
-
taskId,
|
|
60
|
-
total: todos.metadata.total,
|
|
61
|
-
pending: todos.metadata.pending,
|
|
62
|
-
in_progress: todos.metadata.in_progress,
|
|
63
|
-
completed: todos.metadata.completed,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
await this.fileManager.writeTaskFile(taskId, {
|
|
67
|
-
name: "todos.json",
|
|
68
|
-
content: JSON.stringify(todos, null, 2),
|
|
69
|
-
type: "artifact",
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
this.logger.info("Todos saved", {
|
|
73
|
-
taskId,
|
|
74
|
-
total: todos.metadata.total,
|
|
75
|
-
completed: todos.metadata.completed,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
parseTodoWriteInput(toolInput: Record<string, unknown>): TodoList {
|
|
80
|
-
const items: TodoItem[] = [];
|
|
81
|
-
|
|
82
|
-
if (toolInput.todos && Array.isArray(toolInput.todos)) {
|
|
83
|
-
for (const todo of toolInput.todos) {
|
|
84
|
-
items.push({
|
|
85
|
-
content: todo.content || "",
|
|
86
|
-
status: todo.status || "pending",
|
|
87
|
-
activeForm: todo.activeForm || todo.content || "",
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const metadata = this.calculateMetadata(items);
|
|
93
|
-
|
|
94
|
-
return { items, metadata };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private calculateMetadata(items: TodoItem[]): TodoList["metadata"] {
|
|
98
|
-
const total = items.length;
|
|
99
|
-
const pending = items.filter((t) => t.status === "pending").length;
|
|
100
|
-
const in_progress = items.filter((t) => t.status === "in_progress").length;
|
|
101
|
-
const completed = items.filter((t) => t.status === "completed").length;
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
total,
|
|
105
|
-
pending,
|
|
106
|
-
in_progress,
|
|
107
|
-
completed,
|
|
108
|
-
last_updated: new Date().toISOString(),
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async getTodoContext(taskId: string): Promise<string> {
|
|
113
|
-
const todos = await this.readTodos(taskId);
|
|
114
|
-
if (!todos || todos.items.length === 0) {
|
|
115
|
-
return "";
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const lines: string[] = ["## Previous Todo List\n"];
|
|
119
|
-
lines.push("You previously created the following todo list:\n");
|
|
120
|
-
|
|
121
|
-
for (const item of todos.items) {
|
|
122
|
-
const statusIcon =
|
|
123
|
-
item.status === "completed"
|
|
124
|
-
? "✓"
|
|
125
|
-
: item.status === "in_progress"
|
|
126
|
-
? "▶"
|
|
127
|
-
: "○";
|
|
128
|
-
lines.push(`${statusIcon} [${item.status}] ${item.content}`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
lines.push(
|
|
132
|
-
`\nProgress: ${todos.metadata.completed}/${todos.metadata.total} completed\n`,
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
return lines.join("\n");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// check for TodoWrite tool call and persist if found
|
|
139
|
-
async checkAndPersistFromMessage(
|
|
140
|
-
message: Record<string, unknown>,
|
|
141
|
-
taskId: string,
|
|
142
|
-
): Promise<TodoList | null> {
|
|
143
|
-
if (
|
|
144
|
-
message.type !== "assistant" ||
|
|
145
|
-
typeof message.message !== "object" ||
|
|
146
|
-
!message.message ||
|
|
147
|
-
!("content" in message.message) ||
|
|
148
|
-
!Array.isArray(message.message.content)
|
|
149
|
-
) {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
for (const block of message.message.content) {
|
|
154
|
-
if (block.type === "tool_use" && block.name === "TodoWrite") {
|
|
155
|
-
try {
|
|
156
|
-
this.logger.info("TodoWrite detected, persisting todos", { taskId });
|
|
157
|
-
|
|
158
|
-
const todoList = this.parseTodoWriteInput(block.input);
|
|
159
|
-
await this.writeTodos(taskId, todoList);
|
|
160
|
-
|
|
161
|
-
this.logger.info("Persisted todos successfully", {
|
|
162
|
-
taskId,
|
|
163
|
-
total: todoList.metadata.total,
|
|
164
|
-
completed: todoList.metadata.completed,
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
return todoList;
|
|
168
|
-
} catch (error) {
|
|
169
|
-
this.logger.error("Failed to persist todos", {
|
|
170
|
-
taskId,
|
|
171
|
-
error: error instanceof Error ? error.message : String(error),
|
|
172
|
-
});
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
}
|
package/src/tools/registry.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import type { Tool } from "./types.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Registry of all known tools with their metadata.
|
|
5
|
-
* Maps tool names to their definitions.
|
|
6
|
-
*/
|
|
7
|
-
const TOOL_DEFINITIONS: Record<string, Tool> = {
|
|
8
|
-
// Filesystem tools
|
|
9
|
-
Read: {
|
|
10
|
-
name: "Read",
|
|
11
|
-
category: "filesystem",
|
|
12
|
-
description: "Read file contents from the filesystem",
|
|
13
|
-
},
|
|
14
|
-
Write: {
|
|
15
|
-
name: "Write",
|
|
16
|
-
category: "filesystem",
|
|
17
|
-
description: "Write content to a file",
|
|
18
|
-
},
|
|
19
|
-
Edit: {
|
|
20
|
-
name: "Edit",
|
|
21
|
-
category: "filesystem",
|
|
22
|
-
description: "Edit file with find and replace operations",
|
|
23
|
-
},
|
|
24
|
-
Glob: {
|
|
25
|
-
name: "Glob",
|
|
26
|
-
category: "filesystem",
|
|
27
|
-
description: "Find files matching a pattern",
|
|
28
|
-
},
|
|
29
|
-
NotebookEdit: {
|
|
30
|
-
name: "NotebookEdit",
|
|
31
|
-
category: "filesystem",
|
|
32
|
-
description: "Edit Jupyter notebook cells",
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
// Shell tools
|
|
36
|
-
Bash: {
|
|
37
|
-
name: "Bash",
|
|
38
|
-
category: "shell",
|
|
39
|
-
description: "Execute bash commands",
|
|
40
|
-
},
|
|
41
|
-
BashOutput: {
|
|
42
|
-
name: "BashOutput",
|
|
43
|
-
category: "shell",
|
|
44
|
-
description: "Read output from a background bash process",
|
|
45
|
-
},
|
|
46
|
-
KillShell: {
|
|
47
|
-
name: "KillShell",
|
|
48
|
-
category: "shell",
|
|
49
|
-
description: "Terminate a background bash process",
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
// Web tools
|
|
53
|
-
WebFetch: {
|
|
54
|
-
name: "WebFetch",
|
|
55
|
-
category: "web",
|
|
56
|
-
description: "Fetch content from a URL",
|
|
57
|
-
},
|
|
58
|
-
WebSearch: {
|
|
59
|
-
name: "WebSearch",
|
|
60
|
-
category: "web",
|
|
61
|
-
description: "Search the web",
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
// Search tools
|
|
65
|
-
Grep: {
|
|
66
|
-
name: "Grep",
|
|
67
|
-
category: "search",
|
|
68
|
-
description: "Search file contents using patterns",
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
// Assistant tools
|
|
72
|
-
Task: {
|
|
73
|
-
name: "Task",
|
|
74
|
-
category: "assistant",
|
|
75
|
-
description: "Launch a specialized agent for a sub-task",
|
|
76
|
-
},
|
|
77
|
-
TodoWrite: {
|
|
78
|
-
name: "TodoWrite",
|
|
79
|
-
category: "assistant",
|
|
80
|
-
description: "Manage task list and track progress",
|
|
81
|
-
},
|
|
82
|
-
ExitPlanMode: {
|
|
83
|
-
name: "ExitPlanMode",
|
|
84
|
-
category: "assistant",
|
|
85
|
-
description: "Exit plan mode and present plan to user",
|
|
86
|
-
},
|
|
87
|
-
SlashCommand: {
|
|
88
|
-
name: "SlashCommand",
|
|
89
|
-
category: "assistant",
|
|
90
|
-
description: "Execute a slash command",
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Tool registry for looking up tool definitions by name.
|
|
96
|
-
* Provides metadata about tools for UI consumption.
|
|
97
|
-
*/
|
|
98
|
-
export class ToolRegistry {
|
|
99
|
-
/**
|
|
100
|
-
* Get tool definition by name.
|
|
101
|
-
* Returns undefined if tool is not recognized.
|
|
102
|
-
*/
|
|
103
|
-
get(name: string): Tool | undefined {
|
|
104
|
-
return TOOL_DEFINITIONS[name];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Get all registered tools.
|
|
109
|
-
*/
|
|
110
|
-
getAll(): Tool[] {
|
|
111
|
-
return Object.values(TOOL_DEFINITIONS);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Check if a tool name is registered.
|
|
116
|
-
*/
|
|
117
|
-
has(name: string): boolean {
|
|
118
|
-
return name in TOOL_DEFINITIONS;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Get all tools in a specific category.
|
|
123
|
-
*/
|
|
124
|
-
getByCategory(category: string): Tool[] {
|
|
125
|
-
return Object.values(TOOL_DEFINITIONS).filter(
|
|
126
|
-
(tool) => tool.category === category,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
}
|
package/src/tools/types.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool category classification for grouping related tools.
|
|
3
|
-
* Makes it easier for UIs to filter and display tools by function.
|
|
4
|
-
*/
|
|
5
|
-
export type ToolCategory =
|
|
6
|
-
| "filesystem" // File operations: Read, Write, Edit, Glob, NotebookEdit
|
|
7
|
-
| "shell" // Shell operations: Bash, BashOutput, KillShell
|
|
8
|
-
| "web" // Web operations: WebFetch, WebSearch
|
|
9
|
-
| "assistant" // Assistant operations: Task, TodoWrite, ExitPlanMode
|
|
10
|
-
| "search" // Search operations: Grep
|
|
11
|
-
| "unknown"; // Unknown or unrecognized tools
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Base tool interface representing a tool that can be called by the agent.
|
|
15
|
-
* Each tool has a name, category, and human-readable description.
|
|
16
|
-
*/
|
|
17
|
-
export interface Tool {
|
|
18
|
-
name: string;
|
|
19
|
-
category: ToolCategory;
|
|
20
|
-
description: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Filesystem tools
|
|
24
|
-
|
|
25
|
-
export interface ReadTool extends Tool {
|
|
26
|
-
name: "Read";
|
|
27
|
-
category: "filesystem";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface WriteTool extends Tool {
|
|
31
|
-
name: "Write";
|
|
32
|
-
category: "filesystem";
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface EditTool extends Tool {
|
|
36
|
-
name: "Edit";
|
|
37
|
-
category: "filesystem";
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface GlobTool extends Tool {
|
|
41
|
-
name: "Glob";
|
|
42
|
-
category: "filesystem";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface NotebookEditTool extends Tool {
|
|
46
|
-
name: "NotebookEdit";
|
|
47
|
-
category: "filesystem";
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Shell tools
|
|
51
|
-
|
|
52
|
-
export interface BashTool extends Tool {
|
|
53
|
-
name: "Bash";
|
|
54
|
-
category: "shell";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface BashOutputTool extends Tool {
|
|
58
|
-
name: "BashOutput";
|
|
59
|
-
category: "shell";
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface KillShellTool extends Tool {
|
|
63
|
-
name: "KillShell";
|
|
64
|
-
category: "shell";
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Web tools
|
|
68
|
-
|
|
69
|
-
export interface WebFetchTool extends Tool {
|
|
70
|
-
name: "WebFetch";
|
|
71
|
-
category: "web";
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface WebSearchTool extends Tool {
|
|
75
|
-
name: "WebSearch";
|
|
76
|
-
category: "web";
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Search tools
|
|
80
|
-
|
|
81
|
-
export interface GrepTool extends Tool {
|
|
82
|
-
name: "Grep";
|
|
83
|
-
category: "search";
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Assistant tools
|
|
87
|
-
|
|
88
|
-
export interface TaskTool extends Tool {
|
|
89
|
-
name: "Task";
|
|
90
|
-
category: "assistant";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export interface TodoWriteTool extends Tool {
|
|
94
|
-
name: "TodoWrite";
|
|
95
|
-
category: "assistant";
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export interface ExitPlanModeTool extends Tool {
|
|
99
|
-
name: "ExitPlanMode";
|
|
100
|
-
category: "assistant";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export interface SlashCommandTool extends Tool {
|
|
104
|
-
name: "SlashCommand";
|
|
105
|
-
category: "assistant";
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Union type of all known tool types.
|
|
110
|
-
* Useful for discriminated unions and type narrowing.
|
|
111
|
-
*/
|
|
112
|
-
export type KnownTool =
|
|
113
|
-
| ReadTool
|
|
114
|
-
| WriteTool
|
|
115
|
-
| EditTool
|
|
116
|
-
| GlobTool
|
|
117
|
-
| NotebookEditTool
|
|
118
|
-
| BashTool
|
|
119
|
-
| BashOutputTool
|
|
120
|
-
| KillShellTool
|
|
121
|
-
| WebFetchTool
|
|
122
|
-
| WebSearchTool
|
|
123
|
-
| GrepTool
|
|
124
|
-
| TaskTool
|
|
125
|
-
| TodoWriteTool
|
|
126
|
-
| ExitPlanModeTool
|
|
127
|
-
| SlashCommandTool;
|