@fungi.computer/shiitake 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +454 -2
- package/dist/agar-extension.d.ts +9 -0
- package/dist/agar-extension.js +38 -0
- package/dist/agent-control.d.ts +72 -0
- package/dist/agent-control.js +431 -0
- package/dist/client-entry.d.ts +211 -0
- package/dist/client-entry.js +101 -0
- package/dist/client-wire.d.ts +199 -0
- package/dist/client-wire.js +271 -0
- package/dist/client.d.ts +439 -0
- package/dist/client.js +4 -0
- package/dist/cloudflare.d.ts +220 -0
- package/dist/cloudflare.js +531 -0
- package/dist/effect.d.ts +42 -0
- package/dist/effect.js +20 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.js +81 -0
- package/dist/extension-client.d.ts +38 -0
- package/dist/extension-client.js +56 -0
- package/dist/extension-contract.d.ts +73 -0
- package/dist/extension-contract.js +11 -0
- package/dist/extensions.d.ts +589 -0
- package/dist/extensions.js +263 -0
- package/dist/fleet.d.ts +297 -0
- package/dist/fleet.js +515 -0
- package/dist/hosted.d.ts +133 -0
- package/dist/hosted.js +265 -0
- package/dist/http-routes.d.ts +772 -0
- package/dist/http-routes.js +242 -0
- package/dist/http.d.ts +1 -0
- package/dist/http.js +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +13 -0
- package/dist/internal/accepted-run-executor.d.ts +23 -0
- package/dist/internal/accepted-run-executor.js +129 -0
- package/dist/internal/admission-door.d.ts +75 -0
- package/dist/internal/admission-door.js +105 -0
- package/dist/internal/agent-close.d.ts +4 -0
- package/dist/internal/agent-close.js +42 -0
- package/dist/internal/browser-sessions.d.ts +31 -0
- package/dist/internal/browser-sessions.js +173 -0
- package/dist/internal/client-boundary.d.ts +262 -0
- package/dist/internal/client-boundary.js +202 -0
- package/dist/internal/compaction/compaction.d.ts +54 -0
- package/dist/internal/compaction/compaction.js +292 -0
- package/dist/internal/compaction/session-compaction.d.ts +69 -0
- package/dist/internal/compaction/session-compaction.js +330 -0
- package/dist/internal/compaction/settings.d.ts +11 -0
- package/dist/internal/compaction/settings.js +40 -0
- package/dist/internal/compaction/utils.d.ts +45 -0
- package/dist/internal/compaction/utils.js +319 -0
- package/dist/internal/contracts.d.ts +235 -0
- package/dist/internal/contracts.js +1 -0
- package/dist/internal/coordinator.d.ts +18 -0
- package/dist/internal/coordinator.js +362 -0
- package/dist/internal/document-codec.d.ts +11 -0
- package/dist/internal/document-codec.js +39 -0
- package/dist/internal/effect-client.d.ts +13 -0
- package/dist/internal/effect-client.js +102 -0
- package/dist/internal/effect-contracts.d.ts +236 -0
- package/dist/internal/effect-contracts.js +2 -0
- package/dist/internal/extension-command-registry.d.ts +11 -0
- package/dist/internal/extension-command-registry.js +29 -0
- package/dist/internal/extension-command-tools.d.ts +17 -0
- package/dist/internal/extension-command-tools.js +50 -0
- package/dist/internal/extension-context.d.ts +25 -0
- package/dist/internal/extension-context.js +35 -0
- package/dist/internal/extension-definitions.d.ts +5 -0
- package/dist/internal/extension-definitions.js +6 -0
- package/dist/internal/extension-hook.d.ts +25 -0
- package/dist/internal/extension-hook.js +46 -0
- package/dist/internal/extension-roster.d.ts +23 -0
- package/dist/internal/extension-roster.js +228 -0
- package/dist/internal/extension-runtime.d.ts +63 -0
- package/dist/internal/extension-runtime.js +1004 -0
- package/dist/internal/failure.d.ts +2 -0
- package/dist/internal/failure.js +9 -0
- package/dist/internal/host-meta.d.ts +41 -0
- package/dist/internal/host-meta.js +39 -0
- package/dist/internal/json-value.d.ts +4 -0
- package/dist/internal/json-value.js +3 -0
- package/dist/internal/model-acquisition.d.ts +21 -0
- package/dist/internal/model-acquisition.js +98 -0
- package/dist/internal/model-preference.d.ts +21 -0
- package/dist/internal/model-preference.js +20 -0
- package/dist/internal/observation-kernel.d.ts +28 -0
- package/dist/internal/observation-kernel.js +169 -0
- package/dist/internal/promise-facade.d.ts +18 -0
- package/dist/internal/promise-facade.js +172 -0
- package/dist/internal/run-scope.d.ts +27 -0
- package/dist/internal/run-scope.js +214 -0
- package/dist/internal/runtime-coordinator.d.ts +34 -0
- package/dist/internal/runtime-coordinator.js +233 -0
- package/dist/internal/runtime-core.d.ts +19 -0
- package/dist/internal/runtime-core.js +39 -0
- package/dist/internal/runtime-reconciliation.d.ts +18 -0
- package/dist/internal/runtime-reconciliation.js +162 -0
- package/dist/internal/session-context.d.ts +11 -0
- package/dist/internal/session-context.js +67 -0
- package/dist/internal/session-status.d.ts +10 -0
- package/dist/internal/session-status.js +52 -0
- package/dist/internal/woodstock/agent-reply.d.ts +25 -0
- package/dist/internal/woodstock/agent-reply.js +67 -0
- package/dist/internal/woodstock/client-projection.d.ts +29 -0
- package/dist/internal/woodstock/client-projection.js +512 -0
- package/dist/internal/woodstock/compaction-activity.d.ts +17 -0
- package/dist/internal/woodstock/compaction-activity.js +32 -0
- package/dist/internal/woodstock/cursor.d.ts +9 -0
- package/dist/internal/woodstock/cursor.js +44 -0
- package/dist/internal/woodstock/extension-store.d.ts +72 -0
- package/dist/internal/woodstock/extension-store.js +262 -0
- package/dist/internal/woodstock/fleet-store.d.ts +32 -0
- package/dist/internal/woodstock/fleet-store.js +93 -0
- package/dist/internal/woodstock/identities.d.ts +6 -0
- package/dist/internal/woodstock/identities.js +11 -0
- package/dist/internal/woodstock/index.d.ts +170 -0
- package/dist/internal/woodstock/index.js +546 -0
- package/dist/internal/woodstock/progress.d.ts +32 -0
- package/dist/internal/woodstock/progress.js +89 -0
- package/dist/internal/woodstock/run-recovery.d.ts +8 -0
- package/dist/internal/woodstock/run-recovery.js +95 -0
- package/dist/internal/woodstock/session-attention.d.ts +16 -0
- package/dist/internal/woodstock/session-attention.js +88 -0
- package/dist/internal/woodstock/session-documents.d.ts +18 -0
- package/dist/internal/woodstock/session-documents.js +51 -0
- package/dist/internal/woodstock/session-entry.d.ts +478 -0
- package/dist/internal/woodstock/session-entry.js +484 -0
- package/dist/internal/woodstock/session-grants.d.ts +24 -0
- package/dist/internal/woodstock/session-grants.js +84 -0
- package/dist/internal/woodstock/session-inbox.d.ts +56 -0
- package/dist/internal/woodstock/session-inbox.js +307 -0
- package/dist/internal/woodstock/session-store.d.ts +432 -0
- package/dist/internal/woodstock/session-store.js +2006 -0
- package/dist/internal/woodstock/storage-admission.d.ts +14 -0
- package/dist/internal/woodstock/storage-admission.js +44 -0
- package/dist/model-preference.d.ts +20 -0
- package/dist/model-preference.js +30 -0
- package/dist/node.d.ts +64 -0
- package/dist/node.js +256 -0
- package/dist/remote-client.d.ts +11 -0
- package/dist/remote-client.js +298 -0
- package/dist/session-attention.d.ts +35 -0
- package/dist/session-attention.js +22 -0
- package/dist/session-documents.d.ts +28 -0
- package/dist/session-documents.js +1 -0
- package/dist/testing.d.ts +54 -0
- package/dist/testing.js +215 -0
- package/docs/api/README.md +26 -0
- package/docs/api/agar-extension.md +40 -0
- package/docs/api/agent-control.md +151 -0
- package/docs/api/client-entry.md +344 -0
- package/docs/api/client.md +1112 -0
- package/docs/api/cloudflare.md +500 -0
- package/docs/api/effect.md +904 -0
- package/docs/api/extensions.md +2003 -0
- package/docs/api/fleet.md +706 -0
- package/docs/api/hosted.md +382 -0
- package/docs/api/http.md +111 -0
- package/docs/api/index.md +1116 -0
- package/docs/api/model-preference.md +151 -0
- package/docs/api/node.md +142 -0
- package/docs/api/testing.md +250 -0
- package/package.json +130 -3
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { SqliteOwner } from "../contracts.js";
|
|
2
|
+
/** Create every extension table. Idempotent `CREATE … IF NOT EXISTS` only. */
|
|
3
|
+
export declare function prepareExtensionStore(owner: SqliteOwner): void;
|
|
4
|
+
/** Read one encoded record value. */
|
|
5
|
+
export declare function readRecord(owner: SqliteOwner, extensionId: string, collection: string, key: string): string | undefined;
|
|
6
|
+
/** Read one key-ordered page of encoded record values. */
|
|
7
|
+
export declare function readRecordPage(owner: SqliteOwner, extensionId: string, collection: string, query: Readonly<{
|
|
8
|
+
index?: string | undefined;
|
|
9
|
+
after?: string | undefined;
|
|
10
|
+
limit: number;
|
|
11
|
+
}>): readonly string[];
|
|
12
|
+
/** Upsert one encoded record. */
|
|
13
|
+
export declare function writeRecord(owner: SqliteOwner, extensionId: string, collection: string, key: string, index: string | null, valueJson: string): void;
|
|
14
|
+
/** Delete one record; absent keys are a no-op. */
|
|
15
|
+
export declare function deleteRecord(owner: SqliteOwner, extensionId: string, collection: string, key: string): void;
|
|
16
|
+
/** Every stored record of one extension, for activation-time migration. */
|
|
17
|
+
export declare function readAllRecords(owner: SqliteOwner, extensionId: string): readonly Readonly<{
|
|
18
|
+
collection: string;
|
|
19
|
+
key: string;
|
|
20
|
+
valueJson: string;
|
|
21
|
+
}>[];
|
|
22
|
+
/** Remove every record of one extension inside a migration transaction. */
|
|
23
|
+
export declare function deleteAllRecords(owner: SqliteOwner, extensionId: string): void;
|
|
24
|
+
/** Stored state version and the revision that last wrote it. */
|
|
25
|
+
export declare function readStateLedger(owner: SqliteOwner, extensionId: string): Readonly<{
|
|
26
|
+
version: number;
|
|
27
|
+
revision: string;
|
|
28
|
+
}> | undefined;
|
|
29
|
+
/** Record the state version an activation migrated to. */
|
|
30
|
+
export declare function writeStateLedger(owner: SqliteOwner, extensionId: string, version: number, revision: string): void;
|
|
31
|
+
/** Durable running/stopped state of one extension. */
|
|
32
|
+
export type StoredExtensionStatus = Readonly<{
|
|
33
|
+
status: "running" | "stopped";
|
|
34
|
+
reason: string | null;
|
|
35
|
+
stoppedAt: number | null;
|
|
36
|
+
revision: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** Read one extension's durable status. */
|
|
39
|
+
export declare function readStatus(owner: SqliteOwner, extensionId: string): StoredExtensionStatus | undefined;
|
|
40
|
+
/** Write one extension's durable status. */
|
|
41
|
+
export declare function writeStatus(owner: SqliteOwner, extensionId: string, status: StoredExtensionStatus): void;
|
|
42
|
+
/** Upsert one timer. */
|
|
43
|
+
export declare function writeTimer(owner: SqliteOwner, extensionId: string, key: string, dueAt: number): void;
|
|
44
|
+
/** Delete one timer; absent keys are a no-op. */
|
|
45
|
+
export declare function deleteTimer(owner: SqliteOwner, extensionId: string, key: string): void;
|
|
46
|
+
/** Read one timer's due instant. */
|
|
47
|
+
export declare function readTimer(owner: SqliteOwner, extensionId: string, key: string): number | undefined;
|
|
48
|
+
/** Due timers of the given extensions, oldest first, bounded by `limit`. */
|
|
49
|
+
export declare function readDueTimers(owner: SqliteOwner, extensionIds: readonly string[], now: number, limit: number): readonly Readonly<{
|
|
50
|
+
extensionId: string;
|
|
51
|
+
key: string;
|
|
52
|
+
dueAt: number;
|
|
53
|
+
}>[];
|
|
54
|
+
/** Whether a timer is due now, and the next future timer instant. */
|
|
55
|
+
export type TimerWake = Readonly<{
|
|
56
|
+
due: boolean;
|
|
57
|
+
nextWakeAt: number | null;
|
|
58
|
+
}>;
|
|
59
|
+
/** Whether a timer of the given extensions is due, and the next future one. */
|
|
60
|
+
export declare function readTimerWake(owner: SqliteOwner, extensionIds: readonly string[], now: number): TimerWake;
|
|
61
|
+
/**
|
|
62
|
+
* The one durable settled cursor table: one row per consumer (`core` or an
|
|
63
|
+
* extension identity).
|
|
64
|
+
*
|
|
65
|
+
* Watchdog's settled `sequence` is the enqueue order, not the settle order.
|
|
66
|
+
* Watchdog exposes only the settled prefix below the first unfinished serial
|
|
67
|
+
* row. That fence makes this high-water cursor exact across queue skips and
|
|
68
|
+
* concurrent delivery. Stream order is enqueue order, not completion order.
|
|
69
|
+
*/
|
|
70
|
+
export declare function readCursor(owner: SqliteOwner, consumer: string): number | undefined;
|
|
71
|
+
/** Advance one consumer's cursor; it never moves backwards. */
|
|
72
|
+
export declare function advanceCursor(owner: SqliteOwner, consumer: string, sequence: number): void;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
import { ShiitakeError } from "../../errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Core-owned durability for rostered v1 extensions.
|
|
5
|
+
*
|
|
6
|
+
* Every table is namespaced by extension identity, and only core writes SQL.
|
|
7
|
+
* An extension sees typed collections, timers and its own settled cursor
|
|
8
|
+
* through the runtime; it never receives this owner.
|
|
9
|
+
*/
|
|
10
|
+
const Text = Schema.String.pipe(Schema.check(Schema.isMinLength(1)));
|
|
11
|
+
const Instant = Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0)));
|
|
12
|
+
const closed = { onExcessProperty: "error" };
|
|
13
|
+
const ValueRowSchema = Schema.Struct({ value_json: Schema.String });
|
|
14
|
+
const StateRowSchema = Schema.Struct({
|
|
15
|
+
state_version: Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(1))),
|
|
16
|
+
revision: Text,
|
|
17
|
+
});
|
|
18
|
+
const StatusRowSchema = Schema.Struct({
|
|
19
|
+
status: Schema.Literals(["running", "stopped"]),
|
|
20
|
+
reason: Schema.NullOr(Schema.String),
|
|
21
|
+
stopped_at: Schema.NullOr(Instant),
|
|
22
|
+
revision: Text,
|
|
23
|
+
});
|
|
24
|
+
const TimerRowSchema = Schema.Struct({
|
|
25
|
+
extension_id: Text,
|
|
26
|
+
key: Text,
|
|
27
|
+
due_at: Instant,
|
|
28
|
+
});
|
|
29
|
+
const StoredRecordRowSchema = Schema.Struct({
|
|
30
|
+
collection: Text,
|
|
31
|
+
key: Text,
|
|
32
|
+
value_json: Schema.String,
|
|
33
|
+
});
|
|
34
|
+
const CursorRowSchema = Schema.Struct({ sequence: Instant });
|
|
35
|
+
const WakeRowSchema = Schema.Struct({
|
|
36
|
+
due: Schema.Literals([0, 1]),
|
|
37
|
+
next_due_at: Schema.NullOr(Instant),
|
|
38
|
+
});
|
|
39
|
+
function unavailable(message) {
|
|
40
|
+
return new ShiitakeError("store", "unavailable", message);
|
|
41
|
+
}
|
|
42
|
+
function decodeRows(schema, rows, message) {
|
|
43
|
+
const decode = Schema.decodeUnknownResult(schema, closed);
|
|
44
|
+
return rows.map((row) => {
|
|
45
|
+
const decoded = decode(row);
|
|
46
|
+
if (decoded._tag === "Failure")
|
|
47
|
+
throw unavailable(message);
|
|
48
|
+
return decoded.success;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Create every extension table. Idempotent `CREATE … IF NOT EXISTS` only. */
|
|
52
|
+
export function prepareExtensionStore(owner) {
|
|
53
|
+
owner.transactionSync(() => {
|
|
54
|
+
owner.sql.exec(`CREATE TABLE IF NOT EXISTS shiitake_extension_records (
|
|
55
|
+
extension_id TEXT NOT NULL,
|
|
56
|
+
collection TEXT NOT NULL,
|
|
57
|
+
key TEXT NOT NULL,
|
|
58
|
+
index_value TEXT,
|
|
59
|
+
value_json TEXT NOT NULL,
|
|
60
|
+
PRIMARY KEY (extension_id, collection, key)
|
|
61
|
+
)`);
|
|
62
|
+
owner.sql
|
|
63
|
+
.exec(`CREATE INDEX IF NOT EXISTS idx_shiitake_extension_records_index
|
|
64
|
+
ON shiitake_extension_records(extension_id, collection, index_value, key)`);
|
|
65
|
+
owner.sql.exec(`CREATE TABLE IF NOT EXISTS shiitake_extension_state (
|
|
66
|
+
extension_id TEXT PRIMARY KEY,
|
|
67
|
+
state_version INTEGER NOT NULL CHECK (state_version >= 1),
|
|
68
|
+
revision TEXT NOT NULL
|
|
69
|
+
)`);
|
|
70
|
+
owner.sql.exec(`CREATE TABLE IF NOT EXISTS shiitake_extension_status (
|
|
71
|
+
extension_id TEXT PRIMARY KEY,
|
|
72
|
+
status TEXT NOT NULL CHECK (status IN ('running', 'stopped')),
|
|
73
|
+
reason TEXT,
|
|
74
|
+
stopped_at INTEGER,
|
|
75
|
+
revision TEXT NOT NULL,
|
|
76
|
+
CHECK ((status = 'running') = (reason IS NULL)),
|
|
77
|
+
CHECK ((reason IS NULL) = (stopped_at IS NULL))
|
|
78
|
+
)`);
|
|
79
|
+
owner.sql.exec(`CREATE TABLE IF NOT EXISTS shiitake_extension_timers (
|
|
80
|
+
extension_id TEXT NOT NULL,
|
|
81
|
+
key TEXT NOT NULL,
|
|
82
|
+
due_at INTEGER NOT NULL CHECK (due_at >= 0),
|
|
83
|
+
PRIMARY KEY (extension_id, key)
|
|
84
|
+
)`);
|
|
85
|
+
owner.sql.exec(`CREATE INDEX IF NOT EXISTS idx_shiitake_extension_timers_due
|
|
86
|
+
ON shiitake_extension_timers(due_at, extension_id, key)`);
|
|
87
|
+
owner.sql.exec(`CREATE TABLE IF NOT EXISTS shiitake_settled_cursors (
|
|
88
|
+
consumer TEXT PRIMARY KEY,
|
|
89
|
+
sequence INTEGER NOT NULL CHECK (sequence >= 0)
|
|
90
|
+
)`);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// ---------- records ------------------------------------------------------------
|
|
94
|
+
/** Read one encoded record value. */
|
|
95
|
+
export function readRecord(owner, extensionId, collection, key) {
|
|
96
|
+
const rows = owner.sql
|
|
97
|
+
.exec(`SELECT value_json FROM shiitake_extension_records
|
|
98
|
+
WHERE extension_id = ? AND collection = ? AND key = ?`, extensionId, collection, key)
|
|
99
|
+
.toArray();
|
|
100
|
+
return decodeRows(ValueRowSchema, rows, "Stored extension record is invalid")[0]?.value_json;
|
|
101
|
+
}
|
|
102
|
+
/** Read one key-ordered page of encoded record values. */
|
|
103
|
+
export function readRecordPage(owner, extensionId, collection, query) {
|
|
104
|
+
const rows = owner.sql
|
|
105
|
+
.exec(`SELECT value_json FROM shiitake_extension_records
|
|
106
|
+
WHERE extension_id = ? AND collection = ?
|
|
107
|
+
AND (? IS NULL OR index_value = ?)
|
|
108
|
+
AND (? IS NULL OR key > ?)
|
|
109
|
+
ORDER BY key LIMIT ?`, extensionId, collection, query.index ?? null, query.index ?? null, query.after ?? null, query.after ?? null, query.limit)
|
|
110
|
+
.toArray();
|
|
111
|
+
return decodeRows(ValueRowSchema, rows, "Stored extension record is invalid").map(({ value_json }) => value_json);
|
|
112
|
+
}
|
|
113
|
+
/** Upsert one encoded record. */
|
|
114
|
+
export function writeRecord(owner, extensionId, collection, key, index, valueJson) {
|
|
115
|
+
owner.sql.exec(`INSERT INTO shiitake_extension_records
|
|
116
|
+
(extension_id, collection, key, index_value, value_json)
|
|
117
|
+
VALUES (?, ?, ?, ?, ?)
|
|
118
|
+
ON CONFLICT(extension_id, collection, key) DO UPDATE SET
|
|
119
|
+
index_value = excluded.index_value, value_json = excluded.value_json`, extensionId, collection, key, index, valueJson);
|
|
120
|
+
}
|
|
121
|
+
/** Delete one record; absent keys are a no-op. */
|
|
122
|
+
export function deleteRecord(owner, extensionId, collection, key) {
|
|
123
|
+
owner.sql.exec(`DELETE FROM shiitake_extension_records
|
|
124
|
+
WHERE extension_id = ? AND collection = ? AND key = ?`, extensionId, collection, key);
|
|
125
|
+
}
|
|
126
|
+
/** Every stored record of one extension, for activation-time migration. */
|
|
127
|
+
export function readAllRecords(owner, extensionId) {
|
|
128
|
+
const rows = owner.sql
|
|
129
|
+
.exec(`SELECT collection, key, value_json FROM shiitake_extension_records
|
|
130
|
+
WHERE extension_id = ? ORDER BY collection, key`, extensionId)
|
|
131
|
+
.toArray();
|
|
132
|
+
return decodeRows(StoredRecordRowSchema, rows, "Stored extension record is invalid").map((row) => ({
|
|
133
|
+
collection: row.collection,
|
|
134
|
+
key: row.key,
|
|
135
|
+
valueJson: row.value_json,
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
/** Remove every record of one extension inside a migration transaction. */
|
|
139
|
+
export function deleteAllRecords(owner, extensionId) {
|
|
140
|
+
owner.sql.exec("DELETE FROM shiitake_extension_records WHERE extension_id = ?", extensionId);
|
|
141
|
+
}
|
|
142
|
+
// ---------- migration ledger ---------------------------------------------------
|
|
143
|
+
/** Stored state version and the revision that last wrote it. */
|
|
144
|
+
export function readStateLedger(owner, extensionId) {
|
|
145
|
+
const rows = owner.sql
|
|
146
|
+
.exec(`SELECT state_version, revision FROM shiitake_extension_state
|
|
147
|
+
WHERE extension_id = ?`, extensionId)
|
|
148
|
+
.toArray();
|
|
149
|
+
const row = decodeRows(StateRowSchema, rows, "Extension ledger is invalid")[0];
|
|
150
|
+
return row === undefined
|
|
151
|
+
? undefined
|
|
152
|
+
: { version: row.state_version, revision: row.revision };
|
|
153
|
+
}
|
|
154
|
+
/** Record the state version an activation migrated to. */
|
|
155
|
+
export function writeStateLedger(owner, extensionId, version, revision) {
|
|
156
|
+
owner.sql.exec(`INSERT INTO shiitake_extension_state (extension_id, state_version, revision)
|
|
157
|
+
VALUES (?, ?, ?)
|
|
158
|
+
ON CONFLICT(extension_id) DO UPDATE SET
|
|
159
|
+
state_version = excluded.state_version, revision = excluded.revision`, extensionId, version, revision);
|
|
160
|
+
}
|
|
161
|
+
/** Read one extension's durable status. */
|
|
162
|
+
export function readStatus(owner, extensionId) {
|
|
163
|
+
const rows = owner.sql
|
|
164
|
+
.exec(`SELECT status, reason, stopped_at, revision FROM shiitake_extension_status
|
|
165
|
+
WHERE extension_id = ?`, extensionId)
|
|
166
|
+
.toArray();
|
|
167
|
+
const row = decodeRows(StatusRowSchema, rows, "Extension status is invalid")[0];
|
|
168
|
+
return row === undefined
|
|
169
|
+
? undefined
|
|
170
|
+
: {
|
|
171
|
+
status: row.status,
|
|
172
|
+
reason: row.reason,
|
|
173
|
+
stoppedAt: row.stopped_at,
|
|
174
|
+
revision: row.revision,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/** Write one extension's durable status. */
|
|
178
|
+
export function writeStatus(owner, extensionId, status) {
|
|
179
|
+
owner.sql.exec(`INSERT INTO shiitake_extension_status
|
|
180
|
+
(extension_id, status, reason, stopped_at, revision)
|
|
181
|
+
VALUES (?, ?, ?, ?, ?)
|
|
182
|
+
ON CONFLICT(extension_id) DO UPDATE SET status = excluded.status,
|
|
183
|
+
reason = excluded.reason, stopped_at = excluded.stopped_at,
|
|
184
|
+
revision = excluded.revision`, extensionId, status.status, status.reason, status.stoppedAt, status.revision);
|
|
185
|
+
}
|
|
186
|
+
// ---------- timers -------------------------------------------------------------
|
|
187
|
+
/** Upsert one timer. */
|
|
188
|
+
export function writeTimer(owner, extensionId, key, dueAt) {
|
|
189
|
+
owner.sql.exec(`INSERT INTO shiitake_extension_timers (extension_id, key, due_at)
|
|
190
|
+
VALUES (?, ?, ?)
|
|
191
|
+
ON CONFLICT(extension_id, key) DO UPDATE SET due_at = excluded.due_at`, extensionId, key, dueAt);
|
|
192
|
+
}
|
|
193
|
+
/** Delete one timer; absent keys are a no-op. */
|
|
194
|
+
export function deleteTimer(owner, extensionId, key) {
|
|
195
|
+
owner.sql.exec("DELETE FROM shiitake_extension_timers WHERE extension_id = ? AND key = ?", extensionId, key);
|
|
196
|
+
}
|
|
197
|
+
/** Read one timer's due instant. */
|
|
198
|
+
export function readTimer(owner, extensionId, key) {
|
|
199
|
+
const rows = owner.sql
|
|
200
|
+
.exec(`SELECT extension_id, key, due_at FROM shiitake_extension_timers
|
|
201
|
+
WHERE extension_id = ? AND key = ?`, extensionId, key)
|
|
202
|
+
.toArray();
|
|
203
|
+
return decodeRows(TimerRowSchema, rows, "Extension timer is invalid")[0]
|
|
204
|
+
?.due_at;
|
|
205
|
+
}
|
|
206
|
+
function placeholders(values) {
|
|
207
|
+
return values.map(() => "?").join(", ");
|
|
208
|
+
}
|
|
209
|
+
/** Due timers of the given extensions, oldest first, bounded by `limit`. */
|
|
210
|
+
export function readDueTimers(owner, extensionIds, now, limit) {
|
|
211
|
+
if (extensionIds.length === 0)
|
|
212
|
+
return [];
|
|
213
|
+
const rows = owner.sql
|
|
214
|
+
.exec(`SELECT extension_id, key, due_at FROM shiitake_extension_timers
|
|
215
|
+
WHERE due_at <= ? AND extension_id IN (${placeholders(extensionIds)})
|
|
216
|
+
ORDER BY due_at, extension_id, key LIMIT ?`, now, ...extensionIds, limit)
|
|
217
|
+
.toArray();
|
|
218
|
+
return decodeRows(TimerRowSchema, rows, "Extension timer is invalid").map((row) => ({
|
|
219
|
+
extensionId: row.extension_id,
|
|
220
|
+
key: row.key,
|
|
221
|
+
dueAt: row.due_at,
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
/** Whether a timer of the given extensions is due, and the next future one. */
|
|
225
|
+
export function readTimerWake(owner, extensionIds, now) {
|
|
226
|
+
if (extensionIds.length === 0)
|
|
227
|
+
return { due: false, nextWakeAt: null };
|
|
228
|
+
const ids = placeholders(extensionIds);
|
|
229
|
+
const rows = owner.sql
|
|
230
|
+
.exec(`SELECT
|
|
231
|
+
EXISTS (SELECT 1 FROM shiitake_extension_timers
|
|
232
|
+
WHERE due_at <= ? AND extension_id IN (${ids})) AS due,
|
|
233
|
+
(SELECT MIN(due_at) FROM shiitake_extension_timers
|
|
234
|
+
WHERE due_at > ? AND extension_id IN (${ids})) AS next_due_at`, now, ...extensionIds, now, ...extensionIds)
|
|
235
|
+
.toArray();
|
|
236
|
+
const row = decodeRows(WakeRowSchema, rows, "Extension timer is invalid")[0];
|
|
237
|
+
if (row === undefined)
|
|
238
|
+
throw unavailable("Extension timer is unavailable");
|
|
239
|
+
return { due: row.due === 1, nextWakeAt: row.next_due_at };
|
|
240
|
+
}
|
|
241
|
+
// ---------- settled cursors ----------------------------------------------------
|
|
242
|
+
/**
|
|
243
|
+
* The one durable settled cursor table: one row per consumer (`core` or an
|
|
244
|
+
* extension identity).
|
|
245
|
+
*
|
|
246
|
+
* Watchdog's settled `sequence` is the enqueue order, not the settle order.
|
|
247
|
+
* Watchdog exposes only the settled prefix below the first unfinished serial
|
|
248
|
+
* row. That fence makes this high-water cursor exact across queue skips and
|
|
249
|
+
* concurrent delivery. Stream order is enqueue order, not completion order.
|
|
250
|
+
*/
|
|
251
|
+
export function readCursor(owner, consumer) {
|
|
252
|
+
const rows = owner.sql
|
|
253
|
+
.exec("SELECT sequence FROM shiitake_settled_cursors WHERE consumer = ?", consumer)
|
|
254
|
+
.toArray();
|
|
255
|
+
return decodeRows(CursorRowSchema, rows, "Settled cursor is invalid")[0]
|
|
256
|
+
?.sequence;
|
|
257
|
+
}
|
|
258
|
+
/** Advance one consumer's cursor; it never moves backwards. */
|
|
259
|
+
export function advanceCursor(owner, consumer, sequence) {
|
|
260
|
+
owner.sql.exec(`INSERT INTO shiitake_settled_cursors (consumer, sequence) VALUES (?, ?)
|
|
261
|
+
ON CONFLICT(consumer) DO UPDATE SET sequence = MAX(sequence, excluded.sequence)`, consumer, sequence);
|
|
262
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { WatchdogSqliteOwner } from "@fungi.computer/watchdog";
|
|
2
|
+
/** Fleet identity and receipt storage; the caller owns the enclosing transaction. */
|
|
3
|
+
export declare function createFleetDirectoryStore(sql: WatchdogSqliteOwner["sql"]): {
|
|
4
|
+
read: (agentId: string) => {
|
|
5
|
+
readonly [x: string]: string | number | ArrayBuffer | null;
|
|
6
|
+
} | undefined;
|
|
7
|
+
readReceipt: (requestId: string) => {
|
|
8
|
+
readonly [x: string]: string | number | ArrayBuffer | null;
|
|
9
|
+
} | undefined;
|
|
10
|
+
findByName: (name: string) => {
|
|
11
|
+
readonly [x: string]: string | number | ArrayBuffer | null;
|
|
12
|
+
} | undefined;
|
|
13
|
+
reserve(agentId: string, name: string, actorUserId: string, now: number, requestId: string, configuration: string): void;
|
|
14
|
+
list: () => readonly {
|
|
15
|
+
readonly [x: string]: string | number | ArrayBuffer | null;
|
|
16
|
+
}[];
|
|
17
|
+
rename(agentId: string, name: string, now: number): void;
|
|
18
|
+
listErasureIds: () => readonly string[];
|
|
19
|
+
erasureRosterComplete: () => boolean;
|
|
20
|
+
readCreator: (agentId: string) => {
|
|
21
|
+
readonly [x: string]: string | number | ArrayBuffer | null;
|
|
22
|
+
} | undefined;
|
|
23
|
+
remove(agentId: string): void;
|
|
24
|
+
};
|
|
25
|
+
/** Durable correspondence is frozen before delivery; retries reuse the same row. */
|
|
26
|
+
export declare function createFleetDelegationStore(storage: WatchdogSqliteOwner): {
|
|
27
|
+
read: (requestId: string) => {
|
|
28
|
+
readonly [x: string]: string | number | ArrayBuffer | null;
|
|
29
|
+
} | undefined;
|
|
30
|
+
reserve(requestId: string, input: string, mail: string): void;
|
|
31
|
+
recordReceipt(requestId: string, receipt: string): void;
|
|
32
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Fleet identity and receipt storage; the caller owns the enclosing transaction. */
|
|
3
|
+
export function createFleetDirectoryStore(sql) {
|
|
4
|
+
const input = { sql };
|
|
5
|
+
input.sql.exec(`CREATE TABLE IF NOT EXISTS hub_team_agents (
|
|
6
|
+
agent_id TEXT PRIMARY KEY,
|
|
7
|
+
name TEXT NOT NULL UNIQUE,
|
|
8
|
+
actor_user_id TEXT NOT NULL,
|
|
9
|
+
created_at INTEGER NOT NULL,
|
|
10
|
+
updated_at INTEGER NOT NULL
|
|
11
|
+
) STRICT`);
|
|
12
|
+
input.sql.exec(`CREATE TABLE IF NOT EXISTS hub_team_agent_create_receipts (
|
|
13
|
+
request_id TEXT PRIMARY KEY,
|
|
14
|
+
actor_user_id TEXT NOT NULL,
|
|
15
|
+
name TEXT NOT NULL,
|
|
16
|
+
agent_id TEXT NOT NULL,
|
|
17
|
+
computer_mode TEXT NOT NULL,
|
|
18
|
+
FOREIGN KEY (agent_id) REFERENCES hub_team_agents (agent_id)
|
|
19
|
+
) STRICT`);
|
|
20
|
+
// Team erasure must retain the DO address after a directory removal.
|
|
21
|
+
input.sql.exec(`CREATE TABLE IF NOT EXISTS hub_team_agent_erasure_ids (
|
|
22
|
+
agent_id TEXT PRIMARY KEY
|
|
23
|
+
) STRICT`);
|
|
24
|
+
input.sql.exec(`CREATE TABLE IF NOT EXISTS hub_team_agent_erasure_scope (
|
|
25
|
+
singleton INTEGER PRIMARY KEY CHECK(singleton=1),
|
|
26
|
+
complete INTEGER NOT NULL CHECK(complete IN (0,1))
|
|
27
|
+
) STRICT`);
|
|
28
|
+
input.sql.exec("INSERT OR IGNORE INTO hub_team_agent_erasure_scope(singleton,complete) VALUES (1,1)");
|
|
29
|
+
return {
|
|
30
|
+
read: (agentId) => input.sql
|
|
31
|
+
.exec("SELECT agent_id, name, actor_user_id, created_at, updated_at FROM hub_team_agents WHERE agent_id = ?", agentId)
|
|
32
|
+
.toArray()[0],
|
|
33
|
+
readReceipt: (requestId) => input.sql
|
|
34
|
+
.exec("SELECT request_id, actor_user_id, name, agent_id, computer_mode FROM hub_team_agent_create_receipts WHERE request_id = ?", requestId)
|
|
35
|
+
.toArray()[0],
|
|
36
|
+
findByName: (name) => input.sql
|
|
37
|
+
.exec("SELECT agent_id, name, actor_user_id, created_at, updated_at FROM hub_team_agents WHERE name = ?", name)
|
|
38
|
+
.toArray()[0],
|
|
39
|
+
reserve(agentId, name, actorUserId, now, requestId, configuration) {
|
|
40
|
+
input.sql.exec("INSERT INTO hub_team_agents (agent_id, name, actor_user_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?)", agentId, name, actorUserId, now, now);
|
|
41
|
+
input.sql.exec("INSERT INTO hub_team_agent_erasure_ids(agent_id) VALUES (?)", agentId);
|
|
42
|
+
input.sql.exec("INSERT INTO hub_team_agent_create_receipts (request_id, actor_user_id, name, agent_id, computer_mode) VALUES (?, ?, ?, ?, ?)", requestId, actorUserId, name, agentId, configuration);
|
|
43
|
+
},
|
|
44
|
+
list: () => input.sql
|
|
45
|
+
.exec("SELECT agent_id, name, actor_user_id, created_at, updated_at FROM hub_team_agents ORDER BY created_at DESC, agent_id DESC")
|
|
46
|
+
.toArray(),
|
|
47
|
+
rename(agentId, name, now) {
|
|
48
|
+
input.sql.exec("UPDATE hub_team_agents SET name = ?, updated_at = ? WHERE agent_id = ?", name, now, agentId);
|
|
49
|
+
},
|
|
50
|
+
listErasureIds,
|
|
51
|
+
erasureRosterComplete,
|
|
52
|
+
readCreator: (agentId) => input.sql
|
|
53
|
+
.exec("SELECT actor_user_id FROM hub_team_agents WHERE agent_id = ?", agentId)
|
|
54
|
+
.toArray()[0],
|
|
55
|
+
remove(agentId) {
|
|
56
|
+
input.sql.exec("DELETE FROM hub_team_agent_create_receipts WHERE agent_id = ?", agentId);
|
|
57
|
+
input.sql.exec("DELETE FROM hub_team_agents WHERE agent_id = ?", agentId);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
function listErasureIds() {
|
|
61
|
+
return input.sql
|
|
62
|
+
.exec("SELECT agent_id FROM hub_team_agent_erasure_ids ORDER BY agent_id")
|
|
63
|
+
.toArray()
|
|
64
|
+
.map(({ agent_id }) => z.string().parse(agent_id));
|
|
65
|
+
}
|
|
66
|
+
function erasureRosterComplete() {
|
|
67
|
+
const row = input.sql
|
|
68
|
+
.exec("SELECT complete FROM hub_team_agent_erasure_scope WHERE singleton=1")
|
|
69
|
+
.toArray()[0];
|
|
70
|
+
return row?.complete === 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Durable correspondence is frozen before delivery; retries reuse the same row. */
|
|
74
|
+
export function createFleetDelegationStore(storage) {
|
|
75
|
+
storage.sql.exec(`CREATE TABLE IF NOT EXISTS shiitake_fleet_delegations (
|
|
76
|
+
request_id TEXT PRIMARY KEY, input TEXT NOT NULL, mail TEXT NOT NULL, receipt TEXT
|
|
77
|
+
) STRICT`);
|
|
78
|
+
return {
|
|
79
|
+
read: (requestId) => storage.sql
|
|
80
|
+
.exec("SELECT input, mail, receipt FROM shiitake_fleet_delegations WHERE request_id = ?", requestId)
|
|
81
|
+
.toArray()[0],
|
|
82
|
+
reserve(requestId, input, mail) {
|
|
83
|
+
storage.transactionSync(() => {
|
|
84
|
+
storage.sql.exec("INSERT OR IGNORE INTO shiitake_fleet_delegations(request_id, input, mail) VALUES (?, ?, ?)", requestId, input, mail);
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
recordReceipt(requestId, receipt) {
|
|
88
|
+
storage.transactionSync(() => {
|
|
89
|
+
storage.sql.exec("UPDATE shiitake_fleet_delegations SET receipt = ? WHERE request_id = ?", receipt, requestId);
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const sessionIds: Readonly<{
|
|
2
|
+
readonly session: import("@fungi.computer/cairn").IdCodec<"session", "session", 1>;
|
|
3
|
+
readonly work: import("@fungi.computer/cairn").IdCodec<"session", "work", 1>;
|
|
4
|
+
readonly fact: import("@fungi.computer/cairn").IdCodec<"session", "fact", 1>;
|
|
5
|
+
readonly receipt: import("@fungi.computer/cairn").IdCodec<"session", "receipt", 1>;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineIdFamily } from "@fungi.computer/cairn";
|
|
2
|
+
export const sessionIds = defineIdFamily({
|
|
3
|
+
family: "session",
|
|
4
|
+
version: 1,
|
|
5
|
+
kinds: {
|
|
6
|
+
session: { prefix: "session" },
|
|
7
|
+
work: { prefix: "session_work" },
|
|
8
|
+
fact: { prefix: "session_fact" },
|
|
9
|
+
receipt: { prefix: "session_receipt" },
|
|
10
|
+
},
|
|
11
|
+
});
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { SandboxFailureEvent } from "@fungi.computer/mycelium";
|
|
2
|
+
import type { Json } from "../../extensions.js";
|
|
3
|
+
import type { MuleError, MuleIdentity, MuleListener } from "@fungi.computer/mule/effect";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import type * as Scope from "effect/Scope";
|
|
6
|
+
import type { ReadOptions, SessionExtensionSlots, SessionSnapshot } from "../../client.js";
|
|
7
|
+
import { ShiitakeError } from "../../errors.js";
|
|
8
|
+
import type { CommandSettlement, SqliteOwner } from "../contracts.js";
|
|
9
|
+
import type { ObservedActivity } from "../session-status.js";
|
|
10
|
+
import { type ClientReplayPage } from "./client-projection.js";
|
|
11
|
+
import { type LiveRetryEvent } from "./session-entry.js";
|
|
12
|
+
import { type CompactionNoticeInput, type AcceptedCommand, type EnqueueAcceptedWork, type AppendCompactionInput, type PreparedSessionRun, type RunContract, type RecordAcceptedCancellation, type SessionQueueHead, type StoredSessionRow } from "./session-store.js";
|
|
13
|
+
export * from "./extension-store.js";
|
|
14
|
+
export { createFleetDirectoryStore, createFleetDelegationStore, } from "./fleet-store.js";
|
|
15
|
+
export * from "./session-attention.js";
|
|
16
|
+
export { deliverSessionGrants, prepareSessionGrants, readSessionGrants, type GrantsDelivery, type GrantsDeliveryResult, } from "./session-grants.js";
|
|
17
|
+
export * from "./progress.js";
|
|
18
|
+
export * from "./compaction-activity.js";
|
|
19
|
+
export * from "./agent-reply.js";
|
|
20
|
+
export * from "./session-entry.js";
|
|
21
|
+
export * from "./session-store.js";
|
|
22
|
+
export * from "./session-inbox.js";
|
|
23
|
+
export { contextMessageIds } from "./run-recovery.js";
|
|
24
|
+
export * from "./storage-admission.js";
|
|
25
|
+
/** Record one compaction notice and publish it to observers. */
|
|
26
|
+
export declare function appendCompactionNotice(owner: SqliteOwner, input: CompactionNoticeInput): StoredSessionRow;
|
|
27
|
+
/** Append compaction through Woodstock's ordinary owner-observation boundary. */
|
|
28
|
+
export declare function appendCompactionTransition(owner: SqliteOwner, input: AppendCompactionInput): StoredSessionRow;
|
|
29
|
+
/** Prepare Woodstock's retained Session and private admission schema. */
|
|
30
|
+
export declare function prepareWoodstockSchema(owner: SqliteOwner): Effect.Effect<void, ShiitakeError>;
|
|
31
|
+
/** Atomically cancel one exact owner-issued command. */
|
|
32
|
+
export declare function cancelSession(owner: SqliteOwner, sessionId: string, commandId: string, onlyIfPending: boolean | undefined, readQueueHead: () => SessionQueueHead, record: RecordAcceptedCancellation, meta: Json | undefined): Effect.Effect<Readonly<{
|
|
33
|
+
accepted: Readonly<{
|
|
34
|
+
commandId: string;
|
|
35
|
+
entryId: string;
|
|
36
|
+
}>;
|
|
37
|
+
delivery: "new" | "replay";
|
|
38
|
+
active: boolean;
|
|
39
|
+
}> | undefined, ShiitakeError, never>;
|
|
40
|
+
/** Deliver one pending control through an active Mule safe point. */
|
|
41
|
+
export declare function takeSessionControls(owner: SqliteOwner, input: Readonly<{
|
|
42
|
+
sessionId: string;
|
|
43
|
+
workId: string;
|
|
44
|
+
delivery: "steer" | "followUp";
|
|
45
|
+
}>): Effect.Effect<readonly Readonly<{
|
|
46
|
+
workId: string;
|
|
47
|
+
requestId: string;
|
|
48
|
+
message: import("@fungi.computer/mule/effect").Message;
|
|
49
|
+
}>[], ShiitakeError>;
|
|
50
|
+
/** Record terminals for controls delivered through one settled parent run. */
|
|
51
|
+
export declare function settleControls(owner: SqliteOwner, input: Readonly<{
|
|
52
|
+
sessionId: string;
|
|
53
|
+
parentWorkId: string;
|
|
54
|
+
outcome: "completed" | "cancelled" | "failed" | "interrupted";
|
|
55
|
+
enqueue: EnqueueAcceptedWork;
|
|
56
|
+
}>): Effect.Effect<void, ShiitakeError>;
|
|
57
|
+
/** Resolve Session-scoped abort to private work and record it atomically. */
|
|
58
|
+
export declare function abortSession(owner: SqliteOwner, sessionId: string, readQueueHead: () => SessionQueueHead, record: RecordAcceptedCancellation, meta?: Json): Effect.Effect<Readonly<{
|
|
59
|
+
commandId: string;
|
|
60
|
+
entryId: string;
|
|
61
|
+
}> | undefined, ShiitakeError, never>;
|
|
62
|
+
/** Select one complete entry as the active Session lineage leaf. */
|
|
63
|
+
export declare function branchSession(owner: SqliteOwner, input: Readonly<{
|
|
64
|
+
sessionId: string;
|
|
65
|
+
type: "branch";
|
|
66
|
+
entryId: string;
|
|
67
|
+
assertIdleSession: (queue: string) => void;
|
|
68
|
+
}>): Effect.Effect<void, ShiitakeError>;
|
|
69
|
+
/** Record one operator or party line on an idle Session; false on replay. */
|
|
70
|
+
export declare function recordOperatorLine(owner: SqliteOwner, input: Readonly<{
|
|
71
|
+
sessionId: string;
|
|
72
|
+
requestId: string;
|
|
73
|
+
author: "operator" | "party";
|
|
74
|
+
meta: Json | undefined;
|
|
75
|
+
text: string;
|
|
76
|
+
assertIdleSession: (queue: string) => void;
|
|
77
|
+
}>): Effect.Effect<void, ShiitakeError>;
|
|
78
|
+
/** Fork one complete entry lineage into a new cold-readable Session. */
|
|
79
|
+
export declare function forkSession(owner: SqliteOwner, input: Readonly<{
|
|
80
|
+
sessionId: string;
|
|
81
|
+
type: "fork";
|
|
82
|
+
entryId: string;
|
|
83
|
+
assertIdleSession: (queue: string) => void;
|
|
84
|
+
}>): Effect.Effect<Readonly<{
|
|
85
|
+
sessionId: string;
|
|
86
|
+
}>, ShiitakeError>;
|
|
87
|
+
/** Load the exact retained lineage ending at one accepted command. */
|
|
88
|
+
export declare function loadAcceptedRun(owner: SqliteOwner, input: Readonly<{
|
|
89
|
+
sessionId: string;
|
|
90
|
+
commandFactId: string;
|
|
91
|
+
}>): Effect.Effect<PreparedSessionRun, ShiitakeError>;
|
|
92
|
+
/** Read the last exact completed assistant text produced by accepted work. */
|
|
93
|
+
export declare function readSettlementContent(owner: SqliteOwner, input: Readonly<{
|
|
94
|
+
sessionId: string;
|
|
95
|
+
commandFactId: string;
|
|
96
|
+
}>): Effect.Effect<string, ShiitakeError>;
|
|
97
|
+
/**
|
|
98
|
+
* The host metadata that settles with one accepted command: the
|
|
99
|
+
* cancellation's when a host-attributed cancel ended it, otherwise the
|
|
100
|
+
* command's own. Absent when the host attached none.
|
|
101
|
+
*/
|
|
102
|
+
export declare function readSettlementMeta(owner: SqliteOwner, input: Readonly<{
|
|
103
|
+
sessionId: string;
|
|
104
|
+
commandFactId: string;
|
|
105
|
+
}>, outcome: "completed" | "cancelled" | "failed" | "interrupted" | "outcome_unknown"): Effect.Effect<Json | undefined, ShiitakeError>;
|
|
106
|
+
/**
|
|
107
|
+
* The Session's recorded terminal diagnostic for one accepted command, the
|
|
108
|
+
* same text `agents.wait` and clients see; absent when none was recorded.
|
|
109
|
+
*/
|
|
110
|
+
export declare function readSettlementDiagnostic(owner: SqliteOwner, input: Readonly<{
|
|
111
|
+
sessionId: string;
|
|
112
|
+
commandFactId: string;
|
|
113
|
+
}>): Effect.Effect<string | undefined, ShiitakeError>;
|
|
114
|
+
/** Read one bounded public Session snapshot. */
|
|
115
|
+
export declare function readSession(owner: SqliteOwner, sessionId: string, activity: ObservedActivity, input?: ReadOptions, projectExtensions?: () => SessionExtensionSlots): Effect.Effect<SessionSnapshot, ShiitakeError>;
|
|
116
|
+
/** Read one bounded folder-resume summary through Woodstock's Effect boundary. */
|
|
117
|
+
export declare function readSessionSummary(owner: SqliteOwner, sessionId: string): Effect.Effect<import("./session-store.js").StoredSessionSummary | undefined, ShiitakeError>;
|
|
118
|
+
/**
|
|
119
|
+
* Persist or replay the Session reserved for a creation request ID.
|
|
120
|
+
* `admitNew` may refuse a new Session; a replayed request is never refused.
|
|
121
|
+
*/
|
|
122
|
+
export declare function createSession(owner: SqliteOwner, requestId: string, admitNew: () => void): Effect.Effect<string, ShiitakeError>;
|
|
123
|
+
/** Permanently delete one idle Session; false when it does not exist. */
|
|
124
|
+
export declare function deleteSession(owner: SqliteOwner, input: Readonly<{
|
|
125
|
+
sessionId: string;
|
|
126
|
+
assertIdleSession: (queue: string) => void;
|
|
127
|
+
}>): Effect.Effect<boolean, ShiitakeError>;
|
|
128
|
+
/** Read a page of stored conversation facts; status needs the Session owner. */
|
|
129
|
+
export declare function readSessionFactPage(owner: SqliteOwner, after?: string): Effect.Effect<import("./session-store.js").StoredSessionSummaryPage, ShiitakeError>;
|
|
130
|
+
/** Read one bounded inbox page in tier, then newest-activity order. */
|
|
131
|
+
export declare function readSessionInbox(owner: SqliteOwner, after: string | undefined): Effect.Effect<import("../../client.js").SessionSummaryPage, ShiitakeError>;
|
|
132
|
+
/** Read one strict-after page from Woodstock's selected lineage. */
|
|
133
|
+
export declare function readSessionReplayPage(owner: SqliteOwner, sessionId: string, after: string | undefined, delivery: "replay" | "live", activity: ObservedActivity, projectExtensions?: () => SessionExtensionSlots, includeSandboxFailures?: boolean): Effect.Effect<ClientReplayPage, ShiitakeError>;
|
|
134
|
+
/** Persist an operator-only sandbox diagnostic beside its accepted Session work. */
|
|
135
|
+
export declare function recordSandboxFailure(owner: SqliteOwner, accepted: Pick<AcceptedCommand, "sessionId" | "commandId">, event: SandboxFailureEvent): Effect.Effect<void, ShiitakeError>;
|
|
136
|
+
/** Extension that admitted one accepted command; null for other producers. */
|
|
137
|
+
export type ExtensionAdmissionOrigin = Readonly<{
|
|
138
|
+
extensionId: string;
|
|
139
|
+
correlation: string | null;
|
|
140
|
+
}> | null;
|
|
141
|
+
/** Exact durable facts core joins into one settled run for extensions. */
|
|
142
|
+
export type SettledRunFacts = Readonly<{
|
|
143
|
+
toolCalls: number;
|
|
144
|
+
/** Latest run or work terminal recorded for the work, if any. */
|
|
145
|
+
terminal: "completed" | "failed" | "cancelled" | "interrupted" | "missing";
|
|
146
|
+
origin: ExtensionAdmissionOrigin;
|
|
147
|
+
}>;
|
|
148
|
+
/** Read the admitting extension of one accepted command. */
|
|
149
|
+
export declare function readExtensionAdmissionOrigin(owner: SqliteOwner, sessionId: string, commandFactId: string, workId: string): ExtensionAdmissionOrigin;
|
|
150
|
+
/** Read the terminal and admission origin of one settled accepted command. */
|
|
151
|
+
export declare function readSettledRunFacts(owner: SqliteOwner, sessionId: string, commandFactId: string, workId: string): SettledRunFacts;
|
|
152
|
+
/** Record unsuccessful Watchdog settlement when Mule has no recorded terminal. */
|
|
153
|
+
export declare function recordWorkSettlement(owner: SqliteOwner, input: Readonly<{
|
|
154
|
+
sessionId: string;
|
|
155
|
+
commandFactId: string;
|
|
156
|
+
workId: string;
|
|
157
|
+
/** `completed` settles work that runs no Mule turn, such as compaction. */
|
|
158
|
+
outcome: "completed" | "interrupted" | "cancelled" | "failed";
|
|
159
|
+
diagnostic?: string | undefined;
|
|
160
|
+
}>): Effect.Effect<void, ShiitakeError>;
|
|
161
|
+
/** Record one retained live Pi retry observation on the Session lineage. */
|
|
162
|
+
export declare function recordLiveRetryEvent(owner: SqliteOwner, accepted: AcceptedCommand, event: LiveRetryEvent, turn: MuleIdentity): Effect.Effect<void, MuleError>;
|
|
163
|
+
/**
|
|
164
|
+
* Open the one scoped listener that projects Mule's exact event stream into
|
|
165
|
+
* retained Session facts and bounded process-local progress.
|
|
166
|
+
*/
|
|
167
|
+
export declare function openMuleRecorder(owner: SqliteOwner, accepted: AcceptedCommand, contract: RunContract): Effect.Effect<MuleListener, never, Scope.Scope>;
|
|
168
|
+
export { declareSessionDocument } from "./session-documents.js";
|
|
169
|
+
/** Read exact settled work facts through Woodstock's native command/work indexes. */
|
|
170
|
+
export declare function readCommandSettlement(owner: SqliteOwner, sessionId: string, commandId: string): Effect.Effect<CommandSettlement | undefined, ShiitakeError>;
|