@nexrall/code-core 1.4.71 → 1.4.72

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 (125) hide show
  1. package/dist/agent/agentRegistry.d.ts.map +1 -1
  2. package/dist/agent/agentRegistry.js +28 -10
  3. package/dist/agent/agentTypes.d.ts.map +1 -1
  4. package/dist/agent/agentTypes.js +159 -48
  5. package/dist/agent/askOnce.d.ts.map +1 -1
  6. package/dist/agent/askOnce.js +14 -5
  7. package/dist/agent/backgroundAgents.d.ts.map +1 -1
  8. package/dist/agent/backgroundAgents.js +22 -8
  9. package/dist/agent/claimEvidence.d.ts.map +1 -1
  10. package/dist/agent/claimEvidence.js +2 -1
  11. package/dist/agent/compaction.d.ts.map +1 -1
  12. package/dist/agent/compaction.js +31 -10
  13. package/dist/agent/crossProcessLock.d.ts.map +1 -1
  14. package/dist/agent/crossProcessLock.js +14 -6
  15. package/dist/agent/editCompleteness.d.ts.map +1 -1
  16. package/dist/agent/fileLocks.d.ts.map +1 -1
  17. package/dist/agent/fileLocks.js +14 -5
  18. package/dist/agent/flaky.d.ts.map +1 -1
  19. package/dist/agent/hooks.d.ts.map +1 -1
  20. package/dist/agent/hooks.js +284 -75
  21. package/dist/agent/iterationPolicy.d.ts.map +1 -1
  22. package/dist/agent/iterationPolicy.js +26 -23
  23. package/dist/agent/lifecycleHost.d.ts.map +1 -1
  24. package/dist/agent/lifecycleHost.js +35 -11
  25. package/dist/agent/loop.d.ts +22 -4
  26. package/dist/agent/loop.d.ts.map +1 -1
  27. package/dist/agent/loop.js +223 -51
  28. package/dist/agent/memory.d.ts.map +1 -1
  29. package/dist/agent/memory.js +13 -7
  30. package/dist/agent/modelCatalogue.d.ts.map +1 -1
  31. package/dist/agent/modelCatalogue.js +4 -1
  32. package/dist/agent/nestedInstructions.d.ts +122 -0
  33. package/dist/agent/nestedInstructions.d.ts.map +1 -0
  34. package/dist/agent/nestedInstructions.js +696 -0
  35. package/dist/agent/peerRegistry.d.ts.map +1 -1
  36. package/dist/agent/peerRegistry.js +44 -6
  37. package/dist/agent/peerTransport.d.ts.map +1 -1
  38. package/dist/agent/peerTransport.js +18 -6
  39. package/dist/agent/planMode.d.ts.map +1 -1
  40. package/dist/agent/planMode.js +194 -41
  41. package/dist/agent/readDedupe.d.ts.map +1 -1
  42. package/dist/agent/readDedupe.js +3 -1
  43. package/dist/agent/securityLint.d.ts.map +1 -1
  44. package/dist/agent/sharedTasks.d.ts.map +1 -1
  45. package/dist/agent/sharedTasks.js +20 -5
  46. package/dist/agent/skills.d.ts +79 -0
  47. package/dist/agent/skills.d.ts.map +1 -1
  48. package/dist/agent/skills.js +403 -14
  49. package/dist/agent/subAgentBudget.d.ts.map +1 -1
  50. package/dist/agent/subTask.d.ts.map +1 -1
  51. package/dist/agent/subTask.js +87 -37
  52. package/dist/agent/subTaskSupport.d.ts.map +1 -1
  53. package/dist/agent/subTaskSupport.js +43 -14
  54. package/dist/agent/testIntegrity.d.ts.map +1 -1
  55. package/dist/agent/testIntegrity.js +4 -2
  56. package/dist/agent/toolDescriptions.d.ts.map +1 -1
  57. package/dist/agent/toolPrefetch.d.ts.map +1 -1
  58. package/dist/agent/toolPrefetch.js +15 -11
  59. package/dist/agent/trust.d.ts.map +1 -1
  60. package/dist/agent/trust.js +6 -2
  61. package/dist/agent/worktree.d.ts.map +1 -1
  62. package/dist/agent/worktree.js +70 -16
  63. package/dist/agent/worktreeEnforcement.d.ts.map +1 -1
  64. package/dist/agent/worktreeEnforcement.js +9 -4
  65. package/dist/api/client.d.ts.map +1 -1
  66. package/dist/api/client.js +63 -31
  67. package/dist/auth/index.d.ts.map +1 -1
  68. package/dist/auth/index.js +3 -1
  69. package/dist/checkpoint/manager.d.ts.map +1 -1
  70. package/dist/checkpoint/manager.js +22 -7
  71. package/dist/commands/loader.d.ts.map +1 -1
  72. package/dist/commands/loader.js +6 -1
  73. package/dist/index.d.ts +2 -0
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +2 -0
  76. package/dist/mcp/client.d.ts +34 -0
  77. package/dist/mcp/client.d.ts.map +1 -1
  78. package/dist/mcp/client.js +89 -24
  79. package/dist/mcp/httpClient.d.ts +24 -1
  80. package/dist/mcp/httpClient.d.ts.map +1 -1
  81. package/dist/mcp/httpClient.js +80 -14
  82. package/dist/mcp/instructions.d.ts +11 -0
  83. package/dist/mcp/instructions.d.ts.map +1 -0
  84. package/dist/mcp/instructions.js +42 -0
  85. package/dist/mcp/manager.d.ts +24 -0
  86. package/dist/mcp/manager.d.ts.map +1 -1
  87. package/dist/mcp/manager.js +117 -24
  88. package/dist/mcp/server.d.ts.map +1 -1
  89. package/dist/mcp/server.js +48 -14
  90. package/dist/mcp/sseClient.d.ts +9 -1
  91. package/dist/mcp/sseClient.d.ts.map +1 -1
  92. package/dist/mcp/sseClient.js +43 -10
  93. package/dist/mcp/stats.d.ts.map +1 -1
  94. package/dist/permissions/bashClassify.d.ts.map +1 -1
  95. package/dist/permissions/bashClassify.js +25 -3
  96. package/dist/permissions/destructive.d.ts.map +1 -1
  97. package/dist/permissions/destructive.js +7 -2
  98. package/dist/permissions/destructiveTokens.d.ts.map +1 -1
  99. package/dist/permissions/destructiveTokens.js +104 -24
  100. package/dist/permissions/modePolicy.d.ts.map +1 -1
  101. package/dist/permissions/modePolicy.js +40 -17
  102. package/dist/permissions/rules.d.ts.map +1 -1
  103. package/dist/permissions/rules.js +7 -5
  104. package/dist/plugins/data.d.ts.map +1 -1
  105. package/dist/plugins/data.js +6 -2
  106. package/dist/plugins/index.d.ts.map +1 -1
  107. package/dist/plugins/index.js +18 -7
  108. package/dist/plugins/installer.d.ts.map +1 -1
  109. package/dist/plugins/installer.js +17 -10
  110. package/dist/plugins/sources.d.ts.map +1 -1
  111. package/dist/plugins/sources.js +9 -3
  112. package/dist/tools/executor.d.ts.map +1 -1
  113. package/dist/tools/executor.js +454 -168
  114. package/dist/tools/sandbox.d.ts.map +1 -1
  115. package/dist/tools/sandbox.js +5 -1
  116. package/dist/tools/symbols.d.ts.map +1 -1
  117. package/dist/tools/symbols.js +30 -8
  118. package/dist/tools/tsLangService.d.ts.map +1 -1
  119. package/dist/tools/tsLangService.js +12 -4
  120. package/dist/types.d.ts +17 -0
  121. package/dist/types.d.ts.map +1 -1
  122. package/dist/util/frontmatter.d.ts.map +1 -1
  123. package/dist/util/miniYaml.d.ts.map +1 -1
  124. package/dist/util/miniYaml.js +3 -1
  125. package/package.json +1 -1
