@gajae-code/coding-agent 0.8.1 → 0.9.0

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 (253) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/dist/types/append-only-mode.d.ts +31 -0
  3. package/dist/types/capability/rule.d.ts +8 -0
  4. package/dist/types/cli/completion-cli.d.ts +41 -0
  5. package/dist/types/cli/config-cli.d.ts +1 -0
  6. package/dist/types/cli/fixture-report.d.ts +20 -0
  7. package/dist/types/cli/fixture-report.test.d.ts +1 -0
  8. package/dist/types/cli/nofile-limit.d.ts +11 -0
  9. package/dist/types/cli/notify-cli.d.ts +7 -0
  10. package/dist/types/cli/update-cli.d.ts +22 -0
  11. package/dist/types/cli.d.ts +124 -1
  12. package/dist/types/commands/completion.d.ts +29 -0
  13. package/dist/types/commands/config.d.ts +3 -0
  14. package/dist/types/commands/deep-interview.d.ts +3 -0
  15. package/dist/types/config/file-lock.d.ts +7 -6
  16. package/dist/types/config/keybindings.d.ts +2 -2
  17. package/dist/types/config/model-profile-activation.d.ts +6 -0
  18. package/dist/types/config/settings-schema.d.ts +105 -1
  19. package/dist/types/config/settings.d.ts +8 -0
  20. package/dist/types/discovery/index.d.ts +1 -0
  21. package/dist/types/export/html/template.generated.d.ts +1 -1
  22. package/dist/types/export/ttsr.d.ts +14 -3
  23. package/dist/types/extensibility/extensions/runner.d.ts +2 -1
  24. package/dist/types/extensibility/extensions/types.d.ts +8 -0
  25. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +39 -0
  26. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
  27. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -1
  28. package/dist/types/gjc-runtime/deep-interview-state.d.ts +17 -2
  29. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +7 -0
  30. package/dist/types/gjc-runtime/state-writer.d.ts +3 -0
  31. package/dist/types/gjc-runtime/team-runtime.d.ts +28 -1
  32. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
  33. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +120 -13
  34. package/dist/types/goals/runtime.d.ts +1 -0
  35. package/dist/types/hooks/native-skill-hook.d.ts +12 -0
  36. package/dist/types/main.d.ts +4 -1
  37. package/dist/types/modes/components/assistant-message.d.ts +5 -1
  38. package/dist/types/modes/components/model-selector.d.ts +4 -0
  39. package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
  40. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  41. package/dist/types/modes/components/status-line.d.ts +9 -0
  42. package/dist/types/modes/controllers/command-controller.d.ts +1 -0
  43. package/dist/types/modes/controllers/event-controller.d.ts +5 -0
  44. package/dist/types/modes/controllers/input-controller.d.ts +1 -3
  45. package/dist/types/modes/interactive-mode.d.ts +2 -0
  46. package/dist/types/modes/print-mode.d.ts +13 -1
  47. package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
  48. package/dist/types/modes/rpc/rpc-types.d.ts +14 -0
  49. package/dist/types/modes/shared/agent-wire/event-contract.d.ts +19 -0
  50. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +23 -1
  51. package/dist/types/modes/types.d.ts +1 -0
  52. package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
  53. package/dist/types/notifications/config.d.ts +14 -1
  54. package/dist/types/notifications/daemon-paths.d.ts +1 -0
  55. package/dist/types/notifications/index.d.ts +6 -3
  56. package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
  57. package/dist/types/notifications/telegram-daemon.d.ts +23 -3
  58. package/dist/types/notifications/telegram-reference.d.ts +0 -5
  59. package/dist/types/notifications/threaded-render.d.ts +6 -0
  60. package/dist/types/runtime-api-key.d.ts +7 -0
  61. package/dist/types/sdk.d.ts +3 -0
  62. package/dist/types/session/agent-session.d.ts +53 -1
  63. package/dist/types/session/agent-storage.d.ts +1 -0
  64. package/dist/types/session/file-mention-pruning.d.ts +8 -0
  65. package/dist/types/session/messages.d.ts +4 -0
  66. package/dist/types/session/session-manager.d.ts +17 -1
  67. package/dist/types/skill-state/active-state.d.ts +18 -1
  68. package/dist/types/system-prompt.d.ts +18 -2
  69. package/dist/types/task/executor.d.ts +3 -0
  70. package/dist/types/task/fork-context-budget.d.ts +7 -0
  71. package/dist/types/task/token-log.d.ts +30 -0
  72. package/dist/types/task/token-log.test.d.ts +1 -0
  73. package/dist/types/tools/bisect.d.ts +81 -0
  74. package/dist/types/tools/computer.d.ts +2 -2
  75. package/dist/types/tools/index.d.ts +1 -0
  76. package/dist/types/tools/search.d.ts +2 -2
  77. package/dist/types/utils/file-mentions.d.ts +14 -0
  78. package/dist/types/utils/git.d.ts +32 -0
  79. package/dist/types/web/scrapers/youtube.d.ts +8 -0
  80. package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
  81. package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
  82. package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
  83. package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
  84. package/package.json +7 -7
  85. package/src/append-only-mode.ts +58 -0
  86. package/src/autoresearch/prompt.md +1 -1
  87. package/src/autoresearch/tools/log-experiment.ts +1 -1
  88. package/src/capability/rule.ts +9 -0
  89. package/src/cli/completion-cli.ts +234 -0
  90. package/src/cli/config-cli.ts +61 -9
  91. package/src/cli/fast-help.ts +1 -0
  92. package/src/cli/fixture-report.test.ts +230 -0
  93. package/src/cli/fixture-report.ts +171 -0
  94. package/src/cli/nofile-limit.ts +48 -0
  95. package/src/cli/notify-cli.ts +91 -7
  96. package/src/cli/update-cli.ts +85 -9
  97. package/src/cli.ts +29 -1
  98. package/src/commands/completion.ts +84 -0
  99. package/src/commands/config.ts +2 -0
  100. package/src/commands/contribution-prep.ts +1 -1
  101. package/src/commands/deep-interview.ts +2 -1
  102. package/src/config/file-lock.ts +73 -34
  103. package/src/config/keybindings.ts +2 -2
  104. package/src/config/model-profile-activation.ts +65 -0
  105. package/src/config/model-registry.ts +14 -2
  106. package/src/config/settings-schema.ts +68 -1
  107. package/src/config/settings.ts +22 -0
  108. package/src/coordinator-mcp/server.ts +34 -8
  109. package/src/defaults/gjc/skills/deep-interview/SKILL.md +50 -18
  110. package/src/defaults/gjc/skills/ralplan/SKILL.md +40 -99
  111. package/src/defaults/gjc/skills/team/SKILL.md +17 -14
  112. package/src/defaults/gjc/skills/ultragoal/SKILL.md +59 -4
  113. package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
  114. package/src/defaults/gjc-defaults.ts +9 -0
  115. package/src/discovery/helpers.ts +10 -0
  116. package/src/discovery/index.ts +1 -0
  117. package/src/export/html/template.generated.ts +1 -1
  118. package/src/export/html/template.js +60 -2
  119. package/src/export/ttsr.ts +96 -18
  120. package/src/extensibility/extensions/runner.ts +183 -219
  121. package/src/extensibility/extensions/types.ts +9 -0
  122. package/src/extensibility/gjc-plugins/runtime-adapters.ts +156 -44
  123. package/src/gjc-runtime/deep-interview-ambiguity.ts +206 -0
  124. package/src/gjc-runtime/deep-interview-recorder.ts +62 -8
  125. package/src/gjc-runtime/deep-interview-runtime.ts +210 -2
  126. package/src/gjc-runtime/deep-interview-state.ts +44 -2
  127. package/src/gjc-runtime/session-state-sidecar.ts +263 -20
  128. package/src/gjc-runtime/state-runtime.ts +12 -2
  129. package/src/gjc-runtime/state-writer.ts +15 -0
  130. package/src/gjc-runtime/team-runtime.ts +187 -15
  131. package/src/gjc-runtime/ultragoal-guard.ts +55 -66
  132. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +315 -0
  133. package/src/gjc-runtime/ultragoal-runtime.ts +1663 -159
  134. package/src/gjc-runtime/workflow-manifest.generated.json +113 -2
  135. package/src/gjc-runtime/workflow-manifest.ts +74 -1
  136. package/src/goals/runtime.ts +10 -2
  137. package/src/hindsight/backend.ts +1 -3
  138. package/src/hooks/native-skill-hook.ts +124 -4
  139. package/src/internal-urls/docs-index.generated.ts +16 -7
  140. package/src/main.ts +95 -43
  141. package/src/memories/index.ts +12 -1
  142. package/src/modes/components/assistant-message.ts +241 -82
  143. package/src/modes/components/custom-editor.ts +1 -0
  144. package/src/modes/components/model-selector.ts +54 -11
  145. package/src/modes/components/queued-message-selector.ts +92 -0
  146. package/src/modes/components/settings-selector.ts +4 -0
  147. package/src/modes/components/status-line.ts +167 -54
  148. package/src/modes/components/tool-execution.ts +44 -19
  149. package/src/modes/components/welcome.ts +160 -44
  150. package/src/modes/controllers/command-controller.ts +40 -4
  151. package/src/modes/controllers/event-controller.ts +66 -47
  152. package/src/modes/controllers/extension-ui-controller.ts +4 -10
  153. package/src/modes/controllers/input-controller.ts +180 -18
  154. package/src/modes/controllers/selector-controller.ts +122 -27
  155. package/src/modes/interactive-mode.ts +51 -16
  156. package/src/modes/print-mode.ts +43 -4
  157. package/src/modes/prompt-action-autocomplete.ts +21 -20
  158. package/src/modes/rpc/rpc-mode.ts +29 -3
  159. package/src/modes/rpc/rpc-types.ts +9 -0
  160. package/src/modes/shared/agent-wire/command-validation.ts +4 -0
  161. package/src/modes/shared/agent-wire/event-contract.ts +22 -0
  162. package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
  163. package/src/modes/shared/agent-wire/scopes.ts +1 -0
  164. package/src/modes/types.ts +1 -0
  165. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  166. package/src/modes/utils/ui-helpers.ts +19 -6
  167. package/src/notifications/config.ts +25 -5
  168. package/src/notifications/daemon-paths.ts +2 -0
  169. package/src/notifications/index.ts +117 -14
  170. package/src/notifications/lifecycle-commands.ts +37 -7
  171. package/src/notifications/lifecycle-orchestrator.ts +19 -6
  172. package/src/notifications/telegram-daemon-cli.ts +2 -2
  173. package/src/notifications/telegram-daemon-control.ts +5 -3
  174. package/src/notifications/telegram-daemon.ts +302 -51
  175. package/src/notifications/telegram-reference.ts +0 -16
  176. package/src/notifications/threaded-render.ts +17 -1
  177. package/src/prompts/agents/architect.md +19 -10
  178. package/src/prompts/agents/critic.md +16 -18
  179. package/src/prompts/agents/executor.md +14 -11
  180. package/src/prompts/agents/planner.md +18 -13
  181. package/src/prompts/ci-green-request.md +3 -8
  182. package/src/prompts/goals/goal-continuation.md +0 -5
  183. package/src/prompts/goals/goal-mode-active.md +0 -5
  184. package/src/prompts/system/agent-creation-architect.md +2 -2
  185. package/src/prompts/system/plan-mode-active.md +1 -1
  186. package/src/prompts/system/plan-mode-subagent.md +3 -3
  187. package/src/prompts/system/project-prompt.md +0 -13
  188. package/src/prompts/system/subagent-system-prompt.md +3 -2
  189. package/src/prompts/system/system-prompt.md +29 -19
  190. package/src/prompts/system/volatile-project-context.md +10 -0
  191. package/src/prompts/system/web-search.md +4 -7
  192. package/src/prompts/tools/apply-patch.md +6 -0
  193. package/src/prompts/tools/ast-edit.md +1 -0
  194. package/src/prompts/tools/bash.md +1 -1
  195. package/src/prompts/tools/bisect.md +22 -0
  196. package/src/prompts/tools/browser.md +1 -1
  197. package/src/prompts/tools/computer.md +2 -2
  198. package/src/prompts/tools/cron.md +0 -2
  199. package/src/prompts/tools/eval.md +2 -2
  200. package/src/prompts/tools/find.md +1 -1
  201. package/src/prompts/tools/github.md +6 -6
  202. package/src/prompts/tools/goal.md +1 -3
  203. package/src/prompts/tools/image-gen.md +12 -5
  204. package/src/prompts/tools/irc.md +5 -4
  205. package/src/prompts/tools/job.md +2 -2
  206. package/src/prompts/tools/lsp.md +1 -1
  207. package/src/prompts/tools/monitor.md +2 -2
  208. package/src/prompts/tools/patch.md +2 -2
  209. package/src/prompts/tools/replace.md +2 -21
  210. package/src/prompts/tools/rewind.md +1 -1
  211. package/src/prompts/tools/search-tool-bm25.md +1 -11
  212. package/src/prompts/tools/search.md +1 -1
  213. package/src/prompts/tools/skill.md +3 -2
  214. package/src/prompts/tools/ssh.md +2 -1
  215. package/src/prompts/tools/subagent.md +2 -2
  216. package/src/prompts/tools/task.md +4 -5
  217. package/src/prompts/tools/todo-write.md +1 -1
  218. package/src/prompts/tools/vim.md +1 -0
  219. package/src/prompts/tools/web-search.md +2 -0
  220. package/src/prompts/tools/write.md +8 -2
  221. package/src/runtime-api-key.ts +16 -0
  222. package/src/sdk.ts +52 -28
  223. package/src/session/agent-session.ts +951 -132
  224. package/src/session/agent-storage.ts +4 -0
  225. package/src/session/file-mention-pruning.ts +64 -0
  226. package/src/session/messages.ts +4 -0
  227. package/src/session/session-manager.ts +103 -4
  228. package/src/skill-state/active-state.ts +141 -5
  229. package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
  230. package/src/slash-commands/builtin-registry.ts +218 -71
  231. package/src/system-prompt.ts +57 -16
  232. package/src/task/executor.ts +132 -24
  233. package/src/task/fork-context-advisory.ts +2 -7
  234. package/src/task/fork-context-budget.ts +9 -0
  235. package/src/task/index.ts +13 -6
  236. package/src/task/output-manager.ts +20 -8
  237. package/src/task/receipt.ts +26 -7
  238. package/src/task/token-log.test.ts +188 -0
  239. package/src/task/token-log.ts +179 -0
  240. package/src/tools/bisect.ts +367 -0
  241. package/src/tools/computer.ts +246 -43
  242. package/src/tools/index.ts +3 -0
  243. package/src/tools/output-meta.ts +116 -4
  244. package/src/tools/search.ts +8 -2
  245. package/src/tools/skill.ts +15 -0
  246. package/src/tools/telegram-send.ts +6 -0
  247. package/src/utils/file-mentions.ts +39 -7
  248. package/src/utils/git.ts +73 -0
  249. package/src/web/scrapers/youtube.ts +24 -12
  250. package/src/workflow/workflow-intent-diff.ts +29 -6
  251. package/src/workflow/workflow-intent-report-consumer.ts +221 -0
  252. package/src/workflow/workflow-intent-report-schema.ts +129 -0
  253. package/src/workflow/workflow-intent-report.ts +135 -0
