@namzu/sdk 48.1.0 → 48.3.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.
@@ -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
  /**
@@ -30,7 +30,7 @@ export interface ComputerUseCapabilities {
30
30
  readonly keyboard: boolean
31
31
  readonly cursorPosition: boolean
32
32
  readonly clipboard: boolean
33
- /** Exact action subset when known. Refines the broad flags; absent retains their legacy interpretation. */
33
+ /** Display action subset when known. Window capture and input are a separate path. */
34
34
  readonly supportedActions?: readonly ComputerUseAction['type'][]
35
35
  /** Supported click buttons; absent leaves button admission to the host. */
36
36
  readonly mouseClickButtons?: readonly MouseButton[]
@@ -50,6 +50,16 @@ export interface ComputerUseCapabilities {
50
50
  * offer `list_windows` or `focus_window`, even when the methods exist.
51
51
  */
52
52
  readonly windows?: boolean
53
+ /**
54
+ * The host can capture and act on one named window without sharing the
55
+ * whole desktop. Requires `captureWindow` and `executeWindow`.
56
+ */
57
+ readonly windowCapture?: boolean
58
+ /**
59
+ * Whether scoped pixel scrolling can be delivered safely. Explicit false
60
+ * refuses it before a batch starts; absent retains host-defined behavior.
61
+ */
62
+ readonly windowScroll?: boolean
53
63
  /**
54
64
  * The host implements {@link ComputerUseHost.captureRegion}. Absent or
55
65
  * false, `zoom` still works: the tool crops a full capture instead, which
@@ -71,12 +81,13 @@ export interface ComputerUseCapabilities {
71
81
  // ---------------------------------------------------------------------------
72
82
  // Geometry + screenshot payload
73
83
  //
74
- // Units, once for the whole file: every coordinate and size a host accepts or
75
- // returns is in PHYSICAL pixels — the pixels of the captured bitmap, not
76
- // logical points or DPI-scaled units. A 3440x1440 monitor at 150 % scaling is
77
- // 3440x1440 here. A point a host is asked to act on is relative to the
78
- // top-left of the display it last captured (the primary display until a host
79
- // offers display selection); the host adds that display's origin itself.
84
+ // Display actions use PHYSICAL pixels, not logical points or DPI-scaled
85
+ // units. A 3440x1440 monitor at 150 % scaling is 3440x1440 here. A point a
86
+ // host is asked to act on is relative to the top-left of the display it last
87
+ // captured (the primary display until a host offers display selection); the
88
+ // host adds that display's origin itself. Window actions are the explicit
89
+ // exception: their coordinates are pixels of captureWindow's returned PNG,
90
+ // which the window driver may have downscaled.
80
91
  // Window and UI-element bounds are the exception and say so: they are in
81
92
  // virtual-desktop physical pixels, because a window can span displays.
82
93
  // ---------------------------------------------------------------------------
@@ -146,6 +157,45 @@ export interface WindowInfo {
146
157
  readonly minimized: boolean
147
158
  }
148
159
 
160
+ /** A PNG of one window. Its pixels are window-local, not display-relative. */
161
+ export interface WindowScreenshotResult {
162
+ readonly data: Buffer
163
+ readonly mimeType: 'image/png'
164
+ /** Pixel size of the exact PNG returned by the host. */
165
+ readonly width: number
166
+ readonly height: number
167
+ readonly window: WindowInfo
168
+ /**
169
+ * Opaque capture token. The host rejects actions after another window
170
+ * capture, driver restart, session revival, or target geometry change.
171
+ */
172
+ readonly captureId: string
173
+ /** A limitation of this capture, when the driver reports one. */
174
+ readonly captureCoverage?: string
175
+ }
176
+
177
+ /** How input is delivered to a captured window. Foreground may briefly activate it. */
178
+ export type WindowDeliveryMode = 'background' | 'foreground'
179
+
180
+ /** Window-local actions. A window-scoped mouse move is not a real OS move. */
181
+ export type WindowInputAction =
182
+ | Extract<ComputerUseAction, { readonly type: 'mouse_click' | 'mouse_drag' | 'scroll' }>
183
+ /** Foreground delivery sends text to the verified target window. */
184
+ | {
185
+ readonly type: 'type_text'
186
+ readonly text: string
187
+ readonly delivery_mode?: WindowDeliveryMode
188
+ }
189
+ /**
190
+ * `foreground` explicitly permits the host to bring the verified target
191
+ * window forward for keys its background input path cannot deliver.
192
+ */
193
+ | {
194
+ readonly type: 'key'
195
+ readonly keys: string
196
+ readonly delivery_mode?: WindowDeliveryMode
197
+ }
198
+
149
199
  /**
150
200
  * What {@link ComputerUseHost.focusWindow} achieved. Bringing a window to
151
201
  * the front is a request the operating system can refuse (Windows'
@@ -334,6 +384,14 @@ export interface ComputerUseHost {
334
384
  * with {@link ComputerUseCapabilities.windows}.
335
385
  */
336
386
  focusWindow?(id: string): Promise<FocusWindowResult>
387
+ /** Capture a named window. Never silently replace a failed capture with the desktop. */
388
+ captureWindow?(id: string): Promise<WindowScreenshotResult>
389
+ /**
390
+ * Act in the PNG pixel space of `captureId`. The host must verify the
391
+ * capture is current and still belongs to the same process/window before
392
+ * dispatching input. No implicit fallback to display input is permitted.
393
+ */
394
+ executeWindow?(captureId: string, action: WindowInputAction): Promise<void>
337
395
  /**
338
396
  * Capture one region of the current display at full physical resolution.
339
397
  * `rect` is display-relative physical pixels; the result's `width` and