@growthub/cli 0.9.0 → 0.9.2

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/index.js CHANGED
@@ -8182,8 +8182,8 @@ var init_onboard = __esm({
8182
8182
 
8183
8183
  // src/client/http.ts
8184
8184
  import { URL as URL2 } from "node:url";
8185
- function buildUrl(apiBase, path71) {
8186
- const normalizedPath = path71.startsWith("/") ? path71 : `/${path71}`;
8185
+ function buildUrl(apiBase, path75) {
8186
+ const normalizedPath = path75.startsWith("/") ? path75 : `/${path75}`;
8187
8187
  const [pathname, query] = normalizedPath.split("?");
8188
8188
  const url = new URL2(apiBase);
8189
8189
  url.pathname = `${url.pathname.replace(/\/+$/, "")}${pathname}`;
@@ -8245,26 +8245,26 @@ var init_http = __esm({
8245
8245
  this.runId = opts.runId?.trim() || void 0;
8246
8246
  this.userId = opts.userId?.trim() || void 0;
8247
8247
  }
8248
- get(path71, opts) {
8249
- return this.request(path71, { method: "GET" }, opts);
8248
+ get(path75, opts) {
8249
+ return this.request(path75, { method: "GET" }, opts);
8250
8250
  }
8251
- post(path71, body, opts) {
8252
- return this.request(path71, {
8251
+ post(path75, body, opts) {
8252
+ return this.request(path75, {
8253
8253
  method: "POST",
8254
8254
  body: body === void 0 ? void 0 : JSON.stringify(body)
8255
8255
  }, opts);
8256
8256
  }
8257
- patch(path71, body, opts) {
8258
- return this.request(path71, {
8257
+ patch(path75, body, opts) {
8258
+ return this.request(path75, {
8259
8259
  method: "PATCH",
8260
8260
  body: body === void 0 ? void 0 : JSON.stringify(body)
8261
8261
  }, opts);
8262
8262
  }
8263
- delete(path71, opts) {
8264
- return this.request(path71, { method: "DELETE" }, opts);
8263
+ delete(path75, opts) {
8264
+ return this.request(path75, { method: "DELETE" }, opts);
8265
8265
  }
8266
- async request(path71, init, opts) {
8267
- const url = buildUrl(this.apiBase, path71);
8266
+ async request(path75, init, opts) {
8267
+ const url = buildUrl(this.apiBase, path75);
8268
8268
  const headers = {
8269
8269
  accept: "application/json",
8270
8270
  ...toStringRecord(init.headers)
@@ -9729,9 +9729,9 @@ async function fetchHostedIntegrations(session) {
9729
9729
  }
9730
9730
  async function fetchHostedIntegrationCredential(session, providerId) {
9731
9731
  const client = toApiClient2(session);
9732
- const path71 = `${DEFAULT_INTEGRATION_CREDENTIAL_PATH}&provider=${encodeURIComponent(providerId)}`;
9732
+ const path75 = `${DEFAULT_INTEGRATION_CREDENTIAL_PATH}&provider=${encodeURIComponent(providerId)}`;
9733
9733
  try {
9734
- return await client.get(path71, { ignoreNotFound: true });
9734
+ return await client.get(path75, { ignoreNotFound: true });
9735
9735
  } catch (err) {
9736
9736
  if (err instanceof ApiRequestError && (err.status === 404 || err.status === 501)) {
9737
9737
  throw new HostedEndpointUnavailableError(err.status, err.message);
@@ -10134,7 +10134,7 @@ __export(github_exports, {
10134
10134
  registerGithubCommands: () => registerGithubCommands
10135
10135
  });
10136
10136
  import * as p29 from "@clack/prompts";
10137
- import pc43 from "picocolors";
10137
+ import pc44 from "picocolors";
10138
10138
  import open2 from "open";
10139
10139
  async function sleep2(ms) {
10140
10140
  await new Promise((r) => setTimeout(r, ms));
@@ -10157,14 +10157,14 @@ async function githubLogin(opts) {
10157
10157
  if (opts.json) {
10158
10158
  console.log(JSON.stringify({ status: "ok", mode: "pat", login: profile.login }, null, 2));
10159
10159
  } else {
10160
- p29.log.success(`Connected to GitHub as ${pc43.cyan(profile.login)} (PAT).`);
10160
+ p29.log.success(`Connected to GitHub as ${pc44.cyan(profile.login)} (PAT).`);
10161
10161
  }
10162
10162
  return;
10163
10163
  }
10164
- p29.intro(pc43.cyan("GitHub device flow login"));
10164
+ p29.intro(pc44.cyan("GitHub device flow login"));
10165
10165
  const start = await startDeviceFlow();
10166
10166
  p29.log.step(
10167
- `Open ${pc43.cyan(start.verificationUri)} and enter code ${pc43.yellow(start.userCode)}`
10167
+ `Open ${pc44.cyan(start.verificationUri)} and enter code ${pc44.yellow(start.userCode)}`
10168
10168
  );
10169
10169
  if (!opts.noBrowser) {
10170
10170
  try {
@@ -10193,7 +10193,7 @@ async function githubLogin(opts) {
10193
10193
  if (opts.json) {
10194
10194
  console.log(JSON.stringify({ status: "ok", mode: "device-flow", login: profile.login }));
10195
10195
  } else {
10196
- p29.outro(`Connected to GitHub as ${pc43.cyan(profile.login)}.`);
10196
+ p29.outro(`Connected to GitHub as ${pc44.cyan(profile.login)}.`);
10197
10197
  }
10198
10198
  return;
10199
10199
  }
@@ -10257,7 +10257,7 @@ async function githubWhoami(opts = {}) {
10257
10257
  return;
10258
10258
  }
10259
10259
  if (token) {
10260
- const status = directExpired ? pc43.red("expired") : pc43.green("active");
10260
+ const status = directExpired ? pc44.red("expired") : pc44.green("active");
10261
10261
  p29.log.message(
10262
10262
  `GitHub (direct): ${status} login=${profile?.login ?? token.login ?? "?"} mode=${token.authMode} scopes=[${token.scopes.join(", ")}]`
10263
10263
  );
@@ -10265,7 +10265,7 @@ async function githubWhoami(opts = {}) {
10265
10265
  if (bridge.growthubConnected) {
10266
10266
  if (bridgeGithub) {
10267
10267
  p29.log.message(
10268
- `GitHub (via Growthub bridge): ${pc43.green("connected")} handle=${bridgeGithub.handle ?? "?"} growthub=${bridge.growthubLogin ?? "?"} scopes=[${(bridgeGithub.scopes ?? []).join(", ")}]`
10268
+ `GitHub (via Growthub bridge): ${pc44.green("connected")} handle=${bridgeGithub.handle ?? "?"} growthub=${bridge.growthubLogin ?? "?"} scopes=[${(bridgeGithub.scopes ?? []).join(", ")}]`
10269
10269
  );
10270
10270
  } else if (bridge.bridgeAvailable) {
10271
10271
  p29.log.info(
@@ -10273,7 +10273,7 @@ async function githubWhoami(opts = {}) {
10273
10273
  );
10274
10274
  }
10275
10275
  }
10276
- p29.log.message(`Effective auth source: ${pc43.cyan(effectiveSource)}`);
10276
+ p29.log.message(`Effective auth source: ${pc44.cyan(effectiveSource)}`);
10277
10277
  }
10278
10278
  function githubLogout(opts = {}) {
10279
10279
  clearGithubToken();
@@ -10306,24 +10306,24 @@ var init_github = __esm({
10306
10306
  });
10307
10307
 
10308
10308
  // src/starter/scaffold-session-memory.ts
10309
- import fs47 from "node:fs";
10310
- import path55 from "node:path";
10309
+ import fs50 from "node:fs";
10310
+ import path59 from "node:path";
10311
10311
  function scaffoldSessionMemory(input) {
10312
- const forkPath = path55.resolve(input.forkPath);
10313
- const templatePath = path55.join(forkPath, TEMPLATE_RELATIVE);
10314
- const projectMdPath = path55.join(forkPath, PROJECT_MD_RELATIVE);
10315
- if (!fs47.existsSync(templatePath)) {
10312
+ const forkPath = path59.resolve(input.forkPath);
10313
+ const templatePath = path59.join(forkPath, TEMPLATE_RELATIVE);
10314
+ const projectMdPath = path59.join(forkPath, PROJECT_MD_RELATIVE);
10315
+ if (!fs50.existsSync(templatePath)) {
10316
10316
  return { written: false, projectMdPath, templatePath: null };
10317
10317
  }
10318
- if (fs47.existsSync(projectMdPath)) {
10318
+ if (fs50.existsSync(projectMdPath)) {
10319
10319
  return { written: false, projectMdPath, templatePath };
10320
10320
  }
10321
- const template = fs47.readFileSync(templatePath, "utf8");
10321
+ const template = fs50.readFileSync(templatePath, "utf8");
10322
10322
  const startedAt = input.startedAt ?? (/* @__PURE__ */ new Date()).toISOString();
10323
10323
  const sourceRef = input.sourceRef ?? "";
10324
10324
  const seeded = template.replaceAll("{{KIT_ID}}", input.kitId).replaceAll("{{FORK_ID}}", input.forkId).replaceAll("{{STARTED_AT}}", startedAt).replaceAll("{{SOURCE}}", input.source).replaceAll("{{SOURCE_REF}}", sourceRef);
10325
- fs47.mkdirSync(path55.dirname(projectMdPath), { recursive: true });
10326
- fs47.writeFileSync(projectMdPath, seeded, "utf8");
10325
+ fs50.mkdirSync(path59.dirname(projectMdPath), { recursive: true });
10326
+ fs50.writeFileSync(projectMdPath, seeded, "utf8");
10327
10327
  return { written: true, projectMdPath, templatePath };
10328
10328
  }
10329
10329
  var PROJECT_MD_RELATIVE, TEMPLATE_RELATIVE;
@@ -10336,12 +10336,12 @@ var init_scaffold_session_memory = __esm({
10336
10336
  });
10337
10337
 
10338
10338
  // src/starter/init.ts
10339
- import fs48 from "node:fs";
10340
- import path56 from "node:path";
10339
+ import fs51 from "node:fs";
10340
+ import path60 from "node:path";
10341
10341
  async function initStarterWorkspace(opts) {
10342
10342
  const kitId = opts.kitId ?? DEFAULT_STARTER_KIT_ID;
10343
- const absOut = path56.resolve(opts.out);
10344
- if (fs48.existsSync(absOut) && fs48.readdirSync(absOut).length > 0) {
10343
+ const absOut = path60.resolve(opts.out);
10344
+ if (fs51.existsSync(absOut) && fs51.readdirSync(absOut).length > 0) {
10345
10345
  throw new Error(`Destination ${absOut} already exists and is not empty.`);
10346
10346
  }
10347
10347
  const info = getBundledKitSourceInfo(kitId);
@@ -10350,7 +10350,7 @@ async function initStarterWorkspace(opts) {
10350
10350
  forkPath: absOut,
10351
10351
  kitId: info.id,
10352
10352
  baseVersion: info.version,
10353
- label: opts.name?.trim() || path56.basename(absOut)
10353
+ label: opts.name?.trim() || path60.basename(absOut)
10354
10354
  });
10355
10355
  const policy = {
10356
10356
  ...makeDefaultKitForkPolicy(),
@@ -10460,8 +10460,8 @@ var init_types2 = __esm({
10460
10460
  });
10461
10461
 
10462
10462
  // src/starter/source-import/github-source.ts
10463
- import fs49 from "node:fs";
10464
- import path57 from "node:path";
10463
+ import fs52 from "node:fs";
10464
+ import path61 from "node:path";
10465
10465
  import { spawnSync as spawnSync6 } from "node:child_process";
10466
10466
  function baseHeaders() {
10467
10467
  return {
@@ -10592,12 +10592,12 @@ function cloneGithubRepo(input) {
10592
10592
  if (!gitAvailable()) {
10593
10593
  throw new Error("`git` is not available on PATH \u2014 cannot clone.");
10594
10594
  }
10595
- if (fs49.existsSync(input.destination)) {
10595
+ if (fs52.existsSync(input.destination)) {
10596
10596
  throw new Error(`Clone destination already exists: ${input.destination}`);
10597
10597
  }
10598
10598
  const cloneUrl = input.token ? buildTokenCloneUrl(input.probe.repo, input.token) : input.probe.cloneUrl;
10599
- const parent = path57.dirname(input.destination);
10600
- fs49.mkdirSync(parent, { recursive: true });
10599
+ const parent = path61.dirname(input.destination);
10600
+ fs52.mkdirSync(parent, { recursive: true });
10601
10601
  const depth = input.depth ?? 1;
10602
10602
  const branch = input.branch ?? input.probe.defaultBranch;
10603
10603
  const args = ["clone"];
@@ -10624,17 +10624,17 @@ function cloneGithubRepo(input) {
10624
10624
  function narrowToSubdirectory(rootDir, subdirectory) {
10625
10625
  const normalizedSub = subdirectory.replace(/^\/+|\/+$/g, "");
10626
10626
  if (!normalizedSub) return;
10627
- const abs = path57.resolve(rootDir, normalizedSub);
10628
- if (!fs49.existsSync(abs) || !fs49.statSync(abs).isDirectory()) {
10627
+ const abs = path61.resolve(rootDir, normalizedSub);
10628
+ if (!fs52.existsSync(abs) || !fs52.statSync(abs).isDirectory()) {
10629
10629
  throw new Error(`Subdirectory not found in cloned repo: ${subdirectory}`);
10630
10630
  }
10631
- const tmp = path57.resolve(
10632
- path57.dirname(rootDir),
10633
- `.${path57.basename(rootDir)}-narrow-${Date.now().toString(36)}`
10631
+ const tmp = path61.resolve(
10632
+ path61.dirname(rootDir),
10633
+ `.${path61.basename(rootDir)}-narrow-${Date.now().toString(36)}`
10634
10634
  );
10635
- fs49.renameSync(abs, tmp);
10636
- fs49.rmSync(rootDir, { recursive: true, force: true });
10637
- fs49.renameSync(tmp, rootDir);
10635
+ fs52.renameSync(abs, tmp);
10636
+ fs52.rmSync(rootDir, { recursive: true, force: true });
10637
+ fs52.renameSync(tmp, rootDir);
10638
10638
  }
10639
10639
  var GITHUB_API_BASE2;
10640
10640
  var init_github_source = __esm({
@@ -10648,9 +10648,9 @@ var init_github_source = __esm({
10648
10648
  });
10649
10649
 
10650
10650
  // src/starter/source-import/skills-source.ts
10651
- import fs50 from "node:fs";
10651
+ import fs53 from "node:fs";
10652
10652
  import os11 from "node:os";
10653
- import path58 from "node:path";
10653
+ import path62 from "node:path";
10654
10654
  import { spawnSync as spawnSync7 } from "node:child_process";
10655
10655
  function resolveBase() {
10656
10656
  const raw = process.env.SKILLS_SH_BASE?.trim();
@@ -10916,9 +10916,9 @@ async function probeSkillsSource(input) {
10916
10916
  };
10917
10917
  }
10918
10918
  function assertInsidePayloadRoot(root, candidate) {
10919
- const abs = path58.resolve(candidate);
10920
- const rootAbs = path58.resolve(root);
10921
- if (!abs.startsWith(rootAbs + path58.sep) && abs !== rootAbs) {
10919
+ const abs = path62.resolve(candidate);
10920
+ const rootAbs = path62.resolve(root);
10921
+ if (!abs.startsWith(rootAbs + path62.sep) && abs !== rootAbs) {
10922
10922
  throw new Error(`Refusing to write outside payload root: ${candidate}`);
10923
10923
  }
10924
10924
  }
@@ -10934,24 +10934,24 @@ function runGit3(args, cwd) {
10934
10934
  };
10935
10935
  }
10936
10936
  function skillDirectoryMatches(dir, skillSlug) {
10937
- const skillFile = path58.resolve(dir, "SKILL.md");
10938
- if (!fs50.existsSync(skillFile) || !fs50.statSync(skillFile).isFile()) {
10937
+ const skillFile = path62.resolve(dir, "SKILL.md");
10938
+ if (!fs53.existsSync(skillFile) || !fs53.statSync(skillFile).isFile()) {
10939
10939
  return false;
10940
10940
  }
10941
- if (path58.basename(dir) === skillSlug) {
10941
+ if (path62.basename(dir) === skillSlug) {
10942
10942
  return true;
10943
10943
  }
10944
- const content = fs50.readFileSync(skillFile, "utf8");
10944
+ const content = fs53.readFileSync(skillFile, "utf8");
10945
10945
  const nameMatch = content.match(/(?:^|\n)name:\s*["']?([A-Za-z0-9._:-]+)["']?\s*(?:\n|$)/i);
10946
10946
  return nameMatch?.[1] === skillSlug;
10947
10947
  }
10948
10948
  function locateSkillDirectory(root, skillSlug) {
10949
10949
  const preferred = [
10950
- path58.resolve(root, "skills", skillSlug),
10951
- path58.resolve(root, skillSlug)
10950
+ path62.resolve(root, "skills", skillSlug),
10951
+ path62.resolve(root, skillSlug)
10952
10952
  ];
10953
10953
  for (const candidate of preferred) {
10954
- if (fs50.existsSync(candidate) && fs50.statSync(candidate).isDirectory() && skillDirectoryMatches(candidate, skillSlug)) {
10954
+ if (fs53.existsSync(candidate) && fs53.statSync(candidate).isDirectory() && skillDirectoryMatches(candidate, skillSlug)) {
10955
10955
  return candidate;
10956
10956
  }
10957
10957
  }
@@ -10961,12 +10961,12 @@ function locateSkillDirectory(root, skillSlug) {
10961
10961
  if (skillDirectoryMatches(current, skillSlug)) {
10962
10962
  return current;
10963
10963
  }
10964
- for (const entry of fs50.readdirSync(current, { withFileTypes: true })) {
10964
+ for (const entry of fs53.readdirSync(current, { withFileTypes: true })) {
10965
10965
  if (!entry.isDirectory()) continue;
10966
10966
  if ([".git", "node_modules", ".next", "dist", "build", "coverage"].includes(entry.name)) {
10967
10967
  continue;
10968
10968
  }
10969
- queue.push(path58.resolve(current, entry.name));
10969
+ queue.push(path62.resolve(current, entry.name));
10970
10970
  }
10971
10971
  }
10972
10972
  return null;
@@ -10976,18 +10976,18 @@ function copySkillTree(sourceDir, destination) {
10976
10976
  const stack = [{ from: sourceDir, to: destination }];
10977
10977
  while (stack.length > 0) {
10978
10978
  const current = stack.pop();
10979
- fs50.mkdirSync(current.to, { recursive: true });
10980
- for (const entry of fs50.readdirSync(current.from, { withFileTypes: true })) {
10981
- const fromPath = path58.resolve(current.from, entry.name);
10982
- const toPath = path58.resolve(current.to, entry.name);
10979
+ fs53.mkdirSync(current.to, { recursive: true });
10980
+ for (const entry of fs53.readdirSync(current.from, { withFileTypes: true })) {
10981
+ const fromPath = path62.resolve(current.from, entry.name);
10982
+ const toPath = path62.resolve(current.to, entry.name);
10983
10983
  assertInsidePayloadRoot(destination, toPath);
10984
10984
  if (entry.isDirectory()) {
10985
10985
  stack.push({ from: fromPath, to: toPath });
10986
10986
  continue;
10987
10987
  }
10988
- const data = fs50.readFileSync(fromPath);
10989
- fs50.mkdirSync(path58.dirname(toPath), { recursive: true });
10990
- fs50.writeFileSync(toPath, data, { mode: 420 });
10988
+ const data = fs53.readFileSync(fromPath);
10989
+ fs53.mkdirSync(path62.dirname(toPath), { recursive: true });
10990
+ fs53.writeFileSync(toPath, data, { mode: 420 });
10991
10991
  written += 1;
10992
10992
  }
10993
10993
  }
@@ -10998,7 +10998,7 @@ async function fetchSkillPayload(input) {
10998
10998
  if (!gitAvailable()) {
10999
10999
  throw new Error("`git` is not available on PATH \u2014 cannot materialize a skills.sh payload.");
11000
11000
  }
11001
- if (fs50.existsSync(destination)) {
11001
+ if (fs53.existsSync(destination)) {
11002
11002
  throw new Error(`Skill payload destination already exists: ${destination}`);
11003
11003
  }
11004
11004
  const repoSource = probe.repoUrl ?? (probe.repository ? `https://github.com/${probe.repository}` : void 0);
@@ -11006,11 +11006,11 @@ async function fetchSkillPayload(input) {
11006
11006
  if (!repoSource || !skillSlug) {
11007
11007
  throw new Error(`Skill '${probe.skillId}' is missing repository metadata \u2014 cannot materialize payload.`);
11008
11008
  }
11009
- const cloneRoot = fs50.mkdtempSync(
11010
- path58.join(os11.tmpdir(), "growthub-skills-source-")
11009
+ const cloneRoot = fs53.mkdtempSync(
11010
+ path62.join(os11.tmpdir(), "growthub-skills-source-")
11011
11011
  );
11012
11012
  try {
11013
- const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot], path58.dirname(cloneRoot));
11013
+ const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot], path62.dirname(cloneRoot));
11014
11014
  if (!cloneRes.ok) {
11015
11015
  throw new Error(`git clone failed: ${cloneRes.stderr || "unable to clone skill repository"}`);
11016
11016
  }
@@ -11023,7 +11023,7 @@ async function fetchSkillPayload(input) {
11023
11023
  const fileCount = copySkillTree(skillDir, destination);
11024
11024
  return { destination, fileCount };
11025
11025
  } finally {
11026
- fs50.rmSync(cloneRoot, { recursive: true, force: true });
11026
+ fs53.rmSync(cloneRoot, { recursive: true, force: true });
11027
11027
  }
11028
11028
  }
11029
11029
  var DEFAULT_BASE, COMMENT_PATTERN;
@@ -11037,13 +11037,13 @@ var init_skills_source = __esm({
11037
11037
  });
11038
11038
 
11039
11039
  // src/starter/source-import/detect.ts
11040
- import fs51 from "node:fs";
11041
- import path59 from "node:path";
11040
+ import fs54 from "node:fs";
11041
+ import path63 from "node:path";
11042
11042
  function safeReadPackageJson(dir) {
11043
- const p36 = path59.resolve(dir, "package.json");
11044
- if (!fs51.existsSync(p36)) return null;
11043
+ const p36 = path63.resolve(dir, "package.json");
11044
+ if (!fs54.existsSync(p36)) return null;
11045
11045
  try {
11046
- return JSON.parse(fs51.readFileSync(p36, "utf8"));
11046
+ return JSON.parse(fs54.readFileSync(p36, "utf8"));
11047
11047
  } catch {
11048
11048
  return null;
11049
11049
  }
@@ -11053,10 +11053,10 @@ function detectPackageManager(dir, pkg) {
11053
11053
  if (pkg?.packageManager?.startsWith("yarn")) return "yarn";
11054
11054
  if (pkg?.packageManager?.startsWith("npm")) return "npm";
11055
11055
  if (pkg?.packageManager?.startsWith("bun")) return "bun";
11056
- if (fs51.existsSync(path59.resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
11057
- if (fs51.existsSync(path59.resolve(dir, "yarn.lock"))) return "yarn";
11058
- if (fs51.existsSync(path59.resolve(dir, "bun.lockb"))) return "bun";
11059
- if (fs51.existsSync(path59.resolve(dir, "package-lock.json"))) return "npm";
11056
+ if (fs54.existsSync(path63.resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
11057
+ if (fs54.existsSync(path63.resolve(dir, "yarn.lock"))) return "yarn";
11058
+ if (fs54.existsSync(path63.resolve(dir, "bun.lockb"))) return "bun";
11059
+ if (fs54.existsSync(path63.resolve(dir, "package-lock.json"))) return "npm";
11060
11060
  return "unknown";
11061
11061
  }
11062
11062
  function collectDeps(pkg) {
@@ -11070,12 +11070,12 @@ function collectDeps(pkg) {
11070
11070
  }
11071
11071
  function looksLikeSkillPayload(rootDir) {
11072
11072
  const markers = ["SKILL.md", "skill.md", "skill.json", "skill.yml", "skill.yaml", "prompt.md"];
11073
- return markers.some((name) => fs51.existsSync(path59.resolve(rootDir, name)));
11073
+ return markers.some((name) => fs54.existsSync(path63.resolve(rootDir, name)));
11074
11074
  }
11075
11075
  function detectFramework(rootDir, pkg) {
11076
11076
  if (!pkg) {
11077
11077
  if (looksLikeSkillPayload(rootDir)) return "skill";
11078
- if (fs51.existsSync(path59.resolve(rootDir, "docs"))) return "docs";
11078
+ if (fs54.existsSync(path63.resolve(rootDir, "docs"))) return "docs";
11079
11079
  return "unknown";
11080
11080
  }
11081
11081
  const deps = collectDeps(pkg);
@@ -11084,8 +11084,8 @@ function detectFramework(rootDir, pkg) {
11084
11084
  "vite.config.ts",
11085
11085
  "vite.config.mjs",
11086
11086
  "vite.config.cjs"
11087
- ].some((name) => fs51.existsSync(path59.resolve(rootDir, name)));
11088
- if (deps.has("next") || fs51.existsSync(path59.resolve(rootDir, "next.config.js")) || fs51.existsSync(path59.resolve(rootDir, "next.config.mjs"))) {
11087
+ ].some((name) => fs54.existsSync(path63.resolve(rootDir, name)));
11088
+ if (deps.has("next") || fs54.existsSync(path63.resolve(rootDir, "next.config.js")) || fs54.existsSync(path63.resolve(rootDir, "next.config.mjs"))) {
11089
11089
  return "next";
11090
11090
  }
11091
11091
  if (deps.has("vite") || hasViteConfig) return "vite";
@@ -11111,15 +11111,15 @@ function pickScripts(pkg) {
11111
11111
  return out;
11112
11112
  }
11113
11113
  function listEnvFiles(dir) {
11114
- if (!fs51.existsSync(dir)) return [];
11115
- return fs51.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).filter((name) => name === ".env" || name.startsWith(".env.") || name === ".env.example");
11114
+ if (!fs54.existsSync(dir)) return [];
11115
+ return fs54.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).filter((name) => name === ".env" || name.startsWith(".env.") || name === ".env.example");
11116
11116
  }
11117
11117
  function findAppRoot(rootDir, pkg) {
11118
11118
  if (pkg) return ".";
11119
11119
  const candidates = ["app", "src", "apps", "packages"];
11120
11120
  for (const candidate of candidates) {
11121
- const abs = path59.resolve(rootDir, candidate);
11122
- if (fs51.existsSync(abs) && fs51.statSync(abs).isDirectory()) {
11121
+ const abs = path63.resolve(rootDir, candidate);
11122
+ if (fs54.existsSync(abs) && fs54.statSync(abs).isDirectory()) {
11123
11123
  const child = safeReadPackageJson(abs);
11124
11124
  if (child) return candidate;
11125
11125
  }
@@ -11135,12 +11135,12 @@ function computeConfidence(framework, manager, pkg) {
11135
11135
  return Math.min(1, Number(score.toFixed(2)));
11136
11136
  }
11137
11137
  function detectSourceShape(rootDir) {
11138
- if (!fs51.existsSync(rootDir) || !fs51.statSync(rootDir).isDirectory()) {
11138
+ if (!fs54.existsSync(rootDir) || !fs54.statSync(rootDir).isDirectory()) {
11139
11139
  throw new Error(`Detection target is not a directory: ${rootDir}`);
11140
11140
  }
11141
11141
  const rootPkg = safeReadPackageJson(rootDir);
11142
11142
  const appRootRel = findAppRoot(rootDir, rootPkg);
11143
- const appRootAbs = path59.resolve(rootDir, appRootRel);
11143
+ const appRootAbs = path63.resolve(rootDir, appRootRel);
11144
11144
  const appPkg = appRootRel === "." ? rootPkg : safeReadPackageJson(appRootAbs);
11145
11145
  const framework = detectFramework(appRootAbs, appPkg ?? rootPkg);
11146
11146
  const packageManager = detectPackageManager(rootDir, rootPkg ?? appPkg);
@@ -11180,18 +11180,18 @@ var init_detect = __esm({
11180
11180
  });
11181
11181
 
11182
11182
  // src/starter/source-import/security.ts
11183
- import fs52 from "node:fs";
11184
- import path60 from "node:path";
11183
+ import fs55 from "node:fs";
11184
+ import path64 from "node:path";
11185
11185
  function isLikelyTextFile(filename) {
11186
- const ext = path60.extname(filename).toLowerCase();
11186
+ const ext = path64.extname(filename).toLowerCase();
11187
11187
  if (!ext) return true;
11188
11188
  return TEXT_EXTENSIONS.has(ext);
11189
11189
  }
11190
11190
  function isSuspiciousBinary(filename) {
11191
- return SUSPICIOUS_BINARY_EXTENSIONS.has(path60.extname(filename).toLowerCase());
11191
+ return SUSPICIOUS_BINARY_EXTENSIONS.has(path64.extname(filename).toLowerCase());
11192
11192
  }
11193
11193
  function isUnexpectedArchive(filename) {
11194
- const ext = path60.extname(filename).toLowerCase();
11194
+ const ext = path64.extname(filename).toLowerCase();
11195
11195
  return ARCHIVE_EXTENSIONS.has(ext) || filename.toLowerCase().endsWith(".tar.gz");
11196
11196
  }
11197
11197
  function shortExcerpt(line) {
@@ -11246,19 +11246,19 @@ function walkPayload(root, onFile, limits) {
11246
11246
  if (!current) break;
11247
11247
  let entries;
11248
11248
  try {
11249
- entries = fs52.readdirSync(current, { withFileTypes: true });
11249
+ entries = fs55.readdirSync(current, { withFileTypes: true });
11250
11250
  } catch {
11251
11251
  continue;
11252
11252
  }
11253
11253
  for (const entry of entries) {
11254
- const abs = path60.resolve(current, entry.name);
11254
+ const abs = path64.resolve(current, entry.name);
11255
11255
  if (entry.isDirectory()) {
11256
11256
  if (entry.name === ".git" || entry.name === "node_modules") continue;
11257
11257
  stack.push(abs);
11258
11258
  continue;
11259
11259
  }
11260
11260
  if (!entry.isFile()) continue;
11261
- const rel = path60.relative(root, abs);
11261
+ const rel = path64.relative(root, abs);
11262
11262
  onFile(abs, rel);
11263
11263
  visited += 1;
11264
11264
  if (visited >= limits.maxFiles) break;
@@ -11268,7 +11268,7 @@ function walkPayload(root, onFile, limits) {
11268
11268
  }
11269
11269
  function inspectSourcePayload(input) {
11270
11270
  const { payloadRoot } = input;
11271
- if (!fs52.existsSync(payloadRoot) || !fs52.statSync(payloadRoot).isDirectory()) {
11271
+ if (!fs55.existsSync(payloadRoot) || !fs55.statSync(payloadRoot).isDirectory()) {
11272
11272
  throw new Error(`Inspection target is not a directory: ${payloadRoot}`);
11273
11273
  }
11274
11274
  const findings = [];
@@ -11278,7 +11278,7 @@ function inspectSourcePayload(input) {
11278
11278
  (abs, rel) => {
11279
11279
  let size = 0;
11280
11280
  try {
11281
- size = fs52.statSync(abs).size;
11281
+ size = fs55.statSync(abs).size;
11282
11282
  } catch {
11283
11283
  return;
11284
11284
  }
@@ -11287,7 +11287,7 @@ function inspectSourcePayload(input) {
11287
11287
  category: "suspicious-binary",
11288
11288
  severity: "high-risk",
11289
11289
  path: rel,
11290
- message: `Payload ships a precompiled binary (${path60.extname(rel)}). Review provenance before use.`
11290
+ message: `Payload ships a precompiled binary (${path64.extname(rel)}). Review provenance before use.`
11291
11291
  });
11292
11292
  return;
11293
11293
  }
@@ -11296,7 +11296,7 @@ function inspectSourcePayload(input) {
11296
11296
  category: "unexpected-archive",
11297
11297
  severity: "caution",
11298
11298
  path: rel,
11299
- message: `Payload ships an archive (${path60.extname(rel)}) \u2014 expand and review contents before use.`
11299
+ message: `Payload ships an archive (${path64.extname(rel)}) \u2014 expand and review contents before use.`
11300
11300
  });
11301
11301
  return;
11302
11302
  }
@@ -11304,12 +11304,12 @@ function inspectSourcePayload(input) {
11304
11304
  if (bytesInspected + Math.min(size, MAX_BYTES_PER_FILE) > MAX_TOTAL_BYTES) return;
11305
11305
  let buf;
11306
11306
  try {
11307
- const handle = fs52.openSync(abs, "r");
11307
+ const handle = fs55.openSync(abs, "r");
11308
11308
  try {
11309
11309
  buf = Buffer.alloc(Math.min(size, MAX_BYTES_PER_FILE));
11310
- fs52.readSync(handle, buf, 0, buf.length, 0);
11310
+ fs55.readSync(handle, buf, 0, buf.length, 0);
11311
11311
  } finally {
11312
- fs52.closeSync(handle);
11312
+ fs55.closeSync(handle);
11313
11313
  }
11314
11314
  } catch {
11315
11315
  return;
@@ -11518,18 +11518,18 @@ var init_security = __esm({
11518
11518
  });
11519
11519
 
11520
11520
  // src/starter/source-import/plan.ts
11521
- import fs53 from "node:fs";
11522
- import path61 from "node:path";
11521
+ import fs56 from "node:fs";
11522
+ import path65 from "node:path";
11523
11523
  function generateImportId() {
11524
11524
  return `si-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
11525
11525
  }
11526
11526
  function destinationState(absDest) {
11527
- if (!fs53.existsSync(absDest)) return { exists: false, nonEmpty: false };
11528
- const stats = fs53.statSync(absDest);
11527
+ if (!fs56.existsSync(absDest)) return { exists: false, nonEmpty: false };
11528
+ const stats = fs56.statSync(absDest);
11529
11529
  if (!stats.isDirectory()) {
11530
11530
  throw new Error(`Destination is not a directory: ${absDest}`);
11531
11531
  }
11532
- const entries = fs53.readdirSync(absDest);
11532
+ const entries = fs56.readdirSync(absDest);
11533
11533
  return { exists: true, nonEmpty: entries.length > 0 };
11534
11534
  }
11535
11535
  function describeSource2(probe) {
@@ -11539,7 +11539,7 @@ function describeSource2(probe) {
11539
11539
  return `skill ${probe.skillId}@${probe.version} (skills.sh)`;
11540
11540
  }
11541
11541
  function buildSourceImportPlan(input) {
11542
- const absDest = path61.resolve(input.destination);
11542
+ const absDest = path65.resolve(input.destination);
11543
11543
  const state = destinationState(absDest);
11544
11544
  const payloadPath = "imported";
11545
11545
  const warnings = [...input.probe.warnings];
@@ -11652,8 +11652,8 @@ var init_plan = __esm({
11652
11652
  });
11653
11653
 
11654
11654
  // src/starter/source-import/summarize.ts
11655
- import fs54 from "node:fs";
11656
- import path62 from "node:path";
11655
+ import fs57 from "node:fs";
11656
+ import path66 from "node:path";
11657
11657
  function sourceHeading(manifest) {
11658
11658
  const src = manifest.source;
11659
11659
  if (src.kind === "github-repo") {
@@ -11708,7 +11708,7 @@ function nextStepsSection(manifest) {
11708
11708
  }
11709
11709
  function writeImportSummary(input) {
11710
11710
  const { forkPath, summaryRelativePath, manifest } = input;
11711
- const summaryPath = path62.resolve(forkPath, summaryRelativePath);
11711
+ const summaryPath = path66.resolve(forkPath, summaryRelativePath);
11712
11712
  const body = [
11713
11713
  `# Source Import Summary`,
11714
11714
  ``,
@@ -11738,8 +11738,8 @@ function writeImportSummary(input) {
11738
11738
  `Generated by the Growthub Source Import Agent. Canonical manifest lives at \`.growthub-fork/source-import.json\`.`,
11739
11739
  ``
11740
11740
  ].join("\n");
11741
- fs54.mkdirSync(path62.dirname(summaryPath), { recursive: true });
11742
- fs54.writeFileSync(summaryPath, body, "utf8");
11741
+ fs57.mkdirSync(path66.dirname(summaryPath), { recursive: true });
11742
+ fs57.writeFileSync(summaryPath, body, "utf8");
11743
11743
  return summaryPath;
11744
11744
  }
11745
11745
  var init_summarize = __esm({
@@ -11749,16 +11749,16 @@ var init_summarize = __esm({
11749
11749
  });
11750
11750
 
11751
11751
  // src/starter/source-import/materialize.ts
11752
- import fs55 from "node:fs";
11752
+ import fs58 from "node:fs";
11753
11753
  import os12 from "node:os";
11754
- import path63 from "node:path";
11754
+ import path67 from "node:path";
11755
11755
  function resolveSourceKind(probe) {
11756
11756
  return probe.kind === "github-repo" ? "github-repo" : "skills-skill";
11757
11757
  }
11758
11758
  function stagingDirFor(forkPath) {
11759
- return path63.join(
11759
+ return path67.join(
11760
11760
  os12.tmpdir(),
11761
- `growthub-source-import-${path63.basename(forkPath)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
11761
+ `growthub-source-import-${path67.basename(forkPath)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
11762
11762
  );
11763
11763
  }
11764
11764
  async function fetchPayload(probe, stagingDir, opts) {
@@ -11790,18 +11790,18 @@ async function fetchPayload(probe, stagingDir, opts) {
11790
11790
  return { payloadRoot: stagingDir };
11791
11791
  }
11792
11792
  function movePayloadIntoFork(payloadRoot, forkPath, payloadRelativePath) {
11793
- const target = path63.resolve(forkPath, payloadRelativePath);
11794
- if (fs55.existsSync(target)) {
11795
- fs55.rmSync(target, { recursive: true, force: true });
11793
+ const target = path67.resolve(forkPath, payloadRelativePath);
11794
+ if (fs58.existsSync(target)) {
11795
+ fs58.rmSync(target, { recursive: true, force: true });
11796
11796
  }
11797
- fs55.mkdirSync(path63.dirname(target), { recursive: true });
11798
- fs55.renameSync(payloadRoot, target);
11797
+ fs58.mkdirSync(path67.dirname(target), { recursive: true });
11798
+ fs58.renameSync(payloadRoot, target);
11799
11799
  return target;
11800
11800
  }
11801
11801
  function writeManifest(forkPath, manifest) {
11802
- const p36 = path63.resolve(forkPath, MANIFEST_RELATIVE_PATH);
11803
- fs55.mkdirSync(path63.dirname(p36), { recursive: true });
11804
- fs55.writeFileSync(p36, JSON.stringify(manifest, null, 2) + "\n", "utf8");
11802
+ const p36 = path67.resolve(forkPath, MANIFEST_RELATIVE_PATH);
11803
+ fs58.mkdirSync(path67.dirname(p36), { recursive: true });
11804
+ fs58.writeFileSync(p36, JSON.stringify(manifest, null, 2) + "\n", "utf8");
11805
11805
  return p36;
11806
11806
  }
11807
11807
  function assertConfirmationsSatisfied(plan, confirmations) {
@@ -11841,7 +11841,7 @@ async function materializeImportPlan(input) {
11841
11841
  requireSkillAcknowledgement: sourceKind === "skills-skill"
11842
11842
  });
11843
11843
  if (security.blocked) {
11844
- fs55.rmSync(fetchResult.payloadRoot, { recursive: true, force: true });
11844
+ fs58.rmSync(fetchResult.payloadRoot, { recursive: true, force: true });
11845
11845
  throw new Error(
11846
11846
  `Security inspection blocked the fetched payload: ${security.summaryLines[0] ?? "blocking finding"}`
11847
11847
  );
@@ -11989,26 +11989,26 @@ var init_materialize = __esm({
11989
11989
  });
11990
11990
 
11991
11991
  // src/starter/source-import/agent.ts
11992
- import fs56 from "node:fs";
11993
- import path64 from "node:path";
11992
+ import fs59 from "node:fs";
11993
+ import path68 from "node:path";
11994
11994
  function resolveJobsDir() {
11995
- return path64.resolve(resolveKitForksHomeDir(), "source-import-jobs");
11995
+ return path68.resolve(resolveKitForksHomeDir(), "source-import-jobs");
11996
11996
  }
11997
11997
  function resolveJobPath2(jobId) {
11998
- return path64.resolve(resolveJobsDir(), `${jobId}.json`);
11998
+ return path68.resolve(resolveJobsDir(), `${jobId}.json`);
11999
11999
  }
12000
12000
  function generateJobId2() {
12001
12001
  return `sij-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
12002
12002
  }
12003
12003
  function writeJob2(job) {
12004
12004
  const p36 = resolveJobPath2(job.jobId);
12005
- fs56.mkdirSync(path64.dirname(p36), { recursive: true });
12006
- fs56.writeFileSync(p36, JSON.stringify(job, null, 2) + "\n", "utf8");
12005
+ fs59.mkdirSync(path68.dirname(p36), { recursive: true });
12006
+ fs59.writeFileSync(p36, JSON.stringify(job, null, 2) + "\n", "utf8");
12007
12007
  }
12008
12008
  function readJobFile(p36) {
12009
- if (!fs56.existsSync(p36)) return null;
12009
+ if (!fs59.existsSync(p36)) return null;
12010
12010
  try {
12011
- return JSON.parse(fs56.readFileSync(p36, "utf8"));
12011
+ return JSON.parse(fs59.readFileSync(p36, "utf8"));
12012
12012
  } catch {
12013
12013
  return null;
12014
12014
  }
@@ -12018,7 +12018,7 @@ function patchJob2(jobId, status, patch = {}) {
12018
12018
  const job = readJobFile(p36);
12019
12019
  if (!job) return null;
12020
12020
  const updated = { ...job, ...patch, status };
12021
- fs56.writeFileSync(p36, JSON.stringify(updated, null, 2) + "\n", "utf8");
12021
+ fs59.writeFileSync(p36, JSON.stringify(updated, null, 2) + "\n", "utf8");
12022
12022
  return updated;
12023
12023
  }
12024
12024
  function getSourceImportJob(jobId) {
@@ -12037,7 +12037,7 @@ async function probeAndPlan(input, destination) {
12037
12037
  }
12038
12038
  async function runSourceImportJob(input) {
12039
12039
  const jobId = generateJobId2();
12040
- const destination = path64.resolve(input.out);
12040
+ const destination = path68.resolve(input.out);
12041
12041
  const sourceKind = input.source.kind;
12042
12042
  const initial = {
12043
12043
  jobId,
@@ -12347,11 +12347,11 @@ var catalog_exports = {};
12347
12347
  __export(catalog_exports, {
12348
12348
  readSkillCatalog: () => readSkillCatalog
12349
12349
  });
12350
- import fs57 from "node:fs";
12351
- import path65 from "node:path";
12350
+ import fs60 from "node:fs";
12351
+ import path69 from "node:path";
12352
12352
  function exists(p36) {
12353
12353
  try {
12354
- fs57.accessSync(p36);
12354
+ fs60.accessSync(p36);
12355
12355
  return true;
12356
12356
  } catch {
12357
12357
  return false;
@@ -12359,14 +12359,14 @@ function exists(p36) {
12359
12359
  }
12360
12360
  function isDir2(p36) {
12361
12361
  try {
12362
- return fs57.statSync(p36).isDirectory();
12362
+ return fs60.statSync(p36).isDirectory();
12363
12363
  } catch {
12364
12364
  return false;
12365
12365
  }
12366
12366
  }
12367
12367
  function safeRead(p36) {
12368
12368
  try {
12369
- return fs57.readFileSync(p36, "utf8");
12369
+ return fs60.readFileSync(p36, "utf8");
12370
12370
  } catch {
12371
12371
  return null;
12372
12372
  }
@@ -12451,10 +12451,10 @@ function readOne(skillPath, source) {
12451
12451
  }
12452
12452
  function readSkillDirs(baseDir, source, out, warnings) {
12453
12453
  if (!isDir2(baseDir)) return;
12454
- for (const child of fs57.readdirSync(baseDir).sort()) {
12455
- const dir = path65.join(baseDir, child);
12454
+ for (const child of fs60.readdirSync(baseDir).sort()) {
12455
+ const dir = path69.join(baseDir, child);
12456
12456
  if (!isDir2(dir)) continue;
12457
- const skill = path65.join(dir, "SKILL.md");
12457
+ const skill = path69.join(dir, "SKILL.md");
12458
12458
  if (!exists(skill)) continue;
12459
12459
  const res = readOne(skill, source);
12460
12460
  if ("entry" in res) out.push(res.entry);
@@ -12462,16 +12462,16 @@ function readSkillDirs(baseDir, source, out, warnings) {
12462
12462
  }
12463
12463
  }
12464
12464
  function readKitSubSkills(kitDir, out, warnings, depth = 0) {
12465
- const base = path65.join(kitDir, "skills");
12465
+ const base = path69.join(kitDir, "skills");
12466
12466
  if (!isDir2(base)) return;
12467
12467
  const walk = (dir, d) => {
12468
12468
  if (d > MAX_DEPTH) return;
12469
- for (const entry of fs57.readdirSync(dir, { withFileTypes: true })) {
12469
+ for (const entry of fs60.readdirSync(dir, { withFileTypes: true })) {
12470
12470
  if (entry.isDirectory()) {
12471
12471
  if (SKIP_DIRS.has(entry.name)) continue;
12472
- walk(path65.join(dir, entry.name), d + 1);
12472
+ walk(path69.join(dir, entry.name), d + 1);
12473
12473
  } else if (entry.isFile() && entry.name === "SKILL.md") {
12474
- const res = readOne(path65.join(dir, entry.name), "worker-kit-sub");
12474
+ const res = readOne(path69.join(dir, entry.name), "worker-kit-sub");
12475
12475
  if ("entry" in res) out.push(res.entry);
12476
12476
  else warnings.push(res.warning);
12477
12477
  }
@@ -12480,11 +12480,11 @@ function readKitSubSkills(kitDir, out, warnings, depth = 0) {
12480
12480
  walk(base, depth);
12481
12481
  }
12482
12482
  function readSkillCatalog(opts) {
12483
- const root = path65.resolve(opts.root);
12483
+ const root = path69.resolve(opts.root);
12484
12484
  const entries = [];
12485
12485
  const warnings = [];
12486
12486
  if (opts.includeProjectRoot !== false) {
12487
- const rootSkill = path65.join(root, "SKILL.md");
12487
+ const rootSkill = path69.join(root, "SKILL.md");
12488
12488
  if (exists(rootSkill)) {
12489
12489
  const res = readOne(rootSkill, "project-root");
12490
12490
  if ("entry" in res) entries.push(res.entry);
@@ -12492,14 +12492,14 @@ function readSkillCatalog(opts) {
12492
12492
  }
12493
12493
  }
12494
12494
  if (opts.includeClaudeSkills !== false) {
12495
- readSkillDirs(path65.join(root, ".claude/skills"), "claude-skills", entries, warnings);
12495
+ readSkillDirs(path69.join(root, ".claude/skills"), "claude-skills", entries, warnings);
12496
12496
  }
12497
12497
  if (opts.includeWorkerKits !== false) {
12498
- const kitsDir = path65.join(root, "cli/assets/worker-kits");
12498
+ const kitsDir = path69.join(root, "cli/assets/worker-kits");
12499
12499
  readSkillDirs(kitsDir, "worker-kit", entries, warnings);
12500
12500
  if (isDir2(kitsDir)) {
12501
- for (const kit of fs57.readdirSync(kitsDir).sort()) {
12502
- const kitPath = path65.join(kitsDir, kit);
12501
+ for (const kit of fs60.readdirSync(kitsDir).sort()) {
12502
+ const kitPath = path69.join(kitsDir, kit);
12503
12503
  if (!isDir2(kitPath)) continue;
12504
12504
  readKitSubSkills(kitPath, entries, warnings);
12505
12505
  }
@@ -12544,9 +12544,9 @@ __export(source_import_discovery_exports, {
12544
12544
  startSourceImportFlow: () => startSourceImportFlow
12545
12545
  });
12546
12546
  import * as p34 from "@clack/prompts";
12547
- import pc49 from "picocolors";
12548
- import fs62 from "node:fs";
12549
- import path69 from "node:path";
12547
+ import pc50 from "picocolors";
12548
+ import fs65 from "node:fs";
12549
+ import path73 from "node:path";
12550
12550
  import { pathToFileURL as pathToFileURL4 } from "node:url";
12551
12551
  function slugifyWorkspaceName(input) {
12552
12552
  const slug = input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -12574,10 +12574,10 @@ async function promptForInteractiveWorkspacePath(input) {
12574
12574
  });
12575
12575
  if (p34.isCancel(raw) || !raw) return null;
12576
12576
  const trimmed = String(raw).trim();
12577
- const expanded = trimmed.startsWith("~/") ? path69.join(process.env.HOME ?? "~", trimmed.slice(2)) : trimmed;
12578
- const resolved = path69.resolve(expanded);
12579
- if (fs62.existsSync(resolved) && fs62.statSync(resolved).isDirectory()) {
12580
- const finalPath = path69.join(resolved, suggestedName);
12577
+ const expanded = trimmed.startsWith("~/") ? path73.join(process.env.HOME ?? "~", trimmed.slice(2)) : trimmed;
12578
+ const resolved = path73.resolve(expanded);
12579
+ if (fs65.existsSync(resolved) && fs65.statSync(resolved).isDirectory()) {
12580
+ const finalPath = path73.join(resolved, suggestedName);
12581
12581
  p34.note(
12582
12582
  [
12583
12583
  `You selected an existing folder: ${resolved}`,
@@ -12753,14 +12753,14 @@ async function startSkillsSourceImportFlow() {
12753
12753
  function renderSuccess(result, jobId) {
12754
12754
  const sourceLine = result.source.kind === "github-repo" ? `${result.source.repo.owner}/${result.source.repo.repo}` : `${result.source.skillId}@${result.source.version}`;
12755
12755
  p34.outro(
12756
- `Imported ${sourceLine} into ${pc49.cyan(result.forkPath)}
12757
- jobId: ${pc49.cyan(jobId)}
12758
- forkId: ${pc49.cyan(result.forkId)}
12756
+ `Imported ${sourceLine} into ${pc50.cyan(result.forkPath)}
12757
+ jobId: ${pc50.cyan(jobId)}
12758
+ forkId: ${pc50.cyan(result.forkId)}
12759
12759
  risk: ${result.security.riskClass} (${result.security.findings.length} findings)
12760
12760
  detection: framework=${result.detection.framework} pm=${result.detection.packageManager}
12761
12761
  open: ${folderOpenLabel3(result.forkPath)}
12762
- summary: ${pc49.dim(result.summaryPath)}
12763
- manifest: ${pc49.dim(result.manifestPath)}`
12762
+ summary: ${pc50.dim(result.summaryPath)}
12763
+ manifest: ${pc50.dim(result.manifestPath)}`
12764
12764
  );
12765
12765
  }
12766
12766
  async function confirmTwice(job) {
@@ -12847,9 +12847,9 @@ var init_source_import_discovery = __esm({
12847
12847
  // src/index.ts
12848
12848
  import { Command } from "commander";
12849
12849
  import * as p35 from "@clack/prompts";
12850
- import pc50 from "picocolors";
12851
- import fs63 from "node:fs";
12852
- import path70 from "node:path";
12850
+ import pc51 from "picocolors";
12851
+ import fs66 from "node:fs";
12852
+ import path74 from "node:path";
12853
12853
  import { spawnSync as spawnSync8 } from "node:child_process";
12854
12854
  import { fileURLToPath as fileURLToPath7 } from "node:url";
12855
12855
 
@@ -13650,8 +13650,8 @@ function printItemCompleted(item) {
13650
13650
  const changes = Array.isArray(item.changes) ? item.changes : [];
13651
13651
  const entries = changes.map((changeRaw) => asRecord(changeRaw)).filter((change) => Boolean(change)).map((change) => {
13652
13652
  const kind = asString(change.kind, "update");
13653
- const path71 = asString(change.path, "unknown");
13654
- return `${kind} ${path71}`;
13653
+ const path75 = asString(change.path, "unknown");
13654
+ return `${kind} ${path75}`;
13655
13655
  });
13656
13656
  const preview = entries.length > 0 ? entries.slice(0, 6).join(", ") : "none";
13657
13657
  const more = entries.length > 6 ? ` (+${entries.length - 6} more)` : "";
@@ -16485,8 +16485,8 @@ function registerIssueCommands(program2) {
16485
16485
  if (opts.assigneeAgentId) params.set("assigneeAgentId", opts.assigneeAgentId);
16486
16486
  if (opts.projectId) params.set("projectId", opts.projectId);
16487
16487
  const query = params.toString();
16488
- const path71 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
16489
- const rows = await ctx.api.get(path71) ?? [];
16488
+ const path75 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
16489
+ const rows = await ctx.api.get(path75) ?? [];
16490
16490
  const filtered = filterIssueRows(rows, opts.match);
16491
16491
  if (ctx.json) {
16492
16492
  printOutput(filtered, { json: true });
@@ -17092,8 +17092,8 @@ function registerActivityCommands(program2) {
17092
17092
  if (opts.entityType) params.set("entityType", opts.entityType);
17093
17093
  if (opts.entityId) params.set("entityId", opts.entityId);
17094
17094
  const query = params.toString();
17095
- const path71 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
17096
- const rows = await ctx.api.get(path71) ?? [];
17095
+ const path75 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
17096
+ const rows = await ctx.api.get(path75) ?? [];
17097
17097
  if (ctx.json) {
17098
17098
  printOutput(rows, { json: true });
17099
17099
  return;
@@ -23788,7 +23788,8 @@ function badge(a) {
23788
23788
  return pc32.magenta("\u{1F9E9} Module");
23789
23789
  }
23790
23790
  function printCard(a) {
23791
- const compat = a.compatibleFormats.length ? pc32.dim("Works with: ") + a.compatibleFormats.map((f) => pc32.cyan(f)).join(", ") : pc32.dim("Works with: any format");
23791
+ const compatibleFormats = "compatibleFormats" in a && Array.isArray(a.compatibleFormats) ? a.compatibleFormats : [];
23792
+ const compat = compatibleFormats.length ? pc32.dim("Works with: ") + compatibleFormats.map((f) => pc32.cyan(f)).join(", ") : pc32.dim("Works with: any format");
23792
23793
  const rows = [
23793
23794
  pc32.bold(a.name),
23794
23795
  `${badge(a)} ${pc32.dim(a.id)}`,
@@ -23821,7 +23822,8 @@ ${pc32.bold(g.label)} ${pc32.dim("(" + g.count + ")")}`);
23821
23822
  console.log(pc32.dim(" " + g.description));
23822
23823
  console.log("");
23823
23824
  for (const a of g.artifacts) {
23824
- const compat = a.compatibleFormats.length ? pc32.dim(" \xB7 " + a.compatibleFormats.join(", ")) : "";
23825
+ const compatibleFormats = "compatibleFormats" in a && Array.isArray(a.compatibleFormats) ? a.compatibleFormats : [];
23826
+ const compat = compatibleFormats.length ? pc32.dim(" \xB7 " + compatibleFormats.join(", ")) : "";
23825
23827
  console.log(` ${pc32.cyan(pc32.bold(a.name))}${compat}`);
23826
23828
  console.log(` ${pc32.dim("growthub template get " + a.slug)}`);
23827
23829
  console.log("");
@@ -24358,6 +24360,18 @@ function collectArtifacts(executionLog) {
24358
24360
  const output = entry.output;
24359
24361
  if (typeof output !== "object" || output === null) continue;
24360
24362
  const record = output;
24363
+ const directStoragePath = stringValue(record.storagePath) ?? stringValue(record.storage_path);
24364
+ const directVideoUrl = stringValue(record.videoUrl);
24365
+ if (directStoragePath || directVideoUrl) {
24366
+ artifacts.push({
24367
+ artifactId: directStoragePath ?? `${entry.nodeId}-video-${artifacts.length + 1}`,
24368
+ artifactType: directVideoUrl || isVideoPath(directStoragePath) ? "video" : "file",
24369
+ nodeId: entry.nodeId,
24370
+ url: directVideoUrl,
24371
+ storagePath: directStoragePath,
24372
+ metadata: record
24373
+ });
24374
+ }
24361
24375
  const images = Array.isArray(record.images) ? record.images : [];
24362
24376
  for (const image of images) {
24363
24377
  if (!image || typeof image !== "object") continue;
@@ -24386,8 +24400,40 @@ function collectArtifacts(executionLog) {
24386
24400
  metadata: slideRecord
24387
24401
  });
24388
24402
  }
24403
+ const videos = Array.isArray(record.videos) ? record.videos : [];
24404
+ for (const video of videos) {
24405
+ if (!video || typeof video !== "object") continue;
24406
+ const videoRecord = video;
24407
+ const storagePath = stringValue(videoRecord.storagePath) ?? stringValue(videoRecord.storage_path);
24408
+ const videoUrl = stringValue(videoRecord.videoUrl) ?? stringValue(videoRecord.url);
24409
+ artifacts.push({
24410
+ artifactId: storagePath ?? `${entry.nodeId}-video-${artifacts.length + 1}`,
24411
+ artifactType: "video",
24412
+ nodeId: entry.nodeId,
24413
+ url: videoUrl,
24414
+ storagePath,
24415
+ metadata: videoRecord
24416
+ });
24417
+ }
24389
24418
  }
24390
- return artifacts;
24419
+ return dedupeArtifacts(artifacts);
24420
+ }
24421
+ function stringValue(value) {
24422
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
24423
+ }
24424
+ function isVideoPath(value) {
24425
+ return Boolean(value?.toLowerCase().match(/\.(mp4|mov|webm|mkv|m4v)(\?|$)/));
24426
+ }
24427
+ function dedupeArtifacts(artifacts) {
24428
+ const seen = /* @__PURE__ */ new Set();
24429
+ const deduped = [];
24430
+ for (const artifact of artifacts) {
24431
+ const key = artifact.storagePath ?? artifact.url ?? artifact.artifactId;
24432
+ if (seen.has(key)) continue;
24433
+ seen.add(key);
24434
+ deduped.push(artifact);
24435
+ }
24436
+ return deduped;
24391
24437
  }
24392
24438
  function resolveNodeSlug(request, nodeId) {
24393
24439
  const match = request.nodes.find((node) => node.id === nodeId);
@@ -24416,6 +24462,7 @@ function summarizeExecution(executionLog) {
24416
24462
  if (Array.isArray(record.images)) imageCount += record.images.length;
24417
24463
  if (Array.isArray(record.slides)) slideCount += record.slides.length;
24418
24464
  if (Array.isArray(record.videos)) videoCount += record.videos.length;
24465
+ if (typeof record.videoUrl === "string" && record.videoUrl.trim().length > 0) videoCount += 1;
24419
24466
  }
24420
24467
  return {
24421
24468
  ...outputText ? { outputText } : {},
@@ -24616,31 +24663,31 @@ function resolveManifestBaseUrl(opts = {}) {
24616
24663
  function isRecord(value) {
24617
24664
  return typeof value === "object" && value !== null && !Array.isArray(value);
24618
24665
  }
24619
- function assertRecord(value, path71) {
24666
+ function assertRecord(value, path75) {
24620
24667
  if (!isRecord(value)) {
24621
- throw new ManifestMalformedError(`Expected object at \`${path71}\`.`);
24668
+ throw new ManifestMalformedError(`Expected object at \`${path75}\`.`);
24622
24669
  }
24623
24670
  return value;
24624
24671
  }
24625
- function assertArray(value, path71) {
24672
+ function assertArray(value, path75) {
24626
24673
  if (!Array.isArray(value)) {
24627
- throw new ManifestMalformedError(`Expected array at \`${path71}\`.`);
24674
+ throw new ManifestMalformedError(`Expected array at \`${path75}\`.`);
24628
24675
  }
24629
24676
  return value;
24630
24677
  }
24631
- function assertString(value, path71) {
24678
+ function assertString(value, path75) {
24632
24679
  if (typeof value !== "string" || value.length === 0) {
24633
- throw new ManifestMalformedError(`Expected non-empty string at \`${path71}\`.`);
24680
+ throw new ManifestMalformedError(`Expected non-empty string at \`${path75}\`.`);
24634
24681
  }
24635
24682
  return value;
24636
24683
  }
24637
- function normalizeProvenance(value, path71) {
24638
- const record = assertRecord(value, path71);
24639
- const originType = assertString(record.originType, `${path71}.originType`);
24684
+ function normalizeProvenance(value, path75) {
24685
+ const record = assertRecord(value, path75);
24686
+ const originType = assertString(record.originType, `${path75}.originType`);
24640
24687
  const allowed = ["hosted", "local-extension", "derived-from-workflow"];
24641
24688
  if (!allowed.includes(originType)) {
24642
24689
  throw new ManifestMalformedError(
24643
- `Unknown provenance originType at \`${path71}.originType\`: ${originType}`
24690
+ `Unknown provenance originType at \`${path75}.originType\`: ${originType}`
24644
24691
  );
24645
24692
  }
24646
24693
  return {
@@ -24712,7 +24759,10 @@ function parseContractVersionHeader(raw) {
24712
24759
  }
24713
24760
  async function fetchCapabilityManifest(opts = {}) {
24714
24761
  const resolvedBaseUrl = resolveManifestBaseUrl(opts);
24715
- const url = new URL(MANIFEST_PATH, `${resolvedBaseUrl.baseUrl}/`).toString();
24762
+ const url = new URL(MANIFEST_PATH, `${resolvedBaseUrl.baseUrl}/`);
24763
+ if (opts.includeExperimental) url.searchParams.set("include_experimental", "true");
24764
+ if (opts.includeDisabled) url.searchParams.set("include_disabled", "true");
24765
+ const manifestUrl = url.toString();
24716
24766
  const headers = {
24717
24767
  accept: "application/json"
24718
24768
  };
@@ -24732,7 +24782,7 @@ async function fetchCapabilityManifest(opts = {}) {
24732
24782
  const timer = controller ? setTimeout(() => controller.abort(), opts.timeoutMs) : null;
24733
24783
  let response;
24734
24784
  try {
24735
- response = await fetch(url, {
24785
+ response = await fetch(manifestUrl, {
24736
24786
  method: "GET",
24737
24787
  headers,
24738
24788
  signal: controller?.signal
@@ -24740,7 +24790,7 @@ async function fetchCapabilityManifest(opts = {}) {
24740
24790
  } catch (err) {
24741
24791
  throw new ManifestEndpointUnavailableError(
24742
24792
  void 0,
24743
- `Hosted manifest endpoint unreachable (${url}): ${err instanceof Error ? err.message : String(err)}`
24793
+ `Hosted manifest endpoint unreachable (${manifestUrl}): ${err instanceof Error ? err.message : String(err)}`
24744
24794
  );
24745
24795
  } finally {
24746
24796
  if (timer) clearTimeout(timer);
@@ -25030,6 +25080,7 @@ async function deriveCapabilitiesFromHostedWorkflows() {
25030
25080
  }
25031
25081
  function matchesQuery(node, query) {
25032
25082
  if (query.enabledOnly !== false && !node.enabled) return false;
25083
+ if (query.includeExperimental !== true && node.experimental) return false;
25033
25084
  if (query.family && node.family !== query.family) return false;
25034
25085
  if (query.executionKind && node.executionKind !== query.executionKind) return false;
25035
25086
  if (query.outputType && !node.outputTypes.includes(query.outputType)) return false;
@@ -25041,9 +25092,12 @@ function matchesQuery(node, query) {
25041
25092
  }
25042
25093
  return true;
25043
25094
  }
25044
- async function resolveFromManifest() {
25095
+ async function resolveFromManifest(query) {
25045
25096
  try {
25046
- const { envelope } = await fetchCapabilityManifest();
25097
+ const { envelope } = await fetchCapabilityManifest({
25098
+ includeExperimental: query?.includeExperimental === true,
25099
+ includeDisabled: query?.enabledOnly === false
25100
+ });
25047
25101
  writeManifestCache(envelope);
25048
25102
  const projected = projectManifestEnvelope(envelope);
25049
25103
  return {
@@ -25104,7 +25158,7 @@ async function resolveFromLegacy() {
25104
25158
  function createCmsCapabilityRegistryClient() {
25105
25159
  return {
25106
25160
  async listCapabilities(query) {
25107
- const outcome = await resolveFromManifest();
25161
+ const outcome = await resolveFromManifest(query);
25108
25162
  const nodes = outcome.nodes;
25109
25163
  const enabledCount = nodes.filter((n) => n.enabled).length;
25110
25164
  const filtered = query ? nodes.filter((n) => matchesQuery(n, query)) : nodes;
@@ -25476,7 +25530,8 @@ function printGroupedCapabilities(nodes) {
25476
25530
  ${header} ${pc33.dim("(" + groupNodes.length + ")")}`);
25477
25531
  for (const node of groupNodes) {
25478
25532
  const enabledTag = node.enabled ? pc33.green("enabled") : pc33.red("disabled");
25479
- console.log(` ${pc33.bold(node.slug)} ${pc33.dim(node.displayName)} ${enabledTag}`);
25533
+ const experimentalTag = node.experimental ? ` ${pc33.yellow("experimental")}` : "";
25534
+ console.log(` ${pc33.bold(node.slug)} ${pc33.dim(node.displayName)} ${enabledTag}${experimentalTag}`);
25480
25535
  console.log(` ${pc33.dim("Execution:")} ${executionKindLabel(node.executionKind)} ${pc33.dim("Outputs:")} ${pc33.dim(node.outputTypes.join(", "))}`);
25481
25536
  if (node.description) {
25482
25537
  console.log(` ${pc33.dim(node.description)}`);
@@ -25493,6 +25548,7 @@ function printCapabilityCard(node) {
25493
25548
  const lines = [
25494
25549
  `${iconPrefix}${pc33.bold(node.displayName)} ${pc33.dim(node.slug)}`,
25495
25550
  `${familyBadge(node.family)} ${node.enabled ? pc33.green("enabled") : pc33.red("disabled")}`,
25551
+ `${pc33.dim("Experimental:")} ${node.experimental ? pc33.yellow("true") : pc33.green("false")}`,
25496
25552
  "",
25497
25553
  `${pc33.dim("Category:")} ${node.category}`,
25498
25554
  `${pc33.dim("Node Type:")} ${node.nodeType}`,
@@ -25620,6 +25676,7 @@ Examples:
25620
25676
  $ growthub capability # interactive browser
25621
25677
  $ growthub capability list # all capabilities grouped by family
25622
25678
  $ growthub capability list --family video # filter by family
25679
+ $ growthub capability list --family video --include-experimental
25623
25680
  $ growthub capability list --json # machine-readable output
25624
25681
  $ growthub capability inspect video-gen # inspect a specific capability
25625
25682
  $ growthub capability resolve # resolve machine bindings for all
@@ -25628,7 +25685,7 @@ Examples:
25628
25685
  cap.action(async () => {
25629
25686
  await runCapabilityPicker({});
25630
25687
  });
25631
- cap.command("list").description("List all CMS-backed runtime node capabilities").option("--family <family>", "Filter by family (video, image, slides, text, data, ops)").option("--json", "Output raw JSON for scripting").action(async (opts) => {
25688
+ cap.command("list").description("List all CMS-backed runtime node capabilities").option("--family <family>", "Filter by family (video, image, slides, text, data, ops)").option("--include-experimental", "Include experimental/admin-hidden capabilities").option("--json", "Output raw JSON for scripting").action(async (opts) => {
25632
25689
  const access = getWorkflowAccess();
25633
25690
  if (access.state !== "ready") {
25634
25691
  console.error(pc33.red(`${access.reason}.`));
@@ -25636,7 +25693,7 @@ Examples:
25636
25693
  return;
25637
25694
  }
25638
25695
  const registry = createCmsCapabilityRegistryClient();
25639
- const query = opts.family ? { family: opts.family } : void 0;
25696
+ const query = opts.family ? { family: opts.family, includeExperimental: opts.includeExperimental === true } : { includeExperimental: opts.includeExperimental === true };
25640
25697
  try {
25641
25698
  const { nodes, meta } = await registry.listCapabilities(query);
25642
25699
  if (opts.json) {
@@ -25657,7 +25714,7 @@ Examples:
25657
25714
  process.exitCode = 1;
25658
25715
  }
25659
25716
  });
25660
- cap.command("inspect").description("Inspect a specific CMS capability node").argument("<slug>", "Capability slug (e.g. 'video-gen', 'text-gen')").option("--json", "Output raw JSON").action(async (slug, opts) => {
25717
+ cap.command("inspect").description("Inspect a specific CMS capability node").argument("<slug>", "Capability slug (e.g. 'video-gen', 'text-gen')").option("--include-experimental", "Include experimental/admin-hidden capabilities").option("--json", "Output raw JSON").action(async (slug, opts) => {
25661
25718
  const access = getWorkflowAccess();
25662
25719
  if (access.state !== "ready") {
25663
25720
  console.error(pc33.red(`${access.reason}.`));
@@ -25666,7 +25723,12 @@ Examples:
25666
25723
  }
25667
25724
  const registry = createCmsCapabilityRegistryClient();
25668
25725
  try {
25669
- const node = await registry.getCapability(slug);
25726
+ const { nodes } = await registry.listCapabilities({
25727
+ slug,
25728
+ enabledOnly: false,
25729
+ includeExperimental: opts.includeExperimental === true
25730
+ });
25731
+ const node = nodes.find((candidate) => candidate.slug === slug) ?? null;
25670
25732
  if (!node) {
25671
25733
  console.error(pc33.red(`Unknown capability: "${slug}".`) + pc33.dim(" Run `growthub capability list` to browse."));
25672
25734
  process.exitCode = 1;
@@ -25920,8 +25982,8 @@ function printRefreshSummary(args) {
25920
25982
  // src/commands/pipeline.ts
25921
25983
  init_session_store();
25922
25984
  init_hosted_client();
25923
- import fs38 from "node:fs";
25924
- import path46 from "node:path";
25985
+ import fs39 from "node:fs";
25986
+ import path47 from "node:path";
25925
25987
  import * as p23 from "@clack/prompts";
25926
25988
  import pc35 from "picocolors";
25927
25989
 
@@ -26584,10 +26646,188 @@ function createArtifactStore() {
26584
26646
  };
26585
26647
  }
26586
26648
 
26649
+ // src/runtime/execution-results/index.ts
26650
+ init_home();
26651
+ import fs36 from "node:fs";
26652
+ import path44 from "node:path";
26653
+ function resolveExecutionResultsDir() {
26654
+ return path44.resolve(resolvePaperclipHomeDir(), "execution-results");
26655
+ }
26656
+ function resolveExecutionResultPath(executionId) {
26657
+ return path44.resolve(resolveExecutionResultsDir(), `${sanitizeCacheKey(executionId)}.json`);
26658
+ }
26659
+ function sanitizeCacheKey(value) {
26660
+ return value.replace(/[^a-zA-Z0-9_.-]/g, "_");
26661
+ }
26662
+ function writeJsonAtomic(filePath, value) {
26663
+ fs36.mkdirSync(path44.dirname(filePath), { recursive: true });
26664
+ const tempPath = `${filePath}.${process.pid}.tmp`;
26665
+ fs36.writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}
26666
+ `, { mode: 384 });
26667
+ fs36.renameSync(tempPath, filePath);
26668
+ }
26669
+ function readJson(filePath) {
26670
+ if (!fs36.existsSync(filePath)) return null;
26671
+ try {
26672
+ return JSON.parse(fs36.readFileSync(filePath, "utf-8"));
26673
+ } catch {
26674
+ return null;
26675
+ }
26676
+ }
26677
+ function initialResult(input) {
26678
+ const cacheKey = input.workflowId?.trim() || input.threadId?.trim() || input.pipelineId;
26679
+ return {
26680
+ executionId: cacheKey,
26681
+ threadId: input.threadId,
26682
+ pipelineId: input.pipelineId,
26683
+ status: "running",
26684
+ nodeResults: Object.fromEntries(
26685
+ input.nodes.map((node) => [
26686
+ node.nodeId,
26687
+ {
26688
+ nodeId: node.nodeId,
26689
+ slug: node.slug,
26690
+ status: "pending"
26691
+ }
26692
+ ])
26693
+ ),
26694
+ artifacts: [],
26695
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
26696
+ cacheKey,
26697
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
26698
+ };
26699
+ }
26700
+ function artifactRefsFromNodeResult(nodeResult) {
26701
+ const output = nodeResult.output;
26702
+ if (!output || typeof output !== "object") return [];
26703
+ const refs = [];
26704
+ const directStoragePath = stringValue2(output.storagePath) ?? stringValue2(output.storage_path);
26705
+ const directUrl = stringValue2(output.videoUrl) ?? stringValue2(output.url);
26706
+ if (directStoragePath || directUrl) {
26707
+ refs.push({
26708
+ artifactId: directStoragePath ?? `${nodeResult.nodeId}-artifact`,
26709
+ artifactType: inferArtifactType(output, directStoragePath, directUrl),
26710
+ nodeId: nodeResult.nodeId,
26711
+ url: directUrl,
26712
+ storagePath: directStoragePath,
26713
+ metadata: output
26714
+ });
26715
+ }
26716
+ const videos = Array.isArray(output.videos) ? output.videos : [];
26717
+ for (const video of videos) {
26718
+ if (!video || typeof video !== "object") continue;
26719
+ const record = video;
26720
+ const storagePath = stringValue2(record.storagePath) ?? stringValue2(record.storage_path);
26721
+ const url = stringValue2(record.videoUrl) ?? stringValue2(record.url);
26722
+ refs.push({
26723
+ artifactId: storagePath ?? `${nodeResult.nodeId}-video-${refs.length + 1}`,
26724
+ artifactType: "video",
26725
+ nodeId: nodeResult.nodeId,
26726
+ url,
26727
+ storagePath,
26728
+ metadata: record
26729
+ });
26730
+ }
26731
+ return dedupeArtifactRefs(refs);
26732
+ }
26733
+ function stringValue2(value) {
26734
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
26735
+ }
26736
+ function inferArtifactType(output, storagePath, url) {
26737
+ const hinted = stringValue2(output.type) ?? stringValue2(output.artifactType);
26738
+ if (hinted) return hinted;
26739
+ const candidate = `${storagePath ?? ""} ${url ?? ""}`.toLowerCase();
26740
+ if (candidate.match(/\.(mp4|mov|webm|mkv|m4v)(\?|$)/) || output.videoUrl) return "video";
26741
+ if (candidate.match(/\.(png|jpg|jpeg|gif|webp)(\?|$)/)) return "image";
26742
+ return "file";
26743
+ }
26744
+ function dedupeArtifactRefs(refs) {
26745
+ const seen = /* @__PURE__ */ new Set();
26746
+ const deduped = [];
26747
+ for (const ref of refs) {
26748
+ const key = ref.storagePath ?? ref.url ?? ref.artifactId;
26749
+ if (seen.has(key)) continue;
26750
+ seen.add(key);
26751
+ deduped.push(ref);
26752
+ }
26753
+ return deduped;
26754
+ }
26755
+ function mergeArtifactRefs(result) {
26756
+ return dedupeArtifactRefs([
26757
+ ...result.artifacts,
26758
+ ...Object.values(result.nodeResults).flatMap((nodeResult) => artifactRefsFromNodeResult(nodeResult))
26759
+ ]);
26760
+ }
26761
+ function createExecutionResultCache(input) {
26762
+ let result = initialResult(input);
26763
+ let currentPath = resolveExecutionResultPath(result.executionId);
26764
+ writeJsonAtomic(currentPath, result);
26765
+ const persist = () => {
26766
+ result.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
26767
+ result.artifacts = mergeArtifactRefs(result);
26768
+ currentPath = resolveExecutionResultPath(result.executionId);
26769
+ writeJsonAtomic(currentPath, result);
26770
+ };
26771
+ return {
26772
+ handleEvent(event) {
26773
+ if (typeof event.executionId === "string" && event.executionId.trim()) {
26774
+ result.executionId = event.executionId.trim();
26775
+ }
26776
+ if (event.nodeId) {
26777
+ const current = result.nodeResults[event.nodeId] ?? {
26778
+ nodeId: event.nodeId,
26779
+ slug: event.nodeId,
26780
+ status: "pending"
26781
+ };
26782
+ if (event.type === "node_start") {
26783
+ current.status = "running";
26784
+ } else if (event.type === "node_complete") {
26785
+ current.status = "succeeded";
26786
+ current.output = event.output;
26787
+ } else if (event.type === "node_error") {
26788
+ current.status = "failed";
26789
+ current.error = event.error;
26790
+ }
26791
+ result.nodeResults[event.nodeId] = current;
26792
+ }
26793
+ if (event.type === "complete" && Array.isArray(event.executionLog)) {
26794
+ result.executionLog = event.executionLog;
26795
+ result.status = "succeeded";
26796
+ result.completedAt = (/* @__PURE__ */ new Date()).toISOString();
26797
+ }
26798
+ if (event.type === "error") {
26799
+ result.status = "failed";
26800
+ result.completedAt = (/* @__PURE__ */ new Date()).toISOString();
26801
+ }
26802
+ persist();
26803
+ },
26804
+ saveFinal(finalResult) {
26805
+ result = {
26806
+ ...finalResult,
26807
+ pipelineId: input.pipelineId,
26808
+ artifacts: dedupeArtifactRefs([...finalResult.artifacts, ...mergeArtifactRefs(result)]),
26809
+ cacheKey: result.cacheKey,
26810
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
26811
+ };
26812
+ currentPath = resolveExecutionResultPath(result.executionId);
26813
+ writeJsonAtomic(currentPath, result);
26814
+ return result;
26815
+ },
26816
+ getPath() {
26817
+ return currentPath;
26818
+ }
26819
+ };
26820
+ }
26821
+ function readExecutionResult(executionId) {
26822
+ const raw = readJson(resolveExecutionResultPath(executionId));
26823
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
26824
+ return raw;
26825
+ }
26826
+
26587
26827
  // src/runtime/native-intelligence/index.ts
26588
26828
  init_home();
26589
- import fs37 from "node:fs";
26590
- import path45 from "node:path";
26829
+ import fs38 from "node:fs";
26830
+ import path46 from "node:path";
26591
26831
 
26592
26832
  // src/runtime/native-intelligence/contract.ts
26593
26833
  var DEFAULT_INTELLIGENCE_CONFIG = {
@@ -27858,8 +28098,8 @@ function parseJsonSafe5(text69) {
27858
28098
  }
27859
28099
 
27860
28100
  // src/runtime/native-intelligence/marketing-context-builder.ts
27861
- import fs36 from "node:fs";
27862
- import path44 from "node:path";
28101
+ import fs37 from "node:fs";
28102
+ import path45 from "node:path";
27863
28103
  var CONTEXT_BUILDER_SYSTEM_PROMPT = `You are a marketing strategist drafting a product-marketing-context document.
27864
28104
 
27865
28105
  You receive project artifacts (README content, package.json metadata, any landing page content) and produce a structured product-marketing-context.md with 12 sections.
@@ -27878,17 +28118,17 @@ var MAX_ARTIFACT_LENGTH = 8e3;
27878
28118
  function scanProjectArtifacts(projectDir, existingContext) {
27879
28119
  const artifacts = { otherFiles: [] };
27880
28120
  for (const name of ["README.md", "readme.md", "Readme.md", "README"]) {
27881
- const readmePath = path44.join(projectDir, name);
27882
- if (fs36.existsSync(readmePath)) {
27883
- const content = fs36.readFileSync(readmePath, "utf-8");
28121
+ const readmePath = path45.join(projectDir, name);
28122
+ if (fs37.existsSync(readmePath)) {
28123
+ const content = fs37.readFileSync(readmePath, "utf-8");
27884
28124
  artifacts.readme = content.slice(0, MAX_ARTIFACT_LENGTH);
27885
28125
  break;
27886
28126
  }
27887
28127
  }
27888
- const pkgPath = path44.join(projectDir, "package.json");
27889
- if (fs36.existsSync(pkgPath)) {
28128
+ const pkgPath = path45.join(projectDir, "package.json");
28129
+ if (fs37.existsSync(pkgPath)) {
27890
28130
  try {
27891
- artifacts.packageJson = JSON.parse(fs36.readFileSync(pkgPath, "utf-8"));
28131
+ artifacts.packageJson = JSON.parse(fs37.readFileSync(pkgPath, "utf-8"));
27892
28132
  } catch {
27893
28133
  }
27894
28134
  }
@@ -27900,15 +28140,15 @@ function scanProjectArtifacts(projectDir, existingContext) {
27900
28140
  ".claude/product-marketing-context.md",
27901
28141
  "brands/_template/product-marketing-context.md"
27902
28142
  ]) {
27903
- const ctxPath = path44.join(projectDir, candidate);
27904
- if (fs36.existsSync(ctxPath)) {
27905
- artifacts.existingContext = fs36.readFileSync(ctxPath, "utf-8");
28143
+ const ctxPath = path45.join(projectDir, candidate);
28144
+ if (fs37.existsSync(ctxPath)) {
28145
+ artifacts.existingContext = fs37.readFileSync(ctxPath, "utf-8");
27906
28146
  break;
27907
28147
  }
27908
28148
  }
27909
28149
  }
27910
28150
  for (const name of ["CONTRIBUTING.md", "AGENTS.md", "landing-page.md", "about.md"]) {
27911
- if (fs36.existsSync(path44.join(projectDir, name))) {
28151
+ if (fs37.existsSync(path45.join(projectDir, name))) {
27912
28152
  artifacts.otherFiles.push(name);
27913
28153
  }
27914
28154
  }
@@ -28149,15 +28389,15 @@ function cleanMarkdownResponse(text69) {
28149
28389
 
28150
28390
  // src/runtime/native-intelligence/index.ts
28151
28391
  function resolveConfigPath2() {
28152
- return path45.resolve(resolvePaperclipHomeDir(), "native-intelligence", "config.json");
28392
+ return path46.resolve(resolvePaperclipHomeDir(), "native-intelligence", "config.json");
28153
28393
  }
28154
28394
  function readIntelligenceConfig() {
28155
28395
  const configPath = resolveConfigPath2();
28156
- if (!fs37.existsSync(configPath)) {
28396
+ if (!fs38.existsSync(configPath)) {
28157
28397
  return { ...DEFAULT_INTELLIGENCE_CONFIG };
28158
28398
  }
28159
28399
  try {
28160
- const raw = JSON.parse(fs37.readFileSync(configPath, "utf-8"));
28400
+ const raw = JSON.parse(fs38.readFileSync(configPath, "utf-8"));
28161
28401
  return {
28162
28402
  modelId: validateModelId(raw.modelId),
28163
28403
  backendType: raw.backendType === "hosted" ? "hosted" : "local",
@@ -28174,8 +28414,8 @@ function readIntelligenceConfig() {
28174
28414
  }
28175
28415
  function writeIntelligenceConfig(config) {
28176
28416
  const configPath = resolveConfigPath2();
28177
- fs37.mkdirSync(path45.dirname(configPath), { recursive: true });
28178
- fs37.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
28417
+ fs38.mkdirSync(path46.dirname(configPath), { recursive: true });
28418
+ fs38.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
28179
28419
  `, "utf-8");
28180
28420
  }
28181
28421
  function validateModelId(id) {
@@ -28494,7 +28734,7 @@ async function runPipelineAssembler(opts) {
28494
28734
  const pipeline2 = builder.build();
28495
28735
  const pkg = await builder.package();
28496
28736
  p23.log.info(`Executing pipeline ${pc35.bold(pipeline2.pipelineId)} (${pkg.executionRoute})...`);
28497
- const result = await executionClient.executeWorkflow({
28737
+ const executionInput = {
28498
28738
  pipelineId: pipeline2.pipelineId,
28499
28739
  threadId: pipeline2.threadId,
28500
28740
  nodes: pipeline2.nodes.map((n) => ({
@@ -28505,11 +28745,19 @@ async function runPipelineAssembler(opts) {
28505
28745
  })),
28506
28746
  executionMode: pipeline2.executionMode,
28507
28747
  metadata: pipeline2.metadata
28748
+ };
28749
+ const resultCache = createExecutionResultCache(executionInput);
28750
+ const result = await executionClient.executeWorkflow(executionInput, {
28751
+ onEvent: async (event) => {
28752
+ resultCache.handleEvent(event);
28753
+ }
28508
28754
  });
28509
- p23.log.success(`Execution ${pc35.bold(result.executionId)}: ${result.status}`);
28755
+ const cachedResult = resultCache.saveFinal(result);
28756
+ p23.log.success(`Execution ${pc35.bold(cachedResult.executionId)}: ${cachedResult.status}`);
28757
+ p23.log.info(`Result cache: ${resultCache.getPath()}`);
28510
28758
  const artifactStore = createArtifactStore();
28511
- for (const artRef of result.artifacts) {
28512
- const nodeResult = result.nodeResults[artRef.nodeId];
28759
+ for (const artRef of cachedResult.artifacts) {
28760
+ const nodeResult = cachedResult.nodeResults[artRef.nodeId];
28513
28761
  artifactStore.create({
28514
28762
  artifactType: artRef.artifactType,
28515
28763
  sourceNodeSlug: nodeResult?.slug ?? "unknown",
@@ -28517,11 +28765,15 @@ async function runPipelineAssembler(opts) {
28517
28765
  pipelineId: pipeline2.pipelineId,
28518
28766
  nodeId: artRef.nodeId,
28519
28767
  threadId: pipeline2.threadId,
28520
- metadata: artRef.metadata ?? {}
28768
+ metadata: {
28769
+ ...artRef.metadata ?? {},
28770
+ ...artRef.url ? { url: artRef.url } : {},
28771
+ ...artRef.storagePath ? { storagePath: artRef.storagePath } : {}
28772
+ }
28521
28773
  });
28522
28774
  }
28523
- if (result.artifacts.length > 0) {
28524
- p23.log.info(`${result.artifacts.length} artifact(s) recorded.`);
28775
+ if (cachedResult.artifacts.length > 0) {
28776
+ p23.log.info(`${cachedResult.artifacts.length} artifact(s) recorded.`);
28525
28777
  }
28526
28778
  } catch (err) {
28527
28779
  p23.log.error("Execution failed: " + err.message);
@@ -28531,9 +28783,9 @@ async function runPipelineAssembler(opts) {
28531
28783
  }
28532
28784
  }
28533
28785
  function loadPipelineFromFileOrJson(input) {
28534
- const resolvedPath = path46.resolve(input);
28535
- if (fs38.existsSync(resolvedPath)) {
28536
- const content = fs38.readFileSync(resolvedPath, "utf-8");
28786
+ const resolvedPath = path47.resolve(input);
28787
+ if (fs39.existsSync(resolvedPath)) {
28788
+ const content = fs39.readFileSync(resolvedPath, "utf-8");
28537
28789
  return deserializePipeline(JSON.parse(content));
28538
28790
  }
28539
28791
  try {
@@ -28589,7 +28841,7 @@ async function executeHostedPipeline(pipeline, opts) {
28589
28841
  startupSettled = true;
28590
28842
  startupSpinner.stop(message ?? "Hosted workflow execution started.");
28591
28843
  };
28592
- const result = await executionClient.executeWorkflow({
28844
+ const executionInput = {
28593
28845
  pipelineId: pipeline.pipelineId,
28594
28846
  workflowId: hostedWorkflowId,
28595
28847
  threadId: hostedWorkflowId ?? pipeline.threadId,
@@ -28601,8 +28853,12 @@ async function executeHostedPipeline(pipeline, opts) {
28601
28853
  })),
28602
28854
  executionMode: pipeline.executionMode,
28603
28855
  metadata: pipeline.metadata
28604
- }, opts?.json ? void 0 : {
28856
+ };
28857
+ const resultCache = createExecutionResultCache(executionInput);
28858
+ const result = await executionClient.executeWorkflow(executionInput, {
28605
28859
  onEvent: async (event) => {
28860
+ resultCache.handleEvent(event);
28861
+ if (opts?.json) return;
28606
28862
  if (event.type === "node_start" || event.type === "node_complete") {
28607
28863
  settleStartup("Hosted workflow execution started.");
28608
28864
  }
@@ -28618,31 +28874,33 @@ async function executeHostedPipeline(pipeline, opts) {
28618
28874
  }
28619
28875
  }
28620
28876
  });
28877
+ const cachedResult = resultCache.saveFinal(result);
28621
28878
  settleStartup("Hosted workflow execution started.");
28622
28879
  if (opts?.json) {
28623
- console.log(JSON.stringify(result, null, 2));
28880
+ console.log(JSON.stringify(cachedResult, null, 2));
28624
28881
  return;
28625
28882
  }
28626
28883
  console.log("");
28627
28884
  console.log(pc35.bold("Pipeline Execution Result"));
28628
28885
  console.log(hr6());
28629
- console.log(` ${pc35.dim("Execution ID:")} ${result.executionId}`);
28886
+ console.log(` ${pc35.dim("Execution ID:")} ${cachedResult.executionId}`);
28887
+ console.log(` ${pc35.dim("Result Cache:")} ${resultCache.getPath()}`);
28630
28888
  if (result.threadId) console.log(` ${pc35.dim("Thread ID:")} ${result.threadId}`);
28631
28889
  console.log(` ${pc35.dim("Status:")} ${result.status === "succeeded" ? pc35.green(result.status) : pc35.red(result.status)}`);
28632
28890
  if (result.startedAt) console.log(` ${pc35.dim("Started:")} ${result.startedAt}`);
28633
28891
  if (result.completedAt) console.log(` ${pc35.dim("Completed:")} ${result.completedAt}`);
28634
28892
  console.log(hr6());
28635
- for (const [nodeId, nodeResult] of Object.entries(result.nodeResults)) {
28893
+ for (const [nodeId, nodeResult] of Object.entries(cachedResult.nodeResults)) {
28636
28894
  const statusColor3 = nodeResult.status === "succeeded" ? pc35.green : pc35.red;
28637
28895
  console.log(` ${statusColor3(nodeResult.status)} ${pc35.bold(nodeResult.slug)} (${pc35.dim(nodeId)})`);
28638
28896
  if (nodeResult.error) {
28639
28897
  console.log(` ${pc35.red(nodeResult.error)}`);
28640
28898
  }
28641
28899
  }
28642
- if (result.artifacts.length > 0) {
28900
+ if (cachedResult.artifacts.length > 0) {
28643
28901
  console.log("");
28644
28902
  console.log(pc35.bold(" Artifacts:"));
28645
- for (const art of result.artifacts) {
28903
+ for (const art of cachedResult.artifacts) {
28646
28904
  console.log(` ${pc35.dim("\xB7")} ${art.artifactType} (${art.artifactId})`);
28647
28905
  }
28648
28906
  }
@@ -28673,8 +28931,8 @@ async function executeHostedPipeline(pipeline, opts) {
28673
28931
  }
28674
28932
  }
28675
28933
  const artifactStore = createArtifactStore();
28676
- for (const artRef of result.artifacts) {
28677
- const nodeResult = result.nodeResults[artRef.nodeId];
28934
+ for (const artRef of cachedResult.artifacts) {
28935
+ const nodeResult = cachedResult.nodeResults[artRef.nodeId];
28678
28936
  artifactStore.create({
28679
28937
  artifactType: artRef.artifactType,
28680
28938
  sourceNodeSlug: nodeResult?.slug ?? "unknown",
@@ -28682,7 +28940,11 @@ async function executeHostedPipeline(pipeline, opts) {
28682
28940
  pipelineId: pipeline.pipelineId,
28683
28941
  nodeId: artRef.nodeId,
28684
28942
  threadId: result.threadId ?? pipeline.threadId,
28685
- metadata: artRef.metadata ?? {}
28943
+ metadata: {
28944
+ ...artRef.metadata ?? {},
28945
+ ...artRef.url ? { url: artRef.url } : {},
28946
+ ...artRef.storagePath ? { storagePath: artRef.storagePath } : {}
28947
+ }
28686
28948
  });
28687
28949
  }
28688
28950
  console.log("");
@@ -28852,7 +29114,7 @@ Examples:
28852
29114
  const totalNodes = Math.max(1, pipeline.nodes.length);
28853
29115
  const completed = /* @__PURE__ */ new Set();
28854
29116
  const trackableNodeIds = new Set(pipeline.nodes.map((node) => node.id));
28855
- const result = await executionClient.executeWorkflow({
29117
+ const executionInput = {
28856
29118
  pipelineId: pipeline.pipelineId,
28857
29119
  workflowId: hostedWorkflowId,
28858
29120
  threadId: hostedWorkflowId ?? pipeline.threadId,
@@ -28864,8 +29126,12 @@ Examples:
28864
29126
  })),
28865
29127
  executionMode: pipeline.executionMode,
28866
29128
  metadata: pipeline.metadata
28867
- }, opts.json ? void 0 : {
29129
+ };
29130
+ const resultCache = createExecutionResultCache(executionInput);
29131
+ const result = await executionClient.executeWorkflow(executionInput, {
28868
29132
  onEvent: async (event) => {
29133
+ resultCache.handleEvent(event);
29134
+ if (opts.json) return;
28869
29135
  if (event.type === "node_complete" && event.nodeId && trackableNodeIds.has(event.nodeId) && !completed.has(event.nodeId)) {
28870
29136
  completed.add(event.nodeId);
28871
29137
  completedNodes = completed.size;
@@ -28877,42 +29143,44 @@ Examples:
28877
29143
  }
28878
29144
  }
28879
29145
  });
29146
+ const cachedResult = resultCache.saveFinal(result);
28880
29147
  if (opts.json) {
28881
- console.log(JSON.stringify(result, null, 2));
29148
+ console.log(JSON.stringify(cachedResult, null, 2));
28882
29149
  return;
28883
29150
  }
28884
29151
  console.log("");
28885
29152
  console.log(pc35.bold("Pipeline Execution Result"));
28886
29153
  console.log(hr6());
28887
- console.log(` ${pc35.dim("Execution ID:")} ${result.executionId}`);
28888
- if (result.threadId) console.log(` ${pc35.dim("Thread ID:")} ${result.threadId}`);
28889
- console.log(` ${pc35.dim("Status:")} ${result.status === "succeeded" ? pc35.green(result.status) : pc35.red(result.status)}`);
28890
- if (result.startedAt) console.log(` ${pc35.dim("Started:")} ${result.startedAt}`);
28891
- if (result.completedAt) console.log(` ${pc35.dim("Completed:")} ${result.completedAt}`);
29154
+ console.log(` ${pc35.dim("Execution ID:")} ${cachedResult.executionId}`);
29155
+ console.log(` ${pc35.dim("Result Cache:")} ${resultCache.getPath()}`);
29156
+ if (cachedResult.threadId) console.log(` ${pc35.dim("Thread ID:")} ${cachedResult.threadId}`);
29157
+ console.log(` ${pc35.dim("Status:")} ${cachedResult.status === "succeeded" ? pc35.green(cachedResult.status) : pc35.red(cachedResult.status)}`);
29158
+ if (cachedResult.startedAt) console.log(` ${pc35.dim("Started:")} ${cachedResult.startedAt}`);
29159
+ if (cachedResult.completedAt) console.log(` ${pc35.dim("Completed:")} ${cachedResult.completedAt}`);
28892
29160
  console.log(hr6());
28893
- for (const [nodeId, nodeResult] of Object.entries(result.nodeResults)) {
29161
+ for (const [nodeId, nodeResult] of Object.entries(cachedResult.nodeResults)) {
28894
29162
  const statusColor3 = nodeResult.status === "succeeded" ? pc35.green : pc35.red;
28895
29163
  console.log(` ${statusColor3(nodeResult.status)} ${pc35.bold(nodeResult.slug)} (${pc35.dim(nodeId)})`);
28896
29164
  if (nodeResult.error) {
28897
29165
  console.log(` ${pc35.red(nodeResult.error)}`);
28898
29166
  }
28899
29167
  }
28900
- if (result.artifacts.length > 0) {
29168
+ if (cachedResult.artifacts.length > 0) {
28901
29169
  console.log("");
28902
29170
  console.log(pc35.bold(" Artifacts:"));
28903
- for (const art of result.artifacts) {
29171
+ for (const art of cachedResult.artifacts) {
28904
29172
  console.log(` ${pc35.dim("\xB7")} ${art.artifactType} (${art.artifactId})`);
28905
29173
  }
28906
29174
  }
28907
- if (result.summary) {
29175
+ if (cachedResult.summary) {
28908
29176
  console.log("");
28909
29177
  console.log(pc35.bold(" Summary:"));
28910
- if (result.summary.outputText) console.log(` ${pc35.dim("\xB7")} ${result.summary.outputText}`);
28911
- if (typeof result.summary.imageCount === "number") console.log(` ${pc35.dim("\xB7")} images: ${result.summary.imageCount}`);
28912
- if (typeof result.summary.slideCount === "number") console.log(` ${pc35.dim("\xB7")} slides: ${result.summary.slideCount}`);
28913
- if (typeof result.summary.videoCount === "number") console.log(` ${pc35.dim("\xB7")} videos: ${result.summary.videoCount}`);
28914
- if (result.summary.workflowRunId) console.log(` ${pc35.dim("\xB7")} workflow_run_id: ${result.summary.workflowRunId}`);
28915
- if (result.summary.keyboardShortcutHint) console.log(` ${pc35.dim("\xB7")} ${result.summary.keyboardShortcutHint}`);
29178
+ if (cachedResult.summary.outputText) console.log(` ${pc35.dim("\xB7")} ${cachedResult.summary.outputText}`);
29179
+ if (typeof cachedResult.summary.imageCount === "number") console.log(` ${pc35.dim("\xB7")} images: ${cachedResult.summary.imageCount}`);
29180
+ if (typeof cachedResult.summary.slideCount === "number") console.log(` ${pc35.dim("\xB7")} slides: ${cachedResult.summary.slideCount}`);
29181
+ if (typeof cachedResult.summary.videoCount === "number") console.log(` ${pc35.dim("\xB7")} videos: ${cachedResult.summary.videoCount}`);
29182
+ if (cachedResult.summary.workflowRunId) console.log(` ${pc35.dim("\xB7")} workflow_run_id: ${cachedResult.summary.workflowRunId}`);
29183
+ if (cachedResult.summary.keyboardShortcutHint) console.log(` ${pc35.dim("\xB7")} ${cachedResult.summary.keyboardShortcutHint}`);
28916
29184
  }
28917
29185
  try {
28918
29186
  const credits = await fetchHostedCredits(session);
@@ -28928,8 +29196,8 @@ Examples:
28928
29196
  }
28929
29197
  }
28930
29198
  const artifactStore = createArtifactStore();
28931
- for (const artRef of result.artifacts) {
28932
- const nodeResult = result.nodeResults[artRef.nodeId];
29199
+ for (const artRef of cachedResult.artifacts) {
29200
+ const nodeResult = cachedResult.nodeResults[artRef.nodeId];
28933
29201
  artifactStore.create({
28934
29202
  artifactType: artRef.artifactType,
28935
29203
  sourceNodeSlug: nodeResult?.slug ?? "unknown",
@@ -28937,7 +29205,11 @@ Examples:
28937
29205
  pipelineId: pipeline.pipelineId,
28938
29206
  nodeId: artRef.nodeId,
28939
29207
  threadId: pipeline.threadId,
28940
- metadata: artRef.metadata ?? {}
29208
+ metadata: {
29209
+ ...artRef.metadata ?? {},
29210
+ ...artRef.url ? { url: artRef.url } : {},
29211
+ ...artRef.storagePath ? { storagePath: artRef.storagePath } : {}
29212
+ }
28941
29213
  });
28942
29214
  }
28943
29215
  console.log("");
@@ -28949,7 +29221,10 @@ Examples:
28949
29221
  }
28950
29222
 
28951
29223
  // src/commands/artifact.ts
29224
+ import fs40 from "node:fs";
29225
+ import path48 from "node:path";
28952
29226
  import pc36 from "picocolors";
29227
+ init_session_store();
28953
29228
  function hr7(width = 72) {
28954
29229
  return pc36.dim("\u2500".repeat(width));
28955
29230
  }
@@ -29027,6 +29302,64 @@ function printArtifactDetail(art) {
29027
29302
  console.log(hr7());
29028
29303
  console.log("");
29029
29304
  }
29305
+ function stringMetadata(value) {
29306
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
29307
+ }
29308
+ function inferOutPath(storagePath, out) {
29309
+ if (out?.trim()) return path48.resolve(out);
29310
+ return path48.resolve(process.cwd(), path48.basename(storagePath));
29311
+ }
29312
+ async function downloadStoragePath(storagePath, outPath, bucket = "node_documents") {
29313
+ const session = readSession();
29314
+ if (!session || isSessionExpired(session)) {
29315
+ throw new Error("Hosted session expired. Run `growthub auth login` again.");
29316
+ }
29317
+ const url = new URL("/api/secure-image", `${session.hostedBaseUrl.replace(/\/+$/, "")}/`);
29318
+ url.searchParams.set("bucket", bucket);
29319
+ url.searchParams.set("path", storagePath);
29320
+ const response = await fetch(url, {
29321
+ headers: {
29322
+ authorization: `Bearer ${session.accessToken}`,
29323
+ ...session.userId ? { "x-user-id": session.userId } : {}
29324
+ }
29325
+ });
29326
+ if (!response.ok) {
29327
+ throw new Error(`Authenticated artifact download failed (${response.status}).`);
29328
+ }
29329
+ const buffer = Buffer.from(await response.arrayBuffer());
29330
+ fs40.mkdirSync(path48.dirname(outPath), { recursive: true });
29331
+ fs40.writeFileSync(outPath, buffer);
29332
+ return buffer.length;
29333
+ }
29334
+ function resolveStorageRef(id, artifactSelector, direct) {
29335
+ if (direct?.storagePath?.trim()) {
29336
+ return {
29337
+ storagePath: direct.storagePath.trim(),
29338
+ bucket: direct.bucket?.trim() || "node_documents",
29339
+ artifactId: direct.storagePath.trim()
29340
+ };
29341
+ }
29342
+ if (!id) return null;
29343
+ const execution = readExecutionResult(id);
29344
+ if (execution) {
29345
+ const artifacts = execution.artifacts.filter((artifact2) => artifact2.storagePath);
29346
+ const selected = artifactSelector ? artifacts.find((artifact2) => artifact2.artifactId === artifactSelector || artifact2.nodeId === artifactSelector) : artifacts[0];
29347
+ if (!selected?.storagePath) return null;
29348
+ return {
29349
+ storagePath: selected.storagePath,
29350
+ bucket: stringMetadata(selected.metadata?.bucket) ?? "node_documents",
29351
+ artifactId: selected.artifactId
29352
+ };
29353
+ }
29354
+ const artifact = createArtifactStore().get(id);
29355
+ const storagePath = stringMetadata(artifact?.metadata?.storagePath) ?? stringMetadata(artifact?.metadata?.storage_path);
29356
+ if (!artifact || !storagePath) return null;
29357
+ return {
29358
+ storagePath,
29359
+ bucket: stringMetadata(artifact.metadata?.bucket) ?? "node_documents",
29360
+ artifactId: artifact.id
29361
+ };
29362
+ }
29030
29363
  function registerArtifactCommands(program2) {
29031
29364
  const art = program2.command("artifact").description("List and inspect pipeline execution artifacts").addHelpText("after", `
29032
29365
  Examples:
@@ -29035,6 +29368,8 @@ Examples:
29035
29368
  $ growthub artifact list --pipeline <id> # filter by pipeline
29036
29369
  $ growthub artifact list --json # machine-readable output
29037
29370
  $ growthub artifact inspect <id> # inspect a specific artifact
29371
+ $ growthub artifact download <executionId>
29372
+ $ growthub artifact download --storage-path workflow_videos/<user>/<thread>/<file>.mp4
29038
29373
  `);
29039
29374
  art.action(async (opts) => {
29040
29375
  const store = createArtifactStore();
@@ -29075,27 +29410,543 @@ Examples:
29075
29410
  }
29076
29411
  printArtifactDetail(artifact);
29077
29412
  });
29413
+ art.command("download").description("Download a hosted execution artifact through the authenticated Growthub proxy").argument("[id]", "Execution ID from pipeline execute, or local artifact ID").option("--artifact <id>", "Artifact ID or node ID when an execution has multiple artifacts").option("--storage-path <path>", "Download this Growthub storage path directly with the active auth session").option("--bucket <bucket>", "Storage bucket for --storage-path", "node_documents").option("--out <path>", "Output file path").option("--json", "Output raw JSON").action(async (id, opts) => {
29414
+ try {
29415
+ const ref = resolveStorageRef(id, opts.artifact, {
29416
+ storagePath: opts.storagePath,
29417
+ bucket: opts.bucket
29418
+ });
29419
+ if (!ref) {
29420
+ throw new Error(
29421
+ id ? `No downloadable storagePath found for "${id}".` : "Provide an execution ID, local artifact ID, or --storage-path."
29422
+ );
29423
+ }
29424
+ const outPath = inferOutPath(ref.storagePath, opts.out);
29425
+ const bytes = await downloadStoragePath(ref.storagePath, outPath, ref.bucket);
29426
+ const payload = {
29427
+ status: "ok",
29428
+ id,
29429
+ artifactId: ref.artifactId,
29430
+ bucket: ref.bucket,
29431
+ storagePath: ref.storagePath,
29432
+ outPath,
29433
+ bytes
29434
+ };
29435
+ if (opts.json) {
29436
+ console.log(JSON.stringify(payload, null, 2));
29437
+ return;
29438
+ }
29439
+ console.log(pc36.green("Downloaded artifact"));
29440
+ console.log(` ${pc36.dim("Artifact:")} ${payload.artifactId}`);
29441
+ console.log(` ${pc36.dim("Storage:")} ${payload.bucket}/${payload.storagePath}`);
29442
+ console.log(` ${pc36.dim("Output:")} ${payload.outPath}`);
29443
+ console.log(` ${pc36.dim("Bytes:")} ${payload.bytes}`);
29444
+ } catch (err) {
29445
+ if (opts.json) {
29446
+ console.log(JSON.stringify({
29447
+ status: "error",
29448
+ message: err instanceof Error ? err.message : String(err)
29449
+ }, null, 2));
29450
+ } else {
29451
+ console.error(pc36.red("Download failed: " + (err instanceof Error ? err.message : String(err))));
29452
+ }
29453
+ process.exitCode = 1;
29454
+ }
29455
+ });
29456
+ }
29457
+
29458
+ // src/commands/bridge.ts
29459
+ import path50 from "node:path";
29460
+ import pc37 from "picocolors";
29461
+
29462
+ // src/runtime/growthub-bridge-client/index.ts
29463
+ init_session_store();
29464
+ import fs41 from "node:fs";
29465
+ import path49 from "node:path";
29466
+ function readActiveSession() {
29467
+ const session = readSession();
29468
+ if (!session || isSessionExpired(session)) {
29469
+ throw new Error("Hosted session expired. Run `growthub auth login` again.");
29470
+ }
29471
+ if (!session.userId) {
29472
+ throw new Error("Hosted session is missing userId. Run `growthub auth login` again.");
29473
+ }
29474
+ return session;
29475
+ }
29476
+ function bridgeUrl(session, pathname, params) {
29477
+ const baseUrl = process.env.GROWTHUB_BRIDGE_BASE_URL?.trim() || session.hostedBaseUrl;
29478
+ const url = new URL(pathname, `${baseUrl.replace(/\/+$/, "")}/`);
29479
+ for (const [key, value] of Object.entries(params ?? {})) {
29480
+ if (value === void 0 || value === "") continue;
29481
+ url.searchParams.set(key, String(value));
29482
+ }
29483
+ return url;
29484
+ }
29485
+ function buildSupabaseSessionCookie(session) {
29486
+ const payload = {
29487
+ access_token: session.accessToken,
29488
+ user: {
29489
+ id: session.userId,
29490
+ email: session.email
29491
+ }
29492
+ };
29493
+ return `sb-growthub-auth-token=${encodeURIComponent(JSON.stringify(payload))}`;
29494
+ }
29495
+ async function requestJson(session, url, init = {}) {
29496
+ const headers = {
29497
+ accept: "application/json",
29498
+ authorization: `Bearer ${session.accessToken}`,
29499
+ "x-user-id": session.userId ?? "",
29500
+ ...Object.fromEntries(new Headers(init.headers).entries())
29501
+ };
29502
+ if (init.body !== void 0 && !headers["content-type"]) {
29503
+ headers["content-type"] = "application/json";
29504
+ }
29505
+ const response = await fetch(url, { ...init, headers });
29506
+ const text69 = await response.text();
29507
+ const parsed = text69.trim() ? safeJson(text69) : null;
29508
+ if (!response.ok) {
29509
+ const message = typeof parsed === "object" && parsed && "error" in parsed ? String(parsed.error) : `Growthub bridge request failed (${response.status})`;
29510
+ throw new Error(message);
29511
+ }
29512
+ return parsed;
29513
+ }
29514
+ async function requestJsonWithSessionCookie(session, url, init = {}) {
29515
+ const headers = {
29516
+ accept: "application/json",
29517
+ cookie: buildSupabaseSessionCookie(session),
29518
+ ...Object.fromEntries(new Headers(init.headers).entries())
29519
+ };
29520
+ if (init.body !== void 0 && !headers["content-type"]) {
29521
+ headers["content-type"] = "application/json";
29522
+ }
29523
+ const response = await fetch(url, { ...init, headers });
29524
+ const text69 = await response.text();
29525
+ const parsed = text69.trim() ? safeJson(text69) : null;
29526
+ if (!response.ok) {
29527
+ const message = typeof parsed === "object" && parsed && "error" in parsed ? String(parsed.error) : `Growthub session-backed request failed (${response.status})`;
29528
+ throw new Error(message);
29529
+ }
29530
+ return parsed;
29531
+ }
29532
+ function safeJson(text69) {
29533
+ try {
29534
+ return JSON.parse(text69);
29535
+ } catch {
29536
+ return text69;
29537
+ }
29538
+ }
29539
+ var GrowthubBridgeClient = class {
29540
+ constructor(session = readActiveSession()) {
29541
+ this.session = session;
29542
+ }
29543
+ session;
29544
+ async listAssets(query = {}) {
29545
+ const url = bridgeUrl(this.session, "/api/cli/profile", {
29546
+ view: "gallery-assets",
29547
+ page: query.page ?? 1,
29548
+ limit: query.limit ?? 20,
29549
+ source: query.source,
29550
+ mediaType: query.mediaType,
29551
+ search: query.search
29552
+ });
29553
+ const bridgeResult = await requestJson(this.session, url);
29554
+ if (isAssetListResponse(bridgeResult)) return bridgeResult;
29555
+ const fallback = bridgeUrl(this.session, "/api/gallery/assets", {
29556
+ userId: this.session.userId,
29557
+ page: query.page ?? 1,
29558
+ limit: query.limit ?? 20,
29559
+ source: query.source,
29560
+ mediaType: query.mediaType,
29561
+ search: query.search
29562
+ });
29563
+ const fallbackResult = await requestJson(this.session, fallback);
29564
+ if (isAssetListResponse(fallbackResult)) return fallbackResult;
29565
+ throw new Error("Growthub bridge asset list did not return the asset contract.");
29566
+ }
29567
+ async listBrandKits(query = {}) {
29568
+ const url = bridgeUrl(this.session, "/api/brand-settings");
29569
+ const directResult = await requestJsonWithSessionCookie(this.session, url);
29570
+ if (!isRemoteBrandKitArray(directResult)) {
29571
+ throw new Error("Growthub brand settings endpoint did not return brand kits.");
29572
+ }
29573
+ const brandKits = directResult.brandKits;
29574
+ if (!query.includeAssets || brandKits.length === 0) {
29575
+ return {
29576
+ success: true,
29577
+ userId: this.session.userId,
29578
+ brandKits,
29579
+ count: brandKits.length
29580
+ };
29581
+ }
29582
+ const assetsResult = await this.listBrandAssets();
29583
+ const assetsByKitId = /* @__PURE__ */ new Map();
29584
+ for (const asset of assetsResult.assets) {
29585
+ const key = String(asset.brand_kit_id);
29586
+ assetsByKitId.set(key, [...assetsByKitId.get(key) ?? [], asset]);
29587
+ }
29588
+ return {
29589
+ success: true,
29590
+ userId: this.session.userId,
29591
+ brandKits: brandKits.map((kit) => ({
29592
+ ...kit,
29593
+ assets: assetsByKitId.get(String(kit.id)) ?? []
29594
+ })),
29595
+ count: brandKits.length
29596
+ };
29597
+ }
29598
+ async listBrandAssets(query = {}) {
29599
+ const url = bridgeUrl(this.session, "/api/brand-settings/assets", {
29600
+ brandKitId: query.brandKitId
29601
+ });
29602
+ const result = await requestJsonWithSessionCookie(this.session, url);
29603
+ if (!isRemoteBrandAssetArray(result)) {
29604
+ throw new Error("Growthub brand assets endpoint did not return brand assets.");
29605
+ }
29606
+ const assets2 = query.assetType ? result.assets.filter((asset) => asset.asset_type === query.assetType) : result.assets;
29607
+ return {
29608
+ success: true,
29609
+ userId: this.session.userId,
29610
+ brandKitId: query.brandKitId,
29611
+ assets: assets2,
29612
+ count: assets2.length
29613
+ };
29614
+ }
29615
+ async listKnowledge(query = {}) {
29616
+ const url = bridgeUrl(this.session, "/api/cli/profile", {
29617
+ view: "knowledge",
29618
+ type: query.type,
29619
+ agentSlug: query.agentSlug,
29620
+ tableId: query.tableId
29621
+ });
29622
+ const result = await requestJson(this.session, url);
29623
+ if (isKnowledgeListResponse(result)) return result;
29624
+ const providerUrl = bridgeUrl(this.session, "/api/providers/growthub-local/knowledge/items", {
29625
+ type: query.type,
29626
+ agentSlug: query.agentSlug,
29627
+ tableId: query.tableId
29628
+ });
29629
+ const providerResult = await requestJson(this.session, providerUrl);
29630
+ if (isKnowledgeListResponse(providerResult)) return providerResult;
29631
+ throw new Error("Growthub bridge knowledge list did not return the knowledge contract.");
29632
+ }
29633
+ async listKnowledgeTables(query = {}) {
29634
+ const url = bridgeUrl(this.session, "/api/cli/profile", {
29635
+ view: "knowledge-tables",
29636
+ origin: query.origin,
29637
+ connectorType: query.connectorType
29638
+ });
29639
+ const result = await requestJson(this.session, url);
29640
+ if (isKnowledgeTableListResponse(result)) return result;
29641
+ const providerUrl = bridgeUrl(this.session, "/api/providers/growthub-local/knowledge/tables", {
29642
+ origin: query.origin,
29643
+ connectorType: query.connectorType
29644
+ });
29645
+ const providerResult = await requestJson(this.session, providerUrl);
29646
+ if (isKnowledgeTableListResponse(providerResult)) return providerResult;
29647
+ throw new Error("Growthub bridge knowledge table list did not return the knowledge table contract.");
29648
+ }
29649
+ async saveKnowledge(input) {
29650
+ const url = bridgeUrl(this.session, "/api/cli/profile", { action: "save-knowledge" });
29651
+ const result = await requestJson(this.session, url, {
29652
+ method: "POST",
29653
+ body: JSON.stringify(input)
29654
+ });
29655
+ if (result && typeof result === "object" && "success" in result) {
29656
+ return result;
29657
+ }
29658
+ const providerUrl = bridgeUrl(this.session, "/api/providers/growthub-local/knowledge/items");
29659
+ const providerResult = await requestJson(this.session, providerUrl, {
29660
+ method: "POST",
29661
+ body: JSON.stringify(input)
29662
+ });
29663
+ if (providerResult && typeof providerResult === "object" && "success" in providerResult) {
29664
+ return providerResult;
29665
+ }
29666
+ throw new Error("Growthub bridge knowledge save did not return the knowledge save contract.");
29667
+ }
29668
+ deleteKnowledge(id) {
29669
+ const url = bridgeUrl(this.session, "/api/cli/profile", { action: "delete-knowledge" });
29670
+ return requestJson(this.session, url, {
29671
+ method: "POST",
29672
+ body: JSON.stringify({ id })
29673
+ });
29674
+ }
29675
+ updateKnowledgeMetadata(input) {
29676
+ const url = bridgeUrl(this.session, "/api/providers/growthub-local/knowledge/items/metadata");
29677
+ return requestJson(this.session, url, {
29678
+ method: "PATCH",
29679
+ body: JSON.stringify(input)
29680
+ });
29681
+ }
29682
+ syncRunOutput(input) {
29683
+ const url = bridgeUrl(this.session, "/api/providers/growthub-local/runs/sync");
29684
+ return requestJson(this.session, url, {
29685
+ method: "POST",
29686
+ body: JSON.stringify(input)
29687
+ });
29688
+ }
29689
+ listMcpAccounts() {
29690
+ const url = bridgeUrl(this.session, "/api/mcp/accounts");
29691
+ return requestJson(this.session, url);
29692
+ }
29693
+ async downloadStoragePath(storagePath, outPath, bucket = "node_documents") {
29694
+ const url = bridgeUrl(this.session, "/api/secure-image", { bucket, path: storagePath });
29695
+ const response = await fetch(url, {
29696
+ headers: {
29697
+ authorization: `Bearer ${this.session.accessToken}`,
29698
+ "x-user-id": this.session.userId ?? ""
29699
+ }
29700
+ });
29701
+ if (!response.ok) {
29702
+ throw new Error(`Authenticated artifact download failed (${response.status}).`);
29703
+ }
29704
+ const buffer = Buffer.from(await response.arrayBuffer());
29705
+ fs41.mkdirSync(path49.dirname(path49.resolve(outPath)), { recursive: true });
29706
+ fs41.writeFileSync(path49.resolve(outPath), buffer);
29707
+ return buffer.length;
29708
+ }
29709
+ async downloadKnowledge(id, outPath) {
29710
+ const url = bridgeUrl(this.session, "/api/cli/profile", { view: "knowledge-download", id });
29711
+ const response = await fetch(url, {
29712
+ headers: {
29713
+ authorization: `Bearer ${this.session.accessToken}`,
29714
+ "x-user-id": this.session.userId ?? ""
29715
+ }
29716
+ });
29717
+ if (!response.ok) {
29718
+ throw new Error(`Knowledge download failed (${response.status}).`);
29719
+ }
29720
+ const buffer = Buffer.from(await response.arrayBuffer());
29721
+ fs41.mkdirSync(path49.dirname(path49.resolve(outPath)), { recursive: true });
29722
+ fs41.writeFileSync(path49.resolve(outPath), buffer);
29723
+ return buffer.length;
29724
+ }
29725
+ };
29726
+ function isAssetListResponse(value) {
29727
+ return Boolean(
29728
+ value && typeof value === "object" && Array.isArray(value.assets) && typeof value.pagination?.total === "number"
29729
+ );
29730
+ }
29731
+ function isRemoteBrandKitArray(value) {
29732
+ return Boolean(
29733
+ value && typeof value === "object" && Array.isArray(value.brandKits)
29734
+ );
29735
+ }
29736
+ function isRemoteBrandAssetArray(value) {
29737
+ return Boolean(
29738
+ value && typeof value === "object" && Array.isArray(value.assets)
29739
+ );
29740
+ }
29741
+ function isKnowledgeListResponse(value) {
29742
+ return Boolean(
29743
+ value && typeof value === "object" && Array.isArray(value.items) && typeof value.count === "number"
29744
+ );
29745
+ }
29746
+ function isKnowledgeTableListResponse(value) {
29747
+ return Boolean(
29748
+ value && typeof value === "object" && Array.isArray(value.tables) && typeof value.count === "number"
29749
+ );
29750
+ }
29751
+ function createGrowthubBridgeClient() {
29752
+ return new GrowthubBridgeClient();
29753
+ }
29754
+
29755
+ // src/commands/bridge.ts
29756
+ function printRows(rows, keys) {
29757
+ for (const row of rows) {
29758
+ console.log(keys.map((key) => `${pc37.dim(`${key}:`)} ${String(row[key] ?? "")}`).join(" "));
29759
+ }
29760
+ }
29761
+ function outPathFromStorage(storagePath, out) {
29762
+ return path50.resolve(out?.trim() || path50.basename(storagePath));
29763
+ }
29764
+ function registerBridgeCommands(program2) {
29765
+ const bridge = program2.command("bridge").description("Authenticated Growthub bridge resources: assets, knowledge, and MCP accounts.");
29766
+ const assets2 = bridge.command("assets").description("User asset gallery through the Growthub bridge.");
29767
+ assets2.command("list").description("List user-owned gallery assets.").option("--page <page>", "Page number", (value) => Number(value), 1).option("--limit <limit>", "Page size", (value) => Number(value), 20).option("--source <source>", "Source filter").option("--media-type <type>", "Media type filter").option("--search <query>", "Filename/source search").option("--json", "Output raw JSON").action(async (opts) => {
29768
+ const client = createGrowthubBridgeClient();
29769
+ const result = await client.listAssets({
29770
+ page: opts.page,
29771
+ limit: opts.limit,
29772
+ source: opts.source,
29773
+ mediaType: opts.mediaType,
29774
+ search: opts.search
29775
+ });
29776
+ if (opts.json) {
29777
+ console.log(JSON.stringify(result, null, 2));
29778
+ return;
29779
+ }
29780
+ console.log(pc37.bold(`Growthub assets (${result.assets.length}/${result.pagination.total})`));
29781
+ printRows(result.assets.map((asset) => ({
29782
+ id: asset.id,
29783
+ type: asset.type,
29784
+ source: asset.source,
29785
+ storage: asset.storage_path
29786
+ })), ["id", "type", "source", "storage"]);
29787
+ });
29788
+ assets2.command("download").description("Download a user-owned gallery asset by storage path.").requiredOption("--storage-path <path>", "Asset storage path from bridge assets list").option("--bucket <bucket>", "Storage bucket", "node_documents").option("--out <path>", "Output file path").option("--json", "Output raw JSON").action(async (opts) => {
29789
+ const client = createGrowthubBridgeClient();
29790
+ const outPath = outPathFromStorage(opts.storagePath, opts.out);
29791
+ const bytes = await client.downloadStoragePath(opts.storagePath, outPath, opts.bucket);
29792
+ const payload = { success: true, storagePath: opts.storagePath, bucket: opts.bucket, outPath, bytes };
29793
+ if (opts.json) console.log(JSON.stringify(payload, null, 2));
29794
+ else console.log(`${pc37.green("Downloaded")} ${outPath} (${bytes} bytes)`);
29795
+ });
29796
+ const brand = bridge.command("brand").description("User brand kits and brand assets through the Growthub bridge.");
29797
+ brand.command("kits").description("List accessible remote brand kits.").option("--include-assets", "Include each brand kit's assets").option("--json", "Output raw JSON").action(async (opts) => {
29798
+ const client = createGrowthubBridgeClient();
29799
+ const result = await client.listBrandKits({ includeAssets: opts.includeAssets === true });
29800
+ if (opts.json) {
29801
+ console.log(JSON.stringify(result, null, 2));
29802
+ return;
29803
+ }
29804
+ console.log(pc37.bold(`Growthub brand kits (${result.count})`));
29805
+ printRows(result.brandKits.map((kit) => ({
29806
+ id: kit.id,
29807
+ name: kit.brand_name,
29808
+ visibility: kit.visibility,
29809
+ assets: kit.assets?.length ?? ""
29810
+ })), ["id", "name", "visibility", "assets"]);
29811
+ });
29812
+ brand.command("assets").description("List remote brand assets from accessible brand kits.").option("--brand-kit-id <id>", "Filter by brand kit id").option("--asset-type <type>", "Filter by asset type").option("--json", "Output raw JSON").action(async (opts) => {
29813
+ const client = createGrowthubBridgeClient();
29814
+ const result = await client.listBrandAssets({ brandKitId: opts.brandKitId, assetType: opts.assetType });
29815
+ if (opts.json) {
29816
+ console.log(JSON.stringify(result, null, 2));
29817
+ return;
29818
+ }
29819
+ console.log(pc37.bold(`Growthub brand assets (${result.count})`));
29820
+ printRows(result.assets.map((asset) => ({
29821
+ id: asset.id,
29822
+ kit: asset.brand_kit_id,
29823
+ type: asset.asset_type,
29824
+ storage: asset.storage_path
29825
+ })), ["id", "kit", "type", "storage"]);
29826
+ });
29827
+ brand.command("download").description("Download a remote brand asset by storage path.").requiredOption("--storage-path <path>", "Brand asset storage path from bridge brand assets").option("--bucket <bucket>", "Storage bucket", "node_documents").option("--out <path>", "Output file path").option("--json", "Output raw JSON").action(async (opts) => {
29828
+ const client = createGrowthubBridgeClient();
29829
+ const outPath = outPathFromStorage(opts.storagePath, opts.out);
29830
+ const bytes = await client.downloadStoragePath(opts.storagePath, outPath, opts.bucket);
29831
+ const payload = { success: true, storagePath: opts.storagePath, bucket: opts.bucket, outPath, bytes };
29832
+ if (opts.json) console.log(JSON.stringify(payload, null, 2));
29833
+ else console.log(`${pc37.green("Downloaded")} ${outPath} (${bytes} bytes)`);
29834
+ });
29835
+ const knowledge = bridge.command("knowledge").description("User knowledge items through the Growthub bridge.");
29836
+ knowledge.command("tables").description("List user-owned knowledge tables, the custom groupings for knowledge items.").option("--origin <origin>", "Filter by metadata.origin").option("--connector-type <type>", "Filter by metadata.connector_type").option("--json", "Output raw JSON").action(async (opts) => {
29837
+ const client = createGrowthubBridgeClient();
29838
+ const result = await client.listKnowledgeTables({ origin: opts.origin, connectorType: opts.connectorType });
29839
+ if (opts.json) {
29840
+ console.log(JSON.stringify(result, null, 2));
29841
+ return;
29842
+ }
29843
+ console.log(pc37.bold(`Growthub knowledge tables (${result.count})`));
29844
+ printRows(result.tables.map((table) => ({
29845
+ id: table.id,
29846
+ file: table.file_name,
29847
+ origin: table.metadata?.origin,
29848
+ children: table.child_count ?? 0
29849
+ })), ["id", "file", "origin", "children"]);
29850
+ });
29851
+ knowledge.command("list").description("List user-owned knowledge items.").option("--type <type>", "Knowledge source type").option("--agent-slug <slug>", "Agent slug filter").option("--table-id <id>", "Filter by metadata.table_id knowledge table grouping").option("--json", "Output raw JSON").action(async (opts) => {
29852
+ const client = createGrowthubBridgeClient();
29853
+ const result = await client.listKnowledge({ type: opts.type, agentSlug: opts.agentSlug, tableId: opts.tableId });
29854
+ if (opts.json) {
29855
+ console.log(JSON.stringify(result, null, 2));
29856
+ return;
29857
+ }
29858
+ console.log(pc37.bold(`Growthub knowledge (${result.count})`));
29859
+ printRows(result.items.map((item) => ({
29860
+ id: item.id,
29861
+ file: item.file_name,
29862
+ type: item.source_type,
29863
+ storage: item.storage_path
29864
+ })), ["id", "file", "type", "storage"]);
29865
+ });
29866
+ knowledge.command("write").description("Create or update a markdown knowledge item.").option("--id <id>", "Existing knowledge item id to update").option("--title <title>", "Title for a new item").option("--file-name <name>", "File name for an update").option("--content <content>", "Markdown content for a new item").option("--table-id <id>", "Attach new item to metadata.table_id knowledge table grouping").option("--notes <notes>", "Notes metadata").option("--agent-slug <slug>", "Agent slug", "growthub-cli").option("--json", "Output raw JSON").action(async (opts) => {
29867
+ const client = createGrowthubBridgeClient();
29868
+ const result = await client.saveKnowledge({
29869
+ id: opts.id,
29870
+ title: opts.title,
29871
+ fileName: opts.fileName,
29872
+ content: opts.content,
29873
+ tableId: opts.tableId,
29874
+ notes: opts.notes,
29875
+ agentSlug: opts.agentSlug
29876
+ });
29877
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
29878
+ else console.log(result.success ? pc37.green("Knowledge saved") : pc37.red(result.error ?? "Knowledge save failed"));
29879
+ });
29880
+ knowledge.command("download").description("Download a knowledge item by id.").argument("<id>", "Knowledge item id").requiredOption("--out <path>", "Output file path").option("--json", "Output raw JSON").action(async (id, opts) => {
29881
+ const client = createGrowthubBridgeClient();
29882
+ const outPath = path50.resolve(opts.out);
29883
+ const bytes = await client.downloadKnowledge(id, outPath);
29884
+ const payload = { success: true, id, outPath, bytes };
29885
+ if (opts.json) console.log(JSON.stringify(payload, null, 2));
29886
+ else console.log(`${pc37.green("Downloaded")} ${outPath} (${bytes} bytes)`);
29887
+ });
29888
+ knowledge.command("delete").description("Delete a knowledge item by id.").argument("<id>", "Knowledge item id").option("--json", "Output raw JSON").action(async (id, opts) => {
29889
+ const client = createGrowthubBridgeClient();
29890
+ const result = await client.deleteKnowledge(id);
29891
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
29892
+ else console.log(result.success ? pc37.green("Knowledge deleted") : pc37.red(result.error ?? "Knowledge delete failed"));
29893
+ });
29894
+ knowledge.command("metadata").description("Patch metadata for an existing knowledge item.").argument("<id>", "Knowledge item id").option("--table-id <id>", "Set metadata.table_id").option("--notes <notes>", "Set metadata.notes").option("--json", "Output raw JSON").action(async (id, opts) => {
29895
+ const client = createGrowthubBridgeClient();
29896
+ const result = await client.updateKnowledgeMetadata({ id, tableId: opts.tableId, notes: opts.notes });
29897
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
29898
+ else console.log(result.success ? pc37.green("Knowledge metadata updated") : pc37.red(result.error ?? "Knowledge metadata update failed"));
29899
+ });
29900
+ bridge.command("run-sync").description("Persist a local run output into the remote Growthub knowledge substrate.").option("--run-id <id>", "Run id").option("--title <title>", "Knowledge item title").option("--output <json>", "JSON output payload").option("--table-id <id>", "Attach to metadata.table_id").option("--agent-slug <slug>", "Agent slug", "growthub_local_bridge").option("--json", "Output raw JSON").action(async (opts) => {
29901
+ const client = createGrowthubBridgeClient();
29902
+ const parsedOutput = opts.output ? JSON.parse(opts.output) : {};
29903
+ const result = await client.syncRunOutput({
29904
+ runId: opts.runId,
29905
+ title: opts.title,
29906
+ output: parsedOutput,
29907
+ tableId: opts.tableId,
29908
+ agentSlug: opts.agentSlug
29909
+ });
29910
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
29911
+ else console.log(result.success ? pc37.green("Run output synced") : pc37.red(result.error ?? "Run output sync failed"));
29912
+ });
29913
+ const mcp = bridge.command("mcp").description("MCP bridge accounts.");
29914
+ mcp.command("accounts").description("List connected MCP accounts.").option("--json", "Output raw JSON").action(async (opts) => {
29915
+ const client = createGrowthubBridgeClient();
29916
+ const result = await client.listMcpAccounts();
29917
+ if (opts.json) {
29918
+ console.log(JSON.stringify(result, null, 2));
29919
+ return;
29920
+ }
29921
+ console.log(pc37.bold(`Growthub MCP accounts (${result.accounts.length})`));
29922
+ printRows(result.accounts.map((account) => ({
29923
+ id: account.id,
29924
+ provider: account.provider,
29925
+ app: account.appSlug,
29926
+ active: account.isActive
29927
+ })), ["id", "provider", "app", "active"]);
29928
+ });
29078
29929
  }
29079
29930
 
29080
29931
  // src/commands/workflow.ts
29081
- import fs40 from "node:fs";
29082
- import path48 from "node:path";
29932
+ import fs43 from "node:fs";
29933
+ import path52 from "node:path";
29083
29934
  import * as p24 from "@clack/prompts";
29084
- import pc38 from "picocolors";
29935
+ import pc39 from "picocolors";
29085
29936
  init_session_store();
29086
29937
  init_hosted_client();
29087
29938
 
29088
29939
  // src/runtime/workflow-hygiene/labels.ts
29089
29940
  init_home();
29090
- import fs39 from "node:fs";
29091
- import path47 from "node:path";
29941
+ import fs42 from "node:fs";
29942
+ import path51 from "node:path";
29092
29943
  function resolveStorePath() {
29093
- return path47.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "labels.json");
29944
+ return path51.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "labels.json");
29094
29945
  }
29095
29946
  function readStoreFile(filePath) {
29096
- if (!fs39.existsSync(filePath)) return { records: [] };
29947
+ if (!fs42.existsSync(filePath)) return { records: [] };
29097
29948
  try {
29098
- const raw = JSON.parse(fs39.readFileSync(filePath, "utf-8"));
29949
+ const raw = JSON.parse(fs42.readFileSync(filePath, "utf-8"));
29099
29950
  if (!Array.isArray(raw.records)) return { records: [] };
29100
29951
  return raw;
29101
29952
  } catch {
@@ -29103,8 +29954,8 @@ function readStoreFile(filePath) {
29103
29954
  }
29104
29955
  }
29105
29956
  function writeStoreFile(filePath, data) {
29106
- fs39.mkdirSync(path47.dirname(filePath), { recursive: true });
29107
- fs39.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}
29957
+ fs42.mkdirSync(path51.dirname(filePath), { recursive: true });
29958
+ fs42.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}
29108
29959
  `, "utf-8");
29109
29960
  }
29110
29961
  function inferDefaultLabel(name, createdAt, versionCount) {
@@ -29146,11 +29997,11 @@ function createWorkflowHygieneStore() {
29146
29997
  }
29147
29998
 
29148
29999
  // src/runtime/workflow-hygiene/summaries.ts
29149
- import pc37 from "picocolors";
30000
+ import pc38 from "picocolors";
29150
30001
  function renderWorkflowLabel(label) {
29151
- if (label === "canonical") return pc37.green("canonical");
29152
- if (label === "archived") return pc37.dim("archived");
29153
- return pc37.yellow("experimental");
30002
+ if (label === "canonical") return pc38.green("canonical");
30003
+ if (label === "archived") return pc38.dim("archived");
30004
+ return pc38.yellow("experimental");
29154
30005
  }
29155
30006
  function enrichWorkflowSummaries(entries, store) {
29156
30007
  return entries.map((entry) => {
@@ -29164,14 +30015,14 @@ init_banner();
29164
30015
  init_home();
29165
30016
  var PAGE_SIZE = 10;
29166
30017
  var FAMILY_CONFIG2 = {
29167
- video: { color: pc38.magenta, label: "Video" },
29168
- image: { color: pc38.cyan, label: "Image" },
29169
- slides: { color: pc38.yellow, label: "Slides" },
29170
- text: { color: pc38.green, label: "Text" },
29171
- data: { color: pc38.blue, label: "Data" },
29172
- ops: { color: pc38.red, label: "Ops" },
29173
- research: { color: pc38.blue, label: "Research" },
29174
- vision: { color: pc38.cyan, label: "Vision" }
30018
+ video: { color: pc39.magenta, label: "Video" },
30019
+ image: { color: pc39.cyan, label: "Image" },
30020
+ slides: { color: pc39.yellow, label: "Slides" },
30021
+ text: { color: pc39.green, label: "Text" },
30022
+ data: { color: pc39.blue, label: "Data" },
30023
+ ops: { color: pc39.red, label: "Ops" },
30024
+ research: { color: pc39.blue, label: "Research" },
30025
+ vision: { color: pc39.cyan, label: "Vision" }
29175
30026
  };
29176
30027
  var FAMILY_EMOJI = {
29177
30028
  video: "\u{1F3AC}",
@@ -29188,7 +30039,7 @@ function familyLabel(family) {
29188
30039
  return cfg ? cfg.color(cfg.label) : family;
29189
30040
  }
29190
30041
  function hr8(width = 72) {
29191
- return pc38.dim("\u2500".repeat(width));
30042
+ return pc39.dim("\u2500".repeat(width));
29192
30043
  }
29193
30044
  function stripAnsi6(str) {
29194
30045
  return str.replace(/\x1B\[[0-9;]*m/g, "");
@@ -29196,25 +30047,25 @@ function stripAnsi6(str) {
29196
30047
  function box5(lines) {
29197
30048
  const padded = lines.map((l) => " " + l);
29198
30049
  const width = Math.max(...padded.map((l) => stripAnsi6(l).length)) + 4;
29199
- const top = pc38.dim("\u250C" + "\u2500".repeat(width) + "\u2510");
29200
- const bottom = pc38.dim("\u2514" + "\u2500".repeat(width) + "\u2518");
30050
+ const top = pc39.dim("\u250C" + "\u2500".repeat(width) + "\u2510");
30051
+ const bottom = pc39.dim("\u2514" + "\u2500".repeat(width) + "\u2518");
29201
30052
  const body = padded.map((l) => {
29202
30053
  const pad2 = width - stripAnsi6(l).length;
29203
- return pc38.dim("\u2502") + l + " ".repeat(pad2) + pc38.dim("\u2502");
30054
+ return pc39.dim("\u2502") + l + " ".repeat(pad2) + pc39.dim("\u2502");
29204
30055
  });
29205
30056
  return [top, ...body, bottom].join("\n");
29206
30057
  }
29207
30058
  function resolveSavedWorkflowsDir() {
29208
- return path48.resolve(resolvePaperclipHomeDir(), "workflows");
30059
+ return path52.resolve(resolvePaperclipHomeDir(), "workflows");
29209
30060
  }
29210
30061
  function resolveDeletedWorkflowIdsPath() {
29211
- return path48.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "deleted-workflows.json");
30062
+ return path52.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "deleted-workflows.json");
29212
30063
  }
29213
30064
  function readDeletedWorkflowIds() {
29214
30065
  const filePath = resolveDeletedWorkflowIdsPath();
29215
- if (!fs40.existsSync(filePath)) return /* @__PURE__ */ new Set();
30066
+ if (!fs43.existsSync(filePath)) return /* @__PURE__ */ new Set();
29216
30067
  try {
29217
- const raw = JSON.parse(fs40.readFileSync(filePath, "utf-8"));
30068
+ const raw = JSON.parse(fs43.readFileSync(filePath, "utf-8"));
29218
30069
  if (!Array.isArray(raw?.workflowIds)) return /* @__PURE__ */ new Set();
29219
30070
  return new Set(raw.workflowIds.filter((value) => typeof value === "string"));
29220
30071
  } catch {
@@ -29223,8 +30074,8 @@ function readDeletedWorkflowIds() {
29223
30074
  }
29224
30075
  function writeDeletedWorkflowIds(ids) {
29225
30076
  const filePath = resolveDeletedWorkflowIdsPath();
29226
- fs40.mkdirSync(path48.dirname(filePath), { recursive: true });
29227
- fs40.writeFileSync(filePath, `${JSON.stringify({ workflowIds: [...ids] }, null, 2)}
30077
+ fs43.mkdirSync(path52.dirname(filePath), { recursive: true });
30078
+ fs43.writeFileSync(filePath, `${JSON.stringify({ workflowIds: [...ids] }, null, 2)}
29228
30079
  `, "utf-8");
29229
30080
  }
29230
30081
  function markWorkflowDeletedLocally(workflowId) {
@@ -29250,10 +30101,10 @@ function filterLocallyDeletedWorkflows(entries) {
29250
30101
  }
29251
30102
  function listLocalSavedWorkflows() {
29252
30103
  const dir = resolveSavedWorkflowsDir();
29253
- if (!fs40.existsSync(dir)) return [];
29254
- const entries = fs40.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
30104
+ if (!fs43.existsSync(dir)) return [];
30105
+ const entries = fs43.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
29255
30106
  try {
29256
- const raw = JSON.parse(fs40.readFileSync(path48.resolve(dir, e.name), "utf-8"));
30107
+ const raw = JSON.parse(fs43.readFileSync(path52.resolve(dir, e.name), "utf-8"));
29257
30108
  const pipeline = raw.pipeline ?? raw;
29258
30109
  return {
29259
30110
  filename: e.name,
@@ -29314,11 +30165,11 @@ async function archiveSavedWorkflow(entry) {
29314
30165
  throw new Error("Local workflow entry is missing filename.");
29315
30166
  }
29316
30167
  const dir = resolveSavedWorkflowsDir();
29317
- const archiveDir = path48.resolve(dir, "archived");
29318
- fs40.mkdirSync(archiveDir, { recursive: true });
29319
- fs40.renameSync(
29320
- path48.resolve(dir, entry.filename),
29321
- path48.resolve(archiveDir, entry.filename)
30168
+ const archiveDir = path52.resolve(dir, "archived");
30169
+ fs43.mkdirSync(archiveDir, { recursive: true });
30170
+ fs43.renameSync(
30171
+ path52.resolve(dir, entry.filename),
30172
+ path52.resolve(archiveDir, entry.filename)
29322
30173
  );
29323
30174
  }
29324
30175
  async function deleteSavedWorkflow(entry) {
@@ -29342,7 +30193,7 @@ async function deleteSavedWorkflow(entry) {
29342
30193
  if (!entry.filename) {
29343
30194
  throw new Error("Local workflow entry is missing filename.");
29344
30195
  }
29345
- fs40.rmSync(path48.resolve(resolveSavedWorkflowsDir(), entry.filename), { force: true });
30196
+ fs43.rmSync(path52.resolve(resolveSavedWorkflowsDir(), entry.filename), { force: true });
29346
30197
  markWorkflowDeletedLocally(entry.workflowId);
29347
30198
  }
29348
30199
  async function loadSavedWorkflowDetail(entry) {
@@ -29361,7 +30212,7 @@ async function loadSavedWorkflowDetail(entry) {
29361
30212
  };
29362
30213
  }
29363
30214
  const dir = resolveSavedWorkflowsDir();
29364
- const content = fs40.readFileSync(path48.resolve(dir, entry.filename), "utf-8");
30215
+ const content = fs43.readFileSync(path52.resolve(dir, entry.filename), "utf-8");
29365
30216
  const raw = JSON.parse(content);
29366
30217
  return {
29367
30218
  pipeline: raw.pipeline ?? raw,
@@ -29431,7 +30282,7 @@ async function paginatedSelect(message, allOptions, opts) {
29431
30282
  const hasPrev = offset > 0;
29432
30283
  const totalPages = Math.ceil(filtered.length / PAGE_SIZE);
29433
30284
  const currentPage = Math.floor(offset / PAGE_SIZE) + 1;
29434
- const pageInfo = filtered.length > PAGE_SIZE ? pc38.dim(` (${currentPage}/${totalPages} \xB7 ${filtered.length} total)`) : "";
30285
+ const pageInfo = filtered.length > PAGE_SIZE ? pc39.dim(` (${currentPage}/${totalPages} \xB7 ${filtered.length} total)`) : "";
29435
30286
  const options = [
29436
30287
  ...page.map((o) => ({
29437
30288
  value: o.value,
@@ -29440,13 +30291,13 @@ async function paginatedSelect(message, allOptions, opts) {
29440
30291
  }))
29441
30292
  ];
29442
30293
  if (hasMore) {
29443
- options.push({ value: "__next_page", label: pc38.dim("\u2192 Next page") });
30294
+ options.push({ value: "__next_page", label: pc39.dim("\u2192 Next page") });
29444
30295
  }
29445
30296
  if (hasPrev) {
29446
- options.push({ value: "__prev_page", label: pc38.dim("\u2190 Previous page") });
30297
+ options.push({ value: "__prev_page", label: pc39.dim("\u2190 Previous page") });
29447
30298
  }
29448
30299
  if (opts?.searchEnabled) {
29449
- options.push({ value: "__search", label: pc38.dim("\u{1F50E} Search") });
30300
+ options.push({ value: "__search", label: pc39.dim("\u{1F50E} Search") });
29450
30301
  }
29451
30302
  options.push({
29452
30303
  value: opts?.backValue ?? "__back",
@@ -29494,8 +30345,8 @@ async function paginatedSelect(message, allOptions, opts) {
29494
30345
  function printTemplateCard(node) {
29495
30346
  const contract = introspectNodeContract(node);
29496
30347
  const lines = renderContractCard(contract);
29497
- lines.splice(1, 0, `${familyLabel(node.family)} ${node.enabled ? pc38.green("enabled") : pc38.red("disabled")}`);
29498
- if (node.description) lines.push("", pc38.dim(node.description));
30348
+ lines.splice(1, 0, `${familyLabel(node.family)} ${node.enabled ? pc39.green("enabled") : pc39.red("disabled")}`);
30349
+ if (node.description) lines.push("", pc39.dim(node.description));
29499
30350
  console.log("");
29500
30351
  console.log(box5(lines));
29501
30352
  console.log("");
@@ -29509,9 +30360,9 @@ function renderTemplateTree(templates) {
29509
30360
  byFamily.set(key, existing);
29510
30361
  }
29511
30362
  const families = [...byFamily.entries()].sort((a, b) => a[0].localeCompare(b[0]));
29512
- const lines = [pc38.bold("Public CMS Node Tree")];
30363
+ const lines = [pc39.bold("Public CMS Node Tree")];
29513
30364
  for (const [family, nodes] of families) {
29514
- lines.push(`${pc38.cyan("\u2022")} ${pc38.bold(family)}`);
30365
+ lines.push(`${pc39.cyan("\u2022")} ${pc39.bold(family)}`);
29515
30366
  const sorted = [...nodes].sort((a, b) => a.slug.localeCompare(b.slug));
29516
30367
  for (const [index51, node] of sorted.entries()) {
29517
30368
  const branch = index51 === sorted.length - 1 ? "\u2514\u2500" : "\u251C\u2500";
@@ -29519,12 +30370,12 @@ function renderTemplateTree(templates) {
29519
30370
  const requiredInputs = contract.inputs.filter((input) => input.required).length;
29520
30371
  const optionalInputs = contract.inputs.length - requiredInputs;
29521
30372
  lines.push(
29522
- ` ${branch} ${node.slug} ${pc38.dim(`(req:${requiredInputs} opt:${optionalInputs} out:${contract.outputTypes.length})`)}`
30373
+ ` ${branch} ${node.slug} ${pc39.dim(`(req:${requiredInputs} opt:${optionalInputs} out:${contract.outputTypes.length})`)}`
29523
30374
  );
29524
30375
  }
29525
30376
  }
29526
30377
  lines.push("");
29527
- lines.push(pc38.dim("Shortcut: growthub workflow saved --json"));
30378
+ lines.push(pc39.dim("Shortcut: growthub workflow saved --json"));
29528
30379
  return lines;
29529
30380
  }
29530
30381
  function renderWorkflowContractDiscoveryTree(nodes) {
@@ -29536,10 +30387,10 @@ function renderWorkflowContractDiscoveryTree(nodes) {
29536
30387
  byFamily.set(key, group);
29537
30388
  }
29538
30389
  const families = [...byFamily.entries()].sort((a, b) => a[0].localeCompare(b[0]));
29539
- const lines = [pc38.bold("CMS Node Contract Discovery")];
30390
+ const lines = [pc39.bold("CMS Node Contract Discovery")];
29540
30391
  for (const [family, familyNodes] of families) {
29541
30392
  const emoji = FAMILY_EMOJI[family] ?? "\u2022";
29542
- lines.push(`${emoji} ${pc38.bold(familyLabel(family))} ${pc38.dim(`(${familyNodes.length})`)}`);
30393
+ lines.push(`${emoji} ${pc39.bold(familyLabel(family))} ${pc39.dim(`(${familyNodes.length})`)}`);
29543
30394
  const sorted = [...familyNodes].sort((a, b) => a.slug.localeCompare(b.slug));
29544
30395
  for (const [index51, node] of sorted.entries()) {
29545
30396
  const branch = index51 === sorted.length - 1 ? "\u2514\u2500" : "\u251C\u2500";
@@ -29547,7 +30398,7 @@ function renderWorkflowContractDiscoveryTree(nodes) {
29547
30398
  const requiredInputs = contract.inputs.filter((input) => input.required).length;
29548
30399
  const optionalInputs = contract.inputs.length - requiredInputs;
29549
30400
  lines.push(
29550
- ` ${branch} ${node.slug} ${pc38.dim(`req:${requiredInputs} opt:${optionalInputs} bindings:${contract.requiredBindings.length} outputs:${contract.outputTypes.length}`)}`
30401
+ ` ${branch} ${node.slug} ${pc39.dim(`req:${requiredInputs} opt:${optionalInputs} bindings:${contract.requiredBindings.length} outputs:${contract.outputTypes.length}`)}`
29551
30402
  );
29552
30403
  }
29553
30404
  }
@@ -29560,7 +30411,7 @@ function buildTemplateOption(template, viewMode) {
29560
30411
  if (viewMode === "expanded") {
29561
30412
  return {
29562
30413
  value: template.slug,
29563
- label: `${template.icon} ${template.displayName} ${pc38.dim(template.slug)}`,
30414
+ label: `${template.icon} ${template.displayName} ${pc39.dim(template.slug)}`,
29564
30415
  hint: `req:${requiredInputs} opt:${optionalInputs} outputs:${contract.outputTypes.join(", ") || "none"} exec:${contract.executionStrategy}`
29565
30416
  };
29566
30417
  }
@@ -29582,11 +30433,11 @@ async function runWorkflowPicker(opts) {
29582
30433
  const hygieneStore = createWorkflowHygieneStore();
29583
30434
  const access = getWorkflowAccess();
29584
30435
  if (access.state === "unauthenticated") {
29585
- p24.intro(pc38.bold("Workflows") + pc38.dim(" (not connected)"));
30436
+ p24.intro(pc39.bold("Workflows") + pc39.dim(" (not connected)"));
29586
30437
  p24.note(
29587
30438
  [
29588
30439
  "Workflow assembly requires an authenticated Growthub session.",
29589
- "Run " + pc38.cyan("growthub auth login") + " to connect your account.",
30440
+ "Run " + pc39.cyan("growthub auth login") + " to connect your account.",
29590
30441
  "",
29591
30442
  "Once connected you can:",
29592
30443
  " - Browse CMS node contracts",
@@ -29598,7 +30449,7 @@ async function runWorkflowPicker(opts) {
29598
30449
  if (opts.allowBackToHub) return "back";
29599
30450
  return "done";
29600
30451
  }
29601
- p24.intro(pc38.bold("Workflows"));
30452
+ p24.intro(pc39.bold("Workflows"));
29602
30453
  while (true) {
29603
30454
  const refreshedAccess = getWorkflowAccess();
29604
30455
  const topChoice = await p24.select({
@@ -29606,12 +30457,12 @@ async function runWorkflowPicker(opts) {
29606
30457
  options: [
29607
30458
  {
29608
30459
  value: "contracts",
29609
- label: refreshedAccess.state === "ready" ? "0. CMS Node Contracts" : pc38.dim("0. CMS Node Contracts (locked)"),
30460
+ label: refreshedAccess.state === "ready" ? "0. CMS Node Contracts" : pc39.dim("0. CMS Node Contracts (locked)"),
29610
30461
  hint: refreshedAccess.state === "ready" ? "Discovery tree for CMS node primitives" : refreshedAccess.reason
29611
30462
  },
29612
30463
  {
29613
30464
  value: "pipelines",
29614
- label: refreshedAccess.state === "ready" ? "1. Dynamic Pipelines" : pc38.dim("1. Dynamic Pipelines (locked)"),
30465
+ label: refreshedAccess.state === "ready" ? "1. Dynamic Pipelines" : pc39.dim("1. Dynamic Pipelines (locked)"),
29615
30466
  hint: refreshedAccess.state === "ready" ? "Create new pipelines and route into Saved Workflows" : refreshedAccess.reason
29616
30467
  },
29617
30468
  {
@@ -29678,7 +30529,7 @@ async function runWorkflowPicker(opts) {
29678
30529
  const requiredInputs = contract.inputs.filter((input) => input.required).length;
29679
30530
  return {
29680
30531
  value: node.slug,
29681
- label: `${node.icon} ${node.displayName} ${pc38.dim(node.slug)}`,
30532
+ label: `${node.icon} ${node.displayName} ${pc39.dim(node.slug)}`,
29682
30533
  hint: `${node.family} \xB7 required:${requiredInputs} \xB7 bindings:${contract.requiredBindings.length} \xB7 outputs:${contract.outputTypes.length}`
29683
30534
  };
29684
30535
  });
@@ -29719,7 +30570,7 @@ async function runWorkflowPicker(opts) {
29719
30570
  }
29720
30571
  }
29721
30572
  } catch (err) {
29722
- contractsSpinner.stop(pc38.red("Failed to load CMS node contracts."));
30573
+ contractsSpinner.stop(pc39.red("Failed to load CMS node contracts."));
29723
30574
  p24.log.error("Failed to load CMS node contracts: " + err.message);
29724
30575
  }
29725
30576
  continue;
@@ -29754,14 +30605,14 @@ async function runWorkflowPicker(opts) {
29754
30605
  saved = withEffectiveWorkflowLabels(enriched, hygieneStore);
29755
30606
  savedSpinner.stop(`Loaded ${saved.length} saved workflow${saved.length === 1 ? "" : "s"}.`);
29756
30607
  } catch (err) {
29757
- savedSpinner.stop(pc38.red("Failed to load saved workflows."));
30608
+ savedSpinner.stop(pc39.red("Failed to load saved workflows."));
29758
30609
  throw err;
29759
30610
  }
29760
30611
  if (saved.length === 0) {
29761
30612
  p24.note(
29762
30613
  [
29763
30614
  "No saved workflows found.",
29764
- "Use " + pc38.cyan("growthub pipeline assemble") + " to create a new workflow pipeline."
30615
+ "Use " + pc39.cyan("growthub pipeline assemble") + " to create a new workflow pipeline."
29765
30616
  ].join("\n"),
29766
30617
  "Nothing saved"
29767
30618
  );
@@ -29769,7 +30620,7 @@ async function runWorkflowPicker(opts) {
29769
30620
  }
29770
30621
  const allOptions = saved.map((w) => ({
29771
30622
  value: w.workflowId,
29772
- label: `${w.name} ${pc38.dim(`[${renderWorkflowLabel(w.workflowLabel)}]`)} ${pc38.dim(`${w.nodeCount} node${w.nodeCount !== 1 ? "s" : ""}`)}`,
30623
+ label: `${w.name} ${pc39.dim(`[${renderWorkflowLabel(w.workflowLabel)}]`)} ${pc39.dim(`${w.nodeCount} node${w.nodeCount !== 1 ? "s" : ""}`)}`,
29773
30624
  hint: `${w.executionMode} \xB7 ${w.updatedAt?.slice(0, 10) ?? w.createdAt.slice(0, 10)}`
29774
30625
  }));
29775
30626
  const choice = await paginatedSelect("Select a saved workflow", allOptions, {
@@ -29790,7 +30641,7 @@ async function runWorkflowPicker(opts) {
29790
30641
  detail = await loadSavedWorkflowDetail(entry);
29791
30642
  detailSpinner.stop(`Loaded ${entry.name}.`);
29792
30643
  } catch (err) {
29793
- detailSpinner.stop(pc38.red(`Failed to load ${entry.name}.`));
30644
+ detailSpinner.stop(pc39.red(`Failed to load ${entry.name}.`));
29794
30645
  p24.log.error(err.message);
29795
30646
  continue;
29796
30647
  }
@@ -29798,14 +30649,14 @@ async function runWorkflowPicker(opts) {
29798
30649
  const nodes = Array.isArray(pipeline.nodes) ? pipeline.nodes : [];
29799
30650
  console.log("");
29800
30651
  console.log(box5([
29801
- `${pc38.bold("Workflow:")} ${entry.name}`,
29802
- `${pc38.dim("ID:")} ${entry.workflowId}`,
29803
- `${pc38.dim("Mode:")} hosted ${pc38.dim("Nodes:")} ${nodes.length}`,
29804
- `${pc38.dim("Label:")} ${renderWorkflowLabel(entry.workflowLabel ?? "experimental")}`,
29805
- `${pc38.dim("Created:")} ${detail.createdAt || "\u2014"}`,
30652
+ `${pc39.bold("Workflow:")} ${entry.name}`,
30653
+ `${pc39.dim("ID:")} ${entry.workflowId}`,
30654
+ `${pc39.dim("Mode:")} hosted ${pc39.dim("Nodes:")} ${nodes.length}`,
30655
+ `${pc39.dim("Label:")} ${renderWorkflowLabel(entry.workflowLabel ?? "experimental")}`,
30656
+ `${pc39.dim("Created:")} ${detail.createdAt || "\u2014"}`,
29806
30657
  "",
29807
30658
  ...nodes.map(
29808
- (n, i) => `${pc38.dim(String(i + 1) + ".")} ${pc38.bold(n.data?.slug ?? n.slug ?? n.id)} ${pc38.dim(n.id)}`
30659
+ (n, i) => `${pc39.dim(String(i + 1) + ".")} ${pc39.bold(n.data?.slug ?? n.slug ?? n.id)} ${pc39.dim(n.id)}`
29809
30660
  )
29810
30661
  ]));
29811
30662
  console.log("");
@@ -29816,7 +30667,7 @@ async function runWorkflowPicker(opts) {
29816
30667
  { value: "set_label", label: "Set workflow label" },
29817
30668
  { value: "archive", label: "Archive workflow" },
29818
30669
  { value: "unarchive", label: "Unarchive workflow" },
29819
- { value: "delete", label: pc38.red("Delete workflow") },
30670
+ { value: "delete", label: pc39.red("Delete workflow") },
29820
30671
  { value: "back_to_saved", label: "\u2190 Back to saved workflows" }
29821
30672
  ]
29822
30673
  });
@@ -29861,7 +30712,7 @@ async function runWorkflowPicker(opts) {
29861
30712
  console.log("");
29862
30713
  }
29863
30714
  await executeHostedPipeline(executablePipeline);
29864
- p24.log.success(`Saved workflow execution completed for ${pc38.bold(entry.name)}.`);
30715
+ p24.log.success(`Saved workflow execution completed for ${pc39.bold(entry.name)}.`);
29865
30716
  } catch (err) {
29866
30717
  p24.log.error("Saved workflow execution failed: " + err.message);
29867
30718
  }
@@ -29880,7 +30731,7 @@ async function runWorkflowPicker(opts) {
29880
30731
  continue;
29881
30732
  }
29882
30733
  hygieneStore.setLabel(entry.workflowId, labelChoice);
29883
- p24.log.success(`Updated label for ${pc38.bold(entry.name)} to ${renderWorkflowLabel(labelChoice)}.`);
30734
+ p24.log.success(`Updated label for ${pc39.bold(entry.name)} to ${renderWorkflowLabel(labelChoice)}.`);
29884
30735
  continue;
29885
30736
  }
29886
30737
  if (nextAction === "archive") {
@@ -29894,10 +30745,10 @@ async function runWorkflowPicker(opts) {
29894
30745
  try {
29895
30746
  await archiveSavedWorkflow(entry);
29896
30747
  hygieneStore.setLabel(entry.workflowId, "archived");
29897
- p24.log.success(`Archived ${pc38.bold(entry.name)}.`);
30748
+ p24.log.success(`Archived ${pc39.bold(entry.name)}.`);
29898
30749
  } catch {
29899
30750
  hygieneStore.setLabel(entry.workflowId, "archived");
29900
- p24.log.success(`Archived ${pc38.bold(entry.name)} (local fallback).`);
30751
+ p24.log.success(`Archived ${pc39.bold(entry.name)} (local fallback).`);
29901
30752
  }
29902
30753
  continue;
29903
30754
  }
@@ -29919,7 +30770,7 @@ async function runWorkflowPicker(opts) {
29919
30770
  }
29920
30771
  hygieneStore.setLabel(entry.workflowId, restoreChoice);
29921
30772
  p24.log.success(
29922
- `Unarchived ${pc38.bold(entry.name)} to ${renderWorkflowLabel(restoreChoice)}.`
30773
+ `Unarchived ${pc39.bold(entry.name)} to ${renderWorkflowLabel(restoreChoice)}.`
29923
30774
  );
29924
30775
  continue;
29925
30776
  }
@@ -29940,10 +30791,10 @@ async function runWorkflowPicker(opts) {
29940
30791
  }
29941
30792
  try {
29942
30793
  await deleteSavedWorkflow(entry);
29943
- p24.log.success(`Deleted ${pc38.bold(entry.name)}.`);
30794
+ p24.log.success(`Deleted ${pc39.bold(entry.name)}.`);
29944
30795
  } catch {
29945
30796
  markWorkflowDeletedLocally(entry.workflowId);
29946
- p24.log.success(`Deleted ${pc38.bold(entry.name)} (local fallback).`);
30797
+ p24.log.success(`Deleted ${pc39.bold(entry.name)} (local fallback).`);
29947
30798
  }
29948
30799
  continue;
29949
30800
  }
@@ -30060,12 +30911,12 @@ async function runWorkflowPicker(opts) {
30060
30911
  const resolver = createMachineCapabilityResolver();
30061
30912
  const binding = await resolver.resolveCapability(selected.slug);
30062
30913
  if (binding) {
30063
- const statusColor3 = binding.allowed ? pc38.green : pc38.red;
30914
+ const statusColor3 = binding.allowed ? pc39.green : pc39.red;
30064
30915
  console.log("");
30065
30916
  console.log(box5([
30066
- `${pc38.bold("Machine Binding:")} ${selected.slug}`,
30067
- `${pc38.dim("Allowed:")} ${statusColor3(String(binding.allowed))}`,
30068
- `${pc38.dim("Reason:")} ${binding.reason ?? "\u2014"}`
30917
+ `${pc39.bold("Machine Binding:")} ${selected.slug}`,
30918
+ `${pc39.dim("Allowed:")} ${statusColor3(String(binding.allowed))}`,
30919
+ `${pc39.dim("Reason:")} ${binding.reason ?? "\u2014"}`
30069
30920
  ]));
30070
30921
  console.log("");
30071
30922
  }
@@ -30100,7 +30951,7 @@ async function runWorkflowPicker(opts) {
30100
30951
  "Input normalization"
30101
30952
  );
30102
30953
  const nodeId = builder.addNode(selected.slug, normalized.bindings);
30103
- p24.log.success(`Added ${pc38.bold(selected.displayName)} (${pc38.dim(nodeId)})`);
30954
+ p24.log.success(`Added ${pc39.bold(selected.displayName)} (${pc39.dim(nodeId)})`);
30104
30955
  const next = await p24.select({
30105
30956
  message: "Pipeline has 1 node. What next?",
30106
30957
  options: [
@@ -30138,7 +30989,7 @@ async function runWorkflowPicker(opts) {
30138
30989
  throw new Error("Hosted workflow save returned no payload.");
30139
30990
  }
30140
30991
  p24.log.success(
30141
- `Hosted workflow saved as ${pc38.bold(workflowName)} (${pc38.dim(saveResult.workflowId)} \xB7 v${saveResult.version})`
30992
+ `Hosted workflow saved as ${pc39.bold(workflowName)} (${pc39.dim(saveResult.workflowId)} \xB7 v${saveResult.version})`
30142
30993
  );
30143
30994
  }
30144
30995
  break;
@@ -30188,31 +31039,31 @@ async function renderWorkflowIntelligenceSummary(pipeline, capabilities, phase)
30188
31039
  };
30189
31040
  const result = await provider.summarizeExecution(input);
30190
31041
  const lines = [
30191
- `${pc38.bold("Intelligence Summary")} ${pc38.dim(result.title)}`,
31042
+ `${pc39.bold("Intelligence Summary")} ${pc39.dim(result.title)}`,
30192
31043
  result.explanation
30193
31044
  ];
30194
31045
  if (result.runtimeModeNote) {
30195
- lines.push(`${pc38.dim("Runtime:")} ${result.runtimeModeNote}`);
31046
+ lines.push(`${pc39.dim("Runtime:")} ${result.runtimeModeNote}`);
30196
31047
  }
30197
31048
  if (result.outputExpectation) {
30198
- lines.push(`${pc38.dim("Expected:")} ${result.outputExpectation}`);
31049
+ lines.push(`${pc39.dim("Expected:")} ${result.outputExpectation}`);
30199
31050
  }
30200
31051
  if (result.missingBindingGuidance.length > 0) {
30201
- lines.push("", pc38.yellow("Missing Binding Guidance"));
31052
+ lines.push("", pc39.yellow("Missing Binding Guidance"));
30202
31053
  for (const guidance of result.missingBindingGuidance) {
30203
- lines.push(` ${pc38.dim("\xB7")} ${guidance}`);
31054
+ lines.push(` ${pc39.dim("\xB7")} ${guidance}`);
30204
31055
  }
30205
31056
  }
30206
31057
  if (result.costLatencyCautions.length > 0) {
30207
- lines.push("", pc38.yellow("Cost/Latency Notes"));
31058
+ lines.push("", pc39.yellow("Cost/Latency Notes"));
30208
31059
  for (const caution of result.costLatencyCautions) {
30209
- lines.push(` ${pc38.dim("\xB7")} ${caution}`);
31060
+ lines.push(` ${pc39.dim("\xB7")} ${caution}`);
30210
31061
  }
30211
31062
  }
30212
31063
  if (result.warnings.length > 0) {
30213
- lines.push("", pc38.yellow("Warnings"));
31064
+ lines.push("", pc39.yellow("Warnings"));
30214
31065
  for (const warning of result.warnings) {
30215
- lines.push(` ${pc38.dim("\xB7")} ${warning}`);
31066
+ lines.push(` ${pc39.dim("\xB7")} ${warning}`);
30216
31067
  }
30217
31068
  }
30218
31069
  return lines;
@@ -30235,7 +31086,7 @@ Examples:
30235
31086
  wf.command("templates").description("List CMS workflow node starter templates").option("--family <family>", "Filter by family").option("--search <term>", "Search templates").option("--view <mode>", "List view mode: condensed | expanded | tree").option("--json", "Output raw JSON").action(async (opts) => {
30236
31087
  const access = getWorkflowAccess();
30237
31088
  if (access.state !== "ready") {
30238
- console.error(pc38.red(`${access.reason}.`));
31089
+ console.error(pc39.red(`${access.reason}.`));
30239
31090
  process.exitCode = 1;
30240
31091
  return;
30241
31092
  }
@@ -30252,24 +31103,24 @@ Examples:
30252
31103
  return;
30253
31104
  }
30254
31105
  if (nodes.length === 0) {
30255
- console.error(pc38.yellow("No templates found."));
31106
+ console.error(pc39.yellow("No templates found."));
30256
31107
  process.exitCode = 1;
30257
31108
  return;
30258
31109
  }
30259
31110
  const viewMode = opts.view ?? "condensed";
30260
31111
  console.log("");
30261
31112
  console.log(
30262
- pc38.bold("Workflow Node Templates") + pc38.dim(` ${nodes.length} template${nodes.length !== 1 ? "s" : ""}`)
31113
+ pc39.bold("Workflow Node Templates") + pc39.dim(` ${nodes.length} template${nodes.length !== 1 ? "s" : ""}`)
30263
31114
  );
30264
31115
  console.log(hr8());
30265
- console.log(pc38.bold("Step 1: CMS Node Contract Validation"));
30266
- console.log(pc38.dim("Validate contract visibility before template selection."));
30267
- console.log(pc38.dim(`View mode: ${viewMode}`));
31116
+ console.log(pc39.bold("Step 1: CMS Node Contract Validation"));
31117
+ console.log(pc39.dim("Validate contract visibility before template selection."));
31118
+ console.log(pc39.dim(`View mode: ${viewMode}`));
30268
31119
  console.log("");
30269
31120
  if (viewMode === "tree") {
30270
31121
  console.log(box5(renderTemplateTree(nodes)));
30271
31122
  console.log(hr8());
30272
- console.log(pc38.dim(` Source: ${meta.source} \xB7 growthub workflow`));
31123
+ console.log(pc39.dim(` Source: ${meta.source} \xB7 growthub workflow`));
30273
31124
  console.log("");
30274
31125
  return;
30275
31126
  }
@@ -30277,24 +31128,24 @@ Examples:
30277
31128
  const contract = introspectNodeContract(node);
30278
31129
  const requiredInputs = contract.inputs.filter((input) => input.required).length;
30279
31130
  const optionalInputs = contract.inputs.length - requiredInputs;
30280
- const enabledTag = node.enabled ? pc38.green("enabled") : pc38.red("disabled");
30281
- console.log(` ${node.icon} ${pc38.bold(node.displayName)} ${pc38.dim(node.slug)} ${enabledTag}`);
31131
+ const enabledTag = node.enabled ? pc39.green("enabled") : pc39.red("disabled");
31132
+ console.log(` ${node.icon} ${pc39.bold(node.displayName)} ${pc39.dim(node.slug)} ${enabledTag}`);
30282
31133
  console.log(
30283
- ` ${pc38.dim("Contract:")} ${pc38.dim("required")}=${requiredInputs} ${pc38.dim("optional")}=${optionalInputs} ${pc38.dim("bindings")}=${contract.requiredBindings.length} ${pc38.dim("outputs")}=${contract.outputTypes.length}`
31134
+ ` ${pc39.dim("Contract:")} ${pc39.dim("required")}=${requiredInputs} ${pc39.dim("optional")}=${optionalInputs} ${pc39.dim("bindings")}=${contract.requiredBindings.length} ${pc39.dim("outputs")}=${contract.outputTypes.length}`
30284
31135
  );
30285
31136
  console.log(
30286
- ` ${pc38.dim("Execution:")} ${contract.executionStrategy} \xB7 ${contract.executionKind}`
31137
+ ` ${pc39.dim("Execution:")} ${contract.executionStrategy} \xB7 ${contract.executionKind}`
30287
31138
  );
30288
31139
  if (node.description) {
30289
- console.log(` ${pc38.dim(node.description)}`);
31140
+ console.log(` ${pc39.dim(node.description)}`);
30290
31141
  }
30291
31142
  console.log("");
30292
31143
  }
30293
31144
  console.log(hr8());
30294
- console.log(pc38.dim(` Source: ${meta.source} \xB7 growthub workflow`));
31145
+ console.log(pc39.dim(` Source: ${meta.source} \xB7 growthub workflow`));
30295
31146
  console.log("");
30296
31147
  } catch (err) {
30297
- console.error(pc38.red("Failed: " + err.message));
31148
+ console.error(pc39.red("Failed: " + err.message));
30298
31149
  process.exitCode = 1;
30299
31150
  }
30300
31151
  });
@@ -30314,67 +31165,67 @@ Examples:
30314
31165
  return;
30315
31166
  }
30316
31167
  if (visibleSaved.length === 0) {
30317
- console.log(pc38.dim("No saved workflows. Run `growthub workflow` to assemble one."));
31168
+ console.log(pc39.dim("No saved workflows. Run `growthub workflow` to assemble one."));
30318
31169
  return;
30319
31170
  }
30320
31171
  console.log("");
30321
31172
  console.log(
30322
- pc38.bold("Saved Workflows") + pc38.dim(` ${visibleSaved.length} workflow${visibleSaved.length !== 1 ? "s" : ""}`)
31173
+ pc39.bold("Saved Workflows") + pc39.dim(` ${visibleSaved.length} workflow${visibleSaved.length !== 1 ? "s" : ""}`)
30323
31174
  );
30324
31175
  if (!opts.includeArchived) {
30325
31176
  const hiddenArchivedCount = saved.length - visibleSaved.length;
30326
31177
  if (hiddenArchivedCount > 0) {
30327
- console.log(pc38.dim(` Archived hidden: ${hiddenArchivedCount} (use --include-archived to show)`));
31178
+ console.log(pc39.dim(` Archived hidden: ${hiddenArchivedCount} (use --include-archived to show)`));
30328
31179
  }
30329
31180
  }
30330
31181
  console.log(hr8());
30331
31182
  for (const w of visibleSaved) {
30332
31183
  console.log(
30333
- ` ${pc38.bold(w.name)} ` + pc38.dim(`[${renderWorkflowLabel(w.workflowLabel)}] `) + pc38.dim(`${w.nodeCount} node${w.nodeCount !== 1 ? "s" : ""} \xB7 ${w.executionMode} \xB7 ${w.updatedAt?.slice(0, 10) ?? w.createdAt.slice(0, 10)}`)
31184
+ ` ${pc39.bold(w.name)} ` + pc39.dim(`[${renderWorkflowLabel(w.workflowLabel)}] `) + pc39.dim(`${w.nodeCount} node${w.nodeCount !== 1 ? "s" : ""} \xB7 ${w.executionMode} \xB7 ${w.updatedAt?.slice(0, 10) ?? w.createdAt.slice(0, 10)}`)
30334
31185
  );
30335
31186
  }
30336
31187
  console.log("");
30337
- console.log(pc38.dim(` Source: ${visibleSaved[0]?.source === "hosted" ? "hosted workflow registry" : resolveSavedWorkflowsDir()}`));
31188
+ console.log(pc39.dim(` Source: ${visibleSaved[0]?.source === "hosted" ? "hosted workflow registry" : resolveSavedWorkflowsDir()}`));
30338
31189
  console.log("");
30339
31190
  });
30340
31191
  }
30341
31192
 
30342
31193
  // src/commands/open-agents.ts
30343
31194
  import * as p25 from "@clack/prompts";
30344
- import pc39 from "picocolors";
31195
+ import pc40 from "picocolors";
30345
31196
 
30346
31197
  // src/runtime/agent-harness/auth-store.ts
30347
31198
  init_home();
30348
- import fs41 from "node:fs";
30349
- import path49 from "node:path";
31199
+ import fs44 from "node:fs";
31200
+ import path53 from "node:path";
30350
31201
  function resolveHarnessAuthDir() {
30351
- return path49.resolve(resolvePaperclipHomeDir(), "harness-auth");
31202
+ return path53.resolve(resolvePaperclipHomeDir(), "harness-auth");
30352
31203
  }
30353
31204
  function resolveHarnessAuthFile(harnessId) {
30354
- return path49.resolve(resolveHarnessAuthDir(), `${harnessId}.json`);
31205
+ return path53.resolve(resolveHarnessAuthDir(), `${harnessId}.json`);
30355
31206
  }
30356
31207
  function normalizeSecret(value) {
30357
31208
  const trimmed = value?.trim();
30358
31209
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
30359
31210
  }
30360
31211
  function ensureSecureDir(dirPath) {
30361
- fs41.mkdirSync(dirPath, { recursive: true });
31212
+ fs44.mkdirSync(dirPath, { recursive: true });
30362
31213
  try {
30363
- fs41.chmodSync(dirPath, 448);
31214
+ fs44.chmodSync(dirPath, 448);
30364
31215
  } catch {
30365
31216
  }
30366
31217
  }
30367
31218
  function ensureSecureFile(filePath) {
30368
31219
  try {
30369
- fs41.chmodSync(filePath, 384);
31220
+ fs44.chmodSync(filePath, 384);
30370
31221
  } catch {
30371
31222
  }
30372
31223
  }
30373
31224
  function readHarnessCredentials(harnessId) {
30374
31225
  const filePath = resolveHarnessAuthFile(harnessId);
30375
- if (!fs41.existsSync(filePath)) return {};
31226
+ if (!fs44.existsSync(filePath)) return {};
30376
31227
  try {
30377
- const parsed = JSON.parse(fs41.readFileSync(filePath, "utf-8"));
31228
+ const parsed = JSON.parse(fs44.readFileSync(filePath, "utf-8"));
30378
31229
  const creds = {};
30379
31230
  for (const [key, value] of Object.entries(parsed)) {
30380
31231
  if (typeof value === "string" && value.trim().length > 0) {
@@ -30401,7 +31252,7 @@ function setHarnessCredential(harnessId, key, value) {
30401
31252
  const dirPath = resolveHarnessAuthDir();
30402
31253
  ensureSecureDir(dirPath);
30403
31254
  const filePath = resolveHarnessAuthFile(harnessId);
30404
- fs41.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
31255
+ fs44.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
30405
31256
  `, "utf-8");
30406
31257
  ensureSecureFile(filePath);
30407
31258
  }
@@ -30418,7 +31269,7 @@ function setHarnessCredentials(harnessId, updates) {
30418
31269
  const dirPath = resolveHarnessAuthDir();
30419
31270
  ensureSecureDir(dirPath);
30420
31271
  const filePath = resolveHarnessAuthFile(harnessId);
30421
- fs41.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
31272
+ fs44.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
30422
31273
  `, "utf-8");
30423
31274
  ensureSecureFile(filePath);
30424
31275
  }
@@ -30430,8 +31281,8 @@ function maskSecret(value) {
30430
31281
 
30431
31282
  // src/runtime/open-agents/index.ts
30432
31283
  init_home();
30433
- import fs42 from "node:fs";
30434
- import path50 from "node:path";
31284
+ import fs45 from "node:fs";
31285
+ import path54 from "node:path";
30435
31286
 
30436
31287
  // src/runtime/open-agents/contract.ts
30437
31288
  var DEFAULT_OPEN_AGENTS_CONFIG = {
@@ -30618,18 +31469,18 @@ var OpenAgentsBackendError = class extends Error {
30618
31469
 
30619
31470
  // src/runtime/open-agents/index.ts
30620
31471
  function resolveConfigPath3() {
30621
- return path50.resolve(resolvePaperclipHomeDir(), "open-agents", "config.json");
31472
+ return path54.resolve(resolvePaperclipHomeDir(), "open-agents", "config.json");
30622
31473
  }
30623
31474
  function readOpenAgentsConfig() {
30624
31475
  const configPath = resolveConfigPath3();
30625
- if (!fs42.existsSync(configPath)) {
31476
+ if (!fs45.existsSync(configPath)) {
30626
31477
  return {
30627
31478
  ...DEFAULT_OPEN_AGENTS_CONFIG,
30628
31479
  apiKey: getHarnessCredential("open-agents", "apiKey")
30629
31480
  };
30630
31481
  }
30631
31482
  try {
30632
- const raw = JSON.parse(fs42.readFileSync(configPath, "utf-8"));
31483
+ const raw = JSON.parse(fs45.readFileSync(configPath, "utf-8"));
30633
31484
  const storedApiKey = getHarnessCredential("open-agents", "apiKey");
30634
31485
  return {
30635
31486
  backendType: validateBackendType(raw.backendType),
@@ -30650,13 +31501,13 @@ function readOpenAgentsConfig() {
30650
31501
  }
30651
31502
  function writeOpenAgentsConfig(config) {
30652
31503
  const configPath = resolveConfigPath3();
30653
- fs42.mkdirSync(path50.dirname(configPath), { recursive: true });
31504
+ fs45.mkdirSync(path54.dirname(configPath), { recursive: true });
30654
31505
  const persisted = {
30655
31506
  ...config,
30656
31507
  authMode: validateAuthMode(config.authMode),
30657
31508
  apiKey: void 0
30658
31509
  };
30659
- fs42.writeFileSync(configPath, `${JSON.stringify(persisted, null, 2)}
31510
+ fs45.writeFileSync(configPath, `${JSON.stringify(persisted, null, 2)}
30660
31511
  `, "utf-8");
30661
31512
  setHarnessCredential("open-agents", "apiKey", config.apiKey);
30662
31513
  }
@@ -30674,21 +31525,21 @@ function validateAuthMode(value) {
30674
31525
  // src/commands/open-agents.ts
30675
31526
  init_banner();
30676
31527
  function statusColor2(status) {
30677
- if (status === "running") return pc39.green(status);
30678
- if (status === "completed") return pc39.cyan(status);
30679
- if (status === "failed" || status === "cancelled") return pc39.red(status);
30680
- if (status === "waiting" || status === "idle") return pc39.yellow(status);
30681
- return pc39.dim(status);
31528
+ if (status === "running") return pc40.green(status);
31529
+ if (status === "completed") return pc40.cyan(status);
31530
+ if (status === "failed" || status === "cancelled") return pc40.red(status);
31531
+ if (status === "waiting" || status === "idle") return pc40.yellow(status);
31532
+ return pc40.dim(status);
30682
31533
  }
30683
31534
  function sandboxBadge(state) {
30684
- if (state === "running") return pc39.green("running");
30685
- if (state === "hibernating") return pc39.yellow("hibernating");
30686
- if (state === "stopped") return pc39.dim("stopped");
30687
- if (state === "error") return pc39.red("error");
30688
- return pc39.dim(state);
31535
+ if (state === "running") return pc40.green("running");
31536
+ if (state === "hibernating") return pc40.yellow("hibernating");
31537
+ if (state === "stopped") return pc40.dim("stopped");
31538
+ if (state === "error") return pc40.red("error");
31539
+ return pc40.dim(state);
30689
31540
  }
30690
31541
  function hr9(width = 72) {
30691
- return pc39.dim("\u2500".repeat(width));
31542
+ return pc40.dim("\u2500".repeat(width));
30692
31543
  }
30693
31544
  function stripAnsi7(str) {
30694
31545
  return str.replace(/\x1B\[[0-9;]*m/g, "");
@@ -30696,27 +31547,27 @@ function stripAnsi7(str) {
30696
31547
  function box6(lines) {
30697
31548
  const padded = lines.map((l) => " " + l);
30698
31549
  const width = Math.max(...padded.map((l) => stripAnsi7(l).length)) + 4;
30699
- const top = pc39.dim("\u250C" + "\u2500".repeat(width) + "\u2510");
30700
- const bottom = pc39.dim("\u2514" + "\u2500".repeat(width) + "\u2518");
31550
+ const top = pc40.dim("\u250C" + "\u2500".repeat(width) + "\u2510");
31551
+ const bottom = pc40.dim("\u2514" + "\u2500".repeat(width) + "\u2518");
30701
31552
  const body = padded.map((l) => {
30702
31553
  const pad2 = width - stripAnsi7(l).length;
30703
- return pc39.dim("\u2502") + l + " ".repeat(pad2) + pc39.dim("\u2502");
31554
+ return pc40.dim("\u2502") + l + " ".repeat(pad2) + pc40.dim("\u2502");
30704
31555
  });
30705
31556
  return [top, ...body, bottom].join("\n");
30706
31557
  }
30707
31558
  function printSessionCard(session) {
30708
31559
  const lines = [
30709
- `${pc39.bold("Session")} ${pc39.dim(session.sessionId)}`,
30710
- `${pc39.dim("Status:")} ${statusColor2(session.status)}`,
30711
- `${pc39.dim("Sandbox:")} ${sandboxBadge(session.sandboxState)}`,
30712
- `${pc39.dim("Events:")} ${session.eventCount}`,
30713
- `${pc39.dim("Created:")} ${session.createdAt}`
31560
+ `${pc40.bold("Session")} ${pc40.dim(session.sessionId)}`,
31561
+ `${pc40.dim("Status:")} ${statusColor2(session.status)}`,
31562
+ `${pc40.dim("Sandbox:")} ${sandboxBadge(session.sandboxState)}`,
31563
+ `${pc40.dim("Events:")} ${session.eventCount}`,
31564
+ `${pc40.dim("Created:")} ${session.createdAt}`
30714
31565
  ];
30715
- if (session.repoUrl) lines.push(`${pc39.dim("Repo:")} ${session.repoUrl}`);
30716
- if (session.branch) lines.push(`${pc39.dim("Branch:")} ${session.branch}`);
31566
+ if (session.repoUrl) lines.push(`${pc40.dim("Repo:")} ${session.repoUrl}`);
31567
+ if (session.branch) lines.push(`${pc40.dim("Branch:")} ${session.branch}`);
30717
31568
  if (session.prompt) {
30718
31569
  const truncated = session.prompt.length > 80 ? session.prompt.slice(0, 77) + "..." : session.prompt;
30719
- lines.push(`${pc39.dim("Prompt:")} ${truncated}`);
31570
+ lines.push(`${pc40.dim("Prompt:")} ${truncated}`);
30720
31571
  }
30721
31572
  console.log("");
30722
31573
  console.log(box6(lines));
@@ -30743,12 +31594,12 @@ var EVENT_EMOJI = {
30743
31594
  };
30744
31595
  function printEvent(event) {
30745
31596
  const emoji = EVENT_EMOJI[event.type] ?? "\xB7";
30746
- const ts = pc39.dim(event.timestamp.split("T")[1]?.slice(0, 8) ?? "");
31597
+ const ts = pc40.dim(event.timestamp.split("T")[1]?.slice(0, 8) ?? "");
30747
31598
  console.log(` ${emoji} ${ts} ${event.detail}`);
30748
31599
  }
30749
31600
  async function runOpenAgentsHub(opts) {
30750
31601
  printPaperclipCliBanner();
30751
- p25.intro(pc39.bold("Open Agents"));
31602
+ p25.intro(pc40.bold("Open Agents"));
30752
31603
  while (true) {
30753
31604
  const config = readOpenAgentsConfig();
30754
31605
  const action = await p25.select({
@@ -30915,7 +31766,7 @@ async function runSessionListFlow(config) {
30915
31766
  options: [
30916
31767
  ...sessions.map((s) => ({
30917
31768
  value: s.sessionId,
30918
- label: `${statusColor2(s.status)} ${pc39.dim(s.sessionId.slice(0, 12))}`,
31769
+ label: `${statusColor2(s.status)} ${pc40.dim(s.sessionId.slice(0, 12))}`,
30919
31770
  hint: s.prompt ? s.prompt.slice(0, 50) : void 0
30920
31771
  })),
30921
31772
  { value: "__back", label: "\u2190 Back" }
@@ -30940,7 +31791,7 @@ async function runSessionListFlow(config) {
30940
31791
  p25.note("No events recorded yet.", "Empty");
30941
31792
  } else {
30942
31793
  console.log("");
30943
- console.log(pc39.bold("Recent Events") + pc39.dim(` (${events.length})`));
31794
+ console.log(pc40.bold("Recent Events") + pc40.dim(` (${events.length})`));
30944
31795
  console.log(hr9());
30945
31796
  for (const event of events.slice(-20)) {
30946
31797
  printEvent(event);
@@ -31006,7 +31857,7 @@ async function runResumeSessionFlow(config) {
31006
31857
  printSessionCard(session);
31007
31858
  const events = await pollSessionEvents(config, session.sessionId);
31008
31859
  if (events.length > 0) {
31009
- console.log(pc39.bold("Latest Events") + pc39.dim(` (${events.length})`));
31860
+ console.log(pc40.bold("Latest Events") + pc40.dim(` (${events.length})`));
31010
31861
  console.log(hr9());
31011
31862
  for (const event of events.slice(-20)) {
31012
31863
  printEvent(event);
@@ -31053,7 +31904,7 @@ Examples:
31053
31904
  if (opts.json) {
31054
31905
  console.log(JSON.stringify(updated, null, 2));
31055
31906
  } else {
31056
- console.log(pc39.green("Configuration updated."));
31907
+ console.log(pc40.green("Configuration updated."));
31057
31908
  }
31058
31909
  return;
31059
31910
  }
@@ -31062,15 +31913,15 @@ Examples:
31062
31913
  return;
31063
31914
  }
31064
31915
  console.log("");
31065
- console.log(pc39.bold("Open Agents Configuration"));
31916
+ console.log(pc40.bold("Open Agents Configuration"));
31066
31917
  console.log(hr9());
31067
- console.log(` ${pc39.dim("Backend:")} ${config.backendType}`);
31068
- console.log(` ${pc39.dim("Auth Mode:")} ${config.authMode ?? "none"}`);
31069
- console.log(` ${pc39.dim("Endpoint:")} ${config.endpoint}`);
31070
- console.log(` ${pc39.dim("API Key:")} ${config.apiKey ? maskSecret(config.apiKey) : pc39.dim("(none)")}`);
31071
- console.log(` ${pc39.dim("Repo:")} ${config.defaultRepo ?? pc39.dim("(none)")}`);
31072
- console.log(` ${pc39.dim("Branch:")} ${config.defaultBranch ?? pc39.dim("(none)")}`);
31073
- console.log(` ${pc39.dim("Timeout:")} ${config.timeoutMs ?? 3e4}ms`);
31918
+ console.log(` ${pc40.dim("Backend:")} ${config.backendType}`);
31919
+ console.log(` ${pc40.dim("Auth Mode:")} ${config.authMode ?? "none"}`);
31920
+ console.log(` ${pc40.dim("Endpoint:")} ${config.endpoint}`);
31921
+ console.log(` ${pc40.dim("API Key:")} ${config.apiKey ? maskSecret(config.apiKey) : pc40.dim("(none)")}`);
31922
+ console.log(` ${pc40.dim("Repo:")} ${config.defaultRepo ?? pc40.dim("(none)")}`);
31923
+ console.log(` ${pc40.dim("Branch:")} ${config.defaultBranch ?? pc40.dim("(none)")}`);
31924
+ console.log(` ${pc40.dim("Timeout:")} ${config.timeoutMs ?? 3e4}ms`);
31074
31925
  console.log(hr9());
31075
31926
  console.log("");
31076
31927
  });
@@ -31083,12 +31934,12 @@ Examples:
31083
31934
  }
31084
31935
  if (health.available) {
31085
31936
  console.log(
31086
- pc39.green("\u2713") + ` Backend reachable at ${config.endpoint} (${health.latencyMs}ms)` + (health.version ? ` version: ${health.version}` : "")
31937
+ pc40.green("\u2713") + ` Backend reachable at ${config.endpoint} (${health.latencyMs}ms)` + (health.version ? ` version: ${health.version}` : "")
31087
31938
  );
31088
31939
  } else {
31089
- console.log(pc39.red("\u2717") + ` Backend unavailable at ${config.endpoint} (${health.latencyMs}ms)`);
31940
+ console.log(pc40.red("\u2717") + ` Backend unavailable at ${config.endpoint} (${health.latencyMs}ms)`);
31090
31941
  if (health.error) {
31091
- console.log(pc39.dim(` ${health.error}`));
31942
+ console.log(pc40.dim(` ${health.error}`));
31092
31943
  }
31093
31944
  process.exitCode = 1;
31094
31945
  }
@@ -31102,22 +31953,22 @@ Examples:
31102
31953
  return;
31103
31954
  }
31104
31955
  if (sessions.length === 0) {
31105
- console.log(pc39.yellow("No sessions found.") + pc39.dim(" Run `growthub open-agents create` to start one."));
31956
+ console.log(pc40.yellow("No sessions found.") + pc40.dim(" Run `growthub open-agents create` to start one."));
31106
31957
  return;
31107
31958
  }
31108
31959
  console.log("");
31109
- console.log(pc39.bold("Agent Sessions") + pc39.dim(` (${sessions.length})`));
31960
+ console.log(pc40.bold("Agent Sessions") + pc40.dim(` (${sessions.length})`));
31110
31961
  console.log(hr9());
31111
31962
  for (const session of sessions) {
31112
- const truncatedPrompt = session.prompt ? pc39.dim(session.prompt.slice(0, 50)) : "";
31963
+ const truncatedPrompt = session.prompt ? pc40.dim(session.prompt.slice(0, 50)) : "";
31113
31964
  console.log(
31114
- ` ${statusColor2(session.status)} ${pc39.dim(session.sessionId.slice(0, 12))} ${sandboxBadge(session.sandboxState)} ${truncatedPrompt}`
31965
+ ` ${statusColor2(session.status)} ${pc40.dim(session.sessionId.slice(0, 12))} ${sandboxBadge(session.sandboxState)} ${truncatedPrompt}`
31115
31966
  );
31116
31967
  }
31117
31968
  console.log(hr9());
31118
31969
  console.log("");
31119
31970
  } catch (err) {
31120
- console.error(pc39.red("Failed to list sessions: " + err.message));
31971
+ console.error(pc40.red("Failed to list sessions: " + err.message));
31121
31972
  process.exitCode = 1;
31122
31973
  }
31123
31974
  });
@@ -31139,7 +31990,7 @@ Examples:
31139
31990
  }
31140
31991
  printSessionCard(session);
31141
31992
  } catch (err) {
31142
- console.error(pc39.red("Failed to create session: " + err.message));
31993
+ console.error(pc40.red("Failed to create session: " + err.message));
31143
31994
  process.exitCode = 1;
31144
31995
  }
31145
31996
  });
@@ -31157,7 +32008,7 @@ Examples:
31157
32008
  }
31158
32009
  printSessionCard(session);
31159
32010
  } catch (err) {
31160
- console.error(pc39.red("Failed to create session: " + err.message));
32011
+ console.error(pc40.red("Failed to create session: " + err.message));
31161
32012
  process.exitCode = 1;
31162
32013
  }
31163
32014
  });
@@ -31172,7 +32023,7 @@ Examples:
31172
32023
  printSessionCard(session);
31173
32024
  const events = await pollSessionEvents(config, session.sessionId);
31174
32025
  if (events.length > 0) {
31175
- console.log(pc39.bold("Latest Events") + pc39.dim(` (${events.length})`));
32026
+ console.log(pc40.bold("Latest Events") + pc40.dim(` (${events.length})`));
31176
32027
  console.log(hr9());
31177
32028
  for (const event of events.slice(-20)) {
31178
32029
  printEvent(event);
@@ -31181,7 +32032,7 @@ Examples:
31181
32032
  console.log("");
31182
32033
  }
31183
32034
  } catch (err) {
31184
- console.error(pc39.red("Failed to resume session: " + err.message));
32035
+ console.error(pc40.red("Failed to resume session: " + err.message));
31185
32036
  process.exitCode = 1;
31186
32037
  }
31187
32038
  });
@@ -31196,7 +32047,7 @@ Examples:
31196
32047
  printSessionCard(session);
31197
32048
  const events = await pollSessionEvents(config, session.sessionId);
31198
32049
  if (events.length > 0) {
31199
- console.log(pc39.bold("Latest Events") + pc39.dim(` (${events.length})`));
32050
+ console.log(pc40.bold("Latest Events") + pc40.dim(` (${events.length})`));
31200
32051
  console.log(hr9());
31201
32052
  for (const event of events.slice(-20)) {
31202
32053
  printEvent(event);
@@ -31205,7 +32056,7 @@ Examples:
31205
32056
  console.log("");
31206
32057
  }
31207
32058
  } catch (err) {
31208
- console.error(pc39.red("Failed to chat/resume session: " + err.message));
32059
+ console.error(pc40.red("Failed to chat/resume session: " + err.message));
31209
32060
  process.exitCode = 1;
31210
32061
  }
31211
32062
  });
@@ -31213,12 +32064,12 @@ Examples:
31213
32064
 
31214
32065
  // src/commands/qwen-code.ts
31215
32066
  import * as p26 from "@clack/prompts";
31216
- import pc40 from "picocolors";
32067
+ import pc41 from "picocolors";
31217
32068
 
31218
32069
  // src/runtime/qwen-code/index.ts
31219
32070
  init_home();
31220
- import fs43 from "node:fs";
31221
- import path51 from "node:path";
32071
+ import fs46 from "node:fs";
32072
+ import path55 from "node:path";
31222
32073
 
31223
32074
  // src/runtime/qwen-code/contract.ts
31224
32075
  var QWEN_CODE_APPROVAL_MODES = [
@@ -31436,19 +32287,19 @@ function buildSetupGuidance(env) {
31436
32287
 
31437
32288
  // src/runtime/qwen-code/index.ts
31438
32289
  function resolveConfigPath4() {
31439
- return path51.resolve(resolvePaperclipHomeDir(), "qwen-code", "config.json");
32290
+ return path55.resolve(resolvePaperclipHomeDir(), "qwen-code", "config.json");
31440
32291
  }
31441
32292
  function readQwenCodeConfig() {
31442
32293
  const configPath = resolveConfigPath4();
31443
32294
  const storedCredentials = readHarnessCredentials("qwen-code");
31444
- if (!fs43.existsSync(configPath)) {
32295
+ if (!fs46.existsSync(configPath)) {
31445
32296
  return {
31446
32297
  ...DEFAULT_QWEN_CODE_CONFIG,
31447
32298
  env: mergeHarnessEnv(DEFAULT_QWEN_CODE_CONFIG.env, storedCredentials)
31448
32299
  };
31449
32300
  }
31450
32301
  try {
31451
- const raw = JSON.parse(fs43.readFileSync(configPath, "utf-8"));
32302
+ const raw = JSON.parse(fs46.readFileSync(configPath, "utf-8"));
31452
32303
  return {
31453
32304
  binaryPath: typeof raw.binaryPath === "string" ? raw.binaryPath : DEFAULT_QWEN_CODE_CONFIG.binaryPath,
31454
32305
  defaultModel: typeof raw.defaultModel === "string" ? raw.defaultModel : DEFAULT_QWEN_CODE_CONFIG.defaultModel,
@@ -31470,7 +32321,7 @@ function readQwenCodeConfig() {
31470
32321
  }
31471
32322
  function writeQwenCodeConfig(config) {
31472
32323
  const configPath = resolveConfigPath4();
31473
- fs43.mkdirSync(path51.dirname(configPath), { recursive: true });
32324
+ fs46.mkdirSync(path55.dirname(configPath), { recursive: true });
31474
32325
  const rawEnv = typeof config.env === "object" && config.env !== null ? config.env : {};
31475
32326
  const credentialUpdates = {};
31476
32327
  const publicEnv = {};
@@ -31482,7 +32333,7 @@ function writeQwenCodeConfig(config) {
31482
32333
  publicEnv[key] = value;
31483
32334
  }
31484
32335
  setHarnessCredentials("qwen-code", credentialUpdates);
31485
- fs43.writeFileSync(
32336
+ fs46.writeFileSync(
31486
32337
  configPath,
31487
32338
  `${JSON.stringify({ ...config, env: publicEnv }, null, 2)}
31488
32339
  `,
@@ -31508,7 +32359,7 @@ async function runQwenCodeHub(opts) {
31508
32359
  while (true) {
31509
32360
  const config = readQwenCodeConfig();
31510
32361
  const health = checkHealth(config.binaryPath, config.env);
31511
- const statusHint = health.status === "available" ? pc40.green("ready") : health.status === "degraded" ? pc40.yellow("degraded") : pc40.red("unavailable");
32362
+ const statusHint = health.status === "available" ? pc41.green("ready") : health.status === "degraded" ? pc41.yellow("degraded") : pc41.red("unavailable");
31512
32363
  const action = await p26.select({
31513
32364
  message: `Qwen Code CLI (${statusHint})`,
31514
32365
  options: [
@@ -31728,36 +32579,36 @@ function registerQwenCodeCommands(program2) {
31728
32579
 
31729
32580
  // src/commands/t3code.ts
31730
32581
  import * as p28 from "@clack/prompts";
31731
- import pc42 from "picocolors";
32582
+ import pc43 from "picocolors";
31732
32583
 
31733
32584
  // src/runtime/t3code/index.ts
31734
32585
  init_home();
31735
- import fs45 from "node:fs";
31736
- import path53 from "node:path";
32586
+ import fs48 from "node:fs";
32587
+ import path57 from "node:path";
31737
32588
 
31738
32589
  // src/runtime/agent-harness/harness-profile.ts
31739
32590
  init_home();
31740
- import fs44 from "node:fs";
31741
- import path52 from "node:path";
32591
+ import fs47 from "node:fs";
32592
+ import path56 from "node:path";
31742
32593
  import * as p27 from "@clack/prompts";
31743
- import pc41 from "picocolors";
32594
+ import pc42 from "picocolors";
31744
32595
  function resolveProfileDir(harnessId) {
31745
- return path52.resolve(resolvePaperclipHomeDir(), harnessId);
32596
+ return path56.resolve(resolvePaperclipHomeDir(), harnessId);
31746
32597
  }
31747
32598
  function resolveProfilePath(harnessId) {
31748
- return path52.resolve(resolveProfileDir(harnessId), "growthub-profile.json");
32599
+ return path56.resolve(resolveProfileDir(harnessId), "growthub-profile.json");
31749
32600
  }
31750
32601
  function ensureSecureFile2(filePath) {
31751
32602
  try {
31752
- fs44.chmodSync(filePath, 384);
32603
+ fs47.chmodSync(filePath, 384);
31753
32604
  } catch {
31754
32605
  }
31755
32606
  }
31756
32607
  function readHarnessProfile(harnessId) {
31757
32608
  const filePath = resolveProfilePath(harnessId);
31758
- if (!fs44.existsSync(filePath)) return null;
32609
+ if (!fs47.existsSync(filePath)) return null;
31759
32610
  try {
31760
- const raw = JSON.parse(fs44.readFileSync(filePath, "utf-8"));
32611
+ const raw = JSON.parse(fs47.readFileSync(filePath, "utf-8"));
31761
32612
  if (typeof raw.workspaceId !== "string" || typeof raw.machineLabel !== "string") return null;
31762
32613
  return {
31763
32614
  profileVersion: 1,
@@ -31775,32 +32626,32 @@ function readHarnessProfile(harnessId) {
31775
32626
  function writeHarnessProfile(harnessId, profile) {
31776
32627
  const dirPath = resolveProfileDir(harnessId);
31777
32628
  const filePath = resolveProfilePath(harnessId);
31778
- fs44.mkdirSync(dirPath, { recursive: true });
31779
- fs44.writeFileSync(filePath, `${JSON.stringify(profile, null, 2)}
32629
+ fs47.mkdirSync(dirPath, { recursive: true });
32630
+ fs47.writeFileSync(filePath, `${JSON.stringify(profile, null, 2)}
31780
32631
  `, "utf-8");
31781
32632
  ensureSecureFile2(filePath);
31782
32633
  }
31783
32634
  function clearHarnessProfile(harnessId) {
31784
32635
  const filePath = resolveProfilePath(harnessId);
31785
- if (fs44.existsSync(filePath)) fs44.rmSync(filePath);
32636
+ if (fs47.existsSync(filePath)) fs47.rmSync(filePath);
31786
32637
  }
31787
32638
  function buildProfileStatusLines(harnessId, harnessLabel, profile) {
31788
32639
  if (!profile) {
31789
32640
  return [
31790
- `${harnessLabel} Growthub Profile: ${pc41.yellow("not linked")}`,
32641
+ `${harnessLabel} Growthub Profile: ${pc42.yellow("not linked")}`,
31791
32642
  "",
31792
32643
  `Link this harness to a Growthub workspace:`,
31793
32644
  ` growthub ${harnessId} profile link`
31794
32645
  ];
31795
32646
  }
31796
32647
  return [
31797
- `${harnessLabel} Growthub Profile: ${pc41.green("linked")}`,
32648
+ `${harnessLabel} Growthub Profile: ${pc42.green("linked")}`,
31798
32649
  ` Workspace ID : ${profile.workspaceId}`,
31799
32650
  ` Machine : ${profile.machineLabel}`,
31800
- ` Fork binary : ${profile.forkBinaryPath ?? pc41.dim("(using default)")}`,
31801
- ` Fork kit : ${profile.forkKitSlug ?? pc41.dim("(none)")}`,
32651
+ ` Fork binary : ${profile.forkBinaryPath ?? pc42.dim("(using default)")}`,
32652
+ ` Fork kit : ${profile.forkKitSlug ?? pc42.dim("(none)")}`,
31802
32653
  ` Linked at : ${profile.linkedAt}`,
31803
- ` Last sync : ${profile.lastSyncAt ?? pc41.dim("(never synced)")}`
32654
+ ` Last sync : ${profile.lastSyncAt ?? pc42.dim("(never synced)")}`
31804
32655
  ];
31805
32656
  }
31806
32657
  async function runProfileLinkFlow(harnessId, harnessLabel, existing) {
@@ -32063,19 +32914,19 @@ function writeT3GrowthubProfile(profile) {
32063
32914
  writeHarnessProfile(T3_HARNESS_ID, profile);
32064
32915
  }
32065
32916
  function resolveConfigPath5() {
32066
- return path53.resolve(resolvePaperclipHomeDir(), "t3code", "config.json");
32917
+ return path57.resolve(resolvePaperclipHomeDir(), "t3code", "config.json");
32067
32918
  }
32068
32919
  function readT3CodeConfig() {
32069
32920
  const configPath = resolveConfigPath5();
32070
32921
  const storedCredentials = readHarnessCredentials(T3_HARNESS_ID);
32071
- if (!fs45.existsSync(configPath)) {
32922
+ if (!fs48.existsSync(configPath)) {
32072
32923
  return {
32073
32924
  ...DEFAULT_T3_CODE_CONFIG,
32074
32925
  env: mergeHarnessEnv2(DEFAULT_T3_CODE_CONFIG.env, storedCredentials)
32075
32926
  };
32076
32927
  }
32077
32928
  try {
32078
- const raw = JSON.parse(fs45.readFileSync(configPath, "utf-8"));
32929
+ const raw = JSON.parse(fs48.readFileSync(configPath, "utf-8"));
32079
32930
  const profile = readHarnessProfile(T3_HARNESS_ID);
32080
32931
  const resolvedBinaryPath = profile?.forkBinaryPath ?? (typeof raw.binaryPath === "string" ? raw.binaryPath : DEFAULT_T3_CODE_CONFIG.binaryPath);
32081
32932
  return {
@@ -32098,7 +32949,7 @@ function readT3CodeConfig() {
32098
32949
  }
32099
32950
  function writeT3CodeConfig(config) {
32100
32951
  const configPath = resolveConfigPath5();
32101
- fs45.mkdirSync(path53.dirname(configPath), { recursive: true });
32952
+ fs48.mkdirSync(path57.dirname(configPath), { recursive: true });
32102
32953
  const rawEnv = typeof config.env === "object" && config.env !== null ? config.env : {};
32103
32954
  const credentialUpdates = {};
32104
32955
  const publicEnv = {};
@@ -32110,7 +32961,7 @@ function writeT3CodeConfig(config) {
32110
32961
  }
32111
32962
  }
32112
32963
  setHarnessCredentials(T3_HARNESS_ID, credentialUpdates);
32113
- fs45.writeFileSync(
32964
+ fs48.writeFileSync(
32114
32965
  configPath,
32115
32966
  `${JSON.stringify({ ...config, env: publicEnv }, null, 2)}
32116
32967
  `,
@@ -32137,8 +32988,8 @@ async function runT3CodeHub(opts) {
32137
32988
  const config = readT3CodeConfig();
32138
32989
  const health = checkHealth2(config.binaryPath, config.env);
32139
32990
  const profile = readT3GrowthubProfile();
32140
- const statusHint = health.status === "available" ? pc42.green("ready") : health.status === "degraded" ? pc42.yellow("degraded") : pc42.red("unavailable");
32141
- const profileHint = profile ? pc42.green(`linked \u2192 ${profile.workspaceId}`) : pc42.dim("not linked");
32991
+ const statusHint = health.status === "available" ? pc43.green("ready") : health.status === "degraded" ? pc43.yellow("degraded") : pc43.red("unavailable");
32992
+ const profileHint = profile ? pc43.green(`linked \u2192 ${profile.workspaceId}`) : pc43.dim("not linked");
32142
32993
  const action = await p28.select({
32143
32994
  message: `T3 Code CLI (${statusHint})`,
32144
32995
  options: [
@@ -32409,7 +33260,7 @@ init_github();
32409
33260
  // src/commands/integrations.ts
32410
33261
  init_bridge();
32411
33262
  import * as p30 from "@clack/prompts";
32412
- import pc44 from "picocolors";
33263
+ import pc45 from "picocolors";
32413
33264
  async function integrationsStatus(opts = {}) {
32414
33265
  const status = await describeIntegrationBridge();
32415
33266
  if (opts.json) {
@@ -32420,7 +33271,7 @@ async function integrationsStatus(opts = {}) {
32420
33271
  p30.log.warn(status.notice ?? "Not logged into Growthub.");
32421
33272
  return;
32422
33273
  }
32423
- p30.log.message(`Growthub: ${pc44.green("connected")} as ${status.growthubLogin ?? "?"}`);
33274
+ p30.log.message(`Growthub: ${pc45.green("connected")} as ${status.growthubLogin ?? "?"}`);
32424
33275
  if (!status.bridgeAvailable) {
32425
33276
  p30.log.info(status.notice ?? "Hosted integrations endpoint not available.");
32426
33277
  return;
@@ -32430,9 +33281,9 @@ async function integrationsStatus(opts = {}) {
32430
33281
  return;
32431
33282
  }
32432
33283
  for (const i of status.integrations) {
32433
- const ready = i.ready ? pc44.green("ready") : pc44.yellow("reauth needed");
33284
+ const ready = i.ready ? pc45.green("ready") : pc45.yellow("reauth needed");
32434
33285
  p30.log.message(
32435
- ` \u2022 ${pc44.cyan(i.provider)} ${ready} handle=${i.handle ?? "?"} scopes=[${(i.scopes ?? []).join(", ")}]`
33286
+ ` \u2022 ${pc45.cyan(i.provider)} ${ready} handle=${i.handle ?? "?"} scopes=[${(i.scopes ?? []).join(", ")}]`
32436
33287
  );
32437
33288
  }
32438
33289
  }
@@ -32447,7 +33298,7 @@ async function integrationsList(opts = {}) {
32447
33298
  return;
32448
33299
  }
32449
33300
  for (const i of integrations) {
32450
- p30.log.message(`${pc44.cyan(i.provider)} ${i.handle ?? ""} (ready=${i.ready})`);
33301
+ p30.log.message(`${pc45.cyan(i.provider)} ${i.handle ?? ""} (ready=${i.ready})`);
32451
33302
  }
32452
33303
  }
32453
33304
  async function integrationsProbe(opts) {
@@ -32470,7 +33321,7 @@ async function integrationsProbe(opts) {
32470
33321
  return;
32471
33322
  }
32472
33323
  p30.log.success(
32473
- `Resolved ${pc44.cyan(opts.provider)} credential via ${cred.source} handle=${cred.handle ?? "?"} scopes=[${(cred.scopes ?? []).join(", ")}]`
33324
+ `Resolved ${pc45.cyan(opts.provider)} credential via ${cred.source} handle=${cred.handle ?? "?"} scopes=[${(cred.scopes ?? []).join(", ")}]`
32474
33325
  );
32475
33326
  }
32476
33327
  function registerIntegrationsCommands(program2) {
@@ -32488,12 +33339,12 @@ function registerIntegrationsCommands(program2) {
32488
33339
 
32489
33340
  // src/commands/status.ts
32490
33341
  import * as p31 from "@clack/prompts";
32491
- import pc45 from "picocolors";
33342
+ import pc46 from "picocolors";
32492
33343
 
32493
33344
  // src/status/probes.ts
32494
33345
  import { spawnSync as spawnSync5 } from "node:child_process";
32495
- import fs46 from "node:fs";
32496
- import path54 from "node:path";
33346
+ import fs49 from "node:fs";
33347
+ import path58 from "node:path";
32497
33348
  var GITHUB_API = "https://api.github.com";
32498
33349
  var NPM_REGISTRY = "https://registry.npmjs.org";
32499
33350
  function isoNow() {
@@ -32658,7 +33509,7 @@ async function probeKitForksIndex(_timeoutMs) {
32658
33509
  try {
32659
33510
  const { resolveKitForksIndexPath: resolveKitForksIndexPath2 } = await Promise.resolve().then(() => (init_kit_forks_home(), kit_forks_home_exports));
32660
33511
  const p36 = resolveKitForksIndexPath2();
32661
- if (!fs46.existsSync(p36)) {
33512
+ if (!fs49.existsSync(p36)) {
32662
33513
  return {
32663
33514
  componentId: "kit-forks-index",
32664
33515
  level: "operational",
@@ -32666,7 +33517,7 @@ async function probeKitForksIndex(_timeoutMs) {
32666
33517
  lastCheckedAt: isoNow()
32667
33518
  };
32668
33519
  }
32669
- const parsed = JSON.parse(fs46.readFileSync(p36, "utf8"));
33520
+ const parsed = JSON.parse(fs49.readFileSync(p36, "utf8"));
32670
33521
  const count = Array.isArray(parsed.entries) ? parsed.entries.length : 0;
32671
33522
  return {
32672
33523
  componentId: "kit-forks-index",
@@ -32735,10 +33586,10 @@ async function probeNode(_timeoutMs) {
32735
33586
  };
32736
33587
  }
32737
33588
  async function probeReleaseBundleArtifacts(_timeoutMs) {
32738
- const distPath = path54.resolve(process.cwd(), "cli/dist/index.js");
32739
- const installerPath = path54.resolve(process.cwd(), "packages/create-growthub-local/bin/create-growthub-local.mjs");
32740
- const distOk = fs46.existsSync(distPath);
32741
- const installerOk = fs46.existsSync(installerPath);
33589
+ const distPath = path58.resolve(process.cwd(), "cli/dist/index.js");
33590
+ const installerPath = path58.resolve(process.cwd(), "packages/create-growthub-local/bin/create-growthub-local.mjs");
33591
+ const distOk = fs49.existsSync(distPath);
33592
+ const installerOk = fs49.existsSync(installerPath);
32742
33593
  const ok = distOk && installerOk;
32743
33594
  return {
32744
33595
  componentId: "release-bundle",
@@ -32921,25 +33772,25 @@ async function runStatuspageReport(opts = {}) {
32921
33772
  function levelGlyph(level) {
32922
33773
  switch (level) {
32923
33774
  case "operational":
32924
- return pc45.green("\u25CF");
33775
+ return pc46.green("\u25CF");
32925
33776
  case "degraded":
32926
- return pc45.yellow("\u25CF");
33777
+ return pc46.yellow("\u25CF");
32927
33778
  case "outage":
32928
- return pc45.red("\u25CF");
33779
+ return pc46.red("\u25CF");
32929
33780
  default:
32930
- return pc45.dim("\u25CB");
33781
+ return pc46.dim("\u25CB");
32931
33782
  }
32932
33783
  }
32933
33784
  function overallBanner(report) {
32934
33785
  switch (report.overallLevel) {
32935
33786
  case "operational":
32936
- return pc45.green("\u2713 All systems operational");
33787
+ return pc46.green("\u2713 All systems operational");
32937
33788
  case "degraded":
32938
- return pc45.yellow("\u26A0 Degraded \u2014 non-critical issues detected");
33789
+ return pc46.yellow("\u26A0 Degraded \u2014 non-critical issues detected");
32939
33790
  case "outage":
32940
- return pc45.red("\u2717 Outage \u2014 at least one critical component is down");
33791
+ return pc46.red("\u2717 Outage \u2014 at least one critical component is down");
32941
33792
  default:
32942
- return pc45.dim("? Status indeterminate");
33793
+ return pc46.dim("? Status indeterminate");
32943
33794
  }
32944
33795
  }
32945
33796
  function renderHuman(report) {
@@ -32949,14 +33800,14 @@ function renderHuman(report) {
32949
33800
  bucket.push(c);
32950
33801
  byCategory.set(c.category, bucket);
32951
33802
  }
32952
- p31.log.message(`${overallBanner(report)} ${pc45.dim(`(${report.summary})`)}`);
33803
+ p31.log.message(`${overallBanner(report)} ${pc46.dim(`(${report.summary})`)}`);
32953
33804
  for (const [category, list] of byCategory) {
32954
- p31.log.message(pc45.cyan(`
33805
+ p31.log.message(pc46.cyan(`
32955
33806
  ${category}`));
32956
33807
  for (const c of list) {
32957
- const crit = c.critical ? pc45.red("!") : pc45.dim("\xB7");
32958
- const lat = c.latencyMs !== void 0 ? pc45.dim(` ${c.latencyMs}ms`) : "";
32959
- const sa = c.superAdminOnly ? pc45.magenta(" [super-admin]") : "";
33808
+ const crit = c.critical ? pc46.red("!") : pc46.dim("\xB7");
33809
+ const lat = c.latencyMs !== void 0 ? pc46.dim(` ${c.latencyMs}ms`) : "";
33810
+ const sa = c.superAdminOnly ? pc46.magenta(" [super-admin]") : "";
32960
33811
  p31.log.message(` ${levelGlyph(c.level)} ${crit} ${c.label.padEnd(30)} ${c.summary}${lat}${sa}`);
32961
33812
  }
32962
33813
  }
@@ -32984,7 +33835,7 @@ function registerStatusCommands(program2) {
32984
33835
 
32985
33836
  // src/commands/starter.ts
32986
33837
  import * as p32 from "@clack/prompts";
32987
- import pc46 from "picocolors";
33838
+ import pc47 from "picocolors";
32988
33839
  import { pathToFileURL as pathToFileURL3 } from "node:url";
32989
33840
  init_init();
32990
33841
  init_table_renderer();
@@ -32999,15 +33850,15 @@ async function runStarterInit(opts) {
32999
33850
  return;
33000
33851
  }
33001
33852
  p32.outro(
33002
- `Workspace scaffolded at ${pc46.cyan(result.forkPath)}
33853
+ `Workspace scaffolded at ${pc47.cyan(result.forkPath)}
33003
33854
  kitId: ${result.kitId}
33004
- forkId: ${pc46.cyan(result.forkId)}
33855
+ forkId: ${pc47.cyan(result.forkId)}
33005
33856
  baseVersion: ${result.baseVersion}
33006
33857
  open: ${folderOpenLabel2(result.forkPath)}
33007
33858
  policyMode: remoteSyncMode=${result.policyMode}` + (result.remote ? `
33008
- remote: ${pc46.cyan(result.remote.htmlUrl)}` : "") + `
33859
+ remote: ${pc47.cyan(result.remote.htmlUrl)}` : "") + `
33009
33860
 
33010
- Next: ${pc46.dim(`growthub kit fork status ${result.forkId}`)}`
33861
+ Next: ${pc47.dim(`growthub kit fork status ${result.forkId}`)}`
33011
33862
  );
33012
33863
  } catch (err) {
33013
33864
  const msg = err instanceof Error ? err.message : String(err);
@@ -33153,19 +34004,19 @@ function finalizeSuccess(result, jobId) {
33153
34004
  printActivationNudge("import_completed");
33154
34005
  const sourceLine = result.source.kind === "github-repo" ? `${result.source.repo.owner}/${result.source.repo.repo}` : `${result.source.skillId}@${result.source.version}`;
33155
34006
  p32.outro(
33156
- `Imported ${sourceLine} into ${pc46.cyan(result.forkPath)}
33157
- jobId: ${pc46.cyan(jobId)}
34007
+ `Imported ${sourceLine} into ${pc47.cyan(result.forkPath)}
34008
+ jobId: ${pc47.cyan(jobId)}
33158
34009
  importId: ${result.importId}
33159
- forkId: ${pc46.cyan(result.forkId)}
34010
+ forkId: ${pc47.cyan(result.forkId)}
33160
34011
  kitId: ${result.kitId}
33161
34012
  sourceKind: ${result.sourceKind}
33162
34013
  importMode: ${result.importMode}
33163
34014
  detection: framework=${result.detection.framework} pm=${result.detection.packageManager} confidence=${result.detection.confidence}
33164
34015
  security: ${formatSecuritySummary(result)}
33165
- summary: ${pc46.dim(result.summaryPath)}
33166
- manifest: ${pc46.dim(result.manifestPath)}
34016
+ summary: ${pc47.dim(result.summaryPath)}
34017
+ manifest: ${pc47.dim(result.manifestPath)}
33167
34018
 
33168
- Next: ${pc46.dim(`growthub kit fork status ${result.forkId}`)}`
34019
+ Next: ${pc47.dim(`growthub kit fork status ${result.forkId}`)}`
33169
34020
  );
33170
34021
  }
33171
34022
  function scopeLabel(scope) {
@@ -33213,7 +34064,7 @@ async function runBrowseSkills(opts) {
33213
34064
  })
33214
34065
  );
33215
34066
  for (const entry of result.entries) {
33216
- p32.log.message(`${pc46.bold(entry.skillId)} ${pc46.dim(entry.htmlUrl)}`);
34067
+ p32.log.message(`${pc47.bold(entry.skillId)} ${pc47.dim(entry.htmlUrl)}`);
33217
34068
  }
33218
34069
  } catch (err) {
33219
34070
  const msg = err instanceof Error ? err.message : String(err);
@@ -33292,22 +34143,22 @@ function registerStarterCommands(program2) {
33292
34143
 
33293
34144
  // src/commands/skills.ts
33294
34145
  init_catalog2();
33295
- import fs59 from "node:fs";
33296
- import path67 from "node:path";
33297
- import pc47 from "picocolors";
34146
+ import fs62 from "node:fs";
34147
+ import path71 from "node:path";
34148
+ import pc48 from "picocolors";
33298
34149
 
33299
34150
  // src/skills/session-memory.ts
33300
34151
  init_frontmatter();
33301
- import fs58 from "node:fs";
33302
- import path66 from "node:path";
34152
+ import fs61 from "node:fs";
34153
+ import path70 from "node:path";
33303
34154
  var PROJECT_MD_RELATIVE2 = ".growthub-fork/project.md";
33304
34155
  function resolveProjectMdPath(forkPath) {
33305
- return path66.resolve(forkPath, PROJECT_MD_RELATIVE2);
34156
+ return path70.resolve(forkPath, PROJECT_MD_RELATIVE2);
33306
34157
  }
33307
34158
  function readSessionMemory(forkPath) {
33308
34159
  const projectMdPath = resolveProjectMdPath(forkPath);
33309
- if (!fs58.existsSync(projectMdPath)) return null;
33310
- const raw = fs58.readFileSync(projectMdPath, "utf8");
34160
+ if (!fs61.existsSync(projectMdPath)) return null;
34161
+ const raw = fs61.readFileSync(projectMdPath, "utf8");
33311
34162
  const sizeBytes = Buffer.byteLength(raw, "utf8");
33312
34163
  try {
33313
34164
  const { frontmatter, body } = readFrontmatter(raw);
@@ -33325,9 +34176,9 @@ init_kit_forks_home();
33325
34176
  init_table_renderer();
33326
34177
  function readLocalForkHead(forkPath) {
33327
34178
  const p36 = resolveInForkRegistrationPath(forkPath);
33328
- if (!fs59.existsSync(p36)) return null;
34179
+ if (!fs62.existsSync(p36)) return null;
33329
34180
  try {
33330
- const parsed = JSON.parse(fs59.readFileSync(p36, "utf8"));
34181
+ const parsed = JSON.parse(fs62.readFileSync(p36, "utf8"));
33331
34182
  if (typeof parsed.forkId !== "string" || typeof parsed.kitId !== "string") return null;
33332
34183
  return { forkId: parsed.forkId, kitId: parsed.kitId };
33333
34184
  } catch {
@@ -33335,7 +34186,7 @@ function readLocalForkHead(forkPath) {
33335
34186
  }
33336
34187
  }
33337
34188
  function resolveRoot(optRoot) {
33338
- if (optRoot) return path67.resolve(optRoot);
34189
+ if (optRoot) return path71.resolve(optRoot);
33339
34190
  return process.cwd();
33340
34191
  }
33341
34192
  function runList(opts) {
@@ -33357,13 +34208,13 @@ function runList(opts) {
33357
34208
  return;
33358
34209
  }
33359
34210
  if (result.entries.length === 0) {
33360
- console.log(pc47.dim(`No SKILL.md found under ${result.catalog.root}`));
34211
+ console.log(pc48.dim(`No SKILL.md found under ${result.catalog.root}`));
33361
34212
  return;
33362
34213
  }
33363
34214
  const rows = result.entries.map((e) => ({
33364
34215
  name: e.manifest.name,
33365
34216
  source: e.source,
33366
- skillPath: path67.relative(result.catalog.root ?? "", e.skillPath),
34217
+ skillPath: path71.relative(result.catalog.root ?? "", e.skillPath),
33367
34218
  triggers: e.manifest.triggers?.length ?? 0,
33368
34219
  helpers: e.manifest.helpers?.length ?? 0,
33369
34220
  subSkills: e.manifest.subSkills?.length ?? 0,
@@ -33383,9 +34234,9 @@ function runList(opts) {
33383
34234
  }));
33384
34235
  if (result.warnings.length > 0) {
33385
34236
  console.log("");
33386
- console.log(pc47.yellow(`${result.warnings.length} warning(s):`));
34237
+ console.log(pc48.yellow(`${result.warnings.length} warning(s):`));
33387
34238
  for (const w of result.warnings) {
33388
- console.log(pc47.yellow(` - ${path67.relative(result.catalog.root ?? "", w.skillPath)}: ${w.reason}`));
34239
+ console.log(pc48.yellow(` - ${path71.relative(result.catalog.root ?? "", w.skillPath)}: ${w.reason}`));
33389
34240
  }
33390
34241
  }
33391
34242
  }
@@ -33412,10 +34263,10 @@ function runValidate(opts) {
33412
34263
  severity: "error"
33413
34264
  });
33414
34265
  }
33415
- const skillDir = path67.dirname(entry.skillPath);
34266
+ const skillDir = path71.dirname(entry.skillPath);
33416
34267
  for (const helper of m.helpers ?? []) {
33417
- const helperPath = path67.resolve(skillDir, helper.path);
33418
- if (!fs59.existsSync(helperPath)) {
34268
+ const helperPath = path71.resolve(skillDir, helper.path);
34269
+ if (!fs62.existsSync(helperPath)) {
33419
34270
  issues2.push({
33420
34271
  skillPath: entry.skillPath,
33421
34272
  reason: `helpers[].path missing on disk: ${helper.path}`,
@@ -33424,8 +34275,8 @@ function runValidate(opts) {
33424
34275
  }
33425
34276
  }
33426
34277
  for (const sub of m.subSkills ?? []) {
33427
- const subPath = path67.resolve(skillDir, sub.path);
33428
- if (!fs59.existsSync(subPath)) {
34278
+ const subPath = path71.resolve(skillDir, sub.path);
34279
+ if (!fs62.existsSync(subPath)) {
33429
34280
  issues2.push({
33430
34281
  skillPath: entry.skillPath,
33431
34282
  reason: `subSkills[].path missing on disk: ${sub.path}`,
@@ -33455,14 +34306,14 @@ function runValidate(opts) {
33455
34306
  process.exitCode = issues2.filter((i) => i.severity === "error").length === 0 ? 0 : 1;
33456
34307
  return;
33457
34308
  }
33458
- console.log(pc47.bold(`Validated ${result.entries.length} skill(s) under ${root}`));
34309
+ console.log(pc48.bold(`Validated ${result.entries.length} skill(s) under ${root}`));
33459
34310
  if (issues2.length === 0) {
33460
- console.log(pc47.green("OK \u2014 no issues."));
34311
+ console.log(pc48.green("OK \u2014 no issues."));
33461
34312
  return;
33462
34313
  }
33463
34314
  for (const issue of issues2) {
33464
- const rel = path67.relative(root, issue.skillPath);
33465
- const tag = issue.severity === "error" ? pc47.red("[error] ") : pc47.yellow("[warning]");
34315
+ const rel = path71.relative(root, issue.skillPath);
34316
+ const tag = issue.severity === "error" ? pc48.red("[error] ") : pc48.yellow("[warning]");
33466
34317
  console.log(`${tag} ${rel}: ${issue.reason}`);
33467
34318
  }
33468
34319
  const errors = issues2.filter((i) => i.severity === "error").length;
@@ -33483,7 +34334,7 @@ function runSessionInit(opts) {
33483
34334
  console.log(JSON.stringify({ status: "error", error: err }));
33484
34335
  process.exitCode = 1;
33485
34336
  } else {
33486
- console.error(pc47.red(err));
34337
+ console.error(pc48.red(err));
33487
34338
  process.exitCode = 1;
33488
34339
  }
33489
34340
  return;
@@ -33513,13 +34364,13 @@ function runSessionInit(opts) {
33513
34364
  return;
33514
34365
  }
33515
34366
  if (result.written) {
33516
- console.log(pc47.green(`Seeded ${path67.relative(forkPath, result.projectMdPath)}`));
34367
+ console.log(pc48.green(`Seeded ${path71.relative(forkPath, result.projectMdPath)}`));
33517
34368
  } else if (!result.templatePath) {
33518
- console.log(pc47.yellow(
34369
+ console.log(pc48.yellow(
33519
34370
  `Kit tree does not ship templates/project.md \u2014 this kit has not been upgraded to the v1.2 primitives yet. No seed written; session memory can still be maintained manually.`
33520
34371
  ));
33521
34372
  } else {
33522
- console.log(pc47.dim(`${path67.relative(forkPath, result.projectMdPath)} already present; left untouched.`));
34373
+ console.log(pc48.dim(`${path71.relative(forkPath, result.projectMdPath)} already present; left untouched.`));
33523
34374
  }
33524
34375
  }
33525
34376
  function runSessionShow(opts) {
@@ -33532,7 +34383,7 @@ function runSessionShow(opts) {
33532
34383
  process.exitCode = 1;
33533
34384
  return;
33534
34385
  }
33535
- console.error(pc47.yellow(err));
34386
+ console.error(pc48.yellow(err));
33536
34387
  process.exitCode = 1;
33537
34388
  return;
33538
34389
  }
@@ -33549,8 +34400,8 @@ function runSessionShow(opts) {
33549
34400
  ));
33550
34401
  return;
33551
34402
  }
33552
- console.log(pc47.bold(head.path));
33553
- console.log(pc47.dim(`${head.sizeBytes} bytes`));
34403
+ console.log(pc48.bold(head.path));
34404
+ console.log(pc48.dim(`${head.sizeBytes} bytes`));
33554
34405
  if (head.frontmatter) {
33555
34406
  for (const [k, v] of Object.entries(head.frontmatter)) {
33556
34407
  if (Array.isArray(v)) {
@@ -33567,7 +34418,7 @@ function runSessionShow(opts) {
33567
34418
  console.log(head.body);
33568
34419
  } else {
33569
34420
  console.log("");
33570
- console.log(pc47.dim("(pass --body to print the markdown body)"));
34421
+ console.log(pc48.dim("(pass --body to print the markdown body)"));
33571
34422
  }
33572
34423
  }
33573
34424
  function registerSkillsCommands(program2) {
@@ -33582,11 +34433,11 @@ function registerSkillsCommands(program2) {
33582
34433
  // src/commands/fleet.ts
33583
34434
  init_fork_registry();
33584
34435
  import * as p33 from "@clack/prompts";
33585
- import pc48 from "picocolors";
34436
+ import pc49 from "picocolors";
33586
34437
 
33587
34438
  // src/fleet/summary.ts
33588
34439
  init_fork_registry();
33589
- import fs60 from "node:fs";
34440
+ import fs63 from "node:fs";
33590
34441
  init_fork_policy();
33591
34442
  init_fork_trace();
33592
34443
  function classifyHealth(drift, pendingConfirmationJobs, lastJobStatus) {
@@ -33606,7 +34457,7 @@ var REMOTE_EVENT_TYPES = /* @__PURE__ */ new Set([
33606
34457
  "conflict_encountered"
33607
34458
  ]);
33608
34459
  function buildForkSummary(reg) {
33609
- if (!fs60.existsSync(reg.forkPath)) {
34460
+ if (!fs63.existsSync(reg.forkPath)) {
33610
34461
  return {
33611
34462
  forkId: reg.forkId,
33612
34463
  kitId: reg.kitId,
@@ -33915,17 +34766,17 @@ init_fork_policy();
33915
34766
  function healthGlyph(level) {
33916
34767
  switch (level) {
33917
34768
  case "clean":
33918
- return pc48.green("\u25CF");
34769
+ return pc49.green("\u25CF");
33919
34770
  case "drift-minor":
33920
- return pc48.cyan("\u25CF");
34771
+ return pc49.cyan("\u25CF");
33921
34772
  case "drift-major":
33922
- return pc48.yellow("\u25CF");
34773
+ return pc49.yellow("\u25CF");
33923
34774
  case "awaiting-confirmation":
33924
- return pc48.magenta("\u25D0");
34775
+ return pc49.magenta("\u25D0");
33925
34776
  case "error":
33926
- return pc48.red("\u25CF");
34777
+ return pc49.red("\u25CF");
33927
34778
  default:
33928
- return pc48.dim("\u25CB");
34779
+ return pc49.dim("\u25CB");
33929
34780
  }
33930
34781
  }
33931
34782
  function truncate4(s, n) {
@@ -33939,7 +34790,7 @@ async function fleetView(opts) {
33939
34790
  return;
33940
34791
  }
33941
34792
  p33.log.message(
33942
- `Fleet: ${pc48.cyan(String(fleet.totalForks))} fork(s) | remote=${fleet.forksWithRemote} awaiting=${fleet.forksAwaitingConfirmation} pending-approvals=${fleet.pendingApprovalCount}`
34793
+ `Fleet: ${pc49.cyan(String(fleet.totalForks))} fork(s) | remote=${fleet.forksWithRemote} awaiting=${fleet.forksAwaitingConfirmation} pending-approvals=${fleet.pendingApprovalCount}`
33943
34794
  );
33944
34795
  p33.log.message(
33945
34796
  ` Health \u2192 clean=${fleet.byHealth.clean} drift-minor=${fleet.byHealth["drift-minor"]} drift-major=${fleet.byHealth["drift-major"]} awaiting=${fleet.byHealth["awaiting-confirmation"]} error=${fleet.byHealth.error} unknown=${fleet.byHealth.unknown}`
@@ -33956,10 +34807,10 @@ function renderForkRow(f) {
33956
34807
  const base = f.baseVersion.padEnd(8);
33957
34808
  const upstream = (f.upstreamVersion ?? "?").padEnd(8);
33958
34809
  const driftCounts = `files=${f.fileDriftCount} pkgs=${f.packageDriftCount}`;
33959
- const pending = f.pendingConfirmationJobs > 0 ? pc48.magenta(` awaits=${f.pendingConfirmationJobs}`) : "";
33960
- const remote = f.remote ? pc48.dim(` ${f.remote.owner}/${f.remote.repo}`) : "";
34810
+ const pending = f.pendingConfirmationJobs > 0 ? pc49.magenta(` awaits=${f.pendingConfirmationJobs}`) : "";
34811
+ const remote = f.remote ? pc49.dim(` ${f.remote.owner}/${f.remote.repo}`) : "";
33961
34812
  p33.log.message(
33962
- ` ${healthGlyph(f.health)} ${label} ${pc48.dim(kit)} ${base} \u2192 ${upstream} ${pc48.dim(driftCounts)}${pending}${remote}`
34813
+ ` ${healthGlyph(f.health)} ${label} ${pc49.dim(kit)} ${base} \u2192 ${upstream} ${pc49.dim(driftCounts)}${pending}${remote}`
33963
34814
  );
33964
34815
  }
33965
34816
  async function fleetDrift(opts) {
@@ -33974,7 +34825,7 @@ async function fleetDrift(opts) {
33974
34825
  return;
33975
34826
  }
33976
34827
  p33.log.message(
33977
- `Fleet drift: ${pc48.cyan(String(withDrift.length))} of ${fleet.totalForks} fork(s) have drift.`
34828
+ `Fleet drift: ${pc49.cyan(String(withDrift.length))} of ${fleet.totalForks} fork(s) have drift.`
33978
34829
  );
33979
34830
  p33.log.message(
33980
34831
  ` By severity \u2192 none=${fleet.bySeverity.none} info=${fleet.bySeverity.info} warning=${fleet.bySeverity.warning} critical=${fleet.bySeverity.critical}`
@@ -33994,7 +34845,7 @@ async function fleetDriftSummary(opts) {
33994
34845
  console.log(JSON.stringify({ summary, narrative }, null, 2));
33995
34846
  return;
33996
34847
  }
33997
- p33.log.message(pc48.cyan(`Drift summary \u2014 ${reg.forkId} (${summary.fromVersion} \u2192 ${summary.toVersion})`));
34848
+ p33.log.message(pc49.cyan(`Drift summary \u2014 ${reg.forkId} (${summary.fromVersion} \u2192 ${summary.toVersion})`));
33998
34849
  for (const line of narrative) p33.log.message(` ${line}`);
33999
34850
  const sections = [
34000
34851
  ["safe additions", summary.buckets.safeAdditions],
@@ -34007,13 +34858,13 @@ async function fleetDriftSummary(opts) {
34007
34858
  ];
34008
34859
  for (const [label, items] of sections) {
34009
34860
  if (items.length === 0) continue;
34010
- p33.log.message(pc48.dim(` \u2014 ${label} (${items.length}) \u2014`));
34011
- for (const item of items) p33.log.message(` \xB7 ${item.path} ${pc48.dim(item.note)}`);
34861
+ p33.log.message(pc49.dim(` \u2014 ${label} (${items.length}) \u2014`));
34862
+ for (const item of items) p33.log.message(` \xB7 ${item.path} ${pc49.dim(item.note)}`);
34012
34863
  }
34013
34864
  if (summary.buckets.packageAdditions.length || summary.buckets.packageUpgrades.length) {
34014
- p33.log.message(pc48.dim(` \u2014 dependency drift \u2014`));
34865
+ p33.log.message(pc49.dim(` \u2014 dependency drift \u2014`));
34015
34866
  for (const d of summary.buckets.packageAdditions) {
34016
- p33.log.message(` + ${d.packageName}@${d.toVersion} ${pc48.dim("(added upstream)")}`);
34867
+ p33.log.message(` + ${d.packageName}@${d.toVersion} ${pc49.dim("(added upstream)")}`);
34017
34868
  }
34018
34869
  for (const d of summary.buckets.packageUpgrades) {
34019
34870
  p33.log.message(` \u2191 ${d.packageName} ${d.fromVersion ?? "?"} \u2192 ${d.toVersion}`);
@@ -34039,14 +34890,14 @@ async function fleetPolicy(opts) {
34039
34890
  console.log(JSON.stringify({ count: rows.length, rows }, null, 2));
34040
34891
  return;
34041
34892
  }
34042
- p33.log.message(pc48.cyan(`Fleet policy matrix (${rows.length} fork(s))`));
34893
+ p33.log.message(pc49.cyan(`Fleet policy matrix (${rows.length} fork(s))`));
34043
34894
  for (const r of rows) {
34044
34895
  const label = truncate4(r.label ?? r.forkId, 28).padEnd(28);
34045
34896
  const aa = r.autoApprove.padEnd(9);
34046
34897
  const ad = r.autoApproveDepUpdates.padEnd(9);
34047
34898
  const rs = r.remoteSyncMode.padEnd(6);
34048
34899
  const ut = String(r.untouchableCount).padStart(3);
34049
- const remote = r.hasRemote ? pc48.green("+") : pc48.dim("\xB7");
34900
+ const remote = r.hasRemote ? pc49.green("+") : pc49.dim("\xB7");
34050
34901
  p33.log.message(
34051
34902
  ` ${label} autoApprove=${aa} deps=${ad} remote=${rs} untouchable=${ut} ${remote}`
34052
34903
  );
@@ -34062,19 +34913,19 @@ async function fleetApprovals(opts) {
34062
34913
  p33.log.success("Approval queue is empty.");
34063
34914
  return;
34064
34915
  }
34065
- p33.log.message(pc48.cyan(`Approval queue: ${queue.length} job(s) awaiting confirmation`));
34916
+ p33.log.message(pc49.cyan(`Approval queue: ${queue.length} job(s) awaiting confirmation`));
34066
34917
  for (const entry of queue) {
34067
34918
  p33.log.message(
34068
- ` \xB7 ${pc48.cyan(entry.jobId)} fork=${entry.forkLabel ?? entry.forkId} created=${entry.createdAt.slice(0, 19)}`
34919
+ ` \xB7 ${pc49.cyan(entry.jobId)} fork=${entry.forkLabel ?? entry.forkId} created=${entry.createdAt.slice(0, 19)}`
34069
34920
  );
34070
- for (const path71 of entry.pendingPaths.slice(0, 6)) {
34071
- p33.log.message(` ${pc48.dim("awaits")} ${path71}`);
34921
+ for (const path75 of entry.pendingPaths.slice(0, 6)) {
34922
+ p33.log.message(` ${pc49.dim("awaits")} ${path75}`);
34072
34923
  }
34073
34924
  if (entry.pendingPaths.length > 6) {
34074
- p33.log.message(` ${pc48.dim(`\u2026 +${entry.pendingPaths.length - 6} more`)}`);
34925
+ p33.log.message(` ${pc49.dim(`\u2026 +${entry.pendingPaths.length - 6} more`)}`);
34075
34926
  }
34076
34927
  p33.log.message(
34077
- ` ${pc48.dim("resume:")} growthub kit fork confirm --job-id ${entry.jobId}`
34928
+ ` ${pc49.dim("resume:")} growthub kit fork confirm --job-id ${entry.jobId}`
34078
34929
  );
34079
34930
  }
34080
34931
  }
@@ -34086,20 +34937,20 @@ async function fleetAgentPlan(opts) {
34086
34937
  console.log(JSON.stringify(doc, null, 2));
34087
34938
  return;
34088
34939
  }
34089
- p33.log.message(pc48.cyan(`Agent heal plan \u2014 ${reg.forkId}`));
34940
+ p33.log.message(pc49.cyan(`Agent heal plan \u2014 ${reg.forkId}`));
34090
34941
  p33.log.message(` ${doc.summary}`);
34091
34942
  for (const line of doc.narrative) p33.log.message(` ${line}`);
34092
34943
  if (doc.awaitsConfirmation.length > 0) {
34093
- p33.log.message(pc48.magenta(` Awaiting confirmation on:`));
34944
+ p33.log.message(pc49.magenta(` Awaiting confirmation on:`));
34094
34945
  for (const p210 of doc.awaitsConfirmation) p33.log.message(` \xB7 ${p210}`);
34095
34946
  p33.log.message(
34096
- pc48.dim(
34947
+ pc49.dim(
34097
34948
  ` Next: growthub kit fork heal ${reg.forkId} (will park in awaiting_confirmation until resumed)`
34098
34949
  )
34099
34950
  );
34100
34951
  } else if (doc.plan.actions.length > 0) {
34101
34952
  p33.log.message(
34102
- pc48.dim(` Next: growthub kit fork heal ${reg.forkId} (${doc.plan.actions.length} safe action(s) ready)`)
34953
+ pc49.dim(` Next: growthub kit fork heal ${reg.forkId} (${doc.plan.actions.length} safe action(s) ready)`)
34103
34954
  );
34104
34955
  }
34105
34956
  }
@@ -34154,21 +35005,21 @@ var DEFAULT_MEMORY_PROVIDER_CONFIG = {
34154
35005
 
34155
35006
  // src/runtime/memory/store.ts
34156
35007
  init_home();
34157
- import fs61 from "node:fs";
34158
- import path68 from "node:path";
35008
+ import fs64 from "node:fs";
35009
+ import path72 from "node:path";
34159
35010
  function toProjectSlug(project) {
34160
35011
  return project.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "default";
34161
35012
  }
34162
35013
  function resolveProjectPath(project) {
34163
- return path68.resolve(resolveMemoryProjectsDir(), `${toProjectSlug(project)}.json`);
35014
+ return path72.resolve(resolveMemoryProjectsDir(), `${toProjectSlug(project)}.json`);
34164
35015
  }
34165
35016
  function loadMemoryDatabase(project) {
34166
35017
  const filePath = resolveProjectPath(project);
34167
- if (!fs61.existsSync(filePath)) {
35018
+ if (!fs64.existsSync(filePath)) {
34168
35019
  return { version: 1, project, observations: [], summaries: [], nextObservationId: 1, nextSummaryId: 1 };
34169
35020
  }
34170
35021
  try {
34171
- const raw = JSON.parse(fs61.readFileSync(filePath, "utf-8"));
35022
+ const raw = JSON.parse(fs64.readFileSync(filePath, "utf-8"));
34172
35023
  return {
34173
35024
  version: 1,
34174
35025
  project,
@@ -34183,9 +35034,9 @@ function loadMemoryDatabase(project) {
34183
35034
  }
34184
35035
  function saveMemoryDatabase(db) {
34185
35036
  const dir = resolveMemoryProjectsDir();
34186
- fs61.mkdirSync(dir, { recursive: true });
35037
+ fs64.mkdirSync(dir, { recursive: true });
34187
35038
  const filePath = resolveProjectPath(db.project);
34188
- fs61.writeFileSync(filePath, `${JSON.stringify(db, null, 2)}
35039
+ fs64.writeFileSync(filePath, `${JSON.stringify(db, null, 2)}
34189
35040
  `, "utf-8");
34190
35041
  }
34191
35042
  function addObservation(project, input) {
@@ -34279,8 +35130,8 @@ function incrementRelevanceCount(project, observationId) {
34279
35130
  }
34280
35131
  function listMemoryProjects() {
34281
35132
  const dir = resolveMemoryProjectsDir();
34282
- if (!fs61.existsSync(dir)) return [];
34283
- return fs61.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, "")).sort();
35133
+ if (!fs64.existsSync(dir)) return [];
35134
+ return fs64.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, "")).sort();
34284
35135
  }
34285
35136
  function getMemoryStats(project) {
34286
35137
  const db = loadMemoryDatabase(project);
@@ -34292,15 +35143,15 @@ function getMemoryStats(project) {
34292
35143
  };
34293
35144
  }
34294
35145
  function resolveProviderConfigPath() {
34295
- return path68.resolve(resolveMemoryDir(), "provider-config.json");
35146
+ return path72.resolve(resolveMemoryDir(), "provider-config.json");
34296
35147
  }
34297
35148
  function readProviderConfig() {
34298
35149
  const filePath = resolveProviderConfigPath();
34299
- if (!fs61.existsSync(filePath)) {
35150
+ if (!fs64.existsSync(filePath)) {
34300
35151
  return { ...DEFAULT_MEMORY_PROVIDER_CONFIG };
34301
35152
  }
34302
35153
  try {
34303
- const raw = JSON.parse(fs61.readFileSync(filePath, "utf-8"));
35154
+ const raw = JSON.parse(fs64.readFileSync(filePath, "utf-8"));
34304
35155
  return {
34305
35156
  provider: validateProvider(raw.provider),
34306
35157
  apiKey: typeof raw.apiKey === "string" ? raw.apiKey : void 0,
@@ -34313,9 +35164,9 @@ function readProviderConfig() {
34313
35164
  }
34314
35165
  function writeProviderConfig(config) {
34315
35166
  const dir = resolveMemoryDir();
34316
- fs61.mkdirSync(dir, { recursive: true });
35167
+ fs64.mkdirSync(dir, { recursive: true });
34317
35168
  const filePath = resolveProviderConfigPath();
34318
- fs61.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}
35169
+ fs64.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}
34319
35170
  `, { mode: 384 });
34320
35171
  }
34321
35172
  function validateProvider(value) {
@@ -34694,14 +35545,14 @@ async function syncMemoriesToHosted(project, options) {
34694
35545
  init_llm();
34695
35546
  function resolveCliVersion() {
34696
35547
  try {
34697
- const moduleDir = path70.dirname(fileURLToPath7(import.meta.url));
35548
+ const moduleDir = path74.dirname(fileURLToPath7(import.meta.url));
34698
35549
  const candidates = [
34699
- path70.resolve(moduleDir, "../package.json"),
34700
- path70.resolve(moduleDir, "../../package.json")
35550
+ path74.resolve(moduleDir, "../package.json"),
35551
+ path74.resolve(moduleDir, "../../package.json")
34701
35552
  ];
34702
35553
  for (const candidate of candidates) {
34703
- if (!fs63.existsSync(candidate)) continue;
34704
- const parsed = JSON.parse(fs63.readFileSync(candidate, "utf8"));
35554
+ if (!fs66.existsSync(candidate)) continue;
35555
+ const parsed = JSON.parse(fs66.readFileSync(candidate, "utf8"));
34705
35556
  if (parsed?.name === "@growthub/cli" && typeof parsed.version === "string") return parsed.version;
34706
35557
  }
34707
35558
  } catch {
@@ -34745,7 +35596,7 @@ function registerSharedCommands(target) {
34745
35596
  });
34746
35597
  target.command("allowed-hostname").description("Allow a hostname for authenticated/private mode access").argument("<host>", "Hostname to allow (for example dotta-macbook-pro)").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).action(addAllowedHostname);
34747
35598
  target.command("run").description("Bootstrap local setup (onboard + doctor) and run Growthub").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("-i, --instance <id>", "Local instance id (default: default)").option("--repair", "Attempt automatic repairs during doctor", true).option("--no-repair", "Disable automatic repairs during doctor").action(runCommand);
34748
- target.command("discover").description("Shared discovery entry for local app install, worker kits, and templates").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--run", "Start Growthub immediately after saving config", false).action(async (opts) => {
35599
+ target.command("discover").description("Shared discovery entry for local app install, worker kits, and templates").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--run", "Start Growthub immediately after saving config", false).option("--start <surface>", "Start in a discovery surface, e.g. create-workspace").action(async (opts) => {
34749
35600
  await runDiscoveryHub(opts);
34750
35601
  });
34751
35602
  registerKitCommands(target);
@@ -34753,6 +35604,7 @@ function registerSharedCommands(target) {
34753
35604
  registerCapabilityCommands(target);
34754
35605
  registerPipelineCommands(target);
34755
35606
  registerArtifactCommands(target);
35607
+ registerBridgeCommands(target);
34756
35608
  registerWorkflowCommands(target);
34757
35609
  registerOpenAgentsCommands(target);
34758
35610
  registerQwenCodeCommands(target);
@@ -34928,7 +35780,7 @@ async function runMarketingContextBuilder(baseUrl, model) {
34928
35780
  });
34929
35781
  if (p35.isCancel(projectDir)) return;
34930
35782
  const dir = String(projectDir).trim() || process.cwd();
34931
- if (!fs63.existsSync(dir)) {
35783
+ if (!fs66.existsSync(dir)) {
34932
35784
  p35.note(`Directory not found: ${dir}`, "Marketing Context Builder");
34933
35785
  return;
34934
35786
  }
@@ -34941,10 +35793,10 @@ async function runMarketingContextBuilder(baseUrl, model) {
34941
35793
  endpoint: baseUrl.replace(/\/v1$/, "") + "/v1/chat/completions",
34942
35794
  localModel: model
34943
35795
  });
34944
- const health = await checkBackendHealth(backend);
35796
+ const health = await checkBackendHealth(config);
34945
35797
  const input = { projectDir: dir };
34946
35798
  let result;
34947
- if (health.ok) {
35799
+ if (health.available) {
34948
35800
  result = await buildMarketingContext(input, backend);
34949
35801
  } else {
34950
35802
  result = buildDeterministicContext(input);
@@ -34964,10 +35816,10 @@ async function runMarketingContextBuilder(baseUrl, model) {
34964
35816
  p35.note("Draft was not saved. You can copy it from the output above.", "Marketing Context Builder");
34965
35817
  return;
34966
35818
  }
34967
- const outDir = path70.resolve(dir, ".agents");
34968
- fs63.mkdirSync(outDir, { recursive: true });
34969
- const outPath = path70.resolve(outDir, "product-marketing-context.md");
34970
- fs63.writeFileSync(outPath, result.contextMarkdown, "utf-8");
35819
+ const outDir = path74.resolve(dir, ".agents");
35820
+ fs66.mkdirSync(outDir, { recursive: true });
35821
+ const outPath = path74.resolve(outDir, "product-marketing-context.md");
35822
+ fs66.writeFileSync(outPath, result.contextMarkdown, "utf-8");
34971
35823
  p35.note(`Saved to: ${outPath}
34972
35824
 
34973
35825
  Review the file and replace [NEEDS INPUT] placeholders with real data.`, "Marketing Context Builder");
@@ -35176,39 +36028,39 @@ function captureSessionSummary(project, sessionId, messages) {
35176
36028
  }
35177
36029
  }
35178
36030
  function resolveLocalThreadsDir() {
35179
- return path70.resolve(resolvePaperclipHomeDir(), "native-intelligence", "threads");
36031
+ return path74.resolve(resolvePaperclipHomeDir(), "native-intelligence", "threads");
35180
36032
  }
35181
36033
  function loadOrCreateLocalThread() {
35182
36034
  const dir = resolveLocalThreadsDir();
35183
- fs63.mkdirSync(dir, { recursive: true });
35184
- const activePath = path70.resolve(dir, "active-thread.json");
35185
- if (fs63.existsSync(activePath)) {
36035
+ fs66.mkdirSync(dir, { recursive: true });
36036
+ const activePath = path74.resolve(dir, "active-thread.json");
36037
+ if (fs66.existsSync(activePath)) {
35186
36038
  try {
35187
- const parsed = JSON.parse(fs63.readFileSync(activePath, "utf-8"));
36039
+ const parsed = JSON.parse(fs66.readFileSync(activePath, "utf-8"));
35188
36040
  const id2 = typeof parsed.id === "string" && parsed.id.length > 0 ? parsed.id : `thread-${Date.now()}`;
35189
- const threadFile = path70.resolve(dir, `${id2}.json`);
36041
+ const threadFile = path74.resolve(dir, `${id2}.json`);
35190
36042
  const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
35191
36043
  return { id: id2, filePath: threadFile, messages };
35192
36044
  } catch {
35193
36045
  }
35194
36046
  }
35195
36047
  const id = `thread-${Date.now()}`;
35196
- const filePath = path70.resolve(dir, `${id}.json`);
36048
+ const filePath = path74.resolve(dir, `${id}.json`);
35197
36049
  const thread = { id, filePath, messages: [] };
35198
36050
  saveLocalThread(thread);
35199
36051
  return thread;
35200
36052
  }
35201
36053
  function saveLocalThread(thread) {
35202
36054
  const dir = resolveLocalThreadsDir();
35203
- fs63.mkdirSync(dir, { recursive: true });
35204
- fs63.writeFileSync(
36055
+ fs66.mkdirSync(dir, { recursive: true });
36056
+ fs66.writeFileSync(
35205
36057
  thread.filePath,
35206
36058
  `${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
35207
36059
  `,
35208
36060
  "utf-8"
35209
36061
  );
35210
- const activePath = path70.resolve(dir, "active-thread.json");
35211
- fs63.writeFileSync(
36062
+ const activePath = path74.resolve(dir, "active-thread.json");
36063
+ fs66.writeFileSync(
35212
36064
  activePath,
35213
36065
  `${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
35214
36066
  `,
@@ -35354,7 +36206,7 @@ async function collectBindingsFromContract(contract, promptSeed) {
35354
36206
  return bindings;
35355
36207
  }
35356
36208
  function resolveCurrentProject() {
35357
- return path70.basename(process.cwd());
36209
+ return path74.basename(process.cwd());
35358
36210
  }
35359
36211
  async function runMemoryKnowledgeHub() {
35360
36212
  const project = resolveCurrentProject();
@@ -35387,7 +36239,7 @@ async function runMemoryKnowledgeHub() {
35387
36239
  },
35388
36240
  {
35389
36241
  value: "sync",
35390
- label: syncStatus.available ? "Sync to Growthub" : "Sync to Growthub" + pc50.dim(" (unavailable)"),
36242
+ label: syncStatus.available ? "Sync to Growthub" : "Sync to Growthub" + pc51.dim(" (unavailable)"),
35391
36243
  hint: syncStatus.available ? "push memories to hosted account" : syncStatus.reason
35392
36244
  },
35393
36245
  { value: "__back_to_hub", label: "\u2190 Back to main menu" }
@@ -35505,34 +36357,126 @@ API key: ${result.apiKey ? "configured" : "not needed"}`,
35505
36357
  }
35506
36358
  }
35507
36359
  }
36360
+ async function runCreateGovernedWorkspaceFlow(opts) {
36361
+ workspaceLoop: while (true) {
36362
+ const starterChoice = await p35.select({
36363
+ message: opts?.firstRun ? "What do you want to create?" : opts?.title ?? "Create Governed Workspace",
36364
+ options: [
36365
+ ...opts?.importOnly ? [] : [
36366
+ {
36367
+ value: "new-greenfield",
36368
+ label: opts?.firstRun ? "\u{1F680} New governed workspace" : "\u{1F680} New greenfield workspace",
36369
+ hint: "Scaffold a fresh governed workspace"
36370
+ }
36371
+ ],
36372
+ {
36373
+ value: "import-github",
36374
+ label: opts?.firstRun ? "\u{1F517} Import GitHub repository" : "\u{1F517} Import GitHub repository",
36375
+ hint: "Import a public or private repo via the Source Import Agent"
36376
+ },
36377
+ {
36378
+ value: "import-skill",
36379
+ label: opts?.firstRun ? "\u{1F9E0} Import skills.sh skill" : "\u{1F9E0} Import skills.sh skill",
36380
+ hint: "Discover live skills, inspect metadata, then import the selected skill"
36381
+ },
36382
+ ...opts?.importOnly ? [] : [
36383
+ {
36384
+ value: "worker-kit",
36385
+ label: opts?.firstRun ? "\u{1F9F0} Start from worker kit" : "\u{1F9F0} Start from worker kit",
36386
+ hint: "Browse worker kits and materialize one locally"
36387
+ }
36388
+ ],
36389
+ opts?.firstRun ? { value: "__full_menu", label: "\u{1F440} Open full discovery menu" } : { value: "__back", label: opts?.backLabel ?? "\u2190 Back" }
36390
+ ],
36391
+ initialValue: opts?.firstRun ? "new-greenfield" : void 0
36392
+ });
36393
+ if (p35.isCancel(starterChoice)) {
36394
+ p35.cancel("Cancelled.");
36395
+ process.exit(0);
36396
+ }
36397
+ if (starterChoice === "__full_menu") return "full-menu";
36398
+ if (starterChoice === "__back") return "back";
36399
+ if (starterChoice === "new-greenfield") {
36400
+ const outRaw = await p35.text({
36401
+ message: "Destination path for the new workspace (will be created if missing):",
36402
+ placeholder: "./my-workspace"
36403
+ });
36404
+ if (p35.isCancel(outRaw) || !outRaw) continue workspaceLoop;
36405
+ const nameRaw = await p35.text({
36406
+ message: "Optional label (leave blank to use directory basename):",
36407
+ placeholder: ""
36408
+ });
36409
+ if (p35.isCancel(nameRaw)) continue workspaceLoop;
36410
+ await runStarterInit({ out: String(outRaw), name: nameRaw ? String(nameRaw) : void 0 });
36411
+ continue workspaceLoop;
36412
+ }
36413
+ if (starterChoice === "import-github") {
36414
+ const repoRaw = await p35.text({
36415
+ message: "GitHub repo (owner/repo or https URL):",
36416
+ placeholder: "octocat/Hello-World"
36417
+ });
36418
+ if (p35.isCancel(repoRaw) || !repoRaw) continue workspaceLoop;
36419
+ const {
36420
+ promptForInteractiveWorkspacePath: promptForInteractiveWorkspacePath2,
36421
+ startSourceImportFlow: startSourceImportFlow2
36422
+ } = await Promise.resolve().then(() => (init_source_import_discovery(), source_import_discovery_exports));
36423
+ const outPath = await promptForInteractiveWorkspacePath2({
36424
+ kind: "github-repo",
36425
+ repo: String(repoRaw),
36426
+ out: ""
36427
+ });
36428
+ if (!outPath) continue workspaceLoop;
36429
+ await startSourceImportFlow2({
36430
+ kind: "github-repo",
36431
+ repo: String(repoRaw),
36432
+ out: outPath
36433
+ });
36434
+ continue workspaceLoop;
36435
+ }
36436
+ if (starterChoice === "import-skill") {
36437
+ const { startSkillsSourceImportFlow: startSkillsSourceImportFlow2 } = await Promise.resolve().then(() => (init_source_import_discovery(), source_import_discovery_exports));
36438
+ await startSkillsSourceImportFlow2();
36439
+ continue workspaceLoop;
36440
+ }
36441
+ if (starterChoice === "worker-kit") {
36442
+ const result = await runInteractivePicker({ allowBackToHub: true });
36443
+ if (result === "back") continue workspaceLoop;
36444
+ return "done";
36445
+ }
36446
+ }
36447
+ }
35508
36448
  async function runDiscoveryHub(opts) {
35509
36449
  track("discover_opened");
35510
36450
  printPaperclipCliBanner();
35511
36451
  p35.intro("Growthub Local");
36452
+ if (opts?.start === "create-workspace") {
36453
+ const result = await runCreateGovernedWorkspaceFlow({ firstRun: true });
36454
+ if (result === "done") return;
36455
+ }
35512
36456
  while (true) {
35513
36457
  const workflowAccess = getWorkflowAccess();
35514
36458
  const surfaceChoice = await p35.select({
35515
36459
  message: "What do you want to do first?",
35516
36460
  options: [
35517
36461
  {
35518
- value: "kits",
35519
- label: "\u{1F9F0} Worker Kits",
35520
- hint: "Self-contained workspace environments for agents"
36462
+ value: "create-workspace",
36463
+ label: "\u{1F680} Create Governed Workspace",
36464
+ hint: "Start from a repo, skills.sh skill, starter, or worker kit"
35521
36465
  },
35522
36466
  {
35523
- value: "templates",
35524
- label: "\u{1F4DA} Templates",
35525
- hint: "Artifact template library"
36467
+ value: "kits",
36468
+ label: "\u{1F9F0} Browse Worker Kits",
36469
+ hint: "Self-contained workspace environments for agents"
35526
36470
  },
35527
36471
  {
35528
- value: "workflows",
35529
- label: workflowAccess.state === "ready" ? "\u{1F517} Workflows" : "\u{1F517} Workflows" + pc50.dim(" (locked)"),
35530
- hint: workflowAccess.state === "ready" ? "CMS contracts, dynamic pipelines, and saved workflows" : workflowAccess.reason
36472
+ value: "import-source",
36473
+ label: "\u{1F501} Import Repo or Skill",
36474
+ hint: "Build a governed workspace from GitHub or skills.sh"
35531
36475
  },
35532
36476
  {
35533
- value: "native-intelligence",
35534
- label: "\u{1F9E0} Local Intelligence",
35535
- hint: "use local custom models adapaters"
36477
+ value: "memory-knowledge",
36478
+ label: "\u{1F4D6} Memory & Knowledge",
36479
+ hint: "persistent memory, search, multi-provider config, Growthub sync"
35536
36480
  },
35537
36481
  {
35538
36482
  value: "agent-harness",
@@ -35542,12 +36486,7 @@ async function runDiscoveryHub(opts) {
35542
36486
  {
35543
36487
  value: "settings",
35544
36488
  label: "\u2699\uFE0F Settings",
35545
- hint: "GitHub, Fork Sync, Integrations, Service Status, Starter, Fleet"
35546
- },
35547
- {
35548
- value: "memory-knowledge",
35549
- label: "\u{1F4D6} Memory & Knowledge",
35550
- hint: "persistent memory, search, multi-provider config, Growthub sync"
36489
+ hint: "GitHub, Fork Sync, workflows, templates, local models, service status"
35551
36490
  },
35552
36491
  {
35553
36492
  value: "help",
@@ -35564,10 +36503,10 @@ async function runDiscoveryHub(opts) {
35564
36503
  p35.note(
35565
36504
  [
35566
36505
  "\u{1F916} Agent Harness: filter by type \u2014 Paperclip Local App (GTM/DX profiles), Open Agents (durable workflow orchestration), Qwen Code CLI, or T3 Code CLI (pingdotgg/t3code).",
35567
- "\u{1F9F0} Worker Kits: browse specialized agents and custom workspaces.",
35568
- "\u{1F4DA} Templates: browse reusable artifact templates by library type.",
35569
- "\u{1F517} Workflows: browse CMS contracts, create dynamic pipelines, and manage saved workflows.",
35570
- "\u{1F9E0} Local Intelligence: use local custom models adapaters: inspect Gemma health, view intelligence tree, and run sample summary checks.",
36506
+ "\u{1F680} Create Governed Workspace: start from a repo, skills.sh skill, greenfield starter, or worker kit.",
36507
+ "\u{1F9F0} Browse Worker Kits: browse specialized agents and custom workspaces.",
36508
+ "\u{1F501} Import Repo or Skill: route directly into the Source Import Agent.",
36509
+ "\u2699\uFE0F Settings: GitHub, Fork Sync, workflows, templates, local models, service status, starter, fleet.",
35571
36510
  "\u{1F4D6} Memory & Knowledge: persistent cross-session memory, search observations, multi-provider AI config, sync to Growthub.",
35572
36511
  ` Locked state: ${workflowAccess.reason}.`,
35573
36512
  "\u{1F500} Fork Sync Agent: register, track, and heal your forked worker kits \u2014 preserves all customisations while syncing to the latest upstream version.",
@@ -35595,6 +36534,16 @@ async function runDiscoveryHub(opts) {
35595
36534
  );
35596
36535
  continue;
35597
36536
  }
36537
+ if (surfaceChoice === "create-workspace") {
36538
+ const result = await runCreateGovernedWorkspaceFlow();
36539
+ if (result === "done") return;
36540
+ continue;
36541
+ }
36542
+ if (surfaceChoice === "import-source") {
36543
+ const result = await runCreateGovernedWorkspaceFlow({ importOnly: true, title: "Import Repo or Skill" });
36544
+ if (result === "done") return;
36545
+ continue;
36546
+ }
35598
36547
  if (surfaceChoice === "agent-harness") {
35599
36548
  while (true) {
35600
36549
  const harnessType = await p35.select({
@@ -35777,8 +36726,23 @@ async function runDiscoveryHub(opts) {
35777
36726
  },
35778
36727
  {
35779
36728
  value: "custom-workspace-starter",
35780
- label: "\u{1F9EA} Custom Workspace Starter",
35781
- hint: "Scaffold a new forked worker kit with v1 Self-Healing Fork Sync wiring"
36729
+ label: "\u{1F680} Create Governed Workspace",
36730
+ hint: "Start from a repo, skills.sh skill, starter, or worker kit"
36731
+ },
36732
+ {
36733
+ value: "workflows",
36734
+ label: workflowAccess.state === "ready" ? "\u{1F517} Workflows" : "\u{1F517} Workflows" + pc51.dim(" (locked)"),
36735
+ hint: workflowAccess.state === "ready" ? "CMS contracts, dynamic pipelines, and saved workflows" : workflowAccess.reason
36736
+ },
36737
+ {
36738
+ value: "templates",
36739
+ label: "\u{1F4DA} Templates",
36740
+ hint: "Artifact template library"
36741
+ },
36742
+ {
36743
+ value: "native-intelligence",
36744
+ label: "\u{1F9E0} Local Intelligence",
36745
+ hint: "Use local custom model adapters"
35782
36746
  },
35783
36747
  {
35784
36748
  value: "fleet-ops",
@@ -35812,8 +36776,8 @@ async function runDiscoveryHub(opts) {
35812
36776
  continue;
35813
36777
  }
35814
36778
  if (surfaceChoice2 === "fork-sync") {
35815
- const result2 = await runKitForkHub({ allowBackToHub: true });
35816
- if (result2 === "back") continue;
36779
+ const result = await runKitForkHub({ allowBackToHub: true });
36780
+ if (result === "back") continue;
35817
36781
  break;
35818
36782
  }
35819
36783
  if (surfaceChoice2 === "service-status") {
@@ -35821,78 +36785,24 @@ async function runDiscoveryHub(opts) {
35821
36785
  continue;
35822
36786
  }
35823
36787
  if (surfaceChoice2 === "custom-workspace-starter") {
35824
- starterLoop: while (true) {
35825
- const starterChoice = await p35.select({
35826
- message: "Custom Workspace Starter",
35827
- options: [
35828
- {
35829
- value: "new-greenfield",
35830
- label: "\u{1F9EA} New greenfield workspace",
35831
- hint: "Scaffold a fresh starter-derived fork (no source import)"
35832
- },
35833
- {
35834
- value: "import-github",
35835
- label: "\u{1F419} Build from GitHub repository",
35836
- hint: "Import a public or private repo via the Source Import Agent"
35837
- },
35838
- {
35839
- value: "import-skill",
35840
- label: "\u{1F9E0} Build from skills.sh",
35841
- hint: "Discover live skills, inspect metadata, then import the selected skill"
35842
- },
35843
- { value: "__back", label: "\u2190 Back to Settings" }
35844
- ]
35845
- });
35846
- if (p35.isCancel(starterChoice)) {
35847
- p35.cancel("Cancelled.");
35848
- process.exit(0);
35849
- }
35850
- if (starterChoice === "__back") break starterLoop;
35851
- if (starterChoice === "new-greenfield") {
35852
- const outRaw = await p35.text({
35853
- message: "Destination path for the new workspace (will be created if missing):",
35854
- placeholder: "./my-workspace"
35855
- });
35856
- if (p35.isCancel(outRaw) || !outRaw) continue starterLoop;
35857
- const nameRaw = await p35.text({
35858
- message: "Optional label (leave blank to use directory basename):",
35859
- placeholder: ""
35860
- });
35861
- if (p35.isCancel(nameRaw)) continue starterLoop;
35862
- await runStarterInit({ out: String(outRaw), name: nameRaw ? String(nameRaw) : void 0 });
35863
- continue starterLoop;
35864
- }
35865
- if (starterChoice === "import-github") {
35866
- const repoRaw = await p35.text({
35867
- message: "GitHub repo (owner/repo or https URL):",
35868
- placeholder: "octocat/Hello-World"
35869
- });
35870
- if (p35.isCancel(repoRaw) || !repoRaw) continue starterLoop;
35871
- const {
35872
- promptForInteractiveWorkspacePath: promptForInteractiveWorkspacePath2,
35873
- startSourceImportFlow: startSourceImportFlow2
35874
- } = await Promise.resolve().then(() => (init_source_import_discovery(), source_import_discovery_exports));
35875
- const outPath = await promptForInteractiveWorkspacePath2({
35876
- kind: "github-repo",
35877
- repo: String(repoRaw),
35878
- out: ""
35879
- });
35880
- if (!outPath) continue starterLoop;
35881
- await startSourceImportFlow2({
35882
- kind: "github-repo",
35883
- repo: String(repoRaw),
35884
- out: outPath
35885
- });
35886
- continue starterLoop;
35887
- }
35888
- if (starterChoice === "import-skill") {
35889
- const { startSkillsSourceImportFlow: startSkillsSourceImportFlow2 } = await Promise.resolve().then(() => (init_source_import_discovery(), source_import_discovery_exports));
35890
- await startSkillsSourceImportFlow2();
35891
- continue starterLoop;
35892
- }
35893
- }
36788
+ await runCreateGovernedWorkspaceFlow({ backLabel: "\u2190 Back to Settings" });
35894
36789
  continue;
35895
36790
  }
36791
+ if (surfaceChoice2 === "workflows") {
36792
+ const result = await runWorkflowPicker({ allowBackToHub: true });
36793
+ if (result === "back") continue;
36794
+ return;
36795
+ }
36796
+ if (surfaceChoice2 === "templates") {
36797
+ const result = await runTemplatePicker({ allowBackToHub: true });
36798
+ if (result === "back") continue;
36799
+ return;
36800
+ }
36801
+ if (surfaceChoice2 === "native-intelligence") {
36802
+ const result = await runNativeIntelligenceHub();
36803
+ if (result === "back") continue;
36804
+ return;
36805
+ }
35896
36806
  if (surfaceChoice2 === "fleet-ops") {
35897
36807
  await fleetView({});
35898
36808
  continue;
@@ -35902,9 +36812,9 @@ async function runDiscoveryHub(opts) {
35902
36812
  const catalog = readSkillCatalog2({ root: process.cwd() });
35903
36813
  p35.note(
35904
36814
  [
35905
- `Root: ${pc50.cyan(catalog.catalog.root ?? process.cwd())}`,
35906
- `Skills discovered: ${pc50.bold(String(catalog.entries.length))}`,
35907
- catalog.warnings.length > 0 ? `Warnings: ${pc50.yellow(String(catalog.warnings.length))}` : `Warnings: 0`,
36815
+ `Root: ${pc51.cyan(catalog.catalog.root ?? process.cwd())}`,
36816
+ `Skills discovered: ${pc51.bold(String(catalog.entries.length))}`,
36817
+ catalog.warnings.length > 0 ? `Warnings: ${pc51.yellow(String(catalog.warnings.length))}` : `Warnings: 0`,
35908
36818
  "",
35909
36819
  "Invoke directly:",
35910
36820
  " growthub skills list --json",
@@ -35920,28 +36830,15 @@ async function runDiscoveryHub(opts) {
35920
36830
  continue;
35921
36831
  }
35922
36832
  if (surfaceChoice === "kits") {
35923
- const result2 = await runInteractivePicker({ allowBackToHub: true });
35924
- if (result2 === "back") continue;
35925
- return;
35926
- }
35927
- if (surfaceChoice === "workflows") {
35928
- const result2 = await runWorkflowPicker({ allowBackToHub: true });
35929
- if (result2 === "back") continue;
35930
- return;
35931
- }
35932
- if (surfaceChoice === "native-intelligence") {
35933
- const result2 = await runNativeIntelligenceHub();
35934
- if (result2 === "back") continue;
36833
+ const result = await runInteractivePicker({ allowBackToHub: true });
36834
+ if (result === "back") continue;
35935
36835
  return;
35936
36836
  }
35937
36837
  if (surfaceChoice === "memory-knowledge") {
35938
- const result2 = await runMemoryKnowledgeHub();
35939
- if (result2 === "back") continue;
36838
+ const result = await runMemoryKnowledgeHub();
36839
+ if (result === "back") continue;
35940
36840
  return;
35941
36841
  }
35942
- const result = await runTemplatePicker({ allowBackToHub: true });
35943
- if (result === "back") continue;
35944
- return;
35945
36842
  }
35946
36843
  }
35947
36844
  function isInstallerMode() {
@@ -35949,12 +36846,12 @@ function isInstallerMode() {
35949
36846
  }
35950
36847
  function listLocalSurfaces() {
35951
36848
  const homeDir = resolvePaperclipHomeDir();
35952
- const instancesDir = path70.resolve(homeDir, "instances");
35953
- if (!fs63.existsSync(instancesDir)) return [];
35954
- return fs63.readdirSync(instancesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
36849
+ const instancesDir = path74.resolve(homeDir, "instances");
36850
+ if (!fs66.existsSync(instancesDir)) return [];
36851
+ return fs66.readdirSync(instancesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
35955
36852
  const instanceId = entry.name;
35956
- const configPath = path70.resolve(instancesDir, instanceId, "config.json");
35957
- if (!fs63.existsSync(configPath)) return null;
36853
+ const configPath = path74.resolve(instancesDir, instanceId, "config.json");
36854
+ if (!fs66.existsSync(configPath)) return null;
35958
36855
  try {
35959
36856
  const config = readConfig(configPath);
35960
36857
  if (!config) return null;