gooseworks 0.3.16 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +9 -9
  2. package/dist/agents/claude.js +1 -1
  3. package/dist/agents/claude.js.map +1 -1
  4. package/dist/agents/codex.js +1 -1
  5. package/dist/agents/codex.js.map +1 -1
  6. package/dist/agents/skill-links.d.ts +7 -2
  7. package/dist/agents/skill-links.d.ts.map +1 -1
  8. package/dist/agents/skill-links.js +10 -5
  9. package/dist/agents/skill-links.js.map +1 -1
  10. package/dist/commands/install.d.ts.map +1 -1
  11. package/dist/commands/install.js +10 -6
  12. package/dist/commands/install.js.map +1 -1
  13. package/dist/commands/login.d.ts.map +1 -1
  14. package/dist/commands/login.js +3 -23
  15. package/dist/commands/login.js.map +1 -1
  16. package/dist/config.d.ts +1 -1
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/config.js +6 -2
  19. package/dist/config.js.map +1 -1
  20. package/dist/skills/installer.d.ts +9 -0
  21. package/dist/skills/installer.d.ts.map +1 -1
  22. package/dist/skills/installer.js +20 -6
  23. package/dist/skills/installer.js.map +1 -1
  24. package/dist/skills/master-skill.d.ts +24 -22
  25. package/dist/skills/master-skill.d.ts.map +1 -1
  26. package/dist/skills/master-skill.js +251 -66
  27. package/dist/skills/master-skill.js.map +1 -1
  28. package/dist/skills/names.d.ts +53 -1
  29. package/dist/skills/names.d.ts.map +1 -1
  30. package/dist/skills/names.js +107 -7
  31. package/dist/skills/names.js.map +1 -1
  32. package/dist/skills/routes.d.ts +68 -0
  33. package/dist/skills/routes.d.ts.map +1 -0
  34. package/dist/skills/routes.js +124 -0
  35. package/dist/skills/routes.js.map +1 -0
  36. package/package.json +1 -1
  37. package/skills/goose-ads/SKILL.md +23 -3
  38. package/skills/goose-product-photos/SKILL.md +27 -3
  39. package/skills/gooseworks/SKILL.md +50 -49
  40. package/skills/routes.json +157 -0
@@ -1,17 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getEntrySkills = getEntrySkills;
4
+ exports.getEntrySkillNames = getEntrySkillNames;
4
5
  exports.getMasterSkillContent = getMasterSkillContent;
5
6
  exports.getGooseAdsSkillContent = getGooseAdsSkillContent;
6
7
  exports.getGooseVideoSkillContent = getGooseVideoSkillContent;
7
- /** Every entry skill the CLI vendors + installs. */
8
+ exports.getGooseProductPhotosSkillContent = getGooseProductPhotosSkillContent;
9
+ /**
10
+ * The CLI installs two vendored ENTRY skills into ~/.agents/skills/:
11
+ * - `gooseworks` — the PARENT router (getMasterSkillContent): GTM/data toolkit
12
+ * PLUS a domain router that hands ads/graphics/video work to the dedicated
13
+ * `goose-*` skills below.
14
+ * - `goose-ads` — the ads entry/contract (getGooseAdsSkillContent): ad creative
15
+ * (remix, brand research) AND ad analytics/intelligence. Formerly `ads-remix`.
16
+ * Each is a separate Claude Code skill; Claude auto-loads whichever matches the
17
+ * task by its description. They are domain-scoped on purpose — do NOT merge them.
18
+ *
19
+ * Sibling domain skills NOT vendored here (fetched live from goose-skills):
20
+ * - `goose-graphics` — charts/slides/infographics/branded visuals. Installed via
21
+ * `gooseworks install --with goose-graphics` or fetched on demand.
22
+ * - `goose-video` — video ad remix: fetches the per-format recipe by slug,
23
+ * renders LOCALLY (Playwright + ffmpeg + media proxies), mirrors a script for
24
+ * in-app review, saves the MP4 back over MCP (getGooseVideoSkillContent).
25
+ *
26
+ * Recipe skills (remix-graphic-ad-from-reference, brand-research, meta-ads-analyzer,
27
+ * …) are NOT vendored here — they live in goose-skills and are fetched live on
28
+ * demand via `gooseworks fetch <slug>`, so they're always current.
29
+ */
30
+ const routes_1 = require("./routes");
31
+ /**
32
+ * THE registry of entry skills (GOOSE-3190) — one list, four consumers:
33
+ * - `gooseworks install` / `update` / login-refresh write exactly these dirs,
34
+ * - `npm run generate:skills` regenerates exactly these `skills/<name>/SKILL.md`,
35
+ * - `skills/names.ts` derives which dirs the CLI is allowed to delete,
36
+ * - the backend raw-fetches these paths for hosted connectors.
37
+ *
38
+ * `goose-product-photos` used to be a hand-maintained `skills/…/SKILL.md` that
39
+ * was on disk and served by the backend but absent here — so it was never
40
+ * regenerated and never refreshed on install. Adding it closes that drift.
41
+ */
8
42
  function getEntrySkills() {
9
43
  return [
10
44
  { name: 'gooseworks', content: getMasterSkillContent() },
11
45
  { name: 'goose-ads', content: getGooseAdsSkillContent() },
12
46
  { name: 'goose-video', content: getGooseVideoSkillContent() },
47
+ { name: 'goose-product-photos', content: getGooseProductPhotosSkillContent() },
13
48
  ];
14
49
  }
