@agentdeck/shared 0.1.0 → 0.2.3
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/dist/adapter.d.ts +18 -3
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +62 -0
- package/dist/adapter.js.map +1 -1
- package/dist/command-builders.d.ts +35 -0
- package/dist/command-builders.d.ts.map +1 -0
- package/dist/command-builders.js +75 -0
- package/dist/command-builders.js.map +1 -0
- package/dist/connection-status.d.ts +42 -0
- package/dist/connection-status.d.ts.map +1 -0
- package/dist/connection-status.js +52 -0
- package/dist/connection-status.js.map +1 -0
- package/dist/d200h-layout.d.ts +131 -0
- package/dist/d200h-layout.d.ts.map +1 -0
- package/dist/d200h-layout.js +627 -0
- package/dist/d200h-layout.js.map +1 -0
- package/dist/design-tokens.d.ts +259 -0
- package/dist/design-tokens.d.ts.map +1 -0
- package/dist/design-tokens.js +156 -0
- package/dist/design-tokens.js.map +1 -0
- package/dist/eval-schema.d.ts +235 -0
- package/dist/eval-schema.d.ts.map +1 -0
- package/dist/eval-schema.js +23 -0
- package/dist/eval-schema.js.map +1 -0
- package/dist/format-utils.d.ts +52 -0
- package/dist/format-utils.d.ts.map +1 -0
- package/dist/format-utils.js +165 -0
- package/dist/format-utils.js.map +1 -0
- package/dist/gateway-protocol.d.ts +391 -0
- package/dist/gateway-protocol.d.ts.map +1 -0
- package/dist/gateway-protocol.js +19 -0
- package/dist/gateway-protocol.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/llm-settings.d.ts +52 -0
- package/dist/llm-settings.d.ts.map +1 -0
- package/dist/llm-settings.js +118 -0
- package/dist/llm-settings.js.map +1 -0
- package/dist/net-utils.d.ts +2 -1
- package/dist/net-utils.d.ts.map +1 -1
- package/dist/net-utils.js +100 -3
- package/dist/net-utils.js.map +1 -1
- package/dist/pricing.d.ts +45 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +93 -0
- package/dist/pricing.js.map +1 -0
- package/dist/protocol.d.ts +496 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +30 -1
- package/dist/protocol.js.map +1 -1
- package/dist/sample.d.ts +152 -0
- package/dist/sample.d.ts.map +1 -0
- package/dist/sample.js +22 -0
- package/dist/sample.js.map +1 -0
- package/dist/session-utils.d.ts +142 -0
- package/dist/session-utils.d.ts.map +1 -0
- package/dist/session-utils.js +304 -0
- package/dist/session-utils.js.map +1 -0
- package/dist/state-colors.d.ts +16 -0
- package/dist/state-colors.d.ts.map +1 -0
- package/dist/state-colors.js +48 -0
- package/dist/state-colors.js.map +1 -0
- package/dist/states.d.ts +2 -0
- package/dist/states.d.ts.map +1 -1
- package/dist/states.js +6 -1
- package/dist/states.js.map +1 -1
- package/dist/svg-renderers/agent-logos.d.ts +45 -0
- package/dist/svg-renderers/agent-logos.d.ts.map +1 -0
- package/dist/svg-renderers/agent-logos.js +238 -0
- package/dist/svg-renderers/agent-logos.js.map +1 -0
- package/dist/svg-renderers/index.d.ts +4 -0
- package/dist/svg-renderers/index.d.ts.map +1 -0
- package/dist/svg-renderers/index.js +4 -0
- package/dist/svg-renderers/index.js.map +1 -0
- package/dist/svg-renderers/session-slot-renderer.d.ts +78 -0
- package/dist/svg-renderers/session-slot-renderer.d.ts.map +1 -0
- package/dist/svg-renderers/session-slot-renderer.js +506 -0
- package/dist/svg-renderers/session-slot-renderer.js.map +1 -0
- package/dist/svg-renderers/text-utils.d.ts +29 -0
- package/dist/svg-renderers/text-utils.d.ts.map +1 -0
- package/dist/svg-renderers/text-utils.js +122 -0
- package/dist/svg-renderers/text-utils.js.map +1 -0
- package/dist/telemetry-envelope.d.ts +108 -0
- package/dist/telemetry-envelope.d.ts.map +1 -0
- package/dist/telemetry-envelope.js +34 -0
- package/dist/telemetry-envelope.js.map +1 -0
- package/dist/timeline-icons.d.ts +70 -0
- package/dist/timeline-icons.d.ts.map +1 -0
- package/dist/timeline-icons.js +161 -0
- package/dist/timeline-icons.js.map +1 -0
- package/dist/timeline-label.d.ts +38 -0
- package/dist/timeline-label.d.ts.map +1 -0
- package/dist/timeline-label.js +95 -0
- package/dist/timeline-label.js.map +1 -0
- package/dist/timeline-markdown.d.ts +80 -0
- package/dist/timeline-markdown.d.ts.map +1 -0
- package/dist/timeline-markdown.js +221 -0
- package/dist/timeline-markdown.js.map +1 -0
- package/dist/timeline-summarizer.d.ts +37 -0
- package/dist/timeline-summarizer.d.ts.map +1 -0
- package/dist/timeline-summarizer.js +125 -0
- package/dist/timeline-summarizer.js.map +1 -0
- package/dist/timeline.d.ts +135 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +633 -0
- package/dist/timeline.js.map +1 -0
- package/dist/voice-paths.d.ts +4 -0
- package/dist/voice-paths.d.ts.map +1 -1
- package/dist/voice-paths.js +5 -0
- package/dist/voice-paths.js.map +1 -1
- package/package.json +9 -3
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// timeline-label.ts — the SINGLE source of truth for turning a TimelineEntry
|
|
2
|
+
// into its attributed, human-readable row text ("agent · project · task ·
|
|
3
|
+
// text").
|
|
4
|
+
//
|
|
5
|
+
// Before this file, shared/src exposed `agentBrandColor` but NO agent
|
|
6
|
+
// display-name function, so every surface (Swift ×5, Kotlin ×2, ESP32 ×4,
|
|
7
|
+
// plugin) hand-rolled the same `claude-code → "Claude"` map and its own
|
|
8
|
+
// separator convention, and they drifted. The mirrors (Swift
|
|
9
|
+
// `SessionFormatters.displayAgentLabel`, Kotlin `EinkFormatUtils`, C++
|
|
10
|
+
// `agent_label.h`) must match `agentDisplayLabel` below exactly.
|
|
11
|
+
//
|
|
12
|
+
// Design: `timelineRowAttribution` returns the STRUCTURED pieces so a
|
|
13
|
+
// space-constrained surface (ESP32 ticker, iPhone) can pick which fields to
|
|
14
|
+
// show, while roomy surfaces render all four. `formatTimelineRowLabel` joins
|
|
15
|
+
// them with the one canonical separator.
|
|
16
|
+
/** Canonical agent → display-name map. The ONLY place this mapping lives on
|
|
17
|
+
* the TS side; language mirrors copy it verbatim. Never abbreviate
|
|
18
|
+
* "OpenClaw" (see memory `brand-direction.md`). */
|
|
19
|
+
export function agentDisplayLabel(agentType) {
|
|
20
|
+
switch (agentType) {
|
|
21
|
+
case 'claude-code': return 'Claude';
|
|
22
|
+
case 'openclaw': return 'OpenClaw';
|
|
23
|
+
case 'codex-cli': return 'Codex CLI';
|
|
24
|
+
case 'codex-app': return 'Codex App';
|
|
25
|
+
case 'opencode': return 'OpenCode';
|
|
26
|
+
case 'antigravity': return 'Antigravity';
|
|
27
|
+
case 'monitor': return 'Monitor';
|
|
28
|
+
case 'daemon': return 'Daemon';
|
|
29
|
+
default:
|
|
30
|
+
if (!agentType)
|
|
31
|
+
return 'Agent';
|
|
32
|
+
// Unknown but non-empty: titlecase the slug so a new agent still reads
|
|
33
|
+
// sensibly instead of collapsing to a generic "Agent".
|
|
34
|
+
return agentType
|
|
35
|
+
.replace(/-/g, ' ')
|
|
36
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Compact agent → display-name for very tight surfaces (LED matrix, ticker
|
|
40
|
+
* when width is scarce). Keeps the brand distinct without the CLI/App suffix. */
|
|
41
|
+
export function agentShortLabel(agentType) {
|
|
42
|
+
switch (agentType) {
|
|
43
|
+
case 'codex-cli':
|
|
44
|
+
case 'codex-app': return 'Codex';
|
|
45
|
+
default: return agentDisplayLabel(agentType);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** The task pieces vary: a `task_start`/`task_end` row's own `raw` is the task
|
|
49
|
+
* label ("Task 1"); a turn row inside a task carries `taskId` but no inline
|
|
50
|
+
* label, so callers that want a task chip use `taskSummary` when the eval has
|
|
51
|
+
* produced one. Returns the best available task descriptor. */
|
|
52
|
+
function taskDescriptor(entry) {
|
|
53
|
+
const summary = entry.taskSummary?.trim();
|
|
54
|
+
if (summary)
|
|
55
|
+
return summary;
|
|
56
|
+
if (entry.type === 'task_start' || entry.type === 'task_end') {
|
|
57
|
+
return entry.raw?.trim() || undefined;
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
/** Decompose a TimelineEntry into its attributed pieces. Every surface builds
|
|
62
|
+
* its displayed row from this, so agent/project/task/text stay consistent. */
|
|
63
|
+
export function timelineRowAttribution(entry) {
|
|
64
|
+
const agent = entry.agentType ? agentDisplayLabel(entry.agentType) : undefined;
|
|
65
|
+
const project = entry.projectName?.trim() || undefined;
|
|
66
|
+
const task = taskDescriptor(entry);
|
|
67
|
+
const text = (entry.raw ?? '').trim();
|
|
68
|
+
return {
|
|
69
|
+
...(agent ? { agent } : {}),
|
|
70
|
+
...(project ? { project } : {}),
|
|
71
|
+
...(task ? { task } : {}),
|
|
72
|
+
text,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Canonical joined label. Replaces the divergent "[project] Agent" vs
|
|
76
|
+
* "project · tag" conventions with one separator (" · ") and an explicit,
|
|
77
|
+
* caller-chosen part order. Example: "Claude · AgentDeck · Fix eink ticker". */
|
|
78
|
+
export function formatTimelineRowLabel(entry, opts = {}) {
|
|
79
|
+
const { parts = ['agent', 'project'], includeText = true, short = false, separator = ' · ' } = opts;
|
|
80
|
+
const attr = timelineRowAttribution(entry);
|
|
81
|
+
const agentText = short ? agentShortLabel(entry.agentType) : attr.agent;
|
|
82
|
+
const pieces = [];
|
|
83
|
+
for (const p of parts) {
|
|
84
|
+
if (p === 'agent' && agentText)
|
|
85
|
+
pieces.push(agentText);
|
|
86
|
+
else if (p === 'project' && attr.project)
|
|
87
|
+
pieces.push(attr.project);
|
|
88
|
+
else if (p === 'task' && attr.task)
|
|
89
|
+
pieces.push(attr.task);
|
|
90
|
+
}
|
|
91
|
+
if (includeText && attr.text)
|
|
92
|
+
pieces.push(attr.text);
|
|
93
|
+
return pieces.join(separator);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=timeline-label.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-label.js","sourceRoot":"","sources":["../src/timeline-label.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight markdown parser for timeline detail panes.
|
|
3
|
+
*
|
|
4
|
+
* Output is a flat array of typed lines that each platform renders natively
|
|
5
|
+
* (SwiftUI / Compose). Pure data — no rendering. Mirrors the Apple parser at
|
|
6
|
+
* apple/AgentDeck/UI/Monitor/TimelineStripView.swift `TimelineMarkdownLine`
|
|
7
|
+
* and the Android port at
|
|
8
|
+
* android/.../ui/timeline/TimelineMarkdown.kt — keep the three in lockstep.
|
|
9
|
+
*
|
|
10
|
+
* Block grammar (line-oriented):
|
|
11
|
+
* - ``` toggles a code fence; lines inside become `code` (verbatim, no inline parsing)
|
|
12
|
+
* - empty / whitespace-only line → `blank`
|
|
13
|
+
* - 1-6 leading hashes + space → `heading` (level 1-6; CommonMark ATX)
|
|
14
|
+
* - `- ` or `* ` → `bullet`
|
|
15
|
+
* - `<digits>.` or `<digits>)` followed by space → `numbered`
|
|
16
|
+
* - `> ` → `quote`
|
|
17
|
+
* - `|...|` (with optional `|---|` separator) → `table` block
|
|
18
|
+
* - anything else → `text`
|
|
19
|
+
*
|
|
20
|
+
* Inline grammar (per `parseInlineSpans`, applied at render time to non-code
|
|
21
|
+
* line content + table cells; first-match-wins, no recursion):
|
|
22
|
+
* - `` `code` `` → `code` span
|
|
23
|
+
* - `**bold**` → `bold` span
|
|
24
|
+
* - `*italic*` → `italic` span (only when not adjacent to another `*`)
|
|
25
|
+
* - `[text](href)` → `link` span
|
|
26
|
+
* - everything else → `plain` span
|
|
27
|
+
*/
|
|
28
|
+
export type MarkdownLine = {
|
|
29
|
+
kind: 'blank';
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'heading';
|
|
32
|
+
level: 1 | 2 | 3 | 4 | 5 | 6;
|
|
33
|
+
content: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'bullet';
|
|
36
|
+
content: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'numbered';
|
|
39
|
+
marker: string;
|
|
40
|
+
content: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'quote';
|
|
43
|
+
content: string;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'code';
|
|
46
|
+
content: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: 'text';
|
|
49
|
+
content: string;
|
|
50
|
+
} | {
|
|
51
|
+
kind: 'table';
|
|
52
|
+
rows: string[][];
|
|
53
|
+
hasHeader: boolean;
|
|
54
|
+
};
|
|
55
|
+
export type InlineSpan = {
|
|
56
|
+
kind: 'plain';
|
|
57
|
+
text: string;
|
|
58
|
+
} | {
|
|
59
|
+
kind: 'bold';
|
|
60
|
+
text: string;
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'italic';
|
|
63
|
+
text: string;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'code';
|
|
66
|
+
text: string;
|
|
67
|
+
} | {
|
|
68
|
+
kind: 'link';
|
|
69
|
+
text: string;
|
|
70
|
+
href: string;
|
|
71
|
+
};
|
|
72
|
+
export declare function parseTimelineMarkdown(text: string): MarkdownLine[];
|
|
73
|
+
/**
|
|
74
|
+
* Tokenize a single line of inline content into spans. First-match-wins
|
|
75
|
+
* left-to-right walker; never recurses (so e.g. `**bold *with italic***` is
|
|
76
|
+
* just bold + plain — keeps the implementation simple and the platform ports
|
|
77
|
+
* trivial). Always returns at least one span; empty input → empty array.
|
|
78
|
+
*/
|
|
79
|
+
export declare function parseInlineSpans(text: string): InlineSpan[];
|
|
80
|
+
//# sourceMappingURL=timeline-markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-markdown.d.ts","sourceRoot":"","sources":["../src/timeline-markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5D,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAgFlE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CA8E3D"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight markdown parser for timeline detail panes.
|
|
3
|
+
*
|
|
4
|
+
* Output is a flat array of typed lines that each platform renders natively
|
|
5
|
+
* (SwiftUI / Compose). Pure data — no rendering. Mirrors the Apple parser at
|
|
6
|
+
* apple/AgentDeck/UI/Monitor/TimelineStripView.swift `TimelineMarkdownLine`
|
|
7
|
+
* and the Android port at
|
|
8
|
+
* android/.../ui/timeline/TimelineMarkdown.kt — keep the three in lockstep.
|
|
9
|
+
*
|
|
10
|
+
* Block grammar (line-oriented):
|
|
11
|
+
* - ``` toggles a code fence; lines inside become `code` (verbatim, no inline parsing)
|
|
12
|
+
* - empty / whitespace-only line → `blank`
|
|
13
|
+
* - 1-6 leading hashes + space → `heading` (level 1-6; CommonMark ATX)
|
|
14
|
+
* - `- ` or `* ` → `bullet`
|
|
15
|
+
* - `<digits>.` or `<digits>)` followed by space → `numbered`
|
|
16
|
+
* - `> ` → `quote`
|
|
17
|
+
* - `|...|` (with optional `|---|` separator) → `table` block
|
|
18
|
+
* - anything else → `text`
|
|
19
|
+
*
|
|
20
|
+
* Inline grammar (per `parseInlineSpans`, applied at render time to non-code
|
|
21
|
+
* line content + table cells; first-match-wins, no recursion):
|
|
22
|
+
* - `` `code` `` → `code` span
|
|
23
|
+
* - `**bold**` → `bold` span
|
|
24
|
+
* - `*italic*` → `italic` span (only when not adjacent to another `*`)
|
|
25
|
+
* - `[text](href)` → `link` span
|
|
26
|
+
* - everything else → `plain` span
|
|
27
|
+
*/
|
|
28
|
+
export function parseTimelineMarkdown(text) {
|
|
29
|
+
if (!text)
|
|
30
|
+
return [];
|
|
31
|
+
const out = [];
|
|
32
|
+
let inCodeFence = false;
|
|
33
|
+
const lines = text.split(/\r?\n/);
|
|
34
|
+
let i = 0;
|
|
35
|
+
while (i < lines.length) {
|
|
36
|
+
const rawLine = lines[i];
|
|
37
|
+
const trimmed = rawLine.trim();
|
|
38
|
+
if (trimmed.startsWith('```')) {
|
|
39
|
+
inCodeFence = !inCodeFence;
|
|
40
|
+
i += 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (inCodeFence) {
|
|
44
|
+
out.push({ kind: 'code', content: rawLine });
|
|
45
|
+
i += 1;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (trimmed.length === 0) {
|
|
49
|
+
out.push({ kind: 'blank' });
|
|
50
|
+
i += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
// Table block: current line looks like `|...|`. Optional separator on
|
|
54
|
+
// next line marks the previous row as header. Continue collecting rows
|
|
55
|
+
// while subsequent lines are also table-rows.
|
|
56
|
+
if (isTableRow(trimmed)) {
|
|
57
|
+
const rows = [splitCells(trimmed)];
|
|
58
|
+
let hasHeader = false;
|
|
59
|
+
let j = i + 1;
|
|
60
|
+
if (j < lines.length && isTableSeparator(lines[j].trim())) {
|
|
61
|
+
hasHeader = true;
|
|
62
|
+
j += 1;
|
|
63
|
+
}
|
|
64
|
+
while (j < lines.length) {
|
|
65
|
+
const nextTrimmed = lines[j].trim();
|
|
66
|
+
if (!isTableRow(nextTrimmed) || isTableSeparator(nextTrimmed))
|
|
67
|
+
break;
|
|
68
|
+
rows.push(splitCells(nextTrimmed));
|
|
69
|
+
j += 1;
|
|
70
|
+
}
|
|
71
|
+
out.push({ kind: 'table', rows, hasHeader });
|
|
72
|
+
i = j;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const heading = parseHeading(trimmed);
|
|
76
|
+
if (heading) {
|
|
77
|
+
out.push({ kind: 'heading', level: heading.level, content: heading.content });
|
|
78
|
+
i += 1;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
|
|
82
|
+
out.push({ kind: 'bullet', content: trimmed.slice(2) });
|
|
83
|
+
i += 1;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const numbered = parseNumbered(trimmed);
|
|
87
|
+
if (numbered) {
|
|
88
|
+
out.push({ kind: 'numbered', marker: numbered.marker, content: numbered.content });
|
|
89
|
+
i += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (trimmed.startsWith('> ')) {
|
|
93
|
+
out.push({ kind: 'quote', content: trimmed.slice(2) });
|
|
94
|
+
i += 1;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
out.push({ kind: 'text', content: rawLine });
|
|
98
|
+
i += 1;
|
|
99
|
+
}
|
|
100
|
+
return out.length === 0 ? [{ kind: 'text', content: text }] : out;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Tokenize a single line of inline content into spans. First-match-wins
|
|
104
|
+
* left-to-right walker; never recurses (so e.g. `**bold *with italic***` is
|
|
105
|
+
* just bold + plain — keeps the implementation simple and the platform ports
|
|
106
|
+
* trivial). Always returns at least one span; empty input → empty array.
|
|
107
|
+
*/
|
|
108
|
+
export function parseInlineSpans(text) {
|
|
109
|
+
if (!text)
|
|
110
|
+
return [];
|
|
111
|
+
const out = [];
|
|
112
|
+
let pending = ''; // buffered plain text waiting to flush
|
|
113
|
+
const flushPlain = () => {
|
|
114
|
+
if (pending.length > 0) {
|
|
115
|
+
out.push({ kind: 'plain', text: pending });
|
|
116
|
+
pending = '';
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
let i = 0;
|
|
120
|
+
while (i < text.length) {
|
|
121
|
+
const ch = text[i];
|
|
122
|
+
// `code`
|
|
123
|
+
if (ch === '`') {
|
|
124
|
+
const close = text.indexOf('`', i + 1);
|
|
125
|
+
if (close > i) {
|
|
126
|
+
flushPlain();
|
|
127
|
+
out.push({ kind: 'code', text: text.slice(i + 1, close) });
|
|
128
|
+
i = close + 1;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// **bold**
|
|
133
|
+
if (ch === '*' && text[i + 1] === '*') {
|
|
134
|
+
const close = text.indexOf('**', i + 2);
|
|
135
|
+
if (close > i + 1) {
|
|
136
|
+
flushPlain();
|
|
137
|
+
out.push({ kind: 'bold', text: text.slice(i + 2, close) });
|
|
138
|
+
i = close + 2;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// *italic* — single `*`, not surrounded by another `*`
|
|
143
|
+
if (ch === '*' &&
|
|
144
|
+
text[i + 1] !== '*' &&
|
|
145
|
+
(i === 0 || text[i - 1] !== '*')) {
|
|
146
|
+
// Find a closing single `*` that isn't doubled.
|
|
147
|
+
let j = i + 1;
|
|
148
|
+
while (j < text.length) {
|
|
149
|
+
if (text[j] === '*' && text[j + 1] !== '*' && text[j - 1] !== '*')
|
|
150
|
+
break;
|
|
151
|
+
j += 1;
|
|
152
|
+
}
|
|
153
|
+
if (j < text.length && j > i + 1) {
|
|
154
|
+
flushPlain();
|
|
155
|
+
out.push({ kind: 'italic', text: text.slice(i + 1, j) });
|
|
156
|
+
i = j + 1;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// [text](href)
|
|
161
|
+
if (ch === '[') {
|
|
162
|
+
const closeBracket = text.indexOf(']', i + 1);
|
|
163
|
+
if (closeBracket > i && text[closeBracket + 1] === '(') {
|
|
164
|
+
const closeParen = text.indexOf(')', closeBracket + 2);
|
|
165
|
+
if (closeParen > closeBracket + 1) {
|
|
166
|
+
const linkText = text.slice(i + 1, closeBracket);
|
|
167
|
+
const href = text.slice(closeBracket + 2, closeParen);
|
|
168
|
+
flushPlain();
|
|
169
|
+
out.push({ kind: 'link', text: linkText, href });
|
|
170
|
+
i = closeParen + 1;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
pending += ch;
|
|
176
|
+
i += 1;
|
|
177
|
+
}
|
|
178
|
+
flushPlain();
|
|
179
|
+
return out.length === 0 ? [{ kind: 'plain', text }] : out;
|
|
180
|
+
}
|
|
181
|
+
function parseHeading(trimmed) {
|
|
182
|
+
let level = 0;
|
|
183
|
+
for (const ch of trimmed) {
|
|
184
|
+
if (ch === '#')
|
|
185
|
+
level += 1;
|
|
186
|
+
else
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
if (level < 1 || level > 6)
|
|
190
|
+
return null;
|
|
191
|
+
if (trimmed.charAt(level) !== ' ')
|
|
192
|
+
return null;
|
|
193
|
+
return { level: level, content: trimmed.slice(level + 1) };
|
|
194
|
+
}
|
|
195
|
+
function parseNumbered(trimmed) {
|
|
196
|
+
const m = trimmed.match(/^(\d+)([.)])\s+(.*)$/);
|
|
197
|
+
if (!m)
|
|
198
|
+
return null;
|
|
199
|
+
return { marker: `${m[1]}${m[2]}`, content: m[3] };
|
|
200
|
+
}
|
|
201
|
+
// ---- Table helpers ----
|
|
202
|
+
const TABLE_ROW_RE = /^\s*\|.+\|\s*$/;
|
|
203
|
+
const TABLE_SEPARATOR_RE = /^\s*\|[-:\s|]+\|\s*$/;
|
|
204
|
+
function isTableRow(trimmed) {
|
|
205
|
+
return TABLE_ROW_RE.test(trimmed) && !isTableSeparator(trimmed);
|
|
206
|
+
}
|
|
207
|
+
function isTableSeparator(trimmed) {
|
|
208
|
+
if (!TABLE_SEPARATOR_RE.test(trimmed))
|
|
209
|
+
return false;
|
|
210
|
+
// Must contain at least one dash to be a real separator (not just `| | |`).
|
|
211
|
+
return /-/.test(trimmed);
|
|
212
|
+
}
|
|
213
|
+
function splitCells(rowLine) {
|
|
214
|
+
return rowLine
|
|
215
|
+
.trim()
|
|
216
|
+
.replace(/^\|/, '')
|
|
217
|
+
.replace(/\|$/, '')
|
|
218
|
+
.split('|')
|
|
219
|
+
.map((c) => c.trim());
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=timeline-markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-markdown.js","sourceRoot":"","sources":["../src/timeline-markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared timeline summarizer utilities — extractTopicHint and cleanLLMOutput.
|
|
3
|
+
* Used by both bridge/src/timeline-summarizer.ts and plugin/src/timeline-summarizer.ts.
|
|
4
|
+
*/
|
|
5
|
+
export declare const SUMMARY_SYSTEM_PROMPT = "You are a timeline summarizer. Given an AI assistant's response text, produce a single-line Korean summary (max 80 characters) of what was accomplished. Focus on the result, not the process. No quotes, no markdown, no punctuation at the end. Output ONLY the summary line, nothing else. Examples:\n- \uBD07\uB9C8\uB2F9 \uC778\uBC15\uC2A4\uC5D0 AI \uC5D0\uC774\uC804\uD2B8 \uC6B4\uC601 \uD301 3\uAC74 \uC218\uC9D1\n- \uC8FC\uAC04 \uBAA8\uB378 \uC0AC\uC6A9\uB7C9 \uB9AC\uD3EC\uD2B8: glm-5 28\uD68C \uCD5C\uB2E4\n- GitHub \uC774\uC288 #10428 \uAC80\uD1A0 \uC644\uB8CC, PR #16831 \uB300\uAE30 \uC911\n- HBF \uB274\uC2A4 9\uC6D4~2\uC6D4\uBD84 \uD55C\uAE00 \uC815\uB9AC \uC644\uB8CC";
|
|
6
|
+
/**
|
|
7
|
+
* Extract a topic hint from the first few tokens of a response.
|
|
8
|
+
* Used for immediate chat_start enrichment before LLM summarization.
|
|
9
|
+
*
|
|
10
|
+
* Korean handling: politeness-only responses ("네, 확인했습니다.") used to be
|
|
11
|
+
* stripped to empty and return null, leaving the timeline showing bare
|
|
12
|
+
* "Completed". Now the strip falls back to the pre-strip candidate so the
|
|
13
|
+
* row shows something meaningful.
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractTopicHint(text: string): string | null;
|
|
16
|
+
export type TopicHintKind = 'topic' | 'fallback' | null;
|
|
17
|
+
/**
|
|
18
|
+
* Same as `extractTopicHint` but tells the caller whether the result was a
|
|
19
|
+
* substantive topic (kind='topic') or just a politeness-fallback /
|
|
20
|
+
* first-sentence fallback (kind='fallback'). Lets emitters set
|
|
21
|
+
* `summaryKind: 'heuristic'` only when there's real content, vs `'none'`
|
|
22
|
+
* when we're scraping the bottom of the barrel.
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractTopicHintWithKind(text: string): {
|
|
25
|
+
hint: string | null;
|
|
26
|
+
kind: TopicHintKind;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Last-resort fallback when the response yielded no usable hint and the
|
|
30
|
+
* caller has the prompt text — produce a snippet of the prompt instead of
|
|
31
|
+
* literal "Completed". Returns the first sentence (up to `maxLen` chars,
|
|
32
|
+
* ending at `.` `!` `?` or newline) or null when prompt is too short.
|
|
33
|
+
*/
|
|
34
|
+
export declare function promptSnippetFallback(prompt: string | null | undefined, maxLen?: number): string | null;
|
|
35
|
+
/** Clean LLM output — strip thinking, quotes, markdown artifacts */
|
|
36
|
+
export declare function cleanLLMOutput(content: string): string | null;
|
|
37
|
+
//# sourceMappingURL=timeline-summarizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-summarizer.d.ts","sourceRoot":"","sources":["../src/timeline-summarizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,eAAO,MAAM,qBAAqB,wqBAIT,CAAC;AAE1B;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE5D;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,aAAa,CAAA;CAAE,CAiD9C;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,MAAM,SAAK,GAAG,MAAM,GAAG,IAAI,CAWnG;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4B7D"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared timeline summarizer utilities — extractTopicHint and cleanLLMOutput.
|
|
3
|
+
* Used by both bridge/src/timeline-summarizer.ts and plugin/src/timeline-summarizer.ts.
|
|
4
|
+
*/
|
|
5
|
+
import { cleanRawText } from './timeline.js';
|
|
6
|
+
export const SUMMARY_SYSTEM_PROMPT = `You are a timeline summarizer. Given an AI assistant's response text, produce a single-line Korean summary (max 80 characters) of what was accomplished. Focus on the result, not the process. No quotes, no markdown, no punctuation at the end. Output ONLY the summary line, nothing else. Examples:
|
|
7
|
+
- 봇마당 인박스에 AI 에이전트 운영 팁 3건 수집
|
|
8
|
+
- 주간 모델 사용량 리포트: glm-5 28회 최다
|
|
9
|
+
- GitHub 이슈 #10428 검토 완료, PR #16831 대기 중
|
|
10
|
+
- HBF 뉴스 9월~2월분 한글 정리 완료`;
|
|
11
|
+
/**
|
|
12
|
+
* Extract a topic hint from the first few tokens of a response.
|
|
13
|
+
* Used for immediate chat_start enrichment before LLM summarization.
|
|
14
|
+
*
|
|
15
|
+
* Korean handling: politeness-only responses ("네, 확인했습니다.") used to be
|
|
16
|
+
* stripped to empty and return null, leaving the timeline showing bare
|
|
17
|
+
* "Completed". Now the strip falls back to the pre-strip candidate so the
|
|
18
|
+
* row shows something meaningful.
|
|
19
|
+
*/
|
|
20
|
+
export function extractTopicHint(text) {
|
|
21
|
+
return extractTopicHintWithKind(text).hint;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Same as `extractTopicHint` but tells the caller whether the result was a
|
|
25
|
+
* substantive topic (kind='topic') or just a politeness-fallback /
|
|
26
|
+
* first-sentence fallback (kind='fallback'). Lets emitters set
|
|
27
|
+
* `summaryKind: 'heuristic'` only when there's real content, vs `'none'`
|
|
28
|
+
* when we're scraping the bottom of the barrel.
|
|
29
|
+
*/
|
|
30
|
+
export function extractTopicHintWithKind(text) {
|
|
31
|
+
if (!text || text.length < 5)
|
|
32
|
+
return { hint: null, kind: null };
|
|
33
|
+
const lines = text.split('\n').map((l) => l.trim()).filter(Boolean);
|
|
34
|
+
// Find first non-markdown, non-code-fence, non-empty line
|
|
35
|
+
let candidate = null;
|
|
36
|
+
let inCodeFence = false;
|
|
37
|
+
for (const line of lines) {
|
|
38
|
+
if (/^```/.test(line)) {
|
|
39
|
+
inCodeFence = !inCodeFence;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (inCodeFence)
|
|
43
|
+
continue;
|
|
44
|
+
if (/^#{1,6}\s*$/.test(line))
|
|
45
|
+
continue;
|
|
46
|
+
const stripped = cleanRawText(line)
|
|
47
|
+
.replace(/^[-*]\s+/, '')
|
|
48
|
+
.replace(/^>\s+/, '')
|
|
49
|
+
.trim();
|
|
50
|
+
if (stripped.length >= 3) {
|
|
51
|
+
candidate = stripped;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (!candidate)
|
|
56
|
+
return { hint: null, kind: null };
|
|
57
|
+
const snippet = candidate.length > 80 ? candidate.slice(0, 77) + '...' : candidate;
|
|
58
|
+
// Try stripping leading Korean polite closers — "네, …" / "확인했습니다."
|
|
59
|
+
let cleaned = snippet
|
|
60
|
+
.replace(/^네[,.]?\s*/i, '')
|
|
61
|
+
.replace(/^(완료했습니다\.\s*|알겠습니다\.\s*|확인했습니다\.\s*)/i, '')
|
|
62
|
+
.trim();
|
|
63
|
+
if (cleaned.length >= 3) {
|
|
64
|
+
return { hint: cleaned, kind: 'topic' };
|
|
65
|
+
}
|
|
66
|
+
// Strip left only the EXTRA content beside the polite closer. If polite
|
|
67
|
+
// closer was the entire candidate, fall back to the candidate itself —
|
|
68
|
+
// "네, 확인했습니다." beats showing just "Completed".
|
|
69
|
+
if (snippet.length >= 3) {
|
|
70
|
+
return { hint: snippet, kind: 'fallback' };
|
|
71
|
+
}
|
|
72
|
+
return { hint: null, kind: null };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Last-resort fallback when the response yielded no usable hint and the
|
|
76
|
+
* caller has the prompt text — produce a snippet of the prompt instead of
|
|
77
|
+
* literal "Completed". Returns the first sentence (up to `maxLen` chars,
|
|
78
|
+
* ending at `.` `!` `?` or newline) or null when prompt is too short.
|
|
79
|
+
*/
|
|
80
|
+
export function promptSnippetFallback(prompt, maxLen = 60) {
|
|
81
|
+
if (!prompt)
|
|
82
|
+
return null;
|
|
83
|
+
const trimmed = prompt.trim();
|
|
84
|
+
if (trimmed.length < 3)
|
|
85
|
+
return null;
|
|
86
|
+
// Cut at the first sentence terminator, otherwise at a hard line break.
|
|
87
|
+
const stop = trimmed.search(/[.!?。、]|\n/);
|
|
88
|
+
let snippet = stop > 0 ? trimmed.slice(0, stop) : trimmed;
|
|
89
|
+
snippet = snippet.trim();
|
|
90
|
+
if (snippet.length === 0)
|
|
91
|
+
snippet = trimmed;
|
|
92
|
+
if (snippet.length > maxLen)
|
|
93
|
+
snippet = snippet.slice(0, maxLen - 1).trim() + '…';
|
|
94
|
+
return snippet;
|
|
95
|
+
}
|
|
96
|
+
/** Clean LLM output — strip thinking, quotes, markdown artifacts */
|
|
97
|
+
export function cleanLLMOutput(content) {
|
|
98
|
+
let cleaned = content
|
|
99
|
+
// Strip <think>...</think> blocks (Qwen thinking mode)
|
|
100
|
+
.replace(/<think>[\s\S]*?<\/think>/g, '')
|
|
101
|
+
// Strip unclosed <think> at end (truncated output)
|
|
102
|
+
.replace(/<think>[\s\S]*$/g, '')
|
|
103
|
+
.trim();
|
|
104
|
+
// If output has multiple lines, take the last non-empty line
|
|
105
|
+
// (thinking text tends to come first, summary last)
|
|
106
|
+
const lines = cleaned.split('\n').map(l => l.trim()).filter(Boolean);
|
|
107
|
+
if (lines.length > 1) {
|
|
108
|
+
// Find the last line that looks like Korean summary (contains Korean chars)
|
|
109
|
+
const koreanLine = lines.reverse().find(l => /[\uAC00-\uD7AF]/.test(l));
|
|
110
|
+
cleaned = koreanLine || lines[lines.length - 1];
|
|
111
|
+
}
|
|
112
|
+
// Strip surrounding quotes, markdown list markers
|
|
113
|
+
cleaned = cleaned
|
|
114
|
+
.replace(/^[-*]\s*/, '')
|
|
115
|
+
.replace(/^["'`\u201C\u201D\u2018\u2019]+|["'`\u201C\u201D\u2018\u2019]+$/g, '')
|
|
116
|
+
.replace(/[.\u3002]$/, '') // remove trailing period
|
|
117
|
+
.trim();
|
|
118
|
+
if (!cleaned || cleaned.length < 3)
|
|
119
|
+
return null;
|
|
120
|
+
// Truncate to 80 chars if needed
|
|
121
|
+
if (cleaned.length > 80)
|
|
122
|
+
cleaned = cleaned.slice(0, 77) + '...';
|
|
123
|
+
return cleaned;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=timeline-summarizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-summarizer.js","sourceRoot":"","sources":["../src/timeline-summarizer.ts"],"names":[],"mappings":"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"}
|