linkshell-cli 0.2.125 → 0.2.126
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/dist/cli/src/commands/setup.js +2 -20
- package/dist/cli/src/commands/setup.js.map +1 -1
- package/dist/cli/src/index.js +26 -28
- package/dist/cli/src/index.js.map +1 -1
- package/dist/cli/src/providers.d.ts +7 -3
- package/dist/cli/src/providers.js +19 -76
- package/dist/cli/src/providers.js.map +1 -1
- package/dist/cli/src/runtime/acp/agent-workspace.js +8 -53
- package/dist/cli/src/runtime/acp/agent-workspace.js.map +1 -1
- package/dist/cli/src/runtime/bridge-session.d.ts +1 -30
- package/dist/cli/src/runtime/bridge-session.js +32 -903
- package/dist/cli/src/runtime/bridge-session.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/dist/shared-protocol/src/index.d.ts +698 -650
- package/dist/shared-protocol/src/index.js +31 -15
- package/dist/shared-protocol/src/index.js.map +1 -1
- package/package.json +2 -2
- package/src/commands/setup.ts +5 -31
- package/src/index.ts +29 -34
- package/src/providers.ts +26 -108
- package/src/runtime/acp/agent-workspace.ts +8 -53
- package/src/runtime/bridge-session.ts +32 -993
- package/src/types/linkshell-gateway.d.ts +18 -0
- package/dist/cli/src/runtime/acp-relay.d.ts +0 -23
- package/dist/cli/src/runtime/acp-relay.js +0 -73
- package/dist/cli/src/runtime/acp-relay.js.map +0 -1
package/src/providers.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { accessSync, constants, existsSync } from "node:fs";
|
|
2
|
-
import { delimiter, join } from "node:path";
|
|
3
|
-
import type { TerminalProvider } from "@linkshell/protocol";
|
|
2
|
+
import { basename, delimiter, join } from "node:path";
|
|
4
3
|
|
|
5
|
-
export type ProviderName =
|
|
4
|
+
export type ProviderName = "shell";
|
|
6
5
|
|
|
7
6
|
export interface ProviderConfig {
|
|
8
7
|
provider: ProviderName;
|
|
@@ -11,6 +10,8 @@ export interface ProviderConfig {
|
|
|
11
10
|
env: NodeJS.ProcessEnv;
|
|
12
11
|
}
|
|
13
12
|
|
|
13
|
+
export type ShellConfig = ProviderConfig;
|
|
14
|
+
|
|
14
15
|
function stripOuterQuotes(value: string): string {
|
|
15
16
|
const trimmed = value.trim();
|
|
16
17
|
if (
|
|
@@ -65,125 +66,42 @@ function which(bin: string): string | undefined {
|
|
|
65
66
|
return undefined;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
function
|
|
69
|
-
command
|
|
70
|
-
|
|
71
|
-
}): ProviderConfig {
|
|
72
|
-
const command = input.command ?? "claude";
|
|
73
|
-
const resolved = which(command);
|
|
74
|
-
if (!resolved) {
|
|
75
|
-
throw new Error(
|
|
76
|
-
`Claude CLI not found ("${command}"). Install it with: npm install -g @anthropic-ai/claude-code`,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Claude starts an interactive REPL by default — that's exactly what we want in the PTY.
|
|
81
|
-
// Pass through any extra args the user provided.
|
|
82
|
-
return {
|
|
83
|
-
provider: "claude",
|
|
84
|
-
command: resolved,
|
|
85
|
-
args: input.args,
|
|
86
|
-
env: { ...process.env },
|
|
87
|
-
};
|
|
69
|
+
function shellSupportsLoginArg(command: string): boolean {
|
|
70
|
+
const name = basename(command).toLowerCase();
|
|
71
|
+
return ["bash", "zsh", "sh", "fish"].includes(name);
|
|
88
72
|
}
|
|
89
73
|
|
|
90
|
-
function
|
|
74
|
+
export function resolveShellConfig(input: {
|
|
91
75
|
command?: string;
|
|
92
|
-
args
|
|
93
|
-
}):
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
process.stderr.write(
|
|
104
|
-
"[warn] OPENAI_API_KEY not set — Codex may fail to authenticate\n",
|
|
105
|
-
);
|
|
106
|
-
}
|
|
76
|
+
args?: string[];
|
|
77
|
+
} = {}): ShellConfig {
|
|
78
|
+
const configuredShell = input.command ?? process.env.SHELL ?? (process.platform === "darwin" ? "/bin/zsh" : undefined);
|
|
79
|
+
const command = configuredShell ?? (process.platform === "win32" ? "cmd.exe" : "sh");
|
|
80
|
+
const resolved = which(command) ?? command;
|
|
81
|
+
const passthrough = input.args ?? [];
|
|
82
|
+
const args = passthrough.length > 0
|
|
83
|
+
? passthrough
|
|
84
|
+
: shellSupportsLoginArg(resolved)
|
|
85
|
+
? ["-l"]
|
|
86
|
+
: [];
|
|
107
87
|
|
|
108
88
|
return {
|
|
109
|
-
provider: "
|
|
89
|
+
provider: "shell",
|
|
110
90
|
command: resolved,
|
|
111
|
-
args
|
|
91
|
+
args,
|
|
112
92
|
env: { ...process.env },
|
|
113
93
|
};
|
|
114
94
|
}
|
|
115
95
|
|
|
116
|
-
function
|
|
96
|
+
export function resolveProviderConfig(input: {
|
|
97
|
+
provider?: string;
|
|
117
98
|
command?: string;
|
|
118
99
|
args: string[];
|
|
119
100
|
}): ProviderConfig {
|
|
120
|
-
|
|
121
|
-
const resolved = which(command);
|
|
122
|
-
if (!resolved) {
|
|
123
|
-
throw new Error(
|
|
124
|
-
`Gemini CLI not found ("${command}"). Install it with: npm install -g @anthropic-ai/gemini-cli or check https://github.com/anthropics/gemini-cli`,
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (!process.env.GOOGLE_API_KEY && !process.env.GEMINI_API_KEY) {
|
|
101
|
+
if (input.provider && input.provider !== "shell") {
|
|
129
102
|
process.stderr.write(
|
|
130
|
-
|
|
103
|
+
`[warn] terminal provider "${input.provider}" is ignored in protocol v2; starting the system shell instead\n`,
|
|
131
104
|
);
|
|
132
105
|
}
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
provider: "gemini",
|
|
136
|
-
command: resolved,
|
|
137
|
-
args: input.args,
|
|
138
|
-
env: { ...process.env },
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function resolveCopilotProvider(input: {
|
|
143
|
-
command?: string;
|
|
144
|
-
args: string[];
|
|
145
|
-
}): ProviderConfig {
|
|
146
|
-
const command = input.command ?? "github-copilot";
|
|
147
|
-
const resolved = which(command);
|
|
148
|
-
if (!resolved) {
|
|
149
|
-
throw new Error(
|
|
150
|
-
`GitHub Copilot CLI not found ("${command}").`,
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
provider: "copilot",
|
|
156
|
-
command: resolved,
|
|
157
|
-
args: input.args,
|
|
158
|
-
env: { ...process.env },
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export function resolveProviderConfig(input: {
|
|
163
|
-
provider: ProviderName;
|
|
164
|
-
command?: string;
|
|
165
|
-
args: string[];
|
|
166
|
-
}): ProviderConfig {
|
|
167
|
-
switch (input.provider) {
|
|
168
|
-
case "claude":
|
|
169
|
-
return resolveClaudeProvider(input);
|
|
170
|
-
case "codex":
|
|
171
|
-
return resolveCodexProvider(input);
|
|
172
|
-
case "gemini":
|
|
173
|
-
return resolveGeminiProvider(input);
|
|
174
|
-
case "copilot":
|
|
175
|
-
return resolveCopilotProvider(input);
|
|
176
|
-
case "custom": {
|
|
177
|
-
if (!input.command) {
|
|
178
|
-
throw new Error("custom provider requires --command");
|
|
179
|
-
}
|
|
180
|
-
const resolved = which(input.command);
|
|
181
|
-
return {
|
|
182
|
-
provider: "custom",
|
|
183
|
-
command: resolved ?? input.command,
|
|
184
|
-
args: input.args,
|
|
185
|
-
env: { ...process.env },
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
}
|
|
106
|
+
return resolveShellConfig({ command: input.command, args: input.args });
|
|
189
107
|
}
|
|
@@ -764,8 +764,6 @@ interface ProviderRuntimeCapabilities {
|
|
|
764
764
|
}
|
|
765
765
|
|
|
766
766
|
const ALL_REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh"] as const;
|
|
767
|
-
const ALL_PERMISSION_MODES = ["read_only", "workspace_write", "full_access"] as const;
|
|
768
|
-
const CODEX_COMMAND_NAMES = ["plan", "exit-plan", "compact", "clear", "status", "review", "subagents"] as const;
|
|
769
767
|
const CLAUDE_REMOTE_HIDDEN_COMMANDS = new Set([
|
|
770
768
|
"add-dir",
|
|
771
769
|
"agents",
|
|
@@ -1039,56 +1037,16 @@ function customClaudeCommands(cwd: string): AgentCommandDescriptor[] {
|
|
|
1039
1037
|
function defaultProviderCommands(provider: AgentProvider, cwd: string, enabled: boolean): AgentCommandDescriptor[] {
|
|
1040
1038
|
const disabledReason = enabled ? undefined : `${providerLabel(provider)} 未安装或启动失败`;
|
|
1041
1039
|
if (provider === "codex") {
|
|
1042
|
-
return
|
|
1043
|
-
provider,
|
|
1044
|
-
name,
|
|
1045
|
-
source: "linkshell",
|
|
1046
|
-
category: name === "plan" || name === "exit-plan" ? "Modes" : "Codex",
|
|
1047
|
-
description: {
|
|
1048
|
-
"plan": "Enter Codex plan mode",
|
|
1049
|
-
"exit-plan": "Exit Codex plan mode",
|
|
1050
|
-
compact: "Compact the current thread",
|
|
1051
|
-
clear: "Start a fresh Codex thread",
|
|
1052
|
-
status: "Show LinkShell agent status",
|
|
1053
|
-
review: "Ask Codex to review local changes",
|
|
1054
|
-
subagents: "Insert a delegation prompt",
|
|
1055
|
-
}[name],
|
|
1056
|
-
argsMode: name === "review" || name === "subagents" ? "optional" : "none",
|
|
1057
|
-
destructive: name === "clear",
|
|
1058
|
-
disabledReason,
|
|
1059
|
-
executionKind: name === "review" || name === "subagents" ? "prompt" : "native",
|
|
1060
|
-
}));
|
|
1040
|
+
return [];
|
|
1061
1041
|
}
|
|
1062
1042
|
if (provider === "claude") {
|
|
1063
|
-
const builtIns = CLAUDE_BUILT_IN_COMMANDS
|
|
1064
|
-
.filter((entry) => isClaudeRemoteFriendlyCommand(entry.name))
|
|
1065
|
-
.map((entry) => makeCommand({
|
|
1066
|
-
provider,
|
|
1067
|
-
name: entry.name,
|
|
1068
|
-
description: entry.description,
|
|
1069
|
-
argsMode: entry.argsMode,
|
|
1070
|
-
destructive: entry.destructive,
|
|
1071
|
-
disabledReason,
|
|
1072
|
-
executionKind: "prompt",
|
|
1073
|
-
}));
|
|
1074
1043
|
const custom = customClaudeCommands(cwd).map((command) => ({
|
|
1075
1044
|
...command,
|
|
1076
1045
|
disabledReason: command.disabledReason ?? disabledReason,
|
|
1077
1046
|
}));
|
|
1078
|
-
return
|
|
1047
|
+
return custom;
|
|
1079
1048
|
}
|
|
1080
|
-
return [
|
|
1081
|
-
makeCommand({
|
|
1082
|
-
provider,
|
|
1083
|
-
name: "status",
|
|
1084
|
-
source: "linkshell",
|
|
1085
|
-
category: "LinkShell",
|
|
1086
|
-
description: "Show LinkShell agent status",
|
|
1087
|
-
argsMode: "none",
|
|
1088
|
-
disabledReason,
|
|
1089
|
-
executionKind: "native",
|
|
1090
|
-
}),
|
|
1091
|
-
];
|
|
1049
|
+
return [];
|
|
1092
1050
|
}
|
|
1093
1051
|
|
|
1094
1052
|
function mergeCommands(...groups: Array<AgentCommandDescriptor[] | undefined>): AgentCommandDescriptor[] {
|
|
@@ -1541,17 +1499,14 @@ export class AgentWorkspaceProxy {
|
|
|
1541
1499
|
supportsPermission,
|
|
1542
1500
|
supportsPlan: enabled,
|
|
1543
1501
|
supportsCancel: enabled,
|
|
1544
|
-
models: runtimeCapabilities?.models
|
|
1545
|
-
defaultModel: runtimeCapabilities?.defaultModel
|
|
1502
|
+
models: runtimeCapabilities?.models,
|
|
1503
|
+
defaultModel: runtimeCapabilities?.defaultModel,
|
|
1546
1504
|
reasoningEfforts: supportsReasoningEffort
|
|
1547
|
-
? runtimeCapabilities?.reasoningEfforts ?? [
|
|
1505
|
+
? runtimeCapabilities?.reasoningEfforts ?? []
|
|
1548
1506
|
: [],
|
|
1549
|
-
permissionModes:
|
|
1507
|
+
permissionModes: [],
|
|
1550
1508
|
commands,
|
|
1551
|
-
modes: runtimeCapabilities?.modes ??
|
|
1552
|
-
{ id: "default", title: "Default", description: "Run normal implementation turns" },
|
|
1553
|
-
{ id: "plan", title: "Plan", description: "Discuss and produce an implementation plan first" },
|
|
1554
|
-
] : []),
|
|
1509
|
+
modes: runtimeCapabilities?.modes ?? [],
|
|
1555
1510
|
currentMode,
|
|
1556
1511
|
features: {
|
|
1557
1512
|
images: supportsImages,
|