@growthub/cli 0.7.4 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1099 -933
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9,6 +9,188 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
+ // src/config/home.ts
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+ function resolvePaperclipHomeDir() {
16
+ const envHome = process.env.PAPERCLIP_HOME?.trim();
17
+ if (envHome) return path.resolve(expandHomePrefix(envHome));
18
+ return path.resolve(os.homedir(), ".paperclip");
19
+ }
20
+ function resolvePaperclipInstanceId(override) {
21
+ const raw = override?.trim() || process.env.PAPERCLIP_INSTANCE_ID?.trim() || DEFAULT_INSTANCE_ID;
22
+ if (!INSTANCE_ID_RE.test(raw)) {
23
+ throw new Error(
24
+ `Invalid instance id '${raw}'. Allowed characters: letters, numbers, '_' and '-'.`
25
+ );
26
+ }
27
+ return raw;
28
+ }
29
+ function resolvePaperclipInstanceRoot(instanceId) {
30
+ const id = resolvePaperclipInstanceId(instanceId);
31
+ return path.resolve(resolvePaperclipHomeDir(), "instances", id);
32
+ }
33
+ function resolveDefaultConfigPath(instanceId) {
34
+ return path.resolve(resolvePaperclipInstanceRoot(instanceId), "config.json");
35
+ }
36
+ function resolveDefaultContextPath() {
37
+ return path.resolve(resolvePaperclipHomeDir(), "context.json");
38
+ }
39
+ function resolveDefaultEmbeddedPostgresDir(instanceId) {
40
+ return path.resolve(resolvePaperclipInstanceRoot(instanceId), "db");
41
+ }
42
+ function resolveDefaultLogsDir(instanceId) {
43
+ return path.resolve(resolvePaperclipInstanceRoot(instanceId), "logs");
44
+ }
45
+ function resolveDefaultSecretsKeyFilePath(instanceId) {
46
+ return path.resolve(resolvePaperclipInstanceRoot(instanceId), "secrets", "master.key");
47
+ }
48
+ function resolveDefaultStorageDir(instanceId) {
49
+ return path.resolve(resolvePaperclipInstanceRoot(instanceId), "data", "storage");
50
+ }
51
+ function resolveDefaultBackupDir(instanceId) {
52
+ return path.resolve(resolvePaperclipInstanceRoot(instanceId), "data", "backups");
53
+ }
54
+ function resolveMemoryDir() {
55
+ return path.resolve(resolvePaperclipHomeDir(), "memory");
56
+ }
57
+ function resolveMemoryProjectsDir() {
58
+ return path.resolve(resolveMemoryDir(), "projects");
59
+ }
60
+ function expandHomePrefix(value) {
61
+ if (value === "~") return os.homedir();
62
+ if (value.startsWith("~/")) return path.resolve(os.homedir(), value.slice(2));
63
+ return value;
64
+ }
65
+ function describeLocalInstancePaths(instanceId) {
66
+ const resolvedInstanceId = resolvePaperclipInstanceId(instanceId);
67
+ const instanceRoot = resolvePaperclipInstanceRoot(resolvedInstanceId);
68
+ return {
69
+ homeDir: resolvePaperclipHomeDir(),
70
+ instanceId: resolvedInstanceId,
71
+ instanceRoot,
72
+ configPath: resolveDefaultConfigPath(resolvedInstanceId),
73
+ embeddedPostgresDataDir: resolveDefaultEmbeddedPostgresDir(resolvedInstanceId),
74
+ backupDir: resolveDefaultBackupDir(resolvedInstanceId),
75
+ logDir: resolveDefaultLogsDir(resolvedInstanceId),
76
+ secretsKeyFilePath: resolveDefaultSecretsKeyFilePath(resolvedInstanceId),
77
+ storageDir: resolveDefaultStorageDir(resolvedInstanceId)
78
+ };
79
+ }
80
+ var DEFAULT_INSTANCE_ID, INSTANCE_ID_RE;
81
+ var init_home = __esm({
82
+ "src/config/home.ts"() {
83
+ "use strict";
84
+ DEFAULT_INSTANCE_ID = "default";
85
+ INSTANCE_ID_RE = /^[a-zA-Z0-9_-]+$/;
86
+ }
87
+ });
88
+
89
+ // src/auth/paths.ts
90
+ import path2 from "node:path";
91
+ function resolveAuthDir() {
92
+ return path2.resolve(resolvePaperclipHomeDir(), "auth");
93
+ }
94
+ function resolveProfilesDir() {
95
+ return path2.resolve(resolvePaperclipHomeDir(), "profiles");
96
+ }
97
+ function resolveSessionPath() {
98
+ return path2.resolve(resolveAuthDir(), "session.json");
99
+ }
100
+ function resolveHostedOverlayPath() {
101
+ return path2.resolve(resolveProfilesDir(), "hosted-overlay.json");
102
+ }
103
+ function resolveEffectiveProfilePath() {
104
+ return path2.resolve(resolveProfilesDir(), "effective-profile.json");
105
+ }
106
+ var init_paths = __esm({
107
+ "src/auth/paths.ts"() {
108
+ "use strict";
109
+ init_home();
110
+ }
111
+ });
112
+
113
+ // src/auth/session-store.ts
114
+ var session_store_exports = {};
115
+ __export(session_store_exports, {
116
+ clearSession: () => clearSession,
117
+ describeSessionPath: () => describeSessionPath,
118
+ isSessionExpired: () => isSessionExpired,
119
+ readSession: () => readSession,
120
+ writeSession: () => writeSession
121
+ });
122
+ import fs from "node:fs";
123
+ import path3 from "node:path";
124
+ function parseJson(filePath) {
125
+ try {
126
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
127
+ } catch (err) {
128
+ throw new Error(
129
+ `Failed to parse auth session at ${filePath}: ${err instanceof Error ? err.message : String(err)}`
130
+ );
131
+ }
132
+ }
133
+ function toStringOrUndefined(value) {
134
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
135
+ }
136
+ function normalizeSession(raw) {
137
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
138
+ const record = raw;
139
+ const accessToken = toStringOrUndefined(record.accessToken);
140
+ const hostedBaseUrl = toStringOrUndefined(record.hostedBaseUrl);
141
+ if (!accessToken || !hostedBaseUrl) return null;
142
+ const issuedAt = toStringOrUndefined(record.issuedAt) ?? (/* @__PURE__ */ new Date()).toISOString();
143
+ return {
144
+ version: 1,
145
+ hostedBaseUrl,
146
+ accessToken,
147
+ expiresAt: toStringOrUndefined(record.expiresAt),
148
+ userId: toStringOrUndefined(record.userId),
149
+ email: toStringOrUndefined(record.email),
150
+ orgId: toStringOrUndefined(record.orgId),
151
+ orgName: toStringOrUndefined(record.orgName),
152
+ machineLabel: toStringOrUndefined(record.machineLabel),
153
+ issuedAt
154
+ };
155
+ }
156
+ function readSession() {
157
+ const filePath = resolveSessionPath();
158
+ if (!fs.existsSync(filePath)) return null;
159
+ const raw = parseJson(filePath);
160
+ return normalizeSession(raw);
161
+ }
162
+ function writeSession(session) {
163
+ const filePath = resolveSessionPath();
164
+ fs.mkdirSync(resolveAuthDir(), { recursive: true });
165
+ fs.writeFileSync(filePath, `${JSON.stringify(session, null, 2)}
166
+ `, { mode: 384 });
167
+ try {
168
+ fs.chmodSync(filePath, 384);
169
+ } catch {
170
+ }
171
+ }
172
+ function clearSession() {
173
+ const filePath = resolveSessionPath();
174
+ if (!fs.existsSync(filePath)) return false;
175
+ fs.rmSync(filePath, { force: true });
176
+ return true;
177
+ }
178
+ function isSessionExpired(session, now = /* @__PURE__ */ new Date()) {
179
+ if (!session.expiresAt) return false;
180
+ const expires = Date.parse(session.expiresAt);
181
+ if (Number.isNaN(expires)) return false;
182
+ return expires <= now.getTime();
183
+ }
184
+ function describeSessionPath() {
185
+ return path3.resolve(resolveSessionPath());
186
+ }
187
+ var init_session_store = __esm({
188
+ "src/auth/session-store.ts"() {
189
+ "use strict";
190
+ init_paths();
191
+ }
192
+ });
193
+
12
194
  // ../packages/shared/src/constants.ts
13
195
  var COMPANY_STATUSES, DEPLOYMENT_MODES, DEPLOYMENT_EXPOSURES, AUTH_BASE_URL_MODES, SURFACE_PROFILES, AGENT_STATUSES, AGENT_ADAPTER_TYPES, AGENT_ROLES, AGENT_ICON_NAMES, TICKET_STAGE_KINDS, TICKET_STAGE_HANDOFF_MODES, TICKET_STATUSES, ISSUE_STATUSES, ISSUE_PRIORITIES, GOAL_LEVELS, GOAL_STATUSES, PROJECT_STATUSES, APPROVAL_TYPES, SECRET_PROVIDERS, STORAGE_PROVIDERS, BILLING_TYPES, FINANCE_EVENT_KINDS, FINANCE_DIRECTIONS, FINANCE_UNITS, BUDGET_SCOPE_TYPES, BUDGET_METRICS, BUDGET_WINDOW_KINDS, BUDGET_INCIDENT_RESOLUTION_ACTIONS, INVITE_JOIN_TYPES, JOIN_REQUEST_TYPES, JOIN_REQUEST_STATUSES, PERMISSION_KEYS, PLUGIN_STATUSES, PLUGIN_CATEGORIES, PLUGIN_CAPABILITIES, PLUGIN_UI_SLOT_TYPES, PLUGIN_RESERVED_COMPANY_ROUTE_SEGMENTS, PLUGIN_LAUNCHER_PLACEMENT_ZONES, PLUGIN_LAUNCHER_ACTIONS, PLUGIN_LAUNCHER_BOUNDS, PLUGIN_LAUNCHER_RENDER_ENVIRONMENTS, PLUGIN_UI_SLOT_ENTITY_TYPES, PLUGIN_STATE_SCOPE_KINDS;
