@namzu/cli 24.0.0 → 25.0.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 (192) hide show
  1. package/CHANGELOG.md +776 -0
  2. package/README.md +1 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +1 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/drain.d.ts +0 -23
  7. package/dist/commands/drain.d.ts.map +1 -1
  8. package/dist/commands/drain.js +23 -9
  9. package/dist/commands/drain.js.map +1 -1
  10. package/dist/commands/resident-flags.d.ts +6 -1
  11. package/dist/commands/resident-flags.d.ts.map +1 -1
  12. package/dist/commands/resident-flags.js +39 -1
  13. package/dist/commands/resident-flags.js.map +1 -1
  14. package/dist/commands/resident-learning.d.ts +6 -0
  15. package/dist/commands/resident-learning.d.ts.map +1 -0
  16. package/dist/commands/resident-learning.js +293 -0
  17. package/dist/commands/resident-learning.js.map +1 -0
  18. package/dist/commands/resident.d.ts.map +1 -1
  19. package/dist/commands/resident.js +42 -4
  20. package/dist/commands/resident.js.map +1 -1
  21. package/dist/commands/run-flags.d.ts +2 -2
  22. package/dist/commands/run-flags.d.ts.map +1 -1
  23. package/dist/commands/run-flags.js +6 -6
  24. package/dist/commands/run-flags.js.map +1 -1
  25. package/dist/commands/run-stream.d.ts.map +1 -1
  26. package/dist/commands/run-stream.js +9 -10
  27. package/dist/commands/run-stream.js.map +1 -1
  28. package/dist/commands/run.d.ts.map +1 -1
  29. package/dist/commands/run.js +3 -2
  30. package/dist/commands/run.js.map +1 -1
  31. package/dist/config/load.d.ts.map +1 -1
  32. package/dist/config/load.js +27 -4
  33. package/dist/config/load.js.map +1 -1
  34. package/dist/config/run-limits.d.ts +11 -0
  35. package/dist/config/run-limits.d.ts.map +1 -0
  36. package/dist/config/run-limits.js +64 -0
  37. package/dist/config/run-limits.js.map +1 -0
  38. package/dist/config/schema.d.ts +12 -4
  39. package/dist/config/schema.d.ts.map +1 -1
  40. package/dist/config/schema.js.map +1 -1
  41. package/dist/context/runtime-message.d.ts.map +1 -1
  42. package/dist/context/runtime-message.js +2 -0
  43. package/dist/context/runtime-message.js.map +1 -1
  44. package/dist/integrations/plugins/runtime.d.ts +19 -1
  45. package/dist/integrations/plugins/runtime.d.ts.map +1 -1
  46. package/dist/integrations/plugins/runtime.js +89 -1
  47. package/dist/integrations/plugins/runtime.js.map +1 -1
  48. package/dist/integrations/plugins/settings.d.ts +15 -0
  49. package/dist/integrations/plugins/settings.d.ts.map +1 -0
  50. package/dist/integrations/plugins/settings.js +106 -0
  51. package/dist/integrations/plugins/settings.js.map +1 -0
  52. package/dist/integrations/resident/inspection.d.ts +10 -0
  53. package/dist/integrations/resident/inspection.d.ts.map +1 -0
  54. package/dist/integrations/resident/inspection.js +263 -0
  55. package/dist/integrations/resident/inspection.js.map +1 -0
  56. package/dist/integrations/resident/learning-sources.d.ts +4 -0
  57. package/dist/integrations/resident/learning-sources.d.ts.map +1 -0
  58. package/dist/integrations/resident/learning-sources.js +79 -0
  59. package/dist/integrations/resident/learning-sources.js.map +1 -0
  60. package/dist/integrations/resident/learning-storage.d.ts +5 -0
  61. package/dist/integrations/resident/learning-storage.d.ts.map +1 -0
  62. package/dist/integrations/resident/learning-storage.js +51 -0
  63. package/dist/integrations/resident/learning-storage.js.map +1 -0
  64. package/dist/integrations/resident/runner-launch.d.ts +5 -0
  65. package/dist/integrations/resident/runner-launch.d.ts.map +1 -1
  66. package/dist/integrations/resident/runner-launch.js +2 -0
  67. package/dist/integrations/resident/runner-launch.js.map +1 -1
  68. package/dist/integrations/resident/runner-store.d.ts.map +1 -1
  69. package/dist/integrations/resident/runner-store.js +2 -4
  70. package/dist/integrations/resident/runner-store.js.map +1 -1
  71. package/dist/integrations/resident/runner-worker.js +3 -0
  72. package/dist/integrations/resident/runner-worker.js.map +1 -1
  73. package/dist/integrations/resident/session-step.d.ts +6 -1
  74. package/dist/integrations/resident/session-step.d.ts.map +1 -1
  75. package/dist/integrations/resident/session-step.js +110 -14
  76. package/dist/integrations/resident/session-step.js.map +1 -1
  77. package/dist/integrations/resident/storage.d.ts.map +1 -1
  78. package/dist/integrations/resident/storage.js +7 -6
  79. package/dist/integrations/resident/storage.js.map +1 -1
  80. package/dist/integrations/resident/tool-evidence.d.ts +6 -0
  81. package/dist/integrations/resident/tool-evidence.d.ts.map +1 -0
  82. package/dist/integrations/resident/tool-evidence.js +117 -0
  83. package/dist/integrations/resident/tool-evidence.js.map +1 -0
  84. package/dist/integrations/resident/verification.d.ts +11 -0
  85. package/dist/integrations/resident/verification.d.ts.map +1 -0
  86. package/dist/integrations/resident/verification.js +109 -0
  87. package/dist/integrations/resident/verification.js.map +1 -0
  88. package/dist/integrations/sessions/compaction-evidence.d.ts +5 -0
  89. package/dist/integrations/sessions/compaction-evidence.d.ts.map +1 -0
  90. package/dist/integrations/sessions/compaction-evidence.js +59 -0
  91. package/dist/integrations/sessions/compaction-evidence.js.map +1 -0
  92. package/dist/integrations/sessions/context-inventory.js +1 -1
  93. package/dist/integrations/sessions/context-inventory.js.map +1 -1
  94. package/dist/integrations/sessions/conversation-search.d.ts +56 -8
  95. package/dist/integrations/sessions/conversation-search.d.ts.map +1 -1
  96. package/dist/integrations/sessions/conversation-search.js +600 -63
  97. package/dist/integrations/sessions/conversation-search.js.map +1 -1
  98. package/dist/integrations/sessions/database.d.ts +5 -0
  99. package/dist/integrations/sessions/database.d.ts.map +1 -0
  100. package/dist/integrations/sessions/database.js +34 -0
  101. package/dist/integrations/sessions/database.js.map +1 -0
  102. package/dist/integrations/sessions/evidence-page-validation.d.ts +8 -0
  103. package/dist/integrations/sessions/evidence-page-validation.d.ts.map +1 -0
  104. package/dist/integrations/sessions/evidence-page-validation.js +74 -0
  105. package/dist/integrations/sessions/evidence-page-validation.js.map +1 -0
  106. package/dist/integrations/sessions/evidence-recall.d.ts +5 -0
  107. package/dist/integrations/sessions/evidence-recall.d.ts.map +1 -0
  108. package/dist/integrations/sessions/evidence-recall.js +173 -0
  109. package/dist/integrations/sessions/evidence-recall.js.map +1 -0
  110. package/dist/integrations/sessions/paths.d.ts +7 -0
  111. package/dist/integrations/sessions/paths.d.ts.map +1 -0
  112. package/dist/integrations/sessions/paths.js +14 -0
  113. package/dist/integrations/sessions/paths.js.map +1 -0
  114. package/dist/integrations/sessions/run-discovery.d.ts +24 -0
  115. package/dist/integrations/sessions/run-discovery.d.ts.map +1 -0
  116. package/dist/integrations/sessions/run-discovery.js +142 -0
  117. package/dist/integrations/sessions/run-discovery.js.map +1 -0
  118. package/dist/integrations/sessions/store.d.ts +8 -18
  119. package/dist/integrations/sessions/store.d.ts.map +1 -1
  120. package/dist/integrations/sessions/store.js +14 -39
  121. package/dist/integrations/sessions/store.js.map +1 -1
  122. package/dist/integrations/sessions/transcript-export.d.ts +0 -1
  123. package/dist/integrations/sessions/transcript-export.d.ts.map +1 -1
  124. package/dist/integrations/sessions/transcript-export.js +3 -2
  125. package/dist/integrations/sessions/transcript-export.js.map +1 -1
  126. package/dist/integrations/sessions/turn-evidence.d.ts +0 -9
  127. package/dist/integrations/sessions/turn-evidence.d.ts.map +1 -1
  128. package/dist/integrations/sessions/turn-evidence.js +5 -2
  129. package/dist/integrations/sessions/turn-evidence.js.map +1 -1
  130. package/dist/integrations/state/report.d.ts.map +1 -1
  131. package/dist/integrations/state/report.js +78 -21
  132. package/dist/integrations/state/report.js.map +1 -1
  133. package/dist/integrations/subagents/parent.d.ts +3 -2
  134. package/dist/integrations/subagents/parent.d.ts.map +1 -1
  135. package/dist/integrations/subagents/parent.js +11 -6
  136. package/dist/integrations/subagents/parent.js.map +1 -1
  137. package/dist/integrations/subagents/policy.d.ts +2 -5
  138. package/dist/integrations/subagents/policy.d.ts.map +1 -1
  139. package/dist/integrations/subagents/policy.js +2 -5
  140. package/dist/integrations/subagents/policy.js.map +1 -1
  141. package/dist/integrations/subagents/runtime.d.ts +7 -0
  142. package/dist/integrations/subagents/runtime.d.ts.map +1 -1
  143. package/dist/integrations/subagents/runtime.js +9 -7
  144. package/dist/integrations/subagents/runtime.js.map +1 -1
  145. package/dist/permissions/rules.d.ts +2 -8
  146. package/dist/permissions/rules.d.ts.map +1 -1
  147. package/dist/permissions/rules.js +19 -10
  148. package/dist/permissions/rules.js.map +1 -1
  149. package/dist/tui/App.d.ts +0 -12
  150. package/dist/tui/App.d.ts.map +1 -1
  151. package/dist/tui/App.js +235 -15
  152. package/dist/tui/App.js.map +1 -1
  153. package/dist/tui/ChoicePicker.d.ts +2 -1
  154. package/dist/tui/ChoicePicker.d.ts.map +1 -1
  155. package/dist/tui/ChoicePicker.js +10 -8
  156. package/dist/tui/ChoicePicker.js.map +1 -1
  157. package/dist/tui/ToolOutputViewer.js +1 -1
  158. package/dist/tui/ToolOutputViewer.js.map +1 -1
  159. package/dist/tui/agent.d.ts +20 -3
  160. package/dist/tui/agent.d.ts.map +1 -1
  161. package/dist/tui/agent.js +159 -31
  162. package/dist/tui/agent.js.map +1 -1
  163. package/dist/tui/conversation-evidence-view.d.ts +6 -0
  164. package/dist/tui/conversation-evidence-view.d.ts.map +1 -0
  165. package/dist/tui/conversation-evidence-view.js +96 -0
  166. package/dist/tui/conversation-evidence-view.js.map +1 -0
  167. package/dist/tui/conversation-history.d.ts +3 -1
  168. package/dist/tui/conversation-history.d.ts.map +1 -1
  169. package/dist/tui/conversation-history.js +16 -1
  170. package/dist/tui/conversation-history.js.map +1 -1
  171. package/dist/tui/markdownParser.d.ts.map +1 -1
  172. package/dist/tui/markdownParser.js +2 -1
  173. package/dist/tui/markdownParser.js.map +1 -1
  174. package/dist/tui/plugin-view.d.ts +9 -0
  175. package/dist/tui/plugin-view.d.ts.map +1 -0
  176. package/dist/tui/plugin-view.js +59 -0
  177. package/dist/tui/plugin-view.js.map +1 -0
  178. package/dist/tui/run-interruption.d.ts +2 -2
  179. package/dist/tui/run-interruption.d.ts.map +1 -1
  180. package/dist/tui/run-interruption.js +5 -1
  181. package/dist/tui/run-interruption.js.map +1 -1
  182. package/dist/tui/run-limits-settings.d.ts +39 -0
  183. package/dist/tui/run-limits-settings.d.ts.map +1 -0
  184. package/dist/tui/run-limits-settings.js +88 -0
  185. package/dist/tui/run-limits-settings.js.map +1 -0
  186. package/dist/tui/slashCommands.d.ts +6 -1
  187. package/dist/tui/slashCommands.d.ts.map +1 -1
  188. package/dist/tui/slashCommands.js +40 -9
  189. package/dist/tui/slashCommands.js.map +1 -1
  190. package/dist/tui/types.d.ts +4 -2
  191. package/dist/tui/types.d.ts.map +1 -1
  192. package/package.json +7 -7
