@gobing-ai/spur 0.4.8 → 0.4.10

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 (211) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/pipeline-budgets.json +2 -2
  3. package/config/rules/README.md +1 -1
  4. package/config/rules/boundary/config-loading-ownership.yaml +1 -0
  5. package/config/rules/boundary/env-var-hygiene.yaml +0 -1
  6. package/config/rules/boundary/sp-plugin-standalone.yaml +1 -1
  7. package/config/rules/boundary/sp-script-placement.yaml +3 -3
  8. package/config/rules/docs/sourced-api-claims.yaml +29 -64
  9. package/config/rules/strict/runtime-boundaries.yaml +40 -1
  10. package/config/rules/structure/protected-files.yaml +1 -1
  11. package/config/rules/surface/check-cli-surface.yaml +33 -0
  12. package/config/rules/typescript/no-debugger.yaml +3 -0
  13. package/config/workflow-candidates.json +2 -2
  14. package/config/workflows/feature-verification.yaml +6 -19
  15. package/config/workflows/history-anatomy.yaml +14 -28
  16. package/config/workflows/idea-pipeline.yaml +6 -19
  17. package/config/workflows/pr-review.yaml +9 -16
  18. package/config/workflows/task-pipeline.yaml +18 -25
  19. package/config/workflows/wrapup-pipeline.yaml +21 -63
  20. package/package.json +3 -3
  21. package/plugins/sp/README.md +70 -37
  22. package/plugins/sp/agents/expert-spur.md +0 -1
  23. package/plugins/sp/agents/super-planner.md +5 -5
  24. package/plugins/sp/agents/super-reviewer.md +2 -2
  25. package/plugins/sp/commands/dev-changelog.md +1 -1
  26. package/plugins/sp/commands/dev-daily.md +1 -1
  27. package/plugins/sp/commands/dev-pr-review.md +1 -1
  28. package/plugins/sp/commands/dev-review-session.md +1 -1
  29. package/plugins/sp/commands/dev-runall.md +4 -4
  30. package/plugins/sp/commands/dev-verify.md +4 -6
  31. package/plugins/sp/commands/dev-verifyall.md +4 -5
  32. package/plugins/sp/hooks/hooks.json +11 -1
  33. package/plugins/sp/lib/context-post-tool.ts +1 -1
  34. package/plugins/sp/lib/context-session-start.ts +1 -1
  35. package/plugins/sp/lib/context-session-stop.ts +1 -1
  36. package/plugins/sp/lib/destructive-policy.ts +65 -1
  37. package/plugins/sp/plugin.json +2 -5
  38. package/plugins/sp/{hooks → scripts/hooks}/agent-lifecycle.ts +1 -1
  39. package/plugins/sp/scripts/hooks/careful-guard.ts +94 -0
  40. package/plugins/sp/{hooks → scripts/hooks}/context-post-tool.ts +2 -2
  41. package/plugins/sp/{hooks → scripts/hooks}/context-session-start.ts +1 -1
  42. package/plugins/sp/{hooks → scripts/hooks}/context-session-stop.ts +1 -1
  43. package/plugins/sp/{hooks → scripts/hooks}/fleet-guest-stop.ts +6 -4
  44. package/plugins/sp/{hooks → scripts/hooks}/task-write-guard.ts +38 -21
  45. package/plugins/sp/skills/brainstorm/SKILL.md +12 -11
  46. package/plugins/sp/skills/brainstorm/agents/openai.yaml +1 -1
  47. package/plugins/sp/skills/brainstorm/examples/ideation-example.md +0 -4
  48. package/plugins/sp/skills/brainstorm/metadata.openclaw +1 -1
  49. package/plugins/sp/skills/brainstorm/references/workflows.md +4 -14
  50. package/plugins/sp/skills/code-implementation/SKILL.md +1 -1
  51. package/plugins/sp/skills/code-verification/SKILL.md +8 -8
  52. package/plugins/sp/skills/code-verification/references/secu-review.md +4 -4
  53. package/plugins/sp/skills/code-verification/references/verdict-schema.md +9 -1
  54. package/plugins/sp/skills/daily-summary/SKILL.md +4 -5
  55. package/plugins/sp/skills/dogfood-testing/SKILL.md +9 -9
  56. package/plugins/sp/skills/dogfood-testing/references/report-template.md +1 -1
  57. package/plugins/sp/skills/history-anatomy/references/modes.md +2 -2
  58. package/plugins/sp/skills/history-anatomy/references/operations.md +3 -4
  59. package/plugins/sp/skills/history-anatomy/references/report-contract.md +2 -3
  60. package/plugins/sp/skills/issue-finding/SKILL.md +1 -1
  61. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  62. package/plugins/sp/skills/parallel-execution/SKILL.md +2 -2
  63. package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +9 -10
  64. package/plugins/sp/skills/pr-reviewing/SKILL.md +14 -15
  65. package/plugins/sp/skills/reverse-engineering/SKILL.md +4 -6
  66. package/plugins/sp/skills/session-review/SKILL.md +13 -29
  67. package/plugins/sp/skills/source-driven-development/SKILL.md +26 -27
  68. package/plugins/sp/skills/spur-check/SKILL.md +14 -13
  69. package/plugins/sp/skills/spur-cli/SKILL.md +1 -1
  70. package/plugins/sp/skills/spur-cli/references/agent.md +17 -2
  71. package/plugins/sp/skills/spur-cli/references/builder.md +27 -6
  72. package/plugins/sp/skills/spur-cli/references/features.md +6 -1
  73. package/plugins/sp/skills/spur-cli/references/history.md +3 -0
  74. package/plugins/sp/skills/spur-cli/references/self.md +5 -3
  75. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +3 -0
  76. package/plugins/sp/skills/spur-cli/references/tasks.md +13 -3
  77. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +1 -1
  78. package/plugins/sp/skills/spur-cli/references/workflows.md +36 -1
  79. package/plugins/sp/skills/spur-dev/SKILL.md +1 -1
  80. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +1 -1
  81. package/plugins/sp/skills/spur-dev/references/dev-operations.md +12 -13
  82. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +10 -11
  83. package/plugins/sp/skills/spur-dev/references/execution-batch.md +16 -17
  84. package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +1 -1
  85. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +9 -12
  86. package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +6 -8
  87. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -1
  88. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +33 -40
  89. package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +24 -24
  90. package/plugins/sp/skills/spur-doctor/SKILL.md +5 -4
  91. package/spur.js +12726 -1456
  92. package/web/_astro/{BoardApp.CaNvQBD_.js → BoardApp.B5rTVNd_.js} +1 -1
  93. package/web/_astro/{BoardApp.C5jnkkKP.js → BoardApp.BMprmPRc.js} +141 -141
  94. package/web/_astro/{TaskDetail.DGKndhI8.js → TaskDetail.Ddsur8qd.js} +1 -1
  95. package/web/_astro/{arc.DHrwdg3G.js → arc.DLqVVBxP.js} +1 -1
  96. package/web/_astro/{architectureDiagram-3BPJPVTR.pvKpK1s5.js → architectureDiagram-3BPJPVTR.C-Pk3uAi.js} +1 -1
  97. package/web/_astro/{blockDiagram-GPEHLZMM.BQmRcZsS.js → blockDiagram-GPEHLZMM.BRO1i_Nm.js} +1 -1
  98. package/web/_astro/{c4Diagram-AAUBKEIU.CCLjHeH1.js → c4Diagram-AAUBKEIU.BU_cWu6e.js} +1 -1
  99. package/web/_astro/channel.Bs3Illhy.js +1 -0
  100. package/web/_astro/{chunk-2J33WTMH.DL6Yuoma.js → chunk-2J33WTMH.D2VXiQ2t.js} +1 -1
  101. package/web/_astro/{chunk-4BX2VUAB.CzlyEI7l.js → chunk-4BX2VUAB.BcHT772J.js} +1 -1
  102. package/web/_astro/{chunk-55IACEB6.B60EWxp1.js → chunk-55IACEB6.DhDtICmo.js} +1 -1
  103. package/web/_astro/{chunk-727SXJPM.c7v_fRLo.js → chunk-727SXJPM.BoKHp7gV.js} +1 -1
  104. package/web/_astro/{chunk-AQP2D5EJ.8BxLWdDc.js → chunk-AQP2D5EJ.Chu4JRpE.js} +1 -1
  105. package/web/_astro/{chunk-FMBD7UC4.DmKuxGFT.js → chunk-FMBD7UC4.wHdwKPlq.js} +1 -1
  106. package/web/_astro/{chunk-ND2GUHAM.1Zwd4mqV.js → chunk-ND2GUHAM.ffN-M1JB.js} +1 -1
  107. package/web/_astro/{chunk-QZHKN3VN.BvYLu-A1.js → chunk-QZHKN3VN.FRubwg4S.js} +1 -1
  108. package/web/_astro/{classDiagram-4FO5ZUOK.CEqRt0WU.js → classDiagram-4FO5ZUOK.c22tQsc_.js} +1 -1
  109. package/web/_astro/{classDiagram-v2-Q7XG4LA2.CEqRt0WU.js → classDiagram-v2-Q7XG4LA2.c22tQsc_.js} +1 -1
  110. package/web/_astro/{cose-bilkent-S5V4N54A.C7JiUdj2.js → cose-bilkent-S5V4N54A.B9c6fiSj.js} +1 -1
  111. package/web/_astro/{cynefin-OW5HDTMX.B6mZ-1be.js → cynefin-OW5HDTMX.DrZsrUHl.js} +1 -1
  112. package/web/_astro/{dagre-BM42HDAG.BuryfDy6.js → dagre-BM42HDAG.DG1U4b3y.js} +1 -1
  113. package/web/_astro/{diagram-2AECGRRQ.dao39YQM.js → diagram-2AECGRRQ.CH15b-K3.js} +1 -1
  114. package/web/_astro/{diagram-5GNKFQAL.lnGZe4At.js → diagram-5GNKFQAL.BH1j7twR.js} +1 -1
  115. package/web/_astro/{diagram-KO2AKTUF.uWfhzEfT.js → diagram-KO2AKTUF.q2zCkbAj.js} +1 -1
  116. package/web/_astro/{diagram-LMA3HP47.ppq8-198.js → diagram-LMA3HP47.BLaaZnHV.js} +1 -1
  117. package/web/_astro/{diagram-OG6HWLK6.CKSCqDt5.js → diagram-OG6HWLK6.BcpRdQwI.js} +1 -1
  118. package/web/_astro/{erDiagram-TEJ5UH35.sFSf2yBN.js → erDiagram-TEJ5UH35.D7KBlqfM.js} +1 -1
  119. package/web/_astro/{flowDiagram-I6XJVG4X.BJQjKLbz.js → flowDiagram-I6XJVG4X.D_gmuRqg.js} +1 -1
  120. package/web/_astro/{ganttDiagram-6RSMTGT7.DAHKNj2N.js → ganttDiagram-6RSMTGT7.DzgWYniD.js} +1 -1
  121. package/web/_astro/{gitGraphDiagram-PVQCEYII.BlmzcW_O.js → gitGraphDiagram-PVQCEYII.576i3hm3.js} +1 -1
  122. package/web/_astro/index.DiC1a6lh.css +1 -0
  123. package/web/_astro/{infoDiagram-5YYISTIA.DGhjaqsi.js → infoDiagram-5YYISTIA.DMCclBiz.js} +1 -1
  124. package/web/_astro/{ishikawaDiagram-YF4QCWOH.gKIpgt6F.js → ishikawaDiagram-YF4QCWOH.9Kyca4SH.js} +1 -1
  125. package/web/_astro/{journeyDiagram-JHISSGLW.DG3tmP0R.js → journeyDiagram-JHISSGLW.chbdG-8q.js} +1 -1
  126. package/web/_astro/{kanban-definition-UN3LZRKU.CgHDSxkR.js → kanban-definition-UN3LZRKU.Bds54-e0.js} +1 -1
  127. package/web/_astro/{linear.BuGEpcuM.js → linear.D5ND9GN_.js} +1 -1
  128. package/web/_astro/{mermaid.core.DBVqkWBp.js → mermaid.core.D9N_PGbj.js} +4 -4
  129. package/web/_astro/{mindmap-definition-RKZ34NQL.D-kOcji9.js → mindmap-definition-RKZ34NQL.t0xop5vp.js} +1 -1
  130. package/web/_astro/{pieDiagram-4H26LBE5.BvGPwtZt.js → pieDiagram-4H26LBE5.DqgKh6hM.js} +1 -1
  131. package/web/_astro/{quadrantDiagram-W4KKPZXB.BKb_9FV6.js → quadrantDiagram-W4KKPZXB.DeuHVi2t.js} +1 -1
  132. package/web/_astro/{requirementDiagram-4Y6WPE33.Cx0fvD8v.js → requirementDiagram-4Y6WPE33.BdYFSG4W.js} +1 -1
  133. package/web/_astro/{sankeyDiagram-5OEKKPKP.fatULi0W.js → sankeyDiagram-5OEKKPKP.k1LPPETJ.js} +1 -1
  134. package/web/_astro/{sequenceDiagram-3UESZ5HK.ChHyKqco.js → sequenceDiagram-3UESZ5HK.DdyfpzoG.js} +1 -1
  135. package/web/_astro/{stateDiagram-AJRCARHV.BdUpKWyj.js → stateDiagram-AJRCARHV.DSEI8il0.js} +1 -1
  136. package/web/_astro/{stateDiagram-v2-BHNVJYJU.fmJxqIm5.js → stateDiagram-v2-BHNVJYJU.CoMnQRKo.js} +1 -1
  137. package/web/_astro/{timeline-definition-PNZ67QCA.BayDn5-V.js → timeline-definition-PNZ67QCA.DM1AHNm-.js} +1 -1
  138. package/web/_astro/{vennDiagram-CIIHVFJN.Bm2Aggwa.js → vennDiagram-CIIHVFJN.C-cJmVtl.js} +1 -1
  139. package/web/_astro/{wardleyDiagram-YWT4CUSO.DI75O-uG.js → wardleyDiagram-YWT4CUSO.D0xMzKPb.js} +1 -1
  140. package/web/_astro/{xychartDiagram-2RQKCTM6.DL90E7Q7.js → xychartDiagram-2RQKCTM6.BH5xJcEq.js} +1 -1
  141. package/web/index.html +2 -2
  142. package/config/plugin-scripts.json +0 -116
  143. package/config/script-placement-baseline.json +0 -33
  144. package/plugins/sp/hooks/careful-guard.ts +0 -74
  145. package/plugins/sp/hooks/pi/guard-extension.ts +0 -304
  146. package/plugins/sp/lib/dogfood-pipeline.ts +0 -265
  147. package/plugins/sp/lib/dogfood-report.ts +0 -278
  148. package/plugins/sp/lib/history-anatomy.generated.d.mts +0 -112
  149. package/plugins/sp/lib/history-anatomy.generated.mjs +0 -691
  150. package/plugins/sp/lib/idea-handoff.generated.d.mts +0 -17
  151. package/plugins/sp/lib/idea-handoff.generated.mjs +0 -1446
  152. package/plugins/sp/lib/inline-run-app.ts +0 -68
  153. package/plugins/sp/lib/inline-run.generated.d.mts +0 -37
  154. package/plugins/sp/lib/inline-run.generated.mjs +0 -3103
  155. package/plugins/sp/lib/plan-projection.generated.d.mts +0 -197
  156. package/plugins/sp/lib/plan-projection.generated.mjs +0 -982
  157. package/plugins/sp/lib/quality-gate.generated.d.mts +0 -139
  158. package/plugins/sp/lib/quality-gate.generated.mjs +0 -30510
  159. package/plugins/sp/lib/residual-scan.generated.d.mts +0 -93
  160. package/plugins/sp/lib/residual-scan.generated.mjs +0 -383
  161. package/plugins/sp/lib/run-summary-core.ts +0 -225
  162. package/plugins/sp/lib/spur-bin.ts +0 -36
  163. package/plugins/sp/lib/step-profile.generated.d.mts +0 -71
  164. package/plugins/sp/lib/step-profile.generated.mjs +0 -174
  165. package/plugins/sp/lib/transcript.ts +0 -112
  166. package/plugins/sp/scripts/batch-plan.mjs +0 -1096
  167. package/plugins/sp/scripts/batch-plan.ts +0 -145
  168. package/plugins/sp/scripts/batch-preflight.mjs +0 -423
  169. package/plugins/sp/scripts/batch-preflight.ts +0 -270
  170. package/plugins/sp/scripts/commit-guard.mjs +0 -226
  171. package/plugins/sp/scripts/commit-guard.ts +0 -248
  172. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +0 -626
  173. package/plugins/sp/scripts/daily-summary/daily-summary.ts +0 -855
  174. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +0 -211
  175. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +0 -110
  176. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +0 -282
  177. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +0 -98
  178. package/plugins/sp/scripts/feature-verification-steps.mjs +0 -82
  179. package/plugins/sp/scripts/feature-verification-steps.ts +0 -164
  180. package/plugins/sp/scripts/history-anatomy-cache.mjs +0 -931
  181. package/plugins/sp/scripts/history-anatomy-cache.ts +0 -247
  182. package/plugins/sp/scripts/idea-handoff.mjs +0 -32
  183. package/plugins/sp/scripts/idea-handoff.ts +0 -47
  184. package/plugins/sp/scripts/inline-run-dispatch.mjs +0 -131
  185. package/plugins/sp/scripts/inline-run-dispatch.ts +0 -115
  186. package/plugins/sp/scripts/inline-run-setup.mjs +0 -746
  187. package/plugins/sp/scripts/inline-run-setup.ts +0 -198
  188. package/plugins/sp/scripts/persist-out-check.mjs +0 -217
  189. package/plugins/sp/scripts/persist-out-check.ts +0 -249
  190. package/plugins/sp/scripts/pr-reviewing.mjs +0 -712
  191. package/plugins/sp/scripts/pr-reviewing.ts +0 -952
  192. package/plugins/sp/scripts/quality-gate.mjs +0 -30491
  193. package/plugins/sp/scripts/quality-gate.ts +0 -80
  194. package/plugins/sp/scripts/residual-scan.mjs +0 -634
  195. package/plugins/sp/scripts/residual-scan.ts +0 -248
  196. package/plugins/sp/scripts/run-summary.mjs +0 -758
  197. package/plugins/sp/scripts/run-summary.ts +0 -107
  198. package/plugins/sp/scripts/script-root.mjs +0 -129
  199. package/plugins/sp/scripts/script-root.ts +0 -199
  200. package/plugins/sp/scripts/session-timeline.mjs +0 -359
  201. package/plugins/sp/scripts/session-timeline.ts +0 -190
  202. package/plugins/sp/scripts/task-diffstat.mjs +0 -181
  203. package/plugins/sp/scripts/task-diffstat.ts +0 -219
  204. package/plugins/sp/scripts/workflow-step-profile.mjs +0 -338
  205. package/plugins/sp/scripts/workflow-step-profile.ts +0 -165
  206. package/plugins/sp/scripts/wrapup-drift-probe.mjs +0 -190
  207. package/plugins/sp/scripts/wrapup-drift-probe.ts +0 -261
  208. package/plugins/sp/scripts/wrapup-steps.mjs +0 -627
  209. package/plugins/sp/scripts/wrapup-steps.ts +0 -891
  210. package/web/_astro/channel.C7wG9RxA.js +0 -1
  211. package/web/_astro/index.BCY1JJHd.css +0 -1
