@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
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WSL: the daemon runs inside the distro, supervised by Windows Task
|
|
3
|
+
* Scheduler through `wsl.exe`.
|
|
4
|
+
*
|
|
5
|
+
* A distro is not running after Windows logs on until something starts it,
|
|
6
|
+
* and a systemd unit inside the distro cannot start its own distro; the
|
|
7
|
+
* `wsl.exe` process the task holds open both starts it and keeps WSL's idle
|
|
8
|
+
* shutdown away. The Windows programs are resolved once, here, from their
|
|
9
|
+
* fixed locations — never through PATH, whose `/mnt` entries make a failed
|
|
10
|
+
* lookup cost seconds — and recorded in the manifest.
|
|
11
|
+
*
|
|
12
|
+
* Refused at install: interop that does not answer, a node or CLI whose path
|
|
13
|
+
* `wsl.exe` would re-parse into something else, and a CLI running from the
|
|
14
|
+
* npx cache (it disappears).
|
|
15
|
+
*/
|
|
16
|
+
import type { CommandRunner } from './runner.js';
|
|
17
|
+
import { type TaskDefinition, taskPath } from './windows-task.js';
|
|
18
|
+
export interface WindowsTools {
|
|
19
|
+
/** Where WSL mounts the Windows drives, with a trailing slash (`/mnt/`). */
|
|
20
|
+
readonly mountRoot: string;
|
|
21
|
+
/**
|
|
22
|
+
* `C:` as WSL mounts it (`/mnt/c`): the directory a Windows program is
|
|
23
|
+
* started in, since one started in a Linux directory warns about UNC paths.
|
|
24
|
+
*/
|
|
25
|
+
readonly drive: string;
|
|
26
|
+
readonly systemRoot: string;
|
|
27
|
+
readonly cmd: string;
|
|
28
|
+
readonly schtasks: string;
|
|
29
|
+
readonly powershell: string;
|
|
30
|
+
readonly whoami: string;
|
|
31
|
+
readonly conhost: string;
|
|
32
|
+
readonly wsl: string;
|
|
33
|
+
}
|
|
34
|
+
/** `System32` under the default mount root. */
|
|
35
|
+
export declare const DEFAULT_SYSTEM32: string;
|
|
36
|
+
/**
|
|
37
|
+
* The Windows programs, under `system32` — by default under the drive mount
|
|
38
|
+
* root `/etc/wsl.conf` sets (`[automount] root`, `/mnt/` unless moved).
|
|
39
|
+
*/
|
|
40
|
+
export declare function windowsTools(system32?: string): WindowsTools;
|
|
41
|
+
/** Interop answers: a Windows program starts and exits 0. */
|
|
42
|
+
export declare function probeInterop(run: CommandRunner, tools: WindowsTools, env?: NodeJS.ProcessEnv): Promise<{
|
|
43
|
+
ok: true;
|
|
44
|
+
} | {
|
|
45
|
+
ok: false;
|
|
46
|
+
reason: string;
|
|
47
|
+
}>;
|
|
48
|
+
/** `DOMAIN\user` of the Windows account, from `whoami.exe`. */
|
|
49
|
+
export declare function windowsUser(run: CommandRunner, tools: WindowsTools): Promise<string>;
|
|
50
|
+
/** A Linux path as Windows sees it, through `wslpath -w`. */
|
|
51
|
+
export declare function toWindowsPath(run: CommandRunner, path: string): Promise<string>;
|
|
52
|
+
/** Whether a CLI path is inside the npx cache, which is not kept. */
|
|
53
|
+
export declare function isEphemeralBin(bin: string): boolean;
|
|
54
|
+
export declare function wslTaskName(name: string, distro: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* The task that runs the daemon in the distro. `conhost.exe --headless` keeps
|
|
57
|
+
* a console window from appearing at logon.
|
|
58
|
+
*/
|
|
59
|
+
export declare function wslTaskDefinition(options: {
|
|
60
|
+
readonly userId: string;
|
|
61
|
+
readonly distro: string;
|
|
62
|
+
readonly linuxUser: string;
|
|
63
|
+
readonly node: string;
|
|
64
|
+
readonly bin: string;
|
|
65
|
+
readonly namzuHome: string;
|
|
66
|
+
readonly systemRoot?: string;
|
|
67
|
+
}): TaskDefinition;
|
|
68
|
+
export { taskPath };
|
|
69
|
+
//# sourceMappingURL=wsl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsl.d.ts","sourceRoot":"","sources":["../../../src/schedule/service/wsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,KAAK,cAAc,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjE,MAAM,WAAW,YAAY;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACpB;AAED,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,QAAgB,CAAA;AAE7C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,SAAkC,GAAG,YAAY,CAcrF;AAED,6DAA6D;AAC7D,wBAAsB,YAAY,CACjC,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,YAAY,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,GAClC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBvD;AAED,+DAA+D;AAC/D,wBAAsB,WAAW,CAAC,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAS1F;AAED,6DAA6D;AAC7D,wBAAsB,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIrF;AAED,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC5B,GAAG,cAAc,CAiCjB;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WSL: the daemon runs inside the distro, supervised by Windows Task
|
|
3
|
+
* Scheduler through `wsl.exe`.
|
|
4
|
+
*
|
|
5
|
+
* A distro is not running after Windows logs on until something starts it,
|
|
6
|
+
* and a systemd unit inside the distro cannot start its own distro; the
|
|
7
|
+
* `wsl.exe` process the task holds open both starts it and keeps WSL's idle
|
|
8
|
+
* shutdown away. The Windows programs are resolved once, here, from their
|
|
9
|
+
* fixed locations — never through PATH, whose `/mnt` entries make a failed
|
|
10
|
+
* lookup cost seconds — and recorded in the manifest.
|
|
11
|
+
*
|
|
12
|
+
* Refused at install: interop that does not answer, a node or CLI whose path
|
|
13
|
+
* `wsl.exe` would re-parse into something else, and a CLI running from the
|
|
14
|
+
* npx cache (it disappears).
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync } from 'node:fs';
|
|
17
|
+
import { readWslMountRoot, wslSystem32 } from '../../context/environment.js';
|
|
18
|
+
import { checkWslPath } from './quote.js';
|
|
19
|
+
import { taskPath } from './windows-task.js';
|
|
20
|
+
/** `System32` under the default mount root. */
|
|
21
|
+
export const DEFAULT_SYSTEM32 = wslSystem32();
|
|
22
|
+
/**
|
|
23
|
+
* The Windows programs, under `system32` — by default under the drive mount
|
|
24
|
+
* root `/etc/wsl.conf` sets (`[automount] root`, `/mnt/` unless moved).
|
|
25
|
+
*/
|
|
26
|
+
export function windowsTools(system32 = wslSystem32(readWslMountRoot())) {
|
|
27
|
+
const systemRoot = system32.replace(/\/System32$/i, '');
|
|
28
|
+
const drive = systemRoot.replace(/\/Windows$/i, '');
|
|
29
|
+
return {
|
|
30
|
+
mountRoot: drive.replace(/[^/]+$/, ''),
|
|
31
|
+
drive,
|
|
32
|
+
systemRoot,
|
|
33
|
+
cmd: `${system32}/cmd.exe`,
|
|
34
|
+
schtasks: `${system32}/schtasks.exe`,
|
|
35
|
+
powershell: `${system32}/WindowsPowerShell/v1.0/powershell.exe`,
|
|
36
|
+
whoami: `${system32}/whoami.exe`,
|
|
37
|
+
conhost: `${system32}/conhost.exe`,
|
|
38
|
+
wsl: `${system32}/wsl.exe`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Interop answers: a Windows program starts and exits 0. */
|
|
42
|
+
export async function probeInterop(run, tools, env = process.env) {
|
|
43
|
+
if (!existsSync(tools.cmd))
|
|
44
|
+
return { ok: false, reason: `${tools.cmd} was not found (is C: mounted at ${tools.drive}?)` };
|
|
45
|
+
if (!env.WSL_INTEROP && !existsSync('/proc/sys/fs/binfmt_misc/WSLInterop')) {
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
reason: 'WSL interop is disabled ([interop] enabled=false in /etc/wsl.conf)',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const result = await run(tools.cmd, ['/d', '/c', 'ver'], { timeoutMs: 20_000, cwd: tools.drive });
|
|
52
|
+
return result.code === 0
|
|
53
|
+
? { ok: true }
|
|
54
|
+
: {
|
|
55
|
+
ok: false,
|
|
56
|
+
reason: `a Windows program did not start through interop (${result.stderr.trim() || `exit ${result.code}`})`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** `DOMAIN\user` of the Windows account, from `whoami.exe`. */
|
|
60
|
+
export async function windowsUser(run, tools) {
|
|
61
|
+
const result = await run(tools.whoami, [], { timeoutMs: 20_000, cwd: tools.drive });
|
|
62
|
+
const user = result.stdout.trim();
|
|
63
|
+
if (result.code !== 0 || !/^[^\\\s]+\\[^\\\s]+$/.test(user)) {
|
|
64
|
+
throw new Error(`could not read the Windows user from whoami.exe (${result.stderr.trim() || user || `exit ${result.code}`})`);
|
|
65
|
+
}
|
|
66
|
+
return user;
|
|
67
|
+
}
|
|
68
|
+
/** A Linux path as Windows sees it, through `wslpath -w`. */
|
|
69
|
+
export async function toWindowsPath(run, path) {
|
|
70
|
+
const result = await run('wslpath', ['-w', path], { timeoutMs: 10_000 });
|
|
71
|
+
if (result.code !== 0 || !result.stdout.trim())
|
|
72
|
+
throw new Error(`wslpath -w ${path} failed`);
|
|
73
|
+
return result.stdout.trim();
|
|
74
|
+
}
|
|
75
|
+
/** Whether a CLI path is inside the npx cache, which is not kept. */
|
|
76
|
+
export function isEphemeralBin(bin) {
|
|
77
|
+
return /[\\/]_npx[\\/]/.test(bin) || /[\\/]\.npm[\\/]_cacache[\\/]/.test(bin);
|
|
78
|
+
}
|
|
79
|
+
export function wslTaskName(name, distro) {
|
|
80
|
+
return `${name}-wsl-${distro.replace(/[^A-Za-z0-9._-]/g, '_')}`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The task that runs the daemon in the distro. `conhost.exe --headless` keeps
|
|
84
|
+
* a console window from appearing at logon.
|
|
85
|
+
*/
|
|
86
|
+
export function wslTaskDefinition(options) {
|
|
87
|
+
checkWslPath('node', options.node);
|
|
88
|
+
checkWslPath('the namzu CLI', options.bin);
|
|
89
|
+
checkWslPath('NAMZU_HOME', options.namzuHome);
|
|
90
|
+
if (!/^[A-Za-z0-9._-]+$/.test(options.distro))
|
|
91
|
+
throw new Error(`unusual WSL distro name: ${options.distro}`);
|
|
92
|
+
if (!/^[a-z_][a-z0-9_-]*\$?$/i.test(options.linuxUser))
|
|
93
|
+
throw new Error(`unusual Linux user name: ${options.linuxUser}`);
|
|
94
|
+
const root = options.systemRoot ?? 'C:\\Windows';
|
|
95
|
+
return {
|
|
96
|
+
userId: options.userId,
|
|
97
|
+
description: `namzu scheduler for NAMZU_HOME=${options.namzuHome} in WSL ${options.distro}`,
|
|
98
|
+
command: `${root}\\System32\\conhost.exe`,
|
|
99
|
+
args: [
|
|
100
|
+
'--headless',
|
|
101
|
+
`${root}\\System32\\wsl.exe`,
|
|
102
|
+
'-d',
|
|
103
|
+
options.distro,
|
|
104
|
+
'-u',
|
|
105
|
+
options.linuxUser,
|
|
106
|
+
'--cd',
|
|
107
|
+
'/',
|
|
108
|
+
'--exec',
|
|
109
|
+
'/usr/bin/env',
|
|
110
|
+
`NAMZU_HOME=${options.namzuHome}`,
|
|
111
|
+
options.node,
|
|
112
|
+
options.bin,
|
|
113
|
+
'schedule',
|
|
114
|
+
'daemon',
|
|
115
|
+
'--home',
|
|
116
|
+
options.namzuHome,
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export { taskPath };
|
|
121
|
+
//# sourceMappingURL=wsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsl.js","sourceRoot":"","sources":["../../../src/schedule/service/wsl.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the scheduler's files are written.
|
|
3
|
+
*
|
|
4
|
+
* Two rules, the ones the session lease settled on (`@namzu/sdk`
|
|
5
|
+
* `store/session-log/lease.ts`):
|
|
6
|
+
*
|
|
7
|
+
* - A file that ARBITRATES — who started an occurrence — is published with
|
|
8
|
+
* `link` from a fully written, fsynced temporary. `link` fails with `EEXIST`
|
|
9
|
+
* when the name exists, so of any number of simultaneous writers exactly one
|
|
10
|
+
* wins, and the name never exists without its whole body. Never `wx` on the
|
|
11
|
+
* real name (a reader can see it empty) and never rename-then-read-back (two
|
|
12
|
+
* renamers can each read themselves).
|
|
13
|
+
* - A file that is a VIEW or an operator-owned document — a job, a state — is
|
|
14
|
+
* replaced by an fsynced temporary and `rename`, so a reader sees the old
|
|
15
|
+
* body or the new one.
|
|
16
|
+
*
|
|
17
|
+
* Every file is 0600 in a 0700 directory.
|
|
18
|
+
*/
|
|
19
|
+
export declare const PRIVATE_FILE_MODE = 384;
|
|
20
|
+
export declare const PRIVATE_DIR_MODE = 448;
|
|
21
|
+
/** A file newer than this reader understands. Never rewritten. */
|
|
22
|
+
export declare class ScheduleFormatError extends Error {
|
|
23
|
+
readonly path: string;
|
|
24
|
+
readonly name = "ScheduleFormatError";
|
|
25
|
+
constructor(path: string, message: string);
|
|
26
|
+
}
|
|
27
|
+
export declare function ensureDir(path: string): void;
|
|
28
|
+
/** Replace `path` with `value` as JSON: fsynced temporary, then rename. */
|
|
29
|
+
export declare function writeJsonAtomic(path: string, value: unknown): void;
|
|
30
|
+
/**
|
|
31
|
+
* Publish `value` at `path` only if nothing is there yet. `true` when this
|
|
32
|
+
* call created it; `false` when the name already existed (someone else won).
|
|
33
|
+
*/
|
|
34
|
+
export declare function publishExclusive(path: string, value: unknown): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Read a scheduler file of `kind`, or `undefined` when there is none.
|
|
37
|
+
* Refuses a newer version or another kind, naming the file.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readVersioned<T extends {
|
|
40
|
+
readonly v: number;
|
|
41
|
+
readonly kind: string;
|
|
42
|
+
}>(path: string, kind: T['kind']): T | undefined;
|
|
43
|
+
//# sourceMappingURL=atomic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.d.ts","sourceRoot":"","sources":["../../../src/schedule/store/atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAgBH,eAAO,MAAM,iBAAiB,MAAQ,CAAA;AACtC,eAAO,MAAM,gBAAgB,MAAQ,CAAA;AAErC,kEAAkE;AAClE,qBAAa,mBAAoB,SAAQ,KAAK;IAG5C,QAAQ,CAAC,IAAI,EAAE,MAAM;IAFtB,SAAkB,IAAI,yBAAwB;gBAEpC,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM;CAIhB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5C;AAgCD,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAalE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAgBtE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpF,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,GACb,CAAC,GAAG,SAAS,CAyBf"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the scheduler's files are written.
|
|
3
|
+
*
|
|
4
|
+
* Two rules, the ones the session lease settled on (`@namzu/sdk`
|
|
5
|
+
* `store/session-log/lease.ts`):
|
|
6
|
+
*
|
|
7
|
+
* - A file that ARBITRATES — who started an occurrence — is published with
|
|
8
|
+
* `link` from a fully written, fsynced temporary. `link` fails with `EEXIST`
|
|
9
|
+
* when the name exists, so of any number of simultaneous writers exactly one
|
|
10
|
+
* wins, and the name never exists without its whole body. Never `wx` on the
|
|
11
|
+
* real name (a reader can see it empty) and never rename-then-read-back (two
|
|
12
|
+
* renamers can each read themselves).
|
|
13
|
+
* - A file that is a VIEW or an operator-owned document — a job, a state — is
|
|
14
|
+
* replaced by an fsynced temporary and `rename`, so a reader sees the old
|
|
15
|
+
* body or the new one.
|
|
16
|
+
*
|
|
17
|
+
* Every file is 0600 in a 0700 directory.
|
|
18
|
+
*/
|
|
19
|
+
import { randomBytes } from 'node:crypto';
|
|
20
|
+
import { closeSync, fsyncSync, linkSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeSync, } from 'node:fs';
|
|
21
|
+
import { basename, dirname, join } from 'node:path';
|
|
22
|
+
export const PRIVATE_FILE_MODE = 0o600;
|
|
23
|
+
export const PRIVATE_DIR_MODE = 0o700;
|
|
24
|
+
/** A file newer than this reader understands. Never rewritten. */
|
|
25
|
+
export class ScheduleFormatError extends Error {
|
|
26
|
+
path;
|
|
27
|
+
name = 'ScheduleFormatError';
|
|
28
|
+
constructor(path, message) {
|
|
29
|
+
super(`${path}: ${message}`);
|
|
30
|
+
this.path = path;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function ensureDir(path) {
|
|
34
|
+
mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
35
|
+
}
|
|
36
|
+
function temporaryBeside(path) {
|
|
37
|
+
return join(dirname(path), `.${basename(path)}.${process.pid}.${randomBytes(6).toString('hex')}.tmp`);
|
|
38
|
+
}
|
|
39
|
+
function writeDurably(path, text) {
|
|
40
|
+
const fd = openSync(path, 'wx', PRIVATE_FILE_MODE);
|
|
41
|
+
try {
|
|
42
|
+
writeSync(fd, text);
|
|
43
|
+
fsyncSync(fd);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
closeSync(fd);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function fsyncDir(path) {
|
|
50
|
+
try {
|
|
51
|
+
const fd = openSync(path, 'r');
|
|
52
|
+
try {
|
|
53
|
+
fsyncSync(fd);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
closeSync(fd);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Not every platform can fsync a directory (Windows). Best effort.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Replace `path` with `value` as JSON: fsynced temporary, then rename. */
|
|
64
|
+
export function writeJsonAtomic(path, value) {
|
|
65
|
+
ensureDir(dirname(path));
|
|
66
|
+
const temporary = temporaryBeside(path);
|
|
67
|
+
writeDurably(temporary, `${JSON.stringify(value, null, 2)}\n`);
|
|
68
|
+
try {
|
|
69
|
+
renameSync(temporary, path);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
try {
|
|
73
|
+
unlinkSync(temporary);
|
|
74
|
+
}
|
|
75
|
+
catch { }
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
fsyncDir(dirname(path));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Publish `value` at `path` only if nothing is there yet. `true` when this
|
|
82
|
+
* call created it; `false` when the name already existed (someone else won).
|
|
83
|
+
*/
|
|
84
|
+
export function publishExclusive(path, value) {
|
|
85
|
+
ensureDir(dirname(path));
|
|
86
|
+
const temporary = temporaryBeside(path);
|
|
87
|
+
writeDurably(temporary, `${JSON.stringify(value)}\n`);
|
|
88
|
+
try {
|
|
89
|
+
linkSync(temporary, path);
|
|
90
|
+
fsyncDir(dirname(path));
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
if (error.code === 'EEXIST')
|
|
95
|
+
return false;
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
try {
|
|
100
|
+
unlinkSync(temporary);
|
|
101
|
+
}
|
|
102
|
+
catch { }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Read a scheduler file of `kind`, or `undefined` when there is none.
|
|
107
|
+
* Refuses a newer version or another kind, naming the file.
|
|
108
|
+
*/
|
|
109
|
+
export function readVersioned(path, kind) {
|
|
110
|
+
let text;
|
|
111
|
+
try {
|
|
112
|
+
text = readFileSync(path, 'utf8');
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (error.code === 'ENOENT')
|
|
116
|
+
return undefined;
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
let parsed;
|
|
120
|
+
try {
|
|
121
|
+
parsed = JSON.parse(text);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
throw new ScheduleFormatError(path, 'is not valid JSON');
|
|
125
|
+
}
|
|
126
|
+
const record = parsed;
|
|
127
|
+
if (typeof record !== 'object' || record === null || record.kind !== kind) {
|
|
128
|
+
throw new ScheduleFormatError(path, `is not a ${kind} file`);
|
|
129
|
+
}
|
|
130
|
+
if (typeof record.v !== 'number' || record.v > 1) {
|
|
131
|
+
throw new ScheduleFormatError(path, `was written by a newer namzu (format ${String(record.v)}); this one reads format 1 and will not change it`);
|
|
132
|
+
}
|
|
133
|
+
return parsed;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=atomic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../../src/schedule/store/atomic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `schedule/claims/<job-id>/<key>.json`: one per occurrence ever started.
|
|
3
|
+
*
|
|
4
|
+
* Published with `link` when the run is DISPATCHED — not when it is queued —
|
|
5
|
+
* so a daemon that restarts while a run waits for a slot re-derives it and
|
|
6
|
+
* runs it once, and a second daemon (or a backward clock) can never start an
|
|
7
|
+
* occurrence that already started. This file is the final once-only
|
|
8
|
+
* guarantee, independent of the daemon lease.
|
|
9
|
+
*/
|
|
10
|
+
import type { SchedulePaths } from '../paths.js';
|
|
11
|
+
export interface ScheduleClaim {
|
|
12
|
+
readonly v: 1;
|
|
13
|
+
readonly kind: 'schedule-claim';
|
|
14
|
+
readonly jobId: string;
|
|
15
|
+
readonly key: string;
|
|
16
|
+
readonly runId: string;
|
|
17
|
+
readonly daemonEpoch: string;
|
|
18
|
+
readonly at: string;
|
|
19
|
+
}
|
|
20
|
+
/** `true` when this call started the occurrence; `false` when it was already started. */
|
|
21
|
+
export declare function claimOccurrence(paths: SchedulePaths, claim: Omit<ScheduleClaim, 'v' | 'kind'>): boolean;
|
|
22
|
+
export declare function readClaim(paths: SchedulePaths, jobId: string, key: string): ScheduleClaim | undefined;
|
|
23
|
+
export declare function isClaimed(paths: SchedulePaths, jobId: string, key: string): boolean;
|
|
24
|
+
/** Remove claims older than `maxAgeMs` (nothing that old can be due again). */
|
|
25
|
+
export declare function pruneClaims(paths: SchedulePaths, jobId: string, maxAgeMs: number, now?: number): number;
|
|
26
|
+
//# sourceMappingURL=claims.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claims.d.ts","sourceRoot":"","sources":["../../../src/schedule/store/claims.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAA;IACb,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACnB;AAED,yFAAyF;AACzF,wBAAgB,eAAe,CAC9B,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,GAAG,GAAG,MAAM,CAAC,GACtC,OAAO,CAWT;AAED,wBAAgB,SAAS,CACxB,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,GACT,aAAa,GAAG,SAAS,CAE3B;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnF;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAC1B,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,GAAG,SAAa,GACd,MAAM,CAiBR"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `schedule/claims/<job-id>/<key>.json`: one per occurrence ever started.
|
|
3
|
+
*
|
|
4
|
+
* Published with `link` when the run is DISPATCHED — not when it is queued —
|
|
5
|
+
* so a daemon that restarts while a run waits for a slot re-derives it and
|
|
6
|
+
* runs it once, and a second daemon (or a backward clock) can never start an
|
|
7
|
+
* occurrence that already started. This file is the final once-only
|
|
8
|
+
* guarantee, independent of the daemon lease.
|
|
9
|
+
*/
|
|
10
|
+
import { readdirSync, rmSync, statSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { publishExclusive, readVersioned } from './atomic.js';
|
|
13
|
+
/** `true` when this call started the occurrence; `false` when it was already started. */
|
|
14
|
+
export function claimOccurrence(paths, claim) {
|
|
15
|
+
if (!/^(\d{1,16}|manual-[0-9a-f-]{8,64})$/.test(claim.key)) {
|
|
16
|
+
throw new Error(`Refusing an occurrence key that is not an instant or a manual run: ${claim.key}`);
|
|
17
|
+
}
|
|
18
|
+
return publishExclusive(paths.claim(claim.jobId, claim.key), {
|
|
19
|
+
v: 1,
|
|
20
|
+
kind: 'schedule-claim',
|
|
21
|
+
...claim,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export function readClaim(paths, jobId, key) {
|
|
25
|
+
return readVersioned(paths.claim(jobId, key), 'schedule-claim');
|
|
26
|
+
}
|
|
27
|
+
export function isClaimed(paths, jobId, key) {
|
|
28
|
+
try {
|
|
29
|
+
statSync(paths.claim(jobId, key));
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/** Remove claims older than `maxAgeMs` (nothing that old can be due again). */
|
|
37
|
+
export function pruneClaims(paths, jobId, maxAgeMs, now = Date.now()) {
|
|
38
|
+
let removed = 0;
|
|
39
|
+
let names;
|
|
40
|
+
try {
|
|
41
|
+
names = readdirSync(paths.claimsOf(jobId));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
for (const name of names) {
|
|
47
|
+
const match = /^(\d{1,16})\.json$/.exec(name);
|
|
48
|
+
if (!match)
|
|
49
|
+
continue;
|
|
50
|
+
if (now - Number(match[1]) > maxAgeMs) {
|
|
51
|
+
rmSync(join(paths.claimsOf(jobId), name), { force: true });
|
|
52
|
+
removed++;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return removed;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=claims.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claims.js","sourceRoot":"","sources":["../../../src/schedule/store/claims.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAY7D,yFAAyF;AACzF,MAAM,UAAU,eAAe,CAC9B,KAAoB,EACpB,KAAwC;IAExC,IAAI,CAAC,qCAAqC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CACd,sEAAsE,KAAK,CAAC,GAAG,EAAE,CACjF,CAAA;IACF,CAAC;IACD,OAAO,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;QAC5D,CAAC,EAAE,CAAC;QACJ,IAAI,EAAE,gBAAgB;QACtB,GAAG,KAAK;KACR,CAAC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CACxB,KAAoB,EACpB,KAAa,EACb,GAAW;IAEX,OAAO,aAAa,CAAgB,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAA;AAC/E,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAoB,EAAE,KAAa,EAAE,GAAW;IACzE,IAAI,CAAC;QACJ,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;QACjC,OAAO,IAAI,CAAA;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAA;IACb,CAAC;AACF,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAC1B,KAAoB,EACpB,KAAa,EACb,QAAgB,EAChB,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAEhB,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,KAAe,CAAA;IACnB,IAAI,CAAC;QACJ,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,CAAC,CAAA;IACT,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7C,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,IAAI,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YAC1D,OAAO,EAAE,CAAA;QACV,CAAC;IACF,CAAC;IACD,OAAO,OAAO,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A digest of the project configuration that runs code, pinned when a job is
|
|
3
|
+
* confirmed.
|
|
4
|
+
*
|
|
5
|
+
* `namzu.config.json` in the job's folder is repository content: a `git pull`
|
|
6
|
+
* in one run can add a hook, a tool server, a plugin or a permission before the
|
|
7
|
+
* next. A folder check compares a path; this compares what is IN it. The
|
|
8
|
+
* sections that execute code or change what may run are hashed, plus the
|
|
9
|
+
* project's command files and plugin bundles. A change gives the next run
|
|
10
|
+
* `blocked-config` until the operator confirms the job again.
|
|
11
|
+
*/
|
|
12
|
+
import type { ProjectDigest } from '../types.js';
|
|
13
|
+
export declare const DIGESTED_SECTIONS: readonly ["hooks", "mcpServers", "plugins", "permissions", "permissionChecks", "sandbox", "web", "additionalDirectories", "profiles"];
|
|
14
|
+
/** The digest of `folder`'s code-executing project configuration now. */
|
|
15
|
+
export declare function computeProjectDigest(folder: string): ProjectDigest;
|
|
16
|
+
/** The entries that differ between two digests, by relative path. */
|
|
17
|
+
export declare function projectDigestChanges(pinned: ProjectDigest, now: ProjectDigest): string[];
|
|
18
|
+
//# sourceMappingURL=digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../../src/schedule/store/digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,eAAO,MAAM,iBAAiB,uIAUpB,CAAA;AA2FV,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAUlE;AAED,qEAAqE;AACrE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,EAAE,CAGxF"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A digest of the project configuration that runs code, pinned when a job is
|
|
3
|
+
* confirmed.
|
|
4
|
+
*
|
|
5
|
+
* `namzu.config.json` in the job's folder is repository content: a `git pull`
|
|
6
|
+
* in one run can add a hook, a tool server, a plugin or a permission before the
|
|
7
|
+
* next. A folder check compares a path; this compares what is IN it. The
|
|
8
|
+
* sections that execute code or change what may run are hashed, plus the
|
|
9
|
+
* project's command files and plugin bundles. A change gives the next run
|
|
10
|
+
* `blocked-config` until the operator confirms the job again.
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
import { lstatSync, readFileSync, readdirSync } from 'node:fs';
|
|
14
|
+
import { join, relative } from 'node:path';
|
|
15
|
+
import { stableStringify } from './jobs.js';
|
|
16
|
+
export const DIGESTED_SECTIONS = [
|
|
17
|
+
'hooks',
|
|
18
|
+
'mcpServers',
|
|
19
|
+
'plugins',
|
|
20
|
+
'permissions',
|
|
21
|
+
'permissionChecks',
|
|
22
|
+
'sandbox',
|
|
23
|
+
'web',
|
|
24
|
+
'additionalDirectories',
|
|
25
|
+
'profiles',
|
|
26
|
+
];
|
|
27
|
+
const MAX_FILES = 2_000;
|
|
28
|
+
const MAX_BYTES = 32 * 1024 * 1024;
|
|
29
|
+
function sha(text) {
|
|
30
|
+
return createHash('sha256').update(text).digest('hex');
|
|
31
|
+
}
|
|
32
|
+
function configSections(folder) {
|
|
33
|
+
let raw;
|
|
34
|
+
try {
|
|
35
|
+
raw = readFileSync(join(folder, 'namzu.config.json'), 'utf8');
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return 'absent';
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const parsed = JSON.parse(raw);
|
|
42
|
+
const picked = {};
|
|
43
|
+
for (const key of DIGESTED_SECTIONS)
|
|
44
|
+
if (key in parsed)
|
|
45
|
+
picked[key] = parsed[key];
|
|
46
|
+
// A file that declares none of these runs nothing, like no file at all.
|
|
47
|
+
return Object.keys(picked).length === 0 ? 'absent' : sha(stableStringify(picked));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Unparseable is a state too: hash the bytes, so fixing it is a change.
|
|
51
|
+
return `unparsed:${sha(raw)}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function treeDigest(root) {
|
|
55
|
+
const hash = createHash('sha256');
|
|
56
|
+
let files = 0;
|
|
57
|
+
let bytes = 0;
|
|
58
|
+
let overflow = false;
|
|
59
|
+
const visit = (dir) => {
|
|
60
|
+
let entries;
|
|
61
|
+
try {
|
|
62
|
+
entries = readdirSync(dir).sort();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
for (const name of entries) {
|
|
68
|
+
if (files >= MAX_FILES) {
|
|
69
|
+
overflow = true;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const path = join(dir, name);
|
|
73
|
+
let st;
|
|
74
|
+
try {
|
|
75
|
+
st = lstatSync(path);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const rel = relative(root, path).replaceAll('\\', '/');
|
|
81
|
+
if (st.isSymbolicLink()) {
|
|
82
|
+
hash.update(`link:${rel}\0`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (st.isDirectory()) {
|
|
86
|
+
if (name === 'node_modules' || name === '.git') {
|
|
87
|
+
hash.update(`dir:${rel}:${st.mtimeMs}\0`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
visit(path);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (!st.isFile())
|
|
94
|
+
continue;
|
|
95
|
+
files++;
|
|
96
|
+
if (bytes + st.size > MAX_BYTES) {
|
|
97
|
+
overflow = true;
|
|
98
|
+
hash.update(`file:${rel}:${st.size}:${st.mtimeMs}\0`);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
bytes += st.size;
|
|
102
|
+
hash.update(`file:${rel}\0`);
|
|
103
|
+
try {
|
|
104
|
+
hash.update(readFileSync(path));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
hash.update('unreadable');
|
|
108
|
+
}
|
|
109
|
+
hash.update('\0');
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
try {
|
|
113
|
+
if (!lstatSync(root).isDirectory())
|
|
114
|
+
return 'absent';
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return 'absent';
|
|
118
|
+
}
|
|
119
|
+
visit(root);
|
|
120
|
+
return `${overflow ? 'partial:' : ''}${hash.digest('hex')}`;
|
|
121
|
+
}
|
|
122
|
+
/** The digest of `folder`'s code-executing project configuration now. */
|
|
123
|
+
export function computeProjectDigest(folder) {
|
|
124
|
+
return {
|
|
125
|
+
algo: 'sha256',
|
|
126
|
+
files: {
|
|
127
|
+
'namzu.config.json': configSections(folder),
|
|
128
|
+
'.namzu/commands': treeDigest(join(folder, '.namzu', 'commands')),
|
|
129
|
+
'.namzu/plugins': treeDigest(join(folder, '.namzu', 'plugins')),
|
|
130
|
+
},
|
|
131
|
+
sections: [...DIGESTED_SECTIONS],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** The entries that differ between two digests, by relative path. */
|
|
135
|
+
export function projectDigestChanges(pinned, now) {
|
|
136
|
+
const keys = new Set([...Object.keys(pinned.files), ...Object.keys(now.files)]);
|
|
137
|
+
return [...keys].filter((k) => pinned.files[k] !== now.files[k]).sort();
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=digest.js.map
|