@corenel/harness 0.1.0 → 0.3.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.
- package/dist/acp/agentMap.d.ts +34 -0
- package/dist/acp/agentMap.d.ts.map +1 -0
- package/dist/acp/agentMap.js +110 -0
- package/dist/acp/agentMap.js.map +1 -0
- package/dist/acp/index.d.ts +4 -0
- package/dist/acp/index.d.ts.map +1 -0
- package/dist/acp/index.js +6 -0
- package/dist/acp/index.js.map +1 -0
- package/dist/acp/policyMap.d.ts +55 -0
- package/dist/acp/policyMap.d.ts.map +1 -0
- package/dist/acp/policyMap.js +121 -0
- package/dist/acp/policyMap.js.map +1 -0
- package/dist/acp/types.d.ts +41 -0
- package/dist/acp/types.d.ts.map +1 -0
- package/dist/acp/types.js +14 -0
- package/dist/acp/types.js.map +1 -0
- package/dist/api/backend.d.ts +39 -0
- package/dist/api/backend.d.ts.map +1 -0
- package/dist/api/backend.js +126 -0
- package/dist/api/backend.js.map +1 -0
- package/dist/api/client.d.ts +95 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +212 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/fileMirrorSource.d.ts +24 -0
- package/dist/api/fileMirrorSource.d.ts.map +1 -0
- package/dist/api/fileMirrorSource.js +59 -0
- package/dist/api/fileMirrorSource.js.map +1 -0
- package/dist/api/mirror.d.ts +102 -0
- package/dist/api/mirror.d.ts.map +1 -0
- package/dist/api/mirror.js +204 -0
- package/dist/api/mirror.js.map +1 -0
- package/dist/api/mirrorScheduler.d.ts +56 -0
- package/dist/api/mirrorScheduler.d.ts.map +1 -0
- package/dist/api/mirrorScheduler.js +167 -0
- package/dist/api/mirrorScheduler.js.map +1 -0
- package/dist/conversation.d.ts +0 -11
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +1 -24
- package/dist/conversation.js.map +1 -1
- package/dist/core/budget.d.ts +40 -0
- package/dist/core/budget.d.ts.map +1 -0
- package/dist/core/budget.js +62 -0
- package/dist/core/budget.js.map +1 -0
- package/dist/core/loop.d.ts +11 -0
- package/dist/core/loop.d.ts.map +1 -1
- package/dist/core/loop.js +89 -20
- package/dist/core/loop.js.map +1 -1
- package/dist/core/pricing.d.ts +8 -0
- package/dist/core/pricing.d.ts.map +1 -0
- package/dist/core/pricing.js +12 -0
- package/dist/core/pricing.js.map +1 -0
- package/dist/core/recovery.d.ts +60 -0
- package/dist/core/recovery.d.ts.map +1 -0
- package/dist/core/recovery.js +128 -0
- package/dist/core/recovery.js.map +1 -0
- package/dist/guardrail/builtins.js +6 -6
- package/dist/guardrail/builtins.js.map +1 -1
- package/dist/guardrail/permission-service.js +1 -1
- package/dist/guardrail/permission-service.js.map +1 -1
- package/dist/guardrail/serialize.d.ts.map +1 -1
- package/dist/guardrail/serialize.js +6 -0
- package/dist/guardrail/serialize.js.map +1 -1
- package/dist/guardrail/validate.d.ts.map +1 -1
- package/dist/guardrail/validate.js +13 -0
- package/dist/guardrail/validate.js.map +1 -1
- package/dist/install/lockfile.d.ts +79 -0
- package/dist/install/lockfile.d.ts.map +1 -0
- package/dist/install/lockfile.js +155 -0
- package/dist/install/lockfile.js.map +1 -0
- package/dist/install/store.d.ts +13 -0
- package/dist/install/store.d.ts.map +1 -0
- package/dist/install/store.js +38 -0
- package/dist/install/store.js.map +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +6 -1
- package/dist/log.js.map +1 -1
- package/dist/prompts/host.d.ts +4 -0
- package/dist/prompts/host.d.ts.map +1 -1
- package/dist/prompts/host.js.map +1 -1
- package/dist/prompts/index.d.ts +6 -0
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +16 -6
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/library/defaults.generated.d.ts.map +1 -1
- package/dist/prompts/library/defaults.generated.js +22 -4
- package/dist/prompts/library/defaults.generated.js.map +1 -1
- package/dist/prompts/toolsMarker.d.ts +13 -0
- package/dist/prompts/toolsMarker.d.ts.map +1 -0
- package/dist/prompts/toolsMarker.js +21 -0
- package/dist/prompts/toolsMarker.js.map +1 -0
- package/dist/providers/gateway.d.ts +19 -1
- package/dist/providers/gateway.d.ts.map +1 -1
- package/dist/providers/gateway.js +33 -4
- package/dist/providers/gateway.js.map +1 -1
- package/dist/services.d.ts +13 -0
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +2 -0
- package/dist/services.js.map +1 -1
- package/dist/sessions/apiLeaseStore.d.ts +10 -0
- package/dist/sessions/apiLeaseStore.d.ts.map +1 -0
- package/dist/sessions/apiLeaseStore.js +41 -0
- package/dist/sessions/apiLeaseStore.js.map +1 -0
- package/dist/sessions/fileRecallStore.d.ts +33 -0
- package/dist/sessions/fileRecallStore.d.ts.map +1 -0
- package/dist/sessions/fileRecallStore.js +112 -0
- package/dist/sessions/fileRecallStore.js.map +1 -0
- package/dist/sessions/fileSessionStore.d.ts +20 -0
- package/dist/sessions/fileSessionStore.d.ts.map +1 -0
- package/dist/sessions/fileSessionStore.js +151 -0
- package/dist/sessions/fileSessionStore.js.map +1 -0
- package/dist/sessions/head.d.ts +90 -0
- package/dist/sessions/head.d.ts.map +1 -0
- package/dist/sessions/head.js +82 -0
- package/dist/sessions/head.js.map +1 -0
- package/dist/sessions/inflight.d.ts +58 -0
- package/dist/sessions/inflight.d.ts.map +1 -0
- package/dist/sessions/inflight.js +0 -0
- package/dist/sessions/inflight.js.map +1 -0
- package/dist/sessions/jsonl.d.ts +23 -0
- package/dist/sessions/jsonl.d.ts.map +1 -0
- package/dist/sessions/jsonl.js +52 -0
- package/dist/sessions/jsonl.js.map +1 -0
- package/dist/sessions/lease.d.ts +59 -0
- package/dist/sessions/lease.d.ts.map +1 -0
- package/dist/sessions/lease.js +115 -0
- package/dist/sessions/lease.js.map +1 -0
- package/dist/sessions/leaseStore.d.ts +46 -0
- package/dist/sessions/leaseStore.d.ts.map +1 -0
- package/dist/sessions/leaseStore.js +58 -0
- package/dist/sessions/leaseStore.js.map +1 -0
- package/dist/sessions/testFs.d.ts +5 -0
- package/dist/sessions/testFs.d.ts.map +1 -0
- package/dist/sessions/testFs.js +85 -0
- package/dist/sessions/testFs.js.map +1 -0
- package/dist/sessions/timeline.d.ts +134 -0
- package/dist/sessions/timeline.d.ts.map +1 -0
- package/dist/sessions/timeline.js +127 -0
- package/dist/sessions/timeline.js.map +1 -0
- package/dist/sidecar/host.d.ts +284 -2
- package/dist/sidecar/host.d.ts.map +1 -1
- package/dist/sidecar/host.js +725 -1
- package/dist/sidecar/host.js.map +1 -1
- package/dist/sidecar/server.d.ts +217 -2
- package/dist/sidecar/server.d.ts.map +1 -1
- package/dist/sidecar/server.js +828 -3
- package/dist/sidecar/server.js.map +1 -1
- package/dist/skills.d.ts +8 -3
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +71 -35
- package/dist/skills.js.map +1 -1
- package/dist/snapshot/effects.d.ts +69 -0
- package/dist/snapshot/effects.d.ts.map +1 -0
- package/dist/snapshot/effects.js +67 -0
- package/dist/snapshot/effects.js.map +1 -0
- package/dist/snapshot/manifest.d.ts +73 -0
- package/dist/snapshot/manifest.d.ts.map +1 -0
- package/dist/snapshot/manifest.js +141 -0
- package/dist/snapshot/manifest.js.map +1 -0
- package/dist/snapshot/tree.d.ts +62 -0
- package/dist/snapshot/tree.d.ts.map +1 -0
- package/dist/snapshot/tree.js +147 -0
- package/dist/snapshot/tree.js.map +1 -0
- package/dist/tools/builtins.d.ts +1 -0
- package/dist/tools/builtins.d.ts.map +1 -1
- package/dist/tools/builtins.js +150 -5
- package/dist/tools/builtins.js.map +1 -1
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +13 -0
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/http.d.ts.map +1 -1
- package/dist/tools/http.js.map +1 -1
- package/dist/tools/namespaces.d.ts +1 -1
- package/dist/tools/namespaces.d.ts.map +1 -1
- package/dist/tools/namespaces.js +24 -0
- package/dist/tools/namespaces.js.map +1 -1
- package/dist/tools/todo.d.ts.map +1 -1
- package/dist/tools/todo.js +12 -0
- package/dist/tools/todo.js.map +1 -1
- package/package.json +26 -34
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { sessionsRoot, flattenFiles } from '@corenel/protocol';
|
|
2
|
+
import { PREVIEW_BYTES } from '../compression';
|
|
3
|
+
/** Reserved pseudo-session for offloads produced outside any chat session
|
|
4
|
+
* (DAG node runs, the editor's prompt Run). */
|
|
5
|
+
export const UNATTACHED_SESSION = '_unattached';
|
|
6
|
+
/** Blob ids are model-supplied on read — accept only our own shape. */
|
|
7
|
+
const SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
8
|
+
function safeJson(v) {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.stringify(v);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return String(v);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class FileRecallStore {
|
|
17
|
+
constructor(getFiles, getSessionId = () => UNATTACHED_SESSION, root = sessionsRoot) {
|
|
18
|
+
Object.defineProperty(this, "getFiles", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: getFiles
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(this, "getSessionId", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
configurable: true,
|
|
27
|
+
writable: true,
|
|
28
|
+
value: getSessionId
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(this, "root", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
configurable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
value: root
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(this, "counter", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: true,
|
|
39
|
+
writable: true,
|
|
40
|
+
value: 0
|
|
41
|
+
});
|
|
42
|
+
Object.defineProperty(this, "prefix", {
|
|
43
|
+
enumerable: true,
|
|
44
|
+
configurable: true,
|
|
45
|
+
writable: true,
|
|
46
|
+
value: Math.random().toString(36).slice(2, 7)
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async files() {
|
|
50
|
+
const f = await this.getFiles();
|
|
51
|
+
if (!f)
|
|
52
|
+
throw new Error('No file workspace is connected — offload storage is unavailable.');
|
|
53
|
+
return f;
|
|
54
|
+
}
|
|
55
|
+
blobPath(id) {
|
|
56
|
+
return `${this.root()}/${this.getSessionId()}/blobs/${id}.json`;
|
|
57
|
+
}
|
|
58
|
+
async record(toolName, content) {
|
|
59
|
+
const text = typeof content === 'string' ? content : safeJson(content);
|
|
60
|
+
const id = `blob-${this.prefix}-${++this.counter}`;
|
|
61
|
+
const rec = { id, toolName, bytes: text.length, content: text, createdAt: Date.now() };
|
|
62
|
+
await (await this.files()).write(this.blobPath(id), JSON.stringify(rec));
|
|
63
|
+
return { id, toolName, bytes: text.length, preview: text.slice(0, PREVIEW_BYTES) };
|
|
64
|
+
}
|
|
65
|
+
async read(id) {
|
|
66
|
+
if (!SAFE_ID.test(id))
|
|
67
|
+
return null;
|
|
68
|
+
const text = await (await this.files()).read(this.blobPath(id)).catch(() => null);
|
|
69
|
+
if (text == null)
|
|
70
|
+
return null;
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(text).content;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** All blobs for a session, newest first (for the context drawer). */
|
|
80
|
+
export async function listSessionBlobs(files, sessionId, root = sessionsRoot()) {
|
|
81
|
+
const blobsDir = `${root}/${sessionId}/blobs`;
|
|
82
|
+
// Same caveat as JsonlSessionStore.list: some backends return a workspace-
|
|
83
|
+
// rooted tree with the ancestor chain at the top level — flatten and match
|
|
84
|
+
// the blob files by path instead of trusting the top-level nodes.
|
|
85
|
+
const nodes = await files.list(blobsDir).catch(() => []);
|
|
86
|
+
const blobFiles = flattenFiles(nodes).filter((f) => f.path.startsWith(blobsDir + '/') && f.path.endsWith('.json'));
|
|
87
|
+
const out = [];
|
|
88
|
+
for (const n of blobFiles) {
|
|
89
|
+
const text = await files.read(n.path).catch(() => null);
|
|
90
|
+
if (text == null)
|
|
91
|
+
continue;
|
|
92
|
+
try {
|
|
93
|
+
out.push(JSON.parse(text));
|
|
94
|
+
}
|
|
95
|
+
catch { /* skip corrupt */ }
|
|
96
|
+
}
|
|
97
|
+
return out.sort((a, b) => b.createdAt - a.createdAt);
|
|
98
|
+
}
|
|
99
|
+
/** Drop a session's offloaded blobs (housekeeping). */
|
|
100
|
+
export async function clearSessionBlobs(files, sessionId, root = sessionsRoot()) {
|
|
101
|
+
await files.remove(`${root}/${sessionId}/blobs`).catch(() => { });
|
|
102
|
+
}
|
|
103
|
+
/** Delete one offloaded blob (the drawer's Restore removes the record after
|
|
104
|
+
* re-injecting its content). The id is validated against SAFE_ID — it arrives
|
|
105
|
+
* from the UI, but the same no-traversal defense as read() applies. Invalid
|
|
106
|
+
* ids and missing files are silent no-ops. */
|
|
107
|
+
export async function removeSessionBlob(files, sessionId, id, root = sessionsRoot()) {
|
|
108
|
+
if (!SAFE_ID.test(id))
|
|
109
|
+
return;
|
|
110
|
+
await files.remove(`${root}/${sessionId}/blobs/${id}.json`).catch(() => { });
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=fileRecallStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileRecallStore.js","sourceRoot":"","sources":["../../sessions/fileRecallStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AgentSession, FileService, ISessionStore, SessionSurface } from '@corenel/protocol';
|
|
2
|
+
export declare class JsonlSessionStore implements ISessionStore {
|
|
3
|
+
private getFiles;
|
|
4
|
+
private root;
|
|
5
|
+
private cursors;
|
|
6
|
+
constructor(getFiles: () => FileService | null | Promise<FileService | null>, root?: () => string);
|
|
7
|
+
private files;
|
|
8
|
+
private path;
|
|
9
|
+
create(title: string, surface?: SessionSurface): Promise<AgentSession>;
|
|
10
|
+
get(id: string): Promise<AgentSession | null>;
|
|
11
|
+
list(surface?: SessionSurface): Promise<AgentSession[]>;
|
|
12
|
+
save(session: AgentSession): Promise<void>;
|
|
13
|
+
/** Cursor for a session this instance hasn't touched (e.g. saved after a
|
|
14
|
+
* reload): fold the existing file, or start a fresh log from the session's
|
|
15
|
+
* own meta. */
|
|
16
|
+
private seed;
|
|
17
|
+
rename(id: string, title: string): Promise<void>;
|
|
18
|
+
delete(id: string): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=fileSessionStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileSessionStore.d.ts","sourceRoot":"","sources":["../../sessions/fileSessionStore.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA4BlG,qBAAa,iBAAkB,YAAW,aAAa;IAInD,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,IAAI;IAJd,OAAO,CAAC,OAAO,CAA6B;gBAGlC,QAAQ,EAAE,MAAM,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,EAChE,IAAI,GAAE,MAAM,MAAqB;YAG7B,KAAK;IAMnB,OAAO,CAAC,IAAI;IAIN,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC;IAUtE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAe7C,IAAI,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAmBvD,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BhD;;mBAEe;YACD,IAAI;IAeZ,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYhD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIxC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { sessionsRoot, flattenFiles } from '@corenel/protocol';
|
|
2
|
+
import { encodeLine, foldSession } from './jsonl';
|
|
3
|
+
function uid(prefix) {
|
|
4
|
+
return `${prefix}_${Date.now().toString(36)}${Math.floor(Math.random() * 1e6).toString(36)}`;
|
|
5
|
+
}
|
|
6
|
+
/** Strictly-increasing millisecond clock. Plain `Date.now()` ties under fast
|
|
7
|
+
* synchronous calls (e.g. back-to-back create()/save() in the same tick),
|
|
8
|
+
* which would make updatedAt-desc ordering ambiguous. Bumping by 1ms on a tie
|
|
9
|
+
* keeps createdAt/updatedAt monotonic without changing the stored shape. */
|
|
10
|
+
let lastTs = 0;
|
|
11
|
+
function now() {
|
|
12
|
+
const t = Date.now();
|
|
13
|
+
lastTs = t > lastTs ? t : lastTs + 1;
|
|
14
|
+
return lastTs;
|
|
15
|
+
}
|
|
16
|
+
export class JsonlSessionStore {
|
|
17
|
+
constructor(getFiles, root = sessionsRoot) {
|
|
18
|
+
Object.defineProperty(this, "getFiles", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
value: getFiles
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(this, "root", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
configurable: true,
|
|
27
|
+
writable: true,
|
|
28
|
+
value: root
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(this, "cursors", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
configurable: true,
|
|
33
|
+
writable: true,
|
|
34
|
+
value: new Map()
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async files() {
|
|
38
|
+
const f = await this.getFiles();
|
|
39
|
+
if (!f)
|
|
40
|
+
throw new Error('No file workspace is connected — sessions are unavailable.');
|
|
41
|
+
return f;
|
|
42
|
+
}
|
|
43
|
+
path(id) {
|
|
44
|
+
return `${this.root()}/${id}/SESSION.jsonl`;
|
|
45
|
+
}
|
|
46
|
+
async create(title, surface) {
|
|
47
|
+
const createdAt = now();
|
|
48
|
+
const id = uid('ses');
|
|
49
|
+
const meta = { k: 'meta', id, title, createdAt, ...(surface ? { surface } : {}) };
|
|
50
|
+
const text = encodeLine(meta);
|
|
51
|
+
await (await this.files()).write(this.path(id), text);
|
|
52
|
+
this.cursors.set(id, { text, turnJson: [], title });
|
|
53
|
+
return { id, title, createdAt, updatedAt: createdAt, messages: [], ...(surface ? { surface } : {}) };
|
|
54
|
+
}
|
|
55
|
+
async get(id) {
|
|
56
|
+
const text = await (await this.files()).read(this.path(id)).catch(() => null);
|
|
57
|
+
if (text == null)
|
|
58
|
+
return null;
|
|
59
|
+
const ses = foldSession(text);
|
|
60
|
+
if (ses) {
|
|
61
|
+
this.cursors.set(id, {
|
|
62
|
+
text,
|
|
63
|
+
turnJson: ses.messages.map((m) => JSON.stringify(m)),
|
|
64
|
+
title: ses.title,
|
|
65
|
+
titleLocked: ses.titleLocked,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return ses;
|
|
69
|
+
}
|
|
70
|
+
async list(surface) {
|
|
71
|
+
const files = await this.files();
|
|
72
|
+
const root = this.root();
|
|
73
|
+
// list(dir) shape differs per backend: MemoryFileService returns a tree
|
|
74
|
+
// rooted at the WORKSPACE root (the top level is the ancestor chain, e.g.
|
|
75
|
+
// ['.prompd']), while others return dir's children. Never trust the top
|
|
76
|
+
// level — flatten and match the SESSION.jsonl files by path.
|
|
77
|
+
const nodes = await files.list(root).catch(() => []);
|
|
78
|
+
const sessionFiles = flattenFiles(nodes).filter((f) => f.name === 'SESSION.jsonl' && f.path.startsWith(root + '/'));
|
|
79
|
+
const out = [];
|
|
80
|
+
for (const f of sessionFiles) {
|
|
81
|
+
const text = await files.read(f.path).catch(() => null);
|
|
82
|
+
const ses = text != null ? foldSession(text) : null;
|
|
83
|
+
if (ses)
|
|
84
|
+
out.push(ses);
|
|
85
|
+
}
|
|
86
|
+
const scoped = surface ? out.filter((s) => s.surface === surface || (surface === 'agent' && !s.surface)) : out;
|
|
87
|
+
return scoped.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
88
|
+
}
|
|
89
|
+
async save(session) {
|
|
90
|
+
// Compute the timestamp candidate up front but don't touch `session` until we
|
|
91
|
+
// know something actually changed — a no-op save must not mutate the caller's
|
|
92
|
+
// object (it should be indistinguishable from not having called save() at all).
|
|
93
|
+
const at = now();
|
|
94
|
+
const cur = this.cursors.get(session.id) ?? (await this.seed(session));
|
|
95
|
+
const turnJson = session.messages.map((m) => JSON.stringify(m));
|
|
96
|
+
const appended = [];
|
|
97
|
+
for (let i = 0; i < turnJson.length; i++) {
|
|
98
|
+
if (cur.turnJson[i] !== turnJson[i]) {
|
|
99
|
+
appended.push(encodeLine({ k: 'turn', i, at, m: session.messages[i] }));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (session.title !== cur.title || session.titleLocked !== cur.titleLocked) {
|
|
103
|
+
appended.push(encodeLine({
|
|
104
|
+
k: 'meta-update',
|
|
105
|
+
at,
|
|
106
|
+
title: session.title,
|
|
107
|
+
...(session.titleLocked !== undefined ? { titleLocked: session.titleLocked } : {}),
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
if (!appended.length)
|
|
111
|
+
return;
|
|
112
|
+
session.updatedAt = at;
|
|
113
|
+
const text = cur.text + appended.join('');
|
|
114
|
+
await (await this.files()).write(this.path(session.id), text);
|
|
115
|
+
this.cursors.set(session.id, { text, turnJson, title: session.title, titleLocked: session.titleLocked });
|
|
116
|
+
}
|
|
117
|
+
/** Cursor for a session this instance hasn't touched (e.g. saved after a
|
|
118
|
+
* reload): fold the existing file, or start a fresh log from the session's
|
|
119
|
+
* own meta. */
|
|
120
|
+
async seed(session) {
|
|
121
|
+
const text = await (await this.files()).read(this.path(session.id)).catch(() => null);
|
|
122
|
+
if (text != null) {
|
|
123
|
+
const ses = foldSession(text);
|
|
124
|
+
if (ses) {
|
|
125
|
+
return { text, turnJson: ses.messages.map((m) => JSON.stringify(m)), title: ses.title, titleLocked: ses.titleLocked };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const meta = encodeLine({
|
|
129
|
+
k: 'meta', id: session.id, title: session.title, createdAt: session.createdAt,
|
|
130
|
+
...(session.surface ? { surface: session.surface } : {}),
|
|
131
|
+
});
|
|
132
|
+
return { text: meta, turnJson: [], title: session.title, titleLocked: undefined };
|
|
133
|
+
}
|
|
134
|
+
async rename(id, title) {
|
|
135
|
+
const cur = this.cursors.get(id);
|
|
136
|
+
const text = cur?.text ?? (await (await this.files()).read(this.path(id)).catch(() => null));
|
|
137
|
+
if (text == null)
|
|
138
|
+
return; // no-op on missing, matching the old store
|
|
139
|
+
const next = text + encodeLine({ k: 'meta-update', at: now(), title, titleLocked: true });
|
|
140
|
+
await (await this.files()).write(this.path(id), next);
|
|
141
|
+
const folded = foldSession(next);
|
|
142
|
+
if (folded) {
|
|
143
|
+
this.cursors.set(id, { text: next, turnJson: folded.messages.map((m) => JSON.stringify(m)), title, titleLocked: true });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async delete(id) {
|
|
147
|
+
this.cursors.delete(id);
|
|
148
|
+
await (await this.files()).remove(`${this.root()}/${id}`).catch(() => { });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=fileSessionStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileSessionStore.js","sourceRoot":"","sources":["../../sessions/fileSessionStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { TimelineEntry } from './timeline';
|
|
2
|
+
export type SessionStatus = 'running' | 'paused' | 'archived' | 'failed' | 'completed';
|
|
3
|
+
/** What the runtime is waiting on. Derived from the tail of the timeline. */
|
|
4
|
+
export type CursorPhase = 'awaiting_model' | 'awaiting_tool_result' | 'awaiting_approval' | 'idle';
|
|
5
|
+
/** A question only a human can answer. Survives transport: an approval requested
|
|
6
|
+
* on the laptop and answered from the phone is the SAME object, and only the
|
|
7
|
+
* client differs (spec s4.4.4). */
|
|
8
|
+
export interface PendingApproval {
|
|
9
|
+
id: string;
|
|
10
|
+
kind: 'tool_permission' | 'resume_unknown' | 'budget';
|
|
11
|
+
callId: string | null;
|
|
12
|
+
/** The timeline entry this is about, so an answer can be attributed. */
|
|
13
|
+
index: number;
|
|
14
|
+
question: string;
|
|
15
|
+
options: {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
}[];
|
|
19
|
+
requestedAt: string;
|
|
20
|
+
}
|
|
21
|
+
export interface SessionHead {
|
|
22
|
+
schemaVersion: 1;
|
|
23
|
+
sessionId: string;
|
|
24
|
+
status: SessionStatus;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
task?: {
|
|
27
|
+
id: string;
|
|
28
|
+
objective: string;
|
|
29
|
+
cwd: string;
|
|
30
|
+
};
|
|
31
|
+
agent?: {
|
|
32
|
+
package: string;
|
|
33
|
+
version: string;
|
|
34
|
+
entrypoint: string;
|
|
35
|
+
};
|
|
36
|
+
cursor: {
|
|
37
|
+
nextIndex: number;
|
|
38
|
+
phase: CursorPhase;
|
|
39
|
+
};
|
|
40
|
+
pendingApproval: PendingApproval | null;
|
|
41
|
+
usage: {
|
|
42
|
+
inputTokens: number;
|
|
43
|
+
outputTokens: number;
|
|
44
|
+
wallMs: number;
|
|
45
|
+
};
|
|
46
|
+
/** Opaque workflow position when the session is running a .pdflow package.
|
|
47
|
+
* Corenel stores and returns it; the workflow runtime owns its meaning. */
|
|
48
|
+
workflow?: {
|
|
49
|
+
package: string;
|
|
50
|
+
version: string;
|
|
51
|
+
position: unknown;
|
|
52
|
+
completedNodes: {
|
|
53
|
+
id: string;
|
|
54
|
+
outputRef: string;
|
|
55
|
+
}[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export declare const HEAD_VERSION: 1;
|
|
59
|
+
export interface DeriveHeadInput {
|
|
60
|
+
sessionId: string;
|
|
61
|
+
entries: readonly TimelineEntry[];
|
|
62
|
+
nextIndex: number;
|
|
63
|
+
updatedAt: string;
|
|
64
|
+
/** Carried through unchanged — none of it is derivable from the timeline. */
|
|
65
|
+
carry?: Pick<SessionHead, 'task' | 'agent' | 'workflow' | 'pendingApproval'>;
|
|
66
|
+
/** The session's own status when it is not implied by the timeline (paused,
|
|
67
|
+
* archived). Absent, the phase decides between running and idle. */
|
|
68
|
+
status?: SessionStatus;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Rebuild the head from the timeline.
|
|
72
|
+
*
|
|
73
|
+
* The phase comes from the LAST entry, because that is what the runtime is
|
|
74
|
+
* actually blocked on:
|
|
75
|
+
* - a tool call still `executing` -> awaiting_tool_result
|
|
76
|
+
* - a user message with no reply -> awaiting_model
|
|
77
|
+
* - an approval outstanding -> awaiting_approval (it outranks the rest;
|
|
78
|
+
* nothing proceeds until it is answered)
|
|
79
|
+
* - anything else -> idle
|
|
80
|
+
*/
|
|
81
|
+
export declare function deriveHead(input: DeriveHeadInput): SessionHead;
|
|
82
|
+
export declare function serializeHead(head: SessionHead): string;
|
|
83
|
+
/**
|
|
84
|
+
* Parse a stored head, or null when it is unusable.
|
|
85
|
+
*
|
|
86
|
+
* Null is not an error condition for the caller: the head is a cache, so the
|
|
87
|
+
* answer to "it did not parse" is "fold the log again", never "fail the session".
|
|
88
|
+
*/
|
|
89
|
+
export declare function parseHead(text: string): SessionHead | null;
|
|
90
|
+
//# sourceMappingURL=head.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../../sessions/head.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEvF,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,sBAAsB,GAAG,mBAAmB,GAAG,MAAM,CAAC;AAEnG;;mCAEmC;AACnC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,QAAQ,CAAC;IACtD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,CAAC,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,CAAC;IAClD,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IACxC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE;+EAC2E;IAC3E,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,CAAC;CACzH;AAED,eAAO,MAAM,YAAY,EAAG,CAAU,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,iBAAiB,CAAC,CAAC;IAC7E;wEACoE;IACpE,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,CAqB9D;AAsBD,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAO1D"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export const HEAD_VERSION = 1;
|
|
2
|
+
/**
|
|
3
|
+
* Rebuild the head from the timeline.
|
|
4
|
+
*
|
|
5
|
+
* The phase comes from the LAST entry, because that is what the runtime is
|
|
6
|
+
* actually blocked on:
|
|
7
|
+
* - a tool call still `executing` -> awaiting_tool_result
|
|
8
|
+
* - a user message with no reply -> awaiting_model
|
|
9
|
+
* - an approval outstanding -> awaiting_approval (it outranks the rest;
|
|
10
|
+
* nothing proceeds until it is answered)
|
|
11
|
+
* - anything else -> idle
|
|
12
|
+
*/
|
|
13
|
+
export function deriveHead(input) {
|
|
14
|
+
const pendingApproval = input.carry?.pendingApproval ?? null;
|
|
15
|
+
const last = input.entries[input.entries.length - 1];
|
|
16
|
+
let phase = 'idle';
|
|
17
|
+
if (pendingApproval)
|
|
18
|
+
phase = 'awaiting_approval';
|
|
19
|
+
else if (input.entries.some((e) => e.type === 'tool_call' && e.status === 'executing'))
|
|
20
|
+
phase = 'awaiting_tool_result';
|
|
21
|
+
else if (last?.type === 'user_message')
|
|
22
|
+
phase = 'awaiting_model';
|
|
23
|
+
return {
|
|
24
|
+
schemaVersion: HEAD_VERSION,
|
|
25
|
+
sessionId: input.sessionId,
|
|
26
|
+
status: input.status ?? (phase === 'idle' ? 'completed' : 'running'),
|
|
27
|
+
updatedAt: input.updatedAt,
|
|
28
|
+
...(input.carry?.task ? { task: input.carry.task } : {}),
|
|
29
|
+
...(input.carry?.agent ? { agent: input.carry.agent } : {}),
|
|
30
|
+
...(input.carry?.workflow ? { workflow: input.carry.workflow } : {}),
|
|
31
|
+
cursor: { nextIndex: input.nextIndex, phase },
|
|
32
|
+
pendingApproval,
|
|
33
|
+
usage: usageOf(input.entries),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Token and wall-clock totals, summed from the timeline rather than tracked
|
|
37
|
+
* separately — a counter that drifts from the log is worse than no counter. */
|
|
38
|
+
function usageOf(entries) {
|
|
39
|
+
let inputTokens = 0;
|
|
40
|
+
let outputTokens = 0;
|
|
41
|
+
let wallMs = 0;
|
|
42
|
+
for (const e of entries) {
|
|
43
|
+
const u = e.usage;
|
|
44
|
+
if (u && typeof u === 'object') {
|
|
45
|
+
if (typeof u.inputTokens === 'number')
|
|
46
|
+
inputTokens += u.inputTokens;
|
|
47
|
+
if (typeof u.outputTokens === 'number')
|
|
48
|
+
outputTokens += u.outputTokens;
|
|
49
|
+
}
|
|
50
|
+
if (e.type === 'tool_call' && e.startedAt && e.completedAt) {
|
|
51
|
+
const ms = Date.parse(e.completedAt) - Date.parse(e.startedAt);
|
|
52
|
+
if (Number.isFinite(ms) && ms > 0)
|
|
53
|
+
wallMs += ms;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { inputTokens, outputTokens, wallMs };
|
|
57
|
+
}
|
|
58
|
+
export function serializeHead(head) {
|
|
59
|
+
return JSON.stringify(head, null, 2) + '\n';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse a stored head, or null when it is unusable.
|
|
63
|
+
*
|
|
64
|
+
* Null is not an error condition for the caller: the head is a cache, so the
|
|
65
|
+
* answer to "it did not parse" is "fold the log again", never "fail the session".
|
|
66
|
+
*/
|
|
67
|
+
export function parseHead(text) {
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = JSON.parse(text);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
76
|
+
return null;
|
|
77
|
+
const h = parsed;
|
|
78
|
+
if (h.schemaVersion !== HEAD_VERSION || typeof h.sessionId !== 'string' || !h.cursor)
|
|
79
|
+
return null;
|
|
80
|
+
return h;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=head.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head.js","sourceRoot":"","sources":["../../sessions/head.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface InflightWork {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
/** The tool call this represents, for the report when a drain times out. */
|
|
4
|
+
callId: string;
|
|
5
|
+
startedAt: number;
|
|
6
|
+
}
|
|
7
|
+
export interface DrainResult {
|
|
8
|
+
/** True when everything finished before the deadline. */
|
|
9
|
+
drained: boolean;
|
|
10
|
+
/** Call ids still running when we gave up. Empty when `drained`. */
|
|
11
|
+
remaining: string[];
|
|
12
|
+
/** How long the drain actually waited. */
|
|
13
|
+
waitedMs: number;
|
|
14
|
+
}
|
|
15
|
+
export interface DrainOptions {
|
|
16
|
+
/** Give up after this long. 0 means "do not wait at all". */
|
|
17
|
+
timeoutMs: number;
|
|
18
|
+
/** Poll interval. Small enough to feel instant, large enough not to spin. */
|
|
19
|
+
stepMs?: number;
|
|
20
|
+
now: () => number;
|
|
21
|
+
sleep: (ms: number) => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Tracks the tool calls currently running per session.
|
|
25
|
+
*
|
|
26
|
+
* Deliberately a registry the runtime writes to, rather than something the
|
|
27
|
+
* backend infers: only the caller knows when a tool call starts and ends, and a
|
|
28
|
+
* backend guessing at it would be wrong in exactly the cases that matter.
|
|
29
|
+
*/
|
|
30
|
+
export declare class InflightRegistry {
|
|
31
|
+
private readonly work;
|
|
32
|
+
private key;
|
|
33
|
+
begin(sessionId: string, callId: string, at: number): void;
|
|
34
|
+
/** Idempotent: ending a call that already ended is a no-op, not an error, so
|
|
35
|
+
* cleanup paths can be unconditional. */
|
|
36
|
+
end(sessionId: string, callId: string): void;
|
|
37
|
+
/** Call ids running for a session, oldest first — the oldest is the one most
|
|
38
|
+
* likely to be stuck, so it leads the report. */
|
|
39
|
+
running(sessionId: string): string[];
|
|
40
|
+
count(sessionId: string): number;
|
|
41
|
+
/** Forget a session's work outright — for destroy, where nothing is coming back. */
|
|
42
|
+
clear(sessionId: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Wait for a session's in-flight work to finish.
|
|
45
|
+
*
|
|
46
|
+
* Returns rather than throwing on timeout: a drain that could not complete is
|
|
47
|
+
* information the caller has to act on (record a problem, mark entries
|
|
48
|
+
* `executing`), not an error that should abandon the export. Losing the
|
|
49
|
+
* snapshot because one tool hung would be a worse outcome than a torn one that
|
|
50
|
+
* says it is torn.
|
|
51
|
+
*/
|
|
52
|
+
drain(sessionId: string, opts: DrainOptions): Promise<DrainResult>;
|
|
53
|
+
}
|
|
54
|
+
/** Default drain budget. Long enough for an ordinary file write or a short
|
|
55
|
+
* command, short enough that closing a laptop still feels immediate. Overridable
|
|
56
|
+
* per call, so a hosted runner and a laptop can differ. */
|
|
57
|
+
export declare const DEFAULT_DRAIN_MS = 5000;
|
|
58
|
+
//# sourceMappingURL=inflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inflight.d.ts","sourceRoot":"","sources":["../../sessions/inflight.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IAExD,OAAO,CAAC,GAAG;IAIX,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAI1D;6CACyC;IACzC,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI5C;qDACiD;IACjD,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAOpC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIhC,oFAAoF;IACpF,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI9B;;;;;;;;OAQG;IACG,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;CAWzE;AAED;;2DAE2D;AAC3D,eAAO,MAAM,gBAAgB,OAAO,CAAC"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inflight.js","sourceRoot":"","sources":["../../sessions/inflight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA2BH;;;;;;GAMG;AACH,MAAM,OAAO,gBAAgB;IAA7B;QACmB;;;;mBAAO,IAAI,GAAG,EAAwB;WAAC;IAsD1D,CAAC;IApDS,GAAG,CAAC,SAAiB,EAAE,MAAc;QAC3C,OAAO,GAAG,SAAS,IAAI,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,SAAiB,EAAE,MAAc,EAAE,EAAU;QACjD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IACnF,CAAC;IAED;6CACyC;IACzC,GAAG,CAAC,SAAiB,EAAE,MAAc;QACnC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,CAAC;IAED;qDACiD;IACjD,OAAO,CAAC,SAAiB;QACvB,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;aAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC;aACxC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;aACzC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,SAAiB;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,oFAAoF;IACpF,KAAK,CAAC,SAAiB;QACrB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,KAAK,CAAC,SAAiB,EAAE,IAAkB;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QAC5C,SAAS,CAAC;YACR,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1C,IAAI,CAAC,SAAS,CAAC,MAAM;gBAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;YAC7F,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAClC,IAAI,MAAM,IAAI,IAAI,CAAC,SAAS;gBAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;YACrF,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;CACF;AAED;;2DAE2D;AAC3D,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AgentSession, SessionSurface } from '@corenel/protocol';
|
|
2
|
+
export type SessionLine = {
|
|
3
|
+
k: 'meta';
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
createdAt: number;
|
|
7
|
+
surface?: SessionSurface;
|
|
8
|
+
} | {
|
|
9
|
+
k: 'meta-update';
|
|
10
|
+
at: number;
|
|
11
|
+
title?: string;
|
|
12
|
+
titleLocked?: boolean;
|
|
13
|
+
} | {
|
|
14
|
+
k: 'turn';
|
|
15
|
+
i: number;
|
|
16
|
+
at: number;
|
|
17
|
+
m: unknown;
|
|
18
|
+
};
|
|
19
|
+
export declare function encodeLine(line: SessionLine): string;
|
|
20
|
+
/** Fold a SESSION.jsonl text into an AgentSession, or null when no valid meta
|
|
21
|
+
* line exists (empty/foreign file). */
|
|
22
|
+
export declare function foldSession(text: string): AgentSession | null;
|
|
23
|
+
//# sourceMappingURL=jsonl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../../sessions/jsonl.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEtE,MAAM,MAAM,WAAW,GACnB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,cAAc,CAAA;CAAE,GACrF;IAAE,CAAC,EAAE,aAAa,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GACvE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAErD,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAEpD;AAED;uCACuC;AACvC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAkC7D"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export function encodeLine(line) {
|
|
2
|
+
return JSON.stringify(line) + '\n';
|
|
3
|
+
}
|
|
4
|
+
/** Fold a SESSION.jsonl text into an AgentSession, or null when no valid meta
|
|
5
|
+
* line exists (empty/foreign file). */
|
|
6
|
+
export function foldSession(text) {
|
|
7
|
+
let meta = null;
|
|
8
|
+
const turns = [];
|
|
9
|
+
let title = '';
|
|
10
|
+
let titleLocked;
|
|
11
|
+
let updatedAt = 0;
|
|
12
|
+
for (const raw of text.split('\n')) {
|
|
13
|
+
const s = raw.trim();
|
|
14
|
+
if (!s)
|
|
15
|
+
continue;
|
|
16
|
+
let line;
|
|
17
|
+
try {
|
|
18
|
+
line = JSON.parse(s);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (line.k === 'meta' && !meta && typeof line.id === 'string' && typeof line.createdAt === 'number') {
|
|
24
|
+
meta = line;
|
|
25
|
+
title = typeof line.title === 'string' ? line.title : '';
|
|
26
|
+
updatedAt = Math.max(updatedAt, line.createdAt);
|
|
27
|
+
}
|
|
28
|
+
else if (line.k === 'meta-update' && typeof line.at === 'number') {
|
|
29
|
+
if (typeof line.title === 'string')
|
|
30
|
+
title = line.title;
|
|
31
|
+
if (typeof line.titleLocked === 'boolean')
|
|
32
|
+
titleLocked = line.titleLocked;
|
|
33
|
+
updatedAt = Math.max(updatedAt, line.at);
|
|
34
|
+
}
|
|
35
|
+
else if (line.k === 'turn' && Number.isInteger(line.i) && line.i >= 0 && typeof line.at === 'number') {
|
|
36
|
+
turns[line.i] = line.m;
|
|
37
|
+
updatedAt = Math.max(updatedAt, line.at);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (!meta)
|
|
41
|
+
return null;
|
|
42
|
+
return {
|
|
43
|
+
id: meta.id,
|
|
44
|
+
title,
|
|
45
|
+
createdAt: meta.createdAt,
|
|
46
|
+
updatedAt: updatedAt || meta.createdAt,
|
|
47
|
+
messages: turns.filter((t) => t !== undefined),
|
|
48
|
+
...(meta.surface ? { surface: meta.surface } : {}),
|
|
49
|
+
...(titleLocked !== undefined ? { titleLocked } : {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=jsonl.js.map
|