@@ -5,6 +5,7 @@ exports.lastToolResults = exports.summariseSubTaskProgress = exports.capSubTaskT
5
5
  exports.dispatchSubAgent = dispatchSubAgent;
6
6
  exports.dispatchBackgroundSubAgent = dispatchBackgroundSubAgent;
7
7
  exports.dispatchForkedSubAgent = dispatchForkedSubAgent;
8
+ exports.runForkedSkill = runForkedSkill;
8
9
  exports.runAgentLoop = runAgentLoop;
9
10
  exports.trimToResumableBoundary = trimToResumableBoundary;
10
11
  const readDedupe_1 = require("./readDedupe");
@@ -16,6 +17,7 @@ const executor_1 = require("../tools/executor");
16
17
  const sharedTasks_1 = require("./sharedTasks");
17
18
  const agentTypes_1 = require("./agentTypes");
18
19
  const skills_1 = require("./skills");
20
+ const nestedInstructions_1 = require("./nestedInstructions");
19
21
  const rules_1 = require("../permissions/rules");
20
22
  const modePolicy_1 = require("../permissions/modePolicy");
21
23
  const destructive_1 = require("../permissions/destructive");
@@ -25,6 +27,7 @@ const destructive_1 = require("../permissions/destructive");
25
27
  const bashClassify_1 = require("../permissions/bashClassify");
26
28
  Object.defineProperty(exports, "bashNeedsRepoLock", { enumerable: true, get: function () { return bashClassify_1.bashNeedsRepoLock; } });
27
29
  const planMode_1 = require("./planMode");
30
+ const instructions_1 = require("../mcp/instructions");
28
31
  const worktreeEnforcement_1 = require("./worktreeEnforcement");
29
32
  const sandbox_1 = require("../tools/sandbox");
30
33
  const testIntegrity_1 = require("./testIntegrity");
