@zhivex-ai/harness 1.4.1 → 1.6.2

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 (76) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/SUPPORT.md +1 -1
  4. package/contracts/stable-api-signatures.json +7 -7
  5. package/dist/acp-cli.js +10 -10
  6. package/dist/approvals/approval-diff.d.ts +2 -1
  7. package/dist/approvals/approval-preview.d.ts +1 -1
  8. package/dist/approvals/auto-approve.d.ts +137 -0
  9. package/dist/audit/index.js +6 -6
  10. package/dist/{audit-pack-e4vaq7np.js → audit-pack-fckpqfsb.js} +3 -3
  11. package/dist/{cli-1cf4dcnj.js → cli-84en174d.js} +14 -8
  12. package/dist/{cli-entry-3s63zn4w.js → cli-entry-10th5awp.js} +16 -15
  13. package/dist/{cli-entry-a890x3kq.js → cli-entry-4g2ewcnw.js} +15 -5
  14. package/dist/{cli-entry-7f0cen32.js → cli-entry-6amx4mcc.js} +209 -68
  15. package/dist/{cli-entry-rgs6bxmy.js → cli-entry-z1pbjrg4.js} +2 -2
  16. package/dist/cli.js +2 -2
  17. package/dist/compat/code-support.js +8 -8
  18. package/dist/engine/acp.js +11 -11
  19. package/dist/engine/client.js +10 -10
  20. package/dist/engine/desktop-state-v1.js +6 -6
  21. package/dist/engine/index.js +15 -15
  22. package/dist/engine/mcp-stdio-v1.js +5 -5
  23. package/dist/engine/service.js +11 -11
  24. package/dist/hostile-repository-demo.js +235 -84
  25. package/dist/{index-mv8sb1ns.js → index-1pn0ecs4.js} +55 -13
  26. package/dist/{index-dtb2c6ds.js → index-2r4f0p4n.js} +2 -2
  27. package/dist/{index-6599mpmy.js → index-4mn6m3bq.js} +3 -3
  28. package/dist/{index-xdbkcccf.js → index-6dxrbnxm.js} +2 -2
  29. package/dist/{index-crta5wzv.js → index-74f9yhfh.js} +4 -4
  30. package/dist/{index-f6mqa5gk.js → index-amjttjaj.js} +11 -39
  31. package/dist/{index-wm9xeq1n.js → index-bt2p8x7r.js} +1 -1
  32. package/dist/{index-sk3cap35.js → index-eps3c3g6.js} +1 -1
  33. package/dist/{index-zxg4ve4j.js → index-fqqz1yt8.js} +77 -4
  34. package/dist/{index-02pqtbbg.js → index-paf7z8kn.js} +10 -10
  35. package/dist/{index-0zs2dz26.js → index-pf73y4gt.js} +18 -9
  36. package/dist/{index-74kkpyqk.js → index-rgqzdgv6.js} +12 -6
  37. package/dist/{index-4fx5f3k5.js → index-rz7wmp71.js} +16 -15
  38. package/dist/{index-d9zkmhz3.js → index-w0m1nckc.js} +127 -28
  39. package/dist/{index-sstgcsr0.js → index-yx52bt4a.js} +1 -1
  40. package/dist/{index-j6zxnc8m.js → index-zrz4rs7p.js} +5 -5
  41. package/dist/index.js +14 -14
  42. package/dist/integrations/mcp-stdio-tools.d.ts +4 -1
  43. package/dist/providers/bedrock.d.ts +1 -1
  44. package/dist/review/reveal-invisible.d.ts +13 -0
  45. package/dist/runtime/budget-ledger-scope.d.ts +14 -0
  46. package/dist/service-cli.js +11 -11
  47. package/dist/{service-client-cli-eqrdc9zq.js → service-client-cli-pp5z4dmf.js} +4 -4
  48. package/dist/tools/workspace.d.ts +2 -2
  49. package/dist/verify-historical-migrations.js +240 -86
  50. package/dist/workspace/edit-contracts.d.ts +2 -2
  51. package/dist/workspace/path-policy.d.ts +2 -1
  52. package/dist/workspace/text-integrity.d.ts +19 -0
  53. package/dist/workspace/workspace.d.ts +21 -3
  54. package/dist/zhx.js +2 -2
  55. package/docs/AUTO_APPROVE.md +51 -0
  56. package/docs/AZURE_OPENAI.md +4 -4
  57. package/docs/BEDROCK.md +4 -4
  58. package/docs/CLI.md +13 -0
  59. package/docs/CODE_RELEASE.md +36 -6
  60. package/docs/CODE_WEB_TASKS.md +1 -1
  61. package/docs/CREDENTIALS.md +1 -1
  62. package/docs/DURABLE_OPERATIONS.md +1 -1
  63. package/docs/ENGINE_API.md +1 -1
  64. package/docs/EXTENSIBILITY.md +7 -3
  65. package/docs/FIRST_USE.md +6 -6
  66. package/docs/MINIMUM_TASK_AUTHORITY.md +5 -5
  67. package/docs/PROJECT_MEMORY.md +1 -1
  68. package/docs/PUBLIC_SECURITY.md +14 -1
  69. package/docs/REPOSITORY_EDITING.md +1 -1
  70. package/docs/TOOL_POLICY.md +7 -1
  71. package/docs/VERTEX.md +2 -2
  72. package/docs/WEB_LIMITS.md +2 -2
  73. package/docs/adr/0002-isolated-mcp-stdio.md +2 -2
  74. package/evaluations/representative-assembly-matrix.json +37 -1
  75. package/examples/README.md +3 -3
  76. package/package.json +16 -15
