@specship/specship-win32-arm64 0.11.8 → 0.12.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 (235) hide show
  1. package/lib/dist/bin/specship.js +141 -66
  2. package/lib/dist/bin/specship.js.map +1 -1
  3. package/lib/dist/commands/specship/check.md +5 -0
  4. package/lib/dist/commands/specship/spec.md +235 -15
  5. package/lib/dist/db/migrations.d.ts.map +1 -1
  6. package/lib/dist/db/migrations.js +1 -0
  7. package/lib/dist/db/migrations.js.map +1 -1
  8. package/lib/dist/enforce/enforce.d.ts +15 -0
  9. package/lib/dist/enforce/enforce.d.ts.map +1 -1
  10. package/lib/dist/enforce/enforce.js +43 -1
  11. package/lib/dist/enforce/enforce.js.map +1 -1
  12. package/lib/dist/extraction/index.d.ts +6 -0
  13. package/lib/dist/extraction/index.d.ts.map +1 -1
  14. package/lib/dist/extraction/index.js.map +1 -1
  15. package/lib/dist/index.d.ts +9 -1
  16. package/lib/dist/index.d.ts.map +1 -1
  17. package/lib/dist/index.js +53 -9
  18. package/lib/dist/index.js.map +1 -1
  19. package/lib/dist/installer/index.d.ts.map +1 -1
  20. package/lib/dist/installer/index.js +35 -0
  21. package/lib/dist/installer/index.js.map +1 -1
  22. package/lib/dist/installer/instructions-template.d.ts +2 -2
  23. package/lib/dist/installer/instructions-template.js +3 -3
  24. package/lib/dist/installer/targets/claude.d.ts +10 -0
  25. package/lib/dist/installer/targets/claude.d.ts.map +1 -1
  26. package/lib/dist/installer/targets/claude.js +33 -7
  27. package/lib/dist/installer/targets/claude.js.map +1 -1
  28. package/lib/dist/mcp/designer-tools.js +1 -1
  29. package/lib/dist/mcp/server-instructions.d.ts +1 -1
  30. package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
  31. package/lib/dist/mcp/server-instructions.js +1 -1
  32. package/lib/dist/mcp/spec-tools.d.ts +10 -0
  33. package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
  34. package/lib/dist/mcp/spec-tools.js +228 -2
  35. package/lib/dist/mcp/spec-tools.js.map +1 -1
  36. package/lib/dist/mcp/tools.d.ts +12 -0
  37. package/lib/dist/mcp/tools.d.ts.map +1 -1
  38. package/lib/dist/mcp/tools.js +34 -1
  39. package/lib/dist/mcp/tools.js.map +1 -1
  40. package/lib/dist/reflect/index.d.ts +1 -1
  41. package/lib/dist/reflect/index.d.ts.map +1 -1
  42. package/lib/dist/reflect/index.js +2 -1
  43. package/lib/dist/reflect/index.js.map +1 -1
  44. package/lib/dist/reflect/miner.d.ts +8 -0
  45. package/lib/dist/reflect/miner.d.ts.map +1 -1
  46. package/lib/dist/reflect/miner.js +64 -36
  47. package/lib/dist/reflect/miner.js.map +1 -1
  48. package/lib/dist/resolution/brief-link-resolver.d.ts +20 -0
  49. package/lib/dist/resolution/brief-link-resolver.d.ts.map +1 -1
  50. package/lib/dist/resolution/brief-link-resolver.js +65 -1
  51. package/lib/dist/resolution/brief-link-resolver.js.map +1 -1
  52. package/lib/dist/resolution/spec-link-resolver.d.ts +16 -2
  53. package/lib/dist/resolution/spec-link-resolver.d.ts.map +1 -1
  54. package/lib/dist/resolution/spec-link-resolver.js +19 -1
  55. package/lib/dist/resolution/spec-link-resolver.js.map +1 -1
  56. package/lib/dist/server/cli.js +5 -49
  57. package/lib/dist/server/ingest/ingestor.js +17 -17
  58. package/lib/dist/server/ingest/pricing-backfill.js +55 -0
  59. package/lib/dist/server/ingest/pricing.js +3 -0
  60. package/lib/dist/server/ingest/project-paths.js +152 -0
  61. package/lib/dist/server/project-registry.js +15 -2
  62. package/lib/dist/server/routes/claude.js +47 -18
  63. package/lib/dist/server/routes/events.js +20 -1
  64. package/lib/dist/server/routes/projects.js +6 -3
  65. package/lib/dist/server/routes/spec.js +22 -2
  66. package/lib/dist/server/server.js +38 -4
  67. package/lib/dist/server/ssr/md.mjs +83 -0
  68. package/lib/dist/server/ssr/public/app.css +1 -0
  69. package/lib/dist/server/ssr/render.mjs +564 -0
  70. package/lib/dist/server/ssr/routes.js +73 -0
  71. package/lib/dist/server/static-handler.js +30 -0
  72. package/lib/dist/workflows/defaults/claude-design-implement.yaml +3 -3
  73. package/lib/dist/workflows/defaults/spec-implement.yaml +41 -9
  74. package/lib/node_modules/.package-lock.json +1 -1
  75. package/lib/package.json +3 -3
  76. package/package.json +1 -1
  77. package/lib/dist/commands/specship/design-implement.md +0 -84
  78. package/lib/dist/commands/specship/design-loop.md +0 -125
  79. package/lib/dist/commands/ss-behaviour.md +0 -116
  80. package/lib/dist/web/chunk-2AJCHB7P.js +0 -1
  81. package/lib/dist/web/chunk-2CPLUFCH.js +0 -2
  82. package/lib/dist/web/chunk-2I7L37NS.js +0 -1
  83. package/lib/dist/web/chunk-2IVSOVQZ.js +0 -1
  84. package/lib/dist/web/chunk-2NAWAJB5.js +0 -1
  85. package/lib/dist/web/chunk-2OJBIPE4.js +0 -1
  86. package/lib/dist/web/chunk-3E2WB6D5.js +0 -1
  87. package/lib/dist/web/chunk-3EBFYSCH.js +0 -2
  88. package/lib/dist/web/chunk-3QCQ4BXS.js +0 -1
  89. package/lib/dist/web/chunk-42XVAQ6I.js +0 -1
  90. package/lib/dist/web/chunk-4G7XU55L.js +0 -1
  91. package/lib/dist/web/chunk-4IMMPEYM.js +0 -1
  92. package/lib/dist/web/chunk-4TJQJPCZ.js +0 -1
  93. package/lib/dist/web/chunk-4WZIHTPC.js +0 -1
  94. package/lib/dist/web/chunk-4YVSYOSD.js +0 -1
  95. package/lib/dist/web/chunk-5BQIOYKW.js +0 -1
  96. package/lib/dist/web/chunk-5HGWHUJA.js +0 -1
  97. package/lib/dist/web/chunk-5NTGUSXJ.js +0 -1
  98. package/lib/dist/web/chunk-5Y244R4G.js +0 -1
  99. package/lib/dist/web/chunk-6RRDPT5Z.js +0 -1
  100. package/lib/dist/web/chunk-6VKB2ZWM.js +0 -1
  101. package/lib/dist/web/chunk-7656MA24.js +0 -1
  102. package/lib/dist/web/chunk-7DMFVTU4.js +0 -1
  103. package/lib/dist/web/chunk-7KWBINA7.js +0 -1
  104. package/lib/dist/web/chunk-7MUNFW56.js +0 -1
  105. package/lib/dist/web/chunk-7SMPKVEP.js +0 -1
  106. package/lib/dist/web/chunk-AZJVTPLU.js +0 -1
  107. package/lib/dist/web/chunk-AZUUBUEJ.js +0 -1
  108. package/lib/dist/web/chunk-BLBRMCN2.js +0 -1
  109. package/lib/dist/web/chunk-BMIAXD2V.js +0 -2
  110. package/lib/dist/web/chunk-BPCJLNBS.js +0 -47
  111. package/lib/dist/web/chunk-BUXWEHIY.js +0 -1
  112. package/lib/dist/web/chunk-CYXQILZI.js +0 -1
  113. package/lib/dist/web/chunk-DLQPZWSI.css +0 -1
  114. package/lib/dist/web/chunk-DOKZOFKM.js +0 -1
  115. package/lib/dist/web/chunk-DTWIJ3GJ.js +0 -1
  116. package/lib/dist/web/chunk-DYRFLPJA.js +0 -1
  117. package/lib/dist/web/chunk-E27QAKAB.js +0 -1
  118. package/lib/dist/web/chunk-E3J3CXR5.js +0 -1
  119. package/lib/dist/web/chunk-E73OX2P7.js +0 -1
  120. package/lib/dist/web/chunk-EAXRKDLV.js +0 -1
  121. package/lib/dist/web/chunk-EBKKDHYI.js +0 -1
  122. package/lib/dist/web/chunk-EE7V7Q5P.js +0 -1
  123. package/lib/dist/web/chunk-EKY2FUHU.js +0 -1
  124. package/lib/dist/web/chunk-EP6XOPXH.js +0 -1
  125. package/lib/dist/web/chunk-ESGDLJOJ.js +0 -1
  126. package/lib/dist/web/chunk-ETJG7NCY.js +0 -1
  127. package/lib/dist/web/chunk-EUUEFEDI.js +0 -1
  128. package/lib/dist/web/chunk-EXBUKHH2.js +0 -17
  129. package/lib/dist/web/chunk-F5TBUYDH.js +0 -1
  130. package/lib/dist/web/chunk-FC3R7YHR.js +0 -4
  131. package/lib/dist/web/chunk-FGNZDHTL.js +0 -11
  132. package/lib/dist/web/chunk-FIJW2UNJ.js +0 -1
  133. package/lib/dist/web/chunk-FMV5PXRC.js +0 -5
  134. package/lib/dist/web/chunk-G7RXFHYO.js +0 -1
  135. package/lib/dist/web/chunk-G7VZT5KB.js +0 -3
  136. package/lib/dist/web/chunk-GRZYXPSO.js +0 -7
  137. package/lib/dist/web/chunk-GYGPS3AN.js +0 -1
  138. package/lib/dist/web/chunk-H723TYYD.js +0 -2
  139. package/lib/dist/web/chunk-H7AF7YS4.js +0 -1
  140. package/lib/dist/web/chunk-HDZDQILN.js +0 -1
  141. package/lib/dist/web/chunk-HMK6UO6N.js +0 -1
  142. package/lib/dist/web/chunk-HSJNHNOH.js +0 -6
  143. package/lib/dist/web/chunk-IHEE5NYJ.js +0 -1
  144. package/lib/dist/web/chunk-IOB4JJT4.js +0 -1
  145. package/lib/dist/web/chunk-ISNEBICW.js +0 -1
  146. package/lib/dist/web/chunk-J2GZVLHH.js +0 -1
  147. package/lib/dist/web/chunk-JGDK6YKG.js +0 -1
  148. package/lib/dist/web/chunk-JLOJCDIY.js +0 -1
  149. package/lib/dist/web/chunk-JPSYO24K.js +0 -1
  150. package/lib/dist/web/chunk-JTFXTIPE.js +0 -903
  151. package/lib/dist/web/chunk-K7UD24Z4.js +0 -1
  152. package/lib/dist/web/chunk-KYSTCHAH.js +0 -1
  153. package/lib/dist/web/chunk-LB6JPLX2.js +0 -1
  154. package/lib/dist/web/chunk-LNSVDHCI.js +0 -1
  155. package/lib/dist/web/chunk-LVGIY3SO.js +0 -1
  156. package/lib/dist/web/chunk-LXLHIHEN.js +0 -1
  157. package/lib/dist/web/chunk-MNFTHCSJ.js +0 -1
  158. package/lib/dist/web/chunk-N6SS4G6S.js +0 -1
  159. package/lib/dist/web/chunk-NKPK3BR3.js +0 -1
  160. package/lib/dist/web/chunk-NTBJG6SJ.js +0 -1
  161. package/lib/dist/web/chunk-NUDB3Q2Y.js +0 -3
  162. package/lib/dist/web/chunk-OTQR5VFM.js +0 -1
  163. package/lib/dist/web/chunk-OXEF5E3E.js +0 -1
  164. package/lib/dist/web/chunk-P62EJGSF.js +0 -1
  165. package/lib/dist/web/chunk-PCW6R7OP.js +0 -1
  166. package/lib/dist/web/chunk-PGGJPDJG.js +0 -1
  167. package/lib/dist/web/chunk-POCVU4VK.js +0 -2
  168. package/lib/dist/web/chunk-PS6HRYQQ.js +0 -3
  169. package/lib/dist/web/chunk-PUYSJNJR.js +0 -1
  170. package/lib/dist/web/chunk-PZSU53SS.js +0 -1
  171. package/lib/dist/web/chunk-Q2RVFS45.js +0 -1
  172. package/lib/dist/web/chunk-Q7L6LLAK.js +0 -1
  173. package/lib/dist/web/chunk-QCMKJIWY.js +0 -1
  174. package/lib/dist/web/chunk-QH6CF3M3.js +0 -1
  175. package/lib/dist/web/chunk-QIZ65CGB.js +0 -1
  176. package/lib/dist/web/chunk-QPA2REUE.js +0 -1
  177. package/lib/dist/web/chunk-QQ5LD7PI.js +0 -1
  178. package/lib/dist/web/chunk-QR6L3KAC.js +0 -1
  179. package/lib/dist/web/chunk-R2DLK4HO.js +0 -1
  180. package/lib/dist/web/chunk-RD6TVPOT.js +0 -1
  181. package/lib/dist/web/chunk-RKY4EJYJ.js +0 -1
  182. package/lib/dist/web/chunk-RONYWVY7.js +0 -1
  183. package/lib/dist/web/chunk-RXKXYF2C.js +0 -1
  184. package/lib/dist/web/chunk-SQPYSOV6.js +0 -1
  185. package/lib/dist/web/chunk-SWKJRNYY.js +0 -1
  186. package/lib/dist/web/chunk-SYGIPC2P.js +0 -4
  187. package/lib/dist/web/chunk-T7AZ65JP.js +0 -1
  188. package/lib/dist/web/chunk-TCZDVOHD.js +0 -1
  189. package/lib/dist/web/chunk-TPTITA3V.js +0 -1
  190. package/lib/dist/web/chunk-TR335633.js +0 -1
  191. package/lib/dist/web/chunk-TWVVIWKO.js +0 -1
  192. package/lib/dist/web/chunk-U67LRNER.js +0 -1
  193. package/lib/dist/web/chunk-UR5KDXPX.js +0 -1
  194. package/lib/dist/web/chunk-UR6O2GEH.js +0 -1
  195. package/lib/dist/web/chunk-USVLLFVR.js +0 -1
  196. package/lib/dist/web/chunk-UTNMGWTP.js +0 -1
  197. package/lib/dist/web/chunk-V74ZPP4B.js +0 -1
  198. package/lib/dist/web/chunk-VECWMHJP.js +0 -1
  199. package/lib/dist/web/chunk-VUACT35R.js +0 -3
  200. package/lib/dist/web/chunk-VZI7H4SZ.js +0 -1
  201. package/lib/dist/web/chunk-WB6YHOD4.js +0 -1
  202. package/lib/dist/web/chunk-WBJ5VEB5.js +0 -1
  203. package/lib/dist/web/chunk-WBT64AWV.js +0 -1
  204. package/lib/dist/web/chunk-WFXJIXZE.js +0 -4
  205. package/lib/dist/web/chunk-WTGYRH3Z.js +0 -298
  206. package/lib/dist/web/chunk-WXTCVDTP.js +0 -1
  207. package/lib/dist/web/chunk-XAUQEKZX.js +0 -1
  208. package/lib/dist/web/chunk-XCDHWLVH.js +0 -1
  209. package/lib/dist/web/chunk-Y3H6FFUZ.js +0 -1
  210. package/lib/dist/web/chunk-Y4F5ULGJ.js +0 -1
  211. package/lib/dist/web/chunk-YEGKAAEE.js +0 -1
  212. package/lib/dist/web/chunk-YM2KU57F.js +0 -1
  213. package/lib/dist/web/chunk-YNYVOPWF.js +0 -1
  214. package/lib/dist/web/chunk-YRERBP6T.js +0 -1
  215. package/lib/dist/web/chunk-YV5LB22R.js +0 -1
  216. package/lib/dist/web/chunk-YWIRU745.js +0 -1
  217. package/lib/dist/web/chunk-YXYPTZ6E.js +0 -1
  218. package/lib/dist/web/chunk-ZLV4VCDG.js +0 -3
  219. package/lib/dist/web/chunk-ZTVI5KFF.js +0 -1
  220. package/lib/dist/web/favicon-16.png +0 -0
  221. package/lib/dist/web/favicon-180.png +0 -0
  222. package/lib/dist/web/favicon-32.png +0 -0
  223. package/lib/dist/web/favicon-512.png +0 -0
  224. package/lib/dist/web/favicon-small.svg +0 -15
  225. package/lib/dist/web/favicon.ico +0 -0
  226. package/lib/dist/web/favicon.svg +0 -20
  227. package/lib/dist/web/icon-192.png +0 -0
  228. package/lib/dist/web/icon-512.png +0 -0
  229. package/lib/dist/web/index.html +0 -146
  230. package/lib/dist/web/main-ESADRXN2.css +0 -1
  231. package/lib/dist/web/main-FY3HQ4PX.js +0 -1
  232. package/lib/dist/web/manifest.webmanifest +0 -15
  233. package/lib/dist/web/media/codicon-LN6W7LCM.ttf +0 -0
  234. package/lib/dist/web/styles-KSOPUVDA.css +0 -1
  235. package/lib/dist/web/sw.js +0 -69
