@kenkaiiii/ggcoder 5.78.0 → 5.79.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.
Files changed (107) hide show
  1. package/dist/app-sidecar/app-settings.d.ts +6 -2
  2. package/dist/app-sidecar/app-settings.js +39 -20
  3. package/dist/app-sidecar/app-settings.js.map +1 -1
  4. package/dist/app-sidecar/git-target.d.ts +17 -0
  5. package/dist/app-sidecar/git-target.js +31 -0
  6. package/dist/app-sidecar/git-target.js.map +1 -0
  7. package/dist/app-sidecar/goal-routes.d.ts +26 -0
  8. package/dist/app-sidecar/goal-routes.js +445 -0
  9. package/dist/app-sidecar/goal-routes.js.map +1 -0
  10. package/dist/app-sidecar/history-routes.d.ts +13 -0
  11. package/dist/app-sidecar/history-routes.js +36 -25
  12. package/dist/app-sidecar/history-routes.js.map +1 -1
  13. package/dist/app-sidecar/mcp-routes.js +1 -2
  14. package/dist/app-sidecar/mcp-routes.js.map +1 -1
  15. package/dist/app-sidecar/route-context.d.ts +12 -0
  16. package/dist/app-sidecar/run-control-routes.js +2 -1
  17. package/dist/app-sidecar/run-control-routes.js.map +1 -1
  18. package/dist/app-sidecar/session-routes.js +41 -0
  19. package/dist/app-sidecar/session-routes.js.map +1 -1
  20. package/dist/app-sidecar/session-types.d.ts +2 -0
  21. package/dist/app-sidecar/workspace-routes.js +13 -95
  22. package/dist/app-sidecar/workspace-routes.js.map +1 -1
  23. package/dist/app-sidecar.js +213 -60
  24. package/dist/app-sidecar.js.map +1 -1
  25. package/dist/cli/shared.js +1 -1
  26. package/dist/cli/shared.js.map +1 -1
  27. package/dist/cli.js +1 -1
  28. package/dist/cli.js.map +1 -1
  29. package/dist/core/acceptance-checks.js +17 -4
  30. package/dist/core/acceptance-checks.js.map +1 -1
  31. package/dist/core/agent-notifications.d.ts +1 -1
  32. package/dist/core/agent-session.d.ts +76 -5
  33. package/dist/core/agent-session.js +118 -22
  34. package/dist/core/agent-session.js.map +1 -1
  35. package/dist/core/ask-user.d.ts +11 -0
  36. package/dist/core/ask-user.js +6 -1
  37. package/dist/core/ask-user.js.map +1 -1
  38. package/dist/core/auth-providers.d.ts +2 -80
  39. package/dist/core/auth-providers.js +4 -183
  40. package/dist/core/auth-providers.js.map +1 -1
  41. package/dist/core/context-files.d.ts +8 -0
  42. package/dist/core/context-files.js +46 -0
  43. package/dist/core/context-files.js.map +1 -0
  44. package/dist/core/env-delta.d.ts +9 -1
  45. package/dist/core/env-delta.js +20 -0
  46. package/dist/core/env-delta.js.map +1 -1
  47. package/dist/core/goals-store.d.ts +208 -0
  48. package/dist/core/goals-store.js +520 -0
  49. package/dist/core/goals-store.js.map +1 -0
  50. package/dist/core/local-endpoint-store.js +15 -11
  51. package/dist/core/local-endpoint-store.js.map +1 -1
  52. package/dist/core/project-discovery.d.ts +7 -0
  53. package/dist/core/project-discovery.js +8 -2
  54. package/dist/core/project-discovery.js.map +1 -1
  55. package/dist/core/radio.d.ts +2 -3
  56. package/dist/core/radio.js.map +1 -1
  57. package/dist/core/session-manager.d.ts +7 -1
  58. package/dist/core/session-manager.js +17 -7
  59. package/dist/core/session-manager.js.map +1 -1
  60. package/dist/core/session-storage.d.ts +3 -0
  61. package/dist/core/session-storage.js +8 -2
  62. package/dist/core/session-storage.js.map +1 -1
  63. package/dist/core/subagent-manager.d.ts +51 -0
  64. package/dist/core/subagent-manager.js +95 -15
  65. package/dist/core/subagent-manager.js.map +1 -1
  66. package/dist/core/subagent-store.js +2 -1
  67. package/dist/core/subagent-store.js.map +1 -1
  68. package/dist/goals-agent/goal-team.d.ts +2 -0
  69. package/dist/goals-agent/goal-team.js +82 -0
  70. package/dist/goals-agent/goal-team.js.map +1 -0
  71. package/dist/goals-agent/goals-agent.d.ts +90 -0
  72. package/dist/goals-agent/goals-agent.js +246 -0
  73. package/dist/goals-agent/goals-agent.js.map +1 -0
  74. package/dist/index.js +1 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/interactive.js +4 -3
  77. package/dist/interactive.js.map +1 -1
  78. package/dist/modes/subagent-worker-mode.d.ts +12 -0
  79. package/dist/modes/subagent-worker-mode.js +22 -1
  80. package/dist/modes/subagent-worker-mode.js.map +1 -1
  81. package/dist/system-prompt.d.ts +8 -0
  82. package/dist/system-prompt.js +21 -9
  83. package/dist/system-prompt.js.map +1 -1
  84. package/dist/tools/bash-read-evidence.d.ts +13 -0
  85. package/dist/tools/bash-read-evidence.js +48 -1
  86. package/dist/tools/bash-read-evidence.js.map +1 -1
  87. package/dist/tools/index.d.ts +7 -1
  88. package/dist/tools/index.js +10 -2
  89. package/dist/tools/index.js.map +1 -1
  90. package/dist/tools/read-tracker.d.ts +6 -12
  91. package/dist/tools/read-tracker.js +21 -36
  92. package/dist/tools/read-tracker.js.map +1 -1
  93. package/dist/tools/read.js +2 -2
  94. package/dist/tools/read.js.map +1 -1
  95. package/dist/tools/subagent-control.js +22 -3
  96. package/dist/tools/subagent-control.js.map +1 -1
  97. package/dist/tools/write.js +110 -8
  98. package/dist/tools/write.js.map +1 -1
  99. package/dist/ui/components/ActivityIndicator.d.ts +5 -5
  100. package/dist/ui/components/InputArea.d.ts +2 -2
  101. package/dist/ui/components/InputArea.js +3 -3
  102. package/dist/ui/components/InputArea.js.map +1 -1
  103. package/dist/ui/components/ToolExecution.d.ts +2 -2
  104. package/dist/utils/format.d.ts +0 -4
  105. package/dist/utils/format.js +0 -7
  106. package/dist/utils/format.js.map +1 -1
  107. package/package.json +4 -4
