@stringsync/splates 0.0.61 → 1.13.3
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/README.md +2 -2
- package/artifact.d.ts +2 -2
- package/blockers.d.ts +1 -1
- package/config.d.ts +12 -0
- package/config.js +0 -0
- package/creds.d.ts +2 -2
- package/evals.d.ts +2 -2
- package/flags.d.ts +4 -4
- package/handoff.d.ts +3 -4
- package/hook.d.ts +2 -2
- package/index.js +108 -108
- package/lane.d.ts +2 -2
- package/mirror.d.ts +14 -0
- package/mirror.js +22 -0
- package/package.json +12 -4
- package/projects.d.ts +2 -2
- package/queue.d.ts +2 -2
- package/replica.d.ts +2 -2
- package/server.d.ts +2 -2
- package/setup.d.ts +2 -2
- package/ship.d.ts +2 -2
- package/slots.d.ts +2 -2
- package/splates.d.ts +2 -2
- package/task.d.ts +2 -2
- package/tunnel.d.ts +2 -2
- package/vendor/@stringsync/splates-server/LICENSE +21 -0
- package/vendor/@stringsync/splates-server/age.d.ts +2 -0
- package/vendor/@stringsync/splates-server/agents/acp-extensions.d.ts +92 -0
- package/vendor/@stringsync/splates-server/agents/agents.d.ts +19 -0
- package/vendor/@stringsync/splates-server/agents/compaction.d.ts +17 -0
- package/vendor/@stringsync/splates-server/agents/connection.d.ts +191 -0
- package/vendor/@stringsync/splates-server/agents/errors.d.ts +8 -0
- package/vendor/@stringsync/splates-server/agents/fold.d.ts +45 -0
- package/vendor/@stringsync/splates-server/agents/index.d.ts +16 -0
- package/vendor/@stringsync/splates-server/agents/index.js +60 -0
- package/vendor/@stringsync/splates-server/agents/process.d.ts +67 -0
- package/vendor/@stringsync/splates-server/agents/scratch.d.ts +7 -0
- package/vendor/@stringsync/splates-server/agents/shared-browser.d.ts +47 -0
- package/vendor/@stringsync/splates-server/agents/start-lock.d.ts +24 -0
- package/vendor/@stringsync/splates-server/agents/stream.d.ts +91 -0
- package/vendor/@stringsync/splates-server/agents/tool-calls.d.ts +18 -0
- package/vendor/@stringsync/splates-server/agents/watch.d.ts +46 -0
- package/vendor/@stringsync/splates-server/agents/watched.d.ts +43 -0
- package/vendor/@stringsync/splates-server/artifacts/artifact.d.ts +33 -0
- package/vendor/@stringsync/splates-server/artifacts/artifacts.d.ts +162 -0
- package/vendor/@stringsync/splates-server/artifacts/attach.d.ts +31 -0
- package/vendor/@stringsync/splates-server/artifacts/attachments.d.ts +50 -0
- package/vendor/@stringsync/splates-server/artifacts/index.d.ts +8 -0
- package/vendor/@stringsync/splates-server/artifacts/index.js +38 -0
- package/vendor/@stringsync/splates-server/artifacts/room.d.ts +46 -0
- package/vendor/@stringsync/splates-server/artifacts/routes.d.ts +22 -0
- package/vendor/@stringsync/splates-server/artifacts/viewers.d.ts +6 -0
- package/vendor/@stringsync/splates-server/auto-pick/classes.d.ts +29 -0
- package/vendor/@stringsync/splates-server/auto-pick/classify.d.ts +60 -0
- package/vendor/@stringsync/splates-server/auto-pick/clef.d.ts +15 -0
- package/vendor/@stringsync/splates-server/auto-pick/decide.d.ts +78 -0
- package/vendor/@stringsync/splates-server/auto-pick/defaults.d.ts +3 -0
- package/vendor/@stringsync/splates-server/auto-pick/follow-up.d.ts +25 -0
- package/vendor/@stringsync/splates-server/auto-pick/index.d.ts +24 -0
- package/vendor/@stringsync/splates-server/auto-pick/jev.d.ts +38 -0
- package/vendor/@stringsync/splates-server/auto-pick/judge.d.ts +21 -0
- package/vendor/@stringsync/splates-server/auto-pick/judged.d.ts +33 -0
- package/vendor/@stringsync/splates-server/auto-pick/key.d.ts +6 -0
- package/vendor/@stringsync/splates-server/auto-pick/lift.d.ts +18 -0
- package/vendor/@stringsync/splates-server/auto-pick/queue.d.ts +30 -0
- package/vendor/@stringsync/splates-server/auto-pick/rank.d.ts +10 -0
- package/vendor/@stringsync/splates-server/auto-pick/record.d.ts +19 -0
- package/vendor/@stringsync/splates-server/auto-pick/routes.d.ts +25 -0
- package/vendor/@stringsync/splates-server/auto-pick/rule-names.d.ts +9 -0
- package/vendor/@stringsync/splates-server/auto-pick/rules-routes.d.ts +49 -0
- package/vendor/@stringsync/splates-server/auto-pick/rules.d.ts +97 -0
- package/vendor/@stringsync/splates-server/auto-pick/start.d.ts +79 -0
- package/vendor/@stringsync/splates-server/auto-pick/store.d.ts +25 -0
- package/vendor/@stringsync/splates-server/auto-pick/system-one.d.ts +60 -0
- package/vendor/@stringsync/splates-server/auto-pick/trial.d.ts +32 -0
- package/vendor/@stringsync/splates-server/board/backlog.d.ts +4 -0
- package/vendor/@stringsync/splates-server/board/blocked-warning.d.ts +7 -0
- package/vendor/@stringsync/splates-server/board/browser.d.ts +8 -0
- package/vendor/@stringsync/splates-server/board/change-lane.d.ts +12 -0
- package/vendor/@stringsync/splates-server/board/deferral.d.ts +87 -0
- package/vendor/@stringsync/splates-server/board/elsewhere-links.d.ts +26 -0
- package/vendor/@stringsync/splates-server/board/elsewhere.d.ts +119 -0
- package/vendor/@stringsync/splates-server/board/index.d.ts +21 -0
- package/vendor/@stringsync/splates-server/board/index.js +112 -0
- package/vendor/@stringsync/splates-server/board/lane.d.ts +69 -0
- package/vendor/@stringsync/splates-server/board/lanes-from-tags.d.ts +17 -0
- package/vendor/@stringsync/splates-server/board/lanes.d.ts +117 -0
- package/vendor/@stringsync/splates-server/board/routes.d.ts +54 -0
- package/vendor/@stringsync/splates-server/board/store.d.ts +74 -0
- package/vendor/@stringsync/splates-server/board/task-edit.d.ts +81 -0
- package/vendor/@stringsync/splates-server/board/task-file.d.ts +24 -0
- package/vendor/@stringsync/splates-server/board/task-journal.d.ts +9 -0
- package/vendor/@stringsync/splates-server/board/task-lanes.d.ts +95 -0
- package/vendor/@stringsync/splates-server/board/task-list.d.ts +40 -0
- package/vendor/@stringsync/splates-server/board/task.d.ts +301 -0
- package/vendor/@stringsync/splates-server/board/tasks.d.ts +172 -0
- package/vendor/@stringsync/splates-server/chunk-files-jkqj87yx.js +14 -0
- package/vendor/@stringsync/splates-server/chunk-maps-mnjqydx4.txt +1 -0
- package/vendor/@stringsync/splates-server/chunks-3jkzx1q9.txt +1 -0
- package/vendor/@stringsync/splates-server/comma-list.d.ts +2 -0
- package/vendor/@stringsync/splates-server/comma-list.js +6 -0
- package/vendor/@stringsync/splates-server/config/browser.d.ts +1 -0
- package/vendor/@stringsync/splates-server/config/config.d.ts +210 -0
- package/vendor/@stringsync/splates-server/config/index.d.ts +6 -0
- package/vendor/@stringsync/splates-server/config/index.js +42 -0
- package/vendor/@stringsync/splates-server/config/legacy-names.d.ts +70 -0
- package/vendor/@stringsync/splates-server/config/legacy-ps.d.ts +32 -0
- package/vendor/@stringsync/splates-server/config/load.d.ts +46 -0
- package/vendor/@stringsync/splates-server/config/source.d.ts +7 -0
- package/vendor/@stringsync/splates-server/config/type-config.d.ts +14 -0
- package/vendor/@stringsync/splates-server/conversations/answered.d.ts +7 -0
- package/vendor/@stringsync/splates-server/conversations/archive.d.ts +16 -0
- package/vendor/@stringsync/splates-server/conversations/background.d.ts +21 -0
- package/vendor/@stringsync/splates-server/conversations/browser.d.ts +12 -0
- package/vendor/@stringsync/splates-server/conversations/choice.d.ts +8 -0
- package/vendor/@stringsync/splates-server/conversations/compact.d.ts +6 -0
- package/vendor/@stringsync/splates-server/conversations/conversation.d.ts +420 -0
- package/vendor/@stringsync/splates-server/conversations/conversations.d.ts +181 -0
- package/vendor/@stringsync/splates-server/conversations/entry.d.ts +286 -0
- package/vendor/@stringsync/splates-server/conversations/events.d.ts +36 -0
- package/vendor/@stringsync/splates-server/conversations/files.d.ts +62 -0
- package/vendor/@stringsync/splates-server/conversations/given.d.ts +18 -0
- package/vendor/@stringsync/splates-server/conversations/heard.d.ts +8 -0
- package/vendor/@stringsync/splates-server/conversations/host.d.ts +176 -0
- package/vendor/@stringsync/splates-server/conversations/index.d.ts +22 -0
- package/vendor/@stringsync/splates-server/conversations/index.js +80 -0
- package/vendor/@stringsync/splates-server/conversations/listing.d.ts +15 -0
- package/vendor/@stringsync/splates-server/conversations/log.d.ts +117 -0
- package/vendor/@stringsync/splates-server/conversations/messages.d.ts +23 -0
- package/vendor/@stringsync/splates-server/conversations/name.d.ts +38 -0
- package/vendor/@stringsync/splates-server/conversations/options.d.ts +87 -0
- package/vendor/@stringsync/splates-server/conversations/outside.d.ts +14 -0
- package/vendor/@stringsync/splates-server/conversations/reference.d.ts +2 -0
- package/vendor/@stringsync/splates-server/conversations/routes.d.ts +109 -0
- package/vendor/@stringsync/splates-server/conversations/search.d.ts +15 -0
- package/vendor/@stringsync/splates-server/conversations/spent.d.ts +19 -0
- package/vendor/@stringsync/splates-server/conversations/state.d.ts +606 -0
- package/vendor/@stringsync/splates-server/conversations/stream.d.ts +34 -0
- package/vendor/@stringsync/splates-server/conversations/transcript.d.ts +9 -0
- package/vendor/@stringsync/splates-server/conversations/tree.d.ts +11 -0
- package/vendor/@stringsync/splates-server/conversations/turn-end.d.ts +30 -0
- package/vendor/@stringsync/splates-server/conversations/turns.d.ts +134 -0
- package/vendor/@stringsync/splates-server/conversations/updates.d.ts +21 -0
- package/vendor/@stringsync/splates-server/creds/creds.d.ts +86 -0
- package/vendor/@stringsync/splates-server/creds/index.d.ts +6 -0
- package/vendor/@stringsync/splates-server/creds/index.js +28 -0
- package/vendor/@stringsync/splates-server/creds/key-file.d.ts +21 -0
- package/vendor/@stringsync/splates-server/creds/requests.d.ts +54 -0
- package/vendor/@stringsync/splates-server/creds/routes.d.ts +16 -0
- package/vendor/@stringsync/splates-server/creds/stores.d.ts +37 -0
- package/vendor/@stringsync/splates-server/dictate/connection.d.ts +18 -0
- package/vendor/@stringsync/splates-server/dictate/dictate.d.ts +16 -0
- package/vendor/@stringsync/splates-server/dictate/index.d.ts +4 -0
- package/vendor/@stringsync/splates-server/dictate/personal.d.ts +26 -0
- package/vendor/@stringsync/splates-server/dictate/transcriber.d.ts +16 -0
- package/vendor/@stringsync/splates-server/dictate/vocabulary.d.ts +12 -0
- package/vendor/@stringsync/splates-server/evals/agents-routes.d.ts +27 -0
- package/vendor/@stringsync/splates-server/evals/agents.d.ts +25 -0
- package/vendor/@stringsync/splates-server/evals/contract.d.ts +73 -0
- package/vendor/@stringsync/splates-server/evals/done.d.ts +11 -0
- package/vendor/@stringsync/splates-server/evals/import.d.ts +10 -0
- package/vendor/@stringsync/splates-server/evals/index.d.ts +19 -0
- package/vendor/@stringsync/splates-server/evals/index.js +40 -0
- package/vendor/@stringsync/splates-server/evals/inspect.d.ts +66 -0
- package/vendor/@stringsync/splates-server/evals/launch-routes.d.ts +39 -0
- package/vendor/@stringsync/splates-server/evals/launch.d.ts +123 -0
- package/vendor/@stringsync/splates-server/evals/routes.d.ts +39 -0
- package/vendor/@stringsync/splates-server/evals/store.d.ts +17 -0
- package/vendor/@stringsync/splates-server/evals/target.d.ts +3 -0
- package/vendor/@stringsync/splates-server/evals/types.d.ts +105 -0
- package/vendor/@stringsync/splates-server/exit.d.ts +55 -0
- package/vendor/@stringsync/splates-server/exit.js +12 -0
- package/vendor/@stringsync/splates-server/git-identity.d.ts +17 -0
- package/vendor/@stringsync/splates-server/git-process.d.ts +8 -0
- package/vendor/@stringsync/splates-server/git.d.ts +168 -0
- package/vendor/@stringsync/splates-server/hooks/commands.d.ts +31 -0
- package/vendor/@stringsync/splates-server/hooks/edit.d.ts +24 -0
- package/vendor/@stringsync/splates-server/hooks/events.d.ts +20 -0
- package/vendor/@stringsync/splates-server/hooks/groomer.d.ts +8 -0
- package/vendor/@stringsync/splates-server/hooks/index.d.ts +17 -0
- package/vendor/@stringsync/splates-server/hooks/index.js +61 -0
- package/vendor/@stringsync/splates-server/hooks/now.d.ts +9 -0
- package/vendor/@stringsync/splates-server/hooks/routes.d.ts +39 -0
- package/vendor/@stringsync/splates-server/hooks/runner.d.ts +75 -0
- package/vendor/@stringsync/splates-server/hooks/runs.d.ts +38 -0
- package/vendor/@stringsync/splates-server/hooks/schedule.d.ts +10 -0
- package/vendor/@stringsync/splates-server/hooks/scheduler.d.ts +28 -0
- package/vendor/@stringsync/splates-server/hooks/store.d.ts +110 -0
- package/vendor/@stringsync/splates-server/index-01z7ycdk.js +6 -0
- package/vendor/@stringsync/splates-server/index-0jttnv86.js +1309 -0
- package/vendor/@stringsync/splates-server/index-5axhdy8c.js +692 -0
- package/vendor/@stringsync/splates-server/index-76t8y8h5.js +779 -0
- package/vendor/@stringsync/splates-server/index-7s01973c.js +2356 -0
- package/vendor/@stringsync/splates-server/index-acbcm66f.js +1468 -0
- package/vendor/@stringsync/splates-server/index-caep3sde.js +27140 -0
- package/vendor/@stringsync/splates-server/index-e9z7s5hh.js +641 -0
- package/vendor/@stringsync/splates-server/index-g18nxyn7.js +99 -0
- package/vendor/@stringsync/splates-server/index-kmzdvvt0.js +23 -0
- package/vendor/@stringsync/splates-server/index-raqrwzdq.js +952 -0
- package/vendor/@stringsync/splates-server/index-t9w5a8ed.js +60 -0
- package/vendor/@stringsync/splates-server/limited.d.ts +8 -0
- package/vendor/@stringsync/splates-server/log.d.ts +14 -0
- package/vendor/@stringsync/splates-server/log.js +32 -0
- package/vendor/@stringsync/splates-server/merge/attribution.d.ts +24 -0
- package/vendor/@stringsync/splates-server/merge/batch.d.ts +119 -0
- package/vendor/@stringsync/splates-server/merge/blame.d.ts +21 -0
- package/vendor/@stringsync/splates-server/merge/branches.d.ts +151 -0
- package/vendor/@stringsync/splates-server/merge/charge.d.ts +18 -0
- package/vendor/@stringsync/splates-server/merge/clear-gate.d.ts +7 -0
- package/vendor/@stringsync/splates-server/merge/cores.d.ts +60 -0
- package/vendor/@stringsync/splates-server/merge/estimates.d.ts +28 -0
- package/vendor/@stringsync/splates-server/merge/finish.d.ts +43 -0
- package/vendor/@stringsync/splates-server/merge/follow.d.ts +50 -0
- package/vendor/@stringsync/splates-server/merge/gate.d.ts +108 -0
- package/vendor/@stringsync/splates-server/merge/github-app.d.ts +99 -0
- package/vendor/@stringsync/splates-server/merge/github-refused.d.ts +5 -0
- package/vendor/@stringsync/splates-server/merge/groups.d.ts +8 -0
- package/vendor/@stringsync/splates-server/merge/index.d.ts +19 -0
- package/vendor/@stringsync/splates-server/merge/index.js +46 -0
- package/vendor/@stringsync/splates-server/merge/landed.d.ts +28 -0
- package/vendor/@stringsync/splates-server/merge/landing.d.ts +38 -0
- package/vendor/@stringsync/splates-server/merge/local-landing.d.ts +11 -0
- package/vendor/@stringsync/splates-server/merge/merge-state.d.ts +37 -0
- package/vendor/@stringsync/splates-server/merge/merge.d.ts +45 -0
- package/vendor/@stringsync/splates-server/merge/output.d.ts +19 -0
- package/vendor/@stringsync/splates-server/merge/phases.d.ts +27 -0
- package/vendor/@stringsync/splates-server/merge/pre-lock.d.ts +28 -0
- package/vendor/@stringsync/splates-server/merge/preflight.d.ts +16 -0
- package/vendor/@stringsync/splates-server/merge/queue-failures.d.ts +11 -0
- package/vendor/@stringsync/splates-server/merge/rebase.d.ts +34 -0
- package/vendor/@stringsync/splates-server/merge/recent-failures.d.ts +10 -0
- package/vendor/@stringsync/splates-server/merge/refusal.d.ts +58 -0
- package/vendor/@stringsync/splates-server/merge/split.d.ts +34 -0
- package/vendor/@stringsync/splates-server/merge/steps.d.ts +37 -0
- package/vendor/@stringsync/splates-server/merge/test-report.d.ts +29 -0
- package/vendor/@stringsync/splates-server/merge/timing.d.ts +20 -0
- package/vendor/@stringsync/splates-server/merge/trunk.d.ts +69 -0
- package/vendor/@stringsync/splates-server/models/codex-limits.d.ts +19 -0
- package/vendor/@stringsync/splates-server/models/effort.d.ts +22 -0
- package/vendor/@stringsync/splates-server/models/index.d.ts +13 -0
- package/vendor/@stringsync/splates-server/models/index.js +76 -0
- package/vendor/@stringsync/splates-server/models/kimi-limits.d.ts +37 -0
- package/vendor/@stringsync/splates-server/models/kimi-usage.d.ts +19 -0
- package/vendor/@stringsync/splates-server/models/kimi.d.ts +10 -0
- package/vendor/@stringsync/splates-server/models/limits.d.ts +32 -0
- package/vendor/@stringsync/splates-server/models/models.d.ts +36 -0
- package/vendor/@stringsync/splates-server/models/offered.d.ts +47 -0
- package/vendor/@stringsync/splates-server/models/opencode-usage.d.ts +37 -0
- package/vendor/@stringsync/splates-server/models/roster.d.ts +130 -0
- package/vendor/@stringsync/splates-server/plans/asked.d.ts +99 -0
- package/vendor/@stringsync/splates-server/plans/browser.d.ts +13 -0
- package/vendor/@stringsync/splates-server/plans/decided.d.ts +12 -0
- package/vendor/@stringsync/splates-server/plans/demo.d.ts +29 -0
- package/vendor/@stringsync/splates-server/plans/index.d.ts +16 -0
- package/vendor/@stringsync/splates-server/plans/index.js +137 -0
- package/vendor/@stringsync/splates-server/plans/needs.d.ts +131 -0
- package/vendor/@stringsync/splates-server/plans/permission.d.ts +64 -0
- package/vendor/@stringsync/splates-server/plans/plan.d.ts +223 -0
- package/vendor/@stringsync/splates-server/plans/prompts.d.ts +148 -0
- package/vendor/@stringsync/splates-server/plans/reply.d.ts +45 -0
- package/vendor/@stringsync/splates-server/plans/run-command.d.ts +21 -0
- package/vendor/@stringsync/splates-server/plans/store.d.ts +26 -0
- package/vendor/@stringsync/splates-server/plans/unanswered.d.ts +15 -0
- package/vendor/@stringsync/splates-server/ports/index.d.ts +8 -0
- package/vendor/@stringsync/splates-server/ports/index.js +36 -0
- package/vendor/@stringsync/splates-server/ports/list.d.ts +22 -0
- package/vendor/@stringsync/splates-server/ports/routes.d.ts +64 -0
- package/vendor/@stringsync/splates-server/ports/slot-tunnel.d.ts +24 -0
- package/vendor/@stringsync/splates-server/ports/slot.d.ts +28 -0
- package/vendor/@stringsync/splates-server/ports/slots.d.ts +150 -0
- package/vendor/@stringsync/splates-server/ports/socket.d.ts +26 -0
- package/vendor/@stringsync/splates-server/ports/task-ports.d.ts +39 -0
- package/vendor/@stringsync/splates-server/prices/index.d.ts +2 -0
- package/vendor/@stringsync/splates-server/prices/prices.d.ts +65 -0
- package/vendor/@stringsync/splates-server/projects/everywhere-routes.d.ts +110 -0
- package/vendor/@stringsync/splates-server/projects/everywhere.d.ts +43 -0
- package/vendor/@stringsync/splates-server/projects/general.d.ts +4 -0
- package/vendor/@stringsync/splates-server/projects/index.d.ts +10 -0
- package/vendor/@stringsync/splates-server/projects/index.js +36 -0
- package/vendor/@stringsync/splates-server/projects/init.d.ts +28 -0
- package/vendor/@stringsync/splates-server/projects/picker.d.ts +64 -0
- package/vendor/@stringsync/splates-server/projects/projects.d.ts +155 -0
- package/vendor/@stringsync/splates-server/projects/reaches.d.ts +26 -0
- package/vendor/@stringsync/splates-server/push/index.d.ts +2 -0
- package/vendor/@stringsync/splates-server/push/notices.d.ts +44 -0
- package/vendor/@stringsync/splates-server/push/push.d.ts +91 -0
- package/vendor/@stringsync/splates-server/queue/commands.d.ts +44 -0
- package/vendor/@stringsync/splates-server/queue/index.d.ts +7 -0
- package/vendor/@stringsync/splates-server/queue/index.js +44 -0
- package/vendor/@stringsync/splates-server/queue/moves.d.ts +15 -0
- package/vendor/@stringsync/splates-server/queue/name.d.ts +9 -0
- package/vendor/@stringsync/splates-server/queue/order.d.ts +50 -0
- package/vendor/@stringsync/splates-server/queue/runner.d.ts +129 -0
- package/vendor/@stringsync/splates-server/records/elsewhere.d.ts +27 -0
- package/vendor/@stringsync/splates-server/records/events.d.ts +556 -0
- package/vendor/@stringsync/splates-server/records/format.d.ts +92 -0
- package/vendor/@stringsync/splates-server/records/home.d.ts +72 -0
- package/vendor/@stringsync/splates-server/records/index.d.ts +10 -0
- package/vendor/@stringsync/splates-server/records/index.js +40 -0
- package/vendor/@stringsync/splates-server/records/journal.d.ts +65 -0
- package/vendor/@stringsync/splates-server/records/lease-lock.d.ts +29 -0
- package/vendor/@stringsync/splates-server/records/migration.d.ts +94 -0
- package/vendor/@stringsync/splates-server/records/one-task-store.d.ts +15 -0
- package/vendor/@stringsync/splates-server/records/repository.d.ts +137 -0
- package/vendor/@stringsync/splates-server/records/task-files.d.ts +8 -0
- package/vendor/@stringsync/splates-server/records/task-stages.d.ts +7 -0
- package/vendor/@stringsync/splates-server/records/to-sqlite.d.ts +3 -0
- package/vendor/@stringsync/splates-server/replica/aws-sign.d.ts +30 -0
- package/vendor/@stringsync/splates-server/replica/dir.d.ts +17 -0
- package/vendor/@stringsync/splates-server/replica/index.d.ts +14 -0
- package/vendor/@stringsync/splates-server/replica/index.js +29 -0
- package/vendor/@stringsync/splates-server/replica/layout.d.ts +45 -0
- package/vendor/@stringsync/splates-server/replica/place.d.ts +31 -0
- package/vendor/@stringsync/splates-server/replica/replica.d.ts +37 -0
- package/vendor/@stringsync/splates-server/replica/replicator.d.ts +102 -0
- package/vendor/@stringsync/splates-server/replica/restore.d.ts +40 -0
- package/vendor/@stringsync/splates-server/replica/s3.d.ts +45 -0
- package/vendor/@stringsync/splates-server/replica/shipped.d.ts +2 -0
- package/vendor/@stringsync/splates-server/replica/status.d.ts +18 -0
- package/vendor/@stringsync/splates-server/server/assets.d.ts +35 -0
- package/vendor/@stringsync/splates-server/server/automations.d.ts +26 -0
- package/vendor/@stringsync/splates-server/server/chunk-files.d.ts +4 -0
- package/vendor/@stringsync/splates-server/server/conflict-watch.d.ts +22 -0
- package/vendor/@stringsync/splates-server/server/early-warning.d.ts +7 -0
- package/vendor/@stringsync/splates-server/server/general.d.ts +53 -0
- package/vendor/@stringsync/splates-server/server/groomer.d.ts +53 -0
- package/vendor/@stringsync/splates-server/server/held.d.ts +10 -0
- package/vendor/@stringsync/splates-server/server/http.d.ts +76 -0
- package/vendor/@stringsync/splates-server/server/index.d.ts +16 -0
- package/vendor/@stringsync/splates-server/server/index.js +14342 -0
- package/vendor/@stringsync/splates-server/server/interrupt.d.ts +24 -0
- package/vendor/@stringsync/splates-server/server/loop-watch.d.ts +12 -0
- package/vendor/@stringsync/splates-server/server/migrations.d.ts +46 -0
- package/vendor/@stringsync/splates-server/server/options.d.ts +143 -0
- package/vendor/@stringsync/splates-server/server/pages.d.ts +35 -0
- package/vendor/@stringsync/splates-server/server/ports.d.ts +11 -0
- package/vendor/@stringsync/splates-server/server/premerge.d.ts +61 -0
- package/vendor/@stringsync/splates-server/server/project-watch.d.ts +94 -0
- package/vendor/@stringsync/splates-server/server/project.d.ts +239 -0
- package/vendor/@stringsync/splates-server/server/pulse.d.ts +8 -0
- package/vendor/@stringsync/splates-server/server/release.d.ts +41 -0
- package/vendor/@stringsync/splates-server/server/replicas.d.ts +23 -0
- package/vendor/@stringsync/splates-server/server/restart.d.ts +177 -0
- package/vendor/@stringsync/splates-server/server/runtime-deps.d.ts +19 -0
- package/vendor/@stringsync/splates-server/server/server.d.ts +19 -0
- package/vendor/@stringsync/splates-server/server/servers.d.ts +31 -0
- package/vendor/@stringsync/splates-server/server/serving.d.ts +28 -0
- package/vendor/@stringsync/splates-server/server/shared.d.ts +14 -0
- package/vendor/@stringsync/splates-server/server/skills.d.ts +16 -0
- package/vendor/@stringsync/splates-server/server/sockets.d.ts +13 -0
- package/vendor/@stringsync/splates-server/server/start-settings.d.ts +15 -0
- package/vendor/@stringsync/splates-server/server/start.d.ts +21 -0
- package/vendor/@stringsync/splates-server/server/suite-grant.d.ts +26 -0
- package/vendor/@stringsync/splates-server/server/supervise.d.ts +81 -0
- package/vendor/@stringsync/splates-server/server/ticketed-lock.d.ts +80 -0
- package/vendor/@stringsync/splates-server/server/update-records.d.ts +8 -0
- package/vendor/@stringsync/splates-server/server/update.d.ts +56 -0
- package/vendor/@stringsync/splates-server/server/versions.d.ts +53 -0
- package/vendor/@stringsync/splates-server/setup/area-auto-pick.d.ts +7 -0
- package/vendor/@stringsync/splates-server/setup/area-dictation.d.ts +3 -0
- package/vendor/@stringsync/splates-server/setup/area-droplet.d.ts +3 -0
- package/vendor/@stringsync/splates-server/setup/area-evals.d.ts +3 -0
- package/vendor/@stringsync/splates-server/setup/area-github.d.ts +8 -0
- package/vendor/@stringsync/splates-server/setup/area-native.d.ts +7 -0
- package/vendor/@stringsync/splates-server/setup/area-opencode.d.ts +5 -0
- package/vendor/@stringsync/splates-server/setup/area-remote.d.ts +3 -0
- package/vendor/@stringsync/splates-server/setup/area-replica.d.ts +3 -0
- package/vendor/@stringsync/splates-server/setup/area-workers.d.ts +5 -0
- package/vendor/@stringsync/splates-server/setup/areas.d.ts +7 -0
- package/vendor/@stringsync/splates-server/setup/checks.d.ts +8 -0
- package/vendor/@stringsync/splates-server/setup/fields.d.ts +69 -0
- package/vendor/@stringsync/splates-server/setup/index.d.ts +8 -0
- package/vendor/@stringsync/splates-server/setup/index.js +25 -0
- package/vendor/@stringsync/splates-server/setup/opencode-model-error.d.ts +3 -0
- package/vendor/@stringsync/splates-server/setup/opencode-models.d.ts +44 -0
- package/vendor/@stringsync/splates-server/setup/opencode-recipe.d.ts +33 -0
- package/vendor/@stringsync/splates-server/setup/opencode-routes.d.ts +17 -0
- package/vendor/@stringsync/splates-server/setup/opencode.d.ts +61 -0
- package/vendor/@stringsync/splates-server/setup/project.d.ts +10 -0
- package/vendor/@stringsync/splates-server/setup/routes.d.ts +31 -0
- package/vendor/@stringsync/splates-server/setup/setup.d.ts +235 -0
- package/vendor/@stringsync/splates-server/setup/step-problem.d.ts +3 -0
- package/vendor/@stringsync/splates-server/setup/undo.d.ts +80 -0
- package/vendor/@stringsync/splates-server/ship/approval-watch.d.ts +57 -0
- package/vendor/@stringsync/splates-server/ship/approval.d.ts +17 -0
- package/vendor/@stringsync/splates-server/ship/cascade-routes.d.ts +25 -0
- package/vendor/@stringsync/splates-server/ship/cascade.d.ts +70 -0
- package/vendor/@stringsync/splates-server/ship/commands.d.ts +26 -0
- package/vendor/@stringsync/splates-server/ship/git.d.ts +31 -0
- package/vendor/@stringsync/splates-server/ship/graph.d.ts +60 -0
- package/vendor/@stringsync/splates-server/ship/history.d.ts +51 -0
- package/vendor/@stringsync/splates-server/ship/index.d.ts +28 -0
- package/vendor/@stringsync/splates-server/ship/live.d.ts +40 -0
- package/vendor/@stringsync/splates-server/ship/mechanical.d.ts +30 -0
- package/vendor/@stringsync/splates-server/ship/npm-terminal.d.ts +14 -0
- package/vendor/@stringsync/splates-server/ship/plan.d.ts +90 -0
- package/vendor/@stringsync/splates-server/ship/progress.d.ts +3 -0
- package/vendor/@stringsync/splates-server/ship/published-notice.d.ts +29 -0
- package/vendor/@stringsync/splates-server/ship/record.d.ts +55 -0
- package/vendor/@stringsync/splates-server/ship/registry.d.ts +13 -0
- package/vendor/@stringsync/splates-server/ship/release-events.d.ts +47 -0
- package/vendor/@stringsync/splates-server/ship/release-steps.d.ts +66 -0
- package/vendor/@stringsync/splates-server/ship/routes.d.ts +14 -0
- package/vendor/@stringsync/splates-server/ship/run.d.ts +132 -0
- package/vendor/@stringsync/splates-server/ship/selection.d.ts +36 -0
- package/vendor/@stringsync/splates-server/ship/served.d.ts +4 -0
- package/vendor/@stringsync/splates-server/ship/stages.d.ts +69 -0
- package/vendor/@stringsync/splates-server/ship/steps.d.ts +69 -0
- package/vendor/@stringsync/splates-server/ship/token-request.d.ts +11 -0
- package/vendor/@stringsync/splates-server/ship/token.d.ts +21 -0
- package/vendor/@stringsync/splates-server/spend/adapters.d.ts +5 -0
- package/vendor/@stringsync/splates-server/spend/billing.d.ts +38 -0
- package/vendor/@stringsync/splates-server/spend/index.d.ts +15 -0
- package/vendor/@stringsync/splates-server/spend/plans.d.ts +45 -0
- package/vendor/@stringsync/splates-server/spend/providers.d.ts +45 -0
- package/vendor/@stringsync/splates-server/spend/rates.d.ts +23 -0
- package/vendor/@stringsync/splates-server/spend/report.d.ts +39 -0
- package/vendor/@stringsync/splates-server/spend/routes.d.ts +46 -0
- package/vendor/@stringsync/splates-server/spend/spend.d.ts +15 -0
- package/vendor/@stringsync/splates-server/spend/totals.d.ts +63 -0
- package/vendor/@stringsync/splates-server/spend/turn.d.ts +39 -0
- package/vendor/@stringsync/splates-server/stats/adherence.d.ts +40 -0
- package/vendor/@stringsync/splates-server/stats/baselines.d.ts +55 -0
- package/vendor/@stringsync/splates-server/stats/budget-routes.d.ts +21 -0
- package/vendor/@stringsync/splates-server/stats/fact-tasks.d.ts +19 -0
- package/vendor/@stringsync/splates-server/stats/finding-facts.d.ts +37 -0
- package/vendor/@stringsync/splates-server/stats/findings.d.ts +89 -0
- package/vendor/@stringsync/splates-server/stats/index.d.ts +12 -0
- package/vendor/@stringsync/splates-server/stats/index.js +30 -0
- package/vendor/@stringsync/splates-server/stats/landed.d.ts +14 -0
- package/vendor/@stringsync/splates-server/stats/outcomes.d.ts +207 -0
- package/vendor/@stringsync/splates-server/stats/overrides.d.ts +19 -0
- package/vendor/@stringsync/splates-server/stats/routes.d.ts +23 -0
- package/vendor/@stringsync/splates-server/stats/scry-models.d.ts +22 -0
- package/vendor/@stringsync/splates-server/stats/skill-checks.d.ts +59 -0
- package/vendor/@stringsync/splates-server/stats/stats.d.ts +176 -0
- package/vendor/@stringsync/splates-server/stats/task-log.d.ts +67 -0
- package/vendor/@stringsync/splates-server/storage/atomic.d.ts +13 -0
- package/vendor/@stringsync/splates-server/storage/collection.d.ts +30 -0
- package/vendor/@stringsync/splates-server/storage/document.d.ts +26 -0
- package/vendor/@stringsync/splates-server/storage/fs-collection.d.ts +26 -0
- package/vendor/@stringsync/splates-server/storage/fs-document.d.ts +16 -0
- package/vendor/@stringsync/splates-server/storage/fs-log.d.ts +31 -0
- package/vendor/@stringsync/splates-server/storage/fs.d.ts +48 -0
- package/vendor/@stringsync/splates-server/storage/index.d.ts +11 -0
- package/vendor/@stringsync/splates-server/storage/index.js +18 -0
- package/vendor/@stringsync/splates-server/storage/json.d.ts +10 -0
- package/vendor/@stringsync/splates-server/storage/key.d.ts +7 -0
- package/vendor/@stringsync/splates-server/storage/log.d.ts +60 -0
- package/vendor/@stringsync/splates-server/storage/schema.d.ts +7 -0
- package/vendor/@stringsync/splates-server/storage/sqlite-collection.d.ts +31 -0
- package/vendor/@stringsync/splates-server/storage/sqlite-db.d.ts +62 -0
- package/vendor/@stringsync/splates-server/storage/sqlite-document.d.ts +20 -0
- package/vendor/@stringsync/splates-server/storage/sqlite-import.d.ts +11 -0
- package/vendor/@stringsync/splates-server/storage/sqlite-keys.d.ts +17 -0
- package/vendor/@stringsync/splates-server/storage/sqlite-lock.d.ts +25 -0
- package/vendor/@stringsync/splates-server/storage/sqlite-log.d.ts +31 -0
- package/vendor/@stringsync/splates-server/storage/sqlite.d.ts +53 -0
- package/vendor/@stringsync/splates-server/storage/storage.d.ts +87 -0
- package/vendor/@stringsync/splates-server/table.d.ts +5 -0
- package/vendor/@stringsync/splates-server/tasks/add.d.ts +45 -0
- package/vendor/@stringsync/splates-server/tasks/browser.d.ts +5 -0
- package/vendor/@stringsync/splates-server/tasks/checkpoint.d.ts +39 -0
- package/vendor/@stringsync/splates-server/tasks/claim.d.ts +14 -0
- package/vendor/@stringsync/splates-server/tasks/conflicts.d.ts +19 -0
- package/vendor/@stringsync/splates-server/tasks/diff.d.ts +29 -0
- package/vendor/@stringsync/splates-server/tasks/dispatched.d.ts +15 -0
- package/vendor/@stringsync/splates-server/tasks/editors.d.ts +22 -0
- package/vendor/@stringsync/splates-server/tasks/finished.d.ts +81 -0
- package/vendor/@stringsync/splates-server/tasks/follow.d.ts +48 -0
- package/vendor/@stringsync/splates-server/tasks/index.d.ts +30 -0
- package/vendor/@stringsync/splates-server/tasks/index.js +90 -0
- package/vendor/@stringsync/splates-server/tasks/landings.d.ts +17 -0
- package/vendor/@stringsync/splates-server/tasks/list.d.ts +18 -0
- package/vendor/@stringsync/splates-server/tasks/merge-output.d.ts +13 -0
- package/vendor/@stringsync/splates-server/tasks/open.d.ts +15 -0
- package/vendor/@stringsync/splates-server/tasks/overlaps.d.ts +16 -0
- package/vendor/@stringsync/splates-server/tasks/path.d.ts +13 -0
- package/vendor/@stringsync/splates-server/tasks/recommend.d.ts +30 -0
- package/vendor/@stringsync/splates-server/tasks/remove.d.ts +47 -0
- package/vendor/@stringsync/splates-server/tasks/retry.d.ts +35 -0
- package/vendor/@stringsync/splates-server/tasks/routes.d.ts +23 -0
- package/vendor/@stringsync/splates-server/tasks/show.d.ts +137 -0
- package/vendor/@stringsync/splates-server/tasks/snapshot.d.ts +86 -0
- package/vendor/@stringsync/splates-server/tasks/started-records.d.ts +71 -0
- package/vendor/@stringsync/splates-server/tasks/wait.d.ts +47 -0
- package/vendor/@stringsync/splates-server/tasks/worktree-checkouts.d.ts +10 -0
- package/vendor/@stringsync/splates-server/tasks/worktree-service.d.ts +151 -0
- package/vendor/@stringsync/splates-server/tasks/worktree.d.ts +342 -0
- package/vendor/@stringsync/splates-server/terminal/connection.d.ts +19 -0
- package/vendor/@stringsync/splates-server/terminal/held.d.ts +22 -0
- package/vendor/@stringsync/splates-server/terminal/index.d.ts +7 -0
- package/vendor/@stringsync/splates-server/terminal/pty.d.ts +45 -0
- package/vendor/@stringsync/splates-server/terminal/remote-pty.d.ts +34 -0
- package/vendor/@stringsync/splates-server/terminal/shell.d.ts +70 -0
- package/vendor/@stringsync/splates-server/terminal/spawn.d.ts +22 -0
- package/vendor/@stringsync/splates-server/terminal/terminal.d.ts +52 -0
- package/vendor/@stringsync/splates-server/tunnel/access.d.ts +61 -0
- package/vendor/@stringsync/splates-server/tunnel/cloudflare-api.d.ts +25 -0
- package/vendor/@stringsync/splates-server/tunnel/cloudflare-error.d.ts +5 -0
- package/vendor/@stringsync/splates-server/tunnel/cloudflared.d.ts +43 -0
- package/vendor/@stringsync/splates-server/tunnel/index.d.ts +14 -0
- package/vendor/@stringsync/splates-server/tunnel/index.js +70 -0
- package/vendor/@stringsync/splates-server/tunnel/machine.d.ts +18 -0
- package/vendor/@stringsync/splates-server/tunnel/provider.d.ts +37 -0
- package/vendor/@stringsync/splates-server/tunnel/remove.d.ts +35 -0
- package/vendor/@stringsync/splates-server/tunnel/saved-ports-host.d.ts +26 -0
- package/vendor/@stringsync/splates-server/tunnel/saved.d.ts +63 -0
- package/vendor/@stringsync/splates-server/tunnel/setup.d.ts +123 -0
- package/vendor/@stringsync/splates-server/tunnel/tunnel.d.ts +38 -0
- package/vendor/@stringsync/splates-server/workers/admin.d.ts +37 -0
- package/vendor/@stringsync/splates-server/workers/call-host.d.ts +68 -0
- package/vendor/@stringsync/splates-server/workers/channel.d.ts +90 -0
- package/vendor/@stringsync/splates-server/workers/connection.d.ts +24 -0
- package/vendor/@stringsync/splates-server/workers/coordinator-state.d.ts +44 -0
- package/vendor/@stringsync/splates-server/workers/daemon.d.ts +128 -0
- package/vendor/@stringsync/splates-server/workers/darwin-footprint.d.ts +7 -0
- package/vendor/@stringsync/splates-server/workers/darwin-temperature.d.ts +7 -0
- package/vendor/@stringsync/splates-server/workers/frame-too-large.d.ts +5 -0
- package/vendor/@stringsync/splates-server/workers/git.d.ts +11 -0
- package/vendor/@stringsync/splates-server/workers/gone.d.ts +36 -0
- package/vendor/@stringsync/splates-server/workers/identity.d.ts +30 -0
- package/vendor/@stringsync/splates-server/workers/index.d.ts +40 -0
- package/vendor/@stringsync/splates-server/workers/index.js +90 -0
- package/vendor/@stringsync/splates-server/workers/lifecycle.d.ts +14 -0
- package/vendor/@stringsync/splates-server/workers/list.d.ts +93 -0
- package/vendor/@stringsync/splates-server/workers/load.d.ts +55 -0
- package/vendor/@stringsync/splates-server/workers/local-id.d.ts +11 -0
- package/vendor/@stringsync/splates-server/workers/local-update.d.ts +81 -0
- package/vendor/@stringsync/splates-server/workers/log-file.d.ts +24 -0
- package/vendor/@stringsync/splates-server/workers/machine.d.ts +47 -0
- package/vendor/@stringsync/splates-server/workers/orphan.d.ts +31 -0
- package/vendor/@stringsync/splates-server/workers/os-sensors.d.ts +49 -0
- package/vendor/@stringsync/splates-server/workers/placement.d.ts +39 -0
- package/vendor/@stringsync/splates-server/workers/process-host.d.ts +60 -0
- package/vendor/@stringsync/splates-server/workers/process.d.ts +33 -0
- package/vendor/@stringsync/splates-server/workers/protocol.d.ts +153 -0
- package/vendor/@stringsync/splates-server/workers/pty-host.d.ts +35 -0
- package/vendor/@stringsync/splates-server/workers/queue.d.ts +39 -0
- package/vendor/@stringsync/splates-server/workers/records.d.ts +43 -0
- package/vendor/@stringsync/splates-server/workers/registry.d.ts +101 -0
- package/vendor/@stringsync/splates-server/workers/replay.d.ts +25 -0
- package/vendor/@stringsync/splates-server/workers/routes.d.ts +119 -0
- package/vendor/@stringsync/splates-server/workers/run-options.d.ts +11 -0
- package/vendor/@stringsync/splates-server/workers/run.d.ts +10 -0
- package/vendor/@stringsync/splates-server/workers/scheduler.d.ts +171 -0
- package/vendor/@stringsync/splates-server/workers/server-of.d.ts +23 -0
- package/vendor/@stringsync/splates-server/workers/server-socket.d.ts +25 -0
- package/vendor/@stringsync/splates-server/workers/session.d.ts +240 -0
- package/vendor/@stringsync/splates-server/workers/socket.d.ts +21 -0
- package/vendor/@stringsync/splates-server/workers/unix-listener.d.ts +23 -0
- package/vendor/@stringsync/splates-server/workers/unix-socket.d.ts +30 -0
- package/vendor/@stringsync/splates-server/workers/websocket-socket.d.ts +24 -0
- package/vendor/@stringsync/splates-server/workers/worker.d.ts +98 -0
- package/vendor/core/LICENSE +21 -0
- package/vendor/core/abort/aborts.d.ts +10 -0
- package/vendor/core/abort/index.d.ts +1 -0
- package/vendor/core/abort/index.js +24 -0
- package/vendor/core/assert/assert-error.d.ts +4 -0
- package/vendor/core/assert/assert.d.ts +24 -0
- package/vendor/core/assert/ensure.d.ts +18 -0
- package/vendor/core/assert/index.d.ts +3 -0
- package/vendor/core/assert/index.js +75 -0
- package/vendor/core/cmd/cli.d.ts +70 -0
- package/vendor/core/cmd/command.d.ts +96 -0
- package/vendor/core/cmd/deps.d.ts +12 -0
- package/vendor/core/cmd/help.d.ts +16 -0
- package/vendor/core/cmd/index.d.ts +6 -0
- package/vendor/core/cmd/index.js +477 -0
- package/vendor/core/cmd/middleware.d.ts +15 -0
- package/vendor/core/cmd/timed.d.ts +15 -0
- package/vendor/core/creds/credential-proxy.d.ts +55 -0
- package/vendor/core/creds/credential-source.d.ts +19 -0
- package/vendor/core/creds/credentials.d.ts +28 -0
- package/vendor/core/creds/dotenv-file.d.ts +22 -0
- package/vendor/core/creds/environment.d.ts +18 -0
- package/vendor/core/creds/index.d.ts +8 -0
- package/vendor/core/creds/index.js +337 -0
- package/vendor/core/creds/memory-secret-store.d.ts +33 -0
- package/vendor/core/creds/secret-store.d.ts +14 -0
- package/vendor/core/creds/system-secret-store.d.ts +49 -0
- package/vendor/core/dictate/buffered-sink.d.ts +9 -0
- package/vendor/core/dictate/cue.d.ts +10 -0
- package/vendor/core/dictate/dictation-failure.d.ts +5 -0
- package/vendor/core/dictate/dictation-link.d.ts +18 -0
- package/vendor/core/dictate/dictation-message.d.ts +24 -0
- package/vendor/core/dictate/dictation-relay.d.ts +28 -0
- package/vendor/core/dictate/index.d.ts +10 -0
- package/vendor/core/dictate/index.js +132 -0
- package/vendor/core/dictate/microphone.d.ts +42 -0
- package/vendor/core/dictate/openai-transcriber.d.ts +22 -0
- package/vendor/core/dictate/openai-transcription.d.ts +27 -0
- package/vendor/core/dictate/pcm.d.ts +5 -0
- package/vendor/core/dictate/pcm16-encoder.d.ts +20 -0
- package/vendor/core/dictate/server.d.ts +1 -0
- package/vendor/core/dictate/server.js +153 -0
- package/vendor/core/dictate/transcriber.d.ts +23 -0
- package/vendor/core/disposable/async-disposer.d.ts +15 -0
- package/vendor/core/disposable/async-resource.d.ts +4 -0
- package/vendor/core/disposable/disposables.d.ts +8 -0
- package/vendor/core/disposable/disposer.d.ts +13 -0
- package/vendor/core/disposable/index.d.ts +5 -0
- package/vendor/core/disposable/index.js +96 -0
- package/vendor/core/disposable/resource.d.ts +4 -0
- package/vendor/core/events/dispatcher.d.ts +18 -0
- package/vendor/core/events/eventful.d.ts +7 -0
- package/vendor/core/events/events.d.ts +14 -0
- package/vendor/core/events/index.d.ts +4 -0
- package/vendor/core/events/index.js +75 -0
- package/vendor/core/events/noop-events.d.ts +6 -0
- package/vendor/core/id/counter-id-provider.d.ts +6 -0
- package/vendor/core/id/id-provider.d.ts +7 -0
- package/vendor/core/id/index.d.ts +3 -0
- package/vendor/core/id/index.js +17 -0
- package/vendor/core/id/uuid-provider.d.ts +11 -0
- package/vendor/core/index-qk5dj664.js +4 -0
- package/vendor/core/log/color.d.ts +22 -0
- package/vendor/core/log/composite-logger.d.ts +7 -0
- package/vendor/core/log/console-logger.d.ts +6 -0
- package/vendor/core/log/index.d.ts +8 -0
- package/vendor/core/log/index.js +154 -0
- package/vendor/core/log/level-prefix-logger.d.ts +12 -0
- package/vendor/core/log/logger.d.ts +12 -0
- package/vendor/core/log/mdc-logger.d.ts +14 -0
- package/vendor/core/log/memory-logger.d.ts +8 -0
- package/vendor/core/log/prefix-logger.d.ts +12 -0
- package/vendor/core/md/index.d.ts +2 -0
- package/vendor/core/md/index.js +182 -0
- package/vendor/core/md/markdown.d.ts +56 -0
- package/vendor/core/md/writer.d.ts +22 -0
- package/vendor/core/push/base64url.d.ts +2 -0
- package/vendor/core/push/encrypt.d.ts +12 -0
- package/vendor/core/push/index.d.ts +4 -0
- package/vendor/core/push/index.js +137 -0
- package/vendor/core/push/push-failure.d.ts +7 -0
- package/vendor/core/push/pusher.d.ts +24 -0
- package/vendor/core/push/vapid.d.ts +18 -0
- package/vendor/core/push/web-pusher.d.ts +20 -0
- package/vendor/core/ship/artifact/artifact.d.ts +52 -0
- package/vendor/core/ship/bundle/bun-bundle.d.ts +71 -0
- package/vendor/core/ship/bundle/bundle-artifact.d.ts +21 -0
- package/vendor/core/ship/bundle/bundle.d.ts +13 -0
- package/vendor/core/ship/bundle/published.d.ts +45 -0
- package/vendor/core/ship/bundle/reach.d.ts +43 -0
- package/vendor/core/ship/bundle/vendor-bundle.d.ts +47 -0
- package/vendor/core/ship/cut.d.ts +64 -0
- package/vendor/core/ship/dry-run.d.ts +63 -0
- package/vendor/core/ship/git/cli-git.d.ts +25 -0
- package/vendor/core/ship/git/git-artifact.d.ts +23 -0
- package/vendor/core/ship/git/git.d.ts +19 -0
- package/vendor/core/ship/github/cli-github.d.ts +31 -0
- package/vendor/core/ship/github/cli-workflows.d.ts +25 -0
- package/vendor/core/ship/github/github-artifact.d.ts +18 -0
- package/vendor/core/ship/github/github.d.ts +10 -0
- package/vendor/core/ship/github/login.d.ts +3 -0
- package/vendor/core/ship/github/workflows.d.ts +27 -0
- package/vendor/core/ship/index.d.ts +26 -0
- package/vendor/core/ship/index.js +3203 -0
- package/vendor/core/ship/mirror/agent-files.d.ts +6 -0
- package/vendor/core/ship/mirror/mirror-build.d.ts +63 -0
- package/vendor/core/ship/mirror/mirror-guard.d.ts +10 -0
- package/vendor/core/ship/mirror/mirror-options.d.ts +75 -0
- package/vendor/core/ship/mirror/mirror-step.d.ts +109 -0
- package/vendor/core/ship/mirror/mirror-tooling.d.ts +59 -0
- package/vendor/core/ship/mirror/source-manifest.d.ts +27 -0
- package/vendor/core/ship/order.d.ts +15 -0
- package/vendor/core/ship/publish-workflow.d.ts +32 -0
- package/vendor/core/ship/registry/github-actions.d.ts +76 -0
- package/vendor/core/ship/registry/npm-registry.d.ts +70 -0
- package/vendor/core/ship/registry/registry-artifact.d.ts +31 -0
- package/vendor/core/ship/registry/registry.d.ts +85 -0
- package/vendor/core/ship/release-file.d.ts +22 -0
- package/vendor/core/ship/release-options.d.ts +122 -0
- package/vendor/core/ship/release.d.ts +61 -0
- package/vendor/core/ship/releases.d.ts +119 -0
- package/vendor/core/ship/shipped.d.ts +54 -0
- package/vendor/core/ship/skill-artifact.d.ts +27 -0
- package/vendor/core/ship/step-events.d.ts +91 -0
- package/vendor/core/ship/step-runner.d.ts +16 -0
- package/vendor/core/ship/step.d.ts +49 -0
- package/vendor/core/ship/trust.d.ts +11 -0
- package/vendor/core/ship/version.d.ts +9 -0
- package/vendor/core/ship/workspace/manifest-workspace.d.ts +61 -0
- package/vendor/core/ship/workspace/workspace.d.ts +29 -0
- package/vendor/core/skills/index.d.ts +1 -0
- package/vendor/core/skills/index.js +77 -0
- package/vendor/core/skills/project-skills.d.ts +53 -0
- package/vendor/core/system/fs/fs.d.ts +58 -0
- package/vendor/core/system/fs/node-fs.d.ts +18 -0
- package/vendor/core/system/glob/glob.d.ts +11 -0
- package/vendor/core/system/glob/node-glob.d.ts +12 -0
- package/vendor/core/system/heavy/heavy-jobs.d.ts +84 -0
- package/vendor/core/system/host-mapper/file-host-mapper.d.ts +20 -0
- package/vendor/core/system/host-mapper/host-mapper.d.ts +11 -0
- package/vendor/core/system/host-mapper/noop-host-mapper.d.ts +4 -0
- package/vendor/core/system/index.d.ts +25 -0
- package/vendor/core/system/index.js +1385 -0
- package/vendor/core/system/ip-provider/darwin-ip-provider.d.ts +6 -0
- package/vendor/core/system/ip-provider/ip-provider.d.ts +8 -0
- package/vendor/core/system/ip-provider/linux-ip-provider.d.ts +6 -0
- package/vendor/core/system/ip-provider/platform-ip-provider.d.ts +6 -0
- package/vendor/core/system/ip-provider/sequential-ip-provider.d.ts +6 -0
- package/vendor/core/system/ip-provider/static-ip-provider.d.ts +8 -0
- package/vendor/core/system/ip-provider/win32-ip-provider.d.ts +6 -0
- package/vendor/core/system/lock/file-lock.d.ts +50 -0
- package/vendor/core/system/lock/lock.d.ts +11 -0
- package/vendor/core/system/lock/memory-lock.d.ts +13 -0
- package/vendor/core/system/port-provider/open-port-provider.d.ts +38 -0
- package/vendor/core/system/port-provider/port-provider.d.ts +14 -0
- package/vendor/core/system/process-like/process-like.d.ts +22 -0
- package/vendor/core/system/ps/file-process.d.ts +40 -0
- package/vendor/core/system/ps/listening.d.ts +20 -0
- package/vendor/core/system/ps/node-ps.d.ts +39 -0
- package/vendor/core/system/ps/ps.d.ts +161 -0
- package/vendor/core/system/ps/reap.d.ts +22 -0
- package/vendor/core/system/undumpable.d.ts +32 -0
- package/vendor/core/system/walk.d.ts +10 -0
- package/vendor/core/time/clock/clock.d.ts +5 -0
- package/vendor/core/time/clock/system-clock.d.ts +5 -0
- package/vendor/core/time/debouncer.d.ts +25 -0
- package/vendor/core/time/duration.d.ts +38 -0
- package/vendor/core/time/index.d.ts +13 -0
- package/vendor/core/time/index.js +271 -0
- package/vendor/core/time/sleep.d.ts +2 -0
- package/vendor/core/time/stopwatch.d.ts +34 -0
- package/vendor/core/time/throttler.d.ts +26 -0
- package/vendor/core/time/time-ago.d.ts +14 -0
- package/vendor/core/time/timeouts.d.ts +12 -0
- package/vendor/core/time/timer/system-timer.d.ts +7 -0
- package/vendor/core/time/timer/timer.d.ts +11 -0
- package/vendor/core/time/wall-clock/system-wall-clock.d.ts +4 -0
- package/vendor/core/time/wall-clock/wall-clock.d.ts +14 -0
- package/waiting.d.ts +2 -2
- package/worker.d.ts +2 -2
|
@@ -0,0 +1,2356 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JUDGE_CREDS,
|
|
3
|
+
judgeFrom,
|
|
4
|
+
AutoPickStore
|
|
5
|
+
} from "./index-acbcm66f.js";
|
|
6
|
+
import {
|
|
7
|
+
KIMI_CLI2,
|
|
8
|
+
AgentStream2,
|
|
9
|
+
body,
|
|
10
|
+
refuse,
|
|
11
|
+
FsStorage2,
|
|
12
|
+
API_TOKEN2,
|
|
13
|
+
SavedTunnel2,
|
|
14
|
+
tunnelSetup2,
|
|
15
|
+
TOKEN_PERMISSIONS2,
|
|
16
|
+
TOKENS_PAGE2,
|
|
17
|
+
tokenInstructions2,
|
|
18
|
+
SavedPortsHost2,
|
|
19
|
+
portsHostFlag2,
|
|
20
|
+
APP_ID2,
|
|
21
|
+
APP_KEY2,
|
|
22
|
+
GitHubApp2,
|
|
23
|
+
githubRepo2,
|
|
24
|
+
PUSHED_PREFIX2,
|
|
25
|
+
LOCAL_WORKER2,
|
|
26
|
+
framed2,
|
|
27
|
+
Roster2,
|
|
28
|
+
DEFAULT_AGENTS2,
|
|
29
|
+
splatesHome2
|
|
30
|
+
} from "./index-caep3sde.js";
|
|
31
|
+
import {
|
|
32
|
+
fail2
|
|
33
|
+
} from "./index-t9w5a8ed.js";
|
|
34
|
+
import {
|
|
35
|
+
Git,
|
|
36
|
+
loadConfig2
|
|
37
|
+
} from "./index-e9z7s5hh.js";
|
|
38
|
+
import {
|
|
39
|
+
REPLICA_ACCESS_KEY2,
|
|
40
|
+
REPLICA_SECRET_KEY2
|
|
41
|
+
} from "./index-5axhdy8c.js";
|
|
42
|
+
|
|
43
|
+
// setup/area-auto-pick.ts
|
|
44
|
+
import { Credentials } from "../../core/creds/index.js";
|
|
45
|
+
var TYPESAFE_KEY = JUDGE_CREDS.jev[0];
|
|
46
|
+
var TYPESAFE = "https://typesafe.ai";
|
|
47
|
+
var AUTO_PICK_AREA = autoPickArea();
|
|
48
|
+
function autoPickArea() {
|
|
49
|
+
const judgeStep = {
|
|
50
|
+
id: "auto-pick-judge",
|
|
51
|
+
title: "Give Auto pick a decision model",
|
|
52
|
+
why: "Auto pick asks a small decision model what kind of work a task is and how deeply it needs to reason, to start it on the agent, model and thinking level your rules give that. Without one, every Auto pick takes your rule for any kind and depth.",
|
|
53
|
+
user: `Create a TypeSafe API key and paste it here, for Jev. Clef on Cloudflare works too, with ${JUDGE_CREDS.clef.join(" and ")} kept for this device.`,
|
|
54
|
+
agent: `Request it with \`splates creds request ${TYPESAFE_KEY} --device\`, with how to get it; or, for Clef, ${JUDGE_CREDS.clef.map((name) => `\`${name}\``).join(" and ")} the same way.`,
|
|
55
|
+
optional: true,
|
|
56
|
+
after: [],
|
|
57
|
+
fields: [
|
|
58
|
+
{
|
|
59
|
+
kind: "cred",
|
|
60
|
+
name: TYPESAFE_KEY,
|
|
61
|
+
label: "TypeSafe API key",
|
|
62
|
+
help: `Make one in [TypeSafe](${TYPESAFE}) under API keys. To use Clef instead, keep ${JUDGE_CREDS.clef.map((name) => `\`${name}\``).join(" and ")} for this device on the Creds page and leave this empty.`,
|
|
63
|
+
optional: true
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
uses: JUDGE_CREDS.clef,
|
|
67
|
+
check: async ({ device }) => await judgeFrom(new Credentials([device])) !== null,
|
|
68
|
+
undo: {
|
|
69
|
+
removes: async ({ device }) => await device.get(TYPESAFE_KEY) === undefined ? [] : ["The TypeSafe API key kept on this device"],
|
|
70
|
+
leaves: async ({ device }) => {
|
|
71
|
+
const leaves = [];
|
|
72
|
+
if (await device.get(TYPESAFE_KEY) !== undefined) {
|
|
73
|
+
leaves.push(`The key still works: revoke it in [TypeSafe](${TYPESAFE}) under API keys if you no longer want it.`);
|
|
74
|
+
}
|
|
75
|
+
if (await clefKept(device)) {
|
|
76
|
+
leaves.push(`Auto pick still judges with Clef, on ${JUDGE_CREDS.clef.map((name) => `\`${name}\``).join(" and ")}, kept for scry's Workers AI: forget them on the Creds page to stop it.`);
|
|
77
|
+
}
|
|
78
|
+
return leaves;
|
|
79
|
+
},
|
|
80
|
+
run: async () => {}
|
|
81
|
+
},
|
|
82
|
+
notDone: `Paste a TypeSafe API key, or keep ${JUDGE_CREDS.clef.join(" and ")} for this device, then press Next.`
|
|
83
|
+
};
|
|
84
|
+
const rulesStep = {
|
|
85
|
+
id: "auto-pick-rules",
|
|
86
|
+
title: "Map tasks to models",
|
|
87
|
+
why: "Auto pick tries your rules from the top, and the first that matches a task's kind and depth picks its agent; a pick whose plan is nearly used up, or used faster than its window goes by, is passed over for the next on its row.",
|
|
88
|
+
user: "Edit the rules, then press Next to save them. They are kept in `~/.splates/auto-pick.json`, which you can edit by hand too.",
|
|
89
|
+
agent: "Have the user edit the rules on the page, or edit `~/.splates/auto-pick.json` with them; its last rule must stay kind `*` and depth `*`.",
|
|
90
|
+
optional: true,
|
|
91
|
+
after: [],
|
|
92
|
+
check: async (machine) => machine.fs.exists(rulesPath(machine)),
|
|
93
|
+
submit: async (machine) => {
|
|
94
|
+
const store = new AutoPickStore(rulesPath(machine), { fs: machine.fs });
|
|
95
|
+
if (!await machine.fs.exists(store.path)) {
|
|
96
|
+
await store.save(await store.rules());
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
doing: "Saving your rules…",
|
|
100
|
+
undo: {
|
|
101
|
+
removes: async (machine) => [
|
|
102
|
+
`Your Auto pick rules in \`${rulesPath(machine)}\``
|
|
103
|
+
],
|
|
104
|
+
run: (machine) => new AutoPickStore(rulesPath(machine), { fs: machine.fs }).remove()
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const tryStep = {
|
|
108
|
+
id: "auto-pick-try",
|
|
109
|
+
title: "Try it on a task",
|
|
110
|
+
why: "See what Auto pick would start a task on, and why, without starting it.",
|
|
111
|
+
user: "Pick a task to see what Auto pick would do with it.",
|
|
112
|
+
agent: "Have the user pick a task on the page; trying starts nothing and changes no task.",
|
|
113
|
+
optional: true,
|
|
114
|
+
after: [rulesStep],
|
|
115
|
+
check: async (machine) => machine.fs.exists(rulesPath(machine))
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
id: "auto-pick",
|
|
119
|
+
title: "Auto pick",
|
|
120
|
+
purpose: "Let a small model pick which agent and model starts each task.",
|
|
121
|
+
steps: [rulesStep, judgeStep, tryStep]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
async function clefKept(device) {
|
|
125
|
+
for (const name of JUDGE_CREDS.clef) {
|
|
126
|
+
if (await device.get(name) === undefined) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
function rulesPath({ home }) {
|
|
133
|
+
return `${home}/auto-pick.json`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// dictate/connection.ts
|
|
137
|
+
import {
|
|
138
|
+
DictationFailure,
|
|
139
|
+
DictationRelay
|
|
140
|
+
} from "../../core/dictate/index.js";
|
|
141
|
+
|
|
142
|
+
// dictate/transcriber.ts
|
|
143
|
+
import { basename } from "node:path";
|
|
144
|
+
import { OpenAiTranscriber } from "../../core/dictate/server.js";
|
|
145
|
+
|
|
146
|
+
// dictate/personal.ts
|
|
147
|
+
class PersonalWords {
|
|
148
|
+
path;
|
|
149
|
+
deps;
|
|
150
|
+
constructor(path, deps) {
|
|
151
|
+
this.path = path;
|
|
152
|
+
this.deps = deps;
|
|
153
|
+
}
|
|
154
|
+
saved() {
|
|
155
|
+
return this.deps.fs.exists(this.path);
|
|
156
|
+
}
|
|
157
|
+
async words() {
|
|
158
|
+
const raw = await this.deps.fs.read(this.path).catch(() => null);
|
|
159
|
+
if (raw === null) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
let json;
|
|
163
|
+
try {
|
|
164
|
+
json = JSON.parse(raw);
|
|
165
|
+
} catch {
|
|
166
|
+
fail2("usage", `${this.path} is not JSON: fix or delete it`, {
|
|
167
|
+
path: this.path
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const words = json?.words;
|
|
171
|
+
if (!Array.isArray(words) || !words.every((word) => typeof word === "string")) {
|
|
172
|
+
fail2("usage", `${this.path} has no \`words\` list of strings: fix or delete it`, { path: this.path });
|
|
173
|
+
}
|
|
174
|
+
return words;
|
|
175
|
+
}
|
|
176
|
+
async save(words) {
|
|
177
|
+
await this.deps.fs.mkdir(this.path.slice(0, this.path.lastIndexOf("/")), {
|
|
178
|
+
recursive: true
|
|
179
|
+
});
|
|
180
|
+
const tmp = `${this.path}.${crypto.randomUUID()}.tmp`;
|
|
181
|
+
await this.deps.fs.write(tmp, `${JSON.stringify({ words }, null, "\t")}
|
|
182
|
+
`);
|
|
183
|
+
await this.deps.fs.rename(tmp, this.path);
|
|
184
|
+
}
|
|
185
|
+
async remove() {
|
|
186
|
+
await this.deps.fs.rm(this.path, { force: true });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function personalWordsPath(home) {
|
|
190
|
+
return `${home}/dictation.json`;
|
|
191
|
+
}
|
|
192
|
+
function parseWords(text) {
|
|
193
|
+
return text.split(/[,\n]/).map((word) => word.trim()).filter((word) => word !== "");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// dictate/vocabulary.ts
|
|
197
|
+
var MAX_WORDS = 50;
|
|
198
|
+
function words(project, ...lists) {
|
|
199
|
+
return [...new Set(["splates", project, ...lists.flat()])].slice(0, MAX_WORDS);
|
|
200
|
+
}
|
|
201
|
+
function vocabulary(listed) {
|
|
202
|
+
return `A developer dictating a prompt for a coding agent. Words that may come up: ${listed.join(", ")}.`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// dictate/transcriber.ts
|
|
206
|
+
var OPENAI_KEY = "OPENAI_API_KEY";
|
|
207
|
+
var PURPOSE = "The mic in the composer transcribes what you say with OpenAI's `gpt-live-transcribe`, on your key.";
|
|
208
|
+
var INSTRUCTIONS = `1. Open [API keys](https://platform.openai.com/api-keys), then **Create new secret key**.
|
|
209
|
+
2. Give it access to the Realtime API (or all), and create it.
|
|
210
|
+
3. Paste it here.`;
|
|
211
|
+
var transcriberFor = async (project, tick) => {
|
|
212
|
+
const key = await project.creds.credentials.get(OPENAI_KEY);
|
|
213
|
+
if (key === undefined) {
|
|
214
|
+
await project.journal.record("creds request", null, () => project.creds.request(OPENAI_KEY, {
|
|
215
|
+
scope: "device",
|
|
216
|
+
purpose: PURPOSE,
|
|
217
|
+
instructions: INSTRUCTIONS,
|
|
218
|
+
task: null
|
|
219
|
+
}), (asked) => ({ name: OPENAI_KEY, asked: asked !== null }));
|
|
220
|
+
tick();
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const root = project.service.git.root;
|
|
224
|
+
const personal = await new PersonalWords(personalWordsPath(splatesHome2(project.ps)), project).words().catch((error) => {
|
|
225
|
+
project.log.error(error instanceof Error ? error.message : String(error));
|
|
226
|
+
return [];
|
|
227
|
+
});
|
|
228
|
+
const listed = words(basename(root), project.config.dictationWords, personal);
|
|
229
|
+
return new OpenAiTranscriber(key, {
|
|
230
|
+
prompt: vocabulary(listed),
|
|
231
|
+
keywords: listed
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// dictate/connection.ts
|
|
236
|
+
class DictationConnection {
|
|
237
|
+
transcriber;
|
|
238
|
+
relay;
|
|
239
|
+
constructor(transcriber) {
|
|
240
|
+
this.transcriber = transcriber;
|
|
241
|
+
}
|
|
242
|
+
open(socket) {
|
|
243
|
+
this.relay = new DictationRelay({
|
|
244
|
+
send: (message) => socket.send(message),
|
|
245
|
+
hangUp: () => socket.close()
|
|
246
|
+
}, this.transcriber.then((transcriber) => {
|
|
247
|
+
if (transcriber === null) {
|
|
248
|
+
throw new DictationFailure(`dictation needs ${OPENAI_KEY}: add it on the Creds page`, OPENAI_KEY);
|
|
249
|
+
}
|
|
250
|
+
return transcriber;
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
253
|
+
message(_socket, message) {
|
|
254
|
+
this.relay?.receive(typeof message === "string" ? message : new Uint8Array(message));
|
|
255
|
+
}
|
|
256
|
+
closed() {
|
|
257
|
+
this.relay?.dispose();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// dictate/dictate.ts
|
|
262
|
+
class Dictations {
|
|
263
|
+
gate;
|
|
264
|
+
projects;
|
|
265
|
+
constructor(gate, projects) {
|
|
266
|
+
this.gate = gate;
|
|
267
|
+
this.projects = projects;
|
|
268
|
+
}
|
|
269
|
+
open = (request, server) => this.gate.local(this.gate.guarded(async (request2) => {
|
|
270
|
+
const host = request2.headers.get("host") ?? "";
|
|
271
|
+
const origin = URL.parse(request2.headers.get("origin") ?? "");
|
|
272
|
+
if (origin === null || origin.host !== host) {
|
|
273
|
+
return refuse(403, "forbidden", "a dictation opens only from its own page");
|
|
274
|
+
}
|
|
275
|
+
const project = await this.projects.projectFor(request2);
|
|
276
|
+
const data = new DictationConnection(project.transcriber());
|
|
277
|
+
return server.upgrade(request2, { data }) ? undefined : refuse(400, "usage", "a dictation is a WebSocket: connect with one");
|
|
278
|
+
}))(request);
|
|
279
|
+
}
|
|
280
|
+
// setup/area-dictation.ts
|
|
281
|
+
var DICTATION_AREA = dictationArea();
|
|
282
|
+
function dictationArea() {
|
|
283
|
+
const dictationStep = {
|
|
284
|
+
id: "dictation",
|
|
285
|
+
title: "Dictate prompts",
|
|
286
|
+
why: "The composer's mic transcribes what you say with OpenAI, on a key of your own.",
|
|
287
|
+
user: "Create an OpenAI API key and paste it here.",
|
|
288
|
+
agent: `Request it with \`splates creds request ${OPENAI_KEY} --device\`, with how to get it.`,
|
|
289
|
+
optional: true,
|
|
290
|
+
after: [],
|
|
291
|
+
fields: [
|
|
292
|
+
{
|
|
293
|
+
kind: "cred",
|
|
294
|
+
name: OPENAI_KEY,
|
|
295
|
+
label: "OpenAI API key",
|
|
296
|
+
help: "Make one at [API keys](https://platform.openai.com/api-keys) with **Create new secret key**, then paste it."
|
|
297
|
+
}
|
|
298
|
+
],
|
|
299
|
+
check: async ({ device }) => await device.get(OPENAI_KEY) !== undefined,
|
|
300
|
+
undo: {
|
|
301
|
+
removes: async () => ["The OpenAI API key kept on this device"],
|
|
302
|
+
leaves: async () => [
|
|
303
|
+
"The key still works: revoke it at [API keys](https://platform.openai.com/api-keys) if you no longer want it."
|
|
304
|
+
],
|
|
305
|
+
run: async () => {}
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const wordsStep = {
|
|
309
|
+
id: "dictation-words",
|
|
310
|
+
title: "Teach it your words",
|
|
311
|
+
why: "The mic spells splates, the project's name and the project's `dictationWords` as written; add the names you say in every project, such as your tools and the people you mention.",
|
|
312
|
+
user: "List your words, separated by commas, then press Next. They are kept in `~/.splates/dictation.json`.",
|
|
313
|
+
agent: 'Have the user list them on the page, or write `~/.splates/dictation.json` as `{ "words": [...] }`. Words for one project go in its `splates.config.ts` as `dictationWords` instead.',
|
|
314
|
+
optional: true,
|
|
315
|
+
after: [dictationStep],
|
|
316
|
+
fields: async (machine) => [
|
|
317
|
+
{
|
|
318
|
+
kind: "text",
|
|
319
|
+
name: "words",
|
|
320
|
+
label: "Your words",
|
|
321
|
+
placeholder: "Pulumi, Fly, Ana",
|
|
322
|
+
value: (await store(machine).words().catch(() => [])).join(", "),
|
|
323
|
+
optional: true
|
|
324
|
+
}
|
|
325
|
+
],
|
|
326
|
+
check: (machine) => store(machine).saved(),
|
|
327
|
+
submit: async (machine, answers) => {
|
|
328
|
+
const words = answers.words;
|
|
329
|
+
await store(machine).save(parseWords(typeof words === "string" ? words : ""));
|
|
330
|
+
},
|
|
331
|
+
doing: "Saving your words…",
|
|
332
|
+
undo: {
|
|
333
|
+
removes: async (machine) => [
|
|
334
|
+
`Your dictation words in \`${store(machine).path}\``
|
|
335
|
+
],
|
|
336
|
+
run: (machine) => store(machine).remove()
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
return {
|
|
340
|
+
id: "dictation",
|
|
341
|
+
title: "Dictation",
|
|
342
|
+
purpose: "Speak prompts instead of typing them.",
|
|
343
|
+
steps: [dictationStep, wordsStep]
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function store(machine) {
|
|
347
|
+
return new PersonalWords(personalWordsPath(machine.home), machine);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// setup/area-droplet.ts
|
|
351
|
+
var DROPLET_AREA = dropletArea();
|
|
352
|
+
function dropletArea() {
|
|
353
|
+
const keysStep = {
|
|
354
|
+
id: "replica-keys",
|
|
355
|
+
title: "Give the server its replica bucket's keys",
|
|
356
|
+
why: "A server on a Droplet keeps its records in a Spaces bucket beside it, which is what lets it move between machines or come back after its box is lost.",
|
|
357
|
+
user: "Make a Spaces access key limited to the bucket in the DigitalOcean control panel, then paste its key and its secret here.",
|
|
358
|
+
agent: `Follow "Server on a Droplet" in setup.md. Request each with \`splates creds request ${REPLICA_ACCESS_KEY2} --device\` and \`splates creds request ${REPLICA_SECRET_KEY2} --device\`, with how to make the key, and \`splates creds wait\` for each. On the Droplet, with \`SPLATES_SECRET_STORE=file\` set, they are kept in files only the user may read.`,
|
|
359
|
+
optional: true,
|
|
360
|
+
after: [],
|
|
361
|
+
fields: [
|
|
362
|
+
{
|
|
363
|
+
kind: "cred",
|
|
364
|
+
name: REPLICA_ACCESS_KEY2,
|
|
365
|
+
label: "Spaces access key",
|
|
366
|
+
help: "In DigitalOcean's **API** page, under **Spaces Keys**, **Generate New Key**, limited to the bucket; paste its key id."
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
kind: "cred",
|
|
370
|
+
name: REPLICA_SECRET_KEY2,
|
|
371
|
+
label: "Spaces secret key",
|
|
372
|
+
help: "The secret shown once beside that key."
|
|
373
|
+
}
|
|
374
|
+
],
|
|
375
|
+
check: async ({ device }) => await device.get(REPLICA_ACCESS_KEY2) !== undefined && await device.get(REPLICA_SECRET_KEY2) !== undefined,
|
|
376
|
+
undo: {
|
|
377
|
+
removes: async () => [
|
|
378
|
+
"The Spaces access key and secret kept on this device"
|
|
379
|
+
],
|
|
380
|
+
leaves: async () => [
|
|
381
|
+
"The key still works: delete it under **Spaces Keys** in DigitalOcean's API page, and the bucket and the Droplet from the dashboard, if you no longer want them."
|
|
382
|
+
],
|
|
383
|
+
run: async () => {}
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
return {
|
|
387
|
+
id: "droplet",
|
|
388
|
+
title: "Server on a Droplet",
|
|
389
|
+
purpose: "Run splates server on a DigitalOcean Droplet that keeps working while your computer is off.",
|
|
390
|
+
steps: [keysStep]
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// setup/area-evals.ts
|
|
395
|
+
var DOCS = "https://github.com/stringsync/splates/blob/main/docs/evals.md";
|
|
396
|
+
var EVALS_AREA = evalsArea();
|
|
397
|
+
function evalsArea() {
|
|
398
|
+
const resultsStep = {
|
|
399
|
+
id: "evals-results",
|
|
400
|
+
title: "Show your evals",
|
|
401
|
+
why: "Results from any eval framework (promptfoo, Inspect, a script of your own) can show on the Evals page once they are written in the `splates-evals/1` format.",
|
|
402
|
+
user: `Add \`evals: { results: ".evals" }\` to this project's \`splates.config.ts\` and merge it, as a task, then restart \`splates server\` and press Next. [How to write the results](${DOCS}).`,
|
|
403
|
+
agent: `In a task of its own, add the \`evals\` the user names to \`splates.config.ts\` and merge it; then have the user restart \`splates server\`, and run \`splates setup evals-results\`. The format is in ${DOCS}.`,
|
|
404
|
+
notDone: `\`splates.config.ts\` names no \`evals.results\` yet: add it, merge it, then press Next. [The format](${DOCS}).`,
|
|
405
|
+
optional: true,
|
|
406
|
+
after: [],
|
|
407
|
+
detail: async (machine) => {
|
|
408
|
+
const evals = (await projectOf(machine).config()).evals;
|
|
409
|
+
return evals === null ? null : `Evals are set up: results are read from \`${evals.results}\`, and show on the Evals page.`;
|
|
410
|
+
},
|
|
411
|
+
check: async (machine) => (await projectOf(machine).config()).evals !== null,
|
|
412
|
+
undo: {
|
|
413
|
+
removes: async () => [],
|
|
414
|
+
leaves: async () => [
|
|
415
|
+
"`evals` in this project's `splates.config.ts`: take it out in a task and merge it, then restart `splates server`.",
|
|
416
|
+
"The results already written: delete them if you no longer want them."
|
|
417
|
+
],
|
|
418
|
+
run: async () => {}
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
return {
|
|
422
|
+
id: "evals",
|
|
423
|
+
title: "Evals",
|
|
424
|
+
purpose: "Show the results of your project's evals on the Evals page.",
|
|
425
|
+
steps: [resultsStep]
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
var UNREAD = "No project to check: open Setup from a project, or run `splates setup` in its repository.";
|
|
429
|
+
function projectOf(machine) {
|
|
430
|
+
if (machine.project === undefined) {
|
|
431
|
+
throw new Error(UNREAD);
|
|
432
|
+
}
|
|
433
|
+
return machine.project;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// setup/area-github.ts
|
|
437
|
+
var NEW_APP_PAGE = "https://github.com/settings/apps/new";
|
|
438
|
+
var DEFAULT_REMOTE = "origin";
|
|
439
|
+
var PROBE_BRANCH = "splates-probe/unnamed";
|
|
440
|
+
var PUSH_RULES = ["creation", "update", "deletion"];
|
|
441
|
+
var RULESET_HOW = `In this repository's **Settings → Rules → Rulesets**, add two rulesets that are **Active**, restrict creations, updates and deletions, and let only **Repository admin** bypass them, the role of the account \`splates server\` pushes trunk with. One is a branch ruleset that targets **All branches** but excludes \`${PUSHED_PREFIX2}*\`. The other is a tag ruleset that targets **All tags**, since the App's contents permission would let a token push or move a release tag.`;
|
|
442
|
+
var RULESETS = [
|
|
443
|
+
{
|
|
444
|
+
name: "splates",
|
|
445
|
+
target: "branch",
|
|
446
|
+
conditions: {
|
|
447
|
+
ref_name: {
|
|
448
|
+
include: ["~ALL"],
|
|
449
|
+
exclude: [`refs/heads/${PUSHED_PREFIX2}*`]
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: "splates-tags",
|
|
455
|
+
target: "tag",
|
|
456
|
+
conditions: { ref_name: { include: ["~ALL"], exclude: [] } }
|
|
457
|
+
}
|
|
458
|
+
].map((each) => ({
|
|
459
|
+
...each,
|
|
460
|
+
enforcement: "active",
|
|
461
|
+
rules: PUSH_RULES.map((type) => ({ type })),
|
|
462
|
+
bypass_actors: [
|
|
463
|
+
{ actor_id: 5, actor_type: "RepositoryRole", bypass_mode: "always" }
|
|
464
|
+
]
|
|
465
|
+
}));
|
|
466
|
+
var GITHUB_AREA = githubArea();
|
|
467
|
+
function githubArea() {
|
|
468
|
+
const appStep = {
|
|
469
|
+
id: "github-app",
|
|
470
|
+
title: "Make the splates GitHub App",
|
|
471
|
+
why: "Workers push each task's branch with an hour-long token the App mints for one repository's contents, never with a credential of yours.",
|
|
472
|
+
user: `[Make a GitHub App](${NEW_APP_PAGE}): any name, Webhook off, Repository permissions **Contents: Read and write** and nothing else, only on this account. Then paste its App ID, and the private key it generates, here.`,
|
|
473
|
+
agent: `Request both as device creds, \`splates creds request ${APP_ID2} --device\` and \`splates creds request ${APP_KEY2} --device\`, with how to make the App: ${NEW_APP_PAGE}, Webhook off, Contents read and write alone, then the App ID and a generated private key.`,
|
|
474
|
+
optional: true,
|
|
475
|
+
after: [],
|
|
476
|
+
fields: [
|
|
477
|
+
{
|
|
478
|
+
kind: "cred",
|
|
479
|
+
name: APP_ID2,
|
|
480
|
+
label: "App ID",
|
|
481
|
+
help: `[Make a GitHub App](${NEW_APP_PAGE}) with Webhook off and Repository permissions **Contents: Read and write** alone, only on this account; its App ID is on its General page.`
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
kind: "cred",
|
|
485
|
+
name: APP_KEY2,
|
|
486
|
+
label: "Private key",
|
|
487
|
+
help: "Generate a private key at the foot of its General page, and paste the whole `.pem` file."
|
|
488
|
+
}
|
|
489
|
+
],
|
|
490
|
+
doing: "Asking GitHub for the App…",
|
|
491
|
+
submit: async (machine) => {
|
|
492
|
+
const app = await keptApp(machine);
|
|
493
|
+
if (app === null) {
|
|
494
|
+
throw new Error("Paste the App ID and its private key first.");
|
|
495
|
+
}
|
|
496
|
+
const about = await app.about().catch(() => {
|
|
497
|
+
throw new Error("GitHub does not know that App ID with that key: paste both again, from the same App.");
|
|
498
|
+
});
|
|
499
|
+
const more = Object.keys(about.permissions).filter((each) => each !== "contents" && each !== "metadata");
|
|
500
|
+
if (more.length > 0) {
|
|
501
|
+
throw new Error(`The App may do more than push contents (${more.join(", ")}): take those permissions off on its page, then press Next.`);
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
check: async ({ device }) => await device.get(APP_ID2) !== undefined && await device.get(APP_KEY2) !== undefined,
|
|
505
|
+
undo: {
|
|
506
|
+
removes: async () => [],
|
|
507
|
+
leaves: async (machine) => [
|
|
508
|
+
`The App itself: delete it at the foot of ${await appSettings(machine)}.`
|
|
509
|
+
],
|
|
510
|
+
run: async () => {}
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
const installStep = {
|
|
514
|
+
id: "github-install",
|
|
515
|
+
title: "Install the App on this repository",
|
|
516
|
+
why: "The App mints tokens only for a repository it is installed on.",
|
|
517
|
+
user: "Install the App from its page on GitHub, picking **Only select repositories** and this project's repository alone, then press Next, which links the page if it is not installed yet.",
|
|
518
|
+
agent: "Run `splates setup github-install`, whose problem names the App's install page, and have the user install it there on this repository alone.",
|
|
519
|
+
notDone: "The App is not installed on this repository yet: install it, then press Next.",
|
|
520
|
+
optional: true,
|
|
521
|
+
after: [appStep],
|
|
522
|
+
check: async (machine) => {
|
|
523
|
+
const app = await keptApp(machine);
|
|
524
|
+
if (app === null) {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
const repo = await projectRepo(machine);
|
|
528
|
+
if (await app.installed(repo)) {
|
|
529
|
+
return true;
|
|
530
|
+
}
|
|
531
|
+
const { slug } = await app.about();
|
|
532
|
+
throw new Error(`Not installed on ${repo.owner}/${repo.name}: install it from https://github.com/apps/${slug}/installations/new`);
|
|
533
|
+
},
|
|
534
|
+
undo: {
|
|
535
|
+
removes: async (machine) => {
|
|
536
|
+
const { owner, name } = await projectRepo(machine);
|
|
537
|
+
return [
|
|
538
|
+
`The App's installation on ${owner}/${name}, and with it every repository it was installed on`
|
|
539
|
+
];
|
|
540
|
+
},
|
|
541
|
+
run: async (machine) => {
|
|
542
|
+
const app = await keptApp(machine);
|
|
543
|
+
if (app !== null) {
|
|
544
|
+
await app.uninstall(await projectRepo(machine));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
const rulesetStep = {
|
|
550
|
+
id: "github-ruleset",
|
|
551
|
+
title: "Keep the App to splates branches, and off tags",
|
|
552
|
+
why: `A ruleset is what keeps the App's tokens, which workers push with, to \`${PUSHED_PREFIX2}*\`: without one they could push trunk or a release tag.`,
|
|
553
|
+
user: RULESET_HOW,
|
|
554
|
+
agent: `Once the user agrees, make both with their own GitHub sign-in (\`gh auth status\`): \`gh api --method POST repos/<owner>/<repo>/rulesets --input -\` once with each of ${RULESETS.map((each) => `\`${JSON.stringify(each)}\``).join(" and ")}, the bypass being the Repository admin role. Then run \`splates setup github-ruleset\`.`,
|
|
555
|
+
notDone: "The rulesets do not cover trunk, every other branch and every tag yet: make them, then press Next.",
|
|
556
|
+
optional: true,
|
|
557
|
+
after: [installStep],
|
|
558
|
+
check: async (machine) => {
|
|
559
|
+
const app = await keptApp(machine);
|
|
560
|
+
if (app === null) {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
const repo = await projectRepo(machine);
|
|
564
|
+
const { trunk } = await requireProject(machine).config();
|
|
565
|
+
const token = await app.token(repo);
|
|
566
|
+
const kept = async (branch) => {
|
|
567
|
+
const rules = await app.rules(repo, branch, token);
|
|
568
|
+
return PUSH_RULES.every((rule) => rules.includes(rule));
|
|
569
|
+
};
|
|
570
|
+
if (!await kept(trunk) || !await kept(PROBE_BRANCH)) {
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
if (await kept(`${PUSHED_PREFIX2}probe`)) {
|
|
574
|
+
throw new Error(`The ruleset covers \`${PUSHED_PREFIX2}*\` too: exclude it, or workers cannot push their branches.`);
|
|
575
|
+
}
|
|
576
|
+
return app.tagsRestricted(repo, PUSH_RULES, token);
|
|
577
|
+
},
|
|
578
|
+
undo: {
|
|
579
|
+
removes: async () => [],
|
|
580
|
+
leaves: async (machine) => {
|
|
581
|
+
const repo = await projectRepo(machine);
|
|
582
|
+
const path = `repos/${repo.owner}/${repo.name}/rulesets`;
|
|
583
|
+
const found = await keptRulesets(machine, repo).catch(() => []);
|
|
584
|
+
return found.length > 0 ? found.map(({ id, name }) => `The ruleset \`${name}\`: \`gh api -X DELETE ${path}/${id}\`, or in https://github.com/${repo.owner}/${repo.name}/settings/rules.`) : [
|
|
585
|
+
`The rulesets keeping the App to \`${PUSHED_PREFIX2}*\`: delete them in https://github.com/${repo.owner}/${repo.name}/settings/rules.`
|
|
586
|
+
];
|
|
587
|
+
},
|
|
588
|
+
run: async () => {}
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
const pushStep = {
|
|
592
|
+
id: "github-push",
|
|
593
|
+
title: "Turn pushing on",
|
|
594
|
+
why: "With a remote named, each task's branch is pushed after every commit and checkpoint, and trunk becomes the remote's, which only `splates server` pushes.",
|
|
595
|
+
user: 'Add `remote: "origin"` to this project\'s `splates.config.ts` and merge it, as a task, then press Next.',
|
|
596
|
+
agent: 'In a task of its own, add `remote: "origin"` to `splates.config.ts` and merge it; then run `splates setup github-push`.',
|
|
597
|
+
notDone: "`splates.config.ts` names no `remote` yet: add it, merge it, then press Next.",
|
|
598
|
+
optional: true,
|
|
599
|
+
after: [rulesetStep],
|
|
600
|
+
check: async (machine) => (await requireProject(machine).config()).remote !== null,
|
|
601
|
+
undo: {
|
|
602
|
+
removes: async () => [],
|
|
603
|
+
leaves: async () => [
|
|
604
|
+
"`remote` stays in `splates.config.ts`: land a change that takes it out to stop pushing."
|
|
605
|
+
],
|
|
606
|
+
run: async () => {}
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
return {
|
|
610
|
+
id: "github",
|
|
611
|
+
title: "GitHub pushing",
|
|
612
|
+
purpose: "Push each landed task to GitHub through a GitHub App.",
|
|
613
|
+
steps: [appStep, installStep, rulesetStep, pushStep]
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
async function keptApp({
|
|
617
|
+
device,
|
|
618
|
+
fetch: fetch2
|
|
619
|
+
}) {
|
|
620
|
+
const id = await device.get(APP_ID2);
|
|
621
|
+
const key = await device.get(APP_KEY2);
|
|
622
|
+
return id === undefined || key === undefined ? null : new GitHubApp2(id, key, { fetch: fetch2 });
|
|
623
|
+
}
|
|
624
|
+
async function appSettings(machine) {
|
|
625
|
+
const about = await (await keptApp(machine))?.about().catch(() => null);
|
|
626
|
+
if (about === null || about === undefined) {
|
|
627
|
+
return "https://github.com/settings/apps";
|
|
628
|
+
}
|
|
629
|
+
const owner = about.owner?.type === "Organization" ? `organizations/${about.owner.login}/` : "";
|
|
630
|
+
return `https://github.com/${owner}settings/apps/${about.slug}/advanced`;
|
|
631
|
+
}
|
|
632
|
+
async function keptRulesets(machine, repo) {
|
|
633
|
+
const app = await keptApp(machine);
|
|
634
|
+
if (app === null) {
|
|
635
|
+
return [];
|
|
636
|
+
}
|
|
637
|
+
const names = new Set(RULESETS.map((each) => each.name));
|
|
638
|
+
const listed = await app.rulesets(repo, await app.token(repo));
|
|
639
|
+
return listed.flatMap(({ id, name }) => name !== undefined && names.has(name) ? [{ id, name }] : []);
|
|
640
|
+
}
|
|
641
|
+
function requireProject({ project }) {
|
|
642
|
+
if (project === undefined) {
|
|
643
|
+
throw new Error("No project to check: open Setup from a project, or run `splates setup` in its repository.");
|
|
644
|
+
}
|
|
645
|
+
return project;
|
|
646
|
+
}
|
|
647
|
+
async function projectRepo(machine) {
|
|
648
|
+
const project = requireProject(machine);
|
|
649
|
+
const remote = (await project.config()).remote ?? DEFAULT_REMOTE;
|
|
650
|
+
const url = await project.remoteUrl(remote);
|
|
651
|
+
if (url === null) {
|
|
652
|
+
throw new Error(`This repository has no remote \`${remote}\`.`);
|
|
653
|
+
}
|
|
654
|
+
const repo = githubRepo2(url);
|
|
655
|
+
if (repo === null) {
|
|
656
|
+
throw new Error(`\`${remote}\` is not on github.com, where the App pushes: ${url}`);
|
|
657
|
+
}
|
|
658
|
+
return repo;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// setup/area-native.ts
|
|
662
|
+
async function rosterAgents({ fs, home }) {
|
|
663
|
+
const roster = Roster2.in(new FsStorage2(home, fs));
|
|
664
|
+
return await fs.exists(`${home}/agents.json`) ? roster.agents() : [];
|
|
665
|
+
}
|
|
666
|
+
var PROBE_MS = 1e4;
|
|
667
|
+
var CLIS = {
|
|
668
|
+
claude: {
|
|
669
|
+
name: "Claude",
|
|
670
|
+
install: "curl -fsSL https://claude.ai/install.sh | bash",
|
|
671
|
+
signedIn: { args: ["auth", "status"] },
|
|
672
|
+
signIn: "claude",
|
|
673
|
+
signOut: "run `claude auth logout`",
|
|
674
|
+
uninstall: "rm -f ~/.local/bin/claude && rm -rf ~/.local/share/claude"
|
|
675
|
+
},
|
|
676
|
+
codex: {
|
|
677
|
+
name: "Codex",
|
|
678
|
+
install: "npm install --global @openai/codex",
|
|
679
|
+
signedIn: { args: ["login", "status"] },
|
|
680
|
+
signIn: "codex",
|
|
681
|
+
signOut: "run `codex logout`",
|
|
682
|
+
uninstall: "npm uninstall --global @openai/codex"
|
|
683
|
+
},
|
|
684
|
+
kimi: {
|
|
685
|
+
name: "Kimi",
|
|
686
|
+
command: KIMI_CLI2,
|
|
687
|
+
install: "curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash",
|
|
688
|
+
signedIn: { args: ["provider", "list"], says: "managed:kimi-code" },
|
|
689
|
+
signIn: "kimi login",
|
|
690
|
+
signOut: "run `kimi` and type `/logout` in it",
|
|
691
|
+
uninstall: "rm -f ~/.kimi-code/bin/kimi"
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
var CLAUDE_AREA = agentJourney("claude");
|
|
695
|
+
var CODEX_AREA = agentJourney("codex");
|
|
696
|
+
var KIMI_AREA = agentJourney("kimi");
|
|
697
|
+
function agentJourney(id) {
|
|
698
|
+
const { name, install, signIn: login, signOut, uninstall } = CLIS[id];
|
|
699
|
+
const signIn = {
|
|
700
|
+
id: `${id}-signin`,
|
|
701
|
+
title: `Install and sign in to ${name}`,
|
|
702
|
+
why: `splates starts ${name} through its own CLI, which has to be installed and signed in on this machine.`,
|
|
703
|
+
user: `Press Next and splates checks that \`${id}\` answers and is signed in. If it is not, install it with \`${install}\`, then run \`${login}\` once to sign in.`,
|
|
704
|
+
agent: `Help set up only ${name}: check \`${id} --version\` and its sign-in status, install it with \`${install}\` if needed, and have the user run \`${login}\` once to sign in. Never collect credentials in chat or send a test prompt.`,
|
|
705
|
+
optional: true,
|
|
706
|
+
after: [],
|
|
707
|
+
doing: `Checking that ${id} answers and is signed in…`,
|
|
708
|
+
check: async (machine) => await probe(machine, id) === "ready",
|
|
709
|
+
submit: async (machine) => {
|
|
710
|
+
switch (await probe(machine, id)) {
|
|
711
|
+
case "missing":
|
|
712
|
+
throw new Error(`${name} is not installed here: install it with ${install}, then run ${login} once to sign in.`);
|
|
713
|
+
case "signed-out":
|
|
714
|
+
throw new Error(`${name} is installed but not signed in: run ${login} once to sign in.`);
|
|
715
|
+
case "ready":
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
undo: {
|
|
720
|
+
removes: async () => [],
|
|
721
|
+
leaves: async () => [
|
|
722
|
+
`${name} stays signed in: ${signOut} to sign out.`,
|
|
723
|
+
`${name} stays installed: run \`${uninstall}\` to remove it.`
|
|
724
|
+
],
|
|
725
|
+
run: async () => {}
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
const models = {
|
|
729
|
+
id: `${id}-models`,
|
|
730
|
+
title: `Choose ${name} models`,
|
|
731
|
+
why: `splates uses the models ticked here for ${name} when assigning work. Ticking one does not prove your account can run it.`,
|
|
732
|
+
user: "Tick the models you can use.",
|
|
733
|
+
agent: `Offer only the default ${id} models; Next writes the ${id} entry of ~/.splates/agents.json, keeping other agents, launch arguments and models. Do not run paid prompts or evals.`,
|
|
734
|
+
optional: true,
|
|
735
|
+
after: [signIn],
|
|
736
|
+
get fields() {
|
|
737
|
+
return modelFields(id);
|
|
738
|
+
},
|
|
739
|
+
check: async (machine) => (await rosterAgents(machine)).some((agent) => agent.id === id && agent.models.length > 0),
|
|
740
|
+
submit: async ({ fs, home }, answers) => {
|
|
741
|
+
const chosen = chosenModels(id, answers);
|
|
742
|
+
if (chosen.length === 0) {
|
|
743
|
+
throw new Error("Tick at least one model.");
|
|
744
|
+
}
|
|
745
|
+
await Roster2.in(new FsStorage2(home, fs)).choose(id, chosen);
|
|
746
|
+
},
|
|
747
|
+
undo: {
|
|
748
|
+
removes: async (machine) => {
|
|
749
|
+
const agent = (await rosterAgents(machine)).find((each) => each.id === id);
|
|
750
|
+
const models = (agent?.models ?? []).map((model) => model.name);
|
|
751
|
+
return [
|
|
752
|
+
`${name} on the roster in \`${machine.home}/agents.json\`${models.length === 0 ? "" : `, running ${models.join(", ")}`}`
|
|
753
|
+
];
|
|
754
|
+
},
|
|
755
|
+
run: ({ fs, home }) => Roster2.in(new FsStorage2(home, fs)).remove(id)
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
return {
|
|
759
|
+
id,
|
|
760
|
+
title: name,
|
|
761
|
+
purpose: `Run agents on ${name}, signed in on this machine.`,
|
|
762
|
+
steps: [signIn, models]
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
function modelField(id, model) {
|
|
766
|
+
return `${id}-model-${model}`;
|
|
767
|
+
}
|
|
768
|
+
function modelFields(id) {
|
|
769
|
+
const agent = DEFAULT_AGENTS2.find((each) => each.id === id);
|
|
770
|
+
return (agent?.models ?? []).map((model) => ({
|
|
771
|
+
kind: "yes-no",
|
|
772
|
+
name: modelField(id, model.id),
|
|
773
|
+
label: `${model.name}: ${model.strengths}`
|
|
774
|
+
}));
|
|
775
|
+
}
|
|
776
|
+
function chosenModels(id, answers) {
|
|
777
|
+
const agent = DEFAULT_AGENTS2.find((each) => each.id === id);
|
|
778
|
+
return (agent?.models ?? []).filter((model) => answers[modelField(id, model.id)] === true).map((model) => model.id);
|
|
779
|
+
}
|
|
780
|
+
async function probe({ ps }, id) {
|
|
781
|
+
if (ps === undefined) {
|
|
782
|
+
return "missing";
|
|
783
|
+
}
|
|
784
|
+
const { command = [id], signedIn } = CLIS[id];
|
|
785
|
+
const run = (args) => ps.spawnCapture([...command, ...args], { timeoutMs: PROBE_MS }).catch(() => null);
|
|
786
|
+
if ((await run(["--version"]))?.exitCode !== 0) {
|
|
787
|
+
return "missing";
|
|
788
|
+
}
|
|
789
|
+
const status = await run(signedIn.args);
|
|
790
|
+
return status?.exitCode === 0 && (signedIn.says === undefined || status.stdout.includes(signedIn.says)) ? "ready" : "signed-out";
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// setup/area-opencode.ts
|
|
794
|
+
var OPENCODE_GO_KEY = "OPENCODE_GO_API_KEY";
|
|
795
|
+
var CONSOLE = "https://opencode.ai/auth";
|
|
796
|
+
var UNINSTALL = "npm uninstall --global @opencode/cli";
|
|
797
|
+
var LOGOUT = "opencode auth logout";
|
|
798
|
+
var OPENCODE_AREA = openCodeArea();
|
|
799
|
+
function openCodeArea() {
|
|
800
|
+
const installStep = {
|
|
801
|
+
id: "opencode-install",
|
|
802
|
+
title: "Install OpenCode",
|
|
803
|
+
why: "OpenCode runs your OpenCode Go models beside the other agents.",
|
|
804
|
+
user: "OpenCode is not on this machine yet. Next installs it with npm.",
|
|
805
|
+
agent: "Press Next on the page, or run `npm install --global @opencode/cli@latest`. Do not start a paid conversation or edit the roster.",
|
|
806
|
+
optional: true,
|
|
807
|
+
after: [],
|
|
808
|
+
check: async (machine) => await native(machine).version() !== null,
|
|
809
|
+
submit: async (machine) => {
|
|
810
|
+
await native(machine).install();
|
|
811
|
+
},
|
|
812
|
+
doing: "Installing OpenCode with npm…",
|
|
813
|
+
undo: {
|
|
814
|
+
removes: async () => [],
|
|
815
|
+
leaves: async () => [
|
|
816
|
+
`OpenCode stays installed: run \`${UNINSTALL}\` to remove it.`
|
|
817
|
+
],
|
|
818
|
+
run: async () => {}
|
|
819
|
+
},
|
|
820
|
+
notDone: "npm installed OpenCode, but splates cannot find it on its PATH. Restart `splates server`, then press Next."
|
|
821
|
+
};
|
|
822
|
+
const connectStep = {
|
|
823
|
+
id: "opencode-connect",
|
|
824
|
+
title: "Paste your OpenCode Go API key",
|
|
825
|
+
why: "splates keeps it for this device and hands it to OpenCode, which keeps its own copy.",
|
|
826
|
+
user: "Paste your OpenCode Go API key.",
|
|
827
|
+
agent: "Have the user paste the key into the page; never ask for it in chat or read native credential files.",
|
|
828
|
+
optional: true,
|
|
829
|
+
after: [installStep],
|
|
830
|
+
fields: [
|
|
831
|
+
{
|
|
832
|
+
kind: "cred",
|
|
833
|
+
name: OPENCODE_GO_KEY,
|
|
834
|
+
label: "OpenCode Go API key",
|
|
835
|
+
help: `Copy it from your Go workspace in the [OpenCode Console](${CONSOLE}).`
|
|
836
|
+
}
|
|
837
|
+
],
|
|
838
|
+
check: async (machine) => await machine.device.get(OPENCODE_GO_KEY) !== undefined && await native(machine).connected(),
|
|
839
|
+
submit: async (machine) => {
|
|
840
|
+
const opencode = native(machine);
|
|
841
|
+
const key = await machine.device.get(OPENCODE_GO_KEY);
|
|
842
|
+
if (key !== undefined && !await opencode.connected()) {
|
|
843
|
+
await opencode.login(key);
|
|
844
|
+
}
|
|
845
|
+
await opencode.handshake();
|
|
846
|
+
},
|
|
847
|
+
doing: "Connecting OpenCode to Go…",
|
|
848
|
+
undo: {
|
|
849
|
+
removes: async () => ["The OpenCode Go API key kept on this device"],
|
|
850
|
+
leaves: async () => [
|
|
851
|
+
`OpenCode keeps its own copy of the key: run \`${LOGOUT}\` and pick OpenCode Go to remove it.`,
|
|
852
|
+
`The key still works: delete it in the [OpenCode Console](${CONSOLE}) if you no longer want it.`
|
|
853
|
+
],
|
|
854
|
+
run: async () => {}
|
|
855
|
+
},
|
|
856
|
+
notDone: "OpenCode still lists no Go key. Paste it again, then press Next."
|
|
857
|
+
};
|
|
858
|
+
const modelsStep = {
|
|
859
|
+
id: "opencode-models",
|
|
860
|
+
title: "Choose your models",
|
|
861
|
+
why: `Turn **Use balance** off in the [OpenCode Console](${CONSOLE}), so conversations stay on your Go plan.`,
|
|
862
|
+
user: "Pick a main and an auxiliary model.",
|
|
863
|
+
agent: "Have the user pick on the page; no prompts or credential exports.",
|
|
864
|
+
optional: true,
|
|
865
|
+
after: [connectStep],
|
|
866
|
+
fields: [
|
|
867
|
+
{
|
|
868
|
+
kind: "choice",
|
|
869
|
+
name: "model",
|
|
870
|
+
label: "Main model",
|
|
871
|
+
options: (machine) => models(machine, "model")
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
kind: "choice",
|
|
875
|
+
name: "auxiliary",
|
|
876
|
+
label: "Auxiliary model, for titles",
|
|
877
|
+
options: (machine) => models(machine, "auxiliary")
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
kind: "yes-no",
|
|
881
|
+
name: "balanceOff",
|
|
882
|
+
label: "Use balance is off in my OpenCode Console"
|
|
883
|
+
}
|
|
884
|
+
],
|
|
885
|
+
check: async (machine) => await native(machine).models.recipes.stored() !== null,
|
|
886
|
+
submit: async (machine, answers) => {
|
|
887
|
+
if (answers.balanceOff !== true) {
|
|
888
|
+
throw new Error("Turn Use balance off in your OpenCode Console first, then say so here.");
|
|
889
|
+
}
|
|
890
|
+
await native(machine).choose({
|
|
891
|
+
model: String(answers.model),
|
|
892
|
+
auxiliary: String(answers.auxiliary)
|
|
893
|
+
});
|
|
894
|
+
},
|
|
895
|
+
doing: "Saving your models…",
|
|
896
|
+
undo: {
|
|
897
|
+
removes: async (machine) => {
|
|
898
|
+
const recipe = await native(machine).models.recipes.stored().catch(() => null);
|
|
899
|
+
const models = recipe === null ? "" : `, running ${recipe.model} and ${recipe.auxiliary}`;
|
|
900
|
+
return [
|
|
901
|
+
`OpenCode on the roster in \`${machine.home}/agents.json\`${models}`
|
|
902
|
+
];
|
|
903
|
+
},
|
|
904
|
+
run: (machine) => native(machine).disable()
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
const readyStep = {
|
|
908
|
+
id: "opencode-ready",
|
|
909
|
+
title: "Check OpenCode",
|
|
910
|
+
why: "Makes sure OpenCode runs your models before your first conversation.",
|
|
911
|
+
user: "Next checks your models with OpenCode, without sending a prompt.",
|
|
912
|
+
agent: "Press Finish on the page. Metadata and ACP initialize only; never send a paid test prompt.",
|
|
913
|
+
optional: true,
|
|
914
|
+
after: [modelsStep],
|
|
915
|
+
check: async (machine) => native(machine).ready(),
|
|
916
|
+
submit: async (machine) => {
|
|
917
|
+
await native(machine).verify();
|
|
918
|
+
},
|
|
919
|
+
doing: "Checking OpenCode…"
|
|
920
|
+
};
|
|
921
|
+
return {
|
|
922
|
+
id: "opencode",
|
|
923
|
+
title: "OpenCode",
|
|
924
|
+
purpose: "Run agents on OpenCode, the cheapest way to start.",
|
|
925
|
+
steps: [installStep, connectStep, modelsStep, readyStep]
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
function native(machine) {
|
|
929
|
+
if (machine.opencode === undefined) {
|
|
930
|
+
throw new Error("OpenCode setup runs only under `splates server`.");
|
|
931
|
+
}
|
|
932
|
+
return machine.opencode;
|
|
933
|
+
}
|
|
934
|
+
async function models(machine, which) {
|
|
935
|
+
const opencode = native(machine);
|
|
936
|
+
const listed = await opencode.models.catalog();
|
|
937
|
+
const saved = await opencode.models.recipes.stored().catch(() => null);
|
|
938
|
+
const first = saved?.[which];
|
|
939
|
+
return [
|
|
940
|
+
...listed.filter((id) => id === first),
|
|
941
|
+
...listed.filter((id) => id !== first)
|
|
942
|
+
].map((id) => ({ value: id, label: id.replace(/^opencode-go\//, "") }));
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// setup/area-remote.ts
|
|
946
|
+
import { Credentials as Credentials2 } from "../../core/creds/index.js";
|
|
947
|
+
import { MemoryLogger } from "../../core/log/index.js";
|
|
948
|
+
var REMOTE_ACCESS_AREA = remoteAccessArea();
|
|
949
|
+
function remoteAccessArea() {
|
|
950
|
+
const tokenStep = {
|
|
951
|
+
id: "cloudflare-token",
|
|
952
|
+
title: "Give splates a Cloudflare API token",
|
|
953
|
+
why: "To reach `splates server` from your phone or another computer, splates makes a Cloudflare tunnel with Cloudflare Access in front, through Cloudflare's API.",
|
|
954
|
+
user: `Create a [Cloudflare API token](${TOKENS_PAGE2}) with ${TOKEN_PERMISSIONS2.join(", ")}, for your account and your zone, and paste it here. Skip to keep \`splates server\` on this machine only, or to run your own \`TunnelProvider\` from \`splates.config.ts\`.`,
|
|
955
|
+
agent: `Request it with \`splates creds request ${API_TOKEN2} --device\`, with how to make it, or let \`splates tunnel setup\` request it.`,
|
|
956
|
+
optional: true,
|
|
957
|
+
after: [],
|
|
958
|
+
fields: [
|
|
959
|
+
{
|
|
960
|
+
kind: "cred",
|
|
961
|
+
name: API_TOKEN2,
|
|
962
|
+
label: "Cloudflare API token",
|
|
963
|
+
help: tokenInstructions2("your host")
|
|
964
|
+
}
|
|
965
|
+
],
|
|
966
|
+
check: async ({ device }) => await device.get(API_TOKEN2) !== undefined,
|
|
967
|
+
undo: {
|
|
968
|
+
removes: async () => [],
|
|
969
|
+
leaves: async () => [
|
|
970
|
+
`The API token itself: delete it in [Cloudflare's API tokens](${TOKENS_PAGE2}).`,
|
|
971
|
+
"The account's Zero Trust organization, which `splates tunnel setup` may have made, stays: it costs nothing on its own."
|
|
972
|
+
],
|
|
973
|
+
run: async () => {}
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
const tunnelStep = {
|
|
977
|
+
id: "tunnel",
|
|
978
|
+
title: "Make the tunnel",
|
|
979
|
+
why: "The tunnel carries a host name of yours to `splates server`, and Access lets in only the emails you name.",
|
|
980
|
+
user: "Pick the host name, in a zone of your account, and the emails Access lets in.",
|
|
981
|
+
agent: "Run `splates tunnel setup <host> --email <emails>`, adding `--team <name>` when the account has no Zero Trust organization yet.",
|
|
982
|
+
optional: true,
|
|
983
|
+
after: [tokenStep],
|
|
984
|
+
uses: [API_TOKEN2],
|
|
985
|
+
fields: [
|
|
986
|
+
{
|
|
987
|
+
kind: "text",
|
|
988
|
+
name: "host",
|
|
989
|
+
label: "Host name",
|
|
990
|
+
placeholder: "splates.example.com"
|
|
991
|
+
},
|
|
992
|
+
{
|
|
993
|
+
kind: "text",
|
|
994
|
+
name: "email",
|
|
995
|
+
label: "Emails Access lets in, comma separated",
|
|
996
|
+
placeholder: "me@example.com"
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
kind: "text",
|
|
1000
|
+
name: "team",
|
|
1001
|
+
label: "Zero Trust team name, only if your account has none yet (for <team>.cloudflareaccess.com)",
|
|
1002
|
+
optional: true
|
|
1003
|
+
}
|
|
1004
|
+
],
|
|
1005
|
+
doing: "Making the tunnel, its DNS record and the Access application in Cloudflare…",
|
|
1006
|
+
submit: async (machine, answers) => {
|
|
1007
|
+
const { fs, home, device } = machine;
|
|
1008
|
+
try {
|
|
1009
|
+
await tunnelSetup2({
|
|
1010
|
+
host: String(answers.host),
|
|
1011
|
+
email: String(answers.email),
|
|
1012
|
+
team: String(answers.team ?? ""),
|
|
1013
|
+
name: "splates",
|
|
1014
|
+
creds: {
|
|
1015
|
+
credentials: new Credentials2([device]),
|
|
1016
|
+
request: async () => null,
|
|
1017
|
+
save: async (name, value) => {
|
|
1018
|
+
await device.set(name, value.trim());
|
|
1019
|
+
return "device";
|
|
1020
|
+
}
|
|
1021
|
+
},
|
|
1022
|
+
task: null,
|
|
1023
|
+
saved: SavedTunnel2.in(new FsStorage2(`${home}`, fs), device),
|
|
1024
|
+
log: new MemoryLogger,
|
|
1025
|
+
fetch: machine.fetch
|
|
1026
|
+
});
|
|
1027
|
+
} catch (error) {
|
|
1028
|
+
throw new Error(plain(error));
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
check: async (machine) => await savedTunnel(machine) !== null,
|
|
1032
|
+
undo: {
|
|
1033
|
+
removes: async (machine) => {
|
|
1034
|
+
const host = (await savedTunnel(machine))?.host ?? "the host";
|
|
1035
|
+
return [
|
|
1036
|
+
`The tunnel to ${host}, and the DNS record routing ${host} to it`,
|
|
1037
|
+
`The Access application in front of ${host}, and its policy`,
|
|
1038
|
+
"The workers' Access policy and its service tokens: workers joined through the tunnel lose their access",
|
|
1039
|
+
"Each slot's tunnel, and the Access application in front of every slot"
|
|
1040
|
+
];
|
|
1041
|
+
},
|
|
1042
|
+
refused: async ({ removeTunnel }) => removeTunnel === undefined ? "Open Setup from a project to remove the tunnel: its API token is read through the project's creds." : null,
|
|
1043
|
+
confirm: async (machine) => (await savedTunnel(machine))?.host ?? null,
|
|
1044
|
+
run: async ({ removeTunnel }) => {
|
|
1045
|
+
if (removeTunnel === undefined) {
|
|
1046
|
+
throw new Error("No project to remove the tunnel from.");
|
|
1047
|
+
}
|
|
1048
|
+
await removeTunnel();
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
const accessStep = {
|
|
1053
|
+
id: "access",
|
|
1054
|
+
title: "Check that Access lets only you in",
|
|
1055
|
+
why: "Access is the one thing between the internet and agents that run commands on this machine.",
|
|
1056
|
+
user: "Open the host on your phone and sign in with an email you named; restart `splates server` first if it ran before the tunnel was made, then press Next.",
|
|
1057
|
+
notDone: "Access did not send a stranger to its sign-in yet: restart `splates server` if it ran before the tunnel was made, then press Next.",
|
|
1058
|
+
agent: "Run `splates tunnel status`, then have the user open the host and sign in, and check this step again.",
|
|
1059
|
+
optional: true,
|
|
1060
|
+
after: [tunnelStep],
|
|
1061
|
+
check: async (machine) => {
|
|
1062
|
+
const saved = await savedTunnel(machine);
|
|
1063
|
+
return saved !== null && guarded(saved, machine.fetch ?? fetch);
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
const portsStep = {
|
|
1067
|
+
id: "ports-host",
|
|
1068
|
+
title: "Open a task's ports from anywhere",
|
|
1069
|
+
why: "With a wildcard base host saved, each port a task listens on opens at `https://<task>-<port>.<base>`, behind the same Access, so you can try its server on your phone.",
|
|
1070
|
+
user: "Pick a base host in your zone, such as `ports.example.com`. Routing its wildcard `*.ports.example.com` to `splates server`, its DNS and TLS included, is yours to do; a running server picks the base up only on restart.",
|
|
1071
|
+
agent: "Have the user restart `splates server` with `--ports-host <base>`, which saves the base for this machine, then check this step again.",
|
|
1072
|
+
optional: true,
|
|
1073
|
+
after: [accessStep],
|
|
1074
|
+
fields: [
|
|
1075
|
+
{
|
|
1076
|
+
kind: "text",
|
|
1077
|
+
name: "base",
|
|
1078
|
+
label: "Base host",
|
|
1079
|
+
placeholder: "ports.example.com"
|
|
1080
|
+
}
|
|
1081
|
+
],
|
|
1082
|
+
submit: async ({ fs, home }, answers) => {
|
|
1083
|
+
let base;
|
|
1084
|
+
try {
|
|
1085
|
+
base = portsHostFlag2(String(answers.base));
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
throw new Error(plain(error));
|
|
1088
|
+
}
|
|
1089
|
+
if (typeof base !== "string") {
|
|
1090
|
+
throw new Error("Give a base host, such as ports.example.com.");
|
|
1091
|
+
}
|
|
1092
|
+
await SavedPortsHost2.in(new FsStorage2(`${home}`, fs)).save(base);
|
|
1093
|
+
},
|
|
1094
|
+
check: async ({ fs, home }) => await SavedPortsHost2.in(new FsStorage2(`${home}`, fs)).read() !== null,
|
|
1095
|
+
undo: {
|
|
1096
|
+
removes: async ({ fs, home }) => {
|
|
1097
|
+
const base = await SavedPortsHost2.in(new FsStorage2(`${home}`, fs)).read();
|
|
1098
|
+
return [
|
|
1099
|
+
`The saved base host ${base}, which a running \`splates server\` serves until it restarts`
|
|
1100
|
+
];
|
|
1101
|
+
},
|
|
1102
|
+
leaves: async ({ fs, home }) => {
|
|
1103
|
+
const base = await SavedPortsHost2.in(new FsStorage2(`${home}`, fs)).read();
|
|
1104
|
+
return [
|
|
1105
|
+
`The DNS and TLS routing \`*.${base}\` to \`splates server\`, which you made: remove it where you made it.`
|
|
1106
|
+
];
|
|
1107
|
+
},
|
|
1108
|
+
run: async ({ fs, home }) => {
|
|
1109
|
+
await SavedPortsHost2.in(new FsStorage2(`${home}`, fs)).save(null);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
return {
|
|
1114
|
+
id: "remote-access",
|
|
1115
|
+
title: "Remote access",
|
|
1116
|
+
purpose: "Reach splates server from your phone or another computer.",
|
|
1117
|
+
steps: [tokenStep, tunnelStep, accessStep, portsStep]
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
async function savedTunnel({
|
|
1121
|
+
fs,
|
|
1122
|
+
home,
|
|
1123
|
+
device
|
|
1124
|
+
}) {
|
|
1125
|
+
const saved = SavedTunnel2.in(new FsStorage2(`${home}`, fs), device);
|
|
1126
|
+
const record = await saved.read();
|
|
1127
|
+
return record !== null && await saved.token() !== undefined ? record : null;
|
|
1128
|
+
}
|
|
1129
|
+
var ACCESS_TIMEOUT = 5000;
|
|
1130
|
+
async function guarded({ host, team }, fetch2) {
|
|
1131
|
+
const response = await fetch2(`https://${host}/`, {
|
|
1132
|
+
redirect: "manual",
|
|
1133
|
+
signal: AbortSignal.timeout(ACCESS_TIMEOUT)
|
|
1134
|
+
}).catch((error) => {
|
|
1135
|
+
throw new Error(`https://${host} did not answer: ${error.message}`);
|
|
1136
|
+
});
|
|
1137
|
+
const location = response.headers.get("location") ?? "";
|
|
1138
|
+
if (location.includes(`${team}.cloudflareaccess.com`)) {
|
|
1139
|
+
return true;
|
|
1140
|
+
}
|
|
1141
|
+
if (response.ok) {
|
|
1142
|
+
throw new Error(`https://${host} served the page without a sign-in: Access is not in front of it`);
|
|
1143
|
+
}
|
|
1144
|
+
return false;
|
|
1145
|
+
}
|
|
1146
|
+
function plain(error) {
|
|
1147
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1148
|
+
if (message.includes("no Zero Trust organization yet")) {
|
|
1149
|
+
return "The account has no Zero Trust organization yet: give a team name below, for <team>.cloudflareaccess.com, to make one.";
|
|
1150
|
+
}
|
|
1151
|
+
return message;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// setup/area-replica.ts
|
|
1155
|
+
import { Duration, timeAgo } from "../../core/time/index.js";
|
|
1156
|
+
var REPLICA_AREA = replicaArea();
|
|
1157
|
+
function replicaArea() {
|
|
1158
|
+
const placeStep = {
|
|
1159
|
+
id: "replica-place",
|
|
1160
|
+
title: "Name a replica",
|
|
1161
|
+
why: "A replica is a copy of this project's records a few seconds behind every change, in a bucket or a folder, so they outlive this machine and can move to another.",
|
|
1162
|
+
user: 'Add a `replica` to this project\'s `splates.config.ts` and merge it, as a task, then restart `splates server` and press Next. For a bucket of any S3-compatible store, `replica: { provider: "s3", endpoint: "https://<region>.digitaloceanspaces.com", bucket: "<bucket>" }`, adding `prefix` for projects that share a bucket; for a folder, `replica: { provider: "dir", path: "/Volumes/Backup/splates" }`.',
|
|
1163
|
+
agent: "In a task of its own, add the `replica` the user names to `splates.config.ts` and merge it; then have the user restart `splates server`, and run `splates setup replica-place`.",
|
|
1164
|
+
notDone: "`splates.config.ts` names no `replica` yet: add it, merge it, then press Next.",
|
|
1165
|
+
optional: true,
|
|
1166
|
+
after: [],
|
|
1167
|
+
detail: async (machine) => {
|
|
1168
|
+
const place = (await projectOf2(machine).config()).replica;
|
|
1169
|
+
return place === null ? null : `Named: \`${whereIs(place)}\`.`;
|
|
1170
|
+
},
|
|
1171
|
+
check: async (machine) => (await projectOf2(machine).config()).replica !== null,
|
|
1172
|
+
undo: {
|
|
1173
|
+
removes: async () => [],
|
|
1174
|
+
leaves: async () => [
|
|
1175
|
+
"`replica` in this project's `splates.config.ts`: take it out in a task and merge it, then restart `splates server`, or it keeps copying.",
|
|
1176
|
+
"The copy already made, in the bucket or folder: delete it there if you no longer want it."
|
|
1177
|
+
],
|
|
1178
|
+
run: async () => {}
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
const credsStep = {
|
|
1182
|
+
id: "replica-creds",
|
|
1183
|
+
title: "Give splates the bucket's key",
|
|
1184
|
+
why: "splates signs each request to the bucket with a key and secret of yours, kept in the project's creds and never shown again.",
|
|
1185
|
+
user: `In the store's control panel, make an access key limited to the bucket if it can be, and fill \`${REPLICA_ACCESS_KEY2}\` with its key id and \`${REPLICA_SECRET_KEY2}\` with its secret on the [Creds page](#creds). The replica starts as soon as both are saved; then press Next.`,
|
|
1186
|
+
agent: `\`splates server\` asks for \`${REPLICA_ACCESS_KEY2}\` and \`${REPLICA_SECRET_KEY2}\` on the Creds page once it starts the replica: have the user fill both there, then run \`splates setup replica-creds\`.`,
|
|
1187
|
+
notDone: `\`${REPLICA_ACCESS_KEY2}\` and \`${REPLICA_SECRET_KEY2}\` are not both saved yet: fill them on the Creds page, then press Next.`,
|
|
1188
|
+
optional: true,
|
|
1189
|
+
after: [placeStep],
|
|
1190
|
+
shown: async (machine) => (await projectOf2(machine).config()).replica?.provider === "s3",
|
|
1191
|
+
check: async (machine) => {
|
|
1192
|
+
const { kept } = projectOf2(machine);
|
|
1193
|
+
if (kept === undefined) {
|
|
1194
|
+
throw new Error(UNREAD2);
|
|
1195
|
+
}
|
|
1196
|
+
return await kept(REPLICA_ACCESS_KEY2) && await kept(REPLICA_SECRET_KEY2);
|
|
1197
|
+
},
|
|
1198
|
+
undo: {
|
|
1199
|
+
removes: async () => [],
|
|
1200
|
+
leaves: async () => [
|
|
1201
|
+
`\`${REPLICA_ACCESS_KEY2}\` and \`${REPLICA_SECRET_KEY2}\` in the project's creds: forget them on the Creds page, and delete the key in the store's control panel.`
|
|
1202
|
+
],
|
|
1203
|
+
run: async () => {}
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
const statusStep = {
|
|
1207
|
+
id: "replica",
|
|
1208
|
+
title: "Keep the replica caught up",
|
|
1209
|
+
why: "A replica is only as good as the last time it held every change.",
|
|
1210
|
+
user: "Nothing to do while it keeps up: this says where it stands. Restart `splates server` if it ran before the replica was named.",
|
|
1211
|
+
agent: "Run `splates replica status`; when it is failing, put right what it says, then run `splates setup replica`.",
|
|
1212
|
+
notDone: "The replica has not caught up yet: put right what it says, or wait for it, then press Next.",
|
|
1213
|
+
optional: true,
|
|
1214
|
+
after: [placeStep],
|
|
1215
|
+
detail: async (machine) => {
|
|
1216
|
+
const project = projectOf2(machine);
|
|
1217
|
+
const place = (await project.config()).replica;
|
|
1218
|
+
if (place === null) {
|
|
1219
|
+
return null;
|
|
1220
|
+
}
|
|
1221
|
+
return standing(whereIs(place), await project.replica?.() ?? null, Date.now());
|
|
1222
|
+
},
|
|
1223
|
+
warning: async (machine) => {
|
|
1224
|
+
const error = (await projectOf2(machine).replica?.())?.error ?? null;
|
|
1225
|
+
return error === null ? null : failing(error);
|
|
1226
|
+
},
|
|
1227
|
+
check: async (machine) => {
|
|
1228
|
+
const { replica } = projectOf2(machine);
|
|
1229
|
+
if (replica === undefined) {
|
|
1230
|
+
throw new Error(UNREAD2);
|
|
1231
|
+
}
|
|
1232
|
+
const status = await replica();
|
|
1233
|
+
return status?.caughtUpAt != null && status.error === null;
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
return {
|
|
1237
|
+
id: "replica",
|
|
1238
|
+
title: "Replica",
|
|
1239
|
+
purpose: "Keep a copy of your tasks and conversations in a bucket you own.",
|
|
1240
|
+
steps: [placeStep, credsStep, statusStep]
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
var UNREAD2 = "No project to check: open Setup from a project, or run `splates setup` in its repository.";
|
|
1244
|
+
function projectOf2(machine) {
|
|
1245
|
+
if (machine.project === undefined) {
|
|
1246
|
+
throw new Error(UNREAD2);
|
|
1247
|
+
}
|
|
1248
|
+
return machine.project;
|
|
1249
|
+
}
|
|
1250
|
+
function whereIs(place) {
|
|
1251
|
+
if (place.provider === "dir") {
|
|
1252
|
+
return place.path;
|
|
1253
|
+
}
|
|
1254
|
+
const prefix = place.prefix?.replace(/^\/+|\/+$/g, "") ?? "";
|
|
1255
|
+
return `s3://${place.bucket}${prefix === "" ? "" : `/${prefix}`}`;
|
|
1256
|
+
}
|
|
1257
|
+
function standing(where, status, now) {
|
|
1258
|
+
if (status === null) {
|
|
1259
|
+
return `\`${where}\` has not started: \`splates server\` starts it as it serves the project.`;
|
|
1260
|
+
}
|
|
1261
|
+
const ago = (at) => timeAgo(Duration.ms(now - at));
|
|
1262
|
+
const { caughtUpAt, pending, behindSince } = status;
|
|
1263
|
+
const caught = caughtUpAt === null ? "never caught up yet" : `caught up ${ago(caughtUpAt)}`;
|
|
1264
|
+
const behind = behindSince === null ? "nothing waits" : `${pending} change${pending === 1 ? " waits" : "s wait"}, the oldest from ${ago(behindSince)}`;
|
|
1265
|
+
return `\`${status.replica}\`: ${caught}; ${behind}.`;
|
|
1266
|
+
}
|
|
1267
|
+
function failing(error) {
|
|
1268
|
+
if (error.startsWith(`no ${REPLICA_ACCESS_KEY2}`)) {
|
|
1269
|
+
return `It has no key for the bucket yet: fill \`${REPLICA_ACCESS_KEY2}\` and \`${REPLICA_SECRET_KEY2}\` on the [Creds page](#creds), and it starts at once.`;
|
|
1270
|
+
}
|
|
1271
|
+
if (error.includes("holds the records of another server")) {
|
|
1272
|
+
return `It refuses to write: ${error}.`;
|
|
1273
|
+
}
|
|
1274
|
+
return `The last batch failed: ${error}. It is tried again on its own, waiting up to five minutes.`;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
// setup/area-workers.ts
|
|
1278
|
+
var WORKERS_AREA = workersArea();
|
|
1279
|
+
function workersArea() {
|
|
1280
|
+
const localStep = {
|
|
1281
|
+
id: "local-worker",
|
|
1282
|
+
title: "Make this Mac a worker",
|
|
1283
|
+
why: "Agents run on this Mac's own worker, as many at once as are started.",
|
|
1284
|
+
user: "Press Next: this Mac takes agents unless its worker was removed.",
|
|
1285
|
+
agent: "Run `splates worker drain local --undo`, which turns this Mac's own worker back on if it was removed. Check `splates worker list`.",
|
|
1286
|
+
optional: true,
|
|
1287
|
+
after: [],
|
|
1288
|
+
check: async (machine) => {
|
|
1289
|
+
const local = (await pool(machine)).find((worker) => worker.id === LOCAL_WORKER2);
|
|
1290
|
+
return local !== undefined && !local.draining && !local.removing;
|
|
1291
|
+
},
|
|
1292
|
+
notDone: "This Mac is not taking agents yet: run `splates worker drain local --undo`, then press Next.",
|
|
1293
|
+
undo: {
|
|
1294
|
+
removes: async () => [
|
|
1295
|
+
`This Mac's worker, \`${LOCAL_WORKER2}\`, its agents running to their end first`
|
|
1296
|
+
],
|
|
1297
|
+
refused: noRemoving,
|
|
1298
|
+
run: (machine) => removeWorkers(machine, (each) => each.id === LOCAL_WORKER2)
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
return {
|
|
1302
|
+
id: "workers",
|
|
1303
|
+
title: "Workers",
|
|
1304
|
+
purpose: "Choose which machines run agents.",
|
|
1305
|
+
steps: [localStep]
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
async function pool(machine) {
|
|
1309
|
+
if (machine.workers === undefined) {
|
|
1310
|
+
throw new Error("no `splates server` to ask which workers it has: start one, or give --dev");
|
|
1311
|
+
}
|
|
1312
|
+
return machine.workers();
|
|
1313
|
+
}
|
|
1314
|
+
async function noRemoving(machine) {
|
|
1315
|
+
return machine.removeWorker === undefined ? "No `splates server` to remove workers from: start one, or give --dev." : null;
|
|
1316
|
+
}
|
|
1317
|
+
async function removeWorkers(machine, which) {
|
|
1318
|
+
if (machine.removeWorker === undefined) {
|
|
1319
|
+
throw new Error("no `splates server` to remove workers from");
|
|
1320
|
+
}
|
|
1321
|
+
for (const worker of await pool(machine)) {
|
|
1322
|
+
if (which(worker) && !worker.removing) {
|
|
1323
|
+
await machine.removeWorker(worker.id);
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// setup/areas.ts
|
|
1329
|
+
var SETUP_AREAS2 = [
|
|
1330
|
+
OPENCODE_AREA,
|
|
1331
|
+
REMOTE_ACCESS_AREA,
|
|
1332
|
+
WORKERS_AREA,
|
|
1333
|
+
REPLICA_AREA,
|
|
1334
|
+
DICTATION_AREA,
|
|
1335
|
+
DROPLET_AREA,
|
|
1336
|
+
EVALS_AREA,
|
|
1337
|
+
AUTO_PICK_AREA,
|
|
1338
|
+
GITHUB_AREA,
|
|
1339
|
+
CLAUDE_AREA,
|
|
1340
|
+
CODEX_AREA,
|
|
1341
|
+
KIMI_AREA
|
|
1342
|
+
];
|
|
1343
|
+
// setup/opencode.ts
|
|
1344
|
+
import { stripVTControlCharacters } from "node:util";
|
|
1345
|
+
import * as acp from "@agentclientprotocol/sdk";
|
|
1346
|
+
|
|
1347
|
+
// setup/opencode-model-error.ts
|
|
1348
|
+
class OpenCodeModelError extends Error {
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// setup/opencode-models.ts
|
|
1352
|
+
import { z as z2 } from "zod";
|
|
1353
|
+
|
|
1354
|
+
// setup/opencode-recipe.ts
|
|
1355
|
+
import { z } from "zod";
|
|
1356
|
+
class OpenCodeRecipes {
|
|
1357
|
+
deps;
|
|
1358
|
+
roster;
|
|
1359
|
+
constructor(deps) {
|
|
1360
|
+
this.deps = deps;
|
|
1361
|
+
this.roster = deps.roster ?? Roster2.in(new FsStorage2(deps.home, deps.fs));
|
|
1362
|
+
}
|
|
1363
|
+
async stored() {
|
|
1364
|
+
await this.checkLink();
|
|
1365
|
+
return this.from(await this.roster.read());
|
|
1366
|
+
}
|
|
1367
|
+
from(file) {
|
|
1368
|
+
if (file === null) {
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
const raw = JSON.stringify(file);
|
|
1372
|
+
const agents = file.agents;
|
|
1373
|
+
const agent = agents.find((entry) => entry.id === "opencode");
|
|
1374
|
+
if (!agent) {
|
|
1375
|
+
return null;
|
|
1376
|
+
}
|
|
1377
|
+
if (!managedArgv(agent.argv) || agent.argv.length !== 5) {
|
|
1378
|
+
throw new OpenCodeModelError("OpenCode has no supported setup recipe. Revisit model selection to repair it; custom commands are left untouched.");
|
|
1379
|
+
}
|
|
1380
|
+
const content = agent.argv[2]?.slice(contentPrefix.length) ?? "";
|
|
1381
|
+
const config = recipeConfig.parse(JSON.parse(content));
|
|
1382
|
+
const selection = {
|
|
1383
|
+
model: config.model,
|
|
1384
|
+
auxiliary: config.agents.title.model
|
|
1385
|
+
};
|
|
1386
|
+
if (Object.entries(config.agents).some(([name, entry]) => entry.model !== (name === "build" || name === "plan" ? selection.model : selection.auxiliary)) || !Object.values(selection).every((id) => agent.models.some((model) => model.id === id))) {
|
|
1387
|
+
throw new OpenCodeModelError("The stored model recipe changed. Revisit model selection and review it again.");
|
|
1388
|
+
}
|
|
1389
|
+
return {
|
|
1390
|
+
...selection,
|
|
1391
|
+
config,
|
|
1392
|
+
env: {
|
|
1393
|
+
OPENCODE_CONFIG_PROJECT_DISABLE: "1",
|
|
1394
|
+
OPENCODE_CONFIG_CONTENT: content
|
|
1395
|
+
},
|
|
1396
|
+
raw
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
async unchanged(recipe, signal) {
|
|
1400
|
+
signal.throwIfAborted();
|
|
1401
|
+
if (await this.rawRoster() !== recipe.raw) {
|
|
1402
|
+
throw new OpenCodeModelError("The roster changed during the check. Check configuration again.");
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
async disable(signal) {
|
|
1406
|
+
const recipe = await this.stored();
|
|
1407
|
+
if (!recipe) {
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
await this.roster.update((file) => {
|
|
1411
|
+
signal.throwIfAborted();
|
|
1412
|
+
if (file === null || JSON.stringify(file) !== recipe.raw) {
|
|
1413
|
+
throw new OpenCodeModelError("The roster changed during the check. Check configuration again.");
|
|
1414
|
+
}
|
|
1415
|
+
file.agents = file.agents.filter((entry) => entry.id !== "opencode");
|
|
1416
|
+
return file;
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
async rawRoster() {
|
|
1420
|
+
await this.checkLink();
|
|
1421
|
+
const file = await this.roster.read();
|
|
1422
|
+
return file === null ? null : JSON.stringify(file);
|
|
1423
|
+
}
|
|
1424
|
+
async checkLink() {
|
|
1425
|
+
if (!this.deps.roster && await this.deps.fs.isSymlink(`${this.deps.home}/agents.json`)) {
|
|
1426
|
+
throw new OpenCodeModelError("The roster is a symbolic link. Manage its target explicitly before using setup.");
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
function managedArgv(value) {
|
|
1431
|
+
if (!Array.isArray(value)) {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
return JSON.stringify(value) === JSON.stringify(["opencode", "acp"]) || value.length === 5 && value[0] === "env" && value[1] === projectOff && typeof value[2] === "string" && value[2].startsWith(contentPrefix) && value[3] === "opencode" && value[4] === "acp";
|
|
1435
|
+
}
|
|
1436
|
+
var projectOff = "OPENCODE_CONFIG_PROJECT_DISABLE=1";
|
|
1437
|
+
var contentPrefix = "OPENCODE_CONFIG_CONTENT=";
|
|
1438
|
+
var id = z.string().max(240).regex(/^opencode-go\/[A-Za-z0-9][A-Za-z0-9._:/-]*$/);
|
|
1439
|
+
var recipeConfig = z.object({
|
|
1440
|
+
model: id,
|
|
1441
|
+
default_agent: z.literal("build"),
|
|
1442
|
+
warming: z.literal(false),
|
|
1443
|
+
policies: z.tuple([
|
|
1444
|
+
z.object({
|
|
1445
|
+
action: z.literal("provider.use"),
|
|
1446
|
+
resource: z.literal("*"),
|
|
1447
|
+
effect: z.literal("deny")
|
|
1448
|
+
}).strict(),
|
|
1449
|
+
z.object({
|
|
1450
|
+
action: z.literal("provider.use"),
|
|
1451
|
+
resource: z.literal("opencode-go"),
|
|
1452
|
+
effect: z.literal("allow")
|
|
1453
|
+
}).strict()
|
|
1454
|
+
]),
|
|
1455
|
+
agents: z.record(z.string(), z.object({ model: id }).strict()).and(z.object({
|
|
1456
|
+
build: z.object({ model: id }),
|
|
1457
|
+
title: z.object({ model: id })
|
|
1458
|
+
}))
|
|
1459
|
+
}).strict();
|
|
1460
|
+
|
|
1461
|
+
// setup/opencode-models.ts
|
|
1462
|
+
class OpenCodeModels {
|
|
1463
|
+
deps;
|
|
1464
|
+
metadata;
|
|
1465
|
+
#catalog = null;
|
|
1466
|
+
recipes;
|
|
1467
|
+
constructor(deps, metadata) {
|
|
1468
|
+
this.deps = deps;
|
|
1469
|
+
this.metadata = metadata;
|
|
1470
|
+
this.recipes = new OpenCodeRecipes(deps);
|
|
1471
|
+
}
|
|
1472
|
+
catalog() {
|
|
1473
|
+
if (this.#catalog === null || Date.now() - this.#catalog.at > CATALOG_TTL) {
|
|
1474
|
+
const models = this.discover(AbortSignal.timeout(15000)).then((models) => {
|
|
1475
|
+
if (!models.length) {
|
|
1476
|
+
throw new OpenCodeModelError("OpenCode lists no Go models.");
|
|
1477
|
+
}
|
|
1478
|
+
return models;
|
|
1479
|
+
});
|
|
1480
|
+
models.catch(() => {
|
|
1481
|
+
this.#catalog = null;
|
|
1482
|
+
});
|
|
1483
|
+
this.#catalog = { models, at: Date.now() };
|
|
1484
|
+
}
|
|
1485
|
+
return this.#catalog.models;
|
|
1486
|
+
}
|
|
1487
|
+
invalidate() {
|
|
1488
|
+
this.#catalog = null;
|
|
1489
|
+
}
|
|
1490
|
+
async save(selection, signal) {
|
|
1491
|
+
if (this.deps.ps.platform === "win32") {
|
|
1492
|
+
throw new OpenCodeModelError("This experiment launch recipe requires macOS or Linux.");
|
|
1493
|
+
}
|
|
1494
|
+
openCodeSelection.parse(selection);
|
|
1495
|
+
this.invalidate();
|
|
1496
|
+
const models = await this.catalog();
|
|
1497
|
+
if (!models.includes(selection.model) || !models.includes(selection.auxiliary)) {
|
|
1498
|
+
throw new OpenCodeModelError("A chosen model is no longer listed. Pick again.");
|
|
1499
|
+
}
|
|
1500
|
+
const config = recipeOf(selection);
|
|
1501
|
+
const env = {
|
|
1502
|
+
OPENCODE_CONFIG_PROJECT_DISABLE: "1",
|
|
1503
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify(config)
|
|
1504
|
+
};
|
|
1505
|
+
await this.verify(selection, config, signal, env);
|
|
1506
|
+
await this.recipes.rawRoster();
|
|
1507
|
+
await this.recipes.roster.update((current) => {
|
|
1508
|
+
const after = this.roster(current, selection, env);
|
|
1509
|
+
signal.throwIfAborted();
|
|
1510
|
+
return after;
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
async verifyStored(recipe, cwd, signal) {
|
|
1514
|
+
const models = await this.discover(signal, recipe.env, cwd);
|
|
1515
|
+
if (!models.includes(recipe.model) || !models.includes(recipe.auxiliary)) {
|
|
1516
|
+
throw new OpenCodeModelError("A saved Go model is no longer listed. Go back to the models and pick again.");
|
|
1517
|
+
}
|
|
1518
|
+
await this.verify(recipe, recipe.config, signal, recipe.env, cwd);
|
|
1519
|
+
await this.recipes.unchanged(recipe, signal);
|
|
1520
|
+
}
|
|
1521
|
+
async discover(signal, env, cwd) {
|
|
1522
|
+
const text = await this.metadata.run(["models", "--standalone"], signal, env, cwd);
|
|
1523
|
+
const lines = text.trim() ? text.trim().split(/\r?\n/) : [];
|
|
1524
|
+
if (lines.length > 1e4 || lines.some((line) => !/^[A-Za-z0-9._-]+\/[A-Za-z0-9][A-Za-z0-9._:/-]*$/.test(line))) {
|
|
1525
|
+
throw new OpenCodeModelError("unknown catalog");
|
|
1526
|
+
}
|
|
1527
|
+
if (env && lines.some((line) => !id.safeParse(line).success)) {
|
|
1528
|
+
throw new OpenCodeModelError("OpenCode did not enforce the Go-only provider policy. Resolve its managed provider configuration, then press Try again.");
|
|
1529
|
+
}
|
|
1530
|
+
return [...new Set(lines.filter((line) => id.safeParse(line).success))];
|
|
1531
|
+
}
|
|
1532
|
+
async verify(selection, config, signal, env, cwd = `${this.deps.home}/setup-opencode`) {
|
|
1533
|
+
const sources = entries.parse(JSON.parse(await this.metadata.run(["api", "config.get", "--standalone", "--param", `directory=${cwd}`], signal, env, cwd)));
|
|
1534
|
+
let found = false;
|
|
1535
|
+
for (const source of sources) {
|
|
1536
|
+
if (source.type !== "document") {
|
|
1537
|
+
continue;
|
|
1538
|
+
}
|
|
1539
|
+
const info = source.info;
|
|
1540
|
+
if (JSON.stringify(info.policies) === JSON.stringify(config.policies) && sameModel(info.model, selection.model) && info.warming === false && info.default_agent === "build" && sameAgents(info.agents, config.agents) && !(typeof info.providers === "object" && info.providers !== null && ("opencode-go" in info.providers))) {
|
|
1541
|
+
found = true;
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
const policies = info.policies;
|
|
1545
|
+
const providers = info.providers;
|
|
1546
|
+
if (Array.isArray(policies) && policies.some((policy) => typeof policy === "object" && policy !== null && ("action" in policy) && policy.action === "provider.use") || typeof providers === "object" && providers !== null && "opencode-go" in providers || found && (("model" in info) || ("agents" in info) || ("warming" in info) || ("default_agent" in info))) {
|
|
1547
|
+
throw new OpenCodeModelError("Your own OpenCode configuration sets providers or models that override this setup. Remove them, then press Try again.");
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
if (!found) {
|
|
1551
|
+
throw new OpenCodeModelError("OpenCode did not confirm the configuration. Update OpenCode, then press Try again.");
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
roster(current, selection, env) {
|
|
1555
|
+
const value = current ?? {
|
|
1556
|
+
format: 1,
|
|
1557
|
+
agents: structuredClone(DEFAULT_AGENTS2)
|
|
1558
|
+
};
|
|
1559
|
+
const agents = value.agents;
|
|
1560
|
+
let agent = agents.find((entry) => entry.id === "opencode");
|
|
1561
|
+
if (agent && !managedArgv(agent.argv)) {
|
|
1562
|
+
throw new OpenCodeModelError("Your roster's OpenCode entry has a launch command of its own, which Setup leaves alone. Remove it from agents.json, then press Try again.");
|
|
1563
|
+
}
|
|
1564
|
+
if (!agent) {
|
|
1565
|
+
agent = { id: "opencode", name: "OpenCode Go", argv: [], models: [] };
|
|
1566
|
+
agents.push(agent);
|
|
1567
|
+
}
|
|
1568
|
+
agent.argv = [
|
|
1569
|
+
"env",
|
|
1570
|
+
projectOff,
|
|
1571
|
+
`${contentPrefix}${env.OPENCODE_CONFIG_CONTENT}`,
|
|
1572
|
+
"opencode",
|
|
1573
|
+
"acp"
|
|
1574
|
+
];
|
|
1575
|
+
const models = agent.models;
|
|
1576
|
+
for (const model of new Set([selection.model, selection.auxiliary])) {
|
|
1577
|
+
if (!models.some((entry) => entry.id === model)) {
|
|
1578
|
+
models.push({
|
|
1579
|
+
id: model,
|
|
1580
|
+
name: model,
|
|
1581
|
+
strengths: "Explicit OpenCode Go selection",
|
|
1582
|
+
cost: "Go subscription; access and billing confirmed in Console"
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return value;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
var CATALOG_TTL = 60000;
|
|
1590
|
+
var RECIPE_AGENTS = {
|
|
1591
|
+
build: "model",
|
|
1592
|
+
plan: "model",
|
|
1593
|
+
title: "auxiliary"
|
|
1594
|
+
};
|
|
1595
|
+
function recipeOf(selection) {
|
|
1596
|
+
return {
|
|
1597
|
+
model: selection.model,
|
|
1598
|
+
default_agent: "build",
|
|
1599
|
+
warming: false,
|
|
1600
|
+
policies: [
|
|
1601
|
+
{ action: "provider.use", resource: "*", effect: "deny" },
|
|
1602
|
+
{ action: "provider.use", resource: "opencode-go", effect: "allow" }
|
|
1603
|
+
],
|
|
1604
|
+
agents: Object.fromEntries(Object.entries(RECIPE_AGENTS).map(([name, which]) => [
|
|
1605
|
+
name,
|
|
1606
|
+
{ model: selection[which] }
|
|
1607
|
+
]))
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
function sameAgents(value, expected) {
|
|
1611
|
+
if (typeof value !== "object" || value === null) {
|
|
1612
|
+
return false;
|
|
1613
|
+
}
|
|
1614
|
+
const echoed = value;
|
|
1615
|
+
return Object.keys(echoed).length === Object.keys(expected).length && Object.entries(expected).every(([name, { model }]) => {
|
|
1616
|
+
const agent = echoed[name];
|
|
1617
|
+
return typeof agent === "object" && agent !== null && "model" in agent && sameModel(agent.model, model);
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
function sameModel(value, expected) {
|
|
1621
|
+
return value === expected || typeof value === "object" && value !== null && "providerID" in value && "model" in value && `${value.providerID}/${value.model}` === expected;
|
|
1622
|
+
}
|
|
1623
|
+
var openCodeSelection = z2.object({ model: id, auxiliary: id });
|
|
1624
|
+
var entries = z2.array(z2.union([
|
|
1625
|
+
z2.object({ type: z2.literal("directory"), path: z2.string() }),
|
|
1626
|
+
z2.object({
|
|
1627
|
+
type: z2.literal("document"),
|
|
1628
|
+
info: z2.record(z2.string(), z2.unknown())
|
|
1629
|
+
})
|
|
1630
|
+
]));
|
|
1631
|
+
|
|
1632
|
+
// setup/opencode.ts
|
|
1633
|
+
var OPENCODE_INSTALL = [
|
|
1634
|
+
"npm",
|
|
1635
|
+
"install",
|
|
1636
|
+
"--global",
|
|
1637
|
+
"@opencode/cli@latest"
|
|
1638
|
+
];
|
|
1639
|
+
var OPENCODE_LOGIN = [
|
|
1640
|
+
"opencode",
|
|
1641
|
+
"auth",
|
|
1642
|
+
"login",
|
|
1643
|
+
"opencode-go",
|
|
1644
|
+
"--method",
|
|
1645
|
+
"key",
|
|
1646
|
+
"--standalone"
|
|
1647
|
+
];
|
|
1648
|
+
|
|
1649
|
+
class OpenCodeSetup2 {
|
|
1650
|
+
deps;
|
|
1651
|
+
models;
|
|
1652
|
+
#verified = null;
|
|
1653
|
+
constructor(deps) {
|
|
1654
|
+
this.deps = deps;
|
|
1655
|
+
this.models = new OpenCodeModels({ ...deps, roster: deps.agents }, {
|
|
1656
|
+
run: (args, signal, env, cwd) => this.command(args, signal, env, cwd)
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
get cwd() {
|
|
1660
|
+
return `${this.deps.home}/setup-opencode`;
|
|
1661
|
+
}
|
|
1662
|
+
async version() {
|
|
1663
|
+
const output = await this.command(["--version"], AbortSignal.timeout(15000)).catch(() => null);
|
|
1664
|
+
const version = output?.trim().replace(/^opencode v/, "") ?? "";
|
|
1665
|
+
return /^\d+\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(version) ? version : null;
|
|
1666
|
+
}
|
|
1667
|
+
async install() {
|
|
1668
|
+
const result = await this.deps.ps.spawnCapture(OPENCODE_INSTALL, {
|
|
1669
|
+
cwd: await this.prepare(),
|
|
1670
|
+
timeoutMs: 10 * 60000,
|
|
1671
|
+
stdin: ""
|
|
1672
|
+
}).catch(() => null);
|
|
1673
|
+
if (result === null) {
|
|
1674
|
+
throw new Error("Could not run npm. Install Node.js, then press Try again.");
|
|
1675
|
+
}
|
|
1676
|
+
if (result.exitCode !== 0) {
|
|
1677
|
+
throw new Error(`npm could not install OpenCode. Run \`${OPENCODE_INSTALL.join(" ")}\` in a terminal to see why.`);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
async connected() {
|
|
1681
|
+
const output = await this.command(["auth", "list", "--format", "json", "--standalone"], AbortSignal.timeout(15000)).catch(() => null);
|
|
1682
|
+
try {
|
|
1683
|
+
return output !== null && storedGo(JSON.parse(output));
|
|
1684
|
+
} catch {
|
|
1685
|
+
return false;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
async login(key) {
|
|
1689
|
+
const child = this.deps.ps.startOnTerminal([...OPENCODE_LOGIN], {
|
|
1690
|
+
cwd: await this.prepare(),
|
|
1691
|
+
cols: 120,
|
|
1692
|
+
rows: 30,
|
|
1693
|
+
env: { TERM: "xterm-256color" }
|
|
1694
|
+
});
|
|
1695
|
+
const decoder = new TextDecoder;
|
|
1696
|
+
let screen = "";
|
|
1697
|
+
let typed = false;
|
|
1698
|
+
const timer = setTimeout(() => child.kill("SIGHUP"), 60000);
|
|
1699
|
+
try {
|
|
1700
|
+
(async () => {
|
|
1701
|
+
for await (const bytes of child.output) {
|
|
1702
|
+
screen += decoder.decode(bytes, { stream: true });
|
|
1703
|
+
if (!typed && /API key/i.test(stripVTControlCharacters(screen))) {
|
|
1704
|
+
typed = true;
|
|
1705
|
+
child.write(new TextEncoder().encode(`${key}\r`));
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
})().catch(() => {});
|
|
1709
|
+
const code = await child.exited;
|
|
1710
|
+
if (code !== 0 || !typed) {
|
|
1711
|
+
throw new Error("OpenCode did not take the key. Check it, then press Try again.");
|
|
1712
|
+
}
|
|
1713
|
+
} finally {
|
|
1714
|
+
clearTimeout(timer);
|
|
1715
|
+
child.close();
|
|
1716
|
+
}
|
|
1717
|
+
this.models.invalidate();
|
|
1718
|
+
}
|
|
1719
|
+
async handshake(cwd, env) {
|
|
1720
|
+
const signal = AbortSignal.timeout(15000);
|
|
1721
|
+
const child = this.deps.ps.start(["opencode", "acp"], {
|
|
1722
|
+
cwd: cwd ?? await this.prepare(),
|
|
1723
|
+
env,
|
|
1724
|
+
signal,
|
|
1725
|
+
timeoutMs: 15000
|
|
1726
|
+
});
|
|
1727
|
+
let aborted;
|
|
1728
|
+
(async () => {
|
|
1729
|
+
for await (const _bytes of child.stderr) {}
|
|
1730
|
+
})().catch(() => {});
|
|
1731
|
+
try {
|
|
1732
|
+
const connection = new acp.ClientSideConnection(() => ({
|
|
1733
|
+
sessionUpdate: async () => {},
|
|
1734
|
+
requestPermission: async () => ({
|
|
1735
|
+
outcome: { outcome: "cancelled" }
|
|
1736
|
+
})
|
|
1737
|
+
}), new AgentStream2({
|
|
1738
|
+
pid: child.pid,
|
|
1739
|
+
input: child.stdin,
|
|
1740
|
+
output: framed2(child.stdout),
|
|
1741
|
+
ack: () => {},
|
|
1742
|
+
handle: null,
|
|
1743
|
+
stderr: () => "",
|
|
1744
|
+
exited: child.exited,
|
|
1745
|
+
kill: () => child.kill()
|
|
1746
|
+
}));
|
|
1747
|
+
const response = await Promise.race([
|
|
1748
|
+
connection.initialize({
|
|
1749
|
+
protocolVersion: acp.PROTOCOL_VERSION,
|
|
1750
|
+
clientCapabilities: {}
|
|
1751
|
+
}),
|
|
1752
|
+
child.exited.then(() => {
|
|
1753
|
+
throw new Error("exited");
|
|
1754
|
+
}),
|
|
1755
|
+
new Promise((_, reject) => {
|
|
1756
|
+
aborted = () => reject(signal.reason);
|
|
1757
|
+
signal.addEventListener("abort", aborted, { once: true });
|
|
1758
|
+
})
|
|
1759
|
+
]);
|
|
1760
|
+
if (response.protocolVersion !== acp.PROTOCOL_VERSION) {
|
|
1761
|
+
throw new Error("protocol version");
|
|
1762
|
+
}
|
|
1763
|
+
} catch {
|
|
1764
|
+
throw new Error("OpenCode did not answer splates over ACP. Update OpenCode, then press Try again.");
|
|
1765
|
+
} finally {
|
|
1766
|
+
if (aborted !== undefined) {
|
|
1767
|
+
signal.removeEventListener("abort", aborted);
|
|
1768
|
+
}
|
|
1769
|
+
child.kill();
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
async choose(selection) {
|
|
1773
|
+
await this.prepare();
|
|
1774
|
+
await this.models.save(selection, AbortSignal.timeout(60000));
|
|
1775
|
+
await this.deps.roster?.();
|
|
1776
|
+
}
|
|
1777
|
+
async verify(cwd) {
|
|
1778
|
+
const where = cwd ?? await this.prepare();
|
|
1779
|
+
const recipe = await this.models.recipes.stored();
|
|
1780
|
+
if (recipe === null) {
|
|
1781
|
+
throw new OpenCodeModelError("Choose the models first.");
|
|
1782
|
+
}
|
|
1783
|
+
try {
|
|
1784
|
+
const signal = AbortSignal.timeout(60000);
|
|
1785
|
+
await this.models.verifyStored(recipe, where, signal);
|
|
1786
|
+
await this.handshake(where, recipe.env);
|
|
1787
|
+
await this.models.recipes.unchanged(recipe, signal);
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
throw error instanceof OpenCodeModelError ? error : new Error("OpenCode could not check the saved models. Press Try again.");
|
|
1790
|
+
}
|
|
1791
|
+
this.#verified = recipe.raw;
|
|
1792
|
+
return { model: recipe.model, auxiliary: recipe.auxiliary };
|
|
1793
|
+
}
|
|
1794
|
+
async ready() {
|
|
1795
|
+
return this.#verified !== null && await this.models.recipes.rawRoster() === this.#verified;
|
|
1796
|
+
}
|
|
1797
|
+
async disable() {
|
|
1798
|
+
await this.models.recipes.disable(AbortSignal.timeout(15000));
|
|
1799
|
+
this.models.invalidate();
|
|
1800
|
+
this.#verified = null;
|
|
1801
|
+
await this.deps.roster?.();
|
|
1802
|
+
}
|
|
1803
|
+
async prepare() {
|
|
1804
|
+
await this.deps.fs.mkdir(this.cwd, { recursive: true });
|
|
1805
|
+
return this.cwd;
|
|
1806
|
+
}
|
|
1807
|
+
async command(args, signal, env, cwd) {
|
|
1808
|
+
signal.throwIfAborted();
|
|
1809
|
+
const result = await this.deps.ps.spawnCapture(["opencode", ...args], {
|
|
1810
|
+
cwd: cwd ?? await this.prepare(),
|
|
1811
|
+
env,
|
|
1812
|
+
signal,
|
|
1813
|
+
timeoutMs: 15000,
|
|
1814
|
+
stdin: ""
|
|
1815
|
+
});
|
|
1816
|
+
if (result.exitCode !== 0) {
|
|
1817
|
+
throw new Error("command failed");
|
|
1818
|
+
}
|
|
1819
|
+
return stripVTControlCharacters(result.stdout);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
function storedGo(value) {
|
|
1823
|
+
return Array.isArray(value) && value.some((item) => typeof item === "object" && item !== null && item.id === "opencode-go" && Array.isArray(item.connections) && item.connections.some((entry) => typeof entry === "object" && entry !== null && ("type" in entry) && entry.type === "credential"));
|
|
1824
|
+
}
|
|
1825
|
+
// setup/opencode-routes.ts
|
|
1826
|
+
class OpenCodeSetupRoutes2 {
|
|
1827
|
+
setup;
|
|
1828
|
+
constructor(setup) {
|
|
1829
|
+
this.setup = setup;
|
|
1830
|
+
}
|
|
1831
|
+
async conversation(cwd, start) {
|
|
1832
|
+
let selection;
|
|
1833
|
+
try {
|
|
1834
|
+
selection = await this.setup.verify(cwd);
|
|
1835
|
+
} catch (error) {
|
|
1836
|
+
return refuse(400, "setup", problemOf(error));
|
|
1837
|
+
}
|
|
1838
|
+
return start(selection);
|
|
1839
|
+
}
|
|
1840
|
+
disable = async () => {
|
|
1841
|
+
try {
|
|
1842
|
+
await this.setup.disable();
|
|
1843
|
+
return Response.json({});
|
|
1844
|
+
} catch {
|
|
1845
|
+
return refuse(400, "setup", "Could not turn OpenCode off: the roster's OpenCode entry was changed by hand, so Setup leaves it alone.");
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
function problemOf(error) {
|
|
1850
|
+
return error instanceof OpenCodeModelError || error instanceof Error ? error.message : "OpenCode could not check the saved models.";
|
|
1851
|
+
}
|
|
1852
|
+
// setup/project.ts
|
|
1853
|
+
function setupProjectAt2(root, { fs, ps }, records = {}) {
|
|
1854
|
+
const git = new Git(root, { fs, ps });
|
|
1855
|
+
return {
|
|
1856
|
+
...records,
|
|
1857
|
+
root,
|
|
1858
|
+
config: () => loadConfig2(root, { fs, git }),
|
|
1859
|
+
remoteUrl: (remote) => git.remoteUrl(remote)
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
// setup/step-problem.ts
|
|
1863
|
+
class StepProblem extends Error {
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
// setup/routes.ts
|
|
1867
|
+
class SetupRoutes2 {
|
|
1868
|
+
#setupFor;
|
|
1869
|
+
constructor(setupFor) {
|
|
1870
|
+
this.#setupFor = setupFor;
|
|
1871
|
+
}
|
|
1872
|
+
read = async (request) => Response.json(await (await this.#setupFor(request)).read());
|
|
1873
|
+
see = async (request) => {
|
|
1874
|
+
const setup = await this.#setupFor(request);
|
|
1875
|
+
await setup.see();
|
|
1876
|
+
return Response.json(await setup.read());
|
|
1877
|
+
};
|
|
1878
|
+
next = async (request) => {
|
|
1879
|
+
const step = idOf(request);
|
|
1880
|
+
const { answers = {} } = await body(request);
|
|
1881
|
+
if (!isAnswers(answers)) {
|
|
1882
|
+
fail2("usage", "send the page's answers: { answers: { [field]: string | boolean } }", {
|
|
1883
|
+
step
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
try {
|
|
1887
|
+
return Response.json(await (await this.#setupFor(request)).submit(step, answers));
|
|
1888
|
+
} catch (error) {
|
|
1889
|
+
if (error instanceof StepProblem) {
|
|
1890
|
+
return refuse(422, "step", error.message);
|
|
1891
|
+
}
|
|
1892
|
+
throw error;
|
|
1893
|
+
}
|
|
1894
|
+
};
|
|
1895
|
+
undoPlan = async (request) => Response.json(await (await this.#setupFor(request)).undoPlan(idOf(request)));
|
|
1896
|
+
undo = async (request) => {
|
|
1897
|
+
const area = idOf(request);
|
|
1898
|
+
const { confirm = null } = await body(request);
|
|
1899
|
+
if (confirm !== null && typeof confirm !== "string") {
|
|
1900
|
+
fail2("usage", "send { confirm: string } or nothing", { area });
|
|
1901
|
+
}
|
|
1902
|
+
try {
|
|
1903
|
+
return Response.json(await (await this.#setupFor(request)).undo(area, confirm));
|
|
1904
|
+
} catch (error) {
|
|
1905
|
+
if (error instanceof StepProblem) {
|
|
1906
|
+
return refuse(422, "undo", error.message);
|
|
1907
|
+
}
|
|
1908
|
+
throw error;
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
function idOf(request) {
|
|
1913
|
+
return decodeURIComponent(new URL(request.url).pathname.split("/")[3] ?? "");
|
|
1914
|
+
}
|
|
1915
|
+
function isAnswers(value) {
|
|
1916
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every((each) => typeof each === "string" || typeof each === "boolean");
|
|
1917
|
+
}
|
|
1918
|
+
// setup/setup.ts
|
|
1919
|
+
import { z as z3 } from "zod";
|
|
1920
|
+
|
|
1921
|
+
// setup/checks.ts
|
|
1922
|
+
async function listed(step, machine) {
|
|
1923
|
+
return await step.shown?.(machine).catch(() => false) ?? true;
|
|
1924
|
+
}
|
|
1925
|
+
async function checked(step, machine) {
|
|
1926
|
+
try {
|
|
1927
|
+
return { done: await step.check(machine), problem: null };
|
|
1928
|
+
} catch (error) {
|
|
1929
|
+
return {
|
|
1930
|
+
done: false,
|
|
1931
|
+
problem: error instanceof Error ? error.message : String(error)
|
|
1932
|
+
};
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
// setup/fields.ts
|
|
1937
|
+
async function fieldsOf(step, machine) {
|
|
1938
|
+
const fields = [];
|
|
1939
|
+
for (const field of await fieldsIn(step, machine).catch(() => [])) {
|
|
1940
|
+
switch (field.kind) {
|
|
1941
|
+
case "cred": {
|
|
1942
|
+
const { optional: _, ...rest } = field;
|
|
1943
|
+
fields.push({
|
|
1944
|
+
...rest,
|
|
1945
|
+
help: field.help ?? null,
|
|
1946
|
+
saved: await machine.device.get(field.name) !== undefined
|
|
1947
|
+
});
|
|
1948
|
+
break;
|
|
1949
|
+
}
|
|
1950
|
+
case "text":
|
|
1951
|
+
fields.push({
|
|
1952
|
+
...field,
|
|
1953
|
+
placeholder: field.placeholder ?? null,
|
|
1954
|
+
value: field.value ?? null,
|
|
1955
|
+
optional: field.optional ?? false
|
|
1956
|
+
});
|
|
1957
|
+
break;
|
|
1958
|
+
case "yes-no":
|
|
1959
|
+
fields.push(field);
|
|
1960
|
+
break;
|
|
1961
|
+
case "choice": {
|
|
1962
|
+
const { options, ...rest } = field;
|
|
1963
|
+
const listed = await options(machine).catch(() => []);
|
|
1964
|
+
fields.push({ ...rest, options: [...listed] });
|
|
1965
|
+
break;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
return fields;
|
|
1970
|
+
}
|
|
1971
|
+
async function fieldsIn(step, machine) {
|
|
1972
|
+
const { fields } = step;
|
|
1973
|
+
return typeof fields === "function" ? fields(machine) : fields ?? [];
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
// setup/undo.ts
|
|
1977
|
+
class SetupUndo {
|
|
1978
|
+
#areas;
|
|
1979
|
+
#machine;
|
|
1980
|
+
constructor(machine, areas) {
|
|
1981
|
+
this.#areas = areas;
|
|
1982
|
+
this.#machine = machine;
|
|
1983
|
+
}
|
|
1984
|
+
async plan(id) {
|
|
1985
|
+
const area = this.#area(id);
|
|
1986
|
+
const machine = this.#machine;
|
|
1987
|
+
const done = await this.#done();
|
|
1988
|
+
const undone = await this.#undone(area, done);
|
|
1989
|
+
const keeps = await this.#keeps(undone, done);
|
|
1990
|
+
const kept = keptOf(keeps);
|
|
1991
|
+
const steps = [];
|
|
1992
|
+
const refusals = [];
|
|
1993
|
+
let confirm = null;
|
|
1994
|
+
for (const step of undone) {
|
|
1995
|
+
const undo = step.undo;
|
|
1996
|
+
const refused = await undo?.refused?.(machine) ?? null;
|
|
1997
|
+
if (refused !== null) {
|
|
1998
|
+
refusals.push(refused);
|
|
1999
|
+
}
|
|
2000
|
+
confirm = confirm ?? await undo?.confirm?.(machine) ?? null;
|
|
2001
|
+
steps.push({
|
|
2002
|
+
id: step.id,
|
|
2003
|
+
title: step.title,
|
|
2004
|
+
done: done.has(step),
|
|
2005
|
+
removes: [...await undo?.removes(machine, kept) ?? []],
|
|
2006
|
+
leaves: [...await undo?.leaves?.(machine) ?? []]
|
|
2007
|
+
});
|
|
2008
|
+
}
|
|
2009
|
+
const needing = this.#needing(area, undone, done);
|
|
2010
|
+
if (needing !== null) {
|
|
2011
|
+
refusals.unshift(needing);
|
|
2012
|
+
}
|
|
2013
|
+
return {
|
|
2014
|
+
area: area.id,
|
|
2015
|
+
title: area.title,
|
|
2016
|
+
steps,
|
|
2017
|
+
creds: await this.#creds(keeps),
|
|
2018
|
+
confirm,
|
|
2019
|
+
refused: refusals[0] ?? null
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
async run(id, confirm) {
|
|
2023
|
+
const plan = await this.plan(id);
|
|
2024
|
+
if (plan.refused !== null) {
|
|
2025
|
+
throw new StepProblem(plan.refused);
|
|
2026
|
+
}
|
|
2027
|
+
if (plan.confirm !== null && confirm?.trim() !== plan.confirm) {
|
|
2028
|
+
throw new StepProblem(`Type ${plan.confirm} to undo ${plan.title}.`);
|
|
2029
|
+
}
|
|
2030
|
+
const area = this.#area(id);
|
|
2031
|
+
const done = await this.#done();
|
|
2032
|
+
const undone = await this.#undone(area, done);
|
|
2033
|
+
const kept = keptOf(await this.#keeps(undone, done));
|
|
2034
|
+
for (const step of undone) {
|
|
2035
|
+
try {
|
|
2036
|
+
await step.undo?.run(this.#machine, kept);
|
|
2037
|
+
} catch (error) {
|
|
2038
|
+
throw new StepProblem(`Undoing "${step.title}" failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
for (const cred of plan.creds) {
|
|
2042
|
+
if (cred.keptFor === null) {
|
|
2043
|
+
await this.#machine.device.delete(cred.name);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
#area(id) {
|
|
2048
|
+
const area = this.#areas.find((each) => each.id === id);
|
|
2049
|
+
if (area === undefined) {
|
|
2050
|
+
fail2("not_found", `no setup area '${id}': \`splates setup\` lists them`, {
|
|
2051
|
+
area: id
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
return area;
|
|
2055
|
+
}
|
|
2056
|
+
async undoable(id, done) {
|
|
2057
|
+
return (await this.#undone(this.#area(id), done)).length > 0;
|
|
2058
|
+
}
|
|
2059
|
+
async#done() {
|
|
2060
|
+
const done = new Set;
|
|
2061
|
+
for (const step of this.#areas.flatMap((area) => area.steps)) {
|
|
2062
|
+
if (await listed(step, this.#machine) && (await checked(step, this.#machine)).done) {
|
|
2063
|
+
done.add(step);
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
return done;
|
|
2067
|
+
}
|
|
2068
|
+
async#undone(area, done) {
|
|
2069
|
+
const undone = [];
|
|
2070
|
+
for (const step of area.steps) {
|
|
2071
|
+
if (done.has(step) || await listed(step, this.#machine) && await this.#started(step, area, done)) {
|
|
2072
|
+
undone.push(step);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
return undone.reverse();
|
|
2076
|
+
}
|
|
2077
|
+
async#started(step, area, done) {
|
|
2078
|
+
const fields = await fieldsIn(step, this.#machine).catch(() => []);
|
|
2079
|
+
for (const field of fields) {
|
|
2080
|
+
if (field.kind === "cred" && await this.#machine.device.get(field.name) !== undefined && this.#keptFor(field.name, done, area.steps) === null) {
|
|
2081
|
+
return true;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
return false;
|
|
2085
|
+
}
|
|
2086
|
+
#needing(area, undone, done) {
|
|
2087
|
+
for (const other of this.#areas) {
|
|
2088
|
+
if (other === area) {
|
|
2089
|
+
continue;
|
|
2090
|
+
}
|
|
2091
|
+
for (const step of other.steps) {
|
|
2092
|
+
const needs = step.after.find((each) => undone.includes(each));
|
|
2093
|
+
if (needs !== undefined && done.has(step)) {
|
|
2094
|
+
return `Undo ${other.title} first: its "${step.title}" needs "${needs.title}".`;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
2100
|
+
async#keeps(undone, done) {
|
|
2101
|
+
const machine = this.#machine;
|
|
2102
|
+
const names = new Set((await Promise.all(undone.map((step) => sharedOf(step, machine)))).flat());
|
|
2103
|
+
return new Map([...names].map((name) => [name, this.#keptFor(name, done, undone)]));
|
|
2104
|
+
}
|
|
2105
|
+
#keptFor(name, done, besides) {
|
|
2106
|
+
const user = [...done].find((step) => !besides.includes(step) && (step.uses ?? []).includes(name));
|
|
2107
|
+
return OUTSIDE[name] ?? user?.title ?? null;
|
|
2108
|
+
}
|
|
2109
|
+
async#creds(keeps) {
|
|
2110
|
+
const creds = [];
|
|
2111
|
+
for (const [name, keptFor] of keeps) {
|
|
2112
|
+
if (await this.#machine.device.get(name) !== undefined) {
|
|
2113
|
+
creds.push({ name, keptFor });
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return creds;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
var OUTSIDE = {
|
|
2120
|
+
CLOUDFLARE_API_TOKEN: "scry's Workers AI",
|
|
2121
|
+
CLOUDFLARE_ACCOUNT_ID: "scry's Workers AI"
|
|
2122
|
+
};
|
|
2123
|
+
function keptOf(keeps) {
|
|
2124
|
+
return new Set([...keeps].filter(([, keptFor]) => keptFor !== null).map(([name]) => name));
|
|
2125
|
+
}
|
|
2126
|
+
async function sharedOf(step, machine) {
|
|
2127
|
+
const fields = await fieldsIn(step, machine).catch(() => []);
|
|
2128
|
+
return [
|
|
2129
|
+
...fields.flatMap((field) => field.kind === "cred" ? [field.name] : []),
|
|
2130
|
+
...step.uses ?? []
|
|
2131
|
+
];
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
// setup/setup.ts
|
|
2135
|
+
class Setup2 {
|
|
2136
|
+
#areas;
|
|
2137
|
+
#machine;
|
|
2138
|
+
#undo;
|
|
2139
|
+
constructor(machine, areas) {
|
|
2140
|
+
checkRoster(areas);
|
|
2141
|
+
this.#areas = areas;
|
|
2142
|
+
this.#machine = machine;
|
|
2143
|
+
this.#undo = new SetupUndo(machine, areas);
|
|
2144
|
+
}
|
|
2145
|
+
get #file() {
|
|
2146
|
+
return new FsStorage2(this.#machine.home, this.#machine.fs).document("setup.json");
|
|
2147
|
+
}
|
|
2148
|
+
async step(id) {
|
|
2149
|
+
for (const area of this.#areas) {
|
|
2150
|
+
for (const step of await this.#stepsOf(area)) {
|
|
2151
|
+
if (step.id === id) {
|
|
2152
|
+
return step;
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
fail2("not_found", `no setup step '${id}': \`splates setup\` lists them`, {
|
|
2157
|
+
step: id
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
async submit(id, answers) {
|
|
2161
|
+
const step = await this.step(id);
|
|
2162
|
+
for (const before of step.after) {
|
|
2163
|
+
if (!(await checked(before, this.#machine)).done) {
|
|
2164
|
+
throw new StepProblem(`Do "${before.title}" first.`);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
for (const field of await fieldsIn(step, this.#machine)) {
|
|
2168
|
+
const answer = answers[field.name];
|
|
2169
|
+
if (field.kind === "yes-no") {
|
|
2170
|
+
if (typeof answer !== "boolean") {
|
|
2171
|
+
throw new StepProblem(`Say yes or no to "${field.label}".`);
|
|
2172
|
+
}
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
if (field.kind === "cred") {
|
|
2176
|
+
if (!field.optional && await this.#machine.device.get(field.name) === undefined) {
|
|
2177
|
+
throw new StepProblem(`Paste the ${field.label} first.`);
|
|
2178
|
+
}
|
|
2179
|
+
continue;
|
|
2180
|
+
}
|
|
2181
|
+
const text = typeof answer === "string" ? answer.trim() : "";
|
|
2182
|
+
if (text === "" && field.kind === "text" && field.optional) {
|
|
2183
|
+
continue;
|
|
2184
|
+
}
|
|
2185
|
+
if (text === "") {
|
|
2186
|
+
throw new StepProblem(`Fill in "${field.label}" first.`);
|
|
2187
|
+
}
|
|
2188
|
+
if (field.kind === "choice" && !(await field.options(this.#machine)).some((option) => option.value === text)) {
|
|
2189
|
+
throw new StepProblem(`Pick one of the choices for "${field.label}".`);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
try {
|
|
2193
|
+
await step.submit?.(this.#machine, answers);
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
throw new StepProblem(error instanceof Error ? error.message : String(error));
|
|
2196
|
+
}
|
|
2197
|
+
const { done, problem } = await checked(step, this.#machine);
|
|
2198
|
+
if (!done) {
|
|
2199
|
+
throw new StepProblem(problem ?? step.notDone ?? NOT_DONE);
|
|
2200
|
+
}
|
|
2201
|
+
return this.read();
|
|
2202
|
+
}
|
|
2203
|
+
async read() {
|
|
2204
|
+
const skipped = new Set(await this.#skipped());
|
|
2205
|
+
const statuses = new Map;
|
|
2206
|
+
const areas = [];
|
|
2207
|
+
for (const area of this.#areas) {
|
|
2208
|
+
const steps = [];
|
|
2209
|
+
for (const step of await this.#stepsOf(area, true)) {
|
|
2210
|
+
if (step.each !== undefined) {
|
|
2211
|
+
statuses.set(step, await this.#standInStatus(step, statuses));
|
|
2212
|
+
continue;
|
|
2213
|
+
}
|
|
2214
|
+
if (!await listed(step, this.#machine)) {
|
|
2215
|
+
continue;
|
|
2216
|
+
}
|
|
2217
|
+
const { done, problem } = await checked(step, this.#machine);
|
|
2218
|
+
const before = step.after.map((each) => statuses.get(each));
|
|
2219
|
+
const status = done ? "done" : skipped.has(step.id) || before.includes("skipped") ? "skipped" : before.every((each) => each === "done") ? "ready" : "waiting";
|
|
2220
|
+
statuses.set(step, status);
|
|
2221
|
+
steps.push({
|
|
2222
|
+
id: step.id,
|
|
2223
|
+
title: step.title,
|
|
2224
|
+
why: step.why,
|
|
2225
|
+
user: step.user,
|
|
2226
|
+
agent: step.agent,
|
|
2227
|
+
optional: step.optional,
|
|
2228
|
+
after: step.after.map((each) => each.id),
|
|
2229
|
+
status,
|
|
2230
|
+
problem,
|
|
2231
|
+
cred: (await fieldsIn(step, this.#machine).catch(() => [])).find((field) => field.kind === "cred")?.name ?? null,
|
|
2232
|
+
fields: await fieldsOf(step, this.#machine),
|
|
2233
|
+
doing: step.doing ?? null,
|
|
2234
|
+
detail: await step.detail?.(this.#machine).catch(() => null) ?? null,
|
|
2235
|
+
warning: await step.warning?.(this.#machine).catch(() => null) ?? null,
|
|
2236
|
+
data: await step.data?.(this.#machine).catch(() => null) ?? null
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
areas.push({
|
|
2240
|
+
id: area.id,
|
|
2241
|
+
title: area.title,
|
|
2242
|
+
purpose: area.purpose,
|
|
2243
|
+
optional: steps.every((step) => step.optional),
|
|
2244
|
+
done: steps.filter((step) => step.status === "done").length,
|
|
2245
|
+
skipped: steps.filter((step) => step.status === "skipped").length,
|
|
2246
|
+
left: steps.filter((step) => step.status === "ready" || step.status === "waiting").length,
|
|
2247
|
+
undoable: false,
|
|
2248
|
+
steps
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
const done = new Set([...statuses].flatMap(([step, status]) => status === "done" ? [step] : []));
|
|
2252
|
+
for (const area of areas) {
|
|
2253
|
+
area.undoable = await this.#undo.undoable(area.id, done);
|
|
2254
|
+
}
|
|
2255
|
+
const all = areas.flatMap((area) => area.steps);
|
|
2256
|
+
const ready = all.filter((step) => step.status === "ready");
|
|
2257
|
+
const next = ready.find((step) => !step.optional) ?? ready[0] ?? null;
|
|
2258
|
+
return {
|
|
2259
|
+
areas,
|
|
2260
|
+
next: next?.id ?? null,
|
|
2261
|
+
fresh: await this.#file.read() === null,
|
|
2262
|
+
required: all.some((step) => !step.optional && (step.status === "ready" || step.status === "waiting"))
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
async skip(id) {
|
|
2266
|
+
await this.step(id);
|
|
2267
|
+
const skipped = await this.#skipped();
|
|
2268
|
+
if (!skipped.includes(id)) {
|
|
2269
|
+
await this.#save([...skipped, id]);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
async unskip(id) {
|
|
2273
|
+
await this.step(id);
|
|
2274
|
+
const skipped = await this.#skipped();
|
|
2275
|
+
if (skipped.includes(id)) {
|
|
2276
|
+
await this.#save(skipped.filter((each) => each !== id));
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
async see() {
|
|
2280
|
+
if (await this.#file.read() === null) {
|
|
2281
|
+
await this.#save([]);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
undoPlan(id) {
|
|
2285
|
+
return this.#undo.plan(id);
|
|
2286
|
+
}
|
|
2287
|
+
async undo(id, confirm) {
|
|
2288
|
+
await this.#undo.run(id, confirm);
|
|
2289
|
+
return this.read();
|
|
2290
|
+
}
|
|
2291
|
+
async#stepsOf(area, standIns = false) {
|
|
2292
|
+
const steps = [];
|
|
2293
|
+
for (const step of area.steps) {
|
|
2294
|
+
if (step.each === undefined) {
|
|
2295
|
+
steps.push(step);
|
|
2296
|
+
continue;
|
|
2297
|
+
}
|
|
2298
|
+
steps.push(...await step.each(this.#machine).catch(() => []));
|
|
2299
|
+
if (standIns) {
|
|
2300
|
+
steps.push(step);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
return steps;
|
|
2304
|
+
}
|
|
2305
|
+
async#standInStatus(step, statuses) {
|
|
2306
|
+
if ((await checked(step, this.#machine)).done) {
|
|
2307
|
+
return "done";
|
|
2308
|
+
}
|
|
2309
|
+
const each = [...statuses].flatMap(([one, status]) => one.of === step ? [status] : []);
|
|
2310
|
+
return each.includes("skipped") && each.every((status) => status === "done" || status === "skipped") ? "skipped" : "waiting";
|
|
2311
|
+
}
|
|
2312
|
+
async#skipped() {
|
|
2313
|
+
const raw = await this.#file.read();
|
|
2314
|
+
if (raw === null) {
|
|
2315
|
+
return [];
|
|
2316
|
+
}
|
|
2317
|
+
const parsed = SKIPS.safeParse(raw);
|
|
2318
|
+
if (!parsed.success) {
|
|
2319
|
+
throw new Error(`${this.#file.key} is not what splates saved: remove it to ask every step again`);
|
|
2320
|
+
}
|
|
2321
|
+
return parsed.data.format > FORMAT ? [] : parsed.data.skipped;
|
|
2322
|
+
}
|
|
2323
|
+
async#save(skipped) {
|
|
2324
|
+
await this.#file.write({ format: FORMAT, skipped });
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
var FORMAT = 1;
|
|
2328
|
+
var SKIPS = z3.object({
|
|
2329
|
+
format: z3.number(),
|
|
2330
|
+
skipped: z3.array(z3.string())
|
|
2331
|
+
});
|
|
2332
|
+
var NOT_DONE = "This step is not done yet: do it, then press Next.";
|
|
2333
|
+
function checkRoster(areas) {
|
|
2334
|
+
const seen = new Set;
|
|
2335
|
+
const ids = new Set;
|
|
2336
|
+
for (const area of areas) {
|
|
2337
|
+
if (ids.has(area.id)) {
|
|
2338
|
+
throw new Error(`setup names '${area.id}' twice`);
|
|
2339
|
+
}
|
|
2340
|
+
ids.add(area.id);
|
|
2341
|
+
}
|
|
2342
|
+
const steps = new Set;
|
|
2343
|
+
for (const step of areas.flatMap((area) => area.steps)) {
|
|
2344
|
+
if (steps.has(step.id)) {
|
|
2345
|
+
throw new Error(`setup names step '${step.id}' twice`);
|
|
2346
|
+
}
|
|
2347
|
+
for (const before of step.after) {
|
|
2348
|
+
if (!seen.has(before)) {
|
|
2349
|
+
throw new Error(`setup step '${step.id}' waits on '${before.id}', which is not on the roster before it`);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
steps.add(step.id);
|
|
2353
|
+
seen.add(step);
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
export { transcriberFor, Dictations, SETUP_AREAS2, OpenCodeSetup2, OpenCodeSetupRoutes2, setupProjectAt2, SetupRoutes2, Setup2 };
|