@zhivex-ai/harness 1.4.0 → 1.5.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 +32 -10
- package/README.md +7 -5
- package/SUPPORT.md +2 -2
- package/contracts/client-protocol-v1.schema.json +593 -0
- package/contracts/engine-api.json +156 -0
- package/contracts/public-api.json +12 -0
- package/contracts/stable-api-signatures.json +36 -36
- package/dist/acp-cli.js +54 -20
- package/dist/approvals/approval-diff.d.ts +2 -1
- package/dist/approvals/approval-preview.d.ts +1 -1
- package/dist/audit/index.d.ts +3 -0
- package/dist/audit/index.js +482 -0
- package/dist/audit/pack.d.ts +72 -0
- package/dist/audit-pack-kvw7ng34.js +532 -0
- package/dist/cli/arguments.d.ts +3 -1
- package/dist/cli/audit-pack.d.ts +24 -0
- package/dist/cli/cli-credentials.d.ts +6 -0
- package/dist/cli/cli-profiles.d.ts +4 -2
- package/dist/cli/node-engine.d.ts +2 -0
- package/dist/cli-entry-75j3r49b.js +484 -0
- package/dist/cli-entry-928p8h41.js +10067 -0
- package/dist/cli-entry-h2yc9x37.js +10350 -0
- package/dist/{cli-entry-20w6nh0k.js → cli-entry-hdtfef27.js} +439 -19
- package/dist/{cli-entry-w0hterjs.js → cli-entry-q8bgkn9m.js} +40 -13
- package/dist/{cli-2h37qyvg.js → cli-vyrytn3m.js} +253 -644
- package/dist/cli.js +27 -2
- package/dist/client/json-contracts.d.ts +4 -0
- package/dist/client/protocol.d.ts +133 -0
- package/dist/client/task-control-host.d.ts +400 -0
- package/dist/client/task-projection-host.d.ts +12 -0
- package/dist/client/task-projection.d.ts +168 -0
- package/dist/compat/code-support.js +28 -22
- package/dist/{config-qt69hkqj.js → config-r9fdhce6.js} +3 -3
- package/dist/{config-j9624t6t.js → config-vyajmksy.js} +1 -1
- package/dist/engine/acp.js +15 -11
- package/dist/engine/client.js +14 -10
- package/dist/engine/desktop-providers-v1.d.ts +2 -0
- package/dist/engine/desktop-providers-v1.js +23 -3
- package/dist/engine/desktop-state-v1.js +11 -8
- package/dist/engine/index.d.ts +3 -0
- package/dist/engine/index.js +101 -554
- package/dist/engine/mcp-stdio-v1.js +8 -6
- package/dist/engine/models.js +76 -4
- package/dist/engine/protocol.d.ts +2 -0
- package/dist/engine/protocol.js +110 -0
- package/dist/engine/service.js +15 -11
- package/dist/hostile-repository-demo.js +1232 -564
- package/dist/{index-8zjmnyw5.js → index-1265j7t2.js} +73 -6
- package/dist/{index-nmjdwd4p.js → index-4gt045j0.js} +109 -1
- package/dist/{index-pdmevfxv.js → index-5zbq9ztj.js} +5 -259
- package/dist/{index-6dft2vev.js → index-63gbp0cz.js} +5 -3
- package/dist/index-6dxrbnxm.js +719 -0
- package/dist/{index-pp474137.js → index-6fp7kdpx.js} +769 -933
- package/dist/{index-61gthdz6.js → index-8sm2a1wa.js} +1 -1
- package/dist/{index-rkbf7dqg.js → index-96ezrvg2.js} +57 -13
- package/dist/index-bt2p8x7r.js +329 -0
- package/dist/index-c39197wq.js +552 -0
- package/dist/{index-m82cfspw.js → index-eps3c3g6.js} +877 -963
- package/dist/{index-s2k2edts.js → index-fqqz1yt8.js} +110 -1544
- package/dist/{index-m34q25jj.js → index-ggstwr0v.js} +192 -838
- package/dist/index-jpdvn09j.js +490 -0
- package/dist/{index-xqxeypt5.js → index-mzydbzp8.js} +76 -4
- package/dist/index-pq3kz1r8.js +269 -0
- package/dist/{index-wg1sd3at.js → index-qfsrrnz6.js} +1 -1
- package/dist/{index-937cb7y8.js → index-vc7yxz50.js} +561 -35
- package/dist/{index-5jhgatga.js → index-vvzc5ezz.js} +7 -6
- package/dist/index-wwthv10a.js +1507 -0
- package/dist/{index-tfzta544.js → index-xfedewpt.js} +17 -9
- package/dist/index-yx52bt4a.js +511 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +93 -77
- package/dist/integrations/mcp-stdio-tools.d.ts +4 -1
- package/dist/internal/desktop/providers.d.ts +2 -0
- package/dist/models/catalog.d.ts +2 -0
- package/dist/persistence/sqlite-database.d.ts +1 -0
- package/dist/providers/azure-openai.d.ts +14 -0
- package/dist/providers/bedrock.d.ts +23 -0
- package/dist/providers/providers.d.ts +1 -1
- package/dist/runtime/budget-ledger-scope.d.ts +14 -0
- package/dist/runtime/durable-review-group.d.ts +33 -0
- package/dist/runtime/harness.d.ts +11 -0
- package/dist/runtime/run-interruption.d.ts +7 -0
- package/dist/runtime/shared-budget.d.ts +30 -0
- package/dist/runtime/task-continuity.d.ts +300 -77
- package/dist/service-cli.js +15 -11
- package/dist/{service-client-cli-fn54ev6w.js → service-client-cli-v6qptg9x.js} +400 -305
- package/dist/tools/workspace.d.ts +2 -2
- package/dist/verify-historical-migrations.js +1237 -566
- package/dist/workspace/edit-contracts.d.ts +2 -2
- package/dist/workspace/path-policy.d.ts +2 -1
- package/dist/workspace/workspace.d.ts +13 -0
- package/dist/zhx.js +27 -2
- package/docs/AUDIT_PACK.md +99 -0
- package/docs/AZURE_OPENAI.md +53 -0
- package/docs/BEDROCK.md +56 -0
- package/docs/CLI.md +15 -0
- package/docs/CLIENT_PROTOCOL.md +178 -0
- package/docs/CODE_RELEASE.md +59 -7
- package/docs/CODE_WEB_TASKS.md +116 -0
- package/docs/CONTEXT_ENGINEERING.md +59 -0
- package/docs/CREDENTIALS.md +21 -0
- package/docs/DURABLE_OPERATIONS.md +93 -1
- package/docs/ENGINE_API.md +5 -2
- package/docs/EXTENSIBILITY.md +8 -4
- package/docs/FIRST_USE.md +6 -6
- package/docs/MINIMUM_TASK_AUTHORITY.md +3 -3
- package/docs/PROJECT_MEMORY.md +1 -1
- package/docs/PUBLIC_SECURITY.md +14 -1
- package/docs/README.md +6 -1
- package/docs/REPOSITORY_EDITING.md +1 -1
- package/docs/STABILITY.md +3 -1
- package/docs/SUPPORT_MATRIX.md +1 -1
- package/docs/SUPPORT_MATRIX_1_1.md +1 -1
- package/docs/TOOL_POLICY.md +4 -1
- package/docs/USAGE.md +3 -1
- package/docs/VERTEX.md +2 -2
- package/docs/WEB_LIMITS.md +4 -3
- package/docs/adr/0002-isolated-mcp-stdio.md +7 -4
- package/docs/support-matrix-1.1.json +3 -1
- package/docs/support-matrix.json +6 -4
- package/evaluations/code-task-ui.json +20 -0
- package/evaluations/representative-assembly-matrix.json +19 -1
- package/evaluations/task-projection.json +10 -0
- package/evaluations/task-recovery-lab.json +60 -0
- package/examples/README.md +3 -3
- package/package.json +23 -13
- package/dist/cli-entry-4ngptr62.js +0 -19900
- package/dist/index-m49jx72n.js +0 -220
|
@@ -1,137 +1,138 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
APPROVAL_HISTORY_KEY,
|
|
4
3
|
ActivityHistory,
|
|
5
|
-
CLI_CHANGES_COMMANDS,
|
|
6
|
-
CLI_COMMANDS,
|
|
7
|
-
CLI_JSON_SCHEMA_VERSION,
|
|
8
|
-
CLI_RUNS_COMMANDS,
|
|
9
|
-
CLI_SESSIONS_COMMANDS,
|
|
10
|
-
CLI_STATE_COMMANDS,
|
|
11
4
|
CliCredentials,
|
|
12
|
-
CliOciRuntimeAdapter,
|
|
13
|
-
CliUsageError,
|
|
14
5
|
ConsoleInput,
|
|
15
6
|
CredentialSetupError,
|
|
16
7
|
DEFAULT_HARNESS_CONTEXT_MANIFEST,
|
|
17
|
-
FileChangedWhileReadingError,
|
|
18
|
-
FileSizeLimitError,
|
|
19
|
-
HARNESS_OPERATIONS_SCHEMA_VERSION,
|
|
20
8
|
HARNESS_RESUME_METADATA_KEY,
|
|
21
9
|
HARNESS_RESUME_METADATA_SCHEMA_VERSION,
|
|
22
|
-
HARNESS_SESSION_SCHEMA_VERSION,
|
|
23
|
-
HARNESS_SQLITE_FILE,
|
|
24
10
|
MAX_HARNESS_CONTEXT_FILE_BYTES,
|
|
25
11
|
MAX_HARNESS_CONTEXT_TOTAL_BYTES,
|
|
26
|
-
SqliteDatabase,
|
|
27
|
-
TASK_ACCEPTANCE_EVIDENCE_KEY,
|
|
28
|
-
TASK_SOURCE_KEY,
|
|
29
|
-
USAGE_LEDGER_KEY,
|
|
30
|
-
UnsafeFileTypeError,
|
|
31
|
-
Workspace,
|
|
32
12
|
annotateCliStreamError,
|
|
33
13
|
appendUserMessage,
|
|
34
|
-
applyCliProfile,
|
|
35
|
-
approvalDecisionViews,
|
|
36
14
|
approvalResponses,
|
|
37
15
|
assertRoutePricingIsSafe,
|
|
38
|
-
assertTaskBudgetBackupLinks,
|
|
39
|
-
cancelHarnessRun,
|
|
40
|
-
canonicalizeChangeEnvelope,
|
|
41
|
-
changeEnvelopePreconditionsSchema,
|
|
42
|
-
changeEnvelopeSchema,
|
|
43
16
|
chooseReasoning,
|
|
44
|
-
cleanupHarnessExecutionArtifacts,
|
|
45
|
-
cleanupHarnessRuns,
|
|
46
17
|
cliStreamErrorSequence,
|
|
47
18
|
compactHarnessMessages,
|
|
48
|
-
createChangeEnvelope,
|
|
49
|
-
createCliProfile,
|
|
50
19
|
createConfiguredHarness,
|
|
51
20
|
createHarness,
|
|
52
21
|
createHarnessResumeMetadata,
|
|
53
|
-
createHarnessRouteModels,
|
|
54
22
|
credentialModel,
|
|
55
23
|
decodeProjectMemory,
|
|
56
|
-
digestChangeEnvelopeArtifact,
|
|
57
24
|
estimateMessages,
|
|
58
|
-
fileDigestSchema,
|
|
59
25
|
flushToolActivity,
|
|
60
26
|
formatAppliedFiles,
|
|
61
27
|
formatConsoleHelp,
|
|
62
28
|
formatConsoleWelcome,
|
|
63
|
-
formatUsageLedger,
|
|
64
29
|
formatVerificationSummary,
|
|
65
30
|
harnessConfigInput,
|
|
66
|
-
harnessPolicyDecisionEventSchema,
|
|
67
|
-
harnessToolExecution,
|
|
68
31
|
inspectCliPolicy,
|
|
69
|
-
inspectHarnessRun,
|
|
70
|
-
inspectRuntimeDiagnostics,
|
|
71
|
-
inspectRuntimeManifest,
|
|
72
|
-
inspectUsageLedger,
|
|
73
32
|
issueAutomaticApprovalResponses,
|
|
74
33
|
issueObservedApprovalResponses,
|
|
75
|
-
listHarnessRuns,
|
|
76
|
-
loadCliProfile,
|
|
77
34
|
loadHarnessMcpConfiguration,
|
|
78
35
|
loadHarnessProjectContext,
|
|
79
36
|
loadModelCatalog,
|
|
80
37
|
navigateConsole,
|
|
81
38
|
observeCliPolicy,
|
|
82
|
-
openCliSessionStore,
|
|
83
|
-
openHarnessActivityStore,
|
|
84
|
-
openHarnessPersistence,
|
|
85
39
|
openHarnessProjectMemory,
|
|
86
40
|
openWorkspaceCheckpointStore,
|
|
87
41
|
orchestrationObserver,
|
|
88
|
-
parseCliArgs,
|
|
89
|
-
parseHarnessModelRoute,
|
|
90
42
|
persistedCliOptions,
|
|
91
43
|
printTerminalResult,
|
|
92
44
|
projectMemoryRecordKey,
|
|
93
|
-
publishPendingPolicyDecision,
|
|
94
45
|
readHarnessResumeConfig,
|
|
95
46
|
readHarnessResumeRoutes,
|
|
96
|
-
readRegularFileChunksNoFollow,
|
|
97
|
-
readRegularFileNoFollow,
|
|
98
|
-
readTaskAcceptanceLedger,
|
|
99
47
|
requiresExplicitHostReview,
|
|
100
|
-
resolveCliDefaults,
|
|
101
|
-
resolveHarnessModelRoutes,
|
|
102
|
-
resolvePackageManager,
|
|
103
48
|
resolvedRouting,
|
|
104
49
|
resumeCommand,
|
|
105
50
|
runHarness,
|
|
106
51
|
runHarnessReviewGroup,
|
|
107
|
-
runPortableProcess,
|
|
108
52
|
runResultDocument,
|
|
109
53
|
sanitizeTerminalText,
|
|
110
|
-
serializeHarnessModelRoutes,
|
|
111
|
-
sqliteAdapter,
|
|
112
54
|
streamSink,
|
|
113
55
|
summarizeApproval,
|
|
114
|
-
taskCheckReceiptSchema,
|
|
115
|
-
taskSources,
|
|
116
56
|
terminalApprovalResolver,
|
|
117
57
|
terminalContinuationMessages,
|
|
118
58
|
terminalErrorMessage,
|
|
119
59
|
terminalRunFailure,
|
|
120
60
|
terminalSupportsColor,
|
|
121
|
-
updateCliProfile,
|
|
122
|
-
validateStateDirectory,
|
|
123
|
-
verifyChangeEnvelope,
|
|
124
61
|
withTemporaryHarnessProfiles,
|
|
125
62
|
workspaceCheckpointSchema,
|
|
126
63
|
workspaceRestoreOperationSchema
|
|
127
|
-
} from "./cli-entry-
|
|
64
|
+
} from "./cli-entry-h2yc9x37.js";
|
|
65
|
+
import {
|
|
66
|
+
exportHarnessGovernanceReport,
|
|
67
|
+
renderHarnessGovernanceMarkdown
|
|
68
|
+
} from "./cli-entry-75j3r49b.js";
|
|
69
|
+
import {
|
|
70
|
+
BUDGET_LEDGER_NAMESPACE,
|
|
71
|
+
BUDGET_OWNER_NAMESPACE_KEY,
|
|
72
|
+
CLI_CHANGES_COMMANDS,
|
|
73
|
+
CLI_COMMANDS,
|
|
74
|
+
CLI_JSON_SCHEMA_VERSION,
|
|
75
|
+
CLI_RUNS_COMMANDS,
|
|
76
|
+
CLI_SESSIONS_COMMANDS,
|
|
77
|
+
CLI_STATE_COMMANDS,
|
|
78
|
+
CliOciRuntimeAdapter,
|
|
79
|
+
CliUsageError,
|
|
80
|
+
FileChangedWhileReadingError,
|
|
81
|
+
FileSizeLimitError,
|
|
82
|
+
HARNESS_OPERATIONS_SCHEMA_VERSION,
|
|
83
|
+
HARNESS_SESSION_SCHEMA_VERSION,
|
|
84
|
+
HARNESS_SQLITE_FILE,
|
|
85
|
+
SqliteDatabase,
|
|
86
|
+
TASK_SOURCE_KEY,
|
|
87
|
+
USAGE_LEDGER_KEY,
|
|
88
|
+
UnsafeFileTypeError,
|
|
89
|
+
Workspace,
|
|
90
|
+
applyCliProfile,
|
|
91
|
+
assertTaskBudgetBackupLinks,
|
|
92
|
+
budgetLedgerNamespace,
|
|
93
|
+
cancelHarnessRun,
|
|
94
|
+
canonicalizeChangeEnvelope,
|
|
95
|
+
changeEnvelopePreconditionsSchema,
|
|
96
|
+
cleanupHarnessExecutionArtifacts,
|
|
97
|
+
cleanupHarnessRuns,
|
|
98
|
+
createChangeEnvelope,
|
|
99
|
+
createCliProfile,
|
|
100
|
+
createHarnessRouteModels,
|
|
101
|
+
digestChangeEnvelopeArtifact,
|
|
102
|
+
fileDigestSchema,
|
|
103
|
+
formatUsageLedger,
|
|
104
|
+
harnessToolExecution,
|
|
105
|
+
inspectHarnessRun,
|
|
106
|
+
inspectRuntimeDiagnostics,
|
|
107
|
+
inspectUsageLedger,
|
|
108
|
+
listHarnessRuns,
|
|
109
|
+
loadCliProfile,
|
|
110
|
+
openCliSessionStore,
|
|
111
|
+
openHarnessActivityStore,
|
|
112
|
+
openHarnessPersistence,
|
|
113
|
+
parseCliArgs,
|
|
114
|
+
parseHarnessModelRoute,
|
|
115
|
+
publishPendingPolicyDecision,
|
|
116
|
+
readRegularFileChunksNoFollow,
|
|
117
|
+
readRegularFileNoFollow,
|
|
118
|
+
resolveCliDefaults,
|
|
119
|
+
resolveHarnessModelRoutes,
|
|
120
|
+
resolvePackageManager,
|
|
121
|
+
runPortableProcess,
|
|
122
|
+
serializeHarnessModelRoutes,
|
|
123
|
+
sqliteAdapter,
|
|
124
|
+
taskSources,
|
|
125
|
+
updateCliProfile,
|
|
126
|
+
validateStateDirectory,
|
|
127
|
+
verifyChangeEnvelope
|
|
128
|
+
} from "./cli-entry-928p8h41.js";
|
|
128
129
|
import {
|
|
129
130
|
BUN_ENGINE_RANGE,
|
|
130
131
|
HARNESS_VERSION,
|
|
131
132
|
NODE_ENGINE_RANGE,
|
|
132
133
|
formatCliHelp,
|
|
133
134
|
shortCliHelp
|
|
134
|
-
} from "./cli-entry-
|
|
135
|
+
} from "./cli-entry-q8bgkn9m.js";
|
|
135
136
|
import {
|
|
136
137
|
DEFAULT_PROVIDER_REGISTRY,
|
|
137
138
|
HARNESS_SUBAGENT_PROFILES,
|
|
@@ -147,7 +148,7 @@ import {
|
|
|
147
148
|
providerDescriptor,
|
|
148
149
|
reasoningEffortSchema,
|
|
149
150
|
resolveHarnessConfig
|
|
150
|
-
} from "./cli-entry-
|
|
151
|
+
} from "./cli-entry-hdtfef27.js";
|
|
151
152
|
import {
|
|
152
153
|
__require
|
|
153
154
|
} from "./cli-entry-1bx83sw4.js";
|
|
@@ -237,7 +238,7 @@ var initializeCli = async (options, context = {}) => {
|
|
|
237
238
|
process.stdout.write([
|
|
238
239
|
`${options.updateProfile ? "Updated" : "Created"} personal profile ${profileName} at ${created.path}.`,
|
|
239
240
|
`Provider: ${created.profile.provider} · Model: ${created.profile.model} · Reasoning: ${created.profile.reasoningEffort ?? "default"}`,
|
|
240
|
-
provider === "vertex" ? "Vertex uses host ADC. Set GOOGLE_CLOUD_PROJECT and VERTEX_LOCATION; route presence does not verify credentials or model access." : availability?.configured ? "Provider credential detected; no secret value was stored or printed." : `Open zhx to configure a managed key, or set ${availability?.credentialNames.join(" or ") || "the provider credential"} for automation.`,
|
|
241
|
+
provider === "vertex" ? "Vertex uses host ADC. Set GOOGLE_CLOUD_PROJECT and VERTEX_LOCATION; route presence does not verify credentials or model access." : provider === "bedrock" ? "Bedrock Converse uses the AWS credential chain and AWS_REGION or AWS_DEFAULT_REGION. BEDROCK_RUNTIME=openai also needs an https BEDROCK_OPENAI_BASE_URL and BEDROCK_API_KEY or AWS_BEARER_TOKEN_BEDROCK. Route presence does not verify credentials or model access." : provider === "azure-openai" ? "Azure OpenAI needs an https AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY. Optional AZURE_OPENAI_API_VERSION and AZURE_OPENAI_DEPLOYMENTS stay in the environment. Route presence does not verify account access." : availability?.configured ? "Provider credential detected; no secret value was stored or printed." : `Open zhx to configure a managed key, or set ${availability?.credentialNames.join(" or ") || "the provider credential"} for automation.`,
|
|
241
242
|
"Next:",
|
|
242
243
|
` ${doctorCommand}`,
|
|
243
244
|
` ${runCommand}`,
|
|
@@ -247,6 +248,31 @@ var initializeCli = async (options, context = {}) => {
|
|
|
247
248
|
`);
|
|
248
249
|
return true;
|
|
249
250
|
};
|
|
251
|
+
var providerStatus = (provider, env = process.env) => {
|
|
252
|
+
if (provider.id === "vertex")
|
|
253
|
+
return provider.configured ? "route configured; ADC not checked" : "missing GOOGLE_CLOUD_PROJECT/VERTEX_LOCATION";
|
|
254
|
+
if (provider.id === "bedrock") {
|
|
255
|
+
if (provider.configuration.runtimeValid === false)
|
|
256
|
+
return "invalid BEDROCK_RUNTIME";
|
|
257
|
+
if (provider.configured)
|
|
258
|
+
return "route configured; AWS credentials not checked";
|
|
259
|
+
if (env.BEDROCK_RUNTIME?.trim() === "openai")
|
|
260
|
+
return "missing BEDROCK_API_KEY/AWS_BEARER_TOKEN_BEDROCK or https BEDROCK_OPENAI_BASE_URL";
|
|
261
|
+
return "missing AWS_REGION/AWS_DEFAULT_REGION";
|
|
262
|
+
}
|
|
263
|
+
if (provider.id === "azure-openai") {
|
|
264
|
+
if (!provider.configuration.customEndpoint)
|
|
265
|
+
return "missing AZURE_OPENAI_ENDPOINT";
|
|
266
|
+
if (!provider.configuration.endpointValid || !provider.configuration.endpointSecure)
|
|
267
|
+
return "invalid AZURE_OPENAI_ENDPOINT";
|
|
268
|
+
if (!provider.credentials.some((credential) => credential.present))
|
|
269
|
+
return "missing AZURE_OPENAI_API_KEY";
|
|
270
|
+
if (!provider.configured)
|
|
271
|
+
return "invalid AZURE_OPENAI_API_VERSION or AZURE_OPENAI_DEPLOYMENTS";
|
|
272
|
+
return "configured; account access not checked";
|
|
273
|
+
}
|
|
274
|
+
return provider.configured ? "configured" : `missing ${provider.credentialNames.join("/")}`;
|
|
275
|
+
};
|
|
250
276
|
var listProviders = (json) => {
|
|
251
277
|
const document = providersDocument();
|
|
252
278
|
if (json) {
|
|
@@ -255,7 +281,7 @@ var listProviders = (json) => {
|
|
|
255
281
|
return;
|
|
256
282
|
}
|
|
257
283
|
for (const provider of document.providers) {
|
|
258
|
-
process.stdout.write(`${provider.id.padEnd(
|
|
284
|
+
process.stdout.write(`${provider.id.padEnd(13)} ${provider.defaultModel.padEnd(28)} ${provider.support.padEnd(11)} ${providerStatus(provider)}
|
|
259
285
|
`);
|
|
260
286
|
}
|
|
261
287
|
};
|
|
@@ -299,6 +325,8 @@ Advanced operations and automation:
|
|
|
299
325
|
zhx state status
|
|
300
326
|
zhx state export <backup.json>
|
|
301
327
|
zhx state import <backup.json> [--apply]
|
|
328
|
+
zhx export-audit <task-id> --out <directory>
|
|
329
|
+
zhx verify-audit --out <directory>
|
|
302
330
|
|
|
303
331
|
The long command zhivex-harness remains supported for compatibility.
|
|
304
332
|
|
|
@@ -378,6 +406,8 @@ Options (automation and advanced configuration):
|
|
|
378
406
|
--cascade Cancel a run and its known child runs
|
|
379
407
|
--final Record terminal cancellation immediately
|
|
380
408
|
--apply Apply a validated state import (default: dry-run)
|
|
409
|
+
--out <directory> Audit pack directory (export-audit, verify-audit)
|
|
410
|
+
--signing-key-file <path> HMAC key file for an audit pack
|
|
381
411
|
-h, --help Show this help
|
|
382
412
|
-v, --version Show the version
|
|
383
413
|
|
|
@@ -758,6 +788,32 @@ var inspectProjectContext = async (config) => {
|
|
|
758
788
|
});
|
|
759
789
|
}
|
|
760
790
|
};
|
|
791
|
+
var bedrockDoctorMessage = (provider, configured, env) => {
|
|
792
|
+
if (provider.configuration.runtimeValid === false)
|
|
793
|
+
return "BEDROCK_RUNTIME must be converse or openai.";
|
|
794
|
+
if (provider.configuration.customEndpoint && (!provider.configuration.endpointValid || !provider.configuration.endpointSecure)) {
|
|
795
|
+
return "BEDROCK_OPENAI_BASE_URL must be an https URL without credentials.";
|
|
796
|
+
}
|
|
797
|
+
if (configured)
|
|
798
|
+
return "Amazon Bedrock route configured; AWS credentials and model access have not been checked. Live support is provisional.";
|
|
799
|
+
if (env.BEDROCK_RUNTIME?.trim() === "openai") {
|
|
800
|
+
return "Bedrock OpenAI-compatible runtime requires BEDROCK_API_KEY or AWS_BEARER_TOKEN_BEDROCK and an https BEDROCK_OPENAI_BASE_URL.";
|
|
801
|
+
}
|
|
802
|
+
return "Bedrock Converse requires a valid AWS_REGION or AWS_DEFAULT_REGION. No API key is stored for the AWS credential chain.";
|
|
803
|
+
};
|
|
804
|
+
var azureDoctorMessage = (provider, configured, credential) => {
|
|
805
|
+
if (!provider.configuration.customEndpoint)
|
|
806
|
+
return "Azure OpenAI requires AZURE_OPENAI_ENDPOINT.";
|
|
807
|
+
if (!provider.configuration.endpointValid || !provider.configuration.endpointSecure) {
|
|
808
|
+
return "AZURE_OPENAI_ENDPOINT must be an https URL without credentials or a query.";
|
|
809
|
+
}
|
|
810
|
+
if (!configured && (provider.credentials.some((item) => item.present) || credential?.configured)) {
|
|
811
|
+
return "AZURE_OPENAI_API_VERSION or AZURE_OPENAI_DEPLOYMENTS is invalid.";
|
|
812
|
+
}
|
|
813
|
+
if (!configured)
|
|
814
|
+
return "Azure OpenAI credential is missing. Set AZURE_OPENAI_API_KEY. Account access is not checked.";
|
|
815
|
+
return "Azure OpenAI route configured; account access has not been checked. Live support is provisional.";
|
|
816
|
+
};
|
|
761
817
|
var createDoctorReport = async (options = {}, context = {}) => {
|
|
762
818
|
const env = context.env ?? process.env;
|
|
763
819
|
const config = resolveHarnessConfig({
|
|
@@ -824,12 +880,13 @@ var createDoctorReport = async (options = {}, context = {}) => {
|
|
|
824
880
|
checks.push(await inspectExecutionEnvironment(config.execution, context.ociRuntimeAdapter));
|
|
825
881
|
for (const provider of providers) {
|
|
826
882
|
const invalidRegion = provider.id === "qwen" && provider.configuration.regionValid === false;
|
|
827
|
-
const
|
|
883
|
+
const invalidRuntime = provider.id === "bedrock" && provider.configuration.runtimeValid === false;
|
|
884
|
+
const invalidEndpoint = !provider.configuration.endpointValid || (provider.id === "bedrock" || provider.id === "azure-openai") && provider.configuration.customEndpoint && !provider.configuration.endpointSecure;
|
|
828
885
|
const selected = provider.id === selectedProvider?.id;
|
|
829
886
|
const credential = selected ? context.credentialStatus : undefined;
|
|
830
887
|
const configured = credential?.configured ?? provider.configured;
|
|
831
|
-
const status = invalidRegion || invalidEndpoint || !configured ? selected ? "fail" : "warn" : provider.support === "provisional" ? "warn" : "pass";
|
|
832
|
-
const message = provider.id === "vertex" ? configured ? "Vertex project/location configured; host ADC and model access have not been checked. Live support is provisional." : "Vertex requires GOOGLE_CLOUD_PROJECT and VERTEX_LOCATION plus host Application Default Credentials. No API key is stored by zhx." : invalidEndpoint ? `${provider.name} custom endpoint configuration is invalid.` : invalidRegion ? "Qwen region configuration is invalid." : credential ? credential.configured ? `${provider.name} credential present (${credential.source}); account access has not been checked.${provider.support === "provisional" ? " Live support is provisional." : ""}` : credential.source === "blocked" ? `${provider.name} managed credentials require the default endpoint. Remove endpoint overrides or provide an environment key.` : `${provider.name} credential ${credential.source === "unavailable" ? "could not be checked: keychain unavailable or locked" : "is missing"}. Run zhx to configure a key, or set ${provider.credentialNames.join(" or ")} for automation.` : provider.configured ? provider.support === "provisional" ? `${provider.name} credentials are present, but live support is provisional.` : `${provider.name} credentials are present.` : `${provider.name} credentials are missing. Set ${provider.credentialNames.join(" or ")} in the environment and rerun zhx doctor.`;
|
|
888
|
+
const status = invalidRegion || invalidRuntime || invalidEndpoint || !configured ? selected ? "fail" : "warn" : provider.support === "provisional" ? "warn" : "pass";
|
|
889
|
+
const message = provider.id === "vertex" ? configured ? "Vertex project/location configured; host ADC and model access have not been checked. Live support is provisional." : "Vertex requires GOOGLE_CLOUD_PROJECT and VERTEX_LOCATION plus host Application Default Credentials. No API key is stored by zhx." : provider.id === "bedrock" ? bedrockDoctorMessage(provider, configured, env) : provider.id === "azure-openai" ? azureDoctorMessage(provider, configured, credential) : invalidEndpoint ? `${provider.name} custom endpoint configuration is invalid.` : invalidRegion ? "Qwen region configuration is invalid." : credential ? credential.configured ? `${provider.name} credential present (${credential.source}); account access has not been checked.${provider.support === "provisional" ? " Live support is provisional." : ""}` : credential.source === "blocked" ? `${provider.name} managed credentials require the default endpoint. Remove endpoint overrides or provide an environment key.` : `${provider.name} credential ${credential.source === "unavailable" ? "could not be checked: keychain unavailable or locked" : "is missing"}. Run zhx to configure a key, or set ${provider.credentialNames.join(" or ")} for automation.` : provider.configured ? provider.support === "provisional" ? `${provider.name} credentials are present, but live support is provisional.` : `${provider.name} credentials are present.` : `${provider.name} credentials are missing. Set ${provider.credentialNames.join(" or ")} in the environment and rerun zhx doctor.`;
|
|
833
890
|
checks.push(diagnostic(`provider:${provider.id}`, status, message, {
|
|
834
891
|
provider: provider.id,
|
|
835
892
|
selected,
|
|
@@ -845,6 +902,17 @@ var createDoctorReport = async (options = {}, context = {}) => {
|
|
|
845
902
|
regionConfigured: provider.configuration.regionConfigured,
|
|
846
903
|
regionValid: provider.configuration.regionValid,
|
|
847
904
|
workspaceIdConfigured: provider.configuration.workspaceIdConfigured
|
|
905
|
+
} : {},
|
|
906
|
+
...provider.id === "bedrock" ? {
|
|
907
|
+
runtimeConfigured: provider.configuration.runtimeConfigured === true,
|
|
908
|
+
runtimeValid: provider.configuration.runtimeValid !== false,
|
|
909
|
+
regionConfigured: provider.configuration.regionConfigured === true,
|
|
910
|
+
defaultRegionConfigured: provider.configuration.defaultRegionConfigured === true,
|
|
911
|
+
profileConfigured: provider.configuration.profileConfigured === true
|
|
912
|
+
} : {},
|
|
913
|
+
...provider.id === "azure-openai" ? {
|
|
914
|
+
apiVersionConfigured: provider.configuration.apiVersionConfigured === true,
|
|
915
|
+
deploymentsConfigured: provider.configuration.deploymentsConfigured === true
|
|
848
916
|
} : {}
|
|
849
917
|
}));
|
|
850
918
|
}
|
|
@@ -1383,7 +1451,7 @@ async function handleConsoleCompaction(command, deps) {
|
|
|
1383
1451
|
const provider = value.slice(0, separator);
|
|
1384
1452
|
const model = value.slice(separator + 1);
|
|
1385
1453
|
if (separator < 1 || !PROVIDERS.includes(provider) || !/^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,159}$/.test(model)) {
|
|
1386
|
-
write(
|
|
1454
|
+
write(`Use /compaction provider:model with ${PROVIDERS.slice(0, -1).join(", ")} or ${PROVIDERS.at(-1)}; /compaction off disables model-assisted compaction.`);
|
|
1387
1455
|
return true;
|
|
1388
1456
|
}
|
|
1389
1457
|
await deps.replaceOptions({ ...deps.options, compactionProvider: provider, compactionModel: model });
|
|
@@ -2493,474 +2561,6 @@ ${summarizeApproval(approval)}
|
|
|
2493
2561
|
|
|
2494
2562
|
// src/cli/governance-report.ts
|
|
2495
2563
|
import path2 from "node:path";
|
|
2496
|
-
|
|
2497
|
-
// src/persistence/governance-report.ts
|
|
2498
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
2499
|
-
import { z as z2 } from "zod";
|
|
2500
|
-
|
|
2501
|
-
// src/persistence/governance-context.ts
|
|
2502
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
2503
|
-
import { z } from "zod";
|
|
2504
|
-
var digest = z.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
2505
|
-
var count = z.number().int().nonnegative().safe();
|
|
2506
|
-
var governanceReference = (kind, value) => "sha256:" + createHash2("sha256").update(JSON.stringify([kind, value])).digest("hex");
|
|
2507
|
-
var governanceSessionSchema = z.strictObject({ availability: z.enum(["recorded", "unavailable"]), reference: digest.nullable(), revision: count.nullable() });
|
|
2508
|
-
var governanceHistorySchema = z.strictObject({
|
|
2509
|
-
availability: z.enum(["recorded", "unavailable"]),
|
|
2510
|
-
retention: z.enum(["unknown", "retained", "expired"]),
|
|
2511
|
-
incomplete: z.boolean(),
|
|
2512
|
-
policyDecisions: z.array(z.strictObject({
|
|
2513
|
-
runReference: digest,
|
|
2514
|
-
sequence: count,
|
|
2515
|
-
toolReference: digest,
|
|
2516
|
-
phase: z.enum(["approval-request", "tool-entry"]),
|
|
2517
|
-
decision: z.enum(["allow", "ask_user", "deny"]),
|
|
2518
|
-
policyDigest: digest.nullable(),
|
|
2519
|
-
source: z.enum(["operator-file", "application", "baseline"]),
|
|
2520
|
-
ruleReferences: z.array(digest).max(128),
|
|
2521
|
-
explicitReviewRequired: z.boolean()
|
|
2522
|
-
})).max(512)
|
|
2523
|
-
});
|
|
2524
|
-
var governanceEnvelopeSchema = z.strictObject({
|
|
2525
|
-
source: z.literal("caller-supplied"),
|
|
2526
|
-
envelopeId: digest.nullable(),
|
|
2527
|
-
patchReference: digest.nullable(),
|
|
2528
|
-
patchDigest: digest.nullable(),
|
|
2529
|
-
linkedRunReferences: z.array(digest).max(64),
|
|
2530
|
-
schemaValid: z.boolean(),
|
|
2531
|
-
integrity: z.enum(["valid", "invalid"]),
|
|
2532
|
-
expiration: z.enum(["unknown", "current", "expired", "not-yet-valid"]),
|
|
2533
|
-
checkedAt: z.iso.datetime(),
|
|
2534
|
-
expiredApprovals: count,
|
|
2535
|
-
authenticity: z.literal("not-verified"),
|
|
2536
|
-
patchBytes: z.literal("not-verified")
|
|
2537
|
-
});
|
|
2538
|
-
async function readGovernanceSession(source, rootRunId, runIds) {
|
|
2539
|
-
const session = { availability: "unavailable", reference: null, revision: null };
|
|
2540
|
-
const history = { availability: "unavailable", retention: "unknown", incomplete: true, policyDecisions: [] };
|
|
2541
|
-
if (!source)
|
|
2542
|
-
return { session, history, verify: async () => {} };
|
|
2543
|
-
const initial = await source.index.get(source.id);
|
|
2544
|
-
if (!initial || initial.sessionId !== source.id || !initial.runs.some((run) => run.runId === rootRunId))
|
|
2545
|
-
throw new Error("GOVERNANCE_SESSION_MISMATCH");
|
|
2546
|
-
const captured = JSON.stringify(initial);
|
|
2547
|
-
session.availability = "recorded";
|
|
2548
|
-
session.reference = governanceReference("session", initial.sessionId);
|
|
2549
|
-
session.revision = initial.revision;
|
|
2550
|
-
const pages = [];
|
|
2551
|
-
if (source.history) {
|
|
2552
|
-
let cursor = 0;
|
|
2553
|
-
history.availability = "recorded";
|
|
2554
|
-
history.retention = "retained";
|
|
2555
|
-
history.incomplete = false;
|
|
2556
|
-
for (let pageIndex = 0;pageIndex < 50; pageIndex++) {
|
|
2557
|
-
const page = source.history.replay(source.id, cursor);
|
|
2558
|
-
pages.push({ cursor, digest: governanceReference("history-page", JSON.stringify(page)) });
|
|
2559
|
-
if (page.schemaVersion !== 1 || !Number.isSafeInteger(page.nextCursor) || page.nextCursor < cursor || page.events.length > 200)
|
|
2560
|
-
throw new Error("GOVERNANCE_HISTORY_INVALID");
|
|
2561
|
-
if (page.cursorExpired || page.policyEvidenceIncomplete) {
|
|
2562
|
-
history.retention = "expired";
|
|
2563
|
-
history.incomplete = true;
|
|
2564
|
-
}
|
|
2565
|
-
let lastSequence = cursor;
|
|
2566
|
-
for (const event of page.events) {
|
|
2567
|
-
if (event.sessionId !== source.id || !Number.isSafeInteger(event.sequence) || event.sequence <= lastSequence || event.sequence > page.nextCursor)
|
|
2568
|
-
throw new Error("GOVERNANCE_HISTORY_INVALID");
|
|
2569
|
-
lastSequence = event.sequence;
|
|
2570
|
-
if (!runIds.has(event.runId) || event.activity.type !== "policy-decision")
|
|
2571
|
-
continue;
|
|
2572
|
-
const parsed = harnessPolicyDecisionEventSchema.safeParse(event.activity);
|
|
2573
|
-
if (!parsed.success) {
|
|
2574
|
-
history.incomplete = true;
|
|
2575
|
-
continue;
|
|
2576
|
-
}
|
|
2577
|
-
if (history.policyDecisions.length === 512) {
|
|
2578
|
-
history.incomplete = true;
|
|
2579
|
-
continue;
|
|
2580
|
-
}
|
|
2581
|
-
const value = parsed.data;
|
|
2582
|
-
history.policyDecisions.push({
|
|
2583
|
-
runReference: governanceReference("run", event.runId),
|
|
2584
|
-
sequence: event.sequence,
|
|
2585
|
-
toolReference: governanceReference("tool", value.toolName),
|
|
2586
|
-
phase: value.phase,
|
|
2587
|
-
decision: value.decision,
|
|
2588
|
-
policyDigest: value.policyDigest,
|
|
2589
|
-
source: value.source,
|
|
2590
|
-
ruleReferences: value.ruleIds.map((rule) => governanceReference("rule", rule)),
|
|
2591
|
-
explicitReviewRequired: value.explicitReviewRequired
|
|
2592
|
-
});
|
|
2593
|
-
}
|
|
2594
|
-
if (page.cursorExpired || !page.hasMore)
|
|
2595
|
-
break;
|
|
2596
|
-
if (page.nextCursor === cursor)
|
|
2597
|
-
throw new Error("GOVERNANCE_HISTORY_INVALID");
|
|
2598
|
-
cursor = page.nextCursor;
|
|
2599
|
-
if (pageIndex === 49)
|
|
2600
|
-
history.incomplete = true;
|
|
2601
|
-
}
|
|
2602
|
-
}
|
|
2603
|
-
return { session, history, verify: async () => {
|
|
2604
|
-
for (const page of pages)
|
|
2605
|
-
if (governanceReference("history-page", JSON.stringify(source.history.replay(source.id, page.cursor))) !== page.digest)
|
|
2606
|
-
throw new Error("GOVERNANCE_STATE_CHANGED");
|
|
2607
|
-
if (JSON.stringify(await source.index.get(source.id)) !== captured)
|
|
2608
|
-
throw new Error("GOVERNANCE_STATE_CHANGED");
|
|
2609
|
-
} };
|
|
2610
|
-
}
|
|
2611
|
-
function projectGovernanceEnvelopes(envelopes, patches, now) {
|
|
2612
|
-
if (envelopes.length > 32)
|
|
2613
|
-
throw new Error("GOVERNANCE_ENVELOPE_LIMIT");
|
|
2614
|
-
return envelopes.map((input) => {
|
|
2615
|
-
if (Buffer.byteLength(JSON.stringify(input) ?? "") > 256 * 1024)
|
|
2616
|
-
throw new Error("GOVERNANCE_ENVELOPE_LIMIT");
|
|
2617
|
-
const parsed = changeEnvelopeSchema.safeParse(input);
|
|
2618
|
-
const proof = verifyChangeEnvelope(input, { now });
|
|
2619
|
-
const envelope = parsed.success ? parsed.data : undefined;
|
|
2620
|
-
return governanceEnvelopeSchema.parse({
|
|
2621
|
-
source: "caller-supplied",
|
|
2622
|
-
envelopeId: envelope?.envelopeId ?? null,
|
|
2623
|
-
patchReference: envelope ? governanceReference("patch", envelope.patch.patchId) : null,
|
|
2624
|
-
patchDigest: envelope?.patch.patchDigest ?? null,
|
|
2625
|
-
linkedRunReferences: envelope ? [...patches.get(envelope.patch.patchId) ?? []] : [],
|
|
2626
|
-
schemaValid: parsed.success,
|
|
2627
|
-
integrity: proof.integrity.envelopeDigestValid && proof.integrity.evidenceDigestValid ? "valid" : "invalid",
|
|
2628
|
-
expiration: !envelope ? "unknown" : proof.expiration.envelopeNotYetValid ? "not-yet-valid" : proof.expiration.envelopeExpired ? "expired" : "current",
|
|
2629
|
-
checkedAt: proof.expiration.checkedAt,
|
|
2630
|
-
expiredApprovals: proof.expiration.expiredApprovalIds.length,
|
|
2631
|
-
authenticity: "not-verified",
|
|
2632
|
-
patchBytes: "not-verified"
|
|
2633
|
-
});
|
|
2634
|
-
});
|
|
2635
|
-
}
|
|
2636
|
-
|
|
2637
|
-
// src/persistence/governance-report.ts
|
|
2638
|
-
var digest2 = z2.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
2639
|
-
var version = z2.string().regex(/^\d+\.\d+\.\d+(?:[-+][a-zA-Z0-9.-]+)?$/);
|
|
2640
|
-
var bindingSchema = z2.object({ schemaVersion: z2.literal(1), id: z2.literal("zhivex-harness"), version, fingerprint: digest2, algorithm: z2.literal("sha256") });
|
|
2641
|
-
var count2 = z2.number().int().nonnegative().safe();
|
|
2642
|
-
var status = z2.enum(["created", "running", "waiting_approval", "cancel_requested", "completed", "failed", "cancelled", "timed_out", "unknown"]);
|
|
2643
|
-
var availability = z2.enum(["recorded", "unavailable", "invalid"]);
|
|
2644
|
-
var providerReason = z2.enum(["empty_arguments", "invalid_json", "arguments_too_large", "incomplete_arguments", "inconsistent_metadata", "response_failed", "response_incomplete", "stream_truncated"]);
|
|
2645
|
-
var deliveryReason = z2.enum(["TASK_ACCEPTANCE_NO_DELIVERY_EVIDENCE", "TASK_ACCEPTANCE_SCOPE_VIOLATION", "TASK_ACCEPTANCE_RUN_NOT_COMPLETED", "TASK_ACCEPTANCE_RUN_NOT_FINISHED", "TASK_ACCEPTANCE_IMPORT_UNCONFIRMED", "TASK_ACCEPTANCE_CHECKS_MISSING", "TASK_ACCEPTANCE_DELIVERY_DRIFT", "TASK_ACCEPTANCE_DELIVERY_INSPECTION_FAILED", "TASK_ACCEPTANCE_HUMAN_REVIEW_REQUIRED", "TASK_ACCEPTANCE_VERIFIED"]);
|
|
2646
|
-
var deliveryStatus = z2.enum(["pending", "incomplete", "failed", "pending_review", "verified", "unknown"]);
|
|
2647
|
-
var checkSchema = z2.strictObject({
|
|
2648
|
-
reference: digest2,
|
|
2649
|
-
argvDigest: digest2,
|
|
2650
|
-
patchId: digest2,
|
|
2651
|
-
snapshotDigest: digest2,
|
|
2652
|
-
exitCode: z2.number().int(),
|
|
2653
|
-
timedOut: z2.boolean(),
|
|
2654
|
-
unchanged: z2.boolean()
|
|
2655
|
-
});
|
|
2656
|
-
var deliverySchema = z2.object({
|
|
2657
|
-
schemaVersion: z2.literal(1),
|
|
2658
|
-
contractRevision: count2,
|
|
2659
|
-
contractDigest: digest2,
|
|
2660
|
-
status: deliveryStatus,
|
|
2661
|
-
checks: z2.array(taskCheckReceiptSchema).max(32),
|
|
2662
|
-
delivery: z2.object({ runId: z2.string().max(512), executionIdentity: z2.string().max(512), patchId: digest2, snapshotDigest: digest2 }).optional()
|
|
2663
|
-
});
|
|
2664
|
-
var approvalSchema = z2.strictObject({
|
|
2665
|
-
reference: digest2,
|
|
2666
|
-
toolReference: digest2,
|
|
2667
|
-
approved: z2.boolean(),
|
|
2668
|
-
origin: z2.enum(["interactive", "automatic", "application", "unknown"]),
|
|
2669
|
-
channelReference: digest2,
|
|
2670
|
-
policyDigest: digest2.nullable(),
|
|
2671
|
-
status: z2.enum(["rejected", "approved", "applied", "succeeded", "failed", "unknown"]),
|
|
2672
|
-
proposalId: digest2.nullable(),
|
|
2673
|
-
exitCode: z2.number().int().nullable(),
|
|
2674
|
-
timedOut: z2.boolean().nullable(),
|
|
2675
|
-
effects: z2.array(z2.strictObject({ pathReference: digest2, beforeDigest: digest2.nullable(), afterDigest: digest2.nullable() })).max(50)
|
|
2676
|
-
});
|
|
2677
|
-
var delegationReason = z2.enum(["valid", "invalid_json", "invalid_schema", "task_mismatch", "incomplete", "duplicate_claim", "path_denied", "evidence_missing", "coverage_missing", "missing_child", "child_identity_unavailable"]);
|
|
2678
|
-
var delegationSchema = z2.strictObject({
|
|
2679
|
-
taskReference: digest2,
|
|
2680
|
-
childReference: digest2.nullable(),
|
|
2681
|
-
recordedAcceptance: z2.boolean(),
|
|
2682
|
-
reason: delegationReason,
|
|
2683
|
-
semanticReview: z2.enum(["pending", "not_requested"]),
|
|
2684
|
-
correctionsUsed: count2.nullable()
|
|
2685
|
-
});
|
|
2686
|
-
var delegationInput = z2.object({ schemaVersion: z2.literal(1), evaluations: z2.array(z2.object({
|
|
2687
|
-
taskId: z2.string().max(128),
|
|
2688
|
-
childRunId: z2.string().max(512).nullable(),
|
|
2689
|
-
childStatus: z2.string().max(32),
|
|
2690
|
-
accepted: z2.boolean(),
|
|
2691
|
-
reason: delegationReason,
|
|
2692
|
-
semanticReview: z2.enum(["pending", "not_requested"]),
|
|
2693
|
-
correctionsUsed: count2.optional()
|
|
2694
|
-
})).max(64) });
|
|
2695
|
-
var runSchema = z2.strictObject({
|
|
2696
|
-
reference: digest2,
|
|
2697
|
-
parentReference: digest2.nullable(),
|
|
2698
|
-
revision: count2.nullable(),
|
|
2699
|
-
status,
|
|
2700
|
-
finalized: z2.boolean(),
|
|
2701
|
-
failure: z2.enum(["run_failed", "cancelled", "timed_out", "not_reported"]).nullable(),
|
|
2702
|
-
failureDetails: z2.strictObject({ providerToolReason: providerReason.nullable(), diagnosticReference: digest2.nullable(), deliveryReason: deliveryReason.nullable() }),
|
|
2703
|
-
identity: z2.literal("not-verified"),
|
|
2704
|
-
runtimePolicy: z2.enum(["assistant-v3-durable-closure"]).nullable(),
|
|
2705
|
-
contract: z2.strictObject({
|
|
2706
|
-
availability,
|
|
2707
|
-
digest: digest2.nullable(),
|
|
2708
|
-
revision: count2.nullable(),
|
|
2709
|
-
requiredChecks: count2.nullable(),
|
|
2710
|
-
humanReviewsPending: count2.nullable(),
|
|
2711
|
-
allowedWritePathReferences: z2.array(digest2).max(256),
|
|
2712
|
-
protectedPathReferences: z2.array(digest2).max(256),
|
|
2713
|
-
checks: z2.array(z2.strictObject({ reference: digest2, argvDigest: digest2, kind: z2.enum(["argv", "package-script"]), backend: z2.enum(["none", "oci"]), approval: z2.literal("required") })).max(32),
|
|
2714
|
-
humanReviewReferences: z2.array(digest2).max(32)
|
|
2715
|
-
}),
|
|
2716
|
-
delivery: z2.strictObject({
|
|
2717
|
-
availability,
|
|
2718
|
-
status: deliveryStatus,
|
|
2719
|
-
patchId: digest2.nullable(),
|
|
2720
|
-
snapshotDigest: digest2.nullable(),
|
|
2721
|
-
interpretation: z2.literal("recorded-checkpoint-not-current-workspace-verification"),
|
|
2722
|
-
checks: z2.array(checkSchema).max(32)
|
|
2723
|
-
}),
|
|
2724
|
-
approvals: z2.strictObject({ availability, items: z2.array(approvalSchema).max(512) }),
|
|
2725
|
-
usage: z2.strictObject({
|
|
2726
|
-
availability: z2.enum(["recorded", "unavailable"]),
|
|
2727
|
-
calls: count2.nullable(),
|
|
2728
|
-
inputTokens: count2.nullable(),
|
|
2729
|
-
outputTokens: count2.nullable(),
|
|
2730
|
-
complete: z2.boolean().nullable(),
|
|
2731
|
-
estimatedUsd: z2.number().finite().nonnegative().nullable(),
|
|
2732
|
-
costKind: z2.literal("estimate-not-invoice")
|
|
2733
|
-
}),
|
|
2734
|
-
journal: z2.strictObject({ availability: z2.enum(["recorded", "unavailable"]), entries: count2, failed: count2, unfinished: count2 }),
|
|
2735
|
-
delegations: z2.strictObject({ availability, interpretation: z2.literal("recorded-checkpoint-not-semantic-review"), items: z2.array(delegationSchema).max(64) }),
|
|
2736
|
-
children: z2.array(digest2).max(64)
|
|
2737
|
-
});
|
|
2738
|
-
var harnessGovernanceReportSchema = z2.strictObject({
|
|
2739
|
-
schemaVersion: z2.literal(1),
|
|
2740
|
-
kind: z2.literal("harness-governance-report"),
|
|
2741
|
-
exporterVersion: z2.string().regex(/^\d+\.\d+\.\d+(?:[-+][a-zA-Z0-9.-]+)?$/),
|
|
2742
|
-
executionArtifact: z2.strictObject({ version: version.nullable(), digest: z2.null(), availability: z2.enum(["recorded-version", "unavailable"]), configurationFingerprint: digest2.nullable(), authenticity: z2.literal("not-verified") }),
|
|
2743
|
-
rootReference: digest2,
|
|
2744
|
-
identity: z2.literal("not-verified"),
|
|
2745
|
-
referencePolicy: z2.literal("sha256-domain-separated-pseudonyms-not-anonymity"),
|
|
2746
|
-
session: governanceSessionSchema,
|
|
2747
|
-
eventHistory: governanceHistorySchema,
|
|
2748
|
-
changeEnvelopes: z2.array(governanceEnvelopeSchema).max(32),
|
|
2749
|
-
runs: z2.array(runSchema).max(64),
|
|
2750
|
-
missingChildren: z2.array(digest2).max(64),
|
|
2751
|
-
limitations: z2.array(z2.enum(["tree_limit", "missing_child", "invalid_contract", "invalid_delivery", "invalid_approvals", "journal_unavailable"])).max(6)
|
|
2752
|
-
});
|
|
2753
|
-
var MAX_JOURNAL = 2048;
|
|
2754
|
-
var MAX_REPORT_BYTES = 2 * 1024 * 1024;
|
|
2755
|
-
var sameScope = (state, scope) => !state.scope || state.scope.tenantId === scope?.tenantId && state.scope.userId === scope?.userId && state.scope.namespace === scope?.namespace;
|
|
2756
|
-
function projectRun(state, journal, limitations) {
|
|
2757
|
-
const runStatus = status.safeParse(state.status);
|
|
2758
|
-
const stateStatus = runStatus.success ? runStatus.data : "unknown";
|
|
2759
|
-
let ledger;
|
|
2760
|
-
let contractAvailability = "unavailable";
|
|
2761
|
-
try {
|
|
2762
|
-
ledger = readTaskAcceptanceLedger(state);
|
|
2763
|
-
if (ledger)
|
|
2764
|
-
contractAvailability = "recorded";
|
|
2765
|
-
} catch {
|
|
2766
|
-
contractAvailability = "invalid";
|
|
2767
|
-
limitations.add("invalid_contract");
|
|
2768
|
-
}
|
|
2769
|
-
const contract = ledger?.revisions.at(-1);
|
|
2770
|
-
const rawDelivery = state.metadata?.[TASK_ACCEPTANCE_EVIDENCE_KEY];
|
|
2771
|
-
const parsedDelivery = deliverySchema.safeParse(rawDelivery);
|
|
2772
|
-
const bound = parsedDelivery.success && contract && parsedDelivery.data.contractDigest === contract.digest && parsedDelivery.data.contractRevision === contract.revision && (!parsedDelivery.data.delivery || parsedDelivery.data.delivery.runId === state.runId);
|
|
2773
|
-
const candidate = bound ? parsedDelivery.data : undefined;
|
|
2774
|
-
const verified = candidate?.status === "verified" || candidate?.status === "pending_review";
|
|
2775
|
-
const validSuccess = !verified || stateStatus === "completed" && candidate.delivery && contract && contract.contract.requiredChecks.every((required) => candidate.checks.some((check) => check.checkId === required.id && check.runId === state.runId && check.argvDigest === "sha256:" + createHash3("sha256").update(JSON.stringify([required.command, ...required.args])).digest("hex") && check.contractDigest === contract.digest && check.contractRevision === contract.revision && check.exitCode === 0 && !check.timedOut && check.unchanged && check.patchId === candidate.delivery.patchId && check.snapshotDigest === candidate.delivery.snapshotDigest && check.executionIdentity === candidate.delivery.executionIdentity)) && candidate.status === "pending_review" === contract.contract.humanReview.length > 0;
|
|
2776
|
-
const delivery = validSuccess ? candidate : undefined;
|
|
2777
|
-
if (rawDelivery !== undefined && !delivery)
|
|
2778
|
-
limitations.add("invalid_delivery");
|
|
2779
|
-
const approvals = { availability: state.metadata?.[APPROVAL_HISTORY_KEY] === undefined ? "unavailable" : "recorded", items: [] };
|
|
2780
|
-
try {
|
|
2781
|
-
for (let offset = 0;offset < 512; offset += 25) {
|
|
2782
|
-
const rows = approvalDecisionViews(state, journal ?? [], offset);
|
|
2783
|
-
for (const row of rows)
|
|
2784
|
-
approvals.items.push({
|
|
2785
|
-
reference: governanceReference("approval", row.approvalId),
|
|
2786
|
-
toolReference: governanceReference("tool", row.name),
|
|
2787
|
-
approved: row.approved,
|
|
2788
|
-
origin: row.provenance?.origin ?? "unknown",
|
|
2789
|
-
channelReference: governanceReference("channel", row.provenance?.channel ?? "unknown"),
|
|
2790
|
-
policyDigest: row.provenance?.policyDigest ?? null,
|
|
2791
|
-
status: row.status,
|
|
2792
|
-
proposalId: row.evidence?.proposalId ?? null,
|
|
2793
|
-
exitCode: row.evidence?.exitCode ?? null,
|
|
2794
|
-
timedOut: row.evidence?.timedOut ?? null,
|
|
2795
|
-
effects: (row.evidence?.effects ?? []).map((effect) => ({ pathReference: governanceReference("path", effect.path), beforeDigest: effect.beforeDigest, afterDigest: effect.afterDigest }))
|
|
2796
|
-
});
|
|
2797
|
-
if (rows.length < 25)
|
|
2798
|
-
break;
|
|
2799
|
-
}
|
|
2800
|
-
} catch {
|
|
2801
|
-
approvals.availability = "invalid";
|
|
2802
|
-
approvals.items = [];
|
|
2803
|
-
limitations.add("invalid_approvals");
|
|
2804
|
-
}
|
|
2805
|
-
const parsedUsage = inspectUsageLedger(state.metadata?.[USAGE_LEDGER_KEY]);
|
|
2806
|
-
const usage = parsedUsage?.runId === state.runId ? parsedUsage : null;
|
|
2807
|
-
const rawDelegations = state.metadata?.zhivexDelegationAcceptanceV1;
|
|
2808
|
-
const delegations = delegationInput.safeParse(rawDelegations);
|
|
2809
|
-
const manifest = inspectRuntimeManifest(state.metadata?.effectiveRuntime);
|
|
2810
|
-
return {
|
|
2811
|
-
reference: governanceReference("run", state.runId),
|
|
2812
|
-
parentReference: state.parentRunId ? governanceReference("run", state.parentRunId) : null,
|
|
2813
|
-
revision: count2.safeParse(state.revision).success ? state.revision : null,
|
|
2814
|
-
status: stateStatus,
|
|
2815
|
-
finalized: ["completed", "failed", "cancelled", "timed_out"].includes(stateStatus),
|
|
2816
|
-
failure: stateStatus === "failed" ? "run_failed" : stateStatus === "cancelled" ? "cancelled" : stateStatus === "timed_out" ? "timed_out" : state.error ? "not_reported" : null,
|
|
2817
|
-
failureDetails: {
|
|
2818
|
-
providerToolReason: providerReason.safeParse(state.error?.reason).success ? state.error.reason : null,
|
|
2819
|
-
diagnosticReference: state.error?.diagnosticCode ? governanceReference("diagnostic", state.error.diagnosticCode) : null,
|
|
2820
|
-
deliveryReason: deliveryReason.safeParse(rawDelivery && typeof rawDelivery === "object" && !Array.isArray(rawDelivery) ? rawDelivery.reason : undefined).success ? rawDelivery.reason : null
|
|
2821
|
-
},
|
|
2822
|
-
identity: "not-verified",
|
|
2823
|
-
runtimePolicy: manifest?.policyVersion ?? null,
|
|
2824
|
-
contract: {
|
|
2825
|
-
availability: contractAvailability,
|
|
2826
|
-
digest: contract?.digest ?? null,
|
|
2827
|
-
revision: contract?.revision ?? null,
|
|
2828
|
-
requiredChecks: contract?.contract.requiredChecks.length ?? null,
|
|
2829
|
-
humanReviewsPending: contract?.contract.humanReview.length ?? null,
|
|
2830
|
-
allowedWritePathReferences: contract?.contract.allowedWritePaths.map((file) => governanceReference("path", file)) ?? [],
|
|
2831
|
-
protectedPathReferences: contract?.contract.protectedFiles.map((file) => governanceReference("path", file)) ?? [],
|
|
2832
|
-
checks: contract?.contract.requiredChecks.map((check) => ({ reference: governanceReference("check", check.id), argvDigest: "sha256:" + createHash3("sha256").update(JSON.stringify([check.command, ...check.args])).digest("hex"), kind: check.kind, backend: check.execution.backend, approval: check.execution.approval })) ?? [],
|
|
2833
|
-
humanReviewReferences: contract?.contract.humanReview.map((review) => governanceReference("review", review.id)) ?? []
|
|
2834
|
-
},
|
|
2835
|
-
delivery: {
|
|
2836
|
-
availability: delivery ? "recorded" : rawDelivery === undefined ? "unavailable" : "invalid",
|
|
2837
|
-
status: delivery?.status ?? "unknown",
|
|
2838
|
-
patchId: delivery?.delivery?.patchId ?? null,
|
|
2839
|
-
snapshotDigest: delivery?.delivery?.snapshotDigest ?? null,
|
|
2840
|
-
interpretation: "recorded-checkpoint-not-current-workspace-verification",
|
|
2841
|
-
checks: (delivery?.checks ?? []).filter((check) => check.runId === state.runId && check.contractDigest === contract?.digest && check.contractRevision === contract?.revision).map((check) => ({ reference: governanceReference("check", check.checkId), argvDigest: check.argvDigest, patchId: check.patchId, snapshotDigest: check.snapshotDigest, exitCode: check.exitCode, timedOut: check.timedOut, unchanged: check.unchanged }))
|
|
2842
|
-
},
|
|
2843
|
-
approvals,
|
|
2844
|
-
usage: {
|
|
2845
|
-
availability: usage ? "recorded" : "unavailable",
|
|
2846
|
-
calls: usage?.calls ?? null,
|
|
2847
|
-
inputTokens: usage?.inputTokens ?? null,
|
|
2848
|
-
outputTokens: usage?.outputTokens ?? null,
|
|
2849
|
-
complete: usage?.usageComplete ?? null,
|
|
2850
|
-
estimatedUsd: usage?.estimatedUsd ?? null,
|
|
2851
|
-
costKind: "estimate-not-invoice"
|
|
2852
|
-
},
|
|
2853
|
-
journal: {
|
|
2854
|
-
availability: journal ? "recorded" : "unavailable",
|
|
2855
|
-
entries: journal?.length ?? 0,
|
|
2856
|
-
failed: journal?.filter((entry) => entry.status === "failed").length ?? 0,
|
|
2857
|
-
unfinished: journal?.filter((entry) => entry.status !== "completed" && entry.status !== "failed").length ?? 0
|
|
2858
|
-
},
|
|
2859
|
-
delegations: {
|
|
2860
|
-
availability: rawDelegations === undefined ? "unavailable" : delegations.success ? "recorded" : "invalid",
|
|
2861
|
-
interpretation: "recorded-checkpoint-not-semantic-review",
|
|
2862
|
-
items: delegations.success ? delegations.data.evaluations.map((item) => ({
|
|
2863
|
-
taskReference: governanceReference("task", item.taskId),
|
|
2864
|
-
childReference: item.childRunId ? governanceReference("run", item.childRunId) : null,
|
|
2865
|
-
recordedAcceptance: item.accepted,
|
|
2866
|
-
reason: item.reason,
|
|
2867
|
-
semanticReview: item.semanticReview,
|
|
2868
|
-
correctionsUsed: item.correctionsUsed ?? null
|
|
2869
|
-
})) : []
|
|
2870
|
-
},
|
|
2871
|
-
children: (state.childRuns ?? []).slice(0, 64).map((child) => governanceReference("run", child.runId))
|
|
2872
|
-
};
|
|
2873
|
-
}
|
|
2874
|
-
async function exportHarnessGovernanceReport(store, scope, runId, options = {}) {
|
|
2875
|
-
const limitations = new Set;
|
|
2876
|
-
const runs = [], missingChildren = [];
|
|
2877
|
-
const observed = [];
|
|
2878
|
-
const queue = [{ id: runId }], seen = new Set;
|
|
2879
|
-
while (queue.length && runs.length + missingChildren.length < 64) {
|
|
2880
|
-
const item = queue.shift();
|
|
2881
|
-
if (seen.has(item.id))
|
|
2882
|
-
continue;
|
|
2883
|
-
seen.add(item.id);
|
|
2884
|
-
const loaded = await store.load(item.id, scope);
|
|
2885
|
-
const state = loaded ? structuredClone(loaded) : undefined;
|
|
2886
|
-
if (!state || state.runId !== item.id || !sameScope(state, scope) || item.parent !== undefined && state.parentRunId !== item.parent) {
|
|
2887
|
-
if (item.parent === undefined)
|
|
2888
|
-
throw new Error("GOVERNANCE_RUN_UNAVAILABLE");
|
|
2889
|
-
missingChildren.push(governanceReference("run", item.id));
|
|
2890
|
-
limitations.add("missing_child");
|
|
2891
|
-
continue;
|
|
2892
|
-
}
|
|
2893
|
-
const loadedJournal = await store.listToolCalls?.(state.runId, scope);
|
|
2894
|
-
const journal = loadedJournal ? structuredClone(loadedJournal) : undefined;
|
|
2895
|
-
if (journal && journal.length > MAX_JOURNAL)
|
|
2896
|
-
throw new Error("GOVERNANCE_JOURNAL_LIMIT");
|
|
2897
|
-
if (journal?.some((entry) => entry.runId !== state.runId))
|
|
2898
|
-
throw new Error("GOVERNANCE_JOURNAL_SCOPE");
|
|
2899
|
-
if (!journal)
|
|
2900
|
-
limitations.add("journal_unavailable");
|
|
2901
|
-
observed.push({ state, journal });
|
|
2902
|
-
runs.push(projectRun(state, journal, limitations));
|
|
2903
|
-
if ((state.childRuns?.length ?? 0) > 64)
|
|
2904
|
-
limitations.add("tree_limit");
|
|
2905
|
-
for (const child of (state.childRuns ?? []).slice(0, 64))
|
|
2906
|
-
queue.push({ id: child.runId, parent: state.runId });
|
|
2907
|
-
}
|
|
2908
|
-
if (queue.length)
|
|
2909
|
-
limitations.add("tree_limit");
|
|
2910
|
-
const context = await readGovernanceSession(options.session, runId, new Set(observed.map((item) => item.state.runId)));
|
|
2911
|
-
for (const { state, journal } of observed) {
|
|
2912
|
-
const current = await store.load(state.runId, scope);
|
|
2913
|
-
const currentJournal = await store.listToolCalls?.(state.runId, scope);
|
|
2914
|
-
if (!current || JSON.stringify(current) !== JSON.stringify(state) || JSON.stringify(currentJournal) !== JSON.stringify(journal))
|
|
2915
|
-
throw new Error("GOVERNANCE_STATE_CHANGED");
|
|
2916
|
-
}
|
|
2917
|
-
await context.verify();
|
|
2918
|
-
const patches = new Map;
|
|
2919
|
-
for (const run of runs)
|
|
2920
|
-
for (const patch of new Set([run.delivery.patchId, ...run.approvals.items.map((row) => row.proposalId)].filter((id) => id !== null)))
|
|
2921
|
-
patches.set(patch, [...patches.get(patch) ?? [], run.reference]);
|
|
2922
|
-
const binding = bindingSchema.safeParse(observed[0]?.state.harness);
|
|
2923
|
-
const report = harnessGovernanceReportSchema.parse({
|
|
2924
|
-
schemaVersion: 1,
|
|
2925
|
-
kind: "harness-governance-report",
|
|
2926
|
-
exporterVersion: HARNESS_VERSION,
|
|
2927
|
-
executionArtifact: { version: binding.success ? binding.data.version : null, digest: null, availability: binding.success ? "recorded-version" : "unavailable", configurationFingerprint: binding.success ? binding.data.fingerprint : null, authenticity: "not-verified" },
|
|
2928
|
-
rootReference: governanceReference("run", runId),
|
|
2929
|
-
identity: "not-verified",
|
|
2930
|
-
referencePolicy: "sha256-domain-separated-pseudonyms-not-anonymity",
|
|
2931
|
-
session: context.session,
|
|
2932
|
-
eventHistory: context.history,
|
|
2933
|
-
changeEnvelopes: projectGovernanceEnvelopes(options.changeEnvelopes ?? [], patches, options.now ?? Date.now()),
|
|
2934
|
-
runs,
|
|
2935
|
-
missingChildren,
|
|
2936
|
-
limitations: [...limitations].sort()
|
|
2937
|
-
});
|
|
2938
|
-
if (Buffer.byteLength(JSON.stringify(report)) > MAX_REPORT_BYTES)
|
|
2939
|
-
throw new Error("GOVERNANCE_REPORT_LIMIT");
|
|
2940
|
-
return report;
|
|
2941
|
-
}
|
|
2942
|
-
function renderHarnessGovernanceMarkdown(input) {
|
|
2943
|
-
const report = harnessGovernanceReportSchema.parse(input);
|
|
2944
|
-
return [
|
|
2945
|
-
"# Execution and governance report",
|
|
2946
|
-
"",
|
|
2947
|
-
`Schema: ${report.schemaVersion}. Exporter: ${report.exporterVersion}.`,
|
|
2948
|
-
`Identity: not verified. Recorded execution version: ${report.executionArtifact.version ?? "unavailable"}. Artifact digest: unavailable. Hash references are pseudonyms, not signatures.`,
|
|
2949
|
-
"Delivery describes a recorded checkpoint; export does not recheck the workspace.",
|
|
2950
|
-
"",
|
|
2951
|
-
"| Run reference | Execution | Recorded delivery | Usage |",
|
|
2952
|
-
"| --- | --- | --- | --- |",
|
|
2953
|
-
...report.runs.map((run) => `| ${run.reference} | ${run.status} | ${run.delivery.status} | ${run.usage.availability === "unavailable" ? "unavailable" : `${run.usage.inputTokens} input / ${run.usage.outputTokens} output (${run.usage.complete ? "complete" : "incomplete"})`} |`),
|
|
2954
|
-
"",
|
|
2955
|
-
`Missing children: ${report.missingChildren.length}. Limitations: ${report.limitations.join(", ") || "none detected"}.`,
|
|
2956
|
-
`Session: ${report.session.availability}. Event history: ${report.eventHistory.availability}. Retention: ${report.eventHistory.retention}. Incomplete: ${report.eventHistory.incomplete}.`,
|
|
2957
|
-
`Change envelopes: ${report.changeEnvelopes.length}. Envelope integrity does not verify patch bytes or authenticity. Estimates are not invoices.`,
|
|
2958
|
-
""
|
|
2959
|
-
].join(`
|
|
2960
|
-
`);
|
|
2961
|
-
}
|
|
2962
|
-
|
|
2963
|
-
// src/cli/governance-report.ts
|
|
2964
2564
|
async function governanceReportCli(options, config, store) {
|
|
2965
2565
|
let index;
|
|
2966
2566
|
let history;
|
|
@@ -3415,17 +3015,17 @@ async function readBackupTransport(source, legacyMaxBytes) {
|
|
|
3415
3015
|
}
|
|
3416
3016
|
|
|
3417
3017
|
// src/persistence/state-backup.ts
|
|
3418
|
-
import { createHash as
|
|
3018
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
3419
3019
|
import { constants as fsConstants2 } from "node:fs";
|
|
3420
3020
|
import { chmod, link, lstat as lstat2, open, realpath, unlink } from "node:fs/promises";
|
|
3421
3021
|
import path4 from "node:path";
|
|
3422
|
-
import { z
|
|
3022
|
+
import { z } from "zod";
|
|
3423
3023
|
import { normalizeAgentRunState } from "@zhivex-ai/agents";
|
|
3424
3024
|
import { createSqliteAgentRunStore } from "@zhivex-ai/agents/ops";
|
|
3425
3025
|
|
|
3426
3026
|
// src/persistence/sdk-store-identity.ts
|
|
3427
|
-
import { createHash as
|
|
3428
|
-
var sdkCanonicalKey = (kind, scope, value) => `${kind}:v2:${
|
|
3027
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3028
|
+
var sdkCanonicalKey = (kind, scope, value) => `${kind}:v2:${createHash2("sha256").update(JSON.stringify([
|
|
3429
3029
|
JSON.stringify([scope.namespace ?? null, scope.tenantId, scope.userId ?? null]),
|
|
3430
3030
|
value
|
|
3431
3031
|
])).digest("hex")}`;
|
|
@@ -3437,128 +3037,128 @@ var HARNESS_STATE_BACKUP_SCHEMA_VERSION = 1;
|
|
|
3437
3037
|
var HARNESS_STATE_BACKUP_MAX_BYTES = 64 * 1024 * 1024;
|
|
3438
3038
|
var terminalRunStatuses = new Set(["completed", "failed", "cancelled", "timed_out"]);
|
|
3439
3039
|
var terminalSessionStatuses = new Set(["completed", "failed", "cancelled", "timed_out"]);
|
|
3440
|
-
var digestSchema =
|
|
3441
|
-
var bindingKeySchema =
|
|
3442
|
-
var jsonRecordSchema =
|
|
3443
|
-
var durableScopeSchema =
|
|
3444
|
-
tenantId:
|
|
3445
|
-
userId:
|
|
3446
|
-
namespace:
|
|
3040
|
+
var digestSchema = z.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
3041
|
+
var bindingKeySchema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
3042
|
+
var jsonRecordSchema = z.record(z.string(), z.unknown());
|
|
3043
|
+
var durableScopeSchema = z.object({
|
|
3044
|
+
tenantId: z.string().min(1),
|
|
3045
|
+
userId: z.string().min(1).optional(),
|
|
3046
|
+
namespace: z.string().min(1).optional()
|
|
3447
3047
|
}).strict();
|
|
3448
|
-
var journalEntrySchema =
|
|
3449
|
-
runId:
|
|
3048
|
+
var journalEntrySchema = z.object({
|
|
3049
|
+
runId: z.string().min(1),
|
|
3450
3050
|
scope: durableScopeSchema,
|
|
3451
|
-
toolCallId:
|
|
3452
|
-
toolName:
|
|
3453
|
-
status:
|
|
3454
|
-
idempotencyKey:
|
|
3455
|
-
revision:
|
|
3456
|
-
input:
|
|
3457
|
-
output:
|
|
3458
|
-
error:
|
|
3459
|
-
startedAt:
|
|
3460
|
-
completedAt:
|
|
3461
|
-
updatedAt:
|
|
3051
|
+
toolCallId: z.string().min(1),
|
|
3052
|
+
toolName: z.string().min(1),
|
|
3053
|
+
status: z.enum(["pending", "running", "completed", "failed"]),
|
|
3054
|
+
idempotencyKey: z.string().min(1),
|
|
3055
|
+
revision: z.number().int().nonnegative(),
|
|
3056
|
+
input: z.json().optional(),
|
|
3057
|
+
output: z.json().optional(),
|
|
3058
|
+
error: z.object({ message: z.string() }).strict().optional(),
|
|
3059
|
+
startedAt: z.number().nonnegative().optional(),
|
|
3060
|
+
completedAt: z.number().nonnegative().optional(),
|
|
3061
|
+
updatedAt: z.number().nonnegative()
|
|
3462
3062
|
}).passthrough();
|
|
3463
|
-
var runRecordSchema =
|
|
3464
|
-
key:
|
|
3063
|
+
var runRecordSchema = z.object({
|
|
3064
|
+
key: z.string().min(1).max(1024),
|
|
3465
3065
|
state: jsonRecordSchema,
|
|
3466
|
-
updatedAt:
|
|
3066
|
+
updatedAt: z.number().int().nonnegative()
|
|
3467
3067
|
}).strict();
|
|
3468
|
-
var journalRecordSchema =
|
|
3469
|
-
runKey:
|
|
3470
|
-
toolCallId:
|
|
3068
|
+
var journalRecordSchema = z.object({
|
|
3069
|
+
runKey: z.string().min(1).max(1024),
|
|
3070
|
+
toolCallId: z.string().min(1).max(1024),
|
|
3471
3071
|
entry: journalEntrySchema,
|
|
3472
|
-
revision:
|
|
3473
|
-
updatedAt:
|
|
3072
|
+
revision: z.number().int().nonnegative(),
|
|
3073
|
+
updatedAt: z.number().int().nonnegative()
|
|
3474
3074
|
}).strict();
|
|
3475
|
-
var idempotencyRecordSchema =
|
|
3476
|
-
key:
|
|
3477
|
-
runKey:
|
|
3478
|
-
updatedAt:
|
|
3075
|
+
var idempotencyRecordSchema = z.object({
|
|
3076
|
+
key: z.string().min(1).max(1024),
|
|
3077
|
+
runKey: z.string().min(1).max(1024),
|
|
3078
|
+
updatedAt: z.number().int().nonnegative()
|
|
3479
3079
|
}).strict();
|
|
3480
|
-
var parentRecordSchema =
|
|
3481
|
-
runKey:
|
|
3482
|
-
parentRunKey:
|
|
3483
|
-
updatedAt:
|
|
3080
|
+
var parentRecordSchema = z.object({
|
|
3081
|
+
runKey: z.string().min(1).max(1024),
|
|
3082
|
+
parentRunKey: z.string().min(1).max(1024),
|
|
3083
|
+
updatedAt: z.number().int().nonnegative()
|
|
3484
3084
|
}).strict();
|
|
3485
|
-
var memoryRecordSchema =
|
|
3486
|
-
key:
|
|
3487
|
-
messages:
|
|
3488
|
-
updatedAt:
|
|
3085
|
+
var memoryRecordSchema = z.object({
|
|
3086
|
+
key: z.string().min(1).max(1024),
|
|
3087
|
+
messages: z.array(z.unknown()),
|
|
3088
|
+
updatedAt: z.number().int().nonnegative()
|
|
3489
3089
|
}).strict();
|
|
3490
3090
|
var serializedMemory = (entry) => JSON.stringify(entry.key.startsWith("agent-memory:v2:") ? { schemaVersion: 1, memoryKey: entry.key, messages: entry.messages } : entry.messages);
|
|
3491
3091
|
var memoryKeysForRuns = (config, runs) => new Set(runs.flatMap(({ state }) => [...new Set([state.runId, state.agentId].filter((id) => typeof id === "string"))].flatMap((id) => [sdkLegacyKey(config.scope, id), sdkCanonicalKey("agent-memory", config.scope, id)])));
|
|
3492
|
-
var sessionRecordSchema =
|
|
3493
|
-
sessionId:
|
|
3092
|
+
var sessionRecordSchema = z.object({
|
|
3093
|
+
sessionId: z.string().min(1).max(260),
|
|
3494
3094
|
workspaceKey: bindingKeySchema,
|
|
3495
3095
|
scopeKey: bindingKeySchema,
|
|
3496
|
-
title:
|
|
3497
|
-
parentSessionId:
|
|
3498
|
-
forkedFromTurnId:
|
|
3499
|
-
revision:
|
|
3500
|
-
activitySequence:
|
|
3501
|
-
createdAt:
|
|
3502
|
-
updatedAt:
|
|
3503
|
-
archivedAt:
|
|
3504
|
-
deletedAt:
|
|
3505
|
-
metadataBytes:
|
|
3096
|
+
title: z.string().nullable(),
|
|
3097
|
+
parentSessionId: z.string().nullable(),
|
|
3098
|
+
forkedFromTurnId: z.string().nullable(),
|
|
3099
|
+
revision: z.number().int().nonnegative(),
|
|
3100
|
+
activitySequence: z.number().int().nonnegative(),
|
|
3101
|
+
createdAt: z.number().int().nonnegative(),
|
|
3102
|
+
updatedAt: z.number().int().nonnegative(),
|
|
3103
|
+
archivedAt: z.number().int().nonnegative().nullable(),
|
|
3104
|
+
deletedAt: z.number().int().nonnegative().nullable(),
|
|
3105
|
+
metadataBytes: z.number().int().nonnegative()
|
|
3506
3106
|
}).strict();
|
|
3507
|
-
var sessionRunRecordSchema =
|
|
3508
|
-
turnId:
|
|
3509
|
-
sourceTurnId:
|
|
3510
|
-
sessionId:
|
|
3511
|
-
ordinal:
|
|
3512
|
-
runId:
|
|
3513
|
-
provider:
|
|
3514
|
-
model:
|
|
3515
|
-
role:
|
|
3516
|
-
status:
|
|
3517
|
-
createdAt:
|
|
3518
|
-
updatedAt:
|
|
3519
|
-
completedAt:
|
|
3520
|
-
metadataBytes:
|
|
3107
|
+
var sessionRunRecordSchema = z.object({
|
|
3108
|
+
turnId: z.string().min(1).max(260),
|
|
3109
|
+
sourceTurnId: z.string().nullable(),
|
|
3110
|
+
sessionId: z.string().min(1).max(260),
|
|
3111
|
+
ordinal: z.number().int().nonnegative(),
|
|
3112
|
+
runId: z.string().min(1).max(260),
|
|
3113
|
+
provider: z.string().min(1).max(260),
|
|
3114
|
+
model: z.string().min(1).max(260),
|
|
3115
|
+
role: z.string().nullable(),
|
|
3116
|
+
status: z.string().min(1),
|
|
3117
|
+
createdAt: z.number().int().nonnegative(),
|
|
3118
|
+
updatedAt: z.number().int().nonnegative(),
|
|
3119
|
+
completedAt: z.number().int().nonnegative().nullable(),
|
|
3120
|
+
metadataBytes: z.number().int().nonnegative()
|
|
3521
3121
|
}).strict();
|
|
3522
|
-
var checkpointRecordSchema =
|
|
3523
|
-
|
|
3524
|
-
id:
|
|
3122
|
+
var checkpointRecordSchema = z.discriminatedUnion("kind", [
|
|
3123
|
+
z.object({
|
|
3124
|
+
id: z.string().uuid(),
|
|
3525
3125
|
workspaceKey: bindingKeySchema,
|
|
3526
3126
|
scopeKey: bindingKeySchema,
|
|
3527
|
-
kind:
|
|
3127
|
+
kind: z.literal("checkpoint"),
|
|
3528
3128
|
body: workspaceCheckpointSchema
|
|
3529
3129
|
}).strict(),
|
|
3530
|
-
|
|
3531
|
-
id:
|
|
3130
|
+
z.object({
|
|
3131
|
+
id: z.string().uuid(),
|
|
3532
3132
|
workspaceKey: bindingKeySchema,
|
|
3533
3133
|
scopeKey: bindingKeySchema,
|
|
3534
|
-
kind:
|
|
3134
|
+
kind: z.literal("restore"),
|
|
3535
3135
|
body: workspaceRestoreOperationSchema
|
|
3536
3136
|
}).strict()
|
|
3537
3137
|
]);
|
|
3538
3138
|
var checkpointTableSql = "CREATE TABLE IF NOT EXISTS zhivex_workspace_checkpoints (id TEXT PRIMARY KEY, workspace_key TEXT NOT NULL, scope_key TEXT NOT NULL, kind TEXT NOT NULL, body TEXT NOT NULL)";
|
|
3539
|
-
var stateBackupPayloadSchema =
|
|
3540
|
-
schemaVersion:
|
|
3541
|
-
kind:
|
|
3542
|
-
createdAt:
|
|
3543
|
-
binding:
|
|
3139
|
+
var stateBackupPayloadSchema = z.object({
|
|
3140
|
+
schemaVersion: z.literal(HARNESS_STATE_BACKUP_SCHEMA_VERSION),
|
|
3141
|
+
kind: z.literal("state-backup"),
|
|
3142
|
+
createdAt: z.iso.datetime({ precision: 3 }),
|
|
3143
|
+
binding: z.object({
|
|
3544
3144
|
workspaceKey: bindingKeySchema,
|
|
3545
3145
|
scopeKey: bindingKeySchema,
|
|
3546
|
-
scopePrefix:
|
|
3146
|
+
scopePrefix: z.string().min(1).max(1024)
|
|
3547
3147
|
}).strict(),
|
|
3548
|
-
schemas:
|
|
3549
|
-
operations:
|
|
3550
|
-
sessions:
|
|
3148
|
+
schemas: z.object({
|
|
3149
|
+
operations: z.literal(HARNESS_OPERATIONS_SCHEMA_VERSION),
|
|
3150
|
+
sessions: z.literal(HARNESS_SESSION_SCHEMA_VERSION)
|
|
3551
3151
|
}).strict(),
|
|
3552
|
-
records:
|
|
3553
|
-
runs:
|
|
3554
|
-
toolJournal:
|
|
3555
|
-
idempotency:
|
|
3556
|
-
parents:
|
|
3557
|
-
memory:
|
|
3558
|
-
sessions:
|
|
3559
|
-
sessionRuns:
|
|
3560
|
-
workspaceCheckpoints:
|
|
3561
|
-
budgetLedgers:
|
|
3152
|
+
records: z.object({
|
|
3153
|
+
runs: z.array(runRecordSchema),
|
|
3154
|
+
toolJournal: z.array(journalRecordSchema),
|
|
3155
|
+
idempotency: z.array(idempotencyRecordSchema),
|
|
3156
|
+
parents: z.array(parentRecordSchema),
|
|
3157
|
+
memory: z.array(memoryRecordSchema),
|
|
3158
|
+
sessions: z.array(sessionRecordSchema),
|
|
3159
|
+
sessionRuns: z.array(sessionRunRecordSchema),
|
|
3160
|
+
workspaceCheckpoints: z.array(checkpointRecordSchema).max(100).optional(),
|
|
3161
|
+
budgetLedgers: z.array(runRecordSchema).optional()
|
|
3562
3162
|
}).strict()
|
|
3563
3163
|
}).strict();
|
|
3564
3164
|
var stateBackupBundleSchema = stateBackupPayloadSchema.extend({ checksum: digestSchema }).strict();
|
|
@@ -3570,12 +3170,12 @@ var canonicalJson = (value) => {
|
|
|
3570
3170
|
return `{${Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
|
|
3571
3171
|
};
|
|
3572
3172
|
var checksumPayload = (payload) => {
|
|
3573
|
-
const hash =
|
|
3173
|
+
const hash = createHash3("sha256");
|
|
3574
3174
|
for (const chunk of canonicalChunks(payload))
|
|
3575
3175
|
hash.update(chunk);
|
|
3576
3176
|
return `sha256:${hash.digest("hex")}`;
|
|
3577
3177
|
};
|
|
3578
|
-
var stableKey = (kind, value) =>
|
|
3178
|
+
var stableKey = (kind, value) => createHash3("sha256").update(kind).update("\x00").update(value).digest("hex");
|
|
3579
3179
|
var scopeValue = (config) => `${config.scope.tenantId}\x00${config.scope.userId ?? ""}\x00${config.scope.namespace ?? ""}`;
|
|
3580
3180
|
var scopePrefix = (config) => `${encodeURIComponent(config.scope.namespace ?? "default")}:${encodeURIComponent(config.scope.tenantId)}:${encodeURIComponent(config.scope.userId ?? "*")}:`;
|
|
3581
3181
|
var stateMatchesScope = (config, state) => {
|
|
@@ -3594,7 +3194,8 @@ var coordinatorIds = (runs) => new Set(runs.flatMap(({ state }) => {
|
|
|
3594
3194
|
var validateBudgetLedger = (config, run, identities) => {
|
|
3595
3195
|
const state = validatedRunState(run.state, `Budget ledger ${run.key}`);
|
|
3596
3196
|
const identity = state.metadata?.budgetIdentity;
|
|
3597
|
-
|
|
3197
|
+
const ownerNamespace = config.scope.namespace;
|
|
3198
|
+
if (!ownerNamespace || state.scope?.namespace !== budgetLedgerNamespace(ownerNamespace) || state.metadata?.[BUDGET_OWNER_NAMESPACE_KEY] !== ownerNamespace || state.scope?.tenantId !== config.scope.tenantId || (state.scope?.userId ?? undefined) !== (config.scope.userId ?? undefined) || state.provider !== "zhivex" || state.modelId !== "budget-coordinator" || state.metadata?.budgetCoordinator !== true || typeof identity !== "string" || !identities.has(identity) || !/^budget_[a-f0-9]{64}$/.test(state.runId) || !sdkRunKeyMatches(run.key, state.scope, state.runId)) {
|
|
3598
3199
|
throw new HarnessStateConflictError("Budget ledger is not bound to an exported run and durable scope.");
|
|
3599
3200
|
}
|
|
3600
3201
|
assertTerminalState(state, `Budget ledger ${run.key}`);
|
|
@@ -3728,7 +3329,9 @@ var readPayload = async (config, recordedWorkspace, accessLease) => {
|
|
|
3728
3329
|
const metadata = state.metadata;
|
|
3729
3330
|
if (typeof metadata?.budgetIdentity !== "string" || !identities.has(metadata.budgetIdentity)) {
|
|
3730
3331
|
const scope = state.scope;
|
|
3731
|
-
|
|
3332
|
+
const sameTenant = scope?.tenantId === config.scope.tenantId && (scope?.userId ?? undefined) === (config.scope.userId ?? undefined);
|
|
3333
|
+
const boundNamespace = config.scope.namespace ? budgetLedgerNamespace(config.scope.namespace) : undefined;
|
|
3334
|
+
if (sameTenant && (scope?.namespace === BUDGET_LEDGER_NAMESPACE || scope?.namespace === boundNamespace)) {
|
|
3732
3335
|
throw new HarnessStateConflictError("An unlinked shared budget ledger cannot be safely assigned to this backup scope; retain the original database.");
|
|
3733
3336
|
}
|
|
3734
3337
|
return [];
|
|
@@ -3778,10 +3381,10 @@ var readPayload = async (config, recordedWorkspace, accessLease) => {
|
|
|
3778
3381
|
const memory = database.query("SELECT memory_key, messages_json, updated_at_ms FROM zhivex_agent_memory ORDER BY memory_key").all().filter((row) => memoryKeys.has(row.memory_key)).map((row) => {
|
|
3779
3382
|
const value = JSON.parse(row.messages_json);
|
|
3780
3383
|
if (row.memory_key.startsWith("agent-memory:v2:")) {
|
|
3781
|
-
const envelope =
|
|
3384
|
+
const envelope = z.strictObject({ schemaVersion: z.literal(1), memoryKey: z.literal(row.memory_key), messages: z.array(z.unknown()) }).parse(value);
|
|
3782
3385
|
return { key: row.memory_key, messages: envelope.messages, updatedAt: row.updated_at_ms };
|
|
3783
3386
|
}
|
|
3784
|
-
return { key: row.memory_key, messages:
|
|
3387
|
+
return { key: row.memory_key, messages: z.array(z.unknown()).parse(value), updatedAt: row.updated_at_ms };
|
|
3785
3388
|
});
|
|
3786
3389
|
const sessionRows = database.query("SELECT * FROM zhivex_cli_sessions ORDER BY session_id").all().filter((row) => row.workspace_key === binding.workspaceKey && row.scope_key === binding.scopeKey);
|
|
3787
3390
|
const selectedSessionIds = new Set(sessionRows.map((row) => row.session_id));
|
|
@@ -4066,7 +3669,7 @@ var validateBundleBinding = async (config, bundle) => {
|
|
|
4066
3669
|
const turn = bundle.records.sessionRuns.find((run) => run.turnId === checkpoint.turnId && run.sessionId === checkpoint.sessionId);
|
|
4067
3670
|
if (!turn || !terminalSessionStatuses.has(turn.status))
|
|
4068
3671
|
throw new HarnessStateConflictError("Checkpoint targets a missing terminal turn.");
|
|
4069
|
-
if (new Set(checkpoint.files.map((file) => file.path)).size !== checkpoint.files.length || checkpoint.files.some((file) => `sha256:${
|
|
3672
|
+
if (new Set(checkpoint.files.map((file) => file.path)).size !== checkpoint.files.length || checkpoint.files.some((file) => `sha256:${createHash3("sha256").update(file.content).digest("hex")}` !== file.digest || Buffer.byteLength(file.content) > 65536)) {
|
|
4070
3673
|
throw new HarnessStateConflictError("Checkpoint content identity is invalid.");
|
|
4071
3674
|
}
|
|
4072
3675
|
if (record.kind === "restore") {
|
|
@@ -4488,7 +4091,7 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
4488
4091
|
parsedOptions = { ...parsedOptions, prompt: await readStdinTask() };
|
|
4489
4092
|
}
|
|
4490
4093
|
if (parsedOptions.serviceFile) {
|
|
4491
|
-
const { runServiceCli } = await import("./service-client-cli-
|
|
4094
|
+
const { runServiceCli } = await import("./service-client-cli-v6qptg9x.js");
|
|
4492
4095
|
await runServiceCli(parsedOptions, annotateCliStreamError);
|
|
4493
4096
|
return;
|
|
4494
4097
|
}
|
|
@@ -4551,6 +4154,12 @@ var main = async (argv = process.argv.slice(2)) => {
|
|
|
4551
4154
|
case "state":
|
|
4552
4155
|
await manageState(options);
|
|
4553
4156
|
return;
|
|
4157
|
+
case "export-audit":
|
|
4158
|
+
case "verify-audit": {
|
|
4159
|
+
const { auditPackCli } = await import("./audit-pack-kvw7ng34.js");
|
|
4160
|
+
await auditPackCli(options);
|
|
4161
|
+
return;
|
|
4162
|
+
}
|
|
4554
4163
|
case "run":
|
|
4555
4164
|
await runOnce(options);
|
|
4556
4165
|
return;
|