@growthub/cli 0.7.8 → 0.8.0
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/SKILL.md +95 -0
- package/assets/worker-kits/creative-strategist-v1/bundles/creative-strategist-v1.json +12 -2
- package/assets/worker-kits/creative-strategist-v1/helpers/README.md +29 -0
- package/assets/worker-kits/creative-strategist-v1/helpers/extract-muse-frames.sh +81 -0
- package/assets/worker-kits/creative-strategist-v1/helpers/grep-hooks.sh +62 -0
- package/assets/worker-kits/creative-strategist-v1/kit.json +20 -2
- package/assets/worker-kits/creative-strategist-v1/skills/README.md +23 -0
- package/assets/worker-kits/creative-strategist-v1/skills/frame-analysis/SKILL.md +88 -0
- package/assets/worker-kits/creative-strategist-v1/templates/project.md +48 -0
- package/assets/worker-kits/creative-strategist-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/creative-strategist-v1/workers/creative-strategist/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/bundles/growthub-ai-website-cloner-v1.json +9 -2
- package/assets/worker-kits/growthub-ai-website-cloner-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-ai-website-cloner-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/workers/ai-website-cloner-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/SKILL.md +122 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/bundles/growthub-custom-workspace-starter-v1.json +14 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/docs/governed-workspace-primitives.md +182 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/README.md +44 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +16 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/skills/README.md +55 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/project.md +55 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/workers/custom-workspace-operator/CLAUDE.md +24 -2
- package/assets/worker-kits/growthub-email-marketing-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-email-marketing-v1/bundles/growthub-email-marketing-v1.json +9 -2
- package/assets/worker-kits/growthub-email-marketing-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-email-marketing-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-email-marketing-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-email-marketing-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-email-marketing-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-email-marketing-v1/workers/email-marketing-strategist/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-geo-seo-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-geo-seo-v1/bundles/growthub-geo-seo-v1.json +12 -3
- package/assets/worker-kits/growthub-geo-seo-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-geo-seo-v1/kit.json +23 -5
- package/assets/worker-kits/growthub-geo-seo-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-geo-seo-v1/workers/geo-seo-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/bundles/growthub-hyperframes-studio-v1.json +6 -1
- package/assets/worker-kits/growthub-hyperframes-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-hyperframes-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/workers/hyperframes-studio-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/bundles/growthub-marketing-skills-v1.json +12 -3
- package/assets/worker-kits/growthub-marketing-skills-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/kit.json +23 -5
- package/assets/worker-kits/growthub-marketing-skills-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/workers/marketing-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/bundles/growthub-open-higgsfield-studio-v1.json +9 -2
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/workers/open-higgsfield-studio-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/bundles/growthub-open-montage-studio-v1.json +9 -2
- package/assets/worker-kits/growthub-open-montage-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-open-montage-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/workers/open-montage-studio-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-postiz-social-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-postiz-social-v1/bundles/growthub-postiz-social-v1.json +9 -2
- package/assets/worker-kits/growthub-postiz-social-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-postiz-social-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-postiz-social-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-postiz-social-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-postiz-social-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-postiz-social-v1/workers/postiz-social-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/bundles/growthub-twenty-crm-v1.json +9 -2
- package/assets/worker-kits/growthub-twenty-crm-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-twenty-crm-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/workers/twenty-crm-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/.env.example +13 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/QUICKSTART.md +47 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/brands/NEW-CLIENT.md +3 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/brands/_template/brand-kit.md +7 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/brands/growthub/brand-kit.md +6 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/bundles/growthub-video-use-studio-v1.json +54 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/docs/provider-adapter-layer.md +15 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/docs/video-use-discovery-path.md +13 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/docs/video-use-fork-integration.md +35 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/examples/video-brief-sample.md +11 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/growthub-meta/README.md +3 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/growthub-meta/kit-standard.md +6 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/kit.json +112 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/output/README.md +9 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/output-standards.md +19 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/runtime-assumptions.md +9 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/setup/check-deps.sh +21 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/setup/clone-fork.sh +18 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/setup/install-skill.sh +23 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/setup/verify-env.mjs +23 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/skills.md +21 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/edit-decision-list.md +17 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/edit-strategy.md +11 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/qa-checklist.md +21 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/render-plan.md +40 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/video-brief.md +11 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/validation-checklist.md +11 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/workers/video-use-studio-operator/CLAUDE.md +93 -0
- package/assets/worker-kits/growthub-zernio-social-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-zernio-social-v1/bundles/growthub-zernio-social-v1.json +9 -2
- package/assets/worker-kits/growthub-zernio-social-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-zernio-social-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-zernio-social-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-zernio-social-v1/workers/zernio-social-operator/CLAUDE.md +22 -0
- package/dist/index.js +974 -233
- package/package.json +2 -2
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, path67) {
|
|
8186
|
+
const normalizedPath = path67.startsWith("/") ? path67 : `/${path67}`;
|
|
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(path67, opts) {
|
|
8249
|
+
return this.request(path67, { method: "GET" }, opts);
|
|
8250
8250
|
}
|
|
8251
|
-
post(
|
|
8252
|
-
return this.request(
|
|
8251
|
+
post(path67, body, opts) {
|
|
8252
|
+
return this.request(path67, {
|
|
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(path67, body, opts) {
|
|
8258
|
+
return this.request(path67, {
|
|
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(path67, opts) {
|
|
8264
|
+
return this.request(path67, { method: "DELETE" }, opts);
|
|
8265
8265
|
}
|
|
8266
|
-
async request(
|
|
8267
|
-
const url = buildUrl(this.apiBase,
|
|
8266
|
+
async request(path67, init, opts) {
|
|
8267
|
+
const url = buildUrl(this.apiBase, path67);
|
|
8268
8268
|
const headers = {
|
|
8269
8269
|
accept: "application/json",
|
|
8270
8270
|
...toStringRecord(init.headers)
|
|
@@ -8563,6 +8563,15 @@ var init_catalog = __esm({
|
|
|
8563
8563
|
executionMode: "export",
|
|
8564
8564
|
activationModes: ["export"],
|
|
8565
8565
|
family: "studio"
|
|
8566
|
+
},
|
|
8567
|
+
{
|
|
8568
|
+
id: "growthub-video-use-studio-v1",
|
|
8569
|
+
packageDirName: "growthub-video-use-studio-v1",
|
|
8570
|
+
defaultBundleId: "growthub-video-use-studio-v1",
|
|
8571
|
+
type: "worker",
|
|
8572
|
+
executionMode: "export",
|
|
8573
|
+
activationModes: ["export"],
|
|
8574
|
+
family: "studio"
|
|
8566
8575
|
}
|
|
8567
8576
|
];
|
|
8568
8577
|
}
|
|
@@ -9702,9 +9711,9 @@ async function fetchHostedIntegrations(session) {
|
|
|
9702
9711
|
}
|
|
9703
9712
|
async function fetchHostedIntegrationCredential(session, providerId) {
|
|
9704
9713
|
const client = toApiClient2(session);
|
|
9705
|
-
const
|
|
9714
|
+
const path67 = `${DEFAULT_INTEGRATION_CREDENTIAL_PATH}&provider=${encodeURIComponent(providerId)}`;
|
|
9706
9715
|
try {
|
|
9707
|
-
return await client.get(
|
|
9716
|
+
return await client.get(path67, { ignoreNotFound: true });
|
|
9708
9717
|
} catch (err) {
|
|
9709
9718
|
if (err instanceof ApiRequestError && (err.status === 404 || err.status === 501)) {
|
|
9710
9719
|
throw new HostedEndpointUnavailableError(err.status, err.message);
|
|
@@ -10278,13 +10287,43 @@ var init_github = __esm({
|
|
|
10278
10287
|
}
|
|
10279
10288
|
});
|
|
10280
10289
|
|
|
10281
|
-
// src/starter/
|
|
10290
|
+
// src/starter/scaffold-session-memory.ts
|
|
10282
10291
|
import fs43 from "node:fs";
|
|
10283
10292
|
import path51 from "node:path";
|
|
10293
|
+
function scaffoldSessionMemory(input) {
|
|
10294
|
+
const forkPath = path51.resolve(input.forkPath);
|
|
10295
|
+
const templatePath = path51.join(forkPath, TEMPLATE_RELATIVE);
|
|
10296
|
+
const projectMdPath = path51.join(forkPath, PROJECT_MD_RELATIVE);
|
|
10297
|
+
if (!fs43.existsSync(templatePath)) {
|
|
10298
|
+
return { written: false, projectMdPath, templatePath: null };
|
|
10299
|
+
}
|
|
10300
|
+
if (fs43.existsSync(projectMdPath)) {
|
|
10301
|
+
return { written: false, projectMdPath, templatePath };
|
|
10302
|
+
}
|
|
10303
|
+
const template = fs43.readFileSync(templatePath, "utf8");
|
|
10304
|
+
const startedAt = input.startedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
10305
|
+
const sourceRef = input.sourceRef ?? "";
|
|
10306
|
+
const seeded = template.replaceAll("{{KIT_ID}}", input.kitId).replaceAll("{{FORK_ID}}", input.forkId).replaceAll("{{STARTED_AT}}", startedAt).replaceAll("{{SOURCE}}", input.source).replaceAll("{{SOURCE_REF}}", sourceRef);
|
|
10307
|
+
fs43.mkdirSync(path51.dirname(projectMdPath), { recursive: true });
|
|
10308
|
+
fs43.writeFileSync(projectMdPath, seeded, "utf8");
|
|
10309
|
+
return { written: true, projectMdPath, templatePath };
|
|
10310
|
+
}
|
|
10311
|
+
var PROJECT_MD_RELATIVE, TEMPLATE_RELATIVE;
|
|
10312
|
+
var init_scaffold_session_memory = __esm({
|
|
10313
|
+
"src/starter/scaffold-session-memory.ts"() {
|
|
10314
|
+
"use strict";
|
|
10315
|
+
PROJECT_MD_RELATIVE = ".growthub-fork/project.md";
|
|
10316
|
+
TEMPLATE_RELATIVE = "templates/project.md";
|
|
10317
|
+
}
|
|
10318
|
+
});
|
|
10319
|
+
|
|
10320
|
+
// src/starter/init.ts
|
|
10321
|
+
import fs44 from "node:fs";
|
|
10322
|
+
import path52 from "node:path";
|
|
10284
10323
|
async function initStarterWorkspace(opts) {
|
|
10285
10324
|
const kitId = opts.kitId ?? DEFAULT_STARTER_KIT_ID;
|
|
10286
|
-
const absOut =
|
|
10287
|
-
if (
|
|
10325
|
+
const absOut = path52.resolve(opts.out);
|
|
10326
|
+
if (fs44.existsSync(absOut) && fs44.readdirSync(absOut).length > 0) {
|
|
10288
10327
|
throw new Error(`Destination ${absOut} already exists and is not empty.`);
|
|
10289
10328
|
}
|
|
10290
10329
|
const info = getBundledKitSourceInfo(kitId);
|
|
@@ -10293,7 +10332,7 @@ async function initStarterWorkspace(opts) {
|
|
|
10293
10332
|
forkPath: absOut,
|
|
10294
10333
|
kitId: info.id,
|
|
10295
10334
|
baseVersion: info.version,
|
|
10296
|
-
label: opts.name?.trim() ||
|
|
10335
|
+
label: opts.name?.trim() || path52.basename(absOut)
|
|
10297
10336
|
});
|
|
10298
10337
|
const policy = {
|
|
10299
10338
|
...makeDefaultKitForkPolicy(),
|
|
@@ -10313,6 +10352,22 @@ async function initStarterWorkspace(opts) {
|
|
|
10313
10352
|
type: "policy_updated",
|
|
10314
10353
|
summary: `Initial policy seeded (remoteSyncMode=${policy.remoteSyncMode})`
|
|
10315
10354
|
});
|
|
10355
|
+
const sessionSeed = scaffoldSessionMemory({
|
|
10356
|
+
forkPath: absOut,
|
|
10357
|
+
kitId: info.id,
|
|
10358
|
+
forkId: reg.forkId,
|
|
10359
|
+
source: "greenfield",
|
|
10360
|
+
sourceRef: ""
|
|
10361
|
+
});
|
|
10362
|
+
if (sessionSeed.written) {
|
|
10363
|
+
appendKitForkTraceEvent(absOut, {
|
|
10364
|
+
forkId: reg.forkId,
|
|
10365
|
+
kitId: reg.kitId,
|
|
10366
|
+
type: "skills_scaffolded",
|
|
10367
|
+
summary: "Seeded .growthub-fork/project.md from templates/project.md",
|
|
10368
|
+
detail: { projectMd: sessionSeed.projectMdPath }
|
|
10369
|
+
});
|
|
10370
|
+
}
|
|
10316
10371
|
let remote;
|
|
10317
10372
|
if (opts.upstream) {
|
|
10318
10373
|
const resolved = await resolveGithubAccessToken();
|
|
@@ -10374,6 +10429,7 @@ var init_init = __esm({
|
|
|
10374
10429
|
init_fork_remote();
|
|
10375
10430
|
init_github_resolver();
|
|
10376
10431
|
init_client2();
|
|
10432
|
+
init_scaffold_session_memory();
|
|
10377
10433
|
DEFAULT_STARTER_KIT_ID = "growthub-custom-workspace-starter-v1";
|
|
10378
10434
|
}
|
|
10379
10435
|
});
|
|
@@ -10386,8 +10442,8 @@ var init_types2 = __esm({
|
|
|
10386
10442
|
});
|
|
10387
10443
|
|
|
10388
10444
|
// src/starter/source-import/github-source.ts
|
|
10389
|
-
import
|
|
10390
|
-
import
|
|
10445
|
+
import fs45 from "node:fs";
|
|
10446
|
+
import path53 from "node:path";
|
|
10391
10447
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
10392
10448
|
function baseHeaders() {
|
|
10393
10449
|
return {
|
|
@@ -10518,12 +10574,12 @@ function cloneGithubRepo(input) {
|
|
|
10518
10574
|
if (!gitAvailable()) {
|
|
10519
10575
|
throw new Error("`git` is not available on PATH \u2014 cannot clone.");
|
|
10520
10576
|
}
|
|
10521
|
-
if (
|
|
10577
|
+
if (fs45.existsSync(input.destination)) {
|
|
10522
10578
|
throw new Error(`Clone destination already exists: ${input.destination}`);
|
|
10523
10579
|
}
|
|
10524
10580
|
const cloneUrl = input.token ? buildTokenCloneUrl(input.probe.repo, input.token) : input.probe.cloneUrl;
|
|
10525
|
-
const parent =
|
|
10526
|
-
|
|
10581
|
+
const parent = path53.dirname(input.destination);
|
|
10582
|
+
fs45.mkdirSync(parent, { recursive: true });
|
|
10527
10583
|
const depth = input.depth ?? 1;
|
|
10528
10584
|
const branch = input.branch ?? input.probe.defaultBranch;
|
|
10529
10585
|
const args = ["clone"];
|
|
@@ -10550,17 +10606,17 @@ function cloneGithubRepo(input) {
|
|
|
10550
10606
|
function narrowToSubdirectory(rootDir, subdirectory) {
|
|
10551
10607
|
const normalizedSub = subdirectory.replace(/^\/+|\/+$/g, "");
|
|
10552
10608
|
if (!normalizedSub) return;
|
|
10553
|
-
const abs =
|
|
10554
|
-
if (!
|
|
10609
|
+
const abs = path53.resolve(rootDir, normalizedSub);
|
|
10610
|
+
if (!fs45.existsSync(abs) || !fs45.statSync(abs).isDirectory()) {
|
|
10555
10611
|
throw new Error(`Subdirectory not found in cloned repo: ${subdirectory}`);
|
|
10556
10612
|
}
|
|
10557
|
-
const tmp =
|
|
10558
|
-
|
|
10559
|
-
`.${
|
|
10613
|
+
const tmp = path53.resolve(
|
|
10614
|
+
path53.dirname(rootDir),
|
|
10615
|
+
`.${path53.basename(rootDir)}-narrow-${Date.now().toString(36)}`
|
|
10560
10616
|
);
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10617
|
+
fs45.renameSync(abs, tmp);
|
|
10618
|
+
fs45.rmSync(rootDir, { recursive: true, force: true });
|
|
10619
|
+
fs45.renameSync(tmp, rootDir);
|
|
10564
10620
|
}
|
|
10565
10621
|
var GITHUB_API_BASE2;
|
|
10566
10622
|
var init_github_source = __esm({
|
|
@@ -10574,9 +10630,9 @@ var init_github_source = __esm({
|
|
|
10574
10630
|
});
|
|
10575
10631
|
|
|
10576
10632
|
// src/starter/source-import/skills-source.ts
|
|
10577
|
-
import
|
|
10633
|
+
import fs46 from "node:fs";
|
|
10578
10634
|
import os11 from "node:os";
|
|
10579
|
-
import
|
|
10635
|
+
import path54 from "node:path";
|
|
10580
10636
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
10581
10637
|
function resolveBase() {
|
|
10582
10638
|
const raw = process.env.SKILLS_SH_BASE?.trim();
|
|
@@ -10842,9 +10898,9 @@ async function probeSkillsSource(input) {
|
|
|
10842
10898
|
};
|
|
10843
10899
|
}
|
|
10844
10900
|
function assertInsidePayloadRoot(root, candidate) {
|
|
10845
|
-
const abs =
|
|
10846
|
-
const rootAbs =
|
|
10847
|
-
if (!abs.startsWith(rootAbs +
|
|
10901
|
+
const abs = path54.resolve(candidate);
|
|
10902
|
+
const rootAbs = path54.resolve(root);
|
|
10903
|
+
if (!abs.startsWith(rootAbs + path54.sep) && abs !== rootAbs) {
|
|
10848
10904
|
throw new Error(`Refusing to write outside payload root: ${candidate}`);
|
|
10849
10905
|
}
|
|
10850
10906
|
}
|
|
@@ -10860,24 +10916,24 @@ function runGit3(args, cwd) {
|
|
|
10860
10916
|
};
|
|
10861
10917
|
}
|
|
10862
10918
|
function skillDirectoryMatches(dir, skillSlug) {
|
|
10863
|
-
const skillFile =
|
|
10864
|
-
if (!
|
|
10919
|
+
const skillFile = path54.resolve(dir, "SKILL.md");
|
|
10920
|
+
if (!fs46.existsSync(skillFile) || !fs46.statSync(skillFile).isFile()) {
|
|
10865
10921
|
return false;
|
|
10866
10922
|
}
|
|
10867
|
-
if (
|
|
10923
|
+
if (path54.basename(dir) === skillSlug) {
|
|
10868
10924
|
return true;
|
|
10869
10925
|
}
|
|
10870
|
-
const content =
|
|
10926
|
+
const content = fs46.readFileSync(skillFile, "utf8");
|
|
10871
10927
|
const nameMatch = content.match(/(?:^|\n)name:\s*["']?([A-Za-z0-9._:-]+)["']?\s*(?:\n|$)/i);
|
|
10872
10928
|
return nameMatch?.[1] === skillSlug;
|
|
10873
10929
|
}
|
|
10874
10930
|
function locateSkillDirectory(root, skillSlug) {
|
|
10875
10931
|
const preferred = [
|
|
10876
|
-
|
|
10877
|
-
|
|
10932
|
+
path54.resolve(root, "skills", skillSlug),
|
|
10933
|
+
path54.resolve(root, skillSlug)
|
|
10878
10934
|
];
|
|
10879
10935
|
for (const candidate of preferred) {
|
|
10880
|
-
if (
|
|
10936
|
+
if (fs46.existsSync(candidate) && fs46.statSync(candidate).isDirectory() && skillDirectoryMatches(candidate, skillSlug)) {
|
|
10881
10937
|
return candidate;
|
|
10882
10938
|
}
|
|
10883
10939
|
}
|
|
@@ -10887,12 +10943,12 @@ function locateSkillDirectory(root, skillSlug) {
|
|
|
10887
10943
|
if (skillDirectoryMatches(current, skillSlug)) {
|
|
10888
10944
|
return current;
|
|
10889
10945
|
}
|
|
10890
|
-
for (const entry of
|
|
10946
|
+
for (const entry of fs46.readdirSync(current, { withFileTypes: true })) {
|
|
10891
10947
|
if (!entry.isDirectory()) continue;
|
|
10892
10948
|
if ([".git", "node_modules", ".next", "dist", "build", "coverage"].includes(entry.name)) {
|
|
10893
10949
|
continue;
|
|
10894
10950
|
}
|
|
10895
|
-
queue.push(
|
|
10951
|
+
queue.push(path54.resolve(current, entry.name));
|
|
10896
10952
|
}
|
|
10897
10953
|
}
|
|
10898
10954
|
return null;
|
|
@@ -10902,18 +10958,18 @@ function copySkillTree(sourceDir, destination) {
|
|
|
10902
10958
|
const stack = [{ from: sourceDir, to: destination }];
|
|
10903
10959
|
while (stack.length > 0) {
|
|
10904
10960
|
const current = stack.pop();
|
|
10905
|
-
|
|
10906
|
-
for (const entry of
|
|
10907
|
-
const fromPath =
|
|
10908
|
-
const toPath =
|
|
10961
|
+
fs46.mkdirSync(current.to, { recursive: true });
|
|
10962
|
+
for (const entry of fs46.readdirSync(current.from, { withFileTypes: true })) {
|
|
10963
|
+
const fromPath = path54.resolve(current.from, entry.name);
|
|
10964
|
+
const toPath = path54.resolve(current.to, entry.name);
|
|
10909
10965
|
assertInsidePayloadRoot(destination, toPath);
|
|
10910
10966
|
if (entry.isDirectory()) {
|
|
10911
10967
|
stack.push({ from: fromPath, to: toPath });
|
|
10912
10968
|
continue;
|
|
10913
10969
|
}
|
|
10914
|
-
const data =
|
|
10915
|
-
|
|
10916
|
-
|
|
10970
|
+
const data = fs46.readFileSync(fromPath);
|
|
10971
|
+
fs46.mkdirSync(path54.dirname(toPath), { recursive: true });
|
|
10972
|
+
fs46.writeFileSync(toPath, data, { mode: 420 });
|
|
10917
10973
|
written += 1;
|
|
10918
10974
|
}
|
|
10919
10975
|
}
|
|
@@ -10924,7 +10980,7 @@ async function fetchSkillPayload(input) {
|
|
|
10924
10980
|
if (!gitAvailable()) {
|
|
10925
10981
|
throw new Error("`git` is not available on PATH \u2014 cannot materialize a skills.sh payload.");
|
|
10926
10982
|
}
|
|
10927
|
-
if (
|
|
10983
|
+
if (fs46.existsSync(destination)) {
|
|
10928
10984
|
throw new Error(`Skill payload destination already exists: ${destination}`);
|
|
10929
10985
|
}
|
|
10930
10986
|
const repoSource = probe.repoUrl ?? (probe.repository ? `https://github.com/${probe.repository}` : void 0);
|
|
@@ -10932,11 +10988,11 @@ async function fetchSkillPayload(input) {
|
|
|
10932
10988
|
if (!repoSource || !skillSlug) {
|
|
10933
10989
|
throw new Error(`Skill '${probe.skillId}' is missing repository metadata \u2014 cannot materialize payload.`);
|
|
10934
10990
|
}
|
|
10935
|
-
const cloneRoot =
|
|
10936
|
-
|
|
10991
|
+
const cloneRoot = fs46.mkdtempSync(
|
|
10992
|
+
path54.join(os11.tmpdir(), "growthub-skills-source-")
|
|
10937
10993
|
);
|
|
10938
10994
|
try {
|
|
10939
|
-
const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot],
|
|
10995
|
+
const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot], path54.dirname(cloneRoot));
|
|
10940
10996
|
if (!cloneRes.ok) {
|
|
10941
10997
|
throw new Error(`git clone failed: ${cloneRes.stderr || "unable to clone skill repository"}`);
|
|
10942
10998
|
}
|
|
@@ -10949,7 +11005,7 @@ async function fetchSkillPayload(input) {
|
|
|
10949
11005
|
const fileCount = copySkillTree(skillDir, destination);
|
|
10950
11006
|
return { destination, fileCount };
|
|
10951
11007
|
} finally {
|
|
10952
|
-
|
|
11008
|
+
fs46.rmSync(cloneRoot, { recursive: true, force: true });
|
|
10953
11009
|
}
|
|
10954
11010
|
}
|
|
10955
11011
|
var DEFAULT_BASE, COMMENT_PATTERN;
|
|
@@ -10963,13 +11019,13 @@ var init_skills_source = __esm({
|
|
|
10963
11019
|
});
|
|
10964
11020
|
|
|
10965
11021
|
// src/starter/source-import/detect.ts
|
|
10966
|
-
import
|
|
10967
|
-
import
|
|
11022
|
+
import fs47 from "node:fs";
|
|
11023
|
+
import path55 from "node:path";
|
|
10968
11024
|
function safeReadPackageJson(dir) {
|
|
10969
|
-
const p35 =
|
|
10970
|
-
if (!
|
|
11025
|
+
const p35 = path55.resolve(dir, "package.json");
|
|
11026
|
+
if (!fs47.existsSync(p35)) return null;
|
|
10971
11027
|
try {
|
|
10972
|
-
return JSON.parse(
|
|
11028
|
+
return JSON.parse(fs47.readFileSync(p35, "utf8"));
|
|
10973
11029
|
} catch {
|
|
10974
11030
|
return null;
|
|
10975
11031
|
}
|
|
@@ -10979,10 +11035,10 @@ function detectPackageManager(dir, pkg) {
|
|
|
10979
11035
|
if (pkg?.packageManager?.startsWith("yarn")) return "yarn";
|
|
10980
11036
|
if (pkg?.packageManager?.startsWith("npm")) return "npm";
|
|
10981
11037
|
if (pkg?.packageManager?.startsWith("bun")) return "bun";
|
|
10982
|
-
if (
|
|
10983
|
-
if (
|
|
10984
|
-
if (
|
|
10985
|
-
if (
|
|
11038
|
+
if (fs47.existsSync(path55.resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
11039
|
+
if (fs47.existsSync(path55.resolve(dir, "yarn.lock"))) return "yarn";
|
|
11040
|
+
if (fs47.existsSync(path55.resolve(dir, "bun.lockb"))) return "bun";
|
|
11041
|
+
if (fs47.existsSync(path55.resolve(dir, "package-lock.json"))) return "npm";
|
|
10986
11042
|
return "unknown";
|
|
10987
11043
|
}
|
|
10988
11044
|
function collectDeps(pkg) {
|
|
@@ -10996,12 +11052,12 @@ function collectDeps(pkg) {
|
|
|
10996
11052
|
}
|
|
10997
11053
|
function looksLikeSkillPayload(rootDir) {
|
|
10998
11054
|
const markers = ["SKILL.md", "skill.md", "skill.json", "skill.yml", "skill.yaml", "prompt.md"];
|
|
10999
|
-
return markers.some((name) =>
|
|
11055
|
+
return markers.some((name) => fs47.existsSync(path55.resolve(rootDir, name)));
|
|
11000
11056
|
}
|
|
11001
11057
|
function detectFramework(rootDir, pkg) {
|
|
11002
11058
|
if (!pkg) {
|
|
11003
11059
|
if (looksLikeSkillPayload(rootDir)) return "skill";
|
|
11004
|
-
if (
|
|
11060
|
+
if (fs47.existsSync(path55.resolve(rootDir, "docs"))) return "docs";
|
|
11005
11061
|
return "unknown";
|
|
11006
11062
|
}
|
|
11007
11063
|
const deps = collectDeps(pkg);
|
|
@@ -11010,8 +11066,8 @@ function detectFramework(rootDir, pkg) {
|
|
|
11010
11066
|
"vite.config.ts",
|
|
11011
11067
|
"vite.config.mjs",
|
|
11012
11068
|
"vite.config.cjs"
|
|
11013
|
-
].some((name) =>
|
|
11014
|
-
if (deps.has("next") ||
|
|
11069
|
+
].some((name) => fs47.existsSync(path55.resolve(rootDir, name)));
|
|
11070
|
+
if (deps.has("next") || fs47.existsSync(path55.resolve(rootDir, "next.config.js")) || fs47.existsSync(path55.resolve(rootDir, "next.config.mjs"))) {
|
|
11015
11071
|
return "next";
|
|
11016
11072
|
}
|
|
11017
11073
|
if (deps.has("vite") || hasViteConfig) return "vite";
|
|
@@ -11037,15 +11093,15 @@ function pickScripts(pkg) {
|
|
|
11037
11093
|
return out;
|
|
11038
11094
|
}
|
|
11039
11095
|
function listEnvFiles(dir) {
|
|
11040
|
-
if (!
|
|
11041
|
-
return
|
|
11096
|
+
if (!fs47.existsSync(dir)) return [];
|
|
11097
|
+
return fs47.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).filter((name) => name === ".env" || name.startsWith(".env.") || name === ".env.example");
|
|
11042
11098
|
}
|
|
11043
11099
|
function findAppRoot(rootDir, pkg) {
|
|
11044
11100
|
if (pkg) return ".";
|
|
11045
11101
|
const candidates = ["app", "src", "apps", "packages"];
|
|
11046
11102
|
for (const candidate of candidates) {
|
|
11047
|
-
const abs =
|
|
11048
|
-
if (
|
|
11103
|
+
const abs = path55.resolve(rootDir, candidate);
|
|
11104
|
+
if (fs47.existsSync(abs) && fs47.statSync(abs).isDirectory()) {
|
|
11049
11105
|
const child = safeReadPackageJson(abs);
|
|
11050
11106
|
if (child) return candidate;
|
|
11051
11107
|
}
|
|
@@ -11061,12 +11117,12 @@ function computeConfidence(framework, manager, pkg) {
|
|
|
11061
11117
|
return Math.min(1, Number(score.toFixed(2)));
|
|
11062
11118
|
}
|
|
11063
11119
|
function detectSourceShape(rootDir) {
|
|
11064
|
-
if (!
|
|
11120
|
+
if (!fs47.existsSync(rootDir) || !fs47.statSync(rootDir).isDirectory()) {
|
|
11065
11121
|
throw new Error(`Detection target is not a directory: ${rootDir}`);
|
|
11066
11122
|
}
|
|
11067
11123
|
const rootPkg = safeReadPackageJson(rootDir);
|
|
11068
11124
|
const appRootRel = findAppRoot(rootDir, rootPkg);
|
|
11069
|
-
const appRootAbs =
|
|
11125
|
+
const appRootAbs = path55.resolve(rootDir, appRootRel);
|
|
11070
11126
|
const appPkg = appRootRel === "." ? rootPkg : safeReadPackageJson(appRootAbs);
|
|
11071
11127
|
const framework = detectFramework(appRootAbs, appPkg ?? rootPkg);
|
|
11072
11128
|
const packageManager = detectPackageManager(rootDir, rootPkg ?? appPkg);
|
|
@@ -11106,18 +11162,18 @@ var init_detect = __esm({
|
|
|
11106
11162
|
});
|
|
11107
11163
|
|
|
11108
11164
|
// src/starter/source-import/security.ts
|
|
11109
|
-
import
|
|
11110
|
-
import
|
|
11165
|
+
import fs48 from "node:fs";
|
|
11166
|
+
import path56 from "node:path";
|
|
11111
11167
|
function isLikelyTextFile(filename) {
|
|
11112
|
-
const ext =
|
|
11168
|
+
const ext = path56.extname(filename).toLowerCase();
|
|
11113
11169
|
if (!ext) return true;
|
|
11114
11170
|
return TEXT_EXTENSIONS.has(ext);
|
|
11115
11171
|
}
|
|
11116
11172
|
function isSuspiciousBinary(filename) {
|
|
11117
|
-
return SUSPICIOUS_BINARY_EXTENSIONS.has(
|
|
11173
|
+
return SUSPICIOUS_BINARY_EXTENSIONS.has(path56.extname(filename).toLowerCase());
|
|
11118
11174
|
}
|
|
11119
11175
|
function isUnexpectedArchive(filename) {
|
|
11120
|
-
const ext =
|
|
11176
|
+
const ext = path56.extname(filename).toLowerCase();
|
|
11121
11177
|
return ARCHIVE_EXTENSIONS.has(ext) || filename.toLowerCase().endsWith(".tar.gz");
|
|
11122
11178
|
}
|
|
11123
11179
|
function shortExcerpt(line) {
|
|
@@ -11172,19 +11228,19 @@ function walkPayload(root, onFile, limits) {
|
|
|
11172
11228
|
if (!current) break;
|
|
11173
11229
|
let entries;
|
|
11174
11230
|
try {
|
|
11175
|
-
entries =
|
|
11231
|
+
entries = fs48.readdirSync(current, { withFileTypes: true });
|
|
11176
11232
|
} catch {
|
|
11177
11233
|
continue;
|
|
11178
11234
|
}
|
|
11179
11235
|
for (const entry of entries) {
|
|
11180
|
-
const abs =
|
|
11236
|
+
const abs = path56.resolve(current, entry.name);
|
|
11181
11237
|
if (entry.isDirectory()) {
|
|
11182
11238
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
11183
11239
|
stack.push(abs);
|
|
11184
11240
|
continue;
|
|
11185
11241
|
}
|
|
11186
11242
|
if (!entry.isFile()) continue;
|
|
11187
|
-
const rel =
|
|
11243
|
+
const rel = path56.relative(root, abs);
|
|
11188
11244
|
onFile(abs, rel);
|
|
11189
11245
|
visited += 1;
|
|
11190
11246
|
if (visited >= limits.maxFiles) break;
|
|
@@ -11194,7 +11250,7 @@ function walkPayload(root, onFile, limits) {
|
|
|
11194
11250
|
}
|
|
11195
11251
|
function inspectSourcePayload(input) {
|
|
11196
11252
|
const { payloadRoot } = input;
|
|
11197
|
-
if (!
|
|
11253
|
+
if (!fs48.existsSync(payloadRoot) || !fs48.statSync(payloadRoot).isDirectory()) {
|
|
11198
11254
|
throw new Error(`Inspection target is not a directory: ${payloadRoot}`);
|
|
11199
11255
|
}
|
|
11200
11256
|
const findings = [];
|
|
@@ -11204,7 +11260,7 @@ function inspectSourcePayload(input) {
|
|
|
11204
11260
|
(abs, rel) => {
|
|
11205
11261
|
let size = 0;
|
|
11206
11262
|
try {
|
|
11207
|
-
size =
|
|
11263
|
+
size = fs48.statSync(abs).size;
|
|
11208
11264
|
} catch {
|
|
11209
11265
|
return;
|
|
11210
11266
|
}
|
|
@@ -11213,7 +11269,7 @@ function inspectSourcePayload(input) {
|
|
|
11213
11269
|
category: "suspicious-binary",
|
|
11214
11270
|
severity: "high-risk",
|
|
11215
11271
|
path: rel,
|
|
11216
|
-
message: `Payload ships a precompiled binary (${
|
|
11272
|
+
message: `Payload ships a precompiled binary (${path56.extname(rel)}). Review provenance before use.`
|
|
11217
11273
|
});
|
|
11218
11274
|
return;
|
|
11219
11275
|
}
|
|
@@ -11222,7 +11278,7 @@ function inspectSourcePayload(input) {
|
|
|
11222
11278
|
category: "unexpected-archive",
|
|
11223
11279
|
severity: "caution",
|
|
11224
11280
|
path: rel,
|
|
11225
|
-
message: `Payload ships an archive (${
|
|
11281
|
+
message: `Payload ships an archive (${path56.extname(rel)}) \u2014 expand and review contents before use.`
|
|
11226
11282
|
});
|
|
11227
11283
|
return;
|
|
11228
11284
|
}
|
|
@@ -11230,12 +11286,12 @@ function inspectSourcePayload(input) {
|
|
|
11230
11286
|
if (bytesInspected + Math.min(size, MAX_BYTES_PER_FILE) > MAX_TOTAL_BYTES) return;
|
|
11231
11287
|
let buf;
|
|
11232
11288
|
try {
|
|
11233
|
-
const handle =
|
|
11289
|
+
const handle = fs48.openSync(abs, "r");
|
|
11234
11290
|
try {
|
|
11235
11291
|
buf = Buffer.alloc(Math.min(size, MAX_BYTES_PER_FILE));
|
|
11236
|
-
|
|
11292
|
+
fs48.readSync(handle, buf, 0, buf.length, 0);
|
|
11237
11293
|
} finally {
|
|
11238
|
-
|
|
11294
|
+
fs48.closeSync(handle);
|
|
11239
11295
|
}
|
|
11240
11296
|
} catch {
|
|
11241
11297
|
return;
|
|
@@ -11444,18 +11500,18 @@ var init_security = __esm({
|
|
|
11444
11500
|
});
|
|
11445
11501
|
|
|
11446
11502
|
// src/starter/source-import/plan.ts
|
|
11447
|
-
import
|
|
11448
|
-
import
|
|
11503
|
+
import fs49 from "node:fs";
|
|
11504
|
+
import path57 from "node:path";
|
|
11449
11505
|
function generateImportId() {
|
|
11450
11506
|
return `si-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
|
|
11451
11507
|
}
|
|
11452
11508
|
function destinationState(absDest) {
|
|
11453
|
-
if (!
|
|
11454
|
-
const stats =
|
|
11509
|
+
if (!fs49.existsSync(absDest)) return { exists: false, nonEmpty: false };
|
|
11510
|
+
const stats = fs49.statSync(absDest);
|
|
11455
11511
|
if (!stats.isDirectory()) {
|
|
11456
11512
|
throw new Error(`Destination is not a directory: ${absDest}`);
|
|
11457
11513
|
}
|
|
11458
|
-
const entries =
|
|
11514
|
+
const entries = fs49.readdirSync(absDest);
|
|
11459
11515
|
return { exists: true, nonEmpty: entries.length > 0 };
|
|
11460
11516
|
}
|
|
11461
11517
|
function describeSource(probe) {
|
|
@@ -11465,7 +11521,7 @@ function describeSource(probe) {
|
|
|
11465
11521
|
return `skill ${probe.skillId}@${probe.version} (skills.sh)`;
|
|
11466
11522
|
}
|
|
11467
11523
|
function buildSourceImportPlan(input) {
|
|
11468
|
-
const absDest =
|
|
11524
|
+
const absDest = path57.resolve(input.destination);
|
|
11469
11525
|
const state = destinationState(absDest);
|
|
11470
11526
|
const payloadPath = "imported";
|
|
11471
11527
|
const warnings = [...input.probe.warnings];
|
|
@@ -11578,8 +11634,8 @@ var init_plan = __esm({
|
|
|
11578
11634
|
});
|
|
11579
11635
|
|
|
11580
11636
|
// src/starter/source-import/summarize.ts
|
|
11581
|
-
import
|
|
11582
|
-
import
|
|
11637
|
+
import fs50 from "node:fs";
|
|
11638
|
+
import path58 from "node:path";
|
|
11583
11639
|
function sourceHeading(manifest) {
|
|
11584
11640
|
const src = manifest.source;
|
|
11585
11641
|
if (src.kind === "github-repo") {
|
|
@@ -11634,7 +11690,7 @@ function nextStepsSection(manifest) {
|
|
|
11634
11690
|
}
|
|
11635
11691
|
function writeImportSummary(input) {
|
|
11636
11692
|
const { forkPath, summaryRelativePath, manifest } = input;
|
|
11637
|
-
const summaryPath =
|
|
11693
|
+
const summaryPath = path58.resolve(forkPath, summaryRelativePath);
|
|
11638
11694
|
const body = [
|
|
11639
11695
|
`# Source Import Summary`,
|
|
11640
11696
|
``,
|
|
@@ -11664,8 +11720,8 @@ function writeImportSummary(input) {
|
|
|
11664
11720
|
`Generated by the Growthub Source Import Agent. Canonical manifest lives at \`.growthub-fork/source-import.json\`.`,
|
|
11665
11721
|
``
|
|
11666
11722
|
].join("\n");
|
|
11667
|
-
|
|
11668
|
-
|
|
11723
|
+
fs50.mkdirSync(path58.dirname(summaryPath), { recursive: true });
|
|
11724
|
+
fs50.writeFileSync(summaryPath, body, "utf8");
|
|
11669
11725
|
return summaryPath;
|
|
11670
11726
|
}
|
|
11671
11727
|
var init_summarize = __esm({
|
|
@@ -11675,16 +11731,16 @@ var init_summarize = __esm({
|
|
|
11675
11731
|
});
|
|
11676
11732
|
|
|
11677
11733
|
// src/starter/source-import/materialize.ts
|
|
11678
|
-
import
|
|
11734
|
+
import fs51 from "node:fs";
|
|
11679
11735
|
import os12 from "node:os";
|
|
11680
|
-
import
|
|
11736
|
+
import path59 from "node:path";
|
|
11681
11737
|
function resolveSourceKind(probe) {
|
|
11682
11738
|
return probe.kind === "github-repo" ? "github-repo" : "skills-skill";
|
|
11683
11739
|
}
|
|
11684
11740
|
function stagingDirFor(forkPath) {
|
|
11685
|
-
return
|
|
11741
|
+
return path59.join(
|
|
11686
11742
|
os12.tmpdir(),
|
|
11687
|
-
`growthub-source-import-${
|
|
11743
|
+
`growthub-source-import-${path59.basename(forkPath)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
|
|
11688
11744
|
);
|
|
11689
11745
|
}
|
|
11690
11746
|
async function fetchPayload(probe, stagingDir, opts) {
|
|
@@ -11716,18 +11772,18 @@ async function fetchPayload(probe, stagingDir, opts) {
|
|
|
11716
11772
|
return { payloadRoot: stagingDir };
|
|
11717
11773
|
}
|
|
11718
11774
|
function movePayloadIntoFork(payloadRoot, forkPath, payloadRelativePath) {
|
|
11719
|
-
const target =
|
|
11720
|
-
if (
|
|
11721
|
-
|
|
11775
|
+
const target = path59.resolve(forkPath, payloadRelativePath);
|
|
11776
|
+
if (fs51.existsSync(target)) {
|
|
11777
|
+
fs51.rmSync(target, { recursive: true, force: true });
|
|
11722
11778
|
}
|
|
11723
|
-
|
|
11724
|
-
|
|
11779
|
+
fs51.mkdirSync(path59.dirname(target), { recursive: true });
|
|
11780
|
+
fs51.renameSync(payloadRoot, target);
|
|
11725
11781
|
return target;
|
|
11726
11782
|
}
|
|
11727
11783
|
function writeManifest(forkPath, manifest) {
|
|
11728
|
-
const p35 =
|
|
11729
|
-
|
|
11730
|
-
|
|
11784
|
+
const p35 = path59.resolve(forkPath, MANIFEST_RELATIVE_PATH);
|
|
11785
|
+
fs51.mkdirSync(path59.dirname(p35), { recursive: true });
|
|
11786
|
+
fs51.writeFileSync(p35, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
11731
11787
|
return p35;
|
|
11732
11788
|
}
|
|
11733
11789
|
function assertConfirmationsSatisfied(plan, confirmations) {
|
|
@@ -11767,7 +11823,7 @@ async function materializeImportPlan(input) {
|
|
|
11767
11823
|
requireSkillAcknowledgement: sourceKind === "skills-skill"
|
|
11768
11824
|
});
|
|
11769
11825
|
if (security.blocked) {
|
|
11770
|
-
|
|
11826
|
+
fs51.rmSync(fetchResult.payloadRoot, { recursive: true, force: true });
|
|
11771
11827
|
throw new Error(
|
|
11772
11828
|
`Security inspection blocked the fetched payload: ${security.summaryLines[0] ?? "blocking finding"}`
|
|
11773
11829
|
);
|
|
@@ -11846,6 +11902,22 @@ async function materializeImportPlan(input) {
|
|
|
11846
11902
|
detail: { gitSha: fetchResult.gitSha }
|
|
11847
11903
|
});
|
|
11848
11904
|
}
|
|
11905
|
+
const sessionSeed = scaffoldSessionMemory({
|
|
11906
|
+
forkPath,
|
|
11907
|
+
kitId: kitInfo.id,
|
|
11908
|
+
forkId: reg.forkId,
|
|
11909
|
+
source: sourceKind,
|
|
11910
|
+
sourceRef: plan.source.kind === "github-repo" ? `${plan.source.repo.owner}/${plan.source.repo.repo}${fetchResult.gitSha ? `@${fetchResult.gitSha.slice(0, 7)}` : ""}` : `${plan.source.skillId}@${plan.source.version}`
|
|
11911
|
+
});
|
|
11912
|
+
if (sessionSeed.written) {
|
|
11913
|
+
appendKitForkTraceEvent(forkPath, {
|
|
11914
|
+
forkId: reg.forkId,
|
|
11915
|
+
kitId: reg.kitId,
|
|
11916
|
+
type: "skills_scaffolded",
|
|
11917
|
+
summary: "Seeded .growthub-fork/project.md from templates/project.md",
|
|
11918
|
+
detail: { projectMd: sessionSeed.projectMdPath }
|
|
11919
|
+
});
|
|
11920
|
+
}
|
|
11849
11921
|
const summaryPath = writeImportSummary({
|
|
11850
11922
|
forkPath,
|
|
11851
11923
|
summaryRelativePath: SUMMARY_RELATIVE_PATH,
|
|
@@ -11882,6 +11954,7 @@ var init_materialize = __esm({
|
|
|
11882
11954
|
init_detect();
|
|
11883
11955
|
init_security();
|
|
11884
11956
|
init_summarize();
|
|
11957
|
+
init_scaffold_session_memory();
|
|
11885
11958
|
MANIFEST_RELATIVE_PATH = ".growthub-fork/source-import.json";
|
|
11886
11959
|
SUMMARY_RELATIVE_PATH = "IMPORT_SUMMARY.md";
|
|
11887
11960
|
PendingConfirmationError = class extends Error {
|
|
@@ -11898,26 +11971,26 @@ var init_materialize = __esm({
|
|
|
11898
11971
|
});
|
|
11899
11972
|
|
|
11900
11973
|
// src/starter/source-import/agent.ts
|
|
11901
|
-
import
|
|
11902
|
-
import
|
|
11974
|
+
import fs52 from "node:fs";
|
|
11975
|
+
import path60 from "node:path";
|
|
11903
11976
|
function resolveJobsDir() {
|
|
11904
|
-
return
|
|
11977
|
+
return path60.resolve(resolveKitForksHomeDir(), "source-import-jobs");
|
|
11905
11978
|
}
|
|
11906
11979
|
function resolveJobPath2(jobId) {
|
|
11907
|
-
return
|
|
11980
|
+
return path60.resolve(resolveJobsDir(), `${jobId}.json`);
|
|
11908
11981
|
}
|
|
11909
11982
|
function generateJobId2() {
|
|
11910
11983
|
return `sij-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
|
|
11911
11984
|
}
|
|
11912
11985
|
function writeJob2(job) {
|
|
11913
11986
|
const p35 = resolveJobPath2(job.jobId);
|
|
11914
|
-
|
|
11915
|
-
|
|
11987
|
+
fs52.mkdirSync(path60.dirname(p35), { recursive: true });
|
|
11988
|
+
fs52.writeFileSync(p35, JSON.stringify(job, null, 2) + "\n", "utf8");
|
|
11916
11989
|
}
|
|
11917
11990
|
function readJobFile(p35) {
|
|
11918
|
-
if (!
|
|
11991
|
+
if (!fs52.existsSync(p35)) return null;
|
|
11919
11992
|
try {
|
|
11920
|
-
return JSON.parse(
|
|
11993
|
+
return JSON.parse(fs52.readFileSync(p35, "utf8"));
|
|
11921
11994
|
} catch {
|
|
11922
11995
|
return null;
|
|
11923
11996
|
}
|
|
@@ -11927,7 +12000,7 @@ function patchJob2(jobId, status, patch = {}) {
|
|
|
11927
12000
|
const job = readJobFile(p35);
|
|
11928
12001
|
if (!job) return null;
|
|
11929
12002
|
const updated = { ...job, ...patch, status };
|
|
11930
|
-
|
|
12003
|
+
fs52.writeFileSync(p35, JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
11931
12004
|
return updated;
|
|
11932
12005
|
}
|
|
11933
12006
|
function getSourceImportJob(jobId) {
|
|
@@ -11946,7 +12019,7 @@ async function probeAndPlan(input, destination) {
|
|
|
11946
12019
|
}
|
|
11947
12020
|
async function runSourceImportJob(input) {
|
|
11948
12021
|
const jobId = generateJobId2();
|
|
11949
|
-
const destination =
|
|
12022
|
+
const destination = path60.resolve(input.out);
|
|
11950
12023
|
const sourceKind = input.source.kind;
|
|
11951
12024
|
const initial = {
|
|
11952
12025
|
jobId,
|
|
@@ -12094,6 +12167,357 @@ var init_source_import = __esm({
|
|
|
12094
12167
|
}
|
|
12095
12168
|
});
|
|
12096
12169
|
|
|
12170
|
+
// src/skills/frontmatter.ts
|
|
12171
|
+
function splitFrontmatter(text69) {
|
|
12172
|
+
const normalised = text69.replace(/\r\n/g, "\n");
|
|
12173
|
+
if (!normalised.startsWith("---\n")) {
|
|
12174
|
+
return { frontmatter: null, body: normalised };
|
|
12175
|
+
}
|
|
12176
|
+
const end = normalised.indexOf("\n---\n", 4);
|
|
12177
|
+
if (end === -1) {
|
|
12178
|
+
return { frontmatter: null, body: normalised };
|
|
12179
|
+
}
|
|
12180
|
+
return {
|
|
12181
|
+
frontmatter: normalised.slice(4, end),
|
|
12182
|
+
body: normalised.slice(end + 5)
|
|
12183
|
+
};
|
|
12184
|
+
}
|
|
12185
|
+
function parseScalar(raw) {
|
|
12186
|
+
const trimmed = raw.trim();
|
|
12187
|
+
if (trimmed === "") return "";
|
|
12188
|
+
if (trimmed === "true") return true;
|
|
12189
|
+
if (trimmed === "false") return false;
|
|
12190
|
+
if (trimmed === "null" || trimmed === "~") return null;
|
|
12191
|
+
if (/^-?\d+$/.test(trimmed)) return Number(trimmed);
|
|
12192
|
+
if (/^-?\d*\.\d+$/.test(trimmed)) return Number(trimmed);
|
|
12193
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
12194
|
+
return trimmed.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
12195
|
+
}
|
|
12196
|
+
if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
12197
|
+
return trimmed.slice(1, -1).replace(/''/g, "'");
|
|
12198
|
+
}
|
|
12199
|
+
return trimmed;
|
|
12200
|
+
}
|
|
12201
|
+
function indentWidth(line) {
|
|
12202
|
+
const match = line.match(/^( *)/);
|
|
12203
|
+
return match ? match[1].length : 0;
|
|
12204
|
+
}
|
|
12205
|
+
function parseFrontmatter(text69) {
|
|
12206
|
+
const lines = text69.split("\n");
|
|
12207
|
+
const root = {};
|
|
12208
|
+
let i = 0;
|
|
12209
|
+
function readBlock(baseIndent) {
|
|
12210
|
+
const out = {};
|
|
12211
|
+
const arr = [];
|
|
12212
|
+
let mode = null;
|
|
12213
|
+
while (i < lines.length) {
|
|
12214
|
+
const line = lines[i];
|
|
12215
|
+
if (line.trim() === "" || line.trimStart().startsWith("#")) {
|
|
12216
|
+
i++;
|
|
12217
|
+
continue;
|
|
12218
|
+
}
|
|
12219
|
+
const indent = indentWidth(line);
|
|
12220
|
+
if (indent < baseIndent) break;
|
|
12221
|
+
if (indent > baseIndent) {
|
|
12222
|
+
i++;
|
|
12223
|
+
continue;
|
|
12224
|
+
}
|
|
12225
|
+
const trimmed = line.slice(baseIndent);
|
|
12226
|
+
if (trimmed.startsWith("- ")) {
|
|
12227
|
+
mode = "array";
|
|
12228
|
+
const after = trimmed.slice(2);
|
|
12229
|
+
const colonAt2 = findTopLevelColon(after);
|
|
12230
|
+
if (colonAt2 === -1) {
|
|
12231
|
+
arr.push(parseScalar(after));
|
|
12232
|
+
i++;
|
|
12233
|
+
} else {
|
|
12234
|
+
const firstKey = after.slice(0, colonAt2).trim();
|
|
12235
|
+
const firstRaw = after.slice(colonAt2 + 1).trim();
|
|
12236
|
+
const obj = {};
|
|
12237
|
+
if (firstRaw === "") {
|
|
12238
|
+
i++;
|
|
12239
|
+
obj[firstKey] = readBlock(baseIndent + 2 + 2);
|
|
12240
|
+
} else {
|
|
12241
|
+
obj[firstKey] = parseScalar(firstRaw);
|
|
12242
|
+
i++;
|
|
12243
|
+
}
|
|
12244
|
+
while (i < lines.length) {
|
|
12245
|
+
const peek = lines[i];
|
|
12246
|
+
if (peek.trim() === "" || peek.trimStart().startsWith("#")) {
|
|
12247
|
+
i++;
|
|
12248
|
+
continue;
|
|
12249
|
+
}
|
|
12250
|
+
const pInd = indentWidth(peek);
|
|
12251
|
+
if (pInd < baseIndent + 2) break;
|
|
12252
|
+
if (peek.slice(baseIndent).startsWith("- ")) break;
|
|
12253
|
+
const cTrimmed = peek.slice(baseIndent + 2);
|
|
12254
|
+
const cColon = findTopLevelColon(cTrimmed);
|
|
12255
|
+
if (cColon === -1) {
|
|
12256
|
+
i++;
|
|
12257
|
+
continue;
|
|
12258
|
+
}
|
|
12259
|
+
const cKey = cTrimmed.slice(0, cColon).trim();
|
|
12260
|
+
const cRaw = cTrimmed.slice(cColon + 1).trim();
|
|
12261
|
+
if (cRaw === "") {
|
|
12262
|
+
i++;
|
|
12263
|
+
obj[cKey] = readBlock(baseIndent + 2 + 2);
|
|
12264
|
+
} else {
|
|
12265
|
+
obj[cKey] = parseScalar(cRaw);
|
|
12266
|
+
i++;
|
|
12267
|
+
}
|
|
12268
|
+
}
|
|
12269
|
+
arr.push(obj);
|
|
12270
|
+
}
|
|
12271
|
+
continue;
|
|
12272
|
+
}
|
|
12273
|
+
mode = "object";
|
|
12274
|
+
const colonAt = findTopLevelColon(trimmed);
|
|
12275
|
+
if (colonAt === -1) {
|
|
12276
|
+
throw new Error(`Malformed frontmatter (expected "key: value") at line ${i + 1}: ${JSON.stringify(line)}`);
|
|
12277
|
+
}
|
|
12278
|
+
const key = trimmed.slice(0, colonAt).trim();
|
|
12279
|
+
const rest = trimmed.slice(colonAt + 1).trim();
|
|
12280
|
+
if (rest === "") {
|
|
12281
|
+
i++;
|
|
12282
|
+
out[key] = readBlock(baseIndent + 2);
|
|
12283
|
+
} else if (rest.startsWith("[") && rest.endsWith("]")) {
|
|
12284
|
+
const inner = rest.slice(1, -1).trim();
|
|
12285
|
+
out[key] = inner === "" ? [] : inner.split(",").map((s) => parseScalar(s));
|
|
12286
|
+
i++;
|
|
12287
|
+
} else {
|
|
12288
|
+
out[key] = parseScalar(rest);
|
|
12289
|
+
i++;
|
|
12290
|
+
}
|
|
12291
|
+
}
|
|
12292
|
+
if (mode === "array") return arr;
|
|
12293
|
+
return out;
|
|
12294
|
+
}
|
|
12295
|
+
const parsed = readBlock(0);
|
|
12296
|
+
if (Array.isArray(parsed)) {
|
|
12297
|
+
throw new Error("Frontmatter root must be an object, not a list.");
|
|
12298
|
+
}
|
|
12299
|
+
Object.assign(root, parsed);
|
|
12300
|
+
return root;
|
|
12301
|
+
}
|
|
12302
|
+
function findTopLevelColon(s) {
|
|
12303
|
+
let inDouble = false;
|
|
12304
|
+
let inSingle = false;
|
|
12305
|
+
for (let idx = 0; idx < s.length; idx++) {
|
|
12306
|
+
const ch = s[idx];
|
|
12307
|
+
const prev = idx > 0 ? s[idx - 1] : "";
|
|
12308
|
+
if (ch === '"' && prev !== "\\" && !inSingle) inDouble = !inDouble;
|
|
12309
|
+
if (ch === "'" && !inDouble) inSingle = !inSingle;
|
|
12310
|
+
if (ch === ":" && !inDouble && !inSingle) {
|
|
12311
|
+
if (idx + 1 >= s.length || s[idx + 1] === " " || s[idx + 1] === " ") return idx;
|
|
12312
|
+
}
|
|
12313
|
+
}
|
|
12314
|
+
return -1;
|
|
12315
|
+
}
|
|
12316
|
+
function readFrontmatter(text69) {
|
|
12317
|
+
const split = splitFrontmatter(text69);
|
|
12318
|
+
if (split.frontmatter === null) return { frontmatter: null, body: split.body };
|
|
12319
|
+
return { frontmatter: parseFrontmatter(split.frontmatter), body: split.body };
|
|
12320
|
+
}
|
|
12321
|
+
var init_frontmatter = __esm({
|
|
12322
|
+
"src/skills/frontmatter.ts"() {
|
|
12323
|
+
"use strict";
|
|
12324
|
+
}
|
|
12325
|
+
});
|
|
12326
|
+
|
|
12327
|
+
// src/skills/catalog.ts
|
|
12328
|
+
var catalog_exports = {};
|
|
12329
|
+
__export(catalog_exports, {
|
|
12330
|
+
readSkillCatalog: () => readSkillCatalog
|
|
12331
|
+
});
|
|
12332
|
+
import fs53 from "node:fs";
|
|
12333
|
+
import path61 from "node:path";
|
|
12334
|
+
function exists(p35) {
|
|
12335
|
+
try {
|
|
12336
|
+
fs53.accessSync(p35);
|
|
12337
|
+
return true;
|
|
12338
|
+
} catch {
|
|
12339
|
+
return false;
|
|
12340
|
+
}
|
|
12341
|
+
}
|
|
12342
|
+
function isDir(p35) {
|
|
12343
|
+
try {
|
|
12344
|
+
return fs53.statSync(p35).isDirectory();
|
|
12345
|
+
} catch {
|
|
12346
|
+
return false;
|
|
12347
|
+
}
|
|
12348
|
+
}
|
|
12349
|
+
function safeRead(p35) {
|
|
12350
|
+
try {
|
|
12351
|
+
return fs53.readFileSync(p35, "utf8");
|
|
12352
|
+
} catch {
|
|
12353
|
+
return null;
|
|
12354
|
+
}
|
|
12355
|
+
}
|
|
12356
|
+
function coerceManifest(raw, source) {
|
|
12357
|
+
const name = raw.name;
|
|
12358
|
+
const description = raw.description;
|
|
12359
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
12360
|
+
return { reason: "frontmatter missing required field 'name'" };
|
|
12361
|
+
}
|
|
12362
|
+
if (typeof description !== "string" || description.trim() === "") {
|
|
12363
|
+
return { reason: "frontmatter missing required field 'description'" };
|
|
12364
|
+
}
|
|
12365
|
+
const manifest = {
|
|
12366
|
+
name: name.trim(),
|
|
12367
|
+
description: description.trim(),
|
|
12368
|
+
source
|
|
12369
|
+
};
|
|
12370
|
+
if (Array.isArray(raw.triggers)) {
|
|
12371
|
+
manifest.triggers = raw.triggers.filter((v) => typeof v === "string");
|
|
12372
|
+
}
|
|
12373
|
+
if (typeof raw.progressiveDisclosure === "boolean") {
|
|
12374
|
+
manifest.progressiveDisclosure = raw.progressiveDisclosure;
|
|
12375
|
+
}
|
|
12376
|
+
if (Array.isArray(raw.helpers)) {
|
|
12377
|
+
manifest.helpers = raw.helpers.filter((v) => typeof v === "object" && v !== null).map((v) => ({
|
|
12378
|
+
path: String(v.path ?? ""),
|
|
12379
|
+
description: String(v.description ?? "")
|
|
12380
|
+
})).filter((h) => h.path.length > 0);
|
|
12381
|
+
}
|
|
12382
|
+
if (Array.isArray(raw.subSkills)) {
|
|
12383
|
+
manifest.subSkills = raw.subSkills.filter((v) => typeof v === "object" && v !== null).map((v) => ({
|
|
12384
|
+
name: String(v.name ?? ""),
|
|
12385
|
+
path: String(v.path ?? "")
|
|
12386
|
+
})).filter((s) => s.name.length > 0 && s.path.length > 0);
|
|
12387
|
+
}
|
|
12388
|
+
if (typeof raw.selfEval === "object" && raw.selfEval !== null && !Array.isArray(raw.selfEval)) {
|
|
12389
|
+
const se = raw.selfEval;
|
|
12390
|
+
const criteria = Array.isArray(se.criteria) ? se.criteria.filter((v) => typeof v === "string") : [];
|
|
12391
|
+
const maxRetries = typeof se.maxRetries === "number" ? se.maxRetries : 3;
|
|
12392
|
+
manifest.selfEval = {
|
|
12393
|
+
criteria,
|
|
12394
|
+
maxRetries,
|
|
12395
|
+
...typeof se.traceTo === "string" ? { traceTo: se.traceTo } : {}
|
|
12396
|
+
};
|
|
12397
|
+
}
|
|
12398
|
+
if (typeof raw.sessionMemory === "object" && raw.sessionMemory !== null && !Array.isArray(raw.sessionMemory)) {
|
|
12399
|
+
const sm = raw.sessionMemory;
|
|
12400
|
+
if (typeof sm.path === "string" && sm.path.length > 0) {
|
|
12401
|
+
manifest.sessionMemory = { path: sm.path };
|
|
12402
|
+
}
|
|
12403
|
+
}
|
|
12404
|
+
if (Array.isArray(raw.mcpTools)) {
|
|
12405
|
+
manifest.mcpTools = raw.mcpTools.filter((v) => typeof v === "string");
|
|
12406
|
+
}
|
|
12407
|
+
return { manifest };
|
|
12408
|
+
}
|
|
12409
|
+
function readOne(skillPath, source) {
|
|
12410
|
+
const body = safeRead(skillPath);
|
|
12411
|
+
if (body === null) {
|
|
12412
|
+
return { warning: { skillPath, reason: "unreadable SKILL.md" } };
|
|
12413
|
+
}
|
|
12414
|
+
let parsed;
|
|
12415
|
+
try {
|
|
12416
|
+
parsed = readFrontmatter(body);
|
|
12417
|
+
} catch (err) {
|
|
12418
|
+
return {
|
|
12419
|
+
warning: {
|
|
12420
|
+
skillPath,
|
|
12421
|
+
reason: `frontmatter parse error: ${err instanceof Error ? err.message : String(err)}`
|
|
12422
|
+
}
|
|
12423
|
+
};
|
|
12424
|
+
}
|
|
12425
|
+
if (parsed.frontmatter === null) {
|
|
12426
|
+
return { warning: { skillPath, reason: "SKILL.md has no YAML frontmatter" } };
|
|
12427
|
+
}
|
|
12428
|
+
const coerced = coerceManifest(parsed.frontmatter, source);
|
|
12429
|
+
if ("reason" in coerced) {
|
|
12430
|
+
return { warning: { skillPath, reason: coerced.reason } };
|
|
12431
|
+
}
|
|
12432
|
+
return { entry: { manifest: coerced.manifest, skillPath, source } };
|
|
12433
|
+
}
|
|
12434
|
+
function readSkillDirs(baseDir, source, out, warnings) {
|
|
12435
|
+
if (!isDir(baseDir)) return;
|
|
12436
|
+
for (const child of fs53.readdirSync(baseDir).sort()) {
|
|
12437
|
+
const dir = path61.join(baseDir, child);
|
|
12438
|
+
if (!isDir(dir)) continue;
|
|
12439
|
+
const skill = path61.join(dir, "SKILL.md");
|
|
12440
|
+
if (!exists(skill)) continue;
|
|
12441
|
+
const res = readOne(skill, source);
|
|
12442
|
+
if ("entry" in res) out.push(res.entry);
|
|
12443
|
+
else warnings.push(res.warning);
|
|
12444
|
+
}
|
|
12445
|
+
}
|
|
12446
|
+
function readKitSubSkills(kitDir, out, warnings, depth = 0) {
|
|
12447
|
+
const base = path61.join(kitDir, "skills");
|
|
12448
|
+
if (!isDir(base)) return;
|
|
12449
|
+
const walk = (dir, d) => {
|
|
12450
|
+
if (d > MAX_DEPTH) return;
|
|
12451
|
+
for (const entry of fs53.readdirSync(dir, { withFileTypes: true })) {
|
|
12452
|
+
if (entry.isDirectory()) {
|
|
12453
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
12454
|
+
walk(path61.join(dir, entry.name), d + 1);
|
|
12455
|
+
} else if (entry.isFile() && entry.name === "SKILL.md") {
|
|
12456
|
+
const res = readOne(path61.join(dir, entry.name), "worker-kit-sub");
|
|
12457
|
+
if ("entry" in res) out.push(res.entry);
|
|
12458
|
+
else warnings.push(res.warning);
|
|
12459
|
+
}
|
|
12460
|
+
}
|
|
12461
|
+
};
|
|
12462
|
+
walk(base, depth);
|
|
12463
|
+
}
|
|
12464
|
+
function readSkillCatalog(opts) {
|
|
12465
|
+
const root = path61.resolve(opts.root);
|
|
12466
|
+
const entries = [];
|
|
12467
|
+
const warnings = [];
|
|
12468
|
+
if (opts.includeProjectRoot !== false) {
|
|
12469
|
+
const rootSkill = path61.join(root, "SKILL.md");
|
|
12470
|
+
if (exists(rootSkill)) {
|
|
12471
|
+
const res = readOne(rootSkill, "project-root");
|
|
12472
|
+
if ("entry" in res) entries.push(res.entry);
|
|
12473
|
+
else warnings.push(res.warning);
|
|
12474
|
+
}
|
|
12475
|
+
}
|
|
12476
|
+
if (opts.includeClaudeSkills !== false) {
|
|
12477
|
+
readSkillDirs(path61.join(root, ".claude/skills"), "claude-skills", entries, warnings);
|
|
12478
|
+
}
|
|
12479
|
+
if (opts.includeWorkerKits !== false) {
|
|
12480
|
+
const kitsDir = path61.join(root, "cli/assets/worker-kits");
|
|
12481
|
+
readSkillDirs(kitsDir, "worker-kit", entries, warnings);
|
|
12482
|
+
if (isDir(kitsDir)) {
|
|
12483
|
+
for (const kit of fs53.readdirSync(kitsDir).sort()) {
|
|
12484
|
+
const kitPath = path61.join(kitsDir, kit);
|
|
12485
|
+
if (!isDir(kitPath)) continue;
|
|
12486
|
+
readKitSubSkills(kitPath, entries, warnings);
|
|
12487
|
+
}
|
|
12488
|
+
}
|
|
12489
|
+
}
|
|
12490
|
+
if (opts.includeForkRootSkills !== false) {
|
|
12491
|
+
readKitSubSkills(root, entries, warnings);
|
|
12492
|
+
}
|
|
12493
|
+
const catalog = {
|
|
12494
|
+
version: 1,
|
|
12495
|
+
skills: entries.map((e) => e.manifest),
|
|
12496
|
+
readAt: Date.now(),
|
|
12497
|
+
root
|
|
12498
|
+
};
|
|
12499
|
+
return { catalog, entries, warnings };
|
|
12500
|
+
}
|
|
12501
|
+
var MAX_DEPTH, SKIP_DIRS;
|
|
12502
|
+
var init_catalog2 = __esm({
|
|
12503
|
+
"src/skills/catalog.ts"() {
|
|
12504
|
+
"use strict";
|
|
12505
|
+
init_frontmatter();
|
|
12506
|
+
MAX_DEPTH = 6;
|
|
12507
|
+
SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
12508
|
+
"node_modules",
|
|
12509
|
+
".git",
|
|
12510
|
+
"dist",
|
|
12511
|
+
"build",
|
|
12512
|
+
".next",
|
|
12513
|
+
".vite",
|
|
12514
|
+
".pnpm-store",
|
|
12515
|
+
"coverage",
|
|
12516
|
+
".growthub-fork"
|
|
12517
|
+
]);
|
|
12518
|
+
}
|
|
12519
|
+
});
|
|
12520
|
+
|
|
12097
12521
|
// src/commands/source-import-discovery.ts
|
|
12098
12522
|
var source_import_discovery_exports = {};
|
|
12099
12523
|
__export(source_import_discovery_exports, {
|
|
@@ -12102,9 +12526,9 @@ __export(source_import_discovery_exports, {
|
|
|
12102
12526
|
startSourceImportFlow: () => startSourceImportFlow
|
|
12103
12527
|
});
|
|
12104
12528
|
import * as p33 from "@clack/prompts";
|
|
12105
|
-
import
|
|
12106
|
-
import
|
|
12107
|
-
import
|
|
12529
|
+
import pc48 from "picocolors";
|
|
12530
|
+
import fs58 from "node:fs";
|
|
12531
|
+
import path65 from "node:path";
|
|
12108
12532
|
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
12109
12533
|
function slugifyWorkspaceName(input) {
|
|
12110
12534
|
const slug = input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -12132,10 +12556,10 @@ async function promptForInteractiveWorkspacePath(input) {
|
|
|
12132
12556
|
});
|
|
12133
12557
|
if (p33.isCancel(raw) || !raw) return null;
|
|
12134
12558
|
const trimmed = String(raw).trim();
|
|
12135
|
-
const expanded = trimmed.startsWith("~/") ?
|
|
12136
|
-
const resolved =
|
|
12137
|
-
if (
|
|
12138
|
-
const finalPath =
|
|
12559
|
+
const expanded = trimmed.startsWith("~/") ? path65.join(process.env.HOME ?? "~", trimmed.slice(2)) : trimmed;
|
|
12560
|
+
const resolved = path65.resolve(expanded);
|
|
12561
|
+
if (fs58.existsSync(resolved) && fs58.statSync(resolved).isDirectory()) {
|
|
12562
|
+
const finalPath = path65.join(resolved, suggestedName);
|
|
12139
12563
|
p33.note(
|
|
12140
12564
|
[
|
|
12141
12565
|
`You selected an existing folder: ${resolved}`,
|
|
@@ -12311,14 +12735,14 @@ async function startSkillsSourceImportFlow() {
|
|
|
12311
12735
|
function renderSuccess(result, jobId) {
|
|
12312
12736
|
const sourceLine = result.source.kind === "github-repo" ? `${result.source.repo.owner}/${result.source.repo.repo}` : `${result.source.skillId}@${result.source.version}`;
|
|
12313
12737
|
p33.outro(
|
|
12314
|
-
`Imported ${sourceLine} into ${
|
|
12315
|
-
jobId: ${
|
|
12316
|
-
forkId: ${
|
|
12738
|
+
`Imported ${sourceLine} into ${pc48.cyan(result.forkPath)}
|
|
12739
|
+
jobId: ${pc48.cyan(jobId)}
|
|
12740
|
+
forkId: ${pc48.cyan(result.forkId)}
|
|
12317
12741
|
risk: ${result.security.riskClass} (${result.security.findings.length} findings)
|
|
12318
12742
|
detection: framework=${result.detection.framework} pm=${result.detection.packageManager}
|
|
12319
12743
|
open: ${folderOpenLabel3(result.forkPath)}
|
|
12320
|
-
summary: ${
|
|
12321
|
-
manifest: ${
|
|
12744
|
+
summary: ${pc48.dim(result.summaryPath)}
|
|
12745
|
+
manifest: ${pc48.dim(result.manifestPath)}`
|
|
12322
12746
|
);
|
|
12323
12747
|
}
|
|
12324
12748
|
async function confirmTwice(job) {
|
|
@@ -12405,9 +12829,9 @@ var init_source_import_discovery = __esm({
|
|
|
12405
12829
|
// src/index.ts
|
|
12406
12830
|
import { Command } from "commander";
|
|
12407
12831
|
import * as p34 from "@clack/prompts";
|
|
12408
|
-
import
|
|
12409
|
-
import
|
|
12410
|
-
import
|
|
12832
|
+
import pc49 from "picocolors";
|
|
12833
|
+
import fs59 from "node:fs";
|
|
12834
|
+
import path66 from "node:path";
|
|
12411
12835
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
12412
12836
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
12413
12837
|
|
|
@@ -13208,8 +13632,8 @@ function printItemCompleted(item) {
|
|
|
13208
13632
|
const changes = Array.isArray(item.changes) ? item.changes : [];
|
|
13209
13633
|
const entries = changes.map((changeRaw) => asRecord(changeRaw)).filter((change) => Boolean(change)).map((change) => {
|
|
13210
13634
|
const kind = asString(change.kind, "update");
|
|
13211
|
-
const
|
|
13212
|
-
return `${kind} ${
|
|
13635
|
+
const path67 = asString(change.path, "unknown");
|
|
13636
|
+
return `${kind} ${path67}`;
|
|
13213
13637
|
});
|
|
13214
13638
|
const preview = entries.length > 0 ? entries.slice(0, 6).join(", ") : "none";
|
|
13215
13639
|
const more = entries.length > 6 ? ` (+${entries.length - 6} more)` : "";
|
|
@@ -14496,10 +14920,10 @@ async function heartbeatRun(opts) {
|
|
|
14496
14920
|
for (const event of Array.isArray(events) ? events : []) {
|
|
14497
14921
|
handleEvent(event);
|
|
14498
14922
|
}
|
|
14499
|
-
const
|
|
14923
|
+
const runList2 = await api.get(
|
|
14500
14924
|
`/api/companies/${agent.companyId}/heartbeat-runs?agentId=${agent.id}`
|
|
14501
14925
|
) || [];
|
|
14502
|
-
const currentRun =
|
|
14926
|
+
const currentRun = runList2.find((r) => r && r.id === activeRunId) ?? null;
|
|
14503
14927
|
if (!currentRun) {
|
|
14504
14928
|
console.error(pc18.red("Heartbeat run disappeared"));
|
|
14505
14929
|
break;
|
|
@@ -16043,8 +16467,8 @@ function registerIssueCommands(program2) {
|
|
|
16043
16467
|
if (opts.assigneeAgentId) params.set("assigneeAgentId", opts.assigneeAgentId);
|
|
16044
16468
|
if (opts.projectId) params.set("projectId", opts.projectId);
|
|
16045
16469
|
const query = params.toString();
|
|
16046
|
-
const
|
|
16047
|
-
const rows = await ctx.api.get(
|
|
16470
|
+
const path67 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
|
|
16471
|
+
const rows = await ctx.api.get(path67) ?? [];
|
|
16048
16472
|
const filtered = filterIssueRows(rows, opts.match);
|
|
16049
16473
|
if (ctx.json) {
|
|
16050
16474
|
printOutput(filtered, { json: true });
|
|
@@ -16650,8 +17074,8 @@ function registerActivityCommands(program2) {
|
|
|
16650
17074
|
if (opts.entityType) params.set("entityType", opts.entityType);
|
|
16651
17075
|
if (opts.entityId) params.set("entityId", opts.entityId);
|
|
16652
17076
|
const query = params.toString();
|
|
16653
|
-
const
|
|
16654
|
-
const rows = await ctx.api.get(
|
|
17077
|
+
const path67 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
|
|
17078
|
+
const rows = await ctx.api.get(path67) ?? [];
|
|
16655
17079
|
if (ctx.json) {
|
|
16656
17080
|
printOutput(rows, { json: true });
|
|
16657
17081
|
return;
|
|
@@ -21389,10 +21813,13 @@ Examples:
|
|
|
21389
21813
|
$ growthub kit list --json # machine-readable output
|
|
21390
21814
|
$ growthub kit download higgsfield # fuzzy slug \u2014 resolves automatically
|
|
21391
21815
|
$ growthub kit download hyperframes # Hyperframes custom workspace
|
|
21816
|
+
$ growthub kit download video-use # browser-use/video-use custom workspace
|
|
21392
21817
|
$ growthub kit download growthub-open-higgsfield-studio-v1
|
|
21393
21818
|
$ growthub kit download growthub-hyperframes-studio-v1
|
|
21819
|
+
$ growthub kit download growthub-video-use-studio-v1
|
|
21394
21820
|
$ growthub kit inspect higgsfield-studio-v1
|
|
21395
21821
|
$ growthub kit inspect hyperframes
|
|
21822
|
+
$ growthub kit inspect video-use
|
|
21396
21823
|
$ growthub kit families # show family taxonomy
|
|
21397
21824
|
|
|
21398
21825
|
Fork Sync Agent:
|
|
@@ -21521,7 +21948,7 @@ Examples:
|
|
|
21521
21948
|
});
|
|
21522
21949
|
kit.command("families").description("Show the kit family taxonomy with descriptions and examples").action(() => {
|
|
21523
21950
|
const defs = [
|
|
21524
|
-
{ family: "studio", tagline: "AI generation studio backed by a local fork", surfaces: "local-fork, browser-hosted, desktop-app", example: "growthub-open-higgsfield-studio-v1, growthub-hyperframes-studio-v1, growthub-zernio-social-v1" },
|
|
21951
|
+
{ family: "studio", tagline: "AI generation studio backed by a local fork", surfaces: "local-fork, browser-hosted, desktop-app", example: "growthub-open-higgsfield-studio-v1, growthub-hyperframes-studio-v1, growthub-video-use-studio-v1, growthub-zernio-social-v1" },
|
|
21525
21952
|
{ family: "workflow", tagline: "Multi-step pipeline operator across tools or APIs", surfaces: "browser-hosted (primary)", example: "creative-strategist-v1" },
|
|
21526
21953
|
{ family: "operator", tagline: "Domain vertical specialist \u2014 one provider, structured deliverables", surfaces: "browser-hosted", example: "growthub-email-marketing-v1" },
|
|
21527
21954
|
{ family: "ops", tagline: "Infrastructure / toolchain operator (provider optional)", surfaces: "local-fork (primary)", example: "(coming soon)" }
|
|
@@ -22824,31 +23251,31 @@ function resolveManifestBaseUrl(opts = {}) {
|
|
|
22824
23251
|
function isRecord(value) {
|
|
22825
23252
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22826
23253
|
}
|
|
22827
|
-
function assertRecord(value,
|
|
23254
|
+
function assertRecord(value, path67) {
|
|
22828
23255
|
if (!isRecord(value)) {
|
|
22829
|
-
throw new ManifestMalformedError(`Expected object at \`${
|
|
23256
|
+
throw new ManifestMalformedError(`Expected object at \`${path67}\`.`);
|
|
22830
23257
|
}
|
|
22831
23258
|
return value;
|
|
22832
23259
|
}
|
|
22833
|
-
function assertArray(value,
|
|
23260
|
+
function assertArray(value, path67) {
|
|
22834
23261
|
if (!Array.isArray(value)) {
|
|
22835
|
-
throw new ManifestMalformedError(`Expected array at \`${
|
|
23262
|
+
throw new ManifestMalformedError(`Expected array at \`${path67}\`.`);
|
|
22836
23263
|
}
|
|
22837
23264
|
return value;
|
|
22838
23265
|
}
|
|
22839
|
-
function assertString(value,
|
|
23266
|
+
function assertString(value, path67) {
|
|
22840
23267
|
if (typeof value !== "string" || value.length === 0) {
|
|
22841
|
-
throw new ManifestMalformedError(`Expected non-empty string at \`${
|
|
23268
|
+
throw new ManifestMalformedError(`Expected non-empty string at \`${path67}\`.`);
|
|
22842
23269
|
}
|
|
22843
23270
|
return value;
|
|
22844
23271
|
}
|
|
22845
|
-
function normalizeProvenance(value,
|
|
22846
|
-
const record = assertRecord(value,
|
|
22847
|
-
const originType = assertString(record.originType, `${
|
|
23272
|
+
function normalizeProvenance(value, path67) {
|
|
23273
|
+
const record = assertRecord(value, path67);
|
|
23274
|
+
const originType = assertString(record.originType, `${path67}.originType`);
|
|
22848
23275
|
const allowed = ["hosted", "local-extension", "derived-from-workflow"];
|
|
22849
23276
|
if (!allowed.includes(originType)) {
|
|
22850
23277
|
throw new ManifestMalformedError(
|
|
22851
|
-
`Unknown provenance originType at \`${
|
|
23278
|
+
`Unknown provenance originType at \`${path67}.originType\`: ${originType}`
|
|
22852
23279
|
);
|
|
22853
23280
|
}
|
|
22854
23281
|
return {
|
|
@@ -31498,14 +31925,303 @@ function registerStarterCommands(program2) {
|
|
|
31498
31925
|
});
|
|
31499
31926
|
}
|
|
31500
31927
|
|
|
31928
|
+
// src/commands/skills.ts
|
|
31929
|
+
init_catalog2();
|
|
31930
|
+
import fs55 from "node:fs";
|
|
31931
|
+
import path63 from "node:path";
|
|
31932
|
+
import pc46 from "picocolors";
|
|
31933
|
+
|
|
31934
|
+
// src/skills/session-memory.ts
|
|
31935
|
+
init_frontmatter();
|
|
31936
|
+
import fs54 from "node:fs";
|
|
31937
|
+
import path62 from "node:path";
|
|
31938
|
+
var PROJECT_MD_RELATIVE2 = ".growthub-fork/project.md";
|
|
31939
|
+
function resolveProjectMdPath(forkPath) {
|
|
31940
|
+
return path62.resolve(forkPath, PROJECT_MD_RELATIVE2);
|
|
31941
|
+
}
|
|
31942
|
+
function readSessionMemory(forkPath) {
|
|
31943
|
+
const projectMdPath = resolveProjectMdPath(forkPath);
|
|
31944
|
+
if (!fs54.existsSync(projectMdPath)) return null;
|
|
31945
|
+
const raw = fs54.readFileSync(projectMdPath, "utf8");
|
|
31946
|
+
const sizeBytes = Buffer.byteLength(raw, "utf8");
|
|
31947
|
+
try {
|
|
31948
|
+
const { frontmatter, body } = readFrontmatter(raw);
|
|
31949
|
+
return { path: projectMdPath, frontmatter, body, sizeBytes };
|
|
31950
|
+
} catch {
|
|
31951
|
+
const split = splitFrontmatter(raw);
|
|
31952
|
+
return { path: projectMdPath, frontmatter: null, body: split.body, sizeBytes };
|
|
31953
|
+
}
|
|
31954
|
+
}
|
|
31955
|
+
|
|
31956
|
+
// src/commands/skills.ts
|
|
31957
|
+
init_scaffold_session_memory();
|
|
31958
|
+
init_fork_trace();
|
|
31959
|
+
init_kit_forks_home();
|
|
31960
|
+
init_table_renderer();
|
|
31961
|
+
function readLocalForkHead(forkPath) {
|
|
31962
|
+
const p35 = resolveInForkRegistrationPath(forkPath);
|
|
31963
|
+
if (!fs55.existsSync(p35)) return null;
|
|
31964
|
+
try {
|
|
31965
|
+
const parsed = JSON.parse(fs55.readFileSync(p35, "utf8"));
|
|
31966
|
+
if (typeof parsed.forkId !== "string" || typeof parsed.kitId !== "string") return null;
|
|
31967
|
+
return { forkId: parsed.forkId, kitId: parsed.kitId };
|
|
31968
|
+
} catch {
|
|
31969
|
+
return null;
|
|
31970
|
+
}
|
|
31971
|
+
}
|
|
31972
|
+
function resolveRoot(optRoot) {
|
|
31973
|
+
if (optRoot) return path63.resolve(optRoot);
|
|
31974
|
+
return process.cwd();
|
|
31975
|
+
}
|
|
31976
|
+
function runList(opts) {
|
|
31977
|
+
const result = readSkillCatalog({ root: resolveRoot(opts.root) });
|
|
31978
|
+
if (opts.json) {
|
|
31979
|
+
console.log(JSON.stringify(
|
|
31980
|
+
{
|
|
31981
|
+
version: result.catalog.version,
|
|
31982
|
+
root: result.catalog.root,
|
|
31983
|
+
skills: result.entries.map((e) => ({
|
|
31984
|
+
...e.manifest,
|
|
31985
|
+
skillPath: e.skillPath
|
|
31986
|
+
})),
|
|
31987
|
+
warnings: result.warnings
|
|
31988
|
+
},
|
|
31989
|
+
null,
|
|
31990
|
+
2
|
|
31991
|
+
));
|
|
31992
|
+
return;
|
|
31993
|
+
}
|
|
31994
|
+
if (result.entries.length === 0) {
|
|
31995
|
+
console.log(pc46.dim(`No SKILL.md found under ${result.catalog.root}`));
|
|
31996
|
+
return;
|
|
31997
|
+
}
|
|
31998
|
+
const rows = result.entries.map((e) => ({
|
|
31999
|
+
name: e.manifest.name,
|
|
32000
|
+
source: e.source,
|
|
32001
|
+
skillPath: path63.relative(result.catalog.root ?? "", e.skillPath),
|
|
32002
|
+
triggers: e.manifest.triggers?.length ?? 0,
|
|
32003
|
+
helpers: e.manifest.helpers?.length ?? 0,
|
|
32004
|
+
subSkills: e.manifest.subSkills?.length ?? 0,
|
|
32005
|
+
maxRetries: e.manifest.selfEval ? String(e.manifest.selfEval.maxRetries) : "\u2014"
|
|
32006
|
+
}));
|
|
32007
|
+
console.log(renderTable({
|
|
32008
|
+
columns: [
|
|
32009
|
+
{ key: "name", label: "name", maxWidth: 42 },
|
|
32010
|
+
{ key: "source", label: "source" },
|
|
32011
|
+
{ key: "skillPath", label: "path", maxWidth: 60 },
|
|
32012
|
+
{ key: "triggers", label: "trg", align: "right" },
|
|
32013
|
+
{ key: "helpers", label: "hlp", align: "right" },
|
|
32014
|
+
{ key: "subSkills", label: "sub", align: "right" },
|
|
32015
|
+
{ key: "maxRetries", label: "maxR", align: "right" }
|
|
32016
|
+
],
|
|
32017
|
+
rows
|
|
32018
|
+
}));
|
|
32019
|
+
if (result.warnings.length > 0) {
|
|
32020
|
+
console.log("");
|
|
32021
|
+
console.log(pc46.yellow(`${result.warnings.length} warning(s):`));
|
|
32022
|
+
for (const w of result.warnings) {
|
|
32023
|
+
console.log(pc46.yellow(` - ${path63.relative(result.catalog.root ?? "", w.skillPath)}: ${w.reason}`));
|
|
32024
|
+
}
|
|
32025
|
+
}
|
|
32026
|
+
}
|
|
32027
|
+
function runValidate(opts) {
|
|
32028
|
+
const root = resolveRoot(opts.root);
|
|
32029
|
+
const result = readSkillCatalog({ root });
|
|
32030
|
+
const issues2 = [];
|
|
32031
|
+
for (const w of result.warnings) {
|
|
32032
|
+
issues2.push({ skillPath: w.skillPath, reason: w.reason, severity: "error" });
|
|
32033
|
+
}
|
|
32034
|
+
for (const entry of result.entries) {
|
|
32035
|
+
const m = entry.manifest;
|
|
32036
|
+
if (m.name.length > 64) {
|
|
32037
|
+
issues2.push({
|
|
32038
|
+
skillPath: entry.skillPath,
|
|
32039
|
+
reason: `name length ${m.name.length} exceeds 64-char limit`,
|
|
32040
|
+
severity: "error"
|
|
32041
|
+
});
|
|
32042
|
+
}
|
|
32043
|
+
if (m.description.length > 1024) {
|
|
32044
|
+
issues2.push({
|
|
32045
|
+
skillPath: entry.skillPath,
|
|
32046
|
+
reason: `description length ${m.description.length} exceeds 1024-char limit`,
|
|
32047
|
+
severity: "error"
|
|
32048
|
+
});
|
|
32049
|
+
}
|
|
32050
|
+
const skillDir = path63.dirname(entry.skillPath);
|
|
32051
|
+
for (const helper of m.helpers ?? []) {
|
|
32052
|
+
const helperPath = path63.resolve(skillDir, helper.path);
|
|
32053
|
+
if (!fs55.existsSync(helperPath)) {
|
|
32054
|
+
issues2.push({
|
|
32055
|
+
skillPath: entry.skillPath,
|
|
32056
|
+
reason: `helpers[].path missing on disk: ${helper.path}`,
|
|
32057
|
+
severity: "warning"
|
|
32058
|
+
});
|
|
32059
|
+
}
|
|
32060
|
+
}
|
|
32061
|
+
for (const sub of m.subSkills ?? []) {
|
|
32062
|
+
const subPath = path63.resolve(skillDir, sub.path);
|
|
32063
|
+
if (!fs55.existsSync(subPath)) {
|
|
32064
|
+
issues2.push({
|
|
32065
|
+
skillPath: entry.skillPath,
|
|
32066
|
+
reason: `subSkills[].path missing on disk: ${sub.path}`,
|
|
32067
|
+
severity: "error"
|
|
32068
|
+
});
|
|
32069
|
+
}
|
|
32070
|
+
}
|
|
32071
|
+
if (m.selfEval && (m.selfEval.maxRetries < 1 || m.selfEval.maxRetries > 10)) {
|
|
32072
|
+
issues2.push({
|
|
32073
|
+
skillPath: entry.skillPath,
|
|
32074
|
+
reason: `selfEval.maxRetries ${m.selfEval.maxRetries} outside recommended 1..10 range`,
|
|
32075
|
+
severity: "warning"
|
|
32076
|
+
});
|
|
32077
|
+
}
|
|
32078
|
+
}
|
|
32079
|
+
if (opts.json) {
|
|
32080
|
+
console.log(JSON.stringify(
|
|
32081
|
+
{
|
|
32082
|
+
root,
|
|
32083
|
+
skillsChecked: result.entries.length,
|
|
32084
|
+
issues: issues2,
|
|
32085
|
+
ok: issues2.filter((i) => i.severity === "error").length === 0
|
|
32086
|
+
},
|
|
32087
|
+
null,
|
|
32088
|
+
2
|
|
32089
|
+
));
|
|
32090
|
+
process.exitCode = issues2.filter((i) => i.severity === "error").length === 0 ? 0 : 1;
|
|
32091
|
+
return;
|
|
32092
|
+
}
|
|
32093
|
+
console.log(pc46.bold(`Validated ${result.entries.length} skill(s) under ${root}`));
|
|
32094
|
+
if (issues2.length === 0) {
|
|
32095
|
+
console.log(pc46.green("OK \u2014 no issues."));
|
|
32096
|
+
return;
|
|
32097
|
+
}
|
|
32098
|
+
for (const issue of issues2) {
|
|
32099
|
+
const rel = path63.relative(root, issue.skillPath);
|
|
32100
|
+
const tag = issue.severity === "error" ? pc46.red("[error] ") : pc46.yellow("[warning]");
|
|
32101
|
+
console.log(`${tag} ${rel}: ${issue.reason}`);
|
|
32102
|
+
}
|
|
32103
|
+
const errors = issues2.filter((i) => i.severity === "error").length;
|
|
32104
|
+
if (errors > 0) process.exitCode = 1;
|
|
32105
|
+
}
|
|
32106
|
+
function runSessionInit(opts) {
|
|
32107
|
+
const forkPath = resolveRoot(opts.fork);
|
|
32108
|
+
let kitId = opts.kit?.trim() ?? "";
|
|
32109
|
+
let forkId = "unknown";
|
|
32110
|
+
const forkHead = readLocalForkHead(forkPath);
|
|
32111
|
+
if (forkHead) {
|
|
32112
|
+
forkId = forkHead.forkId;
|
|
32113
|
+
if (!kitId) kitId = forkHead.kitId;
|
|
32114
|
+
}
|
|
32115
|
+
if (!kitId) {
|
|
32116
|
+
const err = "Pass --kit <id>, or run this inside a registered fork (`.growthub-fork/fork.json`).";
|
|
32117
|
+
if (opts.json) {
|
|
32118
|
+
console.log(JSON.stringify({ status: "error", error: err }));
|
|
32119
|
+
process.exitCode = 1;
|
|
32120
|
+
} else {
|
|
32121
|
+
console.error(pc46.red(err));
|
|
32122
|
+
process.exitCode = 1;
|
|
32123
|
+
}
|
|
32124
|
+
return;
|
|
32125
|
+
}
|
|
32126
|
+
const result = scaffoldSessionMemory({
|
|
32127
|
+
forkPath,
|
|
32128
|
+
kitId,
|
|
32129
|
+
forkId,
|
|
32130
|
+
source: "skills-session-init",
|
|
32131
|
+
sourceRef: ""
|
|
32132
|
+
});
|
|
32133
|
+
if (result.written && forkHead) {
|
|
32134
|
+
appendKitForkTraceEvent(forkPath, {
|
|
32135
|
+
forkId,
|
|
32136
|
+
kitId,
|
|
32137
|
+
type: "skills_scaffolded",
|
|
32138
|
+
summary: "Seeded .growthub-fork/project.md via 'growthub skills session init'",
|
|
32139
|
+
detail: { projectMd: result.projectMdPath }
|
|
32140
|
+
});
|
|
32141
|
+
}
|
|
32142
|
+
if (opts.json) {
|
|
32143
|
+
console.log(JSON.stringify(
|
|
32144
|
+
{ status: result.written ? "ok" : "already-initialised", ...result },
|
|
32145
|
+
null,
|
|
32146
|
+
2
|
|
32147
|
+
));
|
|
32148
|
+
return;
|
|
32149
|
+
}
|
|
32150
|
+
if (result.written) {
|
|
32151
|
+
console.log(pc46.green(`Seeded ${path63.relative(forkPath, result.projectMdPath)}`));
|
|
32152
|
+
} else if (!result.templatePath) {
|
|
32153
|
+
console.log(pc46.yellow(
|
|
32154
|
+
`Kit tree does not ship templates/project.md \u2014 this kit has not been upgraded to the v1.2 primitives yet. No seed written; session memory can still be maintained manually.`
|
|
32155
|
+
));
|
|
32156
|
+
} else {
|
|
32157
|
+
console.log(pc46.dim(`${path63.relative(forkPath, result.projectMdPath)} already present; left untouched.`));
|
|
32158
|
+
}
|
|
32159
|
+
}
|
|
32160
|
+
function runSessionShow(opts) {
|
|
32161
|
+
const forkPath = resolveRoot(opts.fork);
|
|
32162
|
+
const head = readSessionMemory(forkPath);
|
|
32163
|
+
if (!head) {
|
|
32164
|
+
const err = `No session memory at ${resolveProjectMdPath(forkPath)}. Run 'growthub skills session init'.`;
|
|
32165
|
+
if (opts.json) {
|
|
32166
|
+
console.log(JSON.stringify({ status: "missing", projectMdPath: resolveProjectMdPath(forkPath) }));
|
|
32167
|
+
process.exitCode = 1;
|
|
32168
|
+
return;
|
|
32169
|
+
}
|
|
32170
|
+
console.error(pc46.yellow(err));
|
|
32171
|
+
process.exitCode = 1;
|
|
32172
|
+
return;
|
|
32173
|
+
}
|
|
32174
|
+
if (opts.json) {
|
|
32175
|
+
console.log(JSON.stringify(
|
|
32176
|
+
{
|
|
32177
|
+
path: head.path,
|
|
32178
|
+
sizeBytes: head.sizeBytes,
|
|
32179
|
+
frontmatter: head.frontmatter,
|
|
32180
|
+
body: opts.body ? head.body : void 0
|
|
32181
|
+
},
|
|
32182
|
+
null,
|
|
32183
|
+
2
|
|
32184
|
+
));
|
|
32185
|
+
return;
|
|
32186
|
+
}
|
|
32187
|
+
console.log(pc46.bold(head.path));
|
|
32188
|
+
console.log(pc46.dim(`${head.sizeBytes} bytes`));
|
|
32189
|
+
if (head.frontmatter) {
|
|
32190
|
+
for (const [k, v] of Object.entries(head.frontmatter)) {
|
|
32191
|
+
if (Array.isArray(v)) {
|
|
32192
|
+
console.log(` ${k}: ${v.length === 0 ? "[]" : `[${v.length} entries]`}`);
|
|
32193
|
+
} else if (typeof v === "object" && v !== null) {
|
|
32194
|
+
console.log(` ${k}: { ${Object.keys(v).join(", ")} }`);
|
|
32195
|
+
} else {
|
|
32196
|
+
console.log(` ${k}: ${String(v)}`);
|
|
32197
|
+
}
|
|
32198
|
+
}
|
|
32199
|
+
}
|
|
32200
|
+
if (opts.body) {
|
|
32201
|
+
console.log("");
|
|
32202
|
+
console.log(head.body);
|
|
32203
|
+
} else {
|
|
32204
|
+
console.log("");
|
|
32205
|
+
console.log(pc46.dim("(pass --body to print the markdown body)"));
|
|
32206
|
+
}
|
|
32207
|
+
}
|
|
32208
|
+
function registerSkillsCommands(program2) {
|
|
32209
|
+
const skills = program2.command("skills").description("Discovery + session memory for SKILL.md + .growthub-fork/project.md");
|
|
32210
|
+
skills.command("list").description("Enumerate every SKILL.md reachable from the current tree").option("--root <path>", "Override the root to scan (default: cwd)").option("--json", "Emit machine-readable JSON").action((opts) => runList(opts));
|
|
32211
|
+
skills.command("validate").description("Strict frontmatter + helper/sub-skill path check; non-zero exit on error").option("--root <path>", "Override the root to scan (default: cwd)").option("--json", "Emit machine-readable JSON").action((opts) => runValidate(opts));
|
|
32212
|
+
const session = skills.command("session").description("Read / seed the fork's session memory (.growthub-fork/project.md)");
|
|
32213
|
+
session.command("init").description("Seed .growthub-fork/project.md from the kit's templates/project.md").option("--fork <path>", "Fork root (default: cwd)").option("--kit <id>", "Explicit kit id; read from fork.json when omitted inside a registered fork").option("--json", "Emit machine-readable JSON").action((opts) => runSessionInit(opts));
|
|
32214
|
+
session.command("show").description("Print the session-memory head for a fork").option("--fork <path>", "Fork root (default: cwd)").option("--body", "Also print the markdown body").option("--json", "Emit machine-readable JSON").action((opts) => runSessionShow(opts));
|
|
32215
|
+
}
|
|
32216
|
+
|
|
31501
32217
|
// src/commands/fleet.ts
|
|
31502
32218
|
init_fork_registry();
|
|
31503
32219
|
import * as p32 from "@clack/prompts";
|
|
31504
|
-
import
|
|
32220
|
+
import pc47 from "picocolors";
|
|
31505
32221
|
|
|
31506
32222
|
// src/fleet/summary.ts
|
|
31507
32223
|
init_fork_registry();
|
|
31508
|
-
import
|
|
32224
|
+
import fs56 from "node:fs";
|
|
31509
32225
|
init_fork_policy();
|
|
31510
32226
|
init_fork_trace();
|
|
31511
32227
|
function classifyHealth(drift, pendingConfirmationJobs, lastJobStatus) {
|
|
@@ -31525,7 +32241,7 @@ var REMOTE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
31525
32241
|
"conflict_encountered"
|
|
31526
32242
|
]);
|
|
31527
32243
|
function buildForkSummary(reg) {
|
|
31528
|
-
if (!
|
|
32244
|
+
if (!fs56.existsSync(reg.forkPath)) {
|
|
31529
32245
|
return {
|
|
31530
32246
|
forkId: reg.forkId,
|
|
31531
32247
|
kitId: reg.kitId,
|
|
@@ -31834,17 +32550,17 @@ init_fork_policy();
|
|
|
31834
32550
|
function healthGlyph(level) {
|
|
31835
32551
|
switch (level) {
|
|
31836
32552
|
case "clean":
|
|
31837
|
-
return
|
|
32553
|
+
return pc47.green("\u25CF");
|
|
31838
32554
|
case "drift-minor":
|
|
31839
|
-
return
|
|
32555
|
+
return pc47.cyan("\u25CF");
|
|
31840
32556
|
case "drift-major":
|
|
31841
|
-
return
|
|
32557
|
+
return pc47.yellow("\u25CF");
|
|
31842
32558
|
case "awaiting-confirmation":
|
|
31843
|
-
return
|
|
32559
|
+
return pc47.magenta("\u25D0");
|
|
31844
32560
|
case "error":
|
|
31845
|
-
return
|
|
32561
|
+
return pc47.red("\u25CF");
|
|
31846
32562
|
default:
|
|
31847
|
-
return
|
|
32563
|
+
return pc47.dim("\u25CB");
|
|
31848
32564
|
}
|
|
31849
32565
|
}
|
|
31850
32566
|
function truncate4(s, n) {
|
|
@@ -31858,7 +32574,7 @@ async function fleetView(opts) {
|
|
|
31858
32574
|
return;
|
|
31859
32575
|
}
|
|
31860
32576
|
p32.log.message(
|
|
31861
|
-
`Fleet: ${
|
|
32577
|
+
`Fleet: ${pc47.cyan(String(fleet.totalForks))} fork(s) | remote=${fleet.forksWithRemote} awaiting=${fleet.forksAwaitingConfirmation} pending-approvals=${fleet.pendingApprovalCount}`
|
|
31862
32578
|
);
|
|
31863
32579
|
p32.log.message(
|
|
31864
32580
|
` Health \u2192 clean=${fleet.byHealth.clean} drift-minor=${fleet.byHealth["drift-minor"]} drift-major=${fleet.byHealth["drift-major"]} awaiting=${fleet.byHealth["awaiting-confirmation"]} error=${fleet.byHealth.error} unknown=${fleet.byHealth.unknown}`
|
|
@@ -31875,10 +32591,10 @@ function renderForkRow(f) {
|
|
|
31875
32591
|
const base = f.baseVersion.padEnd(8);
|
|
31876
32592
|
const upstream = (f.upstreamVersion ?? "?").padEnd(8);
|
|
31877
32593
|
const driftCounts = `files=${f.fileDriftCount} pkgs=${f.packageDriftCount}`;
|
|
31878
|
-
const pending = f.pendingConfirmationJobs > 0 ?
|
|
31879
|
-
const remote = f.remote ?
|
|
32594
|
+
const pending = f.pendingConfirmationJobs > 0 ? pc47.magenta(` awaits=${f.pendingConfirmationJobs}`) : "";
|
|
32595
|
+
const remote = f.remote ? pc47.dim(` ${f.remote.owner}/${f.remote.repo}`) : "";
|
|
31880
32596
|
p32.log.message(
|
|
31881
|
-
` ${healthGlyph(f.health)} ${label} ${
|
|
32597
|
+
` ${healthGlyph(f.health)} ${label} ${pc47.dim(kit)} ${base} \u2192 ${upstream} ${pc47.dim(driftCounts)}${pending}${remote}`
|
|
31882
32598
|
);
|
|
31883
32599
|
}
|
|
31884
32600
|
async function fleetDrift(opts) {
|
|
@@ -31893,7 +32609,7 @@ async function fleetDrift(opts) {
|
|
|
31893
32609
|
return;
|
|
31894
32610
|
}
|
|
31895
32611
|
p32.log.message(
|
|
31896
|
-
`Fleet drift: ${
|
|
32612
|
+
`Fleet drift: ${pc47.cyan(String(withDrift.length))} of ${fleet.totalForks} fork(s) have drift.`
|
|
31897
32613
|
);
|
|
31898
32614
|
p32.log.message(
|
|
31899
32615
|
` By severity \u2192 none=${fleet.bySeverity.none} info=${fleet.bySeverity.info} warning=${fleet.bySeverity.warning} critical=${fleet.bySeverity.critical}`
|
|
@@ -31913,7 +32629,7 @@ async function fleetDriftSummary(opts) {
|
|
|
31913
32629
|
console.log(JSON.stringify({ summary, narrative }, null, 2));
|
|
31914
32630
|
return;
|
|
31915
32631
|
}
|
|
31916
|
-
p32.log.message(
|
|
32632
|
+
p32.log.message(pc47.cyan(`Drift summary \u2014 ${reg.forkId} (${summary.fromVersion} \u2192 ${summary.toVersion})`));
|
|
31917
32633
|
for (const line of narrative) p32.log.message(` ${line}`);
|
|
31918
32634
|
const sections = [
|
|
31919
32635
|
["safe additions", summary.buckets.safeAdditions],
|
|
@@ -31926,13 +32642,13 @@ async function fleetDriftSummary(opts) {
|
|
|
31926
32642
|
];
|
|
31927
32643
|
for (const [label, items] of sections) {
|
|
31928
32644
|
if (items.length === 0) continue;
|
|
31929
|
-
p32.log.message(
|
|
31930
|
-
for (const item of items) p32.log.message(` \xB7 ${item.path} ${
|
|
32645
|
+
p32.log.message(pc47.dim(` \u2014 ${label} (${items.length}) \u2014`));
|
|
32646
|
+
for (const item of items) p32.log.message(` \xB7 ${item.path} ${pc47.dim(item.note)}`);
|
|
31931
32647
|
}
|
|
31932
32648
|
if (summary.buckets.packageAdditions.length || summary.buckets.packageUpgrades.length) {
|
|
31933
|
-
p32.log.message(
|
|
32649
|
+
p32.log.message(pc47.dim(` \u2014 dependency drift \u2014`));
|
|
31934
32650
|
for (const d of summary.buckets.packageAdditions) {
|
|
31935
|
-
p32.log.message(` + ${d.packageName}@${d.toVersion} ${
|
|
32651
|
+
p32.log.message(` + ${d.packageName}@${d.toVersion} ${pc47.dim("(added upstream)")}`);
|
|
31936
32652
|
}
|
|
31937
32653
|
for (const d of summary.buckets.packageUpgrades) {
|
|
31938
32654
|
p32.log.message(` \u2191 ${d.packageName} ${d.fromVersion ?? "?"} \u2192 ${d.toVersion}`);
|
|
@@ -31958,14 +32674,14 @@ async function fleetPolicy(opts) {
|
|
|
31958
32674
|
console.log(JSON.stringify({ count: rows.length, rows }, null, 2));
|
|
31959
32675
|
return;
|
|
31960
32676
|
}
|
|
31961
|
-
p32.log.message(
|
|
32677
|
+
p32.log.message(pc47.cyan(`Fleet policy matrix (${rows.length} fork(s))`));
|
|
31962
32678
|
for (const r of rows) {
|
|
31963
32679
|
const label = truncate4(r.label ?? r.forkId, 28).padEnd(28);
|
|
31964
32680
|
const aa = r.autoApprove.padEnd(9);
|
|
31965
32681
|
const ad = r.autoApproveDepUpdates.padEnd(9);
|
|
31966
32682
|
const rs = r.remoteSyncMode.padEnd(6);
|
|
31967
32683
|
const ut = String(r.untouchableCount).padStart(3);
|
|
31968
|
-
const remote = r.hasRemote ?
|
|
32684
|
+
const remote = r.hasRemote ? pc47.green("+") : pc47.dim("\xB7");
|
|
31969
32685
|
p32.log.message(
|
|
31970
32686
|
` ${label} autoApprove=${aa} deps=${ad} remote=${rs} untouchable=${ut} ${remote}`
|
|
31971
32687
|
);
|
|
@@ -31981,19 +32697,19 @@ async function fleetApprovals(opts) {
|
|
|
31981
32697
|
p32.log.success("Approval queue is empty.");
|
|
31982
32698
|
return;
|
|
31983
32699
|
}
|
|
31984
|
-
p32.log.message(
|
|
32700
|
+
p32.log.message(pc47.cyan(`Approval queue: ${queue.length} job(s) awaiting confirmation`));
|
|
31985
32701
|
for (const entry of queue) {
|
|
31986
32702
|
p32.log.message(
|
|
31987
|
-
` \xB7 ${
|
|
32703
|
+
` \xB7 ${pc47.cyan(entry.jobId)} fork=${entry.forkLabel ?? entry.forkId} created=${entry.createdAt.slice(0, 19)}`
|
|
31988
32704
|
);
|
|
31989
|
-
for (const
|
|
31990
|
-
p32.log.message(` ${
|
|
32705
|
+
for (const path67 of entry.pendingPaths.slice(0, 6)) {
|
|
32706
|
+
p32.log.message(` ${pc47.dim("awaits")} ${path67}`);
|
|
31991
32707
|
}
|
|
31992
32708
|
if (entry.pendingPaths.length > 6) {
|
|
31993
|
-
p32.log.message(` ${
|
|
32709
|
+
p32.log.message(` ${pc47.dim(`\u2026 +${entry.pendingPaths.length - 6} more`)}`);
|
|
31994
32710
|
}
|
|
31995
32711
|
p32.log.message(
|
|
31996
|
-
` ${
|
|
32712
|
+
` ${pc47.dim("resume:")} growthub kit fork confirm --job-id ${entry.jobId}`
|
|
31997
32713
|
);
|
|
31998
32714
|
}
|
|
31999
32715
|
}
|
|
@@ -32005,20 +32721,20 @@ async function fleetAgentPlan(opts) {
|
|
|
32005
32721
|
console.log(JSON.stringify(doc, null, 2));
|
|
32006
32722
|
return;
|
|
32007
32723
|
}
|
|
32008
|
-
p32.log.message(
|
|
32724
|
+
p32.log.message(pc47.cyan(`Agent heal plan \u2014 ${reg.forkId}`));
|
|
32009
32725
|
p32.log.message(` ${doc.summary}`);
|
|
32010
32726
|
for (const line of doc.narrative) p32.log.message(` ${line}`);
|
|
32011
32727
|
if (doc.awaitsConfirmation.length > 0) {
|
|
32012
|
-
p32.log.message(
|
|
32728
|
+
p32.log.message(pc47.magenta(` Awaiting confirmation on:`));
|
|
32013
32729
|
for (const p210 of doc.awaitsConfirmation) p32.log.message(` \xB7 ${p210}`);
|
|
32014
32730
|
p32.log.message(
|
|
32015
|
-
|
|
32731
|
+
pc47.dim(
|
|
32016
32732
|
` Next: growthub kit fork heal ${reg.forkId} (will park in awaiting_confirmation until resumed)`
|
|
32017
32733
|
)
|
|
32018
32734
|
);
|
|
32019
32735
|
} else if (doc.plan.actions.length > 0) {
|
|
32020
32736
|
p32.log.message(
|
|
32021
|
-
|
|
32737
|
+
pc47.dim(` Next: growthub kit fork heal ${reg.forkId} (${doc.plan.actions.length} safe action(s) ready)`)
|
|
32022
32738
|
);
|
|
32023
32739
|
}
|
|
32024
32740
|
}
|
|
@@ -32073,21 +32789,21 @@ var DEFAULT_MEMORY_PROVIDER_CONFIG = {
|
|
|
32073
32789
|
|
|
32074
32790
|
// src/runtime/memory/store.ts
|
|
32075
32791
|
init_home();
|
|
32076
|
-
import
|
|
32077
|
-
import
|
|
32792
|
+
import fs57 from "node:fs";
|
|
32793
|
+
import path64 from "node:path";
|
|
32078
32794
|
function toProjectSlug(project) {
|
|
32079
32795
|
return project.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "default";
|
|
32080
32796
|
}
|
|
32081
32797
|
function resolveProjectPath(project) {
|
|
32082
|
-
return
|
|
32798
|
+
return path64.resolve(resolveMemoryProjectsDir(), `${toProjectSlug(project)}.json`);
|
|
32083
32799
|
}
|
|
32084
32800
|
function loadMemoryDatabase(project) {
|
|
32085
32801
|
const filePath = resolveProjectPath(project);
|
|
32086
|
-
if (!
|
|
32802
|
+
if (!fs57.existsSync(filePath)) {
|
|
32087
32803
|
return { version: 1, project, observations: [], summaries: [], nextObservationId: 1, nextSummaryId: 1 };
|
|
32088
32804
|
}
|
|
32089
32805
|
try {
|
|
32090
|
-
const raw = JSON.parse(
|
|
32806
|
+
const raw = JSON.parse(fs57.readFileSync(filePath, "utf-8"));
|
|
32091
32807
|
return {
|
|
32092
32808
|
version: 1,
|
|
32093
32809
|
project,
|
|
@@ -32102,9 +32818,9 @@ function loadMemoryDatabase(project) {
|
|
|
32102
32818
|
}
|
|
32103
32819
|
function saveMemoryDatabase(db) {
|
|
32104
32820
|
const dir = resolveMemoryProjectsDir();
|
|
32105
|
-
|
|
32821
|
+
fs57.mkdirSync(dir, { recursive: true });
|
|
32106
32822
|
const filePath = resolveProjectPath(db.project);
|
|
32107
|
-
|
|
32823
|
+
fs57.writeFileSync(filePath, `${JSON.stringify(db, null, 2)}
|
|
32108
32824
|
`, "utf-8");
|
|
32109
32825
|
}
|
|
32110
32826
|
function addObservation(project, input) {
|
|
@@ -32198,8 +32914,8 @@ function incrementRelevanceCount(project, observationId) {
|
|
|
32198
32914
|
}
|
|
32199
32915
|
function listMemoryProjects() {
|
|
32200
32916
|
const dir = resolveMemoryProjectsDir();
|
|
32201
|
-
if (!
|
|
32202
|
-
return
|
|
32917
|
+
if (!fs57.existsSync(dir)) return [];
|
|
32918
|
+
return fs57.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, "")).sort();
|
|
32203
32919
|
}
|
|
32204
32920
|
function getMemoryStats(project) {
|
|
32205
32921
|
const db = loadMemoryDatabase(project);
|
|
@@ -32211,15 +32927,15 @@ function getMemoryStats(project) {
|
|
|
32211
32927
|
};
|
|
32212
32928
|
}
|
|
32213
32929
|
function resolveProviderConfigPath() {
|
|
32214
|
-
return
|
|
32930
|
+
return path64.resolve(resolveMemoryDir(), "provider-config.json");
|
|
32215
32931
|
}
|
|
32216
32932
|
function readProviderConfig() {
|
|
32217
32933
|
const filePath = resolveProviderConfigPath();
|
|
32218
|
-
if (!
|
|
32934
|
+
if (!fs57.existsSync(filePath)) {
|
|
32219
32935
|
return { ...DEFAULT_MEMORY_PROVIDER_CONFIG };
|
|
32220
32936
|
}
|
|
32221
32937
|
try {
|
|
32222
|
-
const raw = JSON.parse(
|
|
32938
|
+
const raw = JSON.parse(fs57.readFileSync(filePath, "utf-8"));
|
|
32223
32939
|
return {
|
|
32224
32940
|
provider: validateProvider(raw.provider),
|
|
32225
32941
|
apiKey: typeof raw.apiKey === "string" ? raw.apiKey : void 0,
|
|
@@ -32232,9 +32948,9 @@ function readProviderConfig() {
|
|
|
32232
32948
|
}
|
|
32233
32949
|
function writeProviderConfig(config) {
|
|
32234
32950
|
const dir = resolveMemoryDir();
|
|
32235
|
-
|
|
32951
|
+
fs57.mkdirSync(dir, { recursive: true });
|
|
32236
32952
|
const filePath = resolveProviderConfigPath();
|
|
32237
|
-
|
|
32953
|
+
fs57.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}
|
|
32238
32954
|
`, { mode: 384 });
|
|
32239
32955
|
}
|
|
32240
32956
|
function validateProvider(value) {
|
|
@@ -32613,14 +33329,14 @@ async function syncMemoriesToHosted(project, options) {
|
|
|
32613
33329
|
init_llm();
|
|
32614
33330
|
function resolveCliVersion() {
|
|
32615
33331
|
try {
|
|
32616
|
-
const moduleDir =
|
|
33332
|
+
const moduleDir = path66.dirname(fileURLToPath7(import.meta.url));
|
|
32617
33333
|
const candidates = [
|
|
32618
|
-
|
|
32619
|
-
|
|
33334
|
+
path66.resolve(moduleDir, "../package.json"),
|
|
33335
|
+
path66.resolve(moduleDir, "../../package.json")
|
|
32620
33336
|
];
|
|
32621
33337
|
for (const candidate of candidates) {
|
|
32622
|
-
if (!
|
|
32623
|
-
const parsed = JSON.parse(
|
|
33338
|
+
if (!fs59.existsSync(candidate)) continue;
|
|
33339
|
+
const parsed = JSON.parse(fs59.readFileSync(candidate, "utf8"));
|
|
32624
33340
|
if (parsed?.name === "@growthub/cli" && typeof parsed.version === "string") return parsed.version;
|
|
32625
33341
|
}
|
|
32626
33342
|
} catch {
|
|
@@ -32847,7 +33563,7 @@ async function runMarketingContextBuilder(baseUrl, model) {
|
|
|
32847
33563
|
});
|
|
32848
33564
|
if (p34.isCancel(projectDir)) return;
|
|
32849
33565
|
const dir = String(projectDir).trim() || process.cwd();
|
|
32850
|
-
if (!
|
|
33566
|
+
if (!fs59.existsSync(dir)) {
|
|
32851
33567
|
p34.note(`Directory not found: ${dir}`, "Marketing Context Builder");
|
|
32852
33568
|
return;
|
|
32853
33569
|
}
|
|
@@ -32883,10 +33599,10 @@ async function runMarketingContextBuilder(baseUrl, model) {
|
|
|
32883
33599
|
p34.note("Draft was not saved. You can copy it from the output above.", "Marketing Context Builder");
|
|
32884
33600
|
return;
|
|
32885
33601
|
}
|
|
32886
|
-
const outDir =
|
|
32887
|
-
|
|
32888
|
-
const outPath =
|
|
32889
|
-
|
|
33602
|
+
const outDir = path66.resolve(dir, ".agents");
|
|
33603
|
+
fs59.mkdirSync(outDir, { recursive: true });
|
|
33604
|
+
const outPath = path66.resolve(outDir, "product-marketing-context.md");
|
|
33605
|
+
fs59.writeFileSync(outPath, result.contextMarkdown, "utf-8");
|
|
32890
33606
|
p34.note(`Saved to: ${outPath}
|
|
32891
33607
|
|
|
32892
33608
|
Review the file and replace [NEEDS INPUT] placeholders with real data.`, "Marketing Context Builder");
|
|
@@ -33095,39 +33811,39 @@ function captureSessionSummary(project, sessionId, messages) {
|
|
|
33095
33811
|
}
|
|
33096
33812
|
}
|
|
33097
33813
|
function resolveLocalThreadsDir() {
|
|
33098
|
-
return
|
|
33814
|
+
return path66.resolve(resolvePaperclipHomeDir(), "native-intelligence", "threads");
|
|
33099
33815
|
}
|
|
33100
33816
|
function loadOrCreateLocalThread() {
|
|
33101
33817
|
const dir = resolveLocalThreadsDir();
|
|
33102
|
-
|
|
33103
|
-
const activePath =
|
|
33104
|
-
if (
|
|
33818
|
+
fs59.mkdirSync(dir, { recursive: true });
|
|
33819
|
+
const activePath = path66.resolve(dir, "active-thread.json");
|
|
33820
|
+
if (fs59.existsSync(activePath)) {
|
|
33105
33821
|
try {
|
|
33106
|
-
const parsed = JSON.parse(
|
|
33822
|
+
const parsed = JSON.parse(fs59.readFileSync(activePath, "utf-8"));
|
|
33107
33823
|
const id2 = typeof parsed.id === "string" && parsed.id.length > 0 ? parsed.id : `thread-${Date.now()}`;
|
|
33108
|
-
const threadFile =
|
|
33824
|
+
const threadFile = path66.resolve(dir, `${id2}.json`);
|
|
33109
33825
|
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
33110
33826
|
return { id: id2, filePath: threadFile, messages };
|
|
33111
33827
|
} catch {
|
|
33112
33828
|
}
|
|
33113
33829
|
}
|
|
33114
33830
|
const id = `thread-${Date.now()}`;
|
|
33115
|
-
const filePath =
|
|
33831
|
+
const filePath = path66.resolve(dir, `${id}.json`);
|
|
33116
33832
|
const thread = { id, filePath, messages: [] };
|
|
33117
33833
|
saveLocalThread(thread);
|
|
33118
33834
|
return thread;
|
|
33119
33835
|
}
|
|
33120
33836
|
function saveLocalThread(thread) {
|
|
33121
33837
|
const dir = resolveLocalThreadsDir();
|
|
33122
|
-
|
|
33123
|
-
|
|
33838
|
+
fs59.mkdirSync(dir, { recursive: true });
|
|
33839
|
+
fs59.writeFileSync(
|
|
33124
33840
|
thread.filePath,
|
|
33125
33841
|
`${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
|
|
33126
33842
|
`,
|
|
33127
33843
|
"utf-8"
|
|
33128
33844
|
);
|
|
33129
|
-
const activePath =
|
|
33130
|
-
|
|
33845
|
+
const activePath = path66.resolve(dir, "active-thread.json");
|
|
33846
|
+
fs59.writeFileSync(
|
|
33131
33847
|
activePath,
|
|
33132
33848
|
`${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
|
|
33133
33849
|
`,
|
|
@@ -33273,7 +33989,7 @@ async function collectBindingsFromContract(contract, promptSeed) {
|
|
|
33273
33989
|
return bindings;
|
|
33274
33990
|
}
|
|
33275
33991
|
function resolveCurrentProject() {
|
|
33276
|
-
return
|
|
33992
|
+
return path66.basename(process.cwd());
|
|
33277
33993
|
}
|
|
33278
33994
|
async function runMemoryKnowledgeHub() {
|
|
33279
33995
|
const project = resolveCurrentProject();
|
|
@@ -33306,7 +34022,7 @@ async function runMemoryKnowledgeHub() {
|
|
|
33306
34022
|
},
|
|
33307
34023
|
{
|
|
33308
34024
|
value: "sync",
|
|
33309
|
-
label: syncStatus.available ? "Sync to Growthub" : "Sync to Growthub" +
|
|
34025
|
+
label: syncStatus.available ? "Sync to Growthub" : "Sync to Growthub" + pc49.dim(" (unavailable)"),
|
|
33310
34026
|
hint: syncStatus.available ? "push memories to hosted account" : syncStatus.reason
|
|
33311
34027
|
},
|
|
33312
34028
|
{ value: "__back_to_hub", label: "\u2190 Back to main menu" }
|
|
@@ -33445,7 +34161,7 @@ async function runDiscoveryHub(opts) {
|
|
|
33445
34161
|
},
|
|
33446
34162
|
{
|
|
33447
34163
|
value: "workflows",
|
|
33448
|
-
label: workflowAccess.state === "ready" ? "\u{1F517} Workflows" : "\u{1F517} Workflows" +
|
|
34164
|
+
label: workflowAccess.state === "ready" ? "\u{1F517} Workflows" : "\u{1F517} Workflows" + pc49.dim(" (locked)"),
|
|
33449
34165
|
hint: workflowAccess.state === "ready" ? "CMS contracts, dynamic pipelines, and saved workflows" : workflowAccess.reason
|
|
33450
34166
|
},
|
|
33451
34167
|
{
|
|
@@ -33468,6 +34184,11 @@ async function runDiscoveryHub(opts) {
|
|
|
33468
34184
|
label: "\u{1F4D6} Memory & Knowledge",
|
|
33469
34185
|
hint: "persistent memory, search, multi-provider config, Growthub sync"
|
|
33470
34186
|
},
|
|
34187
|
+
{
|
|
34188
|
+
value: "skills-catalog",
|
|
34189
|
+
label: "\u{1F4C7} Skills Catalog",
|
|
34190
|
+
hint: "enumerate SKILL.md across this tree + inspect .growthub-fork/project.md"
|
|
34191
|
+
},
|
|
33471
34192
|
{
|
|
33472
34193
|
value: "hosted-auth",
|
|
33473
34194
|
label: "\u{1F510} Connect Growthub Account",
|
|
@@ -33839,6 +34560,25 @@ async function runDiscoveryHub(opts) {
|
|
|
33839
34560
|
if (result2 === "back") continue;
|
|
33840
34561
|
return;
|
|
33841
34562
|
}
|
|
34563
|
+
if (surfaceChoice === "skills-catalog") {
|
|
34564
|
+
const { readSkillCatalog: readSkillCatalog2 } = await Promise.resolve().then(() => (init_catalog2(), catalog_exports));
|
|
34565
|
+
const catalog = readSkillCatalog2({ root: process.cwd() });
|
|
34566
|
+
p34.note(
|
|
34567
|
+
[
|
|
34568
|
+
`Root: ${pc49.cyan(catalog.catalog.root ?? process.cwd())}`,
|
|
34569
|
+
`Skills discovered: ${pc49.bold(String(catalog.entries.length))}`,
|
|
34570
|
+
catalog.warnings.length > 0 ? `Warnings: ${pc49.yellow(String(catalog.warnings.length))}` : `Warnings: 0`,
|
|
34571
|
+
"",
|
|
34572
|
+
"Invoke directly:",
|
|
34573
|
+
" growthub skills list --json",
|
|
34574
|
+
" growthub skills validate",
|
|
34575
|
+
" growthub skills session show",
|
|
34576
|
+
" growthub skills session init --kit <kit-id>"
|
|
34577
|
+
].join("\n"),
|
|
34578
|
+
"Skills Catalog"
|
|
34579
|
+
);
|
|
34580
|
+
continue;
|
|
34581
|
+
}
|
|
33842
34582
|
if (surfaceChoice === "hosted-auth") {
|
|
33843
34583
|
await runHostedBridgeEntry({ config: opts?.config, dataDir: opts?.dataDir });
|
|
33844
34584
|
continue;
|
|
@@ -33853,12 +34593,12 @@ function isInstallerMode() {
|
|
|
33853
34593
|
}
|
|
33854
34594
|
function listLocalSurfaces() {
|
|
33855
34595
|
const homeDir = resolvePaperclipHomeDir();
|
|
33856
|
-
const instancesDir =
|
|
33857
|
-
if (!
|
|
33858
|
-
return
|
|
34596
|
+
const instancesDir = path66.resolve(homeDir, "instances");
|
|
34597
|
+
if (!fs59.existsSync(instancesDir)) return [];
|
|
34598
|
+
return fs59.readdirSync(instancesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
33859
34599
|
const instanceId = entry.name;
|
|
33860
|
-
const configPath =
|
|
33861
|
-
if (!
|
|
34600
|
+
const configPath = path66.resolve(instancesDir, instanceId, "config.json");
|
|
34601
|
+
if (!fs59.existsSync(configPath)) return null;
|
|
33862
34602
|
try {
|
|
33863
34603
|
const config = readConfig(configPath);
|
|
33864
34604
|
if (!config) return null;
|
|
@@ -34020,6 +34760,7 @@ registerGithubCommands(program);
|
|
|
34020
34760
|
registerIntegrationsCommands(program);
|
|
34021
34761
|
registerStatusCommands(program);
|
|
34022
34762
|
registerStarterCommands(program);
|
|
34763
|
+
registerSkillsCommands(program);
|
|
34023
34764
|
registerFleetCommands(program);
|
|
34024
34765
|
if (surfaceRuntime.capabilities.dxEnabled) {
|
|
34025
34766
|
registerDxCommands(program);
|