reasonix 0.45.1 → 0.46.1

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 (121) hide show
  1. package/README.md +3 -8
  2. package/README.zh-CN.md +3 -0
  3. package/dashboard/dist/app.js +76 -6
  4. package/dashboard/dist/app.js.map +1 -1
  5. package/dist/cli/{acp-LGBLHBKY.js → acp-LKJU5DZX.js} +19 -19
  6. package/dist/cli/chat-W7LAWEN6.js +51 -0
  7. package/dist/cli/{chunk-5I2C4JEO.js → chunk-2AASOSD5.js} +6 -6
  8. package/dist/cli/{chunk-5I2C4JEO.js.map → chunk-2AASOSD5.js.map} +1 -1
  9. package/dist/cli/{chunk-HVUZWNSP.js → chunk-3AAG2CUT.js} +2 -2
  10. package/dist/cli/{chunk-IJ7JA32V.js → chunk-6VANO7KB.js} +44 -8
  11. package/dist/cli/chunk-6VANO7KB.js.map +1 -0
  12. package/dist/cli/{chunk-LIR2HBQH.js → chunk-7LOJS3LV.js} +2 -2
  13. package/dist/cli/{chunk-AB2RED3C.js → chunk-7SGGXNB2.js} +16 -16
  14. package/dist/cli/{chunk-AB2RED3C.js.map → chunk-7SGGXNB2.js.map} +1 -1
  15. package/dist/cli/{chunk-CBIQWMS6.js → chunk-7YW6TPXK.js} +7 -7
  16. package/dist/cli/{chunk-A3TSSDS2.js → chunk-C72TNHDE.js} +2 -2
  17. package/dist/cli/{chunk-AVFXO2EZ.js → chunk-DGA5QYFM.js} +107 -4
  18. package/dist/cli/chunk-DGA5QYFM.js.map +1 -0
  19. package/dist/cli/{chunk-JNAQYELD.js → chunk-DHRVZJ2D.js} +2 -2
  20. package/dist/cli/{chunk-5ACMUK4Q.js → chunk-E7TAHQ4A.js} +2 -1
  21. package/dist/cli/{chunk-C53JQES5.js → chunk-EAOL43HB.js} +3 -3
  22. package/dist/cli/{chunk-QJDDIK3Z.js → chunk-IYQ325V7.js} +2 -2
  23. package/dist/cli/{chunk-4CTDEJUF.js → chunk-JLQDNLZF.js} +2 -2
  24. package/dist/cli/{chunk-RDRC3XDT.js → chunk-JVFEJAJX.js} +2 -2
  25. package/dist/cli/{chunk-GTZTQNX5.js → chunk-JVQT5IYP.js} +7 -7
  26. package/dist/cli/{chunk-IBJIK2DD.js → chunk-K3AIFMI6.js} +2 -2
  27. package/dist/cli/chunk-K3AIFMI6.js.map +1 -0
  28. package/dist/cli/{chunk-ZZYBBX5N.js → chunk-M4E5JK6S.js} +23 -9
  29. package/dist/cli/chunk-M4E5JK6S.js.map +1 -0
  30. package/dist/cli/{chunk-V26WPN3J.js → chunk-MIIZJD5O.js} +28 -1
  31. package/dist/cli/chunk-MIIZJD5O.js.map +1 -0
  32. package/dist/cli/{chunk-4HCP2UQW.js → chunk-NCBP5D6E.js} +2 -2
  33. package/dist/cli/{chunk-HKWSPKMU.js → chunk-R2ASNSEO.js} +8 -8
  34. package/dist/cli/{chunk-W7YGWUWU.js → chunk-SE7C5ZSI.js} +3 -3
  35. package/dist/cli/{chunk-OLLQ76U6.js → chunk-SPXN5JIT.js} +1536 -2500
  36. package/dist/cli/chunk-SPXN5JIT.js.map +1 -0
  37. package/dist/cli/{chunk-WK3UFQY3.js → chunk-TDSBASOF.js} +2 -2
  38. package/dist/cli/{chunk-XSU4QVFW.js → chunk-WQ6ZRDQM.js} +12 -3
  39. package/dist/cli/chunk-WQ6ZRDQM.js.map +1 -0
  40. package/dist/cli/{chunk-R3CTO2HM.js → chunk-WRONKNIH.js} +2 -2
  41. package/dist/cli/{chunk-MJ6W5UN3.js → chunk-XPAUNFOL.js} +2 -2
  42. package/dist/cli/{chunk-NVURFF27.js → chunk-YRLC2EDF.js} +2 -2
  43. package/dist/cli/{chunk-WL6SNQ5T.js → chunk-ZOQHVQON.js} +9 -93
  44. package/dist/cli/chunk-ZOQHVQON.js.map +1 -0
  45. package/dist/cli/{code-D7V2TQX2.js → code-2JIHL5M2.js} +30 -33
  46. package/dist/cli/code-2JIHL5M2.js.map +1 -0
  47. package/dist/cli/{commands-OCU42XG4.js → commands-OPT5AJNH.js} +4 -4
  48. package/dist/cli/{commit-XCQIQCYG.js → commit-KA37H6GM.js} +3 -3
  49. package/dist/cli/{desktop-ZCUG7LMF.js → desktop-5ONTRU3C.js} +20 -20
  50. package/dist/cli/{diff-66B2KWOJ.js → diff-SOIA7AKH.js} +8 -8
  51. package/dist/cli/{doctor-Y73CPPRZ.js → doctor-RCUP4XRV.js} +9 -9
  52. package/dist/cli/{events-NGZ2OJYH.js → events-6KHITNX4.js} +3 -3
  53. package/dist/cli/index.js +46 -102
  54. package/dist/cli/index.js.map +1 -1
  55. package/dist/cli/{mcp-MPVGBBJF.js → mcp-JP5OWD6R.js} +2 -2
  56. package/dist/cli/{mcp-browse-4XOTC3FJ.js → mcp-browse-ONCJJPJN.js} +2 -2
  57. package/dist/cli/{mcp-inspect-CEMGKKAH.js → mcp-inspect-TPLHW5JA.js} +4 -4
  58. package/dist/cli/{prompt-2D7ID24X.js → prompt-RJDNCQAP.js} +3 -3
  59. package/dist/cli/{prune-sessions-OJEYYLHY.js → prune-sessions-MKEATRVL.js} +2 -2
  60. package/dist/cli/{replay-HIQYWBEK.js → replay-4NILJG4U.js} +8 -8
  61. package/dist/cli/{run-5DPQFSP6.js → run-WFGXB4SB.js} +17 -18
  62. package/dist/cli/run-WFGXB4SB.js.map +1 -0
  63. package/dist/cli/{server-TQ2IHYQJ.js → server-5VFQP3PV.js} +13 -13
  64. package/dist/cli/{sessions-KY54NG45.js → sessions-5XDJDALO.js} +28 -14
  65. package/dist/cli/sessions-5XDJDALO.js.map +1 -0
  66. package/dist/cli/{setup-DDNOMMAB.js → setup-F6XSWLRA.js} +7 -7
  67. package/dist/cli/setup-F6XSWLRA.js.map +1 -0
  68. package/dist/cli/{stats-X2VTWKNS.js → stats-ALHBZICE.js} +6 -6
  69. package/dist/cli/{version-7O6A5T7Q.js → version-JVRAHBMM.js} +14 -14
  70. package/dist/index.d.ts +23 -13
  71. package/dist/index.js +1112 -1090
  72. package/dist/index.js.map +1 -1
  73. package/package.json +5 -16
  74. package/dist/cli/chat-I7UTQO5L.js +0 -51
  75. package/dist/cli/chunk-AVFXO2EZ.js.map +0 -1
  76. package/dist/cli/chunk-IBJIK2DD.js.map +0 -1
  77. package/dist/cli/chunk-IJ7JA32V.js.map +0 -1
  78. package/dist/cli/chunk-OLLQ76U6.js.map +0 -1
  79. package/dist/cli/chunk-V26WPN3J.js.map +0 -1
  80. package/dist/cli/chunk-WL6SNQ5T.js.map +0 -1
  81. package/dist/cli/chunk-XSU4QVFW.js.map +0 -1
  82. package/dist/cli/chunk-ZZYBBX5N.js.map +0 -1
  83. package/dist/cli/code-D7V2TQX2.js.map +0 -1
  84. package/dist/cli/run-5DPQFSP6.js.map +0 -1
  85. package/dist/cli/sessions-KY54NG45.js.map +0 -1
  86. package/dist/cli/setup-DDNOMMAB.js.map +0 -1
  87. /package/dist/cli/{acp-LGBLHBKY.js.map → acp-LKJU5DZX.js.map} +0 -0
  88. /package/dist/cli/{chat-I7UTQO5L.js.map → chat-W7LAWEN6.js.map} +0 -0
  89. /package/dist/cli/{chunk-HVUZWNSP.js.map → chunk-3AAG2CUT.js.map} +0 -0
  90. /package/dist/cli/{chunk-LIR2HBQH.js.map → chunk-7LOJS3LV.js.map} +0 -0
  91. /package/dist/cli/{chunk-CBIQWMS6.js.map → chunk-7YW6TPXK.js.map} +0 -0
  92. /package/dist/cli/{chunk-A3TSSDS2.js.map → chunk-C72TNHDE.js.map} +0 -0
  93. /package/dist/cli/{chunk-JNAQYELD.js.map → chunk-DHRVZJ2D.js.map} +0 -0
  94. /package/dist/cli/{chunk-5ACMUK4Q.js.map → chunk-E7TAHQ4A.js.map} +0 -0
  95. /package/dist/cli/{chunk-C53JQES5.js.map → chunk-EAOL43HB.js.map} +0 -0
  96. /package/dist/cli/{chunk-QJDDIK3Z.js.map → chunk-IYQ325V7.js.map} +0 -0
  97. /package/dist/cli/{chunk-4CTDEJUF.js.map → chunk-JLQDNLZF.js.map} +0 -0
  98. /package/dist/cli/{chunk-RDRC3XDT.js.map → chunk-JVFEJAJX.js.map} +0 -0
  99. /package/dist/cli/{chunk-GTZTQNX5.js.map → chunk-JVQT5IYP.js.map} +0 -0
  100. /package/dist/cli/{chunk-4HCP2UQW.js.map → chunk-NCBP5D6E.js.map} +0 -0
  101. /package/dist/cli/{chunk-HKWSPKMU.js.map → chunk-R2ASNSEO.js.map} +0 -0
  102. /package/dist/cli/{chunk-W7YGWUWU.js.map → chunk-SE7C5ZSI.js.map} +0 -0
  103. /package/dist/cli/{chunk-WK3UFQY3.js.map → chunk-TDSBASOF.js.map} +0 -0
  104. /package/dist/cli/{chunk-R3CTO2HM.js.map → chunk-WRONKNIH.js.map} +0 -0
  105. /package/dist/cli/{chunk-MJ6W5UN3.js.map → chunk-XPAUNFOL.js.map} +0 -0
  106. /package/dist/cli/{chunk-NVURFF27.js.map → chunk-YRLC2EDF.js.map} +0 -0
  107. /package/dist/cli/{commands-OCU42XG4.js.map → commands-OPT5AJNH.js.map} +0 -0
  108. /package/dist/cli/{commit-XCQIQCYG.js.map → commit-KA37H6GM.js.map} +0 -0
  109. /package/dist/cli/{desktop-ZCUG7LMF.js.map → desktop-5ONTRU3C.js.map} +0 -0
  110. /package/dist/cli/{diff-66B2KWOJ.js.map → diff-SOIA7AKH.js.map} +0 -0
  111. /package/dist/cli/{doctor-Y73CPPRZ.js.map → doctor-RCUP4XRV.js.map} +0 -0
  112. /package/dist/cli/{events-NGZ2OJYH.js.map → events-6KHITNX4.js.map} +0 -0
  113. /package/dist/cli/{mcp-MPVGBBJF.js.map → mcp-JP5OWD6R.js.map} +0 -0
  114. /package/dist/cli/{mcp-browse-4XOTC3FJ.js.map → mcp-browse-ONCJJPJN.js.map} +0 -0
  115. /package/dist/cli/{mcp-inspect-CEMGKKAH.js.map → mcp-inspect-TPLHW5JA.js.map} +0 -0
  116. /package/dist/cli/{prompt-2D7ID24X.js.map → prompt-RJDNCQAP.js.map} +0 -0
  117. /package/dist/cli/{prune-sessions-OJEYYLHY.js.map → prune-sessions-MKEATRVL.js.map} +0 -0
  118. /package/dist/cli/{replay-HIQYWBEK.js.map → replay-4NILJG4U.js.map} +0 -0
  119. /package/dist/cli/{server-TQ2IHYQJ.js.map → server-5VFQP3PV.js.map} +0 -0
  120. /package/dist/cli/{stats-X2VTWKNS.js.map → stats-ALHBZICE.js.map} +0 -0
  121. /package/dist/cli/{version-7O6A5T7Q.js.map → version-JVRAHBMM.js.map} +0 -0
@@ -2,7 +2,7 @@
2
2
  import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
3
  import {
4
4
  buildCodeToolset
5
- } from "./chunk-CBIQWMS6.js";
5
+ } from "./chunk-7YW6TPXK.js";
6
6
  import {
7
7
  Eventizer,
8
8
  autoResolveVerdict
@@ -10,28 +10,28 @@ import {
10
10
  import {
11
11
  formatMcpLifecycleEvent,
12
12
  formatMcpSlowToast
13
- } from "./chunk-4HCP2UQW.js";
13
+ } from "./chunk-NCBP5D6E.js";
14
14
  import {
15
15
  buildTransportFromSpec,
16
16
  preflightStdioSpec
17
- } from "./chunk-NVURFF27.js";
17
+ } from "./chunk-YRLC2EDF.js";
18
18
  import {
19
19
  CacheFirstLoop,
20
20
  ImmutablePrefix,
21
21
  bridgeMcpTools
22
- } from "./chunk-WL6SNQ5T.js";
23
- import "./chunk-WK3UFQY3.js";
22
+ } from "./chunk-ZOQHVQON.js";
23
+ import "./chunk-TDSBASOF.js";
24
24
  import {
25
25
  openTranscriptFile,
26
26
  recordFromLoopEvent,
27
27
  writeRecord
28
- } from "./chunk-C53JQES5.js";
28
+ } from "./chunk-EAOL43HB.js";
29
29
  import {
30
30
  McpClient
31
- } from "./chunk-XSU4QVFW.js";
31
+ } from "./chunk-WQ6ZRDQM.js";
32
32
  import {
33
33
  codeSystemPrompt
34
- } from "./chunk-JNAQYELD.js";
34
+ } from "./chunk-DHRVZJ2D.js";
35
35
  import {
36
36
  canonicalPresetName,
37
37
  resolvePreset
@@ -39,28 +39,28 @@ import {
39
39
  import "./chunk-6OWJV3YW.js";
40
40
  import {
41
41
  DeepSeekClient
42
- } from "./chunk-V26WPN3J.js";
42
+ } from "./chunk-MIIZJD5O.js";
43
43
  import "./chunk-25T6CVUP.js";
44
44
  import {
45
45
  loadDotenv
46
46
  } from "./chunk-2UQP6H6T.js";
47
- import "./chunk-MJ6W5UN3.js";
47
+ import "./chunk-XPAUNFOL.js";
48
48
  import {
49
49
  pauseGate
50
- } from "./chunk-RDRC3XDT.js";
50
+ } from "./chunk-JVFEJAJX.js";
51
51
  import "./chunk-TEUDEGX2.js";
52
52
  import "./chunk-PLHAZOLZ.js";
53
- import "./chunk-4CTDEJUF.js";
54
- import "./chunk-A3TSSDS2.js";
53
+ import "./chunk-JLQDNLZF.js";
54
+ import "./chunk-C72TNHDE.js";
55
55
  import "./chunk-S4XVGLRW.js";
