@peekdev/cli 0.1.0-alpha.2 → 0.1.0-alpha.21
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/README.md +124 -0
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +10 -0
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +154 -5
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/sessions.d.ts.map +1 -1
- package/dist/commands/sessions.js +129 -11
- package/dist/commands/sessions.js.map +1 -1
- package/dist/lib/claude-skill.d.ts +54 -0
- package/dist/lib/claude-skill.d.ts.map +1 -0
- package/dist/lib/claude-skill.js +88 -0
- package/dist/lib/claude-skill.js.map +1 -0
- package/dist/lib/db.d.ts +46 -5
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +78 -7
- package/dist/lib/db.js.map +1 -1
- package/dist/lib/extension-id.d.ts +30 -0
- package/dist/lib/extension-id.d.ts.map +1 -0
- package/dist/lib/extension-id.js +78 -0
- package/dist/lib/extension-id.js.map +1 -0
- package/dist/lib/format/index.d.ts +11 -1
- package/dist/lib/format/index.d.ts.map +1 -1
- package/dist/lib/format/index.js +23 -22
- package/dist/lib/format/index.js.map +1 -1
- package/dist/lib/format/json.d.ts +26 -1
- package/dist/lib/format/json.d.ts.map +1 -1
- package/dist/lib/format/json.js +39 -2
- package/dist/lib/format/json.js.map +1 -1
- package/dist/lib/format/markdown.d.ts.map +1 -1
- package/dist/lib/format/markdown.js +17 -0
- package/dist/lib/format/markdown.js.map +1 -1
- package/dist/lib/format/playwright.d.ts +13 -0
- package/dist/lib/format/playwright.d.ts.map +1 -0
- package/dist/lib/format/playwright.js +37 -0
- package/dist/lib/format/playwright.js.map +1 -0
- package/dist/lib/init-config.d.ts +12 -2
- package/dist/lib/init-config.d.ts.map +1 -1
- package/dist/lib/init-config.js +1 -1
- package/dist/lib/init-config.js.map +1 -1
- package/dist/lib/native-host-wrapper.d.ts +23 -0
- package/dist/lib/native-host-wrapper.d.ts.map +1 -0
- package/dist/lib/native-host-wrapper.js +45 -0
- package/dist/lib/native-host-wrapper.js.map +1 -0
- package/dist/lib/peek-home.d.ts +8 -0
- package/dist/lib/peek-home.d.ts.map +1 -1
- package/dist/lib/peek-home.js +10 -0
- package/dist/lib/peek-home.js.map +1 -1
- package/dist/lib/prompt.d.ts +13 -0
- package/dist/lib/prompt.d.ts.map +1 -1
- package/dist/lib/prompt.js +40 -0
- package/dist/lib/prompt.js.map +1 -1
- package/dist/skills/peek-skill.md +182 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +14 -5
- package/dist/version.js.map +1 -1
- package/package.json +24 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a candidate Chrome extension ID. Returns `null` if the input is the
|
|
3
|
+
* expected 32-character `a–p` shape; otherwise a user-facing error message.
|
|
4
|
+
*
|
|
5
|
+
* Trims internal whitespace defensively — users routinely paste from
|
|
6
|
+
* `chrome://extensions/` with a trailing newline or leading space.
|
|
7
|
+
*/
|
|
8
|
+
export declare function validateChromeExtensionId(raw: string): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Build the `chrome-extension://<id>/` origin Chrome expects in a native-host
|
|
11
|
+
* manifest's `allowed_origins`. Mirrors `allowedOrigins()` in peek-mcp's
|
|
12
|
+
* manifest.ts but emits the bare origin string for a single id (the manifest
|
|
13
|
+
* builder de-dupes when it folds multiple IDs together).
|
|
14
|
+
*/
|
|
15
|
+
export declare function chromeExtensionOrigin(id: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* P-13 (2026-05-28 QA walk) — pull the previously-saved unpacked extension ID
|
|
18
|
+
* out of an existing native-host manifest's `allowed_origins`. Returns the
|
|
19
|
+
* first 32-char a–p ID found (origins are written in the order
|
|
20
|
+
* chromeWebStore / edgeAddons / dev, but the published-store slots ship as
|
|
21
|
+
* `PLACEHOLDER_*` strings that `allowedOrigins()` drops, so anything actually
|
|
22
|
+
* present is by definition the user's dev ID).
|
|
23
|
+
*
|
|
24
|
+
* Pure — accepts any value, returns `undefined` for non-objects, malformed
|
|
25
|
+
* arrays, missing fields, or origin strings that don't match the expected
|
|
26
|
+
* `chrome-extension://<a-p×32>/` shape. The caller's idempotency check then
|
|
27
|
+
* skips the prompt and reuses the captured ID.
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractDevId(manifest: unknown): string | undefined;
|
|
30
|
+
//# sourceMappingURL=extension-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-id.d.ts","sourceRoot":"","sources":["../../src/lib/extension-id.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYpE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAWlE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Chrome extension ID validator + helpers used by `peek init` (P-10 fix,
|
|
2
|
+
// 2026-05-28 QA walk).
|
|
3
|
+
//
|
|
4
|
+
// Chrome derives the unpacked-extension ID from the SHA-256 of the absolute
|
|
5
|
+
// path of the extension folder, mapped through a 16-letter alphabet (a–p).
|
|
6
|
+
// That makes every loaded-unpacked extension ID a 32-character string of
|
|
7
|
+
// lowercase a–p — and the same shape Chrome uses for Web Store IDs. peek init
|
|
8
|
+
// captures this ID and writes it into the native-host manifest's
|
|
9
|
+
// `allowed_origins` so Chrome will let the unpacked extension connect to the
|
|
10
|
+
// native host (without an entry the manifest ships with `allowed_origins: []`
|
|
11
|
+
// and Chrome silently blocks `chrome.runtime.connectNative()`).
|
|
12
|
+
//
|
|
13
|
+
// Pure helpers — no prompt I/O lives here. The prompt loop in
|
|
14
|
+
// commands/init.ts calls `validateChromeExtensionId` from prompt.ts's
|
|
15
|
+
// `promptText({ validate })` so tests cover the input shape independently of
|
|
16
|
+
// the readline machinery.
|
|
17
|
+
/** Length + alphabet Chrome uses for both unpacked and Web Store extension IDs. */
|
|
18
|
+
const EXTENSION_ID_LENGTH = 32;
|
|
19
|
+
const EXTENSION_ID_PATTERN = /^[a-p]{32}$/;
|
|
20
|
+
/**
|
|
21
|
+
* Validate a candidate Chrome extension ID. Returns `null` if the input is the
|
|
22
|
+
* expected 32-character `a–p` shape; otherwise a user-facing error message.
|
|
23
|
+
*
|
|
24
|
+
* Trims internal whitespace defensively — users routinely paste from
|
|
25
|
+
* `chrome://extensions/` with a trailing newline or leading space.
|
|
26
|
+
*/
|
|
27
|
+
export function validateChromeExtensionId(raw) {
|
|
28
|
+
const id = raw.trim();
|
|
29
|
+
if (id.length === 0) {
|
|
30
|
+
return 'Extension ID is required (or leave empty to skip).';
|
|
31
|
+
}
|
|
32
|
+
if (id.length !== EXTENSION_ID_LENGTH) {
|
|
33
|
+
return `Expected a 32-character ID; got ${id.length}. (Copy it from chrome://extensions/.)`;
|
|
34
|
+
}
|
|
35
|
+
if (!EXTENSION_ID_PATTERN.test(id)) {
|
|
36
|
+
return 'Extension IDs are 32 lowercase letters a–p only. Re-copy from chrome://extensions/.';
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build the `chrome-extension://<id>/` origin Chrome expects in a native-host
|
|
42
|
+
* manifest's `allowed_origins`. Mirrors `allowedOrigins()` in peek-mcp's
|
|
43
|
+
* manifest.ts but emits the bare origin string for a single id (the manifest
|
|
44
|
+
* builder de-dupes when it folds multiple IDs together).
|
|
45
|
+
*/
|
|
46
|
+
export function chromeExtensionOrigin(id) {
|
|
47
|
+
return `chrome-extension://${id}/`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* P-13 (2026-05-28 QA walk) — pull the previously-saved unpacked extension ID
|
|
51
|
+
* out of an existing native-host manifest's `allowed_origins`. Returns the
|
|
52
|
+
* first 32-char a–p ID found (origins are written in the order
|
|
53
|
+
* chromeWebStore / edgeAddons / dev, but the published-store slots ship as
|
|
54
|
+
* `PLACEHOLDER_*` strings that `allowedOrigins()` drops, so anything actually
|
|
55
|
+
* present is by definition the user's dev ID).
|
|
56
|
+
*
|
|
57
|
+
* Pure — accepts any value, returns `undefined` for non-objects, malformed
|
|
58
|
+
* arrays, missing fields, or origin strings that don't match the expected
|
|
59
|
+
* `chrome-extension://<a-p×32>/` shape. The caller's idempotency check then
|
|
60
|
+
* skips the prompt and reuses the captured ID.
|
|
61
|
+
*/
|
|
62
|
+
export function extractDevId(manifest) {
|
|
63
|
+
if (manifest === null || typeof manifest !== 'object')
|
|
64
|
+
return undefined;
|
|
65
|
+
const ao = manifest.allowed_origins;
|
|
66
|
+
if (!Array.isArray(ao))
|
|
67
|
+
return undefined;
|
|
68
|
+
const pattern = /^chrome-extension:\/\/([a-p]{32})\/$/;
|
|
69
|
+
for (const origin of ao) {
|
|
70
|
+
if (typeof origin !== 'string')
|
|
71
|
+
continue;
|
|
72
|
+
const m = pattern.exec(origin);
|
|
73
|
+
if (m)
|
|
74
|
+
return m[1];
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=extension-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-id.js","sourceRoot":"","sources":["../../src/lib/extension-id.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,uBAAuB;AACvB,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,yEAAyE;AACzE,8EAA8E;AAC9E,iEAAiE;AACjE,6EAA6E;AAC7E,8EAA8E;AAC9E,gEAAgE;AAChE,EAAE;AACF,8DAA8D;AAC9D,sEAAsE;AACtE,6EAA6E;AAC7E,0BAA0B;AAE1B,mFAAmF;AACnF,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,MAAM,oBAAoB,GAAG,aAAa,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAAW;IACnD,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACtB,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,oDAAoD,CAAC;IAC9D,CAAC;IACD,IAAI,EAAE,CAAC,MAAM,KAAK,mBAAmB,EAAE,CAAC;QACtC,OAAO,mCAAmC,EAAE,CAAC,MAAM,wCAAwC,CAAC;IAC9F,CAAC;IACD,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;QACnC,OAAO,qFAAqF,CAAC;IAC/F,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAU;IAC9C,OAAO,sBAAsB,EAAE,GAAG,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAC,QAAiB;IAC5C,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACxE,MAAM,EAAE,GAAI,QAA0C,CAAC,eAAe,CAAC;IACvE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,OAAO,GAAG,sCAAsC,CAAC;IACvD,KAAK,MAAM,MAAM,IAAI,EAAE,EAAE,CAAC;QACxB,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,SAAS;QACzC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -11,6 +11,16 @@ export type FormatResult = {
|
|
|
11
11
|
readonly ok: false;
|
|
12
12
|
readonly message: string;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Optional ancillary data the formatter may need beyond `SessionDetail`. The
|
|
16
|
+
* playwright format needs `blobPath` (the `sessions.events_blob_path` value)
|
|
17
|
+
* to load the gzipped rrweb stream from disk; markdown / json work purely
|
|
18
|
+
* from the SQL rows already on `detail` and ignore it.
|
|
19
|
+
*/
|
|
20
|
+
export interface FormatOptions {
|
|
21
|
+
/** Relative path to the session's gzipped event blob, for the playwright walker. */
|
|
22
|
+
readonly blobPath?: string;
|
|
23
|
+
}
|
|
14
24
|
/** Render a hydrated session in the requested format. */
|
|
15
|
-
export declare function formatSession(detail: SessionDetail, format: ExportFormat): FormatResult;
|
|
25
|
+
export declare function formatSession(detail: SessionDetail, format: ExportFormat, options?: FormatOptions): FormatResult;
|
|
16
26
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/format/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/format/index.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAK9C,iDAAiD;AACjD,eAAO,MAAM,cAAc,qDAAsD,CAAC;AAClF,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,YAAY,CAEnE;AAED,kFAAkF;AAClF,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAsBd"}
|
package/dist/lib/format/index.js
CHANGED
|
@@ -1,42 +1,43 @@
|
|
|
1
|
-
// Export-format dispatch (P2 PRD §C.3). `markdown` and `
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// -
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
1
|
+
// Export-format dispatch (P2 PRD §C.3). `markdown`, `json`, and `playwright`
|
|
2
|
+
// are implemented fully:
|
|
3
|
+
// - markdown / json: self-contained AI-paste formats, read straight from
|
|
4
|
+
// the extracted SQL rows (consoleErrors / networkErrors).
|
|
5
|
+
// - playwright (K.2 alpha.7 fix): wires to the SAME walker the MCP
|
|
6
|
+
// `generate_playwright_repro` tool uses via `@peekdev/mcp/mcp/playwright-
|
|
7
|
+
// repro` + `@peekdev/mcp/mcp/event-blobs`. CLI + AI consumers produce
|
|
8
|
+
// identical output for the same session (P2 PRD §B3 parity guarantee).
|
|
9
|
+
//
|
|
10
|
+
// `html` (self-contained rrweb replay) stays deferred — it would require
|
|
11
|
+
// bundling an rrweb player inline; importing @tracelane/report is explicitly
|
|
12
|
+
// forbidden (ADR-0001 product independence), so a peek-specific viewer is a
|
|
13
|
+
// tracked follow-up. The stub returns a non-ok result so the command shell
|
|
14
|
+
// exits non-zero with a clear message (never silently emit an empty/partial
|
|
15
|
+
// file).
|
|
13
16
|
import { formatSessionJson } from './json.js';
|
|
14
17
|
import { formatSessionMarkdown } from './markdown.js';
|
|
18
|
+
import { formatSessionPlaywright } from './playwright.js';
|
|
15
19
|
/** Supported `--format` values (P2 PRD §C.1). */
|
|
16
20
|
export const EXPORT_FORMATS = ['markdown', 'json', 'html', 'playwright'];
|
|
17
21
|
export function isExportFormat(value) {
|
|
18
22
|
return EXPORT_FORMATS.includes(value);
|
|
19
23
|
}
|
|
20
24
|
/** Render a hydrated session in the requested format. */
|
|
21
|
-
export function formatSession(detail, format) {
|
|
25
|
+
export function formatSession(detail, format, options = {}) {
|
|
22
26
|
switch (format) {
|
|
23
27
|
case 'markdown':
|
|
24
28
|
return { ok: true, content: formatSessionMarkdown(detail) };
|
|
25
29
|
case 'json':
|
|
26
30
|
return { ok: true, content: formatSessionJson(detail) };
|
|
27
|
-
case '
|
|
31
|
+
case 'playwright':
|
|
28
32
|
return {
|
|
29
|
-
ok:
|
|
30
|
-
|
|
31
|
-
'rrweb replay viewer is tracked for a follow-up; @tracelane/report is intentionally ' +
|
|
32
|
-
'not reused — ADR-0001 product independence). Use --format markdown or json.',
|
|
33
|
+
ok: true,
|
|
34
|
+
content: formatSessionPlaywright(detail, ...(options.blobPath !== undefined ? [options.blobPath] : [])),
|
|
33
35
|
};
|
|
34
|
-
case '
|
|
36
|
+
case 'html':
|
|
35
37
|
return {
|
|
36
38
|
ok: false,
|
|
37
|
-
message: "export format '
|
|
38
|
-
'
|
|
39
|
-
'Use --format markdown or json.',
|
|
39
|
+
message: "export format 'html' is not yet implemented (a peek-specific self-contained " +
|
|
40
|
+
'rrweb replay viewer is tracked for a follow-up). Use --format markdown or json.',
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/format/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/format/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,yBAAyB;AACzB,2EAA2E;AAC3E,8DAA8D;AAC9D,qEAAqE;AACrE,8EAA8E;AAC9E,0EAA0E;AAC1E,2EAA2E;AAC3E,EAAE;AACF,yEAAyE;AACzE,6EAA6E;AAC7E,4EAA4E;AAC5E,2EAA2E;AAC3E,4EAA4E;AAC5E,SAAS;AAGT,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,iDAAiD;AACjD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAU,CAAC;AAGlF,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAQ,cAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAkBD,yDAAyD;AACzD,MAAM,UAAU,aAAa,CAC3B,MAAqB,EACrB,MAAoB,EACpB,UAAyB,EAAE;IAE3B,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,UAAU;YACb,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,qBAAqB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9D,KAAK,MAAM;YACT,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,KAAK,YAAY;YACf,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,OAAO,EAAE,uBAAuB,CAC9B,MAAM,EACN,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAC9D;aACF,CAAC;QACJ,KAAK,MAAM;YACT,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,OAAO,EACL,8EAA8E;oBAC9E,iFAAiF;aACpF,CAAC;IACN,CAAC;AACH,CAAC"}
|
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
import type { SessionDetail } from '../db.js';
|
|
2
|
+
/** Static attribution block shape — never references session data. */
|
|
3
|
+
export interface AttributionBlock {
|
|
4
|
+
readonly tool: 'peek';
|
|
5
|
+
readonly url: string;
|
|
6
|
+
readonly description: string;
|
|
7
|
+
readonly version: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Build the self-marketing attribution block (Phase 5 indirect virality).
|
|
11
|
+
*
|
|
12
|
+
* The URL links to `packages/peek-mcp` because the install command
|
|
13
|
+
* (`npm i @peekdev/mcp` / `peek init`) is the marketing artifact per the
|
|
14
|
+
* research — not the docs site, not a landing page. The UTM medium is
|
|
15
|
+
* format-specific so we can attribute which export shape drives the most
|
|
16
|
+
* click-through (JSON vs Markdown vs future formats).
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildAttribution(medium: 'json-attribution' | 'markdown-attribution'): AttributionBlock;
|
|
2
19
|
/** The JSON export envelope. Field names mirror the MCP tool return shapes. */
|
|
3
20
|
export interface SessionJsonExport {
|
|
4
21
|
readonly id: string;
|
|
@@ -30,6 +47,14 @@ export interface SessionJsonExport {
|
|
|
30
47
|
}
|
|
31
48
|
/** Build the JSON export object (pure; not yet stringified). */
|
|
32
49
|
export declare function toJsonExport(detail: SessionDetail): SessionJsonExport;
|
|
33
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Render a session as a pretty-printed JSON string (2-space indent).
|
|
52
|
+
*
|
|
53
|
+
* `_attribution` is inserted FIRST in the object literal so it appears at the
|
|
54
|
+
* top of the serialized output — `JSON.stringify` preserves insertion order
|
|
55
|
+
* per the ECMA-262 spec for string keys (own enumerable string properties are
|
|
56
|
+
* visited in insertion order). The `_` prefix is the JSON convention for
|
|
57
|
+
* "metadata, not data" — discoverable but not part of the session payload.
|
|
58
|
+
*/
|
|
34
59
|
export declare function formatSessionJson(detail: SessionDetail): string;
|
|
35
60
|
//# sourceMappingURL=json.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/lib/format/json.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/lib/format/json.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,kBAAkB,GAAG,sBAAsB,GAClD,gBAAgB,CAQlB;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;QACpC,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC,CAAC;IACH,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;QACpC,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,CAAC,CAAC;CACJ;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,iBAAiB,CA8BrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAM/D"}
|
package/dist/lib/format/json.js
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
// (P2 PRD §C.3 "same schema as MCP tool returns", §B3) so an AI consumer can
|
|
3
3
|
// treat a CLI export and an MCP `get_session_*` response interchangeably. Pure:
|
|
4
4
|
// SessionDetail in, JSON string out.
|
|
5
|
+
//
|
|
6
|
+
// Phase 5 self-marketing: every export carries a top-level `_attribution` block
|
|
7
|
+
// (underscore-prefixed per JSON convention for "metadata not data") so a JSON
|
|
8
|
+
// export shared in a PR or attached to a JIRA ticket is a tracked acquisition
|
|
9
|
+
// channel — the Loom / Calendly / Statuspage indirect-virality pattern. The
|
|
10
|
+
// block contains only static strings + the CLI version; no session content
|
|
11
|
+
// leaks in.
|
|
12
|
+
import { CLI_VERSION } from '../../version.js';
|
|
13
|
+
/**
|
|
14
|
+
* Build the self-marketing attribution block (Phase 5 indirect virality).
|
|
15
|
+
*
|
|
16
|
+
* The URL links to `packages/peek-mcp` because the install command
|
|
17
|
+
* (`npm i @peekdev/mcp` / `peek init`) is the marketing artifact per the
|
|
18
|
+
* research — not the docs site, not a landing page. The UTM medium is
|
|
19
|
+
* format-specific so we can attribute which export shape drives the most
|
|
20
|
+
* click-through (JSON vs Markdown vs future formats).
|
|
21
|
+
*/
|
|
22
|
+
export function buildAttribution(medium) {
|
|
23
|
+
return {
|
|
24
|
+
tool: 'peek',
|
|
25
|
+
url: `https://github.com/Cubenest/rrweb-stack/tree/main/packages/peek-mcp?utm_source=peek-export&utm_medium=${medium}&utm_campaign=indirect-virality`,
|
|
26
|
+
description: 'Captured with peek — your real browser, exposed to your AI coding agent over MCP. Capture once, query forever, never leaves your machine.',
|
|
27
|
+
version: CLI_VERSION,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
5
30
|
/** Build the JSON export object (pure; not yet stringified). */
|
|
6
31
|
export function toJsonExport(detail) {
|
|
7
32
|
const { session, counts, consoleErrors, networkErrors } = detail;
|
|
@@ -34,8 +59,20 @@ export function toJsonExport(detail) {
|
|
|
34
59
|
})),
|
|
35
60
|
};
|
|
36
61
|
}
|
|
37
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Render a session as a pretty-printed JSON string (2-space indent).
|
|
64
|
+
*
|
|
65
|
+
* `_attribution` is inserted FIRST in the object literal so it appears at the
|
|
66
|
+
* top of the serialized output — `JSON.stringify` preserves insertion order
|
|
67
|
+
* per the ECMA-262 spec for string keys (own enumerable string properties are
|
|
68
|
+
* visited in insertion order). The `_` prefix is the JSON convention for
|
|
69
|
+
* "metadata, not data" — discoverable but not part of the session payload.
|
|
70
|
+
*/
|
|
38
71
|
export function formatSessionJson(detail) {
|
|
39
|
-
|
|
72
|
+
const envelope = {
|
|
73
|
+
_attribution: buildAttribution('json-attribution'),
|
|
74
|
+
session: toJsonExport(detail),
|
|
75
|
+
};
|
|
76
|
+
return `${JSON.stringify(envelope, null, 2)}\n`;
|
|
40
77
|
}
|
|
41
78
|
//# sourceMappingURL=json.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/lib/format/json.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,gFAAgF;AAChF,qCAAqC;
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/lib/format/json.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,gFAAgF;AAChF,qCAAqC;AACrC,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,YAAY;AAEZ,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAW/C;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAmD;IAEnD,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,yGAAyG,MAAM,iCAAiC;QACrJ,WAAW,EACT,2IAA2I;QAC7I,OAAO,EAAE,WAAW;KACrB,CAAC;AACJ,CAAC;AAgCD,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;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAqB;IACrD,MAAM,QAAQ,GAAG;QACf,YAAY,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;QAClD,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC;KAC9B,CAAC;IACF,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/lib/format/markdown.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/lib/format/markdown.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAoC,aAAa,EAAE,MAAM,UAAU,CAAC;AAiChF,6DAA6D;AAC7D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAuDnE"}
|
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
// `generate_playwright_repro` tools (Phase 3c). The CLI markdown export reads
|
|
13
13
|
// only the extracted SQL rows, so it states where the richer data lives rather
|
|
14
14
|
// than fabricating it.
|
|
15
|
+
//
|
|
16
|
+
// Phase 5 self-marketing: the export ends with an `---` rule + an attribution
|
|
17
|
+
// blockquote so every Markdown export shared in a PR or attached to a ticket
|
|
18
|
+
// is a tracked acquisition channel (UTM-tagged link to peek-mcp's install
|
|
19
|
+
// path on GitHub — the install command IS the marketing artifact per the
|
|
20
|
+
// indirect-virality research). The attribution is static — no session data.
|
|
21
|
+
import { buildAttribution } from './json.js';
|
|
15
22
|
function isoFromMs(tsMs) {
|
|
16
23
|
return new Date(tsMs).toISOString();
|
|
17
24
|
}
|
|
@@ -71,6 +78,16 @@ export function formatSessionMarkdown(detail) {
|
|
|
71
78
|
lines.push('## Suggested reproduction');
|
|
72
79
|
lines.push(`Generate a Playwright repro with \`peek sessions export ${session.id} --format playwright\`, or the MCP \`generate_playwright_repro\` tool.`);
|
|
73
80
|
lines.push('');
|
|
81
|
+
// Self-marketing attribution (Phase 5 indirect virality). Horizontal-rule
|
|
82
|
+
// separates it from the export body; blockquote keeps it visually distinct
|
|
83
|
+
// (won't be mistaken for a user-action line by an AI paste consumer). The
|
|
84
|
+
// link target is the install path on GitHub — that's where the reader
|
|
85
|
+
// sees `npm i @peekdev/mcp`.
|
|
86
|
+
const attribution = buildAttribution('markdown-attribution');
|
|
87
|
+
lines.push('---');
|
|
88
|
+
lines.push('');
|
|
89
|
+
lines.push(`> _Captured with [peek](${attribution.url}) — your real browser, exposed to your AI coding agent over MCP._`);
|
|
90
|
+
lines.push('');
|
|
74
91
|
return lines.join('\n');
|
|
75
92
|
}
|
|
76
93
|
//# sourceMappingURL=markdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/lib/format/markdown.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,4DAA4D;AAC5D,YAAY;AACZ,sBAAsB;AACtB,uBAAuB;AACvB,iCAAiC;AACjC,8BAA8B;AAC9B,+CAA+C;AAC/C,EAAE;AACF,4EAA4E;AAC5E,mEAAmE;AACnE,8EAA8E;AAC9E,+EAA+E;AAC/E,uBAAuB;
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/lib/format/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SessionDetail } from '../db.js';
|
|
2
|
+
/**
|
|
3
|
+
* Render a hydrated session as a Playwright `.spec.ts` test string. Returns
|
|
4
|
+
* the script verbatim — no trailing newline mutation — so byte-identical
|
|
5
|
+
* comparison with the MCP tool output works for tests.
|
|
6
|
+
*
|
|
7
|
+
* If the session has no recorded event blob (active session pre-flush, or
|
|
8
|
+
* blob pruned by retention), the generator still emits a valid `test(...)`
|
|
9
|
+
* shell with a `// No user actions were recorded` placeholder so the user
|
|
10
|
+
* gets a script they can edit, not an empty file.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatSessionPlaywright(detail: SessionDetail, blobPath?: string): string;
|
|
13
|
+
//# sourceMappingURL=playwright.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../../src/lib/format/playwright.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// `--format playwright`: emit a runnable Playwright `test(...)` repro from a
|
|
2
|
+
// session's rrweb stream (K.2 alpha.7 fix). This wires the CLI to the SAME
|
|
3
|
+
// code path the MCP `generate_playwright_repro` tool uses — Phase 3c Task 3.13,
|
|
4
|
+
// implemented in `@peekdev/mcp/mcp/playwright-repro`. CLI and AI consumers MUST
|
|
5
|
+
// produce identical output for the same session (P2 PRD §B3 cross-surface
|
|
6
|
+
// parity guarantee).
|
|
7
|
+
//
|
|
8
|
+
// The MCP tool walks the in-memory eventWithTime[] directly; the CLI reads
|
|
9
|
+
// the on-disk gzipped blob first (via @peekdev/mcp/mcp/event-blobs), then
|
|
10
|
+
// hands the decoded events to the shared generator. The session metadata
|
|
11
|
+
// (used as the test title) comes from the same SessionDetail the markdown +
|
|
12
|
+
// json formatters consume.
|
|
13
|
+
//
|
|
14
|
+
// Pre-K.2, this format returned a non-ok "not yet implemented (Phase 3c Task
|
|
15
|
+
// 3.13)" message because the walker lived in peek-mcp and wasn't published
|
|
16
|
+
// as a sub-path export. Alpha.7 adds the `./mcp/playwright-repro` and
|
|
17
|
+
// `./mcp/event-blobs` sub-path exports so the CLI can import the generator
|
|
18
|
+
// + the on-disk blob loader directly, with no code forking.
|
|
19
|
+
import { loadSessionEvents } from '@peekdev/mcp/mcp/event-blobs';
|
|
20
|
+
import { generatePlaywrightRepro } from '@peekdev/mcp/mcp/playwright-repro';
|
|
21
|
+
/**
|
|
22
|
+
* Render a hydrated session as a Playwright `.spec.ts` test string. Returns
|
|
23
|
+
* the script verbatim — no trailing newline mutation — so byte-identical
|
|
24
|
+
* comparison with the MCP tool output works for tests.
|
|
25
|
+
*
|
|
26
|
+
* If the session has no recorded event blob (active session pre-flush, or
|
|
27
|
+
* blob pruned by retention), the generator still emits a valid `test(...)`
|
|
28
|
+
* shell with a `// No user actions were recorded` placeholder so the user
|
|
29
|
+
* gets a script they can edit, not an empty file.
|
|
30
|
+
*/
|
|
31
|
+
export function formatSessionPlaywright(detail, blobPath) {
|
|
32
|
+
const events = blobPath !== undefined && blobPath.length > 0 ? loadSessionEvents(blobPath) : [];
|
|
33
|
+
return generatePlaywrightRepro(events, {
|
|
34
|
+
title: detail.session.title ?? `peek session ${detail.session.id}`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=playwright.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright.js","sourceRoot":"","sources":["../../../src/lib/format/playwright.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,2EAA2E;AAC3E,gFAAgF;AAChF,gFAAgF;AAChF,0EAA0E;AAC1E,qBAAqB;AACrB,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,4EAA4E;AAC5E,2BAA2B;AAC3B,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,sEAAsE;AACtE,2EAA2E;AAC3E,4DAA4D;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAG5E;;;;;;;;;GASG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAqB,EAAE,QAAiB;IAC9E,MAAM,MAAM,GAAG,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,OAAO,uBAAuB,CAAC,MAAM,EAAE;QACrC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,gBAAgB,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE;KACnE,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
/** The MCP server key peek registers under, and the block written for it. */
|
|
2
2
|
export declare const PEEK_SERVER_KEY = "peek";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* The `mcpServers.peek` block (P2 PRD §K.1-K.5): `npx -y @peekdev/mcp@latest`.
|
|
5
|
+
*
|
|
6
|
+
* The version tag is load-bearing. `@peekdev/mcp` is published only under
|
|
7
|
+
* prerelease versions (`0.1.0-alpha.*`) while in alpha, and a bare
|
|
8
|
+
* `npx -y @peekdev/mcp` resolves the implicit `*` range, which per semver does
|
|
9
|
+
* NOT match prereleases — npx fails with `ETARGET: No matching version found
|
|
10
|
+
* for @peekdev/mcp@*` and the MCP client reports a connection error. Pinning
|
|
11
|
+
* `@latest` forces the dist-tag (the newest published alpha) so resolution
|
|
12
|
+
* succeeds. Revisit once a stable (non-prerelease) version ships.
|
|
13
|
+
*/
|
|
4
14
|
export interface PeekMcpServerBlock {
|
|
5
15
|
readonly command: 'npx';
|
|
6
|
-
readonly args: readonly ['-y', '@peekdev/mcp'];
|
|
16
|
+
readonly args: readonly ['-y', '@peekdev/mcp@latest'];
|
|
7
17
|
}
|
|
8
18
|
export declare const PEEK_MCP_BLOCK: PeekMcpServerBlock;
|
|
9
19
|
/** Stable identifiers for the supported MCP clients. */
|
|
@@ -1 +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
|
|
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;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC;CACvD;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"}
|
package/dist/lib/init-config.js
CHANGED
|
@@ -9,7 +9,7 @@ import { join } from 'node:path';
|
|
|
9
9
|
export const PEEK_SERVER_KEY = 'peek';
|
|
10
10
|
export const PEEK_MCP_BLOCK = {
|
|
11
11
|
command: 'npx',
|
|
12
|
-
args: ['-y', '@peekdev/mcp'],
|
|
12
|
+
args: ['-y', '@peekdev/mcp@latest'],
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
15
|
* The five MCP clients from the §K.5 wizard. Cline is `manualOnly` because its
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-config.js","sourceRoot":"","sources":["../../src/lib/init-config.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+EAA+E;AAC/E,0EAA0E;AAC1E,mEAAmE;AACnE,0EAA0E;AAC1E,sCAAsC;AAEtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"init-config.js","sourceRoot":"","sources":["../../src/lib/init-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SupportedPlatform } from '@peekdev/mcp/native-host';
|
|
2
|
+
/**
|
|
3
|
+
* Where the generated wrapper lives. On POSIX it ends in `.sh`; on Windows
|
|
4
|
+
* `.cmd` so the shell that Chrome's CreateProcess invocation finds knows what
|
|
5
|
+
* to execute. The wrapper lives under `~/.peek/` so it shares the same
|
|
6
|
+
* permission scope as the audit log + sessions DB.
|
|
7
|
+
*/
|
|
8
|
+
export declare function wrapperPath(peekHomeDir: string, platform: SupportedPlatform): string;
|
|
9
|
+
/**
|
|
10
|
+
* Body of the wrapper script. Pure — accepts the node binary and the host
|
|
11
|
+
* `.js` path explicitly so tests can hand it any fixture without touching
|
|
12
|
+
* `process.execPath` or `hostBinaryPath()`.
|
|
13
|
+
*
|
|
14
|
+
* POSIX: a `/bin/sh` script that `exec`s `node host.js "$@"`. `exec` replaces
|
|
15
|
+
* the shell so Chrome's process tree stays minimal (it tracks the JS process
|
|
16
|
+
* directly for stdin/stdout, not a shell wrapper that's blocking the pipe).
|
|
17
|
+
*
|
|
18
|
+
* Windows: a `.cmd` that calls node with the args via `%*`. We use
|
|
19
|
+
* Windows line endings (`\r\n`) because some legacy CMD versions choke on
|
|
20
|
+
* LF-only `.cmd` files when invoked via CreateProcess.
|
|
21
|
+
*/
|
|
22
|
+
export declare function wrapperContent(nodePath: string, hostJsPath: string, platform: SupportedPlatform): string;
|
|
23
|
+
//# sourceMappingURL=native-host-wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-host-wrapper.d.ts","sourceRoot":"","sources":["../../src/lib/native-host-wrapper.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CAGpF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,iBAAiB,GAC1B,MAAM,CAKR"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// P-16 (2026-05-28 QA walk) — generate a tiny shell wrapper for the native
|
|
2
|
+
// host. Chrome (and other Chromium-based browsers) spawn the manifest's `path`
|
|
3
|
+
// via the GUI launcher's `$PATH`, NOT the shell's. On macOS with both a
|
|
4
|
+
// legacy /usr/local/bin/node and a current /opt/homebrew/bin/node, the system
|
|
5
|
+
// PATH resolves `#!/usr/bin/env node` to the older binary — typically
|
|
6
|
+
// architecture-mismatched, so `better-sqlite3.node` fails dlopen and the
|
|
7
|
+
// host process exits before Chrome reads any output. Chrome silently moves on.
|
|
8
|
+
//
|
|
9
|
+
// The fix is to write a wrapper that hardcodes `process.execPath` (the node
|
|
10
|
+
// that ran `peek init`) and point the manifest at the wrapper. This is the
|
|
11
|
+
// well-trodden pattern for any Node-based native messaging host.
|
|
12
|
+
//
|
|
13
|
+
// Pure helpers — `writeNativeHostWrapper` (in commands/init.ts) does the
|
|
14
|
+
// filesystem write. Tests pin the path layout + content shape per platform.
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
/**
|
|
17
|
+
* Where the generated wrapper lives. On POSIX it ends in `.sh`; on Windows
|
|
18
|
+
* `.cmd` so the shell that Chrome's CreateProcess invocation finds knows what
|
|
19
|
+
* to execute. The wrapper lives under `~/.peek/` so it shares the same
|
|
20
|
+
* permission scope as the audit log + sessions DB.
|
|
21
|
+
*/
|
|
22
|
+
export function wrapperPath(peekHomeDir, platform) {
|
|
23
|
+
const filename = platform === 'win32' ? 'peek-mcp-host.cmd' : 'peek-mcp-host.sh';
|
|
24
|
+
return join(peekHomeDir, filename);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Body of the wrapper script. Pure — accepts the node binary and the host
|
|
28
|
+
* `.js` path explicitly so tests can hand it any fixture without touching
|
|
29
|
+
* `process.execPath` or `hostBinaryPath()`.
|
|
30
|
+
*
|
|
31
|
+
* POSIX: a `/bin/sh` script that `exec`s `node host.js "$@"`. `exec` replaces
|
|
32
|
+
* the shell so Chrome's process tree stays minimal (it tracks the JS process
|
|
33
|
+
* directly for stdin/stdout, not a shell wrapper that's blocking the pipe).
|
|
34
|
+
*
|
|
35
|
+
* Windows: a `.cmd` that calls node with the args via `%*`. We use
|
|
36
|
+
* Windows line endings (`\r\n`) because some legacy CMD versions choke on
|
|
37
|
+
* LF-only `.cmd` files when invoked via CreateProcess.
|
|
38
|
+
*/
|
|
39
|
+
export function wrapperContent(nodePath, hostJsPath, platform) {
|
|
40
|
+
if (platform === 'win32') {
|
|
41
|
+
return `@echo off\r\n"${nodePath}" "${hostJsPath}" %*\r\n`;
|
|
42
|
+
}
|
|
43
|
+
return `#!/bin/sh\nexec "${nodePath}" "${hostJsPath}" "$@"\n`;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=native-host-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"native-host-wrapper.js","sourceRoot":"","sources":["../../src/lib/native-host-wrapper.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,+EAA+E;AAC/E,wEAAwE;AACxE,8EAA8E;AAC9E,sEAAsE;AACtE,yEAAyE;AACzE,+EAA+E;AAC/E,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,iEAAiE;AACjE,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAE5E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,QAA2B;IAC1E,MAAM,QAAQ,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,kBAAkB,CAAC;IACjF,OAAO,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAgB,EAChB,UAAkB,EAClB,QAA2B;IAE3B,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,UAAU,CAAC;IAC7D,CAAC;IACD,OAAO,oBAAoB,QAAQ,MAAM,UAAU,UAAU,CAAC;AAChE,CAAC"}
|
package/dist/lib/peek-home.d.ts
CHANGED
|
@@ -2,4 +2,12 @@ import { defaultDbPath, peekHomeDir } from '@peekdev/mcp/db';
|
|
|
2
2
|
export { defaultDbPath, peekHomeDir };
|
|
3
3
|
/** Absolute path to the append-only audit log (~/.peek/audit.log, ADR-0010). */
|
|
4
4
|
export declare function auditLogPath(): string;
|
|
5
|
+
/**
|
|
6
|
+
* Base directory for gzipped rrweb event chunks (ADR-0007): `~/.peek/rrweb-events/`.
|
|
7
|
+
* Each session has a subdirectory `<sessionId>/` with one `<seq>.json.gz` per
|
|
8
|
+
* append batch. Mirrors `rrwebEventsDir()` in peek-mcp's `mcp/event-blobs.ts`;
|
|
9
|
+
* the path layout is the public contract between writer (native host) and
|
|
10
|
+
* reader/cleaner (this CLI).
|
|
11
|
+
*/
|
|
12
|
+
export declare function rrwebEventsDir(): string;
|
|
5
13
|
//# sourceMappingURL=peek-home.d.ts.map
|
|
@@ -1 +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"}
|
|
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;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
|