vouchington-tooling 0.29.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -19
- package/bin/node-guard.mjs +9 -0
- package/bin/vouchington-mcp.mjs +20 -0
- package/bin/vouchington.mjs +18 -0
- package/dist/agent-blackboard/feedback-outbox-counts.d.mts +5 -0
- package/dist/agent-blackboard/feedback-outbox-counts.mjs +11 -0
- package/dist/agent-blackboard/feedback-outbox-directory.d.mts +2 -0
- package/dist/agent-blackboard/feedback-outbox-directory.mjs +16 -0
- package/dist/agent-blackboard/feedback-outbox.mjs +5 -7
- package/dist/agent-blackboard/index.d.mts +1 -0
- package/dist/agent-blackboard/index.mjs +1 -0
- package/dist/api-contract-discovery/header-contract-registry.mjs +2 -0
- package/dist/api-contract-discovery/protocol-body-status.d.mts +2 -0
- package/dist/api-contract-discovery/protocol-body-status.mjs +4 -0
- package/dist/api-contract-discovery/protocol-callback-argument-bindings.d.mts +7 -0
- package/dist/api-contract-discovery/protocol-callback-argument-bindings.mjs +33 -0
- package/dist/api-contract-discovery/protocol-callback-invocation.d.mts +5 -0
- package/dist/api-contract-discovery/protocol-callback-invocation.mjs +103 -0
- package/dist/api-contract-discovery/protocol-callback-mutations.d.mts +5 -0
- package/dist/api-contract-discovery/protocol-callback-mutations.mjs +42 -0
- package/dist/api-contract-discovery/protocol-callback-registration.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-callback-registration.mjs +27 -0
- package/dist/api-contract-discovery/protocol-callback-values.d.mts +17 -0
- package/dist/api-contract-discovery/protocol-callback-values.mjs +114 -0
- package/dist/api-contract-discovery/protocol-context-alias.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-context-alias.mjs +20 -0
- package/dist/api-contract-discovery/protocol-contract-extraction.d.mts +9 -0
- package/dist/api-contract-discovery/protocol-contract-extraction.mjs +87 -0
- package/dist/api-contract-discovery/protocol-contract-keys.d.mts +1 -0
- package/dist/api-contract-discovery/protocol-contract-keys.mjs +8 -0
- package/dist/api-contract-discovery/protocol-contract-registry.d.mts +5 -0
- package/dist/api-contract-discovery/protocol-contract-registry.mjs +133 -0
- package/dist/api-contract-discovery/protocol-executable-path.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-executable-path.mjs +64 -0
- package/dist/api-contract-discovery/protocol-execution-path.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-execution-path.mjs +16 -0
- package/dist/api-contract-discovery/protocol-http-association.d.mts +7 -0
- package/dist/api-contract-discovery/protocol-http-association.mjs +97 -0
- package/dist/api-contract-discovery/protocol-http-body-kinds.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-http-body-kinds.mjs +19 -0
- package/dist/api-contract-discovery/protocol-http-context-callers.d.mts +6 -0
- package/dist/api-contract-discovery/protocol-http-context-callers.mjs +34 -0
- package/dist/api-contract-discovery/protocol-http-context.d.mts +9 -0
- package/dist/api-contract-discovery/protocol-http-context.mjs +108 -0
- package/dist/api-contract-discovery/protocol-http-emission.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-http-emission.mjs +76 -0
- package/dist/api-contract-discovery/protocol-http-implicit-taint.d.mts +7 -0
- package/dist/api-contract-discovery/protocol-http-implicit-taint.mjs +26 -0
- package/dist/api-contract-discovery/protocol-http-registration.d.mts +12 -0
- package/dist/api-contract-discovery/protocol-http-registration.mjs +53 -0
- package/dist/api-contract-discovery/protocol-marker-analysis.d.mts +7 -0
- package/dist/api-contract-discovery/protocol-marker-analysis.mjs +50 -0
- package/dist/api-contract-discovery/protocol-opaque-callback.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-opaque-callback.mjs +107 -0
- package/dist/api-contract-discovery/protocol-platform-callbacks.d.mts +5 -0
- package/dist/api-contract-discovery/protocol-platform-callbacks.mjs +72 -0
- package/dist/api-contract-discovery/protocol-platform-mutation-targets.d.mts +5 -0
- package/dist/api-contract-discovery/protocol-platform-mutation-targets.mjs +89 -0
- package/dist/api-contract-discovery/protocol-platform-writes.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-platform-writes.mjs +92 -0
- package/dist/api-contract-discovery/protocol-requested-keys.d.mts +5 -0
- package/dist/api-contract-discovery/protocol-requested-keys.mjs +45 -0
- package/dist/api-contract-discovery/protocol-sse-callers.d.mts +7 -0
- package/dist/api-contract-discovery/protocol-sse-callers.mjs +67 -0
- package/dist/api-contract-discovery/protocol-sse-emission.d.mts +11 -0
- package/dist/api-contract-discovery/protocol-sse-emission.mjs +61 -0
- package/dist/api-contract-discovery/protocol-sse-feasible-status.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-sse-feasible-status.mjs +24 -0
- package/dist/api-contract-discovery/protocol-sse-raw-writes.d.mts +9 -0
- package/dist/api-contract-discovery/protocol-sse-raw-writes.mjs +70 -0
- package/dist/api-contract-discovery/protocol-sse-status.d.mts +3 -0
- package/dist/api-contract-discovery/protocol-sse-status.mjs +84 -0
- package/dist/api-contract-discovery/protocol-sse-write-access.d.mts +9 -0
- package/dist/api-contract-discovery/protocol-sse-write-access.mjs +42 -0
- package/dist/api-contract-discovery/protocol-sse-write-helpers.d.mts +6 -0
- package/dist/api-contract-discovery/protocol-sse-write-helpers.mjs +66 -0
- package/dist/api-contract-discovery/protocol-sse-write-mutations.d.mts +9 -0
- package/dist/api-contract-discovery/protocol-sse-write-mutations.mjs +36 -0
- package/dist/api-contract-discovery/protocol-sse-write-resolution.d.mts +14 -0
- package/dist/api-contract-discovery/protocol-sse-write-resolution.mjs +79 -0
- package/dist/api-contract-discovery/protocol-status-dominance.d.mts +5 -0
- package/dist/api-contract-discovery/protocol-status-dominance.mjs +35 -0
- package/dist/api-contract-discovery/protocol-write-receiver.d.mts +9 -0
- package/dist/api-contract-discovery/protocol-write-receiver.mjs +79 -0
- package/dist/api-contract-discovery/query-contract-registry.mjs +2 -0
- package/dist/api-contract-discovery/registered-route-binding-writes.d.mts +3 -0
- package/dist/api-contract-discovery/registered-route-binding-writes.mjs +30 -0
- package/dist/api-contract-discovery/registered-route-catalog.mjs +11 -7
- package/dist/api-contract-discovery/registered-route-factory-returns.d.mts +3 -0
- package/dist/api-contract-discovery/registered-route-factory-returns.mjs +29 -0
- package/dist/api-contract-discovery/registered-route-handler-analysis.d.mts +5 -1
- package/dist/api-contract-discovery/registered-route-handler-analysis.mjs +79 -35
- package/dist/api-contract-discovery/registered-route-runtime-parameters.d.mts +3 -0
- package/dist/api-contract-discovery/registered-route-runtime-parameters.mjs +5 -0
- package/dist/api-contract-discovery/registered-route-terminal-error.d.mts +3 -0
- package/dist/api-contract-discovery/registered-route-terminal-error.mjs +98 -0
- package/dist/api-contract-discovery/request-contract-registry.mjs +2 -0
- package/dist/api-contract-discovery/response-contract-implicit.mjs +28 -10
- package/dist/api-contract-discovery/response-contract-registry.mjs +14 -1
- package/dist/api-contract-discovery/response-contract-route-analysis.d.mts +1 -1
- package/dist/api-contract-discovery/response-contract-route-analysis.mjs +22 -4
- package/dist/api-contract-discovery/response-contract-status.d.mts +1 -1
- package/dist/api-contract-discovery/response-contract-status.mjs +10 -8
- package/dist/api-contract-discovery/response-contract-types.d.mts +7 -0
- package/dist/cli/commands/agent-blackboard-flags.d.mts +4 -0
- package/dist/cli/commands/agent-blackboard-flags.mjs +34 -0
- package/dist/cli/commands/agent-blackboard.mjs +27 -35
- package/dist/cli/index.d.mts +2 -0
- package/dist/cli/index.mjs +12 -15
- package/dist/cli/parse-forwarded-commands.d.mts +0 -3
- package/dist/cli/parse-forwarded-commands.mjs +0 -2
- package/dist/cli/parse.d.mts +0 -3
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +2 -6
- package/dist/contract-schema/contract-schema-bounded-array.d.mts +1 -3
- package/dist/contract-schema/contract-schema-bounded-array.mjs +5 -0
- package/dist/contract-schema/contract-schema-object-tuple.mjs +7 -5
- package/dist/contract-schema/contract-schema-type-extractor.mjs +13 -0
- package/dist/contract-schema/contract-schema-validator.mjs +2 -2
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +0 -1
- package/dist/mcp-server/dispatch.d.mts +4 -1
- package/dist/mcp-server/dispatch.mjs +6 -4
- package/dist/mcp-server/handlers-outbox.mjs +2 -7
- package/dist/mcp-server/harness.test-helpers.d.mts +1 -0
- package/dist/mcp-server/harness.test-helpers.mjs +1 -1
- package/dist/mcp-server/main.d.mts +5 -0
- package/dist/mcp-server/main.mjs +8 -0
- package/dist/mcp-server/run.d.mts +2 -0
- package/dist/mcp-server/run.mjs +4 -1
- package/dist/mcp-server/sdk.d.mts +11 -2
- package/dist/mcp-server/sdk.mjs +37 -5
- package/dist/mcp-server/server.mjs +3 -2
- package/dist/mcp-server/tools.mjs +3 -2
- package/dist/mcp-server/worktree.d.mts +17 -10
- package/dist/mcp-server/worktree.mjs +48 -31
- package/dist/openapi-document/build-openapi-catalog-sse.d.mts +4 -0
- package/dist/openapi-document/build-openapi-catalog-sse.mjs +27 -0
- package/dist/openapi-document/build-openapi-document.mjs +5 -2
- package/dist/openapi-document/build-openapi-response.d.mts +2 -2
- package/dist/openapi-document/build-openapi-response.mjs +33 -3
- package/dist/openapi-document/build-openapi-sse-events.d.mts +11 -0
- package/dist/openapi-document/build-openapi-sse-events.mjs +46 -0
- package/dist/openapi-document/contract-schema-intersection-merge.mjs +11 -11
- package/dist/openapi-document/contract-schema-to-openapi.mjs +3 -3
- package/dist/openapi-document/openapi-route-helpers.mjs +1 -3
- package/dist/openapi-document/openapi-types.d.mts +3 -0
- package/dist/openapi-document/operation-types.d.mts +7 -0
- package/docs/mcp-server.md +83 -25
- package/package.json +11 -9
- package/scripts/build.mjs +2 -0
- package/skills/blackboard/SKILL.md +66 -4
- package/skills/manifest.json +19 -19
- package/dist/agent-harness-config/apply.d.mts +0 -4
- package/dist/agent-harness-config/apply.mjs +0 -72
- package/dist/agent-harness-config/cli.d.mts +0 -10
- package/dist/agent-harness-config/cli.mjs +0 -100
- package/dist/agent-harness-config/index.d.mts +0 -4
- package/dist/agent-harness-config/index.mjs +0 -3
- package/dist/agent-harness-config/merge-json.d.mts +0 -5
- package/dist/agent-harness-config/merge-json.mjs +0 -62
- package/dist/agent-harness-config/merge-toml.d.mts +0 -6
- package/dist/agent-harness-config/merge-toml.mjs +0 -132
- package/dist/agent-harness-config/paths.d.mts +0 -3
- package/dist/agent-harness-config/paths.mjs +0 -117
- package/dist/agent-harness-config/policy.d.mts +0 -14
- package/dist/agent-harness-config/policy.mjs +0 -51
- package/dist/agent-harness-config/prerequisites.d.mts +0 -2
- package/dist/agent-harness-config/prerequisites.mjs +0 -67
- package/dist/agent-harness-config/toml-value.d.mts +0 -6
- package/dist/agent-harness-config/toml-value.mjs +0 -69
- package/dist/agent-harness-config/types.d.mts +0 -90
- package/dist/agent-harness-config/types.mjs +0 -2
- package/docs/agent-harness-config.md +0 -134
package/dist/cli/usage.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n
|
|
1
|
+
export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n gha-runtime-audit Audit successful GitHub Actions job runtimes\n require-up-to-date Require HEAD to include a fetched remote branch\n gitleaks-directory-scan Scan a directory with Gitleaks\n ast-grep-examples Run AST-grep rule examples\n ast-grep-pack Print shipped unconditional AST-grep pack paths as JSON\n gha-workspace-policy Check GitHub Actions workspace safety policy\n gha-output Write a collision-safe multiline GITHUB_OUTPUT record\n gha-needs-results Fail if required GitHub Actions job results failed\n download-with-diagnostics Download a URL and report HTTP status on failure\n download-optional-run-artifacts Download optional artifacts from the current run\n host-pressure-diagnostics Print a bounded host memory/OOM/PSI snapshot\n allocate-browser-safe-ports Allocate Fetch-safe localhost ports\n diagnose-port-collision Capture bounded localhost port diagnostics\n prepare-trivy-db Download the Trivy vulnerability database\n gha-artifacts-cleanup Delete classified GitHub Actions artifacts\n http-origin Validate an optional HTTP(S) origin\n vitest-blob-manifest Stamp a vitest-blob-manifest:v1 identity file\n vitest-report-attempt Write or read a Vitest report-attempt marker\n prepare-vitest-reports Validate and select Vitest report JSON files\n pnpm-install Install a pnpm workspace with retry and release-age fail-fast\n check-cache-size Measure a path and decide whether to save a GHA cache\n make-shard-matrix Emit a [1..N] GitHub Actions shard matrix\n load-runner-env Overlay a runner env file onto GITHUB_ENV with injection guards\n clean-workspace Reset a persistent-runner workspace with a fork-PR trust gate\n install-github-release Download a checksum-verified GitHub Release binary\n run-with-timeout Run a command with GNU timeout or a Perl fallback\n lint-links Two-pass lychee: internal links fail, external warn\n materialize-pr-context Dump PR title/body/files/diff/comments and #N crawl\n wait-for-apt-locks Wait until apt/dpkg lock files are free\n install-playwright-chromium-arm64 Install Playwright Chromium from browsers.json\n ghcr-package-retention Delete old GHCR package versions past KEEP_MIN\n harness-admission-lane Compute a GITHUB_RUN_ID admission lane for fleet fan-out\n harness-assert-gates Fail if any named HARNESS_*_ENABLED gate is enabled\n gha-collaborator-trust Classify authors as write-access collaborators or not\n nuget-central-version Validate a Directory.Packages.props PackageVersion delta\n swift-semantic-equal Compare Swift sources ignoring comments and whitespace\n post-review Post one COMMENT review from a staged payload file\n stage-review-payload Validate a review payload file into a staging directory\n retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts\n link-skill Link one packaged skill into an explicit consumer directory\n retrospective-facts Gather immutable facts for a retrospective\n agent-blackboard Probe and journal an Agent Blackboard deployment\n mcp Serve the agent-blackboard journal tools over stdio (MCP)\n\nOptions:\n -h, --help Show this help\n -v, --version Print the package version\n\nrunner-port-policy\n (no args) Print the shipped policy as JSON\n --file <path> Validate and print a policy file\n --reserved <port> Print true if the port is reserved\n\nwith-host-lock\n --name <family>\n [--slots <n>]\n --timeout-seconds <n>\n [--command-timeout-seconds <n>]\n [--failure-diagnostics <absolute-script>]\n [--on-acquire-timeout fail|run-unlocked]\n -- <command> [args...]\n\ngha-runtime-audit\n [--repository owner/name] Default GITHUB_REPOSITORY\n [--branch main]\n [--median-threshold-floor <seconds>] Off unless set. Must be below the ceiling\n [--median-threshold-ceiling <seconds>] Default 360. Flags a five-sample median above this\n --pr-workflow <name|/regex/> Repeatable\n --push-workflow <name|/regex/> Repeatable\n\nrequire-up-to-date --remote <name> --branch <name>\ngitleaks-directory-scan --config <path> [--directory <path>]\nast-grep-examples --rules <directory> --config <path>\nast-grep-pack\ngha-workspace-policy [--root <directory>] [--workflow-directory <directory>] [--action-directory <directory>]\n\ngha-output <name>\ngha-needs-results [label]\ndownload-with-diagnostics <url> <destination> [-- curl-args...]\ndownload-optional-run-artifacts (--name <name>... | --pattern <pattern>) --dir <directory>\nhost-pressure-diagnostics\nallocate-browser-safe-ports <count> [--policy path] [--forbidden-ports path]\ndiagnose-port-collision [--ports \"2200 2216\"] [--output-dir PATH]\nprepare-trivy-db\ngha-artifacts-cleanup run --run-id <id> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\ngha-artifacts-cleanup sweep --older-than-hours <n> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\nhttp-origin [--field NAME] [value]\nvitest-blob-manifest <suite> [reports-directory]\nvitest-report-attempt <write DIRECTORY SUITE|read ROOT>\nprepare-vitest-reports [primary-directory] [fallback-directory] [output-directory]\npnpm-install --runner-lifecycle persistent|ephemeral|ephemeral-full --install-scripts true|false\ncheck-cache-size <path> <max-bytes> <label>\nmake-shard-matrix <total>\nload-runner-env\nclean-workspace\ninstall-github-release --repo owner/name --version X --asset 'name-{platform}.tar.gz' --bin name [--tag-prefix PREFIX] [--expected-sha256 SHA256] [--no-checksum] [--checksums-asset NAME] [--version-flag FLAG] [--bin-dir DIR]\nrun-with-timeout <timeout-seconds> <kill-after-seconds> <command...>\nlint-links [--offline] [--config PATH] [--glob PATTERN] [files...]\nmaterialize-pr-context\nwait-for-apt-locks\ninstall-playwright-chromium-arm64 [name:archive...]\nghcr-package-retention <url-encoded-package>...\nharness-admission-lane <lanes>\nharness-assert-gates <gate>...\ngha-collaborator-trust <owner/repo> [--allow-bot <login>]... < authors.json\nnuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-props>\nswift-semantic-equal <base> <head> <file.swift>\npost-review\nstage-review-payload optional|required <source> <destination>\nretrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]\nlink-skill <name> --source-root <skills-dir> --target-root <consumer-skills-dir> Link a packaged or repository-local skill\nretrospective-facts (--pr NUMBER | --branch NAME | --no-pr) [--repo OWNER/NAME] [--raw]\nagent-blackboard probe\nagent-blackboard journal append --mode interactive|autonomous --source-event-id ID --work-outcome OUTCOME --coverage-status STATUS --session-id UUID --agent NAME --version VERSION --file PATH --repository OWNER/NAME [--repository OWNER/NAME ...] [--parent-session-id UUID] [--timestamp ISO8601] [--coverage-source SOURCE,...] [--dropped-count N] [--outbox-directory PATH]\nagent-blackboard journal entries --session-id UUID\nagent-blackboard journal status --session-id UUID --outbox-directory PATH\nagent-blackboard journal flush --outbox-directory PATH [--session-id UUID]\nInteractive journal append requires --outbox-directory PATH.\nagent-blackboard snapshot partition --snapshot PATH --checksum SHA256 --counts '{\"sessions\":N,\"entries\":N,\"records\":N,\"bytes\":N}'\nagent-blackboard snapshot cleanup [--snapshot PATH] [--partition-directory PATH --receipt JSON]\nmcp\n (no args) Serve journal_append, journal_entries, outbox_status, outbox_flush,\n session_ensure, snapshot_export, and session_archive over stdio.\n Needs the optional @modelcontextprotocol/sdk peer (and zod).\n Launch it from inside the repository's git worktree.\n";
|
|
2
2
|
export declare function printUsage(stream?: NodeJS.WritableStream): void;
|
|
3
3
|
export declare function commandNames(usage?: string): string[];
|
|
4
4
|
export declare function commandUsage(command: string, usage?: string): string;
|
package/dist/cli/usage.mjs
CHANGED
|
@@ -3,7 +3,6 @@ export const USAGE = `Usage: vouchington <command> [options]
|
|
|
3
3
|
Commands:
|
|
4
4
|
runner-port-policy Print or validate a runner port policy
|
|
5
5
|
with-host-lock Run a command under a host-wide lock
|
|
6
|
-
agent-harness-config Apply classifier-auto + sandbox keys to agent harnesses
|
|
7
6
|
gha-runtime-audit Audit successful GitHub Actions job runtimes
|
|
8
7
|
require-up-to-date Require HEAD to include a fetched remote branch
|
|
9
8
|
gitleaks-directory-scan Scan a directory with Gitleaks
|
|
@@ -66,10 +65,6 @@ with-host-lock
|
|
|
66
65
|
[--on-acquire-timeout fail|run-unlocked]
|
|
67
66
|
-- <command> [args...]
|
|
68
67
|
|
|
69
|
-
agent-harness-config dump
|
|
70
|
-
agent-harness-config check|apply [--global] [--repo PATH]... [--harness claude|codex|grok|cursor]...
|
|
71
|
-
[--home PATH]
|
|
72
|
-
|
|
73
68
|
gha-runtime-audit
|
|
74
69
|
[--repository owner/name] Default GITHUB_REPOSITORY
|
|
75
70
|
[--branch main]
|
|
@@ -123,7 +118,8 @@ retrospective-facts (--pr NUMBER | --branch NAME | --no-pr) [--repo OWNER/NAME]
|
|
|
123
118
|
agent-blackboard probe
|
|
124
119
|
agent-blackboard journal append --mode interactive|autonomous --source-event-id ID --work-outcome OUTCOME --coverage-status STATUS --session-id UUID --agent NAME --version VERSION --file PATH --repository OWNER/NAME [--repository OWNER/NAME ...] [--parent-session-id UUID] [--timestamp ISO8601] [--coverage-source SOURCE,...] [--dropped-count N] [--outbox-directory PATH]
|
|
125
120
|
agent-blackboard journal entries --session-id UUID
|
|
126
|
-
agent-blackboard journal
|
|
121
|
+
agent-blackboard journal status --session-id UUID --outbox-directory PATH
|
|
122
|
+
agent-blackboard journal flush --outbox-directory PATH [--session-id UUID]
|
|
127
123
|
Interactive journal append requires --outbox-directory PATH.
|
|
128
124
|
agent-blackboard snapshot partition --snapshot PATH --checksum SHA256 --counts '{"sessions":N,"entries":N,"records":N,"bytes":N}'
|
|
129
125
|
agent-blackboard snapshot cleanup [--snapshot PATH] [--partition-directory PATH --receipt JSON]
|
|
@@ -9,7 +9,5 @@ export type ExtractionContext = {
|
|
|
9
9
|
options: ExtractContractSchemaOptions;
|
|
10
10
|
};
|
|
11
11
|
type SchemaForType = (type: ts.Type, context: ExtractionContext) => ContractSchemaNode;
|
|
12
|
-
export declare function boundedArraySchema(type: ts.Type, context: ExtractionContext, schemaForType: SchemaForType):
|
|
13
|
-
type: 'array';
|
|
14
|
-
}> | undefined;
|
|
12
|
+
export declare function boundedArraySchema(type: ts.Type, context: ExtractionContext, schemaForType: SchemaForType): ContractSchemaNode | undefined;
|
|
15
13
|
export {};
|
|
@@ -16,6 +16,11 @@ export function boundedArraySchema(type, context, schemaForType) {
|
|
|
16
16
|
if (!(uniqueItemsType.flags & ts.TypeFlags.BooleanLiteral)) {
|
|
17
17
|
throw unsupportedType(type, context.checker, `${alias} uniqueness must be literal`);
|
|
18
18
|
}
|
|
19
|
+
if (itemType.flags & ts.TypeFlags.Never) {
|
|
20
|
+
if (minItems !== 0)
|
|
21
|
+
throw unsupportedType(type, context.checker, `${alias} has impossible never element bounds`);
|
|
22
|
+
return { type: 'tuple', items: [], optionalItems: 0 };
|
|
23
|
+
}
|
|
19
24
|
return {
|
|
20
25
|
type: 'array',
|
|
21
26
|
items: schemaForType(itemType, context),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ts from './typescript-api.mjs';
|
|
2
2
|
import { compareSymbols } from './contract-schema-type-utils.mjs';
|
|
3
3
|
export function objectSchema(type, context, schemaForType) {
|
|
4
|
-
const properties =
|
|
4
|
+
const properties = new Map();
|
|
5
5
|
for (const property of context.checker.getPropertiesOfType(type).toSorted(compareSymbols)) {
|
|
6
6
|
const declaration = property.valueDeclaration;
|
|
7
7
|
/* v8 ignore start */
|
|
@@ -12,10 +12,10 @@ export function objectSchema(type, context, schemaForType) {
|
|
|
12
12
|
throw new Error(`Property "${property.name}" has no type`);
|
|
13
13
|
/* v8 ignore stop */
|
|
14
14
|
try {
|
|
15
|
-
properties
|
|
15
|
+
properties.set(property.name, {
|
|
16
16
|
required: !(property.flags & ts.SymbolFlags.Optional),
|
|
17
17
|
schema: schemaForType(propertyType, context),
|
|
18
|
-
};
|
|
18
|
+
});
|
|
19
19
|
}
|
|
20
20
|
catch (error) {
|
|
21
21
|
throw new Error(`Property "${property.name}": ${error.message}`, { cause: error });
|
|
@@ -24,8 +24,10 @@ export function objectSchema(type, context, schemaForType) {
|
|
|
24
24
|
const stringIndex = context.checker.getIndexInfoOfType(type, ts.IndexKind.String);
|
|
25
25
|
return {
|
|
26
26
|
type: 'object',
|
|
27
|
-
properties,
|
|
28
|
-
additionalProperties: stringIndex
|
|
27
|
+
properties: Object.fromEntries(properties),
|
|
28
|
+
additionalProperties: stringIndex && !(stringIndex.type.flags & ts.TypeFlags.Never)
|
|
29
|
+
? schemaForType(stringIndex.type, context)
|
|
30
|
+
: false,
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
/* v8 ignore start -- checker internal used only for compiler-synthesized properties */
|
|
@@ -80,6 +80,17 @@ function schemaForType(type, context) {
|
|
|
80
80
|
return buildUnion();
|
|
81
81
|
}
|
|
82
82
|
if (type.isIntersection()) {
|
|
83
|
+
const index = checker.getIndexTypeOfType(type, ts.IndexKind.String);
|
|
84
|
+
const properties = checker.getPropertiesOfType(type);
|
|
85
|
+
if (index && index.flags & ts.TypeFlags.Never && properties.length > 0) {
|
|
86
|
+
if (properties.some((property) => !(property.flags & ts.SymbolFlags.Optional)))
|
|
87
|
+
throw unsupportedType(type, checker, 'never string index conflicts with named properties');
|
|
88
|
+
if (checker.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0)
|
|
89
|
+
throw unsupportedType(type, checker, 'callable types are not supported');
|
|
90
|
+
if (checker.getSignaturesOfType(type, ts.SignatureKind.Construct).length > 0)
|
|
91
|
+
throw unsupportedType(type, checker, 'constructable types are not supported');
|
|
92
|
+
return { type: 'object', properties: {}, additionalProperties: false };
|
|
93
|
+
}
|
|
83
94
|
return {
|
|
84
95
|
type: 'intersection',
|
|
85
96
|
variants: distinctNodes(type.types.map((variant) => schemaForType(variant, context))),
|
|
@@ -104,6 +115,8 @@ function schemaForType(type, context) {
|
|
|
104
115
|
/* v8 ignore next */
|
|
105
116
|
if (!typeArguments[0])
|
|
106
117
|
throw unsupportedType(type, checker, 'array element type is missing');
|
|
118
|
+
if (typeArguments[0].flags & ts.TypeFlags.Never)
|
|
119
|
+
return { type: 'tuple', items: [], optionalItems: 0 };
|
|
107
120
|
return { type: 'array', items: schemaForType(typeArguments[0], context) };
|
|
108
121
|
}
|
|
109
122
|
if (checker.getSignaturesOfType(type, ts.SignatureKind.Call).length > 0) {
|
|
@@ -66,7 +66,7 @@ function validateObject(node, value, path, context, checkUnexpected) {
|
|
|
66
66
|
if (!isObject(value))
|
|
67
67
|
return requireType(false, 'object', value, path, context);
|
|
68
68
|
for (const [key, property] of Object.entries(node.properties)) {
|
|
69
|
-
if (!(key
|
|
69
|
+
if (!Object.hasOwn(value, key)) {
|
|
70
70
|
if (property.required) {
|
|
71
71
|
addIssue(context, propertyPath(path, key), 'missing-required', 'Required field is missing');
|
|
72
72
|
}
|
|
@@ -77,7 +77,7 @@ function validateObject(node, value, path, context, checkUnexpected) {
|
|
|
77
77
|
if (!checkUnexpected)
|
|
78
78
|
return;
|
|
79
79
|
for (const [key, nested] of Object.entries(value)) {
|
|
80
|
-
if (
|
|
80
|
+
if (Object.hasOwn(node.properties, key))
|
|
81
81
|
continue;
|
|
82
82
|
if (node.additionalProperties === false) {
|
|
83
83
|
addUnexpectedIssue(context, propertyPath(path, key));
|
package/dist/index.d.mts
CHANGED
|
@@ -15,8 +15,6 @@ export type { EphemeralListenerOptions, RunnerPortPolicy } from './runner-port-p
|
|
|
15
15
|
export { extractAlterTableAddColumnLocations, extractCreateIndexMetadata, extractCreateTableMetadata, extractDefaultFunction, extractDropIndexMetadata, extractFuncCallArgColumnNames, extractMigrationConstraintMetadata, initSqlAst, lineOfUtf8ByteOffset, MissingSqlAstParserError, parseSql, } from './sql-ast/index.mts';
|
|
16
16
|
export type { ForeignKey, SqlCreateIndexMetadata, SqlCreateTableColumn, SqlCreateTableMetadata, SqlDropIndexMetadata, SqlIndexParam, SqlMigrationConstraintMetadata, } from './sql-ast/index.mts';
|
|
17
17
|
export { dollarQuoteEnd, lineOf, maskSqlQuotedText, readDollarQuoteDelimiter, readStringLiteral, splitSqlStatements, sqlFragments, stripSqlComments, } from './sql-scanner/index.mts';
|
|
18
|
-
export { applyHarnessConfig, checkHarnessConfig, dumpHarnessPolicy, planHarnessConfig, DEFAULT_EXTRA_WRITABLE_ROOTS, } from './agent-harness-config/index.mts';
|
|
19
|
-
export type { ApplyTarget, FilePlan, FileResult, HarnessApplyResult, HarnessCheckResult, HarnessConfigOptions, HarnessId, HarnessPlan, HarnessPolicyDump, JsonPatch, KeyDrift, TomlPatch, TomlValue, } from './agent-harness-config/index.mts';
|
|
20
18
|
export { auditCiJobRuntime, parseWorkflowNameMatch } from './gha-runtime-audit/index.mts';
|
|
21
19
|
export type { GhApiExecutor, RuntimeAuditOptions, RuntimeAuditResult, RuntimeAuditWorkflowFilter, RuntimeJobResult, RuntimeSample, } from './gha-runtime-audit/index.mts';
|
|
22
20
|
export { checkGhaWorkspacePolicy } from './gha-workspace-policy/index.mts';
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,6 @@ export { buildSessionFrictionReport, classifyFrictionObservation, FRICTION_LOG_M
|
|
|
8
8
|
export { EphemeralListenerAttemptsExhaustedError, isRunnerReservedPort, listenOnRunnerUnreservedEphemeralPort, loadRunnerPortPolicy, runnerPortPolicy, validateRunnerPortPolicy, } from './runner-port-policy/index.mjs';
|
|
9
9
|
export { extractAlterTableAddColumnLocations, extractCreateIndexMetadata, extractCreateTableMetadata, extractDefaultFunction, extractDropIndexMetadata, extractFuncCallArgColumnNames, extractMigrationConstraintMetadata, initSqlAst, lineOfUtf8ByteOffset, MissingSqlAstParserError, parseSql, } from './sql-ast/index.mjs';
|
|
10
10
|
export { dollarQuoteEnd, lineOf, maskSqlQuotedText, readDollarQuoteDelimiter, readStringLiteral, splitSqlStatements, sqlFragments, stripSqlComments, } from './sql-scanner/index.mjs';
|
|
11
|
-
export { applyHarnessConfig, checkHarnessConfig, dumpHarnessPolicy, planHarnessConfig, DEFAULT_EXTRA_WRITABLE_ROOTS, } from './agent-harness-config/index.mjs';
|
|
12
11
|
export { auditCiJobRuntime, parseWorkflowNameMatch } from './gha-runtime-audit/index.mjs';
|
|
13
12
|
export { checkGhaWorkspacePolicy } from './gha-workspace-policy/index.mjs';
|
|
14
13
|
export { requireUpToDate } from './require-up-to-date/index.mjs';
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { BlackboardClientDependencies } from '../agent-blackboard/client.mts';
|
|
2
2
|
import type { RunTextCommand } from '../gh-cli/exec.mts';
|
|
3
3
|
export type ServerEnvironment = {
|
|
4
|
-
|
|
4
|
+
/** The launch directory's worktree top level, or undefined when it is not inside one. */
|
|
5
|
+
launchRoot: string | undefined;
|
|
5
6
|
env: NodeJS.ProcessEnv;
|
|
6
7
|
runGit: RunTextCommand;
|
|
8
|
+
/** Test seam: where `agent-blackboard` resolves from. Defaults to this package's own module. */
|
|
9
|
+
resolveFrom?: string | URL;
|
|
7
10
|
/** Test seam: replaces how the consumer's `agent-blackboard` client is loaded. */
|
|
8
11
|
blackboard?: BlackboardClientDependencies;
|
|
9
12
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { join } from 'node:path';
|
|
2
1
|
import { FeedbackDeliveryError } from '../agent-blackboard/index.mjs';
|
|
3
2
|
import { optionalString, rejectUnknown, requireObject } from './args.mjs';
|
|
4
3
|
import { readSessionId } from './context.mjs';
|
|
@@ -23,7 +22,7 @@ const DIAGNOSTIC_HINTS = {
|
|
|
23
22
|
'authentication-rejected': 'the blackboard rejected AGENT_BLACKBOARD_TOKEN',
|
|
24
23
|
'blackboard-unavailable': 'the blackboard could not be reached or returned an error',
|
|
25
24
|
'configuration-invalid': 'AGENT_BLACKBOARD_URL or AGENT_BLACKBOARD_TOKEN is missing or invalid',
|
|
26
|
-
'client-unavailable': 'agent-blackboard is not installed
|
|
25
|
+
'client-unavailable': 'agent-blackboard is not installed next to vouchington-tooling',
|
|
27
26
|
'readback-unconfirmed': 'the write could not be confirmed; retry the same call (same sourceEventId and content)',
|
|
28
27
|
'delivery-timeout': 'delivery timed out; retry the same call (same sourceEventId and content)',
|
|
29
28
|
};
|
|
@@ -52,8 +51,11 @@ export async function callTool(name, rawArguments, environment) {
|
|
|
52
51
|
sessionId,
|
|
53
52
|
worktree,
|
|
54
53
|
env: environment.env,
|
|
55
|
-
// The client resolves from
|
|
56
|
-
dependencies: {
|
|
54
|
+
// The client resolves from this package's install, like the SDK, never from the worktree.
|
|
55
|
+
dependencies: {
|
|
56
|
+
...environment.blackboard,
|
|
57
|
+
resolveFrom: environment.resolveFrom ?? import.meta.url,
|
|
58
|
+
},
|
|
57
59
|
});
|
|
58
60
|
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
59
61
|
}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import { flushFeedbackOutbox,
|
|
1
|
+
import { flushFeedbackOutbox, feedbackOutboxCounts } from '../agent-blackboard/index.mjs';
|
|
2
2
|
import { outboxDirectory } from './context.mjs';
|
|
3
3
|
/**
|
|
4
4
|
* The outbox belongs to the worktree, not to one session, so two counts are reported. `pendingCount`
|
|
5
5
|
* is the caller's session only; `worktreePendingCount` is every session's records.
|
|
6
6
|
*/
|
|
7
7
|
export function outboxCounts(worktree, sessionId) {
|
|
8
|
-
|
|
9
|
-
const records = readFeedbackOutbox(outboxDirectory(worktree));
|
|
10
|
-
return {
|
|
11
|
-
pendingCount: records.filter((record) => record.identity.sessionId === sessionId).length,
|
|
12
|
-
worktreePendingCount: records.length,
|
|
13
|
-
};
|
|
8
|
+
return feedbackOutboxCounts(outboxDirectory(worktree), sessionId);
|
|
14
9
|
}
|
|
15
10
|
function sessionStatus(pendingCount) {
|
|
16
11
|
return pendingCount === 0 ? 'empty' : 'pending';
|
|
@@ -11,6 +11,7 @@ export type Harness = {
|
|
|
11
11
|
/** Calls tools against a repository fixture with the blackboard client faked. */
|
|
12
12
|
export declare function harness(fixture: RepoFixture, options?: FakeOptions & {
|
|
13
13
|
env?: NodeJS.ProcessEnv;
|
|
14
|
+
launchRoot?: string | undefined;
|
|
14
15
|
}): Harness;
|
|
15
16
|
export declare function textOf(result: ToolCallResult): string;
|
|
16
17
|
export declare function jsonOf(result: ToolCallResult): Record<string, unknown>;
|
|
@@ -20,7 +20,7 @@ export function outboxPath(worktree) {
|
|
|
20
20
|
export function harness(fixture, options = {}) {
|
|
21
21
|
const fake = fakeBlackboard(options);
|
|
22
22
|
const environment = {
|
|
23
|
-
launchRoot: fixture.main,
|
|
23
|
+
launchRoot: 'launchRoot' in options ? options.launchRoot : fixture.main,
|
|
24
24
|
env: options.env ?? BLACKBOARD_ENV,
|
|
25
25
|
runGit: runIsolatedGit,
|
|
26
26
|
blackboard: fake.dependencies,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { runMcpCommand } from '../cli/commands/mcp.mjs';
|
|
2
|
+
/**
|
|
3
|
+
* Entry of `bin/vouchington-mcp.mjs`: starts the server without parsing CLI arguments and records
|
|
4
|
+
* the exit code. The open stdin keeps the process alive after a successful start.
|
|
5
|
+
*/
|
|
6
|
+
export async function runMcpMain() {
|
|
7
|
+
process.exitCode = await runMcpCommand([]);
|
|
8
|
+
}
|
|
@@ -10,6 +10,8 @@ export type RunMcpServerOptions = {
|
|
|
10
10
|
runGit?: RunTextCommand;
|
|
11
11
|
/** Defaults to stdio. Tests pass one half of an in-memory pair. */
|
|
12
12
|
transport?: Transport;
|
|
13
|
+
/** Test seam: where the startup check looks for `agent-blackboard`. Defaults to this module. */
|
|
14
|
+
resolveFrom?: string | URL;
|
|
13
15
|
/** Test seam: replaces how the consumer's `agent-blackboard` client is loaded. */
|
|
14
16
|
blackboard?: BlackboardClientDependencies;
|
|
15
17
|
};
|
package/dist/mcp-server/run.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loadMcpSdk } from './sdk.mjs';
|
|
1
|
+
import { assertBlackboardInstalled, loadMcpSdk } from './sdk.mjs';
|
|
2
2
|
import { createMcpServer } from './server.mjs';
|
|
3
3
|
import { launchWorktreeRoot, runIsolatedGit } from './worktree.mjs';
|
|
4
4
|
/**
|
|
@@ -8,11 +8,14 @@ import { launchWorktreeRoot, runIsolatedGit } from './worktree.mjs';
|
|
|
8
8
|
export async function runMcpServer(options) {
|
|
9
9
|
const runGit = options.runGit ?? runIsolatedGit;
|
|
10
10
|
const sdk = await loadMcpSdk(options.importSdk);
|
|
11
|
+
if (options.blackboard === undefined)
|
|
12
|
+
assertBlackboardInstalled(options.resolveFrom);
|
|
11
13
|
const launchRoot = await launchWorktreeRoot(options.cwd, runGit);
|
|
12
14
|
const environment = {
|
|
13
15
|
launchRoot,
|
|
14
16
|
env: options.env,
|
|
15
17
|
runGit,
|
|
18
|
+
...(options.resolveFrom === undefined ? {} : { resolveFrom: options.resolveFrom }),
|
|
16
19
|
...(options.blackboard === undefined ? {} : { blackboard: options.blackboard }),
|
|
17
20
|
};
|
|
18
21
|
const server = createMcpServer(sdk, environment, options.version);
|
|
@@ -9,9 +9,18 @@ export type McpSdk = {
|
|
|
9
9
|
ListToolsRequestSchema: typeof ListToolsRequestSchema;
|
|
10
10
|
};
|
|
11
11
|
export type SdkImporter = (specifier: string) => Promise<unknown>;
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The directory the server was installed into: the parent of the outermost `node_modules` above
|
|
14
|
+
* `from`, which is where `pnpm add` must run so the peers resolve from this package. Outside any
|
|
15
|
+
* `node_modules` (a source checkout) it is the module's own directory.
|
|
16
|
+
*/
|
|
17
|
+
export declare function installDirectory(from?: string | URL): string;
|
|
18
|
+
export declare function missingSdkMessage(directory: string): string;
|
|
13
19
|
/**
|
|
14
20
|
* Imports the SDK lazily. A static import would make every `vouchington` command fail on a
|
|
15
21
|
* consumer that never installed the optional peer.
|
|
16
22
|
*/
|
|
17
|
-
export declare function loadMcpSdk(importSdk?: SdkImporter): Promise<McpSdk>;
|
|
23
|
+
export declare function loadMcpSdk(importSdk?: SdkImporter, directory?: string): Promise<McpSdk>;
|
|
24
|
+
export declare function missingBlackboardMessage(directory: string): string;
|
|
25
|
+
/** Fails fast at startup when `agent-blackboard` cannot be resolved from this package's install. */
|
|
26
|
+
export declare function assertBlackboardInstalled(resolveFrom?: string | URL): void;
|
package/dist/mcp-server/sdk.mjs
CHANGED
|
@@ -6,17 +6,34 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
+
import { createRequire } from 'node:module';
|
|
10
|
+
import { dirname, sep } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
9
12
|
import { isMissingModuleError } from '../agent-blackboard/client.mjs';
|
|
10
13
|
const SDK_PACKAGE = '@modelcontextprotocol/sdk';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The directory the server was installed into: the parent of the outermost `node_modules` above
|
|
16
|
+
* `from`, which is where `pnpm add` must run so the peers resolve from this package. Outside any
|
|
17
|
+
* `node_modules` (a source checkout) it is the module's own directory.
|
|
18
|
+
*/
|
|
19
|
+
export function installDirectory(from = import.meta.url) {
|
|
20
|
+
const file = typeof from === 'string' && !from.startsWith('file:') ? from : fileURLToPath(from);
|
|
21
|
+
const marker = `${sep}node_modules${sep}`;
|
|
22
|
+
const index = file.indexOf(marker);
|
|
23
|
+
return index === -1 ? dirname(file) : file.slice(0, index);
|
|
24
|
+
}
|
|
25
|
+
export function missingSdkMessage(directory) {
|
|
26
|
+
return (`vouchington mcp needs ${SDK_PACKAGE} (and its zod peer), which is an optional peer ` +
|
|
27
|
+
`dependency of vouchington-tooling and is not installed. Install it in the directory ` +
|
|
28
|
+
`vouchington-tooling is installed in, not in a project: cd ${directory} && ` +
|
|
29
|
+
`pnpm add ${SDK_PACKAGE} zod`);
|
|
30
|
+
}
|
|
14
31
|
const defaultImporter = (specifier) => import(__rewriteRelativeImportExtension(specifier));
|
|
15
32
|
/**
|
|
16
33
|
* Imports the SDK lazily. A static import would make every `vouchington` command fail on a
|
|
17
34
|
* consumer that never installed the optional peer.
|
|
18
35
|
*/
|
|
19
|
-
export async function loadMcpSdk(importSdk = defaultImporter) {
|
|
36
|
+
export async function loadMcpSdk(importSdk = defaultImporter, directory = installDirectory()) {
|
|
20
37
|
try {
|
|
21
38
|
const [server, stdio, types] = await Promise.all([
|
|
22
39
|
importSdk(`${SDK_PACKAGE}/server/mcp.js`),
|
|
@@ -27,7 +44,22 @@ export async function loadMcpSdk(importSdk = defaultImporter) {
|
|
|
27
44
|
}
|
|
28
45
|
catch (error) {
|
|
29
46
|
if (isMissingModuleError(error))
|
|
30
|
-
throw new Error(
|
|
47
|
+
throw new Error(missingSdkMessage(directory), { cause: error });
|
|
31
48
|
throw error;
|
|
32
49
|
}
|
|
33
50
|
}
|
|
51
|
+
export function missingBlackboardMessage(directory) {
|
|
52
|
+
return ('vouchington mcp needs agent-blackboard, which is an optional peer dependency of ' +
|
|
53
|
+
'vouchington-tooling and is not installed. Install it in the directory vouchington-tooling ' +
|
|
54
|
+
`is installed in, not in a project: cd ${directory} && pnpm add agent-blackboard`);
|
|
55
|
+
}
|
|
56
|
+
/** Fails fast at startup when `agent-blackboard` cannot be resolved from this package's install. */
|
|
57
|
+
export function assertBlackboardInstalled(resolveFrom = import.meta.url) {
|
|
58
|
+
try {
|
|
59
|
+
createRequire(resolveFrom).resolve('agent-blackboard');
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// `resolve` only fails when the package cannot be found from `resolveFrom`.
|
|
63
|
+
throw new Error(missingBlackboardMessage(installDirectory(resolveFrom)), { cause: error });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -2,8 +2,9 @@ import { callTool } from './dispatch.mjs';
|
|
|
2
2
|
import { TOOLS } from './tools.mjs';
|
|
3
3
|
export const SERVER_NAME = 'vouchington-tooling';
|
|
4
4
|
const INSTRUCTIONS = 'Journals agent-blackboard feedback for a vouchington consumer. Every tool takes an explicit ' +
|
|
5
|
-
'sessionId and an optional worktree (
|
|
6
|
-
'
|
|
5
|
+
'sessionId and an optional worktree (the absolute path of a git worktree top level; it ' +
|
|
6
|
+
'defaults to the launch directory worktree and is required when the server was launched ' +
|
|
7
|
+
'outside one). Hosts prefix the tool names differently: Claude ' +
|
|
7
8
|
'Code mcp__vouchington-tooling__<tool>, Codex mcp__vouchington_tooling__<tool>, Grok ' +
|
|
8
9
|
'vouchington-tooling__<tool> (through search_tool and use_tool), Cursor the vouchington-tooling ' +
|
|
9
10
|
'namespace (through GetDynamicTools and CallDynamicTool). Search for journal_append before ' +
|
|
@@ -7,8 +7,9 @@ const SESSION_ID = {
|
|
|
7
7
|
};
|
|
8
8
|
const WORKTREE = {
|
|
9
9
|
type: 'string',
|
|
10
|
-
description: 'Absolute path of
|
|
11
|
-
'
|
|
10
|
+
description: 'Absolute path of the top level of a git worktree (`git rev-parse --show-toplevel`), not a ' +
|
|
11
|
+
'subdirectory. Defaults to the launch directory worktree; required when the server was ' +
|
|
12
|
+
'launched outside a git worktree.',
|
|
12
13
|
};
|
|
13
14
|
const PARENT_SESSION_ID = {
|
|
14
15
|
type: ['string', 'null'],
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { type RunTextCommand } from '../gh-cli/exec.mts';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* The environment for git: no inherited `GIT_*` variables, so `GIT_DIR` cannot redirect the check,
|
|
4
|
+
* and the C locale, so git's diagnostics are not translated and can be classified reliably.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isolatedGitEnv(): NodeJS.ProcessEnv;
|
|
3
7
|
export declare const runIsolatedGit: RunTextCommand;
|
|
4
|
-
/** The worktree root containing `cwd`, or a message that says how to fix the launch directory. */
|
|
5
|
-
export declare function launchWorktreeRoot(cwd: string, runGit: RunTextCommand): Promise<string>;
|
|
6
|
-
/** Paths of the non-bare entries in `git worktree list --porcelain` output. */
|
|
7
|
-
export declare function parseWorktreeList(porcelain: string): string[];
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
9
|
+
* The worktree root containing `cwd`, or undefined when git reports `cwd` is not inside one (so
|
|
10
|
+
* the server may be launched from anywhere). Any other git failure, such as a missing git binary
|
|
11
|
+
* or an unsafe repository, is thrown with the cause rather than reported as "outside a worktree".
|
|
12
|
+
*/
|
|
13
|
+
export declare function launchWorktreeRoot(cwd: string, runGit: RunTextCommand): Promise<string | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the worktree a tool call may act on. It must be an absolute path that, after
|
|
16
|
+
* resolving symlinks, is exactly the top level of a git worktree (of any repository on the
|
|
17
|
+
* machine). A subdirectory, a relative or nonexistent path, and a non-git directory are rejected.
|
|
18
|
+
* Git is asked on every call, so worktrees created after the server started are accepted and
|
|
19
|
+
* removed ones are not. Without `requested`, the launch worktree is used when there is one.
|
|
13
20
|
*/
|
|
14
21
|
export declare function resolveWorktree(input: {
|
|
15
|
-
launchRoot: string;
|
|
22
|
+
launchRoot: string | undefined;
|
|
16
23
|
requested?: string | undefined;
|
|
17
24
|
runGit: RunTextCommand;
|
|
18
25
|
}): Promise<string>;
|
|
@@ -5,8 +5,15 @@ import { promisify } from 'node:util';
|
|
|
5
5
|
import { createCommandRunner } from '../gh-cli/exec.mjs';
|
|
6
6
|
import { gitEnv } from '../shared-context/index.mjs';
|
|
7
7
|
const execFileAsync = promisify(execFile);
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The environment for git: no inherited `GIT_*` variables, so `GIT_DIR` cannot redirect the check,
|
|
10
|
+
* and the C locale, so git's diagnostics are not translated and can be classified reliably.
|
|
11
|
+
*/
|
|
12
|
+
export function isolatedGitEnv() {
|
|
13
|
+
const { LANGUAGE: _language, ...env } = gitEnv();
|
|
14
|
+
return { ...env, LC_ALL: 'C' };
|
|
15
|
+
}
|
|
16
|
+
export const runIsolatedGit = createCommandRunner('git', (command, args) => execFileAsync(command, args, { env: isolatedGitEnv() }));
|
|
10
17
|
async function canonical(path) {
|
|
11
18
|
try {
|
|
12
19
|
return await realpath(path);
|
|
@@ -15,44 +22,54 @@ async function canonical(path) {
|
|
|
15
22
|
return undefined;
|
|
16
23
|
}
|
|
17
24
|
}
|
|
18
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* git's two "no worktree here" outcomes: outside any repository, and inside a `.git` directory.
|
|
27
|
+
* The messages are English because `isolatedGitEnv` forces the C locale.
|
|
28
|
+
*/
|
|
29
|
+
function isNotAGitRepository(error) {
|
|
30
|
+
if (typeof error !== 'object' || error === null)
|
|
31
|
+
return false;
|
|
32
|
+
const { stderr, message } = error;
|
|
33
|
+
return [stderr, message].some((text) => typeof text === 'string' && /not a git repository|must be run in a work tree/i.test(text));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The worktree root containing `cwd`, or undefined when git reports `cwd` is not inside one (so
|
|
37
|
+
* the server may be launched from anywhere). Any other git failure, such as a missing git binary
|
|
38
|
+
* or an unsafe repository, is thrown with the cause rather than reported as "outside a worktree".
|
|
39
|
+
*/
|
|
19
40
|
export async function launchWorktreeRoot(cwd, runGit) {
|
|
41
|
+
let output;
|
|
20
42
|
try {
|
|
21
|
-
|
|
43
|
+
output = await runGit(['-C', cwd, 'rev-parse', '--show-toplevel']);
|
|
22
44
|
}
|
|
23
45
|
catch (error) {
|
|
24
|
-
|
|
46
|
+
if (isNotAGitRepository(error))
|
|
47
|
+
return undefined;
|
|
48
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
49
|
+
throw new Error(`git could not determine the worktree of ${cwd}: ${reason}. Check that git is installed and ` +
|
|
50
|
+
'on PATH, that the directory exists, and that the repository is readable by this user ' +
|
|
51
|
+
'(see safe.directory).', { cause: error });
|
|
25
52
|
}
|
|
26
|
-
|
|
27
|
-
/** Paths of the non-bare entries in `git worktree list --porcelain` output. */
|
|
28
|
-
export function parseWorktreeList(porcelain) {
|
|
29
|
-
const paths = [];
|
|
30
|
-
for (const block of porcelain.split(/\r?\n\r?\n/)) {
|
|
31
|
-
const lines = block.split(/\r?\n/);
|
|
32
|
-
const first = lines.find((line) => line.startsWith('worktree '));
|
|
33
|
-
if (first !== undefined && !lines.includes('bare'))
|
|
34
|
-
paths.push(first.slice('worktree '.length));
|
|
35
|
-
}
|
|
36
|
-
return paths;
|
|
53
|
+
return realpath(output.trim());
|
|
37
54
|
}
|
|
38
55
|
/**
|
|
39
|
-
* Resolves the worktree a tool call may act on.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* is
|
|
56
|
+
* Resolves the worktree a tool call may act on. It must be an absolute path that, after
|
|
57
|
+
* resolving symlinks, is exactly the top level of a git worktree (of any repository on the
|
|
58
|
+
* machine). A subdirectory, a relative or nonexistent path, and a non-git directory are rejected.
|
|
59
|
+
* Git is asked on every call, so worktrees created after the server started are accepted and
|
|
60
|
+
* removed ones are not. Without `requested`, the launch worktree is used when there is one.
|
|
43
61
|
*/
|
|
44
62
|
export async function resolveWorktree(input) {
|
|
45
63
|
const { launchRoot, requested, runGit } = input;
|
|
46
|
-
if (requested
|
|
47
|
-
throw new Error('worktree
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
if (requested === undefined && launchRoot === undefined)
|
|
65
|
+
throw new Error('worktree is required: this server was launched outside a git worktree, so pass ' +
|
|
66
|
+
'worktree as the absolute path of the git worktree to act on');
|
|
67
|
+
const path = requested ?? launchRoot;
|
|
68
|
+
if (!isAbsolute(path))
|
|
69
|
+
throw new Error('worktree must be an absolute path to a git worktree');
|
|
70
|
+
const target = await canonical(path);
|
|
71
|
+
if (target !== undefined && (await launchWorktreeRoot(target, runGit)) === target)
|
|
52
72
|
return target;
|
|
53
|
-
throw new Error(`worktree ${
|
|
54
|
-
`
|
|
55
|
-
}
|
|
56
|
-
function errorText(error) {
|
|
57
|
-
return error instanceof Error ? error.message : String(error);
|
|
73
|
+
throw new Error(`worktree ${path} is not the top level of a git worktree: it must exist and be the ` +
|
|
74
|
+
'directory `git rev-parse --show-toplevel` reports, not a subdirectory of it');
|
|
58
75
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { buildOperationResponse } from './build-openapi-response.mts';
|
|
2
|
+
import type { RegisteredRoute, ResponseContract } from './operation-types.mts';
|
|
3
|
+
/** Keeps a cataloged stream unavailable until its extracted variants describe SSE. */
|
|
4
|
+
export declare function retainCatalogSseResponse(kind: RegisteredRoute['kind'] | undefined, variants: readonly ResponseContract[], rendered: ReturnType<typeof buildOperationResponse>): ReturnType<typeof buildOperationResponse>;
|