@elevasis/sdk 0.5.13 → 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 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
  *
@@ -43478,6 +43531,21 @@ var ResourceRegistry = class {
43478
43531
  }
43479
43532
  return null;
43480
43533
  }
43534
+ /**
43535
+ * Get statistics about remotely-deployed resources
43536
+ * Used by the health endpoint for platform-wide deployment visibility.
43537
+ */
43538
+ getRemoteStats() {
43539
+ const orgs = /* @__PURE__ */ new Set();
43540
+ for (const key of this.remoteResources.keys()) {
43541
+ const orgName = key.split("/")[0];
43542
+ orgs.add(orgName);
43543
+ }
43544
+ return {
43545
+ activeOrgs: orgs.size,
43546
+ totalResources: this.remoteResources.size
43547
+ };
43548
+ }
43481
43549
  // ============================================================================
43482
43550
  // Resource Manifest Accessors
43483
43551
  // ============================================================================
@@ -43783,7 +43851,7 @@ async function apiDelete(endpoint, apiUrl = resolveApiUrl()) {
43783
43851
  // package.json
43784
43852
  var package_default = {
43785
43853
  name: "@elevasis/sdk",
43786
- version: "0.5.13",
43854
+ version: "0.5.15",
43787
43855
  description: "SDK for building Elevasis organization resources",
43788
43856
  type: "module",
43789
43857
  bin: {
@@ -43869,9 +43937,7 @@ async function scanDocumentation() {
43869
43937
  const raw = await (0, import_promises.readFile)(fullPath, "utf-8");
43870
43938
  const fileSize = Buffer.byteLength(raw, "utf-8");
43871
43939
  if (fileSize > 100 * 1024) {
43872
- throw new Error(
43873
- `Documentation file exceeds 100KB: docs/${relPath} (${Math.round(fileSize / 1024)}KB)`
43874
- );
43940
+ throw new Error(`Documentation file exceeds 100KB: docs/${relPath} (${Math.round(fileSize / 1024)}KB)`);
43875
43941
  }
43876
43942
  totalSize += fileSize;
43877
43943
  if (totalSize > 1024 * 1024) {
@@ -43924,7 +43990,9 @@ async function generateResourceMap(org) {
43924
43990
  );
43925
43991
  for (const w of workflows) {
43926
43992
  const desc = escapeMdx(w.config.description);
43927
- lines.push(`| \`${w.config.resourceId}\` | ${escapeMdx(w.config.name)} | ${w.config.version} | ${w.config.status} | ${desc} |`);
43993
+ lines.push(
43994
+ `| \`${w.config.resourceId}\` | ${escapeMdx(w.config.name)} | ${w.config.version} | ${w.config.status} | ${desc} |`
43995
+ );
43928
43996
  }
43929
43997
  lines.push("");
43930
43998
  }
@@ -43937,11 +44005,16 @@ async function generateResourceMap(org) {
43937
44005
  );
43938
44006
  for (const a of agents) {
43939
44007
  const desc = escapeMdx(a.config.description);
43940
- lines.push(`| \`${a.config.resourceId}\` | ${escapeMdx(a.config.name)} | ${a.config.version} | ${a.config.status} | ${desc} |`);
44008
+ lines.push(
44009
+ `| \`${a.config.resourceId}\` | ${escapeMdx(a.config.name)} | ${a.config.version} | ${a.config.status} | ${desc} |`
44010
+ );
43941
44011
  }
43942
44012
  lines.push("");
43943
44013
  }
43944
- lines.push(`**Total:** ${workflows.length + agents.length} resources (${workflows.length} workflows, ${agents.length} agents)`, "");
44014
+ lines.push(
44015
+ `**Total:** ${workflows.length + agents.length} resources (${workflows.length} workflows, ${agents.length} agents)`,
44016
+ ""
44017
+ );
43945
44018
  await (0, import_promises.mkdir)((0, import_path.resolve)("docs"), { recursive: true });
43946
44019
  await (0, import_promises.writeFile)((0, import_path.resolve)("docs/resource-map.mdx"), lines.join("\n"), "utf-8");
43947
44020
  }
@@ -44005,8 +44078,12 @@ async function generateProjectMap(org) {
44005
44078
  if (resourceCount === 0) {
44006
44079
  types = "(utilities)";
44007
44080
  } else {
44008
- const wCount = workflows.filter((w) => Array.isArray(w.config.domains) && w.config.domains.includes(domainName)).length;
44009
- const aCount = agents.filter((a) => Array.isArray(a.config.domains) && a.config.domains.includes(domainName)).length;
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;
44010
44087
  const parts = [];
44011
44088
  if (wCount > 0) parts.push(`${wCount} workflow${wCount !== 1 ? "s" : ""}`);
44012
44089
  if (aCount > 0) parts.push(`${aCount} agent${aCount !== 1 ? "s" : ""}`);
@@ -44118,10 +44195,7 @@ async function generateProjectMap(org) {
44118
44195
  if (categories.length === 0) {
44119
44196
  lines.push("SDK reference found but no categories parsed.", "");
44120
44197
  } else {
44121
- lines.push(
44122
- "| Category | Files | Covers |",
44123
- "| --- | --- | --- |"
44124
- );
44198
+ lines.push("| Category | Files | Covers |", "| --- | --- | --- |");
44125
44199
  for (const cat of categories) {
44126
44200
  const covers = cat.titles.slice(0, 5).join(", ") + (cat.titles.length > 5 ? ", ..." : "");
44127
44201
  lines.push(`| ${escapeMdx(cat.name)} | ${cat.count} | ${escapeMdx(covers)} |`);
@@ -44139,10 +44213,7 @@ async function generateProjectMap(org) {
44139
44213
  if (cmdFiles.length === 0) {
44140
44214
  lines.push("No commands found.", "");
44141
44215
  } else {
44142
- lines.push(
44143
- "| Command | File | Purpose |",
44144
- "| --- | --- | --- |"
44145
- );
44216
+ lines.push("| Command | File | Purpose |", "| --- | --- | --- |");
44146
44217
  for (const f of cmdFiles) {
44147
44218
  const cmdName = f.name.replace(/\.md$/, "");
44148
44219
  let purpose = "";
@@ -44171,10 +44242,7 @@ async function generateProjectMap(org) {
44171
44242
  if (ruleFiles.length === 0) {
44172
44243
  lines.push("No rules found.", "");
44173
44244
  } else {
44174
- lines.push(
44175
- "| Rule | File | Scope |",
44176
- "| --- | --- | --- |"
44177
- );
44245
+ lines.push("| Rule | File | Scope |", "| --- | --- | --- |");
44178
44246
  for (const f of ruleFiles) {
44179
44247
  const ruleName = f.name.replace(/\.md$/, "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
44180
44248
  let scope = "";
@@ -44205,10 +44273,7 @@ async function generateProjectMap(org) {
44205
44273
  if (skillDirs.length === 0) {
44206
44274
  lines.push("No skills found.", "");
44207
44275
  } else {
44208
- lines.push(
44209
- "| Skill | File | Trigger |",
44210
- "| --- | --- | --- |"
44211
- );
44276
+ lines.push("| Skill | File | Trigger |", "| --- | --- | --- |");
44212
44277
  for (const d of skillDirs) {
44213
44278
  const skillFile = (0, import_path.resolve)(".claude/skills", d.name, "SKILL.md");
44214
44279
  let trigger = "";
@@ -44264,10 +44329,7 @@ async function generateProjectMap(org) {
44264
44329
  if (memoryFiles.length === 0) {
44265
44330
  lines.push("No memory files found.", "");
44266
44331
  } else {
44267
- lines.push(
44268
- "| File | Purpose | Last Modified |",
44269
- "| --- | --- | --- |"
44270
- );
44332
+ lines.push("| File | Purpose | Last Modified |", "| --- | --- | --- |");
44271
44333
  for (const m of memoryFiles) {
44272
44334
  lines.push(`| .claude/memory/${m.rel} | ${escapeMdx(m.purpose)} | ${m.mtime} |`);
44273
44335
  }
@@ -44299,250 +44361,293 @@ async function generateProjectMap(org) {
44299
44361
  await (0, import_promises.mkdir)((0, import_path.resolve)("docs"), { recursive: true });
44300
44362
  await (0, import_promises.writeFile)((0, import_path.resolve)("docs/project-map.mdx"), lines.join("\n"), "utf-8");
44301
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
+ }
44302
44393
  function registerDeployCommand(program3) {
44303
- program3.command("deploy").description("Validate, bundle, upload, and deploy project resources\n Example: elevasis-sdk deploy --api-url http://localhost:5170").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(wrapAction("deploy", async (options2) => {
44304
- const startTime = Date.now();
44305
- const apiUrl = resolveApiUrl(options2.apiUrl, options2.prod);
44306
- const env2 = resolveEnvironment(options2.prod);
44307
- const entryPath = options2.entry ?? "./src/index.ts";
44308
- const authSpinner = ora("Authenticating...").start();
44309
- let orgName;
44310
- try {
44311
- const me = await apiGet("/api/external/me", apiUrl);
44312
- orgName = me.organizationName;
44313
- authSpinner.succeed(
44314
- source_default.green("Authenticating...") + source_default.white(" done") + source_default.gray(` (${orgName})`)
44315
- );
44316
- } catch (error46) {
44317
- authSpinner.fail(source_default.red("Authentication failed"));
44318
- const errMsg = error46 instanceof Error ? error46.message : String(error46);
44319
- if (errMsg.includes("401") || errMsg.toLowerCase().includes("unauthorized")) {
44320
- const keyVar = !options2.prod && process.env.NODE_ENV === "development" && process.env.ELEVASIS_PLATFORM_KEY_DEV ? "ELEVASIS_PLATFORM_KEY_DEV" : "ELEVASIS_PLATFORM_KEY";
44321
- console.error(source_default.red(" Invalid API key."));
44322
- console.error(source_default.gray(` Your ${keyVar} was rejected by the server.`));
44323
- console.error(source_default.gray(" Check your .env file and verify the key in the Elevasis dashboard."));
44324
- } else {
44325
- console.error(source_default.gray(" Check your API key and API URL."));
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;
44326
44422
  }
44327
- throw error46;
44328
- }
44329
- const validateSpinner = ora("Validating...").start();
44330
- let org;
44331
- try {
44332
- const jiti = (0, import_jiti.createJiti)(import_meta.url);
44333
- const entryModule = await jiti.import((0, import_path.resolve)(entryPath));
44334
- org = entryModule.default;
44335
- if (!org) {
44336
- validateSpinner.fail("Invalid entry: no default export found");
44337
- console.error(source_default.gray(` Entry file: ${(0, import_path.resolve)(entryPath)}`));
44338
- throw new Error("Invalid entry: no default export found");
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;
44339
44464
  }
44340
- new ResourceRegistry({ [orgName]: org });
44341
- const workflowCount = org.workflows?.length ?? 0;
44342
- const agentCount = org.agents?.length ?? 0;
44343
- const totalCount = workflowCount + agentCount;
44344
- validateSpinner.succeed(
44345
- source_default.green("Validating...") + source_default.white(" done") + source_default.gray(` (${totalCount} resource${totalCount !== 1 ? "s" : ""}, 0 errors)`)
44346
- );
44347
- console.log("");
44348
- console.log(source_default.gray(` Org: ${orgName}`));
44349
- console.log(source_default.gray(` Target: ${apiUrl} (${env2})`));
44350
- console.log("");
44351
- for (const w of org.workflows ?? []) {
44352
- 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
+ );
44353
44476
  }
44354
- for (const a of org.agents ?? []) {
44355
- console.log(source_default.gray(` agent ${source_default.white(a.config.resourceId)} v${a.config.version}`));
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
+ );
44356
44490
  }
44357
- console.log("");
44358
- } catch (error46) {
44359
- if (error46 instanceof RegistryValidationError) {
44360
- validateSpinner.fail(source_default.red("Validation failed"));
44361
- console.error("");
44362
- console.error(source_default.red(` ERROR ${error46.message}`));
44363
- if (error46.resourceId) {
44364
- console.error(source_default.gray(` Resource: ${error46.resourceId}`));
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
+ }
44365
44507
  }
44366
- console.error("");
44367
- console.error(source_default.gray(" Deploy aborted."));
44368
- }
44369
- throw error46;
44370
- }
44371
- await generateResourceMap(org);
44372
- await generateProjectMap(org);
44373
- const documentation = await scanDocumentation();
44374
- if (documentation) {
44375
- console.log(source_default.gray(` docs ${source_default.white(String(documentation.length))} file${documentation.length !== 1 ? "s" : ""}`));
44376
- }
44377
- const triggerCount = org.triggers?.length ?? 0;
44378
- const integrationCount = org.integrations?.length ?? 0;
44379
- const checkpointCount = org.humanCheckpoints?.length ?? 0;
44380
- if (triggerCount > 0) console.log(source_default.gray(` triggers ${source_default.white(String(triggerCount))}`));
44381
- if (integrationCount > 0) console.log(source_default.gray(` integrations ${source_default.white(String(integrationCount))}`));
44382
- if (checkpointCount > 0) console.log(source_default.gray(` checkpoints ${source_default.white(String(checkpointCount))}`));
44383
- const relationshipCount = org.relationships ? Object.keys(org.relationships).length : 0;
44384
- if (relationshipCount > 0) {
44385
- console.log(source_default.gray(` rels ${source_default.white(String(relationshipCount))} resource${relationshipCount !== 1 ? "s" : ""}`));
44386
- }
44387
- const schemaWarnings = [];
44388
- const workflows = (org.workflows ?? []).map((w) => {
44389
- const meta = {
44390
- resourceId: w.config.resourceId,
44391
- name: w.config.name,
44392
- version: w.config.version,
44393
- status: w.config.status,
44394
- description: w.config.description,
44395
- domains: w.config.domains
44396
- };
44397
- if (w.contract.inputSchema) {
44398
- try {
44399
- meta.inputSchema = external_exports.toJSONSchema(w.contract.inputSchema);
44400
- } catch {
44401
- 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
+ }
44402
44514
  }
44403
- }
44404
- if (w.contract.outputSchema) {
44405
- try {
44406
- meta.outputSchema = external_exports.toJSONSchema(w.contract.outputSchema);
44407
- } catch {
44408
- schemaWarnings.push(`${w.config.resourceId}: outputSchema could not be serialized`);
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
+ }
44409
44532
  }
44410
- }
44411
- return meta;
44412
- });
44413
- const agents = (org.agents ?? []).map((a) => {
44414
- const meta = {
44415
- resourceId: a.config.resourceId,
44416
- name: a.config.name,
44417
- version: a.config.version,
44418
- status: a.config.status,
44419
- description: a.config.description,
44420
- domains: a.config.domains
44421
- };
44422
- if (a.contract.inputSchema) {
44423
- try {
44424
- meta.inputSchema = external_exports.toJSONSchema(a.contract.inputSchema);
44425
- } catch {
44426
- 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
+ }
44427
44539
  }
44428
- }
44429
- if (a.contract.outputSchema) {
44430
- try {
44431
- meta.outputSchema = external_exports.toJSONSchema(a.contract.outputSchema);
44432
- } catch {
44433
- 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}`));
44434
44545
  }
44546
+ console.log(source_default.gray(" Schemas will be unavailable on the platform for these resources."));
44547
+ console.log("");
44435
44548
  }
44436
- return meta;
44437
- });
44438
- if (schemaWarnings.length > 0) {
44439
- for (const warning of schemaWarnings) {
44440
- console.log(source_default.yellow(` warn ${warning}`));
44441
- }
44442
- console.log(source_default.gray(" Schemas will be unavailable on the platform for these resources."));
44443
- console.log("");
44444
- }
44445
- const bundleSpinner = ora("Bundling...").start();
44446
- const wrapperPath = (0, import_path.resolve)("__elevasis_worker.ts");
44447
- const bundleOutfile = (0, import_path.resolve)("dist/bundle.js");
44448
- try {
44449
- const entryImport = entryPath.replace(/\.ts$/, ".js");
44450
- 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)}
44451
44555
  import { startWorker } from '@elevasis/sdk/worker'
44452
44556
  startWorker(org)
44453
44557
  `;
44454
- await (0, import_promises.writeFile)(wrapperPath, wrapperContent, "utf-8");
44455
- await (0, import_promises.mkdir)((0, import_path.resolve)("dist"), { recursive: true });
44456
- await esbuild.build({
44457
- entryPoints: [wrapperPath],
44458
- bundle: true,
44459
- platform: "node",
44460
- format: "cjs",
44461
- outfile: bundleOutfile
44462
- });
44463
- await (0, import_promises.unlink)(wrapperPath);
44464
- const bundleBuffer = await (0, import_promises.readFile)(bundleOutfile);
44465
- const bundleSizeKB = Math.round(bundleBuffer.length / 1024);
44466
- bundleSpinner.succeed(
44467
- source_default.green("Bundling...") + source_default.white(" done") + source_default.gray(` (${bundleSizeKB} KB)`)
44468
- );
44469
- } catch (error46) {
44470
- 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
+ });
44471
44567
  await (0, import_promises.unlink)(wrapperPath);
44472
- } catch {
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;
44473
44580
  }
44474
- bundleSpinner.fail(source_default.red("Bundling failed"));
44475
- throw error46;
44476
- }
44477
- const uploadSpinner = ora("Uploading...").start();
44478
- try {
44479
- const bundleBuffer = await (0, import_promises.readFile)(bundleOutfile);
44480
- const apiKey = resolveApiKey(options2.prod);
44481
- if (!apiKey) {
44482
- uploadSpinner.fail(source_default.red("Missing API key environment variable"));
44483
- console.error(source_default.gray(" Set it in your .env file or shell environment:"));
44484
- if (!options2.prod && process.env.NODE_ENV === "development") {
44485
- console.error(source_default.gray(" ELEVASIS_PLATFORM_KEY_DEV=sk_... (or ELEVASIS_PLATFORM_KEY as fallback)"));
44486
- } else {
44487
- console.error(source_default.gray(" ELEVASIS_PLATFORM_KEY=sk_..."));
44488
- }
44489
- throw new Error("Missing API key environment variable");
44490
- }
44491
- const metadata = {
44492
- sdkVersion: SDK_VERSION,
44493
- mode: env2,
44494
- resources: { workflows, agents },
44495
- ...documentation ? { documentation } : {},
44496
- ...org.relationships ? { relationships: org.relationships } : {}
44497
- };
44498
- const form = new FormData();
44499
- form.append("bundle", new Blob([bundleBuffer]), "bundle.js");
44500
- form.append("metadata", JSON.stringify(metadata));
44501
- const response = await fetch(`${apiUrl}/api/external/deploy`, {
44502
- method: "POST",
44503
- headers: { Authorization: `Bearer ${apiKey}` },
44504
- body: form
44505
- });
44506
- if (!response.ok) {
44507
- const errorText = await response.text();
44508
- uploadSpinner.fail(source_default.red("Upload failed"));
44509
- console.error(source_default.red(` ${response.status}: ${errorText}`));
44510
- throw new Error(`Deploy upload failed (${response.status}): ${errorText}`);
44511
- }
44512
- const result = await response.json();
44513
- uploadSpinner.succeed(
44514
- source_default.green("Uploading...") + source_default.white(" done")
44515
- );
44516
- const totalResources = (org.workflows?.length ?? 0) + (org.agents?.length ?? 0);
44517
- const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
44518
- if (result.status === "active") {
44519
- console.log("");
44520
- console.log(source_default.green.bold(` Deployed! ${totalResources} resource${totalResources !== 1 ? "s" : ""} live.`));
44521
- if (result.deployId) {
44522
- 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");
44523
44594
  }
44524
- console.log(source_default.gray(` Duration: ${elapsed}s`));
44525
- } else if (result.status === "failed") {
44526
- console.log("");
44527
- console.log(source_default.red.bold(" Deploy failed."));
44528
- if (result.error) {
44529
- console.error(source_default.red(` ${result.error}`));
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
+ }
44530
44642
  }
44531
- throw new Error(`Deploy failed: ${result.error ?? "unknown error"}`);
44532
- } else {
44533
- console.log("");
44534
- console.log(source_default.yellow(` Deploy status: ${result.status ?? "unknown"}`));
44535
- if (result.deployId) {
44536
- console.log(source_default.gray(` Version: ${result.deployId}`));
44643
+ } catch (error46) {
44644
+ if (uploadSpinner.isSpinning) {
44645
+ uploadSpinner.fail(source_default.red("Deploy failed"));
44537
44646
  }
44647
+ throw error46;
44538
44648
  }
44539
- } catch (error46) {
44540
- if (uploadSpinner.isSpinning) {
44541
- uploadSpinner.fail(source_default.red("Deploy failed"));
44542
- }
44543
- throw error46;
44544
- }
44545
- }));
44649
+ })
44650
+ );
44546
44651
  }
44547
44652
 
44548
44653
  // src/cli/commands/check.ts
@@ -45075,7 +45180,7 @@ var import_path3 = require("path");
45075
45180
  var import_promises2 = require("fs/promises");
45076
45181
 
45077
45182
  // src/cli/commands/templates/core/workspace.ts
45078
- var TEMPLATE_VERSION = 27;
45183
+ var TEMPLATE_VERSION = 28;
45079
45184
  function configTemplate() {
45080
45185
  return `import type { ElevasConfig } from '@elevasis/sdk'
45081
45186
 
@@ -45087,44 +45192,52 @@ export default {
45087
45192
  `;
45088
45193
  }
45089
45194
  function packageJsonTemplate(organization) {
45090
- return JSON.stringify({
45091
- name: organization,
45092
- private: true,
45093
- type: "module",
45094
- scripts: {
45095
- "check-types": "tsc --noEmit",
45096
- check: "elevasis-sdk check",
45097
- deploy: "elevasis-sdk deploy"
45098
- },
45099
- dependencies: {
45100
- "@elevasis/sdk": `^${SDK_VERSION}`
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
+ }
45101
45212
  },
45102
- devDependencies: {
45103
- typescript: "5.9.2",
45104
- zod: "4.1.12"
45105
- }
45106
- }, null, 2) + "\n";
45213
+ null,
45214
+ 2
45215
+ ) + "\n";
45107
45216
  }
45108
45217
  function pnpmWorkspaceTemplate() {
45109
45218
  return `packages: []
45110
45219
  `;
45111
45220
  }
45112
45221
  function tsconfigTemplate() {
45113
- return JSON.stringify({
45114
- compilerOptions: {
45115
- target: "ES2022",
45116
- module: "ESNext",
45117
- moduleResolution: "Bundler",
45118
- strict: true,
45119
- esModuleInterop: true,
45120
- skipLibCheck: true,
45121
- forceConsistentCasingInFileNames: true,
45122
- isolatedModules: true,
45123
- outDir: "./dist"
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"]
45124
45237
  },
45125
- include: ["src"],
45126
- exclude: ["node_modules", "dist"]
45127
- }, null, 2) + "\n";
45238
+ null,
45239
+ 2
45240
+ ) + "\n";
45128
45241
  }
45129
45242
  function envTemplate() {
45130
45243
  return `ELEVASIS_PLATFORM_KEY=
@@ -45242,6 +45355,28 @@ function claudeSettingsTemplate() {
45242
45355
  }
45243
45356
  ]
45244
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
+ }
45245
45380
  ]
45246
45381
  }
45247
45382
  },
@@ -45450,16 +45585,16 @@ proactivity -- to their assessed levels.
45450
45585
 
45451
45586
  | Resource | Location | When to Load |
45452
45587
  | --- | --- | --- |
45453
- | Workspace concepts | \`reference/concepts/index.mdx\` | User asks "what is...?" or needs conceptual grounding |
45588
+ | Workspace concepts | \`reference/concepts.mdx\` | User asks "what is...?" or needs conceptual grounding |
45454
45589
  | SDK patterns and examples | \`reference/resources/patterns.mdx\` | Building or modifying a workflow |
45455
45590
  | Platform tool catalog | \`reference/platform-tools/index.mdx\` | Connecting to external services |
45456
- | CLI reference | \`reference/cli/index.mdx\` | Running execution/platform operations |
45457
- | Credential model | \`reference/security/credentials.mdx\` | Setting up integrations or tool access |
45458
- | Interaction guidance | \`reference/developer/interaction-guidance.mdx\` | Unsure how to adapt for a skill combination |
45591
+ | CLI reference | \`reference/cli.mdx\` | Running execution/platform operations |
45592
+ | Credential model | \`reference/platform-tools/index.mdx\` | Setting up integrations or credential security |
45593
+ | Interaction guidance | \`reference/framework/interaction-guidance.mdx\` | Unsure how to adapt for a skill combination |
45459
45594
  | Error history | \`.claude/memory/errors/index.md\` | Debugging errors, checking past fixes |
45460
- | Command View model | \`reference/deployment/command-view.mdx\` | Deploying or building resources that invoke other resources |
45461
- | Command Center UI reference | \`reference/deployment/command-center-ui.mdx\` | User asks about post-deployment UI or Command Center navigation |
45462
- | SDK error reference | \`reference/troubleshooting/common-errors.mdx\` | Unknown error not in workspace memory |
45595
+ | Command View model | \`reference/deployment/command-center.mdx\` | Deploying or building resources that invoke other resources |
45596
+ | Command Center UI reference | \`reference/deployment/command-center.mdx\` | User asks about post-deployment UI or Command Center navigation |
45597
+ | SDK error reference | \`reference/troubleshooting.mdx\` | Unknown error not in workspace memory |
45463
45598
  | Project map | \`docs/project-map.mdx\` | Session start, project orientation |
45464
45599
  | Resource inventory | \`docs/resource-map.mdx\` | Finding a specific resource by name or ID |
45465
45600
  | Project priorities | \`docs/priorities.mdx\` | Deciding what to work on next |
@@ -45485,7 +45620,7 @@ Use \`pnpm exec elevasis-sdk\` for runtime commands (resolves the locally instal
45485
45620
  - \`pnpm exec elevasis-sdk execution <resource-id> <execution-id>\` -- inspect execution detail
45486
45621
 
45487
45622
  Organization is derived from your API key -- no org prefix needed in the resource ID.
45488
- For full CLI reference: \`reference/cli/index.mdx\`
45623
+ For full CLI reference: \`reference/cli.mdx\`
45489
45624
 
45490
45625
  ## Rules
45491
45626
 
@@ -45500,8 +45635,8 @@ SDK patterns (imports, source structure, platform tools) are auto-loaded from
45500
45635
 
45501
45636
  When an error occurs:
45502
45637
  1. Check \`.claude/memory/errors/\` first for past fixes
45503
- 2. If new, check \`reference/troubleshooting/common-errors.mdx\`
45504
- 3. After resolving, record in \`memory/errors/\` with context and fix
45638
+ 2. If new, check \`reference/troubleshooting.mdx\`
45639
+ 3. After resolving, record in \`.claude/memory/errors/\` with context and fix
45505
45640
  4. If an error recurs 3+ times, add a rule to \`.claude/rules/workspace-patterns.md\`${ctx.hasUI ? `
45506
45641
 
45507
45642
  ### UI App (\`ui/\`)
@@ -45533,7 +45668,7 @@ based on what you find.
45533
45668
  - When growth is observed, note it in the skills.md Growth Log.
45534
45669
 
45535
45670
  For detailed per-dimension adaptation rules, read
45536
- \`reference/developer/interaction-guidance.mdx\`.
45671
+ \`reference/framework/interaction-guidance.mdx\`.
45537
45672
 
45538
45673
  ## Commands
45539
45674
 
@@ -45542,7 +45677,7 @@ For detailed per-dimension adaptation rules, read
45542
45677
  | \`/meta\` | Project lifecycle: init, status, fix, deploy, health |
45543
45678
  | \`/docs\` | Browse, create, and verify permanent documentation |
45544
45679
  | \`/work\` | Task tracking: create, save, resume, complete |
45545
- | \`/tutorial\` | Progressive learning path (7 core lessons + 9 modules) |
45680
+ | \`/tutorial\` | Progressive learning path (21 items across 4 sections) |
45546
45681
 
45547
45682
  ## Skills
45548
45683
 
@@ -45575,7 +45710,7 @@ Do not store in \`.claude/memory/\`:
45575
45710
 
45576
45711
  ### Structure
45577
45712
 
45578
- - \`memory/index.md\` is the root -- maps to topic files and subdirectories
45713
+ - \`.claude/memory/index.md\` is the root -- maps to topic files and subdirectories
45579
45714
  - Every subdirectory has its own \`index.md\` mapping to children
45580
45715
  - Start at the root index and drill down
45581
45716
  - When a file outgrows a single document, split into a subdirectory
@@ -45599,14 +45734,14 @@ Read \`.claude/memory/profile/skills.md\` first. The \`automation\` skill level
45599
45734
  controls which docs you load and which lesson variant you deliver.
45600
45735
 
45601
45736
  **automation: none**
45602
- - Load from \`reference/concepts/index.mdx\`: Glossary, What is a Workflow,
45737
+ - Load from \`reference/concepts.mdx\`: Glossary, What is a Workflow,
45603
45738
  Platform Tools Overview only. Skip Zod, Execution Model, Design Decisions.
45604
- - Load \`reference/deployment/command-center-ui.mdx\` for UI-first teaching.
45739
+ - Load \`reference/deployment/command-center.mdx\` for UI-first teaching.
45605
45740
  - Do NOT load \`reference/resources/patterns.mdx\` or
45606
45741
  \`reference/platform-tools/adapters.mdx\` during core lessons.
45607
45742
 
45608
45743
  **automation: low-code**
45609
- - Load all sections of \`reference/concepts/index.mdx\`.
45744
+ - Load all sections of \`reference/concepts.mdx\`.
45610
45745
  - Load \`reference/resources/patterns.mdx\` with Zapier/Make mapping in mind.
45611
45746
  - Load \`reference/platform-tools/adapters.mdx\` on-demand (when tools are used).
45612
45747
 
@@ -45694,7 +45829,7 @@ Each lesson follows this flow:
45694
45829
 
45695
45830
  When automation is none:
45696
45831
  Skip the file tour. Start with what Elevasis does for their business -- use analogies
45697
- from \`reference/developer/interaction-guidance.mdx\` (recipe, assembly line, kitchen
45832
+ from \`reference/framework/interaction-guidance.mdx\` (recipe, assembly line, kitchen
45698
45833
  appliance). Explain deployment plainly: "You write the recipe here, then deploy it so
45699
45834
  it's live." Deploy the starter echo workflow (\`elevasis-sdk check\` + \`elevasis-sdk deploy\`),
45700
45835
  THEN tour the Command Center so the user sees populated pages, not empty ones. Tour:
@@ -45942,14 +46077,14 @@ Each module follows this flow:
45942
46077
  ## Modules
45943
46078
 
45944
46079
  **Module: hitl -- Human-in-the-Loop**
45945
- Read: \`reference/deployment/command-center-ui.mdx\` (Command Queue section).
46080
+ Read: \`reference/deployment/command-center.mdx\` (Command Queue section).
45946
46081
  Build: Add an approval gate using \`approval.requestApproval()\`. Test full lifecycle:
45947
46082
  trigger, see pending in Command Queue, approve/reject, observe resume.
45948
46083
  Key concepts: approval adapter, pending state, Command Queue UI, resume on decision.
45949
46084
  Verify: Trigger workflow, open Command Queue, approve, confirm completion.
45950
46085
 
45951
46086
  **Module: schedules -- Task Scheduling**
45952
- Read: \`reference/deployment/command-center-ui.mdx\` (Task Scheduler section).
46087
+ Read: \`reference/deployment/command-center.mdx\` (Task Scheduler section).
45953
46088
  Build: Create all three schedule types (Recurring cron, Relative delay, Absolute
45954
46089
  datetime). Use \`scheduler\` adapter for in-workflow scheduling.
45955
46090
  Key concepts: schedule types, cron syntax, scheduler adapter, Task Scheduler UI.
@@ -45963,7 +46098,7 @@ Verify: Run workflow, check notification in Command Center, confirm email receiv
45963
46098
 
45964
46099
  **Module: integrations -- Real-World Integrations**
45965
46100
  Read: \`reference/platform-tools/index.mdx\`, \`reference/platform-tools/adapters.mdx\`,
45966
- \`reference/security/credentials.mdx\`.
46101
+ \`reference/platform-tools/index.mdx\`.
45967
46102
  Build: Pick a real integration adapter based on user's goals (read \`identity.md\`).
45968
46103
  Set up credential (OAuth via UI, API key via CLI). Build end-to-end integration workflow.
45969
46104
  Key concepts: adapter pattern, credential scoping, error handling for external calls.
@@ -45972,7 +46107,7 @@ handling with invalid credential.
45972
46107
 
45973
46108
  **Module: error-handling -- Error Handling Mastery**
45974
46109
  Read: \`reference/resources/patterns.mdx\` (error handling),
45975
- \`reference/troubleshooting/common-errors.mdx\`.
46110
+ \`reference/troubleshooting.mdx\`.
45976
46111
  Build: Create a workflow demonstrating all three error types. Add try/catch,
45977
46112
  \`context.logger\`, and error recovery.
45978
46113
  Key concepts: ExecutionError, PlatformToolError, ToolingError, recovery patterns.
@@ -45988,7 +46123,7 @@ Key concepts: context.store, context.logger, domain organization, schema depth.
45988
46123
  Verify: Run workflow, confirm store values in step output, check logs in Execution Logs.
45989
46124
 
45990
46125
  **Module: composition -- Resource Composition**
45991
- Read: \`reference/deployment/command-view.mdx\`, \`reference/resources/patterns.mdx\`.
46126
+ Read: \`reference/deployment/command-center.mdx\`, \`reference/resources/patterns.mdx\`.
45992
46127
  Build: Create two workflows where the first triggers the second using
45993
46128
  \`execution.trigger()\`. Declare the relationship.
45994
46129
  Key concepts: execution.trigger, relationship declarations, Command View graph edges.
@@ -46136,7 +46271,7 @@ Last Session: {today's date}
46136
46271
  \`\`\`
46137
46272
 
46138
46273
  Update rules:
46139
- - \`Current\`: free-form, e.g. "4: Using Platform Tools" or "M:integrations" or "20: Rules, Memory, and Customization"
46274
+ - \`Current\`: free-form, e.g. "7: Using Platform Tools" or "M:integrations" or "20: Rules, Memory, and Customization"
46140
46275
  - \`Last Session\`: update to today's date on each \`/tutorial\` invocation
46141
46276
  - Completed Lessons: add a row when any numbered item (1-10, 20-21) finishes
46142
46277
  - Completed Modules: add a row when any module (items 11-19) finishes
@@ -46232,9 +46367,9 @@ by the \`<!-- initialized: false -->\` flag in CLAUDE.md, or run manually.
46232
46367
  - Create \`.claude/memory/profile/preferences.md\` (verbosity, guidance)
46233
46368
 
46234
46369
  4. **Git check**
46235
- - If \`.git/\` exists: note git is configured in memory/profile/preferences.md
46370
+ - If \`.git/\` exists: note git is configured in .claude/memory/profile/preferences.md
46236
46371
  - If \`.git/\` does not exist: suggest \`git init\` and optionally GitHub
46237
- - If git remote exists: note remote URL in memory/profile/preferences.md
46372
+ - If git remote exists: note remote URL in .claude/memory/profile/preferences.md
46238
46373
 
46239
46374
  5. **Verify project**
46240
46375
  Run \`elevasis-sdk check\` to confirm the starter resource is valid.
@@ -46255,9 +46390,9 @@ by the \`<!-- initialized: false -->\` flag in CLAUDE.md, or run manually.
46255
46390
 
46256
46391
  Display a project health summary:
46257
46392
  1. Template version (from elevasis.config.ts) and installed SDK version (from package.json). Suggest \`elevasis-sdk update\` to check for updates
46258
- 3. Profile summary (from memory/profile/skills.md)
46259
- 4. Quick drift check: count of missing managed files, missing gitignore entries
46260
- 5. Last deployment status (from memory/deployment-state.md if it exists)
46393
+ 2. Profile summary (from .claude/memory/profile/skills.md)
46394
+ 3. Quick drift check: count of missing managed files, missing gitignore entries
46395
+ 4. Last deployment status (from .claude/memory/deployment-state.md if it exists)
46261
46396
 
46262
46397
  ### \`/meta fix\` -- Maintenance and Upgrade
46263
46398
 
@@ -46275,9 +46410,9 @@ Detect and repair all drift. Optionally upgrades the SDK first.
46275
46410
  3. **CLAUDE.md sections:** Add missing sections in correct position
46276
46411
  4. **Memory structure:** Create base structure if missing, then verify index consistency.
46277
46412
  If \`.claude/memory/\` does not exist or is empty:
46278
- - Create \`memory/index.md\` (root index with placeholder entries)
46279
- - Create \`memory/errors/index.md\` (error category summary, empty tables)
46280
- - Create \`memory/errors/deploy.md\`, \`memory/errors/runtime.md\`, \`memory/errors/typescript.md\`
46413
+ - Create \`.claude/memory/index.md\` (root index with placeholder entries)
46414
+ - Create \`.claude/memory/errors/index.md\` (error category summary, empty tables)
46415
+ - Create \`.claude/memory/errors/deploy.md\`, \`.claude/memory/errors/runtime.md\`, \`.claude/memory/errors/typescript.md\`
46281
46416
  If memory exists, verify: every file referenced in an index exists; every file
46282
46417
  without an index entry gets one added; broken references are removed.
46283
46418
  5. **Documentation verification:** For each file in docs/:
@@ -46288,7 +46423,7 @@ Detect and repair all drift. Optionally upgrades the SDK first.
46288
46423
  e. Report discrepancies with suggested fixes
46289
46424
  Note: \`/docs verify\` is available for standalone interactive verification outside this pipeline.
46290
46425
  6. **Settings consistency:** Verify expected fields
46291
- 7. **Rules health:** Scan \`memory/errors/\` -- flag any entry that has recurred
46426
+ 7. **Rules health:** Scan \`.claude/memory/errors/\` -- flag any entry that has recurred
46292
46427
  3+ times and is not yet in \`.claude/rules/workspace-patterns.md\`.
46293
46428
  If \`workspace-patterns.md\` has no rules yet and 5+ resources exist in \`src/\`,
46294
46429
  suggest adding patterns. Surface suggestions only -- do not auto-generate.
@@ -46301,7 +46436,7 @@ Each step reports its result. Steps 1-8 run even if step 0 is skipped.
46301
46436
 
46302
46437
  ### \`/meta deploy\` -- Full Deploy Pipeline
46303
46438
 
46304
- 0. Read \`reference/deployment/command-view.mdx\` -- understand the Command View
46439
+ 0. Read \`reference/deployment/command-center.mdx\` -- understand the Command View
46305
46440
  model, relationship declarations, and what deploy-time validation checks.
46306
46441
  This context is essential for diagnosing validation failures in steps 1-2.
46307
46442
  1. Run \`elevasis-sdk check\` (validation)
@@ -46311,18 +46446,18 @@ Each step reports its result. Steps 1-8 run even if step 0 is skipped.
46311
46446
  5. Run \`elevasis-sdk deploy\`
46312
46447
  6. \`docs/project-map.mdx\` is auto-regenerated by deploy (no manual bump needed)
46313
46448
  7. Verify deployment via platform
46314
- 8. Update \`memory/deployment-state.md\` with count, timestamp, inventory
46449
+ 8. Update \`.claude/memory/deployment-state.md\` with count, timestamp, inventory
46315
46450
  9. If git configured and remote exists: optionally push
46316
46451
 
46317
46452
  Each step reports its result. Pipeline stops on failure with suggested fix.
46318
- If validation fails with relationship errors, re-read \`reference/deployment/command-view.mdx\`
46453
+ If validation fails with relationship errors, re-read \`reference/deployment/command-center.mdx\`
46319
46454
  for the enforcement model and common fixes.
46320
46455
 
46321
46456
  ### \`/meta health\` -- Execution Debugging
46322
46457
 
46323
46458
  Diagnose runtime failures and environment issues:
46324
46459
  - Show recent executions with status (completed/failed)
46325
- - For failed executions: analyze logs, cross-reference with memory/errors/
46460
+ - For failed executions: analyze logs, cross-reference with .claude/memory/errors/
46326
46461
  - Check resource deployment status (deployed, outdated, never deployed)
46327
46462
  - Verify environment: API key valid, credentials accessible, DB connected
46328
46463
 
@@ -46829,7 +46964,7 @@ This file is yours. The other \`.claude/rules/\` files are SDK-owned and updated
46829
46964
 
46830
46965
  ## When to Add a Rule
46831
46966
 
46832
- - An error has recurred 3+ times (CLAUDE.md instructs you to promote from \`memory/errors/\`)
46967
+ - An error has recurred 3+ times (CLAUDE.md instructs you to promote from \`.claude/memory/errors/\`)
46833
46968
  - A pattern appears across 3+ resources and is worth documenting for consistency
46834
46969
  - A naming or structural convention exists that future sessions would likely get wrong
46835
46970
 
@@ -46954,6 +47089,199 @@ When all plan steps are marked COMPLETE, suggest \`/work complete\` to finalize
46954
47089
  - Completed tasks move OUT of \`docs/in-progress/\` to \`docs/<relevant-dir>/\`
46955
47090
  `;
46956
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
+ }
46957
47285
 
46958
47286
  // src/cli/commands/templates/core/resources.ts
46959
47287
  function starterTemplate() {
@@ -47129,6 +47457,8 @@ function getManagedTemplates(ctx = {}) {
47129
47457
  ".claude/settings.json": claudeSettingsTemplate,
47130
47458
  ".claude/scripts/statusline-command.js": claudeStatuslineScriptTemplate,
47131
47459
  ".claude/hooks/enforce-sdk-boundary.mjs": claudeSdkBoundaryHookTemplate,
47460
+ ".claude/hooks/post-edit-validate.mjs": claudePostEditValidateHookTemplate,
47461
+ ".claude/hooks/tool-failure-recovery.mjs": claudeToolFailureRecoveryHookTemplate,
47132
47462
  ".claude/commands/tutorial.md": claudeTutorialCommandTemplate,
47133
47463
  ".claude/commands/meta.md": claudeMetaCommandTemplate,
47134
47464
  ".claude/commands/work.md": claudeWorkCommandTemplate,
@@ -47341,6 +47671,8 @@ var MANAGED_FILES = [
47341
47671
  "CLAUDE.md",
47342
47672
  ".claude/settings.json",
47343
47673
  ".claude/hooks/enforce-sdk-boundary.mjs",
47674
+ ".claude/hooks/post-edit-validate.mjs",
47675
+ ".claude/hooks/tool-failure-recovery.mjs",
47344
47676
  ".claude/commands/tutorial.md",
47345
47677
  ".claude/commands/meta.md",
47346
47678
  ".claude/commands/work.md",
@@ -47355,96 +47687,100 @@ var MANAGED_FILES = [
47355
47687
  ];
47356
47688
  var SCAFFOLD_FILES = [...INIT_ONLY_FILES, ...MANAGED_FILES];
47357
47689
  function registerInitCommand(program3) {
47358
- 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(wrapAction("init", async (directory, options2) => {
47359
- const targetDir = directory ? (0, import_path3.resolve)(directory) : process.cwd();
47360
- const orgSlug = toSlug((0, import_path3.basename)(targetDir));
47361
- if (!options2.force) {
47362
- const filesToCheck = options2.ui ? [...SCAFFOLD_FILES, ...UI_INIT_FILES] : SCAFFOLD_FILES;
47363
- const conflicts = [];
47364
- for (const file2 of filesToCheck) {
47365
- try {
47366
- await (0, import_promises2.access)((0, import_path3.resolve)(targetDir, file2));
47367
- conflicts.push(file2);
47368
- } catch {
47369
- }
47370
- }
47371
- if (conflicts.length > 0) {
47372
- console.error(source_default.red("Files already exist:"));
47373
- for (const f of conflicts) {
47374
- 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
+ }
47375
47703
  }
47376
- console.error(source_default.gray("\n Use --force to overwrite."));
47377
- throw new Error("Scaffold conflict");
47378
- }
47379
- }
47380
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "src/operations"), { recursive: true });
47381
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "src/example"), { recursive: true });
47382
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "src/shared"), { recursive: true });
47383
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "docs/in-progress"), { recursive: true });
47384
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/hooks"), { recursive: true });
47385
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/scripts"), { recursive: true });
47386
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/commands"), { recursive: true });
47387
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/skills/creds"), { recursive: true });
47388
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, ".claude/rules"), { recursive: true });
47389
- if (options2.ui) {
47390
- await (0, import_promises2.mkdir)((0, import_path3.resolve)(targetDir, "ui/src"), { recursive: true });
47391
- }
47392
- const files = {
47393
- "elevasis.config.ts": configTemplate(),
47394
- "package.json": packageJsonTemplate(orgSlug),
47395
- "pnpm-workspace.yaml": pnpmWorkspaceTemplate(),
47396
- "tsconfig.json": tsconfigTemplate(),
47397
- ".env": envTemplate(),
47398
- ".npmrc": npmrcTemplate(),
47399
- ".gitignore": gitignoreTemplate({ hasUI: options2.ui }),
47400
- "src/index.ts": starterTemplate(),
47401
- "src/operations/platform-status.ts": platformStatusTemplate(),
47402
- "src/operations/index.ts": operationsBarrelTemplate(),
47403
- "src/example/echo.ts": starterWorkflowTemplate(),
47404
- "src/example/index.ts": exampleBarrelTemplate(),
47405
- "src/shared/.gitkeep": "",
47406
- "docs/index.mdx": docsIndexTemplate(orgSlug),
47407
- "docs/in-progress/.gitkeep": "",
47408
- "CLAUDE.md": claudeMdTemplate({ hasUI: options2.ui }),
47409
- ".claude/settings.json": claudeSettingsTemplate(),
47410
- ".claude/hooks/enforce-sdk-boundary.mjs": claudeSdkBoundaryHookTemplate(),
47411
- ".claude/commands/tutorial.md": claudeTutorialCommandTemplate(),
47412
- ".claude/commands/meta.md": claudeMetaCommandTemplate(),
47413
- ".claude/commands/work.md": claudeWorkCommandTemplate(),
47414
- ".claude/commands/docs.md": claudeDocsCommandTemplate(),
47415
- ".claude/skills/creds/SKILL.md": claudeCredsSkillTemplate(),
47416
- ".claude/rules/sdk-patterns.md": claudeSdkPatternsRuleTemplate(),
47417
- ".claude/rules/workspace-patterns.md": claudeWorkspaceRulesTemplate(),
47418
- ".claude/rules/docs-authoring.md": claudeDocsAuthoringRuleTemplate(),
47419
- ".claude/rules/memory-conventions.md": claudeMemoryConventionsRuleTemplate(),
47420
- ".claude/rules/project-map.md": claudeProjectMapRuleTemplate(),
47421
- ".claude/rules/task-tracking.md": claudeTaskTrackingRuleTemplate(),
47422
- ".claude/scripts/statusline-command.js": claudeStatuslineScriptTemplate()
47423
- };
47424
- if (options2.ui) {
47425
- Object.assign(files, getUIFiles(orgSlug));
47426
- }
47427
- for (const [filePath, content] of Object.entries(files)) {
47428
- await (0, import_promises2.writeFile)((0, import_path3.resolve)(targetDir, filePath), content, "utf-8");
47429
- }
47430
- console.log(source_default.green.bold(" Workspace created!"));
47431
- console.log("");
47432
- console.log(source_default.gray(" Next steps:"));
47433
- if (directory) {
47434
- console.log(source_default.gray(` cd ${directory}`));
47435
- }
47436
- console.log(source_default.gray(" pnpm install"));
47437
- console.log(source_default.gray(" # Add your API key to .env"));
47438
- console.log(source_default.gray(" elevasis-sdk check"));
47439
- console.log(source_default.gray(" elevasis-sdk deploy"));
47440
- 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!"));
47441
47766
  console.log("");
47442
- console.log(source_default.gray(" UI app:"));
47443
- console.log(source_default.gray(" cd ui && pnpm install"));
47444
- console.log(source_default.gray(" # Set VITE_WORKOS_CLIENT_ID in ui/.env"));
47445
- console.log(source_default.gray(" pnpm dev"));
47446
- }
47447
- }));
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
+ );
47448
47784
  }
47449
47785
  function toSlug(name) {
47450
47786
  const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^[^a-z]+/, "").replace(/-+/g, "-").replace(/-$/, "");