@zhivex-ai/harness 1.3.0 → 1.4.0-rc.6

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +30 -8
  3. package/SECURITY.md +1 -1
  4. package/SUPPORT.md +2 -2
  5. package/contracts/engine-api.json +70 -0
  6. package/contracts/public-api.json +162 -0
  7. package/contracts/stable-api-signatures.json +9 -9
  8. package/dist/acp-cli.js +38 -12
  9. package/dist/cli/arguments.d.ts +5 -1
  10. package/dist/cli/memory.d.ts +2 -0
  11. package/dist/{cli-entry-bx3vjw7h.js → cli-entry-4k1cf0m3.js} +38 -12
  12. package/dist/{cli-entry-1gfg3brj.js → cli-entry-9c2k0zwz.js} +1086 -446
  13. package/dist/{cli-etsmtst3.js → cli-s1rs15vv.js} +136 -24
  14. package/dist/cli.js +2 -2
  15. package/dist/client/check-evidence.d.ts +17 -0
  16. package/dist/client/run-document.d.ts +12 -0
  17. package/dist/compat/cli-options.d.ts +12 -1
  18. package/dist/compat/code-support.d.ts +4 -0
  19. package/dist/compat/code-support.js +12 -4
  20. package/dist/context/compaction.d.ts +5 -0
  21. package/dist/context/project-memory-context.d.ts +6 -0
  22. package/dist/context/task-memory.d.ts +33 -1
  23. package/dist/engine/acp.js +8 -8
  24. package/dist/engine/client.js +7 -7
  25. package/dist/engine/desktop-state-v1.js +5 -5
  26. package/dist/engine/index.d.ts +4 -0
  27. package/dist/engine/index.js +88 -11
  28. package/dist/engine/mcp-stdio-v1.js +4 -4
  29. package/dist/engine/service.js +8 -8
  30. package/dist/hostile-repository-demo.js +1260 -712
  31. package/dist/{index-azmwjp95.js → index-0g939pfs.js} +13 -12
  32. package/dist/{index-6m08wvab.js → index-2tgb2b4e.js} +3 -3
  33. package/dist/{index-w2sj0wkw.js → index-49ys3s4q.js} +64 -14
  34. package/dist/{index-hnaxfpb5.js → index-4j1h4j8c.js} +137 -42
  35. package/dist/{index-8zzhggxv.js → index-a1q355va.js} +125 -2
  36. package/dist/{index-8vm2m34s.js → index-dj5z774k.js} +18 -2
  37. package/dist/{index-z0qxmkm2.js → index-e6r04a18.js} +1 -1
  38. package/dist/{index-yb239ghk.js → index-r0tdj04h.js} +21 -6
  39. package/dist/{index-h0mqx2ed.js → index-rd0s3gqj.js} +300 -4
  40. package/dist/{index-42gp2hy8.js → index-vtqfjnab.js} +98 -27
  41. package/dist/{index-2jrdcj6b.js → index-wq2tax80.js} +15 -1
  42. package/dist/{index-a97bezbz.js → index-z6br6qdn.js} +44 -23
  43. package/dist/index.js +11 -11
  44. package/dist/persistence/project-memory-command.d.ts +11 -0
  45. package/dist/persistence/project-memory.d.ts +109 -0
  46. package/dist/persistence/sdk-store-identity.d.ts +4 -0
  47. package/dist/persistence/sessions.d.ts +4 -0
  48. package/dist/runtime/error-diagnostics.d.ts +35 -0
  49. package/dist/runtime/harness.d.ts +5 -1
  50. package/dist/runtime/run-interruption.d.ts +1 -1
  51. package/dist/runtime/runtime-checkpoints.d.ts +3 -0
  52. package/dist/runtime/task-acceptance-native.d.ts +10 -0
  53. package/dist/runtime/time-to-safe-fix.d.ts +35 -0
  54. package/dist/service-cli.js +8 -8
  55. package/dist/{service-client-cli-3365rfav.js → service-client-cli-b52c67hx.js} +2 -2
  56. package/dist/verify-historical-migrations.js +1021 -456
  57. package/dist/zhx.js +2 -2
  58. package/docs/CLI.md +4 -0
  59. package/docs/CLIENT_PROTOCOL.md +10 -0
  60. package/docs/CODE_RELEASE.md +136 -19
  61. package/docs/CONTEXT_ENGINEERING.md +25 -0
  62. package/docs/DURABLE_OPERATIONS.md +60 -1
  63. package/docs/ENGINE_API.md +23 -9
  64. package/docs/EXTENSIBILITY.md +1 -1
  65. package/docs/FIRST_USE.md +6 -6
  66. package/docs/LOCAL_SERVICE.md +10 -4
  67. package/docs/PROJECT_MEMORY.md +157 -0
  68. package/docs/README.md +2 -0
  69. package/docs/STABILITY.md +1 -1
  70. package/docs/WORKSPACE_CHECKPOINTS.md +11 -1
  71. package/evaluations/representative-assembly-matrix.json +55 -1
  72. package/examples/README.md +4 -4
  73. package/package.json +12 -11
