@rubytech/create-maxy-code 0.1.567 → 0.1.569

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 (120) hide show
  1. package/dist/__tests__/brand-agent-root.test.js +91 -0
  2. package/dist/brand-agent-root.js +58 -0
  3. package/dist/index.js +25 -28
  4. package/package.json +1 -1
  5. package/payload/platform/plugins/admin/PLUGIN.md +4 -2
  6. package/payload/platform/plugins/admin/hooks/__tests__/quote-path-write-gate.test.sh +152 -0
  7. package/payload/platform/plugins/admin/hooks/__tests__/quote-pdf-bash-gate.test.sh +95 -0
  8. package/payload/platform/plugins/admin/hooks/__tests__/quote-render-gate.test.sh +141 -45
  9. package/payload/platform/plugins/admin/hooks/__tests__/quote-render-pdf-conformance.test.sh +114 -0
  10. package/payload/platform/plugins/admin/hooks/quote-path-write-gate.sh +137 -0
  11. package/payload/platform/plugins/admin/hooks/quote-pdf-bash-gate.sh +70 -0
  12. package/payload/platform/plugins/admin/hooks/quote-render-gate.sh +105 -37
  13. package/payload/platform/plugins/admin/hooks/quote-render-pdf-conformance.sh +178 -0
  14. package/payload/platform/plugins/admin/mcp/dist/index.js +7 -1
  15. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  16. package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.d.ts +10 -1
  17. package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.d.ts.map +1 -1
  18. package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.js +52 -1
  19. package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.js.map +1 -1
  20. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts +9 -0
  21. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts.map +1 -1
  22. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js +1 -1
  23. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js.map +1 -1
  24. package/payload/platform/plugins/admin/skills/capabilities-here/SKILL.md +1 -1
  25. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +44 -1
  26. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +15 -0
  27. package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +43 -0
  28. package/payload/platform/scripts/__tests__/mailbox-inject-registered.test.sh +5 -5
  29. package/payload/platform/scripts/__tests__/preference-hooks-registered.test.sh +3 -1
  30. package/payload/platform/scripts/__tests__/public-surface-registered.test.sh +5 -5
  31. package/payload/platform/scripts/__tests__/quote-ownership-contract.test.sh +86 -0
  32. package/payload/platform/scripts/lib/__tests__/account-settings-reconcile.test.sh +73 -0
  33. package/payload/platform/scripts/lib/account-settings-reconcile.sh +88 -0
  34. package/payload/platform/scripts/lib/provision-account-dir.sh +11 -146
  35. package/payload/platform/scripts/setup-account.sh +13 -0
  36. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.d.ts +39 -0
  37. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.d.ts.map +1 -0
  38. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.js +223 -0
  39. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.js.map +1 -0
  40. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts +5 -0
  41. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
  42. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +5 -5
  43. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
  44. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +11 -1
  45. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  46. package/payload/platform/services/claude-session-manager/dist/http-server.js +58 -12
  47. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  48. package/payload/platform/services/claude-session-manager/dist/index.js +112 -13
  49. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  50. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +6 -1
  51. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -1
  52. package/payload/platform/services/claude-session-manager/dist/pty-census.js +6 -3
  53. package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -1
  54. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +21 -8
  55. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  56. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +38 -15
  57. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  58. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts +42 -0
  59. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts.map +1 -0
  60. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js +215 -0
  61. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js.map +1 -0
  62. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +2 -0
  63. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  64. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +4 -1
  65. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  66. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts +3 -0
  67. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -1
  68. package/payload/platform/services/claude-session-manager/dist/reaper.js +2 -1
  69. package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -1
  70. package/payload/platform/services/claude-session-manager/dist/session-cap-audit.d.ts +2 -0
  71. package/payload/platform/services/claude-session-manager/dist/session-cap-audit.d.ts.map +1 -1
  72. package/payload/platform/services/claude-session-manager/dist/session-cap-audit.js +5 -2
  73. package/payload/platform/services/claude-session-manager/dist/session-cap-audit.js.map +1 -1
  74. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts +2 -0
  75. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.d.ts.map +1 -1
  76. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js +5 -3
  77. package/payload/platform/services/claude-session-manager/dist/slice-memory-policy.js.map +1 -1
  78. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.d.ts +108 -0
  79. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.d.ts.map +1 -0
  80. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.js +299 -0
  81. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.js.map +1 -0
  82. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts +26 -16
  83. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts.map +1 -1
  84. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js +84 -31
  85. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js.map +1 -1
  86. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +7 -0
  87. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -1
  88. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +6 -0
  89. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
  90. package/payload/platform/services/telegram-channel/dist/notification.d.ts +10 -2
  91. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  92. package/payload/platform/services/telegram-channel/dist/notification.js +15 -3
  93. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  94. package/payload/platform/services/telegram-channel/dist/server.d.ts.map +1 -1
  95. package/payload/platform/services/telegram-channel/dist/server.js +35 -3
  96. package/payload/platform/services/telegram-channel/dist/server.js.map +1 -1
  97. package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts +10 -0
  98. package/payload/platform/services/telegram-channel/dist/turn-follow.d.ts.map +1 -1
  99. package/payload/platform/services/telegram-channel/dist/turn-follow.js +38 -1
  100. package/payload/platform/services/telegram-channel/dist/turn-follow.js.map +1 -1
  101. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
  102. package/payload/platform/services/webchat-channel/dist/server.js +31 -2
  103. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
  104. package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts +10 -0
  105. package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts.map +1 -1
  106. package/payload/platform/services/webchat-channel/dist/turn-follow.js +38 -1
  107. package/payload/platform/services/webchat-channel/dist/turn-follow.js.map +1 -1
  108. package/payload/platform/services/whatsapp-channel/dist/instructions.d.ts +9 -0
  109. package/payload/platform/services/whatsapp-channel/dist/instructions.d.ts.map +1 -0
  110. package/payload/platform/services/whatsapp-channel/dist/instructions.js +22 -0
  111. package/payload/platform/services/whatsapp-channel/dist/instructions.js.map +1 -0
  112. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +3 -1
  113. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  114. package/payload/platform/services/whatsapp-channel/dist/notification.js +10 -2
  115. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  116. package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
  117. package/payload/platform/services/whatsapp-channel/dist/server.js +26 -2
  118. package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
  119. package/payload/platform/templates/account-settings.json +153 -0
  120. package/payload/server/server.js +254 -96
