@the-open-engine/zeroshot 5.4.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/CHANGELOG.md +539 -0
- package/LICENSE +21 -0
- package/README.md +508 -0
- package/cli/commands/inspect-render.js +135 -0
- package/cli/commands/inspect.js +294 -0
- package/cli/commands/providers.js +149 -0
- package/cli/index.js +5431 -0
- package/cli/lib/first-run.js +211 -0
- package/cli/lib/update-checker.js +281 -0
- package/cli/message-formatter-utils.js +75 -0
- package/cli/message-formatters-normal.js +275 -0
- package/cli/message-formatters-watch.js +185 -0
- package/cluster-templates/base-templates/debug-workflow.json +422 -0
- package/cluster-templates/base-templates/full-workflow.json +727 -0
- package/cluster-templates/base-templates/heavy-validation.json +272 -0
- package/cluster-templates/base-templates/quick-validation.json +285 -0
- package/cluster-templates/base-templates/single-worker.json +71 -0
- package/cluster-templates/base-templates/worker-validator.json +230 -0
- package/cluster-templates/conductor-bootstrap.json +130 -0
- package/docker/zeroshot-cluster/Dockerfile +153 -0
- package/docker/zeroshot-cluster/pre-baked-deps.json +28 -0
- package/lib/agent-cli-provider/adapters/claude-parser.d.ts +3 -0
- package/lib/agent-cli-provider/adapters/claude-parser.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/claude-parser.js +122 -0
- package/lib/agent-cli-provider/adapters/claude-parser.js.map +1 -0
- package/lib/agent-cli-provider/adapters/claude-recovery.d.ts +15 -0
- package/lib/agent-cli-provider/adapters/claude-recovery.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/claude-recovery.js +165 -0
- package/lib/agent-cli-provider/adapters/claude-recovery.js.map +1 -0
- package/lib/agent-cli-provider/adapters/claude.d.ts +3 -0
- package/lib/agent-cli-provider/adapters/claude.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/claude.js +181 -0
- package/lib/agent-cli-provider/adapters/claude.js.map +1 -0
- package/lib/agent-cli-provider/adapters/codex-parser.d.ts +3 -0
- package/lib/agent-cli-provider/adapters/codex-parser.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/codex-parser.js +192 -0
- package/lib/agent-cli-provider/adapters/codex-parser.js.map +1 -0
- package/lib/agent-cli-provider/adapters/codex.d.ts +3 -0
- package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/codex.js +151 -0
- package/lib/agent-cli-provider/adapters/codex.js.map +1 -0
- package/lib/agent-cli-provider/adapters/common.d.ts +28 -0
- package/lib/agent-cli-provider/adapters/common.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/common.js +71 -0
- package/lib/agent-cli-provider/adapters/common.js.map +1 -0
- package/lib/agent-cli-provider/adapters/gemini.d.ts +3 -0
- package/lib/agent-cli-provider/adapters/gemini.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/gemini.js +176 -0
- package/lib/agent-cli-provider/adapters/gemini.js.map +1 -0
- package/lib/agent-cli-provider/adapters/index.d.ts +9 -0
- package/lib/agent-cli-provider/adapters/index.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/index.js +95 -0
- package/lib/agent-cli-provider/adapters/index.js.map +1 -0
- package/lib/agent-cli-provider/adapters/opencode.d.ts +3 -0
- package/lib/agent-cli-provider/adapters/opencode.d.ts.map +1 -0
- package/lib/agent-cli-provider/adapters/opencode.js +228 -0
- package/lib/agent-cli-provider/adapters/opencode.js.map +1 -0
- package/lib/agent-cli-provider/contract-actions.d.ts +5 -0
- package/lib/agent-cli-provider/contract-actions.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-actions.js +140 -0
- package/lib/agent-cli-provider/contract-actions.js.map +1 -0
- package/lib/agent-cli-provider/contract-env.d.ts +11 -0
- package/lib/agent-cli-provider/contract-env.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-env.js +113 -0
- package/lib/agent-cli-provider/contract-env.js.map +1 -0
- package/lib/agent-cli-provider/contract-envelope.d.ts +49 -0
- package/lib/agent-cli-provider/contract-envelope.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-envelope.js +52 -0
- package/lib/agent-cli-provider/contract-envelope.js.map +1 -0
- package/lib/agent-cli-provider/contract-errors.d.ts +22 -0
- package/lib/agent-cli-provider/contract-errors.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-errors.js +71 -0
- package/lib/agent-cli-provider/contract-errors.js.map +1 -0
- package/lib/agent-cli-provider/contract-fallback.d.ts +7 -0
- package/lib/agent-cli-provider/contract-fallback.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-fallback.js +102 -0
- package/lib/agent-cli-provider/contract-fallback.js.map +1 -0
- package/lib/agent-cli-provider/contract-invoke.d.ts +5 -0
- package/lib/agent-cli-provider/contract-invoke.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-invoke.js +89 -0
- package/lib/agent-cli-provider/contract-invoke.js.map +1 -0
- package/lib/agent-cli-provider/contract-options.d.ts +3 -0
- package/lib/agent-cli-provider/contract-options.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-options.js +140 -0
- package/lib/agent-cli-provider/contract-options.js.map +1 -0
- package/lib/agent-cli-provider/contract-parse.d.ts +15 -0
- package/lib/agent-cli-provider/contract-parse.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-parse.js +81 -0
- package/lib/agent-cli-provider/contract-parse.js.map +1 -0
- package/lib/agent-cli-provider/contract-support.d.ts +18 -0
- package/lib/agent-cli-provider/contract-support.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract-support.js +154 -0
- package/lib/agent-cli-provider/contract-support.js.map +1 -0
- package/lib/agent-cli-provider/contract.d.ts +13 -0
- package/lib/agent-cli-provider/contract.d.ts.map +1 -0
- package/lib/agent-cli-provider/contract.js +30 -0
- package/lib/agent-cli-provider/contract.js.map +1 -0
- package/lib/agent-cli-provider/env-safety.d.ts +11 -0
- package/lib/agent-cli-provider/env-safety.d.ts.map +1 -0
- package/lib/agent-cli-provider/env-safety.js +83 -0
- package/lib/agent-cli-provider/env-safety.js.map +1 -0
- package/lib/agent-cli-provider/errors.d.ts +5 -0
- package/lib/agent-cli-provider/errors.d.ts.map +1 -0
- package/lib/agent-cli-provider/errors.js +115 -0
- package/lib/agent-cli-provider/errors.js.map +1 -0
- package/lib/agent-cli-provider/executable.d.ts +3 -0
- package/lib/agent-cli-provider/executable.d.ts.map +1 -0
- package/lib/agent-cli-provider/executable.js +24 -0
- package/lib/agent-cli-provider/executable.js.map +1 -0
- package/lib/agent-cli-provider/index.d.ts +8 -0
- package/lib/agent-cli-provider/index.d.ts.map +1 -0
- package/lib/agent-cli-provider/index.js +31 -0
- package/lib/agent-cli-provider/index.js.map +1 -0
- package/lib/agent-cli-provider/invoke-evidence.d.ts +4 -0
- package/lib/agent-cli-provider/invoke-evidence.d.ts.map +1 -0
- package/lib/agent-cli-provider/invoke-evidence.js +17 -0
- package/lib/agent-cli-provider/invoke-evidence.js.map +1 -0
- package/lib/agent-cli-provider/json.d.ts +16 -0
- package/lib/agent-cli-provider/json.d.ts.map +1 -0
- package/lib/agent-cli-provider/json.js +110 -0
- package/lib/agent-cli-provider/json.js.map +1 -0
- package/lib/agent-cli-provider/log-prefix.d.ts +2 -0
- package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -0
- package/lib/agent-cli-provider/log-prefix.js +22 -0
- package/lib/agent-cli-provider/log-prefix.js.map +1 -0
- package/lib/agent-cli-provider/process-runner.d.ts +17 -0
- package/lib/agent-cli-provider/process-runner.d.ts.map +1 -0
- package/lib/agent-cli-provider/process-runner.js +89 -0
- package/lib/agent-cli-provider/process-runner.js.map +1 -0
- package/lib/agent-cli-provider/redaction.d.ts +9 -0
- package/lib/agent-cli-provider/redaction.d.ts.map +1 -0
- package/lib/agent-cli-provider/redaction.js +227 -0
- package/lib/agent-cli-provider/redaction.js.map +1 -0
- package/lib/agent-cli-provider/schema.d.ts +5 -0
- package/lib/agent-cli-provider/schema.d.ts.map +1 -0
- package/lib/agent-cli-provider/schema.js +136 -0
- package/lib/agent-cli-provider/schema.js.map +1 -0
- package/lib/agent-cli-provider/single-agent-runtime.d.ts +15 -0
- package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -0
- package/lib/agent-cli-provider/single-agent-runtime.js +228 -0
- package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -0
- package/lib/agent-cli-provider/types.d.ts +194 -0
- package/lib/agent-cli-provider/types.d.ts.map +1 -0
- package/lib/agent-cli-provider/types.js +12 -0
- package/lib/agent-cli-provider/types.js.map +1 -0
- package/lib/completion.js +174 -0
- package/lib/detached-startup.js +220 -0
- package/lib/docker-config.js +220 -0
- package/lib/git-remote-utils.js +165 -0
- package/lib/id-detector.js +55 -0
- package/lib/provider-defaults.js +62 -0
- package/lib/provider-detection.js +59 -0
- package/lib/provider-names.js +57 -0
- package/lib/repo-settings.js +69 -0
- package/lib/settings/claude-auth.js +78 -0
- package/lib/settings.js +542 -0
- package/lib/start-cluster.js +321 -0
- package/lib/stream-json-parser.js +67 -0
- package/package.json +162 -0
- package/scripts/fix-node-pty-permissions.js +75 -0
- package/scripts/record-demo.sh +279 -0
- package/scripts/setup-merge-queue.sh +170 -0
- package/scripts/test-install.sh +40 -0
- package/scripts/validate-templates.js +107 -0
- package/src/agent/agent-config.js +266 -0
- package/src/agent/agent-context-builder.js +189 -0
- package/src/agent/agent-context-sections.js +338 -0
- package/src/agent/agent-context-sources.js +147 -0
- package/src/agent/agent-hook-executor.js +721 -0
- package/src/agent/agent-input-injector.js +141 -0
- package/src/agent/agent-lifecycle.js +982 -0
- package/src/agent/agent-quality-gate-schema.js +93 -0
- package/src/agent/agent-quality-gates-context.js +51 -0
- package/src/agent/agent-stuck-detector.js +256 -0
- package/src/agent/agent-task-executor.js +2028 -0
- package/src/agent/agent-trigger-evaluator.js +67 -0
- package/src/agent/context-metrics.js +160 -0
- package/src/agent/context-pack-builder.js +367 -0
- package/src/agent/context-replay-policy.js +51 -0
- package/src/agent/guidance-queue.js +77 -0
- package/src/agent/output-extraction.js +367 -0
- package/src/agent/output-reformatter.js +175 -0
- package/src/agent/pr-verification.js +653 -0
- package/src/agent/rate-limit-backoff.js +82 -0
- package/src/agent/schema-utils.js +146 -0
- package/src/agent/validation-platform.js +35 -0
- package/src/agent-cli-provider/adapters/claude-parser.ts +133 -0
- package/src/agent-cli-provider/adapters/claude-recovery.ts +203 -0
- package/src/agent-cli-provider/adapters/claude.ts +247 -0
- package/src/agent-cli-provider/adapters/codex-parser.ts +211 -0
- package/src/agent-cli-provider/adapters/codex.ts +217 -0
- package/src/agent-cli-provider/adapters/common.ts +124 -0
- package/src/agent-cli-provider/adapters/gemini.ts +243 -0
- package/src/agent-cli-provider/adapters/index.ts +126 -0
- package/src/agent-cli-provider/adapters/opencode.ts +286 -0
- package/src/agent-cli-provider/contract-actions.ts +150 -0
- package/src/agent-cli-provider/contract-env.ts +111 -0
- package/src/agent-cli-provider/contract-envelope.ts +110 -0
- package/src/agent-cli-provider/contract-errors.ts +66 -0
- package/src/agent-cli-provider/contract-fallback.ts +121 -0
- package/src/agent-cli-provider/contract-invoke.ts +104 -0
- package/src/agent-cli-provider/contract-options.ts +173 -0
- package/src/agent-cli-provider/contract-parse.ts +94 -0
- package/src/agent-cli-provider/contract-support.ts +167 -0
- package/src/agent-cli-provider/contract.ts +56 -0
- package/src/agent-cli-provider/env-safety.ts +82 -0
- package/src/agent-cli-provider/errors.ts +122 -0
- package/src/agent-cli-provider/executable.ts +24 -0
- package/src/agent-cli-provider/index.ts +83 -0
- package/src/agent-cli-provider/invoke-evidence.ts +18 -0
- package/src/agent-cli-provider/json.ts +114 -0
- package/src/agent-cli-provider/log-prefix.ts +20 -0
- package/src/agent-cli-provider/process-runner.ts +145 -0
- package/src/agent-cli-provider/redaction.ts +282 -0
- package/src/agent-cli-provider/schema.ts +115 -0
- package/src/agent-cli-provider/single-agent-runtime.ts +311 -0
- package/src/agent-cli-provider/types.ts +237 -0
- package/src/agent-wrapper.js +615 -0
- package/src/agents/git-pusher-template.js +705 -0
- package/src/attach/attach-client.js +438 -0
- package/src/attach/attach-server.js +543 -0
- package/src/attach/index.js +37 -0
- package/src/attach/protocol.js +220 -0
- package/src/attach/ring-buffer.js +121 -0
- package/src/attach/send-input.js +88 -0
- package/src/attach/socket-discovery.js +267 -0
- package/src/claude-task-runner.js +661 -0
- package/src/config-router.js +89 -0
- package/src/config-validator.js +2202 -0
- package/src/copy-worker.js +43 -0
- package/src/guidance-topics.js +10 -0
- package/src/input-helpers.js +65 -0
- package/src/isolation-manager.js +1734 -0
- package/src/issue-providers/README.md +305 -0
- package/src/issue-providers/azure-devops-provider.js +307 -0
- package/src/issue-providers/base-provider.js +232 -0
- package/src/issue-providers/github-provider.js +210 -0
- package/src/issue-providers/gitlab-provider.js +262 -0
- package/src/issue-providers/index.js +196 -0
- package/src/issue-providers/jira-provider.js +260 -0
- package/src/ledger.js +692 -0
- package/src/lib/gc.js +232 -0
- package/src/lib/safe-exec.js +88 -0
- package/src/logic-engine.js +201 -0
- package/src/message-buffer.js +81 -0
- package/src/message-bus-bridge.js +144 -0
- package/src/message-bus.js +256 -0
- package/src/name-generator.js +232 -0
- package/src/orchestrator.js +3924 -0
- package/src/preflight.js +712 -0
- package/src/process-metrics.js +608 -0
- package/src/providers/anthropic/index.js +3 -0
- package/src/providers/base-provider.js +355 -0
- package/src/providers/capabilities.js +60 -0
- package/src/providers/google/index.js +3 -0
- package/src/providers/index.js +293 -0
- package/src/providers/openai/index.js +3 -0
- package/src/providers/opencode/index.js +3 -0
- package/src/quality-gates.js +143 -0
- package/src/schemas/sub-cluster.js +208 -0
- package/src/state-snapshot.js +398 -0
- package/src/state-snapshotter.js +142 -0
- package/src/status-footer.js +1026 -0
- package/src/sub-cluster-wrapper.js +693 -0
- package/src/task-runner.js +30 -0
- package/src/template-resolver.js +425 -0
- package/src/template-validation/index.js +338 -0
- package/src/template-validation/simulate-consensus-gates.js +324 -0
- package/src/template-validation/simulate-random-topology.js +541 -0
- package/src/template-validation/simulate-two-stage-validation.js +270 -0
- package/src/worktree-claude-config.js +135 -0
- package/src/worktree-tooling-env.js +150 -0
- package/task-lib/attachable-watcher.js +381 -0
- package/task-lib/commands/clean.js +50 -0
- package/task-lib/commands/episodes.js +105 -0
- package/task-lib/commands/get-log-path.js +23 -0
- package/task-lib/commands/kill.js +32 -0
- package/task-lib/commands/list.js +105 -0
- package/task-lib/commands/logs.js +439 -0
- package/task-lib/commands/resume.js +42 -0
- package/task-lib/commands/run.js +57 -0
- package/task-lib/commands/schedule.js +105 -0
- package/task-lib/commands/scheduler-cmd.js +96 -0
- package/task-lib/commands/schedules.js +148 -0
- package/task-lib/commands/status.js +44 -0
- package/task-lib/commands/unschedule.js +16 -0
- package/task-lib/completion.js +9 -0
- package/task-lib/config.js +11 -0
- package/task-lib/name-generator.js +230 -0
- package/task-lib/package.json +3 -0
- package/task-lib/provider-helper-runtime.js +29 -0
- package/task-lib/runner.js +190 -0
- package/task-lib/scheduler.js +252 -0
- package/task-lib/store.js +529 -0
- package/task-lib/watcher.js +305 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export class ContractRequestError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly exitCode: number;
|
|
4
|
+
readonly field?: string;
|
|
5
|
+
|
|
6
|
+
constructor(input: { code: string; message: string; exitCode: number; field?: string }) {
|
|
7
|
+
super(input.message);
|
|
8
|
+
this.name = 'ContractRequestError';
|
|
9
|
+
this.code = input.code;
|
|
10
|
+
this.exitCode = input.exitCode;
|
|
11
|
+
if (input.field !== undefined) this.field = input.field;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function contractError(input: {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
readonly message: string;
|
|
18
|
+
readonly exitCode: number;
|
|
19
|
+
readonly field?: string;
|
|
20
|
+
}): ContractRequestError {
|
|
21
|
+
return new ContractRequestError(input);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function invalidField(field: string, message: string): never {
|
|
25
|
+
throw contractError({
|
|
26
|
+
code: 'invalid-field',
|
|
27
|
+
message,
|
|
28
|
+
exitCode: 2,
|
|
29
|
+
field,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function requiredString(record: Record<string, unknown>, field: string): string {
|
|
34
|
+
const value = record[field];
|
|
35
|
+
if (typeof value === 'string' && value.length > 0) return value;
|
|
36
|
+
throw contractError({
|
|
37
|
+
code: 'missing-field',
|
|
38
|
+
message: `${field} is required.`,
|
|
39
|
+
exitCode: 2,
|
|
40
|
+
field,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function optionalString(record: Record<string, unknown>, field: string): string | undefined {
|
|
45
|
+
const value = record[field];
|
|
46
|
+
if (value === undefined) return undefined;
|
|
47
|
+
if (typeof value === 'string') return value;
|
|
48
|
+
throw contractError({
|
|
49
|
+
code: 'invalid-field',
|
|
50
|
+
message: `${field} must be a string.`,
|
|
51
|
+
exitCode: 2,
|
|
52
|
+
field,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function optionalNumber(record: Record<string, unknown>, field: string): number | undefined {
|
|
57
|
+
const value = record[field];
|
|
58
|
+
if (value === undefined) return undefined;
|
|
59
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
60
|
+
throw contractError({
|
|
61
|
+
code: 'invalid-field',
|
|
62
|
+
message: `${field} must be a finite number.`,
|
|
63
|
+
exitCode: 2,
|
|
64
|
+
field,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { getProviderAdapter } from './adapters';
|
|
2
|
+
import { envRedactions, mergeEnvForRedaction } from './contract-env';
|
|
3
|
+
import { ContractRequestError, contractError } from './contract-errors';
|
|
4
|
+
import {
|
|
5
|
+
errorEnvelope,
|
|
6
|
+
type ContractErrorObject,
|
|
7
|
+
type ContractEnvelope,
|
|
8
|
+
} from './contract-envelope';
|
|
9
|
+
import { getString, isRecord, parseJson, unknownToMessage } from './json';
|
|
10
|
+
import { mergeRedactions, redactString } from './redaction';
|
|
11
|
+
import type { ProviderAdapter } from './types';
|
|
12
|
+
import type { RequestData } from './contract-support';
|
|
13
|
+
|
|
14
|
+
export function requestEnvelopeData(input: string): RequestData {
|
|
15
|
+
try {
|
|
16
|
+
const parsed = parseJson(input);
|
|
17
|
+
if (isRecord(parsed)) {
|
|
18
|
+
return {
|
|
19
|
+
raw: parsed,
|
|
20
|
+
command: getString(parsed, 'command'),
|
|
21
|
+
provider: getString(parsed, 'provider'),
|
|
22
|
+
env: fallbackRedactionEnv(parsed),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
return { raw: {}, command: null, provider: null, env: {} };
|
|
27
|
+
}
|
|
28
|
+
return { raw: {}, command: null, provider: null, env: {} };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function fallbackStringRecord(value: unknown): Readonly<Record<string, string>> {
|
|
32
|
+
if (!isRecord(value)) return {};
|
|
33
|
+
const result: Record<string, string> = {};
|
|
34
|
+
for (const [key, item] of Object.entries(value)) {
|
|
35
|
+
if (typeof item === 'string') result[key] = item;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function fallbackRedactionEnv(value: Record<string, unknown>): Readonly<Record<string, string>> {
|
|
41
|
+
const options = isRecord(value.options) ? value.options : {};
|
|
42
|
+
return mergeEnvForRedaction(
|
|
43
|
+
{ source: 'request', env: fallbackStringRecord(value.env) },
|
|
44
|
+
{ source: 'options.authEnv', env: fallbackStringRecord(options.authEnv) }
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function redactFallbackField(input: {
|
|
49
|
+
readonly value: string | null;
|
|
50
|
+
readonly env: Readonly<Record<string, string>>;
|
|
51
|
+
readonly untrusted: boolean;
|
|
52
|
+
}): {
|
|
53
|
+
readonly value: string | null;
|
|
54
|
+
readonly redactions: ReturnType<typeof redactString>['redactions'];
|
|
55
|
+
} {
|
|
56
|
+
if (input.value === null || !input.untrusted) return { value: input.value, redactions: [] };
|
|
57
|
+
const result = redactString(input.value, input.env);
|
|
58
|
+
if (typeof result.value !== 'string') {
|
|
59
|
+
throw new Error('Redacted provider contract field lost its string shape.');
|
|
60
|
+
}
|
|
61
|
+
return { value: result.value, redactions: result.redactions };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function errorObject(requestError: ContractRequestError): ContractErrorObject {
|
|
65
|
+
if (requestError.field === undefined) {
|
|
66
|
+
return {
|
|
67
|
+
code: requestError.code,
|
|
68
|
+
message: requestError.message,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
code: requestError.code,
|
|
73
|
+
message: requestError.message,
|
|
74
|
+
field: requestError.field,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function requestErrorFromUnknown(error: unknown): ContractRequestError {
|
|
79
|
+
if (error instanceof ContractRequestError) return error;
|
|
80
|
+
return contractError({
|
|
81
|
+
code: 'internal-error',
|
|
82
|
+
message: unknownToMessage(error),
|
|
83
|
+
exitCode: 5,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function fallbackErrorEnvelope(
|
|
88
|
+
fallback: RequestData,
|
|
89
|
+
requestError: ContractRequestError
|
|
90
|
+
): ContractEnvelope {
|
|
91
|
+
const adapter = fallback.provider === null ? null : providerAdapterOrNull(fallback.provider);
|
|
92
|
+
const command = redactFallbackField({
|
|
93
|
+
value: fallback.command,
|
|
94
|
+
env: fallback.env,
|
|
95
|
+
untrusted: requestError.field === 'command',
|
|
96
|
+
});
|
|
97
|
+
const provider = redactFallbackField({
|
|
98
|
+
value: fallback.provider,
|
|
99
|
+
env: fallback.env,
|
|
100
|
+
untrusted: requestError.field === 'provider',
|
|
101
|
+
});
|
|
102
|
+
return errorEnvelope({
|
|
103
|
+
command: command.value,
|
|
104
|
+
provider: provider.value,
|
|
105
|
+
adapterVersion: adapter?.adapterVersion ?? null,
|
|
106
|
+
redactions: mergeRedactions(
|
|
107
|
+
envRedactions(fallback.env),
|
|
108
|
+
command.redactions,
|
|
109
|
+
provider.redactions
|
|
110
|
+
),
|
|
111
|
+
error: errorObject(requestError),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function providerAdapterOrNull(provider: string): ProviderAdapter | null {
|
|
116
|
+
try {
|
|
117
|
+
return getProviderAdapter(provider);
|
|
118
|
+
} catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { unlink } from 'node:fs/promises';
|
|
2
|
+
import { commandRedactions } from './contract-env';
|
|
3
|
+
import { successEnvelope, type ContractEnvelope } from './contract-envelope';
|
|
4
|
+
import { buildCommandSpec, optionalNumber, schemaMode, type RequestData } from './contract-support';
|
|
5
|
+
import { providerFailureClassification } from './invoke-evidence';
|
|
6
|
+
import { parseOutputEvents } from './contract-parse';
|
|
7
|
+
import { unknownToMessage } from './json';
|
|
8
|
+
import type { CommandSpec } from './types';
|
|
9
|
+
import type { ProcessResult, ProcessRunner, ProcessRunnerOptions } from './process-runner';
|
|
10
|
+
|
|
11
|
+
interface CleanupResult {
|
|
12
|
+
readonly path: string;
|
|
13
|
+
readonly removed: boolean;
|
|
14
|
+
readonly error?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function cleanupFiles(commandSpec: CommandSpec): Promise<readonly CleanupResult[]> {
|
|
18
|
+
const cleanup = commandSpec.cleanup ?? [];
|
|
19
|
+
const results: CleanupResult[] = [];
|
|
20
|
+
for (const file of cleanup) {
|
|
21
|
+
try {
|
|
22
|
+
await unlink(file);
|
|
23
|
+
results.push({ path: file, removed: true });
|
|
24
|
+
} catch (error) {
|
|
25
|
+
results.push({ path: file, removed: false, error: unknownToMessage(error) });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return results;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function runAndCleanup(
|
|
32
|
+
commandSpec: CommandSpec,
|
|
33
|
+
runner: ProcessRunner,
|
|
34
|
+
runnerOptions: ProcessRunnerOptions
|
|
35
|
+
): Promise<{ readonly result: ProcessResult; readonly cleanup: readonly CleanupResult[] }> {
|
|
36
|
+
let result: ProcessResult | null = null;
|
|
37
|
+
let runnerError: unknown;
|
|
38
|
+
try {
|
|
39
|
+
result = await runner(commandSpec, runnerOptions);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
runnerError = error;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const cleanup = await cleanupFiles(commandSpec);
|
|
45
|
+
if (runnerError !== undefined) throw runnerError;
|
|
46
|
+
if (result === null) throw new Error('Provider runner did not produce a result.');
|
|
47
|
+
return { result, cleanup };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function runInvoke(
|
|
51
|
+
request: RequestData,
|
|
52
|
+
runner: ProcessRunner
|
|
53
|
+
): Promise<ContractEnvelope> {
|
|
54
|
+
const { adapter, commandSpec, options } = buildCommandSpec(request);
|
|
55
|
+
const timeoutMs = optionalNumber(request.raw, 'timeoutMs');
|
|
56
|
+
const runnerOptions = timeoutMs === undefined ? {} : { timeoutMs };
|
|
57
|
+
const { result, cleanup } = await runAndCleanup(commandSpec, runner, runnerOptions);
|
|
58
|
+
const parsed = parseOutputEvents(adapter, {
|
|
59
|
+
chunk: [result.stdout, result.stderr].join('\n'),
|
|
60
|
+
sources: [
|
|
61
|
+
{ name: 'stdout', value: result.stdout },
|
|
62
|
+
{ name: 'stderr', value: result.stderr },
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
const classification = providerFailureClassification(adapter, result);
|
|
66
|
+
return successEnvelope({
|
|
67
|
+
command: request.command ?? 'invoke',
|
|
68
|
+
adapter,
|
|
69
|
+
warnings: commandSpec.warnings,
|
|
70
|
+
redactions: commandRedactions(commandSpec),
|
|
71
|
+
evidence: invokeEvidence(result, timeoutMs),
|
|
72
|
+
result: {
|
|
73
|
+
commandSpec,
|
|
74
|
+
outputFormat: options.outputFormat ?? null,
|
|
75
|
+
schemaMode: schemaMode(options),
|
|
76
|
+
evidence: {
|
|
77
|
+
stdout: result.stdout,
|
|
78
|
+
stderr: result.stderr,
|
|
79
|
+
},
|
|
80
|
+
events: parsed.events,
|
|
81
|
+
diagnostics: parsed.diagnostics,
|
|
82
|
+
exitCode: result.exitCode,
|
|
83
|
+
signal: result.signal,
|
|
84
|
+
durationMs: result.durationMs,
|
|
85
|
+
timedOut: result.timedOut ?? false,
|
|
86
|
+
timeoutMs: result.timeoutMs ?? timeoutMs ?? null,
|
|
87
|
+
cleanup,
|
|
88
|
+
classification,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function invokeEvidence(
|
|
94
|
+
result: ProcessResult,
|
|
95
|
+
timeoutMs: number | undefined
|
|
96
|
+
): Record<string, unknown> {
|
|
97
|
+
return {
|
|
98
|
+
exitCode: result.exitCode,
|
|
99
|
+
signal: result.signal,
|
|
100
|
+
durationMs: result.durationMs,
|
|
101
|
+
timedOut: result.timedOut ?? false,
|
|
102
|
+
timeoutMs: result.timeoutMs ?? timeoutMs ?? null,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { isRecord } from './json';
|
|
2
|
+
import { invalidField, contractError } from './contract-errors';
|
|
3
|
+
import { stringRecord } from './contract-env';
|
|
4
|
+
import type {
|
|
5
|
+
BuildProviderCommandOptions,
|
|
6
|
+
CliFeatureOverrides,
|
|
7
|
+
ModelLevel,
|
|
8
|
+
ModelSpec,
|
|
9
|
+
OutputFormat,
|
|
10
|
+
ReasoningEffort,
|
|
11
|
+
} from './types';
|
|
12
|
+
|
|
13
|
+
const OUTPUT_FORMATS: readonly OutputFormat[] = ['text', 'json', 'stream-json'];
|
|
14
|
+
const MODEL_LEVELS: readonly ModelLevel[] = ['level1', 'level2', 'level3'];
|
|
15
|
+
const REASONING_EFFORTS: readonly ReasoningEffort[] = ['low', 'medium', 'high', 'xhigh'];
|
|
16
|
+
const CLI_FEATURE_FIELDS = [
|
|
17
|
+
'supportsOutputFormat',
|
|
18
|
+
'supportsStreamJson',
|
|
19
|
+
'supportsJsonSchema',
|
|
20
|
+
'supportsAutoApprove',
|
|
21
|
+
'supportsIncludePartials',
|
|
22
|
+
'supportsVerbose',
|
|
23
|
+
'supportsModel',
|
|
24
|
+
'supportsJson',
|
|
25
|
+
'supportsOutputSchema',
|
|
26
|
+
'supportsCwd',
|
|
27
|
+
'supportsConfigOverride',
|
|
28
|
+
'supportsSkipGitRepoCheck',
|
|
29
|
+
'supportsVariant',
|
|
30
|
+
'unknown',
|
|
31
|
+
] as const;
|
|
32
|
+
|
|
33
|
+
type CliFeatureField = (typeof CLI_FEATURE_FIELDS)[number];
|
|
34
|
+
|
|
35
|
+
export function requestOptions(value: unknown): BuildProviderCommandOptions {
|
|
36
|
+
if (value === undefined) return {};
|
|
37
|
+
if (!isRecord(value)) {
|
|
38
|
+
throw contractError({
|
|
39
|
+
code: 'invalid-field',
|
|
40
|
+
message: 'options must be an object.',
|
|
41
|
+
exitCode: 2,
|
|
42
|
+
field: 'options',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
rejectProviderCommandOverrides(value);
|
|
46
|
+
return normalizeBuildOptions(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function rejectProviderCommandOverrides(value: Record<string, unknown>): void {
|
|
50
|
+
for (const field of ['command', 'commandArgs']) {
|
|
51
|
+
if (!Object.prototype.hasOwnProperty.call(value, field)) continue;
|
|
52
|
+
throw contractError({
|
|
53
|
+
code: 'forbidden-field',
|
|
54
|
+
message: `options.${field} is not accepted by provider executable requests; provider adapters own executable binaries and arguments.`,
|
|
55
|
+
exitCode: 2,
|
|
56
|
+
field: `options.${field}`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function optionalStringValue(value: unknown, field: string): string | undefined {
|
|
62
|
+
if (value === undefined) return undefined;
|
|
63
|
+
if (typeof value === 'string') return value;
|
|
64
|
+
invalidField(field, `${field} must be a string.`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function optionalNullableStringValue(value: unknown, field: string): string | null | undefined {
|
|
68
|
+
if (value === undefined) return undefined;
|
|
69
|
+
if (value === null) return null;
|
|
70
|
+
if (typeof value === 'string') return value;
|
|
71
|
+
invalidField(field, `${field} must be a string or null.`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function optionalBooleanValue(value: unknown, field: string): boolean | undefined {
|
|
75
|
+
if (value === undefined) return undefined;
|
|
76
|
+
if (typeof value === 'boolean') return value;
|
|
77
|
+
invalidField(field, `${field} must be a boolean.`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function optionalEnumValue<T extends string>(
|
|
81
|
+
value: unknown,
|
|
82
|
+
field: string,
|
|
83
|
+
allowed: readonly T[]
|
|
84
|
+
): T | undefined {
|
|
85
|
+
if (value === undefined) return undefined;
|
|
86
|
+
if (typeof value !== 'string') {
|
|
87
|
+
invalidField(field, `${field} must be a string.`);
|
|
88
|
+
}
|
|
89
|
+
for (const item of allowed) {
|
|
90
|
+
if (value === item) return item;
|
|
91
|
+
}
|
|
92
|
+
invalidField(field, `${field} must be one of: ${allowed.join(', ')}.`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function optionalModelSpec(value: unknown): ModelSpec | undefined {
|
|
96
|
+
if (value === undefined) return undefined;
|
|
97
|
+
if (!isRecord(value)) {
|
|
98
|
+
invalidField('options.modelSpec', 'options.modelSpec must be an object.');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const level = optionalEnumValue(value.level, 'options.modelSpec.level', MODEL_LEVELS);
|
|
102
|
+
const model = optionalNullableStringValue(value.model, 'options.modelSpec.model');
|
|
103
|
+
const reasoningEffort = optionalEnumValue(
|
|
104
|
+
value.reasoningEffort,
|
|
105
|
+
'options.modelSpec.reasoningEffort',
|
|
106
|
+
REASONING_EFFORTS
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
...(level === undefined ? {} : { level }),
|
|
111
|
+
...(model === undefined ? {} : { model }),
|
|
112
|
+
...(reasoningEffort === undefined ? {} : { reasoningEffort }),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function optionalCliFeatures(value: unknown): CliFeatureOverrides | undefined {
|
|
117
|
+
if (value === undefined) return undefined;
|
|
118
|
+
if (!isRecord(value)) {
|
|
119
|
+
invalidField('options.cliFeatures', 'options.cliFeatures must be an object.');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const result: Partial<Record<CliFeatureField, boolean>> = {};
|
|
123
|
+
for (const field of CLI_FEATURE_FIELDS) {
|
|
124
|
+
const item = optionalBooleanValue(value[field], `options.cliFeatures.${field}`);
|
|
125
|
+
if (item !== undefined) result[field] = item;
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function normalizeBuildOptions(value: Record<string, unknown>): BuildProviderCommandOptions {
|
|
131
|
+
const result: Record<string, unknown> = {};
|
|
132
|
+
addDefined(result, 'modelSpec', optionalModelSpec(value.modelSpec));
|
|
133
|
+
addDefined(
|
|
134
|
+
result,
|
|
135
|
+
'outputFormat',
|
|
136
|
+
optionalEnumValue(value.outputFormat, 'options.outputFormat', OUTPUT_FORMATS)
|
|
137
|
+
);
|
|
138
|
+
addPresent(result, value, 'jsonSchema');
|
|
139
|
+
addDefined(result, 'cwd', optionalStringValue(value.cwd, 'options.cwd'));
|
|
140
|
+
addDefined(result, 'autoApprove', optionalBooleanValue(value.autoApprove, 'options.autoApprove'));
|
|
141
|
+
addDefined(
|
|
142
|
+
result,
|
|
143
|
+
'resumeSessionId',
|
|
144
|
+
optionalStringValue(value.resumeSessionId, 'options.resumeSessionId')
|
|
145
|
+
);
|
|
146
|
+
addDefined(
|
|
147
|
+
result,
|
|
148
|
+
'continueSession',
|
|
149
|
+
optionalBooleanValue(value.continueSession, 'options.continueSession')
|
|
150
|
+
);
|
|
151
|
+
addDefined(result, 'cliFeatures', optionalCliFeatures(value.cliFeatures));
|
|
152
|
+
addDefined(
|
|
153
|
+
result,
|
|
154
|
+
'strictSchema',
|
|
155
|
+
optionalBooleanValue(value.strictSchema, 'options.strictSchema')
|
|
156
|
+
);
|
|
157
|
+
if (Object.prototype.hasOwnProperty.call(value, 'authEnv')) {
|
|
158
|
+
result.authEnv = stringRecord(value.authEnv, 'options.authEnv');
|
|
159
|
+
}
|
|
160
|
+
return result as BuildProviderCommandOptions;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function addDefined(result: Record<string, unknown>, key: string, value: unknown): void {
|
|
164
|
+
if (value !== undefined) result[key] = value;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function addPresent(
|
|
168
|
+
result: Record<string, unknown>,
|
|
169
|
+
input: Record<string, unknown>,
|
|
170
|
+
key: string
|
|
171
|
+
): void {
|
|
172
|
+
if (Object.prototype.hasOwnProperty.call(input, key)) result[key] = input[key];
|
|
173
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { parseProviderChunk } from './adapters';
|
|
2
|
+
import { envRedactions } from './contract-env';
|
|
3
|
+
import { optionalString } from './contract-errors';
|
|
4
|
+
import { successEnvelope, type ContractEnvelope, type ContractEvidence } from './contract-envelope';
|
|
5
|
+
import { adapterForProvider, type RequestData } from './contract-support';
|
|
6
|
+
import { tryParseJson, unknownToMessage } from './json';
|
|
7
|
+
import type { OutputEvent, ProviderAdapter } from './types';
|
|
8
|
+
|
|
9
|
+
function parseFragments(record: Record<string, unknown>): {
|
|
10
|
+
readonly chunk: string;
|
|
11
|
+
readonly sources: readonly { readonly name: string; readonly value: string }[];
|
|
12
|
+
} {
|
|
13
|
+
const sources = ['stdout', 'stderr', 'jsonl']
|
|
14
|
+
.map((name) => {
|
|
15
|
+
const value = optionalString(record, name);
|
|
16
|
+
return value === undefined ? null : { name, value };
|
|
17
|
+
})
|
|
18
|
+
.filter((value): value is { readonly name: string; readonly value: string } => value !== null);
|
|
19
|
+
return {
|
|
20
|
+
chunk: sources.map((source) => source.value).join('\n'),
|
|
21
|
+
sources,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function collectParseDiagnostics(
|
|
26
|
+
sources: readonly { readonly name: string; readonly value: string }[]
|
|
27
|
+
): readonly ContractEvidence[] {
|
|
28
|
+
const diagnostics: ContractEvidence[] = [];
|
|
29
|
+
for (const source of sources) {
|
|
30
|
+
collectSourceDiagnostics(diagnostics, source);
|
|
31
|
+
}
|
|
32
|
+
return diagnostics;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function collectSourceDiagnostics(
|
|
36
|
+
diagnostics: ContractEvidence[],
|
|
37
|
+
source: { readonly name: string; readonly value: string }
|
|
38
|
+
): void {
|
|
39
|
+
const lines = source.value.split('\n');
|
|
40
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
41
|
+
const line = lines[index]?.trim() ?? '';
|
|
42
|
+
if (!isMalformedJsonCandidate(line)) continue;
|
|
43
|
+
diagnostics.push({
|
|
44
|
+
kind: 'parse-error',
|
|
45
|
+
source: source.name,
|
|
46
|
+
line: index + 1,
|
|
47
|
+
fragment: line,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isMalformedJsonCandidate(line: string): boolean {
|
|
53
|
+
if (!line || (!line.startsWith('{') && !line.startsWith('['))) return false;
|
|
54
|
+
return tryParseJson(line) === null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function parseOutputEvents(
|
|
58
|
+
adapter: ProviderAdapter,
|
|
59
|
+
fragments: {
|
|
60
|
+
readonly chunk: string;
|
|
61
|
+
readonly sources: readonly { readonly name: string; readonly value: string }[];
|
|
62
|
+
}
|
|
63
|
+
): { readonly events: readonly OutputEvent[]; readonly diagnostics: readonly ContractEvidence[] } {
|
|
64
|
+
const diagnostics = [...collectParseDiagnostics(fragments.sources)];
|
|
65
|
+
try {
|
|
66
|
+
return {
|
|
67
|
+
events: parseProviderChunk(adapter.id, fragments.chunk),
|
|
68
|
+
diagnostics,
|
|
69
|
+
};
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return {
|
|
72
|
+
events: [],
|
|
73
|
+
diagnostics: [
|
|
74
|
+
...diagnostics,
|
|
75
|
+
{
|
|
76
|
+
kind: 'parser-error',
|
|
77
|
+
message: unknownToMessage(error),
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function runParseOutput(request: RequestData): ContractEnvelope {
|
|
85
|
+
const adapter = adapterForProvider(request.provider);
|
|
86
|
+
const fragments = parseFragments(request.raw);
|
|
87
|
+
const parsed = parseOutputEvents(adapter, fragments);
|
|
88
|
+
return successEnvelope({
|
|
89
|
+
command: request.command ?? 'parse-output',
|
|
90
|
+
adapter,
|
|
91
|
+
redactions: envRedactions(request.env),
|
|
92
|
+
result: parsed,
|
|
93
|
+
});
|
|
94
|
+
}
|