@rubytech/create-maxy-code 0.1.246 → 0.1.248

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 (168) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/config/brand.json +3 -3
  3. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  4. package/payload/platform/plugins/admin/PLUGIN.md +4 -1
  5. package/payload/platform/plugins/admin/hooks/__tests__/pin-identity-gate.test.sh +96 -0
  6. package/payload/platform/plugins/admin/hooks/pin-identity-gate.sh +136 -0
  7. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts +2 -0
  8. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts.map +1 -0
  9. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js +34 -0
  10. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js.map +1 -0
  11. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts +2 -0
  12. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts.map +1 -0
  13. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js +50 -0
  14. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js.map +1 -0
  15. package/payload/platform/plugins/admin/mcp/dist/index.js +8 -0
  16. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  17. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts +6 -0
  18. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts.map +1 -0
  19. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js +32 -0
  20. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js.map +1 -0
  21. package/payload/platform/plugins/admin/skills/investigate/SKILL.md +34 -17
  22. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +15 -8
  23. package/payload/platform/plugins/admin/skills/publish-site/SKILL.md +5 -0
  24. package/payload/platform/plugins/admin/skills/unzip-attachment/SKILL.md +5 -0
  25. package/payload/platform/plugins/admin/skills/update-knowledge/SKILL.md +5 -0
  26. package/payload/platform/plugins/docs/references/admin-identity-gate.md +81 -0
  27. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +1 -0
  28. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +5 -0
  29. package/payload/platform/plugins/workflows/skills/workflow-manager/SKILL.md +5 -0
  30. package/payload/platform/scripts/check-skill-frontmatter.mjs +139 -0
  31. package/payload/platform/scripts/setup-account.sh +5 -16
  32. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts +39 -0
  33. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts.map +1 -0
  34. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js +133 -0
  35. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js.map +1 -0
  36. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  37. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  38. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  39. package/payload/platform/services/claude-session-manager/dist/index.js +29 -0
  40. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  41. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +28 -0
  42. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -0
  43. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +99 -0
  44. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -0
  45. package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
  46. package/payload/server/{chunk-JMEX5NRX.js → chunk-UEIA5YUG.js} +30 -18
  47. package/payload/server/maxy-edge.js +7 -5
  48. package/payload/server/public/assets/{AdminShell-D_eg2QKE.js → AdminShell-892Jy_rs.js} +1 -1
  49. package/payload/server/public/assets/AdminShell-qc_xy7Az.css +1 -0
  50. package/payload/server/public/assets/{Checkbox-CfE7p1Tv.js → Checkbox-Bc2QzX9b.js} +1 -1
  51. package/payload/server/public/assets/{admin-DfeXRW1m.js → admin-D3K13ndi.js} +1 -1
  52. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DvDVmNbJ.js → architectureDiagram-Q4EWVU46-c09loTER.js} +1 -1
  53. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CVCQHVcw.js → blockDiagram-DXYQGD6D-Cjdeyoq1.js} +1 -1
  54. package/payload/server/public/assets/brand-D0gNihp7.css +1 -0
  55. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DancbaY-.js → c4Diagram-AHTNJAMY-NY6Wlzo2.js} +1 -1
  56. package/payload/server/public/assets/channel-B1IT7to2.js +1 -0
  57. package/payload/server/public/assets/chunk-336JU56O-CdKRCIeE.js +2 -0
  58. package/payload/server/public/assets/{chunk-426QAEUC-Dqt07sZz.js → chunk-426QAEUC-BybuQ3Ve.js} +1 -1
  59. package/payload/server/public/assets/{chunk-4TB4RGXK-Bdm77ygl.js → chunk-4TB4RGXK-BXpto3yW.js} +1 -1
  60. package/payload/server/public/assets/{chunk-5FUZZQ4R-nDbgOH1b.js → chunk-5FUZZQ4R-C403gCUk.js} +1 -1
  61. package/payload/server/public/assets/{chunk-5PVQY5BW-mYip6Ias.js → chunk-5PVQY5BW-CjVzXQEp.js} +1 -1
  62. package/payload/server/public/assets/{chunk-EDXVE4YY-DubyAY7F.js → chunk-EDXVE4YY-DJcJAsAg.js} +1 -1
  63. package/payload/server/public/assets/{chunk-ENJZ2VHE-DIa8CJbF.js → chunk-ENJZ2VHE-CFDNvYu1.js} +1 -1
  64. package/payload/server/public/assets/{chunk-ICPOFSXX-bKmK-tZo.js → chunk-ICPOFSXX-ecLOxGhL.js} +1 -1
  65. package/payload/server/public/assets/{chunk-OYMX7WX6-KcUQTwd8.js → chunk-OYMX7WX6-B7MW66KB.js} +1 -1
  66. package/payload/server/public/assets/{chunk-U2HBQHQK-3p-zDDFG.js → chunk-U2HBQHQK-BMawmsyk.js} +1 -1
  67. package/payload/server/public/assets/{chunk-X2U36JSP-C5F60GoO.js → chunk-X2U36JSP-CT6g7pno.js} +1 -1
  68. package/payload/server/public/assets/{chunk-YZCP3GAM-CEhP6XMC.js → chunk-YZCP3GAM-xeAluiAH.js} +1 -1
  69. package/payload/server/public/assets/{chunk-ZZ45TVLE-Bac24FOS.js → chunk-ZZ45TVLE-BRN9qUC5.js} +1 -1
  70. package/payload/server/public/assets/classDiagram-6PBFFD2Q-rjCize6i.js +1 -0
  71. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BORWOUt0.js +1 -0
  72. package/payload/server/public/assets/clone-Csqv5U6T.js +1 -0
  73. package/payload/server/public/assets/{dagre-xntZVDsO.js → dagre-DTjePoco.js} +1 -1
  74. package/payload/server/public/assets/{dagre-KV5264BT-DqGsPaYJ.js → dagre-KV5264BT-DHBkRke4.js} +1 -1
  75. package/payload/server/public/assets/{data-JoiWCmz6.js → data-Br-pdljK.js} +1 -1
  76. package/payload/server/public/assets/{diagram-5BDNPKRD-Co8NC28s.js → diagram-5BDNPKRD-BIq1-idL.js} +1 -1
  77. package/payload/server/public/assets/{diagram-G4DWMVQ6-HewQArEf.js → diagram-G4DWMVQ6-BsIUDzV6.js} +1 -1
  78. package/payload/server/public/assets/{diagram-MMDJMWI5-s6NqURmM.js → diagram-MMDJMWI5-CgHSri2i.js} +1 -1
  79. package/payload/server/public/assets/{diagram-TYMM5635-CAof9UmL.js → diagram-TYMM5635-Ce2Wh9ZX.js} +1 -1
  80. package/payload/server/public/assets/{erDiagram-SMLLAGMA-CUqIICFD.js → erDiagram-SMLLAGMA-BU0Kh6OQ.js} +1 -1
  81. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DN1n7xgU.js → flowDiagram-DWJPFMVM-B0N06MF7.js} +1 -1
  82. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-sGoWsEWZ.js → ganttDiagram-T4ZO3ILL-BVbx4ARZ.js} +1 -1
  83. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-Dz_cZL1Q.js → gitGraphDiagram-UUTBAWPF-C-xRJ94t.js} +1 -1
  84. package/payload/server/public/assets/{graph-DmOvqjTa.js → graph-g48ZcA5M.js} +1 -1
  85. package/payload/server/public/assets/{graph-labels-iPC15OmD.js → graph-labels-BYH-IPCb.js} +1 -1
  86. package/payload/server/public/assets/{graphlib-eZzlPtt9.js → graphlib-YmNcoMjY.js} +1 -1
  87. package/payload/server/public/assets/{infoDiagram-42DDH7IO-DFMOgYMn.js → infoDiagram-42DDH7IO-Di6oPQ_-.js} +1 -1
  88. package/payload/server/public/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  89. package/payload/server/public/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  90. package/payload/server/public/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  91. package/payload/server/public/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  92. package/payload/server/public/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  93. package/payload/server/public/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  94. package/payload/server/public/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  95. package/payload/server/public/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  96. package/payload/server/public/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  97. package/payload/server/public/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  98. package/payload/server/public/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  99. package/payload/server/public/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  100. package/payload/server/public/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  101. package/payload/server/public/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  102. package/payload/server/public/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  103. package/payload/server/public/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  104. package/payload/server/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  105. package/payload/server/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  106. package/payload/server/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  107. package/payload/server/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  108. package/payload/server/public/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  109. package/payload/server/public/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  110. package/payload/server/public/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  111. package/payload/server/public/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  112. package/payload/server/public/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  113. package/payload/server/public/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  114. package/payload/server/public/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  115. package/payload/server/public/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  116. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-C9AGnqZn.js → ishikawaDiagram-UXIWVN3A-DTrq54yC.js} +1 -1
  117. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-C4-y1Faf.js → journeyDiagram-VCZTEJTY-OZZZMrFX.js} +1 -1
  118. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DIynz-Si.js → kanban-definition-6JOO6SKY--w-IP9pN.js} +1 -1
  119. package/payload/server/public/assets/{line-CzaIC22F.js → line-Ckeulv5T.js} +1 -1
  120. package/payload/server/public/assets/{mermaid-parser.core-Dcdye_D2.js → mermaid-parser.core-CVRAxYRD.js} +1 -1
  121. package/payload/server/public/assets/{mermaid.core-HWxg8X0R.js → mermaid.core-B-mE18I1.js} +3 -3
  122. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-ve0J3SsF.js → mindmap-definition-QFDTVHPH-Bm8mDicL.js} +1 -1
  123. package/payload/server/public/assets/newsreader-latin-300-normal-AOSWdb_s.woff +0 -0
  124. package/payload/server/public/assets/newsreader-latin-300-normal-FGBQ0wlI.woff2 +0 -0
  125. package/payload/server/public/assets/newsreader-latin-400-normal-BFBkh4jY.woff2 +0 -0
  126. package/payload/server/public/assets/newsreader-latin-400-normal-gRTjlS2D.woff +0 -0
  127. package/payload/server/public/assets/newsreader-latin-500-normal-B66TYsaK.woff2 +0 -0
  128. package/payload/server/public/assets/newsreader-latin-500-normal-DFwuUcdu.woff +0 -0
  129. package/payload/server/public/assets/newsreader-latin-ext-300-normal-CFtw49Zd.woff +0 -0
  130. package/payload/server/public/assets/newsreader-latin-ext-300-normal-DRMzurxT.woff2 +0 -0
  131. package/payload/server/public/assets/newsreader-latin-ext-400-normal-DYA1XoQK.woff +0 -0
  132. package/payload/server/public/assets/newsreader-latin-ext-400-normal-svq1FPys.woff2 +0 -0
  133. package/payload/server/public/assets/newsreader-latin-ext-500-normal-BNHmvKvI.woff2 +0 -0
  134. package/payload/server/public/assets/newsreader-latin-ext-500-normal-CZruMFou.woff +0 -0
  135. package/payload/server/public/assets/newsreader-vietnamese-300-normal-CsrIkm-V.woff +0 -0
  136. package/payload/server/public/assets/newsreader-vietnamese-300-normal-D3VHEe81.woff2 +0 -0
  137. package/payload/server/public/assets/newsreader-vietnamese-400-normal-BekUZro8.woff +0 -0
  138. package/payload/server/public/assets/newsreader-vietnamese-400-normal-DdKr49mV.woff2 +0 -0
  139. package/payload/server/public/assets/newsreader-vietnamese-500-normal-BEAbKU8A.woff +0 -0
  140. package/payload/server/public/assets/newsreader-vietnamese-500-normal-CL6a8tp2.woff2 +0 -0
  141. package/payload/server/public/assets/{pieDiagram-DEJITSTG-DdiZi8Iv.js → pieDiagram-DEJITSTG-BCmRLgGO.js} +1 -1
  142. package/payload/server/public/assets/{public-DbW8Up_b.js → public-DknO-g9S.js} +5 -5
  143. package/payload/server/public/assets/public-vnj7OhQj.css +1 -0
  144. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CvNd8CMM.js → quadrantDiagram-34T5L4WZ-CniTIUTm.js} +1 -1
  145. package/payload/server/public/assets/{requirementDiagram-MS252O5E-8LsItfG7.js → requirementDiagram-MS252O5E-CoxBSj9M.js} +1 -1
  146. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-CoXsggQF.js → sankeyDiagram-XADWPNL6-BjS-4jzq.js} +1 -1
  147. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CxtIGmey.js → sequenceDiagram-FGHM5R23-B9jVOnPR.js} +1 -1
  148. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-C2zgoy3P.js → stateDiagram-FHFEXIEX-BvOQPzP8.js} +1 -1
  149. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-v4ND10uR.js +1 -0
  150. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DQ_J-0lx.js → timeline-definition-GMOUNBTQ-CdfgWLo1.js} +1 -1
  151. package/payload/server/public/assets/{useSelectionMode-BbLqtKTJ.js → useSelectionMode-DwsyptOw.js} +1 -1
  152. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-B7Y7Cw54.js → vennDiagram-DHZGUBPP-JCgpIbj-.js} +1 -1
  153. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-1XkR1IH-.js → wardleyDiagram-NUSXRM2D-Dei3VqHo.js} +1 -1
  154. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CcatDElf.js → xychartDiagram-5P7HB3ND-DUtIyoIb.js} +1 -1
  155. package/payload/server/public/brand-defaults.css +3 -3
  156. package/payload/server/public/data.html +6 -5
  157. package/payload/server/public/graph.html +7 -6
  158. package/payload/server/public/index.html +7 -6
  159. package/payload/server/public/public.html +7 -6
  160. package/payload/server/server.js +290 -157
  161. package/payload/server/public/assets/brand-hVIfBy3s.css +0 -1
  162. package/payload/server/public/assets/channel-t5srld-W.js +0 -1
  163. package/payload/server/public/assets/chunk-336JU56O-DL5O4-qf.js +0 -2
  164. package/payload/server/public/assets/classDiagram-6PBFFD2Q-197c9FtA.js +0 -1
  165. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C5RIsovf.js +0 -1
  166. package/payload/server/public/assets/clone-BJPTkE0R.js +0 -1
  167. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C3CpI3Q7.js +0 -1
  168. /package/payload/server/public/assets/{brand-Dmpzr6Qq.js → brand-CcN3dELF.js} +0 -0
