@hienlh/ppm 0.9.63 → 0.9.65

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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.65] - 2026-04-08
4
+
5
+ ### Changed
6
+ - **Removed `ppm cloud link`/`unlink` CLI commands**: Login auto-links, logout auto-unlinks — separate commands no longer needed. API routes remain for web UI.
7
+
3
8
  ## [0.9.63] - 2026-04-08
4
9
 
5
10
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hienlh/ppm",
3
- "version": "0.9.63",
3
+ "version": "0.9.65",
4
4
  "description": "Personal Project Manager — mobile-first web IDE with AI assistance",
5
5
  "author": "hienlh",
6
6
  "license": "MIT",
@@ -19,8 +19,6 @@ import { homedir } from "node:os";
19
19
  const ROOT = resolve(import.meta.dir, "..");
20
20
  const INDEX_PATH = join(ROOT, "src", "index.ts");
21
21
  const CMD_DIR = join(ROOT, "src", "cli", "commands");
22
- const SESSION_PATH = join(ROOT, "src", "services", "ppmbot", "ppmbot-session.ts");
23
- const COORDINATOR_MD = join(homedir(), ".ppm", "bot", "coordinator.md");
24
22
 
25
23
  // ── Types ──────────────────────────────────────────────────────────────
26
24
 
@@ -297,51 +295,15 @@ function formatCommand(group: string, cmd: CliCommand): string {
297
295
  return line;
298
296
  }
299
297
 
300
- function generateCoordinatorMd(groups: CommandGroup[]): string {
298
+ /** Generate CLI-only reference (for cli-reference.md) */
299
+ function generateCliReference(groups: CommandGroup[]): string {
301
300
  const sections: string[] = [];
302
-
303
- sections.push(`# PPMBot — AI Project Coordinator
304
-
305
- You are PPMBot, a personal AI project coordinator and team leader. You communicate with users via Telegram and have full control over PPM through CLI commands.
306
-
307
- ## Role
308
- - Answer direct questions immediately (coding, general knowledge, quick advice)
309
- - Delegate project-specific tasks to subagents using \`ppm bot delegate\`
310
- - Track delegated task status and report results proactively
311
- - Manage PPM server, projects, config, git, cloud, extensions, and databases
312
- - Remember user preferences across conversations
313
-
314
- ## Decision Framework
315
- 1. Can I answer this directly without project context? → Answer now
316
- 2. Does this reference a specific project or need file access? → Delegate with \`ppm bot delegate\`
317
- 3. Is this about PPM management (server/config/projects/git/db/cloud/ext)? → Use CLI commands directly
318
- 4. Is this a destructive operation? → Confirm with user first
319
- 5. Ambiguous project? → Ask user to clarify
320
-
321
- ## Safety Rules (CRITICAL)
322
- Before executing destructive commands, ALWAYS confirm with the user:
323
- - \`ppm stop\` / \`ppm down\` / \`ppm restart\` → "Are you sure you want to stop/restart PPM?"
324
- - \`ppm db query <name> <sql>\` with writes → warn about data modification risk
325
- - \`ppm projects remove\` → confirm project name, warn it removes from registry
326
- - \`ppm config set\` → show current value with \`ppm config get\` BEFORE changing
327
- - \`ppm cloud logout\` / \`ppm cloud unlink\` → confirm, warn about losing cloud sync
328
- - \`ppm git reset\` → warn about potential data loss
329
- - \`ppm ext remove\` → confirm extension name
330
-
331
- ## Operational Patterns
332
- - Before restart: check \`ppm status\` first
333
- - Before config change: read current value with \`ppm config get <key>\`
334
- - Before git push: check \`ppm git status --project <name>\` first
335
- - For DB operations: always specify connection name
336
- - For git operations: always use \`--project <name>\` flag`);
337
-
338
- // CLI Reference
339
- sections.push(`\n## CLI Command Reference`);
301
+ sections.push(`# PPM CLI Reference`);
340
302
 
341
303
  for (const group of groups) {
342
304
  const heading = group.name === "core"
343
- ? `### Core Commands (${group.description})`
344
- : `### ppm ${group.name} — ${group.description}`;
305
+ ? `## Core Commands (${group.description})`
306
+ : `## ppm ${group.name} — ${group.description}`;
345
307
  sections.push(heading);
346
308
 
347
309
  const cmdLines = group.commands.map((c) => formatCommand(group.name, c));
@@ -350,103 +312,86 @@ Before executing destructive commands, ALWAYS confirm with the user:
350
312
  sections.push("```");
351
313
  }
352
314
 
353
- // Delegation section (always present, emphasized as primary tool)
354
315
  sections.push(`
355
- ## Task Delegation (Primary Tool)
356
-
357
- ### Delegate a task to a project
358
- \`\`\`
359
- ppm bot delegate --chat <chatId> --project <name> --prompt "<enriched task description>"
360
- \`\`\`
361
- Returns task ID in JSON. Tell user you're working on it.
362
-
363
- ### Check task status
364
- \`\`\`
365
- ppm bot task-status <task-id>
366
- \`\`\`
367
-
368
- ### Get task result
369
- \`\`\`
370
- ppm bot task-result <task-id>
371
- \`\`\`
372
-
373
- ### List recent tasks
316
+ ## Quick Reference — Task Delegation
374
317
  \`\`\`
318
+ ppm bot delegate --chat <chatId> --project <name> --prompt "<enriched task>"
319
+ ppm bot task-status <id>
320
+ ppm bot task-result <id>
375
321
  ppm bot tasks
376
322
  \`\`\`
377
323
 
378
- ## Memory Management
324
+ ## Quick Reference — Memory
379
325
  \`\`\`
380
- ppm bot memory save "<content>" -c <category> # categories: fact|preference|decision|architecture|issue
381
- ppm bot memory list # list saved memories
382
- ppm bot memory forget "<topic>" # delete matching memories
326
+ ppm bot memory save "<content>" -c <category>
327
+ ppm bot memory list
328
+ ppm bot memory forget "<topic>"
383
329
  \`\`\`
384
330
 
385
- ## Response Style
386
- - Keep responses concise (Telegram context mobile-friendly)
387
- - Use short paragraphs, no walls of text
388
- - When delegating: acknowledge immediately, notify on completion
389
- - Support Vietnamese and English naturally
390
- - When showing CLI output: format for readability
391
-
392
- ## Important
393
- - When delegating, write an enriched prompt with full context — not just the raw user message
394
- - Include relevant details: what the user wants, which files/features, acceptance criteria
395
- - Each delegation creates a fresh AI session in the target project workspace
396
- - Use \`--json\` flag when you need to parse command output programmatically`);
331
+ ## Tips
332
+ - Use \`--json\` flag when parsing command output programmatically
333
+ - For git/chat/db operations: always specify \`--project <name>\` or connection name`);
397
334
 
398
335
  return sections.join("\n");
399
336
  }
