@unbrained/pm-web 2026.9.13 → 2026.9.23
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 +18 -1
- package/README.md +6 -4
- package/dist/app.d.ts +10 -0
- package/dist/app.js +19 -9
- package/dist/app.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/routes/admin.js +6 -6
- package/dist/routes/admin.js.map +1 -1
- package/dist/routes/auth.js +2 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/extensions.js +24 -37
- package/dist/routes/extensions.js.map +1 -1
- package/dist/routes/github.js +169 -107
- package/dist/routes/github.js.map +1 -1
- package/dist/routes/groups.js +9 -14
- package/dist/routes/groups.js.map +1 -1
- package/dist/routes/pm.js +532 -1015
- package/dist/routes/pm.js.map +1 -1
- package/dist/routes/projects.js +10 -6
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/route-helpers.d.ts +74 -0
- package/dist/routes/route-helpers.js +85 -0
- package/dist/routes/route-helpers.js.map +1 -0
- package/dist/routes/sharing.js +30 -18
- package/dist/routes/sharing.js.map +1 -1
- package/dist/server.js +18 -23
- package/dist/server.js.map +1 -1
- package/dist/services/mutation-event-watcher.js +3 -28
- package/dist/services/mutation-event-watcher.js.map +1 -1
- package/dist/services/pm-runner.js +3 -1
- package/dist/services/pm-runner.js.map +1 -1
- package/dist/services/project-watcher.js +14 -38
- package/dist/services/project-watcher.js.map +1 -1
- package/dist/services/sse.d.ts +7 -0
- package/dist/services/sse.js +22 -0
- package/dist/services/sse.js.map +1 -1
- package/dist/services/watcher-utils.d.ts +42 -0
- package/dist/services/watcher-utils.js +60 -0
- package/dist/services/watcher-utils.js.map +1 -0
- package/manifest.json +2 -2
- package/package.json +20 -9
- package/public/src/app.js +22 -52
- package/public/src/app.js.map +1 -1
- package/public/src/app.ts +18 -75
- package/public/src/browser-window.js +29 -0
- package/public/src/browser-window.js.map +1 -0
- package/public/src/browser-window.ts +56 -0
- package/public/src/components/modals.js +1 -1
- package/public/src/components/modals.js.map +1 -1
- package/public/src/components/modals.ts +1 -1
- package/public/src/i18n.js +14 -6
- package/public/src/i18n.js.map +1 -1
- package/public/src/i18n.ts +16 -6
- package/public/src/sw.ts +1 -0
- package/public/src/utils.js +58 -0
- package/public/src/utils.js.map +1 -1
- package/public/src/utils.ts +53 -0
- package/public/src/views/admin.js +2 -5
- package/public/src/views/admin.js.map +1 -1
- package/public/src/views/admin.ts +2 -2
- package/public/src/views/auth.js +5 -1
- package/public/src/views/auth.js.map +1 -1
- package/public/src/views/auth.ts +6 -1
- package/public/src/views/calendar.js +1 -2
- package/public/src/views/calendar.js.map +1 -1
- package/public/src/views/calendar.ts +1 -2
- package/public/src/views/config.js +14 -21
- package/public/src/views/config.js.map +1 -1
- package/public/src/views/config.ts +14 -19
- package/public/src/views/context.js +11 -12
- package/public/src/views/context.js.map +1 -1
- package/public/src/views/context.ts +13 -12
- package/public/src/views/create.js +3 -11
- package/public/src/views/create.js.map +1 -1
- package/public/src/views/create.ts +3 -3
- package/public/src/views/export.js +2 -3
- package/public/src/views/export.js.map +1 -1
- package/public/src/views/export.ts +2 -3
- package/public/src/views/github.js +33 -47
- package/public/src/views/github.js.map +1 -1
- package/public/src/views/github.ts +35 -28
- package/public/src/views/graph-canvas.js +92 -99
- package/public/src/views/graph-canvas.js.map +1 -1
- package/public/src/views/graph-canvas.ts +94 -93
- package/public/src/views/graph.js +88 -73
- package/public/src/views/graph.js.map +1 -1
- package/public/src/views/graph.ts +97 -63
- package/public/src/views/groups.js +2 -5
- package/public/src/views/groups.js.map +1 -1
- package/public/src/views/groups.ts +2 -2
- package/public/src/views/guide.js +11 -10
- package/public/src/views/guide.js.map +1 -1
- package/public/src/views/guide.ts +12 -10
- package/public/src/views/items.js +100 -130
- package/public/src/views/items.js.map +1 -1
- package/public/src/views/items.ts +99 -117
- package/public/src/views/normalize.js +2 -9
- package/public/src/views/normalize.js.map +1 -1
- package/public/src/views/normalize.ts +2 -9
- package/public/src/views/packages.js +7 -4
- package/public/src/views/packages.js.map +1 -1
- package/public/src/views/packages.ts +8 -4
- package/public/src/views/plan-execution.js.map +1 -1
- package/public/src/views/plan-execution.ts +5 -15
- package/public/src/views/plan.js +2 -1
- package/public/src/views/plan.js.map +1 -1
- package/public/src/views/plan.ts +6 -17
- package/public/src/views/projects.js +5 -6
- package/public/src/views/projects.js.map +1 -1
- package/public/src/views/projects.ts +5 -6
- package/public/src/views/search.js +5 -1
- package/public/src/views/search.js.map +1 -1
- package/public/src/views/search.ts +7 -1
- package/public/src/views/settings.js +30 -55
- package/public/src/views/settings.js.map +1 -1
- package/public/src/views/settings.ts +23 -17
- package/public/src/views/shared.js +2 -5
- package/public/src/views/shared.js.map +1 -1
- package/public/src/views/shared.ts +2 -5
- package/public/src/views/sharing.js +2 -5
- package/public/src/views/sharing.js.map +1 -1
- package/public/src/views/sharing.ts +2 -2
- package/public/src/views/templates.js +9 -16
- package/public/src/views/templates.js.map +1 -1
- package/public/src/views/templates.ts +9 -14
- package/public/src/views/validate.js +2 -9
- package/public/src/views/validate.js.map +1 -1
- package/public/src/views/validate.ts +2 -9
- package/public/sw.js +1 -0
|
@@ -2,6 +2,7 @@ import { readdir, stat } from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { resolveProjectDir } from "./pm-runner.js";
|
|
4
4
|
import { consumeSignaledMutation, deliverProjectEvent, getActiveProjectIds, wasSignaledWithin, } from "./sse.js";
|
|
5
|
+
import { cachedProjectDir, dropInactive, positiveIntEnv } from "./watcher-utils.js";
|
|
5
6
|
// Safety-net filesystem sweep. The mutation-event stream
|
|
6
7
|
// (src/services/mutation-event-watcher.ts) is now the PRIMARY out-of-band change
|
|
7
8
|
// detector; this poll only catches raw non-pm writes that bypass the committed
|
|
@@ -19,26 +20,6 @@ const ITEM_DIRS = [
|
|
|
19
20
|
// files are swept round-robin across ticks so I/O stays bounded (see
|
|
20
21
|
// stepWorkspaceSweep); overridable via PM_WATCH_MAX_FILES_PER_TICK.
|
|
21
22
|
const DEFAULT_MAX_FILES_PER_TICK = 8_000;
|
|
22
|
-
/**
|
|
23
|
-
* Read a positive-integer environment variable, with a fallback.
|
|
24
|
-
*
|
|
25
|
-
* Returns the parsed integer when the variable is set and the raw value parses
|
|
26
|
-
* as a positive integer via `Number.parseInt`; otherwise returns `fallback`.
|
|
27
|
-
* Because `parseInt` parses a leading integer prefix, values like `"500ms"`
|
|
28
|
-
* parse as `500` and `"1.5"` truncates to `1`. Non-numeric, zero, or negative
|
|
29
|
-
* values fall back rather than throwing.
|
|
30
|
-
*
|
|
31
|
-
* @param name - The environment variable name.
|
|
32
|
-
* @param fallback - Value used when unset or invalid.
|
|
33
|
-
* @returns The parsed positive integer, or the fallback.
|
|
34
|
-
*/
|
|
35
|
-
function positiveIntEnv(name, fallback) {
|
|
36
|
-
const raw = process.env[name];
|
|
37
|
-
if (!raw)
|
|
38
|
-
return fallback;
|
|
39
|
-
const n = Number.parseInt(raw, 10);
|
|
40
|
-
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
41
|
-
}
|
|
42
23
|
// FNV-1a (32-bit), computed over UTF-8 bytes via `Math.imul` — fast, no BigInt
|
|
43
24
|
// per byte and no allocation. Used to bind each file's path to its mtime so the
|
|
44
25
|
// aggregate fingerprint below can't be aliased by rearranging raw mtimes.
|
|
@@ -180,6 +161,12 @@ export async function stepWorkspaceSweep(dir, state, maxFilesPerTick) {
|
|
|
180
161
|
}
|
|
181
162
|
return { completed: false };
|
|
182
163
|
}
|
|
164
|
+
/** Adapt a one-shot signature reader into a sweep step that always completes. */
|
|
165
|
+
function bindLegacySignature(readSignature) {
|
|
166
|
+
return async function readLegacySignature(dir) {
|
|
167
|
+
return { completed: true, signature: await readSignature(dir) };
|
|
168
|
+
};
|
|
169
|
+
}
|
|
183
170
|
// Pure, testable cycle. Holds per-project baseline state across ticks.
|
|
184
171
|
export function createProjectWatchCycle(deps = {}) {
|
|
185
172
|
const intervalMs = Math.max(MIN_INTERVAL_MS, deps.intervalMs ?? positiveIntEnv("PM_WATCH_INTERVAL_MS", DEFAULT_INTERVAL_MS));
|
|
@@ -193,12 +180,11 @@ export function createProjectWatchCycle(deps = {}) {
|
|
|
193
180
|
const onError = deps.onError ?? (() => undefined);
|
|
194
181
|
// A caller-supplied one-shot `readSignature` is adapted into a sweep that
|
|
195
182
|
// completes on the first tick, so legacy callers/tests keep exact semantics.
|
|
183
|
+
// A named function keeps the return type off an arrow, which the lint parser
|
|
184
|
+
// rejects when a generic annotation follows `=>` in this ternary.
|
|
196
185
|
const legacyReadSig = deps.readSignature;
|
|
197
186
|
const stepSig = legacyReadSig
|
|
198
|
-
?
|
|
199
|
-
completed: true,
|
|
200
|
-
signature: await legacyReadSig(dir),
|
|
201
|
-
})
|
|
187
|
+
? bindLegacySignature(legacyReadSig)
|
|
202
188
|
: deps.stepSignature ?? stepWorkspaceSweep;
|
|
203
189
|
const lastSeen = new Map();
|
|
204
190
|
const dirCache = new Map();
|
|
@@ -211,22 +197,12 @@ export function createProjectWatchCycle(deps = {}) {
|
|
|
211
197
|
try {
|
|
212
198
|
const ids = getIds();
|
|
213
199
|
const active = new Set(ids);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
for (const id of [...dirCache.keys()])
|
|
218
|
-
if (!active.has(id))
|
|
219
|
-
dirCache.delete(id);
|
|
220
|
-
for (const id of [...sweeps.keys()])
|
|
221
|
-
if (!active.has(id))
|
|
222
|
-
sweeps.delete(id);
|
|
200
|
+
dropInactive(lastSeen, active);
|
|
201
|
+
dropInactive(dirCache, active);
|
|
202
|
+
dropInactive(sweeps, active);
|
|
223
203
|
for (const projectId of ids) {
|
|
224
204
|
try {
|
|
225
|
-
|
|
226
|
-
if (dir === undefined) {
|
|
227
|
-
dir = await resolveDir(projectId);
|
|
228
|
-
dirCache.set(projectId, dir);
|
|
229
|
-
}
|
|
205
|
+
const dir = await cachedProjectDir(projectId, dirCache, resolveDir);
|
|
230
206
|
if (!dir)
|
|
231
207
|
continue;
|
|
232
208
|
let state = sweeps.get(projectId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-watcher.js","sourceRoot":"","sources":["../../src/services/project-watcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAElB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"project-watcher.js","sourceRoot":"","sources":["../../src/services/project-watcher.ts"],"names":[],"mappings":"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"}
|
package/dist/services/sse.d.ts
CHANGED
|
@@ -152,6 +152,13 @@ export declare function getProjectPresence(projectId: string): PresenceUser[];
|
|
|
152
152
|
export declare function setupSSEHeaders(res: Response): void;
|
|
153
153
|
/** Return the total number of currently connected SSE clients. */
|
|
154
154
|
export declare function getSSEClientCount(): number;
|
|
155
|
+
/**
|
|
156
|
+
* End every active SSE response and remove it from the connection indexes.
|
|
157
|
+
*
|
|
158
|
+
* Server shutdown calls this before `server.close()` because open streaming
|
|
159
|
+
* responses otherwise keep the HTTP server's close event pending indefinitely.
|
|
160
|
+
*/
|
|
161
|
+
export declare function closeAllSSEClients(): void;
|
|
155
162
|
/**
|
|
156
163
|
* Close long-lived clients and prune stale signal entries.
|
|
157
164
|
*
|
package/dist/services/sse.js
CHANGED
|
@@ -352,6 +352,28 @@ export function setupSSEHeaders(res) {
|
|
|
352
352
|
export function getSSEClientCount() {
|
|
353
353
|
return byId.size;
|
|
354
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* End every active SSE response and remove it from the connection indexes.
|
|
357
|
+
*
|
|
358
|
+
* Server shutdown calls this before `server.close()` because open streaming
|
|
359
|
+
* responses otherwise keep the HTTP server's close event pending indefinitely.
|
|
360
|
+
*/
|
|
361
|
+
export function closeAllSSEClients() {
|
|
362
|
+
for (const client of [...byId.values()]) {
|
|
363
|
+
try {
|
|
364
|
+
client.res.end();
|
|
365
|
+
}
|
|
366
|
+
catch (error) {
|
|
367
|
+
// One response that cannot end (e.g. its socket already failed) must not
|
|
368
|
+
// abort shutdown: the remaining streams still have to close, and the
|
|
369
|
+
// caller still has to reach server.close().
|
|
370
|
+
console.error(`SSE client ${client.id} failed to end during shutdown:`, error instanceof Error ? error.message : error);
|
|
371
|
+
}
|
|
372
|
+
finally {
|
|
373
|
+
removeClient(client);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
355
377
|
/**
|
|
356
378
|
* Close long-lived clients and prune stale signal entries.
|
|
357
379
|
*
|
package/dist/services/sse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/services/sse.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/services/sse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared primitives for the workspace watcher services.
|
|
3
|
+
*
|
|
4
|
+
* The mutation-event watcher and the filesystem sweep watcher iterate the same
|
|
5
|
+
* active-project list and resolve the same per-project workspace directories.
|
|
6
|
+
* Both loops previously carried byte-identical helpers, which the duplication
|
|
7
|
+
* gate flags; this module is the single copy.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Read a positive-integer environment variable, with a fallback.
|
|
11
|
+
*
|
|
12
|
+
* Returns the parsed integer when the variable is set and the raw value parses
|
|
13
|
+
* as a positive integer via `Number.parseInt`; otherwise returns `fallback`.
|
|
14
|
+
* Because `parseInt` parses a leading integer prefix, values like `"500ms"`
|
|
15
|
+
* parse as `500` and `"1.5"` truncates to `1`. Non-numeric, zero, or negative
|
|
16
|
+
* values fall back rather than throwing.
|
|
17
|
+
*
|
|
18
|
+
* @param name - The environment variable name.
|
|
19
|
+
* @param fallback - Value used when unset or invalid.
|
|
20
|
+
* @returns The parsed positive integer, or the fallback.
|
|
21
|
+
*/
|
|
22
|
+
export declare function positiveIntEnv(name: string, fallback: number): number;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a project's workspace directory through a shared cache.
|
|
25
|
+
*
|
|
26
|
+
* A cache miss resolves once and stores the result (including a stored `null`
|
|
27
|
+
* for an unresolvable project, which is distinct from the `undefined` of a
|
|
28
|
+
* project never looked up); a hit returns the cached value untouched.
|
|
29
|
+
*
|
|
30
|
+
* @param projectId - The project to resolve.
|
|
31
|
+
* @param cache - Cache shared across ticks, keyed by project id.
|
|
32
|
+
* @param resolveDir - Resolver returning the directory or `null`.
|
|
33
|
+
* @returns The directory, or `null` when the project has no workspace.
|
|
34
|
+
*/
|
|
35
|
+
export declare function cachedProjectDir(projectId: string, cache: Map<string, string | null>, resolveDir: (projectId: string) => Promise<string | null>): Promise<string | null>;
|
|
36
|
+
/**
|
|
37
|
+
* Delete entries whose key is no longer an active project id.
|
|
38
|
+
*
|
|
39
|
+
* @param cache - Cache to prune in place.
|
|
40
|
+
* @param active - The ids returned by this tick's active-project query.
|
|
41
|
+
*/
|
|
42
|
+
export declare function dropInactive<T>(cache: Map<string, T>, active: ReadonlySet<string>): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared primitives for the workspace watcher services.
|
|
3
|
+
*
|
|
4
|
+
* The mutation-event watcher and the filesystem sweep watcher iterate the same
|
|
5
|
+
* active-project list and resolve the same per-project workspace directories.
|
|
6
|
+
* Both loops previously carried byte-identical helpers, which the duplication
|
|
7
|
+
* gate flags; this module is the single copy.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Read a positive-integer environment variable, with a fallback.
|
|
11
|
+
*
|
|
12
|
+
* Returns the parsed integer when the variable is set and the raw value parses
|
|
13
|
+
* as a positive integer via `Number.parseInt`; otherwise returns `fallback`.
|
|
14
|
+
* Because `parseInt` parses a leading integer prefix, values like `"500ms"`
|
|
15
|
+
* parse as `500` and `"1.5"` truncates to `1`. Non-numeric, zero, or negative
|
|
16
|
+
* values fall back rather than throwing.
|
|
17
|
+
*
|
|
18
|
+
* @param name - The environment variable name.
|
|
19
|
+
* @param fallback - Value used when unset or invalid.
|
|
20
|
+
* @returns The parsed positive integer, or the fallback.
|
|
21
|
+
*/
|
|
22
|
+
export function positiveIntEnv(name, fallback) {
|
|
23
|
+
const raw = process.env[name];
|
|
24
|
+
if (!raw)
|
|
25
|
+
return fallback;
|
|
26
|
+
const n = Number.parseInt(raw, 10);
|
|
27
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a project's workspace directory through a shared cache.
|
|
31
|
+
*
|
|
32
|
+
* A cache miss resolves once and stores the result (including a stored `null`
|
|
33
|
+
* for an unresolvable project, which is distinct from the `undefined` of a
|
|
34
|
+
* project never looked up); a hit returns the cached value untouched.
|
|
35
|
+
*
|
|
36
|
+
* @param projectId - The project to resolve.
|
|
37
|
+
* @param cache - Cache shared across ticks, keyed by project id.
|
|
38
|
+
* @param resolveDir - Resolver returning the directory or `null`.
|
|
39
|
+
* @returns The directory, or `null` when the project has no workspace.
|
|
40
|
+
*/
|
|
41
|
+
export async function cachedProjectDir(projectId, cache, resolveDir) {
|
|
42
|
+
const cached = cache.get(projectId);
|
|
43
|
+
if (cached !== undefined)
|
|
44
|
+
return cached;
|
|
45
|
+
const dir = await resolveDir(projectId);
|
|
46
|
+
cache.set(projectId, dir);
|
|
47
|
+
return dir;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Delete entries whose key is no longer an active project id.
|
|
51
|
+
*
|
|
52
|
+
* @param cache - Cache to prune in place.
|
|
53
|
+
* @param active - The ids returned by this tick's active-project query.
|
|
54
|
+
*/
|
|
55
|
+
export function dropInactive(cache, active) {
|
|
56
|
+
for (const id of [...cache.keys()])
|
|
57
|
+
if (!active.has(id))
|
|
58
|
+
cache.delete(id);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=watcher-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher-utils.js","sourceRoot":"","sources":["../../src/services/watcher-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,QAAgB;IAC3D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,KAAiC,EACjC,UAAyD;IAEzD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;IACxC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAqB,EACrB,MAA2B;IAE3B,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAC5E,CAAC"}
|
package/manifest.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-web",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.23",
|
|
4
4
|
"description": "Full web UI for pm-cli — browse, create, update, search and manage pm projects in the browser. Self-hosted via Docker or Node.js.",
|
|
5
5
|
"author": "@unbraind",
|
|
6
6
|
"entry": "./dist/index.js",
|
|
7
7
|
"priority": 50,
|
|
8
|
-
"pm_min_version": "2026.9.
|
|
8
|
+
"pm_min_version": "2026.9.21",
|
|
9
9
|
"capabilities": [
|
|
10
10
|
"commands",
|
|
11
11
|
"schema"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unbrained/pm-web",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.23",
|
|
4
4
|
"description": "Full web UI for pm-cli — browse, create, update, search and manage pm projects in the browser. Self-hosted via Docker or Node.js.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -31,12 +31,14 @@
|
|
|
31
31
|
"changelog:full": "pm-changelog --pm-root .agents/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-web/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm",
|
|
32
32
|
"changelog:check": "pm-changelog --pm-root .agents/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-web/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --check",
|
|
33
33
|
"release:notes": "pm-changelog --pm-root .agents/pm --pm-arg=--output-budget --pm-arg=unbounded --pm-arg=--output-limit --pm-arg=unbounded --stdout --since-previous-tag --until-release-tag --release-version-from-package --date-from-version --item-url-base https://github.com/unbraind/pm-web/blob/main/.agents/pm --respect-item-release --pm-bin ./node_modules/.bin/pm --github-step-summary",
|
|
34
|
-
"release:check": "npm run check && npm run docstring && npm run coverage && npm run audit:prod && npm run pack:dry-run && npm run accept:packed && npm run changelog:check && npm run verify:release-changelog-date && npm run verify:release-publish-attestation",
|
|
34
|
+
"release:check": "npm run check && npm run lint && npm run duplication && npm run docstring && npm run coverage && npm run audit:prod && npm run pack:dry-run && npm run accept:packed && npm run changelog:check && npm run verify:release-changelog-date && npm run verify:release-publish-attestation",
|
|
35
35
|
"prepack": "npm run build",
|
|
36
36
|
"build:test": "tsc -p tsconfig.test.json",
|
|
37
37
|
"test": "npm run build && npm run build:test && node scripts/with-test-db.ts node --test test/*.test.ts",
|
|
38
38
|
"prepublishOnly": "npm run release:check",
|
|
39
|
-
"
|
|
39
|
+
"lint": "node scripts/lint.ts",
|
|
40
|
+
"duplication": "node scripts/duplication-gate.ts",
|
|
41
|
+
"prepare": "node scripts/prepare-merge-driver.ts",
|
|
40
42
|
"merge:install": "pm merge install",
|
|
41
43
|
"coverage": "npm run build && npm run build:test && node scripts/with-test-db.ts node scripts/coverage-gate.ts",
|
|
42
44
|
"db:up": "node scripts/db-up.ts",
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
"verify:release-publish-attestation": "node scripts/verify-release-publish-attestation.ts"
|
|
47
49
|
},
|
|
48
50
|
"dependencies": {
|
|
49
|
-
"@unbrained/pm-cli": "2026.9.
|
|
51
|
+
"@unbrained/pm-cli": "2026.9.21",
|
|
50
52
|
"bcryptjs": "^3.0.3",
|
|
51
53
|
"cookie-parser": "^1.4.7",
|
|
52
54
|
"express": "^5.2.1",
|
|
@@ -58,14 +60,19 @@
|
|
|
58
60
|
"uuid": "^14.0.2"
|
|
59
61
|
},
|
|
60
62
|
"devDependencies": {
|
|
63
|
+
"@babel/eslint-parser": "^8.0.5",
|
|
64
|
+
"@babel/plugin-syntax-typescript": "^8.0.3",
|
|
61
65
|
"@types/cookie-parser": "^1.4.8",
|
|
62
66
|
"@types/express": "^5.0.6",
|
|
63
67
|
"@types/jsonwebtoken": "^9.0.9",
|
|
64
68
|
"@types/node": "^26.2.0",
|
|
65
69
|
"@types/pg": "^8.23.1",
|
|
66
70
|
"@types/uuid": "^11.0.0",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
71
|
+
"eslint": "^10.10.0",
|
|
72
|
+
"fast-glob": "^3.3.3",
|
|
73
|
+
"jscpd": "^4.3.0",
|
|
74
|
+
"pm-changelog": "2026.9.18",
|
|
75
|
+
"pm-ops": "2026.9.18",
|
|
69
76
|
"tsx": "^4.23.12",
|
|
70
77
|
"typescript": "^7.0.2",
|
|
71
78
|
"yaml": "^2.9.0"
|
|
@@ -124,6 +131,10 @@
|
|
|
124
131
|
]
|
|
125
132
|
},
|
|
126
133
|
"private": false,
|
|
134
|
+
"duplicationGate": {
|
|
135
|
+
"threshold": 0,
|
|
136
|
+
"minTokens": 50
|
|
137
|
+
},
|
|
127
138
|
"coverageGate": {
|
|
128
139
|
"sources": [
|
|
129
140
|
"src"
|
|
@@ -132,9 +143,9 @@
|
|
|
132
143
|
"test/*.test.ts"
|
|
133
144
|
],
|
|
134
145
|
"thresholds": {
|
|
135
|
-
"lines":
|
|
136
|
-
"branches":
|
|
137
|
-
"functions":
|
|
146
|
+
"lines": 79,
|
|
147
|
+
"branches": 79,
|
|
148
|
+
"functions": 75
|
|
138
149
|
},
|
|
139
150
|
"ignore": []
|
|
140
151
|
}
|
package/public/src/app.js
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
// ═══════════════════════════════════════════════════════════════
|
|
4
4
|
import { state } from './state.js';
|
|
5
5
|
import { api, csrfTokenFromCookie } from './api.js';
|
|
6
|
-
import { showView, setOnViewChange } from './views/router.js';
|
|
6
|
+
import { showView, setOnViewChange, getViewForPath } from './views/router.js';
|
|
7
7
|
import { loadProjects, onProjectSelect, loadItemsBadge, renderProjectsView, selectProject, deleteProject, buildCreateProjectModal, submitCreateProject, submitCreateProject2 } from './views/projects.js';
|
|
8
|
-
import
|
|
8
|
+
import * as itemsView from './views/items.js';
|
|
9
9
|
import { submitCreateItem, submitCreateItemAndOpen } from './views/create.js';
|
|
10
10
|
import { renderActivityView } from './views/activity.js';
|
|
11
11
|
import { renderSearchView, setSearchMode, reindexProject, debouncedSearch, doSearch } from './views/search.js';
|
|
12
12
|
import { renderStatsView } from './views/stats.js';
|
|
13
13
|
import { renderCalendarView, calNav, showDayItems } from './views/calendar.js';
|
|
14
14
|
import { renderContextView } from './views/context.js';
|
|
15
|
-
import { renderGraphView } from './views/graph.js';
|
|
15
|
+
import { renderGraphView, refreshGraphData as refreshGraphViewData } from './views/graph.js';
|
|
16
16
|
/** Switch to the graph view, wait for it to mount, render it, then focus the
|
|
17
17
|
* node with the given id by invoking the graph view's select-node hook. */
|
|
18
18
|
async function openGraphAt(nodeId) {
|
|
@@ -21,7 +21,7 @@ async function openGraphAt(nodeId) {
|
|
|
21
21
|
setTimeout(async () => {
|
|
22
22
|
await renderGraphView();
|
|
23
23
|
// Select the node via the graph canvas
|
|
24
|
-
|
|
24
|
+
browserWindow().__graphSelectNode?.(nodeId);
|
|
25
25
|
}, 50);
|
|
26
26
|
}
|
|
27
27
|
import { renderSharingView, openShareModal, submitShare, removeShare } from './views/sharing.js';
|
|
@@ -45,7 +45,8 @@ import { initI18n, setLocale as i18nSetLocale, applyTranslations } from './i18n.
|
|
|
45
45
|
import { initPlanView, openPlanDetail, openCreatePlanModal, submitCreatePlan, openAddStepModal, submitAddStep, planCompleteStep, planBlockStepPrompt, submitBlockStep, planRemoveStep, planApprove, planMaterializePrompt, submitMaterializePlan, copyPlanAgentBrief, copyPlanNextStepPrompt, planEditPrompt, submitEditPlan, planDeletePrompt } from './views/plan.js';
|
|
46
46
|
import { showModal, hideModal, createModal } from './components/modals.js';
|
|
47
47
|
import { toast } from './components/toast.js';
|
|
48
|
-
import { escHtml } from './utils.js';
|
|
48
|
+
import { escHtml, typeIcon, priorityDot, statusBadge, updateHeaderUser } from './utils.js';
|
|
49
|
+
import { browserWindow, isBeforeInstallPromptEvent } from './browser-window.js';
|
|
49
50
|
import { initTheme, cycleTheme } from './theme.js';
|
|
50
51
|
// Apply the persisted theme immediately on script load (before boot) so the UI
|
|
51
52
|
// renders in the right palette without a flash.
|
|
@@ -179,7 +180,6 @@ async function doGlobalSearch() {
|
|
|
179
180
|
try {
|
|
180
181
|
const data = await api('POST', `/projects/${state.currentProject.id}/pm/search`, { query });
|
|
181
182
|
const results = data.results || data.items || [];
|
|
182
|
-
const { escHtml, typeIcon, priorityDot, statusBadge } = await import('./utils.js');
|
|
183
183
|
if (resultsEl)
|
|
184
184
|
resultsEl.innerHTML = results.length === 0
|
|
185
185
|
? `<div class="empty-state" style="padding:24px"><div class="empty-state-text">No results for "${escHtml(query)}"</div></div>`
|
|
@@ -196,6 +196,9 @@ async function doGlobalSearch() {
|
|
|
196
196
|
resultsEl.innerHTML = `<div class="empty-state" style="padding:24px"><div class="empty-state-text">Error: ${err instanceof Error ? err.message : String(err)}</div></div>`;
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
|
+
// PWA install
|
|
200
|
+
// The DOM lib has no `BeforeInstallPromptEvent` type, so model the two members
|
|
201
|
+
// the install flow actually uses (`prompt()` and `userChoice`).
|
|
199
202
|
let deferredPrompt = null;
|
|
200
203
|
// Expose everything needed by inline onclick handlers via window.__app
|
|
201
204
|
const __app = {
|
|
@@ -203,7 +206,6 @@ const __app = {
|
|
|
203
206
|
// Views
|
|
204
207
|
showView,
|
|
205
208
|
renderProjectsView,
|
|
206
|
-
renderItemsView,
|
|
207
209
|
renderActivityView,
|
|
208
210
|
renderSearchView,
|
|
209
211
|
renderStatsView,
|
|
@@ -247,34 +249,7 @@ const __app = {
|
|
|
247
249
|
submitCreateProject,
|
|
248
250
|
submitCreateProject2,
|
|
249
251
|
// Items
|
|
250
|
-
|
|
251
|
-
switchDetailTab,
|
|
252
|
-
addComment,
|
|
253
|
-
addNote,
|
|
254
|
-
appendItem,
|
|
255
|
-
updateItem,
|
|
256
|
-
closeItem,
|
|
257
|
-
confirmDeleteItem,
|
|
258
|
-
claimItem,
|
|
259
|
-
releaseItem,
|
|
260
|
-
startItem,
|
|
261
|
-
pauseItem,
|
|
262
|
-
addDep,
|
|
263
|
-
removeDep,
|
|
264
|
-
addLearning,
|
|
265
|
-
addTest,
|
|
266
|
-
addFileLink,
|
|
267
|
-
setStatusFilter,
|
|
268
|
-
applyItemFilters,
|
|
269
|
-
clearFilters,
|
|
270
|
-
copyFilterLink,
|
|
271
|
-
showBulkUpdateModal,
|
|
272
|
-
previewBulkUpdate,
|
|
273
|
-
applyBulkUpdate,
|
|
274
|
-
showBulkCloseModal,
|
|
275
|
-
previewBulkClose,
|
|
276
|
-
applyBulkClose,
|
|
277
|
-
useItemAsTemplate,
|
|
252
|
+
...itemsView,
|
|
278
253
|
// Create
|
|
279
254
|
submitCreateItem,
|
|
280
255
|
submitCreateItemAndOpen,
|
|
@@ -370,7 +345,7 @@ const __app = {
|
|
|
370
345
|
submitEditPlan,
|
|
371
346
|
planDeletePrompt,
|
|
372
347
|
};
|
|
373
|
-
|
|
348
|
+
browserWindow().__app = __app;
|
|
374
349
|
// ═══════════════════════════════════════════════════════════════
|
|
375
350
|
// SSE REAL-TIME SYNC
|
|
376
351
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -521,7 +496,7 @@ function connectSSE(projectId, attempt = 0) {
|
|
|
521
496
|
const doRefreshView = () => {
|
|
522
497
|
const view = state.currentView;
|
|
523
498
|
if (view === 'items') {
|
|
524
|
-
fetchAndRenderItems();
|
|
499
|
+
itemsView.fetchAndRenderItems();
|
|
525
500
|
}
|
|
526
501
|
else if (view === 'activity') {
|
|
527
502
|
renderActivityView();
|
|
@@ -542,7 +517,7 @@ function connectSSE(projectId, attempt = 0) {
|
|
|
542
517
|
// Graph-synced events (Neo4j sync complete) do a full graph reload
|
|
543
518
|
const refreshGraph = () => {
|
|
544
519
|
if (state.currentView === 'graph') {
|
|
545
|
-
|
|
520
|
+
void renderGraphView();
|
|
546
521
|
}
|
|
547
522
|
};
|
|
548
523
|
// Item events on graph view use lightweight data-only refresh
|
|
@@ -573,7 +548,7 @@ function connectSSE(projectId, attempt = 0) {
|
|
|
573
548
|
catch { /* ignore parse errors */ }
|
|
574
549
|
}
|
|
575
550
|
if (state.currentView === 'graph') {
|
|
576
|
-
|
|
551
|
+
void refreshGraphViewData();
|
|
577
552
|
}
|
|
578
553
|
else {
|
|
579
554
|
refreshView();
|
|
@@ -648,13 +623,7 @@ export async function bootApp() {
|
|
|
648
623
|
if (mainApp)
|
|
649
624
|
mainApp.style.display = 'flex';
|
|
650
625
|
const u = state.user;
|
|
651
|
-
|
|
652
|
-
const avatarEl = document.getElementById('user-avatar');
|
|
653
|
-
if (avatarEl)
|
|
654
|
-
avatarEl.textContent = initials;
|
|
655
|
-
const nameEl = document.getElementById('user-name-display');
|
|
656
|
-
if (nameEl)
|
|
657
|
-
nameEl.textContent = u.display_name || u.email;
|
|
626
|
+
updateHeaderUser(u);
|
|
658
627
|
document.querySelectorAll('.admin-only').forEach((el) => {
|
|
659
628
|
el.style.display = u.is_admin ? '' : 'none';
|
|
660
629
|
});
|
|
@@ -693,7 +662,6 @@ async function handleLaunchAction() {
|
|
|
693
662
|
return;
|
|
694
663
|
}
|
|
695
664
|
// Restore view from URL path (supports refresh/bookmark)
|
|
696
|
-
const { getViewForPath } = await import('./views/router.js');
|
|
697
665
|
const view = getViewForPath(window.location.pathname);
|
|
698
666
|
// If view requires a project and none is selected, try to select first one
|
|
699
667
|
const projectRequired = view !== 'projects' && view !== 'settings' && view !== 'admin' && view !== 'shared' && view !== 'groups' && view !== 'guide';
|
|
@@ -906,9 +874,11 @@ document.addEventListener('keydown', e => {
|
|
|
906
874
|
// ═══════════════════════════════════════════════════════════════
|
|
907
875
|
// PWA INSTALL PROMPT
|
|
908
876
|
// ═══════════════════════════════════════════════════════════════
|
|
909
|
-
window.addEventListener('beforeinstallprompt', (
|
|
910
|
-
|
|
911
|
-
|
|
877
|
+
window.addEventListener('beforeinstallprompt', (event) => {
|
|
878
|
+
if (!isBeforeInstallPromptEvent(event))
|
|
879
|
+
return;
|
|
880
|
+
event.preventDefault();
|
|
881
|
+
deferredPrompt = event;
|
|
912
882
|
const banner = document.getElementById('install-banner');
|
|
913
883
|
if (banner && !localStorage.getItem('pm-web-install-dismissed')) {
|
|
914
884
|
banner.classList.add('visible');
|
|
@@ -921,7 +891,7 @@ window.addEventListener('appinstalled', () => {
|
|
|
921
891
|
banner.classList.remove('visible');
|
|
922
892
|
toast('pm-web installed!', 'success');
|
|
923
893
|
});
|
|
924
|
-
|
|
894
|
+
browserWindow().installPwa = function () {
|
|
925
895
|
if (!deferredPrompt)
|
|
926
896
|
return;
|
|
927
897
|
deferredPrompt.prompt();
|
|
@@ -935,7 +905,7 @@ window.installPwa = function () {
|
|
|
935
905
|
banner.classList.remove('visible');
|
|
936
906
|
});
|
|
937
907
|
};
|
|
938
|
-
|
|
908
|
+
browserWindow().dismissInstallBanner = function () {
|
|
939
909
|
localStorage.setItem('pm-web-install-dismissed', '1');
|
|
940
910
|
const banner = document.getElementById('install-banner');
|
|
941
911
|
if (banner)
|