@hartvig/developer-control-center 0.8.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.
- package/.developer-control-center/metrics.json +1 -0
- package/.developer-control-center/status.json +1 -0
- package/.developer-control-center/timings.jsonl +3 -0
- package/.github/workflows/ci.yml +47 -0
- package/AGENTS.md +51 -0
- package/PLUGINS.md +145 -0
- package/README.md +147 -0
- package/developer-control-center.config.example.js +91 -0
- package/developer-control-center.config.js +177 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +223 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +4 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +96 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/loader.test.d.ts +2 -0
- package/dist/config/loader.test.d.ts.map +1 -0
- package/dist/config/loader.test.js +25 -0
- package/dist/config/loader.test.js.map +1 -0
- package/dist/config/presets/node.d.ts +10 -0
- package/dist/config/presets/node.d.ts.map +1 -0
- package/dist/config/presets/node.js +31 -0
- package/dist/config/presets/node.js.map +1 -0
- package/dist/config/presets/react.d.ts +10 -0
- package/dist/config/presets/react.d.ts.map +1 -0
- package/dist/config/presets/react.js +36 -0
- package/dist/config/presets/react.js.map +1 -0
- package/dist/config/types.d.ts +55 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/types.test.d.ts +2 -0
- package/dist/config/types.test.d.ts.map +1 -0
- package/dist/config/types.test.js +23 -0
- package/dist/config/types.test.js.map +1 -0
- package/dist/core/ci.d.ts +6 -0
- package/dist/core/ci.d.ts.map +1 -0
- package/dist/core/ci.js +22 -0
- package/dist/core/ci.js.map +1 -0
- package/dist/core/ci.test.d.ts +2 -0
- package/dist/core/ci.test.d.ts.map +1 -0
- package/dist/core/ci.test.js +45 -0
- package/dist/core/ci.test.js.map +1 -0
- package/dist/core/event-bus.d.ts +18 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +19 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/event-bus.test.d.ts +2 -0
- package/dist/core/event-bus.test.d.ts.map +1 -0
- package/dist/core/event-bus.test.js +49 -0
- package/dist/core/event-bus.test.js.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/notifier.d.ts +2 -0
- package/dist/core/notifier.d.ts.map +1 -0
- package/dist/core/notifier.js +28 -0
- package/dist/core/notifier.js.map +1 -0
- package/dist/core/notifier.test.d.ts +2 -0
- package/dist/core/notifier.test.d.ts.map +1 -0
- package/dist/core/notifier.test.js +25 -0
- package/dist/core/notifier.test.js.map +1 -0
- package/dist/core/runtime.d.ts +25 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +85 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/task-runner.d.ts +26 -0
- package/dist/core/task-runner.d.ts.map +1 -0
- package/dist/core/task-runner.js +354 -0
- package/dist/core/task-runner.js.map +1 -0
- package/dist/core/timer-plugin.d.ts +3 -0
- package/dist/core/timer-plugin.d.ts.map +1 -0
- package/dist/core/timer-plugin.js +34 -0
- package/dist/core/timer-plugin.js.map +1 -0
- package/dist/core/workspaces.d.ts +6 -0
- package/dist/core/workspaces.d.ts.map +1 -0
- package/dist/core/workspaces.js +60 -0
- package/dist/core/workspaces.js.map +1 -0
- package/dist/core/workspaces.test.d.ts +2 -0
- package/dist/core/workspaces.test.d.ts.map +1 -0
- package/dist/core/workspaces.test.js +62 -0
- package/dist/core/workspaces.test.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/index.d.ts +3 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/manager.d.ts +13 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +43 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/manager.test.d.ts +2 -0
- package/dist/plugins/manager.test.d.ts.map +1 -0
- package/dist/plugins/manager.test.js +79 -0
- package/dist/plugins/manager.test.js.map +1 -0
- package/dist/plugins/types.d.ts +17 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/status/index.d.ts +3 -0
- package/dist/status/index.d.ts.map +1 -0
- package/dist/status/index.js +2 -0
- package/dist/status/index.js.map +1 -0
- package/dist/status/store.d.ts +18 -0
- package/dist/status/store.d.ts.map +1 -0
- package/dist/status/store.js +76 -0
- package/dist/status/store.js.map +1 -0
- package/dist/status/store.test.d.ts +2 -0
- package/dist/status/store.test.d.ts.map +1 -0
- package/dist/status/store.test.js +107 -0
- package/dist/status/store.test.js.map +1 -0
- package/dist/status/types.d.ts +12 -0
- package/dist/status/types.d.ts.map +1 -0
- package/dist/status/types.js +2 -0
- package/dist/status/types.js.map +1 -0
- package/dist/ui/app.d.ts +10 -0
- package/dist/ui/app.d.ts.map +1 -0
- package/dist/ui/app.js +479 -0
- package/dist/ui/app.js.map +1 -0
- package/dist/ui/command-list.d.ts +30 -0
- package/dist/ui/command-list.d.ts.map +1 -0
- package/dist/ui/command-list.js +45 -0
- package/dist/ui/command-list.js.map +1 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +8 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/metrics-panel.d.ts +10 -0
- package/dist/ui/metrics-panel.d.ts.map +1 -0
- package/dist/ui/metrics-panel.js +139 -0
- package/dist/ui/metrics-panel.js.map +1 -0
- package/dist/ui/panel.d.ts +16 -0
- package/dist/ui/panel.d.ts.map +1 -0
- package/dist/ui/panel.js +16 -0
- package/dist/ui/panel.js.map +1 -0
- package/dist/ui/status-panel.d.ts +16 -0
- package/dist/ui/status-panel.d.ts.map +1 -0
- package/dist/ui/status-panel.js +52 -0
- package/dist/ui/status-panel.js.map +1 -0
- package/docs/architecture.md +29 -0
- package/docs/config.md +15 -0
- package/docs/mvp.md +17 -0
- package/docs/phases.md +49 -0
- package/docs/technical-decisions.md +19 -0
- package/docs/ui.md +14 -0
- package/package.json +30 -0
- package/src/cli.ts +242 -0
- package/src/config/index.ts +2 -0
- package/src/config/loader.test.ts +30 -0
- package/src/config/loader.ts +123 -0
- package/src/config/presets/node.ts +30 -0
- package/src/config/presets/react.ts +35 -0
- package/src/config/types.test.ts +24 -0
- package/src/config/types.ts +52 -0
- package/src/core/ci.test.ts +54 -0
- package/src/core/ci.ts +26 -0
- package/src/core/event-bus.test.ts +56 -0
- package/src/core/event-bus.ts +34 -0
- package/src/core/index.ts +8 -0
- package/src/core/notifier.test.ts +30 -0
- package/src/core/notifier.ts +34 -0
- package/src/core/runtime.ts +99 -0
- package/src/core/task-runner.ts +408 -0
- package/src/core/timer-plugin.ts +34 -0
- package/src/core/workspaces.test.ts +72 -0
- package/src/core/workspaces.ts +73 -0
- package/src/index.ts +15 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/manager.test.ts +92 -0
- package/src/plugins/manager.ts +54 -0
- package/src/plugins/types.ts +18 -0
- package/src/status/index.ts +2 -0
- package/src/status/store.test.ts +122 -0
- package/src/status/store.ts +88 -0
- package/src/status/types.ts +12 -0
- package/src/ui/app.tsx +606 -0
- package/src/ui/command-list.tsx +163 -0
- package/src/ui/index.tsx +10 -0
- package/src/ui/metrics-panel.tsx +234 -0
- package/src/ui/panel.tsx +76 -0
- package/src/ui/status-panel.tsx +160 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Plugin, PluginHooks } from './types.js';
|
|
2
|
+
type HookName = keyof PluginHooks;
|
|
3
|
+
export declare class PluginManager {
|
|
4
|
+
private plugins;
|
|
5
|
+
register(plugin: Plugin): void;
|
|
6
|
+
get(id: string): Plugin | undefined;
|
|
7
|
+
getAll(): Plugin[];
|
|
8
|
+
remove(id: string): boolean;
|
|
9
|
+
executeHook<K extends HookName>(hook: K, ...args: Parameters<NonNullable<PluginHooks[K]>>): Promise<void>;
|
|
10
|
+
loadFromConfig(pluginNames?: string[]): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/plugins/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjD,KAAK,QAAQ,GAAG,MAAM,WAAW,CAAC;AAElC,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAA6B;IAE5C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI9B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAInC,MAAM,IAAI,MAAM,EAAE;IAIlB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIrB,WAAW,CAAC,CAAC,SAAS,QAAQ,EAClC,IAAI,EAAE,CAAC,EACP,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC;IAeV,cAAc,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAY5D"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export class PluginManager {
|
|
2
|
+
plugins = new Map();
|
|
3
|
+
register(plugin) {
|
|
4
|
+
this.plugins.set(plugin.id, plugin);
|
|
5
|
+
}
|
|
6
|
+
get(id) {
|
|
7
|
+
return this.plugins.get(id);
|
|
8
|
+
}
|
|
9
|
+
getAll() {
|
|
10
|
+
return Array.from(this.plugins.values());
|
|
11
|
+
}
|
|
12
|
+
remove(id) {
|
|
13
|
+
return this.plugins.delete(id);
|
|
14
|
+
}
|
|
15
|
+
async executeHook(hook, ...args) {
|
|
16
|
+
for (const plugin of this.plugins.values()) {
|
|
17
|
+
const fn = plugin.hooks?.[hook];
|
|
18
|
+
if (fn) {
|
|
19
|
+
try {
|
|
20
|
+
await Promise.resolve(fn(...args));
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
console.error(`Plugin ${plugin.id} ${hook} error:`, e);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async loadFromConfig(pluginNames) {
|
|
29
|
+
if (!pluginNames?.length)
|
|
30
|
+
return;
|
|
31
|
+
for (const name of pluginNames) {
|
|
32
|
+
try {
|
|
33
|
+
const mod = await import(name);
|
|
34
|
+
const p = mod.default || mod;
|
|
35
|
+
this.register(p);
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.error(`Failed to load plugin "${name}":`, e);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/plugins/manager.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,aAAa;IAChB,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,QAAQ,CAAC,MAAc;QACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,MAAM;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,WAAW,CACf,IAAO,EACP,GAAG,IAA6C;QAEhD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAEjB,CAAC;YACd,IAAI,EAAE,EAAE,CAAC;gBACP,IAAI,CAAC;oBACH,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;gBACrC,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,OAAO,CAAC,KAAK,CAAC,UAAU,MAAM,CAAC,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,WAAsB;QACzC,IAAI,CAAC,WAAW,EAAE,MAAM;YAAE,OAAO;QACjC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC/B,MAAM,CAAC,GAAW,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC;gBACrC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.test.d.ts","sourceRoot":"","sources":["../../src/plugins/manager.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { PluginManager } from './manager.js';
|
|
3
|
+
describe('PluginManager', () => {
|
|
4
|
+
let pm;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
pm = new PluginManager();
|
|
7
|
+
});
|
|
8
|
+
it('registers and retrieves a plugin', () => {
|
|
9
|
+
pm.register({ id: 'p1', name: 'Plugin 1' });
|
|
10
|
+
expect(pm.get('p1')?.name).toBe('Plugin 1');
|
|
11
|
+
});
|
|
12
|
+
it('returns all plugins', () => {
|
|
13
|
+
pm.register({ id: 'a', name: 'A' });
|
|
14
|
+
pm.register({ id: 'b', name: 'B' });
|
|
15
|
+
expect(pm.getAll().length).toBe(2);
|
|
16
|
+
});
|
|
17
|
+
it('removes a plugin', () => {
|
|
18
|
+
pm.register({ id: 'x', name: 'X' });
|
|
19
|
+
expect(pm.remove('x')).toBe(true);
|
|
20
|
+
expect(pm.get('x')).toBeUndefined();
|
|
21
|
+
});
|
|
22
|
+
it('returns false when removing nonexistent plugin', () => {
|
|
23
|
+
expect(pm.remove('nope')).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
it('executes a hook on all registered plugins', async () => {
|
|
26
|
+
const calls = [];
|
|
27
|
+
pm.register({
|
|
28
|
+
id: 'a',
|
|
29
|
+
name: 'A',
|
|
30
|
+
hooks: { beforeRun: () => { calls.push('a-before'); } },
|
|
31
|
+
});
|
|
32
|
+
pm.register({
|
|
33
|
+
id: 'b',
|
|
34
|
+
name: 'B',
|
|
35
|
+
hooks: { beforeRun: () => { calls.push('b-before'); } },
|
|
36
|
+
});
|
|
37
|
+
await pm.executeHook('beforeRun', { id: 'test', label: 'T', command: 't' });
|
|
38
|
+
expect(calls).toEqual(['a-before', 'b-before']);
|
|
39
|
+
});
|
|
40
|
+
it('handles async hooks', async () => {
|
|
41
|
+
const order = [];
|
|
42
|
+
pm.register({
|
|
43
|
+
id: 'slow',
|
|
44
|
+
name: 'Slow',
|
|
45
|
+
hooks: {
|
|
46
|
+
beforeRun: async () => {
|
|
47
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
48
|
+
order.push(1);
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
pm.register({
|
|
53
|
+
id: 'fast',
|
|
54
|
+
name: 'Fast',
|
|
55
|
+
hooks: { beforeRun: () => { order.push(2); } },
|
|
56
|
+
});
|
|
57
|
+
await pm.executeHook('beforeRun', { id: 'x', label: 'X', command: 'x' });
|
|
58
|
+
expect(order).toEqual([1, 2]);
|
|
59
|
+
});
|
|
60
|
+
it('does not throw when a hook fails', async () => {
|
|
61
|
+
vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
62
|
+
pm.register({
|
|
63
|
+
id: 'bad',
|
|
64
|
+
name: 'Bad',
|
|
65
|
+
hooks: { beforeRun: () => { throw new Error('fail'); } },
|
|
66
|
+
});
|
|
67
|
+
await expect(pm.executeHook('beforeRun', { id: 'x', label: 'X', command: 'x' })).resolves.toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
it('skips plugin with no hooks for the requested hook', async () => {
|
|
70
|
+
pm.register({ id: 'none', name: 'None' });
|
|
71
|
+
await pm.executeHook('beforeRun', { id: 'x', label: 'X', command: 'x' });
|
|
72
|
+
});
|
|
73
|
+
it('loads nothing when pluginNames is empty', async () => {
|
|
74
|
+
await pm.loadFromConfig();
|
|
75
|
+
await pm.loadFromConfig([]);
|
|
76
|
+
expect(pm.getAll().length).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=manager.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.test.js","sourceRoot":"","sources":["../../src/plugins/manager.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ProkomCommand } from '../config/types.js';
|
|
2
|
+
export interface PluginHooks {
|
|
3
|
+
beforeRun?: (command: ProkomCommand) => void | Promise<void>;
|
|
4
|
+
afterRun?: (command: ProkomCommand, result: {
|
|
5
|
+
exitCode?: number;
|
|
6
|
+
status: string;
|
|
7
|
+
}) => void | Promise<void>;
|
|
8
|
+
onOutput?: (commandId: string, text: string) => void | Promise<void>;
|
|
9
|
+
onError?: (commandId: string, error: Error) => void | Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export interface Plugin {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
version?: string;
|
|
15
|
+
hooks?: PluginHooks;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,QAAQ,CAAC,EAAE,CACT,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC1C,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/status/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/status/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TaskState } from './types.js';
|
|
2
|
+
type Listener = (tasks: ReadonlyMap<string, TaskState>) => void;
|
|
3
|
+
export declare class StatusStore {
|
|
4
|
+
private tasks;
|
|
5
|
+
private listeners;
|
|
6
|
+
getTask(id: string): TaskState | undefined;
|
|
7
|
+
getAllTasks(): ReadonlyMap<string, TaskState>;
|
|
8
|
+
updateTask(id: string, update: Partial<TaskState>): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
removeTask(id: string): void;
|
|
11
|
+
pruneCompleted(): void;
|
|
12
|
+
subscribe(listener: Listener): () => void;
|
|
13
|
+
saveDir(dir: string): void;
|
|
14
|
+
loadDir(dir: string): void;
|
|
15
|
+
private notify;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/status/store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,IAAI,CAAC;AAEhE,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,SAAS,CAAuB;IAExC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI1C,WAAW,IAAI,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC;IAI7C,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI;IAUxD,KAAK,IAAI,IAAI;IAKb,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK5B,cAAc,IAAI,IAAI;IAWtB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI;IAKzC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAO1B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqB1B,OAAO,CAAC,MAAM;CAKf"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export class StatusStore {
|
|
4
|
+
tasks = new Map();
|
|
5
|
+
listeners = new Set();
|
|
6
|
+
getTask(id) {
|
|
7
|
+
return this.tasks.get(id);
|
|
8
|
+
}
|
|
9
|
+
getAllTasks() {
|
|
10
|
+
return new Map(this.tasks);
|
|
11
|
+
}
|
|
12
|
+
updateTask(id, update) {
|
|
13
|
+
const existing = this.tasks.get(id) ?? {
|
|
14
|
+
id,
|
|
15
|
+
label: id,
|
|
16
|
+
status: 'idle',
|
|
17
|
+
};
|
|
18
|
+
this.tasks.set(id, { ...existing, ...update });
|
|
19
|
+
this.notify();
|
|
20
|
+
}
|
|
21
|
+
clear() {
|
|
22
|
+
this.tasks.clear();
|
|
23
|
+
this.notify();
|
|
24
|
+
}
|
|
25
|
+
removeTask(id) {
|
|
26
|
+
this.tasks.delete(id);
|
|
27
|
+
this.notify();
|
|
28
|
+
}
|
|
29
|
+
pruneCompleted() {
|
|
30
|
+
let changed = false;
|
|
31
|
+
for (const [id, task] of this.tasks) {
|
|
32
|
+
if (task.status !== 'running') {
|
|
33
|
+
this.tasks.delete(id);
|
|
34
|
+
changed = true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (changed)
|
|
38
|
+
this.notify();
|
|
39
|
+
}
|
|
40
|
+
subscribe(listener) {
|
|
41
|
+
this.listeners.add(listener);
|
|
42
|
+
return () => this.listeners.delete(listener);
|
|
43
|
+
}
|
|
44
|
+
saveDir(dir) {
|
|
45
|
+
const filePath = path.join(dir, 'status.json');
|
|
46
|
+
const data = JSON.stringify(Array.from(this.tasks.entries()));
|
|
47
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
48
|
+
fs.writeFileSync(filePath, data, 'utf-8');
|
|
49
|
+
}
|
|
50
|
+
loadDir(dir) {
|
|
51
|
+
const filePath = path.join(dir, 'status.json');
|
|
52
|
+
if (fs.existsSync(filePath)) {
|
|
53
|
+
const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
54
|
+
const tasks = new Map(raw);
|
|
55
|
+
let changed = false;
|
|
56
|
+
for (const [id] of tasks) {
|
|
57
|
+
const task = tasks.get(id);
|
|
58
|
+
if (task.status === 'running') {
|
|
59
|
+
tasks.set(id, { ...task, status: 'failure', endTime: Date.now() });
|
|
60
|
+
changed = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (changed) {
|
|
64
|
+
fs.writeFileSync(filePath, JSON.stringify(Array.from(tasks.entries())), 'utf-8');
|
|
65
|
+
}
|
|
66
|
+
this.tasks = tasks;
|
|
67
|
+
this.notify();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
notify() {
|
|
71
|
+
for (const listener of this.listeners) {
|
|
72
|
+
listener(new Map(this.tasks));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/status/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.test.d.ts","sourceRoot":"","sources":["../../src/status/store.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { StatusStore } from './store.js';
|
|
4
|
+
describe('StatusStore', () => {
|
|
5
|
+
let store;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
store = new StatusStore();
|
|
8
|
+
});
|
|
9
|
+
it('starts empty', () => {
|
|
10
|
+
expect(store.getAllTasks().size).toBe(0);
|
|
11
|
+
});
|
|
12
|
+
it('stores and retrieves a task', () => {
|
|
13
|
+
store.updateTask('build', {
|
|
14
|
+
id: 'build',
|
|
15
|
+
label: 'Build',
|
|
16
|
+
status: 'running',
|
|
17
|
+
output: '',
|
|
18
|
+
});
|
|
19
|
+
const task = store.getTask('build');
|
|
20
|
+
expect(task?.label).toBe('Build');
|
|
21
|
+
expect(task?.status).toBe('running');
|
|
22
|
+
});
|
|
23
|
+
it('updates an existing task', () => {
|
|
24
|
+
store.updateTask('build', {
|
|
25
|
+
id: 'build',
|
|
26
|
+
label: 'Build',
|
|
27
|
+
status: 'running',
|
|
28
|
+
output: 'start',
|
|
29
|
+
});
|
|
30
|
+
store.updateTask('build', { output: 'start\nprogress' });
|
|
31
|
+
expect(store.getTask('build')?.output).toBe('start\nprogress');
|
|
32
|
+
});
|
|
33
|
+
it('clears all tasks', () => {
|
|
34
|
+
store.updateTask('a', { id: 'a', label: 'A', status: 'running' });
|
|
35
|
+
store.updateTask('b', { id: 'b', label: 'B', status: 'success' });
|
|
36
|
+
expect(store.getAllTasks().size).toBe(2);
|
|
37
|
+
store.clear();
|
|
38
|
+
expect(store.getAllTasks().size).toBe(0);
|
|
39
|
+
});
|
|
40
|
+
it('prunes completed tasks but keeps running ones', () => {
|
|
41
|
+
store.updateTask('running-task', { id: 'running-task', label: 'Running', status: 'running' });
|
|
42
|
+
store.updateTask('done-task', { id: 'done-task', label: 'Done', status: 'success' });
|
|
43
|
+
store.updateTask('failed-task', { id: 'failed-task', label: 'Failed', status: 'failure' });
|
|
44
|
+
expect(store.getAllTasks().size).toBe(3);
|
|
45
|
+
store.pruneCompleted();
|
|
46
|
+
expect(store.getAllTasks().size).toBe(1);
|
|
47
|
+
expect(store.getTask('running-task')).toBeDefined();
|
|
48
|
+
expect(store.getTask('done-task')).toBeUndefined();
|
|
49
|
+
expect(store.getTask('failed-task')).toBeUndefined();
|
|
50
|
+
});
|
|
51
|
+
it('pruneCompleted removes nothing when all tasks are running', () => {
|
|
52
|
+
store.updateTask('a', { id: 'a', label: 'A', status: 'running' });
|
|
53
|
+
store.updateTask('b', { id: 'b', label: 'B', status: 'running' });
|
|
54
|
+
store.pruneCompleted();
|
|
55
|
+
expect(store.getAllTasks().size).toBe(2);
|
|
56
|
+
});
|
|
57
|
+
it('notifies subscribers on update', () => {
|
|
58
|
+
const updates = [];
|
|
59
|
+
store.subscribe((tasks) => updates.push(tasks.size));
|
|
60
|
+
store.updateTask('x', { id: 'x', label: 'X', status: 'running' });
|
|
61
|
+
expect(updates).toEqual([1]);
|
|
62
|
+
});
|
|
63
|
+
it('unsubscribes correctly', () => {
|
|
64
|
+
const updates = [];
|
|
65
|
+
const unsub = store.subscribe((tasks) => updates.push(tasks.size));
|
|
66
|
+
unsub();
|
|
67
|
+
store.updateTask('x', { id: 'x', label: 'X', status: 'running' });
|
|
68
|
+
expect(updates).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
it('persists and loads from directory', () => {
|
|
71
|
+
const dir = '/tmp/dcc-test-store';
|
|
72
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
73
|
+
store.updateTask('persist', {
|
|
74
|
+
id: 'persist',
|
|
75
|
+
label: 'Persist',
|
|
76
|
+
status: 'success',
|
|
77
|
+
exitCode: 0,
|
|
78
|
+
});
|
|
79
|
+
store.saveDir(dir);
|
|
80
|
+
const store2 = new StatusStore();
|
|
81
|
+
store2.loadDir(dir);
|
|
82
|
+
const task = store2.getTask('persist');
|
|
83
|
+
expect(task?.label).toBe('Persist');
|
|
84
|
+
expect(task?.status).toBe('success');
|
|
85
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
86
|
+
});
|
|
87
|
+
it('resets stale running tasks to failure on load', () => {
|
|
88
|
+
const dir = '/tmp/dcc-test-stale-store';
|
|
89
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
90
|
+
const store = new StatusStore();
|
|
91
|
+
store.updateTask('stale-run', {
|
|
92
|
+
id: 'stale-run',
|
|
93
|
+
label: 'Stale Run',
|
|
94
|
+
status: 'running',
|
|
95
|
+
startTime: Date.now(),
|
|
96
|
+
});
|
|
97
|
+
store.saveDir(dir);
|
|
98
|
+
const store2 = new StatusStore();
|
|
99
|
+
store2.loadDir(dir);
|
|
100
|
+
const task = store2.getTask('stale-run');
|
|
101
|
+
expect(task?.status).toBe('failure');
|
|
102
|
+
expect(task?.label).toBe('Stale Run');
|
|
103
|
+
expect(typeof task?.endTime).toBe('number');
|
|
104
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=store.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.test.js","sourceRoot":"","sources":["../../src/status/store.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type TaskStatus = 'idle' | 'running' | 'success' | 'failure';
|
|
2
|
+
export interface TaskState {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
status: TaskStatus;
|
|
6
|
+
output?: string;
|
|
7
|
+
exitCode?: number;
|
|
8
|
+
startTime?: number;
|
|
9
|
+
endTime?: number;
|
|
10
|
+
watchMode?: boolean;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/status/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/status/types.ts"],"names":[],"mappings":""}
|
package/dist/ui/app.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Runtime } from '../core/index.js';
|
|
3
|
+
import { ProkomConfig } from '../config/index.js';
|
|
4
|
+
interface AppProps {
|
|
5
|
+
config: ProkomConfig;
|
|
6
|
+
runtime: Runtime;
|
|
7
|
+
}
|
|
8
|
+
export declare const App: React.FC<AppProps>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/ui/app.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAEjF,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAgC,MAAM,oBAAoB,CAAC;AAOhF,UAAU,QAAQ;IAChB,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAsCD,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CA0iBlC,CAAC"}
|