@sushant-kum/ccstatus 0.1.1 → 0.1.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.
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
COLORS,
|
|
4
|
+
LINKABLE,
|
|
4
5
|
configPath,
|
|
5
6
|
importCcstatusline,
|
|
6
7
|
isValidWhen,
|
|
8
|
+
linkedSurfaces,
|
|
7
9
|
loadConfigFile,
|
|
8
10
|
readSnapshot,
|
|
9
11
|
registry,
|
|
@@ -11,8 +13,9 @@ import {
|
|
|
11
13
|
rendererBg,
|
|
12
14
|
rendererColor,
|
|
13
15
|
saveConfigFile,
|
|
14
|
-
snapshotPath
|
|
15
|
-
|
|
16
|
+
snapshotPath,
|
|
17
|
+
writeLinkedLines
|
|
18
|
+
} from "./chunk-BCBGMRHQ.js";
|
|
16
19
|
|
|
17
20
|
// src/app.tsx
|
|
18
21
|
import { Box as Box12, Text as Text12, useApp, useInput as useInput10 } from "ink";
|
|
@@ -317,14 +320,15 @@ var NAMED_COLORS = [
|
|
|
317
320
|
];
|
|
318
321
|
|
|
319
322
|
// src/screens/items.tsx
|
|
320
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
321
|
-
var SURFACES =
|
|
323
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
324
|
+
var SURFACES = LINKABLE;
|
|
322
325
|
var FIELDS2 = ["fg", "bg", "raw", "merge", "align"];
|
|
323
326
|
var ALIGNS = ["left", "center", "right"];
|
|
324
327
|
var FG = NAMED_COLORS.filter((c) => !c.startsWith("bg"));
|
|
325
328
|
var BG = ["(none)", ...NAMED_COLORS.filter((c) => c.startsWith("bg"))];
|
|
326
329
|
var WIDGETS = Object.values(registry);
|
|
327
330
|
var wrap = (i, n) => (i + n) % n;
|
|
331
|
+
var makeId = (type) => `${type}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
328
332
|
var isStylable = (item) => item.type !== "flex-separator";
|
|
329
333
|
function Chip({ item, selected }) {
|
|
330
334
|
const fg = isStylable(item) ? item.fg : void 0;
|
|
@@ -349,16 +353,16 @@ function Items({ config, setConfig, goHome }) {
|
|
|
349
353
|
const [surface, setSurface] = useState3("band");
|
|
350
354
|
const [sel, setSel] = useState3(0);
|
|
351
355
|
const [mode, setMode] = useState3("strip");
|
|
356
|
+
const [linkPick, setLinkPick] = useState3(0);
|
|
357
|
+
const [confirm, setConfirm] = useState3(null);
|
|
352
358
|
const [field, setField] = useState3(0);
|
|
353
359
|
const [pick, setPick] = useState3(0);
|
|
354
360
|
const items = config.surfaces[surface].lines[0] ?? [];
|
|
355
361
|
const cur = items[Math.min(sel, items.length - 1)];
|
|
356
362
|
const idx = cur ? items.indexOf(cur) : -1;
|
|
357
363
|
const commit = (next) => {
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
const c = { ...config, surfaces: { ...config.surfaces, [surface]: { ...s, lines } } };
|
|
361
|
-
setConfig(c);
|
|
364
|
+
const lines = [next, ...config.surfaces[surface].lines.slice(1)];
|
|
365
|
+
setConfig({ ...config, surfaces: writeLinkedLines(config.surfaces, surface, lines) });
|
|
362
366
|
};
|
|
363
367
|
const patch = (p) => {
|
|
364
368
|
const base = items[idx];
|
|
@@ -410,6 +414,45 @@ function Items({ config, setConfig, goHome }) {
|
|
|
410
414
|
commit(next);
|
|
411
415
|
setSel(j);
|
|
412
416
|
};
|
|
417
|
+
const others = SURFACES.filter((s) => s !== surface);
|
|
418
|
+
const linkOptions = [
|
|
419
|
+
...others.map((s) => ({ label: s, targets: [s] })),
|
|
420
|
+
{ label: "all others", targets: others }
|
|
421
|
+
];
|
|
422
|
+
const linkReplacements = (targets) => SURFACES.filter((s) => s !== surface && (targets.includes(s) || config.surfaces[s].linked));
|
|
423
|
+
const applyLink = (targets) => {
|
|
424
|
+
const marked = { ...config.surfaces };
|
|
425
|
+
marked[surface] = { ...config.surfaces[surface], linked: true };
|
|
426
|
+
for (const t of targets) {
|
|
427
|
+
marked[t] = { ...config.surfaces[t], linked: true };
|
|
428
|
+
}
|
|
429
|
+
const surfaces = writeLinkedLines(marked, surface, config.surfaces[surface].lines);
|
|
430
|
+
setConfig({ ...config, surfaces });
|
|
431
|
+
};
|
|
432
|
+
const applyUnlink = () => {
|
|
433
|
+
const layout = config.surfaces[surface];
|
|
434
|
+
if (!layout.linked) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const surfaces = {
|
|
438
|
+
...config.surfaces,
|
|
439
|
+
[surface]: {
|
|
440
|
+
...layout,
|
|
441
|
+
linked: false,
|
|
442
|
+
lines: layout.lines.map(
|
|
443
|
+
(line) => line.map((it) => ({ ...it, id: makeId(it.type) }))
|
|
444
|
+
)
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
const remaining = linkedSurfaces(surfaces);
|
|
448
|
+
if (remaining.length === 1) {
|
|
449
|
+
const lone = remaining[0];
|
|
450
|
+
if (lone) {
|
|
451
|
+
surfaces[lone] = { ...surfaces[lone], linked: false };
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
setConfig({ ...config, surfaces });
|
|
455
|
+
};
|
|
413
456
|
useInput3((input, key) => {
|
|
414
457
|
if (mode === "picker") {
|
|
415
458
|
if (key.escape) {
|
|
@@ -422,7 +465,7 @@ function Items({ config, setConfig, goHome }) {
|
|
|
422
465
|
const picked = WIDGETS[pick];
|
|
423
466
|
if (picked) {
|
|
424
467
|
const type = picked.type;
|
|
425
|
-
const id =
|
|
468
|
+
const id = makeId(type);
|
|
426
469
|
const newItem = type === "custom-text" ? { id, type, text: "" } : type === "custom-command" ? { id, type, command: "" } : type === "flex-separator" ? { id, type } : { id, type };
|
|
427
470
|
commit([...items, newItem]);
|
|
428
471
|
setSel(items.length);
|
|
@@ -441,6 +484,35 @@ function Items({ config, setConfig, goHome }) {
|
|
|
441
484
|
} else if (key.rightArrow) {
|
|
442
485
|
change(1);
|
|
443
486
|
}
|
|
487
|
+
} else if (mode === "link") {
|
|
488
|
+
if (confirm) {
|
|
489
|
+
if (input === "y") {
|
|
490
|
+
applyLink(confirm);
|
|
491
|
+
setConfirm(null);
|
|
492
|
+
setMode("strip");
|
|
493
|
+
} else if (input === "n" || key.escape) {
|
|
494
|
+
setConfirm(null);
|
|
495
|
+
setMode("strip");
|
|
496
|
+
}
|
|
497
|
+
} else if (key.escape) {
|
|
498
|
+
setMode("strip");
|
|
499
|
+
} else if (key.upArrow) {
|
|
500
|
+
setLinkPick((p) => wrap(p - 1 + linkOptions.length, linkOptions.length));
|
|
501
|
+
} else if (key.downArrow) {
|
|
502
|
+
setLinkPick((p) => wrap(p + 1, linkOptions.length));
|
|
503
|
+
} else if (key.return) {
|
|
504
|
+
const chosen = linkOptions[linkPick];
|
|
505
|
+
if (chosen) {
|
|
506
|
+
const affected = linkReplacements(chosen.targets);
|
|
507
|
+
const nonEmpty = affected.some((t) => config.surfaces[t].lines.some((l) => l.length > 0));
|
|
508
|
+
if (nonEmpty) {
|
|
509
|
+
setConfirm(affected);
|
|
510
|
+
} else {
|
|
511
|
+
applyLink(chosen.targets);
|
|
512
|
+
setMode("strip");
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
444
516
|
} else {
|
|
445
517
|
if (key.escape) {
|
|
446
518
|
goHome();
|
|
@@ -464,6 +536,12 @@ function Items({ config, setConfig, goHome }) {
|
|
|
464
536
|
} else if (input === "e" && idx >= 0) {
|
|
465
537
|
setField(0);
|
|
466
538
|
setMode("editor");
|
|
539
|
+
} else if (input === "l") {
|
|
540
|
+
setLinkPick(0);
|
|
541
|
+
setConfirm(null);
|
|
542
|
+
setMode("link");
|
|
543
|
+
} else if (input === "u") {
|
|
544
|
+
applyUnlink();
|
|
467
545
|
}
|
|
468
546
|
}
|
|
469
547
|
});
|
|
@@ -482,8 +560,35 @@ function Items({ config, setConfig, goHome }) {
|
|
|
482
560
|
s === surface ? `[${s}]` : s,
|
|
483
561
|
" "
|
|
484
562
|
] }, s)) }),
|
|
485
|
-
|
|
486
|
-
|
|
563
|
+
config.surfaces[surface].linked && /* @__PURE__ */ jsxs4(Text5, { color: "magenta", children: [
|
|
564
|
+
"\u{1F517} linked: ",
|
|
565
|
+
SURFACES.filter((s) => config.surfaces[s].linked).join(", "),
|
|
566
|
+
" \u2014 edits apply to all"
|
|
567
|
+
] }),
|
|
568
|
+
/* @__PURE__ */ jsx4(Box5, { children: items.length === 0 ? /* @__PURE__ */ jsx4(Text5, { dimColor: true, children: "(no items \u2014 press a)" }) : (
|
|
569
|
+
// Item ids are unique within a surface. Linked surfaces share ids across
|
|
570
|
+
// surfaces (DEC-0018), but only one surface's items render here at a time,
|
|
571
|
+
// so these keys never collide. (The live Preview renders a RenderModel of
|
|
572
|
+
// positional segments — paint.tsx keys by index, not item id.)
|
|
573
|
+
items.map((it, i) => /* @__PURE__ */ jsx4(Chip, { item: it, selected: i === idx }, it.id))
|
|
574
|
+
) }),
|
|
575
|
+
mode === "link" ? /* @__PURE__ */ jsx4(Box5, { flexDirection: "column", marginTop: 1, children: confirm ? /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
576
|
+
"Replace ",
|
|
577
|
+
confirm.join(", "),
|
|
578
|
+
" layout with ",
|
|
579
|
+
surface,
|
|
580
|
+
"'s? (y/n)"
|
|
581
|
+
] }) : /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
582
|
+
/* @__PURE__ */ jsxs4(Text5, { bold: true, children: [
|
|
583
|
+
"Link ",
|
|
584
|
+
surface,
|
|
585
|
+
" layout to:"
|
|
586
|
+
] }),
|
|
587
|
+
linkOptions.map((o, i) => /* @__PURE__ */ jsxs4(Text5, { color: i === linkPick ? "cyan" : void 0, children: [
|
|
588
|
+
i === linkPick ? "\u25B8 " : " ",
|
|
589
|
+
o.label
|
|
590
|
+
] }, o.label))
|
|
591
|
+
] }) }) : mode === "picker" ? /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
487
592
|
/* @__PURE__ */ jsx4(Text5, { bold: true, children: "Add widget" }),
|
|
488
593
|
WIDGETS.map((w, i) => /* @__PURE__ */ jsxs4(Text5, { color: i === pick ? "cyan" : void 0, children: [
|
|
489
594
|
i === pick ? "\u25B8 " : " ",
|
|
@@ -508,7 +613,7 @@ function Items({ config, setConfig, goHome }) {
|
|
|
508
613
|
] }),
|
|
509
614
|
/* @__PURE__ */ jsx4(Text5, { dimColor: true, children: "(flex separator \u2014 no style options)" })
|
|
510
615
|
] })),
|
|
511
|
-
/* @__PURE__ */ jsx4(Text5, { dimColor: true, children: mode === "strip" ? "\u2190/\u2192 select \xB7 [/] move \xB7 a add \xB7 x remove \xB7 e edit \xB7 tab surface \xB7 esc back" : mode === "editor" ? "\u2191/\u2193 field \xB7 \u2190/\u2192 change \xB7 esc done" : "\u2191/\u2193 choose \xB7 enter add \xB7 esc cancel" })
|
|
616
|
+
/* @__PURE__ */ jsx4(Text5, { dimColor: true, children: mode === "strip" ? "\u2190/\u2192 select \xB7 [/] move \xB7 a add \xB7 x remove \xB7 e edit \xB7 l link \xB7 u unlink \xB7 tab surface \xB7 esc back" : mode === "editor" ? "\u2191/\u2193 field \xB7 \u2190/\u2192 change \xB7 esc done" : mode === "link" ? confirm ? "y confirm \xB7 n cancel" : "\u2191/\u2193 choose \xB7 enter link \xB7 esc cancel" : "\u2191/\u2193 choose \xB7 enter add \xB7 esc cancel" })
|
|
512
617
|
] });
|
|
513
618
|
}
|
|
514
619
|
|
|
@@ -655,6 +655,53 @@ var defaultConfig = {
|
|
|
655
655
|
}
|
|
656
656
|
};
|
|
657
657
|
|
|
658
|
+
// ../core/src/config/links.ts
|
|
659
|
+
var LINKABLE = ["band", "statusline", "pane"];
|
|
660
|
+
var clone = (v) => JSON.parse(JSON.stringify(v));
|
|
661
|
+
function linkedSurfaces(surfaces) {
|
|
662
|
+
return LINKABLE.filter((name) => surfaces[name].linked);
|
|
663
|
+
}
|
|
664
|
+
function writeLinkedLines(surfaces, surface, lines) {
|
|
665
|
+
const next = { ...surfaces };
|
|
666
|
+
next[surface] = { ...surfaces[surface], lines: clone(lines) };
|
|
667
|
+
if (surfaces[surface].linked) {
|
|
668
|
+
for (const member of LINKABLE) {
|
|
669
|
+
if (member !== surface && surfaces[member].linked) {
|
|
670
|
+
next[member] = { ...surfaces[member], lines: clone(lines) };
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return next;
|
|
675
|
+
}
|
|
676
|
+
function normalizeLinks(surfaces, warn) {
|
|
677
|
+
const linked = linkedSurfaces(surfaces);
|
|
678
|
+
if (linked.length < 2) {
|
|
679
|
+
for (const name of linked) {
|
|
680
|
+
delete surfaces[name].linked;
|
|
681
|
+
warn(`dropped lone surface link on "${name}"`);
|
|
682
|
+
}
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const canonical = linked[0];
|
|
686
|
+
if (!canonical) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
const source = JSON.stringify(surfaces[canonical].lines);
|
|
690
|
+
let diverged = false;
|
|
691
|
+
for (const name of linked) {
|
|
692
|
+
if (name === canonical) {
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
if (JSON.stringify(surfaces[name].lines) !== source) {
|
|
696
|
+
surfaces[name].lines = clone(surfaces[canonical].lines);
|
|
697
|
+
diverged = true;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
if (diverged) {
|
|
701
|
+
warn(`linked surfaces diverged; synced to "${canonical}"`);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
658
705
|
// ../../node_modules/zod/v3/external.js
|
|
659
706
|
var external_exports = {};
|
|
660
707
|
__export(external_exports, {
|
|
@@ -4713,7 +4760,8 @@ var itemSchema = external_exports.object({
|
|
|
4713
4760
|
});
|
|
4714
4761
|
var surfaceLayoutSchema = external_exports.object({
|
|
4715
4762
|
enabled: external_exports.boolean(),
|
|
4716
|
-
lines: external_exports.array(external_exports.array(itemSchema))
|
|
4763
|
+
lines: external_exports.array(external_exports.array(itemSchema)),
|
|
4764
|
+
linked: external_exports.boolean().optional()
|
|
4717
4765
|
});
|
|
4718
4766
|
var toastRuleSchema = external_exports.object({
|
|
4719
4767
|
when: external_exports.string(),
|
|
@@ -4780,7 +4828,7 @@ var WIDGET_TYPES = [
|
|
|
4780
4828
|
];
|
|
4781
4829
|
|
|
4782
4830
|
// ../core/src/config/validate.ts
|
|
4783
|
-
var
|
|
4831
|
+
var clone2 = (v) => JSON.parse(JSON.stringify(v));
|
|
4784
4832
|
var WIDGET_TYPE_SET = new Set(WIDGET_TYPES);
|
|
4785
4833
|
function cleanStyle(raw, type, warn) {
|
|
4786
4834
|
const style = {};
|
|
@@ -4856,7 +4904,7 @@ function cleanThemes(themes, warn) {
|
|
|
4856
4904
|
}
|
|
4857
4905
|
function cleanToasts(raw, warn) {
|
|
4858
4906
|
if (!raw) {
|
|
4859
|
-
return
|
|
4907
|
+
return clone2(defaultConfig.surfaces.toasts);
|
|
4860
4908
|
}
|
|
4861
4909
|
const rules = raw.rules.filter((r) => {
|
|
4862
4910
|
if (isValidWhen(r.when)) {
|
|
@@ -4881,22 +4929,26 @@ function loadConfig(raw) {
|
|
|
4881
4929
|
if (raw !== void 0) {
|
|
4882
4930
|
warn(`config invalid (${parsed.error.issues[0]?.message ?? "unknown"}); using defaults`);
|
|
4883
4931
|
}
|
|
4884
|
-
return { config:
|
|
4932
|
+
return { config: clone2(defaultConfig), warnings };
|
|
4885
4933
|
}
|
|
4886
4934
|
const p = parsed.data;
|
|
4887
4935
|
const surf = (name) => {
|
|
4888
4936
|
const s = p.surfaces[name];
|
|
4889
4937
|
if (!s) {
|
|
4890
|
-
return
|
|
4938
|
+
return clone2(defaultConfig.surfaces[name]);
|
|
4891
4939
|
}
|
|
4892
|
-
|
|
4940
|
+
const layout = {
|
|
4893
4941
|
enabled: s.enabled,
|
|
4894
4942
|
lines: s.lines.map(
|
|
4895
4943
|
(line) => line.map((it) => cleanItem(it, warn)).filter((x) => x !== null)
|
|
4896
4944
|
)
|
|
4897
4945
|
};
|
|
4946
|
+
if (s.linked) {
|
|
4947
|
+
layout.linked = true;
|
|
4948
|
+
}
|
|
4949
|
+
return layout;
|
|
4898
4950
|
};
|
|
4899
|
-
const themesToUse = Object.keys(p.themes).length ? p.themes :
|
|
4951
|
+
const themesToUse = Object.keys(p.themes).length ? p.themes : clone2(defaultConfig.themes);
|
|
4900
4952
|
const config = {
|
|
4901
4953
|
version: 1,
|
|
4902
4954
|
theme: p.theme,
|
|
@@ -4909,11 +4961,12 @@ function loadConfig(raw) {
|
|
|
4909
4961
|
toasts: cleanToasts(p.surfaces.toasts, warn)
|
|
4910
4962
|
}
|
|
4911
4963
|
};
|
|
4964
|
+
normalizeLinks(config.surfaces, warn);
|
|
4912
4965
|
return { config, warnings };
|
|
4913
4966
|
}
|
|
4914
4967
|
|
|
4915
4968
|
// ../core/src/config/import-ccstatusline.ts
|
|
4916
|
-
var
|
|
4969
|
+
var clone3 = (v) => JSON.parse(JSON.stringify(v));
|
|
4917
4970
|
var TYPE_MAP = {
|
|
4918
4971
|
model: "model",
|
|
4919
4972
|
version: "version",
|
|
@@ -5013,7 +5066,7 @@ function importCcstatusline(raw) {
|
|
|
5013
5066
|
const warnings = [];
|
|
5014
5067
|
if (!raw || typeof raw !== "object" || !Array.isArray(raw.lines)) {
|
|
5015
5068
|
warnings.push("input is not a ccstatusline config; using defaults");
|
|
5016
|
-
return { config:
|
|
5069
|
+
return { config: clone3(defaultConfig), warnings };
|
|
5017
5070
|
}
|
|
5018
5071
|
const lines = raw.lines.map(
|
|
5019
5072
|
(line) => (Array.isArray(line) ? line : []).flatMap((item) => {
|
|
@@ -5252,6 +5305,9 @@ export {
|
|
|
5252
5305
|
toAnsi,
|
|
5253
5306
|
COLORS,
|
|
5254
5307
|
isValidWhen,
|
|
5308
|
+
LINKABLE,
|
|
5309
|
+
linkedSurfaces,
|
|
5310
|
+
writeLinkedLines,
|
|
5255
5311
|
importCcstatusline,
|
|
5256
5312
|
rendererColor,
|
|
5257
5313
|
rendererBg,
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
var sub = process.argv[2];
|
|
6
6
|
if (sub === "statusline") {
|
|
7
|
-
const { runStatusline } = await import("./statusline-cmd-
|
|
7
|
+
const { runStatusline } = await import("./statusline-cmd-2YHMLVSM.js");
|
|
8
8
|
await runStatusline();
|
|
9
9
|
} else {
|
|
10
10
|
const { render } = await import("ink");
|
|
11
|
-
const { App } = await import("./app-
|
|
11
|
+
const { App } = await import("./app-WR7CHOQI.js");
|
|
12
12
|
render(/* @__PURE__ */ jsx(App, {}));
|
|
13
13
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sushant-kum/ccstatus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Interactive configurator (npx @sushant-kum/ccstatus) for the ccstatus Claude Code status bar — band, status line, pane, and threshold toasts from one config.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sushant Kumar",
|