@alvera-ai/platform-sdk 0.10.0-rc.8 → 0.11.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.
Files changed (66) hide show
  1. package/.agent/AGENTS.md +499 -0
  2. package/.agent/account_management.md +456 -0
  3. package/.agent/action_status_updaters.md +264 -0
  4. package/.agent/ai_agents.md +462 -0
  5. package/.agent/ai_sandbox.md +265 -0
  6. package/.agent/async.md +112 -0
  7. package/.agent/connected_apps.md +408 -0
  8. package/.agent/cookbook/_fixtures/README.md +106 -0
  9. package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_customer.liquid +32 -0
  10. package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_mdm.liquid +20 -0
  11. package/.agent/cookbook/_fixtures/accounts_receivable/stripe_customers_batch1.csv +5 -0
  12. package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_generic_table.liquid +33 -0
  13. package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid +88 -0
  14. package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_mdm.liquid +48 -0
  15. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid +47 -0
  16. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_mdm.liquid +24 -0
  17. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_patient.liquid +38 -0
  18. package/.agent/cookbook/_fixtures/healthcare/memorandum-of-association-01.png +0 -0
  19. package/.agent/cookbook/_fixtures/healthcare/sample_two_page.pdf +43 -0
  20. package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_compliance_screening.liquid +59 -0
  21. package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_mdm.liquid +36 -0
  22. package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_mdm.liquid +30 -0
  23. package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_payment_account.liquid +55 -0
  24. package/.agent/cookbook/_setup/accounts_receivable.md +282 -0
  25. package/.agent/cookbook/_setup/foundation.md +277 -0
  26. package/.agent/cookbook/_setup/healthcare.md +279 -0
  27. package/.agent/cookbook/_setup/payment_risk.md +283 -0
  28. package/.agent/cookbook/action-status-updaters.md +212 -0
  29. package/.agent/cookbook/ai-agent-invoke.md +243 -0
  30. package/.agent/cookbook/appointment-review-sms-workflow.md +761 -0
  31. package/.agent/cookbook/birthday-greeting-sms-trigger.md +656 -0
  32. package/.agent/cookbook/bulk-ingest.md +254 -0
  33. package/.agent/cookbook/contact-us-triage-with-llm.md +622 -0
  34. package/.agent/cookbook/custom-tables.md +201 -0
  35. package/.agent/cookbook/dunning-sms-for-delinquent.md +619 -0
  36. package/.agent/cookbook/invite-team.md +194 -0
  37. package/.agent/cookbook/kyc-notification-on-account-activation.md +619 -0
  38. package/.agent/cookbook/rest-fetch.md +246 -0
  39. package/.agent/cookbook/sanctions-screening-with-agent-review.md +733 -0
  40. package/.agent/cookbook/score-leads-with-llm-categorization.md +624 -0
  41. package/.agent/cookbook/system-templates.md +129 -0
  42. package/.agent/cookbook/triage-prospects-by-priority.md +533 -0
  43. package/.agent/cookbook/welcome-sms-for-customers.md +607 -0
  44. package/.agent/data_activation_clients.md +559 -0
  45. package/.agent/data_sources.md +235 -0
  46. package/.agent/datalakes.md +714 -0
  47. package/.agent/debugging.md +137 -0
  48. package/.agent/errors.md +190 -0
  49. package/.agent/generic_tables.md +351 -0
  50. package/.agent/interoperability_contracts.md +417 -0
  51. package/.agent/mdm.md +293 -0
  52. package/.agent/mutations.md +126 -0
  53. package/.agent/templates.md +98 -0
  54. package/.agent/tool-call-configs.md +90 -0
  55. package/.agent/tools.md +547 -0
  56. package/.agent/type_naming.md +129 -0
  57. package/.agent/workflows.md +617 -0
  58. package/README.md +178 -0
  59. package/dist/bin/platform-sdk.d.mts +1 -0
  60. package/dist/bin/platform-sdk.mjs +106 -0
  61. package/dist/bin/platform-sdk.mjs.map +1 -0
  62. package/dist/index.d.mts +1310 -44116
  63. package/dist/index.d.mts.map +1 -1
  64. package/dist/index.mjs +1194 -7344
  65. package/dist/index.mjs.map +1 -1
  66. package/package.json +19 -10
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # `@alvera-ai/platform-sdk`
2
+
3
+ Typed TypeScript SDK for the Alvera platform API — manage datalakes, data
4
+ sources, tools, AI agents, interoperability contracts, data activation clients,
5
+ workflows, and more, all from a single typed client.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @alvera-ai/platform-sdk
11
+ # or: pnpm add / bun add / yarn add @alvera-ai/platform-sdk
12
+ ```
13
+
14
+ ## Quick start
15
+
16
+ Authentication is two steps — mint a session, then build a typed client:
17
+
18
+ ```ts
19
+ import {
20
+ createSession,
21
+ createIsolatedPlatformApi,
22
+ type PlatformApi,
23
+ } from '@alvera-ai/platform-sdk'
24
+
25
+ // 1. mint a session (pass tenantSlug to scope it to a tenant)
26
+ const session = await createSession({
27
+ baseUrl: 'https://api.alvera.ai',
28
+ email,
29
+ password,
30
+ tenantSlug,
31
+ })
32
+
33
+ // 2. build a typed client
34
+ const api: PlatformApi = createIsolatedPlatformApi({
35
+ baseUrl: 'https://api.alvera.ai',
36
+ sessionToken: session.sessionToken,
37
+ })
38
+
39
+ // 3. call resources — every nested resource is tenant + datalake scoped
40
+ const { data: datalake } = await api.datalakes.create(tenantSlug, {
41
+ name: 'Production Lake',
42
+ data_domain: 'accounts_receivable',
43
+ // …database + storage credentials…
44
+ })
45
+
46
+ const { data, meta } = await api.tools.list(tenantSlug, datalake.slug)
47
+ ```
48
+
49
+ ### Session scopes
50
+
51
+ `createSession` mints one of three scopes:
52
+
53
+ - **root** — Alvera root admin (user signup + confirmation).
54
+ - **tenantless** — an authenticated user with no tenant yet; used once to create
55
+ a tenant, or to accept an invitation. Omit `tenantSlug`.
56
+ - **tenant-scoped** — the canonical bearer for tenant operations. Pass
57
+ `tenantSlug`.
58
+
59
+ Holding more than one client in the same process (e.g. a test or an app serving
60
+ multiple users)? Use `createIsolatedPlatformApi` — it builds a fresh, private
61
+ client. `createPlatformApi` mutates a shared singleton and is only safe for a
62
+ single bearer.
63
+
64
+ ### A few things to know
65
+
66
+ - **`update()` replaces the whole resource** — there is no partial update; send
67
+ the full body.
68
+ - **List endpoints return `{ data, meta }`** — destructure, don't iterate the
69
+ response directly.
70
+ - **Slugs are server-derived** — read `slug` off a `create()` response; never
71
+ pre-compute it.
72
+ - **The SDK validates nothing client-side** — a bad body comes back as a thrown
73
+ `422 AlveraApiError` with a `source.pointer` to the offending field.
74
+
75
+ ## TypeScript configuration
76
+
77
+ The SDK uses [`@hey-api/client-fetch`](https://heyapi.dev/openapi-ts/clients/fetch),
78
+ whose generated code references WHATWG fetch types — `BodyInit`, `RequestInit`,
79
+ `Headers`, `FormData`, etc. Those names live in `lib.dom.d.ts`, not
80
+ `@types/node`, so a Node-only consumer with `"lib": ["ES2022"]` in its
81
+ `tsconfig.json` will see errors like `Cannot find name 'BodyInit'` when
82
+ typechecking.
83
+
84
+ The fix is to add `DOM` and `DOM.Iterable` to your `lib`:
85
+
86
+ ```jsonc
87
+ // tsconfig.json
88
+ {
89
+ "compilerOptions": {
90
+ "lib": ["ES2022", "DOM", "DOM.Iterable"]
91
+ // ^^^^^^^^^^^^^^^^^^^^^^^
92
+ // Required by @hey-api/client-fetch — see hey-api/openapi-ts#2539.
93
+ // Type-only: adds NOTHING to the runtime — Node 18+ provides real
94
+ // fetch independently of these declarations.
95
+ }
96
+ }
97
+ ```
98
+
99
+ This is the workaround for hey-api's open issue
100
+ [#2539](https://github.com/hey-api/openapi-ts/issues/2539); drop the `DOM`
101
+ entries again once the upstream fix emits self-contained types. Browser
102
+ consumers (React, Vue, Next, Nuxt, Remix) already enable `DOM` /
103
+ `DOM.Iterable` by default — no change needed.
104
+
105
+ ## Environments
106
+
107
+ Base URLs ship with the package, derived at build time from the `servers[]`
108
+ block of the committed OpenAPI spec and exported as `ENVIRONMENTS`:
109
+
110
+ ```ts
111
+ import { ENVIRONMENTS, DEFAULT_ENVIRONMENT } from '@alvera-ai/platform-sdk'
112
+
113
+ ENVIRONMENTS.local.base_url // http://localhost:4000
114
+ ENVIRONMENTS.demo.base_url // https://platform-hh.alvera.ai
115
+ ENVIRONMENTS.prod.base_url // https://app.alvera.ai
116
+
117
+ DEFAULT_ENVIRONMENT // 'prod'
118
+ ```
119
+
120
+ Pass the chosen `base_url` into `createSession` and `createIsolatedPlatformApi`.
121
+
122
+ ## Resources
123
+
124
+ Every resource is a typed namespace on the client (`api.<resource>.<verb>`):
125
+
126
+ | Resource | Operations |
127
+ |------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
128
+ | `ping` | health check |
129
+ | `sessions` | `verify` |
130
+ | `auth` | `signUp` |
131
+ | `admin` | `confirmUser` |
132
+ | `tenants` | `list`, `create` |
133
+ | `invitations` | `list`, `create`, `accept` |
134
+ | `datasets` | `search`, `metadata`, `createUserSearch` |
135
+ | `datalakes` | `list`, `get`, `create`, `metadata`, `migrate`, `createUploadLink`, `createDownloadLink` |
136
+ | `dataSources` | `list`, `create`, `update` |
137
+ | `tools` | `list`, `get`, `create`, `update`, `delete`, `testInvocation` |
138
+ | `genericTables` | `list`, `create` |
139
+ | `actionStatusUpdaters` | `list`, `create`, `update` |
140
+ | `aiAgents` | `list`, `get`, `create`, `update`, `delete`, `invoke` |
141
+ | `connectedApps` | `list`, `get`, `create`, `update`, `syncRoutes`, `resolvePage`, `updateMessageTracking` |
142
+ | `dataActivationClients` | `list`, `get`, `create`, `update`, `delete`, `metadata`, `runManually`, `ingest`, `ingestFile`, `logs.list`, `logs.get` |
143
+ | `interoperabilityContracts` | `list`, `get`, `create`, `update`, `delete`, `metadata`, `run` |
144
+ | `mdm` | `verify` |
145
+ | `workflows` | `list`, `get`, `create`, `update`, `delete`, `metadata`, `execute`, `run`, `workflowLogs.list/get/download`, `batchLogs.list/get/start/stop/refresh` |
146
+
147
+ Tenant and datalake provisioning are performed by Alvera admins — contact your
148
+ representative to onboard a new tenant.
149
+
150
+ ## For coding agents
151
+
152
+ This package ships an **agent-docs corpus** under `.agent/` — it lands at
153
+ `node_modules/@alvera-ai/platform-sdk/.agent/` after install, and an agent that
154
+ walks `node_modules` discovers it automatically. It is self-sufficient for
155
+ building an app or a test suite against the SDK:
156
+
157
+ - [`.agent/AGENTS.md`](./.agent/AGENTS.md) — the index + per-resource reference.
158
+ - [`.agent/cookbook/`](./.agent/cookbook/) — validated, runnable recipes:
159
+ business cookbooks (one outcome each) and capability docs (one capability
160
+ each, e.g. `bulk-ingest`, `ai-agent-invoke`, `custom-tables`, `invite-team`).
161
+
162
+ To wire a pointer to the corpus into your own project's `AGENTS.md` (and a
163
+ `@AGENTS.md` import into `CLAUDE.md`), run — no global install needed:
164
+
165
+ ```sh
166
+ npx @alvera-ai/platform-sdk llm-export
167
+ ```
168
+
169
+ It writes an idempotent managed block; re-running replaces only that block.
170
+
171
+ ## Documentation
172
+
173
+ - [`.agent/`](./.agent/AGENTS.md) — consumer reference + cookbooks (ships in the package)
174
+ - [`docs/sdk-architecture.md`](../../docs/sdk-architecture.md) — the SDK's design
175
+
176
+ ## License
177
+
178
+ Elastic-2.0
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ //#region src/llm-export.ts
6
+ const MARKER_BEGIN = "<!-- @alvera-ai/platform-sdk:BEGIN -->";
7
+ const MARKER_END = "<!-- @alvera-ai/platform-sdk:END -->";
8
+ const CLAUDE_IMPORT_LINE = "@AGENTS.md";
9
+ const SDK_PACKAGE_NAME = "@alvera-ai/platform-sdk";
10
+ function buildManagedBlock() {
11
+ const corpus = `node_modules/${SDK_PACKAGE_NAME}/.agent`;
12
+ return [
13
+ MARKER_BEGIN,
14
+ "",
15
+ "<!-- Managed by `alvera llm-export` — do not edit by hand. -->",
16
+ "<!-- Re-running the command replaces only this block. -->",
17
+ "",
18
+ `## \`${SDK_PACKAGE_NAME}\` corpus`,
19
+ "",
20
+ "The SDK ships an agent-docs corpus next to its npm install. Read the",
21
+ "corpus index first (Claude Code inlines this import):",
22
+ "",
23
+ `@${corpus}/AGENTS.md`,
24
+ "",
25
+ `Cookbook recipes live under \`${corpus}/cookbook/\`.`,
26
+ "",
27
+ "### Top-3 consumer gotchas",
28
+ "",
29
+ "1. **`update()` replaces the whole resource.** There is no partial",
30
+ ` update — resupply the full body. See \`${corpus}/mutations.md\`.`,
31
+ "2. **Paginated catalogs return `{ data, meta }`.** Catalog endpoints",
32
+ " (`tools.list`, `dataSources.list`, etc.) wrap rows in `data` with a",
33
+ " `meta` envelope — destructure, do not iterate the response directly.",
34
+ "3. **Resources are datalake-slug-scoped.** Every nested URL takes both",
35
+ " `tenantSlug` and `datalakeSlug` — never a single slug. The datalake",
36
+ " slug comes from the server (`api.datalakes.create`'s response).",
37
+ "",
38
+ MARKER_END
39
+ ].join("\n");
40
+ }
41
+ function upsertManagedBlock(target, block) {
42
+ const beginIdx = target.indexOf(MARKER_BEGIN);
43
+ const endIdx = target.indexOf(MARKER_END);
44
+ if (beginIdx === -1 && endIdx === -1) return target + (target.length === 0 ? "" : target.endsWith("\n\n") ? "" : target.endsWith("\n") ? "\n" : "\n\n") + block + "\n";
45
+ if (beginIdx === -1 || endIdx === -1 || endIdx < beginIdx) throw new Error(`AGENTS.md: managed-block markers are damaged (BEGIN at ${beginIdx}, END at ${endIdx}). Fix by hand or remove both markers, then re-run llm-export.`);
46
+ const before = target.slice(0, beginIdx);
47
+ const after = target.slice(endIdx + 36);
48
+ return before + block + after;
49
+ }
50
+ function upsertClaudeImport(target) {
51
+ if (target.split("\n").some((line) => line.trim() === CLAUDE_IMPORT_LINE)) return {
52
+ next: target,
53
+ written: false
54
+ };
55
+ return {
56
+ next: target + (target.length === 0 ? "" : target.endsWith("\n\n") ? "" : target.endsWith("\n") ? "\n" : "\n\n") + CLAUDE_IMPORT_LINE + "\n",
57
+ written: true
58
+ };
59
+ }
60
+ function readOrEmpty(path) {
61
+ return existsSync(path) ? readFileSync(path, "utf8") : "";
62
+ }
63
+ function runLlmExport(cwd = process.cwd()) {
64
+ const block = buildManagedBlock();
65
+ const agentsMdPath = join(cwd, "AGENTS.md");
66
+ writeFileSync(agentsMdPath, upsertManagedBlock(readOrEmpty(agentsMdPath), block), "utf8");
67
+ const claudeMdPath = join(cwd, "CLAUDE.md");
68
+ const { next: claudeAfter, written: claudeImportWritten } = upsertClaudeImport(readOrEmpty(claudeMdPath));
69
+ writeFileSync(claudeMdPath, claudeAfter, "utf8");
70
+ return {
71
+ agentsMdPath,
72
+ claudeMdPath,
73
+ managedBlockBytes: block.length,
74
+ claudeImportWritten
75
+ };
76
+ }
77
+
78
+ //#endregion
79
+ //#region src/bin/platform-sdk.ts
80
+ function usage() {
81
+ process.stderr.write("Usage: npx @alvera-ai/platform-sdk <command>\n\nCommands:\n llm-export Write a managed AGENTS.md block pointing at the\n SDK agent-docs corpus in node_modules; ensure\n CLAUDE.md imports AGENTS.md. Idempotent.\n");
82
+ }
83
+ function main() {
84
+ const command = process.argv[2];
85
+ if (command === void 0 || command === "--help" || command === "-h") {
86
+ usage();
87
+ process.exit(command === void 0 ? 1 : 0);
88
+ }
89
+ if (command === "llm-export") try {
90
+ const result = runLlmExport(process.cwd());
91
+ process.stderr.write(`✓ ${result.agentsMdPath} (${result.managedBlockBytes} bytes in managed block)\n`);
92
+ process.stderr.write(`✓ ${result.claudeMdPath}${result.claudeImportWritten ? " (added @AGENTS.md import)" : " (@AGENTS.md import already present)"}\n`);
93
+ return;
94
+ } catch (err) {
95
+ process.stderr.write(`llm-export failed: ${err instanceof Error ? err.message : String(err)}\n`);
96
+ process.exit(1);
97
+ }
98
+ process.stderr.write(`unknown command "${command}".\n\n`);
99
+ usage();
100
+ process.exit(1);
101
+ }
102
+ main();
103
+
104
+ //#endregion
105
+ export { };
106
+ //# sourceMappingURL=platform-sdk.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-sdk.mjs","names":[],"sources":["../../src/llm-export.ts","../../src/bin/platform-sdk.ts"],"sourcesContent":["// Consumer-facing agent-docs injector — the SDK-bin home of\n// `llm-export`. Writes a managed block into <cwd>/AGENTS.md that POINTS\n// at this package's shipped `.agent/` corpus (predictable npm path), and\n// ensures <cwd>/CLAUDE.md imports AGENTS.md.\n//\n// This writer is DUPLICATED in the CLI (packages/cli/src/cli/llm-export.ts)\n// for the brew `alvera llm-export` path. The two copies must emit a\n// byte-identical block — `buildManagedBlock()` below is kept verbatim in\n// both, and each package snapshot-tests its own output (architecture-\n// decisions §2.10.13). They are not shared via import: the CLI's tsconfig\n// rootDir forbids importing SDK source, a public SDK export was rejected\n// to keep the surface lean (CLAUDE.md #6), and the sharing would be\n// throwaway under a future Go CLI anyway.\n//\n// Unlike the CLI copy, this one is a LIBRARY module: it throws on damaged\n// markers rather than calling process.exit — the bin entry catches and\n// exits.\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nconst MARKER_BEGIN = '<!-- @alvera-ai/platform-sdk:BEGIN -->'\nconst MARKER_END = '<!-- @alvera-ai/platform-sdk:END -->'\nconst CLAUDE_IMPORT_LINE = '@AGENTS.md'\nconst SDK_PACKAGE_NAME = '@alvera-ai/platform-sdk'\n\nexport interface LlmExportResult {\n agentsMdPath: string\n claudeMdPath: string\n managedBlockBytes: number\n claudeImportWritten: boolean\n}\n\n// Pure + deterministic. MUST stay byte-identical to the CLI copy's\n// buildManagedBlock (§2.10.13 drift guard).\nexport function buildManagedBlock(): string {\n const corpus = `node_modules/${SDK_PACKAGE_NAME}/.agent`\n const lines: string[] = [\n MARKER_BEGIN,\n '',\n '<!-- Managed by `alvera llm-export` — do not edit by hand. -->',\n '<!-- Re-running the command replaces only this block. -->',\n '',\n `## \\`${SDK_PACKAGE_NAME}\\` corpus`,\n '',\n 'The SDK ships an agent-docs corpus next to its npm install. Read the',\n 'corpus index first (Claude Code inlines this import):',\n '',\n `@${corpus}/AGENTS.md`,\n '',\n `Cookbook recipes live under \\`${corpus}/cookbook/\\`.`,\n '',\n '### Top-3 consumer gotchas',\n '',\n '1. **`update()` replaces the whole resource.** There is no partial',\n ` update — resupply the full body. See \\`${corpus}/mutations.md\\`.`,\n '2. **Paginated catalogs return `{ data, meta }`.** Catalog endpoints',\n ' (`tools.list`, `dataSources.list`, etc.) wrap rows in `data` with a',\n ' `meta` envelope — destructure, do not iterate the response directly.',\n '3. **Resources are datalake-slug-scoped.** Every nested URL takes both',\n ' `tenantSlug` and `datalakeSlug` — never a single slug. The datalake',\n \" slug comes from the server (`api.datalakes.create`'s response).\",\n '',\n MARKER_END,\n ]\n return lines.join('\\n')\n}\n\nexport function upsertManagedBlock(target: string, block: string): string {\n const beginIdx = target.indexOf(MARKER_BEGIN)\n const endIdx = target.indexOf(MARKER_END)\n\n if (beginIdx === -1 && endIdx === -1) {\n const tail =\n target.length === 0\n ? ''\n : target.endsWith('\\n\\n')\n ? ''\n : target.endsWith('\\n')\n ? '\\n'\n : '\\n\\n'\n return target + tail + block + '\\n'\n }\n\n if (beginIdx === -1 || endIdx === -1 || endIdx < beginIdx) {\n throw new Error(\n `AGENTS.md: managed-block markers are damaged ` +\n `(BEGIN at ${beginIdx}, END at ${endIdx}). ` +\n `Fix by hand or remove both markers, then re-run llm-export.`,\n )\n }\n\n const before = target.slice(0, beginIdx)\n const after = target.slice(endIdx + MARKER_END.length)\n return before + block + after\n}\n\nexport function upsertClaudeImport(target: string): { next: string; written: boolean } {\n const already = target.split('\\n').some((line) => line.trim() === CLAUDE_IMPORT_LINE)\n if (already) return { next: target, written: false }\n const tail =\n target.length === 0\n ? ''\n : target.endsWith('\\n\\n')\n ? ''\n : target.endsWith('\\n')\n ? '\\n'\n : '\\n\\n'\n return { next: target + tail + CLAUDE_IMPORT_LINE + '\\n', written: true }\n}\n\nfunction readOrEmpty(path: string): string {\n return existsSync(path) ? readFileSync(path, 'utf8') : ''\n}\n\nexport function runLlmExport(cwd: string = process.cwd()): LlmExportResult {\n const block = buildManagedBlock()\n\n const agentsMdPath = join(cwd, 'AGENTS.md')\n writeFileSync(agentsMdPath, upsertManagedBlock(readOrEmpty(agentsMdPath), block), 'utf8')\n\n const claudeMdPath = join(cwd, 'CLAUDE.md')\n const { next: claudeAfter, written: claudeImportWritten } = upsertClaudeImport(\n readOrEmpty(claudeMdPath),\n )\n writeFileSync(claudeMdPath, claudeAfter, 'utf8')\n\n return {\n agentsMdPath,\n claudeMdPath,\n managedBlockBytes: block.length,\n claudeImportWritten,\n }\n}\n","#!/usr/bin/env node\n// The SDK's single bin (Stripe multi-subcommand pattern). Today the only\n// subcommand is `llm-export`, the consumer-facing agent-docs injector —\n// so an npm-only consumer runs `npx @alvera-ai/platform-sdk llm-export`\n// with no brew CLI install (architecture-decisions §2.10.13). The bin is\n// the ONLY thing reversed from inv #21; the SDK stays sub-export-less and\n// declares no postinstall.\nimport { runLlmExport } from '../llm-export.js'\n\nfunction usage(): void {\n process.stderr.write(\n 'Usage: npx @alvera-ai/platform-sdk <command>\\n\\n' +\n 'Commands:\\n' +\n ' llm-export Write a managed AGENTS.md block pointing at the\\n' +\n ' SDK agent-docs corpus in node_modules; ensure\\n' +\n ' CLAUDE.md imports AGENTS.md. Idempotent.\\n',\n )\n}\n\nfunction main(): void {\n const command = process.argv[2]\n\n if (command === undefined || command === '--help' || command === '-h') {\n usage()\n process.exit(command === undefined ? 1 : 0)\n }\n\n if (command === 'llm-export') {\n try {\n const result = runLlmExport(process.cwd())\n process.stderr.write(\n `✓ ${result.agentsMdPath} (${result.managedBlockBytes} bytes in managed block)\\n`,\n )\n process.stderr.write(\n `✓ ${result.claudeMdPath}` +\n `${result.claudeImportWritten ? ' (added @AGENTS.md import)' : ' (@AGENTS.md import already present)'}\\n`,\n )\n return\n } catch (err) {\n process.stderr.write(`llm-export failed: ${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(1)\n }\n }\n\n process.stderr.write(`unknown command \"${command}\".\\n\\n`)\n usage()\n process.exit(1)\n}\n\nmain()\n"],"mappings":";;;;;AAoBA,MAAM,eAAe;AACrB,MAAM,aAAa;AACnB,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AAWzB,SAAgB,oBAA4B;CAC1C,MAAM,SAAS,gBAAgB,iBAAiB;AA6BhD,QA5BwB;EACtB;EACA;EACA;EACA;EACA;EACA,QAAQ,iBAAiB;EACzB;EACA;EACA;EACA;EACA,IAAI,OAAO;EACX;EACA,iCAAiC,OAAO;EACxC;EACA;EACA;EACA;EACA,6CAA6C,OAAO;EACpD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACY,KAAK,KAAK;;AAGzB,SAAgB,mBAAmB,QAAgB,OAAuB;CACxE,MAAM,WAAW,OAAO,QAAQ,aAAa;CAC7C,MAAM,SAAS,OAAO,QAAQ,WAAW;AAEzC,KAAI,aAAa,MAAM,WAAW,GAShC,QAAO,UAPL,OAAO,WAAW,IACd,KACA,OAAO,SAAS,OAAO,GACrB,KACA,OAAO,SAAS,KAAK,GACnB,OACA,UACa,QAAQ;AAGjC,KAAI,aAAa,MAAM,WAAW,MAAM,SAAS,SAC/C,OAAM,IAAI,MACR,0DACe,SAAS,WAAW,OAAO,gEAE3C;CAGH,MAAM,SAAS,OAAO,MAAM,GAAG,SAAS;CACxC,MAAM,QAAQ,OAAO,MAAM,SAAS,GAAkB;AACtD,QAAO,SAAS,QAAQ;;AAG1B,SAAgB,mBAAmB,QAAoD;AAErF,KADgB,OAAO,MAAM,KAAK,CAAC,MAAM,SAAS,KAAK,MAAM,KAAK,mBAAmB,CACxE,QAAO;EAAE,MAAM;EAAQ,SAAS;EAAO;AASpD,QAAO;EAAE,MAAM,UAPb,OAAO,WAAW,IACd,KACA,OAAO,SAAS,OAAO,GACrB,KACA,OAAO,SAAS,KAAK,GACnB,OACA,UACqB,qBAAqB;EAAM,SAAS;EAAM;;AAG3E,SAAS,YAAY,MAAsB;AACzC,QAAO,WAAW,KAAK,GAAG,aAAa,MAAM,OAAO,GAAG;;AAGzD,SAAgB,aAAa,MAAc,QAAQ,KAAK,EAAmB;CACzE,MAAM,QAAQ,mBAAmB;CAEjC,MAAM,eAAe,KAAK,KAAK,YAAY;AAC3C,eAAc,cAAc,mBAAmB,YAAY,aAAa,EAAE,MAAM,EAAE,OAAO;CAEzF,MAAM,eAAe,KAAK,KAAK,YAAY;CAC3C,MAAM,EAAE,MAAM,aAAa,SAAS,wBAAwB,mBAC1D,YAAY,aAAa,CAC1B;AACD,eAAc,cAAc,aAAa,OAAO;AAEhD,QAAO;EACL;EACA;EACA,mBAAmB,MAAM;EACzB;EACD;;;;;AC1HH,SAAS,QAAc;AACrB,SAAQ,OAAO,MACb,wPAKD;;AAGH,SAAS,OAAa;CACpB,MAAM,UAAU,QAAQ,KAAK;AAE7B,KAAI,YAAY,UAAa,YAAY,YAAY,YAAY,MAAM;AACrE,SAAO;AACP,UAAQ,KAAK,YAAY,SAAY,IAAI,EAAE;;AAG7C,KAAI,YAAY,aACd,KAAI;EACF,MAAM,SAAS,aAAa,QAAQ,KAAK,CAAC;AAC1C,UAAQ,OAAO,MACb,KAAK,OAAO,aAAa,IAAI,OAAO,kBAAkB,4BACvD;AACD,UAAQ,OAAO,MACb,KAAK,OAAO,eACP,OAAO,sBAAsB,+BAA+B,uCAAuC,IACzG;AACD;UACO,KAAK;AACZ,UAAQ,OAAO,MAAM,sBAAsB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC,IAAI;AAChG,UAAQ,KAAK,EAAE;;AAInB,SAAQ,OAAO,MAAM,oBAAoB,QAAQ,QAAQ;AACzD,QAAO;AACP,SAAQ,KAAK,EAAE;;AAGjB,MAAM"}