56
56
  import {
57
57
  timestampSuffix
58
- } from "./chunk-5ACMUK4Q.js";
59
- import "./chunk-R3CTO2HM.js";
60
- import "./chunk-ZZYBBX5N.js";
58
+ } from "./chunk-E7TAHQ4A.js";
59
+ import "./chunk-WRONKNIH.js";
60
+ import "./chunk-M4E5JK6S.js";
61
61
  import {
62
62
  t
63
- } from "./chunk-IJ7JA32V.js";
63
+ } from "./chunk-6VANO7KB.js";
64
64
  import {
65
65
  loadApiKey,
66
66
  loadBaseUrl,
@@ -69,7 +69,7 @@ import {
69
69
  loadReasoningEffort,
70
70
  normalizeMcpConfig,
71
71
  readConfig
72
- } from "./chunk-AVFXO2EZ.js";
72
+ } from "./chunk-DGA5QYFM.js";
73
73
  import {
74
74
  VERSION
75
75
  } from "./chunk-XXC2BYTV.js";
@@ -708,4 +708,4 @@ export {
708
708
  acpCommand,
709
709
  loadMcpServers
710
710
  };
711
- //# sourceMappingURL=acp-LGBLHBKY.js.map
711
+ //# sourceMappingURL=acp-LKJU5DZX.js.map
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
+ import {
4
+ chatCommand
5
+ } from "./chunk-SPXN5JIT.js";
6
+ import "./chunk-CXVWUPA3.js";
7
+ import "./chunk-JMBMLOBP.js";
8
+ import "./chunk-JVQT5IYP.js";
9
+ import "./chunk-HNXDZGC6.js";
10
+ import "./chunk-NCBP5D6E.js";
11
+ import "./chunk-YRLC2EDF.js";
12
+ import "./chunk-ZZM6QJ4W.js";
13
+ import "./chunk-ZOQHVQON.js";
14
+ import "./chunk-TDSBASOF.js";
15
+ import "./chunk-EAOL43HB.js";
16
+ import "./chunk-WQ6ZRDQM.js";
17
+ import "./chunk-DHRVZJ2D.js";
18
+ import "./chunk-FEZK652I.js";
19
+ import "./chunk-K3AIFMI6.js";
20
+ import "./chunk-7SGGXNB2.js";
21
+ import "./chunk-X53B3JIX.js";
22
+ import "./chunk-2425HK6U.js";
23
+ import "./chunk-R2ASNSEO.js";
24
+ import "./chunk-5QCB62C4.js";
25
+ import "./chunk-6OWJV3YW.js";
26
+ import "./chunk-MIIZJD5O.js";
27
+ import "./chunk-25T6CVUP.js";
28
+ import "./chunk-2UQP6H6T.js";
29
+ import "./chunk-SE7C5ZSI.js";
30
+ import "./chunk-SZ5XES2N.js";
31
+ import "./chunk-2AASOSD5.js";
32
+ import "./chunk-IYQ325V7.js";
33
+ import "./chunk-XJXDHAES.js";
34
+ import "./chunk-JVFEJAJX.js";
35
+ import "./chunk-TEUDEGX2.js";
36
+ import "./chunk-PLHAZOLZ.js";
37
+ import "./chunk-7LOJS3LV.js";
38
+ import "./chunk-JLQDNLZF.js";
39
+ import "./chunk-C72TNHDE.js";
40
+ import "./chunk-S4XVGLRW.js";
41
+ import "./chunk-E7TAHQ4A.js";
42
+ import "./chunk-WRONKNIH.js";
43
+ import "./chunk-M4E5JK6S.js";
44
+ import "./chunk-6VANO7KB.js";
45
+ import "./chunk-DGA5QYFM.js";
46
+ import "./chunk-XXC2BYTV.js";
47
+ import "./chunk-TUK7OWJA.js";
48
+ export {
49
+ chatCommand
50
+ };
51
+ //# sourceMappingURL=chat-W7LAWEN6.js.map
@@ -3,7 +3,7 @@ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.requi
3
3
  import {
4
4
  sanitizeName,
5
5
  sessionsDir
6
- } from "./chunk-5ACMUK4Q.js";
6
+ } from "./chunk-E7TAHQ4A.js";
7
7
 
8
8
  // src/code/checkpoints.ts
