@hartvig/developer-control-center 0.8.5 → 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.
- package/.developer-control-center/metrics.json +1 -1
- package/.developer-control-center/status.json +1 -1
- package/.developer-control-center/timings.jsonl +24 -0
- package/.github/workflows/ci.yml +1 -7
- package/coverage/Developer Control Center/dcc.config.js.html +628 -0
- package/coverage/Developer Control Center/index.html +116 -0
- package/coverage/Developer Control Center/src/config/index.html +116 -0
- package/coverage/Developer Control Center/src/config/loader.ts.html +454 -0
- package/coverage/Developer Control Center/src/core/ci.ts.html +163 -0
- package/coverage/Developer Control Center/src/core/event-bus.ts.html +187 -0
- package/coverage/Developer Control Center/src/core/index.html +191 -0
- package/coverage/Developer Control Center/src/core/notifier.ts.html +187 -0
- package/coverage/Developer Control Center/src/core/persistence.ts.html +88 -0
- package/coverage/Developer Control Center/src/core/task-runner.ts.html +1498 -0
- package/coverage/Developer Control Center/src/core/workspaces.ts.html +304 -0
- package/coverage/Developer Control Center/src/plugins/index.html +116 -0
- package/coverage/Developer Control Center/src/plugins/manager.ts.html +259 -0
- package/coverage/Developer Control Center/src/status/index.html +116 -0
- package/coverage/Developer Control Center/src/status/store.ts.html +349 -0
- package/coverage/Developer Control Center/src/ui/command-list.tsx.html +574 -0
- package/coverage/Developer Control Center/src/ui/index.html +161 -0
- package/coverage/Developer Control Center/src/ui/metrics-panel.tsx.html +787 -0
- package/coverage/Developer Control Center/src/ui/panel.tsx.html +313 -0
- package/coverage/Developer Control Center/src/ui/status-panel.tsx.html +565 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +588 -0
- package/coverage/coverage-final.json +15 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +191 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dcc.config.js +8 -4
- package/dist/cli.js +0 -0
- package/dist/core/persistence.d.ts +2 -0
- package/dist/core/persistence.d.ts.map +1 -0
- package/dist/core/persistence.js +2 -0
- package/dist/core/persistence.js.map +1 -0
- package/dist/core/runtime.d.ts.map +1 -1
- package/dist/core/runtime.js +5 -2
- package/dist/core/runtime.js.map +1 -1
- package/dist/core/task-runner.d.ts +1 -0
- package/dist/core/task-runner.d.ts.map +1 -1
- package/dist/core/task-runner.js +24 -4
- package/dist/core/task-runner.js.map +1 -1
- package/dist/core/task-runner.test.d.ts +2 -0
- package/dist/core/task-runner.test.d.ts.map +1 -0
- package/dist/core/task-runner.test.js +326 -0
- package/dist/core/task-runner.test.js.map +1 -0
- package/dist/core/timer-plugin.d.ts.map +1 -1
- package/dist/core/timer-plugin.js +2 -1
- package/dist/core/timer-plugin.js.map +1 -1
- package/dist/plugins/manager.d.ts +2 -0
- package/dist/plugins/manager.d.ts.map +1 -1
- package/dist/plugins/manager.js +6 -2
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manager.test.js +5 -2
- package/dist/plugins/manager.test.js.map +1 -1
- package/dist/ui/app.d.ts.map +1 -1
- package/dist/ui/app.js +106 -19
- package/dist/ui/app.js.map +1 -1
- package/dist/ui/command-list.test.d.ts +2 -0
- package/dist/ui/command-list.test.d.ts.map +1 -0
- package/dist/ui/command-list.test.js +104 -0
- package/dist/ui/command-list.test.js.map +1 -0
- package/dist/ui/metrics-panel.d.ts.map +1 -1
- package/dist/ui/metrics-panel.js +10 -9
- package/dist/ui/metrics-panel.js.map +1 -1
- package/dist/ui/metrics-panel.test.d.ts +2 -0
- package/dist/ui/metrics-panel.test.d.ts.map +1 -0
- package/dist/ui/metrics-panel.test.js +111 -0
- package/dist/ui/metrics-panel.test.js.map +1 -0
- package/dist/ui/panel.test.d.ts +2 -0
- package/dist/ui/panel.test.d.ts.map +1 -0
- package/dist/ui/panel.test.js +51 -0
- package/dist/ui/panel.test.js.map +1 -0
- package/dist/ui/status-panel.test.d.ts +2 -0
- package/dist/ui/status-panel.test.d.ts.map +1 -0
- package/dist/ui/status-panel.test.js +88 -0
- package/dist/ui/status-panel.test.js.map +1 -0
- package/package.json +3 -1
- package/src/core/persistence.ts +1 -0
- package/src/core/runtime.ts +7 -2
- package/src/core/task-runner.test.ts +395 -0
- package/src/core/task-runner.ts +26 -5
- package/src/core/timer-plugin.ts +2 -1
- package/src/plugins/manager.test.ts +5 -2
- package/src/plugins/manager.ts +6 -2
- package/src/ui/app.tsx +151 -31
- package/src/ui/command-list.test.tsx +124 -0
- package/src/ui/metrics-panel.test.tsx +128 -0
- package/src/ui/metrics-panel.tsx +10 -10
- package/src/ui/panel.test.tsx +84 -0
- package/src/ui/status-panel.test.tsx +116 -0
- 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":"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"}
|
|
@@ -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 @@
|
|
|
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.
|
|
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';
|
package/src/core/runtime.ts
CHANGED
|
@@ -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 =
|
|
38
|
+
private persistenceDir = PERSISTENCE_DIR;
|
|
34
39
|
private unsubPersistence?: () => void;
|
|
35
40
|
private unsubNotifier?: () => void;
|
|
36
41
|
|