@dylanpiercey/work 0.0.37 → 0.0.40

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 (158) hide show
  1. package/README.md +15 -2
  2. package/bin/work.mjs +76 -1
  3. package/dist/index.mjs +1393 -745
  4. package/dist/public/assets/{_pFmckaaP2.js → _-KsWGHKz2.js} +2 -2
  5. package/dist/public/assets/{_pFmckaaP2.js.map → _-KsWGHKz2.js.map} +1 -1
  6. package/dist/public/assets/{_BjiamLhC2.js → _3VenI2OT2.js} +2 -2
  7. package/dist/public/assets/{_BjiamLhC2.js.map → _3VenI2OT2.js.map} +1 -1
  8. package/dist/public/assets/{_e1mFK4xC.js → _8DPiXP2D.js} +2 -2
  9. package/dist/public/assets/{_e1mFK4xC.js.map → _8DPiXP2D.js.map} +1 -1
  10. package/dist/public/assets/{_aCPbjwsL2.js → _8UwDOo_Z2.js} +2 -2
  11. package/dist/public/assets/{_aCPbjwsL2.js.map → _8UwDOo_Z2.js.map} +1 -1
  12. package/dist/public/assets/{_7WXRxrlU.js → _B0ILW1ln.js} +2 -2
  13. package/dist/public/assets/{_7WXRxrlU.js.map → _B0ILW1ln.js.map} +1 -1
  14. package/dist/public/assets/{_ChxFmNZf2.js → _B7cE3DDh2.js} +2 -2
  15. package/dist/public/assets/{_ChxFmNZf2.js.map → _B7cE3DDh2.js.map} +1 -1
  16. package/dist/public/assets/{_ETxOUn4j2.js → _B8CG1lYk2.js} +2 -2
  17. package/dist/public/assets/{_ETxOUn4j2.js.map → _B8CG1lYk2.js.map} +1 -1
  18. package/dist/public/assets/{_CKmHgYfe.js → _BFoRA3M-.js} +2 -2
  19. package/dist/public/assets/{_CKmHgYfe.js.map → _BFoRA3M-.js.map} +1 -1
  20. package/dist/public/assets/{_CH2C5dSU.js → _BHNTdpyr.js} +2 -2
  21. package/dist/public/assets/{_CH2C5dSU.js.map → _BHNTdpyr.js.map} +1 -1
  22. package/dist/public/assets/{_qFxIW2tY.js → _BJLP6wPD.js} +2 -2
  23. package/dist/public/assets/{_qFxIW2tY.js.map → _BJLP6wPD.js.map} +1 -1
  24. package/dist/public/assets/{_uHn5Sjo52.js → _BKoDBxkc2.js} +2 -2
  25. package/dist/public/assets/{_uHn5Sjo52.js.map → _BKoDBxkc2.js.map} +1 -1
  26. package/dist/public/assets/{_snZlpI9-2.js → _BPQMLvu02.js} +2 -2
  27. package/dist/public/assets/{_snZlpI9-2.js.map → _BPQMLvu02.js.map} +1 -1
  28. package/dist/public/assets/{_D_QEBWxx.js → _BTgtIJbs.js} +2 -2
  29. package/dist/public/assets/{_D_QEBWxx.js.map → _BTgtIJbs.js.map} +1 -1
  30. package/dist/public/assets/{__8BegO0O.js → _BVhbSv_7.js} +2 -2
  31. package/dist/public/assets/{__8BegO0O.js.map → _BVhbSv_7.js.map} +1 -1
  32. package/dist/public/assets/{_ChALr73Q.js → _BXFyaVzV.js} +2 -2
  33. package/dist/public/assets/{_ChALr73Q.js.map → _BXFyaVzV.js.map} +1 -1
  34. package/dist/public/assets/{_WtSbc-0z2.js → _Ba56VGPa2.js} +2 -2
  35. package/dist/public/assets/{_WtSbc-0z2.js.map → _Ba56VGPa2.js.map} +1 -1
  36. package/dist/public/assets/{_CJ4f2Gn22.js → _BbczFSm62.js} +2 -2
  37. package/dist/public/assets/{_CJ4f2Gn22.js.map → _BbczFSm62.js.map} +1 -1
  38. package/dist/public/assets/{_TzFjCY4x.js → _BdxRwSdd.js} +2 -2
  39. package/dist/public/assets/{_TzFjCY4x.js.map → _BdxRwSdd.js.map} +1 -1
  40. package/dist/public/assets/{_CpZyjYVd.js → _BgyAIeMk.js} +2 -2
  41. package/dist/public/assets/{_CpZyjYVd.js.map → _BgyAIeMk.js.map} +1 -1
  42. package/dist/public/assets/{_BbK3eXZN2.js → _BjYoD_6z2.js} +2 -2
  43. package/dist/public/assets/{_BbK3eXZN2.js.map → _BjYoD_6z2.js.map} +1 -1
  44. package/dist/public/assets/{_CqgeXAyq.js → _BlnfI-cd.js} +2 -2
  45. package/dist/public/assets/{_CqgeXAyq.js.map → _BlnfI-cd.js.map} +1 -1
  46. package/dist/public/assets/{_Cgcy-XAW.js → _Bm15UJ5r.js} +2 -2
  47. package/dist/public/assets/{_Cgcy-XAW.js.map → _Bm15UJ5r.js.map} +1 -1
  48. package/dist/public/assets/{_ickmOHj-.js → _BmY-aR2i.js} +2 -2
  49. package/dist/public/assets/{_ickmOHj-.js.map → _BmY-aR2i.js.map} +1 -1
  50. package/dist/public/assets/{_DMqId9I32.js → _Bq9rbiCa2.js} +2 -2
  51. package/dist/public/assets/{_DMqId9I32.js.map → _Bq9rbiCa2.js.map} +1 -1
  52. package/dist/public/assets/{_CerTTqHR.js → _Br2uo0OK.js} +2 -2
  53. package/dist/public/assets/{_CerTTqHR.js.map → _Br2uo0OK.js.map} +1 -1
  54. package/dist/public/assets/{_C0Jt_Xjm.js → _Brtx9zLF.js} +2 -2
  55. package/dist/public/assets/{_C0Jt_Xjm.js.map → _Brtx9zLF.js.map} +1 -1
  56. package/dist/public/assets/{_DCP8qFc6.js → _BtnmnAxJ.js} +2 -2
  57. package/dist/public/assets/{_DCP8qFc6.js.map → _BtnmnAxJ.js.map} +1 -1
  58. package/dist/public/assets/{_BnSuNHJ7.js → _Bv_RWYiQ.js} +2 -2
  59. package/dist/public/assets/{_BnSuNHJ7.js.map → _Bv_RWYiQ.js.map} +1 -1
  60. package/dist/public/assets/{_CEkpXUQi2.js → _BvtYDSuT2.js} +2 -2
  61. package/dist/public/assets/{_CEkpXUQi2.js.map → _BvtYDSuT2.js.map} +1 -1
  62. package/dist/public/assets/{_BgZq7RwW.js → _C83jn7M7.js} +2 -2
  63. package/dist/public/assets/{_BgZq7RwW.js.map → _C83jn7M7.js.map} +1 -1
  64. package/dist/public/assets/{_TZbrx97x2.js → _CA4_OXC62.js} +2 -2
  65. package/dist/public/assets/{_TZbrx97x2.js.map → _CA4_OXC62.js.map} +1 -1
  66. package/dist/public/assets/{_C6Ku6tce.js → _CEr-0D0d.js} +2 -2
  67. package/dist/public/assets/{_C6Ku6tce.js.map → _CEr-0D0d.js.map} +1 -1
  68. package/dist/public/assets/{_DeL04cfO2.js → _CGlOgonA2.js} +2 -2
  69. package/dist/public/assets/{_DeL04cfO2.js.map → _CGlOgonA2.js.map} +1 -1
  70. package/dist/public/assets/{_BduevJm5.js → _CLJ7h8rZ.js} +2 -2
  71. package/dist/public/assets/{_BduevJm5.js.map → _CLJ7h8rZ.js.map} +1 -1
  72. package/dist/public/assets/{_Dzo0xXFy2.js → _CV6LlXY32.js} +2 -2
  73. package/dist/public/assets/{_Dzo0xXFy2.js.map → _CV6LlXY32.js.map} +1 -1
  74. package/dist/public/assets/{_B0l1050s.js → _CVFOAkWc.js} +2 -2
  75. package/dist/public/assets/{_B0l1050s.js.map → _CVFOAkWc.js.map} +1 -1
  76. package/dist/public/assets/{_B62EUIfl2.js → _CVgZFxTy2.js} +2 -2
  77. package/dist/public/assets/{_B62EUIfl2.js.map → _CVgZFxTy2.js.map} +1 -1
  78. package/dist/public/assets/{_B1zT643d.js → _CWG8S2bO.js} +2 -2
  79. package/dist/public/assets/{_B1zT643d.js.map → _CWG8S2bO.js.map} +1 -1
  80. package/dist/public/assets/{_BS-0-1w-.js → _CX2FR9en.js} +2 -2
  81. package/dist/public/assets/{_BS-0-1w-.js.map → _CX2FR9en.js.map} +1 -1
  82. package/dist/public/assets/{_BfOhO-ik.js → _CcyXwmyV.js} +2 -2
  83. package/dist/public/assets/{_BfOhO-ik.js.map → _CcyXwmyV.js.map} +1 -1
  84. package/dist/public/assets/{_B61Z1jwf.js → _CfNBAgk5.js} +2 -2
  85. package/dist/public/assets/{_B61Z1jwf.js.map → _CfNBAgk5.js.map} +1 -1
  86. package/dist/public/assets/{_CFlhxTwD.js → _CmH32z5I.js} +2 -2
  87. package/dist/public/assets/{_CFlhxTwD.js.map → _CmH32z5I.js.map} +1 -1
  88. package/dist/public/assets/{_328LsgJQ.js → _Cn-JhCBl.js} +2 -2
  89. package/dist/public/assets/{_328LsgJQ.js.map → _Cn-JhCBl.js.map} +1 -1
  90. package/dist/public/assets/{_CCquK4b1.js → _Cn880iWo.js} +2 -2
  91. package/dist/public/assets/{_CCquK4b1.js.map → _Cn880iWo.js.map} +1 -1
  92. package/dist/public/assets/{_Dt-7Y3TE2.js → _CpelmBB72.js} +2 -2
  93. package/dist/public/assets/{_Dt-7Y3TE2.js.map → _CpelmBB72.js.map} +1 -1
  94. package/dist/public/assets/{_T9N_IxyL.js → _CqS9_RIm.js} +2 -2
  95. package/dist/public/assets/{_T9N_IxyL.js.map → _CqS9_RIm.js.map} +1 -1
  96. package/dist/public/assets/{_C0UJDcvl2.js → _Ct5nAVXE2.js} +2 -2
  97. package/dist/public/assets/{_C0UJDcvl2.js.map → _Ct5nAVXE2.js.map} +1 -1
  98. package/dist/public/assets/{_CnWV64BG2.js → _Cu-YDqqS2.js} +2 -2
  99. package/dist/public/assets/{_CnWV64BG2.js.map → _Cu-YDqqS2.js.map} +1 -1
  100. package/dist/public/assets/{_Bpw8-M-2.js → _Cw00Etn-.js} +2 -2
  101. package/dist/public/assets/{_Bpw8-M-2.js.map → _Cw00Etn-.js.map} +1 -1
  102. package/dist/public/assets/{_y6dVQHpH.js → _Cy0mebiK.js} +2 -2
  103. package/dist/public/assets/{_y6dVQHpH.js.map → _Cy0mebiK.js.map} +1 -1
  104. package/dist/public/assets/{_DJ0lGemR.js → _D1KsrNGN.js} +2 -2
  105. package/dist/public/assets/{_DJ0lGemR.js.map → _D1KsrNGN.js.map} +1 -1
  106. package/dist/public/assets/{_BwHIIw2E2.js → _D63K5MAL2.js} +2 -2
  107. package/dist/public/assets/{_BwHIIw2E2.js.map → _D63K5MAL2.js.map} +1 -1
  108. package/dist/public/assets/{_CiLcz-CP.js → _DDn1qNlx.js} +2 -2
  109. package/dist/public/assets/{_CiLcz-CP.js.map → _DDn1qNlx.js.map} +1 -1
  110. package/dist/public/assets/{_B0p7k1Wy.js → _DGWkqOrB.js} +2 -2
  111. package/dist/public/assets/{_B0p7k1Wy.js.map → _DGWkqOrB.js.map} +1 -1
  112. package/dist/public/assets/{_BG7PgpSh.js → _DIsTDKVR.js} +2 -2
  113. package/dist/public/assets/{_BG7PgpSh.js.map → _DIsTDKVR.js.map} +1 -1
  114. package/dist/public/assets/{_DimDQHw9.js → _DQ-kE1KO.js} +2 -2
  115. package/dist/public/assets/{_DimDQHw9.js.map → _DQ-kE1KO.js.map} +1 -1
  116. package/dist/public/assets/{_Dghs5wz6.js → _DXPT_5Ww.js} +2 -2
  117. package/dist/public/assets/{_Dghs5wz6.js.map → _DXPT_5Ww.js.map} +1 -1
  118. package/dist/public/assets/{_BlnqFsCL.js → _Dgbb7WCq.js} +2 -2
  119. package/dist/public/assets/{_BlnqFsCL.js.map → _Dgbb7WCq.js.map} +1 -1
  120. package/dist/public/assets/{_DE45Wi_v2.js → _DiGEIi7y2.js} +2 -2
  121. package/dist/public/assets/{_DE45Wi_v2.js.map → _DiGEIi7y2.js.map} +1 -1
  122. package/dist/public/assets/{_BzyfiiMx.js → _DlycnL0G.js} +2 -2
  123. package/dist/public/assets/{_BzyfiiMx.js.map → _DlycnL0G.js.map} +1 -1
  124. package/dist/public/assets/{_OntiqL02.js → _DsnM-qIE.js} +2 -2
  125. package/dist/public/assets/{_OntiqL02.js.map → _DsnM-qIE.js.map} +1 -1
  126. package/dist/public/assets/{_CznN3jlr.js → _DvhrN_AC.js} +2 -2
  127. package/dist/public/assets/{_CznN3jlr.js.map → _DvhrN_AC.js.map} +1 -1
  128. package/dist/public/assets/{_DC_ioCXZ.js → _Dzmzf0jy.js} +2 -2
  129. package/dist/public/assets/{_DC_ioCXZ.js.map → _Dzmzf0jy.js.map} +1 -1
  130. package/dist/public/assets/{_aJqK30432.js → _FK3N8vMM2.js} +2 -2
  131. package/dist/public/assets/{_aJqK30432.js.map → _FK3N8vMM2.js.map} +1 -1
  132. package/dist/public/assets/{_Cbz3Zb2r.js → _Ivuhnz8D.js} +2 -2
  133. package/dist/public/assets/{_Cbz3Zb2r.js.map → _Ivuhnz8D.js.map} +1 -1
  134. package/dist/public/assets/{_BiVb_8fl2.js → _TKY_rFIy2.js} +2 -2
  135. package/dist/public/assets/{_BiVb_8fl2.js.map → _TKY_rFIy2.js.map} +1 -1
  136. package/dist/public/assets/{_D-9YZFuF.js → _UeUsduDg.js} +2 -2
  137. package/dist/public/assets/{_D-9YZFuF.js.map → _UeUsduDg.js.map} +1 -1
  138. package/dist/public/assets/{_BTDPW9iy.js → _ZG408fQc.js} +2 -2
  139. package/dist/public/assets/{_BTDPW9iy.js.map → _ZG408fQc.js.map} +1 -1
  140. package/dist/public/assets/{_CjmNk-3X.js → _dpF9TA5S.js} +2 -2
  141. package/dist/public/assets/{_CjmNk-3X.js.map → _dpF9TA5S.js.map} +1 -1
  142. package/dist/public/assets/{_B35oLYjV.js → _fIQDai7d.js} +2 -2
  143. package/dist/public/assets/{_B35oLYjV.js.map → _fIQDai7d.js.map} +1 -1
  144. package/dist/public/assets/{_4oI4DLD12.js → _irjxI44N2.js} +2 -2
  145. package/dist/public/assets/{_4oI4DLD12.js.map → _irjxI44N2.js.map} +1 -1
  146. package/dist/public/assets/{_7Hr6x6JT.js → _jifvQF0M.js} +2 -2
  147. package/dist/public/assets/{_7Hr6x6JT.js.map → _jifvQF0M.js.map} +1 -1
  148. package/dist/public/assets/{_BpJ6F21O.js → _mH9R9oGB.js} +2 -2
  149. package/dist/public/assets/{_BpJ6F21O.js.map → _mH9R9oGB.js.map} +1 -1
  150. package/dist/public/assets/{_CuVyPGCR.js → _pUoTA7Pg.js} +2 -2
  151. package/dist/public/assets/{_CuVyPGCR.js.map → _pUoTA7Pg.js.map} +1 -1
  152. package/dist/public/assets/index--QwhN0hy.css +1 -0
  153. package/dist/public/assets/index-CdVBL6Kf.js +1615 -0
  154. package/dist/public/assets/index-CdVBL6Kf.js.map +1 -0
  155. package/package.json +1 -1
  156. package/dist/public/assets/index-B-C71W3M.js +0 -1615
  157. package/dist/public/assets/index-B-C71W3M.js.map +0 -1
  158. package/dist/public/assets/index-DxoJXJz6.css +0 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  A self-hosted web GUI for agentic dev workspaces — on desktop and as a mobile