package/src/main.ts CHANGED
@@ -37,6 +37,7 @@ import type { ExtensionUIContext } from "./extensibility/extensions/types";
37
37
  import type { InteractiveMode } from "./modes/interactive-mode";
38
38
  import { initTheme, stopThemeWatcher } from "./modes/theme/theme";
39
39
  import type { SubmittedUserInput } from "./modes/types";
40
+ import { applyCliRuntimeApiKeyOverride } from "./runtime-api-key";
40
41
  import type { MCPManager } from "./runtime-mcp";
41
42
  import {
42
43
  type CreateAgentSessionOptions,
@@ -51,6 +52,7 @@ import { runStartupCredentialAutoImportIfNeeded } from "./setup/credential-auto-
51
52
  import { formatModelOnboardingGuidance } from "./setup/model-onboarding-guidance";
52
53
  import { executeBuiltinSlashCommand } from "./slash-commands/builtin-registry";
53
54
  import { resolvePromptInput } from "./system-prompt";
55
+ import { persistTaskTokenLog, resolveTaskTokenLogDir, taskTokenLogFromUsage } from "./task/token-log";
54
56
  import type { LspStartupServerInfo } from "./tools";
55
57
  import { getDisplayChangelogEntries, getInstalledVersionChangelogEntry, getNewEntries } from "./utils/changelog";
56
58
  import type { EventBus } from "./utils/event-bus";
@@ -189,6 +191,11 @@ function applyExtensionFlagValues(session: AgentSession, rawArgs: string[]): Map
189
191
  return extensionRunner.getFlagValues();
190
192
  }
