@agentdeck/shared 0.2.0 → 1.0.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.
Files changed (113) hide show
  1. package/dist/adapter.d.ts +3 -1
  2. package/dist/adapter.d.ts.map +1 -1
  3. package/dist/adapter.js +24 -0
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/command-builders.d.ts +8 -2
  6. package/dist/command-builders.d.ts.map +1 -1
  7. package/dist/command-builders.js +20 -2
  8. package/dist/command-builders.js.map +1 -1
  9. package/dist/connection-status.d.ts +42 -0
  10. package/dist/connection-status.d.ts.map +1 -0
  11. package/dist/connection-status.js +52 -0
  12. package/dist/connection-status.js.map +1 -0
  13. package/dist/creature-layout.d.ts +18 -0
  14. package/dist/creature-layout.d.ts.map +1 -0
  15. package/dist/creature-layout.js +131 -0
  16. package/dist/creature-layout.js.map +1 -0
  17. package/dist/d200h-layout.d.ts +146 -0
  18. package/dist/d200h-layout.d.ts.map +1 -0
  19. package/dist/d200h-layout.js +808 -0
  20. package/dist/d200h-layout.js.map +1 -0
  21. package/dist/design-tokens.d.ts +261 -0
  22. package/dist/design-tokens.d.ts.map +1 -0
  23. package/dist/design-tokens.js +157 -0
  24. package/dist/design-tokens.js.map +1 -0
  25. package/dist/eval-schema.d.ts +32 -2
  26. package/dist/eval-schema.d.ts.map +1 -1
  27. package/dist/eval-schema.js.map +1 -1
  28. package/dist/format-utils.d.ts +38 -0
  29. package/dist/format-utils.d.ts.map +1 -1
  30. package/dist/format-utils.js +70 -0
  31. package/dist/format-utils.js.map +1 -1
  32. package/dist/gateway-protocol.d.ts +1 -1
  33. package/dist/gateway-protocol.js +1 -1
  34. package/dist/index.d.ts +11 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +11 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/llm-settings.d.ts +3 -3
  39. package/dist/llm-settings.d.ts.map +1 -1
  40. package/dist/llm-settings.js +3 -3
  41. package/dist/llm-settings.js.map +1 -1
  42. package/dist/net-utils.d.ts +2 -1
  43. package/dist/net-utils.d.ts.map +1 -1
  44. package/dist/net-utils.js +100 -3
  45. package/dist/net-utils.js.map +1 -1
  46. package/dist/pricing.d.ts +45 -0
  47. package/dist/pricing.d.ts.map +1 -0
  48. package/dist/pricing.js +93 -0
  49. package/dist/pricing.js.map +1 -0
  50. package/dist/protocol.d.ts +220 -5
  51. package/dist/protocol.d.ts.map +1 -1
  52. package/dist/protocol.js +11 -1
  53. package/dist/protocol.js.map +1 -1
  54. package/dist/sample.d.ts +152 -0
  55. package/dist/sample.d.ts.map +1 -0
  56. package/dist/sample.js +22 -0
  57. package/dist/sample.js.map +1 -0
  58. package/dist/session-utils.d.ts +82 -2
  59. package/dist/session-utils.d.ts.map +1 -1
  60. package/dist/session-utils.js +205 -10
  61. package/dist/session-utils.js.map +1 -1
  62. package/dist/state-colors.d.ts.map +1 -1
  63. package/dist/state-colors.js +2 -0
  64. package/dist/state-colors.js.map +1 -1
  65. package/dist/states.d.ts +1 -0
  66. package/dist/states.d.ts.map +1 -1
  67. package/dist/states.js +6 -1
  68. package/dist/states.js.map +1 -1
  69. package/dist/svg-renderers/agent-logos.d.ts +20 -12
  70. package/dist/svg-renderers/agent-logos.d.ts.map +1 -1
  71. package/dist/svg-renderers/agent-logos.js +154 -46
  72. package/dist/svg-renderers/agent-logos.js.map +1 -1
  73. package/dist/svg-renderers/session-slot-renderer.d.ts +71 -6
  74. package/dist/svg-renderers/session-slot-renderer.d.ts.map +1 -1
  75. package/dist/svg-renderers/session-slot-renderer.js +429 -209
  76. package/dist/svg-renderers/session-slot-renderer.js.map +1 -1
  77. package/dist/svg-renderers/text-utils.d.ts +14 -0
  78. package/dist/svg-renderers/text-utils.d.ts.map +1 -1
  79. package/dist/svg-renderers/text-utils.js +34 -0
  80. package/dist/svg-renderers/text-utils.js.map +1 -1
  81. package/dist/telemetry-envelope.d.ts +1 -1
  82. package/dist/telemetry-envelope.d.ts.map +1 -1
  83. package/dist/terrarium-rules.d.ts +46 -0
  84. package/dist/terrarium-rules.d.ts.map +1 -0
  85. package/dist/terrarium-rules.js +63 -0
  86. package/dist/terrarium-rules.js.map +1 -0
  87. package/dist/timeline-icons.d.ts +80 -0
  88. package/dist/timeline-icons.d.ts.map +1 -0
  89. package/dist/timeline-icons.js +174 -0
  90. package/dist/timeline-icons.js.map +1 -0
  91. package/dist/timeline-label.d.ts +38 -0
  92. package/dist/timeline-label.d.ts.map +1 -0
  93. package/dist/timeline-label.js +95 -0
  94. package/dist/timeline-label.js.map +1 -0
  95. package/dist/timeline-markdown.d.ts +80 -0
  96. package/dist/timeline-markdown.d.ts.map +1 -0
  97. package/dist/timeline-markdown.js +221 -0
  98. package/dist/timeline-markdown.js.map +1 -0
  99. package/dist/timeline-summarizer.d.ts +24 -0
  100. package/dist/timeline-summarizer.d.ts.map +1 -1
  101. package/dist/timeline-summarizer.js +55 -13
  102. package/dist/timeline-summarizer.js.map +1 -1
  103. package/dist/timeline-task-display.d.ts +66 -0
  104. package/dist/timeline-task-display.d.ts.map +1 -0
  105. package/dist/timeline-task-display.js +94 -0
  106. package/dist/timeline-task-display.js.map +1 -0
  107. package/dist/timeline.d.ts +101 -2
  108. package/dist/timeline.d.ts.map +1 -1
  109. package/dist/timeline.js +249 -11
  110. package/dist/timeline.js.map +1 -1
  111. package/dist/trmnl-layout.d.ts.map +1 -0
  112. package/dist/trmnl-layout.js.map +1 -0
  113. package/package.json +2 -1
