peaks-loop 4.1.2 → 4.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +136 -47
- package/CHANGELOG.md +56 -0
- package/README-en.md +1 -1
- package/README.md +1 -1
- package/contracts/readonly-argv-whitelist.json +211 -0
- package/dist/cli/commands/audit-artifact-runners.d.ts +16 -0
- package/dist/cli/commands/audit-artifact-runners.js +170 -0
- package/dist/cli/commands/audit-command-shared.d.ts +97 -0
- package/dist/cli/commands/audit-command-shared.js +60 -0
- package/dist/cli/commands/audit-commands.d.ts +7 -31
- package/dist/cli/commands/audit-commands.js +64 -473
- package/dist/cli/commands/audit-goal-runners.d.ts +17 -0
- package/dist/cli/commands/audit-goal-runners.js +114 -0
- package/dist/cli/commands/audit-red-lines-runners.d.ts +11 -0
- package/dist/cli/commands/audit-red-lines-runners.js +43 -0
- package/dist/cli/commands/audit-refusal-data.d.ts +23 -0
- package/dist/cli/commands/audit-refusal-data.js +69 -0
- package/dist/cli/commands/audit-static-runners.d.ts +13 -0
- package/dist/cli/commands/audit-static-runners.js +139 -0
- package/dist/cli/commands/await-runners.d.ts +11 -0
- package/dist/cli/commands/await-runners.js +148 -0
- package/dist/cli/commands/code-auto-compact-command.d.ts +3 -0
- package/dist/cli/commands/code-auto-compact-command.js +124 -0
- package/dist/cli/commands/code-auto-compact-envelope.d.ts +22 -0
- package/dist/cli/commands/code-auto-compact-envelope.js +39 -0
- package/dist/cli/commands/code-context-audit-command.d.ts +3 -0
- package/dist/cli/commands/code-context-audit-command.js +68 -0
- package/dist/cli/commands/code-context-now-command.d.ts +3 -0
- package/dist/cli/commands/code-context-now-command.js +124 -0
- package/dist/cli/commands/code-context-now-envelope.d.ts +66 -0
- package/dist/cli/commands/code-context-now-envelope.js +136 -0
- package/dist/cli/commands/code-context-now-mapping.d.ts +27 -0
- package/dist/cli/commands/code-context-now-mapping.js +43 -0
- package/dist/cli/commands/code-emit-handoff-command.d.ts +3 -0
- package/dist/cli/commands/code-emit-handoff-command.js +99 -0
- package/dist/cli/commands/code-gate-step-08-command.d.ts +3 -0
- package/dist/cli/commands/code-gate-step-08-command.js +139 -0
- package/dist/cli/commands/code-post-compact-detect-command.d.ts +3 -0
- package/dist/cli/commands/code-post-compact-detect-command.js +50 -0
- package/dist/cli/commands/code-runtime-commands.d.ts +9 -43
- package/dist/cli/commands/code-runtime-commands.js +20 -672
- package/dist/cli/commands/code-runtime-session.d.ts +1 -0
- package/dist/cli/commands/code-runtime-session.js +15 -0
- package/dist/cli/commands/compact-command.d.ts +6 -2
- package/dist/cli/commands/compact-command.js +12 -559
- package/dist/cli/commands/compact-dry-run-command.d.ts +3 -0
- package/dist/cli/commands/compact-dry-run-command.js +87 -0
- package/dist/cli/commands/compact-force-command.d.ts +3 -0
- package/dist/cli/commands/compact-force-command.js +98 -0
- package/dist/cli/commands/compact-harness-window-command.d.ts +3 -0
- package/dist/cli/commands/compact-harness-window-command.js +174 -0
- package/dist/cli/commands/compact-history-command.d.ts +3 -0
- package/dist/cli/commands/compact-history-command.js +89 -0
- package/dist/cli/commands/compact-read-commands.d.ts +3 -0
- package/dist/cli/commands/compact-read-commands.js +123 -0
- package/dist/cli/commands/compact-settle-command.d.ts +3 -0
- package/dist/cli/commands/compact-settle-command.js +130 -0
- package/dist/cli/commands/compact-shared.d.ts +9 -0
- package/dist/cli/commands/compact-shared.js +26 -0
- package/dist/cli/commands/core/skill-command.d.ts +1 -44
- package/dist/cli/commands/core/skill-command.js +13 -541
- package/dist/cli/commands/core/skill-context-verdict.d.ts +38 -0
- package/dist/cli/commands/core/skill-context-verdict.js +63 -0
- package/dist/cli/commands/core/skill-generated-config-notice.d.ts +41 -0
- package/dist/cli/commands/core/skill-generated-config-notice.js +75 -0
- package/dist/cli/commands/core/skill-heartbeat-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-heartbeat-commands.js +50 -0
- package/dist/cli/commands/core/skill-presence-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-presence-commands.js +123 -0
- package/dist/cli/commands/core/skill-presence-housekeeping-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-presence-housekeeping-commands.js +165 -0
- package/dist/cli/commands/core/skill-registry-commands.d.ts +3 -0
- package/dist/cli/commands/core/skill-registry-commands.js +117 -0
- package/dist/cli/commands/core/skill-runbook-command.d.ts +3 -0
- package/dist/cli/commands/core/skill-runbook-command.js +29 -0
- package/dist/cli/commands/dispatch-command-spec.d.ts +2 -0
- package/dist/cli/commands/dispatch-command-spec.js +62 -0
- package/dist/cli/commands/dispatch-commands.js +159 -775
- package/dist/cli/commands/dispatch-detached-branch.d.ts +3 -0
- package/dist/cli/commands/dispatch-detached-branch.js +58 -0
- package/dist/cli/commands/dispatch-envelope.d.ts +36 -0
- package/dist/cli/commands/dispatch-envelope.js +104 -0
- package/dist/cli/commands/dispatch-isolation-lease.d.ts +17 -0
- package/dist/cli/commands/dispatch-isolation-lease.js +149 -0
- package/dist/cli/commands/dispatch-preflight.d.ts +7 -0
- package/dist/cli/commands/dispatch-preflight.js +105 -0
- package/dist/cli/commands/dispatch-prompt-blocks.d.ts +10 -0
- package/dist/cli/commands/dispatch-prompt-blocks.js +56 -0
- package/dist/cli/commands/dispatch-prompt-composition.d.ts +30 -0
- package/dist/cli/commands/dispatch-prompt-composition.js +171 -0
- package/dist/cli/commands/dispatch-record-write.d.ts +24 -0
- package/dist/cli/commands/dispatch-record-write.js +96 -0
- package/dist/cli/commands/dispatch-tool-call.d.ts +15 -0
- package/dist/cli/commands/dispatch-tool-call.js +128 -0
- package/dist/cli/commands/evolution-command-shared.d.ts +78 -0
- package/dist/cli/commands/evolution-command-shared.js +107 -0
- package/dist/cli/commands/evolution-commands.d.ts +11 -1
- package/dist/cli/commands/evolution-commands.js +19 -350
- package/dist/cli/commands/evolution-evaluate-command.d.ts +24 -0
- package/dist/cli/commands/evolution-evaluate-command.js +138 -0
- package/dist/cli/commands/evolution-propose-command.d.ts +23 -0
- package/dist/cli/commands/evolution-propose-command.js +145 -0
- package/dist/cli/commands/evolution-status-command.d.ts +17 -0
- package/dist/cli/commands/evolution-status-command.js +41 -0
- package/dist/cli/commands/evolution-verdict-commands.d.ts +30 -0
- package/dist/cli/commands/evolution-verdict-commands.js +100 -0
- package/dist/cli/commands/finalize-accumulator.d.ts +44 -0
- package/dist/cli/commands/finalize-accumulator.js +55 -0
- package/dist/cli/commands/finalize-branches.d.ts +34 -0
- package/dist/cli/commands/finalize-branches.js +119 -0
- package/dist/cli/commands/finalize-runners.d.ts +3 -0
- package/dist/cli/commands/finalize-runners.js +92 -0
- package/dist/cli/commands/finalize-selection.d.ts +65 -0
- package/dist/cli/commands/finalize-selection.js +35 -0
- package/dist/cli/commands/gate-commands.js +26 -8
- package/dist/cli/commands/job-checkpoint-commands.d.ts +3 -0
- package/dist/cli/commands/job-checkpoint-commands.js +157 -0
- package/dist/cli/commands/job-command-shared.d.ts +109 -0
- package/dist/cli/commands/job-command-shared.js +72 -0
- package/dist/cli/commands/job-commands.d.ts +4 -64
- package/dist/cli/commands/job-commands.js +42 -552
- package/dist/cli/commands/job-cost-check-command.d.ts +3 -0
- package/dist/cli/commands/job-cost-check-command.js +41 -0
- package/dist/cli/commands/job-init-status-commands.d.ts +3 -0
- package/dist/cli/commands/job-init-status-commands.js +149 -0
- package/dist/cli/commands/job-run-commands.d.ts +3 -0
- package/dist/cli/commands/job-run-commands.js +97 -0
- package/dist/cli/commands/job-state-root.d.ts +35 -0
- package/dist/cli/commands/job-state-root.js +76 -0
- package/dist/cli/commands/loop-eval-capture-index.d.ts +4 -0
- package/dist/cli/commands/loop-eval-capture-index.js +44 -0
- package/dist/cli/commands/loop-eval-commands.d.ts +8 -5
- package/dist/cli/commands/loop-eval-commands.js +12 -626
- package/dist/cli/commands/loop-eval-eval-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-eval-command.js +168 -0
- package/dist/cli/commands/loop-eval-monotonic-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-monotonic-command.js +90 -0
- package/dist/cli/commands/loop-eval-parents.d.ts +7 -0
- package/dist/cli/commands/loop-eval-parents.js +20 -0
- package/dist/cli/commands/loop-eval-run-code.d.ts +7 -0
- package/dist/cli/commands/loop-eval-run-code.js +40 -0
- package/dist/cli/commands/loop-eval-run-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-run-command.js +113 -0
- package/dist/cli/commands/loop-eval-spec-commands.d.ts +3 -0
- package/dist/cli/commands/loop-eval-spec-commands.js +165 -0
- package/dist/cli/commands/loop-eval-spec-lint-command.d.ts +3 -0
- package/dist/cli/commands/loop-eval-spec-lint-command.js +42 -0
- package/dist/cli/commands/loop-eval-workflow-commands.d.ts +3 -0
- package/dist/cli/commands/loop-eval-workflow-commands.js +141 -0
- package/dist/cli/commands/mcp-commands.d.ts +10 -0
- package/dist/cli/commands/mcp-commands.js +157 -0
- package/dist/cli/commands/request-command-options.d.ts +49 -0
- package/dist/cli/commands/request-command-options.js +1 -0
- package/dist/cli/commands/request-commands.d.ts +3 -9
- package/dist/cli/commands/request-commands.js +17 -522
- package/dist/cli/commands/request-init-command.d.ts +3 -0
- package/dist/cli/commands/request-init-command.js +100 -0
- package/dist/cli/commands/request-lint-command.d.ts +3 -0
- package/dist/cli/commands/request-lint-command.js +50 -0
- package/dist/cli/commands/request-list-command.d.ts +10 -0
- package/dist/cli/commands/request-list-command.js +53 -0
- package/dist/cli/commands/request-repair-status-command.d.ts +3 -0
- package/dist/cli/commands/request-repair-status-command.js +61 -0
- package/dist/cli/commands/request-show-command.d.ts +3 -0
- package/dist/cli/commands/request-show-command.js +56 -0
- package/dist/cli/commands/request-transition-command.d.ts +3 -0
- package/dist/cli/commands/request-transition-command.js +122 -0
- package/dist/cli/commands/request-transition-failures.d.ts +8 -0
- package/dist/cli/commands/request-transition-failures.js +90 -0
- package/dist/cli/commands/request-transition-hooks.d.ts +50 -0
- package/dist/cli/commands/request-transition-hooks.js +115 -0
- package/dist/cli/commands/request-transition-preflight.d.ts +10 -0
- package/dist/cli/commands/request-transition-preflight.js +107 -0
- package/dist/cli/commands/scan-command-shared.d.ts +96 -0
- package/dist/cli/commands/scan-command-shared.js +83 -0
- package/dist/cli/commands/scan-commands.d.ts +3 -2
- package/dist/cli/commands/scan-commands.js +23 -463
- package/dist/cli/commands/scan-inventory-commands.d.ts +3 -0
- package/dist/cli/commands/scan-inventory-commands.js +96 -0
- package/dist/cli/commands/scan-project-commands.d.ts +3 -0
- package/dist/cli/commands/scan-project-commands.js +65 -0
- package/dist/cli/commands/scan-scope-commands.d.ts +3 -0
- package/dist/cli/commands/scan-scope-commands.js +149 -0
- package/dist/cli/commands/scan-scope-helpers.d.ts +8 -0
- package/dist/cli/commands/scan-scope-helpers.js +54 -0
- package/dist/cli/commands/scan-structural-commands.d.ts +3 -0
- package/dist/cli/commands/scan-structural-commands.js +113 -0
- package/dist/cli/commands/share-commands.d.ts +12 -68
- package/dist/cli/commands/share-commands.js +47 -556
- package/dist/cli/commands/share-error-hints.d.ts +14 -0
- package/dist/cli/commands/share-error-hints.js +38 -0
- package/dist/cli/commands/share-identity.d.ts +13 -0
- package/dist/cli/commands/share-identity.js +22 -0
- package/dist/cli/commands/share-record-paths.d.ts +37 -0
- package/dist/cli/commands/share-record-paths.js +68 -0
- package/dist/cli/commands/share-runners.d.ts +3 -0
- package/dist/cli/commands/share-runners.js +158 -0
- package/dist/cli/commands/shared-read-runners.d.ts +3 -0
- package/dist/cli/commands/shared-read-runners.js +51 -0
- package/dist/cli/commands/slice-check-command.d.ts +3 -0
- package/dist/cli/commands/slice-check-command.js +54 -0
- package/dist/cli/commands/slice-commands.d.ts +2 -22
- package/dist/cli/commands/slice-commands.js +18 -517
- package/dist/cli/commands/slice-decompose-artifacts.d.ts +18 -0
- package/dist/cli/commands/slice-decompose-artifacts.js +79 -0
- package/dist/cli/commands/slice-decompose-command.d.ts +3 -0
- package/dist/cli/commands/slice-decompose-command.js +123 -0
- package/dist/cli/commands/slice-list-commands.d.ts +3 -0
- package/dist/cli/commands/slice-list-commands.js +182 -0
- package/dist/cli/commands/slice-pick-command.d.ts +3 -0
- package/dist/cli/commands/slice-pick-command.js +60 -0
- package/dist/cli/commands/slice-plan-command.d.ts +24 -0
- package/dist/cli/commands/slice-plan-command.js +111 -0
- package/dist/cli/commands/workflow-commands.d.ts +10 -1
- package/dist/cli/commands/workflow-commands.js +6 -594
- package/dist/cli/commands/workflow-gate-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-gate-commands.js +116 -0
- package/dist/cli/commands/workflow-plan-helpers.d.ts +48 -0
- package/dist/cli/commands/workflow-plan-helpers.js +103 -0
- package/dist/cli/commands/workflow-planning-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-planning-commands.js +56 -0
- package/dist/cli/commands/workflow-swarm-actions.d.ts +7 -0
- package/dist/cli/commands/workflow-swarm-actions.js +109 -0
- package/dist/cli/commands/workflow-swarm-commands.d.ts +3 -0
- package/dist/cli/commands/workflow-swarm-commands.js +138 -0
- package/dist/cli/commands/workflow-tech-actions.d.ts +10 -0
- package/dist/cli/commands/workflow-tech-actions.js +150 -0
- package/dist/cli/commands/workspace/init-actions.d.ts +10 -0
- package/dist/cli/commands/workspace/init-actions.js +199 -0
- package/dist/cli/commands/workspace/init-codegraph-stake.d.ts +10 -0
- package/dist/cli/commands/workspace/init-codegraph-stake.js +54 -0
- package/dist/cli/commands/workspace/init-command.d.ts +8 -124
- package/dist/cli/commands/workspace/init-command.js +59 -623
- package/dist/cli/commands/workspace/init-context.d.ts +58 -0
- package/dist/cli/commands/workspace/init-context.js +121 -0
- package/dist/cli/commands/workspace/init-envelope.d.ts +3 -0
- package/dist/cli/commands/workspace/init-envelope.js +34 -0
- package/dist/cli/commands/workspace/init-failures.d.ts +3 -0
- package/dist/cli/commands/workspace/init-failures.js +84 -0
- package/dist/cli/commands/workspace/init-hooks-decision.d.ts +24 -0
- package/dist/cli/commands/workspace/init-hooks-decision.js +189 -0
- package/dist/cli/commands/workspace/init-options.d.ts +102 -0
- package/dist/cli/commands/workspace/init-options.js +1 -0
- package/dist/cli/commands/worktree-lease-commands.d.ts +10 -6
- package/dist/cli/commands/worktree-lease-commands.js +42 -512
- package/dist/cli/commands/worktree-lease-gc-command.d.ts +12 -0
- package/dist/cli/commands/worktree-lease-gc-command.js +117 -0
- package/dist/cli/commands/worktree-lease-git.d.ts +22 -0
- package/dist/cli/commands/worktree-lease-git.js +48 -0
- package/dist/cli/commands/worktree-lease-list-command.d.ts +12 -0
- package/dist/cli/commands/worktree-lease-list-command.js +100 -0
- package/dist/cli/commands/worktree-lease-load.d.ts +37 -0
- package/dist/cli/commands/worktree-lease-load.js +28 -0
- package/dist/cli/commands/worktree-lease-release-command.d.ts +13 -0
- package/dist/cli/commands/worktree-lease-release-command.js +105 -0
- package/dist/cli/commands/worktree-lease-renew-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-renew-command.js +99 -0
- package/dist/cli/commands/worktree-lease-session.d.ts +22 -0
- package/dist/cli/commands/worktree-lease-session.js +29 -0
- package/dist/cli/commands/worktree-lease-spawn-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-spawn-command.js +119 -0
- package/dist/cli/commands/worktree-lease-status-command.d.ts +11 -0
- package/dist/cli/commands/worktree-lease-status-command.js +86 -0
- package/dist/cli/commands/worktree-lease-store.d.ts +19 -0
- package/dist/cli/commands/worktree-lease-store.js +24 -0
- package/dist/cli/program.js +5 -0
- package/dist/services/distribution/mcp-install-runner.d.ts +21 -0
- package/dist/services/distribution/mcp-install-runner.js +59 -0
- package/dist/services/distribution/mcp-install.d.ts +95 -0
- package/dist/services/distribution/mcp-install.js +179 -0
- package/dist/services/distribution/plugin-manifest.d.ts +97 -0
- package/dist/services/distribution/plugin-manifest.js +126 -0
- package/dist/services/hooks/mcp-surface-gate.d.ts +19 -0
- package/dist/services/hooks/mcp-surface-gate.js +87 -0
- package/dist/services/ide/adapters/claude-code-adapter.d.ts +4 -35
- package/dist/services/ide/adapters/claude-code-adapter.js +48 -171
- package/dist/services/ide/adapters/claude-code-local-state.d.ts +28 -0
- package/dist/services/ide/adapters/claude-code-local-state.js +112 -0
- package/dist/services/ide/adapters/claude-code-model-window.d.ts +37 -0
- package/dist/services/ide/adapters/claude-code-model-window.js +113 -0
- package/dist/services/ide/ide-mcp-install-types.d.ts +78 -0
- package/dist/services/ide/ide-mcp-install-types.js +104 -0
- package/dist/services/ide/ide-types.d.ts +45 -1
- package/dist/services/ide/mcp-tool-matcher.d.ts +34 -0
- package/dist/services/ide/mcp-tool-matcher.js +84 -0
- package/dist/services/lint/npx-resolver.js +7 -0
- package/dist/services/mcp/cli-executor.d.ts +36 -0
- package/dist/services/mcp/cli-executor.js +97 -0
- package/dist/services/mcp/json-rpc.d.ts +81 -0
- package/dist/services/mcp/json-rpc.js +116 -0
- package/dist/services/mcp/memory-tool.d.ts +3 -0
- package/dist/services/mcp/memory-tool.js +62 -0
- package/dist/services/mcp/server-main.d.ts +1 -0
- package/dist/services/mcp/server-main.js +66 -0
- package/dist/services/mcp/server.d.ts +22 -0
- package/dist/services/mcp/server.js +152 -0
- package/dist/services/mcp/surface.d.ts +62 -0
- package/dist/services/mcp/surface.js +198 -0
- package/dist/services/mcp/tool-core.d.ts +42 -0
- package/dist/services/mcp/tool-core.js +137 -0
- package/dist/services/mcp/tools.d.ts +13 -0
- package/dist/services/mcp/tools.js +58 -0
- package/dist/services/readonly-surface/argv-guard.d.ts +32 -0
- package/dist/services/readonly-surface/argv-guard.js +164 -0
- package/dist/services/readonly-surface/readonly-whitelist.d.ts +147 -0
- package/dist/services/readonly-surface/readonly-whitelist.js +107 -0
- package/dist/services/readonly-surface/whitelist-generator.d.ts +64 -0
- package/dist/services/readonly-surface/whitelist-generator.js +212 -0
- package/dist/services/skills/hooks-codegate-superpowers.d.ts +1 -0
- package/dist/services/skills/hooks-codegate-superpowers.js +26 -0
- package/dist/services/skills/hooks-settings-service.js +10 -2
- package/package.json +17 -6
- package/scripts/install-skills-bundles.mjs +233 -0
- package/scripts/install-skills-fs.mjs +148 -0
- package/scripts/install-skills-ide.mjs +279 -0
- package/scripts/install-skills-output-style-default.mjs +196 -0
- package/scripts/install-skills-output-styles.mjs +121 -0
- package/scripts/install-skills-report.mjs +42 -0
- package/scripts/install-skills-user-config.mjs +198 -0
- package/scripts/install-skills.mjs +36 -1066
- package/scripts/watch-tree.mjs +140 -0
- package/scripts/watch.mjs +4 -126
- package/skills/peaks-status/SKILL.md +31 -13
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parameter-injection guard for the read-only surface.
|
|
3
|
+
*
|
|
4
|
+
* THE ATTACK. An argv template has placeholder slots (`request show <rid>`). If a
|
|
5
|
+
* placeholder value is pasted into a command LINE, the value `--apply` stops being
|
|
6
|
+
* a request id and becomes a flag - the semantics of the call are inverted by its
|
|
7
|
+
* own data. Two independent defences, both required (spec §8.1):
|
|
8
|
+
*
|
|
9
|
+
* 1. TYPE WHITELIST - every placeholder declares a type, and the value must
|
|
10
|
+
* satisfy it. No type admits a leading `-`, so a flag-shaped value is never a
|
|
11
|
+
* legal value of any placeholder.
|
|
12
|
+
* 2. ARRAY PASSING - `buildArgv` returns `string[]`. The caller passes the array
|
|
13
|
+
* to the process API with shell parsing disabled (`readonlySpawnOptions`), so
|
|
14
|
+
* no value is ever re-tokenized by a shell.
|
|
15
|
+
*
|
|
16
|
+
* Defence 2 alone is not enough: `spawn(..., {shell:false})` still hands `--apply`
|
|
17
|
+
* to the CLI as a real flag. Defence 1 alone is not enough: a caller that joins
|
|
18
|
+
* the array into a string reintroduces the shell. Hence both.
|
|
19
|
+
*/
|
|
20
|
+
import { isAbsolute } from 'node:path';
|
|
21
|
+
/** Fallback pattern for a `slug` placeholder that declares none. */
|
|
22
|
+
const DEFAULT_SLUG_PATTERN = '^[a-z0-9][a-z0-9-]*$';
|
|
23
|
+
/** Upper bound on any single placeholder value, whatever its type. */
|
|
24
|
+
export const READONLY_VALUE_MAX_LENGTH = 200;
|
|
25
|
+
/** The process options that keep the array from being re-parsed by a shell. */
|
|
26
|
+
export function readonlySpawnOptions() {
|
|
27
|
+
return { shell: false };
|
|
28
|
+
}
|
|
29
|
+
function reject(param, code, message) {
|
|
30
|
+
return { ok: false, param, code, message };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Control characters, matched by Unicode category rather than by a literal range:
|
|
34
|
+
* a hand-written `\x00-\x1f` class is a lint error (`no-control-regex`) precisely
|
|
35
|
+
* because such a range in a pattern is usually a bug, and `\p{Cc}` says what is
|
|
36
|
+
* meant without spelling out code points.
|
|
37
|
+
*/
|
|
38
|
+
function hasControlCharacter(value) {
|
|
39
|
+
return /\p{Cc}/u.test(value);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The rules that hold for EVERY type, before any type-specific rule runs. A
|
|
43
|
+
* leading `-` is refused here, so no type can carry a flag into the argv.
|
|
44
|
+
*/
|
|
45
|
+
function precheckCommon(param, raw) {
|
|
46
|
+
if (typeof raw !== 'string') {
|
|
47
|
+
return reject(param, 'NOT_A_STRING', `Parameter ${param} must be a string.`);
|
|
48
|
+
}
|
|
49
|
+
if (raw.length === 0)
|
|
50
|
+
return reject(param, 'EMPTY', `Parameter ${param} must not be empty.`);
|
|
51
|
+
if (raw.length > READONLY_VALUE_MAX_LENGTH) {
|
|
52
|
+
return reject(param, 'TOO_LONG', `Parameter ${param} exceeds ${READONLY_VALUE_MAX_LENGTH} characters.`);
|
|
53
|
+
}
|
|
54
|
+
if (raw.startsWith('-')) {
|
|
55
|
+
return reject(param, 'FLAG_SHAPED', `Parameter ${param} must not look like a flag: ${raw}`);
|
|
56
|
+
}
|
|
57
|
+
if (hasControlCharacter(raw)) {
|
|
58
|
+
return reject(param, 'CONTROL_CHARACTER', `Parameter ${param} must not contain control characters.`);
|
|
59
|
+
}
|
|
60
|
+
return { ok: true, value: raw };
|
|
61
|
+
}
|
|
62
|
+
function checkToken(param, value) {
|
|
63
|
+
if (/\s/.test(value)) {
|
|
64
|
+
return reject(param, 'WHITESPACE', `Parameter ${param} must be a single token.`);
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, value };
|
|
67
|
+
}
|
|
68
|
+
function checkSlug(param, value, spec) {
|
|
69
|
+
const asToken = checkToken(param, value);
|
|
70
|
+
if (!asToken.ok)
|
|
71
|
+
return asToken;
|
|
72
|
+
const pattern = new RegExp(spec.pattern ?? DEFAULT_SLUG_PATTERN);
|
|
73
|
+
if (!pattern.test(value)) {
|
|
74
|
+
return reject(param, 'PATTERN_MISMATCH', `Parameter ${param} must match ${pattern.source}: ${value}`);
|
|
75
|
+
}
|
|
76
|
+
return { ok: true, value };
|
|
77
|
+
}
|
|
78
|
+
function checkEnum(param, value, spec) {
|
|
79
|
+
if (spec.values === undefined || !spec.values.includes(value)) {
|
|
80
|
+
return reject(param, 'NOT_IN_ENUM', `Parameter ${param} must be one of: ${(spec.values ?? []).join(', ')}`);
|
|
81
|
+
}
|
|
82
|
+
return { ok: true, value };
|
|
83
|
+
}
|
|
84
|
+
function checkInteger(param, value, spec) {
|
|
85
|
+
if (!/^[0-9]+$/.test(value)) {
|
|
86
|
+
return reject(param, 'NOT_AN_INTEGER', `Parameter ${param} must be an integer: ${value}`);
|
|
87
|
+
}
|
|
88
|
+
const parsed = Number.parseInt(value, 10);
|
|
89
|
+
const min = spec.min ?? 0;
|
|
90
|
+
const max = spec.max ?? Number.MAX_SAFE_INTEGER;
|
|
91
|
+
if (parsed < min || parsed > max) {
|
|
92
|
+
return reject(param, 'OUT_OF_RANGE', `Parameter ${param} must be between ${min} and ${max}.`);
|
|
93
|
+
}
|
|
94
|
+
return { ok: true, value };
|
|
95
|
+
}
|
|
96
|
+
function checkPath(param, value) {
|
|
97
|
+
// Spaces are legal in a path and irrelevant under array passing; the absolute
|
|
98
|
+
// check is what keeps `--apply` and a bare word out.
|
|
99
|
+
if (!isAbsolute(value)) {
|
|
100
|
+
return reject(param, 'NOT_ABSOLUTE', `Parameter ${param} must be an absolute path.`);
|
|
101
|
+
}
|
|
102
|
+
return { ok: true, value };
|
|
103
|
+
}
|
|
104
|
+
const TYPE_CHECKS = {
|
|
105
|
+
token: (param, value) => checkToken(param, value),
|
|
106
|
+
slug: (param, value, spec) => checkSlug(param, value, spec),
|
|
107
|
+
enum: (param, value, spec) => checkEnum(param, value, spec),
|
|
108
|
+
integer: (param, value, spec) => checkInteger(param, value, spec),
|
|
109
|
+
path: (param, value) => checkPath(param, value)
|
|
110
|
+
};
|
|
111
|
+
/** Validate one placeholder value against its spec. */
|
|
112
|
+
export function validatePlaceholderValue(param, spec, raw) {
|
|
113
|
+
const prechecked = precheckCommon(param, raw);
|
|
114
|
+
if (!prechecked.ok)
|
|
115
|
+
return prechecked;
|
|
116
|
+
return TYPE_CHECKS[spec.type](param, prechecked.value, spec);
|
|
117
|
+
}
|
|
118
|
+
function missingParam(param) {
|
|
119
|
+
return reject(param, 'EMPTY', `Parameter ${param} was not supplied.`);
|
|
120
|
+
}
|
|
121
|
+
/** A value is required for every placeholder present in the template. */
|
|
122
|
+
function resolveParamValue(param, declared, values) {
|
|
123
|
+
if (declared === undefined)
|
|
124
|
+
return missingParam(param);
|
|
125
|
+
const supplied = values[param];
|
|
126
|
+
// Every placeholder in this surface is required (introspected), and a missing
|
|
127
|
+
// OPTIONAL value could only be honoured by also dropping the flag literal the
|
|
128
|
+
// loop has already pushed. Refusing is the honest answer.
|
|
129
|
+
if (supplied === undefined)
|
|
130
|
+
return missingParam(param);
|
|
131
|
+
return validatePlaceholderValue(param, declared, supplied);
|
|
132
|
+
}
|
|
133
|
+
function unknownParams(entry, values) {
|
|
134
|
+
for (const name of Object.keys(values)) {
|
|
135
|
+
if (!(name in entry.params)) {
|
|
136
|
+
return reject(name, 'NOT_A_STRING', `Entry ${entry.id} declares no parameter ${name}.`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Render a whitelist entry into a concrete argv ARRAY.
|
|
143
|
+
*
|
|
144
|
+
* The output is never a string: literals and validated values are pushed as
|
|
145
|
+
* separate elements, so no value can contribute token boundaries. A parameter the
|
|
146
|
+
* entry does not declare is refused rather than appended.
|
|
147
|
+
*/
|
|
148
|
+
export function buildArgv(entry, values) {
|
|
149
|
+
const unexpected = unknownParams(entry, values);
|
|
150
|
+
if (unexpected !== undefined)
|
|
151
|
+
return unexpected;
|
|
152
|
+
const argv = [];
|
|
153
|
+
for (const segment of entry.argv) {
|
|
154
|
+
if (segment.kind === 'literal') {
|
|
155
|
+
argv.push(segment.value);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const resolved = resolveParamValue(segment.name, entry.params[segment.name], values);
|
|
159
|
+
if (!resolved.ok)
|
|
160
|
+
return resolved;
|
|
161
|
+
argv.push(resolved.value);
|
|
162
|
+
}
|
|
163
|
+
return { ok: true, argv };
|
|
164
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Where the generator writes the artifact, relative to the package root. */
|
|
3
|
+
export declare const READONLY_WHITELIST_RELATIVE_PATH = "contracts/readonly-argv-whitelist.json";
|
|
4
|
+
declare const PlaceholderSpecSchema: z.ZodObject<{
|
|
5
|
+
type: z.ZodEnum<{
|
|
6
|
+
enum: "enum";
|
|
7
|
+
path: "path";
|
|
8
|
+
token: "token";
|
|
9
|
+
slug: "slug";
|
|
10
|
+
integer: "integer";
|
|
11
|
+
}>;
|
|
12
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
13
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
14
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
binding: z.ZodObject<{
|
|
18
|
+
kind: z.ZodEnum<{
|
|
19
|
+
option: "option";
|
|
20
|
+
positional: "positional";
|
|
21
|
+
}>;
|
|
22
|
+
token: z.ZodString;
|
|
23
|
+
required: z.ZodBoolean;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
constraintSource: z.ZodEnum<{
|
|
26
|
+
introspected: "introspected";
|
|
27
|
+
handwritten: "handwritten";
|
|
28
|
+
}>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
declare const EntrySchema: z.ZodObject<{
|
|
31
|
+
id: z.ZodString;
|
|
32
|
+
tool: z.ZodString;
|
|
33
|
+
commandPath: z.ZodArray<z.ZodString>;
|
|
34
|
+
argv: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
35
|
+
kind: z.ZodLiteral<"literal">;
|
|
36
|
+
value: z.ZodString;
|
|
37
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
38
|
+
kind: z.ZodLiteral<"param">;
|
|
39
|
+
name: z.ZodString;
|
|
40
|
+
}, z.core.$strip>]>>;
|
|
41
|
+
params: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
42
|
+
type: z.ZodEnum<{
|
|
43
|
+
enum: "enum";
|
|
44
|
+
path: "path";
|
|
45
|
+
token: "token";
|
|
46
|
+
slug: "slug";
|
|
47
|
+
integer: "integer";
|
|
48
|
+
}>;
|
|
49
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
50
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
51
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
52
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
53
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
54
|
+
binding: z.ZodObject<{
|
|
55
|
+
kind: z.ZodEnum<{
|
|
56
|
+
option: "option";
|
|
57
|
+
positional: "positional";
|
|
58
|
+
}>;
|
|
59
|
+
token: z.ZodString;
|
|
60
|
+
required: z.ZodBoolean;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
constraintSource: z.ZodEnum<{
|
|
63
|
+
introspected: "introspected";
|
|
64
|
+
handwritten: "handwritten";
|
|
65
|
+
}>;
|
|
66
|
+
}, z.core.$strip>>;
|
|
67
|
+
introspection: z.ZodObject<{
|
|
68
|
+
optionTokens: z.ZodArray<z.ZodString>;
|
|
69
|
+
positionalCount: z.ZodNumber;
|
|
70
|
+
}, z.core.$strip>;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
declare const WhitelistSchema: z.ZodObject<{
|
|
73
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
74
|
+
source: z.ZodString;
|
|
75
|
+
readOnlyDefinition: z.ZodString;
|
|
76
|
+
entries: z.ZodArray<z.ZodObject<{
|
|
77
|
+
id: z.ZodString;
|
|
78
|
+
tool: z.ZodString;
|
|
79
|
+
commandPath: z.ZodArray<z.ZodString>;
|
|
80
|
+
argv: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
81
|
+
kind: z.ZodLiteral<"literal">;
|
|
82
|
+
value: z.ZodString;
|
|
83
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
84
|
+
kind: z.ZodLiteral<"param">;
|
|
85
|
+
name: z.ZodString;
|
|
86
|
+
}, z.core.$strip>]>>;
|
|
87
|
+
params: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
88
|
+
type: z.ZodEnum<{
|
|
89
|
+
enum: "enum";
|
|
90
|
+
path: "path";
|
|
91
|
+
token: "token";
|
|
92
|
+
slug: "slug";
|
|
93
|
+
integer: "integer";
|
|
94
|
+
}>;
|
|
95
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
96
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
97
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
98
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
99
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
100
|
+
binding: z.ZodObject<{
|
|
101
|
+
kind: z.ZodEnum<{
|
|
102
|
+
option: "option";
|
|
103
|
+
positional: "positional";
|
|
104
|
+
}>;
|
|
105
|
+
token: z.ZodString;
|
|
106
|
+
required: z.ZodBoolean;
|
|
107
|
+
}, z.core.$strip>;
|
|
108
|
+
constraintSource: z.ZodEnum<{
|
|
109
|
+
introspected: "introspected";
|
|
110
|
+
handwritten: "handwritten";
|
|
111
|
+
}>;
|
|
112
|
+
}, z.core.$strip>>;
|
|
113
|
+
introspection: z.ZodObject<{
|
|
114
|
+
optionTokens: z.ZodArray<z.ZodString>;
|
|
115
|
+
positionalCount: z.ZodNumber;
|
|
116
|
+
}, z.core.$strip>;
|
|
117
|
+
}, z.core.$strip>>;
|
|
118
|
+
}, z.core.$strip>;
|
|
119
|
+
export type PlaceholderSpec = z.infer<typeof PlaceholderSpecSchema>;
|
|
120
|
+
export type ReadOnlyWhitelistEntry = z.infer<typeof EntrySchema>;
|
|
121
|
+
export type ReadOnlyWhitelist = z.infer<typeof WhitelistSchema>;
|
|
122
|
+
/** Absolute path of the generated artifact for a package root. */
|
|
123
|
+
export declare function resolveReadOnlyWhitelistPath(root?: string): string;
|
|
124
|
+
/** Parse + validate the artifact text. Throws a zod error when the shape drifts. */
|
|
125
|
+
export declare function parseReadOnlyWhitelist(text: string): ReadOnlyWhitelist;
|
|
126
|
+
/** Read + validate the artifact. The only supported way to obtain it. */
|
|
127
|
+
export declare function loadReadOnlyWhitelist(root?: string): ReadOnlyWhitelist;
|
|
128
|
+
/** The param names an entry expects, in argv order. */
|
|
129
|
+
export declare function paramNamesOf(entry: ReadOnlyWhitelistEntry): string[];
|
|
130
|
+
/**
|
|
131
|
+
* The tool names the surface declares, in first-appearance order.
|
|
132
|
+
*
|
|
133
|
+
* This is the pre-tool interceptor's view of "what may be called", and it is
|
|
134
|
+
* computed HERE rather than in the MCP module on purpose: the interceptor must
|
|
135
|
+
* keep working when `src/services/mcp/` is deleted (spec §1), so it cannot reach
|
|
136
|
+
* into it for the answer. Grouping the entries by their `tool` field is the whole
|
|
137
|
+
* computation, and both readers do it from the same DATA.
|
|
138
|
+
*/
|
|
139
|
+
export declare function toolIdsOf(whitelist: ReadOnlyWhitelist): string[];
|
|
140
|
+
/**
|
|
141
|
+
* Match a CONCRETE argv against the entries. A param slot consumes exactly one
|
|
142
|
+
* token, so `--apply` in a param slot still MATCHES here - refusing it is the
|
|
143
|
+
* validator's job (`argv-guard.ts`), not the matcher's. Keeping the two separate
|
|
144
|
+
* is what stops a rejected value from silently re-routing to another entry.
|
|
145
|
+
*/
|
|
146
|
+
export declare function matchReadOnlyEntry(whitelist: ReadOnlyWhitelist, argv: readonly string[]): ReadOnlyWhitelistEntry | undefined;
|
|
147
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only argv whitelist, as DATA.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS IS A LOADER AND NOT AN IMPORT. The generated whitelist is read by two
|
|
5
|
+
* consumers that must survive the removal of the MCP module (spec §1): the
|
|
6
|
+
* pre-tool interceptor and, later, the MCP server. If either `import`ed the
|
|
7
|
+
* generated artifact it would become a static edge between them, and deleting
|
|
8
|
+
* the MCP module would break the gate. So the artifact stays a `.json` file and
|
|
9
|
+
* every reader goes through the filesystem. `tests/unit/standards/no-mcp-source-import.test.ts`
|
|
10
|
+
* pins that no module may `import` it.
|
|
11
|
+
*
|
|
12
|
+
* The shape is `{ schemaVersion, source, readOnlyDefinition, entries[] }`. Each
|
|
13
|
+
* entry is a full argv template (flags included) plus typed placeholders - the
|
|
14
|
+
* key is the WHOLE argv, never the top-level verb, because each named command
|
|
15
|
+
* family mixes read and write subcommands.
|
|
16
|
+
*/
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { z } from 'zod';
|
|
20
|
+
import { repoRoot } from 'peaks-loop-shared/paths';
|
|
21
|
+
/** Where the generator writes the artifact, relative to the package root. */
|
|
22
|
+
export const READONLY_WHITELIST_RELATIVE_PATH = 'contracts/readonly-argv-whitelist.json';
|
|
23
|
+
const PlaceholderBindingSchema = z.object({
|
|
24
|
+
/** `option` when the value is the argument of a flag, `positional` otherwise. */
|
|
25
|
+
kind: z.enum(['option', 'positional']),
|
|
26
|
+
/** The flag token (`--role`) or the positional name (`request-id`). */
|
|
27
|
+
token: z.string().min(1),
|
|
28
|
+
required: z.boolean()
|
|
29
|
+
});
|
|
30
|
+
const PlaceholderSpecSchema = z.object({
|
|
31
|
+
type: z.enum(['slug', 'enum', 'token', 'integer', 'path']),
|
|
32
|
+
pattern: z.string().min(1).optional(),
|
|
33
|
+
values: z.array(z.string().min(1)).min(1).optional(),
|
|
34
|
+
min: z.number().int().optional(),
|
|
35
|
+
max: z.number().int().optional(),
|
|
36
|
+
default: z.number().int().optional(),
|
|
37
|
+
/**
|
|
38
|
+
* Where the placeholder lives and whether the REGISTRY makes it mandatory.
|
|
39
|
+
* A placeholder present in the template is always supplied a value; this
|
|
40
|
+
* field carries the introspected fact, not the template's demand.
|
|
41
|
+
*/
|
|
42
|
+
binding: PlaceholderBindingSchema,
|
|
43
|
+
/** `introspected` when the registry supplied the constraint, else `handwritten`. */
|
|
44
|
+
constraintSource: z.enum(['introspected', 'handwritten'])
|
|
45
|
+
});
|
|
46
|
+
const ArgvSegmentSchema = z.union([
|
|
47
|
+
z.object({ kind: z.literal('literal'), value: z.string().min(1) }),
|
|
48
|
+
z.object({ kind: z.literal('param'), name: z.string().min(1) })
|
|
49
|
+
]);
|
|
50
|
+
const EntrySchema = z.object({
|
|
51
|
+
id: z.string().min(1),
|
|
52
|
+
tool: z.string().min(1),
|
|
53
|
+
commandPath: z.array(z.string().min(1)).min(1),
|
|
54
|
+
argv: z.array(ArgvSegmentSchema).min(1),
|
|
55
|
+
params: z.record(z.string(), PlaceholderSpecSchema),
|
|
56
|
+
introspection: z.object({
|
|
57
|
+
optionTokens: z.array(z.string().min(1)),
|
|
58
|
+
positionalCount: z.number().int().gte(0)
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
const WhitelistSchema = z.object({
|
|
62
|
+
schemaVersion: z.literal(1),
|
|
63
|
+
source: z.string().min(1),
|
|
64
|
+
readOnlyDefinition: z.string().min(1),
|
|
65
|
+
entries: z.array(EntrySchema).min(1)
|
|
66
|
+
});
|
|
67
|
+
/** Absolute path of the generated artifact for a package root. */
|
|
68
|
+
export function resolveReadOnlyWhitelistPath(root = repoRoot) {
|
|
69
|
+
return join(root, READONLY_WHITELIST_RELATIVE_PATH);
|
|
70
|
+
}
|
|
71
|
+
/** Parse + validate the artifact text. Throws a zod error when the shape drifts. */
|
|
72
|
+
export function parseReadOnlyWhitelist(text) {
|
|
73
|
+
return WhitelistSchema.parse(JSON.parse(text));
|
|
74
|
+
}
|
|
75
|
+
/** Read + validate the artifact. The only supported way to obtain it. */
|
|
76
|
+
export function loadReadOnlyWhitelist(root = repoRoot) {
|
|
77
|
+
return parseReadOnlyWhitelist(readFileSync(resolveReadOnlyWhitelistPath(root), 'utf8'));
|
|
78
|
+
}
|
|
79
|
+
/** The param names an entry expects, in argv order. */
|
|
80
|
+
export function paramNamesOf(entry) {
|
|
81
|
+
return entry.argv.flatMap((segment) => (segment.kind === 'param' ? [segment.name] : []));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The tool names the surface declares, in first-appearance order.
|
|
85
|
+
*
|
|
86
|
+
* This is the pre-tool interceptor's view of "what may be called", and it is
|
|
87
|
+
* computed HERE rather than in the MCP module on purpose: the interceptor must
|
|
88
|
+
* keep working when `src/services/mcp/` is deleted (spec §1), so it cannot reach
|
|
89
|
+
* into it for the answer. Grouping the entries by their `tool` field is the whole
|
|
90
|
+
* computation, and both readers do it from the same DATA.
|
|
91
|
+
*/
|
|
92
|
+
export function toolIdsOf(whitelist) {
|
|
93
|
+
return [...new Set(whitelist.entries.map((entry) => entry.tool))];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Match a CONCRETE argv against the entries. A param slot consumes exactly one
|
|
97
|
+
* token, so `--apply` in a param slot still MATCHES here - refusing it is the
|
|
98
|
+
* validator's job (`argv-guard.ts`), not the matcher's. Keeping the two separate
|
|
99
|
+
* is what stops a rejected value from silently re-routing to another entry.
|
|
100
|
+
*/
|
|
101
|
+
export function matchReadOnlyEntry(whitelist, argv) {
|
|
102
|
+
return whitelist.entries.find((entry) => {
|
|
103
|
+
if (entry.argv.length !== argv.length)
|
|
104
|
+
return false;
|
|
105
|
+
return entry.argv.every((segment, index) => segment.kind === 'literal' ? segment.value === argv[index] : true);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { type ReadOnlyWhitelist } from './readonly-whitelist.js';
|
|
4
|
+
/** The hand-authored input, relative to the package root. */
|
|
5
|
+
export declare const READONLY_SURFACE_RELATIVE_PATH = "contracts/readonly-surface.json";
|
|
6
|
+
/** The schema version of the artifact this module emits. */
|
|
7
|
+
export declare const READONLY_WHITELIST_SCHEMA_VERSION = 1;
|
|
8
|
+
declare const SurfaceEntrySchema: z.ZodObject<{
|
|
9
|
+
id: z.ZodString;
|
|
10
|
+
commandPath: z.ZodArray<z.ZodString>;
|
|
11
|
+
argv: z.ZodArray<z.ZodString>;
|
|
12
|
+
params: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
13
|
+
type: z.ZodEnum<{
|
|
14
|
+
enum: "enum";
|
|
15
|
+
path: "path";
|
|
16
|
+
token: "token";
|
|
17
|
+
slug: "slug";
|
|
18
|
+
integer: "integer";
|
|
19
|
+
}>;
|
|
20
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
21
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
22
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
}, z.core.$strip>>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export declare const ReadOnlySurfaceSchema: z.ZodObject<{
|
|
28
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
29
|
+
readOnlyDefinition: z.ZodString;
|
|
30
|
+
note: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
31
|
+
tools: z.ZodArray<z.ZodObject<{
|
|
32
|
+
tool: z.ZodString;
|
|
33
|
+
entries: z.ZodArray<z.ZodObject<{
|
|
34
|
+
id: z.ZodString;
|
|
35
|
+
commandPath: z.ZodArray<z.ZodString>;
|
|
36
|
+
argv: z.ZodArray<z.ZodString>;
|
|
37
|
+
params: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
38
|
+
type: z.ZodEnum<{
|
|
39
|
+
enum: "enum";
|
|
40
|
+
path: "path";
|
|
41
|
+
token: "token";
|
|
42
|
+
slug: "slug";
|
|
43
|
+
integer: "integer";
|
|
44
|
+
}>;
|
|
45
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
46
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
47
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
48
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
49
|
+
default: z.ZodOptional<z.ZodNumber>;
|
|
50
|
+
}, z.core.$strip>>;
|
|
51
|
+
}, z.core.$strip>>;
|
|
52
|
+
}, z.core.$strip>>;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
export type ReadOnlySurface = z.infer<typeof ReadOnlySurfaceSchema>;
|
|
55
|
+
export type ReadOnlySurfaceEntry = z.infer<typeof SurfaceEntrySchema>;
|
|
56
|
+
/** Build the artifact object from a surface declaration and a live program. */
|
|
57
|
+
export declare function generateReadOnlyWhitelist(surface: ReadOnlySurface, program: Command): ReadOnlyWhitelist;
|
|
58
|
+
/** Byte-stable serialization: two runs over the same input MUST match. */
|
|
59
|
+
export declare function serializeReadOnlyWhitelist(whitelist: ReadOnlyWhitelist): string;
|
|
60
|
+
/** Read + validate the hand-authored surface declaration. */
|
|
61
|
+
export declare function loadReadOnlySurface(root?: string): ReadOnlySurface;
|
|
62
|
+
/** Absolute path of the generated artifact. */
|
|
63
|
+
export declare function readonlyWhitelistPath(root?: string): string;
|
|
64
|
+
export {};
|