@agimon-ai/doompi-edit 0.0.1-alpha.20 → 0.0.1-alpha.22

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-edit",
3
- "version": "0.0.1-alpha.20",
3
+ "version": "0.0.1-alpha.22",
4
4
  "description": "Snapshot-bound hashline edit tool for Pi and DoomPi.",
5
5
  "keywords": [
6
6
  "ai",
@@ -51,11 +51,11 @@
51
51
  "dependencies": {
52
52
  "@deepseek-ai/cordis": "4.0.1",
53
53
  "typebox": "1.3.19",
54
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.47",
55
- "@agimon-ai/doompi-ui": "0.0.1-alpha.48",
56
- "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.11",
57
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.8",
58
- "@agimon-ai/doompi-hashline": "0.0.1-alpha.19"
54
+ "@agimon-ai/doompi-hashline": "0.0.1-alpha.21",
55
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.10",
56
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.49",
57
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.50",
58
+ "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.13"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@earendil-works/pi-coding-agent": "0.84.4",
@@ -4,7 +4,10 @@ import {
4
4
  MessageItemBody,
5
5
  MessageItemHeader,
6
6
  MessageItemStatus,
7
+ SyntaxLine,
8
+ ToolPathLink,
7
9
  toolTone,
10
+ useSyntaxLines,
8
11
  } from '@agimon-ai/doompi-web-components';
9
12
  import type { ToolMessageRenderProps } from '@agimon-ai/doompi-web-contracts';
10
13
  import { type DiffRow, editCallView, editResultView, resultTextLines } from './editToolView.ts';
@@ -20,15 +23,53 @@ const ROW_TONE: Readonly<Record<DiffRow['marker'], string>> = {
20
23
  ' ': 'text-doom-dim',
21
24
  };
22
25
 
26
+ /**
27
+ * The banded rows, and the grammar over them.
28
+ *
29
+ * Its own component because the colours come from a hook, and the body that
30
+ * renders these rows is chosen inside a render prop. The rows are parsed as
31
+ * one document: a diff is not a file, so a replaced line is seen twice and a
32
+ * split string can colour oddly, which costs a token here and there and never
33
+ * costs the reader the text. The `+` and `-` wash stays underneath, so what
34
+ * changed is still legible when the grammar has coloured the foreground.
35
+ */
36
+ function DiffRows({ rows, gutter, path }: { rows: readonly DiffRow[]; gutter: number; path: string }) {
37
+ const spans = useSyntaxLines(rows.map((row) => row.content).join('\n'), { path });
38
+ return (
39
+ <>
40
+ {rows.map((row, index) => (
41
+ <span key={`${String(index)}-${row.lineNumber}`} className={`flex gap-2 ${ROW_TONE[row.marker]}`}>
42
+ <span className="shrink-0 text-right text-doom-faint" style={{ width: `${String(gutter)}ch` }}>
43
+ {row.lineNumber}
44
+ </span>
45
+ <span className="w-2 shrink-0">{row.marker === ' ' ? '' : row.marker}</span>
46
+ <SyntaxLine spans={spans?.[index]} text={row.content} className="min-w-0 whitespace-pre-wrap break-words" />
47
+ </span>
48
+ ))}
49
+ </>
50
+ );
51
+ }
52
+
23
53
  /**
24
54
  * The edit tool's timeline item: `path · N ranges` in the header; the display
25
55
  * diff from the result's details, banded by row, in the body. A successful
26
56
  * edit whose details never arrived shows nothing, and a failed one shows the
27
57
  * tool's message in red.
28
58
  */
29
- export function EditToolMessage({ args, result, output, running, isError }: ToolMessageRenderProps) {
59
+ export function EditToolMessage({
60
+ args,
61
+ result,
62
+ output,
63
+ running,
64
+ isError,
65
+ fileTabFor,
66
+ openTransientTab,
67
+ }: ToolMessageRenderProps) {
30
68
  const call = editCallView(args);
31
69
  const view = result === null || isError ? undefined : editResultView(result);
70
+ // The file this edit lands in, opened from the header rather than found
71
+ // again in a file list; plain text when nothing installed can show it.
72
+ const tab = fileTabFor(call.path);
32
73
  return (
33
74
  <MessageItem
34
75
  tone={toolTone({ running, isError })}
@@ -38,7 +79,7 @@ export function EditToolMessage({ args, result, output, running, isError }: Tool
38
79
  <>
39
80
  <MessageItemHeader title="edit">
40
81
  <span data-testid="tool-call-edit" className="flex min-w-0 flex-1 items-center gap-2">
41
- <span className="truncate text-doom-text">{call.path}</span>
82
+ <ToolPathLink path={call.path} {...(tab === undefined ? {} : { onOpen: () => openTransientTab(tab) })} />
42
83
  <span className="shrink-0 text-doom-faint">· {call.ranges}</span>
43
84
  </span>
44
85
  </MessageItemHeader>
@@ -62,18 +103,7 @@ export function EditToolMessage({ args, result, output, running, isError }: Tool
62
103
  const { shown, hidden } = collapseLines(view.rows, COLLAPSED_ROWS, expanded);
63
104
  return (
64
105
  <MessageItemBody data-testid="tool-result-edit" className="flex flex-col font-mono">
65
- {shown.map((row, index) => (
66
- <span key={`${String(index)}-${row.lineNumber}`} className={`flex gap-2 ${ROW_TONE[row.marker]}`}>
67
- <span
68
- className="shrink-0 text-right text-doom-faint"
69
- style={{ width: `${String(view.gutter)}ch` }}
70
- >
71
- {row.lineNumber}
72
- </span>
73
- <span className="w-2 shrink-0">{row.marker === ' ' ? '' : row.marker}</span>
74
- <span className="min-w-0 whitespace-pre-wrap break-words">{row.content}</span>
75
- </span>
76
- ))}
106
+ <DiffRows rows={shown} gutter={view.gutter} path={call.path} />
77
107
  {hidden > 0 ? (
78
108
  <MessageItemStatus expands className="pt-1">
79
109
  {hidden} more rows