@@ -0,0 +1,32 @@
1
+ // Task 619 — admin-identity-authenticate tool.
2
+ //
3
+ // The agent-callable PIN-submit surface for native-CC admin sessions. The
4
+ // PreToolUse identity gate validates the PIN, writes per-session auth state, and
5
+ // only then allows this tool to run; the tool itself re-asks the same loopback
6
+ // endpoint solely to fetch and return the authenticated operator's profile to
7
+ // the agent. It never touches users.json or Neo4j directly — the endpoint is the
8
+ // single resolution surface, so `loadUserProfile` is not duplicated here.
9
+ export async function runAuthenticate(pin, deps = {}) {
10
+ const f = deps.fetchImpl ?? fetch;
11
+ const port = deps.uiPort ?? process.env.MAXY_UI_INTERNAL_PORT ?? "";
12
+ const url = `http://127.0.0.1:${port}/api/admin/identity/validate`;
13
+ let data;
14
+ try {
15
+ const r = await f(url, {
16
+ method: "POST",
17
+ headers: { "content-type": "application/json" },
18
+ body: JSON.stringify({ pin }),
19
+ });
20
+ data = (await r.json());
21
+ }
22
+ catch {
23
+ return "Identity service unavailable; could not load your profile.";
24
+ }
25
+ if (data.kind !== "match")
26
+ return "Invalid PIN.";
27
+ const name = data.userName ?? "operator";
28
+ const profile = data.aboutOwner?.ok ? (data.aboutOwner.body ?? "") : "";
29
+ console.error(`[admin-identity] op=about-owner-loaded userId=${(data.userId ?? "").slice(0, 8)}`);
30
+ return `Authenticated as ${name}.\n\n${profile}`.trim();
31
+ }
32
+ //# sourceMappingURL=admin-identity-authenticate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-identity-authenticate.js","sourceRoot":"","sources":["../../src/tools/admin-identity-authenticate.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,EAAE;AACF,0EAA0E;AAC1E,iFAAiF;AACjF,+EAA+E;AAC/E,8EAA8E;AAC9E,iFAAiF;AACjF,0EAA0E;AAc1E,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,OAAyB,EAAE;IAC5E,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAA;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAA;IACnE,MAAM,GAAG,GAAG,oBAAoB,IAAI,8BAA8B,CAAA;IAElE,IAAI,IAAsB,CAAA;IAC1B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE;YACrB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;SAC9B,CAAC,CAAA;QACF,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAqB,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,4DAA4D,CAAC;IACtE,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,cAAc,CAAC;IAEjD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,UAAU,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,OAAO,CAAC,KAAK,CAAC,iDAAiD,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAClG,OAAO,oBAAoB,IAAI,QAAQ,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AAC1D,CAAC"}
@@ -41,6 +41,40 @@ deliverable is a task entry, written through the resolved task surface.
41
41
 