package/dist/tui/agent.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createCurrentCredentialReader } from '../integrations/providers/current-credential.js';
2
+ import { CliPathBuilder } from '../integrations/sessions/paths.js';
2
3
  import { createWebSearchTool, resolveWebSearch, webSearchLabel, } from '../integrations/web/search.js';
3
4
  /**
4
5
  * TUI agent session — provider-direct, tool-enabled.
@@ -22,12 +23,13 @@ import { createWebSearchTool, resolveWebSearch, webSearchLabel, } from '../integ
22
23
  * `emptySession()` whose `send()` yields a single error event so the UI
23
24
  * renders an actionable hint rather than crashing.
24
25
  */
25
- import { BOOT_EVENT_NAMES, BackgroundJobRegistry, DefaultPathBuilder, DiskCheckpointStore, DiskMemoryStore, DiskTaskStore, EVENT_NAME_ATTRIBUTE, GuardedFetchProvider, PromptContributionRegistry, ProviderRegistry, SESSION_GOAL_TOOL_NAMES, ToolRegistry, WebFetchTool, batchNeedsReview, buildAskUserQuestionTool, buildMemoryTools, buildSessionGoalTools, compactNow, createComputerUseTool, createFileReadTracker, createMemoryPromoter, createMemoryRecallStep, createResidentStepContributions, createReviewHandler, createToolPresenter, generateProjectId, generateRunId, generateSessionId, generateTenantId, generateTopicId, getBuiltinTools, isReviewExempt, query, resumeRun, webGuidanceContribution, withProviderFallback, } from '@namzu/sdk';
26
+ import { BOOT_EVENT_NAMES, BackgroundJobRegistry, DiskCheckpointStore, DiskMemoryStore, DiskTaskStore, EVENT_NAME_ATTRIBUTE, GuardedFetchProvider, PromptContributionRegistry, ProviderRegistry, SESSION_GOAL_TOOL_NAMES, ToolRegistry, WebFetchTool, asRunId, batchNeedsReview, buildAskUserQuestionTool, buildMemoryTools, buildResidentHistoryTools, buildResidentToolEvidenceTools, buildSessionGoalTools, compactNow, createComputerUseTool, createFileReadTracker, createMemoryPromoter, createMemoryRecallStep, createResidentStepContext, createResidentStepContributions, createReviewHandler, createToolPresenter, generateProjectId, generateRunId, generateSessionId, generateTenantId, generateTopicId, getBuiltinTools, isReviewExempt, query, resumeRun, webGuidanceContribution, withProviderFallback, } from '@namzu/sdk';
26
27
  import { SubprocessComputerUseHost } from '@namzu/computer-use';