50
+ /** Just the directory names, for callers that don't need the bodies. */
51
+ function getEntrySkillNames() {
52
+ return getEntrySkills().map((s) => s.name);
53
+ }
15
54
  /**
16
55
  * Returns the GTM master SKILL.md content (the `gooseworks` entry skill).
17
56
  * It teaches the coding agent how to discover and use GooseWorks skills on
@@ -44,19 +83,37 @@ This skill is also the **parent router** for the GooseWorks family. Data/GTM wor
44
83
 
45
84
  ## Route to the right skill FIRST
46
85
 
47
- Before anything else, check whether the request belongs to a specialized domain. If so, **switch to that skill** instead of the data flow below:
86
+ First apply the **Common company onboarding** gate below. Preserve the user's original request while onboarding, then continue with it as soon as onboarding is complete. Then load the brand context (**"Load the brand context FIRST"**, immediately below). After that, check whether the request belongs to a specialized domain. If so, **switch to that skill** instead of the data flow below:
48
87
 
49
88
  | If the user wants… | Route to | How |
50
89
  | --- | --- | --- |
51
- | Remix/make an ad, research a brand for ads, OR analyze ad performance — Meta/Google ad campaigns, creative fatigue, CAC/lead quality, competitor ad intel, ad angles & hooks | **\`goose-ads\`** | Installed locally as an entry skill. Just use it. If unavailable, run \`gooseworks install --claude\`. |
52
- | Charts, infographics, slides, social graphics, branded visual designs from a style/format | **\`goose-graphics\`** | If installed locally, use it. Otherwise \`gooseworks fetch goose-graphics\` (or \`gooseworks install --claude --with goose-graphics\`). |
53
- | Make a **video** ad — remix a video ad template (e.g. iMessage chat-reveal), or "make the video for project <id>" | **\`goose-video\`** | Installed locally as an entry skill. Just use it. If unavailable, run \`gooseworks install --claude\`. |
54
- | Make **product photos** — studio, lifestyle, marketplace, social, or on-model product photography | **\`goose-product-photos\`** | Installed locally as an entry skill. Just use it. If unavailable, run \`gooseworks install --claude\`. |
55
- | Animate an approved static ad or product image | **\`animate-image\`** | Fetch with \`gooseworks fetch animate-image\` and follow its GooseWorks MCP workflow. |
90
+ ${(0, routes_1.renderDomainRouteTable)()}
56
91
  | Anything else — scraping, research, lead gen, enrichment, any data lookup | (stay here) | Follow "How to Use" below. |
57
92
 
58
93
  Examples — all of these route to \`goose-ads\`, not the data flow: "remix this ad with project id 123", "make an ad for my product", "research my brand", "why is my Meta campaign underperforming", "which creatives should I cut".
59
94
 
95
+ ## Load the brand context FIRST (mandatory — before you route, and before you ask anything)
96
+
97
+ **Call \`brand_get_context\` before the first substantive step of ANY task**, and before you route to a specialist skill. It is a cheap, read-only call that returns the brand's canonical facts:
98
+
99
+ | It returns | Use it for |
100
+ | --- | --- |
101
+ | **voice** — tone, style, banned phrasing | Any copy, script, caption, hook, or headline. Don't ask "what tone?" |
102
+ | **products** — names, descriptions, pricing, links, imagery | Picking the product to feature. Don't ask "which product?" — offer the list. |
103
+ | **audience** — segments, demographics, jobs-to-be-done | Targeting, angles, creator fit. Don't ask "who is this for?" |
104
+ | **positioning** — category, value props, proof points, tagline | Angles, offers, competitive framing. Don't ask "what makes you different?" |
105
+ | **research status** — whether the brand's research pass has completed | Whether the facts are trustworthy yet, or still being filled in. |
106
+
107
+ Then:
108
+
109
+ 1. **Pass what it returned INTO the routed skill.** When you hand off to \`goose-ads\`, \`goose-video\`, \`goose-product-photos\`, \`goose-graphics\`, or a fetched Brand Growth recipe, carry the voice / products / audience / positioning with you. Do **not** make the routed skill re-derive them, and do **not** re-run brand research when the context is already there.
110
+ 2. **Never re-ask the user for something the brand context already answers.** If a routed skill's own prose asks a question the context answers, the context wins — answer it yourself and move on. Ask only for what is genuinely missing or ambiguous.
111
+ 3. **If research status is not complete**, say so in one line, use what you have, and continue. Only run brand research when the context comes back empty or the user asks for it.
112
+ 4. **If \`brand_get_context\` is unavailable** (no MCP connection), fall back to \`get_brand_kit\` for the selected brand and treat its fields the same way. If neither is available, tell the user the GooseWorks MCP connection is needed rather than guessing brand facts.
113
+ 5. **Treat it as read-only.** Writing brand facts back is the reconciliation flow in \`goose-ads\` (ask first, then \`update_brand_kit\`) — not something this router does.
114
+
115
+ Never invent a brand fact. If it isn't in the brand context and the user hasn't said it, ask.
116
+
60
117
  ## Setup
61
118
 
62
119
  All commands below auto-load credentials from \`~/.gooseworks/credentials.json\`. If a command exits with "Not logged in", tell the user to run: \`npx gooseworks login\`. To log out: \`npx gooseworks logout\`.
@@ -93,57 +150,32 @@ gooseworks credits
93
150
 
94
151
  ## Common company onboarding
95
152
 
96
- Onboarding is voluntary and happens inside the current coding agent. Run it when the user explicitly says **\`/gooseworks onboard me\`**, or ask for one missing answer when it is necessary for the task in front of you. **Never force an existing user through onboarding after an update.**
97
-
98
- The CLI and GooseWorks Ads share one brand-scoped questionnaire through these MCP tools:
99
-
100
- - \`list_ad_brands\` and \`create_ad_brand\` — select or create the company/brand.
101
- - \`get_brand_onboarding { brand_id }\` — load completed answers and \`missing_fields\` before asking anything.
102
- - \`update_brand_onboarding { brand_id, ...answers }\` — save each group of answers and the final first-task choice.
103
-
104
- If these tools are unavailable, tell the user that onboarding needs the GooseWorks MCP connection. Do not send them to another UI and do not fall back to a separate context record.
105
-
106
- ### Resume rules
107
-
108
- 1. Run \`list_ad_brands\`. If there are multiple brands, ask which one to use.
109
- 2. If there is no brand, ask for the company or brand website, research it, and use \`create_ad_brand { name, website_url }\`. If the domain matches an existing brand, reuse it.
110
- 3. Call \`get_brand_onboarding\` and ask only the returned missing questions.
111
- 4. Save after each small group so an interrupted interview can resume.
112
- 5. If the record is complete, confirm the brand and continue; do not repeat the interview.
113
-
114
- ### Shared questions and answer values
153
+ Onboarding happens inside the current agent and is the first-run gate for every GooseWorks task. It uses the exact same saved state and step order as the web onboarding. The user does not need to type **\`/gooseworks onboard me\`**; that explicit command only starts or resumes the same flow.
115
154
 
116
- Use the host's native question controls. Keep the labels below; the values in backticks are the stable values accepted by \`update_brand_onboarding\`.
155
+ Keep the user's original task pending. Call **\`brand_onboarding { action: "status" }\`** before routing or executing it, then:
117
156
 
118
- 1. **What is your role?** Founder / Business Owner · C-Suite · VP / Director · Performance / Growth Marketing · Brand / Content Marketing · Creative / Design · Agency · Consultant / Freelancer · Other.
119
- 2. **How much do you spend on paid ads right now?** \`zero\` · \`under_10k\` · \`10k_30k\` · \`30k_100k\` · \`100k_plus\`.
120
- 3. **What are your goals?** Multi-select: create ads \`make_creatives\` · analyze ads \`analyze_ads\` · manage/optimize ads \`ai_manage\` · competitor or customer research \`research_competitors\` · creators and social trends \`creators_trends\` · content \`content_growth\` · lead generation \`lead_generation\` · data work \`data_work\` · work with an expert team \`expert_team\`.
121
- 4. **Who makes your ad creatives right now?** and **Who manages your ads right now?** Use the shared values returned in the tool schema. Skip both when ad spend is \`zero\` and no advertising goal was selected.
122
- 5. **Which platforms or channels do you use or want help with?** Multi-select: \`meta\` · \`tiktok\` · \`google\` · \`chatgpt\` · \`x\` · \`linkedin\` · \`reddit\` · \`other\`.
123
- 6. **Where did you find GooseWorks?** Use the shared discovery-source values returned in the tool schema.
157
+ - follow only the returned \`next_step\`;
158
+ - save each answer immediately with \`brand_onboarding\` so web, Claude, Codex, ChatGPT, and Cowork can resume one another;
159
+ - continue the original request immediately when \`onboarding_completed\` is true.
124
160
 
125
- Do not add CLI-only questions about business type, products, or audience. Infer them from the website and ask one clarification only when the research is materially uncertain.
161
+ If \`brand_onboarding\` is unavailable, explain that the GooseWorks MCP connection must be enabled. Do not write a parallel local profile and do not run the retired role / discovery-source / ad-owner questionnaire.
126
162
 
127
- ### Research while onboarding
163
+ When onboarding returns a review link, show that single link and ask the user to review the creatives and reply \`done\`. When they reply \`done\`, do not restart onboarding: continue the task they originally asked for. If there was no earlier task, ask: **“Let’s start your next campaign. What are you promoting, and what result do you want?”** Use the same preserved-task-or-campaign handoff if onboarding completes while the creatives are still being prepared or could not be generated.
128
164
 
129
- Do useful setup work, not only form collection:
165
+ ### Shared flow
130
166
 
131
- 1. Fetch \`brand-research\` and research the website, products/services, audiences, competitors, offers, and messaging evidence.
132
- 2. Reuse existing Brand Kit/Core data. For an ecommerce store, import the relevant catalog with \`import_product\` and poll \`get_product_import\` rather than submitting duplicates.
133
- 3. When ads are relevant, offer to import existing creative. This is optional.
134
- 4. Suggest evidence-backed messaging angles. Approval is optional and never blocks completion.
135
- 5. Show the researched profile for confirmation: products/services, audience, competitors, imported ads, and suggested angles. Clearly label uncertainty.
167
+ Use the host's native question controls. Ask one short group at a time and rely on the live tool schema for accepted values.
136
168
 
137
- ### First task
169
+ 1. **Start** — If status returns \`start\`, ask for the company website or Apple App Store URL. Also offer the optional hero product URL and “Where do you do your work?” choices: Slack, WhatsApp, iMessage, Claude Code, Claude, Codex, and ChatGPT. Call \`action: "start"\`; server-side research begins immediately. If status returns \`select_brand\`, ask which company/client to use. Otherwise reuse the only brand automatically.
170
+ 2. **Your coworker** — Ask what they want to name their Growth Coworker. A text-only client may keep the default avatar; do not block on an image. Save with \`action: "save_coworker"\`.
171
+ 3. **Your company** — Use the returned \`company_draft\` as the starting point and ask the user to verify or edit: what they sell (\`marketCategory\`), where people buy (\`appPlatforms\`), primary customer, customer problem, promised outcome, and optional differentiator. Save with \`action: "save_company"\`.
172
+ 4. **Your taste** — In a terminal or CLI host, use the returned \`taste_url\`: open it when the host supports opening links and always show one clickable **Choose your taste in GooseWorks** link. Ask the user to heart or skip ads on that page, click **Continue** or **Skip this**, return to the agent, and reply \`done\`. Do not print, enumerate, or summarize \`taste_deck\` in the terminal. After \`done\`, call \`brand_onboarding { action: "status" }\` again and follow the refreshed \`next_step\`. In a chat host that renders images, show only the one image attached by the tool and save each Love/Skip decision with \`action: "save_taste"\`; send \`complete: true\` after three hearts or an explicit skip.
173
+ 5. **First campaign** — Ask **“What’s happening right now?”**: launch \`launch\`, promotion \`promo\`, seasonal moment \`seasonal\`, or nothing special \`nothing\`, plus an optional note. Call \`action: "propose_campaign"\`, show the returned editable card (name, objective, offer, audience, 2–3 angles, CTA, and product URL), and save edits with \`action: "save_campaign"\`. Send \`accept: true\` only after approval; acceptance can start the complimentary first creatives.
174
+ 6. **Where you are** — Ask monthly ad spend (\`none\`, \`under_1k\`, \`1k_5k\`, \`5k_25k\`, \`25k_plus\`), annual revenue (\`under_1m\`, \`1m_10m\`, \`10m_100m\`, \`100m_plus\`), the 90-day goal, current channels (an empty list is a valid “nothing yet”), and at least one channel they are willing to use. Channel values: \`paid_social\`, \`search_ads\`, \`content\`, \`creators\`, \`seo\`, \`communities\`, \`referrals\`, \`partnerships\`, \`outbound\`, \`app_stores\`, \`other\`. Save with \`action: "save_progress"\`.
175
+ 7. **Review** — Show the returned founder, researched, and inferred facts with their provenance. The user may correct positioning, audience, voice, value propositions, proof points, or competitors through \`action: "review_research"\`. Complete the review even when research is still running, failed, or sparse; never trap the user waiting for it.
176
+ 8. **Channels** — If \`channel_connected\` is already true, this is complete automatically. Otherwise ask whether they want to connect Slack, WhatsApp, or iMessage later, or skip for now. An explicit skip is valid; call \`action: "complete_channels"\`.
138
177
 
139
- Finish with **What do you want to do first?**
140
-
141
- - Connect my tools and data — \`connect_tools\`
142
- - Research customers, competitors, creators, or trends — \`research\`
143
- - Analyze ads, content, landing pages, or performance — \`analyze\`
144
- - Create ads, product images, or social content — \`create\`
145
-
146
- Save the choice as \`first_task\`, then start that job. If the user already stated a concrete job, save the matching value and start without showing the menu.
178
+ Do not ask for role, discovery source, who makes creatives, who manages ads, or a separate “what do you want to do first?” menu. Those belonged to the retired CLI questionnaire. The task the user already asked for is their first task.
147
179
 
148
180
  ## Brand Growth discovery
149
181
 
@@ -151,19 +183,9 @@ Brand Growth is a collection inside the normal skill catalog, not a command or i
151
183
 
152
184
  | Job | Skill |
153
185
  | --- | --- |
154
- | Brand foundation | \`brand-research\` |
155
- | Competitor ads | \`competitor-ad-intelligence\` |
156
- | Customer language and angles | \`comment-mining\` → \`ad-angle-miner\` |
157
- | Competitor social content | \`competitor-social-research\` |
158
- | Creator discovery and evaluation | \`influencer-prospecting\` |
159
- | Trends and outlier posts | \`trend-discovery\`, \`outlier-post-finder\` |
160
- | Social listening and product demand | \`social-listening-brief\`, \`product-demand-research\` |
161
- | Meta performance, policy, and landing-page match | \`meta-ads-analyzer\`, \`meta-ad-policy-checker\`, \`ad-to-landing-page-auditor\` |
162
- | Static ads | \`goose-ads\` / \`remix-graphic-ad-from-reference\` |
163
- | Product photos | \`goose-product-photos\` |
164
- | Graphics and animation | \`goose-graphics\`, \`animate-image\` |
165
-
166
- Fetch the named public skill before following it. Provider helpers such as \`scrapecreators-api\` and \`transcript-intelligence\` are dependencies, not user-facing results.
186
+ ${(0, routes_1.renderBrandGrowthTable)()}
187
+
188
+ Fetch the named public skill before following it. You already called \`brand_get_context\` — hand the brand's voice, products, audience, and positioning to the fetched skill instead of letting it re-derive or re-ask them. Provider helpers such as \`scrapecreators-api\` and \`transcript-intelligence\` are dependencies, not user-facing results.
167
189
 
168
190
  For a multi-part request, repeat this routing check before each new job. Fetch and follow the
169
191
  closest outcome skill first (for example, \`comment-mining\`, \`creator-profile-teardown\`, or
@@ -293,6 +315,7 @@ The \`gooseworks\` CLI sends authenticated requests (Bearer \`GOOSEWORKS_API_KEY
293
315
 
294
316
  ## Rules
295
317
 
318
+ 0. **Call \`brand_get_context\` before anything else**, pass what it returns into whatever skill you route to, and never re-ask the user for a fact it already answers (see "Load the brand context FIRST").
296
319
  1. **Consider a GooseWorks skill when it fits the task** — scraping, research, lead gen, enrichment, especially at scale, behind auth, or from a specific source. For a quick lookup your built-in tools are fine; use your judgement and pick the best tool for the user.
297
320
  2. **Before paid operations**, tell the user the estimated credit cost
298
321
  3. **If a \`gooseworks\` command exits with "Not logged in"**: tell the user to run \`npx gooseworks login\`
@@ -356,6 +379,24 @@ Everything goes through the \`mcp__gooseworks__*\` tools. If they are not availa
356
379
  tell the user to run \`gooseworks install --claude --mcp\`** (and restart Claude Code). There is
357
380
  no HTTP/file fallback — the REST ad endpoints are session-cookie-only and reject your token.
358
381
 
382
+ ## Start from the brand context — don't re-ask what it already answers
383
+
384
+ If the \`gooseworks\` router handed you brand context, USE IT. If you were invoked directly, call
385
+ \`brand_get_context\` first (falling back to \`get_brand_kit\` for the selected brand). It already
386
+ answers most of what the flows below would otherwise ask the user:
387
+
388
+ - **Which product to feature** → \`products[]\`. Offer the real catalog entries; never guess a
389
+ product name and never ask the user to list their products.
390
+ - **The vibe / tone of the copy** → the brand's **voice**. Use it; don't ask "what tone?".
391
+ - **Who the ad is for** → the brand's **audience**. Don't ask "who's the target?".
392
+ - **The angle, offer framing, and what to claim** → **positioning**, value props, proof points.
393
+ - **Logo, colors, fonts** → owned by the backend research pass. **Never re-derive them.**
394
+ - **Whether the facts are trustworthy yet** → **research status**. If it isn't complete, say so in
395
+ one line and continue; the batch queues and runs when research finishes.
396
+
397
+ Ask only for what the context genuinely doesn't answer: the specific campaign intent (season,
398
+ promo, which of several angles), the source ad, and anything the user must consent to.
399
+
359
400
  ## Identity & credits
360
401
 
361
402
  - One agent-scoped token authenticates the \`gooseworks\` MCP tools. Never print it. The tools
@@ -481,9 +522,11 @@ When the user wants to make ads but has NOT named a specific template (id/slug/C
481
522
  ad/upload), do NOT silently browse the raw catalog and hand-pick for them. Instead run this
482
523
  short ask flow — it mirrors the web app and keeps the human in the loop:
483
524
 
484
- 1. **Ask what kind of ads they want** — the angle/offer/theme/season, the vibe, and which
485
- product from the brand kit to feature. This shapes both the source choice and your steering
486
- \`prompt\`. Keep it to one or two quick questions.
525
+ 1. **Ask what kind of ads they want** — the angle/offer/theme/season. **The brand context already
526
+ gives you the vibe (voice), the audience, and the product catalog — do NOT ask for those.**
527
+ Offer the real \`products[]\` to pick from rather than asking "which product?", and derive the
528
+ tone from the brand's voice. This shapes both the source choice and your steering \`prompt\`.
529
+ Keep it to one quick question about campaign intent.
487
530
  2. **Ask how to pick a source: their own ads, Community, upload, or "Surprise me".**
488
531
  - **Their own ads** → use \`list_user_ad_templates\` to load the active brand's own sources and
489
532
  let them choose from the results.
@@ -1104,4 +1147,146 @@ path. (\`fal-storage-proxy\` may 404 depending on the install; don't block on it
1104
1147
  - Always end a successful run with \`app_url\` + \`brand_url\`, verbatim.
1105
1148
  `;
1106
1149
  }
1150
+ /**
1151
+ * Returns the goose-product-photos entry SKILL.md content.
1152
+ *
1153
+ * GOOSE-3190: this skill already existed on disk (`skills/goose-product-photos/
1154
+ * SKILL.md`, hand-maintained) and was already served by the backend to hosted
1155
+ * connectors — but it was NOT in `getEntrySkills()`, so `npm run generate:skills`
1156
+ * never regenerated it and `install` / `update` / login-refresh never wrote or
1157
+ * refreshed it on a user's machine. Moving the body here makes the registry the
1158
+ * one source: one command emits all four entry skills.
1159
+ */
1160
+ function getGooseProductPhotosSkillContent() {
1161
+ return `---
1162
+ name: goose-product-photos
1163
+ slug: goose-product-photos
1164
+ description: >
1165
+ GooseWorks Product Photos — turn a brand's product images into publish-ready photography
1166
+ (clean studio shots, lifestyle scenes, on-model looks) while keeping the product faithful
1167
+ (silhouette, materials, logo, colorway). You pick a brand + product and submit; the GooseWorks
1168
+ backend runs the SAME server-side pipeline the Product Photos studio uses (compose → generate →
1169
+ judge → auto-retry) and bills credits. Use when the user says "make product photos", "shoot my
1170
+ product", "studio/lifestyle/on-model photo of <product>", "generate product photography", or
1171
+ references a product to photograph. Unlike goose-ads (ad creative) this produces clean PRODUCT
1172
+ photos that can then feed the ad workflow.
1173
+ category: ads
1174
+ version: 0.2.0
1175
+ author: GooseWorks
1176
+ tags: [gooseworks, ads, product-photos, photoshoot, product, ecommerce, studio, lifestyle, on-model]
1177
+ ---
1178
+
1179
+ # GooseWorks Product Photos — branded product photography
1180
+
1181
+ The GooseWorks Product Photos skill. You **pick a brand + product and submit one generation**;
1182
+ the **backend** runs the whole pipeline (compose the shot prompt → generate on \`gpt_image_2\` →
1183
+ judge for product fidelity → auto-retry a few times for free) and stores the results. You do NOT
1184
+ generate images, call a model, or manage files — this is the exact same workflow the Product
1185
+ Photos studio uses, so the skill and the app can never drift. The point is to **enrich a brand's
1186
+ usable product imagery** — approved photos join the brand kit and can then feed the ad workflow
1187
+ (\`goose-ads\`).
1188
+
1189
+ ## Prerequisite — the GooseWorks MCP server is REQUIRED
1190
+
1191
+ Everything goes through the \`mcp__gooseworks__*\` tools. If they are not available, **stop and
1192
+ tell the user to run \`gooseworks install --claude --mcp\`** (and restart Claude Code). There is no
1193
+ HTTP/file fallback.
1194
+
1195
+ ## Start from the brand context — don't re-ask what it already answers
1196
+
1197
+ If the \`gooseworks\` router handed you brand context, USE IT. If you were invoked directly, call
1198
+ \`brand_get_context\` yourself first. It answers most of the setup questions below, so **do not ask
1199
+ the user for them**:
1200
+
1201
+ - **Which product?** — the context's \`products[]\` are the real catalog entries. Offer them; never
1202
+ invent a product or ask the user to describe one you can already see.
1203
+ - **What does it look like / what is it made of?** — grounded in the product's stored images and
1204
+ description. Never guess a material, colorway, or silhouette.
1205
+ - **What vibe / who is it for?** — the context's voice, positioning, and audience already say. Let
1206
+ them shape the scene and styling instead of asking "what mood do you want?".
1207
+ - **Brand look** — logo, colors, and fonts are owned by the backend research pass. Read them, never
1208
+ re-derive them.
1209
+
1210
+ Ask only for the genuinely open choices: the shot \`category\`, how many photos, quality, and
1211
+ whether a human model is wanted (which needs explicit consent — see the rules).
1212
+
1213
+ ## Identity & credits
1214
+
1215
+ - One agent-scoped token authenticates the tools; they resolve your org automatically. Never
1216
+ print the token. (You may pass an optional \`target\` to operate on a specific agent/org, exactly
1217
+ as the other GooseWorks tools; omit it to use your pinned scope.)
1218
+ - **Credits are handled by the backend.** \`generate_product_photos\` reserves the estimated cost up
1219
+ front and bills only the photos that pass the judge — **automatic retries are free**, and a photo
1220
+ the judge can't get right (\`flagged\`) is shown but **never billed**. Call
1221
+ \`estimate_product_photos\` first to quote the cost; \`get_ad_credits\` shows the balance.
1222
+
1223
+ ## The tools
1224
+
1225
+ **Pick the brand + product**
1226
+ - \`list_ad_brands\` — the user's ad brands (get a \`brand_id\`; also carries \`slug\`).
1227
+ - \`list_brand_products { brand_id, search?, page?, page_size? }\` — the brand's imported products.
1228
+ Pick a \`product_id\` to shoot. \`search\` matches name / type / variant / SKU.
1229
+ - \`import_product { brand_id, kind, url, product_name? }\` — import a product if it isn't in the
1230
+ catalog yet. \`kind\` is \`product_url\` (a single product page), \`shopify_store\` (a store URL →
1231
+ imports the catalog), or \`image_url\` (a direct image; requires \`product_name\`). Returns an import
1232
+ row with an \`id\`; if its \`status\` isn't \`complete\`, poll \`get_product_import\` until it is, then
1233
+ \`list_brand_products\` to find the new product. (File uploads aren't available over MCP — use a URL.)
1234
+ - \`get_product_import { import_id }\` — poll an import until \`status\` is \`complete\` or \`failed\`.
1235
+
1236
+ **Generate**
1237
+ - \`estimate_product_photos { count, quality? }\` — cost preview (per-photo + total credits). \`count\`
1238
+ is 1, 2, 4, or 8; \`quality\` is \`low\` | \`medium\` | \`high\` (default \`medium\`). Reserves nothing.
1239
+ - \`generate_product_photos { brand_id, product_id, variant_id?, category, controls?, prompt?,
1240
+ count?, quality?, reference_image_urls?, attestation_accepted? }\` — **the one call that makes
1241
+ photos.** \`category\` is \`apparel\` | \`beauty\` | \`cpg\` (seeds sensible scene/framing defaults).
1242
+ Omit \`controls\` to use the category preset; pass \`prompt\` as free-text steering **added on top of**
1243
+ the settings (it doesn't replace them). Returns a generation with an \`id\` **immediately** — poll
1244
+ \`get_product_photo_generation\` until done, then read each \`outputs[].final_image_url\`.
1245
+ **If you request a human model** (\`controls.model.presence\` is not \`none\`) you MUST pass
1246
+ \`attestation_accepted: true\` to confirm the user has the rights for model imagery.
1247
+ - \`get_product_photo_generation { generation_id }\` — poll until \`status\` is \`complete\`,
1248
+ \`partial_failure\`, or \`failed\`. Each \`outputs[]\` entry has its own \`status\` and, once ready, a
1249
+ \`final_image_url\`. A \`flagged\` output is the best attempt but wasn't billed.
1250
+
1251
+ **Use the results**
1252
+ - \`list_product_photos { brand_id, archived? }\` — the brand's generated photos (\`archived: false\`
1253
+ = active, \`true\` = archived).
1254
+ - \`approve_product_photo { output_id }\` — approve a photo: links it to the product and makes it
1255
+ available in the **brand kit**, so \`goose-ads\` can use it. **Photos are not used anywhere until
1256
+ approved.**
1257
+ - \`archive_product_photo { output_id, reason? }\` — archive a photo; archived photos are **excluded**
1258
+ from ad generation.
1259
+
1260
+ ## Workflow — shoot a product
1261
+
1262
+ 1. **Load the brand context** (\`brand_get_context\`, or reuse what the router passed you) and
1263
+ **resolve the brand + product.** \`list_ad_brands\` → \`brand_id\`. \`list_brand_products\` → pick a
1264
+ \`product_id\` from the catalog you already know about. If the product genuinely isn't there,
1265
+ \`import_product\` (poll \`get_product_import\`).
1266
+ 2. **Quote the cost.** \`estimate_product_photos { count, quality }\` → tell the user credits.
1267
+ 3. **Generate.** \`generate_product_photos { brand_id, product_id, category, count, quality, prompt? }\`.
1268
+ Build \`prompt\` from the brand's voice/positioning you already have — don't interview the user for it.
1269
+ Returns a generation \`id\` right away.
1270
+ 4. **Poll.** \`get_product_photo_generation { generation_id }\` until terminal; hand back each
1271
+ \`final_image_url\`.
1272
+ 5. **Approve the keepers.** Show the results and let the user pick; \`approve_product_photo\` the ones
1273
+ they'd publish (that's what puts them in the brand kit for ads), \`archive_product_photo\` the rest.
1274
+
1275
+ ## Rules
1276
+
1277
+ - **Never invent product facts.** The backend grounds the shot on the product's real images; don't
1278
+ describe a product you can't see.
1279
+ - **Use the brand context instead of interviewing the user.** Product, audience, voice, positioning,
1280
+ logo/colors/fonts all come from \`brand_get_context\` / the brand kit. Ask only for the shot
1281
+ category, count, quality, and model consent.
1282
+ - **Ask before spending.** Quote the estimate and confirm \`count\` / \`quality\` before
1283
+ \`generate_product_photos\` — it reserves credits.
1284
+ - **Poll, don't re-submit.** A generation that's still \`running\` is not stuck; re-submitting
1285
+ double-bills. Only a \`failed\` generation should be retried.
1286
+ - **Model imagery needs consent.** Only set a human model when the user asks, and pass
1287
+ \`attestation_accepted: true\`.
1288
+ - **Approval is the hand-off to ads.** Remind the user that only **approved** photos reach the brand
1289
+ kit / ad workflow; archived ones never do.
1290
+ `;
1291
+ }
1107
1292
  //# sourceMappingURL=master-skill.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"master-skill.js","sourceRoot":"","sources":["../../src/skills/master-skill.ts"],"names":[],"mappings":";;AA4BA,wCAMC;AAWD,sDAwRC;AAiBD,0DA0UC;AAcD,8DA2bC;AA9kCD,oDAAoD;AACpD,SAAgB,cAAc;IAC5B,OAAO;QACL,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,qBAAqB,EAAE,EAAE;QACxD,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE;QACzD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,yBAAyB,EAAE,EAAE;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,qBAAqB;IACnC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsRR,CAAC;AACF,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,uBAAuB;IACrC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwUR,CAAC;AACF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,yBAAyB;IACvC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAybR,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"master-skill.js","sourceRoot":"","sources":["../../src/skills/master-skill.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,54 @@