42
42
  ---
43
43
 
44
+ ## Step 0: Evidence First — prerequisites before any reasoning
45
+
46
+ **Do this before resolving the task surface, searching prior work,
47
+ reading code, or forming any hypothesis.** The failure mode this guards
48
+ against is forming a hypothesis from the conversation context — the
49
+ error text the user pasted, what you assume the code does — and then
50
+ treating evidence retrieval as redundant. By the time you have read the
51
+ rest of this skill you have already started doing it. Stop.
52
+
53
+ First action in this skill: create a TodoWrite list of the
54
+ prerequisites below. Work through them in order. Do not read code, do
55
+ not search prior tasks, do not propose a cause while any prerequisite
56
+ is still open.
57
+
58
+ 1. **Retrieve the requested evidence.** When the user provides a
59
+ specific artifact — a session key, log reference, error excerpt, or
60
+ pointer to a particular event — that artifact is the primary
61
+ evidence. Retrieve it with the canonical log-retrieval tool for the
62
+ surface (e.g. `logs-read` for Pi sessions on deployed maxy). If a
63
+ retrieval hook injects an exact command, execute it as given; do not
64
+ improvise.
65
+
66
+ This todo may not be marked complete until the **actual retrieved
67
+ output appears in the transcript** — the real log lines, not a
68
+ summary, not a paraphrase, not "the logs confirm X." If you cannot
69
+ produce the output, the todo stays open and that itself is the
70
+ finding: an observability or retrieval gap (see Phase 1 step 6).
71
+
72
+ 2. **If no specific artifact was provided**, mark item 1 N/A and
73
+ proceed to Phase 1 — but state explicitly that no evidence artifact
74
+ was supplied, so the investigation starts from code-path tracing.
75
+
76
+ ---
77
+
44
78
  ## Task surface (where tasks live in this environment)
