linkshell-cli 0.2.109 → 0.2.111

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.
@@ -1,5 +1,6 @@
1
1
  import type { AgentFraming, AgentProtocol } from "./provider-resolver.js";
2
2
  type AgentPermissionMode = "read_only" | "workspace_write" | "full_access";
3
+ type AgentCollaborationMode = "default" | "plan";
3
4
  export declare class AcpClient {
4
5
  private readonly transport;
5
6
  private readonly protocol;
@@ -31,6 +32,7 @@ export declare class AcpClient {
31
32
  model?: string;
32
33
  reasoningEffort?: string;
33
34
  permissionMode?: AgentPermissionMode;
35
+ collaborationMode?: AgentCollaborationMode;
34
36
  cwd: string;
35
37
  }): Promise<unknown>;
36
38
  cancel(input: {
@@ -43,6 +45,9 @@ export declare class AcpClient {
43
45
  outcome: "allow" | "deny";
44
46
  optionId?: string;
45
47
  }): void;
48
+ compact(input: {
49
+ sessionId: string;
50
+ }): Promise<unknown>;
46
51
  stop(): void;
47
52
  }
48
53
  export {};
@@ -96,11 +96,22 @@ export class AcpClient {
96
96
  }
97
97
  prompt(input) {
98
98
  if (this.protocol === "codex-app-server") {
99
+ const collaborationSettings = {
100
+ ...(input.model ? { model: input.model } : {}),
101
+ ...(input.reasoningEffort ? { reasoning_effort: input.reasoningEffort } : {}),
102
+ };
103
+ const collaborationMode = input.collaborationMode && input.collaborationMode !== "default"
104
+ ? {
105
+ mode: input.collaborationMode,
106
+ ...(Object.keys(collaborationSettings).length > 0 ? { settings: collaborationSettings } : {}),
107
+ }
108
+ : undefined;
99
109
  return this.transport.request("turn/start", {
100
110
  threadId: input.sessionId,
101
111
  model: input.model,
102
112
  effort: input.reasoningEffort,
103
113
  permissions: permissionsForMode(input.permissionMode, input.cwd),
114
+ collaborationMode,
104
115
  input: input.content.map((block) => {
105
116
  const raw = block;
106
117
  if (raw.type === "image" && raw.data) {
@@ -136,6 +147,12 @@ export class AcpClient {
136
147
  respondPermission(input) {
137
148
  this.transport.notify("session/respond_permission", input);
138
149
  }
150
+ compact(input) {
151
+ if (this.protocol === "codex-app-server") {
152
+ return this.transport.request("thread/compact/start", { threadId: input.sessionId });
153
+ }
154
+ return Promise.reject(new Error("Native compact is not supported by this provider."));
155
+ }
139
156
  stop() {
140
157
  this.transport.stop();
141
158
  }
@@ -1 +1 @@
1
- {"version":3,"file":"acp-client.js","sourceRoot":"","sources":["../../../../../src/runtime/acp/acp-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acp-client.js","sourceRoot":"","sources":["../../../../../src/runtime/acp/acp-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAMtD,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE;QAC7E,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACnE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAiC,EAAE,CAAC;QACxD,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB,CACzB,IAAqC,EACrC,GAAW;IAEX,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,IAAI,KAAK,aAAa;QAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAExD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC3B,UAAU,EAAE;YACV,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE;oBACjC,MAAM,EAAE,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;iBACtD;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,SAAS;IACH,SAAS,CAAwB;IACjC,QAAQ,CAAgB;IAEzC,YAAY,KAQX;QACC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,IAAI,qBAAqB,CACxC,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,cAAc,EACpB,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,MAAM,CACb,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE;gBACxD,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;gBACjD,YAAY,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;aACxC,CAAC,CAAC;YACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YACzC,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE;YAC1C,eAAe,EAAE,CAAC;YAClB,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE;YACjD,kBAAkB,EAAE;gBAClB,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE;gBACjD,QAAQ,EAAE,KAAK;aAChB;SACF,CAAC,CAAC;IACL,CAAC;IAED,UAAU,CAAC,KAA4C;QACrD,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE;gBAC5C,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,kBAAkB,EAAE,SAAS;aAC9B,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE;YAC3C,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,UAAU,EAAE,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC;SAClD,CAAC,CAAC;IACL,CAAC;IAED,WAAW,CAAC,KAA+D;QACzE,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE;gBAC7C,QAAQ,EAAE,KAAK,CAAC,SAAS;gBACzB,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,YAAY,EAAE,KAAK;aACpB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE;YAC5C,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,UAAU,EAAE,mBAAmB,CAAC,KAAK,CAAC,UAAU,CAAC;SAClD,CAAC,CAAC;IACL,CAAC;IAED,YAAY;QACV,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,UAAU;QACR,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,CAAC,KASN;QACC,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,MAAM,qBAAqB,GAAG;gBAC5B,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC9E,CAAC;YACF,MAAM,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS;gBACxF,CAAC,CAAC;oBACE,IAAI,EAAE,KAAK,CAAC,iBAAiB;oBAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC9F;gBACH,CAAC,CAAC,SAAS,CAAC;YACd,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE;gBAC1C,QAAQ,EAAE,KAAK,CAAC,SAAS;gBACzB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,MAAM,EAAE,KAAK,CAAC,eAAe;gBAC7B,WAAW,EAAE,kBAAkB,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC;gBAChE,iBAAiB;gBACjB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;oBACjC,MAAM,GAAG,GAAG,KAAwD,CAAC;oBACrE,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;wBACrC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;oBAC1C,CAAC;oBACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;gBAChD,CAAC,CAAC;aACH,EAAE,IAAI,CAAC,CAAC;QACX,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE;YAC9C,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,MAAM,EAAE,KAAK,CAAC,OAAO;YACrB,KAAK,EAAE;gBACL,wBAAwB,EAAE,KAAK,CAAC,eAAe;gBAC/C,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,eAAe,EAAE,KAAK,CAAC,eAAe;gBACtC,cAAc,EAAE,KAAK,CAAC,cAAc;aACrC;SACF,EAAE,MAAM,CAAC,CAAC;IACb,CAAC;IAED,MAAM,CAAC,KAA8C;QACnD,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM;gBAAE,OAAO;YAC9C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE;gBACvC,QAAQ,EAAE,KAAK,CAAC,SAAS;gBACzB,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,iBAAiB,CAAC,KAKjB;QACC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,CAAC,KAA4B;QAClC,IAAI,IAAI,CAAC,QAAQ,KAAK,kBAAkB,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,IAAI;QACF,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -40,6 +40,9 @@ export declare class AgentWorkspaceProxy {
40
40
  private openConversation;
41
41
  private openFailure;
42
42
  private sendPrompt;
43
+ private commandForConversation;
44
+ private executeCommand;
45
+ private executeNativeCommand;
43
46
  private handleRequest;
44
47
  private handleNotification;
45
48
  private handleAgentMessageDelta;
@@ -1,4 +1,6 @@
1
- import { basename } from "node:path";
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { basename, join, relative } from "node:path";
2
4
  import { createEnvelope, parseTypedPayload, } from "@linkshell/protocol";
3
5
  import { AcpClient } from "./acp-client.js";
4
6
  import { ClaudeSdkClient } from "./claude-sdk-client.js";
@@ -509,6 +511,222 @@ function providerLabel(provider) {
509
511
  }
510
512
  const ALL_REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh"];
511
513
  const ALL_PERMISSION_MODES = ["read_only", "workspace_write", "full_access"];
514
+ const CODEX_COMMAND_NAMES = ["plan", "exit-plan", "compact", "clear", "status", "review", "subagents"];
515
+ const CLAUDE_BUILT_IN_COMMANDS = [
516
+ { name: "add-dir", description: "Add additional working directories" },
517
+ { name: "agents", description: "Manage subagents" },
518
+ { name: "bug", description: "Report a Claude Code bug" },
519
+ { name: "clear", description: "Clear conversation context", argsMode: "none", destructive: true },
520
+ { name: "compact", description: "Compact conversation history" },
521
+ { name: "config", description: "Open configuration" },
522
+ { name: "cost", description: "Show usage cost" },
523
+ { name: "doctor", description: "Check Claude Code health" },
524
+ { name: "exit", description: "Exit Claude Code", argsMode: "none", destructive: true },
525
+ { name: "export", description: "Export conversation" },
526
+ { name: "help", description: "Show help" },
527
+ { name: "ide", description: "Manage IDE integration" },
528
+ { name: "init", description: "Create or update CLAUDE.md" },
529
+ { name: "login", description: "Sign in" },
530
+ { name: "logout", description: "Sign out" },
531
+ { name: "mcp", description: "Manage MCP servers" },
532
+ { name: "memory", description: "Edit memory files" },
533
+ { name: "model", description: "Switch model" },
534
+ { name: "permissions", description: "Manage permissions" },
535
+ { name: "pr-comments", description: "Fetch PR comments" },
536
+ { name: "release-notes", description: "Show release notes" },
537
+ { name: "resume", description: "Resume a conversation" },
538
+ { name: "review", description: "Review local changes" },
539
+ { name: "security-review", description: "Run a security review" },
540
+ { name: "status", description: "Show status" },
541
+ { name: "statusline", description: "Configure status line" },
542
+ { name: "terminal-setup", description: "Configure terminal integration" },
543
+ { name: "upgrade", description: "Upgrade Claude Code" },
544
+ { name: "vim", description: "Toggle vim mode" },
545
+ ];
546
+ function commandId(provider, name, source = "built_in") {
547
+ return `${provider}:${source}:${name.replace(/^\/+/, "")}`;
548
+ }
549
+ function commandTitle(name) {
550
+ return `/${name.replace(/^\/+/, "")}`;
551
+ }
552
+ function makeCommand(input) {
553
+ const cleanName = input.name.replace(/^\/+/, "");
554
+ const source = input.source ?? "built_in";
555
+ return {
556
+ id: commandId(input.provider, cleanName, source),
557
+ name: cleanName,
558
+ title: commandTitle(cleanName),
559
+ description: input.description,
560
+ provider: input.provider,
561
+ source,
562
+ category: input.category,
563
+ argsMode: input.argsMode ?? "optional",
564
+ requiresIdle: input.requiresIdle,
565
+ destructive: input.destructive,
566
+ disabledReason: input.disabledReason,
567
+ executionKind: input.executionKind ?? "prompt",
568
+ };
569
+ }
570
+ function commandFromMarkdownFile(provider, root, filePath, source) {
571
+ if (!filePath.endsWith(".md"))
572
+ return undefined;
573
+ const rel = relative(root, filePath).replace(/\\/g, "/").replace(/\.md$/i, "");
574
+ const name = rel.split("/").filter(Boolean).join(":");
575
+ if (!name)
576
+ return undefined;
577
+ let description;
578
+ try {
579
+ const text = readFileSync(filePath, "utf8");
580
+ description = text.split(/\r?\n/).map((line) => line.trim()).find((line) => line && !line.startsWith("---"))?.slice(0, 160);
581
+ }
582
+ catch {
583
+ description = undefined;
584
+ }
585
+ return makeCommand({
586
+ provider,
587
+ name,
588
+ description: description || "Custom Claude command",
589
+ source,
590
+ category: source === "project" ? "Project commands" : "User commands",
591
+ argsMode: "raw",
592
+ });
593
+ }
594
+ function walkMarkdownCommands(provider, root, source) {
595
+ if (!existsSync(root))
596
+ return [];
597
+ const result = [];
598
+ const walk = (dir) => {
599
+ let entries = [];
600
+ try {
601
+ entries = readdirSync(dir);
602
+ }
603
+ catch {
604
+ return;
605
+ }
606
+ for (const entry of entries) {
607
+ const path = join(dir, entry);
608
+ let stat;
609
+ try {
610
+ stat = statSync(path);
611
+ }
612
+ catch {
613
+ continue;
614
+ }
615
+ if (stat.isDirectory())
616
+ walk(path);
617
+ else if (stat.isFile()) {
618
+ const command = commandFromMarkdownFile(provider, root, path, source);
619
+ if (command)
620
+ result.push(command);
621
+ }
622
+ }
623
+ };
624
+ walk(root);
625
+ return result;
626
+ }
627
+ function customClaudeCommands(cwd) {
628
+ const projectCommands = walkMarkdownCommands("claude", join(cwd, ".claude", "commands"), "project");
629
+ const userCommands = walkMarkdownCommands("claude", join(homedir(), ".claude", "commands"), "user");
630
+ return [...projectCommands, ...userCommands];
631
+ }
632
+ function defaultProviderCommands(provider, cwd, enabled) {
633
+ const disabledReason = enabled ? undefined : `${providerLabel(provider)} 未安装或启动失败`;
634
+ if (provider === "codex") {
635
+ return CODEX_COMMAND_NAMES.map((name) => makeCommand({
636
+ provider,
637
+ name,
638
+ source: "linkshell",
639
+ category: name === "plan" || name === "exit-plan" ? "Modes" : "Codex",
640
+ description: {
641
+ "plan": "Enter Codex plan mode",
642
+ "exit-plan": "Exit Codex plan mode",
643
+ compact: "Compact the current thread",
644
+ clear: "Start a fresh Codex thread",
645
+ status: "Show LinkShell agent status",
646
+ review: "Ask Codex to review local changes",
647
+ subagents: "Insert a delegation prompt",
648
+ }[name],
649
+ argsMode: name === "review" || name === "subagents" ? "optional" : "none",
650
+ destructive: name === "clear",
651
+ disabledReason,
652
+ executionKind: name === "review" || name === "subagents" ? "prompt" : "native",
653
+ }));
654
+ }
655
+ if (provider === "claude") {
656
+ const builtIns = CLAUDE_BUILT_IN_COMMANDS.map((entry) => makeCommand({
657
+ provider,
658
+ name: entry.name,
659
+ description: entry.description,
660
+ argsMode: entry.argsMode,
661
+ destructive: entry.destructive,
662
+ disabledReason,
663
+ executionKind: "prompt",
664
+ }));
665
+ const custom = customClaudeCommands(cwd).map((command) => ({
666
+ ...command,
667
+ disabledReason: command.disabledReason ?? disabledReason,
668
+ }));
669
+ return [...builtIns, ...custom];
670
+ }
671
+ return [
672
+ makeCommand({
673
+ provider,
674
+ name: "status",
675
+ source: "linkshell",
676
+ category: "LinkShell",
677
+ description: "Show LinkShell agent status",
678
+ argsMode: "none",
679
+ disabledReason,
680
+ executionKind: "native",
681
+ }),
682
+ ];
683
+ }
684
+ function mergeCommands(...groups) {
685
+ const map = new Map();
686
+ for (const group of groups) {
687
+ for (const command of group ?? []) {
688
+ const key = `${command.provider ?? ""}:${command.name}`;
689
+ map.set(key, { ...map.get(key), ...command });
690
+ }
691
+ }
692
+ return [...map.values()].sort((a, b) => a.name.localeCompare(b.name));
693
+ }
694
+ function runtimeCommands(provider, value) {
695
+ const raw = asRecord(value);
696
+ const commandsValue = Array.isArray(value) ? value :
697
+ Array.isArray(raw?.commands) ? raw.commands :
698
+ Array.isArray(raw?.slashCommands) ? raw.slashCommands :
699
+ Array.isArray(raw?.slash_commands) ? raw.slash_commands :
700
+ Array.isArray(raw?.available_commands) ? raw.available_commands :
701
+ [];
702
+ return commandsValue
703
+ .map((entry) => {
704
+ if (typeof entry === "string") {
705
+ return makeCommand({
706
+ provider,
707
+ name: entry,
708
+ description: undefined,
709
+ source: "built_in",
710
+ argsMode: "raw",
711
+ executionKind: "prompt",
712
+ });
713
+ }
714
+ const record = asRecord(entry);
715
+ const name = firstString(record, ["name", "command", "id"]);
716
+ if (!name)
717
+ return undefined;
718
+ return makeCommand({
719
+ provider,
720
+ name,
721
+ description: firstString(record, ["description", "summary"]),
722
+ source: "built_in",
723
+ category: firstString(record, ["category", "group"]),
724
+ argsMode: "raw",
725
+ executionKind: "prompt",
726
+ });
727
+ })
728
+ .filter((entry) => Boolean(entry));
729
+ }
512
730
  function parseModelListCapabilities(value) {
513
731
  const raw = asRecord(value);
514
732
  const modelsValue = Array.isArray(value) ? value :
@@ -641,6 +859,11 @@ export class AgentWorkspaceProxy {
641
859
  await this.sendPrompt(payload);
642
860
  break;
643
861
  }
862
+ case "agent.v2.command.execute": {
863
+ const payload = parseTypedPayload("agent.v2.command.execute", envelope.payload);
864
+ await this.executeCommand(payload);
865
+ break;
866
+ }
644
867
  case "agent.v2.cancel": {
645
868
  const payload = parseTypedPayload("agent.v2.cancel", envelope.payload);
646
869
  const conversation = this.conversations.get(payload.conversationId);
@@ -820,6 +1043,7 @@ export class AgentWorkspaceProxy {
820
1043
  model: remote.model ?? existing?.model,
821
1044
  reasoningEffort: existing?.reasoningEffort,
822
1045
  permissionMode: existing?.permissionMode,
1046
+ collaborationMode: existing?.collaborationMode,
823
1047
  status: existing?.status ?? "idle",
824
1048
  archived: existing?.archived ?? false,
825
1049
  lastMessagePreview: existing?.lastMessagePreview,
@@ -848,6 +1072,8 @@ export class AgentWorkspaceProxy {
848
1072
  const isClaudeFallback = protocol === "claude-stream-json";
849
1073
  const supportsPermission = enabled && !isClaudeFallback;
850
1074
  const supportsReasoningEffort = enabled && !isClaudeFallback;
1075
+ const commands = mergeCommands(defaultProviderCommands(provider, this.input.cwd, enabled), runtimeCapabilities?.commands);
1076
+ const currentMode = [...this.conversations.values()].find((conversation) => conversation.provider === provider)?.collaborationMode;
851
1077
  return {
852
1078
  id: provider,
853
1079
  label: providerLabel(provider),
@@ -863,6 +1089,12 @@ export class AgentWorkspaceProxy {
863
1089
  ? runtimeCapabilities?.reasoningEfforts ?? [...ALL_REASONING_EFFORTS]
864
1090
  : [],
865
1091
  permissionModes: supportsPermission ? [...ALL_PERMISSION_MODES] : [],
1092
+ commands,
1093
+ modes: runtimeCapabilities?.modes ?? (provider === "codex" ? [
1094
+ { id: "default", title: "Default", description: "Run normal implementation turns" },
1095
+ { id: "plan", title: "Plan", description: "Discuss and produce an implementation plan first" },
1096
+ ] : []),
1097
+ currentMode,
866
1098
  features: {
867
1099
  images: supportsImages,
868
1100
  permissions: supportsPermission,
@@ -911,7 +1143,7 @@ export class AgentWorkspaceProxy {
911
1143
  let agentSessionId = payload.agentSessionId;
912
1144
  let existingConversation = (payload.conversationId ? this.conversations.get(payload.conversationId) : undefined) ??
913
1145
  (agentSessionId ? this.conversations.get(this.conversationByAgentSessionId.get(agentSessionId) ?? "") : undefined);
914
- if (existingConversation && existingConversation.status !== "error") {
1146
+ if (existingConversation && existingConversation.status !== "error" && existingConversation.agentSessionId) {
915
1147
  if (payload.conversationId && existingConversation.id !== payload.conversationId) {
916
1148
  existingConversation = this.adoptConversationId(existingConversation.id, payload.conversationId);
917
1149
  }
@@ -943,6 +1175,7 @@ export class AgentWorkspaceProxy {
943
1175
  model: payload.model ?? existingConversation?.model,
944
1176
  reasoningEffort: payload.reasoningEffort ?? existingConversation?.reasoningEffort,
945
1177
  permissionMode: payload.permissionMode ?? existingConversation?.permissionMode,
1178
+ collaborationMode: payload.collaborationMode ?? existingConversation?.collaborationMode,
946
1179
  status: "idle",
947
1180
  archived: existingConversation?.archived ?? false,
948
1181
  lastMessagePreview: existingConversation?.status === "error" ? undefined : existingConversation?.lastMessagePreview,
@@ -976,6 +1209,7 @@ export class AgentWorkspaceProxy {
976
1209
  model: payload.model,
977
1210
  reasoningEffort: payload.reasoningEffort,
978
1211
  permissionMode: payload.permissionMode,
1212
+ collaborationMode: payload.collaborationMode,
979
1213
  status: "error",
980
1214
  archived: false,
981
1215
  lastMessagePreview: message,
@@ -1001,11 +1235,29 @@ export class AgentWorkspaceProxy {
1001
1235
  async sendPrompt(payload) {
1002
1236
  const conversation = this.conversations.get(payload.conversationId) ??
1003
1237
  await this.openConversation({ conversationId: payload.conversationId });
1004
- if (!conversation || !conversation.agentSessionId)
1238
+ if (!conversation)
1239
+ return;
1240
+ if (!conversation.agentSessionId) {
1241
+ this.addItem(payload.conversationId, {
1242
+ id: id("error"),
1243
+ conversationId: payload.conversationId,
1244
+ type: "error",
1245
+ error: "Agent session 尚未就绪,消息没有发送。请重新打开对话后再试。",
1246
+ createdAt: Date.now(),
1247
+ });
1005
1248
  return;
1249
+ }
1006
1250
  const client = this.clientForProvider(conversation.provider);
1007
- if (!client)
1251
+ if (!client) {
1252
+ this.addItem(conversation.id, {
1253
+ id: id("error"),
1254
+ conversationId: conversation.id,
1255
+ type: "error",
1256
+ error: `${providerLabel(conversation.provider)} 未连接,消息没有发送。`,
1257
+ createdAt: Date.now(),
1258
+ });
1008
1259
  return;
1260
+ }
1009
1261
  const protocol = this.protocolForProvider(conversation.provider);
1010
1262
  if (payload.contentBlocks.some((block) => block.type === "image") && !protocolSupportsImages(protocol)) {
1011
1263
  conversation.status = "idle";
@@ -1023,6 +1275,7 @@ export class AgentWorkspaceProxy {
1023
1275
  conversation.model = payload.model ?? conversation.model;
1024
1276
  conversation.reasoningEffort = payload.reasoningEffort ?? conversation.reasoningEffort;
1025
1277
  conversation.permissionMode = payload.permissionMode ?? conversation.permissionMode;
1278
+ conversation.collaborationMode = payload.collaborationMode ?? conversation.collaborationMode;
1026
1279
  conversation.status = "running";
1027
1280
  conversation.lastActivityAt = Date.now();
1028
1281
  this.activeConversationId = conversation.id;
@@ -1045,6 +1298,7 @@ export class AgentWorkspaceProxy {
1045
1298
  model: payload.model,
1046
1299
  reasoningEffort: payload.reasoningEffort,
1047
1300
  permissionMode: payload.permissionMode,
1301
+ collaborationMode: payload.collaborationMode ?? conversation.collaborationMode,
1048
1302
  cwd: conversation.cwd,
1049
1303
  });
1050
1304
  const nextAgentSessionId = this.extractSessionId(result);
@@ -1073,6 +1327,176 @@ export class AgentWorkspaceProxy {
1073
1327
  });
1074
1328
  }
1075
1329
  }
1330
+ commandForConversation(conversation, commandId) {
1331
+ const runtimeCapabilities = this.providerCapabilities.get(conversation.provider);
1332
+ const commands = mergeCommands(defaultProviderCommands(conversation.provider, conversation.cwd, true), runtimeCapabilities?.commands);
1333
+ return commands.find((command) => command.id === commandId ||
1334
+ command.name === commandId ||
1335
+ `/${command.name}` === commandId);
1336
+ }
1337
+ async executeCommand(payload) {
1338
+ const conversation = this.conversations.get(payload.conversationId) ??
1339
+ await this.openConversation({ conversationId: payload.conversationId });
1340
+ if (!conversation)
1341
+ return;
1342
+ if (!conversation.agentSessionId) {
1343
+ this.addItem(payload.conversationId, {
1344
+ id: id("error"),
1345
+ conversationId: payload.conversationId,
1346
+ type: "error",
1347
+ error: "Agent session 尚未就绪,命令没有执行。请重新打开对话后再试。",
1348
+ createdAt: Date.now(),
1349
+ });
1350
+ return;
1351
+ }
1352
+ const command = this.commandForConversation(conversation, payload.commandId);
1353
+ if (!command) {
1354
+ this.addItem(conversation.id, {
1355
+ id: id("error"),
1356
+ conversationId: conversation.id,
1357
+ type: "error",
1358
+ error: `未知命令:${payload.commandId}`,
1359
+ createdAt: Date.now(),
1360
+ });
1361
+ return;
1362
+ }
1363
+ if (command.disabledReason) {
1364
+ this.addItem(conversation.id, {
1365
+ id: id("error"),
1366
+ conversationId: conversation.id,
1367
+ type: "error",
1368
+ error: command.disabledReason,
1369
+ createdAt: Date.now(),
1370
+ });
1371
+ return;
1372
+ }
1373
+ const rawText = payload.rawText?.trim() || `/${command.name}${payload.args?.trim() ? ` ${payload.args.trim()}` : ""}`;
1374
+ if (command.executionKind === "prompt") {
1375
+ await this.sendPrompt({
1376
+ conversationId: conversation.id,
1377
+ clientMessageId: payload.clientMessageId,
1378
+ contentBlocks: [{ type: "text", text: rawText }],
1379
+ model: conversation.model,
1380
+ reasoningEffort: conversation.reasoningEffort,
1381
+ permissionMode: conversation.permissionMode,
1382
+ collaborationMode: conversation.collaborationMode,
1383
+ });
1384
+ return;
1385
+ }
1386
+ this.addItem(conversation.id, {
1387
+ id: payload.clientMessageId,
1388
+ conversationId: conversation.id,
1389
+ type: "message",
1390
+ kind: "chat",
1391
+ role: "user",
1392
+ content: [{ type: "text", text: rawText }],
1393
+ text: rawText,
1394
+ metadata: { commandId: command.id, commandExecutionKind: command.executionKind },
1395
+ createdAt: Date.now(),
1396
+ });
1397
+ if (command.executionKind === "local_ui") {
1398
+ this.emitStatus(conversation.id, "idle", `${command.title} 已由移动端处理。`);
1399
+ return;
1400
+ }
1401
+ await this.executeNativeCommand(conversation, command, payload.args?.trim());
1402
+ }
1403
+ async executeNativeCommand(conversation, command, args) {
1404
+ const client = this.clientForProvider(conversation.provider);
1405
+ const now = Date.now();
1406
+ try {
1407
+ if (command.name === "status") {
1408
+ this.emitStatus(conversation.id, conversation.status, `${providerLabel(conversation.provider)} · ${conversation.collaborationMode === "plan" ? "Plan mode" : "Default mode"} · ${conversation.cwd}`);
1409
+ return;
1410
+ }
1411
+ if (conversation.provider !== "codex") {
1412
+ this.addItem(conversation.id, {
1413
+ id: id("error"),
1414
+ conversationId: conversation.id,
1415
+ type: "error",
1416
+ error: `${command.title} 暂无 ${providerLabel(conversation.provider)} 原生实现。`,
1417
+ createdAt: now,
1418
+ });
1419
+ return;
1420
+ }
1421
+ if (command.name === "plan" || command.name === "exit-plan") {
1422
+ conversation.collaborationMode = command.name === "plan" ? "plan" : "default";
1423
+ conversation.status = "idle";
1424
+ conversation.lastMessagePreview = command.name === "plan" ? "已进入 Plan mode" : "已退出 Plan mode";
1425
+ conversation.lastActivityAt = now;
1426
+ this.emitConversation(conversation);
1427
+ this.sendCapabilities();
1428
+ this.emitStatus(conversation.id, "idle", command.name === "plan"
1429
+ ? "已进入 Plan mode。下一条消息会先制定计划。"
1430
+ : "已退出 Plan mode。");
1431
+ return;
1432
+ }
1433
+ if (command.name === "compact") {
1434
+ if (!(client instanceof AcpClient))
1435
+ throw new Error("当前 Codex runtime 不支持原生 compact。");
1436
+ conversation.status = "running";
1437
+ this.emitConversation(conversation);
1438
+ this.addItem(conversation.id, {
1439
+ id: id("compact"),
1440
+ conversationId: conversation.id,
1441
+ type: "status",
1442
+ kind: "context_compaction",
1443
+ text: "正在压缩上下文",
1444
+ status: "running",
1445
+ isStreaming: true,
1446
+ createdAt: now,
1447
+ });
1448
+ await client.compact({ sessionId: conversation.agentSessionId });
1449
+ this.updateConversationStatus(conversation.id, "idle", "上下文压缩完成");
1450
+ this.emitStatus(conversation.id, "idle", "上下文压缩完成。");
1451
+ return;
1452
+ }
1453
+ if (command.name === "clear") {
1454
+ if (!client)
1455
+ throw new Error("Agent provider 不在线。");
1456
+ const result = await client.newSession({ cwd: conversation.cwd });
1457
+ const nextAgentSessionId = this.extractSessionId(result) ?? id("agent-session");
1458
+ if (conversation.agentSessionId)
1459
+ this.conversationByAgentSessionId.delete(conversation.agentSessionId);
1460
+ conversation.agentSessionId = nextAgentSessionId;
1461
+ conversation.collaborationMode = "default";
1462
+ conversation.status = "idle";
1463
+ conversation.lastMessagePreview = "上下文已重置";
1464
+ conversation.lastActivityAt = now;
1465
+ this.conversationByAgentSessionId.set(nextAgentSessionId, conversation.id);
1466
+ this.timelines.set(conversation.id, []);
1467
+ this.emitConversation(conversation);
1468
+ this.emitStatus(conversation.id, "idle", "上下文已重置,已创建新的 Codex thread。");
1469
+ return;
1470
+ }
1471
+ if (command.name === "review" || command.name === "subagents") {
1472
+ const prompt = command.name === "review"
1473
+ ? args || "Review the current local changes."
1474
+ : args || "Run subagents for distinct tasks in parallel when useful, then synthesize the results.";
1475
+ await this.sendPrompt({
1476
+ conversationId: conversation.id,
1477
+ clientMessageId: id(command.name),
1478
+ contentBlocks: [{ type: "text", text: prompt }],
1479
+ model: conversation.model,
1480
+ reasoningEffort: conversation.reasoningEffort,
1481
+ permissionMode: conversation.permissionMode,
1482
+ collaborationMode: conversation.collaborationMode,
1483
+ });
1484
+ return;
1485
+ }
1486
+ throw new Error(`命令暂未实现:/${command.name}`);
1487
+ }
1488
+ catch (error) {
1489
+ const message = error instanceof Error ? error.message : String(error);
1490
+ this.updateConversationStatus(conversation.id, "error", message);
1491
+ this.addItem(conversation.id, {
1492
+ id: id("error"),
1493
+ conversationId: conversation.id,
1494
+ type: "error",
1495
+ error: message,
1496
+ createdAt: Date.now(),
1497
+ });
1498
+ }
1499
+ }
1076
1500
  handleRequest(method, params) {
1077
1501
  if (method === "item/tool/requestUserInput" || method === "tool/requestUserInput") {
1078
1502
  return this.handleStructuredInput(params, true);
@@ -1092,8 +1516,23 @@ export class AgentWorkspaceProxy {
1092
1516
  if (this.input.verbose) {
1093
1517
  process.stderr.write(`[agent:v2] ${method} ${stringify(params).slice(0, 500)}\n`);
1094
1518
  }
1095
- if (method === "initialized" ||
1096
- method.startsWith("account/") ||
1519
+ if (method === "initialized") {
1520
+ const conversationId = this.conversationIdFromParams(params) ?? this.activeConversationId;
1521
+ const provider = conversationId ? this.conversations.get(conversationId)?.provider : this.input.availableProviders[0];
1522
+ if (provider) {
1523
+ const commands = runtimeCommands(provider, params);
1524
+ if (commands.length > 0) {
1525
+ const existing = this.providerCapabilities.get(provider);
1526
+ this.providerCapabilities.set(provider, {
1527
+ ...(existing ?? {}),
1528
+ commands: mergeCommands(existing?.commands, commands),
1529
+ });
1530
+ this.sendCapabilities();
1531
+ }
1532
+ }
1533
+ return;
1534
+ }
1535
+ if (method.startsWith("account/") ||
1097
1536
  method.startsWith("mcpServer/startupStatus/") ||
1098
1537
  method === "thread/status/changed" ||
1099
1538
  method === "thread/tokenUsage/updated" ||