@cjhyy/code-shell-capability-coding 0.8.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.
- package/README.md +69 -0
- package/THIRD_PARTY_NOTICES.md +206 -0
- package/dist/bin/agent-server-stdio.d.ts +1 -0
- package/dist/bin/agent-server-stdio.js +4 -0
- package/dist/capability-runtime.d.ts +22 -0
- package/dist/capability-runtime.js +88 -0
- package/dist/cc-orchestrator/agent-adapter.d.ts +55 -0
- package/dist/cc-orchestrator/agent-adapter.js +143 -0
- package/dist/cc-orchestrator/cc-capability.d.ts +20 -0
- package/dist/cc-orchestrator/cc-capability.js +57 -0
- package/dist/cc-orchestrator/codex-session-discovery.d.ts +45 -0
- package/dist/cc-orchestrator/codex-session-discovery.js +251 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +39 -0
- package/dist/cc-orchestrator/codex-session-history.js +249 -0
- package/dist/cc-orchestrator/codex-user-text.d.ts +9 -0
- package/dist/cc-orchestrator/codex-user-text.js +25 -0
- package/dist/cc-orchestrator/external-agent-bindings.d.ts +27 -0
- package/dist/cc-orchestrator/external-agent-bindings.js +150 -0
- package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-changes.js +231 -0
- package/dist/cc-orchestrator/external-agent-driver.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-driver.js +284 -0
- package/dist/cc-orchestrator/external-agent-session-store.d.ts +36 -0
- package/dist/cc-orchestrator/external-agent-session-store.js +185 -0
- package/dist/cc-orchestrator/index.d.ts +10 -0
- package/dist/cc-orchestrator/index.js +10 -0
- package/dist/cc-orchestrator/related-session-discovery.d.ts +21 -0
- package/dist/cc-orchestrator/related-session-discovery.js +77 -0
- package/dist/cc-orchestrator/relevance-judge.d.ts +16 -0
- package/dist/cc-orchestrator/relevance-judge.js +38 -0
- package/dist/cc-orchestrator/session-discovery.d.ts +99 -0
- package/dist/cc-orchestrator/session-discovery.js +295 -0
- package/dist/cc-orchestrator/session-history.d.ts +55 -0
- package/dist/cc-orchestrator/session-history.js +150 -0
- package/dist/external-agents/config.d.ts +3 -0
- package/dist/external-agents/config.js +16 -0
- package/dist/external-agents/types.d.ts +32 -0
- package/dist/external-agents/types.js +1 -0
- package/dist/external-runtimes/claude-code/event-translator.d.ts +54 -0
- package/dist/external-runtimes/claude-code/event-translator.js +201 -0
- package/dist/external-runtimes/claude-code/mcp-config.d.ts +84 -0
- package/dist/external-runtimes/claude-code/mcp-config.js +175 -0
- package/dist/external-runtimes/claude-code/runtime.d.ts +56 -0
- package/dist/external-runtimes/claude-code/runtime.js +168 -0
- package/dist/external-runtimes/codex/app-server-client.d.ts +66 -0
- package/dist/external-runtimes/codex/app-server-client.js +244 -0
- package/dist/external-runtimes/codex/event-translator.d.ts +68 -0
- package/dist/external-runtimes/codex/event-translator.js +187 -0
- package/dist/external-runtimes/codex/index.d.ts +7 -0
- package/dist/external-runtimes/codex/index.js +6 -0
- package/dist/external-runtimes/codex/runtime.d.ts +128 -0
- package/dist/external-runtimes/codex/runtime.js +216 -0
- package/dist/external-runtimes/index.d.ts +37 -0
- package/dist/external-runtimes/index.js +27 -0
- package/dist/external-runtimes/session-factory.d.ts +97 -0
- package/dist/external-runtimes/session-factory.js +110 -0
- package/dist/external-runtimes/shared/mcp-bridge.d.ts +66 -0
- package/dist/external-runtimes/shared/mcp-bridge.js +365 -0
- package/dist/external-runtimes/shared/session-context-store.d.ts +83 -0
- package/dist/external-runtimes/shared/session-context-store.js +114 -0
- package/dist/external-runtimes/shared/spawn-env.d.ts +30 -0
- package/dist/external-runtimes/shared/spawn-env.js +41 -0
- package/dist/git/parse-log.d.ts +14 -0
- package/dist/git/parse-log.js +21 -0
- package/dist/git/utils.d.ts +49 -0
- package/dist/git/utils.js +161 -0
- package/dist/git/worktree/crud.d.ts +108 -0
- package/dist/git/worktree/crud.js +415 -0
- package/dist/git/worktree/diff.d.ts +14 -0
- package/dist/git/worktree/diff.js +83 -0
- package/dist/git/worktree/git-exec.d.ts +7 -0
- package/dist/git/worktree/git-exec.js +86 -0
- package/dist/git/worktree/index.d.ts +6 -0
- package/dist/git/worktree/index.js +6 -0
- package/dist/git/worktree/query.d.ts +43 -0
- package/dist/git/worktree/query.js +128 -0
- package/dist/git/worktree/slug.d.ts +12 -0
- package/dist/git/worktree/slug.js +59 -0
- package/dist/git/worktree.d.ts +1 -0
- package/dist/git/worktree.js +5 -0
- package/dist/index.capability.d.ts +7 -0
- package/dist/index.capability.js +190 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.git.d.ts +4 -0
- package/dist/index.git.js +4 -0
- package/dist/index.js +18 -0
- package/dist/index.orchestration.d.ts +7 -0
- package/dist/index.orchestration.js +5 -0
- package/dist/lsp/client.d.ts +41 -0
- package/dist/lsp/client.js +192 -0
- package/dist/lsp/manager.d.ts +53 -0
- package/dist/lsp/manager.js +248 -0
- package/dist/lsp/root-path.d.ts +9 -0
- package/dist/lsp/root-path.js +12 -0
- package/dist/lsp/servers.d.ts +16 -0
- package/dist/lsp/servers.js +60 -0
- package/dist/prompt/coding.md +42 -0
- package/dist/quota/credentials.d.ts +3 -0
- package/dist/quota/credentials.js +80 -0
- package/dist/quota/index.d.ts +36 -0
- package/dist/quota/index.js +161 -0
- package/dist/quota/types.d.ts +48 -0
- package/dist/quota/types.js +13 -0
- package/dist/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/tools/apply-patch/LICENSE-codex +201 -0
- package/dist/tools/apply-patch/NOTICE.md +29 -0
- package/dist/tools/apply-patch/applier.d.ts +26 -0
- package/dist/tools/apply-patch/applier.js +306 -0
- package/dist/tools/apply-patch/backup-targets.d.ts +10 -0
- package/dist/tools/apply-patch/backup-targets.js +30 -0
- package/dist/tools/apply-patch/eol.d.ts +4 -0
- package/dist/tools/apply-patch/eol.js +9 -0
- package/dist/tools/apply-patch/index.d.ts +20 -0
- package/dist/tools/apply-patch/index.js +106 -0
- package/dist/tools/apply-patch/parser.d.ts +17 -0
- package/dist/tools/apply-patch/parser.js +209 -0
- package/dist/tools/apply-patch/seek-sequence.d.ts +18 -0
- package/dist/tools/apply-patch/seek-sequence.js +123 -0
- package/dist/tools/apply-patch/types.d.ts +49 -0
- package/dist/tools/apply-patch/types.js +13 -0
- package/dist/tools/brief.d.ts +6 -0
- package/dist/tools/brief.js +41 -0
- package/dist/tools/check-quota.d.ts +14 -0
- package/dist/tools/check-quota.js +38 -0
- package/dist/tools/drive-agent.d.ts +52 -0
- package/dist/tools/drive-agent.js +1184 -0
- package/dist/tools/lsp.d.ts +6 -0
- package/dist/tools/lsp.js +220 -0
- package/dist/tools/notebook-edit.d.ts +6 -0
- package/dist/tools/notebook-edit.js +127 -0
- package/dist/tools/worktree.d.ts +10 -0
- package/dist/tools/worktree.js +363 -0
- package/package.json +60 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSPTool — language server protocol operations for code intelligence.
|
|
3
|
+
*/
|
|
4
|
+
import type { ToolContext, ToolDefinition } from "@cjhyy/code-shell-core/extension";
|
|
5
|
+
export declare const lspToolDef: ToolDefinition;
|
|
6
|
+
export declare function lspTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSPTool — language server protocol operations for code intelligence.
|
|
3
|
+
*/
|
|
4
|
+
import { getLSPManager } from "../lsp/manager.js";
|
|
5
|
+
import { detectLSPServer } from "../lsp/servers.js";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { isAbsolute, resolve } from "node:path";
|
|
8
|
+
/**
|
|
9
|
+
* How long to wait for `textDocument/publishDiagnostics` after opening a file.
|
|
10
|
+
*
|
|
11
|
+
* A cold server has to index the project first, so this is a deadline rather
|
|
12
|
+
* than an expected duration — timing out reports "still indexing" instead of
|
|
13
|
+
* silently claiming the file is clean.
|
|
14
|
+
*/
|
|
15
|
+
const DIAGNOSTICS_TIMEOUT_MS = 10_000;
|
|
16
|
+
const DIAGNOSTIC_SEVERITY = {
|
|
17
|
+
1: "error",
|
|
18
|
+
2: "warning",
|
|
19
|
+
3: "info",
|
|
20
|
+
4: "hint",
|
|
21
|
+
};
|
|
22
|
+
export const lspToolDef = {
|
|
23
|
+
name: "LSP",
|
|
24
|
+
description: "Use Language Server Protocol for code intelligence operations. " +
|
|
25
|
+
"Available actions: goToDefinition, findReferences, hover, getDiagnostics, getSymbols. " +
|
|
26
|
+
"Requires a language server to be installed for the target language.",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
action: {
|
|
31
|
+
type: "string",
|
|
32
|
+
enum: ["goToDefinition", "findReferences", "hover", "getDiagnostics", "getSymbols"],
|
|
33
|
+
description: "The LSP operation to perform",
|
|
34
|
+
},
|
|
35
|
+
file_path: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Absolute path to the file",
|
|
38
|
+
},
|
|
39
|
+
line: {
|
|
40
|
+
type: "number",
|
|
41
|
+
description: "Line number (0-based). Required for goToDefinition, findReferences, hover.",
|
|
42
|
+
},
|
|
43
|
+
character: {
|
|
44
|
+
type: "number",
|
|
45
|
+
description: "Character offset (0-based). Required for goToDefinition, findReferences, hover.",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
required: ["action", "file_path"],
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
export async function lspTool(args, ctx) {
|
|
52
|
+
const action = args.action;
|
|
53
|
+
const rawPath = args.file_path;
|
|
54
|
+
const line = args.line ?? 0;
|
|
55
|
+
const character = args.character ?? 0;
|
|
56
|
+
if (!rawPath)
|
|
57
|
+
return "Error: file_path is required";
|
|
58
|
+
const cwd = ctx?.cwd ?? process.cwd();
|
|
59
|
+
const filePath = isAbsolute(rawPath) ? rawPath : resolve(cwd, rawPath);
|
|
60
|
+
// Lazily create the manager for THIS workspace. Previously this read a
|
|
61
|
+
// process-wide singleton that no host ever initialized, so the tool was
|
|
62
|
+
// advertised to the agent but always answered "LSP is not initialized".
|
|
63
|
+
const manager = getLSPManager(cwd);
|
|
64
|
+
if (!manager)
|
|
65
|
+
return "Error: LSP is not initialized. Language servers are not available.";
|
|
66
|
+
// Detect the appropriate server
|
|
67
|
+
const serverConfig = detectLSPServer(filePath);
|
|
68
|
+
if (!serverConfig)
|
|
69
|
+
return `Error: No language server configured for ${filePath}`;
|
|
70
|
+
const client = await manager.getClient(serverConfig.name);
|
|
71
|
+
if (!client) {
|
|
72
|
+
return `Error: Language server "${serverConfig.name}" is not available. Install: ${serverConfig.installHint}`;
|
|
73
|
+
}
|
|
74
|
+
const uri = pathToFileURL(filePath).href;
|
|
75
|
+
const position = { line, character };
|
|
76
|
+
try {
|
|
77
|
+
switch (action) {
|
|
78
|
+
case "goToDefinition": {
|
|
79
|
+
const result = await client.request("textDocument/definition", {
|
|
80
|
+
textDocument: { uri },
|
|
81
|
+
position,
|
|
82
|
+
});
|
|
83
|
+
return formatLocationResult(result, "Definition");
|
|
84
|
+
}
|
|
85
|
+
case "findReferences": {
|
|
86
|
+
const result = await client.request("textDocument/references", {
|
|
87
|
+
textDocument: { uri },
|
|
88
|
+
position,
|
|
89
|
+
context: { includeDeclaration: true },
|
|
90
|
+
});
|
|
91
|
+
return formatLocationResult(result, "References");
|
|
92
|
+
}
|
|
93
|
+
case "hover": {
|
|
94
|
+
const result = (await client.request("textDocument/hover", {
|
|
95
|
+
textDocument: { uri },
|
|
96
|
+
position,
|
|
97
|
+
}));
|
|
98
|
+
if (!result)
|
|
99
|
+
return "No hover information available.";
|
|
100
|
+
const content = typeof result.contents === "string"
|
|
101
|
+
? result.contents
|
|
102
|
+
: (result.contents?.value ?? JSON.stringify(result.contents));
|
|
103
|
+
return `Hover:\n${content}`;
|
|
104
|
+
}
|
|
105
|
+
case "getDiagnostics": {
|
|
106
|
+
// Collect the ACTUAL diagnostics for this file.
|
|
107
|
+
//
|
|
108
|
+
// This used to open the document, sleep 2s, and return "Diagnostics
|
|
109
|
+
// requested. Check LSP notifications for results." — nobody was
|
|
110
|
+
// subscribed to those notifications, so the agent got a status string
|
|
111
|
+
// and never any findings. Subscribe first, then open, then wait for the
|
|
112
|
+
// matching publishDiagnostics (with a deadline, since a clean file may
|
|
113
|
+
// legitimately produce none).
|
|
114
|
+
const { readFileSync } = await import("node:fs");
|
|
115
|
+
const text = readFileSync(filePath, "utf-8");
|
|
116
|
+
const diagnostics = await new Promise((resolveWait) => {
|
|
117
|
+
let settled = false;
|
|
118
|
+
const finish = (value) => {
|
|
119
|
+
if (settled)
|
|
120
|
+
return;
|
|
121
|
+
settled = true;
|
|
122
|
+
client.off?.("notification", onNotification);
|
|
123
|
+
clearTimeout(timer);
|
|
124
|
+
resolveWait(value);
|
|
125
|
+
};
|
|
126
|
+
const onNotification = (message) => {
|
|
127
|
+
if (message?.method !== "textDocument/publishDiagnostics")
|
|
128
|
+
return;
|
|
129
|
+
const params = message.params;
|
|
130
|
+
// Servers report per-URI; ignore other files opened in the session.
|
|
131
|
+
if (params?.uri !== uri)
|
|
132
|
+
return;
|
|
133
|
+
finish(params.diagnostics ?? []);
|
|
134
|
+
};
|
|
135
|
+
const timer = setTimeout(() => finish(undefined), DIAGNOSTICS_TIMEOUT_MS);
|
|
136
|
+
client.on?.("notification", onNotification);
|
|
137
|
+
void client.notify("textDocument/didOpen", {
|
|
138
|
+
textDocument: { uri, languageId: serverConfig.language, version: 1, text },
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
if (diagnostics === undefined) {
|
|
142
|
+
return `No diagnostics published within ${DIAGNOSTICS_TIMEOUT_MS}ms. The server may still be indexing.`;
|
|
143
|
+
}
|
|
144
|
+
if (diagnostics.length === 0)
|
|
145
|
+
return "No diagnostics — the file is clean.";
|
|
146
|
+
const lines = diagnostics.slice(0, 100).map((diagnostic) => {
|
|
147
|
+
const severity = DIAGNOSTIC_SEVERITY[diagnostic.severity ?? 1] ?? "info";
|
|
148
|
+
const start = diagnostic.range?.start;
|
|
149
|
+
const at = start ? `${start.line + 1}:${start.character + 1}` : "?";
|
|
150
|
+
const source = diagnostic.source ? ` [${diagnostic.source}]` : "";
|
|
151
|
+
return ` ${severity} ${at}${source} ${diagnostic.message}`;
|
|
152
|
+
});
|
|
153
|
+
const more = diagnostics.length > 100 ? `\n … ${diagnostics.length - 100} more` : "";
|
|
154
|
+
return `Diagnostics (${diagnostics.length}):\n${lines.join("\n")}${more}`;
|
|
155
|
+
}
|
|
156
|
+
case "getSymbols": {
|
|
157
|
+
const result = (await client.request("textDocument/documentSymbol", {
|
|
158
|
+
textDocument: { uri },
|
|
159
|
+
}));
|
|
160
|
+
if (!result?.length)
|
|
161
|
+
return "No symbols found.";
|
|
162
|
+
const lines = result.map((s) => {
|
|
163
|
+
const kind = SYMBOL_KINDS[s.kind] ?? `kind:${s.kind}`;
|
|
164
|
+
const range = s.range ?? s.location?.range;
|
|
165
|
+
const loc = range ? `:${range.start.line + 1}` : "";
|
|
166
|
+
return ` ${kind} ${s.name}${loc}`;
|
|
167
|
+
});
|
|
168
|
+
return `Symbols in ${filePath}:\n${lines.join("\n")}`;
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
return `Unknown action: ${action}`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
return `LSP error: ${err.message}`;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function formatLocationResult(result, label) {
|
|
179
|
+
if (!result)
|
|
180
|
+
return `No ${label.toLowerCase()} found.`;
|
|
181
|
+
const locations = Array.isArray(result) ? result : [result];
|
|
182
|
+
if (locations.length === 0)
|
|
183
|
+
return `No ${label.toLowerCase()} found.`;
|
|
184
|
+
const lines = locations.map((loc) => {
|
|
185
|
+
const uri = loc.uri ?? loc.targetUri ?? "";
|
|
186
|
+
const range = loc.range ?? loc.targetRange ?? {};
|
|
187
|
+
const path = uri.replace("file://", "");
|
|
188
|
+
const line = (range.start?.line ?? 0) + 1;
|
|
189
|
+
return ` ${path}:${line}`;
|
|
190
|
+
});
|
|
191
|
+
return `${label} (${locations.length}):\n${lines.join("\n")}`;
|
|
192
|
+
}
|
|
193
|
+
const SYMBOL_KINDS = {
|
|
194
|
+
1: "File",
|
|
195
|
+
2: "Module",
|
|
196
|
+
3: "Namespace",
|
|
197
|
+
4: "Package",
|
|
198
|
+
5: "Class",
|
|
199
|
+
6: "Method",
|
|
200
|
+
7: "Property",
|
|
201
|
+
8: "Field",
|
|
202
|
+
9: "Constructor",
|
|
203
|
+
10: "Enum",
|
|
204
|
+
11: "Interface",
|
|
205
|
+
12: "Function",
|
|
206
|
+
13: "Variable",
|
|
207
|
+
14: "Constant",
|
|
208
|
+
15: "String",
|
|
209
|
+
16: "Number",
|
|
210
|
+
17: "Boolean",
|
|
211
|
+
18: "Array",
|
|
212
|
+
19: "Object",
|
|
213
|
+
20: "Key",
|
|
214
|
+
21: "Null",
|
|
215
|
+
22: "EnumMember",
|
|
216
|
+
23: "Struct",
|
|
217
|
+
24: "Event",
|
|
218
|
+
25: "Operator",
|
|
219
|
+
26: "TypeParameter",
|
|
220
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotebookEditTool — read and edit Jupyter notebook (.ipynb) cells.
|
|
3
|
+
*/
|
|
4
|
+
import type { ToolContext, ToolDefinition } from "@cjhyy/code-shell-core/extension";
|
|
5
|
+
export declare const notebookEditToolDef: ToolDefinition;
|
|
6
|
+
export declare function notebookEditTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotebookEditTool — read and edit Jupyter notebook (.ipynb) cells.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
5
|
+
import { isAbsolute, resolve } from "node:path";
|
|
6
|
+
export const notebookEditToolDef = {
|
|
7
|
+
name: "NotebookEdit",
|
|
8
|
+
description: "Edit a Jupyter notebook (.ipynb) file. Supports actions: " +
|
|
9
|
+
"'read' to view cells, 'insert' to add a cell, 'replace' to update a cell, " +
|
|
10
|
+
"'delete' to remove a cell.",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
file_path: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "Path to the .ipynb file",
|
|
17
|
+
},
|
|
18
|
+
action: {
|
|
19
|
+
type: "string",
|
|
20
|
+
enum: ["read", "insert", "replace", "delete"],
|
|
21
|
+
description: "Operation to perform",
|
|
22
|
+
},
|
|
23
|
+
cell_index: {
|
|
24
|
+
type: "number",
|
|
25
|
+
description: "Cell index (0-based). Required for replace and delete.",
|
|
26
|
+
},
|
|
27
|
+
cell_type: {
|
|
28
|
+
type: "string",
|
|
29
|
+
enum: ["code", "markdown", "raw"],
|
|
30
|
+
description: "Cell type for insert/replace (default: 'code')",
|
|
31
|
+
},
|
|
32
|
+
source: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Cell content for insert/replace",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: ["file_path", "action"],
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
export async function notebookEditTool(args, ctx) {
|
|
41
|
+
const rawPath = args.file_path;
|
|
42
|
+
const action = args.action;
|
|
43
|
+
if (!rawPath)
|
|
44
|
+
return "Error: file_path is required";
|
|
45
|
+
const cwd = ctx?.cwd ?? process.cwd();
|
|
46
|
+
const filePath = isAbsolute(rawPath) ? rawPath : resolve(cwd, rawPath);
|
|
47
|
+
if (!filePath.endsWith(".ipynb"))
|
|
48
|
+
return "Error: file must be a .ipynb file";
|
|
49
|
+
if (action === "read") {
|
|
50
|
+
if (!existsSync(filePath))
|
|
51
|
+
return `Error: File not found: ${filePath}`;
|
|
52
|
+
const nb = readNotebook(filePath);
|
|
53
|
+
const lines = [`Notebook: ${filePath} (${nb.cells.length} cells)\n`];
|
|
54
|
+
nb.cells.forEach((cell, i) => {
|
|
55
|
+
const source = cell.source.join("");
|
|
56
|
+
const preview = source.slice(0, 200);
|
|
57
|
+
lines.push(`[${i}] ${cell.cell_type}: ${preview}${source.length > 200 ? "..." : ""}`);
|
|
58
|
+
});
|
|
59
|
+
return lines.join("\n");
|
|
60
|
+
}
|
|
61
|
+
if (action === "insert") {
|
|
62
|
+
const nb = existsSync(filePath) ? readNotebook(filePath) : createEmptyNotebook();
|
|
63
|
+
const cellType = args.cell_type ?? "code";
|
|
64
|
+
const source = args.source ?? "";
|
|
65
|
+
const index = args.cell_index ?? nb.cells.length;
|
|
66
|
+
const newCell = createCell(cellType, source);
|
|
67
|
+
nb.cells.splice(index, 0, newCell);
|
|
68
|
+
writeNotebook(filePath, nb);
|
|
69
|
+
return `Inserted ${cellType} cell at index ${index}.`;
|
|
70
|
+
}
|
|
71
|
+
if (action === "replace") {
|
|
72
|
+
if (!existsSync(filePath))
|
|
73
|
+
return `Error: File not found: ${filePath}`;
|
|
74
|
+
const nb = readNotebook(filePath);
|
|
75
|
+
const index = args.cell_index;
|
|
76
|
+
if (index === undefined || index < 0 || index >= nb.cells.length) {
|
|
77
|
+
return `Error: Invalid cell_index ${index}. Notebook has ${nb.cells.length} cells.`;
|
|
78
|
+
}
|
|
79
|
+
const cellType = args.cell_type ?? nb.cells[index].cell_type;
|
|
80
|
+
const source = args.source ?? "";
|
|
81
|
+
nb.cells[index] = createCell(cellType, source);
|
|
82
|
+
writeNotebook(filePath, nb);
|
|
83
|
+
return `Replaced cell ${index} with ${cellType} cell.`;
|
|
84
|
+
}
|
|
85
|
+
if (action === "delete") {
|
|
86
|
+
if (!existsSync(filePath))
|
|
87
|
+
return `Error: File not found: ${filePath}`;
|
|
88
|
+
const nb = readNotebook(filePath);
|
|
89
|
+
const index = args.cell_index;
|
|
90
|
+
if (index === undefined || index < 0 || index >= nb.cells.length) {
|
|
91
|
+
return `Error: Invalid cell_index ${index}. Notebook has ${nb.cells.length} cells.`;
|
|
92
|
+
}
|
|
93
|
+
nb.cells.splice(index, 1);
|
|
94
|
+
writeNotebook(filePath, nb);
|
|
95
|
+
return `Deleted cell ${index}. Notebook now has ${nb.cells.length} cells.`;
|
|
96
|
+
}
|
|
97
|
+
return `Unknown action: ${action}`;
|
|
98
|
+
}
|
|
99
|
+
function readNotebook(filePath) {
|
|
100
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
101
|
+
}
|
|
102
|
+
function writeNotebook(filePath, nb) {
|
|
103
|
+
writeFileSync(filePath, JSON.stringify(nb, null, 1) + "\n", "utf-8");
|
|
104
|
+
}
|
|
105
|
+
function createEmptyNotebook() {
|
|
106
|
+
return {
|
|
107
|
+
cells: [],
|
|
108
|
+
metadata: {
|
|
109
|
+
kernelspec: { display_name: "Python 3", language: "python", name: "python3" },
|
|
110
|
+
language_info: { name: "python", version: "3.10.0" },
|
|
111
|
+
},
|
|
112
|
+
nbformat: 4,
|
|
113
|
+
nbformat_minor: 5,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function createCell(type, source) {
|
|
117
|
+
const cell = {
|
|
118
|
+
cell_type: type,
|
|
119
|
+
source: source.split("\n").map((line, i, arr) => (i < arr.length - 1 ? line + "\n" : line)),
|
|
120
|
+
metadata: {},
|
|
121
|
+
};
|
|
122
|
+
if (type === "code") {
|
|
123
|
+
cell.outputs = [];
|
|
124
|
+
cell.execution_count = null;
|
|
125
|
+
}
|
|
126
|
+
return cell;
|
|
127
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EnterWorktree / ExitWorktree tools — switch a session between git workspaces.
|
|
3
|
+
*/
|
|
4
|
+
import type { ToolContext, ToolDefinition } from "@cjhyy/code-shell-core/extension";
|
|
5
|
+
export declare const switchSessionWorkspaceToolDef: ToolDefinition;
|
|
6
|
+
export declare function switchSessionWorkspaceTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
7
|
+
export declare const enterWorktreeToolDef: ToolDefinition;
|
|
8
|
+
export declare function enterWorktreeTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
9
|
+
export declare const exitWorktreeToolDef: ToolDefinition;
|
|
10
|
+
export declare function exitWorktreeTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|