@tea-agent/loop-agent 0.42.0-next.7 → 0.42.0-next.8

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/executors/shell-executor.js +3 -1
  4. package/dist/worker/console/chat/pi-runtime.js +20 -4
  5. package/dist/worker/console/chat/routes.js +44 -22
  6. package/dist/worker/console/chat/session-store.js +16 -0
  7. package/dist/worker/console/server.js +19 -1
  8. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-BQBHX31n.js → abnfDiagram-N423BO3Z-C6n9_m0P.js} +1 -1
  9. package/dist/worker/console/static/assets/{arc-MSJ199eR.js → arc-DQh-IfZ1.js} +1 -1
  10. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DiRq2qMX.js → architectureDiagram-T3A2C74G-54NnrwUC.js} +1 -1
  11. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-rlaxFOvi.js → blockDiagram-VBNYF7ZC-pivRALGK.js} +1 -1
  12. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BSpi9ump.js → c4Diagram-5PPSVZJV-BR7OV2NJ.js} +1 -1
  13. package/dist/worker/console/static/assets/channel-DsZxrgqe.js +1 -0
  14. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-BN8VNeh5.js → chunk-2GRJ4B5K-B1Aq6BcK.js} +1 -1
  15. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CDa1OVRA.js → chunk-2Q5K7J3B-CbdU0rjo.js} +1 -1
  16. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-zxMQ5b8E.js → chunk-5RXB4S5H-Dqi2GJeD.js} +1 -1
  17. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-XTqNlzH4.js → chunk-5VM5RSS4-BYn1Hu4R.js} +1 -1
  18. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DpZQfFTq.js → chunk-6Q2QTUOP-DRLjDL0k.js} +1 -1
  19. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-DPv743zu.js → chunk-GF5L2VYU-CY9Xx2jV.js} +1 -1
  20. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CFsCFoF4.js → chunk-JWPE2WC7-BNCZs7_z.js} +1 -1
  21. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CV__aJTt.js → chunk-KBJHAD2P-DZ8AStLL.js} +1 -1
  22. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-BshKlNir.js → chunk-RYQCIY6F-DsxjYrzz.js} +1 -1
  23. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-B-A3ErBP.js → chunk-XXDRQBXY-Ddx1KC1l.js} +1 -1
  24. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CuToPeGV.js +1 -0
  25. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CuToPeGV.js +1 -0
  26. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-25xj8928.js → cose-bilkent-JH36ORCC-W9TveCnK.js} +1 -1
  27. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DFmv38cl.js → cynefin-VYW2F7L2-l9j_ztZH.js} +1 -1
  28. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-hReuWDQP.js → cynefinDiagram-MW4NZA55-BMJMKi4G.js} +1 -1
  29. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-C9X3YPUI.js → dagre-VZM6K2ZE-Bb4mG9pH.js} +1 -1
  30. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CAVmqjg9.js → diagram-7IWD3JNH-BMgL_Qv0.js} +1 -1
  31. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-DYNlLsIm.js → diagram-B4RE2ZJO-Bvo2T4OQ.js} +1 -1
  32. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BP5mlbfb.js → diagram-LBJQPF4R-_5kWRN9c.js} +1 -1
  33. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-KWOHK5ZM.js → diagram-Q27KOJAE-DqdMrltM.js} +1 -1
  34. package/dist/worker/console/static/assets/{diagram-UB23O5K3-D25Ro5y-.js → diagram-UB23O5K3-CDDYsNkp.js} +1 -1
  35. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-kLaahtbh.js → ebnfDiagram-BXEA7PRR-c4nfnZUV.js} +1 -1
  36. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-1tgKuLez.js → erDiagram-JOGREHBK-DnkUcNMs.js} +1 -1
  37. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DARr-Cvn.js → flowDiagram-UKHOOZJN-Dz0KGLZE.js} +1 -1
  38. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BgwjBv_V.js → ganttDiagram-PKOTCBZU-Cj1t1uka.js} +1 -1
  39. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DneIlYSI.js → gitGraphDiagram-DS77QQ5N-tp2FrBHd.js} +1 -1
  40. package/dist/worker/console/static/assets/{index-Dkv0ezuE.js → index-D9Sc0f0y.js} +84 -84
  41. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DA7ATqY6.js → infoDiagram-6WML65LV-DQwJS8DH.js} +1 -1
  42. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DnOS-E1Z.js → ishikawaDiagram-WSZJBQD7-eimCQWD4.js} +1 -1
  43. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-C8JnwJ_s.js → journeyDiagram-NVQOT4AX-Dd9Gbwgv.js} +1 -1
  44. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Cw0_OjEC.js → kanban-definition-27J2QSJJ-Qve3cyft.js} +1 -1
  45. package/dist/worker/console/static/assets/{linear-mrxq3fyn.js → linear-UXKSe36Z.js} +1 -1
  46. package/dist/worker/console/static/assets/{mermaid.core-Bagus6zF.js → mermaid.core-CWhj4JXN.js} +5 -5
  47. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-Bf95bLuW.js → mindmap-definition-FAOFIHXS-yTcwf4SJ.js} +1 -1
  48. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BvtUW6w2.js → pegDiagram-VL7TDLO6-_7qToaZP.js} +1 -1
  49. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CbWtT-Ry.js → pieDiagram-7S7Q4E2Y-CXmrKmDm.js} +1 -1
  50. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-ctnxxIdD.js → quadrantDiagram-CIZ2JOQS-hMmrJyaS.js} +1 -1
  51. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BZ7Z3X0-.js → railroadDiagram-AXF67PYL-BXw8tCBe.js} +1 -1
  52. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BMX1xnIy.js → requirementDiagram-LRYGKXZP-BmjgnLZl.js} +1 -1
  53. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-MShOQznz.js → sankeyDiagram-W5VNT64P-Bj77SPpN.js} +1 -1
  54. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CTGOazaB.js → sequenceDiagram-SI44F4Z6-B2FDVysL.js} +1 -1
  55. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-zGbfM4nV.js → sizeCapture-X5ZJPWSS-UChNY9ZZ.js} +1 -1
  56. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Brf8Wwzr.js → stateDiagram-OKZ733FA-wbAEkbd7.js} +1 -1
  57. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-yPoT19ft.js +1 -0
  58. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CvNw3ZqF.js → swimlanes-SLNWSIFB-DCEkU8HR.js} +2 -2
  59. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-VWdarchG.js +8 -0
  60. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-z2LyZpDt.js → timeline-definition-Z64GVDOM-BGp7H06U.js} +1 -1
  61. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-Bc_coprH.js → vennDiagram-T6HMQDX7-DsCIQuWR.js} +1 -1
  62. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-M1NSmWq-.js → wardleyDiagram-T6FBY63Y-cRZLP4Xe.js} +1 -1
  63. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-Ct0rjGXW.js → xychartDiagram-ELKLHX3M-CP0xLR9Y.js} +1 -1
  64. package/dist/worker/console/static/index.html +1 -1
  65. package/dist/worker/console/static-src/operator-chat/runtime-snapshot-store.js +10 -0
  66. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +31 -2
  67. package/dist/worker/console/static-src/operator-chat/useComposer.js +8 -3
  68. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +29 -6
  69. package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +8 -2
  70. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +40 -9
  71. package/dist/workflows/dag/backend-test-scenario-param.js +126 -19
  72. package/dist/workflows/dag/backend-test-scenario-partitions.js +62 -1
  73. package/dist/workflows/dag/backend-test-writer-completeness.js +7 -3
  74. package/dist/workflows/dag/init-hybrid.js +23 -3
  75. package/package.json +1 -1
  76. package/dist/worker/console/static/assets/channel-BdTaMnYP.js +0 -1
  77. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cid7CSRK.js +0 -1
  78. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cid7CSRK.js +0 -1
  79. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CIkoculx.js +0 -1
  80. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-pJ-V5EdT.js +0 -8
