@growthub/cli 0.7.9 → 0.8.1
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-agency-portal-starter-v1/.env.example +53 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/QUICKSTART.md +98 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/.env.example +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/README.md +36 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/api/settings/integrations/route.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/api/workspace/route.js +27 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/globals.css +237 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/layout.jsx +14 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/page.jsx +165 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/settings/integrations/page.jsx +134 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/auth/index.js +21 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/env.js +28 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/integrations/growthub-connection-normalizer.js +95 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/integrations/index.js +178 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/payments/index.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/index.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/postgres.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/provider-managed.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/qstash-kv.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/domain/integrations.js +185 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/domain/portal.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/next.config.js +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package-lock.json +976 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package.json +17 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/postcss.config.mjs +3 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/vercel.json +5 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/NEW-CLIENT.md +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/_template/brand-kit.md +27 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/growthub/brand-kit.md +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/bundles/growthub-agency-portal-starter-v1.json +65 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/adapter-contracts.md +79 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/fork-sync-integration.md +32 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/governed-workspace-primitives.md +182 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/starter-kit-overview.md +30 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/vercel-serverless-deployment.md +46 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/vite-ui-shell-guide.md +24 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/examples/portal-brief-sample.md +44 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/examples/workspace-sample.md +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/growthub-meta/README.md +11 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/growthub-meta/kit-standard.md +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/helpers/README.md +49 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/kit.json +156 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/output/README.md +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/output-standards.md +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/runtime-assumptions.md +15 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/setup/check-deps.sh +20 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/setup/verify-env.mjs +92 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/skills/README.md +55 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/skills.md +133 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/index.html +12 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/package-lock.json +1677 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/package.json +20 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/serve.mjs +42 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/App.jsx +162 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/app.css +138 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/main.jsx +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/vite.config.js +8 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/agent-contract.md +9 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/client-onboarding-plan.md +56 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/deployment-handoff.md +61 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/deployment-plan.md +22 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/portal-brief.md +65 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/project.md +55 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/supabase-setup-plan.md +26 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/workspace-brief.md +11 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/validation-checklist.md +32 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/workers/agency-portal-operator/CLAUDE.md +75 -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/SKILL.md +89 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/bundles/growthub-video-use-studio-v1.json +6 -1
- 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 +14 -2
- package/assets/worker-kits/growthub-video-use-studio-v1/skills/README.md +23 -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/self-eval.md +67 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/workers/video-use-studio-operator/CLAUDE.md +22 -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 +970 -241
- 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)
|
|
@@ -8519,6 +8519,15 @@ var init_catalog = __esm({
|
|
|
8519
8519
|
activationModes: ["export"],
|
|
8520
8520
|
family: "studio"
|
|
8521
8521
|
},
|
|
8522
|
+
{
|
|
8523
|
+
id: "growthub-agency-portal-starter-v1",
|
|
8524
|
+
packageDirName: "growthub-agency-portal-starter-v1",
|
|
8525
|
+
defaultBundleId: "growthub-agency-portal-starter-v1",
|
|
8526
|
+
type: "worker",
|
|
8527
|
+
executionMode: "export",
|
|
8528
|
+
activationModes: ["export"],
|
|
8529
|
+
family: "studio"
|
|
8530
|
+
},
|
|
8522
8531
|
{
|
|
8523
8532
|
id: "growthub-twenty-crm-v1",
|
|
8524
8533
|
packageDirName: "growthub-twenty-crm-v1",
|
|
@@ -9711,9 +9720,9 @@ async function fetchHostedIntegrations(session) {
|
|
|
9711
9720
|
}
|
|
9712
9721
|
async function fetchHostedIntegrationCredential(session, providerId) {
|
|
9713
9722
|
const client = toApiClient2(session);
|
|
9714
|
-
const
|
|
9723
|
+
const path67 = `${DEFAULT_INTEGRATION_CREDENTIAL_PATH}&provider=${encodeURIComponent(providerId)}`;
|
|
9715
9724
|
try {
|
|
9716
|
-
return await client.get(
|
|
9725
|
+
return await client.get(path67, { ignoreNotFound: true });
|
|
9717
9726
|
} catch (err) {
|
|
9718
9727
|
if (err instanceof ApiRequestError && (err.status === 404 || err.status === 501)) {
|
|
9719
9728
|
throw new HostedEndpointUnavailableError(err.status, err.message);
|
|
@@ -10287,13 +10296,43 @@ var init_github = __esm({
|
|
|
10287
10296
|
}
|
|
10288
10297
|
});
|
|
10289
10298
|
|
|
10290
|
-
// src/starter/
|
|
10299
|
+
// src/starter/scaffold-session-memory.ts
|
|
10291
10300
|
import fs43 from "node:fs";
|
|
10292
10301
|
import path51 from "node:path";
|
|
10302
|
+
function scaffoldSessionMemory(input) {
|
|
10303
|
+
const forkPath = path51.resolve(input.forkPath);
|
|
10304
|
+
const templatePath = path51.join(forkPath, TEMPLATE_RELATIVE);
|
|
10305
|
+
const projectMdPath = path51.join(forkPath, PROJECT_MD_RELATIVE);
|
|
10306
|
+
if (!fs43.existsSync(templatePath)) {
|
|
10307
|
+
return { written: false, projectMdPath, templatePath: null };
|
|
10308
|
+
}
|
|
10309
|
+
if (fs43.existsSync(projectMdPath)) {
|
|
10310
|
+
return { written: false, projectMdPath, templatePath };
|
|
10311
|
+
}
|
|
10312
|
+
const template = fs43.readFileSync(templatePath, "utf8");
|
|
10313
|
+
const startedAt = input.startedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
10314
|
+
const sourceRef = input.sourceRef ?? "";
|
|
10315
|
+
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);
|
|
10316
|
+
fs43.mkdirSync(path51.dirname(projectMdPath), { recursive: true });
|
|
10317
|
+
fs43.writeFileSync(projectMdPath, seeded, "utf8");
|
|
10318
|
+
return { written: true, projectMdPath, templatePath };
|
|
10319
|
+
}
|
|
10320
|
+
var PROJECT_MD_RELATIVE, TEMPLATE_RELATIVE;
|
|
10321
|
+
var init_scaffold_session_memory = __esm({
|
|
10322
|
+
"src/starter/scaffold-session-memory.ts"() {
|
|
10323
|
+
"use strict";
|
|
10324
|
+
PROJECT_MD_RELATIVE = ".growthub-fork/project.md";
|
|
10325
|
+
TEMPLATE_RELATIVE = "templates/project.md";
|
|
10326
|
+
}
|
|
10327
|
+
});
|
|
10328
|
+
|
|
10329
|
+
// src/starter/init.ts
|
|
10330
|
+
import fs44 from "node:fs";
|
|
10331
|
+
import path52 from "node:path";
|
|
10293
10332
|
async function initStarterWorkspace(opts) {
|
|
10294
10333
|
const kitId = opts.kitId ?? DEFAULT_STARTER_KIT_ID;
|
|
10295
|
-
const absOut =
|
|
10296
|
-
if (
|
|
10334
|
+
const absOut = path52.resolve(opts.out);
|
|
10335
|
+
if (fs44.existsSync(absOut) && fs44.readdirSync(absOut).length > 0) {
|
|
10297
10336
|
throw new Error(`Destination ${absOut} already exists and is not empty.`);
|
|
10298
10337
|
}
|
|
10299
10338
|
const info = getBundledKitSourceInfo(kitId);
|
|
@@ -10302,7 +10341,7 @@ async function initStarterWorkspace(opts) {
|
|
|
10302
10341
|
forkPath: absOut,
|
|
10303
10342
|
kitId: info.id,
|
|
10304
10343
|
baseVersion: info.version,
|
|
10305
|
-
label: opts.name?.trim() ||
|
|
10344
|
+
label: opts.name?.trim() || path52.basename(absOut)
|
|
10306
10345
|
});
|
|
10307
10346
|
const policy = {
|
|
10308
10347
|
...makeDefaultKitForkPolicy(),
|
|
@@ -10322,6 +10361,22 @@ async function initStarterWorkspace(opts) {
|
|
|
10322
10361
|
type: "policy_updated",
|
|
10323
10362
|
summary: `Initial policy seeded (remoteSyncMode=${policy.remoteSyncMode})`
|
|
10324
10363
|
});
|
|
10364
|
+
const sessionSeed = scaffoldSessionMemory({
|
|
10365
|
+
forkPath: absOut,
|
|
10366
|
+
kitId: info.id,
|
|
10367
|
+
forkId: reg.forkId,
|
|
10368
|
+
source: "greenfield",
|
|
10369
|
+
sourceRef: ""
|
|
10370
|
+
});
|
|
10371
|
+
if (sessionSeed.written) {
|
|
10372
|
+
appendKitForkTraceEvent(absOut, {
|
|
10373
|
+
forkId: reg.forkId,
|
|
10374
|
+
kitId: reg.kitId,
|
|
10375
|
+
type: "skills_scaffolded",
|
|
10376
|
+
summary: "Seeded .growthub-fork/project.md from templates/project.md",
|
|
10377
|
+
detail: { projectMd: sessionSeed.projectMdPath }
|
|
10378
|
+
});
|
|
10379
|
+
}
|
|
10325
10380
|
let remote;
|
|
10326
10381
|
if (opts.upstream) {
|
|
10327
10382
|
const resolved = await resolveGithubAccessToken();
|
|
@@ -10383,6 +10438,7 @@ var init_init = __esm({
|
|
|
10383
10438
|
init_fork_remote();
|
|
10384
10439
|
init_github_resolver();
|
|
10385
10440
|
init_client2();
|
|
10441
|
+
init_scaffold_session_memory();
|
|
10386
10442
|
DEFAULT_STARTER_KIT_ID = "growthub-custom-workspace-starter-v1";
|
|
10387
10443
|
}
|
|
10388
10444
|
});
|
|
@@ -10395,8 +10451,8 @@ var init_types2 = __esm({
|
|
|
10395
10451
|
});
|
|
10396
10452
|
|
|
10397
10453
|
// src/starter/source-import/github-source.ts
|
|
10398
|
-
import
|
|
10399
|
-
import
|
|
10454
|
+
import fs45 from "node:fs";
|
|
10455
|
+
import path53 from "node:path";
|
|
10400
10456
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
10401
10457
|
function baseHeaders() {
|
|
10402
10458
|
return {
|
|
@@ -10527,12 +10583,12 @@ function cloneGithubRepo(input) {
|
|
|
10527
10583
|
if (!gitAvailable()) {
|
|
10528
10584
|
throw new Error("`git` is not available on PATH \u2014 cannot clone.");
|
|
10529
10585
|
}
|
|
10530
|
-
if (
|
|
10586
|
+
if (fs45.existsSync(input.destination)) {
|
|
10531
10587
|
throw new Error(`Clone destination already exists: ${input.destination}`);
|
|
10532
10588
|
}
|
|
10533
10589
|
const cloneUrl = input.token ? buildTokenCloneUrl(input.probe.repo, input.token) : input.probe.cloneUrl;
|
|
10534
|
-
const parent =
|
|
10535
|
-
|
|
10590
|
+
const parent = path53.dirname(input.destination);
|
|
10591
|
+
fs45.mkdirSync(parent, { recursive: true });
|
|
10536
10592
|
const depth = input.depth ?? 1;
|
|
10537
10593
|
const branch = input.branch ?? input.probe.defaultBranch;
|
|
10538
10594
|
const args = ["clone"];
|
|
@@ -10559,17 +10615,17 @@ function cloneGithubRepo(input) {
|
|
|
10559
10615
|
function narrowToSubdirectory(rootDir, subdirectory) {
|
|
10560
10616
|
const normalizedSub = subdirectory.replace(/^\/+|\/+$/g, "");
|
|
10561
10617
|
if (!normalizedSub) return;
|
|
10562
|
-
const abs =
|
|
10563
|
-
if (!
|
|
10618
|
+
const abs = path53.resolve(rootDir, normalizedSub);
|
|
10619
|
+
if (!fs45.existsSync(abs) || !fs45.statSync(abs).isDirectory()) {
|
|
10564
10620
|
throw new Error(`Subdirectory not found in cloned repo: ${subdirectory}`);
|
|
10565
10621
|
}
|
|
10566
|
-
const tmp =
|
|
10567
|
-
|
|
10568
|
-
`.${
|
|
10622
|
+
const tmp = path53.resolve(
|
|
10623
|
+
path53.dirname(rootDir),
|
|
10624
|
+
`.${path53.basename(rootDir)}-narrow-${Date.now().toString(36)}`
|
|
10569
10625
|
);
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10626
|
+
fs45.renameSync(abs, tmp);
|
|
10627
|
+
fs45.rmSync(rootDir, { recursive: true, force: true });
|
|
10628
|
+
fs45.renameSync(tmp, rootDir);
|
|
10573
10629
|
}
|
|
10574
10630
|
var GITHUB_API_BASE2;
|
|
10575
10631
|
var init_github_source = __esm({
|
|
@@ -10583,9 +10639,9 @@ var init_github_source = __esm({
|
|
|
10583
10639
|
});
|
|
10584
10640
|
|
|
10585
10641
|
// src/starter/source-import/skills-source.ts
|
|
10586
|
-
import
|
|
10642
|
+
import fs46 from "node:fs";
|
|
10587
10643
|
import os11 from "node:os";
|
|
10588
|
-
import
|
|
10644
|
+
import path54 from "node:path";
|
|
10589
10645
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
10590
10646
|
function resolveBase() {
|
|
10591
10647
|
const raw = process.env.SKILLS_SH_BASE?.trim();
|
|
@@ -10851,9 +10907,9 @@ async function probeSkillsSource(input) {
|
|
|
10851
10907
|
};
|
|
10852
10908
|
}
|
|
10853
10909
|
function assertInsidePayloadRoot(root, candidate) {
|
|
10854
|
-
const abs =
|
|
10855
|
-
const rootAbs =
|
|
10856
|
-
if (!abs.startsWith(rootAbs +
|
|
10910
|
+
const abs = path54.resolve(candidate);
|
|
10911
|
+
const rootAbs = path54.resolve(root);
|
|
10912
|
+
if (!abs.startsWith(rootAbs + path54.sep) && abs !== rootAbs) {
|
|
10857
10913
|
throw new Error(`Refusing to write outside payload root: ${candidate}`);
|
|
10858
10914
|
}
|
|
10859
10915
|
}
|
|
@@ -10869,24 +10925,24 @@ function runGit3(args, cwd) {
|
|
|
10869
10925
|
};
|
|
10870
10926
|
}
|
|
10871
10927
|
function skillDirectoryMatches(dir, skillSlug) {
|
|
10872
|
-
const skillFile =
|
|
10873
|
-
if (!
|
|
10928
|
+
const skillFile = path54.resolve(dir, "SKILL.md");
|
|
10929
|
+
if (!fs46.existsSync(skillFile) || !fs46.statSync(skillFile).isFile()) {
|
|
10874
10930
|
return false;
|
|
10875
10931
|
}
|
|
10876
|
-
if (
|
|
10932
|
+
if (path54.basename(dir) === skillSlug) {
|
|
10877
10933
|
return true;
|
|
10878
10934
|
}
|
|
10879
|
-
const content =
|
|
10935
|
+
const content = fs46.readFileSync(skillFile, "utf8");
|
|
10880
10936
|
const nameMatch = content.match(/(?:^|\n)name:\s*["']?([A-Za-z0-9._:-]+)["']?\s*(?:\n|$)/i);
|
|
10881
10937
|
return nameMatch?.[1] === skillSlug;
|
|
10882
10938
|
}
|
|
10883
10939
|
function locateSkillDirectory(root, skillSlug) {
|
|
10884
10940
|
const preferred = [
|
|
10885
|
-
|
|
10886
|
-
|
|
10941
|
+
path54.resolve(root, "skills", skillSlug),
|
|
10942
|
+
path54.resolve(root, skillSlug)
|
|
10887
10943
|
];
|
|
10888
10944
|
for (const candidate of preferred) {
|
|
10889
|
-
if (
|
|
10945
|
+
if (fs46.existsSync(candidate) && fs46.statSync(candidate).isDirectory() && skillDirectoryMatches(candidate, skillSlug)) {
|
|
10890
10946
|
return candidate;
|
|
10891
10947
|
}
|
|
10892
10948
|
}
|
|
@@ -10896,12 +10952,12 @@ function locateSkillDirectory(root, skillSlug) {
|
|
|
10896
10952
|
if (skillDirectoryMatches(current, skillSlug)) {
|
|
10897
10953
|
return current;
|
|
10898
10954
|
}
|
|
10899
|
-
for (const entry of
|
|
10955
|
+
for (const entry of fs46.readdirSync(current, { withFileTypes: true })) {
|
|
10900
10956
|
if (!entry.isDirectory()) continue;
|
|
10901
10957
|
if ([".git", "node_modules", ".next", "dist", "build", "coverage"].includes(entry.name)) {
|
|
10902
10958
|
continue;
|
|
10903
10959
|
}
|
|
10904
|
-
queue.push(
|
|
10960
|
+
queue.push(path54.resolve(current, entry.name));
|
|
10905
10961
|
}
|
|
10906
10962
|
}
|
|
10907
10963
|
return null;
|
|
@@ -10911,18 +10967,18 @@ function copySkillTree(sourceDir, destination) {
|
|
|
10911
10967
|
const stack = [{ from: sourceDir, to: destination }];
|
|
10912
10968
|
while (stack.length > 0) {
|
|
10913
10969
|
const current = stack.pop();
|
|
10914
|
-
|
|
10915
|
-
for (const entry of
|
|
10916
|
-
const fromPath =
|
|
10917
|
-
const toPath =
|
|
10970
|
+
fs46.mkdirSync(current.to, { recursive: true });
|
|
10971
|
+
for (const entry of fs46.readdirSync(current.from, { withFileTypes: true })) {
|
|
10972
|
+
const fromPath = path54.resolve(current.from, entry.name);
|
|
10973
|
+
const toPath = path54.resolve(current.to, entry.name);
|
|
10918
10974
|
assertInsidePayloadRoot(destination, toPath);
|
|
10919
10975
|
if (entry.isDirectory()) {
|
|
10920
10976
|
stack.push({ from: fromPath, to: toPath });
|
|
10921
10977
|
continue;
|
|
10922
10978
|
}
|
|
10923
|
-
const data =
|
|
10924
|
-
|
|
10925
|
-
|
|
10979
|
+
const data = fs46.readFileSync(fromPath);
|
|
10980
|
+
fs46.mkdirSync(path54.dirname(toPath), { recursive: true });
|
|
10981
|
+
fs46.writeFileSync(toPath, data, { mode: 420 });
|
|
10926
10982
|
written += 1;
|
|
10927
10983
|
}
|
|
10928
10984
|
}
|
|
@@ -10933,7 +10989,7 @@ async function fetchSkillPayload(input) {
|
|
|
10933
10989
|
if (!gitAvailable()) {
|
|
10934
10990
|
throw new Error("`git` is not available on PATH \u2014 cannot materialize a skills.sh payload.");
|
|
10935
10991
|
}
|
|
10936
|
-
if (
|
|
10992
|
+
if (fs46.existsSync(destination)) {
|
|
10937
10993
|
throw new Error(`Skill payload destination already exists: ${destination}`);
|
|
10938
10994
|
}
|
|
10939
10995
|
const repoSource = probe.repoUrl ?? (probe.repository ? `https://github.com/${probe.repository}` : void 0);
|
|
@@ -10941,11 +10997,11 @@ async function fetchSkillPayload(input) {
|
|
|
10941
10997
|
if (!repoSource || !skillSlug) {
|
|
10942
10998
|
throw new Error(`Skill '${probe.skillId}' is missing repository metadata \u2014 cannot materialize payload.`);
|
|
10943
10999
|
}
|
|
10944
|
-
const cloneRoot =
|
|
10945
|
-
|
|
11000
|
+
const cloneRoot = fs46.mkdtempSync(
|
|
11001
|
+
path54.join(os11.tmpdir(), "growthub-skills-source-")
|
|
10946
11002
|
);
|
|
10947
11003
|
try {
|
|
10948
|
-
const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot],
|
|
11004
|
+
const cloneRes = runGit3(["clone", "--depth", "1", repoSource, cloneRoot], path54.dirname(cloneRoot));
|
|
10949
11005
|
if (!cloneRes.ok) {
|
|
10950
11006
|
throw new Error(`git clone failed: ${cloneRes.stderr || "unable to clone skill repository"}`);
|
|
10951
11007
|
}
|
|
@@ -10958,7 +11014,7 @@ async function fetchSkillPayload(input) {
|
|
|
10958
11014
|
const fileCount = copySkillTree(skillDir, destination);
|
|
10959
11015
|
return { destination, fileCount };
|
|
10960
11016
|
} finally {
|
|
10961
|
-
|
|
11017
|
+
fs46.rmSync(cloneRoot, { recursive: true, force: true });
|
|
10962
11018
|
}
|
|
10963
11019
|
}
|
|
10964
11020
|
var DEFAULT_BASE, COMMENT_PATTERN;
|
|
@@ -10972,13 +11028,13 @@ var init_skills_source = __esm({
|
|
|
10972
11028
|
});
|
|
10973
11029
|
|
|
10974
11030
|
// src/starter/source-import/detect.ts
|
|
10975
|
-
import
|
|
10976
|
-
import
|
|
11031
|
+
import fs47 from "node:fs";
|
|
11032
|
+
import path55 from "node:path";
|
|
10977
11033
|
function safeReadPackageJson(dir) {
|
|
10978
|
-
const p35 =
|
|
10979
|
-
if (!
|
|
11034
|
+
const p35 = path55.resolve(dir, "package.json");
|
|
11035
|
+
if (!fs47.existsSync(p35)) return null;
|
|
10980
11036
|
try {
|
|
10981
|
-
return JSON.parse(
|
|
11037
|
+
return JSON.parse(fs47.readFileSync(p35, "utf8"));
|
|
10982
11038
|
} catch {
|
|
10983
11039
|
return null;
|
|
10984
11040
|
}
|
|
@@ -10988,10 +11044,10 @@ function detectPackageManager(dir, pkg) {
|
|
|
10988
11044
|
if (pkg?.packageManager?.startsWith("yarn")) return "yarn";
|
|
10989
11045
|
if (pkg?.packageManager?.startsWith("npm")) return "npm";
|
|
10990
11046
|
if (pkg?.packageManager?.startsWith("bun")) return "bun";
|
|
10991
|
-
if (
|
|
10992
|
-
if (
|
|
10993
|
-
if (
|
|
10994
|
-
if (
|
|
11047
|
+
if (fs47.existsSync(path55.resolve(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
11048
|
+
if (fs47.existsSync(path55.resolve(dir, "yarn.lock"))) return "yarn";
|
|
11049
|
+
if (fs47.existsSync(path55.resolve(dir, "bun.lockb"))) return "bun";
|
|
11050
|
+
if (fs47.existsSync(path55.resolve(dir, "package-lock.json"))) return "npm";
|
|
10995
11051
|
return "unknown";
|
|
10996
11052
|
}
|
|
10997
11053
|
function collectDeps(pkg) {
|
|
@@ -11005,12 +11061,12 @@ function collectDeps(pkg) {
|
|
|
11005
11061
|
}
|
|
11006
11062
|
function looksLikeSkillPayload(rootDir) {
|
|
11007
11063
|
const markers = ["SKILL.md", "skill.md", "skill.json", "skill.yml", "skill.yaml", "prompt.md"];
|
|
11008
|
-
return markers.some((name) =>
|
|
11064
|
+
return markers.some((name) => fs47.existsSync(path55.resolve(rootDir, name)));
|
|
11009
11065
|
}
|
|
11010
11066
|
function detectFramework(rootDir, pkg) {
|
|
11011
11067
|
if (!pkg) {
|
|
11012
11068
|
if (looksLikeSkillPayload(rootDir)) return "skill";
|
|
11013
|
-
if (
|
|
11069
|
+
if (fs47.existsSync(path55.resolve(rootDir, "docs"))) return "docs";
|
|
11014
11070
|
return "unknown";
|
|
11015
11071
|
}
|
|
11016
11072
|
const deps = collectDeps(pkg);
|
|
@@ -11019,8 +11075,8 @@ function detectFramework(rootDir, pkg) {
|
|
|
11019
11075
|
"vite.config.ts",
|
|
11020
11076
|
"vite.config.mjs",
|
|
11021
11077
|
"vite.config.cjs"
|
|
11022
|
-
].some((name) =>
|
|
11023
|
-
if (deps.has("next") ||
|
|
11078
|
+
].some((name) => fs47.existsSync(path55.resolve(rootDir, name)));
|
|
11079
|
+
if (deps.has("next") || fs47.existsSync(path55.resolve(rootDir, "next.config.js")) || fs47.existsSync(path55.resolve(rootDir, "next.config.mjs"))) {
|
|
11024
11080
|
return "next";
|
|
11025
11081
|
}
|
|
11026
11082
|
if (deps.has("vite") || hasViteConfig) return "vite";
|
|
@@ -11046,15 +11102,15 @@ function pickScripts(pkg) {
|
|
|
11046
11102
|
return out;
|
|
11047
11103
|
}
|
|
11048
11104
|
function listEnvFiles(dir) {
|
|
11049
|
-
if (!
|
|
11050
|
-
return
|
|
11105
|
+
if (!fs47.existsSync(dir)) return [];
|
|
11106
|
+
return fs47.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).filter((name) => name === ".env" || name.startsWith(".env.") || name === ".env.example");
|
|
11051
11107
|
}
|
|
11052
11108
|
function findAppRoot(rootDir, pkg) {
|
|
11053
11109
|
if (pkg) return ".";
|
|
11054
11110
|
const candidates = ["app", "src", "apps", "packages"];
|
|
11055
11111
|
for (const candidate of candidates) {
|
|
11056
|
-
const abs =
|
|
11057
|
-
if (
|
|
11112
|
+
const abs = path55.resolve(rootDir, candidate);
|
|
11113
|
+
if (fs47.existsSync(abs) && fs47.statSync(abs).isDirectory()) {
|
|
11058
11114
|
const child = safeReadPackageJson(abs);
|
|
11059
11115
|
if (child) return candidate;
|
|
11060
11116
|
}
|
|
@@ -11070,12 +11126,12 @@ function computeConfidence(framework, manager, pkg) {
|
|
|
11070
11126
|
return Math.min(1, Number(score.toFixed(2)));
|
|
11071
11127
|
}
|
|
11072
11128
|
function detectSourceShape(rootDir) {
|
|
11073
|
-
if (!
|
|
11129
|
+
if (!fs47.existsSync(rootDir) || !fs47.statSync(rootDir).isDirectory()) {
|
|
11074
11130
|
throw new Error(`Detection target is not a directory: ${rootDir}`);
|
|
11075
11131
|
}
|
|
11076
11132
|
const rootPkg = safeReadPackageJson(rootDir);
|
|
11077
11133
|
const appRootRel = findAppRoot(rootDir, rootPkg);
|
|
11078
|
-
const appRootAbs =
|
|
11134
|
+
const appRootAbs = path55.resolve(rootDir, appRootRel);
|
|
11079
11135
|
const appPkg = appRootRel === "." ? rootPkg : safeReadPackageJson(appRootAbs);
|
|
11080
11136
|
const framework = detectFramework(appRootAbs, appPkg ?? rootPkg);
|
|
11081
11137
|
const packageManager = detectPackageManager(rootDir, rootPkg ?? appPkg);
|
|
@@ -11115,18 +11171,18 @@ var init_detect = __esm({
|
|
|
11115
11171
|
});
|
|
11116
11172
|
|
|
11117
11173
|
// src/starter/source-import/security.ts
|
|
11118
|
-
import
|
|
11119
|
-
import
|
|
11174
|
+
import fs48 from "node:fs";
|
|
11175
|
+
import path56 from "node:path";
|
|
11120
11176
|
function isLikelyTextFile(filename) {
|
|
11121
|
-
const ext =
|
|
11177
|
+
const ext = path56.extname(filename).toLowerCase();
|
|
11122
11178
|
if (!ext) return true;
|
|
11123
11179
|
return TEXT_EXTENSIONS.has(ext);
|
|
11124
11180
|
}
|
|
11125
11181
|
function isSuspiciousBinary(filename) {
|
|
11126
|
-
return SUSPICIOUS_BINARY_EXTENSIONS.has(
|
|
11182
|
+
return SUSPICIOUS_BINARY_EXTENSIONS.has(path56.extname(filename).toLowerCase());
|
|
11127
11183
|
}
|
|
11128
11184
|
function isUnexpectedArchive(filename) {
|
|
11129
|
-
const ext =
|
|
11185
|
+
const ext = path56.extname(filename).toLowerCase();
|
|
11130
11186
|
return ARCHIVE_EXTENSIONS.has(ext) || filename.toLowerCase().endsWith(".tar.gz");
|
|
11131
11187
|
}
|
|
11132
11188
|
function shortExcerpt(line) {
|
|
@@ -11181,19 +11237,19 @@ function walkPayload(root, onFile, limits) {
|
|
|
11181
11237
|
if (!current) break;
|
|
11182
11238
|
let entries;
|
|
11183
11239
|
try {
|
|
11184
|
-
entries =
|
|
11240
|
+
entries = fs48.readdirSync(current, { withFileTypes: true });
|
|
11185
11241
|
} catch {
|
|
11186
11242
|
continue;
|
|
11187
11243
|
}
|
|
11188
11244
|
for (const entry of entries) {
|
|
11189
|
-
const abs =
|
|
11245
|
+
const abs = path56.resolve(current, entry.name);
|
|
11190
11246
|
if (entry.isDirectory()) {
|
|
11191
11247
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
11192
11248
|
stack.push(abs);
|
|
11193
11249
|
continue;
|
|
11194
11250
|
}
|
|
11195
11251
|
if (!entry.isFile()) continue;
|
|
11196
|
-
const rel =
|
|
11252
|
+
const rel = path56.relative(root, abs);
|
|
11197
11253
|
onFile(abs, rel);
|
|
11198
11254
|
visited += 1;
|
|
11199
11255
|
if (visited >= limits.maxFiles) break;
|
|
@@ -11203,7 +11259,7 @@ function walkPayload(root, onFile, limits) {
|
|
|
11203
11259
|
}
|
|
11204
11260
|
function inspectSourcePayload(input) {
|
|
11205
11261
|
const { payloadRoot } = input;
|
|
11206
|
-
if (!
|
|
11262
|
+
if (!fs48.existsSync(payloadRoot) || !fs48.statSync(payloadRoot).isDirectory()) {
|
|
11207
11263
|
throw new Error(`Inspection target is not a directory: ${payloadRoot}`);
|
|
11208
11264
|
}
|
|
11209
11265
|
const findings = [];
|
|
@@ -11213,7 +11269,7 @@ function inspectSourcePayload(input) {
|
|
|
11213
11269
|
(abs, rel) => {
|
|
11214
11270
|
let size = 0;
|
|
11215
11271
|
try {
|
|
11216
|
-
size =
|
|
11272
|
+
size = fs48.statSync(abs).size;
|
|
11217
11273
|
} catch {
|
|
11218
11274
|
return;
|
|
11219
11275
|
}
|
|
@@ -11222,7 +11278,7 @@ function inspectSourcePayload(input) {
|
|
|
11222
11278
|
category: "suspicious-binary",
|
|
11223
11279
|
severity: "high-risk",
|
|
11224
11280
|
path: rel,
|
|
11225
|
-
message: `Payload ships a precompiled binary (${
|
|
11281
|
+
message: `Payload ships a precompiled binary (${path56.extname(rel)}). Review provenance before use.`
|
|
11226
11282
|
});
|
|
11227
11283
|
return;
|
|
11228
11284
|
}
|
|
@@ -11231,7 +11287,7 @@ function inspectSourcePayload(input) {
|
|
|
11231
11287
|
category: "unexpected-archive",
|
|
11232
11288
|
severity: "caution",
|
|
11233
11289
|
path: rel,
|
|
11234
|
-
message: `Payload ships an archive (${
|
|
11290
|
+
message: `Payload ships an archive (${path56.extname(rel)}) \u2014 expand and review contents before use.`
|
|
11235
11291
|
});
|
|
11236
11292
|
return;
|
|
11237
11293
|
}
|
|
@@ -11239,12 +11295,12 @@ function inspectSourcePayload(input) {
|
|
|
11239
11295
|
if (bytesInspected + Math.min(size, MAX_BYTES_PER_FILE) > MAX_TOTAL_BYTES) return;
|
|
11240
11296
|
let buf;
|
|
11241
11297
|
try {
|
|
11242
|
-
const handle =
|
|
11298
|
+
const handle = fs48.openSync(abs, "r");
|
|
11243
11299
|
try {
|
|
11244
11300
|
buf = Buffer.alloc(Math.min(size, MAX_BYTES_PER_FILE));
|
|
11245
|
-
|
|
11301
|
+
fs48.readSync(handle, buf, 0, buf.length, 0);
|
|
11246
11302
|
} finally {
|
|
11247
|
-
|
|
11303
|
+
fs48.closeSync(handle);
|
|
11248
11304
|
}
|
|
11249
11305
|
} catch {
|
|
11250
11306
|
return;
|
|
@@ -11453,18 +11509,18 @@ var init_security = __esm({
|
|
|
11453
11509
|
});
|
|
11454
11510
|
|
|
11455
11511
|
// src/starter/source-import/plan.ts
|
|
11456
|
-
import
|
|
11457
|
-
import
|
|
11512
|
+
import fs49 from "node:fs";
|
|
11513
|
+
import path57 from "node:path";
|
|
11458
11514
|
function generateImportId() {
|
|
11459
11515
|
return `si-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
|
|
11460
11516
|
}
|
|
11461
11517
|
function destinationState(absDest) {
|
|
11462
|
-
if (!
|
|
11463
|
-
const stats =
|
|
11518
|
+
if (!fs49.existsSync(absDest)) return { exists: false, nonEmpty: false };
|
|
11519
|
+
const stats = fs49.statSync(absDest);
|
|
11464
11520
|
if (!stats.isDirectory()) {
|
|
11465
11521
|
throw new Error(`Destination is not a directory: ${absDest}`);
|
|
11466
11522
|
}
|
|
11467
|
-
const entries =
|
|
11523
|
+
const entries = fs49.readdirSync(absDest);
|
|
11468
11524
|
return { exists: true, nonEmpty: entries.length > 0 };
|
|
11469
11525
|
}
|
|
11470
11526
|
function describeSource(probe) {
|
|
@@ -11474,7 +11530,7 @@ function describeSource(probe) {
|
|
|
11474
11530
|
return `skill ${probe.skillId}@${probe.version} (skills.sh)`;
|
|
11475
11531
|
}
|
|
11476
11532
|
function buildSourceImportPlan(input) {
|
|
11477
|
-
const absDest =
|
|
11533
|
+
const absDest = path57.resolve(input.destination);
|
|
11478
11534
|
const state = destinationState(absDest);
|
|
11479
11535
|
const payloadPath = "imported";
|
|
11480
11536
|
const warnings = [...input.probe.warnings];
|
|
@@ -11587,8 +11643,8 @@ var init_plan = __esm({
|
|
|
11587
11643
|
});
|
|
11588
11644
|
|
|
11589
11645
|
// src/starter/source-import/summarize.ts
|
|
11590
|
-
import
|
|
11591
|
-
import
|
|
11646
|
+
import fs50 from "node:fs";
|
|
11647
|
+
import path58 from "node:path";
|
|
11592
11648
|
function sourceHeading(manifest) {
|
|
11593
11649
|
const src = manifest.source;
|
|
11594
11650
|
if (src.kind === "github-repo") {
|
|
@@ -11643,7 +11699,7 @@ function nextStepsSection(manifest) {
|
|
|
11643
11699
|
}
|
|
11644
11700
|
function writeImportSummary(input) {
|
|
11645
11701
|
const { forkPath, summaryRelativePath, manifest } = input;
|
|
11646
|
-
const summaryPath =
|
|
11702
|
+
const summaryPath = path58.resolve(forkPath, summaryRelativePath);
|
|
11647
11703
|
const body = [
|
|
11648
11704
|
`# Source Import Summary`,
|
|
11649
11705
|
``,
|
|
@@ -11673,8 +11729,8 @@ function writeImportSummary(input) {
|
|
|
11673
11729
|
`Generated by the Growthub Source Import Agent. Canonical manifest lives at \`.growthub-fork/source-import.json\`.`,
|
|
11674
11730
|
``
|
|
11675
11731
|
].join("\n");
|
|
11676
|
-
|
|
11677
|
-
|
|
11732
|
+
fs50.mkdirSync(path58.dirname(summaryPath), { recursive: true });
|
|
11733
|
+
fs50.writeFileSync(summaryPath, body, "utf8");
|
|
11678
11734
|
return summaryPath;
|
|
11679
11735
|
}
|
|
11680
11736
|
var init_summarize = __esm({
|
|
@@ -11684,16 +11740,16 @@ var init_summarize = __esm({
|
|
|
11684
11740
|
});
|
|
11685
11741
|
|
|
11686
11742
|
// src/starter/source-import/materialize.ts
|
|
11687
|
-
import
|
|
11743
|
+
import fs51 from "node:fs";
|
|
11688
11744
|
import os12 from "node:os";
|
|
11689
|
-
import
|
|
11745
|
+
import path59 from "node:path";
|
|
11690
11746
|
function resolveSourceKind(probe) {
|
|
11691
11747
|
return probe.kind === "github-repo" ? "github-repo" : "skills-skill";
|
|
11692
11748
|
}
|
|
11693
11749
|
function stagingDirFor(forkPath) {
|
|
11694
|
-
return
|
|
11750
|
+
return path59.join(
|
|
11695
11751
|
os12.tmpdir(),
|
|
11696
|
-
`growthub-source-import-${
|
|
11752
|
+
`growthub-source-import-${path59.basename(forkPath)}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
|
|
11697
11753
|
);
|
|
11698
11754
|
}
|
|
11699
11755
|
async function fetchPayload(probe, stagingDir, opts) {
|
|
@@ -11725,18 +11781,18 @@ async function fetchPayload(probe, stagingDir, opts) {
|
|
|
11725
11781
|
return { payloadRoot: stagingDir };
|
|
11726
11782
|
}
|
|
11727
11783
|
function movePayloadIntoFork(payloadRoot, forkPath, payloadRelativePath) {
|
|
11728
|
-
const target =
|
|
11729
|
-
if (
|
|
11730
|
-
|
|
11784
|
+
const target = path59.resolve(forkPath, payloadRelativePath);
|
|
11785
|
+
if (fs51.existsSync(target)) {
|
|
11786
|
+
fs51.rmSync(target, { recursive: true, force: true });
|
|
11731
11787
|
}
|
|
11732
|
-
|
|
11733
|
-
|
|
11788
|
+
fs51.mkdirSync(path59.dirname(target), { recursive: true });
|
|
11789
|
+
fs51.renameSync(payloadRoot, target);
|
|
11734
11790
|
return target;
|
|
11735
11791
|
}
|
|
11736
11792
|
function writeManifest(forkPath, manifest) {
|
|
11737
|
-
const p35 =
|
|
11738
|
-
|
|
11739
|
-
|
|
11793
|
+
const p35 = path59.resolve(forkPath, MANIFEST_RELATIVE_PATH);
|
|
11794
|
+
fs51.mkdirSync(path59.dirname(p35), { recursive: true });
|
|
11795
|
+
fs51.writeFileSync(p35, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
11740
11796
|
return p35;
|
|
11741
11797
|
}
|
|
11742
11798
|
function assertConfirmationsSatisfied(plan, confirmations) {
|
|
@@ -11776,7 +11832,7 @@ async function materializeImportPlan(input) {
|
|
|
11776
11832
|
requireSkillAcknowledgement: sourceKind === "skills-skill"
|
|
11777
11833
|
});
|
|
11778
11834
|
if (security.blocked) {
|
|
11779
|
-
|
|
11835
|
+
fs51.rmSync(fetchResult.payloadRoot, { recursive: true, force: true });
|
|
11780
11836
|
throw new Error(
|
|
11781
11837
|
`Security inspection blocked the fetched payload: ${security.summaryLines[0] ?? "blocking finding"}`
|
|
11782
11838
|
);
|
|
@@ -11855,6 +11911,22 @@ async function materializeImportPlan(input) {
|
|
|
11855
11911
|
detail: { gitSha: fetchResult.gitSha }
|
|
11856
11912
|
});
|
|
11857
11913
|
}
|
|
11914
|
+
const sessionSeed = scaffoldSessionMemory({
|
|
11915
|
+
forkPath,
|
|
11916
|
+
kitId: kitInfo.id,
|
|
11917
|
+
forkId: reg.forkId,
|
|
11918
|
+
source: sourceKind,
|
|
11919
|
+
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}`
|
|
11920
|
+
});
|
|
11921
|
+
if (sessionSeed.written) {
|
|
11922
|
+
appendKitForkTraceEvent(forkPath, {
|
|
11923
|
+
forkId: reg.forkId,
|
|
11924
|
+
kitId: reg.kitId,
|
|
11925
|
+
type: "skills_scaffolded",
|
|
11926
|
+
summary: "Seeded .growthub-fork/project.md from templates/project.md",
|
|
11927
|
+
detail: { projectMd: sessionSeed.projectMdPath }
|
|
11928
|
+
});
|
|
11929
|
+
}
|
|
11858
11930
|
const summaryPath = writeImportSummary({
|
|
11859
11931
|
forkPath,
|
|
11860
11932
|
summaryRelativePath: SUMMARY_RELATIVE_PATH,
|
|
@@ -11891,6 +11963,7 @@ var init_materialize = __esm({
|
|
|
11891
11963
|
init_detect();
|
|
11892
11964
|
init_security();
|
|
11893
11965
|
init_summarize();
|
|
11966
|
+
init_scaffold_session_memory();
|
|
11894
11967
|
MANIFEST_RELATIVE_PATH = ".growthub-fork/source-import.json";
|
|
11895
11968
|
SUMMARY_RELATIVE_PATH = "IMPORT_SUMMARY.md";
|
|
11896
11969
|
PendingConfirmationError = class extends Error {
|
|
@@ -11907,26 +11980,26 @@ var init_materialize = __esm({
|
|
|
11907
11980
|
});
|
|
11908
11981
|
|
|
11909
11982
|
// src/starter/source-import/agent.ts
|
|
11910
|
-
import
|
|
11911
|
-
import
|
|
11983
|
+
import fs52 from "node:fs";
|
|
11984
|
+
import path60 from "node:path";
|
|
11912
11985
|
function resolveJobsDir() {
|
|
11913
|
-
return
|
|
11986
|
+
return path60.resolve(resolveKitForksHomeDir(), "source-import-jobs");
|
|
11914
11987
|
}
|
|
11915
11988
|
function resolveJobPath2(jobId) {
|
|
11916
|
-
return
|
|
11989
|
+
return path60.resolve(resolveJobsDir(), `${jobId}.json`);
|
|
11917
11990
|
}
|
|
11918
11991
|
function generateJobId2() {
|
|
11919
11992
|
return `sij-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`;
|
|
11920
11993
|
}
|
|
11921
11994
|
function writeJob2(job) {
|
|
11922
11995
|
const p35 = resolveJobPath2(job.jobId);
|
|
11923
|
-
|
|
11924
|
-
|
|
11996
|
+
fs52.mkdirSync(path60.dirname(p35), { recursive: true });
|
|
11997
|
+
fs52.writeFileSync(p35, JSON.stringify(job, null, 2) + "\n", "utf8");
|
|
11925
11998
|
}
|
|
11926
11999
|
function readJobFile(p35) {
|
|
11927
|
-
if (!
|
|
12000
|
+
if (!fs52.existsSync(p35)) return null;
|
|
11928
12001
|
try {
|
|
11929
|
-
return JSON.parse(
|
|
12002
|
+
return JSON.parse(fs52.readFileSync(p35, "utf8"));
|
|
11930
12003
|
} catch {
|
|
11931
12004
|
return null;
|
|
11932
12005
|
}
|
|
@@ -11936,7 +12009,7 @@ function patchJob2(jobId, status, patch = {}) {
|
|
|
11936
12009
|
const job = readJobFile(p35);
|
|
11937
12010
|
if (!job) return null;
|
|
11938
12011
|
const updated = { ...job, ...patch, status };
|
|
11939
|
-
|
|
12012
|
+
fs52.writeFileSync(p35, JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
11940
12013
|
return updated;
|
|
11941
12014
|
}
|
|
11942
12015
|
function getSourceImportJob(jobId) {
|
|
@@ -11955,7 +12028,7 @@ async function probeAndPlan(input, destination) {
|
|
|
11955
12028
|
}
|
|
11956
12029
|
async function runSourceImportJob(input) {
|
|
11957
12030
|
const jobId = generateJobId2();
|
|
11958
|
-
const destination =
|
|
12031
|
+
const destination = path60.resolve(input.out);
|
|
11959
12032
|
const sourceKind = input.source.kind;
|
|
11960
12033
|
const initial = {
|
|
11961
12034
|
jobId,
|
|
@@ -12103,6 +12176,357 @@ var init_source_import = __esm({
|
|
|
12103
12176
|
}
|
|
12104
12177
|
});
|
|
12105
12178
|
|
|
12179
|
+
// src/skills/frontmatter.ts
|
|
12180
|
+
function splitFrontmatter(text69) {
|
|
12181
|
+
const normalised = text69.replace(/\r\n/g, "\n");
|
|
12182
|
+
if (!normalised.startsWith("---\n")) {
|
|
12183
|
+
return { frontmatter: null, body: normalised };
|
|
12184
|
+
}
|
|
12185
|
+
const end = normalised.indexOf("\n---\n", 4);
|
|
12186
|
+
if (end === -1) {
|
|
12187
|
+
return { frontmatter: null, body: normalised };
|
|
12188
|
+
}
|
|
12189
|
+
return {
|
|
12190
|
+
frontmatter: normalised.slice(4, end),
|
|
12191
|
+
body: normalised.slice(end + 5)
|
|
12192
|
+
};
|
|
12193
|
+
}
|
|
12194
|
+
function parseScalar(raw) {
|
|
12195
|
+
const trimmed = raw.trim();
|
|
12196
|
+
if (trimmed === "") return "";
|
|
12197
|
+
if (trimmed === "true") return true;
|
|
12198
|
+
if (trimmed === "false") return false;
|
|
12199
|
+
if (trimmed === "null" || trimmed === "~") return null;
|
|
12200
|
+
if (/^-?\d+$/.test(trimmed)) return Number(trimmed);
|
|
12201
|
+
if (/^-?\d*\.\d+$/.test(trimmed)) return Number(trimmed);
|
|
12202
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
12203
|
+
return trimmed.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
12204
|
+
}
|
|
12205
|
+
if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
12206
|
+
return trimmed.slice(1, -1).replace(/''/g, "'");
|
|
12207
|
+
}
|
|
12208
|
+
return trimmed;
|
|
12209
|
+
}
|
|
12210
|
+
function indentWidth(line) {
|
|
12211
|
+
const match = line.match(/^( *)/);
|
|
12212
|
+
return match ? match[1].length : 0;
|
|
12213
|
+
}
|
|
12214
|
+
function parseFrontmatter(text69) {
|
|
12215
|
+
const lines = text69.split("\n");
|
|
12216
|
+
const root = {};
|
|
12217
|
+
let i = 0;
|
|
12218
|
+
function readBlock(baseIndent) {
|
|
12219
|
+
const out = {};
|
|
12220
|
+
const arr = [];
|
|
12221
|
+
let mode = null;
|
|
12222
|
+
while (i < lines.length) {
|
|
12223
|
+
const line = lines[i];
|
|
12224
|
+
if (line.trim() === "" || line.trimStart().startsWith("#")) {
|
|
12225
|
+
i++;
|
|
12226
|
+
continue;
|
|
12227
|
+
}
|
|
12228
|
+
const indent = indentWidth(line);
|
|
12229
|
+
if (indent < baseIndent) break;
|
|
12230
|
+
if (indent > baseIndent) {
|
|
12231
|
+
i++;
|
|
12232
|
+
continue;
|
|
12233
|
+
}
|
|
12234
|
+
const trimmed = line.slice(baseIndent);
|
|
12235
|
+
if (trimmed.startsWith("- ")) {
|
|
12236
|
+
mode = "array";
|
|
12237
|
+
const after = trimmed.slice(2);
|
|
12238
|
+
const colonAt2 = findTopLevelColon(after);
|
|
12239
|
+
if (colonAt2 === -1) {
|
|
12240
|
+
arr.push(parseScalar(after));
|
|
12241
|
+
i++;
|
|
12242
|
+
} else {
|
|
12243
|
+
const firstKey = after.slice(0, colonAt2).trim();
|
|
12244
|
+
const firstRaw = after.slice(colonAt2 + 1).trim();
|
|
12245
|
+
const obj = {};
|
|
12246
|
+
if (firstRaw === "") {
|
|
12247
|
+
i++;
|
|
12248
|
+
obj[firstKey] = readBlock(baseIndent + 2 + 2);
|
|
12249
|
+
} else {
|
|
12250
|
+
obj[firstKey] = parseScalar(firstRaw);
|
|
12251
|
+
i++;
|
|
12252
|
+
}
|
|
12253
|
+
while (i < lines.length) {
|
|
12254
|
+
const peek = lines[i];
|
|
12255
|
+
if (peek.trim() === "" || peek.trimStart().startsWith("#")) {
|
|
12256
|
+
i++;
|
|
12257
|
+
continue;
|
|
12258
|
+
}
|
|
12259
|
+
const pInd = indentWidth(peek);
|
|
12260
|
+
if (pInd < baseIndent + 2) break;
|
|
12261
|
+
if (peek.slice(baseIndent).startsWith("- ")) break;
|
|
12262
|
+
const cTrimmed = peek.slice(baseIndent + 2);
|
|
12263
|
+
const cColon = findTopLevelColon(cTrimmed);
|
|
12264
|
+
if (cColon === -1) {
|
|
12265
|
+
i++;
|
|
12266
|
+
continue;
|
|
12267
|
+
}
|
|
12268
|
+
const cKey = cTrimmed.slice(0, cColon).trim();
|
|
12269
|
+
const cRaw = cTrimmed.slice(cColon + 1).trim();
|
|
12270
|
+
if (cRaw === "") {
|
|
12271
|
+
i++;
|
|
12272
|
+
obj[cKey] = readBlock(baseIndent + 2 + 2);
|
|
12273
|
+
} else {
|
|
12274
|
+
obj[cKey] = parseScalar(cRaw);
|
|
12275
|
+
i++;
|
|
12276
|
+
}
|
|
12277
|
+
}
|
|
12278
|
+
arr.push(obj);
|
|
12279
|
+
}
|
|
12280
|
+
continue;
|
|
12281
|
+
}
|
|
12282
|
+
mode = "object";
|
|
12283
|
+
const colonAt = findTopLevelColon(trimmed);
|
|
12284
|
+
if (colonAt === -1) {
|
|
12285
|
+
throw new Error(`Malformed frontmatter (expected "key: value") at line ${i + 1}: ${JSON.stringify(line)}`);
|
|
12286
|
+
}
|
|
12287
|
+
const key = trimmed.slice(0, colonAt).trim();
|
|
12288
|
+
const rest = trimmed.slice(colonAt + 1).trim();
|
|
12289
|
+
if (rest === "") {
|
|
12290
|
+
i++;
|
|
12291
|
+
out[key] = readBlock(baseIndent + 2);
|
|
12292
|
+
} else if (rest.startsWith("[") && rest.endsWith("]")) {
|
|
12293
|
+
const inner = rest.slice(1, -1).trim();
|
|
12294
|
+
out[key] = inner === "" ? [] : inner.split(",").map((s) => parseScalar(s));
|
|
12295
|
+
i++;
|
|
12296
|
+
} else {
|
|
12297
|
+
out[key] = parseScalar(rest);
|
|
12298
|
+
i++;
|
|
12299
|
+
}
|
|
12300
|
+
}
|
|
12301
|
+
if (mode === "array") return arr;
|
|
12302
|
+
return out;
|
|
12303
|
+
}
|
|
12304
|
+
const parsed = readBlock(0);
|
|
12305
|
+
if (Array.isArray(parsed)) {
|
|
12306
|
+
throw new Error("Frontmatter root must be an object, not a list.");
|
|
12307
|
+
}
|
|
12308
|
+
Object.assign(root, parsed);
|
|
12309
|
+
return root;
|
|
12310
|
+
}
|
|
12311
|
+
function findTopLevelColon(s) {
|
|
12312
|
+
let inDouble = false;
|
|
12313
|
+
let inSingle = false;
|
|
12314
|
+
for (let idx = 0; idx < s.length; idx++) {
|
|
12315
|
+
const ch = s[idx];
|
|
12316
|
+
const prev = idx > 0 ? s[idx - 1] : "";
|
|
12317
|
+
if (ch === '"' && prev !== "\\" && !inSingle) inDouble = !inDouble;
|
|
12318
|
+
if (ch === "'" && !inDouble) inSingle = !inSingle;
|
|
12319
|
+
if (ch === ":" && !inDouble && !inSingle) {
|
|
12320
|
+
if (idx + 1 >= s.length || s[idx + 1] === " " || s[idx + 1] === " ") return idx;
|
|
12321
|
+
}
|
|
12322
|
+
}
|
|
12323
|
+
return -1;
|
|
12324
|
+
}
|
|
12325
|
+
function readFrontmatter(text69) {
|
|
12326
|
+
const split = splitFrontmatter(text69);
|
|
12327
|
+
if (split.frontmatter === null) return { frontmatter: null, body: split.body };
|
|
12328
|
+
return { frontmatter: parseFrontmatter(split.frontmatter), body: split.body };
|
|
12329
|
+
}
|
|
12330
|
+
var init_frontmatter = __esm({
|
|
12331
|
+
"src/skills/frontmatter.ts"() {
|
|
12332
|
+
"use strict";
|
|
12333
|
+
}
|
|
12334
|
+
});
|
|
12335
|
+
|
|
12336
|
+
// src/skills/catalog.ts
|
|
12337
|
+
var catalog_exports = {};
|
|
12338
|
+
__export(catalog_exports, {
|
|
12339
|
+
readSkillCatalog: () => readSkillCatalog
|
|
12340
|
+
});
|
|
12341
|
+
import fs53 from "node:fs";
|
|
12342
|
+
import path61 from "node:path";
|
|
12343
|
+
function exists(p35) {
|
|
12344
|
+
try {
|
|
12345
|
+
fs53.accessSync(p35);
|
|
12346
|
+
return true;
|
|
12347
|
+
} catch {
|
|
12348
|
+
return false;
|
|
12349
|
+
}
|
|
12350
|
+
}
|
|
12351
|
+
function isDir(p35) {
|
|
12352
|
+
try {
|
|
12353
|
+
return fs53.statSync(p35).isDirectory();
|
|
12354
|
+
} catch {
|
|
12355
|
+
return false;
|
|
12356
|
+
}
|
|
12357
|
+
}
|
|
12358
|
+
function safeRead(p35) {
|
|
12359
|
+
try {
|
|
12360
|
+
return fs53.readFileSync(p35, "utf8");
|
|
12361
|
+
} catch {
|
|
12362
|
+
return null;
|
|
12363
|
+
}
|
|
12364
|
+
}
|
|
12365
|
+
function coerceManifest(raw, source) {
|
|
12366
|
+
const name = raw.name;
|
|
12367
|
+
const description = raw.description;
|
|
12368
|
+
if (typeof name !== "string" || name.trim() === "") {
|
|
12369
|
+
return { reason: "frontmatter missing required field 'name'" };
|
|
12370
|
+
}
|
|
12371
|
+
if (typeof description !== "string" || description.trim() === "") {
|
|
12372
|
+
return { reason: "frontmatter missing required field 'description'" };
|
|
12373
|
+
}
|
|
12374
|
+
const manifest = {
|
|
12375
|
+
name: name.trim(),
|
|
12376
|
+
description: description.trim(),
|
|
12377
|
+
source
|
|
12378
|
+
};
|
|
12379
|
+
if (Array.isArray(raw.triggers)) {
|
|
12380
|
+
manifest.triggers = raw.triggers.filter((v) => typeof v === "string");
|
|
12381
|
+
}
|
|
12382
|
+
if (typeof raw.progressiveDisclosure === "boolean") {
|
|
12383
|
+
manifest.progressiveDisclosure = raw.progressiveDisclosure;
|
|
12384
|
+
}
|
|
12385
|
+
if (Array.isArray(raw.helpers)) {
|
|
12386
|
+
manifest.helpers = raw.helpers.filter((v) => typeof v === "object" && v !== null).map((v) => ({
|
|
12387
|
+
path: String(v.path ?? ""),
|
|
12388
|
+
description: String(v.description ?? "")
|
|
12389
|
+
})).filter((h) => h.path.length > 0);
|
|
12390
|
+
}
|
|
12391
|
+
if (Array.isArray(raw.subSkills)) {
|
|
12392
|
+
manifest.subSkills = raw.subSkills.filter((v) => typeof v === "object" && v !== null).map((v) => ({
|
|
12393
|
+
name: String(v.name ?? ""),
|
|
12394
|
+
path: String(v.path ?? "")
|
|
12395
|
+
})).filter((s) => s.name.length > 0 && s.path.length > 0);
|
|
12396
|
+
}
|
|
12397
|
+
if (typeof raw.selfEval === "object" && raw.selfEval !== null && !Array.isArray(raw.selfEval)) {
|
|
12398
|
+
const se = raw.selfEval;
|
|
12399
|
+
const criteria = Array.isArray(se.criteria) ? se.criteria.filter((v) => typeof v === "string") : [];
|
|
12400
|
+
const maxRetries = typeof se.maxRetries === "number" ? se.maxRetries : 3;
|
|
12401
|
+
manifest.selfEval = {
|
|
12402
|
+
criteria,
|
|
12403
|
+
maxRetries,
|
|
12404
|
+
...typeof se.traceTo === "string" ? { traceTo: se.traceTo } : {}
|
|
12405
|
+
};
|
|
12406
|
+
}
|
|
12407
|
+
if (typeof raw.sessionMemory === "object" && raw.sessionMemory !== null && !Array.isArray(raw.sessionMemory)) {
|
|
12408
|
+
const sm = raw.sessionMemory;
|
|
12409
|
+
if (typeof sm.path === "string" && sm.path.length > 0) {
|
|
12410
|
+
manifest.sessionMemory = { path: sm.path };
|
|
12411
|
+
}
|
|
12412
|
+
}
|
|
12413
|
+
if (Array.isArray(raw.mcpTools)) {
|
|
12414
|
+
manifest.mcpTools = raw.mcpTools.filter((v) => typeof v === "string");
|
|
12415
|
+
}
|
|
12416
|
+
return { manifest };
|
|
12417
|
+
}
|
|
12418
|
+
function readOne(skillPath, source) {
|
|
12419
|
+
const body = safeRead(skillPath);
|
|
12420
|
+
if (body === null) {
|
|
12421
|
+
return { warning: { skillPath, reason: "unreadable SKILL.md" } };
|
|
12422
|
+
}
|
|
12423
|
+
let parsed;
|
|
12424
|
+
try {
|
|
12425
|
+
parsed = readFrontmatter(body);
|
|
12426
|
+
} catch (err) {
|
|
12427
|
+
return {
|
|
12428
|
+
warning: {
|
|
12429
|
+
skillPath,
|
|
12430
|
+
reason: `frontmatter parse error: ${err instanceof Error ? err.message : String(err)}`
|
|
12431
|
+
}
|
|
12432
|
+
};
|
|
12433
|
+
}
|
|
12434
|
+
if (parsed.frontmatter === null) {
|
|
12435
|
+
return { warning: { skillPath, reason: "SKILL.md has no YAML frontmatter" } };
|
|
12436
|
+
}
|
|
12437
|
+
const coerced = coerceManifest(parsed.frontmatter, source);
|
|
12438
|
+
if ("reason" in coerced) {
|
|
12439
|
+
return { warning: { skillPath, reason: coerced.reason } };
|
|
12440
|
+
}
|
|
12441
|
+
return { entry: { manifest: coerced.manifest, skillPath, source } };
|
|
12442
|
+
}
|
|
12443
|
+
function readSkillDirs(baseDir, source, out, warnings) {
|
|
12444
|
+
if (!isDir(baseDir)) return;
|
|
12445
|
+
for (const child of fs53.readdirSync(baseDir).sort()) {
|
|
12446
|
+
const dir = path61.join(baseDir, child);
|
|
12447
|
+
if (!isDir(dir)) continue;
|
|
12448
|
+
const skill = path61.join(dir, "SKILL.md");
|
|
12449
|
+
if (!exists(skill)) continue;
|
|
12450
|
+
const res = readOne(skill, source);
|
|
12451
|
+
if ("entry" in res) out.push(res.entry);
|
|
12452
|
+
else warnings.push(res.warning);
|
|
12453
|
+
}
|
|
12454
|
+
}
|
|
12455
|
+
function readKitSubSkills(kitDir, out, warnings, depth = 0) {
|
|
12456
|
+
const base = path61.join(kitDir, "skills");
|
|
12457
|
+
if (!isDir(base)) return;
|
|
12458
|
+
const walk = (dir, d) => {
|
|
12459
|
+
if (d > MAX_DEPTH) return;
|
|
12460
|
+
for (const entry of fs53.readdirSync(dir, { withFileTypes: true })) {
|
|
12461
|
+
if (entry.isDirectory()) {
|
|
12462
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
12463
|
+
walk(path61.join(dir, entry.name), d + 1);
|
|
12464
|
+
} else if (entry.isFile() && entry.name === "SKILL.md") {
|
|
12465
|
+
const res = readOne(path61.join(dir, entry.name), "worker-kit-sub");
|
|
12466
|
+
if ("entry" in res) out.push(res.entry);
|
|
12467
|
+
else warnings.push(res.warning);
|
|
12468
|
+
}
|
|
12469
|
+
}
|
|
12470
|
+
};
|
|
12471
|
+
walk(base, depth);
|
|
12472
|
+
}
|
|
12473
|
+
function readSkillCatalog(opts) {
|
|
12474
|
+
const root = path61.resolve(opts.root);
|
|
12475
|
+
const entries = [];
|
|
12476
|
+
const warnings = [];
|
|
12477
|
+
if (opts.includeProjectRoot !== false) {
|
|
12478
|
+
const rootSkill = path61.join(root, "SKILL.md");
|
|
12479
|
+
if (exists(rootSkill)) {
|
|
12480
|
+
const res = readOne(rootSkill, "project-root");
|
|
12481
|
+
if ("entry" in res) entries.push(res.entry);
|
|
12482
|
+
else warnings.push(res.warning);
|
|
12483
|
+
}
|
|
12484
|
+
}
|
|
12485
|
+
if (opts.includeClaudeSkills !== false) {
|
|
12486
|
+
readSkillDirs(path61.join(root, ".claude/skills"), "claude-skills", entries, warnings);
|
|
12487
|
+
}
|
|
12488
|
+
if (opts.includeWorkerKits !== false) {
|
|
12489
|
+
const kitsDir = path61.join(root, "cli/assets/worker-kits");
|
|
12490
|
+
readSkillDirs(kitsDir, "worker-kit", entries, warnings);
|
|
12491
|
+
if (isDir(kitsDir)) {
|
|
12492
|
+
for (const kit of fs53.readdirSync(kitsDir).sort()) {
|
|
12493
|
+
const kitPath = path61.join(kitsDir, kit);
|
|
12494
|
+
if (!isDir(kitPath)) continue;
|
|
12495
|
+
readKitSubSkills(kitPath, entries, warnings);
|
|
12496
|
+
}
|
|
12497
|
+
}
|
|
12498
|
+
}
|
|
12499
|
+
if (opts.includeForkRootSkills !== false) {
|
|
12500
|
+
readKitSubSkills(root, entries, warnings);
|
|
12501
|
+
}
|
|
12502
|
+
const catalog = {
|
|
12503
|
+
version: 1,
|
|
12504
|
+
skills: entries.map((e) => e.manifest),
|
|
12505
|
+
readAt: Date.now(),
|
|
12506
|
+
root
|
|
12507
|
+
};
|
|
12508
|
+
return { catalog, entries, warnings };
|
|
12509
|
+
}
|
|
12510
|
+
var MAX_DEPTH, SKIP_DIRS;
|
|
12511
|
+
var init_catalog2 = __esm({
|
|
12512
|
+
"src/skills/catalog.ts"() {
|
|
12513
|
+
"use strict";
|
|
12514
|
+
init_frontmatter();
|
|
12515
|
+
MAX_DEPTH = 6;
|
|
12516
|
+
SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
12517
|
+
"node_modules",
|
|
12518
|
+
".git",
|
|
12519
|
+
"dist",
|
|
12520
|
+
"build",
|
|
12521
|
+
".next",
|
|
12522
|
+
".vite",
|
|
12523
|
+
".pnpm-store",
|
|
12524
|
+
"coverage",
|
|
12525
|
+
".growthub-fork"
|
|
12526
|
+
]);
|
|
12527
|
+
}
|
|
12528
|
+
});
|
|
12529
|
+
|
|
12106
12530
|
// src/commands/source-import-discovery.ts
|
|
12107
12531
|
var source_import_discovery_exports = {};
|
|
12108
12532
|
__export(source_import_discovery_exports, {
|
|
@@ -12111,9 +12535,9 @@ __export(source_import_discovery_exports, {
|
|
|
12111
12535
|
startSourceImportFlow: () => startSourceImportFlow
|
|
12112
12536
|
});
|
|
12113
12537
|
import * as p33 from "@clack/prompts";
|
|
12114
|
-
import
|
|
12115
|
-
import
|
|
12116
|
-
import
|
|
12538
|
+
import pc48 from "picocolors";
|
|
12539
|
+
import fs58 from "node:fs";
|
|
12540
|
+
import path65 from "node:path";
|
|
12117
12541
|
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
12118
12542
|
function slugifyWorkspaceName(input) {
|
|
12119
12543
|
const slug = input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -12141,10 +12565,10 @@ async function promptForInteractiveWorkspacePath(input) {
|
|
|
12141
12565
|
});
|
|
12142
12566
|
if (p33.isCancel(raw) || !raw) return null;
|
|
12143
12567
|
const trimmed = String(raw).trim();
|
|
12144
|
-
const expanded = trimmed.startsWith("~/") ?
|
|
12145
|
-
const resolved =
|
|
12146
|
-
if (
|
|
12147
|
-
const finalPath =
|
|
12568
|
+
const expanded = trimmed.startsWith("~/") ? path65.join(process.env.HOME ?? "~", trimmed.slice(2)) : trimmed;
|
|
12569
|
+
const resolved = path65.resolve(expanded);
|
|
12570
|
+
if (fs58.existsSync(resolved) && fs58.statSync(resolved).isDirectory()) {
|
|
12571
|
+
const finalPath = path65.join(resolved, suggestedName);
|
|
12148
12572
|
p33.note(
|
|
12149
12573
|
[
|
|
12150
12574
|
`You selected an existing folder: ${resolved}`,
|
|
@@ -12320,14 +12744,14 @@ async function startSkillsSourceImportFlow() {
|
|
|
12320
12744
|
function renderSuccess(result, jobId) {
|
|
12321
12745
|
const sourceLine = result.source.kind === "github-repo" ? `${result.source.repo.owner}/${result.source.repo.repo}` : `${result.source.skillId}@${result.source.version}`;
|
|
12322
12746
|
p33.outro(
|
|
12323
|
-
`Imported ${sourceLine} into ${
|
|
12324
|
-
jobId: ${
|
|
12325
|
-
forkId: ${
|
|
12747
|
+
`Imported ${sourceLine} into ${pc48.cyan(result.forkPath)}
|
|
12748
|
+
jobId: ${pc48.cyan(jobId)}
|
|
12749
|
+
forkId: ${pc48.cyan(result.forkId)}
|
|
12326
12750
|
risk: ${result.security.riskClass} (${result.security.findings.length} findings)
|
|
12327
12751
|
detection: framework=${result.detection.framework} pm=${result.detection.packageManager}
|
|
12328
12752
|
open: ${folderOpenLabel3(result.forkPath)}
|
|
12329
|
-
summary: ${
|
|
12330
|
-
manifest: ${
|
|
12753
|
+
summary: ${pc48.dim(result.summaryPath)}
|
|
12754
|
+
manifest: ${pc48.dim(result.manifestPath)}`
|
|
12331
12755
|
);
|
|
12332
12756
|
}
|
|
12333
12757
|
async function confirmTwice(job) {
|
|
@@ -12414,9 +12838,9 @@ var init_source_import_discovery = __esm({
|
|
|
12414
12838
|
// src/index.ts
|
|
12415
12839
|
import { Command } from "commander";
|
|
12416
12840
|
import * as p34 from "@clack/prompts";
|
|
12417
|
-
import
|
|
12418
|
-
import
|
|
12419
|
-
import
|
|
12841
|
+
import pc49 from "picocolors";
|
|
12842
|
+
import fs59 from "node:fs";
|
|
12843
|
+
import path66 from "node:path";
|
|
12420
12844
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
12421
12845
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
12422
12846
|
|
|
@@ -13217,8 +13641,8 @@ function printItemCompleted(item) {
|
|
|
13217
13641
|
const changes = Array.isArray(item.changes) ? item.changes : [];
|
|
13218
13642
|
const entries = changes.map((changeRaw) => asRecord(changeRaw)).filter((change) => Boolean(change)).map((change) => {
|
|
13219
13643
|
const kind = asString(change.kind, "update");
|
|
13220
|
-
const
|
|
13221
|
-
return `${kind} ${
|
|
13644
|
+
const path67 = asString(change.path, "unknown");
|
|
13645
|
+
return `${kind} ${path67}`;
|
|
13222
13646
|
});
|
|
13223
13647
|
const preview = entries.length > 0 ? entries.slice(0, 6).join(", ") : "none";
|
|
13224
13648
|
const more = entries.length > 6 ? ` (+${entries.length - 6} more)` : "";
|
|
@@ -14505,10 +14929,10 @@ async function heartbeatRun(opts) {
|
|
|
14505
14929
|
for (const event of Array.isArray(events) ? events : []) {
|
|
14506
14930
|
handleEvent(event);
|
|
14507
14931
|
}
|
|
14508
|
-
const
|
|
14932
|
+
const runList2 = await api.get(
|
|
14509
14933
|
`/api/companies/${agent.companyId}/heartbeat-runs?agentId=${agent.id}`
|
|
14510
14934
|
) || [];
|
|
14511
|
-
const currentRun =
|
|
14935
|
+
const currentRun = runList2.find((r) => r && r.id === activeRunId) ?? null;
|
|
14512
14936
|
if (!currentRun) {
|
|
14513
14937
|
console.error(pc18.red("Heartbeat run disappeared"));
|
|
14514
14938
|
break;
|
|
@@ -16052,8 +16476,8 @@ function registerIssueCommands(program2) {
|
|
|
16052
16476
|
if (opts.assigneeAgentId) params.set("assigneeAgentId", opts.assigneeAgentId);
|
|
16053
16477
|
if (opts.projectId) params.set("projectId", opts.projectId);
|
|
16054
16478
|
const query = params.toString();
|
|
16055
|
-
const
|
|
16056
|
-
const rows = await ctx.api.get(
|
|
16479
|
+
const path67 = `/api/companies/${ctx.companyId}/issues${query ? `?${query}` : ""}`;
|
|
16480
|
+
const rows = await ctx.api.get(path67) ?? [];
|
|
16057
16481
|
const filtered = filterIssueRows(rows, opts.match);
|
|
16058
16482
|
if (ctx.json) {
|
|
16059
16483
|
printOutput(filtered, { json: true });
|
|
@@ -16659,8 +17083,8 @@ function registerActivityCommands(program2) {
|
|
|
16659
17083
|
if (opts.entityType) params.set("entityType", opts.entityType);
|
|
16660
17084
|
if (opts.entityId) params.set("entityId", opts.entityId);
|
|
16661
17085
|
const query = params.toString();
|
|
16662
|
-
const
|
|
16663
|
-
const rows = await ctx.api.get(
|
|
17086
|
+
const path67 = `/api/companies/${ctx.companyId}/activity${query ? `?${query}` : ""}`;
|
|
17087
|
+
const rows = await ctx.api.get(path67) ?? [];
|
|
16664
17088
|
if (ctx.json) {
|
|
16665
17089
|
printOutput(rows, { json: true });
|
|
16666
17090
|
return;
|
|
@@ -22836,31 +23260,31 @@ function resolveManifestBaseUrl(opts = {}) {
|
|
|
22836
23260
|
function isRecord(value) {
|
|
22837
23261
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22838
23262
|
}
|
|
22839
|
-
function assertRecord(value,
|
|
23263
|
+
function assertRecord(value, path67) {
|
|
22840
23264
|
if (!isRecord(value)) {
|
|
22841
|
-
throw new ManifestMalformedError(`Expected object at \`${
|
|
23265
|
+
throw new ManifestMalformedError(`Expected object at \`${path67}\`.`);
|
|
22842
23266
|
}
|
|
22843
23267
|
return value;
|
|
22844
23268
|
}
|
|
22845
|
-
function assertArray(value,
|
|
23269
|
+
function assertArray(value, path67) {
|
|
22846
23270
|
if (!Array.isArray(value)) {
|
|
22847
|
-
throw new ManifestMalformedError(`Expected array at \`${
|
|
23271
|
+
throw new ManifestMalformedError(`Expected array at \`${path67}\`.`);
|
|
22848
23272
|
}
|
|
22849
23273
|
return value;
|
|
22850
23274
|
}
|
|
22851
|
-
function assertString(value,
|
|
23275
|
+
function assertString(value, path67) {
|
|
22852
23276
|
if (typeof value !== "string" || value.length === 0) {
|
|
22853
|
-
throw new ManifestMalformedError(`Expected non-empty string at \`${
|
|
23277
|
+
throw new ManifestMalformedError(`Expected non-empty string at \`${path67}\`.`);
|
|
22854
23278
|
}
|
|
22855
23279
|
return value;
|
|
22856
23280
|
}
|
|
22857
|
-
function normalizeProvenance(value,
|
|
22858
|
-
const record = assertRecord(value,
|
|
22859
|
-
const originType = assertString(record.originType, `${
|
|
23281
|
+
function normalizeProvenance(value, path67) {
|
|
23282
|
+
const record = assertRecord(value, path67);
|
|
23283
|
+
const originType = assertString(record.originType, `${path67}.originType`);
|
|
22860
23284
|
const allowed = ["hosted", "local-extension", "derived-from-workflow"];
|
|
22861
23285
|
if (!allowed.includes(originType)) {
|
|
22862
23286
|
throw new ManifestMalformedError(
|
|
22863
|
-
`Unknown provenance originType at \`${
|
|
23287
|
+
`Unknown provenance originType at \`${path67}.originType\`: ${originType}`
|
|
22864
23288
|
);
|
|
22865
23289
|
}
|
|
22866
23290
|
return {
|
|
@@ -31510,14 +31934,303 @@ function registerStarterCommands(program2) {
|
|
|
31510
31934
|
});
|
|
31511
31935
|
}
|
|
31512
31936
|
|
|
31937
|
+
// src/commands/skills.ts
|
|
31938
|
+
init_catalog2();
|
|
31939
|
+
import fs55 from "node:fs";
|
|
31940
|
+
import path63 from "node:path";
|
|
31941
|
+
import pc46 from "picocolors";
|
|
31942
|
+
|
|
31943
|
+
// src/skills/session-memory.ts
|
|
31944
|
+
init_frontmatter();
|
|
31945
|
+
import fs54 from "node:fs";
|
|
31946
|
+
import path62 from "node:path";
|
|
31947
|
+
var PROJECT_MD_RELATIVE2 = ".growthub-fork/project.md";
|
|
31948
|
+
function resolveProjectMdPath(forkPath) {
|
|
31949
|
+
return path62.resolve(forkPath, PROJECT_MD_RELATIVE2);
|
|
31950
|
+
}
|
|
31951
|
+
function readSessionMemory(forkPath) {
|
|
31952
|
+
const projectMdPath = resolveProjectMdPath(forkPath);
|
|
31953
|
+
if (!fs54.existsSync(projectMdPath)) return null;
|
|
31954
|
+
const raw = fs54.readFileSync(projectMdPath, "utf8");
|
|
31955
|
+
const sizeBytes = Buffer.byteLength(raw, "utf8");
|
|
31956
|
+
try {
|
|
31957
|
+
const { frontmatter, body } = readFrontmatter(raw);
|
|
31958
|
+
return { path: projectMdPath, frontmatter, body, sizeBytes };
|
|
31959
|
+
} catch {
|
|
31960
|
+
const split = splitFrontmatter(raw);
|
|
31961
|
+
return { path: projectMdPath, frontmatter: null, body: split.body, sizeBytes };
|
|
31962
|
+
}
|
|
31963
|
+
}
|
|
31964
|
+
|
|
31965
|
+
// src/commands/skills.ts
|
|
31966
|
+
init_scaffold_session_memory();
|
|
31967
|
+
init_fork_trace();
|
|
31968
|
+
init_kit_forks_home();
|
|
31969
|
+
init_table_renderer();
|
|
31970
|
+
function readLocalForkHead(forkPath) {
|
|
31971
|
+
const p35 = resolveInForkRegistrationPath(forkPath);
|
|
31972
|
+
if (!fs55.existsSync(p35)) return null;
|
|
31973
|
+
try {
|
|
31974
|
+
const parsed = JSON.parse(fs55.readFileSync(p35, "utf8"));
|
|
31975
|
+
if (typeof parsed.forkId !== "string" || typeof parsed.kitId !== "string") return null;
|
|
31976
|
+
return { forkId: parsed.forkId, kitId: parsed.kitId };
|
|
31977
|
+
} catch {
|
|
31978
|
+
return null;
|
|
31979
|
+
}
|
|
31980
|
+
}
|
|
31981
|
+
function resolveRoot(optRoot) {
|
|
31982
|
+
if (optRoot) return path63.resolve(optRoot);
|
|
31983
|
+
return process.cwd();
|
|
31984
|
+
}
|
|
31985
|
+
function runList(opts) {
|
|
31986
|
+
const result = readSkillCatalog({ root: resolveRoot(opts.root) });
|
|
31987
|
+
if (opts.json) {
|
|
31988
|
+
console.log(JSON.stringify(
|
|
31989
|
+
{
|
|
31990
|
+
version: result.catalog.version,
|
|
31991
|
+
root: result.catalog.root,
|
|
31992
|
+
skills: result.entries.map((e) => ({
|
|
31993
|
+
...e.manifest,
|
|
31994
|
+
skillPath: e.skillPath
|
|
31995
|
+
})),
|
|
31996
|
+
warnings: result.warnings
|
|
31997
|
+
},
|
|
31998
|
+
null,
|
|
31999
|
+
2
|
|
32000
|
+
));
|
|
32001
|
+
return;
|
|
32002
|
+
}
|
|
32003
|
+
if (result.entries.length === 0) {
|
|
32004
|
+
console.log(pc46.dim(`No SKILL.md found under ${result.catalog.root}`));
|
|
32005
|
+
return;
|
|
32006
|
+
}
|
|
32007
|
+
const rows = result.entries.map((e) => ({
|
|
32008
|
+
name: e.manifest.name,
|
|
32009
|
+
source: e.source,
|
|
32010
|
+
skillPath: path63.relative(result.catalog.root ?? "", e.skillPath),
|
|
32011
|
+
triggers: e.manifest.triggers?.length ?? 0,
|
|
32012
|
+
helpers: e.manifest.helpers?.length ?? 0,
|
|
32013
|
+
subSkills: e.manifest.subSkills?.length ?? 0,
|
|
32014
|
+
maxRetries: e.manifest.selfEval ? String(e.manifest.selfEval.maxRetries) : "\u2014"
|
|
32015
|
+
}));
|
|
32016
|
+
console.log(renderTable({
|
|
32017
|
+
columns: [
|
|
32018
|
+
{ key: "name", label: "name", maxWidth: 42 },
|
|
32019
|
+
{ key: "source", label: "source" },
|
|
32020
|
+
{ key: "skillPath", label: "path", maxWidth: 60 },
|
|
32021
|
+
{ key: "triggers", label: "trg", align: "right" },
|
|
32022
|
+
{ key: "helpers", label: "hlp", align: "right" },
|
|
32023
|
+
{ key: "subSkills", label: "sub", align: "right" },
|
|
32024
|
+
{ key: "maxRetries", label: "maxR", align: "right" }
|
|
32025
|
+
],
|
|
32026
|
+
rows
|
|
32027
|
+
}));
|
|
32028
|
+
if (result.warnings.length > 0) {
|
|
32029
|
+
console.log("");
|
|
32030
|
+
console.log(pc46.yellow(`${result.warnings.length} warning(s):`));
|
|
32031
|
+
for (const w of result.warnings) {
|
|
32032
|
+
console.log(pc46.yellow(` - ${path63.relative(result.catalog.root ?? "", w.skillPath)}: ${w.reason}`));
|
|
32033
|
+
}
|
|
32034
|
+
}
|
|
32035
|
+
}
|
|
32036
|
+
function runValidate(opts) {
|
|
32037
|
+
const root = resolveRoot(opts.root);
|
|
32038
|
+
const result = readSkillCatalog({ root });
|
|
32039
|
+
const issues2 = [];
|
|
32040
|
+
for (const w of result.warnings) {
|
|
32041
|
+
issues2.push({ skillPath: w.skillPath, reason: w.reason, severity: "error" });
|
|
32042
|
+
}
|
|
32043
|
+
for (const entry of result.entries) {
|
|
32044
|
+
const m = entry.manifest;
|
|
32045
|
+
if (m.name.length > 64) {
|
|
32046
|
+
issues2.push({
|
|
32047
|
+
skillPath: entry.skillPath,
|
|
32048
|
+
reason: `name length ${m.name.length} exceeds 64-char limit`,
|
|
32049
|
+
severity: "error"
|
|
32050
|
+
});
|
|
32051
|
+
}
|
|
32052
|
+
if (m.description.length > 1024) {
|
|
32053
|
+
issues2.push({
|
|
32054
|
+
skillPath: entry.skillPath,
|
|
32055
|
+
reason: `description length ${m.description.length} exceeds 1024-char limit`,
|
|
32056
|
+
severity: "error"
|
|
32057
|
+
});
|
|
32058
|
+
}
|
|
32059
|
+
const skillDir = path63.dirname(entry.skillPath);
|
|
32060
|
+
for (const helper of m.helpers ?? []) {
|
|
32061
|
+
const helperPath = path63.resolve(skillDir, helper.path);
|
|
32062
|
+
if (!fs55.existsSync(helperPath)) {
|
|
32063
|
+
issues2.push({
|
|
32064
|
+
skillPath: entry.skillPath,
|
|
32065
|
+
reason: `helpers[].path missing on disk: ${helper.path}`,
|
|
32066
|
+
severity: "warning"
|
|
32067
|
+
});
|
|
32068
|
+
}
|
|
32069
|
+
}
|
|
32070
|
+
for (const sub of m.subSkills ?? []) {
|
|
32071
|
+
const subPath = path63.resolve(skillDir, sub.path);
|
|
32072
|
+
if (!fs55.existsSync(subPath)) {
|
|
32073
|
+
issues2.push({
|
|
32074
|
+
skillPath: entry.skillPath,
|
|
32075
|
+
reason: `subSkills[].path missing on disk: ${sub.path}`,
|
|
32076
|
+
severity: "error"
|
|
32077
|
+
});
|
|
32078
|
+
}
|
|
32079
|
+
}
|
|
32080
|
+
if (m.selfEval && (m.selfEval.maxRetries < 1 || m.selfEval.maxRetries > 10)) {
|
|
32081
|
+
issues2.push({
|
|
32082
|
+
skillPath: entry.skillPath,
|
|
32083
|
+
reason: `selfEval.maxRetries ${m.selfEval.maxRetries} outside recommended 1..10 range`,
|
|
32084
|
+
severity: "warning"
|
|
32085
|
+
});
|
|
32086
|
+
}
|
|
32087
|
+
}
|
|
32088
|
+
if (opts.json) {
|
|
32089
|
+
console.log(JSON.stringify(
|
|
32090
|
+
{
|
|
32091
|
+
root,
|
|
32092
|
+
skillsChecked: result.entries.length,
|
|
32093
|
+
issues: issues2,
|
|
32094
|
+
ok: issues2.filter((i) => i.severity === "error").length === 0
|
|
32095
|
+
},
|
|
32096
|
+
null,
|
|
32097
|
+
2
|
|
32098
|
+
));
|
|
32099
|
+
process.exitCode = issues2.filter((i) => i.severity === "error").length === 0 ? 0 : 1;
|
|
32100
|
+
return;
|
|
32101
|
+
}
|
|
32102
|
+
console.log(pc46.bold(`Validated ${result.entries.length} skill(s) under ${root}`));
|
|
32103
|
+
if (issues2.length === 0) {
|
|
32104
|
+
console.log(pc46.green("OK \u2014 no issues."));
|
|
32105
|
+
return;
|
|
32106
|
+
}
|
|
32107
|
+
for (const issue of issues2) {
|
|
32108
|
+
const rel = path63.relative(root, issue.skillPath);
|
|
32109
|
+
const tag = issue.severity === "error" ? pc46.red("[error] ") : pc46.yellow("[warning]");
|
|
32110
|
+
console.log(`${tag} ${rel}: ${issue.reason}`);
|
|
32111
|
+
}
|
|
32112
|
+
const errors = issues2.filter((i) => i.severity === "error").length;
|
|
32113
|
+
if (errors > 0) process.exitCode = 1;
|
|
32114
|
+
}
|
|
32115
|
+
function runSessionInit(opts) {
|
|
32116
|
+
const forkPath = resolveRoot(opts.fork);
|
|
32117
|
+
let kitId = opts.kit?.trim() ?? "";
|
|
32118
|
+
let forkId = "unknown";
|
|
32119
|
+
const forkHead = readLocalForkHead(forkPath);
|
|
32120
|
+
if (forkHead) {
|
|
32121
|
+
forkId = forkHead.forkId;
|
|
32122
|
+
if (!kitId) kitId = forkHead.kitId;
|
|
32123
|
+
}
|
|
32124
|
+
if (!kitId) {
|
|
32125
|
+
const err = "Pass --kit <id>, or run this inside a registered fork (`.growthub-fork/fork.json`).";
|
|
32126
|
+
if (opts.json) {
|
|
32127
|
+
console.log(JSON.stringify({ status: "error", error: err }));
|
|
32128
|
+
process.exitCode = 1;
|
|
32129
|
+
} else {
|
|
32130
|
+
console.error(pc46.red(err));
|
|
32131
|
+
process.exitCode = 1;
|
|
32132
|
+
}
|
|
32133
|
+
return;
|
|
32134
|
+
}
|
|
32135
|
+
const result = scaffoldSessionMemory({
|
|
32136
|
+
forkPath,
|
|
32137
|
+
kitId,
|
|
32138
|
+
forkId,
|
|
32139
|
+
source: "skills-session-init",
|
|
32140
|
+
sourceRef: ""
|
|
32141
|
+
});
|
|
32142
|
+
if (result.written && forkHead) {
|
|
32143
|
+
appendKitForkTraceEvent(forkPath, {
|
|
32144
|
+
forkId,
|
|
32145
|
+
kitId,
|
|
32146
|
+
type: "skills_scaffolded",
|
|
32147
|
+
summary: "Seeded .growthub-fork/project.md via 'growthub skills session init'",
|
|
32148
|
+
detail: { projectMd: result.projectMdPath }
|
|
32149
|
+
});
|
|
32150
|
+
}
|
|
32151
|
+
if (opts.json) {
|
|
32152
|
+
console.log(JSON.stringify(
|
|
32153
|
+
{ status: result.written ? "ok" : "already-initialised", ...result },
|
|
32154
|
+
null,
|
|
32155
|
+
2
|
|
32156
|
+
));
|
|
32157
|
+
return;
|
|
32158
|
+
}
|
|
32159
|
+
if (result.written) {
|
|
32160
|
+
console.log(pc46.green(`Seeded ${path63.relative(forkPath, result.projectMdPath)}`));
|
|
32161
|
+
} else if (!result.templatePath) {
|
|
32162
|
+
console.log(pc46.yellow(
|
|
32163
|
+
`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.`
|
|
32164
|
+
));
|
|
32165
|
+
} else {
|
|
32166
|
+
console.log(pc46.dim(`${path63.relative(forkPath, result.projectMdPath)} already present; left untouched.`));
|
|
32167
|
+
}
|
|
32168
|
+
}
|
|
32169
|
+
function runSessionShow(opts) {
|
|
32170
|
+
const forkPath = resolveRoot(opts.fork);
|
|
32171
|
+
const head = readSessionMemory(forkPath);
|
|
32172
|
+
if (!head) {
|
|
32173
|
+
const err = `No session memory at ${resolveProjectMdPath(forkPath)}. Run 'growthub skills session init'.`;
|
|
32174
|
+
if (opts.json) {
|
|
32175
|
+
console.log(JSON.stringify({ status: "missing", projectMdPath: resolveProjectMdPath(forkPath) }));
|
|
32176
|
+
process.exitCode = 1;
|
|
32177
|
+
return;
|
|
32178
|
+
}
|
|
32179
|
+
console.error(pc46.yellow(err));
|
|
32180
|
+
process.exitCode = 1;
|
|
32181
|
+
return;
|
|
32182
|
+
}
|
|
32183
|
+
if (opts.json) {
|
|
32184
|
+
console.log(JSON.stringify(
|
|
32185
|
+
{
|
|
32186
|
+
path: head.path,
|
|
32187
|
+
sizeBytes: head.sizeBytes,
|
|
32188
|
+
frontmatter: head.frontmatter,
|
|
32189
|
+
body: opts.body ? head.body : void 0
|
|
32190
|
+
},
|
|
32191
|
+
null,
|
|
32192
|
+
2
|
|
32193
|
+
));
|
|
32194
|
+
return;
|
|
32195
|
+
}
|
|
32196
|
+
console.log(pc46.bold(head.path));
|
|
32197
|
+
console.log(pc46.dim(`${head.sizeBytes} bytes`));
|
|
32198
|
+
if (head.frontmatter) {
|
|
32199
|
+
for (const [k, v] of Object.entries(head.frontmatter)) {
|
|
32200
|
+
if (Array.isArray(v)) {
|
|
32201
|
+
console.log(` ${k}: ${v.length === 0 ? "[]" : `[${v.length} entries]`}`);
|
|
32202
|
+
} else if (typeof v === "object" && v !== null) {
|
|
32203
|
+
console.log(` ${k}: { ${Object.keys(v).join(", ")} }`);
|
|
32204
|
+
} else {
|
|
32205
|
+
console.log(` ${k}: ${String(v)}`);
|
|
32206
|
+
}
|
|
32207
|
+
}
|
|
32208
|
+
}
|
|
32209
|
+
if (opts.body) {
|
|
32210
|
+
console.log("");
|
|
32211
|
+
console.log(head.body);
|
|
32212
|
+
} else {
|
|
32213
|
+
console.log("");
|
|
32214
|
+
console.log(pc46.dim("(pass --body to print the markdown body)"));
|
|
32215
|
+
}
|
|
32216
|
+
}
|
|
32217
|
+
function registerSkillsCommands(program2) {
|
|
32218
|
+
const skills = program2.command("skills").description("Discovery + session memory for SKILL.md + .growthub-fork/project.md");
|
|
32219
|
+
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));
|
|
32220
|
+
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));
|
|
32221
|
+
const session = skills.command("session").description("Read / seed the fork's session memory (.growthub-fork/project.md)");
|
|
32222
|
+
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));
|
|
32223
|
+
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));
|
|
32224
|
+
}
|
|
32225
|
+
|
|
31513
32226
|
// src/commands/fleet.ts
|
|
31514
32227
|
init_fork_registry();
|
|
31515
32228
|
import * as p32 from "@clack/prompts";
|
|
31516
|
-
import
|
|
32229
|
+
import pc47 from "picocolors";
|
|
31517
32230
|
|
|
31518
32231
|
// src/fleet/summary.ts
|
|
31519
32232
|
init_fork_registry();
|
|
31520
|
-
import
|
|
32233
|
+
import fs56 from "node:fs";
|
|
31521
32234
|
init_fork_policy();
|
|
31522
32235
|
init_fork_trace();
|
|
31523
32236
|
function classifyHealth(drift, pendingConfirmationJobs, lastJobStatus) {
|
|
@@ -31537,7 +32250,7 @@ var REMOTE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
31537
32250
|
"conflict_encountered"
|
|
31538
32251
|
]);
|
|
31539
32252
|
function buildForkSummary(reg) {
|
|
31540
|
-
if (!
|
|
32253
|
+
if (!fs56.existsSync(reg.forkPath)) {
|
|
31541
32254
|
return {
|
|
31542
32255
|
forkId: reg.forkId,
|
|
31543
32256
|
kitId: reg.kitId,
|
|
@@ -31846,17 +32559,17 @@ init_fork_policy();
|
|
|
31846
32559
|
function healthGlyph(level) {
|
|
31847
32560
|
switch (level) {
|
|
31848
32561
|
case "clean":
|
|
31849
|
-
return
|
|
32562
|
+
return pc47.green("\u25CF");
|
|
31850
32563
|
case "drift-minor":
|
|
31851
|
-
return
|
|
32564
|
+
return pc47.cyan("\u25CF");
|
|
31852
32565
|
case "drift-major":
|
|
31853
|
-
return
|
|
32566
|
+
return pc47.yellow("\u25CF");
|
|
31854
32567
|
case "awaiting-confirmation":
|
|
31855
|
-
return
|
|
32568
|
+
return pc47.magenta("\u25D0");
|
|
31856
32569
|
case "error":
|
|
31857
|
-
return
|
|
32570
|
+
return pc47.red("\u25CF");
|
|
31858
32571
|
default:
|
|
31859
|
-
return
|
|
32572
|
+
return pc47.dim("\u25CB");
|
|
31860
32573
|
}
|
|
31861
32574
|
}
|
|
31862
32575
|
function truncate4(s, n) {
|
|
@@ -31870,7 +32583,7 @@ async function fleetView(opts) {
|
|
|
31870
32583
|
return;
|
|
31871
32584
|
}
|
|
31872
32585
|
p32.log.message(
|
|
31873
|
-
`Fleet: ${
|
|
32586
|
+
`Fleet: ${pc47.cyan(String(fleet.totalForks))} fork(s) | remote=${fleet.forksWithRemote} awaiting=${fleet.forksAwaitingConfirmation} pending-approvals=${fleet.pendingApprovalCount}`
|
|
31874
32587
|
);
|
|
31875
32588
|
p32.log.message(
|
|
31876
32589
|
` 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}`
|
|
@@ -31887,10 +32600,10 @@ function renderForkRow(f) {
|
|
|
31887
32600
|
const base = f.baseVersion.padEnd(8);
|
|
31888
32601
|
const upstream = (f.upstreamVersion ?? "?").padEnd(8);
|
|
31889
32602
|
const driftCounts = `files=${f.fileDriftCount} pkgs=${f.packageDriftCount}`;
|
|
31890
|
-
const pending = f.pendingConfirmationJobs > 0 ?
|
|
31891
|
-
const remote = f.remote ?
|
|
32603
|
+
const pending = f.pendingConfirmationJobs > 0 ? pc47.magenta(` awaits=${f.pendingConfirmationJobs}`) : "";
|
|
32604
|
+
const remote = f.remote ? pc47.dim(` ${f.remote.owner}/${f.remote.repo}`) : "";
|
|
31892
32605
|
p32.log.message(
|
|
31893
|
-
` ${healthGlyph(f.health)} ${label} ${
|
|
32606
|
+
` ${healthGlyph(f.health)} ${label} ${pc47.dim(kit)} ${base} \u2192 ${upstream} ${pc47.dim(driftCounts)}${pending}${remote}`
|
|
31894
32607
|
);
|
|
31895
32608
|
}
|
|
31896
32609
|
async function fleetDrift(opts) {
|
|
@@ -31905,7 +32618,7 @@ async function fleetDrift(opts) {
|
|
|
31905
32618
|
return;
|
|
31906
32619
|
}
|
|
31907
32620
|
p32.log.message(
|
|
31908
|
-
`Fleet drift: ${
|
|
32621
|
+
`Fleet drift: ${pc47.cyan(String(withDrift.length))} of ${fleet.totalForks} fork(s) have drift.`
|
|
31909
32622
|
);
|
|
31910
32623
|
p32.log.message(
|
|
31911
32624
|
` By severity \u2192 none=${fleet.bySeverity.none} info=${fleet.bySeverity.info} warning=${fleet.bySeverity.warning} critical=${fleet.bySeverity.critical}`
|
|
@@ -31925,7 +32638,7 @@ async function fleetDriftSummary(opts) {
|
|
|
31925
32638
|
console.log(JSON.stringify({ summary, narrative }, null, 2));
|
|
31926
32639
|
return;
|
|
31927
32640
|
}
|
|
31928
|
-
p32.log.message(
|
|
32641
|
+
p32.log.message(pc47.cyan(`Drift summary \u2014 ${reg.forkId} (${summary.fromVersion} \u2192 ${summary.toVersion})`));
|
|
31929
32642
|
for (const line of narrative) p32.log.message(` ${line}`);
|
|
31930
32643
|
const sections = [
|
|
31931
32644
|
["safe additions", summary.buckets.safeAdditions],
|
|
@@ -31938,13 +32651,13 @@ async function fleetDriftSummary(opts) {
|
|
|
31938
32651
|
];
|
|
31939
32652
|
for (const [label, items] of sections) {
|
|
31940
32653
|
if (items.length === 0) continue;
|
|
31941
|
-
p32.log.message(
|
|
31942
|
-
for (const item of items) p32.log.message(` \xB7 ${item.path} ${
|
|
32654
|
+
p32.log.message(pc47.dim(` \u2014 ${label} (${items.length}) \u2014`));
|
|
32655
|
+
for (const item of items) p32.log.message(` \xB7 ${item.path} ${pc47.dim(item.note)}`);
|
|
31943
32656
|
}
|
|
31944
32657
|
if (summary.buckets.packageAdditions.length || summary.buckets.packageUpgrades.length) {
|
|
31945
|
-
p32.log.message(
|
|
32658
|
+
p32.log.message(pc47.dim(` \u2014 dependency drift \u2014`));
|
|
31946
32659
|
for (const d of summary.buckets.packageAdditions) {
|
|
31947
|
-
p32.log.message(` + ${d.packageName}@${d.toVersion} ${
|
|
32660
|
+
p32.log.message(` + ${d.packageName}@${d.toVersion} ${pc47.dim("(added upstream)")}`);
|
|
31948
32661
|
}
|
|
31949
32662
|
for (const d of summary.buckets.packageUpgrades) {
|
|
31950
32663
|
p32.log.message(` \u2191 ${d.packageName} ${d.fromVersion ?? "?"} \u2192 ${d.toVersion}`);
|
|
@@ -31970,14 +32683,14 @@ async function fleetPolicy(opts) {
|
|
|
31970
32683
|
console.log(JSON.stringify({ count: rows.length, rows }, null, 2));
|
|
31971
32684
|
return;
|
|
31972
32685
|
}
|
|
31973
|
-
p32.log.message(
|
|
32686
|
+
p32.log.message(pc47.cyan(`Fleet policy matrix (${rows.length} fork(s))`));
|
|
31974
32687
|
for (const r of rows) {
|
|
31975
32688
|
const label = truncate4(r.label ?? r.forkId, 28).padEnd(28);
|
|
31976
32689
|
const aa = r.autoApprove.padEnd(9);
|
|
31977
32690
|
const ad = r.autoApproveDepUpdates.padEnd(9);
|
|
31978
32691
|
const rs = r.remoteSyncMode.padEnd(6);
|
|
31979
32692
|
const ut = String(r.untouchableCount).padStart(3);
|
|
31980
|
-
const remote = r.hasRemote ?
|
|
32693
|
+
const remote = r.hasRemote ? pc47.green("+") : pc47.dim("\xB7");
|
|
31981
32694
|
p32.log.message(
|
|
31982
32695
|
` ${label} autoApprove=${aa} deps=${ad} remote=${rs} untouchable=${ut} ${remote}`
|
|
31983
32696
|
);
|
|
@@ -31993,19 +32706,19 @@ async function fleetApprovals(opts) {
|
|
|
31993
32706
|
p32.log.success("Approval queue is empty.");
|
|
31994
32707
|
return;
|
|
31995
32708
|
}
|
|
31996
|
-
p32.log.message(
|
|
32709
|
+
p32.log.message(pc47.cyan(`Approval queue: ${queue.length} job(s) awaiting confirmation`));
|
|
31997
32710
|
for (const entry of queue) {
|
|
31998
32711
|
p32.log.message(
|
|
31999
|
-
` \xB7 ${
|
|
32712
|
+
` \xB7 ${pc47.cyan(entry.jobId)} fork=${entry.forkLabel ?? entry.forkId} created=${entry.createdAt.slice(0, 19)}`
|
|
32000
32713
|
);
|
|
32001
|
-
for (const
|
|
32002
|
-
p32.log.message(` ${
|
|
32714
|
+
for (const path67 of entry.pendingPaths.slice(0, 6)) {
|
|
32715
|
+
p32.log.message(` ${pc47.dim("awaits")} ${path67}`);
|
|
32003
32716
|
}
|
|
32004
32717
|
if (entry.pendingPaths.length > 6) {
|
|
32005
|
-
p32.log.message(` ${
|
|
32718
|
+
p32.log.message(` ${pc47.dim(`\u2026 +${entry.pendingPaths.length - 6} more`)}`);
|
|
32006
32719
|
}
|
|
32007
32720
|
p32.log.message(
|
|
32008
|
-
` ${
|
|
32721
|
+
` ${pc47.dim("resume:")} growthub kit fork confirm --job-id ${entry.jobId}`
|
|
32009
32722
|
);
|
|
32010
32723
|
}
|
|
32011
32724
|
}
|
|
@@ -32017,20 +32730,20 @@ async function fleetAgentPlan(opts) {
|
|
|
32017
32730
|
console.log(JSON.stringify(doc, null, 2));
|
|
32018
32731
|
return;
|
|
32019
32732
|
}
|
|
32020
|
-
p32.log.message(
|
|
32733
|
+
p32.log.message(pc47.cyan(`Agent heal plan \u2014 ${reg.forkId}`));
|
|
32021
32734
|
p32.log.message(` ${doc.summary}`);
|
|
32022
32735
|
for (const line of doc.narrative) p32.log.message(` ${line}`);
|
|
32023
32736
|
if (doc.awaitsConfirmation.length > 0) {
|
|
32024
|
-
p32.log.message(
|
|
32737
|
+
p32.log.message(pc47.magenta(` Awaiting confirmation on:`));
|
|
32025
32738
|
for (const p210 of doc.awaitsConfirmation) p32.log.message(` \xB7 ${p210}`);
|
|
32026
32739
|
p32.log.message(
|
|
32027
|
-
|
|
32740
|
+
pc47.dim(
|
|
32028
32741
|
` Next: growthub kit fork heal ${reg.forkId} (will park in awaiting_confirmation until resumed)`
|
|
32029
32742
|
)
|
|
32030
32743
|
);
|
|
32031
32744
|
} else if (doc.plan.actions.length > 0) {
|
|
32032
32745
|
p32.log.message(
|
|
32033
|
-
|
|
32746
|
+
pc47.dim(` Next: growthub kit fork heal ${reg.forkId} (${doc.plan.actions.length} safe action(s) ready)`)
|
|
32034
32747
|
);
|
|
32035
32748
|
}
|
|
32036
32749
|
}
|
|
@@ -32085,21 +32798,21 @@ var DEFAULT_MEMORY_PROVIDER_CONFIG = {
|
|
|
32085
32798
|
|
|
32086
32799
|
// src/runtime/memory/store.ts
|
|
32087
32800
|
init_home();
|
|
32088
|
-
import
|
|
32089
|
-
import
|
|
32801
|
+
import fs57 from "node:fs";
|
|
32802
|
+
import path64 from "node:path";
|
|
32090
32803
|
function toProjectSlug(project) {
|
|
32091
32804
|
return project.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "default";
|
|
32092
32805
|
}
|
|
32093
32806
|
function resolveProjectPath(project) {
|
|
32094
|
-
return
|
|
32807
|
+
return path64.resolve(resolveMemoryProjectsDir(), `${toProjectSlug(project)}.json`);
|
|
32095
32808
|
}
|
|
32096
32809
|
function loadMemoryDatabase(project) {
|
|
32097
32810
|
const filePath = resolveProjectPath(project);
|
|
32098
|
-
if (!
|
|
32811
|
+
if (!fs57.existsSync(filePath)) {
|
|
32099
32812
|
return { version: 1, project, observations: [], summaries: [], nextObservationId: 1, nextSummaryId: 1 };
|
|
32100
32813
|
}
|
|
32101
32814
|
try {
|
|
32102
|
-
const raw = JSON.parse(
|
|
32815
|
+
const raw = JSON.parse(fs57.readFileSync(filePath, "utf-8"));
|
|
32103
32816
|
return {
|
|
32104
32817
|
version: 1,
|
|
32105
32818
|
project,
|
|
@@ -32114,9 +32827,9 @@ function loadMemoryDatabase(project) {
|
|
|
32114
32827
|
}
|
|
32115
32828
|
function saveMemoryDatabase(db) {
|
|
32116
32829
|
const dir = resolveMemoryProjectsDir();
|
|
32117
|
-
|
|
32830
|
+
fs57.mkdirSync(dir, { recursive: true });
|
|
32118
32831
|
const filePath = resolveProjectPath(db.project);
|
|
32119
|
-
|
|
32832
|
+
fs57.writeFileSync(filePath, `${JSON.stringify(db, null, 2)}
|
|
32120
32833
|
`, "utf-8");
|
|
32121
32834
|
}
|
|
32122
32835
|
function addObservation(project, input) {
|
|
@@ -32210,8 +32923,8 @@ function incrementRelevanceCount(project, observationId) {
|
|
|
32210
32923
|
}
|
|
32211
32924
|
function listMemoryProjects() {
|
|
32212
32925
|
const dir = resolveMemoryProjectsDir();
|
|
32213
|
-
if (!
|
|
32214
|
-
return
|
|
32926
|
+
if (!fs57.existsSync(dir)) return [];
|
|
32927
|
+
return fs57.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, "")).sort();
|
|
32215
32928
|
}
|
|
32216
32929
|
function getMemoryStats(project) {
|
|
32217
32930
|
const db = loadMemoryDatabase(project);
|
|
@@ -32223,15 +32936,15 @@ function getMemoryStats(project) {
|
|
|
32223
32936
|
};
|
|
32224
32937
|
}
|
|
32225
32938
|
function resolveProviderConfigPath() {
|
|
32226
|
-
return
|
|
32939
|
+
return path64.resolve(resolveMemoryDir(), "provider-config.json");
|
|
32227
32940
|
}
|
|
32228
32941
|
function readProviderConfig() {
|
|
32229
32942
|
const filePath = resolveProviderConfigPath();
|
|
32230
|
-
if (!
|
|
32943
|
+
if (!fs57.existsSync(filePath)) {
|
|
32231
32944
|
return { ...DEFAULT_MEMORY_PROVIDER_CONFIG };
|
|
32232
32945
|
}
|
|
32233
32946
|
try {
|
|
32234
|
-
const raw = JSON.parse(
|
|
32947
|
+
const raw = JSON.parse(fs57.readFileSync(filePath, "utf-8"));
|
|
32235
32948
|
return {
|
|
32236
32949
|
provider: validateProvider(raw.provider),
|
|
32237
32950
|
apiKey: typeof raw.apiKey === "string" ? raw.apiKey : void 0,
|
|
@@ -32244,9 +32957,9 @@ function readProviderConfig() {
|
|
|
32244
32957
|
}
|
|
32245
32958
|
function writeProviderConfig(config) {
|
|
32246
32959
|
const dir = resolveMemoryDir();
|
|
32247
|
-
|
|
32960
|
+
fs57.mkdirSync(dir, { recursive: true });
|
|
32248
32961
|
const filePath = resolveProviderConfigPath();
|
|
32249
|
-
|
|
32962
|
+
fs57.writeFileSync(filePath, `${JSON.stringify(config, null, 2)}
|
|
32250
32963
|
`, { mode: 384 });
|
|
32251
32964
|
}
|
|
32252
32965
|
function validateProvider(value) {
|
|
@@ -32625,14 +33338,14 @@ async function syncMemoriesToHosted(project, options) {
|
|
|
32625
33338
|
init_llm();
|
|
32626
33339
|
function resolveCliVersion() {
|
|
32627
33340
|
try {
|
|
32628
|
-
const moduleDir =
|
|
33341
|
+
const moduleDir = path66.dirname(fileURLToPath7(import.meta.url));
|
|
32629
33342
|
const candidates = [
|
|
32630
|
-
|
|
32631
|
-
|
|
33343
|
+
path66.resolve(moduleDir, "../package.json"),
|
|
33344
|
+
path66.resolve(moduleDir, "../../package.json")
|
|
32632
33345
|
];
|
|
32633
33346
|
for (const candidate of candidates) {
|
|
32634
|
-
if (!
|
|
32635
|
-
const parsed = JSON.parse(
|
|
33347
|
+
if (!fs59.existsSync(candidate)) continue;
|
|
33348
|
+
const parsed = JSON.parse(fs59.readFileSync(candidate, "utf8"));
|
|
32636
33349
|
if (parsed?.name === "@growthub/cli" && typeof parsed.version === "string") return parsed.version;
|
|
32637
33350
|
}
|
|
32638
33351
|
} catch {
|
|
@@ -32859,7 +33572,7 @@ async function runMarketingContextBuilder(baseUrl, model) {
|
|
|
32859
33572
|
});
|
|
32860
33573
|
if (p34.isCancel(projectDir)) return;
|
|
32861
33574
|
const dir = String(projectDir).trim() || process.cwd();
|
|
32862
|
-
if (!
|
|
33575
|
+
if (!fs59.existsSync(dir)) {
|
|
32863
33576
|
p34.note(`Directory not found: ${dir}`, "Marketing Context Builder");
|
|
32864
33577
|
return;
|
|
32865
33578
|
}
|
|
@@ -32895,10 +33608,10 @@ async function runMarketingContextBuilder(baseUrl, model) {
|
|
|
32895
33608
|
p34.note("Draft was not saved. You can copy it from the output above.", "Marketing Context Builder");
|
|
32896
33609
|
return;
|
|
32897
33610
|
}
|
|
32898
|
-
const outDir =
|
|
32899
|
-
|
|
32900
|
-
const outPath =
|
|
32901
|
-
|
|
33611
|
+
const outDir = path66.resolve(dir, ".agents");
|
|
33612
|
+
fs59.mkdirSync(outDir, { recursive: true });
|
|
33613
|
+
const outPath = path66.resolve(outDir, "product-marketing-context.md");
|
|
33614
|
+
fs59.writeFileSync(outPath, result.contextMarkdown, "utf-8");
|
|
32902
33615
|
p34.note(`Saved to: ${outPath}
|
|
32903
33616
|
|
|
32904
33617
|
Review the file and replace [NEEDS INPUT] placeholders with real data.`, "Marketing Context Builder");
|
|
@@ -33107,39 +33820,39 @@ function captureSessionSummary(project, sessionId, messages) {
|
|
|
33107
33820
|
}
|
|
33108
33821
|
}
|
|
33109
33822
|
function resolveLocalThreadsDir() {
|
|
33110
|
-
return
|
|
33823
|
+
return path66.resolve(resolvePaperclipHomeDir(), "native-intelligence", "threads");
|
|
33111
33824
|
}
|
|
33112
33825
|
function loadOrCreateLocalThread() {
|
|
33113
33826
|
const dir = resolveLocalThreadsDir();
|
|
33114
|
-
|
|
33115
|
-
const activePath =
|
|
33116
|
-
if (
|
|
33827
|
+
fs59.mkdirSync(dir, { recursive: true });
|
|
33828
|
+
const activePath = path66.resolve(dir, "active-thread.json");
|
|
33829
|
+
if (fs59.existsSync(activePath)) {
|
|
33117
33830
|
try {
|
|
33118
|
-
const parsed = JSON.parse(
|
|
33831
|
+
const parsed = JSON.parse(fs59.readFileSync(activePath, "utf-8"));
|
|
33119
33832
|
const id2 = typeof parsed.id === "string" && parsed.id.length > 0 ? parsed.id : `thread-${Date.now()}`;
|
|
33120
|
-
const threadFile =
|
|
33833
|
+
const threadFile = path66.resolve(dir, `${id2}.json`);
|
|
33121
33834
|
const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
|
|
33122
33835
|
return { id: id2, filePath: threadFile, messages };
|
|
33123
33836
|
} catch {
|
|
33124
33837
|
}
|
|
33125
33838
|
}
|
|
33126
33839
|
const id = `thread-${Date.now()}`;
|
|
33127
|
-
const filePath =
|
|
33840
|
+
const filePath = path66.resolve(dir, `${id}.json`);
|
|
33128
33841
|
const thread = { id, filePath, messages: [] };
|
|
33129
33842
|
saveLocalThread(thread);
|
|
33130
33843
|
return thread;
|
|
33131
33844
|
}
|
|
33132
33845
|
function saveLocalThread(thread) {
|
|
33133
33846
|
const dir = resolveLocalThreadsDir();
|
|
33134
|
-
|
|
33135
|
-
|
|
33847
|
+
fs59.mkdirSync(dir, { recursive: true });
|
|
33848
|
+
fs59.writeFileSync(
|
|
33136
33849
|
thread.filePath,
|
|
33137
33850
|
`${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
|
|
33138
33851
|
`,
|
|
33139
33852
|
"utf-8"
|
|
33140
33853
|
);
|
|
33141
|
-
const activePath =
|
|
33142
|
-
|
|
33854
|
+
const activePath = path66.resolve(dir, "active-thread.json");
|
|
33855
|
+
fs59.writeFileSync(
|
|
33143
33856
|
activePath,
|
|
33144
33857
|
`${JSON.stringify({ id: thread.id, messages: thread.messages }, null, 2)}
|
|
33145
33858
|
`,
|
|
@@ -33285,7 +33998,7 @@ async function collectBindingsFromContract(contract, promptSeed) {
|
|
|
33285
33998
|
return bindings;
|
|
33286
33999
|
}
|
|
33287
34000
|
function resolveCurrentProject() {
|
|
33288
|
-
return
|
|
34001
|
+
return path66.basename(process.cwd());
|
|
33289
34002
|
}
|
|
33290
34003
|
async function runMemoryKnowledgeHub() {
|
|
33291
34004
|
const project = resolveCurrentProject();
|
|
@@ -33318,7 +34031,7 @@ async function runMemoryKnowledgeHub() {
|
|
|
33318
34031
|
},
|
|
33319
34032
|
{
|
|
33320
34033
|
value: "sync",
|
|
33321
|
-
label: syncStatus.available ? "Sync to Growthub" : "Sync to Growthub" +
|
|
34034
|
+
label: syncStatus.available ? "Sync to Growthub" : "Sync to Growthub" + pc49.dim(" (unavailable)"),
|
|
33322
34035
|
hint: syncStatus.available ? "push memories to hosted account" : syncStatus.reason
|
|
33323
34036
|
},
|
|
33324
34037
|
{ value: "__back_to_hub", label: "\u2190 Back to main menu" }
|
|
@@ -33457,7 +34170,7 @@ async function runDiscoveryHub(opts) {
|
|
|
33457
34170
|
},
|
|
33458
34171
|
{
|
|
33459
34172
|
value: "workflows",
|
|
33460
|
-
label: workflowAccess.state === "ready" ? "\u{1F517} Workflows" : "\u{1F517} Workflows" +
|
|
34173
|
+
label: workflowAccess.state === "ready" ? "\u{1F517} Workflows" : "\u{1F517} Workflows" + pc49.dim(" (locked)"),
|
|
33461
34174
|
hint: workflowAccess.state === "ready" ? "CMS contracts, dynamic pipelines, and saved workflows" : workflowAccess.reason
|
|
33462
34175
|
},
|
|
33463
34176
|
{
|
|
@@ -33480,11 +34193,6 @@ async function runDiscoveryHub(opts) {
|
|
|
33480
34193
|
label: "\u{1F4D6} Memory & Knowledge",
|
|
33481
34194
|
hint: "persistent memory, search, multi-provider config, Growthub sync"
|
|
33482
34195
|
},
|
|
33483
|
-
{
|
|
33484
|
-
value: "hosted-auth",
|
|
33485
|
-
label: "\u{1F510} Connect Growthub Account",
|
|
33486
|
-
hint: "Attach this CLI to the hosted Growthub user through the canonical browser flow"
|
|
33487
|
-
},
|
|
33488
34196
|
{
|
|
33489
34197
|
value: "help",
|
|
33490
34198
|
label: "\u2753 Help CLI",
|
|
@@ -33721,6 +34429,11 @@ async function runDiscoveryHub(opts) {
|
|
|
33721
34429
|
label: "\u{1F6A2} Fleet Operations",
|
|
33722
34430
|
hint: "Fleet-level fork view \xB7 drift \xB7 policy matrix \xB7 approvals \xB7 agent-led plans"
|
|
33723
34431
|
},
|
|
34432
|
+
{
|
|
34433
|
+
value: "skills-catalog",
|
|
34434
|
+
label: "\u{1F4C7} Skills Catalog",
|
|
34435
|
+
hint: "enumerate SKILL.md across this tree + inspect .growthub-fork/project.md"
|
|
34436
|
+
},
|
|
33724
34437
|
{
|
|
33725
34438
|
value: "__back_to_hub",
|
|
33726
34439
|
label: "\u2190 Back to main menu"
|
|
@@ -33828,6 +34541,25 @@ async function runDiscoveryHub(opts) {
|
|
|
33828
34541
|
await fleetView({});
|
|
33829
34542
|
continue;
|
|
33830
34543
|
}
|
|
34544
|
+
if (surfaceChoice2 === "skills-catalog") {
|
|
34545
|
+
const { readSkillCatalog: readSkillCatalog2 } = await Promise.resolve().then(() => (init_catalog2(), catalog_exports));
|
|
34546
|
+
const catalog = readSkillCatalog2({ root: process.cwd() });
|
|
34547
|
+
p34.note(
|
|
34548
|
+
[
|
|
34549
|
+
`Root: ${pc49.cyan(catalog.catalog.root ?? process.cwd())}`,
|
|
34550
|
+
`Skills discovered: ${pc49.bold(String(catalog.entries.length))}`,
|
|
34551
|
+
catalog.warnings.length > 0 ? `Warnings: ${pc49.yellow(String(catalog.warnings.length))}` : `Warnings: 0`,
|
|
34552
|
+
"",
|
|
34553
|
+
"Invoke directly:",
|
|
34554
|
+
" growthub skills list --json",
|
|
34555
|
+
" growthub skills validate",
|
|
34556
|
+
" growthub skills session show",
|
|
34557
|
+
" growthub skills session init --kit <kit-id>"
|
|
34558
|
+
].join("\n"),
|
|
34559
|
+
"Skills Catalog"
|
|
34560
|
+
);
|
|
34561
|
+
continue;
|
|
34562
|
+
}
|
|
33831
34563
|
}
|
|
33832
34564
|
continue;
|
|
33833
34565
|
}
|
|
@@ -33851,10 +34583,6 @@ async function runDiscoveryHub(opts) {
|
|
|
33851
34583
|
if (result2 === "back") continue;
|
|
33852
34584
|
return;
|
|
33853
34585
|
}
|
|
33854
|
-
if (surfaceChoice === "hosted-auth") {
|
|
33855
|
-
await runHostedBridgeEntry({ config: opts?.config, dataDir: opts?.dataDir });
|
|
33856
|
-
continue;
|
|
33857
|
-
}
|
|
33858
34586
|
const result = await runTemplatePicker({ allowBackToHub: true });
|
|
33859
34587
|
if (result === "back") continue;
|
|
33860
34588
|
return;
|
|
@@ -33865,12 +34593,12 @@ function isInstallerMode() {
|
|
|
33865
34593
|
}
|
|
33866
34594
|
function listLocalSurfaces() {
|
|
33867
34595
|
const homeDir = resolvePaperclipHomeDir();
|
|
33868
|
-
const instancesDir =
|
|
33869
|
-
if (!
|
|
33870
|
-
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) => {
|
|
33871
34599
|
const instanceId = entry.name;
|
|
33872
|
-
const configPath =
|
|
33873
|
-
if (!
|
|
34600
|
+
const configPath = path66.resolve(instancesDir, instanceId, "config.json");
|
|
34601
|
+
if (!fs59.existsSync(configPath)) return null;
|
|
33874
34602
|
try {
|
|
33875
34603
|
const config = readConfig(configPath);
|
|
33876
34604
|
if (!config) return null;
|
|
@@ -34032,6 +34760,7 @@ registerGithubCommands(program);
|
|
|
34032
34760
|
registerIntegrationsCommands(program);
|
|
34033
34761
|
registerStatusCommands(program);
|
|
34034
34762
|
registerStarterCommands(program);
|
|
34763
|
+
registerSkillsCommands(program);
|
|
34035
34764
|
registerFleetCommands(program);
|
|
34036
34765
|
if (surfaceRuntime.capabilities.dxEnabled) {
|
|
34037
34766
|
registerDxCommands(program);
|