@@ -1,626 +0,0 @@
1
- #!/usr/bin/env node
2
- // @bun
3
-
4
- // plugins/sp/scripts/daily-summary/daily-summary.ts
5
- import { spawn, spawnSync } from "child_process";
6
- import { existsSync as existsSync2, mkdirSync, readlinkSync, writeFileSync } from "fs";
7
- import { dirname as dirname2, isAbsolute, join as join2, resolve as resolve2 } from "path";
8
- import { fileURLToPath as fileURLToPath2 } from "url";
9
-
10
- // plugins/sp/lib/env.ts
11
- function getEnvVar(name, fallback) {
12
- const raw = process.env[name];
13
- return raw === undefined ? fallback : raw;
14
- }
15
- function getEnvVars() {
16
- return process.env;
17
- }
18
-
19
- // plugins/sp/lib/inline-run-app.ts
20
- import { existsSync } from "node:fs";
21
- import { dirname, join, resolve } from "node:path";
22
- import { fileURLToPath } from "node:url";
23
- function resolveAppEntry(spurBin) {
24
- const fallback = fileURLToPath(new URL("../../../apps/cli/src/index.ts", import.meta.url));
25
- const candidates = spurBin !== "" ? [spurBin] : [fallback];
26
- for (const candidate of candidates) {
27
- const tokens = candidate.split(/\s+/).filter(Boolean);
28
- const mainModule = [...tokens].reverse().find((t) => t.endsWith(".ts"));
29
- if (mainModule === undefined || !existsSync(mainModule))
30
- continue;
31
- const repoRoot = resolve(dirname(mainModule), "..", "..", "..");
32
- const appEntry = join(repoRoot, "packages", "app", "src", "index.ts");
33
- if (existsSync(appEntry))
34
- return { entry: appEntry, portable: false };
35
- }
36
- const entry = fileURLToPath(new URL("../lib/inline-run.generated.mjs", import.meta.url));
37
- if (!existsSync(entry)) {
38
- throw new Error("inline application bundle is missing — rebuild/install the sp plugin before running inline");
39
- }
40
- return { entry, portable: true };
41
- }
42
- async function loadInlineApp(spurBin, resolveAppEntry, required) {
43
- const { entry, portable } = resolveAppEntry(spurBin);
44
- const app = await import(entry);
45
- const missing = portable ? required.filter((name) => typeof app[name] !== "function") : [];
46
- if (missing.length > 0) {
47
- throw new Error(`inline application bundle ${entry} is older than its scripts — missing ${missing.join(", ")}. Reinstall sp with a superskill release that stages lib/ (commit b42961b), or pass --spur-bin <spur checkout>/apps/cli/src/index.ts.`);
48
- }
49
- return { app, portable };
50
- }
51
-
52
- // plugins/sp/scripts/daily-summary/daily-summary.ts
53
- var consoleEnabled = true;
54
- function enableLogger(consoleOn) {
55
- consoleEnabled = consoleOn;
56
- }
57
- function logAt(stream, message) {
58
- if (!consoleEnabled)
59
- return;
60
- console[stream](message);
61
- }
62
- var logger = {
63
- info: (message) => logAt("log", message),
64
- warn: (message) => logAt("warn", message),
65
- error: (message) => logAt("error", message)
66
- };
67
- var DAILY_DIR = "docs/daily";
68
- var DEFAULT_DATE = "today";
69
- function parseArgs(argv = process.argv.slice(2)) {
70
- const args = argv;
71
- const options = {
72
- date: DEFAULT_DATE,
73
- dryRun: false,
74
- skipGit: false,
75
- skipCcusage: false
76
- };
77
- for (let i = 0;i < args.length; i++) {
78
- const arg = args[i];
79
- if (arg === "--date" && i + 1 < args.length) {
80
- options.date = args[++i] ?? options.date;
81
- } else if (arg === "--dry-run") {
82
- options.dryRun = true;
83
- } else if (arg === "--output" && i + 1 < args.length) {
84
- options.outputPath = args[++i];
85
- } else if (arg === "--no-git") {
86
- options.skipGit = true;
87
- } else if (arg === "--no-ccusage") {
88
- options.skipCcusage = true;
89
- } else if (arg === "--help" || arg === "-h") {
90
- printUsage();
91
- process.exit(0);
92
- }
93
- }
94
- if (options.date === "today") {
95
- options.date = todayLocal();
96
- } else if (options.date === "yesterday") {
97
- options.date = yesterdayLocal();
98
- }
99
- return options;
100
- }
101
- function printUsage() {
102
- console.log(`
103
- sp:daily-summary \u2014 Generate daily summary reports
104
-
105
- Usage: daily-summary.ts [options]
106
-
107
- Options:
108
- --date YYYY-MM-DD Date for summary (default: today, also: yesterday)
109
- --dry-run Show summary without writing file
110
- --output <path> Write to custom path
111
- --no-git Skip git history collection
112
- --no-ccusage Skip token usage collection
113
- --help, -h Show this help
114
-
115
- Examples:
116
- daily-summary.ts # Today's summary
117
- daily-summary.ts --date yesterday # Yesterday's summary
118
- daily-summary.ts --dry-run # Preview without writing
119
- `);
120
- }
121
- function todayLocal() {
122
- const proc = spawnSync("date", ["+%Y-%m-%d"], { encoding: "utf8" });
123
- return (proc.stdout ?? "").trim();
124
- }
125
- function yesterdayLocal() {
126
- const epochProc = spawnSync("date", ["+%s"], { encoding: "utf8" });
127
- const epoch = parseInt((epochProc.stdout ?? "").trim(), 10);
128
- const yesterdayEpoch = epoch - 86400;
129
- let proc = spawnSync("date", ["-r", String(yesterdayEpoch), "+%Y-%m-%d"], { encoding: "utf8" });
130
- if ((proc.status ?? 1) !== 0) {
131
- proc = spawnSync("date", ["-d", `@${yesterdayEpoch}`, "+%Y-%m-%d"], { encoding: "utf8" });
132
- }
133
- return (proc.stdout ?? "").trim();
134
- }
135
- function getDateRange(dateStr) {
136
- const date = new Date(`${dateStr}T00:00:00`);
137
- const start = `${dateStr} 00:00:00`;
138
- const endDate = new Date(date);
139
- endDate.setDate(endDate.getDate() + 1);
140
- const end = `${endDate.toISOString().slice(0, 10)} 00:00:00`;
141
- return { start, end };
142
- }
143
- var defaultProcessSpawner = (cmd, args, env) => {
144
- return new Promise((resolve, reject) => {
145
- try {
146
- const proc = spawn(cmd, args, {
147
- stdio: ["ignore", "pipe", "pipe"],
148
- env: env ?? getEnvVars()
149
- });
150
- const stdoutChunks = [];
151
- const stderrChunks = [];
152
- proc.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.from(chunk)));
153
- proc.stderr.on("data", (chunk) => stderrChunks.push(Buffer.from(chunk)));
154
- proc.on("close", (exitCode) => {
155
- resolve({
156
- stdout: Buffer.concat(stdoutChunks).toString("utf8"),
157
- stderr: Buffer.concat(stderrChunks).toString("utf8"),
158
- exitCode: exitCode ?? 0
159
- });
160
- });
161
- proc.on("error", (err) => {
162
- reject(err);
163
- });
164
- } catch (err) {
165
- reject(err);
166
- }
167
- });
168
- };
169
- var processSpawner = defaultProcessSpawner;
170
- function setProcessSpawner(next) {
171
- processSpawner = next ?? defaultProcessSpawner;
172
- }
173
- async function getCcusageData(date) {
174
- try {
175
- const env = { ...getEnvVars() };
176
- const ccusageCheck = await processSpawner("ccusage", ["--version"], env);
177
- if (ccusageCheck.exitCode !== 0) {
178
- return null;
179
- }
180
- const since = `${date}T00:00:00`;
181
- const until = `${date}T23:59:59`;
182
- const proc = await processSpawner("ccusage", ["daily", "--since", since, "--until", until, "--json"], env);
183
- if (proc.exitCode !== 0) {
184
- logger.warn(`ccusage error: ${proc.stderr}`);
185
- return null;
186
- }
187
- const data = JSON.parse(proc.stdout);
188
- return data;
189
- } catch (error) {
190
- logger.warn(`Failed to get ccusage data: ${error}`);
191
- return null;
192
- }
193
- }
194
- function composeHistoryHealth(reading) {
195
- const loops = reading.loops.map((row) => ({
196
- toolName: row.toolName,
197
- argsDigest: row.argsDigest || "repeated execution",
198
- repeats: row.repeats,
199
- sessionId: row.sessionId,
200
- fromSeq: row.firstSeq,
201
- toSeq: row.lastSeq,
202
- wastedTokens: row.repeats * 250
203
- }));
204
- const remediationProposals = [];
205
- for (const lp of loops.slice(0, 5)) {
206
- const cleanTool = lp.toolName.replace(/[^a-zA-Z0-9_-]/g, "_");
207
- const key = `repetition:${cleanTool}:${lp.argsDigest.slice(0, 16)}`;
208
- const title = `Break execution loop in ${lp.toolName} (${lp.repeats} repeats)`;
209
- const command = `spur task create "<title>" --feature <id> && spur task update <wbs> --section Plan --from-file <path>`;
210
- remediationProposals.push({ key, title, command });
211
- }
212
- if (reading.toolCalls > 0 && reading.errorRatePct > 10) {
213
- remediationProposals.push({
214
- key: "reliability:tooling:high-error-rate",
215
- title: `Investigate high tool error rate (${reading.errorRatePct.toFixed(1)}%)`,
216
- command: `spur task create "<title>" --feature <id> && spur task update <wbs> --section Plan --from-file <path>`
217
- });
218
- }
219
- return {
220
- toolCalls: reading.toolCalls,
221
- toolErrors: reading.toolErrors,
222
- errorRatePct: reading.errorRatePct,
223
- loops,
224
- redundantCalls: loops.reduce((acc, l) => acc + Math.max(0, l.repeats - 1), 0),
225
- wastedTokens: loops.reduce((acc, l) => acc + l.wastedTokens, 0),
226
- remediationProposals
227
- };
228
- }
229
- async function getSpurHistoryHealth(date, dbPath = ".spur/spur.db") {
230
- try {
231
- const resolvedPath = resolve2(process.cwd(), dbPath);
232
- const { app } = await loadInlineApp(getEnvVar("SPUR_BIN") ?? "", resolveAppEntry, [
233
- "readHistoryHealth"
234
- ]);
235
- const reading = await app.readHistoryHealth({ date, dbPath: resolvedPath });
236
- return reading === null ? null : composeHistoryHealth(reading);
237
- } catch {
238
- return null;
239
- }
240
- }
241
- async function getGitCommits(date) {
242
- try {
243
- const { start, end } = getDateRange(date);
244
- const proc = await processSpawner("git", [
245
- "log",
246
- "--since",
247
- start,
248
- "--until",
249
- end,
250
- "--pretty=format:%H|%ad|%s",
251
- "--date=iso",
252
- "--numstat"
253
- ]);
254
- if (proc.exitCode !== 0) {
255
- logger.warn("Failed to get git commits");
256
- return [];
257
- }
258
- const commits = [];
259
- const lines = proc.stdout.trim().split(`
260
- `);
261
- let currentCommit = null;
262
- for (const line of lines) {
263
- if (!line.trim())
264
- continue;
265
- if (line.includes("|")) {
266
- const parts = line.split("|");
267
- if (parts.length >= 3) {
268
- if (currentCommit?.hash) {
269
- commits.push(currentCommit);
270
- }
271
- currentCommit = {
272
- hash: parts[0],
273
- date: parts[1],
274
- message: parts[2],
275
- filesChanged: 0,
276
- insertions: 0,
277
- deletions: 0
278
- };
279
- }
280
- } else if (currentCommit && line.includes("\t")) {
281
- const parts = line.split("\t");
282
- if (parts.length >= 3) {
283
- const insertions = parseInt(parts[0] ?? "", 10) || 0;
284
- const deletions = parseInt(parts[1] ?? "", 10) || 0;
285
- currentCommit.filesChanged = (currentCommit.filesChanged ?? 0) + 1;
286
- currentCommit.insertions = (currentCommit.insertions ?? 0) + insertions;
287
- currentCommit.deletions = (currentCommit.deletions ?? 0) + deletions;
288
- }
289
- }
290
- }
291
- if (currentCommit?.hash) {
292
- commits.push(currentCommit);
293
- }
294
- return commits;
295
- } catch (error) {
296
- logger.warn(`Failed to get git commits: ${error}`);
297
- return [];
298
- }
299
- }
300
- async function promptUser() {
301
- if (getEnvVar("SP_DAILY_SUMMARY_NO_PROMPT") === "1") {
302
- return { learnings: "", issuesFixed: "", pending: "" };
303
- }
304
- if (getEnvVar("RD3_DAILY_SUMMARY_NO_PROMPT") === "1") {
305
- logger.warn("[deprecate] RD3_DAILY_SUMMARY_NO_PROMPT is deprecated; use SP_DAILY_SUMMARY_NO_PROMPT");
306
- return { learnings: "", issuesFixed: "", pending: "" };
307
- }
308
- console.log(`
309
- \uD83D\uDCCA Daily Summary \u2014 ${todayLocal()}`);
310
- console.log("\u2550".repeat(50));
311
- console.log(`
312
- Please provide the following (press Enter to skip):
313
- `);
314
- if (!process.stdin.isTTY) {
315
- const chunks = [];
316
- for await (const chunk of process.stdin) {
317
- chunks.push(chunk);
318
- }
319
- const buffered = Buffer.concat(chunks).toString("utf-8");
320
- const [learnings = "", issuesFixed = "", pending = ""] = buffered.split(`
321
- `);
322
- return {
323
- learnings: learnings.trim(),
324
- issuesFixed: issuesFixed.trim(),
325
- pending: pending.trim()
326
- };
327
- }
328
- const readline = await import("readline");
329
- const rl = readline.createInterface({
330
- input: process.stdin,
331
- output: process.stdout
332
- });
333
- const question = (prompt) => new Promise((resolve) => {
334
- rl.question(prompt, (answer) => {
335
- resolve(answer.trim());
336
- });
337
- });
338
- const learnings = await question(`1. What did you learn today? (optional)
339
- > `);
340
- const issuesFixed = await question(`
341
- 2. What issues did you fix? (optional)
342
- > `);
343
- const pending = await question(`
344
- 3. What's pending for tomorrow? (optional)
345
- > `);
346
- rl.close();
347
- return {
348
- learnings,
349
- issuesFixed,
350
- pending
351
- };
352
- }
353
- function generateMarkdown(summary) {
354
- const lines = [];
355
- lines.push(`# Daily Summary \u2014 ${summary.date}`);
356
- lines.push("");
357
- lines.push(`**Generated:** ${summary.generatedAt}`);
358
- lines.push("");
359
- lines.push("## Meta");
360
- lines.push("");
361
- lines.push(`- **Date:** ${summary.date}`);
362
- lines.push(`- **Platforms:** ${summary.platforms.join(", ") || "unknown"}`);
363
- lines.push("");
364
- if (summary.tokenUsage) {
365
- const tu = summary.tokenUsage;
366
- lines.push("## Token Usage");
367
- lines.push("");
368
- lines.push(`| Metric | Value |`);
369
- lines.push(`|--------|-------|`);
370
- lines.push(`| Input Tokens | ${tu.inputTokens.toLocaleString()} |`);
371
- lines.push(`| Output Tokens | ${tu.outputTokens.toLocaleString()} |`);
372
- lines.push(`| Cache Tokens | ${tu.cacheTokens.toLocaleString()} |`);
373
- lines.push(`| Total Tokens | ${tu.totalTokens.toLocaleString()} |`);
374
- lines.push(`| Estimated Cost | $${tu.costUsd.toFixed(4)} |`);
375
- lines.push("");
376
- if (tu.inputTokens > 0) {
377
- const cacheHitRate = tu.cacheTokens / (tu.inputTokens + tu.cacheTokens) * 100;
378
- lines.push(`**Cache Hit Rate:** ${cacheHitRate.toFixed(1)}%`);
379
- lines.push("");
380
- }
381
- }
382
- if (summary.gitActivity) {
383
- const ga = summary.gitActivity;
384
- lines.push("## Git Activity");
385
- lines.push("");
386
- lines.push(`| Metric | Value |`);
387
- lines.push(`|--------|-------|`);
388
- lines.push(`| Commits | ${ga.commitCount} |`);
389
- lines.push(`| Files Changed | ${ga.filesChanged} |`);
390
- lines.push(`| Insertions | +${ga.insertions} |`);
391
- lines.push(`| Deletions | -${ga.deletions} |`);
392
- lines.push("");
393
- }
394
- if (summary.commits.length > 0) {
395
- lines.push("## Commits");
396
- lines.push("");
397
- for (const commit of summary.commits.slice(0, 10)) {
398
- const shortHash = commit.hash.slice(0, 7);
399
- lines.push(`- \`${shortHash}\` ${commit.message}`);
400
- }
401
- if (summary.commits.length > 10) {
402
- lines.push(`- ... and ${summary.commits.length - 10} more commits`);
403
- }
404
- lines.push("");
405
- }
406
- const { learnings, issuesFixed, pending } = summary.annotations;
407
- if (learnings) {
408
- lines.push("## Learnings");
409
- lines.push("");
410
- lines.push(learnings);
411
- lines.push("");
412
- }
413
- if (issuesFixed) {
414
- lines.push("## Issues Fixed");
415
- lines.push("");
416
- lines.push(issuesFixed);
417
- lines.push("");
418
- }
419
- if (pending) {
420
- lines.push("## Pending");
421
- lines.push("");
422
- lines.push(pending);
423
- lines.push("");
424
- }
425
- if (summary.historyHealth) {
426
- const hh = summary.historyHealth;
427
- lines.push("## Execution Loops & Health Findings");
428
- lines.push("");
429
- if (hh.loops.length === 0 && hh.toolCalls === 0) {
430
- lines.push("- **Status:** \u2705 Clean \u2014 No execution loops or tool calls recorded for this date.");
431
- lines.push("");
432
- } else {
433
- lines.push("| Metric | Value |");
434
- lines.push("|--------|-------|");
435
- lines.push(`| Tool Invocations | ${hh.toolCalls.toLocaleString()} |`);
436
- lines.push(`| Tool Errors | ${hh.toolErrors.toLocaleString()} (${hh.errorRatePct.toFixed(1)}%) |`);
437
- lines.push(`| Detected Loops (Repeats \u2265 3) | ${hh.loops.length} |`);
438
- lines.push(`| Redundant Invocations | ${hh.redundantCalls.toLocaleString()} |`);
439
- lines.push(`| Estimated Wasted Tokens | ${hh.wastedTokens.toLocaleString()} |`);
440
- lines.push("");
441
- if (hh.loops.length > 0) {
442
- lines.push("### Detected Execution Loops");
443
- lines.push("");
444
- for (const lp of hh.loops.slice(0, 10)) {
445
- const seqInfo = lp.fromSeq && lp.toSeq ? ` (steps #${lp.fromSeq} \u2192 #${lp.toSeq})` : "";
446
- const argsHint = lp.argsDigest === "74234e98afe7498fb5daf1f36ac2d78acc339464f950703b8c019892f982b90b" ? "empty/unrecorded arguments" : lp.argsDigest.length > 28 ? `${lp.argsDigest.slice(0, 24)}...` : lp.argsDigest;
447
- lines.push(`- \`${lp.toolName || "unknown"}\` \xD7 **${lp.repeats} repeats** in session \`${lp.sessionId}\`${seqInfo}`);
448
- lines.push(` - *Args hint:* \`${argsHint}\` (~${lp.wastedTokens.toLocaleString()} wasted tokens)`);
449
- }
450
- lines.push("");
451
- }
452
- if (hh.remediationProposals.length > 0) {
453
- lines.push("### Auto-Healing Remediation Proposals");
454
- lines.push("");
455
- lines.push("To remediate root causes and prevent recurring token waste, execute:");
456
- lines.push("");
457
- lines.push("```bash");
458
- for (const prop of hh.remediationProposals) {
459
- lines.push(`# ${prop.title} [${prop.key}]`);
460
- lines.push(prop.command);
461
- lines.push("");
462
- }
463
- lines.push("```");
464
- lines.push("");
465
- }
466
- }
467
- }
468
- if (summary.historyReportPath) {
469
- lines.push("## History Report");
470
- lines.push("");
471
- lines.push(`- **Newest artifact:** ${summary.historyReportPath}`);
472
- lines.push("");
473
- }
474
- lines.push("---");
475
- lines.push("");
476
- lines.push(`*Generated by sp:daily-summary at ${summary.generatedAt}*`);
477
- return lines.join(`
478
- `);
479
- }
480
- function ensureDir(path) {
481
- if (!existsSync2(path)) {
482
- mkdirSync(path, { recursive: true });
483
- }
484
- }
485
- function writeSummary(markdown, options) {
486
- const filename = `summary_${options.date.replace(/-/g, "")}.md`;
487
- const outputPath = options.outputPath || join2(DAILY_DIR, filename);
488
- ensureDir(join2(outputPath, ".."));
489
- writeFileSync(outputPath, markdown, "utf-8");
490
- return outputPath;
491
- }
492
- function resolveHistoryReportPath() {
493
- const pointer = resolve2(process.cwd(), ".spur", "reports", "history", "latest.json");
494
- if (!existsSync2(pointer)) {
495
- return;
496
- }
497
- try {
498
- const target = readlinkSync(pointer);
499
- const resolved = isAbsolute(target) ? target : resolve2(dirname2(pointer), target);
500
- return existsSync2(resolved) ? resolved : undefined;
501
- } catch {
502
- return;
503
- }
504
- }
505
- async function buildDailySummary(options) {
506
- const platforms = [];
507
- let tokenUsage;
508
- if (!options.skipCcusage) {
509
- const ccusageData = await getCcusageData(options.date);
510
- if (ccusageData?.totals) {
511
- const totals = ccusageData.totals;
512
- tokenUsage = {
513
- inputTokens: totals.inputTokens,
514
- outputTokens: totals.outputTokens,
515
- cacheTokens: totals.cacheCreationTokens + totals.cacheReadTokens,
516
- totalTokens: totals.totalTokens,
517
- costUsd: totals.totalCost
518
- };
519
- platforms.push("Claude Code");
520
- }
521
- }
522
- let gitActivity;
523
- let commits = [];
524
- if (!options.skipGit) {
525
- commits = await getGitCommits(options.date);
526
- if (commits.length > 0) {
527
- gitActivity = commits.reduce((acc, commit) => ({
528
- commitCount: acc.commitCount + 1,
529
- filesChanged: acc.filesChanged + (commit.filesChanged || 0),
530
- insertions: acc.insertions + (commit.insertions || 0),
531
- deletions: acc.deletions + (commit.deletions || 0)
532
- }), { commitCount: 0, filesChanged: 0, insertions: 0, deletions: 0 });
533
- platforms.push("Git");
534
- }
535
- }
536
- const historyReportPath = resolveHistoryReportPath();
537
- const annotations = await promptUser();
538
- const result = {
539
- date: options.date,
540
- platforms,
541
- commits,
542
- annotations,
543
- historyReportPath,
544
- generatedAt: new Date().toISOString().replace("T", " ").slice(0, 19)
545
- };
546
- if (tokenUsage !== undefined) {
547
- result.tokenUsage = tokenUsage;
548
- }
549
- if (gitActivity !== undefined) {
550
- result.gitActivity = gitActivity;
551
- }
552
- const historyHealth = await getSpurHistoryHealth(options.date);
553
- if (historyHealth) {
554
- result.historyHealth = historyHealth;
555
- platforms.push("Spur History");
556
- }
557
- return result;
558
- }
559
- async function main() {
560
- if (!process.versions.bun) {
561
- const child = spawnSync("bun", [fileURLToPath2(import.meta.url), ...process.argv.slice(2)], {
562
- stdio: "inherit"
563
- });
564
- if (!child.error)
565
- process.exit(child.status ?? 1);
566
- console.error(`daily-summary: Bun not on PATH (${child.error.message}); history health unavailable`);
567
- }
568
- const options = parseArgs();
569
- logger.info(`Generating daily summary for ${options.date}...`);
570
- try {
571
- const summary = await buildDailySummary(options);
572
- const markdown = generateMarkdown(summary);
573
- if (options.dryRun) {
574
- console.log(`
575
- ${markdown}
576
- `);
577
- logger.info("(dry-run) Summary not written to file");
578
- } else {
579
- const outputPath = writeSummary(markdown, options);
580
- console.log(`
581
- ${markdown}
582
- `);
583
- console.log(`
584
- \u2705 Summary written to: ${outputPath}`);
585
- }
586
- console.log(`
587
- \uD83D\uDCCA Summary Statistics:`);
588
- console.log(` Date: ${summary.date}`);
589
- console.log(` Platforms: ${summary.platforms.join(", ") || "none"}`);
590
- if (summary.tokenUsage) {
591
- console.log(` Tokens: ${summary.tokenUsage.totalTokens.toLocaleString()}`);
592
- console.log(` Cost: $${summary.tokenUsage.costUsd.toFixed(4)}`);
593
- }
594
- if (summary.gitActivity) {
595
- console.log(` Commits: ${summary.gitActivity.commitCount}`);
596
- }
597
- } catch (error) {
598
- logger.error(`Failed to generate summary: ${error}`);
599
- process.exit(1);
600
- }
601
- }
602
- {
603
- main().catch((error) => {
604
- logger.error(`Daily summary failed: ${error}`);
605
- process.exit(1);
606
- });
607
- }
608
- export {
609
- buildDailySummary,
610
- defaultProcessSpawner,
611
- enableLogger,
612
- ensureDir,
613
- generateMarkdown,
614
- getCcusageData,
615
- getDateRange,
616
- getGitCommits,
617
- getSpurHistoryHealth,
618
- main,
619
- parseArgs,
620
- printUsage,
621
- promptUser,
622
- setProcessSpawner,
623
- todayLocal,
624
- writeSummary,
625
- yesterdayLocal
626
- };