@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.
- package/package.json +1 -1
- package/payload/platform/config/brand.json +3 -3
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +4 -1
- package/payload/platform/plugins/admin/hooks/__tests__/pin-identity-gate.test.sh +96 -0
- package/payload/platform/plugins/admin/hooks/pin-identity-gate.sh +136 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js +34 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js +50 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +8 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts +6 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js +32 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js.map +1 -0
- package/payload/platform/plugins/admin/skills/investigate/SKILL.md +34 -17
- package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +15 -8
- package/payload/platform/plugins/admin/skills/publish-site/SKILL.md +5 -0
- package/payload/platform/plugins/admin/skills/unzip-attachment/SKILL.md +5 -0
- package/payload/platform/plugins/admin/skills/update-knowledge/SKILL.md +5 -0
- package/payload/platform/plugins/docs/references/admin-identity-gate.md +81 -0
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +1 -0
- package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +5 -0
- package/payload/platform/plugins/workflows/skills/workflow-manager/SKILL.md +5 -0
- package/payload/platform/scripts/check-skill-frontmatter.mjs +139 -0
- package/payload/platform/scripts/setup-account.sh +5 -16
- package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts +39 -0
- package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js +133 -0
- package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +29 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +28 -0
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +99 -0
- package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -0
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
- package/payload/server/{chunk-JMEX5NRX.js → chunk-UEIA5YUG.js} +30 -18
- package/payload/server/maxy-edge.js +7 -5
- package/payload/server/public/assets/{AdminShell-D_eg2QKE.js → AdminShell-892Jy_rs.js} +1 -1
- package/payload/server/public/assets/AdminShell-qc_xy7Az.css +1 -0
- package/payload/server/public/assets/{Checkbox-CfE7p1Tv.js → Checkbox-Bc2QzX9b.js} +1 -1
- package/payload/server/public/assets/{admin-DfeXRW1m.js → admin-D3K13ndi.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DvDVmNbJ.js → architectureDiagram-Q4EWVU46-c09loTER.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CVCQHVcw.js → blockDiagram-DXYQGD6D-Cjdeyoq1.js} +1 -1
- package/payload/server/public/assets/brand-D0gNihp7.css +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DancbaY-.js → c4Diagram-AHTNJAMY-NY6Wlzo2.js} +1 -1
- package/payload/server/public/assets/channel-B1IT7to2.js +1 -0
- package/payload/server/public/assets/chunk-336JU56O-CdKRCIeE.js +2 -0
- package/payload/server/public/assets/{chunk-426QAEUC-Dqt07sZz.js → chunk-426QAEUC-BybuQ3Ve.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-Bdm77ygl.js → chunk-4TB4RGXK-BXpto3yW.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-nDbgOH1b.js → chunk-5FUZZQ4R-C403gCUk.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-mYip6Ias.js → chunk-5PVQY5BW-CjVzXQEp.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DubyAY7F.js → chunk-EDXVE4YY-DJcJAsAg.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-DIa8CJbF.js → chunk-ENJZ2VHE-CFDNvYu1.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-bKmK-tZo.js → chunk-ICPOFSXX-ecLOxGhL.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-KcUQTwd8.js → chunk-OYMX7WX6-B7MW66KB.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-3p-zDDFG.js → chunk-U2HBQHQK-BMawmsyk.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-C5F60GoO.js → chunk-X2U36JSP-CT6g7pno.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-CEhP6XMC.js → chunk-YZCP3GAM-xeAluiAH.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Bac24FOS.js → chunk-ZZ45TVLE-BRN9qUC5.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-rjCize6i.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BORWOUt0.js +1 -0
- package/payload/server/public/assets/clone-Csqv5U6T.js +1 -0
- package/payload/server/public/assets/{dagre-xntZVDsO.js → dagre-DTjePoco.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-DqGsPaYJ.js → dagre-KV5264BT-DHBkRke4.js} +1 -1
- package/payload/server/public/assets/{data-JoiWCmz6.js → data-Br-pdljK.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-Co8NC28s.js → diagram-5BDNPKRD-BIq1-idL.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-HewQArEf.js → diagram-G4DWMVQ6-BsIUDzV6.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-s6NqURmM.js → diagram-MMDJMWI5-CgHSri2i.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CAof9UmL.js → diagram-TYMM5635-Ce2Wh9ZX.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-CUqIICFD.js → erDiagram-SMLLAGMA-BU0Kh6OQ.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DN1n7xgU.js → flowDiagram-DWJPFMVM-B0N06MF7.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-sGoWsEWZ.js → ganttDiagram-T4ZO3ILL-BVbx4ARZ.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-Dz_cZL1Q.js → gitGraphDiagram-UUTBAWPF-C-xRJ94t.js} +1 -1
- package/payload/server/public/assets/{graph-DmOvqjTa.js → graph-g48ZcA5M.js} +1 -1
- package/payload/server/public/assets/{graph-labels-iPC15OmD.js → graph-labels-BYH-IPCb.js} +1 -1
- package/payload/server/public/assets/{graphlib-eZzlPtt9.js → graphlib-YmNcoMjY.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-DFMOgYMn.js → infoDiagram-42DDH7IO-Di6oPQ_-.js} +1 -1
- package/payload/server/public/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
- package/payload/server/public/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
- package/payload/server/public/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
- package/payload/server/public/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
- package/payload/server/public/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
- package/payload/server/public/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/payload/server/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/payload/server/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
- package/payload/server/public/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
- package/payload/server/public/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
- package/payload/server/public/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
- package/payload/server/public/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
- package/payload/server/public/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-C9AGnqZn.js → ishikawaDiagram-UXIWVN3A-DTrq54yC.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-C4-y1Faf.js → journeyDiagram-VCZTEJTY-OZZZMrFX.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DIynz-Si.js → kanban-definition-6JOO6SKY--w-IP9pN.js} +1 -1
- package/payload/server/public/assets/{line-CzaIC22F.js → line-Ckeulv5T.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-Dcdye_D2.js → mermaid-parser.core-CVRAxYRD.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-HWxg8X0R.js → mermaid.core-B-mE18I1.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-ve0J3SsF.js → mindmap-definition-QFDTVHPH-Bm8mDicL.js} +1 -1
- package/payload/server/public/assets/newsreader-latin-300-normal-AOSWdb_s.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-300-normal-FGBQ0wlI.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-400-normal-BFBkh4jY.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-400-normal-gRTjlS2D.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-500-normal-B66TYsaK.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-500-normal-DFwuUcdu.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-300-normal-CFtw49Zd.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-300-normal-DRMzurxT.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-400-normal-DYA1XoQK.woff +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-400-normal-svq1FPys.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-500-normal-BNHmvKvI.woff2 +0 -0
- package/payload/server/public/assets/newsreader-latin-ext-500-normal-CZruMFou.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-300-normal-CsrIkm-V.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-300-normal-D3VHEe81.woff2 +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-400-normal-BekUZro8.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-400-normal-DdKr49mV.woff2 +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-500-normal-BEAbKU8A.woff +0 -0
- package/payload/server/public/assets/newsreader-vietnamese-500-normal-CL6a8tp2.woff2 +0 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DdiZi8Iv.js → pieDiagram-DEJITSTG-BCmRLgGO.js} +1 -1
- package/payload/server/public/assets/{public-DbW8Up_b.js → public-DknO-g9S.js} +5 -5
- package/payload/server/public/assets/public-vnj7OhQj.css +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CvNd8CMM.js → quadrantDiagram-34T5L4WZ-CniTIUTm.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-8LsItfG7.js → requirementDiagram-MS252O5E-CoxBSj9M.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-CoXsggQF.js → sankeyDiagram-XADWPNL6-BjS-4jzq.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CxtIGmey.js → sequenceDiagram-FGHM5R23-B9jVOnPR.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-C2zgoy3P.js → stateDiagram-FHFEXIEX-BvOQPzP8.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-v4ND10uR.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DQ_J-0lx.js → timeline-definition-GMOUNBTQ-CdfgWLo1.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-BbLqtKTJ.js → useSelectionMode-DwsyptOw.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-B7Y7Cw54.js → vennDiagram-DHZGUBPP-JCgpIbj-.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-1XkR1IH-.js → wardleyDiagram-NUSXRM2D-Dei3VqHo.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CcatDElf.js → xychartDiagram-5P7HB3ND-DUtIyoIb.js} +1 -1
- package/payload/server/public/brand-defaults.css +3 -3
- package/payload/server/public/data.html +6 -5
- package/payload/server/public/graph.html +7 -6
- package/payload/server/public/index.html +7 -6
- package/payload/server/public/public.html +7 -6
- package/payload/server/server.js +290 -157
- package/payload/server/public/assets/brand-hVIfBy3s.css +0 -1
- package/payload/server/public/assets/channel-t5srld-W.js +0 -1
- package/payload/server/public/assets/chunk-336JU56O-DL5O4-qf.js +0 -2
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-197c9FtA.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C5RIsovf.js +0 -1
- package/payload/server/public/assets/clone-BJPTkE0R.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-C3CpI3Q7.js +0 -1
- /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
|
|
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`
|
|
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
|
-
- **
|
|
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
|
|
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-
|
|
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
|
|
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.
|
|
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
|
-
**
|
|
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"}
|