@@ -51,6 +51,7 @@ import {
51
51
  createHarnessResumeMetadata,
52
52
  createHarnessRouteModels,
53
53
  credentialModel,
54
+ decodeProjectMemory,
54
55
  digestChangeEnvelopeArtifact,
55
56
  estimateMessages,
56
57
  fileDigestSchema,
@@ -80,12 +81,14 @@ import {
80
81
  openCliSessionStore,
81
82
  openHarnessActivityStore,
82
83
  openHarnessPersistence,
84
+ openHarnessProjectMemory,
83
85
  openWorkspaceCheckpointStore,
84
86
  orchestrationObserver,
85
87
  parseCliArgs,
86
88
  parseHarnessModelRoute,
87
89
  persistedCliOptions,
88
90
  printTerminalResult,
91
+ projectMemoryRecordKey,
89
92
  publishPendingPolicyDecision,
90
93
  readHarnessResumeConfig,
91
94
  readHarnessResumeRoutes,
@@ -120,14 +123,14 @@ import {
120
123
  withTemporaryHarnessProfiles,
121
124
  workspaceCheckpointSchema,
122
125
  workspaceRestoreOperationSchema
123
- } from "./cli-entry-1gfg3brj.js";
126
+ } from "./cli-entry-9c2k0zwz.js";
124
127
  import {
125
128
  BUN_ENGINE_RANGE,
126
129
  HARNESS_VERSION,
127
130
  NODE_ENGINE_RANGE,
128
131
  formatCliHelp,
129
132
  shortCliHelp
130
- } from "./cli-entry-bx3vjw7h.js";
133
+ } from "./cli-entry-4k1cf0m3.js";
131
134
  import {
132
135
  DEFAULT_HARNESS_MAX_STEPS,
133
136
  DEFAULT_PROVIDER_REGISTRY,
@@ -315,6 +318,8 @@ Options (automation and advanced configuration):
315
318
  --state-dir <path> Durable run-state directory
316
319
  --mcp-config <path> Declarative governed MCP JSON configuration
317
320
  --context-config <path> Project context/rules/skills manifest (default: .zhivex/harness.json)
321
+ --no-memory Disable project-memory retrieval for this invocation
322
+ --source <text> Provenance label for explicit memory input
318
323
  --no-project-context Disable AGENTS.md and the project context manifest
319
324
  --patch <path> Exact patch/artifact bytes bound to a change envelope
320
325
  --preconditions <path> Verification preconditions JSON for changes verify
@@ -1432,6 +1437,7 @@ Stopping the active operation; waiting for durable state and cleanup.
1432
1437
  let session = selectedSession ?? await sessionStore.create();
1433
1438
  let messages = [];
1434
1439
  let retainedTasks = [];
1440
+ let retainedResponses = [];
1435
1441
  let persistenceHarness;
1436
1442
  const latestState = async (selected) => {
1437
1443
  const latest = selected.runs.at(-1);
@@ -1461,6 +1467,7 @@ Stopping the active operation; waiting for durable state and cleanup.
1461
1467
  routes = readHarnessResumeRoutes(restored);
1462
1468
  messages = restored.messages;
1463
1469
  retainedTasks = taskSources(restored.metadata);
1470
+ retainedResponses = restored.metadata?.zhivexAssistantResponses ?? [];
1464
1471
  }
1465
1472
  harness = (await createConfiguredHarness(runtimeOptions, [], routes, credentials)).harness;
1466
1473
  persistenceHarness = harness;
@@ -1550,6 +1557,7 @@ Stopping the active operation; waiting for durable state and cleanup.
1550
1557
  activityHistory.clear();
1551
1558
  messages = state?.messages ?? [];
1552
1559
  retainedTasks = taskSources(state?.metadata);
1560
+ retainedResponses = state?.metadata?.zhivexAssistantResponses ?? [];
1553
1561
  };
1554
1562
  const continuePendingApproval = async (approve) => {
1555
1563
  const current = await refreshSession();
@@ -1616,6 +1624,7 @@ Stopping the active operation; waiting for durable state and cleanup.
1616
1624
  `);
1617
1625
  messages = result.messages;
1618
1626
  retainedTasks = taskSources(result.state.metadata);
1627
+ retainedResponses = result.state.metadata?.zhivexAssistantResponses ?? [];
1619
1628
  session = await sessionStore.updateRun(session.sessionId, state.runId, {
1620
1629
  status: sessionStatus(result.status)
1621
1630
  });
@@ -1895,6 +1904,7 @@ ${summarizeApproval(approval)}
1895
1904
  if (command === "/clear") {
1896
1905
  messages = [];
1897
1906
  retainedTasks = [];
1907
+ retainedResponses = [];
1898
1908
  attachments.clear();
1899
1909
  readline.clearHistory();
1900
1910
  activityHistory.clear();
@@ -2178,6 +2188,7 @@ ${sanitizeTerminalText(prompt)}
2178
2188
  metadata: {
2179
2189
  ...createHarnessResumeMetadata(harness.config, routes),
2180
2190
  [TASK_SOURCE_KEY]: retainedTasks,
2191
+ zhivexAssistantResponses: retainedResponses,
2181
2192
  zhivexCliSession: {
2182
2193
  schemaVersion: 1,
2183
2194
  sessionId: session.sessionId,
@@ -2196,6 +2207,7 @@ ${sanitizeTerminalText(prompt)}
2196
2207
  metadata: {
2197
2208
  ...createHarnessResumeMetadata(harness.config, routes),
2198
2209
  [TASK_SOURCE_KEY]: retainedTasks,
2210
+ zhivexAssistantResponses: retainedResponses,
2199
2211
  zhivexCliSession: {
2200
2212
  schemaVersion: 1,
2201
2213
  sessionId: session.sessionId,
@@ -2224,6 +2236,7 @@ ${sanitizeTerminalText(prompt)}
2224
2236
  if (durable) {
2225
2237
  messages = durable.messages;
2226
2238
  retainedTasks = taskSources(durable.metadata);
2239
+ retainedResponses = durable.metadata?.zhivexAssistantResponses ?? [];
2227
2240
  }
2228
2241
  throw error;
2229
2242
  }
@@ -2239,6 +2252,7 @@ ${sanitizeTerminalText(prompt)}
2239
2252
  `);
2240
2253
  messages = result.messages;
2241
2254
  retainedTasks = taskSources(result.state.metadata);
2255
+ retainedResponses = result.state.metadata?.zhivexAssistantResponses ?? [];
2242
2256
  attachments.clear();
2243
2257
  process.stderr.write(formatUsageLedger(result.state.metadata?.[USAGE_LEDGER_KEY]) + `
2244
2258
  `);
@@ -2425,7 +2439,7 @@ ${summarizeApproval(approval)}
2425
2439
  ])],
2426
2440
  subagentModels: createHarnessRouteModels(persistedRoutes),
2427
2441
  store: persistence.store,
2428
- memory: persistence.memory,
2442
+ projectMemory: options.projectMemory ?? true,
2429
2443
  onTelemetryEvent: orchestrationObserver(options.json || options.jsonl)
