@elevasis/sdk 0.5.14 → 0.5.15
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/dist/cli.cjs +693 -372
- package/dist/index.d.ts +24 -0
- package/dist/index.js +53 -0
- package/dist/templates.js +218 -1
- package/dist/worker/index.js +3 -7
- package/package.json +1 -1
- package/reference/framework/project-structure.mdx +5 -5
package/dist/cli.cjs
CHANGED
|
@@ -40164,6 +40164,12 @@ var DOMAIN_MAP = {
|
|
|
40164
40164
|
[DOMAINS.DIAGNOSTIC]: DIAGNOSTIC_DOMAIN
|
|
40165
40165
|
};
|
|
40166
40166
|
|
|
40167
|
+
// ../core/src/platform/registry/reserved.ts
|
|
40168
|
+
var RESERVED_RESOURCE_IDS = /* @__PURE__ */ new Set(["command-center-assistant"]);
|
|
40169
|
+
function isReservedResourceId(resourceId) {
|
|
40170
|
+
return RESERVED_RESOURCE_IDS.has(resourceId);
|
|
40171
|
+
}
|
|
40172
|
+
|
|
40167
40173
|
// ../core/src/execution/engine/base/errors.ts
|
|
40168
40174
|
var ExecutionError = class extends Error {
|
|
40169
40175
|
/**
|
|
@@ -43363,6 +43369,13 @@ var ResourceRegistry = class {
|
|
|
43363
43369
|
}
|
|
43364
43370
|
seen.add(id);
|
|
43365
43371
|
}
|
|
43372
|
+
for (const id of incomingIds) {
|
|
43373
|
+
if (isReservedResourceId(id)) {
|
|
43374
|
+
throw new Error(
|
|
43375
|
+
`Resource ID '${id}' is reserved for platform use. External deployments cannot use reserved resource IDs.`
|
|
43376
|
+
);
|
|
43377
|
+
}
|
|
43378
|
+
}
|
|
43366
43379
|
if (this.isRemote(orgName)) {
|
|
43367
43380
|
this.unregisterOrganization(orgName);
|
|
43368
43381
|
}
|
|
@@ -43395,6 +43408,46 @@ var ResourceRegistry = class {
|
|
|
43395
43408
|
}
|
|
43396
43409
|
this.serializedCache.set(orgName, serializeOrganization(this.registry[orgName]));
|
|
43397
43410
|
}
|
|
43411
|
+
/**
|
|
43412
|
+
* Register built-in platform resources (static, local execution)
|
|
43413
|
+
*
|
|
43414
|
+
* Unlike registerOrganization(), these resources:
|
|
43415
|
+
* - Do NOT have remote config (execute in-process, not in worker threads)
|
|
43416
|
+
* - Are NOT removed by unregisterOrganization() (persist across redeployments)
|
|
43417
|
+
* - Use reserved resource IDs that external deployments cannot claim
|
|
43418
|
+
*
|
|
43419
|
+
* @param orgName - Organization name
|
|
43420
|
+
* @param org - Resource definitions with real handlers (not stubs)
|
|
43421
|
+
*/
|
|
43422
|
+
registerStaticResources(orgName, org) {
|
|
43423
|
+
const incomingWorkflowIds = (org.workflows ?? []).map((w) => w.config.resourceId);
|
|
43424
|
+
const incomingAgentIds = (org.agents ?? []).map((a) => a.config.resourceId);
|
|
43425
|
+
const incomingIds = [...incomingWorkflowIds, ...incomingAgentIds];
|
|
43426
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43427
|
+
for (const id of incomingIds) {
|
|
43428
|
+
if (seen.has(id)) {
|
|
43429
|
+
throw new Error(`Duplicate resource ID '${id}' in static resources.`);
|
|
43430
|
+
}
|
|
43431
|
+
seen.add(id);
|
|
43432
|
+
}
|
|
43433
|
+
const existingOrg = this.registry[orgName];
|
|
43434
|
+
if (existingOrg) {
|
|
43435
|
+
const existingWorkflowIds = new Set((existingOrg.workflows ?? []).map((w) => w.config.resourceId));
|
|
43436
|
+
const existingAgentIds = new Set((existingOrg.agents ?? []).map((a) => a.config.resourceId));
|
|
43437
|
+
for (const id of incomingIds) {
|
|
43438
|
+
if (existingWorkflowIds.has(id) || existingAgentIds.has(id)) {
|
|
43439
|
+
throw new Error(`Static resource '${id}' conflicts with existing resource in '${orgName}'.`);
|
|
43440
|
+
}
|
|
43441
|
+
}
|
|
43442
|
+
}
|
|
43443
|
+
if (existingOrg) {
|
|
43444
|
+
existingOrg.workflows = [...existingOrg.workflows ?? [], ...org.workflows ?? []];
|
|
43445
|
+
existingOrg.agents = [...existingOrg.agents ?? [], ...org.agents ?? []];
|
|
43446
|
+
} else {
|
|
43447
|
+
this.registry[orgName] = org;
|
|
43448
|
+
}
|
|
43449
|
+
this.serializedCache.set(orgName, serializeOrganization(this.registry[orgName]));
|
|
43450
|
+
}
|
|
43398
43451
|
/**
|
|
43399
43452
|
* Unregister runtime-registered resources for an organization
|
|
43400
43453
|
*
|
|
@@ -43798,7 +43851,7 @@ async function apiDelete(endpoint, apiUrl = resolveApiUrl()) {
|
|
|
43798
43851
|
// package.json
|
|
43799
43852
|
var package_default = {
|
|
43800
43853
|
name: "@elevasis/sdk",
|
|
43801
|
-
version: "0.5.
|
|
43854
|
+
version: "0.5.15",
|
|
43802
43855
|
description: "SDK for building Elevasis organization resources",
|
|
43803
43856
|
type: "module",
|
|
43804
43857
|
bin: {
|
|
@@ -43884,9 +43937,7 @@ async function scanDocumentation() {
|
|
|
43884
43937
|
const raw = await (0, import_promises.readFile)(fullPath, "utf-8");
|
|
43885
43938
|
const fileSize = Buffer.byteLength(raw, "utf-8");
|
|
43886
43939
|
if (fileSize > 100 * 1024) {
|
|
43887
|
-
throw new Error(
|
|
43888
|
-
`Documentation file exceeds 100KB: docs/${relPath} (${Math.round(fileSize / 1024)}KB)`
|
|
43889
|
-
);
|
|
43940
|
+
throw new Error(`Documentation file exceeds 100KB: docs/${relPath} (${Math.round(fileSize / 1024)}KB)`);
|
|
43890
43941
|
}
|
|
43891
43942
|
totalSize += fileSize;
|
|
43892
43943
|
if (totalSize > 1024 * 1024) {
|
|
@@ -43939,7 +43990,9 @@ async function generateResourceMap(org) {
|
|
|
43939
43990
|
);
|
|
43940
43991
|
for (const w of workflows) {
|
|
43941
43992
|
const desc = escapeMdx(w.config.description);
|
|
43942
|
-
lines.push(
|
|
43993
|
+
lines.push(
|
|
43994
|
+
`| \`${w.config.resourceId}\` | ${escapeMdx(w.config.name)} | ${w.config.version} | ${w.config.status} | ${desc} |`
|
|
43995
|
+
);
|
|
43943
43996
|
}
|
|
43944
43997
|
lines.push("");
|
|
43945
43998
|
}
|
|
@@ -43952,11 +44005,16 @@ async function generateResourceMap(org) {
|
|
|
43952
44005
|
);
|
|
43953
44006
|
for (const a of agents) {
|
|
43954
44007
|
const desc = escapeMdx(a.config.description);
|
|
43955
|
-
lines.push(
|
|
44008
|
+
lines.push(
|
|
44009
|
+
`| \`${a.config.resourceId}\` | ${escapeMdx(a.config.name)} | ${a.config.version} | ${a.config.status} | ${desc} |`
|
|
44010
|
+
);
|
|
43956
44011
|
}
|
|
43957
44012
|
lines.push("");
|
|
43958
44013
|
}
|
|
43959
|
-
lines.push(
|
|
44014
|
+
lines.push(
|
|
44015
|
+
`**Total:** ${workflows.length + agents.length} resources (${workflows.length} workflows, ${agents.length} agents)`,
|
|
44016
|
+
""
|
|
44017
|
+
);
|
|
43960
44018
|
await (0, import_promises.mkdir)((0, import_path.resolve)("docs"), { recursive: true });
|
|
43961
44019
|
await (0, import_promises.writeFile)((0, import_path.resolve)("docs/resource-map.mdx"), lines.join("\n"), "utf-8");
|
|
43962
44020
|
}
|
|
@@ -44020,8 +44078,12 @@ async function generateProjectMap(org) {
|
|
|
44020
44078
|
if (resourceCount === 0) {
|
|
44021
44079
|
types = "(utilities)";
|
|
44022
44080
|
} else {
|
|
44023
|
-
const wCount = workflows.filter(
|
|
44024
|
-
|
|
44081
|
+
const wCount = workflows.filter(
|
|
44082
|
+
(w) => Array.isArray(w.config.domains) && w.config.domains.includes(domainName)
|
|
44083
|
+
).length;
|
|
44084
|
+
const aCount = agents.filter(
|
|
44085
|
+
(a) => Array.isArray(a.config.domains) && a.config.domains.includes(domainName)
|
|
44086
|
+
).length;
|
|
44025
44087
|
const parts = [];
|
|
44026
44088
|
if (wCount > 0) parts.push(`${wCount} workflow${wCount !== 1 ? "s" : ""}`);
|
|
44027
44089
|
if (aCount > 0) parts.push(`${aCount} agent${aCount !== 1 ? "s" : ""}`);
|
|
@@ -44133,10 +44195,7 @@ async function generateProjectMap(org) {
|
|
|
44133
44195
|
if (categories.length === 0) {
|
|
44134
44196
|
lines.push("SDK reference found but no categories parsed.", "");
|
|
44135
44197
|
} else {
|
|
44136
|
-
lines.push(
|
|
44137
|
-
"| Category | Files | Covers |",
|
|
44138
|
-
"| --- | --- | --- |"
|
|
44139
|
-
);
|
|
44198
|
+
lines.push("| Category | Files | Covers |", "| --- | --- | --- |");
|
|
44140
44199
|
for (const cat of categories) {
|
|
44141
44200
|
const covers = cat.titles.slice(0, 5).join(", ") + (cat.titles.length > 5 ? ", ..." : "");
|
|
44142
44201
|
lines.push(`| ${escapeMdx(cat.name)} | ${cat.count} | ${escapeMdx(covers)} |`);
|
|
@@ -44154,10 +44213,7 @@ async function generateProjectMap(org) {
|
|
|
44154
44213
|
if (cmdFiles.length === 0) {
|
|
44155
44214
|
lines.push("No commands found.", "");
|
|
44156
44215
|
} else {
|
|
44157
|
-
lines.push(
|
|
44158
|
-
"| Command | File | Purpose |",
|
|
44159
|
-
"| --- | --- | --- |"
|
|
44160
|
-
);
|
|
44216
|
+
lines.push("| Command | File | Purpose |", "| --- | --- | --- |");
|
|
44161
44217
|
for (const f of cmdFiles) {
|
|
44162
44218
|
const cmdName = f.name.replace(/\.md$/, "");
|
|
44163
44219
|
let purpose = "";
|
|
@@ -44186,10 +44242,7 @@ async function generateProjectMap(org) {
|
|
|
44186
44242
|
if (ruleFiles.length === 0) {
|
|
44187
44243
|
lines.push("No rules found.", "");
|
|
44188
44244
|
} else {
|
|
44189
|
-
lines.push(
|
|
44190
|
-
"| Rule | File | Scope |",
|
|
44191
|
-
"| --- | --- | --- |"
|
|
44192
|
-
);
|
|
44245
|
+
lines.push("| Rule | File | Scope |", "| --- | --- | --- |");
|
|
44193
44246
|
for (const f of ruleFiles) {
|
|
44194
44247
|
const ruleName = f.name.replace(/\.md$/, "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
44195
44248
|
let scope = "";
|
|
@@ -44220,10 +44273,7 @@ async function generateProjectMap(org) {
|
|
|
44220
44273
|
if (skillDirs.length === 0) {
|
|
44221
44274
|
lines.push("No skills found.", "");
|
|
44222
44275
|
} else {
|
|
44223
|
-
lines.push(
|
|
44224
|
-
"| Skill | File | Trigger |",
|
|
44225
|
-
"| --- | --- | --- |"
|
|
44226
|
-
);
|
|
44276
|
+
lines.push("| Skill | File | Trigger |", "| --- | --- | --- |");
|
|
44227
44277
|
for (const d of skillDirs) {
|
|
44228
44278
|
const skillFile = (0, import_path.resolve)(".claude/skills", d.name, "SKILL.md");
|
|
44229
44279
|
let trigger = "";
|
|
@@ -44279,10 +44329,7 @@ async function generateProjectMap(org) {
|
|
|
44279
44329
|
if (memoryFiles.length === 0) {
|
|
44280
44330
|
lines.push("No memory files found.", "");
|
|
44281
44331
|
} else {
|
|
44282
|
-
lines.push(
|
|
44283
|
-
"| File | Purpose | Last Modified |",
|
|
44284
|
-
"| --- | --- | --- |"
|
|
44285
|
-
);
|
|
44332
|
+
lines.push("| File | Purpose | Last Modified |", "| --- | --- | --- |");
|
|
44286
44333
|
for (const m of memoryFiles) {
|
|
44287
44334
|
lines.push(`| .claude/memory/${m.rel} | ${escapeMdx(m.purpose)} | ${m.mtime} |`);
|
|
44288
44335
|
}
|
|
@@ -44314,250 +44361,293 @@ async function generateProjectMap(org) {
|
|
|
44314
44361
|
await (0, import_promises.mkdir)((0, import_path.resolve)("docs"), { recursive: true });
|
|
44315
44362
|
await (0, import_promises.writeFile)((0, import_path.resolve)("docs/project-map.mdx"), lines.join("\n"), "utf-8");
|
|
44316
44363
|
}
|
|
44364
|
+
async function generateNavigationMap(docs) {
|
|
44365
|
+
const excludedFiles = /* @__PURE__ */ new Set(["docs/navigation-map.mdx", "docs/project-map.mdx", "docs/resource-map.mdx"]);
|
|
44366
|
+
const filtered = docs.filter((doc) => !excludedFiles.has(doc.path)).sort((a, b) => {
|
|
44367
|
+
const orderA = a.frontmatter.order ?? 9999;
|
|
44368
|
+
const orderB = b.frontmatter.order ?? 9999;
|
|
44369
|
+
if (orderA !== orderB) return orderA - orderB;
|
|
44370
|
+
return a.frontmatter.title.localeCompare(b.frontmatter.title);
|
|
44371
|
+
});
|
|
44372
|
+
const lines = [
|
|
44373
|
+
"---",
|
|
44374
|
+
"title: Navigation Map",
|
|
44375
|
+
"description: Auto-generated table of contents for all documentation (updated on each deploy)",
|
|
44376
|
+
"order: 997",
|
|
44377
|
+
"---",
|
|
44378
|
+
"",
|
|
44379
|
+
"# Navigation Map",
|
|
44380
|
+
"",
|
|
44381
|
+
"> Auto-generated by `elevasis-sdk deploy`. Do not edit manually.",
|
|
44382
|
+
"",
|
|
44383
|
+
"| Title | Description | Path |",
|
|
44384
|
+
"| --- | --- | --- |"
|
|
44385
|
+
];
|
|
44386
|
+
for (const doc of filtered) {
|
|
44387
|
+
lines.push(`| ${escapeMdx(doc.frontmatter.title)} | ${escapeMdx(doc.frontmatter.description)} | ${doc.path} |`);
|
|
44388
|
+
}
|
|
44389
|
+
lines.push("");
|
|
44390
|
+
await (0, import_promises.mkdir)((0, import_path.resolve)("docs"), { recursive: true });
|
|
44391
|
+
await (0, import_promises.writeFile)((0, import_path.resolve)("docs/navigation-map.mdx"), lines.join("\n"), "utf-8");
|
|
44392
|
+
}
|
|
44317
44393
|
function registerDeployCommand(program3) {
|
|
44318
|
-
program3.command("deploy").description(
|
|
44319
|
-
|
|
44320
|
-
|
|
44321
|
-
|
|
44322
|
-
|
|
44323
|
-
|
|
44324
|
-
|
|
44325
|
-
|
|
44326
|
-
const
|
|
44327
|
-
orgName
|
|
44328
|
-
|
|
44329
|
-
|
|
44330
|
-
|
|
44331
|
-
|
|
44332
|
-
|
|
44333
|
-
|
|
44334
|
-
|
|
44335
|
-
|
|
44336
|
-
|
|
44337
|
-
|
|
44338
|
-
|
|
44339
|
-
|
|
44340
|
-
|
|
44394
|
+
program3.command("deploy").description(
|
|
44395
|
+
"Validate, bundle, upload, and deploy project resources\n Example: elevasis-sdk deploy --api-url http://localhost:5170"
|
|
44396
|
+
).option("--api-url <url>", "API URL").option("--entry <path>", "Path to entry file (default: ./src/index.ts)").option("--prod", "Deploy to production (overrides NODE_ENV=development)").action(
|
|
44397
|
+
wrapAction("deploy", async (options2) => {
|
|
44398
|
+
const startTime = Date.now();
|
|
44399
|
+
const apiUrl = resolveApiUrl(options2.apiUrl, options2.prod);
|
|
44400
|
+
const env2 = resolveEnvironment(options2.prod);
|
|
44401
|
+
const entryPath = options2.entry ?? "./src/index.ts";
|
|
44402
|
+
const authSpinner = ora("Authenticating...").start();
|
|
44403
|
+
let orgName;
|
|
44404
|
+
try {
|
|
44405
|
+
const me = await apiGet("/api/external/me", apiUrl);
|
|
44406
|
+
orgName = me.organizationName;
|
|
44407
|
+
authSpinner.succeed(
|
|
44408
|
+
source_default.green("Authenticating...") + source_default.white(" done") + source_default.gray(` (${orgName})`)
|
|
44409
|
+
);
|
|
44410
|
+
} catch (error46) {
|
|
44411
|
+
authSpinner.fail(source_default.red("Authentication failed"));
|
|
44412
|
+
const errMsg = error46 instanceof Error ? error46.message : String(error46);
|
|
44413
|
+
if (errMsg.includes("401") || errMsg.toLowerCase().includes("unauthorized")) {
|
|
44414
|
+
const keyVar = !options2.prod && process.env.NODE_ENV === "development" && process.env.ELEVASIS_PLATFORM_KEY_DEV ? "ELEVASIS_PLATFORM_KEY_DEV" : "ELEVASIS_PLATFORM_KEY";
|
|
44415
|
+
console.error(source_default.red(" Invalid API key."));
|
|
44416
|
+
console.error(source_default.gray(` Your ${keyVar} was rejected by the server.`));
|
|
44417
|
+
console.error(source_default.gray(" Check your .env file and verify the key in the Elevasis dashboard."));
|
|
44418
|
+
} else {
|
|
44419
|
+
console.error(source_default.gray(" Check your API key and API URL."));
|
|
44420
|
+
}
|
|
44421
|
+
throw error46;
|
|
44341
44422
|
}
|
|
44342
|
-
|
|
44343
|
-
|
|
44344
|
-
|
|
44345
|
-
|
|
44346
|
-
|
|
44347
|
-
|
|
44348
|
-
|
|
44349
|
-
|
|
44350
|
-
|
|
44351
|
-
|
|
44352
|
-
|
|
44353
|
-
|
|
44423
|
+
const validateSpinner = ora("Validating...").start();
|
|
44424
|
+
let org;
|
|
44425
|
+
try {
|
|
44426
|
+
const jiti = (0, import_jiti.createJiti)(import_meta.url);
|
|
44427
|
+
const entryModule = await jiti.import((0, import_path.resolve)(entryPath));
|
|
44428
|
+
org = entryModule.default;
|
|
44429
|
+
if (!org) {
|
|
44430
|
+
validateSpinner.fail("Invalid entry: no default export found");
|
|
44431
|
+
console.error(source_default.gray(` Entry file: ${(0, import_path.resolve)(entryPath)}`));
|
|
44432
|
+
throw new Error("Invalid entry: no default export found");
|
|
44433
|
+
}
|
|
44434
|
+
new ResourceRegistry({ [orgName]: org });
|
|
44435
|
+
const workflowCount = org.workflows?.length ?? 0;
|
|
44436
|
+
const agentCount = org.agents?.length ?? 0;
|
|
44437
|
+
const totalCount = workflowCount + agentCount;
|
|
44438
|
+
validateSpinner.succeed(
|
|
44439
|
+
source_default.green("Validating...") + source_default.white(" done") + source_default.gray(` (${totalCount} resource${totalCount !== 1 ? "s" : ""}, 0 errors)`)
|
|
44440
|
+
);
|
|
44441
|
+
console.log("");
|
|
44442
|
+
console.log(source_default.gray(` Org: ${orgName}`));
|
|
44443
|
+
console.log(source_default.gray(` Target: ${apiUrl} (${env2})`));
|
|
44444
|
+
console.log("");
|
|
44445
|
+
for (const w of org.workflows ?? []) {
|
|
44446
|
+
console.log(source_default.gray(` workflow ${source_default.white(w.config.resourceId)} v${w.config.version}`));
|
|
44447
|
+
}
|
|
44448
|
+
for (const a of org.agents ?? []) {
|
|
44449
|
+
console.log(source_default.gray(` agent ${source_default.white(a.config.resourceId)} v${a.config.version}`));
|
|
44450
|
+
}
|
|
44451
|
+
console.log("");
|
|
44452
|
+
} catch (error46) {
|
|
44453
|
+
if (error46 instanceof RegistryValidationError) {
|
|
44454
|
+
validateSpinner.fail(source_default.red("Validation failed"));
|
|
44455
|
+
console.error("");
|
|
44456
|
+
console.error(source_default.red(` ERROR ${error46.message}`));
|
|
44457
|
+
if (error46.resourceId) {
|
|
44458
|
+
console.error(source_default.gray(` Resource: ${error46.resourceId}`));
|
|
44459
|
+
}
|
|
44460
|
+
console.error("");
|
|
44461
|
+
console.error(source_default.gray(" Deploy aborted."));
|
|
44462
|
+
}
|
|
44463
|
+
throw error46;
|
|
44354
44464
|
}
|
|
44355
|
-
|
|
44356
|
-
|
|
44357
|
-
|
|
44358
|
-
|
|
44359
|
-
|
|
44360
|
-
|
|
44361
|
-
|
|
44362
|
-
|
|
44363
|
-
|
|
44364
|
-
|
|
44365
|
-
|
|
44366
|
-
for (const w of org.workflows ?? []) {
|
|
44367
|
-
console.log(source_default.gray(` workflow ${source_default.white(w.config.resourceId)} v${w.config.version}`));
|
|
44465
|
+
await generateResourceMap(org);
|
|
44466
|
+
await generateProjectMap(org);
|
|
44467
|
+
let documentation = await scanDocumentation();
|
|
44468
|
+
if (documentation) {
|
|
44469
|
+
await generateNavigationMap(documentation);
|
|
44470
|
+
documentation = await scanDocumentation();
|
|
44471
|
+
console.log(
|
|
44472
|
+
source_default.gray(
|
|
44473
|
+
` docs ${source_default.white(String(documentation.length))} file${documentation.length !== 1 ? "s" : ""}`
|
|
44474
|
+
)
|
|
44475
|
+
);
|
|
44368
44476
|
}
|
|
44369
|
-
|
|
44370
|
-
|
|
44477
|
+
const triggerCount = org.triggers?.length ?? 0;
|
|
44478
|
+
const integrationCount = org.integrations?.length ?? 0;
|
|
44479
|
+
const checkpointCount = org.humanCheckpoints?.length ?? 0;
|
|
44480
|
+
if (triggerCount > 0) console.log(source_default.gray(` triggers ${source_default.white(String(triggerCount))}`));
|
|
44481
|
+
if (integrationCount > 0) console.log(source_default.gray(` integrations ${source_default.white(String(integrationCount))}`));
|
|
44482
|
+
if (checkpointCount > 0) console.log(source_default.gray(` checkpoints ${source_default.white(String(checkpointCount))}`));
|
|
44483
|
+
const relationshipCount = org.relationships ? Object.keys(org.relationships).length : 0;
|
|
44484
|
+
if (relationshipCount > 0) {
|
|
44485
|
+
console.log(
|
|
44486
|
+
source_default.gray(
|
|
44487
|
+
` rels ${source_default.white(String(relationshipCount))} resource${relationshipCount !== 1 ? "s" : ""}`
|
|
44488
|
+
)
|
|
44489
|
+
);
|
|
44371
44490
|
}
|
|
44372
|
-
|
|
44373
|
-
|
|
44374
|
-
|
|
44375
|
-
|
|
44376
|
-
|
|
44377
|
-
|
|
44378
|
-
|
|
44379
|
-
|
|
44491
|
+
const schemaWarnings = [];
|
|
44492
|
+
const workflows = (org.workflows ?? []).map((w) => {
|
|
44493
|
+
const meta = {
|
|
44494
|
+
resourceId: w.config.resourceId,
|
|
44495
|
+
name: w.config.name,
|
|
44496
|
+
version: w.config.version,
|
|
44497
|
+
status: w.config.status,
|
|
44498
|
+
description: w.config.description,
|
|
44499
|
+
domains: w.config.domains
|
|
44500
|
+
};
|
|
44501
|
+
if (w.contract.inputSchema) {
|
|
44502
|
+
try {
|
|
44503
|
+
meta.inputSchema = external_exports.toJSONSchema(w.contract.inputSchema);
|
|
44504
|
+
} catch {
|
|
44505
|
+
schemaWarnings.push(`${w.config.resourceId}: inputSchema could not be serialized`);
|
|
44506
|
+
}
|
|
44380
44507
|
}
|
|
44381
|
-
|
|
44382
|
-
|
|
44383
|
-
|
|
44384
|
-
|
|
44385
|
-
|
|
44386
|
-
|
|
44387
|
-
await generateProjectMap(org);
|
|
44388
|
-
const documentation = await scanDocumentation();
|
|
44389
|
-
if (documentation) {
|
|
44390
|
-
console.log(source_default.gray(` docs ${source_default.white(String(documentation.length))} file${documentation.length !== 1 ? "s" : ""}`));
|
|
44391
|
-
}
|
|
44392
|
-
const triggerCount = org.triggers?.length ?? 0;
|
|
44393
|
-
const integrationCount = org.integrations?.length ?? 0;
|
|
44394
|
-
const checkpointCount = org.humanCheckpoints?.length ?? 0;
|
|
44395
|
-
if (triggerCount > 0) console.log(source_default.gray(` triggers ${source_default.white(String(triggerCount))}`));
|
|
44396
|
-
if (integrationCount > 0) console.log(source_default.gray(` integrations ${source_default.white(String(integrationCount))}`));
|
|
44397
|
-
if (checkpointCount > 0) console.log(source_default.gray(` checkpoints ${source_default.white(String(checkpointCount))}`));
|
|
44398
|
-
const relationshipCount = org.relationships ? Object.keys(org.relationships).length : 0;
|
|
44399
|
-
if (relationshipCount > 0) {
|
|
44400
|
-
console.log(source_default.gray(` rels ${source_default.white(String(relationshipCount))} resource${relationshipCount !== 1 ? "s" : ""}`));
|
|
44401
|
-
}
|
|
44402
|
-
const schemaWarnings = [];
|
|
44403
|
-
const workflows = (org.workflows ?? []).map((w) => {
|
|
44404
|
-
const meta = {
|
|
44405
|
-
resourceId: w.config.resourceId,
|
|
44406
|
-
name: w.config.name,
|
|
44407
|
-
version: w.config.version,
|
|
44408
|
-
status: w.config.status,
|
|
44409
|
-
description: w.config.description,
|
|
44410
|
-
domains: w.config.domains
|
|
44411
|
-
};
|
|
44412
|
-
if (w.contract.inputSchema) {
|
|
44413
|
-
try {
|
|
44414
|
-
meta.inputSchema = external_exports.toJSONSchema(w.contract.inputSchema);
|
|
44415
|
-
} catch {
|
|
44416
|
-
schemaWarnings.push(`${w.config.resourceId}: inputSchema could not be serialized`);
|
|
44508
|
+
if (w.contract.outputSchema) {
|
|
44509
|
+
try {
|
|
44510
|
+
meta.outputSchema = external_exports.toJSONSchema(w.contract.outputSchema);
|
|
44511
|
+
} catch {
|
|
44512
|
+
schemaWarnings.push(`${w.config.resourceId}: outputSchema could not be serialized`);
|
|
44513
|
+
}
|
|
44417
44514
|
}
|
|
44418
|
-
|
|
44419
|
-
|
|
44420
|
-
|
|
44421
|
-
|
|
44422
|
-
|
|
44423
|
-
|
|
44515
|
+
return meta;
|
|
44516
|
+
});
|
|
44517
|
+
const agents = (org.agents ?? []).map((a) => {
|
|
44518
|
+
const meta = {
|
|
44519
|
+
resourceId: a.config.resourceId,
|
|
44520
|
+
name: a.config.name,
|
|
44521
|
+
version: a.config.version,
|
|
44522
|
+
status: a.config.status,
|
|
44523
|
+
description: a.config.description,
|
|
44524
|
+
domains: a.config.domains
|
|
44525
|
+
};
|
|
44526
|
+
if (a.contract.inputSchema) {
|
|
44527
|
+
try {
|
|
44528
|
+
meta.inputSchema = external_exports.toJSONSchema(a.contract.inputSchema);
|
|
44529
|
+
} catch {
|
|
44530
|
+
schemaWarnings.push(`${a.config.resourceId}: inputSchema could not be serialized`);
|
|
44531
|
+
}
|
|
44424
44532
|
}
|
|
44425
|
-
|
|
44426
|
-
|
|
44427
|
-
|
|
44428
|
-
|
|
44429
|
-
|
|
44430
|
-
|
|
44431
|
-
name: a.config.name,
|
|
44432
|
-
version: a.config.version,
|
|
44433
|
-
status: a.config.status,
|
|
44434
|
-
description: a.config.description,
|
|
44435
|
-
domains: a.config.domains
|
|
44436
|
-
};
|
|
44437
|
-
if (a.contract.inputSchema) {
|
|
44438
|
-
try {
|
|
44439
|
-
meta.inputSchema = external_exports.toJSONSchema(a.contract.inputSchema);
|
|
44440
|
-
} catch {
|
|
44441
|
-
schemaWarnings.push(`${a.config.resourceId}: inputSchema could not be serialized`);
|
|
44533
|
+
if (a.contract.outputSchema) {
|
|
44534
|
+
try {
|
|
44535
|
+
meta.outputSchema = external_exports.toJSONSchema(a.contract.outputSchema);
|
|
44536
|
+
} catch {
|
|
44537
|
+
schemaWarnings.push(`${a.config.resourceId}: outputSchema could not be serialized`);
|
|
44538
|
+
}
|
|
44442
44539
|
}
|
|
44443
|
-
|
|
44444
|
-
|
|
44445
|
-
|
|
44446
|
-
|
|
44447
|
-
|
|
44448
|
-
schemaWarnings.push(`${a.config.resourceId}: outputSchema could not be serialized`);
|
|
44540
|
+
return meta;
|
|
44541
|
+
});
|
|
44542
|
+
if (schemaWarnings.length > 0) {
|
|
44543
|
+
for (const warning of schemaWarnings) {
|
|
44544
|
+
console.log(source_default.yellow(` warn ${warning}`));
|
|
44449
44545
|
}
|
|
44546
|
+
console.log(source_default.gray(" Schemas will be unavailable on the platform for these resources."));
|
|
44547
|
+
console.log("");
|
|
44450
44548
|
}
|
|
44451
|
-
|
|
44452
|
-
|
|
44453
|
-
|
|
44454
|
-
|
|
44455
|
-
|
|
44456
|
-
|
|
44457
|
-
console.log(source_default.gray(" Schemas will be unavailable on the platform for these resources."));
|
|
44458
|
-
console.log("");
|
|
44459
|
-
}
|
|
44460
|
-
const bundleSpinner = ora("Bundling...").start();
|
|
44461
|
-
const wrapperPath = (0, import_path.resolve)("__elevasis_worker.ts");
|
|
44462
|
-
const bundleOutfile = (0, import_path.resolve)("dist/bundle.js");
|
|
44463
|
-
try {
|
|
44464
|
-
const entryImport = entryPath.replace(/\.ts$/, ".js");
|
|
44465
|
-
const wrapperContent = `import org from ${JSON.stringify(entryImport)}
|
|
44549
|
+
const bundleSpinner = ora("Bundling...").start();
|
|
44550
|
+
const wrapperPath = (0, import_path.resolve)("__elevasis_worker.ts");
|
|
44551
|
+
const bundleOutfile = (0, import_path.resolve)("dist/bundle.js");
|
|
44552
|
+
try {
|
|
44553
|
+
const entryImport = entryPath.replace(/\.ts$/, ".js");
|
|
44554
|
+
const wrapperContent = `import org from ${JSON.stringify(entryImport)}
|
|
44466
44555
|
import { startWorker } from '@elevasis/sdk/worker'
|
|
44467
44556
|
startWorker(org)
|
|
44468
44557
|
`;
|
|
44469
|
-
|
|
44470
|
-
|
|
44471
|
-
|
|
44472
|
-
|
|
44473
|
-
|
|
44474
|
-
|
|
44475
|
-
|
|
44476
|
-
|
|
44477
|
-
|
|
44478
|
-
await (0, import_promises.unlink)(wrapperPath);
|
|
44479
|
-
const bundleBuffer = await (0, import_promises.readFile)(bundleOutfile);
|
|
44480
|
-
const bundleSizeKB = Math.round(bundleBuffer.length / 1024);
|
|
44481
|
-
bundleSpinner.succeed(
|
|
44482
|
-
source_default.green("Bundling...") + source_default.white(" done") + source_default.gray(` (${bundleSizeKB} KB)`)
|
|
44483
|
-
);
|
|
44484
|
-
} catch (error46) {
|
|
44485
|
-
try {
|
|
44558
|
+
await (0, import_promises.writeFile)(wrapperPath, wrapperContent, "utf-8");
|
|
44559
|
+
await (0, import_promises.mkdir)((0, import_path.resolve)("dist"), { recursive: true });
|
|
44560
|
+
await esbuild.build({
|
|
44561
|
+
entryPoints: [wrapperPath],
|
|
44562
|
+
bundle: true,
|
|
44563
|
+
platform: "node",
|
|
44564
|
+
format: "cjs",
|
|
44565
|
+
outfile: bundleOutfile
|
|
44566
|
+
});
|
|
44486
44567
|
await (0, import_promises.unlink)(wrapperPath);
|
|
44487
|
-
|
|
44568
|
+
const bundleBuffer = await (0, import_promises.readFile)(bundleOutfile);
|
|
44569
|
+
const bundleSizeKB = Math.round(bundleBuffer.length / 1024);
|
|
44570
|
+
bundleSpinner.succeed(
|
|
44571
|
+
source_default.green("Bundling...") + source_default.white(" done") + source_default.gray(` (${bundleSizeKB} KB)`)
|
|
44572
|
+
);
|
|
44573
|
+
} catch (error46) {
|
|
44574
|
+
try {
|
|
44575
|
+
await (0, import_promises.unlink)(wrapperPath);
|
|
44576
|
+
} catch {
|
|
44577
|
+
}
|
|
44578
|
+
bundleSpinner.fail(source_default.red("Bundling failed"));
|
|
44579
|
+
throw error46;
|
|
44488
44580
|
}
|
|
44489
|
-
|
|
44490
|
-
|
|
44491
|
-
|
|
44492
|
-
|
|
44493
|
-
|
|
44494
|
-
|
|
44495
|
-
|
|
44496
|
-
|
|
44497
|
-
|
|
44498
|
-
|
|
44499
|
-
|
|
44500
|
-
|
|
44501
|
-
|
|
44502
|
-
console.error(source_default.gray(" ELEVASIS_PLATFORM_KEY=sk_..."));
|
|
44503
|
-
}
|
|
44504
|
-
throw new Error("Missing API key environment variable");
|
|
44505
|
-
}
|
|
44506
|
-
const metadata = {
|
|
44507
|
-
sdkVersion: SDK_VERSION,
|
|
44508
|
-
mode: env2,
|
|
44509
|
-
resources: { workflows, agents },
|
|
44510
|
-
...documentation ? { documentation } : {},
|
|
44511
|
-
...org.relationships ? { relationships: org.relationships } : {}
|
|
44512
|
-
};
|
|
44513
|
-
const form = new FormData();
|
|
44514
|
-
form.append("bundle", new Blob([bundleBuffer]), "bundle.js");
|
|
44515
|
-
form.append("metadata", JSON.stringify(metadata));
|
|
44516
|
-
const response = await fetch(`${apiUrl}/api/external/deploy`, {
|
|
44517
|
-
method: "POST",
|
|
44518
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
44519
|
-
body: form
|
|
44520
|
-
});
|
|
44521
|
-
if (!response.ok) {
|
|
44522
|
-
const errorText = await response.text();
|
|
44523
|
-
uploadSpinner.fail(source_default.red("Upload failed"));
|
|
44524
|
-
console.error(source_default.red(` ${response.status}: ${errorText}`));
|
|
44525
|
-
throw new Error(`Deploy upload failed (${response.status}): ${errorText}`);
|
|
44526
|
-
}
|
|
44527
|
-
const result = await response.json();
|
|
44528
|
-
uploadSpinner.succeed(
|
|
44529
|
-
source_default.green("Uploading...") + source_default.white(" done")
|
|
44530
|
-
);
|
|
44531
|
-
const totalResources = (org.workflows?.length ?? 0) + (org.agents?.length ?? 0);
|
|
44532
|
-
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
44533
|
-
if (result.status === "active") {
|
|
44534
|
-
console.log("");
|
|
44535
|
-
console.log(source_default.green.bold(` Deployed! ${totalResources} resource${totalResources !== 1 ? "s" : ""} live.`));
|
|
44536
|
-
if (result.deployId) {
|
|
44537
|
-
console.log(source_default.gray(` Version: ${result.deployId}`));
|
|
44581
|
+
const uploadSpinner = ora("Uploading...").start();
|
|
44582
|
+
try {
|
|
44583
|
+
const bundleBuffer = await (0, import_promises.readFile)(bundleOutfile);
|
|
44584
|
+
const apiKey = resolveApiKey(options2.prod);
|
|
44585
|
+
if (!apiKey) {
|
|
44586
|
+
uploadSpinner.fail(source_default.red("Missing API key environment variable"));
|
|
44587
|
+
console.error(source_default.gray(" Set it in your .env file or shell environment:"));
|
|
44588
|
+
if (!options2.prod && process.env.NODE_ENV === "development") {
|
|
44589
|
+
console.error(source_default.gray(" ELEVASIS_PLATFORM_KEY_DEV=sk_... (or ELEVASIS_PLATFORM_KEY as fallback)"));
|
|
44590
|
+
} else {
|
|
44591
|
+
console.error(source_default.gray(" ELEVASIS_PLATFORM_KEY=sk_..."));
|
|
44592
|
+
}
|
|
44593
|
+
throw new Error("Missing API key environment variable");
|
|
44538
44594
|
}
|
|
44539
|
-
|
|
44540
|
-
|
|
44541
|
-
|
|
44542
|
-
|
|
44543
|
-
|
|
44544
|
-
|
|
44595
|
+
const metadata = {
|
|
44596
|
+
sdkVersion: SDK_VERSION,
|
|
44597
|
+
mode: env2,
|
|
44598
|
+
resources: { workflows, agents },
|
|
44599
|
+
...documentation ? { documentation } : {},
|
|
44600
|
+
...org.relationships ? { relationships: org.relationships } : {}
|
|
44601
|
+
};
|
|
44602
|
+
const form = new FormData();
|
|
44603
|
+
form.append("bundle", new Blob([bundleBuffer]), "bundle.js");
|
|
44604
|
+
form.append("metadata", JSON.stringify(metadata));
|
|
44605
|
+
const response = await fetch(`${apiUrl}/api/external/deploy`, {
|
|
44606
|
+
method: "POST",
|
|
44607
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
44608
|
+
body: form
|
|
44609
|
+
});
|
|
44610
|
+
if (!response.ok) {
|
|
44611
|
+
const errorText = await response.text();
|
|
44612
|
+
uploadSpinner.fail(source_default.red("Upload failed"));
|
|
44613
|
+
console.error(source_default.red(` ${response.status}: ${errorText}`));
|
|
44614
|
+
throw new Error(`Deploy upload failed (${response.status}): ${errorText}`);
|
|
44615
|
+
}
|
|
44616
|
+
const result = await response.json();
|
|
44617
|
+
uploadSpinner.succeed(source_default.green("Uploading...") + source_default.white(" done"));
|
|
44618
|
+
const totalResources = (org.workflows?.length ?? 0) + (org.agents?.length ?? 0);
|
|
44619
|
+
const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
|
|
44620
|
+
if (result.status === "active") {
|
|
44621
|
+
console.log("");
|
|
44622
|
+
console.log(
|
|
44623
|
+
source_default.green.bold(` Deployed! ${totalResources} resource${totalResources !== 1 ? "s" : ""} live.`)
|
|
44624
|
+
);
|
|
44625
|
+
if (result.deployId) {
|
|
44626
|
+
console.log(source_default.gray(` Version: ${result.deployId}`));
|
|
44627
|
+
}
|
|
44628
|
+
console.log(source_default.gray(` Duration: ${elapsed}s`));
|
|
44629
|
+
} else if (result.status === "failed") {
|
|
44630
|
+
console.log("");
|
|
44631
|
+
console.log(source_default.red.bold(" Deploy failed."));
|
|
44632
|
+
if (result.error) {
|
|
44633
|
+
console.error(source_default.red(` ${result.error}`));
|
|
44634
|
+
}
|
|
44635
|
+
throw new Error(`Deploy failed: ${result.error ?? "unknown error"}`);
|
|
44636
|
+
} else {
|
|
44637
|
+
console.log("");
|
|
44638
|
+
console.log(source_default.yellow(` Deploy status: ${result.status ?? "unknown"}`));
|
|
44639
|
+
if (result.deployId) {
|
|
44640
|
+
console.log(source_default.gray(` Version: ${result.deployId}`));
|
|
44641
|
+
}
|
|
44545
44642
|
}
|
|
44546
|
-
|
|
44547
|
-
|
|
44548
|
-
|
|
44549
|
-
console.log(source_default.yellow(` Deploy status: ${result.status ?? "unknown"}`));
|
|
44550
|
-
if (result.deployId) {
|
|
44551
|
-
console.log(source_default.gray(` Version: ${result.deployId}`));
|
|
44643
|
+
} catch (error46) {
|
|
44644
|
+
if (uploadSpinner.isSpinning) {
|
|
44645
|
+
uploadSpinner.fail(source_default.red("Deploy failed"));
|
|
44552
44646
|
}
|
|
44647
|
+
throw error46;
|
|
44553
44648
|
}
|
|
44554
|
-
}
|
|
44555
|
-
|
|
44556
|
-
uploadSpinner.fail(source_default.red("Deploy failed"));
|
|
44557
|
-
}
|
|
44558
|
-
throw error46;
|
|
44559
|
-
}
|
|
44560
|
-
}));
|
|
44649
|
+
})
|
|
44650
|
+
);
|
|
44561
44651
|
}
|
|
44562
44652
|
|
|
44563
44653
|
// src/cli/commands/check.ts
|
|
@@ -45090,7 +45180,7 @@ var import_path3 = require("path");
|
|
|
45090
45180
|
var import_promises2 = require("fs/promises");
|
|
45091
45181
|
|
|
45092
45182
|
// src/cli/commands/templates/core/workspace.ts
|
|
45093
|
-
var TEMPLATE_VERSION =
|
|
45183
|
+
var TEMPLATE_VERSION = 28;
|
|
45094
45184
|
function configTemplate() {
|
|
45095
45185
|
return `import type { ElevasConfig } from '@elevasis/sdk'
|
|
45096
45186
|
|
|
@@ -45102,44 +45192,52 @@ export default {
|
|
|
45102
45192
|
`;
|
|
45103
45193
|
}
|
|
45104
45194
|
function packageJsonTemplate(organization) {
|
|
45105
|
-
return JSON.stringify(
|
|
45106
|
-
|
|
45107
|
-
|
|
45108
|
-
|
|
45109
|
-
|
|
45110
|
-
|
|
45111
|
-
|
|
45112
|
-
|
|
45113
|
-
|
|
45114
|
-
|
|
45115
|
-
|
|
45195
|
+
return JSON.stringify(
|
|
45196
|
+
{
|
|
45197
|
+
name: organization,
|
|
45198
|
+
private: true,
|
|
45199
|
+
type: "module",
|
|
45200
|
+
scripts: {
|
|
45201
|
+
"check-types": "tsc --noEmit",
|
|
45202
|
+
check: "elevasis-sdk check",
|
|
45203
|
+
deploy: "elevasis-sdk deploy"
|
|
45204
|
+
},
|
|
45205
|
+
dependencies: {
|
|
45206
|
+
"@elevasis/sdk": `^${SDK_VERSION}`
|
|
45207
|
+
},
|
|
45208
|
+
devDependencies: {
|
|
45209
|
+
typescript: "5.9.2",
|
|
45210
|
+
zod: "4.1.12"
|
|
45211
|
+
}
|
|
45116
45212
|
},
|
|
45117
|
-
|
|
45118
|
-
|
|
45119
|
-
|
|
45120
|
-
}
|
|
45121
|
-
}, null, 2) + "\n";
|
|
45213
|
+
null,
|
|
45214
|
+
2
|
|
45215
|
+
) + "\n";
|
|
45122
45216
|
}
|
|
45123
45217
|
function pnpmWorkspaceTemplate() {
|
|
45124
45218
|
return `packages: []
|
|
45125
45219
|
`;
|
|
45126
45220
|
}
|
|
45127
45221
|
function tsconfigTemplate() {
|
|
45128
|
-
return JSON.stringify(
|
|
45129
|
-
|
|
45130
|
-
|
|
45131
|
-
|
|
45132
|
-
|
|
45133
|
-
|
|
45134
|
-
|
|
45135
|
-
|
|
45136
|
-
|
|
45137
|
-
|
|
45138
|
-
|
|
45222
|
+
return JSON.stringify(
|
|
45223
|
+
{
|
|
45224
|
+
compilerOptions: {
|
|
45225
|
+
target: "ES2022",
|
|
45226
|
+
module: "ESNext",
|
|
45227
|
+
moduleResolution: "Bundler",
|
|
45228
|
+
strict: true,
|
|
45229
|
+
esModuleInterop: true,
|
|
45230
|
+
skipLibCheck: true,
|
|
45231
|
+
forceConsistentCasingInFileNames: true,
|
|
45232
|
+
isolatedModules: true,
|
|
45233
|
+
outDir: "./dist"
|
|
45234
|
+
},
|
|
45235
|
+
include: ["src"],
|
|
45236
|
+
exclude: ["node_modules", "dist"]
|
|
45139
45237
|
},
|
|
45140
|
-
|
|
45141
|
-
|
|
45142
|
-
|
|
45238
|
+
null,
|
|
45239
|
+
2
|
|
45240
|
+
) + "\n";
|
|
45143
45241
|
}
|
|
45144
45242
|
function envTemplate() {
|
|
45145
45243
|
return `ELEVASIS_PLATFORM_KEY=
|
|
@@ -45257,6 +45355,28 @@ function claudeSettingsTemplate() {
|
|
|
45257
45355
|
}
|
|
45258
45356
|
]
|
|
45259
45357
|
}
|
|
45358
|
+
],
|
|
45359
|
+
PostToolUse: [
|
|
45360
|
+
{
|
|
45361
|
+
matcher: "Write|Edit|MultiEdit",
|
|
45362
|
+
hooks: [
|
|
45363
|
+
{
|
|
45364
|
+
type: "command",
|
|
45365
|
+
command: "node .claude/hooks/post-edit-validate.mjs"
|
|
45366
|
+
}
|
|
45367
|
+
]
|
|
45368
|
+
}
|
|
45369
|
+
],
|
|
45370
|
+
PostToolUseFailure: [
|
|
45371
|
+
{
|
|
45372
|
+
matcher: "Bash",
|
|
45373
|
+
hooks: [
|
|
45374
|
+
{
|
|
45375
|
+
type: "command",
|
|
45376
|
+
command: "node .claude/hooks/tool-failure-recovery.mjs"
|
|
45377
|
+
}
|
|
45378
|
+
]
|
|
45379
|
+
}
|
|
45260
45380
|
]
|
|
45261
45381
|
}
|
|
45262
45382
|
},
|
|
@@ -46969,6 +47089,199 @@ When all plan steps are marked COMPLETE, suggest \`/work complete\` to finalize
|
|
|
46969
47089
|
- Completed tasks move OUT of \`docs/in-progress/\` to \`docs/<relevant-dir>/\`
|
|
46970
47090
|
`;
|
|
46971
47091
|
}
|
|
47092
|
+
function claudePostEditValidateHookTemplate() {
|
|
47093
|
+
return `#!/usr/bin/env node
|
|
47094
|
+
// post-edit-validate.mjs
|
|
47095
|
+
// PostToolUse hook \u2014 auto-formats with prettier, type-checks .ts/.tsx files.
|
|
47096
|
+
// Fires after Edit|Write|MultiEdit succeeds.
|
|
47097
|
+
|
|
47098
|
+
import { existsSync } from 'node:fs'
|
|
47099
|
+
import { resolve, normalize, extname, join, dirname } from 'node:path'
|
|
47100
|
+
import { execSync } from 'node:child_process'
|
|
47101
|
+
|
|
47102
|
+
const ROOT = process.env.CLAUDE_PROJECT_DIR ?? process.cwd()
|
|
47103
|
+
|
|
47104
|
+
// Extensions prettier should format
|
|
47105
|
+
const PRETTIER_EXTENSIONS = new Set([
|
|
47106
|
+
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json', '.css', '.md', '.mdx'
|
|
47107
|
+
])
|
|
47108
|
+
|
|
47109
|
+
// Extensions that trigger type-checking
|
|
47110
|
+
const TS_EXTENSIONS = new Set(['.ts', '.tsx'])
|
|
47111
|
+
|
|
47112
|
+
function findNearestTsconfig(startDir) {
|
|
47113
|
+
let dir = startDir
|
|
47114
|
+
const root = normalize(ROOT)
|
|
47115
|
+
while (dir.length >= root.length) {
|
|
47116
|
+
const candidate = join(dir, 'tsconfig.json')
|
|
47117
|
+
if (existsSync(candidate)) return candidate
|
|
47118
|
+
const parent = dirname(dir)
|
|
47119
|
+
if (parent === dir) break
|
|
47120
|
+
dir = parent
|
|
47121
|
+
}
|
|
47122
|
+
return null
|
|
47123
|
+
}
|
|
47124
|
+
|
|
47125
|
+
try {
|
|
47126
|
+
const chunks = []
|
|
47127
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
47128
|
+
const input = JSON.parse(Buffer.concat(chunks).toString())
|
|
47129
|
+
|
|
47130
|
+
const filePath = input.tool_input?.file_path
|
|
47131
|
+
if (!filePath) process.exit(0)
|
|
47132
|
+
|
|
47133
|
+
const ext = extname(filePath).toLowerCase()
|
|
47134
|
+
const absPath = normalize(resolve(filePath))
|
|
47135
|
+
if (!existsSync(absPath)) process.exit(0)
|
|
47136
|
+
|
|
47137
|
+
const results = []
|
|
47138
|
+
|
|
47139
|
+
// 1. Prettier
|
|
47140
|
+
if (PRETTIER_EXTENSIONS.has(ext)) {
|
|
47141
|
+
try {
|
|
47142
|
+
execSync('pnpm exec prettier --write "' + absPath + '"', {
|
|
47143
|
+
cwd: ROOT,
|
|
47144
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
47145
|
+
timeout: 10_000
|
|
47146
|
+
})
|
|
47147
|
+
} catch (err) {
|
|
47148
|
+
const stderr = err.stderr?.toString().trim() || ''
|
|
47149
|
+
if (stderr && !/ignored/i.test(stderr)) {
|
|
47150
|
+
results.push('Prettier error: ' + stderr.slice(0, 300))
|
|
47151
|
+
}
|
|
47152
|
+
}
|
|
47153
|
+
}
|
|
47154
|
+
|
|
47155
|
+
// 2. Type-check for .ts/.tsx
|
|
47156
|
+
if (TS_EXTENSIONS.has(ext)) {
|
|
47157
|
+
const tsconfig = findNearestTsconfig(dirname(absPath))
|
|
47158
|
+
if (tsconfig) {
|
|
47159
|
+
try {
|
|
47160
|
+
execSync('pnpm exec tsc --noEmit -p "' + tsconfig + '"', {
|
|
47161
|
+
cwd: ROOT,
|
|
47162
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
47163
|
+
timeout: 30_000,
|
|
47164
|
+
env: { ...process.env, NODE_OPTIONS: '--max-old-space-size=4096' }
|
|
47165
|
+
})
|
|
47166
|
+
} catch (err) {
|
|
47167
|
+
if (err.killed) process.exit(0) // Don't block on timeout
|
|
47168
|
+
const stdout = err.stdout?.toString() || ''
|
|
47169
|
+
if (stdout.includes('error TS')) {
|
|
47170
|
+
const errorLines = stdout
|
|
47171
|
+
.split('\\n')
|
|
47172
|
+
.filter(l => l.includes('error TS'))
|
|
47173
|
+
.slice(0, 10)
|
|
47174
|
+
results.push('Type errors after editing ' + filePath + ':\\n' + errorLines.join('\\n'))
|
|
47175
|
+
}
|
|
47176
|
+
}
|
|
47177
|
+
}
|
|
47178
|
+
}
|
|
47179
|
+
|
|
47180
|
+
// Output errors to Claude's context (silence = success)
|
|
47181
|
+
if (results.length > 0) {
|
|
47182
|
+
process.stderr.write(results.join('\\n\\n'))
|
|
47183
|
+
process.exit(2) // Exit 2 = send stderr as feedback to Claude
|
|
47184
|
+
}
|
|
47185
|
+
} catch {}
|
|
47186
|
+
|
|
47187
|
+
process.exit(0)
|
|
47188
|
+
`;
|
|
47189
|
+
}
|
|
47190
|
+
function claudeToolFailureRecoveryHookTemplate() {
|
|
47191
|
+
return `#!/usr/bin/env node
|
|
47192
|
+
// tool-failure-recovery.mjs
|
|
47193
|
+
// PostToolUseFailure hook \u2014 pattern-matches known Bash errors and returns
|
|
47194
|
+
// recovery advice via stderr + exit 2 (feedback to Claude).
|
|
47195
|
+
|
|
47196
|
+
const RECOVERY_TABLE = [
|
|
47197
|
+
{
|
|
47198
|
+
test: r => /JavaScript heap out of memory/i.test(r),
|
|
47199
|
+
advice: 'Out of memory.',
|
|
47200
|
+
fix: 'Run the command with NODE_OPTIONS="--max-old-space-size=4096".',
|
|
47201
|
+
why: 'Large TypeScript projects can exceed Node default heap limit.',
|
|
47202
|
+
},
|
|
47203
|
+
{
|
|
47204
|
+
test: r => /boundary hook/i.test(r) && /block|denied/i.test(r),
|
|
47205
|
+
advice: 'Command blocked by SDK boundary hook.',
|
|
47206
|
+
fix: 'Ask the user to run this command manually.',
|
|
47207
|
+
why: 'The boundary hook blocks gh CLI, destructive git operations, and file writes outside the project.',
|
|
47208
|
+
see: 'CLAUDE.md',
|
|
47209
|
+
},
|
|
47210
|
+
{
|
|
47211
|
+
test: r => /ENOENT/.test(r) && /node_modules/.test(r),
|
|
47212
|
+
advice: 'Missing node_modules dependency.',
|
|
47213
|
+
fix: 'Run: pnpm install',
|
|
47214
|
+
why: 'Dependencies are not installed or were cleared.',
|
|
47215
|
+
},
|
|
47216
|
+
{
|
|
47217
|
+
test: r => /ERR_MODULE_NOT_FOUND/.test(r) && /@elevasis\\/sdk/.test(r),
|
|
47218
|
+
advice: '@elevasis/sdk module not found.',
|
|
47219
|
+
fix: 'Run: pnpm install \u2014 then verify @elevasis/sdk is in package.json dependencies.',
|
|
47220
|
+
why: 'The SDK package is not installed or the version is mismatched.',
|
|
47221
|
+
},
|
|
47222
|
+
{
|
|
47223
|
+
test: r => /ERR_MODULE_NOT_FOUND/.test(r),
|
|
47224
|
+
advice: 'Module not found at import path.',
|
|
47225
|
+
fix: 'Check the import path and verify the package is installed (pnpm install).',
|
|
47226
|
+
why: 'The import path does not match any installed package or local file.',
|
|
47227
|
+
},
|
|
47228
|
+
{
|
|
47229
|
+
test: r => /TS2307/.test(r) || (/cannot find/i.test(r) && /declaration/i.test(r)),
|
|
47230
|
+
advice: 'TypeScript cannot resolve module or declaration file.',
|
|
47231
|
+
fix: 'Check that the package is installed and tsconfig paths are correct.',
|
|
47232
|
+
why: 'Missing dependency or incorrect TypeScript configuration.',
|
|
47233
|
+
},
|
|
47234
|
+
{
|
|
47235
|
+
test: r => /EPERM/.test(r) || /permission denied/i.test(r),
|
|
47236
|
+
advice: 'Permission denied (EPERM).',
|
|
47237
|
+
fix: 'Close the file in any other process (editor, terminal, or dev server) and retry.',
|
|
47238
|
+
why: 'On Windows, files locked by another process cannot be written to.',
|
|
47239
|
+
},
|
|
47240
|
+
{
|
|
47241
|
+
test: r => /lockfile/i.test(r) && /conflict|outdated|ERR_PNPM/i.test(r),
|
|
47242
|
+
advice: 'pnpm lockfile conflict or outdated.',
|
|
47243
|
+
fix: 'Run: pnpm install to regenerate the lockfile.',
|
|
47244
|
+
why: 'The lockfile is out of sync with package.json changes.',
|
|
47245
|
+
},
|
|
47246
|
+
{
|
|
47247
|
+
test: r => /elevasis-sdk check/.test(r) || /elevasis-sdk deploy/.test(r),
|
|
47248
|
+
advice: 'elevasis-sdk CLI command failed.',
|
|
47249
|
+
fix: 'Check the error output above. Common causes: missing .env ELEVASIS_API_KEY, invalid resource schemas, or network issues.',
|
|
47250
|
+
why: 'The SDK CLI validates resources and communicates with the platform API.',
|
|
47251
|
+
},
|
|
47252
|
+
{
|
|
47253
|
+
test: r => /EADDRINUSE/.test(r),
|
|
47254
|
+
advice: 'Port already in use.',
|
|
47255
|
+
fix: 'Find and kill the process using the port, or use a different port.',
|
|
47256
|
+
why: 'A previous dev server or process is still holding the port.',
|
|
47257
|
+
},
|
|
47258
|
+
]
|
|
47259
|
+
|
|
47260
|
+
function formatRecovery(entry) {
|
|
47261
|
+
let msg = 'FAILED: ' + entry.advice + '\\nFIX: ' + entry.fix
|
|
47262
|
+
if (entry.why) msg += '\\nWHY: ' + entry.why
|
|
47263
|
+
if (entry.see) msg += '\\nSEE: ' + entry.see
|
|
47264
|
+
return msg
|
|
47265
|
+
}
|
|
47266
|
+
|
|
47267
|
+
try {
|
|
47268
|
+
const chunks = []
|
|
47269
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
47270
|
+
const input = JSON.parse(Buffer.concat(chunks).toString())
|
|
47271
|
+
|
|
47272
|
+
const response = input.tool_response ?? ''
|
|
47273
|
+
|
|
47274
|
+
for (const entry of RECOVERY_TABLE) {
|
|
47275
|
+
if (entry.test(response)) {
|
|
47276
|
+
process.stderr.write(formatRecovery(entry))
|
|
47277
|
+
process.exit(2)
|
|
47278
|
+
}
|
|
47279
|
+
}
|
|
47280
|
+
} catch {}
|
|
47281
|
+
|
|
47282
|
+
process.exit(0)
|
|
47283
|
+
`;
|
|
47284
|
+
}
|
|
46972
47285
|
|
|
46973
47286
|
// src/cli/commands/templates/core/resources.ts
|
|
46974
47287
|
function starterTemplate() {
|
|
@@ -47144,6 +47457,8 @@ function getManagedTemplates(ctx = {}) {
|
|
|
47144
47457
|
".claude/settings.json": claudeSettingsTemplate,
|
|
47145
47458
|
".claude/scripts/statusline-command.js": claudeStatuslineScriptTemplate,
|
|
47146
47459
|
".claude/hooks/enforce-sdk-boundary.mjs": claudeSdkBoundaryHookTemplate,
|
|
47460
|
+
".claude/hooks/post-edit-validate.mjs": claudePostEditValidateHookTemplate,
|
|
47461
|
+
".claude/hooks/tool-failure-recovery.mjs": claudeToolFailureRecoveryHookTemplate,
|
|
47147
47462
|
".claude/commands/tutorial.md": claudeTutorialCommandTemplate,
|
|
47148
47463
|
".claude/commands/meta.md": claudeMetaCommandTemplate,
|
|
47149
47464
|
".claude/commands/work.md": claudeWorkCommandTemplate,
|
|
@@ -47356,6 +47671,8 @@ var MANAGED_FILES = [
|
|
|
47356
47671
|
"CLAUDE.md",
|
|
47357
47672
|
".claude/settings.json",
|
|
47358
47673
|
".claude/hooks/enforce-sdk-boundary.mjs",
|
|
47674
|
+
".claude/hooks/post-edit-validate.mjs",
|
|
47675
|
+
".claude/hooks/tool-failure-recovery.mjs",
|
|
47359
47676
|
".claude/commands/tutorial.md",
|
|
47360
47677
|
".claude/commands/meta.md",
|
|
47361
47678
|
".claude/commands/work.md",
|
|
@@ -47370,96 +47687,100 @@ var MANAGED_FILES = [
|
|
|
47370
47687
|
];
|
|
47371
47688
|
var SCAFFOLD_FILES = [...INIT_ONLY_FILES, ...MANAGED_FILES];
|
|
47372
47689
|
function registerInitCommand(program3) {
|
|
47373
|
-
program3.command("init [directory]").description("Scaffold a new Elevasis workspace\n Example: elevasis-sdk init my-workspace").option("--force", "Overwrite existing files").option("--ui", "Include a Vite + React UI app in ui/").action(
|
|
47374
|
-
|
|
47375
|
-
|
|
47376
|
-
|
|
47377
|
-
|
|
47378
|
-
|
|
47379
|
-
|
|
47380
|
-
|
|
47381
|
-
|
|
47382
|
-
|
|
47383
|
-
|
|
47384
|
-
|
|
47385
|
-
|
|
47386
|
-
if (conflicts.length > 0) {
|
|
47387
|
-
console.error(source_default.red("Files already exist:"));
|
|
47388
|
-
for (const f of conflicts) {
|
|
47389
|
-
console.error(source_default.gray(` ${f}`));
|
|
47690
|
+
program3.command("init [directory]").description("Scaffold a new Elevasis workspace\n Example: elevasis-sdk init my-workspace").option("--force", "Overwrite existing files").option("--ui", "Include a Vite + React UI app in ui/").action(
|
|
47691
|
+
wrapAction("init", async (directory, options2) => {
|
|
47692
|
+
const targetDir = directory ? (0, import_path3.resolve)(directory) : process.cwd();
|
|
47693
|
+
const orgSlug = toSlug((0, import_path3.basename)(targetDir));
|
|
47694
|
+
if (!options2.force) {
|
|
47695
|
+
const filesToCheck = options2.ui ? [...SCAFFOLD_FILES, ...UI_INIT_FILES] : SCAFFOLD_FILES;
|
|
47696
|
+
const conflicts = [];
|
|
47697
|
+
for (const file2 of filesToCheck) {
|
|
47698
|
+
try {
|
|
47699
|
+
await (0, import_promises2.access)((0, import_path3.resolve)(targetDir, file2));
|
|
47700
|
+
conflicts.push(file2);
|
|
47701
|
+
} catch {
|
|
47702
|
+
}
|
|
47390
47703
|
}
|
|
47391
|
-
|
|
47392
|
-
|
|
47393
|
-
|
|
47394
|
-
|
|
47395
|
-
|
|
47396
|
-
|
|
47397
|
-
|
|
47398
|
-
|
|
47399
|
-
|
|
47400
|
-
|
|
47401
|
-
|
|
47402
|
-
|
|
47403
|
-
|
|
47404
|
-
|
|
47405
|
-
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "
|
|
47406
|
-
|
|
47407
|
-
|
|
47408
|
-
|
|
47409
|
-
|
|
47410
|
-
|
|
47411
|
-
|
|
47412
|
-
|
|
47413
|
-
|
|
47414
|
-
|
|
47415
|
-
|
|
47416
|
-
|
|
47417
|
-
|
|
47418
|
-
|
|
47419
|
-
|
|
47420
|
-
|
|
47421
|
-
|
|
47422
|
-
|
|
47423
|
-
|
|
47424
|
-
|
|
47425
|
-
|
|
47426
|
-
|
|
47427
|
-
|
|
47428
|
-
|
|
47429
|
-
|
|
47430
|
-
|
|
47431
|
-
|
|
47432
|
-
|
|
47433
|
-
|
|
47434
|
-
|
|
47435
|
-
|
|
47436
|
-
|
|
47437
|
-
|
|
47438
|
-
|
|
47439
|
-
|
|
47440
|
-
|
|
47441
|
-
|
|
47442
|
-
|
|
47443
|
-
|
|
47444
|
-
|
|
47445
|
-
|
|
47446
|
-
|
|
47447
|
-
|
|
47448
|
-
|
|
47449
|
-
|
|
47450
|
-
|
|
47451
|
-
|
|
47452
|
-
|
|
47453
|
-
console.log(source_default.gray(" elevasis-sdk check"));
|
|
47454
|
-
console.log(source_default.gray(" elevasis-sdk deploy"));
|
|
47455
|
-
if (options2.ui) {
|
|
47704
|
+
if (conflicts.length > 0) {
|
|
47705
|
+
console.error(source_default.red("Files already exist:"));
|
|
47706
|
+
for (const f of conflicts) {
|
|
47707
|
+
console.error(source_default.gray(` ${f}`));
|
|
47708
|
+
}
|
|
47709
|
+
console.error(source_default.gray("\n Use --force to overwrite."));
|
|
47710
|
+
throw new Error("Scaffold conflict");
|
|
47711
|
+
}
|
|
47712
|
+
}
|
|
47713
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "src/operations"), { recursive: true });
|
|
47714
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "src/example"), { recursive: true });
|
|
47715
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "src/shared"), { recursive: true });
|
|
47716
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "docs/in-progress"), { recursive: true });
|
|
47717
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/hooks"), { recursive: true });
|
|
47718
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/scripts"), { recursive: true });
|
|
47719
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/commands"), { recursive: true });
|
|
47720
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/skills/creds"), { recursive: true });
|
|
47721
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/rules"), { recursive: true });
|
|
47722
|
+
if (options2.ui) {
|
|
47723
|
+
await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "ui/src"), { recursive: true });
|
|
47724
|
+
}
|
|
47725
|
+
const files = {
|
|
47726
|
+
"elevasis.config.ts": configTemplate(),
|
|
47727
|
+
"package.json": packageJsonTemplate(orgSlug),
|
|
47728
|
+
"pnpm-workspace.yaml": pnpmWorkspaceTemplate(),
|
|
47729
|
+
"tsconfig.json": tsconfigTemplate(),
|
|
47730
|
+
".env": envTemplate(),
|
|
47731
|
+
".npmrc": npmrcTemplate(),
|
|
47732
|
+
".gitignore": gitignoreTemplate({ hasUI: options2.ui }),
|
|
47733
|
+
"src/index.ts": starterTemplate(),
|
|
47734
|
+
"src/operations/platform-status.ts": platformStatusTemplate(),
|
|
47735
|
+
"src/operations/index.ts": operationsBarrelTemplate(),
|
|
47736
|
+
"src/example/echo.ts": starterWorkflowTemplate(),
|
|
47737
|
+
"src/example/index.ts": exampleBarrelTemplate(),
|
|
47738
|
+
"src/shared/.gitkeep": "",
|
|
47739
|
+
"docs/index.mdx": docsIndexTemplate(orgSlug),
|
|
47740
|
+
"docs/in-progress/.gitkeep": "",
|
|
47741
|
+
"CLAUDE.md": claudeMdTemplate({ hasUI: options2.ui }),
|
|
47742
|
+
".claude/settings.json": claudeSettingsTemplate(),
|
|
47743
|
+
".claude/hooks/enforce-sdk-boundary.mjs": claudeSdkBoundaryHookTemplate(),
|
|
47744
|
+
".claude/hooks/post-edit-validate.mjs": claudePostEditValidateHookTemplate(),
|
|
47745
|
+
".claude/hooks/tool-failure-recovery.mjs": claudeToolFailureRecoveryHookTemplate(),
|
|
47746
|
+
".claude/commands/tutorial.md": claudeTutorialCommandTemplate(),
|
|
47747
|
+
".claude/commands/meta.md": claudeMetaCommandTemplate(),
|
|
47748
|
+
".claude/commands/work.md": claudeWorkCommandTemplate(),
|
|
47749
|
+
".claude/commands/docs.md": claudeDocsCommandTemplate(),
|
|
47750
|
+
".claude/skills/creds/SKILL.md": claudeCredsSkillTemplate(),
|
|
47751
|
+
".claude/rules/sdk-patterns.md": claudeSdkPatternsRuleTemplate(),
|
|
47752
|
+
".claude/rules/workspace-patterns.md": claudeWorkspaceRulesTemplate(),
|
|
47753
|
+
".claude/rules/docs-authoring.md": claudeDocsAuthoringRuleTemplate(),
|
|
47754
|
+
".claude/rules/memory-conventions.md": claudeMemoryConventionsRuleTemplate(),
|
|
47755
|
+
".claude/rules/project-map.md": claudeProjectMapRuleTemplate(),
|
|
47756
|
+
".claude/rules/task-tracking.md": claudeTaskTrackingRuleTemplate(),
|
|
47757
|
+
".claude/scripts/statusline-command.js": claudeStatuslineScriptTemplate()
|
|
47758
|
+
};
|
|
47759
|
+
if (options2.ui) {
|
|
47760
|
+
Object.assign(files, getUIFiles(orgSlug));
|
|
47761
|
+
}
|
|
47762
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
47763
|
+
await (0, import_promises2.writeFile)((0, import_path3.resolve)(targetDir, filePath), content, "utf-8");
|
|
47764
|
+
}
|
|
47765
|
+
console.log(source_default.green.bold(" Workspace created!"));
|
|
47456
47766
|
console.log("");
|
|
47457
|
-
console.log(source_default.gray("
|
|
47458
|
-
|
|
47459
|
-
|
|
47460
|
-
|
|
47461
|
-
|
|
47462
|
-
|
|
47767
|
+
console.log(source_default.gray(" Next steps:"));
|
|
47768
|
+
if (directory) {
|
|
47769
|
+
console.log(source_default.gray(` cd ${directory}`));
|
|
47770
|
+
}
|
|
47771
|
+
console.log(source_default.gray(" pnpm install"));
|
|
47772
|
+
console.log(source_default.gray(" # Add your API key to .env"));
|
|
47773
|
+
console.log(source_default.gray(" elevasis-sdk check"));
|
|
47774
|
+
console.log(source_default.gray(" elevasis-sdk deploy"));
|
|
47775
|
+
if (options2.ui) {
|
|
47776
|
+
console.log("");
|
|
47777
|
+
console.log(source_default.gray(" UI app:"));
|
|
47778
|
+
console.log(source_default.gray(" cd ui && pnpm install"));
|
|
47779
|
+
console.log(source_default.gray(" # Set VITE_WORKOS_CLIENT_ID in ui/.env"));
|
|
47780
|
+
console.log(source_default.gray(" pnpm dev"));
|
|
47781
|
+
}
|
|
47782
|
+
})
|
|
47783
|
+
);
|
|
47463
47784
|
}
|
|
47464
47785
|
function toSlug(name) {
|
|
47465
47786
|
const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^[^a-z]+/, "").replace(/-+/g, "-").replace(/-$/, "");
|