@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.
- package/CHANGELOG.md +56 -0
- package/README.md +30 -8
- package/SECURITY.md +1 -1
- package/SUPPORT.md +2 -2
- package/contracts/engine-api.json +70 -0
- package/contracts/public-api.json +162 -0
- package/contracts/stable-api-signatures.json +9 -9
- package/dist/acp-cli.js +38 -12
- package/dist/cli/arguments.d.ts +5 -1
- package/dist/cli/memory.d.ts +2 -0
- package/dist/{cli-entry-bx3vjw7h.js → cli-entry-4k1cf0m3.js} +38 -12
- package/dist/{cli-entry-1gfg3brj.js → cli-entry-9c2k0zwz.js} +1086 -446
- package/dist/{cli-etsmtst3.js → cli-s1rs15vv.js} +136 -24
- package/dist/cli.js +2 -2
- package/dist/client/check-evidence.d.ts +17 -0
- package/dist/client/run-document.d.ts +12 -0
- package/dist/compat/cli-options.d.ts +12 -1
- package/dist/compat/code-support.d.ts +4 -0
- package/dist/compat/code-support.js +12 -4
- package/dist/context/compaction.d.ts +5 -0
- package/dist/context/project-memory-context.d.ts +6 -0
- package/dist/context/task-memory.d.ts +33 -1
- package/dist/engine/acp.js +8 -8
- package/dist/engine/client.js +7 -7
- package/dist/engine/desktop-state-v1.js +5 -5
- package/dist/engine/index.d.ts +4 -0
- package/dist/engine/index.js +88 -11
- package/dist/engine/mcp-stdio-v1.js +4 -4
- package/dist/engine/service.js +8 -8
- package/dist/hostile-repository-demo.js +1260 -712
- package/dist/{index-azmwjp95.js → index-0g939pfs.js} +13 -12
- package/dist/{index-6m08wvab.js → index-2tgb2b4e.js} +3 -3
- package/dist/{index-w2sj0wkw.js → index-49ys3s4q.js} +64 -14
- package/dist/{index-hnaxfpb5.js → index-4j1h4j8c.js} +137 -42
- package/dist/{index-8zzhggxv.js → index-a1q355va.js} +125 -2
- package/dist/{index-8vm2m34s.js → index-dj5z774k.js} +18 -2
- package/dist/{index-z0qxmkm2.js → index-e6r04a18.js} +1 -1
- package/dist/{index-yb239ghk.js → index-r0tdj04h.js} +21 -6
- package/dist/{index-h0mqx2ed.js → index-rd0s3gqj.js} +300 -4
- package/dist/{index-42gp2hy8.js → index-vtqfjnab.js} +98 -27
- package/dist/{index-2jrdcj6b.js → index-wq2tax80.js} +15 -1
- package/dist/{index-a97bezbz.js → index-z6br6qdn.js} +44 -23
- package/dist/index.js +11 -11
- package/dist/persistence/project-memory-command.d.ts +11 -0
- package/dist/persistence/project-memory.d.ts +109 -0
- package/dist/persistence/sdk-store-identity.d.ts +4 -0
- package/dist/persistence/sessions.d.ts +4 -0
- package/dist/runtime/error-diagnostics.d.ts +35 -0
- package/dist/runtime/harness.d.ts +5 -1
- package/dist/runtime/run-interruption.d.ts +1 -1
- package/dist/runtime/runtime-checkpoints.d.ts +3 -0
- package/dist/runtime/task-acceptance-native.d.ts +10 -0
- package/dist/runtime/time-to-safe-fix.d.ts +35 -0
- package/dist/service-cli.js +8 -8
- package/dist/{service-client-cli-3365rfav.js → service-client-cli-b52c67hx.js} +2 -2
- package/dist/verify-historical-migrations.js +1021 -456
- package/dist/zhx.js +2 -2
- package/docs/CLI.md +4 -0
- package/docs/CLIENT_PROTOCOL.md +10 -0
- package/docs/CODE_RELEASE.md +136 -19
- package/docs/CONTEXT_ENGINEERING.md +25 -0
- package/docs/DURABLE_OPERATIONS.md +60 -1
- package/docs/ENGINE_API.md +23 -9
- package/docs/EXTENSIBILITY.md +1 -1
- package/docs/FIRST_USE.md +6 -6
- package/docs/LOCAL_SERVICE.md +10 -4
- package/docs/PROJECT_MEMORY.md +157 -0
- package/docs/README.md +2 -0
- package/docs/STABILITY.md +1 -1
- package/docs/WORKSPACE_CHECKPOINTS.md +11 -1
- package/evaluations/representative-assembly-matrix.json +55 -1
- package/examples/README.md +4 -4
- package/package.json +12 -11
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
taskAcceptanceDeliveryDiagnostic,
|
|
5
5
|
taskAcceptanceOutcome,
|
|
6
6
|
workspaceFilePathSchema
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-r0tdj04h.js";
|
|
8
8
|
import {
|
|
9
9
|
HarnessConfigError,
|
|
10
10
|
HarnessStateConflictError,
|
|
@@ -1171,8 +1171,7 @@ class UsageLedger {
|
|
|
1171
1171
|
}
|
|
1172
1172
|
async run(runId, operation, historicalUsageUnknown = false) {
|
|
1173
1173
|
this.database.query("INSERT OR IGNORE INTO zhivex_usage_policies (scope_key, run_id, policy) VALUES (?1, ?2, ?3)").run(this.key, runId, JSON.stringify({ ...this.options, ...historicalUsageUnknown ? { historicalUsageUnknown: true } : {} }));
|
|
1174
|
-
|
|
1175
|
-
return current.run({ ledger: this, runId }, operation);
|
|
1174
|
+
return current.run({ ledger: this, runId, recovered: false }, operation);
|
|
1176
1175
|
}
|
|
1177
1176
|
summary(runId) {
|
|
1178
1177
|
const rows = this.database.query("SELECT * FROM zhivex_usage_calls WHERE scope_key = ?1 AND run_id = ?2 ORDER BY rowid").all(this.key, runId);
|
|
@@ -1300,6 +1299,21 @@ class UsageLedger {
|
|
|
1300
1299
|
store(store) {
|
|
1301
1300
|
const ledger = this;
|
|
1302
1301
|
return new Proxy(store, { get(target, key) {
|
|
1302
|
+
if (key === "acquireLease" && target.acquireLease)
|
|
1303
|
+
return async (...args) => {
|
|
1304
|
+
const lease = await target.acquireLease(...args);
|
|
1305
|
+
const scope = current.getStore();
|
|
1306
|
+
if (lease && scope?.ledger === ledger && args[0] === scope.runId && !scope.recovered) {
|
|
1307
|
+
try {
|
|
1308
|
+
ledger.database.query("UPDATE zhivex_usage_calls SET status = 'unknown' WHERE scope_key = ?1 AND run_id = ?2 AND status = 'pending'").run(ledger.key, scope.runId);
|
|
1309
|
+
scope.recovered = true;
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
await target.releaseLease?.(args[0], lease.ownerId, args[2]);
|
|
1312
|
+
throw error;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
return lease;
|
|
1316
|
+
};
|
|
1303
1317
|
if (key === "save")
|
|
1304
1318
|
return async (...args) => {
|
|
1305
1319
|
const scope = current.getStore();
|
|
@@ -1387,28 +1401,14 @@ function compileTaskAcceptanceContract(input) {
|
|
|
1387
1401
|
return { contract, digest: `sha256:${createHash2("sha256").update(JSON.stringify(contract)).digest("hex")}` };
|
|
1388
1402
|
}
|
|
1389
1403
|
|
|
1390
|
-
// src/context/task-memory.ts
|
|
1391
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
1392
|
-
import { tool, serializeJsonValue as serializeJsonValue2 } from "@zhivex-ai/core";
|
|
1393
|
-
import { createRedactionPolicy as createRedactionPolicy3 } from "@zhivex-ai/agents";
|
|
1394
|
-
import { z as z8 } from "zod";
|
|
1395
|
-
|
|
1396
|
-
// src/runtime/repair-verifier.ts
|
|
1397
|
-
import { z as z6 } from "zod";
|
|
1398
|
-
var verifierSchema = z6.strictObject({
|
|
1399
|
-
command: z6.string().min(1).max(64),
|
|
1400
|
-
args: z6.array(z6.string().max(8192)).max(256).default([]),
|
|
1401
|
-
purpose: z6.string().min(1).max(500)
|
|
1402
|
-
});
|
|
1403
|
-
|
|
1404
1404
|
// src/runtime/task-acceptance-record.ts
|
|
1405
|
-
import { z as
|
|
1405
|
+
import { z as z6 } from "zod";
|
|
1406
1406
|
import { serializeJsonValue } from "@zhivex-ai/core";
|
|
1407
1407
|
var TASK_ACCEPTANCE_KEY = "zhivexTaskAcceptanceV1";
|
|
1408
1408
|
var TASK_ACCEPTANCE_EVIDENCE_KEY = "zhivexTaskAcceptanceEvidenceV1";
|
|
1409
|
-
var digest2 =
|
|
1410
|
-
var revisionSchema =
|
|
1411
|
-
var ledgerSchema =
|
|
1409
|
+
var digest2 = z6.string().regex(/^sha256:[a-f0-9]{64}$/);
|
|
1410
|
+
var revisionSchema = z6.strictObject({ revision: z6.number().int().min(1), digest: digest2, previousDigest: digest2.nullable(), contract: taskAcceptanceContractSchema });
|
|
1411
|
+
var ledgerSchema = z6.strictObject({ schemaVersion: z6.literal(1), revisions: z6.array(revisionSchema).min(1).max(16) });
|
|
1412
1412
|
function readTaskAcceptanceLedger(state) {
|
|
1413
1413
|
const raw = state.metadata?.[TASK_ACCEPTANCE_KEY];
|
|
1414
1414
|
if (raw === undefined)
|
|
@@ -1484,9 +1484,55 @@ function taskAcceptanceCheckpointStore(store, runId, ledger) {
|
|
|
1484
1484
|
} });
|
|
1485
1485
|
}
|
|
1486
1486
|
|
|
1487
|
+
// src/context/task-memory.ts
|
|
1488
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
1489
|
+
import { tool, serializeJsonValue as serializeJsonValue2 } from "@zhivex-ai/core";
|
|
1490
|
+
import { createRedactionPolicy as createRedactionPolicy3 } from "@zhivex-ai/agents";
|
|
1491
|
+
import { z as z8 } from "zod";
|
|
1492
|
+
|
|
1493
|
+
// src/runtime/repair-verifier.ts
|
|
1494
|
+
import { z as z7 } from "zod";
|
|
1495
|
+
var verifierSchema = z7.strictObject({
|
|
1496
|
+
command: z7.string().min(1).max(64),
|
|
1497
|
+
args: z7.array(z7.string().max(8192)).max(256).default([]),
|
|
1498
|
+
purpose: z7.string().min(1).max(500)
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1487
1501
|
// src/context/task-memory.ts
|
|
1488
1502
|
var redact2 = createRedactionPolicy3({ includeEmails: true });
|
|
1489
1503
|
var TASK_SOURCE_KEY = "zhivexTaskSources";
|
|
1504
|
+
var ASSISTANT_RESPONSE_KEY = "zhivexAssistantResponses";
|
|
1505
|
+
var MAX_ASSISTANT_RESPONSES = 3;
|
|
1506
|
+
var MAX_ASSISTANT_RESPONSE_CHARACTERS = 64000;
|
|
1507
|
+
var redactSource = (text2) => redact2.redactText(text2).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]");
|
|
1508
|
+
var sourceId = (text2) => `sha256:${createHash3("sha256").update(text2).digest("hex")}`;
|
|
1509
|
+
var assistantResponses = (metadata) => {
|
|
1510
|
+
const value = metadata && typeof metadata === "object" ? metadata[ASSISTANT_RESPONSE_KEY] : undefined;
|
|
1511
|
+
return Array.isArray(value) ? value.slice(-MAX_ASSISTANT_RESPONSES).flatMap((item) => {
|
|
1512
|
+
if (!item || typeof item.text !== "string" || item.text.length > MAX_ASSISTANT_RESPONSE_CHARACTERS || item.id !== sourceId(item.text))
|
|
1513
|
+
return [];
|
|
1514
|
+
return [{ id: item.id, text: item.text, truncated: item.truncated === true }];
|
|
1515
|
+
}) : [];
|
|
1516
|
+
};
|
|
1517
|
+
var captureAssistantResponses = (metadata, messages) => {
|
|
1518
|
+
const sources = new Map(assistantResponses(metadata).map((source) => [source.id, source]));
|
|
1519
|
+
for (const message of messages) {
|
|
1520
|
+
if (message.role !== "assistant" || message.parts.some((part) => part.type === "tool-call"))
|
|
1521
|
+
continue;
|
|
1522
|
+
const text2 = redactSource(message.parts.flatMap((part) => part.type === "text" ? [part.text] : []).join(`
|
|
1523
|
+
`));
|
|
1524
|
+
if (!text2.trim() || /^\[Compacted (?:conversation context|prior conversation)\]/.test(text2))
|
|
1525
|
+
continue;
|
|
1526
|
+
const bounded = text2.slice(0, MAX_ASSISTANT_RESPONSE_CHARACTERS);
|
|
1527
|
+
const id = sourceId(bounded);
|
|
1528
|
+
const truncated = sources.get(id)?.truncated === true || text2.length > bounded.length;
|
|
1529
|
+
sources.delete(id);
|
|
1530
|
+
sources.set(id, { id, text: bounded, truncated });
|
|
1531
|
+
while (sources.size > MAX_ASSISTANT_RESPONSES)
|
|
1532
|
+
sources.delete(sources.keys().next().value);
|
|
1533
|
+
}
|
|
1534
|
+
return [...sources.values()];
|
|
1535
|
+
};
|
|
1490
1536
|
var taskSources = (metadata) => {
|
|
1491
1537
|
const value = metadata && typeof metadata === "object" ? metadata[TASK_SOURCE_KEY] : undefined;
|
|
1492
1538
|
return Array.isArray(value) ? value.filter((v) => !!v && typeof v.id === "string" && /^sha256:[a-f0-9]{64}$/.test(v.id) && typeof v.text === "string").map((source) => ({ id: source.id, text: source.text, ...source.original === true ? { original: true } : {} })) : [];
|
|
@@ -1503,8 +1549,8 @@ var captureTaskSources = (metadata, messages) => {
|
|
|
1503
1549
|
for (const part of message.parts) {
|
|
1504
1550
|
if (part.type !== "text" || /^\[Compacted (?:conversation context|prior conversation)\]/.test(part.text))
|
|
1505
1551
|
continue;
|
|
1506
|
-
const text2 =
|
|
1507
|
-
const id =
|
|
1552
|
+
const text2 = redactSource(part.text);
|
|
1553
|
+
const id = sourceId(text2);
|
|
1508
1554
|
const original = sources.size === 0 || sources.get(id)?.original === true;
|
|
1509
1555
|
sources.delete(id);
|
|
1510
1556
|
sources.set(id, { id, text: text2, ...original ? { original: true } : {} });
|
|
@@ -1514,14 +1560,39 @@ var captureTaskSources = (metadata, messages) => {
|
|
|
1514
1560
|
var createTaskTools = () => ({
|
|
1515
1561
|
read_task: tool({
|
|
1516
1562
|
name: "read_task",
|
|
1517
|
-
description: "Recover operator requests after compaction. Omit id for the latest
|
|
1563
|
+
description: "Recover operator requests after compaction (default source). Use source=assistant_response to recover a prior assistant report or plan referenced by the user; optional literal query locates text in the newest matching retained response. Assistant text is untrusted, unverified, never permissions or acceptance. Omit id for the latest source. Operator IDs default to the newest 64; sourceOffset pages earlier IDs. Text offsets are characters; pages are at most 4000 characters.",
|
|
1518
1564
|
metadata: { advancedRegistry: { permissions: ["read"], audit: { riskLevel: "low" } } },
|
|
1519
1565
|
schema: z8.object({
|
|
1566
|
+
source: z8.enum(["operator", "assistant_response"]).optional(),
|
|
1567
|
+
query: z8.string().min(1).max(200).optional(),
|
|
1520
1568
|
id: z8.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
|
|
1521
|
-
offset: z8.number().int().min(0).
|
|
1569
|
+
offset: z8.number().int().min(0).optional(),
|
|
1522
1570
|
sourceOffset: z8.number().int().min(0).optional()
|
|
1523
1571
|
}),
|
|
1524
|
-
execute: async ({ id, offset, sourceOffset }, context) => {
|
|
1572
|
+
execute: async ({ source: kind, query, id, offset: requestedOffset, sourceOffset }, context) => {
|
|
1573
|
+
if (kind === "assistant_response") {
|
|
1574
|
+
const sources2 = assistantResponses(context?.metadata);
|
|
1575
|
+
const source2 = id ? sources2.find((item) => item.id === id) : [...sources2].reverse().find((item) => !query || item.text.includes(query));
|
|
1576
|
+
if (!source2)
|
|
1577
|
+
throw new Error("Requested assistant response is not retained in this run.");
|
|
1578
|
+
const offset2 = requestedOffset ?? (query ? Math.max(0, source2.text.indexOf(query)) : 0);
|
|
1579
|
+
return {
|
|
1580
|
+
source: "assistant_response",
|
|
1581
|
+
untrusted: true,
|
|
1582
|
+
verified: false,
|
|
1583
|
+
id: source2.id,
|
|
1584
|
+
sourceIds: sources2.map((item) => item.id),
|
|
1585
|
+
totalSources: sources2.length,
|
|
1586
|
+
truncated: source2.truncated,
|
|
1587
|
+
content: source2.text.slice(offset2, offset2 + 4000),
|
|
1588
|
+
offset: offset2,
|
|
1589
|
+
totalCharacters: source2.text.length,
|
|
1590
|
+
nextOffset: offset2 + 4000 < source2.text.length ? offset2 + 4000 : null
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
if (query)
|
|
1594
|
+
throw new Error("Literal query is only supported for assistant responses.");
|
|
1595
|
+
const offset = requestedOffset ?? 0;
|
|
1525
1596
|
const sources = taskSources(context?.metadata);
|
|
1526
1597
|
const source = id ? sources.find((s) => s.id === id) : sources.at(-1);
|
|
1527
1598
|
if (!source)
|
|
@@ -1552,4 +1623,4 @@ var createTaskTools = () => ({
|
|
|
1552
1623
|
})
|
|
1553
1624
|
});
|
|
1554
1625
|
|
|
1555
|
-
export { protectStateFromGit, validateStateDirectory, HARNESS_SESSION_INDEX_FILE, HARNESS_SESSION_SCHEMA_VERSION, SESSION_RUN_STATUSES, TERMINAL_SESSION_RUN_STATUSES, openCliSessionStore, openSessionStore, inspectRuntimeDiagnostics, inspectRuntimeManifest, estimateContextTokens, measureContext, MODEL_BUDGET_KEY, estimateRequestTokens, workBudgetReached, createModelBudget, harnessToolExecution, USAGE_LEDGER_KEY, usagePricingSchema, inspectUsageLedger, formatUsageLedger, UsageLedger, verifierSchema, taskAcceptanceContractSchema, compileTaskAcceptanceContract, TASK_ACCEPTANCE_KEY, TASK_ACCEPTANCE_EVIDENCE_KEY, readTaskAcceptanceLedger, nextTaskAcceptanceLedger, persistTaskAcceptanceRevision, taskAcceptanceCheckpointStore, TASK_SOURCE_KEY, taskSources, captureTaskSources, createTaskTools };
|
|
1626
|
+
export { protectStateFromGit, validateStateDirectory, HARNESS_SESSION_INDEX_FILE, HARNESS_SESSION_SCHEMA_VERSION, SESSION_RUN_STATUSES, TERMINAL_SESSION_RUN_STATUSES, ensurePrivateDatabase, openCliSessionStore, openSessionStore, inspectRuntimeDiagnostics, inspectRuntimeManifest, estimateContextTokens, measureContext, MODEL_BUDGET_KEY, estimateRequestTokens, workBudgetReached, createModelBudget, harnessToolExecution, USAGE_LEDGER_KEY, usagePricingSchema, inspectUsageLedger, formatUsageLedger, UsageLedger, verifierSchema, taskAcceptanceContractSchema, compileTaskAcceptanceContract, TASK_ACCEPTANCE_KEY, TASK_ACCEPTANCE_EVIDENCE_KEY, readTaskAcceptanceLedger, nextTaskAcceptanceLedger, persistTaskAcceptanceRevision, taskAcceptanceCheckpointStore, TASK_SOURCE_KEY, ASSISTANT_RESPONSE_KEY, assistantResponses, captureAssistantResponses, taskSources, captureTaskSources, createTaskTools };
|
|
@@ -89,6 +89,8 @@ var CLI_OPTION_NAMES = [
|
|
|
89
89
|
"--workspace",
|
|
90
90
|
"--state-dir",
|
|
91
91
|
"--mcp-config",
|
|
92
|
+
"--no-memory",
|
|
93
|
+
"--source",
|
|
92
94
|
"--context-config",
|
|
93
95
|
"--no-project-context",
|
|
94
96
|
"--patch",
|
|
@@ -220,6 +222,7 @@ var childBudgets = [
|
|
|
220
222
|
"--subagent-timeout-ms"
|
|
221
223
|
];
|
|
222
224
|
var agent = [
|
|
225
|
+
"--no-memory",
|
|
223
226
|
"--compaction-model",
|
|
224
227
|
"--compaction-provider",
|
|
225
228
|
"--tool-policy",
|
|
@@ -271,7 +274,7 @@ var CLI_COMMAND_OPTION_CONTRACTS = {
|
|
|
271
274
|
providers: contract(["--json"]),
|
|
272
275
|
policy: contract(["--service", ...agent, "--json"]),
|
|
273
276
|
doctor: contract([...provider, ...profile, ...locator, ...project, ...execution, ...budgets, "--allow-check", "--require-capability", "--subagent", "--json"]),
|
|
274
|
-
resume: contract(["--tool-policy", "--service", "--session", ...locator, "--approve", "--deny", "--json", "--jsonl"], [["--approve", "--deny"]]),
|
|
277
|
+
resume: contract(["--no-memory", "--tool-policy", "--service", "--session", ...locator, "--approve", "--deny", "--json", "--jsonl"], [["--approve", "--deny"]]),
|
|
275
278
|
"runs:list": contract([...locator, "--status", "--limit", "--cursor", "--json"]),
|
|
276
279
|
"runs:inspect": contract([...locator, "--json"]),
|
|
277
280
|
"runs:cancel": contract([...locator, "--reason", "--cascade", "--final", "--json"]),
|
|
@@ -295,6 +298,17 @@ var CLI_COMMAND_OPTION_CONTRACTS = {
|
|
|
295
298
|
"checkpoints:recover": contract([...locator, "--json"]),
|
|
296
299
|
"changes:create": contract(["--patch"], ["--patch"]),
|
|
297
300
|
"changes:verify": contract(["--patch", "--preconditions", "--now"], ["--patch"]),
|
|
301
|
+
"memory:remember": contract([...locator, "--json", "--source"]),
|
|
302
|
+
"memory:suggest": contract([...locator, "--json", "--source"]),
|
|
303
|
+
"memory:list": contract([...locator, "--json"]),
|
|
304
|
+
"memory:read": contract([...locator, "--json"]),
|
|
305
|
+
"memory:update": contract([...locator, "--json", "--source"]),
|
|
306
|
+
"memory:forget": contract([...locator, "--json"]),
|
|
307
|
+
"memory:accept": contract([...locator, "--json"]),
|
|
308
|
+
"memory:clear": contract([...locator, "--json"]),
|
|
309
|
+
"memory:enable": contract([...locator, "--json"]),
|
|
310
|
+
"memory:disable": contract([...locator, "--json"]),
|
|
311
|
+
"memory:context": contract([...locator, "--json"]),
|
|
298
312
|
"state:status": contract([...locator, "--json"]),
|
|
299
313
|
"state:export": contract([...locator, "--json"]),
|
|
300
314
|
"state:import": contract([...locator, "--apply", "--json"]),
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
HARNESS_OPERATIONS_SCHEMA_VERSION,
|
|
3
3
|
HARNESS_SQLITE_FILE,
|
|
4
|
+
decodeProjectMemory,
|
|
4
5
|
openHarnessPersistence,
|
|
6
|
+
projectMemoryRecordKey,
|
|
5
7
|
sqliteAdapter,
|
|
6
8
|
workspaceCheckpointSchema,
|
|
7
9
|
workspaceRestoreOperationSchema
|
|
8
|
-
} from "./index-
|
|
10
|
+
} from "./index-rd0s3gqj.js";
|
|
9
11
|
import {
|
|
10
12
|
HARNESS_SESSION_SCHEMA_VERSION,
|
|
11
13
|
openCliSessionStore,
|
|
12
14
|
validateStateDirectory
|
|
13
|
-
} from "./index-
|
|
15
|
+
} from "./index-vtqfjnab.js";
|
|
14
16
|
import {
|
|
15
17
|
SqliteDatabase,
|
|
16
18
|
readRegularFileChunksNoFollow
|
|
17
|
-
} from "./index-
|
|
19
|
+
} from "./index-r0tdj04h.js";
|
|
18
20
|
import {
|
|
19
21
|
HarnessStateConflictError,
|
|
20
22
|
HarnessWorkspaceError
|
|
@@ -214,13 +216,24 @@ async function readBackupTransport(source, legacyMaxBytes) {
|
|
|
214
216
|
}
|
|
215
217
|
|
|
216
218
|
// src/persistence/state-backup.ts
|
|
217
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
219
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
218
220
|
import { constants as fsConstants } from "node:fs";
|
|
219
221
|
import { chmod, link, lstat as lstat2, open, realpath as realpath2, unlink } from "node:fs/promises";
|
|
220
222
|
import path2 from "node:path";
|
|
221
223
|
import { z } from "zod";
|
|
222
224
|
import { normalizeAgentRunState } from "@zhivex-ai/agents";
|
|
223
225
|
import { createSqliteAgentRunStore } from "@zhivex-ai/agents/ops";
|
|
226
|
+
|
|
227
|
+
// src/persistence/sdk-store-identity.ts
|
|
228
|
+
import { createHash } from "node:crypto";
|
|
229
|
+
var sdkCanonicalKey = (kind, scope, value) => `${kind}:v2:${createHash("sha256").update(JSON.stringify([
|
|
230
|
+
JSON.stringify([scope.namespace ?? null, scope.tenantId, scope.userId ?? null]),
|
|
231
|
+
value
|
|
232
|
+
])).digest("hex")}`;
|
|
233
|
+
var sdkLegacyKey = (scope, value) => `${encodeURIComponent(scope.namespace ?? "default")}:${encodeURIComponent(scope.tenantId)}:${encodeURIComponent(scope.userId ?? "*")}:${value}`;
|
|
234
|
+
var sdkRunKeyMatches = (key, scope, value) => key === sdkCanonicalKey("agent-run", scope, value) || key === sdkLegacyKey(scope, value);
|
|
235
|
+
|
|
236
|
+
// src/persistence/state-backup.ts
|
|
224
237
|
var HARNESS_STATE_BACKUP_SCHEMA_VERSION = 1;
|
|
225
238
|
var HARNESS_STATE_BACKUP_MAX_BYTES = 64 * 1024 * 1024;
|
|
226
239
|
var terminalRunStatuses = new Set(["completed", "failed", "cancelled", "timed_out"]);
|
|
@@ -275,6 +288,8 @@ var memoryRecordSchema = z.object({
|
|
|
275
288
|
messages: z.array(z.unknown()),
|
|
276
289
|
updatedAt: z.number().int().nonnegative()
|
|
277
290
|
}).strict();
|
|
291
|
+
var serializedMemory = (entry) => JSON.stringify(entry.key.startsWith("agent-memory:v2:") ? { schemaVersion: 1, memoryKey: entry.key, messages: entry.messages } : entry.messages);
|
|
292
|
+
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)])));
|
|
278
293
|
var sessionRecordSchema = z.object({
|
|
279
294
|
sessionId: z.string().min(1).max(260),
|
|
280
295
|
workspaceKey: bindingKeySchema,
|
|
@@ -356,12 +371,12 @@ var canonicalJson = (value) => {
|
|
|
356
371
|
return `{${Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson(entry)}`).join(",")}}`;
|
|
357
372
|
};
|
|
358
373
|
var checksumPayload = (payload) => {
|
|
359
|
-
const hash =
|
|
374
|
+
const hash = createHash2("sha256");
|
|
360
375
|
for (const chunk of canonicalChunks(payload))
|
|
361
376
|
hash.update(chunk);
|
|
362
377
|
return `sha256:${hash.digest("hex")}`;
|
|
363
378
|
};
|
|
364
|
-
var stableKey = (kind, value) =>
|
|
379
|
+
var stableKey = (kind, value) => createHash2("sha256").update(kind).update("\x00").update(value).digest("hex");
|
|
365
380
|
var scopeValue = (config) => `${config.scope.tenantId}\x00${config.scope.userId ?? ""}\x00${config.scope.namespace ?? ""}`;
|
|
366
381
|
var scopePrefix = (config) => `${encodeURIComponent(config.scope.namespace ?? "default")}:${encodeURIComponent(config.scope.tenantId)}:${encodeURIComponent(config.scope.userId ?? "*")}:`;
|
|
367
382
|
var stateMatchesScope = (config, state) => {
|
|
@@ -373,7 +388,6 @@ var stateMatchesScope = (config, state) => {
|
|
|
373
388
|
const scope = candidate.scope;
|
|
374
389
|
return scope.tenantId === config.scope.tenantId && (scope.userId ?? undefined) === (config.scope.userId ?? undefined) && (scope.namespace ?? undefined) === (config.scope.namespace ?? undefined);
|
|
375
390
|
};
|
|
376
|
-
var budgetScopePrefix = (config) => `__zhivex_budget__:${encodeURIComponent(config.scope.tenantId)}:${encodeURIComponent(config.scope.userId ?? "*")}:`;
|
|
377
391
|
var coordinatorIds = (runs) => new Set(runs.flatMap(({ state }) => {
|
|
378
392
|
const id = state.budgetCoordinatorId;
|
|
379
393
|
return typeof id === "string" ? [id] : [];
|
|
@@ -381,7 +395,7 @@ var coordinatorIds = (runs) => new Set(runs.flatMap(({ state }) => {
|
|
|
381
395
|
var validateBudgetLedger = (config, run, identities) => {
|
|
382
396
|
const state = validatedRunState(run.state, `Budget ledger ${run.key}`);
|
|
383
397
|
const identity = state.metadata?.budgetIdentity;
|
|
384
|
-
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
|
|
398
|
+
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)) {
|
|
385
399
|
throw new HarnessStateConflictError("Budget ledger is not bound to an exported run and durable scope.");
|
|
386
400
|
}
|
|
387
401
|
assertTerminalState(state, `Budget ledger ${run.key}`);
|
|
@@ -559,12 +573,16 @@ var readPayload = async (config, recordedWorkspace, accessLease) => {
|
|
|
559
573
|
parentRunKey: row.parent_run_id,
|
|
560
574
|
updatedAt: row.updated_at_ms
|
|
561
575
|
}));
|
|
562
|
-
const memoryKeys =
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
576
|
+
const memoryKeys = memoryKeysForRuns(config, runs);
|
|
577
|
+
memoryKeys.add(projectMemoryRecordKey(binding));
|
|
578
|
+
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) => {
|
|
579
|
+
const value = JSON.parse(row.messages_json);
|
|
580
|
+
if (row.memory_key.startsWith("agent-memory:v2:")) {
|
|
581
|
+
const envelope = z.strictObject({ schemaVersion: z.literal(1), memoryKey: z.literal(row.memory_key), messages: z.array(z.unknown()) }).parse(value);
|
|
582
|
+
return { key: row.memory_key, messages: envelope.messages, updatedAt: row.updated_at_ms };
|
|
583
|
+
}
|
|
584
|
+
return { key: row.memory_key, messages: z.array(z.unknown()).parse(value), updatedAt: row.updated_at_ms };
|
|
585
|
+
});
|
|
568
586
|
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);
|
|
569
587
|
const selectedSessionIds = new Set(sessionRows.map((row) => row.session_id));
|
|
570
588
|
const sessionRunRows = database.query("SELECT * FROM zhivex_cli_session_runs ORDER BY session_id, ordinal").all().filter((row) => selectedSessionIds.has(row.session_id));
|
|
@@ -762,7 +780,7 @@ var validateBundleBinding = async (config, bundle) => {
|
|
|
762
780
|
throw new HarnessStateConflictError(`Run ${run.key} is bound to another durable scope.`);
|
|
763
781
|
}
|
|
764
782
|
runIds.add(state.runId);
|
|
765
|
-
if (run.key
|
|
783
|
+
if (!sdkRunKeyMatches(run.key, config.scope, state.runId)) {
|
|
766
784
|
throw new HarnessStateConflictError(`Run ${run.key} does not match its bound scope and runId.`);
|
|
767
785
|
}
|
|
768
786
|
}
|
|
@@ -781,7 +799,7 @@ var validateBundleBinding = async (config, bundle) => {
|
|
|
781
799
|
const journalKeys = new Set;
|
|
782
800
|
for (const entry of bundle.records.toolJournal) {
|
|
783
801
|
const journalKey = `${entry.runKey}\x00${entry.toolCallId}`;
|
|
784
|
-
if (journalKeys.has(journalKey) || !runKeys.has(entry.runKey) || !stateMatchesScope(config, entry.entry) || entry.entry.runId !==
|
|
802
|
+
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) {
|
|
785
803
|
throw new HarnessStateConflictError(`Tool journal ${entry.toolCallId} is not bound to an imported run.`);
|
|
786
804
|
}
|
|
787
805
|
journalKeys.add(journalKey);
|
|
@@ -793,7 +811,7 @@ var validateBundleBinding = async (config, bundle) => {
|
|
|
793
811
|
}
|
|
794
812
|
idempotencyKeys.add(entry.key);
|
|
795
813
|
const state = bundle.records.runs.find((run) => run.key === entry.runKey).state;
|
|
796
|
-
if (typeof state.idempotencyKey !== "string" || entry.key
|
|
814
|
+
if (typeof state.idempotencyKey !== "string" || !sdkRunKeyMatches(entry.key, config.scope, state.idempotencyKey)) {
|
|
797
815
|
throw new HarnessStateConflictError("Idempotency record does not match its bound run state.");
|
|
798
816
|
}
|
|
799
817
|
}
|
|
@@ -805,9 +823,12 @@ var validateBundleBinding = async (config, bundle) => {
|
|
|
805
823
|
parentKeys.add(entry.runKey);
|
|
806
824
|
}
|
|
807
825
|
const memoryKeys = new Set;
|
|
826
|
+
const allowedMemoryKeys = memoryKeysForRuns(config, bundle.records.runs);
|
|
808
827
|
for (const entry of bundle.records.memory) {
|
|
809
|
-
const
|
|
810
|
-
if (
|
|
828
|
+
const projectRecord = entry.key === projectMemoryRecordKey(expected);
|
|
829
|
+
if (projectRecord)
|
|
830
|
+
decodeProjectMemory(entry.messages, expected);
|
|
831
|
+
if (memoryKeys.has(entry.key) || !projectRecord && !allowedMemoryKeys.has(entry.key)) {
|
|
811
832
|
throw new HarnessStateConflictError(`Memory record ${entry.key} is not bound to an imported run.`);
|
|
812
833
|
}
|
|
813
834
|
memoryKeys.add(entry.key);
|
|
@@ -849,7 +870,7 @@ var validateBundleBinding = async (config, bundle) => {
|
|
|
849
870
|
const turn = bundle.records.sessionRuns.find((run) => run.turnId === checkpoint.turnId && run.sessionId === checkpoint.sessionId);
|
|
850
871
|
if (!turn || !terminalSessionStatuses.has(turn.status))
|
|
851
872
|
throw new HarnessStateConflictError("Checkpoint targets a missing terminal turn.");
|
|
852
|
-
if (new Set(checkpoint.files.map((file) => file.path)).size !== checkpoint.files.length || checkpoint.files.some((file) => `sha256:${
|
|
873
|
+
if (new Set(checkpoint.files.map((file) => file.path)).size !== checkpoint.files.length || checkpoint.files.some((file) => `sha256:${createHash2("sha256").update(file.content).digest("hex")}` !== file.digest || Buffer.byteLength(file.content) > 65536)) {
|
|
853
874
|
throw new HarnessStateConflictError("Checkpoint content identity is invalid.");
|
|
854
875
|
}
|
|
855
876
|
if (record.kind === "restore") {
|
|
@@ -946,9 +967,9 @@ var importHarnessStateBackup = async (config, bundle, options = {}) => {
|
|
|
946
967
|
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}`) : []),
|
|
947
968
|
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) : []),
|
|
948
969
|
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) : []),
|
|
949
|
-
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) => {
|
|
970
|
+
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) => {
|
|
950
971
|
const state = JSON.parse(run.state_json);
|
|
951
|
-
return
|
|
972
|
+
return memoryKeysForRuns(config, [{ state }]).has(row.memory_key);
|
|
952
973
|
})).map((row) => row.memory_key) : []),
|
|
953
974
|
sessions: destinationSessionIds,
|
|
954
975
|
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) : [])
|
|
@@ -974,7 +995,7 @@ var importHarnessStateBackup = async (config, bundle, options = {}) => {
|
|
|
974
995
|
for (const entry of bundle.records.toolJournal)
|
|
975
996
|
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]);
|
|
976
997
|
for (const entry of bundle.records.memory)
|
|
977
|
-
insertOrCompare("zhivex_agent_memory", "memory_key = ?", [entry.key], "messages_json, updated_at_ms", [
|
|
998
|
+
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]);
|
|
978
999
|
for (const session of bundle.records.sessions)
|
|
979
1000
|
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", [
|
|
980
1001
|
session.workspaceKey,
|
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
timeToSafeFixLatencyStatistics,
|
|
72
72
|
timeToSafeFixTaskSchema,
|
|
73
73
|
verifyChangeEnvelope
|
|
74
|
-
} from "./index-
|
|
74
|
+
} from "./index-dj5z774k.js";
|
|
75
75
|
import {
|
|
76
76
|
HARNESS_STATE_BACKUP_MAX_BYTES,
|
|
77
77
|
HARNESS_STATE_BACKUP_SCHEMA_VERSION,
|
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
inspectHarnessState,
|
|
83
83
|
readHarnessStateBackup,
|
|
84
84
|
stateBackupBundleSchema
|
|
85
|
-
} from "./index-
|
|
85
|
+
} from "./index-z6br6qdn.js";
|
|
86
86
|
import {
|
|
87
87
|
CLI_COMMAND_OPTION_CONTRACTS,
|
|
88
88
|
CLI_OPTION_DEFINITIONS,
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
resolveHarnessModelRoutes,
|
|
93
93
|
serializeHarnessModelRoutes,
|
|
94
94
|
validateCliCommandOptions
|
|
95
|
-
} from "./index-
|
|
95
|
+
} from "./index-wq2tax80.js";
|
|
96
96
|
import {
|
|
97
97
|
harnessLocalCredentialsSchema,
|
|
98
98
|
openHarnessActivityStore,
|
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
recoverHarnessLocalService,
|
|
101
101
|
requestHarnessLocalService,
|
|
102
102
|
startHarnessLocalService
|
|
103
|
-
} from "./index-
|
|
103
|
+
} from "./index-49ys3s4q.js";
|
|
104
104
|
import {
|
|
105
105
|
createAcpConnection,
|
|
106
106
|
serveAcpStdio
|
|
@@ -147,7 +147,7 @@ import {
|
|
|
147
147
|
runHarness,
|
|
148
148
|
runHarnessReviewGroup,
|
|
149
149
|
selectHarnessModel
|
|
150
|
-
} from "./index-
|
|
150
|
+
} from "./index-4j1h4j8c.js";
|
|
151
151
|
import {
|
|
152
152
|
HARNESS_OPERATIONS_SCHEMA_VERSION,
|
|
153
153
|
HARNESS_SQLITE_FILE,
|
|
@@ -159,8 +159,8 @@ import {
|
|
|
159
159
|
migrateLegacyFileRuns,
|
|
160
160
|
openHarnessPersistence,
|
|
161
161
|
openWorkspaceCheckpointStore
|
|
162
|
-
} from "./index-
|
|
163
|
-
import"./index-
|
|
162
|
+
} from "./index-rd0s3gqj.js";
|
|
163
|
+
import"./index-a1q355va.js";
|
|
164
164
|
import {
|
|
165
165
|
HARNESS_SESSION_INDEX_FILE,
|
|
166
166
|
HARNESS_SESSION_SCHEMA_VERSION,
|
|
@@ -169,7 +169,7 @@ import {
|
|
|
169
169
|
openCliSessionStore,
|
|
170
170
|
openSessionStore,
|
|
171
171
|
validateStateDirectory
|
|
172
|
-
} from "./index-
|
|
172
|
+
} from "./index-vtqfjnab.js";
|
|
173
173
|
import {
|
|
174
174
|
BUN_ENGINE_RANGE,
|
|
175
175
|
HARNESS_MCP_CONFIG_SCHEMA_VERSION,
|
|
@@ -180,7 +180,7 @@ import {
|
|
|
180
180
|
createHttpMcpClient,
|
|
181
181
|
loadHarnessMcpConfiguration,
|
|
182
182
|
normalizeHarnessMcpConfiguration
|
|
183
|
-
} from "./index-
|
|
183
|
+
} from "./index-0g939pfs.js";
|
|
184
184
|
import {
|
|
185
185
|
CliOciRuntimeAdapter,
|
|
186
186
|
HARNESS_EXECUTION_ARTIFACT_SCHEMA_VERSION,
|
|
@@ -192,7 +192,7 @@ import {
|
|
|
192
192
|
describeOciCommand,
|
|
193
193
|
executionFingerprintInput,
|
|
194
194
|
harnessExecutionSession
|
|
195
|
-
} from "./index-
|
|
195
|
+
} from "./index-e6r04a18.js";
|
|
196
196
|
import {
|
|
197
197
|
EDIT_CONTRACT_SCHEMA_VERSION,
|
|
198
198
|
EDIT_DIGEST_ALGORITHM,
|
|
@@ -215,7 +215,7 @@ import {
|
|
|
215
215
|
restoreFileInputSchema,
|
|
216
216
|
validateEditProposal,
|
|
217
217
|
workspaceFilePathSchema
|
|
218
|
-
} from "./index-
|
|
218
|
+
} from "./index-r0tdj04h.js";
|
|
219
219
|
import {
|
|
220
220
|
BUILTIN_PROVIDER_REGISTRATIONS,
|
|
221
221
|
DEFAULT_ALLOWED_CHECKS,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type HarnessProjectMemoryOptions } from "./project-memory.js";
|
|
2
|
+
export declare const HARNESS_MEMORY_COMMANDS: readonly ["remember", "list", "read", "update", "forget", "suggest", "accept", "clear", "enable", "disable", "context"];
|
|
3
|
+
/** Host/CLI operations only: these commands are never added to the model tool catalog. */
|
|
4
|
+
export declare function executeHarnessMemoryCommand(options: HarnessProjectMemoryOptions, command: string, args: readonly string[], source?: string): Promise<{
|
|
5
|
+
schemaVersion: number;
|
|
6
|
+
kind: string;
|
|
7
|
+
command: string;
|
|
8
|
+
workspaceKey: string;
|
|
9
|
+
scopeKey: string;
|
|
10
|
+
result: unknown;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { AgentStoreScope } from "@zhivex-ai/agents/ops";
|
|
3
|
+
export declare const HARNESS_PROJECT_MEMORY_SCHEMA_VERSION: 1;
|
|
4
|
+
export declare const HARNESS_PROJECT_MEMORY_LIMITS: Readonly<{
|
|
5
|
+
entries: 128;
|
|
6
|
+
entryBytes: 4096;
|
|
7
|
+
documentBytes: number;
|
|
8
|
+
contextBytes: 6000;
|
|
9
|
+
contextEntries: 3;
|
|
10
|
+
staleAfterMs: number;
|
|
11
|
+
}>;
|
|
12
|
+
declare const entrySchema: z.ZodObject<{
|
|
13
|
+
id: z.ZodString;
|
|
14
|
+
content: z.ZodString;
|
|
15
|
+
source: z.ZodObject<{
|
|
16
|
+
kind: z.ZodEnum<{
|
|
17
|
+
operator: "operator";
|
|
18
|
+
suggestion: "suggestion";
|
|
19
|
+
}>;
|
|
20
|
+
reference: z.ZodString;
|
|
21
|
+
}, z.core.$strict>;
|
|
22
|
+
status: z.ZodEnum<{
|
|
23
|
+
accepted: "accepted";
|
|
24
|
+
pending: "pending";
|
|
25
|
+
}>;
|
|
26
|
+
revision: z.ZodNumber;
|
|
27
|
+
createdAt: z.ZodNumber;
|
|
28
|
+
updatedAt: z.ZodNumber;
|
|
29
|
+
reviewedAt: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
expiresAt: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
export type HarnessProjectMemoryEntry = z.infer<typeof entrySchema>;
|
|
33
|
+
export interface HarnessProjectMemoryInput {
|
|
34
|
+
content: string;
|
|
35
|
+
source: string;
|
|
36
|
+
expiresAt?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface HarnessProjectMemoryOptions {
|
|
39
|
+
workspace: string;
|
|
40
|
+
stateDirectory: string;
|
|
41
|
+
scope: AgentStoreScope;
|
|
42
|
+
now?: () => number;
|
|
43
|
+
}
|
|
44
|
+
export interface HarnessProjectMemoryView {
|
|
45
|
+
schemaVersion: 1;
|
|
46
|
+
kind: "project-memory";
|
|
47
|
+
workspaceKey: string;
|
|
48
|
+
scopeKey: string;
|
|
49
|
+
enabled: boolean;
|
|
50
|
+
entries: (HarnessProjectMemoryEntry & {
|
|
51
|
+
freshness: "fresh" | "stale" | "expired" | "pending";
|
|
52
|
+
})[];
|
|
53
|
+
limits: typeof HARNESS_PROJECT_MEMORY_LIMITS;
|
|
54
|
+
}
|
|
55
|
+
export interface HarnessProjectMemory {
|
|
56
|
+
readonly databasePath: string;
|
|
57
|
+
list(): HarnessProjectMemoryView;
|
|
58
|
+
read(id: string): HarnessProjectMemoryView["entries"][number];
|
|
59
|
+
remember(input: HarnessProjectMemoryInput): HarnessProjectMemoryEntry;
|
|
60
|
+
suggest(input: HarnessProjectMemoryInput): HarnessProjectMemoryEntry;
|
|
61
|
+
update(id: string, expectedRevision: number, input: HarnessProjectMemoryInput): HarnessProjectMemoryEntry;
|
|
62
|
+
accept(id: string, expectedRevision: number): HarnessProjectMemoryEntry;
|
|
63
|
+
forget(id: string, expectedRevision: number): void;
|
|
64
|
+
clear(): number;
|
|
65
|
+
setEnabled(enabled: boolean): void;
|
|
66
|
+
retrieve(query: string, budget?: {
|
|
67
|
+
maxBytes?: number;
|
|
68
|
+
maxEntries?: number;
|
|
69
|
+
}): {
|
|
70
|
+
content: string;
|
|
71
|
+
ids: string[];
|
|
72
|
+
bytes: number;
|
|
73
|
+
};
|
|
74
|
+
close(): void;
|
|
75
|
+
}
|
|
76
|
+
export declare const projectMemoryRecordKey: (binding: {
|
|
77
|
+
workspaceKey: string;
|
|
78
|
+
scopeKey: string;
|
|
79
|
+
}) => string;
|
|
80
|
+
export declare const projectMemoryBinding: (workspace: string, scope: AgentStoreScope) => {
|
|
81
|
+
workspaceKey: string;
|
|
82
|
+
scopeKey: string;
|
|
83
|
+
memoryKey: string;
|
|
84
|
+
};
|
|
85
|
+
export declare const decodeProjectMemory: (messages: unknown, binding: {
|
|
86
|
+
workspaceKey: string;
|
|
87
|
+
scopeKey: string;
|
|
88
|
+
}) => {
|
|
89
|
+
schemaVersion: 1;
|
|
90
|
+
workspaceKey: string;
|
|
91
|
+
scopeKey: string;
|
|
92
|
+
enabled: boolean;
|
|
93
|
+
entries: {
|
|
94
|
+
id: string;
|
|
95
|
+
content: string;
|
|
96
|
+
source: {
|
|
97
|
+
kind: "operator" | "suggestion";
|
|
98
|
+
reference: string;
|
|
99
|
+
};
|
|
100
|
+
status: "accepted" | "pending";
|
|
101
|
+
revision: number;
|
|
102
|
+
createdAt: number;
|
|
103
|
+
updatedAt: number;
|
|
104
|
+
reviewedAt?: number | undefined;
|
|
105
|
+
expiresAt?: number | undefined;
|
|
106
|
+
}[];
|
|
107
|
+
};
|
|
108
|
+
export declare function openHarnessProjectMemory(options: HarnessProjectMemoryOptions): Promise<HarnessProjectMemory>;
|
|
109
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AgentStoreScope } from "@zhivex-ai/core";
|
|
2
|
+
export declare const sdkCanonicalKey: (kind: "agent-run" | "agent-memory", scope: AgentStoreScope, value: string) => string;
|
|
3
|
+
export declare const sdkLegacyKey: (scope: AgentStoreScope, value: string) => string;
|
|
4
|
+
export declare const sdkRunKeyMatches: (key: string, scope: AgentStoreScope, value: string) => boolean;
|
|
@@ -120,6 +120,10 @@ export interface CliSessionStore {
|
|
|
120
120
|
}): Promise<SessionRetentionResult>;
|
|
121
121
|
close(): void;
|
|
122
122
|
}
|
|
123
|
+
export declare const ensurePrivateDatabase: (workspace: string, stateDirectory: string) => Promise<{
|
|
124
|
+
databasePath: string;
|
|
125
|
+
databaseEntry: import("node:fs").Stats;
|
|
126
|
+
}>;
|
|
123
127
|
export declare const openCliSessionStore: (options: OpenSessionStoreOptions) => Promise<CliSessionStore>;
|
|
124
128
|
/** Compatibility-friendly name for consumers that do not care that the index is CLI-owned. */
|
|
125
129
|
export declare const openSessionStore: typeof openCliSessionStore;
|