@tph/team-prompt-history 0.0.0-stage → 2.0.0

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 (90) hide show
  1. package/.cursor-plugin/plugin.json +16 -0
  2. package/README.md +13 -2
  3. package/commands/prompt-history-config.md +20 -0
  4. package/commands/prompt-history-export.md +14 -0
  5. package/commands/prompt-history-register.md +17 -0
  6. package/commands/prompt-history-search.md +18 -0
  7. package/commands/prompt-history-status.md +20 -0
  8. package/dist/capture/dedupe.d.ts +2 -0
  9. package/dist/capture/dedupe.js +93 -0
  10. package/dist/capture/dedupe.js.map +1 -0
  11. package/dist/capture/handler.d.ts +18 -0
  12. package/dist/capture/handler.js +59 -0
  13. package/dist/capture/handler.js.map +1 -0
  14. package/dist/capture/record.d.ts +8 -0
  15. package/dist/capture/record.js +56 -0
  16. package/dist/capture/record.js.map +1 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +456 -0
  19. package/dist/cli.js.map +1 -0
  20. package/dist/config/paths.d.ts +6 -0
  21. package/dist/config/paths.js +62 -0
  22. package/dist/config/paths.js.map +1 -0
  23. package/dist/config/store.d.ts +27 -0
  24. package/dist/config/store.js +233 -0
  25. package/dist/config/store.js.map +1 -0
  26. package/dist/config/validate.d.ts +3 -0
  27. package/dist/config/validate.js +86 -0
  28. package/dist/config/validate.js.map +1 -0
  29. package/dist/history/search.d.ts +5 -0
  30. package/dist/history/search.js +57 -0
  31. package/dist/history/search.js.map +1 -0
  32. package/dist/history/service.d.ts +18 -0
  33. package/dist/history/service.js +54 -0
  34. package/dist/history/service.js.map +1 -0
  35. package/dist/hook-entry.d.ts +1 -0
  36. package/dist/hook-entry.js +56 -0
  37. package/dist/hook-entry.js.map +1 -0
  38. package/dist/install-plugin.d.ts +17 -0
  39. package/dist/install-plugin.js +110 -0
  40. package/dist/install-plugin.js.map +1 -0
  41. package/dist/storage/format.d.ts +6 -0
  42. package/dist/storage/format.js +89 -0
  43. package/dist/storage/format.js.map +1 -0
  44. package/dist/storage/importExport.d.ts +3 -0
  45. package/dist/storage/importExport.js +68 -0
  46. package/dist/storage/importExport.js.map +1 -0
  47. package/dist/storage/writer.d.ts +6 -0
  48. package/dist/storage/writer.js +87 -0
  49. package/dist/storage/writer.js.map +1 -0
  50. package/dist/sync/api-client.d.ts +16 -0
  51. package/dist/sync/api-client.js +75 -0
  52. package/dist/sync/api-client.js.map +1 -0
  53. package/dist/sync/backup-rotate.d.ts +15 -0
  54. package/dist/sync/backup-rotate.js +68 -0
  55. package/dist/sync/backup-rotate.js.map +1 -0
  56. package/dist/sync/collector.d.ts +21 -0
  57. package/dist/sync/collector.js +200 -0
  58. package/dist/sync/collector.js.map +1 -0
  59. package/dist/sync/doctor.d.ts +5 -0
  60. package/dist/sync/doctor.js +152 -0
  61. package/dist/sync/doctor.js.map +1 -0
  62. package/dist/sync/poll-daemon.d.ts +5 -0
  63. package/dist/sync/poll-daemon.js +83 -0
  64. package/dist/sync/poll-daemon.js.map +1 -0
  65. package/dist/sync/push-queue.d.ts +43 -0
  66. package/dist/sync/push-queue.js +159 -0
  67. package/dist/sync/push-queue.js.map +1 -0
  68. package/dist/sync/push.d.ts +29 -0
  69. package/dist/sync/push.js +113 -0
  70. package/dist/sync/push.js.map +1 -0
  71. package/dist/sync/service-manager.d.ts +24 -0
  72. package/dist/sync/service-manager.js +327 -0
  73. package/dist/sync/service-manager.js.map +1 -0
  74. package/dist/types/prompt.d.ts +68 -0
  75. package/dist/types/prompt.js +3 -0
  76. package/dist/types/prompt.js.map +1 -0
  77. package/dist/ui/cli-config.d.ts +1 -0
  78. package/dist/ui/cli-config.js +100 -0
  79. package/dist/ui/cli-config.js.map +1 -0
  80. package/dist/ui/display.d.ts +5 -0
  81. package/dist/ui/display.js +44 -0
  82. package/dist/ui/display.js.map +1 -0
  83. package/examples/sample-history.txt +32 -0
  84. package/hooks/hooks.json +10 -0
  85. package/node_modules/@tph/shared/dist/index.d.ts +97 -0
  86. package/node_modules/@tph/shared/dist/index.js +6 -0
  87. package/node_modules/@tph/shared/package.json +6 -0
  88. package/package.json +43 -4
  89. package/scripts/capture-prompt.js +12 -0
  90. package/skills/prompt-history/SKILL.md +38 -0
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "team-prompt-history",
3
+ "version": "2.0.0",
4
+ "description": "Capture Cursor Agent Chat prompts locally and sync to a team server when admins collect history via client polling.",
5
+ "author": {
6
+ "name": "GTCSYS Learning"
7
+ },
8
+ "keywords": [
9
+ "prompt-history",
10
+ "hooks",
11
+ "team",
12
+ "privacy",
13
+ "local-storage"
14
+ ],
15
+ "license": "MIT"
16
+ }
package/README.md CHANGED
@@ -1,3 +1,14 @@
1
- # Temporary Holding Version
1
+ # @tph/team-prompt-history
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Team Prompt History — Cursor client (capture + push-on-capture + team sync).
4
+
5
+ ## Install (developers)
6
+
7
+ ```bash
8
+ npm config set @tph:registry https://registry.npmjs.org/
9
+ npm install -g @tph/team-prompt-history
10
+ prompt-history install-plugin
11
+ prompt-history register --server https://YOUR_TPH_HOST --key tph_… --device-name "$(hostname -s)"
12
+ ```
13
+
14
+ Reload Cursor after `install-plugin`.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: prompt-history-config
3
+ description: Configure Local Prompt History name, storage folder, and file (non-interactive flags preferred)
4
+ ---
5
+
6
+ # Configure prompt history
7
+
8
+ Explain that changing path/file does **not** overwrite the old history file; old file stays untouched and new captures go to the new path only.
9
+
10
+ Prefer non-interactive setup when the user provides values:
11
+
12
+ ```bash
13
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" config-set --name "<History Name>" --folder "<absolute folder>" --file "prompt-history.txt"
14
+ ```
15
+
16
+ Then run `test-storage` and `status`. For interactive wizard (TTY):
17
+
18
+ ```bash
19
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" config
20
+ ```
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: prompt-history-export
3
+ description: Export local prompt history (all, date range, or search results) to a .txt file
4
+ ---
5
+
6
+ # Export prompt history
7
+
8
+ ```bash
9
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" export --out "<absolute-path>.txt"
10
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" export --out "<path>.txt" --from YYYY-MM-DD --to YYYY-MM-DD
11
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" export --out "<path>.txt" --text "<query>"
12
+ ```
13
+
14
+ Confirm count and destination. Files stay local.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: prompt-history-register
3
+ description: Register this device with the Team Prompt History server using an enrollment key
4
+ ---
5
+
6
+ # Register device
7
+
8
+ Ensure local config exists first (`prompt-history config` / `config-set`).
9
+
10
+ ```bash
11
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" register \
12
+ --server "<https://your-server>" \
13
+ --key "<enrollment-key-plaintext>" \
14
+ --device-name "<friendly-name>"
15
+ ```
16
+
17
+ Then recommend starting `poll-daemon` for ~30s collection polling. Do not print enrollment keys in logs after use.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: prompt-history-search
3
+ description: Search or filter locally stored Cursor prompts by text, id, date, or range
4
+ ---
5
+
6
+ # Search prompt history
7
+
8
+ Use only the local CLI. Do not upload prompts.
9
+
10
+ ```bash
11
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" list --text "<query>" --sort newest
12
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" list --date YYYY-MM-DD
13
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" list --from YYYY-MM-DD --to YYYY-MM-DD
14
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" list --latest week
15
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" show <id-prefix>
16
+ ```
17
+
18
+ Show list previews to the user. Only show full prompt text when they select an id.
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: prompt-history-status
3
+ description: Show Local Prompt History Manager status (name, path, count, capture state)
4
+ ---
5
+
6
+ # Prompt history status
7
+
8
+ Run the local CLI (no network; never print full prompt bodies unless the user asks):
9
+
10
+ ```bash
11
+ node "${CURSOR_PLUGIN_ROOT:-.}/dist/cli.js" status
12
+ ```
13
+
14
+ If the plugin is not built yet, from the plugin repo:
15
+
16
+ ```bash
17
+ npm run build && npm run cli -- status
18
+ ```
19
+
20
+ Summarize the output for the user: history name, resolved storage path, record count, and whether capture is enabled/paused/disabled.
@@ -0,0 +1,2 @@
1
+ export declare function buildDedupeKey(generationId: string | undefined, prompt: string): string;
2
+ export declare function shouldCaptureOnce(key: string, homeDir?: string, now?: number): boolean;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildDedupeKey = buildDedupeKey;
37
+ exports.shouldCaptureOnce = shouldCaptureOnce;
38
+ const fs = __importStar(require("node:fs"));
39
+ const crypto = __importStar(require("node:crypto"));
40
+ const paths_1 = require("../config/paths");
41
+ const TTL_MS = 60_000;
42
+ const MAX_ENTRIES = 200;
43
+ function buildDedupeKey(generationId, prompt) {
44
+ if (generationId && generationId.trim()) {
45
+ return `gen:${generationId.trim()}`;
46
+ }
47
+ const hash = crypto.createHash("sha256").update(prompt).digest("hex").slice(0, 24);
48
+ const bucket = Math.floor(Date.now() / 1000);
49
+ return `hash:${hash}:${bucket}`;
50
+ }
51
+ function shouldCaptureOnce(key, homeDir, now = Date.now()) {
52
+ (0, paths_1.ensureStateDir)(homeDir);
53
+ const filePath = (0, paths_1.getDedupePath)(homeDir);
54
+ const state = readState(filePath);
55
+ prune(state, now);
56
+ if (state.seen[key] != null && now - state.seen[key] < TTL_MS) {
57
+ writeState(filePath, state);
58
+ return false;
59
+ }
60
+ state.seen[key] = now;
61
+ writeState(filePath, state);
62
+ return true;
63
+ }
64
+ function readState(filePath) {
65
+ try {
66
+ if (!fs.existsSync(filePath))
67
+ return { seen: {} };
68
+ const raw = JSON.parse(fs.readFileSync(filePath, "utf8"));
69
+ return { seen: raw.seen && typeof raw.seen === "object" ? raw.seen : {} };
70
+ }
71
+ catch {
72
+ return { seen: {} };
73
+ }
74
+ }
75
+ function writeState(filePath, state) {
76
+ const tmp = `${filePath}.tmp`;
77
+ fs.writeFileSync(tmp, JSON.stringify(state), "utf8");
78
+ fs.renameSync(tmp, filePath);
79
+ }
80
+ function prune(state, now) {
81
+ for (const [k, t] of Object.entries(state.seen)) {
82
+ if (now - t > TTL_MS)
83
+ delete state.seen[k];
84
+ }
85
+ const keys = Object.keys(state.seen);
86
+ if (keys.length <= MAX_ENTRIES)
87
+ return;
88
+ keys
89
+ .sort((a, b) => state.seen[a] - state.seen[b])
90
+ .slice(0, keys.length - MAX_ENTRIES)
91
+ .forEach((k) => delete state.seen[k]);
92
+ }
93
+ //# sourceMappingURL=dedupe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../../src/capture/dedupe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { HookSubmitPayload } from "../types/prompt";
2
+ export interface CaptureResult {
3
+ captured: boolean;
4
+ reason: "ok" | "not_configured" | "disabled" | "paused" | "empty" | "duplicate" | "config_noise" | "error";
5
+ /** Safe for logs — never includes full prompt text. */
6
+ detail?: string;
7
+ /** Queued for background server push (enrolled + sync on). */
8
+ pushQueued?: boolean;
9
+ }
10
+ /**
11
+ * Process a beforeSubmitPrompt payload. Always safe to call; never throws to caller
12
+ * for normal skip paths. Does not log prompt contents.
13
+ */
14
+ export declare function handleBeforeSubmitPrompt(payload: HookSubmitPayload, homeDir?: string): Promise<CaptureResult>;
15
+ /** Hook stdout response — observe only; never block submission. */
16
+ export declare function hookAllowResponse(): {
17
+ continue: true;
18
+ };
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleBeforeSubmitPrompt = handleBeforeSubmitPrompt;
4
+ exports.hookAllowResponse = hookAllowResponse;
5
+ const store_1 = require("../config/store");
6
+ const writer_1 = require("../storage/writer");
7
+ const push_1 = require("../sync/push");
8
+ const dedupe_1 = require("./dedupe");
9
+ const record_1 = require("./record");
10
+ /**
11
+ * Process a beforeSubmitPrompt payload. Always safe to call; never throws to caller
12
+ * for normal skip paths. Does not log prompt contents.
13
+ */
14
+ async function handleBeforeSubmitPrompt(payload, homeDir) {
15
+ try {
16
+ const config = (0, store_1.loadConfig)(homeDir);
17
+ if (!config || !(0, store_1.isConfigured)(config)) {
18
+ return { captured: false, reason: "not_configured" };
19
+ }
20
+ if (config.captureState === "disabled") {
21
+ return { captured: false, reason: "disabled" };
22
+ }
23
+ if (config.captureState === "paused") {
24
+ return { captured: false, reason: "paused" };
25
+ }
26
+ const prompt = typeof payload.prompt === "string" ? payload.prompt : "";
27
+ if ((0, record_1.isEmptyPrompt)(prompt)) {
28
+ return { captured: false, reason: "empty" };
29
+ }
30
+ if ((0, record_1.looksLikeConfigUiNoise)(prompt)) {
31
+ return { captured: false, reason: "config_noise" };
32
+ }
33
+ const key = (0, dedupe_1.buildDedupeKey)(typeof payload.generation_id === "string" ? payload.generation_id : undefined, prompt);
34
+ if (!(0, dedupe_1.shouldCaptureOnce)(key, homeDir)) {
35
+ return { captured: false, reason: "duplicate" };
36
+ }
37
+ const record = (0, record_1.createPromptRecord)(prompt, config.historyName);
38
+ const { fullPath } = (0, store_1.resolveConfigStorage)(config);
39
+ // Local append first — never lose the prompt if the network fails.
40
+ await (0, writer_1.appendRecord)(fullPath, record, config.historyName);
41
+ const push = (0, push_1.schedulePushAfterCapture)(record, homeDir);
42
+ return {
43
+ captured: true,
44
+ reason: "ok",
45
+ detail: record.id,
46
+ pushQueued: push.enqueued,
47
+ };
48
+ }
49
+ catch (err) {
50
+ const message = err instanceof Error ? err.message : "unknown error";
51
+ // Permission / IO errors — never include prompt text
52
+ return { captured: false, reason: "error", detail: message };
53
+ }
54
+ }
55
+ /** Hook stdout response — observe only; never block submission. */
56
+ function hookAllowResponse() {
57
+ return { continue: true };
58
+ }
59
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/capture/handler.ts"],"names":[],"mappings":";;AAoCA,4DAgDC;AAGD,8CAEC;AAzFD,2CAIyB;AACzB,8CAAiD;AACjD,uCAAwD;AAExD,qCAA6D;AAC7D,qCAIkB;AAmBlB;;;GAGG;AACI,KAAK,UAAU,wBAAwB,CAC5C,OAA0B,EAC1B,OAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,kBAAU,EAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAA,oBAAY,EAAC,MAAM,CAAC,EAAE,CAAC;YACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QACvD,CAAC;QACD,IAAI,MAAM,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;YACvC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QACjD,CAAC;QACD,IAAI,MAAM,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAC/C,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,IAAI,IAAA,sBAAa,EAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC9C,CAAC;QACD,IAAI,IAAA,+BAAsB,EAAC,MAAM,CAAC,EAAE,CAAC;YACnC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QACrD,CAAC;QAED,MAAM,GAAG,GAAG,IAAA,uBAAc,EACxB,OAAO,OAAO,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,EAC7E,MAAM,CACP,CAAC;QACF,IAAI,CAAC,IAAA,0BAAiB,EAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;YACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAClD,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,2BAAkB,EAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9D,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,4BAAoB,EAAC,MAAM,CAAC,CAAC;QAClD,mEAAmE;QACnE,MAAM,IAAA,qBAAY,EAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAA,+BAAwB,EAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACvD,OAAO;YACL,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,MAAM,CAAC,EAAE;YACjB,UAAU,EAAE,IAAI,CAAC,QAAQ;SAC1B,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,qDAAqD;QACrD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC/D,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,SAAgB,iBAAiB;IAC/B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { PromptRecord } from "../types/prompt";
2
+ export declare function createPromptRecord(prompt: string, historyName: string, now?: Date): PromptRecord;
3
+ export declare function formatIsoWithOffset(date: Date): string;
4
+ export declare function formatLocalDate(date: Date): string;
5
+ export declare function formatLocalTime(date: Date): string;
6
+ export declare function isEmptyPrompt(prompt: string | undefined | null): boolean;
7
+ /** Heuristic: never treat our own config CLI chatter as a user prompt to store. */
8
+ export declare function looksLikeConfigUiNoise(prompt: string): boolean;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPromptRecord = createPromptRecord;
4
+ exports.formatIsoWithOffset = formatIsoWithOffset;
5
+ exports.formatLocalDate = formatLocalDate;
6
+ exports.formatLocalTime = formatLocalTime;
7
+ exports.isEmptyPrompt = isEmptyPrompt;
8
+ exports.looksLikeConfigUiNoise = looksLikeConfigUiNoise;
9
+ const node_crypto_1 = require("node:crypto");
10
+ function createPromptRecord(prompt, historyName, now = new Date()) {
11
+ const timestamp = formatIsoWithOffset(now);
12
+ const date = formatLocalDate(now);
13
+ const time = formatLocalTime(now);
14
+ return {
15
+ id: (0, node_crypto_1.randomUUID)(),
16
+ date,
17
+ time,
18
+ timestamp,
19
+ application: "Cursor",
20
+ historyName,
21
+ prompt,
22
+ };
23
+ }
24
+ function formatIsoWithOffset(date) {
25
+ const pad = (n, w = 2) => String(Math.abs(n)).padStart(w, "0");
26
+ const y = date.getFullYear();
27
+ const m = pad(date.getMonth() + 1);
28
+ const d = pad(date.getDate());
29
+ const h = pad(date.getHours());
30
+ const min = pad(date.getMinutes());
31
+ const s = pad(date.getSeconds());
32
+ const offsetMin = -date.getTimezoneOffset();
33
+ const sign = offsetMin >= 0 ? "+" : "-";
34
+ const oh = pad(Math.floor(Math.abs(offsetMin) / 60));
35
+ const om = pad(Math.abs(offsetMin) % 60);
36
+ return `${y}-${m}-${d}T${h}:${min}:${s}${sign}${oh}:${om}`;
37
+ }
38
+ function formatLocalDate(date) {
39
+ const pad = (n) => String(n).padStart(2, "0");
40
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
41
+ }
42
+ function formatLocalTime(date) {
43
+ const pad = (n) => String(n).padStart(2, "0");
44
+ return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
45
+ }
46
+ function isEmptyPrompt(prompt) {
47
+ return !prompt || !prompt.trim();
48
+ }
49
+ /** Heuristic: never treat our own config CLI chatter as a user prompt to store. */
50
+ function looksLikeConfigUiNoise(prompt) {
51
+ const t = prompt.trim();
52
+ if (t.startsWith("__PROMPT_HISTORY_INTERNAL__"))
53
+ return true;
54
+ return false;
55
+ }
56
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../src/capture/record.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};