45
79
 
46
80
  Before searching prior work or writing the deliverable, resolve where
@@ -64,23 +98,6 @@ Throughout this skill, "search prior tasks", "cite prior work", and
64
98
  "write a task" mean: use the resolved surface. Do not invent a new
65
99
  location.
66
100
 
67
- ---
68
-
69
- ## Evidence First
70
-
71
- When the user provides a specific artifact — a session key, log
72
- reference, error excerpt, or pointer to a particular event — that
73
- artifact is the primary evidence. Retrieve it before prior-task
74
- searches, code reading, or hypothesis formation.
75
-
76
- Use the canonical log-retrieval tool for the surface in question (e.g.
77
- `logs-read` for Pi sessions on deployed maxy). If a retrieval hook
78
- injects an exact command, execute it as given; do not improvise.
79
-
80
- If no specific artifact was provided, proceed directly to Phase 1.
81
-
82
- ---
83
-
84
101
  ## Phase 1: Root Cause Investigation
85
102
 
86
103
  1. **Check prior work.** Search the task surface (graph or `.tasks/`)
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: public-agent-manager
3
+ description: "Create, edit, clone, list, preview, and delete public agents, each a self-contained directory with its own identity, personality, knowledge, and model. Use when asked to manage, configure, or set up public agents."
4
+ ---
5
+
1
6
  # Public Agent Manager
2
7
 
3
8
  Create, edit, clone, list, preview, and delete public agents. Each public agent is a self-contained directory under `agents/` with its own identity, personality, knowledge, and model.
@@ -10,7 +15,7 @@ Each agent lives at `{accountDir}/agents/{slug}/`:
10
15
  |------|---------|----------|
11
16
  | `config.json` | Model, display name, status, image identity, knowledge keywords | Yes |
12
17
  | `IDENTITY.md` | Boundaries, behavioural rules — copied verbatim from the Rubytech template | Yes |
13
- | `SOUL.md` | Personality and role — tone, voice, warmth, greeting; plus the agent's job: give basic public info and capture the visitor's contact details for human follow-up (the chat equivalent of the landing-page contact form) | Yes |
18
+ | `SOUL.md` | Personality and the operator-defined role — tone, voice, warmth, greeting, and the role the operator gives the agent at creation | Yes |
14
19
  | `KNOWLEDGE.md` | The business's public-facing facts at landing-page detail — pricing, FAQs, services | Yes |
15
20
  | `KNOWLEDGE-SUMMARY.md` | Auto-generated summary when KNOWLEDGE.md exceeds context budget | No |
16
21
  | `assets/` | Per-agent images (logo, avatar, icon) | No |
@@ -22,7 +27,8 @@ Each agent lives at `{accountDir}/agents/{slug}/`:
22
27
  - Lowercase a-z, 0-9, hyphens only
23
28
  - 3-50 characters, must start with a letter
24
29
  - Reserved (rejected): `admin`, `api`, `assets`, `agent-assets`, `brand`, `bot`, `privacy`
25
- - `public` is the conventional default slug, but public agents are optional the platform operates without any
30
+ - Shadowed by a static route, also rejected: `public`, `chat`, `graph`, `sessions`, `data` a slug equal to one of these would 404 at `/{slug}`. If the operator asks for one, reject it and name the collision.
31
+ - Public agents are optional — the platform operates without any.
26
32
 
27
33
  ## config.json
28
34
 
@@ -82,10 +88,10 @@ Present as a `select` field within the agent configuration `form` during creatio
82
88
  SOUL.md is personality and role. When the user provides content for SOUL.md, route content that belongs elsewhere to the correct file:
83
89
 
84
90
  - **Facts, pricing, services, FAQs** → KNOWLEDGE.md