400
337
 
401
338
  // ── Source Code Update ────────────────────────────────────────────────
402
339
 
403
- function updateSourceDefault(content: string): void {
404
- const src = readFileSync(SESSION_PATH, "utf-8");
340
+ const CLI_DEFAULT_PATH = join(ROOT, "src", "services", "ppmbot", "cli-reference-default.ts");
341
+
342
+ function updateBundledDefault(cliRef: string): void {
343
+ const escaped = cliRef
344
+ .replace(/\\/g, "\\\\")
345
+ .replace(/`/g, "\\`")
346
+ .replace(/\$\{/g, "\\${");
405
347
 
406
- const startMarker = "export const DEFAULT_COORDINATOR_IDENTITY = `";
348
+ const src = readFileSync(CLI_DEFAULT_PATH, "utf-8");
349
+ const startMarker = "export const DEFAULT_CLI_REFERENCE = `";
407
350
  const startIdx = src.indexOf(startMarker);
408
351
  if (startIdx === -1) {
409
- console.error("Could not find DEFAULT_COORDINATOR_IDENTITY in source");
352
+ console.error("Could not find DEFAULT_CLI_REFERENCE in cli-reference-default.ts");
410
353
  process.exit(1);
411
354
  }
412
355
 
413
356
  const afterStart = startIdx + startMarker.length;
414
357
  const endIdx = src.indexOf("\n`;\n", afterStart);
415
358
  if (endIdx === -1) {
416
- console.error("Could not find closing backtick for DEFAULT_COORDINATOR_IDENTITY");
359
+ console.error("Could not find closing backtick for DEFAULT_CLI_REFERENCE");
417
360
  process.exit(1);
418
361
  }
419
362
 
420
- // Escape backticks and ${} for template literal safety
421
- const escaped = content
422
- .replace(/\\/g, "\\\\")
423
- .replace(/`/g, "\\`")
424
- .replace(/\$\{/g, "\\${");
425
-
426
363
  const updated = src.slice(0, afterStart) + escaped + src.slice(endIdx);
427
- writeFileSync(SESSION_PATH, updated);
428
- console.log(`Updated: ${SESSION_PATH}`);
364
+ writeFileSync(CLI_DEFAULT_PATH, updated);
365
+ console.log(`Updated: ${CLI_DEFAULT_PATH}`);
429
366
  }
430
367
 
431
- function writeCoordinatorMd(content: string): void {
368
+ function writeCliReferenceMd(cliRef: string): void {
432
369
  const dir = join(homedir(), ".ppm", "bot");
433
370
  mkdirSync(dir, { recursive: true });
434
- writeFileSync(COORDINATOR_MD, content);
435
- console.log(`Written: ${COORDINATOR_MD}`);
371
+ const cliRefPath = join(dir, "cli-reference.md");
372
+ // Read version from package.json
373
+ const pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf-8"));
374
+ writeFileSync(cliRefPath, `<!-- ppm-version: ${pkg.version} -->\n${cliRef}`);
375
+ console.log(`Written: ${cliRefPath}`);
436
376
  }
437
377
 
438
378
  // ── Main ───────────────────────────────────────────────────────────────
439
379
 
440
380
  const cliArgs = process.argv.slice(2);
441
381
  const groups = buildGroups();
442
- const output = generateCoordinatorMd(groups);
443
-
444
- if (cliArgs.includes("--update")) {
445
- writeCoordinatorMd(output);
446
- updateSourceDefault(output);
382
+ const cliRef = generateCliReference(groups);
383
+
384
+ if (cliArgs.includes("--cli-only")) {
385
+ // Runtime mode: just output CLI reference to stdout (used by ensureCliReference)
386
+ console.log(cliRef);
387
+ } else if (cliArgs.includes("--update")) {
388
+ // Dev mode: write cli-reference.md + update bundled default
389
+ writeCliReferenceMd(cliRef);
390
+ updateBundledDefault(cliRef);
447
391
  console.log("\nDone. Review the changes and test with PPMBot.");
448
392
  } else if (cliArgs.includes("--write-md")) {
449
- writeCoordinatorMd(output);
393
+ writeCliReferenceMd(cliRef);
450
394
  } else {
451
- console.log(output);
395
+ // Default: stdout
396
+ console.log(cliRef);
452
397
  }
@@ -75,7 +75,6 @@ export function registerCloudCommands(program: Command): void {
75
75
  } catch (linkErr: unknown) {
76
76
  const linkMsg = linkErr instanceof Error ? linkErr.message : String(linkErr);
77
77
  console.warn(` ⚠ Auto-link failed: ${linkMsg}`);
78
- console.log(` Run 'ppm cloud link' manually to register this machine.`);
79
78
  }
80
79
  console.log();
81
80
  } catch (err: unknown) {
@@ -113,69 +112,6 @@ export function registerCloudCommands(program: Command): void {
113
112
  console.log(` ✓ Logged out (was: ${auth.email})\n`);
114
113
  });
115
114
 
116
- cmd
117
- .command("link")
118
- .description("Register this machine with PPM Cloud")
119
- .option("-n, --name <name>", "Machine display name")
120
- .action(async (options) => {
121
- const { linkDevice } = await import("../../services/cloud.service.ts");
122
-
123
- try {
124
- const device = await linkDevice(options.name);
125
- console.log(` ✓ Machine linked`);
126
- console.log(` Name: ${device.name}`);
127
- console.log(` ID: ${device.device_id}`);
128
-
129
- // Auto-detect running tunnel and start heartbeat immediately
130
- try {
131
- const { resolve } = await import("node:path");
132
- const { homedir } = await import("node:os");
133
- const { existsSync, readFileSync } = await import("node:fs");
134
- const statusFile = resolve(homedir(), ".ppm", "status.json");
135
- if (existsSync(statusFile)) {
136
- const status = JSON.parse(readFileSync(statusFile, "utf-8"));
137
- if (status.shareUrl) {
138
- const { sendHeartbeat } = await import("../../services/cloud.service.ts");
139
- const ok = await sendHeartbeat(status.shareUrl);
140
- if (ok) {
141
- console.log(`\n ➜ Cloud: synced tunnel URL (${status.shareUrl})`);
142
- }
143
- }
144
- }
145
- } catch { /* non-blocking */ }
146
-
147
- console.log();
148
- } catch (err: unknown) {
149
- const msg = err instanceof Error ? err.message : String(err);
150
- console.error(` ✗ Link failed: ${msg}\n`);
151
- process.exit(1);
152
- }
153
- });
154
-
155
- cmd
156
- .command("unlink")
157
- .description("Remove this machine from PPM Cloud")
158
- .action(async () => {
159
- const { unlinkDevice, getCloudDevice } = await import(
160
- "../../services/cloud.service.ts"
161
- );
162
-
163
- const device = getCloudDevice();
164
- if (!device) {
165
- console.log(` Not linked to cloud.\n`);
166
- return;
167
- }
168
-
169
- try {
170
- await unlinkDevice();
171
- console.log(` ✓ Machine unlinked (was: ${device.name})\n`);
172
- } catch (err: unknown) {
173
- const msg = err instanceof Error ? err.message : String(err);
174
- console.error(` ✗ Unlink failed: ${msg}\n`);
175
- process.exit(1);
176
- }
177
- });
178
-
179
115
  cmd
180
116
  .command("status")
181
117
  .description("Show PPM Cloud connection status")
@@ -217,7 +153,7 @@ export function registerCloudCommands(program: Command): void {
217
153
  console.log(` Linked at: ${device.linked_at}`);
218
154
  } else {
219
155
  console.log(` Machine: not linked`);
220
- if (auth) console.log(` Run 'ppm cloud link' to register this machine.`);
156
+ if (auth) console.log(` Run 'ppm cloud login' to re-link this machine.`);
221
157
  }
222
158
 
223
159
  console.log();
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Bundled CLI reference fallback for compiled binary (when generator script is unavailable).
3
+ * Auto-generated by: bun scripts/generate-bot-coordinator.ts --update-default
4
+ *
5
+ * To regenerate: bun generate:bot
6
+ */
7
+
8
+ // prettier-ignore
9
+ export const DEFAULT_CLI_REFERENCE = `# PPM CLI Reference
10
+ ## Core Commands (Server & system management)
11
+ \`\`\`
12
+ ppm start
13
+ Start the PPM server (background by default)
14
+ -p, --port <port> — Port to listen on
15
+ -s, --share — (deprecated) Tunnel is now always enabled
16
+ -c, --config <path> — Path to config file (YAML import into DB)
17
+
18
+ ppm stop
19
+ Stop the PPM server (supervisor stays alive)
20
+ -a, --all — Kill all PPM and cloudflared processes (including untracked)
21
+ --kill — Full shutdown (kills supervisor too)
22
+
23
+ ppm down
24
+ Fully shut down PPM (supervisor + server + tunnel)
25
+
26
+ ppm restart
27
+ Restart the server (keeps tunnel alive)
28
+ -c, --config <path> — Path to config file
29
+ --force — Force resume from paused state
30
+
31
+ ppm status
32
+ Show PPM daemon status
33
+ -a, --all — Show all PPM and cloudflared processes (including untracked)
34
+ --json — Output as JSON
35
+
36
+ ppm open
37
+ Open PPM in browser
38
+ -c, --config <path> — Path to config file
39
+
40
+ ppm logs
41
+ View PPM daemon logs
42
+ -n, --tail <lines> — Number of lines to show [default: 50]
43
+ -f, --follow — Follow log output
44
+ --clear — Clear log file
45
+
46
+ ppm report
47
+ Report a bug on GitHub (pre-fills env info + logs)
48
+
49
+ ppm init
50
+ Initialize PPM configuration (interactive or via flags)
51
+ -p, --port <port> — Port to listen on
52
+ --scan <path> — Directory to scan for git repos
53
+ --auth — Enable authentication
54
+ --no-auth — Disable authentication
55
+ --password <pw> — Set access password
56
+ --share — Pre-install cloudflared for sharing
57
+ -y, --yes — Non-interactive mode (use defaults + flags)
58
+
59
+ ppm upgrade
60
+ Check for and install PPM updates
61
+ \`\`\`
62
+ ## ppm projects — Manage registered projects
63
+ \`\`\`
64
+ ppm projects list
65
+ List all registered projects
66
+
67
+ ppm projects add <path>
68
+ Add a project to the registry
69
+ -n, --name <name> — Project name (defaults to folder name)
70
+
71
+ ppm projects remove <name>
72
+ Remove a project from the registry
73
+ \`\`\`
74
+ ## ppm config — Configuration management
75
+ \`\`\`
76
+ ppm config get <key>
77
+ Get a config value (e.g. port, auth.enabled)
78
+
79
+ ppm config set <key> <value>
80
+ Set a config value (e.g. port 9090)
81
+ \`\`\`
82
+ ## ppm git — Git operations for a project
83
+ \`\`\`
84
+ ppm git status
85
+ Show working tree status
86
+ -p, --project <name> — Project name or path
87
+
88
+ ppm git log
89
+ Show recent commits
90
+ -p, --project <name> — Project name or path
91
+ -n, --count <n> — Number of commits to show [default: 20]
92
+
93
+ ppm git diff [ref1] [ref2]
94
+ Show diff between refs or working tree
95
+ -p, --project <name> — Project name or path
96
+
97
+ ppm git stage <files...>
98
+ Stage files (use "." to stage all)
99
+ -p, --project <name> — Project name or path
100
+
101
+ ppm git unstage <files...>
102
+ Unstage files
103
+ -p, --project <name> — Project name or path
104
+
105
+ ppm git commit
106
+ Commit staged changes
107
+ -p, --project <name> — Project name or path
108
+ -m, --message <msg> — Commit message (required)
109
+
110
+ ppm git push
111
+ Push to remote
112
+ -p, --project <name> — Project name or path
113
+ --remote <remote> — Remote name [default: origin]
114
+ --branch <branch> — Branch name
115
+
116
+ ppm git pull
117
+ Pull from remote
118
+ -p, --project <name> — Project name or path
119
+ --remote <remote> — Remote name
120
+ --branch <branch> — Branch name
121
+
122
+ ppm git branch create <name>
123
+ Create and checkout a new branch
124
+ -p, --project <name> — Project name or path
125
+ --from <ref> — Base ref (commit/branch/tag)
126
+
127
+ ppm git branch checkout <name>
128
+ Switch to a branch
129
+ -p, --project <name> — Project name or path
130
+
131
+ ppm git branch delete <name>
132
+ Delete a branch
133
+ -p, --project <name> — Project name or path
134
+ -f, --force — Force delete
135
+
136
+ ppm git branch merge <source>
137
+ Merge a branch into current branch
138
+ -p, --project <name> — Project name or path
139
+ \`\`\`
140
+ ## ppm chat — AI chat sessions
141
+ \`\`\`
142
+ ppm chat list
143
+ List all chat sessions
144
+ -p, --project <name> — Filter by project name
145
+
146
+ ppm chat create
147
+ Create a new chat session
148
+ -p, --project <name> — Project name or path
149
+ --provider <provider> — AI provider (default: claude)
150
+
151
+ ppm chat send <session-id> <message>
152
+ Send a message and stream response to stdout
153
+ -p, --project <name> — Project name or path
154
+
155
+ ppm chat resume <session-id>
156
+ Resume an interactive chat session
157
+ -p, --project <name> — Project name or path
158
+
159
+ ppm chat delete <session-id>
160
+ Delete a chat session
161
+ \`\`\`
162
+ ## ppm db — Database connections & queries
163
+ \`\`\`
164
+ ppm db list
165
+ List all saved database connections
166
+
167
+ ppm db add
168
+ Add a new database connection
169
+ -n, --name <name> — Connection name (unique) (required)
170
+ -t, --type <type> — Database type: sqlite | postgres (required)
171
+ -c, --connection-string <url> — PostgreSQL connection string
172
+ -f, --file <path> — SQLite file path (absolute)
173
+ -g, --group <group> — Group name
174
+ --color <color> — Tab color (hex, e.g. #3b82f6)
175
+
176
+ ppm db remove <name>
177
+ Remove a saved connection (by name or ID)
178
+
179
+ ppm db test <name>
180
+ Test a saved connection
181
+
182
+ ppm db tables <name>
183
+ List tables in a database connection
184
+
185
+ ppm db schema <name> <table>
186
+ Show table schema (columns, types, constraints)
187
+ -s, --schema <schema> — PostgreSQL schema name [default: public]
188
+
189
+ ppm db data <name> <table>
190
+ View table data (paginated)
191
+ -p, --page <page> — Page number [default: 1]
192
+ -l, --limit <limit> — Rows per page [default: 50]
193
+ --order <column> — Order by column
194
+ --desc — Descending order
195
+ -s, --schema <schema> — PostgreSQL schema name [default: public]
196
+
197
+ ppm db query <name> <sql>
198
+ Execute a SQL query against a saved connection
199
+ \`\`\`
200
+ ## ppm autostart — Auto-start on boot
201
+ \`\`\`
202
+ ppm autostart enable
203
+ Register PPM to start automatically on boot
204
+ -p, --port <port> — Override port
205
+ -s, --share — (deprecated) Tunnel is now always enabled
206
+ -c, --config <path> — Config file path
207
+ --profile <name> — DB profile name
208
+
209
+ ppm autostart disable
210
+ Remove PPM auto-start registration
211
+
212
+ ppm autostart status
213
+ Show auto-start status
214
+ --json — Output as JSON
215
+ \`\`\`
216
+ ## ppm cloud — PPM Cloud — device registry + tunnel
217
+ \`\`\`
218
+ ppm cloud login
219
+ Sign in with Google
220
+ --url <url> — Cloud URL override
221
+ --device-code — Force device code flow (for remote terminals)
222
+
223
+ ppm cloud logout
224
+ Sign out from PPM Cloud
225
+
226
+ ppm cloud link
227
+ Register this machine with PPM Cloud
228
+ -n, --name <name> — Machine display name
229
+
230
+ ppm cloud unlink
231
+ Remove this machine from PPM Cloud
232
+
233
+ ppm cloud status
234
+ Show PPM Cloud connection status
235
+ --json — Output as JSON
236
+
237
+ ppm cloud devices
238
+ List all registered devices from cloud
239
+ --json — Output as JSON
240
+ \`\`\`
241
+ ## ppm ext — Manage PPM extensions
242
+ \`\`\`
243
+ ppm ext install <name>
244
+ Install an extension from npm
245
+
246
+ ppm ext remove <name>
247
+ Remove an installed extension
248
+
249
+ ppm ext list
250
+ List installed extensions
251
+
252
+ ppm ext enable <name>
253
+ Enable an extension
254
+
255
+ ppm ext disable <name>
256
+ Disable an extension
257
+
258
+ ppm ext dev <path>
259
+ Symlink a local extension for development
260
+ \`\`\`
261
+ ## ppm bot — PPMBot coordinator utilities
262
+ \`\`\`
263
+ ppm bot delegate
264
+ Delegate a task to a project subagent
265
+ --chat <id> — Telegram chat ID (required)
266
+ --project <name> — Project name (required)
267
+ --prompt <text> — Enriched task prompt (required)
268
+ --timeout <ms> — Timeout in milliseconds [default: 900000]
269
+
270
+ ppm bot task-status <id>
271
+ Get status of a delegated task
272
+
273
+ ppm bot task-result <id>
274
+ Get full result of a completed task
275
+
276
+ ppm bot tasks
277
+ List recent delegated tasks
278
+ --chat <id> — Telegram chat ID (auto-detected if single)
279
+
280
+ ppm bot memory save <content>
281
+ Save a cross-project memory
282
+ -c, --category <cat> — Category: fact|preference|decision|architecture|issue [default: fact]
283
+ -s, --session <id> — Session ID (optional)
284
+
285
+ ppm bot memory list
286
+ List active cross-project memories
287
+ -l, --limit <n> — Max results [default: 30]
288
+ --json — Output as JSON
289
+
290
+ ppm bot memory forget <topic>
291
+ Delete memories matching a topic (FTS5 search)
292
+
293
+ ppm bot project list
294
+ List available projects
295
+ --json — Output as JSON
296
+
297
+ ppm bot status
298
+ Show current status and running tasks
299
+ --chat <id> — Telegram chat ID (auto-detected if single)
300
+ --json — Output as JSON
301
+
302
+ ppm bot version
303
+ Show PPM version
304
+
305
+ ppm bot restart
306
+ Restart the PPM server
307
+
308
+ ppm bot help
309
+ Show all bot CLI commands
310
+ \`\`\`
311
+
312
+ ## Quick Reference — Task Delegation
313
+ \`\`\`
314
+ ppm bot delegate --chat <chatId> --project <name> --prompt "<enriched task>"
315
+ ppm bot task-status <id>
316
+ ppm bot task-result <id>
317
+ ppm bot tasks
318
+ \`\`\`
319
+
320
+ ## Quick Reference — Memory
321
+ \`\`\`
322
+ ppm bot memory save "<content>" -c <category>
323
+ ppm bot memory list
324
+ ppm bot memory forget "<topic>"
325
+ \`\`\`
326
+
327
+ ## Tips
328
+ - Use \`--json\` flag when parsing command output programmatically
329
+ - For git/chat/db operations: always specify \`--project <name>\` or connection name
330
+ `;
@@ -14,7 +14,7 @@ import {
14
14
  markBotTaskReported,
15
15
  } from "../db.service.ts";
16
16
  import { PPMBotTelegram } from "./ppmbot-telegram.ts";
17
- import { PPMBotSessionManager, ensureCoordinatorWorkspace, DEFAULT_COORDINATOR_IDENTITY } from "./ppmbot-session.ts";
17
+ import { PPMBotSessionManager, ensureCoordinatorWorkspace, readCliReference, DEFAULT_COORDINATOR_IDENTITY } from "./ppmbot-session.ts";
18
18
  import { PPMBotMemory } from "./ppmbot-memory.ts";
19
19
  import { streamToTelegram } from "./ppmbot-streamer.ts";
20
20
  import { escapeHtml } from "./ppmbot-formatter.ts";
@@ -286,6 +286,13 @@ I'll answer directly or delegate to your project's AI.`;
286
286
  parts.push(identity);
287
287
  }
288
288
 
289
+ // CLI reference (from cli-reference.md)
290
+ const cliRef = readCliReference();
291
+ if (cliRef) {
292
+ parts.push(`\n## CLI Reference`);
293
+ parts.push(cliRef);
294
+ }
295
+
289
296
  // Session info
290
297
  parts.push(`\n## Session Info`);
291
298
  parts.push(`Chat ID: ${chatId}`);
@@ -1,8 +1,9 @@
1
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync as fsRead, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { homedir } from "node:os";
4
4
  import { chatService } from "../chat.service.ts";
5
5
  import { configService } from "../config.service.ts";
6
+ import { VERSION } from "../../version.ts";
6
7
  import {
7
8
  getActivePPMBotSession,
8
9
  createPPMBotSession,
@@ -10,6 +11,7 @@ import {
10
11
  touchPPMBotSession,
11
12
  getDistinctPPMBotProjectNames,
12
13
  } from "../db.service.ts";
14
+ import { DEFAULT_CLI_REFERENCE } from "./cli-reference-default.ts";
13
15
  import type { PPMBotActiveSession, PPMBotSessionRow } from "../../types/ppmbot.ts";
14
16
  import type { PPMBotConfig, ProjectConfig } from "../../types/config.ts";
15
17
 
@@ -34,371 +36,41 @@ You are PPMBot, a personal AI project coordinator and team leader. You communica
34
36
  ## Safety Rules (CRITICAL)
35
37
  Before executing destructive commands, ALWAYS confirm with the user:
36
38
  - \`ppm stop\` / \`ppm down\` / \`ppm restart\` → "Are you sure you want to stop/restart PPM?"
37
- - \`ppm db query <name> <sql>\` with writes → warn about data modification risk
38
- - \`ppm projects remove\` → confirm project name, warn it removes from registry
39
+ - \`ppm db query\` with writes → warn about data modification risk
40
+ - \`ppm projects remove\` → confirm project name
39
41
  - \`ppm config set\` → show current value with \`ppm config get\` BEFORE changing
40
- - \`ppm cloud logout\` / \`ppm cloud unlink\` → confirm, warn about losing cloud sync
41
- - \`ppm git reset\` → warn about potential data loss
42
+ - \`ppm cloud logout\` / \`ppm cloud unlink\` → confirm
43
+ - \`ppm git branch delete\` → warn about potential data loss
42
44
  - \`ppm ext remove\` → confirm extension name
43
45
 
44
46
  ## Operational Patterns
45
47
  - Before restart: check \`ppm status\` first
46
- - Before config change: read current value with \`ppm config get <key>\`
47
- - Before git push: check \`ppm git status --project <name>\` first
48
+ - Before config change: read current with \`ppm config get <key>\`
49
+ - Before git push: check \`ppm git status --project <name>\`
48
50
  - For DB operations: always specify connection name
49
51
  - For git operations: always use \`--project <name>\` flag
50
52
 
51
- ## CLI Command Reference
52
- ### Core Commands (Server & system management)
53
- \`\`\`
54
- ppm start
55
- Start the PPM server (background by default)
56
- -p, --port <port> — Port to listen on
57
- -s, --share — (deprecated) Tunnel is now always enabled
58
- -c, --config <path> — Path to config file (YAML import into DB)
59
-
60
- ppm stop
61
- Stop the PPM server (supervisor stays alive)
62
- -a, --all — Kill all PPM and cloudflared processes (including untracked)
63
- --kill — Full shutdown (kills supervisor too)
64
-
65
- ppm down
66
- Fully shut down PPM (supervisor + server + tunnel)
67
-
68
- ppm restart
69
- Restart the server (keeps tunnel alive)
70
- -c, --config <path> — Path to config file
71
- --force — Force resume from paused state
72
-
73
- ppm status
74
- Show PPM daemon status
75
- -a, --all — Show all PPM and cloudflared processes (including untracked)
76
- --json — Output as JSON
77
-
78
- ppm open
79
- Open PPM in browser
80
- -c, --config <path> — Path to config file
81
-
82
- ppm logs
83
- View PPM daemon logs
84
- -n, --tail <lines> — Number of lines to show [default: 50]
85
- -f, --follow — Follow log output
86
- --clear — Clear log file
87
-
88
- ppm report
89
- Report a bug on GitHub (pre-fills env info + logs)
90
-
91
- ppm init
92
- Initialize PPM configuration (interactive or via flags)
93
- -p, --port <port> — Port to listen on
94
- --scan <path> — Directory to scan for git repos
95
- --auth — Enable authentication
96
- --no-auth — Disable authentication
97
- --password <pw> — Set access password
98
- --share — Pre-install cloudflared for sharing
99
- -y, --yes — Non-interactive mode (use defaults + flags)
100
-
101
- ppm upgrade
102
- Check for and install PPM updates
103
- \`\`\`
104
- ### ppm projects — Manage registered projects
105
- \`\`\`
106
- ppm projects list
107
- List all registered projects
108
-
109
- ppm projects add <path>
110
- Add a project to the registry
111
- -n, --name <name> — Project name (defaults to folder name)
112
-
113
- ppm projects remove <name>
114
- Remove a project from the registry
115
- \`\`\`
116
- ### ppm config — Configuration management
117
- \`\`\`
118
- ppm config get <key>
119
- Get a config value (e.g. port, auth.enabled)
120
-
121
- ppm config set <key> <value>
122
- Set a config value (e.g. port 9090)
123
- \`\`\`
124
- ### ppm git — Git operations for a project
125
- \`\`\`
126
- ppm git status
127
- Show working tree status
128
- -p, --project <name> — Project name or path
129
-
130
- ppm git log
131
- Show recent commits
132
- -p, --project <name> — Project name or path
133
- -n, --count <n> — Number of commits to show [default: 20]
134
-
135
- ppm git diff [ref1] [ref2]
136
- Show diff between refs or working tree
137
- -p, --project <name> — Project name or path
138
-
139
- ppm git stage <files...>
140
- Stage files (use "." to stage all)
141
- -p, --project <name> — Project name or path
142
-
143
- ppm git unstage <files...>
144
- Unstage files
145
- -p, --project <name> — Project name or path
146
-
147
- ppm git commit
148
- Commit staged changes
149
- -p, --project <name> — Project name or path
150
- -m, --message <msg> — Commit message (required)
151
-
152
- ppm git push
153
- Push to remote
154
- -p, --project <name> — Project name or path
155
- --remote <remote> — Remote name [default: origin]
156
- --branch <branch> — Branch name
157
-
158
- ppm git pull
159
- Pull from remote
160
- -p, --project <name> — Project name or path
161
- --remote <remote> — Remote name
162
- --branch <branch> — Branch name
163
-
164
- ppm git branch create <name>
165
- Create and checkout a new branch
166
- -p, --project <name> — Project name or path
167
- --from <ref> — Base ref (commit/branch/tag)
168
-
169
- ppm git branch checkout <name>
170
- Switch to a branch
171
- -p, --project <name> — Project name or path
172
-
173
- ppm git branch delete <name>
174
- Delete a branch
175
- -p, --project <name> — Project name or path
176
- -f, --force — Force delete
177
-
178
- ppm git branch merge <source>
179
- Merge a branch into current branch
180
- -p, --project <name> — Project name or path
181
- \`\`\`
182
- ### ppm chat — AI chat sessions
183
- \`\`\`
184
- ppm chat list
185
- List all chat sessions
186
- -p, --project <name> — Filter by project name
187
-
188
- ppm chat create
189
- Create a new chat session
190
- -p, --project <name> — Project name or path
191
- --provider <provider> — AI provider (default: claude)
192
-
193
- ppm chat send <session-id> <message>
194
- Send a message and stream response to stdout
195
- -p, --project <name> — Project name or path
196
-
197
- ppm chat resume <session-id>
198
- Resume an interactive chat session
199
- -p, --project <name> — Project name or path
200
-
201
- ppm chat delete <session-id>
202
- Delete a chat session
203
- \`\`\`
204
- ### ppm db — Database connections & queries
205
- \`\`\`
206
- ppm db list
207
- List all saved database connections
208
-
209
- ppm db add
210
- Add a new database connection
211
- -n, --name <name> — Connection name (unique) (required)
212
- -t, --type <type> — Database type: sqlite | postgres (required)
213
- -c, --connection-string <url> — PostgreSQL connection string
214
- -f, --file <path> — SQLite file path (absolute)
215
- -g, --group <group> — Group name
216
- --color <color> — Tab color (hex, e.g. #3b82f6)
217
-
218
- ppm db remove <name>
219
- Remove a saved connection (by name or ID)
220
-
221
- ppm db test <name>
222
- Test a saved connection
223
-
224
- ppm db tables <name>
225
- List tables in a database connection
226
-
227
- ppm db schema <name> <table>
228
- Show table schema (columns, types, constraints)
229
- -s, --schema <schema> — PostgreSQL schema name [default: public]
230
-
231
- ppm db data <name> <table>
232
- View table data (paginated)
233
- -p, --page <page> — Page number [default: 1]
234
- -l, --limit <limit> — Rows per page [default: 50]
235
- --order <column> — Order by column
236
- --desc — Descending order
237
- -s, --schema <schema> — PostgreSQL schema name [default: public]
238
-
239
- ppm db query <name> <sql>
240
- Execute a SQL query against a saved connection
241
- \`\`\`
242
- ### ppm autostart — Auto-start on boot
243
- \`\`\`
244
- ppm autostart enable
245
- Register PPM to start automatically on boot
246
- -p, --port <port> — Override port
247
- -s, --share — (deprecated) Tunnel is now always enabled
248
- -c, --config <path> — Config file path
249
- --profile <name> — DB profile name
250
-
251
- ppm autostart disable
252
- Remove PPM auto-start registration
253
-
254
- ppm autostart status
255
- Show auto-start status
256
- --json — Output as JSON
257
- \`\`\`
258
- ### ppm cloud — PPM Cloud — device registry + tunnel
259
- \`\`\`
260
- ppm cloud login
261
- Sign in with Google
262
- --url <url> — Cloud URL override
263
- --device-code — Force device code flow (for remote terminals)
264
-
265
- ppm cloud logout
266
- Sign out from PPM Cloud
267
-
268
- ppm cloud link
269
- Register this machine with PPM Cloud
270
- -n, --name <name> — Machine display name
271
-
272
- ppm cloud unlink
273
- Remove this machine from PPM Cloud
274
-
275
- ppm cloud status
276
- Show PPM Cloud connection status
277
- --json — Output as JSON
278
-
279
- ppm cloud devices
280
- List all registered devices from cloud
281
- --json — Output as JSON
282
- \`\`\`
283
- ### ppm ext — Manage PPM extensions
284
- \`\`\`
285
- ppm ext install <name>
286
- Install an extension from npm
287
-
288
- ppm ext remove <name>
289
- Remove an installed extension
290
-
291
- ppm ext list
292
- List installed extensions
293
-
294
- ppm ext enable <name>
295
- Enable an extension
296
-
297
- ppm ext disable <name>
298
- Disable an extension
299
-
300
- ppm ext dev <path>
301
- Symlink a local extension for development
302
- \`\`\`
303
- ### ppm bot — PPMBot coordinator utilities
304
- \`\`\`
305
- ppm bot delegate
306
- Delegate a task to a project subagent
307
- --chat <id> — Telegram chat ID (required)
308
- --project <name> — Project name (required)
309
- --prompt <text> — Enriched task prompt (required)
310
- --timeout <ms> — Timeout in milliseconds [default: 900000]
311
-
312
- ppm bot task-status <id>
313
- Get status of a delegated task
314
-
315
- ppm bot task-result <id>
316
- Get full result of a completed task
317
-
318
- ppm bot tasks
319
- List recent delegated tasks
320
- --chat <id> — Telegram chat ID (auto-detected if single)
321
-
322
- ppm bot memory save <content>
323
- Save a cross-project memory
324
- -c, --category <cat> — Category: fact|preference|decision|architecture|issue [default: fact]
325
- -s, --session <id> — Session ID (optional)
326
-
327
- ppm bot memory list
328
- List active cross-project memories
329
- -l, --limit <n> — Max results [default: 30]
330
- --json — Output as JSON
331
-
332
- ppm bot memory forget <topic>
333
- Delete memories matching a topic (FTS5 search)
334
-
335
- ppm bot project list
336
- List available projects
337
- --json — Output as JSON
338
-
339
- ppm bot status
340
- Show current status and running tasks
341
- --chat <id> — Telegram chat ID (auto-detected if single)
342
- --json — Output as JSON
343
-
344
- ppm bot version
345
- Show PPM version
346
-
347
- ppm bot restart
348
- Restart the PPM server
349
-
350
- ppm bot help
351
- Show all bot CLI commands
352
- \`\`\`
353
-
354
- ## Task Delegation (Primary Tool)
355
-
356
- ### Delegate a task to a project
357
- \`\`\`
358
- ppm bot delegate --chat <chatId> --project <name> --prompt "<enriched task description>"
359
- \`\`\`
360
- Returns task ID in JSON. Tell user you're working on it.
361
-
362
- ### Check task status
363
- \`\`\`
364
- ppm bot task-status <task-id>
365
- \`\`\`
366
-
367
- ### Get task result
368
- \`\`\`
369
- ppm bot task-result <task-id>
370
- \`\`\`
371
-
372
- ### List recent tasks
373
- \`\`\`
374
- ppm bot tasks
375
- \`\`\`
376
-
377
- ## Memory Management
378
- \`\`\`
379
- ppm bot memory save "<content>" -c <category> # categories: fact|preference|decision|architecture|issue
380
- ppm bot memory list # list saved memories
381
- ppm bot memory forget "<topic>" # delete matching memories
382
- \`\`\`
53
+ ## CLI Commands
54
+ Full CLI reference is in \`cli-reference.md\` (auto-injected into context).
383
55
 
384
56
  ## Response Style
385
- - Keep responses concise (Telegram context — mobile-friendly)
386
- - Use short paragraphs, no walls of text
57
+ - Keep responses concise (Telegram — mobile-friendly)
58
+ - Short paragraphs, no walls of text
387
59
  - When delegating: acknowledge immediately, notify on completion
388
60
  - Support Vietnamese and English naturally
389
- - When showing CLI output: format for readability
390
61
 
391
62
  ## Important
392
- - When delegating, write an enriched prompt with full context — not just the raw user message
393
- - Include relevant details: what the user wants, which files/features, acceptance criteria
63
+ - When delegating, write enriched prompts with full context — not just raw user message
64
+ - Include: what user wants, which files/features, acceptance criteria
394
65
  - Each delegation creates a fresh AI session in the target project workspace
395
- - Use \`--json\` flag when you need to parse command output programmatically
66
+ - Use \`--json\` flag when parsing command output programmatically
396
67
  `;
397
68
 
398
- /** Ensure ~/.ppm/bot/ workspace exists with coordinator.md */
69
+ /** Ensure ~/.ppm/bot/ workspace exists with coordinator.md + cli-reference.md */
399
70
  export function ensureCoordinatorWorkspace(): void {
400
71
  const botDir = join(homedir(), ".ppm", "bot");
401
72
  const coordinatorMd = join(botDir, "coordinator.md");
73
+ const cliRefPath = join(botDir, "cli-reference.md");
402
74
  const settingsDir = join(botDir, ".claude");
403
75
  const settingsFile = join(settingsDir, "settings.local.json");
404
76
 
@@ -413,6 +85,63 @@ export function ensureCoordinatorWorkspace(): void {
413
85
  permissions: { allow: ["Bash", "Read", "Write", "Edit", "Glob", "Grep"] },
414
86
  }, null, 2));
415
87
  }
88
+
89
+ // Auto-generate cli-reference.md if missing or version mismatch
90
+ ensureCliReference(cliRefPath);
91
+ }
92
+
93
+ /** Read CLI reference from disk (for context injection) */
94
+ export function readCliReference(): string {
95
+ const cliRefPath = join(homedir(), ".ppm", "bot", "cli-reference.md");
96
+ try {
97
+ return fsRead(cliRefPath, "utf-8");
98
+ } catch {
99
+ return "";
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Generate cli-reference.md if missing or version differs.
105
+ * Embeds version header: `<!-- ppm-version: x.x.x -->`
106
+ */
107
+ function ensureCliReference(cliRefPath: string): void {
108
+ // Check existing version
109
+ if (existsSync(cliRefPath)) {
110
+ try {
111
+ const existing = fsRead(cliRefPath, "utf-8");
112
+ const versionMatch = existing.match(/<!-- ppm-version: (.+?) -->/);
113
+ if (versionMatch && versionMatch[1] === VERSION) return; // up to date
114
+ } catch { /* regenerate on read error */ }
115
+ }
116
+
117
+ try {
118
+ const content = generateCliReference();
119
+ writeFileSync(cliRefPath, content);
120
+ console.log(`[ppmbot] Generated cli-reference.md (v${VERSION})`);
121
+ } catch (err) {
122
+ console.warn(`[ppmbot] Failed to generate cli-reference.md:`, (err as Error).message);
123
+ }
124
+ }
125
+
126
+ /** Generate CLI reference by running the generator script */
127
+ function generateCliReference(): string {
128
+ const { spawnSync } = require("node:child_process") as typeof import("node:child_process");
129
+ const scriptPath = join(import.meta.dir, "../../../scripts/generate-bot-coordinator.ts");
130
+
131
+ // If generator script exists (dev/source install), run it
132
+ if (existsSync(scriptPath)) {
133
+ const result = spawnSync("bun", [scriptPath, "--cli-only"], {
134
+ cwd: join(import.meta.dir, "../../.."),
135
+ timeout: 10_000,
136
+ encoding: "utf-8",
137
+ });
138
+ if (result.status === 0 && result.stdout) {
139
+ return `<!-- ppm-version: ${VERSION} -->\n${result.stdout}`;
140
+ }
141
+ }
142
+
143
+ // Fallback: generate from bundled constant
144
+ return `<!-- ppm-version: ${VERSION} -->\n${DEFAULT_CLI_REFERENCE}`;
416
145
  }
417
146
 
418
147
  export class PPMBotSessionManager {