@theokit/agents 7.6.0 → 8.1.0
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-handle-BX4oFqfb.d.ts → agent-handle-Dgi4ZGbg.d.ts} +11 -1
- package/dist/ask.d.ts +190 -0
- package/dist/ask.js +179 -0
- package/dist/ask.js.map +1 -0
- package/dist/auth.d.ts +95 -1
- package/dist/auth.js +83 -0
- package/dist/auth.js.map +1 -1
- package/dist/{bridge-entry-CvmBrmc9.d.ts → bridge-entry-BEniSXWE.d.ts} +223 -700
- package/dist/bridge.d.ts +6 -3
- package/dist/bridge.js +16 -8
- package/dist/chunk-4VHCH6IZ.js +181 -0
- package/dist/chunk-4VHCH6IZ.js.map +1 -0
- package/dist/{chunk-22IPZFVT.js → chunk-C7UXZWVY.js} +167 -207
- package/dist/chunk-C7UXZWVY.js.map +1 -0
- package/dist/{chunk-2BAFKRXT.js → chunk-M6HMASZC.js} +9 -4
- package/dist/chunk-M6HMASZC.js.map +1 -0
- package/dist/client-react.d.ts +2 -1
- package/dist/client-react.js +1 -1
- package/dist/client.d.ts +3 -2
- package/dist/client.js +1 -1
- package/dist/commands.d.ts +120 -0
- package/dist/commands.js +145 -0
- package/dist/commands.js.map +1 -0
- package/dist/define-agent-3Kuf6iKM.d.ts +633 -0
- package/dist/doctor.d.ts +119 -0
- package/dist/doctor.js +84 -0
- package/dist/doctor.js.map +1 -0
- package/dist/hook-handlers-Cw2FsnE5.d.ts +56 -0
- package/dist/hooks.d.ts +225 -0
- package/dist/hooks.js +286 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +170 -26
- package/dist/index.js +90 -22
- package/dist/index.js.map +1 -1
- package/dist/mcp-health.d.ts +69 -0
- package/dist/mcp-health.js +42 -0
- package/dist/mcp-health.js.map +1 -0
- package/dist/session.d.ts +238 -0
- package/dist/session.js +338 -0
- package/dist/session.js.map +1 -0
- package/dist/testing.d.ts +90 -1
- package/dist/testing.js +76 -1
- package/dist/testing.js.map +1 -1
- package/dist/tool-scope.d.ts +133 -0
- package/dist/tool-scope.js +61 -0
- package/dist/tool-scope.js.map +1 -0
- package/dist/usage.d.ts +98 -0
- package/dist/usage.js +55 -0
- package/dist/usage.js.map +1 -0
- package/package.json +35 -3
- package/dist/chunk-22IPZFVT.js.map +0 -1
- package/dist/chunk-2BAFKRXT.js.map +0 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { TheokitAgentError } from '@theokit/sdk/errors';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* M71 — the session LIFECYCLE vocabulary: list, delete, protect, fork.
|
|
5
|
+
*
|
|
6
|
+
* ## Why this module exists, and what it deliberately is not
|
|
7
|
+
*
|
|
8
|
+
* The store is fully supplied — 29 pass-throughs under `/persistence` cover paths, atomic writes,
|
|
9
|
+
* locks and artifact classification. What had no home was the vocabulary ABOVE them: listing,
|
|
10
|
+
* deleting with a live-session guard, forking, going back before a turn.
|
|
11
|
+
*
|
|
12
|
+
* The named risk was that absorbing lifecycle reads as owning the store (G2). The separation is
|
|
13
|
+
* real and this module is where it is drawn: **owning the vocabulary is not owning the store.**
|
|
14
|
+
* Nothing here writes a transcript. Every file operation is either a delete of something the caller
|
|
15
|
+
* named, or a delegation to an SDK primitive. The knowledge added is which files are protected and
|
|
16
|
+
* what "delete a session" means — decisions, not storage.
|
|
17
|
+
*
|
|
18
|
+
* ## The asymmetry that made the gap a trap
|
|
19
|
+
*
|
|
20
|
+
* `Agent.delete` clears the REGISTRY ENTRY and never touches the transcript on disk. A consumer had
|
|
21
|
+
* to discover that by measuring. {@link deleteSession} is the answer: it returns
|
|
22
|
+
* `{ registryRemoved, transcriptRemoved }` so the two are impossible to confuse, and a caller that
|
|
23
|
+
* wanted both and got one can see it.
|
|
24
|
+
*/
|
|
25
|
+
/** Raised when a lifecycle operation is refused because the session is live. */
|
|
26
|
+
declare class SessionInUseError extends TheokitAgentError {
|
|
27
|
+
readonly sessionId: string;
|
|
28
|
+
/** Why it is protected — a writer lease, the resumable pointer, or being the most recent. */
|
|
29
|
+
readonly reason: string;
|
|
30
|
+
readonly name = "SessionInUseError";
|
|
31
|
+
constructor(sessionId: string,
|
|
32
|
+
/** Why it is protected — a writer lease, the resumable pointer, or being the most recent. */
|
|
33
|
+
reason: string);
|
|
34
|
+
}
|
|
35
|
+
/** One session as the lifecycle vocabulary sees it. */
|
|
36
|
+
interface SessionSummary {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
/** Absolute path of the transcript file. */
|
|
39
|
+
readonly transcript: string;
|
|
40
|
+
/** Last modification, for recency ordering. */
|
|
41
|
+
readonly modifiedAt: Date;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sessions with a transcript under `cwd`'s project directory, most recent first.
|
|
45
|
+
*
|
|
46
|
+
* Uses `classifySessionArtifact` rather than matching file names here: the SDK owns what a file in a
|
|
47
|
+
* project directory IS, and a second matcher would answer differently the day the layout changes —
|
|
48
|
+
* silently, on a path whose purpose is deleting things.
|
|
49
|
+
*/
|
|
50
|
+
declare function listSessions(cwd: string, root?: string): SessionSummary[];
|
|
51
|
+
/**
|
|
52
|
+
* Transcripts that must NOT be collected: the resumable pointer's target, the most recent session,
|
|
53
|
+
* and anything holding a writer lease.
|
|
54
|
+
*
|
|
55
|
+
* Three reasons, deliberately not collapsed into a boolean. A caller reporting "skipped 4 sessions"
|
|
56
|
+
* is far less useful than one reporting why each was skipped, and retention policy is exactly where
|
|
57
|
+
* an operator asks that question.
|
|
58
|
+
*/
|
|
59
|
+
declare function protectedTranscripts(cwd: string, root?: string): Map<string, string>;
|
|
60
|
+
/** What `deleteSession` did, per store. */
|
|
61
|
+
interface DeleteSessionResult {
|
|
62
|
+
/** Whether a registry entry was removed. */
|
|
63
|
+
readonly registryRemoved: boolean;
|
|
64
|
+
/** Whether the transcript file was removed. */
|
|
65
|
+
readonly transcriptRemoved: boolean;
|
|
66
|
+
}
|
|
67
|
+
interface DeleteSessionOptions {
|
|
68
|
+
readonly cwd: string;
|
|
69
|
+
readonly root?: string;
|
|
70
|
+
/** Delete even when protected. The refusal is the default because the damage is unrecoverable. */
|
|
71
|
+
readonly force?: boolean;
|
|
72
|
+
/** Remove the registry entry too. Injected (DIP) — the registry is the runtime's, not ours. */
|
|
73
|
+
readonly removeFromRegistry?: (sessionId: string) => boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Delete a session, refusing by default when it is protected.
|
|
77
|
+
*
|
|
78
|
+
* The two stores are reported separately because they genuinely are separate — `Agent.delete`
|
|
79
|
+
* touches only the registry, and a caller that assumed otherwise would leave the transcript behind
|
|
80
|
+
* believing it gone. Returning one boolean would rebuild that confusion inside this function.
|
|
81
|
+
*
|
|
82
|
+
* @throws {SessionInUseError} when the session is protected and `force` is not set.
|
|
83
|
+
*/
|
|
84
|
+
declare function deleteSession(sessionId: string, options: DeleteSessionOptions): DeleteSessionResult;
|
|
85
|
+
/**
|
|
86
|
+
* Fork `srcId` into `newId`, keeping everything BEFORE the `nth` user turn.
|
|
87
|
+
*
|
|
88
|
+
* Delegates the copy to the SDK's `forkTranscript` — the truncation rule is the SDK's knowledge and
|
|
89
|
+
* re-deriving it here would give two answers to "where does a turn begin".
|
|
90
|
+
*
|
|
91
|
+
* `nth` is 1-based, matching how a person counts turns out loud. A 0-based index here would be a
|
|
92
|
+
* silent off-by-one on a destructive-feeling operation.
|
|
93
|
+
*/
|
|
94
|
+
declare function forkBeforeUserTurn(srcId: string, newId: string, nth: number, options: {
|
|
95
|
+
readonly cwd: string;
|
|
96
|
+
readonly root?: string;
|
|
97
|
+
}): {
|
|
98
|
+
readonly transcript: string;
|
|
99
|
+
readonly recordIndex: number;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/** Where the pointer for `cwd` lives. */
|
|
103
|
+
declare function sessionPointerPath(cwd: string, root?: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* The session id to resume for `cwd`, or a freshly minted one when there is nothing to resume.
|
|
106
|
+
*
|
|
107
|
+
* Never rejects. A missing, empty or unreadable pointer all mean the same thing to the caller —
|
|
108
|
+
* "start a new session" — and distinguishing them would only give the caller three ways to write
|
|
109
|
+
* the same branch.
|
|
110
|
+
*
|
|
111
|
+
* @param mintId how to create an id when there is nothing to resume. Injected (DIP) so the caller
|
|
112
|
+
* owns id shape and the tests are deterministic — a `crypto.randomUUID()` baked in here would make
|
|
113
|
+
* every assertion about the fresh path unwritable.
|
|
114
|
+
*/
|
|
115
|
+
declare function loadOrCreateSessionId(cwd: string, mintId: () => string, root?: string): {
|
|
116
|
+
readonly sessionId: string;
|
|
117
|
+
readonly resumed: boolean;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Point `cwd` at `sessionId`, atomically.
|
|
121
|
+
*
|
|
122
|
+
* Delegates to `atomicWriteText`, so a reader never observes a half-written pointer.
|
|
123
|
+
*
|
|
124
|
+
* The first draft reached for `atomicWriteTempTarget` instead, which was a misreading worth
|
|
125
|
+
* recording: that function does not GENERATE a temp name, it RECOGNISES one and answers which final
|
|
126
|
+
* file it belongs to. It is the collector's question ("is this scratch, and whose?"), not the
|
|
127
|
+
* writer's. Its return type — `string | undefined` — is what said so, and the typechecker refused
|
|
128
|
+
* the misuse before it could ship.
|
|
129
|
+
*
|
|
130
|
+
* Returns `{ persisted }` instead of throwing (see the module docblock). The failure is reported,
|
|
131
|
+
* not hidden.
|
|
132
|
+
*
|
|
133
|
+
* ASYNC because `atomicWriteText` is. The first draft called it synchronously and returned
|
|
134
|
+
* `{ persisted: true }` before the bytes landed — so the function reported a success that had not
|
|
135
|
+
* happened yet, and a read immediately after found nothing. The tests caught it; a caller would
|
|
136
|
+
* have caught it as an intermittently missing `--continue`.
|
|
137
|
+
*/
|
|
138
|
+
declare function persistSessionId(cwd: string, sessionId: string, root?: string): Promise<{
|
|
139
|
+
readonly persisted: boolean;
|
|
140
|
+
}>;
|
|
141
|
+
|
|
142
|
+
/** Absolute path of the project directory for `cwd`, under the transcript root. */
|
|
143
|
+
declare function projectDirFor(cwd: string, root?: string): string;
|
|
144
|
+
/**
|
|
145
|
+
* Record that `cwd` is the project behind its encoded directory.
|
|
146
|
+
*
|
|
147
|
+
* Idempotent and best-effort by design: this is an index, and a machine that cannot write it should
|
|
148
|
+
* still be able to run an agent. A throw here would turn a missing optimisation into a failed run.
|
|
149
|
+
*/
|
|
150
|
+
declare function recordProjectDir(cwd: string, root?: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* The cwd behind an encoded project directory name, or `undefined` when this layer never saw it.
|
|
153
|
+
*
|
|
154
|
+
* `undefined` is NOT "the project is gone". It is "no sidecar here", which a project created before
|
|
155
|
+
* this index existed also produces. A caller that treated the two as the same would delete live
|
|
156
|
+
* projects — which is precisely why the distinction is stated rather than left to the reader.
|
|
157
|
+
*/
|
|
158
|
+
declare function resolveProjectDir(encodedName: string, root?: string): string | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Whether `encodedName` is the encoding of `cwd`.
|
|
161
|
+
*
|
|
162
|
+
* The verification that makes the index trustworthy rather than merely convenient: a sidecar can be
|
|
163
|
+
* stale (the directory was renamed) and re-encoding is the cheap way to notice. It is also the whole
|
|
164
|
+
* of the `classifyProject` oracle the milestone offered as the alternative — kept as a companion to
|
|
165
|
+
* the index rather than a replacement, because it can only confirm a cwd the caller already has.
|
|
166
|
+
*/
|
|
167
|
+
declare function projectDirMatches(encodedName: string, cwd: string): boolean;
|
|
168
|
+
|
|
169
|
+
/** Raised when a retention knob is below its floor. Refusing beats clamping — see invariant 1. */
|
|
170
|
+
declare class GCFloorError extends TheokitAgentError {
|
|
171
|
+
readonly field: 'keepLast' | 'maxAgeDays';
|
|
172
|
+
readonly received: number;
|
|
173
|
+
readonly name = "GCFloorError";
|
|
174
|
+
constructor(field: 'keepLast' | 'maxAgeDays', received: number);
|
|
175
|
+
}
|
|
176
|
+
/** A transcript the policy would collect. */
|
|
177
|
+
interface GCCandidate {
|
|
178
|
+
readonly id: string;
|
|
179
|
+
readonly transcript: string;
|
|
180
|
+
readonly modifiedAt: Date;
|
|
181
|
+
}
|
|
182
|
+
/** A transcript the policy keeps, and why. */
|
|
183
|
+
interface GCKept {
|
|
184
|
+
readonly id: string;
|
|
185
|
+
/** Human-readable protection reason — recency, policy, lease, or unreadable age. */
|
|
186
|
+
readonly reason: string;
|
|
187
|
+
}
|
|
188
|
+
interface TranscriptGCOptions {
|
|
189
|
+
readonly cwd: string;
|
|
190
|
+
/** Newest N sessions always survive. Floor: 1 — a project with none has nothing to `--continue`. */
|
|
191
|
+
readonly keepLast: number;
|
|
192
|
+
/** Only sessions older than this may be collected. Floor: 1. */
|
|
193
|
+
readonly maxAgeDays: number;
|
|
194
|
+
readonly root?: string;
|
|
195
|
+
/** Injected clock (DIP) — a live `Date.now()` makes every age assertion depend on run speed. */
|
|
196
|
+
readonly now?: number;
|
|
197
|
+
}
|
|
198
|
+
interface TranscriptGCPlan {
|
|
199
|
+
readonly cwd: string;
|
|
200
|
+
readonly root: string;
|
|
201
|
+
readonly candidates: readonly GCCandidate[];
|
|
202
|
+
readonly kept: readonly GCKept[];
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Decide what a retention policy would collect, without touching anything.
|
|
206
|
+
*
|
|
207
|
+
* Both conditions must hold for a transcript to be a candidate: beyond `keepLast` in recency order
|
|
208
|
+
* AND older than `maxAgeDays`. Age alone would delete a project's whole recent history the moment it
|
|
209
|
+
* exceeded the count; count alone would delete yesterday's work on a busy project.
|
|
210
|
+
*
|
|
211
|
+
* @throws {GCFloorError} when a knob is below its floor (invariant 1).
|
|
212
|
+
*/
|
|
213
|
+
declare function planTranscriptGC(options: TranscriptGCOptions): TranscriptGCPlan;
|
|
214
|
+
/** What one candidate's removal did, or why it did not. */
|
|
215
|
+
interface GCError {
|
|
216
|
+
readonly id: string;
|
|
217
|
+
readonly message: string;
|
|
218
|
+
}
|
|
219
|
+
interface RunTranscriptGCResult {
|
|
220
|
+
readonly dryRun: boolean;
|
|
221
|
+
/** Ids that were (or, in a dry run, would be) removed. */
|
|
222
|
+
readonly removed: readonly string[];
|
|
223
|
+
/** One entry per candidate that failed — the rest still ran. */
|
|
224
|
+
readonly errors: readonly GCError[];
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Execute a plan. `apply: false` reports what would happen and changes nothing.
|
|
228
|
+
*
|
|
229
|
+
* Errors accumulate PER CANDIDATE (fail-open): one undeletable file must not leave the rest of the
|
|
230
|
+
* disk uncollected, and the operator must still learn which one failed. `ENOENT` counts as success —
|
|
231
|
+
* absent is the desired end state, and reporting it as failure would make the second run of an
|
|
232
|
+
* interrupted GC look broken.
|
|
233
|
+
*/
|
|
234
|
+
declare function runTranscriptGC(plan: TranscriptGCPlan, options: {
|
|
235
|
+
readonly apply: boolean;
|
|
236
|
+
}): RunTranscriptGCResult;
|
|
237
|
+
|
|
238
|
+
export { type DeleteSessionOptions, type DeleteSessionResult, type GCCandidate, type GCError, GCFloorError, type GCKept, type RunTranscriptGCResult, SessionInUseError, type SessionSummary, type TranscriptGCOptions, type TranscriptGCPlan, deleteSession, forkBeforeUserTurn, listSessions, loadOrCreateSessionId, persistSessionId, planTranscriptGC, projectDirFor, projectDirMatches, protectedTranscripts, recordProjectDir, resolveProjectDir, runTranscriptGC, sessionPointerPath };
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-Z4QWC7IK.js";
|
|
4
|
+
|
|
5
|
+
// src/session/session-lifecycle.ts
|
|
6
|
+
import { readFileSync as readFileSync3, readdirSync, rmSync, statSync } from "fs";
|
|
7
|
+
import { join as join3 } from "path";
|
|
8
|
+
import { TheokitAgentError } from "@theokit/sdk/errors";
|
|
9
|
+
import { classifySessionArtifact, forkTranscript, loadJsonl, sessionHasWriter, transcriptPath, transcriptRoot as transcriptRoot3 } from "@theokit/sdk/persistence";
|
|
10
|
+
|
|
11
|
+
// src/session/project-index.ts
|
|
12
|
+
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
13
|
+
import { dirname, join } from "path";
|
|
14
|
+
import { encodeProjectDir, transcriptRoot } from "@theokit/sdk/persistence";
|
|
15
|
+
var CWD_SIDECAR = "cwd";
|
|
16
|
+
function projectDirFor(cwd, root = transcriptRoot()) {
|
|
17
|
+
return join(root, "projects", encodeProjectDir(cwd));
|
|
18
|
+
}
|
|
19
|
+
__name(projectDirFor, "projectDirFor");
|
|
20
|
+
function recordProjectDir(cwd, root = transcriptRoot()) {
|
|
21
|
+
const sidecar = join(projectDirFor(cwd, root), CWD_SIDECAR);
|
|
22
|
+
try {
|
|
23
|
+
mkdirSync(dirname(sidecar), {
|
|
24
|
+
recursive: true
|
|
25
|
+
});
|
|
26
|
+
writeFileSync(sidecar, `${cwd}
|
|
27
|
+
`, "utf8");
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
__name(recordProjectDir, "recordProjectDir");
|
|
32
|
+
function resolveProjectDir(encodedName, root = transcriptRoot()) {
|
|
33
|
+
try {
|
|
34
|
+
const raw = readFileSync(join(root, "projects", encodedName, CWD_SIDECAR), "utf8");
|
|
35
|
+
const cwd = raw.trim();
|
|
36
|
+
return cwd.length > 0 ? cwd : void 0;
|
|
37
|
+
} catch {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
__name(resolveProjectDir, "resolveProjectDir");
|
|
42
|
+
function projectDirMatches(encodedName, cwd) {
|
|
43
|
+
return encodeProjectDir(cwd) === encodedName;
|
|
44
|
+
}
|
|
45
|
+
__name(projectDirMatches, "projectDirMatches");
|
|
46
|
+
|
|
47
|
+
// src/session/session-pointer.ts
|
|
48
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
49
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
50
|
+
import { join as join2 } from "path";
|
|
51
|
+
import { dirname as dirname2 } from "path";
|
|
52
|
+
import { atomicWriteText, transcriptRoot as transcriptRoot2 } from "@theokit/sdk/persistence";
|
|
53
|
+
var POINTER = "last-session";
|
|
54
|
+
function sessionPointerPath(cwd, root = transcriptRoot2()) {
|
|
55
|
+
return join2(projectDirFor(cwd, root), POINTER);
|
|
56
|
+
}
|
|
57
|
+
__name(sessionPointerPath, "sessionPointerPath");
|
|
58
|
+
function loadOrCreateSessionId(cwd, mintId, root = transcriptRoot2()) {
|
|
59
|
+
try {
|
|
60
|
+
const existing = readFileSync2(sessionPointerPath(cwd, root), "utf8").trim();
|
|
61
|
+
if (existing.length > 0) return {
|
|
62
|
+
sessionId: existing,
|
|
63
|
+
resumed: true
|
|
64
|
+
};
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
sessionId: mintId(),
|
|
69
|
+
resumed: false
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
__name(loadOrCreateSessionId, "loadOrCreateSessionId");
|
|
73
|
+
async function persistSessionId(cwd, sessionId, root = transcriptRoot2()) {
|
|
74
|
+
const target = sessionPointerPath(cwd, root);
|
|
75
|
+
try {
|
|
76
|
+
mkdirSync2(dirname2(target), {
|
|
77
|
+
recursive: true
|
|
78
|
+
});
|
|
79
|
+
await atomicWriteText(target, `${sessionId}
|
|
80
|
+
`);
|
|
81
|
+
return {
|
|
82
|
+
persisted: true
|
|
83
|
+
};
|
|
84
|
+
} catch {
|
|
85
|
+
return {
|
|
86
|
+
persisted: false
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
__name(persistSessionId, "persistSessionId");
|
|
91
|
+
|
|
92
|
+
// src/session/session-lifecycle.ts
|
|
93
|
+
var SessionInUseError = class extends TheokitAgentError {
|
|
94
|
+
static {
|
|
95
|
+
__name(this, "SessionInUseError");
|
|
96
|
+
}
|
|
97
|
+
sessionId;
|
|
98
|
+
reason;
|
|
99
|
+
name = "SessionInUseError";
|
|
100
|
+
constructor(sessionId, reason) {
|
|
101
|
+
super(`session "${sessionId}" is protected (${reason}). Deleting it would discard state something is still using. Stop the run, or pass { force: true } to delete anyway.`), this.sessionId = sessionId, this.reason = reason;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
function listSessions(cwd, root = transcriptRoot3()) {
|
|
105
|
+
const dir = projectDirFor(cwd, root);
|
|
106
|
+
let entries;
|
|
107
|
+
try {
|
|
108
|
+
entries = readdirSync(dir);
|
|
109
|
+
} catch {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
const found = [];
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
const path = join3(dir, entry);
|
|
115
|
+
let isDirectory;
|
|
116
|
+
let modifiedAt;
|
|
117
|
+
try {
|
|
118
|
+
const stats = statSync(path);
|
|
119
|
+
isDirectory = stats.isDirectory();
|
|
120
|
+
modifiedAt = stats.mtime;
|
|
121
|
+
} catch {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const kind = classifySessionArtifact(entry, isDirectory);
|
|
125
|
+
if (kind !== "transcript") continue;
|
|
126
|
+
found.push({
|
|
127
|
+
id: entry.replace(/\.jsonl$/, ""),
|
|
128
|
+
transcript: path,
|
|
129
|
+
modifiedAt
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return found.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
|
|
133
|
+
}
|
|
134
|
+
__name(listSessions, "listSessions");
|
|
135
|
+
function protectedTranscripts(cwd, root = transcriptRoot3()) {
|
|
136
|
+
const protectedBy = /* @__PURE__ */ new Map();
|
|
137
|
+
const sessions = listSessions(cwd, root);
|
|
138
|
+
const pointer = readPointer(cwd, root);
|
|
139
|
+
if (pointer !== void 0) protectedBy.set(pointer, "resumable session pointer");
|
|
140
|
+
if (sessions.length > 0 && !protectedBy.has(sessions[0].id)) {
|
|
141
|
+
protectedBy.set(sessions[0].id, "most recent session");
|
|
142
|
+
}
|
|
143
|
+
for (const session of sessions) {
|
|
144
|
+
const hasWriter = sessionHasWriter(session.transcript);
|
|
145
|
+
if (hasWriter) protectedBy.set(session.id, "active writer lease");
|
|
146
|
+
}
|
|
147
|
+
return protectedBy;
|
|
148
|
+
}
|
|
149
|
+
__name(protectedTranscripts, "protectedTranscripts");
|
|
150
|
+
function readPointer(cwd, root) {
|
|
151
|
+
try {
|
|
152
|
+
const id = readFileSync3(sessionPointerPath(cwd, root), "utf8").trim();
|
|
153
|
+
return id.length > 0 ? id : void 0;
|
|
154
|
+
} catch {
|
|
155
|
+
return void 0;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
__name(readPointer, "readPointer");
|
|
159
|
+
function deleteSession(sessionId, options) {
|
|
160
|
+
const root = options.root ?? transcriptRoot3();
|
|
161
|
+
if (options.force !== true) {
|
|
162
|
+
const reason = protectedTranscripts(options.cwd, root).get(sessionId);
|
|
163
|
+
if (reason !== void 0) throw new SessionInUseError(sessionId, reason);
|
|
164
|
+
}
|
|
165
|
+
let transcriptRemoved = false;
|
|
166
|
+
try {
|
|
167
|
+
rmSync(transcriptPath(root, options.cwd, sessionId));
|
|
168
|
+
transcriptRemoved = true;
|
|
169
|
+
} catch {
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
registryRemoved: options.removeFromRegistry?.(sessionId) ?? false,
|
|
173
|
+
transcriptRemoved
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
__name(deleteSession, "deleteSession");
|
|
177
|
+
function forkBeforeUserTurn(srcId, newId, nth, options) {
|
|
178
|
+
if (!Number.isInteger(nth) || nth < 1) {
|
|
179
|
+
throw new TheokitAgentError(`forkBeforeUserTurn: \`nth\` counts user turns from 1, received ${String(nth)}.`);
|
|
180
|
+
}
|
|
181
|
+
const root = options.root ?? transcriptRoot3();
|
|
182
|
+
const src = transcriptPath(root, options.cwd, srcId);
|
|
183
|
+
const dst = transcriptPath(root, options.cwd, newId);
|
|
184
|
+
const recordIndex = recordIndexOfUserTurn(src, nth);
|
|
185
|
+
if (recordIndex === void 0) {
|
|
186
|
+
throw new TheokitAgentError(`forkBeforeUserTurn: session "${srcId}" has fewer than ${String(nth)} user turns.`);
|
|
187
|
+
}
|
|
188
|
+
forkTranscript(src, dst, {
|
|
189
|
+
beforeRecordIndex: recordIndex,
|
|
190
|
+
liveSessionPaths: [
|
|
191
|
+
...protectedTranscripts(options.cwd, root).keys()
|
|
192
|
+
].map((id) => transcriptPath(root, options.cwd, id))
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
transcript: dst,
|
|
196
|
+
recordIndex
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
__name(forkBeforeUserTurn, "forkBeforeUserTurn");
|
|
200
|
+
function recordIndexOfUserTurn(src, nth) {
|
|
201
|
+
const records = loadJsonl(src);
|
|
202
|
+
let seen = 0;
|
|
203
|
+
for (const [index, record] of records.entries()) {
|
|
204
|
+
if (record.role !== "user") continue;
|
|
205
|
+
seen += 1;
|
|
206
|
+
if (seen === nth) return index;
|
|
207
|
+
}
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
__name(recordIndexOfUserTurn, "recordIndexOfUserTurn");
|
|
211
|
+
|
|
212
|
+
// src/session/gc/transcript-gc.ts
|
|
213
|
+
import { rmSync as rmSync2 } from "fs";
|
|
214
|
+
import { TheokitAgentError as TheokitAgentError2 } from "@theokit/sdk/errors";
|
|
215
|
+
import { transcriptPath as transcriptPath2, transcriptRoot as transcriptRoot4 } from "@theokit/sdk/persistence";
|
|
216
|
+
var FLOOR = {
|
|
217
|
+
keepLast: 1,
|
|
218
|
+
maxAgeDays: 1
|
|
219
|
+
};
|
|
220
|
+
var GCFloorError = class extends TheokitAgentError2 {
|
|
221
|
+
static {
|
|
222
|
+
__name(this, "GCFloorError");
|
|
223
|
+
}
|
|
224
|
+
field;
|
|
225
|
+
received;
|
|
226
|
+
name = "GCFloorError";
|
|
227
|
+
constructor(field, received) {
|
|
228
|
+
super(`transcript GC: \`${field}\` must be at least ${String(FLOOR[field])}, received ${String(received)}. This is refused rather than clamped: a policy silently replaced by a different one is a policy nobody reviewed.`), this.field = field, this.received = received;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
function planTranscriptGC(options) {
|
|
232
|
+
if (!Number.isFinite(options.keepLast) || options.keepLast < FLOOR.keepLast) {
|
|
233
|
+
throw new GCFloorError("keepLast", options.keepLast);
|
|
234
|
+
}
|
|
235
|
+
if (!Number.isFinite(options.maxAgeDays) || options.maxAgeDays < FLOOR.maxAgeDays) {
|
|
236
|
+
throw new GCFloorError("maxAgeDays", options.maxAgeDays);
|
|
237
|
+
}
|
|
238
|
+
const root = options.root ?? transcriptRoot4();
|
|
239
|
+
const now = options.now ?? Date.now();
|
|
240
|
+
const cutoff = now - options.maxAgeDays * 864e5;
|
|
241
|
+
const sessions = listSessions(options.cwd, root);
|
|
242
|
+
const protectedBy = protectedTranscripts(options.cwd, root);
|
|
243
|
+
const candidates = [];
|
|
244
|
+
const kept = [];
|
|
245
|
+
for (const [index, session] of sessions.entries()) {
|
|
246
|
+
const protection = protectedBy.get(session.id);
|
|
247
|
+
if (protection !== void 0) {
|
|
248
|
+
kept.push({
|
|
249
|
+
id: session.id,
|
|
250
|
+
reason: protection
|
|
251
|
+
});
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (index < options.keepLast) {
|
|
255
|
+
kept.push({
|
|
256
|
+
id: session.id,
|
|
257
|
+
reason: `within the newest ${String(options.keepLast)}`
|
|
258
|
+
});
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const age = session.modifiedAt.getTime();
|
|
262
|
+
if (Number.isNaN(age)) {
|
|
263
|
+
kept.push({
|
|
264
|
+
id: session.id,
|
|
265
|
+
reason: "modification time unreadable \u2014 age cannot be shown"
|
|
266
|
+
});
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (age >= cutoff) {
|
|
270
|
+
kept.push({
|
|
271
|
+
id: session.id,
|
|
272
|
+
reason: `younger than ${String(options.maxAgeDays)} days`
|
|
273
|
+
});
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
candidates.push({
|
|
277
|
+
id: session.id,
|
|
278
|
+
transcript: session.transcript,
|
|
279
|
+
modifiedAt: session.modifiedAt
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
cwd: options.cwd,
|
|
284
|
+
root,
|
|
285
|
+
candidates,
|
|
286
|
+
kept
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
__name(planTranscriptGC, "planTranscriptGC");
|
|
290
|
+
function runTranscriptGC(plan, options) {
|
|
291
|
+
const removed = [];
|
|
292
|
+
const errors = [];
|
|
293
|
+
const protectedNow = options.apply ? protectedTranscripts(plan.cwd, plan.root) : /* @__PURE__ */ new Map();
|
|
294
|
+
for (const candidate of plan.candidates) {
|
|
295
|
+
if (protectedNow.has(candidate.id)) continue;
|
|
296
|
+
if (!options.apply) {
|
|
297
|
+
removed.push(candidate.id);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
try {
|
|
301
|
+
rmSync2(transcriptPath2(plan.root, plan.cwd, candidate.id));
|
|
302
|
+
removed.push(candidate.id);
|
|
303
|
+
} catch (error) {
|
|
304
|
+
if (error.code === "ENOENT") {
|
|
305
|
+
removed.push(candidate.id);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
errors.push({
|
|
309
|
+
id: candidate.id,
|
|
310
|
+
message: error.message
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
dryRun: !options.apply,
|
|
316
|
+
removed,
|
|
317
|
+
errors
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
__name(runTranscriptGC, "runTranscriptGC");
|
|
321
|
+
export {
|
|
322
|
+
GCFloorError,
|
|
323
|
+
SessionInUseError,
|
|
324
|
+
deleteSession,
|
|
325
|
+
forkBeforeUserTurn,
|
|
326
|
+
listSessions,
|
|
327
|
+
loadOrCreateSessionId,
|
|
328
|
+
persistSessionId,
|
|
329
|
+
planTranscriptGC,
|
|
330
|
+
projectDirFor,
|
|
331
|
+
projectDirMatches,
|
|
332
|
+
protectedTranscripts,
|
|
333
|
+
recordProjectDir,
|
|
334
|
+
resolveProjectDir,
|
|
335
|
+
runTranscriptGC,
|
|
336
|
+
sessionPointerPath
|
|
337
|
+
};
|
|
338
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/session/session-lifecycle.ts","../src/session/project-index.ts","../src/session/session-pointer.ts","../src/session/gc/transcript-gc.ts"],"mappings":"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","names":["readFileSync","readdirSync","rmSync","statSync","join","TheokitAgentError","classifySessionArtifact","forkTranscript","loadJsonl","sessionHasWriter","transcriptPath","transcriptRoot","mkdirSync","readFileSync","writeFileSync","dirname","join","encodeProjectDir","transcriptRoot","CWD_SIDECAR","projectDirFor","cwd","root","transcriptRoot","join","encodeProjectDir","recordProjectDir","sidecar","mkdirSync","dirname","recursive","writeFileSync","resolveProjectDir","encodedName","raw","readFileSync","trim","length","undefined","projectDirMatches","readFileSync","mkdirSync","join","dirname","atomicWriteText","transcriptRoot","POINTER","sessionPointerPath","cwd","root","transcriptRoot","join","projectDirFor","loadOrCreateSessionId","mintId","existing","readFileSync","trim","length","sessionId","resumed","persistSessionId","target","mkdirSync","dirname","recursive","atomicWriteText","persisted","SessionInUseError","TheokitAgentError","name","sessionId","reason","listSessions","cwd","root","transcriptRoot","dir","projectDirFor","entries","readdirSync","found","entry","path","join","isDirectory","modifiedAt","stats","statSync","mtime","kind","classifySessionArtifact","push","id","replace","transcript","sort","a","b","getTime","protectedTranscripts","protectedBy","Map","sessions","pointer","readPointer","undefined","set","length","has","session","hasWriter","sessionHasWriter","readFileSync","sessionPointerPath","trim","deleteSession","options","force","get","transcriptRemoved","rmSync","transcriptPath","registryRemoved","removeFromRegistry","forkBeforeUserTurn","srcId","newId","nth","Number","isInteger","String","src","dst","recordIndex","recordIndexOfUserTurn","forkTranscript","beforeRecordIndex","liveSessionPaths","keys","map","records","loadJsonl","seen","index","record","role","rmSync","TheokitAgentError","transcriptPath","transcriptRoot","FLOOR","keepLast","maxAgeDays","GCFloorError","TheokitAgentError","name","field","received","String","planTranscriptGC","options","Number","isFinite","root","transcriptRoot","now","Date","cutoff","sessions","listSessions","cwd","protectedBy","protectedTranscripts","candidates","kept","index","session","entries","protection","get","id","undefined","push","reason","age","modifiedAt","getTime","isNaN","transcript","runTranscriptGC","plan","removed","errors","protectedNow","apply","Map","candidate","has","rmSync","transcriptPath","error","code","message","dryRun"]}
|