@@ -96,8 +96,8 @@ var quarantineFileInputSchema = z.strictObject({
96
96
  });
97
97
  var restoreFileInputSchema = z.strictObject({
98
98
  quarantineId: z.string().min(1).max(200).regex(/^[A-Za-z0-9._:-]+$/),
99
- destination: workspaceFilePathSchema.optional(),
100
- expectedDigest: fileDigestSchema.optional()
99
+ destination: workspaceFilePathSchema.describe("Required workspace path for the quarantined bytes. Restore does not fall back to the original path."),
100
+ expectedDigest: fileDigestSchema.describe("Required sha256 of the quarantined bytes the operator reviewed.")
101
101
  });
102
102
  var mutationOperationSchema = z.enum(["create", "update", "move", "quarantine", "restore"]);
103
103
  var mutationAuditEntrySchema = z.strictObject({
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  createHarnessClientAdapter
3
- } from "./index-02pqtbbg.js";
3
+ } from "./index-paf7z8kn.js";
4
4
  import {
5
5
  harnessPolicyDecisionEventSchema
6
- } from "./index-wm9xeq1n.js";
6
+ } from "./index-bt2p8x7r.js";
7
7
  import {
8
8
  openCliSessionStore
9
- } from "./index-zxg4ve4j.js";
9
+ } from "./index-fqqz1yt8.js";
10
10
  import {
11
11
  SqliteDatabase
12
- } from "./index-xdbkcccf.js";
12
+ } from "./index-6dxrbnxm.js";
13
13
  import {
14
14
  harnessClientRequestSchema,
15
15
  streamEventDocument
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  harnessExecutionSession
3
- } from "./index-d9zkmhz3.js";
3
+ } from "./index-w0m1nckc.js";
4
4
  import {
5
5
  defaultHarnessNamespace
6
6
  } from "./index-1265j7t2.js";
