@xfey/tutti 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/dist/approvals/index.d.ts +3 -0
- package/dist/approvals/index.js +3 -0
- package/dist/approvals/manager.d.ts +47 -0
- package/dist/approvals/manager.js +180 -0
- package/dist/approvals/projections.d.ts +34 -0
- package/dist/approvals/projections.js +444 -0
- package/dist/artifacts/index.d.ts +4 -0
- package/dist/artifacts/index.js +4 -0
- package/dist/artifacts/manifest.d.ts +48 -0
- package/dist/artifacts/manifest.js +334 -0
- package/dist/artifacts/preview-runtime.d.ts +97 -0
- package/dist/artifacts/preview-runtime.js +585 -0
- package/dist/artifacts/static-preview.d.ts +17 -0
- package/dist/artifacts/static-preview.js +180 -0
- package/dist/chat-assistant/index.d.ts +66 -0
- package/dist/chat-assistant/index.js +268 -0
- package/dist/checks/index.d.ts +47 -0
- package/dist/checks/index.js +169 -0
- package/dist/collaboration-state/clarification-messages.d.ts +8 -0
- package/dist/collaboration-state/clarification-messages.js +180 -0
- package/dist/collaboration-state/clarification-records.d.ts +27 -0
- package/dist/collaboration-state/clarification-records.js +266 -0
- package/dist/collaboration-state/clarification-round-writes.d.ts +14 -0
- package/dist/collaboration-state/clarification-round-writes.js +58 -0
- package/dist/collaboration-state/clarification-rounds.d.ts +19 -0
- package/dist/collaboration-state/clarification-rounds.js +347 -0
- package/dist/collaboration-state/clarification-successors.d.ts +8 -0
- package/dist/collaboration-state/clarification-successors.js +318 -0
- package/dist/collaboration-state/execution-status.d.ts +3 -0
- package/dist/collaboration-state/execution-status.js +8 -0
- package/dist/collaboration-state/index.d.ts +17 -0
- package/dist/collaboration-state/index.js +16 -0
- package/dist/collaboration-state/messages.d.ts +25 -0
- package/dist/collaboration-state/messages.js +371 -0
- package/dist/collaboration-state/read-state.d.ts +7 -0
- package/dist/collaboration-state/read-state.js +136 -0
- package/dist/collaboration-state/recovery.d.ts +6 -0
- package/dist/collaboration-state/recovery.js +125 -0
- package/dist/collaboration-state/run-recording.d.ts +5 -0
- package/dist/collaboration-state/run-recording.js +216 -0
- package/dist/collaboration-state/run-results.d.ts +12 -0
- package/dist/collaboration-state/run-results.js +202 -0
- package/dist/collaboration-state/scratchpad-source-state.d.ts +46 -0
- package/dist/collaboration-state/scratchpad-source-state.js +207 -0
- package/dist/collaboration-state/scratchpad.d.ts +8 -0
- package/dist/collaboration-state/scratchpad.js +84 -0
- package/dist/collaboration-state/serialization.d.ts +16 -0
- package/dist/collaboration-state/serialization.js +71 -0
- package/dist/collaboration-state/storage-types.d.ts +136 -0
- package/dist/collaboration-state/storage-types.js +2 -0
- package/dist/collaboration-state/task-details.d.ts +5 -0
- package/dist/collaboration-state/task-details.js +25 -0
- package/dist/collaboration-state/types.d.ts +289 -0
- package/dist/collaboration-state/types.js +2 -0
- package/dist/collaboration-state/worklist.d.ts +11 -0
- package/dist/collaboration-state/worklist.js +286 -0
- package/dist/control-plane/clarification-commands.d.ts +34 -0
- package/dist/control-plane/clarification-commands.js +106 -0
- package/dist/control-plane/command-recovery.d.ts +3 -0
- package/dist/control-plane/command-recovery.js +79 -0
- package/dist/control-plane/context-sync.d.ts +47 -0
- package/dist/control-plane/context-sync.js +207 -0
- package/dist/control-plane/event-publishers.d.ts +24 -0
- package/dist/control-plane/event-publishers.js +192 -0
- package/dist/control-plane/execution-status.d.ts +13 -0
- package/dist/control-plane/execution-status.js +130 -0
- package/dist/control-plane/follow-up-context.d.ts +27 -0
- package/dist/control-plane/follow-up-context.js +93 -0
- package/dist/control-plane/follow-up-output.d.ts +53 -0
- package/dist/control-plane/follow-up-output.js +141 -0
- package/dist/control-plane/follow-up-run.d.ts +22 -0
- package/dist/control-plane/follow-up-run.js +90 -0
- package/dist/control-plane/follow-up-start.d.ts +26 -0
- package/dist/control-plane/follow-up-start.js +101 -0
- package/dist/control-plane/formatters.d.ts +12 -0
- package/dist/control-plane/formatters.js +47 -0
- package/dist/control-plane/index.d.ts +62 -0
- package/dist/control-plane/index.js +416 -0
- package/dist/control-plane/invalidations.d.ts +12 -0
- package/dist/control-plane/invalidations.js +67 -0
- package/dist/control-plane/procedure-logging.d.ts +11 -0
- package/dist/control-plane/procedure-logging.js +95 -0
- package/dist/control-plane/project-brief-refresh.d.ts +31 -0
- package/dist/control-plane/project-brief-refresh.js +105 -0
- package/dist/control-plane/project-context-bootstrap.d.ts +39 -0
- package/dist/control-plane/project-context-bootstrap.js +107 -0
- package/dist/control-plane/reference-summary-refresh.d.ts +22 -0
- package/dist/control-plane/reference-summary-refresh.js +344 -0
- package/dist/control-plane/run-lineage.d.ts +8 -0
- package/dist/control-plane/run-lineage.js +13 -0
- package/dist/control-plane/run-result-recording.d.ts +46 -0
- package/dist/control-plane/run-result-recording.js +81 -0
- package/dist/control-plane/run-scheduler.d.ts +35 -0
- package/dist/control-plane/run-scheduler.js +110 -0
- package/dist/control-plane/run-start.d.ts +30 -0
- package/dist/control-plane/run-start.js +167 -0
- package/dist/control-plane/scratchpad-auto-refresh.d.ts +32 -0
- package/dist/control-plane/scratchpad-auto-refresh.js +150 -0
- package/dist/control-plane/scratchpad-refresh-start.d.ts +60 -0
- package/dist/control-plane/scratchpad-refresh-start.js +240 -0
- package/dist/control-plane/scratchpad-refresh.d.ts +29 -0
- package/dist/control-plane/scratchpad-refresh.js +55 -0
- package/dist/control-plane/scratchpad-source-messages.d.ts +10 -0
- package/dist/control-plane/scratchpad-source-messages.js +131 -0
- package/dist/control-plane/startup-recovery.d.ts +19 -0
- package/dist/control-plane/startup-recovery.js +113 -0
- package/dist/control-plane/task-compile-continuation.d.ts +25 -0
- package/dist/control-plane/task-compile-continuation.js +127 -0
- package/dist/control-plane/task-compile-output.d.ts +29 -0
- package/dist/control-plane/task-compile-output.js +122 -0
- package/dist/control-plane/task-compile-start.d.ts +43 -0
- package/dist/control-plane/task-compile-start.js +280 -0
- package/dist/control-plane/task-proposal.d.ts +3 -0
- package/dist/control-plane/task-proposal.js +37 -0
- package/dist/control-plane/types.d.ts +155 -0
- package/dist/control-plane/types.js +2 -0
- package/dist/control-plane/workflows/index.d.ts +4 -0
- package/dist/control-plane/workflows/index.js +4 -0
- package/dist/control-plane/workflows/openai.d.ts +34 -0
- package/dist/control-plane/workflows/openai.js +411 -0
- package/dist/control-plane/workflows/structured-output-schemas.d.ts +9 -0
- package/dist/control-plane/workflows/structured-output-schemas.js +289 -0
- package/dist/control-plane/workflows/structured-output-validators.d.ts +15 -0
- package/dist/control-plane/workflows/structured-output-validators.js +295 -0
- package/dist/control-plane/workflows/structured-output.d.ts +3 -0
- package/dist/control-plane/workflows/structured-output.js +3 -0
- package/dist/control-plane/workflows/types.d.ts +274 -0
- package/dist/control-plane/workflows/types.js +2 -0
- package/dist/control-plane/worklist-terminal-feedback.d.ts +15 -0
- package/dist/control-plane/worklist-terminal-feedback.js +135 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +32 -0
- package/dist/procedure-engine/index.d.ts +56 -0
- package/dist/procedure-engine/index.js +163 -0
- package/dist/project-brief/index.d.ts +4 -0
- package/dist/project-brief/index.js +3 -0
- package/dist/project-brief/repository.d.ts +5 -0
- package/dist/project-brief/repository.js +97 -0
- package/dist/project-brief/source.d.ts +8 -0
- package/dist/project-brief/source.js +75 -0
- package/dist/project-brief/types.d.ts +40 -0
- package/dist/project-brief/types.js +2 -0
- package/dist/project-docs/context.d.ts +34 -0
- package/dist/project-docs/context.js +86 -0
- package/dist/project-timeline/index.d.ts +20 -0
- package/dist/project-timeline/index.js +100 -0
- package/dist/prompt-templates/index.d.ts +13 -0
- package/dist/prompt-templates/index.js +86 -0
- package/dist/provider-usage/index.d.ts +37 -0
- package/dist/provider-usage/index.js +227 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +2 -0
- package/dist/providers/openai/app-server/json-rpc.d.ts +71 -0
- package/dist/providers/openai/app-server/json-rpc.js +298 -0
- package/dist/providers/openai/app-server/permission-profile.d.ts +64 -0
- package/dist/providers/openai/app-server/permission-profile.js +67 -0
- package/dist/providers/openai/app-server/provider-config.d.ts +10 -0
- package/dist/providers/openai/app-server/provider-config.js +39 -0
- package/dist/providers/openai/app-server/read-only-procedure.d.ts +68 -0
- package/dist/providers/openai/app-server/read-only-procedure.js +293 -0
- package/dist/providers/openai/app-server/runtime-helpers.d.ts +20 -0
- package/dist/providers/openai/app-server/runtime-helpers.js +151 -0
- package/dist/providers/openai/app-server/skills.d.ts +82 -0
- package/dist/providers/openai/app-server/skills.js +222 -0
- package/dist/providers/openai/app-server/smoke-cli.d.ts +2 -0
- package/dist/providers/openai/app-server/smoke-cli.js +42 -0
- package/dist/providers/openai/app-server/smoke-helpers.d.ts +19 -0
- package/dist/providers/openai/app-server/smoke-helpers.js +125 -0
- package/dist/providers/openai/app-server/smoke-provider-input.d.ts +6 -0
- package/dist/providers/openai/app-server/smoke-provider-input.js +20 -0
- package/dist/providers/openai/app-server/smoke-types.d.ts +49 -0
- package/dist/providers/openai/app-server/smoke-types.js +20 -0
- package/dist/providers/openai/app-server/smoke.d.ts +9 -0
- package/dist/providers/openai/app-server/smoke.js +157 -0
- package/dist/providers/openai/app-server/workspace-write-run.d.ts +87 -0
- package/dist/providers/openai/app-server/workspace-write-run.js +379 -0
- package/dist/providers/openai/chat-assistant.d.ts +34 -0
- package/dist/providers/openai/chat-assistant.js +72 -0
- package/dist/providers/openai/codex-app-server.d.ts +126 -0
- package/dist/providers/openai/codex-app-server.js +147 -0
- package/dist/providers/openai/credential-store.d.ts +31 -0
- package/dist/providers/openai/credential-store.js +143 -0
- package/dist/providers/openai/credential-validation.d.ts +45 -0
- package/dist/providers/openai/credential-validation.js +190 -0
- package/dist/providers/openai/index.d.ts +13 -0
- package/dist/providers/openai/index.js +13 -0
- package/dist/providers/openai/machine-local-files.d.ts +19 -0
- package/dist/providers/openai/machine-local-files.js +55 -0
- package/dist/providers/openai/model-config.d.ts +4 -0
- package/dist/providers/openai/model-config.js +4 -0
- package/dist/providers/openai/provider-config-errors.d.ts +6 -0
- package/dist/providers/openai/provider-config-errors.js +13 -0
- package/dist/providers/openai/provider-config-shape.d.ts +3 -0
- package/dist/providers/openai/provider-config-shape.js +108 -0
- package/dist/providers/openai/provider-config-toml.d.ts +13 -0
- package/dist/providers/openai/provider-config-toml.js +113 -0
- package/dist/providers/openai/provider-config.d.ts +73 -0
- package/dist/providers/openai/provider-config.js +117 -0
- package/dist/providers/openai/provider-setup.d.ts +31 -0
- package/dist/providers/openai/provider-setup.js +88 -0
- package/dist/providers/openai/sdk-procedure-runner.d.ts +70 -0
- package/dist/providers/openai/sdk-procedure-runner.js +123 -0
- package/dist/providers/openai/token-usage.d.ts +11 -0
- package/dist/providers/openai/token-usage.js +90 -0
- package/dist/run-engine/index.d.ts +61 -0
- package/dist/run-engine/index.js +140 -0
- package/dist/run-pipeline/candidate-diff.d.ts +3 -0
- package/dist/run-pipeline/candidate-diff.js +10 -0
- package/dist/run-pipeline/openai.d.ts +41 -0
- package/dist/run-pipeline/openai.js +548 -0
- package/dist/run-pipeline/promotion-reconcile.d.ts +13 -0
- package/dist/run-pipeline/promotion-reconcile.js +138 -0
- package/dist/run-pipeline/result-projections.d.ts +39 -0
- package/dist/run-pipeline/result-projections.js +115 -0
- package/dist/run-pipeline/task-run-invocation.d.ts +6 -0
- package/dist/run-pipeline/task-run-invocation.js +130 -0
- package/dist/run-pipeline/task-run-output.d.ts +38 -0
- package/dist/run-pipeline/task-run-output.js +146 -0
- package/dist/server-shell/cli/args.d.ts +7 -0
- package/dist/server-shell/cli/args.js +30 -0
- package/dist/server-shell/cli/cli.d.ts +3 -0
- package/dist/server-shell/cli/cli.js +57 -0
- package/dist/server-shell/cli/errors.d.ts +9 -0
- package/dist/server-shell/cli/errors.js +53 -0
- package/dist/server-shell/cli/git-bootstrap.d.ts +24 -0
- package/dist/server-shell/cli/git-bootstrap.js +246 -0
- package/dist/server-shell/cli/host-lifecycle.d.ts +45 -0
- package/dist/server-shell/cli/host-lifecycle.js +298 -0
- package/dist/server-shell/cli/host-relay-status.d.ts +6 -0
- package/dist/server-shell/cli/host-relay-status.js +43 -0
- package/dist/server-shell/cli/host-runtime-endpoint.d.ts +22 -0
- package/dist/server-shell/cli/host-runtime-endpoint.js +120 -0
- package/dist/server-shell/cli/host-server-runtime.d.ts +30 -0
- package/dist/server-shell/cli/host-server-runtime.js +432 -0
- package/dist/server-shell/cli/index.d.ts +8 -0
- package/dist/server-shell/cli/index.js +8 -0
- package/dist/server-shell/cli/launch.d.ts +45 -0
- package/dist/server-shell/cli/launch.js +115 -0
- package/dist/server-shell/cli/machine-local.d.ts +69 -0
- package/dist/server-shell/cli/machine-local.js +223 -0
- package/dist/server-shell/cli/project-identity.d.ts +20 -0
- package/dist/server-shell/cli/project-identity.js +87 -0
- package/dist/server-shell/cli/relay-registration.d.ts +31 -0
- package/dist/server-shell/cli/relay-registration.js +61 -0
- package/dist/server-shell/command-idempotency/index.d.ts +44 -0
- package/dist/server-shell/command-idempotency/index.js +155 -0
- package/dist/server-shell/dev-runner/cli.d.ts +2 -0
- package/dist/server-shell/dev-runner/cli.js +10 -0
- package/dist/server-shell/dev-runner/config.d.ts +38 -0
- package/dist/server-shell/dev-runner/config.js +277 -0
- package/dist/server-shell/dev-runner/host-cli.d.ts +2 -0
- package/dist/server-shell/dev-runner/host-cli.js +22 -0
- package/dist/server-shell/dev-runner/index.d.ts +3 -0
- package/dist/server-shell/dev-runner/index.js +3 -0
- package/dist/server-shell/dev-runner/runner.d.ts +30 -0
- package/dist/server-shell/dev-runner/runner.js +236 -0
- package/dist/server-shell/http/create-server.d.ts +18 -0
- package/dist/server-shell/http/create-server.js +51 -0
- package/dist/server-shell/http/host-tunnel.d.ts +15 -0
- package/dist/server-shell/http/host-tunnel.js +154 -0
- package/dist/server-shell/http/logger.d.ts +7 -0
- package/dist/server-shell/http/logger.js +19 -0
- package/dist/server-shell/http/routes/agent-context-auth.d.ts +41 -0
- package/dist/server-shell/http/routes/agent-context-auth.js +73 -0
- package/dist/server-shell/http/routes/agent-context-errors.d.ts +6 -0
- package/dist/server-shell/http/routes/agent-context-errors.js +9 -0
- package/dist/server-shell/http/routes/agent-context-messages-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/agent-context-messages-routes.js +74 -0
- package/dist/server-shell/http/routes/agent-context-project-doc-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/agent-context-project-doc-routes.js +86 -0
- package/dist/server-shell/http/routes/agent-context-project-docs.d.ts +40 -0
- package/dist/server-shell/http/routes/agent-context-project-docs.js +98 -0
- package/dist/server-shell/http/routes/agent-context-query.d.ts +31 -0
- package/dist/server-shell/http/routes/agent-context-query.js +72 -0
- package/dist/server-shell/http/routes/agent-context-reference-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/agent-context-reference-routes.js +82 -0
- package/dist/server-shell/http/routes/agent-context-references.d.ts +21 -0
- package/dist/server-shell/http/routes/agent-context-references.js +85 -0
- package/dist/server-shell/http/routes/agent-context-shared.d.ts +34 -0
- package/dist/server-shell/http/routes/agent-context-shared.js +44 -0
- package/dist/server-shell/http/routes/agent-context-skills-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/agent-context-skills-routes.js +85 -0
- package/dist/server-shell/http/routes/agent-context-workspace-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/agent-context-workspace-routes.js +130 -0
- package/dist/server-shell/http/routes/agent-context.d.ts +8 -0
- package/dist/server-shell/http/routes/agent-context.js +16 -0
- package/dist/server-shell/http/routes/health.d.ts +7 -0
- package/dist/server-shell/http/routes/health.js +41 -0
- package/dist/server-shell/http/routes/local-control.d.ts +40 -0
- package/dist/server-shell/http/routes/local-control.js +260 -0
- package/dist/server-shell/http/routes/project-api/approval-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/project-api/approval-routes.js +64 -0
- package/dist/server-shell/http/routes/project-api/artifacts-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/artifacts-routes.js +166 -0
- package/dist/server-shell/http/routes/project-api/clarification-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/project-api/clarification-routes.js +150 -0
- package/dist/server-shell/http/routes/project-api/constants.d.ts +3 -0
- package/dist/server-shell/http/routes/project-api/constants.js +3 -0
- package/dist/server-shell/http/routes/project-api/errors.d.ts +26 -0
- package/dist/server-shell/http/routes/project-api/errors.js +41 -0
- package/dist/server-shell/http/routes/project-api/events-stream.d.ts +11 -0
- package/dist/server-shell/http/routes/project-api/events-stream.js +55 -0
- package/dist/server-shell/http/routes/project-api/execution-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/project-api/execution-routes.js +92 -0
- package/dist/server-shell/http/routes/project-api/headers.d.ts +2 -0
- package/dist/server-shell/http/routes/project-api/headers.js +7 -0
- package/dist/server-shell/http/routes/project-api/invalidations.d.ts +10 -0
- package/dist/server-shell/http/routes/project-api/invalidations.js +57 -0
- package/dist/server-shell/http/routes/project-api/messages-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/messages-routes.js +80 -0
- package/dist/server-shell/http/routes/project-api/openapi-approval-routes.d.ts +128 -0
- package/dist/server-shell/http/routes/project-api/openapi-approval-routes.js +32 -0
- package/dist/server-shell/http/routes/project-api/openapi-artifacts-routes.d.ts +51 -0
- package/dist/server-shell/http/routes/project-api/openapi-artifacts-routes.js +56 -0
- package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.d.ts +466 -0
- package/dist/server-shell/http/routes/project-api/openapi-collaboration-routes.js +165 -0
- package/dist/server-shell/http/routes/project-api/openapi-diagnostic-routes.d.ts +16 -0
- package/dist/server-shell/http/routes/project-api/openapi-diagnostic-routes.js +17 -0
- package/dist/server-shell/http/routes/project-api/openapi-execution-routes.d.ts +215 -0
- package/dist/server-shell/http/routes/project-api/openapi-execution-routes.js +75 -0
- package/dist/server-shell/http/routes/project-api/openapi-path-parameters.d.ts +9 -0
- package/dist/server-shell/http/routes/project-api/openapi-path-parameters.js +18 -0
- package/dist/server-shell/http/routes/project-api/openapi-skills-routes.d.ts +60 -0
- package/dist/server-shell/http/routes/project-api/openapi-skills-routes.js +51 -0
- package/dist/server-shell/http/routes/project-api/openapi-timeline-routes.d.ts +115 -0
- package/dist/server-shell/http/routes/project-api/openapi-timeline-routes.js +17 -0
- package/dist/server-shell/http/routes/project-api/openapi-viewer-routes.d.ts +323 -0
- package/dist/server-shell/http/routes/project-api/openapi-viewer-routes.js +120 -0
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.d.ts +1317 -0
- package/dist/server-shell/http/routes/project-api/openapi-workspace-routes.js +95 -0
- package/dist/server-shell/http/routes/project-api/openapi.d.ts +2457 -0
- package/dist/server-shell/http/routes/project-api/openapi.js +30 -0
- package/dist/server-shell/http/routes/project-api/payload-validation.d.ts +6 -0
- package/dist/server-shell/http/routes/project-api/payload-validation.js +36 -0
- package/dist/server-shell/http/routes/project-api/project-docs-helpers.d.ts +9 -0
- package/dist/server-shell/http/routes/project-api/project-docs-helpers.js +17 -0
- package/dist/server-shell/http/routes/project-api/project-docs-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/project-docs-routes.js +151 -0
- package/dist/server-shell/http/routes/project-api/project-timeline-projection.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/project-timeline-projection.js +658 -0
- package/dist/server-shell/http/routes/project-api/project-timeline-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/project-api/project-timeline-routes.js +23 -0
- package/dist/server-shell/http/routes/project-api/read-state-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/read-state-routes.js +82 -0
- package/dist/server-shell/http/routes/project-api/reference-files-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/reference-files-routes.js +184 -0
- package/dist/server-shell/http/routes/project-api/reference-files.d.ts +17 -0
- package/dist/server-shell/http/routes/project-api/reference-files.js +212 -0
- package/dist/server-shell/http/routes/project-api/repo-projection.d.ts +3 -0
- package/dist/server-shell/http/routes/project-api/repo-projection.js +58 -0
- package/dist/server-shell/http/routes/project-api/schemas.d.ts +1351 -0
- package/dist/server-shell/http/routes/project-api/schemas.js +441 -0
- package/dist/server-shell/http/routes/project-api/session-requirements.d.ts +10 -0
- package/dist/server-shell/http/routes/project-api/session-requirements.js +60 -0
- package/dist/server-shell/http/routes/project-api/skills-helpers.d.ts +7 -0
- package/dist/server-shell/http/routes/project-api/skills-helpers.js +48 -0
- package/dist/server-shell/http/routes/project-api/skills-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/skills-routes.js +185 -0
- package/dist/server-shell/http/routes/project-api/staged-uploads.d.ts +14 -0
- package/dist/server-shell/http/routes/project-api/staged-uploads.js +149 -0
- package/dist/server-shell/http/routes/project-api/system-routes.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api/system-routes.js +141 -0
- package/dist/server-shell/http/routes/project-api/types.d.ts +137 -0
- package/dist/server-shell/http/routes/project-api/types.js +2 -0
- package/dist/server-shell/http/routes/project-api/viewer-projections.d.ts +17 -0
- package/dist/server-shell/http/routes/project-api/viewer-projections.js +102 -0
- package/dist/server-shell/http/routes/project-api/viewer-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/project-api/viewer-routes.js +100 -0
- package/dist/server-shell/http/routes/project-api/workflow-routes.d.ts +4 -0
- package/dist/server-shell/http/routes/project-api/workflow-routes.js +85 -0
- package/dist/server-shell/http/routes/project-api/workspace-projections.d.ts +5 -0
- package/dist/server-shell/http/routes/project-api/workspace-projections.js +103 -0
- package/dist/server-shell/http/routes/project-api.d.ts +8 -0
- package/dist/server-shell/http/routes/project-api.js +34 -0
- package/dist/server-shell/http/sse-replay-buffer.d.ts +54 -0
- package/dist/server-shell/http/sse-replay-buffer.js +110 -0
- package/dist/server-shell/http/sse.d.ts +12 -0
- package/dist/server-shell/http/sse.js +22 -0
- package/dist/server-shell/http/static-web.d.ts +6 -0
- package/dist/server-shell/http/static-web.js +52 -0
- package/dist/server-shell/http/validation.d.ts +13 -0
- package/dist/server-shell/http/validation.js +136 -0
- package/dist/server-shell/http/workspace-events.d.ts +38 -0
- package/dist/server-shell/http/workspace-events.js +98 -0
- package/dist/server-shell/session/relay-session-context.d.ts +25 -0
- package/dist/server-shell/session/relay-session-context.js +49 -0
- package/dist/server-shell/smoke/e2e-client.d.ts +59 -0
- package/dist/server-shell/smoke/e2e-client.js +304 -0
- package/dist/server-shell/smoke/index.d.ts +2 -0
- package/dist/server-shell/smoke/index.js +2 -0
- package/dist/skills/constants.d.ts +8 -0
- package/dist/skills/constants.js +9 -0
- package/dist/skills/errors.d.ts +6 -0
- package/dist/skills/errors.js +9 -0
- package/dist/skills/index.d.ts +41 -0
- package/dist/skills/index.js +171 -0
- package/dist/skills/metadata.d.ts +8 -0
- package/dist/skills/metadata.js +80 -0
- package/dist/skills/zip-import.d.ts +18 -0
- package/dist/skills/zip-import.js +241 -0
- package/dist/store/command-recovery.d.ts +26 -0
- package/dist/store/command-recovery.js +71 -0
- package/dist/store/index.d.ts +6 -0
- package/dist/store/index.js +6 -0
- package/dist/store/lifecycle.d.ts +23 -0
- package/dist/store/lifecycle.js +53 -0
- package/dist/store/metadata.d.ts +18 -0
- package/dist/store/metadata.js +30 -0
- package/dist/store/migrations.d.ts +20 -0
- package/dist/store/migrations.js +76 -0
- package/dist/store/sqlite.d.ts +11 -0
- package/dist/store/sqlite.js +21 -0
- package/dist/workspace-ops/constants.d.ts +15 -0
- package/dist/workspace-ops/constants.js +20 -0
- package/dist/workspace-ops/errors.d.ts +8 -0
- package/dist/workspace-ops/errors.js +33 -0
- package/dist/workspace-ops/git.d.ts +13 -0
- package/dist/workspace-ops/git.js +53 -0
- package/dist/workspace-ops/index.d.ts +11 -0
- package/dist/workspace-ops/index.js +9 -0
- package/dist/workspace-ops/mainline.d.ts +2 -0
- package/dist/workspace-ops/mainline.js +16 -0
- package/dist/workspace-ops/project-doc-templates.d.ts +12 -0
- package/dist/workspace-ops/project-doc-templates.js +180 -0
- package/dist/workspace-ops/project-docs.d.ts +7 -0
- package/dist/workspace-ops/project-docs.js +156 -0
- package/dist/workspace-ops/reference-files.d.ts +3 -0
- package/dist/workspace-ops/reference-files.js +137 -0
- package/dist/workspace-ops/reference-metadata.d.ts +13 -0
- package/dist/workspace-ops/reference-metadata.js +86 -0
- package/dist/workspace-ops/reference-summaries.d.ts +17 -0
- package/dist/workspace-ops/reference-summaries.js +298 -0
- package/dist/workspace-ops/run-workspaces.d.ts +18 -0
- package/dist/workspace-ops/run-workspaces.js +271 -0
- package/dist/workspace-ops/types.d.ts +219 -0
- package/dist/workspace-ops/types.js +2 -0
- package/dist/workspace-ops/viewer-file.d.ts +4 -0
- package/dist/workspace-ops/viewer-file.js +207 -0
- package/dist/workspace-ops/viewer-git.d.ts +20 -0
- package/dist/workspace-ops/viewer-git.js +111 -0
- package/dist/workspace-ops/viewer-paths.d.ts +3 -0
- package/dist/workspace-ops/viewer-paths.js +13 -0
- package/dist/workspace-ops/viewer-tree.d.ts +9 -0
- package/dist/workspace-ops/viewer-tree.js +144 -0
- package/dist/workspace-ops/viewer.d.ts +5 -0
- package/dist/workspace-ops/viewer.js +5 -0
- package/migrations/0001_init.sql +674 -0
- package/migrations/0002_allow_sealed_round_successor_note.sql +14 -0
- package/migrations/0003_drop_scratchpad_source_message_refs.sql +1 -0
- package/migrations/0004_read_state.sql +109 -0
- package/migrations/0005_provider_usage.sql +15 -0
- package/migrations/0006_scratchpad_source_state.sql +29 -0
- package/migrations/0007_workspace_signal_read_state_scopes.sql +74 -0
- package/migrations/0008_provider_usage_anchors.sql +32 -0
- package/migrations/0009_project_timeline_events.sql +33 -0
- package/migrations/0010_project_brief.sql +13 -0
- package/migrations/0011_message_author_avatar.sql +5 -0
- package/migrations/README.md +44 -0
- package/node_modules/@tutti/relay-client/dist/host-control.d.ts +164 -0
- package/node_modules/@tutti/relay-client/dist/host-control.js +284 -0
- package/node_modules/@tutti/relay-client/dist/index.d.ts +3 -0
- package/node_modules/@tutti/relay-client/dist/index.js +3 -0
- package/node_modules/@tutti/relay-client/dist/tunnel-frames.d.ts +8 -0
- package/node_modules/@tutti/relay-client/dist/tunnel-frames.js +124 -0
- package/node_modules/@tutti/relay-client/dist/tunnel-types.d.ts +61 -0
- package/node_modules/@tutti/relay-client/dist/tunnel-types.js +2 -0
- package/node_modules/@tutti/relay-client/dist/tunnel.d.ts +4 -0
- package/node_modules/@tutti/relay-client/dist/tunnel.js +144 -0
- package/node_modules/@tutti/relay-client/package.json +18 -0
- package/node_modules/@tutti/shared/dist/domain/index.d.ts +59 -0
- package/node_modules/@tutti/shared/dist/domain/index.js +37 -0
- package/node_modules/@tutti/shared/dist/ids/index.d.ts +85 -0
- package/node_modules/@tutti/shared/dist/ids/index.js +88 -0
- package/node_modules/@tutti/shared/dist/index.d.ts +6 -0
- package/node_modules/@tutti/shared/dist/index.js +6 -0
- package/node_modules/@tutti/shared/dist/schemas/api/approvals.d.ts +307 -0
- package/node_modules/@tutti/shared/dist/schemas/api/approvals.js +110 -0
- package/node_modules/@tutti/shared/dist/schemas/api/artifacts.d.ts +173 -0
- package/node_modules/@tutti/shared/dist/schemas/api/artifacts.js +107 -0
- package/node_modules/@tutti/shared/dist/schemas/api/clarifications.d.ts +704 -0
- package/node_modules/@tutti/shared/dist/schemas/api/clarifications.js +224 -0
- package/node_modules/@tutti/shared/dist/schemas/api/index.d.ts +18 -0
- package/node_modules/@tutti/shared/dist/schemas/api/index.js +17 -0
- package/node_modules/@tutti/shared/dist/schemas/api/messages.d.ts +370 -0
- package/node_modules/@tutti/shared/dist/schemas/api/messages.js +134 -0
- package/node_modules/@tutti/shared/dist/schemas/api/openapi.d.ts +32 -0
- package/node_modules/@tutti/shared/dist/schemas/api/openapi.js +100 -0
- package/node_modules/@tutti/shared/dist/schemas/api/primitives.d.ts +109 -0
- package/node_modules/@tutti/shared/dist/schemas/api/primitives.js +174 -0
- package/node_modules/@tutti/shared/dist/schemas/api/project-timeline.d.ts +149 -0
- package/node_modules/@tutti/shared/dist/schemas/api/project-timeline.js +44 -0
- package/node_modules/@tutti/shared/dist/schemas/api/provider-config.d.ts +21 -0
- package/node_modules/@tutti/shared/dist/schemas/api/provider-config.js +33 -0
- package/node_modules/@tutti/shared/dist/schemas/api/provider-usage.d.ts +87 -0
- package/node_modules/@tutti/shared/dist/schemas/api/provider-usage.js +48 -0
- package/node_modules/@tutti/shared/dist/schemas/api/read-state.d.ts +89 -0
- package/node_modules/@tutti/shared/dist/schemas/api/read-state.js +39 -0
- package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.d.ts +484 -0
- package/node_modules/@tutti/shared/dist/schemas/api/runtime-events.js +185 -0
- package/node_modules/@tutti/shared/dist/schemas/api/skills.d.ts +88 -0
- package/node_modules/@tutti/shared/dist/schemas/api/skills.js +71 -0
- package/node_modules/@tutti/shared/dist/schemas/api/types.d.ts +253 -0
- package/node_modules/@tutti/shared/dist/schemas/api/types.js +2 -0
- package/node_modules/@tutti/shared/dist/schemas/api/uploads.d.ts +103 -0
- package/node_modules/@tutti/shared/dist/schemas/api/uploads.js +78 -0
- package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.d.ts +484 -0
- package/node_modules/@tutti/shared/dist/schemas/api/viewer-reference.js +267 -0
- package/node_modules/@tutti/shared/dist/schemas/api/work-items.d.ts +264 -0
- package/node_modules/@tutti/shared/dist/schemas/api/work-items.js +196 -0
- package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.d.ts +179 -0
- package/node_modules/@tutti/shared/dist/schemas/api/workspace-commands.js +137 -0
- package/node_modules/@tutti/shared/dist/schemas/domain/index.d.ts +31 -0
- package/node_modules/@tutti/shared/dist/schemas/domain/index.js +49 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.d.ts +46 -0
- package/node_modules/@tutti/shared/dist/schemas/internal/index.js +46 -0
- package/node_modules/@tutti/shared/dist/utils/command-idempotency/index.d.ts +40 -0
- package/node_modules/@tutti/shared/dist/utils/command-idempotency/index.js +100 -0
- package/node_modules/@tutti/shared/dist/utils/index.d.ts +5 -0
- package/node_modules/@tutti/shared/dist/utils/index.js +5 -0
- package/node_modules/@tutti/shared/dist/utils/logging/index.d.ts +34 -0
- package/node_modules/@tutti/shared/dist/utils/logging/index.js +130 -0
- package/node_modules/@tutti/shared/dist/utils/path-policy/index.d.ts +13 -0
- package/node_modules/@tutti/shared/dist/utils/path-policy/index.js +80 -0
- package/node_modules/@tutti/shared/dist/utils/redaction/index.d.ts +19 -0
- package/node_modules/@tutti/shared/dist/utils/redaction/index.js +158 -0
- package/node_modules/@tutti/shared/package.json +63 -0
- package/package.json +47 -0
- package/prompts/README.md +36 -0
- package/prompts/chat-assistant.md +43 -0
- package/prompts/codex/README.md +13 -0
- package/prompts/codex/no-write-smoke.md +35 -0
- package/prompts/procedures/README.md +38 -0
- package/prompts/procedures/context-sync.md +66 -0
- package/prompts/procedures/follow-up-check.md +83 -0
- package/prompts/procedures/project-brief-refresh.md +79 -0
- package/prompts/procedures/project-context-bootstrap.md +58 -0
- package/prompts/procedures/reference-file-summary.md +49 -0
- package/prompts/procedures/scratchpad-refresh.md +83 -0
- package/prompts/procedures/task-compile.md +116 -0
- package/prompts/prompt-flow-experiment-plan.md +203 -0
- package/prompts/prompt-flow-map.md +478 -0
- package/prompts/runs/README.md +17 -0
- package/prompts/runs/task-continuation.md +148 -0
- package/prompts/runs/task-retry.md +153 -0
- package/prompts/runs/task-run.md +135 -0
- package/prompts/skills/README.md +25 -0
- package/prompts/skills/read-main-chat/README.md +8 -0
- package/prompts/skills/read-main-chat/SKILL.md +18 -0
- package/prompts/skills/read-project-docs/README.md +13 -0
- package/prompts/skills/read-project-docs/SKILL.md +42 -0
- package/prompts/skills/read-references/README.md +9 -0
- package/prompts/skills/read-references/SKILL.md +26 -0
- package/prompts/skills/read-scratchpad/README.md +8 -0
- package/prompts/skills/read-scratchpad/SKILL.md +16 -0
- package/prompts/skills/read-user-skills/README.md +7 -0
- package/prompts/skills/read-user-skills/SKILL.md +22 -0
- package/prompts/skills/read-worklist/README.md +9 -0
- package/prompts/skills/read-worklist/SKILL.md +20 -0
- package/web/assets/Tutti-B7gEyTp1.png +0 -0
- package/web/assets/Tutti-square-BqFU7F0D.png +0 -0
- package/web/assets/index-CWkBgHap.js +29 -0
- package/web/assets/index-D8xJY8Gr.css +1 -0
- package/web/index.html +13 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { ID_PREFIXES, isPrefixedId } from "@tutti/shared/ids";
|
|
5
|
+
import { LaunchError } from "./errors.js";
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function ensurePrivateDirectory(directoryPath) {
|
|
10
|
+
mkdirSync(directoryPath, { recursive: true, mode: 0o700 });
|
|
11
|
+
chmodSync(directoryPath, 0o700);
|
|
12
|
+
}
|
|
13
|
+
function writePrivateJsonFile(filePath, value) {
|
|
14
|
+
ensurePrivateDirectory(dirname(filePath));
|
|
15
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
16
|
+
writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, {
|
|
17
|
+
encoding: "utf8",
|
|
18
|
+
mode: 0o600,
|
|
19
|
+
});
|
|
20
|
+
chmodSync(tempPath, 0o600);
|
|
21
|
+
renameSync(tempPath, filePath);
|
|
22
|
+
chmodSync(filePath, 0o600);
|
|
23
|
+
}
|
|
24
|
+
function readJsonFile(filePath) {
|
|
25
|
+
if (!existsSync(filePath)) {
|
|
26
|
+
return { kind: "missing" };
|
|
27
|
+
}
|
|
28
|
+
return { kind: "loaded", value: JSON.parse(readFileSync(filePath, "utf8")) };
|
|
29
|
+
}
|
|
30
|
+
export function getProjectLocalStoreRoot(tuttiHome, projectId) {
|
|
31
|
+
return join(tuttiHome, "projects", projectId);
|
|
32
|
+
}
|
|
33
|
+
export function getMachineProjectBindingPath(tuttiHome, projectId) {
|
|
34
|
+
return join(getProjectLocalStoreRoot(tuttiHome, projectId), "binding.json");
|
|
35
|
+
}
|
|
36
|
+
export function getMachineRuntimeEndpointPath(tuttiHome, projectId) {
|
|
37
|
+
return join(getProjectLocalStoreRoot(tuttiHome, projectId), "runtime", "endpoint.json");
|
|
38
|
+
}
|
|
39
|
+
export function createHostRegistrationSecretRef(projectId) {
|
|
40
|
+
return `host_registration:${projectId}`;
|
|
41
|
+
}
|
|
42
|
+
export function getHostRegistrationSecretPath(tuttiHome, projectId) {
|
|
43
|
+
return join(tuttiHome, "credentials", "host-registration", `${projectId}.json`);
|
|
44
|
+
}
|
|
45
|
+
export function createHostRegistrationSecret() {
|
|
46
|
+
return randomBytes(32).toString("base64url");
|
|
47
|
+
}
|
|
48
|
+
export function createMachineRuntimeEndpointToken() {
|
|
49
|
+
return randomBytes(32).toString("base64url");
|
|
50
|
+
}
|
|
51
|
+
export function readMachineProjectBinding(tuttiHome, projectId) {
|
|
52
|
+
const readResult = readJsonFile(getMachineProjectBindingPath(tuttiHome, projectId));
|
|
53
|
+
if (readResult.kind === "missing") {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const raw = readResult.value;
|
|
57
|
+
if (!isRecord(raw) ||
|
|
58
|
+
raw.project_id !== projectId ||
|
|
59
|
+
typeof raw.workspace_root !== "string" ||
|
|
60
|
+
typeof raw.local_store_root !== "string" ||
|
|
61
|
+
typeof raw.updated_at !== "string" ||
|
|
62
|
+
(raw.relay_project_ref !== undefined &&
|
|
63
|
+
(typeof raw.relay_project_ref !== "string" ||
|
|
64
|
+
!isPrefixedId(raw.relay_project_ref, ID_PREFIXES.relayProject))) ||
|
|
65
|
+
(raw.host_registration_secret_ref !== undefined &&
|
|
66
|
+
typeof raw.host_registration_secret_ref !== "string")) {
|
|
67
|
+
throw new LaunchError("project_identity_conflict", "Machine-local project binding is invalid or conflicts with the Git config project identity", "Inspect or remove the project binding under TUTTI_HOME after confirming it is not needed.");
|
|
68
|
+
}
|
|
69
|
+
const binding = {
|
|
70
|
+
project_id: raw.project_id,
|
|
71
|
+
workspace_root: raw.workspace_root,
|
|
72
|
+
local_store_root: raw.local_store_root,
|
|
73
|
+
updated_at: raw.updated_at,
|
|
74
|
+
};
|
|
75
|
+
if (raw.relay_project_ref !== undefined) {
|
|
76
|
+
binding.relay_project_ref = raw.relay_project_ref;
|
|
77
|
+
}
|
|
78
|
+
if (raw.host_registration_secret_ref !== undefined) {
|
|
79
|
+
binding.host_registration_secret_ref = raw.host_registration_secret_ref;
|
|
80
|
+
}
|
|
81
|
+
return binding;
|
|
82
|
+
}
|
|
83
|
+
export function readMachineRuntimeEndpoint(tuttiHome, projectId) {
|
|
84
|
+
const readResult = readJsonFile(getMachineRuntimeEndpointPath(tuttiHome, projectId));
|
|
85
|
+
if (readResult.kind === "missing") {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const raw = readResult.value;
|
|
89
|
+
if (!isRecord(raw) ||
|
|
90
|
+
raw.project_id !== projectId ||
|
|
91
|
+
typeof raw.pid !== "number" ||
|
|
92
|
+
!Number.isInteger(raw.pid) ||
|
|
93
|
+
typeof raw.base_url !== "string" ||
|
|
94
|
+
typeof raw.token !== "string" ||
|
|
95
|
+
raw.token.trim() === "" ||
|
|
96
|
+
typeof raw.workspace_root !== "string" ||
|
|
97
|
+
typeof raw.updated_at !== "string") {
|
|
98
|
+
throw new LaunchError("existing_server_unhealthy", "Machine-local runtime endpoint is invalid", "Remove the stale runtime endpoint after confirming no host server is running.");
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
project_id: raw.project_id,
|
|
102
|
+
pid: raw.pid,
|
|
103
|
+
base_url: raw.base_url,
|
|
104
|
+
token: raw.token,
|
|
105
|
+
workspace_root: raw.workspace_root,
|
|
106
|
+
updated_at: raw.updated_at,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function writeMachineRuntimeEndpoint(options) {
|
|
110
|
+
const now = (options.now ?? (() => new Date()))().toISOString();
|
|
111
|
+
const token = options.token ?? createMachineRuntimeEndpointToken();
|
|
112
|
+
if (token.trim() === "") {
|
|
113
|
+
throw new LaunchError("existing_server_unhealthy", "Machine-local runtime endpoint token must be non-empty", "Restart the host server so it can write a valid runtime endpoint.");
|
|
114
|
+
}
|
|
115
|
+
const record = {
|
|
116
|
+
project_id: options.projectId,
|
|
117
|
+
pid: options.pid,
|
|
118
|
+
base_url: options.baseUrl,
|
|
119
|
+
token,
|
|
120
|
+
workspace_root: resolve(options.workspaceRoot),
|
|
121
|
+
updated_at: now,
|
|
122
|
+
};
|
|
123
|
+
writePrivateJsonFile(getMachineRuntimeEndpointPath(options.tuttiHome, options.projectId), record);
|
|
124
|
+
return record;
|
|
125
|
+
}
|
|
126
|
+
export function deleteMachineRuntimeEndpoint(options) {
|
|
127
|
+
const endpointPath = getMachineRuntimeEndpointPath(options.tuttiHome, options.projectId);
|
|
128
|
+
if (!existsSync(endpointPath)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (options.expectedToken !== undefined) {
|
|
132
|
+
const existing = readMachineRuntimeEndpoint(options.tuttiHome, options.projectId);
|
|
133
|
+
if (existing?.token !== options.expectedToken) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
unlinkSync(endpointPath);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
export function readHostRegistrationSecret(tuttiHome, projectId) {
|
|
141
|
+
const readResult = readJsonFile(getHostRegistrationSecretPath(tuttiHome, projectId));
|
|
142
|
+
if (readResult.kind === "missing") {
|
|
143
|
+
throw new LaunchError("relay_registration_failed", "Host registration secret is missing from the machine-local credential store", "Run `tutti launch` again so Tutti can recreate the host registration credential.");
|
|
144
|
+
}
|
|
145
|
+
const raw = readResult.value;
|
|
146
|
+
if (!isRecord(raw) ||
|
|
147
|
+
raw.kind !== "host_registration_secret_v1" ||
|
|
148
|
+
raw.project_id !== projectId ||
|
|
149
|
+
typeof raw.secret !== "string" ||
|
|
150
|
+
raw.secret.trim() === "" ||
|
|
151
|
+
typeof raw.created_at !== "string" ||
|
|
152
|
+
typeof raw.updated_at !== "string") {
|
|
153
|
+
throw new LaunchError("relay_registration_failed", "Host registration secret file is invalid", "Remove the invalid host registration credential only after confirming this host should be re-registered.");
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
kind: "host_registration_secret_v1",
|
|
157
|
+
project_id: raw.project_id,
|
|
158
|
+
secret: raw.secret,
|
|
159
|
+
created_at: raw.created_at,
|
|
160
|
+
updated_at: raw.updated_at,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
export function updateMachineProjectRelayBinding(options) {
|
|
164
|
+
const existing = readMachineProjectBinding(options.tuttiHome, options.projectId);
|
|
165
|
+
if (existing === null) {
|
|
166
|
+
throw new LaunchError("relay_registration_failed", "Machine-local project binding is missing after Relay registration", "Run `tutti launch` again from the project workspace.");
|
|
167
|
+
}
|
|
168
|
+
const binding = {
|
|
169
|
+
...existing,
|
|
170
|
+
relay_project_ref: options.relayProjectRef,
|
|
171
|
+
updated_at: (options.now ?? (() => new Date()))().toISOString(),
|
|
172
|
+
};
|
|
173
|
+
writePrivateJsonFile(getMachineProjectBindingPath(options.tuttiHome, options.projectId), binding);
|
|
174
|
+
return binding;
|
|
175
|
+
}
|
|
176
|
+
function ensureHostRegistrationSecret(tuttiHome, projectId, now) {
|
|
177
|
+
const secretPath = getHostRegistrationSecretPath(tuttiHome, projectId);
|
|
178
|
+
const ref = createHostRegistrationSecretRef(projectId);
|
|
179
|
+
if (existsSync(secretPath)) {
|
|
180
|
+
return { ref, created: false };
|
|
181
|
+
}
|
|
182
|
+
const timestamp = now().toISOString();
|
|
183
|
+
const secretFile = {
|
|
184
|
+
kind: "host_registration_secret_v1",
|
|
185
|
+
project_id: projectId,
|
|
186
|
+
secret: createHostRegistrationSecret(),
|
|
187
|
+
created_at: timestamp,
|
|
188
|
+
updated_at: timestamp,
|
|
189
|
+
};
|
|
190
|
+
writePrivateJsonFile(secretPath, secretFile);
|
|
191
|
+
return { ref, created: true };
|
|
192
|
+
}
|
|
193
|
+
export function ensureMachineProjectBinding(options) {
|
|
194
|
+
const now = options.now ?? (() => new Date());
|
|
195
|
+
const workspaceRoot = resolve(options.workspaceRoot);
|
|
196
|
+
const localStoreRoot = getProjectLocalStoreRoot(options.tuttiHome, options.projectId);
|
|
197
|
+
const bindingPath = getMachineProjectBindingPath(options.tuttiHome, options.projectId);
|
|
198
|
+
const secret = ensureHostRegistrationSecret(options.tuttiHome, options.projectId, now);
|
|
199
|
+
const existing = readMachineProjectBinding(options.tuttiHome, options.projectId);
|
|
200
|
+
if (existing !== null &&
|
|
201
|
+
resolve(existing.workspace_root) !== workspaceRoot &&
|
|
202
|
+
options.allowWorkspaceRootTakeover !== true) {
|
|
203
|
+
throw new LaunchError("project_identity_conflict", "This project is already bound to a different workspace root on this machine", "Use the future takeover flow, or remove the stale binding only after verifying no host server is running.");
|
|
204
|
+
}
|
|
205
|
+
const binding = {
|
|
206
|
+
project_id: options.projectId,
|
|
207
|
+
workspace_root: workspaceRoot,
|
|
208
|
+
local_store_root: localStoreRoot,
|
|
209
|
+
host_registration_secret_ref: existing?.host_registration_secret_ref ?? secret.ref,
|
|
210
|
+
updated_at: now().toISOString(),
|
|
211
|
+
};
|
|
212
|
+
if (existing?.relay_project_ref !== undefined) {
|
|
213
|
+
binding.relay_project_ref = existing.relay_project_ref;
|
|
214
|
+
}
|
|
215
|
+
writePrivateJsonFile(bindingPath, binding);
|
|
216
|
+
return {
|
|
217
|
+
binding,
|
|
218
|
+
binding_path: bindingPath,
|
|
219
|
+
host_registration_secret_ref: binding.host_registration_secret_ref ?? secret.ref,
|
|
220
|
+
host_registration_secret_created: secret.created,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=machine-local.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ProjectId } from "@tutti/shared/ids";
|
|
2
|
+
export declare const PROJECT_ID_GIT_CONFIG_KEY = "tutti.project-id";
|
|
3
|
+
export declare const PROJECT_DISPLAY_NAME_GIT_CONFIG_KEY = "tutti.project-display-name";
|
|
4
|
+
export type ProjectIdentityReadResult = {
|
|
5
|
+
kind: "missing";
|
|
6
|
+
} | {
|
|
7
|
+
kind: "present";
|
|
8
|
+
project_id: ProjectId;
|
|
9
|
+
source: "git_config";
|
|
10
|
+
};
|
|
11
|
+
export declare function readProjectIdentity(workspaceRoot: string): ProjectIdentityReadResult;
|
|
12
|
+
export declare function writeProjectIdentity(workspaceRoot: string, projectId: ProjectId): void;
|
|
13
|
+
export declare function readProjectDisplayName(workspaceRoot: string): string | null;
|
|
14
|
+
export declare function writeProjectDisplayName(workspaceRoot: string, displayName: string): void;
|
|
15
|
+
export declare function ensureProjectIdentity(workspaceRoot: string, projectId?: ProjectId): {
|
|
16
|
+
project_id: ProjectId;
|
|
17
|
+
created: boolean;
|
|
18
|
+
source: "git_config";
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=project-identity.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { createProjectId, ID_PREFIXES, isPrefixedId } from "@tutti/shared/ids";
|
|
5
|
+
import { LaunchError } from "./errors.js";
|
|
6
|
+
export const PROJECT_ID_GIT_CONFIG_KEY = "tutti.project-id";
|
|
7
|
+
export const PROJECT_DISPLAY_NAME_GIT_CONFIG_KEY = "tutti.project-display-name";
|
|
8
|
+
function runGitRaw(args, cwd) {
|
|
9
|
+
const result = spawnSync("git", [...args], {
|
|
10
|
+
cwd,
|
|
11
|
+
encoding: "utf8",
|
|
12
|
+
shell: false,
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
status: result.status,
|
|
16
|
+
stdout: result.stdout ?? "",
|
|
17
|
+
stderr: result.stderr ?? "",
|
|
18
|
+
...(result.error === undefined ? {} : { error: result.error }),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function runGit(args, cwd) {
|
|
22
|
+
const result = runGitRaw(args, cwd);
|
|
23
|
+
if (result.status !== 0) {
|
|
24
|
+
const stderr = result.stderr.trim();
|
|
25
|
+
throw new LaunchError("git_bootstrap_failed", stderr.length > 0 ? stderr : `git ${args.join(" ")} failed`, "Resolve the Git error and run `tutti launch` again.");
|
|
26
|
+
}
|
|
27
|
+
return result.stdout.trim();
|
|
28
|
+
}
|
|
29
|
+
function readGitTopLevel(workspaceRoot) {
|
|
30
|
+
const result = runGitRaw(["rev-parse", "--show-toplevel"], workspaceRoot);
|
|
31
|
+
if (result.status !== 0) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return resolve(result.stdout.trim());
|
|
35
|
+
}
|
|
36
|
+
function resolvePhysicalPath(path) {
|
|
37
|
+
try {
|
|
38
|
+
return realpathSync(path);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return resolve(path);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function readProjectIdentity(workspaceRoot) {
|
|
45
|
+
const resolvedWorkspaceRoot = resolve(workspaceRoot);
|
|
46
|
+
const gitTopLevel = readGitTopLevel(resolvedWorkspaceRoot);
|
|
47
|
+
if (gitTopLevel === null ||
|
|
48
|
+
resolvePhysicalPath(gitTopLevel) !== resolvePhysicalPath(resolvedWorkspaceRoot)) {
|
|
49
|
+
return { kind: "missing" };
|
|
50
|
+
}
|
|
51
|
+
const result = runGitRaw(["config", "--local", "--get", PROJECT_ID_GIT_CONFIG_KEY], resolvedWorkspaceRoot);
|
|
52
|
+
if (result.status !== 0) {
|
|
53
|
+
return { kind: "missing" };
|
|
54
|
+
}
|
|
55
|
+
const projectId = result.stdout.trim();
|
|
56
|
+
if (!isPrefixedId(projectId, ID_PREFIXES.project)) {
|
|
57
|
+
throw new LaunchError("unsupported_tutti_schema", "`tutti.project-id` must be a prj_<ULID> opaque id", "Fix the local Git config project identity before launching.");
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
kind: "present",
|
|
61
|
+
project_id: projectId,
|
|
62
|
+
source: "git_config",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function writeProjectIdentity(workspaceRoot, projectId) {
|
|
66
|
+
runGit(["config", "--local", PROJECT_ID_GIT_CONFIG_KEY, projectId], resolve(workspaceRoot));
|
|
67
|
+
}
|
|
68
|
+
export function readProjectDisplayName(workspaceRoot) {
|
|
69
|
+
const result = runGitRaw(["config", "--local", "--get", PROJECT_DISPLAY_NAME_GIT_CONFIG_KEY], resolve(workspaceRoot));
|
|
70
|
+
if (result.status !== 0) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const displayName = result.stdout.trim();
|
|
74
|
+
return displayName.length === 0 ? null : displayName;
|
|
75
|
+
}
|
|
76
|
+
export function writeProjectDisplayName(workspaceRoot, displayName) {
|
|
77
|
+
runGit(["config", "--local", PROJECT_DISPLAY_NAME_GIT_CONFIG_KEY, displayName], resolve(workspaceRoot));
|
|
78
|
+
}
|
|
79
|
+
export function ensureProjectIdentity(workspaceRoot, projectId = createProjectId()) {
|
|
80
|
+
const existing = readProjectIdentity(workspaceRoot);
|
|
81
|
+
if (existing.kind === "present") {
|
|
82
|
+
return { project_id: existing.project_id, created: false, source: existing.source };
|
|
83
|
+
}
|
|
84
|
+
writeProjectIdentity(workspaceRoot, projectId);
|
|
85
|
+
return { project_id: projectId, created: true, source: "git_config" };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=project-identity.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ConnectRelayHostTunnelOptions, type RelayHostTunnelHandle, type RegisterRelayHostConnectionOptions, type RegisterRelayHostConnectionResponse } from "@tutti/relay-client";
|
|
2
|
+
import type { HostConnectionRef, RelayProjectRef } from "@tutti/shared/ids";
|
|
3
|
+
import { LaunchError } from "./errors.js";
|
|
4
|
+
import type { LaunchPreparationResult } from "./launch.js";
|
|
5
|
+
type FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>;
|
|
6
|
+
export type HostLaunchRelaySummary = {
|
|
7
|
+
relay_project_ref: RelayProjectRef;
|
|
8
|
+
host_connection_ref: HostConnectionRef;
|
|
9
|
+
join_url?: string;
|
|
10
|
+
join_url_visibility: "visible_once" | "not_recoverable";
|
|
11
|
+
join_token_expires_at?: string;
|
|
12
|
+
join_token_reusable: boolean;
|
|
13
|
+
tunnel_url: string;
|
|
14
|
+
connected_at: string;
|
|
15
|
+
};
|
|
16
|
+
export type RelayHostConnectionRegistrar = (options: RegisterRelayHostConnectionOptions) => Promise<RegisterRelayHostConnectionResponse>;
|
|
17
|
+
export type RelayHostTunnelConnector = (options: ConnectRelayHostTunnelOptions) => RelayHostTunnelHandle;
|
|
18
|
+
export type RegisteredRelayHostConnection = {
|
|
19
|
+
summary: HostLaunchRelaySummary;
|
|
20
|
+
hostConnectionToken: string;
|
|
21
|
+
};
|
|
22
|
+
export declare function relayErrorToLaunchError(error: unknown, relayUrl: string): LaunchError;
|
|
23
|
+
export declare function registerHostWithRelay(options: {
|
|
24
|
+
preparation: LaunchPreparationResult;
|
|
25
|
+
fetchImpl: FetchLike;
|
|
26
|
+
registerRelayHostConnection: RelayHostConnectionRegistrar;
|
|
27
|
+
serverVersion: string;
|
|
28
|
+
now?: () => Date;
|
|
29
|
+
}): Promise<RegisteredRelayHostConnection>;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=relay-registration.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { RelayHostControlClientError, } from "@tutti/relay-client";
|
|
3
|
+
import { readHostRegistrationSecret, updateMachineProjectRelayBinding } from "./machine-local.js";
|
|
4
|
+
import { LaunchError } from "./errors.js";
|
|
5
|
+
import { readProjectDisplayName } from "./project-identity.js";
|
|
6
|
+
export function relayErrorToLaunchError(error, relayUrl) {
|
|
7
|
+
if (error instanceof LaunchError) {
|
|
8
|
+
return error;
|
|
9
|
+
}
|
|
10
|
+
if (error instanceof RelayHostControlClientError) {
|
|
11
|
+
if (error.code === "relay_unavailable") {
|
|
12
|
+
return new LaunchError("relay_unavailable", `Cannot register host connection because Relay is unavailable at ${relayUrl}`, "Keep the project host stopped, start or fix Relay, then run `tutti launch` again.");
|
|
13
|
+
}
|
|
14
|
+
return new LaunchError("relay_registration_failed", `Relay rejected host registration${error.relayErrorCode === undefined ? "" : ` (${error.relayErrorCode})`}`, error.retryable
|
|
15
|
+
? "Retry after Relay recovers, or run `tutti launch` again with a new registration command."
|
|
16
|
+
: "Check Relay host-control registration state and this machine's host registration credential.");
|
|
17
|
+
}
|
|
18
|
+
return new LaunchError("relay_registration_failed", "Relay host registration failed before a join URL could be created", "Retry `tutti launch`; if it keeps failing, inspect Relay host-control logs.");
|
|
19
|
+
}
|
|
20
|
+
export async function registerHostWithRelay(options) {
|
|
21
|
+
const hostSecret = readHostRegistrationSecret(options.preparation.tutti_home, options.preparation.project_id);
|
|
22
|
+
const registrationOptions = {
|
|
23
|
+
relayUrl: options.preparation.relay_url,
|
|
24
|
+
projectId: options.preparation.project_id,
|
|
25
|
+
hostRegistrationSecret: hostSecret.secret,
|
|
26
|
+
displayName: readProjectDisplayName(options.preparation.workspace_root) ??
|
|
27
|
+
(basename(options.preparation.workspace_root) || options.preparation.project_id),
|
|
28
|
+
serverVersion: options.serverVersion,
|
|
29
|
+
joinToken: { mode: "rotate" },
|
|
30
|
+
fetch: options.fetchImpl,
|
|
31
|
+
...(options.now === undefined ? {} : { issuedAt: options.now() }),
|
|
32
|
+
};
|
|
33
|
+
const response = await options.registerRelayHostConnection(registrationOptions);
|
|
34
|
+
if (response.disposition.kind !== "registered" || response.result === undefined) {
|
|
35
|
+
throw new LaunchError("relay_registration_failed", "Relay host registration did not complete", "Retry `tutti launch` with a new registration command.");
|
|
36
|
+
}
|
|
37
|
+
const result = response.result;
|
|
38
|
+
if (result.join_token.visibility !== "visible_once" || result.join_token.join_url === undefined) {
|
|
39
|
+
throw new LaunchError("relay_registration_failed", "Relay did not return a visible join URL for this launch", "Retry `tutti launch` so the host can rotate a fresh visible-once join URL.");
|
|
40
|
+
}
|
|
41
|
+
updateMachineProjectRelayBinding({
|
|
42
|
+
tuttiHome: options.preparation.tutti_home,
|
|
43
|
+
projectId: options.preparation.project_id,
|
|
44
|
+
relayProjectRef: result.relay_project.relay_project_ref,
|
|
45
|
+
...(options.now === undefined ? {} : { now: options.now }),
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
summary: {
|
|
49
|
+
relay_project_ref: result.relay_project.relay_project_ref,
|
|
50
|
+
host_connection_ref: result.host_connection.host_connection_ref,
|
|
51
|
+
join_url: result.join_token.join_url,
|
|
52
|
+
join_url_visibility: result.join_token.visibility,
|
|
53
|
+
join_token_expires_at: result.join_token.expires_at,
|
|
54
|
+
join_token_reusable: result.join_token.reusable,
|
|
55
|
+
tunnel_url: result.host_connection.tunnel_url,
|
|
56
|
+
connected_at: result.host_connection.connected_at,
|
|
57
|
+
},
|
|
58
|
+
hostConnectionToken: result.host_connection_token,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=relay-registration.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { IdempotencyKey } from "@tutti/shared/ids";
|
|
2
|
+
import { type CommandIdempotencyRecordLike, type CommandReplayDecision } from "@tutti/shared/utils/command-idempotency";
|
|
3
|
+
import { type SqliteDatabase } from "../../store/index.js";
|
|
4
|
+
export type CommandRequestHashInput = {
|
|
5
|
+
command_name: string;
|
|
6
|
+
target_ref?: string | null;
|
|
7
|
+
payload: unknown;
|
|
8
|
+
};
|
|
9
|
+
export type CommandIdempotencyRecordRow = {
|
|
10
|
+
command_id: IdempotencyKey;
|
|
11
|
+
command_name: string;
|
|
12
|
+
target_ref: string | null;
|
|
13
|
+
request_hash: string;
|
|
14
|
+
status: "in_progress" | "completed" | "failed";
|
|
15
|
+
disposition_json: string | null;
|
|
16
|
+
};
|
|
17
|
+
export type ExecuteIdempotentCommandOptions<TDisposition, TResult> = {
|
|
18
|
+
db: SqliteDatabase;
|
|
19
|
+
command_id: IdempotencyKey;
|
|
20
|
+
command_name: string;
|
|
21
|
+
target_ref?: string | null;
|
|
22
|
+
payload: unknown;
|
|
23
|
+
now?: () => Date;
|
|
24
|
+
execute: (tx: SqliteDatabase) => {
|
|
25
|
+
disposition: TDisposition;
|
|
26
|
+
result?: TResult;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export type ExecuteIdempotentCommandResult<TDisposition, TResult> = {
|
|
30
|
+
command_id: IdempotencyKey;
|
|
31
|
+
disposition: TDisposition;
|
|
32
|
+
result?: TResult;
|
|
33
|
+
replayed: boolean;
|
|
34
|
+
};
|
|
35
|
+
export declare class CommandReplayMismatchError extends Error {
|
|
36
|
+
readonly statusCode = 409;
|
|
37
|
+
readonly code = "command_replay_mismatch";
|
|
38
|
+
constructor();
|
|
39
|
+
}
|
|
40
|
+
export declare function createCommandRequestHash(input: CommandRequestHashInput): string;
|
|
41
|
+
export declare function decideCommandIdempotencyReplay(record: CommandIdempotencyRecordLike | null | undefined, input: CommandRequestHashInput): CommandReplayDecision;
|
|
42
|
+
export declare function readCommandIdempotencyRecord(db: SqliteDatabase, commandId: IdempotencyKey): CommandIdempotencyRecordLike | null;
|
|
43
|
+
export declare function executeIdempotentCommand<TDisposition, TResult>(options: ExecuteIdempotentCommandOptions<TDisposition, TResult>): ExecuteIdempotentCommandResult<TDisposition, TResult>;
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { createCommandRequestCanonicalInput, createInterruptedCommandDisposition, decideCommandReplay, redactCommandDisposition, } from "@tutti/shared/utils/command-idempotency";
|
|
3
|
+
import { withHostStoreTransaction } from "../../store/index.js";
|
|
4
|
+
export class CommandReplayMismatchError extends Error {
|
|
5
|
+
statusCode = 409;
|
|
6
|
+
code = "command_replay_mismatch";
|
|
7
|
+
constructor() {
|
|
8
|
+
super("Command idempotency replay payload does not match the original request");
|
|
9
|
+
this.name = "CommandReplayMismatchError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function createCommandRequestHash(input) {
|
|
13
|
+
const canonicalInput = createCommandRequestCanonicalInput(input);
|
|
14
|
+
const digest = createHash("sha256").update(canonicalInput, "utf8").digest("hex");
|
|
15
|
+
return `sha256:${digest}`;
|
|
16
|
+
}
|
|
17
|
+
export function decideCommandIdempotencyReplay(record, input) {
|
|
18
|
+
return decideCommandReplay(record, createCommandRequestHash(input));
|
|
19
|
+
}
|
|
20
|
+
function parseDisposition(json) {
|
|
21
|
+
if (json === null) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(json);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function readCommandIdempotencyRecord(db, commandId) {
|
|
32
|
+
const row = db
|
|
33
|
+
.prepare(`
|
|
34
|
+
SELECT
|
|
35
|
+
command_id,
|
|
36
|
+
command_name,
|
|
37
|
+
target_ref,
|
|
38
|
+
request_hash,
|
|
39
|
+
status,
|
|
40
|
+
disposition_json
|
|
41
|
+
FROM command_idempotency_records
|
|
42
|
+
WHERE command_id = ?
|
|
43
|
+
`)
|
|
44
|
+
.get(commandId);
|
|
45
|
+
if (row === undefined) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
command_id: row.command_id,
|
|
50
|
+
command_name: row.command_name,
|
|
51
|
+
target_ref: row.target_ref,
|
|
52
|
+
request_hash: row.request_hash,
|
|
53
|
+
status: row.status,
|
|
54
|
+
disposition: parseDisposition(row.disposition_json),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function startCommandIdempotencyRecord(options) {
|
|
58
|
+
options.db
|
|
59
|
+
.prepare(`
|
|
60
|
+
INSERT INTO command_idempotency_records (
|
|
61
|
+
command_id,
|
|
62
|
+
command_name,
|
|
63
|
+
target_ref,
|
|
64
|
+
request_hash,
|
|
65
|
+
status,
|
|
66
|
+
created_at,
|
|
67
|
+
updated_at
|
|
68
|
+
)
|
|
69
|
+
VALUES (?, ?, ?, ?, 'in_progress', ?, ?)
|
|
70
|
+
`)
|
|
71
|
+
.run(options.command_id, options.command_name, options.target_ref ?? null, options.request_hash, options.now, options.now);
|
|
72
|
+
}
|
|
73
|
+
function completeCommandIdempotencyRecord(options) {
|
|
74
|
+
options.db
|
|
75
|
+
.prepare(`
|
|
76
|
+
UPDATE command_idempotency_records
|
|
77
|
+
SET status = 'completed',
|
|
78
|
+
disposition_json = ?,
|
|
79
|
+
updated_at = ?,
|
|
80
|
+
completed_at = ?
|
|
81
|
+
WHERE command_id = ?
|
|
82
|
+
AND status = 'in_progress'
|
|
83
|
+
`)
|
|
84
|
+
.run(JSON.stringify(redactCommandDisposition(options.disposition)), options.now, options.now, options.command_id);
|
|
85
|
+
}
|
|
86
|
+
function interruptCommandIdempotencyRecord(options) {
|
|
87
|
+
const disposition = createInterruptedCommandDisposition();
|
|
88
|
+
options.db
|
|
89
|
+
.prepare(`
|
|
90
|
+
UPDATE command_idempotency_records
|
|
91
|
+
SET status = 'failed',
|
|
92
|
+
disposition_json = ?,
|
|
93
|
+
updated_at = ?,
|
|
94
|
+
completed_at = ?
|
|
95
|
+
WHERE command_id = ?
|
|
96
|
+
AND status = 'in_progress'
|
|
97
|
+
`)
|
|
98
|
+
.run(JSON.stringify(disposition), options.now, options.now, options.command_id);
|
|
99
|
+
}
|
|
100
|
+
export function executeIdempotentCommand(options) {
|
|
101
|
+
const now = (options.now ?? (() => new Date()))().toISOString();
|
|
102
|
+
const request = {
|
|
103
|
+
command_name: options.command_name,
|
|
104
|
+
target_ref: options.target_ref ?? null,
|
|
105
|
+
payload: options.payload,
|
|
106
|
+
};
|
|
107
|
+
const requestHash = createCommandRequestHash(request);
|
|
108
|
+
return withHostStoreTransaction(options.db, (tx) => {
|
|
109
|
+
const replay = decideCommandReplay(readCommandIdempotencyRecord(tx, options.command_id), requestHash);
|
|
110
|
+
if (replay.kind === "mismatch") {
|
|
111
|
+
throw new CommandReplayMismatchError();
|
|
112
|
+
}
|
|
113
|
+
if (replay.kind === "replay") {
|
|
114
|
+
return {
|
|
115
|
+
command_id: options.command_id,
|
|
116
|
+
disposition: replay.disposition,
|
|
117
|
+
replayed: true,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (replay.kind === "in_progress") {
|
|
121
|
+
interruptCommandIdempotencyRecord({
|
|
122
|
+
db: tx,
|
|
123
|
+
command_id: options.command_id,
|
|
124
|
+
now,
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
command_id: options.command_id,
|
|
128
|
+
disposition: replay.disposition,
|
|
129
|
+
replayed: true,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
startCommandIdempotencyRecord({
|
|
133
|
+
db: tx,
|
|
134
|
+
command_id: options.command_id,
|
|
135
|
+
command_name: options.command_name,
|
|
136
|
+
target_ref: options.target_ref,
|
|
137
|
+
request_hash: requestHash,
|
|
138
|
+
now,
|
|
139
|
+
});
|
|
140
|
+
const executed = options.execute(tx);
|
|
141
|
+
completeCommandIdempotencyRecord({
|
|
142
|
+
db: tx,
|
|
143
|
+
command_id: options.command_id,
|
|
144
|
+
disposition: executed.disposition,
|
|
145
|
+
now,
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
command_id: options.command_id,
|
|
149
|
+
disposition: executed.disposition,
|
|
150
|
+
...(executed.result === undefined ? {} : { result: executed.result }),
|
|
151
|
+
replayed: false,
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type DevRunnerR2Config = {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
bucket: string;
|
|
4
|
+
accessKeyId: string;
|
|
5
|
+
secretAccessKey: string;
|
|
6
|
+
region?: string;
|
|
7
|
+
uploadTtlSeconds?: number;
|
|
8
|
+
hostReadTtlSeconds?: number;
|
|
9
|
+
};
|
|
10
|
+
export type DevRunnerConfig = {
|
|
11
|
+
repoRoot: string;
|
|
12
|
+
tuttiHome: string;
|
|
13
|
+
targetWorkspaceRoot: string;
|
|
14
|
+
targetSource: "default_dummy" | "env_override";
|
|
15
|
+
r2?: DevRunnerR2Config;
|
|
16
|
+
relayUrl: string;
|
|
17
|
+
relayHost: string;
|
|
18
|
+
relayPort: number;
|
|
19
|
+
hostEndpointHost: string;
|
|
20
|
+
hostEndpointPort: number;
|
|
21
|
+
webHost: string;
|
|
22
|
+
webPort: number;
|
|
23
|
+
webUrl: string;
|
|
24
|
+
};
|
|
25
|
+
export type ResolveDevRunnerConfigOptions = {
|
|
26
|
+
env?: NodeJS.ProcessEnv;
|
|
27
|
+
repoRoot?: string;
|
|
28
|
+
userHome?: string;
|
|
29
|
+
};
|
|
30
|
+
export declare class DevRunnerConfigError extends Error {
|
|
31
|
+
readonly code: "invalid_port" | "invalid_r2_config" | "target_inside_repo";
|
|
32
|
+
constructor(code: "invalid_port" | "invalid_r2_config" | "target_inside_repo", message: string);
|
|
33
|
+
}
|
|
34
|
+
export declare function resolveDevRunnerConfig(options?: ResolveDevRunnerConfigOptions): DevRunnerConfig;
|
|
35
|
+
export declare function ensureDevRunnerState(config: DevRunnerConfig): void;
|
|
36
|
+
export declare function createDevProcessEnv(config: DevRunnerConfig, sourceEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
37
|
+
export declare function createDevRelayProcessEnv(config: DevRunnerConfig, sourceEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
38
|
+
//# sourceMappingURL=config.d.ts.map
|