@elevasis/sdk 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/cli.cjs +899 -57
  2. package/dist/index.d.ts +94 -110
  3. package/package.json +3 -3
  4. package/reference/_navigation.md +11 -1
  5. package/reference/_reference-manifest.json +70 -0
  6. package/reference/claude-config/commands/submit-issue.md +12 -0
  7. package/reference/claude-config/hooks/post-edit-validate.mjs +109 -0
  8. package/reference/claude-config/hooks/tool-failure-recovery.mjs +73 -0
  9. package/reference/claude-config/rules/deployment.md +57 -0
  10. package/reference/claude-config/rules/docs.md +26 -0
  11. package/reference/claude-config/rules/error-handling.md +56 -0
  12. package/reference/claude-config/rules/execution.md +40 -0
  13. package/reference/claude-config/rules/frontend.md +43 -0
  14. package/reference/claude-config/rules/observability.md +31 -0
  15. package/reference/claude-config/rules/organization-os.md +62 -0
  16. package/reference/claude-config/rules/platform.md +41 -0
  17. package/reference/claude-config/rules/shared-types.md +46 -0
  18. package/reference/claude-config/rules/task-tracking.md +47 -0
  19. package/reference/claude-config/scripts/statusline-command.js +18 -0
  20. package/reference/claude-config/settings.json +30 -0
  21. package/reference/claude-config/skills/deploy/SKILL.md +166 -0
  22. package/reference/claude-config/skills/dsp/SKILL.md +66 -0
  23. package/reference/claude-config/skills/elevasis/SKILL.md +239 -0
  24. package/reference/claude-config/skills/explore/SKILL.md +78 -0
  25. package/reference/claude-config/skills/project/SKILL.md +918 -0
  26. package/reference/claude-config/skills/save/SKILL.md +197 -0
  27. package/reference/claude-config/skills/setup/SKILL.md +210 -0
  28. package/reference/claude-config/skills/status/SKILL.md +60 -0
  29. package/reference/claude-config/skills/submit-issue/SKILL.md +179 -0
  30. package/reference/claude-config/skills/sync/SKILL.md +81 -0
  31. package/reference/cli.mdx +35 -20
  32. package/reference/deployment/index.mdx +6 -5
  33. package/reference/deployment/provided-features.mdx +62 -40
  34. package/reference/deployment/ui-execution.mdx +1 -2
  35. package/reference/framework/agent.mdx +50 -50
  36. package/reference/framework/index.mdx +13 -10
  37. package/reference/framework/project-structure.mdx +76 -70
  38. package/reference/packages/core/src/README.md +24 -17
  39. package/reference/packages/core/src/business/README.md +52 -0
  40. package/reference/packages/core/src/organization-model/README.md +25 -26
  41. package/reference/packages/ui/src/app/README.md +24 -0
  42. package/reference/packages/ui/src/provider/README.md +8 -7
  43. package/reference/platform-tools/type-safety.mdx +0 -10
  44. package/reference/roadmap.mdx +6 -4
  45. package/reference/scaffold/core/organization-graph.mdx +37 -28
  46. package/reference/scaffold/core/organization-model.mdx +34 -36
  47. package/reference/scaffold/index.mdx +14 -9
  48. package/reference/scaffold/operations/propagation-pipeline.md +133 -0
  49. package/reference/scaffold/operations/scaffold-maintenance.md +125 -0
  50. package/reference/scaffold/operations/workflow-recipes.md +18 -1
  51. package/reference/scaffold/recipes/add-a-feature.md +37 -21
  52. package/reference/scaffold/recipes/add-a-resource.md +16 -12
  53. package/reference/scaffold/recipes/customize-organization-model.md +400 -0
  54. package/reference/scaffold/recipes/extend-a-base-entity.md +140 -0
  55. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +18 -12
  56. package/reference/scaffold/recipes/index.md +3 -3
  57. package/reference/scaffold/reference/contracts.md +11 -32
  58. package/reference/scaffold/reference/feature-registry.md +10 -9
  59. package/reference/scaffold/reference/glossary.md +14 -18
  60. package/reference/scaffold/ui/customization.md +2 -2
  61. package/reference/scaffold/ui/feature-flags-and-gating.md +40 -54
  62. package/reference/scaffold/ui/feature-shell.mdx +23 -24
  63. package/reference/scaffold/ui/recipes.md +118 -3
