@agimon-ai/doompi-plan 0.0.1-alpha.42 → 0.0.1-alpha.44

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-plan",
3
- "version": "0.0.1-alpha.42",
3
+ "version": "0.0.1-alpha.44",
4
4
  "description": "Reviewable Pi planning mode that removes file-editing tools and persists implementation plans.",
5
5
  "keywords": [
6
6
  "ai",
@@ -94,20 +94,20 @@
94
94
  },
95
95
  "dependencies": {
96
96
  "@deepseek-ai/cordis": "4.0.1",
97
- "hono": "4.13.3",
98
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.3",
99
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.42",
100
- "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.5",
101
- "@agimon-ai/doompi-telemetry": "0.0.1-alpha.42",
102
- "@agimon-ai/doompi-config": "0.0.1-alpha.42"
97
+ "hono": "4.13.5",
98
+ "@agimon-ai/doompi-config": "0.0.1-alpha.44",
99
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.44",
100
+ "@agimon-ai/doompi-telemetry": "0.0.1-alpha.44",
101
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.5",
102
+ "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.7"
103
103
  },
104
104
  "devDependencies": {
105
105
  "@earendil-works/pi-coding-agent": "0.84.4",
106
106
  "@tanstack/react-store": "0.11.1",
107
107
  "@tanstack/store": "0.11.1",
108
- "@types/node": "26.2.0",
109
- "@types/react": "19.2.7",
110
- "@types/react-dom": "19.2.3",
108
+ "@types/node": "26.4.0",
109
+ "@types/react": "19.2.18",
110
+ "@types/react-dom": "19.2.5",
111
111
  "@vitest/coverage-v8": "4.1.11",
112
112
  "react": "19.2.8",
113
113
  "react-dom": "19.2.8",
package/web/PlanPanel.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { Button, Markdown, Textarea } from '@agimon-ai/doompi-web-components';
1
+ import { Button, CodeEditor, Markdown } from '@agimon-ai/doompi-web-components';
2
2
  import type { TransientTab, WebPluginSlotProps } from '@agimon-ai/doompi-web-contracts';
3
3
  import { useEffect, useState } from 'react';
4
4
  import { PLAN_STATUS_KEY, type PlanDetailView } from '../src/types/planApi.ts';
@@ -8,8 +8,9 @@ import { fetchPlan, savePlan } from './planApi.ts';
8
8
  * The plan's tab: what the agent decided, and what the reader wants changed.
9
9
  *
10
10
  * Two views over the same file. A plan is read, not diffed, so preview is
11
- * where it opens; source is where a reader corrects a step themselves rather
12
- * than spending a turn asking for it. The save goes to the plan file the
11
+ * where it opens; source is a real editor, line numbers and markdown colour
12
+ * and all, because a reader who corrects a step themselves is cheaper than a
13
+ * turn spent asking for it. The save goes to the plan file the
13
14
  * session recorded, and the next turn reads that file, so a correction made
14
15
  * here is the plan the agent implements.
15
16
  *
@@ -23,6 +24,9 @@ type View = 'preview' | 'source';
23
24
  /** One tab per session; the plan is singular, so the id needs nothing else. */
24
25
  export const PLAN_TAB_ID = 'plan-document';
25
26
 
27
+ /** The one note that is not an error: anything else in that slot failed. */
28
+ const SAVED_NOTE = 'saved';
29
+
26
30
  export function PlanPanel({ sessionId, statuses, closeTransientTab }: WebPluginSlotProps) {
27
31
  const [detail, setDetail] = useState<PlanDetailView | undefined>(undefined);
28
32
  const [error, setError] = useState<string | undefined>(undefined);
@@ -68,7 +72,7 @@ export function PlanPanel({ sessionId, statuses, closeTransientTab }: WebPluginS
68
72
  const result = await savePlan(sessionId, detail.hash, draft);
69
73
  setSaving(false);
70
74
  if (result.ok) {
71
- setSaveNote('saved');
75
+ setSaveNote(SAVED_NOTE);
72
76
  setDraft(undefined);
73
77
  const refreshed = await fetchPlan(sessionId);
74
78
  if (refreshed.ok) setDetail(refreshed.detail);
@@ -120,26 +124,30 @@ export function PlanPanel({ sessionId, statuses, closeTransientTab }: WebPluginS
120
124
  </p>
121
125
  )}
122
126
 
123
- <div className="min-h-0 flex-1 overflow-y-auto">
127
+ <div className="flex min-h-0 flex-1 flex-col">
124
128
  {detail === undefined ? null : detail.unavailable ? (
125
129
  <p data-testid="plan-unavailable" className="px-4 py-3 text-[11px] text-doom-faint">
126
130
  {detail.reason ?? 'this plan cannot be shown'}
127
131
  </p>
128
132
  ) : view === 'preview' ? (
129
- <div data-testid="plan-preview" className="flex flex-col gap-2 p-4 text-[12px] text-doom-text">
133
+ <div
134
+ data-testid="plan-preview"
135
+ className="flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto p-4 text-[12px] text-doom-text"
136
+ >
130
137
  <Markdown text={content} />
131
138
  </div>
132
139
  ) : (
133
- <div className="flex flex-col gap-2 p-3">
134
- <Textarea
140
+ <>
141
+ {/* The editor owns the scrolling: its gutter has to stay put while
142
+ the text moves, which an outer scroll container would break. */}
143
+ <CodeEditor
135
144
  data-testid="plan-source"
136
145
  value={content}
137
- spellCheck={false}
138
- rows={24}
139
- onChange={(event) => setDraft(event.target.value)}
140
- className="min-h-[24rem] font-mono text-[11px] leading-[1.5]"
146
+ path={detail.path}
147
+ onChange={setDraft}
148
+ className="min-h-0 flex-1"
141
149
  />
142
- <div className="flex items-center gap-2">
150
+ <div className="flex shrink-0 items-center gap-2 border-t border-doom-border px-3 py-2">
143
151
  <Button
144
152
  variant="outline"
145
153
  size="xs"
@@ -165,13 +173,13 @@ export function PlanPanel({ sessionId, statuses, closeTransientTab }: WebPluginS
165
173
  {saveNote === undefined ? null : (
166
174
  <span
167
175
  data-testid="plan-save-note"
168
- className={saveNote === 'saved' ? 'text-[9px] text-doom-green' : 'text-[9px] text-doom-red'}
176
+ className={saveNote === SAVED_NOTE ? 'text-[9px] text-doom-green' : 'text-[9px] text-doom-red'}
169
177
  >
170
178
  {saveNote}
171
179
  </span>
172
180
  )}
173
181
  </div>
174
- </div>
182
+ </>
175
183
  )}
176
184
  </div>
177
185
 
@@ -21,15 +21,13 @@ export function PlanToolMessage({ toolName, args, result, running, isError }: To
21
21
  <MessageItem tone={toolTone({ running, isError })} expandable={full.length > collapsed.length}>
22
22
  {({ expanded }) => (
23
23
  <>
24
- <MessageItemHeader title={toolName}>
25
- <span data-testid={`tool-call-${toolName}`} className="flex min-w-0 flex-1 items-center gap-2">
26
- <span className="font-bold text-doom-hi">{summary.action}</span>
27
- {summary.detail ? <span className="min-w-0 truncate text-doom-faint">{summary.detail}</span> : null}
28
- {summary.metadata.map((value) => (
29
- <span key={value} className="shrink-0 text-doom-dim">
30
- · {value}
31
- </span>
32
- ))}
24
+ <MessageItemHeader title={summary.action}>
25
+ <span
26
+ data-testid={`tool-call-${toolName}`}
27
+ title={[summary.detail, ...summary.metadata].filter(Boolean).join(' · ') || undefined}
28
+ className="min-w-0 flex-1 truncate text-doom-dim"
29
+ >
30
+ {[summary.detail, ...summary.metadata].filter(Boolean).join(' · ')}
33
31
  </span>
34
32
  </MessageItemHeader>
35
33
  {(expanded ? full : collapsed).length > 0 ? (
package/web/index.ts CHANGED
@@ -18,7 +18,9 @@ export const webPlugin = defineWebPlugin({
18
18
  // which is when a reader most wants it open. There is no `tab`, so the chip
19
19
  // stays the label for the TUI's SPC p e; the section's row is the way in,
20
20
  // and a leader binding could not open a transient tab anyway.
21
- activityGroups: [{ name: 'plan', keys: 'p e', statusKey: PLAN_STATUS_KEY, order: 25 }],
21
+ // `marksBackgroundWork: false`: a saved plan is a document, not a running
22
+ // process, so it must not count toward the dock's "N running" badge.
23
+ activityGroups: [{ name: 'plan', keys: 'p e', statusKey: PLAN_STATUS_KEY, marksBackgroundWork: false, order: 25 }],
22
24
  // Same name as the group: the dock renders this inside it, in place of the
23
25
  // raw status line the session publishes for a terminal footer.
24
26
  activitySections: [{ id: 'plan', component: PlanActivitySection }],