@monoes/monomindcli 2.9.21 → 2.9.22

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 (61) hide show
  1. package/.claude/skills/mastermind-createorg/SKILL.md +26 -3
  2. package/dist/src/commands/events.d.ts +9 -0
  3. package/dist/src/commands/events.d.ts.map +1 -0
  4. package/dist/src/commands/events.js +89 -0
  5. package/dist/src/commands/events.js.map +1 -0
  6. package/dist/src/commands/index.d.ts +1 -1
  7. package/dist/src/commands/index.d.ts.map +1 -1
  8. package/dist/src/commands/index.js +2 -1
  9. package/dist/src/commands/index.js.map +1 -1
  10. package/dist/src/commands/org-observe.d.ts +21 -0
  11. package/dist/src/commands/org-observe.d.ts.map +1 -1
  12. package/dist/src/commands/org-observe.js +79 -0
  13. package/dist/src/commands/org-observe.js.map +1 -1
  14. package/dist/src/commands/org.d.ts.map +1 -1
  15. package/dist/src/commands/org.js +20 -0
  16. package/dist/src/commands/org.js.map +1 -1
  17. package/dist/src/orgrt/approvals.d.ts +16 -1
  18. package/dist/src/orgrt/approvals.d.ts.map +1 -1
  19. package/dist/src/orgrt/approvals.js +39 -2
  20. package/dist/src/orgrt/approvals.js.map +1 -1
  21. package/dist/src/orgrt/copilot-runner.d.ts +14 -0
  22. package/dist/src/orgrt/copilot-runner.d.ts.map +1 -0
  23. package/dist/src/orgrt/copilot-runner.js +250 -0
  24. package/dist/src/orgrt/copilot-runner.js.map +1 -0
  25. package/dist/src/orgrt/crush-runner.d.ts +24 -0
  26. package/dist/src/orgrt/crush-runner.d.ts.map +1 -0
  27. package/dist/src/orgrt/crush-runner.js +251 -0
  28. package/dist/src/orgrt/crush-runner.js.map +1 -0
  29. package/dist/src/orgrt/daemon.d.ts +40 -1
  30. package/dist/src/orgrt/daemon.d.ts.map +1 -1
  31. package/dist/src/orgrt/daemon.js +63 -2
  32. package/dist/src/orgrt/daemon.js.map +1 -1
  33. package/dist/src/orgrt/grok-runner.d.ts +18 -0
  34. package/dist/src/orgrt/grok-runner.d.ts.map +1 -0
  35. package/dist/src/orgrt/grok-runner.js +323 -0
  36. package/dist/src/orgrt/grok-runner.js.map +1 -0
  37. package/dist/src/orgrt/pi-rpc-runner.d.ts +68 -0
  38. package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -0
  39. package/dist/src/orgrt/pi-rpc-runner.js +400 -0
  40. package/dist/src/orgrt/pi-rpc-runner.js.map +1 -0
  41. package/dist/src/orgrt/pi-runner.d.ts +16 -0
  42. package/dist/src/orgrt/pi-runner.d.ts.map +1 -0
  43. package/dist/src/orgrt/pi-runner.js +264 -0
  44. package/dist/src/orgrt/pi-runner.js.map +1 -0
  45. package/dist/src/orgrt/qwen-runner.d.ts +18 -0
  46. package/dist/src/orgrt/qwen-runner.d.ts.map +1 -0
  47. package/dist/src/orgrt/qwen-runner.js +267 -0
  48. package/dist/src/orgrt/qwen-runner.js.map +1 -0
  49. package/dist/src/orgrt/types.d.ts +18 -0
  50. package/dist/src/orgrt/types.d.ts.map +1 -1
  51. package/dist/src/orgrt/types.js +2 -2
  52. package/dist/src/orgrt/types.js.map +1 -1
  53. package/dist/src/orgrt/usage-proxy.d.ts +32 -0
  54. package/dist/src/orgrt/usage-proxy.d.ts.map +1 -0
  55. package/dist/src/orgrt/usage-proxy.js +226 -0
  56. package/dist/src/orgrt/usage-proxy.js.map +1 -0
  57. package/dist/src/ui/dashboard.html +63 -0
  58. package/dist/src/ui/orgs.html +8 -1
  59. package/dist/src/ui/routes-org.mjs +26 -0
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +2 -2
@@ -96,7 +96,7 @@ export const RoleSchema = z.object({
96
96
  * agent runtime regardless of the org-level `runtime` field or the
97
97
  * MONOMIND_RUNTIME env var ('claude' explicitly forces the Claude default).
98
98
  * Enables mixed-runtime orgs — e.g. a Claude coordinator with opencode workers. */
99
- runtime: z.enum(['claude', 'kimicode', 'opencode', 'vercel', 'codex', 'antigravity']).optional(),
99
+ runtime: z.enum(['claude', 'kimicode', 'opencode', 'vercel', 'codex', 'antigravity', 'grok', 'qwen', 'crush', 'copilot', 'pi', 'pi-rpc']).optional(),
100
100
  /** Per-role override of run_config.max_turns_per_message — roles that legitimately
101
101
  * need many more turns per message (e.g. a developer doing sequential build/fix/verify
102
102
  * cycles) than others (e.g. docs, pm) shouldn't be forced onto one global budget. */
@@ -155,7 +155,7 @@ export const OrgDefSchema = z.object({
155
155
  * MONOMIND_RUNTIME env var is honored, falling back to the default Claude
156
156
  * runner. Per-org values override the env var, and a role's own `runtime`
157
157
  * field (see RoleSchema) overrides this per role. */
158
- runtime: z.enum(['claude', 'kimicode', 'opencode', 'vercel', 'codex', 'antigravity']).optional(),
158
+ runtime: z.enum(['claude', 'kimicode', 'opencode', 'vercel', 'codex', 'antigravity', 'grok', 'qwen', 'crush', 'copilot', 'pi', 'pi-rpc']).optional(),
159
159
  }).passthrough();
160
160
  export const ORG_DIR = '.monomind/orgs';
161
161
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/orgrt/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/orgrt/types.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAExF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAEpG,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAEtG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACvD,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACjD,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACrD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;QACxC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,EAAE;KAC9D,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACvB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACvC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC,OAAO,EAAE,CAAC;AAGb,4FAA4F;AAC5F,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;QACX,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ;QAC9E,gBAAgB,EAAE,OAAO,EAAE,aAAa;KACzC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;IAC1B,6EAA6E;IAC7E,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC;QACb,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK;QACzD,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ;QACpD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ;QAC/C,mBAAmB;KACpB,CAAC,CAAC,QAAQ,EAAE;IACb,8DAA8D;IAC9D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,iEAAiE;IACjE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC,MAAM,EAAE,CAAC;AAEZ,MAAM,YAAY,GAAG,CAAC,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,sBAAsB;IAC3F,gBAAgB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,SAAS,CAAU,CAAC;AAExG,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxD,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC1C,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACvC,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACtC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IACrD,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACzD,CAAC,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC;AAK3B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1C,wCAAwC;IACxC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7C;;6EAEyE;IACzE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACxC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACjD;2EACuE;IACvE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC/D,KAAK,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACnC;;;;;6DAKyD;IACzD,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CACjD,CAAC,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC;AAE3B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC/C,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACjD,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC;QACvB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;QAC9C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAClC,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACvB,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE;IACnC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,EAAE;IACnC;;;wFAGoF;IACpF,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;IACpJ;;0FAEsF;IACtF,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC7D;;kFAE8E;IAC9E,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACtD,CAAC,CAAC,WAAW,EAAE,CAAC;AAEjB;;;;;sEAKsE;AACtE,MAAM,CAAC,MAAM,6BAA6B,GAAG,OAAO,CAAC;AAErD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;IACrC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACnE,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;QAC7D,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACvC,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,6BAA6B,CAAC;QACzF,mFAAmF;QACnF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;QACjD;;;;iDAIyC;QACzC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;QAC5I;wFACgF;QAChF,eAAe,EAAE,CAAC,CAAC,MAAM,CAAC;YACxB,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YACzD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;SACvD,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QACvB,eAAe,EAAE,oBAAoB,CAAC,QAAQ,EAAE;QAChD;uEAC+D;QAC/D,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAC/D;kFAC0E;QAC1E,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;YAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;YAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;SACpB,CAAC,CAAC,CAAC,QAAQ,EAAE;KACf,CAAC,CAAC,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;SACnC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE,aAAa,EAAE,SAAS,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,SAAS,EAAE,MAAgB,EAAE,oBAAoB,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC/L,KAAK,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACnC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC;;;0DAGsD;IACtD,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;CACrJ,CAAC,CAAC,WAAW,EAAE,CAAC;AA+CjB,MAAM,CAAC,MAAM,OAAO,GAAG,gBAAgB,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
@@ -0,0 +1,32 @@
1
+ export interface UsageTotals {
2
+ inputTokens: number;
3
+ outputTokens: number;
4
+ }
5
+ export type UsageApiStyle = 'openai' | 'anthropic';
6
+ export interface UsageProxyOptions {
7
+ /** The real API base URL requests are relayed to, e.g. https://api.openai.com. */
8
+ upstreamBaseUrl: string;
9
+ /** Which response-body shape to look for usage in. */
10
+ apiStyle: UsageApiStyle;
11
+ }
12
+ /** Parse a (possibly SSE) response body buffer for the usage it carries,
13
+ * merging per-field across every JSON document / SSE chunk found (not
14
+ * "last chunk wins" as a whole object — see mergeUsage). Handles both a
15
+ * single JSON document and `data: {...}\n\n` SSE framing. Exported for unit
16
+ * testing without spinning up a real server. */
17
+ export declare function parseUsageFromResponseBody(body: string, apiStyle: UsageApiStyle): UsageTotals | undefined;
18
+ export declare class UsageProxyServer {
19
+ private opts;
20
+ private server;
21
+ private boundPort;
22
+ private totalsAcc;
23
+ private readonly upstream;
24
+ constructor(opts: UsageProxyOptions);
25
+ start(): Promise<void>;
26
+ url(): string;
27
+ totals(): UsageTotals;
28
+ reset(): void;
29
+ stop(): Promise<void>;
30
+ private handle;
31
+ }
32
+ //# sourceMappingURL=usage-proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-proxy.d.ts","sourceRoot":"","sources":["../../../src/orgrt/usage-proxy.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,kFAAkF;IAClF,eAAe,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,EAAE,aAAa,CAAC;CACzB;AAoDD;;;;iDAIiD;AACjD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,WAAW,GAAG,SAAS,CAyCzG;AAED,qBAAa,gBAAgB;IAMf,OAAO,CAAC,IAAI;IALxB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,SAAS,CAAoD;IACrE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAM;IAE/B,YAAoB,IAAI,EAAE,iBAAiB,EAE1C;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAS3B;IAED,GAAG,IAAI,MAAM,CAEZ;IAED,MAAM,IAAI,WAAW,CAEpB;IAED,KAAK,IAAI,IAAI,CAEZ;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAI1B;IAED,OAAO,CAAC,MAAM;CAuDf"}
@@ -0,0 +1,226 @@
1
+ // packages/@monomind/cli/src/orgrt/usage-proxy.ts
2
+ /**
3
+ * UsageProxyServer — a loopback HTTP reverse proxy that sits between a
4
+ * subprocess CLI and its configured LLM API base URL, purely to observe
5
+ * token usage. It is NOT part of the request/response path functionally —
6
+ * every request/response is relayed byte-for-byte unchanged; usage parsing
7
+ * is a side-channel that never affects what the CLI sees.
8
+ *
9
+ * Why this exists: some subprocess-backed AgentRunners (CrushAgentRunner,
10
+ * CopilotAgentRunner) drive CLIs whose non-interactive output doesn't
11
+ * self-report token usage the way codex/kimi/qwen/grok's JSON event streams
12
+ * do. Those CLIs DO support pointing at a custom OpenAI-compatible (or
13
+ * Anthropic-compatible) base URL for BYOK/self-hosted use — this proxy uses
14
+ * that existing knob rather than needing any CLI-side cooperation: the
15
+ * runner starts a UsageProxyServer pointed at the real upstream, sets the
16
+ * CLI's base-url env var to `proxy.url()`, and reads `proxy.totals()` after
17
+ * each turn.
18
+ *
19
+ * Deliberately generic — not tied to crush/copilot specifically. Any future
20
+ * subprocess runner whose CLI doesn't self-report usage can reuse this.
21
+ */
22
+ import { createServer as createHttpServer, request as httpRequest } from 'node:http';
23
+ import { request as httpsRequest } from 'node:https';
24
+ import { URL } from 'node:url';
25
+ /** Extract usage tokens from a single parsed JSON body (a plain
26
+ * chat-completion response, or one SSE `data:` chunk). Returns undefined
27
+ * when the body has no usage field — callers accumulate across chunks.
28
+ *
29
+ * Anthropic-specific: input_tokens arrives on the `message_start` SSE event
30
+ * under `message.usage` (NOT top-level `usage`), while output_tokens
31
+ * arrives on later `message_delta` events under top-level `usage` — the two
32
+ * fields legitimately arrive in DIFFERENT chunks of the same stream. Fields
33
+ * are OPTIONAL in the return value (omitted, not defaulted to 0) precisely
34
+ * so the caller can merge per-field across chunks instead of the last
35
+ * chunk's presence/absence clobbering an earlier chunk's value — a body
36
+ * shape returning always-present-defaulted-to-0 fields made that merge
37
+ * impossible to do correctly upstream. */
38
+ function extractUsageFromBody(body, apiStyle) {
39
+ if (!body || typeof body !== 'object')
40
+ return undefined;
41
+ const record = body;
42
+ const topUsage = record.usage;
43
+ const nestedMessageUsage = apiStyle === 'anthropic' && record.message && typeof record.message === 'object'
44
+ ? record.message.usage
45
+ : undefined;
46
+ if (apiStyle === 'anthropic') {
47
+ const topU = (topUsage && typeof topUsage === 'object') ? topUsage : undefined;
48
+ const nestedU = (nestedMessageUsage && typeof nestedMessageUsage === 'object') ? nestedMessageUsage : undefined;
49
+ if (!topU && !nestedU)
50
+ return undefined;
51
+ const input = nestedU?.input_tokens ?? topU?.input_tokens;
52
+ const output = topU?.output_tokens ?? nestedU?.output_tokens;
53
+ const result = {};
54
+ if (typeof input === 'number')
55
+ result.inputTokens = input;
56
+ if (typeof output === 'number')
57
+ result.outputTokens = output;
58
+ return (result.inputTokens !== undefined || result.outputTokens !== undefined) ? result : undefined;
59
+ }
60
+ // openai style
61
+ if (!topUsage || typeof topUsage !== 'object')
62
+ return undefined;
63
+ const u = topUsage;
64
+ const result = {};
65
+ if (typeof u.prompt_tokens === 'number')
66
+ result.inputTokens = u.prompt_tokens;
67
+ if (typeof u.completion_tokens === 'number')
68
+ result.outputTokens = u.completion_tokens;
69
+ return (result.inputTokens !== undefined || result.outputTokens !== undefined) ? result : undefined;
70
+ }
71
+ /** Merge a newly-seen partial usage reading into an accumulator, per field —
72
+ * a later chunk that doesn't report a field must not erase an earlier
73
+ * chunk's value for that field (see extractUsageFromBody's header). */
74
+ function mergeUsage(acc, next) {
75
+ if (next.inputTokens !== undefined)
76
+ acc.inputTokens = next.inputTokens;
77
+ if (next.outputTokens !== undefined)
78
+ acc.outputTokens = next.outputTokens;
79
+ }
80
+ /** Parse a (possibly SSE) response body buffer for the usage it carries,
81
+ * merging per-field across every JSON document / SSE chunk found (not
82
+ * "last chunk wins" as a whole object — see mergeUsage). Handles both a
83
+ * single JSON document and `data: {...}\n\n` SSE framing. Exported for unit
84
+ * testing without spinning up a real server. */
85
+ export function parseUsageFromResponseBody(body, apiStyle) {
86
+ const trimmed = body.trim();
87
+ if (!trimmed)
88
+ return undefined;
89
+ const merged = {};
90
+ if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
91
+ try {
92
+ const parsed = JSON.parse(trimmed);
93
+ if (Array.isArray(parsed)) {
94
+ for (const item of parsed) {
95
+ const u = extractUsageFromBody(item, apiStyle);
96
+ if (u)
97
+ mergeUsage(merged, u);
98
+ }
99
+ }
100
+ else {
101
+ const u = extractUsageFromBody(parsed, apiStyle);
102
+ if (u)
103
+ mergeUsage(merged, u);
104
+ }
105
+ }
106
+ catch {
107
+ return undefined;
108
+ }
109
+ return (merged.inputTokens !== undefined || merged.outputTokens !== undefined)
110
+ ? { inputTokens: merged.inputTokens ?? 0, outputTokens: merged.outputTokens ?? 0 }
111
+ : undefined;
112
+ }
113
+ // SSE framing: scan every `data: ` line, merging per field across chunks.
114
+ for (const rawLine of trimmed.split('\n')) {
115
+ const line = rawLine.trim();
116
+ if (!line.startsWith('data:'))
117
+ continue;
118
+ const payload = line.slice(5).trim();
119
+ if (!payload || payload === '[DONE]')
120
+ continue;
121
+ try {
122
+ const u = extractUsageFromBody(JSON.parse(payload), apiStyle);
123
+ if (u)
124
+ mergeUsage(merged, u);
125
+ }
126
+ catch {
127
+ // ignore malformed SSE chunk — best-effort side-channel
128
+ }
129
+ }
130
+ return (merged.inputTokens !== undefined || merged.outputTokens !== undefined)
131
+ ? { inputTokens: merged.inputTokens ?? 0, outputTokens: merged.outputTokens ?? 0 }
132
+ : undefined;
133
+ }
134
+ export class UsageProxyServer {
135
+ opts;
136
+ server;
137
+ boundPort = 0;
138
+ totalsAcc = { inputTokens: 0, outputTokens: 0 };
139
+ upstream;
140
+ constructor(opts) {
141
+ this.opts = opts;
142
+ this.upstream = new URL(opts.upstreamBaseUrl);
143
+ }
144
+ async start() {
145
+ if (this.server)
146
+ return;
147
+ this.server = createHttpServer((req, res) => this.handle(req, res));
148
+ await new Promise((resolve, reject) => {
149
+ this.server.once('error', reject);
150
+ this.server.listen(0, '127.0.0.1', () => resolve());
151
+ });
152
+ const addr = this.server.address();
153
+ this.boundPort = typeof addr === 'object' && addr ? addr.port : 0;
154
+ }
155
+ url() {
156
+ return `http://127.0.0.1:${this.boundPort}`;
157
+ }
158
+ totals() {
159
+ return { ...this.totalsAcc };
160
+ }
161
+ reset() {
162
+ this.totalsAcc = { inputTokens: 0, outputTokens: 0 };
163
+ }
164
+ async stop() {
165
+ if (!this.server)
166
+ return;
167
+ await new Promise((resolve) => this.server.close(() => resolve()));
168
+ this.server = undefined;
169
+ }
170
+ handle(clientReq, clientRes) {
171
+ const isHttps = this.upstream.protocol === 'https:';
172
+ const upstreamPath = (clientReq.url ?? '/');
173
+ // Force identity encoding: parseUsageFromResponseBody reads the response
174
+ // body as raw utf8 text. If the CLI's HTTP client sends its own
175
+ // Accept-Encoding and the upstream honors it with a compressed (gzip)
176
+ // response, that read silently produces garbage — JSON.parse fails,
177
+ // usage extraction returns undefined, and accounting stays at 0 with no
178
+ // error surfaced anywhere. Stripping it here means the upstream always
179
+ // sends plain text, which this proxy can actually parse.
180
+ const headers = { ...clientReq.headers, host: this.upstream.host };
181
+ delete headers['accept-encoding'];
182
+ const upstreamReq = (isHttps ? httpsRequest : httpRequest)({
183
+ protocol: this.upstream.protocol,
184
+ hostname: this.upstream.hostname,
185
+ port: this.upstream.port || (isHttps ? 443 : 80),
186
+ path: upstreamPath,
187
+ method: clientReq.method,
188
+ headers,
189
+ }, (upstreamRes) => {
190
+ clientRes.writeHead(upstreamRes.statusCode ?? 502, upstreamRes.headers);
191
+ const chunks = [];
192
+ upstreamRes.on('data', (chunk) => {
193
+ chunks.push(chunk);
194
+ clientRes.write(chunk);
195
+ });
196
+ upstreamRes.on('end', () => {
197
+ clientRes.end();
198
+ try {
199
+ const body = Buffer.concat(chunks).toString('utf8');
200
+ const usage = parseUsageFromResponseBody(body, this.opts.apiStyle);
201
+ if (usage) {
202
+ this.totalsAcc.inputTokens += usage.inputTokens;
203
+ this.totalsAcc.outputTokens += usage.outputTokens;
204
+ }
205
+ }
206
+ catch {
207
+ // usage extraction is a side-channel — never let it break the proxied response
208
+ }
209
+ });
210
+ upstreamRes.on('error', () => { try {
211
+ clientRes.end();
212
+ }
213
+ catch { /* already closed */ } });
214
+ });
215
+ upstreamReq.on('error', () => {
216
+ try {
217
+ if (!clientRes.headersSent)
218
+ clientRes.writeHead(502);
219
+ clientRes.end();
220
+ }
221
+ catch { /* client already gone */ }
222
+ });
223
+ clientReq.pipe(upstreamReq);
224
+ }
225
+ }
226
+ //# sourceMappingURL=usage-proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-proxy.js","sourceRoot":"","sources":["../../../src/orgrt/usage-proxy.ts"],"names":[],"mappings":"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"}
@@ -2098,6 +2098,9 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
2098
2098
  <button class="odt-btn secondary" data-tab="costs" onclick="v2SwitchOrgTab('costs')">Costs</button>
2099
2099
  <button class="odt-btn secondary" data-tab="config" onclick="v2SwitchOrgTab('config')">Config</button>
2100
2100
  <button class="odt-btn secondary" data-tab="files" onclick="v2SwitchOrgTab('files')">Files</button>
2101
+ <button class="odt-btn secondary" data-tab="approvals" onclick="v2SwitchOrgTab('approvals')">Approvals</button>
2102
+ <button class="odt-btn secondary" data-tab="budgets" onclick="v2SwitchOrgTab('budgets')">Budgets</button>
2103
+ <button class="odt-btn secondary" data-tab="decisions" onclick="v2SwitchOrgTab('decisions')">Decisions</button>
2101
2104
  </div>
2102
2105
  <div id="org-detail-body">
2103
2106
  <div class="odt-pane active" id="odt-chart"></div>
@@ -2108,6 +2111,9 @@ select.pb-cfg-inp { padding: 4px 7px; cursor: pointer; }
2108
2111
  <div class="odt-pane" id="odt-costs"></div>
2109
2112
  <div class="odt-pane" id="odt-config" style="overflow-y:auto"></div>
2110
2113
  <div class="odt-pane" id="odt-files" style="overflow-y:auto"></div>
2114
+ <div class="odt-pane" id="odt-approvals"></div>
2115
+ <div class="odt-pane" id="odt-budgets"></div>
2116
+ <div class="odt-pane" id="odt-decisions"></div>
2111
2117
  </div>
2112
2118
  </div>
2113
2119
  <div id="org-copy-dialog" style="display:none;position:absolute;inset:0;background:rgba(0,0,0,0.72);z-index:90;align-items:center;justify-content:center">
@@ -5863,6 +5869,7 @@ function v2RenderOrgTab(tab) {
5863
5869
  else if (tab === 'routines') v2RenderOrgRoutines();
5864
5870
  else if (tab === 'myissues') v2RenderOrgMyIssues();
5865
5871
  else if (tab === 'budgets') v2RenderOrgBudgets();
5872
+ else if (tab === 'decisions') v2RenderOrgDecisions();
5866
5873
  else if (tab === 'plugins') v2RenderOrgPlugins();
5867
5874
  else if (tab === 'charts') v2RenderOrgCharts();
5868
5875
  else if (tab === 'projects') v2RenderOrgProjects();
@@ -7171,6 +7178,62 @@ async function orgApprovalAction(id, action) {
7171
7178
  } catch (e) { showToast('Error', e.message, 'err'); }
7172
7179
  }
7173
7180
 
7181
+ // ── DECISIONS ──────────────────────────────────────────────
7182
+ let _v2DecisionsCache = [];
7183
+ let _v2DecisionsStatusFilter = 'all';
7184
+ let _v2DecisionsRoleFilter = 'all';
7185
+
7186
+ async function v2RenderOrgDecisions() {
7187
+ const el = document.getElementById('odt-decisions');
7188
+ if (!el || !_v2SelOrg) return;
7189
+ const _rendOrg = _v2SelOrg;
7190
+ el.innerHTML = '<div class="loading-txt">Loading…</div>';
7191
+ try {
7192
+ const _enc = encodeURIComponent(_rendOrg);
7193
+ const data = await fetch(`/api/org/${_enc}/gates${DIR ? '?dir=' + encodeURIComponent(DIR) : ''}`).then(r => r.ok ? r.json() : { gates: [] }).catch(() => ({ gates: [] }));
7194
+ if (_v2SelOrg !== _rendOrg) return;
7195
+ _v2DecisionsCache = Array.isArray(data) ? data : (data.gates || []);
7196
+ _v2DecisionsStatusFilter = 'all';
7197
+ _v2DecisionsRoleFilter = 'all';
7198
+ v2RenderDecisionsTable();
7199
+ } catch (e) { el.innerHTML = '<div class="empty">Failed: ' + esc(e.message) + '</div>'; }
7200
+ }
7201
+
7202
+ function v2RenderDecisionsTable() {
7203
+ const el = document.getElementById('odt-decisions');
7204
+ if (!el) return;
7205
+ const gates = _v2DecisionsCache;
7206
+ const roles = [...new Set(gates.map(g => g.roleId || '—'))].sort();
7207
+ const filtered = gates.filter(g =>
7208
+ (_v2DecisionsStatusFilter === 'all' || (g.status || 'pending') === _v2DecisionsStatusFilter) &&
7209
+ (_v2DecisionsRoleFilter === 'all' || (g.roleId || '—') === _v2DecisionsRoleFilter)
7210
+ );
7211
+ const filterBar = `<div style="display:flex;gap:10px;margin-bottom:10px">
7212
+ <select class="filter-input" style="width:auto" onchange="_v2DecisionsStatusFilter=this.value;v2RenderDecisionsTable()">
7213
+ ${['all', 'pending', 'approved', 'rejected'].map(s => `<option value="${s}" ${_v2DecisionsStatusFilter===s?'selected':''}>${s === 'all' ? 'All statuses' : s}</option>`).join('')}
7214
+ </select>
7215
+ <select class="filter-input" style="width:auto" onchange="_v2DecisionsRoleFilter=this.value;v2RenderDecisionsTable()">
7216
+ <option value="all" ${_v2DecisionsRoleFilter==='all'?'selected':''}>All roles</option>
7217
+ ${roles.map(r => `<option value="${esc(r)}" ${_v2DecisionsRoleFilter===r?'selected':''}>${esc(r)}</option>`).join('')}
7218
+ </select>
7219
+ </div>`;
7220
+ if (!filtered.length) { el.innerHTML = filterBar + '<div class="empty">No decision gates match</div>'; return; }
7221
+ el.innerHTML = filterBar + `<table style="width:100%;border-collapse:collapse;font-size:12px">
7222
+ <thead><tr style="color:var(--text-xs);text-align:left">
7223
+ <th style="padding:6px 8px">Role</th><th>Gate</th><th>Status</th><th>Resolution</th><th>Date</th>
7224
+ </tr></thead><tbody>` +
7225
+ filtered.slice(0, 100).map(g => {
7226
+ const cls = g.status === 'approved' ? 'on' : g.status === 'rejected' ? 'warn' : '';
7227
+ return `<tr style="border-top:1px solid var(--border)">
7228
+ <td style="padding:6px 8px;color:var(--text-hi)">${esc(g.roleId || '—')}</td>
7229
+ <td style="padding:6px 8px;color:var(--text-lo);max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="${esc(g.description || '')}">${esc(g.name || '—')}</td>
7230
+ <td style="padding:6px 8px"><span class="ss-pill ${cls}">${esc(g.status || 'pending')}</span></td>
7231
+ <td style="padding:6px 8px;color:var(--text-lo);max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(g.resolution || '—')}</td>
7232
+ <td style="padding:6px 8px;color:var(--text-xs);font-size:11px;font-family:var(--mono)">${relTime(g.resolvedAt || g.createdAt)}</td>
7233
+ </tr>`;
7234
+ }).join('') + '</tbody></table>';
7235
+ }
7236
+
7174
7237
  // ── SECRETS ────────────────────────────────────────────────
7175
7238
  async function v2RenderOrgSecrets() {
7176
7239
  const el = document.getElementById('odt-secrets');
@@ -1406,7 +1406,14 @@ function renderTab(tab) {
1406
1406
  function renderChart() {
1407
1407
  const d = orgDetailData;
1408
1408
  const roles = Array.isArray(d.roles) ? d.roles : [];
1409
- const comms = Array.isArray(d.communication) ? d.communication : [];
1409
+ // Structural report lines come straight from each role's reports_to (the
1410
+ // authoritative chain also shown in the Roles tab) — declared communication
1411
+ // edges (command/feedback/handoff busses) don't reflect who actually reports
1412
+ // to whom, e.g. a hierarchical topology's queen commanding every worker directly.
1413
+ const reportEdges = roles
1414
+ .filter(r => r.reports_to && r.reports_to !== r.id)
1415
+ .map(r => ({ from: r.id, to: r.reports_to, type: 'report' }));
1416
+ const comms = reportEdges.concat(Array.isArray(d.communication) ? d.communication : []);
1410
1417
  const running = !!(allOrgs.find(o => o.name === selectedOrg) || {}).running;
1411
1418
 
1412
1419
  // Meta bar
@@ -878,6 +878,32 @@ if (req.method === 'GET' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/ap
878
878
  return true;
879
879
  }
880
880
 
881
+ // GET /api/org/:name/gates — decision gate log (read-only explorer; resolving stays
882
+ // CLI-only via `org gate-approve`/`gate-reject`, which needs the daemon's
883
+ // x-monomind-cred auth header for live delivery — out of scope for a read-only view)
884
+ if (req.method === 'GET' && url.match(/^\/api\/org\/[a-z0-9][a-z0-9_-]{0,63}\/gates(\?.*)?$/i)) {
885
+ try {
886
+ const orgName = decodeURIComponent(url.split('/')[3].split('?')[0]);
887
+ if (orgName.length > 64 || !/^[a-z0-9][a-z0-9_-]*$/i.test(orgName)) { res.writeHead(400); res.end('Invalid org name'); return true; }
888
+ const _gatesQs = new URL(req.url, 'http://localhost').searchParams;
889
+ const base = path.join(path.resolve(_gatesQs.get('dir') || ctx.projectDir || process.cwd()), '.monomind', 'orgs');
890
+ const readJsonSafe = (f) => { try { return JSON.parse(fs.readFileSync(f, 'utf8')); } catch(_) { return null; } };
891
+ const data = readJsonSafe(path.join(base, orgName, 'gates.json')) || { gates: [] };
892
+ const gates = (data.gates || [])
893
+ .sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0))
894
+ .map(g => ({
895
+ id: g.id, name: g.name, description: g.description, roleId: g.roleId,
896
+ status: g.status || 'pending', createdAt: g.createdAt || null,
897
+ resolvedBy: g.resolvedBy || null, resolvedAt: g.resolvedAt || null,
898
+ resolution: g.resolution || null,
899
+ }));
900
+ const pending = gates.filter(g => g.status === 'pending').length;
901
+ res.writeHead(200, { 'Content-Type': 'application/json', ...(corsOrigin ? { 'Access-Control-Allow-Origin': corsOrigin } : {}) });
902
+ res.end(JSON.stringify({ gates, pending }));
903
+ } catch(_) { res.writeHead(500); res.end('{"gates":[],"pending":0}'); }
904
+ return true;
905
+ }
906
+
881
907
  // GET /api/questions?dir=<ctx.projectDir> — list ask_human questions (pending and
882
908
  // answered) for every org in one project. Mirrors the existing -approvals.json
883
909
  // sidecar convention, but reads this feature's .monomind/orgs/<org>/questions.json