@tea-agent/loop-agent 0.41.1 → 0.41.2
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/CHANGELOG.md +15 -1
- package/dist/build-stamp.json +3 -3
- package/dist/executors/pi-extension-resolver.js +14 -2
- package/dist/worker/console/chat/pi-runtime.js +60 -5
- package/dist/worker/console/chat/routes.js +44 -22
- package/dist/worker/console/chat/session-store.js +16 -0
- package/dist/worker/console/server.js +19 -1
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-D7oU983t.js → abnfDiagram-N423BO3Z-DQ5jlYVU.js} +1 -1
- package/dist/worker/console/static/assets/{arc-BrKSRdFS.js → arc-BeTVCzH9.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CiXV7L56.js → architectureDiagram-T3A2C74G-DassREBi.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-D_Hs_gIG.js → blockDiagram-VBNYF7ZC-DyeNX8Ek.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DbM-Lqqh.js → c4Diagram-5PPSVZJV-BXb_zxGx.js} +1 -1
- package/dist/worker/console/static/assets/channel-B_lofstT.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D1M8uqJw.js → chunk-2GRJ4B5K-B9F9gxGC.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-4D3RFHT6.js → chunk-2Q5K7J3B-Byd5zHEQ.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CdwpY_n9.js → chunk-5RXB4S5H-BqoxMJk9.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BLeLZ9PG.js → chunk-5VM5RSS4-CT7d6YZw.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-CeRNEMvc.js → chunk-6Q2QTUOP-CdiNyN0N.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CjkHP8Vy.js → chunk-GF5L2VYU-BGw9bpVc.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-B54ZUQY-.js → chunk-JWPE2WC7-DiDVlVB1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-4bKaMVmx.js → chunk-KBJHAD2P-BhHf-4yK.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-Cyjfznu_.js → chunk-RYQCIY6F-B79pEgwv.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CDN-zGFV.js → chunk-XXDRQBXY-Cb70EcUV.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-ieUI0-eY.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-ieUI0-eY.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-HxJmz411.js → cose-bilkent-JH36ORCC-DBHLnAf1.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DtSt5K2w.js → cynefin-VYW2F7L2-BT_JRsOH.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-VtkSpRmG.js → cynefinDiagram-MW4NZA55-Bss-msa3.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-Bj4DT4du.js → dagre-VZM6K2ZE-B8Gr24pt.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-Bpuk6BmP.js → diagram-7IWD3JNH-BrjU70Jw.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BHYGv_yO.js → diagram-B4RE2ZJO-Cp_JpPGd.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DEx3WwnT.js → diagram-LBJQPF4R-BWKICEP-.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-Cj0dS5e8.js → diagram-Q27KOJAE-D3z_UNR_.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-B97h8l21.js → diagram-UB23O5K3-_Ywm390x.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DMSFAhBd.js → ebnfDiagram-BXEA7PRR-D9QYQQMB.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DhVOCbt6.js → erDiagram-JOGREHBK-BNgXNKAr.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-GlakITWL.js → flowDiagram-UKHOOZJN-QRLnkPCg.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-VxPpu9eQ.js → ganttDiagram-PKOTCBZU-B9fOduNi.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bs_e5DRT.js → gitGraphDiagram-DS77QQ5N-FSEdtPN2.js} +1 -1
- package/dist/worker/console/static/assets/{index-BLzcAykx.js → index-DtPrwu7M.js} +71 -71
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BXYuU4Uw.js → infoDiagram-6WML65LV-D5Bjg9dm.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C34erCbU.js → ishikawaDiagram-WSZJBQD7-BlNRkWvf.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DZCAiOU3.js → journeyDiagram-NVQOT4AX-BdJiw3SL.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-C9gaTdUm.js → kanban-definition-27J2QSJJ-CsDNlYht.js} +1 -1
- package/dist/worker/console/static/assets/{linear-CvI0Z17U.js → linear-8g9dbEmX.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-DMMSIx7j.js → mermaid.core-ChyQH_ut.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-BKKP0EO6.js → mindmap-definition-FAOFIHXS-DwYoCTYt.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-C3LiFbl5.js → pegDiagram-VL7TDLO6-T_b2rS17.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-Bb3Om2Dz.js → pieDiagram-7S7Q4E2Y-1Cr7WMhH.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DNthMjzc.js → quadrantDiagram-CIZ2JOQS-Bq4qM59o.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-miFsr4Tv.js → railroadDiagram-AXF67PYL-ytFgR1RL.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-yXUncmn6.js → requirementDiagram-LRYGKXZP-CnUdUVYX.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DLeWKLak.js → sankeyDiagram-W5VNT64P-_5rJqG6R.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CI3he1R3.js → sequenceDiagram-SI44F4Z6-D5imyGbt.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-B7jfDkS5.js → sizeCapture-X5ZJPWSS-DvgDn3wL.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BmrZod7J.js → stateDiagram-OKZ733FA-BViu7duc.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-kNxnG4_w.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CDOlHVSY.js → swimlanes-SLNWSIFB-BcULKg2P.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DyTzlcWH.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cz-XX1gy.js → timeline-definition-Z64GVDOM-DmPveIjt.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-caV4cI8C.js → vennDiagram-T6HMQDX7-9r-iFy0R.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-dImPlnIO.js → wardleyDiagram-T6FBY63Y-D3fIXdvM.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CtRYVJcn.js → xychartDiagram-ELKLHX3M-BCSS9SBg.js} +1 -1
- package/dist/worker/console/static/index.html +1 -1
- package/dist/worker/console/static-src/shell/workspace-route.js +4 -0
- package/dist/worker/observe/routes.js +4 -0
- package/package.json +1 -1
- package/dist/worker/console/static/assets/channel-D1xajGpe.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BmuGTfRr.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BmuGTfRr.js +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-D9ykKEWP.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BvPOXALT.js +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
## [0.41.
|
|
5
|
+
## [0.41.2] - 2026-09-04
|
|
6
6
|
|
|
7
7
|
### 新增
|
|
8
8
|
|
|
@@ -16,6 +16,20 @@
|
|
|
16
16
|
|
|
17
17
|
- 修复了影响使用体验或运行稳定性的问题。
|
|
18
18
|
|
|
19
|
+
## [0.41.1] - 2026-09-02
|
|
20
|
+
|
|
21
|
+
### 修复
|
|
22
|
+
|
|
23
|
+
- 修复 Next Release 发布 workflow 的 io-heavy 测试并发不稳定:将该测试池固定为单 worker,避免全部测试通过后因过高并发触发 Vitest `onTaskUpdate` RPC settlement timeout,并消除 controller identity / package fingerprint 测试之间的共享状态竞态。
|
|
24
|
+
- 修复 Operator Chat 旧会话继续使用过期模型认证的问题:模型配置变化后,下一轮发送或手动重新加载会自动刷新模型目录和当前模型认证。
|
|
25
|
+
- 修复 Operator Chat 长工具链的消息错序:模型过程文字、思考和工具卡片现在按服务端事件顺序稳定交替展示,刷新历史会话后也保持相同顺序。
|
|
26
|
+
- 统一工作区、Todo 和其他滚动区域的滚动条样式,默认更轻巧,鼠标悬浮时也更容易辨认。
|
|
27
|
+
- HTML 文件预览现在支持页面内的标签切换等交互;较大的自包含 HTML 可以在新窗口中直接完整加载,不再受源码摘要长度限制。
|
|
28
|
+
|
|
29
|
+
### 测试
|
|
30
|
+
|
|
31
|
+
- `harness.json` Pi MED 档测试不再 pin 具体模型 id,改为校验 tier 形状,避免每次 dogfood 档位切换都造成测试失败。
|
|
32
|
+
|
|
19
33
|
## [0.41.0] - 2026-08-31
|
|
20
34
|
|
|
21
35
|
### 新增
|
package/dist/build-stamp.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.41.
|
|
4
|
-
"gitSha": "
|
|
5
|
-
"builtAt": "2026-09-
|
|
3
|
+
"version": "0.41.2",
|
|
4
|
+
"gitSha": "25160b4bb4a3933642d33e6d00d860d31c6b370b",
|
|
5
|
+
"builtAt": "2026-09-04T11:09:28.745Z"
|
|
6
6
|
}
|
|
@@ -62,9 +62,21 @@ function readSettingsPackages(settingsPath) {
|
|
|
62
62
|
return undefined;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Strip an `npm:` prefix and a trailing `@<version>`/`@<dist-tag>` suffix
|
|
67
|
+
* from a settings package spec, e.g. `npm:pi-lens@3.8.72` → `pi-lens`,
|
|
68
|
+
* `npm:@scope/pkg@1.0.0` → `@scope/pkg`. The leading `@` of a scoped
|
|
69
|
+
* package name is preserved (the version separator is the LAST `@` at a
|
|
70
|
+
* positive index). Mirrors the console-side spec parsing semantics so a
|
|
71
|
+
* version-pinned install (e.g. via `pi install npm:pi-lens@3.8.72`) resolves
|
|
72
|
+
* identically in both surfaces.
|
|
73
|
+
*/
|
|
66
74
|
export function packageNameFromSpec(spec) {
|
|
67
|
-
|
|
75
|
+
const base = spec.startsWith("npm:") ? spec.slice(4) : spec;
|
|
76
|
+
const at = base.lastIndexOf("@");
|
|
77
|
+
if (at > 0)
|
|
78
|
+
return base.slice(0, at);
|
|
79
|
+
return base;
|
|
68
80
|
}
|
|
69
81
|
function loadPackageInventories(repoRoot) {
|
|
70
82
|
const agentDir = getPiAgentDir();
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* `createDefaultPiSdkBindings()`.
|
|
27
27
|
*/
|
|
28
28
|
import { createHash, randomBytes } from "node:crypto";
|
|
29
|
-
import { access, stat } from "node:fs/promises";
|
|
29
|
+
import { access, mkdir, rm, stat, writeFile } from "node:fs/promises";
|
|
30
30
|
import path from "node:path";
|
|
31
31
|
import { extractAssistantContentBlocks, extractAssistantText, isAssistantSdkMessage, } from "./assistant-content.js";
|
|
32
32
|
import { parseProviderError, } from "./provider-error.js";
|
|
@@ -1305,6 +1305,15 @@ export class ConsolePiRuntime {
|
|
|
1305
1305
|
if (!sessionFile) {
|
|
1306
1306
|
throw new Error(`chat session shell missing sessionFile for ${sessionId}`);
|
|
1307
1307
|
}
|
|
1308
|
+
// Pi's SessionManager.create deliberately postpones writing a JSONL until
|
|
1309
|
+
// an assistant response. Materialize a valid header now, otherwise Console
|
|
1310
|
+
// could persist a path that disappears on a restart before first reply.
|
|
1311
|
+
await this.bindings.materializeSessionShell?.({
|
|
1312
|
+
sessionManager,
|
|
1313
|
+
sessionId,
|
|
1314
|
+
sessionFile,
|
|
1315
|
+
cwd: this.options.cwd,
|
|
1316
|
+
});
|
|
1308
1317
|
this.sessionManagers.set(sessionId, sessionManager);
|
|
1309
1318
|
this.thinkingSelections.set(sessionId, "auto");
|
|
1310
1319
|
// Detached single-flight materialization; dependent routes await the same promise.
|
|
@@ -2312,6 +2321,16 @@ export class ConsolePiRuntime {
|
|
|
2312
2321
|
});
|
|
2313
2322
|
}
|
|
2314
2323
|
catch (error) {
|
|
2324
|
+
const code = error && typeof error === "object" && "code" in error
|
|
2325
|
+
? String(error.code ?? "")
|
|
2326
|
+
: "";
|
|
2327
|
+
if (code === "SESSION_FILE_MISSING" || code === "ENOENT") {
|
|
2328
|
+
return {
|
|
2329
|
+
ok: false,
|
|
2330
|
+
code: "NO_SESSION_FILE",
|
|
2331
|
+
message: `Pi session file missing or not openable: ${init.sessionFile}`,
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2315
2334
|
return {
|
|
2316
2335
|
ok: false,
|
|
2317
2336
|
code: "REOPEN_FAILED",
|
|
@@ -3147,6 +3166,36 @@ export function createDefaultPiSdkBindings() {
|
|
|
3147
3166
|
id: opts.sessionId,
|
|
3148
3167
|
});
|
|
3149
3168
|
},
|
|
3169
|
+
materializeSessionShell: async (opts) => {
|
|
3170
|
+
const sdk = (await loadSdk());
|
|
3171
|
+
const manager = opts.sessionManager;
|
|
3172
|
+
if (typeof manager.setSessionFile !== "function") {
|
|
3173
|
+
throw new Error("Pi SessionManager cannot materialize a session file");
|
|
3174
|
+
}
|
|
3175
|
+
let created = false;
|
|
3176
|
+
try {
|
|
3177
|
+
await mkdir(path.dirname(opts.sessionFile), { recursive: true });
|
|
3178
|
+
// Match Pi's documented session header. Rebinding through the public
|
|
3179
|
+
// SessionManager API marks it flushed, so Pi appends the first user
|
|
3180
|
+
// entry instead of trying to create the already-present file later.
|
|
3181
|
+
await writeFile(opts.sessionFile, `${JSON.stringify({
|
|
3182
|
+
type: "session",
|
|
3183
|
+
version: typeof sdk.CURRENT_SESSION_VERSION === "number"
|
|
3184
|
+
? sdk.CURRENT_SESSION_VERSION
|
|
3185
|
+
: 3,
|
|
3186
|
+
id: opts.sessionId,
|
|
3187
|
+
timestamp: new Date().toISOString(),
|
|
3188
|
+
cwd: opts.cwd,
|
|
3189
|
+
})}\n`, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
3190
|
+
created = true;
|
|
3191
|
+
manager.setSessionFile(opts.sessionFile);
|
|
3192
|
+
}
|
|
3193
|
+
catch (error) {
|
|
3194
|
+
if (created)
|
|
3195
|
+
await rm(opts.sessionFile, { force: true }).catch(() => undefined);
|
|
3196
|
+
throw error;
|
|
3197
|
+
}
|
|
3198
|
+
},
|
|
3150
3199
|
createInMemorySessionManager: async (opts) => {
|
|
3151
3200
|
const sdk = (await loadSdk());
|
|
3152
3201
|
return sdk.SessionManager.inMemory(opts.cwd);
|
|
@@ -3163,13 +3212,19 @@ export function createDefaultPiSdkBindings() {
|
|
|
3163
3212
|
// wrong conversation under the durable Console sessionId. Fail closed
|
|
3164
3213
|
// before open when the persisted file is absent.
|
|
3165
3214
|
await access(opts.sessionFile);
|
|
3166
|
-
return sdk.SessionManager.open(opts.sessionFile);
|
|
3167
3215
|
}
|
|
3168
|
-
catch {
|
|
3169
|
-
|
|
3170
|
-
|
|
3216
|
+
catch (error) {
|
|
3217
|
+
const code = error && typeof error === "object" && "code" in error
|
|
3218
|
+
? String(error.code ?? "")
|
|
3219
|
+
: "";
|
|
3220
|
+
if (code === "ENOENT") {
|
|
3221
|
+
throw Object.assign(new Error(`SESSION_FILE_MISSING: ${opts.sessionFile}`), { code: "SESSION_FILE_MISSING", cause: error });
|
|
3222
|
+
}
|
|
3223
|
+
// File exists but is unreadable (permissions / I/O) — caller maps
|
|
3224
|
+
// undefined to 503 rather than silently creating a fresh session.
|
|
3171
3225
|
return undefined;
|
|
3172
3226
|
}
|
|
3227
|
+
return sdk.SessionManager.open(opts.sessionFile);
|
|
3173
3228
|
},
|
|
3174
3229
|
resolveModel: (opts) => {
|
|
3175
3230
|
const rt = opts.modelRuntime;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* Read routes (GET capabilities / sessions) are open to loopback.
|
|
14
14
|
*/
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
16
|
+
import { access } from "node:fs/promises";
|
|
16
17
|
import { parseAssistantContent } from "./assistant-content.js";
|
|
17
18
|
import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_DENIED_TOOLS, OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS, } from "./tools.js";
|
|
18
19
|
import { buildModelCallableToolSchemas } from "./tool-adapter.js";
|
|
@@ -468,7 +469,7 @@ function sendRuntimeUnavailable(res, error) {
|
|
|
468
469
|
* handled here — only reopen/init readiness failures.
|
|
469
470
|
*/
|
|
470
471
|
function mapReopenSessionFailure(reopen) {
|
|
471
|
-
if (reopen.code === "NO_SESSION_FILE") {
|
|
472
|
+
if (reopen.code === "NO_SESSION_FILE" || reopen.code === "SESSION_FILE_MISSING") {
|
|
472
473
|
return {
|
|
473
474
|
status: 404,
|
|
474
475
|
code: "PI_SESSION_NOT_FOUND",
|
|
@@ -488,6 +489,19 @@ function mapReopenSessionFailure(reopen) {
|
|
|
488
489
|
message: reopen.message,
|
|
489
490
|
};
|
|
490
491
|
}
|
|
492
|
+
/** Drop an orphan catalog record whose promised Pi JSONL is gone. */
|
|
493
|
+
async function healMissingSessionFile(deps, sessionId, reopen) {
|
|
494
|
+
if (reopen && reopen.code !== "NO_SESSION_FILE" && reopen.code !== "SESSION_FILE_MISSING") {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (typeof deps.store.remove !== "function")
|
|
498
|
+
return;
|
|
499
|
+
await deps.store.remove(sessionId).catch(() => undefined);
|
|
500
|
+
}
|
|
501
|
+
async function mapFailedReopen(deps, sessionId, reopen) {
|
|
502
|
+
await healMissingSessionFile(deps, sessionId, reopen);
|
|
503
|
+
return mapReopenSessionFailure(reopen);
|
|
504
|
+
}
|
|
491
505
|
export async function handleChatCapabilities(_req, res, deps) {
|
|
492
506
|
const toolSchemas = buildModelCallableToolSchemas();
|
|
493
507
|
sendJson(res, 200, {
|
|
@@ -731,10 +745,7 @@ export async function handleBranchChatSession(req, res, deps, sessionId) {
|
|
|
731
745
|
sessionFile: record.sessionFile,
|
|
732
746
|
});
|
|
733
747
|
if (!reopened.ok) {
|
|
734
|
-
const mapped =
|
|
735
|
-
code: reopened.code,
|
|
736
|
-
message: reopened.message,
|
|
737
|
-
});
|
|
748
|
+
const mapped = await mapFailedReopen(deps, sessionId, reopened);
|
|
738
749
|
sendJson(res, mapped.status, {
|
|
739
750
|
ok: false,
|
|
740
751
|
error: { code: mapped.code, message: mapped.message },
|
|
@@ -809,6 +820,29 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
809
820
|
});
|
|
810
821
|
return;
|
|
811
822
|
}
|
|
823
|
+
if (record.sessionFile) {
|
|
824
|
+
try {
|
|
825
|
+
await access(record.sessionFile);
|
|
826
|
+
}
|
|
827
|
+
catch (error) {
|
|
828
|
+
const code = error && typeof error === "object" && "code" in error
|
|
829
|
+
? String(error.code ?? "")
|
|
830
|
+
: "";
|
|
831
|
+
if (code === "ENOENT") {
|
|
832
|
+
await healMissingSessionFile(deps, sessionId, {
|
|
833
|
+
code: "NO_SESSION_FILE",
|
|
834
|
+
});
|
|
835
|
+
sendJson(res, 404, {
|
|
836
|
+
ok: false,
|
|
837
|
+
error: {
|
|
838
|
+
code: "PI_SESSION_NOT_FOUND",
|
|
839
|
+
message: `Pi session file missing or not openable: ${record.sessionFile}`,
|
|
840
|
+
},
|
|
841
|
+
});
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
812
846
|
await deps.operationLinker.recoverSession(sessionId);
|
|
813
847
|
const composerDraft = await new ComposerDraftStore(deps.appData).get(sessionId);
|
|
814
848
|
const snapshot = deps.events.snapshot(sessionId);
|
|
@@ -1486,10 +1520,7 @@ export async function handleReopenChatSession(req, res, deps, sessionId) {
|
|
|
1486
1520
|
: {}),
|
|
1487
1521
|
});
|
|
1488
1522
|
if (!result.ok) {
|
|
1489
|
-
const mapped =
|
|
1490
|
-
code: result.code,
|
|
1491
|
-
message: result.message,
|
|
1492
|
-
});
|
|
1523
|
+
const mapped = await mapFailedReopen(deps, sessionId, result);
|
|
1493
1524
|
sendJson(res, mapped.status, {
|
|
1494
1525
|
ok: false,
|
|
1495
1526
|
error: { code: mapped.code, message: mapped.message },
|
|
@@ -1575,10 +1606,7 @@ export async function handleChatPrompt(req, res, deps, sessionId) {
|
|
|
1575
1606
|
: {}),
|
|
1576
1607
|
});
|
|
1577
1608
|
if (!reopen.ok) {
|
|
1578
|
-
const mapped =
|
|
1579
|
-
code: reopen.code,
|
|
1580
|
-
message: reopen.message,
|
|
1581
|
-
});
|
|
1609
|
+
const mapped = await mapFailedReopen(deps, sessionId, reopen);
|
|
1582
1610
|
sendJson(res, mapped.status, {
|
|
1583
1611
|
ok: false,
|
|
1584
1612
|
error: { code: mapped.code, message: mapped.message },
|
|
@@ -1847,10 +1875,7 @@ export async function handleCreateChatTurn(req, res, deps, sessionId, trustedPay
|
|
|
1847
1875
|
: {}),
|
|
1848
1876
|
});
|
|
1849
1877
|
if (!reopen.ok) {
|
|
1850
|
-
const mapped =
|
|
1851
|
-
code: reopen.code,
|
|
1852
|
-
message: reopen.message,
|
|
1853
|
-
});
|
|
1878
|
+
const mapped = await mapFailedReopen(deps, sessionId, reopen);
|
|
1854
1879
|
sendJson(res, mapped.status, {
|
|
1855
1880
|
ok: false,
|
|
1856
1881
|
accepted: false,
|
|
@@ -2999,7 +3024,7 @@ export async function ensureActiveSession(deps, sessionId) {
|
|
|
2999
3024
|
: {}),
|
|
3000
3025
|
});
|
|
3001
3026
|
if (!reopened.ok) {
|
|
3002
|
-
return { ok: false, ...
|
|
3027
|
+
return { ok: false, ...(await mapFailedReopen(deps, sessionId, reopened)) };
|
|
3003
3028
|
}
|
|
3004
3029
|
return { ok: true };
|
|
3005
3030
|
}
|
|
@@ -3946,10 +3971,7 @@ export async function handleChatCompact(req, res, deps, sessionId) {
|
|
|
3946
3971
|
: {}),
|
|
3947
3972
|
});
|
|
3948
3973
|
if (!reopened.ok) {
|
|
3949
|
-
const mapped =
|
|
3950
|
-
code: reopened.code,
|
|
3951
|
-
message: reopened.message,
|
|
3952
|
-
});
|
|
3974
|
+
const mapped = await mapFailedReopen(deps, sessionId, reopened);
|
|
3953
3975
|
sendJson(res, mapped.status, {
|
|
3954
3976
|
ok: false,
|
|
3955
3977
|
error: { code: mapped.code, message: mapped.message },
|
|
@@ -38,6 +38,16 @@ export function cleanChatTitle(value) {
|
|
|
38
38
|
function recordPath(appData, sessionId) {
|
|
39
39
|
return path.join(appData.chats, `${sessionId}.json`);
|
|
40
40
|
}
|
|
41
|
+
/** True when `sessionFile` lives inside this store's dedicated Pi JSONL dir. */
|
|
42
|
+
export function isConsoleOwnedSessionFile(appData, sessionFile) {
|
|
43
|
+
const value = sessionFile?.trim();
|
|
44
|
+
if (!value)
|
|
45
|
+
return false;
|
|
46
|
+
const root = path.resolve(appData.chatSessions);
|
|
47
|
+
const target = path.resolve(value);
|
|
48
|
+
const relative = path.relative(root, target);
|
|
49
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
50
|
+
}
|
|
41
51
|
export class ChatSessionStore {
|
|
42
52
|
appData;
|
|
43
53
|
options;
|
|
@@ -237,8 +247,14 @@ export class ChatSessionStore {
|
|
|
237
247
|
const record = await this.get(sessionId);
|
|
238
248
|
if (!record)
|
|
239
249
|
return false;
|
|
250
|
+
const sessionFile = record.sessionFile;
|
|
240
251
|
await rm(recordPath(this.appData, sessionId), { force: true });
|
|
241
252
|
this.options.onRecordChange?.(sessionId, undefined);
|
|
253
|
+
// Record first, then best-effort JSONL unlink. Final consistency is
|
|
254
|
+
// "both gone" — a leftover JSONL is harmless, a leftover record is not.
|
|
255
|
+
if (isConsoleOwnedSessionFile(this.appData, sessionFile) && sessionFile) {
|
|
256
|
+
await rm(sessionFile, { force: true }).catch(() => undefined);
|
|
257
|
+
}
|
|
242
258
|
return true;
|
|
243
259
|
});
|
|
244
260
|
}
|
|
@@ -566,8 +566,26 @@ export async function createConsoleServer(options) {
|
|
|
566
566
|
const stored = await context.chatRouteDeps.store.get(sessionId);
|
|
567
567
|
if (stored)
|
|
568
568
|
owner = context;
|
|
569
|
+
else if (!catalogEntry) {
|
|
570
|
+
// Catalog and store both miss: the session was deleted, not
|
|
571
|
+
// retargeted. Do not scan other workspaces or leak existence.
|
|
572
|
+
sendJson(res, 404, {
|
|
573
|
+
ok: false,
|
|
574
|
+
error: {
|
|
575
|
+
code: "PI_SESSION_NOT_FOUND",
|
|
576
|
+
message: `chat session not found: ${sessionId}`,
|
|
577
|
+
},
|
|
578
|
+
});
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
569
581
|
else {
|
|
570
|
-
|
|
582
|
+
chatSessionCatalog.remove(sessionId);
|
|
583
|
+
await registry
|
|
584
|
+
.detachSession(ownerRecord.workspaceId, sessionId)
|
|
585
|
+
.catch(() => undefined);
|
|
586
|
+
// Catalog had the id, but this workspace store does not.
|
|
587
|
+
// Keep the conflict code so a mismatched selection cannot
|
|
588
|
+
// discover whether the session lives elsewhere.
|
|
571
589
|
sendJson(res, 403, {
|
|
572
590
|
ok: false,
|
|
573
591
|
error: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-
|
|
1
|
+
import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-CdiNyN0N.js";import{p as f}from"./chunk-JWPE2WC7-DiDVlVB1.js";import{_ as n,l as o}from"./mermaid.core-ChyQH_ut.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-BT_JRsOH.js";import"./index-DtPrwu7M.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-
|
|
1
|
+
import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-ChyQH_ut.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
|