14
196
  var init_constants = __esm({
@@ -2084,108 +2266,31 @@ var init_schema = __esm({
2084
2266
  }
2085
2267
  });
2086
2268
 
2087
- // src/config/home.ts
2088
- import os from "node:os";
2089
- import path from "node:path";
2090
- function resolvePaperclipHomeDir() {
2091
- const envHome = process.env.PAPERCLIP_HOME?.trim();
2092
- if (envHome) return path.resolve(expandHomePrefix(envHome));
2093
- return path.resolve(os.homedir(), ".paperclip");
2094
- }
2095
- function resolvePaperclipInstanceId(override) {
2096
- const raw = override?.trim() || process.env.PAPERCLIP_INSTANCE_ID?.trim() || DEFAULT_INSTANCE_ID;
2097
- if (!INSTANCE_ID_RE.test(raw)) {
2098
- throw new Error(
2099
- `Invalid instance id '${raw}'. Allowed characters: letters, numbers, '_' and '-'.`
2100
- );
2101
- }
2102
- return raw;
2103
- }
2104
- function resolvePaperclipInstanceRoot(instanceId) {
2105
- const id = resolvePaperclipInstanceId(instanceId);
2106
- return path.resolve(resolvePaperclipHomeDir(), "instances", id);
2107
- }
2108
- function resolveDefaultConfigPath(instanceId) {
2109
- return path.resolve(resolvePaperclipInstanceRoot(instanceId), "config.json");
2110
- }
2111
- function resolveDefaultContextPath() {
2112
- return path.resolve(resolvePaperclipHomeDir(), "context.json");
2113
- }
2114
- function resolveDefaultEmbeddedPostgresDir(instanceId) {
2115
- return path.resolve(resolvePaperclipInstanceRoot(instanceId), "db");
2116
- }
2117
- function resolveDefaultLogsDir(instanceId) {
2118
- return path.resolve(resolvePaperclipInstanceRoot(instanceId), "logs");
2119
- }
2120
- function resolveDefaultSecretsKeyFilePath(instanceId) {
2121
- return path.resolve(resolvePaperclipInstanceRoot(instanceId), "secrets", "master.key");
2122
- }
2123
- function resolveDefaultStorageDir(instanceId) {
2124
- return path.resolve(resolvePaperclipInstanceRoot(instanceId), "data", "storage");
2125
- }
2126
- function resolveDefaultBackupDir(instanceId) {
2127
- return path.resolve(resolvePaperclipInstanceRoot(instanceId), "data", "backups");
2128
- }
2129
- function resolveMemoryDir() {
2130
- return path.resolve(resolvePaperclipHomeDir(), "memory");
2131
- }
2132
- function resolveMemoryProjectsDir() {
2133
- return path.resolve(resolveMemoryDir(), "projects");
2134
- }
2135
- function expandHomePrefix(value) {
2136
- if (value === "~") return os.homedir();
2137
- if (value.startsWith("~/")) return path.resolve(os.homedir(), value.slice(2));
2138
- return value;
2139
- }
2140
- function describeLocalInstancePaths(instanceId) {
2141
- const resolvedInstanceId = resolvePaperclipInstanceId(instanceId);
2142
- const instanceRoot = resolvePaperclipInstanceRoot(resolvedInstanceId);
2143
- return {
2144
- homeDir: resolvePaperclipHomeDir(),
2145
- instanceId: resolvedInstanceId,
2146
- instanceRoot,
2147
- configPath: resolveDefaultConfigPath(resolvedInstanceId),
2148
- embeddedPostgresDataDir: resolveDefaultEmbeddedPostgresDir(resolvedInstanceId),
2149
- backupDir: resolveDefaultBackupDir(resolvedInstanceId),
2150
- logDir: resolveDefaultLogsDir(resolvedInstanceId),
2151
- secretsKeyFilePath: resolveDefaultSecretsKeyFilePath(resolvedInstanceId),
2152
- storageDir: resolveDefaultStorageDir(resolvedInstanceId)
2153
- };
2154
- }
2155
- var DEFAULT_INSTANCE_ID, INSTANCE_ID_RE;
2156
- var init_home = __esm({
2157
- "src/config/home.ts"() {
2158
- "use strict";
2159
- DEFAULT_INSTANCE_ID = "default";
2160
- INSTANCE_ID_RE = /^[a-zA-Z0-9_-]+$/;
2161
- }
2162
- });
2163
-
2164
2269
  // src/config/store.ts
2165
- import fs from "node:fs";
2166
- import path2 from "node:path";
2270
+ import fs3 from "node:fs";
2271
+ import path5 from "node:path";
2167
2272
  function findConfigFileFromAncestors(startDir) {
2168
- const absoluteStartDir = path2.resolve(startDir);
2273
+ const absoluteStartDir = path5.resolve(startDir);
2169
2274
  let currentDir = absoluteStartDir;
2170
2275
  while (true) {
2171
- const candidate = path2.resolve(currentDir, ".paperclip", DEFAULT_CONFIG_BASENAME);
2172
- if (fs.existsSync(candidate)) {
2276
+ const candidate = path5.resolve(currentDir, ".paperclip", DEFAULT_CONFIG_BASENAME);
2277
+ if (fs3.existsSync(candidate)) {
2173
2278
  return candidate;
2174
2279
  }
2175
- const nextDir = path2.resolve(currentDir, "..");
2280
+ const nextDir = path5.resolve(currentDir, "..");
2176
2281
  if (nextDir === currentDir) break;
2177
2282
  currentDir = nextDir;
2178
2283
  }
2179
2284
  return null;
2180
2285
  }
2181
2286
  function resolveConfigPath(overridePath) {
2182
- if (overridePath) return path2.resolve(overridePath);
2183
- if (process.env.PAPERCLIP_CONFIG) return path2.resolve(process.env.PAPERCLIP_CONFIG);
2287
+ if (overridePath) return path5.resolve(overridePath);
2288
+ if (process.env.PAPERCLIP_CONFIG) return path5.resolve(process.env.PAPERCLIP_CONFIG);
2184
2289
  return findConfigFileFromAncestors(process.cwd()) ?? resolveDefaultConfigPath(resolvePaperclipInstanceId());
2185
2290
  }
2186
- function parseJson(filePath) {
2291
+ function parseJson2(filePath) {
2187
2292
  try {
2188
- return JSON.parse(fs.readFileSync(filePath, "utf-8"));
2293
+ return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
2189
2294
  } catch (err) {
2190
2295
  throw new Error(`Failed to parse JSON at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
2191
2296
  }
@@ -2224,8 +2329,8 @@ function formatValidationError(err) {
2224
2329
  }
2225
2330
  function readConfig(configPath) {
2226
2331
  const filePath = resolveConfigPath(configPath);
2227
- if (!fs.existsSync(filePath)) return null;
2228
- const raw = parseJson(filePath);
2332
+ if (!fs3.existsSync(filePath)) return null;
2333
+ const raw = parseJson2(filePath);
2229
2334
  const migrated = migrateLegacyConfig(raw);
2230
2335
  const parsed = paperclipConfigSchema.safeParse(migrated);
2231
2336
  if (!parsed.success) {
@@ -2235,19 +2340,19 @@ function readConfig(configPath) {
2235
2340
  }
2236
2341
  function writeConfig(config, configPath) {
2237
2342
  const filePath = resolveConfigPath(configPath);
2238
- const dir = path2.dirname(filePath);
2239
- fs.mkdirSync(dir, { recursive: true });
2240
- if (fs.existsSync(filePath)) {
2343
+ const dir = path5.dirname(filePath);
2344
+ fs3.mkdirSync(dir, { recursive: true });
2345
+ if (fs3.existsSync(filePath)) {
2241
2346
  const backupPath = filePath + ".backup";
2242
- fs.copyFileSync(filePath, backupPath);
2243
- fs.chmodSync(backupPath, 384);
2347
+ fs3.copyFileSync(filePath, backupPath);
2348
+ fs3.chmodSync(backupPath, 384);
2244
2349
  }
2245
- fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", {
2350
+ fs3.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", {
2246
2351
  mode: 384
2247
2352
  });
2248
2353
  }
2249
2354
  function configExists(configPath) {
2250
- return fs.existsSync(resolveConfigPath(configPath));
2355
+ return fs3.existsSync(resolveConfigPath(configPath));
2251
2356
  }
2252
2357
  var DEFAULT_CONFIG_BASENAME;
2253
2358
  var init_store = __esm({
@@ -2260,12 +2365,12 @@ var init_store = __esm({
2260
2365
  });
2261
2366
 
2262
2367
  // src/config/env.ts
2263
- import fs2 from "node:fs";
2264
- import path3 from "node:path";
2368
+ import fs4 from "node:fs";
2369
+ import path6 from "node:path";
2265
2370
  import { randomBytes } from "node:crypto";
2266
2371
  import { config as loadDotenv, parse as parseEnvFileContents } from "dotenv";
2267
2372
  function resolveEnvFilePath(configPath) {
2268
- return path3.resolve(path3.dirname(resolveConfigPath(configPath)), ".env");
2373
+ return path6.resolve(path6.dirname(resolveConfigPath(configPath)), ".env");
2269
2374
  }
2270
2375
  function isNonEmpty(value) {
2271
2376
  return typeof value === "string" && value.trim().length > 0;
@@ -2303,7 +2408,7 @@ function loadPaperclipEnvFile(configPath) {
2303
2408
  }
2304
2409
  function loadAgentJwtEnvFile(filePath = resolveEnvFilePath()) {
2305
2410
  if (loadedEnvFiles.has(filePath)) return;
2306
- if (!fs2.existsSync(filePath)) return;
2411
+ if (!fs4.existsSync(filePath)) return;
2307
2412
  loadedEnvFiles.add(filePath);
2308
2413
  loadDotenv({ path: filePath, override: false, quiet: true });
2309
2414
  }
@@ -2313,8 +2418,8 @@ function readAgentJwtSecretFromEnv(configPath) {
2313
2418
  return isNonEmpty(raw) ? raw.trim() : null;
2314
2419
  }
2315
2420
  function readAgentJwtSecretFromEnvFile(filePath = resolveEnvFilePath()) {
2316
- if (!fs2.existsSync(filePath)) return null;
2317
- const raw = fs2.readFileSync(filePath, "utf-8");
2421
+ if (!fs4.existsSync(filePath)) return null;
2422
+ const raw = fs4.readFileSync(filePath, "utf-8");
2318
2423
  const values = parseEnvFile(raw);
2319
2424
  const value = values[JWT_SECRET_ENV_KEY];
2320
2425
  return isNonEmpty(value) ? value.trim() : null;
@@ -2337,13 +2442,13 @@ function writeAgentJwtEnv(secret, filePath = resolveEnvFilePath()) {
2337
2442
  mergePaperclipEnvEntries({ [JWT_SECRET_ENV_KEY]: secret }, filePath);
2338
2443
  }
2339
2444
  function readPaperclipEnvEntries(filePath = resolveEnvFilePath()) {
2340
- if (!fs2.existsSync(filePath)) return {};
2341
- return parseEnvFile(fs2.readFileSync(filePath, "utf-8"));
2445
+ if (!fs4.existsSync(filePath)) return {};
2446
+ return parseEnvFile(fs4.readFileSync(filePath, "utf-8"));
2342
2447
  }
2343
2448
  function writePaperclipEnvEntries(entries, filePath = resolveEnvFilePath()) {
2344
- const dir = path3.dirname(filePath);
2345
- fs2.mkdirSync(dir, { recursive: true });
2346
- fs2.writeFileSync(filePath, renderEnvFile(entries), {
2449
+ const dir = path6.dirname(filePath);
2450
+ fs4.mkdirSync(dir, { recursive: true });
2451
+ fs4.writeFileSync(filePath, renderEnvFile(entries), {
2347
2452
  mode: 384
2348
2453
  });
2349
2454
  }
@@ -2369,24 +2474,24 @@ var init_env = __esm({
2369
2474
  });
2370
2475
 
2371
2476
  // src/utils/path-resolver.ts
2372
- import fs3 from "node:fs";
2373
- import path4 from "node:path";
2477
+ import fs5 from "node:fs";
2478
+ import path7 from "node:path";
2374
2479
  function unique(items) {
2375
2480
  return Array.from(new Set(items));
2376
2481
  }
2377
2482
  function resolveRuntimeLikePath(value, configPath) {
2378
2483
  const expanded = expandHomePrefix(value);
2379
- if (path4.isAbsolute(expanded)) return path4.resolve(expanded);
2484
+ if (path7.isAbsolute(expanded)) return path7.resolve(expanded);
2380
2485
  const cwd = process.cwd();
2381
- const configDir = configPath ? path4.dirname(configPath) : null;
2382
- const workspaceRoot = configDir ? path4.resolve(configDir, "..") : cwd;
2486
+ const configDir = configPath ? path7.dirname(configPath) : null;
2487
+ const workspaceRoot = configDir ? path7.resolve(configDir, "..") : cwd;
2383
2488
  const candidates = unique([
2384
- ...configDir ? [path4.resolve(configDir, expanded)] : [],
2385
- path4.resolve(workspaceRoot, "server", expanded),
2386
- path4.resolve(workspaceRoot, expanded),
2387
- path4.resolve(cwd, expanded)
2489
+ ...configDir ? [path7.resolve(configDir, expanded)] : [],
2490
+ path7.resolve(workspaceRoot, "server", expanded),
2491
+ path7.resolve(workspaceRoot, expanded),
2492
+ path7.resolve(cwd, expanded)
2388
2493
  ]);
2389
- return candidates.find((candidate) => fs3.existsSync(candidate)) ?? candidates[0];
2494
+ return candidates.find((candidate) => fs5.existsSync(candidate)) ?? candidates[0];
2390
2495
  }
2391
2496
  var init_path_resolver = __esm({
2392
2497
  "src/utils/path-resolver.ts"() {
@@ -2397,8 +2502,8 @@ var init_path_resolver = __esm({
2397
2502
 
2398
2503
  // src/config/secrets-key.ts
2399
2504
  import { randomBytes as randomBytes2 } from "node:crypto";
2400
- import fs4 from "node:fs";
2401
- import path5 from "node:path";
2505
+ import fs6 from "node:fs";
2506
+ import path8 from "node:path";
2402
2507
  function ensureLocalSecretsKeyFile(config, configPath) {
2403
2508
  if (config.secrets.provider !== "local_encrypted") {
2404
2509
  return { status: "skipped_provider", path: null };
@@ -2410,16 +2515,16 @@ function ensureLocalSecretsKeyFile(config, configPath) {
2410
2515
  const keyFileOverride = process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE;
2411
2516
  const configuredPath = keyFileOverride && keyFileOverride.trim().length > 0 ? keyFileOverride.trim() : config.secrets.localEncrypted.keyFilePath;
2412
2517
  const keyFilePath = resolveRuntimeLikePath(configuredPath, configPath);
2413
- if (fs4.existsSync(keyFilePath)) {
2518
+ if (fs6.existsSync(keyFilePath)) {
2414
2519
  return { status: "existing", path: keyFilePath };
2415
2520
  }
2416
- fs4.mkdirSync(path5.dirname(keyFilePath), { recursive: true });
2417
- fs4.writeFileSync(keyFilePath, randomBytes2(32).toString("base64"), {
2521
+ fs6.mkdirSync(path8.dirname(keyFilePath), { recursive: true });
2522
+ fs6.writeFileSync(keyFilePath, randomBytes2(32).toString("base64"), {
2418
2523
  encoding: "utf8",
2419
2524
  mode: 384
2420
2525
  });
2421
2526
  try {
2422
- fs4.chmodSync(keyFilePath, 384);
2527
+ fs6.chmodSync(keyFilePath, 384);
2423
2528
  } catch {
2424
2529
  }
2425
2530
  return { status: "created", path: keyFilePath };
@@ -2596,17 +2701,17 @@ async function promptLlm() {
2596
2701
  p2.cancel("Setup cancelled.");
2597
2702
  process.exit(0);
2598
2703
  }
2599
- const apiKey = await p2.password({
2704
+ const apiKey2 = await p2.password({
2600
2705
  message: `${provider === "claude" ? "Anthropic" : "OpenAI"} API key`,
2601
2706
  validate: (val) => {
2602
2707
  if (!val) return "API key is required";
2603
2708
  }
2604
2709
  });
2605
- if (p2.isCancel(apiKey)) {
2710
+ if (p2.isCancel(apiKey2)) {
2606
2711
  p2.cancel("Setup cancelled.");
2607
2712
  process.exit(0);
2608
2713
  }
2609
- return { provider, apiKey };
2714
+ return { provider, apiKey: apiKey2 };
2610
2715
  }
2611
2716
  async function promptExtendedProvider(context) {
2612
2717
  const provider = await p2.select({
@@ -2630,13 +2735,13 @@ async function promptExtendedProvider(context) {
2630
2735
  modelId: String(modelId2).trim() || DEFAULT_MODELS.local
2631
2736
  };
2632
2737
  }
2633
- const apiKey = await p2.password({
2738
+ const apiKey2 = await p2.password({
2634
2739
  message: `${PROVIDER_LABELS[selectedProvider]} API key`,
2635
2740
  validate: (val) => {
2636
2741
  if (!val) return "API key is required for this provider";
2637
2742
  }
2638
2743
  });
2639
- if (p2.isCancel(apiKey)) return null;
2744
+ if (p2.isCancel(apiKey2)) return null;
2640
2745
  const modelId = await p2.text({
2641
2746
  message: "Model id",
2642
2747
  placeholder: DEFAULT_MODELS[selectedProvider],
@@ -2645,7 +2750,7 @@ async function promptExtendedProvider(context) {
2645
2750
  if (p2.isCancel(modelId)) return null;
2646
2751
  return {
2647
2752
  provider: selectedProvider,
2648
- apiKey: String(apiKey),
2753
+ apiKey: String(apiKey2),
2649
2754
  modelId: String(modelId).trim() || DEFAULT_MODELS[selectedProvider]
2650
2755
  };
2651
2756
  }
@@ -6912,7 +7017,7 @@ var init_path_resolver2 = __esm({
6912
7017
  });
6913
7018
 
6914
7019
  // src/checks/database-check.ts
6915
- import fs5 from "node:fs";
7020
+ import fs7 from "node:fs";
6916
7021
  async function databaseCheck(config, configPath) {
6917
7022
  if (config.database.mode === "postgres") {
6918
7023
  if (!config.database.connectionString) {
@@ -6946,8 +7051,8 @@ async function databaseCheck(config, configPath) {
6946
7051
  if (config.database.mode === "embedded-postgres") {
6947
7052
  const dataDir = resolveRuntimeLikePath(config.database.embeddedPostgresDataDir, configPath);
6948
7053
  const reportedPath = dataDir;
6949
- if (!fs5.existsSync(dataDir)) {
6950
- fs5.mkdirSync(reportedPath, { recursive: true });
7054
+ if (!fs7.existsSync(dataDir)) {
7055
+ fs7.mkdirSync(reportedPath, { recursive: true });
6951
7056
  }
6952
7057
  return {
6953
7058
  name: "Database",
@@ -7055,15 +7160,15 @@ var init_llm_check = __esm({
7055
7160
  });
7056
7161
 
7057
7162
  // src/checks/log-check.ts
7058
- import fs6 from "node:fs";
7163
+ import fs8 from "node:fs";
7059
7164
  function logCheck(config, configPath) {
7060
7165
  const logDir = resolveRuntimeLikePath(config.logging.logDir, configPath);
7061
7166
  const reportedDir = logDir;
7062
- if (!fs6.existsSync(logDir)) {
7063
- fs6.mkdirSync(reportedDir, { recursive: true });
7167
+ if (!fs8.existsSync(logDir)) {
7168
+ fs8.mkdirSync(reportedDir, { recursive: true });
7064
7169
  }
7065
7170
  try {
7066
- fs6.accessSync(reportedDir, fs6.constants.W_OK);
7171
+ fs8.accessSync(reportedDir, fs8.constants.W_OK);
7067
7172
  return {
7068
7173
  name: "Log directory",
7069
7174
  status: "pass",
@@ -7138,8 +7243,8 @@ var init_port_check = __esm({
7138
7243
 
7139
7244
  // src/checks/secrets-check.ts
7140
7245
  import { randomBytes as randomBytes4 } from "node:crypto";
7141
- import fs7 from "node:fs";
7142
- import path6 from "node:path";
7246
+ import fs9 from "node:fs";
7247
+ import path9 from "node:path";
7143
7248
  function decodeMasterKey(raw) {
7144
7249
  const trimmed = raw.trim();
7145
7250
  if (!trimmed) return null;
@@ -7201,7 +7306,7 @@ function secretsCheck(config, configPath) {
7201
7306
  const keyFileOverride = process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE;
7202
7307
  const configuredPath = keyFileOverride && keyFileOverride.trim().length > 0 ? keyFileOverride.trim() : config.secrets.localEncrypted.keyFilePath;
7203
7308
  const keyFilePath = resolveRuntimeLikePath(configuredPath, configPath);
7204
- if (!fs7.existsSync(keyFilePath)) {
7309
+ if (!fs9.existsSync(keyFilePath)) {
7205
7310
  return withStrictModeNote(
7206
7311
  {
7207
7312
  name: "Secrets adapter",
@@ -7209,13 +7314,13 @@ function secretsCheck(config, configPath) {
7209
7314
  message: `Secrets key file does not exist yet: ${keyFilePath}`,
7210
7315
  canRepair: true,
7211
7316
  repair: () => {
7212
- fs7.mkdirSync(path6.dirname(keyFilePath), { recursive: true });
7213
- fs7.writeFileSync(keyFilePath, randomBytes4(32).toString("base64"), {
7317
+ fs9.mkdirSync(path9.dirname(keyFilePath), { recursive: true });
7318
+ fs9.writeFileSync(keyFilePath, randomBytes4(32).toString("base64"), {
7214
7319
  encoding: "utf8",
7215
7320
  mode: 384
7216
7321
  });
7217
7322
  try {
7218
- fs7.chmodSync(keyFilePath, 384);
7323
+ fs9.chmodSync(keyFilePath, 384);
7219
7324
  } catch {
7220
7325
  }
7221
7326
  },
@@ -7226,7 +7331,7 @@ function secretsCheck(config, configPath) {
7226
7331
  }
7227
7332
  let raw;
7228
7333
  try {
7229
- raw = fs7.readFileSync(keyFilePath, "utf8");
7334
+ raw = fs9.readFileSync(keyFilePath, "utf8");
7230
7335
  } catch (err) {
7231
7336
  return {
7232
7337
  name: "Secrets adapter",
@@ -7262,15 +7367,15 @@ var init_secrets_check = __esm({
7262
7367
  });
7263
7368
 
7264
7369
  // src/checks/storage-check.ts
7265
- import fs8 from "node:fs";
7370
+ import fs10 from "node:fs";
7266
7371
  function storageCheck(config, configPath) {
7267
7372
  if (config.storage.provider === "local_disk") {
7268
7373
  const baseDir = resolveRuntimeLikePath(config.storage.localDisk.baseDir, configPath);
7269
- if (!fs8.existsSync(baseDir)) {
7270
- fs8.mkdirSync(baseDir, { recursive: true });
7374
+ if (!fs10.existsSync(baseDir)) {
7375
+ fs10.mkdirSync(baseDir, { recursive: true });
7271
7376
  }
7272
7377
  try {
7273
- fs8.accessSync(baseDir, fs8.constants.W_OK);
7378
+ fs10.accessSync(baseDir, fs10.constants.W_OK);
7274
7379
  return {
7275
7380
  name: "Storage",
7276
7381
  status: "pass",
@@ -7483,8 +7588,8 @@ var run_exports = {};
7483
7588
  __export(run_exports, {
7484
7589
  runCommand: () => runCommand
7485
7590
  });
7486
- import fs9 from "node:fs";
7487
- import path7 from "node:path";
7591
+ import fs11 from "node:fs";
7592
+ import path10 from "node:path";
7488
7593
  import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
7489
7594
  import * as p9 from "@clack/prompts";
7490
7595
  import pc4 from "picocolors";
@@ -7492,9 +7597,9 @@ async function runCommand(opts) {
7492
7597
  const instanceId = resolvePaperclipInstanceId(opts.instance);
7493
7598
  process.env.PAPERCLIP_INSTANCE_ID = instanceId;
7494
7599
  const homeDir = resolvePaperclipHomeDir();
7495
- fs9.mkdirSync(homeDir, { recursive: true });
7600
+ fs11.mkdirSync(homeDir, { recursive: true });
7496
7601
  const paths = describeLocalInstancePaths(instanceId);
7497
- fs9.mkdirSync(paths.instanceRoot, { recursive: true });
7602
+ fs11.mkdirSync(paths.instanceRoot, { recursive: true });
7498
7603
  const configPath = resolveConfigPath(opts.config);
7499
7604
  process.env.PAPERCLIP_CONFIG = configPath;
7500
7605
  loadPaperclipEnvFile(configPath);
@@ -7578,18 +7683,18 @@ function maybeEnableUiDevMiddleware(entrypoint) {
7578
7683
  }
7579
7684
  }
7580
7685
  async function importServerEntry() {
7581
- const projectRoot = path7.resolve(path7.dirname(fileURLToPath2(import.meta.url)), "../../..");
7582
- const devEntry = path7.resolve(projectRoot, "server/src/index.ts");
7583
- if (fs9.existsSync(devEntry)) {
7686
+ const projectRoot = path10.resolve(path10.dirname(fileURLToPath2(import.meta.url)), "../../..");
7687
+ const devEntry = path10.resolve(projectRoot, "server/src/index.ts");
7688
+ if (fs11.existsSync(devEntry)) {
7584
7689
  maybeEnableUiDevMiddleware(devEntry);
7585
7690
  const mod = await import(pathToFileURL(devEntry).href);
7586
7691
  return await startServerFromModule(mod, devEntry);
7587
7692
  }
7588
- const bundledEntry = path7.resolve(
7589
- path7.dirname(fileURLToPath2(import.meta.url)),
7693
+ const bundledEntry = path10.resolve(
7694
+ path10.dirname(fileURLToPath2(import.meta.url)),
7590
7695
  "./runtime/server/dist/index.js"
7591
7696
  );
7592
- if (fs9.existsSync(bundledEntry)) {
7697
+ if (fs11.existsSync(bundledEntry)) {
7593
7698
  const mod = await import(pathToFileURL(bundledEntry).href);
7594
7699
  return await startServerFromModule(mod, bundledEntry);
7595
7700
  }
@@ -7637,7 +7742,7 @@ var init_run = __esm({
7637
7742
 
7638
7743
  // src/commands/onboard.ts
7639
7744
  import * as p10 from "@clack/prompts";
7640
- import path8 from "node:path";
7745
+ import path11 from "node:path";
7641
7746
  import pc5 from "picocolors";
7642
7747
  function parseBooleanFromEnv(rawValue) {
7643
7748
  if (rawValue === void 0) return null;
@@ -7658,7 +7763,7 @@ function parseEnumFromEnv(rawValue, allowedValues) {
7658
7763
  }
7659
7764
  function resolvePathFromEnv(rawValue) {
7660
7765
  if (!rawValue || rawValue.trim().length === 0) return null;
7661
- return path8.resolve(expandHomePrefix(rawValue.trim()));
7766
+ return path11.resolve(expandHomePrefix(rawValue.trim()));
7662
7767
  }
7663
7768
  function quickstartDefaultsFromEnv() {
7664
7769
  const instanceId = resolvePaperclipInstanceId();
@@ -8077,8 +8182,8 @@ var init_onboard = __esm({
8077
8182
 
8078
8183
  // src/client/http.ts
8079
8184
  import { URL as URL2 } from "node:url";
8080
- function buildUrl(apiBase, path61) {
8081
- const normalizedPath = path61.startsWith("/") ? path61 : `/${path61}`;
8185
+ function buildUrl(apiBase, path62) {
8186
+ const normalizedPath = path62.startsWith("/") ? path62 : `/${path62}`;
8082
8187
  const [pathname, query] = normalizedPath.split("?");
8083
8188
  const url = new URL2(apiBase);
8084
8189
  url.pathname = `${url.pathname.replace(/\/+$/, "")}${pathname}`;
@@ -8140,26 +8245,26 @@ var init_http = __esm({
8140
8245
  this.runId = opts.runId?.trim() || void 0;
8141
8246
  this.userId = opts.userId?.trim() || void 0;
8142
8247
  }
8143
- get(path61, opts) {
8144
- return this.request(path61, { method: "GET" }, opts);
8248
+ get(path62, opts) {
8249
+ return this.request(path62, { method: "GET" }, opts);
8145
8250
  }
8146
- post(path61, body, opts) {
8147
- return this.request(path61, {
8251
+ post(path62, body, opts) {
8252
+ return this.request(path62, {
8148
8253
  method: "POST",
8149
8254
  body: body === void 0 ? void 0 : JSON.stringify(body)
8150
8255
  }, opts);
8151
8256
  }
8152
- patch(path61, body, opts) {
8153
- return this.request(path61, {
8257
+ patch(path62, body, opts) {
8258
+ return this.request(path62, {
8154
8259
  method: "PATCH",
8155
8260
  body: body === void 0 ? void 0 : JSON.stringify(body)
8156
8261
  }, opts);
8157
8262
  }
8158
- delete(path61, opts) {
8159
- return this.request(path61, { method: "DELETE" }, opts);
8263
+ delete(path62, opts) {
8264
+ return this.request(path62, { method: "DELETE" }, opts);
8160
8265
  }
8161
- async request(path61, init, opts) {
8162
- const url = buildUrl(this.apiBase, path61);
8266
+ async request(path62, init, opts) {
8267
+ const url = buildUrl(this.apiBase, path62);
8163
8268
  const headers = {
8164
8269
  accept: "application/json",
8165
8270
  ...toStringRecord(init.headers)
@@ -8199,111 +8304,6 @@ var init_http = __esm({
8199
8304
  }
8200
8305
  });
8201
8306
 
8202
- // src/auth/paths.ts
8203
- import path10 from "node:path";
8204
- function resolveAuthDir() {
8205
- return path10.resolve(resolvePaperclipHomeDir(), "auth");
8206
- }
8207
- function resolveProfilesDir() {
8208
- return path10.resolve(resolvePaperclipHomeDir(), "profiles");
8209
- }
8210
- function resolveSessionPath() {
8211
- return path10.resolve(resolveAuthDir(), "session.json");
8212
- }
8213
- function resolveHostedOverlayPath() {
8214
- return path10.resolve(resolveProfilesDir(), "hosted-overlay.json");
8215
- }
8216
- function resolveEffectiveProfilePath() {
8217
- return path10.resolve(resolveProfilesDir(), "effective-profile.json");
8218
- }
8219
- var init_paths = __esm({
8220
- "src/auth/paths.ts"() {
8221
- "use strict";
8222
- init_home();
8223
- }
8224
- });
8225
-
8226
- // src/auth/session-store.ts
8227
- var session_store_exports = {};
8228
- __export(session_store_exports, {
8229
- clearSession: () => clearSession,
8230
- describeSessionPath: () => describeSessionPath,
8231
- isSessionExpired: () => isSessionExpired,
8232
- readSession: () => readSession,
8233
- writeSession: () => writeSession
8234
- });
8235
- import fs11 from "node:fs";
8236
- import path11 from "node:path";
8237
- function parseJson3(filePath) {
8238
- try {
8239
- return JSON.parse(fs11.readFileSync(filePath, "utf-8"));
8240
- } catch (err) {
8241
- throw new Error(
8242
- `Failed to parse auth session at ${filePath}: ${err instanceof Error ? err.message : String(err)}`
8243
- );
8244
- }
8245
- }
8246
- function toStringOrUndefined2(value) {
8247
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
8248
- }
8249
- function normalizeSession(raw) {
8250
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
8251
- const record = raw;
8252
- const accessToken = toStringOrUndefined2(record.accessToken);
8253
- const hostedBaseUrl = toStringOrUndefined2(record.hostedBaseUrl);
8254
- if (!accessToken || !hostedBaseUrl) return null;
8255
- const issuedAt = toStringOrUndefined2(record.issuedAt) ?? (/* @__PURE__ */ new Date()).toISOString();
8256
- return {
8257
- version: 1,
8258
- hostedBaseUrl,
8259
- accessToken,
8260
- expiresAt: toStringOrUndefined2(record.expiresAt),
8261
- userId: toStringOrUndefined2(record.userId),
8262
- email: toStringOrUndefined2(record.email),
8263
- orgId: toStringOrUndefined2(record.orgId),
8264
- orgName: toStringOrUndefined2(record.orgName),
8265
- machineLabel: toStringOrUndefined2(record.machineLabel),
8266
- issuedAt
8267
- };
8268
- }
8269
- function readSession() {
8270
- const filePath = resolveSessionPath();
8271
- if (!fs11.existsSync(filePath)) return null;
8272
- const raw = parseJson3(filePath);
8273
- return normalizeSession(raw);
8274
- }
8275
- function writeSession(session) {
8276
- const filePath = resolveSessionPath();
8277
- fs11.mkdirSync(resolveAuthDir(), { recursive: true });
8278
- fs11.writeFileSync(filePath, `${JSON.stringify(session, null, 2)}
8279
- `, { mode: 384 });
8280
- try {
8281
- fs11.chmodSync(filePath, 384);
8282
- } catch {
8283
- }
8284
- }
8285
- function clearSession() {
8286
- const filePath = resolveSessionPath();
8287
- if (!fs11.existsSync(filePath)) return false;
8288
- fs11.rmSync(filePath, { force: true });
8289
- return true;
8290
- }
8291
- function isSessionExpired(session, now = /* @__PURE__ */ new Date()) {
8292
- if (!session.expiresAt) return false;
8293
- const expires = Date.parse(session.expiresAt);
8294
- if (Number.isNaN(expires)) return false;
8295
- return expires <= now.getTime();
8296
- }
8297
- function describeSessionPath() {
8298
- return path11.resolve(resolveSessionPath());
8299
- }
8300
- var init_session_store = __esm({
8301
- "src/auth/session-store.ts"() {
8302
- "use strict";
8303
- init_paths();
8304
- }
8305
- });
8306
-
8307
8307
  // src/auth/hosted-client.ts
8308
8308
  var hosted_client_exports = {};
8309
8309
  __export(hosted_client_exports, {
@@ -8643,52 +8643,52 @@ __export(service_exports, {
8643
8643
  validateBundledKitAssetRoot: () => validateBundledKitAssetRoot,
8644
8644
  validateKitDirectory: () => validateKitDirectory
8645
8645
  });
8646
- import fs17 from "node:fs";
8647
- import path23 from "node:path";
8646
+ import fs18 from "node:fs";
8647
+ import path24 from "node:path";
8648
8648
  import { fileURLToPath as fileURLToPath4 } from "node:url";
8649
8649
  function resolveBundledKitAssetsRoot() {
8650
- const moduleDir = path23.dirname(fileURLToPath4(import.meta.url));
8650
+ const moduleDir = path24.dirname(fileURLToPath4(import.meta.url));
8651
8651
  const candidates = [
8652
- path23.resolve(moduleDir, "../../assets/worker-kits"),
8653
- path23.resolve(moduleDir, "../assets/worker-kits")
8652
+ path24.resolve(moduleDir, "../../assets/worker-kits"),
8653
+ path24.resolve(moduleDir, "../assets/worker-kits")
8654
8654
  ];
8655
8655
  for (const candidate of candidates) {
8656
- if (fs17.existsSync(candidate)) return candidate;
8656
+ if (fs18.existsSync(candidate)) return candidate;
8657
8657
  }
8658
8658
  throw new Error("Could not locate bundled worker kit assets.");
8659
8659
  }
8660
8660
  function resolveRequestedOutputRoot(outDir) {
8661
8661
  if (outDir?.trim()) {
8662
- return path23.resolve(expandHomePrefix(outDir.trim()));
8662
+ return path24.resolve(expandHomePrefix(outDir.trim()));
8663
8663
  }
8664
- return path23.resolve(resolvePaperclipHomeDir(), "kits", "exports");
8664
+ return path24.resolve(resolvePaperclipHomeDir(), "kits", "exports");
8665
8665
  }
8666
8666
  function readJsonFile(filePath) {
8667
- return JSON.parse(fs17.readFileSync(filePath, "utf8"));
8667
+ return JSON.parse(fs18.readFileSync(filePath, "utf8"));
8668
8668
  }
8669
8669
  function assertRelativePathExists(assetRoot, relativePath, label) {
8670
- const fullPath = path23.resolve(assetRoot, relativePath);
8671
- if (!fs17.existsSync(fullPath)) {
8670
+ const fullPath = path24.resolve(assetRoot, relativePath);
8671
+ if (!fs18.existsSync(fullPath)) {
8672
8672
  throw new Error(`${label} is missing required path: ${relativePath}`);
8673
8673
  }
8674
8674
  }
8675
8675
  function listRelativeFiles(rootDir) {
8676
8676
  const files = [];
8677
8677
  const walk = (currentDir) => {
8678
- for (const entry of fs17.readdirSync(currentDir, { withFileTypes: true })) {
8679
- const fullPath = path23.join(currentDir, entry.name);
8678
+ for (const entry of fs18.readdirSync(currentDir, { withFileTypes: true })) {
8679
+ const fullPath = path24.join(currentDir, entry.name);
8680
8680
  if (entry.isDirectory()) {
8681
8681
  walk(fullPath);
8682
8682
  continue;
8683
8683
  }
8684
- files.push(path23.relative(rootDir, fullPath).split(path23.sep).join("/"));
8684
+ files.push(path24.relative(rootDir, fullPath).split(path24.sep).join("/"));
8685
8685
  }
8686
8686
  };
8687
8687
  walk(rootDir);
8688
8688
  return files.sort();
8689
8689
  }
8690
8690
  function parseManifest(assetRoot) {
8691
- const raw = readJsonFile(path23.resolve(assetRoot, "kit.json"));
8691
+ const raw = readJsonFile(path24.resolve(assetRoot, "kit.json"));
8692
8692
  if (!SUPPORTED_SCHEMA_VERSIONS.includes(raw.schemaVersion)) {
8693
8693
  throw new Error(`Unsupported kit schema version for ${assetRoot}: ${raw.schemaVersion}`);
8694
8694
  }
@@ -8699,7 +8699,7 @@ function parseBundleManifest(assetRoot, manifest, bundleId) {
8699
8699
  if (!bundleRef) {
8700
8700
  throw new Error(`Kit ${manifest.kit.id} does not declare bundle ${bundleId}.`);
8701
8701
  }
8702
- const raw = readJsonFile(path23.resolve(assetRoot, bundleRef.path));
8702
+ const raw = readJsonFile(path24.resolve(assetRoot, bundleRef.path));
8703
8703
  if (!SUPPORTED_SCHEMA_VERSIONS.includes(raw.schemaVersion)) {
8704
8704
  throw new Error(
8705
8705
  `Unsupported bundle schema version for ${bundleRef.path}: ${raw.schemaVersion}`
@@ -8764,14 +8764,14 @@ function validateKitDirectory(kitPath) {
8764
8764
  const warnings = [];
8765
8765
  let schemaVersion = 0;
8766
8766
  let kitId = "<unknown>";
8767
- const kitJsonPath = path23.resolve(kitPath, "kit.json");
8768
- if (!fs17.existsSync(kitJsonPath)) {
8767
+ const kitJsonPath = path24.resolve(kitPath, "kit.json");
8768
+ if (!fs18.existsSync(kitJsonPath)) {
8769
8769
  errors.push({ field: "kit.json", message: "kit.json not found in kit directory" });
8770
8770
  return { valid: false, schemaVersion, kitId, errors, warnings };
8771
8771
  }
8772
8772
  let raw;
8773
8773
  try {
8774
- raw = JSON.parse(fs17.readFileSync(kitJsonPath, "utf8"));
8774
+ raw = JSON.parse(fs18.readFileSync(kitJsonPath, "utf8"));
8775
8775
  } catch {
8776
8776
  errors.push({ field: "kit.json", message: "kit.json is not valid JSON" });
8777
8777
  return { valid: false, schemaVersion, kitId, errors, warnings };
@@ -8838,8 +8838,8 @@ function validateKitDirectory(kitPath) {
8838
8838
  if (typeof entrypoint.path !== "string") {
8839
8839
  errors.push({ field: "entrypoint.path", message: "Missing required field 'entrypoint.path'" });
8840
8840
  } else {
8841
- const fullPath = path23.resolve(kitPath, entrypoint.path);
8842
- if (!fs17.existsSync(fullPath)) {
8841
+ const fullPath = path24.resolve(kitPath, entrypoint.path);
8842
+ if (!fs18.existsSync(fullPath)) {
8843
8843
  errors.push({ field: "entrypoint.path", message: `Entrypoint file not found: ${entrypoint.path}` });
8844
8844
  }
8845
8845
  }
@@ -8847,16 +8847,16 @@ function validateKitDirectory(kitPath) {
8847
8847
  if (typeof raw.agentContractPath !== "string") {
8848
8848
  errors.push({ field: "agentContractPath", message: "Missing required field 'agentContractPath'" });
8849
8849
  } else {
8850
- const fullPath = path23.resolve(kitPath, raw.agentContractPath);
8851
- if (!fs17.existsSync(fullPath)) {
8850
+ const fullPath = path24.resolve(kitPath, raw.agentContractPath);
8851
+ if (!fs18.existsSync(fullPath)) {
8852
8852
  errors.push({ field: "agentContractPath", message: `Agent contract not found: ${raw.agentContractPath}` });
8853
8853
  }
8854
8854
  }
8855
8855
  if (typeof raw.brandTemplatePath !== "string") {
8856
8856
  errors.push({ field: "brandTemplatePath", message: "Missing required field 'brandTemplatePath'" });
8857
8857
  } else {
8858
- const fullPath = path23.resolve(kitPath, raw.brandTemplatePath);
8859
- if (!fs17.existsSync(fullPath)) {
8858
+ const fullPath = path24.resolve(kitPath, raw.brandTemplatePath);
8859
+ if (!fs18.existsSync(fullPath)) {
8860
8860
  errors.push({ field: "brandTemplatePath", message: `Brand template not found: ${raw.brandTemplatePath}` });
8861
8861
  }
8862
8862
  }
@@ -8866,8 +8866,8 @@ function validateKitDirectory(kitPath) {
8866
8866
  } else {
8867
8867
  for (const assetPath of frozenAssets) {
8868
8868
  if (typeof assetPath !== "string") continue;
8869
- const fullPath = path23.resolve(kitPath, assetPath);
8870
- if (!fs17.existsSync(fullPath)) {
8869
+ const fullPath = path24.resolve(kitPath, assetPath);
8870
+ if (!fs18.existsSync(fullPath)) {
8871
8871
  errors.push({ field: "frozenAssetPaths", message: `Frozen asset not found: ${assetPath}` });
8872
8872
  }
8873
8873
  }
@@ -8885,8 +8885,8 @@ function validateKitDirectory(kitPath) {
8885
8885
  } else {
8886
8886
  for (const reqPath of requiredPaths) {
8887
8887
  if (typeof reqPath !== "string") continue;
8888
- const fullPath = path23.resolve(kitPath, reqPath);
8889
- if (!fs17.existsSync(fullPath)) {
8888
+ const fullPath = path24.resolve(kitPath, reqPath);
8889
+ if (!fs18.existsSync(fullPath)) {
8890
8890
  errors.push({ field: "outputStandard.requiredPaths", message: `Required output path not found: ${reqPath}` });
8891
8891
  }
8892
8892
  }
@@ -8902,13 +8902,13 @@ function validateKitDirectory(kitPath) {
8902
8902
  errors.push({ field: "bundles[].path", message: "Bundle ref missing 'path' field" });
8903
8903
  continue;
8904
8904
  }
8905
- const bundlePath = path23.resolve(kitPath, ref.path);
8906
- if (!fs17.existsSync(bundlePath)) {
8905
+ const bundlePath = path24.resolve(kitPath, ref.path);
8906
+ if (!fs18.existsSync(bundlePath)) {
8907
8907
  errors.push({ field: "bundles[].path", message: `Bundle manifest not found: ${ref.path}` });
8908
8908
  continue;
8909
8909
  }
8910
8910
  try {
8911
- const bundleRaw = JSON.parse(fs17.readFileSync(bundlePath, "utf8"));
8911
+ const bundleRaw = JSON.parse(fs18.readFileSync(bundlePath, "utf8"));
8912
8912
  const bundleBlock = bundleRaw.bundle;
8913
8913
  if (!bundleBlock || typeof bundleBlock !== "object") {
8914
8914
  errors.push({ field: `bundle(${ref.id})`, message: "Bundle manifest missing 'bundle' block" });
@@ -8946,7 +8946,7 @@ function loadResolvedBundledKit(assetRoot, catalogEntry) {
8946
8946
  function validateBundledKitAssetRoot(assetRoot, input) {
8947
8947
  const catalogEntry = {
8948
8948
  id: input.kitId,
8949
- packageDirName: path23.basename(assetRoot),
8949
+ packageDirName: path24.basename(assetRoot),
8950
8950
  defaultBundleId: input.bundleId ?? input.kitId,
8951
8951
  type: "worker",
8952
8952
  executionMode: "export",
@@ -8980,7 +8980,7 @@ Available: ${available}`
8980
8980
  );
8981
8981
  }
8982
8982
  const catalogEntry = BUNDLED_KIT_CATALOG.find((e) => e.id === resolvedId);
8983
- const assetRoot = path23.resolve(resolveBundledKitAssetsRoot(), catalogEntry.packageDirName);
8983
+ const assetRoot = path24.resolve(resolveBundledKitAssetsRoot(), catalogEntry.packageDirName);
8984
8984
  return loadResolvedBundledKit(assetRoot, catalogEntry);
8985
8985
  }
8986
8986
  function toListItem(resolved) {
@@ -9000,8 +9000,8 @@ function toListItem(resolved) {
9000
9000
  }
9001
9001
  function resolveOutputPaths(resolved, outDir) {
9002
9002
  const outputRoot = resolveRequestedOutputRoot(outDir);
9003
- const folderPath = path23.resolve(outputRoot, resolved.bundleManifest.export.folderName);
9004
- const zipPath = path23.resolve(outputRoot, resolved.bundleManifest.export.zipFileName);
9003
+ const folderPath = path24.resolve(outputRoot, resolved.bundleManifest.export.folderName);
9004
+ const zipPath = path24.resolve(outputRoot, resolved.bundleManifest.export.zipFileName);
9005
9005
  return { outputRoot, folderPath, zipPath };
9006
9006
  }
9007
9007
  function listBundledKits() {
@@ -9043,9 +9043,9 @@ function getBundledKitSourceInfo(kitId) {
9043
9043
  }
9044
9044
  function copyBundledKitSource(kitId, destinationPath) {
9045
9045
  const info = getBundledKitSourceInfo(kitId);
9046
- fs17.mkdirSync(path23.dirname(destinationPath), { recursive: true });
9047
- fs17.rmSync(destinationPath, { recursive: true, force: true });
9048
- fs17.cpSync(info.assetRoot, destinationPath, { recursive: true });
9046
+ fs18.mkdirSync(path24.dirname(destinationPath), { recursive: true });
9047
+ fs18.rmSync(destinationPath, { recursive: true, force: true });
9048
+ fs18.cpSync(info.assetRoot, destinationPath, { recursive: true });
9049
9049
  return info;
9050
9050
  }
9051
9051
  function crc32(buffer) {
@@ -9133,7 +9133,7 @@ function reportProgress(onProgress, progress) {
9133
9133
  function copyDirectoryWithProgress(sourceRoot, targetRoot, onProgress) {
9134
9134
  const files = listRelativeFiles(sourceRoot);
9135
9135
  const total = Math.max(files.length, 1);
9136
- fs17.mkdirSync(targetRoot, { recursive: true });
9136
+ fs18.mkdirSync(targetRoot, { recursive: true });
9137
9137
  reportProgress(onProgress, {
9138
9138
  phase: "copying",
9139
9139
  completed: 0,
@@ -9142,10 +9142,10 @@ function copyDirectoryWithProgress(sourceRoot, targetRoot, onProgress) {
9142
9142
  detail: "Preparing files"
9143
9143
  });
9144
9144
  files.forEach((relativePath, index51) => {
9145
- const sourcePath = path23.resolve(sourceRoot, relativePath);
9146
- const targetPath = path23.resolve(targetRoot, relativePath);
9147
- fs17.mkdirSync(path23.dirname(targetPath), { recursive: true });
9148
- fs17.copyFileSync(sourcePath, targetPath);
9145
+ const sourcePath = path24.resolve(sourceRoot, relativePath);
9146
+ const targetPath = path24.resolve(targetRoot, relativePath);
9147
+ fs18.mkdirSync(path24.dirname(targetPath), { recursive: true });
9148
+ fs18.copyFileSync(sourcePath, targetPath);
9149
9149
  const completed = index51 + 1;
9150
9150
  const percent = 10 + Math.round(completed / total * 55);
9151
9151
  reportProgress(onProgress, {
@@ -9171,8 +9171,8 @@ function buildZipEntriesWithProgress(sourceRoot, exportFolderName, onProgress) {
9171
9171
  detail: relativePath
9172
9172
  });
9173
9173
  return {
9174
- name: path23.posix.join(exportFolderName, relativePath),
9175
- data: fs17.readFileSync(path23.resolve(sourceRoot, relativePath))
9174
+ name: path24.posix.join(exportFolderName, relativePath),
9175
+ data: fs18.readFileSync(path24.resolve(sourceRoot, relativePath))
9176
9176
  };
9177
9177
  });
9178
9178
  }
@@ -9187,8 +9187,8 @@ function downloadBundledKit(kitId, outDir, options = {}) {
9187
9187
  percent: 0,
9188
9188
  detail: "Resolving export target"
9189
9189
  });
9190
- fs17.mkdirSync(outputPaths.outputRoot, { recursive: true });
9191
- fs17.rmSync(outputPaths.folderPath, { recursive: true, force: true });
9190
+ fs18.mkdirSync(outputPaths.outputRoot, { recursive: true });
9191
+ fs18.rmSync(outputPaths.folderPath, { recursive: true, force: true });
9192
9192
  copyDirectoryWithProgress(resolved.assetRoot, outputPaths.folderPath, onProgress);
9193
9193
  const zipBuffer = buildStoredZip(
9194
9194
  buildZipEntriesWithProgress(outputPaths.folderPath, resolved.bundleManifest.export.folderName, onProgress)
@@ -9198,9 +9198,9 @@ function downloadBundledKit(kitId, outDir, options = {}) {
9198
9198
  completed: 1,
9199
9199
  total: 1,
9200
9200
  percent: 98,
9201
- detail: path23.basename(outputPaths.zipPath)
9201
+ detail: path24.basename(outputPaths.zipPath)
9202
9202
  });
9203
- fs17.writeFileSync(outputPaths.zipPath, zipBuffer);
9203
+ fs18.writeFileSync(outputPaths.zipPath, zipBuffer);
9204
9204
  reportProgress(onProgress, {
9205
9205
  phase: "done",
9206
9206
  completed: 1,
@@ -9236,26 +9236,26 @@ __export(kit_forks_home_exports, {
9236
9236
  resolveKitForksOrphanJobsDir: () => resolveKitForksOrphanJobsDir
9237
9237
  });
9238
9238
  import os6 from "node:os";
9239
- import path24 from "node:path";
9239
+ import path25 from "node:path";
9240
9240
  function resolveKitForksHomeDir() {
9241
9241
  const envHome = process.env.GROWTHUB_KIT_FORKS_HOME?.trim();
9242
- if (envHome) return path24.resolve(expandHomePrefix(envHome));
9243
- return path24.resolve(os6.homedir(), ".growthub", "kit-forks");
9242
+ if (envHome) return path25.resolve(expandHomePrefix(envHome));
9243
+ return path25.resolve(os6.homedir(), ".growthub", "kit-forks");
9244
9244
  }
9245
9245
  function resolveKitForksIndexPath() {
9246
- return path24.resolve(resolveKitForksHomeDir(), "index.json");
9246
+ return path25.resolve(resolveKitForksHomeDir(), "index.json");
9247
9247
  }
9248
9248
  function resolveKitForksJobsDir() {
9249
- return path24.resolve(resolveKitForksHomeDir(), "jobs");
9249
+ return path25.resolve(resolveKitForksHomeDir(), "jobs");
9250
9250
  }
9251
9251
  function resolveKitForksOrphanJobsDir() {
9252
- return path24.resolve(resolveKitForksHomeDir(), "orphan-jobs");
9252
+ return path25.resolve(resolveKitForksHomeDir(), "orphan-jobs");
9253
9253
  }
9254
9254
  function resolveInForkStateDir(forkPath) {
9255
- return path24.resolve(forkPath, IN_FORK_STATE_DIRNAME);
9255
+ return path25.resolve(forkPath, IN_FORK_STATE_DIRNAME);
9256
9256
  }
9257
9257
  function resolveInForkRegistrationPath(forkPath) {
9258
- return path24.resolve(resolveInForkStateDir(forkPath), "fork.json");
9258
+ return path25.resolve(resolveInForkStateDir(forkPath), "fork.json");
9259
9259
  }
9260
9260
  var IN_FORK_STATE_DIRNAME;
9261
9261
  var init_kit_forks_home = __esm({
@@ -9267,13 +9267,13 @@ var init_kit_forks_home = __esm({
9267
9267
  });
9268
9268
 
9269
9269
  // src/kits/fork-registry.ts
9270
- import fs18 from "node:fs";
9271
- import path25 from "node:path";
9270
+ import fs19 from "node:fs";
9271
+ import path26 from "node:path";
9272
9272
  function readIndex() {
9273
9273
  const p35 = resolveKitForksIndexPath();
9274
- if (!fs18.existsSync(p35)) return { version: 1, entries: [] };
9274
+ if (!fs19.existsSync(p35)) return { version: 1, entries: [] };
9275
9275
  try {
9276
- const parsed = JSON.parse(fs18.readFileSync(p35, "utf8"));
9276
+ const parsed = JSON.parse(fs19.readFileSync(p35, "utf8"));
9277
9277
  if (!parsed || !Array.isArray(parsed.entries)) return { version: 1, entries: [] };
9278
9278
  return parsed;
9279
9279
  } catch {
@@ -9282,8 +9282,8 @@ function readIndex() {
9282
9282
  }
9283
9283
  function writeIndex(index51) {
9284
9284
  const p35 = resolveKitForksIndexPath();
9285
- fs18.mkdirSync(path25.dirname(p35), { recursive: true });
9286
- fs18.writeFileSync(p35, JSON.stringify(index51, null, 2) + "\n", "utf8");
9285
+ fs19.mkdirSync(path26.dirname(p35), { recursive: true });
9286
+ fs19.writeFileSync(p35, JSON.stringify(index51, null, 2) + "\n", "utf8");
9287
9287
  }
9288
9288
  function upsertIndexEntry(entry) {
9289
9289
  const index51 = readIndex();
@@ -9303,32 +9303,32 @@ function sanitizeForkId(raw) {
9303
9303
  return raw.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").slice(0, 56);
9304
9304
  }
9305
9305
  function generateForkId(forkPath, kitId) {
9306
- const dirName = path25.basename(forkPath);
9306
+ const dirName = path26.basename(forkPath);
9307
9307
  const base = sanitizeForkId(`${kitId}-${dirName}`);
9308
9308
  const suffix = Date.now().toString(36).slice(-4);
9309
9309
  return `${base}-${suffix}`;
9310
9310
  }
9311
9311
  function readForkJson(forkPath) {
9312
9312
  const p35 = resolveInForkRegistrationPath(forkPath);
9313
- if (!fs18.existsSync(p35)) return null;
9313
+ if (!fs19.existsSync(p35)) return null;
9314
9314
  try {
9315
- return JSON.parse(fs18.readFileSync(p35, "utf8"));
9315
+ return JSON.parse(fs19.readFileSync(p35, "utf8"));
9316
9316
  } catch {
9317
9317
  return null;
9318
9318
  }
9319
9319
  }
9320
9320
  function writeForkJson(reg) {
9321
9321
  const stateDir = resolveInForkStateDir(reg.forkPath);
9322
- fs18.mkdirSync(stateDir, { recursive: true });
9323
- fs18.writeFileSync(
9322
+ fs19.mkdirSync(stateDir, { recursive: true });
9323
+ fs19.writeFileSync(
9324
9324
  resolveInForkRegistrationPath(reg.forkPath),
9325
9325
  JSON.stringify(reg, null, 2) + "\n",
9326
9326
  "utf8"
9327
9327
  );
9328
9328
  }
9329
9329
  function registerKitFork(opts) {
9330
- const resolvedPath = path25.resolve(opts.forkPath);
9331
- if (!fs18.existsSync(resolvedPath)) {
9330
+ const resolvedPath = path26.resolve(opts.forkPath);
9331
+ if (!fs19.existsSync(resolvedPath)) {
9332
9332
  throw new Error(`Fork path does not exist: ${resolvedPath}`);
9333
9333
  }
9334
9334
  const forkId = generateForkId(resolvedPath, opts.kitId);
@@ -9362,7 +9362,7 @@ function updateKitForkRegistration(reg) {
9362
9362
  function loadKitForkRegistration(kitId, forkId) {
9363
9363
  const entry = readIndex().entries.find((e) => e.kitId === kitId && e.forkId === forkId);
9364
9364
  if (!entry) return null;
9365
- if (!fs18.existsSync(entry.forkPath)) return null;
9365
+ if (!fs19.existsSync(entry.forkPath)) return null;
9366
9366
  return readForkJson(entry.forkPath);
9367
9367
  }
9368
9368
  function listKitForkRegistrations(filterKitId) {
@@ -9370,7 +9370,7 @@ function listKitForkRegistrations(filterKitId) {
9370
9370
  const results = [];
9371
9371
  for (const entry of index51.entries) {
9372
9372
  if (filterKitId && entry.kitId !== filterKitId) continue;
9373
- if (!fs18.existsSync(entry.forkPath)) continue;
9373
+ if (!fs19.existsSync(entry.forkPath)) continue;
9374
9374
  const reg = readForkJson(entry.forkPath);
9375
9375
  if (reg) results.push(reg);
9376
9376
  }
@@ -9379,9 +9379,9 @@ function listKitForkRegistrations(filterKitId) {
9379
9379
  function deregisterKitFork(kitId, forkId) {
9380
9380
  const entry = readIndex().entries.find((e) => e.kitId === kitId && e.forkId === forkId);
9381
9381
  if (!entry) return false;
9382
- if (fs18.existsSync(entry.forkPath)) {
9382
+ if (fs19.existsSync(entry.forkPath)) {
9383
9383
  const stateDir = resolveInForkStateDir(entry.forkPath);
9384
- fs18.rmSync(stateDir, { recursive: true, force: true });
9384
+ fs19.rmSync(stateDir, { recursive: true, force: true });
9385
9385
  }
9386
9386
  removeIndexEntry(kitId, forkId);
9387
9387
  return true;
@@ -9389,7 +9389,7 @@ function deregisterKitFork(kitId, forkId) {
9389
9389
  function lookupKitForkPath(kitId, forkId) {
9390
9390
  const entry = readIndex().entries.find((e) => e.kitId === kitId && e.forkId === forkId);
9391
9391
  if (!entry) return null;
9392
- if (!fs18.existsSync(entry.forkPath)) return null;
9392
+ if (!fs19.existsSync(entry.forkPath)) return null;
9393
9393
  return entry.forkPath;
9394
9394
  }
9395
9395
  var init_fork_registry = __esm({
@@ -9400,8 +9400,8 @@ var init_fork_registry = __esm({
9400
9400
  });
9401
9401
 
9402
9402
  // src/kits/fork-policy.ts
9403
- import fs19 from "node:fs";
9404
- import path26 from "node:path";
9403
+ import fs20 from "node:fs";
9404
+ import path27 from "node:path";
9405
9405
  function makeDefaultKitForkPolicy() {
9406
9406
  return {
9407
9407
  version: 1,
@@ -9416,13 +9416,13 @@ function makeDefaultKitForkPolicy() {
9416
9416
  };
9417
9417
  }
9418
9418
  function resolvePolicyPath(forkPath) {
9419
- return path26.resolve(resolveInForkStateDir(forkPath), "policy.json");
9419
+ return path27.resolve(resolveInForkStateDir(forkPath), "policy.json");
9420
9420
  }
9421
9421
  function readKitForkPolicy(forkPath) {
9422
9422
  const p35 = resolvePolicyPath(forkPath);
9423
- if (!fs19.existsSync(p35)) return makeDefaultKitForkPolicy();
9423
+ if (!fs20.existsSync(p35)) return makeDefaultKitForkPolicy();
9424
9424
  try {
9425
- const parsed = JSON.parse(fs19.readFileSync(p35, "utf8"));
9425
+ const parsed = JSON.parse(fs20.readFileSync(p35, "utf8"));
9426
9426
  return { ...makeDefaultKitForkPolicy(), ...parsed, version: 1 };
9427
9427
  } catch {
9428
9428
  return makeDefaultKitForkPolicy();
@@ -9430,9 +9430,9 @@ function readKitForkPolicy(forkPath) {
9430
9430
  }
9431
9431
  function writeKitForkPolicy(forkPath, policy) {
9432
9432
  const p35 = resolvePolicyPath(forkPath);
9433
- fs19.mkdirSync(path26.dirname(p35), { recursive: true });
9433
+ fs20.mkdirSync(path27.dirname(p35), { recursive: true });
9434
9434
  const body = { ...policy, version: 1, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9435
- fs19.writeFileSync(p35, JSON.stringify(body, null, 2) + "\n", "utf8");
9435
+ fs20.writeFileSync(p35, JSON.stringify(body, null, 2) + "\n", "utf8");
9436
9436
  }
9437
9437
  function matchesAnyPrefix(targetPath, patterns) {
9438
9438
  const normalized = targetPath.replace(/^\/+|\/+$/g, "");
@@ -9454,10 +9454,10 @@ var init_fork_policy = __esm({
9454
9454
  });
9455
9455
 
9456
9456
  // src/kits/fork-trace.ts
9457
- import fs20 from "node:fs";
9458
- import path27 from "node:path";
9457
+ import fs21 from "node:fs";
9458
+ import path28 from "node:path";
9459
9459
  function resolveTracePath(forkPath) {
9460
- return path27.resolve(resolveInForkStateDir(forkPath), "trace.jsonl");
9460
+ return path28.resolve(resolveInForkStateDir(forkPath), "trace.jsonl");
9461
9461
  }
9462
9462
  function appendKitForkTraceEvent(forkPath, event) {
9463
9463
  const full = {
@@ -9465,14 +9465,14 @@ function appendKitForkTraceEvent(forkPath, event) {
9465
9465
  timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
9466
9466
  };
9467
9467
  const p35 = resolveTracePath(forkPath);
9468
- fs20.mkdirSync(path27.dirname(p35), { recursive: true });
9469
- fs20.appendFileSync(p35, JSON.stringify(full) + "\n", "utf8");
9468
+ fs21.mkdirSync(path28.dirname(p35), { recursive: true });
9469
+ fs21.appendFileSync(p35, JSON.stringify(full) + "\n", "utf8");
9470
9470
  return full;
9471
9471
  }
9472
9472
  function readKitForkTrace(forkPath) {
9473
9473
  const p35 = resolveTracePath(forkPath);
9474
- if (!fs20.existsSync(p35)) return [];
9475
- const raw = fs20.readFileSync(p35, "utf8").trim();
9474
+ if (!fs21.existsSync(p35)) return [];
9475
+ const raw = fs21.readFileSync(p35, "utf8").trim();
9476
9476
  if (!raw) return [];
9477
9477
  const events = [];
9478
9478
  for (const line of raw.split("\n")) {
@@ -9498,8 +9498,8 @@ var init_fork_trace = __esm({
9498
9498
 
9499
9499
  // src/kits/fork-remote.ts
9500
9500
  import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
9501
- import fs21 from "node:fs";
9502
- import path28 from "node:path";
9501
+ import fs22 from "node:fs";
9502
+ import path29 from "node:path";
9503
9503
  function runGit(cwd, args, opts) {
9504
9504
  const res = spawnSync("git", args, {
9505
9505
  cwd,
@@ -9515,7 +9515,7 @@ function runGit(cwd, args, opts) {
9515
9515
  };
9516
9516
  }
9517
9517
  function isGitRepo(forkPath) {
9518
- if (!fs21.existsSync(path28.resolve(forkPath, ".git"))) return false;
9518
+ if (!fs22.existsSync(path29.resolve(forkPath, ".git"))) return false;
9519
9519
  const res = runGit(forkPath, ["rev-parse", "--is-inside-work-tree"]);
9520
9520
  return res.ok && res.stdout.trim() === "true";
9521
9521
  }
@@ -9582,17 +9582,17 @@ var init_fork_remote = __esm({
9582
9582
 
9583
9583
  // src/config/github-home.ts
9584
9584
  import os7 from "node:os";
9585
- import path30 from "node:path";
9585
+ import path31 from "node:path";
9586
9586
  function resolveGithubHomeDir() {
9587
9587
  const envHome = process.env.GROWTHUB_GITHUB_HOME?.trim();
9588
- if (envHome) return path30.resolve(expandHomePrefix(envHome));
9589
- return path30.resolve(os7.homedir(), ".growthub", "github");
9588
+ if (envHome) return path31.resolve(expandHomePrefix(envHome));
9589
+ return path31.resolve(os7.homedir(), ".growthub", "github");
9590
9590
  }
9591
9591
  function resolveGithubTokenPath() {
9592
- return path30.resolve(resolveGithubHomeDir(), "token.json");
9592
+ return path31.resolve(resolveGithubHomeDir(), "token.json");
9593
9593
  }
9594
9594
  function resolveGithubProfilePath() {
9595
- return path30.resolve(resolveGithubHomeDir(), "profile.json");
9595
+ return path31.resolve(resolveGithubHomeDir(), "profile.json");
9596
9596
  }
9597
9597
  var init_github_home = __esm({
9598
9598
  "src/config/github-home.ts"() {
@@ -9613,24 +9613,24 @@ __export(token_store_exports, {
9613
9613
  writeGithubProfile: () => writeGithubProfile,
9614
9614
  writeGithubToken: () => writeGithubToken
9615
9615
  });
9616
- import fs23 from "node:fs";
9616
+ import fs24 from "node:fs";
9617
9617
  function ensureDir(dir) {
9618
- fs23.mkdirSync(dir, { recursive: true });
9618
+ fs24.mkdirSync(dir, { recursive: true });
9619
9619
  }
9620
9620
  function atomicWrite(filePath, body) {
9621
9621
  const tmp = `${filePath}.tmp`;
9622
- fs23.writeFileSync(tmp, body, { encoding: "utf8", mode: 384 });
9623
- fs23.renameSync(tmp, filePath);
9622
+ fs24.writeFileSync(tmp, body, { encoding: "utf8", mode: 384 });
9623
+ fs24.renameSync(tmp, filePath);
9624
9624
  try {
9625
- fs23.chmodSync(filePath, 384);
9625
+ fs24.chmodSync(filePath, 384);
9626
9626
  } catch {
9627
9627
  }
9628
9628
  }
9629
9629
  function readGithubToken() {
9630
9630
  const p35 = resolveGithubTokenPath();
9631
- if (!fs23.existsSync(p35)) return null;
9631
+ if (!fs24.existsSync(p35)) return null;
9632
9632
  try {
9633
- const parsed = JSON.parse(fs23.readFileSync(p35, "utf8"));
9633
+ const parsed = JSON.parse(fs24.readFileSync(p35, "utf8"));
9634
9634
  if (!parsed?.accessToken) return null;
9635
9635
  return parsed;
9636
9636
  } catch {
@@ -9643,7 +9643,7 @@ function writeGithubToken(token) {
9643
9643
  }
9644
9644
  function clearGithubToken() {
9645
9645
  const p35 = resolveGithubTokenPath();
9646
- if (fs23.existsSync(p35)) fs23.rmSync(p35, { force: true });
9646
+ if (fs24.existsSync(p35)) fs24.rmSync(p35, { force: true });
9647
9647
  }
9648
9648
  function isGithubTokenExpired(token) {
9649
9649
  if (!token) return true;
@@ -9654,9 +9654,9 @@ function isGithubTokenExpired(token) {
9654
9654
  }
9655
9655
  function readGithubProfile() {
9656
9656
  const p35 = resolveGithubProfilePath();
9657
- if (!fs23.existsSync(p35)) return null;
9657
+ if (!fs24.existsSync(p35)) return null;
9658
9658
  try {
9659
- return JSON.parse(fs23.readFileSync(p35, "utf8"));
9659
+ return JSON.parse(fs24.readFileSync(p35, "utf8"));
9660
9660
  } catch {
9661
9661
  return null;
9662
9662
  }
@@ -9667,7 +9667,7 @@ function writeGithubProfile(profile) {
9667
9667
  }
9668
9668
  function clearGithubProfile() {
9669
9669
  const p35 = resolveGithubProfilePath();
9670
- if (fs23.existsSync(p35)) fs23.rmSync(p35, { force: true });
9670
+ if (fs24.existsSync(p35)) fs24.rmSync(p35, { force: true });
9671
9671
  }
9672
9672
  function describeGithubTokenPath() {
9673
9673
  return resolveGithubTokenPath();
@@ -9702,9 +9702,9 @@ async function fetchHostedIntegrations(session) {
9702
9702
  }
9703
9703
  async function fetchHostedIntegrationCredential(session, providerId) {
9704
9704
  const client = toApiClient2(session);
9705
- const path61 = `${DEFAULT_INTEGRATION_CREDENTIAL_PATH}&provider=${encodeURIComponent(providerId)}`;
9705
+ const path62 = `${DEFAULT_INTEGRATION_CREDENTIAL_PATH}&provider=${encodeURIComponent(providerId)}`;
9706
9706
  try {
9707
- return await client.get(path61, { ignoreNotFound: true });
9707
+ return await client.get(path62, { ignoreNotFound: true });
9708
9708
  } catch (err) {
9709
9709
  if (err instanceof ApiRequestError && (err.status === 404 || err.status === 501)) {
9710
9710
  throw new HostedEndpointUnavailableError(err.status, err.message);
@@ -10278,13 +10278,13 @@ var init_github = __esm({
10278
10278
  }
10279
10279
  });
10280
10280
 
10281
- // src/starter/init.ts
10282
- import fs41 from "node:fs";
10283
- import path49 from "node:path";
10281
+ // src/starter/init.ts
10282
+ import fs42 from "node:fs";
10283
+ import path50 from "node:path";
10284
10284
  async function initStarterWorkspace(opts) {
10285
10285
  const kitId = opts.kitId ?? DEFAULT_STARTER_KIT_ID;
10286
- const absOut = path49.resolve(opts.out);
10287
- if (fs41.existsSync(absOut) && fs41.readdirSync(absOut).length > 0) {
10286
+ const absOut = path50.resolve(opts.out);
10287
+ if (fs42.existsSync(absOut) && fs42.readdirSync(absOut).length > 0) {
10288
10288
  throw new Error(`Destination ${absOut} already exists and is not empty.`);
10289
10289
  }
10290
10290
  const info = getBundledKitSourceInfo(kitId);
@@ -10293,7 +10293,7 @@ async function initStarterWorkspace(opts) {
10293
10293
  forkPath: absOut,
10294
10294
  kitId: info.id,
10295
10295
  baseVersion: info.version,
10296
- label: opts.name?.trim() || path49.basename(absOut)
10296
+ label: opts.name?.trim() || path50.basename(absOut)
10297
10297
  });
10298
10298
  const policy = {
10299
10299
  ...makeDefaultKitForkPolicy(),
@@ -10386,8 +10386,8 @@ var init_types2 = __esm({
10386
10386
  });
10387
10387
 
10388
10388
  // src/starter/source-import/github-source.ts
10389
- import fs42 from "node:fs";
10390
- import path50 from "node:path";
10389
+ import fs43 from "node:fs";
10390
+ import path51 from "node:path";
10391
10391
  import { spawnSync as spawnSync5 } from "node:child_process";
10392
10392
  function baseHeaders() {
10393
10393
  return {
@@ -10518,12 +10518,12 @@ function cloneGithubRepo(input) {
10518
10518
  if (!gitAvailable()) {
10519
10519
  throw new Error("`git` is not available on PATH \u2014 cannot clone.");
10520
10520
  }
10521
- if (fs42.existsSync(input.destination)) {
10521
+ if (fs43.existsSync(input.destination)) {
10522
10522
  throw new Error(`Clone destination already exists: ${input.destination}`);
10523
10523
  }
10524
10524
  const cloneUrl = input.token ? buildTokenCloneUrl(input.probe.repo, input.token) : input.probe.cloneUrl;
10525
- const parent = path50.dirname(input.destination);
10526
- fs42.mkdirSync(parent, { recursive: true });
10525
+ const parent = path51.dirname(input.destination);
10526
+ fs43.mkdirSync(parent, { recursive: true });
10527
10527
  const depth = input.depth ?? 1;
10528
10528
  const branch = input.branch ?? input.probe.defaultBranch;
10529
10529
  const args = ["clone"];
@@ -10550,17 +10550,17 @@ function cloneGithubRepo(input) {
10550
10550
  function narrowToSubdirectory(rootDir, subdirectory) {
10551
10551
  const normalizedSub = subdirectory.replace(/^\/+|\/+$/g, "");
10552
10552
  if (!normalizedSub) return;
10553
- const abs = path50.resolve(rootDir, normalizedSub);
10554
- if (!fs42.existsSync(abs) || !fs42.statSync(abs).isDirectory()) {
10553
+ const abs = path51.resolve(rootDir, normalizedSub);
10554
+ if (!fs43.existsSync(abs) || !fs43.statSync(abs).isDirectory()) {
10555
10555
  throw new Error(`Subdirectory not found in cloned repo: ${subdirectory}`);
10556
10556
  }
10557
- const tmp = path50.resolve(
10558
- path50.dirname(rootDir),
10559
- `.${path50.basename(rootDir)}-narrow-${Date.now().toString(36)}`
10557
+ const tmp = path51.resolve(
10558
+ path51.dirname(rootDir),
10559
+ `.${path51.basename(rootDir)}-narrow-${Date.now().toString(36)}`
10560
10560
  );
10561
- fs42.renameSync(abs, tmp);
10562
- fs42.rmSync(rootDir, { recursive: true, force: true });
10563
- fs42.renameSync(tmp, rootDir);
10561
+ fs43.renameSync(abs, tmp);
10562
+ fs43.rmSync(rootDir, { recursive: true, force: true });
10563
+ fs43.renameSync(tmp, rootDir);
10564
10564
  }
10565
10565
  var GITHUB_API_BASE2;
10566
10566
  var init_github_source = __esm({
@@ -10574,9 +10574,9 @@ var init_github_source = __esm({
10574
10574
  });
10575
10575
 
10576
10576
  // src/starter/source-import/skills-source.ts
10577
- import fs43 from "node:fs";
10577
+ import fs44 from "node:fs";
10578
10578
  import os10 from "node:os";
10579
- import path51 from "node:path";
10579
+ import path52 from "node:path";
10580
10580
  import { spawnSync as spawnSync6 } from "node:child_process";
10581
10581
  function resolveBase() {
10582
10582
  const raw = process.env.SKILLS_SH_BASE?.trim();
@@ -10842,9 +10842,9 @@ async function probeSkillsSource(input) {
10842
10842
  };
10843
10843
  }
10844
10844
  function assertInsidePayloadRoot(root, candidate) {
10845
- const abs = path51.resolve(candidate);
10846
- const rootAbs = path51.resolve(root);
10847
- if (!abs.startsWith(rootAbs + path51.sep) && abs !== rootAbs) {
10845
+ const abs = path52.resolve(candidate);
10846
+ const rootAbs = path52.resolve(root);
10847
+ if (!abs.startsWith(rootAbs + path52.sep) && abs !== rootAbs) {
10848
10848
  throw new Error(`Refusing to write outside payload root: ${candidate}`);
10849
10849
  }
10850
10850
  }
@@ -10860,24 +10860,24 @@ function runGit3(args, cwd) {
10860
10860
  };
10861
10861
  }
10862
10862
  function skillDirectoryMatches(dir, skillSlug) {
10863
- const skillFile = path51.resolve(dir, "SKILL.md");
10864
- if (!fs43.existsSync(skillFile) || !fs43.statSync(skillFile).isFile()) {
10863
+ const skillFile = path52.resolve(dir, "SKILL.md");
10864
+ if (!fs44.existsSync(skillFile) || !fs44.statSync(skillFile).isFile()) {
10865
10865
  return false;
10866
10866
  }
10867
- if (path51.basename(dir) === skillSlug) {
10867
+ if (path52.basename(dir) === skillSlug) {
10868
10868
  return true;
10869
10869
  }
10870
- const content = fs43.readFileSync(skillFile, "utf8");
10870
+ const content = fs44.readFileSync(skillFile, "utf8");
10871
10871
  const nameMatch = content.match(/(?:^|\n)name:\s*["']?([A-Za-z0-9._:-]+)["']?\s*(?:\n|$)/i);
10872
10872
  return nameMatch?.[1] === skillSlug;
10873
10873
  }
10874
10874
  function locateSkillDirectory(root, skillSlug) {
10875
10875
  const preferred = [
10876
- path51.resolve(root, "skills", skillSlug),
10877
- path51.resolve(root, skillSlug)
10876
+ path52.resolve(root, "skills", skillSlug),
10877
+ path52.resolve(root, skillSlug)
10878
10878
  ];
10879
10879
  for (const candidate of preferred) {
10880
- if (fs43.existsSync(candidate) && fs43.statSync(candidate).isDirectory() && skillDirectoryMatches(candidate, skillSlug)) {
10880
+ if (fs44.existsSync(candidate) && fs44.statSync(candidate).isDirectory() && skillDirectoryMatches(candidate, skillSlug)) {
10881
10881
  return candidate;
10882
10882
  }
10883
10883
  }
@@ -10887,12 +10887,12 @@ function locateSkillDirectory(root, skillSlug) {
10887
10887
  if (skillDirectoryMatches(current, skillSlug)) {
10888
10888
  return current;
10889
10889
  }
10890
- for (const entry of fs43.readdirSync(current, { withFileTypes: true })) {
10890
+ for (const entry of fs44.readdirSync(current, { withFileTypes: true })) {
10891
10891
  if (!entry.isDirectory()) continue;
10892
10892
  if ([".git", "node_modules", ".next", "dist", "build", "coverage"].includes(entry.name)) {
10893
10893
  continue;
10894
10894
  }
10895
- queue.push(path51.resolve(current, entry.name));
10895
+ queue.push(path52.resolve(current, entry.name));
10896
10896
  }
10897
10897
  }
10898
10898
  return null;
@@ -10902,18 +10902,18 @@ function copySkillTree(sourceDir, destination) {
10902
10902
  const stack = [{ from: sourceDir, to: destination }];
10903
10903
  while (stack.length > 0) {
10904
10904
  const current = stack.pop();
10905
- fs43.mkdirSync(current.to, { recursive: true });
10906
- for (const entry of fs43.readdirSync(current.from, { withFileTypes: true })) {
10907
- const fromPath = path51.resolve(current.from, entry.name);
10908
- const toPath = path51.resolve(current.to, entry.name);
10905
+ fs44.mkdirSync(current.to, { recursive: true });
10906
+ for (const entry of fs44.readdirSync(current.from, { withFileTypes: true })) {
10907
+ const fromPath = path52.resolve(current.from, entry.name);
10908
+ const toPath = path52.resolve(current.to, entry.name);
10909
10909
  assertInsidePayloadRoot(destination, toPath);
10910
10910
  if (entry.isDirectory()) {
10911
10911
  stack.push({ from: fromPath, to: toPath });
10912
10912
  continue;
10913
10913
  }
10914
- const data = fs43.readFileSync(fromPath);
10915
- fs43.mkdirSync(path51.dirname(toPath), { recursive: true });
10916
- fs43.writeFileSync(toPath, data, { mode: 420 });
10914
+ const data = fs44.readFileSync(fromPath);
10915
+ fs44.mkdirSync(path52.dirname(toPath), { recursive: true });
10916
+ fs44.writeFileSync(toPath, data, { mode: 420 });
10917
10917
  written += 1;
10918
10918
  }
10919
10919
  }
@@ -10924,7 +10924,7 @@ async function fetchSkillPayload(input) {
10924
10924
  if (!gitAvailable()) {
10925
10925
  throw new Error("`git` is not available on PATH \u2014 cannot materialize a skills.sh payload.");
10926
10926
  }
10927
- if (fs43.existsSync(destination)) {
10927
+ if (fs44.existsSync(destination)) {
10928
10928
  throw new Error(`Skill payload destination already exists: ${destination}`);
10929
10929
  }
10930
10930
  const repoSource = probe.repoUrl ?? (probe.repository ? `https://github.com/${probe.repository}` : void 0);
@@ -10932,11 +10932,11 @@ async function fetchSkillPayload(input) {
10932
10932
  if (!repoSource || !skillSlug) {
10933
10933
  throw new Error(`Skill '${probe.skillId}' is missing repository metadata \u2014 cannot materialize payload.`);
10934
10934
  }
10935
- const cloneRoot = fs43.mkdtempSync(
10936
- path51.join(os10.tmpdir(), "growthub-skills-source-")
10935
+ const cloneRoot = fs44.mkdtempSync(
10936
+ path52.join(os10.tmpdir(), "growthub-skills-source-")
10937
10937
  );
10938
10938
  try {
10939
- const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot], path51.dirname(cloneRoot));
10939
+ const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot], path52.dirname(cloneRoot));
10940
10940
  if (!cloneRes.ok) {
10941
10941
  throw new Error(`git clone failed: ${cloneRes.stderr || "unable to clone skill repository"}`);
10942
10942
  }
@@ -10949,7 +10949,7 @@ async function fetchSkillPayload(input) {
10949
10949
  const fileCount = copySkillTree(skillDir, destination);
10950
10950
  return { destination, fileCount };
10951
10951
  } finally {
10952
- fs43.rmSync(cloneRoot, { recursive: true, force: true });
10952
+ fs44.rmSync(cloneRoot, { recursive: true, force: true });
10953
10953
  }
10954
10954
  }
10955
10955
  var DEFAULT_BASE, COMMENT_PATTERN;
@@ -10963,13 +10963,13 @@ var init_skills_source = __esm({
10963
10963
  });
10964
10964
 
10965
10965
  // src/starter/source-import/detect.ts
10966
- import fs44 from "node:fs";
10967
- import path52 from "node:path";
10966
+ import fs45 from "node:fs";
10967
+ import path53 from "node:path";
10968
10968
  function safeReadPackageJson(dir) {
10969
- const p35 = path52.resolve(dir, "package.json");
10970
- if (!fs44.existsSync(p35)) return null;
10969
+ const p35 = path53.resolve(dir, "package.json");
10970
+ if (!fs45.existsSync(p35)) return null;
10971
10971
  try {
10972
- return JSON.parse(fs44.readFileSync(p35, "utf8"));
10972
+ return JSON.parse(fs45.readFileSync(p35, "utf8"));
10973
10973
  } catch {
10974
10974
  return null;
10975
10975
  }
@@ -10979,10 +10979,10 @@ function detectPackageManager(dir, pkg) {
10979
10979
  if (pkg?.packageManager?.startsWith("yarn")) return "yarn";
10980
10980
  if (pkg?.packageManager?.startsWith("npm")) return "npm";
10981
10981
  if (pkg?.packageManager?.startsWith("bun")) return "bun";
10982
- if (fs44.existsSync(path52.resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
10983
- if (fs44.existsSync(path52.resolve(dir, "yarn.lock"))) return "yarn";
10984
- if (fs44.existsSync(path52.resolve(dir, "bun.lockb"))) return "bun";
10985
- if (fs44.existsSync(path52.resolve(dir, "package-lock.json"))) return "npm";
10982
+ if (fs45.existsSync(path53.resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
10983
+ if (fs45.existsSync(path53.resolve(dir, "yarn.lock"))) return "yarn";
10984
+ if (fs45.existsSync(path53.resolve(dir, "bun.lockb"))) return "bun";
10985
+ if (fs45.existsSync(path53.resolve(dir, "package-lock.json"))) return "npm";
10986
10986
  return "unknown";
10987
10987
  }
10988
10988
  function collectDeps(pkg) {
@@ -10996,12 +10996,12 @@ function collectDeps(pkg) {
10996
10996
  }
10997
10997
  function looksLikeSkillPayload(rootDir) {
10998
10998
  const markers = ["SKILL.md", "skill.md", "skill.json", "skill.yml", "skill.yaml", "prompt.md"];
10999
- return markers.some((name) => fs44.existsSync(path52.resolve(rootDir, name)));
10999
+ return markers.some((name) => fs45.existsSync(path53.resolve(rootDir, name)));
11000
11000
  }
11001
11001
  function detectFramework(rootDir, pkg) {
11002
11002
  if (!pkg) {
11003
11003
  if (looksLikeSkillPayload(rootDir)) return "skill";
11004
- if (fs44.existsSync(path52.resolve(rootDir, "docs"))) return "docs";
11004
+ if (fs45.existsSync(path53.resolve(rootDir, "docs"))) return "docs";
11005
11005
  return "unknown";
11006
11006
  }
11007
11007
  const deps = collectDeps(pkg);
@@ -11010,8 +11010,8 @@ function detectFramework(rootDir, pkg) {
11010
11010
  "vite.config.ts",
11011
11011
  "vite.config.mjs",
11012
11012
  "vite.config.cjs"
11013
- ].some((name) => fs44.existsSync(path52.resolve(rootDir, name)));
11014
- if (deps.has("next") || fs44.existsSync(path52.resolve(rootDir, "next.config.js")) || fs44.existsSync(path52.resolve(rootDir, "next.config.mjs"))) {
11013
+ ].some((name) => fs45.existsSync(path53.resolve(rootDir, name)));
11014
+ if (deps.has("next") || fs45.existsSync(path53.resolve(rootDir, "next.config.js")) || fs45.existsSync(path53.resolve(rootDir, "next.config.mjs"))) {
11015
11015
  return "next";
11016
11016
  }
11017
11017
  if (deps.has("vite") || hasViteConfig) return "vite";
@@ -11037,15 +11037,15 @@ function pickScripts(pkg) {
11037
11037
  return out;
11038
11038
  }
11039
11039
  function listEnvFiles(dir) {
11040
- if (!fs44.existsSync(dir)) return [];
11041
- return fs44.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).filter((name) => name === ".env" || name.startsWith(".env.") || name === ".env.example");
11040
+ if (!fs45.existsSync(dir)) return [];
11041
+ return fs45.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).filter((name) => name === ".env" || name.startsWith(".env.") || name === ".env.example");
11042
11042
  }
11043
11043
  function findAppRoot(rootDir, pkg) {
11044
11044
  if (pkg) return ".";
11045
11045
  const candidates = ["app", "src", "apps", "packages"];
11046
11046
  for (const candidate of candidates) {
11047
- const abs = path52.resolve(rootDir, candidate);
11048
- if (fs44.existsSync(abs) && fs44.statSync(abs).isDirectory()) {
11047
+ const abs = path53.resolve(rootDir, candidate);
11048
+ if (fs45.existsSync(abs) && fs45.statSync(abs).isDirectory()) {
11049
11049
  const child = safeReadPackageJson(abs);
11050
11050
  if (child) return candidate;
11051
11051
  }
@@ -11061,12 +11061,12 @@ function computeConfidence(framework, manager, pkg) {
11061
11061
  return Math.min(1, Number(score.toFixed(2)));
11062
11062
  }
11063
11063
  function detectSourceShape(rootDir) {
11064
- if (!fs44.existsSync(rootDir) || !fs44.statSync(rootDir).isDirectory()) {
11064
+ if (!fs45.existsSync(rootDir) || !fs45.statSync(rootDir).isDirectory()) {
11065
11065
  throw new Error(`Detection target is not a directory: ${rootDir}`);
11066
11066
  }
11067
11067
  const rootPkg = safeReadPackageJson(rootDir);
11068
11068
  const appRootRel = findAppRoot(rootDir, rootPkg);
11069
- const appRootAbs = path52.resolve(rootDir, appRootRel);
11069
+ const appRootAbs = path53.resolve(rootDir, appRootRel);
11070
11070
  const appPkg = appRootRel === "." ? rootPkg : safeReadPackageJson(appRootAbs);
11071
11071
  const framework = detectFramework(appRootAbs, appPkg ?? rootPkg);
11072
11072
  const packageManager = detectPackageManager(rootDir, rootPkg ?? appPkg);
@@ -11106,18 +11106,18 @@ var init_detect = __esm({
11106
11106
  });
11107
11107
 
11108
11108
  // src/starter/source-import/security.ts
11109
- import fs45 from "node:fs";
11110
- import path53 from "node:path";
11109
+ import fs46 from "node:fs";
11110
+ import path54 from "node:path";
11111
11111
  function isLikelyTextFile(filename) {
11112
- const ext = path53.extname(filename).toLowerCase();
11112
+ const ext = path54.extname(filename).toLowerCase();
11113
11113
  if (!ext) return true;
11114
11114
  return TEXT_EXTENSIONS.has(ext);
11115
11115
  }
11116
11116
  function isSuspiciousBinary(filename) {
11117
- return SUSPICIOUS_BINARY_EXTENSIONS.has(path53.extname(filename).toLowerCase());
11117
+ return SUSPICIOUS_BINARY_EXTENSIONS.has(path54.extname(filename).toLowerCase());
11118
11118
  }
11119
11119
  function isUnexpectedArchive(filename) {
11120
- const ext = path53.extname(filename).toLowerCase();
11120
+ const ext = path54.extname(filename).toLowerCase();
11121
11121
  return ARCHIVE_EXTENSIONS.has(ext) || filename.toLowerCase().endsWith(".tar.gz");
11122
11122
  }
11123
11123
  function shortExcerpt(line) {
@@ -11172,19 +11172,19 @@ function walkPayload(root, onFile, limits) {
11172
11172
  if (!current) break;
11173
11173
  let entries;
11174
11174
  try {
11175
- entries = fs45.readdirSync(current, { withFileTypes: true });
11175
+ entries = fs46.readdirSync(current, { withFileTypes: true });
11176
11176
  } catch {
11177
11177
  continue;
11178
11178
  }
11179
11179
  for (const entry of entries) {
11180
- const abs = path53.resolve(current, entry.name);
11180
+ const abs = path54.resolve(current, entry.name);
11181
11181
  if (entry.isDirectory()) {
11182
11182
  if (entry.name === ".git" || entry.name === "node_modules") continue;
11183
11183
  stack.push(abs);
11184
11184
  continue;
11185
11185
  }
11186
11186
  if (!entry.isFile()) continue;
11187
- const rel = path53.relative(root, abs);
11187
+ const rel = path54.relative(root, abs);
11188
11188
  onFile(abs, rel);
11189
11189
  visited += 1;
11190
11190
  if (visited >= limits.maxFiles) break;
@@ -11194,7 +11194,7 @@ function walkPayload(root, onFile, limits) {
11194
11194
  }
11195
11195
  function inspectSourcePayload(input) {
11196
11196
  const { payloadRoot } = input;
11197
- if (!fs45.existsSync(payloadRoot) || !fs45.statSync(payloadRoot).isDirectory()) {
11197
+ if (!fs46.existsSync(payloadRoot) || !fs46.statSync(payloadRoot).isDirectory()) {
11198
11198
  throw new Error(`Inspection target is not a directory: ${payloadRoot}`);
11199
11199
  }
11200
11200
  const findings = [];
@@ -11204,7 +11204,7 @@ function inspectSourcePayload(input) {
11204
11204
  (abs, rel) => {
11205
11205
  let size = 0;
11206
11206
  try {
11207
- size = fs45.statSync(abs).size;
11207
+ size = fs46.statSync(abs).size;
11208
11208
  } catch {
11209
11209
  return;
11210
11210
  }
@@ -11213,7 +11213,7 @@ function inspectSourcePayload(input) {
11213
11213
  category: "suspicious-binary",
11214
11214
  severity: "high-risk",
11215
11215
  path: rel,
11216
- message: `Payload ships a precompiled binary (${path53.extname(rel)}). Review provenance before use.`
11216
+ message: `Payload ships a precompiled binary (${path54.extname(rel)}). Review provenance before use.`
11217
11217
  });
11218
11218
  return;
11219
11219
  }
@@ -11222,7 +11222,7 @@ function inspectSourcePayload(input) {
11222
11222
  category: "unexpected-archive",
11223
11223
  severity: "caution",
11224
11224
  path: rel,
11225
- message: `Payload ships an archive (${path53.extname(rel)}) \u2014 expand and review contents before use.`
11225
+ message: `Payload ships an archive (${path54.extname(rel)}) \u2014 expand and review contents before use.`
11226
11226
  });
11227
11227
  return;
11228
11228
  }
@@ -11230,12 +11230,12 @@ function inspectSourcePayload(input) {
11230
11230
  if (bytesInspected + Math.min(size, MAX_BYTES_PER_FILE) > MAX_TOTAL_BYTES) return;
11231
11231
  let buf;
11232
11232
  try {
11233
- const handle = fs45.openSync(abs, "r");
11233
+ const handle = fs46.openSync(abs, "r");
11234
11234
  try {
11235
11235
  buf = Buffer.alloc(Math.min(size, MAX_BYTES_PER_FILE));
11236
- fs45.readSync(handle, buf, 0, buf.length, 0);
11236
+ fs46.readSync(handle, buf, 0, buf.length, 0);
11237
11237
  } finally {
11238
- fs45.closeSync(handle);
11238
+ fs46.closeSync(handle);
11239
11239
  }
11240
11240
  } catch {
11241
11241
  return;
@@ -11444,18 +11444,18 @@ var init_security = __esm({
11444
11444
  });
11445
11445
 
11446
11446
  // src/starter/source-import/plan.ts
11447
- import fs46 from "node:fs";
11448
- import path54 from "node:path";
11447
+ import fs47 from "node:fs";
11448
+ import path55 from "node:path";
11449
11449
  function generateImportId() {
11450
11450
  return `si-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
11451
11451
  }
11452
11452
  function destinationState(absDest) {
11453
- if (!fs46.existsSync(absDest)) return { exists: false, nonEmpty: false };
11454
- const stats = fs46.statSync(absDest);
11453
+ if (!fs47.existsSync(absDest)) return { exists: false, nonEmpty: false };
11454
+ const stats = fs47.statSync(absDest);
11455
11455
  if (!stats.isDirectory()) {
11456
11456
  throw new Error(`Destination is not a directory: ${absDest}`);
11457
11457
  }
11458
- const entries = fs46.readdirSync(absDest);
11458
+ const entries = fs47.readdirSync(absDest);
11459
11459
  return { exists: true, nonEmpty: entries.length > 0 };
11460
11460
  }
11461
11461
  function describeSource(probe) {
@@ -11465,7 +11465,7 @@ function describeSource(probe) {
11465
11465
  return `skill ${probe.skillId}@${probe.version} (skills.sh)`;
11466
11466
  }
11467
11467
  function buildSourceImportPlan(input) {
11468
- const absDest = path54.resolve(input.destination);
11468
+ const absDest = path55.resolve(input.destination);
11469
11469
  const state = destinationState(absDest);
11470
11470
  const payloadPath = "imported";
11471
11471
  const warnings = [...input.probe.warnings];
@@ -11578,8 +11578,8 @@ var init_plan = __esm({
11578
11578
  });
11579
11579
 
11580
11580
  // src/starter/source-import/summarize.ts
11581
- import fs47 from "node:fs";
11582
- import path55 from "node:path";
11581
+ import fs48 from "node:fs";
11582
+ import path56 from "node:path";
11583
11583
  function sourceHeading(manifest) {
11584
11584
  const src = manifest.source;
11585
11585
  if (src.kind === "github-repo") {
@@ -11634,7 +11634,7 @@ function nextStepsSection(manifest) {
11634
11634
  }
11635
11635
  function writeImportSummary(input) {
11636
11636
  const { forkPath, summaryRelativePath, manifest } = input;
11637
- const summaryPath = path55.resolve(forkPath, summaryRelativePath);
11637
+ const summaryPath = path56.resolve(forkPath, summaryRelativePath);
11638
11638
  const body = [
11639
11639
  `# Source Import Summary`,
11640
11640
  ``,
@@ -11664,8 +11664,8 @@ function writeImportSummary(input) {
11664
11664
  `Generated by the Growthub Source Import Agent. Canonical manifest lives at \`.growthub-fork/source-import.json\`.`,
11665
11665
  ``
11666
11666
  ].join("\n");
11667
- fs47.mkdirSync(path55.dirname(summaryPath), { recursive: true });
11668
- fs47.writeFileSync(summaryPath, body, "utf8");
11667
+ fs48.mkdirSync(path56.dirname(summaryPath), { recursive: true });
11668
+ fs48.writeFileSync(summaryPath, body, "utf8");
11669
11669
  return summaryPath;
11670
11670
  }
11671
11671
  var init_summarize = __esm({
@@ -11675,16 +11675,16 @@ var init_summarize = __esm({
11675
11675
  });
11676
11676
 
11677
11677
  // src/starter/source-import/materialize.ts
11678
- import fs48 from "node:fs";
11678
+ import fs49 from "node:fs";
11679
11679
  import os11 from "node:os";
11680
- import path56 from "node:path";
11680
+ import path57 from "node:path";
11681
11681
  function resolveSourceKind(probe) {
11682
11682
  return probe.kind === "github-repo" ? "github-repo" : "skills-skill";
11683
11683
  }
11684
11684
  function stagingDirFor(forkPath) {
11685
- return path56.join(
11685
+ return path57.join(
11686
11686
  os11.tmpdir(),
11687
- `growthub-source-import-${path56.basename(forkPath)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
11687
+ `growthub-source-import-${path57.basename(forkPath)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
11688
11688
  );
11689
11689
  }
11690
11690
  async function fetchPayload(probe, stagingDir, opts) {
@@ -11716,18 +11716,18 @@ async function fetchPayload(probe, stagingDir, opts) {
11716
11716
  return { payloadRoot: stagingDir };
11717
11717
  }
11718
11718
  function movePayloadIntoFork(payloadRoot, forkPath, payloadRelativePath) {
11719
- const target = path56.resolve(forkPath, payloadRelativePath);
11720
- if (fs48.existsSync(target)) {
11721
- fs48.rmSync(target, { recursive: true, force: true });
11719
+ const target = path57.resolve(forkPath, payloadRelativePath);
11720
+ if (fs49.existsSync(target)) {
11721
+ fs49.rmSync(target, { recursive: true, force: true });
11722
11722
  }
11723
- fs48.mkdirSync(path56.dirname(target), { recursive: true });
11724
- fs48.renameSync(payloadRoot, target);
11723
+ fs49.mkdirSync(path57.dirname(target), { recursive: true });
11724
+ fs49.renameSync(payloadRoot, target);
11725
11725
  return target;
11726
11726
  }
11727
11727
  function writeManifest(forkPath, manifest) {
11728
- const p35 = path56.resolve(forkPath, MANIFEST_RELATIVE_PATH);
11729
- fs48.mkdirSync(path56.dirname(p35), { recursive: true });
11730
- fs48.writeFileSync(p35, JSON.stringify(manifest, null, 2) + "\n", "utf8");
11728
+ const p35 = path57.resolve(forkPath, MANIFEST_RELATIVE_PATH);
11729
+ fs49.mkdirSync(path57.dirname(p35), { recursive: true });
11730
+ fs49.writeFileSync(p35, JSON.stringify(manifest, null, 2) + "\n", "utf8");
11731
11731
  return p35;
11732
11732
  }
11733
11733
  function assertConfirmationsSatisfied(plan, confirmations) {
@@ -11767,7 +11767,7 @@ async function materializeImportPlan(input) {
11767
11767
  requireSkillAcknowledgement: sourceKind === "skills-skill"
11768
11768
  });
11769
11769
  if (security.blocked) {
11770
- fs48.rmSync(fetchResult.payloadRoot, { recursive: true, force: true });
11770
+ fs49.rmSync(fetchResult.payloadRoot, { recursive: true, force: true });
11771
11771
  throw new Error(
11772
11772
  `Security inspection blocked the fetched payload: ${security.summaryLines[0] ?? "blocking finding"}`
11773
11773
  );
@@ -11898,26 +11898,26 @@ var init_materialize = __esm({
11898
11898
  });
11899
11899
 
11900
11900
  // src/starter/source-import/agent.ts
11901
- import fs49 from "node:fs";
11902
- import path57 from "node:path";
11901
+ import fs50 from "node:fs";
11902
+ import path58 from "node:path";
11903
11903
  function resolveJobsDir() {
11904
- return path57.resolve(resolveKitForksHomeDir(), "source-import-jobs");
11904
+ return path58.resolve(resolveKitForksHomeDir(), "source-import-jobs");
11905
11905
  }
11906
11906
  function resolveJobPath2(jobId) {
11907
- return path57.resolve(resolveJobsDir(), `${jobId}.json`);
11907
+ return path58.resolve(resolveJobsDir(), `${jobId}.json`);
11908
11908
  }
11909
11909
  function generateJobId2() {
11910
11910
  return `sij-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
11911
11911
  }
11912
11912
  function writeJob2(job) {
11913
11913
  const p35 = resolveJobPath2(job.jobId);
11914
- fs49.mkdirSync(path57.dirname(p35), { recursive: true });
11915
- fs49.writeFileSync(p35, JSON.stringify(job, null, 2) + "\n", "utf8");
11914
+ fs50.mkdirSync(path58.dirname(p35), { recursive: true });
11915
+ fs50.writeFileSync(p35, JSON.stringify(job, null, 2) + "\n", "utf8");
11916
11916
  }
11917
11917
  function readJobFile(p35) {
11918
- if (!fs49.existsSync(p35)) return null;
11918
+ if (!fs50.existsSync(p35)) return null;
11919
11919
  try {
11920
- return JSON.parse(fs49.readFileSync(p35, "utf8"));
11920
+ return JSON.parse(fs50.readFileSync(p35, "utf8"));
11921
11921
  } catch {
11922
11922
  return null;
11923
11923
  }
@@ -11927,7 +11927,7 @@ function patchJob2(jobId, status, patch = {}) {
11927
11927
  const job = readJobFile(p35);
11928
11928
  if (!job) return null;
11929
11929
  const updated = { ...job, ...patch, status };
11930
- fs49.writeFileSync(p35, JSON.stringify(updated, null, 2) + "\n", "utf8");
11930
+ fs50.writeFileSync(p35, JSON.stringify(updated, null, 2) + "\n", "utf8");
11931
11931
  return updated;
11932
11932
  }
11933
11933
  function getSourceImportJob(jobId) {
@@ -11946,7 +11946,7 @@ async function probeAndPlan(input, destination) {
11946
11946
  }
11947
11947
  async function runSourceImportJob(input) {
11948
11948
  const jobId = generateJobId2();
11949
- const destination = path57.resolve(input.out);
11949
+ const destination = path58.resolve(input.out);
11950
11950
  const sourceKind = input.source.kind;
11951
11951
  const initial = {
11952
11952
  jobId,
@@ -12103,20 +12103,20 @@ __export(source_import_discovery_exports, {
12103
12103
  });
12104
12104
  import * as p33 from "@clack/prompts";
12105
12105
  import pc47 from "picocolors";
12106
- import fs52 from "node:fs";
12107
- import path59 from "node:path";
12106
+ import fs53 from "node:fs";
12107
+ import path60 from "node:path";
12108
12108
  import { pathToFileURL as pathToFileURL4 } from "node:url";
12109
12109
  function slugifyWorkspaceName(input) {
12110
12110
  const slug = input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
12111
12111
  return slug || "custom-workspace";
12112
12112
  }
12113
- function terminalLink3(label, href) {
12113
+ function terminalLink4(label, href) {
12114
12114
  return `\x1B]8;;${href}\x07${label}\x1B]8;;\x07`;
12115
12115
  }
12116
12116
  function folderOpenLabel3(folderPath) {
12117
12117
  const href = pathToFileURL4(folderPath).href;
12118
12118
  const label = process.platform === "darwin" ? "Open in Finder" : process.platform === "win32" ? "Open in Explorer" : "Open folder";
12119
- return terminalLink3(label, href);
12119
+ return terminalLink4(label, href);
12120
12120
  }
12121
12121
  function defaultWorkspaceFolderName(input) {
12122
12122
  if (input.kind === "github-repo") {
@@ -12132,10 +12132,10 @@ async function promptForInteractiveWorkspacePath(input) {
12132
12132
  });
12133
12133
  if (p33.isCancel(raw) || !raw) return null;
12134
12134
  const trimmed = String(raw).trim();
12135
- const expanded = trimmed.startsWith("~/") ? path59.join(process.env.HOME ?? "~", trimmed.slice(2)) : trimmed;
12136
- const resolved = path59.resolve(expanded);
12137
- if (fs52.existsSync(resolved) && fs52.statSync(resolved).isDirectory()) {
12138
- const finalPath = path59.join(resolved, suggestedName);
12135
+ const expanded = trimmed.startsWith("~/") ? path60.join(process.env.HOME ?? "~", trimmed.slice(2)) : trimmed;
12136
+ const resolved = path60.resolve(expanded);
12137
+ if (fs53.existsSync(resolved) && fs53.statSync(resolved).isDirectory()) {
12138
+ const finalPath = path60.join(resolved, suggestedName);
12139
12139
  p33.note(
12140
12140
  [
12141
12141
  `You selected an existing folder: ${resolved}`,
@@ -12403,16 +12403,154 @@ var init_source_import_discovery = __esm({
12403
12403
  });
12404
12404
 
12405
12405
  // src/index.ts
12406
- init_onboard();
12407
- init_doctor();
12408
12406
  import { Command } from "commander";
12409
12407
  import * as p34 from "@clack/prompts";
12410
12408
  import pc48 from "picocolors";
12411
- import fs53 from "node:fs";
12412
- import path60 from "node:path";
12409
+ import fs54 from "node:fs";
12410
+ import path61 from "node:path";
12413
12411
  import { spawnSync as spawnSync7 } from "node:child_process";
12414
12412
  import { fileURLToPath as fileURLToPath7 } from "node:url";
12415
12413
 
12414
+ // src/analytics/posthog.ts
12415
+ init_home();
12416
+ init_session_store();
12417
+ import crypto from "node:crypto";
12418
+ import fs2 from "node:fs";
12419
+ import path4 from "node:path";
12420
+ function resolveHost() {
12421
+ return (process.env.GROWTHUB_POSTHOG_HOST ?? "").trim() || (process.env.NEXT_PUBLIC_POSTHOG_HOST ?? "").trim() || "https://us.posthog.com";
12422
+ }
12423
+ function apiKey() {
12424
+ return (process.env.GROWTHUB_POSTHOG_API_KEY ?? "").trim() || (process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN ?? "").trim();
12425
+ }
12426
+ function debugEnabled() {
12427
+ return process.env.GROWTHUB_POSTHOG_DEBUG === "true";
12428
+ }
12429
+ function resolveHostedIdentity() {
12430
+ if (_hostedUserId !== null || _hostedEmail !== null) {
12431
+ return { userId: _hostedUserId, email: _hostedEmail };
12432
+ }
12433
+ const session = readSession();
12434
+ if (session && !isSessionExpired(session)) {
12435
+ if (typeof session.userId === "string" && session.userId.length > 0) {
12436
+ _hostedUserId = session.userId;
12437
+ }
12438
+ if (typeof session.email === "string" && session.email.length > 0) {
12439
+ _hostedEmail = session.email;
12440
+ }
12441
+ }
12442
+ return { userId: _hostedUserId, email: _hostedEmail };
12443
+ }
12444
+ function isDisabled() {
12445
+ return !apiKey() || process.env.GROWTHUB_TELEMETRY_DISABLED === "true" || process.env.DO_NOT_TRACK === "1" || process.env.CI === "true";
12446
+ }
12447
+ var _machineId = null;
12448
+ var _isFirstRun = false;
12449
+ var _hostedUserId = null;
12450
+ var _hostedEmail = null;
12451
+ function analyticsIdPath() {
12452
+ return path4.resolve(resolvePaperclipHomeDir(), "analytics-machine-id");
12453
+ }
12454
+ function ensureMachineId() {
12455
+ if (_machineId !== null) return _machineId;
12456
+ const idPath = analyticsIdPath();
12457
+ let resolved = "anon";
12458
+ try {
12459
+ if (fs2.existsSync(idPath)) {
12460
+ const stored = fs2.readFileSync(idPath, "utf-8").trim();
12461
+ if (stored.length > 0) {
12462
+ _machineId = stored;
12463
+ return stored;
12464
+ }
12465
+ }
12466
+ _isFirstRun = true;
12467
+ const fresh = crypto.randomUUID();
12468
+ fs2.mkdirSync(path4.dirname(idPath), { recursive: true });
12469
+ fs2.writeFileSync(idPath, fresh, "utf-8");
12470
+ resolved = fresh;
12471
+ } catch {
12472
+ resolved = "anon";
12473
+ }
12474
+ _machineId = resolved;
12475
+ return resolved;
12476
+ }
12477
+ function setHostedUserId(userId) {
12478
+ _hostedUserId = userId;
12479
+ }
12480
+ function track(event, properties) {
12481
+ if (isDisabled()) return;
12482
+ const distinctId = ensureMachineId();
12483
+ const key = apiKey();
12484
+ const host = resolveHost();
12485
+ const identity = resolveHostedIdentity();
12486
+ const body = JSON.stringify({
12487
+ api_key: key,
12488
+ event,
12489
+ distinct_id: distinctId,
12490
+ properties: {
12491
+ ...properties,
12492
+ $lib: "growthub-cli",
12493
+ platform: process.platform,
12494
+ ...identity.userId !== null ? { hosted_user_id: identity.userId } : {},
12495
+ ...identity.email !== null ? { hosted_email: identity.email } : {}
12496
+ },
12497
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
12498
+ });
12499
+ fetch(`${host}/capture/`, {
12500
+ method: "POST",
12501
+ headers: { "Content-Type": "application/json" },
12502
+ body,
12503
+ signal: AbortSignal.timeout(5e3)
12504
+ }).then(async (response) => {
12505
+ if (response.ok) {
12506
+ if (debugEnabled()) {
12507
+ console.error(
12508
+ `[posthog] captured ${event} (${response.status}) user=${identity.userId ?? "none"} email=${identity.email ?? "none"}`
12509
+ );
12510
+ }
12511
+ return;
12512
+ }
12513
+ if (debugEnabled()) {
12514
+ const text69 = await response.text().catch(() => "");
12515
+ console.error(`[posthog] failed ${event} (${response.status}) ${text69.slice(0, 240)}`);
12516
+ }
12517
+ }).catch((err) => {
12518
+ if (debugEnabled()) {
12519
+ console.error(`[posthog] error ${event}: ${err instanceof Error ? err.message : String(err)}`);
12520
+ }
12521
+ });
12522
+ }
12523
+ function trackCliStart() {
12524
+ ensureMachineId();
12525
+ if (_isFirstRun) {
12526
+ track("cli_first_run");
12527
+ }
12528
+ }
12529
+ var ACTIVATION_URL = "https://www.growthub.ai/";
12530
+ function isAlreadyConnected() {
12531
+ const session = readSession();
12532
+ if (!session) return false;
12533
+ return !isSessionExpired(session);
12534
+ }
12535
+ function terminalLink(label, href) {
12536
+ return `\x1B]8;;${href}\x07${label}\x1B]8;;\x07`;
12537
+ }
12538
+ function printActivationNudge(trigger) {
12539
+ if (isAlreadyConnected()) return;
12540
+ track("email_capture_shown", { trigger });
12541
+ const link = terminalLink("growthub.ai \u2014 first month $1", ACTIVATION_URL);
12542
+ console.log("");
12543
+ console.log(` \x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m`);
12544
+ console.log(` \x1B[36m\u2726\x1B[0m Fork anything. Stay current. Ship faster.`);
12545
+ console.log(` \x1B[2mActivate Growthub \u2192\x1B[0m \x1B[36m${link}\x1B[0m`);
12546
+ console.log(` \x1B[2m\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\x1B[0m`);
12547
+ console.log("");
12548
+ }
12549
+
12550
+ // src/index.ts
12551
+ init_onboard();
12552
+ init_doctor();
12553
+
12416
12554
  // src/commands/env.ts
12417
12555
  init_store();
12418
12556
  init_env();
@@ -13070,8 +13208,8 @@ function printItemCompleted(item) {
13070
13208
  const changes = Array.isArray(item.changes) ? item.changes : [];
13071
13209
  const entries = changes.map((changeRaw) => asRecord(changeRaw)).filter((change) => Boolean(change)).map((change) => {
13072
13210
  const kind = asString(change.kind, "update");
13073
- const path61 = asString(change.path, "unknown");
13074
- return `${kind} ${path61}`;
13211
+ const path62 = asString(change.path, "unknown");
13212
+ return `${kind} ${path62}`;
13075
13213
  });
13076
13214
  const preview = entries.length > 0 ? entries.slice(0, 6).join(", ") : "none";
13077
13215
  const more = entries.length > 6 ? ` (+${entries.length - 6} more)` : "";
@@ -13958,27 +14096,27 @@ import pc17 from "picocolors";
13958
14096
 
13959
14097
  // src/client/context.ts
13960
14098
  init_home();
13961
- import fs10 from "node:fs";
13962
- import path9 from "node:path";
14099
+ import fs12 from "node:fs";
14100
+ import path12 from "node:path";
13963
14101
  var DEFAULT_CONTEXT_BASENAME = "context.json";
13964
14102
  var DEFAULT_PROFILE = "default";
13965
14103
  function findContextFileFromAncestors(startDir) {
13966
- const absoluteStartDir = path9.resolve(startDir);
14104
+ const absoluteStartDir = path12.resolve(startDir);
13967
14105
  let currentDir = absoluteStartDir;
13968
14106
  while (true) {
13969
- const candidate = path9.resolve(currentDir, ".paperclip", DEFAULT_CONTEXT_BASENAME);
13970
- if (fs10.existsSync(candidate)) {
14107
+ const candidate = path12.resolve(currentDir, ".paperclip", DEFAULT_CONTEXT_BASENAME);
14108
+ if (fs12.existsSync(candidate)) {
13971
14109
  return candidate;
13972
14110
  }
13973
- const nextDir = path9.resolve(currentDir, "..");
14111
+ const nextDir = path12.resolve(currentDir, "..");
13974
14112
  if (nextDir === currentDir) break;
13975
14113
  currentDir = nextDir;
13976
14114
  }
13977
14115
  return null;
13978
14116
  }
13979
14117
  function resolveContextPath(overridePath) {
13980
- if (overridePath) return path9.resolve(overridePath);
13981
- if (process.env.PAPERCLIP_CONTEXT) return path9.resolve(process.env.PAPERCLIP_CONTEXT);
14118
+ if (overridePath) return path12.resolve(overridePath);
14119
+ if (process.env.PAPERCLIP_CONTEXT) return path12.resolve(process.env.PAPERCLIP_CONTEXT);
13982
14120
  return findContextFileFromAncestors(process.cwd()) ?? resolveDefaultContextPath();
13983
14121
  }
13984
14122
  function defaultClientContext() {
@@ -13990,23 +14128,23 @@ function defaultClientContext() {
13990
14128
  }
13991
14129
  };
13992
14130
  }
13993
- function parseJson2(filePath) {
14131
+ function parseJson3(filePath) {
13994
14132
  try {
13995
- return JSON.parse(fs10.readFileSync(filePath, "utf-8"));
14133
+ return JSON.parse(fs12.readFileSync(filePath, "utf-8"));
13996
14134
  } catch (err) {
13997
14135
  throw new Error(`Failed to parse JSON at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
13998
14136
  }
13999
14137
  }
14000
- function toStringOrUndefined(value) {
14138
+ function toStringOrUndefined2(value) {
14001
14139
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
14002
14140
  }
14003
14141
  function normalizeProfile(value) {
14004
14142
  if (typeof value !== "object" || value === null || Array.isArray(value)) return {};
14005
14143
  const profile = value;
14006
14144
  return {
14007
- apiBase: toStringOrUndefined(profile.apiBase),
14008
- companyId: toStringOrUndefined(profile.companyId),
14009
- apiKeyEnvVarName: toStringOrUndefined(profile.apiKeyEnvVarName)
14145
+ apiBase: toStringOrUndefined2(profile.apiBase),
14146
+ companyId: toStringOrUndefined2(profile.companyId),
14147
+ apiKeyEnvVarName: toStringOrUndefined2(profile.apiKeyEnvVarName)
14010
14148
  };
14011
14149
  }
14012
14150
  function normalizeContext(raw) {
@@ -14015,7 +14153,7 @@ function normalizeContext(raw) {
14015
14153
  }
14016
14154
  const record = raw;
14017
14155
  const version = record.version === 1 ? 1 : 1;
14018
- const currentProfile = toStringOrUndefined(record.currentProfile) ?? DEFAULT_PROFILE;
14156
+ const currentProfile = toStringOrUndefined2(record.currentProfile) ?? DEFAULT_PROFILE;
14019
14157
  const rawProfiles = record.profiles;
14020
14158
  const profiles = {};
14021
14159
  if (typeof rawProfiles === "object" && rawProfiles !== null && !Array.isArray(rawProfiles)) {
@@ -14038,18 +14176,18 @@ function normalizeContext(raw) {
14038
14176
  }
14039
14177
  function readContext(contextPath) {
14040
14178
  const filePath = resolveContextPath(contextPath);
14041
- if (!fs10.existsSync(filePath)) {
14179
+ if (!fs12.existsSync(filePath)) {
14042
14180
  return defaultClientContext();
14043
14181
  }
14044
- const raw = parseJson2(filePath);
14182
+ const raw = parseJson3(filePath);
14045
14183
  return normalizeContext(raw);
14046
14184
  }
14047
14185
  function writeContext(context, contextPath) {
14048
14186
  const filePath = resolveContextPath(contextPath);
14049
- const dir = path9.dirname(filePath);
14050
- fs10.mkdirSync(dir, { recursive: true });
14187
+ const dir = path12.dirname(filePath);
14188
+ fs12.mkdirSync(dir, { recursive: true });
14051
14189
  const normalized = normalizeContext(context);
14052
- fs10.writeFileSync(filePath, `${JSON.stringify(normalized, null, 2)}
14190
+ fs12.writeFileSync(filePath, `${JSON.stringify(normalized, null, 2)}
14053
14191
  `, { mode: 384 });
14054
14192
  }
14055
14193
  function upsertProfile(profileName, patch, contextPath) {
@@ -14101,14 +14239,14 @@ function resolveCommandContext(options, opts) {
14101
14239
  const context = readContext(options.context);
14102
14240
  const { name: profileName, profile } = resolveProfile(context, options.profile);
14103
14241
  const apiBase = options.apiBase?.trim() || process.env.PAPERCLIP_API_URL?.trim() || profile.apiBase || inferApiBaseFromConfig(options.config);
14104
- const apiKey = options.apiKey?.trim() || process.env.PAPERCLIP_API_KEY?.trim() || readKeyFromProfileEnv(profile);
14242
+ const apiKey2 = options.apiKey?.trim() || process.env.PAPERCLIP_API_KEY?.trim() || readKeyFromProfileEnv(profile);
14105
14243
  const companyId = options.companyId?.trim() || process.env.PAPERCLIP_COMPANY_ID?.trim() || profile.companyId;
14106
14244
  if (opts?.requireCompany && !companyId) {
14107
14245
  throw new Error(
14108
14246
  "Company ID is required. Pass --company-id, set PAPERCLIP_COMPANY_ID, or set context profile companyId via `growthub context set`."
14109
14247
  );
14110
14248
  }
14111
- const api = new PaperclipApiClient({ apiBase, apiKey });
14249
+ const api = new PaperclipApiClient({ apiBase, apiKey: apiKey2 });
14112
14250
  return {
14113
14251
  api,
14114
14252
  companyId,
@@ -14468,12 +14606,12 @@ init_run();
14468
14606
  init_auth_bootstrap_ceo();
14469
14607
 
14470
14608
  // src/commands/auth-login.ts
14471
- init_store();
14472
- init_env();
14473
14609
  import os3 from "node:os";
14474
14610
  import * as p14 from "@clack/prompts";
14475
14611
  import pc19 from "picocolors";
14476
14612
  import open from "open";
14613
+ init_store();
14614
+ init_env();
14477
14615
 
14478
14616
  // src/auth/login-flow.ts
14479
14617
  import { createServer } from "node:http";
@@ -14667,11 +14805,11 @@ init_session_store();
14667
14805
 
14668
14806
  // src/auth/overlay-store.ts
14669
14807
  init_paths();
14670
- import fs12 from "node:fs";
14671
- import path12 from "node:path";
14808
+ import fs13 from "node:fs";
14809
+ import path13 from "node:path";
14672
14810
  function parseJson4(filePath) {
14673
14811
  try {
14674
- return JSON.parse(fs12.readFileSync(filePath, "utf-8"));
14812
+ return JSON.parse(fs13.readFileSync(filePath, "utf-8"));
14675
14813
  } catch (err) {
14676
14814
  throw new Error(
14677
14815
  `Failed to parse hosted overlay at ${filePath}: ${err instanceof Error ? err.message : String(err)}`
@@ -14735,27 +14873,27 @@ function normalizeOverlay(raw) {
14735
14873
  }
14736
14874
  function readHostedOverlay() {
14737
14875
  const filePath = resolveHostedOverlayPath();
14738
- if (!fs12.existsSync(filePath)) return null;
14876
+ if (!fs13.existsSync(filePath)) return null;
14739
14877
  return normalizeOverlay(parseJson4(filePath));
14740
14878
  }
14741
14879
  function writeHostedOverlay(overlay) {
14742
14880
  const filePath = resolveHostedOverlayPath();
14743
- fs12.mkdirSync(resolveProfilesDir(), { recursive: true });
14744
- fs12.writeFileSync(filePath, `${JSON.stringify(overlay, null, 2)}
14881
+ fs13.mkdirSync(resolveProfilesDir(), { recursive: true });
14882
+ fs13.writeFileSync(filePath, `${JSON.stringify(overlay, null, 2)}
14745
14883
  `, { mode: 384 });
14746
14884
  try {
14747
- fs12.chmodSync(filePath, 384);
14885
+ fs13.chmodSync(filePath, 384);
14748
14886
  } catch {
14749
14887
  }
14750
14888
  }
14751
14889
  function clearHostedOverlay() {
14752
14890
  const filePath = resolveHostedOverlayPath();
14753
- if (!fs12.existsSync(filePath)) return false;
14754
- fs12.rmSync(filePath, { force: true });
14891
+ if (!fs13.existsSync(filePath)) return false;
14892
+ fs13.rmSync(filePath, { force: true });
14755
14893
  return true;
14756
14894
  }
14757
14895
  function describeHostedOverlayPath() {
14758
- return path12.resolve(resolveHostedOverlayPath());
14896
+ return path13.resolve(resolveHostedOverlayPath());
14759
14897
  }
14760
14898
  function seedHostedOverlayFromSession(input) {
14761
14899
  return {
@@ -14779,8 +14917,8 @@ function seedHostedOverlayFromSession(input) {
14779
14917
  // src/auth/effective-profile.ts
14780
14918
  init_store();
14781
14919
  init_home();
14782
- import fs13 from "node:fs";
14783
- import path13 from "node:path";
14920
+ import fs14 from "node:fs";
14921
+ import path14 from "node:path";
14784
14922
  init_session_store();
14785
14923
  init_paths();
14786
14924
  function toLocalWorkspaceView(configPath, config) {
@@ -14890,10 +15028,10 @@ function computeEffectiveProfile(opts = {}) {
14890
15028
  }
14891
15029
  function writeEffectiveProfileSnapshot(profile) {
14892
15030
  const filePath = resolveEffectiveProfilePath();
14893
- fs13.mkdirSync(resolveProfilesDir(), { recursive: true });
14894
- fs13.writeFileSync(filePath, `${JSON.stringify(profile, null, 2)}
15031
+ fs14.mkdirSync(resolveProfilesDir(), { recursive: true });
15032
+ fs14.writeFileSync(filePath, `${JSON.stringify(profile, null, 2)}
14895
15033
  `, { mode: 384 });
14896
- return path13.resolve(filePath);
15034
+ return path14.resolve(filePath);
14897
15035
  }
14898
15036
 
14899
15037
  // src/commands/auth-login.ts
@@ -15052,6 +15190,8 @@ async function authLogin(opts) {
15052
15190
  writeHostedOverlay(overlay);
15053
15191
  const effective = computeEffectiveProfile({ configPath });
15054
15192
  writeEffectiveProfileSnapshot(effective);
15193
+ if (result.userId) setHostedUserId(result.userId);
15194
+ track("growthub_auth_connected", { has_org: Boolean(result.orgId) });
15055
15195
  if (opts.json) {
15056
15196
  console.log(
15057
15197
  JSON.stringify(
@@ -15414,7 +15554,7 @@ init_src2();
15414
15554
  init_home();
15415
15555
  init_store();
15416
15556
  init_banner();
15417
- import path14 from "node:path";
15557
+ import path15 from "node:path";
15418
15558
  import * as p15 from "@clack/prompts";
15419
15559
  import pc21 from "picocolors";
15420
15560
  function resolveConnectionString(configPath) {
@@ -15438,7 +15578,7 @@ function normalizeRetentionDays(value, fallback) {
15438
15578
  return candidate;
15439
15579
  }
15440
15580
  function resolveBackupDir(raw) {
15441
- return path14.resolve(expandHomePrefix(raw.trim()));
15581
+ return path15.resolve(expandHomePrefix(raw.trim()));
15442
15582
  }
15443
15583
  async function dbBackupCommand(opts) {
15444
15584
  printPaperclipCliBanner();
@@ -15559,7 +15699,7 @@ function registerContextCommands(program2) {
15559
15699
  // src/commands/client/company.ts
15560
15700
  init_http();
15561
15701
  import { mkdir, readFile as readFile3, stat, writeFile as writeFile2 } from "node:fs/promises";
15562
- import path15 from "node:path";
15702
+ import path16 from "node:path";
15563
15703
  function isUuidLike2(value) {
15564
15704
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
15565
15705
  }
@@ -15593,32 +15733,32 @@ function isGithubUrl(input) {
15593
15733
  return /^https?:\/\/github\.com\//i.test(input.trim());
15594
15734
  }
15595
15735
  async function resolveInlineSourceFromPath(inputPath) {
15596
- const resolved = path15.resolve(inputPath);
15736
+ const resolved = path16.resolve(inputPath);
15597
15737
  const resolvedStat = await stat(resolved);
15598
- const manifestPath = resolvedStat.isDirectory() ? path15.join(resolved, "paperclip.manifest.json") : resolved;
15599
- const manifestBaseDir = path15.dirname(manifestPath);
15738
+ const manifestPath = resolvedStat.isDirectory() ? path16.join(resolved, "paperclip.manifest.json") : resolved;
15739
+ const manifestBaseDir = path16.dirname(manifestPath);
15600
15740
  const manifestRaw = await readFile3(manifestPath, "utf8");
15601
15741
  const manifest = JSON.parse(manifestRaw);
15602
15742
  const files = {};
15603
15743
  if (manifest.company?.path) {
15604
15744
  const companyPath = manifest.company.path.replace(/\\/g, "/");
15605
- files[companyPath] = await readFile3(path15.join(manifestBaseDir, companyPath), "utf8");
15745
+ files[companyPath] = await readFile3(path16.join(manifestBaseDir, companyPath), "utf8");
15606
15746
  }
15607
15747
  for (const agent of manifest.agents ?? []) {
15608
15748
  const agentPath = agent.path.replace(/\\/g, "/");
15609
- files[agentPath] = await readFile3(path15.join(manifestBaseDir, agentPath), "utf8");
15749
+ files[agentPath] = await readFile3(path16.join(manifestBaseDir, agentPath), "utf8");
15610
15750
  }
15611
15751
  return { manifest, files };
15612
15752
  }
15613
15753
  async function writeExportToFolder(outDir, exported) {
15614
- const root = path15.resolve(outDir);
15754
+ const root = path16.resolve(outDir);
15615
15755
  await mkdir(root, { recursive: true });
15616
- const manifestPath = path15.join(root, "paperclip.manifest.json");
15756
+ const manifestPath = path16.join(root, "paperclip.manifest.json");
15617
15757
  await writeFile2(manifestPath, JSON.stringify(exported.manifest, null, 2), "utf8");
15618
15758
  for (const [relativePath, content] of Object.entries(exported.files)) {
15619
15759
  const normalized = relativePath.replace(/\\/g, "/");
15620
- const filePath = path15.join(root, normalized);
15621
- await mkdir(path15.dirname(filePath), { recursive: true });
15760
+ const filePath = path16.join(root, normalized);
15761
+ await mkdir(path16.dirname(filePath), { recursive: true });
15622
15762
  await writeFile2(filePath, content, "utf8");
15623
15763
  }
15624
15764
  }
@@ -15741,7 +15881,7 @@ function registerCompanyCommands(program2) {
15741
15881
  printOutput(
15742
15882
  {
15743
15883
  ok: true,
15744
- out: path15.resolve(opts.out),
15884
+ out: path16.resolve(opts.out),
15745
15885
  filesWritten: Object.keys(exported.files).length + 1,
15746
15886
  warningCount: exported.warnings.length
15747
15887
  },
@@ -15903,8 +16043,8 @@ function registerIssueCommands(program2) {
15903
16043
  if (opts.assigneeAgentId) params.set("assigneeAgentId", opts.assigneeAgentId);
15904
16044
  if (opts.projectId) params.set("projectId", opts.projectId);
15905
16045
  const query = params.toString();
15906
- const path61 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
15907
- const rows = await ctx.api.get(path61) ?? [];
16046
+ const path62 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
16047
+ const rows = await ctx.api.get(path62) ?? [];
15908
16048
  const filtered = filterIssueRows(rows, opts.match);
15909
16049
  if (ctx.json) {
15910
16050
  printOutput(filtered, { json: true });
@@ -16066,8 +16206,8 @@ function filterIssueRows(rows, match) {
16066
16206
  }
16067
16207
 
16068
16208
  // ../packages/adapter-utils/src/server-utils.ts
16069
- import { constants as fsConstants, promises as fs14 } from "node:fs";
16070
- import path16 from "node:path";
16209
+ import { constants as fsConstants, promises as fs15 } from "node:fs";
16210
+ import path17 from "node:path";
16071
16211
  var MAX_CAPTURE_BYTES = 4 * 1024 * 1024;
16072
16212
  var MAX_EXCERPT_BYTES = 32 * 1024;
16073
16213
  var PAPERCLIP_SKILL_ROOT_RELATIVE_CANDIDATES = [
@@ -16082,14 +16222,14 @@ function isMaintainerOnlySkillTarget(candidate) {
16082
16222
  }
16083
16223
  async function resolvePaperclipSkillsDir(moduleDir, additionalCandidates = []) {
16084
16224
  const candidates = [
16085
- ...PAPERCLIP_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) => path16.resolve(moduleDir, relativePath)),
16086
- ...additionalCandidates.map((candidate) => path16.resolve(candidate))
16225
+ ...PAPERCLIP_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) => path17.resolve(moduleDir, relativePath)),
16226
+ ...additionalCandidates.map((candidate) => path17.resolve(candidate))
16087
16227
  ];
16088
16228
  const seenRoots = /* @__PURE__ */ new Set();
16089
16229
  for (const root of candidates) {
16090
16230
  if (seenRoots.has(root)) continue;
16091
16231
  seenRoots.add(root);
16092
- const isDirectory = await fs14.stat(root).then((stats) => stats.isDirectory()).catch(() => false);
16232
+ const isDirectory = await fs15.stat(root).then((stats) => stats.isDirectory()).catch(() => false);
16093
16233
  if (isDirectory) return root;
16094
16234
  }
16095
16235
  return null;
@@ -16097,20 +16237,20 @@ async function resolvePaperclipSkillsDir(moduleDir, additionalCandidates = []) {
16097
16237
  async function removeMaintainerOnlySkillSymlinks(skillsHome, allowedSkillNames) {
16098
16238
  const allowed = new Set(Array.from(allowedSkillNames));
16099
16239
  try {
16100
- const entries = await fs14.readdir(skillsHome, { withFileTypes: true });
16240
+ const entries = await fs15.readdir(skillsHome, { withFileTypes: true });
16101
16241
  const removed = [];
16102
16242
  for (const entry of entries) {
16103
16243
  if (allowed.has(entry.name)) continue;
16104
- const target = path16.join(skillsHome, entry.name);
16105
- const existing = await fs14.lstat(target).catch(() => null);
16244
+ const target = path17.join(skillsHome, entry.name);
16245
+ const existing = await fs15.lstat(target).catch(() => null);
16106
16246
  if (!existing?.isSymbolicLink()) continue;
16107
- const linkedPath = await fs14.readlink(target).catch(() => null);
16247
+ const linkedPath = await fs15.readlink(target).catch(() => null);
16108
16248
  if (!linkedPath) continue;
16109
- const resolvedLinkedPath = path16.isAbsolute(linkedPath) ? linkedPath : path16.resolve(path16.dirname(target), linkedPath);
16249
+ const resolvedLinkedPath = path17.isAbsolute(linkedPath) ? linkedPath : path17.resolve(path17.dirname(target), linkedPath);
16110
16250
  if (!isMaintainerOnlySkillTarget(linkedPath) && !isMaintainerOnlySkillTarget(resolvedLinkedPath)) {
16111
16251
  continue;
16112
16252
  }
16113
- await fs14.unlink(target);
16253
+ await fs15.unlink(target);
16114
16254
  removed.push(entry.name);
16115
16255
  }
16116
16256
  return removed;
@@ -16120,20 +16260,20 @@ async function removeMaintainerOnlySkillSymlinks(skillsHome, allowedSkillNames)
16120
16260
  }
16121
16261
 
16122
16262
  // src/commands/client/agent.ts
16123
- import fs15 from "node:fs/promises";
16263
+ import fs16 from "node:fs/promises";
16124
16264
  import os4 from "node:os";
16125
- import path17 from "node:path";
16265
+ import path18 from "node:path";
16126
16266
  import { fileURLToPath as fileURLToPath3 } from "node:url";
16127
- var __moduleDir = path17.dirname(fileURLToPath3(import.meta.url));
16267
+ var __moduleDir = path18.dirname(fileURLToPath3(import.meta.url));
16128
16268
  function codexSkillsHome() {
16129
16269
  const fromEnv = process.env.CODEX_HOME?.trim();
16130
- const base = fromEnv && fromEnv.length > 0 ? fromEnv : path17.join(os4.homedir(), ".codex");
16131
- return path17.join(base, "skills");
16270
+ const base = fromEnv && fromEnv.length > 0 ? fromEnv : path18.join(os4.homedir(), ".codex");
16271
+ return path18.join(base, "skills");
16132
16272
  }
16133
16273
  function claudeSkillsHome() {
16134
16274
  const fromEnv = process.env.CLAUDE_HOME?.trim();
16135
- const base = fromEnv && fromEnv.length > 0 ? fromEnv : path17.join(os4.homedir(), ".claude");
16136
- return path17.join(base, "skills");
16275
+ const base = fromEnv && fromEnv.length > 0 ? fromEnv : path18.join(os4.homedir(), ".claude");
16276
+ return path18.join(base, "skills");
16137
16277
  }
16138
16278
  async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool) {
16139
16279
  const summary = {
@@ -16144,26 +16284,26 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool) {
16144
16284
  skipped: [],
16145
16285
  failed: []
16146
16286
  };
16147
- await fs15.mkdir(targetSkillsDir, { recursive: true });
16148
- const entries = await fs15.readdir(sourceSkillsDir, { withFileTypes: true });
16287
+ await fs16.mkdir(targetSkillsDir, { recursive: true });
16288
+ const entries = await fs16.readdir(sourceSkillsDir, { withFileTypes: true });
16149
16289
  summary.removed = await removeMaintainerOnlySkillSymlinks(
16150
16290
  targetSkillsDir,
16151
16291
  entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name)
16152
16292
  );
16153
16293
  for (const entry of entries) {
16154
16294
  if (!entry.isDirectory()) continue;
16155
- const source = path17.join(sourceSkillsDir, entry.name);
16156
- const target = path17.join(targetSkillsDir, entry.name);
16157
- const existing = await fs15.lstat(target).catch(() => null);
16295
+ const source = path18.join(sourceSkillsDir, entry.name);
16296
+ const target = path18.join(targetSkillsDir, entry.name);
16297
+ const existing = await fs16.lstat(target).catch(() => null);
16158
16298
  if (existing) {
16159
16299
  if (existing.isSymbolicLink()) {
16160
16300
  let linkedPath = null;
16161
16301
  try {
16162
- linkedPath = await fs15.readlink(target);
16302
+ linkedPath = await fs16.readlink(target);
16163
16303
  } catch (err) {
16164
- await fs15.unlink(target);
16304
+ await fs16.unlink(target);
16165
16305
  try {
16166
- await fs15.symlink(source, target);
16306
+ await fs16.symlink(source, target);
16167
16307
  summary.linked.push(entry.name);
16168
16308
  continue;
16169
16309
  } catch (linkErr) {
@@ -16174,10 +16314,10 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool) {
16174
16314
  continue;
16175
16315
  }
16176
16316
  }
16177
- const resolvedLinkedPath = path17.isAbsolute(linkedPath) ? linkedPath : path17.resolve(path17.dirname(target), linkedPath);
16178
- const linkedTargetExists = await fs15.stat(resolvedLinkedPath).then(() => true).catch(() => false);
16317
+ const resolvedLinkedPath = path18.isAbsolute(linkedPath) ? linkedPath : path18.resolve(path18.dirname(target), linkedPath);
16318
+ const linkedTargetExists = await fs16.stat(resolvedLinkedPath).then(() => true).catch(() => false);
16179
16319
  if (!linkedTargetExists) {
16180
- await fs15.unlink(target);
16320
+ await fs16.unlink(target);
16181
16321
  } else {
16182
16322
  summary.skipped.push(entry.name);
16183
16323
  continue;
@@ -16188,7 +16328,7 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool) {
16188
16328
  }
16189
16329
  }
16190
16330
  try {
16191
- await fs15.symlink(source, target);
16331
+ await fs16.symlink(source, target);
16192
16332
  summary.linked.push(entry.name);
16193
16333
  } catch (err) {
16194
16334
  summary.failed.push({
@@ -16277,7 +16417,7 @@ function registerAgentCommands(program2) {
16277
16417
  }
16278
16418
  const installSummaries = [];
16279
16419
  if (opts.installSkills !== false) {
16280
- const skillsDir = await resolvePaperclipSkillsDir(__moduleDir, [path17.resolve(process.cwd(), "skills")]);
16420
+ const skillsDir = await resolvePaperclipSkillsDir(__moduleDir, [path18.resolve(process.cwd(), "skills")]);
16281
16421
  if (!skillsDir) {
16282
16422
  throw new Error(
16283
16423
  "Could not locate local Paperclip skills directory. Expected ./skills in the repo checkout."
@@ -16510,8 +16650,8 @@ function registerActivityCommands(program2) {
16510
16650
  if (opts.entityType) params.set("entityType", opts.entityType);
16511
16651
  if (opts.entityId) params.set("entityId", opts.entityId);
16512
16652
  const query = params.toString();
16513
- const path61 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
16514
- const rows = await ctx.api.get(path61) ?? [];
16653
+ const path62 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
16654
+ const rows = await ctx.api.get(path62) ?? [];
16515
16655
  if (ctx.json) {
16516
16656
  printOutput(rows, { json: true });
16517
16657
  return;
@@ -16560,11 +16700,11 @@ function registerDashboardCommands(program2) {
16560
16700
 
16561
16701
  // src/config/data-dir.ts
16562
16702
  init_home();
16563
- import path18 from "node:path";
16703
+ import path19 from "node:path";
16564
16704
  function applyDataDirOverride(options, support = {}) {
16565
16705
  const rawDataDir = options.dataDir?.trim();
16566
16706
  if (!rawDataDir) return null;
16567
- const resolvedDataDir = path18.resolve(expandHomePrefix(rawDataDir));
16707
+ const resolvedDataDir = path19.resolve(expandHomePrefix(rawDataDir));
16568
16708
  process.env.PAPERCLIP_HOME = resolvedDataDir;
16569
16709
  if (support.hasConfigOption) {
16570
16710
  const hasConfigOverride = Boolean(options.config?.trim()) || Boolean(process.env.PAPERCLIP_CONFIG?.trim());
@@ -16591,35 +16731,35 @@ init_store();
16591
16731
  // src/commands/gtm.ts
16592
16732
  init_src();
16593
16733
  init_home();
16594
- import fs16 from "node:fs";
16595
- import path19 from "node:path";
16734
+ import fs17 from "node:fs";
16735
+ import path20 from "node:path";
16596
16736
  import { spawn } from "node:child_process";
16597
16737
  import pc23 from "picocolors";
16598
16738
  function resolveGtmStatePath() {
16599
- return path19.resolve(resolvePaperclipHomeDir(), "gtm", "state.json");
16739
+ return path20.resolve(resolvePaperclipHomeDir(), "gtm", "state.json");
16600
16740
  }
16601
16741
  function readState() {
16602
16742
  const filePath = resolveGtmStatePath();
16603
- if (!fs16.existsSync(filePath)) return createDefaultGtmState();
16604
- return coerceGtmState(JSON.parse(fs16.readFileSync(filePath, "utf-8")));
16743
+ if (!fs17.existsSync(filePath)) return createDefaultGtmState();
16744
+ return coerceGtmState(JSON.parse(fs17.readFileSync(filePath, "utf-8")));
16605
16745
  }
16606
16746
  function writeState(state) {
16607
16747
  const filePath = resolveGtmStatePath();
16608
- fs16.mkdirSync(path19.dirname(filePath), { recursive: true });
16609
- fs16.writeFileSync(filePath, JSON.stringify(state, null, 2) + "\n", "utf-8");
16748
+ fs17.mkdirSync(path20.dirname(filePath), { recursive: true });
16749
+ fs17.writeFileSync(filePath, JSON.stringify(state, null, 2) + "\n", "utf-8");
16610
16750
  }
16611
16751
  function launchWorkflow(state) {
16612
16752
  const runnerPath = state.workflow.runnerPath?.trim();
16613
16753
  if (!runnerPath) {
16614
16754
  throw new Error("No local SDR runner configured.");
16615
16755
  }
16616
- if (!fs16.existsSync(runnerPath)) {
16756
+ if (!fs17.existsSync(runnerPath)) {
16617
16757
  throw new Error(`Runner not found at ${runnerPath}`);
16618
16758
  }
16619
16759
  const args = runnerPath.endsWith(".mjs") || runnerPath.endsWith(".js") ? [runnerPath] : [];
16620
16760
  const command = args.length > 0 ? process.execPath : runnerPath;
16621
16761
  const child = spawn(command, args, {
16622
- cwd: path19.dirname(runnerPath),
16762
+ cwd: path20.dirname(runnerPath),
16623
16763
  detached: true,
16624
16764
  stdio: "ignore"
16625
16765
  });
@@ -16657,7 +16797,7 @@ function registerGtmCommands(program2) {
16657
16797
  if (opts.internalSocialsPath) state.workflow.referenceInterfaces.internalSocialsPath = opts.internalSocialsPath.trim();
16658
16798
  if (opts.localSdrPath) {
16659
16799
  state.workflow.referenceInterfaces.localSdrPath = opts.localSdrPath.trim();
16660
- state.workflow.runnerPath = path19.resolve(opts.localSdrPath.trim(), "sdr-bot.mjs");
16800
+ state.workflow.runnerPath = path20.resolve(opts.localSdrPath.trim(), "sdr-bot.mjs");
16661
16801
  }
16662
16802
  writeState(state);
16663
16803
  const view = toGtmViewModel(state);
@@ -16710,7 +16850,7 @@ import {
16710
16850
  writeFileSync
16711
16851
  } from "node:fs";
16712
16852
  import os5 from "node:os";
16713
- import path21 from "node:path";
16853
+ import path22 from "node:path";
16714
16854
  import { execFileSync } from "node:child_process";
16715
16855
  import { createServer as createServer2 } from "node:net";
16716
16856
  import * as p16 from "@clack/prompts";
@@ -16720,7 +16860,7 @@ import { eq as eq2 } from "drizzle-orm";
16720
16860
  // src/commands/worktree-lib.ts
16721
16861
  init_home();
16722
16862
  import { randomInt } from "node:crypto";
16723
- import path20 from "node:path";
16863
+ import path21 from "node:path";
16724
16864
  var DEFAULT_WORKTREE_HOME = "~/.paperclip-worktrees";
16725
16865
  var WORKTREE_SEED_MODES = ["minimal", "full"];
16726
16866
  var MINIMAL_WORKTREE_EXCLUDED_TABLES = [
@@ -16768,7 +16908,7 @@ function sanitizeWorktreeInstanceId(rawValue) {
16768
16908
  return normalized || "worktree";
16769
16909
  }
16770
16910
  function resolveSuggestedWorktreeName(cwd, explicitName) {
16771
- return nonEmpty(explicitName) ?? path20.basename(path20.resolve(cwd));
16911
+ return nonEmpty(explicitName) ?? path21.basename(path21.resolve(cwd));
16772
16912
  }
16773
16913
  function hslComponentToHex(n) {
16774
16914
  return Math.round(Math.max(0, Math.min(255, n))).toString(16).padStart(2, "0");
@@ -16808,24 +16948,24 @@ function generateWorktreeColor() {
16808
16948
  return hslToHex(randomInt(0, 360), 68, 56);
16809
16949
  }
16810
16950
  function resolveWorktreeLocalPaths(opts) {
16811
- const cwd = path20.resolve(opts.cwd);
16812
- const homeDir = path20.resolve(expandHomePrefix(opts.homeDir ?? DEFAULT_WORKTREE_HOME));
16813
- const instanceRoot = path20.resolve(homeDir, "instances", opts.instanceId);
16814
- const repoConfigDir = path20.resolve(cwd, ".paperclip");
16951
+ const cwd = path21.resolve(opts.cwd);
16952
+ const homeDir = path21.resolve(expandHomePrefix(opts.homeDir ?? DEFAULT_WORKTREE_HOME));
16953
+ const instanceRoot = path21.resolve(homeDir, "instances", opts.instanceId);
16954
+ const repoConfigDir = path21.resolve(cwd, ".paperclip");
16815
16955
  return {
16816
16956
  cwd,
16817
16957
  repoConfigDir,
16818
- configPath: path20.resolve(repoConfigDir, "config.json"),
16819
- envPath: path20.resolve(repoConfigDir, ".env"),
16958
+ configPath: path21.resolve(repoConfigDir, "config.json"),
16959
+ envPath: path21.resolve(repoConfigDir, ".env"),
16820
16960
  homeDir,
16821
16961
  instanceId: opts.instanceId,
16822
16962
  instanceRoot,
16823
- contextPath: path20.resolve(homeDir, "context.json"),
16824
- embeddedPostgresDataDir: path20.resolve(instanceRoot, "db"),
16825
- backupDir: path20.resolve(instanceRoot, "data", "backups"),
16826
- logDir: path20.resolve(instanceRoot, "logs"),
16827
- secretsKeyFilePath: path20.resolve(instanceRoot, "secrets", "master.key"),
16828
- storageDir: path20.resolve(instanceRoot, "data", "storage")
16963
+ contextPath: path21.resolve(homeDir, "context.json"),
16964
+ embeddedPostgresDataDir: path21.resolve(instanceRoot, "db"),
16965
+ backupDir: path21.resolve(instanceRoot, "data", "backups"),
16966
+ logDir: path21.resolve(instanceRoot, "logs"),
16967
+ secretsKeyFilePath: path21.resolve(instanceRoot, "secrets", "master.key"),
16968
+ storageDir: path21.resolve(instanceRoot, "data", "storage")
16829
16969
  };
16830
16970
  }
16831
16971
  function rewriteLocalUrlPort(rawUrl, port) {
@@ -16931,7 +17071,7 @@ function isCurrentSourceConfigPath(sourceConfigPath) {
16931
17071
  if (!currentConfigPath || currentConfigPath.trim().length === 0) {
16932
17072
  return false;
16933
17073
  }
16934
- return path21.resolve(currentConfigPath) === path21.resolve(sourceConfigPath);
17074
+ return path22.resolve(currentConfigPath) === path22.resolve(sourceConfigPath);
16935
17075
  }
16936
17076
  var WORKTREE_NAME_PREFIX = "paperclip-";
16937
17077
  function resolveWorktreeMakeName(name) {
@@ -16953,7 +17093,7 @@ function resolveWorktreeStartPoint(explicit) {
16953
17093
  return explicit ?? nonEmpty2(process.env.PAPERCLIP_WORKTREE_START_POINT) ?? void 0;
16954
17094
  }
16955
17095
  function resolveWorktreeMakeTargetPath(name) {
16956
- return path21.resolve(os5.homedir(), resolveWorktreeMakeName(name));
17096
+ return path22.resolve(os5.homedir(), resolveWorktreeMakeName(name));
16957
17097
  }
16958
17098
  function extractExecSyncErrorMessage(error) {
16959
17099
  if (!error || typeof error !== "object") {
@@ -17059,10 +17199,10 @@ function detectGitWorkspaceInfo(cwd) {
17059
17199
  stdio: ["ignore", "pipe", "ignore"]
17060
17200
  }).trim();
17061
17201
  return {
17062
- root: path21.resolve(root),
17063
- commonDir: path21.resolve(root, commonDirRaw),
17064
- gitDir: path21.resolve(root, gitDirRaw),
17065
- hooksPath: path21.resolve(root, hooksPathRaw)
17202
+ root: path22.resolve(root),
17203
+ commonDir: path22.resolve(root, commonDirRaw),
17204
+ gitDir: path22.resolve(root, gitDirRaw),
17205
+ hooksPath: path22.resolve(root, hooksPathRaw)
17066
17206
  };
17067
17207
  } catch {
17068
17208
  return null;
@@ -17075,8 +17215,8 @@ function copyDirectoryContents(sourceDir, targetDir) {
17075
17215
  mkdirSync2(targetDir, { recursive: true });
17076
17216
  let copied = false;
17077
17217
  for (const entry of entries) {
17078
- const sourcePath = path21.resolve(sourceDir, entry.name);
17079
- const targetPath = path21.resolve(targetDir, entry.name);
17218
+ const sourcePath = path22.resolve(sourceDir, entry.name);
17219
+ const targetPath = path22.resolve(targetDir, entry.name);
17080
17220
  if (entry.isDirectory()) {
17081
17221
  mkdirSync2(targetPath, { recursive: true });
17082
17222
  copyDirectoryContents(sourcePath, targetPath);
@@ -17102,7 +17242,7 @@ function copyGitHooksToWorktreeGitDir(cwd) {
17102
17242
  const workspace = detectGitWorkspaceInfo(cwd);
17103
17243
  if (!workspace) return null;
17104
17244
  const sourceHooksPath = workspace.hooksPath;
17105
- const targetHooksPath = path21.resolve(workspace.gitDir, "hooks");
17245
+ const targetHooksPath = path22.resolve(workspace.gitDir, "hooks");
17106
17246
  if (sourceHooksPath === targetHooksPath) {
17107
17247
  return {
17108
17248
  sourceHooksPath,
@@ -17117,17 +17257,17 @@ function copyGitHooksToWorktreeGitDir(cwd) {
17117
17257
  };
17118
17258
  }
17119
17259
  function rebindWorkspaceCwd(input) {
17120
- const sourceRepoRoot = path21.resolve(input.sourceRepoRoot);
17121
- const targetRepoRoot = path21.resolve(input.targetRepoRoot);
17122
- const workspaceCwd = path21.resolve(input.workspaceCwd);
17123
- const relative = path21.relative(sourceRepoRoot, workspaceCwd);
17260
+ const sourceRepoRoot = path22.resolve(input.sourceRepoRoot);
17261
+ const targetRepoRoot = path22.resolve(input.targetRepoRoot);
17262
+ const workspaceCwd = path22.resolve(input.workspaceCwd);
17263
+ const relative = path22.relative(sourceRepoRoot, workspaceCwd);
17124
17264
  if (!relative || relative === "") {
17125
17265
  return targetRepoRoot;
17126
17266
  }
17127
- if (relative.startsWith("..") || path21.isAbsolute(relative)) {
17267
+ if (relative.startsWith("..") || path22.isAbsolute(relative)) {
17128
17268
  return null;
17129
17269
  }
17130
- return path21.resolve(targetRepoRoot, relative);
17270
+ return path22.resolve(targetRepoRoot, relative);
17131
17271
  }
17132
17272
  async function rebindSeededProjectWorkspaces(input) {
17133
17273
  const targetRepo = detectGitWorkspaceInfo(input.currentCwd);
@@ -17153,7 +17293,7 @@ async function rebindSeededProjectWorkspaces(input) {
17153
17293
  workspaceCwd
17154
17294
  });
17155
17295
  if (!reboundCwd) continue;
17156
- const normalizedCurrent = path21.resolve(workspaceCwd);
17296
+ const normalizedCurrent = path22.resolve(workspaceCwd);
17157
17297
  if (reboundCwd === normalizedCurrent) continue;
17158
17298
  if (!existsSync2(reboundCwd)) continue;
17159
17299
  await db.update(projectWorkspaces).set({
@@ -17172,14 +17312,14 @@ async function rebindSeededProjectWorkspaces(input) {
17172
17312
  }
17173
17313
  }
17174
17314
  function resolveSourceConfigPath(opts) {
17175
- if (opts.sourceConfigPathOverride) return path21.resolve(opts.sourceConfigPathOverride);
17176
- if (opts.fromConfig) return path21.resolve(opts.fromConfig);
17315
+ if (opts.sourceConfigPathOverride) return path22.resolve(opts.sourceConfigPathOverride);
17316
+ if (opts.fromConfig) return path22.resolve(opts.fromConfig);
17177
17317
  if (!opts.fromDataDir && !opts.fromInstance) {
17178
17318
  return resolveConfigPath();
17179
17319
  }
17180
- const sourceHome = path21.resolve(expandHomePrefix(opts.fromDataDir ?? "~/.paperclip"));
17320
+ const sourceHome = path22.resolve(expandHomePrefix(opts.fromDataDir ?? "~/.paperclip"));
17181
17321
  const sourceInstanceId = sanitizeWorktreeInstanceId(opts.fromInstance ?? "default");
17182
- return path21.resolve(sourceHome, "instances", sourceInstanceId, "config.json");
17322
+ return path22.resolve(sourceHome, "instances", sourceInstanceId, "config.json");
17183
17323
  }
17184
17324
  function resolveSourceConnectionString(config, envEntries, portOverride) {
17185
17325
  if (config.database.mode === "postgres") {
@@ -17198,7 +17338,7 @@ function copySeededSecretsKey(input) {
17198
17338
  if (input.sourceConfig.secrets.provider !== "local_encrypted") {
17199
17339
  return;
17200
17340
  }
17201
- mkdirSync2(path21.dirname(input.targetKeyFilePath), { recursive: true });
17341
+ mkdirSync2(path22.dirname(input.targetKeyFilePath), { recursive: true });
17202
17342
  const allowProcessEnvFallback = isCurrentSourceConfigPath(input.sourceConfigPath);
17203
17343
  const sourceInlineMasterKey = nonEmpty2(input.sourceEnvEntries.PAPERCLIP_SECRETS_MASTER_KEY) ?? (allowProcessEnvFallback ? nonEmpty2(process.env.PAPERCLIP_SECRETS_MASTER_KEY) : null);
17204
17344
  if (sourceInlineMasterKey) {
@@ -17237,7 +17377,7 @@ async function ensureEmbeddedPostgres(dataDir, preferredPort) {
17237
17377
  "Embedded PostgreSQL support requires dependency `embedded-postgres`. Reinstall dependencies and try again."
17238
17378
  );
17239
17379
  }
17240
- const postmasterPidFile = path21.resolve(dataDir, "postmaster.pid");
17380
+ const postmasterPidFile = path22.resolve(dataDir, "postmaster.pid");
17241
17381
  const runningPid = readRunningPostmasterPid(postmasterPidFile);
17242
17382
  if (runningPid) {
17243
17383
  return {
@@ -17260,7 +17400,7 @@ async function ensureEmbeddedPostgres(dataDir, preferredPort) {
17260
17400
  onError: () => {
17261
17401
  }
17262
17402
  });
17263
- if (!existsSync2(path21.resolve(dataDir, "PG_VERSION"))) {
17403
+ if (!existsSync2(path22.resolve(dataDir, "PG_VERSION"))) {
17264
17404
  await instance.initialise();
17265
17405
  }
17266
17406
  if (existsSync2(postmasterPidFile)) {
@@ -17301,7 +17441,7 @@ async function seedWorktreeDatabase(input) {
17301
17441
  );
17302
17442
  const backup = await runDatabaseBackup({
17303
17443
  connectionString: sourceConnectionString,
17304
- backupDir: path21.resolve(input.targetPaths.backupDir, "seed"),
17444
+ backupDir: path22.resolve(input.targetPaths.backupDir, "seed"),
17305
17445
  retentionDays: 7,
17306
17446
  filenamePrefix: `${input.instanceId}-seed`,
17307
17447
  includeMigrationJournal: true,
@@ -17460,7 +17600,7 @@ async function worktreeMakeCommand(nameArg, opts) {
17460
17600
  if (existsSync2(targetPath)) {
17461
17601
  throw new Error(`Target path already exists: ${targetPath}`);
17462
17602
  }
17463
- mkdirSync2(path21.dirname(targetPath), { recursive: true });
17603
+ mkdirSync2(path22.dirname(targetPath), { recursive: true });
17464
17604
  if (startPoint) {
17465
17605
  const [remote] = startPoint.split("/", 1);
17466
17606
  try {
@@ -17517,7 +17657,7 @@ async function worktreeMakeCommand(nameArg, opts) {
17517
17657
  } finally {
17518
17658
  process.chdir(originalCwd);
17519
17659
  }
17520
- const bootstrapScript = path21.resolve(sourceCwd, "scripts/worktree-bootstrap.mjs");
17660
+ const bootstrapScript = path22.resolve(sourceCwd, "scripts/worktree-bootstrap.mjs");
17521
17661
  if (existsSync2(bootstrapScript)) {
17522
17662
  p16.log.message(pc24.dim(`Running worktree bootstrap in ${targetPath}...`));
17523
17663
  try {
@@ -17607,14 +17747,14 @@ async function worktreeCleanupCommand(nameArg, opts) {
17607
17747
  const sourceCwd = process.cwd();
17608
17748
  const targetPath = resolveWorktreeMakeTargetPath(name);
17609
17749
  const instanceId = sanitizeWorktreeInstanceId(opts.instance ?? name);
17610
- const homeDir = path21.resolve(expandHomePrefix(resolveWorktreeHome(opts.home)));
17611
- const instanceRoot = path21.resolve(homeDir, "instances", instanceId);
17750
+ const homeDir = path22.resolve(expandHomePrefix(resolveWorktreeHome(opts.home)));
17751
+ const instanceRoot = path22.resolve(homeDir, "instances", instanceId);
17612
17752
  const hasBranch = localBranchExists(sourceCwd, name);
17613
17753
  const hasTargetDir = existsSync2(targetPath);
17614
17754
  const hasInstanceData = existsSync2(instanceRoot);
17615
17755
  const worktrees = parseGitWorktreeList(sourceCwd);
17616
17756
  const linkedWorktree = worktrees.find(
17617
- (wt) => wt.branch === `refs/heads/${name}` || path21.resolve(wt.worktree) === path21.resolve(targetPath)
17757
+ (wt) => wt.branch === `refs/heads/${name}` || path22.resolve(wt.worktree) === path22.resolve(targetPath)
17618
17758
  );
17619
17759
  if (!hasBranch && !hasTargetDir && !hasInstanceData && !linkedWorktree) {
17620
17760
  p16.log.info("Nothing to clean up \u2014 no branch, worktree directory, or instance data found.");
@@ -17736,16 +17876,16 @@ function registerWorktreeCommands(program2) {
17736
17876
  }
17737
17877
 
17738
17878
  // src/commands/client/plugin.ts
17739
- import path22 from "node:path";
17879
+ import path23 from "node:path";
17740
17880
  import pc25 from "picocolors";
17741
17881
  function resolvePackageArg(packageArg, isLocal) {
17742
17882
  if (!isLocal) return packageArg;
17743
- if (path22.isAbsolute(packageArg)) return packageArg;
17883
+ if (path23.isAbsolute(packageArg)) return packageArg;
17744
17884
  if (packageArg.startsWith("~")) {
17745
17885
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
17746
- return path22.resolve(home, packageArg.slice(1).replace(/^[\\/]/, ""));
17886
+ return path23.resolve(home, packageArg.slice(1).replace(/^[\\/]/, ""));
17747
17887
  }
17748
- return path22.resolve(process.cwd(), packageArg);
17888
+ return path23.resolve(process.cwd(), packageArg);
17749
17889
  }
17750
17890
  function formatPlugin(p35) {
17751
17891
  const statusColor3 = p35.status === "ready" ? pc25.green(p35.status) : p35.status === "error" ? pc25.red(p35.status) : p35.status === "disabled" ? pc25.dim(p35.status) : pc25.yellow(p35.status);
@@ -17943,15 +18083,15 @@ ${result.lastError}`);
17943
18083
  }
17944
18084
 
17945
18085
  // src/commands/kit.ts
17946
- init_service();
17947
- init_banner();
17948
- import path34 from "node:path";
18086
+ import path35 from "node:path";
17949
18087
  import { pathToFileURL as pathToFileURL2 } from "node:url";
17950
18088
  import * as p19 from "@clack/prompts";
17951
18089
  import pc30 from "picocolors";
18090
+ init_service();
18091
+ init_banner();
17952
18092
 
17953
18093
  // src/commands/kit-fork.ts
17954
- import fs27 from "node:fs";
18094
+ import fs28 from "node:fs";
17955
18095
  import * as p18 from "@clack/prompts";
17956
18096
 
17957
18097
  // src/commands/kit-fork-remote.ts
@@ -17961,50 +18101,50 @@ init_fork_trace();
17961
18101
  init_fork_remote();
17962
18102
  import * as p17 from "@clack/prompts";
17963
18103
  import pc26 from "picocolors";
17964
- import fs25 from "node:fs";
17965
- import path32 from "node:path";
18104
+ import fs26 from "node:fs";
18105
+ import path33 from "node:path";
17966
18106
 
17967
18107
  // src/kits/fork-sync-agent.ts
17968
18108
  init_kit_forks_home();
17969
18109
  init_fork_registry();
17970
- import fs24 from "node:fs";
17971
- import path31 from "node:path";
18110
+ import fs25 from "node:fs";
18111
+ import path32 from "node:path";
17972
18112
 
17973
18113
  // src/kits/fork-sync.ts
17974
18114
  init_service();
17975
- import fs22 from "node:fs";
17976
- import path29 from "node:path";
18115
+ import fs23 from "node:fs";
18116
+ import path30 from "node:path";
17977
18117
  import { fileURLToPath as fileURLToPath5 } from "node:url";
17978
18118
  function resolveUpstreamAssetRoot(kitId) {
17979
- const moduleDir = path29.dirname(fileURLToPath5(import.meta.url));
18119
+ const moduleDir = path30.dirname(fileURLToPath5(import.meta.url));
17980
18120
  const candidates = [
17981
- path29.resolve(moduleDir, "../../assets/worker-kits", kitId),
17982
- path29.resolve(moduleDir, "../assets/worker-kits", kitId)
18121
+ path30.resolve(moduleDir, "../../assets/worker-kits", kitId),
18122
+ path30.resolve(moduleDir, "../assets/worker-kits", kitId)
17983
18123
  ];
17984
18124
  for (const c of candidates) {
17985
- if (fs22.existsSync(c)) return c;
18125
+ if (fs23.existsSync(c)) return c;
17986
18126
  }
17987
18127
  throw new Error(`Cannot locate bundled asset root for kit: ${kitId}`);
17988
18128
  }
17989
18129
  function readFileIfExists(p35) {
17990
- if (!fs22.existsSync(p35)) return null;
18130
+ if (!fs23.existsSync(p35)) return null;
17991
18131
  try {
17992
- return fs22.readFileSync(p35, "utf8");
18132
+ return fs23.readFileSync(p35, "utf8");
17993
18133
  } catch {
17994
18134
  return null;
17995
18135
  }
17996
18136
  }
17997
18137
  function listRelativeFiles2(rootDir) {
17998
18138
  const files = /* @__PURE__ */ new Set();
17999
- if (!fs22.existsSync(rootDir)) return files;
18139
+ if (!fs23.existsSync(rootDir)) return files;
18000
18140
  const walk = (cur) => {
18001
- for (const entry of fs22.readdirSync(cur, { withFileTypes: true })) {
18002
- const full = path29.join(cur, entry.name);
18141
+ for (const entry of fs23.readdirSync(cur, { withFileTypes: true })) {
18142
+ const full = path30.join(cur, entry.name);
18003
18143
  if (entry.isDirectory()) {
18004
18144
  walk(full);
18005
18145
  continue;
18006
18146
  }
18007
- files.add(path29.relative(rootDir, full).split(path29.sep).join("/"));
18147
+ files.add(path30.relative(rootDir, full).split(path30.sep).join("/"));
18008
18148
  }
18009
18149
  };
18010
18150
  walk(rootDir);
@@ -18068,7 +18208,7 @@ function getUpstreamFiles(kitId) {
18068
18208
  return files;
18069
18209
  }
18070
18210
  function detectKitForkDrift(reg) {
18071
- if (!fs22.existsSync(reg.forkPath)) {
18211
+ if (!fs23.existsSync(reg.forkPath)) {
18072
18212
  throw new Error(`Fork path does not exist: ${reg.forkPath}`);
18073
18213
  }
18074
18214
  const allKits = listBundledKits();
@@ -18107,8 +18247,8 @@ function detectKitForkDrift(reg) {
18107
18247
  const AUDIT_PATHS = ["kit.json", "package.json", ".env.example", "QUICKSTART.md"];
18108
18248
  for (const rel of AUDIT_PATHS) {
18109
18249
  if (upstreamFiles.has(rel) && forkFiles.has(rel)) {
18110
- const upContent = readFileIfExists(path29.resolve(upstreamRoot, rel));
18111
- const fkContent = readFileIfExists(path29.resolve(reg.forkPath, rel));
18250
+ const upContent = readFileIfExists(path30.resolve(upstreamRoot, rel));
18251
+ const fkContent = readFileIfExists(path30.resolve(reg.forkPath, rel));
18112
18252
  if (upContent !== null && fkContent !== null && upContent !== fkContent) {
18113
18253
  fileDrifts.push({
18114
18254
  relativePath: rel,
@@ -18120,12 +18260,12 @@ function detectKitForkDrift(reg) {
18120
18260
  }
18121
18261
  }
18122
18262
  let packageDrifts = [];
18123
- const upPkgPath = path29.resolve(upstreamRoot, "package.json");
18124
- const fkPkgPath = path29.resolve(reg.forkPath, "package.json");
18125
- if (fs22.existsSync(upPkgPath) && fs22.existsSync(fkPkgPath)) {
18263
+ const upPkgPath = path30.resolve(upstreamRoot, "package.json");
18264
+ const fkPkgPath = path30.resolve(reg.forkPath, "package.json");
18265
+ if (fs23.existsSync(upPkgPath) && fs23.existsSync(fkPkgPath)) {
18126
18266
  try {
18127
- const upPkg = JSON.parse(fs22.readFileSync(upPkgPath, "utf8"));
18128
- const fkPkg = JSON.parse(fs22.readFileSync(fkPkgPath, "utf8"));
18267
+ const upPkg = JSON.parse(fs23.readFileSync(upPkgPath, "utf8"));
18268
+ const fkPkg = JSON.parse(fs23.readFileSync(fkPkgPath, "utf8"));
18129
18269
  packageDrifts = detectPackageDrift(upPkg, fkPkg);
18130
18270
  } catch {
18131
18271
  }
@@ -18384,38 +18524,38 @@ function executeHealAction(action, forkPath, kitId, _toVersion) {
18384
18524
  }
18385
18525
  }
18386
18526
  function execAddFile(action, forkPath, kitId) {
18387
- const targetFull = path29.resolve(forkPath, action.targetPath);
18388
- if (fs22.existsSync(targetFull)) {
18527
+ const targetFull = path30.resolve(forkPath, action.targetPath);
18528
+ if (fs23.existsSync(targetFull)) {
18389
18529
  return { action, status: "skipped", detail: "File already exists in fork" };
18390
18530
  }
18391
18531
  const upstreamRoot = resolveUpstreamAssetRoot(kitId);
18392
- const upstreamFull = path29.resolve(upstreamRoot, action.targetPath);
18393
- if (!fs22.existsSync(upstreamFull)) {
18532
+ const upstreamFull = path30.resolve(upstreamRoot, action.targetPath);
18533
+ if (!fs23.existsSync(upstreamFull)) {
18394
18534
  return { action, status: "skipped", detail: "Upstream file not found \u2014 skipped" };
18395
18535
  }
18396
18536
  const content = readFileIfExists(upstreamFull);
18397
18537
  if (content === null) {
18398
18538
  return { action, status: "skipped", detail: "Could not read upstream file (binary?) \u2014 skipped" };
18399
18539
  }
18400
- fs22.mkdirSync(path29.dirname(targetFull), { recursive: true });
18401
- fs22.writeFileSync(targetFull, content, "utf8");
18540
+ fs23.mkdirSync(path30.dirname(targetFull), { recursive: true });
18541
+ fs23.writeFileSync(targetFull, content, "utf8");
18402
18542
  return { action, status: "applied", detail: `Added ${action.targetPath}` };
18403
18543
  }
18404
18544
  function execUpdatePackageDeps(action, forkPath, kitId) {
18405
- const forkPkgPath = path29.resolve(forkPath, "package.json");
18406
- if (!fs22.existsSync(forkPkgPath)) {
18545
+ const forkPkgPath = path30.resolve(forkPath, "package.json");
18546
+ if (!fs23.existsSync(forkPkgPath)) {
18407
18547
  return { action, status: "skipped", detail: "No package.json in fork" };
18408
18548
  }
18409
18549
  const upstreamRoot = resolveUpstreamAssetRoot(kitId);
18410
- const upstreamPkgPath = path29.resolve(upstreamRoot, "package.json");
18411
- if (!fs22.existsSync(upstreamPkgPath)) {
18550
+ const upstreamPkgPath = path30.resolve(upstreamRoot, "package.json");
18551
+ if (!fs23.existsSync(upstreamPkgPath)) {
18412
18552
  return { action, status: "skipped", detail: "No package.json in upstream kit" };
18413
18553
  }
18414
18554
  let forkPkg;
18415
18555
  let upstreamPkg;
18416
18556
  try {
18417
- forkPkg = JSON.parse(fs22.readFileSync(forkPkgPath, "utf8"));
18418
- upstreamPkg = JSON.parse(fs22.readFileSync(upstreamPkgPath, "utf8"));
18557
+ forkPkg = JSON.parse(fs23.readFileSync(forkPkgPath, "utf8"));
18558
+ upstreamPkg = JSON.parse(fs23.readFileSync(upstreamPkgPath, "utf8"));
18419
18559
  } catch {
18420
18560
  return { action, status: "error", detail: "Failed to parse package.json" };
18421
18561
  }
@@ -18433,7 +18573,7 @@ function execUpdatePackageDeps(action, forkPath, kitId) {
18433
18573
  const updated = { ...forkPkg };
18434
18574
  if (mergedDeps) updated.dependencies = mergedDeps;
18435
18575
  if (mergedDevDeps) updated.devDependencies = mergedDevDeps;
18436
- fs22.writeFileSync(forkPkgPath, JSON.stringify(updated, null, 2) + "\n", "utf8");
18576
+ fs23.writeFileSync(forkPkgPath, JSON.stringify(updated, null, 2) + "\n", "utf8");
18437
18577
  return { action, status: "applied", detail: "Merged upstream dependency additions" };
18438
18578
  }
18439
18579
  function mergeAddOnlyDeps(fork, upstream) {
@@ -18449,20 +18589,20 @@ function mergeAddOnlyDeps(fork, upstream) {
18449
18589
  return changed ? merged : null;
18450
18590
  }
18451
18591
  function execPatchManifest(action, forkPath, kitId) {
18452
- const forkManifestPath = path29.resolve(forkPath, "kit.json");
18453
- if (!fs22.existsSync(forkManifestPath)) {
18592
+ const forkManifestPath = path30.resolve(forkPath, "kit.json");
18593
+ if (!fs23.existsSync(forkManifestPath)) {
18454
18594
  return { action, status: "skipped", detail: "No kit.json in fork" };
18455
18595
  }
18456
18596
  const upstreamRoot = resolveUpstreamAssetRoot(kitId);
18457
- const upstreamManifestPath = path29.resolve(upstreamRoot, "kit.json");
18458
- if (!fs22.existsSync(upstreamManifestPath)) {
18597
+ const upstreamManifestPath = path30.resolve(upstreamRoot, "kit.json");
18598
+ if (!fs23.existsSync(upstreamManifestPath)) {
18459
18599
  return { action, status: "skipped", detail: "No kit.json in upstream kit" };
18460
18600
  }
18461
18601
  let forkManifest;
18462
18602
  let upstreamManifest;
18463
18603
  try {
18464
- forkManifest = JSON.parse(fs22.readFileSync(forkManifestPath, "utf8"));
18465
- upstreamManifest = JSON.parse(fs22.readFileSync(upstreamManifestPath, "utf8"));
18604
+ forkManifest = JSON.parse(fs23.readFileSync(forkManifestPath, "utf8"));
18605
+ upstreamManifest = JSON.parse(fs23.readFileSync(upstreamManifestPath, "utf8"));
18466
18606
  } catch {
18467
18607
  return { action, status: "error", detail: "Failed to parse kit.json" };
18468
18608
  }
@@ -18478,7 +18618,7 @@ function execPatchManifest(action, forkPath, kitId) {
18478
18618
  if (patched.length === 0) {
18479
18619
  return { action, status: "skipped", detail: "kit.json alignment fields already match" };
18480
18620
  }
18481
- fs22.writeFileSync(forkManifestPath, JSON.stringify(updated, null, 2) + "\n", "utf8");
18621
+ fs23.writeFileSync(forkManifestPath, JSON.stringify(updated, null, 2) + "\n", "utf8");
18482
18622
  return { action, status: "applied", detail: `Patched kit.json fields: ${patched.join(", ")}` };
18483
18623
  }
18484
18624
 
@@ -18489,35 +18629,35 @@ init_fork_remote();
18489
18629
  init_github_resolver();
18490
18630
  init_client2();
18491
18631
  function resolveInForkJobsDir(forkPath) {
18492
- return path31.resolve(resolveInForkStateDir(forkPath), "jobs");
18632
+ return path32.resolve(resolveInForkStateDir(forkPath), "jobs");
18493
18633
  }
18494
18634
  function resolveJobPath(jobId, kitId, forkId) {
18495
18635
  const forkPath = lookupKitForkPath(kitId, forkId);
18496
18636
  if (forkPath) {
18497
- return path31.resolve(resolveInForkJobsDir(forkPath), `${jobId}.json`);
18637
+ return path32.resolve(resolveInForkJobsDir(forkPath), `${jobId}.json`);
18498
18638
  }
18499
- return path31.resolve(resolveKitForksOrphanJobsDir(), `${jobId}.json`);
18639
+ return path32.resolve(resolveKitForksOrphanJobsDir(), `${jobId}.json`);
18500
18640
  }
18501
18641
  function resolveOrphanJobPath(jobId) {
18502
- return path31.resolve(resolveKitForksOrphanJobsDir(), `${jobId}.json`);
18642
+ return path32.resolve(resolveKitForksOrphanJobsDir(), `${jobId}.json`);
18503
18643
  }
18504
18644
  function generateJobId() {
18505
18645
  return `kfj-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
18506
18646
  }
18507
18647
  function parseJobFile(p35) {
18508
- if (!fs24.existsSync(p35)) return null;
18648
+ if (!fs25.existsSync(p35)) return null;
18509
18649
  try {
18510
- return JSON.parse(fs24.readFileSync(p35, "utf8"));
18650
+ return JSON.parse(fs25.readFileSync(p35, "utf8"));
18511
18651
  } catch {
18512
18652
  return null;
18513
18653
  }
18514
18654
  }
18515
18655
  function findJobPath(jobId) {
18516
18656
  const orphanPath = resolveOrphanJobPath(jobId);
18517
- if (fs24.existsSync(orphanPath)) return orphanPath;
18657
+ if (fs25.existsSync(orphanPath)) return orphanPath;
18518
18658
  for (const reg of listKitForkRegistrations()) {
18519
- const p35 = path31.resolve(resolveInForkJobsDir(reg.forkPath), `${jobId}.json`);
18520
- if (fs24.existsSync(p35)) return p35;
18659
+ const p35 = path32.resolve(resolveInForkJobsDir(reg.forkPath), `${jobId}.json`);
18660
+ if (fs25.existsSync(p35)) return p35;
18521
18661
  }
18522
18662
  return null;
18523
18663
  }
@@ -18527,8 +18667,8 @@ function readJob(jobId) {
18527
18667
  }
18528
18668
  function writeJob(job) {
18529
18669
  const p35 = resolveJobPath(job.jobId, job.kitId, job.forkId);
18530
- fs24.mkdirSync(path31.dirname(p35), { recursive: true });
18531
- fs24.writeFileSync(p35, JSON.stringify(job, null, 2) + "\n", "utf8");
18670
+ fs25.mkdirSync(path32.dirname(p35), { recursive: true });
18671
+ fs25.writeFileSync(p35, JSON.stringify(job, null, 2) + "\n", "utf8");
18532
18672
  }
18533
18673
  function patchJob(jobId, status, patch) {
18534
18674
  const existingPath = findJobPath(jobId);
@@ -18537,30 +18677,30 @@ function patchJob(jobId, status, patch) {
18537
18677
  if (!job) return null;
18538
18678
  const updated = { ...job, ...patch, status };
18539
18679
  const targetPath = resolveJobPath(updated.jobId, updated.kitId, updated.forkId);
18540
- if (path31.resolve(existingPath) !== path31.resolve(targetPath)) {
18541
- fs24.mkdirSync(path31.dirname(targetPath), { recursive: true });
18542
- fs24.rmSync(existingPath, { force: true });
18680
+ if (path32.resolve(existingPath) !== path32.resolve(targetPath)) {
18681
+ fs25.mkdirSync(path32.dirname(targetPath), { recursive: true });
18682
+ fs25.rmSync(existingPath, { force: true });
18543
18683
  }
18544
- fs24.mkdirSync(path31.dirname(targetPath), { recursive: true });
18545
- fs24.writeFileSync(targetPath, JSON.stringify(updated, null, 2) + "\n", "utf8");
18684
+ fs25.mkdirSync(path32.dirname(targetPath), { recursive: true });
18685
+ fs25.writeFileSync(targetPath, JSON.stringify(updated, null, 2) + "\n", "utf8");
18546
18686
  return updated;
18547
18687
  }
18548
18688
  function collectAllJobFiles() {
18549
18689
  const files = [];
18550
18690
  for (const reg of listKitForkRegistrations()) {
18551
18691
  const dir = resolveInForkJobsDir(reg.forkPath);
18552
- if (!fs24.existsSync(dir)) continue;
18553
- for (const entry of fs24.readdirSync(dir, { withFileTypes: true })) {
18692
+ if (!fs25.existsSync(dir)) continue;
18693
+ for (const entry of fs25.readdirSync(dir, { withFileTypes: true })) {
18554
18694
  if (entry.isFile() && entry.name.endsWith(".json")) {
18555
- files.push(path31.resolve(dir, entry.name));
18695
+ files.push(path32.resolve(dir, entry.name));
18556
18696
  }
18557
18697
  }
18558
18698
  }
18559
18699
  const orphanDir = resolveKitForksOrphanJobsDir();
18560
- if (fs24.existsSync(orphanDir)) {
18561
- for (const entry of fs24.readdirSync(orphanDir, { withFileTypes: true })) {
18700
+ if (fs25.existsSync(orphanDir)) {
18701
+ for (const entry of fs25.readdirSync(orphanDir, { withFileTypes: true })) {
18562
18702
  if (entry.isFile() && entry.name.endsWith(".json")) {
18563
- files.push(path31.resolve(orphanDir, entry.name));
18703
+ files.push(path32.resolve(orphanDir, entry.name));
18564
18704
  }
18565
18705
  }
18566
18706
  }
@@ -18598,7 +18738,7 @@ function pruneKitForkSyncJobs(retentionMs = 7 * 24 * 60 * 60 * 1e3) {
18598
18738
  if (!terminal.includes(job.status)) continue;
18599
18739
  const ts = new Date(job.completedAt ?? job.createdAt).getTime();
18600
18740
  if (ts < cutoff) {
18601
- fs24.rmSync(filePath, { force: true });
18741
+ fs25.rmSync(filePath, { force: true });
18602
18742
  pruned++;
18603
18743
  }
18604
18744
  }
@@ -18858,8 +18998,8 @@ async function requireGithubToken() {
18858
18998
  async function kitForkCreate(opts) {
18859
18999
  const accessToken = await requireGithubToken();
18860
19000
  const upstream = parseRepoRef(opts.upstream);
18861
- const absOut = path32.resolve(opts.out);
18862
- if (fs25.existsSync(absOut) && fs25.readdirSync(absOut).length > 0) {
19001
+ const absOut = path33.resolve(opts.out);
19002
+ if (fs26.existsSync(absOut) && fs26.readdirSync(absOut).length > 0) {
18863
19003
  throw new Error(`Destination ${absOut} already exists and is not empty.`);
18864
19004
  }
18865
19005
  p17.log.step(`Forking ${upstream.owner}/${upstream.repo} on GitHub...`);
@@ -19260,9 +19400,9 @@ Examples:
19260
19400
  }
19261
19401
 
19262
19402
  // src/commands/kit-fork.ts
19403
+ import pc29 from "picocolors";
19263
19404
  init_banner();
19264
19405
  init_table_renderer();
19265
- import pc29 from "picocolors";
19266
19406
 
19267
19407
  // src/utils/progress.ts
19268
19408
  import pc28 from "picocolors";
@@ -19304,20 +19444,20 @@ init_fork_trace();
19304
19444
  // src/kits/fork-authority.ts
19305
19445
  init_home();
19306
19446
  init_kit_forks_home();
19307
- import crypto from "node:crypto";
19308
- import fs26 from "node:fs";
19447
+ import crypto2 from "node:crypto";
19448
+ import fs27 from "node:fs";
19309
19449
  import os8 from "node:os";
19310
- import path33 from "node:path";
19450
+ import path34 from "node:path";
19311
19451
  function resolveAuthorityHomeDir() {
19312
19452
  const env = process.env.GROWTHUB_AUTHORITY_HOME?.trim();
19313
- if (env) return path33.resolve(expandHomePrefix(env));
19314
- return path33.resolve(os8.homedir(), ".growthub", "authority");
19453
+ if (env) return path34.resolve(expandHomePrefix(env));
19454
+ return path34.resolve(os8.homedir(), ".growthub", "authority");
19315
19455
  }
19316
19456
  function resolveAuthorityIssuersPath() {
19317
- return path33.resolve(resolveAuthorityHomeDir(), "issuers.json");
19457
+ return path34.resolve(resolveAuthorityHomeDir(), "issuers.json");
19318
19458
  }
19319
19459
  function resolveInForkAuthorityPath(forkPath) {
19320
- return path33.resolve(resolveInForkStateDir(forkPath), "authority.json");
19460
+ return path34.resolve(resolveInForkStateDir(forkPath), "authority.json");
19321
19461
  }
19322
19462
  function canonicalize(value) {
19323
19463
  if (value === null) return "null";
@@ -19363,13 +19503,13 @@ function computePolicyHash(policy) {
19363
19503
  interactiveConflicts: policy.interactiveConflicts,
19364
19504
  allowedScripts: [...policy.allowedScripts].sort()
19365
19505
  };
19366
- return crypto.createHash("sha256").update(canonicalize(shape), "utf8").digest("hex");
19506
+ return crypto2.createHash("sha256").update(canonicalize(shape), "utf8").digest("hex");
19367
19507
  }
19368
19508
  function readIssuerRegistry() {
19369
19509
  const p35 = resolveAuthorityIssuersPath();
19370
- if (!fs26.existsSync(p35)) return { version: 1, issuers: [] };
19510
+ if (!fs27.existsSync(p35)) return { version: 1, issuers: [] };
19371
19511
  try {
19372
- const parsed = JSON.parse(fs26.readFileSync(p35, "utf8"));
19512
+ const parsed = JSON.parse(fs27.readFileSync(p35, "utf8"));
19373
19513
  if (!parsed || !Array.isArray(parsed.issuers)) return { version: 1, issuers: [] };
19374
19514
  return { version: 1, issuers: parsed.issuers.filter(isValidIssuer) };
19375
19515
  } catch {
@@ -19383,8 +19523,8 @@ function isValidIssuer(x) {
19383
19523
  }
19384
19524
  function writeIssuerRegistry(registry) {
19385
19525
  const p35 = resolveAuthorityIssuersPath();
19386
- fs26.mkdirSync(path33.dirname(p35), { recursive: true });
19387
- fs26.writeFileSync(p35, JSON.stringify({ version: 1, issuers: registry.issuers }, null, 2) + "\n", "utf8");
19526
+ fs27.mkdirSync(path34.dirname(p35), { recursive: true });
19527
+ fs27.writeFileSync(p35, JSON.stringify({ version: 1, issuers: registry.issuers }, null, 2) + "\n", "utf8");
19388
19528
  }
19389
19529
  function upsertIssuer(issuer) {
19390
19530
  if (!isValidIssuer(issuer)) {
@@ -19442,8 +19582,8 @@ function verifyAuthorityEnvelope(envelope, options = {}) {
19442
19582
  try {
19443
19583
  const { signature: _omit, ...unsigned } = envelope;
19444
19584
  const payload = buildSigningPayload(unsigned);
19445
- const pubKey = crypto.createPublicKey({ key: issuer.publicKeyPem, format: "pem" });
19446
- ok = crypto.verify(null, Buffer.from(payload, "utf8"), pubKey, signatureBytes);
19585
+ const pubKey = crypto2.createPublicKey({ key: issuer.publicKeyPem, format: "pem" });
19586
+ ok = crypto2.verify(null, Buffer.from(payload, "utf8"), pubKey, signatureBytes);
19447
19587
  } catch (err) {
19448
19588
  return { ok: false, reason: "bad-signature", detail: err.message };
19449
19589
  }
@@ -19457,11 +19597,11 @@ function isWellFormedEnvelope(x) {
19457
19597
  }
19458
19598
  function readForkAuthorityState(forkPath) {
19459
19599
  const p35 = resolveInForkAuthorityPath(forkPath);
19460
- if (!fs26.existsSync(p35)) {
19600
+ if (!fs27.existsSync(p35)) {
19461
19601
  return { state: "none", version: 1, updatedAt: (/* @__PURE__ */ new Date(0)).toISOString() };
19462
19602
  }
19463
19603
  try {
19464
- const parsed = JSON.parse(fs26.readFileSync(p35, "utf8"));
19604
+ const parsed = JSON.parse(fs27.readFileSync(p35, "utf8"));
19465
19605
  if (!parsed || parsed.version !== 1) {
19466
19606
  return { state: "none", version: 1, updatedAt: (/* @__PURE__ */ new Date(0)).toISOString() };
19467
19607
  }
@@ -19472,8 +19612,8 @@ function readForkAuthorityState(forkPath) {
19472
19612
  }
19473
19613
  function writeForkAuthorityState(forkPath, state) {
19474
19614
  const p35 = resolveInForkAuthorityPath(forkPath);
19475
- fs26.mkdirSync(path33.dirname(p35), { recursive: true });
19476
- fs26.writeFileSync(p35, JSON.stringify(state, null, 2) + "\n", "utf8");
19615
+ fs27.mkdirSync(path34.dirname(p35), { recursive: true });
19616
+ fs27.writeFileSync(p35, JSON.stringify(state, null, 2) + "\n", "utf8");
19477
19617
  }
19478
19618
  function attachAuthorityEnvelope(forkPath, envelope, options = {}) {
19479
19619
  const verification = verifyAuthorityEnvelope(envelope, options);
@@ -20090,6 +20230,7 @@ async function runRegisterFlow() {
20090
20230
  label: labelInput.trim() || void 0
20091
20231
  });
20092
20232
  spinner13.stop(pc29.green("Fork registered."));
20233
+ track("fork_registered", { kit_id: reg.kitId });
20093
20234
  p18.note(
20094
20235
  [
20095
20236
  `Fork ID: ${pc29.cyan(reg.forkId)}`,
@@ -20136,6 +20277,7 @@ async function runStatusFlow() {
20136
20277
  try {
20137
20278
  const report = detectKitForkDrift(reg);
20138
20279
  spinner13.stop(pc29.green("Analysis complete."));
20280
+ track("fork_sync_preview_started", { kit_id: reg.kitId, drift_severity: report.overallSeverity });
20139
20281
  printDriftReport(report);
20140
20282
  } catch (err) {
20141
20283
  spinner13.stop(pc29.red("Drift detection failed."));
@@ -20221,6 +20363,13 @@ async function runHealFlow() {
20221
20363
  healSpinner.stop(
20222
20364
  job.status === "completed" ? pc29.green(isDryRun ? "Dry run complete." : "Heal complete.") : pc29.red("Heal encountered errors.")
20223
20365
  );
20366
+ if (job.status === "completed" && !isDryRun) {
20367
+ track("fork_sync_heal_applied", {
20368
+ kit_id: reg.kitId,
20369
+ action_count: plan.actions.length,
20370
+ applied_count: job.healResult?.appliedCount ?? 0
20371
+ });
20372
+ }
20224
20373
  if (job.healResult) {
20225
20374
  const r = job.healResult;
20226
20375
  console.log("");
@@ -20767,7 +20916,7 @@ function registerAuthoritySubcommands(parentCmd) {
20767
20916
  }
20768
20917
  let raw;
20769
20918
  try {
20770
- raw = fs27.readFileSync(opts.file, "utf8");
20919
+ raw = fs28.readFileSync(opts.file, "utf8");
20771
20920
  } catch (err) {
20772
20921
  console.error(pc29.red(`Cannot read envelope file: ${err.message}`));
20773
20922
  process.exitCode = 1;
@@ -20860,7 +21009,7 @@ function registerAuthoritySubcommands(parentCmd) {
20860
21009
  }
20861
21010
  let pem;
20862
21011
  try {
20863
- pem = fs27.readFileSync(opts.key, "utf8");
21012
+ pem = fs28.readFileSync(opts.key, "utf8");
20864
21013
  } catch (err) {
20865
21014
  console.error(pc29.red(`Cannot read key file: ${err.message}`));
20866
21015
  process.exitCode = 1;
@@ -20944,13 +21093,13 @@ function box(lines) {
20944
21093
  function stripAnsi2(str) {
20945
21094
  return str.replace(/\x1B\[[0-9;]*m/g, "");
20946
21095
  }
20947
- function terminalLink(label, href) {
21096
+ function terminalLink2(label, href) {
20948
21097
  return `\x1B]8;;${href}\x07${label}\x1B]8;;\x07`;
20949
21098
  }
20950
21099
  function folderOpenLabel(folderPath) {
20951
21100
  const href = pathToFileURL2(folderPath).href;
20952
21101
  const label = process.platform === "darwin" ? "Open in Finder" : process.platform === "win32" ? "Open in Explorer" : "Open folder";
20953
- return terminalLink(label, href);
21102
+ return terminalLink2(label, href);
20954
21103
  }
20955
21104
  function renderProgressBar2(progress) {
20956
21105
  if (!process.stdout.isTTY) return;
@@ -21180,6 +21329,8 @@ async function runDownload(kitId, opts) {
21180
21329
  const result = downloadBundledKit(resolvedId, opts.out, {
21181
21330
  onProgress: renderProgressBar2
21182
21331
  });
21332
+ track("kit_download_completed", { kit_id: resolvedId });
21333
+ printActivationNudge("kit_download");
21183
21334
  console.log("");
21184
21335
  console.log(pc30.green(pc30.bold("Kit exported successfully.")));
21185
21336
  console.log("");
@@ -21318,6 +21469,7 @@ Examples:
21318
21469
  const result = downloadBundledKit(resolvedId, opts.out, {
21319
21470
  onProgress: renderProgressBar2
21320
21471
  });
21472
+ track("kit_download_completed", { kit_id: resolvedId });
21321
21473
  console.log("");
21322
21474
  console.log(pc30.bold("Exported folder:"), pc30.cyan(result.folderPath));
21323
21475
  console.log(pc30.bold("Open folder: "), folderOpenLabel(result.folderPath));
@@ -21347,7 +21499,7 @@ Examples:
21347
21499
  $ growthub kit validate ./my-kit
21348
21500
  $ growthub kit validate ~/kits/growthub-open-higgsfield-studio-v1
21349
21501
  `).action((kitPath) => {
21350
- const resolvedPath = path34.resolve(kitPath);
21502
+ const resolvedPath = path35.resolve(kitPath);
21351
21503
  const result = validateKitDirectory(resolvedPath);
21352
21504
  console.log("");
21353
21505
  console.log(pc30.bold("Kit: " + result.kitId) + pc30.dim(" schema v" + result.schemaVersion));
@@ -21392,13 +21544,13 @@ Examples:
21392
21544
  }
21393
21545
 
21394
21546
  // src/commands/template.ts
21395
- import path36 from "node:path";
21547
+ import path37 from "node:path";
21396
21548
  import * as p20 from "@clack/prompts";
21397
21549
  import pc31 from "picocolors";
21398
21550
 
21399
21551
  // src/templates/service.ts
21400
- import fs28 from "node:fs";
21401
- import path35 from "node:path";
21552
+ import fs29 from "node:fs";
21553
+ import path36 from "node:path";
21402
21554
  import { fileURLToPath as fileURLToPath6 } from "node:url";
21403
21555
 
21404
21556
  // src/templates/catalog.ts
@@ -21720,12 +21872,12 @@ var TEMPLATE_CATALOG = [
21720
21872
 
21721
21873
  // src/templates/service.ts
21722
21874
  function resolveSharedTemplatesRoot() {
21723
- const moduleDir = path35.dirname(fileURLToPath6(import.meta.url));
21875
+ const moduleDir = path36.dirname(fileURLToPath6(import.meta.url));
21724
21876
  for (const candidate of [
21725
- path35.resolve(moduleDir, "../../assets/shared-templates"),
21726
- path35.resolve(moduleDir, "../assets/shared-templates")
21877
+ path36.resolve(moduleDir, "../../assets/shared-templates"),
21878
+ path36.resolve(moduleDir, "../assets/shared-templates")
21727
21879
  ]) {
21728
- if (fs28.existsSync(candidate)) return candidate;
21880
+ if (fs29.existsSync(candidate)) return candidate;
21729
21881
  }
21730
21882
  throw new Error("Shared template assets not found at cli/assets/shared-templates/");
21731
21883
  }
@@ -21761,15 +21913,15 @@ function getArtifact(slugOrId) {
21761
21913
  const artifact = resolveSlug(slugOrId);
21762
21914
  if (!artifact) throw new Error(`Unknown template '${slugOrId}'. Run 'growthub template list' to browse.`);
21763
21915
  const root = resolveSharedTemplatesRoot();
21764
- const absolutePath = path35.resolve(root, artifact.path);
21765
- if (!fs28.existsSync(absolutePath)) throw new Error(`Template file missing: ${absolutePath}`);
21766
- return { artifact, content: fs28.readFileSync(absolutePath, "utf8"), absolutePath };
21916
+ const absolutePath = path36.resolve(root, artifact.path);
21917
+ if (!fs29.existsSync(absolutePath)) throw new Error(`Template file missing: ${absolutePath}`);
21918
+ return { artifact, content: fs29.readFileSync(absolutePath, "utf8"), absolutePath };
21767
21919
  }
21768
21920
  function copyArtifact(slugOrId, destDir) {
21769
21921
  const resolved = getArtifact(slugOrId);
21770
- fs28.mkdirSync(destDir, { recursive: true });
21771
- const destPath = path35.resolve(destDir, path35.basename(resolved.absolutePath));
21772
- fs28.copyFileSync(resolved.absolutePath, destPath);
21922
+ fs29.mkdirSync(destDir, { recursive: true });
21923
+ const destPath = path36.resolve(destDir, path36.basename(resolved.absolutePath));
21924
+ fs29.copyFileSync(resolved.absolutePath, destPath);
21773
21925
  return destPath;
21774
21926
  }
21775
21927
  var GROUP_ORDER = ["ad-formats", "scene-modules/hooks", "scene-modules/body", "scene-modules/cta", "marketing-frameworks"];
@@ -22011,7 +22163,7 @@ async function runTemplatePicker(opts) {
22011
22163
  p20.cancel("Cancelled.");
22012
22164
  process.exit(0);
22013
22165
  }
22014
- const destDir = path36.resolve(destInput.replace(/^~/, process.env["HOME"] ?? ""));
22166
+ const destDir = path37.resolve(destInput.replace(/^~/, process.env["HOME"] ?? ""));
22015
22167
  const destPath = copyArtifact(selected.id, destDir);
22016
22168
  p20.outro(pc31.green("Copied \u2192 ") + destPath);
22017
22169
  return "done";
@@ -22085,7 +22237,7 @@ Any agent or kit resolves them by slug.
22085
22237
  return;
22086
22238
  }
22087
22239
  if (opts.out) {
22088
- const destDir = path36.resolve(opts.out.replace(/^~/, process.env["HOME"] ?? ""));
22240
+ const destDir = path37.resolve(opts.out.replace(/^~/, process.env["HOME"] ?? ""));
22089
22241
  try {
22090
22242
  const dest = copyArtifact(artifact.id, destDir);
22091
22243
  console.log(pc31.green("Copied \u2192 ") + dest);
@@ -23169,8 +23321,8 @@ Examples:
23169
23321
  // src/commands/pipeline.ts
23170
23322
  init_session_store();
23171
23323
  init_hosted_client();
23172
- import fs32 from "node:fs";
23173
- import path40 from "node:path";
23324
+ import fs33 from "node:fs";
23325
+ import path41 from "node:path";
23174
23326
  import * as p22 from "@clack/prompts";
23175
23327
  import pc34 from "picocolors";
23176
23328
 
@@ -23680,40 +23832,40 @@ function renderPreSaveReview(input) {
23680
23832
 
23681
23833
  // src/runtime/artifact-contracts/index.ts
23682
23834
  init_home();
23683
- import fs29 from "node:fs";
23684
- import path37 from "node:path";
23835
+ import fs30 from "node:fs";
23836
+ import path38 from "node:path";
23685
23837
  import { randomBytes as randomBytes7 } from "node:crypto";
23686
23838
  function generateArtifactId() {
23687
23839
  return `art_${randomBytes7(8).toString("hex")}`;
23688
23840
  }
23689
23841
  function resolveArtifactsDir() {
23690
- return path37.resolve(resolvePaperclipHomeDir(), "artifacts");
23842
+ return path38.resolve(resolvePaperclipHomeDir(), "artifacts");
23691
23843
  }
23692
23844
  function resolveArtifactManifestPath(artifactId) {
23693
- return path37.resolve(resolveArtifactsDir(), `${artifactId}.json`);
23845
+ return path38.resolve(resolveArtifactsDir(), `${artifactId}.json`);
23694
23846
  }
23695
23847
  function readLocalManifest(artifactId) {
23696
23848
  const filePath = resolveArtifactManifestPath(artifactId);
23697
- if (!fs29.existsSync(filePath)) return null;
23849
+ if (!fs30.existsSync(filePath)) return null;
23698
23850
  try {
23699
- return JSON.parse(fs29.readFileSync(filePath, "utf-8"));
23851
+ return JSON.parse(fs30.readFileSync(filePath, "utf-8"));
23700
23852
  } catch {
23701
23853
  return null;
23702
23854
  }
23703
23855
  }
23704
23856
  function writeLocalManifest(manifest) {
23705
23857
  const dir = resolveArtifactsDir();
23706
- fs29.mkdirSync(dir, { recursive: true });
23858
+ fs30.mkdirSync(dir, { recursive: true });
23707
23859
  const filePath = resolveArtifactManifestPath(manifest.id);
23708
- fs29.writeFileSync(filePath, `${JSON.stringify(manifest, null, 2)}
23860
+ fs30.writeFileSync(filePath, `${JSON.stringify(manifest, null, 2)}
23709
23861
  `, { mode: 384 });
23710
23862
  }
23711
23863
  function listLocalManifests() {
23712
23864
  const dir = resolveArtifactsDir();
23713
- if (!fs29.existsSync(dir)) return [];
23714
- return fs29.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => {
23865
+ if (!fs30.existsSync(dir)) return [];
23866
+ return fs30.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => {
23715
23867
  try {
23716
- const content = fs29.readFileSync(path37.resolve(dir, entry.name), "utf-8");
23868
+ const content = fs30.readFileSync(path38.resolve(dir, entry.name), "utf-8");
23717
23869
  return JSON.parse(content);
23718
23870
  } catch {
23719
23871
  return null;
@@ -23791,8 +23943,8 @@ function createArtifactStore() {
23791
23943
 
23792
23944
  // src/runtime/native-intelligence/index.ts
23793
23945
  init_home();
23794
- import fs31 from "node:fs";
23795
- import path39 from "node:path";
23946
+ import fs32 from "node:fs";
23947
+ import path40 from "node:path";
23796
23948
 
23797
23949
  // src/runtime/native-intelligence/contract.ts
23798
23950
  var DEFAULT_INTELLIGENCE_CONFIG = {
@@ -25063,8 +25215,8 @@ function parseJsonSafe4(text69) {
25063
25215
  }
25064
25216
 
25065
25217
  // src/runtime/native-intelligence/marketing-context-builder.ts
25066
- import fs30 from "node:fs";
25067
- import path38 from "node:path";
25218
+ import fs31 from "node:fs";
25219
+ import path39 from "node:path";
25068
25220
  var CONTEXT_BUILDER_SYSTEM_PROMPT = `You are a marketing strategist drafting a product-marketing-context document.
25069
25221
 
25070
25222
  You receive project artifacts (README content, package.json metadata, any landing page content) and produce a structured product-marketing-context.md with 12 sections.
@@ -25083,17 +25235,17 @@ var MAX_ARTIFACT_LENGTH = 8e3;
25083
25235
  function scanProjectArtifacts(projectDir, existingContext) {
25084
25236
  const artifacts = { otherFiles: [] };
25085
25237
  for (const name of ["README.md", "readme.md", "Readme.md", "README"]) {
25086
- const readmePath = path38.join(projectDir, name);
25087
- if (fs30.existsSync(readmePath)) {
25088
- const content = fs30.readFileSync(readmePath, "utf-8");
25238
+ const readmePath = path39.join(projectDir, name);
25239
+ if (fs31.existsSync(readmePath)) {
25240
+ const content = fs31.readFileSync(readmePath, "utf-8");
25089
25241
  artifacts.readme = content.slice(0, MAX_ARTIFACT_LENGTH);
25090
25242
  break;
25091
25243
  }
25092
25244
  }
25093
- const pkgPath = path38.join(projectDir, "package.json");
25094
- if (fs30.existsSync(pkgPath)) {
25245
+ const pkgPath = path39.join(projectDir, "package.json");
25246
+ if (fs31.existsSync(pkgPath)) {
25095
25247
  try {
25096
- artifacts.packageJson = JSON.parse(fs30.readFileSync(pkgPath, "utf-8"));
25248
+ artifacts.packageJson = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
25097
25249
  } catch {
25098
25250
  }
25099
25251
  }
@@ -25105,15 +25257,15 @@ function scanProjectArtifacts(projectDir, existingContext) {
25105
25257
  ".claude/product-marketing-context.md",
25106
25258
  "brands/_template/product-marketing-context.md"
25107
25259
  ]) {
25108
- const ctxPath = path38.join(projectDir, candidate);
25109
- if (fs30.existsSync(ctxPath)) {
25110
- artifacts.existingContext = fs30.readFileSync(ctxPath, "utf-8");
25260
+ const ctxPath = path39.join(projectDir, candidate);
25261
+ if (fs31.existsSync(ctxPath)) {
25262
+ artifacts.existingContext = fs31.readFileSync(ctxPath, "utf-8");
25111
25263
  break;
25112
25264
  }
25113
25265
  }
25114
25266
  }
25115
25267
  for (const name of ["CONTRIBUTING.md", "AGENTS.md", "landing-page.md", "about.md"]) {
25116
- if (fs30.existsSync(path38.join(projectDir, name))) {
25268
+ if (fs31.existsSync(path39.join(projectDir, name))) {
25117
25269
  artifacts.otherFiles.push(name);
25118
25270
  }
25119
25271
  }
@@ -25354,15 +25506,15 @@ function cleanMarkdownResponse(text69) {
25354
25506
 
25355
25507
  // src/runtime/native-intelligence/index.ts
25356
25508
  function resolveConfigPath2() {
25357
- return path39.resolve(resolvePaperclipHomeDir(), "native-intelligence", "config.json");
25509
+ return path40.resolve(resolvePaperclipHomeDir(), "native-intelligence", "config.json");
25358
25510
  }
25359
25511
  function readIntelligenceConfig() {
25360
25512
  const configPath = resolveConfigPath2();
25361
- if (!fs31.existsSync(configPath)) {
25513
+ if (!fs32.existsSync(configPath)) {
25362
25514
  return { ...DEFAULT_INTELLIGENCE_CONFIG };
25363
25515
  }
25364
25516
  try {
25365
- const raw = JSON.parse(fs31.readFileSync(configPath, "utf-8"));
25517
+ const raw = JSON.parse(fs32.readFileSync(configPath, "utf-8"));
25366
25518
  return {
25367
25519
  modelId: validateModelId(raw.modelId),
25368
25520
  backendType: raw.backendType === "hosted" ? "hosted" : "local",
@@ -25379,8 +25531,8 @@ function readIntelligenceConfig() {
25379
25531
  }
25380
25532
  function writeIntelligenceConfig(config) {
25381
25533
  const configPath = resolveConfigPath2();
25382
- fs31.mkdirSync(path39.dirname(configPath), { recursive: true });
25383
- fs31.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
25534
+ fs32.mkdirSync(path40.dirname(configPath), { recursive: true });
25535
+ fs32.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
25384
25536
  `, "utf-8");
25385
25537
  }
25386
25538
  function validateModelId(id) {
@@ -25736,9 +25888,9 @@ async function runPipelineAssembler(opts) {
25736
25888
  }
25737
25889
  }
25738
25890
  function loadPipelineFromFileOrJson(input) {
25739
- const resolvedPath = path40.resolve(input);
25740
- if (fs32.existsSync(resolvedPath)) {
25741
- const content = fs32.readFileSync(resolvedPath, "utf-8");
25891
+ const resolvedPath = path41.resolve(input);
25892
+ if (fs33.existsSync(resolvedPath)) {
25893
+ const content = fs33.readFileSync(resolvedPath, "utf-8");
25742
25894
  return deserializePipeline(JSON.parse(content));
25743
25895
  }
25744
25896
  try {
@@ -26283,8 +26435,8 @@ Examples:
26283
26435
  }
26284
26436
 
26285
26437
  // src/commands/workflow.ts
26286
- import fs34 from "node:fs";
26287
- import path42 from "node:path";
26438
+ import fs35 from "node:fs";
26439
+ import path43 from "node:path";
26288
26440
  import * as p23 from "@clack/prompts";
26289
26441
  import pc37 from "picocolors";
26290
26442
  init_session_store();
@@ -26292,15 +26444,15 @@ init_hosted_client();
26292
26444
 
26293
26445
  // src/runtime/workflow-hygiene/labels.ts
26294
26446
  init_home();
26295
- import fs33 from "node:fs";
26296
- import path41 from "node:path";
26447
+ import fs34 from "node:fs";
26448
+ import path42 from "node:path";
26297
26449
  function resolveStorePath() {
26298
- return path41.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "labels.json");
26450
+ return path42.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "labels.json");
26299
26451
  }
26300
26452
  function readStoreFile(filePath) {
26301
- if (!fs33.existsSync(filePath)) return { records: [] };
26453
+ if (!fs34.existsSync(filePath)) return { records: [] };
26302
26454
  try {
26303
- const raw = JSON.parse(fs33.readFileSync(filePath, "utf-8"));
26455
+ const raw = JSON.parse(fs34.readFileSync(filePath, "utf-8"));
26304
26456
  if (!Array.isArray(raw.records)) return { records: [] };
26305
26457
  return raw;
26306
26458
  } catch {
@@ -26308,8 +26460,8 @@ function readStoreFile(filePath) {
26308
26460
  }
26309
26461
  }
26310
26462
  function writeStoreFile(filePath, data) {
26311
- fs33.mkdirSync(path41.dirname(filePath), { recursive: true });
26312
- fs33.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}
26463
+ fs34.mkdirSync(path42.dirname(filePath), { recursive: true });
26464
+ fs34.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}
26313
26465
  `, "utf-8");
26314
26466
  }
26315
26467
  function inferDefaultLabel(name, createdAt, versionCount) {
@@ -26410,16 +26562,16 @@ function box5(lines) {
26410
26562
  return [top, ...body, bottom].join("\n");
26411
26563
  }
26412
26564
  function resolveSavedWorkflowsDir() {
26413
- return path42.resolve(resolvePaperclipHomeDir(), "workflows");
26565
+ return path43.resolve(resolvePaperclipHomeDir(), "workflows");
26414
26566
  }
26415
26567
  function resolveDeletedWorkflowIdsPath() {
26416
- return path42.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "deleted-workflows.json");
26568
+ return path43.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "deleted-workflows.json");
26417
26569
  }
26418
26570
  function readDeletedWorkflowIds() {
26419
26571
  const filePath = resolveDeletedWorkflowIdsPath();
26420
- if (!fs34.existsSync(filePath)) return /* @__PURE__ */ new Set();
26572
+ if (!fs35.existsSync(filePath)) return /* @__PURE__ */ new Set();
26421
26573
  try {
26422
- const raw = JSON.parse(fs34.readFileSync(filePath, "utf-8"));
26574
+ const raw = JSON.parse(fs35.readFileSync(filePath, "utf-8"));
26423
26575
  if (!Array.isArray(raw?.workflowIds)) return /* @__PURE__ */ new Set();
26424
26576
  return new Set(raw.workflowIds.filter((value) => typeof value === "string"));
26425
26577
  } catch {
@@ -26428,8 +26580,8 @@ function readDeletedWorkflowIds() {
26428
26580
  }
26429
26581
  function writeDeletedWorkflowIds(ids) {
26430
26582
  const filePath = resolveDeletedWorkflowIdsPath();
26431
- fs34.mkdirSync(path42.dirname(filePath), { recursive: true });
26432
- fs34.writeFileSync(filePath, `${JSON.stringify({ workflowIds: [...ids] }, null, 2)}
26583
+ fs35.mkdirSync(path43.dirname(filePath), { recursive: true });
26584
+ fs35.writeFileSync(filePath, `${JSON.stringify({ workflowIds: [...ids] }, null, 2)}
26433
26585
  `, "utf-8");
26434
26586
  }
26435
26587
  function markWorkflowDeletedLocally(workflowId) {
@@ -26455,10 +26607,10 @@ function filterLocallyDeletedWorkflows(entries) {
26455
26607
  }
26456
26608
  function listLocalSavedWorkflows() {
26457
26609
  const dir = resolveSavedWorkflowsDir();
26458
- if (!fs34.existsSync(dir)) return [];
26459
- const entries = fs34.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
26610
+ if (!fs35.existsSync(dir)) return [];
26611
+ const entries = fs35.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
26460
26612
  try {
26461
- const raw = JSON.parse(fs34.readFileSync(path42.resolve(dir, e.name), "utf-8"));
26613
+ const raw = JSON.parse(fs35.readFileSync(path43.resolve(dir, e.name), "utf-8"));
26462
26614
  const pipeline = raw.pipeline ?? raw;
26463
26615
  return {
26464
26616
  filename: e.name,
@@ -26519,11 +26671,11 @@ async function archiveSavedWorkflow(entry) {
26519
26671
  throw new Error("Local workflow entry is missing filename.");
26520
26672
  }
26521
26673
  const dir = resolveSavedWorkflowsDir();
26522
- const archiveDir = path42.resolve(dir, "archived");
26523
- fs34.mkdirSync(archiveDir, { recursive: true });
26524
- fs34.renameSync(
26525
- path42.resolve(dir, entry.filename),
26526
- path42.resolve(archiveDir, entry.filename)
26674
+ const archiveDir = path43.resolve(dir, "archived");
26675
+ fs35.mkdirSync(archiveDir, { recursive: true });
26676
+ fs35.renameSync(
26677
+ path43.resolve(dir, entry.filename),
26678
+ path43.resolve(archiveDir, entry.filename)
26527
26679
  );
26528
26680
  }
26529
26681
  async function deleteSavedWorkflow(entry) {
@@ -26547,7 +26699,7 @@ async function deleteSavedWorkflow(entry) {
26547
26699
  if (!entry.filename) {
26548
26700
  throw new Error("Local workflow entry is missing filename.");
26549
26701
  }
26550
- fs34.rmSync(path42.resolve(resolveSavedWorkflowsDir(), entry.filename), { force: true });
26702
+ fs35.rmSync(path43.resolve(resolveSavedWorkflowsDir(), entry.filename), { force: true });
26551
26703
  markWorkflowDeletedLocally(entry.workflowId);
26552
26704
  }
26553
26705
  async function loadSavedWorkflowDetail(entry) {
@@ -26566,7 +26718,7 @@ async function loadSavedWorkflowDetail(entry) {
26566
26718
  };
26567
26719
  }
26568
26720
  const dir = resolveSavedWorkflowsDir();
26569
- const content = fs34.readFileSync(path42.resolve(dir, entry.filename), "utf-8");
26721
+ const content = fs35.readFileSync(path43.resolve(dir, entry.filename), "utf-8");
26570
26722
  const raw = JSON.parse(content);
26571
26723
  return {
26572
26724
  pipeline: raw.pipeline ?? raw,
@@ -27550,36 +27702,36 @@ import pc38 from "picocolors";
27550
27702
 
27551
27703
  // src/runtime/agent-harness/auth-store.ts
27552
27704
  init_home();
27553
- import fs35 from "node:fs";
27554
- import path43 from "node:path";
27705
+ import fs36 from "node:fs";
27706
+ import path44 from "node:path";
27555
27707
  function resolveHarnessAuthDir() {
27556
- return path43.resolve(resolvePaperclipHomeDir(), "harness-auth");
27708
+ return path44.resolve(resolvePaperclipHomeDir(), "harness-auth");
27557
27709
  }
27558
27710
  function resolveHarnessAuthFile(harnessId) {
27559
- return path43.resolve(resolveHarnessAuthDir(), `${harnessId}.json`);
27711
+ return path44.resolve(resolveHarnessAuthDir(), `${harnessId}.json`);
27560
27712
  }
27561
27713
  function normalizeSecret(value) {
27562
27714
  const trimmed = value?.trim();
27563
27715
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
27564
27716
  }
27565
27717
  function ensureSecureDir(dirPath) {
27566
- fs35.mkdirSync(dirPath, { recursive: true });
27718
+ fs36.mkdirSync(dirPath, { recursive: true });
27567
27719
  try {
27568
- fs35.chmodSync(dirPath, 448);
27720
+ fs36.chmodSync(dirPath, 448);
27569
27721
  } catch {
27570
27722
  }
27571
27723
  }
27572
27724
  function ensureSecureFile(filePath) {
27573
27725
  try {
27574
- fs35.chmodSync(filePath, 384);
27726
+ fs36.chmodSync(filePath, 384);
27575
27727
  } catch {
27576
27728
  }
27577
27729
  }
27578
27730
  function readHarnessCredentials(harnessId) {
27579
27731
  const filePath = resolveHarnessAuthFile(harnessId);
27580
- if (!fs35.existsSync(filePath)) return {};
27732
+ if (!fs36.existsSync(filePath)) return {};
27581
27733
  try {
27582
- const parsed = JSON.parse(fs35.readFileSync(filePath, "utf-8"));
27734
+ const parsed = JSON.parse(fs36.readFileSync(filePath, "utf-8"));
27583
27735
  const creds = {};
27584
27736
  for (const [key, value] of Object.entries(parsed)) {
27585
27737
  if (typeof value === "string" && value.trim().length > 0) {
@@ -27606,7 +27758,7 @@ function setHarnessCredential(harnessId, key, value) {
27606
27758
  const dirPath = resolveHarnessAuthDir();
27607
27759
  ensureSecureDir(dirPath);
27608
27760
  const filePath = resolveHarnessAuthFile(harnessId);
27609
- fs35.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
27761
+ fs36.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
27610
27762
  `, "utf-8");
27611
27763
  ensureSecureFile(filePath);
27612
27764
  }
@@ -27623,7 +27775,7 @@ function setHarnessCredentials(harnessId, updates) {
27623
27775
  const dirPath = resolveHarnessAuthDir();
27624
27776
  ensureSecureDir(dirPath);
27625
27777
  const filePath = resolveHarnessAuthFile(harnessId);
27626
- fs35.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
27778
+ fs36.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
27627
27779
  `, "utf-8");
27628
27780
  ensureSecureFile(filePath);
27629
27781
  }
@@ -27635,8 +27787,8 @@ function maskSecret(value) {
27635
27787
 
27636
27788
  // src/runtime/open-agents/index.ts
27637
27789
  init_home();
27638
- import fs36 from "node:fs";
27639
- import path44 from "node:path";
27790
+ import fs37 from "node:fs";
27791
+ import path45 from "node:path";
27640
27792
 
27641
27793
  // src/runtime/open-agents/contract.ts
27642
27794
  var DEFAULT_OPEN_AGENTS_CONFIG = {
@@ -27823,18 +27975,18 @@ var OpenAgentsBackendError = class extends Error {
27823
27975
 
27824
27976
  // src/runtime/open-agents/index.ts
27825
27977
  function resolveConfigPath3() {
27826
- return path44.resolve(resolvePaperclipHomeDir(), "open-agents", "config.json");
27978
+ return path45.resolve(resolvePaperclipHomeDir(), "open-agents", "config.json");
27827
27979
  }
27828
27980
  function readOpenAgentsConfig() {
27829
27981
  const configPath = resolveConfigPath3();
27830
- if (!fs36.existsSync(configPath)) {
27982
+ if (!fs37.existsSync(configPath)) {
27831
27983
  return {
27832
27984
  ...DEFAULT_OPEN_AGENTS_CONFIG,
27833
27985
  apiKey: getHarnessCredential("open-agents", "apiKey")
27834
27986
  };
27835
27987
  }
27836
27988
  try {
27837
- const raw = JSON.parse(fs36.readFileSync(configPath, "utf-8"));
27989
+ const raw = JSON.parse(fs37.readFileSync(configPath, "utf-8"));
27838
27990
  const storedApiKey = getHarnessCredential("open-agents", "apiKey");
27839
27991
  return {
27840
27992
  backendType: validateBackendType(raw.backendType),
@@ -27855,13 +28007,13 @@ function readOpenAgentsConfig() {
27855
28007
  }
27856
28008
  function writeOpenAgentsConfig(config) {
27857
28009
  const configPath = resolveConfigPath3();
27858
- fs36.mkdirSync(path44.dirname(configPath), { recursive: true });
28010
+ fs37.mkdirSync(path45.dirname(configPath), { recursive: true });
27859
28011
  const persisted = {
27860
28012
  ...config,
27861
28013
  authMode: validateAuthMode(config.authMode),
27862
28014
  apiKey: void 0
27863
28015
  };
27864
- fs36.writeFileSync(configPath, `${JSON.stringify(persisted, null, 2)}
28016
+ fs37.writeFileSync(configPath, `${JSON.stringify(persisted, null, 2)}
27865
28017
  `, "utf-8");
27866
28018
  setHarnessCredential("open-agents", "apiKey", config.apiKey);
27867
28019
  }
@@ -28422,8 +28574,8 @@ import pc39 from "picocolors";
28422
28574
 
28423
28575
  // src/runtime/qwen-code/index.ts
28424
28576
  init_home();
28425
- import fs37 from "node:fs";
28426
- import path45 from "node:path";
28577
+ import fs38 from "node:fs";
28578
+ import path46 from "node:path";
28427
28579
 
28428
28580
  // src/runtime/qwen-code/contract.ts
28429
28581
  var QWEN_CODE_APPROVAL_MODES = [
@@ -28641,19 +28793,19 @@ function buildSetupGuidance(env) {
28641
28793
 
28642
28794
  // src/runtime/qwen-code/index.ts
28643
28795
  function resolveConfigPath4() {
28644
- return path45.resolve(resolvePaperclipHomeDir(), "qwen-code", "config.json");
28796
+ return path46.resolve(resolvePaperclipHomeDir(), "qwen-code", "config.json");
28645
28797
  }
28646
28798
  function readQwenCodeConfig() {
28647
28799
  const configPath = resolveConfigPath4();
28648
28800
  const storedCredentials = readHarnessCredentials("qwen-code");
28649
- if (!fs37.existsSync(configPath)) {
28801
+ if (!fs38.existsSync(configPath)) {
28650
28802
  return {
28651
28803
  ...DEFAULT_QWEN_CODE_CONFIG,
28652
28804
  env: mergeHarnessEnv(DEFAULT_QWEN_CODE_CONFIG.env, storedCredentials)
28653
28805
  };
28654
28806
  }
28655
28807
  try {
28656
- const raw = JSON.parse(fs37.readFileSync(configPath, "utf-8"));
28808
+ const raw = JSON.parse(fs38.readFileSync(configPath, "utf-8"));
28657
28809
  return {
28658
28810
  binaryPath: typeof raw.binaryPath === "string" ? raw.binaryPath : DEFAULT_QWEN_CODE_CONFIG.binaryPath,
28659
28811
  defaultModel: typeof raw.defaultModel === "string" ? raw.defaultModel : DEFAULT_QWEN_CODE_CONFIG.defaultModel,
@@ -28675,7 +28827,7 @@ function readQwenCodeConfig() {
28675
28827
  }
28676
28828
  function writeQwenCodeConfig(config) {
28677
28829
  const configPath = resolveConfigPath4();
28678
- fs37.mkdirSync(path45.dirname(configPath), { recursive: true });
28830
+ fs38.mkdirSync(path46.dirname(configPath), { recursive: true });
28679
28831
  const rawEnv = typeof config.env === "object" && config.env !== null ? config.env : {};
28680
28832
  const credentialUpdates = {};
28681
28833
  const publicEnv = {};
@@ -28687,7 +28839,7 @@ function writeQwenCodeConfig(config) {
28687
28839
  publicEnv[key] = value;
28688
28840
  }
28689
28841
  setHarnessCredentials("qwen-code", credentialUpdates);
28690
- fs37.writeFileSync(
28842
+ fs38.writeFileSync(
28691
28843
  configPath,
28692
28844
  `${JSON.stringify({ ...config, env: publicEnv }, null, 2)}
28693
28845
  `,
@@ -28937,32 +29089,32 @@ import pc41 from "picocolors";
28937
29089
 
28938
29090
  // src/runtime/t3code/index.ts
28939
29091
  init_home();
28940
- import fs39 from "node:fs";
28941
- import path47 from "node:path";
29092
+ import fs40 from "node:fs";
29093
+ import path48 from "node:path";
28942
29094
 
28943
29095
  // src/runtime/agent-harness/harness-profile.ts
28944
29096
  init_home();
28945
- import fs38 from "node:fs";
28946
- import path46 from "node:path";
29097
+ import fs39 from "node:fs";
29098
+ import path47 from "node:path";
28947
29099
  import * as p26 from "@clack/prompts";
28948
29100
  import pc40 from "picocolors";
28949
29101
  function resolveProfileDir(harnessId) {
28950
- return path46.resolve(resolvePaperclipHomeDir(), harnessId);
29102
+ return path47.resolve(resolvePaperclipHomeDir(), harnessId);
28951
29103
  }
28952
29104
  function resolveProfilePath(harnessId) {
28953
- return path46.resolve(resolveProfileDir(harnessId), "growthub-profile.json");
29105
+ return path47.resolve(resolveProfileDir(harnessId), "growthub-profile.json");
28954
29106
  }
28955
29107
  function ensureSecureFile2(filePath) {
28956
29108
  try {
28957
- fs38.chmodSync(filePath, 384);
29109
+ fs39.chmodSync(filePath, 384);
28958
29110
  } catch {
28959
29111
  }
28960
29112
  }
28961
29113
  function readHarnessProfile(harnessId) {
28962
29114
  const filePath = resolveProfilePath(harnessId);
28963
- if (!fs38.existsSync(filePath)) return null;
29115
+ if (!fs39.existsSync(filePath)) return null;
28964
29116
  try {
28965
- const raw = JSON.parse(fs38.readFileSync(filePath, "utf-8"));
29117
+ const raw = JSON.parse(fs39.readFileSync(filePath, "utf-8"));
28966
29118
  if (typeof raw.workspaceId !== "string" || typeof raw.machineLabel !== "string") return null;
28967
29119
  return {
28968
29120
  profileVersion: 1,
@@ -28980,14 +29132,14 @@ function readHarnessProfile(harnessId) {
28980
29132
  function writeHarnessProfile(harnessId, profile) {
28981
29133
  const dirPath = resolveProfileDir(harnessId);
28982
29134
  const filePath = resolveProfilePath(harnessId);
28983
- fs38.mkdirSync(dirPath, { recursive: true });
28984
- fs38.writeFileSync(filePath, `${JSON.stringify(profile, null, 2)}
29135
+ fs39.mkdirSync(dirPath, { recursive: true });
29136
+ fs39.writeFileSync(filePath, `${JSON.stringify(profile, null, 2)}
28985
29137
  `, "utf-8");
28986
29138
  ensureSecureFile2(filePath);
28987
29139
  }
28988
29140
  function clearHarnessProfile(harnessId) {
28989
29141
  const filePath = resolveProfilePath(harnessId);
28990
- if (fs38.existsSync(filePath)) fs38.rmSync(filePath);
29142
+ if (fs39.existsSync(filePath)) fs39.rmSync(filePath);
28991
29143
  }
28992
29144
  function buildProfileStatusLines(harnessId, harnessLabel, profile) {
28993
29145
  if (!profile) {
@@ -29268,19 +29420,19 @@ function writeT3GrowthubProfile(profile) {
29268
29420
  writeHarnessProfile(T3_HARNESS_ID, profile);
29269
29421
  }
29270
29422
  function resolveConfigPath5() {
29271
- return path47.resolve(resolvePaperclipHomeDir(), "t3code", "config.json");
29423
+ return path48.resolve(resolvePaperclipHomeDir(), "t3code", "config.json");
29272
29424
  }
29273
29425
  function readT3CodeConfig() {
29274
29426
  const configPath = resolveConfigPath5();
29275
29427
  const storedCredentials = readHarnessCredentials(T3_HARNESS_ID);
29276
- if (!fs39.existsSync(configPath)) {
29428
+ if (!fs40.existsSync(configPath)) {
29277
29429
  return {
29278
29430
  ...DEFAULT_T3_CODE_CONFIG,
29279
29431
  env: mergeHarnessEnv2(DEFAULT_T3_CODE_CONFIG.env, storedCredentials)
29280
29432
  };
29281
29433
  }
29282
29434
  try {
29283
- const raw = JSON.parse(fs39.readFileSync(configPath, "utf-8"));
29435
+ const raw = JSON.parse(fs40.readFileSync(configPath, "utf-8"));
29284
29436
  const profile = readHarnessProfile(T3_HARNESS_ID);
29285
29437
  const resolvedBinaryPath = profile?.forkBinaryPath ?? (typeof raw.binaryPath === "string" ? raw.binaryPath : DEFAULT_T3_CODE_CONFIG.binaryPath);
29286
29438
  return {
@@ -29303,7 +29455,7 @@ function readT3CodeConfig() {
29303
29455
  }
29304
29456
  function writeT3CodeConfig(config) {
29305
29457
  const configPath = resolveConfigPath5();
29306
- fs39.mkdirSync(path47.dirname(configPath), { recursive: true });
29458
+ fs40.mkdirSync(path48.dirname(configPath), { recursive: true });
29307
29459
  const rawEnv = typeof config.env === "object" && config.env !== null ? config.env : {};
29308
29460
  const credentialUpdates = {};
29309
29461
  const publicEnv = {};
@@ -29315,7 +29467,7 @@ function writeT3CodeConfig(config) {
29315
29467
  }
29316
29468
  }
29317
29469
  setHarnessCredentials(T3_HARNESS_ID, credentialUpdates);
29318
- fs39.writeFileSync(
29470
+ fs40.writeFileSync(
29319
29471
  configPath,
29320
29472
  `${JSON.stringify({ ...config, env: publicEnv }, null, 2)}
29321
29473
  `,
@@ -29697,8 +29849,8 @@ import pc44 from "picocolors";
29697
29849
 
29698
29850
  // src/status/probes.ts
29699
29851
  import { spawnSync as spawnSync4 } from "node:child_process";
29700
- import fs40 from "node:fs";
29701
- import path48 from "node:path";
29852
+ import fs41 from "node:fs";
29853
+ import path49 from "node:path";
29702
29854
  var GITHUB_API = "https://api.github.com";
29703
29855
  var NPM_REGISTRY = "https://registry.npmjs.org";
29704
29856
  function isoNow() {
@@ -29863,7 +30015,7 @@ async function probeKitForksIndex(_timeoutMs) {
29863
30015
  try {
29864
30016
  const { resolveKitForksIndexPath: resolveKitForksIndexPath2 } = await Promise.resolve().then(() => (init_kit_forks_home(), kit_forks_home_exports));
29865
30017
  const p35 = resolveKitForksIndexPath2();
29866
- if (!fs40.existsSync(p35)) {
30018
+ if (!fs41.existsSync(p35)) {
29867
30019
  return {
29868
30020
  componentId: "kit-forks-index",
29869
30021
  level: "operational",
@@ -29871,7 +30023,7 @@ async function probeKitForksIndex(_timeoutMs) {
29871
30023
  lastCheckedAt: isoNow()
29872
30024
  };
29873
30025
  }
29874
- const parsed = JSON.parse(fs40.readFileSync(p35, "utf8"));
30026
+ const parsed = JSON.parse(fs41.readFileSync(p35, "utf8"));
29875
30027
  const count = Array.isArray(parsed.entries) ? parsed.entries.length : 0;
29876
30028
  return {
29877
30029
  componentId: "kit-forks-index",
@@ -29940,10 +30092,10 @@ async function probeNode(_timeoutMs) {
29940
30092
  };
29941
30093
  }
29942
30094
  async function probeReleaseBundleArtifacts(_timeoutMs) {
29943
- const distPath = path48.resolve(process.cwd(), "cli/dist/index.js");
29944
- const installerPath = path48.resolve(process.cwd(), "packages/create-growthub-local/bin/create-growthub-local.mjs");
29945
- const distOk = fs40.existsSync(distPath);
29946
- const installerOk = fs40.existsSync(installerPath);
30095
+ const distPath = path49.resolve(process.cwd(), "cli/dist/index.js");
30096
+ const installerPath = path49.resolve(process.cwd(), "packages/create-growthub-local/bin/create-growthub-local.mjs");
30097
+ const distOk = fs41.existsSync(distPath);
30098
+ const installerOk = fs41.existsSync(installerPath);
29947
30099
  const ok = distOk && installerOk;
29948
30100
  return {
29949
30101
  componentId: "release-bundle",
@@ -30188,15 +30340,17 @@ function registerStatusCommands(program2) {
30188
30340
  }
30189
30341
 
30190
30342
  // src/commands/starter.ts
30191
- init_init();
30192
- init_table_renderer();
30193
- init_source_import();
30194
30343
  import * as p31 from "@clack/prompts";
30195
30344
  import pc45 from "picocolors";
30196
30345
  import { pathToFileURL as pathToFileURL3 } from "node:url";
30346
+ init_init();
30347
+ init_table_renderer();
30348
+ init_source_import();
30197
30349
  async function runStarterInit(opts) {
30198
30350
  try {
30199
30351
  const result = await initStarterWorkspace(opts);
30352
+ track("workspace_starter_created", { kit_id: result.kitId });
30353
+ printActivationNudge("workspace_created");
30200
30354
  if (opts.json) {
30201
30355
  console.log(JSON.stringify({ status: "ok", ...result }, null, 2));
30202
30356
  return;
@@ -30223,13 +30377,13 @@ Next: ${pc45.dim(`growthub kit fork status ${result.forkId}`)}`
30223
30377
  process.exitCode = 1;
30224
30378
  }
30225
30379
  }
30226
- function terminalLink2(label, href) {
30380
+ function terminalLink3(label, href) {
30227
30381
  return `\x1B]8;;${href}\x07${label}\x1B]8;;\x07`;
30228
30382
  }
30229
30383
  function folderOpenLabel2(folderPath) {
30230
30384
  const href = pathToFileURL3(folderPath).href;
30231
30385
  const label = process.platform === "darwin" ? "Open in Finder" : process.platform === "win32" ? "Open in Explorer" : "Open folder";
30232
- return terminalLink2(label, href);
30386
+ return terminalLink3(label, href);
30233
30387
  }
30234
30388
  function formatSecuritySummary(result) {
30235
30389
  const findings = result.security.findings.length;
@@ -30270,6 +30424,9 @@ async function promptConfirmations(pending, securitySummary) {
30270
30424
  }
30271
30425
  async function runSourceImportCommand(opts) {
30272
30426
  const { input, json } = opts;
30427
+ track(
30428
+ input.source.kind === "github-repo" ? "starter_import_repo_started" : "starter_import_skill_started"
30429
+ );
30273
30430
  try {
30274
30431
  const onProgressFromInput = input.onProgress;
30275
30432
  const onProgress = (step) => {
@@ -30281,6 +30438,7 @@ async function runSourceImportCommand(opts) {
30281
30438
  onProgress
30282
30439
  });
30283
30440
  if (job.status === "awaiting_confirmation") {
30441
+ track("awaiting_confirmation_reached", { source_kind: job.sourceKind });
30284
30442
  if (json) {
30285
30443
  console.log(
30286
30444
  JSON.stringify(
@@ -30317,6 +30475,7 @@ async function runSourceImportCommand(opts) {
30317
30475
  return;
30318
30476
  }
30319
30477
  if (job.status === "failed" || !result) {
30478
+ track("import_failed", { source_kind: job.sourceKind });
30320
30479
  const msg = job.error ?? "Import failed.";
30321
30480
  if (json) {
30322
30481
  console.log(JSON.stringify({ status: "error", error: msg, job: renderJob(job) }, null, 2));
@@ -30344,6 +30503,11 @@ async function runSourceImportCommand(opts) {
30344
30503
  }
30345
30504
  }
30346
30505
  function finalizeSuccess(result, jobId) {
30506
+ track(
30507
+ result.sourceKind === "github-repo" ? "starter_import_repo_completed" : "starter_import_skill_completed",
30508
+ { import_mode: result.importMode }
30509
+ );
30510
+ printActivationNudge("import_completed");
30347
30511
  const sourceLine = result.source.kind === "github-repo" ? `${result.source.repo.owner}/${result.source.repo.repo}` : `${result.source.skillId}@${result.source.version}`;
30348
30512
  p31.outro(
30349
30513
  `Imported ${sourceLine} into ${pc45.cyan(result.forkPath)}
@@ -30490,7 +30654,7 @@ import pc46 from "picocolors";
30490
30654
 
30491
30655
  // src/fleet/summary.ts
30492
30656
  init_fork_registry();
30493
- import fs50 from "node:fs";
30657
+ import fs51 from "node:fs";
30494
30658
  init_fork_policy();
30495
30659
  init_fork_trace();
30496
30660
  function classifyHealth(drift, pendingConfirmationJobs, lastJobStatus) {
@@ -30510,7 +30674,7 @@ var REMOTE_EVENT_TYPES = /* @__PURE__ */ new Set([
30510
30674
  "conflict_encountered"
30511
30675
  ]);
30512
30676
  function buildForkSummary(reg) {
30513
- if (!fs50.existsSync(reg.forkPath)) {
30677
+ if (!fs51.existsSync(reg.forkPath)) {
30514
30678
  return {
30515
30679
  forkId: reg.forkId,
30516
30680
  kitId: reg.kitId,
@@ -30971,8 +31135,8 @@ async function fleetApprovals(opts) {
30971
31135
  p32.log.message(
30972
31136
  ` \xB7 ${pc46.cyan(entry.jobId)} fork=${entry.forkLabel ?? entry.forkId} created=${entry.createdAt.slice(0, 19)}`
30973
31137
  );
30974
- for (const path61 of entry.pendingPaths.slice(0, 6)) {
30975
- p32.log.message(` ${pc46.dim("awaits")} ${path61}`);
31138
+ for (const path62 of entry.pendingPaths.slice(0, 6)) {
31139
+ p32.log.message(` ${pc46.dim("awaits")} ${path62}`);
30976
31140
  }
30977
31141
  if (entry.pendingPaths.length > 6) {
30978
31142
  p32.log.message(` ${pc46.dim(`\u2026 +${entry.pendingPaths.length - 6} more`)}`);
@@ -31058,21 +31222,21 @@ var DEFAULT_MEMORY_PROVIDER_CONFIG = {
31058
31222
 
31059
31223
  // src/runtime/memory/store.ts
31060
31224
  init_home();
31061
- import fs51 from "node:fs";
31062
- import path58 from "node:path";
31225
+ import fs52 from "node:fs";
31226
+ import path59 from "node:path";
31063
31227
  function toProjectSlug(project) {
31064
31228
  return project.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "default";
31065
31229
  }
31066
31230
  function resolveProjectPath(project) {
31067
- return path58.resolve(resolveMemoryProjectsDir(), `${toProjectSlug(project)}.json`);
31231
+ return path59.resolve(resolveMemoryProjectsDir(), `${toProjectSlug(project)}.json`);
31068
31232
  }
31069
31233
  function loadMemoryDatabase(project) {
31070
31234
  const filePath = resolveProjectPath(project);
31071
- if (!fs51.existsSync(filePath)) {
31235
+ if (!fs52.existsSync(filePath)) {
31072
31236
  return { version: 1, project, observations: [], summaries: [], nextObservationId: 1, nextSummaryId: 1 };
31073
31237
  }
31074
31238
  try {
31075
- const raw = JSON.parse(fs51.readFileSync(filePath, "utf-8"));
31239
+ const raw = JSON.parse(fs52.readFileSync(filePath, "utf-8"));
31076
31240
  return {
31077
31241
  version: 1,
31078
31242
  project,
@@ -31087,9 +31251,9 @@ function loadMemoryDatabase(project) {
31087
31251
  }
31088
31252
  function saveMemoryDatabase(db) {
31089
31253
  const dir = resolveMemoryProjectsDir();
31090
- fs51.mkdirSync(dir, { recursive: true });
31254
+ fs52.mkdirSync(dir, { recursive: true });
31091
31255
  const filePath = resolveProjectPath(db.project);
31092
- fs51.writeFileSync(filePath, `${JSON.stringify(db, null, 2)}
31256
+ fs52.writeFileSync(filePath, `${JSON.stringify(db, null, 2)}
31093
31257
  `, "utf-8");
31094
31258
  }
31095
31259
  function addObservation(project, input) {
@@ -31183,8 +31347,8 @@ function incrementRelevanceCount(project, observationId) {
31183
31347
  }
31184
31348
  function listMemoryProjects() {
31185
31349
  const dir = resolveMemoryProjectsDir();
31186
- if (!fs51.existsSync(dir)) return [];
31187
- return fs51.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, "")).sort();
31350
+ if (!fs52.existsSync(dir)) return [];
31351
+ return fs52.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, "")).sort();
31188
31352
  }
31189
31353
  function getMemoryStats(project) {
31190
31354
  const db = loadMemoryDatabase(project);
@@ -31196,15 +31360,15 @@ function getMemoryStats(project) {
31196
31360
  };
31197
31361
  }
31198
31362
  function resolveProviderConfigPath() {
31199
- return path58.resolve(resolveMemoryDir(), "provider-config.json");
31363
+ return path59.resolve(resolveMemoryDir(), "provider-config.json");
31200
31364
  }
31201
31365
  function readProviderConfig() {
31202
31366
  const filePath = resolveProviderConfigPath();
31203
- if (!fs51.existsSync(filePath)) {
31367
+ if (!fs52.existsSync(filePath)) {
31204
31368
  return { ...DEFAULT_MEMORY_PROVIDER_CONFIG };
31205
31369
  }
31206
31370
  try {
31207
- const raw = JSON.parse(fs51.readFileSync(filePath, "utf-8"));
31371
+ const raw = JSON.parse(fs52.readFileSync(filePath, "utf-8"));
31208
31372
  return {
31209
31373
  provider: validateProvider(raw.provider),
31210
31374
  apiKey: typeof raw.apiKey === "string" ? raw.apiKey : void 0,
@@ -31217,9 +31381,9 @@ function readProviderConfig() {
31217
31381
  }
31218
31382
  function writeProviderConfig(config) {
31219
31383
  const dir = resolveMemoryDir();
31220
- fs51.mkdirSync(dir, { recursive: true });
31384
+ fs52.mkdirSync(dir, { recursive: true });
31221
31385
  const filePath = resolveProviderConfigPath();
31222
- fs51.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}
31386
+ fs52.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}
31223
31387
  `, { mode: 384 });
31224
31388
  }
31225
31389
  function validateProvider(value) {
@@ -31598,14 +31762,14 @@ async function syncMemoriesToHosted(project, options) {
31598
31762
  init_llm();
31599
31763
  function resolveCliVersion() {
31600
31764
  try {
31601
- const moduleDir = path60.dirname(fileURLToPath7(import.meta.url));
31765
+ const moduleDir = path61.dirname(fileURLToPath7(import.meta.url));
31602
31766
  const candidates = [
31603
- path60.resolve(moduleDir, "../package.json"),
31604
- path60.resolve(moduleDir, "../../package.json")
31767
+ path61.resolve(moduleDir, "../package.json"),
31768
+ path61.resolve(moduleDir, "../../package.json")
31605
31769
  ];
31606
31770
  for (const candidate of candidates) {
31607
- if (!fs53.existsSync(candidate)) continue;
31608
- const parsed = JSON.parse(fs53.readFileSync(candidate, "utf8"));
31771
+ if (!fs54.existsSync(candidate)) continue;
31772
+ const parsed = JSON.parse(fs54.readFileSync(candidate, "utf8"));
31609
31773
  if (parsed?.name === "@growthub/cli" && typeof parsed.version === "string") return parsed.version;
31610
31774
  }
31611
31775
  } catch {
@@ -31832,7 +31996,7 @@ async function runMarketingContextBuilder(baseUrl, model) {
31832
31996
  });
31833
31997
  if (p34.isCancel(projectDir)) return;
31834
31998
  const dir = String(projectDir).trim() || process.cwd();
31835
- if (!fs53.existsSync(dir)) {
31999
+ if (!fs54.existsSync(dir)) {
31836
32000
  p34.note(`Directory not found: ${dir}`, "Marketing Context Builder");
31837
32001
  return;
31838
32002
  }
@@ -31868,10 +32032,10 @@ async function runMarketingContextBuilder(baseUrl, model) {
31868
32032
  p34.note("Draft was not saved. You can copy it from the output above.", "Marketing Context Builder");
31869
32033
  return;
31870
32034
  }
31871
- const outDir = path60.resolve(dir, ".agents");
31872
- fs53.mkdirSync(outDir, { recursive: true });
31873
- const outPath = path60.resolve(outDir, "product-marketing-context.md");
31874
- fs53.writeFileSync(outPath, result.contextMarkdown, "utf-8");
32035
+ const outDir = path61.resolve(dir, ".agents");
32036
+ fs54.mkdirSync(outDir, { recursive: true });
32037
+ const outPath = path61.resolve(outDir, "product-marketing-context.md");
32038
+ fs54.writeFileSync(outPath, result.contextMarkdown, "utf-8");
31875
32039
  p34.note(`Saved to: ${outPath}
31876
32040
 
31877
32041
  Review the file and replace [NEEDS INPUT] placeholders with real data.`, "Marketing Context Builder");
@@ -32080,39 +32244,39 @@ function captureSessionSummary(project, sessionId, messages) {
32080
32244
  }
32081
32245
  }
32082
32246
  function resolveLocalThreadsDir() {
32083
- return path60.resolve(resolvePaperclipHomeDir(), "native-intelligence", "threads");
32247
+ return path61.resolve(resolvePaperclipHomeDir(), "native-intelligence", "threads");
32084
32248
  }
32085
32249
  function loadOrCreateLocalThread() {
32086
32250
  const dir = resolveLocalThreadsDir();
32087
- fs53.mkdirSync(dir, { recursive: true });
32088
- const activePath = path60.resolve(dir, "active-thread.json");
32089
- if (fs53.existsSync(activePath)) {
32251
+ fs54.mkdirSync(dir, { recursive: true });
32252
+ const activePath = path61.resolve(dir, "active-thread.json");
32253
+ if (fs54.existsSync(activePath)) {
32090
32254
  try {
32091
- const parsed = JSON.parse(fs53.readFileSync(activePath, "utf-8"));
32255
+ const parsed = JSON.parse(fs54.readFileSync(activePath, "utf-8"));
32092
32256
  const id2 = typeof parsed.id === "string" && parsed.id.length > 0 ? parsed.id : `thread-${Date.now()}`;
32093
- const threadFile = path60.resolve(dir, `${id2}.json`);
32257
+ const threadFile = path61.resolve(dir, `${id2}.json`);
32094
32258
  const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
32095
32259
  return { id: id2, filePath: threadFile, messages };
32096
32260
  } catch {
32097
32261
  }
32098
32262
  }
32099
32263
  const id = `thread-${Date.now()}`;
32100
- const filePath = path60.resolve(dir, `${id}.json`);
32264
+ const filePath = path61.resolve(dir, `${id}.json`);
32101
32265
  const thread = { id, filePath, messages: [] };
32102
32266
  saveLocalThread(thread);
32103
32267
  return thread;
32104
32268
  }
32105
32269
  function saveLocalThread(thread) {
32106
32270
  const dir = resolveLocalThreadsDir();
32107
- fs53.mkdirSync(dir, { recursive: true });
32108
- fs53.writeFileSync(
32271
+ fs54.mkdirSync(dir, { recursive: true });
32272
+ fs54.writeFileSync(
32109
32273
  thread.filePath,
32110
32274
  `${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
32111
32275
  `,
32112
32276
  "utf-8"
32113
32277
  );
32114
- const activePath = path60.resolve(dir, "active-thread.json");
32115
- fs53.writeFileSync(
32278
+ const activePath = path61.resolve(dir, "active-thread.json");
32279
+ fs54.writeFileSync(
32116
32280
  activePath,
32117
32281
  `${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
32118
32282
  `,
@@ -32258,7 +32422,7 @@ async function collectBindingsFromContract(contract, promptSeed) {
32258
32422
  return bindings;
32259
32423
  }
32260
32424
  function resolveCurrentProject() {
32261
- return path60.basename(process.cwd());
32425
+ return path61.basename(process.cwd());
32262
32426
  }
32263
32427
  async function runMemoryKnowledgeHub() {
32264
32428
  const project = resolveCurrentProject();
@@ -32410,6 +32574,7 @@ API key: ${result.apiKey ? "configured" : "not needed"}`,
32410
32574
  }
32411
32575
  }
32412
32576
  async function runDiscoveryHub(opts) {
32577
+ track("discover_opened");
32413
32578
  printPaperclipCliBanner();
32414
32579
  p34.intro("Growthub Local");
32415
32580
  while (true) {
@@ -32837,12 +33002,12 @@ function isInstallerMode() {
32837
33002
  }
32838
33003
  function listLocalSurfaces() {
32839
33004
  const homeDir = resolvePaperclipHomeDir();
32840
- const instancesDir = path60.resolve(homeDir, "instances");
32841
- if (!fs53.existsSync(instancesDir)) return [];
32842
- return fs53.readdirSync(instancesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
33005
+ const instancesDir = path61.resolve(homeDir, "instances");
33006
+ if (!fs54.existsSync(instancesDir)) return [];
33007
+ return fs54.readdirSync(instancesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
32843
33008
  const instanceId = entry.name;
32844
- const configPath = path60.resolve(instancesDir, instanceId, "config.json");
32845
- if (!fs53.existsSync(configPath)) return null;
33009
+ const configPath = path61.resolve(instancesDir, instanceId, "config.json");
33010
+ if (!fs54.existsSync(configPath)) return null;
32846
33011
  try {
32847
33012
  const config = readConfig(configPath);
32848
33013
  if (!config) return null;
@@ -33010,6 +33175,7 @@ if (surfaceRuntime.capabilities.dxEnabled) {
33010
33175
  } else {
33011
33176
  registerGtmCommands(program);
33012
33177
  }
33178
+ trackCliStart();
33013
33179
  program.parseAsync().catch((err) => {
33014
33180
  console.error(err instanceof Error ? err.message : String(err));
33015
33181
  process.exit(1);