@@ -1 +1 @@
1
- {"version":3,"file":"spec-link-resolver.js","sourceRoot":"","sources":["../../src/resolution/spec-link-resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spec-link-resolver.js","sourceRoot":"","sources":["../../src/resolution/spec-link-resolver.ts"],"names":[],"mappings":"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"}
@@ -11,9 +11,6 @@
11
11
  * The JSONL ingest watcher is started inside `createServer()` by default —
12
12
  * pass `--no-ingest` to disable.
13
13
  */
14
- import path from 'node:path';
15
- import { existsSync } from 'node:fs';
16
- import { fileURLToPath } from 'node:url';
17
14
  import { spawn } from 'node:child_process';
18
15
  import { createServer } from './server.js';
19
16
  function parseArgs() {
@@ -64,45 +61,6 @@ Options:
64
61
  }
65
62
  return args;
66
63
  }
67
- /**
68
- * Locate the built Angular UI. Tries (in order):
69
- * 1. Explicit --web-dir / env var
70
- * 2. Sibling `public/web/` next to the running script (production layout)
71
- * 3. Sibling `../web-ng/dist/web-ng/browser/` (monorepo dev layout)
72
- * 4. Walk up looking for `packages/web-ng/dist/web-ng/browser/`
73
- * Returns null when nothing is found — the server then runs API-only.
74
- */
75
- function locateWebDir(explicit) {
76
- const envDir = process.env.SPECSHIP_WEB_DIR ?? process.env.SPECSHIP_WEB_DIR;
77
- const candidates = [];
78
- if (explicit)
79
- candidates.push(path.resolve(explicit));
80
- if (envDir)
81
- candidates.push(path.resolve(envDir));
82
- // __dirname equivalent in ESM
83
- const here = path.dirname(fileURLToPath(import.meta.url));
84
- // Production layout: <pkg>/dist/cli.js, UI shipped at <pkg>/public/web/
85
- candidates.push(path.resolve(here, '..', 'public', 'web'));
86
- candidates.push(path.resolve(here, '..', '..', 'public', 'web'));
87
- // Monorepo dev layout: packages/server/dist/cli.js → packages/web-ng/dist/web-ng/browser
88
- candidates.push(path.resolve(here, '..', '..', 'web-ng', 'dist', 'web-ng', 'browser'));
89
- candidates.push(path.resolve(here, '..', '..', '..', 'web-ng', 'dist', 'web-ng', 'browser'));
90
- // Walk up from cwd looking for the monorepo layout (handy when run via npx
91
- // inside a checkout).
92
- let cur = process.cwd();
93
- for (let depth = 0; depth < 6; depth++) {
94
- candidates.push(path.join(cur, 'packages', 'web-ng', 'dist', 'web-ng', 'browser'));
95
- const parent = path.dirname(cur);
96
- if (parent === cur)
97
- break;
98
- cur = parent;
99
- }
100
- for (const c of candidates) {
101
- if (existsSync(path.join(c, 'index.html')))
102
- return c;
103
- }
104
- return null;
105
- }
106
64
  function tryOpenInBrowser(url) {
107
65
  const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
108
66
  try {
@@ -114,26 +72,24 @@ function tryOpenInBrowser(url) {
114
72
  }
115
73
  async function main() {
116
74
  const args = parseArgs();
117
- const webDir = args.noWeb ? null : locateWebDir(args.webDir);
75
+ const serveUi = !args.noWeb;
118
76
  const handle = await createServer({
119
77
  projectRoot: args.projectRoot ?? undefined,
120
78
  host: args.host,
121
79
  port: args.port,
122
80
  ingest: args.ingest,
123
81
  verbose: args.verbose,
124
- webDir,
82
+ webDir: null,
83
+ ssr: serveUi,
125
84
  });
126
85
  console.error(`[specship-desktop] listening on ${handle.url}`);
127
86
  if (args.projectRoot) {
128
87
  console.error(`[specship-desktop] project: ${args.projectRoot}`);
129
88
  }
130
89
  else {
131
- console.error(`[specship-desktop] project: (none — pick one in the desktop UI)`);
90
+ console.error(`[specship-desktop] project: (none — pick one in the dashboard)`);
132
91
  }
133
- if (webDir)
134
- console.error(`[specship-desktop] UI: ${webDir}`);
135
- else
136
- console.error(`[specship-desktop] UI: (none — running headless)`);
92
+ console.error(`[specship-desktop] UI: ${serveUi ? handle.url + '/ (server-rendered)' : '(none — running headless)'}`);
137
93
  if (args.ingest)
138
94
  console.error(`[specship-desktop] Claude Code transcript ingest active`);
139
95
  if (args.open)
@@ -97,6 +97,7 @@ export function listTranscriptFiles(claudeRoot) {
97
97
  * the ingestor seeds on first pass instead of failing silently.
98
98
  */
99
99
  const DEFAULT_PRICING = [
100
+ ['claude-fable-5', 10.0, 50.0, 12.5, 1.0],
100
101
  ['claude-opus-4-7', 15.0, 75.0, 18.75, 1.5],
101
102
  ['claude-opus-4', 15.0, 75.0, 18.75, 1.5],
102
103
  ['claude-sonnet-4-6', 3.0, 15.0, 3.75, 0.3],
@@ -105,25 +106,24 @@ const DEFAULT_PRICING = [
105
106
  ['claude-haiku-4-5', 0.80, 4.0, 1.0, 0.08],
106
107
  ['claude-haiku-4', 0.80, 4.0, 1.0, 0.08],
107
108
  ];
108
- /** Load the pricing table once per ingest pass. Seeds defaults if empty. */
109
- function loadPricing(db) {
110
- let rows = db
109
+ /**
110
+ * Load the pricing table once per ingest pass. Always INSERT OR IGNOREs the
111
+ * default rows first — self-healing for DBs seeded by an older binary that
112
+ * lacked newer model families (e.g. fable), while user-edited rates survive
113
+ * untouched (REQ-DASHINT-001).
114
+ */
115
+ export function loadPricing(db) {
116
+ const now = Date.now();
117
+ const ins = db.prepare(`
118
+ INSERT OR IGNORE INTO claude_pricing
119
+ (model, input_per_mtok, output_per_mtok, cache_creation_per_mtok, cache_read_per_mtok, updated_at)
120
+ VALUES (?, ?, ?, ?, ?, ?)
121
+ `);
122
+ for (const r of DEFAULT_PRICING)
123
+ ins.run(r[0], r[1], r[2], r[3], r[4], now);
124
+ return db
111
125
  .prepare('SELECT model, input_per_mtok, output_per_mtok, cache_creation_per_mtok, cache_read_per_mtok FROM claude_pricing')
112
126
  .all();
113
- if (rows.length === 0) {
114
- const now = Date.now();
115
- const ins = db.prepare(`
116
- INSERT OR IGNORE INTO claude_pricing
117
- (model, input_per_mtok, output_per_mtok, cache_creation_per_mtok, cache_read_per_mtok, updated_at)
118
- VALUES (?, ?, ?, ?, ?, ?)
119
- `);
120
- for (const r of DEFAULT_PRICING)
121
- ins.run(r[0], r[1], r[2], r[3], r[4], now);
122
- rows = db
123
- .prepare('SELECT model, input_per_mtok, output_per_mtok, cache_creation_per_mtok, cache_read_per_mtok FROM claude_pricing')
124
- .all();
125
- }
126
- return rows;
127
127
  }
128
128
  /**
129
129
  * Read a file's tail from `fromOffset` to end. Returns the full text plus
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Re-cost prompts that were ingested while their model had no pricing row
3
+ * (REQ-DASHINT-001.A2). Before the fable family was priced, every
4
+ * `claude-fable-5` prompt landed with `cost_usd = 0` despite real token
5
+ * usage — poisoning session totals, the dashboard's last-session tile, and
6
+ * the Costs/Compare rankings.
7
+ *
8
+ * Idempotent: only rows with `cost_usd = 0` AND non-zero tokens are
9
+ * touched, and only when their model now resolves to a pricing row with a
10
+ * non-zero computed cost. Session totals are bumped by the same delta the
11
+ * prompt rows gained. Run once per server boot (cheap: indexed scan).
12
+ */
13
+ import { loadPricing } from './ingestor.js';
14
+ import { computeCost, resolvePricing } from './pricing.js';
15
+ /** Returns the number of prompt rows re-costed. */
16
+ export function recostUnpricedPrompts(db) {
17
+ const pricingRows = loadPricing(db);
18
+ const candidates = db
19
+ .prepare(`
20
+ SELECT id, session_id, model, input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens
21
+ FROM claude_prompts
22
+ WHERE cost_usd = 0 AND model IS NOT NULL
23
+ AND (input_tokens > 0 OR output_tokens > 0 OR cache_creation_tokens > 0 OR cache_read_tokens > 0)
24
+ `)
25
+ .all();
26
+ if (candidates.length === 0)
27
+ return 0;
28
+ const updatePrompt = db.prepare('UPDATE claude_prompts SET cost_usd = ? WHERE id = ?');
29
+ const bumpSession = db.prepare('UPDATE claude_sessions SET total_cost_usd = total_cost_usd + ? WHERE id = ?');
30
+ let updated = 0;
31
+ const run = db.transaction(() => {
32
+ const sessionDeltas = new Map();
33
+ for (const row of candidates) {
34
+ const pricing = resolvePricing(row.model, pricingRows);
35
+ if (!pricing)
36
+ continue;
37
+ const cost = computeCost({
38
+ input_tokens: row.input_tokens,
39
+ output_tokens: row.output_tokens,
40
+ cache_creation_input_tokens: row.cache_creation_tokens,
41
+ cache_read_input_tokens: row.cache_read_tokens,
42
+ }, pricing);
43
+ if (cost <= 0)
44
+ continue;
45
+ updatePrompt.run(cost, row.id);
46
+ sessionDeltas.set(row.session_id, (sessionDeltas.get(row.session_id) ?? 0) + cost);
47
+ updated++;
48
+ }
49
+ for (const [sessionId, delta] of sessionDeltas) {
50
+ bumpSession.run(delta, sessionId);
51
+ }
52
+ });
53
+ run();
54
+ return updated;
55
+ }
@@ -15,6 +15,9 @@ const FAMILY_FALLBACKS = {
15
15
  opus: 'claude-opus-4',
16
16
  sonnet: 'claude-sonnet-4',
17
17
  haiku: 'claude-haiku-4',
18
+ fable: 'claude-fable-5',
19
+ // Claude Mythos shares Fable's capabilities and pricing.
20
+ mythos: 'claude-fable-5',
18
21
  };
19
22
  /**
20
23
  * Normalize a Claude model ID:
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Slug→path resolution for Claude Code project dirs (REQ-SLUGRES-001).
3
+ *
4
+ * Claude Code names `~/.claude/projects/<slug>` by replacing every character
5
+ * outside [A-Za-z0-9] in the project's absolute path with '-'. The encoding
6
+ * is lossy — '-', '/', '.', '_' all collapse into '-' — so decoding by
7
+ * mapping '-' back to '/' mangles any real path containing those characters
8
+ * (`/Users/a/dev/claude-projects/x` → `/Users/a/dev/claude/projects/x`).
9
+ *
10
+ * Real paths are recovered from authoritative local sources instead:
11
+ * 1. `~/.claude.json` — its `projects` object is keyed by real absolute
12
+ * paths. We slug-encode each key into a reverse index.
13
+ * 2. Transcript sniffing — JSONL lines carry a `"cwd"` field; a cwd (or
14
+ * one of its ancestors) whose encoding equals the slug is the real path.
15
+ * 3. The legacy lossy decode, preserving behavior for hyphen-free paths.
16
+ */
17
+ import * as fs from 'fs';
18
+ import * as os from 'os';
19
+ import * as path from 'path';
20
+ import { decodeProjectSlug } from './ingestor.js';
21
+ /** Claude Code's encoding: every char outside [A-Za-z0-9] becomes '-'. */
22
+ export function encodeProjectSlug(realPath) {
23
+ return realPath.replace(/[^A-Za-z0-9]/g, '-');
24
+ }
25
+ /** Max bytes read per transcript while sniffing for a cwd line. */
26
+ const SNIFF_BYTES = 64 * 1024;
27
+ /** Newest transcripts to try per slug before giving up. */
28
+ const SNIFF_FILES = 3;
29
+ // Keyed by claudeJsonPath so tests with distinct temp files don't collide.
30
+ const indexCache = new Map();
31
+ /**
32
+ * Reverse index of slug → real path from `~/.claude.json`'s projects keys.
33
+ * Cached per file and refreshed when the file's mtime changes. Any read or
34
+ * parse failure yields an empty index (the caller falls through to sniffing).
35
+ */
36
+ function claudeJsonIndex(claudeJsonPath) {
37
+ let mtimeMs;
38
+ try {
39
+ mtimeMs = fs.statSync(claudeJsonPath).mtimeMs;
40
+ }
41
+ catch {
42
+ return new Map();
43
+ }
44
+ const cached = indexCache.get(claudeJsonPath);
45
+ if (cached && cached.mtimeMs === mtimeMs)
46
+ return cached.bySlug;
47
+ const bySlug = new Map();
48
+ try {
49
+ const parsed = JSON.parse(fs.readFileSync(claudeJsonPath, 'utf8'));
50
+ for (const realPath of Object.keys(parsed.projects ?? {})) {
51
+ bySlug.set(encodeProjectSlug(realPath), realPath);
52
+ }
53
+ }
54
+ catch {
55
+ /* malformed — serve the empty index, retry on next mtime change */
56
+ }
57
+ indexCache.set(claudeJsonPath, { mtimeMs, bySlug });
58
+ return bySlug;
59
+ }
60
+ /**
61
+ * Scan the newest transcripts in `<claudeRoot>/<slug>/` for a `"cwd"` whose
62
+ * encoding matches the slug. Bounded read (first SNIFF_BYTES of up to
63
+ * SNIFF_FILES files). Also accepts an ancestor of the cwd — sessions can
64
+ * record a subdirectory cwd while the slug is for the project root.
65
+ */
66
+ function sniffCwd(claudeRoot, slug) {
67
+ const dir = path.join(claudeRoot, slug);
68
+ let files;
69
+ try {
70
+ files = fs
71
+ .readdirSync(dir, { withFileTypes: true })
72
+ .filter((f) => f.isFile() && f.name.toLowerCase().endsWith('.jsonl'))
73
+ .map((f) => {
74
+ try {
75
+ return { name: f.name, mtimeMs: fs.statSync(path.join(dir, f.name)).mtimeMs };
76
+ }
77
+ catch {
78
+ return { name: f.name, mtimeMs: 0 };
79
+ }
80
+ });
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ files.sort((a, b) => b.mtimeMs - a.mtimeMs);
86
+ const cwdRe = /"cwd"\s*:\s*"((?:[^"\\]|\\.)*)"/g;
87
+ for (const f of files.slice(0, SNIFF_FILES)) {
88
+ let chunk;
89
+ try {
90
+ const fd = fs.openSync(path.join(dir, f.name), 'r');
91
+ try {
92
+ const buf = Buffer.alloc(SNIFF_BYTES);
93
+ const read = fs.readSync(fd, buf, 0, SNIFF_BYTES, 0);
94
+ chunk = buf.toString('utf8', 0, read);
95
+ }
96
+ finally {
97
+ fs.closeSync(fd);
98
+ }
99
+ }
100
+ catch {
101
+ continue;
102
+ }
103
+ cwdRe.lastIndex = 0;
104
+ for (let m = cwdRe.exec(chunk); m; m = cwdRe.exec(chunk)) {
105
+ let cwd;
106
+ try {
107
+ cwd = JSON.parse(`"${m[1]}"`);
108
+ }
109
+ catch {
110
+ continue;
111
+ }
112
+ // Exact match, then walk up: a subdir cwd still identifies the root.
113
+ for (let p = cwd;;) {
114
+ if (encodeProjectSlug(p) === slug)
115
+ return p;
116
+ const parent = path.dirname(p);
117
+ if (parent === p)
118
+ break;
119
+ p = parent;
120
+ }
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+ /**
126
+ * Build a resolver closure. Positive sniff results are memoized per slug so
127
+ * per-request resolution stays cheap; the claude.json index refreshes on
128
+ * mtime change (REQ-SLUGRES-001).
129
+ */
130
+ export function createSlugResolver(opts = {}) {
131
+ const claudeJsonPath = opts.claudeJsonPath ?? path.join(os.homedir(), '.claude.json');
132
+ const claudeRoot = opts.claudeRoot ?? path.join(os.homedir(), '.claude', 'projects');
133
+ const sniffed = new Map();
134
+ return (slug) => {
135
+ const fromIndex = claudeJsonIndex(claudeJsonPath).get(slug);
136
+ if (fromIndex)
137
+ return fromIndex;
138
+ const cached = sniffed.get(slug);
139
+ if (cached)
140
+ return cached;
141
+ const fromCwd = sniffCwd(claudeRoot, slug);
142
+ if (fromCwd) {
143
+ sniffed.set(slug, fromCwd);
144
+ return fromCwd;
145
+ }
146
+ return decodeProjectSlug(slug);
147
+ };
148
+ }
149
+ /** One-shot convenience for callers without a resolver to hold on to. */
150
+ export function resolveProjectSlug(slug, opts = {}) {
151
+ return createSlugResolver(opts)(slug);
152
+ }
@@ -14,16 +14,19 @@
14
14
  * "primary" instance instead, since their data (JSONL ingest, CLAUDE.md
15
15
  * hierarchy) is global to the user, not scoped to one project.
16
16
  */
17
- import { decodeProjectSlug } from './ingest/ingestor.js';
17
+ import { createSlugResolver } from './ingest/project-paths.js';
18
18
  export class ProjectRegistry {
19
19
  cache = new Map();
20
+ pinned = new Set();
20
21
  maxOpen;
21
22
  verbose;
22
23
  openImpl;
24
+ resolveSlug;
23
25
  constructor(opts, defaultOpenImpl) {
24
26
  this.maxOpen = opts.maxOpen ?? 5;
25
27
  this.verbose = opts.verbose ?? false;
26
28
  this.openImpl = opts.openImpl ?? defaultOpenImpl;
29
+ this.resolveSlug = opts.resolveSlug ?? createSlugResolver();
27
30
  }
28
31
  /**
29
32
  * Return the cached SpecShip for `projectPath`, opening it on demand.
@@ -55,7 +58,7 @@ export class ProjectRegistry {
55
58
  * (`-Users-alice-foo` → `/Users/alice/foo`).
56
59
  */
57
60
  async getBySlug(slug) {
58
- return this.get(decodeProjectSlug(slug));
61
+ return this.get(this.resolveSlug(slug));
59
62
  }
60
63
  /** Currently-cached project paths (most-recent-access first). */
61
64
  openPaths() {
@@ -64,6 +67,14 @@ export class ProjectRegistry {
64
67
  .map(([k]) => k);
65
68
  }
66
69
  has(projectPath) { return this.cache.has(projectPath); }
70
+ /**
71
+ * Exempt `projectPath` from LRU eviction. The server pins its primary:
72
+ * routes capture the primary instance by reference (`app.primaryCg`), so
73
+ * an eviction CLOSES a handle they still use and every request 500s with
74
+ * "database connection is not open". Surfaced when the /api/events sweep
75
+ * started opening many projects through this cache.
76
+ */
77
+ pin(projectPath) { this.pinned.add(projectPath); }
67
78
  /** Close + drop every cached instance. Called on server shutdown. */
68
79
  closeAll() {
69
80
  for (const [, v] of this.cache) {
@@ -80,6 +91,8 @@ export class ProjectRegistry {
80
91
  let oldestKey = null;
81
92
  let oldestTime = Infinity;
82
93
  for (const [k, v] of this.cache) {
94
+ if (this.pinned.has(k))
95
+ continue; // never close a pinned instance
83
96
  if (v.lastAccess < oldestTime) {
84
97
  oldestTime = v.lastAccess;
85
98
  oldestKey = k;
@@ -69,6 +69,20 @@ function priorWindow(key) {
69
69
  * Claude-specific aggregate queries directly. SpecShip exposes this via
70
70
  * `getDb()`-style accessors. Falls back to digging via the queries property.
71
71
  */
72
+ /**
73
+ * SQL expression extracting `path` from a tool call's input JSON. Prefers
74
+ * the full v7 `input_json` column and falls back to `input_summary`; BOTH
75
+ * are guarded with json_valid() because input_summary is truncated to 400
76
+ * chars by the ingestor — long inputs are malformed JSON and an unguarded
77
+ * json_extract throws SQLITE_ERROR, 500ing the route (REQ-DASHINT-003).
78
+ * `col` is the optional table alias prefix (e.g. 't.').
79
+ */
80
+ function jsonInputExtract(path, col = '') {
81
+ return `COALESCE(
82
+ CASE WHEN json_valid(${col}input_json) THEN json_extract(${col}input_json, '${path}') END,
83
+ CASE WHEN json_valid(${col}input_summary) THEN json_extract(${col}input_summary, '${path}') END
84
+ )`;
85
+ }
72
86
  function getDb(cg) {
73
87
  // SpecShip exposes the underlying DB via its DatabaseConnection. Look it
74
88
  // up via the private field as a fallback — works because it's the same
@@ -309,13 +323,20 @@ export async function registerClaudeRoutes(app) {
309
323
  ORDER BY ops DESC
310
324
  LIMIT 30
311
325
  `).all(sessionId);
312
- // Skills invoked via the Skill tool. The ingestor stashes the
313
- // JSON-serialized input under input_summary, so json_extract pulls the
314
- // skill name straight out without needing the v7 input_json column to
315
- // be backfilled.
326
+ // Skills invoked via the Skill tool. Read the skill name from the full
327
+ // v7 `input_json` column first — `input_summary` is truncated to 400
328
+ // chars by the ingestor, so long inputs are INVALID JSON and a bare
329
+ // json_extract on them throws SQLITE_ERROR ("malformed JSON"), 500ing
330
+ // the whole summary (REQ-DASHINT-003). Every extraction is guarded by
331
+ // json_valid(); rows malformed in both columns degrade to 'unknown'.
316
332
  const skills = db.prepare(`
317
333
  SELECT
318
- COALESCE(json_extract(input_summary, '$.skill'), json_extract(input_summary, '$.skill_name'), 'unknown') as name,
334
+ COALESCE(
335
+ CASE WHEN json_valid(input_json)
336
+ THEN COALESCE(json_extract(input_json, '$.skill'), json_extract(input_json, '$.skill_name')) END,
337
+ CASE WHEN json_valid(input_summary)
338
+ THEN COALESCE(json_extract(input_summary, '$.skill'), json_extract(input_summary, '$.skill_name')) END,
339
+ 'unknown') as name,
319
340
  COUNT(*) as count
320
341
  FROM claude_tool_calls
321
342
  WHERE session_id = ? AND tool_name = 'Skill'
@@ -421,12 +442,12 @@ export async function registerClaudeRoutes(app) {
421
442
  WHERE p.ts >= ?
422
443
  GROUP BY type
423
444
  `).all(since);
424
- // Subagent breakdown by name — Task tool calls grouped by subagent_type.
425
- // input_summary is the JSON-serialized tool input; json_extract pulls
426
- // out subagent_type (defaults to 'general-purpose' when unset).
445
+ // Subagent breakdown by name — Task tool calls grouped by subagent_type
446
+ // (defaults to 'general-purpose' when unset). Guarded extraction: Task
447
+ // inputs carry long prompts, so input_summary is almost always truncated.
427
448
  const subagentByName = db.prepare(`
428
449
  SELECT
429
- COALESCE(NULLIF(json_extract(input_summary, '$.subagent_type'), ''), 'general-purpose') as name,
450
+ COALESCE(NULLIF(${jsonInputExtract('$.subagent_type')}, ''), 'general-purpose') as name,
430
451
  COUNT(*) as calls,
431
452
  MIN(ts) as firstSeen,
432
453
  MAX(ts) as lastSeen
@@ -529,19 +550,19 @@ export async function registerClaudeRoutes(app) {
529
550
  SELECT COUNT(*) as calls, COUNT(DISTINCT session_id) as sessions
530
551
  FROM claude_tool_calls
531
552
  WHERE tool_name = 'Task' AND ts >= ?
532
- AND COALESCE(NULLIF(json_extract(input_summary, '$.subagent_type'), ''), 'general-purpose') = ?
553
+ AND COALESCE(NULLIF(${jsonInputExtract('$.subagent_type')}, ''), 'general-purpose') = ?
533
554
  `).get(since, type);
534
555
  const invocations = db.prepare(`
535
556
  SELECT
536
557
  t.session_id,
537
558
  t.ts,
538
- COALESCE(json_extract(t.input_summary, '$.description'), '') as description,
539
- COALESCE(json_extract(t.input_summary, '$.prompt'), '') as prompt,
559
+ COALESCE(${jsonInputExtract('$.description', 't.')}, '') as description,
560
+ COALESCE(${jsonInputExtract('$.prompt', 't.')}, '') as prompt,
540
561
  s.last_model
541
562
  FROM claude_tool_calls t
542
563
  LEFT JOIN claude_sessions s ON s.id = t.session_id
543
564
  WHERE t.tool_name = 'Task' AND t.ts >= ?
544
- AND COALESCE(NULLIF(json_extract(t.input_summary, '$.subagent_type'), ''), 'general-purpose') = ?
565
+ AND COALESCE(NULLIF(${jsonInputExtract('$.subagent_type', 't.')}, ''), 'general-purpose') = ?
545
566
  ORDER BY t.ts DESC
546
567
  LIMIT 50
547
568
  `).all(since, type);
@@ -798,17 +819,24 @@ export async function registerClaudeRoutes(app) {
798
819
  return;
799
820
  const db = getDb(cg);
800
821
  const tips = [];
822
+ // The claude_* tables span every project's sessions; tips for the primary
823
+ // project must cite only its own (REQ-DASHINT-006). Sessions store the
824
+ // project path in the mangled slug round-trip form, so match both it and
825
+ // the real path.
826
+ const realRoot = (cg.getProjectRoot ? cg.getProjectRoot() : '').replace(/\/+$/, '');
827
+ const mangledRoot = realRoot.replace(/[^A-Za-z0-9]/g, '/');
828
+ const inProject = `session_id IN (SELECT id FROM claude_sessions WHERE project_path IN (?, ?))`;
801
829
  // Rule 1: "you read X N times" — same file path Read more than 10 times in
802
830
  // a single session.
803
831
  const wastefulReads = db.prepare(`
804
832
  SELECT session_id, input_summary as file, COUNT(*) as n
805
833
  FROM claude_tool_calls
806
- WHERE tool_name = 'Read' AND input_summary != ''
834
+ WHERE tool_name = 'Read' AND input_summary != '' AND ${inProject}
807
835
  GROUP BY session_id, input_summary
808
836
  HAVING n >= 10
809
837
  ORDER BY n DESC
810
838
  LIMIT 5
811
- `).all();
839
+ `).all(realRoot, mangledRoot);
812
840
  for (const r of wastefulReads) {
813
841
  tips.push({
814
842
  id: 'wasteful_reads:' + r.session_id + ':' + r.file,
@@ -825,10 +853,10 @@ export async function registerClaudeRoutes(app) {
825
853
  const heavyResults = db.prepare(`
826
854
  SELECT id, session_id, tool_name, input_summary, result_length
827
855
  FROM claude_tool_calls
828
- WHERE result_length > 50000
856
+ WHERE result_length > 50000 AND ${inProject}
829
857
  ORDER BY result_length DESC
830
858
  LIMIT 5
831
- `).all();
859
+ `).all(realRoot, mangledRoot);
832
860
  for (const r of heavyResults) {
833
861
  tips.push({
834
862
  id: 'heavy_result:' + r.id,
@@ -847,9 +875,10 @@ export async function registerClaudeRoutes(app) {
847
875
  FROM claude_sessions s
848
876
  WHERE s.prompt_count >= 10
849
877
  AND (s.total_input_tokens + s.total_cache_creation_tokens + s.total_cache_read_tokens) > 0
878
+ AND s.project_path IN (?, ?)
850
879
  ORDER BY (CAST(s.total_cache_read_tokens AS REAL) / (s.total_input_tokens + s.total_cache_creation_tokens + s.total_cache_read_tokens)) ASC
851
880
  LIMIT 3
852
- `).all();
881
+ `).all(realRoot, mangledRoot);
853
882
  for (const r of lowCache) {
854
883
  const total = r.ti + r.cw + r.cr;
855
884
  const rate = total > 0 ? r.cr / total : 0;
@@ -32,6 +32,7 @@ export async function registerEventsRoutes(app) {
32
32
  const lastStatus = new Map(); // `${slug}:${runId}` -> status
33
33
  const seenDrift = new Set(); // `${slug}:${linkId}`
34
34
  const lastSweep = new Map(); // slug -> last reflection sweep ms
35
+ const lastIndexSig = new Map(); // slug -> lastIndexed signature
35
36
  let primed = false; // first pass seeds state silently (no burst on connect)
36
37
  let closed = false;
37
38
  const send = (ev) => {
@@ -50,8 +51,13 @@ export async function registerEventsRoutes(app) {
50
51
  catch {
51
52
  return;
52
53
  }
54
+ // Bound the sweep to the most-recently-active initialized projects
55
+ // (enumerate() sorts by recency): every project here is opened via the
56
+ // registry, and an unbounded sweep churns the LRU open/close cycle on
57
+ // every poll once slugs resolve to real paths.
58
+ projects = projects.filter((p) => p.initialized).slice(0, 10);
53
59
  for (const p of projects) {
54
- if (!p.initialized || closed)
60
+ if (closed)
55
61
  continue;
56
62
  let cg;
57
63
  try {
@@ -83,6 +89,19 @@ export async function registerEventsRoutes(app) {
83
89
  send({ kind: 'runDone', project: p.slug, projectPath: p.path, id: r.id, title: `Run ${r.status}`, detail: r.workflowName, status: r.status });
84
90
  }
85
91
  }
92
+ // Index/ingest activity (REQ-DASHUX-004): emit when the project's
93
+ // index freshness changes so open pages can refetch instead of
94
+ // going stale between manual refreshes.
95
+ try {
96
+ const sig = String(cg.getLastIndexedAt() ?? '');
97
+ if (lastIndexSig.get(p.slug) !== sig) {
98
+ lastIndexSig.set(p.slug, sig);
99
+ if (primed) {
100
+ send({ kind: 'activity', project: p.slug, projectPath: p.path, id: sig, title: 'Index updated' });
101
+ }
102
+ }
103
+ }
104
+ catch { /* ignore — activity detection must not break the stream */ }
86
105
  // Newly-drifted links.
87
106
  let links = [];
88
107
  try {