191
193
 
194
+ type CreateSessionForMain = (
195
+ options: CreateAgentSessionOptions,
196
+ context?: { skipPostCreateModelRefresh?: boolean },
197
+ ) => Promise<CreateAgentSessionResult>;
198
+
192
199
  type AcpSessionFactory = (cwd: string) => Promise<AgentSession>;
193
200
 
194
201
  export interface AcpSessionFactoryOptions {
@@ -199,7 +206,7 @@ export interface AcpSessionFactoryOptions {
199
206
  modelRegistry: ModelRegistry;
200
207
  parsedArgs: Pick<Args, "apiKey" | "default" | "model" | "mpreset" | "thinking">;
201
208
  rawArgs: string[];
202
- createSession: (options: CreateAgentSessionOptions) => Promise<CreateAgentSessionResult>;
209
+ createSession: CreateSessionForMain;
203
210
  }
204
211
 
205
212
  export async function applyStartupModelProfiles(args: {
@@ -221,8 +228,11 @@ export async function applyStartupModelProfiles(args: {
221
228
  // override it. startupModel covers the eager path; session.model covers the
222
229
  // deferred `--model <pattern>` path resolved inside createAgentSession.
223
230
  const explicitModel = args.parsedArgs.model ? (args.startupModel ?? args.session.model) : undefined;
224
-
225
231
  const defaultProfile = args.settings.get("modelProfile.default");
232
+ if (defaultProfile || args.parsedArgs.mpreset) {
233
+ await args.modelRegistry.refresh("online-if-uncached");
234
+ }
235
+
226
236
  if (defaultProfile) {
227
237
  await applyProfile(defaultProfile, false);
228
238
  }
@@ -263,19 +273,23 @@ export async function applyStartupModelProfilesOrExit(
263
273
  export function createAcpSessionFactory(args: AcpSessionFactoryOptions): AcpSessionFactory {
264
274
  return async cwd => {
265
275
  const nextSettings = await args.settings.cloneForCwd(cwd);
276
+ const hasStartupProfile = Boolean(nextSettings.get("modelProfile.default") || args.parsedArgs.mpreset);
266
277
  const nextSessionManager = SessionManager.create(cwd, args.sessionDir);
267
278
  const agentId = `acp:${nextSessionManager.getSessionId()}`;
268
- const { session: nextSession } = await args.createSession({
269
- ...args.baseOptions,
270
- cwd,
271
- sessionManager: nextSessionManager,
272
- settings: nextSettings,
273
- authStorage: args.authStorage,
274
- modelRegistry: args.modelRegistry,
275
- agentId,
276
- hasUI: false,
277
- enableMCP: false,
278
- });
279
+ const { session: nextSession } = await args.createSession(
280
+ {
281
+ ...args.baseOptions,
282
+ cwd,
283
+ sessionManager: nextSessionManager,
284
+ settings: nextSettings,
285
+ authStorage: args.authStorage,
286
+ modelRegistry: args.modelRegistry,
287
+ agentId,
288
+ hasUI: false,
289
+ enableMCP: false,
290
+ },
291
+ { skipPostCreateModelRefresh: hasStartupProfile },
292
+ );
279
293
  await applyStartupModelProfilesOrExit({
280
294
  session: nextSession,
281
295
  settings: nextSettings,
@@ -284,9 +298,7 @@ export function createAcpSessionFactory(args: AcpSessionFactoryOptions): AcpSess
284
298
  startupModel: args.baseOptions.model,
285
299
  startupThinkingLevel: args.baseOptions.thinkingLevel,
286
300
  });
287
- if (args.parsedArgs.apiKey && !args.baseOptions.model && nextSession.model) {
288
- args.authStorage.setRuntimeApiKey(nextSession.model.provider, args.parsedArgs.apiKey);
289
- }
301
+ applyCliRuntimeApiKeyOverride(args.authStorage, args.parsedArgs.apiKey, nextSession.model);
290
302
  applyExtensionFlagValues(nextSession, args.rawArgs);
291
303
  return nextSession;
292
304
  };
@@ -395,30 +407,28 @@ async function getChangelogForDisplay(parsed: Args): Promise<string | undefined>
395
407
  return undefined;
396
408
  }
397
409
 
398
- const lastVersion = settings.get("lastChangelogVersion");
399
- if (lastVersion === VERSION) {
400
- // Steady state: user already saw the current version's changelog. Skip the file read + parse.
410
+ const entries = getDisplayChangelogEntries();
411
+ if (entries.length === 0) {
401
412
  return undefined;
402
413
  }
403
414
 
404
- const entries = getDisplayChangelogEntries();
405
-
415
+ const lastVersion = settings.get("lastChangelogVersion");
406
416
  if (!lastVersion) {
407
- if (entries.length > 0) {
408
- settings.set("lastChangelogVersion", VERSION);
409
- await flushChangelogVersion();
410
- return getInstalledVersionChangelogEntry(entries, VERSION)?.content;
411
- }
412
- } else {
417
+ settings.set("lastChangelogVersion", VERSION);
418
+ await flushChangelogVersion();
419
+ return getInstalledVersionChangelogEntry(entries, VERSION)?.content;
420
+ }
421
+
422
+ if (lastVersion !== VERSION) {
413
423
  const newEntries = getNewEntries(entries, lastVersion);
424
+ settings.set("lastChangelogVersion", VERSION);
425
+ await flushChangelogVersion();
414
426
  if (newEntries.length > 0) {
415
- settings.set("lastChangelogVersion", VERSION);
416
- await flushChangelogVersion();
417
427
  return newEntries.map(e => e.content).join("\n\n");
418
428
  }
419
429
  }
420
430
 
421
- return undefined;
431
+ return getInstalledVersionChangelogEntry(entries, VERSION)?.content;
422
432
  }
423
433
 
424
434
  async function flushChangelogVersion(): Promise<void> {
@@ -504,8 +514,8 @@ export async function createSessionManager(
504
514
  }
505
515
  return manager;
506
516
  }
507
- // Default case (new session) returns undefined, SDK will create one
508
- return undefined;
517
+ const sessionDir = parsed.sessionDir ?? SessionManager.getDefaultSessionDir(cwd, activeSettings.getAgentDir());
518
+ return SessionManager.create(cwd, sessionDir);
509
519
  }
510
520
 
511
521
  async function maybeAutoChdir(parsed: Args): Promise<void> {
@@ -942,10 +952,51 @@ export async function runRootCommand(
942
952
  modelRegistry,
943
953
  settingsInstance,
944
954
  );
955
+ // Resolve the token-log dir lazily on the first chat-usage event: a fresh
956
+ // launch's session dir does not exist yet at this point (the SDK creates it),
957
+ // so eager resolution would miss it. Re-resolve when the SessionManager id
958
+ // changes mid-run (fork/new) so root turns keep landing in the SAME
959
+ // `<session>/token-logs` dir the task executor uses for subagent turns.
960
+ let rootTokenLogDir: string | undefined;
961
+ let rootTokenLogSessionId: string | undefined;
962
+ let rootTokenLogResolved = false;
963
+ let rootTokenTurn = 0;
964
+ const baseTelemetry = sessionOptions.telemetry;
965
+ sessionOptions.telemetry = {
966
+ ...(baseTelemetry ?? {}),
967
+ onChatUsage: async event => {
968
+ await baseTelemetry?.onChatUsage?.(event);
969
+ const currentSessionId = sessionManager?.getSessionId();
970
+ if (!rootTokenLogResolved || (currentSessionId && currentSessionId !== rootTokenLogSessionId)) {
971
+ rootTokenLogDir = await resolveTaskTokenLogDir(process.cwd(), sessionManager);
972
+ // Reset the per-session turn counter when the log dir moves to a new
973
+ // session so each session's log starts at turn 1.
974
+ if (rootTokenLogSessionId !== undefined && currentSessionId !== rootTokenLogSessionId) rootTokenTurn = 0;
975
+ rootTokenLogSessionId = currentSessionId;
976
+ rootTokenLogResolved = true;
977
+ }
978
+ if (!rootTokenLogDir) return;
979
+ rootTokenTurn += 1;
980
+ await persistTaskTokenLog(
981
+ taskTokenLogFromUsage(event.usage, {
982
+ subagentId: "root",
983
+ agent: event.agent?.name ?? "main",
984
+ // Monotonic 1-based sequence of persisted usage events for this
985
+ // session (event.stepNumber is 0-based and -1 for oneshot spans).
986
+ turn: rootTokenTurn,
987
+ at: new Date().toISOString(),
988
+ model: event.model,
989
+ cost: event.cost,
990
+ }),
991
+ { dir: rootTokenLogDir },
992
+ );
993
+ },
994
+ };
945
995
  sessionOptions.authStorage = authStorage;
946
996
  sessionOptions.modelRegistry = modelRegistry;
947
997
  sessionOptions.hasUI = isInteractive || mode === "rpc-ui";
948
998
  sessionOptions.settings = settingsInstance;
999
+ const hasRootStartupProfile = Boolean(settingsInstance.get("modelProfile.default") || parsedArgs.mpreset);
949
1000
 
950
1001
  // Research-mode (RLM) preset: augment session options before session creation.
951
1002
  deps.rlmPreset?.applyOptions(sessionOptions, settingsInstance);
@@ -958,18 +1009,19 @@ export async function runRootCommand(
958
1009
  );
959
1010
  process.exit(1);
960
1011
  }
961
- if (sessionOptions.model) {
962
- authStorage.setRuntimeApiKey(sessionOptions.model.provider, parsedArgs.apiKey);
963
- }
1012
+ applyCliRuntimeApiKeyOverride(authStorage, parsedArgs.apiKey, sessionOptions.model);
964
1013
  }
965
1014
 
966
1015
  const createAgentSessionImpl = deps.createAgentSession ?? createAgentSession;
967
- const createSession = async (options: CreateAgentSessionOptions): Promise<CreateAgentSessionResult> => {
1016
+ const createSession: CreateSessionForMain = async (options, context): Promise<CreateAgentSessionResult> => {
968
1017
  const result = await logger.time("createAgentSession", createAgentSessionImpl, options);
969
1018
  // Kick off background model discovery only after createAgentSession finishes its parallel
970
1019
  // discovery arms; running these concurrently contends for the event loop and stretches
971
- // every parallel arm by ~30ms.
972
- modelRegistry.refreshInBackground();
1020
+ // every parallel arm by ~30ms. Startup model profiles do their own foreground refresh
1021
+ // before activation so project-scoped defaults can resolve freshly discovered models.
1022
+ if (!context?.skipPostCreateModelRefresh) {
1023
+ modelRegistry.refreshInBackground();
1024
+ }
973
1025
  return result;
974
1026
  };
975
1027
 
@@ -986,11 +1038,11 @@ export async function runRootCommand(
986
1038
  });
987
1039
  await (deps.runAcpMode ?? (await import("./modes/acp")).runAcpMode)(createAcpSession);
988
1040
  } else {
989
- const { session, setToolUIContext, modelFallbackMessage, lspServers, mcpManager, eventBus } =
990
- await createSession(sessionOptions);
991
- if (parsedArgs.apiKey && !sessionOptions.model && session.model) {
992
- authStorage.setRuntimeApiKey(session.model.provider, parsedArgs.apiKey);
993
- }
1041
+ const { session, setToolUIContext, modelFallbackMessage, lspServers, mcpManager, eventBus } = await createSession(
1042
+ sessionOptions,
1043
+ { skipPostCreateModelRefresh: hasRootStartupProfile },
1044
+ );
1045
+ applyCliRuntimeApiKeyOverride(authStorage, parsedArgs.apiKey, session.model);
994
1046
 
995
1047
  // Research-mode (RLM) preset: hard tool-boundary assertion after the registry is assembled.
996
1048
  if (deps.rlmPreset?.onSessionCreated) {
@@ -1083,7 +1083,18 @@ async function resolveMemoryModel(options: {
1083
1083
  });
1084
1084
  if (resolved.model) return resolved.model;
1085
1085
  }
1086
- return session.model ?? modelRegistry.getAll()[0];
1086
+ if (session.model) return session.model;
1087
+ // No configured role and no active session model (e.g. background startup
1088
+ // before lazy model resolution): prefer the most recently used model over
1089
+ // raw registry order. `getAll()[0]` can be a retired model the provider
1090
+ // now rejects with 404, which permanently fails consolidation jobs.
1091
+ const allModels = modelRegistry.getAll();
1092
+ const usageOrder = session.settings.getStorage()?.getModelUsageOrder() ?? [];
1093
+ for (const usedKey of usageOrder) {
1094
+ const match = allModels.find(model => `${model.provider}/${model.id}` === usedKey);
1095
+ if (match) return match;
1096
+ }
1097
+ return allModels[0];
1087
1098
  }
1088
1099
 
1089
1100
  function loadMemoryConfig(settings: Settings): MemoryRuntimeConfig {