2430
2444
  });
2431
2445
  const approve = options.approve;
@@ -3152,6 +3166,82 @@ var manageChanges = async (options) => {
3152
3166
  process.exitCode = CLI_EXIT_CODES.runtimeError;
3153
3167
  };
3154
3168
 
3169
+ // src/persistence/project-memory-command.ts
3170
+ async function executeHarnessMemoryCommand(options, command, args, source = "Explicit operator input") {
3171
+ const counts = {
3172
+ remember: 1,
3173
+ list: 0,
3174
+ read: 1,
3175
+ update: 3,
3176
+ forget: 2,
3177
+ suggest: 1,
3178
+ accept: 2,
3179
+ clear: 0,
3180
+ enable: 0,
3181
+ disable: 0,
3182
+ context: 1
3183
+ };
3184
+ if (!Object.hasOwn(counts, command) || args.length !== counts[command])
3185
+ throw new HarnessConfigError("Invalid memory command arguments. Use memory --help.");
3186
+ const memory = await openHarnessProjectMemory(options);
3187
+ try {
3188
+ let result;
3189
+ switch (command) {
3190
+ case "list":
3191
+ result = memory.list();
3192
+ break;
3193
+ case "read":
3194
+ result = memory.read(args[0]);
3195
+ break;
3196
+ case "remember":
3197
+ result = memory.remember({ content: args[0], source });
3198
+ break;
3199
+ case "suggest":
3200
+ result = memory.suggest({ content: args[0], source });
3201
+ break;
3202
+ case "update":
3203
+ result = memory.update(args[0], Number(args[1]), { content: args[2], source });
3204
+ break;
3205
+ case "accept":
3206
+ result = memory.accept(args[0], Number(args[1]));
3207
+ break;
3208
+ case "forget":
3209
+ memory.forget(args[0], Number(args[1]));
3210
+ result = { forgotten: args[0] };
3211
+ break;
3212
+ case "clear":
3213
+ result = { cleared: memory.clear() };
3214
+ break;
3215
+ case "enable":
3216
+ case "disable":
3217
+ memory.setEnabled(command === "enable");
3218
+ result = { enabled: command === "enable" };
3219
+ break;
3220
+ case "context":
3221
+ result = memory.retrieve(args[0]);
3222
+ break;
3223
+ }
3224
+ const view = memory.list();
3225
+ return {
3226
+ schemaVersion: 1,
3227
+ kind: "memory-command",
3228
+ command,
3229
+ workspaceKey: view.workspaceKey,
3230
+ scopeKey: view.scopeKey,
3231
+ result
3232
+ };
3233
+ } finally {
3234
+ memory.close();
3235
+ }
3236
+ }
3237
+
3238
+ // src/cli/memory.ts
3239
+ async function manageMemory(options) {
3240
+ const document = await executeHarnessMemoryCommand(resolveHarnessConfig(options), options.memoryCommand, options.memoryArguments ?? [], options.memorySource);
3241
+ process.stdout.write(`${JSON.stringify(document, null, 2)}
3242
+ `);
3243
+ }
3244
+
3155
3245
  // src/persistence/state-backup-stream.ts
3156
3246
  var MAGIC = `ZHIVEX-STATE-SEGMENTS-1
3157
3247
  `;
@@ -3322,13 +3412,24 @@ async function readBackupTransport(source, legacyMaxBytes) {
3322
3412
  }
3323
3413
 
3324
3414
  // src/persistence/state-backup.ts
3325
- import { createHash as createHash4, randomUUID as randomUUID2 } from "node:crypto";
3415
+ import { createHash as createHash5, randomUUID as randomUUID2 } from "node:crypto";
3326
3416
  import { constants as fsConstants2 } from "node:fs";
3327
3417
  import { chmod, link, lstat as lstat2, open, realpath, unlink } from "node:fs/promises";
3328
3418
  import path4 from "node:path";
3329
3419
  import { z as z3 } from "zod";
3330
3420
  import { normalizeAgentRunState } from "@zhivex-ai/agents";
3331
3421
  import { createSqliteAgentRunStore } from "@zhivex-ai/agents/ops";
3422
+
3423
+ // src/persistence/sdk-store-identity.ts
3424
+ import { createHash as createHash4 } from "node:crypto";
3425
+ var sdkCanonicalKey = (kind, scope, value) => `${kind}:v2:${createHash4("sha256").update(JSON.stringify([
3426
+ JSON.stringify([scope.namespace ?? null, scope.tenantId, scope.userId ?? null]),
3427
+ value
3428
+ ])).digest("hex")}`;
3429
+ var sdkLegacyKey = (scope, value) => `${encodeURIComponent(scope.namespace ?? "default")}:${encodeURIComponent(scope.tenantId)}:${encodeURIComponent(scope.userId ?? "*")}:${value}`;
3430
+ var sdkRunKeyMatches = (key, scope, value) => key === sdkCanonicalKey("agent-run", scope, value) || key === sdkLegacyKey(scope, value);
3431
+
3432
+ // src/persistence/state-backup.ts
3332
3433
  var HARNESS_STATE_BACKUP_SCHEMA_VERSION = 1;
3333
3434
  var HARNESS_STATE_BACKUP_MAX_BYTES = 64 * 1024 * 1024;
3334
3435
  var terminalRunStatuses = new Set(["completed", "failed", "cancelled", "timed_out"]);
@@ -3383,6 +3484,8 @@ var memoryRecordSchema = z3.object({
3383
3484
  messages: z3.array(z3.unknown()),
3384
3485
  updatedAt: z3.number().int().nonnegative()
3385
3486
  }).strict();