27
28
  import { realpath, stat } from 'node:fs/promises';
28
29
  import { join, parse, resolve } from 'node:path';
29
30
  import { FileCheckpointStore } from '../checkpoints/store.js';
30
31
  import { CHECKPOINTED_TOOLS, withCheckpoints } from '../checkpoints/wrap.js';
32
+ import { readStoredRunGuards, resolveRunGuards } from '../config/run-limits.js';
31
33
  import { probeCapabilities } from '../context/capabilities.js';
32
34
  import { NAMZU_DELEGATION_DOCTRINE, NAMZU_PLAN_MODE_DOCTRINE, NAMZU_WORKING_DOCTRINE, } from '../context/doctrine.js';
33
35
  import { composeEnvironmentPrompt, readEnvironmentFacts } from '../context/environment.js';
@@ -41,15 +43,16 @@ import { canSelectModel } from '../integrations/providers/access.js';
41
43
  import { createGeminiAccessTokenResolver } from '../integrations/providers/gemini-credentials.js';
42
44
  import { CredentialRefreshRejectedError, CredentialWithdrawnError, PROVIDER_REGISTRY, chainCapabilityDisagreements, chainPositionName, describeAcceptedMismatch, describeCapabilityRefusal, discoverProviders, ensureFreshAnthropicToken, ensureFreshStoredCodexCredential, ensureRegistered, findDetected, isAnthropicOAuthToken, isRegistered, missingCredentialMessage, primaryProvider, readCodexCredentialFile, readPreferences, readSubscriptionCredential, resolveChainCapabilities, sameOAuthCredential, unresolvedMembers, unsupportedProviderMessage, } from '../integrations/providers/index.js';
