@hartvig/developer-control-center 0.8.6 → 0.8.7

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 (97) hide show
  1. package/.developer-control-center/metrics.json +1 -1
  2. package/.developer-control-center/status.json +1 -1
  3. package/.developer-control-center/timings.jsonl +15 -0
  4. package/.github/workflows/ci.yml +1 -7
  5. package/coverage/Developer Control Center/dcc.config.js.html +628 -0
  6. package/coverage/Developer Control Center/index.html +116 -0
  7. package/coverage/Developer Control Center/src/config/index.html +116 -0
  8. package/coverage/Developer Control Center/src/config/loader.ts.html +454 -0
  9. package/coverage/Developer Control Center/src/core/ci.ts.html +163 -0
  10. package/coverage/Developer Control Center/src/core/event-bus.ts.html +187 -0
  11. package/coverage/Developer Control Center/src/core/index.html +191 -0
  12. package/coverage/Developer Control Center/src/core/notifier.ts.html +187 -0
  13. package/coverage/Developer Control Center/src/core/persistence.ts.html +88 -0
  14. package/coverage/Developer Control Center/src/core/task-runner.ts.html +1498 -0
  15. package/coverage/Developer Control Center/src/core/workspaces.ts.html +304 -0
  16. package/coverage/Developer Control Center/src/plugins/index.html +116 -0
  17. package/coverage/Developer Control Center/src/plugins/manager.ts.html +259 -0
  18. package/coverage/Developer Control Center/src/status/index.html +116 -0
  19. package/coverage/Developer Control Center/src/status/store.ts.html +349 -0
  20. package/coverage/Developer Control Center/src/ui/command-list.tsx.html +574 -0
  21. package/coverage/Developer Control Center/src/ui/index.html +161 -0
  22. package/coverage/Developer Control Center/src/ui/metrics-panel.tsx.html +787 -0
  23. package/coverage/Developer Control Center/src/ui/panel.tsx.html +313 -0
  24. package/coverage/Developer Control Center/src/ui/status-panel.tsx.html +565 -0
  25. package/coverage/base.css +224 -0
  26. package/coverage/block-navigation.js +87 -0
  27. package/coverage/clover.xml +588 -0
  28. package/coverage/coverage-final.json +15 -0
  29. package/coverage/favicon.png +0 -0
  30. package/coverage/index.html +191 -0
  31. package/coverage/prettify.css +1 -0
  32. package/coverage/prettify.js +2 -0
  33. package/coverage/sort-arrow-sprite.png +0 -0
  34. package/coverage/sorter.js +210 -0
  35. package/dcc.config.js +2 -2
  36. package/dist/cli.js +0 -0
  37. package/dist/core/persistence.d.ts +2 -0
  38. package/dist/core/persistence.d.ts.map +1 -0
  39. package/dist/core/persistence.js +2 -0
  40. package/dist/core/persistence.js.map +1 -0
  41. package/dist/core/runtime.d.ts.map +1 -1
  42. package/dist/core/runtime.js +5 -2
  43. package/dist/core/runtime.js.map +1 -1
  44. package/dist/core/task-runner.d.ts +1 -0
  45. package/dist/core/task-runner.d.ts.map +1 -1
  46. package/dist/core/task-runner.js +24 -4
  47. package/dist/core/task-runner.js.map +1 -1
  48. package/dist/core/task-runner.test.d.ts +2 -0
  49. package/dist/core/task-runner.test.d.ts.map +1 -0
  50. package/dist/core/task-runner.test.js +326 -0
  51. package/dist/core/task-runner.test.js.map +1 -0
  52. package/dist/core/timer-plugin.d.ts.map +1 -1
  53. package/dist/core/timer-plugin.js +2 -1
  54. package/dist/core/timer-plugin.js.map +1 -1
  55. package/dist/plugins/manager.d.ts +2 -0
  56. package/dist/plugins/manager.d.ts.map +1 -1
  57. package/dist/plugins/manager.js +6 -2
  58. package/dist/plugins/manager.js.map +1 -1
  59. package/dist/plugins/manager.test.js +5 -2
  60. package/dist/plugins/manager.test.js.map +1 -1
  61. package/dist/ui/app.d.ts.map +1 -1
  62. package/dist/ui/app.js +97 -16
  63. package/dist/ui/app.js.map +1 -1
  64. package/dist/ui/command-list.test.d.ts +2 -0
  65. package/dist/ui/command-list.test.d.ts.map +1 -0
  66. package/dist/ui/command-list.test.js +104 -0
  67. package/dist/ui/command-list.test.js.map +1 -0
  68. package/dist/ui/metrics-panel.d.ts.map +1 -1
  69. package/dist/ui/metrics-panel.js +10 -9
  70. package/dist/ui/metrics-panel.js.map +1 -1
  71. package/dist/ui/metrics-panel.test.d.ts +2 -0
  72. package/dist/ui/metrics-panel.test.d.ts.map +1 -0
  73. package/dist/ui/metrics-panel.test.js +111 -0
  74. package/dist/ui/metrics-panel.test.js.map +1 -0
  75. package/dist/ui/panel.test.d.ts +2 -0
  76. package/dist/ui/panel.test.d.ts.map +1 -0
  77. package/dist/ui/panel.test.js +51 -0
  78. package/dist/ui/panel.test.js.map +1 -0
  79. package/dist/ui/status-panel.test.d.ts +2 -0
  80. package/dist/ui/status-panel.test.d.ts.map +1 -0
  81. package/dist/ui/status-panel.test.js +88 -0
  82. package/dist/ui/status-panel.test.js.map +1 -0
  83. package/package.json +3 -1
  84. package/src/core/persistence.ts +1 -0
  85. package/src/core/runtime.ts +7 -2
  86. package/src/core/task-runner.test.ts +395 -0
  87. package/src/core/task-runner.ts +26 -5
  88. package/src/core/timer-plugin.ts +2 -1
  89. package/src/plugins/manager.test.ts +5 -2
  90. package/src/plugins/manager.ts +6 -2
  91. package/src/ui/app.tsx +139 -27
  92. package/src/ui/command-list.test.tsx +124 -0
  93. package/src/ui/metrics-panel.test.tsx +128 -0
  94. package/src/ui/metrics-panel.tsx +10 -10
  95. package/src/ui/panel.test.tsx +84 -0
  96. package/src/ui/status-panel.test.tsx +116 -0
  97. package/vitest.config.ts +1 -1