9
9
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
@@ -637,7 +637,7 @@ var SLASH_COMMANDS = [
637
637
  {
638
638
  cmd: "cwd",
639
639
  group: "code",
640
- argsHint: "<path>",
640
+ argsHint: "[path]",
641
641
  summary: "switch the workspace root mid-session \u2014 re-points fs / shell / memory tools, reloads project hooks, refreshes the at-mention walker",
642
642
  contextual: "code",
643
643
  aliases: ["sandbox"],
@@ -680,9 +680,9 @@ var SLASH_COMMANDS = [
680
680
  {
681
681
  cmd: "search-engine",
682
682
  group: "advanced",
683
- argsHint: "<mojeek|searxng> [<endpoint>]",
684
- summary: "switch web search backend \u2014 mojeek (default, no deps) or searxng (self-hosted)",
685
- argCompleter: ["mojeek", "searxng"],
683
+ argsHint: "<mojeek|searxng|metaso> [<endpoint>]",
684
+ summary: "switch web search backend \u2014 mojeek (default, no deps), searxng (self-hosted), or metaso (free quota 100/d)",
685
+ argCompleter: ["mojeek", "searxng", "metaso"],
686
686
  aliases: ["se"]
687
687
  },
688
688
  {
@@ -815,4 +815,4 @@ export {
815
815
  detectSlashArgContext,
816
816
  parseSlash
817
817
  };
818
- //# sourceMappingURL=chunk-5I2C4JEO.js.map
818
+ //# sourceMappingURL=chunk-2AASOSD5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/code/checkpoints.ts","../../src/code/plan-store.ts","../../src/cli/ui/slash/commands.ts"],"sourcesContent":["/** One file per checkpoint (not jsonl) so delete/restore is cheap and a corrupt snapshot only loses itself. */\n\nimport { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\n\n/** One file's state at the time of snapshot. `content === null` → didn't exist. */\nexport interface CheckpointFile {\n path: string;\n content: string | null;\n}\n\nexport interface Checkpoint {\n id: string;\n /** User-given name, or `auto-<reason>` for system-created snapshots. */\n name: string;\n /** Absolute workspace root the snapshot belongs to. */\n rootDir: string;\n createdAt: number;\n source: \"manual\" | \"auto-session-start\" | \"auto-pre-restore\";\n files: CheckpointFile[];\n /** Total bytes of file content captured (sum of `content?.length`). */\n bytes: number;\n}\n\nexport interface CheckpointMeta {\n id: string;\n name: string;\n createdAt: number;\n source: Checkpoint[\"source\"];\n fileCount: number;\n bytes: number;\n}\n\n/** Sanitize a directory path into a safe filesystem name for the store. */\nfunction sanitizeRoot(rootDir: string): string {\n return resolve(rootDir)\n .replace(/[\\\\/:]+/g, \"_\")\n .replace(/^_+/, \"\");\n}\n\nfunction storeRoot(rootDir: string): string {\n return join(homedir(), \".reasonix\", \"sessions\", sanitizeRoot(rootDir), \"checkpoints\");\n}\n\nfunction indexPath(rootDir: string): string {\n return join(storeRoot(rootDir), \"index.json\");\n}\n\nfunction snapshotPath(rootDir: string, id: string): string {\n return join(storeRoot(rootDir), `${id}.json`);\n}\n\n/** Load the index of checkpoint metadata for a workspace. Empty when missing. */\nexport function listCheckpoints(rootDir: string): CheckpointMeta[] {\n const path = indexPath(rootDir);\n if (!existsSync(path)) return [];\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n // Defensive: filter out malformed entries rather than throwing on\n // a single bad row. A stale entry is annoying; a thrown listCheckpoints\n // would break /checkpoint list entirely.\n return parsed.filter(\n (m): m is CheckpointMeta =>\n typeof m === \"object\" &&\n m !== null &&\n typeof m.id === \"string\" &&\n typeof m.name === \"string\" &&\n typeof m.createdAt === \"number\" &&\n typeof m.source === \"string\" &&\n typeof m.fileCount === \"number\" &&\n typeof m.bytes === \"number\",\n );\n } catch {\n return [];\n }\n}\n\nfunction writeIndex(rootDir: string, items: CheckpointMeta[]): void {\n const path = indexPath(rootDir);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(items, null, 2), \"utf8\");\n}\n\n/** Read a single checkpoint by id. Returns null when missing or corrupt. */\nexport function loadCheckpoint(rootDir: string, id: string): Checkpoint | null {\n const path = snapshotPath(rootDir, id);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && Array.isArray(parsed.files)) {\n return parsed as Checkpoint;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport interface CreateCheckpointOptions {\n rootDir: string;\n name: string;\n source?: Checkpoint[\"source\"];\n paths: readonly string[];\n}\n\n/** Missing files recorded as `content: null` so restore knows to delete; ID has random suffix to avoid same-ms collision. */\nexport function createCheckpoint(opts: CreateCheckpointOptions): CheckpointMeta {\n const absRoot = resolve(opts.rootDir);\n const id = `cp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n const files: CheckpointFile[] = [];\n let bytes = 0;\n const seen = new Set<string>();\n for (const p of opts.paths) {\n if (seen.has(p)) continue;\n seen.add(p);\n const abs = resolve(absRoot, p);\n // Path-escape guard. A snapshot of `../../../etc/passwd` is not\n // something we want — refuse silently rather than abort the whole\n // checkpoint.\n if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep}`)) continue;\n const rel = relative(absRoot, abs).split(sep).join(\"/\");\n if (existsSync(abs)) {\n try {\n const content = readFileSync(abs, \"utf8\");\n files.push({ path: rel, content });\n bytes += content.length;\n } catch {\n // Unreadable (binary, perms) — record as null so restore knows\n // to delete on revert. Wrong for binary files but consistent.\n files.push({ path: rel, content: null });\n }\n } else {\n files.push({ path: rel, content: null });\n }\n }\n\n const checkpoint: Checkpoint = {\n id,\n name: opts.name,\n rootDir: absRoot,\n createdAt: Date.now(),\n source: opts.source ?? \"manual\",\n files,\n bytes,\n };\n const cpPath = snapshotPath(absRoot, id);\n mkdirSync(dirname(cpPath), { recursive: true });\n writeFileSync(cpPath, JSON.stringify(checkpoint), \"utf8\");\n\n const meta: CheckpointMeta = {\n id,\n name: opts.name,\n createdAt: checkpoint.createdAt,\n source: checkpoint.source,\n fileCount: files.length,\n bytes,\n };\n const items = listCheckpoints(absRoot);\n items.push(meta);\n writeIndex(absRoot, items);\n return meta;\n}\n\n/** Most-recent name wins on collision. */\nexport function findCheckpoint(rootDir: string, idOrName: string): CheckpointMeta | null {\n const items = listCheckpoints(rootDir);\n // Prefer exact id match, then most-recent name match.\n const byId = items.find((m) => m.id === idOrName);\n if (byId) return byId;\n const byName = [...items].reverse().find((m) => m.name === idOrName);\n return byName ?? null;\n}\n\nexport interface RestoreResult {\n /** Files we wrote back to disk. */\n restored: string[];\n /** Files we removed (snapshot had `content: null`, file existed). */\n removed: string[];\n /** Files we couldn't touch (errors), with the reason. */\n skipped: Array<{ path: string; reason: string }>;\n}\n\n/** Path-escape rechecked against live `rootDir` since snapshot's may differ (project moved). */\nexport function restoreCheckpoint(rootDir: string, id: string): RestoreResult {\n const cp = loadCheckpoint(rootDir, id);\n const absRoot = resolve(rootDir);\n const result: RestoreResult = { restored: [], removed: [], skipped: [] };\n if (!cp) {\n result.skipped.push({ path: \"(checkpoint)\", reason: `not found: ${id}` });\n return result;\n }\n for (const f of cp.files) {\n const abs = resolve(absRoot, f.path);\n if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep}`)) {\n result.skipped.push({ path: f.path, reason: \"path escapes rootDir\" });\n continue;\n }\n try {\n if (f.content === null) {\n if (existsSync(abs)) {\n rmSync(abs);\n result.removed.push(f.path);\n }\n } else {\n mkdirSync(dirname(abs), { recursive: true });\n writeFileSync(abs, f.content, \"utf8\");\n result.restored.push(f.path);\n }\n } catch (err) {\n result.skipped.push({ path: f.path, reason: (err as Error).message });\n }\n }\n return result;\n}\n\nexport function deleteCheckpoint(rootDir: string, id: string): boolean {\n const cpPath = snapshotPath(rootDir, id);\n let removed = false;\n if (existsSync(cpPath)) {\n try {\n rmSync(cpPath);\n removed = true;\n } catch {\n return false;\n }\n }\n const items = listCheckpoints(rootDir);\n const next = items.filter((m) => m.id !== id);\n if (next.length !== items.length) {\n writeIndex(rootDir, next);\n removed = true;\n }\n return removed;\n}\n\n/** Format ms-timestamp diff as human-readable relative age. */\nexport function fmtAgo(ms: number): string {\n const now = Date.now();\n const diff = Math.max(0, now - ms);\n const s = Math.floor(diff / 1000);\n if (s < 60) return `${s}s ago`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${h}h ago`;\n const d = Math.floor(h / 24);\n return `${d}d ago`;\n}\n","/** Persists structured plan state alongside the JSONL log; markdown body lives in the log (it was a tool result) and replays on resume. */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { sanitizeName, sessionsDir } from \"../memory/session.js\";\nimport type { PlanStep } from \"../tools/plan.js\";\n\nexport interface PlanStateOnDisk {\n /** File format version — bump when shape changes. */\n version: 1;\n steps: PlanStep[];\n completedStepIds: string[];\n /** ISO8601 timestamp of the last write. */\n updatedAt: string;\n body?: string;\n summary?: string;\n}\n\nexport function planStatePath(sessionName: string): string {\n return join(sessionsDir(), `${sanitizeName(sessionName)}.plan.json`);\n}\n\nexport function loadPlanState(sessionName: string): PlanStateOnDisk | null {\n const path = planStatePath(sessionName);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (!parsed || typeof parsed !== \"object\") return null;\n if (parsed.version !== 1) return null;\n if (!Array.isArray(parsed.steps)) return null;\n if (!Array.isArray(parsed.completedStepIds)) return null;\n if (typeof parsed.updatedAt !== \"string\") return null;\n // Defensive: filter out any malformed step entries so a partially\n // corrupted file still yields a usable subset.\n const steps: PlanStep[] = [];\n for (const s of parsed.steps) {\n if (!s || typeof s !== \"object\") continue;\n const e = s as unknown as Record<string, unknown>;\n if (typeof e.id !== \"string\" || !e.id) continue;\n if (typeof e.title !== \"string\" || !e.title) continue;\n if (typeof e.action !== \"string\" || !e.action) continue;\n const step: PlanStep = { id: e.id, title: e.title, action: e.action };\n if (e.risk === \"low\" || e.risk === \"med\" || e.risk === \"high\") step.risk = e.risk;\n steps.push(step);\n }\n if (steps.length === 0) return null;\n const completedStepIds = parsed.completedStepIds.filter(\n (id): id is string => typeof id === \"string\" && id.length > 0,\n );\n const out: PlanStateOnDisk = {\n version: 1,\n steps,\n completedStepIds,\n updatedAt: parsed.updatedAt,\n };\n if (typeof parsed.body === \"string\" && parsed.body) out.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) out.summary = parsed.summary;\n return out;\n } catch {\n return null;\n }\n}\n\n/** Best-effort: write failure logs to stderr instead of crashing the TUI. */\nexport function savePlanState(\n sessionName: string,\n steps: PlanStep[],\n completedStepIds: Iterable<string>,\n extras?: { body?: string; summary?: string },\n): void {\n const path = planStatePath(sessionName);\n try {\n mkdirSync(dirname(path), { recursive: true });\n const state: PlanStateOnDisk = {\n version: 1,\n steps,\n completedStepIds: [...completedStepIds],\n updatedAt: new Date().toISOString(),\n };\n if (extras?.body) state.body = extras.body;\n if (extras?.summary) state.summary = extras.summary;\n writeFileSync(path, `${JSON.stringify(state, null, 2)}\\n`, \"utf8\");\n } catch (err) {\n process.stderr.write(\n `▸ plan-store: failed to save plan for \"${sessionName}\": ${(err as Error).message}\\n`,\n );\n }\n}\n\n/** Remove the persisted plan, if any. Used on cancel / clean reset. */\nexport function clearPlanState(sessionName: string): void {\n const path = planStatePath(sessionName);\n try {\n if (existsSync(path)) unlinkSync(path);\n } catch {\n /* nothing to do — leftover file is harmless, will be overwritten next save */\n }\n}\n\n/** Random suffix avoids same-millisecond collision; `:`/`.` swapped for Windows-safe filenames. */\nexport function archivePlanState(sessionName: string): string | null {\n const active = planStatePath(sessionName);\n if (!existsSync(active)) return null;\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const suffix = Math.random().toString(36).slice(2, 6);\n const archive = join(\n sessionsDir(),\n `${sanitizeName(sessionName)}.plan.${stamp}-${suffix}.done.json`,\n );\n try {\n renameSync(active, archive);\n return archive;\n } catch (err) {\n process.stderr.write(\n `▸ plan-store: failed to archive plan for \"${sessionName}\": ${(err as Error).message}\\n`,\n );\n return null;\n }\n}\n\nexport interface PlanArchiveSummary {\n path: string;\n completedAt: string;\n steps: PlanStep[];\n completedStepIds: string[];\n /** Markdown body, when the archive carried it. */\n body?: string;\n /** One-line human-friendly title, when supplied. */\n summary?: string;\n}\n\nexport function listPlanArchives(sessionName: string): PlanArchiveSummary[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n const prefix = `${sanitizeName(sessionName)}.plan.`;\n const suffix = \".done.json\";\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n const summaries: PlanArchiveSummary[] = [];\n for (const name of entries) {\n if (!name.startsWith(prefix) || !name.endsWith(suffix)) continue;\n const full = join(dir, name);\n try {\n const raw = readFileSync(full, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (parsed.version !== 1) continue;\n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) continue;\n const steps = parsed.steps.filter(\n (s): s is PlanStep =>\n !!s &&\n typeof s === \"object\" &&\n typeof (s as PlanStep).id === \"string\" &&\n typeof (s as PlanStep).title === \"string\" &&\n typeof (s as PlanStep).action === \"string\",\n );\n if (steps.length === 0) continue;\n const completedStepIds = Array.isArray(parsed.completedStepIds)\n ? parsed.completedStepIds.filter((id): id is string => typeof id === \"string\" && !!id)\n : [];\n // Prefer the file's own updatedAt; fall back to mtime if missing\n // or unparseable so a hand-edited archive still sorts sensibly.\n let completedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : \"\";\n if (!completedAt || Number.isNaN(Date.parse(completedAt))) {\n try {\n completedAt = statSync(full).mtime.toISOString();\n } catch {\n completedAt = new Date(0).toISOString();\n }\n }\n const entry: PlanArchiveSummary = { path: full, completedAt, steps, completedStepIds };\n if (typeof parsed.body === \"string\" && parsed.body) entry.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) entry.summary = parsed.summary;\n summaries.push(entry);\n } catch {\n // Skip the corrupt archive entirely.\n }\n }\n summaries.sort((a, b) => b.completedAt.localeCompare(a.completedAt));\n return summaries;\n}\n\nexport interface PlanArchiveWithSession extends PlanArchiveSummary {\n sessionName: string;\n}\n\n/** Cross-session enumeration in a single dir scan — used by the dashboard plans panel where the per-session loop was O(N×M) and timed out for users with hundreds of sessions. */\nexport function listAllPlanArchives(): PlanArchiveWithSession[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n const out: PlanArchiveWithSession[] = [];\n const suffix = \".done.json\";\n const planMarker = \".plan.\";\n for (const name of entries) {\n if (!name.endsWith(suffix)) continue;\n const planIdx = name.indexOf(planMarker);\n if (planIdx < 0) continue;\n const sessionName = name.slice(0, planIdx);\n if (!sessionName) continue;\n const full = join(dir, name);\n try {\n const raw = readFileSync(full, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (parsed.version !== 1) continue;\n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) continue;\n const steps = parsed.steps.filter(\n (s): s is PlanStep =>\n !!s &&\n typeof s === \"object\" &&\n typeof (s as PlanStep).id === \"string\" &&\n typeof (s as PlanStep).title === \"string\" &&\n typeof (s as PlanStep).action === \"string\",\n );\n if (steps.length === 0) continue;\n const completedStepIds = Array.isArray(parsed.completedStepIds)\n ? parsed.completedStepIds.filter((id): id is string => typeof id === \"string\" && !!id)\n : [];\n let completedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : \"\";\n if (!completedAt || Number.isNaN(Date.parse(completedAt))) {\n try {\n completedAt = statSync(full).mtime.toISOString();\n } catch {\n completedAt = new Date(0).toISOString();\n }\n }\n const entry: PlanArchiveWithSession = {\n sessionName,\n path: full,\n completedAt,\n steps,\n completedStepIds,\n };\n if (typeof parsed.body === \"string\" && parsed.body) entry.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) entry.summary = parsed.summary;\n out.push(entry);\n } catch {\n // Skip the corrupt archive entirely.\n }\n }\n out.sort((a, b) => b.completedAt.localeCompare(a.completedAt));\n return out;\n}\n\n/** Falls back to raw ISO string past a week — \"47 days ago\" misleads more than it helps. */\nexport function relativeTime(updatedAt: string, now: number = Date.now()): string {\n const t = Date.parse(updatedAt);\n if (Number.isNaN(t)) return updatedAt;\n const diffMs = Math.max(0, now - t);\n const sec = Math.floor(diffMs / 1000);\n if (sec < 60) return `${sec}s ago`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.floor(hr / 24);\n if (day < 7) return `${day}d ago`;\n return updatedAt.slice(0, 10);\n}\n","import type { SlashArgContext, SlashCommandSpec, SlashGroup } from \"./types.js\";\n\nexport const SLASH_GROUP_ORDER = [\n \"setup\",\n \"info\",\n \"chat\",\n \"extend\",\n \"session\",\n \"code\",\n \"jobs\",\n \"advanced\",\n] as const satisfies readonly SlashGroup[];\n\nexport const SLASH_GROUP_LABEL: Record<SlashGroup, string> = {\n setup: \"SETUP\",\n info: \"INFO\",\n chat: \"CHAT\",\n extend: \"EXTEND\",\n session: \"SESSION\",\n code: \"CODE\",\n jobs: \"JOBS\",\n advanced: \"ADVANCED\",\n};\n\nconst SLASH_GROUP_RANK = new Map<SlashGroup, number>(\n SLASH_GROUP_ORDER.map((group, index) => [group, index]),\n);\n\nexport function orderSlashCommandsByGroup<T extends Pick<SlashCommandSpec, \"group\">>(\n commands: readonly T[],\n): T[] {\n return commands\n .map((command, index) => ({ command, index }))\n .sort((a, b) => {\n const groupDiff =\n SLASH_GROUP_RANK.get(a.command.group)! - SLASH_GROUP_RANK.get(b.command.group)!;\n if (groupDiff !== 0) return groupDiff;\n return a.index - b.index;\n })\n .map((entry) => entry.command);\n}\n\nexport const SLASH_COMMANDS: readonly SlashCommandSpec[] = [\n { cmd: \"help\", group: \"chat\", summary: \"show the full command reference\", aliases: [\"?\"] },\n {\n cmd: \"new\",\n group: \"chat\",\n summary: \"start a fresh conversation (clear context + scrollback)\",\n aliases: [\"reset\", \"clear\"],\n },\n { cmd: \"retry\", group: \"chat\", summary: \"truncate & resend your last message (fresh sample)\" },\n {\n cmd: \"compact\",\n group: \"chat\",\n summary:\n \"fold older turns into a summary message (cache-safe). Auto-fires at 50% ctx; this is the manual trigger.\",\n },\n {\n cmd: \"stop\",\n group: \"chat\",\n summary: \"abort the current model turn (typed alternative to Esc)\",\n },\n {\n cmd: \"btw\",\n group: \"chat\",\n argsHint: \"<question>\",\n summary:\n \"ask a quick side question — answered from a blank slate, never added to the conversation context\",\n },\n\n {\n cmd: \"preset\",\n group: \"setup\",\n argsHint: \"<auto|flash|pro>\",\n summary: \"model bundle — auto escalates flash → pro, flash/pro lock. Bare opens picker.\",\n argCompleter: [\"auto\", \"flash\", \"pro\"],\n },\n {\n cmd: \"model\",\n group: \"setup\",\n argsHint: \"<id>\",\n summary: \"switch DeepSeek model id. Bare opens picker.\",\n argCompleter: \"models\",\n },\n {\n cmd: \"language\",\n group: \"setup\",\n argsHint: \"<EN|zh-CN>\",\n summary: \"switch the runtime language\",\n argCompleter: [\"EN\", \"zh-CN\"],\n aliases: [\"lang\"],\n },\n {\n cmd: \"theme\",\n group: \"setup\",\n argsHint: \"[auto|default|dark|light|tokyo-night|github-dark|github-light|high-contrast]\",\n summary: \"show or persist the terminal theme preference. Bare opens picker.\",\n argCompleter: [\n \"auto\",\n \"default\",\n \"dark\",\n \"light\",\n \"tokyo-night\",\n \"github-dark\",\n \"github-light\",\n \"high-contrast\",\n ],\n },\n\n { cmd: \"status\", group: \"info\", summary: \"current model, flags, context, session\" },\n {\n cmd: \"cost\",\n group: \"info\",\n argsHint: \"[text]\",\n summary:\n \"bare → last turn's spend (Usage card); with text → estimate cost of sending it next (worst-case + likely-cache)\",\n },\n {\n cmd: \"context\",\n group: \"info\",\n summary: \"show context-window breakdown (system / tools / log / input)\",\n },\n {\n cmd: \"stats\",\n group: \"info\",\n summary:\n \"cross-session cost dashboard (today / week / month / all-time · cache hit · vs Claude)\",\n },\n {\n cmd: \"doctor\",\n group: \"info\",\n summary: \"health check (api / config / api-reach / index / hooks / project)\",\n },\n {\n cmd: \"keys\",\n group: \"info\",\n summary: \"keyboard + mouse + copy/paste reference\",\n },\n {\n cmd: \"copy\",\n group: \"chat\",\n summary: \"vim/tmux-style copy mode — j/k navigate, v select, y yank to clipboard\",\n },\n {\n cmd: \"feedback\",\n group: \"info\",\n summary: \"open a GitHub issue with diagnostic info copied to clipboard\",\n },\n\n { cmd: \"sessions\", group: \"session\", summary: \"list saved sessions (current marked with ▸)\" },\n {\n cmd: \"title\",\n group: \"session\",\n summary: \"ask the model to rename this session from the conversation\",\n aliases: [\"retitle\"],\n },\n\n { cmd: \"mcp\", group: \"extend\", summary: \"list MCP servers + tools attached to this session\" },\n {\n cmd: \"resource\",\n group: \"extend\",\n argsHint: \"[uri]\",\n summary: \"browse + read MCP resources (no arg → list URIs; <uri> → fetch contents)\",\n argCompleter: \"mcp-resources\",\n },\n {\n cmd: \"prompt\",\n group: \"extend\",\n argsHint: \"[name]\",\n summary: \"browse + fetch MCP prompts (no arg → list names; <name> → render prompt)\",\n argCompleter: \"mcp-prompts\",\n },\n {\n cmd: \"memory\",\n group: \"extend\",\n argsHint: \"[list|show <name>|forget <name>|clear <scope> confirm]\",\n summary: \"show / manage pinned memory (REASONIX.md + ~/.reasonix/memory)\",\n },\n {\n cmd: \"skill\",\n group: \"extend\",\n argsHint:\n \"[list|paths|paths add <path>|paths remove <path|N>|show <name>|new <name>|<name> [args]]\",\n summary: \"list / run / scaffold skills (project + custom + global + builtin)\",\n argCompleter: \"skills\",\n },\n {\n cmd: \"qq\",\n group: \"extend\",\n argsHint: \"<connect|status|disconnect>\",\n summary: \"connect, inspect, or disconnect the QQ channel\",\n argCompleter: [\"connect\", \"status\", \"disconnect\"],\n },\n\n {\n cmd: \"init\",\n group: \"code\",\n argsHint: \"[force]\",\n summary:\n \"scan the project and synthesize a baseline REASONIX.md (model writes; review with /apply). `force` overwrites an existing file.\",\n contextual: \"code\",\n argCompleter: [\"force\"],\n },\n {\n cmd: \"apply\",\n group: \"code\",\n argsHint: \"[N|N,M|N-M]\",\n summary:\n \"commit pending edit blocks to disk (no arg → all; `1`, `1,3`, or `1-4` → that subset, rest stay pending)\",\n contextual: \"code\",\n },\n {\n cmd: \"discard\",\n group: \"code\",\n argsHint: \"[N|N,M|N-M]\",\n summary: \"drop pending edit blocks without writing (no arg → all; indices → that subset)\",\n contextual: \"code\",\n },\n {\n cmd: \"walk\",\n group: \"code\",\n summary:\n \"step through pending edits one block at a time (git-add-p style: y/n per block, a apply rest, A flip AUTO)\",\n contextual: \"code\",\n },\n {\n cmd: \"undo\",\n group: \"code\",\n summary: \"roll back the last applied edit batch\",\n contextual: \"code\",\n },\n {\n cmd: \"history\",\n group: \"code\",\n summary: \"list every edit batch this session (ids for /show, undone markers)\",\n contextual: \"code\",\n },\n {\n cmd: \"show\",\n group: \"code\",\n argsHint: \"[id]\",\n summary: \"dump a stored edit diff (omit id for newest non-undone)\",\n contextual: \"code\",\n },\n {\n cmd: \"commit\",\n group: \"code\",\n argsHint: '\"msg\"',\n summary: \"git add -A && git commit -m ...\",\n contextual: \"code\",\n },\n {\n cmd: \"mode\",\n group: \"code\",\n argsHint: \"[review|auto|yolo]\",\n summary:\n \"edit-gate: review (queue) · auto (apply+undo) · yolo (apply+auto-shell). Shift+Tab cycles.\",\n contextual: \"code\",\n argCompleter: [\"review\", \"auto\", \"yolo\"],\n },\n {\n cmd: \"plan\",\n group: \"code\",\n argsHint: \"[on|off]\",\n summary: \"toggle read-only plan mode (writes bounced until submit_plan + approval)\",\n contextual: \"code\",\n argCompleter: [\"on\", \"off\"],\n },\n {\n cmd: \"checkpoint\",\n group: \"code\",\n argsHint: \"[name|list|forget <id>]\",\n summary:\n \"snapshot every file the session has touched (Cursor-style internal store, not git). /checkpoint alone lists.\",\n contextual: \"code\",\n argCompleter: [\"list\", \"forget\"],\n },\n {\n cmd: \"restore\",\n group: \"code\",\n argsHint: \"<name|id>\",\n summary: \"roll back files to a named checkpoint (see /checkpoint list)\",\n contextual: \"code\",\n },\n {\n cmd: \"cwd\",\n group: \"code\",\n argsHint: \"<path>\",\n summary:\n \"switch the workspace root mid-session — re-points fs / shell / memory tools, reloads project hooks, refreshes the at-mention walker\",\n contextual: \"code\",\n aliases: [\"sandbox\"],\n argCompleter: \"path\",\n },\n\n {\n cmd: \"jobs\",\n group: \"jobs\",\n summary: \"list background jobs started by run_background\",\n contextual: \"code\",\n },\n {\n cmd: \"kill\",\n group: \"jobs\",\n argsHint: \"<id>\",\n summary: \"stop a background job by id (SIGTERM → SIGKILL after grace)\",\n contextual: \"code\",\n },\n {\n cmd: \"logs\",\n group: \"jobs\",\n argsHint: \"<id> [lines]\",\n summary: \"tail a background job's output (default last 80 lines)\",\n contextual: \"code\",\n },\n\n {\n cmd: \"pro\",\n group: \"advanced\",\n argsHint: \"[off]\",\n summary: \"arm v4-pro for the NEXT turn only (one-shot · auto-disarms after turn)\",\n argCompleter: [\"off\"],\n },\n {\n cmd: \"budget\",\n group: \"advanced\",\n argsHint: \"[usd|off]\",\n summary:\n \"session USD cap — warns at 80%, refuses next turn at 100%. Off by default. /budget alone shows status\",\n argCompleter: [\"off\", \"1\", \"5\", \"10\", \"20\", \"50\"],\n },\n {\n cmd: \"search-engine\",\n group: \"advanced\",\n argsHint: \"<mojeek|searxng> [<endpoint>]\",\n summary: \"switch web search backend — mojeek (default, no deps) or searxng (self-hosted)\",\n argCompleter: [\"mojeek\", \"searxng\"],\n aliases: [\"se\"],\n },\n {\n cmd: \"hooks\",\n group: \"advanced\",\n argsHint: \"[reload]\",\n summary: \"list active hooks (settings.json under .reasonix/) · reload re-reads from disk\",\n },\n {\n cmd: \"permissions\",\n group: \"advanced\",\n argsHint: \"[list|add <prefix>|remove <prefix|N>|clear confirm]\",\n summary:\n \"show / edit shell allowlist (builtin read-only · per-project: ~/.reasonix/config.json)\",\n argCompleter: [\"list\", \"add\", \"remove\", \"clear\"],\n },\n {\n cmd: \"dashboard\",\n group: \"advanced\",\n argsHint: \"[stop]\",\n summary: \"launch the embedded web dashboard (127.0.0.1, token-gated)\",\n argCompleter: [\"stop\"],\n },\n {\n cmd: \"loop\",\n group: \"advanced\",\n argsHint: \"<5s..6h> <prompt> · stop · (no args = status)\",\n summary: \"auto-resubmit <prompt> every <interval> until you type something / Esc / /loop stop\",\n },\n {\n cmd: \"plans\",\n group: \"advanced\",\n summary: \"list this session's active + archived plans, newest first\",\n },\n {\n cmd: \"replay\",\n group: \"advanced\",\n summary: \"load an archived plan as a read-only Time Travel snapshot (default: newest)\",\n argsHint: \"[N]\",\n },\n {\n cmd: \"update\",\n group: \"advanced\",\n summary: \"show current vs latest version + the shell command to upgrade\",\n },\n { cmd: \"exit\", group: \"advanced\", summary: \"quit the TUI\", aliases: [\"quit\", \"q\"] },\n];\n\nexport function suggestSlashCommands(\n prefix: string,\n codeMode = false,\n counts?: Readonly<Record<string, number>>,\n): SlashCommandSpec[] {\n const p = prefix.toLowerCase();\n const matches = SLASH_COMMANDS.filter((c) => {\n // Empty prefix = browsing the menu — show the full release command surface except\n // advanced rows, which remain collapsed behind the footer hint.\n if (p === \"\") return c.group !== \"advanced\";\n if (c.contextual === \"code\" && !codeMode) return false;\n if (c.cmd.startsWith(p)) return true;\n return c.aliases?.some((a) => a.startsWith(p)) ?? false;\n });\n if (p === \"\") return orderSlashCommandsByGroup(matches);\n if (!counts) return matches;\n const indexOf = new Map(matches.map((s, i) => [s.cmd, i]));\n return [...matches].sort((a, b) => {\n const diff = (counts[b.cmd] ?? 0) - (counts[a.cmd] ?? 0);\n if (diff !== 0) return diff;\n return (indexOf.get(a.cmd) ?? 0) - (indexOf.get(b.cmd) ?? 0);\n });\n}\n\nexport function countAdvancedCommands(codeMode: boolean): number {\n return SLASH_COMMANDS.filter(\n (c) => c.group === \"advanced\" && (c.contextual !== \"code\" || codeMode),\n ).length;\n}\n\n/** alias → canonical cmd map, derived from SLASH_COMMANDS at module init. */\nconst ALIAS_TO_CMD: Readonly<Record<string, string>> = (() => {\n const m: Record<string, string> = {};\n for (const spec of SLASH_COMMANDS) {\n if (!spec.aliases) continue;\n for (const a of spec.aliases) m[a] = spec.cmd;\n }\n return m;\n})();\n\nexport function resolveSlashAlias(name: string): string {\n return ALIAS_TO_CMD[name] ?? name;\n}\n\n/** Picker fires only when arg tail has no internal whitespace; past that it's a usage hint. */\nexport function detectSlashArgContext(input: string, codeMode = false): SlashArgContext | null {\n const m = /^\\/(\\S+) ([\\s\\S]*)$/.exec(input);\n if (!m) return null;\n const cmdName = resolveSlashAlias(m[1]!.toLowerCase());\n const tail = m[2] ?? \"\";\n const spec = SLASH_COMMANDS.find(\n (s) => s.cmd === cmdName && (s.contextual !== \"code\" || codeMode),\n );\n if (!spec) return null;\n const hasInternalSpace = /\\s/.test(tail);\n const partialOffset = input.length - tail.length;\n if (hasInternalSpace) {\n return { spec, partial: tail, partialOffset, kind: \"hint\" };\n }\n return {\n spec,\n partial: tail,\n partialOffset,\n kind: spec.argCompleter ? \"picker\" : \"hint\",\n };\n}\n\nexport function parseSlash(text: string): { cmd: string; args: string[] } | null {\n if (!text.startsWith(\"/\")) return null;\n const parts = text.slice(1).trim().split(/\\s+/);\n const cmd = parts[0]?.toLowerCase() ?? \"\";\n if (!cmd) return null;\n return { cmd, args: parts.slice(1) };\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","readFileSync","readdirSync","writeFileSync","dirname","join","join","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","readdirSync"]}
1
+ {"version":3,"sources":["../../src/code/checkpoints.ts","../../src/code/plan-store.ts","../../src/cli/ui/slash/commands.ts"],"sourcesContent":["/** One file per checkpoint (not jsonl) so delete/restore is cheap and a corrupt snapshot only loses itself. */\n\nimport { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\n\n/** One file's state at the time of snapshot. `content === null` → didn't exist. */\nexport interface CheckpointFile {\n path: string;\n content: string | null;\n}\n\nexport interface Checkpoint {\n id: string;\n /** User-given name, or `auto-<reason>` for system-created snapshots. */\n name: string;\n /** Absolute workspace root the snapshot belongs to. */\n rootDir: string;\n createdAt: number;\n source: \"manual\" | \"auto-session-start\" | \"auto-pre-restore\";\n files: CheckpointFile[];\n /** Total bytes of file content captured (sum of `content?.length`). */\n bytes: number;\n}\n\nexport interface CheckpointMeta {\n id: string;\n name: string;\n createdAt: number;\n source: Checkpoint[\"source\"];\n fileCount: number;\n bytes: number;\n}\n\n/** Sanitize a directory path into a safe filesystem name for the store. */\nfunction sanitizeRoot(rootDir: string): string {\n return resolve(rootDir)\n .replace(/[\\\\/:]+/g, \"_\")\n .replace(/^_+/, \"\");\n}\n\nfunction storeRoot(rootDir: string): string {\n return join(homedir(), \".reasonix\", \"sessions\", sanitizeRoot(rootDir), \"checkpoints\");\n}\n\nfunction indexPath(rootDir: string): string {\n return join(storeRoot(rootDir), \"index.json\");\n}\n\nfunction snapshotPath(rootDir: string, id: string): string {\n return join(storeRoot(rootDir), `${id}.json`);\n}\n\n/** Load the index of checkpoint metadata for a workspace. Empty when missing. */\nexport function listCheckpoints(rootDir: string): CheckpointMeta[] {\n const path = indexPath(rootDir);\n if (!existsSync(path)) return [];\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n // Defensive: filter out malformed entries rather than throwing on\n // a single bad row. A stale entry is annoying; a thrown listCheckpoints\n // would break /checkpoint list entirely.\n return parsed.filter(\n (m): m is CheckpointMeta =>\n typeof m === \"object\" &&\n m !== null &&\n typeof m.id === \"string\" &&\n typeof m.name === \"string\" &&\n typeof m.createdAt === \"number\" &&\n typeof m.source === \"string\" &&\n typeof m.fileCount === \"number\" &&\n typeof m.bytes === \"number\",\n );\n } catch {\n return [];\n }\n}\n\nfunction writeIndex(rootDir: string, items: CheckpointMeta[]): void {\n const path = indexPath(rootDir);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(items, null, 2), \"utf8\");\n}\n\n/** Read a single checkpoint by id. Returns null when missing or corrupt. */\nexport function loadCheckpoint(rootDir: string, id: string): Checkpoint | null {\n const path = snapshotPath(rootDir, id);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && Array.isArray(parsed.files)) {\n return parsed as Checkpoint;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport interface CreateCheckpointOptions {\n rootDir: string;\n name: string;\n source?: Checkpoint[\"source\"];\n paths: readonly string[];\n}\n\n/** Missing files recorded as `content: null` so restore knows to delete; ID has random suffix to avoid same-ms collision. */\nexport function createCheckpoint(opts: CreateCheckpointOptions): CheckpointMeta {\n const absRoot = resolve(opts.rootDir);\n const id = `cp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n const files: CheckpointFile[] = [];\n let bytes = 0;\n const seen = new Set<string>();\n for (const p of opts.paths) {\n if (seen.has(p)) continue;\n seen.add(p);\n const abs = resolve(absRoot, p);\n // Path-escape guard. A snapshot of `../../../etc/passwd` is not\n // something we want — refuse silently rather than abort the whole\n // checkpoint.\n if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep}`)) continue;\n const rel = relative(absRoot, abs).split(sep).join(\"/\");\n if (existsSync(abs)) {\n try {\n const content = readFileSync(abs, \"utf8\");\n files.push({ path: rel, content });\n bytes += content.length;\n } catch {\n // Unreadable (binary, perms) — record as null so restore knows\n // to delete on revert. Wrong for binary files but consistent.\n files.push({ path: rel, content: null });\n }\n } else {\n files.push({ path: rel, content: null });\n }\n }\n\n const checkpoint: Checkpoint = {\n id,\n name: opts.name,\n rootDir: absRoot,\n createdAt: Date.now(),\n source: opts.source ?? \"manual\",\n files,\n bytes,\n };\n const cpPath = snapshotPath(absRoot, id);\n mkdirSync(dirname(cpPath), { recursive: true });\n writeFileSync(cpPath, JSON.stringify(checkpoint), \"utf8\");\n\n const meta: CheckpointMeta = {\n id,\n name: opts.name,\n createdAt: checkpoint.createdAt,\n source: checkpoint.source,\n fileCount: files.length,\n bytes,\n };\n const items = listCheckpoints(absRoot);\n items.push(meta);\n writeIndex(absRoot, items);\n return meta;\n}\n\n/** Most-recent name wins on collision. */\nexport function findCheckpoint(rootDir: string, idOrName: string): CheckpointMeta | null {\n const items = listCheckpoints(rootDir);\n // Prefer exact id match, then most-recent name match.\n const byId = items.find((m) => m.id === idOrName);\n if (byId) return byId;\n const byName = [...items].reverse().find((m) => m.name === idOrName);\n return byName ?? null;\n}\n\nexport interface RestoreResult {\n /** Files we wrote back to disk. */\n restored: string[];\n /** Files we removed (snapshot had `content: null`, file existed). */\n removed: string[];\n /** Files we couldn't touch (errors), with the reason. */\n skipped: Array<{ path: string; reason: string }>;\n}\n\n/** Path-escape rechecked against live `rootDir` since snapshot's may differ (project moved). */\nexport function restoreCheckpoint(rootDir: string, id: string): RestoreResult {\n const cp = loadCheckpoint(rootDir, id);\n const absRoot = resolve(rootDir);\n const result: RestoreResult = { restored: [], removed: [], skipped: [] };\n if (!cp) {\n result.skipped.push({ path: \"(checkpoint)\", reason: `not found: ${id}` });\n return result;\n }\n for (const f of cp.files) {\n const abs = resolve(absRoot, f.path);\n if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep}`)) {\n result.skipped.push({ path: f.path, reason: \"path escapes rootDir\" });\n continue;\n }\n try {\n if (f.content === null) {\n if (existsSync(abs)) {\n rmSync(abs);\n result.removed.push(f.path);\n }\n } else {\n mkdirSync(dirname(abs), { recursive: true });\n writeFileSync(abs, f.content, \"utf8\");\n result.restored.push(f.path);\n }\n } catch (err) {\n result.skipped.push({ path: f.path, reason: (err as Error).message });\n }\n }\n return result;\n}\n\nexport function deleteCheckpoint(rootDir: string, id: string): boolean {\n const cpPath = snapshotPath(rootDir, id);\n let removed = false;\n if (existsSync(cpPath)) {\n try {\n rmSync(cpPath);\n removed = true;\n } catch {\n return false;\n }\n }\n const items = listCheckpoints(rootDir);\n const next = items.filter((m) => m.id !== id);\n if (next.length !== items.length) {\n writeIndex(rootDir, next);\n removed = true;\n }\n return removed;\n}\n\n/** Format ms-timestamp diff as human-readable relative age. */\nexport function fmtAgo(ms: number): string {\n const now = Date.now();\n const diff = Math.max(0, now - ms);\n const s = Math.floor(diff / 1000);\n if (s < 60) return `${s}s ago`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${h}h ago`;\n const d = Math.floor(h / 24);\n return `${d}d ago`;\n}\n","/** Persists structured plan state alongside the JSONL log; markdown body lives in the log (it was a tool result) and replays on resume. */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { sanitizeName, sessionsDir } from \"../memory/session.js\";\nimport type { PlanStep } from \"../tools/plan.js\";\n\nexport interface PlanStateOnDisk {\n /** File format version — bump when shape changes. */\n version: 1;\n steps: PlanStep[];\n completedStepIds: string[];\n /** ISO8601 timestamp of the last write. */\n updatedAt: string;\n body?: string;\n summary?: string;\n}\n\nexport function planStatePath(sessionName: string): string {\n return join(sessionsDir(), `${sanitizeName(sessionName)}.plan.json`);\n}\n\nexport function loadPlanState(sessionName: string): PlanStateOnDisk | null {\n const path = planStatePath(sessionName);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (!parsed || typeof parsed !== \"object\") return null;\n if (parsed.version !== 1) return null;\n if (!Array.isArray(parsed.steps)) return null;\n if (!Array.isArray(parsed.completedStepIds)) return null;\n if (typeof parsed.updatedAt !== \"string\") return null;\n // Defensive: filter out any malformed step entries so a partially\n // corrupted file still yields a usable subset.\n const steps: PlanStep[] = [];\n for (const s of parsed.steps) {\n if (!s || typeof s !== \"object\") continue;\n const e = s as unknown as Record<string, unknown>;\n if (typeof e.id !== \"string\" || !e.id) continue;\n if (typeof e.title !== \"string\" || !e.title) continue;\n if (typeof e.action !== \"string\" || !e.action) continue;\n const step: PlanStep = { id: e.id, title: e.title, action: e.action };\n if (e.risk === \"low\" || e.risk === \"med\" || e.risk === \"high\") step.risk = e.risk;\n steps.push(step);\n }\n if (steps.length === 0) return null;\n const completedStepIds = parsed.completedStepIds.filter(\n (id): id is string => typeof id === \"string\" && id.length > 0,\n );\n const out: PlanStateOnDisk = {\n version: 1,\n steps,\n completedStepIds,\n updatedAt: parsed.updatedAt,\n };\n if (typeof parsed.body === \"string\" && parsed.body) out.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) out.summary = parsed.summary;\n return out;\n } catch {\n return null;\n }\n}\n\n/** Best-effort: write failure logs to stderr instead of crashing the TUI. */\nexport function savePlanState(\n sessionName: string,\n steps: PlanStep[],\n completedStepIds: Iterable<string>,\n extras?: { body?: string; summary?: string },\n): void {\n const path = planStatePath(sessionName);\n try {\n mkdirSync(dirname(path), { recursive: true });\n const state: PlanStateOnDisk = {\n version: 1,\n steps,\n completedStepIds: [...completedStepIds],\n updatedAt: new Date().toISOString(),\n };\n if (extras?.body) state.body = extras.body;\n if (extras?.summary) state.summary = extras.summary;\n writeFileSync(path, `${JSON.stringify(state, null, 2)}\\n`, \"utf8\");\n } catch (err) {\n process.stderr.write(\n `▸ plan-store: failed to save plan for \"${sessionName}\": ${(err as Error).message}\\n`,\n );\n }\n}\n\n/** Remove the persisted plan, if any. Used on cancel / clean reset. */\nexport function clearPlanState(sessionName: string): void {\n const path = planStatePath(sessionName);\n try {\n if (existsSync(path)) unlinkSync(path);\n } catch {\n /* nothing to do — leftover file is harmless, will be overwritten next save */\n }\n}\n\n/** Random suffix avoids same-millisecond collision; `:`/`.` swapped for Windows-safe filenames. */\nexport function archivePlanState(sessionName: string): string | null {\n const active = planStatePath(sessionName);\n if (!existsSync(active)) return null;\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const suffix = Math.random().toString(36).slice(2, 6);\n const archive = join(\n sessionsDir(),\n `${sanitizeName(sessionName)}.plan.${stamp}-${suffix}.done.json`,\n );\n try {\n renameSync(active, archive);\n return archive;\n } catch (err) {\n process.stderr.write(\n `▸ plan-store: failed to archive plan for \"${sessionName}\": ${(err as Error).message}\\n`,\n );\n return null;\n }\n}\n\nexport interface PlanArchiveSummary {\n path: string;\n completedAt: string;\n steps: PlanStep[];\n completedStepIds: string[];\n /** Markdown body, when the archive carried it. */\n body?: string;\n /** One-line human-friendly title, when supplied. */\n summary?: string;\n}\n\nexport function listPlanArchives(sessionName: string): PlanArchiveSummary[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n const prefix = `${sanitizeName(sessionName)}.plan.`;\n const suffix = \".done.json\";\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n const summaries: PlanArchiveSummary[] = [];\n for (const name of entries) {\n if (!name.startsWith(prefix) || !name.endsWith(suffix)) continue;\n const full = join(dir, name);\n try {\n const raw = readFileSync(full, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (parsed.version !== 1) continue;\n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) continue;\n const steps = parsed.steps.filter(\n (s): s is PlanStep =>\n !!s &&\n typeof s === \"object\" &&\n typeof (s as PlanStep).id === \"string\" &&\n typeof (s as PlanStep).title === \"string\" &&\n typeof (s as PlanStep).action === \"string\",\n );\n if (steps.length === 0) continue;\n const completedStepIds = Array.isArray(parsed.completedStepIds)\n ? parsed.completedStepIds.filter((id): id is string => typeof id === \"string\" && !!id)\n : [];\n // Prefer the file's own updatedAt; fall back to mtime if missing\n // or unparseable so a hand-edited archive still sorts sensibly.\n let completedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : \"\";\n if (!completedAt || Number.isNaN(Date.parse(completedAt))) {\n try {\n completedAt = statSync(full).mtime.toISOString();\n } catch {\n completedAt = new Date(0).toISOString();\n }\n }\n const entry: PlanArchiveSummary = { path: full, completedAt, steps, completedStepIds };\n if (typeof parsed.body === \"string\" && parsed.body) entry.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) entry.summary = parsed.summary;\n summaries.push(entry);\n } catch {\n // Skip the corrupt archive entirely.\n }\n }\n summaries.sort((a, b) => b.completedAt.localeCompare(a.completedAt));\n return summaries;\n}\n\nexport interface PlanArchiveWithSession extends PlanArchiveSummary {\n sessionName: string;\n}\n\n/** Cross-session enumeration in a single dir scan — used by the dashboard plans panel where the per-session loop was O(N×M) and timed out for users with hundreds of sessions. */\nexport function listAllPlanArchives(): PlanArchiveWithSession[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n const out: PlanArchiveWithSession[] = [];\n const suffix = \".done.json\";\n const planMarker = \".plan.\";\n for (const name of entries) {\n if (!name.endsWith(suffix)) continue;\n const planIdx = name.indexOf(planMarker);\n if (planIdx < 0) continue;\n const sessionName = name.slice(0, planIdx);\n if (!sessionName) continue;\n const full = join(dir, name);\n try {\n const raw = readFileSync(full, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (parsed.version !== 1) continue;\n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) continue;\n const steps = parsed.steps.filter(\n (s): s is PlanStep =>\n !!s &&\n typeof s === \"object\" &&\n typeof (s as PlanStep).id === \"string\" &&\n typeof (s as PlanStep).title === \"string\" &&\n typeof (s as PlanStep).action === \"string\",\n );\n if (steps.length === 0) continue;\n const completedStepIds = Array.isArray(parsed.completedStepIds)\n ? parsed.completedStepIds.filter((id): id is string => typeof id === \"string\" && !!id)\n : [];\n let completedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : \"\";\n if (!completedAt || Number.isNaN(Date.parse(completedAt))) {\n try {\n completedAt = statSync(full).mtime.toISOString();\n } catch {\n completedAt = new Date(0).toISOString();\n }\n }\n const entry: PlanArchiveWithSession = {\n sessionName,\n path: full,\n completedAt,\n steps,\n completedStepIds,\n };\n if (typeof parsed.body === \"string\" && parsed.body) entry.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) entry.summary = parsed.summary;\n out.push(entry);\n } catch {\n // Skip the corrupt archive entirely.\n }\n }\n out.sort((a, b) => b.completedAt.localeCompare(a.completedAt));\n return out;\n}\n\n/** Falls back to raw ISO string past a week — \"47 days ago\" misleads more than it helps. */\nexport function relativeTime(updatedAt: string, now: number = Date.now()): string {\n const t = Date.parse(updatedAt);\n if (Number.isNaN(t)) return updatedAt;\n const diffMs = Math.max(0, now - t);\n const sec = Math.floor(diffMs / 1000);\n if (sec < 60) return `${sec}s ago`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.floor(hr / 24);\n if (day < 7) return `${day}d ago`;\n return updatedAt.slice(0, 10);\n}\n","import type { SlashArgContext, SlashCommandSpec, SlashGroup } from \"./types.js\";\n\nexport const SLASH_GROUP_ORDER = [\n \"setup\",\n \"info\",\n \"chat\",\n \"extend\",\n \"session\",\n \"code\",\n \"jobs\",\n \"advanced\",\n] as const satisfies readonly SlashGroup[];\n\nexport const SLASH_GROUP_LABEL: Record<SlashGroup, string> = {\n setup: \"SETUP\",\n info: \"INFO\",\n chat: \"CHAT\",\n extend: \"EXTEND\",\n session: \"SESSION\",\n code: \"CODE\",\n jobs: \"JOBS\",\n advanced: \"ADVANCED\",\n};\n\nconst SLASH_GROUP_RANK = new Map<SlashGroup, number>(\n SLASH_GROUP_ORDER.map((group, index) => [group, index]),\n);\n\nexport function orderSlashCommandsByGroup<T extends Pick<SlashCommandSpec, \"group\">>(\n commands: readonly T[],\n): T[] {\n return commands\n .map((command, index) => ({ command, index }))\n .sort((a, b) => {\n const groupDiff =\n SLASH_GROUP_RANK.get(a.command.group)! - SLASH_GROUP_RANK.get(b.command.group)!;\n if (groupDiff !== 0) return groupDiff;\n return a.index - b.index;\n })\n .map((entry) => entry.command);\n}\n\nexport const SLASH_COMMANDS: readonly SlashCommandSpec[] = [\n { cmd: \"help\", group: \"chat\", summary: \"show the full command reference\", aliases: [\"?\"] },\n {\n cmd: \"new\",\n group: \"chat\",\n summary: \"start a fresh conversation (clear context + scrollback)\",\n aliases: [\"reset\", \"clear\"],\n },\n { cmd: \"retry\", group: \"chat\", summary: \"truncate & resend your last message (fresh sample)\" },\n {\n cmd: \"compact\",\n group: \"chat\",\n summary:\n \"fold older turns into a summary message (cache-safe). Auto-fires at 50% ctx; this is the manual trigger.\",\n },\n {\n cmd: \"stop\",\n group: \"chat\",\n summary: \"abort the current model turn (typed alternative to Esc)\",\n },\n {\n cmd: \"btw\",\n group: \"chat\",\n argsHint: \"<question>\",\n summary:\n \"ask a quick side question — answered from a blank slate, never added to the conversation context\",\n },\n\n {\n cmd: \"preset\",\n group: \"setup\",\n argsHint: \"<auto|flash|pro>\",\n summary: \"model bundle — auto escalates flash → pro, flash/pro lock. Bare opens picker.\",\n argCompleter: [\"auto\", \"flash\", \"pro\"],\n },\n {\n cmd: \"model\",\n group: \"setup\",\n argsHint: \"<id>\",\n summary: \"switch DeepSeek model id. Bare opens picker.\",\n argCompleter: \"models\",\n },\n {\n cmd: \"language\",\n group: \"setup\",\n argsHint: \"<EN|zh-CN>\",\n summary: \"switch the runtime language\",\n argCompleter: [\"EN\", \"zh-CN\"],\n aliases: [\"lang\"],\n },\n {\n cmd: \"theme\",\n group: \"setup\",\n argsHint: \"[auto|default|dark|light|tokyo-night|github-dark|github-light|high-contrast]\",\n summary: \"show or persist the terminal theme preference. Bare opens picker.\",\n argCompleter: [\n \"auto\",\n \"default\",\n \"dark\",\n \"light\",\n \"tokyo-night\",\n \"github-dark\",\n \"github-light\",\n \"high-contrast\",\n ],\n },\n\n { cmd: \"status\", group: \"info\", summary: \"current model, flags, context, session\" },\n {\n cmd: \"cost\",\n group: \"info\",\n argsHint: \"[text]\",\n summary:\n \"bare → last turn's spend (Usage card); with text → estimate cost of sending it next (worst-case + likely-cache)\",\n },\n {\n cmd: \"context\",\n group: \"info\",\n summary: \"show context-window breakdown (system / tools / log / input)\",\n },\n {\n cmd: \"stats\",\n group: \"info\",\n summary:\n \"cross-session cost dashboard (today / week / month / all-time · cache hit · vs Claude)\",\n },\n {\n cmd: \"doctor\",\n group: \"info\",\n summary: \"health check (api / config / api-reach / index / hooks / project)\",\n },\n {\n cmd: \"keys\",\n group: \"info\",\n summary: \"keyboard + mouse + copy/paste reference\",\n },\n {\n cmd: \"copy\",\n group: \"chat\",\n summary: \"vim/tmux-style copy mode — j/k navigate, v select, y yank to clipboard\",\n },\n {\n cmd: \"feedback\",\n group: \"info\",\n summary: \"open a GitHub issue with diagnostic info copied to clipboard\",\n },\n\n { cmd: \"sessions\", group: \"session\", summary: \"list saved sessions (current marked with ▸)\" },\n {\n cmd: \"title\",\n group: \"session\",\n summary: \"ask the model to rename this session from the conversation\",\n aliases: [\"retitle\"],\n },\n\n { cmd: \"mcp\", group: \"extend\", summary: \"list MCP servers + tools attached to this session\" },\n {\n cmd: \"resource\",\n group: \"extend\",\n argsHint: \"[uri]\",\n summary: \"browse + read MCP resources (no arg → list URIs; <uri> → fetch contents)\",\n argCompleter: \"mcp-resources\",\n },\n {\n cmd: \"prompt\",\n group: \"extend\",\n argsHint: \"[name]\",\n summary: \"browse + fetch MCP prompts (no arg → list names; <name> → render prompt)\",\n argCompleter: \"mcp-prompts\",\n },\n {\n cmd: \"memory\",\n group: \"extend\",\n argsHint: \"[list|show <name>|forget <name>|clear <scope> confirm]\",\n summary: \"show / manage pinned memory (REASONIX.md + ~/.reasonix/memory)\",\n },\n {\n cmd: \"skill\",\n group: \"extend\",\n argsHint:\n \"[list|paths|paths add <path>|paths remove <path|N>|show <name>|new <name>|<name> [args]]\",\n summary: \"list / run / scaffold skills (project + custom + global + builtin)\",\n argCompleter: \"skills\",\n },\n {\n cmd: \"qq\",\n group: \"extend\",\n argsHint: \"<connect|status|disconnect>\",\n summary: \"connect, inspect, or disconnect the QQ channel\",\n argCompleter: [\"connect\", \"status\", \"disconnect\"],\n },\n\n {\n cmd: \"init\",\n group: \"code\",\n argsHint: \"[force]\",\n summary:\n \"scan the project and synthesize a baseline REASONIX.md (model writes; review with /apply). `force` overwrites an existing file.\",\n contextual: \"code\",\n argCompleter: [\"force\"],\n },\n {\n cmd: \"apply\",\n group: \"code\",\n argsHint: \"[N|N,M|N-M]\",\n summary:\n \"commit pending edit blocks to disk (no arg → all; `1`, `1,3`, or `1-4` → that subset, rest stay pending)\",\n contextual: \"code\",\n },\n {\n cmd: \"discard\",\n group: \"code\",\n argsHint: \"[N|N,M|N-M]\",\n summary: \"drop pending edit blocks without writing (no arg → all; indices → that subset)\",\n contextual: \"code\",\n },\n {\n cmd: \"walk\",\n group: \"code\",\n summary:\n \"step through pending edits one block at a time (git-add-p style: y/n per block, a apply rest, A flip AUTO)\",\n contextual: \"code\",\n },\n {\n cmd: \"undo\",\n group: \"code\",\n summary: \"roll back the last applied edit batch\",\n contextual: \"code\",\n },\n {\n cmd: \"history\",\n group: \"code\",\n summary: \"list every edit batch this session (ids for /show, undone markers)\",\n contextual: \"code\",\n },\n {\n cmd: \"show\",\n group: \"code\",\n argsHint: \"[id]\",\n summary: \"dump a stored edit diff (omit id for newest non-undone)\",\n contextual: \"code\",\n },\n {\n cmd: \"commit\",\n group: \"code\",\n argsHint: '\"msg\"',\n summary: \"git add -A && git commit -m ...\",\n contextual: \"code\",\n },\n {\n cmd: \"mode\",\n group: \"code\",\n argsHint: \"[review|auto|yolo]\",\n summary:\n \"edit-gate: review (queue) · auto (apply+undo) · yolo (apply+auto-shell). Shift+Tab cycles.\",\n contextual: \"code\",\n argCompleter: [\"review\", \"auto\", \"yolo\"],\n },\n {\n cmd: \"plan\",\n group: \"code\",\n argsHint: \"[on|off]\",\n summary: \"toggle read-only plan mode (writes bounced until submit_plan + approval)\",\n contextual: \"code\",\n argCompleter: [\"on\", \"off\"],\n },\n {\n cmd: \"checkpoint\",\n group: \"code\",\n argsHint: \"[name|list|forget <id>]\",\n summary:\n \"snapshot every file the session has touched (Cursor-style internal store, not git). /checkpoint alone lists.\",\n contextual: \"code\",\n argCompleter: [\"list\", \"forget\"],\n },\n {\n cmd: \"restore\",\n group: \"code\",\n argsHint: \"<name|id>\",\n summary: \"roll back files to a named checkpoint (see /checkpoint list)\",\n contextual: \"code\",\n },\n {\n cmd: \"cwd\",\n group: \"code\",\n argsHint: \"[path]\",\n summary:\n \"switch the workspace root mid-session — re-points fs / shell / memory tools, reloads project hooks, refreshes the at-mention walker\",\n contextual: \"code\",\n aliases: [\"sandbox\"],\n argCompleter: \"path\",\n },\n\n {\n cmd: \"jobs\",\n group: \"jobs\",\n summary: \"list background jobs started by run_background\",\n contextual: \"code\",\n },\n {\n cmd: \"kill\",\n group: \"jobs\",\n argsHint: \"<id>\",\n summary: \"stop a background job by id (SIGTERM → SIGKILL after grace)\",\n contextual: \"code\",\n },\n {\n cmd: \"logs\",\n group: \"jobs\",\n argsHint: \"<id> [lines]\",\n summary: \"tail a background job's output (default last 80 lines)\",\n contextual: \"code\",\n },\n\n {\n cmd: \"pro\",\n group: \"advanced\",\n argsHint: \"[off]\",\n summary: \"arm v4-pro for the NEXT turn only (one-shot · auto-disarms after turn)\",\n argCompleter: [\"off\"],\n },\n {\n cmd: \"budget\",\n group: \"advanced\",\n argsHint: \"[usd|off]\",\n summary:\n \"session USD cap — warns at 80%, refuses next turn at 100%. Off by default. /budget alone shows status\",\n argCompleter: [\"off\", \"1\", \"5\", \"10\", \"20\", \"50\"],\n },\n {\n cmd: \"search-engine\",\n group: \"advanced\",\n argsHint: \"<mojeek|searxng|metaso> [<endpoint>]\",\n summary:\n \"switch web search backend — mojeek (default, no deps), searxng (self-hosted), or metaso (free quota 100/d)\",\n argCompleter: [\"mojeek\", \"searxng\", \"metaso\"],\n aliases: [\"se\"],\n },\n {\n cmd: \"hooks\",\n group: \"advanced\",\n argsHint: \"[reload]\",\n summary: \"list active hooks (settings.json under .reasonix/) · reload re-reads from disk\",\n },\n {\n cmd: \"permissions\",\n group: \"advanced\",\n argsHint: \"[list|add <prefix>|remove <prefix|N>|clear confirm]\",\n summary:\n \"show / edit shell allowlist (builtin read-only · per-project: ~/.reasonix/config.json)\",\n argCompleter: [\"list\", \"add\", \"remove\", \"clear\"],\n },\n {\n cmd: \"dashboard\",\n group: \"advanced\",\n argsHint: \"[stop]\",\n summary: \"launch the embedded web dashboard (127.0.0.1, token-gated)\",\n argCompleter: [\"stop\"],\n },\n {\n cmd: \"loop\",\n group: \"advanced\",\n argsHint: \"<5s..6h> <prompt> · stop · (no args = status)\",\n summary: \"auto-resubmit <prompt> every <interval> until you type something / Esc / /loop stop\",\n },\n {\n cmd: \"plans\",\n group: \"advanced\",\n summary: \"list this session's active + archived plans, newest first\",\n },\n {\n cmd: \"replay\",\n group: \"advanced\",\n summary: \"load an archived plan as a read-only Time Travel snapshot (default: newest)\",\n argsHint: \"[N]\",\n },\n {\n cmd: \"update\",\n group: \"advanced\",\n summary: \"show current vs latest version + the shell command to upgrade\",\n },\n { cmd: \"exit\", group: \"advanced\", summary: \"quit the TUI\", aliases: [\"quit\", \"q\"] },\n];\n\nexport function suggestSlashCommands(\n prefix: string,\n codeMode = false,\n counts?: Readonly<Record<string, number>>,\n): SlashCommandSpec[] {\n const p = prefix.toLowerCase();\n const matches = SLASH_COMMANDS.filter((c) => {\n // Empty prefix = browsing the menu — show the full release command surface except\n // advanced rows, which remain collapsed behind the footer hint.\n if (p === \"\") return c.group !== \"advanced\";\n if (c.contextual === \"code\" && !codeMode) return false;\n if (c.cmd.startsWith(p)) return true;\n return c.aliases?.some((a) => a.startsWith(p)) ?? false;\n });\n if (p === \"\") return orderSlashCommandsByGroup(matches);\n if (!counts) return matches;\n const indexOf = new Map(matches.map((s, i) => [s.cmd, i]));\n return [...matches].sort((a, b) => {\n const diff = (counts[b.cmd] ?? 0) - (counts[a.cmd] ?? 0);\n if (diff !== 0) return diff;\n return (indexOf.get(a.cmd) ?? 0) - (indexOf.get(b.cmd) ?? 0);\n });\n}\n\nexport function countAdvancedCommands(codeMode: boolean): number {\n return SLASH_COMMANDS.filter(\n (c) => c.group === \"advanced\" && (c.contextual !== \"code\" || codeMode),\n ).length;\n}\n\n/** alias → canonical cmd map, derived from SLASH_COMMANDS at module init. */\nconst ALIAS_TO_CMD: Readonly<Record<string, string>> = (() => {\n const m: Record<string, string> = {};\n for (const spec of SLASH_COMMANDS) {\n if (!spec.aliases) continue;\n for (const a of spec.aliases) m[a] = spec.cmd;\n }\n return m;\n})();\n\nexport function resolveSlashAlias(name: string): string {\n return ALIAS_TO_CMD[name] ?? name;\n}\n\n/** Picker fires only when arg tail has no internal whitespace; past that it's a usage hint. */\nexport function detectSlashArgContext(input: string, codeMode = false): SlashArgContext | null {\n const m = /^\\/(\\S+) ([\\s\\S]*)$/.exec(input);\n if (!m) return null;\n const cmdName = resolveSlashAlias(m[1]!.toLowerCase());\n const tail = m[2] ?? \"\";\n const spec = SLASH_COMMANDS.find(\n (s) => s.cmd === cmdName && (s.contextual !== \"code\" || codeMode),\n );\n if (!spec) return null;\n const hasInternalSpace = /\\s/.test(tail);\n const partialOffset = input.length - tail.length;\n if (hasInternalSpace) {\n return { spec, partial: tail, partialOffset, kind: \"hint\" };\n }\n return {\n spec,\n partial: tail,\n partialOffset,\n kind: spec.argCompleter ? \"picker\" : \"hint\",\n };\n}\n\nexport function parseSlash(text: string): { cmd: string; args: string[] } | null {\n if (!text.startsWith(\"/\")) return null;\n const parts = text.slice(1).trim().split(/\\s+/);\n const cmd = parts[0]?.toLowerCase() ?? \"\";\n if (!cmd) return null;\n return { cmd, args: parts.slice(1) };\n}\n"],"mappings":";;;;;;;;AAEA,SAAS,YAAY,WAAW,cAA2B,QAAQ,qBAAqB;AACxF,SAAS,eAAe;AACxB,SAAS,SAAS,MAAM,UAAU,SAAS,WAAW;AA+BtD,SAAS,aAAa,SAAyB;AAC7C,SAAO,QAAQ,OAAO,EACnB,QAAQ,YAAY,GAAG,EACvB,QAAQ,OAAO,EAAE;AACtB;AAEA,SAAS,UAAU,SAAyB;AAC1C,SAAO,KAAK,QAAQ,GAAG,aAAa,YAAY,aAAa,OAAO,GAAG,aAAa;AACtF;AAEA,SAAS,UAAU,SAAyB;AAC1C,SAAO,KAAK,UAAU,OAAO,GAAG,YAAY;AAC9C;AAEA,SAAS,aAAa,SAAiB,IAAoB;AACzD,SAAO,KAAK,UAAU,OAAO,GAAG,GAAG,EAAE,OAAO;AAC9C;AAGO,SAAS,gBAAgB,SAAmC;AACjE,QAAM,OAAO,UAAU,OAAO;AAC9B,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO,CAAC;AAC/B,MAAI;AACF,UAAM,MAAM,aAAa,MAAM,MAAM;AACrC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO,CAAC;AAIpC,WAAO,OAAO;AAAA,MACZ,CAAC,MACC,OAAO,MAAM,YACb,MAAM,QACN,OAAO,EAAE,OAAO,YAChB,OAAO,EAAE,SAAS,YAClB,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,WAAW,YACpB,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,UAAU;AAAA,IACvB;AAAA,EACF,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,SAAS,WAAW,SAAiB,OAA+B;AAClE,QAAM,OAAO,UAAU,OAAO;AAC9B,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,gBAAc,MAAM,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,MAAM;AAC5D;AAGO,SAAS,eAAe,SAAiB,IAA+B;AAC7E,QAAM,OAAO,aAAa,SAAS,EAAE;AACrC,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,MAAM,aAAa,MAAM,MAAM;AACrC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,KAAK,GAAG;AACvE,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAUO,SAAS,iBAAiB,MAA+C;AAC9E,QAAM,UAAU,QAAQ,KAAK,OAAO;AACpC,QAAM,KAAK,MAAM,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAClF,QAAM,QAA0B,CAAC;AACjC,MAAI,QAAQ;AACZ,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,KAAK,KAAK,OAAO;AAC1B,QAAI,KAAK,IAAI,CAAC,EAAG;AACjB,SAAK,IAAI,CAAC;AACV,UAAM,MAAM,QAAQ,SAAS,CAAC;AAI9B,QAAI,QAAQ,WAAW,CAAC,IAAI,WAAW,GAAG,OAAO,GAAG,GAAG,EAAE,EAAG;AAC5D,UAAM,MAAM,SAAS,SAAS,GAAG,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AACtD,QAAI,WAAW,GAAG,GAAG;AACnB,UAAI;AACF,cAAM,UAAU,aAAa,KAAK,MAAM;AACxC,cAAM,KAAK,EAAE,MAAM,KAAK,QAAQ,CAAC;AACjC,iBAAS,QAAQ;AAAA,MACnB,QAAQ;AAGN,cAAM,KAAK,EAAE,MAAM,KAAK,SAAS,KAAK,CAAC;AAAA,MACzC;AAAA,IACF,OAAO;AACL,YAAM,KAAK,EAAE,MAAM,KAAK,SAAS,KAAK,CAAC;AAAA,IACzC;AAAA,EACF;AAEA,QAAM,aAAyB;AAAA,IAC7B;AAAA,IACA,MAAM,KAAK;AAAA,IACX,SAAS;AAAA,IACT,WAAW,KAAK,IAAI;AAAA,IACpB,QAAQ,KAAK,UAAU;AAAA,IACvB;AAAA,IACA;AAAA,EACF;AACA,QAAM,SAAS,aAAa,SAAS,EAAE;AACvC,YAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,gBAAc,QAAQ,KAAK,UAAU,UAAU,GAAG,MAAM;AAExD,QAAM,OAAuB;AAAA,IAC3B;AAAA,IACA,MAAM,KAAK;AAAA,IACX,WAAW,WAAW;AAAA,IACtB,QAAQ,WAAW;AAAA,IACnB,WAAW,MAAM;AAAA,IACjB;AAAA,EACF;AACA,QAAM,QAAQ,gBAAgB,OAAO;AACrC,QAAM,KAAK,IAAI;AACf,aAAW,SAAS,KAAK;AACzB,SAAO;AACT;AAGO,SAAS,eAAe,SAAiB,UAAyC;AACvF,QAAM,QAAQ,gBAAgB,OAAO;AAErC,QAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AAChD,MAAI,KAAM,QAAO;AACjB,QAAM,SAAS,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ;AACnE,SAAO,UAAU;AACnB;AAYO,SAAS,kBAAkB,SAAiB,IAA2B;AAC5E,QAAM,KAAK,eAAe,SAAS,EAAE;AACrC,QAAM,UAAU,QAAQ,OAAO;AAC/B,QAAM,SAAwB,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AACvE,MAAI,CAAC,IAAI;AACP,WAAO,QAAQ,KAAK,EAAE,MAAM,gBAAgB,QAAQ,cAAc,EAAE,GAAG,CAAC;AACxE,WAAO;AAAA,EACT;AACA,aAAW,KAAK,GAAG,OAAO;AACxB,UAAM,MAAM,QAAQ,SAAS,EAAE,IAAI;AACnC,QAAI,QAAQ,WAAW,CAAC,IAAI,WAAW,GAAG,OAAO,GAAG,GAAG,EAAE,GAAG;AAC1D,aAAO,QAAQ,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,uBAAuB,CAAC;AACpE;AAAA,IACF;AACA,QAAI;AACF,UAAI,EAAE,YAAY,MAAM;AACtB,YAAI,WAAW,GAAG,GAAG;AACnB,iBAAO,GAAG;AACV,iBAAO,QAAQ,KAAK,EAAE,IAAI;AAAA,QAC5B;AAAA,MACF,OAAO;AACL,kBAAU,QAAQ,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3C,sBAAc,KAAK,EAAE,SAAS,MAAM;AACpC,eAAO,SAAS,KAAK,EAAE,IAAI;AAAA,MAC7B;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,QAAQ,KAAK,EAAE,MAAM,EAAE,MAAM,QAAS,IAAc,QAAQ,CAAC;AAAA,IACtE;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,SAAiB,IAAqB;AACrE,QAAM,SAAS,aAAa,SAAS,EAAE;AACvC,MAAI,UAAU;AACd,MAAI,WAAW,MAAM,GAAG;AACtB,QAAI;AACF,aAAO,MAAM;AACb,gBAAU;AAAA,IACZ,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,QAAQ,gBAAgB,OAAO;AACrC,QAAM,OAAO,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAC5C,MAAI,KAAK,WAAW,MAAM,QAAQ;AAChC,eAAW,SAAS,IAAI;AACxB,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAGO,SAAS,OAAO,IAAoB;AACzC,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,OAAO,KAAK,IAAI,GAAG,MAAM,EAAE;AACjC,QAAM,IAAI,KAAK,MAAM,OAAO,GAAI;AAChC,MAAI,IAAI,GAAI,QAAO,GAAG,CAAC;AACvB,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,MAAI,IAAI,GAAI,QAAO,GAAG,CAAC;AACvB,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,MAAI,IAAI,GAAI,QAAO,GAAG,CAAC;AACvB,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,SAAO,GAAG,CAAC;AACb;;;ACzPA;AAAA,EACE,cAAAA;AAAA,EACA,aAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,eAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,OACK;AACP,SAAS,WAAAC,UAAS,QAAAC,aAAY;AAevB,SAAS,cAAc,aAA6B;AACzD,SAAOC,MAAK,YAAY,GAAG,GAAG,aAAa,WAAW,CAAC,YAAY;AACrE;AAEO,SAAS,cAAc,aAA6C;AACzE,QAAM,OAAO,cAAc,WAAW;AACtC,MAAI,CAACC,YAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,MAAMC,cAAa,MAAM,MAAM;AACrC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,QAAI,OAAO,YAAY,EAAG,QAAO;AACjC,QAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,EAAG,QAAO;AACzC,QAAI,CAAC,MAAM,QAAQ,OAAO,gBAAgB,EAAG,QAAO;AACpD,QAAI,OAAO,OAAO,cAAc,SAAU,QAAO;AAGjD,UAAM,QAAoB,CAAC;AAC3B,eAAW,KAAK,OAAO,OAAO;AAC5B,UAAI,CAAC,KAAK,OAAO,MAAM,SAAU;AACjC,YAAM,IAAI;AACV,UAAI,OAAO,EAAE,OAAO,YAAY,CAAC,EAAE,GAAI;AACvC,UAAI,OAAO,EAAE,UAAU,YAAY,CAAC,EAAE,MAAO;AAC7C,UAAI,OAAO,EAAE,WAAW,YAAY,CAAC,EAAE,OAAQ;AAC/C,YAAM,OAAiB,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,OAAO,QAAQ,EAAE,OAAO;AACpE,UAAI,EAAE,SAAS,SAAS,EAAE,SAAS,SAAS,EAAE,SAAS,OAAQ,MAAK,OAAO,EAAE;AAC7E,YAAM,KAAK,IAAI;AAAA,IACjB;AACA,QAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,UAAM,mBAAmB,OAAO,iBAAiB;AAAA,MAC/C,CAAC,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS;AAAA,IAC9D;AACA,UAAM,MAAuB;AAAA,MAC3B,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,WAAW,OAAO;AAAA,IACpB;AACA,QAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAM,KAAI,OAAO,OAAO;AACtE,QAAI,OAAO,OAAO,YAAY,YAAY,OAAO,QAAS,KAAI,UAAU,OAAO;AAC/E,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,cACd,aACA,OACA,kBACA,QACM;AACN,QAAM,OAAO,cAAc,WAAW;AACtC,MAAI;AACF,IAAAC,WAAUC,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,UAAM,QAAyB;AAAA,MAC7B,SAAS;AAAA,MACT;AAAA,MACA,kBAAkB,CAAC,GAAG,gBAAgB;AAAA,MACtC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AACA,QAAI,QAAQ,KAAM,OAAM,OAAO,OAAO;AACtC,QAAI,QAAQ,QAAS,OAAM,UAAU,OAAO;AAC5C,IAAAC,eAAc,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AAAA,EACnE,SAAS,KAAK;AACZ,YAAQ,OAAO;AAAA,MACb,+CAA0C,WAAW,MAAO,IAAc,OAAO;AAAA;AAAA,IACnF;AAAA,EACF;AACF;AAGO,SAAS,eAAe,aAA2B;AACxD,QAAM,OAAO,cAAc,WAAW;AACtC,MAAI;AACF,QAAIJ,YAAW,IAAI,EAAG,YAAW,IAAI;AAAA,EACvC,QAAQ;AAAA,EAER;AACF;AAGO,SAAS,iBAAiB,aAAoC;AACnE,QAAM,SAAS,cAAc,WAAW;AACxC,MAAI,CAACA,YAAW,MAAM,EAAG,QAAO;AAChC,QAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,SAAS,GAAG;AAC3D,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;AACpD,QAAM,UAAUD;AAAA,IACd,YAAY;AAAA,IACZ,GAAG,aAAa,WAAW,CAAC,SAAS,KAAK,IAAI,MAAM;AAAA,EACtD;AACA,MAAI;AACF,eAAW,QAAQ,OAAO;AAC1B,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAQ,OAAO;AAAA,MACb,kDAA6C,WAAW,MAAO,IAAc,OAAO;AAAA;AAAA,IACtF;AACA,WAAO;AAAA,EACT;AACF;AAaO,SAAS,iBAAiB,aAA2C;AAC1E,QAAM,MAAM,YAAY;AACxB,MAAI,CAACC,YAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,QAAM,SAAS,GAAG,aAAa,WAAW,CAAC;AAC3C,QAAM,SAAS;AACf,MAAI;AACJ,MAAI;AACF,cAAUK,aAAY,GAAG;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,YAAkC,CAAC;AACzC,aAAW,QAAQ,SAAS;AAC1B,QAAI,CAAC,KAAK,WAAW,MAAM,KAAK,CAAC,KAAK,SAAS,MAAM,EAAG;AACxD,UAAM,OAAON,MAAK,KAAK,IAAI;AAC3B,QAAI;AACF,YAAM,MAAME,cAAa,MAAM,MAAM;AACrC,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,OAAO,YAAY,EAAG;AAC1B,UAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM,WAAW,EAAG;AAC/D,YAAM,QAAQ,OAAO,MAAM;AAAA,QACzB,CAAC,MACC,CAAC,CAAC,KACF,OAAO,MAAM,YACb,OAAQ,EAAe,OAAO,YAC9B,OAAQ,EAAe,UAAU,YACjC,OAAQ,EAAe,WAAW;AAAA,MACtC;AACA,UAAI,MAAM,WAAW,EAAG;AACxB,YAAM,mBAAmB,MAAM,QAAQ,OAAO,gBAAgB,IAC1D,OAAO,iBAAiB,OAAO,CAAC,OAAqB,OAAO,OAAO,YAAY,CAAC,CAAC,EAAE,IACnF,CAAC;AAGL,UAAI,cAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAC5E,UAAI,CAAC,eAAe,OAAO,MAAM,KAAK,MAAM,WAAW,CAAC,GAAG;AACzD,YAAI;AACF,wBAAc,SAAS,IAAI,EAAE,MAAM,YAAY;AAAA,QACjD,QAAQ;AACN,yBAAc,oBAAI,KAAK,CAAC,GAAE,YAAY;AAAA,QACxC;AAAA,MACF;AACA,YAAM,QAA4B,EAAE,MAAM,MAAM,aAAa,OAAO,iBAAiB;AACrF,UAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAM,OAAM,OAAO,OAAO;AACxE,UAAI,OAAO,OAAO,YAAY,YAAY,OAAO,QAAS,OAAM,UAAU,OAAO;AACjF,gBAAU,KAAK,KAAK;AAAA,IACtB,QAAQ;AAAA,IAER;AAAA,EACF;AACA,YAAU,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,cAAc,EAAE,WAAW,CAAC;AACnE,SAAO;AACT;AAOO,SAAS,sBAAgD;AAC9D,QAAM,MAAM,YAAY;AACxB,MAAI,CAACD,YAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,MAAI;AACJ,MAAI;AACF,cAAUK,aAAY,GAAG;AAAA,EAC3B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,MAAgC,CAAC;AACvC,QAAM,SAAS;AACf,QAAM,aAAa;AACnB,aAAW,QAAQ,SAAS;AAC1B,QAAI,CAAC,KAAK,SAAS,MAAM,EAAG;AAC5B,UAAM,UAAU,KAAK,QAAQ,UAAU;AACvC,QAAI,UAAU,EAAG;AACjB,UAAM,cAAc,KAAK,MAAM,GAAG,OAAO;AACzC,QAAI,CAAC,YAAa;AAClB,UAAM,OAAON,MAAK,KAAK,IAAI;AAC3B,QAAI;AACF,YAAM,MAAME,cAAa,MAAM,MAAM;AACrC,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,UAAI,OAAO,YAAY,EAAG;AAC1B,UAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM,WAAW,EAAG;AAC/D,YAAM,QAAQ,OAAO,MAAM;AAAA,QACzB,CAAC,MACC,CAAC,CAAC,KACF,OAAO,MAAM,YACb,OAAQ,EAAe,OAAO,YAC9B,OAAQ,EAAe,UAAU,YACjC,OAAQ,EAAe,WAAW;AAAA,MACtC;AACA,UAAI,MAAM,WAAW,EAAG;AACxB,YAAM,mBAAmB,MAAM,QAAQ,OAAO,gBAAgB,IAC1D,OAAO,iBAAiB,OAAO,CAAC,OAAqB,OAAO,OAAO,YAAY,CAAC,CAAC,EAAE,IACnF,CAAC;AACL,UAAI,cAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAC5E,UAAI,CAAC,eAAe,OAAO,MAAM,KAAK,MAAM,WAAW,CAAC,GAAG;AACzD,YAAI;AACF,wBAAc,SAAS,IAAI,EAAE,MAAM,YAAY;AAAA,QACjD,QAAQ;AACN,yBAAc,oBAAI,KAAK,CAAC,GAAE,YAAY;AAAA,QACxC;AAAA,MACF;AACA,YAAM,QAAgC;AAAA,QACpC;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,UAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAM,OAAM,OAAO,OAAO;AACxE,UAAI,OAAO,OAAO,YAAY,YAAY,OAAO,QAAS,OAAM,UAAU,OAAO;AACjF,UAAI,KAAK,KAAK;AAAA,IAChB,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,cAAc,EAAE,WAAW,CAAC;AAC7D,SAAO;AACT;AAGO,SAAS,aAAa,WAAmB,MAAc,KAAK,IAAI,GAAW;AAChF,QAAM,IAAI,KAAK,MAAM,SAAS;AAC9B,MAAI,OAAO,MAAM,CAAC,EAAG,QAAO;AAC5B,QAAM,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;AAClC,QAAM,MAAM,KAAK,MAAM,SAAS,GAAI;AACpC,MAAI,MAAM,GAAI,QAAO,GAAG,GAAG;AAC3B,QAAM,MAAM,KAAK,MAAM,MAAM,EAAE;AAC/B,MAAI,MAAM,GAAI,QAAO,GAAG,GAAG;AAC3B,QAAM,KAAK,KAAK,MAAM,MAAM,EAAE;AAC9B,MAAI,KAAK,GAAI,QAAO,GAAG,EAAE;AACzB,QAAM,MAAM,KAAK,MAAM,KAAK,EAAE;AAC9B,MAAI,MAAM,EAAG,QAAO,GAAG,GAAG;AAC1B,SAAO,UAAU,MAAM,GAAG,EAAE;AAC9B;;;AClRO,IAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAaA,IAAM,mBAAmB,IAAI;AAAA,EAC3B,kBAAkB,IAAI,CAAC,OAAO,UAAU,CAAC,OAAO,KAAK,CAAC;AACxD;AAEO,SAAS,0BACd,UACK;AACL,SAAO,SACJ,IAAI,CAAC,SAAS,WAAW,EAAE,SAAS,MAAM,EAAE,EAC5C,KAAK,CAAC,GAAG,MAAM;AACd,UAAM,YACJ,iBAAiB,IAAI,EAAE,QAAQ,KAAK,IAAK,iBAAiB,IAAI,EAAE,QAAQ,KAAK;AAC/E,QAAI,cAAc,EAAG,QAAO;AAC5B,WAAO,EAAE,QAAQ,EAAE;AAAA,EACrB,CAAC,EACA,IAAI,CAAC,UAAU,MAAM,OAAO;AACjC;AAEO,IAAM,iBAA8C;AAAA,EACzD,EAAE,KAAK,QAAQ,OAAO,QAAQ,SAAS,mCAAmC,SAAS,CAAC,GAAG,EAAE;AAAA,EACzF;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,IACT,SAAS,CAAC,SAAS,OAAO;AAAA,EAC5B;AAAA,EACA,EAAE,KAAK,SAAS,OAAO,QAAQ,SAAS,qDAAqD;AAAA,EAC7F;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SACE;AAAA,EACJ;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,EACJ;AAAA,EAEA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc,CAAC,QAAQ,SAAS,KAAK;AAAA,EACvC;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc,CAAC,MAAM,OAAO;AAAA,IAC5B,SAAS,CAAC,MAAM;AAAA,EAClB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,EAAE,KAAK,UAAU,OAAO,QAAQ,SAAS,yCAAyC;AAAA,EAClF;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,EACJ;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SACE;AAAA,EACJ;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EAEA,EAAE,KAAK,YAAY,OAAO,WAAW,SAAS,mDAA8C;AAAA,EAC5F;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,IACT,SAAS,CAAC,SAAS;AAAA,EACrB;AAAA,EAEA,EAAE,KAAK,OAAO,OAAO,UAAU,SAAS,oDAAoD;AAAA,EAC5F;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UACE;AAAA,IACF,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc,CAAC,WAAW,UAAU,YAAY;AAAA,EAClD;AAAA,EAEA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,YAAY;AAAA,IACZ,cAAc,CAAC,OAAO;AAAA,EACxB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SACE;AAAA,IACF,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,YAAY;AAAA,IACZ,cAAc,CAAC,UAAU,QAAQ,MAAM;AAAA,EACzC;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,cAAc,CAAC,MAAM,KAAK;AAAA,EAC5B;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,YAAY;AAAA,IACZ,cAAc,CAAC,QAAQ,QAAQ;AAAA,EACjC;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,YAAY;AAAA,IACZ,SAAS,CAAC,SAAS;AAAA,IACnB,cAAc;AAAA,EAChB;AAAA,EAEA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AAAA,EAEA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc,CAAC,KAAK;AAAA,EACtB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,cAAc,CAAC,OAAO,KAAK,KAAK,MAAM,MAAM,IAAI;AAAA,EAClD;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,cAAc,CAAC,UAAU,WAAW,QAAQ;AAAA,IAC5C,SAAS,CAAC,IAAI;AAAA,EAChB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SACE;AAAA,IACF,cAAc,CAAC,QAAQ,OAAO,UAAU,OAAO;AAAA,EACjD;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc,CAAC,MAAM;AAAA,EACvB;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,EAAE,KAAK,QAAQ,OAAO,YAAY,SAAS,gBAAgB,SAAS,CAAC,QAAQ,GAAG,EAAE;AACpF;AAEO,SAAS,qBACd,QACA,WAAW,OACX,QACoB;AACpB,QAAM,IAAI,OAAO,YAAY;AAC7B,QAAM,UAAU,eAAe,OAAO,CAAC,MAAM;AAG3C,QAAI,MAAM,GAAI,QAAO,EAAE,UAAU;AACjC,QAAI,EAAE,eAAe,UAAU,CAAC,SAAU,QAAO;AACjD,QAAI,EAAE,IAAI,WAAW,CAAC,EAAG,QAAO;AAChC,WAAO,EAAE,SAAS,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK;AAAA,EACpD,CAAC;AACD,MAAI,MAAM,GAAI,QAAO,0BAA0B,OAAO;AACtD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,UAAU,IAAI,IAAI,QAAQ,IAAI,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACzD,SAAO,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM;AACjC,UAAM,QAAQ,OAAO,EAAE,GAAG,KAAK,MAAM,OAAO,EAAE,GAAG,KAAK;AACtD,QAAI,SAAS,EAAG,QAAO;AACvB,YAAQ,QAAQ,IAAI,EAAE,GAAG,KAAK,MAAM,QAAQ,IAAI,EAAE,GAAG,KAAK;AAAA,EAC5D,CAAC;AACH;AAEO,SAAS,sBAAsB,UAA2B;AAC/D,SAAO,eAAe;AAAA,IACpB,CAAC,MAAM,EAAE,UAAU,eAAe,EAAE,eAAe,UAAU;AAAA,EAC/D,EAAE;AACJ;AAGA,IAAM,gBAAkD,MAAM;AAC5D,QAAM,IAA4B,CAAC;AACnC,aAAW,QAAQ,gBAAgB;AACjC,QAAI,CAAC,KAAK,QAAS;AACnB,eAAW,KAAK,KAAK,QAAS,GAAE,CAAC,IAAI,KAAK;AAAA,EAC5C;AACA,SAAO;AACT,GAAG;AAEI,SAAS,kBAAkB,MAAsB;AACtD,SAAO,aAAa,IAAI,KAAK;AAC/B;AAGO,SAAS,sBAAsB,OAAe,WAAW,OAA+B;AAC7F,QAAM,IAAI,sBAAsB,KAAK,KAAK;AAC1C,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,UAAU,kBAAkB,EAAE,CAAC,EAAG,YAAY,CAAC;AACrD,QAAM,OAAO,EAAE,CAAC,KAAK;AACrB,QAAM,OAAO,eAAe;AAAA,IAC1B,CAAC,MAAM,EAAE,QAAQ,YAAY,EAAE,eAAe,UAAU;AAAA,EAC1D;AACA,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,mBAAmB,KAAK,KAAK,IAAI;AACvC,QAAM,gBAAgB,MAAM,SAAS,KAAK;AAC1C,MAAI,kBAAkB;AACpB,WAAO,EAAE,MAAM,SAAS,MAAM,eAAe,MAAM,OAAO;AAAA,EAC5D;AACA,SAAO;AAAA,IACL;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA,MAAM,KAAK,eAAe,WAAW;AAAA,EACvC;AACF;AAEO,SAAS,WAAW,MAAsD;AAC/E,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAClC,QAAM,QAAQ,KAAK,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK;AAC9C,QAAM,MAAM,MAAM,CAAC,GAAG,YAAY,KAAK;AACvC,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,EAAE,KAAK,MAAM,MAAM,MAAM,CAAC,EAAE;AACrC;","names":["existsSync","mkdirSync","readFileSync","readdirSync","writeFileSync","dirname","join","join","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","readdirSync"]}
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-X53B3JIX.js";
8
8
  import {
9
9
  t
10
- } from "./chunk-IJ7JA32V.js";
10
+ } from "./chunk-6VANO7KB.js";
11
11
  import {
12
12
  __toESM
13
13
  } from "./chunk-TUK7OWJA.js";
@@ -51,4 +51,4 @@ function truncate(s, max) {
51
51
  export {
52
52
  RecordView
53
53
  };
54
- //# sourceMappingURL=chunk-HVUZWNSP.js.map
54
+ //# sourceMappingURL=chunk-3AAG2CUT.js.map
@@ -3,7 +3,7 @@ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.requi
3
3
  import {
4
4
  loadLanguage,
5
5
  saveLanguage
6
- } from "./chunk-AVFXO2EZ.js";
6
+ } from "./chunk-DGA5QYFM.js";
7
7
 
8
8
  // src/i18n/EN.ts
9
9
  var EN = {
@@ -313,7 +313,7 @@ var EN = {
313
313
  },
314
314
  cwd: {
315
315
  description: "switch the workspace root mid-session \u2014 re-points fs / shell / memory tools, reloads project hooks, refreshes the at-mention walker",
316
- argsHint: "<path>"
316
+ argsHint: "[path]"
317
317
  },
318
318
  stop: { description: "abort the current model turn (typed alternative to Esc)" },
319
319
  feedback: { description: "open a GitHub issue with diagnostic info copied to clipboard" },
@@ -567,6 +567,10 @@ var EN = {
567
567
  sessionTitleRenameFailed: '\u25B8 could not rename the session for title "{title}".',
568
568
  sessionTitleRenamed: '\u25B8 session renamed to "{name}" \u2014 {title}',
569
569
  sessionTitleAutoRenamed: '\u25B8 auto-named session "{name}" \u2014 {title}',
570
+ workspaceSwitched: "\u25B8 workspace switched to {root}",
571
+ semanticRepointed: "\u25B8 semantic_search re-pointed at {root}",
572
+ semanticDisabledForRoot: "\u25B8 semantic_search disabled (no compatible index in {root})",
573
+ semanticRebootstrapFailed: "\u25B8 semantic_search re-bootstrap failed: {reason}",
570
574
  denied: "\u25B8 denied: {cmd}{context}",
571
575
  alwaysAllowed: '\u25B8 always allowed "{prefix}" for {dir}',
572
576
  runningCommand: "\u25B8 running: {cmd}",
@@ -603,7 +607,6 @@ var EN = {
603
607
  preflightNoFold: "preflight: request ~{estimate}/{ctxMax} tokens ({pct}%) and nothing left to truncate \u2014 DeepSeek will likely 400. Run /clear or /new to start fresh.",
604
608
  flashEscalation: "\u21E7 flash requested escalation \u2014 retrying this turn on {model}{reasonSuffix}",
605
609
  harvestStatus: "extracting plan state from reasoning\u2026",
606
- autoEscalation: "\u21E7 auto-escalating to {model} for the rest of this turn \u2014 flash hit {breakdown}. Next turn falls back to {fallback} unless /pro is armed.",
607
610
  repeatToolCallWarning: "Caught a repeated tool call \u2014 let the model see the issue and retry with a different approach.",
608
611
  stormStuck: "Stopped a stuck retry loop \u2014 the model kept calling the same tool with identical args after a self-correction nudge. Try /retry, rephrase, or rule out the underlying blocker.",
609
612
  stormSuppressed: "Suppressed {count} repeated tool call(s) \u2014 same name + args fired 3+ times.",
@@ -1094,11 +1097,14 @@ var EN = {
1094
1097
  messages: "{count} message",
1095
1098
  messagesPlural: "{count} messages",
1096
1099
  turns: "{count} turns",
1097
- pickerHint: "\u2191\u2193 pick \xB7 \u23CE open \xB7 [n] new \xB7 [d] delete \xB7 [r] rename \xB7 esc quit",
1100
+ pickerHint: "\u2191\u2193 pick \xB7 / search \xB7 \u23CE open \xB7 [n] new \xB7 [d] delete \xB7 [r] rename \xB7 esc quit",
1098
1101
  empty: " no saved sessions in this workspace yet \u2014 press ",
1099
1102
  emptyNew: " to start a new one",
1100
1103
  renamePrompt: ' rename "{from}" \u2192 ',
1101
1104
  renameHint: " \u23CE confirm rename \xB7 esc cancel",
1105
+ searchPrompt: " search sessions: /",
1106
+ searchHint: " type to filter \xB7 \u23CE open match \xB7 esc clear",
1107
+ searchEmpty: " no sessions match this search",
1102
1108
  emptyHint: " \u23CE new session \xB7 esc quit",
1103
1109
  justNow: "just now",
1104
1110
  minAgo: "{count} min ago",
@@ -1106,6 +1112,18 @@ var EN = {
1106
1112
  hoursAgo: "{count}h ago",
1107
1113
  daysAgo: "{count} days ago"
1108
1114
  },
1115
+ workspacePicker: {
1116
+ header: " \u25C8 REASONIX \xB7 pick a workspace ",
1117
+ title: "pick a workspace \u2014 {workspace}",
1118
+ sessions: "{count} session",
1119
+ sessionsPlural: "{count} sessions",
1120
+ current: "current",
1121
+ pickerHint: "\u2191\u2193 pick \xB7 / search \xB7 \u23CE switch + pick session \xB7 esc quit \xB7 /cwd <path> adds one",
1122
+ empty: " no known workspaces yet \u2014 run /cwd <path> once to add one",
1123
+ searchPrompt: " search workspaces: /",
1124
+ searchHint: " type to filter \xB7 \u23CE switch + pick session \xB7 esc clear",
1125
+ searchEmpty: " no workspaces match this search"
1126
+ },
1109
1127
  modelPicker: {
1110
1128
  header: " \u25C8 REASONIX \xB7 pick a setup ",
1111
1129
  loading: " \xB7 loading catalog\u2026",
@@ -1739,7 +1757,7 @@ var zhCN = {
1739
1757
  keys: { description: "\u952E\u76D8 + \u9F20\u6807 + \u590D\u5236\u7C98\u8D34\u53C2\u8003" },
1740
1758
  cwd: {
1741
1759
  description: "\u5207\u6362\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55 \u2014 \u91CD\u65B0\u6307\u5411\u6587\u4EF6/Shell/\u8BB0\u5FC6\u5DE5\u5177\uFF0C\u91CD\u8F7D\u9879\u76EE hooks\uFF0C\u5237\u65B0 @ \u5F15\u7528\u904D\u5386\u5668",
1742
- argsHint: "<path>"
1760
+ argsHint: "[path]"
1743
1761
  },
1744
1762
  stop: { description: "\u4E2D\u6B62\u5F53\u524D\u6A21\u578B\u56DE\u5408\uFF08\u6309 Esc \u7684\u66FF\u4EE3\u65B9\u5F0F\uFF09" },
1745
1763
  feedback: { description: "\u6253\u5F00 GitHub Issue\uFF0C\u8BCA\u65AD\u4FE1\u606F\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F" },
@@ -1994,6 +2012,10 @@ var zhCN = {
1994
2012
  sessionTitleRenameFailed: '\u25B8 \u65E0\u6CD5\u6309\u6807\u9898 "{title}" \u91CD\u547D\u540D\u4F1A\u8BDD\u3002',
1995
2013
  sessionTitleRenamed: '\u25B8 \u4F1A\u8BDD\u5DF2\u91CD\u547D\u540D\u4E3A "{name}" \u2014 {title}',
1996
2014
  sessionTitleAutoRenamed: '\u25B8 \u5DF2\u81EA\u52A8\u547D\u540D\u4F1A\u8BDD "{name}" \u2014 {title}',
2015
+ workspaceSwitched: "\u25B8 \u5DE5\u4F5C\u533A\u5DF2\u5207\u6362\u5230 {root}",
2016
+ semanticRepointed: "\u25B8 semantic_search \u5DF2\u6307\u5411 {root}",
2017
+ semanticDisabledForRoot: "\u25B8 semantic_search \u5DF2\u7981\u7528\uFF08{root} \u6CA1\u6709\u517C\u5BB9\u7D22\u5F15\uFF09",
2018
+ semanticRebootstrapFailed: "\u25B8 semantic_search \u91CD\u65B0\u521D\u59CB\u5316\u5931\u8D25\uFF1A{reason}",
1997
2019
  denied: "\u25B8 \u5DF2\u62D2\u7EDD\uFF1A{cmd}{context}",
1998
2020
  alwaysAllowed: '\u25B8 \u5DF2\u5BF9 {dir} \u6C38\u4E45\u5141\u8BB8 "{prefix}"',
1999
2021
  runningCommand: "\u25B8 \u6B63\u5728\u6267\u884C\uFF1A{cmd}",
@@ -2030,7 +2052,6 @@ var zhCN = {
2030
2052
  preflightNoFold: "\u9884\u68C0\uFF1A\u8BF7\u6C42\u7EA6 {estimate}/{ctxMax} tokens\uFF08{pct}%\uFF09\u4E14\u6CA1\u6709\u53EF\u88C1\u526A\u7684\u5185\u5BB9 \u2014 DeepSeek \u5927\u6982\u7387\u4F1A\u8FD4\u56DE 400\u3002\u8BF7\u8FD0\u884C /clear \u6216 /new \u91CD\u65B0\u5F00\u59CB\u3002",
2031
2053
  flashEscalation: "\u21E7 flash \u8BF7\u6C42\u5347\u7EA7 \u2014 \u672C\u8F6E\u6539\u7528 {model}{reasonSuffix}",
2032
2054
  harvestStatus: "\u6B63\u5728\u4ECE\u63A8\u7406\u8FC7\u7A0B\u63D0\u53D6\u8BA1\u5212\u72B6\u6001\u2026",
2033
- autoEscalation: "\u21E7 \u672C\u8F6E\u5269\u4F59\u8C03\u7528\u81EA\u52A8\u5347\u7EA7\u5230 {model} \u2014 flash \u547D\u4E2D {breakdown}\u3002\u4E0B\u4E00\u8F6E\u56DE\u9000\u5230 {fallback}\uFF0C\u9664\u975E\u5DF2\u88C5\u5907 /pro\u3002",
2034
2055
  repeatToolCallWarning: "\u62E6\u622A\u5230\u91CD\u590D\u5DE5\u5177\u8C03\u7528 \u2014 \u8BA9\u6A21\u578B\u5BDF\u89C9\u95EE\u9898\u5E76\u6362\u79CD\u65B9\u5F0F\u91CD\u8BD5\u3002",
2035
2056
  stormStuck: "\u5DF2\u505C\u6B62\u5361\u6B7B\u7684\u91CD\u8BD5\u5FAA\u73AF \u2014 \u6A21\u578B\u5728\u81EA\u7EA0\u63D0\u793A\u540E\u4ECD\u4EE5\u76F8\u540C\u53C2\u6570\u91CD\u590D\u8C03\u7528\u540C\u4E00\u5DE5\u5177\u3002\u8BF7\u5C1D\u8BD5 /retry\u3001\u6362\u79CD\u8BF4\u6CD5\uFF0C\u6216\u6392\u67E5\u5E95\u5C42\u963B\u585E\u3002",
2036
2057
  stormSuppressed: "\u5DF2\u6291\u5236 {count} \u6B21\u91CD\u590D\u5DE5\u5177\u8C03\u7528 \u2014 \u540C\u4E00\u540D\u79F0 + \u53C2\u6570\u89E6\u53D1 3 \u6B21\u4EE5\u4E0A\u3002",
@@ -2521,11 +2542,14 @@ var zhCN = {
2521
2542
  messages: "{count} \u6761\u6D88\u606F",
2522
2543
  messagesPlural: "{count} \u6761\u6D88\u606F",
2523
2544
  turns: "{count} \u8F6E",
2524
- pickerHint: "\u2191\u2193 \u9009\u62E9 \xB7 \u23CE \u6253\u5F00 \xB7 [n] \u65B0\u5EFA \xB7 [d] \u5220\u9664 \xB7 [r] \u91CD\u547D\u540D \xB7 Esc \u9000\u51FA",
2545
+ pickerHint: "\u2191\u2193 \u9009\u62E9 \xB7 / \u641C\u7D22 \xB7 \u23CE \u6253\u5F00 \xB7 [n] \u65B0\u5EFA \xB7 [d] \u5220\u9664 \xB7 [r] \u91CD\u547D\u540D \xB7 Esc \u9000\u51FA",
2525
2546
  empty: " \u6B64\u5DE5\u4F5C\u533A\u6682\u65E0\u5DF2\u4FDD\u5B58\u7684\u4F1A\u8BDD \u2014 \u6309 ",
2526
2547
  emptyNew: " \u5F00\u59CB\u65B0\u4F1A\u8BDD",
2527
2548
  renamePrompt: ' \u91CD\u547D\u540D "{from}" \u2192 ',
2528
2549
  renameHint: " \u23CE \u786E\u8BA4\u91CD\u547D\u540D \xB7 Esc \u53D6\u6D88",
2550
+ searchPrompt: " \u641C\u7D22\u4F1A\u8BDD\uFF1A/",
2551
+ searchHint: " \u8F93\u5165\u8FC7\u6EE4 \xB7 \u23CE \u6253\u5F00\u5339\u914D\u9879 \xB7 Esc \u6E05\u9664",
2552
+ searchEmpty: " \u6CA1\u6709\u5339\u914D\u7684\u4F1A\u8BDD",
2529
2553
  emptyHint: " \u23CE \u65B0\u5EFA\u4F1A\u8BDD \xB7 Esc \u9000\u51FA",
2530
2554
  justNow: "\u521A\u521A",
2531
2555
  minAgo: "{count} \u5206\u949F\u524D",
@@ -2533,6 +2557,18 @@ var zhCN = {
2533
2557
  hoursAgo: "{count} \u5C0F\u65F6\u524D",
2534
2558
  daysAgo: "{count} \u5929\u524D"
2535
2559
  },
2560
+ workspacePicker: {
2561
+ header: " \u25C8 REASONIX \xB7 \u9009\u62E9\u5DE5\u4F5C\u533A ",
2562
+ title: "\u9009\u62E9\u5DE5\u4F5C\u533A \u2014 {workspace}",
2563
+ sessions: "{count} \u4E2A\u4F1A\u8BDD",
2564
+ sessionsPlural: "{count} \u4E2A\u4F1A\u8BDD",
2565
+ current: "\u5F53\u524D",
2566
+ pickerHint: "\u2191\u2193 \u9009\u62E9 \xB7 / \u641C\u7D22 \xB7 \u23CE \u5207\u6362\u5E76\u9009\u62E9\u4F1A\u8BDD \xB7 Esc \u9000\u51FA \xB7 /cwd <path> \u6DFB\u52A0",
2567
+ empty: " \u6682\u65E0\u5DF2\u77E5\u5DE5\u4F5C\u533A \u2014 \u5148\u8FD0\u884C\u4E00\u6B21 /cwd <path> \u6DFB\u52A0",
2568
+ searchPrompt: " \u641C\u7D22\u5DE5\u4F5C\u533A\uFF1A/",
2569
+ searchHint: " \u8F93\u5165\u8FC7\u6EE4 \xB7 \u23CE \u5207\u6362\u5E76\u9009\u62E9\u4F1A\u8BDD \xB7 Esc \u6E05\u9664",
2570
+ searchEmpty: " \u6CA1\u6709\u5339\u914D\u7684\u5DE5\u4F5C\u533A"
2571
+ },
2536
2572
  modelPicker: {
2537
2573
  header: " \u25C8 REASONIX \xB7 \u9009\u62E9\u914D\u7F6E ",
2538
2574
  loading: " \xB7 \u52A0\u8F7D\u76EE\u5F55\u2026",
@@ -2945,4 +2981,4 @@ export {
2945
2981
  tObj,
2946
2982
  t
2947
2983
  };
2948
- //# sourceMappingURL=chunk-IJ7JA32V.js.map
2984
+ //# sourceMappingURL=chunk-6VANO7KB.js.map