4
4
  PWA. Spin up multi-repo worktree workspaces, run coding agents (Claude Code,
5
5
  Codex, Copilot, Cursor, Grok) or plain shells in real terminals, review diffs
6
- and send feedback to agents, and watch PR/CI status — from any device.
6
+ and send feedback to agents, and watch PR status — from any device.
7
7
 
8
8
  - **Workspaces** — named directories of git worktrees (one per GitHub repo,
9
9
  cloned from a shared bare-repo cache), all on a generated branch. Create,
@@ -50,6 +50,14 @@ For a production build plus a background service (systemd on Linux, launchd on m
50
50
 
51
51
  ```sh
52
52
  ./scripts/setup-prod.sh # build + install + start the service
53
+
54
+ # While hacking on work itself, point the background service at a checkout
55
+ # (and back at the npm install when done):
56
+ cp scripts/work-source.sh ~/.local/bin/work-source && chmod +x ~/.local/bin/work-source
57
+ work-source local # this tree (or: work-source local /path/to/work)
58
+ work-source rebuild # rebuild + restart without rewriting the unit
59
+ work-source prod # global @dylanpiercey/work again
60
+ work-source # status
53
61
  ./scripts/run-prod.sh # or: build with --no-service and run manually
54
62
  ./scripts/update.sh # later: pull latest, rebuild, restart
55
63
  ```
@@ -86,7 +94,12 @@ surrounding environment still takes precedence:
86
94
  WORK_BRANCH_PREFIX=rturnq
87
95
  ```
88
96
 
89
- Optional: a `plan-usage` CLI on PATH enables the agent plan/quota usage panel.
97
+ The usage panel (and `work usage`) reads plan/quota windows straight from each
98
+ agent CLI's own credentials on disk — Claude, Codex, Cursor, Grok, and Copilot
99
+ (via `gh`'s token). Providers you are not signed into simply say so.
100
+
101
+ PR chips refresh by polling GitHub (faster for a few minutes after a
102
+ local push via `repo-pushed`). No inbound GitHub webhooks are required.
90
103
 
91
104
  ## Layout on disk
92
105
 
package/bin/work.mjs CHANGED
@@ -4,6 +4,7 @@
4
4
  // work setup install/refresh the background service (+ optional tunnel)
5
5
  // work start run the server in the foreground
6
6
  // work update upgrade the npm package and refresh the service
7
+ // work usage print agent plan/quota usage
7
8
  // work version print the installed version
8
9
  import { execFileSync, spawnSync } from "node:child_process";
9
10
  import fs from "node:fs";
@@ -43,6 +44,9 @@ switch (command) {
43
44
  case "update":
44
45
  await update();
45
46
  break;
47
+ case "usage":
48
+ await usage();
49
+ break;
46
50
  case "version":
47
51
  case "--version":
48
52
  case "-v":
@@ -50,7 +54,7 @@ switch (command) {
50
54
  break;
51
55
  default:
52
56
  console.log(
53
- `work ${pkg.version}\n\nusage: work <setup|start|update|version>`,
57
+ `work ${pkg.version}\n\nusage: work <setup|start|update|usage|version>`,
54
58
  );
55
59
  }
56
60
 
@@ -60,6 +64,77 @@ async function start() {
60
64
  await import(distEntry);
61
65
  }
62
66
 
67
+ /** Plan/quota usage, read from the running server.
68
+ *
69
+ * The collector lives in the server bundle (src/server/usage/) so the page and
70
+ * this table can never disagree, which is also why this asks over HTTP instead
71
+ * of re-reading every provider's credentials itself. */
72
+ async function usage() {
73
+ const port = serviceEnv().PORT;
74
+ const url = `http://127.0.0.1:${port}/api/usage${args.includes("--refresh") ? "?refresh" : ""}`;
75
+ let data;
76
+ try {
77
+ const res = await fetch(url, { signal: AbortSignal.timeout(30_000) });
78
+ if (!res.ok) die(`server answered ${res.status} for /api/usage`);
79
+ data = await res.json();
80
+ } catch {
81
+ die(`no work server on port ${port} — start one with: work start`);
82
+ }
83
+ if (args.includes("--json")) {
84
+ console.log(JSON.stringify(data, null, 2));
85
+ return;
86
+ }
87
+ if (data.error) die(data.error);
88
+ const agents = data.agents || [];
89
+ if (!agents.length) return console.log("no agent accounts found");
90
+ for (const agent of agents) {
91
+ const head = [agent.agent, agent.plan?.replace(/^default_/, "").replaceAll("_", " "), agent.account]
92
+ .filter(Boolean)
93
+ .join(" · ");
94
+ console.log(`\n${head}`);
95
+ for (const win of agent.windows || []) {
96
+ const pct = Math.max(0, Math.min(100, win.used_percent));
97
+ const filled = Math.round(pct / 10);
98
+ const bar = "█".repeat(filled) + "░".repeat(10 - filled);
99
+ const resets = until(win.resets_at);
100
+ console.log(
101
+ ` ${win.window.padEnd(5)} ${bar} ${pctText(win.used_percent).padStart(5)}${resets ? ` ↻ ${resets}` : ""}`,
102
+ );
103
+ }
104
+ // Only reason a row can be empty or wrong, so it goes last and unindented
105
+ // enough to read as a warning rather than another window.
106
+ if (agent.note) console.log(` ⚠ ${agent.note}`);
107
+ if (agent.stale_seconds != null) {
108
+ console.log(` ⚠ ${short(agent.stale_seconds * 1000)} old`);
109
+ }
110
+ }
111
+ }
112
+
113
+ /** "4h" / "6d" — how long until an ISO timestamp. A reset already in the past
114
+ * means the window turned over and this row hasn't refreshed since, so there
115
+ * is no honest countdown to print. */
116
+ function until(iso) {
117
+ if (!iso) return null;
118
+ const ms = new Date(iso).getTime() - Date.now();
119
+ return ms > 0 ? short(ms) : null;
120
+ }
121
+
122
+ /** Percent, with a decimal only where rounding would lie: 99.6% must not
123
+ * read as a spent 100%, and 0.4% must not read as an untouched 0%. */
124
+ function pctText(pct) {
125
+ const rounded = Math.round(pct);
126
+ return rounded !== pct && (rounded === 100 || rounded === 0)
127
+ ? `${pct.toFixed(1)}%`
128
+ : `${rounded}%`;
129
+ }
130
+
131
+ function short(ms) {
132
+ const m = Math.round(ms / 60_000);
133
+ if (m < 60) return `${m}m`;
134
+ const h = Math.round(m / 60);
135
+ return h < 48 ? `${h}h` : `${Math.round(h / 24)}d`;
136
+ }
137
+
63
138
  async function setup() {
64
139
  // Runtime tools. The curl installer normally provides these; a plain
65
140
  // `npm i -g` user may be missing them.