@damaall/ccx 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/commands/report.d.ts +8 -0
- package/dist/commands/report.d.ts.map +1 -0
- package/dist/commands/report.js +115 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/reuse.d.ts +7 -0
- package/dist/commands/reuse.d.ts.map +1 -0
- package/dist/commands/reuse.js +167 -0
- package/dist/commands/reuse.js.map +1 -0
- package/dist/commands/watch.d.ts +10 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +201 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/core/cursor-reader.d.ts +24 -0
- package/dist/core/cursor-reader.d.ts.map +1 -0
- package/dist/core/cursor-reader.js +128 -0
- package/dist/core/cursor-reader.js.map +1 -0
- package/dist/core/data-source-adapter.d.ts +239 -0
- package/dist/core/data-source-adapter.d.ts.map +1 -0
- package/dist/core/data-source-adapter.js +85 -0
- package/dist/core/data-source-adapter.js.map +1 -0
- package/dist/core/identity-resolver.d.ts +27 -0
- package/dist/core/identity-resolver.d.ts.map +1 -0
- package/dist/core/identity-resolver.js +55 -0
- package/dist/core/identity-resolver.js.map +1 -0
- package/dist/core/inbox-reader.d.ts +20 -0
- package/dist/core/inbox-reader.d.ts.map +1 -0
- package/dist/core/inbox-reader.js +105 -0
- package/dist/core/inbox-reader.js.map +1 -0
- package/dist/core/paths.d.ts +28 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +46 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/pricing.d.ts +25 -0
- package/dist/core/pricing.d.ts.map +1 -0
- package/dist/core/pricing.js +108 -0
- package/dist/core/pricing.js.map +1 -0
- package/dist/core/redact.d.ts +15 -0
- package/dist/core/redact.d.ts.map +1 -0
- package/dist/core/redact.js +60 -0
- package/dist/core/redact.js.map +1 -0
- package/dist/core/session-discovery.d.ts +26 -0
- package/dist/core/session-discovery.d.ts.map +1 -0
- package/dist/core/session-discovery.js +89 -0
- package/dist/core/session-discovery.js.map +1 -0
- package/dist/core/snapshot-manager.d.ts +29 -0
- package/dist/core/snapshot-manager.d.ts.map +1 -0
- package/dist/core/snapshot-manager.js +120 -0
- package/dist/core/snapshot-manager.js.map +1 -0
- package/dist/core/snapshot-reader.d.ts +23 -0
- package/dist/core/snapshot-reader.d.ts.map +1 -0
- package/dist/core/snapshot-reader.js +142 -0
- package/dist/core/snapshot-reader.js.map +1 -0
- package/dist/core/state-aggregator.d.ts +36 -0
- package/dist/core/state-aggregator.d.ts.map +1 -0
- package/dist/core/state-aggregator.js +218 -0
- package/dist/core/state-aggregator.js.map +1 -0
- package/dist/core/task-reader.d.ts +14 -0
- package/dist/core/task-reader.d.ts.map +1 -0
- package/dist/core/task-reader.js +55 -0
- package/dist/core/task-reader.js.map +1 -0
- package/dist/core/team-reader.d.ts +18 -0
- package/dist/core/team-reader.d.ts.map +1 -0
- package/dist/core/team-reader.js +68 -0
- package/dist/core/team-reader.js.map +1 -0
- package/dist/core/types.d.ts +105 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/watcher.d.ts +16 -0
- package/dist/core/watcher.d.ts.map +1 -0
- package/dist/core/watcher.js +194 -0
- package/dist/core/watcher.js.map +1 -0
- package/dist/guard/hard-limit.d.ts +13 -0
- package/dist/guard/hard-limit.d.ts.map +1 -0
- package/dist/guard/hard-limit.js +79 -0
- package/dist/guard/hard-limit.js.map +1 -0
- package/dist/guard/soft-limit.d.ts +5 -0
- package/dist/guard/soft-limit.d.ts.map +1 -0
- package/dist/guard/soft-limit.js +22 -0
- package/dist/guard/soft-limit.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +171 -0
- package/dist/index.js.map +1 -0
- package/dist/report/json.d.ts +6 -0
- package/dist/report/json.d.ts.map +1 -0
- package/dist/report/json.js +4 -0
- package/dist/report/json.js.map +1 -0
- package/dist/report/markdown.d.ts +6 -0
- package/dist/report/markdown.d.ts.map +1 -0
- package/dist/report/markdown.js +57 -0
- package/dist/report/markdown.js.map +1 -0
- package/dist/report/redact-snapshot.d.ts +3 -0
- package/dist/report/redact-snapshot.d.ts.map +1 -0
- package/dist/report/redact-snapshot.js +21 -0
- package/dist/report/redact-snapshot.js.map +1 -0
- package/dist/report/terminal.d.ts +3 -0
- package/dist/report/terminal.d.ts.map +1 -0
- package/dist/report/terminal.js +85 -0
- package/dist/report/terminal.js.map +1 -0
- package/dist/ui/AgentPanel.d.ts +13 -0
- package/dist/ui/AgentPanel.d.ts.map +1 -0
- package/dist/ui/AgentPanel.js +61 -0
- package/dist/ui/AgentPanel.js.map +1 -0
- package/dist/ui/AlertBanner.d.ts +11 -0
- package/dist/ui/AlertBanner.d.ts.map +1 -0
- package/dist/ui/AlertBanner.js +19 -0
- package/dist/ui/AlertBanner.js.map +1 -0
- package/dist/ui/CompletionBanner.d.ts +12 -0
- package/dist/ui/CompletionBanner.d.ts.map +1 -0
- package/dist/ui/CompletionBanner.js +11 -0
- package/dist/ui/CompletionBanner.js.map +1 -0
- package/dist/ui/CostBar.d.ts +12 -0
- package/dist/ui/CostBar.d.ts.map +1 -0
- package/dist/ui/CostBar.js +29 -0
- package/dist/ui/CostBar.js.map +1 -0
- package/dist/ui/Dashboard.d.ts +10 -0
- package/dist/ui/Dashboard.d.ts.map +1 -0
- package/dist/ui/Dashboard.js +70 -0
- package/dist/ui/Dashboard.js.map +1 -0
- package/dist/ui/TaskPanel.d.ts +11 -0
- package/dist/ui/TaskPanel.d.ts.map +1 -0
- package/dist/ui/TaskPanel.js +41 -0
- package/dist/ui/TaskPanel.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot-level secret redaction
|
|
3
|
+
*
|
|
4
|
+
* 套用 redactSecrets 到所有文字欄位(task subject/description, alert message)
|
|
5
|
+
*/
|
|
6
|
+
import { redactSecrets } from '../core/redact.js';
|
|
7
|
+
export function redactSnapshot(snapshot) {
|
|
8
|
+
return {
|
|
9
|
+
...snapshot,
|
|
10
|
+
tasks: snapshot.tasks.map(t => ({
|
|
11
|
+
...t,
|
|
12
|
+
subject: redactSecrets(t.subject),
|
|
13
|
+
description: redactSecrets(t.description),
|
|
14
|
+
})),
|
|
15
|
+
alerts: snapshot.alerts.map(a => ({
|
|
16
|
+
...a,
|
|
17
|
+
message: redactSecrets(a.message),
|
|
18
|
+
})),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=redact-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact-snapshot.js","sourceRoot":"","sources":["../../src/report/redact-snapshot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAGjD,MAAM,UAAU,cAAc,CAAC,QAAyB;IACtD,OAAO;QACL,GAAG,QAAQ;QACX,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9B,GAAG,CAAC;YACJ,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC;YACjC,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC;SAC1C,CAAC,CAAC;QACH,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChC,GAAG,CAAC;YACJ,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC;SAClC,CAAC,CAAC;KACJ,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/report/terminal.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAsEtE"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal report formatter:彩色表格輸出
|
|
3
|
+
*/
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { formatCost, formatTokens, totalTokenCount, formatDuration } from '../core/pricing.js';
|
|
6
|
+
export function formatTerminalReport(snapshot) {
|
|
7
|
+
const lines = [];
|
|
8
|
+
const elapsed = formatDuration(snapshot.lastUpdatedAt - snapshot.startedAt);
|
|
9
|
+
const startedAt = new Date(snapshot.startedAt).toLocaleString();
|
|
10
|
+
// Header
|
|
11
|
+
lines.push(chalk.bold(`ccx report: ${snapshot.teamName}`));
|
|
12
|
+
lines.push(chalk.dim('═'.repeat(72)));
|
|
13
|
+
lines.push('');
|
|
14
|
+
// Summary
|
|
15
|
+
lines.push(chalk.bold('SUMMARY'));
|
|
16
|
+
lines.push(` Team: ${snapshot.teamName}`);
|
|
17
|
+
lines.push(` Session: ${snapshot.sessionId}`);
|
|
18
|
+
lines.push(` Started: ${startedAt}`);
|
|
19
|
+
lines.push(` Duration: ${elapsed}`);
|
|
20
|
+
lines.push(` Status: ${snapshot.finalized ? chalk.blue('finalized') : chalk.green('active')}`);
|
|
21
|
+
lines.push(` Total Cost: ${chalk.bold(formatCost(snapshot.totalCost))}`);
|
|
22
|
+
lines.push(` Agents: ${snapshot.agents.length}`);
|
|
23
|
+
lines.push(` Tasks: ${snapshot.tasks.length}`);
|
|
24
|
+
lines.push('');
|
|
25
|
+
// Agents table
|
|
26
|
+
lines.push(chalk.bold('AGENTS'));
|
|
27
|
+
lines.push(chalk.dim(` ${'NAME'.padEnd(25)} ${'MODEL'.padEnd(10)} ${'STATUS'.padEnd(12)} ${'TOKENS'.padEnd(12)} COST`));
|
|
28
|
+
lines.push(chalk.dim(' ' + '─'.repeat(68)));
|
|
29
|
+
for (const agent of snapshot.agents) {
|
|
30
|
+
const name = agent.name.slice(0, 24).padEnd(25);
|
|
31
|
+
const model = agent.model.padEnd(10);
|
|
32
|
+
const status = colorStatus(agent.status).padEnd(20); // extra for ANSI
|
|
33
|
+
const tokens = formatTokens(totalTokenCount(agent.tokenUsage)).padEnd(12);
|
|
34
|
+
const cost = formatCost(agent.cost);
|
|
35
|
+
lines.push(` ${name} ${model} ${status} ${tokens} ${cost}`);
|
|
36
|
+
}
|
|
37
|
+
// Totals
|
|
38
|
+
const totalTokens = formatTokens(totalTokenCount(snapshot.totalTokens));
|
|
39
|
+
lines.push(chalk.dim(' ' + '─'.repeat(68)));
|
|
40
|
+
lines.push(` ${'TOTAL'.padEnd(25)} ${''.padEnd(10)} ${''.padEnd(12)} ${totalTokens.padEnd(12)} ${chalk.bold(formatCost(snapshot.totalCost))}`);
|
|
41
|
+
lines.push('');
|
|
42
|
+
// Tasks table
|
|
43
|
+
if (snapshot.tasks.length > 0) {
|
|
44
|
+
lines.push(chalk.bold('TASKS'));
|
|
45
|
+
for (const task of snapshot.tasks) {
|
|
46
|
+
const id = `#${task.id}`.padEnd(6);
|
|
47
|
+
const status = colorTaskStatus(task.status);
|
|
48
|
+
const subject = task.subject.slice(0, 40).padEnd(42);
|
|
49
|
+
const owner = task.owner || chalk.dim('──');
|
|
50
|
+
lines.push(` ${id}${status} ${subject} ${owner}`);
|
|
51
|
+
}
|
|
52
|
+
lines.push('');
|
|
53
|
+
}
|
|
54
|
+
// Alerts
|
|
55
|
+
if (snapshot.alerts.length > 0) {
|
|
56
|
+
lines.push(chalk.bold('ALERTS'));
|
|
57
|
+
for (const alert of snapshot.alerts) {
|
|
58
|
+
const time = new Date(alert.timestamp).toLocaleTimeString();
|
|
59
|
+
const icon = alert.level === 'critical' ? chalk.red('!!') : chalk.yellow('!!');
|
|
60
|
+
const msg = alert.level === 'critical' ? chalk.red(alert.message) : chalk.yellow(alert.message);
|
|
61
|
+
lines.push(` ${icon} ${chalk.dim(time)} ${msg}`);
|
|
62
|
+
}
|
|
63
|
+
lines.push('');
|
|
64
|
+
}
|
|
65
|
+
return lines.join('\n');
|
|
66
|
+
}
|
|
67
|
+
function colorStatus(status) {
|
|
68
|
+
switch (status) {
|
|
69
|
+
case 'working': return chalk.green(status);
|
|
70
|
+
case 'idle': return chalk.dim(status);
|
|
71
|
+
case 'stuck': return chalk.red('stuck?');
|
|
72
|
+
case 'done': return chalk.blue(status);
|
|
73
|
+
case 'shutdown': return chalk.dim(status);
|
|
74
|
+
default: return chalk.dim(status);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function colorTaskStatus(status) {
|
|
78
|
+
switch (status) {
|
|
79
|
+
case 'in_progress': return chalk.green('[working]'.padEnd(12));
|
|
80
|
+
case 'completed': return chalk.blue('[done]'.padEnd(12));
|
|
81
|
+
case 'pending': return chalk.dim('[pending]'.padEnd(12));
|
|
82
|
+
default: return chalk.dim(`[${status}]`.padEnd(12));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=terminal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/report/terminal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentPanel:顯示 agent 列表 + heartbeat + last-activity
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import type { AgentState } from '../core/types.js';
|
|
6
|
+
interface AgentPanelProps {
|
|
7
|
+
readonly agents: readonly AgentState[];
|
|
8
|
+
readonly totalCost: number;
|
|
9
|
+
readonly totalTokens: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const AgentPanel: React.NamedExoticComponent<AgentPanelProps>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=AgentPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentPanel.d.ts","sourceRoot":"","sources":["../../src/ui/AgentPanel.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAe,MAAM,OAAO,CAAA;AAEnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAGlD,UAAU,eAAe;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,eAAO,MAAM,UAAU,6CAmCrB,CAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* AgentPanel:顯示 agent 列表 + heartbeat + last-activity
|
|
4
|
+
*/
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
import { formatCost, formatTokens, totalTokenCount } from '../core/pricing.js';
|
|
8
|
+
export const AgentPanel = memo(function AgentPanel({ agents, totalCost, totalTokens }) {
|
|
9
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: pad('AGENTS', 30) }), _jsx(Text, { dimColor: true, children: pad('STATUS', 12) }), _jsx(Text, { dimColor: true, children: pad('ACTIVE', 10) }), _jsx(Text, { dimColor: true, children: pad('TOKENS', 10) }), _jsx(Text, { dimColor: true, children: "COST" })] }), agents.length === 0 ? (_jsx(Text, { dimColor: true, children: " (no agents detected yet)" })) : (agents.map((agent, i) => (_jsx(AgentRow, { agent: agent, isLast: i === agents.length - 1 }, agent.agentId)))), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: ' '.repeat(30) + '────────────────────────────' }) }), _jsxs(Box, { children: [_jsx(Text, { children: pad('', 30) }), _jsx(Text, { bold: true, children: pad('TOTAL', 12) }), _jsx(Text, { children: pad('', 10) }), _jsx(Text, { children: pad(formatTokens(totalTokens), 10) }), _jsx(Text, { bold: true, children: formatCost(totalCost) })] })] }));
|
|
10
|
+
});
|
|
11
|
+
const AgentRow = memo(function AgentRow({ agent, isLast }) {
|
|
12
|
+
const prefix = isLast ? '└─' : '├─';
|
|
13
|
+
const name = truncate(`${agent.name} (${agent.model})`, 26);
|
|
14
|
+
const active = agent.lastActivityAt > 0
|
|
15
|
+
? formatTimeSince(agent.lastActivityAt)
|
|
16
|
+
: '──';
|
|
17
|
+
const tokens = formatTokens(totalTokenCount(agent.tokenUsage));
|
|
18
|
+
const cost = formatCost(agent.cost);
|
|
19
|
+
return (_jsx(Box, { flexDirection: "column", children: _jsxs(Box, { children: [_jsxs(Text, { children: [prefix, " ", pad(name, 28)] }), _jsx(StatusText, { status: agent.status }), _jsx(Text, { dimColor: true, children: pad(active, 10) }), _jsx(Text, { children: pad(tokens, 10) }), _jsx(Text, { children: cost })] }) }));
|
|
20
|
+
});
|
|
21
|
+
function StatusText({ status }) {
|
|
22
|
+
const width = 12;
|
|
23
|
+
switch (status) {
|
|
24
|
+
case 'working':
|
|
25
|
+
return _jsx(Text, { color: "green", children: pad(status, width) });
|
|
26
|
+
case 'idle':
|
|
27
|
+
return _jsx(Text, { dimColor: true, children: pad(status, width) });
|
|
28
|
+
case 'thinking':
|
|
29
|
+
return _jsx(Text, { color: "yellow", children: pad(status, width) });
|
|
30
|
+
case 'stuck':
|
|
31
|
+
return _jsx(Text, { color: "red", children: pad('stuck?', width) });
|
|
32
|
+
case 'done':
|
|
33
|
+
return _jsx(Text, { color: "blue", children: pad(status, width) });
|
|
34
|
+
case 'shutdown':
|
|
35
|
+
return _jsx(Text, { dimColor: true, children: pad(status, width) });
|
|
36
|
+
default:
|
|
37
|
+
return _jsx(Text, { dimColor: true, children: pad(status, width) });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// ─── Helpers ───
|
|
41
|
+
function pad(str, width) {
|
|
42
|
+
if (str.length >= width)
|
|
43
|
+
return str.slice(0, width);
|
|
44
|
+
return str + ' '.repeat(width - str.length);
|
|
45
|
+
}
|
|
46
|
+
function truncate(str, maxLen) {
|
|
47
|
+
if (str.length <= maxLen)
|
|
48
|
+
return str;
|
|
49
|
+
return str.slice(0, maxLen - 3) + '...';
|
|
50
|
+
}
|
|
51
|
+
function formatTimeSince(timestamp) {
|
|
52
|
+
const ms = Date.now() - timestamp;
|
|
53
|
+
const secs = Math.floor(ms / 1000);
|
|
54
|
+
if (secs < 60)
|
|
55
|
+
return `${secs}s`;
|
|
56
|
+
const mins = Math.floor(secs / 60);
|
|
57
|
+
if (mins < 60)
|
|
58
|
+
return `${mins}m${secs % 60}s`;
|
|
59
|
+
return `${Math.floor(mins / 60)}h${mins % 60}m`;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=AgentPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentPanel.js","sourceRoot":"","sources":["../../src/ui/AgentPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AlertBanner:最近 alerts(最多 3 條)
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import type { Alert } from '../core/types.js';
|
|
6
|
+
interface AlertBannerProps {
|
|
7
|
+
readonly alerts: readonly Alert[];
|
|
8
|
+
}
|
|
9
|
+
export declare const AlertBanner: React.NamedExoticComponent<AlertBannerProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=AlertBanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlertBanner.d.ts","sourceRoot":"","sources":["../../src/ui/AlertBanner.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAe,MAAM,OAAO,CAAA;AAEnC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,UAAU,gBAAgB;IACxB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAA;CAClC;AAID,eAAO,MAAM,WAAW,8CAgBtB,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* AlertBanner:最近 alerts(最多 3 條)
|
|
4
|
+
*/
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
const MAX_VISIBLE = 3;
|
|
8
|
+
export const AlertBanner = memo(function AlertBanner({ alerts }) {
|
|
9
|
+
if (alerts.length === 0)
|
|
10
|
+
return null;
|
|
11
|
+
const visible = alerts.slice(-MAX_VISIBLE);
|
|
12
|
+
const hidden = alerts.length - visible.length;
|
|
13
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: ["ALERTS", hidden > 0 ? ` (showing ${visible.length} of ${alerts.length})` : ''] }), visible.map((alert, i) => (_jsx(AlertRow, { alert: alert }, i)))] }));
|
|
14
|
+
});
|
|
15
|
+
function AlertRow({ alert }) {
|
|
16
|
+
const isCritical = alert.level === 'critical';
|
|
17
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: isCritical ? 'red' : 'yellow', children: '⚠ ' }), _jsx(Text, { color: isCritical ? 'red' : 'yellow', children: alert.message })] }));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=AlertBanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlertBanner.js","sourceRoot":"","sources":["../../src/ui/AlertBanner.tsx"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAO/B,MAAM,WAAW,GAAG,CAAC,CAAA;AAErB,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,WAAW,CAAC,EAAE,MAAM,EAAoB;IAC/E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEpC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAE7C,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,MAAC,IAAI,IAAC,IAAI,6BACD,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,MAAM,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,IACtE,EACN,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CACzB,KAAC,QAAQ,IAAS,KAAK,EAAE,KAAK,IAAf,CAAC,CAAkB,CACnC,CAAC,IACE,CACP,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,SAAS,QAAQ,CAAC,EAAE,KAAK,EAAoB;IAC3C,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,KAAK,UAAU,CAAA;IAC7C,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,YAAG,IAAI,GAAQ,EACzD,KAAC,IAAI,IAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,YAAG,KAAK,CAAC,OAAO,GAAQ,IAC9D,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CompletionBanner:team 完成時的 summary + 快捷鍵
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
interface CompletionBannerProps {
|
|
6
|
+
readonly completedAt: string;
|
|
7
|
+
readonly elapsed: string;
|
|
8
|
+
readonly totalCost: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const CompletionBanner: React.NamedExoticComponent<CompletionBannerProps>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=CompletionBanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompletionBanner.d.ts","sourceRoot":"","sources":["../../src/ui/CompletionBanner.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAe,MAAM,OAAO,CAAA;AAInC,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED,eAAO,MAAM,gBAAgB,mDAe3B,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* CompletionBanner:team 完成時的 summary + 快捷鍵
|
|
4
|
+
*/
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
import { formatCost } from '../core/pricing.js';
|
|
8
|
+
export const CompletionBanner = memo(function CompletionBanner({ completedAt, elapsed, totalCost, }) {
|
|
9
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "green", paddingX: 1, children: [_jsxs(Text, { color: "green", bold: true, children: ["Team completed at ", completedAt, " | ", elapsed, " | ", formatCost(totalCost)] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "[r] report [s] save snapshot [q] quit" }) })] }));
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=CompletionBanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CompletionBanner.js","sourceRoot":"","sources":["../../src/ui/CompletionBanner.tsx"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAQ/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,gBAAgB,CAAC,EAC7D,WAAW,EACX,OAAO,EACP,SAAS,GACa;IACtB,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAC,QAAQ,EAAC,WAAW,EAAC,OAAO,EAAC,QAAQ,EAAE,CAAC,aAC9E,MAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,yCACH,WAAW,SAAK,OAAO,SAAK,UAAU,CAAC,SAAS,CAAC,IAC/D,EACP,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,KAAC,IAAI,IAAC,QAAQ,8DAA+C,GACzD,IACF,CACP,CAAA;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CostBar:cost/budget 進度條 + soft/hard indicator
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
interface CostBarProps {
|
|
6
|
+
readonly currentCost: number;
|
|
7
|
+
readonly budget: number | null;
|
|
8
|
+
readonly hardLimit: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const CostBar: React.NamedExoticComponent<CostBarProps>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=CostBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CostBar.d.ts","sourceRoot":"","sources":["../../src/ui/CostBar.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAe,MAAM,OAAO,CAAA;AAInC,UAAU,YAAY;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,eAAO,MAAM,OAAO,0CA0BlB,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* CostBar:cost/budget 進度條 + soft/hard indicator
|
|
4
|
+
*/
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
import { formatCost } from '../core/pricing.js';
|
|
8
|
+
export const CostBar = memo(function CostBar({ currentCost, budget, hardLimit }) {
|
|
9
|
+
if (!budget)
|
|
10
|
+
return null;
|
|
11
|
+
const pct = Math.min(currentCost / budget, 1.5); // cap at 150% for display
|
|
12
|
+
const pctDisplay = Math.round((currentCost / budget) * 100);
|
|
13
|
+
const barWidth = 20;
|
|
14
|
+
const filled = Math.min(Math.round(pct * barWidth), barWidth);
|
|
15
|
+
const empty = barWidth - filled;
|
|
16
|
+
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
17
|
+
const limitLabel = hardLimit ? ' [HARD]' : ' [soft]';
|
|
18
|
+
let barColor;
|
|
19
|
+
if (pctDisplay >= 100)
|
|
20
|
+
barColor = 'red';
|
|
21
|
+
else if (pctDisplay >= 80)
|
|
22
|
+
barColor = 'red';
|
|
23
|
+
else if (pctDisplay >= 60)
|
|
24
|
+
barColor = 'yellow';
|
|
25
|
+
else
|
|
26
|
+
barColor = 'green';
|
|
27
|
+
return (_jsxs(Box, { children: [_jsx(Text, { children: "Budget: " }), _jsx(Text, { color: barColor, children: bar }), _jsxs(Text, { children: [" ", formatCost(currentCost), " / ", formatCost(budget), " (", pctDisplay, "%)"] }), _jsx(Text, { color: hardLimit ? 'red' : 'yellow', bold: hardLimit, children: limitLabel })] }));
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=CostBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CostBar.js","sourceRoot":"","sources":["../../src/ui/CostBar.tsx"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAc,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAQ/C,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,OAAO,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAgB;IAC3F,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAExB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,EAAE,GAAG,CAAC,CAAA,CAAC,0BAA0B;IAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,CAAA;IAC3D,MAAM,QAAQ,GAAG,EAAE,CAAA;IACnB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAA;IAC7D,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAA;IAE/B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAClD,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;IAEpD,IAAI,QAAgB,CAAA;IACpB,IAAI,UAAU,IAAI,GAAG;QAAE,QAAQ,GAAG,KAAK,CAAA;SAClC,IAAI,UAAU,IAAI,EAAE;QAAE,QAAQ,GAAG,KAAK,CAAA;SACtC,IAAI,UAAU,IAAI,EAAE;QAAE,QAAQ,GAAG,QAAQ,CAAA;;QACzC,QAAQ,GAAG,OAAO,CAAA;IAEvB,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,2BAAgB,EACrB,KAAC,IAAI,IAAC,KAAK,EAAE,QAAQ,YAAG,GAAG,GAAQ,EACnC,MAAC,IAAI,oBAAG,UAAU,CAAC,WAAW,CAAC,SAAK,UAAU,CAAC,MAAM,CAAC,QAAI,UAAU,UAAU,EAC9E,KAAC,IAAI,IAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,YAAG,UAAU,GAAQ,IAC3E,CACP,CAAA;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StateAggregator } from '../core/state-aggregator.js';
|
|
2
|
+
interface DashboardProps {
|
|
3
|
+
readonly aggregator: StateAggregator;
|
|
4
|
+
readonly budget: number | null;
|
|
5
|
+
readonly hardLimit: boolean;
|
|
6
|
+
readonly sessionPath: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function Dashboard({ aggregator, budget, hardLimit, sessionPath }: DashboardProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=Dashboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Dashboard.d.ts","sourceRoot":"","sources":["../../src/ui/Dashboard.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AASlE,UAAU,cAAc;IACtB,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,wBAAgB,SAAS,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,cAAc,2CAmHvF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Dashboard:ink 主畫面 — 組合所有 panel
|
|
4
|
+
*
|
|
5
|
+
* 200ms render throttle 由 ink 自身處理(React reconciliation)
|
|
6
|
+
* 這裡只負責 state → UI 映射
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useEffect } from 'react';
|
|
9
|
+
import { Box, Text, useApp, useInput } from 'ink';
|
|
10
|
+
import { formatCost, totalTokenCount, formatDuration } from '../core/pricing.js';
|
|
11
|
+
import { AgentPanel } from './AgentPanel.js';
|
|
12
|
+
import { TaskPanel } from './TaskPanel.js';
|
|
13
|
+
import { CostBar } from './CostBar.js';
|
|
14
|
+
import { AlertBanner } from './AlertBanner.js';
|
|
15
|
+
import { CompletionBanner } from './CompletionBanner.js';
|
|
16
|
+
export function Dashboard({ aggregator, budget, hardLimit, sessionPath }) {
|
|
17
|
+
const { exit } = useApp();
|
|
18
|
+
const [state, setState] = useState(aggregator.getState());
|
|
19
|
+
const [teamDeleted, setTeamDeleted] = useState(false);
|
|
20
|
+
const [isCompleted, setIsCompleted] = useState(false);
|
|
21
|
+
// 監聽 state events → trigger re-render
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
let lastUpdate = 0;
|
|
24
|
+
const THROTTLE = 200;
|
|
25
|
+
const handler = (event) => {
|
|
26
|
+
if (event.type === 'team_deleted') {
|
|
27
|
+
setTeamDeleted(true);
|
|
28
|
+
setState(aggregator.getState());
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// watcher_error 不需要 throttle
|
|
32
|
+
if (event.type === 'watcher_error') {
|
|
33
|
+
setState(aggregator.getState());
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const now = Date.now();
|
|
37
|
+
if (now - lastUpdate < THROTTLE)
|
|
38
|
+
return;
|
|
39
|
+
lastUpdate = now;
|
|
40
|
+
setState(aggregator.getState());
|
|
41
|
+
};
|
|
42
|
+
aggregator.on('event', handler);
|
|
43
|
+
// 定期更新 elapsed time
|
|
44
|
+
const timer = setInterval(() => {
|
|
45
|
+
setState(aggregator.getState());
|
|
46
|
+
}, 2000);
|
|
47
|
+
return () => {
|
|
48
|
+
aggregator.removeListener('event', handler);
|
|
49
|
+
clearInterval(timer);
|
|
50
|
+
};
|
|
51
|
+
}, [aggregator]);
|
|
52
|
+
// 檢查是否所有 task 都完成
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (state.tasks.length > 0) {
|
|
55
|
+
const allDone = state.tasks.every(t => t.status === 'completed' || t.status === 'deleted');
|
|
56
|
+
if (allDone && !isCompleted) {
|
|
57
|
+
setIsCompleted(true);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}, [state.tasks, isCompleted]);
|
|
61
|
+
// 鍵盤:q 或 Escape → 通知 ink 退出
|
|
62
|
+
useInput((input, key) => {
|
|
63
|
+
if (input === 'q' || key.escape) {
|
|
64
|
+
exit();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
const elapsed = formatDuration(state.elapsedMs);
|
|
68
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Text, { bold: true, children: ["ccx watch: ", state.teamName, " (", elapsed, ")"] }), _jsxs(Text, { color: "cyan", children: ["Cost: ", formatCost(state.totalCost)] })] }), _jsx(Text, { dimColor: true, children: '─'.repeat(72) }), _jsx(CostBar, { currentCost: state.totalCost, budget: budget, hardLimit: hardLimit }), _jsx(AgentPanel, { agents: state.agents, totalCost: state.totalCost, totalTokens: totalTokenCount(state.totalTokens) }), _jsx(Text, { children: " " }), _jsx(TaskPanel, { tasks: state.tasks }), _jsx(Text, { children: " " }), _jsx(AlertBanner, { alerts: state.alerts }), teamDeleted && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "yellow", bold: true, children: ["Team has been deleted. Snapshot saved to: ", sessionPath] }) })), isCompleted && !teamDeleted && (_jsx(Box, { marginTop: 1, children: _jsx(CompletionBanner, { completedAt: new Date().toLocaleTimeString(), elapsed: elapsed, totalCost: state.totalCost }) })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Press q to quit | Snapshot: ", sessionPath] }) })] }));
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=Dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Dashboard.js","sourceRoot":"","sources":["../../src/ui/Dashboard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TaskPanel:顯示 task 列表 + dependency + elapsed time
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import type { TaskData } from '../core/types.js';
|
|
6
|
+
interface TaskPanelProps {
|
|
7
|
+
readonly tasks: readonly TaskData[];
|
|
8
|
+
}
|
|
9
|
+
export declare const TaskPanel: React.NamedExoticComponent<TaskPanelProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=TaskPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskPanel.d.ts","sourceRoot":"","sources":["../../src/ui/TaskPanel.tsx"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAe,MAAM,OAAO,CAAA;AAEnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEhD,UAAU,cAAc;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAA;CACpC;AAED,eAAO,MAAM,SAAS,4CAWpB,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* TaskPanel:顯示 task 列表 + dependency + elapsed time
|
|
4
|
+
*/
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Box, Text } from 'ink';
|
|
7
|
+
export const TaskPanel = memo(function TaskPanel({ tasks }) {
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "TASKS" }), tasks.length === 0 ? (_jsx(Text, { dimColor: true, children: " (no tasks)" })) : (tasks.map(task => _jsx(TaskRow, { task: task }, task.id)))] }));
|
|
9
|
+
});
|
|
10
|
+
const TaskRow = memo(function TaskRow({ task }) {
|
|
11
|
+
const id = `#${task.id}`;
|
|
12
|
+
const subject = truncate(task.subject, 30);
|
|
13
|
+
const owner = task.owner || '──';
|
|
14
|
+
const blocked = task.blockedBy.length > 0
|
|
15
|
+
? `needs #${task.blockedBy.join(',#')}`
|
|
16
|
+
: '──';
|
|
17
|
+
return (_jsxs(Box, { children: [_jsx(Text, { children: pad(id, 6) }), _jsx(TaskStatusBadge, { status: task.status }), _jsxs(Text, { children: [" ", pad(subject, 32)] }), _jsx(Text, { dimColor: true, children: pad(owner, 18) }), task.blockedBy.length > 0 && _jsx(Text, { color: "yellow", children: blocked })] }));
|
|
18
|
+
});
|
|
19
|
+
function TaskStatusBadge({ status }) {
|
|
20
|
+
switch (status) {
|
|
21
|
+
case 'in_progress':
|
|
22
|
+
return _jsx(Text, { color: "green", children: pad('[working]', 12) });
|
|
23
|
+
case 'completed':
|
|
24
|
+
return _jsx(Text, { color: "blue", children: pad('[done]', 12) });
|
|
25
|
+
case 'pending':
|
|
26
|
+
return _jsx(Text, { dimColor: true, children: pad('[pending]', 12) });
|
|
27
|
+
default:
|
|
28
|
+
return _jsx(Text, { dimColor: true, children: pad(`[${status}]`, 12) });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function pad(str, width) {
|
|
32
|
+
if (str.length >= width)
|
|
33
|
+
return str.slice(0, width);
|
|
34
|
+
return str + ' '.repeat(width - str.length);
|
|
35
|
+
}
|
|
36
|
+
function truncate(str, maxLen) {
|
|
37
|
+
if (str.length <= maxLen)
|
|
38
|
+
return str;
|
|
39
|
+
return str.slice(0, maxLen - 3) + '...';
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=TaskPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaskPanel.js","sourceRoot":"","sources":["../../src/ui/TaskPanel.tsx"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@damaall/ccx",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent Teams control plane for Claude Code — observability, cost tracking, and team topology reuse",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ccx": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsx src/index.ts",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"test:watch": "vitest",
|
|
19
|
+
"lint": "tsc --noEmit",
|
|
20
|
+
"prepublishOnly": "npm run lint && npm run test && npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"claude-code",
|
|
24
|
+
"claude",
|
|
25
|
+
"agent-teams",
|
|
26
|
+
"monitoring",
|
|
27
|
+
"dashboard",
|
|
28
|
+
"observability",
|
|
29
|
+
"cost-tracking",
|
|
30
|
+
"cli"
|
|
31
|
+
],
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/DamaAll/ccx.git"
|
|
35
|
+
},
|
|
36
|
+
"author": "DamaAll",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"chalk": "^5.4.1",
|
|
46
|
+
"chokidar": "^4.0.3",
|
|
47
|
+
"commander": "^13.1.0",
|
|
48
|
+
"ink": "^5.2.1",
|
|
49
|
+
"ink-spinner": "^5.0.0",
|
|
50
|
+
"react": "^18.3.1",
|
|
51
|
+
"yaml": "^2.7.0",
|
|
52
|
+
"zod": "^3.24.2"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^22.13.4",
|
|
56
|
+
"@types/react": "^18.3.28",
|
|
57
|
+
"tsx": "^4.19.2",
|
|
58
|
+
"typescript": "^5.7.3",
|
|
59
|
+
"vitest": "^3.0.5"
|
|
60
|
+
}
|
|
61
|
+
}
|