@@ -9,20 +9,23 @@ import {
9
9
  TASK_BUDGET_KEY,
10
10
  TaskBudget,
11
11
  USAGE_LEDGER_KEY,
12
+ bindBudgetLedgerStore,
13
+ budgetLedgerScope,
12
14
  ensurePrivateDatabase,
13
15
  estimateRequestTokens,
14
16
  inspectRuntimeDiagnostics,
15
17
  inspectRuntimeManifest,
16
18
  inspectTaskBudgetSummary,
17
19
  inspectUsageLedger,
20
+ isReservedBudgetNamespace,
18
21
  protectStateFromGit,
19
22
  readTaskAcceptanceLedger,
20
23
  validateStateDirectory,
21
24
  withRuntimeInstruction
22
- } from "./index-zxg4ve4j.js";
25
+ } from "./index-fqqz1yt8.js";
23
26
  import {
24
27
  SqliteDatabase
25
- } from "./index-xdbkcccf.js";
28
+ } from "./index-6dxrbnxm.js";
26
29
  import {
27
30
  HarnessConfigError,
28
31
  HarnessStateConflictError,
@@ -869,37 +872,7 @@ import {
869
872
  createSqliteAgentRunStore
870
873
  } from "@zhivex-ai/agents/ops";
871
874
  import { createAgentRunLedger } from "@zhivex-ai/agents/control-plane";
872
- var budgetScopeFor = (config) => ({
873
- tenantId: config.scope.tenantId,
874
- ...config.scope.userId ? { userId: config.scope.userId } : {},
875
- namespace: "__zhivex_budget__"
876
- });
877
- var withBudgetLedgerStore = (primary, budget, config) => {
878
- const scope = budgetScopeFor(config);
879
- const budgetScope = (value) => value?.namespace === scope.namespace && value.tenantId === scope.tenantId && (value.userId ?? undefined) === (scope.userId ?? undefined);
880
- const assertId = (id) => {
881
- if (!/^budget_[a-f0-9]{64}$/.test(id))
882
- throw new HarnessStateConflictError("Invalid budget ledger identity.");
883
- };
884
- return {
885
- ...primary,
886
- load: async (id, requestedScope) => {
887
- if (!budgetScope(requestedScope))
888
- return primary.load(id, requestedScope);
889
- assertId(id);
890
- return budget.load(id, requestedScope);
891
- },
892
- save: async (state, options) => {
893
- if (!budgetScope(state.scope))
894
- return primary.save(state, options);
895
- assertId(state.runId);
896
- if (state.provider !== "zhivex" || state.modelId !== "budget-coordinator" || state.metadata?.budgetCoordinator !== true) {
897
- throw new HarnessStateConflictError("Only SDK budget ledger states may use the reserved namespace.");
898
- }
899
- return budget.save(state, options);
900
- }
901
- };
902
- };
875
+ var withBudgetLedgerStore = (primary, budget, config) => bindBudgetLedgerStore(primary, config.scope, budget);
903
876
  var HARNESS_SQLITE_FILE = "operations.sqlite";
904
877
  var HARNESS_OPERATIONS_SCHEMA_VERSION = 1;
905
878
  var TERMINAL_RUN_STATUSES = ["completed", "failed", "cancelled", "timed_out"];
@@ -1154,13 +1127,12 @@ var migrateLegacyFileRuns = async (directory, target, config) => {
1154
1127
  return result;
1155
1128
  };
1156
1129
  var openHarnessPersistence = async (config, options = {}) => {
1157
- if (config.scope.namespace === "__zhivex_budget__")
1158
- throw new HarnessStateConflictError("The budget ledger namespace is reserved.");
1130
+ const budgetScope = budgetLedgerScope(config.scope);
1159
1131
  await validateStateDirectory(config.workspace, config.stateDirectory);
1160
1132
  await ensurePrivateStateDirectory(config.stateDirectory);
1161
1133
  await protectStateFromGit(config.workspace, config.stateDirectory);
1162
1134
  if (config.storeBackend === "file") {
1163
- const store = withBudgetLedgerStore(createFileAgentRunStore({ directory: config.stateDirectory, scope: config.scope }), createFileAgentRunStore({ directory: config.stateDirectory, scope: budgetScopeFor(config) }), config);
1135
+ const store = withBudgetLedgerStore(createFileAgentRunStore({ directory: config.stateDirectory, scope: config.scope }), createFileAgentRunStore({ directory: config.stateDirectory, scope: budgetScope }), config);
1164
1136
  const migration = shouldMigrateLegacyRuns(config, options.migrateLegacyFileStore) ? await migrateLegacyFileRuns(config.stateDirectory, store, config) : emptyMigration();
1165
1137
  return {
1166
1138
  backend: "file",
@@ -1205,7 +1177,7 @@ var openHarnessPersistence = async (config, options = {}) => {
1205
1177
  database.exec("PRAGMA foreign_keys = ON");
1206
1178
  await chmod(databasePath, 384);
1207
1179
  const databaseLike = sqliteAdapter(database);
1208
- const store = withBudgetLedgerStore(createSqliteAgentRunStore({ db: databaseLike, scope: config.scope, history: "incremental" }), createSqliteAgentRunStore({ db: databaseLike, scope: budgetScopeFor(config) }), config);
1180
+ const store = withBudgetLedgerStore(createSqliteAgentRunStore({ db: databaseLike, scope: config.scope, history: "incremental" }), createSqliteAgentRunStore({ db: databaseLike, scope: budgetScope }), config);
1209
1181
  database.exec(`CREATE TRIGGER IF NOT EXISTS zhivex_task_budget_retain_run
1210
1182
  BEFORE DELETE ON zhivex_agent_runs
1211
1183
  WHEN json_type(OLD.state_json, '$.metadata.zhivexTaskBudgetAccountV1') IS NOT NULL
@@ -1302,7 +1274,7 @@ var projectMemoryBinding = (workspace, scope) => {
1302
1274
  segment(scope.userId);
1303
1275
  if (scope.namespace !== undefined)
1304
1276
  segment(scope.namespace);
1305
- if (scope.namespace === "__zhivex_budget__")
1277
+ if (isReservedBudgetNamespace(scope.namespace))
1306
1278
  throw new HarnessConfigError("Reserved memory namespace.");
1307
1279
  const key = (kind, value) => createHash4("sha256").update(kind).update("\x00").update(value).digest("hex");
1308
1280
  const workspaceKey = key("workspace", workspace);
@@ -2,7 +2,7 @@ import {
2
2
  createEditProposal,
3
3
  editChangesSchema,
4
4
  workspaceFilePathSchema
5
- } from "./index-xdbkcccf.js";
5
+ } from "./index-6dxrbnxm.js";
6
6
 
7
7
  // src/runtime/tool-policy.ts
8
8
  import { createHash } from "node:crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  changeEnvelopeSchema
3
- } from "./index-sstgcsr0.js";
3
+ } from "./index-yx52bt4a.js";
4
4
  import {
5
5
  PROVIDERS,
6
6
  reasoningEffortSchema
@@ -5,7 +5,7 @@ import {
5
5
  taskAcceptanceOutcome,
6
6
  taskCheckReceiptSchema,
7
7
  workspaceFilePathSchema
8
- } from "./index-xdbkcccf.js";
8
+ } from "./index-6dxrbnxm.js";
9
9
  import {
10
10
  HarnessConfigError,
11
11
  HarnessStateConflictError,
@@ -1604,6 +1604,79 @@ function taskAcceptanceCheckpointStore(store, runId, ledger) {
1604
1604
  import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
1605
1605
  import { randomUUID as randomUUID3 } from "node:crypto";
1606
1606
  import { z as z7 } from "zod";
1607
+
1608
+ // src/runtime/budget-ledger-scope.ts
1609
+ var BUDGET_LEDGER_NAMESPACE = "__zhivex_budget__";
1610
+ var BUDGET_OWNER_NAMESPACE_KEY = "budgetOwnerNamespace";
1611
+ var isReservedBudgetNamespace = (namespace) => namespace === BUDGET_LEDGER_NAMESPACE || (namespace?.startsWith(`${BUDGET_LEDGER_NAMESPACE}:`) ?? false);
1612
+ var budgetLedgerNamespace = (namespace) => {
1613
+ if (!namespace || isReservedBudgetNamespace(namespace)) {
1614
+ throw new HarnessStateConflictError("The budget ledger namespace is reserved.");
1615
+ }
1616
+ return `${BUDGET_LEDGER_NAMESPACE}:${namespace}`;
1617
+ };
1618
+ var budgetLedgerScope = (scope) => {
1619
+ if (scope.namespace && isReservedBudgetNamespace(scope.namespace)) {
1620
+ throw new HarnessStateConflictError("The budget ledger namespace is reserved.");
1621
+ }
1622
+ return {
1623
+ tenantId: scope.tenantId,
1624
+ ...scope.userId ? { userId: scope.userId } : {},
1625
+ namespace: scope.namespace ? budgetLedgerNamespace(scope.namespace) : `${BUDGET_LEDGER_NAMESPACE}:`
1626
+ };
1627
+ };
1628
+ var sameIdentity = (left, right) => left?.tenantId === right.tenantId && (left.userId ?? undefined) === (right.userId ?? undefined);
1629
+ var bindBudgetLedgerStore = (primary, scope, budget = primary) => {
1630
+ const bound = budgetLedgerScope(scope);
1631
+ const ownerNamespace = scope.namespace ?? "";
1632
+ const isSdkBudget = (value) => sameIdentity(value, bound) && value?.namespace === BUDGET_LEDGER_NAMESPACE;
1633
+ const isBoundBudget = (value) => sameIdentity(value, bound) && value?.namespace === bound.namespace;
1634
+ const assertId = (id) => {
1635
+ if (!/^budget_[a-f0-9]{64}$/.test(id))
1636
+ throw new HarnessStateConflictError("Invalid budget ledger identity.");
1637
+ };
1638
+ const bindState = (state) => {
1639
+ const metadata = { ...state.metadata ?? {} };
1640
+ const owner = metadata[BUDGET_OWNER_NAMESPACE_KEY];
1641
+ if (owner !== undefined && owner !== ownerNamespace) {
1642
+ throw new HarnessStateConflictError("Budget ledger is bound to another namespace.");
1643
+ }
1644
+ return {
1645
+ ...state,
1646
+ scope: bound,
1647
+ metadata: { ...metadata, [BUDGET_OWNER_NAMESPACE_KEY]: ownerNamespace }
1648
+ };
1649
+ };
1650
+ const assertStored = (state) => {
1651
+ if (!state)
1652
+ return state;
1653
+ const owner = state.metadata?.[BUDGET_OWNER_NAMESPACE_KEY];
1654
+ if (state.scope?.namespace !== bound.namespace || owner !== ownerNamespace) {
1655
+ throw new HarnessStateConflictError("Budget ledger is not bound to this namespace.");
1656
+ }
1657
+ return state;
1658
+ };
1659
+ return {
1660
+ ...primary,
1661
+ load: async (id, requestedScope) => {
1662
+ if (!isSdkBudget(requestedScope) && !isBoundBudget(requestedScope))
1663
+ return primary.load(id, requestedScope);
1664
+ assertId(id);
1665
+ return assertStored(await budget.load(id, bound));
1666
+ },
1667
+ save: async (state, options) => {
1668
+ if (!isSdkBudget(state.scope) && !isBoundBudget(state.scope))
1669
+ return primary.save(state, options);
1670
+ assertId(state.runId);
1671
+ if (state.provider !== "zhivex" || state.modelId !== "budget-coordinator" || state.metadata?.budgetCoordinator !== true) {
1672
+ throw new HarnessStateConflictError("Only SDK budget ledger states may use the reserved namespace.");
1673
+ }
1674
+ return budget.save(bindState(state), options);
1675
+ }
1676
+ };
1677
+ };
1678
+
1679
+ // src/runtime/task-budget.ts
1607
1680
  import {
1608
1681
  createAgentBudgetCoordinator,
1609
1682
  fingerprintAgentHarness as fingerprintAgentHarness2,
@@ -1751,10 +1824,10 @@ class TaskBudget {
1751
1824
  this.accountRunId = TaskBudget.accountId(scope, taskId);
1752
1825
  this.policy = structuredClone(account.policy);
1753
1826
  const budgetId = this.accountRunId;
1754
- this.coordinator = createAgentBudgetCoordinator({ store, scope, budgetId, limits: this.policy.limits });
1827
+ this.coordinator = createAgentBudgetCoordinator({ store: bindBudgetLedgerStore(store, scope), scope, budgetId, limits: this.policy.limits });
1755
1828
  this.coordinatorId = this.coordinator.id;
1756
1829
  this.budgetRunId = `budget_${fingerprintAgentHarness2({ budgetId, scope }).slice("sha256:".length)}`;
1757
- this.budgetScope = { tenantId: scope.tenantId, ...scope.userId ? { userId: scope.userId } : {}, namespace: "__zhivex_budget__" };
1830
+ this.budgetScope = budgetLedgerScope(scope);
1758
1831
  }
1759
1832
  static accountId(scope, taskId) {
1760
1833
  return `task_budget_${fingerprintAgentHarness2({ scope, taskId }).slice("sha256:".length)}`;
@@ -2268,4 +2341,4 @@ class TaskBudget {
2268
2341
  }
2269
2342
  }
2270
2343
 
2271
- export { protectStateFromGit, validateStateDirectory, HARNESS_SESSION_INDEX_FILE, HARNESS_SESSION_SCHEMA_VERSION, SESSION_RUN_STATUSES, TERMINAL_SESSION_RUN_STATUSES, ensurePrivateDatabase, openCliSessionStore, openSessionStore, withRuntimeInstruction, withFreshSystemInstructions, inspectRuntimeDiagnostics, inspectRuntimeManifest, estimateContextTokens, measureContext, MODEL_BUDGET_KEY, estimateRequestTokens, workBudgetReached, createModelBudget, USAGE_LEDGER_KEY, usagePricingSchema, inspectUsageLedger, formatUsageLedger, runUsageLedgerWithPolicy, UsageLedger, inspectTaskMonetaryUsage, taskAcceptanceContractSchema, compileTaskAcceptanceContract, TASK_ACCEPTANCE_KEY, TASK_ACCEPTANCE_EVIDENCE_KEY, readTaskAcceptanceLedger, nextTaskAcceptanceLedger, persistTaskAcceptanceRevision, taskAcceptanceCheckpointStore, TASK_BUDGET_KEY, TASK_BUDGET_ACCOUNT_KEY, inspectTaskBudgetSummary, assertTaskBudgetBackupLinks, TaskBudget };
2344
+ export { protectStateFromGit, validateStateDirectory, HARNESS_SESSION_INDEX_FILE, HARNESS_SESSION_SCHEMA_VERSION, SESSION_RUN_STATUSES, TERMINAL_SESSION_RUN_STATUSES, ensurePrivateDatabase, openCliSessionStore, openSessionStore, withRuntimeInstruction, withFreshSystemInstructions, inspectRuntimeDiagnostics, inspectRuntimeManifest, estimateContextTokens, measureContext, MODEL_BUDGET_KEY, estimateRequestTokens, workBudgetReached, createModelBudget, USAGE_LEDGER_KEY, usagePricingSchema, inspectUsageLedger, formatUsageLedger, runUsageLedgerWithPolicy, UsageLedger, inspectTaskMonetaryUsage, taskAcceptanceContractSchema, compileTaskAcceptanceContract, TASK_ACCEPTANCE_KEY, TASK_ACCEPTANCE_EVIDENCE_KEY, readTaskAcceptanceLedger, nextTaskAcceptanceLedger, persistTaskAcceptanceRevision, taskAcceptanceCheckpointStore, BUDGET_LEDGER_NAMESPACE, BUDGET_OWNER_NAMESPACE_KEY, isReservedBudgetNamespace, budgetLedgerNamespace, budgetLedgerScope, bindBudgetLedgerStore, TASK_BUDGET_KEY, TASK_BUDGET_ACCOUNT_KEY, inspectTaskBudgetSummary, assertTaskBudgetBackupLinks, TaskBudget };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  openWorkspaceCheckpointStore
3
- } from "./index-6599mpmy.js";
3
+ } from "./index-4mn6m3bq.js";
4
4
  import {
5
5
  appendUserMessage,
6
6
  checkEvidence,
@@ -16,17 +16,17 @@ import {
16
16
  reviseHarnessTaskAcceptance,
17
17
  runHarness,
18
18
  runHarnessTask
19
- } from "./index-0zs2dz26.js";
19
+ } from "./index-pf73y4gt.js";
20
20
  import {
21
21
  ASSISTANT_RESPONSE_KEY,
22
22
  TASK_SOURCE_KEY,
23
23
  assistantResponses,
24
24
  cancelHarnessRun,
25
25
  captureTaskSources
26
- } from "./index-f6mqa5gk.js";
26
+ } from "./index-amjttjaj.js";
27
27
  import {
28
28
  resolvePackageCheckCommand
29
- } from "./index-d9zkmhz3.js";
29
+ } from "./index-w0m1nckc.js";
30
30
  import {
31
31
  APPROVAL_HISTORY_KEY,
32
32
  approvalDecisionViews,
@@ -35,7 +35,7 @@ import {
35
35
  inspectHarnessPolicy,
36
36
  observeHarnessPolicyDecisions,
37
37
  readApprovalDecisions
38
- } from "./index-wm9xeq1n.js";
38
+ } from "./index-bt2p8x7r.js";
39
39
  import {
40
40
  SESSION_RUN_STATUSES,
41
41
  TASK_ACCEPTANCE_KEY,
@@ -48,12 +48,12 @@ import {
48
48
  nextTaskAcceptanceLedger,
49
49
  openCliSessionStore,
50
50
  readTaskAcceptanceLedger
51
- } from "./index-zxg4ve4j.js";
51
+ } from "./index-fqqz1yt8.js";
52
52
  import {
53
53
  createEditProposal,
54
54
  editProposalInputSchema,
55
55
  fileDigestSchema
56
- } from "./index-xdbkcccf.js";
56
+ } from "./index-6dxrbnxm.js";
57
57
  import {
58
58
  CLI_JSON_SCHEMA_VERSION,
59
59
  harnessClientRequestSchema,
@@ -476,7 +476,7 @@ import { createHash as createHash3 } from "node:crypto";
476
476
  import { z } from "zod";
477
477
  var APPROVAL_DIFFS_KEY = "clientApprovalDiffsV1";
478
478
  var sha2 = z.string().regex(/^sha256:[a-f0-9]{64}$/);
479
- var file = z.object({ path: z.string().max(1024), expectedDigest: sha2.nullable(), before: z.string().nullable(), after: z.string().nullable(), afterDigest: sha2.nullable(), beforeMode: z.number().int().optional(), afterMode: z.number().int().optional(), operation: z.enum(["create", "update", "delete"]).optional() }).strict();
479
+ var file = z.object({ path: z.string().max(1024), expectedDigest: sha2.nullable(), before: z.string().nullable(), after: z.string().nullable(), afterDigest: sha2.nullable(), beforeMode: z.number().int().optional(), afterMode: z.number().int().optional(), operation: z.enum(["create", "update", "delete", "restore"]).optional() }).strict();
480
480
  var archive = z.object({ approvalId: z.string().max(256), digest: z.string().regex(/^[a-f0-9]{64}$/), proposalId: sha2, files: z.array(file).min(1).max(50) }).strict();
481
481
  var archives = z.array(archive).max(512);
482
482
  var maxBytes = 2 * 1024 * 1024;
@@ -534,14 +534,14 @@ async function attachApprovalPreviews(run, workspace, options = {}) {
534
534
  let remaining = 256 * 1024;
535
535
  for (const approval of run.approvals) {
536
536
  const action = approval.action;
537
- if (!action || !["apply_patch", "apply_reviewed_edits", "apply_reviewed_replacement", "apply_environment_patch", "verify_and_apply_environment_patch", "verify_and_apply_reviewed_edits"].includes(String(action.name)))
537
+ if (!action || !["apply_patch", "apply_reviewed_edits", "apply_reviewed_replacement", "apply_environment_patch", "verify_and_apply_environment_patch", "verify_and_apply_reviewed_edits", "restore_file"].includes(String(action.name)))
538
538
  continue;
539
539
  approval.filePreview = { status: "unavailable" };
540
540
  try {
541
541
  if (typeof action.arguments !== "string" || Buffer.byteLength(action.arguments) > 256 * 1024)
542
542
  continue;
543
543
  const args = JSON.parse(action.arguments);
544
- const preview = action.name === "apply_environment_patch" || action.name === "verify_and_apply_environment_patch" ? await (async () => {
544
+ const preview = action.name === "restore_file" ? await workspace.previewRestore(args) : action.name === "apply_environment_patch" || action.name === "verify_and_apply_environment_patch" ? await (async () => {
545
545
  if (!options.environment)
546
546
  throw new Error("OCI_REVIEW_UNAVAILABLE");
547
547
  const patchId = fileDigestSchema.parse(args?.patchId);
@@ -20,7 +20,7 @@ import {
20
20
  runtimeManifest,
21
21
  taskSources,
22
22
  tokenUsageCheckpointStore
23
- } from "./index-f6mqa5gk.js";
23
+ } from "./index-amjttjaj.js";
24
24
  import {
25
25
  HARNESS_MCP_CONFIG_SCHEMA_VERSION,
26
26
  closeMcpHostSession,
@@ -29,7 +29,7 @@ import {
29
29
  mcpConfigurationFingerprintInput,
30
30
  normalizeHarnessMcpConfiguration,
31
31
  resolveMcpHostSession
32
- } from "./index-dtb2c6ds.js";
32
+ } from "./index-2r4f0p4n.js";
33
33
  import {
34
34
  EnvironmentPatchDriftError,
35
35
  Workspace,
@@ -40,7 +40,7 @@ import {
40
40
  isHardIgnored,
41
41
  replacementEditSchema,
42
42
  resolvePackageCheckCommand
43
- } from "./index-d9zkmhz3.js";
43
+ } from "./index-w0m1nckc.js";
44
44
  import {
45
45
  DEFAULT_PROVIDER_REGISTRY,
46
46
  HARNESS_CONFIG_SCHEMA_VERSION,
@@ -60,7 +60,7 @@ import {
60
60
  publishHarnessPolicyDecision,
61
61
  publishPendingPolicyDecision,
62
62
  readApprovalDecisions
63
- } from "./index-wm9xeq1n.js";
63
+ } from "./index-bt2p8x7r.js";
64
64
  import {
65
65
  MODEL_BUDGET_KEY,
66
66
  TASK_ACCEPTANCE_EVIDENCE_KEY,
@@ -85,10 +85,10 @@ import {
85
85
  withFreshSystemInstructions,
86
86
  withRuntimeInstruction,
87
87
  workBudgetReached
88
- } from "./index-zxg4ve4j.js";
88
+ } from "./index-fqqz1yt8.js";
89
89
  import {
90
90
  HARNESS_VERSION
91
- } from "./index-4fx5f3k5.js";
91
+ } from "./index-rz7wmp71.js";
92
92
  import {
93
93
  FileSizeLimitError,
94
94
  MAX_EDIT_CHANGES,
@@ -108,7 +108,7 @@ import {
108
108
  validateEditProposal,
109
109
  withTaskAcceptanceDelivery,
110
110
  workspaceFilePathSchema
111
- } from "./index-xdbkcccf.js";
111
+ } from "./index-6dxrbnxm.js";
112
112
  import {
113
113
  HarnessConfigError,
114
114
  HarnessError,
@@ -1832,6 +1832,7 @@ var record = (value) => value !== null && typeof value === "object" && !Array.is
1832
1832
  var LOCAL_TOOLS = LOCAL_TOOL_NAMES;
1833
1833
  var MAX_USER_STEERING = 10;
1834
1834
  var CONTEXT_PRIORITY = "Latest user > chronological user steering > historical objective. Assistant never overrides user facts. Questions retain task.";
1835
+ var EARLIER = "[before later user messages] ";
1835
1836
  var summarizeHarnessMessages = (messages, maxCharacters = 4000) => {
1836
1837
  const redaction = createRedactionPolicy({ includeEmails: true });
1837
1838
  const clean = (text, limit = 512) => redaction.redactText(text).replace(/\bBearer\s+\S+/gi, "Bearer [REDACTED]").replace(/\b([A-Z][A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD)|api[_-]?key|access[_-]?token|password)\s*([=:])\s*(?:"[^"]*"|'[^']*'|\S+)/gi, "$1$2[REDACTED]").replace(/\b(?:sk|ghp|gho|github_pat)-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(/\s+/g, " ").trim().slice(0, limit);
@@ -1857,6 +1858,12 @@ var summarizeHarnessMessages = (messages, maxCharacters = 4000) => {
1857
1858
  omitted = true;
1858
1859
  }
1859
1860
  };
1861
+ const markRecentEarlier = () => {
1862
+ const marked = recent.map((value) => value.startsWith(EARLIER) ? value : `${EARLIER}${value}`);
1863
+ recent.length = 0;
1864
+ for (const value of marked)
1865
+ add(recent, value, 4);
1866
+ };
1860
1867
  const rememberObservation = (tool2, detail) => {
1861
1868
  if (typeof tool2 !== "string" || !LOCAL_TOOLS.has(tool2) || typeof detail !== "string")
1862
1869
  return;
@@ -1974,6 +1981,7 @@ var summarizeHarnessMessages = (messages, maxCharacters = 4000) => {
1974
1981
  objective = text;
1975
1982
  if (historicalObjective)
1976
1983
  add(steering, text, MAX_USER_STEERING);
1984
+ markRecentEarlier();
1977
1985
  } else
1978
1986
  add(recent, `${message.role}: ${text}`, 4);
1979
1987
  } else if (part.type === "tool-call") {
@@ -4199,7 +4207,8 @@ var resolvers = {
4199
4207
  const parsed = moveFileInputSchema.parse(input);
4200
4208
  return [parsed.source, parsed.destination];
4201
4209
  },
4202
- quarantine_file: (input) => [quarantineFileInputSchema.parse(input).path]
4210
+ quarantine_file: (input) => [quarantineFileInputSchema.parse(input).path],
4211
+ restore_file: (input) => [restoreFileInputSchema.parse(input).destination]
4203
4212
  };
4204
4213
  var validateBuiltinToolPolicy = (policy, tools) => {
4205
4214
  for (const rule of policy.rules)
@@ -4656,7 +4665,7 @@ var createWorkspaceTools = (workspace, allowedChecks) => ({
4656
4665
  }),
4657
4666
  restore_file: tool4({
4658
4667
  name: "restore_file",
4659
- description: "Restore a quarantined file to its original path or an explicit safe destination without overwriting content unexpectedly.",
4668
+ description: "Restore a quarantined file to the required destination after the reviewed expectedDigest matches the quarantined bytes. Restore does not fall back to the original path and never overwrites an existing file.",
4660
4669
  schema: restoreFileInputSchema,
4661
4670
  ...mutationApproval,
4662
4671
  execute: async (input, context) => serializeJsonValue6(editContractDocument("restore-result", await (harnessExecutionSession(context)?.workspace ?? workspace).restoreQuarantined(input)))
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  workspaceCheckpointSchema,
3
3
  workspaceRestoreOperationSchema
4
- } from "./index-6599mpmy.js";
4
+ } from "./index-4mn6m3bq.js";
5
5
  import {
6
6
  HARNESS_OPERATIONS_SCHEMA_VERSION,
7
7
  HARNESS_SQLITE_FILE,
@@ -9,17 +9,20 @@ import {
9
9
  openHarnessPersistence,
10
10
  projectMemoryRecordKey,
11
11
  sqliteAdapter
12
- } from "./index-f6mqa5gk.js";
12
+ } from "./index-amjttjaj.js";
13
13
  import {
14
+ BUDGET_LEDGER_NAMESPACE,
15
+ BUDGET_OWNER_NAMESPACE_KEY,
14
16
  HARNESS_SESSION_SCHEMA_VERSION,
15
17
  assertTaskBudgetBackupLinks,
18
+ budgetLedgerNamespace,
16
19
  openCliSessionStore,
17
20
  validateStateDirectory
18
- } from "./index-zxg4ve4j.js";
21
+ } from "./index-fqqz1yt8.js";
19
22
  import {
20
23
  SqliteDatabase,
21
24
  readRegularFileChunksNoFollow
22
- } from "./index-xdbkcccf.js";
25
+ } from "./index-6dxrbnxm.js";
23
26
  import {
24
27
  HarnessStateConflictError,
25
28
  HarnessWorkspaceError
@@ -398,7 +401,8 @@ var coordinatorIds = (runs) => new Set(runs.flatMap(({ state }) => {
398
401
  var validateBudgetLedger = (config, run, identities) => {
399
402
  const state = validatedRunState(run.state, `Budget ledger ${run.key}`);
400
403
  const identity = state.metadata?.budgetIdentity;
401
- 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)) {
404
+ const ownerNamespace = config.scope.namespace;
405
+ 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)) {
402
406
  throw new HarnessStateConflictError("Budget ledger is not bound to an exported run and durable scope.");
403
407
  }
404
408
  assertTerminalState(state, `Budget ledger ${run.key}`);
@@ -532,7 +536,9 @@ var readPayload = async (config, recordedWorkspace, accessLease) => {
532
536
  const metadata = state.metadata;
533
537
  if (typeof metadata?.budgetIdentity !== "string" || !identities.has(metadata.budgetIdentity)) {
534
538
  const scope = state.scope;
535
- if (scope?.namespace === "__zhivex_budget__" && scope.tenantId === config.scope.tenantId && (scope.userId ?? undefined) === (config.scope.userId ?? undefined)) {
539
+ const sameTenant = scope?.tenantId === config.scope.tenantId && (scope?.userId ?? undefined) === (config.scope.userId ?? undefined);
540
+ const boundNamespace = config.scope.namespace ? budgetLedgerNamespace(config.scope.namespace) : undefined;
541
+ if (sameTenant && (scope?.namespace === BUDGET_LEDGER_NAMESPACE || scope?.namespace === boundNamespace)) {
536
542
  throw new HarnessStateConflictError("An unlinked shared budget ledger cannot be safely assigned to this backup scope; retain the original database.");
537
543
  }
538
544
  return [];
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@zhivex-ai/harness",
4
- version: "1.4.1",
4
+ version: "1.6.2",
5
5
  description: "Governed, provider-portable runtime for coding agents with durable approvals and isolated repository execution.",
6
6
  type: "module",
7
7
  license: "MIT",
@@ -101,6 +101,7 @@ var package_default = {
101
101
  "LICENSE",
102
102
  "docs/CHANGE_ENVELOPES.md",
103
103
  "docs/CLI.md",
104
+ "docs/AUTO_APPROVE.md",
104
105
  "docs/WEB_LIMITS.md",
105
106
  "docs/CODE_RELEASE.md",
106
107
  "docs/CODE_WEB_TASKS.md",
@@ -217,26 +218,26 @@ var package_default = {
217
218
  "smoke:mcp:installed": "bun run build && bun scripts/mcp-installed-smoke.ts"
218
219
  },
219
220
  dependencies: {
220
- "@zhivex-ai/agents": "1.11.0",
221
- "@zhivex-ai/anthropic": "0.14.0",
222
- "@zhivex-ai/azure-openai": "0.7.8",
223
- "@zhivex-ai/bedrock": "2.0.7",
224
- "@zhivex-ai/core": "1.34.0",
225
- "@zhivex-ai/gemini": "0.13.0",
226
- "@zhivex-ai/meta": "0.2.9",
227
- "@zhivex-ai/openai": "0.16.0",
228
- "@zhivex-ai/qwen": "0.16.4",
229
- "@zhivex-ai/vertex": "1.2.7",
230
- "google-auth-library": "11.1.0",
231
- zod: "4.6.5"
221
+ "@zhivex-ai/agents": "1.12.0",
222
+ "@zhivex-ai/anthropic": "0.15.0",
223
+ "@zhivex-ai/azure-openai": "0.8.0",
224
+ "@zhivex-ai/bedrock": "2.1.0",
225
+ "@zhivex-ai/core": "1.36.0",
226
+ "@zhivex-ai/gemini": "0.14.0",
227
+ "@zhivex-ai/meta": "0.3.0",
228
+ "@zhivex-ai/openai": "0.17.0",
229
+ "@zhivex-ai/qwen": "0.18.0",
230
+ "@zhivex-ai/vertex": "1.3.0",
231
+ "google-auth-library": "11.3.1",
232
+ zod: "4.6.7"
232
233
  },
233
234
  overrides: {
234
- "@zhivex-ai/core": "1.34.0"
235
+ "@zhivex-ai/core": "1.36.0"
235
236
  },
236
237
  devDependencies: {
237
238
  "@agentclientprotocol/sdk": "1.8.0",
238
239
  "@modelcontextprotocol/server": "2.3.1",
239
- "@types/bun": "1.4.2",
240
+ "@types/bun": "1.4.3",
240
241
  "@types/node": "^26.6.5",
241
242
  typescript: "7.0.2",
242
243
  "typescript-compiler-api": "npm:typescript@6.0.3"