approval-md 0.0.1 → 0.2.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 +176 -0
- package/NOTICE +5 -0
- package/README.md +940 -4
- package/SPEC.md +476 -34
- package/cli.js +29 -3
- package/dist/src/adapters/agentmail.d.ts +426 -0
- package/dist/src/adapters/agentmail.js +1200 -0
- package/dist/src/adapters/agentmail.js.map +1 -0
- package/dist/src/adapters/conformance.d.ts +149 -0
- package/dist/src/adapters/conformance.js +461 -0
- package/dist/src/adapters/conformance.js.map +1 -0
- package/dist/src/adapters/contract.d.ts +628 -0
- package/dist/src/adapters/contract.js +1035 -0
- package/dist/src/adapters/contract.js.map +1 -0
- package/dist/src/adapters/email.d.ts +324 -0
- package/dist/src/adapters/email.js +749 -0
- package/dist/src/adapters/email.js.map +1 -0
- package/dist/src/adapters/env-passphrase.d.ts +93 -0
- package/dist/src/adapters/env-passphrase.js +132 -0
- package/dist/src/adapters/env-passphrase.js.map +1 -0
- package/dist/src/adapters/public.d.ts +11 -0
- package/dist/src/adapters/public.js +11 -0
- package/dist/src/adapters/public.js.map +1 -0
- package/dist/src/adapters/registry.d.ts +59 -0
- package/dist/src/adapters/registry.js +77 -0
- package/dist/src/adapters/registry.js.map +1 -0
- package/dist/src/adapters/smtp.d.ts +213 -0
- package/dist/src/adapters/smtp.js +499 -0
- package/dist/src/adapters/smtp.js.map +1 -0
- package/dist/src/adapters/vault-provider.d.ts +114 -0
- package/dist/src/adapters/vault-provider.js +161 -0
- package/dist/src/adapters/vault-provider.js.map +1 -0
- package/dist/src/adapters/zzz.d.ts +66 -0
- package/dist/src/adapters/zzz.js +299 -0
- package/dist/src/adapters/zzz.js.map +1 -0
- package/dist/src/channels/batch.d.ts +109 -0
- package/dist/src/channels/batch.js +121 -0
- package/dist/src/channels/batch.js.map +1 -0
- package/dist/src/channels/cli.d.ts +193 -0
- package/dist/src/channels/cli.js +468 -0
- package/dist/src/channels/cli.js.map +1 -0
- package/dist/src/channels/conformance.d.ts +92 -0
- package/dist/src/channels/conformance.js +445 -0
- package/dist/src/channels/conformance.js.map +1 -0
- package/dist/src/channels/contract.d.ts +623 -0
- package/dist/src/channels/contract.js +494 -0
- package/dist/src/channels/contract.js.map +1 -0
- package/dist/src/channels/payload-view.d.ts +35 -0
- package/dist/src/channels/payload-view.js +43 -0
- package/dist/src/channels/payload-view.js.map +1 -0
- package/dist/src/channels/render-queue.d.ts +149 -0
- package/dist/src/channels/render-queue.js +564 -0
- package/dist/src/channels/render-queue.js.map +1 -0
- package/dist/src/channels/tagging.d.ts +196 -0
- package/dist/src/channels/tagging.js +723 -0
- package/dist/src/channels/tagging.js.map +1 -0
- package/dist/src/channels/telegram.d.ts +1832 -0
- package/dist/src/channels/telegram.js +3190 -0
- package/dist/src/channels/telegram.js.map +1 -0
- package/dist/src/channels/web.d.ts +341 -0
- package/dist/src/channels/web.js +903 -0
- package/dist/src/channels/web.js.map +1 -0
- package/dist/src/cli/adapter.d.ts +90 -0
- package/dist/src/cli/adapter.js +288 -0
- package/dist/src/cli/adapter.js.map +1 -0
- package/dist/src/cli/amend.d.ts +59 -0
- package/dist/src/cli/amend.js +2171 -0
- package/dist/src/cli/amend.js.map +1 -0
- package/dist/src/cli/args.d.ts +43 -0
- package/dist/src/cli/args.js +86 -0
- package/dist/src/cli/args.js.map +1 -0
- package/dist/src/cli/attest.d.ts +41 -0
- package/dist/src/cli/attest.js +307 -0
- package/dist/src/cli/attest.js.map +1 -0
- package/dist/src/cli/audit-card.d.ts +62 -0
- package/dist/src/cli/audit-card.js +201 -0
- package/dist/src/cli/audit-card.js.map +1 -0
- package/dist/src/cli/audit.d.ts +59 -0
- package/dist/src/cli/audit.js +460 -0
- package/dist/src/cli/audit.js.map +1 -0
- package/dist/src/cli/channel-telegram.d.ts +806 -0
- package/dist/src/cli/channel-telegram.js +2063 -0
- package/dist/src/cli/channel-telegram.js.map +1 -0
- package/dist/src/cli/channel-web.d.ts +131 -0
- package/dist/src/cli/channel-web.js +357 -0
- package/dist/src/cli/channel-web.js.map +1 -0
- package/dist/src/cli/channel.d.ts +71 -0
- package/dist/src/cli/channel.js +438 -0
- package/dist/src/cli/channel.js.map +1 -0
- package/dist/src/cli/checkpoint-tap.d.ts +169 -0
- package/dist/src/cli/checkpoint-tap.js +238 -0
- package/dist/src/cli/checkpoint-tap.js.map +1 -0
- package/dist/src/cli/codex.d.ts +2 -0
- package/dist/src/cli/codex.js +172 -0
- package/dist/src/cli/codex.js.map +1 -0
- package/dist/src/cli/coverage.d.ts +61 -0
- package/dist/src/cli/coverage.js +343 -0
- package/dist/src/cli/coverage.js.map +1 -0
- package/dist/src/cli/daemon.d.ts +120 -0
- package/dist/src/cli/daemon.js +631 -0
- package/dist/src/cli/daemon.js.map +1 -0
- package/dist/src/cli/doctor.d.ts +129 -0
- package/dist/src/cli/doctor.js +2762 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/env.d.ts +65 -0
- package/dist/src/cli/env.js +302 -0
- package/dist/src/cli/env.js.map +1 -0
- package/dist/src/cli/execute.d.ts +202 -0
- package/dist/src/cli/execute.js +1682 -0
- package/dist/src/cli/execute.js.map +1 -0
- package/dist/src/cli/exit-codes.d.ts +73 -0
- package/dist/src/cli/exit-codes.js +82 -0
- package/dist/src/cli/exit-codes.js.map +1 -0
- package/dist/src/cli/feedback.d.ts +60 -0
- package/dist/src/cli/feedback.js +205 -0
- package/dist/src/cli/feedback.js.map +1 -0
- package/dist/src/cli/gate-window.d.ts +40 -0
- package/dist/src/cli/gate-window.js +294 -0
- package/dist/src/cli/gate-window.js.map +1 -0
- package/dist/src/cli/gate.d.ts +68 -0
- package/dist/src/cli/gate.js +557 -0
- package/dist/src/cli/gate.js.map +1 -0
- package/dist/src/cli/git-scope.d.ts +190 -0
- package/dist/src/cli/git-scope.js +295 -0
- package/dist/src/cli/git-scope.js.map +1 -0
- package/dist/src/cli/gloss-attach.d.ts +85 -0
- package/dist/src/cli/gloss-attach.js +107 -0
- package/dist/src/cli/gloss-attach.js.map +1 -0
- package/dist/src/cli/gloss-codex-child.d.ts +9 -0
- package/dist/src/cli/gloss-codex-child.js +149 -0
- package/dist/src/cli/gloss-codex-child.js.map +1 -0
- package/dist/src/cli/gloss-codex.d.ts +24 -0
- package/dist/src/cli/gloss-codex.js +255 -0
- package/dist/src/cli/gloss-codex.js.map +1 -0
- package/dist/src/cli/gloss-options.d.ts +42 -0
- package/dist/src/cli/gloss-options.js +79 -0
- package/dist/src/cli/gloss-options.js.map +1 -0
- package/dist/src/cli/gloss.d.ts +265 -0
- package/dist/src/cli/gloss.js +362 -0
- package/dist/src/cli/gloss.js.map +1 -0
- package/dist/src/cli/help.d.ts +103 -0
- package/dist/src/cli/help.js +2339 -0
- package/dist/src/cli/help.js.map +1 -0
- package/dist/src/cli/hook-codex.d.ts +78 -0
- package/dist/src/cli/hook-codex.js +167 -0
- package/dist/src/cli/hook-codex.js.map +1 -0
- package/dist/src/cli/hook.d.ts +331 -0
- package/dist/src/cli/hook.js +2849 -0
- package/dist/src/cli/hook.js.map +1 -0
- package/dist/src/cli/import.d.ts +35 -0
- package/dist/src/cli/import.js +175 -0
- package/dist/src/cli/import.js.map +1 -0
- package/dist/src/cli/init.d.ts +84 -0
- package/dist/src/cli/init.js +336 -0
- package/dist/src/cli/init.js.map +1 -0
- package/dist/src/cli/instructions.d.ts +23 -0
- package/dist/src/cli/instructions.js +262 -0
- package/dist/src/cli/instructions.js.map +1 -0
- package/dist/src/cli/journal.d.ts +41 -0
- package/dist/src/cli/journal.js +238 -0
- package/dist/src/cli/journal.js.map +1 -0
- package/dist/src/cli/log-advance.d.ts +287 -0
- package/dist/src/cli/log-advance.js +840 -0
- package/dist/src/cli/log-advance.js.map +1 -0
- package/dist/src/cli/log-anchor.d.ts +176 -0
- package/dist/src/cli/log-anchor.js +387 -0
- package/dist/src/cli/log-anchor.js.map +1 -0
- package/dist/src/cli/log-checkpoint.d.ts +22 -0
- package/dist/src/cli/log-checkpoint.js +128 -0
- package/dist/src/cli/log-checkpoint.js.map +1 -0
- package/dist/src/cli/log-sync.d.ts +243 -0
- package/dist/src/cli/log-sync.js +849 -0
- package/dist/src/cli/log-sync.js.map +1 -0
- package/dist/src/cli/log-verbs.d.ts +16 -0
- package/dist/src/cli/log-verbs.js +360 -0
- package/dist/src/cli/log-verbs.js.map +1 -0
- package/dist/src/cli/long-help.d.ts +70 -0
- package/dist/src/cli/long-help.js +148 -0
- package/dist/src/cli/long-help.js.map +1 -0
- package/dist/src/cli/main.d.ts +77 -0
- package/dist/src/cli/main.js +1206 -0
- package/dist/src/cli/main.js.map +1 -0
- package/dist/src/cli/mcp.d.ts +52 -0
- package/dist/src/cli/mcp.js +306 -0
- package/dist/src/cli/mcp.js.map +1 -0
- package/dist/src/cli/paths.d.ts +56 -0
- package/dist/src/cli/paths.js +79 -0
- package/dist/src/cli/paths.js.map +1 -0
- package/dist/src/cli/payload.d.ts +58 -0
- package/dist/src/cli/payload.js +253 -0
- package/dist/src/cli/payload.js.map +1 -0
- package/dist/src/cli/policy.d.ts +43 -0
- package/dist/src/cli/policy.js +229 -0
- package/dist/src/cli/policy.js.map +1 -0
- package/dist/src/cli/preflight.d.ts +363 -0
- package/dist/src/cli/preflight.js +1175 -0
- package/dist/src/cli/preflight.js.map +1 -0
- package/dist/src/cli/progress.d.ts +78 -0
- package/dist/src/cli/progress.js +112 -0
- package/dist/src/cli/progress.js.map +1 -0
- package/dist/src/cli/prompt.d.ts +209 -0
- package/dist/src/cli/prompt.js +312 -0
- package/dist/src/cli/prompt.js.map +1 -0
- package/dist/src/cli/quickstart.d.ts +46 -0
- package/dist/src/cli/quickstart.js +297 -0
- package/dist/src/cli/quickstart.js.map +1 -0
- package/dist/src/cli/records.d.ts +34 -0
- package/dist/src/cli/records.js +66 -0
- package/dist/src/cli/records.js.map +1 -0
- package/dist/src/cli/render.d.ts +22 -0
- package/dist/src/cli/render.js +132 -0
- package/dist/src/cli/render.js.map +1 -0
- package/dist/src/cli/sandbox.d.ts +51 -0
- package/dist/src/cli/sandbox.js +150 -0
- package/dist/src/cli/sandbox.js.map +1 -0
- package/dist/src/cli/scaffold.d.ts +79 -0
- package/dist/src/cli/scaffold.js +137 -0
- package/dist/src/cli/scaffold.js.map +1 -0
- package/dist/src/cli/setup-adapter.d.ts +137 -0
- package/dist/src/cli/setup-adapter.js +509 -0
- package/dist/src/cli/setup-adapter.js.map +1 -0
- package/dist/src/cli/setup-channel.d.ts +117 -0
- package/dist/src/cli/setup-channel.js +635 -0
- package/dist/src/cli/setup-channel.js.map +1 -0
- package/dist/src/cli/setup-checkpoint.d.ts +57 -0
- package/dist/src/cli/setup-checkpoint.js +196 -0
- package/dist/src/cli/setup-checkpoint.js.map +1 -0
- package/dist/src/cli/setup-common.d.ts +275 -0
- package/dist/src/cli/setup-common.js +376 -0
- package/dist/src/cli/setup-common.js.map +1 -0
- package/dist/src/cli/setup-flow.d.ts +287 -0
- package/dist/src/cli/setup-flow.js +476 -0
- package/dist/src/cli/setup-flow.js.map +1 -0
- package/dist/src/cli/setup-service.d.ts +96 -0
- package/dist/src/cli/setup-service.js +308 -0
- package/dist/src/cli/setup-service.js.map +1 -0
- package/dist/src/cli/setup.d.ts +202 -0
- package/dist/src/cli/setup.js +473 -0
- package/dist/src/cli/setup.js.map +1 -0
- package/dist/src/cli/style.d.ts +320 -0
- package/dist/src/cli/style.js +469 -0
- package/dist/src/cli/style.js.map +1 -0
- package/dist/src/cli/token.d.ts +39 -0
- package/dist/src/cli/token.js +274 -0
- package/dist/src/cli/token.js.map +1 -0
- package/dist/src/cli/up.d.ts +155 -0
- package/dist/src/cli/up.js +849 -0
- package/dist/src/cli/up.js.map +1 -0
- package/dist/src/cli/usage.d.ts +37 -0
- package/dist/src/cli/usage.js +91 -0
- package/dist/src/cli/usage.js.map +1 -0
- package/dist/src/cli/values.d.ts +40 -0
- package/dist/src/cli/values.js +189 -0
- package/dist/src/cli/values.js.map +1 -0
- package/dist/src/cli/vault.d.ts +59 -0
- package/dist/src/cli/vault.js +362 -0
- package/dist/src/cli/vault.js.map +1 -0
- package/dist/src/cli/verb-registry.d.ts +76 -0
- package/dist/src/cli/verb-registry.js +2341 -0
- package/dist/src/cli/verb-registry.js.map +1 -0
- package/dist/src/cli/wordmark.d.ts +31 -0
- package/dist/src/cli/wordmark.js +52 -0
- package/dist/src/cli/wordmark.js.map +1 -0
- package/dist/src/codex/doctor.d.ts +13 -0
- package/dist/src/codex/doctor.js +41 -0
- package/dist/src/codex/doctor.js.map +1 -0
- package/dist/src/codex/manifest.d.ts +49 -0
- package/dist/src/codex/manifest.js +103 -0
- package/dist/src/codex/manifest.js.map +1 -0
- package/dist/src/codex/templates.d.ts +41 -0
- package/dist/src/codex/templates.js +319 -0
- package/dist/src/codex/templates.js.map +1 -0
- package/dist/src/codex/trust.d.ts +19 -0
- package/dist/src/codex/trust.js +183 -0
- package/dist/src/codex/trust.js.map +1 -0
- package/dist/src/codex/workspace-plan.d.ts +131 -0
- package/dist/src/codex/workspace-plan.js +561 -0
- package/dist/src/codex/workspace-plan.js.map +1 -0
- package/dist/src/core/actor.d.ts +2 -0
- package/dist/src/core/actor.js +5 -0
- package/dist/src/core/actor.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +170 -0
- package/dist/src/core/advance-cycle.js +200 -0
- package/dist/src/core/advance-cycle.js.map +1 -0
- package/dist/src/core/agents-md.d.ts +276 -0
- package/dist/src/core/agents-md.js +747 -0
- package/dist/src/core/agents-md.js.map +1 -0
- package/dist/src/core/apply-patch.d.ts +49 -0
- package/dist/src/core/apply-patch.js +266 -0
- package/dist/src/core/apply-patch.js.map +1 -0
- package/dist/src/core/attest.d.ts +420 -0
- package/dist/src/core/attest.js +589 -0
- package/dist/src/core/attest.js.map +1 -0
- package/dist/src/core/audit.d.ts +492 -0
- package/dist/src/core/audit.js +882 -0
- package/dist/src/core/audit.js.map +1 -0
- package/dist/src/core/budgets.d.ts +238 -0
- package/dist/src/core/budgets.js +449 -0
- package/dist/src/core/budgets.js.map +1 -0
- package/dist/src/core/checkpoint.d.ts +500 -0
- package/dist/src/core/checkpoint.js +738 -0
- package/dist/src/core/checkpoint.js.map +1 -0
- package/dist/src/core/child-env.d.ts +88 -0
- package/dist/src/core/child-env.js +86 -0
- package/dist/src/core/child-env.js.map +1 -0
- package/dist/src/core/clock.d.ts +52 -0
- package/dist/src/core/clock.js +43 -0
- package/dist/src/core/clock.js.map +1 -0
- package/dist/src/core/command-class.d.ts +543 -0
- package/dist/src/core/command-class.js +2356 -0
- package/dist/src/core/command-class.js.map +1 -0
- package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
- package/dist/src/core/coverage-sources/adapter.js +71 -0
- package/dist/src/core/coverage-sources/adapter.js.map +1 -0
- package/dist/src/core/coverage-sources/gh.d.ts +48 -0
- package/dist/src/core/coverage-sources/gh.js +136 -0
- package/dist/src/core/coverage-sources/gh.js.map +1 -0
- package/dist/src/core/coverage-sources/git.d.ts +101 -0
- package/dist/src/core/coverage-sources/git.js +269 -0
- package/dist/src/core/coverage-sources/git.js.map +1 -0
- package/dist/src/core/coverage.d.ts +217 -0
- package/dist/src/core/coverage.js +337 -0
- package/dist/src/core/coverage.js.map +1 -0
- package/dist/src/core/credential-spec.d.ts +72 -0
- package/dist/src/core/credential-spec.js +23 -0
- package/dist/src/core/credential-spec.js.map +1 -0
- package/dist/src/core/dark-session.d.ts +331 -0
- package/dist/src/core/dark-session.js +714 -0
- package/dist/src/core/dark-session.js.map +1 -0
- package/dist/src/core/decision-refusal.d.ts +185 -0
- package/dist/src/core/decision-refusal.js +265 -0
- package/dist/src/core/decision-refusal.js.map +1 -0
- package/dist/src/core/env-file.d.ts +450 -0
- package/dist/src/core/env-file.js +837 -0
- package/dist/src/core/env-file.js.map +1 -0
- package/dist/src/core/execute.d.ts +858 -0
- package/dist/src/core/execute.js +1271 -0
- package/dist/src/core/execute.js.map +1 -0
- package/dist/src/core/frontmatter.d.ts +78 -0
- package/dist/src/core/frontmatter.js +100 -0
- package/dist/src/core/frontmatter.js.map +1 -0
- package/dist/src/core/gate-window.d.ts +312 -0
- package/dist/src/core/gate-window.js +506 -0
- package/dist/src/core/gate-window.js.map +1 -0
- package/dist/src/core/gate.d.ts +1364 -0
- package/dist/src/core/gate.js +3002 -0
- package/dist/src/core/gate.js.map +1 -0
- package/dist/src/core/git-run.d.ts +73 -0
- package/dist/src/core/git-run.js +93 -0
- package/dist/src/core/git-run.js.map +1 -0
- package/dist/src/core/harness-version.d.ts +157 -0
- package/dist/src/core/harness-version.js +211 -0
- package/dist/src/core/harness-version.js.map +1 -0
- package/dist/src/core/harness-wait.d.ts +55 -0
- package/dist/src/core/harness-wait.js +58 -0
- package/dist/src/core/harness-wait.js.map +1 -0
- package/dist/src/core/head-retry.d.ts +107 -0
- package/dist/src/core/head-retry.js +121 -0
- package/dist/src/core/head-retry.js.map +1 -0
- package/dist/src/core/instance.d.ts +253 -0
- package/dist/src/core/instance.js +319 -0
- package/dist/src/core/instance.js.map +1 -0
- package/dist/src/core/intake-limits.d.ts +247 -0
- package/dist/src/core/intake-limits.js +350 -0
- package/dist/src/core/intake-limits.js.map +1 -0
- package/dist/src/core/jcs.d.ts +52 -0
- package/dist/src/core/jcs.js +132 -0
- package/dist/src/core/jcs.js.map +1 -0
- package/dist/src/core/journal.d.ts +144 -0
- package/dist/src/core/journal.js +200 -0
- package/dist/src/core/journal.js.map +1 -0
- package/dist/src/core/live-draw.d.ts +436 -0
- package/dist/src/core/live-draw.js +703 -0
- package/dist/src/core/live-draw.js.map +1 -0
- package/dist/src/core/log-reconcile.d.ts +89 -0
- package/dist/src/core/log-reconcile.js +136 -0
- package/dist/src/core/log-reconcile.js.map +1 -0
- package/dist/src/core/log-subscribe.d.ts +36 -0
- package/dist/src/core/log-subscribe.js +162 -0
- package/dist/src/core/log-subscribe.js.map +1 -0
- package/dist/src/core/log.d.ts +278 -0
- package/dist/src/core/log.js +546 -0
- package/dist/src/core/log.js.map +1 -0
- package/dist/src/core/loop.d.ts +274 -0
- package/dist/src/core/loop.js +487 -0
- package/dist/src/core/loop.js.map +1 -0
- package/dist/src/core/md-fence.d.ts +41 -0
- package/dist/src/core/md-fence.js +74 -0
- package/dist/src/core/md-fence.js.map +1 -0
- package/dist/src/core/money.d.ts +147 -0
- package/dist/src/core/money.js +195 -0
- package/dist/src/core/money.js.map +1 -0
- package/dist/src/core/payload-census.d.ts +74 -0
- package/dist/src/core/payload-census.js +146 -0
- package/dist/src/core/payload-census.js.map +1 -0
- package/dist/src/core/payload-store.d.ts +175 -0
- package/dist/src/core/payload-store.js +340 -0
- package/dist/src/core/payload-store.js.map +1 -0
- package/dist/src/core/payload.d.ts +71 -0
- package/dist/src/core/payload.js +80 -0
- package/dist/src/core/payload.js.map +1 -0
- package/dist/src/core/policy-diff.d.ts +292 -0
- package/dist/src/core/policy-diff.js +588 -0
- package/dist/src/core/policy-diff.js.map +1 -0
- package/dist/src/core/policy-expectations.d.ts +199 -0
- package/dist/src/core/policy-expectations.js +394 -0
- package/dist/src/core/policy-expectations.js.map +1 -0
- package/dist/src/core/policy-explain.d.ts +150 -0
- package/dist/src/core/policy-explain.js +258 -0
- package/dist/src/core/policy-explain.js.map +1 -0
- package/dist/src/core/policy-load.d.ts +527 -0
- package/dist/src/core/policy-load.js +536 -0
- package/dist/src/core/policy-load.js.map +1 -0
- package/dist/src/core/policy-match.d.ts +281 -0
- package/dist/src/core/policy-match.js +478 -0
- package/dist/src/core/policy-match.js.map +1 -0
- package/dist/src/core/policy-proposal.d.ts +265 -0
- package/dist/src/core/policy-proposal.js +458 -0
- package/dist/src/core/policy-proposal.js.map +1 -0
- package/dist/src/core/prompt-layout.d.ts +221 -0
- package/dist/src/core/prompt-layout.js +422 -0
- package/dist/src/core/prompt-layout.js.map +1 -0
- package/dist/src/core/protected-path-guard.d.ts +453 -0
- package/dist/src/core/protected-path-guard.js +1566 -0
- package/dist/src/core/protected-path-guard.js.map +1 -0
- package/dist/src/core/registration.d.ts +25 -0
- package/dist/src/core/registration.js +39 -0
- package/dist/src/core/registration.js.map +1 -0
- package/dist/src/core/reindex.d.ts +99 -0
- package/dist/src/core/reindex.js +336 -0
- package/dist/src/core/reindex.js.map +1 -0
- package/dist/src/core/sampler.d.ts +313 -0
- package/dist/src/core/sampler.js +388 -0
- package/dist/src/core/sampler.js.map +1 -0
- package/dist/src/core/sandbox.d.ts +290 -0
- package/dist/src/core/sandbox.js +424 -0
- package/dist/src/core/sandbox.js.map +1 -0
- package/dist/src/core/seal.d.ts +165 -0
- package/dist/src/core/seal.js +290 -0
- package/dist/src/core/seal.js.map +1 -0
- package/dist/src/core/state.d.ts +505 -0
- package/dist/src/core/state.js +1009 -0
- package/dist/src/core/state.js.map +1 -0
- package/dist/src/core/task-file.d.ts +185 -0
- package/dist/src/core/task-file.js +464 -0
- package/dist/src/core/task-file.js.map +1 -0
- package/dist/src/core/telegram-config.d.ts +93 -0
- package/dist/src/core/telegram-config.js +114 -0
- package/dist/src/core/telegram-config.js.map +1 -0
- package/dist/src/core/token.d.ts +409 -0
- package/dist/src/core/token.js +561 -0
- package/dist/src/core/token.js.map +1 -0
- package/dist/src/core/validate.d.ts +138 -0
- package/dist/src/core/validate.js +0 -0
- package/dist/src/core/validate.js.map +1 -0
- package/dist/src/core/values.d.ts +137 -0
- package/dist/src/core/values.js +153 -0
- package/dist/src/core/values.js.map +1 -0
- package/dist/src/core/vault.d.ts +291 -0
- package/dist/src/core/vault.js +612 -0
- package/dist/src/core/vault.js.map +1 -0
- package/dist/src/core/verified-snapshot.d.ts +204 -0
- package/dist/src/core/verified-snapshot.js +506 -0
- package/dist/src/core/verified-snapshot.js.map +1 -0
- package/dist/src/core/verify.d.ts +336 -0
- package/dist/src/core/verify.js +549 -0
- package/dist/src/core/verify.js.map +1 -0
- package/dist/src/core/version.d.ts +8 -0
- package/dist/src/core/version.js +9 -0
- package/dist/src/core/version.js.map +1 -0
- package/dist/src/core/wysiwys.d.ts +370 -0
- package/dist/src/core/wysiwys.js +728 -0
- package/dist/src/core/wysiwys.js.map +1 -0
- package/dist/src/daemon/advance-child.d.ts +39 -0
- package/dist/src/daemon/advance-child.js +78 -0
- package/dist/src/daemon/advance-child.js.map +1 -0
- package/dist/src/daemon/advance.d.ts +466 -0
- package/dist/src/daemon/advance.js +849 -0
- package/dist/src/daemon/advance.js.map +1 -0
- package/dist/src/daemon/audit.d.ts +87 -0
- package/dist/src/daemon/audit.js +90 -0
- package/dist/src/daemon/audit.js.map +1 -0
- package/dist/src/daemon/daemon.d.ts +1180 -0
- package/dist/src/daemon/daemon.js +1988 -0
- package/dist/src/daemon/daemon.js.map +1 -0
- package/dist/src/daemon/dark-session.d.ts +64 -0
- package/dist/src/daemon/dark-session.js +119 -0
- package/dist/src/daemon/dark-session.js.map +1 -0
- package/dist/src/daemon/draw-child.d.ts +36 -0
- package/dist/src/daemon/draw-child.js +132 -0
- package/dist/src/daemon/draw-child.js.map +1 -0
- package/dist/src/daemon/draw.d.ts +154 -0
- package/dist/src/daemon/draw.js +458 -0
- package/dist/src/daemon/draw.js.map +1 -0
- package/dist/src/daemon/git-evidence.d.ts +173 -0
- package/dist/src/daemon/git-evidence.js +345 -0
- package/dist/src/daemon/git-evidence.js.map +1 -0
- package/dist/src/daemon/projection.d.ts +180 -0
- package/dist/src/daemon/projection.js +233 -0
- package/dist/src/daemon/projection.js.map +1 -0
- package/dist/src/daemon/prune.d.ts +207 -0
- package/dist/src/daemon/prune.js +376 -0
- package/dist/src/daemon/prune.js.map +1 -0
- package/dist/src/mcp/http.d.ts +113 -0
- package/dist/src/mcp/http.js +343 -0
- package/dist/src/mcp/http.js.map +1 -0
- package/dist/src/mcp/server.d.ts +265 -0
- package/dist/src/mcp/server.js +602 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/docs/adapter-api.md +106 -0
- package/docs/cli-reference.md +5716 -0
- package/docs/codex-enforced-session.md +30 -0
- package/package.json +53 -4
- package/schema/.gitkeep +0 -0
- package/schema/LICENSE +117 -0
- package/schema/codex-instance.schema.json +82 -0
- package/schema/envelope.schema.json +137 -0
- package/schema/event.schema.json +1811 -0
- package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
- package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
- package/schema/fixtures/envelope/invalid/action-missing-idempotency-key.json +15 -0
- package/schema/fixtures/envelope/invalid/action-unknown-class-format.json +14 -0
- package/schema/fixtures/envelope/invalid/confidence-out-of-range.json +11 -0
- package/schema/fixtures/envelope/invalid/est-cost-bare-number.json +14 -0
- package/schema/fixtures/envelope/invalid/est-cost-noncanonical-string.json +14 -0
- package/schema/fixtures/envelope/invalid/malformed-assignee.json +10 -0
- package/schema/fixtures/envelope/invalid/malformed-created-by.json +7 -0
- package/schema/fixtures/envelope/invalid/malformed-max-latency.json +11 -0
- package/schema/fixtures/envelope/invalid/malformed-payload-hash.json +14 -0
- package/schema/fixtures/envelope/invalid/max-cost-bare-number.json +11 -0
- package/schema/fixtures/envelope/invalid/missing-origin.json +3 -0
- package/schema/fixtures/envelope/invalid/negative-est-cost.json +14 -0
- package/schema/fixtures/envelope/invalid/unknown-state.json +7 -0
- package/schema/fixtures/envelope/invalid/unknown-top-level-field.json +8 -0
- package/schema/fixtures/envelope/valid/action-payload-hash.json +17 -0
- package/schema/fixtures/envelope/valid/actions-without-budget.json +18 -0
- package/schema/fixtures/envelope/valid/canonical.json +25 -0
- package/schema/fixtures/envelope/valid/minimal.json +7 -0
- package/schema/fixtures/envelope/valid/multi-action-executed.json +30 -0
- package/schema/fixtures/envelope/valid/record-write-stage.json +22 -0
- package/schema/fixtures/event/invalid/approval-granted-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/approval-granted-empty-batch-delivery-id.json +17 -0
- package/schema/fixtures/event/invalid/approval-granted-fifth-reaction.json +16 -0
- package/schema/fixtures/event/invalid/approval-granted-missing-actor.json +14 -0
- package/schema/fixtures/event/invalid/approval-requested-missing-action-key.json +14 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-agent-policy-drift.json +15 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-missing-reason.json +15 -0
- package/schema/fixtures/event/invalid/approval-withdrawn-system-actor.json +15 -0
- package/schema/fixtures/event/invalid/audit-decision-refused-human-actor.json +17 -0
- package/schema/fixtures/event/invalid/audit-decision-refused-missing-code.json +16 -0
- package/schema/fixtures/event/invalid/audit-reviewed-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/audit-reviewed-loved-no-note.json +16 -0
- package/schema/fixtures/event/invalid/audit-reviewed-system-actor.json +15 -0
- package/schema/fixtures/event/invalid/bad-actor-prefix.json +15 -0
- package/schema/fixtures/event/invalid/est-cost-bare-number.json +17 -0
- package/schema/fixtures/event/invalid/execution-completed-fabricated-exit-code.json +16 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-empty-id.json +18 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-extra-field.json +19 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-id-not-string.json +18 -0
- package/schema/fixtures/event/invalid/execution-completed-provider-ref-missing-adapter.json +17 -0
- package/schema/fixtures/event/invalid/execution-failed-open-reported-by.json +16 -0
- package/schema/fixtures/event/invalid/execution-indeterminate-open-reason.json +14 -0
- package/schema/fixtures/event/invalid/execution-reconciled-agent-actor.json +17 -0
- package/schema/fixtures/event/invalid/execution-started-negative-env-stripped.json +16 -0
- package/schema/fixtures/event/invalid/gate-bypassed-missing-opened-seq.json +15 -0
- package/schema/fixtures/event/invalid/gate-closed-non-integer-opened-seq.json +13 -0
- package/schema/fixtures/event/invalid/gate-opened-agent-actor.json +16 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-absolute-path.json +14 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-agent-actor.json +14 -0
- package/schema/fixtures/event/invalid/gate-organ-attested-missing-organ-path.json +13 -0
- package/schema/fixtures/event/invalid/harness-unknown-kind.json +18 -0
- package/schema/fixtures/event/invalid/harness-version-multiline.json +16 -0
- package/schema/fixtures/event/invalid/log-checkpoint-agent-actor.json +17 -0
- package/schema/fixtures/event/invalid/log-checkpoint-missing-signature.json +16 -0
- package/schema/fixtures/event/invalid/log-checkpoint-short-signed-hash.json +17 -0
- package/schema/fixtures/event/invalid/log-checkpoint-unknown-signature-alg.json +17 -0
- package/schema/fixtures/event/invalid/malformed-ts.json +15 -0
- package/schema/fixtures/event/invalid/missing-alg.json +14 -0
- package/schema/fixtures/event/invalid/missing-hash.json +14 -0
- package/schema/fixtures/event/invalid/non-integer-seq.json +15 -0
- package/schema/fixtures/event/invalid/payload-pruned-human-actor.json +14 -0
- package/schema/fixtures/event/invalid/payload-pruned-missing-hash.json +14 -0
- package/schema/fixtures/event/invalid/policy-declined-agent-actor.json +15 -0
- package/schema/fixtures/event/invalid/policy-proposed-missing-diff.json +19 -0
- package/schema/fixtures/event/invalid/policy-proposed-system-actor.json +26 -0
- package/schema/fixtures/event/invalid/short-hash.json +15 -0
- package/schema/fixtures/event/invalid/unknown-alg.json +15 -0
- package/schema/fixtures/event/invalid/unknown-event-type.json +15 -0
- package/schema/fixtures/event/invalid/unknown-top-level-field.json +16 -0
- package/schema/fixtures/event/valid/approval-expired.json +15 -0
- package/schema/fixtures/event/valid/approval-granted-batch.json +19 -0
- package/schema/fixtures/event/valid/approval-granted-reaction.json +16 -0
- package/schema/fixtures/event/valid/approval-granted.json +15 -0
- package/schema/fixtures/event/valid/approval-rejected.json +15 -0
- package/schema/fixtures/event/valid/approval-requested.json +19 -0
- package/schema/fixtures/event/valid/approval-revoked.json +15 -0
- package/schema/fixtures/event/valid/approval-withdrawn-policy-drift.json +17 -0
- package/schema/fixtures/event/valid/approval-withdrawn.json +16 -0
- package/schema/fixtures/event/valid/audit-decision-refused.json +20 -0
- package/schema/fixtures/event/valid/audit-reviewed-reaction.json +17 -0
- package/schema/fixtures/event/valid/audit-reviewed.json +15 -0
- package/schema/fixtures/event/valid/audit-sampled.json +14 -0
- package/schema/fixtures/event/valid/budget-exceeded.json +21 -0
- package/schema/fixtures/event/valid/envelope-drift.json +16 -0
- package/schema/fixtures/event/valid/execution-completed-harness-report.json +16 -0
- package/schema/fixtures/event/valid/execution-completed-provider-ref.json +18 -0
- package/schema/fixtures/event/valid/execution-completed.json +15 -0
- package/schema/fixtures/event/valid/execution-failed-harness-report.json +16 -0
- package/schema/fixtures/event/valid/execution-failed.json +15 -0
- package/schema/fixtures/event/valid/execution-indeterminate.json +15 -0
- package/schema/fixtures/event/valid/execution-reconciled.json +17 -0
- package/schema/fixtures/event/valid/execution-started-env-stripped.json +17 -0
- package/schema/fixtures/event/valid/execution-started.json +14 -0
- package/schema/fixtures/event/valid/gate-bypassed-harness-version.json +18 -0
- package/schema/fixtures/event/valid/gate-bypassed.json +19 -0
- package/schema/fixtures/event/valid/gate-closed.json +14 -0
- package/schema/fixtures/event/valid/gate-opened.json +16 -0
- package/schema/fixtures/event/valid/gate-organ-attested.json +14 -0
- package/schema/fixtures/event/valid/genesis-null-prev.json +14 -0
- package/schema/fixtures/event/valid/log-checkpoint.json +17 -0
- package/schema/fixtures/event/valid/payload-pruned-orphan.json +13 -0
- package/schema/fixtures/event/valid/payload-pruned.json +17 -0
- package/schema/fixtures/event/valid/policy-declined.json +16 -0
- package/schema/fixtures/event/valid/policy-proposed.json +35 -0
- package/schema/fixtures/event/valid/policy-updated.json +14 -0
- package/schema/fixtures/event/valid/reconciliation-required.json +18 -0
- package/schema/fixtures/event/valid/reconciliation-satisfied.json +17 -0
- package/schema/fixtures/event/valid/route-accepted.json +15 -0
- package/schema/fixtures/event/valid/route-proposed.json +16 -0
- package/schema/fixtures/event/valid/spec-example.json +15 -0
- package/schema/fixtures/event/valid/task-registered-harness-version.json +23 -0
- package/schema/fixtures/event/valid/task-registered.json +14 -0
- package/schema/fixtures/hash/known-answer-pre-121.json +74 -0
- package/schema/fixtures/hash/known-answer.json +74 -0
- package/schema/fixtures/policy/invalid/bad-approval-ttl.json +7 -0
- package/schema/fixtures/policy/invalid/bad-web-port.json +4 -0
- package/schema/fixtures/policy/invalid/checkpoint-key-not-base64.json +6 -0
- package/schema/fixtures/policy/invalid/class-rule-missing-autonomy.json +9 -0
- package/schema/fixtures/policy/invalid/empty-class-key.json +6 -0
- package/schema/fixtures/policy/invalid/live-rate-on-human-only.json +7 -0
- package/schema/fixtures/policy/invalid/malformed-class-key.json +6 -0
- package/schema/fixtures/policy/invalid/missing-version.json +8 -0
- package/schema/fixtures/policy/invalid/negative-limit.json +9 -0
- package/schema/fixtures/policy/invalid/non-numeric-limit.json +9 -0
- package/schema/fixtures/policy/invalid/non-positive-max-pending.json +9 -0
- package/schema/fixtures/policy/invalid/on-expiry-grant.json +8 -0
- package/schema/fixtures/policy/invalid/payload-retention-bare-number.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-compound.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-fractional.json +4 -0
- package/schema/fixtures/policy/invalid/payload-retention-zero.json +4 -0
- package/schema/fixtures/policy/invalid/protected-paths-escape.json +4 -0
- package/schema/fixtures/policy/invalid/protected-paths-glob.json +4 -0
- package/schema/fixtures/policy/invalid/retro-rate-on-human-only.json +7 -0
- package/schema/fixtures/policy/invalid/retro-rate-on-manual.json +7 -0
- package/schema/fixtures/policy/invalid/retro-rate-zero.json +7 -0
- package/schema/fixtures/policy/invalid/sample-rate-too-high.json +5 -0
- package/schema/fixtures/policy/invalid/sampling-secret-env-empty.json +7 -0
- package/schema/fixtures/policy/invalid/sampling-secret-env-not-string.json +6 -0
- package/schema/fixtures/policy/invalid/skew-tolerance-compound.json +6 -0
- package/schema/fixtures/policy/invalid/unknown-autonomy.json +7 -0
- package/schema/fixtures/policy/invalid/unknown-class-rule-key.json +6 -0
- package/schema/fixtures/policy/invalid/unknown-top-level-key.json +7 -0
- package/schema/fixtures/policy/invalid/vault-passphrase-env-empty.json +6 -0
- package/schema/fixtures/policy/invalid/vault-passphrase-literal.json +6 -0
- package/schema/fixtures/policy/invalid/version-not-string.json +4 -0
- package/schema/fixtures/policy/valid/canonical.json +47 -0
- package/schema/fixtures/policy/valid/checkpoint-keys.json +18 -0
- package/schema/fixtures/policy/valid/class-approvers-limits.json +25 -0
- package/schema/fixtures/policy/valid/class-retro-rate.json +17 -0
- package/schema/fixtures/policy/valid/global-budgets.json +19 -0
- package/schema/fixtures/policy/valid/human-only.json +9 -0
- package/schema/fixtures/policy/valid/minimal.json +6 -0
- package/schema/fixtures/policy/valid/protected-paths.json +10 -0
- package/schema/fixtures/policy/valid/record-namespace.json +13 -0
- package/schema/fixtures/policy/valid/request-volume-limits.json +26 -0
- package/schema/fixtures/policy/valid/retention-and-sampling-secret.json +16 -0
- package/schema/fixtures/policy/valid/skew-tolerance.json +15 -0
- package/schema/fixtures/policy/valid/vault-passphrase-env.json +14 -0
- package/schema/fixtures/policy/valid/wildcards.json +15 -0
- package/schema/fixtures/policy-md/invalid/alias-bomb.md +15 -0
- package/schema/fixtures/policy-md/invalid/no-fence.md +7 -0
- package/schema/fixtures/policy-md/invalid/protected-route-not-a-subclass.md +16 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-autonomy.md +16 -0
- package/schema/fixtures/policy-md/invalid/schema-invalid-read-proof.md +17 -0
- package/schema/fixtures/policy-md/invalid/two-fences.md +19 -0
- package/schema/fixtures/policy-md/invalid/unclosed-fence.md +11 -0
- package/schema/fixtures/policy-md/invalid/wrong-info-string.md +11 -0
- package/schema/fixtures/policy-md/invalid/yaml-syntax-error.md +13 -0
- package/schema/fixtures/policy-md/precedence/both/APPROVAL.md +7 -0
- package/schema/fixtures/policy-md/precedence/both/APPROVALS.md +7 -0
- package/schema/fixtures/policy-md/precedence/fallback-only/APPROVALS.md +7 -0
- package/schema/fixtures/policy-md/valid/canonical.md +50 -0
- package/schema/fixtures/policy-md/valid/daemon-read-proof.md +18 -0
- package/schema/fixtures/policy-md/valid/minimal.md +3 -0
- package/schema/fixtures/policy-md/valid/prose-lookalikes.md +54 -0
- package/schema/fixtures/policy-md/valid/routed-protected-paths.md +49 -0
- package/schema/fixtures/policy-md/valid/with-values.md +79 -0
- package/schema/fixtures/sample-record/invalid/bad-date-time.json +4 -0
- package/schema/fixtures/sample-record/invalid/missing-required-field.json +3 -0
- package/schema/fixtures/sample-record/invalid/unknown-top-level-field.json +5 -0
- package/schema/fixtures/sample-record/invalid/wrong-type.json +4 -0
- package/schema/fixtures/sample-record/valid/minimal.json +4 -0
- package/schema/fixtures/sample-record/valid/with-note.json +5 -0
- package/schema/fixtures/values/invalid/class-shaped.json +9 -0
- package/schema/fixtures/values/invalid/duplicate-entry.json +4 -0
- package/schema/fixtures/values/invalid/non-string-item.json +4 -0
- package/schema/fixtures/values/invalid/over-cap.json +26 -0
- package/schema/fixtures/values/invalid/unknown-key.json +5 -0
- package/schema/fixtures/values/invalid/version-string.json +1 -0
- package/schema/fixtures/values/valid/empty-lists.json +7 -0
- package/schema/fixtures/values/valid/full.json +20 -0
- package/schema/fixtures/values/valid/minimal.json +1 -0
- package/schema/fixtures/values-md/invalid/schema-invalid.md +62 -0
- package/schema/fixtures/values-md/invalid/two-blocks.md +69 -0
- package/schema/fixtures/values-md/invalid/unterminated.md +61 -0
- package/schema/fixtures/values-md/invalid/yaml-error.md +63 -0
- package/schema/fixtures/values-md/valid/absent.md +50 -0
- package/schema/fixtures/values-md/valid/with-values.md +79 -0
- package/schema/policy.schema.json +501 -0
- package/schema/sample-record.schema.json +26 -0
- package/schema/values.schema.json +55 -0
- package/templates/codex/README.md +9 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal prompts — the one place this CLI reads from a human (APRV-74).
|
|
3
|
+
*
|
|
4
|
+
* Two of these three functions existed already, privately, inside
|
|
5
|
+
* `cli/amend.ts`: a synchronous line reader and the `[y/N]` question built on
|
|
6
|
+
* it. `approval setup` needs both, plus a third that `amend` never needed — a
|
|
7
|
+
* reader that does not echo — and three copies of a raw-mode byte loop is two
|
|
8
|
+
* too many. So they live here, `amend` imports the line reader, and the
|
|
9
|
+
* no-echo one is written once, in the open, where it can be read.
|
|
10
|
+
*
|
|
11
|
+
* ## Synchronous, on purpose
|
|
12
|
+
*
|
|
13
|
+
* `readSync(0, …)` rather than `readline/promises`. Every verb in this CLI
|
|
14
|
+
* returns an exit code from a synchronous function, and the two that do not
|
|
15
|
+
* (`channel`, `daemon`) are asynchronous because they hold a socket open, not
|
|
16
|
+
* because they ask a question. A prompt that forced `setup identity` to become
|
|
17
|
+
* a promise would be an async CLI shape adopted for the sake of one line of
|
|
18
|
+
* input.
|
|
19
|
+
*
|
|
20
|
+
* ## The no-echo reader, and what it is worth
|
|
21
|
+
*
|
|
22
|
+
* {@link readSecret} puts the terminal in raw mode and reads one byte at a
|
|
23
|
+
* time, printing nothing — not even asterisks, which leak a length. It restores
|
|
24
|
+
* the terminal in a `finally`, including on the abort paths, because a shell
|
|
25
|
+
* left in raw mode after a Ctrl-C is a broken session and the operator's next
|
|
26
|
+
* act would be to close the window.
|
|
27
|
+
*
|
|
28
|
+
* What it defends is a secret in a scrollback buffer, a `script` capture, or a
|
|
29
|
+
* screen share. What it does not defend is a compromised terminal, a keylogger,
|
|
30
|
+
* or the process itself: the value is a `string` in this process's heap the
|
|
31
|
+
* instant it is complete, exactly as `approval vault set`'s stdin value is. The
|
|
32
|
+
* design point that matters more is upstream of this file — wherever a secret
|
|
33
|
+
* can be collected by a helper's OWN prompt, `setup` delegates to that helper
|
|
34
|
+
* and this function is never called (see `cli/setup.ts`, "the token never
|
|
35
|
+
* enters our process").
|
|
36
|
+
*
|
|
37
|
+
* **Ctrl-C is a distinct result, not an exception and not an empty string.** An
|
|
38
|
+
* aborted prompt must be distinguishable from an empty answer by the caller, so
|
|
39
|
+
* that "the human changed their mind" stores nothing and exits, while "the
|
|
40
|
+
* human pressed Enter" is an ordinary validation failure. Collapsing the two is
|
|
41
|
+
* how a half-configured keystore entry gets written.
|
|
42
|
+
*
|
|
43
|
+
* Nothing here throws, and nothing here ever writes the value it read to any
|
|
44
|
+
* stream.
|
|
45
|
+
*
|
|
46
|
+
* ## A bad answer is a question asked again, not a mangled command line (APRV-90)
|
|
47
|
+
*
|
|
48
|
+
* {@link askUntil} is the loop every typed question in `setup` runs through. It
|
|
49
|
+
* exists because the first shipped build treated a wrong answer to a PROMPT the
|
|
50
|
+
* way it treats a wrong flag on an argv: exit 2 with the whole help page under
|
|
51
|
+
* it. Observed on 2026-08-18, `setup identity` printed `human identity
|
|
52
|
+
* (human:<id>):`, the operator typed `carter`, and forty lines of help came
|
|
53
|
+
* back. A prompt has already told the human what it wants; when the answer does
|
|
54
|
+
* not fit, the useful reply is one line saying which part did not fit, followed
|
|
55
|
+
* by the same question.
|
|
56
|
+
*
|
|
57
|
+
* Three ends, and they are different on purpose:
|
|
58
|
+
*
|
|
59
|
+
* - **accepted** — the validator's parsed value, which may be a NORMALISED form
|
|
60
|
+
* of what was typed (`carter` → `human:carter`) rather than the bytes;
|
|
61
|
+
* - **aborted** — `readLine` returned `null`, which is Ctrl-D (and, for the
|
|
62
|
+
* scripted prompter, the modelled Ctrl-C). Nothing is stored, and the caller
|
|
63
|
+
* exits with a one-line reason and NO help page, because there was no command
|
|
64
|
+
* line for a help page to be about;
|
|
65
|
+
* - **exhausted** — {@link DEFAULT_MAX_ATTEMPTS} answers in a row failed
|
|
66
|
+
* validation. Bounded rather than infinite so that a prompt driven by
|
|
67
|
+
* something that is not a person (a stuck script, a terminal replaying bytes)
|
|
68
|
+
* terminates instead of looping forever.
|
|
69
|
+
*
|
|
70
|
+
* ## EAGAIN is "not yet", never "end of input" (APRV-84)
|
|
71
|
+
*
|
|
72
|
+
* Every caller checks `process.stdin.isTTY` before it prompts, and merely
|
|
73
|
+
* touching `process.stdin` on a terminal has libuv put fd 0 into non-blocking
|
|
74
|
+
* mode. From then on a `readSync(0, …)` issued before the human has typed
|
|
75
|
+
* fails with EAGAIN instead of waiting. The first shipped line reader treated
|
|
76
|
+
* every error as EOF, so `approval setup identity` on a macOS terminal printed
|
|
77
|
+
* "no identity was entered" the instant the prompt appeared. Both readers now
|
|
78
|
+
* go through {@link readByteBlocking}, which sleeps a few milliseconds on
|
|
79
|
+
* EAGAIN and tries again, and treats nothing else as "wait".
|
|
80
|
+
*/
|
|
81
|
+
import { readSync } from "node:fs";
|
|
82
|
+
const CTRL_C = 0x03;
|
|
83
|
+
const CTRL_D = 0x04;
|
|
84
|
+
const BACKSPACE = 0x08;
|
|
85
|
+
const DELETE = 0x7f;
|
|
86
|
+
const CR = 0x0d;
|
|
87
|
+
const LF = 0x0a;
|
|
88
|
+
/**
|
|
89
|
+
* One line from stdin, synchronously. `null` at EOF.
|
|
90
|
+
*
|
|
91
|
+
* Hoisted verbatim from `cli/amend.ts` (APRV-74), which is why it reads bytes
|
|
92
|
+
* rather than using a stream: it is called from inside a synchronous command
|
|
93
|
+
* function, after output has already been written, and it must not consume more
|
|
94
|
+
* of stdin than the line it was asked for.
|
|
95
|
+
*/
|
|
96
|
+
export function readLineFromStdin(read = readByteBlocking) {
|
|
97
|
+
const buffer = Buffer.alloc(1);
|
|
98
|
+
const chars = [];
|
|
99
|
+
for (;;) {
|
|
100
|
+
let count = 0;
|
|
101
|
+
try {
|
|
102
|
+
count = read(buffer);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return chars.length === 0 ? null : chars.join("");
|
|
106
|
+
}
|
|
107
|
+
if (count === 0)
|
|
108
|
+
return chars.length === 0 ? null : chars.join("");
|
|
109
|
+
const char = buffer.toString("utf8");
|
|
110
|
+
if (char === "\n")
|
|
111
|
+
return chars.join("");
|
|
112
|
+
if (char !== "\r")
|
|
113
|
+
chars.push(char);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** How long to sleep between EAGAIN retries. Short enough that a keystroke feels immediate. */
|
|
117
|
+
const EAGAIN_NAP_MS = 5;
|
|
118
|
+
const napCell = new Int32Array(new SharedArrayBuffer(4));
|
|
119
|
+
/**
|
|
120
|
+
* One byte from fd 0, blocking, whatever mode libuv left the descriptor in.
|
|
121
|
+
*
|
|
122
|
+
* EAGAIN means the terminal has nothing yet: nap and retry (`Atomics.wait` is
|
|
123
|
+
* the one synchronous sleep JavaScript has, and it keeps the wait from being a
|
|
124
|
+
* hot loop). Every other error propagates, and 0 bytes is EOF, exactly as with
|
|
125
|
+
* `readSync` itself.
|
|
126
|
+
*/
|
|
127
|
+
export function readByteBlocking(buffer) {
|
|
128
|
+
for (;;) {
|
|
129
|
+
try {
|
|
130
|
+
return readSync(0, buffer, 0, 1, null);
|
|
131
|
+
}
|
|
132
|
+
catch (cause) {
|
|
133
|
+
if (cause.code !== "EAGAIN")
|
|
134
|
+
throw cause;
|
|
135
|
+
Atomics.wait(napCell, 0, 0, EAGAIN_NAP_MS);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* A UTF-8 character's worth of bytes, popped off the end of `bytes`.
|
|
141
|
+
*
|
|
142
|
+
* Backspace deletes a CHARACTER, so the continuation bytes (`10xxxxxx`) of a
|
|
143
|
+
* multi-byte sequence come off together with their lead byte. A loop that
|
|
144
|
+
* popped one byte would leave a truncated sequence in the buffer and turn a
|
|
145
|
+
* passphrase containing an accented letter into one the operator cannot retype.
|
|
146
|
+
*/
|
|
147
|
+
function popCharacter(bytes) {
|
|
148
|
+
while (bytes.length > 0) {
|
|
149
|
+
const byte = bytes[bytes.length - 1];
|
|
150
|
+
bytes.pop();
|
|
151
|
+
if ((byte & 0xc0) !== 0x80)
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Read a secret with no echo. See the module doc for what this is worth.
|
|
157
|
+
*
|
|
158
|
+
* The byte loop, in full: `\r` or `\n` ends the read; DEL (0x7f) and BS (0x08)
|
|
159
|
+
* remove the last character and echo nothing (no cursor movement — there is
|
|
160
|
+
* nothing on screen to erase); Ctrl-C aborts always; Ctrl-D aborts only on an
|
|
161
|
+
* empty buffer, which is EOF's meaning everywhere else in a shell and which
|
|
162
|
+
* leaves the "Ctrl-D at the end of a typed line" case as an ordinary end. Every
|
|
163
|
+
* other byte accumulates.
|
|
164
|
+
*
|
|
165
|
+
* Raw mode is restored in a `finally`, and a newline is printed after, so the
|
|
166
|
+
* caller's next output starts on its own line whichever way the read ended.
|
|
167
|
+
*/
|
|
168
|
+
export function readSecret(streams, prompt, read = readByteBlocking) {
|
|
169
|
+
streams.out(prompt);
|
|
170
|
+
const stdin = process.stdin;
|
|
171
|
+
const wasRaw = stdin.isRaw === true;
|
|
172
|
+
const buffer = Buffer.alloc(1);
|
|
173
|
+
const bytes = [];
|
|
174
|
+
try {
|
|
175
|
+
stdin.setRawMode(true);
|
|
176
|
+
for (;;) {
|
|
177
|
+
let count = 0;
|
|
178
|
+
try {
|
|
179
|
+
count = read(buffer);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// EAGAIN never reaches here (readByteBlocking waits it out); anything else is the terminal going away.
|
|
183
|
+
return { ok: false, reason: "aborted" };
|
|
184
|
+
}
|
|
185
|
+
if (count === 0) {
|
|
186
|
+
return bytes.length === 0
|
|
187
|
+
? { ok: false, reason: "aborted" }
|
|
188
|
+
: { ok: true, value: Buffer.from(bytes).toString("utf8") };
|
|
189
|
+
}
|
|
190
|
+
const byte = buffer[0];
|
|
191
|
+
if (byte === CR || byte === LF) {
|
|
192
|
+
return { ok: true, value: Buffer.from(bytes).toString("utf8") };
|
|
193
|
+
}
|
|
194
|
+
if (byte === CTRL_C)
|
|
195
|
+
return { ok: false, reason: "aborted" };
|
|
196
|
+
if (byte === CTRL_D && bytes.length === 0)
|
|
197
|
+
return { ok: false, reason: "aborted" };
|
|
198
|
+
if (byte === DELETE || byte === BACKSPACE) {
|
|
199
|
+
popCharacter(bytes);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (byte === CTRL_D)
|
|
203
|
+
continue;
|
|
204
|
+
bytes.push(byte);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
try {
|
|
209
|
+
stdin.setRawMode(wasRaw);
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
/* the terminal went away; there is nothing left to restore it to */
|
|
213
|
+
}
|
|
214
|
+
streams.out("\n");
|
|
215
|
+
bytes.length = 0;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The real prompter, or `null` when stdin is not a terminal.
|
|
220
|
+
*
|
|
221
|
+
* Refusing to construct is deliberate: a prompter that fell back to reading a
|
|
222
|
+
* pipe would let a CI job answer `setup`'s confirmations by feeding it a
|
|
223
|
+
* heredoc, and "a human was asked" is the entire content of these questions.
|
|
224
|
+
* Callers check `process.stdin.isTTY` themselves and print the non-interactive
|
|
225
|
+
* alternative; this is the second lock on the same door.
|
|
226
|
+
*/
|
|
227
|
+
export function createPrompter(streams) {
|
|
228
|
+
if (process.stdin.isTTY !== true)
|
|
229
|
+
return null;
|
|
230
|
+
return {
|
|
231
|
+
readLine(prompt) {
|
|
232
|
+
streams.out(prompt);
|
|
233
|
+
return readLineFromStdin();
|
|
234
|
+
},
|
|
235
|
+
readSecret(prompt) {
|
|
236
|
+
return readSecret(streams, prompt);
|
|
237
|
+
},
|
|
238
|
+
confirm(prompt, defaultNo = true) {
|
|
239
|
+
streams.out(`${prompt} ${defaultNo ? "[y/N]" : "[Y/n]"} `);
|
|
240
|
+
const answer = (readLineFromStdin() ?? "").trim().toLowerCase();
|
|
241
|
+
if (answer.length === 0)
|
|
242
|
+
return !defaultNo;
|
|
243
|
+
return answer === "y" || answer === "yes";
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
248
|
+
// Asking again (APRV-90)
|
|
249
|
+
// ---------------------------------------------------------------------------
|
|
250
|
+
/**
|
|
251
|
+
* How many failed answers to one question before the loop gives up. See the
|
|
252
|
+
* module doc: bounded so that a prompt nobody is answering terminates.
|
|
253
|
+
*/
|
|
254
|
+
export const DEFAULT_MAX_ATTEMPTS = 5;
|
|
255
|
+
/**
|
|
256
|
+
* Ask until the answer validates, the human gives up, or the attempts run out.
|
|
257
|
+
*
|
|
258
|
+
* The reason line goes to STDOUT, indented, because it is part of the
|
|
259
|
+
* conversation and not a diagnostic about a command: it is read by the person
|
|
260
|
+
* at the terminal, in between their answer and the next prompt. A caller turns
|
|
261
|
+
* an `aborted` or `exhausted` outcome into its own one-line refusal; nothing
|
|
262
|
+
* here prints a help page (see the module doc).
|
|
263
|
+
*/
|
|
264
|
+
export function askUntil(streams, prompter, question, validate, options = {}) {
|
|
265
|
+
const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
266
|
+
for (let attempts = 1;; attempts += 1) {
|
|
267
|
+
const answer = prompter.readLine(question);
|
|
268
|
+
// Ctrl-D at the prompt, or the terminal going away. Distinct from an empty
|
|
269
|
+
// line, which is an ordinary answer a validator may accept or refuse.
|
|
270
|
+
if (answer === null)
|
|
271
|
+
return { ok: false, reason: "aborted", attempts };
|
|
272
|
+
const verdict = validate(answer);
|
|
273
|
+
if (verdict.ok)
|
|
274
|
+
return { ok: true, value: verdict.value };
|
|
275
|
+
// The reason is printed for the LAST attempt too: an operator who has just
|
|
276
|
+
// run out of tries is owed the same sentence as one who has not.
|
|
277
|
+
streams.out(` ${verdict.reason}\n`);
|
|
278
|
+
if (attempts >= maxAttempts)
|
|
279
|
+
return { ok: false, reason: "exhausted", attempts };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* A yes/no question that asks AGAIN when the answer is neither (APRV-99).
|
|
284
|
+
*
|
|
285
|
+
* {@link Prompter.confirm} takes the default for anything it does not
|
|
286
|
+
* recognise, which is the right reading for a question whose default is the
|
|
287
|
+
* safe answer: a stray keystroke declines. It is the wrong reading for a
|
|
288
|
+
* question whose default is YES and whose subject is a check the operator
|
|
289
|
+
* asked for, where a typo would silently skip the proof and report it as a
|
|
290
|
+
* decision. APRV-90's answer to that class of question is that every question
|
|
291
|
+
* loops, so this is {@link askUntil} over a yes/no validator: the same bounded
|
|
292
|
+
* loop, the same indented reason line, the same abort handling.
|
|
293
|
+
*
|
|
294
|
+
* Existing `confirm` calls are deliberately untouched — their output is pinned
|
|
295
|
+
* byte for byte — so this is an addition to the vocabulary, not a replacement.
|
|
296
|
+
* A withdrawal (Ctrl-D) or an exhausted loop reads as NO, which is the
|
|
297
|
+
* fail-closed direction for a question that offers to do something.
|
|
298
|
+
*/
|
|
299
|
+
export function confirmUntil(streams, prompter, question, defaultYes) {
|
|
300
|
+
const asked = askUntil(streams, prompter, `${question} ${defaultYes ? "[Y/n]" : "[y/N]"} `, (answer) => {
|
|
301
|
+
const typed = answer.trim().toLowerCase();
|
|
302
|
+
if (typed.length === 0)
|
|
303
|
+
return { ok: true, value: defaultYes };
|
|
304
|
+
if (typed === "y" || typed === "yes")
|
|
305
|
+
return { ok: true, value: true };
|
|
306
|
+
if (typed === "n" || typed === "no")
|
|
307
|
+
return { ok: true, value: false };
|
|
308
|
+
return { ok: false, reason: `${JSON.stringify(answer.trim())} is not yes or no` };
|
|
309
|
+
});
|
|
310
|
+
return asked.ok ? asked.value : false;
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../src/cli/prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `approval quickstart` (APRV-309): one human ceremony for a small, operative
|
|
3
|
+
* policy. The command is terminal-only, displays the exact bytes it will
|
|
4
|
+
* attest, and leaves any interrupted setup unattested.
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { type SourceRunner } from "../core/env-file.js";
|
|
8
|
+
import type { Streams } from "./main.js";
|
|
9
|
+
import { type Prompter } from "./prompt.js";
|
|
10
|
+
import type { SetupDeps } from "./setup-common.js";
|
|
11
|
+
export declare const QUICKSTART_CLASSES: readonly [{
|
|
12
|
+
readonly pattern: "communicate.*";
|
|
13
|
+
readonly label: "send a message or email";
|
|
14
|
+
}, {
|
|
15
|
+
readonly pattern: "financial.*";
|
|
16
|
+
readonly label: "spend money";
|
|
17
|
+
}, {
|
|
18
|
+
readonly pattern: "files.delete.*";
|
|
19
|
+
readonly label: "delete files";
|
|
20
|
+
}, {
|
|
21
|
+
readonly pattern: "public.*";
|
|
22
|
+
readonly label: "post publicly";
|
|
23
|
+
}, {
|
|
24
|
+
readonly pattern: "vcs.push.main";
|
|
25
|
+
readonly label: "push to main";
|
|
26
|
+
}];
|
|
27
|
+
type Channel = "cli" | "telegram";
|
|
28
|
+
export interface QuickstartDeps {
|
|
29
|
+
prompter?: Prompter | null;
|
|
30
|
+
setup?: SetupDeps;
|
|
31
|
+
sourceRunner?: SourceRunner;
|
|
32
|
+
doctor?: (dir: string, actor: string, resolvedEnv: Readonly<Record<string, string>>, apiBase: string | null) => Promise<DoctorRun>;
|
|
33
|
+
}
|
|
34
|
+
interface DoctorRun {
|
|
35
|
+
code: number;
|
|
36
|
+
stdout: string;
|
|
37
|
+
stderr: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function renderSoloPolicy(humanId: string, channel: Channel, patterns: readonly string[]): string;
|
|
40
|
+
export declare function runQuickstartDoctor(dir: string, actor: string, resolvedEnv: Readonly<Record<string, string>>, apiBase: string | null, options?: {
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
outputLimitBytes?: number;
|
|
43
|
+
spawnChild?: typeof spawn;
|
|
44
|
+
}): Promise<DoctorRun>;
|
|
45
|
+
export declare function commandQuickstart(argv: string[], streams: Streams, cwd: string, deps?: QuickstartDeps): Promise<number>;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `approval quickstart` (APRV-309): one human ceremony for a small, operative
|
|
3
|
+
* policy. The command is terminal-only, displays the exact bytes it will
|
|
4
|
+
* attest, and leaves any interrupted setup unattested.
|
|
5
|
+
*/
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { isAbsolute, join, resolve as resolvePathSegments } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { appendAttestation, HUMAN_ACTOR_ENV, policyBytesHash } from "../core/attest.js";
|
|
11
|
+
import { SECRET_ENV_PREFIXES } from "../core/child-env.js";
|
|
12
|
+
import { defaultSourceRunner, envFilePathFor, resolveEnvironment, upsertEnvFileEntries, } from "../core/env-file.js";
|
|
13
|
+
import { loadPolicy, loadPolicyText } from "../core/policy-load.js";
|
|
14
|
+
import { parseFlags, boolFlag, stringFlag } from "./args.js";
|
|
15
|
+
import { EXIT_INTEGRITY, EXIT_IO, EXIT_OK, EXIT_TORN_TAIL, EXIT_USAGE } from "./exit-codes.js";
|
|
16
|
+
import { QUICKSTART_HELP } from "./help.js";
|
|
17
|
+
import { commandInit } from "./init.js";
|
|
18
|
+
import { DEFAULT_LOG_PATH } from "./paths.js";
|
|
19
|
+
import { askUntil, createPrompter } from "./prompt.js";
|
|
20
|
+
import { commandSetupChannel } from "./setup-channel.js";
|
|
21
|
+
import { identityFromAnswer } from "./setup.js";
|
|
22
|
+
import { usageErrorText } from "./usage.js";
|
|
23
|
+
const FLAGS = {
|
|
24
|
+
"--dir": "string",
|
|
25
|
+
"--api-base": "string",
|
|
26
|
+
"--json": "boolean",
|
|
27
|
+
"--help": "boolean",
|
|
28
|
+
"-h": "boolean",
|
|
29
|
+
};
|
|
30
|
+
export const QUICKSTART_CLASSES = [
|
|
31
|
+
{ pattern: "communicate.*", label: "send a message or email" },
|
|
32
|
+
{ pattern: "financial.*", label: "spend money" },
|
|
33
|
+
{ pattern: "files.delete.*", label: "delete files" },
|
|
34
|
+
{ pattern: "public.*", label: "post publicly" },
|
|
35
|
+
{ pattern: "vcs.push.main", label: "push to main" },
|
|
36
|
+
];
|
|
37
|
+
const DOCTOR_TIMEOUT_MS = 20_000;
|
|
38
|
+
const DOCTOR_OUTPUT_LIMIT_BYTES = 256 * 1024;
|
|
39
|
+
function absolute(value, cwd) {
|
|
40
|
+
return isAbsolute(value) ? value : resolvePathSegments(cwd, value);
|
|
41
|
+
}
|
|
42
|
+
function refusal(streams, message) {
|
|
43
|
+
streams.err(usageErrorText(message, QUICKSTART_HELP));
|
|
44
|
+
return EXIT_USAGE;
|
|
45
|
+
}
|
|
46
|
+
function shellQuote(value) {
|
|
47
|
+
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
48
|
+
}
|
|
49
|
+
function nonInteractive(streams, json) {
|
|
50
|
+
const message = "quickstart needs a human at a terminal and has no JSON mode. Non-interactive equivalent: run `approval init`, write and review APPROVAL.md, run `approval setup identity`, optionally run `approval setup channel telegram`, then run `approval policy attest --as human:<id>`.";
|
|
51
|
+
if (json)
|
|
52
|
+
streams.err(`${JSON.stringify({ error: { code: "usage", message } })}\n`);
|
|
53
|
+
else
|
|
54
|
+
streams.err(usageErrorText(message, QUICKSTART_HELP));
|
|
55
|
+
return EXIT_USAGE;
|
|
56
|
+
}
|
|
57
|
+
function channelAnswer(answer) {
|
|
58
|
+
switch (answer.trim().toLowerCase()) {
|
|
59
|
+
case "1":
|
|
60
|
+
case "terminal":
|
|
61
|
+
case "cli":
|
|
62
|
+
return { ok: true, value: "cli" };
|
|
63
|
+
case "2":
|
|
64
|
+
case "telegram":
|
|
65
|
+
return { ok: true, value: "telegram" };
|
|
66
|
+
default:
|
|
67
|
+
return { ok: false, reason: "choose 1 for this terminal or 2 for Telegram" };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function classesAnswer(answer) {
|
|
71
|
+
const typed = answer.trim().toLowerCase();
|
|
72
|
+
if (typed.length === 0 || typed === "all") {
|
|
73
|
+
return { ok: true, value: QUICKSTART_CLASSES.map((entry) => entry.pattern) };
|
|
74
|
+
}
|
|
75
|
+
if (typed === "none")
|
|
76
|
+
return { ok: true, value: [] };
|
|
77
|
+
const indexes = typed.split(",").map((part) => Number(part.trim()));
|
|
78
|
+
if (indexes.some((index) => !Number.isInteger(index) || index < 1 || index > QUICKSTART_CLASSES.length)) {
|
|
79
|
+
return { ok: false, reason: "enter comma-separated numbers 1-5, all, none, or press Enter for all" };
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
ok: true,
|
|
83
|
+
value: [...new Set(indexes)].map((index) => QUICKSTART_CLASSES[index - 1]?.pattern),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function quickstartIdentity(answer) {
|
|
87
|
+
const parsed = identityFromAnswer(answer);
|
|
88
|
+
if (!parsed.ok)
|
|
89
|
+
return parsed;
|
|
90
|
+
const humanId = parsed.value.slice("human:".length);
|
|
91
|
+
return /^[a-z0-9][a-z0-9_-]*$/u.test(humanId)
|
|
92
|
+
? parsed
|
|
93
|
+
: { ok: false, reason: "the id must start with a lowercase letter or digit and contain only lowercase letters, digits, _ or -" };
|
|
94
|
+
}
|
|
95
|
+
export function renderSoloPolicy(humanId, channel, patterns) {
|
|
96
|
+
const rules = patterns
|
|
97
|
+
.map((pattern) => ` ${pattern}:\n autonomy: manual\n approvers: [${humanId}]`)
|
|
98
|
+
.join("\n");
|
|
99
|
+
const channelBlock = channel === "telegram"
|
|
100
|
+
? "\nchannels:\n telegram:\n chat_id_env: APPROVAL_TG_CHAT\n token_env: APPROVAL_TG_TOKEN\n"
|
|
101
|
+
: "";
|
|
102
|
+
return `# Approval Policy\n\nThis is a solo policy. The selected class families ask the person below.\nOther classified reversible actions use the autonomous default. Runtime safety\nfloors and unclassified-command refusals still apply.\n\n\`\`\`yaml approval-policy\nversion: "0.1"\n\ndefaults:\n autonomy: autonomous # Tighten to manual to make every unnamed class ask.\n channel: ${channel}\n approval_ttl: 24h\n on_expiry: reject\n\napprovers:\n ${humanId}:\n channels: [${channel}]\n\nclasses:\n${rules.length === 0 ? " {}" : rules}\n${channelBlock}\`\`\`\n\nNo audit block means retrospective sampling is off. Add one only through a\nhuman-reviewed policy amendment; see \`approval policy amend --help\`.\n`;
|
|
103
|
+
}
|
|
104
|
+
function appendBounded(current, chunk, limit) {
|
|
105
|
+
const remaining = limit - Buffer.byteLength(current);
|
|
106
|
+
if (remaining <= 0)
|
|
107
|
+
return { text: current, overflow: true };
|
|
108
|
+
const bytes = Buffer.from(chunk);
|
|
109
|
+
if (bytes.byteLength <= remaining)
|
|
110
|
+
return { text: current + chunk, overflow: false };
|
|
111
|
+
return { text: current + bytes.subarray(0, remaining).toString("utf8"), overflow: true };
|
|
112
|
+
}
|
|
113
|
+
export function runQuickstartDoctor(dir, actor, resolvedEnv, apiBase, options = {}) {
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
const env = { ...process.env };
|
|
116
|
+
// The check must not borrow identity or credentials from another instance.
|
|
117
|
+
// Only values explicitly resolved from this quickstart's source map return.
|
|
118
|
+
for (const name of Object.keys(env)) {
|
|
119
|
+
if (SECRET_ENV_PREFIXES.some((prefix) => name.startsWith(prefix)))
|
|
120
|
+
delete env[name];
|
|
121
|
+
}
|
|
122
|
+
Object.assign(env, resolvedEnv, { [HUMAN_ACTOR_ENV]: actor });
|
|
123
|
+
const cliEntry = fileURLToPath(new URL("./main.js", import.meta.url));
|
|
124
|
+
const childArgs = [cliEntry, "doctor", "--json", "--dir", dir];
|
|
125
|
+
if (apiBase !== null)
|
|
126
|
+
childArgs.push("--api-base", apiBase);
|
|
127
|
+
const child = (options.spawnChild ?? spawn)(process.execPath, childArgs, {
|
|
128
|
+
cwd: dir,
|
|
129
|
+
env,
|
|
130
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
131
|
+
});
|
|
132
|
+
let stdout = "";
|
|
133
|
+
let stderr = "";
|
|
134
|
+
let settled = false;
|
|
135
|
+
const outputLimit = options.outputLimitBytes ?? DOCTOR_OUTPUT_LIMIT_BYTES;
|
|
136
|
+
const finish = (result) => {
|
|
137
|
+
if (settled)
|
|
138
|
+
return;
|
|
139
|
+
settled = true;
|
|
140
|
+
clearTimeout(timer);
|
|
141
|
+
resolve(result);
|
|
142
|
+
};
|
|
143
|
+
const abortForOutput = () => {
|
|
144
|
+
child.kill("SIGTERM");
|
|
145
|
+
finish({ code: EXIT_IO, stdout, stderr: `${stderr}approval doctor output exceeded ${String(outputLimit)} bytes and was stopped\n` });
|
|
146
|
+
};
|
|
147
|
+
child.stdout.setEncoding("utf8");
|
|
148
|
+
child.stderr.setEncoding("utf8");
|
|
149
|
+
child.stdout.on("data", (text) => {
|
|
150
|
+
const next = appendBounded(stdout, text, outputLimit);
|
|
151
|
+
stdout = next.text;
|
|
152
|
+
if (next.overflow)
|
|
153
|
+
abortForOutput();
|
|
154
|
+
});
|
|
155
|
+
child.stderr.on("data", (text) => {
|
|
156
|
+
const next = appendBounded(stderr, text, outputLimit);
|
|
157
|
+
stderr = next.text;
|
|
158
|
+
if (next.overflow)
|
|
159
|
+
abortForOutput();
|
|
160
|
+
});
|
|
161
|
+
child.once("error", (cause) => finish({ code: EXIT_IO, stdout, stderr: `${stderr}${cause.message}\n` }));
|
|
162
|
+
child.once("close", (code) => finish({ code: code ?? EXIT_IO, stdout, stderr }));
|
|
163
|
+
const timer = setTimeout(() => {
|
|
164
|
+
child.kill("SIGTERM");
|
|
165
|
+
finish({ code: EXIT_IO, stdout, stderr: `${stderr}approval doctor exceeded ${String(options.timeoutMs ?? DOCTOR_TIMEOUT_MS)}ms and was stopped\n` });
|
|
166
|
+
}, options.timeoutMs ?? DOCTOR_TIMEOUT_MS);
|
|
167
|
+
timer.unref();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function doctorPreflight(run) {
|
|
171
|
+
if (run.code === EXIT_OK)
|
|
172
|
+
return { ok: true };
|
|
173
|
+
if (run.code === EXIT_INTEGRITY) {
|
|
174
|
+
try {
|
|
175
|
+
const report = JSON.parse(run.stdout);
|
|
176
|
+
const failed = report.checks?.filter((check) => check.status === "fail") ?? [];
|
|
177
|
+
if (failed.length === 1 &&
|
|
178
|
+
failed[0]?.check === "attestation" &&
|
|
179
|
+
typeof failed[0].detail === "string" &&
|
|
180
|
+
failed[0].detail.includes("has never been attested"))
|
|
181
|
+
return { ok: true };
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// The diagnostic's malformed output is reported below with its exit.
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
ok: false,
|
|
189
|
+
code: run.code,
|
|
190
|
+
message: `approval doctor preflight reported a setup problem; the policy remains unattested:\n${run.stderr}${run.stdout}`,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
export async function commandQuickstart(argv, streams, cwd, deps = {}) {
|
|
194
|
+
const json = argv.includes("--json");
|
|
195
|
+
const parsed = parseFlags(argv, FLAGS);
|
|
196
|
+
if (!parsed.ok)
|
|
197
|
+
return refusal(streams, parsed.message);
|
|
198
|
+
if (boolFlag(parsed.flags, "--help") || boolFlag(parsed.flags, "-h")) {
|
|
199
|
+
streams.out(`${QUICKSTART_HELP}\n`);
|
|
200
|
+
return EXIT_OK;
|
|
201
|
+
}
|
|
202
|
+
if (parsed.positionals.length > 0)
|
|
203
|
+
return refusal(streams, `unexpected argument ${JSON.stringify(parsed.positionals[0])}`);
|
|
204
|
+
const prompter = deps.prompter === undefined ? createPrompter(streams) : deps.prompter;
|
|
205
|
+
if (json || prompter === null)
|
|
206
|
+
return nonInteractive(streams, json);
|
|
207
|
+
const dirFlag = stringFlag(parsed.flags, "--dir");
|
|
208
|
+
const dir = dirFlag === null ? cwd : absolute(dirFlag, cwd);
|
|
209
|
+
const apiBase = stringFlag(parsed.flags, "--api-base");
|
|
210
|
+
if (existsSync(join(dir, "APPROVAL.md")) ||
|
|
211
|
+
existsSync(join(dir, "APPROVALS.md")) ||
|
|
212
|
+
existsSync(join(dir, ".approval"))) {
|
|
213
|
+
streams.err(`approval: setup artifacts already exist in ${dir}; quickstart only initializes a fresh instance and changed nothing\n`);
|
|
214
|
+
return EXIT_IO;
|
|
215
|
+
}
|
|
216
|
+
streams.out("approval quickstart — three decisions to make a solo gate operative.\n\n");
|
|
217
|
+
const identity = askUntil(streams, prompter, "1/3 your name (for human:<id>): ", quickstartIdentity);
|
|
218
|
+
if (!identity.ok)
|
|
219
|
+
return refusal(streams, "no valid human identity was entered; nothing was written");
|
|
220
|
+
const actor = identity.value;
|
|
221
|
+
const humanId = actor.slice("human:".length);
|
|
222
|
+
const channel = askUntil(streams, prompter, "2/3 button location (1 terminal, 2 Telegram): ", channelAnswer);
|
|
223
|
+
if (!channel.ok)
|
|
224
|
+
return refusal(streams, "no channel was chosen; nothing was written");
|
|
225
|
+
streams.out(`${QUICKSTART_CLASSES.map((entry, index) => ` ${String(index + 1)}. ${entry.label}`).join("\n")}\n`);
|
|
226
|
+
const selected = askUntil(streams, prompter, "3/3 always ask (numbers, Enter for all): ", classesAnswer);
|
|
227
|
+
if (!selected.ok)
|
|
228
|
+
return refusal(streams, "no valid checklist was entered; nothing was written");
|
|
229
|
+
const policy = renderSoloPolicy(humanId, channel.value, selected.value);
|
|
230
|
+
const loaded = loadPolicyText(join(dir, "APPROVAL.md"), policy);
|
|
231
|
+
if (!loaded.ok) {
|
|
232
|
+
streams.err(`approval: generated policy failed validation: ${loaded.message}\n`);
|
|
233
|
+
return EXIT_IO;
|
|
234
|
+
}
|
|
235
|
+
let initOut = "";
|
|
236
|
+
let initErr = "";
|
|
237
|
+
const initCode = commandInit([], { out: (text) => { initOut += text; }, err: (text) => { initErr += text; } }, dir, { policyText: policy });
|
|
238
|
+
if (initCode !== EXIT_OK) {
|
|
239
|
+
streams.err(`${initErr}${initOut}`);
|
|
240
|
+
return initCode;
|
|
241
|
+
}
|
|
242
|
+
const envPath = envFilePathFor(join(dir, DEFAULT_LOG_PATH));
|
|
243
|
+
const envWrite = upsertEnvFileEntries(envPath, [{ key: HUMAN_ACTOR_ENV, value: actor }]);
|
|
244
|
+
if (!envWrite.ok) {
|
|
245
|
+
streams.err(`approval: ${envWrite.message}\n`);
|
|
246
|
+
return EXIT_IO;
|
|
247
|
+
}
|
|
248
|
+
if (channel.value === "telegram") {
|
|
249
|
+
const setupArgs = ["telegram", "--as", actor, "--dir", dir];
|
|
250
|
+
if (apiBase !== null)
|
|
251
|
+
setupArgs.push("--api-base", apiBase);
|
|
252
|
+
const setupCode = await commandSetupChannel(setupArgs, streams, dir, { ...deps.setup, prompter });
|
|
253
|
+
if (setupCode !== EXIT_OK)
|
|
254
|
+
return setupCode;
|
|
255
|
+
}
|
|
256
|
+
const onDisk = loadPolicy({ dir });
|
|
257
|
+
if (!onDisk.ok) {
|
|
258
|
+
streams.err(`approval: generated policy could not be reloaded for preflight: ${onDisk.message}\n`);
|
|
259
|
+
return EXIT_IO;
|
|
260
|
+
}
|
|
261
|
+
const resolution = resolveEnvironment(onDisk, envPath, deps.sourceRunner ?? defaultSourceRunner, {});
|
|
262
|
+
if (!resolution.ok) {
|
|
263
|
+
streams.err(`approval: quickstart environment could not be resolved: ${resolution.message}\n`);
|
|
264
|
+
return EXIT_IO;
|
|
265
|
+
}
|
|
266
|
+
const resolvedEnv = {};
|
|
267
|
+
for (const variable of resolution.variables) {
|
|
268
|
+
if (variable.value !== undefined)
|
|
269
|
+
resolvedEnv[variable.name] = variable.value;
|
|
270
|
+
else if (variable.declared) {
|
|
271
|
+
streams.err(`approval: ${variable.name} could not be resolved from this instance (${variable.source}); the policy remains unattested\n`);
|
|
272
|
+
return EXIT_IO;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const doctor = await (deps.doctor ?? runQuickstartDoctor)(dir, actor, resolvedEnv, apiBase);
|
|
276
|
+
const preflight = doctorPreflight(doctor);
|
|
277
|
+
if (!preflight.ok) {
|
|
278
|
+
streams.err(preflight.message);
|
|
279
|
+
return preflight.code;
|
|
280
|
+
}
|
|
281
|
+
streams.out(`\nReview the exact policy that will become operative:\n\n${policy}\n`);
|
|
282
|
+
const understood = askUntil(streams, prompter, "type understood to attest these exact bytes: ", (answer) => answer.trim() === "understood"
|
|
283
|
+
? { ok: true, value: true }
|
|
284
|
+
: { ok: false, reason: "type understood exactly, or Ctrl-D to leave the policy unattested" });
|
|
285
|
+
if (!understood.ok)
|
|
286
|
+
return refusal(streams, "policy left unattested");
|
|
287
|
+
const attestation = appendAttestation(join(dir, DEFAULT_LOG_PATH), join(dir, "APPROVAL.md"), actor, { expectedSha256: policyBytesHash(Buffer.from(policy, "utf8")) });
|
|
288
|
+
if (!attestation.ok) {
|
|
289
|
+
streams.err(`approval: ${attestation.error.message}\n`);
|
|
290
|
+
return attestation.error.code === "corrupt-tail" ? EXIT_TORN_TAIL : EXIT_IO;
|
|
291
|
+
}
|
|
292
|
+
streams.out(`ready: ${String(selected.value.length)} selected class families ask ${actor} on ${channel.value}; other classified reversible actions use the autonomous default\n`);
|
|
293
|
+
streams.out(`activate: eval "$(approval env --dir ${shellQuote(dir)})"\n`);
|
|
294
|
+
streams.out("try: approval hook classify -- curl -X POST https://api.example.com/apply\n");
|
|
295
|
+
return EXIT_OK;
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=quickstart.js.map
|