@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.
- package/.agent/AGENTS.md +499 -0
- package/.agent/account_management.md +456 -0
- package/.agent/action_status_updaters.md +264 -0
- package/.agent/ai_agents.md +462 -0
- package/.agent/ai_sandbox.md +265 -0
- package/.agent/async.md +112 -0
- package/.agent/connected_apps.md +408 -0
- package/.agent/cookbook/_fixtures/README.md +106 -0
- package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_customer.liquid +32 -0
- package/.agent/cookbook/_fixtures/accounts_receivable/_customers_accounts_receivable_mdm.liquid +20 -0
- package/.agent/cookbook/_fixtures/accounts_receivable/stripe_customers_batch1.csv +5 -0
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_generic_table.liquid +33 -0
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid +88 -0
- package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_mdm.liquid +48 -0
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid +47 -0
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_mdm.liquid +24 -0
- package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_patient.liquid +38 -0
- package/.agent/cookbook/_fixtures/healthcare/memorandum-of-association-01.png +0 -0
- package/.agent/cookbook/_fixtures/healthcare/sample_two_page.pdf +43 -0
- package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_compliance_screening.liquid +59 -0
- package/.agent/cookbook/_fixtures/payment_risk/_compliance_screenings_payment_risk_mdm.liquid +36 -0
- package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_mdm.liquid +30 -0
- package/.agent/cookbook/_fixtures/payment_risk/_payment_accounts_payment_risk_payment_account.liquid +55 -0
- package/.agent/cookbook/_setup/accounts_receivable.md +282 -0
- package/.agent/cookbook/_setup/foundation.md +277 -0
- package/.agent/cookbook/_setup/healthcare.md +279 -0
- package/.agent/cookbook/_setup/payment_risk.md +283 -0
- package/.agent/cookbook/action-status-updaters.md +212 -0
- package/.agent/cookbook/ai-agent-invoke.md +243 -0
- package/.agent/cookbook/appointment-review-sms-workflow.md +761 -0
- package/.agent/cookbook/birthday-greeting-sms-trigger.md +656 -0
- package/.agent/cookbook/bulk-ingest.md +254 -0
- package/.agent/cookbook/contact-us-triage-with-llm.md +622 -0
- package/.agent/cookbook/custom-tables.md +201 -0
- package/.agent/cookbook/dunning-sms-for-delinquent.md +619 -0
- package/.agent/cookbook/invite-team.md +194 -0
- package/.agent/cookbook/kyc-notification-on-account-activation.md +619 -0
- package/.agent/cookbook/rest-fetch.md +246 -0
- package/.agent/cookbook/sanctions-screening-with-agent-review.md +733 -0
- package/.agent/cookbook/score-leads-with-llm-categorization.md +624 -0
- package/.agent/cookbook/system-templates.md +129 -0
- package/.agent/cookbook/triage-prospects-by-priority.md +533 -0
- package/.agent/cookbook/welcome-sms-for-customers.md +607 -0
- package/.agent/data_activation_clients.md +559 -0
- package/.agent/data_sources.md +235 -0
- package/.agent/datalakes.md +714 -0
- package/.agent/debugging.md +137 -0
- package/.agent/errors.md +190 -0
- package/.agent/generic_tables.md +351 -0
- package/.agent/interoperability_contracts.md +417 -0
- package/.agent/mdm.md +293 -0
- package/.agent/mutations.md +126 -0
- package/.agent/templates.md +98 -0
- package/.agent/tool-call-configs.md +90 -0
- package/.agent/tools.md +547 -0
- package/.agent/type_naming.md +129 -0
- package/.agent/workflows.md +617 -0
- package/README.md +178 -0
- package/dist/bin/platform-sdk.d.mts +1 -0
- package/dist/bin/platform-sdk.mjs +106 -0
- package/dist/bin/platform-sdk.mjs.map +1 -0
- package/dist/index.d.mts +1310 -44116
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1194 -7344
- package/dist/index.mjs.map +1 -1
- 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"}
|