@cotrrackpro-dev/sdk 0.1.0
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/CHANGELOG.md +51 -0
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/assistant/compliance.d.ts +24 -0
- package/dist/assistant/compliance.js +60 -0
- package/dist/assistant/compliance.js.map +1 -0
- package/dist/assistant/crisis.d.ts +31 -0
- package/dist/assistant/crisis.js +62 -0
- package/dist/assistant/crisis.js.map +1 -0
- package/dist/assistant/index.d.ts +15 -0
- package/dist/assistant/index.js +16 -0
- package/dist/assistant/index.js.map +1 -0
- package/dist/assistant/levels.d.ts +43 -0
- package/dist/assistant/levels.js +102 -0
- package/dist/assistant/levels.js.map +1 -0
- package/dist/assistant/prompt.d.ts +20 -0
- package/dist/assistant/prompt.js +96 -0
- package/dist/assistant/prompt.js.map +1 -0
- package/dist/assistant/rbac.d.ts +45 -0
- package/dist/assistant/rbac.js +75 -0
- package/dist/assistant/rbac.js.map +1 -0
- package/dist/assistant/readability.d.ts +28 -0
- package/dist/assistant/readability.js +70 -0
- package/dist/assistant/readability.js.map +1 -0
- package/dist/auth/broker.d.ts +32 -0
- package/dist/auth/broker.js +48 -0
- package/dist/auth/broker.js.map +1 -0
- package/dist/auth/deviceFlow.d.ts +26 -0
- package/dist/auth/deviceFlow.js +65 -0
- package/dist/auth/deviceFlow.js.map +1 -0
- package/dist/auth/provider.d.ts +32 -0
- package/dist/auth/provider.js +29 -0
- package/dist/auth/provider.js.map +1 -0
- package/dist/community/badges.d.ts +19 -0
- package/dist/community/badges.js +19 -0
- package/dist/community/badges.js.map +1 -0
- package/dist/community/events.d.ts +30 -0
- package/dist/community/events.js +31 -0
- package/dist/community/events.js.map +1 -0
- package/dist/community/identity.d.ts +28 -0
- package/dist/community/identity.js +2 -0
- package/dist/community/identity.js.map +1 -0
- package/dist/community/index.d.ts +7 -0
- package/dist/community/index.js +8 -0
- package/dist/community/index.js.map +1 -0
- package/dist/community/org.d.ts +46 -0
- package/dist/community/org.js +32 -0
- package/dist/community/org.js.map +1 -0
- package/dist/community/tiers.d.ts +8 -0
- package/dist/community/tiers.js +40 -0
- package/dist/community/tiers.js.map +1 -0
- package/dist/community/types.d.ts +26 -0
- package/dist/community/types.js +2 -0
- package/dist/community/types.js.map +1 -0
- package/dist/core/config.d.ts +22 -0
- package/dist/core/config.js +27 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/errors.d.ts +29 -0
- package/dist/core/errors.js +20 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/transport.d.ts +45 -0
- package/dist/core/transport.js +109 -0
- package/dist/core/transport.js.map +1 -0
- package/dist/diagram/core.d.ts +11 -0
- package/dist/diagram/core.js +12 -0
- package/dist/diagram/core.js.map +1 -0
- package/dist/diagram/extract.d.ts +17 -0
- package/dist/diagram/extract.js +213 -0
- package/dist/diagram/extract.js.map +1 -0
- package/dist/diagram/index.d.ts +2 -0
- package/dist/diagram/index.js +3 -0
- package/dist/diagram/index.js.map +1 -0
- package/dist/diagram/mermaid.d.ts +10 -0
- package/dist/diagram/mermaid.js +50 -0
- package/dist/diagram/mermaid.js.map +1 -0
- package/dist/diagram/prompt.d.ts +4 -0
- package/dist/diagram/prompt.js +16 -0
- package/dist/diagram/prompt.js.map +1 -0
- package/dist/diagram/types.d.ts +33 -0
- package/dist/diagram/types.js +2 -0
- package/dist/diagram/types.js.map +1 -0
- package/dist/diagram/validate.d.ts +13 -0
- package/dist/diagram/validate.js +48 -0
- package/dist/diagram/validate.js.map +1 -0
- package/dist/guide/compose.d.ts +10 -0
- package/dist/guide/compose.js +31 -0
- package/dist/guide/compose.js.map +1 -0
- package/dist/guide/core.d.ts +10 -0
- package/dist/guide/core.js +11 -0
- package/dist/guide/core.js.map +1 -0
- package/dist/guide/index.d.ts +2 -0
- package/dist/guide/index.js +3 -0
- package/dist/guide/index.js.map +1 -0
- package/dist/guide/prompt.d.ts +8 -0
- package/dist/guide/prompt.js +20 -0
- package/dist/guide/prompt.js.map +1 -0
- package/dist/guide/render.d.ts +9 -0
- package/dist/guide/render.js +180 -0
- package/dist/guide/render.js.map +1 -0
- package/dist/guide/types.d.ts +67 -0
- package/dist/guide/types.js +2 -0
- package/dist/guide/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/artifacts.generated.d.ts +19 -0
- package/dist/mcp/artifacts.generated.js +140 -0
- package/dist/mcp/artifacts.generated.js.map +1 -0
- package/dist/mcp/format.d.ts +10 -0
- package/dist/mcp/format.js +17 -0
- package/dist/mcp/format.js.map +1 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.js +18 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/knowledge.generated.d.ts +11 -0
- package/dist/mcp/knowledge.generated.js +12 -0
- package/dist/mcp/knowledge.generated.js.map +1 -0
- package/dist/mcp/prompt-modules.generated.d.ts +12 -0
- package/dist/mcp/prompt-modules.generated.js +19 -0
- package/dist/mcp/prompt-modules.generated.js.map +1 -0
- package/dist/mcp/roles.generated.d.ts +15 -0
- package/dist/mcp/roles.generated.js +25 -0
- package/dist/mcp/roles.generated.js.map +1 -0
- package/dist/mcp/safety.d.ts +35 -0
- package/dist/mcp/safety.js +76 -0
- package/dist/mcp/safety.js.map +1 -0
- package/dist/mcp/scenarios.generated.d.ts +13 -0
- package/dist/mcp/scenarios.generated.js +16 -0
- package/dist/mcp/scenarios.generated.js.map +1 -0
- package/dist/mcp/search.d.ts +13 -0
- package/dist/mcp/search.js +33 -0
- package/dist/mcp/search.js.map +1 -0
- package/dist/mcp/skills.generated.d.ts +17 -0
- package/dist/mcp/skills.generated.js +40 -0
- package/dist/mcp/skills.generated.js.map +1 -0
- package/dist/mcp/toolset.d.ts +31 -0
- package/dist/mcp/toolset.js +54 -0
- package/dist/mcp/toolset.js.map +1 -0
- package/dist/mcp/types.d.ts +96 -0
- package/dist/mcp/types.js +9 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/mcp/workflows.generated.d.ts +17 -0
- package/dist/mcp/workflows.generated.js +12 -0
- package/dist/mcp/workflows.generated.js.map +1 -0
- package/dist/nocode/core.d.ts +12 -0
- package/dist/nocode/core.js +13 -0
- package/dist/nocode/core.js.map +1 -0
- package/dist/nocode/examples.d.ts +28 -0
- package/dist/nocode/examples.js +218 -0
- package/dist/nocode/examples.js.map +1 -0
- package/dist/nocode/index.d.ts +2 -0
- package/dist/nocode/index.js +3 -0
- package/dist/nocode/index.js.map +1 -0
- package/dist/nocode/mermaid.d.ts +9 -0
- package/dist/nocode/mermaid.js +33 -0
- package/dist/nocode/mermaid.js.map +1 -0
- package/dist/nocode/prompt.d.ts +8 -0
- package/dist/nocode/prompt.js +46 -0
- package/dist/nocode/prompt.js.map +1 -0
- package/dist/nocode/runtime.d.ts +28 -0
- package/dist/nocode/runtime.js +113 -0
- package/dist/nocode/runtime.js.map +1 -0
- package/dist/nocode/simpleOps.d.ts +16 -0
- package/dist/nocode/simpleOps.js +137 -0
- package/dist/nocode/simpleOps.js.map +1 -0
- package/dist/nocode/types.d.ts +72 -0
- package/dist/nocode/types.js +12 -0
- package/dist/nocode/types.js.map +1 -0
- package/dist/nocode/validate.d.ts +17 -0
- package/dist/nocode/validate.js +136 -0
- package/dist/nocode/validate.js.map +1 -0
- package/dist/params/codegen.d.ts +8 -0
- package/dist/params/codegen.js +12 -0
- package/dist/params/codegen.js.map +1 -0
- package/dist/params/convert.d.ts +7 -0
- package/dist/params/convert.js +123 -0
- package/dist/params/convert.js.map +1 -0
- package/dist/params/core.d.ts +11 -0
- package/dist/params/core.js +12 -0
- package/dist/params/core.js.map +1 -0
- package/dist/params/fieldTypes.d.ts +26 -0
- package/dist/params/fieldTypes.js +29 -0
- package/dist/params/fieldTypes.js.map +1 -0
- package/dist/params/index.d.ts +3 -0
- package/dist/params/index.js +4 -0
- package/dist/params/index.js.map +1 -0
- package/dist/params/prompt.d.ts +4 -0
- package/dist/params/prompt.js +16 -0
- package/dist/params/prompt.js.map +1 -0
- package/dist/params/render.d.ts +5 -0
- package/dist/params/render.js +25 -0
- package/dist/params/render.js.map +1 -0
- package/dist/params/types.d.ts +76 -0
- package/dist/params/types.js +16 -0
- package/dist/params/types.js.map +1 -0
- package/dist/params/validate.d.ts +5 -0
- package/dist/params/validate.js +104 -0
- package/dist/params/validate.js.map +1 -0
- package/dist/resources/client.d.ts +58 -0
- package/dist/resources/client.js +79 -0
- package/dist/resources/client.js.map +1 -0
- package/dist/resources/types.d.ts +72 -0
- package/dist/resources/types.js +9 -0
- package/dist/resources/types.js.map +1 -0
- package/dist/workflow/assets.d.ts +8 -0
- package/dist/workflow/assets.js +16 -0
- package/dist/workflow/assets.js.map +1 -0
- package/dist/workflow/commands.d.ts +10 -0
- package/dist/workflow/commands.js +21 -0
- package/dist/workflow/commands.js.map +1 -0
- package/dist/workflow/core.d.ts +15 -0
- package/dist/workflow/core.js +16 -0
- package/dist/workflow/core.js.map +1 -0
- package/dist/workflow/index.d.ts +2 -0
- package/dist/workflow/index.js +3 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/stack.d.ts +11 -0
- package/dist/workflow/stack.js +40 -0
- package/dist/workflow/stack.js.map +1 -0
- package/dist/workflow/templates.d.ts +17 -0
- package/dist/workflow/templates.js +223 -0
- package/dist/workflow/templates.js.map +1 -0
- package/dist/workflow/types.d.ts +27 -0
- package/dist/workflow/types.js +2 -0
- package/dist/workflow/types.js.map +1 -0
- package/package.json +77 -0
- package/schemas/artifacts.index.json +1211 -0
- package/schemas/knowledge.index.json +49 -0
- package/schemas/prompt-modules.index.json +105 -0
- package/schemas/roles.index.json +431 -0
- package/schemas/scenarios.index.json +15 -0
- package/schemas/skills.index.json +670 -0
- package/schemas/workflows.index.json +462 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System-prompt composer for the assistant ("Buddy"). The guardrails are NOT a
|
|
3
|
+
* generic "be helpful" preamble — they are composed from the same child-centered
|
|
4
|
+
* / trauma-informed prompt modules the platform binds to every role and skill, so
|
|
5
|
+
* the assistant that helps people *build* child-welfare tools is held to the same
|
|
6
|
+
* standard as the tools themselves.
|
|
7
|
+
*
|
|
8
|
+
* Server-side (the broker calls this to seed the Anthropic system prompt). It
|
|
9
|
+
* imports the catalog taxonomy, so it is not shipped to the browser.
|
|
10
|
+
*/
|
|
11
|
+
import { CHILD_CENTERED_MODULES, TRAUMA_INFORMED_MODULES, } from "../mcp/safety.js";
|
|
12
|
+
import { PROMPT_MODULES } from "../mcp/prompt-modules.generated.js";
|
|
13
|
+
import { readingLevelDirective } from "./levels.js";
|
|
14
|
+
/**
|
|
15
|
+
* Extra directive for the "rewrite this page" intent: re-tone, never re-author. The reading-
|
|
16
|
+
* level directive still applies on top; this only constrains *what* the model does with the copy.
|
|
17
|
+
*/
|
|
18
|
+
const REWRITE_DIRECTIVE = [
|
|
19
|
+
`The user turn is the existing copy of a CoTrackPro portal page. Rewrite it for the target`,
|
|
20
|
+
`reading level above — same content, different voice. Rules:`,
|
|
21
|
+
`- Preserve the meaning EXACTLY. Do not add, drop, soften, or invent any fact, claim, step,`,
|
|
22
|
+
` link, or instruction. You are re-toning, not re-authoring.`,
|
|
23
|
+
`- Keep all safety, crisis, legal, and clinical wording intact — never water down a warning,`,
|
|
24
|
+
` a hotline, a disclaimer, or "not legal/clinical advice" language. When in doubt, keep it verbatim.`,
|
|
25
|
+
`- Keep the structure (headings, lists, links). Output ONLY the rewritten page copy — no preamble,`,
|
|
26
|
+
` no "here's the rewrite", no commentary, no new advice.`,
|
|
27
|
+
].join("\n");
|
|
28
|
+
/** One-line description for a guardrail module, from the generated catalog. */
|
|
29
|
+
function moduleLine(name) {
|
|
30
|
+
const meta = PROMPT_MODULES[name];
|
|
31
|
+
return meta ? `- ${name} (${meta.category} · ${meta.injectionPoint})` : `- ${name}`;
|
|
32
|
+
}
|
|
33
|
+
const GUARDRAIL_MODULES = [...CHILD_CENTERED_MODULES, ...TRAUMA_INFORMED_MODULES];
|
|
34
|
+
/** Build the full system prompt for one turn, grounded in the live guardrails. */
|
|
35
|
+
export function buildSystemPrompt(opts) {
|
|
36
|
+
const { tier, page, allowedTools, readingLevel, intent } = opts;
|
|
37
|
+
const guardrails = GUARDRAIL_MODULES.map(moduleLine).join("\n");
|
|
38
|
+
const levelDirective = readingLevel ? readingLevelDirective(readingLevel) : "";
|
|
39
|
+
return [
|
|
40
|
+
`You are Buddy, the building companion for the CoTrackPro developer community`,
|
|
41
|
+
`(developer.cotrackpro.com). CoTrackPro is a trauma-informed, child-centered,`,
|
|
42
|
+
`court-neutral documentation platform for families navigating high-conflict`,
|
|
43
|
+
`separation. You help people understand the community, find the right catalog`,
|
|
44
|
+
`pieces, and build on the platform — you are not the product's end-user assistant.`,
|
|
45
|
+
``,
|
|
46
|
+
`## The lens you operate under (non-negotiable)`,
|
|
47
|
+
`You model the same guardrails the platform asks builders to encode. These come`,
|
|
48
|
+
`from the platform's own prompt modules:`,
|
|
49
|
+
guardrails,
|
|
50
|
+
``,
|
|
51
|
+
`Concretely:`,
|
|
52
|
+
`- Warm, not clinical. Acknowledge effort before delivering information.`,
|
|
53
|
+
`- Never characterize a parent or person; describe behavior. Use a child's initials or a pseudonym.`,
|
|
54
|
+
`- Keep guidance court-neutral. Do not coach anyone toward an adversarial advantage.`,
|
|
55
|
+
``,
|
|
56
|
+
`## Crisis comes first, always`,
|
|
57
|
+
`If the user expresses suicidal thoughts, danger to their safety, or child-safety`,
|
|
58
|
+
`concerns, STOP and lead with these resources before anything else, and do not`,
|
|
59
|
+
`gate them behind a question: 988 (call/text), text HOME to 741741, 1-800-799-7233`,
|
|
60
|
+
`(domestic violence), 1-800-422-4453 (Childhelp), 911 for immediate danger.`,
|
|
61
|
+
``,
|
|
62
|
+
`## What you will not do`,
|
|
63
|
+
`Decline to help build surveillance, coercive-control, or "evidence-farming`,
|
|
64
|
+
`against the other parent" tooling. When a design choice affects a child, bias`,
|
|
65
|
+
`toward the child's interest and court-neutral language. Everything you produce is`,
|
|
66
|
+
`educational and informational only — not legal or clinical advice. Say so when it matters.`,
|
|
67
|
+
``,
|
|
68
|
+
`## Do not attempt (hard limits)`,
|
|
69
|
+
`You are a build copilot, not an advice service. NEVER give legal, medical, or`,
|
|
70
|
+
`mental-health ADVICE applied to someone's situation: no legal conclusions or`,
|
|
71
|
+
`jurisdiction-specific procedure, no diagnosis, no medication or dosage guidance, no`,
|
|
72
|
+
`clinical judgment. You may share GENERAL, educational information about building`,
|
|
73
|
+
`tools. If asked "should I…", "is this legal/abuse", "am I depressed", "what`,
|
|
74
|
+
`medication", and similar, decline and route to a licensed professional (and surface`,
|
|
75
|
+
`crisis resources if there's any risk of harm). Make clear the user is talking to an AI.`,
|
|
76
|
+
``,
|
|
77
|
+
`## Tools & data (RBAC tier: ${tier})`,
|
|
78
|
+
`You may ONLY use these tools this turn: ${allowedTools.join(", ") || "(none)"}.`,
|
|
79
|
+
`These are read-only educational catalog lookups unless explicitly noted. Never`,
|
|
80
|
+
`claim to access a user's personal or case data unless a tool you were given`,
|
|
81
|
+
`returns it. When you use a tool, tell the user which one ("I checked list_skills").`,
|
|
82
|
+
`If a request needs data you cannot reach at this tier, say so and point to how to`,
|
|
83
|
+
`get access (join the community / sign in) rather than guessing.`,
|
|
84
|
+
``,
|
|
85
|
+
page ? `## Context\nThe user is on the "${page}" page of the portal. Prefer next steps relevant to it.` : ``,
|
|
86
|
+
levelDirective ? `## Reading level\n${levelDirective}` : ``,
|
|
87
|
+
intent === "rewrite" ? `## Task: rewrite this page\n${REWRITE_DIRECTIVE}` : ``,
|
|
88
|
+
``,
|
|
89
|
+
intent === "rewrite"
|
|
90
|
+
? `Return only the rewritten copy.`
|
|
91
|
+
: `Be concise. Offer one clear next step. Link to portal pages when helpful.`,
|
|
92
|
+
]
|
|
93
|
+
.filter((l) => l !== undefined)
|
|
94
|
+
.join("\n");
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/assistant/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAyB,MAAM,oCAAoC,CAAC;AAE3F,OAAO,EAAE,qBAAqB,EAAqB,MAAM,aAAa,CAAC;AAmBvE;;;GAGG;AACH,MAAM,iBAAiB,GAAG;IACxB,2FAA2F;IAC3F,6DAA6D;IAC7D,4FAA4F;IAC5F,8DAA8D;IAC9D,6FAA6F;IAC7F,sGAAsG;IACtG,mGAAmG;IACnG,0DAA0D;CAC3D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,+EAA+E;AAC/E,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,IAAI,GAAG,cAAc,CAAC,IAAwB,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC,QAAQ,MAAM,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;AACtF,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,GAAG,sBAAsB,EAAE,GAAG,uBAAuB,CAAC,CAAC;AAElF,kFAAkF;AAClF,MAAM,UAAU,iBAAiB,CAAC,IAAyB;IACzD,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChE,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,MAAM,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,OAAO;QACL,8EAA8E;QAC9E,8EAA8E;QAC9E,4EAA4E;QAC5E,8EAA8E;QAC9E,mFAAmF;QACnF,EAAE;QACF,gDAAgD;QAChD,gFAAgF;QAChF,yCAAyC;QACzC,UAAU;QACV,EAAE;QACF,aAAa;QACb,yEAAyE;QACzE,oGAAoG;QACpG,qFAAqF;QACrF,EAAE;QACF,+BAA+B;QAC/B,kFAAkF;QAClF,+EAA+E;QAC/E,mFAAmF;QACnF,4EAA4E;QAC5E,EAAE;QACF,yBAAyB;QACzB,4EAA4E;QAC5E,+EAA+E;QAC/E,mFAAmF;QACnF,4FAA4F;QAC5F,EAAE;QACF,iCAAiC;QACjC,+EAA+E;QAC/E,8EAA8E;QAC9E,qFAAqF;QACrF,kFAAkF;QAClF,6EAA6E;QAC7E,qFAAqF;QACrF,yFAAyF;QACzF,EAAE;QACF,+BAA+B,IAAI,GAAG;QACtC,2CAA2C,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,GAAG;QACjF,gFAAgF;QAChF,6EAA6E;QAC7E,qFAAqF;QACrF,mFAAmF;QACnF,iEAAiE;QACjE,EAAE;QACF,IAAI,CAAC,CAAC,CAAC,mCAAmC,IAAI,yDAAyD,CAAC,CAAC,CAAC,EAAE;QAC5G,cAAc,CAAC,CAAC,CAAC,qBAAqB,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE;QAC3D,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,+BAA+B,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE;QAC9E,EAAE;QACF,MAAM,KAAK,SAAS;YAClB,CAAC,CAAC,iCAAiC;YACnC,CAAC,CAAC,2EAA2E;KAChF;SACE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;SAC9B,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RBAC for the assistant — the access decision lives HERE, not in the model's
|
|
3
|
+
* prompt. The broker resolves a caller's tier from their Clerk claims, then passes
|
|
4
|
+
* ONLY the allowlisted tool names into the Anthropic loop. Prompt-level "please
|
|
5
|
+
* don't" is not a control; this allowlist is.
|
|
6
|
+
*
|
|
7
|
+
* Dependency-free (pure data + functions) so it runs on both sides.
|
|
8
|
+
*/
|
|
9
|
+
export type AssistantTier = "anonymous" | "developer" | "builder";
|
|
10
|
+
/**
|
|
11
|
+
* Read-only, educational catalog tools (roles/skills/workflows/artifact *schemas*
|
|
12
|
+
* + worked examples). No personal/family data, no writes — safe for anonymous use.
|
|
13
|
+
* Names mirror the live MCP server (see site/data/mcp.json).
|
|
14
|
+
*/
|
|
15
|
+
export declare const PUBLIC_TOOLS: readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* A signed-in developer (Clerk + dev-org member) gets the public read set plus
|
|
18
|
+
* routing help. Sandbox proposals flow through the CLI/GitHub, not extra MCP
|
|
19
|
+
* write tools, so the tool set is the same read surface — the difference is a
|
|
20
|
+
* server-synced session (see Phase 3), not broader data access.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DEVELOPER_TOOLS: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* A builder operating on THEIR OWN case data (top tier, user-scoped token) may
|
|
25
|
+
* additionally seed/clear their own drafts. These touch personal data and are
|
|
26
|
+
* gated behind the user's own authenticated, scoped session.
|
|
27
|
+
*/
|
|
28
|
+
export declare const BUILDER_TOOLS: readonly string[];
|
|
29
|
+
/** The exact tool names a tier may invoke. Never widen this from the prompt. */
|
|
30
|
+
export declare function toolAllowlistFor(tier: AssistantTier): readonly string[];
|
|
31
|
+
/** True if a tool is reachable for the tier — the broker's per-call gate. */
|
|
32
|
+
export declare function isToolAllowed(tier: AssistantTier, tool: string): boolean;
|
|
33
|
+
/** Minimal shape of the Clerk session claims the broker inspects. */
|
|
34
|
+
export interface AssistantClaims {
|
|
35
|
+
/** The developer org id the user must belong to, to count as a developer. */
|
|
36
|
+
orgIds?: string[];
|
|
37
|
+
/** Whether the caller presented their own scoped CoTrackPro data token. */
|
|
38
|
+
hasScopedDataToken?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a tier from verified claims. Conservative by construction: no session →
|
|
42
|
+
* anonymous; dev-org member → developer; member WITH their own scoped data token →
|
|
43
|
+
* builder. Never infer "builder" from org membership alone.
|
|
44
|
+
*/
|
|
45
|
+
export declare function tierFromClaims(claims: AssistantClaims | null | undefined, developerOrgId: string): AssistantTier;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RBAC for the assistant — the access decision lives HERE, not in the model's
|
|
3
|
+
* prompt. The broker resolves a caller's tier from their Clerk claims, then passes
|
|
4
|
+
* ONLY the allowlisted tool names into the Anthropic loop. Prompt-level "please
|
|
5
|
+
* don't" is not a control; this allowlist is.
|
|
6
|
+
*
|
|
7
|
+
* Dependency-free (pure data + functions) so it runs on both sides.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Read-only, educational catalog tools (roles/skills/workflows/artifact *schemas*
|
|
11
|
+
* + worked examples). No personal/family data, no writes — safe for anonymous use.
|
|
12
|
+
* Names mirror the live MCP server (see site/data/mcp.json).
|
|
13
|
+
*/
|
|
14
|
+
export const PUBLIC_TOOLS = [
|
|
15
|
+
"get_started",
|
|
16
|
+
"find_tool_for",
|
|
17
|
+
"find_example_for",
|
|
18
|
+
"list_roles",
|
|
19
|
+
"get_role",
|
|
20
|
+
"list_skills",
|
|
21
|
+
"list_workflows",
|
|
22
|
+
"get_workflow",
|
|
23
|
+
"list_artifacts",
|
|
24
|
+
"search_artifacts",
|
|
25
|
+
"list_prompt_modules",
|
|
26
|
+
"list_scenarios",
|
|
27
|
+
"get_scenario",
|
|
28
|
+
"list_example_cases",
|
|
29
|
+
"get_example_case",
|
|
30
|
+
"get_example_artifact",
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* A signed-in developer (Clerk + dev-org member) gets the public read set plus
|
|
34
|
+
* routing help. Sandbox proposals flow through the CLI/GitHub, not extra MCP
|
|
35
|
+
* write tools, so the tool set is the same read surface — the difference is a
|
|
36
|
+
* server-synced session (see Phase 3), not broader data access.
|
|
37
|
+
*/
|
|
38
|
+
export const DEVELOPER_TOOLS = [...PUBLIC_TOOLS];
|
|
39
|
+
/**
|
|
40
|
+
* A builder operating on THEIR OWN case data (top tier, user-scoped token) may
|
|
41
|
+
* additionally seed/clear their own drafts. These touch personal data and are
|
|
42
|
+
* gated behind the user's own authenticated, scoped session.
|
|
43
|
+
*/
|
|
44
|
+
export const BUILDER_TOOLS = [
|
|
45
|
+
...DEVELOPER_TOOLS,
|
|
46
|
+
"start_from_example",
|
|
47
|
+
"delete_all_my_data",
|
|
48
|
+
];
|
|
49
|
+
const ALLOWLISTS = {
|
|
50
|
+
anonymous: PUBLIC_TOOLS,
|
|
51
|
+
developer: DEVELOPER_TOOLS,
|
|
52
|
+
builder: BUILDER_TOOLS,
|
|
53
|
+
};
|
|
54
|
+
/** The exact tool names a tier may invoke. Never widen this from the prompt. */
|
|
55
|
+
export function toolAllowlistFor(tier) {
|
|
56
|
+
return ALLOWLISTS[tier] ?? PUBLIC_TOOLS;
|
|
57
|
+
}
|
|
58
|
+
/** True if a tool is reachable for the tier — the broker's per-call gate. */
|
|
59
|
+
export function isToolAllowed(tier, tool) {
|
|
60
|
+
return toolAllowlistFor(tier).includes(tool);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve a tier from verified claims. Conservative by construction: no session →
|
|
64
|
+
* anonymous; dev-org member → developer; member WITH their own scoped data token →
|
|
65
|
+
* builder. Never infer "builder" from org membership alone.
|
|
66
|
+
*/
|
|
67
|
+
export function tierFromClaims(claims, developerOrgId) {
|
|
68
|
+
if (!claims)
|
|
69
|
+
return "anonymous";
|
|
70
|
+
const isMember = Boolean(developerOrgId) && (claims.orgIds ?? []).includes(developerOrgId);
|
|
71
|
+
if (!isMember)
|
|
72
|
+
return "anonymous";
|
|
73
|
+
return claims.hasScopedDataToken ? "builder" : "developer";
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=rbac.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac.js","sourceRoot":"","sources":["../../src/assistant/rbac.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAsB;IAC7C,aAAa;IACb,eAAe;IACf,kBAAkB;IAClB,YAAY;IACZ,UAAU;IACV,aAAa;IACb,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,kBAAkB;IAClB,qBAAqB;IACrB,gBAAgB;IAChB,cAAc;IACd,oBAAoB;IACpB,kBAAkB;IAClB,sBAAsB;CACvB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAsB,CAAC,GAAG,YAAY,CAAC,CAAC;AAEpE;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAsB;IAC9C,GAAG,eAAe;IAClB,oBAAoB;IACpB,oBAAoB;CACrB,CAAC;AAEF,MAAM,UAAU,GAA6C;IAC3D,SAAS,EAAE,YAAY;IACvB,SAAS,EAAE,eAAe;IAC1B,OAAO,EAAE,aAAa;CACvB,CAAC;AAEF,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,IAAmB;IAClD,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC;AAC1C,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,aAAa,CAAC,IAAmB,EAAE,IAAY;IAC7D,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAA0C,EAAE,cAAsB;IAC/F,IAAI,CAAC,MAAM;QAAE,OAAO,WAAW,CAAC;IAChC,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAC3F,IAAI,CAAC,QAAQ;QAAE,OAAO,WAAW,CAAC;IAClC,OAAO,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-language scoring for the portal. People reach this platform under
|
|
3
|
+
* stress — in a custody dispute, sometimes in crisis — and a broad, interdisciplinary
|
|
4
|
+
* contributor base (social work, law, design, not just engineers) needs the docs to
|
|
5
|
+
* be readable. This computes the Flesch–Kincaid grade level and Flesch reading ease
|
|
6
|
+
* so we can see, deterministically, where prose is too dense.
|
|
7
|
+
*
|
|
8
|
+
* Pure and dependency-free. Estimates (especially syllables) are heuristic — use the
|
|
9
|
+
* scores comparatively (which page is densest, did this edit help) rather than as
|
|
10
|
+
* an exact grade.
|
|
11
|
+
*/
|
|
12
|
+
export interface Readability {
|
|
13
|
+
/** Flesch–Kincaid grade level (US school grade; lower = easier). */
|
|
14
|
+
grade: number;
|
|
15
|
+
/** Flesch reading ease (0–100; higher = easier). */
|
|
16
|
+
ease: number;
|
|
17
|
+
words: number;
|
|
18
|
+
sentences: number;
|
|
19
|
+
syllables: number;
|
|
20
|
+
}
|
|
21
|
+
/** Strip Markdown to the prose a reader actually reads — drop code, tables, markup. */
|
|
22
|
+
export declare function plainTextFromMarkdown(md: string): string;
|
|
23
|
+
/** Estimate syllables in a single word (vowel-group heuristic, silent-e aware). */
|
|
24
|
+
export declare function countSyllables(word: string): number;
|
|
25
|
+
/** Score a block of prose. Pass Markdown through `plainTextFromMarkdown` first. */
|
|
26
|
+
export declare function readability(text: string): Readability;
|
|
27
|
+
/** Score a Markdown document end to end. */
|
|
28
|
+
export declare function readabilityOfMarkdown(md: string): Readability;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-language scoring for the portal. People reach this platform under
|
|
3
|
+
* stress — in a custody dispute, sometimes in crisis — and a broad, interdisciplinary
|
|
4
|
+
* contributor base (social work, law, design, not just engineers) needs the docs to
|
|
5
|
+
* be readable. This computes the Flesch–Kincaid grade level and Flesch reading ease
|
|
6
|
+
* so we can see, deterministically, where prose is too dense.
|
|
7
|
+
*
|
|
8
|
+
* Pure and dependency-free. Estimates (especially syllables) are heuristic — use the
|
|
9
|
+
* scores comparatively (which page is densest, did this edit help) rather than as
|
|
10
|
+
* an exact grade.
|
|
11
|
+
*/
|
|
12
|
+
/** Strip Markdown to the prose a reader actually reads — drop code, tables, markup. */
|
|
13
|
+
export function plainTextFromMarkdown(md) {
|
|
14
|
+
return md
|
|
15
|
+
.replace(/```[\s\S]*?```/g, " ") // fenced code blocks
|
|
16
|
+
.replace(/`[^`]*`/g, " ") // inline code
|
|
17
|
+
.replace(/^\s*\|.*\|\s*$/gm, " ") // table rows
|
|
18
|
+
.replace(/!\[[^\]]*\]\([^)]*\)/g, " ") // images
|
|
19
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") // links → link text
|
|
20
|
+
.replace(/<[^>]+>/g, " ") // inline HTML
|
|
21
|
+
.replace(/^[#>\s-]*\s*/gm, "") // heading / blockquote / list markers
|
|
22
|
+
.replace(/[*_~]+/g, "") // emphasis
|
|
23
|
+
.replace(/&[a-z]+;/gi, " ") // html entities
|
|
24
|
+
.replace(/\s+/g, " ")
|
|
25
|
+
.trim();
|
|
26
|
+
}
|
|
27
|
+
/** Estimate syllables in a single word (vowel-group heuristic, silent-e aware). */
|
|
28
|
+
export function countSyllables(word) {
|
|
29
|
+
const w = word.toLowerCase().replace(/[^a-z]/g, "");
|
|
30
|
+
if (!w)
|
|
31
|
+
return 0;
|
|
32
|
+
if (w.length <= 3)
|
|
33
|
+
return 1;
|
|
34
|
+
const groups = w
|
|
35
|
+
.replace(/(?:[^laeiouy]|ed|es|e)\b/g, "") // drop trailing silent e/es/ed
|
|
36
|
+
.replace(/^y/, "")
|
|
37
|
+
.match(/[aeiouy]{1,2}/g);
|
|
38
|
+
return Math.max(1, groups ? groups.length : 1);
|
|
39
|
+
}
|
|
40
|
+
function countSentences(text) {
|
|
41
|
+
const m = text.match(/[.!?]+(?:\s|$)/g);
|
|
42
|
+
// Fall back to 1 so a heading-only fragment doesn't divide by zero.
|
|
43
|
+
return Math.max(1, m ? m.length : 1);
|
|
44
|
+
}
|
|
45
|
+
function words(text) {
|
|
46
|
+
return text.split(/\s+/).filter((t) => /[a-z0-9]/i.test(t));
|
|
47
|
+
}
|
|
48
|
+
/** Score a block of prose. Pass Markdown through `plainTextFromMarkdown` first. */
|
|
49
|
+
export function readability(text) {
|
|
50
|
+
const ws = words(text);
|
|
51
|
+
const wordCount = Math.max(1, ws.length);
|
|
52
|
+
const sentences = countSentences(text);
|
|
53
|
+
const syllables = ws.reduce((n, w) => n + countSyllables(w), 0);
|
|
54
|
+
const wps = wordCount / sentences;
|
|
55
|
+
const spw = syllables / wordCount;
|
|
56
|
+
const grade = 0.39 * wps + 11.8 * spw - 15.59;
|
|
57
|
+
const ease = 206.835 - 1.015 * wps - 84.6 * spw;
|
|
58
|
+
return {
|
|
59
|
+
grade: Math.round(grade * 10) / 10,
|
|
60
|
+
ease: Math.round(ease * 10) / 10,
|
|
61
|
+
words: ws.length,
|
|
62
|
+
sentences,
|
|
63
|
+
syllables,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Score a Markdown document end to end. */
|
|
67
|
+
export function readabilityOfMarkdown(md) {
|
|
68
|
+
return readability(plainTextFromMarkdown(md));
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=readability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readability.js","sourceRoot":"","sources":["../../src/assistant/readability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type AuthProvider } from "./provider.js";
|
|
2
|
+
import { type CotrackproClient } from "../resources/client.js";
|
|
3
|
+
/** The env var contract the CLI sets when it brokers gated access to a child
|
|
4
|
+
* process (see cotrackpro-cli `src/lib/pluginRunner.ts` and `cotrackpro token`). */
|
|
5
|
+
export declare const BROKER_ENV: {
|
|
6
|
+
readonly token: "COTRACKPRO_PLUGIN_TOKEN";
|
|
7
|
+
readonly scopes: "COTRACKPRO_PLUGIN_SCOPES";
|
|
8
|
+
readonly api: "COTRACKPRO_API";
|
|
9
|
+
readonly org: "COTRACKPRO_ORG";
|
|
10
|
+
};
|
|
11
|
+
export type BrokerEnv = Record<string, string | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves a token from the **CLI-brokered environment** — never from a keychain
|
|
14
|
+
* or credential store. The CoTrackPro CLI is the single gatekeeper: it mints a
|
|
15
|
+
* short-lived, RBAC-scoped token and injects `COTRACKPRO_PLUGIN_TOKEN`. A
|
|
16
|
+
* developer package (in any repo) or an Antigravity agent uses this provider to
|
|
17
|
+
* retrieve gated information with least-privilege access and **zero credentials**.
|
|
18
|
+
*/
|
|
19
|
+
export declare class CliBrokerProvider implements AuthProvider {
|
|
20
|
+
private readonly env;
|
|
21
|
+
constructor(env?: BrokerEnv);
|
|
22
|
+
getToken(): Promise<string | null>;
|
|
23
|
+
}
|
|
24
|
+
/** The scopes the CLI granted this brokered session, if any. */
|
|
25
|
+
export declare function brokerScopes(env?: BrokerEnv): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Build a fully-configured client from the brokered environment — base URL, org,
|
|
28
|
+
* and the brokered token. The one-liner a gated developer package needs:
|
|
29
|
+
* const cp = clientFromBrokerEnv();
|
|
30
|
+
* const pkgs = await cp.packages.list();
|
|
31
|
+
*/
|
|
32
|
+
export declare function clientFromBrokerEnv(env?: BrokerEnv): CotrackproClient;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createClient } from "../resources/client.js";
|
|
2
|
+
import { DEFAULT_BASE_URL } from "../core/config.js";
|
|
3
|
+
/** The env var contract the CLI sets when it brokers gated access to a child
|
|
4
|
+
* process (see cotrackpro-cli `src/lib/pluginRunner.ts` and `cotrackpro token`). */
|
|
5
|
+
export const BROKER_ENV = {
|
|
6
|
+
token: "COTRACKPRO_PLUGIN_TOKEN",
|
|
7
|
+
scopes: "COTRACKPRO_PLUGIN_SCOPES",
|
|
8
|
+
api: "COTRACKPRO_API",
|
|
9
|
+
org: "COTRACKPRO_ORG",
|
|
10
|
+
};
|
|
11
|
+
function defaultEnv() {
|
|
12
|
+
return globalThis.process?.env ?? {};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolves a token from the **CLI-brokered environment** — never from a keychain
|
|
16
|
+
* or credential store. The CoTrackPro CLI is the single gatekeeper: it mints a
|
|
17
|
+
* short-lived, RBAC-scoped token and injects `COTRACKPRO_PLUGIN_TOKEN`. A
|
|
18
|
+
* developer package (in any repo) or an Antigravity agent uses this provider to
|
|
19
|
+
* retrieve gated information with least-privilege access and **zero credentials**.
|
|
20
|
+
*/
|
|
21
|
+
export class CliBrokerProvider {
|
|
22
|
+
env;
|
|
23
|
+
constructor(env = defaultEnv()) {
|
|
24
|
+
this.env = env;
|
|
25
|
+
}
|
|
26
|
+
async getToken() {
|
|
27
|
+
return this.env[BROKER_ENV.token] ?? null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** The scopes the CLI granted this brokered session, if any. */
|
|
31
|
+
export function brokerScopes(env = defaultEnv()) {
|
|
32
|
+
const raw = env[BROKER_ENV.scopes];
|
|
33
|
+
return raw ? raw.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build a fully-configured client from the brokered environment — base URL, org,
|
|
37
|
+
* and the brokered token. The one-liner a gated developer package needs:
|
|
38
|
+
* const cp = clientFromBrokerEnv();
|
|
39
|
+
* const pkgs = await cp.packages.list();
|
|
40
|
+
*/
|
|
41
|
+
export function clientFromBrokerEnv(env = defaultEnv()) {
|
|
42
|
+
return createClient({
|
|
43
|
+
baseUrl: env[BROKER_ENV.api] ?? DEFAULT_BASE_URL,
|
|
44
|
+
org: env[BROKER_ENV.org] ?? null,
|
|
45
|
+
auth: new CliBrokerProvider(env),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=broker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker.js","sourceRoot":"","sources":["../../src/auth/broker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAyB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD;qFACqF;AACrF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,KAAK,EAAE,yBAAyB;IAChC,MAAM,EAAE,0BAA0B;IAClC,GAAG,EAAE,gBAAgB;IACrB,GAAG,EAAE,gBAAgB;CACb,CAAC;AAIX,SAAS,UAAU;IACjB,OAAQ,UAAgD,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,iBAAiB;IACX,GAAG,CAAY;IAChC,YAAY,MAAiB,UAAU,EAAE;QACvC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IACD,KAAK,CAAC,QAAQ;QACZ,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;IAC5C,CAAC;CACF;AAED,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAAC,MAAiB,UAAU,EAAE;IACxD,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAiB,UAAU,EAAE;IAC/D,OAAO,YAAY,CAAC;QAClB,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,gBAAgB;QAChD,GAAG,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI;QAChC,IAAI,EAAE,IAAI,iBAAiB,CAAC,GAAG,CAAC;KACjC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AuthProvider } from "./provider.js";
|
|
2
|
+
import type { CotrackproClient } from "../resources/client.js";
|
|
3
|
+
export interface DeviceFlowHooks {
|
|
4
|
+
/** Called once with the URL + code the user must visit/enter. */
|
|
5
|
+
onPrompt(info: {
|
|
6
|
+
verificationUrl: string;
|
|
7
|
+
deviceCode: string;
|
|
8
|
+
expiresInSec: number;
|
|
9
|
+
}): void | Promise<void>;
|
|
10
|
+
/** Optional: return a previously-saved token to skip the flow. */
|
|
11
|
+
load?(): string | null | Promise<string | null>;
|
|
12
|
+
/** Optional: persist the token once the flow completes. */
|
|
13
|
+
persist?(token: string, account?: string): void | Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Browser device-flow auth provider for hosts that can show a prompt (CLI,
|
|
17
|
+
* desktop, IDE agents). The HTTP lives in the SDK; persistence/prompting is
|
|
18
|
+
* delegated to the host via {@link DeviceFlowHooks}, so the SDK stays free of
|
|
19
|
+
* keychain/UI assumptions.
|
|
20
|
+
*/
|
|
21
|
+
export declare class DeviceFlowProvider implements AuthProvider {
|
|
22
|
+
private readonly client;
|
|
23
|
+
private readonly hooks;
|
|
24
|
+
constructor(client: CotrackproClient, hooks: DeviceFlowHooks);
|
|
25
|
+
getToken(): Promise<string | null>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { CotrackproError } from "../core/errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Is this a transient failure worth another poll (network blip, timeout, 5xx) —
|
|
4
|
+
* as opposed to a terminal one (a bad/expired device code, or any other 4xx)
|
|
5
|
+
* that means the sign-in genuinely can't complete?
|
|
6
|
+
*/
|
|
7
|
+
function isTransientPollError(e) {
|
|
8
|
+
if (!(e instanceof CotrackproError))
|
|
9
|
+
return false;
|
|
10
|
+
return e.code === "network" || (e.status !== undefined && e.status >= 500);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Browser device-flow auth provider for hosts that can show a prompt (CLI,
|
|
14
|
+
* desktop, IDE agents). The HTTP lives in the SDK; persistence/prompting is
|
|
15
|
+
* delegated to the host via {@link DeviceFlowHooks}, so the SDK stays free of
|
|
16
|
+
* keychain/UI assumptions.
|
|
17
|
+
*/
|
|
18
|
+
export class DeviceFlowProvider {
|
|
19
|
+
client;
|
|
20
|
+
hooks;
|
|
21
|
+
constructor(client, hooks) {
|
|
22
|
+
this.client = client;
|
|
23
|
+
this.hooks = hooks;
|
|
24
|
+
}
|
|
25
|
+
async getToken() {
|
|
26
|
+
const existing = this.hooks.load ? await this.hooks.load() : null;
|
|
27
|
+
if (existing)
|
|
28
|
+
return existing;
|
|
29
|
+
const start = await this.client.authEndpoints.deviceStart();
|
|
30
|
+
await this.hooks.onPrompt({
|
|
31
|
+
verificationUrl: start.verificationUrl,
|
|
32
|
+
deviceCode: start.deviceCode,
|
|
33
|
+
expiresInSec: start.expiresInSec,
|
|
34
|
+
});
|
|
35
|
+
const deadline = Date.now() + start.expiresInSec * 1000;
|
|
36
|
+
while (Date.now() < deadline) {
|
|
37
|
+
await delay(start.intervalSec * 1000);
|
|
38
|
+
let poll;
|
|
39
|
+
try {
|
|
40
|
+
poll = await this.client.authEndpoints.devicePoll(start.deviceCode);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
// A single transient hiccup (network blip, timeout, 5xx) during the wait
|
|
44
|
+
// must not abort a sign-in the user may still be completing — keep polling
|
|
45
|
+
// until the deadline. A terminal error (bad/expired code, 4xx) is real.
|
|
46
|
+
if (isTransientPollError(e))
|
|
47
|
+
continue;
|
|
48
|
+
throw e;
|
|
49
|
+
}
|
|
50
|
+
if (poll.status === "complete" && poll.token) {
|
|
51
|
+
if (this.hooks.persist)
|
|
52
|
+
await this.hooks.persist(poll.token, poll.account);
|
|
53
|
+
return poll.token;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw new CotrackproError({
|
|
57
|
+
code: "unauthenticated",
|
|
58
|
+
message: "Login timed out. Try signing in again.",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function delay(ms) {
|
|
63
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=deviceFlow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deviceFlow.js","sourceRoot":"","sources":["../../src/auth/deviceFlow.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,CAAU;IACtC,IAAI,CAAC,CAAC,CAAC,YAAY,eAAe,CAAC;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;AAC7E,CAAC;AAWD;;;;;GAKG;AACH,MAAM,OAAO,kBAAkB;IAEV;IACA;IAFnB,YACmB,MAAwB,EACxB,KAAsB;QADtB,WAAM,GAAN,MAAM,CAAkB;QACxB,UAAK,GAAL,KAAK,CAAiB;IACtC,CAAC;IAEJ,KAAK,CAAC,QAAQ;QACZ,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAClE,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC;QAC5D,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;YACxB,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;QACxD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,MAAM,KAAK,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;YACtC,IAAI,IAAgB,CAAC;YACrB,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACtE,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,yEAAyE;gBACzE,2EAA2E;gBAC3E,wEAAwE;gBACxE,IAAI,oBAAoB,CAAC,CAAC,CAAC;oBAAE,SAAS;gBACtC,MAAM,CAAC,CAAC;YACV,CAAC;YACD,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC7C,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO;oBAAE,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC,KAAK,CAAC;YACpB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,eAAe,CAAC;YACxB,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,wCAAwC;SAClD,CAAC,CAAC;IACL,CAAC;CACF;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable authentication. The SDK never assumes *how* a token is obtained —
|
|
3
|
+
* it only asks an `AuthProvider` for one. This is what lets a single SDK serve
|
|
4
|
+
* both internal contributors and external/3rd-party developers:
|
|
5
|
+
*
|
|
6
|
+
* - `StaticTokenProvider` → API keys / env tokens (CI, agents, Antigravity)
|
|
7
|
+
* - `CallbackTokenProvider` → read from a keychain/credential store (the CLI)
|
|
8
|
+
* - `DeviceFlowProvider` → browser device-flow sign-in (see ./deviceFlow)
|
|
9
|
+
* - `AnonymousProvider` → unauthenticated endpoints (health, device start)
|
|
10
|
+
*/
|
|
11
|
+
export interface AuthProvider {
|
|
12
|
+
/** Resolve a bearer token, or null when no credential is available. */
|
|
13
|
+
getToken(): Promise<string | null>;
|
|
14
|
+
}
|
|
15
|
+
export declare class AnonymousProvider implements AuthProvider {
|
|
16
|
+
getToken(): Promise<string | null>;
|
|
17
|
+
}
|
|
18
|
+
export declare class StaticTokenProvider implements AuthProvider {
|
|
19
|
+
private readonly token;
|
|
20
|
+
constructor(token: string);
|
|
21
|
+
getToken(): Promise<string | null>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolves the token lazily via a host-supplied callback. The CLI uses this to
|
|
25
|
+
* read from its OS keychain on every request without the SDK knowing about
|
|
26
|
+
* keychains at all.
|
|
27
|
+
*/
|
|
28
|
+
export declare class CallbackTokenProvider implements AuthProvider {
|
|
29
|
+
private readonly fn;
|
|
30
|
+
constructor(fn: () => string | null | Promise<string | null>);
|
|
31
|
+
getToken(): Promise<string | null>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export class AnonymousProvider {
|
|
2
|
+
async getToken() {
|
|
3
|
+
return null;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
export class StaticTokenProvider {
|
|
7
|
+
token;
|
|
8
|
+
constructor(token) {
|
|
9
|
+
this.token = token;
|
|
10
|
+
}
|
|
11
|
+
async getToken() {
|
|
12
|
+
return this.token;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the token lazily via a host-supplied callback. The CLI uses this to
|
|
17
|
+
* read from its OS keychain on every request without the SDK knowing about
|
|
18
|
+
* keychains at all.
|
|
19
|
+
*/
|
|
20
|
+
export class CallbackTokenProvider {
|
|
21
|
+
fn;
|
|
22
|
+
constructor(fn) {
|
|
23
|
+
this.fn = fn;
|
|
24
|
+
}
|
|
25
|
+
async getToken() {
|
|
26
|
+
return this.fn();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/auth/provider.ts"],"names":[],"mappings":"AAeA,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,QAAQ;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,OAAO,mBAAmB;IACD;IAA7B,YAA6B,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;IAAG,CAAC;IAC9C,KAAK,CAAC,QAAQ;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,qBAAqB;IACH;IAA7B,YAA6B,EAAgD;QAAhD,OAAE,GAAF,EAAE,CAA8C;IAAG,CAAC;IACjF,KAAK,CAAC,QAAQ;QACZ,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Badges — named achievements the community celebrates, tied to XP events.
|
|
3
|
+
* Recognition only (see events.ts); badges never grant scopes or tiers.
|
|
4
|
+
*/
|
|
5
|
+
import type { XpEventId } from "./events.js";
|
|
6
|
+
export type BadgeId = "first-light" | "publisher" | "shipwright" | "contributor" | "mentor" | "showcased" | "connector";
|
|
7
|
+
export interface Badge {
|
|
8
|
+
id: BadgeId;
|
|
9
|
+
label: string;
|
|
10
|
+
description: string;
|
|
11
|
+
/** The XP event(s) that earn it. */
|
|
12
|
+
events: XpEventId[];
|
|
13
|
+
/** How many times the event(s) must occur (default 1). */
|
|
14
|
+
threshold: number;
|
|
15
|
+
}
|
|
16
|
+
export declare const BADGE_IDS: BadgeId[];
|
|
17
|
+
export declare const BADGES: Record<BadgeId, Badge>;
|
|
18
|
+
/** Which badges a known set of event counts has earned (recognition only). */
|
|
19
|
+
export declare function earnedBadges(counts: Partial<Record<XpEventId, number>>): BadgeId[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const BADGE_IDS = ["first-light", "publisher", "shipwright", "contributor", "mentor", "showcased", "connector"];
|
|
2
|
+
export const BADGES = {
|
|
3
|
+
"first-light": { id: "first-light", label: "First Light", description: "Set up the CLI and made your first authenticated call.", events: ["first-setup"], threshold: 1 },
|
|
4
|
+
publisher: { id: "publisher", label: "Publisher", description: "Published your first package to your org.", events: ["publish-package"], threshold: 1 },
|
|
5
|
+
shipwright: { id: "shipwright", label: "Shipwright", description: "Shipped a working module from a blueprint.", events: ["ship-project"], threshold: 1 },
|
|
6
|
+
contributor: { id: "contributor", label: "Contributor", description: "Had a pull request merged into the ecosystem.", events: ["merge-pr"], threshold: 1 },
|
|
7
|
+
mentor: { id: "mentor", label: "Mentor", description: "Answered ten community questions.", events: ["answer-help"], threshold: 10 },
|
|
8
|
+
showcased: { id: "showcased", label: "Showcased", description: "Added a tool to the community Showcase.", events: ["submit-showcase"], threshold: 1 },
|
|
9
|
+
connector: { id: "connector", label: "Connector", description: "Referred someone who joined the community.", events: ["invite-accepted"], threshold: 1 },
|
|
10
|
+
};
|
|
11
|
+
/** Which badges a known set of event counts has earned (recognition only). */
|
|
12
|
+
export function earnedBadges(counts) {
|
|
13
|
+
return BADGE_IDS.filter((id) => {
|
|
14
|
+
const b = BADGES[id];
|
|
15
|
+
const total = b.events.reduce((sum, e) => sum + (counts[e] ?? 0), 0);
|
|
16
|
+
return total >= b.threshold;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=badges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badges.js","sourceRoot":"","sources":["../../src/community/badges.ts"],"names":[],"mappings":"AAyBA,MAAM,CAAC,MAAM,SAAS,GAAc,CAAC,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AAElI,MAAM,CAAC,MAAM,MAAM,GAA2B;IAC5C,aAAa,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,wDAAwD,EAAE,MAAM,EAAE,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;IACxK,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,2CAA2C,EAAE,MAAM,EAAE,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;IACvJ,UAAU,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,4CAA4C,EAAE,MAAM,EAAE,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;IACxJ,WAAW,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,+CAA+C,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;IAC1J,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,mCAAmC,EAAE,MAAM,EAAE,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;IACnI,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,yCAAyC,EAAE,MAAM,EAAE,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;IACrJ,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,4CAA4C,EAAE,MAAM,EAAE,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;CACzJ,CAAC;AAEF,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,MAA0C;IACrE,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE;QAC7B,MAAM,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACrB,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrE,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC"}
|