@unbrained/pm-web 2026.7.26 → 2026.7.28

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.
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The set of capabilities a pm package can declare, mirrored verbatim from
3
+ * each package's `manifest.json` `capabilities` array. The union is kept
4
+ * open-ended as a string array (not a closed enum) because the pm extension
5
+ * contract may add new capability kinds upstream; pinning a closed list here
6
+ * would reject a future package that uses a capability we have not enumerated.
7
+ */
8
+ export type PackageCapability = string;
9
+ /**
10
+ * Honest gating metadata so the UI can tell a user what they must configure
11
+ * before a package is useful. Both fields are OPTIONAL — most packages work
12
+ * with no external setup.
13
+ *
14
+ * - `requiresService`: a backing service the package talks to (e.g. Neo4j for
15
+ * pm-graph's sync). When set, the UI explains that the package's
16
+ * service-dependent features will not work until the service is reachable.
17
+ * `optional: true` means the package is still useful without the service
18
+ * (e.g. pm-graph's offline export/analyze work without Neo4j).
19
+ *
20
+ * - `requiresCredentials`: human-supplied secrets the package needs for its
21
+ * network-mutating commands (e.g. JIRA_API_TOKEN, LINEAR_API_KEY,
22
+ * PM_SLACK_WEBHOOK, GITHUB_TOKEN). Each entry names the env var(s) and a
23
+ * short human description. The UI must not pretend these are one-click; it
24
+ * surfaces the variables the user must set.
25
+ */
26
+ export interface ServiceRequirement {
27
+ /** Display name of the backing service, e.g. "Neo4j". */
28
+ name: string;
29
+ /** True when the package is useful without the service (best-effort). */
30
+ optional?: boolean;
31
+ }
32
+ export interface CredentialRequirement {
33
+ /** Display label for what the credentials unlock, e.g. "Jira sync". */
34
+ label: string;
35
+ /** Environment variable(s) the package reads for the credentials. */
36
+ envVars: string[];
37
+ /**
38
+ * True when the package is partially usable without the credentials (e.g.
39
+ * `--dry-run` paths, unauthenticated reads). When false, the package is
40
+ * inert until the credentials are configured.
41
+ */
42
+ optional?: boolean;
43
+ }
44
+ export interface PackageCatalogEntry {
45
+ /** Canonical npm package name, e.g. `pm-graph`. */
46
+ readonly name: string;
47
+ /** The install spec passed to `pm install`, always `npm:<name>`. */
48
+ readonly npmSpec: string;
49
+ /** Human-friendly title, e.g. `Graph`. */
50
+ readonly title: string;
51
+ /** One-line description, mirrored from the package's manifest/package.json. */
52
+ readonly description: string;
53
+ /** Capabilities declared in the package manifest. */
54
+ readonly capabilities: readonly PackageCapability[];
55
+ /** Backing service the package needs (optional). */
56
+ readonly requiresService?: ServiceRequirement;
57
+ /** Credentials the user must configure (optional). */
58
+ readonly requiresCredentials?: readonly CredentialRequirement[];
59
+ }
60
+ /**
61
+ * The catalog. Order is the display order in the UI. The list is exhaustive
62
+ * over user-facing pm packages: every package in the fleet that is not an
63
+ * authoring template (`pm-starter`/`pm-ts-starter`) and not pm-web itself is
64
+ * here. `pm-starter`/`pm-ts-starter` are authoring templates, not user-facing
65
+ * packages; `pm-web` is this package.
66
+ */
67
+ export declare const PACKAGE_CATALOG: readonly PackageCatalogEntry[];
68
+ /**
69
+ * Look up a catalog entry by package name. Returns the entry or `undefined`
70
+ * when the name is not in the catalog. This is the security-critical gate:
71
+ * route handlers MUST call this and reject with 400 on a miss BEFORE passing
72
+ * the name to any pm command, so a user-supplied string can never be
73
+ * interpolated into an install target.
74
+ */
75
+ export declare function findCatalogEntry(name: string): PackageCatalogEntry | undefined;
76
+ /**
77
+ * Resolve a package name to its verified npm install spec
78
+ * (`npm:<name>`), or `null` when the name is not in the catalog. Route
79
+ * handlers use this to obtain the spawn argument without ever building an
80
+ * install target from a raw user string.
81
+ */
82
+ export declare function resolveNpmSpec(name: string): string | null;
83
+ /** The immutable list of catalog package names, in display order. */
84
+ export declare function catalogNames(): readonly string[];
@@ -0,0 +1,194 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // PACKAGE CATALOG — the typed, immutable list of every user-facing pm package
3
+ // ═══════════════════════════════════════════════════════════════
4
+ //
5
+ // pm-web used to ship exactly one pm package — a vendored copy of pm-graph
6
+ // pinned to an old CLI — and offered no way to install any other. This
7
+ // catalog is the single source of truth for the per-project "Packages" view
8
+ // and the extensions routes: every package the UI can install is declared
9
+ // here, and every `:name` route parameter is validated against it BEFORE a
10
+ // pm command is ever spawned. A user-supplied name can never reach an install
11
+ // target — a catalog lookup miss must 400 before any process spawn.
12
+ //
13
+ // Truthfulness contract: the catalog mirrors each package's real
14
+ // `manifest.json` (name, capabilities) and README (gating). Do NOT invent
15
+ // capabilities or hide requirements here — the UI surfaces `requiresService`
16
+ // and `requiresCredentials` so users are not promised a one-click install for
17
+ // a package that needs a Neo4j instance or an API token. The
18
+ // `test/catalog.test.ts` suite asserts that every entry's declared capabilities
19
+ // match the on-disk `manifest.json` under fleet/<pkg>/manifest.json, so a
20
+ // drift between this catalog and the packages is a failing test, not a silent
21
+ // UI lie.
22
+ /**
23
+ * The catalog. Order is the display order in the UI. The list is exhaustive
24
+ * over user-facing pm packages: every package in the fleet that is not an
25
+ * authoring template (`pm-starter`/`pm-ts-starter`) and not pm-web itself is
26
+ * here. `pm-starter`/`pm-ts-starter` are authoring templates, not user-facing
27
+ * packages; `pm-web` is this package.
28
+ */
29
+ export const PACKAGE_CATALOG = [
30
+ {
31
+ name: "pm-graph",
32
+ npmSpec: "npm:pm-graph",
33
+ title: "Graph",
34
+ description: "Knowledge graph and dependency graph extension for pm CLI workspaces, with optional Neo4j sync.",
35
+ capabilities: ["commands", "importers", "services"],
36
+ requiresService: { name: "Neo4j", optional: true },
37
+ },
38
+ {
39
+ name: "pm-beads",
40
+ npmSpec: "npm:pm-beads",
41
+ title: "Beads",
42
+ description: "Beads JSONL importer/exporter. Import work items from the Beads JSONL format into pm and export pm items back to Beads JSONL, preserving ids and dependency edges.",
43
+ capabilities: ["commands", "schema", "importers"],
44
+ },
45
+ {
46
+ name: "pm-brief",
47
+ npmSpec: "npm:pm-brief",
48
+ title: "Brief",
49
+ description: "Token-budgeted agent briefs and next-work plans for pm workspaces",
50
+ capabilities: ["commands", "renderers", "schema"],
51
+ },
52
+ {
53
+ name: "pm-changelog",
54
+ npmSpec: "npm:pm-changelog",
55
+ title: "Changelog",
56
+ description: "Generate CHANGELOG.md release notes from pm-cli items",
57
+ capabilities: ["commands", "schema", "importers", "renderers"],
58
+ },
59
+ {
60
+ name: "pm-context",
61
+ npmSpec: "npm:pm-context",
62
+ title: "Context",
63
+ description: "Generate deterministic pm context packs for agent handoffs, reviews, and status briefs",
64
+ capabilities: ["commands", "renderers", "schema"],
65
+ },
66
+ {
67
+ name: "pm-csv",
68
+ npmSpec: "npm:pm-csv",
69
+ title: "CSV",
70
+ description: "CSV importer and exporter for pm-cli",
71
+ capabilities: ["commands", "importers", "schema"],
72
+ },
73
+ {
74
+ name: "pm-gantt-chart",
75
+ npmSpec: "npm:pm-gantt-chart",
76
+ title: "Gantt Chart",
77
+ description: "ASCII Gantt chart renderer + multi-format exporter for pm-cli",
78
+ capabilities: ["commands", "schema", "importers", "preflight"],
79
+ },
80
+ {
81
+ name: "pm-github",
82
+ npmSpec: "npm:pm-github",
83
+ title: "GitHub",
84
+ description: "GitHub Issues + Projects v2 integration. Imports issues as pm items (`pm github import`), exports pm items as GitHub issues, syncs issue state, and bidirectionally syncs pm items with a GitHub Projects v2 board (`pm github project import/sync/list/fields`) — mapping pm status to the board Status column with idempotent, no-data-loss provenance.",
85
+ capabilities: ["commands", "importers", "schema", "hooks", "preflight", "search"],
86
+ requiresCredentials: [
87
+ {
88
+ label: "GitHub token (for private repos, 5000 req/hr, and export/push)",
89
+ envVars: ["GITHUB_TOKEN", "GH_TOKEN"],
90
+ optional: true,
91
+ },
92
+ ],
93
+ },
94
+ {
95
+ name: "pm-jira",
96
+ npmSpec: "npm:pm-jira",
97
+ title: "Jira",
98
+ description: "Jira issue sync for pm-cli",
99
+ capabilities: ["commands", "schema", "importers", "hooks", "preflight"],
100
+ requiresCredentials: [
101
+ {
102
+ label: "Jira API credentials (for live sync, import, and export --push)",
103
+ envVars: ["JIRA_BASE_URL", "JIRA_EMAIL", "JIRA_API_TOKEN"],
104
+ },
105
+ ],
106
+ },
107
+ {
108
+ name: "pm-linear",
109
+ npmSpec: "npm:pm-linear",
110
+ title: "Linear",
111
+ description: "Linear.app issue sync for pm-cli",
112
+ capabilities: ["commands", "schema", "importers", "preflight"],
113
+ requiresCredentials: [
114
+ {
115
+ label: "Linear API key (for live import/export and validate --check-network)",
116
+ envVars: ["LINEAR_API_KEY"],
117
+ },
118
+ ],
119
+ },
120
+ {
121
+ name: "pm-ops",
122
+ npmSpec: "npm:pm-ops",
123
+ title: "Ops",
124
+ description: "Multi-repo fleet operations for pm-cli",
125
+ capabilities: ["commands", "renderers", "schema", "parser"],
126
+ },
127
+ {
128
+ name: "pm-presets",
129
+ npmSpec: "npm:pm-presets",
130
+ title: "Presets",
131
+ description: "All 7 official pm-cli workspace presets in one package: bug-triage, indie-dev, open-source, software-sprint, startup-roadmap, kanban, agent-workflow",
132
+ capabilities: ["commands", "schema"],
133
+ },
134
+ {
135
+ name: "pm-slack",
136
+ npmSpec: "npm:pm-slack",
137
+ title: "Slack",
138
+ description: "Slack notifications for pm item lifecycle events",
139
+ capabilities: ["commands", "hooks", "schema", "preflight"],
140
+ requiresCredentials: [
141
+ {
142
+ label: "Slack webhook (for posting notifications)",
143
+ envVars: ["PM_SLACK_WEBHOOK"],
144
+ },
145
+ ],
146
+ },
147
+ {
148
+ name: "pm-slack-standup",
149
+ npmSpec: "npm:pm-slack-standup",
150
+ title: "Slack Standup",
151
+ description: "Post pm context as a Slack standup message",
152
+ capabilities: ["commands", "schema", "importers", "preflight", "services"],
153
+ requiresCredentials: [
154
+ {
155
+ label: "Slack webhook (for posting the standup)",
156
+ envVars: ["PM_SLACK_WEBHOOK"],
157
+ },
158
+ ],
159
+ },
160
+ {
161
+ name: "pm-todos",
162
+ npmSpec: "npm:pm-todos",
163
+ title: "Todos",
164
+ description: "TODO round-trip. Import/export/sync markdown checkboxes, todo.txt, jsonl, checkbox, and pi coding-agent todo JSON as pm items.",
165
+ capabilities: ["commands", "schema", "importers", "preflight"],
166
+ },
167
+ ];
168
+ /** A frozen map keyed by package name for O(1) catalog lookup. */
169
+ const CATALOG_BY_NAME = new Map(PACKAGE_CATALOG.map((entry) => [entry.name, entry]));
170
+ /**
171
+ * Look up a catalog entry by package name. Returns the entry or `undefined`
172
+ * when the name is not in the catalog. This is the security-critical gate:
173
+ * route handlers MUST call this and reject with 400 on a miss BEFORE passing
174
+ * the name to any pm command, so a user-supplied string can never be
175
+ * interpolated into an install target.
176
+ */
177
+ export function findCatalogEntry(name) {
178
+ return CATALOG_BY_NAME.get(name);
179
+ }
180
+ /**
181
+ * Resolve a package name to its verified npm install spec
182
+ * (`npm:<name>`), or `null` when the name is not in the catalog. Route
183
+ * handlers use this to obtain the spawn argument without ever building an
184
+ * install target from a raw user string.
185
+ */
186
+ export function resolveNpmSpec(name) {
187
+ const entry = CATALOG_BY_NAME.get(name);
188
+ return entry ? entry.npmSpec : null;
189
+ }
190
+ /** The immutable list of catalog package names, in display order. */
191
+ export function catalogNames() {
192
+ return PACKAGE_CATALOG.map((entry) => entry.name);
193
+ }
194
+ //# sourceMappingURL=package-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-catalog.js","sourceRoot":"","sources":["../../src/services/package-catalog.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { PmCliError, EXIT_CODE, type GetItemAtResult } from "@unbrained/pm-cli/sdk";
2
- export { PmCliError, EXIT_CODE, type GetItemAtResult };
1
+ import { PmClient, PmCliError, isPmCliExpectedError, EXIT_CODE, type GetItemAtResult } from "@unbrained/pm-cli/sdk";
2
+ export { PmCliError, isPmCliExpectedError, EXIT_CODE, type GetItemAtResult };
3
3
  export declare class Semaphore {
4
4
  private readonly limit;
5
5
  private active;
@@ -40,6 +40,8 @@ export interface PmRunResult {
40
40
  stderr: string;
41
41
  ok: boolean;
42
42
  parsed?: unknown;
43
+ /** pm CLI exit code from either the SDK dispatcher or spawned CLI fallback. */
44
+ exitCode?: number;
43
45
  }
44
46
  export interface EnsureGraphExtensionResult {
45
47
  ok: boolean;
@@ -47,7 +49,87 @@ export interface EnsureGraphExtensionResult {
47
49
  active: boolean;
48
50
  error?: string;
49
51
  }
52
+ /**
53
+ * The per-extension state shape emitted by `pm extension --json`. Only the
54
+ * fields consumers read are typed; the command emits far more (triage, policy,
55
+ * diagnostics) which is deliberately dropped.
56
+ */
57
+ export interface ExtensionState {
58
+ name: string;
59
+ version?: string;
60
+ active?: boolean;
61
+ enabled?: boolean;
62
+ runtime_active?: boolean;
63
+ activation_status?: string;
64
+ managed?: boolean;
65
+ source?: {
66
+ kind?: string;
67
+ input?: string;
68
+ };
69
+ }
70
+ /**
71
+ * Outcome of reading per-project extension state.
72
+ *
73
+ * `ok` distinguishes "the command ran and this is the state" from "the command
74
+ * failed, so we know nothing" — a distinction both previous copies of this
75
+ * parser collapsed, reporting a failed `pm extension --json` identically to a
76
+ * project with nothing installed.
77
+ */
78
+ export interface ExtensionStatesResult {
79
+ ok: boolean;
80
+ states: Map<string, ExtensionState>;
81
+ error?: string;
82
+ }
83
+ /**
84
+ * Read the per-project extension state from `pm extension --json`, returning a
85
+ * map keyed by extension name. Used both by {@link ensureGraphExtension} and
86
+ * the extensions routes' catalog join.
87
+ */
88
+ export declare function readProjectExtensionStates(projectDir: string): Promise<ExtensionStatesResult>;
89
+ /**
90
+ * Timeout for package installs, which resolve and download from the npm
91
+ * registry rather than only touching local state.
92
+ *
93
+ * The 30s default is sized for local commands and leaves too thin a margin
94
+ * here. Measured on this host: a warm-cache install is ~2s, and a cold-cache
95
+ * install of the heaviest catalog package (pm-graph, which pulls
96
+ * `neo4j-driver`) is ~10s. That is only a 3x margin on a fast connection,
97
+ * before accounting for a container sharing bandwidth or a slow registry —
98
+ * and the failure mode is a project create or package install that dies
99
+ * mid-download. A hung install still terminates, just later.
100
+ */
101
+ export declare const INSTALL_COMMAND_TIMEOUT_MS = 180000;
102
+ /**
103
+ * Ensure the pm-graph package is installed and active for a project.
104
+ *
105
+ * This used to install a *vendored* copy of pm-graph from
106
+ * `extensions/pm-graph/` (a stale fork pinned to pm-cli `^2026.7.5`). The
107
+ * vendored fork is gone; pm-graph is now installed from npm through the same
108
+ * generic catalog path as every other pm package
109
+ * (src/services/package-catalog.ts). The npm spec is resolved from the catalog
110
+ * — never built from a user-supplied string — so the install target is always
111
+ * the verified `npm:pm-graph` constant.
112
+ *
113
+ * The graph routes in src/routes/pm.ts call this before `pm pm-graph export`,
114
+ * and {@link initProject} calls it on project creation, so the user-facing
115
+ * graph behaviour is unchanged.
116
+ */
50
117
  export declare function ensureGraphExtension(userId: string, slug: string): Promise<EnsureGraphExtensionResult>;
118
+ /**
119
+ * Return a cached {@link PmClient} for a workspace pm-root, creating one on
120
+ * first use. The SDK owns extension activation and serialization internally;
121
+ * caching avoids reconstructing the immutable workspace defaults while each
122
+ * call still receives the SDK's current extension snapshot. Author identity is
123
+ * resolved by the SDK's default detection, preserving prior CLI behaviour.
124
+ */
125
+ export declare function getPmClient(pmRoot: string): PmClient;
126
+ /** Drop a cached client when its workspace is deleted. */
127
+ export declare function evictPmClient(pmRoot: string): void;
128
+ /**
129
+ * Read a workspace's parsed `settings.json` for the search-tuning resolvers.
130
+ * Returns `{}` when absent so resolvers fall back to their built-in defaults.
131
+ */
132
+ export declare function readPmSettings(userId: string, slug: string): unknown;
51
133
  export declare function runPm(opts: PmRunOptions): Promise<PmRunResult>;
52
134
  /**
53
135
  * Reconstruct a single item at a one-based version or ISO timestamp using the