@unbrained/pm-web 2026.8.7 → 2026.8.14
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/CHANGELOG.md +16 -0
- package/dist/app.d.ts +16 -0
- package/dist/app.js +16 -0
- package/dist/app.js.map +1 -1
- package/dist/auth.d.ts +5 -0
- package/dist/auth.js.map +1 -1
- package/dist/board.d.ts +53 -0
- package/dist/board.js +48 -0
- package/dist/board.js.map +1 -1
- package/dist/crypto.d.ts +23 -0
- package/dist/crypto.js +32 -0
- package/dist/crypto.js.map +1 -1
- package/dist/db.d.ts +19 -0
- package/dist/db.js +19 -0
- package/dist/db.js.map +1 -1
- package/dist/ical.d.ts +72 -0
- package/dist/ical.js +73 -0
- package/dist/ical.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.js +52 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +8 -0
- package/dist/middleware/auth.js.map +1 -1
- package/dist/oidc.d.ts +87 -0
- package/dist/oidc.js +113 -0
- package/dist/oidc.js.map +1 -1
- package/dist/routes/admin.js +15 -0
- package/dist/routes/admin.js.map +1 -1
- package/dist/routes/github.js +13 -0
- package/dist/routes/github.js.map +1 -1
- package/dist/routes/oidc.d.ts +10 -0
- package/dist/routes/oidc.js +51 -0
- package/dist/routes/oidc.js.map +1 -1
- package/dist/routes/pm.js +132 -1
- package/dist/routes/pm.js.map +1 -1
- package/dist/routes/sharing.js +8 -0
- package/dist/routes/sharing.js.map +1 -1
- package/dist/services/mutation-event-watcher.js +13 -0
- package/dist/services/mutation-event-watcher.js.map +1 -1
- package/dist/services/pm-runner.d.ts +82 -0
- package/dist/services/pm-runner.js +121 -0
- package/dist/services/pm-runner.js.map +1 -1
- package/dist/services/project-watcher.d.ts +22 -0
- package/dist/services/project-watcher.js +51 -0
- package/dist/services/project-watcher.js.map +1 -1
- package/dist/services/realtime-bus.d.ts +46 -0
- package/dist/services/realtime-bus.js +59 -0
- package/dist/services/realtime-bus.js.map +1 -1
- package/dist/services/sse.d.ts +134 -0
- package/dist/services/sse.js +145 -0
- package/dist/services/sse.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +5 -3
- package/public/src/app.js +44 -1
- package/public/src/app.js.map +1 -1
- package/public/src/app.ts +44 -1
- package/public/src/components/modals.js +11 -0
- package/public/src/components/modals.js.map +1 -1
- package/public/src/components/modals.ts +11 -0
- package/public/src/components/toast.js +2 -0
- package/public/src/components/toast.js.map +1 -1
- package/public/src/components/toast.ts +2 -0
- package/public/src/constants.js +21 -4
- package/public/src/constants.js.map +1 -1
- package/public/src/constants.ts +21 -4
- package/public/src/filters.js +10 -7
- package/public/src/filters.js.map +1 -1
- package/public/src/filters.ts +10 -7
- package/public/src/i18n.js +11 -1
- package/public/src/i18n.js.map +1 -1
- package/public/src/i18n.ts +13 -1
- package/public/src/state.js +3 -0
- package/public/src/state.js.map +1 -1
- package/public/src/state.ts +3 -0
- package/public/src/sw.ts +71 -7
- package/public/src/theme.js +13 -1
- package/public/src/theme.js.map +1 -1
- package/public/src/theme.ts +15 -1
- package/public/src/types.ts +2 -0
- package/public/src/utils.js +26 -1
- package/public/src/utils.js.map +1 -1
- package/public/src/utils.ts +26 -1
- package/public/src/views/activity.js +1 -0
- package/public/src/views/activity.js.map +1 -1
- package/public/src/views/activity.ts +1 -0
- package/public/src/views/admin.js +134 -0
- package/public/src/views/admin.js.map +1 -1
- package/public/src/views/admin.ts +134 -0
- package/public/src/views/auth.js +31 -0
- package/public/src/views/auth.js.map +1 -1
- package/public/src/views/auth.ts +31 -0
- package/public/src/views/calendar.js +3 -0
- package/public/src/views/calendar.js.map +1 -1
- package/public/src/views/calendar.ts +3 -0
- package/public/src/views/comments-audit.js +1 -0
- package/public/src/views/comments-audit.js.map +1 -1
- package/public/src/views/comments-audit.ts +1 -0
- package/public/src/views/config.js +67 -0
- package/public/src/views/config.js.map +1 -1
- package/public/src/views/config.ts +67 -0
- package/public/src/views/context.js +2 -0
- package/public/src/views/context.js.map +1 -1
- package/public/src/views/context.ts +2 -0
- package/public/src/views/create.js +3 -0
- package/public/src/views/create.js.map +1 -1
- package/public/src/views/create.ts +3 -0
- package/public/src/views/dedupe.js +1 -0
- package/public/src/views/dedupe.js.map +1 -1
- package/public/src/views/dedupe.ts +1 -0
- package/public/src/views/export.js +6 -0
- package/public/src/views/export.js.map +1 -1
- package/public/src/views/export.ts +6 -0
- package/public/src/views/github.js +58 -0
- package/public/src/views/github.js.map +1 -1
- package/public/src/views/github.ts +58 -0
- package/public/src/views/graph-canvas.js +18 -0
- package/public/src/views/graph-canvas.js.map +1 -1
- package/public/src/views/graph-canvas.ts +20 -0
- package/public/src/views/graph.js +41 -0
- package/public/src/views/graph.js.map +1 -1
- package/public/src/views/graph.ts +42 -1
- package/public/src/views/groups.js +45 -0
- package/public/src/views/groups.js.map +1 -1
- package/public/src/views/groups.ts +45 -0
- package/public/src/views/guide.js +3 -0
- package/public/src/views/guide.js.map +1 -1
- package/public/src/views/guide.ts +3 -0
- package/public/src/views/health.js +3 -0
- package/public/src/views/health.js.map +1 -1
- package/public/src/views/health.ts +3 -0
- package/public/src/views/items.js +196 -6
- package/public/src/views/items.js.map +1 -1
- package/public/src/views/items.ts +196 -6
- package/public/src/views/normalize.js +2 -0
- package/public/src/views/normalize.js.map +1 -1
- package/public/src/views/normalize.ts +2 -0
- package/public/src/views/packages.js +41 -0
- package/public/src/views/packages.js.map +1 -1
- package/public/src/views/packages.ts +41 -0
- package/public/src/views/plan-execution.js +6 -0
- package/public/src/views/plan-execution.js.map +1 -1
- package/public/src/views/plan-execution.ts +8 -0
- package/public/src/views/plan.js +145 -0
- package/public/src/views/plan.js.map +1 -1
- package/public/src/views/plan.ts +146 -1
- package/public/src/views/projects.js +60 -0
- package/public/src/views/projects.js.map +1 -1
- package/public/src/views/projects.ts +60 -0
- package/public/src/views/router.js +43 -0
- package/public/src/views/router.js.map +1 -1
- package/public/src/views/router.ts +43 -0
- package/public/src/views/search.js +5 -0
- package/public/src/views/search.js.map +1 -1
- package/public/src/views/search.ts +5 -0
- package/public/src/views/settings.js +36 -0
- package/public/src/views/settings.js.map +1 -1
- package/public/src/views/settings.ts +36 -0
- package/public/src/views/shared.js +1 -0
- package/public/src/views/shared.js.map +1 -1
- package/public/src/views/shared.ts +1 -0
- package/public/src/views/sharing.js +32 -0
- package/public/src/views/sharing.js.map +1 -1
- package/public/src/views/sharing.ts +32 -0
- package/public/src/views/stats.js +1 -0
- package/public/src/views/stats.js.map +1 -1
- package/public/src/views/stats.ts +1 -0
- package/public/src/views/templates.js +4 -0
- package/public/src/views/templates.js.map +1 -1
- package/public/src/views/templates.ts +4 -0
- package/public/src/views/validate.js +1 -0
- package/public/src/views/validate.js.map +1 -1
- package/public/src/views/validate.ts +1 -0
- package/public/sw.js +60 -5
|
@@ -60,6 +60,12 @@ let currentPackages: PackageRow[] = [];
|
|
|
60
60
|
*/
|
|
61
61
|
let packagesFetchToken = 0;
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Mounts the packages view into the #content-packages element. Wires the
|
|
65
|
+
* action handler, shows an empty state when no project is selected, otherwise
|
|
66
|
+
* renders the header and a loading placeholder, then fetches and renders the
|
|
67
|
+
* package cards.
|
|
68
|
+
*/
|
|
63
69
|
export async function renderPackagesView(): Promise<void> {
|
|
64
70
|
ensureActionsWired();
|
|
65
71
|
const el = document.getElementById('content-packages');
|
|
@@ -82,6 +88,12 @@ export async function renderPackagesView(): Promise<void> {
|
|
|
82
88
|
await fetchAndRenderPackages();
|
|
83
89
|
}
|
|
84
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Fetches the project's package catalog from the extensions endpoint and
|
|
93
|
+
* renders the package cards into the content container, or an empty/error
|
|
94
|
+
* state. Uses a fetch token to discard stale responses that resolve after a
|
|
95
|
+
* project switch or a newer refresh.
|
|
96
|
+
*/
|
|
85
97
|
async function fetchAndRenderPackages(): Promise<void> {
|
|
86
98
|
const pid = state.currentProject?.id;
|
|
87
99
|
if (!pid) return;
|
|
@@ -111,6 +123,14 @@ async function fetchAndRenderPackages(): Promise<void> {
|
|
|
111
123
|
}
|
|
112
124
|
}
|
|
113
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Renders one package as a card showing its title, install status and
|
|
128
|
+
* version, a template badge for authoring scaffolds, honest gating notes for
|
|
129
|
+
* required services or credentials, its capabilities, and action buttons
|
|
130
|
+
* appropriate to its installed/active state.
|
|
131
|
+
* @param row - The package catalog row to render.
|
|
132
|
+
* @returns The card markup string.
|
|
133
|
+
*/
|
|
114
134
|
function renderPackageCard(row: PackageRow): string {
|
|
115
135
|
const statusChip = row.installed
|
|
116
136
|
? `<span style="font-size:11px;color:var(--text-muted);background:var(--bg-input);padding:2px 8px;border-radius:4px">${escHtml(t('packages.installed'))}${row.version ? ' · ' + escHtml(t('packages.version', { version: row.version })) : ''}</span>`
|
|
@@ -180,6 +200,13 @@ function renderPackageCard(row: PackageRow): string {
|
|
|
180
200
|
// Delegate clicks on package action buttons so each card stays simple and the
|
|
181
201
|
// handler resolves the action + name from data attributes, then calls the
|
|
182
202
|
// server-validated extensions route.
|
|
203
|
+
/**
|
|
204
|
+
* Installs a delegated click handler on the given container that routes
|
|
205
|
+
* package action button clicks (install/activate/deactivate/uninstall) to the
|
|
206
|
+
* package action handler, reading the action and package name from data
|
|
207
|
+
* attributes.
|
|
208
|
+
* @param root - The container element capturing the clicks.
|
|
209
|
+
*/
|
|
183
210
|
function wirePackageActions(root: HTMLElement): void {
|
|
184
211
|
root.addEventListener('click', (ev: MouseEvent) => {
|
|
185
212
|
const btn = (ev.target as HTMLElement).closest<HTMLButtonElement>('[data-pkg-action]');
|
|
@@ -191,6 +218,16 @@ function wirePackageActions(root: HTMLElement): void {
|
|
|
191
218
|
});
|
|
192
219
|
}
|
|
193
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Performs a package action against the extensions route for the current
|
|
223
|
+
* project. Disables and marks the clicked button while in flight, confirms
|
|
224
|
+
* before uninstalling, picks the HTTP method and URL suffix from the action,
|
|
225
|
+
* toasts the result, and re-renders the package list. Restores the button on
|
|
226
|
+
* failure.
|
|
227
|
+
* @param name - The catalog name of the target package.
|
|
228
|
+
* @param action - One of install, activate, deactivate, or uninstall.
|
|
229
|
+
* @param btn - The button element that triggered the action.
|
|
230
|
+
*/
|
|
194
231
|
async function handlePackageAction(name: string, action: string, btn: HTMLButtonElement): Promise<void> {
|
|
195
232
|
const pid = state.currentProject?.id;
|
|
196
233
|
if (!pid) return;
|
|
@@ -226,6 +263,10 @@ async function handlePackageAction(name: string, action: string, btn: HTMLButton
|
|
|
226
263
|
|
|
227
264
|
// Wire the delegated action handler once the view container exists.
|
|
228
265
|
let actionsWired = false;
|
|
266
|
+
/**
|
|
267
|
+
* Wires the delegated package action handler onto the #content-packages
|
|
268
|
+
* container exactly once, guarded by the actionsWired flag.
|
|
269
|
+
*/
|
|
229
270
|
function ensureActionsWired(): void {
|
|
230
271
|
if (actionsWired) return;
|
|
231
272
|
const root = document.getElementById('content-packages');
|
|
@@ -8,6 +8,7 @@ function normalizeStepRef(step, index) {
|
|
|
8
8
|
const candidate = (step.ref || step.id || '').trim();
|
|
9
9
|
return candidate || `step-${index + 1}`;
|
|
10
10
|
}
|
|
11
|
+
/** Returns the de-duplicated, trimmed dependency refs declared on a step, accepting either the camelCase or snake_case dependency field. */
|
|
11
12
|
function normalizeDependsOn(step) {
|
|
12
13
|
const raw = Array.isArray(step.dependsOn)
|
|
13
14
|
? step.dependsOn
|
|
@@ -23,6 +24,7 @@ function normalizeDependsOn(step) {
|
|
|
23
24
|
function formatStepLine(step) {
|
|
24
25
|
return `- [${step.ref}] ${step.title}`;
|
|
25
26
|
}
|
|
27
|
+
/** Returns a human-readable reason a step is waiting — joining its incomplete dependencies and unresolved (missing) ones — or the literal "waiting" when there are none. */
|
|
26
28
|
function formatWaitReason(step) {
|
|
27
29
|
const blockers = [
|
|
28
30
|
...step.incompleteDependencies,
|
|
@@ -32,12 +34,14 @@ function formatWaitReason(step) {
|
|
|
32
34
|
return 'waiting';
|
|
33
35
|
return `waiting on ${blockers.join(', ')}`;
|
|
34
36
|
}
|
|
37
|
+
/** Returns the combined list of a step's incomplete dependencies and its unresolved (missing) dependencies, with each missing ref suffixed by " (missing)". */
|
|
35
38
|
function stepDependencyBlockers(step) {
|
|
36
39
|
return [
|
|
37
40
|
...step.incompleteDependencies,
|
|
38
41
|
...step.unresolvedDependencies.map(dep => `${dep} (missing)`),
|
|
39
42
|
];
|
|
40
43
|
}
|
|
44
|
+
/** Builds an execution snapshot from raw plan steps: normalizes each step, resolves dependencies against completed steps, and partitions the not-done steps into ready, waiting, and blocked buckets along with completion percentage and the next ready step. */
|
|
41
45
|
export function buildPlanExecutionSnapshot(steps) {
|
|
42
46
|
const normalized = steps.map((step, index) => {
|
|
43
47
|
const status = normalizeStatus(step.status);
|
|
@@ -107,6 +111,7 @@ export function buildPlanExecutionSnapshot(steps) {
|
|
|
107
111
|
nextReadyStep: readySteps[0] || null,
|
|
108
112
|
};
|
|
109
113
|
}
|
|
114
|
+
/** Builds a markdown agent brief for a plan, summarizing plan metadata and the ready, waiting, and blocked steps from the execution snapshot, closing with a single execution instruction. */
|
|
110
115
|
export function buildPlanAgentBrief(plan, snapshot) {
|
|
111
116
|
const title = (plan.title || plan.id || '(untitled)').trim();
|
|
112
117
|
const lines = [
|
|
@@ -146,6 +151,7 @@ export function buildPlanAgentBrief(plan, snapshot) {
|
|
|
146
151
|
lines.push('', 'Instruction:', 'Pick the top ready step, execute it end-to-end, and report tests/evidence before moving to the next.');
|
|
147
152
|
return lines.join('\n');
|
|
148
153
|
}
|
|
154
|
+
/** Builds a markdown prompt for executing the next ready step (or the step matching stepRef), including its readiness, satisfied or pending dependencies, and execution requirements; returns a no-ready-step message when none applies. */
|
|
149
155
|
export function buildNextStepPrompt(plan, snapshot, stepRef) {
|
|
150
156
|
const step = stepRef ? snapshot.stepByRef[stepRef] : snapshot.nextReadyStep;
|
|
151
157
|
if (!step) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-execution.js","sourceRoot":"","sources":["plan-execution.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plan-execution.js","sourceRoot":"","sources":["plan-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,6 +18,7 @@ type PlanInput = {
|
|
|
18
18
|
status?: string;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
/** A normalized plan step carrying its status and dependency refs plus derived readiness, including the done/blocked flags and the lists of dependencies that are missing or still incomplete. */
|
|
21
22
|
export type AnalyzedPlanStep = {
|
|
22
23
|
ref: string;
|
|
23
24
|
title: string;
|
|
@@ -32,6 +33,7 @@ export type AnalyzedPlanStep = {
|
|
|
32
33
|
original: PlanStepInput;
|
|
33
34
|
};
|
|
34
35
|
|
|
36
|
+
/** Aggregated execution state for a plan: step counts, the waiting/ready/blocked/all step lists, a ref-to-step lookup map, completion percentage, and the next ready step (if any). */
|
|
35
37
|
export type PlanExecutionSnapshot = {
|
|
36
38
|
totalSteps: number;
|
|
37
39
|
completedSteps: number;
|
|
@@ -58,6 +60,7 @@ function normalizeStepRef(step: PlanStepInput, index: number): string {
|
|
|
58
60
|
return candidate || `step-${index + 1}`;
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
/** Returns the de-duplicated, trimmed dependency refs declared on a step, accepting either the camelCase or snake_case dependency field. */
|
|
61
64
|
function normalizeDependsOn(step: PlanStepInput): string[] {
|
|
62
65
|
const raw = Array.isArray(step.dependsOn)
|
|
63
66
|
? step.dependsOn
|
|
@@ -74,6 +77,7 @@ function formatStepLine(step: AnalyzedPlanStep): string {
|
|
|
74
77
|
return `- [${step.ref}] ${step.title}`;
|
|
75
78
|
}
|
|
76
79
|
|
|
80
|
+
/** Returns a human-readable reason a step is waiting — joining its incomplete dependencies and unresolved (missing) ones — or the literal "waiting" when there are none. */
|
|
77
81
|
function formatWaitReason(step: AnalyzedPlanStep): string {
|
|
78
82
|
const blockers = [
|
|
79
83
|
...step.incompleteDependencies,
|
|
@@ -83,6 +87,7 @@ function formatWaitReason(step: AnalyzedPlanStep): string {
|
|
|
83
87
|
return `waiting on ${blockers.join(', ')}`;
|
|
84
88
|
}
|
|
85
89
|
|
|
90
|
+
/** Returns the combined list of a step's incomplete dependencies and its unresolved (missing) dependencies, with each missing ref suffixed by " (missing)". */
|
|
86
91
|
function stepDependencyBlockers(step: AnalyzedPlanStep): string[] {
|
|
87
92
|
return [
|
|
88
93
|
...step.incompleteDependencies,
|
|
@@ -90,6 +95,7 @@ function stepDependencyBlockers(step: AnalyzedPlanStep): string[] {
|
|
|
90
95
|
];
|
|
91
96
|
}
|
|
92
97
|
|
|
98
|
+
/** Builds an execution snapshot from raw plan steps: normalizes each step, resolves dependencies against completed steps, and partitions the not-done steps into ready, waiting, and blocked buckets along with completion percentage and the next ready step. */
|
|
93
99
|
export function buildPlanExecutionSnapshot(steps: PlanStepInput[]): PlanExecutionSnapshot {
|
|
94
100
|
const normalized: AnalyzedPlanStep[] = steps.map((step, index) => {
|
|
95
101
|
const status = normalizeStatus(step.status);
|
|
@@ -162,6 +168,7 @@ export function buildPlanExecutionSnapshot(steps: PlanStepInput[]): PlanExecutio
|
|
|
162
168
|
};
|
|
163
169
|
}
|
|
164
170
|
|
|
171
|
+
/** Builds a markdown agent brief for a plan, summarizing plan metadata and the ready, waiting, and blocked steps from the execution snapshot, closing with a single execution instruction. */
|
|
165
172
|
export function buildPlanAgentBrief(plan: PlanInput, snapshot: PlanExecutionSnapshot): string {
|
|
166
173
|
const title = (plan.title || plan.id || '(untitled)').trim();
|
|
167
174
|
const lines: string[] = [
|
|
@@ -213,6 +220,7 @@ export function buildPlanAgentBrief(plan: PlanInput, snapshot: PlanExecutionSnap
|
|
|
213
220
|
return lines.join('\n');
|
|
214
221
|
}
|
|
215
222
|
|
|
223
|
+
/** Builds a markdown prompt for executing the next ready step (or the step matching stepRef), including its readiness, satisfied or pending dependencies, and execution requirements; returns a no-ready-step message when none applies. */
|
|
216
224
|
export function buildNextStepPrompt(
|
|
217
225
|
plan: PlanInput,
|
|
218
226
|
snapshot: PlanExecutionSnapshot,
|
package/public/src/views/plan.js
CHANGED
|
@@ -15,6 +15,11 @@ let currentExecutionSnapshot = null;
|
|
|
15
15
|
function stepRef(step) {
|
|
16
16
|
return step.ref || step.id || '';
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Returns a small colored HTML status badge for a plan step, mapping the step
|
|
20
|
+
* status (defaulting to pending) to a fixed color by lowercasing the status
|
|
21
|
+
* text.
|
|
22
|
+
*/
|
|
18
23
|
function stepStatusBadge(status) {
|
|
19
24
|
const s = (status || 'pending').toLowerCase();
|
|
20
25
|
const colors = {
|
|
@@ -28,6 +33,10 @@ function stepStatusBadge(status) {
|
|
|
28
33
|
const color = colors[s] || 'var(--text-muted)';
|
|
29
34
|
return `<span style="font-size:11px;padding:2px 7px;border-radius:4px;background:color-mix(in srgb,${color} 18%,transparent);color:${color};font-weight:600;letter-spacing:.3px">${escHtml(s)}</span>`;
|
|
30
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns an HTML metric badge card showing an uppercase label and a colored
|
|
38
|
+
* value, used for the plan execution summary counts.
|
|
39
|
+
*/
|
|
31
40
|
function metricBadge(label, value, color) {
|
|
32
41
|
return `
|
|
33
42
|
<div style="padding:8px 10px;border-radius:8px;background:color-mix(in srgb,${color} 14%, var(--bg-card));border:1px solid color-mix(in srgb,${color} 28%, var(--border));min-width:95px">
|
|
@@ -35,6 +44,12 @@ function metricBadge(label, value, color) {
|
|
|
35
44
|
<div style="font-size:14px;font-weight:600;color:${color};margin-top:2px">${escHtml(value)}</div>
|
|
36
45
|
</div>`;
|
|
37
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Returns inline HTML describing a step's dependency state: an empty string
|
|
49
|
+
* when the step has no dependencies, is done, or is blocked; a 'Dependencies
|
|
50
|
+
* complete' note when all are finished; or a 'Waiting on' note listing the
|
|
51
|
+
* incomplete and unresolved (missing) dependencies.
|
|
52
|
+
*/
|
|
38
53
|
function renderDependencyHint(analyzed) {
|
|
39
54
|
if (!analyzed || analyzed.dependsOn.length === 0 || analyzed.isDone || analyzed.isBlocked)
|
|
40
55
|
return '';
|
|
@@ -47,6 +62,12 @@ function renderDependencyHint(analyzed) {
|
|
|
47
62
|
];
|
|
48
63
|
return `<div style="font-size:12px;color:var(--warning,#f59e0b);margin-top:3px">Waiting on: ${escHtml(blockers.join(', '))}</div>`;
|
|
49
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Renders the Execution Focus card for a plan: a dependency-aware summary with
|
|
67
|
+
* copy buttons for the agent brief and next-step prompt, metric badges for the
|
|
68
|
+
* completed/ready/waiting/blocked counts, the next ready step, and previews of
|
|
69
|
+
* the waiting and blocked steps.
|
|
70
|
+
*/
|
|
50
71
|
function renderExecutionFocus(planId, snapshot) {
|
|
51
72
|
const next = snapshot.nextReadyStep;
|
|
52
73
|
const waitingPreview = snapshot.waitingSteps.slice(0, 2).map(step => {
|
|
@@ -103,6 +124,12 @@ function renderExecutionFocus(planId, snapshot) {
|
|
|
103
124
|
: ''}
|
|
104
125
|
</div>`;
|
|
105
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns the HTML for a single plan step row: the step ref, title (struck
|
|
129
|
+
* through when done), status badge, description, dependency hint, and blocked
|
|
130
|
+
* reason, plus conditional action buttons to copy the step prompt, mark
|
|
131
|
+
* complete, block, or remove the step.
|
|
132
|
+
*/
|
|
106
133
|
function renderStepRow(step, planId, analyzed) {
|
|
107
134
|
const ref = stepRef(step);
|
|
108
135
|
const isDone = ['done', 'completed'].includes((step.status || '').toLowerCase());
|
|
@@ -134,6 +161,11 @@ function renderStepRow(step, planId, analyzed) {
|
|
|
134
161
|
</div>`;
|
|
135
162
|
}
|
|
136
163
|
// ─── Render ──────────────────────────────────────────────────
|
|
164
|
+
/**
|
|
165
|
+
* Returns the top-level HTML markup for the Plans view: a page header with New
|
|
166
|
+
* Plan and Refresh buttons and a two-panel layout holding the plan list and
|
|
167
|
+
* detail panels.
|
|
168
|
+
*/
|
|
137
169
|
export function renderPlanView() {
|
|
138
170
|
return `
|
|
139
171
|
<div class="page-header">
|
|
@@ -157,6 +189,11 @@ export function renderPlanView() {
|
|
|
157
189
|
</div>
|
|
158
190
|
</div>`;
|
|
159
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Initializes the Plans view into the page and resets the currently selected
|
|
194
|
+
* plan state. Shows a no-project empty state and returns when no project is
|
|
195
|
+
* selected; otherwise renders the view and loads the plan list.
|
|
196
|
+
*/
|
|
160
197
|
export async function initPlanView() {
|
|
161
198
|
const el = document.getElementById('content-plan');
|
|
162
199
|
if (!el)
|
|
@@ -171,6 +208,12 @@ export async function initPlanView() {
|
|
|
171
208
|
el.innerHTML = renderPlanView();
|
|
172
209
|
await loadPlanList();
|
|
173
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Fetches all plans for the current project and renders them as clickable
|
|
213
|
+
* sidebar entries in the plan list panel, updating the subtitle to the project
|
|
214
|
+
* name. Clears the current plan when there are none, and shows an error state
|
|
215
|
+
* if the request fails.
|
|
216
|
+
*/
|
|
174
217
|
async function loadPlanList() {
|
|
175
218
|
const listEl = document.getElementById('plan-list-panel');
|
|
176
219
|
const subEl = document.getElementById('plan-subtitle');
|
|
@@ -206,6 +249,13 @@ async function loadPlanList() {
|
|
|
206
249
|
listEl.innerHTML = `<div class="empty-state" style="padding:16px"><div class="empty-state-text">Error: ${escHtml(err instanceof Error ? err.message : String(err))}</div></div>`;
|
|
207
250
|
}
|
|
208
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Loads a plan into the detail panel by id, highlighting it in the list and
|
|
254
|
+
* building a dependency-aware execution snapshot. Renders a card with
|
|
255
|
+
* approve/materialize/edit/delete actions, the description and scope, the
|
|
256
|
+
* execution focus summary, and the list of step rows with an add-step button.
|
|
257
|
+
* Shows an error state if the fetch fails.
|
|
258
|
+
*/
|
|
209
259
|
export async function openPlanDetail(planId) {
|
|
210
260
|
currentPlanId = planId;
|
|
211
261
|
// Highlight selected in list
|
|
@@ -345,6 +395,11 @@ export async function openPlanDetail(planId) {
|
|
|
345
395
|
}
|
|
346
396
|
}
|
|
347
397
|
// ─── Modal builders ──────────────────────────────────────────
|
|
398
|
+
/**
|
|
399
|
+
* Opens the New Plan modal with fields for title, description, scope, tags, and
|
|
400
|
+
* priority. Shows an info toast and returns early when no project is currently
|
|
401
|
+
* selected.
|
|
402
|
+
*/
|
|
348
403
|
export function openCreatePlanModal() {
|
|
349
404
|
if (!state.currentProject) {
|
|
350
405
|
toast('Select a project first', 'info');
|
|
@@ -383,6 +438,11 @@ export function openCreatePlanModal() {
|
|
|
383
438
|
<button class="btn btn-ghost" onclick="window.__app.hideModal('create-plan-modal')">Cancel</button>`);
|
|
384
439
|
showModal('create-plan-modal');
|
|
385
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Submits the New Plan form, requiring a title, and posts the plan fields to
|
|
443
|
+
* the plan endpoint. On success it closes the modal, toasts confirmation, and
|
|
444
|
+
* reloads the plan list.
|
|
445
|
+
*/
|
|
386
446
|
export async function submitCreatePlan() {
|
|
387
447
|
if (!state.currentProject)
|
|
388
448
|
return;
|
|
@@ -414,6 +474,11 @@ export async function submitCreatePlan() {
|
|
|
414
474
|
toast(err instanceof Error ? err.message : 'Failed to create plan', 'error');
|
|
415
475
|
}
|
|
416
476
|
}
|
|
477
|
+
/**
|
|
478
|
+
* Opens the Add Step modal for the given plan with title, description, and
|
|
479
|
+
* depends-on fields, wiring its submit button to submitAddStep with the plan
|
|
480
|
+
* id.
|
|
481
|
+
*/
|
|
417
482
|
export function openAddStepModal(planId) {
|
|
418
483
|
createModal('add-step-modal', 'Add Step', `
|
|
419
484
|
<div class="form-group">
|
|
@@ -431,6 +496,11 @@ export function openAddStepModal(planId) {
|
|
|
431
496
|
<button class="btn btn-ghost" onclick="window.__app.hideModal('add-step-modal')">Cancel</button>`);
|
|
432
497
|
showModal('add-step-modal');
|
|
433
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* Submits the Add Step form for a plan, requiring a title, and posts the step
|
|
501
|
+
* fields to the plan's steps endpoint. On success it closes the modal, toasts
|
|
502
|
+
* confirmation, and reopens the plan detail to show the new step.
|
|
503
|
+
*/
|
|
434
504
|
export async function submitAddStep(planId) {
|
|
435
505
|
if (!state.currentProject)
|
|
436
506
|
return;
|
|
@@ -456,6 +526,10 @@ export async function submitAddStep(planId) {
|
|
|
456
526
|
toast(err instanceof Error ? err.message : 'Failed to add step', 'error');
|
|
457
527
|
}
|
|
458
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Marks the given plan step complete by posting to the step's complete
|
|
531
|
+
* endpoint, then toasts confirmation and reopens the plan detail.
|
|
532
|
+
*/
|
|
459
533
|
export async function planCompleteStep(planId, stepRef) {
|
|
460
534
|
if (!state.currentProject)
|
|
461
535
|
return;
|
|
@@ -468,6 +542,11 @@ export async function planCompleteStep(planId, stepRef) {
|
|
|
468
542
|
toast(err instanceof Error ? err.message : 'Failed to complete step', 'error');
|
|
469
543
|
}
|
|
470
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Opens the Block Step modal for the given plan step, collecting a required
|
|
547
|
+
* reason and wiring its submit button to submitBlockStep with the plan id and
|
|
548
|
+
* step ref.
|
|
549
|
+
*/
|
|
471
550
|
export function planBlockStepPrompt(planId, stepRef) {
|
|
472
551
|
createModal('block-step-modal', 'Block Step', `
|
|
473
552
|
<div class="form-group">
|
|
@@ -477,6 +556,11 @@ export function planBlockStepPrompt(planId, stepRef) {
|
|
|
477
556
|
<button class="btn btn-ghost" onclick="window.__app.hideModal('block-step-modal')">Cancel</button>`);
|
|
478
557
|
showModal('block-step-modal');
|
|
479
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* Submits the Block Step form, requiring a reason, and posts it to the step's
|
|
561
|
+
* block endpoint. On success it closes the modal, toasts confirmation, and
|
|
562
|
+
* reopens the plan detail.
|
|
563
|
+
*/
|
|
480
564
|
export async function submitBlockStep(planId, stepRef) {
|
|
481
565
|
if (!state.currentProject)
|
|
482
566
|
return;
|
|
@@ -495,6 +579,11 @@ export async function submitBlockStep(planId, stepRef) {
|
|
|
495
579
|
toast(err instanceof Error ? err.message : 'Failed to block step', 'error');
|
|
496
580
|
}
|
|
497
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* Removes a plan step after confirming with the user, DELETEing it from the
|
|
584
|
+
* plan's steps endpoint. On success it toasts confirmation and reopens the plan
|
|
585
|
+
* detail.
|
|
586
|
+
*/
|
|
498
587
|
export function planRemoveStep(planId, stepRef) {
|
|
499
588
|
confirmDialog('Remove step', `Remove step ${stepRef} from plan?`, async () => {
|
|
500
589
|
if (!state.currentProject)
|
|
@@ -509,6 +598,10 @@ export function planRemoveStep(planId, stepRef) {
|
|
|
509
598
|
}
|
|
510
599
|
}, true);
|
|
511
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* Approves a plan after confirming with the user by posting to the plan's
|
|
603
|
+
* approve endpoint, then toasts confirmation and reopens the plan detail.
|
|
604
|
+
*/
|
|
512
605
|
export function planApprove(planId) {
|
|
513
606
|
confirmDialog('Approve plan', `Approve plan ${planId}? Once approved, it can be materialized.`, async () => {
|
|
514
607
|
if (!state.currentProject)
|
|
@@ -523,6 +616,11 @@ export function planApprove(planId) {
|
|
|
523
616
|
}
|
|
524
617
|
});
|
|
525
618
|
}
|
|
619
|
+
/**
|
|
620
|
+
* Opens the Materialize Plan modal for the given plan, offering fields for item
|
|
621
|
+
* type, a parent item id, and which steps to materialize, wiring its submit
|
|
622
|
+
* button to submitMaterializePlan with the plan id.
|
|
623
|
+
*/
|
|
526
624
|
export function planMaterializePrompt(planId) {
|
|
527
625
|
createModal('materialize-plan-modal', 'Materialize Plan', `
|
|
528
626
|
<p style="font-size:13px;color:var(--text-secondary);margin-bottom:12px">Materializing creates real project items from plan steps.</p>
|
|
@@ -547,6 +645,12 @@ export function planMaterializePrompt(planId) {
|
|
|
547
645
|
<button class="btn btn-ghost" onclick="window.__app.hideModal('materialize-plan-modal')">Cancel</button>`);
|
|
548
646
|
showModal('materialize-plan-modal');
|
|
549
647
|
}
|
|
648
|
+
/**
|
|
649
|
+
* Submits the Materialize Plan form, posting the chosen item type, parent item,
|
|
650
|
+
* and steps to the plan's materialize endpoint to create real items. On success
|
|
651
|
+
* it closes the modal, toasts confirmation, and switches to the Items view
|
|
652
|
+
* after a short delay.
|
|
653
|
+
*/
|
|
550
654
|
export async function submitMaterializePlan(planId) {
|
|
551
655
|
if (!state.currentProject)
|
|
552
656
|
return;
|
|
@@ -571,6 +675,12 @@ export async function submitMaterializePlan(planId) {
|
|
|
571
675
|
toast(err instanceof Error ? err.message : 'Failed to materialize plan', 'error');
|
|
572
676
|
}
|
|
573
677
|
}
|
|
678
|
+
/**
|
|
679
|
+
* Copies text to the clipboard and toasts the success message when the
|
|
680
|
+
* Clipboard API is available. When clipboard access is unavailable or blocked,
|
|
681
|
+
* opens a modal with a prefilled, selected textarea for manual copy and toasts
|
|
682
|
+
* an info notice instead.
|
|
683
|
+
*/
|
|
574
684
|
async function copyTextWithFallback(modalTitle, text, successMessage) {
|
|
575
685
|
if (navigator.clipboard?.writeText) {
|
|
576
686
|
try {
|
|
@@ -595,6 +705,11 @@ async function copyTextWithFallback(modalTitle, text, successMessage) {
|
|
|
595
705
|
}
|
|
596
706
|
toast('Clipboard blocked. Opened manual copy panel.', 'info');
|
|
597
707
|
}
|
|
708
|
+
/**
|
|
709
|
+
* Returns the currently open plan and its execution snapshot when the requested
|
|
710
|
+
* plan id matches the active plan; otherwise toasts an info notice and returns
|
|
711
|
+
* null so prompt generators bail out.
|
|
712
|
+
*/
|
|
598
713
|
function getCurrentPlanContext(planId) {
|
|
599
714
|
const activeId = currentPlanData?.id || currentPlanId;
|
|
600
715
|
if (!currentPlanData || !currentExecutionSnapshot || activeId !== planId) {
|
|
@@ -603,6 +718,11 @@ function getCurrentPlanContext(planId) {
|
|
|
603
718
|
}
|
|
604
719
|
return { plan: currentPlanData, snapshot: currentExecutionSnapshot };
|
|
605
720
|
}
|
|
721
|
+
/**
|
|
722
|
+
* Builds the dependency-aware agent brief for the currently open plan and
|
|
723
|
+
* copies it via copyTextWithFallback, first confirming the plan is open using
|
|
724
|
+
* its id.
|
|
725
|
+
*/
|
|
606
726
|
export async function copyPlanAgentBrief(planId) {
|
|
607
727
|
const ctx = getCurrentPlanContext(planId);
|
|
608
728
|
if (!ctx)
|
|
@@ -610,6 +730,12 @@ export async function copyPlanAgentBrief(planId) {
|
|
|
610
730
|
const brief = buildPlanAgentBrief(ctx.plan, ctx.snapshot);
|
|
611
731
|
await copyTextWithFallback('Plan Agent Brief', brief, 'Agent brief copied');
|
|
612
732
|
}
|
|
733
|
+
/**
|
|
734
|
+
* Builds and copies an execution prompt for a specific plan step, or for the
|
|
735
|
+
* next ready step when no ref is given. Validates that the requested step
|
|
736
|
+
* exists (or that a ready step exists), then copies the prompt via
|
|
737
|
+
* copyTextWithFallback.
|
|
738
|
+
*/
|
|
613
739
|
export async function copyPlanNextStepPrompt(planId, stepRef) {
|
|
614
740
|
const ctx = getCurrentPlanContext(planId);
|
|
615
741
|
if (!ctx)
|
|
@@ -625,6 +751,11 @@ export async function copyPlanNextStepPrompt(planId, stepRef) {
|
|
|
625
751
|
const prompt = buildNextStepPrompt(ctx.plan, ctx.snapshot, stepRef);
|
|
626
752
|
await copyTextWithFallback('Next Step Prompt', prompt, 'Next-step prompt copied');
|
|
627
753
|
}
|
|
754
|
+
/**
|
|
755
|
+
* Opens the Edit Plan modal with the title pre-filled, asynchronously
|
|
756
|
+
* populates the description by re-fetching the plan, and wires the submit
|
|
757
|
+
* button to submitEditPlan with the plan id.
|
|
758
|
+
*/
|
|
628
759
|
export function planEditPrompt(planId, currentTitle) {
|
|
629
760
|
createModal('edit-plan-modal', 'Edit Plan', `
|
|
630
761
|
<div class="form-group">
|
|
@@ -645,6 +776,11 @@ export function planEditPrompt(planId, currentTitle) {
|
|
|
645
776
|
el.value = desc;
|
|
646
777
|
}).catch(() => { });
|
|
647
778
|
}
|
|
779
|
+
/**
|
|
780
|
+
* Submits the Edit Plan form, requiring a title, and PATCHes the title and
|
|
781
|
+
* description to the plan endpoint. On success it closes the modal, toasts
|
|
782
|
+
* confirmation, and reloads both the plan list and the plan detail.
|
|
783
|
+
*/
|
|
648
784
|
export async function submitEditPlan(planId) {
|
|
649
785
|
if (!state.currentProject)
|
|
650
786
|
return;
|
|
@@ -665,6 +801,11 @@ export async function submitEditPlan(planId) {
|
|
|
665
801
|
toast(err instanceof Error ? err.message : 'Failed to update plan', 'error');
|
|
666
802
|
}
|
|
667
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* Deletes a plan after confirming with the user by DELETEing it from the plan
|
|
806
|
+
* endpoint. On success it toasts confirmation, clears the active plan state and
|
|
807
|
+
* detail panel, and reloads the plan list.
|
|
808
|
+
*/
|
|
668
809
|
export function planDeletePrompt(planId) {
|
|
669
810
|
confirmDialog('Delete plan', `Delete plan ${planId} and all its steps? This cannot be undone.`, async () => {
|
|
670
811
|
if (!state.currentProject)
|
|
@@ -686,5 +827,9 @@ export function planDeletePrompt(planId) {
|
|
|
686
827
|
}, true);
|
|
687
828
|
}
|
|
688
829
|
// Expose currentPlanId for potential external use
|
|
830
|
+
/**
|
|
831
|
+
* Returns the id of the currently selected plan, or null when no plan is
|
|
832
|
+
* selected.
|
|
833
|
+
*/
|
|
689
834
|
export function getCurrentPlanId() { return currentPlanId; }
|
|
690
835
|
//# sourceMappingURL=plan.js.map
|