@hegemonart/get-design-done 1.25.0 → 1.27.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 (58) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +96 -0
  4. package/README.md +12 -6
  5. package/SKILL.md +3 -0
  6. package/agents/README.md +89 -0
  7. package/agents/design-reflector.md +43 -0
  8. package/agents/gdd-intel-updater.md +34 -1
  9. package/hooks/budget-enforcer.ts +143 -4
  10. package/package.json +1 -1
  11. package/reference/model-prices.md +40 -19
  12. package/reference/peer-cli-capabilities.md +151 -0
  13. package/reference/peer-protocols.md +266 -0
  14. package/reference/prices/antigravity.md +21 -0
  15. package/reference/prices/augment.md +21 -0
  16. package/reference/prices/claude.md +42 -0
  17. package/reference/prices/cline.md +23 -0
  18. package/reference/prices/codebuddy.md +21 -0
  19. package/reference/prices/codex.md +25 -0
  20. package/reference/prices/copilot.md +21 -0
  21. package/reference/prices/cursor.md +21 -0
  22. package/reference/prices/gemini.md +25 -0
  23. package/reference/prices/kilo.md +21 -0
  24. package/reference/prices/opencode.md +23 -0
  25. package/reference/prices/qwen.md +25 -0
  26. package/reference/prices/trae.md +23 -0
  27. package/reference/prices/windsurf.md +21 -0
  28. package/reference/registry.json +121 -1
  29. package/reference/runtime-models.md +446 -0
  30. package/reference/schemas/runtime-models.schema.json +123 -0
  31. package/scripts/install.cjs +8 -0
  32. package/scripts/lib/bandit-router.cjs +214 -7
  33. package/scripts/lib/budget-enforcer.cjs +514 -0
  34. package/scripts/lib/cost-arbitrage.cjs +294 -0
  35. package/scripts/lib/event-stream/index.ts +14 -1
  36. package/scripts/lib/event-stream/types.ts +125 -1
  37. package/scripts/lib/install/installer.cjs +188 -11
  38. package/scripts/lib/install/parse-runtime-models.cjs +267 -0
  39. package/scripts/lib/install/runtimes.cjs +101 -0
  40. package/scripts/lib/peer-cli/acp-client.cjs +375 -0
  41. package/scripts/lib/peer-cli/adapters/codex.cjs +101 -0
  42. package/scripts/lib/peer-cli/adapters/copilot.cjs +79 -0
  43. package/scripts/lib/peer-cli/adapters/cursor.cjs +78 -0
  44. package/scripts/lib/peer-cli/adapters/gemini.cjs +81 -0
  45. package/scripts/lib/peer-cli/adapters/qwen.cjs +72 -0
  46. package/scripts/lib/peer-cli/asp-client.cjs +587 -0
  47. package/scripts/lib/peer-cli/broker-lifecycle.cjs +406 -0
  48. package/scripts/lib/peer-cli/registry.cjs +434 -0
  49. package/scripts/lib/peer-cli/spawn-cmd.cjs +149 -0
  50. package/scripts/lib/runtime-detect.cjs +96 -0
  51. package/scripts/lib/session-runner/index.ts +215 -0
  52. package/scripts/lib/session-runner/types.ts +60 -0
  53. package/scripts/lib/tier-resolver.cjs +311 -0
  54. package/scripts/validate-frontmatter.ts +297 -2
  55. package/skills/peer-cli-add/SKILL.md +170 -0
  56. package/skills/peer-cli-customize/SKILL.md +110 -0
  57. package/skills/peers/SKILL.md +101 -0
  58. package/skills/router/SKILL.md +51 -2
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * bandit-router.cjs — contextual Thompson-sampling bandit over
3
- * (agent_type, touches_size_bin) → {haiku, sonnet, opus} (Plan 23.5-01).
3
+ * (agent_type, touches_size_bin[, delegate]) → {haiku, sonnet, opus}
4
+ * (Plan 23.5-01 + Plan 27-07 delegate dimension).
4
5
  *
5
6
  * Replaces Phase 10.1's static tier_overrides map when the user opts
6
7
  * into adaptive_mode = "full". The static map continues to apply when