@@ -0,0 +1,38 @@
1
+ import type { TimelineEntry } from './timeline.js';
2
+ /** Canonical agent → display-name map. The ONLY place this mapping lives on
3
+ * the TS side; language mirrors copy it verbatim. Never abbreviate
4
+ * "OpenClaw" (see memory `brand-direction.md`). */
5
+ export declare function agentDisplayLabel(agentType: string | undefined | null): string;
6
+ /** Compact agent → display-name for very tight surfaces (LED matrix, ticker
7
+ * when width is scarce). Keeps the brand distinct without the CLI/App suffix. */
8
+ export declare function agentShortLabel(agentType: string | undefined | null): string;
9
+ export interface TimelineRowAttribution {
10
+ /** Resolved agent display name, or undefined when no agent is attributed. */
11
+ agent?: string;
12
+ /** Project / worktree name. */
13
+ project?: string;
14
+ /** Task label — the APME task summary when present, else the task row's
15
+ * own label; undefined for rows outside a task. */
16
+ task?: string;
17
+ /** The already-summarized row body (`entry.raw`). */
18
+ text: string;
19
+ }
20
+ /** Decompose a TimelineEntry into its attributed pieces. Every surface builds
21
+ * its displayed row from this, so agent/project/task/text stay consistent. */
22
+ export declare function timelineRowAttribution(entry: TimelineEntry): TimelineRowAttribution;
23
+ export interface FormatTimelineRowOptions {
24
+ /** Which attribution parts to prepend before the text, in order. Defaults
25
+ * to agent + project (the common glance form). */
26
+ parts?: Array<'agent' | 'project' | 'task'>;
27
+ /** Include the row body text after the attribution. Default true. */
28
+ includeText?: boolean;
29
+ /** Use the compact agent name (ticker/matrix). Default false. */
30
+ short?: boolean;
31
+ /** Separator between attribution parts. Default " · ". */
32
+ separator?: string;
33
+ }
34
+ /** Canonical joined label. Replaces the divergent "[project] Agent" vs
35
+ * "project · tag" conventions with one separator (" · ") and an explicit,
36
+ * caller-chosen part order. Example: "Claude · AgentDeck · Fix eink ticker". */
37
+ export declare function formatTimelineRowLabel(entry: TimelineEntry, opts?: FormatTimelineRowOptions): string;
38
+ //# sourceMappingURL=timeline-label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-label.d.ts","sourceRoot":"","sources":["../src/timeline-label.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;oDAEoD;AACpD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAkB9E;AAED;kFACkF;AAClF,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAM5E;AAED,MAAM,WAAW,sBAAsB;IACrC,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;wDACoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;CACd;AAeD;+EAC+E;AAC/E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,sBAAsB,CAWnF;AAED,MAAM,WAAW,wBAAwB;IACvC;uDACmD;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC;IAC5C,qEAAqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;iFAEiF;AACjF,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,aAAa,EACpB,IAAI,GAAE,wBAA6B,GAClC,MAAM,CAYR"}
@@ -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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"}
@@ -6,8 +6,32 @@ export declare const SUMMARY_SYSTEM_PROMPT = "You are a timeline summarizer. Giv
6
6
  /**
7
7
  * Extract a topic hint from the first few tokens of a response.
8
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.
9
14
  */