43
45
  import { modelReasoningView } from '../integrations/providers/model-reasoning.js';
46
+ import { retainManualCompaction } from '../integrations/sessions/compaction-evidence.js';
44
47
  import { createContextInventoryStep } from '../integrations/sessions/context-inventory.js';
45
- import { buildConversationReadTool, buildConversationSearchTool, } from '../integrations/sessions/conversation-search.js';
48
+ import { CONVERSATION_EVIDENCE_GUIDANCE, buildConversationReadTool, buildConversationSearchTool, releaseConversationEvidence, } from '../integrations/sessions/conversation-search.js';
49
+ import { createConversationEvidenceRecall } from '../integrations/sessions/evidence-recall.js';
46
50
  import { createTaskContextStep } from '../integrations/sessions/task-context.js';
47
51
  import { ensurePrivateStateDirectory } from '../integrations/state/private-directory.js';
48
52
  import { discoverAgentDefinitions } from '../integrations/subagents/definitions.js';
49
53
  import { createDelegationHistoryStep } from '../integrations/subagents/history.js';
50
54
  import { prepareDelegatedEffort } from '../integrations/subagents/model-effort.js';
51
55
  import { SubagentPathBuilder, resolveSubagentParent } from '../integrations/subagents/parent.js';
52
- import { CLI_INTERACTIVE_RUN_TIMEOUT_MS } from '../integrations/subagents/policy.js';
53
56
  import { createSubagentRuntime } from '../integrations/subagents/runtime.js';
54
57
  import { cliLogger } from '../logging.js';
55
58
  import { formatMemoryDiagnostics } from '../memory/presentation.js';
