@supersession/sup 0.1.3 → 0.1.5
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 +6 -3
- package/dist/cli.js +92 -31
- package/dist/cli.js.map +1 -1
- package/dist/cloud.d.ts +11 -1
- package/dist/cloud.js +6 -1
- package/dist/cloud.js.map +1 -1
- package/dist/discover.d.ts +19 -1
- package/dist/discover.js +90 -3
- package/dist/discover.js.map +1 -1
- package/dist/distill/template.d.ts +9 -0
- package/dist/distill/template.js +61 -4
- package/dist/distill/template.js.map +1 -1
- package/dist/engine.d.ts +1 -1
- package/dist/engine.js +5 -6
- package/dist/engine.js.map +1 -1
- package/dist/facts.d.ts +24 -0
- package/dist/facts.js +68 -0
- package/dist/facts.js.map +1 -0
- package/dist/nsf.d.ts +2 -0
- package/dist/parsers/codex.d.ts +25 -0
- package/dist/parsers/codex.js +212 -0
- package/dist/parsers/codex.js.map +1 -0
- package/dist/parsers/cursor.d.ts +33 -0
- package/dist/parsers/cursor.js +224 -0
- package/dist/parsers/cursor.js.map +1 -0
- package/dist/redact.d.ts +12 -0
- package/dist/redact.js +15 -0
- package/dist/redact.js.map +1 -1
- package/dist/tools.js +31 -1
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/distill/template.js
CHANGED
|
@@ -70,23 +70,64 @@ export function groundFiles(session) {
|
|
|
70
70
|
git: git.get(path),
|
|
71
71
|
}));
|
|
72
72
|
}
|
|
73
|
-
|
|
73
|
+
// Read-only exploration/inspection tools. A handoff wants the commands that
|
|
74
|
+
// CHANGED or VERIFIED state (build, test, migrate, deploy, git), not the
|
|
75
|
+
// agent's spelunking (grep/find/gh api/sqlite SELECT) — that noise buries the
|
|
76
|
+
// signal an agent actually needs to continue.
|
|
77
|
+
const NOISE_HEADS = new Set([
|
|
78
|
+
"cd", "ls", "pwd", "cat", "echo", "printf", "clear", "which", "whoami", "env", "export",
|
|
79
|
+
"grep", "egrep", "fgrep", "rg", "ripgrep", "ag", "find", "fd", "locate",
|
|
80
|
+
"head", "tail", "less", "more", "tree", "wc", "du", "df", "stat", "file",
|
|
81
|
+
"sed", "awk", "jq", "yq", "sort", "uniq", "cut", "column", "xxd", "od",
|
|
82
|
+
"sqlite3", "gh", "dig", "ping", "host", "nslookup", "man", "help", "true", "false",
|
|
83
|
+
]);
|
|
84
|
+
/** The verb of a single command segment: drop `VAR=val ` prefixes and redirects. */
|
|
85
|
+
function segmentHead(seg) {
|
|
86
|
+
// Trailing \s* (not \s+) so a quoted value is fully consumed even when the
|
|
87
|
+
// assignment is the whole segment — otherwise \S+ backtracks into the quote.
|
|
88
|
+
const stripped = seg.replace(/^(?:\w+=(?:"[^"]*"|'[^']*'|\S+)\s*)+/, "").trim();
|
|
89
|
+
return stripped.split(/\s+/)[0] ?? "";
|
|
90
|
+
}
|
|
91
|
+
/** Inline code-eval invocations are exploration, not project commands. */
|
|
92
|
+
function isInlineEval(cmd) {
|
|
93
|
+
return /\b(?:node|python3?|ruby|deno|bun)\b[^\n]*\s(?:-e|--eval|-c|--input-type)\b/.test(cmd);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A command is meaningful (worth a handoff) only if, after splitting compound
|
|
97
|
+
* one-liners on shell separators, at least one segment is a real verb — not a
|
|
98
|
+
* bare `VAR=val` assignment and not a read-only exploration tool. This kills
|
|
99
|
+
* `DB=…; sqlite3 …; echo …` spelunking while keeping `pnpm test | tail`.
|
|
100
|
+
*/
|
|
101
|
+
function isMeaningfulCommand(cmd) {
|
|
102
|
+
if (isInlineEval(cmd))
|
|
103
|
+
return false;
|
|
104
|
+
// Split on command separators only — NOT single `|`. A pipe's first command
|
|
105
|
+
// is the primary one (its head decides), and splitting on `|` would shred
|
|
106
|
+
// grep/regex patterns like "a\|b" into verb-looking fragments.
|
|
107
|
+
const segments = cmd.split(/&&|\|\||;/);
|
|
108
|
+
return segments.some((seg) => {
|
|
109
|
+
const head = segmentHead(seg);
|
|
110
|
+
return head.length > 0 && !head.includes("=") && !NOISE_HEADS.has(head);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Notable, deduped shell commands (skip read-only navigation/inspection). */
|
|
74
114
|
function keyCommands(session) {
|
|
75
115
|
const seen = new Set();
|
|
76
116
|
const out = [];
|
|
77
|
-
const trivial = /^(cd|ls|pwd|cat|echo|clear|which|whoami)\b/;
|
|
78
117
|
for (const turn of session.turns) {
|
|
79
118
|
for (const a of turn.actions) {
|
|
80
119
|
if (a.kind !== "run" || !a.command)
|
|
81
120
|
continue;
|
|
82
121
|
const cmd = a.command.split("\n")[0].trim();
|
|
83
|
-
if (!cmd ||
|
|
122
|
+
if (!cmd || seen.has(cmd))
|
|
123
|
+
continue;
|
|
124
|
+
if (!isMeaningfulCommand(cmd))
|
|
84
125
|
continue;
|
|
85
126
|
seen.add(cmd);
|
|
86
127
|
out.push(cmd);
|
|
87
128
|
}
|
|
88
129
|
}
|
|
89
|
-
return out.slice(0,
|
|
130
|
+
return out.slice(0, 15);
|
|
90
131
|
}
|
|
91
132
|
function firstLines(text, n) {
|
|
92
133
|
return text.split("\n").slice(0, n).join("\n").trim();
|
|
@@ -103,6 +144,22 @@ function inferNextStep(turns) {
|
|
|
103
144
|
return firstLines(lastUser.text, 3);
|
|
104
145
|
return "(no pending user request — continue the last thread)";
|
|
105
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* One-line title + short summary for a session, used as cloud/list metadata.
|
|
149
|
+
* Prefers the source tool's own session name (Cursor names chats); otherwise
|
|
150
|
+
* the inferred goal. Same grounded-only rules as the rest of template distill.
|
|
151
|
+
*/
|
|
152
|
+
export function sessionHeadline(session) {
|
|
153
|
+
const clip = (s, n) => {
|
|
154
|
+
const one = s.split("\n")[0].trim();
|
|
155
|
+
return one.length > n ? `${one.slice(0, n - 1)}…` : one;
|
|
156
|
+
};
|
|
157
|
+
const title = session.provenance.title?.trim() || inferGoal(session.turns);
|
|
158
|
+
return {
|
|
159
|
+
title: clip(title, 80),
|
|
160
|
+
summary: clip(summarizeState(session.turns), 200),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
106
163
|
export function distillTemplate(session, opts = {}) {
|
|
107
164
|
const recentN = opts.recentTurns ?? DEFAULT_RECENT;
|
|
108
165
|
const recentTurns = session.turns.slice(-recentN);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/distill/template.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/distill/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AA6CjD,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,0EAA0E;AAC1E,SAAS,SAAS,CAAC,KAAgB;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QACnC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QACpB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,0DAA0D;QAC1D,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,SAAS;QAC3D,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,qCAAqC,CAAC;AAC/C,CAAC;AAED,oFAAoF;AACpF,SAAS,SAAS,CAAC,GAAuB,EAAE,KAAe;IACzD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE;YACzD,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;QACH,4DAA4D;QAC5D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;QACxC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/B,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACrB,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACvD,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAmB;IAC7C,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACpE,OAAO,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI;QACJ,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC;QACxB,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;KACnB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,4EAA4E;AAC5E,yEAAyE;AACzE,8EAA8E;AAC9E,8CAA8C;AAC9C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ;IACvF,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ;IACvE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM;IACxE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI;IACtE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;CACnF,CAAC,CAAC;AAEH,oFAAoF;AACpF,SAAS,WAAW,CAAC,GAAW;IAC9B,2EAA2E;IAC3E,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,sCAAsC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAChF,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,0EAA0E;AAC1E,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,4EAA4E,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChG,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,GAAW;IACtC,IAAI,YAAY,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,4EAA4E;IAC5E,0EAA0E;IAC1E,+DAA+D;IAC/D,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACxC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,SAAS,WAAW,CAAC,OAAmB;IACtC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,SAAS;YAC7C,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;YAC7C,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YACpC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC;gBAAE,SAAS;YACxC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,CAAS;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,cAAc,CAAC,KAAgB;IACtC,MAAM,aAAa,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IACzF,IAAI,aAAa;QAAE,OAAO,UAAU,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5D,OAAO,4CAA4C,CAAC;AACtD,CAAC;AAED,SAAS,aAAa,CAAC,KAAgB;IACrC,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/E,IAAI,QAAQ;QAAE,OAAO,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAClD,OAAO,sDAAsD,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAAmB;IACjD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE;QACpC,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC;QACrC,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1D,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3E,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC;KAClD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAmB,EAAE,OAAuB,EAAE;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,IAAI,cAAc,CAAC;IACnD,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAE/E,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC;QAC9B,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC;QAC3B,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC;QAC9B,WAAW;QACX,YAAY,EAAE,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC;QAC3C,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;QACtC,QAAQ,EAAE;YACR,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM;YAChC,aAAa,EAAE,WAAW,CAAC,MAAM;YACjC,eAAe;YACf,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAC7E,eAAe,EAAE,IAAI,CAAC,eAAe,IAAI,CAAC;SAC3C;KACF,CAAC;AACJ,CAAC"}
|
package/dist/engine.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { type Brief } from "./distill/template.js";
|
|
|
9
9
|
import type { NsfSession } from "./nsf.js";
|
|
10
10
|
export declare class NoSessionError extends Error {
|
|
11
11
|
}
|
|
12
|
-
/** Parse the
|
|
12
|
+
/** Parse the newest session (any supported tool) for a directory, or throw. */
|
|
13
13
|
export declare function requireSession(cwd: string): NsfSession;
|
|
14
14
|
export interface DistillResult {
|
|
15
15
|
brief: Brief;
|
package/dist/engine.js
CHANGED
|
@@ -5,19 +5,18 @@
|
|
|
5
5
|
* over stdout, so a stray console.log would corrupt the protocol. Callers get
|
|
6
6
|
* structured results and decide how (or whether) to print them.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
9
|
-
import { parseClaudeCode } from "./parsers/claude-code.js";
|
|
8
|
+
import { findLatestSession } from "./discover.js";
|
|
10
9
|
import { redactSession } from "./redact.js";
|
|
11
10
|
import { distillTemplate } from "./distill/template.js";
|
|
12
11
|
import { distillSmart } from "./distill/smart.js";
|
|
13
12
|
export class NoSessionError extends Error {
|
|
14
13
|
}
|
|
15
|
-
/** Parse the
|
|
14
|
+
/** Parse the newest session (any supported tool) for a directory, or throw. */
|
|
16
15
|
export function requireSession(cwd) {
|
|
17
|
-
const found =
|
|
16
|
+
const found = findLatestSession(cwd);
|
|
18
17
|
if (!found)
|
|
19
|
-
throw new NoSessionError(`No
|
|
20
|
-
const parsed =
|
|
18
|
+
throw new NoSessionError(`No session found for ${cwd} (looked for Claude Code, Codex, and Cursor sessions).`);
|
|
19
|
+
const parsed = found.parse();
|
|
21
20
|
if (parsed.turns.length === 0)
|
|
22
21
|
throw new NoSessionError("Session file had no usable turns.");
|
|
23
22
|
return parsed;
|
package/dist/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAc,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,OAAO,cAAe,SAAQ,KAAK;CAAG;AAE5C,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QACR,MAAM,IAAI,cAAc,CACtB,wBAAwB,GAAG,wDAAwD,CACpF,CAAC;IACJ,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;IAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,cAAc,CAAC,mCAAmC,CAAC,CAAC;IAC7F,OAAO,MAAM,CAAC;AAChB,CAAC;AASD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAe,EACf,aAAsB;IAEtB,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,EAAE,KAAK,EAAE,eAAe,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACxF,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IACzF,MAAM,IAAI,GAAG,OAAO;QAClB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,KAAK;YACL,CAAC,CAAC,8BAA8B,KAAK,0BAA0B;YAC/D,CAAC,CAAC,wGAAwG,CAAC;IAC/G,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC"}
|
package/dist/facts.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sup facts` — extract the nuggets people scroll transcripts hunting for:
|
|
3
|
+
* credentials the agent generated, URLs and ports, and credential-ish prose
|
|
4
|
+
* lines ("your test login is admin@x.com / hunter2").
|
|
5
|
+
*
|
|
6
|
+
* LOCAL ONLY. This module is the mirror image of redact.ts: redaction strips
|
|
7
|
+
* secrets before anything leaves the machine; facts surfaces them ON the
|
|
8
|
+
* machine. Nothing here is ever pushed, written to a brief, or logged remotely.
|
|
9
|
+
*/
|
|
10
|
+
import type { NsfSession } from "./nsf.js";
|
|
11
|
+
export interface Fact {
|
|
12
|
+
/** What was found (secret value, URL, or a verbatim prose line). */
|
|
13
|
+
value: string;
|
|
14
|
+
/** Category detail, e.g. "github-token" or "credential mention". */
|
|
15
|
+
label: string;
|
|
16
|
+
/** 1-based turn number, so the user can find it in context. */
|
|
17
|
+
turn: number;
|
|
18
|
+
}
|
|
19
|
+
export interface SessionFacts {
|
|
20
|
+
secrets: Fact[];
|
|
21
|
+
urls: Fact[];
|
|
22
|
+
credentialLines: Fact[];
|
|
23
|
+
}
|
|
24
|
+
export declare function extractFacts(session: NsfSession): SessionFacts;
|
package/dist/facts.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sup facts` — extract the nuggets people scroll transcripts hunting for:
|
|
3
|
+
* credentials the agent generated, URLs and ports, and credential-ish prose
|
|
4
|
+
* lines ("your test login is admin@x.com / hunter2").
|
|
5
|
+
*
|
|
6
|
+
* LOCAL ONLY. This module is the mirror image of redact.ts: redaction strips
|
|
7
|
+
* secrets before anything leaves the machine; facts surfaces them ON the
|
|
8
|
+
* machine. Nothing here is ever pushed, written to a brief, or logged remotely.
|
|
9
|
+
*/
|
|
10
|
+
import { findSecrets } from "./redact.js";
|
|
11
|
+
const URL_RE = /\bhttps?:\/\/[^\s)"'`<>\]]+/g;
|
|
12
|
+
// Bare host:port the way dev servers get mentioned ("listening on localhost:3000").
|
|
13
|
+
// The lookbehind keeps it from double-reporting the host inside an http:// URL.
|
|
14
|
+
const HOSTPORT_RE = /(?<![/.\w])(?:localhost|127\.0\.0\.1|0\.0\.0\.0):\d{2,5}\b/g;
|
|
15
|
+
// A credential MENTION worth surfacing pairs a credential keyword with an
|
|
16
|
+
// actual value — not just prose that discusses credentials. The value signal
|
|
17
|
+
// must be an email or an explicit `keyword: value` / `keyword=value` pair;
|
|
18
|
+
// backticks alone are too common in prose to count. This keeps "test login:
|
|
19
|
+
// admin@x.com / Passw0rd!" while dropping "the credentials/tokens problem" and
|
|
20
|
+
// "OAuth login (commit `abc123`)".
|
|
21
|
+
const CRED_KEYWORD_RE = /\b(password|passwd|username|user ?name|login|credentials?|api ?key|access ?token)\b/i;
|
|
22
|
+
const EMAIL_RE = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/;
|
|
23
|
+
const KEYVAL_RE = /\b(pass\w*|pwd|user\w*|login|token|key|secret|cred\w*)\b\s*[:=]\s*\S{3,}/i;
|
|
24
|
+
function isCredentialMention(line) {
|
|
25
|
+
if (!CRED_KEYWORD_RE.test(line))
|
|
26
|
+
return false;
|
|
27
|
+
return EMAIL_RE.test(line) || KEYVAL_RE.test(line);
|
|
28
|
+
}
|
|
29
|
+
/** Dedupe by value, keeping the first (earliest turn) occurrence. */
|
|
30
|
+
function dedupe(facts) {
|
|
31
|
+
const seen = new Set();
|
|
32
|
+
return facts.filter((f) => (seen.has(f.value) ? false : (seen.add(f.value), true)));
|
|
33
|
+
}
|
|
34
|
+
export function extractFacts(session) {
|
|
35
|
+
const secrets = [];
|
|
36
|
+
const urls = [];
|
|
37
|
+
const credentialLines = [];
|
|
38
|
+
session.turns.forEach((t, i) => {
|
|
39
|
+
const turn = i + 1;
|
|
40
|
+
const texts = [t.text, ...t.actions.map((a) => a.command ?? "")].filter(Boolean);
|
|
41
|
+
for (const text of texts) {
|
|
42
|
+
for (const hit of findSecrets(text))
|
|
43
|
+
secrets.push({ value: hit.value, label: hit.name, turn });
|
|
44
|
+
for (const m of text.matchAll(URL_RE)) {
|
|
45
|
+
// Trailing punctuation is sentence noise, not part of the URL.
|
|
46
|
+
urls.push({ value: m[0].replace(/[.,;:!?]+$/, ""), label: "url", turn });
|
|
47
|
+
}
|
|
48
|
+
for (const m of text.matchAll(HOSTPORT_RE))
|
|
49
|
+
urls.push({ value: m[0], label: "port", turn });
|
|
50
|
+
}
|
|
51
|
+
// Credential mentions: only assistant prose (that's where "your login is…"
|
|
52
|
+
// lives), line-by-line so the printed fact reads in context.
|
|
53
|
+
if (t.role === "assistant" && t.text) {
|
|
54
|
+
for (const line of t.text.split("\n")) {
|
|
55
|
+
const trimmed = line.trim();
|
|
56
|
+
if (trimmed && isCredentialMention(trimmed)) {
|
|
57
|
+
credentialLines.push({ value: trimmed.slice(0, 160), label: "credential mention", turn });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
secrets: dedupe(secrets),
|
|
64
|
+
urls: dedupe(urls),
|
|
65
|
+
credentialLines: dedupe(credentialLines),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facts.js","sourceRoot":"","sources":["../src/facts.ts"],"names":[],"mappings":"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"}
|
package/dist/nsf.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface NsfProvenance {
|
|
|
40
40
|
tool: string;
|
|
41
41
|
/** The tool's native session id. */
|
|
42
42
|
sessionId?: string;
|
|
43
|
+
/** Human title the source tool gave this session (e.g. Cursor's chat name). */
|
|
44
|
+
title?: string;
|
|
43
45
|
/** Absolute working directory the session ran in. */
|
|
44
46
|
cwd?: string;
|
|
45
47
|
/** Git branch recorded at capture time, if any. */
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI parser: rollout JSONL -> NSF.
|
|
3
|
+
*
|
|
4
|
+
* Grounded in the upstream format (verified 2026-07-15 against openai/codex
|
|
5
|
+
* codex-rs rollout recorder test fixtures), not a guess:
|
|
6
|
+
* - Files live at ~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl
|
|
7
|
+
* - Each line: { timestamp, type, payload } (+ optional ordinal)
|
|
8
|
+
* - type "session_meta": payload has session_id/id, cwd, source; sibling
|
|
9
|
+
* `git` object may carry the branch.
|
|
10
|
+
* - type "response_item": payload is tagged by payload.type:
|
|
11
|
+
* "message" { role, content: [{type:"input_text"|"output_text", text}] }
|
|
12
|
+
* "function_call" { name, arguments (JSON string), call_id }
|
|
13
|
+
* "local_shell_call" { status, action: { command: [...] } }
|
|
14
|
+
* "reasoning", "function_call_output", ... -> gaps
|
|
15
|
+
* - type "event_msg" duplicates messages as UI events -> counted as gaps so
|
|
16
|
+
* turns aren't doubled.
|
|
17
|
+
* - type "compacted" is Codex's lossy in-place summarization -> a scar.
|
|
18
|
+
*/
|
|
19
|
+
import type { NsfSession } from "../nsf.js";
|
|
20
|
+
export declare const CODEX_TOOL_ID = "codex";
|
|
21
|
+
/**
|
|
22
|
+
* Parse a Codex rollout JSONL file into NSF.
|
|
23
|
+
* @param filePath absolute path to the rollout-*.jsonl transcript.
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseCodex(filePath: string): NsfSession;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI parser: rollout JSONL -> NSF.
|
|
3
|
+
*
|
|
4
|
+
* Grounded in the upstream format (verified 2026-07-15 against openai/codex
|
|
5
|
+
* codex-rs rollout recorder test fixtures), not a guess:
|
|
6
|
+
* - Files live at ~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl
|
|
7
|
+
* - Each line: { timestamp, type, payload } (+ optional ordinal)
|
|
8
|
+
* - type "session_meta": payload has session_id/id, cwd, source; sibling
|
|
9
|
+
* `git` object may carry the branch.
|
|
10
|
+
* - type "response_item": payload is tagged by payload.type:
|
|
11
|
+
* "message" { role, content: [{type:"input_text"|"output_text", text}] }
|
|
12
|
+
* "function_call" { name, arguments (JSON string), call_id }
|
|
13
|
+
* "local_shell_call" { status, action: { command: [...] } }
|
|
14
|
+
* "reasoning", "function_call_output", ... -> gaps
|
|
15
|
+
* - type "event_msg" duplicates messages as UI events -> counted as gaps so
|
|
16
|
+
* turns aren't doubled.
|
|
17
|
+
* - type "compacted" is Codex's lossy in-place summarization -> a scar.
|
|
18
|
+
*/
|
|
19
|
+
import { readFileSync } from "node:fs";
|
|
20
|
+
import { NSF_VERSION } from "../nsf.js";
|
|
21
|
+
export const CODEX_TOOL_ID = "codex";
|
|
22
|
+
/** Codex injects wrapped context as fake user messages; they aren't the user. */
|
|
23
|
+
const INJECTED_USER_RE = /^<(user_instructions|environment_context|ENVIRONMENT_CONTEXT)/i;
|
|
24
|
+
function contentText(content) {
|
|
25
|
+
if (!Array.isArray(content))
|
|
26
|
+
return "";
|
|
27
|
+
return content
|
|
28
|
+
.map((c) => {
|
|
29
|
+
const o = c;
|
|
30
|
+
return (o?.type === "input_text" || o?.type === "output_text") && typeof o.text === "string"
|
|
31
|
+
? o.text
|
|
32
|
+
: "";
|
|
33
|
+
})
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.join("\n\n")
|
|
36
|
+
.trim();
|
|
37
|
+
}
|
|
38
|
+
/** Best-effort shell command out of function_call arguments / shell action. */
|
|
39
|
+
function commandFrom(args) {
|
|
40
|
+
if (typeof args !== "object" || args === null)
|
|
41
|
+
return undefined;
|
|
42
|
+
const cmd = args.command ?? args.cmd;
|
|
43
|
+
if (typeof cmd === "string")
|
|
44
|
+
return cmd;
|
|
45
|
+
if (Array.isArray(cmd))
|
|
46
|
+
return cmd.filter((x) => typeof x === "string").join(" ");
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/** Paths named in an apply_patch envelope ("*** Update File: src/x.ts" etc). */
|
|
50
|
+
function patchPaths(patch) {
|
|
51
|
+
const out = [];
|
|
52
|
+
for (const m of patch.matchAll(/^\*\*\* (?:Update|Add|Delete) File: (.+)$/gm)) {
|
|
53
|
+
out.push(m[1].trim());
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
function functionCallActions(name, rawArguments) {
|
|
58
|
+
let args = rawArguments;
|
|
59
|
+
if (typeof rawArguments === "string") {
|
|
60
|
+
try {
|
|
61
|
+
args = JSON.parse(rawArguments);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
args = undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const o = (typeof args === "object" && args !== null ? args : {});
|
|
68
|
+
if (name === "apply_patch") {
|
|
69
|
+
const patch = typeof o.input === "string" ? o.input : typeof rawArguments === "string" ? rawArguments : "";
|
|
70
|
+
const paths = patchPaths(patch);
|
|
71
|
+
if (paths.length === 0)
|
|
72
|
+
return [{ kind: "edit", rawName: name }];
|
|
73
|
+
return paths.map((path) => ({ kind: "edit", rawName: name, path }));
|
|
74
|
+
}
|
|
75
|
+
const path = typeof o.path === "string" ? o.path : typeof o.file_path === "string" ? o.file_path : undefined;
|
|
76
|
+
const command = commandFrom(o);
|
|
77
|
+
const kind = /shell|exec/.test(name)
|
|
78
|
+
? "run"
|
|
79
|
+
: /read|view/.test(name)
|
|
80
|
+
? "read"
|
|
81
|
+
: /write|create/.test(name)
|
|
82
|
+
? "write"
|
|
83
|
+
: /search|grep|glob|find/.test(name)
|
|
84
|
+
? "search"
|
|
85
|
+
: "other";
|
|
86
|
+
return [{ kind, rawName: name, path, command }];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Parse a Codex rollout JSONL file into NSF.
|
|
90
|
+
* @param filePath absolute path to the rollout-*.jsonl transcript.
|
|
91
|
+
*/
|
|
92
|
+
export function parseCodex(filePath) {
|
|
93
|
+
const raw = readFileSync(filePath, "utf8");
|
|
94
|
+
const turns = [];
|
|
95
|
+
const filesSeen = new Set();
|
|
96
|
+
const filesOrdered = [];
|
|
97
|
+
const gapCounts = new Map();
|
|
98
|
+
const addGap = (reason) => gapCounts.set(reason, (gapCounts.get(reason) ?? 0) + 1);
|
|
99
|
+
const provenance = {
|
|
100
|
+
tool: CODEX_TOOL_ID,
|
|
101
|
+
rawBytes: Buffer.byteLength(raw, "utf8"),
|
|
102
|
+
};
|
|
103
|
+
let compactions = 0;
|
|
104
|
+
// function_call actions attach to the pending assistant turn (Codex records
|
|
105
|
+
// calls as separate lines, unlike Claude Code's in-message blocks).
|
|
106
|
+
let pendingActions = [];
|
|
107
|
+
const flushActions = () => {
|
|
108
|
+
if (pendingActions.length === 0)
|
|
109
|
+
return;
|
|
110
|
+
turns.push({ role: "assistant", text: "", actions: pendingActions });
|
|
111
|
+
pendingActions = [];
|
|
112
|
+
};
|
|
113
|
+
for (const line of raw.split("\n")) {
|
|
114
|
+
const trimmed = line.trim();
|
|
115
|
+
if (!trimmed)
|
|
116
|
+
continue;
|
|
117
|
+
let rec;
|
|
118
|
+
try {
|
|
119
|
+
rec = JSON.parse(trimmed);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
addGap("unparseable line");
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const payload = rec.payload ?? {};
|
|
126
|
+
switch (rec.type) {
|
|
127
|
+
case "session_meta": {
|
|
128
|
+
const id = payload.id ?? payload.session_id;
|
|
129
|
+
provenance.sessionId ??= typeof id === "string" ? id : undefined;
|
|
130
|
+
provenance.cwd ??= typeof payload.cwd === "string" ? payload.cwd : undefined;
|
|
131
|
+
const git = rec.git ?? payload.git;
|
|
132
|
+
const branch = git?.branch;
|
|
133
|
+
provenance.gitBranch ??= typeof branch === "string" ? branch : undefined;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "compacted":
|
|
137
|
+
compactions++;
|
|
138
|
+
addGap("compaction/summary event");
|
|
139
|
+
break;
|
|
140
|
+
case "response_item": {
|
|
141
|
+
const ptype = payload.type;
|
|
142
|
+
if (ptype === "message") {
|
|
143
|
+
const role = payload.role === "user" ? "user" : payload.role === "assistant" ? "assistant" : undefined;
|
|
144
|
+
const text = contentText(payload.content);
|
|
145
|
+
if (!role || !text) {
|
|
146
|
+
addGap("empty turn");
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
if (role === "user" && INJECTED_USER_RE.test(text)) {
|
|
150
|
+
addGap("injected context message");
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
if (role === "assistant" && pendingActions.length > 0) {
|
|
154
|
+
// Attach the actions Codex logged since the last prose turn.
|
|
155
|
+
turns.push({
|
|
156
|
+
role,
|
|
157
|
+
text,
|
|
158
|
+
actions: pendingActions,
|
|
159
|
+
timestamp: rec.timestamp ? Date.parse(rec.timestamp) : undefined,
|
|
160
|
+
});
|
|
161
|
+
pendingActions = [];
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
flushActions();
|
|
165
|
+
turns.push({
|
|
166
|
+
role,
|
|
167
|
+
text,
|
|
168
|
+
actions: [],
|
|
169
|
+
timestamp: rec.timestamp ? Date.parse(rec.timestamp) : undefined,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (ptype === "function_call") {
|
|
174
|
+
const name = typeof payload.name === "string" ? payload.name : "unknown";
|
|
175
|
+
const actions = functionCallActions(name, payload.arguments);
|
|
176
|
+
pendingActions.push(...actions);
|
|
177
|
+
for (const a of actions) {
|
|
178
|
+
if (a.path && !filesSeen.has(a.path)) {
|
|
179
|
+
filesSeen.add(a.path);
|
|
180
|
+
filesOrdered.push(a.path);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (ptype === "local_shell_call") {
|
|
185
|
+
const command = commandFrom(payload.action);
|
|
186
|
+
pendingActions.push({ kind: "run", rawName: "local_shell_call", command });
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
addGap(`non-conversational response item (${String(ptype ?? "unknown")})`);
|
|
190
|
+
}
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "event_msg":
|
|
194
|
+
// Duplicates of message content as UI events — skip to avoid doubled turns.
|
|
195
|
+
addGap("ui event record");
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
addGap(`non-message record (${rec.type ?? "unknown"})`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
flushActions();
|
|
202
|
+
provenance.compactions = compactions;
|
|
203
|
+
const gaps = [...gapCounts.entries()].map(([reason, count]) => ({ reason, count }));
|
|
204
|
+
return {
|
|
205
|
+
nsfVersion: NSF_VERSION,
|
|
206
|
+
provenance,
|
|
207
|
+
turns,
|
|
208
|
+
filesTouched: filesOrdered,
|
|
209
|
+
gaps,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/parsers/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor parser: global state.vscdb (SQLite) -> NSF.
|
|
3
|
+
*
|
|
4
|
+
* Grounded in the REAL on-disk schema (verified 2026-07-15 against a live
|
|
5
|
+
* Cursor install), not a guess:
|
|
6
|
+
* - DB: <appdata>/Cursor/User/globalStorage/state.vscdb
|
|
7
|
+
* - Table `composerHeaders` (composerId, workspaceId, lastUpdatedAt,
|
|
8
|
+
* isSubagent, recency, value JSON) — value carries `name` (the chat title),
|
|
9
|
+
* `workspaceIdentifier.uri.fsPath` (cwd) and `trackedGitRepos[].branches`.
|
|
10
|
+
* - Table `cursorDiskKV`:
|
|
11
|
+
* key `composerData:<composerId>` -> { fullConversationHeadersOnly:
|
|
12
|
+
* [{bubbleId, type}] } — the ordered conversation.
|
|
13
|
+
* key `bubbleId:<composerId>:<bubbleId>` -> the message:
|
|
14
|
+
* { type: 1(user)|2(assistant), text, createdAt (ISO),
|
|
15
|
+
* toolFormerData?: { name, rawArgs, status } }.
|
|
16
|
+
*
|
|
17
|
+
* Uses node:sqlite (built-in, Node >= 22.5) — read-only, no native deps. The
|
|
18
|
+
* DB can be multi-GB, so bubbles are fetched by key, never table-scanned.
|
|
19
|
+
*/
|
|
20
|
+
import type { NsfSession } from "../nsf.js";
|
|
21
|
+
export declare const CURSOR_TOOL_ID = "cursor";
|
|
22
|
+
export declare function cursorDbPath(): string;
|
|
23
|
+
/** Newest non-subagent Cursor conversation for a working directory, if any. */
|
|
24
|
+
export declare function findCursorComposer(cwd: string): {
|
|
25
|
+
composerId: string;
|
|
26
|
+
mtimeMs: number;
|
|
27
|
+
} | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Parse one Cursor conversation into NSF.
|
|
30
|
+
* @param dbPath absolute path to Cursor's global state.vscdb
|
|
31
|
+
* @param composerId the conversation to parse (from findCursorComposer)
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseCursor(dbPath: string, composerId: string): NsfSession;
|