@selvakumaresra/specship 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/README.md +2 -2
  2. package/commands/ss-design-implement.md +79 -0
  3. package/commands/{cg-drifted.md → ss-drifted.md} +2 -2
  4. package/commands/{cg-fix.md → ss-fix.md} +1 -1
  5. package/commands/{cg-implement.md → ss-implement.md} +1 -1
  6. package/commands/ss-spec-author.md +43 -0
  7. package/commands/ss-spec-review.md +48 -0
  8. package/dist/bin/specship.js +6 -5
  9. package/dist/bin/specship.js.map +1 -1
  10. package/dist/db/index.d.ts +3 -1
  11. package/dist/db/index.d.ts.map +1 -1
  12. package/dist/db/index.js +5 -2
  13. package/dist/db/index.js.map +1 -1
  14. package/dist/db/migrations.d.ts +1 -1
  15. package/dist/db/migrations.d.ts.map +1 -1
  16. package/dist/db/migrations.js +36 -1
  17. package/dist/db/migrations.js.map +1 -1
  18. package/dist/db/schema.sql +9 -0
  19. package/dist/directory.d.ts +13 -3
  20. package/dist/directory.d.ts.map +1 -1
  21. package/dist/directory.js +17 -3
  22. package/dist/directory.js.map +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/installer/index.d.ts.map +1 -1
  27. package/dist/installer/index.js +16 -10
  28. package/dist/installer/index.js.map +1 -1
  29. package/dist/installer/targets/claude.d.ts +11 -1
  30. package/dist/installer/targets/claude.d.ts.map +1 -1
  31. package/dist/installer/targets/claude.js +59 -2
  32. package/dist/installer/targets/claude.js.map +1 -1
  33. package/dist/server/ingest/ingestor.js +117 -17
  34. package/dist/server/routes/claude.js +394 -6
  35. package/dist/server/routes/graph.js +62 -0
  36. package/dist/server/routes/spec.js +161 -1
  37. package/dist/server/routes/status.js +77 -0
  38. package/dist/server/routes/workflow.js +31 -3
  39. package/dist/web/chunk-2AJCHB7P.js +1 -0
  40. package/dist/web/chunk-2CPLUFCH.js +2 -0
  41. package/dist/web/chunk-2DHIGIOI.js +1 -0
  42. package/dist/web/chunk-2GBEK2GM.js +1 -0
  43. package/dist/web/chunk-2I7L37NS.js +1 -0
  44. package/dist/web/chunk-2NAWAJB5.js +1 -0
  45. package/dist/web/chunk-2OJBIPE4.js +1 -0
  46. package/dist/web/chunk-2OKMB4KX.js +2 -0
  47. package/dist/web/chunk-3E2WB6D5.js +1 -0
  48. package/dist/web/chunk-3EBFYSCH.js +2 -0
  49. package/dist/web/chunk-3QCQ4BXS.js +1 -0
  50. package/dist/web/chunk-3SEJX2BK.js +1 -0
  51. package/dist/web/chunk-42XVAQ6I.js +1 -0
  52. package/dist/web/chunk-4IMMPEYM.js +1 -0
  53. package/dist/web/chunk-4N5DWG46.js +1 -0
  54. package/dist/web/chunk-4TJQJPCZ.js +1 -0
  55. package/dist/web/chunk-4WZIHTPC.js +1 -0
  56. package/dist/web/chunk-4YVSYOSD.js +1 -0
  57. package/dist/web/chunk-5BQIOYKW.js +1 -0
  58. package/dist/web/chunk-5HGWHUJA.js +1 -0
  59. package/dist/web/chunk-5Y244R4G.js +1 -0
  60. package/dist/web/chunk-6RRDPT5Z.js +1 -0
  61. package/dist/web/chunk-6VKB2ZWM.js +1 -0
  62. package/dist/web/chunk-7DMFVTU4.js +1 -0
  63. package/dist/web/chunk-7RNS77UP.js +1 -0
  64. package/dist/web/chunk-7SMPKVEP.js +1 -0
  65. package/dist/web/chunk-AZJVTPLU.js +1 -0
  66. package/dist/web/chunk-BCZM5AXU.js +1 -0
  67. package/dist/web/chunk-BLBRMCN2.js +1 -0
  68. package/dist/web/chunk-BMIAXD2V.js +2 -0
  69. package/dist/web/chunk-BPECIDVO.js +1 -0
  70. package/dist/web/chunk-BUXWEHIY.js +1 -0
  71. package/dist/web/chunk-BYZFQSM6.js +1 -0
  72. package/dist/web/chunk-DA6SNNAF.js +1 -0
  73. package/dist/web/chunk-DLQPZWSI.css +1 -0
  74. package/dist/web/chunk-DTRN7FZR.js +1 -0
  75. package/dist/web/chunk-DYRFLPJA.js +1 -0
  76. package/dist/web/chunk-E3J3CXR5.js +1 -0
  77. package/dist/web/chunk-E44X4RH2.js +1 -0
  78. package/dist/web/chunk-E73OX2P7.js +1 -0
  79. package/dist/web/chunk-EAXRKDLV.js +1 -0
  80. package/dist/web/chunk-EBKKDHYI.js +1 -0
  81. package/dist/web/chunk-EE7V7Q5P.js +1 -0
  82. package/dist/web/chunk-EKY2FUHU.js +1 -0
  83. package/dist/web/chunk-EMGMOEVR.js +1 -0
  84. package/dist/web/chunk-EP6XOPXH.js +1 -0
  85. package/dist/web/chunk-ESGDLJOJ.js +1 -0
  86. package/dist/web/chunk-ETJG7NCY.js +1 -0
  87. package/dist/web/chunk-EUUEFEDI.js +1 -0
  88. package/dist/web/chunk-FGNZDHTL.js +11 -0
  89. package/dist/web/chunk-FIJW2UNJ.js +1 -0
  90. package/dist/web/chunk-FMV5PXRC.js +5 -0
  91. package/dist/web/chunk-G7VZT5KB.js +3 -0
  92. package/dist/web/chunk-GRZYXPSO.js +7 -0
  93. package/dist/web/chunk-GYGPS3AN.js +1 -0
  94. package/dist/web/chunk-H7AF7YS4.js +1 -0
  95. package/dist/web/chunk-HDZDQILN.js +1 -0
  96. package/dist/web/chunk-HMK6UO6N.js +1 -0
  97. package/dist/web/chunk-HZA6NEAB.js +1 -0
  98. package/dist/web/chunk-IHEE5NYJ.js +1 -0
  99. package/dist/web/chunk-ISNEBICW.js +1 -0
  100. package/dist/web/chunk-J2GZVLHH.js +1 -0
  101. package/dist/web/chunk-JFYVCXK3.js +1 -0
  102. package/dist/web/chunk-JN6W7HCN.js +17 -0
  103. package/dist/web/chunk-JT7P3DEK.js +6 -0
  104. package/dist/web/chunk-JTFXTIPE.js +903 -0
  105. package/dist/web/chunk-L37MTFSG.js +3 -0
  106. package/dist/web/chunk-LB6JPLX2.js +1 -0
  107. package/dist/web/chunk-LNSVDHCI.js +1 -0
  108. package/dist/web/chunk-LV4G6QFG.js +2 -0
  109. package/dist/web/chunk-LVGIY3SO.js +1 -0
  110. package/dist/web/chunk-LXLHIHEN.js +1 -0
  111. package/dist/web/chunk-MC4DFIHG.js +1 -0
  112. package/dist/web/chunk-MVOMVPYB.js +1 -0
  113. package/dist/web/chunk-N6SS4G6S.js +1 -0
  114. package/dist/web/chunk-NTBJG6SJ.js +1 -0
  115. package/dist/web/chunk-NUDB3Q2Y.js +3 -0
  116. package/dist/web/chunk-OXEF5E3E.js +1 -0
  117. package/dist/web/chunk-PDN6QYGJ.js +4 -0
  118. package/dist/web/chunk-PGGJPDJG.js +1 -0
  119. package/dist/web/chunk-PUYSJNJR.js +1 -0
  120. package/dist/web/chunk-Q2RVFS45.js +1 -0
  121. package/dist/web/chunk-Q7L6LLAK.js +1 -0
  122. package/dist/web/chunk-QCMKJIWY.js +1 -0
  123. package/dist/web/chunk-QH6CF3M3.js +1 -0
  124. package/dist/web/chunk-QQ5LD7PI.js +1 -0
  125. package/dist/web/chunk-QR6L3KAC.js +1 -0
  126. package/dist/web/chunk-R2DLK4HO.js +1 -0
  127. package/dist/web/chunk-R5W2MDZN.js +1 -0
  128. package/dist/web/chunk-RAAMPHPJ.js +1 -0
  129. package/dist/web/chunk-RD6TVPOT.js +1 -0
  130. package/dist/web/chunk-RKY4EJYJ.js +1 -0
  131. package/dist/web/chunk-RONYWVY7.js +1 -0
  132. package/dist/web/chunk-RXKXYF2C.js +1 -0
  133. package/dist/web/chunk-SBWU7JFC.js +1 -0
  134. package/dist/web/chunk-SEXBRGYK.js +1 -0
  135. package/dist/web/chunk-SHPTC4RL.js +1 -0
  136. package/dist/web/chunk-SUZYBYDW.js +1 -0
  137. package/dist/web/chunk-SWKJRNYY.js +1 -0
  138. package/dist/web/chunk-T66XVKGB.js +1 -0
  139. package/dist/web/chunk-T7AZ65JP.js +1 -0
  140. package/dist/web/chunk-TCZDVOHD.js +1 -0
  141. package/dist/web/chunk-TPTITA3V.js +1 -0
  142. package/dist/web/chunk-TR335633.js +1 -0
  143. package/dist/web/chunk-TWXZK6XM.js +1 -0
  144. package/dist/web/chunk-UR5KDXPX.js +1 -0
  145. package/dist/web/chunk-UR6O2GEH.js +1 -0
  146. package/dist/web/chunk-UTNMGWTP.js +1 -0
  147. package/dist/web/chunk-UYC52MBC.js +1 -0
  148. package/dist/web/chunk-VECWMHJP.js +1 -0
  149. package/dist/web/chunk-VUACT35R.js +3 -0
  150. package/dist/web/chunk-VZI7H4SZ.js +1 -0
  151. package/dist/web/chunk-WAI2JMZP.js +1 -0
  152. package/dist/web/chunk-WB6YHOD4.js +1 -0
  153. package/dist/web/chunk-WBT64AWV.js +1 -0
  154. package/dist/web/chunk-WDU3WICG.js +1 -0
  155. package/dist/web/chunk-WFXJIXZE.js +4 -0
  156. package/dist/web/chunk-WTGYRH3Z.js +298 -0
  157. package/dist/web/chunk-WXTCVDTP.js +1 -0
  158. package/dist/web/chunk-X2HTISHL.js +1 -0
  159. package/dist/web/chunk-XCDHWLVH.js +1 -0
  160. package/dist/web/chunk-Y3H6FFUZ.js +1 -0
  161. package/dist/web/chunk-Y4F5ULGJ.js +1 -0
  162. package/dist/web/chunk-YAWCRPHV.js +1 -0
  163. package/dist/web/chunk-YEGKAAEE.js +1 -0
  164. package/dist/web/chunk-YM2KU57F.js +1 -0
  165. package/dist/web/chunk-YRERBP6T.js +1 -0
  166. package/dist/web/chunk-ZLV4VCDG.js +3 -0
  167. package/dist/web/chunk-ZTVI5KFF.js +1 -0
  168. package/dist/web/index.html +3 -3
  169. package/dist/web/main-ESADRXN2.css +1 -0
  170. package/dist/web/main-WVI3YTDU.js +1 -0
  171. package/dist/web/media/codicon-LN6W7LCM.ttf +0 -0
  172. package/dist/web/styles-KSOPUVDA.css +1 -0
  173. package/dist/workflows/defaults/claude-design-implement.yaml +247 -0
  174. package/dist/workflows/defaults/spec-author.yaml +214 -0
  175. package/dist/workflows/executor.d.ts.map +1 -1
  176. package/dist/workflows/executor.js +4 -3
  177. package/dist/workflows/executor.js.map +1 -1
  178. package/package.json +8 -3
  179. package/scripts/offline-install.sh +19 -6
  180. package/scripts/sync-shim-version.mjs +64 -0
  181. package/dist/web/chunk-2YZXEHZ2.js +0 -1
  182. package/dist/web/chunk-3GIC555L.js +0 -18
  183. package/dist/web/chunk-3IIIGRMT.js +0 -1
  184. package/dist/web/chunk-47QYKLE5.js +0 -1
  185. package/dist/web/chunk-4LHBWWP7.js +0 -1
  186. package/dist/web/chunk-4OAZLD5W.js +0 -1
  187. package/dist/web/chunk-5OQKAJAE.js +0 -1
  188. package/dist/web/chunk-7B525GKQ.js +0 -1
  189. package/dist/web/chunk-BPDXCOOZ.js +0 -1
  190. package/dist/web/chunk-DT37HTZB.js +0 -1
  191. package/dist/web/chunk-EIMUHJND.js +0 -1
  192. package/dist/web/chunk-FTESTUEO.js +0 -1
  193. package/dist/web/chunk-GLJZV6MU.js +0 -1
  194. package/dist/web/chunk-I7LS67U5.js +0 -1
  195. package/dist/web/chunk-L4TVIPSR.js +0 -1
  196. package/dist/web/chunk-MASCULC2.js +0 -1
  197. package/dist/web/chunk-MW7ICSRM.js +0 -1
  198. package/dist/web/chunk-OI5VP2A3.js +0 -1
  199. package/dist/web/chunk-RA6EBF6I.js +0 -1
  200. package/dist/web/chunk-RP3WU5Y6.js +0 -1
  201. package/dist/web/chunk-RQDRMTXN.js +0 -1
  202. package/dist/web/chunk-TQMT6UDU.js +0 -1
  203. package/dist/web/chunk-U7IYOV7T.js +0 -1
  204. package/dist/web/chunk-UE227MWF.js +0 -1
  205. package/dist/web/chunk-WV573J4K.js +0 -1
  206. package/dist/web/chunk-WVCKOJZL.js +0 -4
  207. package/dist/web/chunk-XZKLVPHE.js +0 -1
  208. package/dist/web/chunk-ZABKKHJ3.js +0 -1
  209. package/dist/web/main-RI5CO5Z4.js +0 -1
  210. package/dist/web/styles-CYN7IKT4.css +0 -1
  211. /package/commands/{cg-explore.md → ss-explore.md} +0 -0
  212. /package/commands/{cg-impact.md → ss-impact.md} +0 -0
  213. /package/commands/{cg-relink.md → ss-relink.md} +0 -0
  214. /package/commands/{cg-spec.md → ss-spec.md} +0 -0
  215. /package/commands/{cg-sync.md → ss-sync.md} +0 -0
  216. /package/commands/{cg-trace.md → ss-trace.md} +0 -0
@@ -1,9 +1,42 @@
1
1
  /**
2
2
  * Spec layer routes — list / fetch / link assert / link verify / drift queue.
3
+ * Plus the v0.2 write endpoints: PUT /api/spec/:id and POST /api/specs,
4
+ * which let the dashboard's Monaco editor save spec edits back to disk.
3
5
  *
4
6
  * Every route is project-scoped via `?project=<slug>` (falls back to the
5
7
  * boot-time primary). Returns 409 / `no_project` when neither is selectable.
6
8
  */