@@ -0,0 +1,111 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import { act } from 'react';
4
+ import { render } from 'ink-testing-library';
5
+ import fs from 'fs';
6
+ import { MetricsPanel } from './metrics-panel.js';
7
+ function makeMetricsData(overrides = {}) {
8
+ return JSON.stringify({
9
+ version: '1.0.0',
10
+ latestTest: { label: 'Unit Tests', status: 'success', time: Date.now() - 60000 },
11
+ latestBuild: { status: 'failure', time: Date.now() - 120000 },
12
+ ...overrides,
13
+ });
14
+ }
15
+ vi.mock('fs', () => ({
16
+ default: {
17
+ readFileSync: vi.fn(() => makeMetricsData()),
18
+ writeFileSync: vi.fn(),
19
+ mkdirSync: vi.fn(),
20
+ existsSync: vi.fn(),
21
+ },
22
+ readFileSync: vi.fn(() => makeMetricsData()),
23
+ writeFileSync: vi.fn(),
24
+ mkdirSync: vi.fn(),
25
+ existsSync: vi.fn(),
26
+ }));
27
+ const mockReadFileSync = () => vi.mocked(fs).readFileSync;
28
+ const mockTasks = (entries) => new Map(Object.entries(entries));
29
+ describe('MetricsPanel', () => {
30
+ const baseProps = {
31
+ tasks: new Map(),
32
+ width: 28,
33
+ menuRows: 10,
34
+ };
35
+ beforeEach(() => {
36
+ mockReadFileSync().mockReturnValue(makeMetricsData());
37
+ });
38
+ it('shows idle status when no tasks are running', () => {
39
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
40
+ expect(lastFrame()).toContain('idle');
41
+ });
42
+ it('displays the package version', () => {
43
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
44
+ expect(lastFrame()).toContain('Version: 1.0.0');
45
+ });
46
+ it('shows active task count for running tasks', async () => {
47
+ const tasks = mockTasks({
48
+ build: { id: 'build', label: 'Build', status: 'running', startTime: Date.now() },
49
+ test: { id: 'test', label: 'Test', status: 'running', startTime: Date.now() },
50
+ });
51
+ const { lastFrame, rerender } = render(_jsx(MetricsPanel, { ...baseProps }));
52
+ await act(async () => {
53
+ rerender(_jsx(MetricsPanel, { ...baseProps, tasks: tasks }));
54
+ });
55
+ const frame = lastFrame();
56
+ expect(frame).toContain('Active: 2');
57
+ expect(frame).toContain('running');
58
+ });
59
+ it('shows test passed status with time ago', () => {
60
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
61
+ const frame = lastFrame();
62
+ expect(frame).toContain('Tests: passed');
63
+ expect(frame).toContain('1m ago');
64
+ });
65
+ it('shows test failure status', () => {
66
+ mockReadFileSync().mockReturnValue(makeMetricsData({
67
+ latestTest: { label: 'Tests', status: 'failure', time: Date.now() - 30000 },
68
+ }));
69
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
70
+ expect(lastFrame()).toContain('Tests: failed');
71
+ });
72
+ it('shows no test run when no test data', () => {
73
+ mockReadFileSync().mockReturnValue(makeMetricsData({ latestTest: undefined }));
74
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
75
+ expect(lastFrame()).toContain('Tests: no run');
76
+ });
77
+ it('shows build failed status', () => {
78
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
79
+ expect(lastFrame()).toContain('Build: failed');
80
+ });
81
+ it('shows build passed status', () => {
82
+ mockReadFileSync().mockReturnValue(makeMetricsData({
83
+ latestBuild: { status: 'success', time: Date.now() - 300000 },
84
+ }));
85
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
86
+ expect(lastFrame()).toContain('Build: passed');
87
+ });
88
+ it('shows no build run when no build data', () => {
89
+ mockReadFileSync().mockReturnValue(makeMetricsData({ latestBuild: undefined }));
90
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
91
+ expect(lastFrame()).toContain('Build: no run');
92
+ });
93
+ it('shows last git push timestamp', () => {
94
+ const pushTime = new Date('2026-06-24T10:00:00').getTime();
95
+ mockReadFileSync().mockReturnValue(makeMetricsData({
96
+ lastGitPush: { label: 'main', time: pushTime },
97
+ }));
98
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
99
+ expect(lastFrame()).toContain('2026-06-24 10:00');
100
+ });
101
+ it('shows push dash when no push data', () => {
102
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
103
+ expect(lastFrame()).toContain('Push: -');
104
+ });
105
+ it('shows version dash when package.json is missing', () => {
106
+ mockReadFileSync().mockImplementation(() => { throw new Error('ENOENT'); });
107
+ const { lastFrame } = render(_jsx(MetricsPanel, { ...baseProps }));
108
+ expect(lastFrame()).toContain('Version: -');
109
+ });
110
+ });
111
+ //# sourceMappingURL=metrics-panel.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics-panel.test.js","sourceRoot":"","sources":["../../src/ui/metrics-panel.test.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAc,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,SAAS,eAAe,CAAC,YAAiC,EAAE;IAC1D,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE;QAChF,WAAW,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE;QAC7D,GAAG,SAAS;KACb,CAAC,CAAC;AACL,CAAC;AAED,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnB,OAAO,EAAE;QACP,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC;QAC5C,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE;QACtB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;QAClB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;KACpB;IACD,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC;IAC5C,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE;IACtB,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE;IAClB,UAAU,EAAE,EAAE,CAAC,EAAE,EAAE;CACpB,CAAC,CAAC,CAAC;AAEJ,MAAM,gBAAgB,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC;AAE1D,MAAM,SAAS,GAAG,CAAC,OAA4B,EAAoB,EAAE,CACnE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAqB,CAAC;AAEvD,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,MAAM,SAAS,GAAG;QAChB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,EAAE;KACb,CAAC;IAEF,UAAU,CAAC,GAAG,EAAE;QACd,gBAAgB,EAAE,CAAC,eAAe,CAAC,eAAe,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,KAAK,GAAG,SAAS,CAAC;YACtB,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;YAChF,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE;SAC9E,CAAC,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QACxE,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACnB,QAAQ,CAAC,KAAC,YAAY,OAAK,SAAS,EAAE,KAAK,EAAE,KAAK,GAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,gBAAgB,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC;YACjD,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE;SAC5E,CAAC,CAAC,CAAC;QACJ,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,gBAAgB,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAC/E,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,gBAAgB,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC;YACjD,WAAW,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE;SAC9D,CAAC,CAAC,CAAC;QACJ,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,gBAAgB,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAChF,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,qBAAqB,CAAC,CAAC,OAAO,EAAE,CAAC;QAC3D,gBAAgB,EAAE,CAAC,eAAe,CAAC,eAAe,CAAC;YACjD,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC/C,CAAC,CAAC,CAAC;QACJ,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,gBAAgB,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,KAAC,YAAY,OAAK,SAAS,GAAI,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=panel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel.test.d.ts","sourceRoot":"","sources":["../../src/ui/panel.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect } from 'vitest';
3
+ import React from 'react';
4
+ import { Box, Text } from 'ink';
5
+ import { render } from 'ink-testing-library';
6
+ import { Panel } from './panel.js';
7
+ describe('Panel', () => {
8
+ it('renders the title in the top border', () => {
9
+ const { lastFrame } = render(_jsx(Panel, { title: "Test", width: 20, height: 5, children: _jsx(React.Fragment, {}) }));
10
+ const frame = lastFrame();
11
+ expect(frame).toContain('╭─ Test');
12
+ });
13
+ it('renders proper bottom border', () => {
14
+ const { lastFrame } = render(_jsx(Panel, { title: "Test", width: 20, height: 5, children: _jsx(React.Fragment, {}) }));
15
+ const frame = lastFrame();
16
+ expect(frame).toContain('╰');
17
+ });
18
+ it('renders side borders for each content row', () => {
19
+ const { lastFrame } = render(_jsx(Panel, { title: "Test", width: 20, height: 5, children: _jsx(React.Fragment, {}) }));
20
+ const frame = lastFrame();
21
+ const lines = frame.split('\n');
22
+ expect(lines.length).toBe(5);
23
+ expect(lines[1].startsWith('│')).toBe(true);
24
+ expect(lines[1].endsWith('│')).toBe(true);
25
+ expect(lines[2].startsWith('│')).toBe(true);
26
+ expect(lines[2].endsWith('│')).toBe(true);
27
+ expect(lines[3].startsWith('│')).toBe(true);
28
+ expect(lines[3].endsWith('│')).toBe(true);
29
+ });
30
+ it('renders children in the content area', () => {
31
+ const { lastFrame } = render(_jsx(Panel, { title: "Test", width: 20, height: 5, children: _jsx(Box, { children: _jsx(Text, { children: "hello" }) }) }));
32
+ const frame = lastFrame();
33
+ expect(frame).toContain('hello');
34
+ });
35
+ it('shows "↑N more" when hiddenAbove is set', () => {
36
+ const { lastFrame } = render(_jsx(Panel, { title: "Test", width: 30, height: 5, hiddenAbove: 3, children: _jsx(React.Fragment, {}) }));
37
+ const frame = lastFrame();
38
+ expect(frame).toContain('↑3 more');
39
+ });
40
+ it('shows "↓N more" when hiddenBelow is set', () => {
41
+ const { lastFrame } = render(_jsx(Panel, { title: "Test", width: 30, height: 5, hiddenBelow: 2, children: _jsx(React.Fragment, {}) }));
42
+ const frame = lastFrame();
43
+ expect(frame).toContain('↓2 more');
44
+ });
45
+ it('renders titleExtra next to the title', () => {
46
+ const { lastFrame } = render(_jsx(Panel, { title: "Main", width: 30, height: 5, titleExtra: _jsx(Text, { children: " [extra]" }), children: _jsx(React.Fragment, {}) }));
47
+ const frame = lastFrame();
48
+ expect(frame).toContain('[extra]');
49
+ });
50
+ });
51
+ //# sourceMappingURL=panel.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel.test.js","sourceRoot":"","sources":["../../src/ui/panel.test.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=status-panel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-panel.test.d.ts","sourceRoot":"","sources":["../../src/ui/status-panel.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect } from 'vitest';
3
+ import { render } from 'ink-testing-library';
4
+ import { StatusPanel } from './status-panel.js';
5
+ function makeTask(overrides = {}) {
6
+ return {
7
+ id: 'test',
8
+ label: 'Test Task',
9
+ status: 'running',
10
+ output: '',
11
+ startTime: Date.now(),
12
+ ...overrides,
13
+ };
14
+ }
15
+ describe('StatusPanel', () => {
16
+ const baseProps = {
17
+ tasks: new Map(),
18
+ scrollOffsets: new Map(),
19
+ focusedPane: 'commands',
20
+ width: 60,
21
+ menuRows: 10,
22
+ };
23
+ it('shows no tasks yet when empty', () => {
24
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps }));
25
+ expect(lastFrame()).toContain('No tasks yet');
26
+ });
27
+ it('displays the task label and status', () => {
28
+ const tasks = new Map([['test', makeTask({ label: 'My Task', status: 'running' })]]);
29
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, tasks: tasks }));
30
+ const frame = lastFrame();
31
+ expect(frame).toContain('My Task');
32
+ expect(frame).toContain('RUNNING');
33
+ });
34
+ it('shows success status with green icon', () => {
35
+ const tasks = new Map([['test', makeTask({ status: 'success' })]]);
36
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, tasks: tasks }));
37
+ expect(lastFrame()).toContain('PASS');
38
+ });
39
+ it('shows failure status', () => {
40
+ const tasks = new Map([['test', makeTask({ status: 'failure', exitCode: 1 })]]);
41
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, tasks: tasks }));
42
+ expect(lastFrame()).toContain('FAIL');
43
+ expect(lastFrame()).toContain('exit 1');
44
+ });
45
+ it('displays output lines', () => {
46
+ const tasks = new Map([['test', makeTask({ output: 'line1\nline2\nline3' })]]);
47
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, tasks: tasks }));
48
+ const frame = lastFrame();
49
+ expect(frame).toContain('line1');
50
+ expect(frame).toContain('line2');
51
+ expect(frame).toContain('line3');
52
+ });
53
+ it('shows confirm prompt when confirmingCommand is set', () => {
54
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, confirmingCommand: { id: 'deploy', label: 'Deploy', command: 'npm run deploy' } }));
55
+ const frame = lastFrame();
56
+ expect(frame).toContain('Run');
57
+ expect(frame).toContain('Deploy');
58
+ });
59
+ it('shows input prompt when inputCommand is set', () => {
60
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, inputCommand: { id: 'greet', label: 'Greet', command: 'echo', input: { message: 'Enter name:' } } }));
61
+ const frame = lastFrame();
62
+ expect(frame).toContain('Enter name:');
63
+ });
64
+ it('shows input value', () => {
65
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, inputCommand: { id: 'greet', label: 'Greet', command: 'echo', input: {} }, inputValue: "hello" }));
66
+ expect(lastFrame()).toContain('hello');
67
+ });
68
+ it('sanitizes ANSI escape codes from output', () => {
69
+ const tasks = new Map([['test', makeTask({ output: '\x1B[31mred\x1B[0m' })]]);
70
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, tasks: tasks }));
71
+ expect(lastFrame()).not.toContain('\x1B[');
72
+ expect(lastFrame()).toContain('red');
73
+ });
74
+ it('shows duration for completed tasks', () => {
75
+ const now = Date.now();
76
+ const tasks = new Map([
77
+ ['test', makeTask({ startTime: now - 5000, endTime: now, status: 'success' })],
78
+ ]);
79
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, tasks: tasks }));
80
+ expect(lastFrame()).toContain('5.0s');
81
+ });
82
+ it('shows watch mode indicator', () => {
83
+ const tasks = new Map([['test', makeTask({ watchMode: true, status: 'running' })]]);
84
+ const { lastFrame } = render(_jsx(StatusPanel, { ...baseProps, tasks: tasks }));
85
+ expect(lastFrame()).toContain('WATCH');
86
+ });
87
+ });
88
+ //# sourceMappingURL=status-panel.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-panel.test.js","sourceRoot":"","sources":["../../src/ui/status-panel.test.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hartvig/developer-control-center",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "bin": {
@@ -24,6 +24,8 @@
24
24
  "devDependencies": {
25
25
  "@types/node": "^25.0.0",
26
26
  "@types/react": "^19.0.0",
27
+ "@vitest/coverage-v8": "^4.1.9",
28
+ "ink-testing-library": "^4.0.0",
27
29
  "typescript": "^6.0.0",
28
30
  "vitest": "^4.1.7"
29
31
  }
