@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,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 資料來源適配層:zod schema validation + 容錯 JSON 解析
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
// ─── Zod Schemas ───
|
|
6
|
+
export const TeamMemberSchema = z.object({
|
|
7
|
+
agentId: z.string(),
|
|
8
|
+
name: z.string(),
|
|
9
|
+
agentType: z.string(),
|
|
10
|
+
model: z.string().default('claude-opus-4-6'),
|
|
11
|
+
joinedAt: z.number(),
|
|
12
|
+
tmuxPaneId: z.string().default(''),
|
|
13
|
+
cwd: z.string().default(''),
|
|
14
|
+
subscriptions: z.array(z.string()).default([]),
|
|
15
|
+
});
|
|
16
|
+
export const TeamConfigSchema = z.object({
|
|
17
|
+
name: z.string(),
|
|
18
|
+
description: z.string().default(''),
|
|
19
|
+
createdAt: z.number(),
|
|
20
|
+
leadAgentId: z.string(),
|
|
21
|
+
leadSessionId: z.string(),
|
|
22
|
+
members: z.array(TeamMemberSchema).default([]),
|
|
23
|
+
});
|
|
24
|
+
export const TaskDataSchema = z.object({
|
|
25
|
+
id: z.string(),
|
|
26
|
+
subject: z.string().default(''),
|
|
27
|
+
description: z.string().default(''),
|
|
28
|
+
activeForm: z.string().default(''),
|
|
29
|
+
owner: z.string().default(''),
|
|
30
|
+
status: z.enum(['pending', 'in_progress', 'completed', 'deleted']).default('pending'),
|
|
31
|
+
blocks: z.array(z.string()).default([]),
|
|
32
|
+
blockedBy: z.array(z.string()).default([]),
|
|
33
|
+
});
|
|
34
|
+
export const InboxMessageSchema = z.object({
|
|
35
|
+
from: z.string(),
|
|
36
|
+
text: z.string().default(''),
|
|
37
|
+
summary: z.string().default(''),
|
|
38
|
+
timestamp: z.string(),
|
|
39
|
+
color: z.string().default(''),
|
|
40
|
+
read: z.boolean().default(false),
|
|
41
|
+
});
|
|
42
|
+
export const JournalEntrySchema = z.object({
|
|
43
|
+
sessionId: z.string().optional(),
|
|
44
|
+
agentId: z.string().optional(),
|
|
45
|
+
timestamp: z.string(),
|
|
46
|
+
message: z.object({
|
|
47
|
+
model: z.string().default('claude-opus-4-6'),
|
|
48
|
+
usage: z.object({
|
|
49
|
+
input_tokens: z.number().default(0),
|
|
50
|
+
output_tokens: z.number().default(0),
|
|
51
|
+
cache_creation_input_tokens: z.number().default(0),
|
|
52
|
+
cache_read_input_tokens: z.number().default(0),
|
|
53
|
+
}),
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
// ─── 容錯 JSON 解析 ───
|
|
57
|
+
export function safeParseJson(raw, schema) {
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(raw);
|
|
60
|
+
const result = schema.safeParse(parsed);
|
|
61
|
+
if (result.success) {
|
|
62
|
+
return { ok: true, data: result.data };
|
|
63
|
+
}
|
|
64
|
+
return { ok: false, error: result.error.message };
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
return { ok: false, error: e instanceof Error ? e.message : 'JSON parse failed' };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export function safeParseJsonArray(raw, itemSchema) {
|
|
71
|
+
return safeParseJson(raw, z.array(itemSchema));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 解析 JSONL 的單一行 — 忽略不完整的行
|
|
75
|
+
*/
|
|
76
|
+
export function parseJournalLine(line) {
|
|
77
|
+
const trimmed = line.trim();
|
|
78
|
+
if (trimmed.length === 0)
|
|
79
|
+
return { ok: false };
|
|
80
|
+
const result = safeParseJson(trimmed, JournalEntrySchema);
|
|
81
|
+
if (result.ok)
|
|
82
|
+
return { ok: true, data: result.data };
|
|
83
|
+
return { ok: false };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=data-source-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-source-adapter.js","sourceRoot":"","sources":["../../src/core/data-source-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IdentityResolver:從 JSONL raw content 確定性匹配 agentId → agent name
|
|
3
|
+
*
|
|
4
|
+
* 映射路徑:
|
|
5
|
+
* 1. 掃描 JSONL 行的 raw text,找 `teammate_id="<name>"` pattern
|
|
6
|
+
* 2. 一旦找到 → 標記為 RESOLVED
|
|
7
|
+
* 3. 交叉比對 inbox 檔名確認
|
|
8
|
+
*
|
|
9
|
+
* 關鍵:teammate_id 在 message.content 裡,不在 parsed JournalEntry 裡
|
|
10
|
+
* 所以必須用 raw line text 而非 parsed entry
|
|
11
|
+
*/
|
|
12
|
+
import type { FileCursor } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* 嘗試從 raw JSONL lines 中解析 agent name
|
|
15
|
+
* 在 UNRESOLVED 狀態下,每次 CursorReader 讀到新行時呼叫
|
|
16
|
+
*/
|
|
17
|
+
export declare function tryResolveFromRawLines(cursor: FileCursor, rawLines: readonly string[]): FileCursor;
|
|
18
|
+
/**
|
|
19
|
+
* Batch resolve:startup 時對所有 cursors 做一次全量匹配
|
|
20
|
+
* rawLinesMap: agentId → raw lines from full scan
|
|
21
|
+
*/
|
|
22
|
+
export declare function batchResolve(cursors: readonly FileCursor[], rawLinesMap: ReadonlyMap<string, readonly string[]>): FileCursor[];
|
|
23
|
+
/**
|
|
24
|
+
* 為 UNRESOLVED cursor 生成顯示名稱
|
|
25
|
+
*/
|
|
26
|
+
export declare function getDisplayName(cursor: FileCursor): string;
|
|
27
|
+
//# sourceMappingURL=identity-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-resolver.d.ts","sourceRoot":"","sources":["../../src/core/identity-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAM5C;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,UAAU,CAWZ;AAgBD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,GAClD,UAAU,EAAE,CAUd;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAGzD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { resolveCursorIdentity } from './cursor-reader.js';
|
|
2
|
+
// 匹配 teammate_id=\"name\" 或 teammate_id="name"
|
|
3
|
+
const TEAMMATE_ID_RE = /teammate_id\\?"?=?\\?"([a-zA-Z0-9_-]+)\\?"/;
|
|
4
|
+
/**
|
|
5
|
+
* 嘗試從 raw JSONL lines 中解析 agent name
|
|
6
|
+
* 在 UNRESOLVED 狀態下,每次 CursorReader 讀到新行時呼叫
|
|
7
|
+
*/
|
|
8
|
+
export function tryResolveFromRawLines(cursor, rawLines) {
|
|
9
|
+
if (cursor.state === 'RESOLVED')
|
|
10
|
+
return cursor;
|
|
11
|
+
for (const line of rawLines) {
|
|
12
|
+
const name = extractTeammateIdFromRaw(line);
|
|
13
|
+
if (name) {
|
|
14
|
+
return resolveCursorIdentity(cursor, name);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return cursor;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 從 raw JSONL line text 中提取 teammate_id
|
|
21
|
+
*
|
|
22
|
+
* JSONL 行範例(已 JSON-escaped):
|
|
23
|
+
* {...,"content":"<teammate-message teammate_id=\"syntax-fixer\" color=\"blue\">\n..."}
|
|
24
|
+
*/
|
|
25
|
+
function extractTeammateIdFromRaw(line) {
|
|
26
|
+
const match = line.match(TEAMMATE_ID_RE);
|
|
27
|
+
if (match && match[1]) {
|
|
28
|
+
return match[1];
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Batch resolve:startup 時對所有 cursors 做一次全量匹配
|
|
34
|
+
* rawLinesMap: agentId → raw lines from full scan
|
|
35
|
+
*/
|
|
36
|
+
export function batchResolve(cursors, rawLinesMap) {
|
|
37
|
+
return cursors.map(cursor => {
|
|
38
|
+
if (cursor.state === 'RESOLVED')
|
|
39
|
+
return cursor;
|
|
40
|
+
const rawLines = rawLinesMap.get(cursor.agentId);
|
|
41
|
+
if (rawLines) {
|
|
42
|
+
return tryResolveFromRawLines(cursor, rawLines);
|
|
43
|
+
}
|
|
44
|
+
return cursor;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 為 UNRESOLVED cursor 生成顯示名稱
|
|
49
|
+
*/
|
|
50
|
+
export function getDisplayName(cursor) {
|
|
51
|
+
if (cursor.resolvedName)
|
|
52
|
+
return cursor.resolvedName;
|
|
53
|
+
return `agent-${cursor.agentId}`;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=identity-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-resolver.js","sourceRoot":"","sources":["../../src/core/identity-resolver.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAE1D,+CAA+C;AAC/C,MAAM,cAAc,GAAG,4CAA4C,CAAA;AAEnE;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAkB,EAClB,QAA2B;IAE3B,IAAI,MAAM,CAAC,KAAK,KAAK,UAAU;QAAE,OAAO,MAAM,CAAA;IAE9C,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAA;QAC3C,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,wBAAwB,CAAC,IAAY;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;IACxC,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,OAA8B,EAC9B,WAAmD;IAEnD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;QAC1B,IAAI,MAAM,CAAC,KAAK,KAAK,UAAU;YAAE,OAAO,MAAM,CAAA;QAE9C,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAChD,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,sBAAsB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACjD,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,IAAI,MAAM,CAAC,YAAY;QAAE,OAAO,MAAM,CAAC,YAAY,CAAA;IACnD,OAAO,SAAS,MAAM,CAAC,OAAO,EAAE,CAAA;AAClC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { InboxMessage, AgentStatus } from './types.js';
|
|
2
|
+
export interface InboxData {
|
|
3
|
+
readonly agentName: string;
|
|
4
|
+
readonly messages: readonly InboxMessage[];
|
|
5
|
+
readonly lastMessage: InboxMessage | null;
|
|
6
|
+
readonly inferredStatus: AgentStatus;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 讀取單一 agent 的 inbox
|
|
10
|
+
*/
|
|
11
|
+
export declare function readInbox(teamName: string, agentName: string): Promise<InboxData | null>;
|
|
12
|
+
/**
|
|
13
|
+
* 讀取 team 所有 inbox
|
|
14
|
+
*/
|
|
15
|
+
export declare function readAllInboxes(teamName: string): Promise<InboxData[]>;
|
|
16
|
+
/**
|
|
17
|
+
* 從 inbox messages 列出所有 agent 名稱
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractAgentNamesFromInboxes(inboxes: readonly InboxData[]): string[];
|
|
20
|
+
//# sourceMappingURL=inbox-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-reader.d.ts","sourceRoot":"","sources":["../../src/core/inbox-reader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE3D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAA;IAC1C,QAAQ,CAAC,WAAW,EAAE,YAAY,GAAG,IAAI,CAAA;IACzC,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAA;CACrC;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAe9F;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAe3E;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,EAAE,CASpF"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InboxReader:讀取 ~/.claude/teams/{team}/inboxes/*.json
|
|
3
|
+
* 從 inbox messages 推斷 agent 狀態
|
|
4
|
+
*/
|
|
5
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
6
|
+
import { claudePaths } from './paths.js';
|
|
7
|
+
import { InboxMessageSchema, safeParseJsonArray } from './data-source-adapter.js';
|
|
8
|
+
/**
|
|
9
|
+
* 讀取單一 agent 的 inbox
|
|
10
|
+
*/
|
|
11
|
+
export async function readInbox(teamName, agentName) {
|
|
12
|
+
const inboxPath = claudePaths.teamInbox(teamName, agentName);
|
|
13
|
+
try {
|
|
14
|
+
const raw = await readFile(inboxPath, 'utf-8');
|
|
15
|
+
const result = safeParseJsonArray(raw, InboxMessageSchema);
|
|
16
|
+
if (!result.ok)
|
|
17
|
+
return null;
|
|
18
|
+
const messages = result.data;
|
|
19
|
+
const lastMessage = messages.length > 0 ? messages[messages.length - 1] : null;
|
|
20
|
+
const inferredStatus = inferStatusFromMessages(messages);
|
|
21
|
+
return { agentName, messages, lastMessage, inferredStatus };
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 讀取 team 所有 inbox
|
|
29
|
+
*/
|
|
30
|
+
export async function readAllInboxes(teamName) {
|
|
31
|
+
const dir = claudePaths.teamInboxes(teamName);
|
|
32
|
+
try {
|
|
33
|
+
const entries = await readdir(dir);
|
|
34
|
+
const jsonFiles = entries.filter(f => f.endsWith('.json'));
|
|
35
|
+
const inboxes = await Promise.all(jsonFiles.map(async (filename) => {
|
|
36
|
+
const agentName = filename.replace('.json', '');
|
|
37
|
+
return readInbox(teamName, agentName);
|
|
38
|
+
}));
|
|
39
|
+
return inboxes.filter((i) => i !== null);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 從 inbox messages 列出所有 agent 名稱
|
|
47
|
+
*/
|
|
48
|
+
export function extractAgentNamesFromInboxes(inboxes) {
|
|
49
|
+
const names = new Set();
|
|
50
|
+
for (const inbox of inboxes) {
|
|
51
|
+
names.add(inbox.agentName);
|
|
52
|
+
for (const msg of inbox.messages) {
|
|
53
|
+
if (msg.from)
|
|
54
|
+
names.add(msg.from);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return [...names].sort();
|
|
58
|
+
}
|
|
59
|
+
// ─── 狀態推斷 ───
|
|
60
|
+
function inferStatusFromMessages(messages) {
|
|
61
|
+
if (messages.length === 0)
|
|
62
|
+
return 'unknown';
|
|
63
|
+
// 從最後一條往前找 type 線索
|
|
64
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
65
|
+
const msgType = parseMessageType(messages[i].text);
|
|
66
|
+
if (msgType) {
|
|
67
|
+
return mapMessageTypeToStatus(msgType);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return 'unknown';
|
|
71
|
+
}
|
|
72
|
+
function parseMessageType(text) {
|
|
73
|
+
// inbox messages 裡的 text 可能包含 JSON,也可能是純文字
|
|
74
|
+
// 嘗試解析 JSON 中的 type 欄位
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(text);
|
|
77
|
+
if (typeof parsed === 'object' && parsed !== null && 'type' in parsed) {
|
|
78
|
+
return parsed.type;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// 純文字 — 用關鍵字比對
|
|
83
|
+
}
|
|
84
|
+
if (text.includes('idle'))
|
|
85
|
+
return 'idle_notification';
|
|
86
|
+
if (text.includes('shutdown_approved') || text.includes('shutdown approved'))
|
|
87
|
+
return 'shutdown_approved';
|
|
88
|
+
if (text.includes('shutdown'))
|
|
89
|
+
return 'shutdown_request';
|
|
90
|
+
if (text.includes('task_completed') || text.includes('完成'))
|
|
91
|
+
return 'task_completed';
|
|
92
|
+
if (text.includes('task_assignment'))
|
|
93
|
+
return 'task_assignment';
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
function mapMessageTypeToStatus(msgType) {
|
|
97
|
+
switch (msgType) {
|
|
98
|
+
case 'idle_notification': return 'idle';
|
|
99
|
+
case 'shutdown_approved': return 'shutdown';
|
|
100
|
+
case 'shutdown_request': return 'idle'; // 收到 shutdown request 但還沒 approve
|
|
101
|
+
case 'task_assignment': return 'working';
|
|
102
|
+
case 'task_completed': return 'done';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=inbox-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-reader.js","sourceRoot":"","sources":["../../src/core/inbox-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const claudePaths: {
|
|
2
|
+
readonly root: string;
|
|
3
|
+
readonly teams: string;
|
|
4
|
+
readonly tasks: string;
|
|
5
|
+
readonly projects: string;
|
|
6
|
+
readonly teamConfig: (teamName: string) => string;
|
|
7
|
+
readonly teamInboxes: (teamName: string) => string;
|
|
8
|
+
readonly teamInbox: (teamName: string, agentName: string) => string;
|
|
9
|
+
readonly teamTasks: (teamName: string) => string;
|
|
10
|
+
readonly teamTask: (teamName: string, taskId: string) => string;
|
|
11
|
+
readonly subagents: (projectPath: string, sessionId: string) => string;
|
|
12
|
+
readonly subagentFile: (projectPath: string, sessionId: string, agentId: string) => string;
|
|
13
|
+
};
|
|
14
|
+
export declare const ccxPaths: {
|
|
15
|
+
readonly root: string;
|
|
16
|
+
readonly sessions: string;
|
|
17
|
+
readonly checkpoints: string;
|
|
18
|
+
readonly config: string;
|
|
19
|
+
readonly session: (sessionName: string) => string;
|
|
20
|
+
readonly sessionMeta: (sessionName: string) => string;
|
|
21
|
+
readonly sessionTokens: (sessionName: string) => string;
|
|
22
|
+
readonly sessionTasks: (sessionName: string) => string;
|
|
23
|
+
readonly sessionAlerts: (sessionName: string) => string;
|
|
24
|
+
readonly checkpoint: (fileHash: string) => string;
|
|
25
|
+
};
|
|
26
|
+
export declare function validateName(name: string): boolean;
|
|
27
|
+
export declare function assertSafeName(name: string, label: string): void;
|
|
28
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,WAAW;;;;;oCAMC,MAAM,KAAG,MAAM;qCAGd,MAAM,KAAG,MAAM;mCAGjB,MAAM,aAAa,MAAM,KAAG,MAAM;mCAGlC,MAAM,KAAG,MAAM;kCAGhB,MAAM,UAAU,MAAM,KAAG,MAAM;sCAG3B,MAAM,aAAa,MAAM,KAAG,MAAM;yCAG/B,MAAM,aAAa,MAAM,WAAW,MAAM,KAAG,MAAM;CAEvE,CAAA;AAMV,eAAO,MAAM,QAAQ;;;;;oCAMI,MAAM,KAAG,MAAM;wCAGX,MAAM,KAAG,MAAM;0CAGb,MAAM,KAAG,MAAM;yCAGhB,MAAM,KAAG,MAAM;0CAGd,MAAM,KAAG,MAAM;oCAGrB,MAAM,KAAG,MAAM;CAE9B,CAAA;AAMV,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAMhE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路徑解析:~/.claude/* 和 ~/.ccx/* 的標準路徑
|
|
3
|
+
*/
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
const HOME = homedir();
|
|
7
|
+
// ─── Claude Code 路徑 ───
|
|
8
|
+
const CLAUDE_HOME = join(HOME, '.claude');
|
|
9
|
+
export const claudePaths = {
|
|
10
|
+
root: CLAUDE_HOME,
|
|
11
|
+
teams: join(CLAUDE_HOME, 'teams'),
|
|
12
|
+
tasks: join(CLAUDE_HOME, 'tasks'),
|
|
13
|
+
projects: join(CLAUDE_HOME, 'projects'),
|
|
14
|
+
teamConfig: (teamName) => join(CLAUDE_HOME, 'teams', teamName, 'config.json'),
|
|
15
|
+
teamInboxes: (teamName) => join(CLAUDE_HOME, 'teams', teamName, 'inboxes'),
|
|
16
|
+
teamInbox: (teamName, agentName) => join(CLAUDE_HOME, 'teams', teamName, 'inboxes', `${agentName}.json`),
|
|
17
|
+
teamTasks: (teamName) => join(CLAUDE_HOME, 'tasks', teamName),
|
|
18
|
+
teamTask: (teamName, taskId) => join(CLAUDE_HOME, 'tasks', teamName, `${taskId}.json`),
|
|
19
|
+
subagents: (projectPath, sessionId) => join(CLAUDE_HOME, 'projects', projectPath, sessionId, 'subagents'),
|
|
20
|
+
subagentFile: (projectPath, sessionId, agentId) => join(CLAUDE_HOME, 'projects', projectPath, sessionId, 'subagents', `agent-${agentId}.jsonl`),
|
|
21
|
+
};
|
|
22
|
+
// ─── ccx 路徑 ───
|
|
23
|
+
const CCX_HOME = join(HOME, '.ccx');
|
|
24
|
+
export const ccxPaths = {
|
|
25
|
+
root: CCX_HOME,
|
|
26
|
+
sessions: join(CCX_HOME, 'sessions'),
|
|
27
|
+
checkpoints: join(CCX_HOME, 'checkpoints'),
|
|
28
|
+
config: join(CCX_HOME, 'config.yaml'),
|
|
29
|
+
session: (sessionName) => join(CCX_HOME, 'sessions', sessionName),
|
|
30
|
+
sessionMeta: (sessionName) => join(CCX_HOME, 'sessions', sessionName, 'meta.yaml'),
|
|
31
|
+
sessionTokens: (sessionName) => join(CCX_HOME, 'sessions', sessionName, 'tokens.yaml'),
|
|
32
|
+
sessionTasks: (sessionName) => join(CCX_HOME, 'sessions', sessionName, 'tasks.yaml'),
|
|
33
|
+
sessionAlerts: (sessionName) => join(CCX_HOME, 'sessions', sessionName, 'alerts.yaml'),
|
|
34
|
+
checkpoint: (fileHash) => join(CCX_HOME, 'checkpoints', `${fileHash}.json`),
|
|
35
|
+
};
|
|
36
|
+
// ─── 名稱驗證 ───
|
|
37
|
+
const SAFE_NAME_RE = /^[a-zA-Z0-9._-]+$/;
|
|
38
|
+
export function validateName(name) {
|
|
39
|
+
return SAFE_NAME_RE.test(name) && name.length > 0 && name.length <= 128;
|
|
40
|
+
}
|
|
41
|
+
export function assertSafeName(name, label) {
|
|
42
|
+
if (!validateName(name)) {
|
|
43
|
+
throw new Error(`Invalid ${label}: "${name}". Must match [a-zA-Z0-9._-] and be 1-128 chars.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude model pricing table (USD per 1M tokens)
|
|
3
|
+
*/
|
|
4
|
+
import type { TokenUsage } from './types.js';
|
|
5
|
+
export declare function resolveModelName(model: string): string;
|
|
6
|
+
export declare function getModelShortName(model: string): string;
|
|
7
|
+
export declare function calculateCost(model: string, usage: TokenUsage): number;
|
|
8
|
+
export declare function formatCost(usd: number): string;
|
|
9
|
+
export declare function formatTokens(count: number): string;
|
|
10
|
+
export declare const emptyUsage: () => TokenUsage;
|
|
11
|
+
export declare function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
|
|
12
|
+
export declare function totalTokenCount(usage: TokenUsage): number;
|
|
13
|
+
/**
|
|
14
|
+
* 格式化持續時間(ms → 人類可讀)
|
|
15
|
+
* < 60s: "45s"
|
|
16
|
+
* < 1h: "12m 30s"
|
|
17
|
+
* < 24h: "5h 30m"
|
|
18
|
+
* >= 24h: "3d 18h"
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatDuration(ms: number): string;
|
|
21
|
+
/**
|
|
22
|
+
* 格式化「距今多久」(timestamp → 人類可讀)
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatTimeSince(timestamp: number): string;
|
|
25
|
+
//# sourceMappingURL=pricing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/core/pricing.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAqC5C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAWtE;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,UAK7B,CAAA;AAEF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAOjE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAOzD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAWjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const PRICING = {
|
|
2
|
+
'claude-opus-4-6': {
|
|
3
|
+
inputPerMillion: 15,
|
|
4
|
+
outputPerMillion: 75,
|
|
5
|
+
cacheWritePerMillion: 18.75,
|
|
6
|
+
cacheReadPerMillion: 1.5,
|
|
7
|
+
},
|
|
8
|
+
'claude-sonnet-4-5-20250929': {
|
|
9
|
+
inputPerMillion: 3,
|
|
10
|
+
outputPerMillion: 15,
|
|
11
|
+
cacheWritePerMillion: 3.75,
|
|
12
|
+
cacheReadPerMillion: 0.3,
|
|
13
|
+
},
|
|
14
|
+
'claude-haiku-4-5-20251001': {
|
|
15
|
+
inputPerMillion: 0.8,
|
|
16
|
+
outputPerMillion: 4,
|
|
17
|
+
cacheWritePerMillion: 1,
|
|
18
|
+
cacheReadPerMillion: 0.08,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
// 短名稱對照
|
|
22
|
+
const MODEL_ALIASES = {
|
|
23
|
+
opus: 'claude-opus-4-6',
|
|
24
|
+
sonnet: 'claude-sonnet-4-5-20250929',
|
|
25
|
+
haiku: 'claude-haiku-4-5-20251001',
|
|
26
|
+
};
|
|
27
|
+
export function resolveModelName(model) {
|
|
28
|
+
return MODEL_ALIASES[model] ?? model;
|
|
29
|
+
}
|
|
30
|
+
export function getModelShortName(model) {
|
|
31
|
+
if (model.includes('opus'))
|
|
32
|
+
return 'opus';
|
|
33
|
+
if (model.includes('sonnet'))
|
|
34
|
+
return 'sonnet';
|
|
35
|
+
if (model.includes('haiku'))
|
|
36
|
+
return 'haiku';
|
|
37
|
+
return model;
|
|
38
|
+
}
|
|
39
|
+
export function calculateCost(model, usage) {
|
|
40
|
+
const resolved = resolveModelName(model);
|
|
41
|
+
const pricing = PRICING[resolved];
|
|
42
|
+
if (!pricing)
|
|
43
|
+
return 0;
|
|
44
|
+
return ((usage.input_tokens * pricing.inputPerMillion) / 1_000_000 +
|
|
45
|
+
(usage.output_tokens * pricing.outputPerMillion) / 1_000_000 +
|
|
46
|
+
(usage.cache_creation_input_tokens * pricing.cacheWritePerMillion) / 1_000_000 +
|
|
47
|
+
(usage.cache_read_input_tokens * pricing.cacheReadPerMillion) / 1_000_000);
|
|
48
|
+
}
|
|
49
|
+
export function formatCost(usd) {
|
|
50
|
+
if (usd < 0.01)
|
|
51
|
+
return `$${usd.toFixed(4)}`;
|
|
52
|
+
return `$${usd.toFixed(2)}`;
|
|
53
|
+
}
|
|
54
|
+
export function formatTokens(count) {
|
|
55
|
+
if (count >= 1_000_000)
|
|
56
|
+
return `${(count / 1_000_000).toFixed(1)}M`;
|
|
57
|
+
if (count >= 1_000)
|
|
58
|
+
return `${(count / 1_000).toFixed(1)}k`;
|
|
59
|
+
return `${count}`;
|
|
60
|
+
}
|
|
61
|
+
export const emptyUsage = () => ({
|
|
62
|
+
input_tokens: 0,
|
|
63
|
+
output_tokens: 0,
|
|
64
|
+
cache_creation_input_tokens: 0,
|
|
65
|
+
cache_read_input_tokens: 0,
|
|
66
|
+
});
|
|
67
|
+
export function addUsage(a, b) {
|
|
68
|
+
return {
|
|
69
|
+
input_tokens: a.input_tokens + b.input_tokens,
|
|
70
|
+
output_tokens: a.output_tokens + b.output_tokens,
|
|
71
|
+
cache_creation_input_tokens: a.cache_creation_input_tokens + b.cache_creation_input_tokens,
|
|
72
|
+
cache_read_input_tokens: a.cache_read_input_tokens + b.cache_read_input_tokens,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function totalTokenCount(usage) {
|
|
76
|
+
return (usage.input_tokens +
|
|
77
|
+
usage.output_tokens +
|
|
78
|
+
usage.cache_creation_input_tokens +
|
|
79
|
+
usage.cache_read_input_tokens);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 格式化持續時間(ms → 人類可讀)
|
|
83
|
+
* < 60s: "45s"
|
|
84
|
+
* < 1h: "12m 30s"
|
|
85
|
+
* < 24h: "5h 30m"
|
|
86
|
+
* >= 24h: "3d 18h"
|
|
87
|
+
*/
|
|
88
|
+
export function formatDuration(ms) {
|
|
89
|
+
const totalSec = Math.floor(ms / 1000);
|
|
90
|
+
const days = Math.floor(totalSec / 86400);
|
|
91
|
+
const hours = Math.floor((totalSec % 86400) / 3600);
|
|
92
|
+
const mins = Math.floor((totalSec % 3600) / 60);
|
|
93
|
+
const secs = totalSec % 60;
|
|
94
|
+
if (days > 0)
|
|
95
|
+
return `${days}d ${hours}h`;
|
|
96
|
+
if (hours > 0)
|
|
97
|
+
return `${hours}h ${mins}m`;
|
|
98
|
+
if (mins > 0)
|
|
99
|
+
return `${mins}m ${secs}s`;
|
|
100
|
+
return `${secs}s`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 格式化「距今多久」(timestamp → 人類可讀)
|
|
104
|
+
*/
|
|
105
|
+
export function formatTimeSince(timestamp) {
|
|
106
|
+
return formatDuration(Date.now() - timestamp);
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/core/pricing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret Redaction:在 CursorReader 層移除敏感資料
|
|
3
|
+
*
|
|
4
|
+
* 套用時機:raw line 進入 ring buffer 之前
|
|
5
|
+
* 即使 --show-content 也會 redact
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 對單一字串做 secret redaction
|
|
9
|
+
*/
|
|
10
|
+
export declare function redactSecrets(text: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* 檢查字串是否包含可能的 secrets
|
|
13
|
+
*/
|
|
14
|
+
export declare function containsSecrets(text: string): boolean;
|
|
15
|
+
//# sourceMappingURL=redact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/core/redact.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkCH;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMrD"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret Redaction:在 CursorReader 層移除敏感資料
|
|
3
|
+
*
|
|
4
|
+
* 套用時機:raw line 進入 ring buffer 之前
|
|
5
|
+
* 即使 --show-content 也會 redact
|
|
6
|
+
*/
|
|
7
|
+
const REDACTION_PLACEHOLDER = '[REDACTED]';
|
|
8
|
+
const SECRET_PATTERNS = [
|
|
9
|
+
// Anthropic API keys
|
|
10
|
+
/sk-ant-[a-zA-Z0-9_-]{20,}/g,
|
|
11
|
+
// OpenAI API keys
|
|
12
|
+
/sk-proj-[a-zA-Z0-9_-]{20,}/g,
|
|
13
|
+
/sk-[a-zA-Z0-9]{40,}/g,
|
|
14
|
+
// GitHub tokens
|
|
15
|
+
/ghp_[a-zA-Z0-9]{36,}/g,
|
|
16
|
+
/gho_[a-zA-Z0-9]{36,}/g,
|
|
17
|
+
/ghs_[a-zA-Z0-9]{36,}/g,
|
|
18
|
+
/github_pat_[a-zA-Z0-9_]{22,}/g,
|
|
19
|
+
// AWS keys
|
|
20
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
21
|
+
// Bearer tokens
|
|
22
|
+
/Bearer\s+[a-zA-Z0-9._\-/+=]{20,}/g,
|
|
23
|
+
// Generic API key patterns
|
|
24
|
+
/(?:api[_-]?key|apikey|api[_-]?secret|api[_-]?token)\s*[:=]\s*['"]?[a-zA-Z0-9_\-/.+=]{16,}['"]?/gi,
|
|
25
|
+
// Password patterns
|
|
26
|
+
/(?:password|passwd|pwd)\s*[:=]\s*['"]?[^\s'"]{8,}['"]?/gi,
|
|
27
|
+
// Private keys
|
|
28
|
+
/-----BEGIN\s[\w\s]+PRIVATE\sKEY-----/g,
|
|
29
|
+
// Connection strings with passwords
|
|
30
|
+
/(?:mongodb|postgres|mysql|redis):\/\/[^:]+:[^@]+@/g,
|
|
31
|
+
// Slack tokens
|
|
32
|
+
/xox[bpsar]-[a-zA-Z0-9-]{10,}/g,
|
|
33
|
+
// Stripe keys
|
|
34
|
+
/sk_(?:live|test)_[a-zA-Z0-9]{20,}/g,
|
|
35
|
+
/pk_(?:live|test)_[a-zA-Z0-9]{20,}/g,
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* 對單一字串做 secret redaction
|
|
39
|
+
*/
|
|
40
|
+
export function redactSecrets(text) {
|
|
41
|
+
let result = text;
|
|
42
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
43
|
+
// Reset lastIndex for global regexes
|
|
44
|
+
pattern.lastIndex = 0;
|
|
45
|
+
result = result.replace(pattern, REDACTION_PLACEHOLDER);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 檢查字串是否包含可能的 secrets
|
|
51
|
+
*/
|
|
52
|
+
export function containsSecrets(text) {
|
|
53
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
54
|
+
pattern.lastIndex = 0;
|
|
55
|
+
if (pattern.test(text))
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/core/redact.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,qBAAqB,GAAG,YAAY,CAAA;AAE1C,MAAM,eAAe,GAAsB;IACzC,qBAAqB;IACrB,4BAA4B;IAC5B,kBAAkB;IAClB,6BAA6B;IAC7B,sBAAsB;IACtB,gBAAgB;IAChB,uBAAuB;IACvB,uBAAuB;IACvB,uBAAuB;IACvB,+BAA+B;IAC/B,WAAW;IACX,mBAAmB;IACnB,gBAAgB;IAChB,mCAAmC;IACnC,2BAA2B;IAC3B,kGAAkG;IAClG,oBAAoB;IACpB,0DAA0D;IAC1D,eAAe;IACf,uCAAuC;IACvC,oCAAoC;IACpC,oDAAoD;IACpD,eAAe;IACf,+BAA+B;IAC/B,cAAc;IACd,oCAAoC;IACpC,oCAAoC;CACrC,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,MAAM,GAAG,IAAI,CAAA;IACjB,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACtC,qCAAqC;QACrC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAA;QACrB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;QACtC,OAAO,CAAC,SAAS,GAAG,CAAC,CAAA;QACrB,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;IACrC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|