package/CHANGELOG.md CHANGED
@@ -2,8 +2,25 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ - 修复 Operator Chat 打开已丢失会话时把孤儿 JSONL 升级成 503、以及删会话后残留 workspace 选择被误报为跨工作区冲突的问题:缺失会话文件现在自愈为 404 并清掉记录,前端恢复路径安静忘记该会话。
5
6
  - 修复前端 `--from-text` 任务缺少 source-fidelity ledger、DAG 生成后降级为 v1 并在 `frontend-contract-pi` 0ms 失败的问题:文本入口现在持久化可校验的 v2 绑定输入,init-hybrid 复用任务自有需求源;Console 默认模型与 Pi readiness 同时排除无凭据 provider,避免把不可执行模型误报为可用。
6
7
  - 常规回归 `npm test` 默认跳过约 6 分钟的 I/O-heavy 测试池(仍跑 fast + integration);完整三池改为 `npm run test:full` / `LOOP_AGENT_FULL_TEST=1`。本地 `ci.sh`、GitHub PR 与 release/next 发布门禁仍跑全量,不降低交付验证。
8
+ - 修复 backend-test 把 `pytest.param({"title": ""})` 整段 dict 当成 empty 观察、且 `example=` 空值导致 `target=body.title` 解析失败的问题:空 example 仍解析 field,dict 内空字符串按字段 MATCH。
9
+ - 修复 backend-test 把自动化映射多写的横切测试点当成 Markdown BLOCKED、挡住 N11 修 docstring 的问题:只拦 `### 测试点` 未恰好绑定一次。
10
+ - 修复 backend-test 把 pytest `_MISSING` 哨兵当成普通 Name、可选 `min; bound=0` UNDETERMINED 的问题:`_MISSING` 与 `_OMIT` 同为省略键。
11
+ - 修复 backend-test 把可选字段 `min; bound=0` 的 `_OMIT` 判成 UNDETERMINED 的问题:省略键视为空最小;`OMITTED` TP 视为 missing。
12
+ - 修复 backend-test 对 `http_client(operation, json_body=dict)` 观察不到 payload 的问题:http-like Name-call 的第一参是参数化 method 变量时仍计入 `json_body`。
13
+ - 修复 backend-test 把 Markdown `Payload Required Paths: false` 当成路径、GET filter 整 Case UNSAFE 的问题:`true`/`false` 与 `none` 一样不是 path。
14
+ - 修复 backend-test 把列表反引号里的 `场景意图: ... bound=0` 解析失败、并把 `max+1` 的数字 1 当成 minLength 的问题:围栏行可解析,`+/-` 后缀数字不进 prose 窗。
15
+ - 修复 backend-test 把 fixture `http("POST", path, json_body={"title": ...})` 当成无 payload、整 Case PAYLOAD_SHAPE_MISMATCH 的问题:首参为 HTTP method 的 Name-call 进入 observedPaths。eligibility 门禁不放宽。
16
+ - 修复 backend-test 把 `intent=min; bound=0` 当成缺 bound 并落到 `maxLength`、导致空 content MISMATCH 的问题:无 `minLength=` / TP LEN 时保留 0;`max; bound=0` 仍是哨兵。
17
+ - 修复 backend-test 把 evidence-only pytest stub(模块 docstring + Case-ID、无 `def test_`)当成截断脚本、N9 `incomplete-write-set` 的问题:闭合 stub 可通过 completeness,半截 `def (` 仍 fail-closed。
18
+ - 修复 backend-test 把 Markdown 机器行 `intent=max-1; bound=99` 当成契约 max、导致 `x*99` MISMATCH 的问题:`max-1`/`max+1`/`min-1` 优先 `maxLength=` 与文案三元组。eligibility 门禁不放宽。
19
+ - 修复 backend-test 把 pytest 多写、Markdown 没有的 `0:1` extra symbol 当成 Markdown Test Point binding 缺陷并 BLOCKED 的问题:这类条目进入 N11 删除多余函数,不再清空 pytest repair。
20
+ - 修复 backend-test N12 只读 effective collection 再次跑 scenario-param 确定性写回、在 `filesystem-only` 下 `write-guard` 失败的问题:N12 只复验,不再改 pytest。N10 仍可修一次。
21
+ - 修复 backend-test 把 `脚本:无` 的 evidence-only Case 当成缺 pytest 符号送进 N11 的问题:精确 1:0 元用例不再触发 `missing-pytest-symbol` repair,N11 不得发明业务函数。真缺符号的 1:0 仍可修。eligibility 门禁不放宽。
22
+ - 修复 backend-test 把 Scenario Partitions 数据行的 exact `TP-SP-...` 清单写成第 8 列、导致 N6 `MISSING_PARTITION` 的问题:仅当尾列全是该 Partition 的 slot ID 时确定性裁成 7 列并写回 run-owned plan。7 列契约与非 slot 多余列 fail-closed 不放宽。
23
+ - 修复 backend-test scenario 把 `intent=max-1` 当成 unknown、以及 Markdown 只写「100 个字符的最大 / 1999、2000、2001」时解析不到 bound 的问题:`max-1` 进入 closed set,长度清单三元组与「N 个字符的最大」可得到 MATCH。eligibility 门禁不放宽。
7
24
  - 修复 backend-test correspondence 把前面函数的 `pytest.param(..., id="TP-...")` 叠进后续 Case `parameterIds` 的问题:decorator 区域遇到上一 `def`/`class` 或非 decorator 续行即停,不再把整组打成 `TEST_POINT_BINDING_EXTRA`。eligibility 门禁不放宽。
