@promptctl/cc-candybar 1.30.0 → 1.31.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.
@@ -37,6 +37,8 @@ import {
37
37
  isGlobalsField,
38
38
  loadConfigOverrides,
39
39
  loadOverrides,
40
+ redoLastOverride,
41
+ undoLastOverride,
40
42
  writeConfigOverride,
41
43
  } from "../config-overrides-store";
42
44
  import { configOverridesPath } from "../paths";
@@ -49,6 +51,7 @@ import {
49
51
  VERB_DISPATCH,
50
52
  VERB_OPEN_VSCODE,
51
53
  VERB_LOAD_CONFIG,
54
+ VERB_REDO,
52
55
  VERB_RESET_CONFIG,
53
56
  VERB_SET_CONFIG,
54
57
  VERB_SET_STATE,
@@ -57,6 +60,7 @@ import {
57
60
  VERB_SHOW_CONFIG_ERROR,
58
61
  VERB_SHOW_CONFIG_WARNING,
59
62
  VERB_TOOLBAR_TOGGLE,
63
+ VERB_UNDO,
60
64
  } from "../../click/wire";
61
65
 
62
66
  export interface VerbContext {
@@ -489,6 +493,35 @@ const applyLayoutOp: VerbHandler = (rawValue, ctx) => {
489
493
  );
490
494
  };
491
495
 
496
+ // [LAW:one-source-of-truth] `reset`'s fine-grained sibling: step the ONE
497
+ // global history over the overrides layer back one entry. No key, no value —
498
+ // the history store (config-overrides-store.ts) owns which entry moves and
499
+ // what it restores; this handler is pure plumbing between the wire and it.
500
+ // [LAW:no-silent-failure] An empty stack is a loud BAD_REQUEST (dispatch's
501
+ // aggregator turns it into a transient click.error), never a silent no-op —
502
+ // the ticket's own done-gate.
503
+ const undoConfig: VerbHandler = (value, ctx) => {
504
+ const [sessionId = ""] = decodeWire(() => decodeSegments(value));
505
+ const sid = requireSessionId(sessionId);
506
+ const entry = undoLastOverride(configOverridesPath(), ctx.dlog);
507
+ if (entry === null) {
508
+ throw new BadVerbArgs("undo: history is empty, nothing to undo");
509
+ }
510
+ ctx.dlog("info", `undo: ${entry.key} (session=${sid})`);
511
+ };
512
+
513
+ // [LAW:one-source-of-truth] undo's mirror — steps the same global history
514
+ // forward one entry.
515
+ const redoConfig: VerbHandler = (value, ctx) => {
516
+ const [sessionId = ""] = decodeWire(() => decodeSegments(value));
517
+ const sid = requireSessionId(sessionId);
518
+ const entry = redoLastOverride(configOverridesPath(), ctx.dlog);
519
+ if (entry === null) {
520
+ throw new BadVerbArgs("redo: nothing to redo");
521
+ }
522
+ ctx.dlog("info", `redo: ${entry.key} (session=${sid})`);
523
+ };
524
+
492
525
  // ─── Registry ───────────────────────────────────────────────────────────────
493
526
 
494
527
  // [LAW:one-source-of-truth] The LEAF verbs — every click effect that does real
@@ -551,6 +584,8 @@ const LEAF_VERBS = new Map<string, VerbHandler>([
551
584
  [VERB_STEP_CONFIG, stepConfig],
552
585
  [VERB_RESET_CONFIG, resetConfig],
553
586
  [VERB_APPLY_LAYOUT_OP, applyLayoutOp],
587
+ [VERB_UNDO, undoConfig],
588
+ [VERB_REDO, redoConfig],
554
589
  [VERB_SHOW_CONFIG_ERROR, showConfigError],
555
590
  [VERB_SHOW_CONFIG_WARNING, showConfigWarning],
556
591
  [VERB_TOOLBAR_TOGGLE, toolbarToggle],
@@ -583,8 +618,9 @@ const dispatch: VerbHandler = (rawValue, ctx) => {
583
618
  for (const { verb, value } of parseEffects(rawValue)) {
584
619
  // Extract session ID from the first session-bearing effect for error display.
585
620
  // set-state, step-state, set-config, step-config, reset-config,
586
- // apply-layout-op, and toolbar-toggle all carry the session id as their
587
- // first segment, so a failing step surfaces in the bar like any other.
621
+ // apply-layout-op, undo, redo, and toolbar-toggle all carry the session id
622
+ // as their first segment, so a failing step surfaces in the bar like any
623
+ // other.
588
624
  if (
589
625
  !sessionId &&
590
626
  (verb === VERB_SET_STATE ||
@@ -593,6 +629,8 @@ const dispatch: VerbHandler = (rawValue, ctx) => {
593
629
  verb === VERB_STEP_CONFIG ||
594
630
  verb === VERB_RESET_CONFIG ||
595
631
  verb === VERB_APPLY_LAYOUT_OP ||
632
+ verb === VERB_UNDO ||
633
+ verb === VERB_REDO ||
596
634
  verb === VERB_TOOLBAR_TOGGLE)
597
635
  ) {
598
636
  const parts = decodeSegments(value);
@@ -34,11 +34,13 @@ import {
34
34
  VERB_APPLY_LAYOUT_OP,
35
35
  VERB_COPY,
36
36
  VERB_OPEN_VSCODE,
37
+ VERB_REDO,
37
38
  VERB_RESET_CONFIG,
38
39
  VERB_SET_CONFIG,
39
40
  VERB_SET_STATE,
40
41
  VERB_STEP_CONFIG,
41
42
  VERB_STEP_STATE,
43
+ VERB_UNDO,
42
44
  type Effect,
43
45
  } from "../click/wire.js";
44
46
 
@@ -142,7 +144,13 @@ export type CompiledActionDecl =
142
144
  // arms. Fully literal at compile time (the op IS the declaration — no
143
145
  // template-bound option, unlike persist-option), so `op` is precomputed
144
146
  // here rather than reconstructed from raw fields at every realize() call.
145
- | { readonly kind: "layout-op"; readonly key: string; readonly op: LayoutOp };
147
+ | { readonly kind: "layout-op"; readonly key: string; readonly op: LayoutOp }
148
+ // [LAW:one-source-of-truth] brandon-layout-edit-2gc.2's global history
149
+ // step over the overrides layer — `reset`'s fine-grained sibling. No key:
150
+ // there is nothing to carry, since the history stack (not this action) is
151
+ // what decides which entry moves.
152
+ | { readonly kind: "undo" }
153
+ | { readonly kind: "redo" };
146
154
 
147
155
  export type CompiledActions = ReadonlyMap<string, CompiledActionDecl>;
148
156
 
@@ -338,7 +346,10 @@ function compileAction(
338
346
  target: parseActionTemplate(parse, action.open, name),
339
347
  };
340
348
  }
341
- return { kind: "reset", key: action.reset };
349
+ if ("reset" in action) {
350
+ return { kind: "reset", key: action.reset };
351
+ }
352
+ return "undo" in action ? { kind: "undo" } : { kind: "redo" };
342
353
  }
343
354
 
344
355
  function parseActionTemplate(
@@ -548,6 +559,20 @@ function realize(
548
559
  effect: { verb: VERB_RESET_CONFIG, args: [sessionId, c.key] },
549
560
  active: false,
550
561
  };
562
+ // [LAW:one-source-of-truth] No key to carry — the click just says "step
563
+ // the history", and which entry moves is entirely server-side state
564
+ // (never wire input, so there is nothing here to gate). Never "active":
565
+ // a history step is a one-shot trigger, not a current-selection toggle.
566
+ case "undo":
567
+ return {
568
+ effect: { verb: VERB_UNDO, args: [sessionId] },
569
+ active: false,
570
+ };
571
+ case "redo":
572
+ return {
573
+ effect: { verb: VERB_REDO, args: [sessionId] },
574
+ active: false,
575
+ };
551
576
  // [LAW:one-source-of-truth] The op is fixed at compile time (see
552
577
  // compileAction) — the click just delivers it. `apply-layout-op`'s
553
578
  // handler does read-current-append-write (see verbs/index.ts), unlike