@ordewell/core 0.12.1 → 0.12.2

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.
@@ -195,8 +195,39 @@ import {
195
195
  titledTaskRefOf,
196
196
  walkPlan
197
197
  } from "./chunk-PKJTN2PD.mjs";
198
+
199
+ // src/services/composerTips.ts
200
+ var COMPOSER_TIPS = [
201
+ // The per-runner model allowlist (ADR-0003) is the easiest command to miss.
202
+ { command: "allowlist", weight: 3, text: "Tip: Use /allowlist to limit which models the planner assigns per runner." },
203
+ { command: "planner", weight: 1, text: "Tip: Use /planner to pick the planner's harness, model and effort." },
204
+ { command: "runners", weight: 1, text: "Tip: Use /runners to turn runners on or off." },
205
+ { command: "settings", weight: 1, text: "Tip: Use /settings for autonomy, supervisor, merging, autorun and more." },
206
+ { command: "help", weight: 1, text: "Tip: Use /help to list every command." }
207
+ ];
208
+ function tipCycle(tips) {
209
+ const total = tips.reduce((sum, tip) => sum + Math.max(0, tip.weight), 0);
210
+ if (total === 0) return [];
211
+ const slots = new Array(total).fill(void 0);
212
+ const order = tips.map((tip, index) => ({ tip, index })).filter(({ tip }) => tip.weight > 0).sort((a, b) => b.tip.weight - a.tip.weight || a.index - b.index);
213
+ for (const { tip } of order) {
214
+ const free = slots.flatMap((slot, at) => slot === void 0 ? [at] : []);
215
+ for (let k = 0; k < tip.weight; k++) {
216
+ slots[free[Math.floor((k + 0.5) * free.length / tip.weight)]] = tip;
217
+ }
218
+ }
219
+ const cycle = slots.filter((tip) => tip !== void 0);
220
+ const start = cycle.indexOf(order[0].tip);
221
+ return [...cycle.slice(start), ...cycle.slice(0, start)];
222
+ }
223
+ function composerTip(seq, answers) {
224
+ const cycle = tipCycle(COMPOSER_TIPS.filter((tip) => answers.has(tip.command)));
225
+ if (cycle.length === 0) return null;
226
+ return cycle[(seq % cycle.length + cycle.length) % cycle.length].text;
227
+ }
198
228
  export {
199
229
  CHECKPOINT_TRUNCATE_LENGTH,
230
+ COMPOSER_TIPS,
200
231
  DEFAULT_RUNNERS,
201
232
  DELEGATION_OFFERED,
202
233
  EMPTY_CONVERSATION,
@@ -249,6 +280,7 @@ export {
249
280
  clampThinkingEffort,
250
281
  closeTurn,
251
282
  compactionText,
283
+ composerTip,
252
284
  confirmedOverride,
253
285
  contextMeterText,
254
286
  contextMeterTitle,
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/services/composerTips.ts"],"sourcesContent":["/**\n * The tips an empty planner chat composer shows (#137), one table for every\n * surface so the TUI and the webview agree on the wording and how often each\n * comes round. A surface offers only the tips for the commands it answers.\n */\n\nexport interface ComposerTip {\n /** The built-in planner chat command the tip names, without its slash. */\n command: string;\n /** How many times per cycle the tip comes round. */\n weight: number;\n /** Short enough to fit after the prompt and caret on an 80-column terminal. */\n text: string;\n}\n\nexport const COMPOSER_TIPS: readonly ComposerTip[] = [\n // The per-runner model allowlist (ADR-0003) is the easiest command to miss.\n { command: 'allowlist', weight: 3, text: 'Tip: Use /allowlist to limit which models the planner assigns per runner.' },\n { command: 'planner', weight: 1, text: \"Tip: Use /planner to pick the planner's harness, model and effort.\" },\n { command: 'runners', weight: 1, text: 'Tip: Use /runners to turn runners on or off.' },\n { command: 'settings', weight: 1, text: 'Tip: Use /settings for autonomy, supervisor, merging, autorun and more.' },\n { command: 'help', weight: 1, text: 'Tip: Use /help to list every command.' },\n];\n\n/**\n * One cycle of `tips`, each appearing exactly its weight times. Heavier tips\n * take their slots first, at the midpoints of equal shares of the free slots, so\n * raising a weight spreads it out instead of leaving it to run together at the\n * end of the cycle; where a tip outnumbers all the others, the touches it\n * cannot avoid are spread as evenly as the counts allow. The cycle starts on\n * the heaviest tip, so the first seq is the one the table weights most.\n */\nexport function tipCycle(tips: readonly ComposerTip[]): ComposerTip[] {\n const total = tips.reduce((sum, tip) => sum + Math.max(0, tip.weight), 0);\n if (total === 0) return [];\n const slots = new Array<ComposerTip | undefined>(total).fill(undefined);\n const order = tips\n .map((tip, index) => ({ tip, index }))\n .filter(({ tip }) => tip.weight > 0)\n .sort((a, b) => b.tip.weight - a.tip.weight || a.index - b.index);\n for (const { tip } of order) {\n const free = slots.flatMap((slot, at) => (slot === undefined ? [at] : []));\n for (let k = 0; k < tip.weight; k++) {\n slots[free[Math.floor(((k + 0.5) * free.length) / tip.weight)]] = tip;\n }\n }\n const cycle = slots.filter((tip): tip is ComposerTip => tip !== undefined);\n const start = cycle.indexOf(order[0].tip);\n return [...cycle.slice(start), ...cycle.slice(0, start)];\n}\n\n/**\n * The tip for the `seq`-th time the composer has been empty, among those for\n * the commands the surface answers, or null when it answers none of them. The\n * same `seq` always gives the same tip, so the surface decides when a new one\n * shows by when it moves `seq` on, and its rendering stays a function of state.\n */\nexport function composerTip(seq: number, answers: ReadonlySet<string>): string | null {\n const cycle = tipCycle(COMPOSER_TIPS.filter((tip) => answers.has(tip.command)));\n if (cycle.length === 0) return null;\n return cycle[((seq % cycle.length) + cycle.length) % cycle.length].text;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeO,IAAM,gBAAwC;AAAA;AAAA,EAEnD,EAAE,SAAS,aAAa,QAAQ,GAAG,MAAM,4EAA4E;AAAA,EACrH,EAAE,SAAS,WAAW,QAAQ,GAAG,MAAM,qEAAqE;AAAA,EAC5G,EAAE,SAAS,WAAW,QAAQ,GAAG,MAAM,+CAA+C;AAAA,EACtF,EAAE,SAAS,YAAY,QAAQ,GAAG,MAAM,0EAA0E;AAAA,EAClH,EAAE,SAAS,QAAQ,QAAQ,GAAG,MAAM,wCAAwC;AAC9E;AAUO,SAAS,SAAS,MAA6C;AACpE,QAAM,QAAQ,KAAK,OAAO,CAAC,KAAK,QAAQ,MAAM,KAAK,IAAI,GAAG,IAAI,MAAM,GAAG,CAAC;AACxE,MAAI,UAAU,EAAG,QAAO,CAAC;AACzB,QAAM,QAAQ,IAAI,MAA+B,KAAK,EAAE,KAAK,MAAS;AACtE,QAAM,QAAQ,KACX,IAAI,CAAC,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,EACpC,OAAO,CAAC,EAAE,IAAI,MAAM,IAAI,SAAS,CAAC,EAClC,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,SAAS,EAAE,IAAI,UAAU,EAAE,QAAQ,EAAE,KAAK;AAClE,aAAW,EAAE,IAAI,KAAK,OAAO;AAC3B,UAAM,OAAO,MAAM,QAAQ,CAAC,MAAM,OAAQ,SAAS,SAAY,CAAC,EAAE,IAAI,CAAC,CAAE;AACzE,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,YAAM,KAAK,KAAK,OAAQ,IAAI,OAAO,KAAK,SAAU,IAAI,MAAM,CAAC,CAAC,IAAI;AAAA,IACpE;AAAA,EACF;AACA,QAAM,QAAQ,MAAM,OAAO,CAAC,QAA4B,QAAQ,MAAS;AACzE,QAAM,QAAQ,MAAM,QAAQ,MAAM,CAAC,EAAE,GAAG;AACxC,SAAO,CAAC,GAAG,MAAM,MAAM,KAAK,GAAG,GAAG,MAAM,MAAM,GAAG,KAAK,CAAC;AACzD;AAQO,SAAS,YAAY,KAAa,SAA6C;AACpF,QAAM,QAAQ,SAAS,cAAc,OAAO,CAAC,QAAQ,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC;AAC9E,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,OAAQ,MAAM,MAAM,SAAU,MAAM,UAAU,MAAM,MAAM,EAAE;AACrE;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordewell/core",
3
- "version": "0.12.1",
3
+ "version": "0.12.2",
4
4
  "description": "Ordewell core — planner, orchestrator, runners and verification engine.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Alessandro Costanzo Ciano",