8
25
  - 修复 backend-test scenario facts 把内部 max/min/oversize helper 哨兵 `-1/-2/-3` 写成 `observedLength`、导致 N10 在 schema `min(0)` 上 `invalid-output` 的问题:这些 helper 仍按 Markdown bound MATCH,持久化长度只保留非负值。
9
26
  - 修复 backend-test 把 GET `params=`/`query=` 过滤字段、Python `True`/`False` 布尔字面量和混合大小写 `pytest.param` 列表漏出 correspondence/payload/scenario 观察的问题:这些 variant 现在可以按 item 授权,而不再把整 Case 打成 `PAYLOAD_SHAPE_MISMATCH` / `VARIANT_PARAMETER_MISSING`。eligibility 门禁不放宽。
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.42.0-next.7",
4
- "gitSha": "dc38c285736865703929d788b0f1929513ebe24c",
5
- "builtAt": "2026-09-02T17:21:58.319Z"
3
+ "version": "0.42.0-next.8",
4
+ "gitSha": "1d1ada8ede350e5778d753c04ed72bacd778e43d",
5
+ "builtAt": "2026-09-02T23:47:25.236Z"
6
6
  }
@@ -58,6 +58,7 @@ import { readProjectGovernanceContext } from "../workflows/dag/project-governanc
58
58
  import { assertMavenPlanFresh, MavenPlanStaleError, } from "../verification/maven/index.js";
