@webpresso/agent-kit 3.1.30 → 3.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.
Potentially problematic release.
This version of @webpresso/agent-kit might be problematic. Click here for more details.
- package/README.md +53 -15
- package/bin/_run.js +179 -19
- package/catalog/AGENTS.md.tpl +3 -3
- package/catalog/agent/agents/implementer.md +45 -0
- package/catalog/agent/rules/parallel-orchestration-quota.md +100 -0
- package/catalog/agent/rules/pre-implementation.md +28 -1
- package/catalog/agent/rules/supported-agent-clis.md +9 -0
- package/catalog/agent/rules/typescript-version.md +50 -0
- package/catalog/agent/skills/codex/SKILL.md +25 -1
- package/catalog/agent/skills/verify/SKILL.md +4 -2
- package/catalog/docs/templates/blueprint.md +1 -1
- package/dist/esm/audit/agents.js +1 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.d.ts +12 -0
- package/dist/esm/audit/blueprint-lifecycle-sql.js +23 -2
- package/dist/esm/audit/blueprint-pr-coverage.js +4 -0
- package/dist/esm/audit/ci-guardrails-wiring.d.ts +22 -0
- package/dist/esm/audit/ci-guardrails-wiring.js +90 -0
- package/dist/esm/audit/ci-test-perf.js +30 -0
- package/dist/esm/audit/command-surface.js +4 -2
- package/dist/esm/audit/host-substitution-risk.d.ts +2 -0
- package/dist/esm/audit/host-substitution-risk.js +256 -0
- package/dist/esm/audit/registry.d.ts +4 -4
- package/dist/esm/audit/registry.js +8 -1
- package/dist/esm/audit/toolchain-isolation.js +1 -2
- package/dist/esm/audit/typescript-version.d.ts +2 -0
- package/dist/esm/audit/typescript-version.js +123 -0
- package/dist/esm/blueprint/core/parser.js +43 -1
- package/dist/esm/blueprint/core/validation/criteria.d.ts +14 -0
- package/dist/esm/blueprint/core/validation/criteria.js +41 -2
- package/dist/esm/blueprint/core/validation/state.js +25 -14
- package/dist/esm/blueprint/db/migrations/run.js +4 -2
- package/dist/esm/blueprint/lifecycle/audit.d.ts +20 -0
- package/dist/esm/blueprint/lifecycle/audit.js +65 -10
- package/dist/esm/blueprint/lifecycle/canonicalize.d.ts +6 -0
- package/dist/esm/blueprint/lifecycle/canonicalize.js +135 -0
- package/dist/esm/blueprint/lifecycle/local.d.ts +2 -1
- package/dist/esm/blueprint/lifecycle/local.js +19 -3
- package/dist/esm/blueprint/lifecycle/review-provenance.js +36 -11
- package/dist/esm/blueprint/service/BlueprintCreationService.d.ts +1 -0
- package/dist/esm/blueprint/service/BlueprintCreationService.js +53 -4
- package/dist/esm/blueprint/service/blueprint-tech-debt-links.js +16 -2
- package/dist/esm/blueprint/trust/command-runner.d.ts +26 -0
- package/dist/esm/blueprint/trust/command-runner.js +148 -0
- package/dist/esm/blueprint/trust/gates.d.ts +7 -0
- package/dist/esm/blueprint/trust/gates.js +20 -0
- package/dist/esm/blueprint/trust/promotion.d.ts +8 -0
- package/dist/esm/blueprint/trust/promotion.js +62 -112
- package/dist/esm/blueprint/trust/scaffold.d.ts +19 -0
- package/dist/esm/blueprint/trust/scaffold.js +64 -0
- package/dist/esm/blueprint/trust/validator.d.ts +1 -0
- package/dist/esm/blueprint/trust/validator.js +7 -1
- package/dist/esm/blueprint/utils/archive.js +27 -5
- package/dist/esm/blueprint/utils/document-paths.d.ts +18 -0
- package/dist/esm/blueprint/utils/document-paths.js +45 -12
- package/dist/esm/build/cli-mcp-parity.js +10 -0
- package/dist/esm/cli/bundle/commands/blueprint.d.ts +1 -0
- package/dist/esm/cli/bundle/commands/blueprint.js +1 -0
- package/dist/esm/cli/cli.d.ts +1 -1
- package/dist/esm/cli/cli.js +34 -0
- package/dist/esm/cli/commands/agent-launch.d.ts +6 -1
- package/dist/esm/cli/commands/agent-launch.js +82 -4
- package/dist/esm/cli/commands/audit-core.d.ts +1 -1
- package/dist/esm/cli/commands/audit-core.js +8 -1
- package/dist/esm/cli/commands/audit.js +17 -5
- package/dist/esm/cli/commands/blueprint/execution.js +18 -6
- package/dist/esm/cli/commands/blueprint/mutations.js +59 -40
- package/dist/esm/cli/commands/blueprint/router-dispatch.d.ts +2 -1
- package/dist/esm/cli/commands/blueprint/router-dispatch.js +20 -1
- package/dist/esm/cli/commands/blueprint/router-output.d.ts +21 -0
- package/dist/esm/cli/commands/blueprint/router-output.js +48 -17
- package/dist/esm/cli/commands/blueprint/router.d.ts +7 -0
- package/dist/esm/cli/commands/blueprint/router.js +13 -1
- package/dist/esm/cli/commands/ci-preflight.d.ts +13 -2
- package/dist/esm/cli/commands/ci-preflight.js +6 -3
- package/dist/esm/cli/commands/compile.js +5 -31
- package/dist/esm/cli/commands/dash/delivery-status.d.ts +1 -0
- package/dist/esm/cli/commands/dash/delivery-status.js +11 -4
- package/dist/esm/cli/commands/doctor.js +5 -0
- package/dist/esm/cli/commands/hook.d.ts +5 -0
- package/dist/esm/cli/commands/hook.js +15 -9
- package/dist/esm/cli/commands/init/config.js +2 -2
- package/dist/esm/cli/commands/init/convergence-apply.d.ts +24 -0
- package/dist/esm/cli/commands/init/convergence-apply.js +221 -0
- package/dist/esm/cli/commands/init/convergence-state.d.ts +13 -0
- package/dist/esm/cli/commands/init/convergence-state.js +54 -0
- package/dist/esm/cli/commands/init/convergence.d.ts +23 -0
- package/dist/esm/cli/commands/init/convergence.js +57 -0
- package/dist/esm/cli/commands/init/git-convergence.d.ts +19 -0
- package/dist/esm/cli/commands/init/git-convergence.js +168 -0
- package/dist/esm/cli/commands/init/gitignore-patcher.js +2 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.d.ts +52 -0
- package/dist/esm/cli/commands/init/grok-privacy-smoke.js +91 -0
- package/dist/esm/cli/commands/init/host-native-proof.d.ts +18 -0
- package/dist/esm/cli/commands/init/host-native-proof.js +88 -0
- package/dist/esm/cli/commands/init/host-visibility.d.ts +2 -2
- package/dist/esm/cli/commands/init/host-visibility.js +94 -5
- package/dist/esm/cli/commands/init/index.d.ts +1 -0
- package/dist/esm/cli/commands/init/index.js +326 -173
- package/dist/esm/cli/commands/init/mcp-spec.d.ts +57 -0
- package/dist/esm/cli/commands/init/mcp-spec.js +273 -0
- package/dist/esm/cli/commands/init/merge.d.ts +1 -0
- package/dist/esm/cli/commands/init/merge.js +30 -1
- package/dist/esm/cli/commands/init/plugin-cache-prune.d.ts +0 -3
- package/dist/esm/cli/commands/init/plugin-cache-prune.js +0 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.d.ts +1 -1
- package/dist/esm/cli/commands/init/scaffold-agents-md.js +9 -3
- package/dist/esm/cli/commands/init/scaffold-base-kit.d.ts +11 -0
- package/dist/esm/cli/commands/init/scaffold-base-kit.js +56 -1
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.d.ts +14 -8
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/emitters/grok.js +41 -24
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.d.ts +2 -0
- package/dist/esm/cli/commands/init/scaffolders/agent-hooks/index.js +51 -23
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.d.ts +12 -31
- package/dist/esm/cli/commands/init/scaffolders/codex-mcp/index.js +288 -202
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.d.ts +7 -0
- package/dist/esm/cli/commands/init/scaffolders/file-transaction.js +58 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.d.ts +38 -0
- package/dist/esm/cli/commands/init/scaffolders/grok-mcp/index.js +73 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.d.ts +21 -0
- package/dist/esm/cli/commands/init/scaffolders/opencode-plugin/index.js +559 -63
- package/dist/esm/cli/commands/init/untracked-collision.d.ts +14 -0
- package/dist/esm/cli/commands/init/untracked-collision.js +42 -0
- package/dist/esm/cli/commands/opencode-rotate.d.ts +49 -0
- package/dist/esm/cli/commands/opencode-rotate.js +135 -0
- package/dist/esm/cli/commands/public-readiness.d.ts +11 -0
- package/dist/esm/cli/commands/public-readiness.js +42 -0
- package/dist/esm/cli/commands/review.d.ts +35 -3
- package/dist/esm/cli/commands/review.js +729 -209
- package/dist/esm/cli/commands/run-wait.d.ts +2 -0
- package/dist/esm/cli/commands/run-wait.js +122 -0
- package/dist/esm/cli/commands/setup-help.js +1 -1
- package/dist/esm/cli/commands/setup-repair-help.js +1 -1
- package/dist/esm/cli/commands/worktree/router-dispatch.js +13 -8
- package/dist/esm/cli/direct-provider-launch.js +9 -5
- package/dist/esm/cli/optional-tool-freshness.d.ts +27 -0
- package/dist/esm/cli/optional-tool-freshness.js +219 -9
- package/dist/esm/daemon/domains/git-actions.d.ts +29 -0
- package/dist/esm/daemon/domains/git-actions.js +136 -0
- package/dist/esm/daemon/domains/run-registry-interop.d.ts +16 -0
- package/dist/esm/daemon/domains/run-registry-interop.js +45 -0
- package/dist/esm/daemon/domains/sessions-search.d.ts +11 -0
- package/dist/esm/daemon/domains/sessions-search.js +29 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.d.ts +5 -0
- package/dist/esm/daemon/handlers/blueprints-handlers.js +36 -0
- package/dist/esm/daemon/handlers/deploy-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/deploy-handlers.js +5 -0
- package/dist/esm/daemon/handlers/fleet-handlers.d.ts +15 -0
- package/dist/esm/daemon/handlers/fleet-handlers.js +91 -0
- package/dist/esm/daemon/handlers/git-handlers.d.ts +6 -0
- package/dist/esm/daemon/handlers/git-handlers.js +27 -0
- package/dist/esm/daemon/handlers/product.d.ts +7 -0
- package/dist/esm/daemon/handlers/product.js +10 -119
- package/dist/esm/daemon/handlers/sessions-handlers.d.ts +12 -0
- package/dist/esm/daemon/handlers/sessions-handlers.js +31 -0
- package/dist/esm/daemon/handlers/shared.d.ts +5 -0
- package/dist/esm/daemon/handlers/shared.js +16 -0
- package/dist/esm/daemon/methods.d.ts +8 -1
- package/dist/esm/daemon/methods.js +7 -0
- package/dist/esm/daemon/protocol/contract.d.ts +43 -0
- package/dist/esm/daemon/protocol/contract.js +26 -0
- package/dist/esm/daemon/protocol/index.d.ts +1 -1
- package/dist/esm/daemon/protocol/index.js +1 -1
- package/dist/esm/hooks/__conformance__/matrix.d.ts +6 -0
- package/dist/esm/hooks/__conformance__/matrix.js +137 -0
- package/dist/esm/hooks/conformance/batch.js +5 -0
- package/dist/esm/hooks/doctor.d.ts +3 -3
- package/dist/esm/hooks/doctor.js +30 -15
- package/dist/esm/hooks/permission-request/index.js +9 -3
- package/dist/esm/hooks/permission-request/policy.d.ts +9 -0
- package/dist/esm/hooks/permission-request/policy.js +13 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.d.ts +9 -0
- package/dist/esm/hooks/pretool-guard/dev-routing.js +41 -5
- package/dist/esm/hooks/pretool-guard/logger.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/logger.js +16 -0
- package/dist/esm/hooks/pretool-guard/runner.d.ts +6 -0
- package/dist/esm/hooks/pretool-guard/runner.js +68 -16
- package/dist/esm/hooks/pretool-guard/validators/blueprint.js +30 -10
- package/dist/esm/hooks/pretool-guard/validators/forbidden-commands.js +54 -0
- package/dist/esm/hooks/pretool-guard/validators/index.d.ts +7 -0
- package/dist/esm/hooks/pretool-guard/validators/index.js +21 -0
- package/dist/esm/hooks/pretool-guard/validators/path-contract.d.ts +19 -0
- package/dist/esm/hooks/pretool-guard/validators/path-contract.js +25 -8
- package/dist/esm/hooks/shared/guard-outcome.d.ts +149 -0
- package/dist/esm/hooks/shared/guard-outcome.js +215 -0
- package/dist/esm/hooks/shared/hook-bootstrap.d.ts +26 -0
- package/dist/esm/hooks/shared/hook-bootstrap.js +64 -1
- package/dist/esm/hooks/shared/types.d.ts +8 -5
- package/dist/esm/hooks/shared/types.js +23 -8
- package/dist/esm/hooks/stop/qa-changed-files.d.ts +11 -0
- package/dist/esm/hooks/stop/qa-changed-files.js +74 -0
- package/dist/esm/mcp/blueprint/_shared/lifecycle.js +14 -1
- package/dist/esm/mcp/blueprint/handlers/document-mutations.js +78 -4
- package/dist/esm/mcp/blueprint/handlers/review-log.js +8 -1
- package/dist/esm/mcp/blueprint/handlers/task-advance.js +113 -54
- package/dist/esm/mcp/blueprint/handlers/task-verify.js +39 -19
- package/dist/esm/mcp/blueprint/registration.js +3 -2
- package/dist/esm/mcp/server.d.ts +1 -0
- package/dist/esm/mcp/server.js +27 -0
- package/dist/esm/mcp/tools/_names.d.ts +1 -1
- package/dist/esm/mcp/tools/_names.js +5 -0
- package/dist/esm/mcp/tools/_registry.js +10 -0
- package/dist/esm/mcp/tools/_shared/audit-kinds.d.ts +1 -1
- package/dist/esm/mcp/tools/_shared/result.js +44 -1
- package/dist/esm/mcp/tools/audit.d.ts +4 -1
- package/dist/esm/mcp/tools/audit.js +30 -0
- package/dist/esm/mcp/tools/audits.d.ts +3 -0
- package/dist/esm/mcp/tools/ci-preflight.d.ts +50 -0
- package/dist/esm/mcp/tools/ci-preflight.js +183 -0
- package/dist/esm/mcp/tools/pr-upsert.js +39 -1
- package/dist/esm/mcp/tools/review-run.d.ts +28 -0
- package/dist/esm/mcp/tools/review-run.js +216 -0
- package/dist/esm/mcp/tools/run-wait.d.ts +86 -0
- package/dist/esm/mcp/tools/run-wait.js +593 -0
- package/dist/esm/mcp/tools/session-id.d.ts +3 -0
- package/dist/esm/mcp/tools/session-id.js +45 -0
- package/dist/esm/mcp/tools/session-info.d.ts +3 -0
- package/dist/esm/mcp/tools/session-info.js +49 -0
- package/dist/esm/output-transforms/audit.d.ts +23 -0
- package/dist/esm/output-transforms/audit.js +47 -0
- package/dist/esm/output-transforms/index.js +2 -0
- package/dist/esm/review/authority.js +13 -5
- package/dist/esm/review/availability.d.ts +22 -0
- package/dist/esm/review/availability.js +107 -20
- package/dist/esm/review/delivery-verifier.d.ts +27 -0
- package/dist/esm/review/delivery-verifier.js +115 -0
- package/dist/esm/review/events.d.ts +3 -2
- package/dist/esm/review/events.js +23 -3
- package/dist/esm/review/execution/adapters.js +26 -9
- package/dist/esm/review/execution/output-policy.d.ts +2 -0
- package/dist/esm/review/execution/output-policy.js +12 -0
- package/dist/esm/review/execution/review-checkout.js +87 -6
- package/dist/esm/review/execution/supervisor.js +5 -0
- package/dist/esm/review/execution/types.d.ts +8 -0
- package/dist/esm/review/opencode-account.d.ts +24 -0
- package/dist/esm/review/opencode-account.js +68 -0
- package/dist/esm/review/opencode-auth.d.ts +33 -0
- package/dist/esm/review/opencode-auth.js +79 -0
- package/dist/esm/review/subject.d.ts +12 -0
- package/dist/esm/review/subject.js +74 -22
- package/dist/esm/runtime/opencode-account-materializer.d.ts +34 -0
- package/dist/esm/runtime/opencode-account-materializer.js +33 -0
- package/dist/esm/status/snapshot.js +30 -19
- package/dist/esm/test/duration-sequencer.d.ts +20 -0
- package/dist/esm/test/duration-sequencer.js +54 -0
- package/dist/esm/test/shard-durations.json +922 -0
- package/dist/esm/test/worker-budget.d.ts +6 -0
- package/dist/esm/test/worker-budget.js +59 -1
- package/dist/esm/test-helpers/global-setup.d.ts +1 -1
- package/dist/esm/test-helpers/global-setup.js +68 -24
- package/dist/esm/ultragoal/service.d.ts +7 -0
- package/dist/esm/ultragoal/service.js +42 -2
- package/dist/esm/utils/write-json-file.js +3 -1
- package/dist/esm/worktrees/codex-project-trust.d.ts +15 -0
- package/dist/esm/worktrees/codex-project-trust.js +56 -0
- package/dist/esm/worktrees/registry.d.ts +8 -0
- package/dist/esm/worktrees/registry.js +18 -3
- package/package.json +16 -13
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defaultIndexDbPath } from "#mcp/tools/session-restore.js";
|
|
2
|
+
import { listDaemonSessions } from "#daemon/domains/run-registry-interop.js";
|
|
3
|
+
import { createSessionMemorySearchBackend, searchSessions, } from "#daemon/domains/sessions-search.js";
|
|
4
|
+
import { asRecord, requireString } from "./shared.js";
|
|
5
|
+
/**
|
|
6
|
+
* Build session-domain handlers scoped to `repoRoot`. `repoRoot` doubles as
|
|
7
|
+
* the dash run-registry cwd (sessions.list) and the session-memory index
|
|
8
|
+
* root (sessions.search) — both already resolve per-repo paths on their own.
|
|
9
|
+
*/
|
|
10
|
+
export function createSessionsHandlers(repoRoot) {
|
|
11
|
+
return {
|
|
12
|
+
"sessions.list": async (_session, params) => {
|
|
13
|
+
const record = asRecord(params);
|
|
14
|
+
const limit = typeof record.limit === "number" ? record.limit : undefined;
|
|
15
|
+
return listDaemonSessions({ cwd: repoRoot, limit });
|
|
16
|
+
},
|
|
17
|
+
"sessions.search": (_session, params) => {
|
|
18
|
+
const record = asRecord(params);
|
|
19
|
+
const query = requireString(record, "query");
|
|
20
|
+
const limit = typeof record.limit === "number" ? record.limit : undefined;
|
|
21
|
+
const backend = createSessionMemorySearchBackend(defaultIndexDbPath(repoRoot));
|
|
22
|
+
const hits = searchSessions(backend, { query, limit });
|
|
23
|
+
return { hits };
|
|
24
|
+
},
|
|
25
|
+
"launch.permissionState": () => ({
|
|
26
|
+
mode: "safe",
|
|
27
|
+
yoloPreference: false,
|
|
28
|
+
isolationWarning: "permission state is advisory until full permission UX lands",
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared parameter-parsing helpers for daemon product-domain handlers.
|
|
3
|
+
*/
|
|
4
|
+
export function asRecord(params) {
|
|
5
|
+
if (params === null || typeof params !== "object" || Array.isArray(params)) {
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
return params;
|
|
9
|
+
}
|
|
10
|
+
export function requireString(record, key) {
|
|
11
|
+
const v = record[key];
|
|
12
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
13
|
+
throw new Error(`missing string param: ${key}`);
|
|
14
|
+
}
|
|
15
|
+
return v;
|
|
16
|
+
}
|
|
@@ -92,6 +92,13 @@ export declare const DAEMON_METHOD_REGISTRY: {
|
|
|
92
92
|
readonly requireHandshake: true;
|
|
93
93
|
readonly uiFacing: true;
|
|
94
94
|
};
|
|
95
|
+
readonly "sessions.search": {
|
|
96
|
+
readonly privileged: true;
|
|
97
|
+
readonly requiresConfirmation: false;
|
|
98
|
+
readonly mutates: false;
|
|
99
|
+
readonly requireHandshake: true;
|
|
100
|
+
readonly uiFacing: true;
|
|
101
|
+
};
|
|
95
102
|
readonly "git.diff": {
|
|
96
103
|
readonly privileged: true;
|
|
97
104
|
readonly requiresConfirmation: false;
|
|
@@ -164,7 +171,7 @@ export type UiRpcMethod = {
|
|
|
164
171
|
[M in DaemonRpcMethod]: (typeof DAEMON_METHOD_REGISTRY)[M]["uiFacing"] extends true ? M : never;
|
|
165
172
|
}[DaemonRpcMethod];
|
|
166
173
|
export declare const UI_RPC_METHODS: UiRpcMethod[];
|
|
167
|
-
export declare const DESTRUCTIVE_METHODS: ("auth.issueNonce" | "blueprints.exec" | "blueprints.list" | "daemon.envMap.push" | "deploy.run" | "fleet.status" | "git.commit" | "git.createPr" | "git.diff" | "handshake" | "launch.claim" | "launch.permissionState" | "launch.prepare" | "ping" | "sessions.list" | "worktrees.list")[];
|
|
174
|
+
export declare const DESTRUCTIVE_METHODS: ("auth.issueNonce" | "blueprints.exec" | "blueprints.list" | "daemon.envMap.push" | "deploy.run" | "fleet.status" | "git.commit" | "git.createPr" | "git.diff" | "handshake" | "launch.claim" | "launch.permissionState" | "launch.prepare" | "ping" | "sessions.list" | "sessions.search" | "worktrees.list")[];
|
|
168
175
|
export declare function getMethodCapability(method: string): MethodCapability | null;
|
|
169
176
|
export declare function isDaemonRpcMethod(method: string): method is DaemonRpcMethod;
|
|
170
177
|
export declare function isUiRpcMethod(method: string): method is UiRpcMethod;
|
|
@@ -60,6 +60,13 @@ export const DAEMON_METHOD_REGISTRY = {
|
|
|
60
60
|
requireHandshake: true,
|
|
61
61
|
uiFacing: true,
|
|
62
62
|
},
|
|
63
|
+
"sessions.search": {
|
|
64
|
+
privileged: true,
|
|
65
|
+
requiresConfirmation: false,
|
|
66
|
+
mutates: false,
|
|
67
|
+
requireHandshake: true,
|
|
68
|
+
uiFacing: true,
|
|
69
|
+
},
|
|
63
70
|
"git.diff": {
|
|
64
71
|
privileged: true,
|
|
65
72
|
requiresConfirmation: false,
|
|
@@ -92,6 +92,7 @@ export declare const daemonRpcMethodSchema: z.ZodEnum<{
|
|
|
92
92
|
"launch.prepare": "launch.prepare";
|
|
93
93
|
ping: "ping";
|
|
94
94
|
"sessions.list": "sessions.list";
|
|
95
|
+
"sessions.search": "sessions.search";
|
|
95
96
|
"worktrees.list": "worktrees.list";
|
|
96
97
|
}>;
|
|
97
98
|
export declare const uiRpcMethodSchema: z.ZodEnum<{
|
|
@@ -108,6 +109,7 @@ export declare const uiRpcMethodSchema: z.ZodEnum<{
|
|
|
108
109
|
"launch.prepare": "launch.prepare";
|
|
109
110
|
ping: "ping";
|
|
110
111
|
"sessions.list": "sessions.list";
|
|
112
|
+
"sessions.search": "sessions.search";
|
|
111
113
|
"worktrees.list": "worktrees.list";
|
|
112
114
|
}>;
|
|
113
115
|
export declare const pingParamsSchema: z.ZodObject<{}, z.core.$strict>;
|
|
@@ -212,6 +214,32 @@ export declare const sessionsListResultSchema: z.ZodObject<{
|
|
|
212
214
|
}, z.core.$strict>>;
|
|
213
215
|
}, z.core.$strict>;
|
|
214
216
|
export type SessionsListResult = z.infer<typeof sessionsListResultSchema>;
|
|
217
|
+
/**
|
|
218
|
+
* No db-path override fields: path safety requires the daemon resolve its
|
|
219
|
+
* own index db path from its configured repoRoot, never from a
|
|
220
|
+
* webview-supplied param.
|
|
221
|
+
*/
|
|
222
|
+
export declare const sessionsSearchParamsSchema: z.ZodObject<{
|
|
223
|
+
query: z.ZodString;
|
|
224
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
225
|
+
}, z.core.$strict>;
|
|
226
|
+
export type SessionsSearchParams = z.infer<typeof sessionsSearchParamsSchema>;
|
|
227
|
+
export declare const sessionSearchHitSchema: z.ZodObject<{
|
|
228
|
+
id: z.ZodString;
|
|
229
|
+
source: z.ZodString;
|
|
230
|
+
text: z.ZodString;
|
|
231
|
+
score: z.ZodNumber;
|
|
232
|
+
}, z.core.$strict>;
|
|
233
|
+
export type SessionSearchHitResult = z.infer<typeof sessionSearchHitSchema>;
|
|
234
|
+
export declare const sessionsSearchResultSchema: z.ZodObject<{
|
|
235
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
236
|
+
id: z.ZodString;
|
|
237
|
+
source: z.ZodString;
|
|
238
|
+
text: z.ZodString;
|
|
239
|
+
score: z.ZodNumber;
|
|
240
|
+
}, z.core.$strict>>;
|
|
241
|
+
}, z.core.$strict>;
|
|
242
|
+
export type SessionsSearchResult = z.infer<typeof sessionsSearchResultSchema>;
|
|
215
243
|
export declare const gitDiffParamsSchema: z.ZodObject<{
|
|
216
244
|
cwd: z.ZodString;
|
|
217
245
|
}, z.core.$strict>;
|
|
@@ -255,6 +283,7 @@ export declare const fleetStatusResultSchema: z.ZodObject<{
|
|
|
255
283
|
label: z.ZodOptional<z.ZodString>;
|
|
256
284
|
}, z.core.$strict>>;
|
|
257
285
|
}, z.core.$strict>;
|
|
286
|
+
export type FleetStatusResult = z.infer<typeof fleetStatusResultSchema>;
|
|
258
287
|
export declare const worktreesListParamsSchema: z.ZodObject<{
|
|
259
288
|
repoRoot: z.ZodOptional<z.ZodString>;
|
|
260
289
|
}, z.core.$strict>;
|
|
@@ -387,6 +416,20 @@ export declare const UI_METHOD_SCHEMAS: {
|
|
|
387
416
|
}, z.core.$strict>>;
|
|
388
417
|
}, z.core.$strict>;
|
|
389
418
|
};
|
|
419
|
+
readonly "sessions.search": {
|
|
420
|
+
readonly params: z.ZodObject<{
|
|
421
|
+
query: z.ZodString;
|
|
422
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
423
|
+
}, z.core.$strict>;
|
|
424
|
+
readonly result: z.ZodObject<{
|
|
425
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
426
|
+
id: z.ZodString;
|
|
427
|
+
source: z.ZodString;
|
|
428
|
+
text: z.ZodString;
|
|
429
|
+
score: z.ZodNumber;
|
|
430
|
+
}, z.core.$strict>>;
|
|
431
|
+
}, z.core.$strict>;
|
|
432
|
+
};
|
|
390
433
|
readonly "git.diff": {
|
|
391
434
|
readonly params: z.ZodObject<{
|
|
392
435
|
cwd: z.ZodString;
|
|
@@ -189,6 +189,31 @@ export const sessionsListResultSchema = z
|
|
|
189
189
|
sessions: z.array(sessionSummarySchema),
|
|
190
190
|
})
|
|
191
191
|
.strict();
|
|
192
|
+
// --- sessions.search ---
|
|
193
|
+
/**
|
|
194
|
+
* No db-path override fields: path safety requires the daemon resolve its
|
|
195
|
+
* own index db path from its configured repoRoot, never from a
|
|
196
|
+
* webview-supplied param.
|
|
197
|
+
*/
|
|
198
|
+
export const sessionsSearchParamsSchema = z
|
|
199
|
+
.object({
|
|
200
|
+
query: z.string().min(1).max(4_096),
|
|
201
|
+
limit: z.number().int().positive().max(100).optional(),
|
|
202
|
+
})
|
|
203
|
+
.strict();
|
|
204
|
+
export const sessionSearchHitSchema = z
|
|
205
|
+
.object({
|
|
206
|
+
id: z.string().min(1),
|
|
207
|
+
source: z.string().min(1),
|
|
208
|
+
text: z.string(),
|
|
209
|
+
score: z.number(),
|
|
210
|
+
})
|
|
211
|
+
.strict();
|
|
212
|
+
export const sessionsSearchResultSchema = z
|
|
213
|
+
.object({
|
|
214
|
+
hits: z.array(sessionSearchHitSchema),
|
|
215
|
+
})
|
|
216
|
+
.strict();
|
|
192
217
|
// --- git (stubs) ---
|
|
193
218
|
export const gitDiffParamsSchema = z
|
|
194
219
|
.object({
|
|
@@ -311,6 +336,7 @@ export const UI_METHOD_SCHEMAS = {
|
|
|
311
336
|
result: launchPermissionStateResultSchema,
|
|
312
337
|
},
|
|
313
338
|
"sessions.list": { params: sessionsListParamsSchema, result: sessionsListResultSchema },
|
|
339
|
+
"sessions.search": { params: sessionsSearchParamsSchema, result: sessionsSearchResultSchema },
|
|
314
340
|
"git.diff": { params: gitDiffParamsSchema, result: gitDiffResultSchema },
|
|
315
341
|
"git.commit": { params: gitCommitParamsSchema, result: gitCommitResultSchema },
|
|
316
342
|
"git.createPr": { params: gitCreatePrParamsSchema, result: gitCreatePrResultSchema },
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* - `#daemon/protocol` (repo-internal package imports)
|
|
6
6
|
* - `@webpresso/agent-kit/daemon/protocol` (published subpath)
|
|
7
7
|
*/
|
|
8
|
-
export { DAEMON_PROTOCOL_VERSION, DAEMON_SESSION_MEMORY_SCHEMA_VERSION, DAEMON_RPC_METHODS, RUST_CHANNEL_METHODS, FORBIDDEN_UI_PAYLOAD_KEYS, UI_METHOD_SCHEMAS, opaqueHandleSchema, permissionModeSchema, providerIdSchema, peerRoleSchema, daemonRpcMethodSchema, handshakeParamsSchema, handshakeResultSchema, pingParamsSchema, pingResultSchema, launchPrepareParamsSchema, launchPrepareResultSchema, launchPermissionStateParamsSchema, launchPermissionStateResultSchema, sessionsListParamsSchema, sessionSummarySchema, sessionsListResultSchema, gitDiffParamsSchema, gitDiffResultSchema, gitCommitParamsSchema, gitCommitResultSchema, gitCreatePrParamsSchema, gitCreatePrResultSchema, fleetStatusParamsSchema, fleetStatusResultSchema, worktreesListParamsSchema, worktreesListResultSchema, blueprintsListParamsSchema, blueprintsListResultSchema, blueprintsExecParamsSchema, blueprintsExecResultSchema, deployRunParamsSchema, deployRunResultSchema, rustSpawnEnvMapSchema, rustSpawnEnvDeliverySchema, sessionExitNotificationSchema, jsonRpcIdSchema, jsonRpcRequestSchema, jsonRpcErrorObjectSchema, jsonRpcSuccessResponseSchema, jsonRpcErrorResponseSchema, jsonRpcResponseSchema, isDaemonRpcMethod, isUiRpcMethod, isRustChannelMethod, UI_RPC_METHODS, parseUiMethodParams, parseUiMethodResult, safeParseUiMethodParams, safeParseUiMethodResult, buildHandshakeResult, payloadHasForbiddenUiKeys, type OpaqueHandle, type PermissionMode, type ProviderId, type PeerRole, type ForbiddenUiPayloadKey, type HandshakeParams, type HandshakeResult, type DaemonRpcMethod, type PingParams, type PingResult, type LaunchPrepareParams, type LaunchPrepareResult, type LaunchPermissionStateParams, type LaunchPermissionStateResult, type SessionsListParams, type SessionSummary, type SessionsListResult, type GitDiffParams, type GitDiffResult, type GitCommitParams, type GitCommitResult, type GitCreatePrParams, type GitCreatePrResult, type RustSpawnEnvMap, type RustSpawnEnvDelivery, type RustChannelMethod, type JsonRpcId, type JsonRpcRequest, type JsonRpcResponse, type MethodSchemaPair, type UiMethodSchemas, } from "./contract.js";
|
|
8
|
+
export { DAEMON_PROTOCOL_VERSION, DAEMON_SESSION_MEMORY_SCHEMA_VERSION, DAEMON_RPC_METHODS, RUST_CHANNEL_METHODS, FORBIDDEN_UI_PAYLOAD_KEYS, UI_METHOD_SCHEMAS, opaqueHandleSchema, permissionModeSchema, providerIdSchema, peerRoleSchema, daemonRpcMethodSchema, handshakeParamsSchema, handshakeResultSchema, pingParamsSchema, pingResultSchema, launchPrepareParamsSchema, launchPrepareResultSchema, launchPermissionStateParamsSchema, launchPermissionStateResultSchema, sessionsListParamsSchema, sessionSummarySchema, sessionsListResultSchema, sessionsSearchParamsSchema, sessionSearchHitSchema, sessionsSearchResultSchema, gitDiffParamsSchema, gitDiffResultSchema, gitCommitParamsSchema, gitCommitResultSchema, gitCreatePrParamsSchema, gitCreatePrResultSchema, fleetStatusParamsSchema, fleetStatusResultSchema, worktreesListParamsSchema, worktreesListResultSchema, blueprintsListParamsSchema, blueprintsListResultSchema, blueprintsExecParamsSchema, blueprintsExecResultSchema, deployRunParamsSchema, deployRunResultSchema, rustSpawnEnvMapSchema, rustSpawnEnvDeliverySchema, sessionExitNotificationSchema, jsonRpcIdSchema, jsonRpcRequestSchema, jsonRpcErrorObjectSchema, jsonRpcSuccessResponseSchema, jsonRpcErrorResponseSchema, jsonRpcResponseSchema, isDaemonRpcMethod, isUiRpcMethod, isRustChannelMethod, UI_RPC_METHODS, parseUiMethodParams, parseUiMethodResult, safeParseUiMethodParams, safeParseUiMethodResult, buildHandshakeResult, payloadHasForbiddenUiKeys, type OpaqueHandle, type PermissionMode, type ProviderId, type PeerRole, type ForbiddenUiPayloadKey, type HandshakeParams, type HandshakeResult, type DaemonRpcMethod, type PingParams, type PingResult, type LaunchPrepareParams, type LaunchPrepareResult, type LaunchPermissionStateParams, type LaunchPermissionStateResult, type SessionsListParams, type SessionSummary, type SessionsListResult, type SessionsSearchParams, type SessionSearchHitResult, type SessionsSearchResult, type GitDiffParams, type GitDiffResult, type GitCommitParams, type GitCommitResult, type GitCreatePrParams, type GitCreatePrResult, type FleetStatusResult, type RustSpawnEnvMap, type RustSpawnEnvDelivery, type RustChannelMethod, type JsonRpcId, type JsonRpcRequest, type JsonRpcResponse, type MethodSchemaPair, type UiMethodSchemas, } from "./contract.js";
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* - `#daemon/protocol` (repo-internal package imports)
|
|
6
6
|
* - `@webpresso/agent-kit/daemon/protocol` (published subpath)
|
|
7
7
|
*/
|
|
8
|
-
export { DAEMON_PROTOCOL_VERSION, DAEMON_SESSION_MEMORY_SCHEMA_VERSION, DAEMON_RPC_METHODS, RUST_CHANNEL_METHODS, FORBIDDEN_UI_PAYLOAD_KEYS, UI_METHOD_SCHEMAS, opaqueHandleSchema, permissionModeSchema, providerIdSchema, peerRoleSchema, daemonRpcMethodSchema, handshakeParamsSchema, handshakeResultSchema, pingParamsSchema, pingResultSchema, launchPrepareParamsSchema, launchPrepareResultSchema, launchPermissionStateParamsSchema, launchPermissionStateResultSchema, sessionsListParamsSchema, sessionSummarySchema, sessionsListResultSchema, gitDiffParamsSchema, gitDiffResultSchema, gitCommitParamsSchema, gitCommitResultSchema, gitCreatePrParamsSchema, gitCreatePrResultSchema, fleetStatusParamsSchema, fleetStatusResultSchema, worktreesListParamsSchema, worktreesListResultSchema, blueprintsListParamsSchema, blueprintsListResultSchema, blueprintsExecParamsSchema, blueprintsExecResultSchema, deployRunParamsSchema, deployRunResultSchema, rustSpawnEnvMapSchema, rustSpawnEnvDeliverySchema, sessionExitNotificationSchema, jsonRpcIdSchema, jsonRpcRequestSchema, jsonRpcErrorObjectSchema, jsonRpcSuccessResponseSchema, jsonRpcErrorResponseSchema, jsonRpcResponseSchema, isDaemonRpcMethod, isUiRpcMethod, isRustChannelMethod, UI_RPC_METHODS, parseUiMethodParams, parseUiMethodResult, safeParseUiMethodParams, safeParseUiMethodResult, buildHandshakeResult, payloadHasForbiddenUiKeys, } from "./contract.js";
|
|
8
|
+
export { DAEMON_PROTOCOL_VERSION, DAEMON_SESSION_MEMORY_SCHEMA_VERSION, DAEMON_RPC_METHODS, RUST_CHANNEL_METHODS, FORBIDDEN_UI_PAYLOAD_KEYS, UI_METHOD_SCHEMAS, opaqueHandleSchema, permissionModeSchema, providerIdSchema, peerRoleSchema, daemonRpcMethodSchema, handshakeParamsSchema, handshakeResultSchema, pingParamsSchema, pingResultSchema, launchPrepareParamsSchema, launchPrepareResultSchema, launchPermissionStateParamsSchema, launchPermissionStateResultSchema, sessionsListParamsSchema, sessionSummarySchema, sessionsListResultSchema, sessionsSearchParamsSchema, sessionSearchHitSchema, sessionsSearchResultSchema, gitDiffParamsSchema, gitDiffResultSchema, gitCommitParamsSchema, gitCommitResultSchema, gitCreatePrParamsSchema, gitCreatePrResultSchema, fleetStatusParamsSchema, fleetStatusResultSchema, worktreesListParamsSchema, worktreesListResultSchema, blueprintsListParamsSchema, blueprintsListResultSchema, blueprintsExecParamsSchema, blueprintsExecResultSchema, deployRunParamsSchema, deployRunResultSchema, rustSpawnEnvMapSchema, rustSpawnEnvDeliverySchema, sessionExitNotificationSchema, jsonRpcIdSchema, jsonRpcRequestSchema, jsonRpcErrorObjectSchema, jsonRpcSuccessResponseSchema, jsonRpcErrorResponseSchema, jsonRpcResponseSchema, isDaemonRpcMethod, isUiRpcMethod, isRustChannelMethod, UI_RPC_METHODS, parseUiMethodParams, parseUiMethodResult, safeParseUiMethodParams, safeParseUiMethodResult, buildHandshakeResult, payloadHasForbiddenUiKeys, } from "./contract.js";
|
|
@@ -24,6 +24,12 @@ export type WebpressoHookBin = (typeof WEBPRESSO_HOOK_BINS)[number];
|
|
|
24
24
|
export type HookRunResult = {
|
|
25
25
|
readonly stdout: string;
|
|
26
26
|
readonly exitCode: number | null;
|
|
27
|
+
/**
|
|
28
|
+
* Captured stderr, when the runner provides it. Claude reads stderr as the
|
|
29
|
+
* blocking feedback on an exit-2 PreToolUse deny, so the coded reason is
|
|
30
|
+
* asserted here when the stdout envelope carries none.
|
|
31
|
+
*/
|
|
32
|
+
readonly stderr?: string;
|
|
27
33
|
};
|
|
28
34
|
type BaseRow = {
|
|
29
35
|
readonly name: string;
|
|
@@ -110,6 +110,96 @@ function denyDecision(obj) {
|
|
|
110
110
|
return "deny";
|
|
111
111
|
return null;
|
|
112
112
|
}
|
|
113
|
+
/** Extract the host-displayed deny reason from either envelope shape. */
|
|
114
|
+
function denyReasonText(obj) {
|
|
115
|
+
const hookSpecific = obj?.hookSpecificOutput;
|
|
116
|
+
if (hookSpecific && typeof hookSpecific === "object") {
|
|
117
|
+
const reason = hookSpecific.permissionDecisionReason;
|
|
118
|
+
if (typeof reason === "string")
|
|
119
|
+
return reason;
|
|
120
|
+
}
|
|
121
|
+
// Grok dual envelope carries a top-level reason.
|
|
122
|
+
if (typeof obj?.reason === "string")
|
|
123
|
+
return obj.reason;
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const GUARD_CODED_REASON_RE = /^GUARD_[A-Z0-9_]+: /u;
|
|
127
|
+
/**
|
|
128
|
+
* Every PreToolUse deny reason on a parseable stdout envelope carries a stable
|
|
129
|
+
* `GUARD_<CODE>: ` prefix within the 80-char permissionDecisionReason budget.
|
|
130
|
+
* The code is the cross-host contract; the prose is truncated to fit.
|
|
131
|
+
*
|
|
132
|
+
* This reads `result.stdout` directly (NOT the decision-path `obj`, which is
|
|
133
|
+
* null for a Claude exit-2 deny) so the coded reason is asserted on BOTH hosts —
|
|
134
|
+
* pretool-guard always prints the deny envelope to stdout (dual for claude/grok,
|
|
135
|
+
* hookSpecificOutput-only for codex) even when Claude reads the exit code for the
|
|
136
|
+
* decision itself. Non-JSON stdout (the synthetic "stdout is ignored" fixture)
|
|
137
|
+
* and the empty-stdout exit-code-deny convention carry no reason and are skipped.
|
|
138
|
+
*/
|
|
139
|
+
/** Parse an optional deny reason out of a JSON stdout deny envelope. */
|
|
140
|
+
function stdoutDenyReason(stdout) {
|
|
141
|
+
const text = stdout.trim();
|
|
142
|
+
if (text === "")
|
|
143
|
+
return null;
|
|
144
|
+
let parsed;
|
|
145
|
+
try {
|
|
146
|
+
parsed = JSON.parse(text);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (parsed === null || typeof parsed !== "object")
|
|
152
|
+
return null;
|
|
153
|
+
return denyReasonText(parsed);
|
|
154
|
+
}
|
|
155
|
+
/** First GUARD_-coded line in a captured stderr blob (Claude's exit-2 channel). */
|
|
156
|
+
function stderrCodedReason(stderr) {
|
|
157
|
+
if (!stderr)
|
|
158
|
+
return null;
|
|
159
|
+
for (const line of stderr.split("\n")) {
|
|
160
|
+
if (GUARD_CODED_REASON_RE.test(line.trim()))
|
|
161
|
+
return line.trim();
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
/** Assert a single reason is GUARD_-coded and within the 80-code-point budget. */
|
|
166
|
+
function assertCodedWithinBudget(row, label, reason) {
|
|
167
|
+
if (!GUARD_CODED_REASON_RE.test(reason)) {
|
|
168
|
+
throw new Error(`[${row.name}] ${label} must start with a GUARD_ code prefix, got ${JSON.stringify(reason)}`);
|
|
169
|
+
}
|
|
170
|
+
const points = [...reason].length;
|
|
171
|
+
if (points > 80) {
|
|
172
|
+
throw new Error(`[${row.name}] ${label} exceeds the 80-code-point budget (${points}): ${JSON.stringify(reason)}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function assertGuardCodedDenyReason(row, result) {
|
|
176
|
+
// The coded reason must reach the host on the channel it reads: the stdout
|
|
177
|
+
// deny envelope (Codex/Grok) or stderr (Claude reads stderr on an exit-2
|
|
178
|
+
// PreToolUse deny). Single-spawn tests capture the host boundary directly;
|
|
179
|
+
// the batch runner installs a row-scoped intentional-stderr capture so this
|
|
180
|
+
// same assertion also applies to source/compiled parity.
|
|
181
|
+
const reason = stdoutDenyReason(result.stdout) ?? stderrCodedReason(result.stderr);
|
|
182
|
+
if (reason === null) {
|
|
183
|
+
throw new Error(`[${row.name}] a PreToolUse deny must carry a GUARD_-coded reason on the stdout envelope or stderr; found none`);
|
|
184
|
+
}
|
|
185
|
+
assertCodedWithinBudget(row, "deny reason", reason);
|
|
186
|
+
}
|
|
187
|
+
function assertCodexExitTwoBlockingReason(row, result) {
|
|
188
|
+
if (row.host !== "codex" ||
|
|
189
|
+
row.event !== "PreToolUse" ||
|
|
190
|
+
result.exitCode !== 2 ||
|
|
191
|
+
result.stderr === undefined) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const stderrReason = stderrCodedReason(result.stderr);
|
|
195
|
+
if (stderrReason === null) {
|
|
196
|
+
throw new Error(`[${row.name}] Codex exit-2 PreToolUse deny must write a GUARD_-coded blocking reason to stderr`);
|
|
197
|
+
}
|
|
198
|
+
const stdoutReason = stdoutDenyReason(result.stdout);
|
|
199
|
+
if (stdoutReason !== null && stderrReason !== stdoutReason) {
|
|
200
|
+
throw new Error(`[${row.name}] Codex stdout and stderr deny reasons must match exactly`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
113
203
|
/** PermissionRequest golden wire: hookSpecificOutput.decision.behavior allow|deny. */
|
|
114
204
|
function permissionRequestBehavior(obj) {
|
|
115
205
|
const hookSpecific = obj?.hookSpecificOutput;
|
|
@@ -121,6 +211,45 @@ function permissionRequestBehavior(obj) {
|
|
|
121
211
|
const behavior = decision.behavior;
|
|
122
212
|
return typeof behavior === "string" ? behavior : null;
|
|
123
213
|
}
|
|
214
|
+
/** PermissionRequest golden wire message: hookSpecificOutput.decision.message. */
|
|
215
|
+
function permissionRequestMessage(obj) {
|
|
216
|
+
const hookSpecific = obj?.hookSpecificOutput;
|
|
217
|
+
if (!hookSpecific || typeof hookSpecific !== "object")
|
|
218
|
+
return null;
|
|
219
|
+
const decision = hookSpecific.decision;
|
|
220
|
+
if (!decision || typeof decision !== "object")
|
|
221
|
+
return null;
|
|
222
|
+
const message = decision.message;
|
|
223
|
+
return typeof message === "string" ? message : null;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* A PermissionRequest allow/deny message on a parseable envelope carries the
|
|
227
|
+
* same `GUARD_<CODE>: ` prefix within the 80-char budget as PreToolUse denies —
|
|
228
|
+
* the vocabulary is central, not PreToolUse-only. Skipped when there is no
|
|
229
|
+
* envelope message (e.g. a pure exit-2 deny with no stdout).
|
|
230
|
+
*/
|
|
231
|
+
function assertGuardCodedPermissionMessage(row, result, expect) {
|
|
232
|
+
let stdoutMessage = null;
|
|
233
|
+
const text = result.stdout.trim();
|
|
234
|
+
if (text !== "") {
|
|
235
|
+
try {
|
|
236
|
+
const parsed = JSON.parse(text);
|
|
237
|
+
if (parsed !== null && typeof parsed === "object") {
|
|
238
|
+
stdoutMessage = permissionRequestMessage(parsed);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
stdoutMessage = null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// A deny exits 2 and also carries the coded message on stderr; an allow exits 0
|
|
246
|
+
// with the coded message on the stdout envelope.
|
|
247
|
+
const message = stdoutMessage ?? stderrCodedReason(result.stderr);
|
|
248
|
+
if (message === null) {
|
|
249
|
+
throw new Error(`[${row.name}] PermissionRequest ${expect} must carry a GUARD_-coded message on the stdout envelope or stderr; found none`);
|
|
250
|
+
}
|
|
251
|
+
assertCodedWithinBudget(row, "PermissionRequest message", message);
|
|
252
|
+
}
|
|
124
253
|
function assertNoCodexUnsupportedFields(row, obj) {
|
|
125
254
|
if (row.host !== "codex" || obj === null)
|
|
126
255
|
return;
|
|
@@ -170,6 +299,11 @@ export function assertConformance(row, result) {
|
|
|
170
299
|
// exit-code deny convention). A deny envelope printed just before the hook
|
|
171
300
|
// crashes (exit 1) is not a valid decision.
|
|
172
301
|
assertExitCode(row, result, true);
|
|
302
|
+
// Every deny reason is GUARD_-coded and within the 80-char budget on
|
|
303
|
+
// both Tier-1 hosts (read from stdout, which carries the envelope even
|
|
304
|
+
// when Claude uses the exit code for the decision).
|
|
305
|
+
assertGuardCodedDenyReason(row, result);
|
|
306
|
+
assertCodexExitTwoBlockingReason(row, result);
|
|
173
307
|
}
|
|
174
308
|
else {
|
|
175
309
|
if (decision === "deny") {
|
|
@@ -196,6 +330,8 @@ export function assertConformance(row, result) {
|
|
|
196
330
|
if (result.exitCode !== 2) {
|
|
197
331
|
throw new Error(`[${row.name}] expected PermissionRequest deny via exit 2, got exit ${result.exitCode ?? "null"}`);
|
|
198
332
|
}
|
|
333
|
+
// The deny message carries the central GUARD_ code contract too.
|
|
334
|
+
assertGuardCodedPermissionMessage(row, result, "deny");
|
|
199
335
|
return;
|
|
200
336
|
}
|
|
201
337
|
if (row.expect === "allow") {
|
|
@@ -203,6 +339,7 @@ export function assertConformance(row, result) {
|
|
|
203
339
|
throw new Error(`[${row.name}] expected PermissionRequest allow envelope, got behavior=${behavior ?? "none"} (stdout: ${result.stdout.slice(0, 160)})`);
|
|
204
340
|
}
|
|
205
341
|
assertExitCode(row, result, false);
|
|
342
|
+
assertGuardCodedPermissionMessage(row, result, "allow");
|
|
206
343
|
return;
|
|
207
344
|
}
|
|
208
345
|
// pass-through: host default UI — empty object (or empty stdout), no decision, exit 0.
|
|
@@ -85,6 +85,7 @@ export async function runHookConformanceBatch() {
|
|
|
85
85
|
}
|
|
86
86
|
const raw = await readBatchStdin();
|
|
87
87
|
const { isHookName, runHookCommand } = await import("#cli/commands/hook.js");
|
|
88
|
+
const { installGuardStderrCapture } = await import("#hooks/shared/hook-bootstrap");
|
|
88
89
|
const payload = parseBatchPayload(raw, isHookName);
|
|
89
90
|
const protocolWrite = process.stdout.write.bind(process.stdout);
|
|
90
91
|
for (const row of payload.rows) {
|
|
@@ -92,6 +93,9 @@ export async function runHookConformanceBatch() {
|
|
|
92
93
|
let stdout = "";
|
|
93
94
|
let stderr = "";
|
|
94
95
|
const restoreEnv = setRowEnvironment(row);
|
|
96
|
+
const restoreGuardStderrCapture = installGuardStderrCapture((text) => {
|
|
97
|
+
stderr += text;
|
|
98
|
+
});
|
|
95
99
|
const originalStdoutWrite = process.stdout.write;
|
|
96
100
|
const originalStderrWrite = process.stderr.write;
|
|
97
101
|
process.stdout.write = (chunk) => {
|
|
@@ -112,6 +116,7 @@ export async function runHookConformanceBatch() {
|
|
|
112
116
|
finally {
|
|
113
117
|
process.stdout.write = originalStdoutWrite;
|
|
114
118
|
process.stderr.write = originalStderrWrite;
|
|
119
|
+
restoreGuardStderrCapture();
|
|
115
120
|
restoreEnv();
|
|
116
121
|
}
|
|
117
122
|
protocolWrite(`${JSON.stringify({ type: "result", id: row.id, stdout, stderr, exitCode })}\n`);
|
|
@@ -124,9 +124,9 @@ export interface ClaudeMcpDuplicateRegistrationOptions {
|
|
|
124
124
|
/**
|
|
125
125
|
* `claude-mcp-duplicate-registration` — advisory. A machine can register the
|
|
126
126
|
* webpresso MCP server twice for the same Claude Code session: a manual
|
|
127
|
-
* `claude mcp add webpresso` entry in
|
|
128
|
-
* project scope) plus the agent-kit marketplace plugin's bundled
|
|
129
|
-
*
|
|
127
|
+
* `claude mcp add webpresso` entry in Claude Code's home JSON config (user
|
|
128
|
+
* scope or a project scope) plus the agent-kit marketplace plugin's bundled
|
|
129
|
+
* server from the Claude plugin cache. Both spawn `wp mcp`, so affected
|
|
130
130
|
* sessions run two server processes and carry a duplicated wp_* tool list.
|
|
131
131
|
* Degrades to ok on missing/unreadable config — loud only on real duplication.
|
|
132
132
|
*/
|
package/dist/esm/hooks/doctor.js
CHANGED
|
@@ -658,11 +658,15 @@ function probeDecisionRow(wpCli, row) {
|
|
|
658
658
|
detached: process.platform !== "win32",
|
|
659
659
|
});
|
|
660
660
|
let stdout = "";
|
|
661
|
+
let stderr = "";
|
|
661
662
|
const timeoutMs = hookProbeTimeoutMs();
|
|
662
663
|
const settle = createOwnedProbeSettler(child, timeoutMs, () => ({ ok: false, detail: `decision probe timed out after ${timeoutMs}ms` }), resolve);
|
|
663
664
|
child.stdout.on("data", (chunk) => {
|
|
664
665
|
stdout += String(chunk);
|
|
665
666
|
});
|
|
667
|
+
child.stderr.on("data", (chunk) => {
|
|
668
|
+
stderr += String(chunk);
|
|
669
|
+
});
|
|
666
670
|
child.stdin.on?.("error", (err) => {
|
|
667
671
|
settle({ ok: false, detail: `stdin write failed: ${err.message}` });
|
|
668
672
|
});
|
|
@@ -674,7 +678,7 @@ function probeDecisionRow(wpCli, row) {
|
|
|
674
678
|
});
|
|
675
679
|
child.on("close", (code) => {
|
|
676
680
|
try {
|
|
677
|
-
assertConformance(row, { stdout, exitCode: code });
|
|
681
|
+
assertConformance(row, { stdout, stderr, exitCode: code });
|
|
678
682
|
settle({ ok: true });
|
|
679
683
|
}
|
|
680
684
|
catch (error) {
|
|
@@ -1256,13 +1260,15 @@ async function checkClaudeHost() {
|
|
|
1256
1260
|
}
|
|
1257
1261
|
async function checkGrokHost(cwd = process.cwd()) {
|
|
1258
1262
|
const available = await runCommand("grok", ["--version"]);
|
|
1259
|
-
const hooksPath = join(cwd, ".grok", "hooks.json");
|
|
1263
|
+
const hooksPath = join(cwd, ".grok", "hooks", "webpresso.json");
|
|
1260
1264
|
let hooksPresent = false;
|
|
1261
1265
|
let hostLabeled = false;
|
|
1262
1266
|
try {
|
|
1263
1267
|
const body = readFileSync(hooksPath, "utf8");
|
|
1264
1268
|
hooksPresent = true;
|
|
1265
|
-
|
|
1269
|
+
// The generated launcher chain shell-quotes the value (WP_HOOK_HOST='grok');
|
|
1270
|
+
// accept any quoting variant so the doctor recognizes its own output.
|
|
1271
|
+
hostLabeled = /WP_HOOK_HOST=(['"]?)grok\1/u.test(body);
|
|
1266
1272
|
}
|
|
1267
1273
|
catch {
|
|
1268
1274
|
// Missing project hooks is advisory when binary absent; fail when binary present.
|
|
@@ -1273,8 +1279,8 @@ async function checkGrokHost(cwd = process.cwd()) {
|
|
|
1273
1279
|
ok: true,
|
|
1274
1280
|
detail: hooksPresent
|
|
1275
1281
|
? hostLabeled
|
|
1276
|
-
? "skipped (grok not on PATH); native .grok/hooks.json present with WP_HOOK_HOST=grok"
|
|
1277
|
-
: "skipped (grok not on PATH); .grok/hooks.json present but missing WP_HOOK_HOST=grok"
|
|
1282
|
+
? "skipped (grok not on PATH); native .grok/hooks/webpresso.json present with WP_HOOK_HOST=grok"
|
|
1283
|
+
: "skipped (grok not on PATH); .grok/hooks/webpresso.json present but missing WP_HOOK_HOST=grok"
|
|
1278
1284
|
: "skipped (grok not on PATH)",
|
|
1279
1285
|
};
|
|
1280
1286
|
}
|
|
@@ -1282,20 +1288,20 @@ async function checkGrokHost(cwd = process.cwd()) {
|
|
|
1282
1288
|
return {
|
|
1283
1289
|
name: "Grok host integration",
|
|
1284
1290
|
ok: false,
|
|
1285
|
-
detail: "grok on PATH but missing project .grok/hooks.json — run wp setup to scaffold native hooks",
|
|
1291
|
+
detail: "grok on PATH but missing project .grok/hooks/webpresso.json — run wp setup to scaffold native hooks, then run /hooks-trust once in Grok",
|
|
1286
1292
|
};
|
|
1287
1293
|
}
|
|
1288
1294
|
if (!hostLabeled) {
|
|
1289
1295
|
return {
|
|
1290
1296
|
name: "Grok host integration",
|
|
1291
1297
|
ok: false,
|
|
1292
|
-
detail: ".grok/hooks.json present but managed commands lack WP_HOOK_HOST=grok",
|
|
1298
|
+
detail: ".grok/hooks/webpresso.json present but managed commands lack WP_HOOK_HOST=grok",
|
|
1293
1299
|
};
|
|
1294
1300
|
}
|
|
1295
1301
|
return {
|
|
1296
1302
|
name: "Grok host integration",
|
|
1297
1303
|
ok: true,
|
|
1298
|
-
detail: "native .grok/hooks.json with WP_HOOK_HOST=grok (PreToolUse fail-open residual applies)",
|
|
1304
|
+
detail: "native .grok/hooks/webpresso.json with WP_HOOK_HOST=grok (trust-gated: run /hooks-trust once; PreToolUse fail-open residual applies)",
|
|
1299
1305
|
};
|
|
1300
1306
|
}
|
|
1301
1307
|
// Markers for the direct hook commands `wp setup` writes into
|
|
@@ -1793,9 +1799,9 @@ export function checkProjectMcpPins(cwd = process.cwd(), deps = {}) {
|
|
|
1793
1799
|
/**
|
|
1794
1800
|
* `claude-mcp-duplicate-registration` — advisory. A machine can register the
|
|
1795
1801
|
* webpresso MCP server twice for the same Claude Code session: a manual
|
|
1796
|
-
* `claude mcp add webpresso` entry in
|
|
1797
|
-
* project scope) plus the agent-kit marketplace plugin's bundled
|
|
1798
|
-
*
|
|
1802
|
+
* `claude mcp add webpresso` entry in Claude Code's home JSON config (user
|
|
1803
|
+
* scope or a project scope) plus the agent-kit marketplace plugin's bundled
|
|
1804
|
+
* server from the Claude plugin cache. Both spawn `wp mcp`, so affected
|
|
1799
1805
|
* sessions run two server processes and carry a duplicated wp_* tool list.
|
|
1800
1806
|
* Degrades to ok on missing/unreadable config — loud only on real duplication.
|
|
1801
1807
|
*/
|
|
@@ -1810,17 +1816,17 @@ export function checkClaudeMcpDuplicateRegistration(options = {}) {
|
|
|
1810
1816
|
}
|
|
1811
1817
|
const claudeJsonPath = join(home, ".claude.json");
|
|
1812
1818
|
if (!exists(claudeJsonPath)) {
|
|
1813
|
-
return { name, ok: true, detail: "skipped (no
|
|
1819
|
+
return { name, ok: true, detail: "skipped (no Claude Code home JSON config)" };
|
|
1814
1820
|
}
|
|
1815
1821
|
let parsed;
|
|
1816
1822
|
try {
|
|
1817
1823
|
parsed = JSON.parse(readFile(claudeJsonPath));
|
|
1818
1824
|
}
|
|
1819
1825
|
catch {
|
|
1820
|
-
return { name, ok: true, detail: "skipped (
|
|
1826
|
+
return { name, ok: true, detail: "skipped (Claude Code home JSON config unreadable)" };
|
|
1821
1827
|
}
|
|
1822
1828
|
if (parsed === null || typeof parsed !== "object") {
|
|
1823
|
-
return { name, ok: true, detail: "skipped (
|
|
1829
|
+
return { name, ok: true, detail: "skipped (Claude Code home JSON config is not an object)" };
|
|
1824
1830
|
}
|
|
1825
1831
|
const config = parsed;
|
|
1826
1832
|
const manualSources = [];
|
|
@@ -1839,7 +1845,7 @@ export function checkClaudeMcpDuplicateRegistration(options = {}) {
|
|
|
1839
1845
|
name,
|
|
1840
1846
|
ok: false,
|
|
1841
1847
|
advisory: true,
|
|
1842
|
-
detail: `the agent-kit Claude plugin bundles the webpresso MCP server, but
|
|
1848
|
+
detail: `the agent-kit Claude plugin bundles the webpresso MCP server, but Claude Code's home JSON config also ` +
|
|
1843
1849
|
`registers "webpresso" manually (${manualSources.join(", ")}). Affected sessions run two ` +
|
|
1844
1850
|
`wp mcp processes with a duplicated wp_* tool list. Remove the manual entry: ` +
|
|
1845
1851
|
`claude mcp remove webpresso (run inside the project directory for project-scope entries).`,
|
|
@@ -2142,6 +2148,15 @@ export async function runHooksDoctor(opts = {}) {
|
|
|
2142
2148
|
detail: "claude required but not on PATH",
|
|
2143
2149
|
});
|
|
2144
2150
|
}
|
|
2151
|
+
if (host === "grok") {
|
|
2152
|
+
const available = await runCommand("grok", ["--version"]);
|
|
2153
|
+
if (!available.ok)
|
|
2154
|
+
checks.push({
|
|
2155
|
+
name: "Grok host integration",
|
|
2156
|
+
ok: false,
|
|
2157
|
+
detail: "grok required but not on PATH",
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2145
2160
|
}
|
|
2146
2161
|
}
|
|
2147
2162
|
checks.push(checkHooksManifest(opts.cwd));
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* Stdin: uses shared `readStdinJson` so conformance-batch can inject payloads via
|
|
10
10
|
* `WP_CONFORMANCE_STDIN` (same contract as other managed hooks).
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { formatGuardReason } from "#hooks/shared/guard-outcome";
|
|
13
|
+
import { readStdinJson, writeGuardStderr, writeHookOutput } from "#hooks/shared/hook-bootstrap";
|
|
13
14
|
import { buildPermissionRequestEnvelope } from "./envelope.js";
|
|
14
15
|
import { evaluatePermissionRequest } from "./policy.js";
|
|
15
16
|
function isRecord(value) {
|
|
@@ -53,9 +54,14 @@ export async function main() {
|
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
56
|
// Claude + Codex share the golden PermissionRequest wire shape
|
|
56
|
-
// (hookSpecificOutput.hookEventName + decision.behavior).
|
|
57
|
-
|
|
57
|
+
// (hookSpecificOutput.hookEventName + decision.behavior). The wire message
|
|
58
|
+
// carries the GUARD_* code so allow/deny decisions are keyable across hosts.
|
|
59
|
+
const codedMessage = formatGuardReason(result.code, result.reason);
|
|
60
|
+
writeHookOutput(JSON.stringify(buildPermissionRequestEnvelope(result.decision, codedMessage)));
|
|
58
61
|
if (result.decision === "deny") {
|
|
62
|
+
// A deny exits 2; deliver the coded message to the real stderr too so it is
|
|
63
|
+
// observable even when a host prefers the exit-code channel.
|
|
64
|
+
writeGuardStderr(`${codedMessage}\n`);
|
|
59
65
|
// Must use process.exit so runHookCommand's synthetic-exit trap records exit 2.
|
|
60
66
|
process.exit(2);
|
|
61
67
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* authoritative when policy is uncertain. Explicit deny only for high-confidence
|
|
6
6
|
* unsafe escalations; explicit allow only for clearly safe read-only escalations.
|
|
7
7
|
*/
|
|
8
|
+
import type { GuardReasonCode } from "#hooks/shared/guard-outcome";
|
|
8
9
|
export type PermissionRequestDecision = "allow" | "deny";
|
|
9
10
|
export type PermissionRequestPolicyInput = {
|
|
10
11
|
readonly toolName?: string;
|
|
@@ -15,13 +16,21 @@ export type PermissionRequestPolicyInput = {
|
|
|
15
16
|
export type PermissionRequestPolicyResult = {
|
|
16
17
|
readonly decision: "allow";
|
|
17
18
|
readonly reason: string;
|
|
19
|
+
readonly code: GuardReasonCode;
|
|
18
20
|
} | {
|
|
19
21
|
readonly decision: "deny";
|
|
20
22
|
readonly reason: string;
|
|
23
|
+
readonly code: GuardReasonCode;
|
|
21
24
|
} | {
|
|
22
25
|
readonly decision: undefined;
|
|
23
26
|
readonly reason: string;
|
|
27
|
+
readonly code: GuardReasonCode;
|
|
24
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Every GUARD_* code the permission-request policy can emit. Consumed by the
|
|
31
|
+
* guard-outcome registry-completeness test.
|
|
32
|
+
*/
|
|
33
|
+
export declare const PERMISSION_GUARD_CODES: readonly ["GUARD_PERMISSION_ALLOWED", "GUARD_PERMISSION_DENIED", "GUARD_HOST_DEFAULT"];
|
|
25
34
|
/**
|
|
26
35
|
* Decide allow / deny / pass-through for a PermissionRequest payload.
|
|
27
36
|
*/
|