@namzu/sdk 48.0.0 → 48.2.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 (61) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  3. package/dist/connector/mcp/adapter.js +11 -0
  4. package/dist/connector/mcp/adapter.js.map +1 -1
  5. package/dist/connector/mcp/client.d.ts +19 -0
  6. package/dist/connector/mcp/client.d.ts.map +1 -1
  7. package/dist/connector/mcp/client.js +363 -2
  8. package/dist/connector/mcp/client.js.map +1 -1
  9. package/dist/connector/mcp/era.d.ts.map +1 -1
  10. package/dist/connector/mcp/era.js +7 -0
  11. package/dist/connector/mcp/era.js.map +1 -1
  12. package/dist/connector/mcp/streamable-http.d.ts +15 -0
  13. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  14. package/dist/connector/mcp/streamable-http.js +281 -6
  15. package/dist/connector/mcp/streamable-http.js.map +1 -1
  16. package/dist/manager/agent/lifecycle.d.ts +1 -0
  17. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  18. package/dist/manager/agent/lifecycle.js +137 -18
  19. package/dist/manager/agent/lifecycle.js.map +1 -1
  20. package/dist/manager/resident/initiative.d.ts +6 -6
  21. package/dist/manager/resident/outbox.d.ts +4 -4
  22. package/dist/scheduler/local.d.ts.map +1 -1
  23. package/dist/scheduler/local.js +2 -0
  24. package/dist/scheduler/local.js.map +1 -1
  25. package/dist/session/retention/archive.js +1 -1
  26. package/dist/session/retention/archive.js.map +1 -1
  27. package/dist/store/session/disk.d.ts.map +1 -1
  28. package/dist/store/session/disk.js +2 -0
  29. package/dist/store/session/disk.js.map +1 -1
  30. package/dist/tools/builtins/browser.js +2 -2
  31. package/dist/tools/builtins/browser.js.map +1 -1
  32. package/dist/tools/schedules/schedule-tool.d.ts.map +1 -1
  33. package/dist/tools/schedules/schedule-tool.js +12 -5
  34. package/dist/tools/schedules/schedule-tool.js.map +1 -1
  35. package/dist/tools/schedules/types.d.ts +6 -0
  36. package/dist/tools/schedules/types.d.ts.map +1 -1
  37. package/dist/types/agent/scheduler.d.ts +6 -1
  38. package/dist/types/agent/scheduler.d.ts.map +1 -1
  39. package/dist/types/agent/task.d.ts +19 -1
  40. package/dist/types/agent/task.d.ts.map +1 -1
  41. package/dist/types/agent/task.js.map +1 -1
  42. package/dist/types/connector/mcp.d.ts +13 -0
  43. package/dist/types/connector/mcp.d.ts.map +1 -1
  44. package/dist/types/session/sub-session.d.ts +2 -0
  45. package/dist/types/session/sub-session.d.ts.map +1 -1
  46. package/package.json +1 -1
  47. package/src/connector/mcp/adapter.ts +15 -0
  48. package/src/connector/mcp/client.ts +405 -2
  49. package/src/connector/mcp/era.ts +7 -0
  50. package/src/connector/mcp/streamable-http.ts +302 -5
  51. package/src/manager/agent/lifecycle.ts +158 -19
  52. package/src/scheduler/local.ts +2 -0
  53. package/src/session/retention/archive.ts +1 -1
  54. package/src/store/session/disk.ts +3 -0
  55. package/src/tools/builtins/browser.ts +2 -2
  56. package/src/tools/schedules/schedule-tool.ts +16 -5
  57. package/src/tools/schedules/types.ts +6 -0
  58. package/src/types/agent/scheduler.ts +6 -1
  59. package/src/types/agent/task.ts +21 -1
  60. package/src/types/connector/mcp.ts +14 -0
  61. package/src/types/session/sub-session.ts +2 -0