59
59
  async function runBackendScenarioParamPreflight(input) {
60
60
  const outputs = [];
61
+ const allowRepair = input.allowRepair !== false;
61
62
  const initial = await assessBackendScenarioParamConsistency({
62
63
  workspaceRoot: input.workspaceRoot,
63
64
  phase: "initial",
@@ -73,7 +74,7 @@ async function runBackendScenarioParamPreflight(input) {
73
74
  outputs.push(`scenarioParamInitial=${initialArtifacts.reportPath}`);
74
75
  let finalFacts;
75
76
  let finalMarkdown;
76
- if (initial.facts.repairEligible) {
77
+ if (allowRepair && initial.facts.repairEligible) {
77
78
  const repair = await applyDeterministicScenarioParamRepairs({
78
79
  workspaceRoot: input.workspaceRoot,
79
80
  facts: initial.facts,
@@ -979,6 +980,7 @@ async function executeBackendTestPipeline(input, meta) {
979
980
  workspaceRoot: input.cwd,
980
981
  runDir: meta.runDir,
981
982
  layout: backendLayout,
983
+ allowRepair: false,
982
984
  strictScenarioParamGate: Boolean((meta.spec.globalConstraints ?? []).some((item) => /strictScenarioParamGate\s*=\s*true/i.test(item))),
983
985
  });
984
986
  outputs.push(...scenario.outputs);
@@ -2347,6 +2347,16 @@ export class ConsolePiRuntime {
2347
2347
  });
2348
2348
  }
2349
2349
  catch (error) {
2350
+ const code = error && typeof error === "object" && "code" in error
2351
+ ? String(error.code ?? "")
2352
+ : "";
2353
+ if (code === "SESSION_FILE_MISSING" || code === "ENOENT") {
2354
+ return {
2355
+ ok: false,
2356
+ code: "NO_SESSION_FILE",
2357
+ message: `Pi session file missing or not openable: ${init.sessionFile}`,
2358
+ };
2359
+ }
2350
2360
  return {
2351
2361
  ok: false,
2352
2362
  code: "REOPEN_FAILED",
@@ -3228,13 +3238,19 @@ export function createDefaultPiSdkBindings() {
3228
3238
  // wrong conversation under the durable Console sessionId. Fail closed
3229
3239
  // before open when the persisted file is absent.
3230
3240
  await access(opts.sessionFile);
3231
- return sdk.SessionManager.open(opts.sessionFile);
3232
3241
  }
3233
- catch {
3234
- // Missing/corrupt session file — caller fails closed rather than
3235
- // silently creating a fresh session and losing prior context.
3242
+ catch (error) {
3243
+ const code = error && typeof error === "object" && "code" in error
3244
+ ? String(error.code ?? "")
3245
+ : "";
3246
+ if (code === "ENOENT") {
3247
+ throw Object.assign(new Error(`SESSION_FILE_MISSING: ${opts.sessionFile}`), { code: "SESSION_FILE_MISSING", cause: error });
3248
+ }
3249
+ // File exists but is unreadable (permissions / I/O) — caller maps
3250
+ // undefined to 503 rather than silently creating a fresh session.
3236
3251
  return undefined;
3237
3252
  }
3253
+ return sdk.SessionManager.open(opts.sessionFile);
3238
3254
  },
3239
3255
  resolveModel: (opts) => {
3240
3256
  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";
@@ -474,7 +475,7 @@ function sendRuntimeUnavailable(res, error) {
474
475
  * handled here — only reopen/init readiness failures.
475
476
  */
476
477
  function mapReopenSessionFailure(reopen) {
477
- if (reopen.code === "NO_SESSION_FILE") {
478
+ if (reopen.code === "NO_SESSION_FILE" || reopen.code === "SESSION_FILE_MISSING") {
478
479
  return {
479
480
  status: 404,
480
481
  code: "PI_SESSION_NOT_FOUND",
@@ -494,6 +495,19 @@ function mapReopenSessionFailure(reopen) {
494
495
  message: reopen.message,
495
496
  };
496
497
  }
498
+ /** Drop an orphan catalog record whose promised Pi JSONL is gone. */
499
+ async function healMissingSessionFile(deps, sessionId, reopen) {
500
+ if (reopen && reopen.code !== "NO_SESSION_FILE" && reopen.code !== "SESSION_FILE_MISSING") {
501
+ return;
502
+ }
503
+ if (typeof deps.store.remove !== "function")
504
+ return;
505
+ await deps.store.remove(sessionId).catch(() => undefined);
506
+ }
507
+ async function mapFailedReopen(deps, sessionId, reopen) {
508
+ await healMissingSessionFile(deps, sessionId, reopen);
509
+ return mapReopenSessionFailure(reopen);
510
+ }
497
511
  export async function handleChatCapabilities(_req, res, deps) {
498
512
  const toolSchemas = buildModelCallableToolSchemas();
499
513
  sendJson(res, 200, {
@@ -738,10 +752,7 @@ export async function handleBranchChatSession(req, res, deps, sessionId) {
738
752
  sessionFile: record.sessionFile,
739
753
  });
740
754
  if (!reopened.ok) {
741
- const mapped = mapReopenSessionFailure({
742
- code: reopened.code,
743
- message: reopened.message,
744
- });
755
+ const mapped = await mapFailedReopen(deps, sessionId, reopened);
745
756
  sendJson(res, mapped.status, {
746
757
  ok: false,
747
758
  error: { code: mapped.code, message: mapped.message },
@@ -816,6 +827,29 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
816
827
  });
817
828
  return;
818
829
  }
830
+ if (record.sessionFile) {
831
+ try {
832
+ await access(record.sessionFile);
833
+ }
834
+ catch (error) {
835
+ const code = error && typeof error === "object" && "code" in error
836
+ ? String(error.code ?? "")
837
+ : "";
838
+ if (code === "ENOENT") {
839
+ await healMissingSessionFile(deps, sessionId, {
840
+ code: "NO_SESSION_FILE",
841
+ });
842
+ sendJson(res, 404, {
843
+ ok: false,
844
+ error: {
845
+ code: "PI_SESSION_NOT_FOUND",
846
+ message: `Pi session file missing or not openable: ${record.sessionFile}`,
847
+ },
848
+ });
849
+ return;
850
+ }
851
+ }
852
+ }
819
853
  await deps.operationLinker.recoverSession(sessionId);
820
854
  const composerDraft = await new ComposerDraftStore(deps.appData).get(sessionId);
821
855
  const snapshot = deps.events.snapshot(sessionId);
@@ -1494,10 +1528,7 @@ export async function handleReopenChatSession(req, res, deps, sessionId) {
1494
1528
  : {}),
1495
1529
  });
1496
1530
  if (!result.ok) {
1497
- const mapped = mapReopenSessionFailure({
1498
- code: result.code,
1499
- message: result.message,
1500
- });
1531
+ const mapped = await mapFailedReopen(deps, sessionId, result);
1501
1532
  sendJson(res, mapped.status, {
1502
1533
  ok: false,
1503
1534
  error: { code: mapped.code, message: mapped.message },
@@ -1583,10 +1614,7 @@ export async function handleChatPrompt(req, res, deps, sessionId) {
1583
1614
  : {}),
1584
1615
  });
1585
1616
  if (!reopen.ok) {
1586
- const mapped = mapReopenSessionFailure({
1587
- code: reopen.code,
1588
- message: reopen.message,
1589
- });
1617
+ const mapped = await mapFailedReopen(deps, sessionId, reopen);
1590
1618
  sendJson(res, mapped.status, {
1591
1619
  ok: false,
1592
1620
  error: { code: mapped.code, message: mapped.message },
@@ -1855,10 +1883,7 @@ export async function handleCreateChatTurn(req, res, deps, sessionId, trustedPay
1855
1883
  : {}),
1856
1884
  });
1857
1885
  if (!reopen.ok) {
1858
- const mapped = mapReopenSessionFailure({
1859
- code: reopen.code,
1860
- message: reopen.message,
1861
- });
1886
+ const mapped = await mapFailedReopen(deps, sessionId, reopen);
1862
1887
  sendJson(res, mapped.status, {
1863
1888
  ok: false,
1864
1889
  accepted: false,
@@ -3050,7 +3075,7 @@ export async function ensureActiveSession(deps, sessionId) {
3050
3075
  : {}),
3051
3076
  });
3052
3077
  if (!reopened.ok) {
3053
- return { ok: false, ...mapReopenSessionFailure(reopened) };
3078
+ return { ok: false, ...(await mapFailedReopen(deps, sessionId, reopened)) };
3054
3079
  }
3055
3080
  return { ok: true };
3056
3081
  }
@@ -3997,10 +4022,7 @@ export async function handleChatCompact(req, res, deps, sessionId) {
3997
4022
  : {}),
3998
4023
  });
3999
4024
  if (!reopened.ok) {
4000
- const mapped = mapReopenSessionFailure({
4001
- code: reopened.code,
4002
- message: reopened.message,
4003
- });
4025
+ const mapped = await mapFailedReopen(deps, sessionId, reopened);
4004
4026
  sendJson(res, mapped.status, {
4005
4027
  ok: false,
4006
4028
  error: { code: mapped.code, message: mapped.message },
@@ -47,6 +47,16 @@ export function cleanChatTitle(value) {
47
47
  function recordPath(appData, sessionId) {
48
48
  return path.join(appData.chats, `${sessionId}.json`);
49
49
  }
50
+ /** True when `sessionFile` lives inside this store's dedicated Pi JSONL dir. */
51
+ export function isConsoleOwnedSessionFile(appData, sessionFile) {
52
+ const value = sessionFile?.trim();
53
+ if (!value)
54
+ return false;
55
+ const root = path.resolve(appData.chatSessions);
56
+ const target = path.resolve(value);
57
+ const relative = path.relative(root, target);
58
+ return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
59
+ }
50
60
  export class ChatSessionStore {
51
61
  appData;
52
62
  options;
@@ -263,8 +273,14 @@ export class ChatSessionStore {
263
273
  const record = await this.get(sessionId);
264
274
  if (!record)
265
275
  return false;
276
+ const sessionFile = record.sessionFile;
266
277
  await rm(recordPath(this.appData, sessionId), { force: true });
267
278
  this.options.onRecordChange?.(sessionId, undefined);
279
+ // Record first, then best-effort JSONL unlink. Final consistency is
280
+ // "both gone" — a leftover JSONL is harmless, a leftover record is not.
281
+ if (isConsoleOwnedSessionFile(this.appData, sessionFile) && sessionFile) {
282
+ await rm(sessionFile, { force: true }).catch(() => undefined);
283
+ }
268
284
  return true;
269
285
  });
270
286
  }
@@ -567,8 +567,26 @@ export async function createConsoleServer(options) {
567
567
  const stored = await context.chatRouteDeps.store.get(sessionId);
568
568
  if (stored)
569
569
  owner = context;
570
+ else if (!catalogEntry) {
571
+ // Catalog and store both miss: the session was deleted, not
572
+ // retargeted. Do not scan other workspaces or leak existence.
573
+ sendJson(res, 404, {
574
+ ok: false,
575
+ error: {
576
+ code: "PI_SESSION_NOT_FOUND",
577
+ message: `chat session not found: ${sessionId}`,
578
+ },
579
+ });
580
+ return;
581
+ }
570
582
  else {
571
- // Do not scan another workspace and disclose whether the id exists there.
583
+ chatSessionCatalog.remove(sessionId);
584
+ await registry
585
+ .detachSession(ownerRecord.workspaceId, sessionId)
586
+ .catch(() => undefined);
587
+ // Catalog had the id, but this workspace store does not.
588
+ // Keep the conflict code so a mismatched selection cannot
589
+ // discover whether the session lives elsewhere.
572
590
  sendJson(res, 403, {
573
591
  ok: false,
574
592
  error: {
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-DpZQfFTq.js";import{p as f}from"./chunk-JWPE2WC7-CFsCFoF4.js";import{_ as n,l as o}from"./mermaid.core-Bagus6zF.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DFmv38cl.js";import"./index-Dkv0ezuE.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
+ import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-DRLjDL0k.js";import{p as f}from"./chunk-JWPE2WC7-BNCZs7_z.js";import{_ as n,l as o}from"./mermaid.core-CWhj4JXN.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-l9j_ztZH.js";import"./index-D9Sc0f0y.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-Bagus6zF.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};
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-CWhj4JXN.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};