@growthub/cli 0.7.6 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/worker-kits/creative-strategist-v1/skills.md +13 -11
- package/assets/worker-kits/creative-strategist-v1/templates/brief-template.js +1 -1
- package/assets/worker-kits/creative-strategist-v1/workers/creative-strategist/CLAUDE.md +22 -21
- package/assets/worker-kits/growthub-ai-website-cloner-v1/.env.example +4 -2
- package/assets/worker-kits/growthub-ai-website-cloner-v1/QUICKSTART.md +4 -4
- package/assets/worker-kits/growthub-ai-website-cloner-v1/runtime-assumptions.md +1 -1
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/clone-fork.sh +1 -1
- package/assets/worker-kits/growthub-ai-website-cloner-v1/setup/verify-env.mjs +1 -1
- package/assets/worker-kits/growthub-ai-website-cloner-v1/validation-checklist.md +1 -1
- package/assets/worker-kits/growthub-ai-website-cloner-v1/workers/ai-website-cloner-operator/CLAUDE.md +1 -1
- package/assets/worker-kits/growthub-geo-seo-v1/.env.example +5 -3
- package/assets/worker-kits/growthub-geo-seo-v1/setup/check-deps.sh +2 -2
- package/assets/worker-kits/growthub-geo-seo-v1/setup/clone-fork.sh +1 -1
- package/assets/worker-kits/growthub-geo-seo-v1/setup/verify-env.mjs +1 -1
- package/assets/worker-kits/growthub-geo-seo-v1/validation-checklist.md +1 -1
- package/assets/worker-kits/growthub-geo-seo-v1/workers/geo-seo-operator/CLAUDE.md +1 -1
- package/assets/worker-kits/growthub-hyperframes-studio-v1/.env.example +4 -2
- package/assets/worker-kits/growthub-hyperframes-studio-v1/docs/hyperframes-discovery-path.md +2 -2
- package/assets/worker-kits/growthub-hyperframes-studio-v1/setup/clone-fork.sh +2 -1
- package/assets/worker-kits/growthub-hyperframes-studio-v1/setup/verify-env.mjs +3 -2
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/.env.example +5 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/QUICKSTART.md +1 -1
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/runtime-assumptions.md +1 -1
- package/assets/worker-kits/growthub-open-montage-studio-v1/.env.example +4 -2
- package/assets/worker-kits/growthub-open-montage-studio-v1/QUICKSTART.md +1 -1
- package/assets/worker-kits/growthub-open-montage-studio-v1/runtime-assumptions.md +1 -1
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/clone-fork.sh +2 -1
- package/assets/worker-kits/growthub-open-montage-studio-v1/setup/verify-env.mjs +5 -2
- package/assets/worker-kits/growthub-open-montage-studio-v1/validation-checklist.md +3 -3
- package/assets/worker-kits/growthub-open-montage-studio-v1/workers/open-montage-studio-operator/CLAUDE.md +2 -2
- package/assets/worker-kits/growthub-postiz-social-v1/.env.example +4 -2
- package/assets/worker-kits/growthub-postiz-social-v1/QUICKSTART.md +2 -2
- package/assets/worker-kits/growthub-postiz-social-v1/setup/clone-fork.sh +1 -1
- package/assets/worker-kits/growthub-postiz-social-v1/setup/verify-env.mjs +2 -1
- package/assets/worker-kits/growthub-postiz-social-v1/validation-checklist.md +1 -1
- package/assets/worker-kits/growthub-postiz-social-v1/workers/postiz-social-operator/CLAUDE.md +1 -1
- package/assets/worker-kits/growthub-twenty-crm-v1/.env.example +4 -2
- package/assets/worker-kits/growthub-twenty-crm-v1/QUICKSTART.md +1 -1
- package/assets/worker-kits/growthub-twenty-crm-v1/setup/clone-fork.sh +1 -1
- package/assets/worker-kits/growthub-twenty-crm-v1/workers/twenty-crm-operator/CLAUDE.md +1 -1
- package/dist/index.js +1177 -326
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -8182,8 +8182,8 @@ var init_onboard = __esm({
|
|
|
8182
8182
|
|
|
8183
8183
|
// src/client/http.ts
|
|
8184
8184
|
import { URL as URL2 } from "node:url";
|
|
8185
|
-
function buildUrl(apiBase,
|
|
8186
|
-
const normalizedPath =
|
|
8185
|
+
function buildUrl(apiBase, path63) {
|
|
8186
|
+
const normalizedPath = path63.startsWith("/") ? path63 : `/${path63}`;
|
|
8187
8187
|
const [pathname, query] = normalizedPath.split("?");
|
|
8188
8188
|
const url = new URL2(apiBase);
|
|
8189
8189
|
url.pathname = `${url.pathname.replace(/\/+$/, "")}${pathname}`;
|
|
@@ -8245,26 +8245,26 @@ var init_http = __esm({
|
|
|
8245
8245
|
this.runId = opts.runId?.trim() || void 0;
|
|
8246
8246
|
this.userId = opts.userId?.trim() || void 0;
|
|
8247
8247
|
}
|
|
8248
|
-
get(
|
|
8249
|
-
return this.request(
|
|
8248
|
+
get(path63, opts) {
|
|
8249
|
+
return this.request(path63, { method: "GET" }, opts);
|
|
8250
8250
|
}
|
|
8251
|
-
post(
|
|
8252
|
-
return this.request(
|
|
8251
|
+
post(path63, body, opts) {
|
|
8252
|
+
return this.request(path63, {
|
|
8253
8253
|
method: "POST",
|
|
8254
8254
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
8255
8255
|
}, opts);
|
|
8256
8256
|
}
|
|
8257
|
-
patch(
|
|
8258
|
-
return this.request(
|
|
8257
|
+
patch(path63, body, opts) {
|
|
8258
|
+
return this.request(path63, {
|
|
8259
8259
|
method: "PATCH",
|
|
8260
8260
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
8261
8261
|
}, opts);
|
|
8262
8262
|
}
|
|
8263
|
-
delete(
|
|
8264
|
-
return this.request(
|
|
8263
|
+
delete(path63, opts) {
|
|
8264
|
+
return this.request(path63, { method: "DELETE" }, opts);
|
|
8265
8265
|
}
|
|
8266
|
-
async request(
|
|
8267
|
-
const url = buildUrl(this.apiBase,
|
|
8266
|
+
async request(path63, init, opts) {
|
|
8267
|
+
const url = buildUrl(this.apiBase, path63);
|
|
8268
8268
|
const headers = {
|
|
8269
8269
|
accept: "application/json",
|
|
8270
8270
|
...toStringRecord(init.headers)
|
|
@@ -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
|
|
9705
|
+
const path63 = `${DEFAULT_INTEGRATION_CREDENTIAL_PATH}&provider=${encodeURIComponent(providerId)}`;
|
|
9706
9706
|
try {
|
|
9707
|
-
return await client.get(
|
|
9707
|
+
return await client.get(path63, { 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);
|
|
@@ -10279,12 +10279,12 @@ var init_github = __esm({
|
|
|
10279
10279
|
});
|
|
10280
10280
|
|
|
10281
10281
|
// src/starter/init.ts
|
|
10282
|
-
import
|
|
10283
|
-
import
|
|
10282
|
+
import fs43 from "node:fs";
|
|
10283
|
+
import path51 from "node:path";
|
|
10284
10284
|
async function initStarterWorkspace(opts) {
|
|
10285
10285
|
const kitId = opts.kitId ?? DEFAULT_STARTER_KIT_ID;
|
|
10286
|
-
const absOut =
|
|
10287
|
-
if (
|
|
10286
|
+
const absOut = path51.resolve(opts.out);
|
|
10287
|
+
if (fs43.existsSync(absOut) && fs43.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() ||
|
|
10296
|
+
label: opts.name?.trim() || path51.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
|
|
10390
|
-
import
|
|
10389
|
+
import fs44 from "node:fs";
|
|
10390
|
+
import path52 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 (
|
|
10521
|
+
if (fs44.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 =
|
|
10526
|
-
|
|
10525
|
+
const parent = path52.dirname(input.destination);
|
|
10526
|
+
fs44.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 =
|
|
10554
|
-
if (!
|
|
10553
|
+
const abs = path52.resolve(rootDir, normalizedSub);
|
|
10554
|
+
if (!fs44.existsSync(abs) || !fs44.statSync(abs).isDirectory()) {
|
|
10555
10555
|
throw new Error(`Subdirectory not found in cloned repo: ${subdirectory}`);
|
|
10556
10556
|
}
|
|
10557
|
-
const tmp =
|
|
10558
|
-
|
|
10559
|
-
`.${
|
|
10557
|
+
const tmp = path52.resolve(
|
|
10558
|
+
path52.dirname(rootDir),
|
|
10559
|
+
`.${path52.basename(rootDir)}-narrow-${Date.now().toString(36)}`
|
|
10560
10560
|
);
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10561
|
+
fs44.renameSync(abs, tmp);
|
|
10562
|
+
fs44.rmSync(rootDir, { recursive: true, force: true });
|
|
10563
|
+
fs44.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
|
|
10578
|
-
import
|
|
10579
|
-
import
|
|
10577
|
+
import fs45 from "node:fs";
|
|
10578
|
+
import os11 from "node:os";
|
|
10579
|
+
import path53 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 =
|
|
10846
|
-
const rootAbs =
|
|
10847
|
-
if (!abs.startsWith(rootAbs +
|
|
10845
|
+
const abs = path53.resolve(candidate);
|
|
10846
|
+
const rootAbs = path53.resolve(root);
|
|
10847
|
+
if (!abs.startsWith(rootAbs + path53.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 =
|
|
10864
|
-
if (!
|
|
10863
|
+
const skillFile = path53.resolve(dir, "SKILL.md");
|
|
10864
|
+
if (!fs45.existsSync(skillFile) || !fs45.statSync(skillFile).isFile()) {
|
|
10865
10865
|
return false;
|
|
10866
10866
|
}
|
|
10867
|
-
if (
|
|
10867
|
+
if (path53.basename(dir) === skillSlug) {
|
|
10868
10868
|
return true;
|
|
10869
10869
|
}
|
|
10870
|
-
const content =
|
|
10870
|
+
const content = fs45.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
|
-
|
|
10877
|
-
|
|
10876
|
+
path53.resolve(root, "skills", skillSlug),
|
|
10877
|
+
path53.resolve(root, skillSlug)
|
|
10878
10878
|
];
|
|
10879
10879
|
for (const candidate of preferred) {
|
|
10880
|
-
if (
|
|
10880
|
+
if (fs45.existsSync(candidate) && fs45.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
|
|
10890
|
+
for (const entry of fs45.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(
|
|
10895
|
+
queue.push(path53.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
|
-
|
|
10906
|
-
for (const entry of
|
|
10907
|
-
const fromPath =
|
|
10908
|
-
const toPath =
|
|
10905
|
+
fs45.mkdirSync(current.to, { recursive: true });
|
|
10906
|
+
for (const entry of fs45.readdirSync(current.from, { withFileTypes: true })) {
|
|
10907
|
+
const fromPath = path53.resolve(current.from, entry.name);
|
|
10908
|
+
const toPath = path53.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 =
|
|
10915
|
-
|
|
10916
|
-
|
|
10914
|
+
const data = fs45.readFileSync(fromPath);
|
|
10915
|
+
fs45.mkdirSync(path53.dirname(toPath), { recursive: true });
|
|
10916
|
+
fs45.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 (
|
|
10927
|
+
if (fs45.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 =
|
|
10936
|
-
|
|
10935
|
+
const cloneRoot = fs45.mkdtempSync(
|
|
10936
|
+
path53.join(os11.tmpdir(), "growthub-skills-source-")
|
|
10937
10937
|
);
|
|
10938
10938
|
try {
|
|
10939
|
-
const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot],
|
|
10939
|
+
const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot], path53.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
|
-
|
|
10952
|
+
fs45.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
|
|
10967
|
-
import
|
|
10966
|
+
import fs46 from "node:fs";
|
|
10967
|
+
import path54 from "node:path";
|
|
10968
10968
|
function safeReadPackageJson(dir) {
|
|
10969
|
-
const p35 =
|
|
10970
|
-
if (!
|
|
10969
|
+
const p35 = path54.resolve(dir, "package.json");
|
|
10970
|
+
if (!fs46.existsSync(p35)) return null;
|
|
10971
10971
|
try {
|
|
10972
|
-
return JSON.parse(
|
|
10972
|
+
return JSON.parse(fs46.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 (
|
|
10983
|
-
if (
|
|
10984
|
-
if (
|
|
10985
|
-
if (
|
|
10982
|
+
if (fs46.existsSync(path54.resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
10983
|
+
if (fs46.existsSync(path54.resolve(dir, "yarn.lock"))) return "yarn";
|
|
10984
|
+
if (fs46.existsSync(path54.resolve(dir, "bun.lockb"))) return "bun";
|
|
10985
|
+
if (fs46.existsSync(path54.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) =>
|
|
10999
|
+
return markers.some((name) => fs46.existsSync(path54.resolve(rootDir, name)));
|
|
11000
11000
|
}
|
|
11001
11001
|
function detectFramework(rootDir, pkg) {
|
|
11002
11002
|
if (!pkg) {
|
|
11003
11003
|
if (looksLikeSkillPayload(rootDir)) return "skill";
|
|
11004
|
-
if (
|
|
11004
|
+
if (fs46.existsSync(path54.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) =>
|
|
11014
|
-
if (deps.has("next") ||
|
|
11013
|
+
].some((name) => fs46.existsSync(path54.resolve(rootDir, name)));
|
|
11014
|
+
if (deps.has("next") || fs46.existsSync(path54.resolve(rootDir, "next.config.js")) || fs46.existsSync(path54.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 (!
|
|
11041
|
-
return
|
|
11040
|
+
if (!fs46.existsSync(dir)) return [];
|
|
11041
|
+
return fs46.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 =
|
|
11048
|
-
if (
|
|
11047
|
+
const abs = path54.resolve(rootDir, candidate);
|
|
11048
|
+
if (fs46.existsSync(abs) && fs46.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 (!
|
|
11064
|
+
if (!fs46.existsSync(rootDir) || !fs46.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 =
|
|
11069
|
+
const appRootAbs = path54.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
|
|
11110
|
-
import
|
|
11109
|
+
import fs47 from "node:fs";
|
|
11110
|
+
import path55 from "node:path";
|
|
11111
11111
|
function isLikelyTextFile(filename) {
|
|
11112
|
-
const ext =
|
|
11112
|
+
const ext = path55.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(
|
|
11117
|
+
return SUSPICIOUS_BINARY_EXTENSIONS.has(path55.extname(filename).toLowerCase());
|
|
11118
11118
|
}
|
|
11119
11119
|
function isUnexpectedArchive(filename) {
|
|
11120
|
-
const ext =
|
|
11120
|
+
const ext = path55.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 =
|
|
11175
|
+
entries = fs47.readdirSync(current, { withFileTypes: true });
|
|
11176
11176
|
} catch {
|
|
11177
11177
|
continue;
|
|
11178
11178
|
}
|
|
11179
11179
|
for (const entry of entries) {
|
|
11180
|
-
const abs =
|
|
11180
|
+
const abs = path55.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 =
|
|
11187
|
+
const rel = path55.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 (!
|
|
11197
|
+
if (!fs47.existsSync(payloadRoot) || !fs47.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 =
|
|
11207
|
+
size = fs47.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 (${
|
|
11216
|
+
message: `Payload ships a precompiled binary (${path55.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 (${
|
|
11225
|
+
message: `Payload ships an archive (${path55.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 =
|
|
11233
|
+
const handle = fs47.openSync(abs, "r");
|
|
11234
11234
|
try {
|
|
11235
11235
|
buf = Buffer.alloc(Math.min(size, MAX_BYTES_PER_FILE));
|
|
11236
|
-
|
|
11236
|
+
fs47.readSync(handle, buf, 0, buf.length, 0);
|
|
11237
11237
|
} finally {
|
|
11238
|
-
|
|
11238
|
+
fs47.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
|
|
11448
|
-
import
|
|
11447
|
+
import fs48 from "node:fs";
|
|
11448
|
+
import path56 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 (!
|
|
11454
|
-
const stats =
|
|
11453
|
+
if (!fs48.existsSync(absDest)) return { exists: false, nonEmpty: false };
|
|
11454
|
+
const stats = fs48.statSync(absDest);
|
|
11455
11455
|
if (!stats.isDirectory()) {
|
|
11456
11456
|
throw new Error(`Destination is not a directory: ${absDest}`);
|
|
11457
11457
|
}
|
|
11458
|
-
const entries =
|
|
11458
|
+
const entries = fs48.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 =
|
|
11468
|
+
const absDest = path56.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
|
|
11582
|
-
import
|
|
11581
|
+
import fs49 from "node:fs";
|
|
11582
|
+
import path57 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 =
|
|
11637
|
+
const summaryPath = path57.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
|
-
|
|
11668
|
-
|
|
11667
|
+
fs49.mkdirSync(path57.dirname(summaryPath), { recursive: true });
|
|
11668
|
+
fs49.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
|
|
11679
|
-
import
|
|
11680
|
-
import
|
|
11678
|
+
import fs50 from "node:fs";
|
|
11679
|
+
import os12 from "node:os";
|
|
11680
|
+
import path58 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
|
|
11686
|
-
|
|
11687
|
-
`growthub-source-import-${
|
|
11685
|
+
return path58.join(
|
|
11686
|
+
os12.tmpdir(),
|
|
11687
|
+
`growthub-source-import-${path58.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 =
|
|
11720
|
-
if (
|
|
11721
|
-
|
|
11719
|
+
const target = path58.resolve(forkPath, payloadRelativePath);
|
|
11720
|
+
if (fs50.existsSync(target)) {
|
|
11721
|
+
fs50.rmSync(target, { recursive: true, force: true });
|
|
11722
11722
|
}
|
|
11723
|
-
|
|
11724
|
-
|
|
11723
|
+
fs50.mkdirSync(path58.dirname(target), { recursive: true });
|
|
11724
|
+
fs50.renameSync(payloadRoot, target);
|
|
11725
11725
|
return target;
|
|
11726
11726
|
}
|
|
11727
11727
|
function writeManifest(forkPath, manifest) {
|
|
11728
|
-
const p35 =
|
|
11729
|
-
|
|
11730
|
-
|
|
11728
|
+
const p35 = path58.resolve(forkPath, MANIFEST_RELATIVE_PATH);
|
|
11729
|
+
fs50.mkdirSync(path58.dirname(p35), { recursive: true });
|
|
11730
|
+
fs50.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
|
-
|
|
11770
|
+
fs50.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
|
|
11902
|
-
import
|
|
11901
|
+
import fs51 from "node:fs";
|
|
11902
|
+
import path59 from "node:path";
|
|
11903
11903
|
function resolveJobsDir() {
|
|
11904
|
-
return
|
|
11904
|
+
return path59.resolve(resolveKitForksHomeDir(), "source-import-jobs");
|
|
11905
11905
|
}
|
|
11906
11906
|
function resolveJobPath2(jobId) {
|
|
11907
|
-
return
|
|
11907
|
+
return path59.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
|
-
|
|
11915
|
-
|
|
11914
|
+
fs51.mkdirSync(path59.dirname(p35), { recursive: true });
|
|
11915
|
+
fs51.writeFileSync(p35, JSON.stringify(job, null, 2) + "\n", "utf8");
|
|
11916
11916
|
}
|
|
11917
11917
|
function readJobFile(p35) {
|
|
11918
|
-
if (!
|
|
11918
|
+
if (!fs51.existsSync(p35)) return null;
|
|
11919
11919
|
try {
|
|
11920
|
-
return JSON.parse(
|
|
11920
|
+
return JSON.parse(fs51.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
|
-
|
|
11930
|
+
fs51.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 =
|
|
11949
|
+
const destination = path59.resolve(input.out);
|
|
11950
11950
|
const sourceKind = input.source.kind;
|
|
11951
11951
|
const initial = {
|
|
11952
11952
|
jobId,
|
|
@@ -12103,8 +12103,8 @@ __export(source_import_discovery_exports, {
|
|
|
12103
12103
|
});
|
|
12104
12104
|
import * as p33 from "@clack/prompts";
|
|
12105
12105
|
import pc47 from "picocolors";
|
|
12106
|
-
import
|
|
12107
|
-
import
|
|
12106
|
+
import fs54 from "node:fs";
|
|
12107
|
+
import path61 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, "");
|
|
@@ -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("~/") ?
|
|
12136
|
-
const resolved =
|
|
12137
|
-
if (
|
|
12138
|
-
const finalPath =
|
|
12135
|
+
const expanded = trimmed.startsWith("~/") ? path61.join(process.env.HOME ?? "~", trimmed.slice(2)) : trimmed;
|
|
12136
|
+
const resolved = path61.resolve(expanded);
|
|
12137
|
+
if (fs54.existsSync(resolved) && fs54.statSync(resolved).isDirectory()) {
|
|
12138
|
+
const finalPath = path61.join(resolved, suggestedName);
|
|
12139
12139
|
p33.note(
|
|
12140
12140
|
[
|
|
12141
12141
|
`You selected an existing folder: ${resolved}`,
|
|
@@ -12406,8 +12406,8 @@ var init_source_import_discovery = __esm({
|
|
|
12406
12406
|
import { Command } from "commander";
|
|
12407
12407
|
import * as p34 from "@clack/prompts";
|
|
12408
12408
|
import pc48 from "picocolors";
|
|
12409
|
-
import
|
|
12410
|
-
import
|
|
12409
|
+
import fs55 from "node:fs";
|
|
12410
|
+
import path62 from "node:path";
|
|
12411
12411
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
12412
12412
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
12413
12413
|
|
|
@@ -13208,8 +13208,8 @@ function printItemCompleted(item) {
|
|
|
13208
13208
|
const changes = Array.isArray(item.changes) ? item.changes : [];
|
|
13209
13209
|
const entries = changes.map((changeRaw) => asRecord(changeRaw)).filter((change) => Boolean(change)).map((change) => {
|
|
13210
13210
|
const kind = asString(change.kind, "update");
|
|
13211
|
-
const
|
|
13212
|
-
return `${kind} ${
|
|
13211
|
+
const path63 = asString(change.path, "unknown");
|
|
13212
|
+
return `${kind} ${path63}`;
|
|
13213
13213
|
});
|
|
13214
13214
|
const preview = entries.length > 0 ? entries.slice(0, 6).join(", ") : "none";
|
|
13215
13215
|
const more = entries.length > 6 ? ` (+${entries.length - 6} more)` : "";
|
|
@@ -16043,8 +16043,8 @@ function registerIssueCommands(program2) {
|
|
|
16043
16043
|
if (opts.assigneeAgentId) params.set("assigneeAgentId", opts.assigneeAgentId);
|
|
16044
16044
|
if (opts.projectId) params.set("projectId", opts.projectId);
|
|
16045
16045
|
const query = params.toString();
|
|
16046
|
-
const
|
|
16047
|
-
const rows = await ctx.api.get(
|
|
16046
|
+
const path63 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
|
|
16047
|
+
const rows = await ctx.api.get(path63) ?? [];
|
|
16048
16048
|
const filtered = filterIssueRows(rows, opts.match);
|
|
16049
16049
|
if (ctx.json) {
|
|
16050
16050
|
printOutput(filtered, { json: true });
|
|
@@ -16650,8 +16650,8 @@ function registerActivityCommands(program2) {
|
|
|
16650
16650
|
if (opts.entityType) params.set("entityType", opts.entityType);
|
|
16651
16651
|
if (opts.entityId) params.set("entityId", opts.entityId);
|
|
16652
16652
|
const query = params.toString();
|
|
16653
|
-
const
|
|
16654
|
-
const rows = await ctx.api.get(
|
|
16653
|
+
const path63 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
|
|
16654
|
+
const rows = await ctx.api.get(path63) ?? [];
|
|
16655
16655
|
if (ctx.json) {
|
|
16656
16656
|
printOutput(rows, { json: true });
|
|
16657
16657
|
return;
|
|
@@ -22749,6 +22749,388 @@ function createHostedExecutionClient() {
|
|
|
22749
22749
|
};
|
|
22750
22750
|
}
|
|
22751
22751
|
|
|
22752
|
+
// src/runtime/cms-manifest-client/index.ts
|
|
22753
|
+
init_store();
|
|
22754
|
+
init_session_store();
|
|
22755
|
+
import {
|
|
22756
|
+
API_CONTRACT_VERSION
|
|
22757
|
+
} from "@growthub/api-contract";
|
|
22758
|
+
var MANIFEST_PATH = "/api/cms/capabilities";
|
|
22759
|
+
var CONTRACT_VERSION_HEADER = "x-growthub-api-contract-version";
|
|
22760
|
+
var DEFAULT_HOSTED_BASE_URL2 = "https://www.growthub.ai";
|
|
22761
|
+
var CLI_SUPPORTED_CONTRACT_VERSION = API_CONTRACT_VERSION;
|
|
22762
|
+
var ManifestClientError = class extends Error {
|
|
22763
|
+
code;
|
|
22764
|
+
constructor(code, message) {
|
|
22765
|
+
super(message);
|
|
22766
|
+
this.code = code;
|
|
22767
|
+
this.name = "ManifestClientError";
|
|
22768
|
+
}
|
|
22769
|
+
};
|
|
22770
|
+
var ManifestUnauthenticatedError = class extends ManifestClientError {
|
|
22771
|
+
constructor(message = "Hosted manifest requires an authenticated session. Run `growthub auth login`.") {
|
|
22772
|
+
super("UNAUTHENTICATED", message);
|
|
22773
|
+
this.name = "ManifestUnauthenticatedError";
|
|
22774
|
+
}
|
|
22775
|
+
};
|
|
22776
|
+
var ManifestEndpointUnavailableError = class extends ManifestClientError {
|
|
22777
|
+
status;
|
|
22778
|
+
constructor(status, message) {
|
|
22779
|
+
super("ENDPOINT_UNAVAILABLE", message);
|
|
22780
|
+
this.status = status;
|
|
22781
|
+
this.name = "ManifestEndpointUnavailableError";
|
|
22782
|
+
}
|
|
22783
|
+
};
|
|
22784
|
+
var ManifestContractMismatchError = class extends ManifestClientError {
|
|
22785
|
+
serverVersion;
|
|
22786
|
+
expectedVersion;
|
|
22787
|
+
constructor(serverVersion, expectedVersion) {
|
|
22788
|
+
super(
|
|
22789
|
+
"CONTRACT_MISMATCH",
|
|
22790
|
+
serverVersion === null ? `Hosted manifest response is missing the \`${CONTRACT_VERSION_HEADER}\` header; expected ${expectedVersion}.` : `Hosted manifest contract version mismatch: expected ${expectedVersion}, server reported ${serverVersion}.`
|
|
22791
|
+
);
|
|
22792
|
+
this.serverVersion = serverVersion;
|
|
22793
|
+
this.expectedVersion = expectedVersion;
|
|
22794
|
+
this.name = "ManifestContractMismatchError";
|
|
22795
|
+
}
|
|
22796
|
+
};
|
|
22797
|
+
var ManifestMalformedError = class extends ManifestClientError {
|
|
22798
|
+
constructor(message) {
|
|
22799
|
+
super("MALFORMED", message);
|
|
22800
|
+
this.name = "ManifestMalformedError";
|
|
22801
|
+
}
|
|
22802
|
+
};
|
|
22803
|
+
function trimSlashes3(value) {
|
|
22804
|
+
return value.replace(/\/+$/, "");
|
|
22805
|
+
}
|
|
22806
|
+
function resolveManifestBaseUrl(opts = {}) {
|
|
22807
|
+
const explicit = opts.explicit?.trim();
|
|
22808
|
+
if (explicit) return { baseUrl: trimSlashes3(explicit), source: "explicit" };
|
|
22809
|
+
const sessionBase = (opts.sessionHostedBaseUrl ?? readSession()?.hostedBaseUrl)?.trim();
|
|
22810
|
+
if (sessionBase) return { baseUrl: trimSlashes3(sessionBase), source: "session" };
|
|
22811
|
+
const envBase = process.env.GROWTHUB_BASE_URL?.trim();
|
|
22812
|
+
if (envBase) return { baseUrl: trimSlashes3(envBase), source: "env" };
|
|
22813
|
+
try {
|
|
22814
|
+
const config = readConfig(opts.configPath);
|
|
22815
|
+
const authNode = config?.auth;
|
|
22816
|
+
const configuredBase = authNode?.growthubBaseUrl?.trim();
|
|
22817
|
+
if (configuredBase) return { baseUrl: trimSlashes3(configuredBase), source: "config.growthubBaseUrl" };
|
|
22818
|
+
const portalBase = authNode?.growthubPortalBaseUrl?.trim();
|
|
22819
|
+
if (portalBase) return { baseUrl: trimSlashes3(portalBase), source: "config.growthubPortalBaseUrl" };
|
|
22820
|
+
} catch {
|
|
22821
|
+
}
|
|
22822
|
+
return { baseUrl: DEFAULT_HOSTED_BASE_URL2, source: "default" };
|
|
22823
|
+
}
|
|
22824
|
+
function isRecord(value) {
|
|
22825
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22826
|
+
}
|
|
22827
|
+
function assertRecord(value, path63) {
|
|
22828
|
+
if (!isRecord(value)) {
|
|
22829
|
+
throw new ManifestMalformedError(`Expected object at \`${path63}\`.`);
|
|
22830
|
+
}
|
|
22831
|
+
return value;
|
|
22832
|
+
}
|
|
22833
|
+
function assertArray(value, path63) {
|
|
22834
|
+
if (!Array.isArray(value)) {
|
|
22835
|
+
throw new ManifestMalformedError(`Expected array at \`${path63}\`.`);
|
|
22836
|
+
}
|
|
22837
|
+
return value;
|
|
22838
|
+
}
|
|
22839
|
+
function assertString(value, path63) {
|
|
22840
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
22841
|
+
throw new ManifestMalformedError(`Expected non-empty string at \`${path63}\`.`);
|
|
22842
|
+
}
|
|
22843
|
+
return value;
|
|
22844
|
+
}
|
|
22845
|
+
function normalizeProvenance(value, path63) {
|
|
22846
|
+
const record = assertRecord(value, path63);
|
|
22847
|
+
const originType = assertString(record.originType, `${path63}.originType`);
|
|
22848
|
+
const allowed = ["hosted", "local-extension", "derived-from-workflow"];
|
|
22849
|
+
if (!allowed.includes(originType)) {
|
|
22850
|
+
throw new ManifestMalformedError(
|
|
22851
|
+
`Unknown provenance originType at \`${path63}.originType\`: ${originType}`
|
|
22852
|
+
);
|
|
22853
|
+
}
|
|
22854
|
+
return {
|
|
22855
|
+
originType,
|
|
22856
|
+
sourceHost: typeof record.sourceHost === "string" ? record.sourceHost : void 0,
|
|
22857
|
+
sourceWorkflowId: typeof record.sourceWorkflowId === "string" ? record.sourceWorkflowId : void 0,
|
|
22858
|
+
sourceManifestId: typeof record.sourceManifestId === "string" ? record.sourceManifestId : void 0,
|
|
22859
|
+
localExtensionPath: typeof record.localExtensionPath === "string" ? record.localExtensionPath : void 0,
|
|
22860
|
+
recordedAt: typeof record.recordedAt === "string" ? record.recordedAt : void 0,
|
|
22861
|
+
note: typeof record.note === "string" ? record.note : void 0
|
|
22862
|
+
};
|
|
22863
|
+
}
|
|
22864
|
+
function normalizeManifestEntry(value, idx) {
|
|
22865
|
+
const record = assertRecord(value, `capabilities[${idx}]`);
|
|
22866
|
+
const slug = assertString(record.slug, `capabilities[${idx}].slug`);
|
|
22867
|
+
const family = assertString(record.family, `capabilities[${idx}].family`);
|
|
22868
|
+
const displayName = assertString(record.displayName, `capabilities[${idx}].displayName`);
|
|
22869
|
+
const executionKind = assertString(record.executionKind, `capabilities[${idx}].executionKind`);
|
|
22870
|
+
const requiredBindings = assertArray(record.requiredBindings, `capabilities[${idx}].requiredBindings`).map((entry, i) => assertString(entry, `capabilities[${idx}].requiredBindings[${i}]`));
|
|
22871
|
+
const outputTypes = assertArray(record.outputTypes, `capabilities[${idx}].outputTypes`).map((entry, i) => assertString(entry, `capabilities[${idx}].outputTypes[${i}]`));
|
|
22872
|
+
const node = assertRecord(record.node, `capabilities[${idx}].node`);
|
|
22873
|
+
const provenance = normalizeProvenance(record.provenance, `capabilities[${idx}].provenance`);
|
|
22874
|
+
return {
|
|
22875
|
+
slug,
|
|
22876
|
+
family,
|
|
22877
|
+
displayName,
|
|
22878
|
+
executionKind,
|
|
22879
|
+
requiredBindings,
|
|
22880
|
+
outputTypes,
|
|
22881
|
+
node,
|
|
22882
|
+
inputSchema: record.inputSchema,
|
|
22883
|
+
outputSchema: record.outputSchema,
|
|
22884
|
+
providerHints: record.providerHints,
|
|
22885
|
+
executionHints: record.executionHints,
|
|
22886
|
+
provenance
|
|
22887
|
+
};
|
|
22888
|
+
}
|
|
22889
|
+
function normalizeEnvelope(raw) {
|
|
22890
|
+
const record = assertRecord(raw, "envelope");
|
|
22891
|
+
if (record.version !== 1) {
|
|
22892
|
+
throw new ManifestMalformedError(
|
|
22893
|
+
`Unsupported envelope version: ${String(record.version)} (expected 1).`
|
|
22894
|
+
);
|
|
22895
|
+
}
|
|
22896
|
+
const host = assertString(record.host, "host");
|
|
22897
|
+
const fetchedAt = assertString(record.fetchedAt, "fetchedAt");
|
|
22898
|
+
const source = assertString(record.source, "source");
|
|
22899
|
+
const allowedSources = ["hosted", "local-extension", "derived"];
|
|
22900
|
+
if (!allowedSources.includes(source)) {
|
|
22901
|
+
throw new ManifestMalformedError(`Unknown envelope source: ${source}`);
|
|
22902
|
+
}
|
|
22903
|
+
const capabilities = assertArray(record.capabilities, "capabilities").map((entry, idx) => normalizeManifestEntry(entry, idx));
|
|
22904
|
+
const provenance = record.provenance !== void 0 ? normalizeProvenance(record.provenance, "provenance") : void 0;
|
|
22905
|
+
return {
|
|
22906
|
+
version: 1,
|
|
22907
|
+
host,
|
|
22908
|
+
fetchedAt,
|
|
22909
|
+
source,
|
|
22910
|
+
capabilities,
|
|
22911
|
+
provenance
|
|
22912
|
+
};
|
|
22913
|
+
}
|
|
22914
|
+
function parseContractVersionHeader(raw) {
|
|
22915
|
+
if (raw === null) return null;
|
|
22916
|
+
const trimmed = raw.trim();
|
|
22917
|
+
if (!trimmed) return null;
|
|
22918
|
+
const parsed = Number(trimmed);
|
|
22919
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
22920
|
+
}
|
|
22921
|
+
async function fetchCapabilityManifest(opts = {}) {
|
|
22922
|
+
const resolvedBaseUrl = resolveManifestBaseUrl(opts);
|
|
22923
|
+
const url = new URL(MANIFEST_PATH, `${resolvedBaseUrl.baseUrl}/`).toString();
|
|
22924
|
+
const headers = {
|
|
22925
|
+
accept: "application/json"
|
|
22926
|
+
};
|
|
22927
|
+
if (!opts.anonymous) {
|
|
22928
|
+
const session = readSession();
|
|
22929
|
+
if (session && isSessionExpired(session)) {
|
|
22930
|
+
throw new ManifestUnauthenticatedError(
|
|
22931
|
+
"Hosted session expired. Run `growthub auth login` to re-authenticate."
|
|
22932
|
+
);
|
|
22933
|
+
}
|
|
22934
|
+
if (session) {
|
|
22935
|
+
headers.authorization = `Bearer ${session.accessToken}`;
|
|
22936
|
+
if (session.userId) headers["x-user-id"] = session.userId;
|
|
22937
|
+
}
|
|
22938
|
+
}
|
|
22939
|
+
const controller = opts.timeoutMs && opts.timeoutMs > 0 ? new AbortController() : null;
|
|
22940
|
+
const timer = controller ? setTimeout(() => controller.abort(), opts.timeoutMs) : null;
|
|
22941
|
+
let response;
|
|
22942
|
+
try {
|
|
22943
|
+
response = await fetch(url, {
|
|
22944
|
+
method: "GET",
|
|
22945
|
+
headers,
|
|
22946
|
+
signal: controller?.signal
|
|
22947
|
+
});
|
|
22948
|
+
} catch (err) {
|
|
22949
|
+
throw new ManifestEndpointUnavailableError(
|
|
22950
|
+
void 0,
|
|
22951
|
+
`Hosted manifest endpoint unreachable (${url}): ${err instanceof Error ? err.message : String(err)}`
|
|
22952
|
+
);
|
|
22953
|
+
} finally {
|
|
22954
|
+
if (timer) clearTimeout(timer);
|
|
22955
|
+
}
|
|
22956
|
+
if (response.status === 401 || response.status === 403) {
|
|
22957
|
+
throw new ManifestUnauthenticatedError(
|
|
22958
|
+
`Hosted manifest endpoint returned ${response.status}. Run \`growthub auth login\` to authenticate.`
|
|
22959
|
+
);
|
|
22960
|
+
}
|
|
22961
|
+
if (response.status === 404 || response.status === 501) {
|
|
22962
|
+
throw new ManifestEndpointUnavailableError(
|
|
22963
|
+
response.status,
|
|
22964
|
+
`Hosted manifest endpoint not available (status ${response.status}). The hosted app may not yet expose /api/cms/capabilities.`
|
|
22965
|
+
);
|
|
22966
|
+
}
|
|
22967
|
+
if (!response.ok) {
|
|
22968
|
+
throw new ManifestEndpointUnavailableError(
|
|
22969
|
+
response.status,
|
|
22970
|
+
`Hosted manifest endpoint failed (status ${response.status}).`
|
|
22971
|
+
);
|
|
22972
|
+
}
|
|
22973
|
+
const rawHeader = response.headers.get(CONTRACT_VERSION_HEADER);
|
|
22974
|
+
const serverVersion = parseContractVersionHeader(rawHeader);
|
|
22975
|
+
if (rawHeader === null) {
|
|
22976
|
+
throw new ManifestContractMismatchError(null, CLI_SUPPORTED_CONTRACT_VERSION);
|
|
22977
|
+
}
|
|
22978
|
+
if (serverVersion !== CLI_SUPPORTED_CONTRACT_VERSION) {
|
|
22979
|
+
throw new ManifestContractMismatchError(rawHeader, CLI_SUPPORTED_CONTRACT_VERSION);
|
|
22980
|
+
}
|
|
22981
|
+
let bodyText;
|
|
22982
|
+
try {
|
|
22983
|
+
bodyText = await response.text();
|
|
22984
|
+
} catch (err) {
|
|
22985
|
+
throw new ManifestMalformedError(
|
|
22986
|
+
`Failed to read manifest response body: ${err instanceof Error ? err.message : String(err)}`
|
|
22987
|
+
);
|
|
22988
|
+
}
|
|
22989
|
+
let parsed;
|
|
22990
|
+
try {
|
|
22991
|
+
parsed = JSON.parse(bodyText);
|
|
22992
|
+
} catch (err) {
|
|
22993
|
+
throw new ManifestMalformedError(
|
|
22994
|
+
`Failed to parse manifest JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
22995
|
+
);
|
|
22996
|
+
}
|
|
22997
|
+
const envelope = normalizeEnvelope(parsed);
|
|
22998
|
+
return {
|
|
22999
|
+
envelope,
|
|
23000
|
+
resolvedBaseUrl,
|
|
23001
|
+
serverContractVersion: rawHeader
|
|
23002
|
+
};
|
|
23003
|
+
}
|
|
23004
|
+
|
|
23005
|
+
// src/runtime/cms-manifest-cache/index.ts
|
|
23006
|
+
init_home();
|
|
23007
|
+
import fs30 from "node:fs";
|
|
23008
|
+
import path38 from "node:path";
|
|
23009
|
+
import os9 from "node:os";
|
|
23010
|
+
function resolveManifestCacheDir() {
|
|
23011
|
+
return path38.resolve(resolvePaperclipHomeDir(), "manifests");
|
|
23012
|
+
}
|
|
23013
|
+
function resolveManifestCachePath() {
|
|
23014
|
+
return path38.resolve(resolveManifestCacheDir(), "capabilities.json");
|
|
23015
|
+
}
|
|
23016
|
+
function parseJsonSafe(text69) {
|
|
23017
|
+
try {
|
|
23018
|
+
return JSON.parse(text69);
|
|
23019
|
+
} catch {
|
|
23020
|
+
return null;
|
|
23021
|
+
}
|
|
23022
|
+
}
|
|
23023
|
+
function isValidEnvelopeShape(value) {
|
|
23024
|
+
if (typeof value !== "object" || value === null) return false;
|
|
23025
|
+
const record = value;
|
|
23026
|
+
return record.version === 1 && typeof record.host === "string" && typeof record.fetchedAt === "string" && typeof record.source === "string" && Array.isArray(record.capabilities);
|
|
23027
|
+
}
|
|
23028
|
+
function readManifestCache() {
|
|
23029
|
+
const filePath = resolveManifestCachePath();
|
|
23030
|
+
if (!fs30.existsSync(filePath)) return null;
|
|
23031
|
+
let text69;
|
|
23032
|
+
try {
|
|
23033
|
+
text69 = fs30.readFileSync(filePath, "utf-8");
|
|
23034
|
+
} catch {
|
|
23035
|
+
return null;
|
|
23036
|
+
}
|
|
23037
|
+
const parsed = parseJsonSafe(text69);
|
|
23038
|
+
if (!isValidEnvelopeShape(parsed)) return null;
|
|
23039
|
+
return parsed;
|
|
23040
|
+
}
|
|
23041
|
+
function writeManifestCache(envelope) {
|
|
23042
|
+
const dir = resolveManifestCacheDir();
|
|
23043
|
+
fs30.mkdirSync(dir, { recursive: true });
|
|
23044
|
+
const filePath = resolveManifestCachePath();
|
|
23045
|
+
const tmpPath = path38.join(dir, `.capabilities.${process.pid}.${Date.now()}.tmp`);
|
|
23046
|
+
const body = `${JSON.stringify(envelope, null, 2)}
|
|
23047
|
+
`;
|
|
23048
|
+
fs30.writeFileSync(tmpPath, body, { mode: 420 });
|
|
23049
|
+
try {
|
|
23050
|
+
fs30.renameSync(tmpPath, filePath);
|
|
23051
|
+
} catch (err) {
|
|
23052
|
+
try {
|
|
23053
|
+
fs30.copyFileSync(tmpPath, filePath);
|
|
23054
|
+
fs30.unlinkSync(tmpPath);
|
|
23055
|
+
} catch {
|
|
23056
|
+
throw err;
|
|
23057
|
+
}
|
|
23058
|
+
}
|
|
23059
|
+
return filePath;
|
|
23060
|
+
}
|
|
23061
|
+
function describeManifestCachePath() {
|
|
23062
|
+
const filePath = resolveManifestCachePath();
|
|
23063
|
+
const home = os9.homedir();
|
|
23064
|
+
if (filePath.startsWith(`${home}/`)) {
|
|
23065
|
+
return `~${filePath.slice(home.length)}`;
|
|
23066
|
+
}
|
|
23067
|
+
return filePath;
|
|
23068
|
+
}
|
|
23069
|
+
|
|
23070
|
+
// src/runtime/cms-manifest-projection/index.ts
|
|
23071
|
+
function coerceFamily(value) {
|
|
23072
|
+
const known = CAPABILITY_FAMILIES;
|
|
23073
|
+
if (known.includes(value)) {
|
|
23074
|
+
return value;
|
|
23075
|
+
}
|
|
23076
|
+
return "ops";
|
|
23077
|
+
}
|
|
23078
|
+
function buildManifestMetadata(baseMetadata, entry) {
|
|
23079
|
+
const merged = {
|
|
23080
|
+
...baseMetadata ?? {}
|
|
23081
|
+
};
|
|
23082
|
+
if (entry.inputSchema) merged.inputSchema = entry.inputSchema;
|
|
23083
|
+
if (entry.outputSchema) merged.outputSchema = entry.outputSchema;
|
|
23084
|
+
if (entry.providerHints) merged.providerHints = entry.providerHints;
|
|
23085
|
+
if (entry.executionHints) merged.executionHints = entry.executionHints;
|
|
23086
|
+
merged.__provenance = entry.provenance;
|
|
23087
|
+
return merged;
|
|
23088
|
+
}
|
|
23089
|
+
function projectEntry(entry) {
|
|
23090
|
+
const node = entry.node;
|
|
23091
|
+
const family = coerceFamily(entry.family);
|
|
23092
|
+
return {
|
|
23093
|
+
slug: entry.slug,
|
|
23094
|
+
displayName: node?.displayName ?? entry.displayName,
|
|
23095
|
+
icon: typeof node?.icon === "string" ? node.icon : "",
|
|
23096
|
+
family,
|
|
23097
|
+
category: typeof node?.category === "string" ? node.category : "automation",
|
|
23098
|
+
nodeType: node?.nodeType ?? "tool_execution",
|
|
23099
|
+
executionKind: entry.executionKind,
|
|
23100
|
+
executionBinding: node?.executionBinding ?? {
|
|
23101
|
+
type: "mcp_tool_call",
|
|
23102
|
+
strategy: "direct"
|
|
23103
|
+
},
|
|
23104
|
+
executionTokens: node?.executionTokens ?? {
|
|
23105
|
+
tool_name: entry.slug,
|
|
23106
|
+
input_template: {},
|
|
23107
|
+
output_mapping: {}
|
|
23108
|
+
},
|
|
23109
|
+
requiredBindings: entry.requiredBindings,
|
|
23110
|
+
outputTypes: entry.outputTypes,
|
|
23111
|
+
enabled: typeof node?.enabled === "boolean" ? node.enabled : true,
|
|
23112
|
+
experimental: typeof node?.experimental === "boolean" ? node.experimental : false,
|
|
23113
|
+
visibility: node?.visibility ?? "authenticated",
|
|
23114
|
+
description: typeof node?.description === "string" ? node.description : void 0,
|
|
23115
|
+
manifestMetadata: buildManifestMetadata(node?.manifestMetadata, entry)
|
|
23116
|
+
};
|
|
23117
|
+
}
|
|
23118
|
+
function projectManifestEnvelope(envelope) {
|
|
23119
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23120
|
+
const nodes = [];
|
|
23121
|
+
for (const entry of envelope.capabilities) {
|
|
23122
|
+
if (seen.has(entry.slug)) continue;
|
|
23123
|
+
seen.add(entry.slug);
|
|
23124
|
+
nodes.push(projectEntry(entry));
|
|
23125
|
+
}
|
|
23126
|
+
return {
|
|
23127
|
+
nodes,
|
|
23128
|
+
host: envelope.host,
|
|
23129
|
+
fetchedAt: envelope.fetchedAt,
|
|
23130
|
+
source: envelope.source
|
|
23131
|
+
};
|
|
23132
|
+
}
|
|
23133
|
+
|
|
22752
23134
|
// src/runtime/cms-capability-registry/index.ts
|
|
22753
23135
|
init_session_store();
|
|
22754
23136
|
init_hosted_client();
|
|
@@ -22867,29 +23249,80 @@ function matchesQuery(node, query) {
|
|
|
22867
23249
|
}
|
|
22868
23250
|
return true;
|
|
22869
23251
|
}
|
|
23252
|
+
async function resolveFromManifest() {
|
|
23253
|
+
try {
|
|
23254
|
+
const { envelope } = await fetchCapabilityManifest();
|
|
23255
|
+
writeManifestCache(envelope);
|
|
23256
|
+
const projected = projectManifestEnvelope(envelope);
|
|
23257
|
+
return {
|
|
23258
|
+
kind: "manifest",
|
|
23259
|
+
nodes: projected.nodes,
|
|
23260
|
+
fetchedAt: projected.fetchedAt,
|
|
23261
|
+
stale: false
|
|
23262
|
+
};
|
|
23263
|
+
} catch (err) {
|
|
23264
|
+
if (err instanceof ManifestContractMismatchError || err instanceof ManifestMalformedError) {
|
|
23265
|
+
const cached = readManifestCache();
|
|
23266
|
+
if (cached) {
|
|
23267
|
+
const projected = projectManifestEnvelope(cached);
|
|
23268
|
+
return {
|
|
23269
|
+
kind: "manifest",
|
|
23270
|
+
nodes: projected.nodes,
|
|
23271
|
+
fetchedAt: projected.fetchedAt,
|
|
23272
|
+
stale: true,
|
|
23273
|
+
stalenessReason: err instanceof ManifestContractMismatchError ? `Contract version mismatch (${err.message}); using cached manifest from ${projected.fetchedAt}.` : `Hosted manifest malformed (${err.message}); using cached manifest from ${projected.fetchedAt}.`
|
|
23274
|
+
};
|
|
23275
|
+
}
|
|
23276
|
+
throw err;
|
|
23277
|
+
}
|
|
23278
|
+
if (err instanceof ManifestEndpointUnavailableError || err instanceof ManifestUnauthenticatedError) {
|
|
23279
|
+
const cached = readManifestCache();
|
|
23280
|
+
if (cached) {
|
|
23281
|
+
const projected = projectManifestEnvelope(cached);
|
|
23282
|
+
return {
|
|
23283
|
+
kind: "manifest",
|
|
23284
|
+
nodes: projected.nodes,
|
|
23285
|
+
fetchedAt: projected.fetchedAt,
|
|
23286
|
+
stale: true,
|
|
23287
|
+
stalenessReason: `Hosted manifest unavailable (${err.message}); using cached manifest from ${projected.fetchedAt}.`
|
|
23288
|
+
};
|
|
23289
|
+
}
|
|
23290
|
+
return resolveFromLegacy();
|
|
23291
|
+
}
|
|
23292
|
+
throw err;
|
|
23293
|
+
}
|
|
23294
|
+
}
|
|
23295
|
+
async function resolveFromLegacy() {
|
|
23296
|
+
const executionClient = createHostedExecutionClient();
|
|
23297
|
+
let hostedRecords = await executionClient.getHostedCapabilities();
|
|
23298
|
+
if (hostedRecords.length === 0) {
|
|
23299
|
+
hostedRecords = await deriveCapabilitiesFromHostedWorkflows();
|
|
23300
|
+
}
|
|
23301
|
+
if (hostedRecords.length === 0) {
|
|
23302
|
+
throw new Error(
|
|
23303
|
+
"Hosted capability registry returned zero nodes, cache is empty, and derivation produced nothing."
|
|
23304
|
+
);
|
|
23305
|
+
}
|
|
23306
|
+
return {
|
|
23307
|
+
kind: "legacy",
|
|
23308
|
+
nodes: hostedRecords.map(toCapabilityNode),
|
|
23309
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23310
|
+
};
|
|
23311
|
+
}
|
|
22870
23312
|
function createCmsCapabilityRegistryClient() {
|
|
22871
23313
|
return {
|
|
22872
23314
|
async listCapabilities(query) {
|
|
22873
|
-
const
|
|
22874
|
-
|
|
22875
|
-
if (hostedRecords.length === 0) {
|
|
22876
|
-
hostedRecords = await deriveCapabilitiesFromHostedWorkflows();
|
|
22877
|
-
}
|
|
22878
|
-
if (hostedRecords.length === 0) {
|
|
22879
|
-
throw new Error("Hosted capability registry returned zero nodes. No local fallback is enabled.");
|
|
22880
|
-
}
|
|
22881
|
-
const nodes = hostedRecords.map(toCapabilityNode);
|
|
23315
|
+
const outcome = await resolveFromManifest();
|
|
23316
|
+
const nodes = outcome.nodes;
|
|
22882
23317
|
const enabledCount = nodes.filter((n) => n.enabled).length;
|
|
22883
23318
|
const filtered = query ? nodes.filter((n) => matchesQuery(n, query)) : nodes;
|
|
22884
|
-
|
|
22885
|
-
|
|
22886
|
-
|
|
22887
|
-
|
|
22888
|
-
|
|
22889
|
-
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22890
|
-
source: "hosted"
|
|
22891
|
-
}
|
|
23319
|
+
const meta = {
|
|
23320
|
+
total: nodes.length,
|
|
23321
|
+
enabledCount,
|
|
23322
|
+
fetchedAt: outcome.fetchedAt,
|
|
23323
|
+
source: "hosted"
|
|
22892
23324
|
};
|
|
23325
|
+
return { nodes: filtered, meta };
|
|
22893
23326
|
},
|
|
22894
23327
|
async getCapability(slug) {
|
|
22895
23328
|
const { nodes } = await this.listCapabilities({ slug, enabledOnly: false });
|
|
@@ -22899,10 +23332,10 @@ function createCmsCapabilityRegistryClient() {
|
|
|
22899
23332
|
}
|
|
22900
23333
|
|
|
22901
23334
|
// src/runtime/machine-capability-resolver/index.ts
|
|
22902
|
-
import
|
|
23335
|
+
import os10 from "node:os";
|
|
22903
23336
|
function buildMachineContext(profile) {
|
|
22904
23337
|
return {
|
|
22905
|
-
hostname:
|
|
23338
|
+
hostname: os10.hostname(),
|
|
22906
23339
|
machineLabel: profile.local.machineLabel ?? void 0,
|
|
22907
23340
|
workspaceLabel: profile.local.workspaceLabel ?? void 0,
|
|
22908
23341
|
instanceId: profile.local.instanceId,
|
|
@@ -22987,6 +23420,186 @@ function createMachineCapabilityResolver() {
|
|
|
22987
23420
|
};
|
|
22988
23421
|
}
|
|
22989
23422
|
|
|
23423
|
+
// src/runtime/cms-manifest-diff/index.ts
|
|
23424
|
+
function stableStringify(value) {
|
|
23425
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
23426
|
+
if (Array.isArray(value)) {
|
|
23427
|
+
return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
|
|
23428
|
+
}
|
|
23429
|
+
const record = value;
|
|
23430
|
+
const keys = Object.keys(record).sort();
|
|
23431
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
|
|
23432
|
+
}
|
|
23433
|
+
function arraysEqual(a, b) {
|
|
23434
|
+
if (a.length !== b.length) return false;
|
|
23435
|
+
const aSorted = [...a].sort();
|
|
23436
|
+
const bSorted = [...b].sort();
|
|
23437
|
+
for (let i = 0; i < aSorted.length; i++) {
|
|
23438
|
+
if (aSorted[i] !== bSorted[i]) return false;
|
|
23439
|
+
}
|
|
23440
|
+
return true;
|
|
23441
|
+
}
|
|
23442
|
+
function diffInputSchema(prev, next) {
|
|
23443
|
+
const prevFields = prev.inputSchema?.fields ?? null;
|
|
23444
|
+
const nextFields = next.inputSchema?.fields ?? null;
|
|
23445
|
+
if (prevFields === null && nextFields === null) return null;
|
|
23446
|
+
if (prevFields === null && nextFields !== null) {
|
|
23447
|
+
return `input schema introduced (${nextFields.length} field${nextFields.length === 1 ? "" : "s"})`;
|
|
23448
|
+
}
|
|
23449
|
+
if (prevFields !== null && nextFields === null) {
|
|
23450
|
+
return `input schema removed (was ${prevFields.length} field${prevFields.length === 1 ? "" : "s"})`;
|
|
23451
|
+
}
|
|
23452
|
+
const prevKeys = new Set((prevFields ?? []).map((f) => f.key));
|
|
23453
|
+
const nextKeys = new Set((nextFields ?? []).map((f) => f.key));
|
|
23454
|
+
const added = [];
|
|
23455
|
+
for (const key of nextKeys) if (!prevKeys.has(key)) added.push(key);
|
|
23456
|
+
const removed = [];
|
|
23457
|
+
for (const key of prevKeys) if (!nextKeys.has(key)) removed.push(key);
|
|
23458
|
+
const changed = [];
|
|
23459
|
+
for (const field of nextFields ?? []) {
|
|
23460
|
+
const prior = (prevFields ?? []).find((f) => f.key === field.key);
|
|
23461
|
+
if (!prior) continue;
|
|
23462
|
+
if (stableStringify(prior) !== stableStringify(field)) changed.push(field.key);
|
|
23463
|
+
}
|
|
23464
|
+
if (added.length === 0 && removed.length === 0 && changed.length === 0) return null;
|
|
23465
|
+
const parts = [];
|
|
23466
|
+
if (added.length > 0) parts.push(`+${added.join(", +")}`);
|
|
23467
|
+
if (removed.length > 0) parts.push(`-${removed.join(", -")}`);
|
|
23468
|
+
if (changed.length > 0) parts.push(`~${changed.join(", ~")}`);
|
|
23469
|
+
return `input schema fields ${parts.join(" ")}`;
|
|
23470
|
+
}
|
|
23471
|
+
function diffOutputSchema(prev, next) {
|
|
23472
|
+
const prevFields = prev.outputSchema?.outputs ?? null;
|
|
23473
|
+
const nextFields = next.outputSchema?.outputs ?? null;
|
|
23474
|
+
if (prevFields === null && nextFields === null) return null;
|
|
23475
|
+
if (stableStringify(prevFields) === stableStringify(nextFields)) return null;
|
|
23476
|
+
const prevKeys = new Set((prevFields ?? []).map((f) => f.key));
|
|
23477
|
+
const nextKeys = new Set((nextFields ?? []).map((f) => f.key));
|
|
23478
|
+
const added = [];
|
|
23479
|
+
for (const key of nextKeys) if (!prevKeys.has(key)) added.push(key);
|
|
23480
|
+
const removed = [];
|
|
23481
|
+
for (const key of prevKeys) if (!nextKeys.has(key)) removed.push(key);
|
|
23482
|
+
const parts = [];
|
|
23483
|
+
if (added.length > 0) parts.push(`+${added.join(", +")}`);
|
|
23484
|
+
if (removed.length > 0) parts.push(`-${removed.join(", -")}`);
|
|
23485
|
+
if (parts.length === 0) parts.push("reshuffled");
|
|
23486
|
+
return `output schema ${parts.join(" ")}`;
|
|
23487
|
+
}
|
|
23488
|
+
function diffExecutionTokens(prev, next) {
|
|
23489
|
+
const prevTokens = prev.node?.executionTokens;
|
|
23490
|
+
const nextTokens = next.node?.executionTokens;
|
|
23491
|
+
if (!prevTokens && !nextTokens) return null;
|
|
23492
|
+
const diffs = [];
|
|
23493
|
+
if (prevTokens?.tool_name !== nextTokens?.tool_name) {
|
|
23494
|
+
diffs.push(`tool_name ${prevTokens?.tool_name ?? "\u2205"} \u2192 ${nextTokens?.tool_name ?? "\u2205"}`);
|
|
23495
|
+
}
|
|
23496
|
+
if (stableStringify(prevTokens?.input_template ?? {}) !== stableStringify(nextTokens?.input_template ?? {})) {
|
|
23497
|
+
diffs.push("input_template changed");
|
|
23498
|
+
}
|
|
23499
|
+
if (stableStringify(prevTokens?.output_mapping ?? {}) !== stableStringify(nextTokens?.output_mapping ?? {})) {
|
|
23500
|
+
diffs.push("output_mapping changed");
|
|
23501
|
+
}
|
|
23502
|
+
if (diffs.length === 0) return null;
|
|
23503
|
+
return `execution tokens: ${diffs.join("; ")}`;
|
|
23504
|
+
}
|
|
23505
|
+
function diffProvenance(prev, next) {
|
|
23506
|
+
const prevOrigin = prev.provenance?.originType;
|
|
23507
|
+
const nextOrigin = next.provenance?.originType;
|
|
23508
|
+
if (prevOrigin === nextOrigin) return null;
|
|
23509
|
+
return `provenance.originType ${prevOrigin ?? "\u2205"} \u2192 ${nextOrigin ?? "\u2205"}`;
|
|
23510
|
+
}
|
|
23511
|
+
function diffManifestEnvelopes(prev, next, opts = {}) {
|
|
23512
|
+
const comparedAt = opts.comparedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
23513
|
+
const markers = [];
|
|
23514
|
+
const changeDetails = {};
|
|
23515
|
+
const prevBySlug = /* @__PURE__ */ new Map();
|
|
23516
|
+
if (prev) {
|
|
23517
|
+
for (const entry of prev.capabilities) prevBySlug.set(entry.slug, entry);
|
|
23518
|
+
}
|
|
23519
|
+
const nextBySlug = /* @__PURE__ */ new Map();
|
|
23520
|
+
for (const entry of next.capabilities) nextBySlug.set(entry.slug, entry);
|
|
23521
|
+
const added = [];
|
|
23522
|
+
const removed = [];
|
|
23523
|
+
const changed = [];
|
|
23524
|
+
for (const [slug] of nextBySlug) {
|
|
23525
|
+
if (!prevBySlug.has(slug)) {
|
|
23526
|
+
added.push(slug);
|
|
23527
|
+
markers.push({ slug, change: "added" });
|
|
23528
|
+
}
|
|
23529
|
+
}
|
|
23530
|
+
for (const [slug] of prevBySlug) {
|
|
23531
|
+
if (!nextBySlug.has(slug)) {
|
|
23532
|
+
removed.push(slug);
|
|
23533
|
+
markers.push({ slug, change: "removed" });
|
|
23534
|
+
}
|
|
23535
|
+
}
|
|
23536
|
+
for (const [slug, nextEntry] of nextBySlug) {
|
|
23537
|
+
const prevEntry = prevBySlug.get(slug);
|
|
23538
|
+
if (!prevEntry) continue;
|
|
23539
|
+
const slugChanges = [];
|
|
23540
|
+
if (prevEntry.family !== nextEntry.family) {
|
|
23541
|
+
const description = `family ${prevEntry.family} \u2192 ${nextEntry.family}`;
|
|
23542
|
+
markers.push({ slug, change: "schema", description });
|
|
23543
|
+
slugChanges.push(description);
|
|
23544
|
+
}
|
|
23545
|
+
if (prevEntry.executionKind !== nextEntry.executionKind) {
|
|
23546
|
+
const description = `executionKind ${prevEntry.executionKind} \u2192 ${nextEntry.executionKind}`;
|
|
23547
|
+
markers.push({ slug, change: "executionKind", description });
|
|
23548
|
+
slugChanges.push(description);
|
|
23549
|
+
}
|
|
23550
|
+
if (!arraysEqual(prevEntry.requiredBindings, nextEntry.requiredBindings)) {
|
|
23551
|
+
const description = `requiredBindings [${prevEntry.requiredBindings.join(", ")}] \u2192 [${nextEntry.requiredBindings.join(", ")}]`;
|
|
23552
|
+
markers.push({ slug, change: "requiredBindings", description });
|
|
23553
|
+
slugChanges.push(description);
|
|
23554
|
+
}
|
|
23555
|
+
if (!arraysEqual(prevEntry.outputTypes, nextEntry.outputTypes)) {
|
|
23556
|
+
const description = `outputTypes [${prevEntry.outputTypes.join(", ")}] \u2192 [${nextEntry.outputTypes.join(", ")}]`;
|
|
23557
|
+
markers.push({ slug, change: "outputTypes", description });
|
|
23558
|
+
slugChanges.push(description);
|
|
23559
|
+
}
|
|
23560
|
+
const prevEnabled = prevEntry.node?.enabled;
|
|
23561
|
+
const nextEnabled = nextEntry.node?.enabled;
|
|
23562
|
+
if (prevEnabled !== nextEnabled) {
|
|
23563
|
+
const description = `enabled ${String(prevEnabled)} \u2192 ${String(nextEnabled)}`;
|
|
23564
|
+
markers.push({ slug, change: "enabled", description });
|
|
23565
|
+
slugChanges.push(description);
|
|
23566
|
+
}
|
|
23567
|
+
const tokensDiff = diffExecutionTokens(prevEntry, nextEntry);
|
|
23568
|
+
if (tokensDiff) {
|
|
23569
|
+
markers.push({ slug, change: "schema", description: tokensDiff });
|
|
23570
|
+
slugChanges.push(tokensDiff);
|
|
23571
|
+
}
|
|
23572
|
+
const inputSchemaDiff = diffInputSchema(prevEntry, nextEntry);
|
|
23573
|
+
if (inputSchemaDiff) {
|
|
23574
|
+
markers.push({ slug, change: "schema", description: inputSchemaDiff });
|
|
23575
|
+
slugChanges.push(inputSchemaDiff);
|
|
23576
|
+
}
|
|
23577
|
+
const outputSchemaDiff = diffOutputSchema(prevEntry, nextEntry);
|
|
23578
|
+
if (outputSchemaDiff) {
|
|
23579
|
+
markers.push({ slug, change: "schema", description: outputSchemaDiff });
|
|
23580
|
+
slugChanges.push(outputSchemaDiff);
|
|
23581
|
+
}
|
|
23582
|
+
const provenanceDiff = diffProvenance(prevEntry, nextEntry);
|
|
23583
|
+
if (provenanceDiff) {
|
|
23584
|
+
markers.push({ slug, change: "schema", description: provenanceDiff });
|
|
23585
|
+
slugChanges.push(provenanceDiff);
|
|
23586
|
+
}
|
|
23587
|
+
if (slugChanges.length > 0) {
|
|
23588
|
+
changed.push(slug);
|
|
23589
|
+
changeDetails[slug] = slugChanges;
|
|
23590
|
+
}
|
|
23591
|
+
}
|
|
23592
|
+
const report = { comparedAt, markers };
|
|
23593
|
+
return {
|
|
23594
|
+
added: added.sort(),
|
|
23595
|
+
removed: removed.sort(),
|
|
23596
|
+
changed: changed.sort(),
|
|
23597
|
+
changeDetails,
|
|
23598
|
+
markers,
|
|
23599
|
+
report
|
|
23600
|
+
};
|
|
23601
|
+
}
|
|
23602
|
+
|
|
22990
23603
|
// src/auth/workflow-access.ts
|
|
22991
23604
|
function getWorkflowAccess() {
|
|
22992
23605
|
const profile = computeEffectiveProfile();
|
|
@@ -23218,6 +23831,7 @@ Examples:
|
|
|
23218
23831
|
$ growthub capability list --json # machine-readable output
|
|
23219
23832
|
$ growthub capability inspect video-gen # inspect a specific capability
|
|
23220
23833
|
$ growthub capability resolve # resolve machine bindings for all
|
|
23834
|
+
$ growthub capability refresh # sync hosted CMS manifest and diff
|
|
23221
23835
|
`);
|
|
23222
23836
|
cap.action(async () => {
|
|
23223
23837
|
await runCapabilityPicker({});
|
|
@@ -23316,13 +23930,206 @@ Examples:
|
|
|
23316
23930
|
process.exitCode = 1;
|
|
23317
23931
|
}
|
|
23318
23932
|
});
|
|
23933
|
+
cap.command("refresh").description("Sync the canonical hosted CMS capability manifest and diff against the local cache").option("--base-url <url>", "Hosted Growthub base URL (defaults to session / env / config / https://www.growthub.ai)").option("--json", "Output raw JSON for scripting").option("--include-experimental", "Include experimental capabilities in the summary rendering").option("--include-disabled", "Include disabled capabilities in the summary rendering").action(async (opts) => {
|
|
23934
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23935
|
+
const cachePath = resolveManifestCachePath();
|
|
23936
|
+
const describedCachePath = describeManifestCachePath();
|
|
23937
|
+
let fetchResult;
|
|
23938
|
+
try {
|
|
23939
|
+
fetchResult = await fetchCapabilityManifest({ explicit: opts.baseUrl });
|
|
23940
|
+
} catch (err) {
|
|
23941
|
+
const prior2 = readManifestCache();
|
|
23942
|
+
if (err instanceof ManifestContractMismatchError) {
|
|
23943
|
+
if (prior2) {
|
|
23944
|
+
if (opts.json) {
|
|
23945
|
+
console.log(JSON.stringify({
|
|
23946
|
+
status: "contract_mismatch_using_cache",
|
|
23947
|
+
error: { code: err.code, message: err.message },
|
|
23948
|
+
cache: {
|
|
23949
|
+
host: prior2.host,
|
|
23950
|
+
fetchedAt: prior2.fetchedAt,
|
|
23951
|
+
total: prior2.capabilities.length,
|
|
23952
|
+
path: cachePath
|
|
23953
|
+
}
|
|
23954
|
+
}, null, 2));
|
|
23955
|
+
} else {
|
|
23956
|
+
console.error(pc32.yellow(`\u26A0 Contract version mismatch: ${err.message}`));
|
|
23957
|
+
console.error(pc32.dim(` Using cached manifest from ${prior2.fetchedAt} (${prior2.capabilities.length} capabilities).`));
|
|
23958
|
+
console.error(pc32.dim(` Cache: ${describedCachePath}`));
|
|
23959
|
+
console.error(pc32.dim(" Hosted manifest was NOT overwritten. Run `growthub upgrade` or re-login if the contract version is supposed to match."));
|
|
23960
|
+
}
|
|
23961
|
+
process.exitCode = 0;
|
|
23962
|
+
return;
|
|
23963
|
+
}
|
|
23964
|
+
reportRefreshError(err, opts.json, describedCachePath);
|
|
23965
|
+
process.exitCode = 1;
|
|
23966
|
+
return;
|
|
23967
|
+
}
|
|
23968
|
+
if (err instanceof ManifestMalformedError) {
|
|
23969
|
+
if (prior2) {
|
|
23970
|
+
if (opts.json) {
|
|
23971
|
+
console.log(JSON.stringify({
|
|
23972
|
+
status: "malformed_using_cache",
|
|
23973
|
+
error: { code: err.code, message: err.message },
|
|
23974
|
+
cache: {
|
|
23975
|
+
host: prior2.host,
|
|
23976
|
+
fetchedAt: prior2.fetchedAt,
|
|
23977
|
+
total: prior2.capabilities.length,
|
|
23978
|
+
path: cachePath
|
|
23979
|
+
}
|
|
23980
|
+
}, null, 2));
|
|
23981
|
+
} else {
|
|
23982
|
+
console.error(pc32.yellow(`\u26A0 Hosted manifest was malformed: ${err.message}`));
|
|
23983
|
+
console.error(pc32.dim(` Using cached manifest from ${prior2.fetchedAt} (${prior2.capabilities.length} capabilities).`));
|
|
23984
|
+
console.error(pc32.dim(` Cache: ${describedCachePath}`));
|
|
23985
|
+
}
|
|
23986
|
+
process.exitCode = 0;
|
|
23987
|
+
return;
|
|
23988
|
+
}
|
|
23989
|
+
reportRefreshError(err, opts.json, describedCachePath);
|
|
23990
|
+
process.exitCode = 1;
|
|
23991
|
+
return;
|
|
23992
|
+
}
|
|
23993
|
+
if (err instanceof ManifestEndpointUnavailableError || err instanceof ManifestUnauthenticatedError) {
|
|
23994
|
+
reportRefreshError(err, opts.json, describedCachePath);
|
|
23995
|
+
process.exitCode = 1;
|
|
23996
|
+
return;
|
|
23997
|
+
}
|
|
23998
|
+
reportRefreshError(err, opts.json, describedCachePath);
|
|
23999
|
+
process.exitCode = 1;
|
|
24000
|
+
return;
|
|
24001
|
+
}
|
|
24002
|
+
const { envelope, resolvedBaseUrl, serverContractVersion } = fetchResult;
|
|
24003
|
+
const prior = readManifestCache();
|
|
24004
|
+
const diffSummary = diffManifestEnvelopes(prior, envelope, { comparedAt: startedAt });
|
|
24005
|
+
try {
|
|
24006
|
+
writeManifestCache(envelope);
|
|
24007
|
+
} catch (writeErr) {
|
|
24008
|
+
const message = writeErr instanceof Error ? writeErr.message : String(writeErr);
|
|
24009
|
+
if (opts.json) {
|
|
24010
|
+
console.log(JSON.stringify({
|
|
24011
|
+
status: "fetched_but_cache_write_failed",
|
|
24012
|
+
error: message,
|
|
24013
|
+
host: envelope.host,
|
|
24014
|
+
fetchedAt: envelope.fetchedAt,
|
|
24015
|
+
total: envelope.capabilities.length,
|
|
24016
|
+
cachePath
|
|
24017
|
+
}, null, 2));
|
|
24018
|
+
} else {
|
|
24019
|
+
console.error(pc32.yellow(`\u26A0 Manifest fetched but cache write failed: ${message}`));
|
|
24020
|
+
console.error(pc32.dim(` Cache path: ${describedCachePath}`));
|
|
24021
|
+
}
|
|
24022
|
+
process.exitCode = 1;
|
|
24023
|
+
return;
|
|
24024
|
+
}
|
|
24025
|
+
if (opts.json) {
|
|
24026
|
+
console.log(JSON.stringify({
|
|
24027
|
+
status: "ok",
|
|
24028
|
+
host: envelope.host,
|
|
24029
|
+
resolvedBaseUrl: resolvedBaseUrl.baseUrl,
|
|
24030
|
+
resolvedBaseUrlSource: resolvedBaseUrl.source,
|
|
24031
|
+
fetchedAt: envelope.fetchedAt,
|
|
24032
|
+
contractVersion: serverContractVersion,
|
|
24033
|
+
total: envelope.capabilities.length,
|
|
24034
|
+
added: diffSummary.added,
|
|
24035
|
+
removed: diffSummary.removed,
|
|
24036
|
+
changed: diffSummary.changed,
|
|
24037
|
+
changeDetails: diffSummary.changeDetails,
|
|
24038
|
+
drift: diffSummary.report,
|
|
24039
|
+
cachePath
|
|
24040
|
+
}, null, 2));
|
|
24041
|
+
return;
|
|
24042
|
+
}
|
|
24043
|
+
printRefreshSummary({
|
|
24044
|
+
envelope,
|
|
24045
|
+
diff: diffSummary,
|
|
24046
|
+
resolvedBaseUrl: resolvedBaseUrl.baseUrl,
|
|
24047
|
+
resolvedBaseUrlSource: resolvedBaseUrl.source,
|
|
24048
|
+
cachePath: describedCachePath,
|
|
24049
|
+
serverContractVersion,
|
|
24050
|
+
includeExperimental: opts.includeExperimental === true,
|
|
24051
|
+
includeDisabled: opts.includeDisabled === true
|
|
24052
|
+
});
|
|
24053
|
+
});
|
|
24054
|
+
}
|
|
24055
|
+
function reportRefreshError(err, json, describedCachePath) {
|
|
24056
|
+
if (json) {
|
|
24057
|
+
const payload = err instanceof ManifestClientError ? { status: "error", code: err.code, message: err.message } : { status: "error", code: "UNKNOWN", message: err instanceof Error ? err.message : String(err) };
|
|
24058
|
+
console.log(JSON.stringify({ ...payload, cachePath: describedCachePath }, null, 2));
|
|
24059
|
+
return;
|
|
24060
|
+
}
|
|
24061
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
24062
|
+
if (err instanceof ManifestUnauthenticatedError) {
|
|
24063
|
+
console.error(pc32.red("\u2717 Not authenticated: ") + message);
|
|
24064
|
+
} else if (err instanceof ManifestEndpointUnavailableError) {
|
|
24065
|
+
console.error(pc32.red("\u2717 Hosted manifest endpoint unavailable: ") + message);
|
|
24066
|
+
} else if (err instanceof ManifestContractMismatchError) {
|
|
24067
|
+
console.error(pc32.red("\u2717 Contract version mismatch: ") + message);
|
|
24068
|
+
console.error(pc32.dim(" No local cache is present to fall back on."));
|
|
24069
|
+
} else if (err instanceof ManifestMalformedError) {
|
|
24070
|
+
console.error(pc32.red("\u2717 Hosted manifest malformed: ") + message);
|
|
24071
|
+
console.error(pc32.dim(" No local cache is present to fall back on."));
|
|
24072
|
+
} else {
|
|
24073
|
+
console.error(pc32.red("\u2717 Failed to refresh manifest: ") + message);
|
|
24074
|
+
}
|
|
24075
|
+
console.error(pc32.dim(` Cache path: ${describedCachePath}`));
|
|
24076
|
+
}
|
|
24077
|
+
function printRefreshSummary(args) {
|
|
24078
|
+
const { envelope, diff, resolvedBaseUrl, resolvedBaseUrlSource, cachePath, serverContractVersion } = args;
|
|
24079
|
+
const { added, removed, changed, changeDetails } = diff;
|
|
24080
|
+
console.log("");
|
|
24081
|
+
console.log(pc32.bold("CMS Capability Manifest \u2014 Refresh"));
|
|
24082
|
+
console.log(hr4());
|
|
24083
|
+
console.log(` ${pc32.dim("Host:")} ${envelope.host}`);
|
|
24084
|
+
console.log(` ${pc32.dim("Resolved base:")} ${resolvedBaseUrl} ${pc32.dim(`(${resolvedBaseUrlSource})`)}`);
|
|
24085
|
+
console.log(` ${pc32.dim("Fetched at:")} ${envelope.fetchedAt}`);
|
|
24086
|
+
if (serverContractVersion !== null) {
|
|
24087
|
+
console.log(` ${pc32.dim("Contract version:")} ${serverContractVersion}`);
|
|
24088
|
+
}
|
|
24089
|
+
console.log(` ${pc32.dim("Source:")} ${envelope.source}`);
|
|
24090
|
+
console.log(` ${pc32.dim("Total:")} ${envelope.capabilities.length}`);
|
|
24091
|
+
console.log(` ${pc32.dim("Added:")} ${added.length > 0 ? pc32.green(String(added.length)) : pc32.dim("0")}`);
|
|
24092
|
+
console.log(` ${pc32.dim("Removed:")} ${removed.length > 0 ? pc32.red(String(removed.length)) : pc32.dim("0")}`);
|
|
24093
|
+
console.log(` ${pc32.dim("Changed:")} ${changed.length > 0 ? pc32.yellow(String(changed.length)) : pc32.dim("0")}`);
|
|
24094
|
+
console.log(` ${pc32.dim("Cache:")} ${cachePath}`);
|
|
24095
|
+
console.log(hr4());
|
|
24096
|
+
if (added.length > 0) {
|
|
24097
|
+
console.log(pc32.green("\n + Added"));
|
|
24098
|
+
for (const slug of added) {
|
|
24099
|
+
const entry = envelope.capabilities.find((c) => c.slug === slug);
|
|
24100
|
+
const label = entry?.displayName ? pc32.dim(` ${entry.displayName}`) : "";
|
|
24101
|
+
console.log(` ${pc32.bold(slug)}${label}`);
|
|
24102
|
+
}
|
|
24103
|
+
}
|
|
24104
|
+
if (removed.length > 0) {
|
|
24105
|
+
console.log(pc32.red("\n \u2212 Removed"));
|
|
24106
|
+
for (const slug of removed) {
|
|
24107
|
+
console.log(` ${pc32.bold(slug)}`);
|
|
24108
|
+
}
|
|
24109
|
+
}
|
|
24110
|
+
if (changed.length > 0) {
|
|
24111
|
+
console.log(pc32.yellow("\n ~ Changed"));
|
|
24112
|
+
for (const slug of changed) {
|
|
24113
|
+
console.log(` ${pc32.bold(slug)}`);
|
|
24114
|
+
for (const detail of changeDetails[slug] ?? []) {
|
|
24115
|
+
console.log(` ${pc32.dim("\xB7")} ${pc32.dim(detail)}`);
|
|
24116
|
+
}
|
|
24117
|
+
}
|
|
24118
|
+
}
|
|
24119
|
+
if (added.length === 0 && removed.length === 0 && changed.length === 0) {
|
|
24120
|
+
console.log(pc32.dim("\n No drift detected since the last cached manifest."));
|
|
24121
|
+
}
|
|
24122
|
+
console.log("");
|
|
24123
|
+
console.log(pc32.dim(" growthub capability list # browse refreshed registry"));
|
|
24124
|
+
console.log(pc32.dim(" growthub capability inspect <slug>"));
|
|
24125
|
+
console.log("");
|
|
23319
24126
|
}
|
|
23320
24127
|
|
|
23321
24128
|
// src/commands/pipeline.ts
|
|
23322
24129
|
init_session_store();
|
|
23323
24130
|
init_hosted_client();
|
|
23324
|
-
import
|
|
23325
|
-
import
|
|
24131
|
+
import fs34 from "node:fs";
|
|
24132
|
+
import path42 from "node:path";
|
|
23326
24133
|
import * as p22 from "@clack/prompts";
|
|
23327
24134
|
import pc34 from "picocolors";
|
|
23328
24135
|
|
|
@@ -23517,10 +24324,53 @@ function outputTypeFromSchema(value) {
|
|
|
23517
24324
|
function humanizeFieldKey(key) {
|
|
23518
24325
|
return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/^\w/, (c) => c.toUpperCase());
|
|
23519
24326
|
}
|
|
24327
|
+
function nodeInputFieldTypeToContractType(field) {
|
|
24328
|
+
switch (field.fieldType) {
|
|
24329
|
+
case "text":
|
|
24330
|
+
case "long-text":
|
|
24331
|
+
case "select":
|
|
24332
|
+
case "url":
|
|
24333
|
+
case "file":
|
|
24334
|
+
case "url-or-file":
|
|
24335
|
+
return "string";
|
|
24336
|
+
case "number":
|
|
24337
|
+
return "number";
|
|
24338
|
+
case "boolean":
|
|
24339
|
+
return "boolean";
|
|
24340
|
+
case "array":
|
|
24341
|
+
return "array";
|
|
24342
|
+
case "json":
|
|
24343
|
+
return "object";
|
|
24344
|
+
default:
|
|
24345
|
+
return "unknown";
|
|
24346
|
+
}
|
|
24347
|
+
}
|
|
24348
|
+
function projectHostedInputField(field) {
|
|
24349
|
+
return {
|
|
24350
|
+
key: field.key,
|
|
24351
|
+
label: field.label?.trim() ? field.label : humanizeFieldKey(field.key),
|
|
24352
|
+
type: nodeInputFieldTypeToContractType(field),
|
|
24353
|
+
required: field.required === true,
|
|
24354
|
+
defaultValue: field.defaultValue
|
|
24355
|
+
};
|
|
24356
|
+
}
|
|
24357
|
+
function extractHostedInputSchema(node) {
|
|
24358
|
+
const schema = node.manifestMetadata?.inputSchema;
|
|
24359
|
+
if (!schema || typeof schema !== "object") return null;
|
|
24360
|
+
const fields = schema.fields;
|
|
24361
|
+
if (!Array.isArray(fields)) return null;
|
|
24362
|
+
return schema;
|
|
24363
|
+
}
|
|
23520
24364
|
function introspectNodeContract(node) {
|
|
23521
24365
|
const inputTemplate = node.executionTokens.input_template ?? {};
|
|
23522
24366
|
const outputMapping = node.executionTokens.output_mapping ?? {};
|
|
23523
|
-
const
|
|
24367
|
+
const hostedSchema = extractHostedInputSchema(node);
|
|
24368
|
+
const hostedFields = hostedSchema?.fields ?? [];
|
|
24369
|
+
const hostedByKey = new Map(
|
|
24370
|
+
hostedFields.map((field) => [field.key, field])
|
|
24371
|
+
);
|
|
24372
|
+
const hostedContracts = hostedFields.map(projectHostedInputField);
|
|
24373
|
+
const heuristicContracts = Object.entries(inputTemplate).filter(([key]) => !hostedByKey.has(key)).map(([key, value]) => {
|
|
23524
24374
|
const required = value === "" || value === null || value === void 0;
|
|
23525
24375
|
return {
|
|
23526
24376
|
key,
|
|
@@ -23530,6 +24380,7 @@ function introspectNodeContract(node) {
|
|
|
23530
24380
|
defaultValue: value
|
|
23531
24381
|
};
|
|
23532
24382
|
});
|
|
24383
|
+
const inputs = [...hostedContracts, ...heuristicContracts];
|
|
23533
24384
|
const outputs = Object.entries(outputMapping).map(([key, value]) => ({
|
|
23534
24385
|
key,
|
|
23535
24386
|
type: outputTypeFromSchema(value),
|
|
@@ -23832,40 +24683,40 @@ function renderPreSaveReview(input) {
|
|
|
23832
24683
|
|
|
23833
24684
|
// src/runtime/artifact-contracts/index.ts
|
|
23834
24685
|
init_home();
|
|
23835
|
-
import
|
|
23836
|
-
import
|
|
24686
|
+
import fs31 from "node:fs";
|
|
24687
|
+
import path39 from "node:path";
|
|
23837
24688
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
23838
24689
|
function generateArtifactId() {
|
|
23839
24690
|
return `art_${randomBytes7(8).toString("hex")}`;
|
|
23840
24691
|
}
|
|
23841
24692
|
function resolveArtifactsDir() {
|
|
23842
|
-
return
|
|
24693
|
+
return path39.resolve(resolvePaperclipHomeDir(), "artifacts");
|
|
23843
24694
|
}
|
|
23844
24695
|
function resolveArtifactManifestPath(artifactId) {
|
|
23845
|
-
return
|
|
24696
|
+
return path39.resolve(resolveArtifactsDir(), `${artifactId}.json`);
|
|
23846
24697
|
}
|
|
23847
24698
|
function readLocalManifest(artifactId) {
|
|
23848
24699
|
const filePath = resolveArtifactManifestPath(artifactId);
|
|
23849
|
-
if (!
|
|
24700
|
+
if (!fs31.existsSync(filePath)) return null;
|
|
23850
24701
|
try {
|
|
23851
|
-
return JSON.parse(
|
|
24702
|
+
return JSON.parse(fs31.readFileSync(filePath, "utf-8"));
|
|
23852
24703
|
} catch {
|
|
23853
24704
|
return null;
|
|
23854
24705
|
}
|
|
23855
24706
|
}
|
|
23856
24707
|
function writeLocalManifest(manifest) {
|
|
23857
24708
|
const dir = resolveArtifactsDir();
|
|
23858
|
-
|
|
24709
|
+
fs31.mkdirSync(dir, { recursive: true });
|
|
23859
24710
|
const filePath = resolveArtifactManifestPath(manifest.id);
|
|
23860
|
-
|
|
24711
|
+
fs31.writeFileSync(filePath, `${JSON.stringify(manifest, null, 2)}
|
|
23861
24712
|
`, { mode: 384 });
|
|
23862
24713
|
}
|
|
23863
24714
|
function listLocalManifests() {
|
|
23864
24715
|
const dir = resolveArtifactsDir();
|
|
23865
|
-
if (!
|
|
23866
|
-
return
|
|
24716
|
+
if (!fs31.existsSync(dir)) return [];
|
|
24717
|
+
return fs31.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => {
|
|
23867
24718
|
try {
|
|
23868
|
-
const content =
|
|
24719
|
+
const content = fs31.readFileSync(path39.resolve(dir, entry.name), "utf-8");
|
|
23869
24720
|
return JSON.parse(content);
|
|
23870
24721
|
} catch {
|
|
23871
24722
|
return null;
|
|
@@ -23943,8 +24794,8 @@ function createArtifactStore() {
|
|
|
23943
24794
|
|
|
23944
24795
|
// src/runtime/native-intelligence/index.ts
|
|
23945
24796
|
init_home();
|
|
23946
|
-
import
|
|
23947
|
-
import
|
|
24797
|
+
import fs33 from "node:fs";
|
|
24798
|
+
import path41 from "node:path";
|
|
23948
24799
|
|
|
23949
24800
|
// src/runtime/native-intelligence/contract.ts
|
|
23950
24801
|
var DEFAULT_INTELLIGENCE_CONFIG = {
|
|
@@ -24337,7 +25188,7 @@ async function summarizeExecution2(input, backend) {
|
|
|
24337
25188
|
maxTokens: 2048,
|
|
24338
25189
|
responseFormat: "json"
|
|
24339
25190
|
});
|
|
24340
|
-
const parsed =
|
|
25191
|
+
const parsed = parseJsonSafe2(completion.text);
|
|
24341
25192
|
if (parsed) {
|
|
24342
25193
|
return validateSummaryResult(parsed);
|
|
24343
25194
|
}
|
|
@@ -24455,7 +25306,7 @@ function buildSummarizerPrompt(input) {
|
|
|
24455
25306
|
}
|
|
24456
25307
|
return sections.join("\n");
|
|
24457
25308
|
}
|
|
24458
|
-
function
|
|
25309
|
+
function parseJsonSafe2(text69) {
|
|
24459
25310
|
try {
|
|
24460
25311
|
const trimmed = text69.trim();
|
|
24461
25312
|
const jsonStart = trimmed.indexOf("{");
|
|
@@ -24524,7 +25375,7 @@ async function intelligentNormalizeBindings(input, backend) {
|
|
|
24524
25375
|
maxTokens: 2048,
|
|
24525
25376
|
responseFormat: "json"
|
|
24526
25377
|
});
|
|
24527
|
-
const parsed =
|
|
25378
|
+
const parsed = parseJsonSafe3(completion.text);
|
|
24528
25379
|
if (parsed) {
|
|
24529
25380
|
return toNormalizationResult(parsed, input);
|
|
24530
25381
|
}
|
|
@@ -24709,7 +25560,7 @@ function validateAction(action) {
|
|
|
24709
25560
|
}
|
|
24710
25561
|
return "kept";
|
|
24711
25562
|
}
|
|
24712
|
-
function
|
|
25563
|
+
function parseJsonSafe3(text69) {
|
|
24713
25564
|
try {
|
|
24714
25565
|
const trimmed = text69.trim();
|
|
24715
25566
|
const jsonStart = trimmed.indexOf("{");
|
|
@@ -24775,7 +25626,7 @@ async function recommendWorkflow(input, backend) {
|
|
|
24775
25626
|
maxTokens: 2048,
|
|
24776
25627
|
responseFormat: "json"
|
|
24777
25628
|
});
|
|
24778
|
-
const parsed =
|
|
25629
|
+
const parsed = parseJsonSafe4(completion.text);
|
|
24779
25630
|
if (parsed) {
|
|
24780
25631
|
return validateRecommendationResult(parsed, input);
|
|
24781
25632
|
}
|
|
@@ -24952,7 +25803,7 @@ function validateStrategy(strategy) {
|
|
|
24952
25803
|
}
|
|
24953
25804
|
return "synthesize-new";
|
|
24954
25805
|
}
|
|
24955
|
-
function
|
|
25806
|
+
function parseJsonSafe4(text69) {
|
|
24956
25807
|
try {
|
|
24957
25808
|
const trimmed = text69.trim();
|
|
24958
25809
|
const jsonStart = trimmed.indexOf("{");
|
|
@@ -25011,7 +25862,7 @@ async function planWorkflow(input, backend) {
|
|
|
25011
25862
|
maxTokens: 3072,
|
|
25012
25863
|
responseFormat: "json"
|
|
25013
25864
|
});
|
|
25014
|
-
const parsed =
|
|
25865
|
+
const parsed = parseJsonSafe5(completion.text);
|
|
25015
25866
|
if (parsed) {
|
|
25016
25867
|
return validatePlanningResult(parsed, input);
|
|
25017
25868
|
}
|
|
@@ -25200,7 +26051,7 @@ function validatePlanningResult(raw, input) {
|
|
|
25200
26051
|
warnings
|
|
25201
26052
|
};
|
|
25202
26053
|
}
|
|
25203
|
-
function
|
|
26054
|
+
function parseJsonSafe5(text69) {
|
|
25204
26055
|
try {
|
|
25205
26056
|
const trimmed = text69.trim();
|
|
25206
26057
|
const jsonStart = trimmed.indexOf("{");
|
|
@@ -25215,8 +26066,8 @@ function parseJsonSafe4(text69) {
|
|
|
25215
26066
|
}
|
|
25216
26067
|
|
|
25217
26068
|
// src/runtime/native-intelligence/marketing-context-builder.ts
|
|
25218
|
-
import
|
|
25219
|
-
import
|
|
26069
|
+
import fs32 from "node:fs";
|
|
26070
|
+
import path40 from "node:path";
|
|
25220
26071
|
var CONTEXT_BUILDER_SYSTEM_PROMPT = `You are a marketing strategist drafting a product-marketing-context document.
|
|
25221
26072
|
|
|
25222
26073
|
You receive project artifacts (README content, package.json metadata, any landing page content) and produce a structured product-marketing-context.md with 12 sections.
|
|
@@ -25235,17 +26086,17 @@ var MAX_ARTIFACT_LENGTH = 8e3;
|
|
|
25235
26086
|
function scanProjectArtifacts(projectDir, existingContext) {
|
|
25236
26087
|
const artifacts = { otherFiles: [] };
|
|
25237
26088
|
for (const name of ["README.md", "readme.md", "Readme.md", "README"]) {
|
|
25238
|
-
const readmePath =
|
|
25239
|
-
if (
|
|
25240
|
-
const content =
|
|
26089
|
+
const readmePath = path40.join(projectDir, name);
|
|
26090
|
+
if (fs32.existsSync(readmePath)) {
|
|
26091
|
+
const content = fs32.readFileSync(readmePath, "utf-8");
|
|
25241
26092
|
artifacts.readme = content.slice(0, MAX_ARTIFACT_LENGTH);
|
|
25242
26093
|
break;
|
|
25243
26094
|
}
|
|
25244
26095
|
}
|
|
25245
|
-
const pkgPath =
|
|
25246
|
-
if (
|
|
26096
|
+
const pkgPath = path40.join(projectDir, "package.json");
|
|
26097
|
+
if (fs32.existsSync(pkgPath)) {
|
|
25247
26098
|
try {
|
|
25248
|
-
artifacts.packageJson = JSON.parse(
|
|
26099
|
+
artifacts.packageJson = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
|
|
25249
26100
|
} catch {
|
|
25250
26101
|
}
|
|
25251
26102
|
}
|
|
@@ -25257,15 +26108,15 @@ function scanProjectArtifacts(projectDir, existingContext) {
|
|
|
25257
26108
|
".claude/product-marketing-context.md",
|
|
25258
26109
|
"brands/_template/product-marketing-context.md"
|
|
25259
26110
|
]) {
|
|
25260
|
-
const ctxPath =
|
|
25261
|
-
if (
|
|
25262
|
-
artifacts.existingContext =
|
|
26111
|
+
const ctxPath = path40.join(projectDir, candidate);
|
|
26112
|
+
if (fs32.existsSync(ctxPath)) {
|
|
26113
|
+
artifacts.existingContext = fs32.readFileSync(ctxPath, "utf-8");
|
|
25263
26114
|
break;
|
|
25264
26115
|
}
|
|
25265
26116
|
}
|
|
25266
26117
|
}
|
|
25267
26118
|
for (const name of ["CONTRIBUTING.md", "AGENTS.md", "landing-page.md", "about.md"]) {
|
|
25268
|
-
if (
|
|
26119
|
+
if (fs32.existsSync(path40.join(projectDir, name))) {
|
|
25269
26120
|
artifacts.otherFiles.push(name);
|
|
25270
26121
|
}
|
|
25271
26122
|
}
|
|
@@ -25506,15 +26357,15 @@ function cleanMarkdownResponse(text69) {
|
|
|
25506
26357
|
|
|
25507
26358
|
// src/runtime/native-intelligence/index.ts
|
|
25508
26359
|
function resolveConfigPath2() {
|
|
25509
|
-
return
|
|
26360
|
+
return path41.resolve(resolvePaperclipHomeDir(), "native-intelligence", "config.json");
|
|
25510
26361
|
}
|
|
25511
26362
|
function readIntelligenceConfig() {
|
|
25512
26363
|
const configPath = resolveConfigPath2();
|
|
25513
|
-
if (!
|
|
26364
|
+
if (!fs33.existsSync(configPath)) {
|
|
25514
26365
|
return { ...DEFAULT_INTELLIGENCE_CONFIG };
|
|
25515
26366
|
}
|
|
25516
26367
|
try {
|
|
25517
|
-
const raw = JSON.parse(
|
|
26368
|
+
const raw = JSON.parse(fs33.readFileSync(configPath, "utf-8"));
|
|
25518
26369
|
return {
|
|
25519
26370
|
modelId: validateModelId(raw.modelId),
|
|
25520
26371
|
backendType: raw.backendType === "hosted" ? "hosted" : "local",
|
|
@@ -25531,8 +26382,8 @@ function readIntelligenceConfig() {
|
|
|
25531
26382
|
}
|
|
25532
26383
|
function writeIntelligenceConfig(config) {
|
|
25533
26384
|
const configPath = resolveConfigPath2();
|
|
25534
|
-
|
|
25535
|
-
|
|
26385
|
+
fs33.mkdirSync(path41.dirname(configPath), { recursive: true });
|
|
26386
|
+
fs33.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
|
|
25536
26387
|
`, "utf-8");
|
|
25537
26388
|
}
|
|
25538
26389
|
function validateModelId(id) {
|
|
@@ -25888,9 +26739,9 @@ async function runPipelineAssembler(opts) {
|
|
|
25888
26739
|
}
|
|
25889
26740
|
}
|
|
25890
26741
|
function loadPipelineFromFileOrJson(input) {
|
|
25891
|
-
const resolvedPath =
|
|
25892
|
-
if (
|
|
25893
|
-
const content =
|
|
26742
|
+
const resolvedPath = path42.resolve(input);
|
|
26743
|
+
if (fs34.existsSync(resolvedPath)) {
|
|
26744
|
+
const content = fs34.readFileSync(resolvedPath, "utf-8");
|
|
25894
26745
|
return deserializePipeline(JSON.parse(content));
|
|
25895
26746
|
}
|
|
25896
26747
|
try {
|
|
@@ -26435,8 +27286,8 @@ Examples:
|
|
|
26435
27286
|
}
|
|
26436
27287
|
|
|
26437
27288
|
// src/commands/workflow.ts
|
|
26438
|
-
import
|
|
26439
|
-
import
|
|
27289
|
+
import fs36 from "node:fs";
|
|
27290
|
+
import path44 from "node:path";
|
|
26440
27291
|
import * as p23 from "@clack/prompts";
|
|
26441
27292
|
import pc37 from "picocolors";
|
|
26442
27293
|
init_session_store();
|
|
@@ -26444,15 +27295,15 @@ init_hosted_client();
|
|
|
26444
27295
|
|
|
26445
27296
|
// src/runtime/workflow-hygiene/labels.ts
|
|
26446
27297
|
init_home();
|
|
26447
|
-
import
|
|
26448
|
-
import
|
|
27298
|
+
import fs35 from "node:fs";
|
|
27299
|
+
import path43 from "node:path";
|
|
26449
27300
|
function resolveStorePath() {
|
|
26450
|
-
return
|
|
27301
|
+
return path43.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "labels.json");
|
|
26451
27302
|
}
|
|
26452
27303
|
function readStoreFile(filePath) {
|
|
26453
|
-
if (!
|
|
27304
|
+
if (!fs35.existsSync(filePath)) return { records: [] };
|
|
26454
27305
|
try {
|
|
26455
|
-
const raw = JSON.parse(
|
|
27306
|
+
const raw = JSON.parse(fs35.readFileSync(filePath, "utf-8"));
|
|
26456
27307
|
if (!Array.isArray(raw.records)) return { records: [] };
|
|
26457
27308
|
return raw;
|
|
26458
27309
|
} catch {
|
|
@@ -26460,8 +27311,8 @@ function readStoreFile(filePath) {
|
|
|
26460
27311
|
}
|
|
26461
27312
|
}
|
|
26462
27313
|
function writeStoreFile(filePath, data) {
|
|
26463
|
-
|
|
26464
|
-
|
|
27314
|
+
fs35.mkdirSync(path43.dirname(filePath), { recursive: true });
|
|
27315
|
+
fs35.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}
|
|
26465
27316
|
`, "utf-8");
|
|
26466
27317
|
}
|
|
26467
27318
|
function inferDefaultLabel(name, createdAt, versionCount) {
|
|
@@ -26562,16 +27413,16 @@ function box5(lines) {
|
|
|
26562
27413
|
return [top, ...body, bottom].join("\n");
|
|
26563
27414
|
}
|
|
26564
27415
|
function resolveSavedWorkflowsDir() {
|
|
26565
|
-
return
|
|
27416
|
+
return path44.resolve(resolvePaperclipHomeDir(), "workflows");
|
|
26566
27417
|
}
|
|
26567
27418
|
function resolveDeletedWorkflowIdsPath() {
|
|
26568
|
-
return
|
|
27419
|
+
return path44.resolve(resolvePaperclipHomeDir(), "workflow-hygiene", "deleted-workflows.json");
|
|
26569
27420
|
}
|
|
26570
27421
|
function readDeletedWorkflowIds() {
|
|
26571
27422
|
const filePath = resolveDeletedWorkflowIdsPath();
|
|
26572
|
-
if (!
|
|
27423
|
+
if (!fs36.existsSync(filePath)) return /* @__PURE__ */ new Set();
|
|
26573
27424
|
try {
|
|
26574
|
-
const raw = JSON.parse(
|
|
27425
|
+
const raw = JSON.parse(fs36.readFileSync(filePath, "utf-8"));
|
|
26575
27426
|
if (!Array.isArray(raw?.workflowIds)) return /* @__PURE__ */ new Set();
|
|
26576
27427
|
return new Set(raw.workflowIds.filter((value) => typeof value === "string"));
|
|
26577
27428
|
} catch {
|
|
@@ -26580,8 +27431,8 @@ function readDeletedWorkflowIds() {
|
|
|
26580
27431
|
}
|
|
26581
27432
|
function writeDeletedWorkflowIds(ids) {
|
|
26582
27433
|
const filePath = resolveDeletedWorkflowIdsPath();
|
|
26583
|
-
|
|
26584
|
-
|
|
27434
|
+
fs36.mkdirSync(path44.dirname(filePath), { recursive: true });
|
|
27435
|
+
fs36.writeFileSync(filePath, `${JSON.stringify({ workflowIds: [...ids] }, null, 2)}
|
|
26585
27436
|
`, "utf-8");
|
|
26586
27437
|
}
|
|
26587
27438
|
function markWorkflowDeletedLocally(workflowId) {
|
|
@@ -26607,10 +27458,10 @@ function filterLocallyDeletedWorkflows(entries) {
|
|
|
26607
27458
|
}
|
|
26608
27459
|
function listLocalSavedWorkflows() {
|
|
26609
27460
|
const dir = resolveSavedWorkflowsDir();
|
|
26610
|
-
if (!
|
|
26611
|
-
const entries =
|
|
27461
|
+
if (!fs36.existsSync(dir)) return [];
|
|
27462
|
+
const entries = fs36.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".json")).map((e) => {
|
|
26612
27463
|
try {
|
|
26613
|
-
const raw = JSON.parse(
|
|
27464
|
+
const raw = JSON.parse(fs36.readFileSync(path44.resolve(dir, e.name), "utf-8"));
|
|
26614
27465
|
const pipeline = raw.pipeline ?? raw;
|
|
26615
27466
|
return {
|
|
26616
27467
|
filename: e.name,
|
|
@@ -26671,11 +27522,11 @@ async function archiveSavedWorkflow(entry) {
|
|
|
26671
27522
|
throw new Error("Local workflow entry is missing filename.");
|
|
26672
27523
|
}
|
|
26673
27524
|
const dir = resolveSavedWorkflowsDir();
|
|
26674
|
-
const archiveDir =
|
|
26675
|
-
|
|
26676
|
-
|
|
26677
|
-
|
|
26678
|
-
|
|
27525
|
+
const archiveDir = path44.resolve(dir, "archived");
|
|
27526
|
+
fs36.mkdirSync(archiveDir, { recursive: true });
|
|
27527
|
+
fs36.renameSync(
|
|
27528
|
+
path44.resolve(dir, entry.filename),
|
|
27529
|
+
path44.resolve(archiveDir, entry.filename)
|
|
26679
27530
|
);
|
|
26680
27531
|
}
|
|
26681
27532
|
async function deleteSavedWorkflow(entry) {
|
|
@@ -26699,7 +27550,7 @@ async function deleteSavedWorkflow(entry) {
|
|
|
26699
27550
|
if (!entry.filename) {
|
|
26700
27551
|
throw new Error("Local workflow entry is missing filename.");
|
|
26701
27552
|
}
|
|
26702
|
-
|
|
27553
|
+
fs36.rmSync(path44.resolve(resolveSavedWorkflowsDir(), entry.filename), { force: true });
|
|
26703
27554
|
markWorkflowDeletedLocally(entry.workflowId);
|
|
26704
27555
|
}
|
|
26705
27556
|
async function loadSavedWorkflowDetail(entry) {
|
|
@@ -26718,7 +27569,7 @@ async function loadSavedWorkflowDetail(entry) {
|
|
|
26718
27569
|
};
|
|
26719
27570
|
}
|
|
26720
27571
|
const dir = resolveSavedWorkflowsDir();
|
|
26721
|
-
const content =
|
|
27572
|
+
const content = fs36.readFileSync(path44.resolve(dir, entry.filename), "utf-8");
|
|
26722
27573
|
const raw = JSON.parse(content);
|
|
26723
27574
|
return {
|
|
26724
27575
|
pipeline: raw.pipeline ?? raw,
|
|
@@ -27702,36 +28553,36 @@ import pc38 from "picocolors";
|
|
|
27702
28553
|
|
|
27703
28554
|
// src/runtime/agent-harness/auth-store.ts
|
|
27704
28555
|
init_home();
|
|
27705
|
-
import
|
|
27706
|
-
import
|
|
28556
|
+
import fs37 from "node:fs";
|
|
28557
|
+
import path45 from "node:path";
|
|
27707
28558
|
function resolveHarnessAuthDir() {
|
|
27708
|
-
return
|
|
28559
|
+
return path45.resolve(resolvePaperclipHomeDir(), "harness-auth");
|
|
27709
28560
|
}
|
|
27710
28561
|
function resolveHarnessAuthFile(harnessId) {
|
|
27711
|
-
return
|
|
28562
|
+
return path45.resolve(resolveHarnessAuthDir(), `${harnessId}.json`);
|
|
27712
28563
|
}
|
|
27713
28564
|
function normalizeSecret(value) {
|
|
27714
28565
|
const trimmed = value?.trim();
|
|
27715
28566
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
27716
28567
|
}
|
|
27717
28568
|
function ensureSecureDir(dirPath) {
|
|
27718
|
-
|
|
28569
|
+
fs37.mkdirSync(dirPath, { recursive: true });
|
|
27719
28570
|
try {
|
|
27720
|
-
|
|
28571
|
+
fs37.chmodSync(dirPath, 448);
|
|
27721
28572
|
} catch {
|
|
27722
28573
|
}
|
|
27723
28574
|
}
|
|
27724
28575
|
function ensureSecureFile(filePath) {
|
|
27725
28576
|
try {
|
|
27726
|
-
|
|
28577
|
+
fs37.chmodSync(filePath, 384);
|
|
27727
28578
|
} catch {
|
|
27728
28579
|
}
|
|
27729
28580
|
}
|
|
27730
28581
|
function readHarnessCredentials(harnessId) {
|
|
27731
28582
|
const filePath = resolveHarnessAuthFile(harnessId);
|
|
27732
|
-
if (!
|
|
28583
|
+
if (!fs37.existsSync(filePath)) return {};
|
|
27733
28584
|
try {
|
|
27734
|
-
const parsed = JSON.parse(
|
|
28585
|
+
const parsed = JSON.parse(fs37.readFileSync(filePath, "utf-8"));
|
|
27735
28586
|
const creds = {};
|
|
27736
28587
|
for (const [key, value] of Object.entries(parsed)) {
|
|
27737
28588
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
@@ -27758,7 +28609,7 @@ function setHarnessCredential(harnessId, key, value) {
|
|
|
27758
28609
|
const dirPath = resolveHarnessAuthDir();
|
|
27759
28610
|
ensureSecureDir(dirPath);
|
|
27760
28611
|
const filePath = resolveHarnessAuthFile(harnessId);
|
|
27761
|
-
|
|
28612
|
+
fs37.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
|
|
27762
28613
|
`, "utf-8");
|
|
27763
28614
|
ensureSecureFile(filePath);
|
|
27764
28615
|
}
|
|
@@ -27775,7 +28626,7 @@ function setHarnessCredentials(harnessId, updates) {
|
|
|
27775
28626
|
const dirPath = resolveHarnessAuthDir();
|
|
27776
28627
|
ensureSecureDir(dirPath);
|
|
27777
28628
|
const filePath = resolveHarnessAuthFile(harnessId);
|
|
27778
|
-
|
|
28629
|
+
fs37.writeFileSync(filePath, `${JSON.stringify(creds, null, 2)}
|
|
27779
28630
|
`, "utf-8");
|
|
27780
28631
|
ensureSecureFile(filePath);
|
|
27781
28632
|
}
|
|
@@ -27787,8 +28638,8 @@ function maskSecret(value) {
|
|
|
27787
28638
|
|
|
27788
28639
|
// src/runtime/open-agents/index.ts
|
|
27789
28640
|
init_home();
|
|
27790
|
-
import
|
|
27791
|
-
import
|
|
28641
|
+
import fs38 from "node:fs";
|
|
28642
|
+
import path46 from "node:path";
|
|
27792
28643
|
|
|
27793
28644
|
// src/runtime/open-agents/contract.ts
|
|
27794
28645
|
var DEFAULT_OPEN_AGENTS_CONFIG = {
|
|
@@ -27975,18 +28826,18 @@ var OpenAgentsBackendError = class extends Error {
|
|
|
27975
28826
|
|
|
27976
28827
|
// src/runtime/open-agents/index.ts
|
|
27977
28828
|
function resolveConfigPath3() {
|
|
27978
|
-
return
|
|
28829
|
+
return path46.resolve(resolvePaperclipHomeDir(), "open-agents", "config.json");
|
|
27979
28830
|
}
|
|
27980
28831
|
function readOpenAgentsConfig() {
|
|
27981
28832
|
const configPath = resolveConfigPath3();
|
|
27982
|
-
if (!
|
|
28833
|
+
if (!fs38.existsSync(configPath)) {
|
|
27983
28834
|
return {
|
|
27984
28835
|
...DEFAULT_OPEN_AGENTS_CONFIG,
|
|
27985
28836
|
apiKey: getHarnessCredential("open-agents", "apiKey")
|
|
27986
28837
|
};
|
|
27987
28838
|
}
|
|
27988
28839
|
try {
|
|
27989
|
-
const raw = JSON.parse(
|
|
28840
|
+
const raw = JSON.parse(fs38.readFileSync(configPath, "utf-8"));
|
|
27990
28841
|
const storedApiKey = getHarnessCredential("open-agents", "apiKey");
|
|
27991
28842
|
return {
|
|
27992
28843
|
backendType: validateBackendType(raw.backendType),
|
|
@@ -28007,13 +28858,13 @@ function readOpenAgentsConfig() {
|
|
|
28007
28858
|
}
|
|
28008
28859
|
function writeOpenAgentsConfig(config) {
|
|
28009
28860
|
const configPath = resolveConfigPath3();
|
|
28010
|
-
|
|
28861
|
+
fs38.mkdirSync(path46.dirname(configPath), { recursive: true });
|
|
28011
28862
|
const persisted = {
|
|
28012
28863
|
...config,
|
|
28013
28864
|
authMode: validateAuthMode(config.authMode),
|
|
28014
28865
|
apiKey: void 0
|
|
28015
28866
|
};
|
|
28016
|
-
|
|
28867
|
+
fs38.writeFileSync(configPath, `${JSON.stringify(persisted, null, 2)}
|
|
28017
28868
|
`, "utf-8");
|
|
28018
28869
|
setHarnessCredential("open-agents", "apiKey", config.apiKey);
|
|
28019
28870
|
}
|
|
@@ -28574,8 +29425,8 @@ import pc39 from "picocolors";
|
|
|
28574
29425
|
|
|
28575
29426
|
// src/runtime/qwen-code/index.ts
|
|
28576
29427
|
init_home();
|
|
28577
|
-
import
|
|
28578
|
-
import
|
|
29428
|
+
import fs39 from "node:fs";
|
|
29429
|
+
import path47 from "node:path";
|
|
28579
29430
|
|
|
28580
29431
|
// src/runtime/qwen-code/contract.ts
|
|
28581
29432
|
var QWEN_CODE_APPROVAL_MODES = [
|
|
@@ -28793,19 +29644,19 @@ function buildSetupGuidance(env) {
|
|
|
28793
29644
|
|
|
28794
29645
|
// src/runtime/qwen-code/index.ts
|
|
28795
29646
|
function resolveConfigPath4() {
|
|
28796
|
-
return
|
|
29647
|
+
return path47.resolve(resolvePaperclipHomeDir(), "qwen-code", "config.json");
|
|
28797
29648
|
}
|
|
28798
29649
|
function readQwenCodeConfig() {
|
|
28799
29650
|
const configPath = resolveConfigPath4();
|
|
28800
29651
|
const storedCredentials = readHarnessCredentials("qwen-code");
|
|
28801
|
-
if (!
|
|
29652
|
+
if (!fs39.existsSync(configPath)) {
|
|
28802
29653
|
return {
|
|
28803
29654
|
...DEFAULT_QWEN_CODE_CONFIG,
|
|
28804
29655
|
env: mergeHarnessEnv(DEFAULT_QWEN_CODE_CONFIG.env, storedCredentials)
|
|
28805
29656
|
};
|
|
28806
29657
|
}
|
|
28807
29658
|
try {
|
|
28808
|
-
const raw = JSON.parse(
|
|
29659
|
+
const raw = JSON.parse(fs39.readFileSync(configPath, "utf-8"));
|
|
28809
29660
|
return {
|
|
28810
29661
|
binaryPath: typeof raw.binaryPath === "string" ? raw.binaryPath : DEFAULT_QWEN_CODE_CONFIG.binaryPath,
|
|
28811
29662
|
defaultModel: typeof raw.defaultModel === "string" ? raw.defaultModel : DEFAULT_QWEN_CODE_CONFIG.defaultModel,
|
|
@@ -28827,7 +29678,7 @@ function readQwenCodeConfig() {
|
|
|
28827
29678
|
}
|
|
28828
29679
|
function writeQwenCodeConfig(config) {
|
|
28829
29680
|
const configPath = resolveConfigPath4();
|
|
28830
|
-
|
|
29681
|
+
fs39.mkdirSync(path47.dirname(configPath), { recursive: true });
|
|
28831
29682
|
const rawEnv = typeof config.env === "object" && config.env !== null ? config.env : {};
|
|
28832
29683
|
const credentialUpdates = {};
|
|
28833
29684
|
const publicEnv = {};
|
|
@@ -28839,7 +29690,7 @@ function writeQwenCodeConfig(config) {
|
|
|
28839
29690
|
publicEnv[key] = value;
|
|
28840
29691
|
}
|
|
28841
29692
|
setHarnessCredentials("qwen-code", credentialUpdates);
|
|
28842
|
-
|
|
29693
|
+
fs39.writeFileSync(
|
|
28843
29694
|
configPath,
|
|
28844
29695
|
`${JSON.stringify({ ...config, env: publicEnv }, null, 2)}
|
|
28845
29696
|
`,
|
|
@@ -29089,32 +29940,32 @@ import pc41 from "picocolors";
|
|
|
29089
29940
|
|
|
29090
29941
|
// src/runtime/t3code/index.ts
|
|
29091
29942
|
init_home();
|
|
29092
|
-
import
|
|
29093
|
-
import
|
|
29943
|
+
import fs41 from "node:fs";
|
|
29944
|
+
import path49 from "node:path";
|
|
29094
29945
|
|
|
29095
29946
|
// src/runtime/agent-harness/harness-profile.ts
|
|
29096
29947
|
init_home();
|
|
29097
|
-
import
|
|
29098
|
-
import
|
|
29948
|
+
import fs40 from "node:fs";
|
|
29949
|
+
import path48 from "node:path";
|
|
29099
29950
|
import * as p26 from "@clack/prompts";
|
|
29100
29951
|
import pc40 from "picocolors";
|
|
29101
29952
|
function resolveProfileDir(harnessId) {
|
|
29102
|
-
return
|
|
29953
|
+
return path48.resolve(resolvePaperclipHomeDir(), harnessId);
|
|
29103
29954
|
}
|
|
29104
29955
|
function resolveProfilePath(harnessId) {
|
|
29105
|
-
return
|
|
29956
|
+
return path48.resolve(resolveProfileDir(harnessId), "growthub-profile.json");
|
|
29106
29957
|
}
|
|
29107
29958
|
function ensureSecureFile2(filePath) {
|
|
29108
29959
|
try {
|
|
29109
|
-
|
|
29960
|
+
fs40.chmodSync(filePath, 384);
|
|
29110
29961
|
} catch {
|
|
29111
29962
|
}
|
|
29112
29963
|
}
|
|
29113
29964
|
function readHarnessProfile(harnessId) {
|
|
29114
29965
|
const filePath = resolveProfilePath(harnessId);
|
|
29115
|
-
if (!
|
|
29966
|
+
if (!fs40.existsSync(filePath)) return null;
|
|
29116
29967
|
try {
|
|
29117
|
-
const raw = JSON.parse(
|
|
29968
|
+
const raw = JSON.parse(fs40.readFileSync(filePath, "utf-8"));
|
|
29118
29969
|
if (typeof raw.workspaceId !== "string" || typeof raw.machineLabel !== "string") return null;
|
|
29119
29970
|
return {
|
|
29120
29971
|
profileVersion: 1,
|
|
@@ -29132,14 +29983,14 @@ function readHarnessProfile(harnessId) {
|
|
|
29132
29983
|
function writeHarnessProfile(harnessId, profile) {
|
|
29133
29984
|
const dirPath = resolveProfileDir(harnessId);
|
|
29134
29985
|
const filePath = resolveProfilePath(harnessId);
|
|
29135
|
-
|
|
29136
|
-
|
|
29986
|
+
fs40.mkdirSync(dirPath, { recursive: true });
|
|
29987
|
+
fs40.writeFileSync(filePath, `${JSON.stringify(profile, null, 2)}
|
|
29137
29988
|
`, "utf-8");
|
|
29138
29989
|
ensureSecureFile2(filePath);
|
|
29139
29990
|
}
|
|
29140
29991
|
function clearHarnessProfile(harnessId) {
|
|
29141
29992
|
const filePath = resolveProfilePath(harnessId);
|
|
29142
|
-
if (
|
|
29993
|
+
if (fs40.existsSync(filePath)) fs40.rmSync(filePath);
|
|
29143
29994
|
}
|
|
29144
29995
|
function buildProfileStatusLines(harnessId, harnessLabel, profile) {
|
|
29145
29996
|
if (!profile) {
|
|
@@ -29420,19 +30271,19 @@ function writeT3GrowthubProfile(profile) {
|
|
|
29420
30271
|
writeHarnessProfile(T3_HARNESS_ID, profile);
|
|
29421
30272
|
}
|
|
29422
30273
|
function resolveConfigPath5() {
|
|
29423
|
-
return
|
|
30274
|
+
return path49.resolve(resolvePaperclipHomeDir(), "t3code", "config.json");
|
|
29424
30275
|
}
|
|
29425
30276
|
function readT3CodeConfig() {
|
|
29426
30277
|
const configPath = resolveConfigPath5();
|
|
29427
30278
|
const storedCredentials = readHarnessCredentials(T3_HARNESS_ID);
|
|
29428
|
-
if (!
|
|
30279
|
+
if (!fs41.existsSync(configPath)) {
|
|
29429
30280
|
return {
|
|
29430
30281
|
...DEFAULT_T3_CODE_CONFIG,
|
|
29431
30282
|
env: mergeHarnessEnv2(DEFAULT_T3_CODE_CONFIG.env, storedCredentials)
|
|
29432
30283
|
};
|
|
29433
30284
|
}
|
|
29434
30285
|
try {
|
|
29435
|
-
const raw = JSON.parse(
|
|
30286
|
+
const raw = JSON.parse(fs41.readFileSync(configPath, "utf-8"));
|
|
29436
30287
|
const profile = readHarnessProfile(T3_HARNESS_ID);
|
|
29437
30288
|
const resolvedBinaryPath = profile?.forkBinaryPath ?? (typeof raw.binaryPath === "string" ? raw.binaryPath : DEFAULT_T3_CODE_CONFIG.binaryPath);
|
|
29438
30289
|
return {
|
|
@@ -29455,7 +30306,7 @@ function readT3CodeConfig() {
|
|
|
29455
30306
|
}
|
|
29456
30307
|
function writeT3CodeConfig(config) {
|
|
29457
30308
|
const configPath = resolveConfigPath5();
|
|
29458
|
-
|
|
30309
|
+
fs41.mkdirSync(path49.dirname(configPath), { recursive: true });
|
|
29459
30310
|
const rawEnv = typeof config.env === "object" && config.env !== null ? config.env : {};
|
|
29460
30311
|
const credentialUpdates = {};
|
|
29461
30312
|
const publicEnv = {};
|
|
@@ -29467,7 +30318,7 @@ function writeT3CodeConfig(config) {
|
|
|
29467
30318
|
}
|
|
29468
30319
|
}
|
|
29469
30320
|
setHarnessCredentials(T3_HARNESS_ID, credentialUpdates);
|
|
29470
|
-
|
|
30321
|
+
fs41.writeFileSync(
|
|
29471
30322
|
configPath,
|
|
29472
30323
|
`${JSON.stringify({ ...config, env: publicEnv }, null, 2)}
|
|
29473
30324
|
`,
|
|
@@ -29849,8 +30700,8 @@ import pc44 from "picocolors";
|
|
|
29849
30700
|
|
|
29850
30701
|
// src/status/probes.ts
|
|
29851
30702
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
29852
|
-
import
|
|
29853
|
-
import
|
|
30703
|
+
import fs42 from "node:fs";
|
|
30704
|
+
import path50 from "node:path";
|
|
29854
30705
|
var GITHUB_API = "https://api.github.com";
|
|
29855
30706
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
29856
30707
|
function isoNow() {
|
|
@@ -30015,7 +30866,7 @@ async function probeKitForksIndex(_timeoutMs) {
|
|
|
30015
30866
|
try {
|
|
30016
30867
|
const { resolveKitForksIndexPath: resolveKitForksIndexPath2 } = await Promise.resolve().then(() => (init_kit_forks_home(), kit_forks_home_exports));
|
|
30017
30868
|
const p35 = resolveKitForksIndexPath2();
|
|
30018
|
-
if (!
|
|
30869
|
+
if (!fs42.existsSync(p35)) {
|
|
30019
30870
|
return {
|
|
30020
30871
|
componentId: "kit-forks-index",
|
|
30021
30872
|
level: "operational",
|
|
@@ -30023,7 +30874,7 @@ async function probeKitForksIndex(_timeoutMs) {
|
|
|
30023
30874
|
lastCheckedAt: isoNow()
|
|
30024
30875
|
};
|
|
30025
30876
|
}
|
|
30026
|
-
const parsed = JSON.parse(
|
|
30877
|
+
const parsed = JSON.parse(fs42.readFileSync(p35, "utf8"));
|
|
30027
30878
|
const count = Array.isArray(parsed.entries) ? parsed.entries.length : 0;
|
|
30028
30879
|
return {
|
|
30029
30880
|
componentId: "kit-forks-index",
|
|
@@ -30092,10 +30943,10 @@ async function probeNode(_timeoutMs) {
|
|
|
30092
30943
|
};
|
|
30093
30944
|
}
|
|
30094
30945
|
async function probeReleaseBundleArtifacts(_timeoutMs) {
|
|
30095
|
-
const distPath =
|
|
30096
|
-
const installerPath =
|
|
30097
|
-
const distOk =
|
|
30098
|
-
const installerOk =
|
|
30946
|
+
const distPath = path50.resolve(process.cwd(), "cli/dist/index.js");
|
|
30947
|
+
const installerPath = path50.resolve(process.cwd(), "packages/create-growthub-local/bin/create-growthub-local.mjs");
|
|
30948
|
+
const distOk = fs42.existsSync(distPath);
|
|
30949
|
+
const installerOk = fs42.existsSync(installerPath);
|
|
30099
30950
|
const ok = distOk && installerOk;
|
|
30100
30951
|
return {
|
|
30101
30952
|
componentId: "release-bundle",
|
|
@@ -30654,7 +31505,7 @@ import pc46 from "picocolors";
|
|
|
30654
31505
|
|
|
30655
31506
|
// src/fleet/summary.ts
|
|
30656
31507
|
init_fork_registry();
|
|
30657
|
-
import
|
|
31508
|
+
import fs52 from "node:fs";
|
|
30658
31509
|
init_fork_policy();
|
|
30659
31510
|
init_fork_trace();
|
|
30660
31511
|
function classifyHealth(drift, pendingConfirmationJobs, lastJobStatus) {
|
|
@@ -30674,7 +31525,7 @@ var REMOTE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
30674
31525
|
"conflict_encountered"
|
|
30675
31526
|
]);
|
|
30676
31527
|
function buildForkSummary(reg) {
|
|
30677
|
-
if (!
|
|
31528
|
+
if (!fs52.existsSync(reg.forkPath)) {
|
|
30678
31529
|
return {
|
|
30679
31530
|
forkId: reg.forkId,
|
|
30680
31531
|
kitId: reg.kitId,
|
|
@@ -31135,8 +31986,8 @@ async function fleetApprovals(opts) {
|
|
|
31135
31986
|
p32.log.message(
|
|
31136
31987
|
` \xB7 ${pc46.cyan(entry.jobId)} fork=${entry.forkLabel ?? entry.forkId} created=${entry.createdAt.slice(0, 19)}`
|
|
31137
31988
|
);
|
|
31138
|
-
for (const
|
|
31139
|
-
p32.log.message(` ${pc46.dim("awaits")} ${
|
|
31989
|
+
for (const path63 of entry.pendingPaths.slice(0, 6)) {
|
|
31990
|
+
p32.log.message(` ${pc46.dim("awaits")} ${path63}`);
|
|
31140
31991
|
}
|
|
31141
31992
|
if (entry.pendingPaths.length > 6) {
|
|
31142
31993
|
p32.log.message(` ${pc46.dim(`\u2026 +${entry.pendingPaths.length - 6} more`)}`);
|
|
@@ -31222,21 +32073,21 @@ var DEFAULT_MEMORY_PROVIDER_CONFIG = {
|
|
|
31222
32073
|
|
|
31223
32074
|
// src/runtime/memory/store.ts
|
|
31224
32075
|
init_home();
|
|
31225
|
-
import
|
|
31226
|
-
import
|
|
32076
|
+
import fs53 from "node:fs";
|
|
32077
|
+
import path60 from "node:path";
|
|
31227
32078
|
function toProjectSlug(project) {
|
|
31228
32079
|
return project.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "default";
|
|
31229
32080
|
}
|
|
31230
32081
|
function resolveProjectPath(project) {
|
|
31231
|
-
return
|
|
32082
|
+
return path60.resolve(resolveMemoryProjectsDir(), `${toProjectSlug(project)}.json`);
|
|
31232
32083
|
}
|
|
31233
32084
|
function loadMemoryDatabase(project) {
|
|
31234
32085
|
const filePath = resolveProjectPath(project);
|
|
31235
|
-
if (!
|
|
32086
|
+
if (!fs53.existsSync(filePath)) {
|
|
31236
32087
|
return { version: 1, project, observations: [], summaries: [], nextObservationId: 1, nextSummaryId: 1 };
|
|
31237
32088
|
}
|
|
31238
32089
|
try {
|
|
31239
|
-
const raw = JSON.parse(
|
|
32090
|
+
const raw = JSON.parse(fs53.readFileSync(filePath, "utf-8"));
|
|
31240
32091
|
return {
|
|
31241
32092
|
version: 1,
|
|
31242
32093
|
project,
|
|
@@ -31251,9 +32102,9 @@ function loadMemoryDatabase(project) {
|
|
|
31251
32102
|
}
|
|
31252
32103
|
function saveMemoryDatabase(db) {
|
|
31253
32104
|
const dir = resolveMemoryProjectsDir();
|
|
31254
|
-
|
|
32105
|
+
fs53.mkdirSync(dir, { recursive: true });
|
|
31255
32106
|
const filePath = resolveProjectPath(db.project);
|
|
31256
|
-
|
|
32107
|
+
fs53.writeFileSync(filePath, `${JSON.stringify(db, null, 2)}
|
|
31257
32108
|
`, "utf-8");
|
|
31258
32109
|
}
|
|
31259
32110
|
function addObservation(project, input) {
|
|
@@ -31347,8 +32198,8 @@ function incrementRelevanceCount(project, observationId) {
|
|
|
31347
32198
|
}
|
|
31348
32199
|
function listMemoryProjects() {
|
|
31349
32200
|
const dir = resolveMemoryProjectsDir();
|
|
31350
|
-
if (!
|
|
31351
|
-
return
|
|
32201
|
+
if (!fs53.existsSync(dir)) return [];
|
|
32202
|
+
return fs53.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, "")).sort();
|
|
31352
32203
|
}
|
|
31353
32204
|
function getMemoryStats(project) {
|
|
31354
32205
|
const db = loadMemoryDatabase(project);
|
|
@@ -31360,15 +32211,15 @@ function getMemoryStats(project) {
|
|
|
31360
32211
|
};
|
|
31361
32212
|
}
|
|
31362
32213
|
function resolveProviderConfigPath() {
|
|
31363
|
-
return
|
|
32214
|
+
return path60.resolve(resolveMemoryDir(), "provider-config.json");
|
|
31364
32215
|
}
|
|
31365
32216
|
function readProviderConfig() {
|
|
31366
32217
|
const filePath = resolveProviderConfigPath();
|
|
31367
|
-
if (!
|
|
32218
|
+
if (!fs53.existsSync(filePath)) {
|
|
31368
32219
|
return { ...DEFAULT_MEMORY_PROVIDER_CONFIG };
|
|
31369
32220
|
}
|
|
31370
32221
|
try {
|
|
31371
|
-
const raw = JSON.parse(
|
|
32222
|
+
const raw = JSON.parse(fs53.readFileSync(filePath, "utf-8"));
|
|
31372
32223
|
return {
|
|
31373
32224
|
provider: validateProvider(raw.provider),
|
|
31374
32225
|
apiKey: typeof raw.apiKey === "string" ? raw.apiKey : void 0,
|
|
@@ -31381,9 +32232,9 @@ function readProviderConfig() {
|
|
|
31381
32232
|
}
|
|
31382
32233
|
function writeProviderConfig(config) {
|
|
31383
32234
|
const dir = resolveMemoryDir();
|
|
31384
|
-
|
|
32235
|
+
fs53.mkdirSync(dir, { recursive: true });
|
|
31385
32236
|
const filePath = resolveProviderConfigPath();
|
|
31386
|
-
|
|
32237
|
+
fs53.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}
|
|
31387
32238
|
`, { mode: 384 });
|
|
31388
32239
|
}
|
|
31389
32240
|
function validateProvider(value) {
|
|
@@ -31762,14 +32613,14 @@ async function syncMemoriesToHosted(project, options) {
|
|
|
31762
32613
|
init_llm();
|
|
31763
32614
|
function resolveCliVersion() {
|
|
31764
32615
|
try {
|
|
31765
|
-
const moduleDir =
|
|
32616
|
+
const moduleDir = path62.dirname(fileURLToPath7(import.meta.url));
|
|
31766
32617
|
const candidates = [
|
|
31767
|
-
|
|
31768
|
-
|
|
32618
|
+
path62.resolve(moduleDir, "../package.json"),
|
|
32619
|
+
path62.resolve(moduleDir, "../../package.json")
|
|
31769
32620
|
];
|
|
31770
32621
|
for (const candidate of candidates) {
|
|
31771
|
-
if (!
|
|
31772
|
-
const parsed = JSON.parse(
|
|
32622
|
+
if (!fs55.existsSync(candidate)) continue;
|
|
32623
|
+
const parsed = JSON.parse(fs55.readFileSync(candidate, "utf8"));
|
|
31773
32624
|
if (parsed?.name === "@growthub/cli" && typeof parsed.version === "string") return parsed.version;
|
|
31774
32625
|
}
|
|
31775
32626
|
} catch {
|
|
@@ -31996,7 +32847,7 @@ async function runMarketingContextBuilder(baseUrl, model) {
|
|
|
31996
32847
|
});
|
|
31997
32848
|
if (p34.isCancel(projectDir)) return;
|
|
31998
32849
|
const dir = String(projectDir).trim() || process.cwd();
|
|
31999
|
-
if (!
|
|
32850
|
+
if (!fs55.existsSync(dir)) {
|
|
32000
32851
|
p34.note(`Directory not found: ${dir}`, "Marketing Context Builder");
|
|
32001
32852
|
return;
|
|
32002
32853
|
}
|
|
@@ -32032,10 +32883,10 @@ async function runMarketingContextBuilder(baseUrl, model) {
|
|
|
32032
32883
|
p34.note("Draft was not saved. You can copy it from the output above.", "Marketing Context Builder");
|
|
32033
32884
|
return;
|
|
32034
32885
|
}
|
|
32035
|
-
const outDir =
|
|
32036
|
-
|
|
32037
|
-
const outPath =
|
|
32038
|
-
|
|
32886
|
+
const outDir = path62.resolve(dir, ".agents");
|
|
32887
|
+
fs55.mkdirSync(outDir, { recursive: true });
|
|
32888
|
+
const outPath = path62.resolve(outDir, "product-marketing-context.md");
|
|
32889
|
+
fs55.writeFileSync(outPath, result.contextMarkdown, "utf-8");
|
|
32039
32890
|
p34.note(`Saved to: ${outPath}
|
|
32040
32891
|
|
|
32041
32892
|
Review the file and replace [NEEDS INPUT] placeholders with real data.`, "Marketing Context Builder");
|
|
@@ -32244,39 +33095,39 @@ function captureSessionSummary(project, sessionId, messages) {
|
|
|
32244
33095
|
}
|
|
32245
33096
|
}
|
|
32246
33097
|
function resolveLocalThreadsDir() {
|
|
32247
|
-
return
|
|
33098
|
+
return path62.resolve(resolvePaperclipHomeDir(), "native-intelligence", "threads");
|
|
32248
33099
|
}
|
|
32249
33100
|
function loadOrCreateLocalThread() {
|
|
32250
33101
|
const dir = resolveLocalThreadsDir();
|
|
32251
|
-
|
|
32252
|
-
const activePath =
|
|
32253
|
-
if (
|
|
33102
|
+
fs55.mkdirSync(dir, { recursive: true });
|
|
33103
|
+
const activePath = path62.resolve(dir, "active-thread.json");
|
|
33104
|
+
if (fs55.existsSync(activePath)) {
|
|
32254
33105
|
try {
|
|
32255
|
-
const parsed = JSON.parse(
|
|
33106
|
+
const parsed = JSON.parse(fs55.readFileSync(activePath, "utf-8"));
|
|
32256
33107
|
const id2 = typeof parsed.id === "string" && parsed.id.length > 0 ? parsed.id : `thread-${Date.now()}`;
|
|
32257
|
-
const threadFile =
|
|
33108
|
+
const threadFile = path62.resolve(dir, `${id2}.json`);
|
|
32258
33109
|
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
32259
33110
|
return { id: id2, filePath: threadFile, messages };
|
|
32260
33111
|
} catch {
|
|
32261
33112
|
}
|
|
32262
33113
|
}
|
|
32263
33114
|
const id = `thread-${Date.now()}`;
|
|
32264
|
-
const filePath =
|
|
33115
|
+
const filePath = path62.resolve(dir, `${id}.json`);
|
|
32265
33116
|
const thread = { id, filePath, messages: [] };
|
|
32266
33117
|
saveLocalThread(thread);
|
|
32267
33118
|
return thread;
|
|
32268
33119
|
}
|
|
32269
33120
|
function saveLocalThread(thread) {
|
|
32270
33121
|
const dir = resolveLocalThreadsDir();
|
|
32271
|
-
|
|
32272
|
-
|
|
33122
|
+
fs55.mkdirSync(dir, { recursive: true });
|
|
33123
|
+
fs55.writeFileSync(
|
|
32273
33124
|
thread.filePath,
|
|
32274
33125
|
`${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
|
|
32275
33126
|
`,
|
|
32276
33127
|
"utf-8"
|
|
32277
33128
|
);
|
|
32278
|
-
const activePath =
|
|
32279
|
-
|
|
33129
|
+
const activePath = path62.resolve(dir, "active-thread.json");
|
|
33130
|
+
fs55.writeFileSync(
|
|
32280
33131
|
activePath,
|
|
32281
33132
|
`${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
|
|
32282
33133
|
`,
|
|
@@ -32422,7 +33273,7 @@ async function collectBindingsFromContract(contract, promptSeed) {
|
|
|
32422
33273
|
return bindings;
|
|
32423
33274
|
}
|
|
32424
33275
|
function resolveCurrentProject() {
|
|
32425
|
-
return
|
|
33276
|
+
return path62.basename(process.cwd());
|
|
32426
33277
|
}
|
|
32427
33278
|
async function runMemoryKnowledgeHub() {
|
|
32428
33279
|
const project = resolveCurrentProject();
|
|
@@ -33002,12 +33853,12 @@ function isInstallerMode() {
|
|
|
33002
33853
|
}
|
|
33003
33854
|
function listLocalSurfaces() {
|
|
33004
33855
|
const homeDir = resolvePaperclipHomeDir();
|
|
33005
|
-
const instancesDir =
|
|
33006
|
-
if (!
|
|
33007
|
-
return
|
|
33856
|
+
const instancesDir = path62.resolve(homeDir, "instances");
|
|
33857
|
+
if (!fs55.existsSync(instancesDir)) return [];
|
|
33858
|
+
return fs55.readdirSync(instancesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
33008
33859
|
const instanceId = entry.name;
|
|
33009
|
-
const configPath =
|
|
33010
|
-
if (!
|
|
33860
|
+
const configPath = path62.resolve(instancesDir, instanceId, "config.json");
|
|
33861
|
+
if (!fs55.existsSync(configPath)) return null;
|
|
33011
33862
|
try {
|
|
33012
33863
|
const config = readConfig(configPath);
|
|
33013
33864
|
if (!config) return null;
|