3487
+ var serializedMemory = (entry) => JSON.stringify(entry.key.startsWith("agent-memory:v2:") ? { schemaVersion: 1, memoryKey: entry.key, messages: entry.messages } : entry.messages);
3488
+ 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)])));
3386
3489
  var sessionRecordSchema = z3.object({
3387
3490
  sessionId: z3.string().min(1).max(260),
3388
3491
  workspaceKey: bindingKeySchema,
@@ -3464,12 +3567,12 @@ var canonicalJson = (value) => {
3464
3567
  return `{${Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
3465
3568
  };
3466
3569
  var checksumPayload = (payload) => {
3467
- const hash = createHash4("sha256");
3570
+ const hash = createHash5("sha256");
3468
3571
  for (const chunk of canonicalChunks(payload))
3469
3572
  hash.update(chunk);
3470
3573
  return `sha256:${hash.digest("hex")}`;
3471
3574
  };
3472
- var stableKey = (kind, value) => createHash4("sha256").update(kind).update("\x00").update(value).digest("hex");
3575
+ var stableKey = (kind, value) => createHash5("sha256").update(kind).update("\x00").update(value).digest("hex");
3473
3576
  var scopeValue = (config) => `${config.scope.tenantId}\x00${config.scope.userId ?? ""}\x00${config.scope.namespace ?? ""}`;
3474
3577
  var scopePrefix = (config) => `${encodeURIComponent(config.scope.namespace ?? "default")}:${encodeURIComponent(config.scope.tenantId)}:${encodeURIComponent(config.scope.userId ?? "*")}:`;
3475
3578
  var stateMatchesScope = (config, state) => {
@@ -3481,7 +3584,6 @@ var stateMatchesScope = (config, state) => {
3481
3584
  const scope = candidate.scope;
3482
3585
  return scope.tenantId === config.scope.tenantId && (scope.userId ?? undefined) === (config.scope.userId ?? undefined) && (scope.namespace ?? undefined) === (config.scope.namespace ?? undefined);
3483
3586
  };
3484
- var budgetScopePrefix = (config) => `__zhivex_budget__:${encodeURIComponent(config.scope.tenantId)}:${encodeURIComponent(config.scope.userId ?? "*")}:`;
3485
3587
  var coordinatorIds = (runs) => new Set(runs.flatMap(({ state }) => {
3486
3588
  const id = state.budgetCoordinatorId;
3487
3589
  return typeof id === "string" ? [id] : [];
@@ -3489,7 +3591,7 @@ var coordinatorIds = (runs) => new Set(runs.flatMap(({ state }) => {
3489
3591
  var validateBudgetLedger = (config, run, identities) => {
3490
3592
  const state = validatedRunState(run.state, `Budget ledger ${run.key}`);
3491
3593
  const identity = state.metadata?.budgetIdentity;
3492
- if (state.scope?.namespace !== "__zhivex_budget__" || 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) || run.key !== `${budgetScopePrefix(config)}${state.runId}`) {
3594
+ if (state.scope?.namespace !== "__zhivex_budget__" || 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)) {
3493
3595
  throw new HarnessStateConflictError("Budget ledger is not bound to an exported run and durable scope.");
3494
3596
  }
3495
3597
  assertTerminalState(state, `Budget ledger ${run.key}`);
@@ -3667,12 +3769,16 @@ var readPayload = async (config, recordedWorkspace, accessLease) => {
3667
3769
  parentRunKey: row.parent_run_id,
3668
3770
  updatedAt: row.updated_at_ms
3669
3771
  }));
3670
- const memoryKeys = new Set(runs.map((run) => `${binding.scopePrefix}${String(run.state.runId)}`));
3671
- 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) => ({
3672
- key: row.memory_key,
3673
- messages: z3.array(z3.unknown()).parse(JSON.parse(row.messages_json)),
3674
- updatedAt: row.updated_at_ms
3675
- }));
3772
+ const memoryKeys = memoryKeysForRuns(config, runs);
3773
+ memoryKeys.add(projectMemoryRecordKey(binding));
3774
+ 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) => {
3775
+ const value = JSON.parse(row.messages_json);
3776
+ if (row.memory_key.startsWith("agent-memory:v2:")) {
3777
+ const envelope = z3.strictObject({ schemaVersion: z3.literal(1), memoryKey: z3.literal(row.memory_key), messages: z3.array(z3.unknown()) }).parse(value);
3778
+ return { key: row.memory_key, messages: envelope.messages, updatedAt: row.updated_at_ms };
3779
+ }
3780
+ return { key: row.memory_key, messages: z3.array(z3.unknown()).parse(value), updatedAt: row.updated_at_ms };
3781
+ });
3676
3782
  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);
3677
3783
  const selectedSessionIds = new Set(sessionRows.map((row) => row.session_id));
3678
3784
  const sessionRunRows = database.query("SELECT * FROM zhivex_cli_session_runs ORDER BY session_id, ordinal").all().filter((row) => selectedSessionIds.has(row.session_id));
@@ -3865,7 +3971,7 @@ var validateBundleBinding = async (config, bundle) => {
3865
3971
  throw new HarnessStateConflictError(`Run ${run.key} is bound to another durable scope.`);
3866
3972
  }
3867
3973
  runIds.add(state.runId);
3868
- if (run.key !== `${expected.scopePrefix}${state.runId}`) {
3974
+ if (!sdkRunKeyMatches(run.key, config.scope, state.runId)) {
3869
3975
  throw new HarnessStateConflictError(`Run ${run.key} does not match its bound scope and runId.`);
3870
3976
  }
3871
3977
  }
@@ -3884,7 +3990,7 @@ var validateBundleBinding = async (config, bundle) => {
3884
3990
  const journalKeys = new Set;
3885
3991
  for (const entry of bundle.records.toolJournal) {
3886
3992
  const journalKey = `${entry.runKey}\x00${entry.toolCallId}`;
3887
- if (journalKeys.has(journalKey) || !runKeys.has(entry.runKey) || !stateMatchesScope(config, entry.entry) || entry.entry.runId !== entry.runKey.slice(expected.scopePrefix.length)) {
3993
+ if (journalKeys.has(journalKey) || !runKeys.has(entry.runKey) || !stateMatchesScope(config, entry.entry) || entry.entry.runId !== bundle.records.runs.find((run) => run.key === entry.runKey)?.state.runId) {
3888
3994
  throw new HarnessStateConflictError(`Tool journal ${entry.toolCallId} is not bound to an imported run.`);
3889
3995
  }
3890
3996
  journalKeys.add(journalKey);
@@ -3896,7 +4002,7 @@ var validateBundleBinding = async (config, bundle) => {
3896
4002
  }
3897
4003
  idempotencyKeys.add(entry.key);
3898
4004
  const state = bundle.records.runs.find((run) => run.key === entry.runKey).state;
3899
- if (typeof state.idempotencyKey !== "string" || entry.key !== `${expected.scopePrefix}${state.idempotencyKey}`) {
4005
+ if (typeof state.idempotencyKey !== "string" || !sdkRunKeyMatches(entry.key, config.scope, state.idempotencyKey)) {
3900
4006
  throw new HarnessStateConflictError("Idempotency record does not match its bound run state.");
3901
4007
  }
3902
4008
  }
@@ -3908,9 +4014,12 @@ var validateBundleBinding = async (config, bundle) => {
3908
4014
  parentKeys.add(entry.runKey);
3909
4015
  }
3910
4016
  const memoryKeys = new Set;
4017
+ const allowedMemoryKeys = memoryKeysForRuns(config, bundle.records.runs);
3911
4018
  for (const entry of bundle.records.memory) {
3912
- const memoryRunId = entry.key.startsWith(expected.scopePrefix) ? entry.key.slice(expected.scopePrefix.length) : "";
3913
- if (memoryKeys.has(entry.key) || !runIds.has(memoryRunId)) {
4019
+ const projectRecord = entry.key === projectMemoryRecordKey(expected);
4020
+ if (projectRecord)
4021
+ decodeProjectMemory(entry.messages, expected);
4022
+ if (memoryKeys.has(entry.key) || !projectRecord && !allowedMemoryKeys.has(entry.key)) {
3914
4023
  throw new HarnessStateConflictError(`Memory record ${entry.key} is not bound to an imported run.`);
3915
4024
  }
3916
4025
  memoryKeys.add(entry.key);
@@ -3952,7 +4061,7 @@ var validateBundleBinding = async (config, bundle) => {
3952
4061
  const turn = bundle.records.sessionRuns.find((run) => run.turnId === checkpoint.turnId && run.sessionId === checkpoint.sessionId);
3953
4062
  if (!turn || !terminalSessionStatuses.has(turn.status))
3954
4063
  throw new HarnessStateConflictError("Checkpoint targets a missing terminal turn.");
3955
- if (new Set(checkpoint.files.map((file) => file.path)).size !== checkpoint.files.length || checkpoint.files.some((file) => `sha256:${createHash4("sha256").update(file.content).digest("hex")}` !== file.digest || Buffer.byteLength(file.content) > 65536)) {
4064
+ if (new Set(checkpoint.files.map((file) => file.path)).size !== checkpoint.files.length || checkpoint.files.some((file) => `sha256:${createHash5("sha256").update(file.content).digest("hex")}` !== file.digest || Buffer.byteLength(file.content) > 65536)) {
3956
4065
  throw new HarnessStateConflictError("Checkpoint content identity is invalid.");
3957
4066
  }
3958
4067
  if (record.kind === "restore") {
@@ -4049,9 +4158,9 @@ var importHarnessStateBackup = async (config, bundle, options = {}) => {
4049
4158
  toolJournal: new Set(availableTables.has("zhivex_agent_runs_tool_journal") ? database.query("SELECT run_key, tool_call_id, entry_json, revision, updated_at_ms FROM zhivex_agent_runs_tool_journal").all().filter((row) => destinationRunKeys.has(row.run_key)).map((row) => `${row.run_key}\x00${row.tool_call_id}`) : []),
4050
4159
  idempotency: new Set(availableTables.has("zhivex_agent_runs_idempotency") ? database.query("SELECT idempotency_key, run_id, updated_at_ms FROM zhivex_agent_runs_idempotency").all().filter((row) => destinationRunKeys.has(row.run_id)).map((row) => row.idempotency_key) : []),
4051
4160
  parents: new Set(availableTables.has("zhivex_agent_runs_parents") ? database.query("SELECT run_id, parent_run_id, updated_at_ms FROM zhivex_agent_runs_parents").all().filter((row) => destinationRunKeys.has(row.run_id)).map((row) => row.run_id) : []),
4052
- memory: new Set(availableTables.has("zhivex_agent_memory") ? database.query("SELECT memory_key, messages_json, updated_at_ms FROM zhivex_agent_memory").all().filter((row) => destinationRunRows.some((run) => {
4161
+ memory: new Set(availableTables.has("zhivex_agent_memory") ? database.query("SELECT memory_key, messages_json, updated_at_ms FROM zhivex_agent_memory").all().filter((row) => row.memory_key === projectMemoryRecordKey(bundle.binding) || destinationRunRows.some((run) => {
4053
4162
  const state = JSON.parse(run.state_json);
4054
- return row.memory_key === `${bundle.binding.scopePrefix}${String(state.runId)}`;
4163
+ return memoryKeysForRuns(config, [{ state }]).has(row.memory_key);
4055
4164
  })).map((row) => row.memory_key) : []),
4056
4165
  sessions: destinationSessionIds,
4057
4166
  sessionRuns: new Set(availableTables.has("zhivex_cli_session_runs") ? database.query("SELECT * FROM zhivex_cli_session_runs ORDER BY session_id, ordinal").all().filter((row) => destinationSessionIds.has(row.session_id)).map((row) => row.turn_id) : [])
@@ -4077,7 +4186,7 @@ var importHarnessStateBackup = async (config, bundle, options = {}) => {
4077
4186
  for (const entry of bundle.records.toolJournal)
4078
4187
  insertOrCompare("zhivex_agent_runs_tool_journal", "run_key = ? AND tool_call_id = ?", [entry.runKey, entry.toolCallId], "entry_json, revision, updated_at_ms", [JSON.stringify(entry.entry), entry.revision, entry.updatedAt], "INSERT INTO zhivex_agent_runs_tool_journal (run_key, tool_call_id, entry_json, revision, updated_at_ms) VALUES (?, ?, ?, ?, ?)", [entry.runKey, entry.toolCallId, JSON.stringify(entry.entry), entry.revision, entry.updatedAt]);
4079
4188
  for (const entry of bundle.records.memory)
4080
- insertOrCompare("zhivex_agent_memory", "memory_key = ?", [entry.key], "messages_json, updated_at_ms", [JSON.stringify(entry.messages), entry.updatedAt], "INSERT INTO zhivex_agent_memory (memory_key, messages_json, updated_at_ms) VALUES (?, ?, ?)", [entry.key, JSON.stringify(entry.messages), entry.updatedAt]);
4189
+ insertOrCompare("zhivex_agent_memory", "memory_key = ?", [entry.key], "messages_json, updated_at_ms", [serializedMemory(entry), entry.updatedAt], "INSERT INTO zhivex_agent_memory (memory_key, messages_json, updated_at_ms) VALUES (?, ?, ?)", [entry.key, serializedMemory(entry), entry.updatedAt]);
4081
4190
  for (const session of bundle.records.sessions)
4082
4191
  insertOrCompare("zhivex_cli_sessions", "session_id = ?", [session.sessionId], "workspace_key, scope_key, title, parent_session_id, forked_from_turn_id, revision, activity_seq, created_at, updated_at, archived_at, deleted_at, metadata_bytes", [
4083
4192
  session.workspaceKey,
@@ -4360,7 +4469,7 @@ var main = async (argv = process.argv.slice(2)) => {
4360
4469
  parsedOptions = { ...parsedOptions, prompt: await readStdinTask() };
4361
4470
  }
4362
4471
  if (parsedOptions.serviceFile) {
4363
- const { runServiceCli } = await import("./service-client-cli-3365rfav.js");
4472
+ const { runServiceCli } = await import("./service-client-cli-b52c67hx.js");
4364
4473
  await runServiceCli(parsedOptions, annotateCliStreamError);
4365
4474
  return;
4366
4475
  }
@@ -4417,6 +4526,9 @@ var main = async (argv = process.argv.slice(2)) => {
4417
4526
  case "changes":
4418
4527
  await manageChanges(options);
4419
4528
  return;
4529
+ case "memory":
4530
+ await manageMemory(options);
4531
+ return;
4420
4532
  case "state":
4421
4533
  await manageState(options);
4422
4534
  return;
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  HARNESS_VERSION,
4
4
  shortCliHelp
5
- } from "./cli-entry-bx3vjw7h.js";
5
+ } from "./cli-entry-4k1cf0m3.js";
6
6
  import {
7
7
  __require
8
8
  } from "./cli-entry-1bx83sw4.js";
@@ -16,6 +16,6 @@ if (argv.length === 1 && ["--version", "-v", "version"].includes(argv[0])) {
16
16
  process.stdout.write(`${shortCliHelp(HARNESS_VERSION)}
17
17
  `);
18
18
  } else {
19
- const { runCli } = await import("./cli-etsmtst3.js");
19
+ const { runCli } = await import("./cli-s1rs15vv.js");
20
20
  await runCli(argv);
21
21
  }
@@ -0,0 +1,17 @@
1
+ /** Redacted observation only: no argv, inputs, stdout, stderr or pass claims for a task. */
2
+ export declare function checkEvidence(results: readonly {
3
+ toolName: string;
4
+ output?: unknown;
5
+ isError?: boolean;
6
+ }[]): {
7
+ coverage: 'recorded-checks-only';
8
+ receipts: {
9
+ toolName: string;
10
+ exitCode: number;
11
+ timedOut: boolean;
12
+ passed: boolean;
13
+ }[];
14
+ passed: number;
15
+ failed: number;
16
+ taskVerified: false;
17
+ };
@@ -10,6 +10,18 @@ export declare const runResultDocument: (result: AgentRunOutput, harness: Zhivex
10
10
  output: string;
11
11
  steps: number;
12
12
  toolCalls: number;
13
+ verification: {
14
+ coverage: 'recorded-checks-only';
15
+ receipts: {
16
+ toolName: string;
17
+ exitCode: number;
18
+ timedOut: boolean;
19
+ passed: boolean;
20
+ }[];
21
+ passed: number;
22
+ failed: number;
23
+ taskVerified: false;
24
+ };
13
25
  mutations: readonly {
14
26
  id: string;
15
27
  operation: "create" | "move" | "quarantine" | "restore" | "update";
@@ -8,7 +8,7 @@ export interface CliCommandOptionContract {
8
8
  repeatable: readonly string[];
9
9
  conflicts: Readonly<Record<string, readonly string[]>>;
10
10
  }
11
- export declare const CLI_OPTION_NAMES: readonly ["--compaction-model", "--compaction-provider", "--provider", "--model", "--reasoning", "--profile", "--route", "--workspace", "--state-dir", "--mcp-config", "--context-config", "--no-project-context", "--patch", "--preconditions", "--now", "--require-verified-delivery", "--execution", "--oci-runtime", "--oci-image", "--oci-allow-command", "--oci-shell", "--oci-max-process-runtime-ms", "--oci-max-process-output-bytes", "--oci-max-memory-mb", "--oci-max-pids", "--oci-max-cpus", "--oci-max-workspace-bytes", "--oci-max-file-write-bytes", "--oci-tmpfs-mb", "--store", "--tenant", "--user", "--namespace", "--idempotency-key", "--token-budget", "--context-tokens", "--no-token-budget", "--max-steps", "--timeout-ms", "--max-tool-calls", "--max-tool-errors", "--max-input-tokens", "--max-output-tokens", "--max-total-tokens", "--subagent-max-steps", "--subagent-max-tool-calls", "--subagent-max-tool-errors", "--subagent-max-input-tokens", "--subagent-max-output-tokens", "--subagent-max-total-tokens", "--subagent-timeout-ms", "--max-parallel-reviews", "--max-cost-usd", "--input-cost-per-million", "--output-cost-per-million", "--allow-check", "--require-capability", "--subagent", "--reviewer", "--approval-mode", "--yes", "--approve", "--deny", "--json", "--jsonl", "--session", "--continue", "--update", "--status", "--limit", "--cursor", "--before", "--reason", "--cascade", "--final", "--service", "--apply", "--help", "--version", "--search", "--tool-policy", "--pricing-file", "--usage-limit-usd"];
11
+ export declare const CLI_OPTION_NAMES: readonly ["--compaction-model", "--compaction-provider", "--provider", "--model", "--reasoning", "--profile", "--route", "--workspace", "--state-dir", "--mcp-config", "--no-memory", "--source", "--context-config", "--no-project-context", "--patch", "--preconditions", "--now", "--require-verified-delivery", "--execution", "--oci-runtime", "--oci-image", "--oci-allow-command", "--oci-shell", "--oci-max-process-runtime-ms", "--oci-max-process-output-bytes", "--oci-max-memory-mb", "--oci-max-pids", "--oci-max-cpus", "--oci-max-workspace-bytes", "--oci-max-file-write-bytes", "--oci-tmpfs-mb", "--store", "--tenant", "--user", "--namespace", "--idempotency-key", "--token-budget", "--context-tokens", "--no-token-budget", "--max-steps", "--timeout-ms", "--max-tool-calls", "--max-tool-errors", "--max-input-tokens", "--max-output-tokens", "--max-total-tokens", "--subagent-max-steps", "--subagent-max-tool-calls", "--subagent-max-tool-errors", "--subagent-max-input-tokens", "--subagent-max-output-tokens", "--subagent-max-total-tokens", "--subagent-timeout-ms", "--max-parallel-reviews", "--max-cost-usd", "--input-cost-per-million", "--output-cost-per-million", "--allow-check", "--require-capability", "--subagent", "--reviewer", "--approval-mode", "--yes", "--approve", "--deny", "--json", "--jsonl", "--session", "--continue", "--update", "--status", "--limit", "--cursor", "--before", "--reason", "--cascade", "--final", "--service", "--apply", "--help", "--version", "--search", "--tool-policy", "--pricing-file", "--usage-limit-usd"];
12
12
  export type CliOptionName = (typeof CLI_OPTION_NAMES)[number];
13
13
  export declare const CLI_OPTION_DEFINITIONS: Readonly<Record<CliOptionName, CliOptionDefinition>>;
14
14
  export declare const CLI_COMMAND_OPTION_CONTRACTS: {
@@ -43,6 +43,17 @@ export declare const CLI_COMMAND_OPTION_CONTRACTS: {
43
43
  readonly "checkpoints:recover": CliCommandOptionContract;
44
44
  readonly "changes:create": CliCommandOptionContract;
45
45
  readonly "changes:verify": CliCommandOptionContract;
46
+ readonly "memory:remember": CliCommandOptionContract;
47
+ readonly "memory:suggest": CliCommandOptionContract;
48
+ readonly "memory:list": CliCommandOptionContract;
49
+ readonly "memory:read": CliCommandOptionContract;
50
+ readonly "memory:update": CliCommandOptionContract;
51
+ readonly "memory:forget": CliCommandOptionContract;
52
+ readonly "memory:accept": CliCommandOptionContract;
53
+ readonly "memory:clear": CliCommandOptionContract;
54
+ readonly "memory:enable": CliCommandOptionContract;
55
+ readonly "memory:disable": CliCommandOptionContract;
56
+ readonly "memory:context": CliCommandOptionContract;
46
57
  readonly "state:status": CliCommandOptionContract;
47
58
  readonly "state:export": CliCommandOptionContract;
48
59
  readonly "state:import": CliCommandOptionContract;
@@ -20,3 +20,7 @@ export { inspectRuntimeDiagnostics } from "../runtime/runtime-diagnostics.js";
20
20
  export { harnessToolExecution } from "../runtime/tool-execution.js";
21
21
  export { USAGE_LEDGER_KEY, formatUsageLedger, inspectUsageLedger, usagePricingSchema } from "../runtime/usage-ledger.js";
22
22
  export { FileChangedWhileReadingError, FileSizeLimitError, UnsafeFileTypeError, readRegularFileNoFollow } from "../workspace/file-security.js";
23
+ export { resolvePackageCheckCommand } from "../execution/package-manager.js";
24
+ export { nativeTaskSnapshot } from "../runtime/task-acceptance-native.js";
25
+ export { TASK_ACCEPTANCE_EVIDENCE_KEY } from "../runtime/task-acceptance-record.js";
26
+ export { checkEvidence } from "../client/check-evidence.js";
@@ -2,9 +2,12 @@ import {
2
2
  loadModelCatalog
3
3
  } from "../index-wg1sd3at.js";
4
4
  import {
5
- estimateMessages
6
- } from "../index-8zzhggxv.js";
5
+ checkEvidence,
6
+ estimateMessages,
7
+ nativeTaskSnapshot
8
+ } from "../index-a1q355va.js";
7
9
  import {
10
+ TASK_ACCEPTANCE_EVIDENCE_KEY,
8
11
  TASK_SOURCE_KEY,
9
12
  USAGE_LEDGER_KEY,
10
13
  formatUsageLedger,
@@ -13,16 +16,17 @@ import {
13
16
  inspectUsageLedger,
14
17
  taskSources,
15
18
  usagePricingSchema
16
- } from "../index-42gp2hy8.js";
19
+ } from "../index-vtqfjnab.js";
17
20
  import {
18
21
  FileChangedWhileReadingError,
19
22
  FileSizeLimitError,
20
23
  SqliteDatabase,
21
24
  UnsafeFileTypeError,
22
25
  readRegularFileNoFollow,
26
+ resolvePackageCheckCommand,
23
27
  resolvePackageManager,
24
28
  runPortableProcess
25
- } from "../index-yb239ghk.js";
29
+ } from "../index-r0tdj04h.js";
26
30
  import {
27
31
  DEFAULT_HARNESS_MAX_STEPS,
28
32
  modelReasoningEfforts,
@@ -51,11 +55,13 @@ export {
51
55
  DEFAULT_HARNESS_MAX_STEPS,
52
56
  FileChangedWhileReadingError,
53
57
  FileSizeLimitError,
58
+ TASK_ACCEPTANCE_EVIDENCE_KEY,
54
59
  TASK_SOURCE_KEY,
55
60
  USAGE_LEDGER_KEY,
56
61
  UnsafeFileTypeError,
57
62
  bundledModelCatalog,
58
63
  catalogModels,
64
+ checkEvidence,
59
65
  estimateMessages,
60
66
  formatUsageLedger,
61
67
  harnessToolExecution,
@@ -65,8 +71,10 @@ export {
65
71
  loadModelCatalog,
66
72
  modelDescription,
67
73
  modelReasoningEfforts,
74
+ nativeTaskSnapshot,
68
75
  readRegularFileNoFollow,
69
76
  reasoningEffortSchema,
77
+ resolvePackageCheckCommand,
70
78
  resolvePackageManager,
71
79
  runPortableProcess,
72
80
  taskSources,
@@ -11,4 +11,9 @@ export declare const compactedTaskSources: (messages: readonly ModelMessage[]) =
11
11
  text: string;
12
12
  original?: true;
13
13
  }[] | undefined;
14
+ export declare const compactedAssistantResponses: (messages: readonly ModelMessage[]) => {
15
+ id: string;
16
+ text: string;
17
+ truncated: boolean;
18
+ }[] | undefined;
14
19
  export declare const compactMessages: (messages: readonly ModelMessage[]) => ModelMessage[];
@@ -0,0 +1,6 @@
1
+ import type { LanguageModelMiddleware } from "@zhivex-ai/core";
2
+ import type { HarnessProjectMemory } from "../persistence/project-memory.js";
3
+ /** Per-request projection; memory text never enters system instructions or durable
4
+ * run messages. Reload for every request so edits, forgetting and opt-out apply
5
+ * even to a resumed run. Existing conversation history has its own retention. */
6
+ export declare function createProjectMemoryMiddleware(memory: HarnessProjectMemory): LanguageModelMiddleware;
@@ -1,6 +1,17 @@
1
1
  import { type ModelMessage } from "@zhivex-ai/core";
2
2
  import { z } from "zod";
3
3
  export declare const TASK_SOURCE_KEY = "zhivexTaskSources";
4
+ export declare const ASSISTANT_RESPONSE_KEY = "zhivexAssistantResponses";
5
+ export declare const MAX_ASSISTANT_RESPONSES = 3;
6
+ export declare const MAX_ASSISTANT_RESPONSE_CHARACTERS = 64000;
7
+ type AssistantResponse = {
8
+ id: string;
9
+ text: string;
10
+ truncated: boolean;
11
+ };
12
+ /** Bounded, untrusted assistant text. Never an operator source or acceptance ledger. */
13
+ export declare const assistantResponses: (metadata: unknown) => AssistantResponse[];
14
+ export declare const captureAssistantResponses: (metadata: unknown, messages: readonly ModelMessage[]) => AssistantResponse[];
4
15
  type TaskSource = {
5
16
  id: string;
6
17
  text: string;
@@ -11,10 +22,31 @@ export declare const taskSources: (metadata: unknown) => TaskSource[];
11
22
  export declare const captureTaskSources: (metadata: unknown, messages: readonly ModelMessage[]) => TaskSource[];
12
23
  export declare const createTaskTools: () => {
13
24
  read_task: import("@zhivex-ai/core").ToolDefinition<z.ZodObject<{
25
+ source: z.ZodOptional<z.ZodEnum<{
26
+ assistant_response: "assistant_response";
27
+ operator: "operator";
28
+ }>>;
29
+ query: z.ZodOptional<z.ZodString>;
14
30
  id: z.ZodOptional<z.ZodString>;
15
- offset: z.ZodDefault<z.ZodNumber>;
31
+ offset: z.ZodOptional<z.ZodNumber>;
16
32
  sourceOffset: z.ZodOptional<z.ZodNumber>;
17
33
  }, z.core.$strip>, {
34
+ source: string;
35
+ untrusted: true;
36
+ verified: false;
37
+ id: string;
38
+ sourceIds: string[];
39
+ totalSources: number;
40
+ truncated: boolean;
41
+ content: string;
42
+ offset: number;
43
+ totalCharacters: number;
44
+ nextOffset: number | null;
45
+ } | {
46
+ source?: never;
47
+ untrusted?: never;
48
+ verified?: never;
49
+ truncated?: never;
18
50
  id: string;
19
51
  sourceIds: string[];
20
52
  acceptance?: import("@zhivex-ai/core").JsonValue;
@@ -2,7 +2,7 @@ import {
2
2
  discardMcpWorkspaceSnapshot,
3
3
  launchDockerMcpGroup,
4
4
  prepareMcpWorkspaceSnapshot
5
- } from "../index-6m08wvab.js";
5
+ } from "../index-2tgb2b4e.js";
6
6
  import {
7
7
  createAcpConnection,
8
8
  issueAcpMcpSessionProvider,
@@ -11,13 +11,13 @@ import {
11
11
  import {
12
12
  createHarness,
13
13
  createHarnessClientAdapter
14
- } from "../index-hnaxfpb5.js";
15
- import"../index-h0mqx2ed.js";
16
- import"../index-8zzhggxv.js";
17
- import"../index-42gp2hy8.js";
18
- import"../index-azmwjp95.js";
19
- import"../index-z0qxmkm2.js";
20
- import"../index-yb239ghk.js";
14
+ } from "../index-4j1h4j8c.js";
15
+ import"../index-rd0s3gqj.js";
16
+ import"../index-a1q355va.js";
17
+ import"../index-vtqfjnab.js";
18
+ import"../index-0g939pfs.js";
19
+ import"../index-e6r04a18.js";
20
+ import"../index-r0tdj04h.js";
21
21
  import"../index-gq9xagx2.js";
22
22
  import"../index-8705zxpr.js";
23
23
  import"../index-xqxeypt5.js";