@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 +10 -10
- package/web/PlanPanel.tsx +23 -15
- package/web/PlanToolMessage.tsx +7 -9
- package/web/index.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi-plan",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
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.
|
|
98
|
-
"@agimon-ai/doompi-
|
|
99
|
-
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.
|
|
100
|
-
"@agimon-ai/doompi-
|
|
101
|
-
"@agimon-ai/doompi-
|
|
102
|
-
"@agimon-ai/doompi-
|
|
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.
|
|
109
|
-
"@types/react": "19.2.
|
|
110
|
-
"@types/react-dom": "19.2.
|
|
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,
|
|
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
|
|
12
|
-
*
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
134
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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 ===
|
|
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
|
-
|
|
182
|
+
</>
|
|
175
183
|
)}
|
|
176
184
|
</div>
|
|
177
185
|
|
package/web/PlanToolMessage.tsx
CHANGED
|
@@ -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={
|
|
25
|
-
<span
|
|
26
|
-
|
|
27
|
-
{summary.detail
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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 }],
|