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,747 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AGENTS.md permissions import (SPEC.md §2, §12) — turn permissions PROSE into
|
|
3
|
+
* a DRAFT policy block a human can read, correct, and confirm.
|
|
4
|
+
*
|
|
5
|
+
* SPEC.md §2 names the gap this closes: AGENTS.md files "routinely contain
|
|
6
|
+
* permissions sections splitting actions into 'allowed without prompting' and
|
|
7
|
+
* 'require approval first'", and "nothing checks". SPEC.md §12 gives the verb:
|
|
8
|
+
* `approval import agents-md` "parses ... permissions sections into draft
|
|
9
|
+
* policy classes for human confirmation".
|
|
10
|
+
*
|
|
11
|
+
* ## This module is deterministic, and there is no model in it
|
|
12
|
+
*
|
|
13
|
+
* Per CLAUDE.md's engineering invariants, routing and policy are pure
|
|
14
|
+
* deterministic code; LLMs are confined to language tasks. Reading a bullet
|
|
15
|
+
* list is a language task in appearance only — its OUTPUT is a permission
|
|
16
|
+
* document, so the mapping is a fixed, ordered, documented keyword table
|
|
17
|
+
* ({@link CLASS_TABLE}), not a judgement. The same bytes always produce the
|
|
18
|
+
* same draft, on any machine, with no network and no clock. An LLM-assisted
|
|
19
|
+
* `--suggest` (proposing classes for bullets this table cannot place) is a
|
|
20
|
+
* separate, opt-in, out-of-scope idea: it would be allowed to propose, never
|
|
21
|
+
* to decide.
|
|
22
|
+
*
|
|
23
|
+
* ## The grammar
|
|
24
|
+
*
|
|
25
|
+
* Input is CommonMark-ish markdown. The scanner is line-based:
|
|
26
|
+
*
|
|
27
|
+
* - **Fenced code blocks** (``` or ~~~, 3+ markers, indented at most 3 spaces)
|
|
28
|
+
* are skipped entirely. A bullet inside an example block is an example.
|
|
29
|
+
* - **Headings** are ATX only: `^ {0,3}#{1,6}\s+text`, trailing `#`s stripped.
|
|
30
|
+
* Setext headings are not recognised; the convention in the wild is ATX.
|
|
31
|
+
* - A heading whose text contains `permissions` (case-insensitive, at any
|
|
32
|
+
* level) opens the **permissions region**. The region closes at the next
|
|
33
|
+
* non-canonical heading whose level is less than or equal to the permissions
|
|
34
|
+
* heading's level.
|
|
35
|
+
* - Three **canonical sub-headings** open a section, matched case-insensitively
|
|
36
|
+
* against {@link SECTION_PHRASES} after normalisation (lowercased, markdown
|
|
37
|
+
* emphasis and backticks stripped, whitespace collapsed, trailing `:`
|
|
38
|
+
* dropped). They are recognised at ANY level and, deliberately, whether or
|
|
39
|
+
* not a parent `Permissions` heading exists: the bare three-heading layout is
|
|
40
|
+
* common in AGENTS.md files.
|
|
41
|
+
* - **Bullets** are `-` or `*` list items (`^\s*[-*]\s+`) appearing while a
|
|
42
|
+
* section is open. A following line that is not blank, not a heading, not a
|
|
43
|
+
* list item and not a fence is a **continuation** and is joined to the
|
|
44
|
+
* previous bullet with a single space. Any heading closes the open section.
|
|
45
|
+
* - Every other line is ignored.
|
|
46
|
+
*
|
|
47
|
+
* Non-canonical headings seen inside the permissions region, and non-canonical
|
|
48
|
+
* headings that interrupt an open section, are reported in `ignored` rather
|
|
49
|
+
* than silently dropped: a heading the importer did not understand may be
|
|
50
|
+
* carrying permissions prose, and the human confirming the draft is the one who
|
|
51
|
+
* should decide.
|
|
52
|
+
*
|
|
53
|
+
* ## Fail closed
|
|
54
|
+
*
|
|
55
|
+
* A bullet the table cannot place is NOT guessed at and NOT dropped. It becomes
|
|
56
|
+
* an `unmapped` entry, is preserved verbatim as a comment in the draft, and is
|
|
57
|
+
* covered by `defaults.autonomy: manual` — the strictest outcome available.
|
|
58
|
+
* Likewise a source with no permissions section produces an empty draft (all
|
|
59
|
+
* classes manual by default) plus a warning, never a permissive one.
|
|
60
|
+
*
|
|
61
|
+
* ## The values draft
|
|
62
|
+
*
|
|
63
|
+
* Since APRV-240 the same file is scanned a second time for four optional
|
|
64
|
+
* headings ("what I value", "what good looks like", "how I like to work",
|
|
65
|
+
* "what I want from you") and their bullets are drafted into a
|
|
66
|
+
* ` ```yaml approval-values ` block (SPEC.md §5.3). Every bullet lands in
|
|
67
|
+
* `wants:`, and nothing is ever placed in `love:`, `like:` or `dislike:`.
|
|
68
|
+
* Grading is the human's act. This importer can see that a line was written
|
|
69
|
+
* down; it cannot see how much its author meant it, and a guessed grade would
|
|
70
|
+
* put words in their mouth inside the one block of `APPROVAL.md` that exists to
|
|
71
|
+
* carry their own.
|
|
72
|
+
*
|
|
73
|
+
* ## Namespaces
|
|
74
|
+
*
|
|
75
|
+
* SPEC.md §7 reserves top-level namespaces to the spec and lets implementations
|
|
76
|
+
* add sub-classes freely. The developer-workstation vocabulary this table emits
|
|
77
|
+
* (`vcs.*`, `deps.*`, `release.*`, `exec.*`, `network.*`, `policy.edit`) is not
|
|
78
|
+
* in the §7 table, which was written for life-admin side effects. That is a
|
|
79
|
+
* deliberate, visible property of a DRAFT: the classes are proposals a human
|
|
80
|
+
* renames or upstreams before confirming, and the draft says so in its header.
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* Canonical section phrases and their tolerant variants, matched against a
|
|
84
|
+
* normalised heading by exact equality first and then by prefix/containment of
|
|
85
|
+
* the variant inside the heading. Order matters only between sections: a
|
|
86
|
+
* heading matching more than one section's variants takes the FIRST section in
|
|
87
|
+
* this list, and the list is ordered strictest-first so an ambiguous heading
|
|
88
|
+
* lands on the stricter reading.
|
|
89
|
+
*/
|
|
90
|
+
const SECTION_PHRASES = [
|
|
91
|
+
["never", ["never", "never do", "forbidden", "prohibited", "not permitted", "off limits"]],
|
|
92
|
+
[
|
|
93
|
+
"approval-first",
|
|
94
|
+
[
|
|
95
|
+
"require approval first",
|
|
96
|
+
"requires approval",
|
|
97
|
+
"require approval",
|
|
98
|
+
"approval required",
|
|
99
|
+
"ask first",
|
|
100
|
+
"ask before",
|
|
101
|
+
"needs approval",
|
|
102
|
+
],
|
|
103
|
+
],
|
|
104
|
+
[
|
|
105
|
+
"allowed",
|
|
106
|
+
[
|
|
107
|
+
"allowed without prompting",
|
|
108
|
+
"allowed without asking",
|
|
109
|
+
"allowed",
|
|
110
|
+
"autonomous",
|
|
111
|
+
"no prompt needed",
|
|
112
|
+
"safe to run",
|
|
113
|
+
],
|
|
114
|
+
],
|
|
115
|
+
];
|
|
116
|
+
/** Marker that a heading opens the permissions region. */
|
|
117
|
+
const PERMISSIONS_MARKER = "permissions";
|
|
118
|
+
/**
|
|
119
|
+
* The class heuristic: an ORDERED, STABLE table. First match wins, and the
|
|
120
|
+
* order of this array IS the precedence. Each entry lists alternative keyword
|
|
121
|
+
* conjunctions; an alternative matches when every one of its keywords appears
|
|
122
|
+
* as a substring of the normalised bullet text.
|
|
123
|
+
*
|
|
124
|
+
* Ordering rules, so future edits stay principled:
|
|
125
|
+
*
|
|
126
|
+
* 1. The most consequential and most specific classes come first, because a
|
|
127
|
+
* bullet naming several actions ("git push, merges to main, tag creation")
|
|
128
|
+
* is placed by its first match and the safer placement is the broader,
|
|
129
|
+
* more consequential class.
|
|
130
|
+
* 2. `network.call` precedes `deps.add` on purpose: "any network call beyond
|
|
131
|
+
* package installs" contains "install" and is not a dependency bullet.
|
|
132
|
+
* 3. `vcs.push` precedes `vcs.push.main`: a bullet naming pushes generally
|
|
133
|
+
* should govern all pushes, not only pushes to the default branch.
|
|
134
|
+
* 4. Generic verbs (`edit`, `read`) come last, since almost every bullet
|
|
135
|
+
* contains one.
|
|
136
|
+
*
|
|
137
|
+
* Adding a keyword here changes what a draft proposes for existing files, so
|
|
138
|
+
* the table is pinned byte-for-byte by `tests/agents-md.test.ts` fixtures.
|
|
139
|
+
*/
|
|
140
|
+
export const CLASS_TABLE = [
|
|
141
|
+
{
|
|
142
|
+
cls: "account.credential",
|
|
143
|
+
any: [["credential"], ["token"], ["vault"], ["secret"], ["api key"], ["password"]],
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
cls: "vcs.history.rewrite",
|
|
147
|
+
any: [["rewrite", "history"], ["force-push"], ["force push"], ["--force"]],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
cls: "policy.edit",
|
|
151
|
+
any: [
|
|
152
|
+
["approval.md"],
|
|
153
|
+
["approvals.md"],
|
|
154
|
+
[".approval/"],
|
|
155
|
+
["agents.md"],
|
|
156
|
+
["claude.md"],
|
|
157
|
+
["policy file"],
|
|
158
|
+
["ci config"],
|
|
159
|
+
["ci/release"],
|
|
160
|
+
["release config"],
|
|
161
|
+
["workflow file"],
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
{ cls: "vcs.push", any: [["git push"], ["push"]] },
|
|
165
|
+
{ cls: "vcs.push.main", any: [["merge", "main"], ["merge", "master"], ["merge", "trunk"]] },
|
|
166
|
+
{
|
|
167
|
+
cls: "release.publish",
|
|
168
|
+
any: [
|
|
169
|
+
["npm publish"],
|
|
170
|
+
["npm version"],
|
|
171
|
+
["registry"],
|
|
172
|
+
["tag creation"],
|
|
173
|
+
["create a tag"],
|
|
174
|
+
["publish"],
|
|
175
|
+
["release"],
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
cls: "network.call",
|
|
180
|
+
any: [["network"], ["api call"], ["webhook"], ["send"], ["http"], ["outbound"], ["email"]],
|
|
181
|
+
},
|
|
182
|
+
{ cls: "deps.add", any: [["depend"], ["install"], ["upgrade"]] },
|
|
183
|
+
// "delet" rather than "delete": the stem is what matches "deleting" and
|
|
184
|
+
// "deletion" too, and a bullet that says "Deleting files ..." must not fall
|
|
185
|
+
// through to unmapped on an inflection.
|
|
186
|
+
{ cls: "data.delete", any: [["delet"], ["rm -rf"], ["destroy"], ["drop table"]] },
|
|
187
|
+
{ cls: "vcs.commit.branch", any: [["commit"]] },
|
|
188
|
+
{
|
|
189
|
+
cls: "exec.local",
|
|
190
|
+
any: [
|
|
191
|
+
["run tests"],
|
|
192
|
+
["run the tests"],
|
|
193
|
+
["lint"],
|
|
194
|
+
["typecheck"],
|
|
195
|
+
["type-check"],
|
|
196
|
+
["build"],
|
|
197
|
+
["script"],
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
cls: "files.write.workspace",
|
|
202
|
+
any: [["edit"], ["write"], ["writing"], ["modif"], ["refactor"]],
|
|
203
|
+
},
|
|
204
|
+
{ cls: "read.*", any: [["read"], ["list director"], ["search"], ["inspect"], ["grep"]] },
|
|
205
|
+
];
|
|
206
|
+
/** Strictness rank; lower is stricter (SPEC.md §5.2 "deny beats allow"). */
|
|
207
|
+
const STRICTNESS = {
|
|
208
|
+
manual: 0,
|
|
209
|
+
supervised: 1,
|
|
210
|
+
autonomous: 2,
|
|
211
|
+
};
|
|
212
|
+
/** Autonomy a section proposes. `never` has no v0.1 level of its own. */
|
|
213
|
+
const SECTION_AUTONOMY = {
|
|
214
|
+
allowed: "autonomous",
|
|
215
|
+
"approval-first": "manual",
|
|
216
|
+
never: "manual",
|
|
217
|
+
};
|
|
218
|
+
/** Lowercase, strip emphasis/backticks, collapse whitespace, drop trailing ':'. */
|
|
219
|
+
function normaliseHeading(text) {
|
|
220
|
+
return text
|
|
221
|
+
.replace(/[`*_]/gu, "")
|
|
222
|
+
.trim()
|
|
223
|
+
.replace(/[:.]+$/u, "")
|
|
224
|
+
.replace(/\s+/gu, " ")
|
|
225
|
+
.toLowerCase();
|
|
226
|
+
}
|
|
227
|
+
/** Match a heading against the section phrases; `null` when it is not one. */
|
|
228
|
+
function sectionOf(heading) {
|
|
229
|
+
const text = normaliseHeading(heading);
|
|
230
|
+
if (text.length === 0)
|
|
231
|
+
return null;
|
|
232
|
+
for (const [section, phrases] of SECTION_PHRASES) {
|
|
233
|
+
for (const phrase of phrases) {
|
|
234
|
+
if (text === phrase || text.startsWith(`${phrase} `) || text.includes(phrase)) {
|
|
235
|
+
return section;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
/** Text used for keyword matching: lowercased with whitespace collapsed. */
|
|
242
|
+
export function normaliseBullet(text) {
|
|
243
|
+
return text.replace(/\s+/gu, " ").trim().toLowerCase();
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* The class this bullet proposes, or `null` when the table cannot place it.
|
|
247
|
+
*
|
|
248
|
+
* Deterministic, total, and side-effect free: the first entry of
|
|
249
|
+
* {@link CLASS_TABLE} with a satisfied keyword conjunction wins.
|
|
250
|
+
*/
|
|
251
|
+
export function classifyBullet(text) {
|
|
252
|
+
const haystack = normaliseBullet(text);
|
|
253
|
+
for (const entry of CLASS_TABLE) {
|
|
254
|
+
for (const alternative of entry.any) {
|
|
255
|
+
if (alternative.every((keyword) => haystack.includes(keyword)))
|
|
256
|
+
return entry.cls;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})/u;
|
|
262
|
+
const HEADING = /^ {0,3}(#{1,6})\s+(.*)$/u;
|
|
263
|
+
const LIST_ITEM = /^\s*[-*]\s+(.*)$/u;
|
|
264
|
+
/**
|
|
265
|
+
* Parse the permissions region of an AGENTS.md-style document.
|
|
266
|
+
*
|
|
267
|
+
* Never throws. Pure function of `markdown`; see the module header for the
|
|
268
|
+
* grammar it accepts.
|
|
269
|
+
*/
|
|
270
|
+
export function parseAgentsMd(markdown) {
|
|
271
|
+
const sections = { allowed: [], approvalFirst: [], never: [] };
|
|
272
|
+
const ignored = [];
|
|
273
|
+
const warnings = [];
|
|
274
|
+
const lines = markdown.split(/\r\n|\n|\r/u);
|
|
275
|
+
let fence = null;
|
|
276
|
+
let inRegion = false;
|
|
277
|
+
let regionLevel = 0;
|
|
278
|
+
let sawPermissionsHeading = false;
|
|
279
|
+
let current = null;
|
|
280
|
+
let currentLevel = 0;
|
|
281
|
+
let lastBullet = null;
|
|
282
|
+
const bucket = (section) => section === "allowed"
|
|
283
|
+
? sections.allowed
|
|
284
|
+
: section === "approval-first"
|
|
285
|
+
? sections.approvalFirst
|
|
286
|
+
: sections.never;
|
|
287
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
288
|
+
const line = lines[index];
|
|
289
|
+
const lineNumber = index + 1;
|
|
290
|
+
if (fence !== null) {
|
|
291
|
+
const close = FENCE_OPEN.exec(line);
|
|
292
|
+
const marker = close === null ? "" : (close[1] ?? "");
|
|
293
|
+
if (marker.length >= fence.length && marker.startsWith(fence.slice(0, 1)))
|
|
294
|
+
fence = null;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const open = FENCE_OPEN.exec(line);
|
|
298
|
+
if (open !== null) {
|
|
299
|
+
fence = open[1];
|
|
300
|
+
lastBullet = null;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const heading = HEADING.exec(line);
|
|
304
|
+
if (heading !== null) {
|
|
305
|
+
const level = heading[1].length;
|
|
306
|
+
const raw = heading[2].replace(/\s+#+\s*$/u, "").trim();
|
|
307
|
+
lastBullet = null;
|
|
308
|
+
const section = sectionOf(raw);
|
|
309
|
+
if (section !== null) {
|
|
310
|
+
current = section;
|
|
311
|
+
currentLevel = level;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
const wasInSection = current !== null;
|
|
315
|
+
const sectionLevel = currentLevel;
|
|
316
|
+
current = null;
|
|
317
|
+
if (normaliseHeading(raw).includes(PERMISSIONS_MARKER)) {
|
|
318
|
+
inRegion = true;
|
|
319
|
+
sawPermissionsHeading = true;
|
|
320
|
+
regionLevel = level;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (inRegion && level <= regionLevel) {
|
|
324
|
+
inRegion = false;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (inRegion || (wasInSection && level > sectionLevel))
|
|
328
|
+
ignored.push(raw);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (current === null) {
|
|
332
|
+
lastBullet = null;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
const item = LIST_ITEM.exec(line);
|
|
336
|
+
if (item !== null) {
|
|
337
|
+
const text = item[1].trim();
|
|
338
|
+
if (text.length === 0) {
|
|
339
|
+
lastBullet = null;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const bullet = { text, line: lineNumber };
|
|
343
|
+
bucket(current).push(bullet);
|
|
344
|
+
lastBullet = bullet;
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (line.trim().length === 0) {
|
|
348
|
+
lastBullet = null;
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
// A continuation of the previous bullet: wrapped prose, joined with one
|
|
352
|
+
// space so the draft's comment carries the whole sentence.
|
|
353
|
+
if (lastBullet !== null)
|
|
354
|
+
lastBullet.text = `${lastBullet.text} ${line.trim()}`;
|
|
355
|
+
}
|
|
356
|
+
const total = sections.allowed.length + sections.approvalFirst.length + sections.never.length;
|
|
357
|
+
if (total === 0) {
|
|
358
|
+
warnings.push(sawPermissionsHeading
|
|
359
|
+
? "a permissions heading was found but no bullets under any recognised section (allowed / require approval first / never); the draft declares no classes and everything falls to defaults.autonomy: manual"
|
|
360
|
+
: "no permissions section found (looked for a heading containing \"permissions\", or the sub-headings \"allowed without prompting\" / \"require approval first\" / \"never\"); the draft declares no classes and everything falls to defaults.autonomy: manual");
|
|
361
|
+
}
|
|
362
|
+
return { sections, ignored, warnings };
|
|
363
|
+
}
|
|
364
|
+
// ---------------------------------------------------------------------------
|
|
365
|
+
// The values headings (APRV-240)
|
|
366
|
+
/**
|
|
367
|
+
* Headings whose bullets become a DRAFT values block (SPEC.md §5.3).
|
|
368
|
+
*
|
|
369
|
+
* Matched against a heading run through {@link normaliseHeading}, at ANY level,
|
|
370
|
+
* with the tolerance {@link sectionOf} already uses (equality, then prefix,
|
|
371
|
+
* then containment), so "## What I value most" and "**What I want from you:**"
|
|
372
|
+
* are recognised too. Four phrases and no more: this is a fixed vocabulary a
|
|
373
|
+
* human can be told about in one line of documentation, and a wider net would
|
|
374
|
+
* start collecting prose nobody offered as values.
|
|
375
|
+
*/
|
|
376
|
+
const VALUES_HEADING_PHRASES = [
|
|
377
|
+
"what i value",
|
|
378
|
+
"what good looks like",
|
|
379
|
+
"how i like to work",
|
|
380
|
+
"what i want from you",
|
|
381
|
+
];
|
|
382
|
+
/**
|
|
383
|
+
* The caps of `values.schema.json` `$defs/valueList`, restated so the renderer
|
|
384
|
+
* can respect them without importing a validator. `tests/agents-md.test.ts`
|
|
385
|
+
* reads the schema and asserts these two numbers still match it, so the copy
|
|
386
|
+
* cannot drift.
|
|
387
|
+
*/
|
|
388
|
+
const VALUES_MAX_ITEMS = 20;
|
|
389
|
+
const VALUES_MAX_LENGTH = 200;
|
|
390
|
+
/** True when this heading opens a values section. */
|
|
391
|
+
function isValuesHeading(heading) {
|
|
392
|
+
const text = normaliseHeading(heading);
|
|
393
|
+
if (text.length === 0)
|
|
394
|
+
return false;
|
|
395
|
+
return VALUES_HEADING_PHRASES.some((phrase) => text === phrase || text.startsWith(`${phrase} `) || text.includes(phrase));
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Bring one bullet under the schema's 200-character cap.
|
|
399
|
+
*
|
|
400
|
+
* Truncation with a visible marker, rather than refusing the draft or dropping
|
|
401
|
+
* the entry. The draft exists to be read and corrected by hand, so a line the
|
|
402
|
+
* human can see is over-long is a line they can repair in place; refusing would
|
|
403
|
+
* cost them the other nineteen bullets over one long sentence, and dropping is
|
|
404
|
+
* the one outcome ruled out everywhere in this module. Sliced by CODE POINT, so
|
|
405
|
+
* an astral character is never cut in half (Ajv measures `maxLength` the same
|
|
406
|
+
* way).
|
|
407
|
+
*/
|
|
408
|
+
function capLength(text) {
|
|
409
|
+
const points = [...text];
|
|
410
|
+
if (points.length <= VALUES_MAX_LENGTH)
|
|
411
|
+
return { text, truncated: false };
|
|
412
|
+
return { text: `${points.slice(0, VALUES_MAX_LENGTH - 1).join("")}…`, truncated: true };
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Collect the bullets under the optional values headings of an AGENTS.md-style
|
|
416
|
+
* document (SPEC.md §5.3).
|
|
417
|
+
*
|
|
418
|
+
* ## Everything goes to `wants`, and nothing is graded
|
|
419
|
+
*
|
|
420
|
+
* The values block has three standing grades (`love`, `like`, `dislike`) and
|
|
421
|
+
* one behavioural list (`wants`). This function fills `wants` and leaves the
|
|
422
|
+
* three grades empty, always. A grade is a statement of taste, and it is the
|
|
423
|
+
* human's to make: the source shows that a line was written under a heading, it
|
|
424
|
+
* does not show how strongly it was meant, and an importer that inferred
|
|
425
|
+
* "love" from an exclamation mark or a heading's wording would be putting words
|
|
426
|
+
* in its reader's mouth in the one block of `APPROVAL.md` that exists to carry
|
|
427
|
+
* theirs. `wants` is the honest destination for a bullet whose grade is
|
|
428
|
+
* unknown: it says the operator asked for something, which is exactly what a
|
|
429
|
+
* bullet under "what I want from you" demonstrates.
|
|
430
|
+
*
|
|
431
|
+
* ## The scan
|
|
432
|
+
*
|
|
433
|
+
* A second line-based pass over the same primitives {@link parseAgentsMd} uses,
|
|
434
|
+
* with the same rules: fenced code blocks are skipped whole (a bullet in an
|
|
435
|
+
* example block is an example), headings are ATX at any level, a values heading
|
|
436
|
+
* opens a section, any other heading closes one, and a non-blank line that is
|
|
437
|
+
* not a bullet, heading or fence is a continuation joined to the previous
|
|
438
|
+
* bullet with a single space.
|
|
439
|
+
*
|
|
440
|
+
* Never throws. No clock, no filesystem, no network.
|
|
441
|
+
*/
|
|
442
|
+
export function parseValuesHeadings(markdown) {
|
|
443
|
+
const headings = [];
|
|
444
|
+
const collected = [];
|
|
445
|
+
const warnings = [];
|
|
446
|
+
const lines = markdown.split(/\r\n|\n|\r/u);
|
|
447
|
+
let fence = null;
|
|
448
|
+
let open = false;
|
|
449
|
+
let lastBullet = null;
|
|
450
|
+
for (const line of lines) {
|
|
451
|
+
if (fence !== null) {
|
|
452
|
+
const close = FENCE_OPEN.exec(line);
|
|
453
|
+
const marker = close === null ? "" : (close[1] ?? "");
|
|
454
|
+
if (marker.length >= fence.length && marker.startsWith(fence.slice(0, 1)))
|
|
455
|
+
fence = null;
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
const opened = FENCE_OPEN.exec(line);
|
|
459
|
+
if (opened !== null) {
|
|
460
|
+
fence = opened[1];
|
|
461
|
+
lastBullet = null;
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const heading = HEADING.exec(line);
|
|
465
|
+
if (heading !== null) {
|
|
466
|
+
const raw = heading[2].replace(/\s+#+\s*$/u, "").trim();
|
|
467
|
+
lastBullet = null;
|
|
468
|
+
open = isValuesHeading(raw);
|
|
469
|
+
if (open)
|
|
470
|
+
headings.push(normaliseHeading(raw));
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
if (!open) {
|
|
474
|
+
lastBullet = null;
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
const item = LIST_ITEM.exec(line);
|
|
478
|
+
if (item !== null) {
|
|
479
|
+
const text = item[1].trim();
|
|
480
|
+
if (text.length === 0) {
|
|
481
|
+
lastBullet = null;
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
const bullet = { text };
|
|
485
|
+
collected.push(bullet);
|
|
486
|
+
lastBullet = bullet;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
if (line.trim().length === 0) {
|
|
490
|
+
lastBullet = null;
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (lastBullet !== null)
|
|
494
|
+
lastBullet.text = `${lastBullet.text} ${line.trim()}`;
|
|
495
|
+
}
|
|
496
|
+
const seen = new Set();
|
|
497
|
+
const unique = [];
|
|
498
|
+
let duplicates = 0;
|
|
499
|
+
for (const bullet of collected) {
|
|
500
|
+
const capped = capLength(bullet.text);
|
|
501
|
+
if (capped.truncated) {
|
|
502
|
+
warnings.push(`a values bullet is ${String([...bullet.text].length)} characters and values.schema.json caps an entry at ${String(VALUES_MAX_LENGTH)}; the draft carries it truncated rather than dropping it, so shorten it by hand before confirming: ${JSON.stringify(capped.text)}`);
|
|
503
|
+
}
|
|
504
|
+
// Deduped AFTER truncation, because `uniqueItems` is checked on the values
|
|
505
|
+
// the block actually carries: two long bullets that differ only past the
|
|
506
|
+
// cap become one entry, and a draft that emitted both would fail its schema.
|
|
507
|
+
if (seen.has(capped.text)) {
|
|
508
|
+
duplicates += 1;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
seen.add(capped.text);
|
|
512
|
+
unique.push(capped.text);
|
|
513
|
+
}
|
|
514
|
+
if (duplicates > 0) {
|
|
515
|
+
warnings.push(`${String(duplicates)} repeated values ${duplicates === 1 ? "bullet was" : "bullets were"} collapsed; values.schema.json requires the entries of a list to be unique`);
|
|
516
|
+
}
|
|
517
|
+
const wants = unique.slice(0, VALUES_MAX_ITEMS);
|
|
518
|
+
const overflow = unique.slice(VALUES_MAX_ITEMS);
|
|
519
|
+
if (overflow.length > 0) {
|
|
520
|
+
warnings.push(`${String(overflow.length)} values ${overflow.length === 1 ? "bullet is" : "bullets are"} past the cap of ${String(VALUES_MAX_ITEMS)}; they are preserved as comments in the draft instead of in wants:, and a human promotes the ones they want`);
|
|
521
|
+
}
|
|
522
|
+
return { headings, wants, overflow, warnings };
|
|
523
|
+
}
|
|
524
|
+
/** Ordered (section, bullet) pairs: allowed, then approval-first, then never. */
|
|
525
|
+
function orderedBullets(parse) {
|
|
526
|
+
return [
|
|
527
|
+
...parse.sections.allowed.map((bullet) => ({ bullet, section: "allowed" })),
|
|
528
|
+
...parse.sections.approvalFirst.map((bullet) => ({
|
|
529
|
+
bullet,
|
|
530
|
+
section: "approval-first",
|
|
531
|
+
})),
|
|
532
|
+
...parse.sections.never.map((bullet) => ({ bullet, section: "never" })),
|
|
533
|
+
];
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Parse and classify: the whole deterministic half of `approval import
|
|
537
|
+
* agents-md`. Emitting bytes is {@link renderDraftPolicy}'s job.
|
|
538
|
+
*
|
|
539
|
+
* Conflicts follow SPEC.md §5.2 "deny beats allow": when bullets from different
|
|
540
|
+
* sections claim the same class, the strictest autonomy wins and a warning
|
|
541
|
+
* names both bullets, because a class that appears in both an allow list and an
|
|
542
|
+
* approval list is a contradiction in the SOURCE that a human must resolve.
|
|
543
|
+
*/
|
|
544
|
+
export function importAgentsMd(markdown) {
|
|
545
|
+
const parse = parseAgentsMd(markdown);
|
|
546
|
+
const values = parseValuesHeadings(markdown);
|
|
547
|
+
// The values notes join the one list every surface already prints. They are
|
|
548
|
+
// notes about a block that enforces nothing, so they change no verdict and
|
|
549
|
+
// never make the policy half of this import fail.
|
|
550
|
+
const warnings = [...parse.warnings, ...values.warnings];
|
|
551
|
+
const unmapped = [];
|
|
552
|
+
const byClass = new Map();
|
|
553
|
+
for (const { bullet, section } of orderedBullets(parse)) {
|
|
554
|
+
const cls = classifyBullet(bullet.text);
|
|
555
|
+
if (cls === null) {
|
|
556
|
+
unmapped.push({ text: bullet.text, section });
|
|
557
|
+
warnings.push(`no class matched ${JSON.stringify(bullet.text)} (section: ${section}); it is preserved as a comment and covered by defaults.autonomy: manual`);
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
const autonomy = SECTION_AUTONOMY[section];
|
|
561
|
+
const existing = byClass.get(cls);
|
|
562
|
+
if (existing === undefined) {
|
|
563
|
+
byClass.set(cls, {
|
|
564
|
+
cls,
|
|
565
|
+
autonomy,
|
|
566
|
+
bullets: [{ text: bullet.text, section }],
|
|
567
|
+
from: { text: bullet.text, section },
|
|
568
|
+
});
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
existing.bullets.push({ text: bullet.text, section });
|
|
572
|
+
if (existing.from.section !== section) {
|
|
573
|
+
const stricter = STRICTNESS[autonomy] < STRICTNESS[existing.autonomy];
|
|
574
|
+
const winner = stricter ? autonomy : existing.autonomy;
|
|
575
|
+
warnings.push(`class ${cls} is claimed by two sections; the stricter autonomy wins (${winner}): ${JSON.stringify(existing.from.text)} (${existing.from.section}) and ${JSON.stringify(bullet.text)} (${section})`);
|
|
576
|
+
if (stricter) {
|
|
577
|
+
existing.autonomy = autonomy;
|
|
578
|
+
existing.from = { text: bullet.text, section };
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return { classes: [...byClass.values()], unmapped, ignored: parse.ignored, warnings, values };
|
|
583
|
+
}
|
|
584
|
+
/** Info string of the machine-readable policy block (SPEC.md §5). */
|
|
585
|
+
export const POLICY_INFO_STRING = "yaml approval-policy";
|
|
586
|
+
/**
|
|
587
|
+
* Info string of the OPTIONAL values block (SPEC.md §5.3).
|
|
588
|
+
*
|
|
589
|
+
* Spelled here rather than imported from `core/values.ts`, exactly as
|
|
590
|
+
* {@link POLICY_INFO_STRING} is spelled rather than imported from
|
|
591
|
+
* `core/policy-load.ts`. `tests/values-inert.test.ts` (APRV-237) lets three CLI
|
|
592
|
+
* surfaces import the values reader and no module under `src/core/` at all,
|
|
593
|
+
* because a core module holding a reference to that reader is something review
|
|
594
|
+
* has to re-argue on every change. A label is not a reader, and this renderer
|
|
595
|
+
* needs only the label. The two spellings are pinned to each other by
|
|
596
|
+
* `tests/agents-md.test.ts`, so the copy cannot drift.
|
|
597
|
+
*/
|
|
598
|
+
const VALUES_INFO_STRING = "yaml approval-values";
|
|
599
|
+
function draftHeader(source) {
|
|
600
|
+
return [
|
|
601
|
+
`# DRAFT policy, generated from ${source} by \`approval import agents-md\`.`,
|
|
602
|
+
"#",
|
|
603
|
+
"# NOTHING HAS BEEN APPLIED. This block was printed, not written: APPROVAL.md",
|
|
604
|
+
"# is untouched, no event was appended, and no attestation was made. A human",
|
|
605
|
+
"# confirms a draft by pasting it into APPROVAL.md and running",
|
|
606
|
+
"# `approval policy amend`, which diffs it, attests it, and commits it.",
|
|
607
|
+
"#",
|
|
608
|
+
"# The v0.1 vocabulary has three levels (manual > supervised > autonomous) and",
|
|
609
|
+
"# NO forbid level, so bullets from a \"Never\" section are rendered `manual`",
|
|
610
|
+
"# and carry a `# never:` comment. Manual is not never — a human can still say",
|
|
611
|
+
"# yes. Read every `# never:` line before confirming this draft.",
|
|
612
|
+
"#",
|
|
613
|
+
"# Class names are PROPOSALS. The importer places bullets with a fixed keyword",
|
|
614
|
+
"# table into the SPEC.md §7 developer-workstation namespaces (vcs.*, deps.*,",
|
|
615
|
+
"# release.*, exec.*, network.*, policy.*). Rename any that do not match the",
|
|
616
|
+
"# classes your adapters actually declare.",
|
|
617
|
+
"#",
|
|
618
|
+
"# No `approvers:` and no `channels:` are invented here: a generated file must",
|
|
619
|
+
"# not name who may approve, or where. Add them by hand (SPEC.md §5.1).",
|
|
620
|
+
];
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* True when a values draft should be rendered at all: the source declared at
|
|
624
|
+
* least one of the four headings. One predicate, so "when is there a values
|
|
625
|
+
* draft" is answered in one place rather than at each surface.
|
|
626
|
+
*/
|
|
627
|
+
function hasValuesDraft(values) {
|
|
628
|
+
return values !== null && values !== undefined && values.headings.length > 0;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Render the values draft, fenced (APRV-240).
|
|
632
|
+
*
|
|
633
|
+
* The argument is the whole {@link ValuesDraft} rather than its bullets alone,
|
|
634
|
+
* because the entries past the cap have to appear in the output as comments:
|
|
635
|
+
* the renderer needs to see what was left out in order to say so.
|
|
636
|
+
*
|
|
637
|
+
* Deterministic, like everything else here. Entries are emitted as
|
|
638
|
+
* double-quoted scalars via `JSON.stringify`, whose escapes are all valid YAML
|
|
639
|
+
* double-quoted escapes, so a bullet full of backticks, colons and `#` survives
|
|
640
|
+
* the round trip without the renderer having to reason about YAML quoting.
|
|
641
|
+
*/
|
|
642
|
+
export function renderFencedValuesDraft(draft, source) {
|
|
643
|
+
const lines = [
|
|
644
|
+
`# DRAFT values block, imported from ${source} by \`approval import agents-md\`.`,
|
|
645
|
+
"#",
|
|
646
|
+
"# NOTHING HAS BEEN APPLIED, exactly as for the policy draft: this block was",
|
|
647
|
+
"# printed, not written. APPROVAL.md is untouched and nothing was attested.",
|
|
648
|
+
"# The values block lives INSIDE APPROVAL.md, so pasting it changes the file's",
|
|
649
|
+
"# bytes and invalidates the standing attestation; renew it immediately after.",
|
|
650
|
+
"#",
|
|
651
|
+
"# EVERY bullet is in `wants:`, and nothing is graded. `love:`, `like:` and",
|
|
652
|
+
"# `dislike:` are yours to fill in. A grade is a statement of taste and it is",
|
|
653
|
+
"# yours to make: this importer can see that you wrote a line down, and cannot",
|
|
654
|
+
"# see how much you meant it. Guessing would put words in your mouth.",
|
|
655
|
+
"#",
|
|
656
|
+
"# This block is guidance and never policy. Nothing here is enforced, counted",
|
|
657
|
+
"# or checked, and no routing, class match, sampling draw, budget or token",
|
|
658
|
+
"# reads it (SPEC.md §11.1 invariant 10).",
|
|
659
|
+
"",
|
|
660
|
+
"version: 1",
|
|
661
|
+
];
|
|
662
|
+
if (draft.wants.length === 0) {
|
|
663
|
+
lines.push("# The headings were there and carried no bullets. An empty list is a real", "# answer: it says the question was considered and left blank.", "wants: []");
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
lines.push("wants:");
|
|
667
|
+
for (const want of draft.wants)
|
|
668
|
+
lines.push(` - ${JSON.stringify(want)}`);
|
|
669
|
+
}
|
|
670
|
+
if (draft.overflow.length > 0) {
|
|
671
|
+
lines.push("", `# OVER THE CAP: values.schema.json admits ${String(VALUES_MAX_ITEMS)} entries and the source`, "# offered more. These are preserved verbatim and are NOT in `wants:`. Promote", "# the ones you want by hand, in place of ones above:");
|
|
672
|
+
for (const want of draft.overflow)
|
|
673
|
+
lines.push(`# ${want}`);
|
|
674
|
+
}
|
|
675
|
+
return `\`\`\`${VALUES_INFO_STRING}\n${lines.join("\n")}\n\`\`\`\n`;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* The fenced values draft for an import, or `null` when the source declared no
|
|
679
|
+
* values headings. The `--json` surface's `values_draft` field, verbatim.
|
|
680
|
+
*/
|
|
681
|
+
export function valuesDraftOf(result, source) {
|
|
682
|
+
return hasValuesDraft(result.values) ? renderFencedValuesDraft(result.values, source) : null;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Render the draft policy YAML. Deterministic: no clock, no cwd, no
|
|
686
|
+
* randomness — the only inputs are the import result and the source label, so
|
|
687
|
+
* the same file always produces the same bytes.
|
|
688
|
+
*
|
|
689
|
+
* With `values` omitted (or from a source that declared no values headings) the
|
|
690
|
+
* output is bare YAML with no fence, a valid policy under
|
|
691
|
+
* `schema/policy.schema.json` that loads through `loadPolicy` once wrapped in a
|
|
692
|
+
* ` ```yaml approval-policy ` fence.
|
|
693
|
+
*
|
|
694
|
+
* With a values draft the shape changes, and it has to. A values fence appended
|
|
695
|
+
* to bare YAML could not be pasted into a policy fence, because the values
|
|
696
|
+
* block's own closing fence would close the policy block and leave a file that
|
|
697
|
+
* loads as neither. So a two-block draft is emitted already fenced: the policy
|
|
698
|
+
* inside its ` ```yaml approval-policy ` fence, then the values fence after it,
|
|
699
|
+
* which is the shape `APPROVAL.md` itself has and which the policy loader and
|
|
700
|
+
* the values reader each read straight off disk.
|
|
701
|
+
*/
|
|
702
|
+
export function renderDraftPolicy(result, source, values) {
|
|
703
|
+
const lines = [...draftHeader(source), ""];
|
|
704
|
+
lines.push('version: "0.1"', "");
|
|
705
|
+
lines.push("defaults:", " autonomy: manual # anything not named below needs sign-off", ' approval_ttl: "24h"', " on_expiry: reject", "");
|
|
706
|
+
if (result.classes.length === 0) {
|
|
707
|
+
lines.push("# No classes: the source declared no permissions bullets this importer could", "# use. Every class therefore resolves to defaults.autonomy (manual).");
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
lines.push("classes:");
|
|
711
|
+
for (const entry of result.classes) {
|
|
712
|
+
for (const bullet of entry.bullets) {
|
|
713
|
+
// The section is named only when more than one bullet mapped here: with
|
|
714
|
+
// one bullet the heading it came from is not in question, and with two
|
|
715
|
+
// the reader needs to see which section the surviving autonomy came from.
|
|
716
|
+
const label = bullet.section === "never"
|
|
717
|
+
? "never"
|
|
718
|
+
: entry.bullets.length > 1
|
|
719
|
+
? `from (${bullet.section})`
|
|
720
|
+
: "from";
|
|
721
|
+
lines.push(` # ${label}: ${bullet.text}`);
|
|
722
|
+
}
|
|
723
|
+
lines.push(` ${entry.cls}: { autonomy: ${entry.autonomy} }`);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (result.unmapped.length > 0) {
|
|
727
|
+
lines.push("", "# UNMAPPED — the importer could not place these bullets, and refuses to", "# guess. They are covered by defaults.autonomy (manual) until a human names", "# their class:");
|
|
728
|
+
for (const bullet of result.unmapped) {
|
|
729
|
+
lines.push(`# (${bullet.section}) ${bullet.text}`);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
const yaml = `${lines.join("\n")}\n`;
|
|
733
|
+
if (!hasValuesDraft(values))
|
|
734
|
+
return yaml;
|
|
735
|
+
return `\`\`\`${POLICY_INFO_STRING}\n${yaml}\`\`\`\n\n${renderFencedValuesDraft(values, source)}`;
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* The draft wrapped in its ` ```yaml approval-policy ` fence, for stdout, with
|
|
739
|
+
* the values fence printed after it when the source declared values headings.
|
|
740
|
+
*/
|
|
741
|
+
export function renderFencedDraft(result, source, values) {
|
|
742
|
+
const policy = `\`\`\`${POLICY_INFO_STRING}\n${renderDraftPolicy(result, source)}\`\`\`\n`;
|
|
743
|
+
if (!hasValuesDraft(values))
|
|
744
|
+
return policy;
|
|
745
|
+
return `${policy}\n${renderFencedValuesDraft(values, source)}`;
|
|
746
|
+
}
|
|
747
|
+
//# sourceMappingURL=agents-md.js.map
|