@@ -10,12 +11,25 @@
10
11
  * .design/telemetry/posterior.json
11
12
  * { schema_version: '1.0.0',
12
13
  * generated_at: ISO,
13
- * arms: [{agent, bin, tier, alpha, beta, last_used, count}] }
14
+ * arms: [{agent, bin, tier, delegate?, alpha, beta, last_used, count}] }
15
+ *
16
+ * The `delegate` field on an arm is OPTIONAL (Plan 27-07 / D-08). Existing
17
+ * callers that pass only `(agent, bin)` continue to read/write arms with
18
+ * `delegate === undefined`, which behaves identically to delegate='none'
19
+ * (i.e., the local-call slice). New callers can opt into the delegate
20
+ * dimension via `pullWithDelegate()` / `updateWithDelegate()` which
21
+ * persist `delegate ∈ {none, gemini, codex, cursor, copilot, qwen}`.
22
+ *
23
+ * Bootstrap discipline (D-08):
24
+ * - delegate='none' arms inherit Phase 23.5's TIER_PRIOR (informed).
25
+ * - delegate ∈ {gemini, codex, cursor, copilot, qwen} arms start
26
+ * neutral — the same TIER_PRIOR shape, on the assumption that we
27
+ * have no prior to favour any delegate over local; data drives.
14
28
  *
15
29
  * Atomic .tmp + rename. Discounted Thompson via per-arm time-decay
16
30
  * factor `rho^days_since_last_use` applied at sample time, not stored.
17
31
  *
18
- * Reward computation (D-06): two-stage lexicographic
32
+ * Reward computation (D-06): two-stage lexicographic — UNCHANGED.
19
33
  * if !solidify_pass: reward = 0
20
34
  * elif user_undo_in_session: reward = 0
21
35
  * else: reward = 1 - lambda * normalize(cost + epsilon * wall_time)