9
+ import * as fs from 'node:fs';
10
+ import * as path from 'node:path';
11
+ /**
12
+ * Resolve a project-relative path to an absolute path under the project
13
+ * root, refusing anything that escapes the root (path-traversal guard).
14
+ * Returns null when the resolved path is outside the project — caller
15
+ * surfaces 400 in that case.
16
+ */
17
+ function safeProjectPath(projectRoot, relPath) {
18
+ // Strip leading slashes so absolute paths in user input don't blow past
19
+ // path.resolve's "drop earlier components" behavior.
20
+ const cleaned = relPath.replace(/^[/\\]+/, '');
21
+ const abs = path.resolve(projectRoot, cleaned);
22
+ const rootResolved = path.resolve(projectRoot);
23
+ const rel = path.relative(rootResolved, abs);
24
+ if (rel.startsWith('..') || path.isAbsolute(rel))
25
+ return null;
26
+ return abs;
27
+ }
28
+ /**
29
+ * Atomic file write: tmp + rename. Mirrors `atomicWriteFileSync` in
30
+ * `src/installer/targets/shared.ts` — kept local here to avoid the
31
+ * @selvakumaresra/specship deep-import dance for a 10-line helper.
32
+ */
33
+ function atomicWriteFile(targetPath, content) {
34
+ const dir = path.dirname(targetPath);
35
+ fs.mkdirSync(dir, { recursive: true });
36
+ const tmp = `${targetPath}.tmp.${process.pid}.${Date.now()}`;
37
+ fs.writeFileSync(tmp, content, 'utf-8');
38
+ fs.renameSync(tmp, targetPath);
39
+ }
7
40
  async function resolveCg(app, req, reply) {
8
41
  const cg = await app.activeCg(req);
9
42
  if (!cg) {
@@ -32,7 +65,23 @@ export async function registerSpecRoutes(app) {
32
65
  const children = sq.getSpecsByParent(spec.id);
33
66
  const siblings = parent ? sq.getSpecsByParent(parent.id).filter((s) => s.id !== spec.id) : [];
34
67
  const links = sq.getLinksBySpec(spec.id);
35
- return { spec, parent, siblings, children, links };
68
+ // Read the raw source file so the dashboard's Monaco editor can edit
69
+ // the whole document, not just the DB-parsed body fragment for this
70
+ // requirement. The `spec.body` field stores per-section content; the
71
+ // editor needs the file.
72
+ let source = null;
73
+ try {
74
+ const projectRoot = cg.getProjectRoot();
75
+ const absPath = safeProjectPath(projectRoot, spec.sourcePath);
76
+ if (absPath && fs.existsSync(absPath)) {
77
+ source = fs.readFileSync(absPath, 'utf-8');
78
+ }
79
+ }
80
+ catch {
81
+ // File missing or unreadable — return null so the UI can show a
82
+ // "source not available" hint without failing the whole fetch.
83
+ }
84
+ return { spec, parent, siblings, children, links, source };
36
85
  });
37
86
  app.get('/api/drift', async (req, reply) => {
38
87
  const cg = await resolveCg(app, req, reply);
@@ -102,4 +151,115 @@ export async function registerSpecRoutes(app) {
102
151
  sq.updateSpecLinkState(body.link_id, body.result === 'pass' ? 'verified' : 'broken', null);
103
152
  return { ok: true, state: body.result === 'pass' ? 'verified' : 'broken' };
104
153
  });
154
+ /**
155
+ * PUT /api/spec/:id — overwrite the spec file backing this spec.
156
+ *
157
+ * Resolves the source file path from the existing spec row, validates it's
158
+ * under the project root (path-traversal guard), atomically writes the new
159
+ * content, then re-syncs the project so the indexer picks up the change.
160
+ * Returns the freshly re-parsed spec node. Used by the dashboard's Monaco
161
+ * editor.
162
+ */
163
+ app.put('/api/spec/:id', async (req, reply) => {
164
+ const cg = await resolveCg(app, req, reply);
165
+ if (!cg)
166
+ return;
167
+ const sq = cg.getSpecQueries();
168
+ const spec = sq.getSpecById(req.params.id);
169
+ if (!spec)
170
+ return reply.code(404).send({ error: 'spec not found' });
171
+ const body = req.body;
172
+ if (typeof body?.content !== 'string') {
173
+ return reply.code(400).send({ error: 'content (string) required' });
174
+ }
175
+ const projectRoot = cg.getProjectRoot();
176
+ const absPath = safeProjectPath(projectRoot, spec.sourcePath);
177
+ if (!absPath) {
178
+ return reply.code(400).send({
179
+ error: 'spec.sourcePath resolves outside project root',
180
+ code: 'path_traversal',
181
+ });
182
+ }
183
+ try {
184
+ atomicWriteFile(absPath, body.content);
185
+ }
186
+ catch (e) {
187
+ return reply.code(500).send({
188
+ error: 'failed to write spec file',
189
+ detail: e instanceof Error ? e.message : String(e),
190
+ });
191
+ }
192
+ // Re-index so the freshly-edited spec replaces the old graph nodes.
193
+ // The Markdown extractor will rebuild the doc + REQs + acceptance
194
+ // children, and the link resolver re-runs against the new content
195
+ // hash so drift states transition correctly.
196
+ try {
197
+ await cg.sync();
198
+ }
199
+ catch (e) {
200
+ // Sync errors don't roll back the write — the file is on disk and
201
+ // the next sync will pick it up. Surface so the UI can show a
202
+ // "saved but not yet indexed" hint.
203
+ const updated = sq.getSpecById(req.params.id);
204
+ return {
205
+ ok: true,
206
+ spec: updated ?? spec,
207
+ syncError: e instanceof Error ? e.message : String(e),
208
+ };
209
+ }
210
+ const updated = sq.getSpecById(req.params.id);
211
+ return { ok: true, spec: updated ?? spec };
212
+ });
213
+ /**
214
+ * POST /api/specs — create a new spec file under the project's specs/
215
+ * directory.
216
+ *
217
+ * `filePath` is project-relative (e.g. `specs/billing.md`). 409 if the
218
+ * file already exists. Used by the dashboard's Draft-with-Claude flow
219
+ * for the optional "finalize via dashboard" path.
220
+ */
221
+ app.post('/api/specs', async (req, reply) => {
222
+ const cg = await resolveCg(app, req, reply);
223
+ if (!cg)
224
+ return;
225
+ const body = req.body;
226
+ if (typeof body?.filePath !== 'string' || typeof body?.content !== 'string') {
227
+ return reply.code(400).send({ error: 'filePath and content (strings) required' });
228
+ }
229
+ const projectRoot = cg.getProjectRoot();
230
+ const absPath = safeProjectPath(projectRoot, body.filePath);
231
+ if (!absPath) {
232
+ return reply.code(400).send({
233
+ error: 'filePath resolves outside project root',
234
+ code: 'path_traversal',
235
+ });
236
+ }
237
+ if (fs.existsSync(absPath)) {
238
+ return reply.code(409).send({
239
+ error: 'file already exists',
240
+ code: 'file_exists',
241
+ filePath: body.filePath,
242
+ });
243
+ }
244
+ try {
245
+ atomicWriteFile(absPath, body.content);
246
+ }
247
+ catch (e) {
248
+ return reply.code(500).send({
249
+ error: 'failed to write spec file',
250
+ detail: e instanceof Error ? e.message : String(e),
251
+ });
252
+ }
253
+ try {
254
+ await cg.sync();
255
+ }
256
+ catch (e) {
257
+ return {
258
+ ok: true,
259
+ filePath: body.filePath,
260
+ syncError: e instanceof Error ? e.message : String(e),
261
+ };
262
+ }
263
+ return { ok: true, filePath: body.filePath };
264
+ });
105
265
  }
@@ -2,6 +2,12 @@
2
2
  * GET /api/status — backend, journal mode, node/edge counts, drift count,
3
3
  * last index time. Drives the UI's persistent status strip.
4
4
  *
5
+ * POST /api/refresh — force-sync the SpecShip index AND trigger an
6
+ * immediate Claude Code transcript re-ingest. Wired to the global
7
+ * refresh button in the dashboard's status strip so users can pull
8
+ * Sessions / Heatmap / Costs / Memory current without waiting on the
9
+ * watcher's debounce.
10
+ *
5
11
  * Project-scoped: accepts `?project=<slug>` and serves the matching
6
12
  * SpecShip instance from the registry. When no project is selectable
7
13
  * (no `?project=`, no primary), returns a 409 with `code: 'no_project'`
@@ -32,4 +38,75 @@ export async function registerStatusRoutes(app) {
32
38
  dbSizeBytes: stats.dbSizeBytes,
33
39
  };
34
40
  });
41
+ /**
42
+ * Force a synchronous re-sync of the project's SpecShip index AND a
43
+ * fresh Claude Code transcript ingest pass. The status strip's
44
+ * refresh button calls this so users can pull every project-scoped
45
+ * surface (Sessions, Heatmap, Costs, Memory, Drift, Graph) to
46
+ * current without waiting on the JSONL watcher's debounce window or
47
+ * the next file-watcher tick.
48
+ *
49
+ * Returns the same shape as GET /api/status (so the UI can update
50
+ * its strip and `lastIndexed` label in one round-trip) plus the
51
+ * ingest stats for surfaces interested in "how many new sessions
52
+ * landed."
53
+ *
54
+ * Both steps run sequentially. Errors in either are surfaced under
55
+ * `syncError` / `ingestError` so a transient ingest hiccup doesn't
56
+ * mask a successful index sync (or vice versa) — and the UI can
57
+ * decide whether to retry or surface the failure.
58
+ */
59
+ app.post('/api/refresh', async (req, reply) => {
60
+ const cg = await app.activeCg(req);
61
+ if (!cg) {
62
+ return reply.code(409).send({ error: 'no project selected', code: 'no_project' });
63
+ }
64
+ let syncError = null;
65
+ let ingestError = null;
66
+ let ingestStats = null;
67
+ // 1. Re-index the project. Picks up code AND specs/ changes the
68
+ // auto-sync hook may not have caught yet.
69
+ try {
70
+ await cg.sync();
71
+ }
72
+ catch (e) {
73
+ syncError = e instanceof Error ? e.message : String(e);
74
+ }
75
+ // 2. Re-ingest Claude Code transcripts. Skipped silently when the
76
+ // server was booted with `--no-ingest` (app.watcher == null).
77
+ if (app.watcher) {
78
+ try {
79
+ ingestStats = await app.watcher.ingestNow();
80
+ }
81
+ catch (e) {
82
+ ingestError = e instanceof Error ? e.message : String(e);
83
+ }
84
+ }
85
+ // 3. Echo the new status so the UI updates its strip + lastIndexed
86
+ // label without a separate GET.
87
+ const stats = cg.getStats();
88
+ const lastIndexed = cg.getLastIndexedAt();
89
+ const drift = cg
90
+ .getSpecQueries()
91
+ .getLinksByState(['drifted', 'broken', 'orphaned']).length;
92
+ return {
93
+ ok: syncError === null && ingestError === null,
94
+ syncError,
95
+ ingestError,
96
+ ingestStats,
97
+ status: {
98
+ projectPath: cg.getProjectRoot ? cg.getProjectRoot() : '',
99
+ backend: cg.getBackend(),
100
+ journalMode: cg.getJournalMode(),
101
+ nodeCount: stats.nodeCount,
102
+ edgeCount: stats.edgeCount,
103
+ fileCount: stats.fileCount,
104
+ drift,
105
+ lastIndexed: lastIndexed != null ? new Date(lastIndexed).toISOString() : null,
106
+ nodesByKind: stats.nodesByKind,
107
+ filesByLanguage: stats.filesByLanguage,
108
+ dbSizeBytes: stats.dbSizeBytes,
109
+ },
110
+ };
111
+ });
35
112
  }
@@ -13,6 +13,9 @@
13
13
  * (polling 500ms). For v1 polling the same SQLite the executor writes to is
14
14
  * faster + more reliable than wiring an in-process event bus across packages.
15
15
  */