@@ -235,8 +238,11 @@ function dispatchBackgroundSubAgent(input, options, agentTypes, hub) {
235
238
  if (overBudget)
236
239
  return { error: overBudget };
237
240
  const agentType = (typeof input.subagent_type === 'string' && input.subagent_type) || 'general-purpose';
238
- const description = (typeof input.description === 'string' && input.description.trim())
239
- || String(input.prompt ?? '').trim().slice(0, 60) || agentType;
241
+ const description = (typeof input.description === 'string' && input.description.trim()) ||
242
+ String(input.prompt ?? '')
243
+ .trim()
244
+ .slice(0, 60) ||
245
+ agentType;
240
246
  const mode = (0, modePolicy_1.parseMode)(options.mode);
241
247
  const backgroundPermission = backgroundPermissionPolicy(options, mode);
242
248
  const started = hub.start({ description, agentType }, async ({ abort, onToolUse }) => {
@@ -344,6 +350,59 @@ function dispatchForkedSubAgent(conversation, prompt, options, agentTypes, hub)
344
350
  }
345
351
  return { id: started.id, description, agentType, messages: conversation.length };
346
352
  }
353
+ /**
354
+ * Resolve the skill a `use_skill` call names, returning it ONLY if it runs as a
355
+ * fork (`context: 'fork'`) — the signal `runAgentLoop` uses to divert the call
356
+ * away from the inline-injection path and into the sub-agent machinery.
357
+ *
358
+ * The snapshot is the list the catalogue was built from (loaded once per run);
359
+ * a MISS reloads from disk so a skill created mid-turn is found — the same
360
+ * trade-off `runSubTask` documents for `agentTypes`.
361
+ */
362
+ function resolveForkSkill(skills, input, options) {
363
+ const name = typeof input.name === 'string' ? input.name.trim() : '';
364
+ if (!name)
365
+ return undefined;
366
+ const skill = (0, skills_1.findSkill)(skills, name) ??
367
+ (0, skills_1.resolveNestedSkill)(options.workDir, name) ?? // `<dir>:<name>` - see skills.ts
368
+ (0, skills_1.findSkill)((0, skills_1.loadSkillsWithWarnings)(options.workDir, options._extraSkills ?? []).skills, name);
369
+ return skill?.context === 'fork' ? skill : undefined;
370
+ }
371
+ /**
372
+ * Run a `context: fork` skill as an ISOLATED sub-agent (Claude Code parity):
373
+ * the expanded body is the child's prompt and the parent conversation is NOT
374
+ * copied in — a forked skill must stand on its own, which is the point of the
375
+ * fork (the invoking context stays clean and the child cannot lean on it).
376
+ *
377
+ * Background by default (CC 2.1.x), exactly like `task(run_in_background)`: the
378
+ * call returns as soon as the child starts and the report arrives later as a
379
+ * <task-notification>; `background: false` awaits the child and returns its
380
+ * report as the tool result. Hosts with no hub (headless `-p`/SDK callers)
381
+ * always await — the same place CC waits regardless of the frontmatter.
382
+ *
383
+ * The `subagent_type` rides the ordinary `task` dispatch, so `deny:
384
+ * ["task(<name>)"]` rules, the depth limit and the session sub-agent budget all
385
+ * apply unchanged (see runSubTask / dispatchSubAgent).
386
+ */
387
+ async function runForkedSkill(skill, args, options, agentTypes) {
388
+ const workDir = options.workDir ?? process.cwd();
389
+ const input = {
390
+ prompt: (0, skills_1.expandSkill)(skill, args, workDir),
391
+ description: `/${skill.name}`,
392
+ subagent_type: skill.agent?.trim() || 'general-purpose',
393
+ };
394
+ // `model:` on the skill applies to the fork exactly as it does when the skill is
395
+ // typed as a turn (`/name` in chat.ts): the child starts on that model. A model
396
+ // the agent TYPE declares still wins — the child resolves it over ours, same as
397
+ // any `task` call (see subTask.ts).
398
+ const childOptions = skill.model ? { ...options, model: (0, modelCatalogue_1.resolveSubAgentModel)(skill.model, options.model) } : options;
399
+ const depth = options._depth ?? 0;
400
+ const wantsBackground = skill.background !== false && depth === 0;
401
+ if (wantsBackground && childOptions.backgroundAgents) {
402
+ return dispatchBackgroundSubAgent(input, childOptions, agentTypes, childOptions.backgroundAgents);
403
+ }
404
+ return dispatchSubAgent(input, childOptions, agentTypes);
405
+ }
347
406
  // ─── Agent Loop ───────────────────────────────────────────────────────────────
348
407
  async function runAgentLoop(initialMessages, options) {
349
408
  const messages = [...initialMessages];
@@ -400,7 +459,10 @@ async function runAgentLoop(initialMessages, options) {
400
459
  const addContext = (ctx) => {
401
460
  const m = messages[lastIdx];
402
461
  if (m && Array.isArray(m.content))
403
- messages[lastIdx] = { ...m, content: [...m.content, { type: 'text', text: `\n\n<hook-context>\n${ctx}\n</hook-context>` }] };
462
+ messages[lastIdx] = {
463
+ ...m,
464
+ content: [...m.content, { type: 'text', text: `\n\n<hook-context>\n${ctx}\n</hook-context>` }],
465
+ };
404
466
  };
405
467
  const sid = options.sessionId || subAgentBudget_1.PROCESS_BUDGET_KEY;
406
468
  if (isPrompt && !_sessionStarted.has(sid) && (hooks.SessionStart?.length ?? 0) > 0) {
@@ -436,7 +498,9 @@ async function runAgentLoop(initialMessages, options) {
436
498
  // the user request that caused it belong to the same run — which is precisely
437
499
  // the chain of custody the trail exists to prove.
438
500
  const auditCfg = options.audit
439
- ? (options.audit.sessionId ? options.audit : { ...options.audit, sessionId: (0, audit_1.newAuditSessionId)() })
501
+ ? options.audit.sessionId
502
+ ? options.audit
503
+ : { ...options.audit, sessionId: (0, audit_1.newAuditSessionId)() }
440
504
  : undefined;
441
505
  const auditCtx = auditCfg
442
506
  ? {
@@ -479,7 +543,24 @@ async function runAgentLoop(initialMessages, options) {
479
543
  // just a reusable prompt template (via use_skill), not another spawn point, so
480
544
  // sub-agents benefit from the same playbooks without the recursion concerns that
481
545
  // gate agentsCatalogue to the top level.
482
- const skillsCatalogue = (0, skills_1.summariseSkills)((0, skills_1.loadSkillsWithWarnings)(options.workDir, options._extraSkills ?? []).skills);
546
+ const skillsList = (0, skills_1.loadSkillsWithWarnings)(options.workDir, options._extraSkills ?? []).skills;
547
+ // Nested-skill discovery (CC 2.1.x parity): as tool calls touch files, their
548
+ // directories get checked for their own `.nexrall/skills`, and anything found is
549
+ // addressed as `<dir>:<name>` (see skills.ts). The catalogue below is rebuilt
550
+ // PER REQUEST precisely so a discovery mid-turn reaches the model on its next
551
+ // round-trip without a new user message; resolutions go through findSkill /
552
+ // resolveNestedSkill, so a scoped name works even before its turn advertises it.
553
+ const nestedSkillScan = options.workDir ? new skills_1.NestedSkillScanner(options.workDir) : null;
554
+ // Nested instruction files (S18c): a subdirectory's `nexrall.md` applies once the
555
+ // agent works there — the same 2.1.x behaviour as the nested skills above, and the
556
+ // same per-request composition (the prompt reads the ledger's list() every call).
557
+ // The HOST normally owns the ledger: one scanner per session, passed to every run,
558
+ // because a loaded file must not silently vanish between turns. A host that passes
559
+ // nothing gets run-scoped discovery — the right lifetime for a one-shot run. `false`
560
+ // disables the feature entirely (`--bare`: no discovery).
561
+ const nestedInstructionScan = options._nestedInstructions === false
562
+ ? null
563
+ : (options._nestedInstructions ?? (options.workDir ? new nestedInstructions_1.NestedInstructionScanner(options.workDir) : null));
483
564
  // Plan mode instructions ride the project-instructions channel, which is
484
565
  // authoritative in the system prompt. Prepended rather than appended: the
485
566
  // lock has to be read before the project conventions it overrides.
@@ -491,7 +572,15 @@ async function runAgentLoop(initialMessages, options) {
491
572
  options.planMode ? planMode_1.PLAN_MODE_INSTRUCTIONS : null,
492
573
  options.worktree ? (0, worktreeEnforcement_1.worktreeInstructions)(options.worktree) : null,
493
574
  options.nexrallMd ?? null,
494
- ].filter((s) => s !== null).join('\n\n---\n\n') || undefined; // '' (nothing at all was present) must behave exactly like the old `: options.nexrallMd` fallback (undefined), not an empty-but-truthy string.
575
+ ]
576
+ .filter((s) => s !== null)
577
+ .join('\n\n---\n\n') || undefined; // '' (nothing at all was present) must behave exactly like the old `: options.nexrallMd` fallback (undefined), not an empty-but-truthy string.
578
+ // MCP `initialize.instructions` — a server's own reference notes. Composed PER
579
+ // REQUEST so a server that connects (or is enabled) mid-session contributes
580
+ // without the caller rebuilding the session brief; a sub-agent only reads the
581
+ // servers its allowlist names (another server's notes are not its business).
582
+ // The size caps live in mcp/instructions.ts.
583
+ const mcpInstructionsBlock = () => (0, instructions_1.formatMcpInstructions)((options.mcpManager?.serverInstructions() ?? []).filter((e) => !options._mcpServerAllowlist || options._mcpServerAllowlist.has(e.server)));
495
584
  // The request options every main-loop call sends. Shared with the compaction
496
585
  // summariser so its request has the SAME system prompt and tools as the conversation
497
586
  // — that is what lets the summary call read the whole history from cache (0.10×)
@@ -502,7 +591,13 @@ async function runAgentLoop(initialMessages, options) {
502
591
  effort: options.effort,
503
592
  env: options.env,
504
593
  editorContext: options.editorContext,
505
- nexrallMd: planAndWorktreeAwareNexrallMd,
594
+ nexrallMd: [
595
+ planAndWorktreeAwareNexrallMd,
596
+ (0, nestedInstructions_1.formatNestedInstructions)(nestedInstructionScan?.list() ?? []),
597
+ mcpInstructionsBlock(),
598
+ ]
599
+ .filter((s) => !!s)
600
+ .join('\n\n---\n\n') || undefined,
506
601
  clientType: options.clientType,
507
602
  abortSignal: options.abortSignal,
508
603
  // MCP tools, plus the per-agent memory tool when (and only when) this run
@@ -511,8 +606,7 @@ async function runAgentLoop(initialMessages, options) {
511
606
  // to every other run: a tool the model cannot see is one it cannot try,
512
607
  // which is better than advertising it everywhere and refusing it at the gate.
513
608
  extraTools: [
514
- ...(options.mcpManager?.getAnthropicTools() ?? [])
515
- .filter((t) => !options._mcpServerAllowlist || options._mcpServerAllowlist.has(String(t.name).split('__')[0])),
609
+ ...(options.mcpManager?.getAnthropicTools() ?? []).filter((t) => !options._mcpServerAllowlist || options._mcpServerAllowlist.has(String(t.name).split('__')[0])),
516
610
  ...(options._agentMemory ? [iterationPolicy_1.AGENT_MEMORY_TOOL_SCHEMA] : []),
517
611
  ...(options.extraToolSchemas ?? []),
518
612
  ],
@@ -522,11 +616,7 @@ async function runAgentLoop(initialMessages, options) {
522
616
  // memory_write, which no sub-agent allowlist contains.
523
617
  // Sub-agents NEVER write the shared store (the main agent decides what to persist) —
524
618
  // an unnamed/general-purpose child has no allowlist, which used to read as "may write".
525
- canWriteSharedMemory: depth > 0
526
- ? false
527
- : options._allowedTools
528
- ? options._allowedTools.has('memory_write')
529
- : true, // no allowlist = main agent = may write
619
+ canWriteSharedMemory: depth > 0 ? false : options._allowedTools ? options._allowedTools.has('memory_write') : true, // no allowlist = main agent = may write
530
620
  hasOwnAgentStore: !!options._agentMemory,
531
621
  // Same derivation, same reason, for the network. The base prompt's
532
622
  // "Web search" section tells the run to reach the network, but
@@ -547,7 +637,7 @@ async function runAgentLoop(initialMessages, options) {
547
637
  // delegate — see canSpawnSubAgents.
548
638
  canSpawnSubAgents: maySpawn,
549
639
  agents: agentsCatalogue || undefined,
550
- skills: skillsCatalogue || undefined,
640
+ skills: (0, skills_1.summariseSkills)(skillsList) || undefined,
551
641
  });
552
642
  // Optional OS-level bash sandbox (opt-in via settings.json "sandbox").
553
643
  const sandboxCfg = (0, sandbox_1.parseSandboxConfig)(settings.raw.sandbox) ?? undefined;
@@ -563,7 +653,7 @@ async function runAgentLoop(initialMessages, options) {
563
653
  // Per-run: a sub-agent's own runAgentLoop gets its own, so it never sees its parent's reads.
564
654
  const readDedupe = new readDedupe_1.ReadDedupe(options.workDir);
565
655
  // Only the main agent owns background agents (runSubTask never passes the hub down).
566
- const drainBackgroundNotifications = () => depth === 0 ? (options.backgroundAgents?.takeNotifications() ?? []) : [];
656
+ const drainBackgroundNotifications = () => (depth === 0 ? (options.backgroundAgents?.takeNotifications() ?? []) : []);
567
657
  // Live prompt-size estimate, updated from usage events after every stream.
568
658
  let lastPromptTokens = 0;
569
659
  let compacting = false; // re-entrancy guard — compaction itself calls streamChat
@@ -734,7 +824,11 @@ async function runAgentLoop(initialMessages, options) {
734
824
  compactDisabled = false;
735
825
  compactFailures = 0;
736
826
  }
737
- if (autoCompact && !compactDisabled && !compacting && (tokenPressure || bytePressure) && messages.length > compaction_1.COMPACT_KEEP_MIN + 2) {
827
+ if (autoCompact &&
828
+ !compactDisabled &&
829
+ !compacting &&
830
+ (tokenPressure || bytePressure) &&
831
+ messages.length > compaction_1.COMPACT_KEEP_MIN + 2) {
738
832
  compacting = true;
739
833
  try {
740
834
  // Measured BEFORE, so "did it actually help?" is a fact about bytes rather
@@ -759,9 +853,7 @@ async function runAgentLoop(initialMessages, options) {
759
853
  const reclaimed = bytesBefore - bytesAfter;
760
854
  if (did) {
761
855
  lastPromptTokens = 0; // stale — next usage event refreshes it
762
- const reason = bytePressure
763
- ? `body ~${(bodyBytes / (1024 * 1024)).toFixed(1)}MB`
764
- : 'context window';
856
+ const reason = bytePressure ? `body ~${(bodyBytes / (1024 * 1024)).toFixed(1)}MB` : 'context window';
765
857
  // Silent, same as the prune above — routine housekeeping. Only the
766
858
  // actionable "auto-compaction paused" warning below is surfaced.
767
859
  void reason;
@@ -1091,8 +1183,8 @@ async function runAgentLoop(initialMessages, options) {
1091
1183
  // be an example here too — as of the 2026-08-11+ provider-agnostic port it is a
1092
1184
  // plain client tool executed by THIS process, so it no longer belongs in this set.)
1093
1185
  const serverSideResultIds = new Set(assistantMessage.content
1094
- .filter(b => b.type === 'tool_result')
1095
- .map(b => b.tool_use_id)
1186
+ .filter((b) => b.type === 'tool_result')
1187
+ .map((b) => b.tool_use_id)
1096
1188
  .filter((id) => !!id));
1097
1189
  const toolUseBlocks = assistantMessage.content.filter((block) => block.type === 'tool_use' && !serverSideResultIds.has(block.id));
1098
1190
  // ─── TRUNCATED-TOOL-CALL GUARD ──────────────────────────────────────────
@@ -1117,9 +1209,7 @@ async function runAgentLoop(initialMessages, options) {
1117
1209
  // model retries with a smaller call, rather than either failing
1118
1210
  // mysteriously or silently mutating a file incompletely.
1119
1211
  const lastBlock = assistantMessage.content[assistantMessage.content.length - 1];
1120
- const truncatedToolUseId = assistantMessage.stopReason === 'max_tokens' && lastBlock?.type === 'tool_use'
1121
- ? lastBlock.id
1122
- : undefined;
1212
+ const truncatedToolUseId = assistantMessage.stopReason === 'max_tokens' && lastBlock?.type === 'tool_use' ? lastBlock.id : undefined;
1123
1213
  // 4. If no tool use → agent produced a final text response.
1124
1214
  // But if the user queued a follow-up while we were working, fold it in as the
1125
1215
  // next user turn and keep going instead of ending (Claude-Code style).
@@ -1170,7 +1260,8 @@ async function runAgentLoop(initialMessages, options) {
1170
1260
  const bullet = fresh.map((t) => ` • ${t.path}: ${t.reason}`).join('\n');
1171
1261
  messages.push({
1172
1262
  role: 'user',
1173
- content: [{
1263
+ content: [
1264
+ {
1174
1265
  type: 'text',
1175
1266
  text: 'STOP — test-integrity check. Before finishing, I detected that you WEAKENED test(s) this session:\n' +
1176
1267
  bullet +
@@ -1178,7 +1269,8 @@ async function runAgentLoop(initialMessages, options) {
1178
1269
  ' 1. Revert the weakening and fix the actual code so the ORIGINAL test passes, or\n' +
1179
1270
  ' 2. Justify concretely why the change is a legitimate test refactor (e.g. the behaviour was intentionally removed per the task, a duplicate test, or the assertion was genuinely wrong) — and confirm the remaining tests still meaningfully cover the behaviour.\n' +
1180
1271
  'Then re-run the test suite to prove it passes for real.',
1181
- }],
1272
+ },
1273
+ ],
1182
1274
  });
1183
1275
  continue;
1184
1276
  }
@@ -1191,15 +1283,19 @@ async function runAgentLoop(initialMessages, options) {
1191
1283
  if (flaky.length) {
1192
1284
  for (const f of flaky)
1193
1285
  flakyNudgedCmds.add(f.cmd);
1194
- const bullet = flaky.map((f) => ` • ${f.cmd} (${f.passes} pass / ${f.fails} fail on identical code)`).join('\n');
1286
+ const bullet = flaky
1287
+ .map((f) => ` • ${f.cmd} (${f.passes} pass / ${f.fails} fail on identical code)`)
1288
+ .join('\n');
1195
1289
  messages.push({
1196
1290
  role: 'user',
1197
- content: [{
1291
+ content: [
1292
+ {
1198
1293
  type: 'text',
1199
1294
  text: 'STOP — flaky-test check. These command(s) produced BOTH a pass and a fail with NO code change in between, so they are non-deterministic:\n' +
1200
1295
  bullet +
1201
1296
  '\n\nA green run of a flaky test proves nothing, and re-running until it passes is not a fix. Do NOT declare success on this basis. Instead: identify the source of non-determinism (unseeded RNG, timing/sleep races, test-ordering or shared-state dependence, wall-clock/timezone, network) and make the test deterministic — or, if it is out of scope, say so explicitly and flag it as pre-existing flakiness rather than treating the passing run as proof.',
1202
- }],
1297
+ },
1298
+ ],
1203
1299
  });
1204
1300
  continue;
1205
1301
  }
@@ -1213,10 +1309,12 @@ async function runAgentLoop(initialMessages, options) {
1213
1309
  verificationNudgeSent = true;
1214
1310
  messages.push({
1215
1311
  role: 'user',
1216
- content: [{
1312
+ content: [
1313
+ {
1217
1314
  type: 'text',
1218
- text: 'Before finishing: you edited file(s) in this task but I don\'t see a build/test/lint/typecheck command run to confirm the change works. If this project has one, please run it now and fix any failures. If verification genuinely doesn\'t apply here (e.g. docs-only change, no test suite), just say so and finish.',
1219
- }],
1315
+ text: "Before finishing: you edited file(s) in this task but I don't see a build/test/lint/typecheck command run to confirm the change works. If this project has one, please run it now and fix any failures. If verification genuinely doesn't apply here (e.g. docs-only change, no test suite), just say so and finish.",
1316
+ },
1317
+ ],
1220
1318
  });
1221
1319
  continue;
1222
1320
  }
@@ -1358,6 +1456,11 @@ async function runAgentLoop(initialMessages, options) {
1358
1456
  if (err instanceof subTaskSupport_1.ToolNotAllowedError)
1359
1457
  deniedReason = err.message;
1360
1458
  }
1459
+ // `context: fork` skills never reach the executor's inline injection: the
1460
+ // call is diverted into the same sub-agent machinery `task` uses, with the
1461
+ // expanded body as the child's prompt (see runForkedSkill). Resolved here —
1462
+ // only for an allowed `use_skill` — so a denied call pays nothing for it.
1463
+ const forkSkill = permitted && name === 'use_skill' ? resolveForkSkill(skillsList, input, options) : undefined;
1361
1464
  if (!permitted) {
1362
1465
  result = { error: deniedReason ?? 'Permission denied by user' };
1363
1466
  }
@@ -1373,8 +1476,9 @@ async function runAgentLoop(initialMessages, options) {
1373
1476
  // reimplementing depth/budget/concurrency enforcement a second time.
1374
1477
  // Background only for the MAIN agent, and only when the host can deliver the
1375
1478
  // result later; otherwise it quietly runs in the foreground.
1376
- const wantsBackground = input.run_in_background === true
1377
- || (input.run_in_background !== false && !!(0, agentTypes_1.findAgentType)(agentTypes, String(input.subagent_type ?? ''))?.background);
1479
+ const wantsBackground = input.run_in_background === true ||
1480
+ (input.run_in_background !== false &&
1481
+ !!(0, agentTypes_1.findAgentType)(agentTypes, String(input.subagent_type ?? ''))?.background);
1378
1482
  const taskOptions = { ...auditOptions, _taskToolUseId: id };
1379
1483
  // PreToolUse/PostToolUse cover spawns too (Claude Code's matcher "Task"/"Agent"
1380
1484
  // works the same way): a hook can veto a delegation or audit what came back.
@@ -1383,9 +1487,10 @@ async function runAgentLoop(initialMessages, options) {
1383
1487
  result = { error: `Blocked by PreToolUse hook: ${preTask.reason}` };
1384
1488
  }
1385
1489
  else {
1386
- result = wantsBackground && depth === 0 && options.backgroundAgents && !input.resume_agent_id
1387
- ? dispatchBackgroundSubAgent(input, taskOptions, agentTypes, options.backgroundAgents)
1388
- : await dispatchSubAgent(input, taskOptions, agentTypes);
1490
+ result =
1491
+ wantsBackground && depth === 0 && options.backgroundAgents && !input.resume_agent_id
1492
+ ? dispatchBackgroundSubAgent(input, taskOptions, agentTypes, options.backgroundAgents)
1493
+ : await dispatchSubAgent(input, taskOptions, agentTypes);
1389
1494
  const postTask = await (0, hooks_1.runToolHooks)(hooks.PostToolUse, 'PostToolUse', name, input, options.workDir, result, (0, hooks_1.hookRunOptsFor)(options));
1390
1495
  const injectedTask = [preTask.context, postTask.context].filter(Boolean).join('\n');
1391
1496
  if (injectedTask) {
@@ -1399,6 +1504,28 @@ async function runAgentLoop(initialMessages, options) {
1399
1504
  }
1400
1505
  }
1401
1506
  }
1507
+ else if (forkSkill) {
1508
+ // `use_skill` on a `context: fork` skill — the same hook pair as any call,
1509
+ // so a Pre can veto the fork and a Post sees its start/report.
1510
+ const preFork = await (0, hooks_1.runToolHooks)(hooks.PreToolUse, 'PreToolUse', name, input, options.workDir, undefined, (0, hooks_1.hookRunOptsFor)(options));
1511
+ if (preFork.block) {
1512
+ result = { error: `Blocked by PreToolUse hook: ${preFork.reason}` };
1513
+ }
1514
+ else {
1515
+ result = await runForkedSkill(forkSkill, typeof input.args === 'string' ? input.args : '', { ...auditOptions, _taskToolUseId: id }, agentTypes);
1516
+ const postFork = await (0, hooks_1.runToolHooks)(hooks.PostToolUse, 'PostToolUse', name, input, options.workDir, result, (0, hooks_1.hookRunOptsFor)(options));
1517
+ const injectedFork = [preFork.context, postFork.context].filter(Boolean).join('\n');
1518
+ if (injectedFork) {
1519
+ if (result.error !== undefined)
1520
+ result.error = `${result.error}\n\n[hook] ${injectedFork}`;
1521
+ else
1522
+ result.output = `${result.output ?? ''}\n\n[hook] ${injectedFork}`;
1523
+ }
1524
+ if (postFork.block) {
1525
+ result.error = `${result.error ? result.error + '\n' : ''}PostToolUse hook flagged: ${postFork.reason}`;
1526
+ }
1527
+ }
1528
+ }
1402
1529
  else {
1403
1530
  const pre = await (0, hooks_1.runToolHooks)(hooks.PreToolUse, 'PreToolUse', name, input, options.workDir, undefined, (0, hooks_1.hookRunOptsFor)(options));
1404
1531
  if (pre.block) {
@@ -1407,9 +1534,7 @@ async function runAgentLoop(initialMessages, options) {
1407
1534
  else {
1408
1535
  // TaskCreated needs the id of the task the tool is ABOUT to create, which only
1409
1536
  // the tool can know — so snapshot the ids first and diff afterwards (see below).
1410
- const taskIdsBefore = name === 'create_shared_task'
1411
- ? new Set((0, sharedTasks_1.listSharedTasks)(options.workDir).map((t) => t.id))
1412
- : null;
1537
+ const taskIdsBefore = name === 'create_shared_task' ? new Set((0, sharedTasks_1.listSharedTasks)(options.workDir).map((t) => t.id)) : null;
1413
1538
  try {
1414
1539
  // TaskCompleted (Claude Code): the hook is the GATE, so it runs BEFORE the
1415
1540
  // update — refusing means the task simply stays open, and the reason goes
@@ -1445,9 +1570,10 @@ async function runAgentLoop(initialMessages, options) {
1445
1570
  }
1446
1571
  else if (options.mcpManager?.isMcpTool(name)) {
1447
1572
  const mcpOutput = await (0, subTaskSupport_1.stopAwaiting)(options.mcpManager.callTool(name, input, options.abortSignal), options.abortSignal);
1448
- result = mcpOutput === subTaskSupport_1.STOP_TIMEOUT_RESULT
1449
- ? subTaskSupport_1.STOP_TIMEOUT_RESULT
1450
- : { output: (0, executor_1.capExternalOutput)(mcpOutput ?? '', `mcp-${name}`) };
1573
+ result =
1574
+ mcpOutput === subTaskSupport_1.STOP_TIMEOUT_RESULT
1575
+ ? subTaskSupport_1.STOP_TIMEOUT_RESULT
1576
+ : { output: (0, executor_1.capExternalOutput)(mcpOutput ?? '', `mcp-${name}`) };
1451
1577
  // 3. Fall through to built-in executor
1452
1578
  }
1453
1579
  else {
@@ -1472,7 +1598,9 @@ async function runAgentLoop(initialMessages, options) {
1472
1598
  // This matters far more with sub-agents than without: up to 4 run
1473
1599
  // concurrently, each issuing its own tool calls into this same process.
1474
1600
  const locks = name === 'bash'
1475
- ? ((0, bashClassify_1.bashNeedsRepoLock)(String(input.command ?? '')) ? [fileLocks_1.REPO_STATE_LOCK] : [])
1601
+ ? (0, bashClassify_1.bashNeedsRepoLock)(String(input.command ?? ''))
1602
+ ? [fileLocks_1.REPO_STATE_LOCK]
1603
+ : []
1476
1604
  : (0, fileLocks_1.lockPathsFor)(name, input, options.workDir);
1477
1605
  // Two lock layers, nested outer-then-inner:
1478
1606
  // 1. Cross-process (OS lock file) — the ONLY layer that protects
@@ -1523,7 +1651,9 @@ async function runAgentLoop(initialMessages, options) {
1523
1651
  const task = created[created.length - 1];
1524
1652
  if (task) {
1525
1653
  const veto = await taskHookVeto(hooks.TaskCreated, 'TaskCreated', input, options, {
1526
- task_id: task.id, task_subject: task.content, task_description: task.content,
1654
+ task_id: task.id,
1655
+ task_subject: task.content,
1656
+ task_description: task.content,
1527
1657
  });
1528
1658
  if (veto) {
1529
1659
  (0, sharedTasks_1.deleteSharedTask)(options.workDir, task.id);
@@ -1531,6 +1661,35 @@ async function runAgentLoop(initialMessages, options) {
1531
1661
  }
1532
1662
  }
1533
1663
  }
1664
+ // Nested-skill discovery: whatever this call touched is where the model
1665
+ // is working, so those directories' own `.nexrall/skills` now matter.
1666
+ // Runs regardless of success - a failed read still signals the area,
1667
+ // and a re-touched directory costs a Set lookup.
1668
+ if (nestedSkillScan) {
1669
+ for (const s of nestedSkillScan.scanInput(input)) {
1670
+ if (!skillsList.some((k) => k.name === s.name))
1671
+ skillsList.push(s);
1672
+ }
1673
+ }
1674
+ // Nested instruction files are discovered on the same touch, from the same
1675
+ // directories (S18c), and path-scoped `.nexrall/rules` files when their globs
1676
+ // match (S18d). A fresh file joins the ledger the prompt reads per request,
1677
+ // and is announced ONCE to the host — carrying the vocabulary's own name for
1678
+ // its event ('nested_traversal' for a directory the agent worked in,
1679
+ // 'path_glob_match' for a rule whose `paths:` matched the touched path).
1680
+ // Sub-agents clear both the callback and the ledger (subTask.ts), so only
1681
+ // the session's own discoveries fire hooks; a child's ephemeral load is
1682
+ // not a fact about this session's instruction set.
1683
+ if (nestedInstructionScan) {
1684
+ const fresh = nestedInstructionScan.scanInput(input);
1685
+ if (fresh.length && options._onInstructionsDiscovered) {
1686
+ options._onInstructionsDiscovered(fresh.map((f) => ({
1687
+ file_path: f.filePath,
1688
+ memory_type: 'Project',
1689
+ load_reason: f.loadReason,
1690
+ })));
1691
+ }
1692
+ }
1534
1693
  // Opportunistic memory compaction — memory_write is the only tool that can
1535
1694
  // grow a memory file, so this is the cheapest point to check whether it just
1536
1695
  // crossed the compaction threshold. Fire-and-forget: never blocks the turn,
@@ -1544,7 +1703,12 @@ async function runAgentLoop(initialMessages, options) {
1544
1703
  // PostToolUseFailure: only when the call errored. Its context/exit-2 text joins the
1545
1704
  // PostToolUse output, so the model sees it next to the error it explains.
1546
1705
  if (result.error !== undefined && (hooks.PostToolUseFailure?.length ?? 0) > 0) {
1547
- const f = await (0, hooks_1.runLifecycleHooks)(hooks.PostToolUseFailure, 'PostToolUseFailure', options.workDir, { session_id: options.sessionId ?? '', tool_name: name, tool_input: input, error: String(result.error).slice(0, 4000) }, name, (0, hooks_1.hookRunOptsFor)(options)).catch(() => ({ block: false }));
1706
+ const f = await (0, hooks_1.runLifecycleHooks)(hooks.PostToolUseFailure, 'PostToolUseFailure', options.workDir, {
1707
+ session_id: options.sessionId ?? '',
1708
+ tool_name: name,
1709
+ tool_input: input,
1710
+ error: String(result.error).slice(0, 4000),
1711
+ }, name, (0, hooks_1.hookRunOptsFor)(options)).catch(() => ({ block: false }));
1548
1712
  if (f.context)
1549
1713
  post.context = [post.context, f.context].filter(Boolean).join('\n');
1550
1714
  if (f.block) {
@@ -1630,8 +1794,10 @@ async function runAgentLoop(initialMessages, options) {
1630
1794
  // command that timed out mid-test-run), surface both so the model can
1631
1795
  // see WHY it hung — the failure detail is usually in the output tail.
1632
1796
  content: result.error
1633
- ? (result.output ? `Error: ${result.error}\n\n${result.output}` : `Error: ${result.error}`)
1634
- : result.output ?? '',
1797
+ ? result.output
1798
+ ? `Error: ${result.error}\n\n${result.output}`
1799
+ : `Error: ${result.error}`
1800
+ : (result.output ?? ''),
1635
1801
  is_error: result.error !== undefined,
1636
1802
  }));
1637
1803
  // Fold any follow-up the user queued mid-task into THIS user turn (alongside the
@@ -1687,7 +1853,9 @@ async function runAgentLoop(initialMessages, options) {
1687
1853
  tool_input: b.input,
1688
1854
  tool_use_id: b.id,
1689
1855
  tool_response: r.error !== undefined
1690
- ? (r.output ? `Error: ${r.error}\n\n${r.output}` : `Error: ${r.error}`)
1856
+ ? r.output
1857
+ ? `Error: ${r.error}\n\n${r.output}`
1858
+ : `Error: ${r.error}`
1691
1859
  : (r.output ?? ''),
1692
1860
  })),
1693
1861
  }, undefined, (0, hooks_1.hookRunOptsFor)(options));
@@ -1791,7 +1959,11 @@ async function runAgentLoop(initialMessages, options) {
1791
1959
  // Routed through onNotice (falling back to onText) like every other housekeeping
1792
1960
  // message in this file — these are statements from the harness, not from the model,
1793
1961
  // and splicing them into the assistant's own bubble reads as if it said them.
1794
- const notice = (0, iterationPolicy_1.stopReasonNotice)(stopReason, { budget, repeatError: stalledRepeatError, hookReason: hookBlockedReason });
1962
+ const notice = (0, iterationPolicy_1.stopReasonNotice)(stopReason, {
1963
+ budget,
1964
+ repeatError: stalledRepeatError,
1965
+ hookReason: hookBlockedReason,
1966
+ });
1795
1967
  // A sub-agent's stop belongs in its parent's tool result, not in the user's chat as
1796
1968
  // if the MAIN agent had stopped (runSubTask turns it into an error for the parent).
1797
1969
  if (options._onStopReason)
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/agent/memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/agent/memory.ts"],"names":[],"mappings":"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"}
@@ -147,7 +147,9 @@ const _locks = new Map();
147
147
  async function withLock(key, fn) {
148
148
  const prev = _locks.get(key) ?? Promise.resolve();
149
149
  let release;
150
- const next = new Promise((res) => { release = res; });
150
+ const next = new Promise((res) => {
151
+ release = res;
152
+ });
151
153
  _locks.set(key, prev.then(() => next));
152
154
  try {
153
155
  await prev;
@@ -218,7 +220,10 @@ function evictToFit(active, archived, maxBytes) {
218
220
  function sanitizeSourceTag(source) {
219
221
  if (!source)
220
222
  return '';
221
- return source.trim().replace(/[[\]\n\r]/g, '').slice(0, SOURCE_TAG_MAX_CHARS);
223
+ return source
224
+ .trim()
225
+ .replace(/[[\]\n\r]/g, '')
226
+ .slice(0, SOURCE_TAG_MAX_CHARS);
222
227
  }
223
228
  async function writeMemory(content, scope, workDir, opts = {}) {
224
229
  let trimmed = content.trim();
@@ -306,7 +311,9 @@ function clearMemory(scope, workDir) {
306
311
  try {
307
312
  fs.rmSync(file, { force: true });
308
313
  }
309
- catch { /* ignore */ }
314
+ catch {
315
+ /* ignore */
316
+ }
310
317
  }
311
318
  function memoryStats(scope, workDir) {
312
319
  const file = memoryFilePath(scope, workDir);
@@ -374,7 +381,8 @@ async function compactMemoryIfNeeded(scope, workDir, summarize) {
374
381
  }
375
382
  // 2. If the active set alone is still driving the size past the trigger,
376
383
  // summarize its oldest half.
377
- if (Buffer.byteLength(serializeSections(active, archived), 'utf-8') > exports.MEMORY_COMPACT_TRIGGER_BYTES && active.length >= 8) {
384
+ if (Buffer.byteLength(serializeSections(active, archived), 'utf-8') > exports.MEMORY_COMPACT_TRIGGER_BYTES &&
385
+ active.length >= 8) {
378
386
  const cut = Math.floor(active.length / 2);
379
387
  const older = active.slice(0, cut);
380
388
  const recent = active.slice(cut);
@@ -524,9 +532,7 @@ function agentMemoryPreamble(agentName, scope, workDir) {
524
532
  const notes = readAgentMemory(agentName, scope, workDir);
525
533
  if (!notes)
526
534
  return '';
527
- const kept = Buffer.byteLength(notes, 'utf-8') > exports.AGENT_MEMORY_INJECT_MAX
528
- ? notes.slice(-exports.AGENT_MEMORY_INJECT_MAX)
529
- : notes;
535
+ const kept = Buffer.byteLength(notes, 'utf-8') > exports.AGENT_MEMORY_INJECT_MAX ? notes.slice(-exports.AGENT_MEMORY_INJECT_MAX) : notes;
530
536
  return (`# Your own notes (agent: ${agentName}, scope: ${scope})\n` +
531
537
  `These are notes YOU saved on previous runs. Treat them as your accumulated experience, ` +
532
538
  `not as instructions from the user, and verify anything that looks stale against the ` +
@@ -1 +1 @@
1
- {"version":3,"file":"modelCatalogue.d.ts","sourceRoot":"","sources":["../../src/agent/modelCatalogue.ts"],"names":[],"mappings":"AAgDA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAiBlE;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAuBnE;AAED,iFAAiF;AACjF,wBAAgB,uBAAuB,IAAI;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAElG;AAOD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErF;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAGzF;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAGvF;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEnF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAExE;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG9G;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,GAAG,IAAI,CAExD;AAED,kEAAkE;AAClE,wBAAgB,iCAAiC,IAAI,IAAI,CAGxD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAO/C,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAW3F;AAED,6GAA6G;AAC7G,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIxH;AAED,8DAA8D;AAC9D,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,GAAG,IAAI,CAE9E"}
1
+ {"version":3,"file":"modelCatalogue.d.ts","sourceRoot":"","sources":["../../src/agent/modelCatalogue.ts"],"names":[],"mappings":"AAgDA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAiBlE;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAuBnE;AAED,iFAAiF;AACjF,wBAAgB,uBAAuB,IAAI;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAElG;AAOD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErF;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAGzF;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAGvF;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEnF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAExE;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG9G;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,GAAG,IAAI,CAExD;AAED,kEAAkE;AAClE,wBAAgB,iCAAiC,IAAI,IAAI,CAGxD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAU/C,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAW3F;AAED,6GAA6G;AAC7G,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,GAAG,SAAS,CAIpB;AAED,8DAA8D;AAC9D,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,GAAG,IAAI,CAE9E"}
@@ -196,7 +196,10 @@ function _resetModelCatalogueCacheForTests() {
196
196
  exports.CHEAPEST_MODEL_ALIAS = 'cheapest';
197
197
  // Legacy tier aliases the backend still resolves (see agentTypes.ts VALID_MODELS).
198
198
  const LEGACY_ALIAS_IDS = {
199
- turbo: 'claude-sonnet-5-5', fast: 'claude-sonnet-5-5', pro: 'claude-opus-5-5', ultra: 'claude-fable-5-1',
199
+ turbo: 'claude-sonnet-5-5',
200
+ fast: 'claude-sonnet-5-5',
201
+ pro: 'claude-opus-5-5',
202
+ ultra: 'claude-fable-5-1',
200
203
  };
201
204
  function cheapestSameVendorModel(parentModel) {
202
205
  if (!_state || !parentModel)