@@ -223,7 +223,7 @@ export class ArchivalManager {
223
223
 
224
224
  // 6. Dispose the workspace (idempotent — driver contract tolerates
225
225
  // already-disposed refs; a missing ref is a no-op).
226
- if (workspace) {
226
+ if (workspace && sub.workspaceRetention !== 'retain') {
227
227
  try {
228
228
  const driver = this.deps.workspaceRegistry.get(workspace.meta.backend)
229
229
  await driver.dispose(workspace)
@@ -226,6 +226,7 @@ interface PersistedSubSession {
226
226
  failureMode: SubSession['failureMode']
227
227
  completionMode: SubSession['completionMode']
228
228
  workspaceId: SubSession['workspaceId']
229
+ workspaceRetention?: SubSession['workspaceRetention']
229
230
  broadcastGroupId?: string
230
231
  summaryRef?: SubSession['summaryRef']
231
232
  archiveRef?: SubSession['archiveRef']
@@ -1126,6 +1127,7 @@ function serializeSubSession(s: SubSession, tenantId: TenantId): PersistedSubSes
1126
1127
  failureMode: s.failureMode,
1127
1128
  completionMode: s.completionMode,
1128
1129
  workspaceId: s.workspaceId,
1130
+ ...(s.workspaceRetention !== undefined && { workspaceRetention: s.workspaceRetention }),
1129
1131
  ...(s.broadcastGroupId !== undefined && { broadcastGroupId: s.broadcastGroupId }),
1130
1132
  ...(s.summaryRef !== undefined && { summaryRef: s.summaryRef }),
1131
1133
  ...(s.archiveRef !== undefined && { archiveRef: s.archiveRef }),
@@ -1146,6 +1148,7 @@ function deserializeSubSession(s: PersistedSubSession): SubSession {
1146
1148
  failureMode: s.failureMode,
1147
1149
  completionMode: s.completionMode,
1148
1150
  workspaceId: s.workspaceId,
1151
+ ...(s.workspaceRetention !== undefined && { workspaceRetention: s.workspaceRetention }),
1149
1152
  ...(s.broadcastGroupId !== undefined && { broadcastGroupId: s.broadcastGroupId }),
1150
1153
  ...(s.summaryRef !== undefined && { summaryRef: s.summaryRef }),
1151
1154
  ...(s.archiveRef !== undefined && { archiveRef: s.archiveRef }),
@@ -508,7 +508,7 @@ const HUMAN_REASON_WORDS: Record<BrowserHumanRequired['reason'], string> = {
508
508
  'two-factor': 'a second sign-in step',
509
509
  captcha: 'a CAPTCHA',
510
510
  'bot-block': 'a bot check',
511
- 'http-auth': 'a password prompt',
511
+ 'http-auth': 'an HTTP authentication challenge',
512
512
  'credential-field': 'a password or one-time-code field',
513
513
  }
514
514
 
@@ -527,7 +527,7 @@ function hostErrorToResult(tool: string, error: BrowserHostError): ToolResult {
527
527
  case 'browser_human_required': {
528
528
  const what = HUMAN_REASON_WORDS[error.reason] ?? 'something only a person can do'
529
529
  const how = error.loginCommand
530
- ? ` The user can sign in with: ${oneLine(error.loginCommand, 300)}`
530
+ ? ` The user can ${error.reason === 'http-auth' ? 'check access' : 'sign in'} with: ${oneLine(error.loginCommand, 300)}`
531
531
  : ''
532
532
  const detail = {
533
533
  origin: error.origin,
@@ -74,20 +74,28 @@ const inputSchema = z.object({
74
74
  folder: z
75
75
  .string()
76
76
  .optional()
77
- .describe("create: folder to run in; leave unset for the session's unless the user named one"),
77
+ .describe(
78
+ "create: existing working directory for the job; leave unset for the session's folder when valid. The file system root, the operator's home directory, NAMZU_HOME and a folder containing NAMZU_HOME are refused. If this session is in one of those, choose an existing project subfolder and set folder explicitly",
79
+ ),
78
80
  tz: z
79
81
  .string()
80
82
  .optional()
81
83
  .describe(
82
84
  "create: IANA time zone; leave unset for the operator's own zone unless the user named another",
83
85
  ),
86
+ notifyOnFinish: z
87
+ .boolean()
88
+ .optional()
89
+ .describe(
90
+ 'create/update: enable routine Namzu desktop completion notices, subject to rate limits (default true). Set false for a script that sends its own notice only when something changes; failure notices stay enabled.',
91
+ ),
84
92
  permissions: z
85
93
  .object({
86
94
  preset: z
87
95
  .enum(['read-only', 'edit-in-folder'])
88
96
  .optional()
89
97
  .describe(
90
- 'read-only: read/glob/grep/ls only. edit-in-folder: also edit and write, bash asks',
98
+ 'read-only: read/glob/grep/ls only; its bash deny blocks every script. edit-in-folder: also edit and write, bash asks. For a pure script, omit the preset and set rules to {} with unmatched: deny',
91
99
  ),
92
100
  unmatched: z
93
101
  .enum(['park', 'deny'])
@@ -120,7 +128,7 @@ const inputSchema = z.object({
120
128
  })
121
129
  .optional()
122
130
  .describe(
123
- 'create: REQUIRED explicit permission set; there is no default. A pure script cannot use a browser grant. update: the whole new set, only when the permissions change',
131
+ 'create: REQUIRED explicit permission set; there is no default. For a pure script, use {rules:{}, unmatched:"deny"} without a preset unless you intend deny rules: read-only denies bash and blocks every script. A pure script cannot use a browser grant. update: the whole new set, only when the permissions change',
124
132
  ),
125
133
  budget: z
126
134
  .object({
@@ -311,6 +319,7 @@ async function create(
311
319
  ...(input.prompt !== undefined ? { prompt: input.prompt } : {}),
312
320
  ...(input.folder !== undefined ? { folder: input.folder } : {}),
313
321
  ...(input.tz !== undefined ? { tz: input.tz } : {}),
322
+ ...(input.notifyOnFinish !== undefined ? { notifyOnFinish: input.notifyOnFinish } : {}),
314
323
  permissions,
315
324
  ...(input.budget ? { budget: input.budget } : {}),
316
325
  }
@@ -352,7 +361,7 @@ async function create(
352
361
  ? `Job "${created.name}" was created paused. The operator can resume it with /schedule.`
353
362
  : runKind === 'script'
354
363
  ? `Job "${created.name}" was created. It runs ${preview.schedule}, with nobody watching; results are recorded in its history and may arrive as a notification. It creates no session.`
355
- : `Job "${created.name}" was created. It runs ${preview.schedule}, with nobody watching; results arrive as a notification and a session.`
364
+ : `Job "${created.name}" was created. It runs ${preview.schedule}, with nobody watching; results are recorded in a session. Completion notices ${draft.notifyOnFinish === false ? 'are off' : 'are enabled, subject to rate limits'}.`
356
365
  return {
357
366
  success: true,
358
367
  output: created.note ? `${said} ${created.note}` : said,
@@ -381,6 +390,7 @@ const CHANGEABLE = [
381
390
  'when',
382
391
  'folder',
383
392
  'tz',
393
+ 'notifyOnFinish',
384
394
  'permissions',
385
395
  'budget',
386
396
  'kind',
@@ -439,6 +449,7 @@ async function update(
439
449
  ...(input.when !== undefined ? { when: input.when } : {}),
440
450
  ...(input.folder !== undefined ? { folder: input.folder } : {}),
441
451
  ...(input.tz !== undefined ? { tz: input.tz } : {}),
452
+ ...(input.notifyOnFinish !== undefined ? { notifyOnFinish: input.notifyOnFinish } : {}),
442
453
  ...(permissions ? { permissions } : {}),
443
454
  ...(input.budget ? { budget: input.budget } : {}),
444
455
  ...(input.kind !== undefined ? { runKind: input.kind } : {}),
@@ -543,7 +554,7 @@ export function buildScheduleTools(host: ScheduleToolHost): ToolDefinition[] {
543
554
  defineTool({
544
555
  name: SCHEDULE_TOOL_NAME,
545
556
  description:
546
- "Manage the operator's scheduled jobs: model prompts or fixed scripts that run later in a folder, with nobody watching, under an explicit permission set. Use it only when the user asks for something to happen on a schedule. create, update, resume and delete are confirmed by the operator; pause is not. A job needs name, when and permissions (unmatched: park or deny, plus a preset, rules or a browser grant). agent and script+agent also need prompt; script and script+agent also need script. A pure script has no prompt, model, agent budget, browser grant or session; set script.timeoutMs to limit it. To change a job, update it with job and only the fields that change; do not delete and recreate it. Leave every other field (folder, tz, execution, budget, headed) unset unless the user asked for it: the defaults are the operator's, and the confirmation marks each value you chose. Scheduled runs cannot ask questions.",
557
+ "Manage the operator's scheduled jobs: model prompts or fixed scripts that run later in a folder, with nobody watching, under an explicit permission set. Use it only when the user asks for something to happen on a schedule. create, update, resume and delete are confirmed by the operator; pause is not. A job needs name, when and permissions (unmatched: park or deny, plus a preset, rules or a browser grant). agent and script+agent also need prompt; script and script+agent also need script. For a pure script, use permissions {rules:{},unmatched:'deny'} without a preset unless you intend deny rules: read-only denies bash and blocks every script. A pure script has no prompt, model, agent budget, browser grant or session; set script.timeoutMs to limit it. To change a job, update it with job and only the fields that change; do not delete and recreate it. Leave folder unset when the session folder is valid; home, root and NAMZU_HOME are invalid, so choose an existing project subfolder there. Leave tz, execution, budget and headed unset unless the user asked for them: the defaults are the operator's, and the confirmation marks each value you chose. Scheduled runs cannot ask questions.",
547
558
  inputSchema,
548
559
  category: 'custom',
549
560
  permissions: [],
@@ -40,6 +40,8 @@ export interface ScheduleJobDraft {
40
40
  readonly folder?: string
41
41
  /** IANA zone for a cron expression or a local time. Absent: the host's. */
42
42
  readonly tz?: string
43
+ /** Enable routine completion notices. Absent: the host's usual setting. */
44
+ readonly notifyOnFinish?: boolean
43
45
  readonly permissions: {
44
46
  readonly preset?: 'read-only' | 'edit-in-folder'
45
47
  /**
@@ -109,6 +111,8 @@ export interface ScheduleJobPreview {
109
111
  }
110
112
  /** The schedule in words, with its zone. */
111
113
  readonly schedule: string
114
+ /** Whether a completed run sends a Namzu desktop notice; absent for older hosts. */
115
+ readonly notifyOnFinish?: boolean
112
116
  /** The next fire times, ISO-8601 UTC. */
113
117
  readonly nextFireTimes: readonly string[]
114
118
  /** The permission set expanded to one line per rule, config denies included. */
@@ -164,6 +168,8 @@ export interface ScheduleJobChanges {
164
168
  readonly when?: string
165
169
  readonly folder?: string
166
170
  readonly tz?: string
171
+ /** Whether routine Namzu desktop completion notices are enabled. */
172
+ readonly notifyOnFinish?: boolean
167
173
  readonly permissions?: ScheduleJobDraft['permissions']
168
174
  readonly budget?: ScheduleJobDraft['budget']
169
175
  /**
@@ -3,8 +3,9 @@ import type { TaskId } from '../ids/index.js'
3
3
  import type { AgentPersona } from '../persona/index.js'
4
4
  import type { CancelCause } from '../session/cancel-cause.js'
5
5
  import type { ChildSessionLifecycleEvent, SessionEventListener } from '../session/events.js'
6
+ import type { WorkspaceRef } from '../workspace/ref.js'
6
7
  import type { AgentRuntimeContext, BaseAgentConfig, BaseAgentResult } from './base.js'
7
- import type { AgentTaskState } from './task.js'
8
+ import type { AgentTaskState, ChildWorkspaceRequest } from './task.js'
8
9
 
9
10
  export interface TaskHandle {
10
11
  readonly taskId: TaskId
@@ -13,6 +14,8 @@ export interface TaskHandle {
13
14
  readonly result?: BaseAgentResult
14
15
  readonly createdAt: number
15
16
  readonly completedAt?: number
17
+ /** The workspace assigned to an explicitly isolated child, when admitted. */
18
+ readonly workspace?: WorkspaceRef
16
19
  }
17
20
 
18
21
  /**
@@ -29,6 +32,8 @@ export interface TaskHandle {
29
32
  export type SiblingFailurePolicy = 'continue' | 'cancel-siblings'
30
33
 
31
34
  export interface CreateTaskOptions {
35
+ /** Per-task filesystem choice, forwarded to the local manager at admission. */
36
+ readonly workspace?: ChildWorkspaceRequest
32
37
  /**
33
38
  * Revalidate host authority at actual admission, including after a capacity wait.
34
39
  * Queue retries may invoke this more than once; checks must tolerate repeated calls.
@@ -1,6 +1,6 @@
1
1
  import type { SessionTokenBudget } from '../../store/budget/index.js'
2
2
  import type { ActorRef } from '../../types/session/actor.js'
3
- import type { WorkspaceBackendKind } from '../../types/workspace/ref.js'
3
+ import type { WorkspaceBackendKind, WorkspaceRef } from '../../types/workspace/ref.js'
4
4
  import type { ResumeHandler } from '../hitl/index.js'
5
5
  import type { SessionId, TaskId, TenantId, TurnId } from '../ids/index.js'
6
6
  import type { Message } from '../message/index.js'
@@ -19,6 +19,19 @@ export type AgentTaskState =
19
19
  | 'rejected'
20
20
  | 'input-required'
21
21
 
22
+ /** Per-spawn filesystem choice. Omission preserves the manager's existing behavior. */
23
+ export type ChildWorkspaceRequest =
24
+ | { readonly mode: 'shared' }
25
+ | {
26
+ readonly mode: 'isolated'
27
+ readonly backend: 'git-worktree'
28
+ readonly baseRef?: string
29
+ /** Relative directory within the checkout where this child starts. */
30
+ readonly subdirectory?: string
31
+ /** The existing SDK behavior is `dispose`; CLI delegates select `retain`. */
32
+ readonly retention?: 'dispose' | 'retain'
33
+ }
34
+
22
35
  export function isTerminalAgentTaskState(state: AgentTaskState): boolean {
23
36
  return state === 'completed' || state === 'failed' || state === 'canceled' || state === 'rejected'
24
37
  }
@@ -206,6 +219,8 @@ export interface AgentTask {
206
219
  pendingMessages: Message[]
207
220
  createdAt: number
208
221
  completedAt?: number
222
+ /** Populated after an explicitly isolated spawn is admitted. */
223
+ workspace?: WorkspaceRef
209
224
 
210
225
  evictAfter?: number
211
226
 
@@ -219,6 +234,8 @@ export interface AgentTask {
219
234
  * WorkspaceRef triple atomically on every spawn.
220
235
  */
221
236
  export interface SendMessageOptions {
237
+ /** Explicit child filesystem policy; omitted preserves legacy backend behavior. */
238
+ readonly workspace?: ChildWorkspaceRequest
222
239
  /**
223
240
  * Revalidate host authority before admission, including after a capacity wait.
224
241
  * Queue retries may invoke this more than once; checks must tolerate repeated calls.
@@ -287,6 +304,9 @@ export interface SendMessageOptions {
287
304
  }
288
305
 
289
306
  export interface AgentManagerConfig {
307
+ /** When neither task workspace field is set, use the registered backend (legacy) or share cwd. */
308
+ workspaceDefault?: 'registered' | 'shared'
309
+
290
310
  /** Reject a full parent immediately (default), or retain bounded pending task handles. */
291
311
  capacityBehavior?: 'reject' | 'queue'
292
312
 
@@ -178,6 +178,14 @@ export interface MCPJsonRpcMessage {
178
178
  error?: MCPJsonRpcError
179
179
  }
180
180
 
181
+ /** A validated, bounded update from one MCP tool call. */
182
+ export interface MCPProgressUpdate {
183
+ readonly progress: number
184
+ readonly total?: number
185
+ /** Server text with terminal controls removed, limited to 512 UTF-8 bytes. */
186
+ readonly message?: string
187
+ }
188
+
181
189
  /** Authority for one MCP JSON-RPC request. */
182
190
  export interface MCPRequestOptions {
183
191
  /**
@@ -187,6 +195,12 @@ export interface MCPRequestOptions {
187
195
  * waiting, not that an already-started remote side effect was rolled back.
188
196
  */
189
197
  readonly signal?: AbortSignal
198
+ /**
199
+ * Receive progress for this `tools/call` only. The client adds a unique
200
+ * `_meta.progressToken` when this is supplied and stops delivery as soon as
201
+ * the request completes, fails or is cancelled. Other methods ignore it.
202
+ */
203
+ readonly onProgress?: (update: MCPProgressUpdate) => void
190
204
  /**
191
205
  * Extra headers for this one request, merged over the transport's static
192
206
  * config headers (a collision resolves to this value) and under this same
@@ -100,6 +100,8 @@ export interface SubSession {
100
100
  failureMode: FailureMode
101
101
  completionMode: CompletionMode
102
102
  workspaceId: WorkspaceId | null
103
+ /** Keep this delegated workspace when the child ends or its session is archived. */
104
+ workspaceRetention?: 'retain'
103
105
  /**
104
106
  * For interventions, the immutable artifact being addressed. Chains form
105
107
  * a strict acyclic DAG — see session-hierarchy.md §4.5.