@peekdev/cli 0.1.0-alpha.1

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.
Files changed (74) hide show
  1. package/NOTICE +8 -0
  2. package/dist/commands/audit.d.ts +3 -0
  3. package/dist/commands/audit.d.ts.map +1 -0
  4. package/dist/commands/audit.js +96 -0
  5. package/dist/commands/audit.js.map +1 -0
  6. package/dist/commands/init.d.ts +3 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +180 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/sessions.d.ts +3 -0
  11. package/dist/commands/sessions.d.ts.map +1 -0
  12. package/dist/commands/sessions.js +214 -0
  13. package/dist/commands/sessions.js.map +1 -0
  14. package/dist/commands/status.d.ts +2 -0
  15. package/dist/commands/status.d.ts.map +1 -0
  16. package/dist/commands/status.js +88 -0
  17. package/dist/commands/status.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +78 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/lib/audit.d.ts +47 -0
  23. package/dist/lib/audit.d.ts.map +1 -0
  24. package/dist/lib/audit.js +68 -0
  25. package/dist/lib/audit.js.map +1 -0
  26. package/dist/lib/db.d.ts +86 -0
  27. package/dist/lib/db.d.ts.map +1 -0
  28. package/dist/lib/db.js +117 -0
  29. package/dist/lib/db.js.map +1 -0
  30. package/dist/lib/duration.d.ts +14 -0
  31. package/dist/lib/duration.d.ts.map +1 -0
  32. package/dist/lib/duration.js +41 -0
  33. package/dist/lib/duration.js.map +1 -0
  34. package/dist/lib/format/index.d.ts +16 -0
  35. package/dist/lib/format/index.d.ts.map +1 -0
  36. package/dist/lib/format/index.js +43 -0
  37. package/dist/lib/format/index.js.map +1 -0
  38. package/dist/lib/format/json.d.ts +35 -0
  39. package/dist/lib/format/json.d.ts.map +1 -0
  40. package/dist/lib/format/json.js +41 -0
  41. package/dist/lib/format/json.js.map +1 -0
  42. package/dist/lib/format/markdown.d.ts +4 -0
  43. package/dist/lib/format/markdown.d.ts.map +1 -0
  44. package/dist/lib/format/markdown.js +76 -0
  45. package/dist/lib/format/markdown.js.map +1 -0
  46. package/dist/lib/fs-atomic.d.ts +10 -0
  47. package/dist/lib/fs-atomic.d.ts.map +1 -0
  48. package/dist/lib/fs-atomic.js +32 -0
  49. package/dist/lib/fs-atomic.js.map +1 -0
  50. package/dist/lib/init-config.d.ts +81 -0
  51. package/dist/lib/init-config.d.ts.map +1 -0
  52. package/dist/lib/init-config.js +152 -0
  53. package/dist/lib/init-config.js.map +1 -0
  54. package/dist/lib/output.d.ts +5 -0
  55. package/dist/lib/output.d.ts.map +1 -0
  56. package/dist/lib/output.js +23 -0
  57. package/dist/lib/output.js.map +1 -0
  58. package/dist/lib/peek-home.d.ts +5 -0
  59. package/dist/lib/peek-home.d.ts.map +1 -0
  60. package/dist/lib/peek-home.js +11 -0
  61. package/dist/lib/peek-home.js.map +1 -0
  62. package/dist/lib/prompt.d.ts +25 -0
  63. package/dist/lib/prompt.d.ts.map +1 -0
  64. package/dist/lib/prompt.js +62 -0
  65. package/dist/lib/prompt.js.map +1 -0
  66. package/dist/lib/status.d.ts +54 -0
  67. package/dist/lib/status.d.ts.map +1 -0
  68. package/dist/lib/status.js +62 -0
  69. package/dist/lib/status.js.map +1 -0
  70. package/dist/version.d.ts +2 -0
  71. package/dist/version.d.ts.map +1 -0
  72. package/dist/version.js +6 -0
  73. package/dist/version.js.map +1 -0
  74. package/package.json +42 -0