@@ -97,10 +100,22 @@ export class SessionOperationOwner {
97
100
  streamClosers = new Set();
98
101
  closeReason = new DOMException('Agent session closed.', 'AbortError');
99
102
  closed = false;
103
+ exclusiveOperation = false;
100
104
  closePromise;
101
105
  constructor(cleanup) {
102
106
  this.cleanup = cleanup;
103
107
  }
108
+ /** Change shared session resources only when no invocation can still use them. */
109
+ exclusive(start) {
110
+ if (this.active.size > 0 || this.exclusiveOperation) {
111
+ return Promise.reject(new Error('Wait for the active session operation to finish before changing plugins.'));
112
+ }
113
+ const operation = this.promise(undefined, start);
114
+ this.exclusiveOperation = true;
115
+ return operation.finally(() => {
116
+ this.exclusiveOperation = false;
117
+ });
118
+ }
104
119
  promise(callerSignal, start) {
105
120
  let signal;
106
121
  try {
@@ -230,14 +245,18 @@ export class SessionOperationOwner {
230
245
  operationSignal(callerSignal) {
231
246
  if (this.closed)
232
247
  throw this.closeReason;
248
+ if (this.exclusiveOperation)
249
+ throw new Error('A plugin change is in progress; try again when it finishes.');
233
250
  return callerSignal
234
251
  ? AbortSignal.any([callerSignal, this.lifetime.signal])
235
252
  : this.lifetime.signal;
236
253
  }
237
254
  track(operation) {
238
- const settlement = Promise.resolve(operation).then(() => { }, () => { });
255
+ const release = () => {
256
+ this.active.delete(settlement);
257
+ };
258
+ const settlement = Promise.resolve(operation).then(release, release);
239
259
  this.active.add(settlement);
240
- void settlement.then(() => this.active.delete(settlement));
241
260
  }
242
261
  async finishClose() {
243
262
  await Promise.allSettled([...this.streamClosers].map((close) => close()));
@@ -342,6 +361,12 @@ const EAGER_TOOLS_WHEN_DEFERRED = [
342
361
  'job',
343
362
  'web_search',
344
363
  'web_fetch',
364
+ 'search_conversation',
365
+ 'read_conversation',
366
+ 'search_resident_history',
367
+ 'read_resident_history',
368
+ 'search_resident_tools',
369
+ 'read_resident_tool',
345
370
  // query mounts discovery when absent; an existing discovery tool must stay ready.
346
371
  'search_tools',
347
372
  ];
@@ -407,7 +432,7 @@ function builtinTools(backgroundJobs) {
407
432
  return [tool.name === 'bash' ? foregroundOnlyBash(tool) : tool];
408
433
  });
409
434
  }
410
- function buildToolRegistry(cwd, projectStateRoot = join(cwd, '.namzu'), backgroundJobs = true, checkpoints) {
435
+ function buildToolRegistry(cwd, projectStateRoot = join(cwd, '.namzu'), backgroundJobs = true, checkpoints, projectId) {
411
436
  const registry = new ToolRegistry();
412
437
  registry.register(builtinTools(backgroundJobs));
413
438
  // The file tools take a checkpoint before they write, so `/restore` can
@@ -427,8 +452,9 @@ function buildToolRegistry(cwd, projectStateRoot = join(cwd, '.namzu'), backgrou
427
452
  // surfaces inject the central application-home hierarchy; embedded callers
428
453
  // that omit it retain the historical `<cwd>/.namzu` layout.
429
454
  // Separate from the user-curated MEMORY.md that is injected into the prompt.
430
- ensurePrivateStateDirectory(projectStateRoot, 'memory');
431
- const memoryStore = new DiskMemoryStore({ baseDir: projectStateRoot });
455
+ const memoryRoot = ensurePrivateStateDirectory(projectStateRoot, 'memory');
456
+ const directory = projectId ? ensurePrivateStateDirectory(memoryRoot, projectId) : memoryRoot;
457
+ const memoryStore = new DiskMemoryStore({ baseDir: projectStateRoot, directory });
432
458
  // Search through the store's async boundary. Its concrete index is lazy:
433
459
  // handing `getIndex()` to the synchronous overload before the first store
434
460
  // read makes a new process report every persisted memory as absent.
@@ -474,13 +500,10 @@ export async function createAgentSession(prefs, detected, options = {}) {
474
500
  return emptySession(`Working-directory sandboxing refuses filesystem root ${cwd}; choose a project directory so confinement has a boundary, or explicitly select an ephemeral workspace.`, 'invocation');
475
501
  }
476
502
  const hierarchyRoot = resolve(options.stateRoot ?? join(cwd, '.namzu'));
477
- const pathBuilder = new DefaultPathBuilder(hierarchyRoot);
478
- let projectStateRoot = hierarchyRoot;
503
+ const pathBuilder = new CliPathBuilder(hierarchyRoot);
504
+ const projectStateRoot = hierarchyRoot;
479
505
  try {
480
- if (options.stateRoot) {
481
- const projectsRoot = ensurePrivateStateDirectory(hierarchyRoot, 'projects');
482
- projectStateRoot = ensurePrivateStateDirectory(projectsRoot, scope.projectId);
483
- }
506
+ ensurePrivateStateDirectory(hierarchyRoot, 'sessions');
484
507
  // Refuse an aliased or otherwise unsafe generated-state root before any
485
508
  // provider, sandbox or plugin runtime is constructed. Project-authored
486
509
  // `.namzu` content may coexist here, but generated memory must never be
@@ -833,7 +856,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
833
856
  },
834
857
  };
835
858
  const checkpoints = new FileCheckpointStore(join(ensurePrivateStateDirectory(projectStateRoot, 'checkpoints'), scope.sessionId), cwd);
836
- const { registry, memoryStore } = buildToolRegistry(cwd, projectStateRoot, backgroundJobs, checkpoints);
859
+ const { registry, memoryStore } = buildToolRegistry(cwd, projectStateRoot, backgroundJobs, checkpoints, options.stateRoot ? scope.projectId : undefined);
837
860
  // Package presence is not tool reachability. The CLI used to probe and
838
861
  // report @namzu/computer-use without ever constructing its host or mounting
839
862
  // SDK's computer_use definition, so even an installed, healthy package was
@@ -954,7 +977,37 @@ export async function createAgentSession(prefs, detected, options = {}) {
954
977
  // delegate a self-contained task to a fresh sub-agent (own context window).
955
978
  // Best-effort — if the runtime can't stand up, the chat still works.
956
979
  const delegationScopes = new Map();
980
+ const delegationLimits = new Map();
957
981
  const delegatedInputWaiters = new Map();
982
+ if (options.residentHistory) {
983
+ const history = options.residentHistory;
984
+ const historyOwner = { ...scope };
985
+ registry.register(buildResidentHistoryTools((context) => {
986
+ const owner = delegationScopes.get(context.runId);
987
+ if (!owner ||
988
+ owner.sessionId !== historyOwner.sessionId ||
989
+ owner.projectId !== historyOwner.projectId ||
990
+ owner.tenantId !== historyOwner.tenantId ||
991
+ owner.tenantId !== history.scope.tenantId)
992
+ throw new Error('The requesting run does not own this resident history.');
993
+ return history;
994
+ }));
995
+ }
996
+ if (options.residentToolEvidence) {
997
+ const evidence = options.residentToolEvidence;
998
+ const evidenceOwner = { ...scope };
999
+ registry.register(buildResidentToolEvidenceTools((context) => {
1000
+ const owner = delegationScopes.get(context.runId);
1001
+ if (!owner ||
1002
+ owner.sessionId !== evidenceOwner.sessionId ||
1003
+ owner.projectId !== evidenceOwner.projectId ||
1004
+ owner.tenantId !== evidenceOwner.tenantId ||
1005
+ owner.projectId !== evidence.scope.projectId ||
1006
+ owner.tenantId !== evidence.scope.tenantId)
1007
+ throw new Error('The requesting run does not own this resident tool evidence.');
1008
+ return evidence;
1009
+ }));
1010
+ }
958
1011
  if (options.conversationSessions) {
959
1012
  const sessions = options.conversationSessions;
960
1013
  for (const build of [buildConversationSearchTool, buildConversationReadTool])
@@ -967,6 +1020,25 @@ export async function createAgentSession(prefs, detected, options = {}) {
967
1020
  return { sessions, sessionId: owner.sessionId };
968
1021
  }));
969
1022
  }
1023
+ const evidenceRecallSteps = new Map();
1024
+ const evidenceRecallFor = (sessionId) => {
1025
+ const sessions = options.conversationSessions;
1026
+ if (!sessions || options.compaction?.recallEvidence === false)
1027
+ return [];
1028
+ let step = evidenceRecallSteps.get(sessionId);
1029
+ if (!step) {
1030
+ step = createConversationEvidenceRecall(sessions, sessionId, (runId) => {
1031
+ const owner = delegationScopes.get(asRunId(runId));
1032
+ if (!owner ||
1033
+ owner.sessionId !== sessionId ||
1034
+ owner.tenantId !== sessions.tenantId ||
1035
+ owner.projectId !== sessions.projectId)
1036
+ throw new Error('The requesting run no longer owns this conversation.');
1037
+ }, options.compaction?.resolveEvidenceQueries !== false);
1038
+ evidenceRecallSteps.set(sessionId, step);
1039
+ }
1040
+ return [step];
1041
+ };
970
1042
  let subagentRuntime;
971
1043
  // Stays empty when the runtime below throws, which is the honest answer: the
972
1044
  // catch is non-fatal and the session then genuinely has no delegate to
@@ -989,6 +1061,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
989
1061
  cwd,
990
1062
  model,
991
1063
  tokenBudget: options.limits?.tokenBudget,
1064
+ maxIterations: options.limits?.maxIterations,
1065
+ resolveLimits: (runId) => delegationLimits.get(runId),
1066
+ timeoutMs: options.limits?.timeoutMs,
992
1067
  definitions: discovered.definitions,
993
1068
  pathBuilder: new SubagentPathBuilder(projectStateRoot, scope.projectId),
994
1069
  resolveParent: async (runId) => {
@@ -1110,7 +1185,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1110
1185
  // delegation, and a parent that delegated six times would leave
1111
1186
  // seven accounts of one piece of work for the next run to read.
1112
1187
  // The parent's settle is the one that speaks for the whole task.
1113
- const childTools = buildToolRegistry(cwd, projectStateRoot, backgroundJobs).registry;
1188
+ const childTools = buildToolRegistry(cwd, projectStateRoot, backgroundJobs, undefined, options.stateRoot ? scope.projectId : undefined).registry;
1114
1189
  // Search owns its provider connection per call, so it is safe to share
1115
1190
  // with a child. Preserve the parent's configured backend/off choice.
1116
1191
  const search = registry.get('web_search');
@@ -1320,6 +1395,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
1320
1395
  });
1321
1396
  const operations = new SessionOperationOwner(async () => {
1322
1397
  const results = await Promise.allSettled([
1398
+ options.conversationSessions
1399
+ ? releaseConversationEvidence(options.conversationSessions, scope.sessionId)
1400
+ : undefined,
1323
1401
  subagentRuntime?.close?.(),
1324
1402
  sessionPlugins
1325
1403
  ? sessionPlugins.manager
@@ -1396,6 +1474,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1396
1474
  */
1397
1475
  const kernelResume = ({ entry, checkpointStore, claimFence, signal, checkpointId, listener, }) => operations.promise(signal, async (ownedSignal) => {
1398
1476
  const selectTaskStore = beginTaskStoreReadout();
1477
+ const resumedLimits = (await readStoredRunGuards(join(pathBuilder.runDir(entry.projectId, entry.sessionId, entry.runId), 'run.json'), entry)) ?? resolveRunGuards(options.limits);
1399
1478
  // The same prelude a turn runs, and for the same reasons: a lapsed
1400
1479
  // OAuth token has to be renewed before the provider is used, and the
1401
1480
  // fallback chain has to be built AFTER that so its members do not
@@ -1416,6 +1495,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1416
1495
  NAMZU_IDENTITY,
1417
1496
  NAMZU_WORKING_DOCTRINE,
1418
1497
  NAMZU_DELEGATION_DOCTRINE,
1498
+ options.conversationSessions ? CONVERSATION_EVIDENCE_GUIDANCE : undefined,
1419
1499
  environmentPrompt,
1420
1500
  memoryPrompt,
1421
1501
  ]
@@ -1427,6 +1507,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1427
1507
  }
1428
1508
  delegatedResumeHandlers.set(entry.runId, resumeHandler);
1429
1509
  delegationScopes.set(entry.runId, { ...entry, topicId: scope.topicId });
1510
+ delegationLimits.set(entry.runId, resumedLimits);
1430
1511
  const runTaskStore = selectTaskStore(entry.runId, {
1431
1512
  ...entry,
1432
1513
  topicId: scope.topicId,
@@ -1457,6 +1538,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
1457
1538
  : {}),
1458
1539
  authorizationGate: gateFor(options.rules),
1459
1540
  compactionConfig: compactionConfigFor(options.compaction),
1541
+ retainedToolPreviewChars: options.conversationSessions
1542
+ ? (options.compaction?.retainedToolPreviewChars ?? 4_000)
1543
+ : undefined,
1460
1544
  prepareStep: [
1461
1545
  createTaskContextStep(runTaskStore, entry.tenantId),
1462
1546
  createDelegationHistoryStep(projectStateRoot, entry.sessionId),
@@ -1469,6 +1553,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1469
1553
  }),
1470
1554
  ]),
1471
1555
  ...(options.conversationSessions ? [createContextInventoryStep()] : []),
1556
+ ...evidenceRecallFor(entry.sessionId),
1472
1557
  ],
1473
1558
  ...(options.compaction?.consolidate
1474
1559
  ? { consolidateInto: memoryStore }
@@ -1488,9 +1573,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1488
1573
  model,
1489
1574
  ...(nativeWebSearch ? { webSearch: nativeWebSearch } : {}),
1490
1575
  ...(sandbox.provider ? { sandbox: { workspace: sandboxWorkspace } } : {}),
1491
- timeoutMs: CLI_INTERACTIVE_RUN_TIMEOUT_MS,
1492
- tokenBudget: options.limits?.tokenBudget ?? 0,
1493
- maxIterations: options.limits?.maxIterations ?? 50,
1576
+ ...resumedLimits,
1494
1577
  maxResponseTokens: 8192,
1495
1578
  permissionMode: 'auto',
1496
1579
  },
@@ -1530,6 +1613,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1530
1613
  if (delegatedResumeHandlers.get(entry.runId) === resumeHandler) {
1531
1614
  delegatedResumeHandlers.delete(entry.runId);
1532
1615
  delegationScopes.delete(entry.runId);
1616
+ delegationLimits.delete(entry.runId);
1533
1617
  await subagentRuntime?.releaseRun(entry.runId);
1534
1618
  }
1535
1619
  }
@@ -1622,6 +1706,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1622
1706
  reasoningEffortDefault,
1623
1707
  compact: (messages) => operations.promise(undefined, async (signal) => {
1624
1708
  const sessionId = scope.sessionId;
1709
+ const sessions = options.conversationSessions;
1625
1710
  await prepareProviderCredential(signal);
1626
1711
  return compactNow({
1627
1712
  messages,
@@ -1629,6 +1714,16 @@ export async function createAgentSession(prefs, detected, options = {}) {
1629
1714
  provider: providerForSession(sessionId),
1630
1715
  model,
1631
1716
  signal,
1717
+ ...(sessions
1718
+ ? {
1719
+ onShed: async (removed) => {
1720
+ if (sessions.projectId !== scope.projectId ||
1721
+ sessions.tenantId !== scope.tenantId)
1722
+ throw new Error('Manual compaction is outside the current conversation scope.');
1723
+ await retainManualCompaction(sessions, sessionId, removed, signal);
1724
+ },
1725
+ }
1726
+ : {}),
1632
1727
  });
1633
1728
  }),
1634
1729
  // Reads the same registry object the deferred registration mutates, at
@@ -1638,6 +1733,17 @@ export async function createAgentSession(prefs, detected, options = {}) {
1638
1733
  .getCallableTools()
1639
1734
  .map((t) => t.name)
1640
1735
  .filter((name) => !goalToolNames.has(name)),
1736
+ ...(pluginRuntime
1737
+ ? {
1738
+ plugins: {
1739
+ list: pluginRuntime.list,
1740
+ rememberState: (name) => operations.exclusive(() => pluginRuntime.rememberState(name)),
1741
+ setEnabled: (name, enabled) => operations.exclusive(async () => {
1742
+ await pluginRuntime.setEnabled(name, enabled);
1743
+ }),
1744
+ },
1745
+ }
1746
+ : {}),
1641
1747
  agentIds: allowedAgentIds,
1642
1748
  currentTaskStore,
1643
1749
  resetTaskStore,
@@ -1685,6 +1791,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1685
1791
  send: (messages, opts) => operations.stream(opts?.signal, (signal) => (async function* () {
1686
1792
  const selectTaskStore = beginTaskStoreReadout();
1687
1793
  const runId = opts?.runId ?? generateRunId();
1794
+ const turnLimits = resolveRunGuards(options.limits, opts?.limits);
1688
1795
  const turnOpts = { ...opts, runId, signal };
1689
1796
  let runTools = registry;
1690
1797
  const resumeHandler = makeResumeHandler(approval, opts?.onPermission, opts?.permissionMode ?? options.permissionMode, (name, input) => isPromptExempt(runTools, name, input));
@@ -1698,6 +1805,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1698
1805
  delegatedInputWaiters.set(runId, opts.waitForInbound);
1699
1806
  const turnScope = { ...scope };
1700
1807
  delegationScopes.set(runId, turnScope);
1808
+ delegationLimits.set(runId, turnLimits);
1701
1809
  try {
1702
1810
  // Renew a lapsed OAuth token before the turn runs (no-op for valid
1703
1811
  // tokens and non-subscription credentials).
@@ -1764,10 +1872,24 @@ export async function createAgentSession(prefs, detected, options = {}) {
1764
1872
  });
1765
1873
  const residentContext = opts?.residentContext;
1766
1874
  if (residentContext) {
1767
- for (const contribution of createResidentStepContributions({
1875
+ const contextOptions = {
1768
1876
  ...residentContext,
1769
1877
  readOnly: (opts?.permissionMode ?? options.permissionMode) === 'plan',
1770
- }))
1878
+ };
1879
+ const bundle = opts?.residentLearningDisclosure === 'on-demand'
1880
+ ? createResidentStepContext({
1881
+ ...contextOptions,
1882
+ authorizeLearningRead: (context) => context.runId === runId &&
1883
+ delegationScopes.get(context.runId) === turnScope,
1884
+ })
1885
+ : { contributions: createResidentStepContributions(contextOptions), tools: [] };
1886
+ if (bundle.tools.length) {
1887
+ // Per-send membership: neither another send nor delegated runs inherit this tool.
1888
+ runTools = runTools.fork();
1889
+ for (const tool of bundle.tools)
1890
+ runTools.register(tool);
1891
+ }
1892
+ for (const contribution of bundle.contributions)
1771
1893
  promptContributions.register(contribution);
1772
1894
  // These are invocation snapshots, not the stable working policy.
1773
1895
  const invocationContext = [environmentPrompt, memoryPrompt, opts?.extraSystem]
@@ -1783,6 +1905,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1783
1905
  NAMZU_IDENTITY,
1784
1906
  residentContext ? undefined : NAMZU_WORKING_DOCTRINE,
1785
1907
  residentContext ? undefined : NAMZU_DELEGATION_DOCTRINE,
1908
+ options.conversationSessions ? CONVERSATION_EVIDENCE_GUIDANCE : undefined,
1786
1909
  options.toolLoading === 'deferred' ? DEFERRED_TOOL_GUIDANCE : undefined,
1787
1910
  // Present only while the turn runs under `plan`. A mode change
1788
1911
  // is rare, so the cached prefix it re-keys is a price paid once
@@ -1830,6 +1953,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
1830
1953
  provider: providerForSession(turnScope.sessionId),
1831
1954
  fileReadTracker: observationsFor(turnScope.sessionId),
1832
1955
  compactionConfig: compactionConfigFor(options.compaction),
1956
+ retainedToolPreviewChars: options.conversationSessions
1957
+ ? (options.compaction?.retainedToolPreviewChars ?? 4_000)
1958
+ : undefined,
1833
1959
  ...(options.compaction?.consolidate ? { consolidateInto: memoryStore } : {}),
1834
1960
  ...(jobRegistry
1835
1961
  ? {
@@ -1854,7 +1980,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1854
1980
  pathBuilder,
1855
1981
  workingDirectory: cwd,
1856
1982
  ...(directories.length > 0 ? { additionalDirectories: [...directories] } : {}),
1857
- ...(options.limits ? { limits: options.limits } : {}),
1983
+ limits: turnLimits,
1858
1984
  sandboxWorkspace,
1859
1985
  rules: options.rules,
1860
1986
  structuredOutput: options.structuredOutput,
@@ -1874,6 +2000,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
1874
2000
  }),
1875
2001
  ]),
1876
2002
  ...(options.conversationSessions ? [createContextInventoryStep()] : []),
2003
+ ...evidenceRecallFor(turnScope.sessionId),
2004
+ ...(options.residentEvidenceRecall ? [options.residentEvidenceRecall] : []),
1877
2005
  ],
1878
2006
  taskStore: runTaskStore,
1879
2007
  systemPrompt,
@@ -1893,6 +2021,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1893
2021
  task_update: options.toolLoading === 'deferred' ? 'deferred' : 'active',
1894
2022
  task_list: options.toolLoading === 'deferred' ? 'deferred' : 'active',
1895
2023
  },
2024
+ emergencySave: options.emergencySave ?? true,
1896
2025
  onRunEvent: options.onRunEvent,
1897
2026
  ...(sandbox.provider ? { sandboxProvider: sandbox.provider } : {}),
1898
2027
  ...(options.sandbox?.teardownTimeoutMs !== undefined
@@ -1916,6 +2045,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
1916
2045
  modelSwitchHandlers.delete(runId);
1917
2046
  delegatedInputWaiters.delete(runId);
1918
2047
  delegationScopes.delete(runId);
2048
+ delegationLimits.delete(runId);
1919
2049
  await subagentRuntime?.releaseRun(runId);
1920
2050
  }
1921
2051
  }
@@ -2339,7 +2469,7 @@ function compactionConfigFor(compaction) {
2339
2469
  : {}),
2340
2470
  };
2341
2471
  }
2342
- async function* runTurn({ fileReadTracker, provider, compactionConfig, consolidateInto, backgroundJobs, backgroundJobOwner, fallbackProviders, model, tools, pluginManager, skillRegistry, skills, scope, pathBuilder, workingDirectory, limits, additionalDirectories, sandboxWorkspace, rules, structuredOutput, reviewAnswer, maxAnswerReviews, promoteMemory, prepareStep, resumeHandler, taskStore, systemPrompt, messages, projectInstructionContext, opts, taskGateway, completionInbox, promptContributions, runtimeToolOverrides, webSearch, web, sandboxProvider, sandboxTeardownTimeoutMs, onRunEvent, }) {
2472
+ async function* runTurn({ emergencySave, retainedToolPreviewChars, fileReadTracker, provider, compactionConfig, consolidateInto, backgroundJobs, backgroundJobOwner, fallbackProviders, model, tools, pluginManager, skillRegistry, skills, scope, pathBuilder, workingDirectory, limits, additionalDirectories, sandboxWorkspace, rules, structuredOutput, reviewAnswer, maxAnswerReviews, promoteMemory, prepareStep, resumeHandler, taskStore, systemPrompt, messages, projectInstructionContext, opts, taskGateway, completionInbox, promptContributions, runtimeToolOverrides, webSearch, web, sandboxProvider, sandboxTeardownTimeoutMs, onRunEvent, }) {
2343
2473
  const signal = opts?.signal;
2344
2474
  // One presenter for the whole stream, built from the registry this scope
2345
2475
  // already holds. Its absence HERE is what forced presentation to be name
@@ -2348,6 +2478,7 @@ async function* runTurn({ fileReadTracker, provider, compactionConfig, consolida
2348
2478
  const presenter = createToolPresenter(tools);
2349
2479
  try {
2350
2480
  const events = query({
2481
+ ...(retainedToolPreviewChars !== undefined ? { retainedToolPreviewChars } : {}),
2351
2482
  ...(fileReadTracker ? { fileReadTracker } : {}),
2352
2483
  ...(structuredOutput ? { structuredOutput } : {}),
2353
2484
  provider,
@@ -2376,19 +2507,15 @@ async function* runTurn({ fileReadTracker, provider, compactionConfig, consolida
2376
2507
  compactionConfig,
2377
2508
  ...(consolidateInto ? { consolidateInto } : {}),
2378
2509
  ...(backgroundJobs ? { backgroundJobs, backgroundJobOwner } : {}),
2379
- // The CLI owns its process end to end, so it can safely hand the
2380
- // termination path to the kernel: a Ctrl-C mid-run now leaves a
2381
- // dump under the injected hierarchy's emergency partition instead of
2382
- // losing the turn.
2383
- emergencySave: true,
2510
+ // Interactive chat may own process exit. An enclosing resident host
2511
+ // instead drains the run and writes its finish/runner receipts first.
2512
+ emergencySave,
2384
2513
  runConfig: {
2385
2514
  model,
2386
2515
  ...(sandboxProvider ? { sandbox: { workspace: sandboxWorkspace } } : {}),
2387
2516
  ...(opts?.effort !== undefined ? { effort: opts.effort } : {}),
2388
2517
  ...(webSearch ? { webSearch } : {}),
2389
- timeoutMs: CLI_INTERACTIVE_RUN_TIMEOUT_MS,
2390
- tokenBudget: limits?.tokenBudget ?? 0,
2391
- maxIterations: limits?.maxIterations ?? 50,
2518
+ ...resolveRunGuards(limits),
2392
2519
  maxResponseTokens: 8192,
2393
2520
  permissionMode: 'auto',
2394
2521
  },
@@ -2535,6 +2662,7 @@ export function toAgentEvent(event, presenter) {
2535
2662
  return {
2536
2663
  kind: 'delta',
2537
2664
  text: event.text,
2665
+ ...(event.textPart ? { textPart: event.textPart } : {}),
2538
2666
  ...(event.messageId ? { messageId: event.messageId } : {}),
2539
2667
  ...(event.runId ? { runId: event.runId } : {}),
2540
2668
  };