@mccaskie-labs/workbench-config 0.2.2 → 0.2.4

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.
@@ -401,7 +401,7 @@ export type Offer = z.infer<typeof offer>;
401
401
  * 11 November 2026: every shared tool ships its questions). The list only
402
402
  * shrinks; a new component can't join it.
403
403
  */
404
- export declare const OFFER_PENDING: readonly ["ai", "analytics", "country", "database", "email", "email-inbound", "image-search", "images", "pdf", "strings", "ui"];
404
+ export declare const OFFER_PENDING: readonly ["analytics", "country", "database", "email", "email-inbound", "strings", "ui"];
405
405
  export interface ManifestProblem {
406
406
  file: string;
407
407
  check: "schema" | "proof" | "ids" | "surfaces" | "errors" | "generated";
@@ -267,7 +267,7 @@ export const capabilitySchema = z.strictObject(baseShape).superRefine((m, ctx) =
267
267
  * 11 November 2026: every shared tool ships its questions). The list only
268
268
  * shrinks; a new component can't join it.
269
269
  */
270
- export const OFFER_PENDING = ["ai", "analytics", "country", "database", "email", "email-inbound", "image-search", "images", "pdf", "strings", "ui"];
270
+ export const OFFER_PENDING = ["analytics", "country", "database", "email", "email-inbound", "strings", "ui"];
271
271
  function checkOffer(file, component, o, seen) {
272
272
  const problems = [];
273
273
  const named = new Map();
package/dist/skills.js CHANGED
@@ -41,8 +41,11 @@ function questionBlock(q, n) {
41
41
  lines.push("Ask as a table: propose a value for each row, show the table, then ask one question with the answers \"Accept all (Recommended)\", \"Change some\" and \"Add or remove\".");
42
42
  }
43
43
  else {
44
+ // A must-ask question has no safe default, so none of its answers is recommended.
45
+ if (q.must_ask)
46
+ lines.push("None of these answers is recommended: only the client knows, so don't label any \"(Recommended)\".", "");
44
47
  lines.push("| Answer | Value | Means |", "| --- | --- | --- |");
45
- (q.answers ?? []).forEach((a, i) => lines.push(`| ${cell(a.label)}${i === 0 ? " (Recommended)" : ""} | ${show(a.value)} | ${cell(a.means ?? "")} |`));
48
+ (q.answers ?? []).forEach((a, i) => lines.push(`| ${cell(a.label)}${i === 0 && !q.must_ask ? " (Recommended)" : ""} | ${show(a.value)} | ${cell(a.means ?? "")} |`));
46
49
  }
47
50
  lines.push("", otherLine(q));
48
51
  if (q.note)
@@ -76,7 +79,7 @@ function draftsBlock(d) {
76
79
  "",
77
80
  `Offer ${d.count} examples of ${d.of} to pick from, at most ${d.max_rounds} round${d.max_rounds === 1 ? "" : "s"}. Make them with \`${d.command}\`: it calls the Workbench Gateway (${d.surface}${d.alias ? `, \`${d.alias}\`` : ""}, job \`${d.job}\`) with the project's development key from \`.dev.vars\`, spends from the development budget, and prints what each round cost. Tell the client the cost it prints.`,
78
81
  "",
79
- "Never write drafts yourself and never call a vendor directly. If the command says there is no development key, say so and offer the standard version instead; never ask for a key in chat. Record the picked draft's request id, model and cost in the answers file.",
82
+ "Never write drafts yourself and never call a vendor directly. If the command says there is no development key, say so and go on without drafts: the standard version, or the client's own wording or picture. Never ask for a key in chat. Keep the client's choice with the pick command the command prints, which records its request ids, model and cost.",
80
83
  ].join("\n");
81
84
  }
82
85
  /** A guide's text as a section of a skill: its title dropped, its headings one level down. */
@@ -149,7 +152,7 @@ export function renderSkill(m, guide) {
149
152
  }
150
153
  out.push("", "## What to say", "", d.choice === "optional"
151
154
  ? `Once the owner's choice is yes, say: "${o.say}"`
152
- : `Say: "${o.say}" Don't ask whether to use Workbench or something of the client's own. If the client says they don't want it, stop and say what they give up.`, "", "## How to ask", "", ...(o.needs?.length ? [`- First check the project setup this needs: ${o.needs.map((n) => `\`workbench/${n}.json\``).join(", ")}. If one is missing, use that component's \`workbench-<component>\` skill first.`] : []), ...PATTERN_STEPS[o.pattern].map((step) => `- ${step}`), "- Ask with the AskUserQuestion tool, up to four questions per call. Give each question's answers in the order below; the first is recommended, so label it \"(Recommended)\". The tool adds \"Other\" itself.", "- Where the client accepts every recommendation, still ask each \"Must ask\" question.", "- An \"Other\" answer must meet the rule under its question. When it doesn't, say why and ask again. Never store a value outside it.", "- Ask nothing that isn't listed here, and invent no setting. A need the questions don't cover goes back to the client as a plain question, and isn't written to the answers file.", `- Write the answers to \`${o.answers_file}\`${o.per ? `, one entry per ${o.per}` : ""}: ${o.answers_format ?? `for each question its id, the value, and the client's own words when they typed "Other" or changed a recommendation.`}${o.generator ? ` Then run \`${o.generator}\`, which writes the code and refuses anything the package can't apply (it doesn't check the "Other" rules: you do). It builds nothing while an answers file is a draft. Never edit what it writes; change the answers file and run it again.` : ""}`, "", "## Questions", "", o.questions.map((q, i) => questionBlock(q, i + 1)).join("\n\n"));
155
+ : `Say: "${o.say}" Don't ask whether to use Workbench or something of the client's own. If the client says they don't want it, stop and say what they give up.`, "", "## How to ask", "", ...(o.needs?.length ? [`- First check the project setup this needs: ${o.needs.map((n) => `\`workbench/${n}.json\``).join(", ")}. If one is missing, use that component's \`workbench-<component>\` skill first.`] : []), ...PATTERN_STEPS[o.pattern].map((step) => `- ${step}`), "- Ask with the AskUserQuestion tool, up to four questions per call. Give each question's answers in the order below; the first is recommended, so label it \"(Recommended)\", unless the question says none is. The tool adds \"Other\" itself.", "- Where the client accepts every recommendation, still ask each \"Must ask\" question.", "- An \"Other\" answer must meet the rule under its question. When it doesn't, say why and ask again. Never store a value outside it.", "- Ask nothing that isn't listed here, and invent no setting. A need the questions don't cover goes back to the client as a plain question, and isn't written to the answers file.", `- Write the answers to \`${o.answers_file}\`${o.per ? `, one entry per ${o.per}` : ""}: ${o.answers_format ?? `for each question its id, the value, and the client's own words when they typed "Other" or changed a recommendation.`}${o.generator ? ` Then run \`${o.generator}\`, which writes the code and refuses anything the package can't apply (it doesn't check the "Other" rules: you do). It builds nothing while an answers file is a draft. Never edit what it writes; change the answers file and run it again.` : ""}`, "", "## Questions", "", o.questions.map((q, i) => questionBlock(q, i + 1)).join("\n\n"));
153
156
  if (o.drafts)
154
157
  out.push("", draftsBlock(o.drafts));
155
158
  if (o.not_asked?.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mccaskie-labs/workbench-config",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Workbench app configuration: WORKBENCH_ENV, typed variables that fail by name, secrets that are never printed, and the capabilities manifest.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",