@@ -0,0 +1 @@
1
+ export const PERSISTENCE_DIR = '.developer-control-center';
@@ -8,6 +8,7 @@ import { detectWorkspaces, WorkspacePackage } from './workspaces.js';
8
8
  import { sendNotification } from './notifier.js';
9
9
  import { detectCI, CIInfo } from './ci.js';
10
10
  import { timerPlugin } from './timer-plugin.js';
11
+ import { PERSISTENCE_DIR } from './persistence.js';
11
12
 
12
13
  function getGitBranch(): string | undefined {
13
14
  try {
@@ -25,12 +26,16 @@ export class Runtime {
25
26
  readonly eventBus = new EventBus();
26
27
  readonly statusStore = new StatusStore();
27
28
  readonly taskRunner: TaskRunner;
28
- readonly pluginManager = new PluginManager();
29
+ readonly pluginManager = new PluginManager(
30
+ (msg: string, err: unknown) => {
31
+ this.eventBus.emit('task:output' as any, '_plugins', `${msg}: ${err instanceof Error ? err.message : String(err)}\n`);
32
+ },
33
+ );
29
34
  readonly gitBranch: string | undefined;
30
35
  readonly workspaces: WorkspacePackage[];
31
36
  readonly ci: CIInfo;
32
37
 
33
- private persistenceDir = '.developer-control-center';
38
+ private persistenceDir = PERSISTENCE_DIR;
34
39
  private unsubPersistence?: () => void;
35
40
  private unsubNotifier?: () => void;
36
41