@askdkc/kiokuko 0.1.24 → 0.1.25
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/dist/agent-file/render.d.ts +1 -1
- package/dist/agent-file/render.d.ts.map +1 -1
- package/dist/agent-file/render.js +4 -3
- package/dist/agent-file/render.js.map +1 -1
- package/dist/akinator/agent-task.d.ts +7 -0
- package/dist/akinator/agent-task.d.ts.map +1 -1
- package/dist/akinator/agent-task.js +25 -11
- package/dist/akinator/agent-task.js.map +1 -1
- package/dist/commands/use.d.ts +2 -1
- package/dist/commands/use.d.ts.map +1 -1
- package/dist/commands/use.js +20 -5
- package/dist/commands/use.js.map +1 -1
- package/dist/context/feedback.d.ts +2 -3
- package/dist/context/feedback.d.ts.map +1 -1
- package/dist/context/feedback.js +2 -3
- package/dist/context/feedback.js.map +1 -1
- package/dist/ledger/checkpoint-contract.d.ts +139 -2
- package/dist/ledger/checkpoint-contract.d.ts.map +1 -1
- package/dist/ledger/checkpoint-contract.js +85 -1
- package/dist/ledger/checkpoint-contract.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +10 -49
- package/dist/mcp/server.js.map +1 -1
- package/dist/memory/checkpoint-contract.d.ts +490 -0
- package/dist/memory/checkpoint-contract.d.ts.map +1 -0
- package/dist/memory/checkpoint-contract.js +105 -0
- package/dist/memory/checkpoint-contract.js.map +1 -0
- package/dist/memory/scoped-memory.d.ts +9 -3
- package/dist/memory/scoped-memory.d.ts.map +1 -1
- package/dist/memory/scoped-memory.js +198 -109
- package/dist/memory/scoped-memory.js.map +1 -1
- package/dist/repository/detect-root.d.ts +1 -0
- package/dist/repository/detect-root.d.ts.map +1 -1
- package/dist/repository/detect-root.js +1 -1
- package/dist/repository/detect-root.js.map +1 -1
- package/dist/setup/render.d.ts.map +1 -1
- package/dist/setup/render.js +10 -9
- package/dist/setup/render.js.map +1 -1
- package/package.json +1 -1
- package/templates/AGENTS.md +4 -3
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { ENTRY_KINDS } from '../serialization/validate.js';
|
|
3
|
+
import { CHECKPOINT_OUTCOMES, CHECKPOINT_RUN_ID_DESCRIPTION, MAX_CHECKPOINT_FEEDBACK_ITEMS, MAX_CHECKPOINT_MEMORY_ITEMS, checkpointEvidenceSchema, checkpointFeedbackSchema, hasCheckpointEvidenceContent, } from '../ledger/checkpoint-contract.js';
|
|
4
|
+
const memoryKind = z.enum(ENTRY_KINDS);
|
|
5
|
+
const memoryClass = z.enum([
|
|
6
|
+
'implementation-pattern', 'troubleshooting', 'tool-usage', 'extension-usage',
|
|
7
|
+
'configuration', 'workflow', 'gotcha', 'reference', 'preference',
|
|
8
|
+
]);
|
|
9
|
+
const applicability = z.object({
|
|
10
|
+
languages: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
11
|
+
frameworks: z.array(z.object({
|
|
12
|
+
name: z.string().trim().min(1).max(500),
|
|
13
|
+
version: z.string().trim().min(1).max(100).optional(),
|
|
14
|
+
}).strict()).max(50).optional(),
|
|
15
|
+
databases: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
16
|
+
runtimes: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
17
|
+
tools: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
18
|
+
platforms: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
19
|
+
}).strict();
|
|
20
|
+
const signals = z.object({
|
|
21
|
+
symbols: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
22
|
+
paths: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
23
|
+
errors: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
24
|
+
packages: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
25
|
+
commands: z.array(z.string().trim().min(1).max(500)).max(100).optional(),
|
|
26
|
+
}).strict();
|
|
27
|
+
export const checkpointMemorySchema = z.object({
|
|
28
|
+
kind: memoryKind,
|
|
29
|
+
title: z.string().trim().min(1).max(300),
|
|
30
|
+
body: z.string().max(20_000),
|
|
31
|
+
summary: z.string().max(2000).optional(),
|
|
32
|
+
scope: z.enum(['project', 'global']).default('project'),
|
|
33
|
+
retrievalScope: z.enum(['project-only', 'ecosystem', 'global']).optional(),
|
|
34
|
+
tags: z.array(z.string().trim().min(1).max(200)).max(20).optional(),
|
|
35
|
+
confidence: z.number().min(0).max(1).default(0.7),
|
|
36
|
+
memoryClass: memoryClass.optional(),
|
|
37
|
+
applicability: applicability.optional(),
|
|
38
|
+
signals: signals.optional(),
|
|
39
|
+
portableReason: z.string().trim().min(1).max(2000).optional(),
|
|
40
|
+
}).strict();
|
|
41
|
+
const checkpointRunId = z.string().min(1).max(256).refine((value) => value.trim() === value && !/\p{Cc}/u.test(value), { message: 'runId must be a canonical bounded identity' }).describe(CHECKPOINT_RUN_ID_DESCRIPTION);
|
|
42
|
+
const checkpointDeliveryId = z.string().min(1).max(256).refine((value) => value.trim() === value && !/\p{Cc}/u.test(value), { message: 'deliveryId must be a canonical bounded identity' });
|
|
43
|
+
function hasCheckpointContent(value) {
|
|
44
|
+
return (value.memories?.length ?? 0) > 0
|
|
45
|
+
|| (value.feedback?.length ?? 0) > 0
|
|
46
|
+
|| hasCheckpointEvidenceContent(value.evidence);
|
|
47
|
+
}
|
|
48
|
+
function addIssue(context, path, message) {
|
|
49
|
+
context.addIssue({ code: 'custom', path, message });
|
|
50
|
+
}
|
|
51
|
+
function refineRunBoundCheckpoint(value, context) {
|
|
52
|
+
if (value.outcome === undefined)
|
|
53
|
+
addIssue(context, ['outcome'], 'outcome is required when runId is supplied');
|
|
54
|
+
if (!hasCheckpointContent(value))
|
|
55
|
+
addIssue(context, [], 'A run-bound checkpoint requires memory, feedback, or non-empty evidence');
|
|
56
|
+
if ((value.feedback?.length ?? 0) > 0 && value.deliveryId === undefined) {
|
|
57
|
+
addIssue(context, ['deliveryId'], 'deliveryId is required when feedback is supplied');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export const runBoundCheckpointSchema = z.object({
|
|
61
|
+
cwd: z.string().min(1).optional(),
|
|
62
|
+
runId: checkpointRunId,
|
|
63
|
+
deliveryId: checkpointDeliveryId.optional(),
|
|
64
|
+
outcome: z.enum(CHECKPOINT_OUTCOMES),
|
|
65
|
+
memories: z.array(checkpointMemorySchema).max(MAX_CHECKPOINT_MEMORY_ITEMS).optional(),
|
|
66
|
+
feedback: z.array(checkpointFeedbackSchema).max(MAX_CHECKPOINT_FEEDBACK_ITEMS).optional(),
|
|
67
|
+
evidence: checkpointEvidenceSchema.optional(),
|
|
68
|
+
}).strict().superRefine((value, context) => refineRunBoundCheckpoint(value, context));
|
|
69
|
+
export const standaloneMemoryCheckpointSchema = z.object({
|
|
70
|
+
cwd: z.string().min(1).optional(),
|
|
71
|
+
memories: z.array(checkpointMemorySchema).min(1).max(MAX_CHECKPOINT_MEMORY_ITEMS),
|
|
72
|
+
}).strict();
|
|
73
|
+
export const memoryCheckpointVariantsSchema = z.union([
|
|
74
|
+
runBoundCheckpointSchema,
|
|
75
|
+
standaloneMemoryCheckpointSchema,
|
|
76
|
+
]);
|
|
77
|
+
function refineCheckpointInput(value, context) {
|
|
78
|
+
if (value.runId !== undefined) {
|
|
79
|
+
refineRunBoundCheckpoint(value, context);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if ((value.memories?.length ?? 0) === 0)
|
|
83
|
+
addIssue(context, ['memories'], 'Without runId, at least one memory is required');
|
|
84
|
+
if (value.outcome !== undefined)
|
|
85
|
+
addIssue(context, ['outcome'], 'outcome is only valid for a run-bound checkpoint');
|
|
86
|
+
if (value.deliveryId !== undefined)
|
|
87
|
+
addIssue(context, ['deliveryId'], 'deliveryId requires runId');
|
|
88
|
+
if (value.feedback !== undefined)
|
|
89
|
+
addIssue(context, ['feedback'], 'feedback requires runId');
|
|
90
|
+
if (value.evidence !== undefined)
|
|
91
|
+
addIssue(context, ['evidence'], 'evidence requires runId');
|
|
92
|
+
}
|
|
93
|
+
// The MCP SDK only serializes object schemas in tools/list; a union would be
|
|
94
|
+
// advertised as an empty schema. This closed object retains the same runtime
|
|
95
|
+
// cross-field contract while keeping the public property schema visible.
|
|
96
|
+
export const memoryCheckpointInputSchema = z.object({
|
|
97
|
+
cwd: z.string().min(1).optional(),
|
|
98
|
+
memories: z.array(checkpointMemorySchema).max(MAX_CHECKPOINT_MEMORY_ITEMS).optional(),
|
|
99
|
+
runId: checkpointRunId.optional(),
|
|
100
|
+
deliveryId: checkpointDeliveryId.optional(),
|
|
101
|
+
outcome: z.enum(CHECKPOINT_OUTCOMES).optional(),
|
|
102
|
+
feedback: z.array(checkpointFeedbackSchema).max(MAX_CHECKPOINT_FEEDBACK_ITEMS).optional(),
|
|
103
|
+
evidence: checkpointEvidenceSchema.optional(),
|
|
104
|
+
}).strict().superRefine((value, context) => refineCheckpointInput(value, context));
|
|
105
|
+
//# sourceMappingURL=checkpoint-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint-contract.js","sourceRoot":"","sources":["../../src/memory/checkpoint-contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { type EntryKind } from '../serialization/validate.js';
|
|
|
5
5
|
import { type Applicability, type MemoryClass, type MemorySignals, type RetrievalScope } from './structured-memory.js';
|
|
6
6
|
import { type FederatedScope, type FederatedRecallResult } from './federated-retrieval.js';
|
|
7
7
|
import type { ProjectFingerprint } from '../repository/project-fingerprint.js';
|
|
8
|
+
import { type CheckpointOutcome } from '../ledger/checkpoint-contract.js';
|
|
8
9
|
interface GitProvenanceExecOptions {
|
|
9
10
|
cwd: string;
|
|
10
11
|
encoding: 'utf8';
|
|
@@ -42,15 +43,20 @@ export interface CheckpointMemory {
|
|
|
42
43
|
signals?: MemorySignals;
|
|
43
44
|
portableReason?: string;
|
|
44
45
|
}
|
|
45
|
-
export interface
|
|
46
|
+
export interface ScopedCheckpointStandaloneInput {
|
|
46
47
|
cwd?: string;
|
|
47
48
|
memories: CheckpointMemory[];
|
|
48
|
-
|
|
49
|
+
}
|
|
50
|
+
export interface ScopedCheckpointRunInput {
|
|
51
|
+
cwd?: string;
|
|
52
|
+
memories: CheckpointMemory[];
|
|
53
|
+
runId: string;
|
|
49
54
|
deliveryId?: string;
|
|
50
|
-
outcome
|
|
55
|
+
outcome: CheckpointOutcome;
|
|
51
56
|
feedback?: unknown[];
|
|
52
57
|
evidence?: unknown;
|
|
53
58
|
}
|
|
59
|
+
export type ScopedCheckpointInput = ScopedCheckpointStandaloneInput | ScopedCheckpointRunInput;
|
|
54
60
|
export interface ScopedCheckpointResult {
|
|
55
61
|
project: ResolvedProjectWorkspace | null;
|
|
56
62
|
entries: Array<Pick<EntryRecord, 'id' | 'workspace' | 'kind' | 'status' | 'title' | 'revision'>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scoped-memory.d.ts","sourceRoot":"","sources":["../../src/memory/scoped-memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAmD,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,EAKL,KAAK,wBAAwB,EAC9B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAkD,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACvK,OAAO,EAA2B,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAYpH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"scoped-memory.d.ts","sourceRoot":"","sources":["../../src/memory/scoped-memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAmD,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,EAKL,KAAK,wBAAwB,EAC9B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAkD,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACvK,OAAO,EAA2B,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAYpH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAgBL,KAAK,iBAAiB,EAGvB,MAAM,kCAAkC,CAAC;AAK1C,UAAU,wBAAwB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,KAAK,qBAAqB,GAAG,CAC3B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,wBAAwB,KAC9B,MAAM,CAAC;AAoBZ,iGAAiG;AACjG,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,qBAA4C,GACpD,MAAM,GAAG,IAAI,CAuBf;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC;AAEzC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,+BAA+B;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,qBAAqB,GAAG,+BAA+B,GAAG,wBAAwB,CAAC;AAE/F,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACzC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC;IACjG,GAAG,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,uBAAuB,EAAE,MAAM,CAAA;KAAE,CAAC;CAChJ;AAgQD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAWxH;AAED,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAkNpI"}
|
|
@@ -15,6 +15,7 @@ import { findSecret } from './secrets.js';
|
|
|
15
15
|
import { assertContextFeedbackRecordable, recordContextFeedbackInTransaction } from '../context/feedback.js';
|
|
16
16
|
import { readContextDelivery } from '../context/delivery.js';
|
|
17
17
|
import { recordKnowledgePathsInTransaction } from '../akinator/knowledge-path.js';
|
|
18
|
+
import { CHECKPOINT_COMMAND_FIELD_NAMES, CHECKPOINT_EVIDENCE_FIELD_NAMES, CHECKPOINT_FEEDBACK_FIELD_NAMES, CHECKPOINT_OUTCOMES, CHECKPOINT_RESULT_OUTCOMES, CHECKPOINT_TEST_FIELD_NAMES, CHECKPOINT_VERIFICATION_FIELD_NAMES, MAX_CHECKPOINT_EVIDENCE_ITEMS, MAX_CHECKPOINT_EXECUTABLE_CHARS, MAX_CHECKPOINT_PATHS, MAX_CHECKPOINT_SHORT_TEXT_CHARS, MAX_CHECKPOINT_SIGNALS, } from '../ledger/checkpoint-contract.js';
|
|
18
19
|
const GIT_PROVENANCE_TIMEOUT_MS = 5_000;
|
|
19
20
|
const GIT_PROVENANCE_MAX_BUFFER = 64 * 1024;
|
|
20
21
|
const executeGitProvenance = (executable, args, options) => execFileSync(executable, args, options);
|
|
@@ -67,8 +68,8 @@ const CHECKPOINT_MEMORY_FIELDS = new Set([
|
|
|
67
68
|
'kind', 'title', 'body', 'summary', 'scope', 'retrievalScope', 'tags', 'confidence',
|
|
68
69
|
'memoryClass', 'applicability', 'signals', 'portableReason',
|
|
69
70
|
]);
|
|
70
|
-
const
|
|
71
|
-
const
|
|
71
|
+
const CHECKPOINT_INPUT_FIELDS = new Set(['cwd', 'memories', 'runId', 'deliveryId', 'outcome', 'feedback', 'evidence']);
|
|
72
|
+
const CHECKPOINT_FEEDBACK_FIELDS = new Set(CHECKPOINT_FEEDBACK_FIELD_NAMES);
|
|
72
73
|
function assertCheckpointEligible(status) {
|
|
73
74
|
const eligibility = checkpointEligibility(status);
|
|
74
75
|
if (eligibility.allowed)
|
|
@@ -86,9 +87,12 @@ function checkpointObject(value, allowed, message) {
|
|
|
86
87
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
87
88
|
throw new KiokukoError('VALIDATION_ERROR', message);
|
|
88
89
|
}
|
|
90
|
+
const keys = Reflect.ownKeys(value);
|
|
91
|
+
if (keys.length > allowed.size)
|
|
92
|
+
throw new KiokukoError('VALIDATION_ERROR', message);
|
|
89
93
|
const result = Object.create(null);
|
|
90
94
|
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
91
|
-
for (const key of
|
|
95
|
+
for (const key of keys) {
|
|
92
96
|
if (typeof key !== 'string' || !allowed.has(key)) {
|
|
93
97
|
throw new KiokukoError('VALIDATION_ERROR', message);
|
|
94
98
|
}
|
|
@@ -107,87 +111,192 @@ function sameProject(left, right) {
|
|
|
107
111
|
&& left.repositoryId === right.repositoryId
|
|
108
112
|
&& left.workspace === right.workspace;
|
|
109
113
|
}
|
|
110
|
-
function
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
114
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Evidence is invalid');
|
|
115
|
-
let canonicalEvidence;
|
|
116
|
-
try {
|
|
117
|
-
canonicalEvidence = canonicalJson(raw);
|
|
114
|
+
function checkpointArray(value, maximum, message) {
|
|
115
|
+
if (!Array.isArray(value) || isProxy(value) || value.length > maximum) {
|
|
116
|
+
throw new KiokukoError('VALIDATION_ERROR', message);
|
|
118
117
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
const keys = Reflect.ownKeys(value);
|
|
119
|
+
if (keys.length !== value.length + 1 || !keys.includes('length') || keys.some((key) => typeof key !== 'string')) {
|
|
120
|
+
throw new KiokukoError('VALIDATION_ERROR', message);
|
|
121
|
+
}
|
|
122
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
123
|
+
const result = [];
|
|
124
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
125
|
+
const descriptor = descriptors[String(index)];
|
|
126
|
+
if (descriptor === undefined || !('value' in descriptor) || descriptor.enumerable !== true) {
|
|
127
|
+
throw new KiokukoError('VALIDATION_ERROR', message);
|
|
122
128
|
}
|
|
123
|
-
|
|
129
|
+
result.push(descriptor.value);
|
|
124
130
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
function boundedEvidence(raw) {
|
|
134
|
+
if (raw === undefined)
|
|
135
|
+
return { changedPaths: [], errorSignatures: [], commands: [], tests: [] };
|
|
136
|
+
const value = checkpointObject(raw, new Set(CHECKPOINT_EVIDENCE_FIELD_NAMES), 'Evidence is invalid');
|
|
137
|
+
const evidenceError = () => new KiokukoError('VALIDATION_ERROR', 'Evidence is invalid');
|
|
138
|
+
const pathError = () => new KiokukoError('VALIDATION_ERROR', 'Evidence path is invalid');
|
|
139
|
+
const strings = (candidate, maximum) => {
|
|
140
|
+
if (candidate === undefined)
|
|
132
141
|
return [];
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
const values = checkpointArray(candidate, maximum, 'Evidence is invalid');
|
|
143
|
+
return [...new Set(values.map((item) => {
|
|
144
|
+
if (typeof item !== 'string' || item.length === 0 || item.length > MAX_CHECKPOINT_SHORT_TEXT_CHARS || /[\u0000-\u001f\u007f]/u.test(item)) {
|
|
145
|
+
throw evidenceError();
|
|
146
|
+
}
|
|
147
|
+
return item;
|
|
148
|
+
}))];
|
|
136
149
|
};
|
|
137
|
-
const changedPaths = strings(value.changedPaths,
|
|
138
|
-
if (item.startsWith('/') || /^[A-Za-z]
|
|
139
|
-
throw
|
|
150
|
+
const changedPaths = strings(value.changedPaths, MAX_CHECKPOINT_PATHS).map((item) => {
|
|
151
|
+
if (item.startsWith('/') || item.startsWith('\\') || /^[A-Za-z]:/u.test(item) || item.split(/[\\/]/u).includes('..'))
|
|
152
|
+
throw pathError();
|
|
140
153
|
return item.replaceAll('\\', '/');
|
|
141
154
|
});
|
|
142
|
-
const errorSignatures = strings(value.errorSignatures,
|
|
155
|
+
const errorSignatures = strings(value.errorSignatures, MAX_CHECKPOINT_SIGNALS);
|
|
143
156
|
const normalizeItems = (items, kind) => {
|
|
144
157
|
if (items === undefined)
|
|
145
158
|
return [];
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const record = item;
|
|
152
|
-
const
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (typeof
|
|
159
|
-
throw
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
159
|
+
const values = checkpointArray(items, MAX_CHECKPOINT_EVIDENCE_ITEMS, 'Evidence is invalid');
|
|
160
|
+
const allowedFields = new Set(kind === 'command' ? CHECKPOINT_COMMAND_FIELD_NAMES : CHECKPOINT_TEST_FIELD_NAMES);
|
|
161
|
+
const optionalFields = kind === 'command' ? ['classification', 'digest'] : ['target', 'digest'];
|
|
162
|
+
const required = kind === 'command' ? 'executable' : 'runner';
|
|
163
|
+
return values.map((item) => {
|
|
164
|
+
const record = checkpointObject(item, allowedFields, 'Evidence is invalid');
|
|
165
|
+
const requiredValue = record[required];
|
|
166
|
+
if (typeof requiredValue !== 'string' || requiredValue.length === 0
|
|
167
|
+
|| requiredValue.length > MAX_CHECKPOINT_EXECUTABLE_CHARS
|
|
168
|
+
|| /[\u0000-\u001f\u007f]/u.test(requiredValue))
|
|
169
|
+
throw evidenceError();
|
|
170
|
+
const rawOutcome = record.outcome;
|
|
171
|
+
if (typeof rawOutcome !== 'string' || !CHECKPOINT_RESULT_OUTCOMES.includes(rawOutcome))
|
|
172
|
+
throw evidenceError();
|
|
173
|
+
const outcome = rawOutcome;
|
|
174
|
+
const optional = {};
|
|
175
|
+
for (const field of optionalFields) {
|
|
176
|
+
const optionalValue = record[field];
|
|
177
|
+
if (optionalValue === undefined)
|
|
178
|
+
continue;
|
|
179
|
+
if (typeof optionalValue !== 'string' || optionalValue.length === 0
|
|
180
|
+
|| optionalValue.length > MAX_CHECKPOINT_SHORT_TEXT_CHARS
|
|
181
|
+
|| /[\u0000-\u001f\u007f]/u.test(optionalValue))
|
|
182
|
+
throw evidenceError();
|
|
183
|
+
if (field === 'classification' || field === 'target' || field === 'digest')
|
|
184
|
+
optional[field] = optionalValue;
|
|
167
185
|
}
|
|
168
|
-
if (kind === 'command'
|
|
186
|
+
if (kind === 'command') {
|
|
169
187
|
const exitCode = record.exitCode;
|
|
170
|
-
if (typeof exitCode !== 'number' || !Number.isSafeInteger(exitCode) || exitCode < 0)
|
|
171
|
-
throw
|
|
172
|
-
|
|
188
|
+
if (exitCode !== undefined && (typeof exitCode !== 'number' || !Number.isSafeInteger(exitCode) || exitCode < 0))
|
|
189
|
+
throw evidenceError();
|
|
190
|
+
return {
|
|
191
|
+
executable: requiredValue,
|
|
192
|
+
outcome,
|
|
193
|
+
...(optional.classification === undefined ? {} : { classification: optional.classification }),
|
|
194
|
+
...(exitCode === undefined ? {} : { exitCode }),
|
|
195
|
+
...(optional.digest === undefined ? {} : { digest: optional.digest }),
|
|
196
|
+
};
|
|
173
197
|
}
|
|
174
|
-
return
|
|
198
|
+
return {
|
|
199
|
+
runner: requiredValue,
|
|
200
|
+
outcome,
|
|
201
|
+
...(optional.target === undefined ? {} : { target: optional.target }),
|
|
202
|
+
...(optional.digest === undefined ? {} : { digest: optional.digest }),
|
|
203
|
+
};
|
|
175
204
|
});
|
|
176
205
|
};
|
|
177
|
-
const verification = value.verification === undefined ? undefined : (() => {
|
|
178
|
-
if (typeof value.verification !== 'object' || value.verification === null || Array.isArray(value.verification))
|
|
179
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Evidence is invalid');
|
|
180
|
-
const verificationValue = value.verification;
|
|
181
|
-
if (Object.keys(verificationValue).some((field) => field !== 'outcome'))
|
|
182
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Evidence is invalid');
|
|
183
|
-
const outcome = verificationValue.outcome;
|
|
184
|
-
if (typeof outcome !== 'string' || !['fresh', 'stale', 'failed', 'unknown'].includes(outcome))
|
|
185
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Evidence is invalid');
|
|
186
|
-
return { outcome };
|
|
187
|
-
})();
|
|
188
206
|
const commands = normalizeItems(value.commands, 'command');
|
|
189
207
|
const tests = normalizeItems(value.tests, 'test');
|
|
190
|
-
|
|
208
|
+
const verification = value.verification === undefined ? undefined : (() => {
|
|
209
|
+
const verificationValue = checkpointObject(value.verification, new Set(CHECKPOINT_VERIFICATION_FIELD_NAMES), 'Evidence is invalid');
|
|
210
|
+
const rawOutcome = verificationValue.outcome;
|
|
211
|
+
if (typeof rawOutcome !== 'string' || !['fresh', 'stale', 'failed', 'unknown'].includes(rawOutcome))
|
|
212
|
+
throw evidenceError();
|
|
213
|
+
return { outcome: rawOutcome };
|
|
214
|
+
})();
|
|
215
|
+
const normalized = {
|
|
216
|
+
changedPaths,
|
|
217
|
+
errorSignatures,
|
|
218
|
+
commands,
|
|
219
|
+
tests,
|
|
220
|
+
...(verification === undefined ? {} : { verification }),
|
|
221
|
+
};
|
|
222
|
+
let canonicalEvidence;
|
|
223
|
+
try {
|
|
224
|
+
canonicalEvidence = canonicalJson(normalized);
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
if (error instanceof RangeError || (error instanceof KiokukoError && error.code === 'VALIDATION_ERROR')) {
|
|
228
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Evidence is invalid');
|
|
229
|
+
}
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
if (findSecret(canonicalEvidence))
|
|
233
|
+
throw new KiokukoError('SECURITY_REJECTION', 'Evidence resembles a secret and was not stored');
|
|
234
|
+
return normalized;
|
|
235
|
+
}
|
|
236
|
+
function checkpointIdentifier(value, label) {
|
|
237
|
+
if (value === undefined)
|
|
238
|
+
return undefined;
|
|
239
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > 256 || value.trim() !== value || /\p{Cc}/u.test(value)) {
|
|
240
|
+
throw new KiokukoError('VALIDATION_ERROR', `${label} is invalid`);
|
|
241
|
+
}
|
|
242
|
+
return value;
|
|
243
|
+
}
|
|
244
|
+
function normalizeCheckpointInput(input) {
|
|
245
|
+
const value = checkpointObject(input, CHECKPOINT_INPUT_FIELDS, 'Checkpoint input is invalid');
|
|
246
|
+
const cwd = value.cwd === undefined
|
|
247
|
+
? undefined
|
|
248
|
+
: typeof value.cwd === 'string' && value.cwd.length > 0 && !/\p{Cc}/u.test(value.cwd)
|
|
249
|
+
? value.cwd
|
|
250
|
+
: (() => { throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint cwd is invalid'); })();
|
|
251
|
+
const memoryValues = value.memories === undefined
|
|
252
|
+
? []
|
|
253
|
+
: checkpointArray(value.memories, 20, 'Checkpoint memories must be an array');
|
|
254
|
+
const memories = memoryValues.map((memory) => checkpointObject(memory, CHECKPOINT_MEMORY_FIELDS, 'Checkpoint memory is invalid'));
|
|
255
|
+
const feedbackValues = value.feedback === undefined
|
|
256
|
+
? []
|
|
257
|
+
: checkpointArray(value.feedback, 100, 'Checkpoint feedback is invalid');
|
|
258
|
+
const feedback = feedbackValues.map((item) => checkpointObject(item, CHECKPOINT_FEEDBACK_FIELDS, 'Checkpoint feedback is invalid'));
|
|
259
|
+
const evidence = boundedEvidence(value.evidence);
|
|
260
|
+
const runId = checkpointIdentifier(value.runId, 'Checkpoint runId');
|
|
261
|
+
const deliveryId = checkpointIdentifier(value.deliveryId, 'Checkpoint deliveryId');
|
|
262
|
+
const rawOutcome = value.outcome;
|
|
263
|
+
if (runId === undefined) {
|
|
264
|
+
if (memories.length === 0)
|
|
265
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Without runId, at least one memory is required');
|
|
266
|
+
if (rawOutcome !== undefined)
|
|
267
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint outcome requires runId');
|
|
268
|
+
if (deliveryId !== undefined)
|
|
269
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint deliveryId requires runId');
|
|
270
|
+
if (value.feedback !== undefined)
|
|
271
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint feedback requires runId');
|
|
272
|
+
if (value.evidence !== undefined)
|
|
273
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint evidence requires runId');
|
|
274
|
+
return { ...(cwd === undefined ? {} : { cwd }), memories };
|
|
275
|
+
}
|
|
276
|
+
if (typeof rawOutcome !== 'string' || !CHECKPOINT_OUTCOMES.includes(rawOutcome)) {
|
|
277
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint outcome is required and invalid');
|
|
278
|
+
}
|
|
279
|
+
const outcome = rawOutcome;
|
|
280
|
+
const hasEvidence = evidence.changedPaths.length > 0
|
|
281
|
+
|| evidence.errorSignatures.length > 0
|
|
282
|
+
|| evidence.commands.length > 0
|
|
283
|
+
|| evidence.tests.length > 0
|
|
284
|
+
|| evidence.verification !== undefined;
|
|
285
|
+
if (memories.length === 0 && feedback.length === 0 && !hasEvidence) {
|
|
286
|
+
throw new KiokukoError('VALIDATION_ERROR', 'An empty checkpoint is not allowed');
|
|
287
|
+
}
|
|
288
|
+
if (feedback.length > 0 && deliveryId === undefined) {
|
|
289
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint feedback requires deliveryId');
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
...(cwd === undefined ? {} : { cwd }),
|
|
293
|
+
memories,
|
|
294
|
+
runId,
|
|
295
|
+
...(deliveryId === undefined ? {} : { deliveryId }),
|
|
296
|
+
outcome,
|
|
297
|
+
feedback,
|
|
298
|
+
evidence,
|
|
299
|
+
};
|
|
191
300
|
}
|
|
192
301
|
export async function recallScopedMemory(database, input) {
|
|
193
302
|
return retrieveFederatedMemory(database, {
|
|
@@ -202,49 +311,27 @@ export async function recallScopedMemory(database, input) {
|
|
|
202
311
|
});
|
|
203
312
|
}
|
|
204
313
|
export async function checkpointScopedMemory(database, input) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (input.outcome !== undefined && !CHECKPOINT_OUTCOMES.has(input.outcome)) {
|
|
217
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint outcome is invalid');
|
|
218
|
-
}
|
|
219
|
-
if (input.deliveryId !== undefined && input.runId === undefined) {
|
|
220
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint deliveryId requires runId');
|
|
221
|
-
}
|
|
222
|
-
if (input.runId === undefined && feedback.length > 0) {
|
|
223
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint feedback requires runId');
|
|
224
|
-
}
|
|
225
|
-
if (feedback.length > 0 && input.deliveryId === undefined) {
|
|
226
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint feedback requires deliveryId');
|
|
227
|
-
}
|
|
228
|
-
const evidence = boundedEvidence(input.evidence);
|
|
229
|
-
const hasEvidence = evidence.changedPaths.length > 0 || evidence.errorSignatures.length > 0 || evidence.commands.length > 0 || evidence.tests.length > 0 || evidence.verification !== undefined;
|
|
230
|
-
if (input.runId === undefined && hasEvidence) {
|
|
231
|
-
throw new KiokukoError('VALIDATION_ERROR', 'Checkpoint evidence requires runId');
|
|
232
|
-
}
|
|
233
|
-
const run = input.runId === undefined ? undefined : new LedgerStore(database).readRun(input.runId);
|
|
234
|
-
if (input.runId !== undefined && run === undefined)
|
|
314
|
+
const request = normalizeCheckpointInput(input);
|
|
315
|
+
const runId = 'runId' in request ? request.runId : undefined;
|
|
316
|
+
const deliveryId = 'runId' in request ? request.deliveryId : undefined;
|
|
317
|
+
const outcome = 'runId' in request ? request.outcome : undefined;
|
|
318
|
+
const feedback = 'runId' in request ? request.feedback : [];
|
|
319
|
+
const evidence = 'runId' in request
|
|
320
|
+
? request.evidence
|
|
321
|
+
: { changedPaths: [], errorSignatures: [], commands: [], tests: [] };
|
|
322
|
+
const memories = request.memories;
|
|
323
|
+
const run = runId === undefined ? undefined : new LedgerStore(database).readRun(runId);
|
|
324
|
+
if (runId !== undefined && run === undefined)
|
|
235
325
|
throw new KiokukoError('NOT_FOUND', 'Checkpoint run was not found');
|
|
236
326
|
if (run !== undefined)
|
|
237
327
|
assertCheckpointEligible(run.status);
|
|
238
|
-
if (
|
|
239
|
-
const delivery = readContextDelivery(database, { workspace: run.workspace, deliveryId
|
|
328
|
+
if (deliveryId !== undefined) {
|
|
329
|
+
const delivery = readContextDelivery(database, { workspace: run.workspace, deliveryId });
|
|
240
330
|
if (delivery.runId !== run.runId)
|
|
241
331
|
throw new KiokukoError('NOT_FOUND', 'Checkpoint delivery was not found for this run');
|
|
242
332
|
}
|
|
243
|
-
if (memories.length === 0 && feedback.length === 0 && !hasEvidence) {
|
|
244
|
-
throw new KiokukoError('VALIDATION_ERROR', 'An empty checkpoint is not allowed');
|
|
245
|
-
}
|
|
246
333
|
const needsProject = memories.some((memory) => (memory.scope ?? 'project') === 'project');
|
|
247
|
-
const plannedProject = await resolveProjectWorkspaceReadOnly(database,
|
|
334
|
+
const plannedProject = await resolveProjectWorkspaceReadOnly(database, request.cwd);
|
|
248
335
|
if (needsProject && !plannedProject) {
|
|
249
336
|
throw new KiokukoError('NOT_FOUND', 'No Git repository or .kiokuko.json binding was found for project-scoped memory; use scope "global" only for cross-project preferences or lessons');
|
|
250
337
|
}
|
|
@@ -325,7 +412,7 @@ export async function checkpointScopedMemory(database, input) {
|
|
|
325
412
|
...(plannedProject === undefined ? {} : { sourceRepositoryId: plannedProject.repositoryId, sourceWorkspace: plannedProject.workspace }),
|
|
326
413
|
...(sourceCommit === null ? {} : { sourceCommit }),
|
|
327
414
|
...(run === undefined ? {} : { runId: run.runId }),
|
|
328
|
-
...(
|
|
415
|
+
...(deliveryId === undefined ? {} : { deliveryId }),
|
|
329
416
|
...(evidenceIds.length === 0 ? {} : { evidenceIds }),
|
|
330
417
|
...(evidence.changedPaths.length === 0 ? {} : { sourcePaths: evidence.changedPaths }),
|
|
331
418
|
clientKind: 'mcp',
|
|
@@ -336,7 +423,7 @@ export async function checkpointScopedMemory(database, input) {
|
|
|
336
423
|
const preparedFeedback = feedback.map((value, index) => {
|
|
337
424
|
const record = {
|
|
338
425
|
workspace: run.workspace,
|
|
339
|
-
deliveryId:
|
|
426
|
+
deliveryId: deliveryId,
|
|
340
427
|
entryId: value.entryId,
|
|
341
428
|
entryRevision: value.entryRevision,
|
|
342
429
|
verdict: value.verdict,
|
|
@@ -350,7 +437,7 @@ export async function checkpointScopedMemory(database, input) {
|
|
|
350
437
|
assertContextFeedbackRecordable(database, record);
|
|
351
438
|
return record;
|
|
352
439
|
});
|
|
353
|
-
const project = await resolveProjectWorkspace(database,
|
|
440
|
+
const project = await resolveProjectWorkspace(database, request.cwd);
|
|
354
441
|
if (!sameProject(plannedProject, project)) {
|
|
355
442
|
throw new KiokukoError('CONFLICT', 'Checkpoint project identity changed after validation');
|
|
356
443
|
}
|
|
@@ -394,8 +481,10 @@ export async function checkpointScopedMemory(database, input) {
|
|
|
394
481
|
const memoryAck = transactionRun === undefined || memoryEvents.length === 0 ? { eventIds: [] } : store.appendBatchInTransaction(transactionRun.runId, { events: memoryEvents });
|
|
395
482
|
const eventId = evidenceAck.eventIds[0] ?? memoryAck.eventIds[0] ?? null;
|
|
396
483
|
if (transactionRun !== undefined) {
|
|
484
|
+
if (outcome === undefined)
|
|
485
|
+
throw new KiokukoError('INTEGRITY_ERROR', 'Run-bound checkpoint outcome is missing');
|
|
397
486
|
for (const entry of saved) {
|
|
398
|
-
database.prepare('INSERT INTO ledger_memory_links (link_id, run_id, event_id, delivery_id, entry_id, created_at) VALUES (?, ?, ?, ?, ?, ?)').run(randomUUID(), transactionRun.runId, eventId,
|
|
487
|
+
database.prepare('INSERT INTO ledger_memory_links (link_id, run_id, event_id, delivery_id, entry_id, created_at) VALUES (?, ?, ?, ?, ?, ?)').run(randomUUID(), transactionRun.runId, eventId, deliveryId ?? null, entry.id, now);
|
|
399
488
|
}
|
|
400
489
|
for (const feedbackRecord of preparedFeedback) {
|
|
401
490
|
recordContextFeedbackInTransaction(database, feedbackRecord);
|
|
@@ -404,7 +493,7 @@ export async function checkpointScopedMemory(database, input) {
|
|
|
404
493
|
runId: transactionRun.runId,
|
|
405
494
|
workspace: transactionRun.workspace,
|
|
406
495
|
entries: saved,
|
|
407
|
-
outcome
|
|
496
|
+
outcome,
|
|
408
497
|
verification: {
|
|
409
498
|
fresh: evidence.verification?.outcome === 'fresh',
|
|
410
499
|
passedTests: evidence.tests.filter((test) => test.outcome === 'passed').length,
|
|
@@ -413,7 +502,7 @@ export async function checkpointScopedMemory(database, input) {
|
|
|
413
502
|
},
|
|
414
503
|
createdAt: now,
|
|
415
504
|
});
|
|
416
|
-
const updated = new LedgerStore(database).updateRunStatusInTransaction(transactionRun.runId,
|
|
505
|
+
const updated = new LedgerStore(database).updateRunStatusInTransaction(transactionRun.runId, outcome, now);
|
|
417
506
|
return {
|
|
418
507
|
saved,
|
|
419
508
|
run: {
|