@namzu/cli 29.0.1 → 30.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.
- package/CHANGELOG.md +194 -0
- package/README.md +20 -0
- package/dist/browser/commands.d.ts +29 -0
- package/dist/browser/commands.d.ts.map +1 -0
- package/dist/browser/commands.js +361 -0
- package/dist/browser/commands.js.map +1 -0
- package/dist/browser/control.d.ts +79 -0
- package/dist/browser/control.d.ts.map +1 -0
- package/dist/browser/control.js +140 -0
- package/dist/browser/control.js.map +1 -0
- package/dist/browser/describe.d.ts +12 -0
- package/dist/browser/describe.d.ts.map +1 -0
- package/dist/browser/describe.js +27 -0
- package/dist/browser/describe.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +29 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/acp.d.ts.map +1 -1
- package/dist/commands/acp.js +1 -0
- package/dist/commands/acp.js.map +1 -1
- package/dist/commands/browser.d.ts +7 -0
- package/dist/commands/browser.d.ts.map +1 -0
- package/dist/commands/browser.js +16 -0
- package/dist/commands/browser.js.map +1 -0
- package/dist/commands/drain.d.ts +2 -1
- package/dist/commands/drain.d.ts.map +1 -1
- package/dist/commands/drain.js +6 -3
- package/dist/commands/drain.js.map +1 -1
- package/dist/commands/exec-flags.d.ts +2 -1
- package/dist/commands/exec-flags.d.ts.map +1 -1
- package/dist/commands/exec-flags.js +6 -3
- package/dist/commands/exec-flags.js.map +1 -1
- package/dist/commands/exec-json.d.ts.map +1 -1
- package/dist/commands/exec-json.js +2 -1
- package/dist/commands/exec-json.js.map +1 -1
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +5 -1
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/host-queries.d.ts.map +1 -1
- package/dist/commands/host-queries.js +10 -3
- package/dist/commands/host-queries.js.map +1 -1
- package/dist/commands/schedule.d.ts +9 -0
- package/dist/commands/schedule.d.ts.map +1 -0
- package/dist/commands/schedule.js +126 -0
- package/dist/commands/schedule.js.map +1 -0
- package/dist/commands/serve.d.ts +3 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +5 -3
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/skills.d.ts +10 -0
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +23 -7
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/upgrade.d.ts +5 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +11 -0
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/config/load.d.ts +39 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +232 -1
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +78 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/config/user-config.d.ts +23 -0
- package/dist/config/user-config.d.ts.map +1 -0
- package/dist/config/user-config.js +48 -0
- package/dist/config/user-config.js.map +1 -0
- package/dist/context/capabilities.d.ts +1 -1
- package/dist/context/capabilities.d.ts.map +1 -1
- package/dist/context/capabilities.js +1 -0
- package/dist/context/capabilities.js.map +1 -1
- package/dist/context/environment.d.ts +26 -3
- package/dist/context/environment.d.ts.map +1 -1
- package/dist/context/environment.js +68 -9
- package/dist/context/environment.js.map +1 -1
- package/dist/doctor/checks/browser.d.ts +15 -0
- package/dist/doctor/checks/browser.d.ts.map +1 -0
- package/dist/doctor/checks/browser.js +63 -0
- package/dist/doctor/checks/browser.js.map +1 -0
- package/dist/doctor/checks/index.d.ts +4 -1
- package/dist/doctor/checks/index.d.ts.map +1 -1
- package/dist/doctor/checks/index.js +8 -1
- package/dist/doctor/checks/index.js.map +1 -1
- package/dist/doctor/checks/scheduler.d.ts +10 -0
- package/dist/doctor/checks/scheduler.d.ts.map +1 -0
- package/dist/doctor/checks/scheduler.js +74 -0
- package/dist/doctor/checks/scheduler.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/notifications/desktop/freedesktop.d.ts +10 -0
- package/dist/integrations/notifications/desktop/freedesktop.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/freedesktop.js +33 -0
- package/dist/integrations/notifications/desktop/freedesktop.js.map +1 -0
- package/dist/integrations/notifications/desktop/macos.d.ts +6 -0
- package/dist/integrations/notifications/desktop/macos.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/macos.js +17 -0
- package/dist/integrations/notifications/desktop/macos.js.map +1 -0
- package/dist/integrations/notifications/desktop/sanitize.d.ts +16 -0
- package/dist/integrations/notifications/desktop/sanitize.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/sanitize.js +49 -0
- package/dist/integrations/notifications/desktop/sanitize.js.map +1 -0
- package/dist/integrations/notifications/desktop/throttle.d.ts +10 -0
- package/dist/integrations/notifications/desktop/throttle.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/throttle.js +39 -0
- package/dist/integrations/notifications/desktop/throttle.js.map +1 -0
- package/dist/integrations/notifications/desktop/windows-toast.d.ts +23 -0
- package/dist/integrations/notifications/desktop/windows-toast.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/windows-toast.js +56 -0
- package/dist/integrations/notifications/desktop/windows-toast.js.map +1 -0
- package/dist/integrations/notifications/desktop.d.ts +84 -0
- package/dist/integrations/notifications/desktop.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop.js +199 -0
- package/dist/integrations/notifications/desktop.js.map +1 -0
- package/dist/integrations/plugins/runtime.d.ts +8 -2
- package/dist/integrations/plugins/runtime.d.ts.map +1 -1
- package/dist/integrations/plugins/runtime.js +14 -8
- package/dist/integrations/plugins/runtime.js.map +1 -1
- package/dist/integrations/providers/harness-credentials.d.ts +9 -4
- package/dist/integrations/providers/harness-credentials.d.ts.map +1 -1
- package/dist/integrations/providers/harness-credentials.js +16 -8
- package/dist/integrations/providers/harness-credentials.js.map +1 -1
- package/dist/integrations/resident/session-step.d.ts.map +1 -1
- package/dist/integrations/resident/session-step.js +1 -0
- package/dist/integrations/resident/session-step.js.map +1 -1
- package/dist/integrations/subagents/runtime.d.ts +6 -0
- package/dist/integrations/subagents/runtime.d.ts.map +1 -1
- package/dist/integrations/subagents/runtime.js +14 -5
- package/dist/integrations/subagents/runtime.js.map +1 -1
- package/dist/integrations/web/open-url.d.ts +24 -0
- package/dist/integrations/web/open-url.d.ts.map +1 -0
- package/dist/integrations/web/open-url.js +73 -0
- package/dist/integrations/web/open-url.js.map +1 -0
- package/dist/permissions/browser-sites.d.ts +95 -0
- package/dist/permissions/browser-sites.d.ts.map +1 -0
- package/dist/permissions/browser-sites.js +270 -0
- package/dist/permissions/browser-sites.js.map +1 -0
- package/dist/schedule/build.d.ts +86 -0
- package/dist/schedule/build.d.ts.map +1 -0
- package/dist/schedule/build.js +267 -0
- package/dist/schedule/build.js.map +1 -0
- package/dist/schedule/changes.d.ts +28 -0
- package/dist/schedule/changes.d.ts.map +1 -0
- package/dist/schedule/changes.js +65 -0
- package/dist/schedule/changes.js.map +1 -0
- package/dist/schedule/commands/add.d.ts +24 -0
- package/dist/schedule/commands/add.d.ts.map +1 -0
- package/dist/schedule/commands/add.js +447 -0
- package/dist/schedule/commands/add.js.map +1 -0
- package/dist/schedule/commands/args.d.ts +22 -0
- package/dist/schedule/commands/args.d.ts.map +1 -0
- package/dist/schedule/commands/args.js +80 -0
- package/dist/schedule/commands/args.js.map +1 -0
- package/dist/schedule/commands/confirm-prompt.d.ts +6 -0
- package/dist/schedule/commands/confirm-prompt.d.ts.map +1 -0
- package/dist/schedule/commands/confirm-prompt.js +21 -0
- package/dist/schedule/commands/confirm-prompt.js.map +1 -0
- package/dist/schedule/commands/lifecycle.d.ts +39 -0
- package/dist/schedule/commands/lifecycle.d.ts.map +1 -0
- package/dist/schedule/commands/lifecycle.js +586 -0
- package/dist/schedule/commands/lifecycle.js.map +1 -0
- package/dist/schedule/commands/list.d.ts +33 -0
- package/dist/schedule/commands/list.d.ts.map +1 -0
- package/dist/schedule/commands/list.js +206 -0
- package/dist/schedule/commands/list.js.map +1 -0
- package/dist/schedule/commands/logs.d.ts +7 -0
- package/dist/schedule/commands/logs.d.ts.map +1 -0
- package/dist/schedule/commands/logs.js +106 -0
- package/dist/schedule/commands/logs.js.map +1 -0
- package/dist/schedule/commands/service.d.ts +16 -0
- package/dist/schedule/commands/service.d.ts.map +1 -0
- package/dist/schedule/commands/service.js +458 -0
- package/dist/schedule/commands/service.js.map +1 -0
- package/dist/schedule/daemon/daemon.d.ts +156 -0
- package/dist/schedule/daemon/daemon.d.ts.map +1 -0
- package/dist/schedule/daemon/daemon.js +1253 -0
- package/dist/schedule/daemon/daemon.js.map +1 -0
- package/dist/schedule/daemon/endpoint.d.ts +38 -0
- package/dist/schedule/daemon/endpoint.d.ts.map +1 -0
- package/dist/schedule/daemon/endpoint.js +158 -0
- package/dist/schedule/daemon/endpoint.js.map +1 -0
- package/dist/schedule/daemon/exit.d.ts +8 -0
- package/dist/schedule/daemon/exit.d.ts.map +1 -0
- package/dist/schedule/daemon/exit.js +8 -0
- package/dist/schedule/daemon/exit.js.map +1 -0
- package/dist/schedule/daemon/log.d.ts +12 -0
- package/dist/schedule/daemon/log.d.ts.map +1 -0
- package/dist/schedule/daemon/log.js +53 -0
- package/dist/schedule/daemon/log.js.map +1 -0
- package/dist/schedule/daemon/notify.d.ts +38 -0
- package/dist/schedule/daemon/notify.d.ts.map +1 -0
- package/dist/schedule/daemon/notify.js +115 -0
- package/dist/schedule/daemon/notify.js.map +1 -0
- package/dist/schedule/daemon/retention.d.ts +16 -0
- package/dist/schedule/daemon/retention.d.ts.map +1 -0
- package/dist/schedule/daemon/retention.js +46 -0
- package/dist/schedule/daemon/retention.js.map +1 -0
- package/dist/schedule/daemon/sessions.d.ts +23 -0
- package/dist/schedule/daemon/sessions.d.ts.map +1 -0
- package/dist/schedule/daemon/sessions.js +52 -0
- package/dist/schedule/daemon/sessions.js.map +1 -0
- package/dist/schedule/env.d.ts +32 -0
- package/dist/schedule/env.d.ts.map +1 -0
- package/dist/schedule/env.js +106 -0
- package/dist/schedule/env.js.map +1 -0
- package/dist/schedule/fire/browser-preflight.d.ts +41 -0
- package/dist/schedule/fire/browser-preflight.d.ts.map +1 -0
- package/dist/schedule/fire/browser-preflight.js +73 -0
- package/dist/schedule/fire/browser-preflight.js.map +1 -0
- package/dist/schedule/fire/calls.d.ts +49 -0
- package/dist/schedule/fire/calls.d.ts.map +1 -0
- package/dist/schedule/fire/calls.js +114 -0
- package/dist/schedule/fire/calls.js.map +1 -0
- package/dist/schedule/fire/fire.d.ts +78 -0
- package/dist/schedule/fire/fire.d.ts.map +1 -0
- package/dist/schedule/fire/fire.js +490 -0
- package/dist/schedule/fire/fire.js.map +1 -0
- package/dist/schedule/fire/result.d.ts +13 -0
- package/dist/schedule/fire/result.d.ts.map +1 -0
- package/dist/schedule/fire/result.js +18 -0
- package/dist/schedule/fire/result.js.map +1 -0
- package/dist/schedule/fire/unattended-note.d.ts +22 -0
- package/dist/schedule/fire/unattended-note.d.ts.map +1 -0
- package/dist/schedule/fire/unattended-note.js +46 -0
- package/dist/schedule/fire/unattended-note.js.map +1 -0
- package/dist/schedule/floor.d.ts +136 -0
- package/dist/schedule/floor.d.ts.map +1 -0
- package/dist/schedule/floor.js +1289 -0
- package/dist/schedule/floor.js.map +1 -0
- package/dist/schedule/folder.d.ts +34 -0
- package/dist/schedule/folder.d.ts.map +1 -0
- package/dist/schedule/folder.js +84 -0
- package/dist/schedule/folder.js.map +1 -0
- package/dist/schedule/paths.d.ts +49 -0
- package/dist/schedule/paths.d.ts.map +1 -0
- package/dist/schedule/paths.js +53 -0
- package/dist/schedule/paths.js.map +1 -0
- package/dist/schedule/policy.d.ts +141 -0
- package/dist/schedule/policy.d.ts.map +1 -0
- package/dist/schedule/policy.js +378 -0
- package/dist/schedule/policy.js.map +1 -0
- package/dist/schedule/resume-command.d.ts +36 -0
- package/dist/schedule/resume-command.d.ts.map +1 -0
- package/dist/schedule/resume-command.js +72 -0
- package/dist/schedule/resume-command.js.map +1 -0
- package/dist/schedule/service/detect.d.ts +22 -0
- package/dist/schedule/service/detect.d.ts.map +1 -0
- package/dist/schedule/service/detect.js +29 -0
- package/dist/schedule/service/detect.js.map +1 -0
- package/dist/schedule/service/index.d.ts +48 -0
- package/dist/schedule/service/index.d.ts.map +1 -0
- package/dist/schedule/service/index.js +361 -0
- package/dist/schedule/service/index.js.map +1 -0
- package/dist/schedule/service/launchd.d.ts +24 -0
- package/dist/schedule/service/launchd.d.ts.map +1 -0
- package/dist/schedule/service/launchd.js +84 -0
- package/dist/schedule/service/launchd.js.map +1 -0
- package/dist/schedule/service/manifest.d.ts +44 -0
- package/dist/schedule/service/manifest.d.ts.map +1 -0
- package/dist/schedule/service/manifest.js +16 -0
- package/dist/schedule/service/manifest.js.map +1 -0
- package/dist/schedule/service/names.d.ts +9 -0
- package/dist/schedule/service/names.d.ts.map +1 -0
- package/dist/schedule/service/names.js +22 -0
- package/dist/schedule/service/names.js.map +1 -0
- package/dist/schedule/service/quote.d.ts +24 -0
- package/dist/schedule/service/quote.d.ts.map +1 -0
- package/dist/schedule/service/quote.js +64 -0
- package/dist/schedule/service/quote.js.map +1 -0
- package/dist/schedule/service/runner.d.ts +17 -0
- package/dist/schedule/service/runner.d.ts.map +1 -0
- package/dist/schedule/service/runner.js +31 -0
- package/dist/schedule/service/runner.js.map +1 -0
- package/dist/schedule/service/systemd.d.ts +37 -0
- package/dist/schedule/service/systemd.d.ts.map +1 -0
- package/dist/schedule/service/systemd.js +96 -0
- package/dist/schedule/service/systemd.js.map +1 -0
- package/dist/schedule/service/windows-task.d.ts +58 -0
- package/dist/schedule/service/windows-task.d.ts.map +1 -0
- package/dist/schedule/service/windows-task.js +199 -0
- package/dist/schedule/service/windows-task.js.map +1 -0
- package/dist/schedule/service/wsl.d.ts +69 -0
- package/dist/schedule/service/wsl.d.ts.map +1 -0
- package/dist/schedule/service/wsl.js +121 -0
- package/dist/schedule/service/wsl.js.map +1 -0
- package/dist/schedule/store/atomic.d.ts +43 -0
- package/dist/schedule/store/atomic.d.ts.map +1 -0
- package/dist/schedule/store/atomic.js +135 -0
- package/dist/schedule/store/atomic.js.map +1 -0
- package/dist/schedule/store/claims.d.ts +26 -0
- package/dist/schedule/store/claims.d.ts.map +1 -0
- package/dist/schedule/store/claims.js +57 -0
- package/dist/schedule/store/claims.js.map +1 -0
- package/dist/schedule/store/digest.d.ts +18 -0
- package/dist/schedule/store/digest.d.ts.map +1 -0
- package/dist/schedule/store/digest.js +139 -0
- package/dist/schedule/store/digest.js.map +1 -0
- package/dist/schedule/store/history.d.ts +21 -0
- package/dist/schedule/store/history.d.ts.map +1 -0
- package/dist/schedule/store/history.js +114 -0
- package/dist/schedule/store/history.js.map +1 -0
- package/dist/schedule/store/jobs.d.ts +61 -0
- package/dist/schedule/store/jobs.d.ts.map +1 -0
- package/dist/schedule/store/jobs.js +210 -0
- package/dist/schedule/store/jobs.js.map +1 -0
- package/dist/schedule/store/state.d.ts +19 -0
- package/dist/schedule/store/state.d.ts.map +1 -0
- package/dist/schedule/store/state.js +38 -0
- package/dist/schedule/store/state.js.map +1 -0
- package/dist/schedule/types.d.ts +283 -0
- package/dist/schedule/types.d.ts.map +1 -0
- package/dist/schedule/types.js +9 -0
- package/dist/schedule/types.js.map +1 -0
- package/dist/skills/catalog.d.ts +96 -0
- package/dist/skills/catalog.d.ts.map +1 -0
- package/dist/skills/catalog.js +226 -0
- package/dist/skills/catalog.js.map +1 -0
- package/dist/skills/directory.d.ts +38 -0
- package/dist/skills/directory.d.ts.map +1 -0
- package/dist/skills/directory.js +51 -0
- package/dist/skills/directory.js.map +1 -0
- package/dist/skills/save.d.ts +148 -0
- package/dist/skills/save.d.ts.map +1 -0
- package/dist/skills/save.js +344 -0
- package/dist/skills/save.js.map +1 -0
- package/dist/skills/store.d.ts +103 -16
- package/dist/skills/store.d.ts.map +1 -1
- package/dist/skills/store.js +227 -30
- package/dist/skills/store.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +609 -74
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/LiveActivity.d.ts +8 -1
- package/dist/tui/LiveActivity.d.ts.map +1 -1
- package/dist/tui/LiveActivity.js +20 -4
- package/dist/tui/LiveActivity.js.map +1 -1
- package/dist/tui/PermissionOverlay.d.ts +36 -4
- package/dist/tui/PermissionOverlay.d.ts.map +1 -1
- package/dist/tui/PermissionOverlay.js +135 -15
- package/dist/tui/PermissionOverlay.js.map +1 -1
- package/dist/tui/SaveSkillOverlay.d.ts +33 -0
- package/dist/tui/SaveSkillOverlay.d.ts.map +1 -0
- package/dist/tui/SaveSkillOverlay.js +118 -0
- package/dist/tui/SaveSkillOverlay.js.map +1 -0
- package/dist/tui/agent.d.ts +208 -6
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +371 -58
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/browser-notices.d.ts +33 -0
- package/dist/tui/browser-notices.d.ts.map +1 -0
- package/dist/tui/browser-notices.js +102 -0
- package/dist/tui/browser-notices.js.map +1 -0
- package/dist/tui/open-browser.d.ts +29 -1
- package/dist/tui/open-browser.d.ts.map +1 -1
- package/dist/tui/open-browser.js +83 -11
- package/dist/tui/open-browser.js.map +1 -1
- package/dist/tui/permission-review.d.ts +10 -1
- package/dist/tui/permission-review.d.ts.map +1 -1
- package/dist/tui/permission-review.js +228 -22
- package/dist/tui/permission-review.js.map +1 -1
- package/dist/tui/schedule/host-commands.d.ts +34 -0
- package/dist/tui/schedule/host-commands.d.ts.map +1 -0
- package/dist/tui/schedule/host-commands.js +310 -0
- package/dist/tui/schedule/host-commands.js.map +1 -0
- package/dist/tui/schedule/integration.d.ts +62 -0
- package/dist/tui/schedule/integration.d.ts.map +1 -0
- package/dist/tui/schedule/integration.js +145 -0
- package/dist/tui/schedule/integration.js.map +1 -0
- package/dist/tui/schedule/loop-host.d.ts +42 -0
- package/dist/tui/schedule/loop-host.d.ts.map +1 -0
- package/dist/tui/schedule/loop-host.js +153 -0
- package/dist/tui/schedule/loop-host.js.map +1 -0
- package/dist/tui/schedule/resume.d.ts +122 -0
- package/dist/tui/schedule/resume.d.ts.map +1 -0
- package/dist/tui/schedule/resume.js +324 -0
- package/dist/tui/schedule/resume.js.map +1 -0
- package/dist/tui/schedule/startup.d.ts +11 -0
- package/dist/tui/schedule/startup.d.ts.map +1 -0
- package/dist/tui/schedule/startup.js +121 -0
- package/dist/tui/schedule/startup.js.map +1 -0
- package/dist/tui/schedule/tool-host.d.ts +58 -0
- package/dist/tui/schedule/tool-host.d.ts.map +1 -0
- package/dist/tui/schedule/tool-host.js +479 -0
- package/dist/tui/schedule/tool-host.js.map +1 -0
- package/dist/tui/skills/learning.d.ts +74 -0
- package/dist/tui/skills/learning.d.ts.map +1 -0
- package/dist/tui/skills/learning.js +131 -0
- package/dist/tui/skills/learning.js.map +1 -0
- package/dist/tui/skills/suggest-setting.d.ts +22 -0
- package/dist/tui/skills/suggest-setting.d.ts.map +1 -0
- package/dist/tui/skills/suggest-setting.js +55 -0
- package/dist/tui/skills/suggest-setting.js.map +1 -0
- package/dist/tui/skills/suggestion-ledger.d.ts +35 -0
- package/dist/tui/skills/suggestion-ledger.d.ts.map +1 -0
- package/dist/tui/skills/suggestion-ledger.js +52 -0
- package/dist/tui/skills/suggestion-ledger.js.map +1 -0
- package/dist/tui/slashCommands.d.ts +20 -0
- package/dist/tui/slashCommands.d.ts.map +1 -1
- package/dist/tui/slashCommands.js +76 -2
- package/dist/tui/slashCommands.js.map +1 -1
- package/dist/tui/turn-interruption.d.ts +20 -1
- package/dist/tui/turn-interruption.d.ts.map +1 -1
- package/dist/tui/turn-interruption.js +43 -0
- package/dist/tui/turn-interruption.js.map +1 -1
- package/dist/tui/types.d.ts +9 -1
- package/dist/tui/types.d.ts.map +1 -1
- package/package.json +7 -5
- package/skills/README.md +20 -0
- package/skills/browser-automation/SKILL.md +84 -0
- package/skills/schedule-task/SKILL.md +146 -0
- package/skills/skill-creator/SKILL.md +101 -0
package/dist/tui/agent.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createCurrentCredentialReader } from '../integrations/providers/current-credential.js';
|
|
2
|
+
import { createOpenUrlTool } from '../integrations/web/open-url.js';
|
|
2
3
|
import { createWebSearchTool, resolveWebSearch, webSearchLabel, } from '../integrations/web/search.js';
|
|
3
4
|
import { countListedResults, webActivityFromInput, webActivityKind, webCallTitle, } from './web-activity.js';
|
|
4
5
|
/**
|
|
@@ -24,10 +25,11 @@ import { countListedResults, webActivityFromInput, webActivityKind, webCallTitle
|
|
|
24
25
|
* `emptySession()` whose `send()` yields a single error event so the UI
|
|
25
26
|
* renders an actionable hint rather than crashing.
|
|
26
27
|
*/
|
|
27
|
-
import { BOOT_EVENT_NAMES, BackgroundJobRegistry, DiskSessionCheckpointStore, DiskSessionLog, DiskTaskStore, EVENT_NAME_ATTRIBUTE, GuardedFetchProvider, InMemorySessionLog, MarkdownMemoryStore, PromptContributionRegistry, ProviderRegistry, SESSION_GOAL_TOOL_NAMES, SessionPaths, ToolRegistry, WebFetchTool, abandonTurn, batchNeedsReview, buildAskUserQuestionTool, buildMemoryTools, buildResidentHistoryTools, buildResidentToolEvidenceTools, buildSessionGoalTools, compactNow, compactSession, createComputerUseTool, createFileReadTracker, createMemoryPromoter, createMemoryRecallStep, createResidentStepContext, createResidentStepContributions, createReviewHandler, createToolPresenter, ensureProject, generateSessionId, generateTenantId, generateTopicId, generateTurnId, getBuiltinTools, isReviewExempt, isTurnInProgressError, query, resumeSession, seedObservationLedger, webGuidanceContribution, withProviderFallback, } from '@namzu/sdk';
|
|
28
|
+
import { BOOT_EVENT_NAMES, BackgroundJobRegistry, DiskSessionCheckpointStore, DiskSessionLog, DiskTaskStore, EVENT_NAME_ATTRIBUTE, GuardedFetchProvider, InMemorySessionLog, MarkdownMemoryStore, PromptContributionRegistry, ProviderRegistry, SCHEDULE_TOOL_NAME, SESSION_GOAL_TOOL_NAMES, SessionPaths, ToolRegistry, WebFetchTool, abandonTurn, batchNeedsReview, buildAskUserQuestionTool, buildMemoryTools, buildResidentHistoryTools, buildResidentToolEvidenceTools, buildSessionGoalTools, compactNow, compactSession, computerUseUnavailableReason, createBrowserTools, createComputerUseTool, createFileReadTracker, createMemoryPromoter, createMemoryRecallStep, createResidentStepContext, createResidentStepContributions, createReviewHandler, createSkillTool, createToolPresenter, ensureProject, generateSessionId, generateTenantId, generateTopicId, generateTurnId, getBuiltinTools, isReviewExempt, isTurnInProgressError, query, resolveContextWindow, resumeSession, seedObservationLedger, webGuidanceContribution, withProviderFallback, } from '@namzu/sdk';
|
|
28
29
|
import { SubprocessComputerUseHost } from '@namzu/computer-use';
|
|
29
30
|
import { realpath, stat } from 'node:fs/promises';
|
|
30
31
|
import { parse, resolve } from 'node:path';
|
|
32
|
+
import { createBrowserControl, } from '../browser/control.js';
|
|
31
33
|
import { FileCheckpointStore } from '../checkpoints/store.js';
|
|
32
34
|
import { CHECKPOINTED_TOOLS, withCheckpoints } from '../checkpoints/wrap.js';
|
|
33
35
|
import { configuredPassthroughTools, resolveToolResultScreens, unmatchedPassthroughTools, } from '../config/tool-result-screens.js';
|
|
@@ -62,13 +64,16 @@ import { discoverAgentDefinitions } from '../integrations/subagents/definitions.
|
|
|
62
64
|
import { prepareDelegatedEffort } from '../integrations/subagents/model-effort.js';
|
|
63
65
|
import { resolveSubagentParent } from '../integrations/subagents/parent.js';
|
|
64
66
|
import { replaySavedChildrenFor } from '../integrations/subagents/replay.js';
|
|
65
|
-
import { createSubagentRuntime } from '../integrations/subagents/runtime.js';
|
|
67
|
+
import { createSubagentRuntime, } from '../integrations/subagents/runtime.js';
|
|
66
68
|
import { createSavedAgentHistory, createSavedAgentsStep, } from '../integrations/subagents/saved-agents.js';
|
|
67
69
|
import { cliLogger } from '../logging.js';
|
|
68
70
|
import { formatMemoryDiagnostics } from '../memory/presentation.js';
|
|
69
71
|
import { composeMemoryPrompt, readMemory } from '../memory/store.js';
|
|
70
72
|
import { composeStoredMemoryPrompt, describeCuratedNotesImport, describeMemoryMigration, importCuratedNotes, migrateMemoryOnce, saveTypedNote, } from '../memory/typed.js';
|
|
71
73
|
import { createLiveModeControl, permissionChangeReason, } from '../permissions/live-mode.js';
|
|
74
|
+
import { createSessionSkillCatalog } from '../skills/catalog.js';
|
|
75
|
+
import { createSkillDirectoryResolver } from '../skills/directory.js';
|
|
76
|
+
import { SAVE_SKILL_TOOL_NAME } from '../skills/save.js';
|
|
72
77
|
import { projectTurnConversation } from './conversation-history.js';
|
|
73
78
|
import { buildSwitchModelTool } from './model-switch-tool.js';
|
|
74
79
|
import { resolveModelSwitch } from './model-switch.js';
|
|
@@ -287,7 +292,7 @@ async function drainIterator(iterator) {
|
|
|
287
292
|
* Read preferences + run discovery once. Returned context drives the
|
|
288
293
|
* App's lifecycle decision: ready / picker / unhealthy.
|
|
289
294
|
*/
|
|
290
|
-
export async function probeAgentSession() {
|
|
295
|
+
export async function probeAgentSession(options = {}) {
|
|
291
296
|
const read = readPreferences();
|
|
292
297
|
// Bracketed in the log because this is where a boot has stalled without
|
|
293
298
|
// a record on either side: it reads credential files, and on WSL it asks
|
|
@@ -295,7 +300,7 @@ export async function probeAgentSession() {
|
|
|
295
300
|
// and nothing after is this step.
|
|
296
301
|
const discoveryStartedAt = Date.now();
|
|
297
302
|
cliLogger().debug('discovering provider credentials');
|
|
298
|
-
const detected = await discoverProviders();
|
|
303
|
+
const detected = await discoverProviders(options.env ? { env: options.env } : {});
|
|
299
304
|
cliLogger().debug('provider credentials discovered', {
|
|
300
305
|
'namzu.boot.discovery_ms': Date.now() - discoveryStartedAt,
|
|
301
306
|
'namzu.boot.detected_count': detected.length,
|
|
@@ -376,6 +381,9 @@ const EAGER_TOOLS_WHEN_DEFERRED = [
|
|
|
376
381
|
'web_fetch',
|
|
377
382
|
'search_conversation',
|
|
378
383
|
'read_conversation',
|
|
384
|
+
// The skills manifest tells the model to load a skill through this tool;
|
|
385
|
+
// deferring it would make every skill a two-step search first.
|
|
386
|
+
'skill',
|
|
379
387
|
'search_resident_history',
|
|
380
388
|
'read_resident_history',
|
|
381
389
|
'search_resident_tools',
|
|
@@ -483,13 +491,6 @@ function buildToolRegistry(paths, backgroundJobs, checkpoints, screens) {
|
|
|
483
491
|
// after runtime tools are registered. Ordinary CLI task tools are active.
|
|
484
492
|
return { registry, memoryStore, memoryDirectory: directory };
|
|
485
493
|
}
|
|
486
|
-
/** Refresh plugin skill metadata before each provider operation. */
|
|
487
|
-
async function currentPluginSkills(registry) {
|
|
488
|
-
const names = registry.list().map((skill) => skill.metadata.name);
|
|
489
|
-
for (const name of names)
|
|
490
|
-
await registry.load(name, 'metadata');
|
|
491
|
-
return registry.list();
|
|
492
|
-
}
|
|
493
494
|
export async function createAgentSession(prefs, detected, options = {}) {
|
|
494
495
|
const fileObservations = new Map();
|
|
495
496
|
/**
|
|
@@ -906,7 +907,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
906
907
|
let lastSendInteractive = false;
|
|
907
908
|
const boundaryFor = (interactive) => ({
|
|
908
909
|
...(sandbox.provider && sandbox.environment
|
|
909
|
-
? {
|
|
910
|
+
? {
|
|
911
|
+
sandbox: {
|
|
912
|
+
environment: sandbox.environment,
|
|
913
|
+
enforced: sandbox.enforced,
|
|
914
|
+
},
|
|
915
|
+
}
|
|
910
916
|
: {}),
|
|
911
917
|
escape: sandboxEscape === 'refuse'
|
|
912
918
|
? 'refused'
|
|
@@ -962,7 +968,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
962
968
|
*/
|
|
963
969
|
const storedMemoryPrompt = async () => {
|
|
964
970
|
try {
|
|
965
|
-
return {
|
|
971
|
+
return {
|
|
972
|
+
prompt: composeStoredMemoryPrompt(await memoryStore.readIndex()),
|
|
973
|
+
};
|
|
966
974
|
}
|
|
967
975
|
catch (error) {
|
|
968
976
|
return {
|
|
@@ -979,12 +987,27 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
979
987
|
const capabilities = await probeCapabilities();
|
|
980
988
|
const computerUsePackage = capabilities.find((probe) => probe.specifier === '@namzu/computer-use');
|
|
981
989
|
let computerUseHost;
|
|
990
|
+
let computerUseTool;
|
|
982
991
|
let computerUseError;
|
|
983
|
-
|
|
992
|
+
// The model sees the desktop only as an image in a tool result. A driver
|
|
993
|
+
// that declares it cannot carry one would hand the model a line of text
|
|
994
|
+
// for every screenshot while each click reported success — the model
|
|
995
|
+
// acting on a screen it never saw. Mounted as a diagnostic that says so,
|
|
996
|
+
// without starting the desktop host at all.
|
|
997
|
+
const computerUseProviderRefusal = options.enableComputerUse === true && computerUsePackage?.state === 'present'
|
|
998
|
+
? computerUseUnavailableReason(provider)
|
|
999
|
+
: undefined;
|
|
1000
|
+
if (computerUseProviderRefusal !== undefined) {
|
|
1001
|
+
registry.register(createComputerUseTool(new SubprocessComputerUseHost(), {
|
|
1002
|
+
unavailableReason: computerUseProviderRefusal,
|
|
1003
|
+
}));
|
|
1004
|
+
}
|
|
1005
|
+
else if (options.enableComputerUse === true && computerUsePackage?.state === 'present') {
|
|
984
1006
|
const candidate = new SubprocessComputerUseHost();
|
|
985
1007
|
try {
|
|
986
1008
|
await candidate.initialize();
|
|
987
|
-
|
|
1009
|
+
computerUseTool = createComputerUseTool(candidate);
|
|
1010
|
+
registry.register(computerUseTool);
|
|
988
1011
|
computerUseHost = candidate;
|
|
989
1012
|
}
|
|
990
1013
|
catch (error) {
|
|
@@ -1014,6 +1037,26 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1014
1037
|
}));
|
|
1015
1038
|
}
|
|
1016
1039
|
}
|
|
1040
|
+
// The browser: mounted for a surface that asked for it, never launched
|
|
1041
|
+
// here. The host detects the engine now and starts the browser on the
|
|
1042
|
+
// model's first call. Parent session only — sub-agents build their own
|
|
1043
|
+
// registries below and never receive it.
|
|
1044
|
+
const browserPackage = capabilities.find((probe) => probe.specifier === '@namzu/browser');
|
|
1045
|
+
let browserControl;
|
|
1046
|
+
let browserError;
|
|
1047
|
+
if (options.browser && browserPackage?.state === 'present') {
|
|
1048
|
+
try {
|
|
1049
|
+
const { PlaywrightBrowserHost } = await import('@namzu/browser');
|
|
1050
|
+
browserControl = createBrowserControl(PlaywrightBrowserHost, options.browser);
|
|
1051
|
+
registry.register(createBrowserTools(browserControl.host));
|
|
1052
|
+
}
|
|
1053
|
+
catch (error) {
|
|
1054
|
+
browserError = error instanceof Error ? error : new Error(String(error));
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
const browserUnavailable = browserError !== undefined
|
|
1058
|
+
? describeError(browserError)
|
|
1059
|
+
: browserControl?.status().unavailableReason;
|
|
1017
1060
|
// Registered only on the main session path. Sub-agents call
|
|
1018
1061
|
// `buildToolRegistry` directly below, so they never receive these tools.
|
|
1019
1062
|
// Per-send denial further keeps the schemas out of ordinary human turns.
|
|
@@ -1069,6 +1112,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1069
1112
|
sandboxReady: sandbox.provider !== undefined,
|
|
1070
1113
|
computerUseReady: computerUseHost !== undefined,
|
|
1071
1114
|
...(computerUseError ? { computerUseError } : {}),
|
|
1115
|
+
browserReady: browserControl !== undefined && browserUnavailable === undefined,
|
|
1116
|
+
...(browserControl ? { browser: browserControl.status() } : {}),
|
|
1117
|
+
...(browserUnavailable !== undefined ? { browserUnavailable } : {}),
|
|
1072
1118
|
});
|
|
1073
1119
|
// URL fetching is separately opt-in and parent-only: children do not
|
|
1074
1120
|
// carry its guarded provider. Independent search is shared below because
|
|
@@ -1096,6 +1142,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1096
1142
|
// Best-effort — if the runtime can't stand up, the chat still works.
|
|
1097
1143
|
const delegationScopes = new Map();
|
|
1098
1144
|
const delegationLimits = new Map();
|
|
1145
|
+
// A resumed turn that runs on another model than the session's (a
|
|
1146
|
+
// scheduled job's): its children inherit that model, not the session's.
|
|
1147
|
+
const delegationModels = new Map();
|
|
1099
1148
|
const delegatedInputWaiters = new Map();
|
|
1100
1149
|
if (options.residentHistory) {
|
|
1101
1150
|
const history = options.residentHistory;
|
|
@@ -1193,6 +1242,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1193
1242
|
tokenBudget: options.limits?.tokenBudget,
|
|
1194
1243
|
maxIterations: options.limits?.maxIterations,
|
|
1195
1244
|
resolveLimits: (turnId) => delegationLimits.get(turnId),
|
|
1245
|
+
resolveTurnModel: (turnId) => delegationModels.get(turnId),
|
|
1196
1246
|
timeoutMs: options.limits?.timeoutMs,
|
|
1197
1247
|
definitions: discovered.definitions,
|
|
1198
1248
|
// Children log under the parent's `<session-id>/subagents/`; an
|
|
@@ -1382,6 +1432,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1382
1432
|
const remaining = await Promise.allSettled([
|
|
1383
1433
|
mcp.close(),
|
|
1384
1434
|
computerUseHost?.dispose(),
|
|
1435
|
+
browserControl?.dispose(),
|
|
1385
1436
|
jobRegistry?.killOwner(jobOwner),
|
|
1386
1437
|
checkpoints.close(),
|
|
1387
1438
|
]);
|
|
@@ -1448,6 +1499,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1448
1499
|
// park recorder is supplied.
|
|
1449
1500
|
registry.register(buildAskUserQuestionTool({ resumeHandler: parkQuestion }));
|
|
1450
1501
|
}
|
|
1502
|
+
// The host's own additions, to this registry only: `buildTools` above
|
|
1503
|
+
// builds a child's roster separately, so none of these reach a sub-agent.
|
|
1504
|
+
for (const tool of options.extraTools ?? [])
|
|
1505
|
+
registry.register(tool);
|
|
1506
|
+
if (options.openUrl)
|
|
1507
|
+
registry.register(createOpenUrlTool());
|
|
1451
1508
|
// Task store → query registers task_create / task_update / task_list and
|
|
1452
1509
|
// emits task_created/task_updated, so the agent can track a plan. Tasks
|
|
1453
1510
|
// belong to the session (`<session-id>/tasks/`) and record the turn that
|
|
@@ -1501,6 +1558,15 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1501
1558
|
// Persists across turns: once the user picks "approve all", later tool
|
|
1502
1559
|
// batches in this session run without prompting.
|
|
1503
1560
|
const approval = { all: false };
|
|
1561
|
+
// The sessions whose operator let the model see the screen, asked once per
|
|
1562
|
+
// session before the first screenshot. Kept across mode switches and
|
|
1563
|
+
// turns, unlike "approve all"; a new session id is asked again.
|
|
1564
|
+
const screenConsent = { sessions: new Set() };
|
|
1565
|
+
// The registry is read at each decision: a turn may swap in its own.
|
|
1566
|
+
const screenPolicyFor = (tools) => ({
|
|
1567
|
+
consent: screenConsent,
|
|
1568
|
+
capturesScreen: (name, input) => tools().get(name)?.capturesScreen?.(input) === true,
|
|
1569
|
+
});
|
|
1504
1570
|
// The turns running now, each deciding under a mode the operator may change
|
|
1505
1571
|
// mid-turn, and the mode each conversation's log last recorded.
|
|
1506
1572
|
const liveModeControls = new Set();
|
|
@@ -1514,14 +1580,43 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1514
1580
|
// refusal closes the MCP processes already opened for this candidate before
|
|
1515
1581
|
// returning an inert session. Sub-agents were built above from their own
|
|
1516
1582
|
// registries, so executable plugins remain a top-level-session capability.
|
|
1583
|
+
// File skills (built-in, ~/.agents, ~/.namzu, and the project's) reach the
|
|
1584
|
+
// model through the kernel's manifest and `skill` tool. Registered BEFORE
|
|
1585
|
+
// the plugin runtime: a runtime that finds the tool already there never
|
|
1586
|
+
// owns it, so disabling the last plugin skill cannot take away the tool
|
|
1587
|
+
// the file skills load through.
|
|
1588
|
+
const skillCatalog = await createSessionSkillCatalog({
|
|
1589
|
+
cwd,
|
|
1590
|
+
...(options.skills ? { config: options.skills } : {}),
|
|
1591
|
+
log: cliLogger(),
|
|
1592
|
+
});
|
|
1593
|
+
// One `skill` tool for file and plugin skills alike, told which directory
|
|
1594
|
+
// the model can open for each: the real one on the host, the mounted one
|
|
1595
|
+
// inside the sandbox, none when the sandbox does not mount it.
|
|
1596
|
+
const skillTool = createSkillTool({
|
|
1597
|
+
resolveModelDirectory: createSkillDirectoryResolver({
|
|
1598
|
+
sandboxMounts: () => (sandboxWorkspace === 'working-directory' ? directories : []),
|
|
1599
|
+
}),
|
|
1600
|
+
});
|
|
1601
|
+
// A session that can save a skill loads it next turn through this tool,
|
|
1602
|
+
// even when it started with none.
|
|
1603
|
+
if ((skillCatalog.hasFileSkills || registry.has(SAVE_SKILL_TOOL_NAME)) &&
|
|
1604
|
+
!registry.has(skillTool.name))
|
|
1605
|
+
registry.register(skillTool);
|
|
1517
1606
|
let pluginRuntime;
|
|
1518
1607
|
try {
|
|
1519
|
-
pluginRuntime = await createCliPluginRuntime(options.plugins, registry, cwd, options.hooks);
|
|
1608
|
+
pluginRuntime = await createCliPluginRuntime(options.plugins, registry, cwd, options.hooks, skillTool);
|
|
1520
1609
|
}
|
|
1521
1610
|
catch (error) {
|
|
1522
|
-
await Promise.allSettled([mcp.close(), computerUseHost?.dispose()]);
|
|
1611
|
+
await Promise.allSettled([mcp.close(), computerUseHost?.dispose(), browserControl?.dispose()]);
|
|
1523
1612
|
return emptySession(describeError(error));
|
|
1524
1613
|
}
|
|
1614
|
+
// Everything is registered by now but the deferred task tools, which no
|
|
1615
|
+
// caller withholds.
|
|
1616
|
+
for (const name of options.withheldTools ?? []) {
|
|
1617
|
+
if (registry.get(name))
|
|
1618
|
+
registry.unregister(name);
|
|
1619
|
+
}
|
|
1525
1620
|
// The session's own lifecycle, for hooks that set up or tear down
|
|
1526
1621
|
// something per session rather than per turn. These two calls belong to no
|
|
1527
1622
|
// turn, so they carry no turn id — nothing is minted to fill the field.
|
|
@@ -1530,6 +1625,14 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1530
1625
|
// is replaced when the conversation is first made durable — and a hook
|
|
1531
1626
|
// given the provisional id could never match it to a turn.
|
|
1532
1627
|
const sessionPlugins = pluginRuntime;
|
|
1628
|
+
// What one turn's prompt manifest and `skill` tool see: the file skills
|
|
1629
|
+
// gated against the tools registered now, merged with the plugins' own.
|
|
1630
|
+
const turnSkillsFor = (turnModel) => skillCatalog.forTurn({
|
|
1631
|
+
toolNames: registry.listNames(),
|
|
1632
|
+
contextWindowTokens: resolveContextWindow(options.compaction?.contextWindowTokens, turnModel)
|
|
1633
|
+
.tokens,
|
|
1634
|
+
...(sessionPlugins ? { pluginSkills: sessionPlugins.skills } : {}),
|
|
1635
|
+
});
|
|
1533
1636
|
let sessionStarted = false;
|
|
1534
1637
|
const announceSessionStart = async () => {
|
|
1535
1638
|
if (!sessionPlugins || sessionStarted)
|
|
@@ -1591,6 +1694,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1591
1694
|
: undefined,
|
|
1592
1695
|
mcp.close(),
|
|
1593
1696
|
computerUseHost?.dispose(),
|
|
1697
|
+
browserControl?.dispose(),
|
|
1594
1698
|
jobRegistry?.killOwner(jobOwner),
|
|
1595
1699
|
checkpoints.close(),
|
|
1596
1700
|
]);
|
|
@@ -1647,13 +1751,35 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1647
1751
|
reasoningEffortDefault = undefined;
|
|
1648
1752
|
effortNotice = `Reasoning effort levels could not be established for this session: ${describeError(error)}`;
|
|
1649
1753
|
}
|
|
1754
|
+
/**
|
|
1755
|
+
* The provider a resumed turn runs on when its caller pinned one (a
|
|
1756
|
+
* scheduled job's model): built from this session's credential for that
|
|
1757
|
+
* provider, with no fallback chain, since the job's own run has none.
|
|
1758
|
+
* `undefined` without a pin.
|
|
1759
|
+
*/
|
|
1760
|
+
const pinnedResumeRoute = async (pin, sessionId, signal) => {
|
|
1761
|
+
if (!pin)
|
|
1762
|
+
return undefined;
|
|
1763
|
+
const providerId = pin.provider;
|
|
1764
|
+
const found = findDetected(detected, providerId);
|
|
1765
|
+
if (!found)
|
|
1766
|
+
throw new Error(`the turn runs on ${pin.provider}${pin.model ? `/${pin.model}` : ''} and this session has no credential for ${pin.provider}`);
|
|
1767
|
+
const pinnedModel = pin.model ?? found.entry.defaultModel;
|
|
1768
|
+
await ensureRegistered(providerId);
|
|
1769
|
+
const credential = await currentCredentialFor(providerId, signal);
|
|
1770
|
+
const pinnedProvider = constructProvider(providerId, credential, pinnedModel, { sessionId });
|
|
1771
|
+
const effort = pin.effort;
|
|
1772
|
+
if (effort !== undefined)
|
|
1773
|
+
await prepareDelegatedEffort(pinnedProvider, pinnedModel, signal);
|
|
1774
|
+
return { provider: pinnedProvider, model: pinnedModel, ...(effort ? { effort } : {}) };
|
|
1775
|
+
};
|
|
1650
1776
|
/**
|
|
1651
1777
|
* The kernel's resume with this session's half of the turn attached: the
|
|
1652
1778
|
* provider, the tools, the working directory, the doctrine — the part a
|
|
1653
1779
|
* checkpoint cannot carry. `resumeDurable` and `resumePaused` differ only
|
|
1654
1780
|
* in where the log and its lease come from.
|
|
1655
1781
|
*/
|
|
1656
|
-
const kernelResume = ({ entry, sessionLog, checkpointStore, lease, signal, checkpointId, listener, permissionMode, currentPermissionMode, }) => operations.promise(signal, async (ownedSignal) => {
|
|
1782
|
+
const kernelResume = ({ entry, sessionLog, checkpointStore, lease, signal, checkpointId, listener, permissionMode, currentPermissionMode, pendingDecision, onPermission, rules, reviewHold, model: pinned, systemNote, }) => operations.promise(signal, async (ownedSignal) => {
|
|
1657
1783
|
const selectTaskStore = beginTaskStoreReadout();
|
|
1658
1784
|
// The turn's own limits, as its `turn_started` recorded them.
|
|
1659
1785
|
const resumedLimits = (await readStoredTurnGuards(sessionLog, entry.turnId)) ?? resolveTurnGuards(options.limits);
|
|
@@ -1662,9 +1788,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1662
1788
|
// fallback chain has to be built AFTER that so its members do not
|
|
1663
1789
|
// hold a client the refresh just replaced.
|
|
1664
1790
|
await prepareProviderCredential(ownedSignal);
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1667
|
-
: undefined;
|
|
1791
|
+
const route = await pinnedResumeRoute(pinned, entry.sessionId, ownedSignal);
|
|
1792
|
+
const turnSkills = await turnSkillsFor(route?.model ?? model);
|
|
1668
1793
|
const curatedMemory = readMemory(undefined, cwd);
|
|
1669
1794
|
for (const notice of formatMemoryDiagnostics(curatedMemory))
|
|
1670
1795
|
cliLogger().warn(notice);
|
|
@@ -1687,6 +1812,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1687
1812
|
options.conversationSessions ? CONVERSATION_EVIDENCE_GUIDANCE : undefined,
|
|
1688
1813
|
environmentPrompt,
|
|
1689
1814
|
memoryPrompt,
|
|
1815
|
+
systemNote,
|
|
1816
|
+
turnSkills.overflowNote,
|
|
1690
1817
|
]
|
|
1691
1818
|
.filter((s) => Boolean(s))
|
|
1692
1819
|
.join('\n\n') || undefined;
|
|
@@ -1708,7 +1835,13 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1708
1835
|
...(recordedModes.has(String(entry.sessionId))
|
|
1709
1836
|
? { recorded: recordedModes.get(String(entry.sessionId)) }
|
|
1710
1837
|
: {}),
|
|
1711
|
-
handlerFor: (mode) =>
|
|
1838
|
+
handlerFor: (mode) => onPermission === undefined && reviewHold !== undefined
|
|
1839
|
+
? makeHoldingResumeHandler(mode, reviewExemptionFor(mode, registry, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }, reviewHold.reason, screenPolicyFor(() => registry))
|
|
1840
|
+
: makeResumeHandler(
|
|
1841
|
+
// A caller that brings its own prompt (a scheduled turn answered in
|
|
1842
|
+
// the TUI) gets its own latch: the session's "approve all" is not
|
|
1843
|
+
// an answer about a turn another policy started.
|
|
1844
|
+
onPermission ? { all: false } : approval, onPermission, mode, reviewExemptionFor(mode, registry, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }, screenPolicyFor(() => registry)),
|
|
1712
1845
|
});
|
|
1713
1846
|
const resumeHandler = modeControl.handler;
|
|
1714
1847
|
const reviewAllowedCalls = modeControl.reviewAllowedCalls;
|
|
@@ -1718,15 +1851,21 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1718
1851
|
delegatedReviewAllowedCalls.set(entry.turnId, reviewAllowedCalls);
|
|
1719
1852
|
delegationScopes.set(entry.turnId, turnScope);
|
|
1720
1853
|
delegationLimits.set(entry.turnId, resumedLimits);
|
|
1854
|
+
if (route && pinned)
|
|
1855
|
+
delegationModels.set(entry.turnId, {
|
|
1856
|
+
provider: pinned.provider,
|
|
1857
|
+
model: route.model,
|
|
1858
|
+
...(route.effort ? { effort: route.effort } : {}),
|
|
1859
|
+
});
|
|
1721
1860
|
const turnTaskStore = selectTaskStore(turnScope);
|
|
1722
1861
|
try {
|
|
1723
1862
|
return await resumeSession({
|
|
1724
|
-
provider: providerForSession(entry.sessionId),
|
|
1725
|
-
fallbackProviders: fallbackPlan.build(currentToken, entry.sessionId),
|
|
1863
|
+
provider: route?.provider ?? providerForSession(entry.sessionId),
|
|
1864
|
+
fallbackProviders: route ? [] : fallbackPlan.build(currentToken, entry.sessionId),
|
|
1726
1865
|
tools: registry,
|
|
1727
1866
|
pluginManager: pluginRuntime?.manager,
|
|
1728
|
-
skillRegistry:
|
|
1729
|
-
skills:
|
|
1867
|
+
...(turnSkills.registry ? { skillRegistry: turnSkills.registry } : {}),
|
|
1868
|
+
...(turnSkills.manifest ? { skills: turnSkills.manifest } : {}),
|
|
1730
1869
|
taskStore: turnTaskStore,
|
|
1731
1870
|
...(webCapability ? { web: webCapability } : {}),
|
|
1732
1871
|
// The same availability the original turn registered under.
|
|
@@ -1739,9 +1878,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1739
1878
|
task_list: 'active',
|
|
1740
1879
|
},
|
|
1741
1880
|
...(subagentRuntime
|
|
1742
|
-
? {
|
|
1881
|
+
? {
|
|
1882
|
+
taskScheduler: await subagentRuntime.gatewayForTurn(entry.turnId),
|
|
1883
|
+
}
|
|
1743
1884
|
: {}),
|
|
1744
|
-
authorizationGate: gateFor(options.rules),
|
|
1885
|
+
authorizationGate: gateFor(rules ?? options.rules),
|
|
1886
|
+
...(pendingDecision ? { pendingDecision } : {}),
|
|
1745
1887
|
compactionConfig: compactionConfigFor(options.compaction),
|
|
1746
1888
|
retainedToolPreviewChars: options.conversationSessions
|
|
1747
1889
|
? (options.compaction?.retainedToolPreviewChars ?? 4_000)
|
|
@@ -1770,7 +1912,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1770
1912
|
? { sandboxTeardownTimeoutMs: options.sandbox.teardownTimeoutMs }
|
|
1771
1913
|
: {}),
|
|
1772
1914
|
turnConfig: {
|
|
1773
|
-
model,
|
|
1915
|
+
model: route?.model ?? model,
|
|
1916
|
+
...(route?.effort ? { effort: route.effort } : {}),
|
|
1774
1917
|
...(nativeWebSearch ? { webSearch: nativeWebSearch } : {}),
|
|
1775
1918
|
...(sandbox.provider ? { sandbox: { workspace: sandboxWorkspace } } : {}),
|
|
1776
1919
|
...resumedLimits,
|
|
@@ -1833,6 +1976,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1833
1976
|
delegatedReviewAllowedCalls.delete(entry.turnId);
|
|
1834
1977
|
delegationScopes.delete(entry.turnId);
|
|
1835
1978
|
delegationLimits.delete(entry.turnId);
|
|
1979
|
+
delegationModels.delete(entry.turnId);
|
|
1836
1980
|
await subagentRuntime?.releaseTurn(entry.turnId);
|
|
1837
1981
|
}
|
|
1838
1982
|
}
|
|
@@ -1843,12 +1987,13 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1843
1987
|
* headless caller renders a resumed turn exactly as it rendered the first
|
|
1844
1988
|
* segment.
|
|
1845
1989
|
*/
|
|
1846
|
-
const resumePausedStream = ({ turnId, checkpointId, signal, permissionMode, currentPermissionMode, }) => {
|
|
1990
|
+
const resumePausedStream = ({ turnId, checkpointId, signal, permissionMode, currentPermissionMode, pendingDecision, onPermission, rules, reviewHold, model: pinned, systemNote, }) => {
|
|
1847
1991
|
const queue = [];
|
|
1848
1992
|
let wake;
|
|
1849
1993
|
let settled = false;
|
|
1850
1994
|
let failure;
|
|
1851
1995
|
const presenter = createToolPresenter(registry);
|
|
1996
|
+
const readsOnly = declaredReadOnly(registry);
|
|
1852
1997
|
// The log the turn appends to, and its checkpoints beside it.
|
|
1853
1998
|
const sessionLog = DiskSessionLog.at(paths, { sessionId: scope.sessionId });
|
|
1854
1999
|
const outcome = kernelResume({
|
|
@@ -1863,6 +2008,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1863
2008
|
...(checkpointId !== undefined ? { checkpointId: checkpointId } : {}),
|
|
1864
2009
|
...(permissionMode ? { permissionMode } : {}),
|
|
1865
2010
|
...(currentPermissionMode ? { currentPermissionMode } : {}),
|
|
2011
|
+
...(pendingDecision ? { pendingDecision } : {}),
|
|
2012
|
+
...(onPermission ? { onPermission } : {}),
|
|
2013
|
+
...(rules ? { rules } : {}),
|
|
2014
|
+
...(reviewHold ? { reviewHold } : {}),
|
|
2015
|
+
...(pinned ? { model: pinned } : {}),
|
|
2016
|
+
...(systemNote ? { systemNote } : {}),
|
|
1866
2017
|
listener: (event) => {
|
|
1867
2018
|
queue.push(event);
|
|
1868
2019
|
wake?.();
|
|
@@ -1888,7 +2039,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1888
2039
|
const next = queue.shift();
|
|
1889
2040
|
if (!next)
|
|
1890
2041
|
break;
|
|
1891
|
-
const mapped = toAgentEvent(next, presenter);
|
|
2042
|
+
const mapped = toAgentEvent(next, presenter, readsOnly);
|
|
1892
2043
|
if (mapped)
|
|
1893
2044
|
yield mapped;
|
|
1894
2045
|
}
|
|
@@ -2005,6 +2156,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2005
2156
|
return mcp.failed;
|
|
2006
2157
|
},
|
|
2007
2158
|
mcpStatus: () => mcp.current(),
|
|
2159
|
+
...(browserControl ? { browser: browserControl } : {}),
|
|
2008
2160
|
configNotices: [
|
|
2009
2161
|
...(capabilityNotice ? [capabilityNotice] : []),
|
|
2010
2162
|
...(effortNotice ? [effortNotice] : []),
|
|
@@ -2012,15 +2164,27 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2012
2164
|
...(computerUseError
|
|
2013
2165
|
? [`Computer use is unavailable on this device: ${describeError(computerUseError)}`]
|
|
2014
2166
|
: []),
|
|
2167
|
+
...(computerUseProviderRefusal !== undefined
|
|
2168
|
+
? [`Computer use is unavailable in this session: ${computerUseProviderRefusal}`]
|
|
2169
|
+
: []),
|
|
2170
|
+
...(browserUnavailable !== undefined
|
|
2171
|
+
? [`The browser is unavailable: ${browserUnavailable}`]
|
|
2172
|
+
: []),
|
|
2015
2173
|
...unresolvedNotice.map((line) => `Provider chain: capabilities could not be established for ${line}.`),
|
|
2016
2174
|
...fallbackPlan.notices,
|
|
2017
2175
|
...memoryMigrationNotices,
|
|
2018
2176
|
],
|
|
2019
2177
|
rememberNote: (text, type) => saveTypedNote(memoryStore, text, type),
|
|
2020
|
-
importCuratedNotes: async () => describeCuratedNotesImport(await importCuratedNotes({
|
|
2178
|
+
importCuratedNotes: async () => describeCuratedNotesImport(await importCuratedNotes({
|
|
2179
|
+
store: memoryStore,
|
|
2180
|
+
directory: memoryDirectory,
|
|
2181
|
+
cwd,
|
|
2182
|
+
}), memoryDirectory),
|
|
2021
2183
|
storedMemoryIndex: async () => ({
|
|
2022
2184
|
directory: memoryDirectory,
|
|
2023
|
-
index: await memoryStore.readIndex({
|
|
2185
|
+
index: await memoryStore.readIndex({
|
|
2186
|
+
maxLines: Number.POSITIVE_INFINITY,
|
|
2187
|
+
}),
|
|
2024
2188
|
derived: await memoryStore.readIndex({
|
|
2025
2189
|
maxLines: Number.POSITIVE_INFINITY,
|
|
2026
2190
|
derived: true,
|
|
@@ -2039,6 +2203,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2039
2203
|
await Promise.all([...liveModeControls].map((control) => control.record(mode, reason ?? permissionChangeReason(mode, 'now'))));
|
|
2040
2204
|
},
|
|
2041
2205
|
promptExemptTools: () => promptExemptToolNames(registry).filter((name) => !goalToolNames.has(name)),
|
|
2206
|
+
describeComputerUseRef: (ref) => computerUseTool?.describeUiRef(ref),
|
|
2042
2207
|
send: (messages, opts) => operations.stream(opts?.signal, (signal) => (async function* () {
|
|
2043
2208
|
const selectTaskStore = beginTaskStoreReadout();
|
|
2044
2209
|
const turnLimits = resolveTurnGuards(options.limits, opts?.limits);
|
|
@@ -2048,7 +2213,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2048
2213
|
const turnScope = { ...scope };
|
|
2049
2214
|
const initialMode = opts?.permissionMode ??
|
|
2050
2215
|
options.permissionMode ??
|
|
2051
|
-
(opts?.onPermission ? 'prompt' : 'auto');
|
|
2216
|
+
(opts?.onPermission || opts?.reviewHold ? 'prompt' : 'auto');
|
|
2052
2217
|
// The mode is read at every decision, so the operator can change it
|
|
2053
2218
|
// while this turn runs (see permissions/live-mode.ts).
|
|
2054
2219
|
const modeControl = createLiveModeControl({
|
|
@@ -2057,7 +2222,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2057
2222
|
...(recordedModes.has(String(turnScope.sessionId))
|
|
2058
2223
|
? { recorded: recordedModes.get(String(turnScope.sessionId)) }
|
|
2059
2224
|
: {}),
|
|
2060
|
-
handlerFor: (mode) =>
|
|
2225
|
+
handlerFor: (mode) => opts?.reviewHold
|
|
2226
|
+
? makeHoldingResumeHandler(mode, reviewExemptionFor(mode, runTools, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }, opts.reviewHold.reason, screenPolicyFor(() => runTools))
|
|
2227
|
+
: makeResumeHandler(approval, opts?.onPermission, mode, reviewExemptionFor(mode, runTools, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }, screenPolicyFor(() => runTools)),
|
|
2061
2228
|
});
|
|
2062
2229
|
const resumeHandler = modeControl.handler;
|
|
2063
2230
|
liveModeControls.add(modeControl);
|
|
@@ -2106,9 +2273,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2106
2273
|
// runs — midnight passes, and the agent checks out a branch itself.
|
|
2107
2274
|
// Its text only changes when a fact changes, so it costs a prompt-cache
|
|
2108
2275
|
// miss exactly when a hit would have been a stale claim.
|
|
2109
|
-
const
|
|
2110
|
-
? await currentPluginSkills(pluginRuntime.skills)
|
|
2111
|
-
: undefined;
|
|
2276
|
+
const turnSkills = await turnSkillsFor(model);
|
|
2112
2277
|
// One fork after plugin refresh, held through every iteration of
|
|
2113
2278
|
// this send. Discovery cannot activate another send's schemas.
|
|
2114
2279
|
if (options.toolLoading === 'deferred')
|
|
@@ -2121,7 +2286,11 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2121
2286
|
}
|
|
2122
2287
|
const storedMemory = await storedMemoryPrompt();
|
|
2123
2288
|
if (storedMemory.notice) {
|
|
2124
|
-
yield {
|
|
2289
|
+
yield {
|
|
2290
|
+
kind: 'context',
|
|
2291
|
+
text: storedMemory.notice,
|
|
2292
|
+
shed: false,
|
|
2293
|
+
};
|
|
2125
2294
|
}
|
|
2126
2295
|
const memoryPrompt = [composeMemoryPrompt(curatedMemory), storedMemory.prompt]
|
|
2127
2296
|
.filter((part) => Boolean(part))
|
|
@@ -2179,7 +2348,10 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2179
2348
|
authorizeLearningRead: (context) => claimed.has(context.turnId) &&
|
|
2180
2349
|
delegationScopes.get(context.turnId) === turnScope,
|
|
2181
2350
|
})
|
|
2182
|
-
: {
|
|
2351
|
+
: {
|
|
2352
|
+
contributions: createResidentStepContributions(contextOptions),
|
|
2353
|
+
tools: [],
|
|
2354
|
+
};
|
|
2183
2355
|
if (bundle.tools.length) {
|
|
2184
2356
|
// Per-send membership: neither another send nor delegated sessions inherit this tool.
|
|
2185
2357
|
runTools = runTools.fork();
|
|
@@ -2201,7 +2373,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2201
2373
|
const systemPrompt = [
|
|
2202
2374
|
NAMZU_IDENTITY,
|
|
2203
2375
|
residentContext ? undefined : NAMZU_WORKING_DOCTRINE,
|
|
2204
|
-
|
|
2376
|
+
// Advice on delegating, for a session that has the Agent tool:
|
|
2377
|
+
// a scheduled run whose job withholds it would only be told how
|
|
2378
|
+
// to use a tool it was not sent.
|
|
2379
|
+
residentContext || options.withheldTools?.includes(AGENT_LAUNCH_TOOL)
|
|
2380
|
+
? undefined
|
|
2381
|
+
: NAMZU_DELEGATION_DOCTRINE,
|
|
2205
2382
|
!residentContext && opts?.orchestrate ? NAMZU_ORCHESTRATE_DOCTRINE : undefined,
|
|
2206
2383
|
options.conversationSessions ? CONVERSATION_EVIDENCE_GUIDANCE : undefined,
|
|
2207
2384
|
options.toolLoading === 'deferred' ? DEFERRED_TOOL_GUIDANCE : undefined,
|
|
@@ -2214,6 +2391,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2214
2391
|
residentContext ? undefined : environmentPrompt,
|
|
2215
2392
|
residentContext ? undefined : memoryPrompt,
|
|
2216
2393
|
residentContext ? undefined : opts?.extraSystem,
|
|
2394
|
+
residentContext ? undefined : opts?.systemNote,
|
|
2395
|
+
turnSkills.overflowNote,
|
|
2217
2396
|
]
|
|
2218
2397
|
.filter((s) => Boolean(s))
|
|
2219
2398
|
.join('\n\n') || undefined;
|
|
@@ -2246,7 +2425,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2246
2425
|
// when this session is the one bringing it into existence.
|
|
2247
2426
|
let ephemeralLog;
|
|
2248
2427
|
if (options.ephemeral) {
|
|
2249
|
-
ephemeralLog = new InMemorySessionLog({
|
|
2428
|
+
ephemeralLog = new InMemorySessionLog({
|
|
2429
|
+
sessionId: turnScope.sessionId,
|
|
2430
|
+
});
|
|
2250
2431
|
await ensureSessionStarted(ephemeralLog, {
|
|
2251
2432
|
...turnScope,
|
|
2252
2433
|
cwd,
|
|
@@ -2288,8 +2469,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2288
2469
|
model,
|
|
2289
2470
|
tools: runTools,
|
|
2290
2471
|
pluginManager: pluginRuntime?.manager,
|
|
2291
|
-
skillRegistry:
|
|
2292
|
-
skills:
|
|
2472
|
+
skillRegistry: turnSkills.registry,
|
|
2473
|
+
skills: turnSkills.manifest,
|
|
2293
2474
|
scope: turnScope,
|
|
2294
2475
|
turnId,
|
|
2295
2476
|
paths,
|
|
@@ -2841,6 +3022,7 @@ async function* runTurn({ retainedToolPreviewChars, fileReadTracker, provider, c
|
|
|
2841
3022
|
// matching in the first place: `toAgentEvent` is pure over a `SessionEvent`
|
|
2842
3023
|
// and could not ask a tool anything, so the host guessed from the name.
|
|
2843
3024
|
const presenter = createToolPresenter(tools);
|
|
3025
|
+
const readsOnly = declaredReadOnly(tools);
|
|
2844
3026
|
try {
|
|
2845
3027
|
const events = query({
|
|
2846
3028
|
...(retainedToolPreviewChars !== undefined ? { retainedToolPreviewChars } : {}),
|
|
@@ -2959,7 +3141,7 @@ async function* runTurn({ retainedToolPreviewChars, fileReadTracker, provider, c
|
|
|
2959
3141
|
// receipts and reasoning before the next user turn.
|
|
2960
3142
|
continue;
|
|
2961
3143
|
}
|
|
2962
|
-
const mapped = toAgentEvent(event, presenter);
|
|
3144
|
+
const mapped = toAgentEvent(event, presenter, readsOnly);
|
|
2963
3145
|
if (!mapped)
|
|
2964
3146
|
continue;
|
|
2965
3147
|
yield mapped;
|
|
@@ -3004,18 +3186,55 @@ async function* runTurn({ retainedToolPreviewChars, fileReadTracker, provider, c
|
|
|
3004
3186
|
* (`createReviewHandler`); what this application adds is the person to ask
|
|
3005
3187
|
* and the session's "approve all" box, which the screen also reads.
|
|
3006
3188
|
*/
|
|
3007
|
-
export function makeResumeHandler(approval, onPermission, mode = onPermission ? 'prompt' : 'auto', exempt = () => false, escapePolicy = {}) {
|
|
3189
|
+
export function makeResumeHandler(approval, onPermission, mode = onPermission ? 'prompt' : 'auto', exempt = () => false, escapePolicy = {}, screen) {
|
|
3008
3190
|
return createReviewHandler({
|
|
3009
3191
|
mode,
|
|
3010
3192
|
prompt: onPermission,
|
|
3011
3193
|
exempt,
|
|
3012
3194
|
remembered: approval,
|
|
3195
|
+
...(screen ? { screenConsent: screen.consent, capturesScreen: screen.capturesScreen } : {}),
|
|
3013
3196
|
// Refused unless the operator wrote `sandbox.allowUnattendedEscape`: a
|
|
3014
3197
|
// session with nobody to ask has nobody to consent to leaving the
|
|
3015
3198
|
// sandbox, and `auto` is not consent to a command it never showed.
|
|
3016
3199
|
unattendedSandboxEscape: escapePolicy.unattendedSandboxEscape ?? 'refuse',
|
|
3017
3200
|
});
|
|
3018
3201
|
}
|
|
3202
|
+
/** Thrown by the holding prompt; never leaves {@link makeHoldingResumeHandler}. */
|
|
3203
|
+
class ReviewHoldSignal extends Error {
|
|
3204
|
+
name = 'ReviewHoldSignal';
|
|
3205
|
+
}
|
|
3206
|
+
/**
|
|
3207
|
+
* The kernel's review policy with a prompt that never answers: every batch
|
|
3208
|
+
* that would be put to a person parks the turn instead (`{ action: 'pause' }`),
|
|
3209
|
+
* which the kernel records durably for a person to answer later.
|
|
3210
|
+
*
|
|
3211
|
+
* The prompt throws and THIS wrapper catches it: a handler that rejects is
|
|
3212
|
+
* turned into `abort` by the kernel (`awaitDecisionOrAbort`), which would end
|
|
3213
|
+
* the turn rather than hold it. The latch is private and never set, so no
|
|
3214
|
+
* earlier answer can approve a later batch.
|
|
3215
|
+
*/
|
|
3216
|
+
export function makeHoldingResumeHandler(mode, exempt, escapePolicy, reason, screen) {
|
|
3217
|
+
const inner = createReviewHandler({
|
|
3218
|
+
mode,
|
|
3219
|
+
prompt: async () => {
|
|
3220
|
+
throw new ReviewHoldSignal(reason);
|
|
3221
|
+
},
|
|
3222
|
+
exempt,
|
|
3223
|
+
remembered: { all: false },
|
|
3224
|
+
...(screen ? { screenConsent: screen.consent, capturesScreen: screen.capturesScreen } : {}),
|
|
3225
|
+
unattendedSandboxEscape: escapePolicy.unattendedSandboxEscape ?? 'refuse',
|
|
3226
|
+
});
|
|
3227
|
+
return async (request) => {
|
|
3228
|
+
try {
|
|
3229
|
+
return await inner(request);
|
|
3230
|
+
}
|
|
3231
|
+
catch (error) {
|
|
3232
|
+
if (error instanceof ReviewHoldSignal)
|
|
3233
|
+
return { action: 'pause', reason };
|
|
3234
|
+
throw error;
|
|
3235
|
+
}
|
|
3236
|
+
};
|
|
3237
|
+
}
|
|
3019
3238
|
/**
|
|
3020
3239
|
* Whether a call runs without asking. The kernel's rule: a trusted read-only
|
|
3021
3240
|
* declaration or a named bookkeeping write, never a fetch, never a tool the
|
|
@@ -3038,10 +3257,53 @@ export const AGENT_LAUNCH_TOOL = 'Agent';
|
|
|
3038
3257
|
* An operator who wants every launch asked about writes
|
|
3039
3258
|
* `permissions: { Agent: "ask" }`: an `ask` rule is an explicit review, which
|
|
3040
3259
|
* no exemption skips.
|
|
3260
|
+
*
|
|
3261
|
+
* `save_skill` (the TUI's alone) is not asked about here either, outside
|
|
3262
|
+
* `strict` and `plan`: its own screen shows the whole file and where it goes,
|
|
3263
|
+
* and asks in every mode, `auto` included. A second question in front of it
|
|
3264
|
+
* would ask the same thing with less on the screen. `strict` and `plan` still
|
|
3265
|
+
* refuse it, and an `ask` or `deny` rule for it still applies. Neither is
|
|
3266
|
+
* the `schedule` tool's `create`, `update`, `resume` or `delete`, for the
|
|
3267
|
+
* same reason (see {@link confirmsItself}).
|
|
3041
3268
|
*/
|
|
3042
3269
|
export function reviewExemptionFor(mode, registry, launchesReadOnlyAgent) {
|
|
3043
3270
|
return (name, input) => isPromptExempt(registry, name, input) ||
|
|
3044
|
-
(mode !== 'strict' && name === AGENT_LAUNCH_TOOL && launchesReadOnlyAgent(input))
|
|
3271
|
+
(mode !== 'strict' && name === AGENT_LAUNCH_TOOL && launchesReadOnlyAgent(input)) ||
|
|
3272
|
+
(mode !== 'strict' && mode !== 'plan' && confirmsItself(name, input)) ||
|
|
3273
|
+
(mode !== 'strict' &&
|
|
3274
|
+
mode !== 'plan' &&
|
|
3275
|
+
name === SAVE_SKILL_TOOL_NAME &&
|
|
3276
|
+
registry.has(SAVE_SKILL_TOOL_NAME));
|
|
3277
|
+
}
|
|
3278
|
+
/**
|
|
3279
|
+
* The `schedule` tool's `create`, `update`, `resume` and `delete`: each puts its own
|
|
3280
|
+
* confirmation in front of the operator, drawn from the host's computation,
|
|
3281
|
+
* and changes nothing unless they choose to. A review before it only asked
|
|
3282
|
+
* "Do you want to run schedule?" over the model's raw arguments, and then the
|
|
3283
|
+
* real question came. `pause` and anything else is reviewed as before; `plan`
|
|
3284
|
+
* and `strict` still refuse, and an `ask` or `deny` rule still decides, since
|
|
3285
|
+
* an explicit review is never exempted.
|
|
3286
|
+
*/
|
|
3287
|
+
export function confirmsItself(name, input) {
|
|
3288
|
+
if (name !== SCHEDULE_TOOL_NAME || typeof input !== 'object' || input === null)
|
|
3289
|
+
return false;
|
|
3290
|
+
const action = input.action;
|
|
3291
|
+
return action === 'create' || action === 'update' || action === 'resume' || action === 'delete';
|
|
3292
|
+
}
|
|
3293
|
+
/**
|
|
3294
|
+
* A call's own read-only declaration, as the tool states it for this input.
|
|
3295
|
+
* Not a permission answer (that is `isPromptExempt`): it only says whether a
|
|
3296
|
+
* finished turn changed anything, for the TUI's skill suggestion.
|
|
3297
|
+
*/
|
|
3298
|
+
function declaredReadOnly(registry) {
|
|
3299
|
+
return (toolName, input) => {
|
|
3300
|
+
try {
|
|
3301
|
+
return registry.get(toolName)?.isReadOnly?.(input) === true;
|
|
3302
|
+
}
|
|
3303
|
+
catch {
|
|
3304
|
+
return false;
|
|
3305
|
+
}
|
|
3306
|
+
};
|
|
3045
3307
|
}
|
|
3046
3308
|
/** The exempt roster, sorted, for the surface that has to NAME it. */
|
|
3047
3309
|
export function promptExemptToolNames(registry) {
|
|
@@ -3058,7 +3320,9 @@ export const batchNeedsPrompt = batchNeedsReview;
|
|
|
3058
3320
|
* `null` for events the chat surface doesn't render (iteration markers,
|
|
3059
3321
|
* checkpoints, plan lifecycle, …). Pure — unit-tested.
|
|
3060
3322
|
*/
|
|
3061
|
-
export function toAgentEvent(event, presenter
|
|
3323
|
+
export function toAgentEvent(event, presenter,
|
|
3324
|
+
/** Whether a call only reads, from the tool's own declaration; see `tool-start.readOnly`. */
|
|
3325
|
+
readsOnly) {
|
|
3062
3326
|
switch (event.type) {
|
|
3063
3327
|
case 'hosted_tool': {
|
|
3064
3328
|
const common = {
|
|
@@ -3134,6 +3398,7 @@ export function toAgentEvent(event, presenter) {
|
|
|
3134
3398
|
const web = webActivityFromInput(event.toolName, event.input);
|
|
3135
3399
|
return web ? { web } : {};
|
|
3136
3400
|
})(),
|
|
3401
|
+
...(readsOnly?.(event.toolName, event.input) ? { readOnly: true } : {}),
|
|
3137
3402
|
};
|
|
3138
3403
|
case 'tool_progress':
|
|
3139
3404
|
return {
|
|
@@ -3151,12 +3416,19 @@ export function toAgentEvent(event, presenter) {
|
|
|
3151
3416
|
output: event.result,
|
|
3152
3417
|
});
|
|
3153
3418
|
const detail = viewToLines(view);
|
|
3154
|
-
//
|
|
3155
|
-
// the
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3419
|
+
// The first line is the summary row. It leaves the body only when
|
|
3420
|
+
// the row says all of it: a shortened summary cannot replace the
|
|
3421
|
+
// first line's evidence in expanded or raw output. A first line
|
|
3422
|
+
// up to a few rows long is shown whole, so a note like "A
|
|
3423
|
+
// navigation to … was blocked" is not printed twice, once cut off
|
|
3424
|
+
// on the summary row and again in full underneath.
|
|
3425
|
+
const first = view.kind === 'terminal' && view.output.trim().length > 0
|
|
3426
|
+
? resultToLines(view.output)[0]
|
|
3427
|
+
: undefined;
|
|
3428
|
+
const summary = first !== undefined ? resultSummaryLine(first) : firstLine(event.result);
|
|
3429
|
+
const withoutRepeatedSummary = first !== undefined && detail?.[0] === first && summarySaysAll(first, summary)
|
|
3430
|
+
? detail.slice(1)
|
|
3431
|
+
: detail;
|
|
3160
3432
|
return {
|
|
3161
3433
|
kind: 'tool-end',
|
|
3162
3434
|
output: event.result,
|
|
@@ -3167,6 +3439,9 @@ export function toAgentEvent(event, presenter) {
|
|
|
3167
3439
|
summary,
|
|
3168
3440
|
...(event.durationMs !== undefined ? { durationMs: event.durationMs } : {}),
|
|
3169
3441
|
...(view.kind === 'generic' && view.visibility === 'hidden' ? { hidden: true } : {}),
|
|
3442
|
+
...(event.isError && view.kind === 'generic' && view.outcome === 'cancelled'
|
|
3443
|
+
? { cancelled: true }
|
|
3444
|
+
: {}),
|
|
3170
3445
|
...(view.kind === 'generic' && view.label.length > 0 ? { resultLabel: view.label } : {}),
|
|
3171
3446
|
...(withoutRepeatedSummary && withoutRepeatedSummary.length > 0
|
|
3172
3447
|
? { detail: withoutRepeatedSummary }
|
|
@@ -3176,7 +3451,9 @@ export function toAgentEvent(event, presenter) {
|
|
|
3176
3451
|
if (!kind)
|
|
3177
3452
|
return {};
|
|
3178
3453
|
const results = kind === 'search' && !event.isError ? countListedResults(event.result) : undefined;
|
|
3179
|
-
return {
|
|
3454
|
+
return {
|
|
3455
|
+
web: { kind, ...(results !== undefined ? { results } : {}) },
|
|
3456
|
+
};
|
|
3180
3457
|
})(),
|
|
3181
3458
|
};
|
|
3182
3459
|
}
|
|
@@ -3265,6 +3542,7 @@ export function toAgentEvent(event, presenter) {
|
|
|
3265
3542
|
...(event.failure ? { failure: event.failure } : {}),
|
|
3266
3543
|
...(event.providerError ? { providerError: event.providerError } : {}),
|
|
3267
3544
|
...(event.explanation ? { explanation: event.explanation } : {}),
|
|
3545
|
+
...(event.handoff ? { handoff: event.handoff } : {}),
|
|
3268
3546
|
};
|
|
3269
3547
|
case 'turn_completed':
|
|
3270
3548
|
// Carried through rather than dropped: `turn_failed` fires only from
|
|
@@ -3448,8 +3726,10 @@ export function viewToLines(view) {
|
|
|
3448
3726
|
if (view.output.trim().length === 0)
|
|
3449
3727
|
return undefined;
|
|
3450
3728
|
const lines = resultToLines(view.output);
|
|
3451
|
-
// A single
|
|
3452
|
-
return lines.length === 1 && lines[0]
|
|
3729
|
+
// A single line the summary row shows whole is not repeated under it.
|
|
3730
|
+
return lines.length === 1 && summarySaysAll(lines[0] ?? '', resultSummaryLine(lines[0] ?? ''))
|
|
3731
|
+
? undefined
|
|
3732
|
+
: lines;
|
|
3453
3733
|
}
|
|
3454
3734
|
}
|
|
3455
3735
|
}
|
|
@@ -3464,6 +3744,21 @@ export function viewToSummary(view) {
|
|
|
3464
3744
|
return truncate(view.command ?? view.output.split('\n')[0] ?? '', 120);
|
|
3465
3745
|
}
|
|
3466
3746
|
}
|
|
3747
|
+
/**
|
|
3748
|
+
* The longest first line a result's summary row shows whole, about three
|
|
3749
|
+
* terminal rows. Longer, the row shows its first 120 characters and the body
|
|
3750
|
+
* keeps the line.
|
|
3751
|
+
*/
|
|
3752
|
+
export const RESULT_SUMMARY_WHOLE_MAX = 300;
|
|
3753
|
+
/** A result's summary row for its first line: whole when short enough, else shortened. */
|
|
3754
|
+
export function resultSummaryLine(line) {
|
|
3755
|
+
const flat = line.replace(/\s+/g, ' ');
|
|
3756
|
+
return flat.length <= RESULT_SUMMARY_WHOLE_MAX ? flat : truncate(line, 120);
|
|
3757
|
+
}
|
|
3758
|
+
/** The summary row says everything `line` does (whitespace aside). */
|
|
3759
|
+
function summarySaysAll(line, summary) {
|
|
3760
|
+
return line === summary || line.replace(/\s+/g, ' ') === summary;
|
|
3761
|
+
}
|
|
3467
3762
|
function truncate(value, max) {
|
|
3468
3763
|
const oneLine = value.replace(/\s+/g, ' ');
|
|
3469
3764
|
return oneLine.length > max ? `${oneLine.slice(0, max - 1)}…` : oneLine;
|
|
@@ -3573,7 +3868,9 @@ function logCapabilities(probes, runtime) {
|
|
|
3573
3868
|
? runtime.sandboxReady
|
|
3574
3869
|
: p.specifier === '@namzu/computer-use'
|
|
3575
3870
|
? runtime.computerUseReady
|
|
3576
|
-
: p.
|
|
3871
|
+
: p.specifier === '@namzu/browser'
|
|
3872
|
+
? runtime.browserReady === true
|
|
3873
|
+
: p.state === 'present';
|
|
3577
3874
|
return `${p.specifier.split('/').pop()} ${present ? 'yes' : 'no'}`;
|
|
3578
3875
|
})
|
|
3579
3876
|
.join(' · ');
|
|
@@ -3597,6 +3894,22 @@ function logCapabilities(probes, runtime) {
|
|
|
3597
3894
|
...(probe.state === 'present' ? { 'namzu.capability.version': probe.version } : {}),
|
|
3598
3895
|
});
|
|
3599
3896
|
}
|
|
3897
|
+
if (runtime.browser) {
|
|
3898
|
+
// The engine and profile the browser tools will use; nothing is running yet.
|
|
3899
|
+
log.info('Browser tools mounted', {
|
|
3900
|
+
[EVENT_NAME_ATTRIBUTE]: BOOT_EVENT_NAMES.CAPABILITY_DETECTED,
|
|
3901
|
+
'namzu.capability.name': '@namzu/browser',
|
|
3902
|
+
'namzu.capability.state': runtime.browserUnavailable === undefined ? 'ready' : 'unavailable',
|
|
3903
|
+
'namzu.capability.present': runtime.browserReady === true,
|
|
3904
|
+
'namzu.browser.engine': runtime.browser.engine,
|
|
3905
|
+
'namzu.browser.profile': runtime.browser.profile,
|
|
3906
|
+
'namzu.browser.headless': runtime.browser.headless,
|
|
3907
|
+
'namzu.browser.site_count': Object.keys(runtime.browser.sites).length,
|
|
3908
|
+
...(runtime.browserUnavailable !== undefined
|
|
3909
|
+
? { 'namzu.browser.unavailable_reason': runtime.browserUnavailable }
|
|
3910
|
+
: {}),
|
|
3911
|
+
});
|
|
3912
|
+
}
|
|
3600
3913
|
if (runtime.computerUseError) {
|
|
3601
3914
|
log.warn('Computer use adapter is unavailable', {
|
|
3602
3915
|
[EVENT_NAME_ATTRIBUTE]: BOOT_EVENT_NAMES.CAPABILITY_DETECTED,
|