linkshell-cli 0.2.101 → 0.2.103
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 +28 -7
- package/dist/cli/src/runtime/acp/agent-workspace.js +5 -2
- package/dist/cli/src/runtime/acp/agent-workspace.js.map +1 -1
- package/dist/cli/src/runtime/acp/claude-sdk-client.d.ts +1 -0
- package/dist/cli/src/runtime/acp/claude-sdk-client.js +44 -1
- package/dist/cli/src/runtime/acp/claude-sdk-client.js.map +1 -1
- package/dist/cli/src/runtime/acp/claude-stream-json-client.d.ts +1 -0
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js +12 -0
- package/dist/cli/src/runtime/acp/claude-stream-json-client.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/runtime/acp/agent-workspace.ts +4 -2
- package/src/runtime/acp/claude-sdk-client.ts +46 -1
- package/src/runtime/acp/claude-stream-json-client.ts +13 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { readdirSync, existsSync } from "node:fs";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
3
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import type { AgentFraming, AgentProtocol } from "./provider-resolver.js";
|
|
5
5
|
|
|
6
6
|
type AgentPermissionMode = "read_only" | "workspace_write" | "full_access";
|
|
@@ -68,6 +68,29 @@ function isRealClaudeSessionId(value: string | undefined): value is string {
|
|
|
68
68
|
return Boolean(value && !value.startsWith("agent-session-"));
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
72
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
73
|
+
? value as Record<string, unknown>
|
|
74
|
+
: undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function stringField(value: unknown, keys: string[]): string | undefined {
|
|
78
|
+
const record = asRecord(value);
|
|
79
|
+
if (!record) return undefined;
|
|
80
|
+
for (const key of keys) {
|
|
81
|
+
const candidate = record[key];
|
|
82
|
+
if (typeof candidate === "string" && candidate.trim()) return candidate;
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function isInsideCwd(cwd: string, candidate: string): boolean {
|
|
88
|
+
const root = resolve(cwd);
|
|
89
|
+
const target = resolve(root, candidate);
|
|
90
|
+
const rel = relative(root, target);
|
|
91
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
92
|
+
}
|
|
93
|
+
|
|
71
94
|
function outcomeFromPermissionResponse(value: unknown): "allow" | "deny" {
|
|
72
95
|
const raw = value && typeof value === "object" ? value as Record<string, unknown> : {};
|
|
73
96
|
if (raw.behavior === "allow") return "allow";
|
|
@@ -158,9 +181,18 @@ export class ClaudeSdkClient {
|
|
|
158
181
|
abortController,
|
|
159
182
|
canUseTool: async (toolName: string, toolInput: unknown) => {
|
|
160
183
|
if (input.permissionMode === "full_access") return { behavior: "allow" };
|
|
184
|
+
if (["Read", "Glob", "Grep", "LS", "NotebookRead", "TodoRead"].includes(toolName)) {
|
|
185
|
+
return { behavior: "allow" };
|
|
186
|
+
}
|
|
161
187
|
if (input.permissionMode === "read_only" && ["Write", "Edit", "MultiEdit", "Bash"].includes(toolName)) {
|
|
162
188
|
return { behavior: "deny", message: "Read-only mode is active." };
|
|
163
189
|
}
|
|
190
|
+
if (input.permissionMode === "workspace_write" && ["Write", "Edit", "MultiEdit"].includes(toolName)) {
|
|
191
|
+
const filePath = stringField(toolInput, ["file_path", "path", "notebook_path"]);
|
|
192
|
+
if (filePath && isInsideCwd(input.cwd ?? this.input.cwd, filePath)) {
|
|
193
|
+
return { behavior: "allow" };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
164
196
|
const requestId = id("claude-perm");
|
|
165
197
|
const response = await this.input.onRequest("claude/requestApproval", {
|
|
166
198
|
requestId,
|
|
@@ -248,6 +280,19 @@ export class ClaudeSdkClient {
|
|
|
248
280
|
return { sessions };
|
|
249
281
|
}
|
|
250
282
|
|
|
283
|
+
async listModels(): Promise<unknown> {
|
|
284
|
+
return {
|
|
285
|
+
defaultModel: "default",
|
|
286
|
+
models: [
|
|
287
|
+
{ id: "sonnet", label: "Sonnet" },
|
|
288
|
+
{ id: "opus", label: "Opus" },
|
|
289
|
+
{ id: "haiku", label: "Haiku" },
|
|
290
|
+
{ id: "sonnet[1m]", label: "Sonnet 1M" },
|
|
291
|
+
{ id: "opusplan", label: "Opus Plan" },
|
|
292
|
+
],
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
251
296
|
stop(): void {
|
|
252
297
|
this.cancel({});
|
|
253
298
|
}
|
|
@@ -443,6 +443,19 @@ export class ClaudeStreamJsonClient {
|
|
|
443
443
|
return { sessions };
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
+
async listModels(): Promise<unknown> {
|
|
447
|
+
return {
|
|
448
|
+
defaultModel: "default",
|
|
449
|
+
models: [
|
|
450
|
+
{ id: "sonnet", label: "Sonnet" },
|
|
451
|
+
{ id: "opus", label: "Opus" },
|
|
452
|
+
{ id: "haiku", label: "Haiku" },
|
|
453
|
+
{ id: "sonnet[1m]", label: "Sonnet 1M" },
|
|
454
|
+
{ id: "opusplan", label: "Opus Plan" },
|
|
455
|
+
],
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
446
459
|
stop(): void {
|
|
447
460
|
if (this.child && !this.child.killed) {
|
|
448
461
|
this.child.kill("SIGTERM");
|