@@ -45,11 +59,25 @@ const TIER_PRIOR = Object.freeze({
45
59
  const PRIOR_STRENGTH = 10;
46
60
  const DEFAULT_TIERS = Object.freeze(['haiku', 'sonnet', 'opus']);
47
61
 
62
+ // Plan 27-07 / D-08. Delegate context dimension. 'none' = local Anthropic
63
+ // call; the other 5 are peer-CLI delegations via ACP/ASP. Adding this as
64
+ // a third context dimension expands the arm space 6× (78 → ~468 contexts).
65
+ const DELEGATE_NONE = 'none';
66
+ const DEFAULT_DELEGATES = Object.freeze([
67
+ DELEGATE_NONE,
68
+ 'gemini',
69
+ 'codex',
70
+ 'cursor',
71
+ 'copilot',
72
+ 'qwen',
73
+ ]);
74
+
48
75
  const DEFAULT_PRIORS = Object.freeze({
49
76
  decay: DEFAULT_DECAY,
50
77
  strength: PRIOR_STRENGTH,
51
78
  tiers: DEFAULT_TIERS,
52
79
  perTier: TIER_PRIOR,
80
+ delegates: DEFAULT_DELEGATES,
53
81
  });
54
82
 
55
83
  const TOUCHES_BINS = Object.freeze([
@@ -141,12 +169,47 @@ function priorFor(tier, strength) {
141
169
  };
142
170
  }
143
171
 
144
- function findArm(arms, agent, bin, tier) {
145
- return arms.find((a) => a.agent === agent && a.bin === bin && a.tier === tier);
172
+ /**
173
+ * @param {object[]} arms
174
+ * @param {string} agent
175
+ * @param {string} bin
176
+ * @param {string} tier
177
+ * @param {string} [delegate] — when provided, match arms with that
178
+ * delegate label. When omitted, match arms with no delegate field
179
+ * (legacy Phase 23.5 slice — equivalent to delegate='none' for
180
+ * bootstrap purposes but persisted distinctly to preserve
181
+ * round-trippability of existing posterior files).
182
+ */
183
+ function findArm(arms, agent, bin, tier, delegate) {
184
+ if (delegate === undefined) {
185
+ return arms.find(
186
+ (a) =>
187
+ a.agent === agent &&
188
+ a.bin === bin &&
189
+ a.tier === tier &&
190
+ a.delegate === undefined,
191
+ );
192
+ }
193
+ return arms.find(
194
+ (a) =>
195
+ a.agent === agent &&
196
+ a.bin === bin &&
197
+ a.tier === tier &&
198
+ a.delegate === delegate,
199
+ );
146
200
  }
147
201
 
148
- function ensureArm(posterior, agent, bin, tier, strength) {
149
- let arm = findArm(posterior.arms, agent, bin, tier);
202
+ /**
203
+ * Ensure an arm exists, creating it with the informed prior when missing.
204
+ *
205
+ * For Plan 27-07: when `delegate` is provided, the arm is persisted with
206
+ * that label. Bootstrap is identical for delegate='none' (inherits Phase
207
+ * 23.5 prior — no migration needed because the legacy slice and the
208
+ * 'none' slice are independent contexts) and for the 5 peer delegates
209
+ * (each starts neutral with the same TIER_PRIOR shape; data drives).
210
+ */
211
+ function ensureArm(posterior, agent, bin, tier, strength, delegate) {
212
+ let arm = findArm(posterior.arms, agent, bin, tier, delegate);
150
213
  if (arm) return arm;
151
214
  const { alpha, beta } = priorFor(tier, strength);
152
215
  arm = {
@@ -158,6 +221,9 @@ function ensureArm(posterior, agent, bin, tier, strength) {
158
221
  last_used: null,
159
222
  count: 0,
160
223
  };
224
+ if (delegate !== undefined) {
225
+ arm.delegate = delegate;
226
+ }
161
227
  posterior.arms.push(arm);
162
228
  return arm;
163
229
  }
@@ -310,6 +376,143 @@ function update(input) {
310
376
  return { alpha: arm.alpha, beta: arm.beta, posteriorPath: p };
311
377
  }
312
378
 
379
+ /**
380
+ * Pull an arm with the delegate context dimension (Plan 27-07 / D-08).
381
+ *
382
+ * Joint sample over `tiers × delegates` — i.e., 3 × 6 = 18 arms in the
383
+ * default case. Returns the (tier, delegate) pair with the highest
384
+ * sampled posterior. Bumps the chosen arm's last_used + count.
385
+ *
386
+ * Caller-restricted delegate set:
387
+ * - For `delegate_to: none` agents (Plan 27-06 frontmatter), the caller
388
+ * should pass `delegates: ['none']` to constrain sampling to the
389
+ * local-call slice — the bandit will not explore peer delegations.
390
+ * - For agents without `delegate_to` (default), the caller may either
391
+ * omit delegates (legacy `pull()` behaviour) or pass DEFAULT_DELEGATES
392
+ * to enable adaptive routing across the full 18-arm space.
393
+ *
394
+ * @param {{
395
+ * agent: string,
396
+ * bin: string,
397
+ * tiers?: string[],
398
+ * delegates?: string[],
399
+ * baseDir?: string,
400
+ * posteriorPath?: string,
401
+ * decay?: number,
402
+ * strength?: number,
403
+ * now?: Date,
404
+ * }} input
405
+ * @returns {{
406
+ * tier: string,
407
+ * delegate: string,
408
+ * samples: Record<string, Record<string, number>>,
409
+ * posteriorPath: string,
410
+ * }}
411
+ */
412
+ function pullWithDelegate(input) {
413
+ if (!input || typeof input.agent !== 'string' || input.agent.length === 0) {
414
+ throw new TypeError('bandit-router.pullWithDelegate: agent (string) required');
415
+ }
416
+ if (typeof input.bin !== 'string' || input.bin.length === 0) {
417
+ throw new TypeError('bandit-router.pullWithDelegate: bin (string) required');
418
+ }
419
+ const tiers = input.tiers ?? DEFAULT_TIERS;
420
+ const delegates = input.delegates ?? DEFAULT_DELEGATES;
421
+ if (!Array.isArray(delegates) || delegates.length === 0) {
422
+ throw new TypeError(
423
+ 'bandit-router.pullWithDelegate: delegates must be a non-empty array',
424
+ );
425
+ }
426
+ const strength = input.strength ?? PRIOR_STRENGTH;
427
+ const now = input.now ?? new Date();
428
+
429
+ const posterior = loadPosterior(input);
430
+ /** @type {Record<string, Record<string, number>>} */
431
+ const samples = {};
432
+ let bestTier = tiers[0];
433
+ let bestDelegate = delegates[0];
434
+ let bestSample = -1;
435
+ for (const delegate of delegates) {
436
+ samples[delegate] = {};
437
+ for (const tier of tiers) {
438
+ const arm = ensureArm(posterior, input.agent, input.bin, tier, strength, delegate);
439
+ const decayed = decayArm(arm, { decay: input.decay, now, strength });
440
+ const s = sampleBeta(decayed.alpha, decayed.beta);
441
+ samples[delegate][tier] = s;
442
+ if (s > bestSample) {
443
+ bestSample = s;
444
+ bestTier = tier;
445
+ bestDelegate = delegate;
446
+ }
447
+ }
448
+ }
449
+ const chosen = ensureArm(
450
+ posterior,
451
+ input.agent,
452
+ input.bin,
453
+ bestTier,
454
+ strength,
455
+ bestDelegate,
456
+ );
457
+ chosen.last_used = now.toISOString();
458
+ chosen.count += 1;
459
+ const written = savePosterior(posterior, input);
460
+ return {
461
+ tier: bestTier,
462
+ delegate: bestDelegate,
463
+ samples,
464
+ posteriorPath: written,
465
+ };
466
+ }
467
+
468
+ /**
469
+ * Update the posterior with a reward signal — delegate-aware variant.
470
+ *
471
+ * Reward signal is UNCHANGED from Phase 23.5 (D-08): two-stage
472
+ * lexicographic via `computeReward()` — correctness first, cost as
473
+ * tiebreaker. The delegate dimension is applied at the arm-locator
474
+ * level, not the reward computation.
475
+ *
476
+ * @param {{
477
+ * agent: string,
478
+ * bin: string,
479
+ * tier: string,
480
+ * delegate: string,
481
+ * reward: number,
482
+ * baseDir?: string,
483
+ * posteriorPath?: string,
484
+ * strength?: number,
485
+ * }} input
486
+ * @returns {{alpha: number, beta: number, posteriorPath: string}}
487
+ */
488
+ function updateWithDelegate(input) {
489
+ if (!input) throw new TypeError('bandit-router.updateWithDelegate: input required');
490
+ for (const k of ['agent', 'bin', 'tier', 'delegate']) {
491
+ if (typeof input[k] !== 'string' || input[k].length === 0) {
492
+ throw new TypeError(
493
+ `bandit-router.updateWithDelegate: ${k} (string) required`,
494
+ );
495
+ }
496
+ }
497
+ if (typeof input.reward !== 'number' || Number.isNaN(input.reward)) {
498
+ throw new TypeError('bandit-router.updateWithDelegate: reward (number) required');
499
+ }
500
+ const r = Math.min(1, Math.max(0, input.reward));
501
+ const posterior = loadPosterior(input);
502
+ const arm = ensureArm(
503
+ posterior,
504
+ input.agent,
505
+ input.bin,
506
+ input.tier,
507
+ input.strength ?? PRIOR_STRENGTH,
508
+ input.delegate,
509
+ );
510
+ arm.alpha += r;
511
+ arm.beta += 1 - r;
512
+ const p = savePosterior(posterior, input);
513
+ return { alpha: arm.alpha, beta: arm.beta, posteriorPath: p };
514
+ }
515
+
313
516
  /**
314
517
  * Two-stage lexicographic reward (D-06).
315
518
  *
@@ -350,6 +553,8 @@ function computeReward(input) {
350
553
  module.exports = {
351
554
  pull,
352
555
  update,
556
+ pullWithDelegate,
557
+ updateWithDelegate,
353
558
  reset,
354
559
  loadPosterior,
355
560
  savePosterior,
@@ -360,6 +565,8 @@ module.exports = {
360
565
  priorFor,
361
566
  DEFAULT_PRIORS,
362
567
  DEFAULT_TIERS,
568
+ DEFAULT_DELEGATES,
569
+ DELEGATE_NONE,
363
570
  TIER_PRIOR,
364
571
  PRIOR_STRENGTH,
365
572
  TOUCHES_BINS,