package/dist/cli.cjs CHANGED
@@ -288,8 +288,8 @@ var require_main = __commonJS({
288
288
  const shortPaths = [];
289
289
  for (const filePath of optionPaths) {
290
290
  try {
291
- const relative = path.relative(process.cwd(), filePath);
292
- shortPaths.push(relative);
291
+ const relative2 = path.relative(process.cwd(), filePath);
292
+ shortPaths.push(relative2);
293
293
  } catch (e) {
294
294
  if (debug) {
295
295
  _debug(`Failed to load ${filePath} ${e.message}`);
@@ -5245,7 +5245,7 @@ var require_buffer_list = __commonJS({
5245
5245
  }
5246
5246
  }, {
5247
5247
  key: "join",
5248
- value: function join(s) {
5248
+ value: function join4(s) {
5249
5249
  if (this.length === 0) return "";
5250
5250
  var p = this.head;
5251
5251
  var ret = "" + p.data;
@@ -6622,14 +6622,14 @@ var require_async_iterator = __commonJS({
6622
6622
  };
6623
6623
  }
6624
6624
  function readAndResolve(iter) {
6625
- var resolve4 = iter[kLastResolve];
6626
- if (resolve4 !== null) {
6625
+ var resolve8 = iter[kLastResolve];
6626
+ if (resolve8 !== null) {
6627
6627
  var data = iter[kStream].read();
6628
6628
  if (data !== null) {
6629
6629
  iter[kLastPromise] = null;
6630
6630
  iter[kLastResolve] = null;
6631
6631
  iter[kLastReject] = null;
6632
- resolve4(createIterResult(data, false));
6632
+ resolve8(createIterResult(data, false));
6633
6633
  }
6634
6634
  }
6635
6635
  }
@@ -6637,13 +6637,13 @@ var require_async_iterator = __commonJS({
6637
6637
  process.nextTick(readAndResolve, iter);
6638
6638
  }
6639
6639
  function wrapForNext(lastPromise, iter) {
6640
- return function(resolve4, reject) {
6640
+ return function(resolve8, reject) {
6641
6641
  lastPromise.then(function() {
6642
6642
  if (iter[kEnded]) {
6643
- resolve4(createIterResult(void 0, true));
6643
+ resolve8(createIterResult(void 0, true));
6644
6644
  return;
6645
6645
  }
6646
- iter[kHandlePromise](resolve4, reject);
6646
+ iter[kHandlePromise](resolve8, reject);
6647
6647
  }, reject);
6648
6648
  };
6649
6649
  }
@@ -6663,12 +6663,12 @@ var require_async_iterator = __commonJS({
6663
6663
  return Promise.resolve(createIterResult(void 0, true));
6664
6664
  }
6665
6665
  if (this[kStream].destroyed) {
6666
- return new Promise(function(resolve4, reject) {
6666
+ return new Promise(function(resolve8, reject) {
6667
6667
  process.nextTick(function() {
6668
6668
  if (_this[kError]) {
6669
6669
  reject(_this[kError]);
6670
6670
  } else {
6671
- resolve4(createIterResult(void 0, true));
6671
+ resolve8(createIterResult(void 0, true));
6672
6672
  }
6673
6673
  });
6674
6674
  });
@@ -6691,13 +6691,13 @@ var require_async_iterator = __commonJS({
6691
6691
  return this;
6692
6692
  }), _defineProperty(_Object$setPrototypeO, "return", function _return() {
6693
6693
  var _this2 = this;
6694
- return new Promise(function(resolve4, reject) {
6694
+ return new Promise(function(resolve8, reject) {
6695
6695
  _this2[kStream].destroy(null, function(err) {
6696
6696
  if (err) {
6697
6697
  reject(err);
6698
6698
  return;
6699
6699
  }
6700
- resolve4(createIterResult(void 0, true));
6700
+ resolve8(createIterResult(void 0, true));
6701
6701
  });
6702
6702
  });
6703
6703
  }), _Object$setPrototypeO), AsyncIteratorPrototype);
@@ -6719,15 +6719,15 @@ var require_async_iterator = __commonJS({
6719
6719
  value: stream._readableState.endEmitted,
6720
6720
  writable: true
6721
6721
  }), _defineProperty(_Object$create, kHandlePromise, {
6722
- value: function value(resolve4, reject) {
6722
+ value: function value(resolve8, reject) {
6723
6723
  var data = iterator[kStream].read();
6724
6724
  if (data) {
6725
6725
  iterator[kLastPromise] = null;
6726
6726
  iterator[kLastResolve] = null;
6727
6727
  iterator[kLastReject] = null;
6728
- resolve4(createIterResult(data, false));
6728
+ resolve8(createIterResult(data, false));
6729
6729
  } else {
6730
- iterator[kLastResolve] = resolve4;
6730
+ iterator[kLastResolve] = resolve8;
6731
6731
  iterator[kLastReject] = reject;
6732
6732
  }
6733
6733
  },
@@ -6746,12 +6746,12 @@ var require_async_iterator = __commonJS({
6746
6746
  iterator[kError] = err;
6747
6747
  return;
6748
6748
  }
6749
- var resolve4 = iterator[kLastResolve];
6750
- if (resolve4 !== null) {
6749
+ var resolve8 = iterator[kLastResolve];
6750
+ if (resolve8 !== null) {
6751
6751
  iterator[kLastPromise] = null;
6752
6752
  iterator[kLastResolve] = null;
6753
6753
  iterator[kLastReject] = null;
6754
- resolve4(createIterResult(void 0, true));
6754
+ resolve8(createIterResult(void 0, true));
6755
6755
  }
6756
6756
  iterator[kEnded] = true;
6757
6757
  });
@@ -6766,7 +6766,7 @@ var require_async_iterator = __commonJS({
6766
6766
  var require_from = __commonJS({
6767
6767
  "../../node_modules/.pnpm/readable-stream@3.6.2/node_modules/readable-stream/lib/internal/streams/from.js"(exports2, module2) {
6768
6768
  "use strict";
6769
- function asyncGeneratorStep(gen, resolve4, reject, _next, _throw, key, arg) {
6769
+ function asyncGeneratorStep(gen, resolve8, reject, _next, _throw, key, arg) {
6770
6770
  try {
6771
6771
  var info = gen[key](arg);
6772
6772
  var value = info.value;
@@ -6775,7 +6775,7 @@ var require_from = __commonJS({
6775
6775
  return;
6776
6776
  }
6777
6777
  if (info.done) {
6778
- resolve4(value);
6778
+ resolve8(value);
6779
6779
  } else {
6780
6780
  Promise.resolve(value).then(_next, _throw);
6781
6781
  }
@@ -6783,13 +6783,13 @@ var require_from = __commonJS({
6783
6783
  function _asyncToGenerator(fn) {
6784
6784
  return function() {
6785
6785
  var self2 = this, args = arguments;
6786
- return new Promise(function(resolve4, reject) {
6786
+ return new Promise(function(resolve8, reject) {
6787
6787
  var gen = fn.apply(self2, args);
6788
6788
  function _next(value) {
6789
- asyncGeneratorStep(gen, resolve4, reject, _next, _throw, "next", value);
6789
+ asyncGeneratorStep(gen, resolve8, reject, _next, _throw, "next", value);
6790
6790
  }
6791
6791
  function _throw(err) {
6792
- asyncGeneratorStep(gen, resolve4, reject, _next, _throw, "throw", err);
6792
+ asyncGeneratorStep(gen, resolve8, reject, _next, _throw, "throw", err);
6793
6793
  }
6794
6794
  _next(void 0);
6795
6795
  });
@@ -43990,7 +43990,7 @@ function wrapAction(commandName, fn) {
43990
43990
  // package.json
43991
43991
  var package_default = {
43992
43992
  name: "@elevasis/sdk",
43993
- version: "1.5.2",
43993
+ version: "1.5.4",
43994
43994
  description: "SDK for building Elevasis organization resources",
43995
43995
  type: "module",
43996
43996
  bin: {
@@ -44508,7 +44508,7 @@ async function pollForCompletion(resourceId, executionId, apiUrl) {
44508
44508
  };
44509
44509
  process.on("SIGINT", cleanup);
44510
44510
  while (true) {
44511
- await new Promise((resolve4) => setTimeout(resolve4, POLL_INTERVAL_MS));
44511
+ await new Promise((resolve8) => setTimeout(resolve8, POLL_INTERVAL_MS));
44512
44512
  const elapsed = Math.round((Date.now() - startTime) / 1e3);
44513
44513
  pollSpinner.text = `Waiting for completion... (${elapsed}s)`;
44514
44514
  try {
@@ -45096,10 +45096,10 @@ Credential renamed successfully!`));
45096
45096
  var import_readline = require("readline");
45097
45097
  function confirm(message) {
45098
45098
  const rl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stdout });
45099
- return new Promise((resolve4) => {
45099
+ return new Promise((resolve8) => {
45100
45100
  rl.question(message, (answer) => {
45101
45101
  rl.close();
45102
- resolve4(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
45102
+ resolve8(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
45103
45103
  });
45104
45104
  });
45105
45105
  }
@@ -45230,38 +45230,320 @@ function registerRenameCommand(program3) {
45230
45230
  );
45231
45231
  }
45232
45232
 
45233
+ // src/cli/commands/project/resolve-project.ts
45234
+ function isUuid(value) {
45235
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
45236
+ }
45237
+ function normalize(value) {
45238
+ return value.trim().toLowerCase();
45239
+ }
45240
+ function formatCandidates(projects) {
45241
+ return projects.slice(0, 5).map((project) => `${project.name} (${project.id})`).join(", ");
45242
+ }
45243
+ async function resolveProject(query, apiUrlOverride) {
45244
+ const trimmedQuery = query.trim();
45245
+ if (!trimmedQuery) {
45246
+ throw new Error("Project query is required");
45247
+ }
45248
+ const apiUrl = resolveApiUrl(apiUrlOverride);
45249
+ if (isUuid(trimmedQuery)) {
45250
+ try {
45251
+ const result2 = await apiGet(`/api/external/projects/${trimmedQuery}`, apiUrl);
45252
+ return result2.project;
45253
+ } catch (error46) {
45254
+ if (!(error46 instanceof Error) || !error46.message.includes("(404)")) {
45255
+ throw error46;
45256
+ }
45257
+ }
45258
+ }
45259
+ const params = new URLSearchParams({ search: trimmedQuery });
45260
+ const result = await apiGet(`/api/external/projects?${params.toString()}`, apiUrl);
45261
+ const projects = result.projects;
45262
+ if (projects.length === 0) {
45263
+ throw new Error(`No project matched "${trimmedQuery}"`);
45264
+ }
45265
+ const normalizedQuery = normalize(trimmedQuery);
45266
+ const exactNameMatches = projects.filter((project) => normalize(project.name) === normalizedQuery);
45267
+ if (exactNameMatches.length === 1) {
45268
+ return exactNameMatches[0];
45269
+ }
45270
+ if (exactNameMatches.length > 1) {
45271
+ throw new Error(`Multiple projects matched "${trimmedQuery}": ${formatCandidates(exactNameMatches)}`);
45272
+ }
45273
+ if (projects.length === 1) {
45274
+ return projects[0];
45275
+ }
45276
+ const prefixMatches = projects.filter((project) => normalize(project.name).startsWith(normalizedQuery));
45277
+ if (prefixMatches.length === 1) {
45278
+ return prefixMatches[0];
45279
+ }
45280
+ throw new Error(`Multiple projects matched "${trimmedQuery}": ${formatCandidates(projects)}`);
45281
+ }
45282
+
45283
+ // src/cli/commands/project/work-project.ts
45284
+ var TASK_DONE_STATUSES = /* @__PURE__ */ new Set(["completed", "approved"]);
45285
+ var TASK_ACTIVE_STATUSES = /* @__PURE__ */ new Set(["in_progress", "submitted", "revision_requested"]);
45286
+ var TASK_BLOCKED_STATUSES = /* @__PURE__ */ new Set(["blocked", "rejected"]);
45287
+ var MILESTONE_BLOCKED_STATUSES = /* @__PURE__ */ new Set(["blocked", "overdue"]);
45288
+ function toText(value) {
45289
+ return typeof value === "string" && value.trim() ? value.trim() : null;
45290
+ }
45291
+ function summarizeText(value, maxLength = 120) {
45292
+ const text = value?.trim() ?? "";
45293
+ if (!text) return "No recent summary recorded.";
45294
+ return text.length > maxLength ? `${text.slice(0, maxLength - 3)}...` : text;
45295
+ }
45296
+ function getTaskSavedState(task) {
45297
+ const resumeContext = task.resume_context;
45298
+ return toText(resumeContext?.current_state);
45299
+ }
45300
+ function compareUpdatedDesc(a, b) {
45301
+ return (b.updated_at ?? "").localeCompare(a.updated_at ?? "");
45302
+ }
45303
+ function deriveLifecycle(project, taskProgress, milestoneProgress) {
45304
+ if (project.status === "completed") return "completed";
45305
+ if (project.status === "blocked" || taskProgress.blocked > 0 || milestoneProgress.blocked > 0) {
45306
+ return "blocked";
45307
+ }
45308
+ const hasStartedWork = taskProgress.completed > 0 || taskProgress.active > 0 || milestoneProgress.completed > 0 || milestoneProgress.inProgress > 0;
45309
+ return hasStartedWork ? "active" : "planning";
45310
+ }
45311
+ function selectResumeTarget(project) {
45312
+ const activeTasks = project.tasks.filter((task) => TASK_ACTIVE_STATUSES.has(task.status ?? "")).sort(compareUpdatedDesc);
45313
+ const savedActiveTask = activeTasks.find((task) => getTaskSavedState(task));
45314
+ if (savedActiveTask) {
45315
+ return {
45316
+ kind: "task",
45317
+ id: savedActiveTask.id,
45318
+ name: savedActiveTask.name,
45319
+ status: savedActiveTask.status,
45320
+ savedState: getTaskSavedState(savedActiveTask)
45321
+ };
45322
+ }
45323
+ if (activeTasks[0]) {
45324
+ return {
45325
+ kind: "task",
45326
+ id: activeTasks[0].id,
45327
+ name: activeTasks[0].name,
45328
+ status: activeTasks[0].status,
45329
+ savedState: null
45330
+ };
45331
+ }
45332
+ const plannedTask = [...project.tasks].filter((task) => task.status === "planned").sort(compareUpdatedDesc)[0];
45333
+ if (plannedTask) {
45334
+ return {
45335
+ kind: "task",
45336
+ id: plannedTask.id,
45337
+ name: plannedTask.name,
45338
+ status: plannedTask.status,
45339
+ savedState: getTaskSavedState(plannedTask)
45340
+ };
45341
+ }
45342
+ const nextMilestone = project.milestones.find((milestone) => milestone.status !== "completed");
45343
+ if (nextMilestone) {
45344
+ return {
45345
+ kind: "milestone",
45346
+ id: nextMilestone.id,
45347
+ name: nextMilestone.name,
45348
+ status: nextMilestone.status,
45349
+ savedState: null
45350
+ };
45351
+ }
45352
+ return null;
45353
+ }
45354
+ function recommendNextStep(lifecycle, project, notes, resumeTarget) {
45355
+ const latestBlockerNote = notes.find((note) => note.type === "blocker" || note.type === "issue");
45356
+ const blockedTask = [...project.tasks].filter((task) => TASK_BLOCKED_STATUSES.has(task.status ?? "")).sort(compareUpdatedDesc)[0];
45357
+ if (lifecycle === "completed") {
45358
+ return "Review the closeout state and decide whether to archive this project or open the next phase.";
45359
+ }
45360
+ if (lifecycle === "blocked") {
45361
+ if (blockedTask) {
45362
+ return `Resolve the blocker on "${blockedTask.name}" before starting new work.`;
45363
+ }
45364
+ if (latestBlockerNote) {
45365
+ return `Address the latest ${latestBlockerNote.type ?? "blocker"} note, then update the project once it is cleared.`;
45366
+ }
45367
+ return "Clear the blocking issue first, then resume the next concrete task.";
45368
+ }
45369
+ if (resumeTarget?.kind === "task") {
45370
+ if (resumeTarget.savedState) {
45371
+ return `Resume "${resumeTarget.name}" from the saved task context.`;
45372
+ }
45373
+ return `Resume "${resumeTarget.name}" and record fresh resume context once the next checkpoint is stable.`;
45374
+ }
45375
+ if (resumeTarget?.kind === "milestone") {
45376
+ return `Start milestone "${resumeTarget.name}" and create the first concrete task under it.`;
45377
+ }
45378
+ const latestNote = notes[0];
45379
+ if (latestNote) {
45380
+ return "Review the latest project note and turn it into the next concrete task or milestone.";
45381
+ }
45382
+ return "Add the next concrete task or milestone before resuming work.";
45383
+ }
45384
+ function buildProjectWorkBrief(project, notes) {
45385
+ const taskProgress = {
45386
+ total: project.tasks.length,
45387
+ completed: project.tasks.filter((task) => TASK_DONE_STATUSES.has(task.status ?? "")).length,
45388
+ active: project.tasks.filter((task) => TASK_ACTIVE_STATUSES.has(task.status ?? "")).length,
45389
+ blocked: project.tasks.filter((task) => TASK_BLOCKED_STATUSES.has(task.status ?? "")).length
45390
+ };
45391
+ const milestoneProgress = {
45392
+ total: project.milestones.length,
45393
+ completed: project.milestones.filter((milestone) => milestone.status === "completed").length,
45394
+ inProgress: project.milestones.filter((milestone) => milestone.status === "in_progress").length,
45395
+ blocked: project.milestones.filter((milestone) => MILESTONE_BLOCKED_STATUSES.has(milestone.status ?? "")).length
45396
+ };
45397
+ const lifecycle = deriveLifecycle(project, taskProgress, milestoneProgress);
45398
+ const resumeTarget = selectResumeTarget(project);
45399
+ return {
45400
+ project: {
45401
+ id: project.id,
45402
+ name: project.name,
45403
+ kind: project.kind,
45404
+ status: project.status,
45405
+ description: project.description
45406
+ },
45407
+ lifecycle,
45408
+ progress: {
45409
+ milestones: milestoneProgress,
45410
+ tasks: taskProgress
45411
+ },
45412
+ recentNotes: notes.slice(0, 3).map((note) => ({
45413
+ id: note.id,
45414
+ type: note.type,
45415
+ occurredAt: note.occurred_at,
45416
+ summary: summarizeText(note.summary ?? note.content)
45417
+ })),
45418
+ resumeTarget,
45419
+ recommendedNextStep: recommendNextStep(lifecycle, project, notes, resumeTarget)
45420
+ };
45421
+ }
45422
+ function renderProjectWorkBrief(brief) {
45423
+ const lines = [
45424
+ `Project work brief: ${brief.project.name}`,
45425
+ ` ID: ${brief.project.id}`,
45426
+ ` Lifecycle: ${brief.lifecycle}`,
45427
+ ` Status: ${brief.project.status ?? "unknown"}`
45428
+ ];
45429
+ if (brief.project.kind) {
45430
+ lines.push(` Kind: ${brief.project.kind}`);
45431
+ }
45432
+ if (brief.project.description) {
45433
+ lines.push(` ${brief.project.description}`);
45434
+ }
45435
+ lines.push("");
45436
+ lines.push("Progress");
45437
+ lines.push(
45438
+ ` Milestones: ${brief.progress.milestones.completed}/${brief.progress.milestones.total} completed, ${brief.progress.milestones.inProgress} in progress, ${brief.progress.milestones.blocked} blocked`
45439
+ );
45440
+ lines.push(
45441
+ ` Tasks: ${brief.progress.tasks.completed}/${brief.progress.tasks.total} completed, ${brief.progress.tasks.active} active, ${brief.progress.tasks.blocked} blocked`
45442
+ );
45443
+ lines.push("");
45444
+ lines.push("Recent notes");
45445
+ if (brief.recentNotes.length === 0) {
45446
+ lines.push(" No recent notes recorded.");
45447
+ } else {
45448
+ for (const note of brief.recentNotes) {
45449
+ const dateLabel = note.occurredAt ? note.occurredAt.slice(0, 10) : "unknown-date";
45450
+ lines.push(` - ${dateLabel} ${note.type ?? "status_update"}: ${note.summary}`);
45451
+ }
45452
+ }
45453
+ lines.push("");
45454
+ lines.push("Resume target");
45455
+ if (!brief.resumeTarget) {
45456
+ lines.push(" No clear resume target yet.");
45457
+ } else {
45458
+ lines.push(
45459
+ ` ${brief.resumeTarget.kind}: ${brief.resumeTarget.name} (${brief.resumeTarget.status ?? "unknown"})`
45460
+ );
45461
+ if (brief.resumeTarget.savedState) {
45462
+ lines.push(` Saved state: ${brief.resumeTarget.savedState}`);
45463
+ }
45464
+ }
45465
+ lines.push("");
45466
+ lines.push("Recommended next step");
45467
+ lines.push(` ${brief.recommendedNextStep}`);
45468
+ return lines.join("\n");
45469
+ }
45470
+
45233
45471
  // src/cli/commands/project/projects.ts
45234
45472
  function registerProjectList(program3) {
45235
- program3.command("project:list").description("List all projects\n Example: elevasis-sdk project:list --kind internal").option("--kind <kind>", "Filter by kind: client_engagement | internal | research | other").option("--status <status>", "Filter by status: active | on_track | at_risk | blocked | completed | paused").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45236
- wrapAction("project:list", async (options2) => {
45237
- const apiUrl = resolveApiUrl(options2.apiUrl);
45238
- const params = new URLSearchParams();
45239
- if (options2.kind) params.set("kind", options2.kind);
45240
- if (options2.status) params.set("status", options2.status);
45241
- const qs = params.toString();
45242
- const endpoint = `/api/external/projects${qs ? `?${qs}` : ""}`;
45243
- const result = await apiGet(endpoint, apiUrl);
45244
- if (options2.pretty) {
45245
- const projects = result.projects;
45246
- if (projects.length === 0) {
45247
- console.log(source_default.yellow("No projects found."));
45248
- return;
45249
- }
45250
- console.log(source_default.cyan(`
45473
+ program3.command("project:list").description("List projects\n Example: elevasis-sdk project:list --search alpha").option("--kind <kind>", "Filter by kind: client_engagement | internal | research | other").option("--status <status>", "Filter by status: active | on_track | at_risk | blocked | completed | paused").option("--search <query>", "Search by project name or description").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45474
+ wrapAction(
45475
+ "project:list",
45476
+ async (options2) => {
45477
+ const apiUrl = resolveApiUrl(options2.apiUrl);
45478
+ const params = new URLSearchParams();
45479
+ if (options2.kind) params.set("kind", options2.kind);
45480
+ if (options2.status) params.set("status", options2.status);
45481
+ if (options2.search) params.set("search", options2.search);
45482
+ const qs = params.toString();
45483
+ const endpoint = `/api/external/projects${qs ? `?${qs}` : ""}`;
45484
+ const result = await apiGet(endpoint, apiUrl);
45485
+ if (options2.pretty) {
45486
+ const projects = result.projects;
45487
+ if (projects.length === 0) {
45488
+ console.log(source_default.yellow("No projects found."));
45489
+ return;
45490
+ }
45491
+ console.log(source_default.cyan(`
45251
45492
  Projects (${projects.length}):
45252
45493
  `));
45253
- for (const p of projects) {
45254
- console.log(` ${source_default.bold(p.name)} ${source_default.dim(p.kind)} ${source_default.gray(p.status)}`);
45255
- console.log(source_default.gray(` ID: ${p.id}`));
45256
- if (p.description) console.log(source_default.gray(` ${p.description}`));
45494
+ for (const p of projects) {
45495
+ console.log(` ${source_default.bold(p.name)} ${source_default.dim(p.kind)} ${source_default.gray(p.status)}`);
45496
+ console.log(source_default.gray(` ID: ${p.id}`));
45497
+ if (p.description) console.log(source_default.gray(` ${p.description}`));
45498
+ }
45499
+ console.log();
45500
+ } else {
45501
+ console.log(JSON.stringify(result, null, 2));
45257
45502
  }
45503
+ }
45504
+ )
45505
+ );
45506
+ }
45507
+ function registerProjectResolve(program3) {
45508
+ program3.command("project:resolve <query>").description('Resolve a project ID from a name, UUID, or search query\n Example: elevasis-sdk project:resolve "Alpha"').option("--api-url <url>", "API base URL").option("--pretty", "Render project details instead of only the resolved ID").action(
45509
+ wrapAction("project:resolve", async (query, options2) => {
45510
+ const project = await resolveProject(query, options2.apiUrl);
45511
+ if (options2.pretty) {
45512
+ console.log(source_default.cyan(`
45513
+ Resolved project: ${project.name}`));
45514
+ console.log(source_default.gray(` ID: ${project.id}`));
45515
+ if (project.kind) console.log(source_default.gray(` Kind: ${project.kind}`));
45516
+ if (project.status) console.log(source_default.gray(` Status: ${project.status}`));
45517
+ if (project.description) console.log(source_default.gray(` ${project.description}`));
45258
45518
  console.log();
45259
45519
  } else {
45260
- console.log(JSON.stringify(result, null, 2));
45520
+ console.log(project.id);
45261
45521
  }
45262
45522
  })
45263
45523
  );
45264
45524
  }
45525
+ function registerProjectWork(program3) {
45526
+ program3.command("project:work <query>").alias("project:open").description(
45527
+ 'Resolve a project and print a lifecycle-aware work brief\n Example: elevasis-sdk project:work "Alpha"'
45528
+ ).option("--api-url <url>", "API base URL").option("--json", "Render the structured work brief as JSON").action(
45529
+ wrapAction("project:work", async (query, options2) => {
45530
+ const apiUrl = resolveApiUrl(options2.apiUrl);
45531
+ const resolved = await resolveProject(query, options2.apiUrl);
45532
+ const [projectResult, notesResult] = await Promise.all([
45533
+ apiGet(`/api/external/projects/${resolved.id}`, apiUrl),
45534
+ apiGet(`/api/external/projects/${resolved.id}/notes`, apiUrl)
45535
+ ]);
45536
+ const brief = buildProjectWorkBrief(projectResult.project, notesResult.notes);
45537
+ if (options2.json) {
45538
+ console.log(JSON.stringify(brief, null, 2));
45539
+ return;
45540
+ }
45541
+ console.log(source_default.cyan(`
45542
+ ${renderProjectWorkBrief(brief)}
45543
+ `));
45544
+ })
45545
+ );
45546
+ }
45265
45547
  function registerProjectGet(program3) {
45266
45548
  program3.command("project:get <id>").description("Get a project by ID\n Example: elevasis-sdk project:get <uuid>").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45267
45549
  wrapAction("project:get", async (id, options2) => {
@@ -45283,7 +45565,7 @@ Project: ${p.name}`));
45283
45565
  );
45284
45566
  }
45285
45567
  function registerProjectCreate(program3) {
45286
- program3.command("project:create").description('Create a new project\n Example: elevasis-sdk project:create --name "My Project" --kind internal').requiredOption("--name <name>", "Project name").requiredOption("--kind <kind>", "Project kind: client_engagement | internal | research | other").option("--status <status>", "Project status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "Project description").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45568
+ program3.command("project:create").description('Create a new project\n Example: elevasis-sdk project:create --name "My Project" --kind internal').requiredOption("--name <name>", "Project name").requiredOption("--kind <kind>", "Project kind: client_engagement | internal | research | other").option("--status <status>", "Project status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "Project description").option("--deal-id <uuid>", "Link to a deal (UUID)").option("--client-company-id <uuid>", "Link to a client company (UUID)").option("--start-date <date>", "Start date (ISO 8601, e.g. 2026-06-01)").option("--target-end-date <date>", "Target end date (ISO 8601, e.g. 2026-12-31)").option("--contract-value <amount>", "Contract value (number)", parseFloat).option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45287
45569
  wrapAction(
45288
45570
  "project:create",
45289
45571
  async (options2) => {
@@ -45294,6 +45576,12 @@ function registerProjectCreate(program3) {
45294
45576
  };
45295
45577
  if (options2.status) body.status = options2.status;
45296
45578
  if (options2.description) body.description = options2.description;
45579
+ if (options2.dealId) body.deal_id = options2.dealId;
45580
+ if (options2.clientCompanyId) body.client_company_id = options2.clientCompanyId;
45581
+ if (options2.startDate) body.start_date = options2.startDate;
45582
+ if (options2.targetEndDate) body.target_end_date = options2.targetEndDate;
45583
+ if (options2.contractValue !== void 0) body.contract_value = options2.contractValue;
45584
+ if (options2.metadata) body.metadata = JSON.parse(options2.metadata);
45297
45585
  const result = await apiPost("/api/external/projects", body, apiUrl);
45298
45586
  if (options2.pretty) {
45299
45587
  const p = result.project;
@@ -45311,7 +45599,7 @@ Project created: ${p.name}`));
45311
45599
  );
45312
45600
  }
45313
45601
  function registerProjectUpdate(program3) {
45314
- program3.command("project:update <id>").description("Update a project\n Example: elevasis-sdk project:update <uuid> --status completed").option("--name <name>", "New project name").option("--status <status>", "New status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "New description").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45602
+ program3.command("project:update <id>").description("Update a project\n Example: elevasis-sdk project:update <uuid> --status completed").option("--name <name>", "New project name").option("--status <status>", "New status: active | on_track | at_risk | blocked | completed | paused").option("--description <description>", "New description").option("--deal-id <uuid>", "Link to a deal (UUID)").option("--client-company-id <uuid>", "Link to a client company (UUID)").option("--start-date <date>", "Start date (ISO 8601, e.g. 2026-06-01)").option("--target-end-date <date>", "Target end date (ISO 8601, e.g. 2026-12-31)").option("--actual-end-date <date>", "Actual end date (ISO 8601)").option("--contract-value <amount>", "Contract value (number)", parseFloat).option("--metadata <json>", "Arbitrary metadata (JSON string)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45315
45603
  wrapAction(
45316
45604
  "project:update",
45317
45605
  async (id, options2) => {
@@ -45319,10 +45607,17 @@ function registerProjectUpdate(program3) {
45319
45607
  if (options2.name !== void 0) body.name = options2.name;
45320
45608
  if (options2.status !== void 0) body.status = options2.status;
45321
45609
  if (options2.description !== void 0) body.description = options2.description;
45610
+ if (options2.dealId !== void 0) body.deal_id = options2.dealId;
45611
+ if (options2.clientCompanyId !== void 0) body.client_company_id = options2.clientCompanyId;
45612
+ if (options2.startDate !== void 0) body.start_date = options2.startDate;
45613
+ if (options2.targetEndDate !== void 0) body.target_end_date = options2.targetEndDate;
45614
+ if (options2.actualEndDate !== void 0) body.actual_end_date = options2.actualEndDate;
45615
+ if (options2.contractValue !== void 0) body.contract_value = options2.contractValue;
45616
+ if (options2.metadata !== void 0) body.metadata = JSON.parse(options2.metadata);
45322
45617
  if (Object.keys(body).length === 0) {
45323
45618
  process.stderr.write(
45324
45619
  JSON.stringify({
45325
- error: "At least one field must be provided (--name, --status, --description)",
45620
+ error: "At least one field must be provided (--name, --status, --description, --deal-id, --client-company-id, --start-date, --target-end-date, --actual-end-date, --contract-value, --metadata)",
45326
45621
  code: "MISSING_FIELDS"
45327
45622
  }) + "\n"
45328
45623
  );
@@ -45419,7 +45714,7 @@ Milestone created: ${m.name}`));
45419
45714
  );
45420
45715
  }
45421
45716
  function registerMilestoneUpdate(program3) {
45422
- program3.command("project:milestone:update <id>").description("Update a milestone\n Example: elevasis-sdk project:milestone:update <uuid> --status completed").option("--name <name>", "New milestone name").option("--status <status>", "New status: upcoming | in_progress | completed | overdue | blocked").option("--due-date <date>", "New due date (ISO 8601)").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45717
+ program3.command("project:milestone:update <id>").description("Update a milestone\n Example: elevasis-sdk project:milestone:update <uuid> --status completed").option("--name <name>", "New milestone name").option("--status <status>", "New status: upcoming | in_progress | completed | overdue | blocked").option("--due-date <date>", "New due date (ISO 8601)").option("--checklist <json>", `Replace checklist (full array): '[{"id":"1","label":"Step","completed":false}]'`).option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45423
45718
  wrapAction(
45424
45719
  "project:milestone:update",
45425
45720
  async (id, options2) => {
@@ -45427,10 +45722,20 @@ function registerMilestoneUpdate(program3) {
45427
45722
  if (options2.name !== void 0) body.name = options2.name;
45428
45723
  if (options2.status !== void 0) body.status = options2.status;
45429
45724
  if (options2.dueDate !== void 0) body.due_date = options2.dueDate;
45725
+ if (options2.checklist !== void 0) {
45726
+ try {
45727
+ body.checklist = JSON.parse(options2.checklist);
45728
+ } catch {
45729
+ process.stderr.write(
45730
+ JSON.stringify({ error: "--checklist must be valid JSON", code: "INVALID_JSON" }) + "\n"
45731
+ );
45732
+ process.exit(1);
45733
+ }
45734
+ }
45430
45735
  if (Object.keys(body).length === 0) {
45431
45736
  process.stderr.write(
45432
45737
  JSON.stringify({
45433
- error: "At least one field must be provided (--name, --status, --due-date)",
45738
+ error: "At least one field must be provided (--name, --status, --due-date, --checklist)",
45434
45739
  code: "MISSING_FIELDS"
45435
45740
  }) + "\n"
45436
45741
  );
@@ -45578,7 +45883,7 @@ function registerTaskUpdate(program3) {
45578
45883
  program3.command("project:task:update <id>").description("Update a task\n Example: elevasis-sdk project:task:update <uuid> --status completed").option("--title <title>", "New task title").option(
45579
45884
  "--status <status>",
45580
45885
  "New status: planned | in_progress | blocked | completed | cancelled | submitted | approved | rejected | revision_requested"
45581
- ).option("--milestone <milestone-id>", "New milestone ID (UUID)").option("--description <description>", "New description").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45886
+ ).option("--milestone <milestone-id>", "New milestone ID (UUID)").option("--description <description>", "New description").option("--checklist <json>", `Replace checklist (full array): '[{"id":"1","label":"Step","completed":false}]'`).option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45582
45887
  wrapAction(
45583
45888
  "project:task:update",
45584
45889
  async (id, options2) => {
@@ -45587,10 +45892,20 @@ function registerTaskUpdate(program3) {
45587
45892
  if (options2.status !== void 0) body.status = options2.status;
45588
45893
  if (options2.milestone !== void 0) body.milestone_id = options2.milestone;
45589
45894
  if (options2.description !== void 0) body.description = options2.description;
45895
+ if (options2.checklist !== void 0) {
45896
+ try {
45897
+ body.checklist = JSON.parse(options2.checklist);
45898
+ } catch {
45899
+ process.stderr.write(
45900
+ JSON.stringify({ error: "--checklist must be valid JSON", code: "INVALID_JSON" }) + "\n"
45901
+ );
45902
+ process.exit(1);
45903
+ }
45904
+ }
45590
45905
  if (Object.keys(body).length === 0) {
45591
45906
  process.stderr.write(
45592
45907
  JSON.stringify({
45593
- error: "At least one field must be provided (--title, --status, --milestone, --description)",
45908
+ error: "At least one field must be provided (--title, --status, --milestone, --description, --checklist)",
45594
45909
  code: "MISSING_FIELDS"
45595
45910
  }) + "\n"
45596
45911
  );
@@ -45766,7 +46081,7 @@ Notes (${notes.length}):
45766
46081
  function registerNoteCreate(program3) {
45767
46082
  program3.command("project:note:create").description(
45768
46083
  'Create a note\n Example: elevasis-sdk project:note:create --project <uuid> --content "Status update"'
45769
- ).requiredOption("--project <project-id>", "Project ID (UUID)").requiredOption("--content <content>", "Note content").option("--task <task-id>", "Attach to a task (UUID)").option("--milestone <milestone-id>", "Attach to a milestone (UUID)").option("--type <type>", "Note type: call_note | status_update | issue | blocker").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
46084
+ ).requiredOption("--project <project-id>", "Project ID (UUID)").requiredOption("--content <content>", "Note content").option("--task <task-id>", "Attach to a task (UUID)").option("--milestone <milestone-id>", "Attach to a milestone (UUID)").option("--type <type>", "Note type: call_note | status_update | issue | blocker | agent_learning").option("--api-url <url>", "API base URL").option("--pretty", "Render human-readable output instead of raw JSON").action(
45770
46085
  wrapAction(
45771
46086
  "project:note:create",
45772
46087
  async (options2) => {
@@ -45827,6 +46142,8 @@ Note ${id} deleted.`));
45827
46142
  // src/cli/commands/project/project.ts
45828
46143
  function registerProjectCommands(program3) {
45829
46144
  registerProjectList(program3);
46145
+ registerProjectResolve(program3);
46146
+ registerProjectWork(program3);
45830
46147
  registerProjectGet(program3);
45831
46148
  registerProjectCreate(program3);
45832
46149
  registerProjectUpdate(program3);
@@ -45848,6 +46165,520 @@ function registerProjectCommands(program3) {
45848
46165
  registerNoteDelete(program3);
45849
46166
  }
45850
46167
 
46168
+ // src/cli/commands/init-claude.ts
46169
+ var import_path4 = require("path");
46170
+ var import_fs2 = require("fs");
46171
+ var import_url = require("url");
46172
+ var import_meta = {};
46173
+ var _filename = import_meta.url ? (0, import_url.fileURLToPath)(import_meta.url) : process.argv[1];
46174
+ var _dirname = (0, import_path4.dirname)(_filename);
46175
+ function copyDirectoryRecursive(sourceDir, targetDir) {
46176
+ if (!(0, import_fs2.existsSync)(sourceDir)) return 0;
46177
+ let count = 0;
46178
+ for (const entry of (0, import_fs2.readdirSync)(sourceDir, { withFileTypes: true })) {
46179
+ const srcPath = (0, import_path4.join)(sourceDir, entry.name);
46180
+ const destPath = (0, import_path4.join)(targetDir, entry.name);
46181
+ if (entry.isDirectory()) {
46182
+ count += copyDirectoryRecursive(srcPath, destPath);
46183
+ } else {
46184
+ (0, import_fs2.mkdirSync)((0, import_path4.dirname)(destPath), { recursive: true });
46185
+ (0, import_fs2.writeFileSync)(destPath, (0, import_fs2.readFileSync)(srcPath, "utf-8"), "utf-8");
46186
+ count++;
46187
+ }
46188
+ }
46189
+ return count;
46190
+ }
46191
+ function listFilesRecursive(dir, prefix = "") {
46192
+ for (const entry of (0, import_fs2.readdirSync)(dir, { withFileTypes: true })) {
46193
+ const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
46194
+ if (entry.isDirectory()) {
46195
+ listFilesRecursive((0, import_path4.join)(dir, entry.name), rel);
46196
+ } else {
46197
+ console.log(source_default.gray(` .claude/${rel}`));
46198
+ }
46199
+ }
46200
+ }
46201
+ function registerInitClaudeCommand(program3) {
46202
+ program3.command("init-claude").description("Initialize or update .claude/ configuration from SDK defaults").option("--dry-run", "Show what would be copied without writing files").action(
46203
+ wrapAction("init-claude", async (options2) => {
46204
+ const spinner = ora("Initializing .claude/ configuration...").start();
46205
+ const claudeConfigSource = (0, import_path4.resolve)(_dirname, "..", "reference", "claude-config");
46206
+ if (!(0, import_fs2.existsSync)(claudeConfigSource)) {
46207
+ spinner.fail("Claude config source not found in SDK package");
46208
+ console.error(source_default.gray(` Expected: ${claudeConfigSource}`));
46209
+ console.error(source_default.gray(" This may indicate an incomplete SDK build."));
46210
+ throw new Error("Claude config source not found");
46211
+ }
46212
+ const targetDir = (0, import_path4.resolve)(process.cwd(), ".claude");
46213
+ if (options2.dryRun) {
46214
+ spinner.info("Dry run -- listing files that would be copied:");
46215
+ listFilesRecursive(claudeConfigSource);
46216
+ return;
46217
+ }
46218
+ const count = copyDirectoryRecursive(claudeConfigSource, targetDir);
46219
+ spinner.succeed(
46220
+ source_default.green(".claude/ configuration initialized") + source_default.gray(` (${count} file${count !== 1 ? "s" : ""} written)`)
46221
+ );
46222
+ })
46223
+ );
46224
+ }
46225
+
46226
+ // src/cli/commands/generate-docs.ts
46227
+ var import_fs3 = require("fs");
46228
+ var import_path5 = require("path");
46229
+ var EXCLUDED_ROOT_FILES = /* @__PURE__ */ new Set(["platform-navigation-map.md"]);
46230
+ var SECTION_ORDER = ["ui", "operations", "knowledge"];
46231
+ var LAST_SECTIONS = ["in-progress"];
46232
+ function parseFrontmatter(content) {
46233
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
46234
+ if (!match) return null;
46235
+ const fm = {};
46236
+ for (const line of match[1].split("\n")) {
46237
+ const idx = line.indexOf(":");
46238
+ if (idx === -1) continue;
46239
+ const key = line.slice(0, idx).trim();
46240
+ const val = line.slice(idx + 1).trim();
46241
+ fm[key] = val;
46242
+ }
46243
+ return fm;
46244
+ }
46245
+ function findMdFiles(dir, docsDir, indexPath, files = []) {
46246
+ for (const entry of (0, import_fs3.readdirSync)(dir)) {
46247
+ if (entry.startsWith(".")) continue;
46248
+ const full = (0, import_path5.join)(dir, entry);
46249
+ const stat = (0, import_fs3.statSync)(full);
46250
+ if (stat.isDirectory()) {
46251
+ findMdFiles(full, docsDir, indexPath, files);
46252
+ } else if (entry.endsWith(".md") && full !== indexPath) {
46253
+ if (dir === docsDir && EXCLUDED_ROOT_FILES.has(entry)) continue;
46254
+ files.push(full);
46255
+ }
46256
+ }
46257
+ return files;
46258
+ }
46259
+ function sectionTitle(slug) {
46260
+ if (slug === "ui") return "UI";
46261
+ return slug.split("-").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
46262
+ }
46263
+ function generateDocsIndex(docsDir) {
46264
+ const indexPath = (0, import_path5.join)(docsDir, "index.md");
46265
+ const files = findMdFiles(docsDir, docsDir, indexPath);
46266
+ const sections = /* @__PURE__ */ new Map();
46267
+ let warnings = 0;
46268
+ for (const file2 of files) {
46269
+ const rel = (0, import_path5.relative)(docsDir, file2).replace(/\\/g, "/");
46270
+ const content2 = (0, import_fs3.readFileSync)(file2, "utf-8");
46271
+ const fm = parseFrontmatter(content2);
46272
+ if (!fm || !fm["title"]) {
46273
+ console.warn(`WARNING: Missing frontmatter in ${rel} -- skipping`);
46274
+ warnings++;
46275
+ continue;
46276
+ }
46277
+ const topDir = rel.includes("/") ? rel.split("/")[0] : "_root";
46278
+ if (!sections.has(topDir)) sections.set(topDir, []);
46279
+ sections.get(topDir).push({ rel, title: fm["title"], description: fm["description"] || "", status: fm["status"] });
46280
+ }
46281
+ for (const entries of sections.values()) {
46282
+ entries.sort((a, b) => a.title.localeCompare(b.title));
46283
+ }
46284
+ const orderedSections = [];
46285
+ for (const s of SECTION_ORDER) {
46286
+ if (sections.has(s)) orderedSections.push(s);
46287
+ }
46288
+ for (const s of [...sections.keys()].sort()) {
46289
+ if (!SECTION_ORDER.includes(s) && !LAST_SECTIONS.includes(s) && s !== "_root") {
46290
+ orderedSections.push(s);
46291
+ }
46292
+ }
46293
+ for (const s of LAST_SECTIONS) {
46294
+ if (sections.has(s)) orderedSections.push(s);
46295
+ }
46296
+ if (sections.has("_root")) orderedSections.push("_root");
46297
+ const lines = [
46298
+ "---",
46299
+ "title: Documentation Index",
46300
+ "description: Auto-generated navigation hub of all project documentation",
46301
+ "---",
46302
+ "",
46303
+ "<!-- AUTO-GENERATED by elevasis-sdk generate-docs -- do not edit manually -->",
46304
+ "",
46305
+ "# Documentation Index",
46306
+ "",
46307
+ `> Last generated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`,
46308
+ ""
46309
+ ];
46310
+ if (orderedSections.length === 0) {
46311
+ lines.push("No documented files found. Add frontmatter (`title`, `description`) to `.md` files in `docs/`.");
46312
+ lines.push("");
46313
+ } else {
46314
+ for (const section of orderedSections) {
46315
+ const entries = sections.get(section);
46316
+ if (!entries || entries.length === 0) continue;
46317
+ const title = section === "_root" ? "General" : sectionTitle(section);
46318
+ lines.push(`## ${title}`);
46319
+ lines.push("");
46320
+ for (const entry of entries) {
46321
+ const status = entry.status ? ` -- *${entry.status}*` : "";
46322
+ const desc = entry.description ? ` -- ${entry.description}` : "";
46323
+ lines.push(`- [${entry.title}](${entry.rel})${desc}${status}`);
46324
+ }
46325
+ lines.push("");
46326
+ }
46327
+ }
46328
+ const content = lines.join("\n");
46329
+ const docCount = files.length - warnings;
46330
+ console.log(
46331
+ `Generated docs/index.md: ${docCount} doc(s) indexed across ${orderedSections.length} section(s)` + (warnings > 0 ? ` (${warnings} skipped -- missing frontmatter)` : "")
46332
+ );
46333
+ return content;
46334
+ }
46335
+ function registerGenerateDocsCommand(program3) {
46336
+ program3.command("generate-docs").description("Generate docs/index.md from documentation frontmatter").option("--docs-dir <path>", "Path to docs directory (default: ./docs)").action(
46337
+ wrapAction("generate-docs", async (options2) => {
46338
+ const docsDir = (0, import_path5.resolve)(options2.docsDir ?? "./docs");
46339
+ const indexPath = (0, import_path5.join)(docsDir, "index.md");
46340
+ const spinner = ora("Generating docs/index.md...").start();
46341
+ const content = generateDocsIndex(docsDir);
46342
+ (0, import_fs3.writeFileSync)(indexPath, content);
46343
+ spinner.succeed(source_default.green("Generated docs/index.md"));
46344
+ })
46345
+ );
46346
+ }
46347
+
46348
+ // src/cli/commands/generate-resources.ts
46349
+ var import_promises2 = require("fs/promises");
46350
+ var import_path6 = require("path");
46351
+ function escapePipes(text) {
46352
+ return text.replace(/\|/g, "\\|");
46353
+ }
46354
+ function noneIfEmpty(lines, body) {
46355
+ const result = body();
46356
+ if (result.length === 0) {
46357
+ return [...lines, "_(none)_", ""];
46358
+ }
46359
+ return [...lines, ...result, ""];
46360
+ }
46361
+ function extractSchemaKeys(schema) {
46362
+ if (!schema || typeof schema !== "object") return null;
46363
+ const s = schema;
46364
+ if (s.shape && typeof s.shape === "object") {
46365
+ return Object.keys(s.shape).join(", ");
46366
+ }
46367
+ if (s._def && typeof s._def === "object") {
46368
+ const def = s._def;
46369
+ if (typeof def.shape === "function") {
46370
+ try {
46371
+ const shape = def.shape();
46372
+ return Object.keys(shape).join(", ");
46373
+ } catch {
46374
+ return null;
46375
+ }
46376
+ }
46377
+ if (Array.isArray(def.options) && def.options.every((o) => typeof o === "string")) {
46378
+ return def.options.join(" | ");
46379
+ }
46380
+ }
46381
+ if (s.properties && typeof s.properties === "object") {
46382
+ return Object.keys(s.properties).join(", ");
46383
+ }
46384
+ return null;
46385
+ }
46386
+ async function generateResourcesContent(spec) {
46387
+ const workflows = spec.workflows ?? [];
46388
+ const agents = spec.agents ?? [];
46389
+ const triggers = spec.triggers ?? [];
46390
+ const integrations = spec.integrations ?? [];
46391
+ const relationships = spec.relationships ?? {};
46392
+ const externalResources = spec.externalResources ?? [];
46393
+ const humanCheckpoints = spec.humanCheckpoints ?? [];
46394
+ const lines = [
46395
+ "---",
46396
+ "title: Platform Topology Map",
46397
+ "description: Auto-generated topology map for workflows, agents, relationships, triggers, integrations, and checkpoints declared in the DeploymentSpec",
46398
+ "---",
46399
+ "",
46400
+ "<!-- AUTO-GENERATED by elevasis-sdk generate-resources -- do not edit manually -->",
46401
+ "",
46402
+ "# Platform Topology Map",
46403
+ "",
46404
+ "> Auto-generated from `operations/src/index.ts`. Regenerate with `pnpm exec elevasis-sdk generate-resources`.",
46405
+ "",
46406
+ "Use this as the scaffold topology map for operational impact analysis.",
46407
+ "",
46408
+ "- Start here to understand what `operations/src/index.ts` deploys and how those resources connect.",
46409
+ "- Read it with `operations/src/README.md` when changing resource registration or deployment structure.",
46410
+ "- Treat `elevasis-sdk generate-resources` and the current `DeploymentSpec` as the source of truth for what this map can and cannot show.",
46411
+ ""
46412
+ ];
46413
+ const total = workflows.length + agents.length;
46414
+ lines.push("## Topology Summary", "");
46415
+ lines.push(`- Deployable resources: ${total}`);
46416
+ lines.push(`- Workflows: ${workflows.length}`);
46417
+ lines.push(`- Agents: ${agents.length}`);
46418
+ lines.push(`- Triggers: ${triggers.length}`);
46419
+ lines.push(`- Integrations: ${integrations.length}`);
46420
+ lines.push(`- Human checkpoints: ${humanCheckpoints.length}`);
46421
+ lines.push(`- External resources: ${externalResources.length}`);
46422
+ lines.push(`- Relationship declarations: ${Object.keys(relationships).length}`);
46423
+ lines.push("");
46424
+ lines.push("## Deployed Resource Inventory", "");
46425
+ lines.push(
46426
+ ...noneIfEmpty([], () => {
46427
+ if (workflows.length === 0 && agents.length === 0) return [];
46428
+ const rows = [];
46429
+ if (workflows.length > 0) {
46430
+ rows.push("### Workflows", "");
46431
+ rows.push("| Resource ID | Name | Version | Status | Description | Domains |");
46432
+ rows.push("| --- | --- | --- | --- | --- | --- |");
46433
+ for (const wf of workflows) {
46434
+ const { resourceId, name, version: version2, status, description, domains } = wf.config;
46435
+ const domainStr = domains?.join(", ") ?? "";
46436
+ rows.push(
46437
+ `| \`${escapePipes(resourceId)}\` | ${escapePipes(name)} | ${escapePipes(version2)} | ${escapePipes(status)} | ${escapePipes(description ?? "")} | ${escapePipes(domainStr)} |`
46438
+ );
46439
+ }
46440
+ rows.push("");
46441
+ }
46442
+ if (agents.length > 0) {
46443
+ rows.push("### Agents", "");
46444
+ rows.push("| Resource ID | Name | Version | Status | Description | Domains | Session-Capable |");
46445
+ rows.push("| --- | --- | --- | --- | --- | --- | --- |");
46446
+ for (const ag of agents) {
46447
+ const { resourceId, name, version: version2, status, description, domains } = ag.config;
46448
+ const sessionCapable = ag.config.sessionCapable ? "Yes" : "No";
46449
+ const domainStr = domains?.join(", ") ?? "";
46450
+ rows.push(
46451
+ `| \`${escapePipes(resourceId)}\` | ${escapePipes(name)} | ${escapePipes(version2)} | ${escapePipes(status)} | ${escapePipes(description ?? "")} | ${escapePipes(domainStr)} | ${sessionCapable} |`
46452
+ );
46453
+ }
46454
+ rows.push("");
46455
+ }
46456
+ return rows;
46457
+ })
46458
+ );
46459
+ lines.push("## Topology Relationships", "");
46460
+ lines.push(
46461
+ ...noneIfEmpty([], () => {
46462
+ const entries = Object.entries(relationships).filter(([, decl]) => {
46463
+ const hasTriggers = (decl.triggers?.agents?.length ?? 0) > 0 || (decl.triggers?.workflows?.length ?? 0) > 0;
46464
+ const hasUses = (decl.uses?.integrations?.length ?? 0) > 0;
46465
+ return hasTriggers || hasUses;
46466
+ });
46467
+ if (entries.length === 0) return [];
46468
+ const rows = [];
46469
+ for (const [resourceId, decl] of entries) {
46470
+ rows.push(`- **\`${resourceId}\`**`);
46471
+ const triggerAgents = decl.triggers?.agents ?? [];
46472
+ const triggerWorkflows = decl.triggers?.workflows ?? [];
46473
+ const usesIntegrations = decl.uses?.integrations ?? [];
46474
+ if (triggerAgents.length > 0 || triggerWorkflows.length > 0) {
46475
+ rows.push(" - Triggers:");
46476
+ for (const id of triggerWorkflows) rows.push(` - workflow \`${id}\``);
46477
+ for (const id of triggerAgents) rows.push(` - agent \`${id}\``);
46478
+ }
46479
+ if (usesIntegrations.length > 0) {
46480
+ rows.push(" - Uses:");
46481
+ for (const id of usesIntegrations) rows.push(` - integration \`${id}\``);
46482
+ }
46483
+ }
46484
+ return rows;
46485
+ })
46486
+ );
46487
+ lines.push("## Triggers", "");
46488
+ lines.push(
46489
+ ...noneIfEmpty([], () => {
46490
+ if (triggers.length === 0) return [];
46491
+ const rows = [
46492
+ "| Resource ID | Trigger Type | Webhook Path | Schedule | Event Type |",
46493
+ "| --- | --- | --- | --- | --- |"
46494
+ ];
46495
+ for (const tr of triggers) {
46496
+ const webhookPath = escapePipes(tr.webhookPath ?? "");
46497
+ const schedule = escapePipes(tr.schedule ?? "");
46498
+ const eventType = escapePipes(tr.eventType ?? "");
46499
+ rows.push(
46500
+ `| \`${escapePipes(tr.resourceId)}\` | ${escapePipes(tr.triggerType)} | ${webhookPath} | ${schedule} | ${eventType} |`
46501
+ );
46502
+ }
46503
+ return rows;
46504
+ })
46505
+ );
46506
+ lines.push("## Integrations", "");
46507
+ lines.push(
46508
+ ...noneIfEmpty([], () => {
46509
+ if (integrations.length === 0) return [];
46510
+ const rows = ["| Resource ID | Provider | Credential Name |", "| --- | --- | --- |"];
46511
+ for (const ig of integrations) {
46512
+ rows.push(
46513
+ `| \`${escapePipes(ig.resourceId)}\` | ${escapePipes(ig.provider)} | \`${escapePipes(ig.credentialName)}\` |`
46514
+ );
46515
+ }
46516
+ return rows;
46517
+ })
46518
+ );
46519
+ lines.push("## Human Checkpoints", "");
46520
+ lines.push(
46521
+ ...noneIfEmpty([], () => {
46522
+ if (humanCheckpoints.length === 0) return [];
46523
+ const rows = [];
46524
+ rows.push("| Resource ID | Requested By | Routes To |");
46525
+ rows.push("| --- | --- | --- |");
46526
+ for (const hc of humanCheckpoints) {
46527
+ const requestedBy = [
46528
+ ...(hc.requestedBy?.agents ?? []).map((id) => `agent \`${id}\``),
46529
+ ...(hc.requestedBy?.workflows ?? []).map((id) => `workflow \`${id}\``)
46530
+ ].join(", ");
46531
+ const routesTo = [
46532
+ ...(hc.routesTo?.agents ?? []).map((id) => `agent \`${id}\``),
46533
+ ...(hc.routesTo?.workflows ?? []).map((id) => `workflow \`${id}\``)
46534
+ ].join(", ");
46535
+ rows.push(`| \`${escapePipes(hc.resourceId)}\` | ${escapePipes(requestedBy)} | ${escapePipes(routesTo)} |`);
46536
+ }
46537
+ return rows;
46538
+ })
46539
+ );
46540
+ lines.push("## External Resources", "");
46541
+ lines.push(
46542
+ ...noneIfEmpty([], () => {
46543
+ if (externalResources.length === 0) return [];
46544
+ const rows = [
46545
+ "| Resource ID | Platform | Platform URL | External ID | Triggers | Uses |",
46546
+ "| --- | --- | --- | --- | --- | --- |"
46547
+ ];
46548
+ for (const er of externalResources) {
46549
+ const triggersList = [
46550
+ ...(er.triggers?.workflows ?? []).map((id) => `workflow \`${id}\``),
46551
+ ...(er.triggers?.agents ?? []).map((id) => `agent \`${id}\``)
46552
+ ].join(", ");
46553
+ const usesList = (er.uses?.integrations ?? []).map((id) => `integration \`${id}\``).join(", ");
46554
+ rows.push(
46555
+ `| \`${escapePipes(er.resourceId)}\` | ${escapePipes(er.platform)} | ${escapePipes(er.platformUrl ?? "")} | ${escapePipes(er.externalId ?? "")} | ${escapePipes(triggersList)} | ${escapePipes(usesList)} |`
46556
+ );
46557
+ }
46558
+ return rows;
46559
+ })
46560
+ );
46561
+ lines.push("## Schema Signatures", "");
46562
+ const allResources = [
46563
+ ...workflows.map((wf) => ({ resourceId: wf.config.resourceId, contract: wf.contract })),
46564
+ ...agents.map((ag) => ({ resourceId: ag.config.resourceId, contract: ag.contract }))
46565
+ ];
46566
+ lines.push(
46567
+ ...noneIfEmpty([], () => {
46568
+ if (allResources.length === 0) return [];
46569
+ const rows = [];
46570
+ for (const { resourceId, contract } of allResources) {
46571
+ const inputKeys = contract?.inputSchema ? extractSchemaKeys(contract.inputSchema) : null;
46572
+ const outputKeys = contract?.outputSchema ? extractSchemaKeys(contract.outputSchema) : null;
46573
+ const inputSig = inputKeys !== null ? `\`{ ${inputKeys} }\`` : "_schema introspection unavailable \u2014 see source_";
46574
+ const outputSig = outputKeys !== null ? `\`{ ${outputKeys} }\`` : "_schema introspection unavailable \u2014 see source_";
46575
+ rows.push(`- **\`${resourceId}\`**`);
46576
+ rows.push(` - input: ${inputSig}`);
46577
+ rows.push(` - output: ${outputSig}`);
46578
+ }
46579
+ return rows;
46580
+ })
46581
+ );
46582
+ lines.push(
46583
+ `**Total:** ${total} resource${total !== 1 ? "s" : ""} (${workflows.length} workflow${workflows.length !== 1 ? "s" : ""}, ${agents.length} agent${agents.length !== 1 ? "s" : ""})`
46584
+ );
46585
+ lines.push("");
46586
+ return lines.join("\n");
46587
+ }
46588
+ function registerGenerateResourcesCommand(program3) {
46589
+ program3.command("generate-resources").description("Generate docs/resources.md from the DeploymentSpec").option("--entry <path>", "Path to operations entry file (default: ./src/index.ts)").option("--docs-dir <path>", "Path to docs directory (default: ../docs from entry)").action(
46590
+ wrapAction("generate-resources", async (options2) => {
46591
+ const entryPath = options2.entry ?? "./src/index.ts";
46592
+ const spinner = ora("Generating resources documentation...").start();
46593
+ const entryModule = await loadTsModule(entryPath);
46594
+ const spec = entryModule.default;
46595
+ if (!spec) {
46596
+ spinner.fail("Invalid entry: no default export found");
46597
+ throw new Error("Invalid entry");
46598
+ }
46599
+ const docsDir = (0, import_path6.resolve)(options2.docsDir ?? (0, import_path6.resolve)(entryPath, "../../docs"));
46600
+ const docsPath = (0, import_path6.resolve)(docsDir, "resources.md");
46601
+ const content = await generateResourcesContent(spec);
46602
+ await (0, import_promises2.mkdir)(docsDir, { recursive: true });
46603
+ await (0, import_promises2.writeFile)(docsPath, content, "utf-8");
46604
+ const workflows = spec.workflows ?? [];
46605
+ const agents = spec.agents ?? [];
46606
+ const total = workflows.length + agents.length;
46607
+ spinner.succeed(source_default.green("Generated docs/resources.md"));
46608
+ console.log(source_default.gray(` ${total} resource(s) (${workflows.length} workflow(s), ${agents.length} agent(s))`));
46609
+ })
46610
+ );
46611
+ }
46612
+
46613
+ // src/cli/commands/validate-docs.ts
46614
+ var import_fs4 = require("fs");
46615
+ var import_path7 = require("path");
46616
+ var import_child_process = require("child_process");
46617
+ function normalizeEol(value) {
46618
+ return value.replace(/\r\n/g, "\n");
46619
+ }
46620
+ function readRequiredFile(filePath) {
46621
+ if (!(0, import_fs4.existsSync)(filePath)) {
46622
+ throw new Error(`Missing generated file: ${filePath}`);
46623
+ }
46624
+ return normalizeEol((0, import_fs4.readFileSync)(filePath, "utf8"));
46625
+ }
46626
+ function runPnpmExec(args, cwd) {
46627
+ if (process.platform === "win32") {
46628
+ const command = `pnpm exec ${args.join(" ")}`;
46629
+ (0, import_child_process.execFileSync)(process.env["ComSpec"] ?? "cmd.exe", ["/d", "/s", "/c", command], {
46630
+ cwd,
46631
+ stdio: "pipe",
46632
+ encoding: "utf8"
46633
+ });
46634
+ return;
46635
+ }
46636
+ (0, import_child_process.execFileSync)("pnpm", ["exec", ...args], {
46637
+ cwd,
46638
+ stdio: "pipe",
46639
+ encoding: "utf8"
46640
+ });
46641
+ }
46642
+ function validateCommandOutput(filePath, commandDescription, sdkArgs, cwd) {
46643
+ const before = readRequiredFile(filePath);
46644
+ runPnpmExec(sdkArgs, cwd);
46645
+ const after = readRequiredFile(filePath);
46646
+ if (before !== after) {
46647
+ throw new Error(`Drift detected in ${filePath}. Regenerate with \`${commandDescription}\`.`);
46648
+ }
46649
+ }
46650
+ function registerValidateDocsCommand(program3) {
46651
+ program3.command("validate-docs").description("Validate that auto-generated docs are up to date").option("--docs-dir <path>", "Path to docs directory (default: ./docs)").option("--entry <path>", "Path to operations entry file for resources validation (default: ./src/index.ts)").action(
46652
+ wrapAction("validate-docs", async (options2) => {
46653
+ const spinner = ora("Validating generated docs...").start();
46654
+ const projectRoot = process.cwd();
46655
+ const docsDir = (0, import_path7.resolve)(options2.docsDir ?? "./docs");
46656
+ const entryPath = options2.entry ?? "./src/index.ts";
46657
+ spinner.text = "Validating docs/index.md...";
46658
+ const indexPath = (0, import_path7.join)(docsDir, "index.md");
46659
+ const generateDocsArgs = ["elevasis-sdk", "generate-docs", "--docs-dir", docsDir];
46660
+ validateCommandOutput(indexPath, "pnpm exec elevasis-sdk generate-docs", generateDocsArgs, projectRoot);
46661
+ spinner.text = "Validating docs/resources.md...";
46662
+ const resourcesPath = (0, import_path7.join)(docsDir, "resources.md");
46663
+ const generateResourcesArgs = [
46664
+ "elevasis-sdk",
46665
+ "generate-resources",
46666
+ "--entry",
46667
+ entryPath,
46668
+ "--docs-dir",
46669
+ docsDir
46670
+ ];
46671
+ validateCommandOutput(
46672
+ resourcesPath,
46673
+ "pnpm exec elevasis-sdk generate-resources",
46674
+ generateResourcesArgs,
46675
+ projectRoot
46676
+ );
46677
+ spinner.succeed(source_default.green("Generated docs are fresh."));
46678
+ })
46679
+ );
46680
+ }
46681
+
45851
46682
  // src/cli/index.ts
45852
46683
  var envPath = findEnvFile();
45853
46684
  if (envPath) {
@@ -45873,7 +46704,14 @@ Commands:
45873
46704
  elevasis-sdk executions <resourceId> List execution history
45874
46705
  elevasis-sdk execution <resourceId> <id> Get execution details
45875
46706
  elevasis-sdk deployments List deployments
46707
+ elevasis-sdk project:list [--search <query>] List projects with optional search
46708
+ elevasis-sdk project:resolve <query> Resolve a project ID from a name or UUID
46709
+ elevasis-sdk project:work <query> Open a lifecycle-aware project work brief
45876
46710
  elevasis-sdk rename <id> --to <newId> [--prod] Rename resource across platform tables
46711
+ elevasis-sdk init-claude Initialize .claude/ config from SDK
46712
+ elevasis-sdk generate-docs Generate docs/index.md from frontmatter
46713
+ elevasis-sdk generate-resources Generate docs/resources.md from DeploymentSpec
46714
+ elevasis-sdk validate-docs Validate generated docs are fresh
45877
46715
 
45878
46716
  Use "elevasis-sdk <command> --help" for more information about a command.`
45879
46717
  ).version(SDK_VERSION);
@@ -45889,6 +46727,10 @@ registerCredsCommand(program2);
45889
46727
  registerErrorCommand(program2);
45890
46728
  registerRenameCommand(program2);
45891
46729
  registerProjectCommands(program2);
46730
+ registerInitClaudeCommand(program2);
46731
+ registerGenerateDocsCommand(program2);
46732
+ registerGenerateResourcesCommand(program2);
46733
+ registerValidateDocsCommand(program2);
45892
46734
  program2.parse();
45893
46735
  /*! Bundled license information:
45894
46736