@kenkaiiii/ggcoder 5.14.0 → 5.15.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.
@@ -22,7 +22,7 @@ import { formatError } from "@kenkaiiii/gg-ai";
22
22
  import { runJsonMode } from "./modes/json-mode.js";
23
23
  import { runSubagentWorkerMode } from "./modes/subagent-worker-mode.js";
24
24
  import { AgentSession } from "./core/agent-session.js";
25
- import { CHAT_AGENT_IDS, chatAgentSessionsDir, createChatAgent, parseChatAgentId, sessionsDirForChatAgent, } from "./chat-agents/index.js";
25
+ import { CHAT_AGENT_IDS, chatAgentSessionsDir, createChatAgent, parseChatAgentId, sessionsDirForChatAgent, switchChatAgent, } from "./chat-agents/index.js";
26
26
  import { buildMemoryTools, MemoryStore } from "./chat-agents/memory.js";
27
27
  import { buildKenSystemPrompt, buildKenAutopilotSystemPrompt } from "./core/ken-prompt.js";
28
28
  import { buildKenDigest, buildKenAutopilotContext, buildKenAutopilotPlanContext, } from "./core/ken-context.js";
@@ -889,7 +889,7 @@ async function createSession(deps, opts) {
889
889
  const { auth, progress, memoryStore } = deps;
890
890
  const paths = deps.paths;
891
891
  const mode = opts.mode;
892
- const chatAgent = opts.chatAgent;
892
+ let chatAgent = opts.chatAgent;
893
893
  const cwd = opts.cwd;
894
894
  // Base host for parsing request-URL query params (value is irrelevant to
895
895
  // parsing); the daemon owns the real listen host.
@@ -1009,6 +1009,15 @@ async function createSession(deps, opts) {
1009
1009
  sessionsDir: paths.sessionsDir,
1010
1010
  additionalTools: buildMemoryTools(memoryStore),
1011
1011
  getSystemPromptTail: () => memoryStore.renderForPrompt(),
1012
+ onAgentChange: async (nextAgent) => {
1013
+ chatAgent = nextAgent;
1014
+ broadcast("chat_agent_change", { chatAgent: nextAgent });
1015
+ await session.persistAppMarker("agent_handoff", { chatAgent: nextAgent }).catch((error) => {
1016
+ log("WARN", "app-sidecar", "agent handoff marker persist failed", {
1017
+ message: error instanceof Error ? error.message : String(error),
1018
+ });
1019
+ });
1020
+ },
1012
1021
  });
1013
1022
  }
1014
1023
  else {
@@ -1036,6 +1045,15 @@ async function createSession(deps, opts) {
1036
1045
  });
1037
1046
  }
1038
1047
  await session.initialize();
1048
+ if (mode === "chat") {
1049
+ const restoredAgent = [...session.getAppMarkers()]
1050
+ .reverse()
1051
+ .find((marker) => marker.kind === "agent_handoff")?.data.chatAgent;
1052
+ if (typeof restoredAgent === "string") {
1053
+ chatAgent = parseChatAgentId(restoredAgent);
1054
+ await switchChatAgent(session, chatAgent, false);
1055
+ }
1056
+ }
1039
1057
  log("INFO", "app-sidecar", "session ready", { provider, model, mode, chatAgent, cwd });
1040
1058
  // Footer extras (context window, git branch, background tasks). The git
1041
1059
  // branch is resolved once at startup and refreshed lazily; the context
@@ -1952,8 +1970,33 @@ async function createSession(deps, opts) {
1952
1970
  return;
1953
1971
  }
1954
1972
  const requestedAgent = new URL(url, `http://${host}`).searchParams.get("chatAgent");
1955
- const sessionsDir = mode === "chat" || requestedAgent
1956
- ? sessionsDirForChatAgent(paths.sessionsDir, requestedAgent ?? chatAgent)
1973
+ if (requestedAgent === "all") {
1974
+ void Promise.all(CHAT_AGENT_IDS.map(async (agentId) => {
1975
+ const agentSessions = await listRecentSessions(target, 5, chatAgentSessionsDir(paths.sessionsDir, agentId));
1976
+ return agentSessions.map((item) => ({ ...item, chatAgent: agentId }));
1977
+ }))
1978
+ .then(async (groups) => {
1979
+ const dated = await Promise.all(groups.flat().map(async (item) => ({
1980
+ item,
1981
+ mtime: await fs
1982
+ .stat(item.path)
1983
+ .then((stat) => stat.mtimeMs)
1984
+ .catch(() => 0),
1985
+ })));
1986
+ const recent = dated
1987
+ .sort((left, right) => right.mtime - left.mtime)
1988
+ .slice(0, 5)
1989
+ .map(({ item }) => item);
1990
+ json(res, 200, { sessions: recent });
1991
+ })
1992
+ .catch(() => json(res, 200, { sessions: [] }));
1993
+ return;
1994
+ }
1995
+ // The picker may be served by a sidecar currently running in Chat mode.
1996
+ // An omitted chatAgent always means coding history; chat callers identify
1997
+ // their namespace explicitly (one agent or "all").
1998
+ const sessionsDir = requestedAgent
1999
+ ? sessionsDirForChatAgent(paths.sessionsDir, requestedAgent)
1957
2000
  : paths.sessionsDir;
1958
2001
  void listRecentSessions(target, 5, sessionsDir)
1959
2002
  .then((sessions) => json(res, 200, { sessions }))
@@ -2824,7 +2867,10 @@ async function createSession(deps, opts) {
2824
2867
  }
2825
2868
  void session
2826
2869
  .newSession()
2827
- .then(() => {
2870
+ .then(async () => {
2871
+ if (mode === "chat") {
2872
+ await session.persistAppMarker("agent_handoff", { chatAgent });
2873
+ }
2828
2874
  injectedAutopilotPrompts = [];
2829
2875
  clearPendingPlan();
2830
2876
  broadcast("session_reset", {});
@@ -3324,7 +3370,9 @@ async function createSession(deps, opts) {
3324
3370
  return {
3325
3371
  id: opts.id,
3326
3372
  mode,
3327
- chatAgent,
3373
+ get chatAgent() {
3374
+ return chatAgent;
3375
+ },
3328
3376
  cwd,
3329
3377
  sessionPath: opts.sessionPath,
3330
3378
  session,