10
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;
11
35
  /** Clean LLM output — strip thinking, quotes, markdown artifacts */
12
36
  export declare function cleanLLMOutput(content: string): string | null;
13
37
  //# sourceMappingURL=timeline-summarizer.d.ts.map
@@ -1 +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;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2C5D;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4B7D"}
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"}
@@ -11,26 +11,38 @@ export const SUMMARY_SYSTEM_PROMPT = `You are a timeline summarizer. Given an AI
11
11
  /**
12
12
  * Extract a topic hint from the first few tokens of a response.
13
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.
14
19
  */
15
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) {
16
31
  if (!text || text.length < 5)
17
- return null;
18
- const lines = text.split('\n').map(l => l.trim()).filter(Boolean);
32
+ return { hint: null, kind: null };
33
+ const lines = text.split('\n').map((l) => l.trim()).filter(Boolean);
19
34
  // Find first non-markdown, non-code-fence, non-empty line
20
35
  let candidate = null;
21
36
  let inCodeFence = false;
22
37
  for (const line of lines) {
23
- // Track code fence boundaries
24
38
  if (/^```/.test(line)) {
25
39
  inCodeFence = !inCodeFence;
26
40
  continue;
27
41
  }
28
42
  if (inCodeFence)
29
43
  continue;
30
- // Skip headings-only
31
44
  if (/^#{1,6}\s*$/.test(line))
32
45
  continue;
33
- // Strip markdown decorators for evaluation
34
46
  const stripped = cleanRawText(line)
35
47
  .replace(/^[-*]\s+/, '')
36
48
  .replace(/^>\s+/, '')
@@ -41,15 +53,45 @@ export function extractTopicHint(text) {
41
53
  }
42
54
  }
43
55
  if (!candidate)
44
- return null;
56
+ return { hint: null, kind: null };
45
57
  const snippet = candidate.length > 80 ? candidate.slice(0, 77) + '...' : candidate;
46
- // Remove common Korean prefixes (chained — "네, 확인했습니다." "")
47
- let cleaned = snippet;
48
- // Strip leading "네," / "네." first, then polite phrases
49
- cleaned = cleaned.replace(/^네[,.]?\s*/i, '');
50
- cleaned = cleaned.replace(/^(완료했습니다\.\s*|알겠습니다\.\s*|확인했습니다\.\s*)/i, '');
51
- cleaned = cleaned.trim();
52
- return cleaned || null;
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;
53
95
  }
54
96
  /** Clean LLM output — strip thinking, quotes, markdown artifacts */
55
97
  export function cleanLLMOutput(content) {
@@ -1 +1 @@
1
- {"version":3,"file":"timeline-summarizer.js","sourceRoot":"","sources":["../src/timeline-summarizer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"timeline-summarizer.js","sourceRoot":"","sources":["../src/timeline-summarizer.ts"],"names":[],"mappings":"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"}