@principal-ai/subsystems-studio 0.6.8 → 0.6.9
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/bundles/macos-arm64/subsystems-studio.app/Contents/Resources/{ct2o0q8id5eq.tar.zst → 13kyfkdd9mdni.tar.zst} +0 -0
- package/bundles/macos-arm64/subsystems-studio.app/Contents/Resources/app/bun/session-warmup-worker.js +366 -14
- package/bundles/macos-arm64/subsystems-studio.app/Contents/Resources/metadata.json +1 -1
- package/package.json +4 -4
|
Binary file
|
|
@@ -10655,7 +10655,7 @@ import {
|
|
|
10655
10655
|
import { homedir as homedir2 } from "os";
|
|
10656
10656
|
import { join as join3 } from "path";
|
|
10657
10657
|
var CACHE_ROOT = join3(homedir2(), ".principal", "session-events");
|
|
10658
|
-
var PROCESSING_VERSION =
|
|
10658
|
+
var PROCESSING_VERSION = 2;
|
|
10659
10659
|
var KEEP_DAYS = 14;
|
|
10660
10660
|
function dayKeyOf(date) {
|
|
10661
10661
|
const y = date.getFullYear();
|
|
@@ -10745,6 +10745,24 @@ function trimSessionEventRows(events) {
|
|
|
10745
10745
|
|
|
10746
10746
|
// src/bun/session-pipeline.ts
|
|
10747
10747
|
import { statSync as statSync3 } from "fs";
|
|
10748
|
+
|
|
10749
|
+
// src/bun/maintain-sessions.ts
|
|
10750
|
+
function isMaintainSessionTitle(title) {
|
|
10751
|
+
return /^Maintain\s*[\u2014\u2013-]/.test(title.trim());
|
|
10752
|
+
}
|
|
10753
|
+
function isMaintainAgentName(agent) {
|
|
10754
|
+
return agent === "issue-fixer" || agent === "gap-filler";
|
|
10755
|
+
}
|
|
10756
|
+
function isMaintainSession(opts) {
|
|
10757
|
+
if (isMaintainAgentName(opts.agent))
|
|
10758
|
+
return true;
|
|
10759
|
+
if (opts.title && isMaintainSessionTitle(opts.title))
|
|
10760
|
+
return true;
|
|
10761
|
+
return false;
|
|
10762
|
+
}
|
|
10763
|
+
|
|
10764
|
+
// src/bun/opencode-v2-messages.ts
|
|
10765
|
+
import { Database } from "bun:sqlite";
|
|
10748
10766
|
function openCodeDBPath() {
|
|
10749
10767
|
const env = process.env;
|
|
10750
10768
|
if (env["OPENCODE_DATA_DIR"])
|
|
@@ -10753,6 +10771,222 @@ function openCodeDBPath() {
|
|
|
10753
10771
|
const xdgData = env["XDG_DATA_HOME"] || `${home}/.local/share`;
|
|
10754
10772
|
return `${xdgData}/opencode/opencode.db`;
|
|
10755
10773
|
}
|
|
10774
|
+
function tableExists(db, name) {
|
|
10775
|
+
const row = db.prepare(`SELECT 1 AS ok FROM sqlite_master WHERE type = 'table' AND name = ?`).get(name);
|
|
10776
|
+
return row != null;
|
|
10777
|
+
}
|
|
10778
|
+
function openReadonlyDb() {
|
|
10779
|
+
return new Database(openCodeDBPath(), { readonly: true });
|
|
10780
|
+
}
|
|
10781
|
+
function resolveOpencodeSessionKind(sessionId, db) {
|
|
10782
|
+
const owned = !db;
|
|
10783
|
+
let conn = db ?? null;
|
|
10784
|
+
try {
|
|
10785
|
+
if (!conn)
|
|
10786
|
+
conn = openReadonlyDb();
|
|
10787
|
+
if (tableExists(conn, "session_v2")) {
|
|
10788
|
+
const v2 = conn.prepare(`SELECT 1 AS ok FROM session_v2 WHERE id = ?`).get(sessionId);
|
|
10789
|
+
if (v2)
|
|
10790
|
+
return "v2";
|
|
10791
|
+
}
|
|
10792
|
+
if (tableExists(conn, "session")) {
|
|
10793
|
+
const v1 = conn.prepare(`SELECT 1 AS ok FROM session WHERE id = ?`).get(sessionId);
|
|
10794
|
+
if (v1)
|
|
10795
|
+
return "v1";
|
|
10796
|
+
}
|
|
10797
|
+
return null;
|
|
10798
|
+
} catch {
|
|
10799
|
+
return null;
|
|
10800
|
+
} finally {
|
|
10801
|
+
if (owned) {
|
|
10802
|
+
try {
|
|
10803
|
+
conn?.close();
|
|
10804
|
+
} catch {}
|
|
10805
|
+
}
|
|
10806
|
+
}
|
|
10807
|
+
}
|
|
10808
|
+
function isOpencodeV2Session(sessionId) {
|
|
10809
|
+
return resolveOpencodeSessionKind(sessionId) === "v2";
|
|
10810
|
+
}
|
|
10811
|
+
function readOpencodeV2Session(sessionId) {
|
|
10812
|
+
let db = null;
|
|
10813
|
+
try {
|
|
10814
|
+
db = openReadonlyDb();
|
|
10815
|
+
if (!tableExists(db, "session_v2"))
|
|
10816
|
+
return null;
|
|
10817
|
+
const metaRow = db.prepare(`SELECT id, title, slug, agent, directory, version
|
|
10818
|
+
FROM session_v2 WHERE id = ?`).get(sessionId);
|
|
10819
|
+
if (!metaRow)
|
|
10820
|
+
return null;
|
|
10821
|
+
const messages = tableExists(db, "session_message") ? db.prepare(`SELECT id, session_id, type, seq, time_created, data
|
|
10822
|
+
FROM session_message
|
|
10823
|
+
WHERE session_id = ?
|
|
10824
|
+
ORDER BY seq ASC`).all(sessionId) : [];
|
|
10825
|
+
return {
|
|
10826
|
+
meta: {
|
|
10827
|
+
id: metaRow.id,
|
|
10828
|
+
title: (metaRow.title ?? "").trim() || metaRow.id.slice(0, 12),
|
|
10829
|
+
slug: metaRow.slug ?? "",
|
|
10830
|
+
agent: metaRow.agent ?? undefined,
|
|
10831
|
+
directory: metaRow.directory ?? undefined,
|
|
10832
|
+
version: metaRow.version ?? undefined
|
|
10833
|
+
},
|
|
10834
|
+
messages
|
|
10835
|
+
};
|
|
10836
|
+
} catch {
|
|
10837
|
+
return null;
|
|
10838
|
+
} finally {
|
|
10839
|
+
try {
|
|
10840
|
+
db?.close();
|
|
10841
|
+
} catch {}
|
|
10842
|
+
}
|
|
10843
|
+
}
|
|
10844
|
+
function mapToolName(name) {
|
|
10845
|
+
const n = name.trim().toLowerCase();
|
|
10846
|
+
if (n === "shell" || n === "bash")
|
|
10847
|
+
return "Bash";
|
|
10848
|
+
if (n === "read")
|
|
10849
|
+
return "Read";
|
|
10850
|
+
if (n === "write")
|
|
10851
|
+
return "Write";
|
|
10852
|
+
if (n === "edit" || n === "multiedit")
|
|
10853
|
+
return "Edit";
|
|
10854
|
+
if (n === "glob")
|
|
10855
|
+
return "Glob";
|
|
10856
|
+
if (n === "grep")
|
|
10857
|
+
return "Grep";
|
|
10858
|
+
if (n === "list" || n === "ls")
|
|
10859
|
+
return "Bash";
|
|
10860
|
+
if (n === "webfetch")
|
|
10861
|
+
return "WebFetch";
|
|
10862
|
+
if (n === "websearch")
|
|
10863
|
+
return "WebSearch";
|
|
10864
|
+
if (n === "task")
|
|
10865
|
+
return "Task";
|
|
10866
|
+
return name;
|
|
10867
|
+
}
|
|
10868
|
+
function pathsFromToolInput(input) {
|
|
10869
|
+
if (!input || typeof input !== "object")
|
|
10870
|
+
return [];
|
|
10871
|
+
const obj = input;
|
|
10872
|
+
const paths = [];
|
|
10873
|
+
for (const key of ["filePath", "file_path", "path", "pattern", "glob"]) {
|
|
10874
|
+
if (typeof obj[key] === "string" && obj[key].trim()) {
|
|
10875
|
+
paths.push(obj[key]);
|
|
10876
|
+
}
|
|
10877
|
+
}
|
|
10878
|
+
return paths;
|
|
10879
|
+
}
|
|
10880
|
+
function applyFileContext(event, toolName, toolInput) {
|
|
10881
|
+
const paths = pathsFromToolInput(toolInput);
|
|
10882
|
+
if (paths.length === 0)
|
|
10883
|
+
return;
|
|
10884
|
+
event.rawFilePaths = [...new Set(paths)];
|
|
10885
|
+
const op = getFileOperation(toolName);
|
|
10886
|
+
if (op)
|
|
10887
|
+
event.operation = op;
|
|
10888
|
+
}
|
|
10889
|
+
function sessionMessagesToUniversalEvents(sessionId, messages, opts) {
|
|
10890
|
+
const workingDirectory = opts?.workingDirectory?.trim() || "";
|
|
10891
|
+
const out = [];
|
|
10892
|
+
for (const row of messages) {
|
|
10893
|
+
let parsed;
|
|
10894
|
+
try {
|
|
10895
|
+
parsed = JSON.parse(row.data);
|
|
10896
|
+
} catch {
|
|
10897
|
+
continue;
|
|
10898
|
+
}
|
|
10899
|
+
const time = parsed["time"];
|
|
10900
|
+
const created = typeof time?.["created"] === "number" ? time["created"] : typeof row.time_created === "number" ? row.time_created : Date.now();
|
|
10901
|
+
const base = {
|
|
10902
|
+
sessionId,
|
|
10903
|
+
workingDirectory,
|
|
10904
|
+
timestamp: created,
|
|
10905
|
+
provider: SupportedAgent.OPENCODE,
|
|
10906
|
+
raw: { id: row.id, type: row.type, seq: row.seq, data: parsed }
|
|
10907
|
+
};
|
|
10908
|
+
if (row.type === "user") {
|
|
10909
|
+
const text = typeof parsed["text"] === "string" ? parsed["text"] : "";
|
|
10910
|
+
out.push({
|
|
10911
|
+
...base,
|
|
10912
|
+
eventType: "user-prompt-submit",
|
|
10913
|
+
data: { prompt: text, messageID: row.id }
|
|
10914
|
+
});
|
|
10915
|
+
continue;
|
|
10916
|
+
}
|
|
10917
|
+
if (row.type !== "assistant")
|
|
10918
|
+
continue;
|
|
10919
|
+
const content = Array.isArray(parsed["content"]) ? parsed["content"] : [];
|
|
10920
|
+
for (const part of content) {
|
|
10921
|
+
const partType = typeof part["type"] === "string" ? part["type"] : "";
|
|
10922
|
+
const partTime = part["time"];
|
|
10923
|
+
const partCreated = typeof partTime?.["created"] === "number" ? partTime["created"] : typeof partTime?.["completed"] === "number" ? partTime["completed"] : created;
|
|
10924
|
+
const partBase = {
|
|
10925
|
+
...base,
|
|
10926
|
+
timestamp: partCreated,
|
|
10927
|
+
raw: { ...base.raw, part }
|
|
10928
|
+
};
|
|
10929
|
+
if (partType === "reasoning") {
|
|
10930
|
+
const text = typeof part["text"] === "string" ? part["text"] : "";
|
|
10931
|
+
out.push({
|
|
10932
|
+
...partBase,
|
|
10933
|
+
eventType: "model-reasoning",
|
|
10934
|
+
data: { messageID: row.id, message: text }
|
|
10935
|
+
});
|
|
10936
|
+
continue;
|
|
10937
|
+
}
|
|
10938
|
+
if (partType === "text") {
|
|
10939
|
+
const text = typeof part["text"] === "string" ? part["text"] : "";
|
|
10940
|
+
out.push({
|
|
10941
|
+
...partBase,
|
|
10942
|
+
eventType: "notification",
|
|
10943
|
+
data: { messageID: row.id, message: text }
|
|
10944
|
+
});
|
|
10945
|
+
continue;
|
|
10946
|
+
}
|
|
10947
|
+
if (partType !== "tool")
|
|
10948
|
+
continue;
|
|
10949
|
+
const rawName = typeof part["name"] === "string" ? part["name"] : typeof part["tool"] === "string" ? part["tool"] : "unknown";
|
|
10950
|
+
const toolName = mapToolName(rawName);
|
|
10951
|
+
const callID = typeof part["id"] === "string" ? part["id"] : `${row.id}-${partCreated}`;
|
|
10952
|
+
const state = typeof part["state"] === "object" && part["state"] !== null ? part["state"] : {};
|
|
10953
|
+
const input = state["input"];
|
|
10954
|
+
const status = typeof state["status"] === "string" ? state["status"].toLowerCase() : "";
|
|
10955
|
+
const failed = status.includes("fail") || status.includes("error") || part["error"] != null;
|
|
10956
|
+
const pre = {
|
|
10957
|
+
...partBase,
|
|
10958
|
+
eventType: "pre-tool-use",
|
|
10959
|
+
toolName,
|
|
10960
|
+
toolInput: input,
|
|
10961
|
+
data: { callID, tool: rawName }
|
|
10962
|
+
};
|
|
10963
|
+
applyFileContext(pre, rawName, input);
|
|
10964
|
+
out.push(pre);
|
|
10965
|
+
const post = {
|
|
10966
|
+
...partBase,
|
|
10967
|
+
timestamp: typeof partTime?.["completed"] === "number" ? partTime["completed"] : partCreated,
|
|
10968
|
+
eventType: failed ? "post-tool-use-failure" : "post-tool-use",
|
|
10969
|
+
toolName,
|
|
10970
|
+
toolInput: input,
|
|
10971
|
+
toolOutput: state["content"] ?? state["output"] ?? state["metadata"],
|
|
10972
|
+
data: { callID, tool: rawName, status: state["status"] }
|
|
10973
|
+
};
|
|
10974
|
+
applyFileContext(post, rawName, input);
|
|
10975
|
+
out.push(post);
|
|
10976
|
+
}
|
|
10977
|
+
}
|
|
10978
|
+
return out;
|
|
10979
|
+
}
|
|
10980
|
+
|
|
10981
|
+
// src/bun/session-pipeline.ts
|
|
10982
|
+
function openCodeDBPath2() {
|
|
10983
|
+
const env = process.env;
|
|
10984
|
+
if (env["OPENCODE_DATA_DIR"])
|
|
10985
|
+
return `${env["OPENCODE_DATA_DIR"]}/opencode/opencode.db`;
|
|
10986
|
+
const home = env["HOME"] || env["USERPROFILE"] || "/root";
|
|
10987
|
+
const xdgData = env["XDG_DATA_HOME"] || `${home}/.local/share`;
|
|
10988
|
+
return `${xdgData}/opencode/opencode.db`;
|
|
10989
|
+
}
|
|
10756
10990
|
var INCLUDE_RAW_EVENT_PAYLOADS = (process.env["TRAIL_INCLUDE_RAW"] ?? "") === "1";
|
|
10757
10991
|
function wantRawPayloads(requestIncludeRaw) {
|
|
10758
10992
|
return INCLUDE_RAW_EVENT_PAYLOADS || requestIncludeRaw;
|
|
@@ -10778,6 +11012,104 @@ var cursorReader = new CursorSessionReader;
|
|
|
10778
11012
|
function isCursorSession(sessionId) {
|
|
10779
11013
|
return cursorReader.readSession(sessionId) !== null;
|
|
10780
11014
|
}
|
|
11015
|
+
async function runOpencodeV2MessagePipeline(sessionId) {
|
|
11016
|
+
const record = readOpencodeV2Session(sessionId);
|
|
11017
|
+
if (!record)
|
|
11018
|
+
return null;
|
|
11019
|
+
const sessionTitle = record.meta.title || "OpenCode V2 session";
|
|
11020
|
+
const sessionSlug = record.meta.slug || "";
|
|
11021
|
+
const workingDirectory = record.meta.directory ?? "";
|
|
11022
|
+
const rawEvents = sessionMessagesToUniversalEvents(sessionId, record.messages, {
|
|
11023
|
+
workingDirectory
|
|
11024
|
+
});
|
|
11025
|
+
if (rawEvents.length === 0)
|
|
11026
|
+
return null;
|
|
11027
|
+
const alexandriaRepos = loadAlexandriaRepos();
|
|
11028
|
+
const knownRoots = new Map;
|
|
11029
|
+
for (const [path, repo] of alexandriaRepos) {
|
|
11030
|
+
knownRoots.set(path, {
|
|
11031
|
+
root: repo.root,
|
|
11032
|
+
remoteUrl: repo.remoteUrl,
|
|
11033
|
+
owner: repo.owner,
|
|
11034
|
+
repo: repo.repo
|
|
11035
|
+
});
|
|
11036
|
+
}
|
|
11037
|
+
const adapter = new BunNormalizationAdapter(knownRoots);
|
|
11038
|
+
const normalizationService = new PathNormalizationService(adapter);
|
|
11039
|
+
const normalizedEvents = await normalizationService.normalizePathsBatch(rawEvents, workingDirectory);
|
|
11040
|
+
for (const discovered of adapter.newlyDiscovered) {
|
|
11041
|
+
registerProjectInAlexandria(discovered.root, discovered.remoteUrl);
|
|
11042
|
+
}
|
|
11043
|
+
const accState = createAccumulatedState(sessionTitle);
|
|
11044
|
+
const events = [];
|
|
11045
|
+
const repoSet = new Map;
|
|
11046
|
+
for (let i = 0;i < normalizedEvents.length; i++) {
|
|
11047
|
+
const normalizedEvent = normalizedEvents[i];
|
|
11048
|
+
const accResult = eventOp(accState, normalizedEvent);
|
|
11049
|
+
events.push({
|
|
11050
|
+
seq: i,
|
|
11051
|
+
type: normalizedEvent.eventType,
|
|
11052
|
+
raw: INCLUDE_RAW_EVENT_PAYLOADS ? normalizedEvent.raw : undefined,
|
|
11053
|
+
normalized: INCLUDE_RAW_EVENT_PAYLOADS ? normalizedEvent : { timestamp: normalizedEvent.timestamp },
|
|
11054
|
+
accumulated: accResult
|
|
11055
|
+
});
|
|
11056
|
+
if (normalizedEvent.files) {
|
|
11057
|
+
for (const f of normalizedEvent.files) {
|
|
11058
|
+
const root = f.repository?.gitRoot;
|
|
11059
|
+
if (root) {
|
|
11060
|
+
const entry = repoSet.get(root) ?? { root, fileCount: 0 };
|
|
11061
|
+
entry.fileCount++;
|
|
11062
|
+
repoSet.set(root, entry);
|
|
11063
|
+
}
|
|
11064
|
+
}
|
|
11065
|
+
}
|
|
11066
|
+
}
|
|
11067
|
+
const lastEvent = events[events.length - 1];
|
|
11068
|
+
if (lastEvent) {
|
|
11069
|
+
const lastTimestamp = lastEvent.normalized["timestamp"] ?? 0;
|
|
11070
|
+
events.push({
|
|
11071
|
+
seq: lastEvent.seq + 1,
|
|
11072
|
+
type: "finished",
|
|
11073
|
+
raw: null,
|
|
11074
|
+
normalized: { timestamp: lastTimestamp },
|
|
11075
|
+
accumulated: {
|
|
11076
|
+
id: "",
|
|
11077
|
+
timestamp: lastTimestamp,
|
|
11078
|
+
sessionId: sessionSlug || sessionId,
|
|
11079
|
+
sessionName: accState.sessionName,
|
|
11080
|
+
sessionColor: accState.sessionColor,
|
|
11081
|
+
operation: "finished",
|
|
11082
|
+
files: [],
|
|
11083
|
+
dependencies: [],
|
|
11084
|
+
description: `${accState.sessionName} finished`,
|
|
11085
|
+
layers: [],
|
|
11086
|
+
contextTokens: accState.contextTokens
|
|
11087
|
+
}
|
|
11088
|
+
});
|
|
11089
|
+
}
|
|
11090
|
+
const repos = Array.from(repoSet.values()).sort((a, b) => b.fileCount - a.fileCount).map((r) => {
|
|
11091
|
+
const parts = r.root.replace(/\/+$/, "").split("/");
|
|
11092
|
+
const known = knownRoots.get(r.root);
|
|
11093
|
+
return {
|
|
11094
|
+
root: r.root,
|
|
11095
|
+
fileCount: r.fileCount,
|
|
11096
|
+
owner: known?.owner ?? null,
|
|
11097
|
+
name: parts[parts.length - 1] ?? null,
|
|
11098
|
+
editing: false
|
|
11099
|
+
};
|
|
11100
|
+
});
|
|
11101
|
+
const repoRoot = repos.length > 0 ? repos[0].root : undefined;
|
|
11102
|
+
return {
|
|
11103
|
+
rawEvents,
|
|
11104
|
+
normalizedEvents,
|
|
11105
|
+
accState,
|
|
11106
|
+
events,
|
|
11107
|
+
repos,
|
|
11108
|
+
repoRoot,
|
|
11109
|
+
sessionTitle,
|
|
11110
|
+
sessionSlug
|
|
11111
|
+
};
|
|
11112
|
+
}
|
|
10781
11113
|
async function runClinePipeline(sessionId) {
|
|
10782
11114
|
const record = clineReader.readSession(sessionId);
|
|
10783
11115
|
if (!record)
|
|
@@ -11241,7 +11573,7 @@ function dbFingerprint(dbPath) {
|
|
|
11241
11573
|
async function buildSessionIndex({ days }) {
|
|
11242
11574
|
const dayCount = Math.max(1, Math.floor(days ?? 7));
|
|
11243
11575
|
const cutoff = Date.now() - dayCount * 86400000;
|
|
11244
|
-
const dbPath =
|
|
11576
|
+
const dbPath = openCodeDBPath2();
|
|
11245
11577
|
const cacheKey = `${dayCount}|${dbFingerprint(dbPath)}`;
|
|
11246
11578
|
const cached = indexCache.get(cacheKey);
|
|
11247
11579
|
if (cached)
|
|
@@ -11249,8 +11581,8 @@ async function buildSessionIndex({ days }) {
|
|
|
11249
11581
|
let result;
|
|
11250
11582
|
let db = null;
|
|
11251
11583
|
try {
|
|
11252
|
-
const { Database } = await import("bun:sqlite");
|
|
11253
|
-
db = new
|
|
11584
|
+
const { Database: Database2 } = await import("bun:sqlite");
|
|
11585
|
+
db = new Database2(dbPath, { readonly: true });
|
|
11254
11586
|
const firstEvents = db.prepare(`SELECT
|
|
11255
11587
|
e.aggregate_id,
|
|
11256
11588
|
e.data
|
|
@@ -11263,6 +11595,7 @@ async function buildSessionIndex({ days }) {
|
|
|
11263
11595
|
let title = row.aggregate_id.slice(0, 12);
|
|
11264
11596
|
let slug = "";
|
|
11265
11597
|
let createdAtStr = "";
|
|
11598
|
+
let agentFromInfo;
|
|
11266
11599
|
const durationMs = 0;
|
|
11267
11600
|
try {
|
|
11268
11601
|
const parsed = JSON.parse(row.data);
|
|
@@ -11275,12 +11608,18 @@ async function buildSessionIndex({ days }) {
|
|
|
11275
11608
|
if (typeof rawSlug === "string") {
|
|
11276
11609
|
slug = rawSlug;
|
|
11277
11610
|
}
|
|
11611
|
+
const rawAgent = info?.["agent"];
|
|
11612
|
+
if (typeof rawAgent === "string") {
|
|
11613
|
+
agentFromInfo = rawAgent;
|
|
11614
|
+
}
|
|
11278
11615
|
const rawTime = info?.["time"];
|
|
11279
11616
|
const rawCreated = rawTime?.["created"];
|
|
11280
11617
|
if (typeof rawCreated === "number") {
|
|
11281
11618
|
createdAtStr = new Date(rawCreated).toISOString();
|
|
11282
11619
|
}
|
|
11283
11620
|
} catch {}
|
|
11621
|
+
if (isMaintainSession({ title, agent: agentFromInfo }))
|
|
11622
|
+
continue;
|
|
11284
11623
|
const createdMs = createdAtStr ? new Date(createdAtStr).getTime() : 0;
|
|
11285
11624
|
if (!createdMs)
|
|
11286
11625
|
continue;
|
|
@@ -11606,6 +11945,17 @@ async function processSessionEvents(sessionId, opts) {
|
|
|
11606
11945
|
return { ok: false, error: err.message };
|
|
11607
11946
|
}
|
|
11608
11947
|
}
|
|
11948
|
+
if (isOpencodeV2Session(sessionId)) {
|
|
11949
|
+
try {
|
|
11950
|
+
const result = await runOpencodeV2MessagePipeline(sessionId);
|
|
11951
|
+
if (!result) {
|
|
11952
|
+
return { ok: false, error: "OpenCode V2 session not found or empty" };
|
|
11953
|
+
}
|
|
11954
|
+
return respondWithCachedPipeline(sessionId, "opencode-v2", result);
|
|
11955
|
+
} catch (err) {
|
|
11956
|
+
return { ok: false, error: err.message };
|
|
11957
|
+
}
|
|
11958
|
+
}
|
|
11609
11959
|
const cacheKey = `opencode:${sessionId}:${includeRaw ? "raw" : "min"}`;
|
|
11610
11960
|
let events = sessionEventsCache.get(cacheKey);
|
|
11611
11961
|
let sessionSlug = "";
|
|
@@ -11613,11 +11963,11 @@ async function processSessionEvents(sessionId, opts) {
|
|
|
11613
11963
|
let repoRoot;
|
|
11614
11964
|
let repos = [];
|
|
11615
11965
|
if (!events) {
|
|
11616
|
-
const dbPath =
|
|
11966
|
+
const dbPath = openCodeDBPath2();
|
|
11617
11967
|
let db = null;
|
|
11618
11968
|
try {
|
|
11619
|
-
const { Database } = await import("bun:sqlite");
|
|
11620
|
-
db = new
|
|
11969
|
+
const { Database: Database2 } = await import("bun:sqlite");
|
|
11970
|
+
db = new Database2(dbPath, { readonly: true });
|
|
11621
11971
|
const rows = db.prepare(`SELECT id, aggregate_id, seq, type, data FROM event WHERE aggregate_id = ? ORDER BY seq ASC`).all(sessionId);
|
|
11622
11972
|
if (rows.length > 0) {
|
|
11623
11973
|
try {
|
|
@@ -11711,13 +12061,15 @@ async function processSessionEvents(sessionId, opts) {
|
|
|
11711
12061
|
}).sort((a, b) => b.fileCount - a.fileCount);
|
|
11712
12062
|
repoRoot = repos.length > 0 ? repos[0].root : undefined;
|
|
11713
12063
|
events = built;
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
12064
|
+
if (built.length > 0) {
|
|
12065
|
+
writeCachedSessionEvents(sessionId, {
|
|
12066
|
+
agent: "opencode",
|
|
12067
|
+
session: { slug: sessionSlug, title: sessionTitle, agent: "opencode" },
|
|
12068
|
+
repoRoot,
|
|
12069
|
+
repos,
|
|
12070
|
+
events: trimSessionEventRows(built)
|
|
12071
|
+
});
|
|
12072
|
+
}
|
|
11721
12073
|
sessionEventsCache.set(cacheKey, events);
|
|
11722
12074
|
while (sessionEventsCache.size > 4) {
|
|
11723
12075
|
const oldestKey = sessionEventsCache.keys().next().value;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principal-ai/subsystems-studio",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "Subsystems Studio — desktop host for subsystem models,
|
|
3
|
+
"version": "0.6.9",
|
|
4
|
+
"description": "Subsystems Studio — desktop host for subsystem models, walkthroughs, trails, and agent sessions. Pairs with the principal-ai CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"os": [
|
|
7
7
|
"darwin"
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"@principal-ai/file-city-react": "^0.5.91",
|
|
45
45
|
"@principal-ai/logo-component": "^0.1.23",
|
|
46
46
|
"@principal-ai/repository-abstraction": "^0.5.7",
|
|
47
|
-
"@principal-ai/subsystems-core": "0.
|
|
48
|
-
"@principal-ai/subsystems-react": "0.
|
|
47
|
+
"@principal-ai/subsystems-core": "0.32.0",
|
|
48
|
+
"@principal-ai/subsystems-react": "0.21.1",
|
|
49
49
|
"@types/bun": "latest",
|
|
50
50
|
"@types/react": "^19.2.17",
|
|
51
51
|
"@types/react-dom": "^19.2.3",
|