@@ -1,8 +1,17 @@
1
1
  export interface RosterCensusInput {
2
2
  /** `<accountDir>/agents/admin/AGENTS.md` — the admin's routing prose. */
3
3
  agentsMdPath: string;
4
- /** `<accountDir>/specialists/agents` — the directory spawn-context reads. */
4
+ /** `<accountDir>/specialists/agents` — the source directory spawn-context
5
+ * reads for the `<specialist-domains>` prompt block, and the directory the
6
+ * registry mirrors. Not what dispatch resolves against; see `registryDir`.
7
+ * Drives `undurable` and `bundleOrphans` only. */
5
8
  specialistsAgentsDir: string;
9
+ /** Task 2460 — `<accountDir>/.claude/agents`, the one directory the CLI
10
+ * resolves a subagent name from once the brand-wide root is retired.
11
+ * `syncAccountAgentRegistry` writes it at every spawn. Required, not
12
+ * optional: a caller that omitted it would report every declared specialist
13
+ * as orphaned. */
14
+ registryDir: string;
6
15
  /** Directories whose own `*.md` files are durable copies. Today just
7
16
  * `$PLATFORM_ROOT/templates/specialists/agents`. Required, not optional:
8
17
  * a caller that omitted them would report every live specialist as
@@ -1 +1 @@
1
- {"version":3,"file":"roster-census.d.ts","sourceRoot":"","sources":["../../src/lib/roster-census.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;qBAGiB;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;4EAIwE;IACxE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B;;qEAEiE;IACjE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;oEAEgE;IAChE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;sEAIkE;IAClE,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAyCD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAgC5E"}
1
+ {"version":3,"file":"roster-census.d.ts","sourceRoot":"","sources":["../../src/lib/roster-census.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB;;;uDAGmD;IACnD,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;uBAImB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB;;;qBAGiB;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;4EAIwE;IACxE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B;;qEAEiE;IACjE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;oEAEgE;IAChE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;sEAIkE;IAClE,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAoFD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,kBAAkB,CAsC5E"}
@@ -10,6 +10,49 @@ function markdownIn(dir) {
10
10
  return [];
11
11
  return readdirSync(dir).filter((entry) => entry.endsWith(".md"));
12
12
  }
13
+ /** The `name:` value from a card's frontmatter, or null. CRLF-tolerant and
14
+ * quote-stripping, the same idiom `specialist-roster.ts` and `spawn-context.ts`
15
+ * use, so all three agree on what a card is called. A card that cannot be read
16
+ * — a dangling registry symlink, EACCES, a directory at the path — yields
17
+ * null, which is the honest answer to "does this resolve?". */
18
+ function frontmatterName(file) {
19
+ let raw;
20
+ try {
21
+ raw = readFileSync(file, "utf8");
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
27
+ if (!fm)
28
+ return null;
29
+ const m = fm[1].match(/^name:\s*(.*?)\r?$/m);
30
+ if (!m)
31
+ return null;
32
+ let value = m[1].trim();
33
+ if ((value.startsWith('"') && value.endsWith('"')) ||
34
+ (value.startsWith("'") && value.endsWith("'"))) {
35
+ value = value.slice(1, -1);
36
+ }
37
+ return value || null;
38
+ }
39
+ /** Every subagent name the CLI can resolve from `registryDir`.
40
+ *
41
+ * Task 2469 — keyed on the frontmatter `name`, not the filename. Those differ
42
+ * by construction for a bundle-scoped card: `glsmith--order-clerk.md`
43
+ * registers `order-clerk`, and `order-clerk` is also what AGENTS.md declares,
44
+ * so asking for `<rosterName>.md` missed all four of GLS's clerks while every
45
+ * one of them dispatched. For a bare card the filename stem and the name are
46
+ * equal, so nothing about that class changes. */
47
+ function resolvableNames(registryDir) {
48
+ const names = new Set();
49
+ for (const filename of markdownIn(registryDir)) {
50
+ const name = frontmatterName(join(registryDir, filename));
51
+ if (name !== null)
52
+ names.add(name);
53
+ }
54
+ return names;
55
+ }
13
56
  function subdirs(dir) {
14
57
  if (!existsSync(dir))
15
58
  return [];
@@ -43,7 +86,15 @@ export function runRosterCensus(input) {
43
86
  for (const match of body.matchAll(/^- \*\*specialists:([^*]+)\*\*:/gm)) {
44
87
  declared.push(match[1]);
45
88
  }
46
- const orphaned = declared.filter((name) => !existsSync(join(input.specialistsAgentsDir, `${name}.md`)));
89
+ // Task 2460 measured against the registry, not the source directory. Those
90
+ // two disagreed on the account that filed that task: 13 authored, 12
91
+ // registered, and this line reported zero orphans three times.
92
+ //
93
+ // Task 2469 — and measured by the name the registry actually resolves rather
94
+ // than by filename. A dangling link still reads as absent, because reading it
95
+ // throws and yields no name.
96
+ const resolvable = resolvableNames(input.registryDir);
97
+ const orphaned = declared.filter((name) => !resolvable.has(name));
47
98
  const durable = new Set();
48
99
  for (const dir of input.durableDirs) {
49
100
  for (const filename of markdownIn(dir))
@@ -1 +1 @@
1
- {"version":3,"file":"roster-census.js","sourceRoot":"","sources":["../../src/lib/roster-census.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"roster-census.js","sourceRoot":"","sources":["../../src/lib/roster-census.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAkFjC;;;;uDAIuD;AACvD,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;gEAIgE;AAChE,SAAS,eAAe,CAAC,IAAY;IACnC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACpD,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACxB,IACE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC9C,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAC9C,CAAC;QACD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,IAAI,IAAI,CAAC;AACvB,CAAC;AAED;;;;;;;kDAOkD;AAClD,SAAS,eAAe,CAAC,WAAmB;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC1D,IAAI,IAAI,KAAK,IAAI;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC7C,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;SACtC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,iBAAiB,CACxB,oBAA4B,EAC5B,iBAA0B;IAE1B,IAAI,CAAC,iBAAiB;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC3C,4EAA4E;IAC5E,0EAA0E;IAC1E,yEAAyE;IACzE,sEAAsE;IACtE,wEAAwE;IACxE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,0EAA0E;IAC1E,6EAA6E;IAC7E,cAAc;IACd,OAAO,UAAU,CAAC,oBAAoB,CAAC;SACpC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;SACrC,MAAM,CACL,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CACvF,CAAC;AACN,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC;QACzC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC;QAC1C,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,mCAAmC,CAAC,EAAE,CAAC;QACvE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,6EAA6E;IAC7E,qEAAqE;IACrE,+DAA+D;IAC/D,EAAE;IACF,6EAA6E;IAC7E,8EAA8E;IAC9E,6BAA6B;IAC7B,MAAM,UAAU,GAAG,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACpC,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChE,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;QAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAC7D,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CACrC,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,MAAM;QACzB,YAAY,EAAE,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;QAC/C,QAAQ;QACR,SAAS;QACT,aAAa,EAAE,iBAAiB,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,iBAAiB,CAAC;KACtF,CAAC;AACJ,CAAC"}
@@ -11,7 +11,16 @@ export interface CapabilitiesHereInput {
11
11
  brandConfigPath: string;
12
12
  platformRoot: string;
13
13
  premiumPluginsRoot: string;
14
+ /** Still needed: `listConnectorsRaw` runs `claude mcp list` under it. No
15
+ * longer the source of `registeredAgentTypes`; see `agentRegistryDir`. */
14
16
  claudeConfigDir: string;
17
+ /** Task 2460 — `<accountDir>/.claude/agents`, the account's agent registry.
18
+ * `registeredAgentTypes` used to enumerate `$CLAUDE_CONFIG_DIR/agents`, the
19
+ * brand-wide root the installer wrote; that root is retired and cleared on
20
+ * upgrade, so reading it would report an empty registry on every install.
21
+ * This tool's contract is that a caller may rely on it before claiming what
22
+ * is dispatchable, so it must name the directory dispatch resolves against. */
23
+ agentRegistryDir: string;
15
24
  /** Task 1160 — returns the raw combined output of `claude mcp list` run under
16
25
  * the brand config dir. Injected by the adapter (index.ts) so this function
17
26
  * stays a pure resolver and so the subprocess never runs in unit tests. When
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities-here.d.ts","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC;qFACiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,sBAAsB,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;yCAKqC;IACrC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B,EAAE,MAAM,EAAE,CAAC;IACvC,2BAA2B,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;KAC/B,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAwBlF;AAuCD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,qBAAqB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,sBAAsB,CAAC,CAmDjC"}
1
+ {"version":3,"file":"capabilities-here.d.ts","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC;qFACiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,sBAAsB,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B;+EAC2E;IAC3E,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;oFAKgF;IAChF,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;yCAKqC;IACrC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B,EAAE,MAAM,EAAE,CAAC;IACvC,2BAA2B,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;KAC/B,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAwBlF;AAuCD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,qBAAqB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,sBAAsB,CAAC,CAiDjC"}
@@ -101,7 +101,7 @@ export async function resolveCapabilitiesHere(input, nowIso) {
101
101
  for (const name of names)
102
102
  installedPremiumSpecialists.push({ bundle, name });
103
103
  }
104
- const registeredAgentTypes = listAgentRegistry(resolve(input.claudeConfigDir, "agents"));
104
+ const registeredAgentTypes = listAgentRegistry(input.agentRegistryDir);
105
105
  const claudeAiConnectors = await resolveClaudeAiConnectors(input.listConnectorsRaw);
106
106
  return {
107
107
  accountId: input.accountId,
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities-here.js","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capabilities-here.js","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"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"}
@@ -22,7 +22,7 @@ Call `mcp__plugin_admin_admin__capabilities-here` with no arguments. The tool re
22
22
  - `brand.json` for `productName` and `shipsPremiumBundles`.
23
23
  - `platform/templates/specialists/agents/` for `installedPlatformSpecialists`.
24
24
  - Each enabled premium bundle's `agents/` for `installedPremiumSpecialists`.
25
- - `$CLAUDE_CONFIG_DIR/agents/` for `registeredAgentTypes` (the same registry the Agent tool resolves against).
25
+ - `<accountDir>/.claude/agents/` for `registeredAgentTypes` (this account's agent registry, the same one the Agent tool resolves against). It is mirrored from `<accountDir>/specialists/agents/` before every spawn. The brand-wide `$CLAUDE_CONFIG_DIR/agents/` is not a registration surface and registers nothing.
26
26
 
27
27
  Returns one JSON object with those fields plus `accountId`, `capturedAt`, and the `brand` block. No LLM in the resolution path; pure disk + JSON reads.
28
28
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:a5382f5dffc8946000b831c6433f7312cae263450bd9e97bfacb58017ae7b783
4
+ content-hash: sha256:021d3690d7d8100b010cc7d9669e51707f501b5be58dac2399a2d751ca9844e1
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -1820,6 +1820,49 @@ grep -E 'op=(turn-drop|census)' ~/.<brand>/logs/mcp-telegram-channel-*.log | tai
1820
1820
  grep -E 'op=(turn-end|turn-answer-absent)' ~/.<brand>/logs/server.log | grep <sessionId>
1821
1821
  ```
1822
1822
 
1823
+ **A seventh discard site, and the one nothing was reading.** An answer that
1824
+ survived every guard above could still be produced and thrown away at the last
1825
+ step, because the gateway resolved its destination from admin identity rather
1826
+ than from the channel it came in on. A public visitor has no admin identity, so
1827
+ the resolver returned no target: nothing was attempted, no transport failed, and
1828
+ the line read `reached=none notReached=none`.
1829
+
1830
+ The turn-end body now carries the channel server's own spawn `role`, and that is
1831
+ the only thing that decides the destination:
1832
+
1833
+ | `role=` | Where the answer goes | `op=fan-out` |
1834
+ |---|---|---|
1835
+ | `public` | every segment through the posting key's own transport; no identity resolver, no registry read | never emitted |
1836
+ | `admin` | every live door the person is reachable on, via `fanTargetsFor` | emitted |
1837
+ | absent or unrecognised | nowhere. 400, plus one `op=turn-role-absent … evicted=<yes\|no>` | never emitted |
1838
+
1839
+ `op=turn-end` and `op=turn-strand-anomaly` both name the role, so no outcome is
1840
+ unattributable.
1841
+
1842
+ A roleless POST has one cause: a channel server from a build predating the field,
1843
+ still attached to a session that outlived the platform restart. It reconnects its
1844
+ stream, so nothing respawns it, and left alone it would post roleless turn-ends for
1845
+ the life of that session. `evicted=yes` says the gateway dropped its subscriber, so
1846
+ the next inbound spawns a server on the current build: one turn is lost per session
1847
+ rather than all of them. That turn's answer is deliberately not delivered to the
1848
+ posting key, because doing so would restore the very fallback whose reachability hid
1849
+ the original defect. The standing check is one line per door per minute, over a
1850
+ rolling hour:
1851
+
1852
+ ```bash
1853
+ # the standing read; any undeliveredPublic>0 is a failure
1854
+ grep -E 'op=census' ~/.<brand>/logs/server.log | grep delivery-census | tail -5
1855
+ # a visitor's answer that reached nobody, or a turn-end that named no role
1856
+ grep -E 'op=(turn-role-absent|turn-strand-anomaly)' ~/.<brand>/logs/server.log | tail -20
1857
+ ```
1858
+
1859
+ `[<door>-delivery-census] op=census windowMin=60 turnEnds=… record=… none=…
1860
+ undelivered=… undeliveredPublic=… undeliveredAdmin=… roleAbsent=…`. Healthy is
1861
+ `undeliveredPublic=0 roleAbsent=0` with `record` tracking `turnEnds` minus
1862
+ `none`. A door with no turn-end in the hour emits nothing; the
1863
+ `op=arm name=channel-delivery-census` line at boot is what separates that from a
1864
+ census that is not running.
1865
+
1823
1866
  ---
1824
1867
  # Settings
1825
1868
  Source: https://docs.getmaxy.com/settings.md
@@ -9,6 +9,21 @@ Invoked by the admin agent directly.
9
9
 
10
10
  This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
11
11
 
12
+ ## 2026-08-06 (0.1.569)
13
+
14
+ - Every account's safeguards are now brought up to date on each install. They used to be written once when the account was created and never revisited, so an account could be missing a protection that every other account had, with nothing reporting the gap.
15
+ - A customer quote can now only be produced by the specialist that owns it. Other assistants were writing quote documents by hand, bypassing the template and the renderer entirely; writes to a quote from anything else are now refused, including producing the PDF through the shell.
16
+ - A specialist you wrote for your own account is dispatchable again. The roster was matching on filenames rather than the name declared inside the file, so cards that looked registered could not actually be reached and the work fell to a general-purpose assistant instead.
17
+ - Two new standing checks: one counts work written into an owned area by the wrong specialist, the other reconciles quotes that were sent against the records of what was actually rendered.
18
+ - A quote's running header no longer depends on where the author happened to put page breaks, so it appears on every page rather than the ones that were hand-marked.
19
+
20
+ ## 2026-08-06 (0.1.568)
21
+
22
+ - Answers reach the conversation they came from again. An answer was being routed by who the account's admin is rather than by the conversation it was sent to, so a public agent's reply could go nowhere and an admin answer could strand with nothing said about it. Delivery now returns to the door the message arrived on, and every failure to find one is named rather than passing silently. If you rolled an install back because of this, you can move forward again.
23
+ - Starting one product no longer kills conversations belonging to another on the same machine. A product starting up was clearing away stale conversations by a pattern that matched every other co-resident product's live ones too.
24
+ - A specialist you wrote is now actually dispatchable. It was being listed to the assistant while never being registered where dispatch looks, so asking for it did nothing.
25
+ - Telegram and webchat no longer spend one of your inbound allowances on a turn that answered nothing.
26
+
12
27
  ## 2026-08-05 (0.1.567)
13
28
 
14
29
  - An answer you can see in the reader is now delivered to the channel it belongs to. A turn that ended on a thinking block was closing before its answer row arrived, and that answer was dropped. Every channel now holds a close that carries no message, merges a split answer back into one message, and records a line at each of the six points where a turn used to be discarded silently.
@@ -133,3 +133,46 @@ grep -E 'op=(turn-drop|census)' ~/.<brand>/logs/mcp-telegram-channel-*.log | tai
133
133
  # the gateway's view of the same turn
134
134
  grep -E 'op=(turn-end|turn-answer-absent)' ~/.<brand>/logs/server.log | grep <sessionId>
135
135
  ```
136
+
137
+ **A seventh discard site, and the one nothing was reading.** An answer that
138
+ survived every guard above could still be produced and thrown away at the last
139
+ step, because the gateway resolved its destination from admin identity rather
140
+ than from the channel it came in on. A public visitor has no admin identity, so
141
+ the resolver returned no target: nothing was attempted, no transport failed, and
142
+ the line read `reached=none notReached=none`.
143
+
144
+ The turn-end body now carries the channel server's own spawn `role`, and that is
145
+ the only thing that decides the destination:
146
+
147
+ | `role=` | Where the answer goes | `op=fan-out` |
148
+ |---|---|---|
149
+ | `public` | every segment through the posting key's own transport; no identity resolver, no registry read | never emitted |
150
+ | `admin` | every live door the person is reachable on, via `fanTargetsFor` | emitted |
151
+ | absent or unrecognised | nowhere. 400, plus one `op=turn-role-absent … evicted=<yes\|no>` | never emitted |
152
+
153
+ `op=turn-end` and `op=turn-strand-anomaly` both name the role, so no outcome is
154
+ unattributable.
155
+
156
+ A roleless POST has one cause: a channel server from a build predating the field,
157
+ still attached to a session that outlived the platform restart. It reconnects its
158
+ stream, so nothing respawns it, and left alone it would post roleless turn-ends for
159
+ the life of that session. `evicted=yes` says the gateway dropped its subscriber, so
160
+ the next inbound spawns a server on the current build: one turn is lost per session
161
+ rather than all of them. That turn's answer is deliberately not delivered to the
162
+ posting key, because doing so would restore the very fallback whose reachability hid
163
+ the original defect. The standing check is one line per door per minute, over a
164
+ rolling hour:
165
+
166
+ ```bash
167
+ # the standing read; any undeliveredPublic>0 is a failure
168
+ grep -E 'op=census' ~/.<brand>/logs/server.log | grep delivery-census | tail -5
169
+ # a visitor's answer that reached nobody, or a turn-end that named no role
170
+ grep -E 'op=(turn-role-absent|turn-strand-anomaly)' ~/.<brand>/logs/server.log | tail -20
171
+ ```
172
+
173
+ `[<door>-delivery-census] op=census windowMin=60 turnEnds=… record=… none=…
174
+ undelivered=… undeliveredPublic=… undeliveredAdmin=… roleAbsent=…`. Healthy is
175
+ `undeliveredPublic=0 roleAbsent=0` with `record` tracking `turnEnds` minus
176
+ `none`. A door with no turn-end in the hour emits nothing; the
177
+ `op=arm name=channel-delivery-census` line at boot is what separates that from a
178
+ census that is not running.
@@ -11,7 +11,7 @@
11
11
  # a comment and proves nothing about what the lib would write.
12
12
  set -uo pipefail
13
13
  DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
- PROV="$DIR/../lib/provision-account-dir.sh"
14
+ PROV="$DIR/../../templates/account-settings.json"
15
15
  BACKFILL="$DIR/../lib/account-settings-mailbox-inject.sh"
16
16
  SETUP="$DIR/../setup-account.sh"
17
17
  PASS=0; FAIL=0
@@ -22,7 +22,7 @@ bad() { echo "FAIL: $1" >&2; FAIL=$((FAIL+1)); }
22
22
  # What provision-account-dir.sh writes into the settings heredoc. HOOKS_PATH is
23
23
  # assigned there as the literal string $PLATFORM_ROOT/plugins/admin/hooks, so the
24
24
  # resolved command is the same string the backfill lib holds.
25
- PROV_LINE='{ "type": "command", "command": "bash $HOOKS_PATH/mailbox-inject.sh" }'
25
+ PROV_LINE='{ "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/mailbox-inject.sh" }'
26
26
  RESOLVED='bash $PLATFORM_ROOT/plugins/admin/hooks/mailbox-inject.sh'
27
27
 
28
28
  if /usr/bin/grep -qF "$PROV_LINE" "$PROV"; then
@@ -53,10 +53,10 @@ fi
53
53
 
54
54
  # HOOKS_PATH must still resolve to the path the backfill lib assumes; if someone
55
55
  # repoints it, the two writers silently disagree and every account gets two hooks.
56
- if /usr/bin/grep -qF 'HOOKS_PATH="\$PLATFORM_ROOT/plugins/admin/hooks"' "$PROV"; then
57
- ok "HOOKS_PATH resolves to the path the backfill lib assumes"
56
+ if ! /usr/bin/grep -q 'HOOKS_PATH' "$PROV"; then
57
+ ok "the template carries no unresolved hook-path indirection"
58
58
  else
59
- bad "HOOKS_PATH in $PROV no longer matches the backfill lib assumption"
59
+ bad "$PROV still carries a HOOKS_PATH indirection, so the two writers can drift"
60
60
  fi
61
61
 
62
62
  if /usr/bin/grep -qF 'account-settings-mailbox-inject.sh' "$SETUP"; then
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env bash
2
2
  set -uo pipefail
3
3
  DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
- LIB="$DIR/../lib/provision-account-dir.sh"
4
+ # The provision-time source of the hook set is the template provision_account_dir
5
+ # copies verbatim, not a heredoc inside the writer.
6
+ LIB="$DIR/../../templates/account-settings.json"
5
7
  PASS=0; FAIL=0; FAILED=()
6
8
  c(){ if grep -qF "$1" "$LIB"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$2"); fi; }
7
9
  c 'preference-consult-gate.sh' "gate registered"
@@ -7,7 +7,7 @@
7
7
  # append a second copy to every house account on every install.
8
8
  set -uo pipefail
9
9
  DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
- PROV="$DIR/../lib/provision-account-dir.sh"
10
+ PROV="$DIR/../../templates/account-settings.json"
11
11
  BACKFILL="$DIR/../lib/account-settings-public-surface.sh"
12
12
  SETUP="$DIR/../setup-account.sh"
13
13
  PASS=0; FAIL=0
@@ -15,7 +15,7 @@ PASS=0; FAIL=0
15
15
  ok() { echo "PASS: $1"; PASS=$((PASS+1)); }
16
16
  bad() { echo "FAIL: $1" >&2; FAIL=$((FAIL+1)); }
17
17
 
18
- PROV_LINE='{ "type": "command", "command": "bash $HOOKS_PATH/public-tool-surface.sh" }'
18
+ PROV_LINE='{ "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/public-tool-surface.sh" }'
19
19
  RESOLVED='bash $PLATFORM_ROOT/plugins/admin/hooks/public-tool-surface.sh'
20
20
 
21
21
  if [ "$(/usr/bin/grep -cF "$PROV_LINE" "$PROV")" = "3" ]; then
@@ -75,10 +75,10 @@ else
75
75
  bad "backfill _PUBSURFACE_CMD is not '$RESOLVED' in $BACKFILL"
76
76
  fi
77
77
 
78
- if /usr/bin/grep -qF 'HOOKS_PATH="\$PLATFORM_ROOT/plugins/admin/hooks"' "$PROV"; then
79
- ok "HOOKS_PATH resolves to the path the backfill lib assumes"
78
+ if ! /usr/bin/grep -q 'HOOKS_PATH' "$PROV"; then
79
+ ok "the template carries no unresolved hook-path indirection"
80
80
  else
81
- bad "HOOKS_PATH in $PROV no longer matches the backfill lib assumption"
81
+ bad "$PROV still carries a HOOKS_PATH indirection, so the two writers can drift"
82
82
  fi
83
83
 
84
84
  if /usr/bin/grep -qF 'account-settings-public-surface.sh' "$SETUP"; then
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env bash
2
+ # The client quote document has exactly one owner, and that ownership is a
3
+ # capability as well as a claim.
4
+ #
5
+ # A hand-orchestrated quote reached a customer because the quoter's own card
6
+ # disclaimed document work ("not a document edit for another agent"), so the
7
+ # admin's routing to a general content specialist was correct against it. The
8
+ # guarantee that replaced that prose is a capability: the quote tools are
9
+ # granted to the quoter's card and to no other, so no other agent can produce a
10
+ # receipt-bearing quote by any route.
11
+ #
12
+ # Covers:
13
+ # A. the quoter's body claims ownership of the document's presentation
14
+ # B. the disclaimer that sent document work elsewhere is gone
15
+ # C. the description front-matter carries the same claim (the roster text the
16
+ # admin reads at dispatch time)
17
+ # D. quote-render / quote-engine-run are granted to the quoter
18
+ # E. no other card in the tree grants either tool
19
+
20
+ set -u
21
+
22
+ ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
23
+ QUOTER="$ROOT/premium-plugins/sitedesk/agents/sitedesk--quoter.md"
24
+
25
+ PASS=0
26
+ FAIL=0
27
+ ok() { echo "PASS: $1"; PASS=$((PASS + 1)); }
28
+ bad() { echo "FAIL: $1" >&2; FAIL=$((FAIL + 1)); }
29
+
30
+ if [ ! -f "$QUOTER" ]; then
31
+ echo "FAIL: quoter card missing at $QUOTER" >&2
32
+ exit 1
33
+ fi
34
+
35
+ # Body = everything outside the frontmatter block.
36
+ BODY="$(sed -n '/^---$/,/^---$/!p' "$QUOTER")"
37
+ DESC="$(grep -m1 '^description:' "$QUOTER" || true)"
38
+
39
+ for word in layout "cover page" photograph "running header" correction; do
40
+ if printf '%s' "$BODY" | grep -qi -- "$word"; then
41
+ ok "A: body claims $word"
42
+ else
43
+ bad "A: body does not claim $word"
44
+ fi
45
+ done
46
+
47
+ if grep -q 'not a document edit for another agent' "$QUOTER"; then
48
+ bad "B: the document-edit disclaimer is still present"
49
+ else
50
+ ok "B: document-edit disclaimer absent"
51
+ fi
52
+
53
+ if printf '%s' "$DESC" | grep -qi 'owns the client quote document'; then
54
+ ok "C: description carries the ownership claim"
55
+ else
56
+ bad "C: description does not carry the ownership claim"
57
+ fi
58
+
59
+ TOOLS="$(grep -m1 '^tools:' "$QUOTER" || true)"
60
+ for t in quote-render quote-engine-run; do
61
+ if printf '%s' "$TOOLS" | grep -q -- "$t"; then
62
+ ok "D: quoter grants $t"
63
+ else
64
+ bad "D: quoter does not grant $t"
65
+ fi
66
+ done
67
+
68
+ STRAY=0
69
+ while IFS= read -r card; do
70
+ [ "$card" = "$QUOTER" ] && continue
71
+ line="$(grep -m1 '^tools:' "$card" || true)"
72
+ if printf '%s' "$line" | grep -qE 'quote-render|quote-engine-run'; then
73
+ echo " stray grant: $card" >&2
74
+ STRAY=$((STRAY + 1))
75
+ fi
76
+ done < <(find "$ROOT/premium-plugins" "$ROOT/platform/templates/specialists/agents" -name '*.md' -type f 2>/dev/null)
77
+
78
+ if [ "$STRAY" -eq 0 ]; then
79
+ ok "E: no other card grants a quote tool"
80
+ else
81
+ bad "E: $STRAY other card(s) grant a quote tool"
82
+ fi
83
+
84
+ echo "──────── quote ownership contract summary ────────"
85
+ echo "PASS=$PASS FAIL=$FAIL"
86
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ # reconcile_all_accounts_settings converges every account's hook set against the
3
+ # shipped template and states the divergence count on every run.
4
+ #
5
+ # provision_account_dir writes the account's .claude/settings.json at provision
6
+ # time only, and the upgrade path re-provisions the house account and no other.
7
+ # An account created before a hook was added therefore runs a stale hook set
8
+ # indefinitely, silently — which is how a client-quote gate came to be
9
+ # registered on one of four accounts on a live install. Five one-hook backfill
10
+ # libs were written that way, each after a different hook was found missing.
11
+ # This lib converges the whole set instead.
12
+ #
13
+ # Covers:
14
+ # A. an account missing a template hook converges → status=updated
15
+ # B. an already-matching account is left alone → status=already-set
16
+ # C. an account with no settings file is seeded → status=absent-seeded
17
+ # D. an unparseable file is reported, not rewritten → status=rewrite-failed
18
+ # E. the summary line is emitted on a re-run, stating its count
19
+ # F. the summary line counts the divergent accounts
20
+
21
+ set -u
22
+
23
+ LIB="$(cd "$(dirname "$0")/.." && pwd)/account-settings-reconcile.sh"
24
+ if [ ! -f "$LIB" ]; then
25
+ echo "FAIL: $LIB missing" >&2
26
+ exit 1
27
+ fi
28
+ # shellcheck disable=SC1090
29
+ . "$LIB"
30
+
31
+ TMP=$(mktemp -d)
32
+ trap 'rm -rf "$TMP"' EXIT
33
+
34
+ TPL="$TMP/account-settings.json"
35
+ printf '{"hooks":{"PreToolUse":[{"matcher":"Write","hooks":[{"type":"command","command":"bash a.sh"}]}]}}' > "$TPL"
36
+
37
+ ACCTS="$TMP/accounts"
38
+ mk() { mkdir -p "$ACCTS/$1/.claude"; printf '{}' > "$ACCTS/$1/account.json"; }
39
+
40
+ PASS=0
41
+ FAIL=0
42
+ ok() { echo "PASS: $1"; PASS=$((PASS + 1)); }
43
+ bad() { echo "FAIL: $1" >&2; FAIL=$((FAIL + 1)); }
44
+
45
+ mk stale; printf '{"hooks":{"PreToolUse":[]}}' > "$ACCTS/stale/.claude/settings.json"
46
+ mk current; cp "$TPL" "$ACCTS/current/.claude/settings.json"
47
+ mk fresh
48
+ mk broken; printf 'not json' > "$ACCTS/broken/.claude/settings.json"
49
+
50
+ OUT="$(MAXY_ACCOUNT_SETTINGS_TEMPLATE="$TPL" reconcile_all_accounts_settings "$ACCTS" 2>&1)"
51
+
52
+ printf '%s' "$OUT" | grep -q 'account=stale status=updated' \
53
+ && ok "A: stale account converged" || bad "A: stale account not converged"
54
+ printf '%s' "$OUT" | grep -q 'account=current status=already-set' \
55
+ && ok "B: matching account left alone" || bad "B: matching account not already-set"
56
+ printf '%s' "$OUT" | grep -q 'account=fresh status=absent-seeded' \
57
+ && ok "C: missing settings seeded" || bad "C: missing settings not seeded"
58
+ printf '%s' "$OUT" | grep -q 'account=broken status=rewrite-failed' \
59
+ && ok "D: unparseable file reported" || bad "D: unparseable file not reported"
60
+ [ "$(cat "$ACCTS/broken/.claude/settings.json")" = "not json" ] \
61
+ && ok "D: unparseable file left untouched" || bad "D: unparseable file was rewritten"
62
+ printf '%s' "$OUT" | grep -q 'accounts=4 divergent=3' \
63
+ && ok "F: summary counts the divergent accounts" || bad "F: wrong summary — $OUT"
64
+
65
+ # The converged accounts stay converged; the unparseable one never does, which
66
+ # is the standing signal.
67
+ OUT2="$(MAXY_ACCOUNT_SETTINGS_TEMPLATE="$TPL" reconcile_all_accounts_settings "$ACCTS" 2>&1)"
68
+ printf '%s' "$OUT2" | grep -q 'accounts=4 divergent=1' \
69
+ && ok "E: re-run states its count" || bad "E: wrong re-run summary — $OUT2"
70
+
71
+ echo "──────── account-settings-reconcile summary ────────"
72
+ echo "PASS=$PASS FAIL=$FAIL"
73
+ [ "$FAIL" -eq 0 ]