pi2dsh 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{analyzer-BgkCub5L.mjs → analyzer-BcuRfHLG.mjs} +2 -2
- package/dist/{analyzer-BgkCub5L.mjs.map → analyzer-BcuRfHLG.mjs.map} +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/host.d.mts +6 -0
- package/dist/host.d.mts.map +1 -1
- package/dist/host.mjs +2 -2
- package/dist/host.mjs.map +1 -1
- package/dist/index.d.mts +4 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +26 -5
- package/dist/index.mjs.map +1 -1
- package/dist/{mcp-config-DoufpLUI.mjs → mcp-config-NvRpjToH.mjs} +12 -12
- package/dist/mcp-config-NvRpjToH.mjs.map +1 -0
- package/dist/{runtime-DE2dU1cA.mjs → runtime-C-cmLDY0.mjs} +128 -15
- package/dist/runtime-C-cmLDY0.mjs.map +1 -0
- package/dist/runtime.d.mts +23 -6
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/package.json +1 -1
- package/dist/mcp-config-DoufpLUI.mjs.map +0 -1
- package/dist/runtime-DE2dU1cA.mjs.map +0 -1
|
@@ -6,7 +6,7 @@ import { W as getKeybindings, _t as stripTerminalSequences } from "./pi-tui-DruS
|
|
|
6
6
|
import { c as resolvePiProviderAuth, i as oauthCredentialRef, l as storedOAuthCredential, n as joinSignals, o as providerSupportsOAuth, r as loginPiProvider, t as FileCredentialStore } from "./oauth-bridge-C_MAPMGA.mjs";
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
8
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
9
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
9
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
10
10
|
import { basename, dirname, join, resolve } from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
@@ -27,6 +27,81 @@ function entrySeq(id) {
|
|
|
27
27
|
const match = /^dsh-(\d+)$/.exec(id);
|
|
28
28
|
return match === null ? void 0 : Number(match[1]);
|
|
29
29
|
}
|
|
30
|
+
/** One Pi-only record as the Pi session-file entry line it is stored as. */
|
|
31
|
+
function piEntryLineOf(record) {
|
|
32
|
+
const base = {
|
|
33
|
+
id: record.id,
|
|
34
|
+
parentId: null,
|
|
35
|
+
timestamp: record.timestamp
|
|
36
|
+
};
|
|
37
|
+
switch (record.kind) {
|
|
38
|
+
case "custom": return JSON.stringify({
|
|
39
|
+
type: "custom",
|
|
40
|
+
...base,
|
|
41
|
+
customType: record.customType,
|
|
42
|
+
...record.data === void 0 ? {} : { data: record.data }
|
|
43
|
+
});
|
|
44
|
+
case "label": return JSON.stringify({
|
|
45
|
+
type: "label",
|
|
46
|
+
...base,
|
|
47
|
+
targetId: record.targetId,
|
|
48
|
+
...record.label === void 0 ? {} : { label: record.label }
|
|
49
|
+
});
|
|
50
|
+
case "branch_summary": return JSON.stringify({
|
|
51
|
+
type: "branch_summary",
|
|
52
|
+
...base,
|
|
53
|
+
fromId: record.fromId,
|
|
54
|
+
summary: record.summary
|
|
55
|
+
});
|
|
56
|
+
case "name": return JSON.stringify({
|
|
57
|
+
type: "session_info",
|
|
58
|
+
...base,
|
|
59
|
+
name: record.name
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Normalize one parsed session-file line back into a record. Understands the
|
|
65
|
+
* Pi entry shapes this bridge writes today AND the pre-0.18 private
|
|
66
|
+
* `{kind: …}` lines, so archives written by older engines keep loading. A Pi
|
|
67
|
+
* header line and anything unrecognized return undefined.
|
|
68
|
+
*/
|
|
69
|
+
function recordOfParsedLine(parsed) {
|
|
70
|
+
if (typeof parsed.kind === "string") return parsed;
|
|
71
|
+
const id = typeof parsed.id === "string" ? parsed.id : void 0;
|
|
72
|
+
const timestamp = typeof parsed.timestamp === "string" ? parsed.timestamp : void 0;
|
|
73
|
+
if (id === void 0 || timestamp === void 0) return void 0;
|
|
74
|
+
switch (parsed.type) {
|
|
75
|
+
case "custom": return {
|
|
76
|
+
kind: "custom",
|
|
77
|
+
id,
|
|
78
|
+
timestamp,
|
|
79
|
+
customType: String(parsed.customType ?? ""),
|
|
80
|
+
...parsed.data === void 0 ? {} : { data: parsed.data }
|
|
81
|
+
};
|
|
82
|
+
case "label": return {
|
|
83
|
+
kind: "label",
|
|
84
|
+
id,
|
|
85
|
+
timestamp,
|
|
86
|
+
...typeof parsed.targetId === "string" ? { targetId: parsed.targetId } : {},
|
|
87
|
+
...typeof parsed.label === "string" ? { label: parsed.label } : {}
|
|
88
|
+
};
|
|
89
|
+
case "branch_summary": return {
|
|
90
|
+
kind: "branch_summary",
|
|
91
|
+
id,
|
|
92
|
+
timestamp,
|
|
93
|
+
...typeof parsed.summary === "string" ? { summary: parsed.summary } : {},
|
|
94
|
+
...typeof parsed.fromId === "string" ? { fromId: parsed.fromId } : {}
|
|
95
|
+
};
|
|
96
|
+
case "session_info": return {
|
|
97
|
+
kind: "name",
|
|
98
|
+
id,
|
|
99
|
+
timestamp,
|
|
100
|
+
...typeof parsed.name === "string" ? { name: parsed.name } : {}
|
|
101
|
+
};
|
|
102
|
+
default: return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
30
105
|
function sidecarDir() {
|
|
31
106
|
return join(getAgentDir(), "session-entries");
|
|
32
107
|
}
|
|
@@ -72,17 +147,24 @@ var PiSessionBridge = class {
|
|
|
72
147
|
/**
|
|
73
148
|
* The Pi-visible archive file for one DSH session — the established
|
|
74
149
|
* `<id>.jsonl` convention (getSessionFile/switchSession use the same one).
|
|
75
|
-
* Guaranteed to EXIST on return
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
150
|
+
* Guaranteed to EXIST on return, and to start with a genuine Pi
|
|
151
|
+
* `{type:"session"}` header line: Pi consumers treat the session file as
|
|
152
|
+
* the durable identity a conversation can be reopened by (pi-subagents
|
|
153
|
+
* guards its tombstone resurrect with existsSync), and real Pi parsing
|
|
154
|
+
* (`SessionManager.open` reads the header for id/cwd) must see a Pi file,
|
|
155
|
+
* not a bare inode. An empty pre-existing file is upgraded in place.
|
|
80
156
|
*/
|
|
81
|
-
archiveFileFor(sessionId) {
|
|
157
|
+
archiveFileFor(sessionId, cwd) {
|
|
82
158
|
const path = this.sidecarPath(sessionId);
|
|
83
|
-
if (!existsSync(path)) {
|
|
159
|
+
if (!existsSync(path) || readFileSync(path, "utf8").trim().length === 0) {
|
|
84
160
|
mkdirSync(sidecarDir(), { recursive: true });
|
|
85
|
-
appendFileSync(path,
|
|
161
|
+
appendFileSync(path, `${JSON.stringify({
|
|
162
|
+
type: "session",
|
|
163
|
+
version: 3,
|
|
164
|
+
id: sessionId,
|
|
165
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
166
|
+
cwd: cwd ?? process.cwd()
|
|
167
|
+
})}\n`);
|
|
86
168
|
}
|
|
87
169
|
return path;
|
|
88
170
|
}
|
|
@@ -100,6 +182,19 @@ var PiSessionBridge = class {
|
|
|
100
182
|
const base = basename(resolved);
|
|
101
183
|
return base.endsWith(".jsonl") ? base.slice(0, -6) : void 0;
|
|
102
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Retire one archive this bridge minted: the file whose existence tells Pi
|
|
187
|
+
* consumers "this conversation can be reopened". Called ONLY on a positive
|
|
188
|
+
* persistence-layer verdict that the DSH session is gone, so existsSync
|
|
189
|
+
* answers honestly again.
|
|
190
|
+
*/
|
|
191
|
+
discardArchive(sessionId) {
|
|
192
|
+
try {
|
|
193
|
+
unlinkSync(this.sidecarPath(sessionId));
|
|
194
|
+
} catch {}
|
|
195
|
+
this.records.delete(sessionId);
|
|
196
|
+
this.loaded.delete(sessionId);
|
|
197
|
+
}
|
|
103
198
|
load(sessionId) {
|
|
104
199
|
if (this.loaded.has(sessionId)) return;
|
|
105
200
|
this.loaded.add(sessionId);
|
|
@@ -112,7 +207,8 @@ var PiSessionBridge = class {
|
|
|
112
207
|
for (const line of readFileSync(path, "utf8").split("\n")) {
|
|
113
208
|
if (line.trim().length === 0) continue;
|
|
114
209
|
try {
|
|
115
|
-
|
|
210
|
+
const record = recordOfParsedLine(JSON.parse(line));
|
|
211
|
+
if (record !== void 0) parsed.push(record);
|
|
116
212
|
} catch {}
|
|
117
213
|
}
|
|
118
214
|
this.records.set(sessionId, parsed);
|
|
@@ -122,8 +218,8 @@ var PiSessionBridge = class {
|
|
|
122
218
|
const list = this.records.get(sessionId) ?? [];
|
|
123
219
|
list.push(record);
|
|
124
220
|
this.records.set(sessionId, list);
|
|
125
|
-
|
|
126
|
-
appendFileSync(this.sidecarPath(sessionId), `${
|
|
221
|
+
this.archiveFileFor(sessionId);
|
|
222
|
+
appendFileSync(this.sidecarPath(sessionId), `${piEntryLineOf(record)}\n`);
|
|
127
223
|
}
|
|
128
224
|
appendCustomEntry(sessionId, customType, data) {
|
|
129
225
|
const id = randomUUID();
|
|
@@ -338,7 +434,7 @@ var PiSessionBridge = class {
|
|
|
338
434
|
getCwd: () => cwd,
|
|
339
435
|
getSessionDir: () => sidecarDir(),
|
|
340
436
|
getSessionId: () => session.id,
|
|
341
|
-
getSessionFile: () => this.archiveFileFor(session.id),
|
|
437
|
+
getSessionFile: () => this.archiveFileFor(session.id, cwd),
|
|
342
438
|
getLeafId: () => leafOf()?.id ?? null,
|
|
343
439
|
getLeafEntry: () => leafOf(),
|
|
344
440
|
getEntry: (id) => entriesOf().find((entry) => entry.id === id),
|
|
@@ -949,7 +1045,14 @@ async function createBridgedAgentSession(host, options) {
|
|
|
949
1045
|
setup
|
|
950
1046
|
});
|
|
951
1047
|
} catch (error) {
|
|
952
|
-
|
|
1048
|
+
if (resumeSessionId !== void 0) {
|
|
1049
|
+
if (await host.sessionGoneFromPersistence?.(resumeSessionId) === true) {
|
|
1050
|
+
host.discardStaleArchive?.(resumeSessionId);
|
|
1051
|
+
throw new Error(`pi2dsh: child session ${JSON.stringify(resumeSessionId)} no longer exists in the host's session persistence — the conversation is gone and its archive identity has been retired (${error instanceof Error ? error.message : String(error)})`);
|
|
1052
|
+
}
|
|
1053
|
+
throw new Error(`pi2dsh: reopening child session ${JSON.stringify(resumeSessionId)} failed — this composition may lack session persistence (${error instanceof Error ? error.message : String(error)})`);
|
|
1054
|
+
}
|
|
1055
|
+
throw new Error(`pi2dsh: subagent creation needs the DSH host loop (model runtime) to provide the agent factory; this composition cannot run one (${error instanceof Error ? error.message : String(error)})`);
|
|
953
1056
|
}
|
|
954
1057
|
const tools = [...Array.isArray(options.tools) ? options.tools : [], ...Array.isArray(options.customTools) ? options.customTools : []];
|
|
955
1058
|
const childSession = handle.agent.session;
|
|
@@ -6779,6 +6882,16 @@ async function applyPiPackage(ctx, options) {
|
|
|
6779
6882
|
return state.bridge.readonlySessionManager(session, cwd);
|
|
6780
6883
|
},
|
|
6781
6884
|
resumeSessionIdFor: (file) => state.bridge.sessionIdOfArchiveFile(file),
|
|
6885
|
+
sessionGoneFromPersistence: async (sessionId) => {
|
|
6886
|
+
const persistence = optionalService(ctx, "sessionPersistence");
|
|
6887
|
+
if (typeof persistence?.list !== "function") return void 0;
|
|
6888
|
+
try {
|
|
6889
|
+
return !(await persistence.list()).some((header) => String(header?.id ?? "") === sessionId);
|
|
6890
|
+
} catch {
|
|
6891
|
+
return;
|
|
6892
|
+
}
|
|
6893
|
+
},
|
|
6894
|
+
discardStaleArchive: (sessionId) => state.bridge.discardArchive(sessionId),
|
|
6782
6895
|
parentModelRoute: () => {
|
|
6783
6896
|
const parent = currentAgent(state);
|
|
6784
6897
|
if (parent === void 0) return void 0;
|
|
@@ -6849,4 +6962,4 @@ const runtimeInternals = {
|
|
|
6849
6962
|
//#endregion
|
|
6850
6963
|
export { registerVisionCompanions as a, overlayProviderConfig as i, mergeProviderRegistration as n, runtimeInternals as o, normalizeToolSchema as r, applyPiPackage as t };
|
|
6851
6964
|
|
|
6852
|
-
//# sourceMappingURL=runtime-
|
|
6965
|
+
//# sourceMappingURL=runtime-C-cmLDY0.mjs.map
|