1
- export declare function isManagedGooseworksSkill(name: string): boolean;
1
+ /**
2
+ * Which directories under ~/.agents/skills/ the CLI is allowed to DELETE.
3
+ *
4
+ * GOOSE-3191 (data loss): this predicate used to match ANY directory whose name
5
+ * started with `goose-` or `gooseworks-`. `gooseworks install` calls
6
+ * `removeAllSkills()` on every install / update / login-refresh, so a user's own
7
+ * unrelated third-party skill — `goose-notes`, `goose-jira`, anything they wrote
8
+ * themselves — was silently destroyed. A name prefix is NOT ownership.
9
+ *
10
+ * The rule now, in order of authority:
11
+ *
12
+ * 1. **Known entry-skill slugs** (`gooseworks`, `goose-ads`, `goose-video`,
13
+ * `goose-product-photos`, plus the legacy `ads-remix` name) are ours by
14
+ * definition — they are the dirs the CLI itself writes on every install, so
15
+ * we delete them regardless of whether they carry a stamp. This is what
16
+ * keeps upgrades from an old CLI working.
17
+ * 2. **A `.gooseworks-version` stamp** marks a directory the installer wrote.
18
+ * It is a SECONDARY signal, used to recognise standalone skills installed
19
+ * with `--with <slug>` (whose slugs we can't enumerate ahead of time).
20
+ * 3. **Anything else is the user's.** An unstamped directory that is not a
21
+ * known entry slug is NEVER deleted, no matter what it's called.
22
+ *
23
+ * Deliberate, documented trade-off: a standalone skill installed by an OLDER CLI
24
+ * (before `installStandaloneSkill` wrote a stamp) is unstamped and therefore no
25
+ * longer removed by `removeAllSkills()`. That is the safe direction to be wrong —
26
+ * it leaves a stale-but-working copy on disk instead of deleting a stranger's
27
+ * work — and it self-heals: re-running `gooseworks install --with <slug>`
28
+ * replaces the directory in place and stamps it.
29
+ */
30
+ /** The stamp file `installEntrySkill` / `installStandaloneSkill` write. */
31
+ export declare const STAMP_FILE = ".gooseworks-version";
32
+ /**
33
+ * Entry-skill dir names the CLI no longer writes but must still clean up.
34
+ * `ads-remix` was renamed to `goose-ads`.
35
+ */
36
+ export declare const LEGACY_ENTRY_SKILL_NAMES: readonly ["ads-remix"];
37
+ /**
38
+ * Every skill directory name the CLI itself owns and writes. Derived from
39
+ * `getEntrySkills()` so the registry stays the single source (GOOSE-3190).
40
+ */
41
+ export declare function getManagedEntrySkillNames(): string[];
42
+ /** True when `name` is a skill directory the CLI itself installs. */
43
+ export declare function isManagedEntrySkillName(name: string): boolean;
44
+ /** True when `<skillsBase>/<name>/.gooseworks-version` exists. */
45
+ export declare function hasGooseworksStamp(skillsBase: string, name: string): boolean;
46
+ /**
47
+ * True when the CLI may manage (link, list, and DELETE) `<skillsBase>/<name>/`.
48
+ *
49
+ * `skillsBase` is required: ownership is a property of what's ON DISK, not of
50
+ * the name. Callers that only have a name (e.g. pruning symlinks in
51
+ * ~/.claude/skills) pass the skills base the links point into.
52
+ */
53
+ export declare function isManagedGooseworksSkill(name: string, skillsBase: string): boolean;
2
54
  //# sourceMappingURL=names.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../src/skills/names.ts"],"names":[],"mappings":"AAAA,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAS9D"}