@@ -68,11 +68,24 @@ function verifyFileChanged(check, calls, cwd) {
68
68
  }
69
69
  return { check, status: "FAIL", reason: "the helper never wrote or edited it" };
70
70
  }
71
- function verifyCommandPassed(check, calls) {
72
- const wanted = normalizeCommand(check.target);
71
+ /**
72
+ * A command without a leading `cd` into the helper's own folder: the helper's
73
+ * shell already starts there, so `cd <cwd> && npm test` and `npm test` are the
74
+ * same run. A `cd` anywhere else is kept, as it changes what ran.
75
+ */
76
+ function inOwnFolder(command, cwd) {
77
+ const match = /^cd\s+("[^"]+"|'[^']+'|\S+)\s*&&\s*(.+)$/.exec(command);
78
+ if (!match?.[1] || !match[2])
79
+ return command;
80
+ const dir = match[1].replace(/^["']|["']$/g, "");
81
+ return path.resolve(cwd, dir) === path.resolve(cwd) ? match[2] : command;
82
+ }
83
+ function verifyCommandPassed(check, calls, cwd) {
84
+ const same = (command) => inOwnFolder(normalizeCommand(command), cwd);
85
+ const wanted = same(check.target);
73
86
  let lastIndex = -1;
74
87
  calls.forEach((call, index) => {
75
- if (call.name === "bash" && normalizeCommand(call.target) === wanted)
88
+ if (call.name === "bash" && same(call.target) === wanted)
76
89
  lastIndex = index;
77
90
  });
78
91
  const last = calls[lastIndex];
@@ -111,7 +124,7 @@ export function verifyAcceptanceChecks(checks, calls, cwd) {
111
124
  case "file_changed":
112
125
  return verifyFileChanged(check, calls, cwd);
113
126
  case "command_passed":
114
- return verifyCommandPassed(check, calls);
127
+ return verifyCommandPassed(check, calls, cwd);
115
128
  }
116
129
  });
117
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"acceptance-checks.js","sourceRoot":"","sources":["../../src/core/acceptance-checks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acceptance-checks.js","sourceRoot":"","sources":["../../src/core/acceptance-checks.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@
15
15
  * queue would silently eat the context window it is meant to save.
16
16
  */
17
17
  /** Notification source. Extended as new push producers are added. */
18
- export type NotificationKind = "subagent" | "process";
18
+ export type NotificationKind = "subagent" | "process" | "goal";
19
19
  export interface AgentNotification {
20
20
  kind: NotificationKind;
21
21
  /** Producer-scoped identity (agent id, process id). Dedupe key with `kind`. */
@@ -6,10 +6,12 @@ import { SlashCommandRegistry } from "./slash-commands.js";
6
6
  import { type BranchInfo, type KenTurnPayload, type AutopilotMarkerPayload, type AppMarkerPayload, type RunOutcome, type TurnMetricPayload } from "./session-manager.js";
7
7
  import { type Skill } from "./skills.js";
8
8
  import type { BackgroundProcess } from "./process-manager.js";
9
+ import { type ChildModelPick, type SubAgentSnapshot } from "./subagent-manager.js";
9
10
  import type { MCPElicitHandler } from "./mcp/index.js";
10
11
  import { type ContextLimits } from "./context-limits.js";
11
12
  import { type ImportForeignTranscriptResult } from "./foreign-session-import.js";
12
13
  import { type CacheExpiryStatus } from "./cache-expiry.js";
14
+ import { type AgentDefinition } from "./agents.js";
13
15
  import { type EnhanceResult } from "../utils/prompt-enhancer.js";
14
16
  import type { VerificationEvidence } from "./verification-evidence.js";
15
17
  /** A chat attachment (image / video / other file) prepared for the model. The
@@ -122,6 +124,45 @@ export interface AgentSessionOptions {
122
124
  * UI. Omitted by callers that don't want plan mode (CLI wires its own).
123
125
  */
124
126
  onEnterPlan?: (reason?: string) => void | Promise<void>;
127
+ /**
128
+ * Built-in tools to keep in the core set instead of the deferred
129
+ * tool_search catalog: for a specialist whose job is a deferred tool (GG
130
+ * Goals orchestrates with spawn_agent and friends). Fixed for the session.
131
+ */
132
+ coreTools?: readonly string[];
133
+ /**
134
+ * Default provider/model for the workers this session spawns, when their
135
+ * agent names no model of its own. Read at spawn time.
136
+ */
137
+ getChildModel?: () => ChildModelPick | undefined;
138
+ /**
139
+ * Wrap each built-in tool once, at registration. Must keep the tool's name,
140
+ * description and parameters (only `execute` may change), so the tool block
141
+ * stays prompt-cache stable. Used by GG Goals to gate its own editing.
142
+ */
143
+ wrapTool?: (tool: AgentTool) => AgentTool;
144
+ /**
145
+ * Built-in tools this session never has, removed at registration (before
146
+ * tiering) and left out of the system prompt's Tools section. Unlike
147
+ * `allowedTools`, the rest of the tool set and its tiering are untouched.
148
+ * Fixed for the session, so the cached tool block never changes. Used by
149
+ * GG Goals, which never edits or runs anything itself.
150
+ */
151
+ withoutTools?: readonly string[];
152
+ /**
153
+ * A fixed team of sub-agents, replacing agent discovery (project, global
154
+ * and bundled): the only agents spawn_agent and subagent can start. Used by
155
+ * GG Goals, whose workers follow their own rules (goals-agent/goal-team.ts).
156
+ */
157
+ subAgents?: readonly AgentDefinition[];
158
+ /**
159
+ * Start every spawned child with this session's extra workspace roots too
160
+ * (less the folder it works in), so it can read and change all of them.
161
+ * GG Goals' workers work across all of a goal's attached folders.
162
+ */
163
+ shareRootsWithSubAgents?: boolean;
164
+ /** The sub-agent a spawned child is when the spawn names none (one of `subAgents`). */
165
+ defaultSubAgent?: string;
125
166
  onExitPlan?: (planPath: string) => Promise<ToolExecuteResult>;
126
167
  /**
127
168
  * If provided, the session's tool set is filtered to ONLY these tool names
@@ -324,6 +365,9 @@ export declare class AgentSession {
324
365
  * for no benefit.
325
366
  */
326
367
  private activeLanguages;
368
+ /** Languages the model has already been given guidance for, via the system
369
+ * prompt or an appended language update. */
370
+ private announcedLanguages;
327
371
  /** Shared with the tool layer so plan-mode restrictions read live state. */
328
372
  private planModeRef;
329
373
  /** Path of the approved plan currently being implemented, or undefined. When
@@ -671,6 +715,15 @@ export declare class AgentSession {
671
715
  /** Clear the queue, returning the combined text (to restore to the composer).
672
716
  * Queued attachments are dropped on cancel — the composer only restores text. */
673
717
  drainQueue(): string;
718
+ /**
719
+ * Tell the agent a new fact at its next turn, as a short hidden message
720
+ * appended after the cached prompt (the same channel as a finished worker),
721
+ * so a mid-session change reaches it without re-rendering the prompt. A
722
+ * later note with the same id replaces one not yet delivered.
723
+ */
724
+ notify(id: string, text: string): void;
725
+ /** This session's sub-agents (workers), newest-state, including ones restored after a restart. */
726
+ listSubAgents(): SubAgentSnapshot[];
674
727
  /** Snapshot of background processes (bash run_in_background), newest-state. */
675
728
  listBackgroundProcesses(): BackgroundProcess[];
676
729
  /** Stop a background process by id. Returns a human-readable status string. */
@@ -745,16 +798,34 @@ export declare class AgentSession {
745
798
  * context, return contract and Environment), or the standard prompt.
746
799
  */
747
800
  private buildBasePrompt;
748
- /**
749
- * Add newly detected project languages. Returns true when the set grew and
750
- * the standard prompt therefore needs a rebuild. Custom and sub-agent
751
- * prompts never render packs, so detection is skipped for them.
752
- */
753
801
  /**
754
802
  * Bring the system prompt to the exact state the next provider request will
755
803
  * send. Shared by real runs and {@link prewarm} so both see one prefix.
804
+ *
805
+ * Languages are re-detected at each task boundary. Before the first reply
806
+ * nothing is cached worth keeping, so a new language simply rebuilds the
807
+ * prompt. After that the prompt is a cached prefix and is left alone: the
808
+ * new language is announced by {@link announceNewLanguages} instead.
756
809
  */
757
810
  private prepareSystemPromptForRequest;
811
+ private hasReply;
812
+ /**
813
+ * Give the model style packs for languages that appeared after its prompt
814
+ * was cached (e.g. the previous task scaffolded a TypeScript project), as a
815
+ * hidden message appended to the history rather than a prompt re-render that
816
+ * would throw away the whole cache. Runs just before a new user message is
817
+ * added, so the user's request stays the last thing the model reads and the
818
+ * update is saved in order with the rest of the conversation.
819
+ */
820
+ private announceNewLanguages;
821
+ /**
822
+ * Whether this session renders language packs: the standard prompt, and a
823
+ * code-writing child (a sub-agent prompt with project context). A verbatim
824
+ * custom prompt never does, nor do user-facing specialist agents (Motion,
825
+ * goals) or recon children without project context.
826
+ */
827
+ private languagesApply;
828
+ /** Add newly detected project languages. Returns true when the set grew. */
758
829
  private refreshActiveLanguages;
759
830
  /** Rebuild messages[0] from current plan-mode + approved-plan state. */
760
831
  private rebuildSystemPromptInPlace;
@@ -26,7 +26,7 @@ import { createTools, createWebSearchTool, } from "../tools/index.js";
26
26
  import { partitionToolsByTier } from "../tools/tool-tiers.js";
27
27
  import { buildProcessCompletionFollowUp } from "./process-gate.js";
28
28
  import { PLAN_SUBMISSION_NUDGE, shouldNudgePlanSubmission } from "./plan-submission-gate.js";
29
- import { buildSubAgentCompletionFollowUp } from "./subagent-manager.js";
29
+ import { buildSubAgentCompletionFollowUp, } from "./subagent-manager.js";
30
30
  import { applyAsyncSubagentPolicy } from "./subagent-policy.js";
31
31
  import { resolveResponsesLite, resolveStrictTools, } from "./codex-request-shape.js";
32
32
  import { subAgentDescription } from "../tools/subagent.js";
@@ -52,7 +52,7 @@ import { detectLanguages, detectProjectStack } from "./language-detector.js";
52
52
  import { buildLoopBreakMessage } from "./loop-breaker.js";
53
53
  import { buildRegroundingMessage, requestTextForRegrounding } from "./regrounding.js";
54
54
  import { buildSemanticLoopJudgePrompt, buildSemanticLoopMessage, parseSemanticLoopVerdict, SEMANTIC_LOOP_JUDGE_TIMEOUT_MS, withJudgeTimeout, } from "./semantic-loop-check.js";
55
- import { buildEnvDeltaMessage } from "./env-delta.js";
55
+ import { buildEnvDeltaMessage, buildLanguageUpdateMessage } from "./env-delta.js";
56
56
  import { wrapSteeringText, buildNotificationSteeringText, STEERING_PREFIX } from "./steering.js";
57
57
  import { AgentNotificationQueue } from "./agent-notifications.js";
58
58
  import { VerificationGate, VERIFICATION_STATE_KIND } from "./verification-gate.js";
@@ -217,6 +217,9 @@ export class AgentSession {
217
217
  * for no benefit.
218
218
  */
219
219
  activeLanguages = new Set();
220
+ /** Languages the model has already been given guidance for, via the system
221
+ * prompt or an appended language update. */
222
+ announcedLanguages = new Set();
220
223
  /** Shared with the tool layer so plan-mode restrictions read live state. */
221
224
  planModeRef = { current: false };
222
225
  /** Path of the approved plan currently being implemented, or undefined. When
@@ -306,7 +309,10 @@ export class AgentSession {
306
309
  // Session manager. Agent-specific roots keep chat and coder histories isolated.
307
310
  this.sessionManager = new SessionManager(this.opts.sessionRootDir ?? paths.sessionsDir);
308
311
  const projectCustomization = this.opts.projectCustomization !== false;
309
- if (projectCustomization) {
312
+ // A sub-agent worker never creates them: the session that owns the
313
+ // project does. GG Goals' workers work in the user's attached folders,
314
+ // which mustn't gain empty .gg folders as a side effect.
315
+ if (projectCustomization && !this.opts.subagentWorker) {
310
316
  // Ensure project-local .gg directories exist.
311
317
  const localGGDir = path.join(this.cwd, ".gg");
312
318
  await fs.mkdir(path.join(localGGDir, "skills"), { recursive: true });
@@ -327,16 +333,20 @@ export class AgentSession {
327
333
  }
328
334
  // Discover agents and create tools (with sub-agent support). Chat sessions
329
335
  // can retain bundled workers without loading project/global customization.
330
- const agents = projectCustomization
331
- ? await discoverAgents({
332
- globalAgentsDir: paths.agentsDir,
333
- projectDir: this.cwd,
334
- })
335
- : this.opts.globalSubagents
336
- ? await discoverAgents({ globalAgentsDir: paths.agentsDir })
337
- : [];
336
+ const agents = this.opts.subAgents
337
+ ? [...this.opts.subAgents]
338
+ : projectCustomization
339
+ ? await discoverAgents({
340
+ globalAgentsDir: paths.agentsDir,
341
+ projectDir: this.cwd,
342
+ })
343
+ : this.opts.globalSubagents
344
+ ? await discoverAgents({ globalAgentsDir: paths.agentsDir })
345
+ : [];
338
346
  const { tools: builtInTools, processManager, rebuildReadTool, clearReadTracker, recordBashReads, lspManager, debugManager, subAgentManager, } = await createTools(this.cwd, {
339
347
  agents,
348
+ shareWorkspaceRoots: this.opts.shareRootsWithSubAgents,
349
+ defaultSubAgent: this.opts.defaultSubAgent,
340
350
  skills: this.skills,
341
351
  contextLimits: this.contextLimits,
342
352
  provider: this.provider,
@@ -378,6 +388,7 @@ export class AgentSession {
378
388
  getBaseUrl: () => this.baseUrl,
379
389
  getCacheKey: () => this.getPromptCacheKey(),
380
390
  getMaxPerModel: () => this.settingsManager.get("subagentMaxPerModel"),
391
+ getChildModel: this.opts.getChildModel,
381
392
  // A persistent child is already the single allowed fan-out level. Blocking
382
393
  // `subagent` here created a timeout sandwich: the nested call could consume
383
394
  // the child's entire 10-minute turn budget, discarding all nested results.
@@ -405,6 +416,16 @@ export class AgentSession {
405
416
  // a hallucinated call can't mutate the repo — and buildSystemPrompt below is
406
417
  // fed the same filtered names so the Tools section matches exactly.
407
418
  this.tools = this.opts.allowedTools ? tools.filter((t) => this.isToolAllowed(t.name)) : tools;
419
+ const without = new Set(this.opts.withoutTools ?? []);
420
+ if (without.size > 0)
421
+ this.tools = this.tools.filter((t) => !without.has(t.name));
422
+ // A host may wrap built-ins (GG Goals holds back its own editing once a
423
+ // goal is underway). Same names and schemas, so the cached tool block and
424
+ // the system prompt's Tools section are unchanged.
425
+ if (this.opts.wrapTool) {
426
+ const wrap = this.opts.wrapTool;
427
+ this.tools = this.tools.map((t) => wrap(t));
428
+ }
408
429
  // Both delegation tools carry the agent roster; when both survive the
409
430
  // allow-list, `subagent` points at `spawn_agent`'s copy instead.
410
431
  if (this.tools.some((t) => t.name === "spawn_agent")) {
@@ -419,7 +440,14 @@ export class AgentSession {
419
440
  // catalog must hold the wrapped tool so a promoted spawn still loads
420
441
  // wait_agent.
421
442
  this.promoteFollowUpTools();
422
- const { core, deferred } = partitionToolsByTier(this.tools);
443
+ const partition = partitionToolsByTier(this.tools);
444
+ // A session can keep chosen built-ins in its core set (GG Goals
445
+ // orchestrates, so its agent tools are always at hand). Fixed for the
446
+ // session, so the cached tool block stays byte-stable.
447
+ const keep = new Set(this.opts.coreTools ?? []);
448
+ const deferred = partition.deferred.filter((t) => !keep.has(t.name));
449
+ // Everything not deferred, in the original relative order.
450
+ const core = keep.size > 0 ? this.tools.filter((t) => !deferred.includes(t)) : partition.core;
423
451
  if (deferred.length > 0) {
424
452
  // Append-only: `core` preserves the original relative order and
425
453
  // tool_search is pushed after it, so the serialized tool block that
@@ -454,6 +482,9 @@ export class AgentSession {
454
482
  else {
455
483
  await this.connectMcpServers();
456
484
  }
485
+ // Detect languages before the first render so the opening prompt already
486
+ // carries their packs and only a genuinely new language needs an update.
487
+ this.refreshActiveLanguages();
457
488
  const basePrompt = await this.buildBasePrompt(false, undefined);
458
489
  this.baseSystemPrompt = basePrompt;
459
490
  this.messages = [{ role: "system", content: this.withSystemPromptTail(basePrompt) }];
@@ -788,6 +819,7 @@ export class AgentSession {
788
819
  if (slash?.kind === "template") {
789
820
  // Prompt templates remain human-originated: the user invoked the command.
790
821
  const userMessage = { role: "user", content: slash.fullPrompt, provenance };
822
+ await this.announceNewLanguages();
791
823
  this.messages.push(userMessage);
792
824
  await this.persistMessage(userMessage);
793
825
  this.lastPersistedIndex = this.messages.length;
@@ -804,6 +836,7 @@ export class AgentSession {
804
836
  }
805
837
  // Push user message
806
838
  const userMessage = { role: "user", content, provenance };
839
+ await this.announceNewLanguages();
807
840
  this.messages.push(userMessage);
808
841
  await this.persistMessage(userMessage);
809
842
  this.lastPersistedIndex = this.messages.length;
@@ -828,6 +861,7 @@ export class AgentSession {
828
861
  content: parts,
829
862
  provenance: { source: "human", kind: "prompt", visibility: "transcript" },
830
863
  };
864
+ await this.announceNewLanguages();
831
865
  this.messages.push(userMessage);
832
866
  await this.persistMessage(userMessage);
833
867
  this.lastPersistedIndex = this.messages.length;
@@ -2442,6 +2476,9 @@ export class AgentSession {
2442
2476
  // new session's /history, and get re-persisted into the new file by the
2443
2477
  // next compaction — the cross-session duplicate-marker propagation bug.
2444
2478
  this.markers.clear();
2479
+ // Detect languages before the first render so the opening prompt already
2480
+ // carries their packs and only a genuinely new language needs an update.
2481
+ this.refreshActiveLanguages();
2445
2482
  const basePrompt = await this.buildBasePrompt(false, undefined);
2446
2483
  this.baseSystemPrompt = basePrompt;
2447
2484
  this.messages = [{ role: "system", content: this.withSystemPromptTail(basePrompt) }];
@@ -2645,6 +2682,19 @@ export class AgentSession {
2645
2682
  .map((m) => m.text)
2646
2683
  .join("\n\n");
2647
2684
  }
2685
+ /**
2686
+ * Tell the agent a new fact at its next turn, as a short hidden message
2687
+ * appended after the cached prompt (the same channel as a finished worker),
2688
+ * so a mid-session change reaches it without re-rendering the prompt. A
2689
+ * later note with the same id replaces one not yet delivered.
2690
+ */
2691
+ notify(id, text) {
2692
+ this.notifications.enqueue("goal", id, text, { terminal: true });
2693
+ }
2694
+ /** This session's sub-agents (workers), newest-state, including ones restored after a restart. */
2695
+ listSubAgents() {
2696
+ return this.subAgentManager?.list() ?? [];
2697
+ }
2648
2698
  /** Snapshot of background processes (bash run_in_background), newest-state. */
2649
2699
  listBackgroundProcesses() {
2650
2700
  return this.processManager?.list() ?? [];
@@ -2797,6 +2847,8 @@ export class AgentSession {
2797
2847
  return this.customSystemPrompt;
2798
2848
  const toolNames = this.tools.map((tool) => tool.name);
2799
2849
  const deferredToolNames = this.deferredToolNamesForPrompt(toolNames);
2850
+ // Whatever is rendered now is what the model has been told.
2851
+ this.announcedLanguages = new Set(this.activeLanguages);
2800
2852
  if (this.agentPrompt !== undefined) {
2801
2853
  return buildSubAgentSystemPrompt(this.agentPrompt, {
2802
2854
  cwd: this.cwd,
@@ -2806,29 +2858,73 @@ export class AgentSession {
2806
2858
  role: this.opts.agentRole,
2807
2859
  environment: this.recordRenderedEnvironment(),
2808
2860
  contextLimits: this.contextLimits,
2861
+ ...(this.languagesApply() ? { activeLanguages: this.activeLanguages } : {}),
2809
2862
  });
2810
2863
  }
2811
2864
  return buildSystemPrompt(this.cwd, this.skills, planMode, approvedPlanPath, toolNames, this.activeLanguages, this.provider, this.recordRenderedEnvironment(), deferredToolNames, this.contextLimits);
2812
2865
  }
2813
- /**
2814
- * Add newly detected project languages. Returns true when the set grew and
2815
- * the standard prompt therefore needs a rebuild. Custom and sub-agent
2816
- * prompts never render packs, so detection is skipped for them.
2817
- */
2818
2866
  /**
2819
2867
  * Bring the system prompt to the exact state the next provider request will
2820
2868
  * send. Shared by real runs and {@link prewarm} so both see one prefix.
2869
+ *
2870
+ * Languages are re-detected at each task boundary. Before the first reply
2871
+ * nothing is cached worth keeping, so a new language simply rebuilds the
2872
+ * prompt. After that the prompt is a cached prefix and is left alone: the
2873
+ * new language is announced by {@link announceNewLanguages} instead.
2821
2874
  */
2822
2875
  async prepareSystemPromptForRequest() {
2823
- // Languages are re-detected at each task boundary so a project scaffolded
2824
- // during the previous turn gets its packs; the prompt is rebuilt only when
2825
- // the set grows, keeping the cached prefix stable otherwise.
2826
- if (this.refreshActiveLanguages())
2876
+ if (this.refreshActiveLanguages() && !this.hasReply()) {
2827
2877
  await this.rebuildSystemPromptInPlace();
2878
+ }
2828
2879
  this.refreshSystemPromptTail();
2829
2880
  }
2881
+ hasReply() {
2882
+ return this.messages.some((m) => m.role === "assistant");
2883
+ }
2884
+ /**
2885
+ * Give the model style packs for languages that appeared after its prompt
2886
+ * was cached (e.g. the previous task scaffolded a TypeScript project), as a
2887
+ * hidden message appended to the history rather than a prompt re-render that
2888
+ * would throw away the whole cache. Runs just before a new user message is
2889
+ * added, so the user's request stays the last thing the model reads and the
2890
+ * update is saved in order with the rest of the conversation.
2891
+ */
2892
+ async announceNewLanguages() {
2893
+ if (!this.hasReply())
2894
+ return; // the next request rebuilds the prompt instead
2895
+ this.refreshActiveLanguages();
2896
+ const fresh = new Set([...this.activeLanguages].filter((id) => !this.announcedLanguages.has(id)));
2897
+ if (fresh.size === 0)
2898
+ return;
2899
+ for (const id of fresh)
2900
+ this.announcedLanguages.add(id);
2901
+ const update = buildLanguageUpdateMessage(fresh, this.cwd);
2902
+ if (!update)
2903
+ return;
2904
+ this.messages.push(update);
2905
+ await this.persistMessage(update);
2906
+ this.lastPersistedIndex = this.messages.length;
2907
+ log("INFO", "language", "Appended style packs for new languages", {
2908
+ added: [...fresh].join(","),
2909
+ });
2910
+ }
2911
+ /**
2912
+ * Whether this session renders language packs: the standard prompt, and a
2913
+ * code-writing child (a sub-agent prompt with project context). A verbatim
2914
+ * custom prompt never does, nor do user-facing specialist agents (Motion,
2915
+ * goals) or recon children without project context.
2916
+ */
2917
+ languagesApply() {
2918
+ if (this.customSystemPrompt)
2919
+ return false;
2920
+ if (this.agentPrompt === undefined)
2921
+ return true;
2922
+ return ((this.opts.agentRole ?? "subagent") === "subagent" &&
2923
+ (this.opts.agentContext ?? "project") === "project");
2924
+ }
2925
+ /** Add newly detected project languages. Returns true when the set grew. */
2830
2926
  refreshActiveLanguages() {
2831
- if (this.customSystemPrompt || this.agentPrompt !== undefined)
2927
+ if (!this.languagesApply())
2832
2928
  return false;
2833
2929
  let grew = false;
2834
2930
  try {