16
+ import path from 'node:path';
17
+ import { existsSync } from 'node:fs';
18
+ import { fileURLToPath, pathToFileURL } from 'node:url';
16
19
  async function resolveCg(app, req, reply) {
17
20
  const cg = await app.activeCg(req);
18
21
  if (!cg) {
@@ -24,9 +27,34 @@ async function resolveCg(app, req, reply) {
24
27
  export async function registerWorkflowRoutes(app) {
25
28
  // Lazy import — keeps the server bootable even if the workflow engine
26
29
  // is disabled in the current build profile.
27
- const { discoverWorkflows, loadWorkflowByName } = await import('@selvakumaresra/specship/dist/workflows/discovery.js');
28
- const { WorkflowExecutor } = await import('@selvakumaresra/specship/dist/workflows/executor.js');
29
- const { WorktreeProvider } = await import('@selvakumaresra/specship/dist/isolation/worktree.js');
30
+ //
31
+ // Two delivery shapes (same pattern as loadSpecShip() in ../server.ts):
32
+ // 1. **Bundled** `dist/server/routes/workflow.js` sits two levels under
33
+ // `dist/`, so the core workflow modules live at `../../workflows/*.js`
34
+ // and `../../isolation/*.js`. We try this relative path first because
35
+ // the bundled tarball stages the specship core without a resolvable
36
+ // `@selvakumaresra/specship` package on Node's module graph (offline
37
+ // installs hit this — see scripts/offline-install.sh).
38
+ // 2. **Workspace / dev** — the `file:../..` workspace dep resolves the
39
+ // named import via Node's normal package resolution.
40
+ let discovery;
41
+ let executorMod;
42
+ let worktreeMod;
43
+ const here = path.dirname(fileURLToPath(import.meta.url));
44
+ const bundledDiscovery = path.resolve(here, '..', '..', 'workflows', 'discovery.js');
45
+ if (existsSync(bundledDiscovery)) {
46
+ discovery = await import(pathToFileURL(bundledDiscovery).href);
47
+ executorMod = await import(pathToFileURL(path.resolve(here, '..', '..', 'workflows', 'executor.js')).href);
48
+ worktreeMod = await import(pathToFileURL(path.resolve(here, '..', '..', 'isolation', 'worktree.js')).href);
49
+ }
50
+ else {
51
+ discovery = await import('@selvakumaresra/specship/dist/workflows/discovery.js');
52
+ executorMod = await import('@selvakumaresra/specship/dist/workflows/executor.js');
53
+ worktreeMod = await import('@selvakumaresra/specship/dist/isolation/worktree.js');
54
+ }
55
+ const { discoverWorkflows, loadWorkflowByName } = discovery;
56
+ const { WorkflowExecutor } = executorMod;
57
+ const { WorktreeProvider } = worktreeMod;
30
58
  const executorCache = new WeakMap();
31
59
  /** Build (or fetch cached) executor + worktree provider for a project. */
32
60
  function executorFor(cg) {
@@ -0,0 +1 @@
1
+ import"./chunk-Q7L6LLAK.js";var e={comments:{lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]},{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]}],folding:{offSide:!0}},t={defaultToken:"",tokenPostfix:".pug",ignoreCase:!0,brackets:[{token:"delimiter.curly",open:"{",close:"}"},{token:"delimiter.array",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"}],keywords:["append","block","case","default","doctype","each","else","extends","for","if","in","include","mixin","typeof","unless","var","when"],tags:["a","abbr","acronym","address","area","article","aside","audio","b","base","basefont","bdi","bdo","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","tracks","tt","u","ul","video","wbr"],symbols:/[\+\-\*\%\&\|\!\=\/\.\,\:]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[[/^(\s*)([a-zA-Z_-][\w-]*)/,{cases:{"$2@tags":{cases:{"@eos":["","tag"],"@default":["",{token:"tag",next:"@tag.$1"}]}},"$2@keywords":["",{token:"keyword.$2"}],"@default":["",""]}}],[/^(\s*)(#[a-zA-Z_-][\w-]*)/,{cases:{"@eos":["","tag.id"],"@default":["",{token:"tag.id",next:"@tag.$1"}]}}],[/^(\s*)(\.[a-zA-Z_-][\w-]*)/,{cases:{"@eos":["","tag.class"],"@default":["",{token:"tag.class",next:"@tag.$1"}]}}],[/^(\s*)(\|.*)$/,""],{include:"@whitespace"},[/[a-zA-Z_$][\w$]*/,{cases:{"@keywords":{token:"keyword.$0"},"@default":""}}],[/[{}()\[\]]/,"@brackets"],[/@symbols/,"delimiter"],[/\d+\.\d+([eE][\-+]?\d+)?/,"number.float"],[/\d+/,"number"],[/"/,"string",'@string."'],[/'/,"string","@string.'"]],tag:[[/(\.)(\s*$)/,[{token:"delimiter",next:"@blockText.$S2."},""]],[/\s+/,{token:"",next:"@simpleText"}],[/#[a-zA-Z_-][\w-]*/,{cases:{"@eos":{token:"tag.id",next:"@pop"},"@default":"tag.id"}}],[/\.[a-zA-Z_-][\w-]*/,{cases:{"@eos":{token:"tag.class",next:"@pop"},"@default":"tag.class"}}],[/\(/,{token:"delimiter.parenthesis",next:"@attributeList"}]],simpleText:[[/[^#]+$/,{token:"",next:"@popall"}],[/[^#]+/,{token:""}],[/(#{)([^}]*)(})/,{cases:{"@eos":["interpolation.delimiter","interpolation",{token:"interpolation.delimiter",next:"@popall"}],"@default":["interpolation.delimiter","interpolation","interpolation.delimiter"]}}],[/#$/,{token:"",next:"@popall"}],[/#/,""]],attributeList:[[/\s+/,""],[/(\w+)(\s*=\s*)("|')/,["attribute.name","delimiter",{token:"attribute.value",next:"@value.$3"}]],[/\w+/,"attribute.name"],[/,/,{cases:{"@eos":{token:"attribute.delimiter",next:"@popall"},"@default":"attribute.delimiter"}}],[/\)$/,{token:"delimiter.parenthesis",next:"@popall"}],[/\)/,{token:"delimiter.parenthesis",next:"@pop"}]],whitespace:[[/^(\s*)(\/\/.*)$/,{token:"comment",next:"@blockText.$1.comment"}],[/[ \t\r\n]+/,""],[/<!--/,{token:"comment",next:"@comment"}]],blockText:[[/^\s+.*$/,{cases:{"($S2\\s+.*$)":{token:"$S3"},"@default":{token:"@rematch",next:"@popall"}}}],[/./,{token:"@rematch",next:"@popall"}]],comment:[[/[^<\-]+/,"comment.content"],[/-->/,{token:"comment",next:"@pop"}],[/<!--/,"comment.content.invalid"],[/[<\-]/,"comment.content"]],string:[[/[^\\"'#]+/,{cases:{"@eos":{token:"string",next:"@popall"},"@default":"string"}}],[/@escapes/,{cases:{"@eos":{token:"string.escape",next:"@popall"},"@default":"string.escape"}}],[/\\./,{cases:{"@eos":{token:"string.escape.invalid",next:"@popall"},"@default":"string.escape.invalid"}}],[/(#{)([^}]*)(})/,["interpolation.delimiter","interpolation","interpolation.delimiter"]],[/#/,"string"],[/["']/,{cases:{"$#==$S2":{token:"string",next:"@pop"},"@default":{token:"string"}}}]],value:[[/[^\\"']+/,{cases:{"@eos":{token:"attribute.value",next:"@popall"},"@default":"attribute.value"}}],[/\\./,{cases:{"@eos":{token:"attribute.value",next:"@popall"},"@default":"attribute.value"}}],[/["']/,{cases:{"$#==$S2":{token:"attribute.value",next:"@pop"},"@default":{token:"attribute.value"}}}]]}};export{e as conf,t as language};
@@ -0,0 +1,2 @@
1
+ import"./chunk-Q7L6LLAK.js";var n=e=>`\\b${e}\\b`,t="[_a-zA-Z]",o="[_a-zA-Z0-9]",i=n(`${t}${o}*`),r=["targetScope","resource","module","param","var","output","for","in","if","existing"],s=["true","false","null"],c="[ \\t\\r\\n]",a="[0-9]+",g={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'"},{open:"'''",close:"'''"}],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:"'",close:"'",notIn:["string","comment"]},{open:"'''",close:"'''",notIn:["string","comment"]}],autoCloseBefore:`:.,=}])'
2
+ `,indentationRules:{increaseIndentPattern:new RegExp("^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$"),decreaseIndentPattern:new RegExp("^((?!.*?\\/\\*).*\\*/)?\\s*[\\}\\]].*$")}},l={defaultToken:"",tokenPostfix:".bicep",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],symbols:/[=><!~?:&|+\-*/^%]+/,keywords:r,namedLiterals:s,escapes:"\\\\(u{[0-9A-Fa-f]+}|n|r|t|\\\\|'|\\${)",tokenizer:{root:[{include:"@expression"},{include:"@whitespace"}],stringVerbatim:[{regex:"(|'|'')[^']",action:{token:"string"}},{regex:"'''",action:{token:"string.quote",next:"@pop"}}],stringLiteral:[{regex:"\\${",action:{token:"delimiter.bracket",next:"@bracketCounting"}},{regex:"[^\\\\'$]+",action:{token:"string"}},{regex:"@escapes",action:{token:"string.escape"}},{regex:"\\\\.",action:{token:"string.escape.invalid"}},{regex:"'",action:{token:"string",next:"@pop"}}],bracketCounting:[{regex:"{",action:{token:"delimiter.bracket",next:"@bracketCounting"}},{regex:"}",action:{token:"delimiter.bracket",next:"@pop"}},{include:"expression"}],comment:[{regex:"[^\\*]+",action:{token:"comment"}},{regex:"\\*\\/",action:{token:"comment",next:"@pop"}},{regex:"[\\/*]",action:{token:"comment"}}],whitespace:[{regex:c},{regex:"\\/\\*",action:{token:"comment",next:"@comment"}},{regex:"\\/\\/.*$",action:{token:"comment"}}],expression:[{regex:"'''",action:{token:"string.quote",next:"@stringVerbatim"}},{regex:"'",action:{token:"string.quote",next:"@stringLiteral"}},{regex:a,action:{token:"number"}},{regex:i,action:{cases:{"@keywords":{token:"keyword"},"@namedLiterals":{token:"keyword"},"@default":{token:"identifier"}}}}]}};export{g as conf,l as language};
@@ -0,0 +1 @@
1
+ import{a as W}from"./chunk-X2HTISHL.js";import{a as Q}from"./chunk-UYC52MBC.js";import{a as U}from"./chunk-SUZYBYDW.js";import{a as Y,b as G}from"./chunk-4N5DWG46.js";import{d as B}from"./chunk-SHPTC4RL.js";import{a as H}from"./chunk-7RNS77UP.js";import{a as $}from"./chunk-E44X4RH2.js";import{Aa as m,Ea as T,Fa as O,I as c,Ia as S,Ka as C,R,Ta as D,Ua as I,Va as s,W as f,Wa as g,X as E,Xa as h,Za as z,bb as u,cb as F,ea as a,eb as j,gb as L,ib as N,ka as P,lb as w,qa as M,ra as v,sa as x,ua as k,va as y,vb as A,wa as b,xa as d,ya as r,za as o,zb as J}from"./chunk-PDN6QYGJ.js";import"./chunk-Q7L6LLAK.js";var K=()=>({value:"time",label:"Latest"}),V=()=>({value:"cost",label:"Cost"}),X=()=>({value:"prompts",label:"Prompts"}),Z=(i,e,t)=>[i,e,t],ee=()=>[0,1,2,3,4],te=i=>["/sessions",i],ne=(i,e)=>e.fullId;function ie(i,e){i&1&&(r(0,"span",10),s(1,"\u26A0 refresh failed"),o()),i&2&&d("title",e)}function re(i,e){i&1&&(r(0,"div",20),m(1,"div",21),o())}function oe(i,e){i&1&&y(0,re,2,0,"div",20,k),i&2&&b(u(0,ee))}function se(i,e){i&1&&(r(0,"div",19),s(1," No sessions in this range. Either nothing's been logged yet, or the JSONL ingest watcher hasn't caught up \u2014 click Refresh. "),o())}function ae(i,e){if(i&1&&(r(0,"a",22)(1,"span",23),s(2),o(),r(3,"span",17)(4,"app-pill"),s(5),o()(),r(6,"span",24),s(7),o(),r(8,"span",25),s(9),o(),r(10,"span",25),s(11),L(12,"number"),o(),r(13,"span",26),s(14),o()()),i&2){let t=e.$implicit,n=C(2);d("routerLink",F(15,te,t.fullId)),M("aria-label","Open session "+t.id),a(2),g(t.id),a(3),g(t.project),a(2),z(" ",t.started," \u2013 ",t.ended," \xB7 ",t.model," "),a(2),g(t.prompts),a(),D("color",n.cacheColor(t.cache)),a(),h(" ",N(12,12,t.cache*100,"1.0-0"),"% "),a(3),h(" $",t.cost.toFixed(2)," ")}}function le(i,e){if(i&1&&y(0,ae,15,17,"a",22,ne),i&2){let t=C();b(t.sorted())}}var de=1e4,q=class i{api=c($);projects=c(H);refresh=c(Y);destroyRef=c(R);range=f("all");sort=f("time");ranges=["today","week","month","all"];localRefreshing=f(!1);resource=G(this.api,()=>`/api/claude/sessions?range=${this.range()}&limit=200${this.projects.projectQuery("&")}`);rows=w(()=>(this.resource.state().data?.sessions??[]).map(t=>this.adapt(t)));sorted=w(()=>{let e=this.sort();return[...this.rows()].sort((t,n)=>e==="cost"?n.cost-t.cost:e==="prompts"?n.prompts-t.prompts:n.startedAt-t.startedAt)});constructor(){let e=null,t=()=>{e===null&&(e=setInterval(()=>{typeof document<"u"&&document.visibilityState==="visible"&&this.resource.refetch()},de))},n=()=>{e!==null&&(clearInterval(e),e=null)},l=()=>{typeof document>"u"||document.visibilityState==="visible"&&this.resource.refetch()};t(),typeof document<"u"&&document.addEventListener("visibilitychange",l),this.destroyRef.onDestroy(()=>{n(),typeof document<"u"&&document.removeEventListener("visibilitychange",l)}),E(()=>{!this.resource.state().loading&&this.localRefreshing()&&this.localRefreshing.set(!1)})}async forceRefresh(){this.localRefreshing.set(!0),await this.refresh.triggerGlobalRefresh()}adapt(e){let t=(e.total_input_tokens||0)+(e.total_cache_creation_tokens||0)+(e.total_cache_read_tokens||0);return{id:(e.id||"").slice(0,8),fullId:e.id,project:(e.project_path||"").split("/").filter(Boolean).pop()||"?",startedAt:e.started_at||0,started:this.fmtTime(e.started_at),ended:this.fmtTime(e.ended_at).split(" ").pop()||"",prompts:e.prompt_count||0,cost:e.total_cost_usd||0,cache:t>0?(e.total_cache_read_tokens||0)/t:0,model:e.last_model||"unknown"}}fmtTime(e){if(!e)return"";try{let t=new Date(e),n=new Date;n.setHours(0,0,0,0);let l=864e5,p=n.getTime()-new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime(),_=t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});return p===0?"Today "+_:p===l?"Yest "+_:t.toLocaleDateString([],{month:"short",day:"numeric"})+" "+_}catch{return String(e)}}setSort(e){this.sort.set(e)}setRange(e){this.range.set(e)}cacheColor(e){return e>=.7?"var(--success)":e>=.5?"var(--warn)":"var(--error)"}static \u0275fac=function(t){return new(t||i)};static \u0275cmp=P({type:i,selectors:[["app-sessions"]],decls:35,vars:18,consts:[[1,"page"],[2,"padding","16px 18px 12px"],["icon","sessions","title","Sessions",3,"sub"],["actions",""],["type","button","title","Force refresh: sync the index + re-ingest Claude Code transcripts","aria-label","Refresh sessions",1,"btn","btn-secondary","btn-sm","refresh-btn",3,"click","disabled"],["name","refresh",3,"size"],[1,"filter-bar",2,"padding","0 18px 12px"],["name","filter",2,"color","var(--text-muted)",3,"size"],[1,"input",2,"font-size","12px","padding","4px 8px"],[1,"grow"],[2,"color","var(--warn)","font-size","11.5px","cursor","help",3,"title"],[1,"muted",2,"font-size","11.5px"],["size","sm",3,"change","value","options"],[1,"scroll-y",2,"flex","1","padding","0 18px 18px"],[1,"card",2,"overflow","hidden"],[1,"row",2,"padding","8px 14px","font-size","10.5px","color","var(--text-muted)","text-transform","uppercase","letter-spacing","0.05em","font-weight","600","border-bottom","1px solid var(--border-subtle)"],[2,"width","90px"],[2,"width","110px"],[2,"width","70px","text-align","right"],[2,"padding","28px 18px","text-align","center","color","var(--text-secondary)","font-size","12.5px","line-height","1.5"],[1,"row",2,"padding","10px 14px","border-top","1px solid var(--border-subtle)"],[1,"skel",2,"flex","1","height","18px"],[1,"row","session-row",2,"padding","11px 14px","border-top","1px solid var(--border-subtle)","display","flex","align-items","center","gap","0","text-decoration","none","color","inherit","cursor","pointer",3,"routerLink"],[1,"mono",2,"width","90px","font-size","12px"],[1,"mono","muted","grow",2,"font-size","11.5px","overflow","hidden","text-overflow","ellipsis","white-space","nowrap"],[1,"mono","tabular",2,"width","70px","text-align","right","font-size","12px"],[1,"mono","tabular",2,"width","70px","text-align","right","font-size","12.5px","font-weight","600"]],template:function(t,n){if(t&1&&(r(0,"div",0)(1,"div",1)(2,"app-page-head",2),T(3,3),r(4,"button",4),S("click",function(){return n.forceRefresh()}),m(5,"app-icon",5),s(6),o(),O(),o()(),r(7,"div",6),m(8,"app-icon",7),r(9,"select",8)(10,"option"),s(11,"All models"),o()(),m(12,"div",9),v(13,ie,2,1,"span",10),r(14,"span",11),s(15,"sort"),o(),r(16,"app-segmented",12),S("change",function(p){return n.setSort(p)}),o()(),r(17,"div",13)(18,"div",14)(19,"div",15)(20,"span",16),s(21,"Session"),o(),r(22,"span",17),s(23,"Project"),o(),r(24,"span",9),s(25,"Window"),o(),r(26,"span",18),s(27,"Prompts"),o(),r(28,"span",18),s(29,"Cache"),o(),r(30,"span",18),s(31,"Cost"),o()(),v(32,oe,2,1)(33,se,2,0,"div",19)(34,le,2,0),o()()()),t&2){let l;a(2),d("sub",n.resource.state().loading?"loading\u2026":n.sorted().length+" sessions \xB7 across all projects"),a(2),I("spinning",n.localRefreshing()||n.refresh.loading()),d("disabled",n.refresh.loading()),a(),d("size",13),a(),h(" ",n.localRefreshing()||n.refresh.loading()?"Refreshing\u2026":"Refresh"," "),a(2),d("size",13),a(5),x((l=n.refresh.error())?13:-1,l),a(3),d("value",n.sort())("options",j(14,Z,u(11,K),u(12,V),u(13,X))),a(16),x(n.resource.state().loading&&n.sorted().length===0?32:n.sorted().length===0?33:34)}},dependencies:[B,J,Q,U,W,A],styles:["[_nghost-%COMP%]{display:contents}.page[_ngcontent-%COMP%]{flex:1;display:flex;flex-direction:column;min-height:0}.filter-bar[_ngcontent-%COMP%]{display:flex;align-items:center;gap:8px}.card[_ngcontent-%COMP%]{background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:var(--r-lg)}.row[_ngcontent-%COMP%]{display:flex;align-items:center}.session-row[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.session-row[_ngcontent-%COMP%]:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}.skel[_ngcontent-%COMP%]{background:var(--bg-elevated);border-radius:5px;animation:_ngcontent-%COMP%_skeleton 1.4s ease-in-out infinite}@keyframes _ngcontent-%COMP%_skeleton{0%,to{opacity:.5}50%{opacity:.9}}.refresh-btn[_ngcontent-%COMP%]{display:inline-flex;align-items:center;gap:6px}.refresh-btn.spinning[_ngcontent-%COMP%] app-icon[_ngcontent-%COMP%]{animation:_ngcontent-%COMP%_spin .9s linear infinite;color:var(--accent)}.refresh-btn[_ngcontent-%COMP%]:disabled{cursor:progress;opacity:.8}@keyframes _ngcontent-%COMP%_spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}"],changeDetection:0})};export{q as Sessions};
@@ -0,0 +1 @@
1
+ import{$a as B,Aa as x,Ga as K,Ia as N,Ka as c,M as k,N as M,O as S,P as R,Ra as U,Sa as A,Ta as C,Ua as L,Va as P,W as H,Wa as Y,X as D,Xa as Q,_a as Z,ab as z,ea as s,ka as q,lb as E,ob as j,pb as w,qa as G,qb as J,ra as y,sa as _,ta as W,va as T,wa as V,xa as $,ya as p,za as u,zb as ee}from"./chunk-PDN6QYGJ.js";import{a as O,b as I}from"./chunk-Q7L6LLAK.js";var se=["host"],de=(r,t)=>t.id;function ce(r,t){if(r&1&&(S(),x(0,"path",9)),r&2){let e=c().$implicit,n=c();G("d",t)("stroke",n.edgeStroke(e))("stroke-width",n.edgeStrokeWidth(e))("opacity",n.edgeOpacity(e))("stroke-dasharray",e.kind==="synth"?"5 4":null)("marker-end",n.edgeHot(e)?"url(#gc-arrow-hi)":"url(#gc-arrow)")}}function le(r,t){if(r&1&&y(0,ce,1,6,":svg:path",9),r&2){let e,n=t.$implicit,i=c();_((e=i.edgePath(n))?0:-1,e)}}function pe(r,t){if(r&1&&(p(0,"div",12),P(1),u()),r&2){let e=c(2).$implicit;s(),Y(e.label)}}function ue(r,t){if(r&1&&(x(0,"div",11),y(1,pe,2,1,"div",12)),r&2){let e=c().$implicit,n=z(1),i=z(2),o=c();C("background",n)("transform","scale("+i+")")("box-shadow",o.isSelected(e)?"0 0 0 4px "+n+"44, 0 0 14px "+n:o.isHovered(e)?"0 0 0 3px "+n+"33":"0 0 8px "+n+"66"),s(),_(o.isHovered(e)||o.isSelected(e)?1:-1)}}function me(r,t){if(r&1&&x(0,"span",17),r&2){let e=c(2).$implicit;C("background",e.state==="drifted"?"var(--warn)":"var(--error)")}}function ge(r,t){if(r&1&&(p(0,"div",16),P(1),u()),r&2){let e=c(2).$implicit;s(),Y(e.sub)}}function he(r,t){if(r&1&&(p(0,"div",13),x(1,"span",14),P(2),y(3,me,1,2,"span",15),u(),y(4,ge,2,1,"div",16)),r&2){let e=c().$implicit,n=z(0),i=z(1),o=z(2),a=c();C("min-width",n.w,"px")("transform","scale("+o+")")("transform-origin","center center")("background","color-mix(in srgb, "+i+" 16%, var(--bg-panel))")("border-color",a.isSelected(e)||e.kind==="spec"&&(e.state==="drifted"||e.state==="broken"||e.state==="orphaned")?i:"color-mix(in srgb, "+i+" 45%, transparent)")("box-shadow",a.isSelected(e)?"0 0 0 4px "+i+"33, 0 4px 16px "+i+"44":a.isHovered(e)?"0 0 0 3px "+i+"22":"0 2px 8px rgba(0,0,0,0.4)"),L("is-rect",n.shape==="rect"),s(),C("background",i)("box-shadow","0 0 6px "+i),s(),Q(" ",e.label," "),s(),_(e.state==="drifted"||e.state==="broken"||e.state==="orphaned"?3:-1),s(),_(a.isHovered(e)&&(e.sub||e.kind==="file")?4:-1)}}function ve(r,t){if(r&1){let e=K();Z(0)(1)(2),p(3,"div",10),N("mouseenter",function(){let i=k(e).$implicit,o=c();return M(o.onHoverEnter(i.id))})("mouseleave",function(){k(e);let i=c();return M(i.onHoverLeave())}),y(4,ue,2,7)(5,he,5,21),u()}if(r&2){let e=t.$implicit,n=c(),i=B(n.box(e));s(),B(n.nodeColor(e)),s(),B(n.nodeScale(e)),s(),C("left",e.x,"px")("top",e.y,"px")("opacity",n.nodeOpacity(e)),L("is-selected",n.isSelected(e))("is-hovered",n.isHovered(e)),G("data-node",e.id),s(),_(i.shape==="dot"?4:5)}}function xe(r,t){if(r&1&&(S(),x(0,"circle",28)),r&2){let e=t.$implicit,n=c(3);G("cx",e.cx)("cy",e.cy)("r",e.kind==="route"?1.6:2.1)("fill",n.minimapNodeColor(e.kind,e.state))}}function be(r,t){if(r&1&&(S(),x(0,"rect",29)),r&2){let e=t;G("x",e.x)("y",e.y)("width",e.w)("height",e.h)}}function fe(r,t){if(r&1&&(S(),p(0,"svg",26),T(1,xe,1,4,":svg:circle",28,W),y(3,be,1,4,":svg:rect",29),u()),r&2){let e,n=c(2);s(),V(n.minimapNodes()),s(2),_((e=n.minimapViewport())?3:-1,e)}}function ye(r,t){if(r&1){let e=K();p(0,"div",18)(1,"button",19),N("click",function(){k(e);let i=c();return M(i.zoom(1.2))}),x(2,"app-icon",20),u(),p(3,"button",21),N("click",function(){k(e);let i=c();return M(i.zoom(1/1.2))}),x(4,"app-icon",22),u(),p(5,"button",23),N("click",function(){k(e);let i=c();return M(i.fitView())}),x(6,"app-icon",24),u()(),p(7,"div",25),y(8,fe,4,1,":svg:svg",26),p(9,"div",27),P(10),u()()}if(r&2){let e=c();s(2),$("size",15),s(2),$("size",15),s(2),$("size",15),s(2),_(e.positioned().length>0?8:-1),s(2),Y(e.zoomLabel())}}var te=class r{nodes=w([]);edges=w([]);selectedId=w(null);fitKey=w(0);hiddenIds=w(new Set);interactive=w(!0);dotGrid=w(!0);nodeClick=j();host=J.required("host");view=H({tx:0,ty:0,k:1});hover=H(null);draggedNodes=H({});hostSize=H({w:0,h:0});drag=null;resizeObs=null;positioned=E(()=>{let t=this.draggedNodes();return this.nodes().map(e=>{let n=t[e.id];return n?I(O({},e),{x:n.x,y:n.y}):e})});nodeMap=E(()=>{let t=new Map;for(let e of this.positioned())t.set(e.id,e);return t});neighborSet=E(()=>{let t=this.selectedId(),e=new Set;if(!t)return e;for(let n of this.edges())n.from===t&&e.add(n.to),n.to===t&&e.add(n.from);return e});degreeMap=E(()=>{let t={};for(let e of this.edges())t[e.from]=(t[e.from]??0)+1,t[e.to]=(t[e.to]??0)+1;return t});constructor(){D(()=>{this.nodes(),this.draggedNodes.set({}),queueMicrotask(()=>this.fitView())}),D(()=>{this.fitKey(),queueMicrotask(()=>this.fitView())}),D(()=>{let t=this.host()?.nativeElement;if(!t)return;this.resizeObs&&(this.resizeObs.disconnect(),this.resizeObs=null);let e=new ResizeObserver(n=>{let i=n[0]?.contentRect;i&&this.hostSize.set({w:i.width,h:i.height})});e.observe(t),this.resizeObs=e})}fitView(){let t=this.host()?.nativeElement;if(!t)return;let e=this.positioned();if(e.length===0){this.view.set({tx:0,ty:0,k:1});return}let n=t.clientWidth,i=t.clientHeight;if(n===0||i===0)return;let o=1/0,a=-1/0,d=1/0,m=-1/0;for(let v of e){let l=X(v);v.x<o&&(o=v.x),v.x+l.w>a&&(a=v.x+l.w),v.y<d&&(d=v.y),v.y+l.h>m&&(m=v.y+l.h)}let h=60;o-=h,d-=h,a+=h,m+=h;let b=Math.max(1,a-o),g=Math.max(1,m-d),f=Math.min(n/b,i/g,1.4)*.92;this.view.set({k:f,tx:(n-b*f)/2-o*f,ty:(i-g*f)/2-d*f})}onWheel(t){if(!this.interactive())return;t.preventDefault();let e=this.host().nativeElement.getBoundingClientRect(),n=t.clientX-e.left,i=t.clientY-e.top,o=-t.deltaY*.0016,a=this.view(),d=Math.min(2.4,Math.max(.25,a.k*(1+o))),m=d/a.k;this.view.set({k:d,tx:n-(n-a.tx)*m,ty:i-(i-a.ty)*m})}onMouseDown(t){if(!this.interactive())return;let n=t.target.closest("[data-node]");if(n){let o=n.getAttribute("data-node"),a=this.nodeMap().get(o);if(!a)return;t.stopPropagation(),this.drag={type:"node",id:o,sx:t.clientX,sy:t.clientY,ox:a.x,oy:a.y,moved:!1};return}let i=this.view();this.drag={type:"pan",sx:t.clientX,sy:t.clientY,ox:i.tx,oy:i.ty}}onMouseMove(t){let e=this.drag;if(!e)return;if(e.type==="pan"){this.view.update(a=>I(O({},a),{tx:e.ox+(t.clientX-e.sx),ty:e.oy+(t.clientY-e.sy)}));return}let n=this.view().k,i=(t.clientX-e.sx)/n,o=(t.clientY-e.sy)/n;Math.abs(t.clientX-e.sx)+Math.abs(t.clientY-e.sy)>3&&(e.moved=!0),this.draggedNodes.update(a=>I(O({},a),{[e.id]:{x:e.ox+i,y:e.oy+o}}))}onMouseUp(){let t=this.drag;t&&t.type==="node"&&!t.moved&&this.nodeClick.emit(t.id),this.drag=null}zoom(t){let e=this.host().nativeElement,n=e.clientWidth,i=e.clientHeight,o=this.view(),a=Math.min(2.4,Math.max(.25,o.k*t)),d=a/o.k;this.view.set({k:a,tx:n/2-(n/2-o.tx)*d,ty:i/2-(i/2-o.ty)*d})}onHoverEnter(t){this.hover.set(t)}onHoverLeave(){this.hover.set(null)}box(t){return X(t)}edgePath(t){let e=this.nodeMap().get(t.from),n=this.nodeMap().get(t.to);if(!e||!n)return null;let i=X(e),o=X(n),a=e.x+i.w/2,d=e.y+i.h/2,m=n.x+o.w/2,h=n.y+o.h/2,b=(a+m)/2;return`M ${a} ${d} C ${b} ${d}, ${b} ${h}, ${m} ${h}`}edgeHot(t){let e=this.selectedId();return!!e&&(t.from===e||t.to===e)}edgeStroke(t){if(this.edgeHot(t))return"var(--accent)";let n=this.nodeMap().get(t.from),i=this.nodeMap().get(t.to);return n?.kind==="spec"||i?.kind==="spec"||t.kind==="implements"?"color-mix(in srgb, var(--node-spec) 62%, transparent)":n?.kind==="test"||i?.kind==="test"?"color-mix(in srgb, var(--node-test) 62%, transparent)":"rgba(150,160,180,0.32)"}edgeStrokeWidth(t){let e=this.edgeHot(t),n=this.nodeMap().get(t.from),i=this.nodeMap().get(t.to),o=n?.kind==="spec"||i?.kind==="spec"||n?.kind==="test"||i?.kind==="test"||t.kind==="implements";return e?2:o?1.5:1.2}edgeOpacity(t){let e=this.edgeHot(t),n=this.hiddenIds();return n.size>0&&(n.has(t.from)||n.has(t.to))?.12:e?.95:.72}nodeColor(t){if(t.state==="drifted")return"var(--warn)";if(t.state==="broken"||t.state==="orphaned")return"var(--error)";switch(t.kind){case"spec":return"var(--node-spec)";case"route":return"var(--node-route)";case"test":return"var(--node-test)";case"class":return"var(--node-class, var(--accent-secondary))";case"method":case"function":return"var(--node-code)";default:return"var(--node-code)"}}nodeOpacity(t){let e=this.hiddenIds();if(e.size>0&&e.has(t.id))return .2;let n=this.selectedId();return!n||t.id===n||this.neighborSet().has(t.id)?1:.55}nodeScale(t){let e=this.degreeMap()[t.id]??0;return 1+Math.min(.24,e*.045)}isSelected(t){return t.id===this.selectedId()}isHovered(t){return t.id===this.hover()}zoomLabel(){return Math.round(this.view().k*100)+"%"}dotGridBgSize(){let t=22*this.view().k;return`${t}px ${t}px`}dotGridBgPos(){let t=this.view();return`${t.tx}px ${t.ty}px`}minimapNodes(){let t=this.positioned();if(t.length===0)return[];let e=138,n=88,i=6,{minX:o,maxX:a,minY:d,maxY:m}=ne(t),h=Math.max(1,a-o),b=Math.max(1,m-d),g=Math.min((e-i*2)/h,(n-i*2)/b),f=i+(e-i*2-h*g)/2,v=i+(n-i*2-b*g)/2;return t.map(l=>({cx:f+(l.x-o)*g,cy:v+(l.y-d)*g,kind:l.kind,state:l.state}))}minimapViewport(){let t=this.positioned();if(t.length===0)return null;let e=138,n=88,i=6,{minX:o,maxX:a,minY:d,maxY:m}=ne(t),h=Math.max(1,a-o),b=Math.max(1,m-d),g=Math.min((e-i*2)/h,(n-i*2)/b),f=i+(e-i*2-h*g)/2,v=i+(n-i*2-b*g)/2,l=this.view(),F=this.hostSize();if(F.w===0)return null;let ie=-l.tx/l.k,oe=-l.ty/l.k,re=F.w/l.k,ae=F.h/l.k;return{x:Math.max(0,f+(ie-o)*g),y:Math.max(0,v+(oe-d)*g),w:Math.min(e,re*g),h:Math.min(n,ae*g)}}minimapNodeColor(t,e){return t==="spec"?e==="drifted"?"var(--warn)":e==="broken"||e==="orphaned"?"var(--error)":"var(--node-spec)":t==="test"?"var(--node-test)":t==="route"?"var(--node-route)":"var(--node-code)"}static \u0275fac=function(e){return new(e||r)};static \u0275cmp=q({type:r,selectors:[["app-graph-canvas"]],viewQuery:function(e,n){e&1&&U(n.host,se,5),e&2&&A()},hostVars:6,hostBindings:function(e,n){e&1&&N("wheel",function(o){return n.onWheel(o)})("mousedown",function(o){return n.onMouseDown(o)})("mousemove",function(o){return n.onMouseMove(o)})("mouseup",function(){return n.onMouseUp()})("mouseleave",function(){return n.onMouseUp()}),e&2&&(C("background-size",n.dotGridBgSize())("background-position",n.dotGridBgPos()),L("no-dot-grid",!n.dotGrid()))},inputs:{nodes:[1,"nodes"],edges:[1,"edges"],selectedId:[1,"selectedId"],fitKey:[1,"fitKey"],hiddenIds:[1,"hiddenIds"],interactive:[1,"interactive"],dotGrid:[1,"dotGrid"]},outputs:{nodeClick:"nodeClick"},decls:15,vars:4,consts:[["host",""],[1,"gc-host"],["width","100%","height","100%",1,"gc-edges"],["id","gc-arrow","viewBox","0 0 10 10","refX","8","refY","5","markerWidth","6","markerHeight","6","orient","auto-start-reverse"],["d","M0 0 L10 5 L0 10 z","fill","rgba(160,170,190,0.5)"],["id","gc-arrow-hi","viewBox","0 0 10 10","refX","8","refY","5","markerWidth","7","markerHeight","7","orient","auto-start-reverse"],["d","M0 0 L10 5 L0 10 z","fill","var(--accent)"],[1,"gc-nodes"],[1,"gc-node",3,"is-selected","is-hovered","left","top","opacity"],["fill","none"],[1,"gc-node",3,"mouseenter","mouseleave"],[1,"gc-dot"],[1,"gc-tooltip","gc-tooltip-top"],[1,"gc-chip"],[1,"gc-chip-bullet"],[1,"gc-chip-state",3,"background"],[1,"gc-tooltip"],[1,"gc-chip-state"],[1,"gc-controls"],["type","button","aria-label","Zoom in",1,"gc-btn","btn","btn-secondary",3,"click"],["name","plus",3,"size"],["type","button","aria-label","Zoom out",1,"gc-btn","btn","btn-secondary",3,"click"],["name","minus",3,"size"],["type","button","aria-label","Fit to view","title","Fit",1,"gc-btn","btn","btn-secondary",3,"click"],["name","maximize",3,"size"],[1,"gc-bottom-left"],["width","138","height","88",1,"gc-minimap"],[1,"gc-zoom-label"],["opacity","0.9"],["fill","var(--accent)","fill-opacity","0.12","stroke","var(--accent)","stroke-width","1","rx","2"]],template:function(e,n){e&1&&(p(0,"div",1,0),S(),p(2,"svg",2)(3,"defs")(4,"marker",3),x(5,"path",4),u(),p(6,"marker",5),x(7,"path",6),u()(),p(8,"g"),T(9,le,1,1,null,null,W),u()(),R(),p(11,"div",7),T(12,ve,6,15,"div",8,de),u(),y(14,ye,11,5),u()),e&2&&(s(8),G("transform","translate("+n.view().tx+" "+n.view().ty+") scale("+n.view().k+")"),s(),V(n.edges()),s(2),C("transform","translate("+n.view().tx+"px, "+n.view().ty+"px) scale("+n.view().k+")"),s(),V(n.positioned()),s(2),_(n.interactive()?14:-1))},dependencies:[ee],styles:['@charset "UTF-8";[_nghost-%COMP%]{display:block;width:100%;height:100%;position:relative;background:var(--bg-canvas-2, var(--bg-canvas));cursor:grab;-webkit-user-select:none;user-select:none;overflow:hidden;background-image:radial-gradient(circle,var(--dot-grid, rgba(120, 130, 150, .16)) 1px,transparent 1px);background-size:22px 22px}[_nghost-%COMP%]:active{cursor:grabbing}.no-dot-grid[_nghost-%COMP%]{background-image:none}.gc-host[_ngcontent-%COMP%]{position:absolute;inset:0}.gc-edges[_ngcontent-%COMP%]{position:absolute;inset:0;pointer-events:none}.gc-nodes[_ngcontent-%COMP%]{position:absolute;inset:0;transform-origin:0 0;pointer-events:none}.gc-node[_ngcontent-%COMP%]{position:absolute;pointer-events:auto;cursor:pointer;transition:opacity .12s}.gc-dot[_ngcontent-%COMP%]{width:18px;height:18px;border-radius:50%;border:2px solid var(--bg-canvas-2, var(--bg-canvas))}.gc-chip[_ngcontent-%COMP%]{height:30px;padding:0 12px;display:flex;align-items:center;gap:7px;border-radius:999px;border-width:1.5px;border-style:solid;color:var(--node-text, var(--text-primary));font-size:12.5px;font-weight:500;white-space:nowrap;font-family:var(--font-mono)}.gc-chip.is-rect[_ngcontent-%COMP%]{border-radius:7px}.gc-chip-bullet[_ngcontent-%COMP%]{width:7px;height:7px;border-radius:50%;flex-shrink:0}.gc-chip.is-rect[_ngcontent-%COMP%] .gc-chip-bullet[_ngcontent-%COMP%]{border-radius:2px}.gc-chip-state[_ngcontent-%COMP%]{width:6px;height:6px;border-radius:50%;margin-left:2px}.gc-tooltip[_ngcontent-%COMP%]{position:absolute;top:34px;left:50%;transform:translate(-50%);background:var(--bg-elevated);border:1px solid var(--border-strong);border-radius:5px;padding:3px 7px;font-size:10.5px;font-family:var(--font-mono);color:var(--text-secondary);white-space:nowrap;pointer-events:none;box-shadow:var(--shadow-pop, 0 4px 14px rgba(0, 0, 0, .4));z-index:5}.gc-tooltip-top[_ngcontent-%COMP%]{top:auto;bottom:22px}.gc-controls[_ngcontent-%COMP%]{position:absolute;right:14px;bottom:14px;display:flex;flex-direction:column;gap:6px;z-index:4}.gc-btn[_ngcontent-%COMP%]{width:30px;height:30px;border-radius:7px;padding:0;display:flex;align-items:center;justify-content:center}.gc-bottom-left[_ngcontent-%COMP%]{position:absolute;left:14px;bottom:14px;display:flex;flex-direction:column;gap:6px;align-items:flex-start;z-index:4}.gc-minimap[_ngcontent-%COMP%]{background:color-mix(in srgb,var(--bg-canvas-2, var(--bg-canvas)) 92%,transparent);border:1px solid var(--border-subtle);border-radius:7px;box-shadow:0 4px 12px #0006;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:block}.gc-zoom-label[_ngcontent-%COMP%]{font-family:var(--font-mono);font-size:10px;color:var(--text-muted);background:#0006;padding:2px 7px;border-radius:5px}'],changeDetection:0})};function X(r){return r.kind==="route"?{w:18,h:18,shape:"dot"}:{w:Math.max(64,r.label.length*(r.kind==="spec"?7.6:7.2)+26),h:30,shape:r.kind==="spec"?"rect":"pill"}}function ne(r){let t=1/0,e=-1/0,n=1/0,i=-1/0;for(let o of r)o.x<t&&(t=o.x),o.x+120>e&&(e=o.x+120),o.y<n&&(n=o.y),o.y+50>i&&(i=o.y+50);return{minX:t,maxX:e,minY:n,maxY:i}}export{te as a};
@@ -0,0 +1 @@
1
+ import"./chunk-Q7L6LLAK.js";var e={brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}]},t={tokenPostfix:".tcl",specialFunctions:["set","unset","rename","variable","proc","coroutine","foreach","incr","append","lappend","linsert","lreplace"],mainFunctions:["if","then","elseif","else","case","switch","while","for","break","continue","return","package","namespace","catch","exit","eval","expr","uplevel","upvar"],builtinFunctions:["file","info","concat","join","lindex","list","llength","lrange","lsearch","lsort","split","array","parray","binary","format","regexp","regsub","scan","string","subst","dict","cd","clock","exec","glob","pid","pwd","close","eof","fblocked","fconfigure","fcopy","fileevent","flush","gets","open","puts","read","seek","socket","tell","interp","after","auto_execok","auto_load","auto_mkindex","auto_reset","bgerror","error","global","history","load","source","time","trace","unknown","unset","update","vwait","winfo","wm","bind","event","pack","place","grid","font","bell","clipboard","destroy","focus","grab","lower","option","raise","selection","send","tk","tkwait","tk_bisque","tk_focusNext","tk_focusPrev","tk_focusFollowsMouse","tk_popup","tk_setPalette"],symbols:/[=><!~?:&|+\-*\/\^%]+/,brackets:[{open:"(",close:")",token:"delimiter.parenthesis"},{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"}],escapes:/\\(?:[abfnrtv\\"'\[\]\{\};\$]|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,variables:/(?:\$+(?:(?:\:\:?)?[a-zA-Z_]\w*)+)/,tokenizer:{root:[[/[a-zA-Z_]\w*/,{cases:{"@specialFunctions":{token:"keyword.flow",next:"@specialFunc"},"@mainFunctions":"keyword","@builtinFunctions":"variable","@default":"operator.scss"}}],[/\s+\-+(?!\d|\.)\w*|{\*}/,"metatag"],{include:"@whitespace"},[/[{}()\[\]]/,"@brackets"],[/@symbols/,"operator"],[/\$+(?:\:\:)?\{/,{token:"identifier",next:"@nestedVariable"}],[/@variables/,"type.identifier"],[/\.(?!\d|\.)[\w\-]*/,"operator.sql"],[/\d+(\.\d+)?/,"number"],[/\d+/,"number"],[/;/,"delimiter"],[/"/,{token:"string.quote",bracket:"@open",next:"@dstring"}],[/'/,{token:"string.quote",bracket:"@open",next:"@sstring"}]],dstring:[[/\[/,{token:"@brackets",next:"@nestedCall"}],[/\$+(?:\:\:)?\{/,{token:"identifier",next:"@nestedVariable"}],[/@variables/,"type.identifier"],[/[^\\$\[\]"]+/,"string"],[/@escapes/,"string.escape"],[/"/,{token:"string.quote",bracket:"@close",next:"@pop"}]],sstring:[[/\[/,{token:"@brackets",next:"@nestedCall"}],[/\$+(?:\:\:)?\{/,{token:"identifier",next:"@nestedVariable"}],[/@variables/,"type.identifier"],[/[^\\$\[\]']+/,"string"],[/@escapes/,"string.escape"],[/'/,{token:"string.quote",bracket:"@close",next:"@pop"}]],whitespace:[[/[ \t\r\n]+/,"white"],[/#.*\\$/,{token:"comment",next:"@newlineComment"}],[/#.*(?!\\)$/,"comment"]],newlineComment:[[/.*\\$/,"comment"],[/.*(?!\\)$/,{token:"comment",next:"@pop"}]],nestedVariable:[[/[^\{\}\$]+/,"type.identifier"],[/\}/,{token:"identifier",next:"@pop"}]],nestedCall:[[/\[/,{token:"@brackets",next:"@nestedCall"}],[/\]/,{token:"@brackets",next:"@pop"}],{include:"root"}],specialFunc:[[/"/,{token:"string",next:"@dstring"}],[/'/,{token:"string",next:"@sstring"}],[/\S+/,{token:"type",next:"@pop"}]]}};export{e as conf,t as language};
@@ -0,0 +1 @@
1
+ import"./chunk-Q7L6LLAK.js";var E={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["[","]"],["(",")"],["{","}"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:"{",close:"}",notIn:["string","comment"]}]},T={defaultToken:"",tokenPostfix:".msdax",ignoreCase:!0,brackets:[{open:"[",close:"]",token:"delimiter.square"},{open:"{",close:"}",token:"delimiter.brackets"},{open:"(",close:")",token:"delimiter.parenthesis"}],keywords:["VAR","RETURN","NOT","EVALUATE","DATATABLE","ORDER","BY","START","AT","DEFINE","MEASURE","ASC","DESC","IN","BOOLEAN","DOUBLE","INTEGER","DATETIME","CURRENCY","STRING"],functions:["CLOSINGBALANCEMONTH","CLOSINGBALANCEQUARTER","CLOSINGBALANCEYEAR","DATEADD","DATESBETWEEN","DATESINPERIOD","DATESMTD","DATESQTD","DATESYTD","ENDOFMONTH","ENDOFQUARTER","ENDOFYEAR","FIRSTDATE","FIRSTNONBLANK","LASTDATE","LASTNONBLANK","NEXTDAY","NEXTMONTH","NEXTQUARTER","NEXTYEAR","OPENINGBALANCEMONTH","OPENINGBALANCEQUARTER","OPENINGBALANCEYEAR","PARALLELPERIOD","PREVIOUSDAY","PREVIOUSMONTH","PREVIOUSQUARTER","PREVIOUSYEAR","SAMEPERIODLASTYEAR","STARTOFMONTH","STARTOFQUARTER","STARTOFYEAR","TOTALMTD","TOTALQTD","TOTALYTD","ADDCOLUMNS","ADDMISSINGITEMS","ALL","ALLEXCEPT","ALLNOBLANKROW","ALLSELECTED","CALCULATE","CALCULATETABLE","CALENDAR","CALENDARAUTO","CROSSFILTER","CROSSJOIN","CURRENTGROUP","DATATABLE","DETAILROWS","DISTINCT","EARLIER","EARLIEST","EXCEPT","FILTER","FILTERS","GENERATE","GENERATEALL","GROUPBY","IGNORE","INTERSECT","ISONORAFTER","KEEPFILTERS","LOOKUPVALUE","NATURALINNERJOIN","NATURALLEFTOUTERJOIN","RELATED","RELATEDTABLE","ROLLUP","ROLLUPADDISSUBTOTAL","ROLLUPGROUP","ROLLUPISSUBTOTAL","ROW","SAMPLE","SELECTCOLUMNS","SUBSTITUTEWITHINDEX","SUMMARIZE","SUMMARIZECOLUMNS","TOPN","TREATAS","UNION","USERELATIONSHIP","VALUES","SUM","SUMX","PATH","PATHCONTAINS","PATHITEM","PATHITEMREVERSE","PATHLENGTH","AVERAGE","AVERAGEA","AVERAGEX","COUNT","COUNTA","COUNTAX","COUNTBLANK","COUNTROWS","COUNTX","DISTINCTCOUNT","DIVIDE","GEOMEAN","GEOMEANX","MAX","MAXA","MAXX","MEDIAN","MEDIANX","MIN","MINA","MINX","PERCENTILE.EXC","PERCENTILE.INC","PERCENTILEX.EXC","PERCENTILEX.INC","PRODUCT","PRODUCTX","RANK.EQ","RANKX","STDEV.P","STDEV.S","STDEVX.P","STDEVX.S","VAR.P","VAR.S","VARX.P","VARX.S","XIRR","XNPV","DATE","DATEDIFF","DATEVALUE","DAY","EDATE","EOMONTH","HOUR","MINUTE","MONTH","NOW","SECOND","TIME","TIMEVALUE","TODAY","WEEKDAY","WEEKNUM","YEAR","YEARFRAC","CONTAINS","CONTAINSROW","CUSTOMDATA","ERROR","HASONEFILTER","HASONEVALUE","ISBLANK","ISCROSSFILTERED","ISEMPTY","ISERROR","ISEVEN","ISFILTERED","ISLOGICAL","ISNONTEXT","ISNUMBER","ISODD","ISSUBTOTAL","ISTEXT","USERNAME","USERPRINCIPALNAME","AND","FALSE","IF","IFERROR","NOT","OR","SWITCH","TRUE","ABS","ACOS","ACOSH","ACOT","ACOTH","ASIN","ASINH","ATAN","ATANH","BETA.DIST","BETA.INV","CEILING","CHISQ.DIST","CHISQ.DIST.RT","CHISQ.INV","CHISQ.INV.RT","COMBIN","COMBINA","CONFIDENCE.NORM","CONFIDENCE.T","COS","COSH","COT","COTH","CURRENCY","DEGREES","EVEN","EXP","EXPON.DIST","FACT","FLOOR","GCD","INT","ISO.CEILING","LCM","LN","LOG","LOG10","MOD","MROUND","ODD","PERMUT","PI","POISSON.DIST","POWER","QUOTIENT","RADIANS","RAND","RANDBETWEEN","ROUND","ROUNDDOWN","ROUNDUP","SIGN","SIN","SINH","SQRT","SQRTPI","TAN","TANH","TRUNC","BLANK","CONCATENATE","CONCATENATEX","EXACT","FIND","FIXED","FORMAT","LEFT","LEN","LOWER","MID","REPLACE","REPT","RIGHT","SEARCH","SUBSTITUTE","TRIM","UNICHAR","UNICODE","UPPER","VALUE"],tokenizer:{root:[{include:"@comments"},{include:"@whitespace"},{include:"@numbers"},{include:"@strings"},{include:"@complexIdentifiers"},[/[;,.]/,"delimiter"],[/[({})]/,"@brackets"],[/[a-z_][a-zA-Z0-9_]*/,{cases:{"@keywords":"keyword","@functions":"keyword","@default":"identifier"}}],[/[<>=!%&+\-*/|~^]/,"operator"]],whitespace:[[/\s+/,"white"]],comments:[[/\/\/+.*/,"comment"],[/\/\*/,{token:"comment.quote",next:"@comment"}]],comment:[[/[^*/]+/,"comment"],[/\*\//,{token:"comment.quote",next:"@pop"}],[/./,"comment"]],numbers:[[/0[xX][0-9a-fA-F]*/,"number"],[/[$][+-]*\d*(\.\d*)?/,"number"],[/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/,"number"]],strings:[[/N"/,{token:"string",next:"@string"}],[/"/,{token:"string",next:"@string"}]],string:[[/[^"]+/,"string"],[/""/,"string"],[/"/,{token:"string",next:"@pop"}]],complexIdentifiers:[[/\[/,{token:"identifier.quote",next:"@bracketedIdentifier"}],[/'/,{token:"identifier.quote",next:"@quotedIdentifier"}]],bracketedIdentifier:[[/[^\]]+/,"identifier"],[/]]/,"identifier"],[/]/,{token:"identifier.quote",next:"@pop"}]],quotedIdentifier:[[/[^']+/,"identifier"],[/''/,"identifier"],[/'/,{token:"identifier.quote",next:"@pop"}]]}};export{E as conf,T as language};
@@ -0,0 +1 @@
1
+ import"./chunk-Q7L6LLAK.js";var o=e=>`\\b${e}\\b`,n=e=>`(?!${e})`,i="[_a-zA-Z]",r="[_a-zA-Z0-9]",t=o(`${i}${r}*`),s=o("[_a-zA-Z-0-9]+"),c=["import","model","scalar","namespace","op","interface","union","using","is","extends","enum","alias","return","void","if","else","projection","dec","extern","fn"],a=["true","false","null","unknown","never"],g="[ \\t\\r\\n]",l="[0-9]+",k={comments:{lineComment:"//",blockComment:["/*","*/"]},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"/**",close:" */",notIn:["string"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'}],indentationRules:{decreaseIndentPattern:new RegExp("^((?!.*?/\\*).*\\*/)?\\s*[\\}\\]].*$"),increaseIndentPattern:new RegExp("^((?!//).)*(\\{([^}\"'`/]*|(\\t|[ ])*//.*)|\\([^)\"'`/]*|\\[[^\\]\"'`/]*)$"),unIndentedLinePattern:new RegExp("^(\\t|[ ])*[ ]\\*[^/]*\\*/\\s*$|^(\\t|[ ])*[ ]\\*/\\s*$|^(\\t|[ ])*[ ]\\*([ ]([^\\*]|\\*(?!/))*)?$")}},x={defaultToken:"",tokenPostfix:".tsp",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"},{open:"(",close:")",token:"delimiter.parenthesis"}],symbols:/[=:;<>]+/,keywords:c,namedLiterals:a,escapes:'\\\\(u{[0-9A-Fa-f]+}|n|r|t|\\\\|"|\\${)',tokenizer:{root:[{include:"@expression"},{include:"@whitespace"}],stringVerbatim:[{regex:'(|"|"")[^"]',action:{token:"string"}},{regex:`"""${n('"')}`,action:{token:"string",next:"@pop"}}],stringLiteral:[{regex:"\\${",action:{token:"delimiter.bracket",next:"@bracketCounting"}},{regex:'[^\\\\"$]+',action:{token:"string"}},{regex:"@escapes",action:{token:"string.escape"}},{regex:"\\\\.",action:{token:"string.escape.invalid"}},{regex:'"',action:{token:"string",next:"@pop"}}],bracketCounting:[{regex:"{",action:{token:"delimiter.bracket",next:"@bracketCounting"}},{regex:"}",action:{token:"delimiter.bracket",next:"@pop"}},{include:"@expression"}],comment:[{regex:"[^\\*]+",action:{token:"comment"}},{regex:"\\*\\/",action:{token:"comment",next:"@pop"}},{regex:"[\\/*]",action:{token:"comment"}}],whitespace:[{regex:g},{regex:"\\/\\*",action:{token:"comment",next:"@comment"}},{regex:"\\/\\/.*$",action:{token:"comment"}}],expression:[{regex:'"""',action:{token:"string",next:"@stringVerbatim"}},{regex:`"${n('""')}`,action:{token:"string",next:"@stringLiteral"}},{regex:l,action:{token:"number"}},{regex:t,action:{cases:{"@keywords":{token:"keyword"},"@namedLiterals":{token:"keyword"},"@default":{token:"identifier"}}}},{regex:`@${t}`,action:{token:"tag"}},{regex:`#${s}`,action:{token:"directive"}}]}};export{k as conf,x as language};
@@ -0,0 +1,2 @@
1
+ import{a as L,b as Q,c as q}from"./chunk-T66XVKGB.js";import{a as Y}from"./chunk-DTRN7FZR.js";import{a as U}from"./chunk-MC4DFIHG.js";import{a as H}from"./chunk-UYC52MBC.js";import{a as W}from"./chunk-2GBEK2GM.js";import{a as K}from"./chunk-SUZYBYDW.js";import{b}from"./chunk-4N5DWG46.js";import{c as G,d as B}from"./chunk-SHPTC4RL.js";import{a as V}from"./chunk-7RNS77UP.js";import{a as j}from"./chunk-E44X4RH2.js";import{Aa as l,Ga as P,I as E,Ia as _,Ka as c,M as f,N as C,Ta as T,Ua as y,Va as s,W as R,Wa as k,Xa as v,Ya as D,bb as N,ea as r,gb as O,ib as z,ka as F,lb as m,ra as u,sa as g,ua as I,va as w,vb as $,wa as M,xa as p,ya as a,za as o,zb as A}from"./chunk-PDN6QYGJ.js";import"./chunk-Q7L6LLAK.js";var Z=()=>[0,1,2,3],ee=()=>[0,1,2,3,4],X=(i,e)=>e.id;function te(i,e){if(i&1&&s(0),i&2){let n=c();v(" ",n.fmt$(n.lastSessionCostStat().value)," ")}}function ne(i,e){i&1&&s(0," \xA0 ")}function ie(i,e){if(i&1&&l(0,"app-sparkline",11),i&2){let n=c();p("data",n.lastSessionCostStat().series)("width",64)("height",22)("fill",!0)}}function ae(i,e){if(i&1&&l(0,"app-delta",12),i&2){let n=c();p("value",n.lastSessionCostStat().delta)("invert",!0)}}function oe(i,e){if(i&1&&s(0),i&2){let n=c();v(" ",n.toolCallsStat().value.toLocaleString()," ")}}function re(i,e){i&1&&s(0," \xA0 ")}function se(i,e){if(i&1&&l(0,"app-sparkline",14),i&2){let n=c();p("data",n.toolCallsStat().series)("width",64)("height",22)("fill",!0)}}function le(i,e){if(i&1&&l(0,"app-delta",12),i&2){let n=c();p("value",n.toolCallsStat().delta)("invert",!0)}}function de(i,e){if(i&1&&s(0),i&2){let n=c();v(" ",n.subagentPctStat().value,"% ")}}function pe(i,e){i&1&&s(0," \xA0 ")}function ce(i,e){if(i&1&&l(0,"app-sparkline",16),i&2){let n=c();p("data",n.subagentPctStat().series)("width",64)("height",22)("fill",!0)}}function me(i,e){if(i&1&&l(0,"app-delta",12),i&2){let n=c();p("value",n.subagentPctStat().delta)("invert",!0)}}function ue(i,e){if(i&1&&s(0),i&2){let n=c();v(" ",n.driftStat().value," ")}}function ge(i,e){i&1&&s(0," \xA0 ")}function he(i,e){i&1&&(a(0,"span",24),s(1,"seed"),o())}function _e(i,e){if(i&1&&(a(0,"span",31),s(1),o()),i&2){let n=c();r(),v(" ",n.urgentTipCount()," urgent ")}}function ve(i,e){i&1&&l(0,"div",58)}function be(i,e){i&1&&w(0,ve,1,0,"div",58,I),i&2&&M(N(0,Z))}function xe(i,e){i&1&&(a(0,"div",34),s(1,"No tips yet. Run more sessions to populate."),o())}function fe(i,e){if(i&1&&(a(0,"code",66),s(1),o()),i&2){let n=c().$implicit;r(),k(n.fix)}}function Ce(i,e){if(i&1&&(a(0,"span",73),s(1),o()),i&2){let n=c().$implicit,t=c(2);T("color",t.tipSevColor(n.severity)),r(),k(n.saving)}}function ye(i,e){if(i&1){let n=P();a(0,"div",60)(1,"div",61),l(2,"app-icon",62),o(),a(3,"div",63)(4,"div",64),s(5),o(),a(6,"div",65),u(7,fe,2,1,"code",66),l(8,"span",67),u(9,Ce,2,3,"span",68),o()(),a(10,"div",69)(11,"button",70),_("click",function(){f(n);let d=c(2);return C(d.go("tips"))}),s(12,"Apply"),o(),a(13,"button",71),_("click",function(){let d=f(n).$implicit,h=c(2);return C(h.dismissTip(d.id))}),l(14,"app-icon",72),o()()()}if(i&2){let n=e.$implicit,t=c(2);T("border-left-color",t.tipSevColor(n.severity)),r(),T("color",t.tipSevColor(n.severity)),r(),p("name",t.tipIcon(n))("size",14),r(3),k(n.title),r(2),g(n.fix?7:-1),r(2),g(n.saving?9:-1),r(5),p("size",12)}}function ke(i,e){if(i&1&&w(0,ye,15,10,"div",59,X),i&2){let n=c();M(n.visibleTips())}}function Se(i,e){i&1&&l(0,"div",42)}function we(i,e){i&1&&(a(0,"div",43),s(1," No tool calls in the selected window. "),o())}function Me(i,e){if(i&1){let n=P();a(0,"app-treemap",74),_("pick",function(){f(n);let d=c();return C(d.go("heatmap"))}),o()}if(i&2){let n=c();p("items",n.treemapItems())("height",116)("selKey",null)}}function Te(i,e){i&1&&l(0,"div",75)}function Ee(i,e){i&1&&w(0,Te,1,0,"div",75,I),i&2&&M(N(0,ee))}function Pe(i,e){i&1&&(a(0,"div",34),s(1,"No prompts ingested for this range."),o())}function De(i,e){i&1&&l(0,"app-icon",80),i&2&&p("size",11)}function Oe(i,e){if(i&1){let n=P();a(0,"div",77),_("click",function(){f(n);let d=c(2);return C(d.go("sessions"))})("keydown.enter",function(){f(n);let d=c(2);return C(d.go("sessions"))})("keydown.space",function(){f(n);let d=c(2);return C(d.go("sessions"))}),a(1,"div",78)(2,"div",79),u(3,De,1,1,"app-icon",80),s(4),o(),a(5,"div",81),l(6,"app-bar",82),o()(),a(7,"div",83)(8,"div",84),s(9),o(),a(10,"div",85),s(11),O(12,"number"),o()()()}if(i&2){let n=e.$implicit,t=c(2);r(3),g(n.is_sidechain?3:-1),r(),v(" ",n.text||"(no text)"," "),r(2),p("frac",t.promptFrac(n.cost_usd))("color",t.promptBarColor(n.cost_usd))("height",4),r(2),T("color",n.cost_usd/t.maxPromptCost()>.7?"var(--error)":"var(--text-primary)"),y("expensive",n.cost_usd/t.maxPromptCost()>.7),r(),v(" ",t.fmt$(n.cost_usd)," "),r(2),D(" ",t.fmtK(t.promptTotalTokens(n))," \xB7 ",z(12,12,t.promptCacheRate(n)*100,"1.0-0"),"% ")}}function ze(i,e){if(i&1&&w(0,Oe,13,15,"div",76,X),i&2){let n=c();M(n.topPrompts())}}function Re(i,e){i&1&&l(0,"div",56)}function Ie(i,e){if(i&1&&(a(0,"div",86)(1,"div",87),s(2),O(3,"number"),o(),a(4,"div",88)(5,"div",40),s(6,"cache read rate"),o(),l(7,"app-delta",12),o()(),l(8,"div",89),a(9,"div",90)(10,"div",91)(11,"div",92),s(12,"Creation tokens"),o(),a(13,"div",93),s(14),o(),a(15,"div",94),s(16,"ephemeral"),o()(),a(17,"div",91)(18,"div",92),s(19,"Read tokens"),o(),a(20,"div",93),s(21),o(),a(22,"div",94),s(23,"charged at ~10%"),o()(),a(24,"div",91)(25,"div",92),s(26,"Saved this week"),o(),a(27,"div",95),s(28),o(),a(29,"div",94),s(30,"vs no cache"),o()(),a(31,"div",91)(32,"div",92),s(33,"WoW"),o(),a(34,"div",95),s(35),O(36,"number"),o(),a(37,"div",94),s(38,"more reuse"),o()()()),i&2){let n=c(),t=n.cache.state().data;r(2),v("",z(3,8,t.readRate*100,"1.0-0"),"%"),r(5),p("value",t.wowDelta)("invert",!1),r(7),k(n.fmtK(t.creationTokens)),r(7),k(n.fmtK(t.readTokens)),r(7),k(n.fmt$(t.dollarsSaved)),r(7),D(" ",t.wowDelta>=0?"+":"","",z(36,11,t.wowDelta*100,"1.0-0"),"% ")}}var J=class i{api=E(j);router=E(G);projects=E(V);range=R("week");rangeOptions=[{value:"today",label:"Today"},{value:"week",label:"This week"},{value:"month",label:"This month"},{value:"all",label:"All time"}];status=b(this.api,()=>`/api/status${this.projects.projectQuery()}`);miniGraphSearch=b(this.api,()=>`/api/graph/search?q=on&limit=18${this.projects.projectQuery("&")}`);tips=b(this.api,()=>"/api/claude/tips");heatmap=b(this.api,()=>`/api/claude/heatmap?range=${this.range()}`);costs=b(this.api,()=>`/api/claude/costs?range=${this.range()}`);cache=b(this.api,()=>`/api/claude/cache?range=${this.range()}`);sessions=b(this.api,()=>`/api/claude/sessions?range=${this.range()}&limit=10`);stats=b(this.api,()=>`/api/claude/stats?range=${this.range()}`);EMPTY_METRIC={value:0,delta:0,series:[]};lastSessionCostStat=m(()=>this.stats.state().data?.lastSessionCost??this.EMPTY_METRIC);toolCallsStat=m(()=>this.stats.state().data?.toolCalls??this.EMPTY_METRIC);subagentPctStat=m(()=>this.stats.state().data?.subagentPct??this.EMPTY_METRIC);driftStat=m(()=>this.stats.state().data?.drift??this.EMPTY_METRIC);lastSession=m(()=>(this.sessions.state().data?.sessions??[])[0]??null);lastSessionCost=m(()=>this.lastSession()?.total_cost_usd??0);toolCallCount=m(()=>(this.heatmap.state().data?.tools??[]).reduce((n,t)=>n+(t.calls??0),0));subagentShare=m(()=>{let e=this.heatmap.state().data?.subagents??[],n=e.find(x=>x.type==="subagent"),t=e.find(x=>x.type==="main"),d=n?.cost??0,h=t?.cost??0,S=d+h;return S>0?Math.round(d/S*100):0});driftCount=m(()=>this.status.state().data?.drift??0);nodeCountLabel=m(()=>this.status.state().data?.nodeCount??0);urgentTipCount=m(()=>(this.tips.state().data?.tips??[]).filter(n=>n.severity==="error").length);dismissedTips=R(new Set);dismissTip(e){this.dismissedTips.update(n=>{let t=new Set(n);return t.add(e),t})}isTipDismissed(e){return this.dismissedTips().has(e)}visibleTips=m(()=>{let e=this.dismissedTips();return(this.tips.state().data?.tips??[]).filter(n=>!e.has(n.id)).slice(0,4)});treemapItems=m(()=>{let e=(this.heatmap.state().data?.files??[]).slice(0,30);if(!e.length)return[];let n=Math.max(1,...e.map(t=>t.resultBytes&&t.calls?t.resultBytes/t.calls:0));return e.map(t=>{let d=t.calls>0?t.resultBytes/t.calls:0,h=Math.min(1,d/n);return{key:t.path,label:L(t.path),value:t.calls,intensity:h,sub:t.calls+" calls",title:`${t.path}
2
+ ${t.calls} calls \xB7 ${this.fmtK(Math.round(d))}/call`}})});topPrompts=m(()=>(this.costs.state().data?.topPrompts??[]).slice(0,8));maxPromptCost=m(()=>Math.max(.01,...this.topPrompts().map(e=>e.cost_usd??0)));rangeTotal=m(()=>(this.costs.state().data?.series??[]).reduce((n,t)=>n+(t.cost??0),0));liveSource=m(()=>this.status.state().source==="api"&&this.status.state().data?"live":"mock");miniGraphSource=m(()=>(this.miniGraphSearch.state().data?.results?.length??0)>0?"api":"seed");miniGraphNodes=m(()=>{let e=this.miniGraphSearch.state().data?.results??[];return e.length>0?$e(e.slice(0,18).map(n=>({id:n.node.id,label:n.node.name,sub:n.node.filePath?.split("/").slice(-2).join("/"),kind:n.node.kind}))):Ne});miniGraphEdges=m(()=>{if(this.miniGraphSource()==="api"){let e=this.miniGraphNodes(),n=[];for(let t=1;t<e.length;t++){let d=e[Math.floor(Math.random()*t)],h=e[t];d&&h&&n.push({from:d.id,to:h.id,kind:"calls"})}return n}return Fe});onMiniGraphPick(e){this.router.navigate(["/graph"],{queryParams:{focus:e}})}setRange(e){this.range.set(e)}go(e){this.router.navigate(["/"+e])}fmt$(e){return"$"+e.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2})}fmtK(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(e>=1e4?0:1)+"k":String(e)}promptCacheRate(e){let n=(e.input_tokens??0)+(e.cache_creation_tokens??0)+(e.cache_read_tokens??0);return n>0?(e.cache_read_tokens??0)/n:0}promptTotalTokens(e){return(e.input_tokens??0)+(e.output_tokens??0)+(e.cache_creation_tokens??0)+(e.cache_read_tokens??0)}promptBarColor(e){return e/this.maxPromptCost()>.7?"var(--error)":"var(--accent)"}promptFrac(e){return Math.max(0,Math.min(1,e/this.maxPromptCost()))}tipSevColor(e){return e==="error"?"var(--error)":e==="warn"?"var(--warn)":"var(--info)"}tipIcon(e){return e.icon?e.icon:e.severity==="error"?"cancel":e.severity==="warn"?"warn":"info"}static \u0275fac=function(n){return new(n||i)};static \u0275cmp=F({type:i,selectors:[["app-dashboard"]],decls:122,vars:48,consts:[[1,"scroll-y","dashboard"],["icon","dashboard","title","Dashboard",3,"sub"],["actions",""],["size","sm",3,"change","options","value"],[1,"stat-grid"],["type","button",1,"stat-tile",3,"click"],[1,"row","gap-8","stat-eyebrow"],["name","coins",2,"color","var(--accent)",3,"size"],[1,"eyebrow",2,"letter-spacing","0.04em"],[1,"row","stat-value-row"],[1,"stat-value","tabular"],["color","var(--accent)",3,"data","width","height","fill"],[3,"value","invert"],["name","wrench",2,"color","var(--node-spec)",3,"size"],["color","var(--node-spec)",3,"data","width","height","fill"],["name","bot",2,"color","var(--node-code)",3,"size"],["color","var(--node-code)",3,"data","width","height","fill"],["name","drift",2,"color","var(--warn)",3,"size"],[1,"center-grid"],[1,"card","graph-card"],[1,"card-head"],[1,"card-title","row","gap-8"],["name","graph",2,"color","var(--accent)",3,"size"],[1,"muted",2,"font-size","11px","font-weight","400"],["title","No graph data yet \u2014 illustrative",1,"pill","seed-pill"],["routerLink","/graph",1,"btn","btn-ghost","btn-xs"],["name","arrowRight",3,"size"],[1,"mini-graph"],[3,"nodeClick","nodes","edges"],[1,"card","tips-card"],["name","tips",2,"color","var(--warn)",3,"size"],[1,"pill",2,"font-size","10px","background","var(--error-soft)","color","var(--error)"],["routerLink","/tips",1,"btn","btn-ghost","btn-xs"],[1,"scroll-y","tips-body"],[1,"tip-empty"],[1,"card","card-pad","heatmap-card"],[1,"row","heatmap-head"],[1,"row","gap-8"],["name","flame",2,"color","var(--warn)",3,"size"],[2,"font-weight","600","font-size","12.5px"],[1,"muted",2,"font-size","11px"],["routerLink","/heatmap",1,"btn","btn-ghost","btn-xs"],[1,"skel",2,"height","116px","border-radius","7px"],[1,"tip-empty",2,"height","116px","display","grid","place-items","center"],[3,"items","height","selKey"],[1,"row","gap-10","heatmap-legend"],[1,"muted",2,"font-size","10px"],[1,"heatmap-gradient"],[1,"muted",2,"font-size","9.5px"],[1,"bottom-grid"],[1,"card","card-pad","prompts-card"],[1,"row","prompts-head"],["routerLink","/costs",1,"btn","btn-ghost","btn-xs"],[1,"col"],[1,"card","card-pad","cache-card"],["name","database",2,"color","var(--node-route)",3,"size"],[1,"skel",2,"height","70px","border-radius","5px"],[1,"dash-footer","mono","muted"],[1,"skel",2,"height","64px","border-radius","8px"],[1,"tip-row",3,"border-left-color"],[1,"tip-row"],[1,"tip-sev-icon"],[3,"name","size"],[1,"grow","tip-body-col",2,"min-width","0"],[1,"tip-title"],[1,"row","gap-8","tip-meta-row"],[1,"mono","tip-fix"],[1,"grow"],[1,"pill",2,"font-size","10px","color","inherit","background","transparent",3,"color"],[1,"row","gap-4",2,"flex-shrink","0"],["type","button",1,"btn","btn-secondary","btn-xs",3,"click"],["type","button","title","Dismiss",1,"btn","btn-ghost","btn-xs",3,"click"],["name","x",3,"size"],[1,"pill",2,"font-size","10px","color","inherit","background","transparent"],[3,"pick","items","height","selKey"],[1,"skel",2,"height","26px","margin","4px 0","border-radius","4px"],["role","button","tabindex","0",1,"prompt-row"],["role","button","tabindex","0",1,"prompt-row",3,"click","keydown.enter","keydown.space"],[1,"grow","prompt-left",2,"min-width","0"],[1,"prompt-text"],["name","bot",2,"color","var(--node-code)","margin-right","5px","vertical-align","-1px",3,"size"],[2,"margin-top","4px","width","70%"],[3,"frac","color","height"],[1,"prompt-right"],[1,"mono","tabular","prompt-cost"],[1,"mono","muted",2,"font-size","10px"],[1,"row","cache-headline"],[1,"tabular","cache-rate"],[2,"padding-bottom","3px"],[1,"cache-divider"],[1,"cache-kv-grid"],[1,"kv"],[1,"kv-label"],[1,"kv-value","mono","tabular"],[1,"kv-sub","mono","muted"],[1,"kv-value","mono","tabular",2,"color","var(--success)"]],template:function(n,t){n&1&&(a(0,"div",0)(1,"app-page-head",1)(2,"div",2)(3,"app-segmented",3),_("change",function(h){return t.setRange(h)}),o()()(),a(4,"div",4)(5,"button",5),_("click",function(){return t.go("sessions")}),a(6,"div",6),l(7,"app-icon",7),a(8,"span",8),s(9,"Last session cost"),o()(),a(10,"div",9)(11,"div",10),u(12,te,1,1)(13,ne,1,0),o(),u(14,ie,1,4,"app-sparkline",11),o(),u(15,ae,1,2,"app-delta",12),o(),a(16,"button",5),_("click",function(){return t.go("heatmap")}),a(17,"div",6),l(18,"app-icon",13),a(19,"span",8),s(20),o()(),a(21,"div",9)(22,"div",10),u(23,oe,1,1)(24,re,1,0),o(),u(25,se,1,4,"app-sparkline",14),o(),u(26,le,1,2,"app-delta",12),o(),a(27,"button",5),_("click",function(){return t.go("heatmap")}),a(28,"div",6),l(29,"app-icon",15),a(30,"span",8),s(31,"Subagent spend"),o()(),a(32,"div",9)(33,"div",10),u(34,de,1,1)(35,pe,1,0),o(),u(36,ce,1,4,"app-sparkline",16),o(),u(37,me,1,2,"app-delta",12),o(),a(38,"button",5),_("click",function(){return t.go("drift")}),a(39,"div",6),l(40,"app-icon",17),a(41,"span",8),s(42,"Drift queue"),o()(),a(43,"div",9)(44,"div",10),u(45,ue,1,1)(46,ge,1,0),o()()()(),a(47,"div",18)(48,"div",19)(49,"div",20)(50,"div",21),l(51,"app-icon",22),a(52,"span"),s(53,"Recent neighborhood"),o(),a(54,"span",23),s(55,"\xB7 last edited files"),o(),u(56,he,2,0,"span",24),o(),a(57,"a",25),s(58," Open graph "),l(59,"app-icon",26),o()(),a(60,"div",27)(61,"app-graph-canvas",28),_("nodeClick",function(h){return t.onMiniGraphPick(h)}),o()()(),a(62,"div",29)(63,"div",20)(64,"div",21),l(65,"app-icon",30),a(66,"span"),s(67,"Tips"),o(),u(68,_e,2,1,"span",31),o(),a(69,"a",32),s(70,"All"),o()(),a(71,"div",33),u(72,be,2,1)(73,xe,2,0,"div",34)(74,ke,2,0),o()()(),a(75,"div",35)(76,"div",36)(77,"div",37),l(78,"app-icon",38),a(79,"span",39),s(80,"Tool-call heatmap"),o(),a(81,"span",40),s(82,"\xB7 area = calls, color = tokens / call"),o()(),a(83,"a",41),s(84," Open heatmap "),l(85,"app-icon",26),o()(),u(86,Se,1,0,"div",42)(87,we,2,0,"div",43)(88,Me,1,3,"app-treemap",44),a(89,"div",45)(90,"span",46),s(91,"tokens / call"),o(),l(92,"div",47),a(93,"span",48),s(94,"efficient \u2192 wasteful"),o()()(),a(95,"div",49)(96,"div",50)(97,"div",51)(98,"div",37),l(99,"app-icon",7),a(100,"span",39),s(101,"Recent prompts"),o(),a(102,"span",40),s(103,"\xB7 by cost"),o()(),a(104,"a",52),s(105,"Cost ranking"),o()(),a(106,"div",53),u(107,Ee,2,1)(108,Pe,2,0,"div",34)(109,ze,2,0),o()(),a(110,"div",54)(111,"div",37),l(112,"app-icon",55),a(113,"span",39),s(114,"Cache analytics"),o()(),u(115,Re,1,0,"div",56)(116,Ie,39,14),o()(),a(117,"footer",57),s(118),a(119,"span"),s(120,"\u25CF"),o(),s(121),o()()),n&2&&(r(),p("sub","specship \xB7 "+t.nodeCountLabel().toLocaleString()+" nodes \xB7 last session "+t.fmt$(t.lastSessionCost())),r(2),p("options",t.rangeOptions)("value",t.range()),r(4),p("size",13),r(4),y("skel",t.stats.state().loading),r(),g(t.stats.state().loading?13:12),r(2),g(t.lastSessionCostStat().series.length>0?14:-1),r(),g(t.lastSessionCostStat().delta!==0?15:-1),r(3),p("size",13),r(2),v("Tool calls \xB7 ",t.range()),r(2),y("skel",t.stats.state().loading),r(),g(t.stats.state().loading?24:23),r(2),g(t.toolCallsStat().series.length>0?25:-1),r(),g(t.toolCallsStat().delta!==0?26:-1),r(3),p("size",13),r(4),y("skel",t.stats.state().loading),r(),g(t.stats.state().loading?35:34),r(2),g(t.subagentPctStat().series.length>0?36:-1),r(),g(t.subagentPctStat().delta!==0?37:-1),r(3),p("size",13),r(4),y("skel",t.stats.state().loading),r(),g(t.stats.state().loading?46:45),r(6),p("size",14),r(5),g(t.miniGraphSource()==="seed"?56:-1),r(3),p("size",11),r(2),p("nodes",t.miniGraphNodes())("edges",t.miniGraphEdges()),r(4),p("size",14),r(3),g(t.urgentTipCount()>0?68:-1),r(4),g(t.tips.state().loading?72:t.visibleTips().length===0?73:74),r(6),p("size",14),r(7),p("size",11),r(),g(t.heatmap.state().loading?86:t.treemapItems().length===0?87:88),r(13),p("size",14),r(8),g(t.costs.state().loading?107:t.topPrompts().length===0?108:109),r(5),p("size",14),r(3),g(t.cache.state().loading?115:t.cache.state().data?116:-1),r(3),D(" ",t.range()," window total: ",t.fmt$(t.rangeTotal())," \xB7 "),r(),y("dot-live",t.liveSource()==="live")("dot-mock",t.liveSource()==="mock"),r(2),v(" ",t.liveSource()," "))},dependencies:[B,A,H,K,U,Y,Q,q,W,$],styles:['@charset "UTF-8";[_nghost-%COMP%]{display:contents}.dashboard[_ngcontent-%COMP%]{flex:1;padding:18px;color:var(--text-primary);background:var(--bg-canvas)}.stat-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:14px}.stat-tile[_ngcontent-%COMP%]{text-align:left;padding:11px 13px;cursor:pointer;background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:var(--r-lg);display:flex;flex-direction:column;gap:6px;color:var(--text-primary);font-family:inherit;transition:background .1s,border-color .1s}.stat-tile[_ngcontent-%COMP%]:hover{background:var(--bg-panel-2);border-color:var(--border-strong)}.stat-eyebrow[_ngcontent-%COMP%]{color:var(--text-muted)}.stat-value-row[_ngcontent-%COMP%]{justify-content:space-between;align-items:flex-end;gap:8px}.stat-value[_ngcontent-%COMP%]{font-size:23px;font-weight:650;letter-spacing:-.02em;line-height:1;min-height:23px}.center-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:2fr 1fr;gap:12px;margin-bottom:14px}.graph-card[_ngcontent-%COMP%], .tips-card[_ngcontent-%COMP%]{height:340px;display:flex;flex-direction:column;background:var(--bg-panel);border:1px solid var(--border-subtle);border-radius:var(--r-lg);overflow:hidden}.card-head[_ngcontent-%COMP%]{display:flex;justify-content:space-between;align-items:center;padding:11px 13px;border-bottom:1px solid var(--border-subtle);flex-shrink:0}.card-title[_ngcontent-%COMP%]{font-weight:600;font-size:12.5px;display:inline-flex;align-items:center;gap:8px}.mini-graph[_ngcontent-%COMP%]{flex:1;min-height:0;overflow:hidden;border-bottom-left-radius:var(--r-lg);border-bottom-right-radius:var(--r-lg)}.mini-graph[_ngcontent-%COMP%] app-graph-canvas[_ngcontent-%COMP%]{display:block;width:100%;height:100%}.seed-pill[_ngcontent-%COMP%]{color:var(--warn);background:var(--warn-soft);font-size:9.5px;font-weight:600;padding:1px 6px}.tips-body[_ngcontent-%COMP%]{flex:1;padding:10px;display:flex;flex-direction:column;gap:8px;min-height:0}.tip-empty[_ngcontent-%COMP%]{color:var(--text-muted);font-size:12px;text-align:center;padding:12px}.tip-row[_ngcontent-%COMP%]{display:flex;gap:10px;padding:10px 12px;border-radius:8px;background:var(--bg-panel-2);border:1px solid var(--border-subtle);border-left-width:2.5px;animation:_ngcontent-%COMP%_slideInRight .2s ease;flex-shrink:0}.tip-sev-icon[_ngcontent-%COMP%]{flex-shrink:0;margin-top:1px}.tip-body-col[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:0}.tip-title[_ngcontent-%COMP%]{font-size:12.5px;font-weight:550;line-height:1.35;text-wrap:pretty}.tip-meta-row[_ngcontent-%COMP%]{margin-top:7px}.tip-fix[_ngcontent-%COMP%]{font-size:10.5px;color:var(--text-secondary);background:var(--bg-canvas);padding:2px 6px;border-radius:4px;border:1px solid var(--border-subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:220px}.heatmap-card[_ngcontent-%COMP%]{margin-bottom:14px}.heatmap-head[_ngcontent-%COMP%]{justify-content:space-between;margin-bottom:10px}.heatmap-legend[_ngcontent-%COMP%]{margin-top:9px;align-items:center}.heatmap-gradient[_ngcontent-%COMP%]{width:96px;height:6px;border-radius:999px;background:linear-gradient(90deg,var(--node-route),var(--warn),var(--error))}.bottom-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:1.4fr 1fr;gap:12px}.prompts-card[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:0}.prompts-head[_ngcontent-%COMP%]{justify-content:space-between;margin-bottom:6px}.prompt-row[_ngcontent-%COMP%]{display:flex;gap:10px;padding:7px 4px;border-radius:6px;cursor:pointer;align-items:center}.prompt-row[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.prompt-text[_ngcontent-%COMP%]{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.prompt-right[_ngcontent-%COMP%]{text-align:right;flex-shrink:0}.prompt-cost[_ngcontent-%COMP%]{font-size:12px;font-weight:600}.prompt-cost.expensive[_ngcontent-%COMP%]{color:var(--error)}.cache-card[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:12px}.cache-headline[_ngcontent-%COMP%]{align-items:flex-end;gap:10px}.cache-rate[_ngcontent-%COMP%]{font-size:38px;font-weight:700;letter-spacing:-.03em;line-height:.9;color:var(--node-route)}.cache-divider[_ngcontent-%COMP%]{height:1px;background:var(--border-subtle)}.cache-kv-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px}.kv[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:1px}.kv-label[_ngcontent-%COMP%]{color:var(--text-muted);font-size:10.5px}.kv-value[_ngcontent-%COMP%]{font-size:15px;font-weight:600}.kv-sub[_ngcontent-%COMP%]{font-size:9.5px}.dash-footer[_ngcontent-%COMP%]{margin-top:16px;text-align:right;font-size:10px}.dot-live[_ngcontent-%COMP%]{color:var(--success)}.dot-mock[_ngcontent-%COMP%]{color:var(--warn)}@keyframes _ngcontent-%COMP%_slideInRight{0%{opacity:0;transform:translate(14px)}to{opacity:1;transform:translate(0)}}'],changeDetection:0})},Ne=[{id:"s-1",label:"validateSession",sub:"src/auth.ts",kind:"function",x:0,y:0},{id:"s-2",label:"checkExpiry",sub:"src/auth.ts",kind:"method",x:-180,y:-70},{id:"s-3",label:"signToken",sub:"src/auth.ts",kind:"function",x:-180,y:50},{id:"s-4",label:"AuthRoute",sub:"src/routes/auth.ts",kind:"route",x:200,y:-90},{id:"s-5",label:"login",sub:"src/routes/auth.ts",kind:"function",x:200,y:30},{id:"s-6",label:"logout",sub:"src/routes/auth.ts",kind:"function",x:230,y:110},{id:"s-7",label:"auth.test.ts",sub:"test/auth.test.ts",kind:"test",x:-240,y:140},{id:"s-8",label:"session.test.ts",sub:"test/session.test.ts",kind:"test",x:-100,y:180},{id:"s-9",label:"REQ-AUTH-005",sub:"reject expired tokens",kind:"spec",state:"drifted",x:30,y:-180},{id:"s-10",label:"REQ-AUTH-001",sub:"sign session tokens",kind:"spec",state:"verified",x:-150,y:-190},{id:"s-11",label:"User",sub:"src/types/user.ts",kind:"class",x:-340,y:-10},{id:"s-12",label:"Session",sub:"src/types/session.ts",kind:"class",x:60,y:130},{id:"s-13",label:"jwtSign",sub:"src/lib/jwt.ts",kind:"function",x:-340,y:80},{id:"s-14",label:"jwtVerify",sub:"src/lib/jwt.ts",kind:"function",x:350,y:-10},{id:"s-15",label:"tokenStore",sub:"src/db/tokens.ts",kind:"function",x:350,y:90}],Fe=[{from:"s-1",to:"s-2",kind:"calls"},{from:"s-1",to:"s-3",kind:"calls"},{from:"s-4",to:"s-5",kind:"calls"},{from:"s-4",to:"s-6",kind:"calls"},{from:"s-5",to:"s-1",kind:"calls"},{from:"s-6",to:"s-1",kind:"calls"},{from:"s-3",to:"s-13",kind:"calls"},{from:"s-2",to:"s-14",kind:"calls"},{from:"s-1",to:"s-12",kind:"references"},{from:"s-5",to:"s-11",kind:"references"},{from:"s-9",to:"s-1",kind:"implements"},{from:"s-10",to:"s-3",kind:"implements"},{from:"s-7",to:"s-1",kind:"references"},{from:"s-8",to:"s-12",kind:"references"},{from:"s-14",to:"s-15",kind:"calls"}];function $e(i){if(i.length===0)return[];let e=i[0],n=i.slice(1),t=[{id:e.id,label:e.label,sub:e.sub,kind:e.kind,x:0,y:0}],d=220;for(let h=0;h<n.length;h++){let S=h/n.length*Math.PI*2-Math.PI/2,x=n[h];t.push({id:x.id,label:x.label,sub:x.sub,kind:x.kind,x:Math.cos(S)*d,y:Math.sin(S)*d})}return t}export{J as Dashboard};
@@ -0,0 +1 @@
1
+ import"./chunk-Q7L6LLAK.js";var e={comments:{lineComment:"#",blockComment:["=begin","=end"]},brackets:[["(",")"],["{","}"],["[","]"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],indentationRules:{increaseIndentPattern:new RegExp(`^\\s*((begin|class|(private|protected)\\s+def|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while|case)|([^#]*\\sdo\\b)|([^#]*=\\s*(case|if|unless)))\\b([^#\\{;]|("|'|/).*\\4)*(#.*)?$`),decreaseIndentPattern:new RegExp("^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif|when)\\b)")}},t={tokenPostfix:".ruby",keywords:["__LINE__","__ENCODING__","__FILE__","BEGIN","END","alias","and","begin","break","case","class","def","defined?","do","else","elsif","end","ensure","for","false","if","in","module","next","nil","not","or","redo","rescue","retry","return","self","super","then","true","undef","unless","until","when","while","yield"],keywordops:["::","..","...","?",":","=>"],builtins:["require","public","private","include","extend","attr_reader","protected","private_class_method","protected_class_method","new"],declarations:["module","class","def","case","do","begin","for","if","while","until","unless"],linedecls:["def","case","do","begin","for","if","while","until","unless"],operators:["^","&","|","<=>","==","===","!~","=~",">",">=","<","<=","<<",">>","+","-","*","/","%","**","~","+@","-@","[]","[]=","`","+=","-=","*=","**=","/=","^=","%=","<<=",">>=","&=","&&=","||=","|="],brackets:[{open:"(",close:")",token:"delimiter.parenthesis"},{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.square"}],symbols:/[=><!~?:&|+\-*\/\^%\.]+/,escape:/(?:[abefnrstv\\"'\n\r]|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4})/,escapes:/\\(?:C\-(@escape|.)|c(@escape|.)|@escape)/,decpart:/\d(_?\d)*/,decimal:/0|@decpart/,delim:/[^a-zA-Z0-9\s\n\r]/,heredelim:/(?:\w+|'[^']*'|"[^"]*"|`[^`]*`)/,regexpctl:/[(){}\[\]\$\^|\-*+?\.]/,regexpesc:/\\(?:[AzZbBdDfnrstvwWn0\\\/]|@regexpctl|c[A-Z]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})?/,tokenizer:{root:[[/^(\s*)([a-z_]\w*[!?=]?)/,["white",{cases:{"for|until|while":{token:"keyword.$2",next:"@dodecl.$2"},"@declarations":{token:"keyword.$2",next:"@root.$2"},end:{token:"keyword.$S2",next:"@pop"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}]],[/[a-z_]\w*[!?=]?/,{cases:{"if|unless|while|until":{token:"keyword.$0x",next:"@modifier.$0x"},for:{token:"keyword.$2",next:"@dodecl.$2"},"@linedecls":{token:"keyword.$0",next:"@root.$0"},end:{token:"keyword.$S2",next:"@pop"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}],[/[A-Z][\w]*[!?=]?/,"constructor.identifier"],[/\$[\w]*/,"global.constant"],[/@[\w]*/,"namespace.instance.identifier"],[/@@@[\w]*/,"namespace.class.identifier"],[/<<[-~](@heredelim).*/,{token:"string.heredoc.delimiter",next:"@heredoc.$1"}],[/[ \t\r\n]+<<(@heredelim).*/,{token:"string.heredoc.delimiter",next:"@heredoc.$1"}],[/^<<(@heredelim).*/,{token:"string.heredoc.delimiter",next:"@heredoc.$1"}],{include:"@whitespace"},[/"/,{token:"string.d.delim",next:'@dstring.d."'}],[/'/,{token:"string.sq.delim",next:"@sstring.sq"}],[/%([rsqxwW]|Q?)/,{token:"@rematch",next:"pstring"}],[/`/,{token:"string.x.delim",next:"@dstring.x.`"}],[/:(\w|[$@])\w*[!?=]?/,"string.s"],[/:"/,{token:"string.s.delim",next:'@dstring.s."'}],[/:'/,{token:"string.s.delim",next:"@sstring.s"}],[/\/(?=(\\\/|[^\/\n])+\/)/,{token:"regexp.delim",next:"@regexp"}],[/[{}()\[\]]/,"@brackets"],[/@symbols/,{cases:{"@keywordops":"keyword","@operators":"operator","@default":""}}],[/[;,]/,"delimiter"],[/0[xX][0-9a-fA-F](_?[0-9a-fA-F])*/,"number.hex"],[/0[_oO][0-7](_?[0-7])*/,"number.octal"],[/0[bB][01](_?[01])*/,"number.binary"],[/0[dD]@decpart/,"number"],[/@decimal((\.@decpart)?([eE][\-+]?@decpart)?)/,{cases:{$1:"number.float","@default":"number"}}]],dodecl:[[/^/,{token:"",switchTo:"@root.$S2"}],[/[a-z_]\w*[!?=]?/,{cases:{end:{token:"keyword.$S2",next:"@pop"},do:{token:"keyword",switchTo:"@root.$S2"},"@linedecls":{token:"@rematch",switchTo:"@root.$S2"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}],{include:"@root"}],modifier:[[/^/,"","@pop"],[/[a-z_]\w*[!?=]?/,{cases:{end:{token:"keyword.$S2",next:"@pop"},"then|else|elsif|do":{token:"keyword",switchTo:"@root.$S2"},"@linedecls":{token:"@rematch",switchTo:"@root.$S2"},"@keywords":"keyword","@builtins":"predefined","@default":"identifier"}}],{include:"@root"}],sstring:[[/[^\\']+/,"string.$S2"],[/\\\\|\\'|\\$/,"string.$S2.escape"],[/\\./,"string.$S2.invalid"],[/'/,{token:"string.$S2.delim",next:"@pop"}]],dstring:[[/[^\\`"#]+/,"string.$S2"],[/#/,"string.$S2.escape","@interpolated"],[/\\$/,"string.$S2.escape"],[/@escapes/,"string.$S2.escape"],[/\\./,"string.$S2.escape.invalid"],[/[`"]/,{cases:{"$#==$S3":{token:"string.$S2.delim",next:"@pop"},"@default":"string.$S2"}}]],heredoc:[[/^(\s*)(@heredelim)$/,{cases:{"$2==$S2":["string.heredoc",{token:"string.heredoc.delimiter",next:"@pop"}],"@default":["string.heredoc","string.heredoc"]}}],[/.*/,"string.heredoc"]],interpolated:[[/\$\w*/,"global.constant","@pop"],[/@\w*/,"namespace.class.identifier","@pop"],[/@@@\w*/,"namespace.instance.identifier","@pop"],[/[{]/,{token:"string.escape.curly",switchTo:"@interpolated_compound"}],["","","@pop"]],interpolated_compound:[[/[}]/,{token:"string.escape.curly",next:"@pop"}],{include:"@root"}],pregexp:[{include:"@whitespace"},[/[^\(\{\[\\]/,{cases:{"$#==$S3":{token:"regexp.delim",next:"@pop"},"$#==$S2":{token:"regexp.delim",next:"@push"},"~[)}\\]]":"@brackets.regexp.escape.control","~@regexpctl":"regexp.escape.control","@default":"regexp"}}],{include:"@regexcontrol"}],regexp:[{include:"@regexcontrol"},[/[^\\\/]/,"regexp"],["/[ixmp]*",{token:"regexp.delim"},"@pop"]],regexcontrol:[[/(\{)(\d+(?:,\d*)?)(\})/,["@brackets.regexp.escape.control","regexp.escape.control","@brackets.regexp.escape.control"]],[/(\[)(\^?)/,["@brackets.regexp.escape.control",{token:"regexp.escape.control",next:"@regexrange"}]],[/(\()(\?[:=!])/,["@brackets.regexp.escape.control","regexp.escape.control"]],[/\(\?#/,{token:"regexp.escape.control",next:"@regexpcomment"}],[/[()]/,"@brackets.regexp.escape.control"],[/@regexpctl/,"regexp.escape.control"],[/\\$/,"regexp.escape"],[/@regexpesc/,"regexp.escape"],[/\\\./,"regexp.invalid"],[/#/,"regexp.escape","@interpolated"]],regexrange:[[/-/,"regexp.escape.control"],[/\^/,"regexp.invalid"],[/\\$/,"regexp.escape"],[/@regexpesc/,"regexp.escape"],[/[^\]]/,"regexp"],[/\]/,"@brackets.regexp.escape.control","@pop"]],regexpcomment:[[/[^)]+/,"comment"],[/\)/,{token:"regexp.escape.control",next:"@pop"}]],pstring:[[/%([qws])\(/,{token:"string.$1.delim",switchTo:"@qstring.$1.(.)"}],[/%([qws])\[/,{token:"string.$1.delim",switchTo:"@qstring.$1.[.]"}],[/%([qws])\{/,{token:"string.$1.delim",switchTo:"@qstring.$1.{.}"}],[/%([qws])</,{token:"string.$1.delim",switchTo:"@qstring.$1.<.>"}],[/%([qws])(@delim)/,{token:"string.$1.delim",switchTo:"@qstring.$1.$2.$2"}],[/%r\(/,{token:"regexp.delim",switchTo:"@pregexp.(.)"}],[/%r\[/,{token:"regexp.delim",switchTo:"@pregexp.[.]"}],[/%r\{/,{token:"regexp.delim",switchTo:"@pregexp.{.}"}],[/%r</,{token:"regexp.delim",switchTo:"@pregexp.<.>"}],[/%r(@delim)/,{token:"regexp.delim",switchTo:"@pregexp.$1.$1"}],[/%(x|W|Q?)\(/,{token:"string.$1.delim",switchTo:"@qqstring.$1.(.)"}],[/%(x|W|Q?)\[/,{token:"string.$1.delim",switchTo:"@qqstring.$1.[.]"}],[/%(x|W|Q?)\{/,{token:"string.$1.delim",switchTo:"@qqstring.$1.{.}"}],[/%(x|W|Q?)</,{token:"string.$1.delim",switchTo:"@qqstring.$1.<.>"}],[/%(x|W|Q?)(@delim)/,{token:"string.$1.delim",switchTo:"@qqstring.$1.$2.$2"}],[/%([rqwsxW]|Q?)./,{token:"invalid",next:"@pop"}],[/./,{token:"invalid",next:"@pop"}]],qstring:[[/\\$/,"string.$S2.escape"],[/\\./,"string.$S2.escape"],[/./,{cases:{"$#==$S4":{token:"string.$S2.delim",next:"@pop"},"$#==$S3":{token:"string.$S2.delim",next:"@push"},"@default":"string.$S2"}}]],qqstring:[[/#/,"string.$S2.escape","@interpolated"],{include:"@qstring"}],whitespace:[[/[ \t\r\n]+/,""],[/^\s*=begin\b/,"comment","@comment"],[/#.*$/,"comment"]],comment:[[/[^=]+/,"comment"],[/^\s*=begin\b/,"comment.invalid"],[/^\s*=end\b.*/,"comment","@pop"],[/[=]/,"comment"]]}};export{e as conf,t as language};
@@ -0,0 +1,2 @@
1
+ import"./chunk-Q7L6LLAK.js";var e={wordPattern:/(#?-?\d*\.\d\w*%?)|([@#!.:]?[\w-?]+%?)|[@#!.]/g,comments:{blockComment:["/*","*/"],lineComment:"//"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:'"',close:'"',notIn:["string","comment"]},{open:"'",close:"'",notIn:["string","comment"]}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{markers:{start:new RegExp("^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/"),end:new RegExp("^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/")}}},t={defaultToken:"",tokenPostfix:".less",identifier:"-?-?([a-zA-Z]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",identifierPlus:"-?-?([a-zA-Z:.]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))([\\w\\-:.]|(\\\\(([0-9a-fA-F]{1,6}\\s?)|[^[0-9a-fA-F])))*",brackets:[{open:"{",close:"}",token:"delimiter.curly"},{open:"[",close:"]",token:"delimiter.bracket"},{open:"(",close:")",token:"delimiter.parenthesis"},{open:"<",close:">",token:"delimiter.angle"}],tokenizer:{root:[{include:"@nestedJSBegin"},["[ \\t\\r\\n]+",""],{include:"@comments"},{include:"@keyword"},{include:"@strings"},{include:"@numbers"},["[*_]?[a-zA-Z\\-\\s]+(?=:.*(;|(\\\\$)))","attribute.name","@attribute"],["url(\\-prefix)?\\(",{token:"tag",next:"@urldeclaration"}],["[{}()\\[\\]]","@brackets"],["[,:;]","delimiter"],["#@identifierPlus","tag.id"],["&","tag"],["\\.@identifierPlus(?=\\()","tag.class","@attribute"],["\\.@identifierPlus","tag.class"],["@identifierPlus","tag"],{include:"@operators"},["@(@identifier(?=[:,\\)]))","variable","@attribute"],["@(@identifier)","variable"],["@","key","@atRules"]],nestedJSBegin:[["``","delimiter.backtick"],["`",{token:"delimiter.backtick",next:"@nestedJSEnd",nextEmbedded:"text/javascript"}]],nestedJSEnd:[["`",{token:"delimiter.backtick",next:"@pop",nextEmbedded:"@pop"}]],operators:[["[<>=\\+\\-\\*\\/\\^\\|\\~]","operator"]],keyword:[["(@[\\s]*import|![\\s]*important|true|false|when|iscolor|isnumber|isstring|iskeyword|isurl|ispixel|ispercentage|isem|hue|saturation|lightness|alpha|lighten|darken|saturate|desaturate|fadein|fadeout|fade|spin|mix|round|ceil|floor|percentage)\\b","keyword"]],urldeclaration:[{include:"@strings"},[`[^)\r
2
+ ]+`,"string"],["\\)",{token:"tag",next:"@pop"}]],attribute:[{include:"@nestedJSBegin"},{include:"@comments"},{include:"@strings"},{include:"@numbers"},{include:"@keyword"},["[a-zA-Z\\-]+(?=\\()","attribute.value","@attribute"],[">","operator","@pop"],["@identifier","attribute.value"],{include:"@operators"},["@(@identifier)","variable"],["[)\\}]","@brackets","@pop"],["[{}()\\[\\]>]","@brackets"],["[;]","delimiter","@pop"],["[,=:]","delimiter"],["\\s",""],[".","attribute.value"]],comments:[["\\/\\*","comment","@comment"],["\\/\\/+.*","comment"]],comment:[["\\*\\/","comment","@pop"],[".","comment"]],numbers:[["(\\d*\\.)?\\d+([eE][\\-+]?\\d+)?",{token:"attribute.value.number",next:"@units"}],["#[0-9a-fA-F_]+(?!\\w)","attribute.value.hex"]],units:[["(em|ex|ch|rem|fr|vmin|vmax|vw|vh|vm|cm|mm|in|px|pt|pc|deg|grad|rad|turn|s|ms|Hz|kHz|%)?","attribute.value.unit","@pop"]],strings:[['~?"',{token:"string.delimiter",next:"@stringsEndDoubleQuote"}],["~?'",{token:"string.delimiter",next:"@stringsEndQuote"}]],stringsEndDoubleQuote:[['\\\\"',"string"],['"',{token:"string.delimiter",next:"@popall"}],[".","string"]],stringsEndQuote:[["\\\\'","string"],["'",{token:"string.delimiter",next:"@popall"}],[".","string"]],atRules:[{include:"@comments"},{include:"@strings"},["[()]","delimiter"],["[\\{;]","delimiter","@pop"],[".","key"]]}};export{e as conf,t as language};
@@ -0,0 +1 @@
1
+ import"./chunk-Q7L6LLAK.js";var e={comments:{lineComment:"'"},brackets:[["(",")"],["[","]"],["If","EndIf"],["While","EndWhile"],["For","EndFor"],["Sub","EndSub"]],autoClosingPairs:[{open:'"',close:'"',notIn:["string","comment"]},{open:"(",close:")",notIn:["string","comment"]},{open:"[",close:"]",notIn:["string","comment"]}]},o={defaultToken:"",tokenPostfix:".sb",ignoreCase:!0,brackets:[{token:"delimiter.array",open:"[",close:"]"},{token:"delimiter.parenthesis",open:"(",close:")"},{token:"keyword.tag-if",open:"If",close:"EndIf"},{token:"keyword.tag-while",open:"While",close:"EndWhile"},{token:"keyword.tag-for",open:"For",close:"EndFor"},{token:"keyword.tag-sub",open:"Sub",close:"EndSub"}],keywords:["Else","ElseIf","EndFor","EndIf","EndSub","EndWhile","For","Goto","If","Step","Sub","Then","To","While"],tagwords:["If","Sub","While","For"],operators:[">","<","<>","<=",">=","And","Or","+","-","*","/","="],identifier:/[a-zA-Z_][\w]*/,symbols:/[=><:+\-*\/%\.,]+/,escapes:/\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,tokenizer:{root:[{include:"@whitespace"},[/(@identifier)(?=[.])/,"type"],[/@identifier/,{cases:{"@keywords":{token:"keyword.$0"},"@operators":"operator","@default":"variable.name"}}],[/([.])(@identifier)/,{cases:{$2:["delimiter","type.member"],"@default":""}}],[/\d*\.\d+/,"number.float"],[/\d+/,"number"],[/[()\[\]]/,"@brackets"],[/@symbols/,{cases:{"@operators":"operator","@default":"delimiter"}}],[/"([^"\\]|\\.)*$/,"string.invalid"],[/"/,"string","@string"]],whitespace:[[/[ \t\r\n]+/,""],[/(\').*$/,"comment"]],string:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"C?/,"string","@pop"]]}};export{e as conf,o as language};