1
+ {"version":3,"file":"names.d.ts","sourceRoot":"","sources":["../../src/skills/names.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,wBAAyB,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,EAAE,CAEpD;AAED,qEAAqE;AACrE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAM5E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAGlF"}
@@ -1,12 +1,112 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.LEGACY_ENTRY_SKILL_NAMES = exports.STAMP_FILE = void 0;
37
+ exports.getManagedEntrySkillNames = getManagedEntrySkillNames;
38
+ exports.isManagedEntrySkillName = isManagedEntrySkillName;
39
+ exports.hasGooseworksStamp = hasGooseworksStamp;
3
40
  exports.isManagedGooseworksSkill = isManagedGooseworksSkill;
4
- function isManagedGooseworksSkill(name) {
5
- return (name === 'gooseworks' ||
6
- // `ads-remix` was renamed to `goose-ads`; keep it managed so a stale
7
- // ads-remix dir from an older install is cleaned up on the next install.
8
- name === 'ads-remix' ||
9
- name.startsWith('gooseworks-') ||
10
- name.startsWith('goose-'));
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const master_skill_1 = require("./master-skill");
44
+ /**
45
+ * Which directories under ~/.agents/skills/ the CLI is allowed to DELETE.
46
+ *
47
+ * GOOSE-3191 (data loss): this predicate used to match ANY directory whose name
48
+ * started with `goose-` or `gooseworks-`. `gooseworks install` calls
49
+ * `removeAllSkills()` on every install / update / login-refresh, so a user's own
50
+ * unrelated third-party skill — `goose-notes`, `goose-jira`, anything they wrote
51
+ * themselves — was silently destroyed. A name prefix is NOT ownership.
52
+ *
53
+ * The rule now, in order of authority:
54
+ *
55
+ * 1. **Known entry-skill slugs** (`gooseworks`, `goose-ads`, `goose-video`,
56
+ * `goose-product-photos`, plus the legacy `ads-remix` name) are ours by
57
+ * definition — they are the dirs the CLI itself writes on every install, so
58
+ * we delete them regardless of whether they carry a stamp. This is what
59
+ * keeps upgrades from an old CLI working.
60
+ * 2. **A `.gooseworks-version` stamp** marks a directory the installer wrote.
61
+ * It is a SECONDARY signal, used to recognise standalone skills installed
62
+ * with `--with <slug>` (whose slugs we can't enumerate ahead of time).
63
+ * 3. **Anything else is the user's.** An unstamped directory that is not a
64
+ * known entry slug is NEVER deleted, no matter what it's called.
65
+ *
66
+ * Deliberate, documented trade-off: a standalone skill installed by an OLDER CLI
67
+ * (before `installStandaloneSkill` wrote a stamp) is unstamped and therefore no
68
+ * longer removed by `removeAllSkills()`. That is the safe direction to be wrong —
69
+ * it leaves a stale-but-working copy on disk instead of deleting a stranger's
70
+ * work — and it self-heals: re-running `gooseworks install --with <slug>`
71
+ * replaces the directory in place and stamps it.
72
+ */
73
+ /** The stamp file `installEntrySkill` / `installStandaloneSkill` write. */
74
+ exports.STAMP_FILE = '.gooseworks-version';
75
+ /**
76
+ * Entry-skill dir names the CLI no longer writes but must still clean up.
77
+ * `ads-remix` was renamed to `goose-ads`.
78
+ */
79
+ exports.LEGACY_ENTRY_SKILL_NAMES = ['ads-remix'];
80
+ /**
81
+ * Every skill directory name the CLI itself owns and writes. Derived from
82
+ * `getEntrySkills()` so the registry stays the single source (GOOSE-3190).
83
+ */
84
+ function getManagedEntrySkillNames() {
85
+ return [...(0, master_skill_1.getEntrySkillNames)(), ...exports.LEGACY_ENTRY_SKILL_NAMES];
86
+ }
87
+ /** True when `name` is a skill directory the CLI itself installs. */
88
+ function isManagedEntrySkillName(name) {
89
+ return getManagedEntrySkillNames().includes(name);
90
+ }
91
+ /** True when `<skillsBase>/<name>/.gooseworks-version` exists. */
92
+ function hasGooseworksStamp(skillsBase, name) {
93
+ try {
94
+ return fs.existsSync(path.join(skillsBase, name, exports.STAMP_FILE));
95
+ }
96
+ catch {
97
+ return false;
98
+ }
99
+ }
100
+ /**
101
+ * True when the CLI may manage (link, list, and DELETE) `<skillsBase>/<name>/`.
102
+ *
103
+ * `skillsBase` is required: ownership is a property of what's ON DISK, not of
104
+ * the name. Callers that only have a name (e.g. pruning symlinks in
105
+ * ~/.claude/skills) pass the skills base the links point into.
106
+ */
107
+ function isManagedGooseworksSkill(name, skillsBase) {
108
+ if (isManagedEntrySkillName(name))
109
+ return true;
110
+ return hasGooseworksStamp(skillsBase, name);
11
111
  }
12
112
  //# sourceMappingURL=names.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"names.js","sourceRoot":"","sources":["../../src/skills/names.ts"],"names":[],"mappings":";;AAAA,4DASC;AATD,SAAgB,wBAAwB,CAAC,IAAY;IACnD,OAAO,CACL,IAAI,KAAK,YAAY;QACrB,qEAAqE;QACrE,yEAAyE;QACzE,IAAI,KAAK,WAAW;QACpB,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAC1B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"names.js","sourceRoot":"","sources":["../../src/skills/names.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,8DAEC;AAGD,0DAEC;AAGD,gDAMC;AASD,4DAGC;AA3ED,uCAAyB;AACzB,2CAA6B;AAC7B,iDAAoD;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,2EAA2E;AAC9D,QAAA,UAAU,GAAG,qBAAqB,CAAC;AAEhD;;;GAGG;AACU,QAAA,wBAAwB,GAAG,CAAC,WAAW,CAAU,CAAC;AAE/D;;;GAGG;AACH,SAAgB,yBAAyB;IACvC,OAAO,CAAC,GAAG,IAAA,iCAAkB,GAAE,EAAE,GAAG,gCAAwB,CAAC,CAAC;AAChE,CAAC;AAED,qEAAqE;AACrE,SAAgB,uBAAuB,CAAC,IAAY;IAClD,OAAO,yBAAyB,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,kEAAkE;AAClE,SAAgB,kBAAkB,CAAC,UAAkB,EAAE,IAAY;IACjE,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,kBAAU,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,wBAAwB,CAAC,IAAY,EAAE,UAAkB;IACvE,IAAI,uBAAuB,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,kBAAkB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC"}