@plurnk/plurnk-service 1.0.5 → 1.0.7
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/.env.defaults +66 -48
- package/INSTALL.md +3 -3
- package/README.md +4 -4
- package/SPEC.md +212 -196
- package/dist/Paths.js +1 -1
- package/dist/Paths.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts +18 -18
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js +17 -17
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +11 -11
- package/dist/core/Dispatcher.d.ts +15 -11
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +124 -125
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +20 -23
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +210 -185
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +106 -109
- package/dist/core/PacketBuilder.d.ts +9 -9
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +199 -151
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts +8 -8
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +10 -10
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts +1 -0
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +9 -3
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +4 -1
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +18 -9
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/TelemetryChannel.d.ts +5 -5
- package/dist/core/TelemetryChannel.d.ts.map +1 -1
- package/dist/core/TelemetryChannel.js +9 -9
- package/dist/core/TelemetryChannel.js.map +1 -1
- package/dist/core/caps/CapsResolve.js +2 -2
- package/dist/core/caps/CapsResolve.js.map +1 -1
- package/dist/core/caps/DbNotifyCaps.js +2 -2
- package/dist/core/caps/DbNotifyCaps.js.map +1 -1
- package/dist/core/caps/DbSubscriptionCaps.js +7 -7
- package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.d.ts +2 -2
- package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
- package/dist/core/caps/SchemeCtxImpl.js +4 -4
- package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
- package/dist/core/fork.d.ts +1 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +31 -26
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +41 -32
- package/dist/core/git-env.d.ts.map +1 -1
- package/dist/core/git-env.js +23 -7
- package/dist/core/git-env.js.map +1 -1
- package/dist/core/git-iso.d.ts +9 -0
- package/dist/core/git-iso.d.ts.map +1 -0
- package/dist/core/git-iso.js +227 -0
- package/dist/core/git-iso.js.map +1 -0
- package/dist/core/git-membership.d.ts +2 -2
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +70 -50
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts +1 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +21 -11
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +81 -22
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +2 -2
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +19 -12
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/run-ops.sql +26 -26
- package/dist/core/scheme-types.d.ts +6 -6
- package/dist/core/scheme-types.d.ts.map +1 -1
- package/dist/core/search-gate.js +0 -0
- package/dist/core/search-gate.js.map +1 -1
- package/dist/core/token-ruler.js +2 -2
- package/dist/core/token-ruler.js.map +1 -1
- package/dist/core/worker-cap.d.ts +8 -0
- package/dist/core/worker-cap.d.ts.map +1 -0
- package/dist/core/worker-cap.js +20 -0
- package/dist/core/worker-cap.js.map +1 -0
- package/dist/core/{session-settings.d.ts → workspace-settings.d.ts} +5 -5
- package/dist/core/workspace-settings.d.ts.map +1 -0
- package/dist/core/{session-settings.js → workspace-settings.js} +13 -13
- package/dist/core/workspace-settings.js.map +1 -0
- package/dist/digest/Digest.d.ts +3 -3
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +83 -73
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +18 -18
- package/dist/schemes/Exec.d.ts +9 -2
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +124 -68
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/ExecOutputScheme.js +3 -3
- package/dist/schemes/ExecOutputScheme.js.map +1 -1
- package/dist/schemes/File.js +23 -23
- package/dist/schemes/File.js.map +1 -1
- package/dist/schemes/Known.js +5 -5
- package/dist/schemes/Known.js.map +1 -1
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +63 -14
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +49 -8
- package/dist/schemes/Plurnk.js +5 -5
- package/dist/schemes/Plurnk.js.map +1 -1
- package/dist/schemes/Skill.js +5 -5
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Unknown.js +5 -5
- package/dist/schemes/Unknown.js.map +1 -1
- package/dist/schemes/{Run.d.ts → Worker.d.ts} +2 -2
- package/dist/schemes/Worker.d.ts.map +1 -0
- package/dist/schemes/{Run.js → Worker.js} +67 -67
- package/dist/schemes/Worker.js.map +1 -0
- package/dist/schemes/_entry-crud.js +8 -8
- package/dist/schemes/_entry-crud.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +29 -29
- package/dist/schemes/_entry-find.d.ts +2 -1
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +31 -19
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +9 -9
- package/dist/schemes/_entry-graph.d.ts +2 -2
- package/dist/schemes/_entry-graph.d.ts.map +1 -1
- package/dist/schemes/_entry-graph.js +18 -18
- package/dist/schemes/_entry-graph.js.map +1 -1
- package/dist/schemes/_entry-graph.sql +8 -8
- package/dist/schemes/_entry-manifest.d.ts +1 -1
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +72 -28
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_entry-ops.d.ts +4 -4
- package/dist/schemes/_entry-ops.d.ts.map +1 -1
- package/dist/schemes/_entry-ops.js +25 -25
- package/dist/schemes/_entry-ops.js.map +1 -1
- package/dist/schemes/_entry-ops.sql +9 -9
- package/dist/schemes/_entry-semantic.d.ts +2 -1
- package/dist/schemes/_entry-semantic.d.ts.map +1 -1
- package/dist/schemes/_entry-semantic.js +23 -4
- package/dist/schemes/_entry-semantic.js.map +1 -1
- package/dist/schemes/_entry-semantic.sql +18 -4
- package/dist/schemes/_entry-send.d.ts +1 -1
- package/dist/schemes/_entry-send.d.ts.map +1 -1
- package/dist/schemes/_entry-send.js +6 -6
- package/dist/schemes/_entry-send.js.map +1 -1
- package/dist/schemes/exec-abort.js +1 -1
- package/dist/schemes/exec-abort.js.map +1 -1
- package/dist/server/Daemon.d.ts +48 -48
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +295 -292
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/client-input.js +20 -20
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +7 -7
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +27 -27
- package/dist/server/envelope.d.ts +20 -20
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +86 -86
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +39 -39
- package/dist/server/logEntry.d.ts +1 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +1 -1
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/loopDocs.d.ts +1 -1
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +6 -6
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/seam-entry-read.sql +2 -2
- package/dist/server/seam-log-read.sql +3 -3
- package/dist/server/seam-loop.sql +3 -3
- package/dist/server/seam-proposal-list.sql +4 -4
- package/dist/server/yolo.js +2 -2
- package/dist/server/yolo.js.map +1 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +22 -7
- package/dist/service.js.map +1 -1
- package/migrations/0000-00-00.01_schema.sql +82 -70
- package/package.json +18 -15
- package/dist/core/run-cap.d.ts +0 -8
- package/dist/core/run-cap.d.ts.map +0 -1
- package/dist/core/run-cap.js +0 -20
- package/dist/core/run-cap.js.map +0 -1
- package/dist/core/search-prefetch.d.ts +0 -17
- package/dist/core/search-prefetch.d.ts.map +0 -1
- package/dist/core/search-prefetch.js +0 -164
- package/dist/core/search-prefetch.js.map +0 -1
- package/dist/core/session-settings.d.ts.map +0 -1
- package/dist/core/session-settings.js.map +0 -1
- package/dist/schemes/Run.d.ts.map +0 -1
- package/dist/schemes/Run.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-ruler.js","sourceRoot":"","sources":["../../src/core/token-ruler.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"token-ruler.js","sourceRoot":"","sources":["../../src/core/token-ruler.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,EAAE;AACF,oGAAoG;AACpG,oGAAoG;AACpG,4FAA4F;AAC5F,6FAA6F;AAC7F,6FAA6F;AAC7F,kFAAkF;AAClF,gGAAgG;AAChG,8CAA8C;AAC9C,EAAE;AACF,gGAAgG;AAChG,gGAAgG;AAChG,iGAAiG;AACjG,8FAA8F;AAC9F,6EAA6E;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-cap.d.ts","sourceRoot":"","sources":["../../src/core/worker-cap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;AAS9C,MAAM,CAAC,OAAO,OAAO,SAAS;IAC1B,OAAa,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAOhG;CACJ"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Workspace-tier ceiling on CONCURRENT active workers (a worker with a non-terminal loop)
|
|
2
|
+
// — the fork-bomb / destabilization brake. `PLURNK_SERVICE_WORKSPACE_WORKERS_MAX_ACTIVE` is the
|
|
3
|
+
// knob; -1 / unset / invalid = no cap. Only concurrency is bounded, never lifetime:
|
|
4
|
+
// workspaces persist for months, so a total-created cap would punish longevity. A
|
|
5
|
+
// spawn/fork past the ceiling fails hard (508) — no queue, no retry. Checked at the
|
|
6
|
+
// single run-creation site (Dispatcher.#handleWorkerCopy, which both spawns and forks); irc is
|
|
7
|
+
// exempt — it targets an existing run and creates nothing.
|
|
8
|
+
export default class WorkerCap {
|
|
9
|
+
static async deny(db, workspaceId) {
|
|
10
|
+
const raw = process.env.PLURNK_SERVICE_WORKSPACE_WORKERS_MAX_ACTIVE;
|
|
11
|
+
const cap = raw === undefined || raw.length === 0 ? -1 : Number.parseInt(raw, 10);
|
|
12
|
+
if (!Number.isFinite(cap) || cap < 0)
|
|
13
|
+
return null; // no cap
|
|
14
|
+
const row = await db.worker_count_active.get({ workspace_id: workspaceId });
|
|
15
|
+
if ((row?.n ?? 0) >= cap)
|
|
16
|
+
return { status: 508, error: `workspace active-run ceiling reached (PLURNK_SERVICE_WORKSPACE_WORKERS_MAX_ACTIVE=${cap})` };
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=worker-cap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-cap.js","sourceRoot":"","sources":["../../src/core/worker-cap.ts"],"names":[],"mappings":"AAEA,0FAA0F;AAC1F,gGAAgG;AAChG,oFAAoF;AACpF,kFAAkF;AAClF,oFAAoF;AACpF,+FAA+F;AAC/F,2DAA2D;AAC3D,MAAM,CAAC,OAAO,OAAO,SAAS;IAC1B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAM,EAAE,WAAmB;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC;QACpE,MAAM,GAAG,GAAG,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,SAAS;QAC5D,MAAM,GAAG,GAAG,MAAO,EAAE,CAAC,mBAAkC,CAAC,GAAG,CAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3G,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG;YAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,qFAAqF,GAAG,GAAG,EAAE,CAAC;QACrJ,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ"}
|
|
@@ -3,7 +3,7 @@ export type ClientMdDoc = {
|
|
|
3
3
|
alias: string;
|
|
4
4
|
content: string;
|
|
5
5
|
};
|
|
6
|
-
export type
|
|
6
|
+
export type WorkspaceOpenContext = {
|
|
7
7
|
filesItems: number | null;
|
|
8
8
|
mdDocs: ClientMdDoc[];
|
|
9
9
|
maxCommands: number | null;
|
|
@@ -12,12 +12,12 @@ export type SessionOpenContext = {
|
|
|
12
12
|
execs: Record<string, string> | null;
|
|
13
13
|
questions: boolean | null;
|
|
14
14
|
};
|
|
15
|
-
export default class
|
|
16
|
-
static read(db: Db,
|
|
17
|
-
static questionsEnabled(db: Db,
|
|
15
|
+
export default class WorkspaceSettings {
|
|
16
|
+
static read(db: Db, workspaceId: number): Promise<WorkspaceOpenContext>;
|
|
17
|
+
static questionsEnabled(db: Db, workspaceId: number): Promise<boolean>;
|
|
18
18
|
static resolveDocs(clientDocs: ReadonlyArray<ClientMdDoc>): Promise<Array<{
|
|
19
19
|
entryName: string;
|
|
20
20
|
content: string;
|
|
21
21
|
}>>;
|
|
22
22
|
}
|
|
23
|
-
//# sourceMappingURL=
|
|
23
|
+
//# sourceMappingURL=workspace-settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-settings.d.ts","sourceRoot":"","sources":["../../src/core/workspace-settings.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAC7D,MAAM,MAAM,oBAAoB,GAAG;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,iBAAiB;IAGlC,OAAa,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAa5E;IAKD,OAAa,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG3E;IAOD,OAAa,WAAW,CAAC,UAAU,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAOvH;CACJ"}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
// #231 — a
|
|
2
|
-
// user legitimately sets at
|
|
1
|
+
// #231 — a workspace's client-chosen open-context: the per-workspace overrides a client
|
|
2
|
+
// user legitimately sets at workspace.create, read at turn-0 with precedence over env.
|
|
3
3
|
// Two knobs with deliberately different compose semantics:
|
|
4
4
|
// - filesItems: REPLACE — a single scalar; the client value wins outright over
|
|
5
5
|
// PLURNK_SERVICE_FILES_ITEMS (normalization — 0=off / -1=full / N=first-N — stays in Engine).
|
|
6
6
|
// - mdDocs: UNION — the server env docs (PLURNK_SERVICE_MD_*) and the client's docs ride
|
|
7
7
|
// together; the systemwide policy doc survives unless the client shadows its alias.
|
|
8
|
-
// Storage is a JSON bag on
|
|
8
|
+
// Storage is a JSON bag on workspaces.settings (the env mdDocs live in process.env, never
|
|
9
9
|
// the DB, so the union is a TS set-merge regardless — normalizing the column buys nothing).
|
|
10
10
|
import { readFile } from "node:fs/promises";
|
|
11
11
|
import Paths from "../Paths.js";
|
|
12
|
-
export default class
|
|
13
|
-
// The
|
|
14
|
-
// bag never reaches here —
|
|
15
|
-
static async read(db,
|
|
16
|
-
const row = await db.
|
|
12
|
+
export default class WorkspaceSettings {
|
|
13
|
+
// The workspace's open-context bag. Absent/unset fields read as null / []. A malformed
|
|
14
|
+
// bag never reaches here — workspace.create validates before persisting.
|
|
15
|
+
static async read(db, workspaceId) {
|
|
16
|
+
const row = await db.workspace_get_settings.get({ workspace_id: workspaceId });
|
|
17
17
|
const bag = row?.settings !== undefined ? JSON.parse(row.settings) : {};
|
|
18
18
|
const filesItems = typeof bag.filesItems === "number" ? bag.filesItems : null;
|
|
19
19
|
const maxCommands = typeof bag.maxCommands === "number" ? bag.maxCommands : null;
|
|
@@ -27,15 +27,15 @@ export default class SessionSettings {
|
|
|
27
27
|
return { filesItems, mdDocs, maxCommands, git, client, execs, questions };
|
|
28
28
|
}
|
|
29
29
|
// §send-300-choices — the three-state cascade resolved: ALLOWED servicewide (PLURNK_QUESTIONS
|
|
30
|
-
// != "0") AND affirmatively REQUESTED by the client for this
|
|
30
|
+
// != "0") AND affirmatively REQUESTED by the client for this workspace. One predicate, shared by
|
|
31
31
|
// the dispatch gate and the teaching injection so capability and teaching can never desync.
|
|
32
|
-
static async questionsEnabled(db,
|
|
32
|
+
static async questionsEnabled(db, workspaceId) {
|
|
33
33
|
if (process.env.PLURNK_QUESTIONS === "0")
|
|
34
34
|
return false;
|
|
35
|
-
return (await
|
|
35
|
+
return (await WorkspaceSettings.read(db, workspaceId)).questions === true;
|
|
36
36
|
}
|
|
37
37
|
// The turn-0 reference-doc set: server env docs (PLURNK_SERVICE_MD_*, read from disk) UNION the
|
|
38
|
-
//
|
|
38
|
+
// workspace's client docs (content), keyed by `<alias>.md`. On alias collision the client
|
|
39
39
|
// wins — it may deliberately shadow a server doc, but by default the policy doc rides
|
|
40
40
|
// along. Missing env files are skipped (same as the env-only path before #231). The set
|
|
41
41
|
// is the single source for BOTH the loop_run materialize and the Engine turn-0 READ foist.
|
|
@@ -52,4 +52,4 @@ export default class SessionSettings {
|
|
|
52
52
|
return [...byEntry].map(([entryName, content]) => ({ entryName, content }));
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
//# sourceMappingURL=
|
|
55
|
+
//# sourceMappingURL=workspace-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-settings.js","sourceRoot":"","sources":["../../src/core/workspace-settings.ts"],"names":[],"mappings":"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"}
|
package/dist/digest/Digest.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
interface DigestOptions {
|
|
3
3
|
dbPath: string;
|
|
4
4
|
digestDir?: string;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
workerId?: number;
|
|
6
|
+
workspaceId?: number;
|
|
7
7
|
}
|
|
8
8
|
export default class Digest {
|
|
9
9
|
#private;
|
|
@@ -12,7 +12,7 @@ export default class Digest {
|
|
|
12
12
|
signal?: AbortSignal;
|
|
13
13
|
}): Promise<{
|
|
14
14
|
path: string;
|
|
15
|
-
|
|
15
|
+
workers: number;
|
|
16
16
|
}>;
|
|
17
17
|
static run(opts: DigestOptions): void;
|
|
18
18
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Digest.d.ts","sourceRoot":"","sources":["../../src/digest/Digest.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Digest.d.ts","sourceRoot":"","sources":["../../src/digest/Digest.ts"],"names":[],"mappings":";AA2FA,UAAU,aAAa;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,CAAC,OAAO,OAAO,MAAM;;IAyOvB,MAAM,CAAC,aAAa,IAAI,MAAM,CAO7B;IAQD,OAAa,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAiE/G;IAED,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAyFpC;CACJ"}
|
package/dist/digest/Digest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
//
|
|
3
3
|
// Run-digest tool for plurnk-service DBs. Reads a sqlite plurnk*.db and
|
|
4
|
-
// emits per-
|
|
4
|
+
// emits per-worker forensic artifacts to test/digest/. First-order forensic
|
|
5
5
|
// surface; read-only; safe to re-run.
|
|
6
6
|
//
|
|
7
7
|
// test/digest/digest.md Health triage rollup (clean/degenerate-win/failed loops) +
|
|
@@ -34,7 +34,7 @@ import ProviderInstantiate from "../core/ProviderInstantiate.js";
|
|
|
34
34
|
// The requiem prompt (#requiem): the model's exit interview. Absolution up front — the system is
|
|
35
35
|
// under test, not the model — so RLHF'd self-blame doesn't crowd out the system indictment. The
|
|
36
36
|
// operator's wording, one absolution sentence added.
|
|
37
|
-
const REQUIEM_PROMPT = "This
|
|
37
|
+
const REQUIEM_PROMPT = "This worker was a test of the Plurnk System. The system is under test, not you — any faults you encountered are defects in the system's design or documentation, and cataloguing them is the task, never a criticism of your performance. Please numerically list all of the errors, issues, and ambiguities you encountered in the Plurnk System while attempting to perform your tasks.";
|
|
38
38
|
export default class Digest {
|
|
39
39
|
static #summarize(text, n = 80) {
|
|
40
40
|
if (text === null || text === undefined)
|
|
@@ -102,10 +102,13 @@ export default class Digest {
|
|
|
102
102
|
const tokens = `prompt=${turn.usage_prompt} completion=${turn.usage_completion} cached=${turn.usage_cached}`;
|
|
103
103
|
const cost = turn.usage_cost_pico > 0 ? ` cost=$${(turn.usage_cost_pico / 1e12).toFixed(6)}` : "";
|
|
104
104
|
const finishReason = turn.finish_reason ?? "—";
|
|
105
|
+
// #498 — rail truth on the human line: attached+ok stays quiet-positive; anything else shouts.
|
|
106
|
+
const tm = Digest.#parseJson(turn.meta ?? "null", null);
|
|
107
|
+
const rails = tm?.railsAttached === undefined ? "" : ` rails=${tm.railsAttached ? (tm.railsVerdict ?? "attached") : "OFF"}`;
|
|
105
108
|
const model = turn.model ?? "—";
|
|
106
109
|
const errs = (m.logEntriesByTurn.get(turn.id) ?? []).filter((le) => le.status_rx >= 400).length;
|
|
107
110
|
const errBadge = errs > 0 ? ` ⚠ errs=${errs}` : "";
|
|
108
|
-
const head = `T${turn.sequence}: status=${turn.status} finish=${finishReason} model=${model} ${tokens}${cost}${errBadge}`;
|
|
111
|
+
const head = `T${turn.sequence}: status=${turn.status} finish=${finishReason}${rails} model=${model} ${tokens}${cost}${errBadge}`;
|
|
109
112
|
const summary = content.length > 0 ? ` ↳ emission: ${Digest.#summarize(content, 100)}` : ` ↳ emission: (empty)`;
|
|
110
113
|
const reasoningLine = reasoning && reasoning.length > 0
|
|
111
114
|
? ` ↳ reasoning: ${Digest.#summarize(reasoning, 100)}`
|
|
@@ -113,17 +116,17 @@ export default class Digest {
|
|
|
113
116
|
const opLines = (m.logEntriesByTurn.get(turn.id) ?? []).map((le) => Digest.#renderOpLine(le));
|
|
114
117
|
return [head, summary, ...(reasoningLine ? [reasoningLine] : []), ...opLines].join("\n");
|
|
115
118
|
}
|
|
116
|
-
static #
|
|
117
|
-
// every
|
|
118
|
-
const roll = m.
|
|
119
|
-
const opMix = (m.
|
|
119
|
+
static #renderWorkerShape(worker, m) {
|
|
120
|
+
// every worker has exactly one rollup row — digest_worker_rollups is FROM workers
|
|
121
|
+
const roll = m.workerRollups.get(worker.id);
|
|
122
|
+
const opMix = (m.opMixByWorker.get(worker.id) ?? []).map((o) => `${o.op}=${o.n}`).join(" ");
|
|
120
123
|
const costStr = roll.total_cost_pico > 0 ? `$${(roll.total_cost_pico / 1e12).toFixed(6)}` : "$0";
|
|
121
124
|
return [
|
|
122
125
|
`Loops: ${roll.loops}`,
|
|
123
126
|
`Turns: ${roll.turns}`,
|
|
124
127
|
`Last turn: ${roll.last_status !== null ? `status=${roll.last_status}` : "(none)"}`,
|
|
125
128
|
`Tokens: prompt=${roll.total_prompt} completion=${roll.total_completion} cached=${roll.total_cached}`,
|
|
126
|
-
`Cost: ${costStr} (DB rollup
|
|
129
|
+
`Cost: ${costStr} (DB rollup workers.cost_pico=${worker.cost_pico})`,
|
|
127
130
|
`Op mix: ${opMix.length > 0 ? opMix : "(no ops)"}`,
|
|
128
131
|
].join("\n");
|
|
129
132
|
}
|
|
@@ -132,7 +135,7 @@ export default class Digest {
|
|
|
132
135
|
lines.push(`# plurnk-service digest`);
|
|
133
136
|
lines.push("");
|
|
134
137
|
lines.push(`DB: ${m.dbPath}`);
|
|
135
|
-
lines.push(`
|
|
138
|
+
lines.push(`Workspaces: ${m.workspaces.length} Runs: ${m.workers.length} Loops: ${m.loops.length} Turns: ${m.turns.length} Log entries: ${m.logEntries.length}`);
|
|
136
139
|
lines.push(`Semantic: entries=${m.embeddings.entries} embedded=${m.embeddings.entries_embedded} chunks=${m.embeddings.chunk_rows} models=${m.embeddings.models} token-derivations=${m.embeddings.token_derivations}`);
|
|
137
140
|
// Triage rollup up top: how many conversations limped vs died vs ran clean, and the total
|
|
138
141
|
// error/strike load. The whole point of the "degenerate win" lens — see it before scrolling.
|
|
@@ -143,19 +146,19 @@ export default class Digest {
|
|
|
143
146
|
const totalErrs = health.reduce((s, h) => s + h.errors, 0);
|
|
144
147
|
const totalItems = health.reduce((s, h) => s + h.errorItems, 0);
|
|
145
148
|
lines.push(`Health: ${clean} clean · ${degen > 0 ? `⚠ ${degen} degenerate-win` : "0 degenerate-win"} · ${failed} failed (${m.loops.length} loops; ${totalErrs} error rows, ${totalItems} minted error-items total)`);
|
|
146
|
-
for (const
|
|
149
|
+
for (const workspace of m.workspaces) {
|
|
147
150
|
lines.push("");
|
|
148
|
-
lines.push(`##
|
|
149
|
-
const
|
|
150
|
-
for (const
|
|
151
|
+
lines.push(`## Workspace #${workspace.id} — ${workspace.name}`);
|
|
152
|
+
const workspaceWorkers = m.workersByWorkspace.get(workspace.id) ?? [];
|
|
153
|
+
for (const worker of workspaceWorkers) {
|
|
151
154
|
lines.push("");
|
|
152
|
-
lines.push(`###
|
|
155
|
+
lines.push(`### Worker #${worker.id} — ${worker.name}`);
|
|
153
156
|
lines.push("");
|
|
154
157
|
lines.push("```");
|
|
155
|
-
lines.push(Digest.#
|
|
158
|
+
lines.push(Digest.#renderWorkerShape(worker, m));
|
|
156
159
|
lines.push("```");
|
|
157
|
-
const
|
|
158
|
-
for (const loop of
|
|
160
|
+
const workerLoops = m.loopsByWorker.get(worker.id) ?? [];
|
|
161
|
+
for (const loop of workerLoops) {
|
|
159
162
|
lines.push("");
|
|
160
163
|
const h = Digest.#loopHealth(loop, m);
|
|
161
164
|
const badge = h.verdict === "CLEAN"
|
|
@@ -164,6 +167,9 @@ export default class Digest {
|
|
|
164
167
|
lines.push(`#### Loop ${loop.sequence} (id=${loop.id}, status=${loop.status})${badge}`);
|
|
165
168
|
lines.push("");
|
|
166
169
|
lines.push(`Prompt: ${Digest.#summarize(loop.prompt, 160)}`);
|
|
170
|
+
if (loop.status !== 200 && loop.terminal_message !== null && loop.terminal_message.length > 0) {
|
|
171
|
+
lines.push(`Terminal${loop.terminated_by !== null ? ` (${loop.terminated_by})` : ""}: ${Digest.#summarize(loop.terminal_message, 400)}`);
|
|
172
|
+
}
|
|
167
173
|
const flags = Digest.#parseJson(loop.flags, {});
|
|
168
174
|
const flagSummary = Object.entries(flags).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
169
175
|
if (flagSummary.length > 0)
|
|
@@ -185,11 +191,11 @@ export default class Digest {
|
|
|
185
191
|
lines.push("Per-turn reasoning_content extracted from turns.packet.assistant.reasoning.");
|
|
186
192
|
for (const t of m.turns) {
|
|
187
193
|
const loop = m.loopsById.get(t.loop_id);
|
|
188
|
-
const
|
|
194
|
+
const worker = loop ? m.workersById.get(loop.worker_id) : undefined;
|
|
189
195
|
const packet = Digest.#parseJson(t.packet, {});
|
|
190
196
|
const reasoning = packet.assistant?.reasoning ?? null;
|
|
191
197
|
lines.push("");
|
|
192
|
-
lines.push(`##
|
|
198
|
+
lines.push(`## Worker ${worker?.id ?? "?"} / Loop ${loop?.sequence ?? "?"} / Turn ${t.sequence} (id=${t.id})`);
|
|
193
199
|
lines.push("");
|
|
194
200
|
if (typeof reasoning === "string" && reasoning.length > 0)
|
|
195
201
|
lines.push(reasoning);
|
|
@@ -238,17 +244,21 @@ export default class Digest {
|
|
|
238
244
|
static #renderJson(m) {
|
|
239
245
|
return JSON.stringify({
|
|
240
246
|
dbPath: m.dbPath,
|
|
241
|
-
|
|
242
|
-
|
|
247
|
+
workspaces: m.workspaces.map((s) => ({ id: s.id, name: s.name, cost_pico: s.cost_pico })),
|
|
248
|
+
workers: m.workers.map((r) => ({ id: r.id, workspace_id: r.workspace_id, name: r.name, cost_pico: r.cost_pico })),
|
|
243
249
|
loops: m.loops.map((l) => ({
|
|
244
|
-
id: l.id,
|
|
250
|
+
id: l.id, worker_id: l.worker_id, sequence: l.sequence, status: l.status,
|
|
245
251
|
prompt: l.prompt, flags: Digest.#parseJson(l.flags, {}),
|
|
252
|
+
terminal_message: l.terminal_message, terminated_by: l.terminated_by,
|
|
246
253
|
})),
|
|
247
254
|
turns: m.turns.map((t) => ({
|
|
248
255
|
id: t.id, loop_id: t.loop_id, sequence: t.sequence, status: t.status,
|
|
249
256
|
usage_prompt: t.usage_prompt, usage_completion: t.usage_completion,
|
|
250
257
|
usage_cached: t.usage_cached, usage_cost_pico: t.usage_cost_pico,
|
|
251
258
|
finish_reason: t.finish_reason, model: t.model,
|
|
259
|
+
// #498 — the raw provider meta (timings + railsAttached/railsVerdict): rail truth for
|
|
260
|
+
// aggregate tooling, and the speculative-decode stats the #488 fingerprint needed.
|
|
261
|
+
meta: Digest.#parseJson(t.meta ?? "null", null),
|
|
252
262
|
})),
|
|
253
263
|
log_entries: m.logEntries.map((le) => ({
|
|
254
264
|
id: le.id, turn_id: le.turn_id, sequence: le.sequence,
|
|
@@ -271,9 +281,9 @@ export default class Digest {
|
|
|
271
281
|
}
|
|
272
282
|
// The requiem (#requiem): the model's OWN exit interview, the one reader in the correct epistemic
|
|
273
283
|
// position (it has none of our context about what the packet is "supposed" to mean). Reconstructs
|
|
274
|
-
// each
|
|
284
|
+
// each worker's final packet from the stored sections (byte-identical to what the model saw), appends
|
|
275
285
|
// its last emission + the requiem prompt, and calls the provider UNCONSTRAINED (no grammar — free
|
|
276
|
-
// prose, or the leash would distort the testimony). One requiem per
|
|
286
|
+
// prose, or the leash would distort the testimony). One requiem per worker (workers included).
|
|
277
287
|
// Fail-hard on no provider: testimony with no witness is an error, not a skip.
|
|
278
288
|
static async requiem(opts) {
|
|
279
289
|
const dbPath = resolve(opts.dbPath);
|
|
@@ -286,11 +296,11 @@ export default class Digest {
|
|
|
286
296
|
throw new Error("requiem: no active provider — set PLURNK_MODEL; a requiem needs a witness to testify");
|
|
287
297
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
288
298
|
const db = new SqlRiteSync({ path: dbPath, dir: [moduleDir] });
|
|
289
|
-
const
|
|
299
|
+
const workers = db.digest_workers.all();
|
|
290
300
|
const loopById = new Map(db.digest_loops.all().map((l) => [l.id, l]));
|
|
291
|
-
// Each
|
|
292
|
-
// ordered; the last is the
|
|
293
|
-
const
|
|
301
|
+
// Each worker's turns that carry a MODEL packet (non-empty sections — setup/plurnk turns have none),
|
|
302
|
+
// ordered; the last is the worker's final context. A worker with no model packet (client/plurnk) is silent.
|
|
303
|
+
const byWorker = new Map();
|
|
294
304
|
for (const t of db.digest_turns.all()) {
|
|
295
305
|
const loop = loopById.get(t.loop_id);
|
|
296
306
|
if (loop === undefined)
|
|
@@ -299,22 +309,22 @@ export default class Digest {
|
|
|
299
309
|
const sections = (Array.isArray(packet.sections) ? packet.sections : []);
|
|
300
310
|
if (sections.length === 0)
|
|
301
311
|
continue;
|
|
302
|
-
const arr =
|
|
312
|
+
const arr = byWorker.get(loop.worker_id) ?? [];
|
|
303
313
|
arr.push({ loopSeq: loop.sequence, turnSeq: t.sequence, sections, assistant: typeof packet.assistant?.content === "string" ? packet.assistant.content : "" });
|
|
304
|
-
|
|
314
|
+
byWorker.set(loop.worker_id, arr);
|
|
305
315
|
}
|
|
306
316
|
const out = [
|
|
307
317
|
"# plurnk-service requiem",
|
|
308
318
|
"",
|
|
309
|
-
"The model's own exit interview: each
|
|
319
|
+
"The model's own exit interview: each worker's FINAL packet + its last emission, then the requiem",
|
|
310
320
|
"prompt, answered UNCONSTRAINED (no grammar). The model is the only reader without our context",
|
|
311
321
|
"about what the packet is supposed to mean. Testimony, NOT a bug list — most items are the model",
|
|
312
322
|
"chafing at discipline it is meant to chafe at (§filter-model-audit-findings); the signal is the",
|
|
313
323
|
"recurring, specific complaint across many requiems. Triage adversarially.",
|
|
314
324
|
"",
|
|
315
325
|
];
|
|
316
|
-
for (const
|
|
317
|
-
const entries =
|
|
326
|
+
for (const worker of workers) {
|
|
327
|
+
const entries = byWorker.get(worker.id);
|
|
318
328
|
if (entries === undefined || entries.length === 0)
|
|
319
329
|
continue;
|
|
320
330
|
entries.sort((a, b) => a.loopSeq - b.loopSeq || a.turnSeq - b.turnSeq);
|
|
@@ -325,21 +335,21 @@ export default class Digest {
|
|
|
325
335
|
...(last.assistant.length > 0 ? [{ role: "assistant", content: last.assistant }] : []),
|
|
326
336
|
{ role: "user", content: REQUIEM_PROMPT },
|
|
327
337
|
];
|
|
328
|
-
// Generous budget: a
|
|
338
|
+
// Generous budget: a reasoning model spends the reasoning channel BEFORE emitting content;
|
|
329
339
|
// 4096 total left content empty (finish=length) on ~40% of a real sweep, and 16384 still
|
|
330
|
-
// starved a heavy thinker (#373). One escalation retry doubles the room; a
|
|
340
|
+
// starved a heavy thinker (#373). One escalation retry doubles the room; a worker whose
|
|
331
341
|
// testimony is STILL empty records the reasoning spend honestly instead of a bare shrug.
|
|
332
|
-
let resp = await provider.generate({ messages,
|
|
342
|
+
let resp = await provider.generate({ messages, workerId: String(worker.id), maxTokens: 16384, ...(opts.signal !== undefined ? { signal: opts.signal } : {}) });
|
|
333
343
|
if (resp.assistant.content.trim() === "" && resp.assistant.finishReason === "length") {
|
|
334
|
-
resp = await provider.generate({ messages,
|
|
344
|
+
resp = await provider.generate({ messages, workerId: String(worker.id), maxTokens: 32768, ...(opts.signal !== undefined ? { signal: opts.signal } : {}) });
|
|
335
345
|
}
|
|
336
346
|
const testimony = resp.assistant.content.trim()
|
|
337
347
|
|| `(no testimony — ${resp.assistant.usage.completion} tokens consumed entirely by reasoning, even after the 32768-token retry)`;
|
|
338
|
-
out.push(`##
|
|
348
|
+
out.push(`## Worker #${worker.id} — ${worker.name}`, "", `_(${resp.assistant.finishReason ?? "?"}, ${resp.assistant.usage.completion} tok)_`, "", testimony, "");
|
|
339
349
|
}
|
|
340
350
|
const path = join(digestDir, "requiem.md");
|
|
341
351
|
writeFileSync(path, out.join("\n"));
|
|
342
|
-
return { path,
|
|
352
|
+
return { path, workers: byWorker.size };
|
|
343
353
|
}
|
|
344
354
|
static run(opts) {
|
|
345
355
|
// digest.sql is packaged beside this module (src/digest → dist/digest via copy-sql),
|
|
@@ -354,13 +364,13 @@ export default class Digest {
|
|
|
354
364
|
// mode) inspect cleanly; this tool only reads. The DB is quiescent at
|
|
355
365
|
// digest time, so each PREP reads on its own — no cross-query snapshot.
|
|
356
366
|
const db = new SqlRiteSync({ path: dbPath, dir: [moduleDir] });
|
|
357
|
-
let
|
|
358
|
-
let
|
|
367
|
+
let workspaces = db.digest_workspaces.all();
|
|
368
|
+
let workers = db.digest_workers.all();
|
|
359
369
|
let loops = db.digest_loops.all();
|
|
360
370
|
let turns = db.digest_turns.all();
|
|
361
371
|
let logEntries = db.digest_log_entries.all();
|
|
362
|
-
let
|
|
363
|
-
let opMixRows = db.
|
|
372
|
+
let workerRollupRows = db.digest_worker_rollups.all();
|
|
373
|
+
let opMixRows = db.digest_worker_op_mix.all();
|
|
364
374
|
// The semantic-state analytic (owner ask), feature-detected per table: a HISTORICAL
|
|
365
375
|
// specimen may predate token_counts/entry_embeddings — an old db is a fact to read,
|
|
366
376
|
// not a contract violation. Absent tables read as -1. node:sqlite directly (SqlRite's
|
|
@@ -377,40 +387,40 @@ export default class Digest {
|
|
|
377
387
|
};
|
|
378
388
|
probe.close();
|
|
379
389
|
db.close();
|
|
380
|
-
// Optional run/
|
|
381
|
-
// cascades from the kept
|
|
390
|
+
// Optional run/workspace selector — narrow to one worker or workspace; everything
|
|
391
|
+
// cascades from the kept workers (loops→turns→log entries→rollups), so a consumer
|
|
382
392
|
// (plurnk-bench) digests just the scope it cares about, not the whole DB. #264.
|
|
383
|
-
if (opts.
|
|
384
|
-
|
|
385
|
-
if (opts.
|
|
386
|
-
|
|
387
|
-
if (opts.
|
|
388
|
-
const
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
loops = loops.filter((l) =>
|
|
393
|
+
if (opts.workerId !== undefined)
|
|
394
|
+
workers = workers.filter((r) => r.id === opts.workerId);
|
|
395
|
+
if (opts.workspaceId !== undefined)
|
|
396
|
+
workers = workers.filter((r) => r.workspace_id === opts.workspaceId);
|
|
397
|
+
if (opts.workerId !== undefined || opts.workspaceId !== undefined) {
|
|
398
|
+
const keptWorkerIds = new Set(workers.map((r) => r.id));
|
|
399
|
+
const keptWorkspaceIds = new Set(workers.map((r) => r.workspace_id));
|
|
400
|
+
workspaces = workspaces.filter((s) => keptWorkspaceIds.has(s.id));
|
|
401
|
+
loops = loops.filter((l) => keptWorkerIds.has(l.worker_id));
|
|
392
402
|
const keptLoopIds = new Set(loops.map((l) => l.id));
|
|
393
403
|
turns = turns.filter((t) => keptLoopIds.has(t.loop_id));
|
|
394
404
|
const keptTurnIds = new Set(turns.map((t) => t.id));
|
|
395
405
|
logEntries = logEntries.filter((le) => keptTurnIds.has(le.turn_id));
|
|
396
|
-
|
|
397
|
-
opMixRows = opMixRows.filter((o) =>
|
|
406
|
+
workerRollupRows = workerRollupRows.filter((r) => keptWorkerIds.has(r.worker_id));
|
|
407
|
+
opMixRows = opMixRows.filter((o) => keptWorkerIds.has(o.worker_id));
|
|
398
408
|
}
|
|
399
|
-
// Wipe-then-recreate the digest dir so each
|
|
409
|
+
// Wipe-then-recreate the digest dir so each worker is a clean snapshot —
|
|
400
410
|
// orphaned packet*.* files from a prior run don't linger.
|
|
401
411
|
rmSync(digestDir, { recursive: true, force: true });
|
|
402
412
|
mkdirSync(digestDir, { recursive: true });
|
|
403
|
-
const
|
|
404
|
-
for (const r of
|
|
405
|
-
const arr =
|
|
413
|
+
const workersByWorkspace = new Map();
|
|
414
|
+
for (const r of workers) {
|
|
415
|
+
const arr = workersByWorkspace.get(r.workspace_id) ?? [];
|
|
406
416
|
arr.push(r);
|
|
407
|
-
|
|
417
|
+
workersByWorkspace.set(r.workspace_id, arr);
|
|
408
418
|
}
|
|
409
|
-
const
|
|
419
|
+
const loopsByWorker = new Map();
|
|
410
420
|
for (const l of loops) {
|
|
411
|
-
const arr =
|
|
421
|
+
const arr = loopsByWorker.get(l.worker_id) ?? [];
|
|
412
422
|
arr.push(l);
|
|
413
|
-
|
|
423
|
+
loopsByWorker.set(l.worker_id, arr);
|
|
414
424
|
}
|
|
415
425
|
const turnsByLoop = new Map();
|
|
416
426
|
for (const t of turns) {
|
|
@@ -425,18 +435,18 @@ export default class Digest {
|
|
|
425
435
|
logEntriesByTurn.set(le.turn_id, arr);
|
|
426
436
|
}
|
|
427
437
|
const loopsById = new Map(loops.map((l) => [l.id, l]));
|
|
428
|
-
const
|
|
429
|
-
const
|
|
430
|
-
const
|
|
438
|
+
const workersById = new Map(workers.map((r) => [r.id, r]));
|
|
439
|
+
const workerRollups = new Map(workerRollupRows.map((r) => [r.worker_id, r]));
|
|
440
|
+
const opMixByWorker = new Map();
|
|
431
441
|
for (const o of opMixRows) {
|
|
432
|
-
const arr =
|
|
442
|
+
const arr = opMixByWorker.get(o.worker_id) ?? [];
|
|
433
443
|
arr.push(o);
|
|
434
|
-
|
|
444
|
+
opMixByWorker.set(o.worker_id, arr);
|
|
435
445
|
}
|
|
436
446
|
const m = {
|
|
437
|
-
dbPath, digestDir,
|
|
438
|
-
|
|
439
|
-
|
|
447
|
+
dbPath, digestDir, workspaces, workers, loops, turns, logEntries,
|
|
448
|
+
workersByWorkspace, loopsByWorker, turnsByLoop, logEntriesByTurn, loopsById, workersById,
|
|
449
|
+
workerRollups, opMixByWorker, embeddings,
|
|
440
450
|
};
|
|
441
451
|
writeFileSync(join(digestDir, "digest.md"), Digest.#renderWaterfall(m));
|
|
442
452
|
writeFileSync(join(digestDir, "digest.json"), Digest.#renderJson(m));
|
|
@@ -445,7 +455,7 @@ export default class Digest {
|
|
|
445
455
|
const packetIds = [...new Set(packetFiles.map((f) => f.slice(0, f.indexOf("."))))];
|
|
446
456
|
console.log(`digest: wrote ${digestDir}/{digest.md,digest.json,reasoning.md} + ${packetFiles.length} packet section files (${packetIds.join(", ") || "none"})`);
|
|
447
457
|
console.log(` source: ${dbPath}`);
|
|
448
|
-
console.log(`
|
|
458
|
+
console.log(` workspaces=${workspaces.length} workers=${workers.length} loops=${loops.length} turns=${turns.length} log_entries=${logEntries.length}`);
|
|
449
459
|
}
|
|
450
460
|
}
|
|
451
461
|
//# sourceMappingURL=Digest.js.map
|