@pi-unipi/unipi 0.1.9 → 0.1.12
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/README.md +29 -0
- package/package.json +8 -2
- package/packages/ask-user/skills/ask-user/SKILL.md +52 -0
- package/packages/autocomplete/src/constants.ts +40 -13
- package/packages/autocomplete/src/provider.ts +21 -2
- package/packages/core/index.ts +1 -0
- package/packages/kanboard/README.md +137 -0
- package/packages/kanboard/index.ts +80 -0
- package/packages/kanboard/skills/kanboard-doctor/SKILL.md +71 -0
- package/packages/memory/index.ts +6 -0
- package/packages/milestone/README.md +123 -0
- package/packages/milestone/index.ts +72 -0
- package/packages/milestone/skills/milestone-onboard/SKILL.md +114 -0
- package/packages/milestone/skills/milestone-update/SKILL.md +109 -0
- package/packages/subagents/src/__tests__/badge-generation.test.ts +244 -0
- package/packages/subagents/src/agent-manager.ts +12 -1
- package/packages/subagents/src/agent-runner.ts +23 -8
- package/packages/subagents/src/conversation-viewer.ts +299 -0
- package/packages/subagents/src/index.ts +432 -49
- package/packages/subagents/src/types.ts +49 -0
- package/packages/subagents/src/widget.ts +332 -72
- package/packages/unipi/index.ts +4 -0
- package/packages/utility/README.md +15 -1
- package/packages/utility/src/commands.ts +101 -0
- package/packages/utility/src/index.ts +127 -9
- package/packages/utility/src/tui/badge-settings-tui.ts +388 -0
- package/packages/utility/src/tui/badge-settings.ts +108 -0
- package/packages/utility/src/tui/name-badge-state.ts +299 -0
- package/packages/utility/src/tui/name-badge.ts +117 -0
- package/packages/workflow/index.ts +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ pi install npm:@pi-unipi/notify
|
|
|
24
24
|
pi install npm:@pi-unipi/utility
|
|
25
25
|
pi install npm:@pi-unipi/mcp
|
|
26
26
|
pi install npm:@pi-unipi/ask-user
|
|
27
|
+
pi install npm:@pi-unipi/milestone
|
|
28
|
+
pi install npm:@pi-unipi/kanboard
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
## Packages
|
|
@@ -43,6 +45,8 @@ pi install npm:@pi-unipi/ask-user
|
|
|
43
45
|
| `@pi-unipi/utility` | Environment info, diagnostics, settings inspector, cleanup |
|
|
44
46
|
| `@pi-unipi/mcp` | MCP server discovery, connection, and tool integration |
|
|
45
47
|
| `@pi-unipi/ask-user` | Structured user input with options and freeform text |
|
|
48
|
+
| `@pi-unipi/milestone` | Milestone tracking and project progress management |
|
|
49
|
+
| `@pi-unipi/kanboard` | Kanboard visualization server with TUI overlay |
|
|
46
50
|
|
|
47
51
|
## Commands
|
|
48
52
|
|
|
@@ -152,6 +156,9 @@ pi install npm:@pi-unipi/ask-user
|
|
|
152
156
|
| `/unipi:status` | Show module status |
|
|
153
157
|
| `/unipi:cleanup` | Clean stale temp files |
|
|
154
158
|
| `/unipi:reload` | Reload extensions |
|
|
159
|
+
| `/unipi:name-badge` | Toggle session name badge overlay |
|
|
160
|
+
| `/unipi:badge-gen` | Generate session name via background agent |
|
|
161
|
+
| `/unipi:badge-toggle` | Configure badge settings |
|
|
155
162
|
|
|
156
163
|
### MCP (`/unipi:mcp-*`)
|
|
157
164
|
|
|
@@ -191,6 +198,24 @@ pi install npm:@pi-unipi/ask-user
|
|
|
191
198
|
| `ctx_fetch_and_index` | compactor | Fetch and index web content |
|
|
192
199
|
| `ctx_stats` | compactor | Show compaction statistics |
|
|
193
200
|
| `ctx_doctor` | compactor | Diagnose compactor issues |
|
|
201
|
+
| `set_session_name` | utility | Set session name for badge display |
|
|
202
|
+
| `ctx_batch` | utility | Atomic batch execution with rollback |
|
|
203
|
+
| `ctx_env` | utility | Show environment information |
|
|
204
|
+
|
|
205
|
+
### Milestone (`/unipi:milestone-*`)
|
|
206
|
+
|
|
207
|
+
| Command | Description |
|
|
208
|
+
|---------|-------------|
|
|
209
|
+
| `/unipi:milestone-onboard` | Create MILESTONES.md from existing workflow docs |
|
|
210
|
+
| `/unipi:milestone-update` | Sync MILESTONES.md with completed work |
|
|
211
|
+
|
|
212
|
+
### Kanboard (`/unipi:kanboard*`)
|
|
213
|
+
|
|
214
|
+
| Command | Description |
|
|
215
|
+
|---------|-------------|
|
|
216
|
+
| `/unipi:kanboard` | Toggle kanboard visualization server |
|
|
217
|
+
| `/unipi:kanboard-doctor` | Diagnose and fix kanboard parser issues |
|
|
218
|
+
| `/unipi:name-gen` | Generate session name badge via background agent |
|
|
194
219
|
|
|
195
220
|
## How It Works
|
|
196
221
|
|
|
@@ -220,6 +245,10 @@ pi install npm:@pi-unipi/ask-user
|
|
|
220
245
|
|
|
221
246
|
**Ask User** provides structured user input with multiple-choice, multi-select, and freeform text options.
|
|
222
247
|
|
|
248
|
+
**Milestone** tracks project progress with MILESTONES.md — onboards existing work and syncs with completed tasks.
|
|
249
|
+
|
|
250
|
+
**Kanboard** provides a visualization server with htmx + Alpine.js UI for kanban boards, workflow timelines, and milestone progress. Includes a TUI overlay for quick access.
|
|
251
|
+
|
|
223
252
|
## Module Discovery
|
|
224
253
|
|
|
225
254
|
Modules announce presence via `pi.events`. When `@pi-unipi/workflow` detects `@pi-unipi/ralph`, it enables loop integration. Each module works standalone.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/unipi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "All-in-one extension suite for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,6 +48,8 @@
|
|
|
48
48
|
"node_modules/@pi-unipi/mcp/src/index.ts",
|
|
49
49
|
"node_modules/@pi-unipi/compactor/src/index.ts",
|
|
50
50
|
"node_modules/@pi-unipi/notify/index.ts",
|
|
51
|
+
"node_modules/@pi-unipi/milestone/index.ts",
|
|
52
|
+
"node_modules/@pi-unipi/kanboard/index.ts",
|
|
51
53
|
"node_modules/@pi-unipi/command-enchantment/src/index.ts"
|
|
52
54
|
],
|
|
53
55
|
"skills": [
|
|
@@ -59,7 +61,9 @@
|
|
|
59
61
|
"node_modules/@pi-unipi/mcp/skills",
|
|
60
62
|
"node_modules/@pi-unipi/utility/skills",
|
|
61
63
|
"node_modules/@pi-unipi/compactor/skills",
|
|
62
|
-
"node_modules/@pi-unipi/notify/skills"
|
|
64
|
+
"node_modules/@pi-unipi/notify/skills",
|
|
65
|
+
"node_modules/@pi-unipi/milestone/skills",
|
|
66
|
+
"node_modules/@pi-unipi/kanboard/skills"
|
|
63
67
|
]
|
|
64
68
|
},
|
|
65
69
|
"peerDependencies": {
|
|
@@ -81,6 +85,8 @@
|
|
|
81
85
|
"@pi-unipi/ralph": "*",
|
|
82
86
|
"@pi-unipi/subagents": "*",
|
|
83
87
|
"@pi-unipi/utility": "*",
|
|
88
|
+
"@pi-unipi/milestone": "*",
|
|
89
|
+
"@pi-unipi/kanboard": "*",
|
|
84
90
|
"@pi-unipi/web-api": "*",
|
|
85
91
|
"@pi-unipi/workflow": "*"
|
|
86
92
|
},
|
|
@@ -38,6 +38,26 @@ Use the `ask_user` tool to collect structured input from the user.
|
|
|
38
38
|
| `allowFreeform` | boolean? | true | Add "Custom response" checkable option |
|
|
39
39
|
| `timeout` | number? | — | Auto-dismiss after N ms |
|
|
40
40
|
|
|
41
|
+
### Option Properties
|
|
42
|
+
|
|
43
|
+
| Property | Type | Default | Description |
|
|
44
|
+
|----------|------|---------|-------------|
|
|
45
|
+
| `label` | string | required | Display label |
|
|
46
|
+
| `description` | string? | — | Description shown below label |
|
|
47
|
+
| `value` | string? | label | Value returned when selected |
|
|
48
|
+
| `allowCustom` | boolean? | false | Allow user to add custom text for this option (shorthand for `action: "input"`) |
|
|
49
|
+
| `action` | string? | "select" | Special action: `"select"`, `"input"`, `"end_turn"`, `"new_session"` |
|
|
50
|
+
| `prefill` | string? | — | Prefill message for `"new_session"` action |
|
|
51
|
+
|
|
52
|
+
### Action Types
|
|
53
|
+
|
|
54
|
+
| Action | Behavior |
|
|
55
|
+
|--------|----------|
|
|
56
|
+
| `"select"` | Normal selection (default). Returns immediately. |
|
|
57
|
+
| `"input"` | Enters text input mode. Returns `combined` response with selection + text. |
|
|
58
|
+
| `"end_turn"` | Signals end of agent turn. Returns `end_turn` response kind. |
|
|
59
|
+
| `"new_session"` | Starts a new session. Returns `new_session` response kind with optional `prefill`. |
|
|
60
|
+
|
|
41
61
|
## Examples
|
|
42
62
|
|
|
43
63
|
Single choice:
|
|
@@ -98,3 +118,35 @@ ask_user({
|
|
|
98
118
|
})
|
|
99
119
|
```
|
|
100
120
|
User can check "Auth", "Cache", and "Custom response" to type additional features.
|
|
121
|
+
|
|
122
|
+
With per-option custom text:
|
|
123
|
+
```
|
|
124
|
+
ask_user({
|
|
125
|
+
question: "Does this look right?",
|
|
126
|
+
options: [
|
|
127
|
+
{ label: "Yes", value: "yes" },
|
|
128
|
+
{ label: "Partially", value: "partial", allowCustom: true },
|
|
129
|
+
{ label: "No", value: "no", allowCustom: true }
|
|
130
|
+
],
|
|
131
|
+
allowFreeform: false
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
Selecting "Partially" or "No" enters text input so the user can explain what needs to change.
|
|
135
|
+
|
|
136
|
+
With end_turn and new_session actions:
|
|
137
|
+
```
|
|
138
|
+
ask_user({
|
|
139
|
+
question: "How would you like to proceed?",
|
|
140
|
+
options: [
|
|
141
|
+
{ label: "Looks good, proceed", value: "proceed" },
|
|
142
|
+
{ label: "I want changes", value: "changes", action: "input" },
|
|
143
|
+
{ label: "Done for now", value: "done", action: "end_turn" },
|
|
144
|
+
{ label: "Start fresh", value: "new", action: "new_session", prefill: "Let's redesign the..." }
|
|
145
|
+
],
|
|
146
|
+
allowFreeform: false
|
|
147
|
+
})
|
|
148
|
+
```
|
|
149
|
+
- "Looks good" returns immediately with selection
|
|
150
|
+
- "I want changes" enters text input mode for the user to explain
|
|
151
|
+
- "Done for now" signals the agent to end its turn
|
|
152
|
+
- "Start fresh" starts a new session with the prefill message
|
|
@@ -20,6 +20,7 @@ export const PACKAGE_ORDER: string[] = [
|
|
|
20
20
|
"workflow",
|
|
21
21
|
"ralph",
|
|
22
22
|
"memory",
|
|
23
|
+
"milestone",
|
|
23
24
|
"mcp",
|
|
24
25
|
"utility",
|
|
25
26
|
"ask-user",
|
|
@@ -27,6 +28,7 @@ export const PACKAGE_ORDER: string[] = [
|
|
|
27
28
|
"web-api",
|
|
28
29
|
"compact",
|
|
29
30
|
"notify",
|
|
31
|
+
"kanboard",
|
|
30
32
|
];
|
|
31
33
|
|
|
32
34
|
// ─── Package Colors ──────────────────────────────────────────────────
|
|
@@ -35,6 +37,7 @@ export const PACKAGE_COLORS: Record<string, string> = {
|
|
|
35
37
|
workflow: `${ESC}[91m`, // Bright Red
|
|
36
38
|
ralph: `${ESC}[33m`, // Yellow/Orange
|
|
37
39
|
memory: `${ESC}[93m`, // Bright Yellow
|
|
40
|
+
milestone: `${ESC}[32m`, // Green
|
|
38
41
|
mcp: `${ESC}[32m`, // Green
|
|
39
42
|
utility: `${ESC}[36m`, // Cyan
|
|
40
43
|
"ask-user": `${ESC}[94m`, // Bright Blue
|
|
@@ -42,6 +45,7 @@ export const PACKAGE_COLORS: Record<string, string> = {
|
|
|
42
45
|
"web-api": `${ESC}[95m`, // Bright Magenta
|
|
43
46
|
compact: `${ESC}[37m`, // White
|
|
44
47
|
notify: `${ESC}[96m`, // Bright Cyan
|
|
48
|
+
kanboard: `${ESC}[92m`, // Bright Green
|
|
45
49
|
};
|
|
46
50
|
|
|
47
51
|
// ─── Command Registry ────────────────────────────────────────────────
|
|
@@ -89,13 +93,17 @@ export const COMMAND_REGISTRY: Record<string, string> = {
|
|
|
89
93
|
"unipi:mcp-settings": "mcp",
|
|
90
94
|
"unipi:mcp-reload": "mcp",
|
|
91
95
|
|
|
92
|
-
// utility (
|
|
93
|
-
"unipi:continue":
|
|
94
|
-
"unipi:reload":
|
|
95
|
-
"unipi:status":
|
|
96
|
-
"unipi:cleanup":
|
|
97
|
-
"unipi:env":
|
|
98
|
-
"unipi:doctor":
|
|
96
|
+
// utility (10 commands)
|
|
97
|
+
"unipi:continue": "utility",
|
|
98
|
+
"unipi:reload": "utility",
|
|
99
|
+
"unipi:status": "utility",
|
|
100
|
+
"unipi:cleanup": "utility",
|
|
101
|
+
"unipi:env": "utility",
|
|
102
|
+
"unipi:doctor": "utility",
|
|
103
|
+
"unipi:badge-name": "utility",
|
|
104
|
+
"unipi:badge-gen": "utility",
|
|
105
|
+
"unipi:badge-toggle": "utility",
|
|
106
|
+
"unipi:badge-settings": "utility",
|
|
99
107
|
|
|
100
108
|
// ask-user (1 command)
|
|
101
109
|
"unipi:ask-user-settings": "ask-user",
|
|
@@ -119,11 +127,19 @@ export const COMMAND_REGISTRY: Record<string, string> = {
|
|
|
119
127
|
"unipi:compact-search": "compact",
|
|
120
128
|
"unipi:compact-purge": "compact",
|
|
121
129
|
|
|
130
|
+
// milestone (2 commands)
|
|
131
|
+
"unipi:milestone-onboard": "milestone",
|
|
132
|
+
"unipi:milestone-update": "milestone",
|
|
133
|
+
|
|
122
134
|
// notify (4 commands)
|
|
123
135
|
"unipi:notify-settings": "notify",
|
|
124
136
|
"unipi:notify-set-gotify": "notify",
|
|
125
137
|
"unipi:notify-set-tg": "notify",
|
|
126
138
|
"unipi:notify-test": "notify",
|
|
139
|
+
|
|
140
|
+
// kanboard (3 commands)
|
|
141
|
+
"unipi:kanboard": "kanboard",
|
|
142
|
+
"unipi:kanboard-doctor": "kanboard",
|
|
127
143
|
};
|
|
128
144
|
|
|
129
145
|
// ─── Description Map ─────────────────────────────────────────────────
|
|
@@ -167,12 +183,18 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
167
183
|
"unipi:mcp-settings": "Configure MCP settings",
|
|
168
184
|
"unipi:mcp-reload": "Reload MCP connections",
|
|
169
185
|
|
|
170
|
-
"unipi:continue":
|
|
171
|
-
"unipi:reload":
|
|
172
|
-
"unipi:status":
|
|
173
|
-
"unipi:cleanup":
|
|
174
|
-
"unipi:env":
|
|
175
|
-
"unipi:doctor":
|
|
186
|
+
"unipi:continue": "Continue the last conversation",
|
|
187
|
+
"unipi:reload": "Reload extensions and settings",
|
|
188
|
+
"unipi:status": "Show system status",
|
|
189
|
+
"unipi:cleanup": "Clean up old sessions and cache",
|
|
190
|
+
"unipi:env": "Show environment info",
|
|
191
|
+
"unipi:doctor": "Run diagnostics",
|
|
192
|
+
"unipi:badge-name": "Toggle session name badge overlay",
|
|
193
|
+
"unipi:badge-gen": "Generate session name via background agent",
|
|
194
|
+
"unipi:badge-toggle": "Configure badge settings (autoGen, badgeEnabled, agentTool)",
|
|
195
|
+
"unipi:badge-settings": "Configure badge settings via TUI overlay",
|
|
196
|
+
"unipi:kanboard": "Start the kanboard visualization server",
|
|
197
|
+
"unipi:kanboard-doctor": "Diagnose and fix kanboard parser issues",
|
|
176
198
|
|
|
177
199
|
"unipi:ask-user-settings": "Configure ask-user settings",
|
|
178
200
|
|
|
@@ -196,6 +218,9 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
196
218
|
"unipi:notify-set-gotify": "Set up Gotify push notifications",
|
|
197
219
|
"unipi:notify-set-tg": "Set up Telegram bot notifications",
|
|
198
220
|
"unipi:notify-test": "Test all enabled notification platforms",
|
|
221
|
+
|
|
222
|
+
"unipi:milestone-onboard": "Create MILESTONES.md from existing workflow docs",
|
|
223
|
+
"unipi:milestone-update": "Sync MILESTONES.md with completed work",
|
|
199
224
|
};
|
|
200
225
|
|
|
201
226
|
// ─── Package Display Names ───────────────────────────────────────────
|
|
@@ -204,6 +229,7 @@ export const PACKAGE_LABELS: Record<string, string> = {
|
|
|
204
229
|
workflow: "workflow",
|
|
205
230
|
ralph: "ralph",
|
|
206
231
|
memory: "memory",
|
|
232
|
+
milestone: "milestone",
|
|
207
233
|
mcp: "mcp",
|
|
208
234
|
utility: "utility",
|
|
209
235
|
"ask-user": "ask-user",
|
|
@@ -211,4 +237,5 @@ export const PACKAGE_LABELS: Record<string, string> = {
|
|
|
211
237
|
"web-api": "web-api",
|
|
212
238
|
compact: "compact",
|
|
213
239
|
notify: "notify",
|
|
240
|
+
kanboard: "kanboard",
|
|
214
241
|
};
|
|
@@ -52,6 +52,7 @@ function detectNamespaceBoost(query: string): string | null {
|
|
|
52
52
|
workflow: "workflow",
|
|
53
53
|
ralph: "ralph",
|
|
54
54
|
memory: "memory",
|
|
55
|
+
milestone: "milestone",
|
|
55
56
|
mcp: "mcp",
|
|
56
57
|
utility: "utility",
|
|
57
58
|
"ask-user": "ask-user",
|
|
@@ -61,6 +62,8 @@ function detectNamespaceBoost(query: string): string | null {
|
|
|
61
62
|
notify: "notify",
|
|
62
63
|
// Unambiguous short aliases
|
|
63
64
|
mem: "memory",
|
|
65
|
+
ms: "milestone",
|
|
66
|
+
goal: "milestone",
|
|
64
67
|
util: "utility",
|
|
65
68
|
web: "web-api",
|
|
66
69
|
notification: "notify",
|
|
@@ -117,7 +120,18 @@ function getEnhancedUnipiItems(
|
|
|
117
120
|
});
|
|
118
121
|
}
|
|
119
122
|
|
|
120
|
-
//
|
|
123
|
+
// Determine match quality for ranking exact > prefix > fuzzy
|
|
124
|
+
const getMatchPriority = (cmd: string): number => {
|
|
125
|
+
const name = isPastUnipiColon
|
|
126
|
+
? cmd.replace("unipi:", "").toLowerCase()
|
|
127
|
+
: cmd.toLowerCase();
|
|
128
|
+
if (name === query) return 0; // Exact match
|
|
129
|
+
if (name.startsWith(query)) return 1; // Prefix match
|
|
130
|
+
return 2; // Fuzzy match
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Sort: boosted package first, then exact > prefix > fuzzy,
|
|
134
|
+
// then by PACKAGE_ORDER, then alphabetically.
|
|
121
135
|
matched.sort((a, b) => {
|
|
122
136
|
const pkgA = a[1];
|
|
123
137
|
const pkgB = b[1];
|
|
@@ -129,6 +143,11 @@ function getEnhancedUnipiItems(
|
|
|
129
143
|
if (!aIsBoosted && bIsBoosted) return 1;
|
|
130
144
|
}
|
|
131
145
|
|
|
146
|
+
// Rank by match quality: exact > prefix > fuzzy
|
|
147
|
+
const priA = getMatchPriority(a[0]);
|
|
148
|
+
const priB = getMatchPriority(b[0]);
|
|
149
|
+
if (priA !== priB) return priA - priB;
|
|
150
|
+
|
|
132
151
|
const orderA = PACKAGE_ORDER.indexOf(pkgA);
|
|
133
152
|
const orderB = PACKAGE_ORDER.indexOf(pkgB);
|
|
134
153
|
if (orderA !== orderB) return orderA - orderB;
|
|
@@ -262,7 +281,7 @@ export function createEnchantedProvider(
|
|
|
262
281
|
: null;
|
|
263
282
|
}
|
|
264
283
|
|
|
265
|
-
// Merge:
|
|
284
|
+
// Merge: system commands first, then enhanced unipi (sorted by package)
|
|
266
285
|
return {
|
|
267
286
|
items: [...nonUnipiItems, ...enhancedUnipiItems],
|
|
268
287
|
prefix: effectivePrefix,
|
package/packages/core/index.ts
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# @pi-unipi/kanboard
|
|
2
|
+
|
|
3
|
+
Visualization layer for unipi workflow data. Kanboard provides an HTTP server with htmx + Alpine.js UI, modular parsers for all workflow document types, two web pages (Milestones + Workflow), a TUI overlay with tasks list and kanban board, and a doctor skill for parser diagnostics.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Start the kanboard server
|
|
9
|
+
/unipi:kanboard
|
|
10
|
+
|
|
11
|
+
# Diagnose parser issues
|
|
12
|
+
/unipi:kanboard-doctor
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
kanboard/
|
|
19
|
+
├── server/ # HTTP server with port allocation
|
|
20
|
+
│ ├── index.ts # Server core (KanboardServer class)
|
|
21
|
+
│ └── routes/ # Route handlers (milestone, workflow)
|
|
22
|
+
├── parser/ # Document parsers
|
|
23
|
+
│ ├── index.ts # ParserRegistry + createDefaultRegistry()
|
|
24
|
+
│ ├── specs.ts # Spec parser (checklist items)
|
|
25
|
+
│ ├── plans.ts # Plan parser (task statuses)
|
|
26
|
+
│ ├── milestones.ts # Milestone parser
|
|
27
|
+
│ └── remaining.ts # Quick-work, debug, fix, chore, review
|
|
28
|
+
├── ui/ # Web UI
|
|
29
|
+
│ ├── layouts/ # Base HTML layout
|
|
30
|
+
│ ├── static/ # CSS + JS (style.css, app.js)
|
|
31
|
+
│ ├── components/ # Reusable components
|
|
32
|
+
│ ├── milestone/ # Milestone page renderer
|
|
33
|
+
│ └── workflow/ # Workflow page renderer
|
|
34
|
+
├── tui/ # TUI overlay
|
|
35
|
+
│ └── kanboard-overlay.ts
|
|
36
|
+
├── skills/ # Skills
|
|
37
|
+
│ └── kanboard-doctor/ # Parser diagnostics
|
|
38
|
+
├── commands.ts # Command registration
|
|
39
|
+
├── types.ts # Shared TypeScript types
|
|
40
|
+
└── index.ts # Extension entry point
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Web Pages
|
|
44
|
+
|
|
45
|
+
### Milestones (`/`)
|
|
46
|
+
- Displays MILESTONES.md phases with progress bars
|
|
47
|
+
- Checklist items with status indicators (✓ done, ○ todo)
|
|
48
|
+
- Collapsible sections per phase
|
|
49
|
+
- Copy-to-clipboard for `/unipi:milestone-update`
|
|
50
|
+
|
|
51
|
+
### Workflow (`/workflow`)
|
|
52
|
+
- Cards grouped by document type (specs, plans, fixes, etc.)
|
|
53
|
+
- Progress indicators per card
|
|
54
|
+
- Alpine.js filtering by status (All, To Do, In Progress, Done)
|
|
55
|
+
- Copy-to-clipboard for relevant commands
|
|
56
|
+
|
|
57
|
+
## TUI Overlay
|
|
58
|
+
|
|
59
|
+
Two tabs accessible via the kanboard overlay:
|
|
60
|
+
|
|
61
|
+
- **Tasks** — Flat list of all tasks from all documents with status icons
|
|
62
|
+
- **Board** — Kanban columns (To Do / In Progress / Done)
|
|
63
|
+
|
|
64
|
+
### Controls
|
|
65
|
+
- `j/k` — Navigate up/down
|
|
66
|
+
- `h/l` — Switch columns (Board tab)
|
|
67
|
+
- `Tab` or `b` — Switch between Tasks/Board tabs
|
|
68
|
+
- `t` — Switch to Tasks tab
|
|
69
|
+
- `gg/G` — Jump to top/bottom
|
|
70
|
+
- `q/Esc` — Close overlay
|
|
71
|
+
|
|
72
|
+
## API Endpoints
|
|
73
|
+
|
|
74
|
+
| Method | Path | Description |
|
|
75
|
+
|--------|------|-------------|
|
|
76
|
+
| GET | `/` | Milestone page |
|
|
77
|
+
| GET | `/workflow` | Workflow page |
|
|
78
|
+
| GET | `/api/milestones` | Milestone JSON data |
|
|
79
|
+
| GET | `/api/workflow` | Workflow JSON data |
|
|
80
|
+
| POST | `/api/docs/:type/:file/items/:line` | Update item status |
|
|
81
|
+
|
|
82
|
+
## Parser System
|
|
83
|
+
|
|
84
|
+
Kanboard parses 8 document types from `.unipi/docs/`:
|
|
85
|
+
|
|
86
|
+
| Type | Directory | What's Parsed |
|
|
87
|
+
|------|-----------|---------------|
|
|
88
|
+
| Spec | `specs/` | `- [ ]` / `- [x]` checklist items |
|
|
89
|
+
| Plan | `plans/` | `unstarted:` / `in-progress:` / `completed:` statuses |
|
|
90
|
+
| Milestone | `MILESTONES.md` | Phase headers + checklist items |
|
|
91
|
+
| Quick-work | `quick-work/` | Title + checklist items |
|
|
92
|
+
| Debug | `debug/` | Headers + checklists |
|
|
93
|
+
| Fix | `fix/` | Headers + checklists + related debug ref |
|
|
94
|
+
| Chore | `chore/` | Chore steps as checklist items |
|
|
95
|
+
| Review | `reviews/` | Review remarks as checklist items |
|
|
96
|
+
|
|
97
|
+
### Parser Warnings
|
|
98
|
+
|
|
99
|
+
Parsers are resilient — they collect warnings per file and return partial results:
|
|
100
|
+
- Empty checkbox text
|
|
101
|
+
- Malformed checkboxes
|
|
102
|
+
- Missing frontmatter
|
|
103
|
+
- Unparseable lines
|
|
104
|
+
|
|
105
|
+
Warnings are surfaced in the kanboard-doctor skill.
|
|
106
|
+
|
|
107
|
+
## Doctor Skill
|
|
108
|
+
|
|
109
|
+
The `kanboard-doctor` skill runs all parsers and produces a diagnostic report:
|
|
110
|
+
|
|
111
|
+
1. **Run All Parsers** — Parse every document
|
|
112
|
+
2. **Collect Errors** — Group warnings by file
|
|
113
|
+
3. **Present Report** — Structured error listing
|
|
114
|
+
4. **Fix One by One** — Suggest fixes, ask user to confirm
|
|
115
|
+
5. **Re-validate** — Re-run parser after each fix
|
|
116
|
+
|
|
117
|
+
## Server Configuration
|
|
118
|
+
|
|
119
|
+
Default configuration (from `@pi-unipi/core`):
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
KANBOARD_DEFAULTS = {
|
|
123
|
+
PORT: 8165, // Starting port
|
|
124
|
+
MAX_PORT: 8175, // Maximum port to try
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- Port allocation: tries 8165, increments on EADDRINUSE
|
|
129
|
+
- PID file: `.unipi/kanboard.pid`
|
|
130
|
+
- Graceful shutdown on SIGINT/SIGTERM
|
|
131
|
+
- Static files served from `ui/static/`
|
|
132
|
+
|
|
133
|
+
## Dependencies
|
|
134
|
+
|
|
135
|
+
- `@pi-unipi/core` — Shared constants and utilities
|
|
136
|
+
- `@mariozechner/pi-coding-agent` — Extension API
|
|
137
|
+
- `@mariozechner/pi-tui` — TUI overlay API
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pi-unipi/kanboard — Extension entry
|
|
3
|
+
*
|
|
4
|
+
* Visualization layer for unipi workflow data.
|
|
5
|
+
* HTTP server with htmx + Alpine.js UI, modular parsers, TUI overlay, and kanban board.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
9
|
+
import { MODULES, KANBOARD_COMMANDS } from "@pi-unipi/core";
|
|
10
|
+
import { registerCommands } from "./commands.js";
|
|
11
|
+
|
|
12
|
+
/** Package version */
|
|
13
|
+
const VERSION = "0.1.0";
|
|
14
|
+
|
|
15
|
+
export default function (pi: ExtensionAPI): void {
|
|
16
|
+
// Register skills directory
|
|
17
|
+
const skillsDir = new URL("./skills", import.meta.url).pathname;
|
|
18
|
+
|
|
19
|
+
pi.on("resources_discover", async () => {
|
|
20
|
+
return {
|
|
21
|
+
skillPaths: [skillsDir],
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Register commands
|
|
26
|
+
registerCommands(pi);
|
|
27
|
+
|
|
28
|
+
// Note: Badge generation on first message is handled by the utility module.
|
|
29
|
+
// Kanboard no longer manages badge generation to avoid duplication.
|
|
30
|
+
|
|
31
|
+
// Register info-screen group
|
|
32
|
+
const globalObj = globalThis as any;
|
|
33
|
+
const registry = globalObj.__unipi_info_registry;
|
|
34
|
+
if (registry) {
|
|
35
|
+
registry.registerGroup({
|
|
36
|
+
id: "kanboard",
|
|
37
|
+
name: "Kanboard",
|
|
38
|
+
icon: "📋",
|
|
39
|
+
priority: 50,
|
|
40
|
+
config: {
|
|
41
|
+
showByDefault: true,
|
|
42
|
+
stats: [
|
|
43
|
+
{ id: "status", label: "Server Status", show: true },
|
|
44
|
+
{ id: "url", label: "URL", show: true },
|
|
45
|
+
{ id: "docs", label: "Documents", show: true },
|
|
46
|
+
{ id: "tasks", label: "Tasks", show: true },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
dataProvider: async () => {
|
|
50
|
+
const { createDefaultRegistry } = await import("./parser/index.js");
|
|
51
|
+
const registry = await createDefaultRegistry();
|
|
52
|
+
const docs = registry.parseAll(".unipi/docs");
|
|
53
|
+
const totalItems = docs.reduce((sum, d) => sum + d.items.length, 0);
|
|
54
|
+
const doneItems = docs.reduce(
|
|
55
|
+
(sum, d) => sum + d.items.filter((i) => i.status === "done").length,
|
|
56
|
+
0,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
status: {
|
|
61
|
+
value: "Ready",
|
|
62
|
+
detail: "Server not running (use /unipi:kanboard to start)",
|
|
63
|
+
},
|
|
64
|
+
url: {
|
|
65
|
+
value: "—",
|
|
66
|
+
detail: "Start server to get URL",
|
|
67
|
+
},
|
|
68
|
+
docs: {
|
|
69
|
+
value: String(docs.length),
|
|
70
|
+
detail: `${docs.length} documents parsed`,
|
|
71
|
+
},
|
|
72
|
+
tasks: {
|
|
73
|
+
value: `${doneItems}/${totalItems}`,
|
|
74
|
+
detail: `${totalItems > 0 ? Math.round((doneItems / totalItems) * 100) : 0}% complete`,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kanboard-doctor
|
|
3
|
+
description: "Diagnose and fix kanboard parser issues — validates all workflow documents, reports errors, suggests fixes."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Kanboard Doctor
|
|
7
|
+
|
|
8
|
+
Diagnose parser issues across all workflow documents. Non-destructive — only suggests fixes, asks user to confirm.
|
|
9
|
+
|
|
10
|
+
## Phase 1: Run All Parsers
|
|
11
|
+
|
|
12
|
+
Execute each parser against its document type directory:
|
|
13
|
+
|
|
14
|
+
1. Load the parser registry from `@pi-unipi/kanboard`
|
|
15
|
+
2. Run `registry.parseAll(".unipi/docs")` to parse all documents
|
|
16
|
+
3. Collect all `ParsedDoc` results including their `warnings` arrays
|
|
17
|
+
|
|
18
|
+
## Phase 2: Collect Errors
|
|
19
|
+
|
|
20
|
+
Group warnings and errors by file with line numbers:
|
|
21
|
+
|
|
22
|
+
1. For each `ParsedDoc` with `warnings.length > 0`:
|
|
23
|
+
- Group by `filePath`
|
|
24
|
+
- Include line numbers where available
|
|
25
|
+
- Categorize: malformed checkboxes, empty fields, parse failures
|
|
26
|
+
2. Also flag documents that returned 0 items (may indicate parsing failure)
|
|
27
|
+
|
|
28
|
+
## Phase 3: Present Report
|
|
29
|
+
|
|
30
|
+
Show a structured error report:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
📋 Kanboard Doctor Report
|
|
34
|
+
|
|
35
|
+
Files scanned: N
|
|
36
|
+
Files with issues: M
|
|
37
|
+
|
|
38
|
+
📄 .unipi/docs/specs/example.md
|
|
39
|
+
⚠ Line 15: Empty checkbox text
|
|
40
|
+
⚠ Line 23: Malformed checkbox (missing bracket)
|
|
41
|
+
|
|
42
|
+
📄 .unipi/docs/plans/old-plan.md
|
|
43
|
+
⚠ Line 5: Empty task name after status
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Phase 4: Fix One by One
|
|
47
|
+
|
|
48
|
+
For each issue, suggest a fix and ask user to confirm:
|
|
49
|
+
|
|
50
|
+
1. Show the problematic line with context
|
|
51
|
+
2. Suggest the corrected version
|
|
52
|
+
3. Ask: "Apply this fix? (y/n)"
|
|
53
|
+
4. If yes, apply the fix using the edit tool
|
|
54
|
+
5. Move to next issue
|
|
55
|
+
|
|
56
|
+
**Non-destructive rules:**
|
|
57
|
+
- Never modify without asking
|
|
58
|
+
- Show before/after for each change
|
|
59
|
+
- Allow skipping individual fixes
|
|
60
|
+
- Allow "fix all" for simple patterns (e.g., trailing whitespace)
|
|
61
|
+
|
|
62
|
+
## Phase 5: Re-validate
|
|
63
|
+
|
|
64
|
+
After each fix, re-run the parser on the modified file:
|
|
65
|
+
|
|
66
|
+
1. Parse the file again
|
|
67
|
+
2. Verify the specific error is resolved
|
|
68
|
+
3. Check that no new errors were introduced
|
|
69
|
+
4. Report: "✓ Fixed" or "✗ Still has issues"
|
|
70
|
+
|
|
71
|
+
After all fixes, run full `registry.parseAll()` to confirm clean state.
|
package/packages/memory/index.ts
CHANGED
|
@@ -75,6 +75,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
75
75
|
projectStorage = new MemoryStorage(projectName);
|
|
76
76
|
try {
|
|
77
77
|
projectStorage.init();
|
|
78
|
+
|
|
79
|
+
// Sync any orphaned markdown files into the database
|
|
80
|
+
const synced = projectStorage.syncOrphanedFiles();
|
|
81
|
+
if (synced > 0) {
|
|
82
|
+
console.warn(`[unipi/memory] Synced ${synced} orphaned memory files into database`);
|
|
83
|
+
}
|
|
78
84
|
} catch (err) {
|
|
79
85
|
console.warn("[unipi/memory] Failed to initialize storage, running without memory:", (err as any)?.message ?? err);
|
|
80
86
|
projectStorage = null;
|