toolroll 0.5.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/LICENSE +21 -0
- package/README.md +1113 -0
- package/THIRD_PARTY_NOTICES.md +449 -0
- package/dist/accent-colors.d.ts +48 -0
- package/dist/accent-colors.js +122 -0
- package/dist/action-ledger.d.ts +26 -0
- package/dist/action-ledger.js +75 -0
- package/dist/agent-fence.d.ts +42 -0
- package/dist/agent-fence.js +183 -0
- package/dist/agentconfig.d.ts +216 -0
- package/dist/agentconfig.js +454 -0
- package/dist/api-tokens.d.ts +16 -0
- package/dist/api-tokens.js +27 -0
- package/dist/approval-policy.d.ts +69 -0
- package/dist/approval-policy.js +137 -0
- package/dist/approval-rules-ui.d.ts +25 -0
- package/dist/approval-rules-ui.js +39 -0
- package/dist/assignment-adapters.d.ts +180 -0
- package/dist/assignment-adapters.js +239 -0
- package/dist/assignment-brief.d.ts +71 -0
- package/dist/assignment-brief.js +129 -0
- package/dist/assignment-delivery.d.ts +56 -0
- package/dist/assignment-delivery.js +160 -0
- package/dist/assignment-presentation.d.ts +26 -0
- package/dist/assignment-presentation.js +80 -0
- package/dist/assignment-status.d.ts +62 -0
- package/dist/assignment-status.js +152 -0
- package/dist/assignment-ui.d.ts +71 -0
- package/dist/assignment-ui.js +103 -0
- package/dist/assignment.d.ts +222 -0
- package/dist/assignment.js +399 -0
- package/dist/attest.d.ts +56 -0
- package/dist/attest.js +153 -0
- package/dist/backend.d.ts +97 -0
- package/dist/backend.js +166 -0
- package/dist/backup-ui.d.ts +22 -0
- package/dist/backup-ui.js +59 -0
- package/dist/backup.d.ts +84 -0
- package/dist/backup.js +421 -0
- package/dist/beads.d.ts +34 -0
- package/dist/beads.js +135 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +22 -0
- package/dist/board.d.ts +150 -0
- package/dist/board.js +210 -0
- package/dist/boot-identity.d.ts +63 -0
- package/dist/boot-identity.js +99 -0
- package/dist/browser/THIRD_PARTY_NOTICES.txt +2295 -0
- package/dist/browser/workspace.css +4 -0
- package/dist/browser/workspace.js +225 -0
- package/dist/browser-crew.d.ts +11 -0
- package/dist/browser-crew.js +50 -0
- package/dist/browser-shell.d.ts +8 -0
- package/dist/browser-shell.js +60 -0
- package/dist/browser-workspace.d.ts +780 -0
- package/dist/browser-workspace.js +47 -0
- package/dist/budget-alerts.d.ts +19 -0
- package/dist/budget-alerts.js +46 -0
- package/dist/builder.d.ts +370 -0
- package/dist/builder.js +3262 -0
- package/dist/capscan.d.ts +35 -0
- package/dist/capscan.js +113 -0
- package/dist/chat-acceptance.d.ts +71 -0
- package/dist/chat-acceptance.js +120 -0
- package/dist/chat-actions.d.ts +265 -0
- package/dist/chat-actions.js +1273 -0
- package/dist/chat-channel.d.ts +109 -0
- package/dist/chat-channel.js +652 -0
- package/dist/chat-continuity.d.ts +32 -0
- package/dist/chat-continuity.js +317 -0
- package/dist/chat-controls.d.ts +113 -0
- package/dist/chat-controls.js +53 -0
- package/dist/chat-delivery-state.d.ts +159 -0
- package/dist/chat-delivery-state.js +309 -0
- package/dist/chat-delivery.d.ts +38 -0
- package/dist/chat-delivery.js +693 -0
- package/dist/chat-display.d.ts +1 -0
- package/dist/chat-display.js +18 -0
- package/dist/chat-evidence.d.ts +123 -0
- package/dist/chat-evidence.js +207 -0
- package/dist/chat-flow.d.ts +44 -0
- package/dist/chat-flow.js +215 -0
- package/dist/chat-inbox.d.ts +57 -0
- package/dist/chat-inbox.js +123 -0
- package/dist/chat-polish.d.ts +16 -0
- package/dist/chat-polish.js +135 -0
- package/dist/chat-review.d.ts +46 -0
- package/dist/chat-review.js +98 -0
- package/dist/chat-rooms.d.ts +123 -0
- package/dist/chat-rooms.js +216 -0
- package/dist/chat-task-actions.d.ts +44 -0
- package/dist/chat-task-actions.js +79 -0
- package/dist/check-progress.d.ts +51 -0
- package/dist/check-progress.js +290 -0
- package/dist/child-database.d.ts +12 -0
- package/dist/child-database.js +30 -0
- package/dist/claim.d.ts +688 -0
- package/dist/claim.js +1740 -0
- package/dist/cli.d.ts +137 -0
- package/dist/cli.js +1461 -0
- package/dist/codex-limits.d.ts +15 -0
- package/dist/codex-limits.js +145 -0
- package/dist/coding-context.d.ts +55 -0
- package/dist/coding-context.js +92 -0
- package/dist/coding-handoff.d.ts +57 -0
- package/dist/coding-handoff.js +277 -0
- package/dist/coding-provider.d.ts +72 -0
- package/dist/coding-provider.js +424 -0
- package/dist/coding-shipping-ui.d.ts +4 -0
- package/dist/coding-shipping-ui.js +12 -0
- package/dist/coding-types.d.ts +62 -0
- package/dist/coding-types.js +1 -0
- package/dist/coding-ui.d.ts +17 -0
- package/dist/coding-ui.js +364 -0
- package/dist/coding-update.d.ts +15 -0
- package/dist/coding-update.js +149 -0
- package/dist/coding-workspace.d.ts +124 -0
- package/dist/coding-workspace.js +768 -0
- package/dist/container-state.d.ts +5 -0
- package/dist/container-state.js +62 -0
- package/dist/containment.d.ts +197 -0
- package/dist/containment.js +559 -0
- package/dist/contest.d.ts +318 -0
- package/dist/contest.js +753 -0
- package/dist/control-setup.d.ts +35 -0
- package/dist/control-setup.js +40 -0
- package/dist/control-ui.d.ts +29 -0
- package/dist/control-ui.js +53 -0
- package/dist/controller-service.d.ts +1 -0
- package/dist/controller-service.js +19 -0
- package/dist/controller-supervisor.d.ts +30 -0
- package/dist/controller-supervisor.js +104 -0
- package/dist/converse.d.ts +304 -0
- package/dist/converse.js +849 -0
- package/dist/coordinator-proposals.d.ts +29 -0
- package/dist/coordinator-proposals.js +137 -0
- package/dist/coordinator.d.ts +186 -0
- package/dist/coordinator.js +447 -0
- package/dist/credentials-ui.d.ts +25 -0
- package/dist/credentials-ui.js +48 -0
- package/dist/daemon.d.ts +209 -0
- package/dist/daemon.js +604 -0
- package/dist/decision.d.ts +120 -0
- package/dist/decision.js +388 -0
- package/dist/demo.d.ts +55 -0
- package/dist/demo.js +992 -0
- package/dist/desktop-access.d.ts +28 -0
- package/dist/desktop-access.js +88 -0
- package/dist/desktop-bundle.d.ts +16 -0
- package/dist/desktop-bundle.js +74 -0
- package/dist/desktop-host.d.ts +54 -0
- package/dist/desktop-host.js +508 -0
- package/dist/desktop-update-gate.d.ts +12 -0
- package/dist/desktop-update-gate.js +91 -0
- package/dist/desktop-update-recovery.d.ts +14 -0
- package/dist/desktop-update-recovery.js +243 -0
- package/dist/desktop-update.d.ts +110 -0
- package/dist/desktop-update.js +740 -0
- package/dist/discord-api.d.ts +20 -0
- package/dist/discord-api.js +138 -0
- package/dist/discord-chat.d.ts +16 -0
- package/dist/discord-chat.js +381 -0
- package/dist/discord-settings.d.ts +7 -0
- package/dist/discord-settings.js +75 -0
- package/dist/discord.d.ts +10 -0
- package/dist/discord.js +169 -0
- package/dist/discover.d.ts +75 -0
- package/dist/discover.js +150 -0
- package/dist/dispatch.d.ts +100 -0
- package/dist/dispatch.js +311 -0
- package/dist/dispose.d.ts +161 -0
- package/dist/dispose.js +803 -0
- package/dist/email-settings.d.ts +34 -0
- package/dist/email-settings.js +50 -0
- package/dist/envelope.d.ts +47 -0
- package/dist/envelope.js +105 -0
- package/dist/evidence-pack.d.ts +185 -0
- package/dist/evidence-pack.js +258 -0
- package/dist/evidence.d.ts +345 -0
- package/dist/evidence.js +782 -0
- package/dist/exec.d.ts +285 -0
- package/dist/exec.js +1841 -0
- package/dist/exhaustion.d.ts +85 -0
- package/dist/exhaustion.js +141 -0
- package/dist/export-ui.d.ts +4 -0
- package/dist/export-ui.js +17 -0
- package/dist/export.d.ts +48 -0
- package/dist/export.js +305 -0
- package/dist/flow-actions.d.ts +77 -0
- package/dist/flow-actions.js +203 -0
- package/dist/flow-code.d.ts +50 -0
- package/dist/flow-code.js +159 -0
- package/dist/flow-draft.d.ts +38 -0
- package/dist/flow-draft.js +80 -0
- package/dist/flow-engine.d.ts +66 -0
- package/dist/flow-engine.js +416 -0
- package/dist/flow-insights.d.ts +95 -0
- package/dist/flow-insights.js +149 -0
- package/dist/flow-live.d.ts +24 -0
- package/dist/flow-live.js +150 -0
- package/dist/flow-people.d.ts +24 -0
- package/dist/flow-people.js +91 -0
- package/dist/flow-replies.d.ts +48 -0
- package/dist/flow-replies.js +113 -0
- package/dist/flow-scripts.d.ts +38 -0
- package/dist/flow-scripts.js +73 -0
- package/dist/flow-secrets.d.ts +13 -0
- package/dist/flow-secrets.js +45 -0
- package/dist/flow-sort.d.ts +82 -0
- package/dist/flow-sort.js +153 -0
- package/dist/flow-steps.d.ts +40 -0
- package/dist/flow-steps.js +408 -0
- package/dist/flow-triggers.d.ts +244 -0
- package/dist/flow-triggers.js +959 -0
- package/dist/flows-ui.d.ts +20 -0
- package/dist/flows-ui.js +175 -0
- package/dist/flows.d.ts +229 -0
- package/dist/flows.js +968 -0
- package/dist/fonts.d.ts +19 -0
- package/dist/fonts.js +19 -0
- package/dist/gaps.d.ts +35 -0
- package/dist/gaps.js +101 -0
- package/dist/gate-failure.d.ts +40 -0
- package/dist/gate-failure.js +66 -0
- package/dist/git.d.ts +54 -0
- package/dist/git.js +94 -0
- package/dist/google-mail.d.ts +58 -0
- package/dist/google-mail.js +151 -0
- package/dist/grant.d.ts +136 -0
- package/dist/grant.js +238 -0
- package/dist/graph.d.ts +164 -0
- package/dist/graph.js +383 -0
- package/dist/guides.d.ts +22 -0
- package/dist/guides.js +363 -0
- package/dist/held.d.ts +150 -0
- package/dist/held.js +799 -0
- package/dist/invoke.d.ts +112 -0
- package/dist/invoke.js +780 -0
- package/dist/issues.d.ts +41 -0
- package/dist/issues.js +131 -0
- package/dist/job-object-helper.ps1 +252 -0
- package/dist/jsonl-discriminants.d.ts +11 -0
- package/dist/jsonl-discriminants.js +93 -0
- package/dist/keys.d.ts +104 -0
- package/dist/keys.js +229 -0
- package/dist/kits-ui.d.ts +17 -0
- package/dist/kits-ui.js +46 -0
- package/dist/kits.d.ts +86 -0
- package/dist/kits.js +215 -0
- package/dist/knowledge-cli.d.ts +101 -0
- package/dist/knowledge-cli.js +92 -0
- package/dist/knowledge-ui.d.ts +24 -0
- package/dist/knowledge-ui.js +40 -0
- package/dist/lead-context.d.ts +8 -0
- package/dist/lead-context.js +56 -0
- package/dist/lead-follow.d.ts +22 -0
- package/dist/lead-follow.js +167 -0
- package/dist/lead-status.d.ts +75 -0
- package/dist/lead-status.js +285 -0
- package/dist/ledger-chain.d.ts +46 -0
- package/dist/ledger-chain.js +187 -0
- package/dist/ledger-csv.d.ts +4 -0
- package/dist/ledger-csv.js +11 -0
- package/dist/ledger-view.d.ts +24 -0
- package/dist/ledger-view.js +58 -0
- package/dist/limits-ui.d.ts +26 -0
- package/dist/limits-ui.js +67 -0
- package/dist/link.d.ts +72 -0
- package/dist/link.js +217 -0
- package/dist/live.d.ts +96 -0
- package/dist/live.js +366 -0
- package/dist/liveness.d.ts +30 -0
- package/dist/liveness.js +42 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.js +25 -0
- package/dist/mailbox.d.ts +57 -0
- package/dist/mailbox.js +150 -0
- package/dist/maintenance.d.ts +11 -0
- package/dist/maintenance.js +35 -0
- package/dist/mate-cli.d.ts +52 -0
- package/dist/mate-cli.js +345 -0
- package/dist/mate-contract.d.ts +10 -0
- package/dist/mate-contract.js +30 -0
- package/dist/mate-doors.d.ts +69 -0
- package/dist/mate-doors.js +548 -0
- package/dist/mate-progress.d.ts +29 -0
- package/dist/mate-progress.js +121 -0
- package/dist/mate-tools.d.ts +94 -0
- package/dist/mate-tools.js +1878 -0
- package/dist/mate.d.ts +92 -0
- package/dist/mate.js +435 -0
- package/dist/mcp-connect.d.ts +103 -0
- package/dist/mcp-connect.js +252 -0
- package/dist/mcp.d.ts +27 -0
- package/dist/mcp.js +651 -0
- package/dist/memory-cli.d.ts +466 -0
- package/dist/memory-cli.js +111 -0
- package/dist/memory-pass.d.ts +160 -0
- package/dist/memory-pass.js +409 -0
- package/dist/metrics.d.ts +3 -0
- package/dist/metrics.js +56 -0
- package/dist/mobile-viewport.d.ts +3 -0
- package/dist/mobile-viewport.js +37 -0
- package/dist/model-catalog.d.ts +118 -0
- package/dist/model-catalog.js +376 -0
- package/dist/models-cli.d.ts +102 -0
- package/dist/models-cli.js +66 -0
- package/dist/models-ui.d.ts +34 -0
- package/dist/models-ui.js +68 -0
- package/dist/modes.d.ts +80 -0
- package/dist/modes.js +182 -0
- package/dist/monitoring-settings.d.ts +44 -0
- package/dist/monitoring-settings.js +173 -0
- package/dist/monitoring-ui.d.ts +20 -0
- package/dist/monitoring-ui.js +51 -0
- package/dist/monitoring.d.ts +34 -0
- package/dist/monitoring.js +221 -0
- package/dist/names.d.ts +67 -0
- package/dist/names.js +102 -0
- package/dist/observations.d.ts +40 -0
- package/dist/observations.js +211 -0
- package/dist/oidc.d.ts +71 -0
- package/dist/oidc.js +182 -0
- package/dist/onboard.d.ts +108 -0
- package/dist/onboard.js +325 -0
- package/dist/openrouter-models.d.ts +30 -0
- package/dist/openrouter-models.js +120 -0
- package/dist/operate.d.ts +118 -0
- package/dist/operate.js +11321 -0
- package/dist/peek-cli.d.ts +97 -0
- package/dist/peek-cli.js +215 -0
- package/dist/peek.d.ts +134 -0
- package/dist/peek.js +578 -0
- package/dist/phase-routing.d.ts +307 -0
- package/dist/phase-routing.js +658 -0
- package/dist/plan-auto.d.ts +14 -0
- package/dist/plan-auto.js +92 -0
- package/dist/plan.d.ts +186 -0
- package/dist/plan.js +401 -0
- package/dist/planner-source.d.ts +251 -0
- package/dist/planner-source.js +460 -0
- package/dist/planner.d.ts +75 -0
- package/dist/planner.js +992 -0
- package/dist/policy-ui.d.ts +20 -0
- package/dist/policy-ui.js +41 -0
- package/dist/policy.d.ts +111 -0
- package/dist/policy.js +231 -0
- package/dist/prepared-evidence.d.ts +16 -0
- package/dist/prepared-evidence.js +96 -0
- package/dist/pricing.d.ts +45 -0
- package/dist/pricing.js +77 -0
- package/dist/principal.d.ts +42 -0
- package/dist/principal.js +82 -0
- package/dist/probe.d.ts +46 -0
- package/dist/probe.js +79 -0
- package/dist/process-custody.d.ts +17 -0
- package/dist/process-custody.js +91 -0
- package/dist/process-liveness.d.ts +10 -0
- package/dist/process-liveness.js +81 -0
- package/dist/process-recovery-anchor.d.ts +75 -0
- package/dist/process-recovery-anchor.js +188 -0
- package/dist/process-recovery-coalition.d.ts +25 -0
- package/dist/process-recovery-coalition.js +105 -0
- package/dist/process-recovery-eligibility.d.ts +178 -0
- package/dist/process-recovery-eligibility.js +170 -0
- package/dist/process-recovery-native.d.ts +172 -0
- package/dist/process-recovery-native.js +592 -0
- package/dist/process-recovery-provenance.d.ts +163 -0
- package/dist/process-recovery-provenance.js +292 -0
- package/dist/process-recovery-services.d.ts +56 -0
- package/dist/process-recovery-services.js +191 -0
- package/dist/process-recovery-settlement.d.ts +32 -0
- package/dist/process-recovery-settlement.js +132 -0
- package/dist/process-recovery.d.ts +41 -0
- package/dist/process-recovery.js +91 -0
- package/dist/process-tree.d.ts +41 -0
- package/dist/process-tree.js +264 -0
- package/dist/project-access.d.ts +14 -0
- package/dist/project-access.js +34 -0
- package/dist/project-cli.d.ts +18 -0
- package/dist/project-cli.js +104 -0
- package/dist/project-delete-ui.d.ts +22 -0
- package/dist/project-delete-ui.js +48 -0
- package/dist/project-delete.d.ts +55 -0
- package/dist/project-delete.js +413 -0
- package/dist/project-knowledge.d.ts +111 -0
- package/dist/project-knowledge.js +241 -0
- package/dist/project-learning.d.ts +100 -0
- package/dist/project-learning.js +438 -0
- package/dist/project-memory.d.ts +81 -0
- package/dist/project-memory.js +264 -0
- package/dist/project-skills.d.ts +152 -0
- package/dist/project-skills.js +660 -0
- package/dist/project-tools.d.ts +219 -0
- package/dist/project-tools.js +796 -0
- package/dist/project.d.ts +61 -0
- package/dist/project.js +125 -0
- package/dist/prompt.d.ts +22 -0
- package/dist/prompt.js +72 -0
- package/dist/proof.d.ts +513 -0
- package/dist/proof.js +1140 -0
- package/dist/proposal.d.ts +82 -0
- package/dist/proposal.js +210 -0
- package/dist/provider-connection.d.ts +22 -0
- package/dist/provider-connection.js +98 -0
- package/dist/provider-limits.d.ts +35 -0
- package/dist/provider-limits.js +95 -0
- package/dist/provider.d.ts +279 -0
- package/dist/provider.js +935 -0
- package/dist/publish.d.ts +107 -0
- package/dist/publish.js +650 -0
- package/dist/pulls.d.ts +118 -0
- package/dist/pulls.js +240 -0
- package/dist/push.d.ts +95 -0
- package/dist/push.js +353 -0
- package/dist/quality.d.ts +8 -0
- package/dist/quality.js +6 -0
- package/dist/recipe-ui.d.ts +18 -0
- package/dist/recipe-ui.js +152 -0
- package/dist/recipes.d.ts +81 -0
- package/dist/recipes.js +332 -0
- package/dist/remote.d.ts +67 -0
- package/dist/remote.js +122 -0
- package/dist/render.d.ts +64 -0
- package/dist/render.js +587 -0
- package/dist/report-summary.d.ts +13 -0
- package/dist/report-summary.js +15 -0
- package/dist/repos.d.ts +65 -0
- package/dist/repos.js +277 -0
- package/dist/repository-context-ui.d.ts +2 -0
- package/dist/repository-context-ui.js +10 -0
- package/dist/repository-context.d.ts +67 -0
- package/dist/repository-context.js +376 -0
- package/dist/restart-certification.d.ts +134 -0
- package/dist/restart-certification.js +226 -0
- package/dist/result-actions.d.ts +28 -0
- package/dist/result-actions.js +270 -0
- package/dist/result-completion.d.ts +18 -0
- package/dist/result-completion.js +66 -0
- package/dist/result-review.d.ts +213 -0
- package/dist/result-review.js +430 -0
- package/dist/retention-ui.d.ts +12 -0
- package/dist/retention-ui.js +39 -0
- package/dist/retention.d.ts +72 -0
- package/dist/retention.js +288 -0
- package/dist/review-context.d.ts +243 -0
- package/dist/review-context.js +1043 -0
- package/dist/review-evidence.d.ts +33 -0
- package/dist/review-evidence.js +56 -0
- package/dist/reviewer.d.ts +97 -0
- package/dist/reviewer.js +202 -0
- package/dist/routine.d.ts +228 -0
- package/dist/routine.js +764 -0
- package/dist/runner.d.ts +266 -0
- package/dist/runner.js +399 -0
- package/dist/scan.d.ts +32 -0
- package/dist/scan.js +92 -0
- package/dist/scope.d.ts +695 -0
- package/dist/scope.js +1176 -0
- package/dist/scout-report.d.ts +42 -0
- package/dist/scout-report.js +108 -0
- package/dist/scout.d.ts +69 -0
- package/dist/scout.js +351 -0
- package/dist/serve.d.ts +313 -0
- package/dist/serve.js +21776 -0
- package/dist/session-brief.d.ts +8 -0
- package/dist/session-brief.js +24 -0
- package/dist/session-cli.d.ts +13 -0
- package/dist/session-cli.js +284 -0
- package/dist/session-contract.d.ts +183 -0
- package/dist/session-contract.js +122 -0
- package/dist/session-http.d.ts +19 -0
- package/dist/session-http.js +154 -0
- package/dist/session-server.d.ts +12 -0
- package/dist/session-server.js +37 -0
- package/dist/session-service.d.ts +22 -0
- package/dist/session-service.js +157 -0
- package/dist/setup-guide.d.ts +39 -0
- package/dist/setup-guide.js +93 -0
- package/dist/sign-in-guard.d.ts +45 -0
- package/dist/sign-in-guard.js +74 -0
- package/dist/skills-ui.d.ts +11 -0
- package/dist/skills-ui.js +58 -0
- package/dist/skills.d.ts +97 -0
- package/dist/skills.js +276 -0
- package/dist/slack-api.d.ts +55 -0
- package/dist/slack-api.js +229 -0
- package/dist/slack-chat.d.ts +28 -0
- package/dist/slack-chat.js +413 -0
- package/dist/slack-settings.d.ts +7 -0
- package/dist/slack-settings.js +75 -0
- package/dist/slack-state.d.ts +13 -0
- package/dist/slack-state.js +9 -0
- package/dist/slack.d.ts +13 -0
- package/dist/slack.js +167 -0
- package/dist/spend-ui.d.ts +28 -0
- package/dist/spend-ui.js +95 -0
- package/dist/spend.d.ts +142 -0
- package/dist/spend.js +313 -0
- package/dist/sqlite-runtime.d.ts +3 -0
- package/dist/sqlite-runtime.js +6 -0
- package/dist/sso-settings.d.ts +33 -0
- package/dist/sso-settings.js +103 -0
- package/dist/sso-ui.d.ts +22 -0
- package/dist/sso-ui.js +39 -0
- package/dist/storage.d.ts +15 -0
- package/dist/storage.js +84 -0
- package/dist/store.d.ts +7754 -0
- package/dist/store.js +23279 -0
- package/dist/structured-output.d.ts +58 -0
- package/dist/structured-output.js +103 -0
- package/dist/style-asset.d.ts +7 -0
- package/dist/style-asset.js +41 -0
- package/dist/subscription-chat.d.ts +46 -0
- package/dist/subscription-chat.js +275 -0
- package/dist/summary.d.ts +33 -0
- package/dist/summary.js +71 -0
- package/dist/supervisor.mjs +297 -0
- package/dist/surface.d.ts +63 -0
- package/dist/surface.js +352 -0
- package/dist/sync.d.ts +94 -0
- package/dist/sync.js +279 -0
- package/dist/task-composer.d.ts +13 -0
- package/dist/task-composer.js +52 -0
- package/dist/task-control.d.ts +165 -0
- package/dist/task-control.js +214 -0
- package/dist/task-outcome-cli.d.ts +10 -0
- package/dist/task-outcome-cli.js +92 -0
- package/dist/task-text.d.ts +30 -0
- package/dist/task-text.js +41 -0
- package/dist/team-cli.d.ts +15 -0
- package/dist/team-cli.js +618 -0
- package/dist/team-contract.d.ts +92 -0
- package/dist/team-contract.js +1 -0
- package/dist/team-http.d.ts +17 -0
- package/dist/team-http.js +144 -0
- package/dist/team-leads.d.ts +81 -0
- package/dist/team-leads.js +565 -0
- package/dist/team-runtime.d.ts +27 -0
- package/dist/team-runtime.js +264 -0
- package/dist/team-ui.d.ts +3 -0
- package/dist/team-ui.js +9 -0
- package/dist/team-updates.d.ts +8 -0
- package/dist/team-updates.js +57 -0
- package/dist/teammate-admin.d.ts +53 -0
- package/dist/teammate-admin.js +111 -0
- package/dist/teammate-desk.d.ts +60 -0
- package/dist/teammate-desk.js +154 -0
- package/dist/teammate-memory.d.ts +64 -0
- package/dist/teammate-memory.js +196 -0
- package/dist/teammate-question.d.ts +59 -0
- package/dist/teammate-question.js +175 -0
- package/dist/teammate-tools.d.ts +108 -0
- package/dist/teammate-tools.js +271 -0
- package/dist/teammate-week.d.ts +68 -0
- package/dist/teammate-week.js +132 -0
- package/dist/teammate-work.d.ts +76 -0
- package/dist/teammate-work.js +280 -0
- package/dist/teammates-ui.d.ts +20 -0
- package/dist/teammates-ui.js +166 -0
- package/dist/teammates.d.ts +180 -0
- package/dist/teammates.js +253 -0
- package/dist/teams-api.d.ts +33 -0
- package/dist/teams-api.js +204 -0
- package/dist/teams-chat.d.ts +26 -0
- package/dist/teams-chat.js +215 -0
- package/dist/teams-settings.d.ts +12 -0
- package/dist/teams-settings.js +57 -0
- package/dist/teams.d.ts +21 -0
- package/dist/teams.js +124 -0
- package/dist/telegram-flow.d.ts +49 -0
- package/dist/telegram-flow.js +110 -0
- package/dist/telegram-mate.d.ts +137 -0
- package/dist/telegram-mate.js +707 -0
- package/dist/telegram-progress.d.ts +14 -0
- package/dist/telegram-progress.js +129 -0
- package/dist/telegram-settings.d.ts +9 -0
- package/dist/telegram-settings.js +36 -0
- package/dist/telegram-status.d.ts +75 -0
- package/dist/telegram-status.js +265 -0
- package/dist/telegram-team.d.ts +85 -0
- package/dist/telegram-team.js +359 -0
- package/dist/telegram.d.ts +230 -0
- package/dist/telegram.js +1931 -0
- package/dist/templates.d.ts +65 -0
- package/dist/templates.js +118 -0
- package/dist/tool-launcher.d.ts +1 -0
- package/dist/tool-launcher.js +101 -0
- package/dist/tools-ui.d.ts +30 -0
- package/dist/tools-ui.js +40 -0
- package/dist/transitions-recipes.d.ts +1 -0
- package/dist/transitions-recipes.js +203 -0
- package/dist/tree-proof.d.ts +34 -0
- package/dist/tree-proof.js +58 -0
- package/dist/verification-evidence.d.ts +44 -0
- package/dist/verification-evidence.js +238 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +10 -0
- package/dist/webhooks.d.ts +91 -0
- package/dist/webhooks.js +283 -0
- package/dist/work-index.d.ts +68 -0
- package/dist/work-index.js +384 -0
- package/dist/work-summary.d.ts +57 -0
- package/dist/work-summary.js +116 -0
- package/dist/workspace-motion.d.ts +4 -0
- package/dist/workspace-motion.js +133 -0
- package/dist/workspace-revision.d.ts +19 -0
- package/dist/workspace-revision.js +92 -0
- package/dist/workspace-ui.d.ts +204 -0
- package/dist/workspace-ui.js +411 -0
- package/dist/worktree-notices.d.ts +13 -0
- package/dist/worktree-notices.js +17 -0
- package/dist/worktree.d.ts +249 -0
- package/dist/worktree.js +720 -0
- package/package.json +122 -0
- package/scripts/canary-assertions.mjs +42 -0
- package/scripts/crash-canary.mjs +253 -0
- package/scripts/fixtures/crash-process.mjs +74 -0
- package/scripts/fixtures/pilot-scenarios.mjs +85 -0
- package/scripts/fixtures/restart-service.mjs +27 -0
- package/scripts/launchd-certification.mjs +143 -0
- package/scripts/pilot.mjs +121 -0
- package/scripts/proof-preflight.mjs +140 -0
- package/scripts/provider-canary.mjs +379 -0
- package/scripts/recovery-canary.mjs +135 -0
- package/scripts/restart-certification.mjs +98 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The terminal exhaustion taxonomy (fallback chains, R1/C5/C8 of the
|
|
3
|
+
* approved design). A finished attempt is classified into ONE of these,
|
|
4
|
+
* where the evidence still exists — the provider adapter's structural
|
|
5
|
+
* record plus the gateway's authoritative CLI version and auth mode —
|
|
6
|
+
* NEVER in disposal, by which time the structural signal is gone.
|
|
7
|
+
*
|
|
8
|
+
* The whole feature is FAIL CLOSED by construction: a recognizer's
|
|
9
|
+
* eligible-signal set is EMPTY until a versioned fixture, captured from a
|
|
10
|
+
* GENUINELY EXHAUSTED subscription, proves the exact bytes. A build with
|
|
11
|
+
* no fixture for a (provider, version) can therefore NEVER return an
|
|
12
|
+
* eligible class — so it can never authorize a paid fallback. A
|
|
13
|
+
* successful run cannot establish the exhausted shape; only real
|
|
14
|
+
* exhaustion can, and the plane cannot manufacture it.
|
|
15
|
+
*
|
|
16
|
+
* Precedence (C5), applied by the classifier:
|
|
17
|
+
* - A present STRUCTURAL FAILURE terminal blocks success ingestion even
|
|
18
|
+
* on exit 0 (that is the parser's job; this module reads the record).
|
|
19
|
+
* - Only an ALLOWLISTED, version+auth-specific pattern yields an ELIGIBLE
|
|
20
|
+
* class. Exit code, bare rate-limit prose, timeout, notFound, stderr,
|
|
21
|
+
* and zero tokens NEVER independently establish exhaustion.
|
|
22
|
+
* - Everything unmatched is `unknown` — the ordinary failure road.
|
|
23
|
+
*/
|
|
24
|
+
import type { ProviderId } from "./provider.js";
|
|
25
|
+
export type TerminalClass =
|
|
26
|
+
/** The subscription/plan usage cap is spent — FALLBACK-ELIGIBLE. */
|
|
27
|
+
"usage-exhausted"
|
|
28
|
+
/** An API-key account's paid credits/quota are gone — FALLBACK-ELIGIBLE. */
|
|
29
|
+
| "credits-depleted"
|
|
30
|
+
/** Temporary throttling NOT tied to the usage cap — backoff, NEVER paid fallback. */
|
|
31
|
+
| "transient-throttle"
|
|
32
|
+
/** A definite non-exhaustion terminal (ordinary failure). */
|
|
33
|
+
| "not-exhausted"
|
|
34
|
+
/** No structural signal matched — the ordinary failure/strike road. */
|
|
35
|
+
| "unknown";
|
|
36
|
+
/** The two classes that may authorize a fallback advance. */
|
|
37
|
+
export declare const FALLBACK_ELIGIBLE: ReadonlySet<TerminalClass>;
|
|
38
|
+
export declare function isFallbackEligible(cls: TerminalClass): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* The structural terminal a provider's parser retained — the honest input
|
|
41
|
+
* to classification. `failed` marks a structural FAILURE terminal (codex
|
|
42
|
+
* turn.failed, a gemini error terminal): its presence blocks success
|
|
43
|
+
* ingestion regardless of exit code. `text` is the bounded terminal
|
|
44
|
+
* message; `code` its machine code if the harness typed one.
|
|
45
|
+
*/
|
|
46
|
+
export type StructuralTerminal = {
|
|
47
|
+
failed: boolean;
|
|
48
|
+
text: string | null;
|
|
49
|
+
code: string | null;
|
|
50
|
+
};
|
|
51
|
+
/** Whether THIS build carries a fixture-backed recognizer for a
|
|
52
|
+
* (provider, version). The C8 gate consults this at every authority
|
|
53
|
+
* point — not only at classification — so a downgrade to an unfixtured
|
|
54
|
+
* build severs any in-flight fallback authority. */
|
|
55
|
+
export declare function hasRecognizer(provider: ProviderId, version: string | null): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* The EXACT C8 capability check (Codex E2/E3 review, finding 8): whether
|
|
58
|
+
* this build can recognize the specific eligible class an AUTH MODE would
|
|
59
|
+
* produce — a subscription's `usage-exhausted` needs a nonempty
|
|
60
|
+
* eligibleUsage set; an api-key account's `credits-depleted` needs a
|
|
61
|
+
* nonempty eligibleCredits set. `hasRecognizer` (any-eligible) is too coarse
|
|
62
|
+
* at the authority point: a version fixtured for usage only must NOT
|
|
63
|
+
* authorize a credits-depleted advance.
|
|
64
|
+
*/
|
|
65
|
+
export declare function recognizesEligible(provider: ProviderId, version: string | null, authMode: "subscription" | "api-key"): boolean;
|
|
66
|
+
/** The eligible class an auth mode can legitimately carry — the C8
|
|
67
|
+
* consistency invariant: `usage-exhausted` iff subscription,
|
|
68
|
+
* `credits-depleted` iff api-key. A stamp that violates this pairing is a
|
|
69
|
+
* bad/overwritten record and must never advance. */
|
|
70
|
+
export declare function classMatchesAuthMode(cls: TerminalClass, authMode: "subscription" | "api-key"): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Classify a finished attempt. Fail closed: no recognizer for this exact
|
|
73
|
+
* (provider, version) => never an eligible class. `authMode` decides which
|
|
74
|
+
* eligible class a match yields — a subscription that hits its cap is
|
|
75
|
+
* `usage-exhausted`; an api-key account out of credits is
|
|
76
|
+
* `credits-depleted`. A structural failure with no eligible/transient
|
|
77
|
+
* match is `not-exhausted`; no structural failure and no match is
|
|
78
|
+
* `unknown`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function classifyTerminal(args: {
|
|
81
|
+
provider: ProviderId;
|
|
82
|
+
version: string | null;
|
|
83
|
+
authMode: "subscription" | "api-key";
|
|
84
|
+
terminal: StructuralTerminal | null;
|
|
85
|
+
}): TerminalClass;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The terminal exhaustion taxonomy (fallback chains, R1/C5/C8 of the
|
|
3
|
+
* approved design). A finished attempt is classified into ONE of these,
|
|
4
|
+
* where the evidence still exists — the provider adapter's structural
|
|
5
|
+
* record plus the gateway's authoritative CLI version and auth mode —
|
|
6
|
+
* NEVER in disposal, by which time the structural signal is gone.
|
|
7
|
+
*
|
|
8
|
+
* The whole feature is FAIL CLOSED by construction: a recognizer's
|
|
9
|
+
* eligible-signal set is EMPTY until a versioned fixture, captured from a
|
|
10
|
+
* GENUINELY EXHAUSTED subscription, proves the exact bytes. A build with
|
|
11
|
+
* no fixture for a (provider, version) can therefore NEVER return an
|
|
12
|
+
* eligible class — so it can never authorize a paid fallback. A
|
|
13
|
+
* successful run cannot establish the exhausted shape; only real
|
|
14
|
+
* exhaustion can, and the plane cannot manufacture it.
|
|
15
|
+
*
|
|
16
|
+
* Precedence (C5), applied by the classifier:
|
|
17
|
+
* - A present STRUCTURAL FAILURE terminal blocks success ingestion even
|
|
18
|
+
* on exit 0 (that is the parser's job; this module reads the record).
|
|
19
|
+
* - Only an ALLOWLISTED, version+auth-specific pattern yields an ELIGIBLE
|
|
20
|
+
* class. Exit code, bare rate-limit prose, timeout, notFound, stderr,
|
|
21
|
+
* and zero tokens NEVER independently establish exhaustion.
|
|
22
|
+
* - Everything unmatched is `unknown` — the ordinary failure road.
|
|
23
|
+
*/
|
|
24
|
+
/** The two classes that may authorize a fallback advance. */
|
|
25
|
+
export const FALLBACK_ELIGIBLE = new Set([
|
|
26
|
+
"usage-exhausted",
|
|
27
|
+
"credits-depleted",
|
|
28
|
+
]);
|
|
29
|
+
export function isFallbackEligible(cls) {
|
|
30
|
+
return FALLBACK_ELIGIBLE.has(cls);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The registry. EVERY entry ships empty (fail closed). A real fixture,
|
|
34
|
+
* once captured from a genuinely exhausted subscription and reviewed,
|
|
35
|
+
* adds the exact patterns under that provider+version — and ONLY then can
|
|
36
|
+
* that (provider, version) ever return an eligible class.
|
|
37
|
+
*
|
|
38
|
+
* The outer key is the provider; the inner key is the exact CLI version
|
|
39
|
+
* string the gateway proved at spawn (never a range — a version this
|
|
40
|
+
* build has no fixture for is unrecognized, so fail closed).
|
|
41
|
+
*/
|
|
42
|
+
const RECOGNIZERS = {
|
|
43
|
+
claude: {},
|
|
44
|
+
codex: {},
|
|
45
|
+
openrouter: {},
|
|
46
|
+
gemini: {},
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* The recognizer lookup. Reads ONLY the module-level RECOGNIZERS registry —
|
|
50
|
+
* there is NO mutation surface, so no build (production or otherwise) can
|
|
51
|
+
* install a recognizer at runtime; a real fixture arrives as a source edit,
|
|
52
|
+
* reviewed in a text diff (Codex E2/E3 review, finding 1). The suite proves
|
|
53
|
+
* the eligible path by MOCKING this module, never by a shipped seam.
|
|
54
|
+
* Object.hasOwn keeps the lookup TOTAL for adversarial version strings
|
|
55
|
+
* (foundation review, finding 3): "__proto__" / "constructor" / "toString"
|
|
56
|
+
* resolve to "no recognizer", never an inherited property.
|
|
57
|
+
*/
|
|
58
|
+
function recognizersFromRegistry(provider, version) {
|
|
59
|
+
if (!Object.hasOwn(RECOGNIZERS[provider], version))
|
|
60
|
+
return undefined;
|
|
61
|
+
return RECOGNIZERS[provider][version];
|
|
62
|
+
}
|
|
63
|
+
/** Whether THIS build carries a fixture-backed recognizer for a
|
|
64
|
+
* (provider, version). The C8 gate consults this at every authority
|
|
65
|
+
* point — not only at classification — so a downgrade to an unfixtured
|
|
66
|
+
* build severs any in-flight fallback authority. */
|
|
67
|
+
export function hasRecognizer(provider, version) {
|
|
68
|
+
if (version === null)
|
|
69
|
+
return false;
|
|
70
|
+
const perVersion = recognizersFromRegistry(provider, version);
|
|
71
|
+
if (perVersion === undefined)
|
|
72
|
+
return false;
|
|
73
|
+
return perVersion.eligibleUsage.length > 0 || perVersion.eligibleCredits.length > 0;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The EXACT C8 capability check (Codex E2/E3 review, finding 8): whether
|
|
77
|
+
* this build can recognize the specific eligible class an AUTH MODE would
|
|
78
|
+
* produce — a subscription's `usage-exhausted` needs a nonempty
|
|
79
|
+
* eligibleUsage set; an api-key account's `credits-depleted` needs a
|
|
80
|
+
* nonempty eligibleCredits set. `hasRecognizer` (any-eligible) is too coarse
|
|
81
|
+
* at the authority point: a version fixtured for usage only must NOT
|
|
82
|
+
* authorize a credits-depleted advance.
|
|
83
|
+
*/
|
|
84
|
+
export function recognizesEligible(provider, version, authMode) {
|
|
85
|
+
if (version === null)
|
|
86
|
+
return false;
|
|
87
|
+
const perVersion = recognizersFromRegistry(provider, version);
|
|
88
|
+
if (perVersion === undefined)
|
|
89
|
+
return false;
|
|
90
|
+
return authMode === "subscription" ? perVersion.eligibleUsage.length > 0 : perVersion.eligibleCredits.length > 0;
|
|
91
|
+
}
|
|
92
|
+
/** The eligible class an auth mode can legitimately carry — the C8
|
|
93
|
+
* consistency invariant: `usage-exhausted` iff subscription,
|
|
94
|
+
* `credits-depleted` iff api-key. A stamp that violates this pairing is a
|
|
95
|
+
* bad/overwritten record and must never advance. */
|
|
96
|
+
export function classMatchesAuthMode(cls, authMode) {
|
|
97
|
+
if (cls === "usage-exhausted")
|
|
98
|
+
return authMode === "subscription";
|
|
99
|
+
if (cls === "credits-depleted")
|
|
100
|
+
return authMode === "api-key";
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Classify a finished attempt. Fail closed: no recognizer for this exact
|
|
105
|
+
* (provider, version) => never an eligible class. `authMode` decides which
|
|
106
|
+
* eligible class a match yields — a subscription that hits its cap is
|
|
107
|
+
* `usage-exhausted`; an api-key account out of credits is
|
|
108
|
+
* `credits-depleted`. A structural failure with no eligible/transient
|
|
109
|
+
* match is `not-exhausted`; no structural failure and no match is
|
|
110
|
+
* `unknown`.
|
|
111
|
+
*/
|
|
112
|
+
export function classifyTerminal(args) {
|
|
113
|
+
const { provider, version, authMode, terminal } = args;
|
|
114
|
+
if (terminal === null)
|
|
115
|
+
return "unknown";
|
|
116
|
+
// The classifier's contract permits failed:false, but a non-failure
|
|
117
|
+
// terminal is never exhaustion (Codex foundation review, finding 4):
|
|
118
|
+
// only a structural FAILURE terminal is even eligible for matching.
|
|
119
|
+
if (terminal.failed !== true)
|
|
120
|
+
return "unknown";
|
|
121
|
+
const perVersion = version === null ? undefined : recognizersFromRegistry(provider, version);
|
|
122
|
+
const haystack = `${terminal.code ?? ""}\n${terminal.text ?? ""}`;
|
|
123
|
+
if (perVersion !== undefined) {
|
|
124
|
+
// Transient throttle is checked FIRST so a throttle can never be read
|
|
125
|
+
// as exhaustion (Claude's "temporarily limiting requests — not your
|
|
126
|
+
// usage limit" family).
|
|
127
|
+
if (perVersion.transient.some(re => re.test(haystack)))
|
|
128
|
+
return "transient-throttle";
|
|
129
|
+
// Then the eligible sets, gated by auth mode.
|
|
130
|
+
if (authMode === "subscription" && perVersion.eligibleUsage.some(re => re.test(haystack))) {
|
|
131
|
+
return "usage-exhausted";
|
|
132
|
+
}
|
|
133
|
+
if (authMode === "api-key" && perVersion.eligibleCredits.some(re => re.test(haystack))) {
|
|
134
|
+
return "credits-depleted";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// A structural FAILURE terminal that matched nothing is a definite
|
|
138
|
+
// non-exhaustion terminal (a non-failure terminal already returned
|
|
139
|
+
// unknown above).
|
|
140
|
+
return "not-exhausted";
|
|
141
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings → Data (v105): an instance operator downloads everything Standing
|
|
3
|
+
* Orders knows as one .zip. One form: the password, typed again, and a button.
|
|
4
|
+
*/
|
|
5
|
+
const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
6
|
+
export const EXPORT_CSS = `.data-export{max-width:720px;min-width:0}.data-export label{display:grid;gap:4px;margin:14px 0 0;font-size:.875rem}` +
|
|
7
|
+
`.data-export input[type=password]{width:100%;max-width:360px;box-sizing:border-box}.data-export button[type=submit]{margin-top:14px;min-height:44px;white-space:nowrap}`;
|
|
8
|
+
export function dataExportHtml(csrf, notice) {
|
|
9
|
+
const note = notice.problem ? `<p class="problem" role="alert">${e(notice.problem)}</p>` : "";
|
|
10
|
+
return `<section class="data-export">${note}` +
|
|
11
|
+
`<p>Everything Toolroll knows, as one .zip: projects, tasks, runs and cost, the action ledger, evidence packs, chats, flows, teammates and settings. ` +
|
|
12
|
+
`Passwords, keys and tokens are never included.</p>` +
|
|
13
|
+
`<form method="post" action="/settings/data"><input type="hidden" name="csrf" value="${e(csrf)}">` +
|
|
14
|
+
`<label>Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label>` +
|
|
15
|
+
`<button type="submit">Download export</button></form>` +
|
|
16
|
+
`<p class="meta">The same export from the command line: <code>toolroll export --out <path> [--zip]</code></p></section>`;
|
|
17
|
+
}
|
package/dist/export.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Store } from "./store.js";
|
|
2
|
+
export declare const EXPORT_FORMAT = "standing-orders/export/v1";
|
|
3
|
+
export type ExportFile = {
|
|
4
|
+
path: string;
|
|
5
|
+
data: Buffer;
|
|
6
|
+
};
|
|
7
|
+
export type ManifestEntry = {
|
|
8
|
+
path: string;
|
|
9
|
+
sha256: string;
|
|
10
|
+
bytes: number;
|
|
11
|
+
rows?: number;
|
|
12
|
+
};
|
|
13
|
+
export type ExportManifest = {
|
|
14
|
+
format: typeof EXPORT_FORMAT;
|
|
15
|
+
generatedAt: string;
|
|
16
|
+
generatedBy: string;
|
|
17
|
+
schemaVersion: number;
|
|
18
|
+
files: ManifestEntry[];
|
|
19
|
+
/** What was left out on purpose, so a reader knows it wasn't lost. */
|
|
20
|
+
excluded: {
|
|
21
|
+
tables: string[];
|
|
22
|
+
columns: string[];
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export type FullExport = {
|
|
26
|
+
root: string;
|
|
27
|
+
files: ExportFile[];
|
|
28
|
+
manifest: ExportManifest;
|
|
29
|
+
tables: number;
|
|
30
|
+
packs: number;
|
|
31
|
+
};
|
|
32
|
+
/** Where a table's file goes: by what it's about. Anything new lands in "other", never nowhere. */
|
|
33
|
+
export declare function categoryOf(table: string): string;
|
|
34
|
+
/** Every key- or token-shaped run in `text` replaced by "[redacted]". */
|
|
35
|
+
export declare function redactKeyShapes(text: string): string;
|
|
36
|
+
/** The whole export, in memory: the files, the manifest and README among them. */
|
|
37
|
+
export declare function buildExport(store: Store, options: {
|
|
38
|
+
who: string;
|
|
39
|
+
now: Date;
|
|
40
|
+
evidenceRoot: string;
|
|
41
|
+
configDir: string | null;
|
|
42
|
+
}): FullExport;
|
|
43
|
+
/** Write the export as a new folder at `out` (its parent must exist; it must not). Files are readable by their owner only. */
|
|
44
|
+
export declare function writeExportFolder(out: string, exported: FullExport): void;
|
|
45
|
+
/** The same files as one .zip (deflated, inside a folder named for the export). */
|
|
46
|
+
export declare function exportZip(exported: FullExport): Buffer;
|
|
47
|
+
/** One line for the ledger and the person who asked. */
|
|
48
|
+
export declare function exportSummary(exported: FullExport): string;
|
package/dist/export.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full export (v105): everything Toolroll knows, for an instance
|
|
3
|
+
* operator to take away — every table of the database as JSON Lines, grouped
|
|
4
|
+
* by what it's about (projects, tasks, runs, the ledger, chats, flows,
|
|
5
|
+
* teammates, people, settings), an evidence pack per task, the settings kept
|
|
6
|
+
* in files beside the database, a README explaining the layout, and a
|
|
7
|
+
* manifest with each file's SHA-256. One folder, or the same files in a .zip.
|
|
8
|
+
*
|
|
9
|
+
* Secrets never leave: tables that are nothing but secrets (sessions,
|
|
10
|
+
* pairing codes, nonces) are skipped, columns that hold one (password and
|
|
11
|
+
* token hashes, button tokens, push keys, webhook secrets) are dropped, a
|
|
12
|
+
* column whose name looks like a secret and that nobody has reviewed is
|
|
13
|
+
* dropped too, and any value shaped like a key or token is replaced by
|
|
14
|
+
* "[redacted]". Provider keys and file-kept secrets are never read.
|
|
15
|
+
*
|
|
16
|
+
* Not included: artifact bodies (logs, diffs, screenshots), which stay in
|
|
17
|
+
* the evidence folder; their records (size, SHA-256) are in runs/artifact.
|
|
18
|
+
*/
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
import { closeSync, constants, fsyncSync, mkdirSync, openSync, writeSync } from "node:fs";
|
|
21
|
+
import { dirname, join } from "node:path";
|
|
22
|
+
import { crc32, deflateRawSync } from "node:zlib";
|
|
23
|
+
import { SCHEMA_VERSION } from "./store.js";
|
|
24
|
+
import { evidencePack } from "./evidence-pack.js";
|
|
25
|
+
import { SECRET_PATTERNS } from "./evidence.js";
|
|
26
|
+
import { origin, readMonitoring } from "./monitoring-settings.js";
|
|
27
|
+
import { readSsoSettings } from "./sso-settings.js";
|
|
28
|
+
import { readEmailSettings } from "./email-settings.js";
|
|
29
|
+
import { SUBSCRIPTION_CAPABLE, readAuthMode } from "./keys.js";
|
|
30
|
+
export const EXPORT_FORMAT = "standing-orders/export/v1";
|
|
31
|
+
/** Tables that hold nothing but secrets or short-lived sign-in material, and derived search indexes. */
|
|
32
|
+
const SECRET_TABLES = new Set(["web_session", "ceremony_nonce", "telegram_pairing", "slack_pair", "discord_pair", "teams_pair"]);
|
|
33
|
+
const DERIVED_TABLE = /^(sqlite_|memory_search)/;
|
|
34
|
+
/** Columns that hold a secret (or what stands in for one): never exported. */
|
|
35
|
+
const SECRET_COLUMNS = new Set([
|
|
36
|
+
"api_token.secret_hash", "approver.credential_hash", "coordinator_credential.credential_hash", "runner.credential_hash", "invite.token_hash",
|
|
37
|
+
"flow_trigger.hook_hash", "held_session.cookie", "push_subscription.endpoint", "push_subscription.p256dh", "push_subscription.auth",
|
|
38
|
+
"chat_turn.credential_key", "mate_session.credential_key", "mate_turn.credential_key", "bridge_lease.push_url", "workflow_preview.token",
|
|
39
|
+
"quota.credential_fp",
|
|
40
|
+
]);
|
|
41
|
+
/** A column named like this holds a secret unless it is reviewed below; an unreviewed one is dropped. */
|
|
42
|
+
const SECRET_NAME = /hash|secret|token|passw|cookie|csrf|credential|p256dh|^auth$|key|nonce|endpoint|url/i;
|
|
43
|
+
/** Reviewed: named like a secret, but it isn't one (a seal, a digest, a lookup name, an address with no key). */
|
|
44
|
+
const REVIEWED_COLUMNS = new Set([
|
|
45
|
+
"artifact.key", "budget.scope_key", "mate_thread.scope_key", "diff_comment.source_key", "discord_meta.key", "slack_meta.key", "teams_meta.key",
|
|
46
|
+
"flow_trigger_event.key", "installation_fact.key", "mcp_idempotency.key", "memory_gap.key", "mutation.idempotency_key", "notification.dedupe_key",
|
|
47
|
+
"service_cursor.key", "ledger_checkpoint.hash", "ledger_seal.hash", "merge_intent.grant_terms_hash", "plan_revision.parent_hash",
|
|
48
|
+
"publication.body_hash", "publication.pr_url", "team_message.payload_hash", "team_request.payload_hash", "backend_grant.credential_scope",
|
|
49
|
+
]);
|
|
50
|
+
/** Token counts are usage, not tokens. */
|
|
51
|
+
const USAGE_COLUMN = /(^|_)tokens(_|$)|output_tokens/;
|
|
52
|
+
/** Where a table's file goes: by what it's about. Anything new lands in "other", never nowhere. */
|
|
53
|
+
export function categoryOf(table) {
|
|
54
|
+
const rules = [
|
|
55
|
+
[/^(action_ledger|ledger_seal|ledger_checkpoint|sync_ledger)$/, "ledger"],
|
|
56
|
+
[/^teammate/, "teammates"],
|
|
57
|
+
[/^(flow|routine|workflow_)/, "flows"],
|
|
58
|
+
[/^(chat_|mate_|team_|telegram_|slack_|discord_|teams_|notification|push_|bridge_lease)/, "chats"],
|
|
59
|
+
[/^(approver|api_token|invite|sso_identity|coordinator_)/, "people"],
|
|
60
|
+
[/^(run|artifact|claim|worktree$|execution_slot|contest|tournament_terms|fallback_cycle|fallback_transition|held_session|session_turn|attended_authorization|criterion_review|diff_comment|proof_|review_request|repair_chain|incident|publication$|merge_|side_spend|knowledge_snapshot|learning_snapshot|skill_snapshot)/, "runs"],
|
|
61
|
+
[/^(task|hold$|plan_|scope_|tool_seal|decision|external_|skill_test)/, "tasks"],
|
|
62
|
+
[/^(project|approval_policy|capability|verify_command|worktree_setup|backend_grant|intake_grant|publication_grant|operating_mode|knowledge_|learning_|memory_|skill_)/, "projects"],
|
|
63
|
+
[/(_config|_default|_defaults)$|^(budget|model_|provider_|installation_fact|runtime_check|monitoring_status|quota|mode_rail|schema_version)/, "settings"],
|
|
64
|
+
];
|
|
65
|
+
return rules.find(([pattern]) => pattern.test(table))?.[1] ?? "other";
|
|
66
|
+
}
|
|
67
|
+
/** Extra shapes beside the evidence scanner's: this installation's own tokens and password hashes, and bearer headers. */
|
|
68
|
+
const EXTRA_SHAPES = [
|
|
69
|
+
/\bso_[a-f0-9]{12}_[A-Za-z0-9_-]{43}/g,
|
|
70
|
+
/\bscrypt\$[^\s"',;]+/g,
|
|
71
|
+
/\bBearer\s+[A-Za-z0-9._~+/-]{16,}=*/gi,
|
|
72
|
+
/\bsk-[A-Za-z0-9_-]{20,}/g,
|
|
73
|
+
/\bxapp-[A-Za-z0-9-]{10,}/g,
|
|
74
|
+
/\blin_(?:api|wh)_[A-Za-z0-9]{20,}/g,
|
|
75
|
+
];
|
|
76
|
+
/** A whole private key, header to footer (or to the end of the text): it goes first, before the scanner's header-only
|
|
77
|
+
* shape can take the header and leave the key's body behind. */
|
|
78
|
+
const PRIVATE_KEY_BLOCK = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g;
|
|
79
|
+
const SHAPES = [PRIVATE_KEY_BLOCK, ...SECRET_PATTERNS.map(({ pattern }) => new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`)), ...EXTRA_SHAPES];
|
|
80
|
+
/** Every key- or token-shaped run in `text` replaced by "[redacted]". */
|
|
81
|
+
export function redactKeyShapes(text) {
|
|
82
|
+
let out = text;
|
|
83
|
+
for (const shape of SHAPES)
|
|
84
|
+
out = out.replace(shape, "[redacted]");
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
function cleanValue(value) {
|
|
88
|
+
if (typeof value === "string")
|
|
89
|
+
return redactKeyShapes(value);
|
|
90
|
+
if (value instanceof Uint8Array)
|
|
91
|
+
return { base64: Buffer.from(value).toString("base64") };
|
|
92
|
+
if (typeof value === "bigint")
|
|
93
|
+
return value.toString();
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
const fileName = (value) => value.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "_").slice(0, 120) || "_";
|
|
97
|
+
const sha256 = (data) => createHash("sha256").update(data).digest("hex");
|
|
98
|
+
/** The whole export, in memory: the files, the manifest and README among them. */
|
|
99
|
+
export function buildExport(store, options) {
|
|
100
|
+
const db = store.handle;
|
|
101
|
+
const stamp = options.now.toISOString().replace(/[:.]/g, "-");
|
|
102
|
+
const root = `standing-orders-export-${stamp}`;
|
|
103
|
+
const files = [];
|
|
104
|
+
const entries = [];
|
|
105
|
+
const add = (path, data, rows) => { files.push({ path, data }); entries.push({ path, sha256: sha256(data), bytes: data.length, ...(rows === undefined ? {} : { rows }) }); };
|
|
106
|
+
const excludedTables = [], excludedColumns = [];
|
|
107
|
+
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name").all().map(one => one.name);
|
|
108
|
+
let written = 0;
|
|
109
|
+
for (const table of tables) {
|
|
110
|
+
if (DERIVED_TABLE.test(table))
|
|
111
|
+
continue;
|
|
112
|
+
if (SECRET_TABLES.has(table)) {
|
|
113
|
+
excludedTables.push(table);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const columns = db.prepare(`PRAGMA table_info("${table.replace(/"/g, '""')}")`).all().map(one => one.name);
|
|
117
|
+
const kept = columns.filter(column => {
|
|
118
|
+
const name = `${table}.${column}`;
|
|
119
|
+
const secret = SECRET_COLUMNS.has(name) || (SECRET_NAME.test(column) && !USAGE_COLUMN.test(column) && !REVIEWED_COLUMNS.has(name));
|
|
120
|
+
if (secret)
|
|
121
|
+
excludedColumns.push(name);
|
|
122
|
+
return !secret;
|
|
123
|
+
});
|
|
124
|
+
if (kept.length === 0) {
|
|
125
|
+
excludedTables.push(table);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const lines = [];
|
|
129
|
+
const select = `SELECT ${kept.map(column => `"${column.replace(/"/g, '""')}"`).join(", ")} FROM "${table.replace(/"/g, '""')}" ORDER BY rowid`;
|
|
130
|
+
let rows;
|
|
131
|
+
// A table without rowids keeps its own order.
|
|
132
|
+
try {
|
|
133
|
+
rows = db.prepare(select).all();
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
rows = db.prepare(select.replace(/ ORDER BY rowid$/, "")).all();
|
|
137
|
+
}
|
|
138
|
+
for (const row of rows) {
|
|
139
|
+
const clean = {};
|
|
140
|
+
for (const column of kept)
|
|
141
|
+
clean[column] = cleanValue(row[column]);
|
|
142
|
+
lines.push(JSON.stringify(clean));
|
|
143
|
+
}
|
|
144
|
+
add(`${categoryOf(table)}/${table}.jsonl`, Buffer.from(lines.length === 0 ? "" : `${lines.join("\n")}\n`, "utf8"), lines.length);
|
|
145
|
+
written++;
|
|
146
|
+
}
|
|
147
|
+
// An evidence pack per task: the task and each revision of it, their terms, approvals, runs, cost and ledger entries.
|
|
148
|
+
const chain = store.ledgerChain({ full: true });
|
|
149
|
+
const access = { principal: "operator", repos: null, includeUnplaced: true };
|
|
150
|
+
const packed = new Set(), roots = new Set(), names = new Set();
|
|
151
|
+
let packs = 0;
|
|
152
|
+
for (const { id } of db.prepare("SELECT id FROM task ORDER BY created_at, id").all()) {
|
|
153
|
+
if (packed.has(id))
|
|
154
|
+
continue;
|
|
155
|
+
packed.add(id);
|
|
156
|
+
const family = store.taskFamilyOf(id, null, true);
|
|
157
|
+
if (family === null || roots.has(family.root.id))
|
|
158
|
+
continue;
|
|
159
|
+
roots.add(family.root.id);
|
|
160
|
+
for (const version of family.versions)
|
|
161
|
+
packed.add(version.id);
|
|
162
|
+
const pack = evidencePack(store, family.root.id, access, options.who, options.now, options.evidenceRoot, chain);
|
|
163
|
+
if (pack === null)
|
|
164
|
+
continue;
|
|
165
|
+
let name = fileName(family.root.id);
|
|
166
|
+
for (let n = 2; names.has(name); n++)
|
|
167
|
+
name = `${fileName(family.root.id)}-${n}`;
|
|
168
|
+
names.add(name);
|
|
169
|
+
add(`evidence-packs/${name}.json`, Buffer.from(`${redactKeyShapes(JSON.stringify(pack, null, 2))}\n`, "utf8"));
|
|
170
|
+
packs++;
|
|
171
|
+
}
|
|
172
|
+
// Settings kept in files beside the database: what they are set to, never their secrets.
|
|
173
|
+
add("settings/files.json", Buffer.from(`${JSON.stringify(fileSettings(options.configDir), null, 2)}\n`, "utf8"));
|
|
174
|
+
add("README.md", Buffer.from(readme(options.now, options.who), "utf8"));
|
|
175
|
+
const manifest = {
|
|
176
|
+
format: EXPORT_FORMAT, generatedAt: options.now.toISOString(), generatedBy: options.who, schemaVersion: SCHEMA_VERSION,
|
|
177
|
+
files: entries, excluded: { tables: excludedTables, columns: excludedColumns },
|
|
178
|
+
};
|
|
179
|
+
files.push({ path: "manifest.json", data: Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`, "utf8") });
|
|
180
|
+
return { root, files, manifest, tables: written, packs };
|
|
181
|
+
}
|
|
182
|
+
/** The settings kept in files (monitoring, sign-in, email, how each provider bills), secrets left out. */
|
|
183
|
+
function fileSettings(dir) {
|
|
184
|
+
const monitoring = readMonitoring(dir);
|
|
185
|
+
const sso = readSsoSettings(dir);
|
|
186
|
+
const email = readEmailSettings(dir);
|
|
187
|
+
const billing = {};
|
|
188
|
+
for (const provider of Object.keys(SUBSCRIPTION_CAPABLE))
|
|
189
|
+
billing[provider] = readAuthMode(provider);
|
|
190
|
+
return {
|
|
191
|
+
monitoring: {
|
|
192
|
+
// A webhook or collector address may carry a key in its path or query: only where it points.
|
|
193
|
+
webhook: monitoring.webhook === null ? null : { origin: origin(monitoring.webhook.url) },
|
|
194
|
+
folder: monitoring.folder,
|
|
195
|
+
traces: monitoring.traces === null ? null : { origin: origin(monitoring.traces.endpoint), header: monitoring.traces.header?.name ?? null },
|
|
196
|
+
},
|
|
197
|
+
signIn: sso === null ? null : { issuer: sso.issuer, clientId: sso.clientId, label: sso.label, scopes: sso.scopes, groupsClaim: sso.groupsClaim, rules: sso.rules, passwords: sso.passwords },
|
|
198
|
+
email: email === null ? null : { host: email.host, port: email.port, secure: email.secure, user: email.user, from: email.from, imap: email.imap },
|
|
199
|
+
providerBilling: billing,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function readme(now, who) {
|
|
203
|
+
return `# Toolroll export
|
|
204
|
+
|
|
205
|
+
Everything this installation knew on ${now.toISOString().slice(0, 16).replace("T", " ")} UTC, exported by ${who}.
|
|
206
|
+
|
|
207
|
+
## Layout
|
|
208
|
+
|
|
209
|
+
- \`manifest.json\`: every other file, with its size and SHA-256. Check a file with \`shasum -a 256 <file>\`.
|
|
210
|
+
- \`projects/\`: projects, their approval rules, checks, grants, knowledge, lessons and skills.
|
|
211
|
+
- \`tasks/\`: tasks and their versions (\`task_ref.revision_of\`), scopes and approvals (\`task_scope\`, \`scope_approval_vote\`), plans, holds and decisions.
|
|
212
|
+
- \`runs/\`: agent runs with usage and cost (\`run\`, \`run_spend\`), their records of artifacts, proofs, reviews and publications.
|
|
213
|
+
- \`ledger/\`: the action ledger (\`action_ledger\`), each entry's seal (\`ledger_seal\`) and the checkpoints (\`ledger_checkpoint\`).
|
|
214
|
+
- \`evidence-packs/\`: one JSON file per task: who asked, the exact terms and who approved them, runs and cost, checks, completion and its ledger entries.
|
|
215
|
+
- \`chats/\`: conversations with the lead and teammates, and Telegram, Slack, Discord and Teams messages and notifications.
|
|
216
|
+
- \`flows/\`: flows, their cards, scripts and triggers, routines and saved recipes.
|
|
217
|
+
- \`teammates/\`: teammates, their versions, memory, tools and turns.
|
|
218
|
+
- \`people/\`: accounts, API token names and invitations (no passwords or tokens).
|
|
219
|
+
- \`settings/\`: models, budgets, spend and permission defaults, provider readings; \`files.json\` holds the settings kept in files.
|
|
220
|
+
- \`other/\`: everything else the database keeps (workers, leases, queues).
|
|
221
|
+
|
|
222
|
+
Each \`.jsonl\` file is one database table: one JSON object per line, one row each. A binary value is \`{"base64": "..."}\`.
|
|
223
|
+
|
|
224
|
+
## What is left out
|
|
225
|
+
|
|
226
|
+
No password, password hash, API key, token or webhook secret is included. \`manifest.json\` lists the tables and columns
|
|
227
|
+
left out for that reason. Any value shaped like a key or token is replaced by \`[redacted]\`; a ledger entry changed that
|
|
228
|
+
way no longer matches its seal. Artifact contents (logs, diffs, screenshots) stay in the evidence folder; their records,
|
|
229
|
+
with sizes and SHA-256, are in \`runs/artifact.jsonl\`.
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
/** Write the export as a new folder at `out` (its parent must exist; it must not). Files are readable by their owner only. */
|
|
233
|
+
export function writeExportFolder(out, exported) {
|
|
234
|
+
mkdirSync(out, { mode: 0o700 });
|
|
235
|
+
for (const file of exported.files) {
|
|
236
|
+
const target = join(out, file.path);
|
|
237
|
+
mkdirSync(dirname(target), { recursive: true, mode: 0o700 });
|
|
238
|
+
const handle = openSync(target, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
239
|
+
try {
|
|
240
|
+
writeSync(handle, file.data);
|
|
241
|
+
fsyncSync(handle);
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
closeSync(handle);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** The same files as one .zip (deflated, inside a folder named for the export). */
|
|
249
|
+
export function exportZip(exported) {
|
|
250
|
+
const local = [], central = [];
|
|
251
|
+
let offset = 0;
|
|
252
|
+
const at = new Date(exported.manifest.generatedAt);
|
|
253
|
+
const time = (at.getUTCHours() << 11) | (at.getUTCMinutes() << 5) | Math.floor(at.getUTCSeconds() / 2);
|
|
254
|
+
const date = ((Math.max(1980, at.getUTCFullYear()) - 1980) << 9) | ((at.getUTCMonth() + 1) << 5) | at.getUTCDate();
|
|
255
|
+
if (exported.files.length > 0xffff)
|
|
256
|
+
throw new Error("Too many files for one .zip; export to a folder instead.");
|
|
257
|
+
for (const file of exported.files) {
|
|
258
|
+
const name = Buffer.from(`${exported.root}/${file.path}`, "utf8");
|
|
259
|
+
const packed = deflateRawSync(file.data);
|
|
260
|
+
const crc = crc32(file.data);
|
|
261
|
+
if (offset + packed.length + 30 + name.length > 0xffffffff || file.data.length > 0xffffffff)
|
|
262
|
+
throw new Error("The export is too large for one .zip; export to a folder instead.");
|
|
263
|
+
const head = Buffer.alloc(30);
|
|
264
|
+
head.writeUInt32LE(0x04034b50, 0);
|
|
265
|
+
head.writeUInt16LE(20, 4);
|
|
266
|
+
head.writeUInt16LE(0x0800, 6);
|
|
267
|
+
head.writeUInt16LE(8, 8);
|
|
268
|
+
head.writeUInt16LE(time, 10);
|
|
269
|
+
head.writeUInt16LE(date, 12);
|
|
270
|
+
head.writeUInt32LE(crc, 14);
|
|
271
|
+
head.writeUInt32LE(packed.length, 18);
|
|
272
|
+
head.writeUInt32LE(file.data.length, 22);
|
|
273
|
+
head.writeUInt16LE(name.length, 26);
|
|
274
|
+
head.writeUInt16LE(0, 28);
|
|
275
|
+
const entry = Buffer.alloc(46);
|
|
276
|
+
entry.writeUInt32LE(0x02014b50, 0);
|
|
277
|
+
entry.writeUInt16LE(0x031e, 4);
|
|
278
|
+
entry.writeUInt16LE(20, 6);
|
|
279
|
+
entry.writeUInt16LE(0x0800, 8);
|
|
280
|
+
entry.writeUInt16LE(8, 10);
|
|
281
|
+
entry.writeUInt16LE(time, 12);
|
|
282
|
+
entry.writeUInt16LE(date, 14);
|
|
283
|
+
entry.writeUInt32LE(crc, 16);
|
|
284
|
+
entry.writeUInt32LE(packed.length, 20);
|
|
285
|
+
entry.writeUInt32LE(file.data.length, 24);
|
|
286
|
+
entry.writeUInt16LE(name.length, 28);
|
|
287
|
+
entry.writeUInt32LE((0o100600 << 16) >>> 0, 38);
|
|
288
|
+
entry.writeUInt32LE(offset, 42);
|
|
289
|
+
local.push(head, name, packed);
|
|
290
|
+
central.push(entry, name);
|
|
291
|
+
offset += head.length + name.length + packed.length;
|
|
292
|
+
}
|
|
293
|
+
const directory = Buffer.concat(central);
|
|
294
|
+
const end = Buffer.alloc(22);
|
|
295
|
+
end.writeUInt32LE(0x06054b50, 0);
|
|
296
|
+
end.writeUInt16LE(exported.files.length, 8);
|
|
297
|
+
end.writeUInt16LE(exported.files.length, 10);
|
|
298
|
+
end.writeUInt32LE(directory.length, 12);
|
|
299
|
+
end.writeUInt32LE(offset, 16);
|
|
300
|
+
return Buffer.concat([...local, directory, end]);
|
|
301
|
+
}
|
|
302
|
+
/** One line for the ledger and the person who asked. */
|
|
303
|
+
export function exportSummary(exported) {
|
|
304
|
+
return `${exported.files.length} files · ${exported.tables} tables · ${exported.packs} evidence packs`;
|
|
305
|
+
}
|