@@ -0,0 +1,41 @@
1
+ // `--format json`: machine-readable export. Same schema the MCP tools return
2
+ // (P2 PRD §C.3 "same schema as MCP tool returns", §B3) so an AI consumer can
3
+ // treat a CLI export and an MCP `get_session_*` response interchangeably. Pure:
4
+ // SessionDetail in, JSON string out.
5
+ /** Build the JSON export object (pure; not yet stringified). */
6
+ export function toJsonExport(detail) {
7
+ const { session, counts, consoleErrors, networkErrors } = detail;
8
+ return {
9
+ id: session.id,
10
+ origin: session.origin,
11
+ url: session.url,
12
+ title: session.title,
13
+ startedAt: session.createdAt,
14
+ updatedAt: session.updatedAt,
15
+ status: session.status,
16
+ eventCount: session.eventCount,
17
+ bytes: session.bytes,
18
+ errorCount: counts.consoleErrors + counts.networkErrors,
19
+ consoleErrors: consoleErrors.map((c) => ({
20
+ ts: c.ts,
21
+ level: c.level,
22
+ message: c.message,
23
+ stack: c.stack,
24
+ })),
25
+ networkErrors: networkErrors.map((n) => ({
26
+ ts: n.ts,
27
+ method: n.method,
28
+ url: n.url,
29
+ status: n.status,
30
+ statusText: n.statusText,
31
+ resourceType: n.resourceType,
32
+ durationMs: n.durationMs,
33
+ errorText: n.errorText,
34
+ })),
35
+ };
36
+ }
37
+ /** Render a session as a pretty-printed JSON string (2-space indent). */
38
+ export function formatSessionJson(detail) {
39
+ return `${JSON.stringify(toJsonExport(detail), null, 2)}\n`;
40
+ }
41
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/lib/format/json.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,gFAAgF;AAChF,qCAAqC;AAkCrC,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAAC,MAAqB;IAChD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IACjE,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,UAAU,EAAE,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa;QACvD,aAAa,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAC,CAAC;QACH,aAAa,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAAC,MAAqB;IACrD,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { SessionDetail } from '../db.js';
2
+ /** Render a session as the §C.3 Markdown AI-paste format. */
3
+ export declare function formatSessionMarkdown(detail: SessionDetail): string;
4
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/lib/format/markdown.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAoC,aAAa,EAAE,MAAM,UAAU,CAAC;AAgChF,6DAA6D;AAC7D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CA0CnE"}
@@ -0,0 +1,76 @@
1
+ // `--format markdown`: structured for AI paste, mirroring Playwright's "Copy
2
+ // Prompt" convention (P2 PRD §C.3). Section order is fixed:
3
+ // ## Page
4
+ // ## Console errors
5
+ // ## Failed requests
6
+ // ## User actions before error
7
+ // ## Suggested reproduction
8
+ // Pure: SessionDetail in, Markdown string out.
9
+ //
10
+ // Note on the last two sections: per-event user actions live in the gzipped
11
+ // rrweb blob, surfaced by the MCP `get_user_action_before_error` /
12
+ // `generate_playwright_repro` tools (Phase 3c). The CLI markdown export reads
13
+ // only the extracted SQL rows, so it states where the richer data lives rather
14
+ // than fabricating it.
15
+ function isoFromMs(tsMs) {
16
+ return new Date(tsMs).toISOString();
17
+ }
18
+ function consoleSection(rows) {
19
+ if (rows.length === 0)
20
+ return 'No console errors recorded.';
21
+ return rows
22
+ .map((r) => {
23
+ const head = `- \`${r.level}\` ${isoFromMs(r.ts)} — ${r.message}`;
24
+ if (!r.stack)
25
+ return head;
26
+ const stack = r.stack
27
+ .split('\n')
28
+ .map((line) => ` ${line}`)
29
+ .join('\n');
30
+ return `${head}\n${stack}`;
31
+ })
32
+ .join('\n');
33
+ }
34
+ function networkSection(rows) {
35
+ if (rows.length === 0)
36
+ return 'No failed requests recorded.';
37
+ return rows
38
+ .map((r) => {
39
+ const status = r.status ?? (r.errorText ? `ERR ${r.errorText}` : 'pending');
40
+ const dur = r.durationMs != null ? ` (${r.durationMs}ms)` : '';
41
+ return `- ${r.method} ${r.url} → ${status}${dur}`;
42
+ })
43
+ .join('\n');
44
+ }
45
+ /** Render a session as the §C.3 Markdown AI-paste format. */
46
+ export function formatSessionMarkdown(detail) {
47
+ const { session, counts, consoleErrors, networkErrors } = detail;
48
+ const title = session.title ?? '(untitled session)';
49
+ const lines = [];
50
+ lines.push(`# Peek session ${session.id}`);
51
+ lines.push('');
52
+ lines.push('## Page');
53
+ lines.push(`- Title: ${title}`);
54
+ lines.push(`- URL: ${session.url ?? '(unknown)'}`);
55
+ lines.push(`- Origin: ${session.origin ?? '(unknown)'}`);
56
+ lines.push(`- Started: ${session.createdAt}`);
57
+ lines.push(`- Updated: ${session.updatedAt}`);
58
+ lines.push(`- Status: ${session.status}`);
59
+ lines.push(`- Events: ${session.eventCount} · Console errors: ${counts.consoleErrors} · Failed requests: ${counts.networkErrors}`);
60
+ lines.push('');
61
+ lines.push('## Console errors');
62
+ lines.push(consoleSection(consoleErrors));
63
+ lines.push('');
64
+ lines.push('## Failed requests');
65
+ lines.push(networkSection(networkErrors));
66
+ lines.push('');
67
+ lines.push('## User actions before error');
68
+ lines.push('User-action timeline lives in the recorded rrweb stream. Use the MCP tool ' +
69
+ '`get_user_action_before_error` (peek-mcp) for the click/type/navigation sequence.');
70
+ lines.push('');
71
+ lines.push('## Suggested reproduction');
72
+ lines.push(`Generate a Playwright repro with \`peek sessions export ${session.id} --format playwright\`, or the MCP \`generate_playwright_repro\` tool.`);
73
+ lines.push('');
74
+ return lines.join('\n');
75
+ }
76
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/lib/format/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Write `content` to `path` atomically: write a temp file in the SAME directory
3
+ * then `renameSync` over the target (rename is atomic on a single filesystem).
4
+ * This avoids the truncate-then-write window of a plain `writeFileSync` that a
5
+ * crash / full disk / OOM could leave as an empty or partial file — and
6
+ * `~/.claude.json` is read on every Claude Code startup. Parent dirs are
7
+ * created; on failure the temp file is best-effort removed.
8
+ */
9
+ export declare function atomicWriteFileSync(path: string, content: string): void;
10
+ //# sourceMappingURL=fs-atomic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-atomic.d.ts","sourceRoot":"","sources":["../../src/lib/fs-atomic.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAcvE"}
@@ -0,0 +1,32 @@
1
+ // Atomic file write used by `peek init` when rewriting a user's MCP-client
2
+ // config (~/.claude.json etc.). Factored out of the command shell so the
3
+ // crash-safety behavior is directly testable.
4
+ import { randomBytes } from 'node:crypto';
5
+ import { mkdirSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
6
+ import { dirname } from 'node:path';
7
+ /**
8
+ * Write `content` to `path` atomically: write a temp file in the SAME directory
9
+ * then `renameSync` over the target (rename is atomic on a single filesystem).
10
+ * This avoids the truncate-then-write window of a plain `writeFileSync` that a
11
+ * crash / full disk / OOM could leave as an empty or partial file — and
12
+ * `~/.claude.json` is read on every Claude Code startup. Parent dirs are
13
+ * created; on failure the temp file is best-effort removed.
14
+ */
15
+ export function atomicWriteFileSync(path, content) {
16
+ mkdirSync(dirname(path), { recursive: true });
17
+ const tmp = `${path}.peek-tmp-${randomBytes(4).toString('hex')}`;
18
+ try {
19
+ writeFileSync(tmp, content, 'utf8');
20
+ renameSync(tmp, path);
21
+ }
22
+ catch (err) {
23
+ try {
24
+ unlinkSync(tmp);
25
+ }
26
+ catch {
27
+ // temp file may not exist (writeFileSync failed before creating it).
28
+ }
29
+ throw err;
30
+ }
31
+ }
32
+ //# sourceMappingURL=fs-atomic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-atomic.js","sourceRoot":"","sources":["../../src/lib/fs-atomic.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,yEAAyE;AACzE,8CAA8C;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,OAAe;IAC/D,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,GAAG,IAAI,aAAa,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IACjE,IAAI,CAAC;QACH,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACpC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YACH,UAAU,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,81 @@
1
+ /** The MCP server key peek registers under, and the block written for it. */
2
+ export declare const PEEK_SERVER_KEY = "peek";
3
+ /** The `mcpServers.peek` block (P2 PRD §K.1-K.5): `npx -y @peekdev/mcp`. */
4
+ export interface PeekMcpServerBlock {
5
+ readonly command: 'npx';
6
+ readonly args: readonly ['-y', '@peekdev/mcp'];
7
+ }
8
+ export declare const PEEK_MCP_BLOCK: PeekMcpServerBlock;
9
+ /** Stable identifiers for the supported MCP clients. */
10
+ export type ClientId = 'claude-code' | 'cursor' | 'vscode' | 'windsurf' | 'cline';
11
+ /** Static metadata about one MCP client's config file. */
12
+ export interface ClientDescriptor {
13
+ readonly id: ClientId;
14
+ /** Human label shown in the wizard (P2 PRD §K.5). */
15
+ readonly label: string;
16
+ /**
17
+ * Where the config file is resolved. `home`-relative for the per-user
18
+ * clients; `cwd`-relative for the project-scoped ones (VS Code's
19
+ * `.vscode/mcp.json`).
20
+ */
21
+ readonly scope: 'home' | 'project';
22
+ /** Path segments under the scope root, e.g. ['.cursor', 'mcp.json']. */
23
+ readonly pathSegments: readonly string[];
24
+ /**
25
+ * Cline stores its MCP config inside the VS Code extension's globalStorage
26
+ * under an OS-specific path the CLI can't reliably resolve, so the wizard
27
+ * marks it "manual config required" rather than writing blindly (matches the
28
+ * §K.5 transcript). `true` ⇒ detection/merge are advisory only.
29
+ */
30
+ readonly manualOnly?: boolean;
31
+ }
32
+ /**
33
+ * The five MCP clients from the §K.5 wizard. Cline is `manualOnly` because its
34
+ * `cline_mcp_settings.json` lives in VS Code's per-OS globalStorage (the §K.5
35
+ * transcript shows "manual config required" for it).
36
+ */
37
+ export declare const CLIENTS: readonly ClientDescriptor[];
38
+ /** Resolve a client's absolute config path given the home dir and cwd. */
39
+ export declare function clientConfigPath(client: ClientDescriptor, homeDir: string, cwd: string): string;
40
+ /** A client paired with its resolved path and whether the file exists. */
41
+ export interface DetectedClient extends ClientDescriptor {
42
+ readonly configPath: string;
43
+ /** True if the config file already exists on disk. */
44
+ readonly exists: boolean;
45
+ }
46
+ /**
47
+ * Detect which clients have a config present. `fileExists` is injected (the
48
+ * shell passes a real `existsSync`; tests pass a fake) so detection stays pure.
49
+ * Every client is returned with its resolved path + `exists`; the wizard shows
50
+ * detected ones and lets the user pick.
51
+ */
52
+ export declare function detectClients(homeDir: string, cwd: string, fileExists: (path: string) => boolean): DetectedClient[];
53
+ /**
54
+ * Merge the peek MCP block into an existing (possibly undefined) parsed config,
55
+ * returning a NEW object (never mutating the input). Any pre-existing
56
+ * `mcpServers` entries are preserved; only the `peek` key is set/overwritten.
57
+ * Non-`mcpServers` top-level keys (e.g. a user's other Claude Code settings)
58
+ * are carried through untouched.
59
+ *
60
+ * Throws if `existing` is present but its `mcpServers` is a non-object (a
61
+ * malformed config the user must fix by hand, rather than us clobbering it).
62
+ */
63
+ export declare function mergePeekConfig(existing: unknown): Record<string, unknown>;
64
+ /** True if a parsed config already registers a `peek` MCP server. */
65
+ export declare function hasPeekServer(existing: unknown): boolean;
66
+ /**
67
+ * Detect line (`//`) or block (slash-star) comments OUTSIDE string literals —
68
+ * i.e. JSONC. VS Code's `.vscode/mcp.json` is JSONC and `JSON.parse` chokes on
69
+ * comments, so the shell uses this to emit an actionable message instead of a
70
+ * cryptic "Unexpected token /". String contents are skipped so a value like
71
+ * `"https://..."` does NOT count as a comment.
72
+ */
73
+ export declare function containsJsonComments(raw: string): boolean;
74
+ /**
75
+ * The `mcpServers.peek` block as a pretty-printed JSON snippet, for the
76
+ * "add this manually" message path (e.g. JSONC configs we won't rewrite).
77
+ */
78
+ export declare const PEEK_BLOCK_SNIPPET: string;
79
+ /** Serialize a merged config for writing (2-space indent + trailing newline). */
80
+ export declare function serializeConfig(config: Record<string, unknown>): string;
81
+ //# sourceMappingURL=init-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-config.d.ts","sourceRoot":"","sources":["../../src/lib/init-config.ts"],"names":[],"mappings":"AASA,6EAA6E;AAC7E,eAAO,MAAM,eAAe,SAAS,CAAC;AAEtC,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;CAChD;AAED,eAAO,MAAM,cAAc,EAAE,kBAG5B,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAElF,0DAA0D;AAC1D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;GAIG;AACH,eAAO,MAAM,OAAO,EAAE,SAAS,gBAAgB,EAgC9C,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/F;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACtD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GACpC,cAAc,EAAE,CAKlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2B1E;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAKxD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAmBzD;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAIhC,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEvE"}
@@ -0,0 +1,152 @@
1
+ // `peek init` pure core (P2 PRD §K.5): detect MCP-capable clients and compute
2
+ // the merged config to write. Everything here is a pure function of (home dir,
3
+ // cwd, which clients, possibly-existing config) → result. The interactive
4
+ // prompts and the real `fs` reads/writes live in the command shell
5
+ // (commands/init.ts), so this logic is exhaustively unit-testable against
6
+ // fixtures with pre-existing servers.
7
+ import { join } from 'node:path';
8
+ /** The MCP server key peek registers under, and the block written for it. */
9
+ export const PEEK_SERVER_KEY = 'peek';
10
+ export const PEEK_MCP_BLOCK = {
11
+ command: 'npx',
12
+ args: ['-y', '@peekdev/mcp'],
13
+ };
14
+ /**
15
+ * The five MCP clients from the §K.5 wizard. Cline is `manualOnly` because its
16
+ * `cline_mcp_settings.json` lives in VS Code's per-OS globalStorage (the §K.5
17
+ * transcript shows "manual config required" for it).
18
+ */
19
+ export const CLIENTS = [
20
+ {
21
+ id: 'claude-code',
22
+ label: 'Claude Code',
23
+ scope: 'home',
24
+ pathSegments: ['.claude.json'],
25
+ },
26
+ {
27
+ id: 'cursor',
28
+ label: 'Cursor',
29
+ scope: 'home',
30
+ pathSegments: ['.cursor', 'mcp.json'],
31
+ },
32
+ {
33
+ id: 'vscode',
34
+ label: 'VS Code',
35
+ scope: 'project',
36
+ pathSegments: ['.vscode', 'mcp.json'],
37
+ },
38
+ {
39
+ id: 'windsurf',
40
+ label: 'Windsurf',
41
+ scope: 'home',
42
+ pathSegments: ['.codeium', 'windsurf', 'mcp_config.json'],
43
+ },
44
+ {
45
+ id: 'cline',
46
+ label: 'Cline',
47
+ scope: 'home',
48
+ pathSegments: ['cline_mcp_settings.json'],
49
+ manualOnly: true,
50
+ },
51
+ ];
52
+ /** Resolve a client's absolute config path given the home dir and cwd. */
53
+ export function clientConfigPath(client, homeDir, cwd) {
54
+ const root = client.scope === 'home' ? homeDir : cwd;
55
+ return join(root, ...client.pathSegments);
56
+ }
57
+ /**
58
+ * Detect which clients have a config present. `fileExists` is injected (the
59
+ * shell passes a real `existsSync`; tests pass a fake) so detection stays pure.
60
+ * Every client is returned with its resolved path + `exists`; the wizard shows
61
+ * detected ones and lets the user pick.
62
+ */
63
+ export function detectClients(homeDir, cwd, fileExists) {
64
+ return CLIENTS.map((c) => {
65
+ const configPath = clientConfigPath(c, homeDir, cwd);
66
+ return { ...c, configPath, exists: fileExists(configPath) };
67
+ });
68
+ }
69
+ /**
70
+ * Merge the peek MCP block into an existing (possibly undefined) parsed config,
71
+ * returning a NEW object (never mutating the input). Any pre-existing
72
+ * `mcpServers` entries are preserved; only the `peek` key is set/overwritten.
73
+ * Non-`mcpServers` top-level keys (e.g. a user's other Claude Code settings)
74
+ * are carried through untouched.
75
+ *
76
+ * Throws if `existing` is present but its `mcpServers` is a non-object (a
77
+ * malformed config the user must fix by hand, rather than us clobbering it).
78
+ */
79
+ export function mergePeekConfig(existing) {
80
+ if (existing === undefined || existing === null) {
81
+ return {
82
+ mcpServers: { [PEEK_SERVER_KEY]: { ...PEEK_MCP_BLOCK, args: [...PEEK_MCP_BLOCK.args] } },
83
+ };
84
+ }
85
+ if (typeof existing !== 'object' || Array.isArray(existing)) {
86
+ throw new Error('existing config is not a JSON object');
87
+ }
88
+ const base = existing;
89
+ const existingServers = base.mcpServers;
90
+ if (existingServers !== undefined &&
91
+ (typeof existingServers !== 'object' ||
92
+ existingServers === null ||
93
+ Array.isArray(existingServers))) {
94
+ throw new Error('existing config has a non-object "mcpServers" — refusing to clobber it');
95
+ }
96
+ const servers = existingServers ?? {};
97
+ return {
98
+ ...base,
99
+ mcpServers: {
100
+ ...servers,
101
+ [PEEK_SERVER_KEY]: { ...PEEK_MCP_BLOCK, args: [...PEEK_MCP_BLOCK.args] },
102
+ },
103
+ };
104
+ }
105
+ /** True if a parsed config already registers a `peek` MCP server. */
106
+ export function hasPeekServer(existing) {
107
+ if (typeof existing !== 'object' || existing === null || Array.isArray(existing))
108
+ return false;
109
+ const servers = existing.mcpServers;
110
+ if (typeof servers !== 'object' || servers === null || Array.isArray(servers))
111
+ return false;
112
+ return PEEK_SERVER_KEY in servers;
113
+ }
114
+ /**
115
+ * Detect line (`//`) or block (slash-star) comments OUTSIDE string literals —
116
+ * i.e. JSONC. VS Code's `.vscode/mcp.json` is JSONC and `JSON.parse` chokes on
117
+ * comments, so the shell uses this to emit an actionable message instead of a
118
+ * cryptic "Unexpected token /". String contents are skipped so a value like
119
+ * `"https://..."` does NOT count as a comment.
120
+ */
121
+ export function containsJsonComments(raw) {
122
+ let inString = false;
123
+ for (let i = 0; i < raw.length; i++) {
124
+ const ch = raw[i];
125
+ if (inString) {
126
+ if (ch === '\\') {
127
+ i++; // skip the escaped char
128
+ continue;
129
+ }
130
+ if (ch === '"')
131
+ inString = false;
132
+ continue;
133
+ }
134
+ if (ch === '"') {
135
+ inString = true;
136
+ continue;
137
+ }
138
+ if (ch === '/' && (raw[i + 1] === '/' || raw[i + 1] === '*'))
139
+ return true;
140
+ }
141
+ return false;
142
+ }
143
+ /**
144
+ * The `mcpServers.peek` block as a pretty-printed JSON snippet, for the
145
+ * "add this manually" message path (e.g. JSONC configs we won't rewrite).
146
+ */
147
+ export const PEEK_BLOCK_SNIPPET = JSON.stringify({ mcpServers: { [PEEK_SERVER_KEY]: { ...PEEK_MCP_BLOCK, args: [...PEEK_MCP_BLOCK.args] } } }, null, 2);
148
+ /** Serialize a merged config for writing (2-space indent + trailing newline). */
149
+ export function serializeConfig(config) {
150
+ return `${JSON.stringify(config, null, 2)}\n`;
151
+ }
152
+ //# sourceMappingURL=init-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-config.js","sourceRoot":"","sources":["../../src/lib/init-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Human-readable byte size (1536 → "1.5 KB"). Binary (1024) units. */
2
+ export declare function formatBytes(bytes: number): string;
3
+ /** Right-pad a string to `width` for simple column alignment. */
4
+ export declare function pad(value: string, width: number): string;
5
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAGA,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAYjD;AAED,iEAAiE;AACjE,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAExD"}
@@ -0,0 +1,23 @@
1
+ // Small pure presentation helpers shared by the command shells. Kept here (and
2
+ // unit-tested) so the commands themselves stay a thin print layer.
3
+ /** Human-readable byte size (1536 → "1.5 KB"). Binary (1024) units. */
4
+ export function formatBytes(bytes) {
5
+ if (!Number.isFinite(bytes) || bytes < 0)
6
+ return '0 B';
7
+ if (bytes < 1024)
8
+ return `${bytes} B`;
9
+ const units = ['KB', 'MB', 'GB', 'TB'];
10
+ let value = bytes / 1024;
11
+ let unit = 0;
12
+ while (value >= 1024 && unit < units.length - 1) {
13
+ value /= 1024;
14
+ unit++;
15
+ }
16
+ const rounded = value >= 100 ? Math.round(value) : Math.round(value * 10) / 10;
17
+ return `${rounded} ${units[unit]}`;
18
+ }
19
+ /** Right-pad a string to `width` for simple column alignment. */
20
+ export function pad(value, width) {
21
+ return value.length >= width ? value : value + ' '.repeat(width - value.length);
22
+ }
23
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AAEnE,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACvD,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC;IACzB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,KAAK,IAAI,IAAI,CAAC;QACd,IAAI,EAAE,CAAC;IACT,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;IAC/E,OAAO,GAAG,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACrC,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,KAAa;IAC9C,OAAO,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;AAClF,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { defaultDbPath, peekHomeDir } from '@peekdev/mcp/db';
2
+ export { defaultDbPath, peekHomeDir };
3
+ /** Absolute path to the append-only audit log (~/.peek/audit.log, ADR-0010). */
4
+ export declare function auditLogPath(): string;
5
+ //# sourceMappingURL=peek-home.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peek-home.d.ts","sourceRoot":"","sources":["../../src/lib/peek-home.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;AAEtC,gFAAgF;AAChF,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
@@ -0,0 +1,11 @@
1
+ // Resolve the ~/.peek paths the CLI reads (ADR-0007 layout). The DB path +
2
+ // home come from @peekdev/mcp/db so the CLI and native host agree on the
3
+ // PEEK_HOME override; the audit log path is added here.
4
+ import { join } from 'node:path';
5
+ import { defaultDbPath, peekHomeDir } from '@peekdev/mcp/db';
6
+ export { defaultDbPath, peekHomeDir };
7
+ /** Absolute path to the append-only audit log (~/.peek/audit.log, ADR-0010). */
8
+ export function auditLogPath() {
9
+ return join(peekHomeDir(), 'audit.log');
10
+ }
11
+ //# sourceMappingURL=peek-home.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peek-home.js","sourceRoot":"","sources":["../../src/lib/peek-home.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,yEAAyE;AACzE,wDAAwD;AAExD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC;AAEtC,gFAAgF;AAChF,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,WAAW,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * One selectable option. The optional fields explicitly allow `undefined` so
3
+ * callers can build choices inline (e.g. `hint: maybeUndefined`) under
4
+ * `exactOptionalPropertyTypes`.
5
+ */
6
+ export interface Choice<T> {
7
+ readonly value: T;
8
+ readonly label: string;
9
+ /** Pre-checked in the multi-select default. */
10
+ readonly checked?: boolean | undefined;
11
+ /** Shown but not selectable (e.g. Cline "manual config required"). */
12
+ readonly disabled?: boolean | undefined;
13
+ /** Optional dim hint after the label. */
14
+ readonly hint?: string | undefined;
15
+ }
16
+ /**
17
+ * Numbered multi-select. Prints each choice with its current [x]/[ ] state and
18
+ * reads a comma/space-separated list of numbers to toggle the default. Empty
19
+ * input keeps the defaults. Disabled choices can't be selected. Returns the
20
+ * chosen values in declaration order.
21
+ */
22
+ export declare function multiSelect<T>(message: string, choices: Choice<T>[]): Promise<T[]>;
23
+ /** Yes/no confirm. `defaultYes` controls the [Y/n] vs [y/N] default on empty input. */
24
+ export declare function confirm(message: string, defaultYes?: boolean): Promise<boolean>;
25
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/lib/prompt.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,yCAAyC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAMD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAkCxF;AAED,uFAAuF;AACvF,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAUlF"}
@@ -0,0 +1,62 @@
1
+ // Thin interactive-prompt shell for `peek init`. Deliberately tiny + dependency
2
+ // free (a numbered multi-select over node:readline) so the wizard's PURE logic
3
+ // (detection + config merge in init-config.ts) carries the testable weight and
4
+ // this file stays an I/O edge that's exercised manually. Not unit-tested.
5
+ import { createInterface } from 'node:readline';
6
+ function ask(rl, question) {
7
+ return new Promise((resolve) => rl.question(question, resolve));
8
+ }
9
+ /**
10
+ * Numbered multi-select. Prints each choice with its current [x]/[ ] state and
11
+ * reads a comma/space-separated list of numbers to toggle the default. Empty
12
+ * input keeps the defaults. Disabled choices can't be selected. Returns the
13
+ * chosen values in declaration order.
14
+ */
15
+ export async function multiSelect(message, choices) {
16
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
17
+ try {
18
+ const selectable = choices.filter((c) => !c.disabled);
19
+ const checked = new Set(selectable.filter((c) => c.checked).map((c) => c.value));
20
+ process.stdout.write(`${message}\n`);
21
+ choices.forEach((c, i) => {
22
+ const num = c.disabled ? ' ' : String(i + 1).padStart(2, ' ');
23
+ const box = c.disabled ? ' ' : checked.has(c.value) ? '[x]' : '[ ]';
24
+ const hint = c.hint ? ` (${c.hint})` : '';
25
+ const dim = c.disabled ? ' — manual config required' : '';
26
+ process.stdout.write(` ${num} ${box} ${c.label}${hint}${dim}\n`);
27
+ });
28
+ const answer = (await ask(rl, 'Toggle by number (comma/space separated), Enter to accept defaults: ')).trim();
29
+ if (answer.length > 0) {
30
+ const tokens = answer.split(/[\s,]+/).filter(Boolean);
31
+ for (const tok of tokens) {
32
+ const idx = Number(tok) - 1;
33
+ const choice = choices[idx];
34
+ if (!choice || choice.disabled)
35
+ continue;
36
+ if (checked.has(choice.value))
37
+ checked.delete(choice.value);
38
+ else
39
+ checked.add(choice.value);
40
+ }
41
+ }
42
+ return choices.filter((c) => !c.disabled && checked.has(c.value)).map((c) => c.value);
43
+ }
44
+ finally {
45
+ rl.close();
46
+ }
47
+ }
48
+ /** Yes/no confirm. `defaultYes` controls the [Y/n] vs [y/N] default on empty input. */
49
+ export async function confirm(message, defaultYes = true) {
50
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
51
+ try {
52
+ const suffix = defaultYes ? '[Y/n]' : '[y/N]';
53
+ const answer = (await ask(rl, `${message} ${suffix} `)).trim().toLowerCase();
54
+ if (answer.length === 0)
55
+ return defaultYes;
56
+ return answer === 'y' || answer === 'yes';
57
+ }
58
+ finally {
59
+ rl.close();
60
+ }
61
+ }
62
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/lib/prompt.ts"],"names":[],"mappings":"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"}