85
- - **Engagement and qualification — how the agent draws out what the visitor needs and captures their contact details for human follow-up** → SOUL.md (this is the agent's role; the public agent is toolless, so there are no plugins to embed)
91
+ - **Personality and the operator-defined role — how the agent sounds and what the operator has tasked it to do** → SOUL.md (the role is whatever the operator specifies at creation; the public agent is toolless, so there are no plugins to embed)
86
92
  - **Boundaries and procedural rules** → IDENTITY.md (Rubytech-controlled and copied verbatim — the agent's hard limits live there, not in SOUL)
87
93
 
88
- SOUL.md answers "what does this agent feel like to talk to, and what is it here to do?" — tone, warmth, formality, greeting, and the role of giving basic public info and capturing contact details. SOUL.md must not restate constraints from IDENTITY.md. When user-provided content could belong to either file, apply this test: "does this restrict what the agent does?" → IDENTITY.md. "Does this describe how the agent sounds?" → SOUL.md. If content does both (e.g. "always respond politely"), route to SOUL — the constraint is a consequence of tone, not an operational boundary. Present SOUL.md via `document-editor` for the user to review and approve. Follow the document-editor encoding constraint in IDENTITY.md when generating content.
94
+ SOUL.md answers "what does this agent feel like to talk to, and what is it here to do?" — tone, warmth, formality, greeting, and the operator-defined role the agent was created to fill. SOUL.md must not restate constraints from IDENTITY.md. When user-provided content could belong to either file, apply this test: "does this restrict what the agent does?" → IDENTITY.md. "Does this describe how the agent sounds?" → SOUL.md. If content does both (e.g. "always respond politely"), route to SOUL — the constraint is a consequence of tone, not an operational boundary. Present SOUL.md via `document-editor` for the user to review and approve. Follow the document-editor encoding constraint in IDENTITY.md when generating content.
89
95
 
90
96
  ## KNOWLEDGE.md Population
91
97
 
@@ -138,7 +144,7 @@ The following Create steps are modified when a template is provided:
138
144
  - **Step 5** — present the template's `SOUL.md` content via `document-editor` instead of drafting from conversation. The user can edit before approving.
139
145
  - **Step 6** — pre-populate form defaults: `model` from `template.json` (or `claude-haiku-4-5` if absent), `knowledgeKeywords` from `template.json` (or empty).
140
146
 
141
- All other steps (3, 7-12) proceed identically — knowledge discovery, direct tagging, KNOWLEDGE.md generation, config write, budget check, and confirmation are unchanged.
147
+ All other steps (3, 7-13) proceed identically — knowledge discovery, direct tagging, KNOWLEDGE.md generation, config write, budget check, default-setting, and confirmation are unchanged.
142
148
 
143
149
  After creation, no template metadata persists in the agent's files. The resulting agent is indistinguishable from one created manually. The user owns it completely.
144
150
 
@@ -148,7 +154,7 @@ After creation, no template metadata persists in the agent's files. The resultin
148
154
  2. Ask for the agent's name (becomes the slug) and role description
149
155
  3. **Knowledge discovery** — search the graph with admin permissions (no `agentSlug` — the agent doesn't exist yet) to find available knowledge. Present available content grouped by category for the user to select.
150
156
  4. **Install `IDENTITY.md`** — copy the Rubytech-controlled template verbatim to `agents/{slug}/IDENTITY.md`. It is fixed (the toolless public directive — Task 615) and is never drafted, edited, or presented for review.
151
- 5. Present `SOUL.md` via document-editor with `filePath: "agents/{slug}/SOUL.md"` (draft personality and role from user conversation — tone plus the job of giving basic public info and capturing the visitor's contact details). Write on approval. Must be non-empty; an empty SOUL is refused at spawn.
157
+ 5. Present `SOUL.md` via document-editor with `filePath: "agents/{slug}/SOUL.md"` (draft personality and the operator-defined role from user conversation — tone plus the role the operator describes for the agent). Write on approval. Must be non-empty; an empty SOUL is refused at spawn.
152
158
  6. Present agent configuration via a single `form` component with these fields:
153
159
  - `knowledgeKeywords` (`text`): label "Knowledge keywords (max 5, comma-separated)", placeholder with examples relevant to the agent's role
154
160
  - `model` (`select`): label "Model", options with descriptions:
@@ -169,7 +175,8 @@ After creation, no template metadata persists in the agent's files. The resultin
169
175
  9. Write `config.json` with selected model, status "active", and `knowledgeKeywords`. This is the last gated write — placed after IDENTITY.md, SOUL.md, and KNOWLEDGE.md to prevent cascade failure if one gate stalls.
170
176
  10. Check context budget — auto-summarise if over threshold
171
177
  11. **Project the agent into the graph** — delegate to the `specialists:database-operator` specialist with the instruction: "Project public agent `{slug}` into the graph by POSTing to `/api/admin/agents/{slug}/project`." The route reads the on-disk files and idempotently MERGEs the `:Agent` node, the four owned `:KnowledgeDocument` projections (IDENTITY/SOUL/KNOWLEDGE/KNOWLEDGE-SUMMARY when present, namespaced `attachmentId="agent:<slug>:<role>"`), the `HAS_*` edges, and the `USES_KNOWLEDGE` edges to every operator-tagged doc. Loud-fail: if the route returns non-2xx, surface the error to the user verbatim — the agent's files exist on disk but its graph projection is incomplete, which means the operator's /graph view will not show this agent. Re-running the projection is safe; it is the same idempotent MERGE.
172
- 12. Confirm creation: "Agent created. Visitors can reach it at `/{slug}`"
178
+ 12. **Set the default if none exists.** Read `defaultAgent` from `account-manage`. If it is empty, set it to this new slug via `account-update` (`field: "defaultAgent"`, `value: "{slug}"`) otherwise the agent answers at `/{slug}` but the bare root serves nothing. If a default already exists, do not change it silently: tell the operator the current default and ask whether to switch the root to this new agent; call `account-update` only if they say yes.
179
+ 13. Confirm creation: "Agent created and reachable at `/{slug}`." If you set or changed the default in step 12, add: "The site root also serves this agent." If a different default remains, add: "The site root still serves `{currentDefault}`."
173
180
 
174
181
  ### List
175
182
 
@@ -181,7 +188,7 @@ Read `defaultAgent` from `account-manage` to identify the current default. Read
181
188
  **support** — Haiku Low cost
182
189
  3,200 / 40,000 tokens (8%) · active
183
190
 
184
- **public** — Haiku Low cost
191
+ **hello** — Haiku Low cost
185
192
  9,800 / 40,000 tokens (25%) · active
186
193
 
187
194
  ### Clone
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: publish-site
3
+ description: "Move an already-extracted static-site tree into the per-account static-publish surface and emit one canonical path slug. Use when asked to publish, host, or put a site online."
4
+ ---
5
+
1
6
  # Publish Site
2
7
 
3
8
  Call `mcp__plugin_admin_admin__publish-site` to move an already-extracted static-site tree into the per-account static-publish surface (`<accountDir>/sites/<slug>/`) and emit one canonical path slug. Pair the slug with `mcp__plugin_admin_admin__public-hostname` to surface the full URL in the same turn.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: unzip-attachment
3
+ description: "Safely extract a zip archive the admin has uploaded, inventory its contents, and route each entry to the right downstream specialist, refusing path traversal, symlink escape, and decompression bombs. Use when an admin uploads a zip to unzip or extract."
4
+ ---
5
+
1
6
  # Unzip Attachment
2
7
 
3
8
  Safely extract a zip archive the admin has uploaded, inventory its contents, and propose one concrete follow-up per entry class — refusing archives that attempt path traversal, symlink escape, or decompression-bomb pathologies.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: update-knowledge
3
+ description: "Refresh a public agent's KNOWLEDGE.md from the current graph, scoped to that agent's knowledge configuration. Use when asked to update, refresh, or regenerate a public agent's knowledge."
4
+ ---
5
+
1
6
  # Update Knowledge
2
7
 
3
8
  Refresh a public agent's KNOWLEDGE.md from the current graph, scoped to that agent's knowledge configuration.
@@ -0,0 +1,81 @@
1
+ # Native-CC admin PIN identity gate
2
+
3
+ Every native-CC admin session — the operator chatting through claude.ai/code (web,
4
+ desktop, mobile) over the per-account `claude rc` daemon — must bind a
5
+ PIN-authenticated `userId` before any tool runs. This closes the gap where the
6
+ daemon stamped one boot-time `USER_ID` (from `users.json`) onto every session,
7
+ which is correct for at most one human on a multi-admin install. (Task 619.)
8
+
9
+ The legacy cookie/PIN browser login (`POST /api/admin/session`) is a separate
10
+ surface documented in [`admin-session.md`](admin-session.md); this gate covers the
11
+ native path, which that login never touched.
12
+
13
+ ## How it works
14
+
15
+ Three pieces, plus a standing audit. No cross-process `session_id` plumbing: the
16
+ hook keys state by the `session_id` it reads from stdin; validation and profile
17
+ resolution live behind one loopback endpoint.
18
+
19
+ 1. **Shared validator** — `ui/app/lib/admin-identity/pin-validator.ts`. The single
20
+ PIN primitive (`validatePin` → `match` / `miss` / `unavailable` / `corrupt`),
21
+ shared by the legacy browser login and the gate so the two cannot drift.
22
+
23
+ 2. **Loopback validate endpoint** — `POST /api/admin/identity/validate`
24
+ (`ui/server/routes/admin/identity.ts`). Loopback-only (rejects any request
25
+ carrying `x-forwarded-for`, which only edge-proxied browser requests have).
26
+ Body `{ pin, sessionId? }`. On a match it resolves the operator's `userName`
27
+ and `aboutOwner` via the same helpers the browser path uses
28
+ (`resolveUserIdentity`, `resolveOwnerProfileBlock`) — `loadUserProfile` is never
29
+ duplicated. On a miss with a `sessionId` it fires a best-effort manager
30
+ `POST /<sessionId>/stop` (only the UI process reliably holds the manager port).
31
+
32
+ 3. **PreToolUse gate hook** — `plugins/admin/hooks/pin-identity-gate.sh`, wired in
33
+ `setup-account.sh` as the first universal PreToolUse entry. Runs only for native
34
+ operator sessions (`MAXY_SESSION_ROLE=admin` and empty `MAXY_SPECIALIST` — the
35
+ latter excludes pty-spawned specialist/recorder sessions). Per tool call: if an
36
+ auth-state file exists for the `session_id`, allow; if the tool is
37
+ `admin-identity-authenticate`, post the PIN to the validate endpoint and on a
38
+ match write the state file and allow (on a miss/unavailable, deny + terminate);
39
+ any other tool while unauthenticated is denied with an instruction to
40
+ authenticate first. Enforcement is in the hook, not the agent's choice — a model
41
+ that skips the prompt reaches no other tool.
42
+
43
+ The agent-callable surface is the eager-loaded `admin-identity-authenticate` MCP
44
+ tool (admin plugin); the gate validates and binds before allowing it, and the tool
45
+ returns the authenticated operator's profile to the agent.
46
+
47
+ Auth state: `<accountDir>/state/admin-identity/<session_id>.json` (`{userId, ts}`).
48
+ One file per authenticated conversation; bound for the session lifetime, not
49
+ re-prompted per message. Task-tool specialist subagents share the operator's
50
+ `session_id`, so they pass once the operator is authenticated.
51
+
52
+ ## Cases
53
+
54
+ - **Zero admins / absent / empty `users.json`** → `pin-unavailable`, the gate
55
+ refuses; never a bound empty `userId`. A real install always has `users.json`
56
+ (the installer/seed writes it), so this is a misconfiguration guard.
57
+ - **One admin** → still prompts; the single matching PIN binds that `userId`.
58
+ - **Many admins** → each PIN binds its own `userId`. The account is fixed (the
59
+ install's own scope); there is no multi-account picker on this path.
60
+ - **Mismatch** → the session is terminated on the first miss (no retry budget).
61
+
62
+ ## Observability
63
+
64
+ One structured `[admin-identity]` line per step, correlated by `sessionId`:
65
+
66
+ ```
67
+ op=loopback-spawn-received → op=pin-prompted → (op=pin-bound source=pin |
68
+ op=pin-miss → op=session-terminated) ; the MCP tool emits op=about-owner-loaded.
69
+ ```
70
+
71
+ **Standing audit** (`services/claude-session-manager/src/admin-identity-audit.ts`,
72
+ every 60s) reconciles, independently of the hook, live native-operator sessions
73
+ (watcher rows with `role === null` — daemon-spawned, no sidecar) that reached real
74
+ tool use against the auth-state files. Any such session with no state file emits
75
+ `[admin-identity] op=audit-orphan sessionId=…
76
+ reason=loopback-session-without-authenticated-userId`. This is the no-event
77
+ detector: a silent gate bypass leaves no per-session log line, but the audit still
78
+ surfaces it.
79
+
80
+ Diagnostic path: `journalctl --user -u <brand>-admin | grep -E '\[admin-identity\]'`,
81
+ then filter by `sessionId` for one session's full lifeline.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: conversation-archive-enrich
3
+ description: "Walk an existing ConversationArchive's chunks and derive high-confidence claims and insights into the graph, one operator-gated proposal per row. Use when asked to enrich, derive insights from, or mine an existing conversation archive."
3
4
  ---
4
5
 
5
6
  # Conversation Archive — chunk-anchored insight derivation
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: conversational-memory
3
+ description: "Notice, store, and recall who the owner is and how they work, accumulated from natural conversation rather than forms. Use when recording or retrieving user profile, preferences, and remembered context across sessions."
4
+ ---
5
+
1
6
  # Conversational Memory
2
7
 
3
8
  Memory accumulates from conversation — never from questionnaires, quizzes, or onboarding forms. The owner reveals who they are and how they work through natural interaction. Your role is to notice, store, and recall that knowledge so every session feels continuous rather than starting from scratch.
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: workflow-manager
3
+ description: "Create, test, and diagnose persistent workflows that automate recurring multi-step processes spanning different plugin tools. Use when the user describes a recurring multi-step process to automate."
4
+ ---
5
+
1
6
  # Workflow Manager
2
7
 
3
8
  Create, test, and diagnose persistent workflows that automate recurring multi-step processes.
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+ // Task 621 — bundle-time frontmatter check for every SKILL.md across the
3
+ // plugins trees.
4
+ //
5
+ // Why: Claude Code surfaces a skill in the session's available-skills reminder,
6
+ // and makes it matchable by the description-driven search tools (ToolSearch,
7
+ // skill-find), ONLY if its SKILL.md opens with YAML frontmatter carrying a
8
+ // `name:` and a `description:`. A SKILL.md that opens straight into an `#` H1
9
+ // has no description for the reminder to list and nothing for fuzzy search to
10
+ // match — it stays invisible until an operator finds the directory by hand,
11
+ // while the agent burns turns on blind find/grep. The skill remains invokable
12
+ // by exact name, so the defect is silent: no error, no log line. This module
13
+ // is the standing guard that fails the bundle before such a payload ships, so
14
+ // the next frontmatter-less skill cannot regress discovery the same way.
15
+ //
16
+ // A file passes iff it opens with a `---\n...\n---` frontmatter block whose
17
+ // keys include both `name:` and `description:`. Three failure shapes are
18
+ // reported distinctly: no frontmatter block at all, missing `name:`, missing
19
+ // `description:`.
20
+
21
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
22
+ import { resolve, relative, join, dirname } from "node:path";
23
+ import { pathToFileURL } from "node:url";
24
+
25
+ // Walk `dir` recursively, collecting every file whose basename matches `predicate`.
26
+ function walk(dir, predicate, out = []) {
27
+ if (!existsSync(dir)) return out;
28
+ let entries;
29
+ try {
30
+ entries = readdirSync(dir);
31
+ } catch {
32
+ return out;
33
+ }
34
+ for (const entry of entries) {
35
+ const full = join(dir, entry);
36
+ let st;
37
+ try {
38
+ st = statSync(full);
39
+ } catch {
40
+ continue;
41
+ }
42
+ if (st.isDirectory()) {
43
+ walk(full, predicate, out);
44
+ } else if (predicate(entry, full)) {
45
+ out.push(full);
46
+ }
47
+ }
48
+ return out;
49
+ }
50
+
51
+ // Extract the leading frontmatter block. A block exists only when the very
52
+ // first line is `---` and a closing `---` follows on its own line. The closing
53
+ // fence is anchored to end-of-line (`\r?\n|$`) so a body line that merely
54
+ // starts with `---` (a `---trailing` divider) cannot be mistaken for the
55
+ // close, and a frontmatter-only file ending exactly at `---` still matches.
56
+ // Returns the block body (between the fences) or null when there is no block.
57
+ function frontmatterBody(raw) {
58
+ const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
59
+ return m ? m[1] : null;
60
+ }
61
+
62
+ // True if the block contains a `<key>:` line at the start of any line. The key
63
+ // may be followed by a value, a block scalar (`|`/`>`), or nothing.
64
+ function hasKey(block, key) {
65
+ const re = new RegExp(`^${key}:`, "m");
66
+ return re.test(block);
67
+ }
68
+
69
+ function scanFile(filePath, repoRoot) {
70
+ let raw;
71
+ try {
72
+ raw = readFileSync(filePath, "utf-8");
73
+ } catch {
74
+ return null;
75
+ }
76
+ const source = relative(repoRoot, filePath);
77
+ const block = frontmatterBody(raw);
78
+ if (block === null) {
79
+ return { source, reason: "no YAML frontmatter block (file opens without a leading `---`)" };
80
+ }
81
+ const missing = [];
82
+ if (!hasKey(block, "name")) missing.push("name");
83
+ if (!hasKey(block, "description")) missing.push("description");
84
+ if (missing.length > 0) {
85
+ return { source, reason: `frontmatter missing required key(s): ${missing.join(", ")}` };
86
+ }
87
+ return null;
88
+ }
89
+
90
+ export function runSkillFrontmatterCheck({ platformRoot, premiumRoot }) {
91
+ const repoRoot = resolve(platformRoot, "..");
92
+ const sources = [];
93
+
94
+ // platform: every SKILL.md under plugins/
95
+ walk(resolve(platformRoot, "plugins"), (name) => name === "SKILL.md", sources);
96
+
97
+ // premium: every SKILL.md under any bundle (standalone or sub)
98
+ if (premiumRoot && existsSync(premiumRoot)) {
99
+ walk(premiumRoot, (name) => name === "SKILL.md", sources);
100
+ }
101
+
102
+ const violations = [];
103
+ for (const src of sources) {
104
+ const v = scanFile(src, repoRoot);
105
+ if (v) violations.push(v);
106
+ }
107
+
108
+ return {
109
+ ok: violations.length === 0,
110
+ violations,
111
+ scanned: sources.length,
112
+ };
113
+ }
114
+
115
+ // CLI entry — `node check-skill-frontmatter.mjs [platformRoot] [premiumRoot]`.
116
+ // pathToFileURL keeps the self-detect correct across paths with spaces or
117
+ // non-ASCII characters. When loaded via `import` from bundle.js the URLs
118
+ // differ and this block is skipped.
119
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
120
+ const defaultPlatform = resolve(import.meta.dirname, "..");
121
+ const defaultPremium = resolve(import.meta.dirname, "..", "..", "premium-plugins");
122
+ const platformRoot = process.argv[2] ? resolve(process.argv[2]) : defaultPlatform;
123
+ const premiumRoot = process.argv[3] ? resolve(process.argv[3]) : defaultPremium;
124
+ const r = runSkillFrontmatterCheck({ platformRoot, premiumRoot });
125
+ if (!r.ok) {
126
+ for (const v of r.violations) {
127
+ console.error(`[bundle-validator] skill frontmatter missing`);
128
+ console.error(` source: ${v.source}`);
129
+ console.error(` reason: ${v.reason}`);
130
+ }
131
+ console.error(
132
+ `FATAL: ${r.violations.length} SKILL.md file(s) without name/description frontmatter across ${r.scanned} scanned file(s).`,
133
+ );
134
+ process.exit(1);
135
+ }
136
+ console.log(
137
+ `[bundle-validator] skill frontmatter ok scanned=${r.scanned}`,
138
+ );
139
+ }
@@ -75,6 +75,11 @@ cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
75
75
  },
76
76
  "hooks": {
77
77
  "PreToolUse": [
78
+ {
79
+ "hooks": [
80
+ { "type": "command", "command": "bash $HOOKS_PATH/pin-identity-gate.sh" }
81
+ ]
82
+ },
78
83
  {
79
84
  "matcher": "Write",
80
85
  "hooks": [
@@ -255,22 +260,6 @@ if [ ! -f "$ACCOUNT_DIR/account.json" ]; then
255
260
  fi
256
261
  fi
257
262
 
258
- # Backfill defaultAgent in account.json if missing (existing accounts earlier).
259
- # Uses the first non-admin agent directory that has a config.json.
260
- if [ -f "$ACCOUNT_DIR/account.json" ] && ! grep -q '"defaultAgent"' "$ACCOUNT_DIR/account.json"; then
261
- _DEFAULT_SLUG=""
262
- for _AGENT_DIR in "$ACCOUNT_DIR/agents"/*/; do
263
- _AGENT_NAME="$(basename "$_AGENT_DIR")"
264
- [ "$_AGENT_NAME" = "admin" ] && continue
265
- [ -f "$_AGENT_DIR/config.json" ] && { _DEFAULT_SLUG="$_AGENT_NAME"; break; }
266
- done
267
- if [ -n "$_DEFAULT_SLUG" ]; then
268
- # Insert defaultAgent before the closing brace
269
- sed -i'' "s/}$/,\"defaultAgent\":\"$_DEFAULT_SLUG\"}/" "$ACCOUNT_DIR/account.json"
270
- echo " Backfilled defaultAgent=$_DEFAULT_SLUG in account.json"
271
- fi
272
- fi
273
-
274
263
  # ------------------------------------------------------------------
275
264
  # 5. Seed enabledPlugins from brand.json plugins.defaultEnabled
276
265
  # ------------------------------------------------------------------
@@ -0,0 +1,39 @@
1
+ import type { FsWatcher } from './fs-watcher.js';
2
+ export type Logger = (line: string) => void;
3
+ export interface AuditSession {
4
+ sessionId: string;
5
+ /** Sidecar role, or null for native rc-daemon operator sessions. */
6
+ role: string | null;
7
+ state: string;
8
+ /** True when the JSONL contains an assistant tool_use whose name is not the
9
+ * auth tool. */
10
+ usedRealTool: boolean;
11
+ }
12
+ export interface AuditOnceDeps {
13
+ sessions: AuditSession[];
14
+ hasState: (sessionId: string) => boolean;
15
+ logger: Logger;
16
+ }
17
+ /** Pure reconciliation: emit one audit-orphan line per live native-operator
18
+ * session that used a real tool but has no auth-state file. */
19
+ export declare function auditOnce(deps: AuditOnceDeps): number;
20
+ export interface IdentityAuditDeps {
21
+ watcher: FsWatcher;
22
+ /** Account dir (the manager's spawnCwd); used to derive JSONL + state paths. */
23
+ spawnCwd: string;
24
+ /** Directory holding per-session auth-state files written by the gate hook. */
25
+ stateDir: string;
26
+ intervalMs: number;
27
+ logger: Logger;
28
+ }
29
+ export interface IdentityAudit {
30
+ start(): void;
31
+ stop(): void;
32
+ /** Run one audit pass synchronously. Exposed for tests. */
33
+ tickOnce(): {
34
+ scanned: number;
35
+ orphans: number;
36
+ };
37
+ }
38
+ export declare function createIdentityAudit(deps: IdentityAuditDeps): IdentityAudit;
39
+ //# sourceMappingURL=admin-identity-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-identity-audit.d.ts","sourceRoot":"","sources":["../src/admin-identity-audit.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAA;AAU5D,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;AAE3C,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,oEAAoE;IACpE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb;qBACiB;IACjB,YAAY,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAA;IACxC,MAAM,EAAE,MAAM,CAAA;CACf;AAED;gEACgE;AAChE,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAarD;AAiCD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,SAAS,CAAA;IAClB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAA;IAChB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;IACZ,2DAA2D;IAC3D,QAAQ,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CACjD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,aAAa,CA0C1E"}