@intentic/iq 1.325.0 → 1.327.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 (59) hide show
  1. package/README.md +59 -4
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +7 -3
  4. package/dist/app.js.map +1 -1
  5. package/dist/commands/sessions/sessions.routes.js +1 -1
  6. package/dist/commands/sessions/sessions.routes.js.map +1 -1
  7. package/dist/recall/fleet/conversations.d.ts +7 -0
  8. package/dist/recall/fleet/conversations.d.ts.map +1 -0
  9. package/dist/recall/fleet/conversations.js +48 -0
  10. package/dist/recall/fleet/conversations.js.map +1 -0
  11. package/dist/recall/fork/fork-point.d.ts +10 -0
  12. package/dist/recall/fork/fork-point.d.ts.map +1 -0
  13. package/dist/recall/fork/fork-point.js +74 -0
  14. package/dist/recall/fork/fork-point.js.map +1 -0
  15. package/dist/recall/fork/fork.d.ts +15 -0
  16. package/dist/recall/fork/fork.d.ts.map +1 -0
  17. package/dist/recall/fork/fork.js +108 -0
  18. package/dist/recall/fork/fork.js.map +1 -0
  19. package/dist/recall/ingest/ingest.d.ts +13 -0
  20. package/dist/recall/ingest/ingest.d.ts.map +1 -0
  21. package/dist/recall/ingest/ingest.js +180 -0
  22. package/dist/recall/ingest/ingest.js.map +1 -0
  23. package/dist/recall/rank/files.d.ts +26 -0
  24. package/dist/recall/rank/files.d.ts.map +1 -0
  25. package/dist/recall/rank/files.js +88 -0
  26. package/dist/recall/rank/files.js.map +1 -0
  27. package/dist/recall/rank/grab.d.ts +25 -0
  28. package/dist/recall/rank/grab.d.ts.map +1 -0
  29. package/dist/recall/rank/grab.js +74 -0
  30. package/dist/recall/rank/grab.js.map +1 -0
  31. package/dist/recall/rank/match.d.ts +18 -0
  32. package/dist/recall/rank/match.d.ts.map +1 -0
  33. package/dist/recall/rank/match.js +122 -0
  34. package/dist/recall/rank/match.js.map +1 -0
  35. package/dist/recall/rank/terms.d.ts +4 -0
  36. package/dist/recall/rank/terms.d.ts.map +1 -0
  37. package/dist/recall/rank/terms.js +25 -0
  38. package/dist/recall/rank/terms.js.map +1 -0
  39. package/dist/recall/recall.d.ts +52 -0
  40. package/dist/recall/recall.d.ts.map +1 -0
  41. package/dist/recall/recall.js +86 -0
  42. package/dist/recall/recall.js.map +1 -0
  43. package/dist/recall/store/db.d.ts +3 -0
  44. package/dist/recall/store/db.d.ts.map +1 -0
  45. package/dist/recall/store/db.js +91 -0
  46. package/dist/recall/store/db.js.map +1 -0
  47. package/dist/recall/transcript/line-reader.d.ts +6 -0
  48. package/dist/recall/transcript/line-reader.d.ts.map +1 -0
  49. package/dist/recall/transcript/line-reader.js +36 -0
  50. package/dist/recall/transcript/line-reader.js.map +1 -0
  51. package/dist/recall/transcript/lines.d.ts +22 -0
  52. package/dist/recall/transcript/lines.d.ts.map +1 -0
  53. package/dist/recall/transcript/lines.js +134 -0
  54. package/dist/recall/transcript/lines.js.map +1 -0
  55. package/dist/recall/transcript/slug.d.ts +3 -0
  56. package/dist/recall/transcript/slug.d.ts.map +1 -0
  57. package/dist/recall/transcript/slug.js +5 -0
  58. package/dist/recall/transcript/slug.js.map +1 -0
  59. package/package.json +17 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terms.js","sourceRoot":"","sources":["../../../src/recall/rank/terms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAK5D,MAAM,aAAa,GAAwB,IAAI,GAAG,CAC9C;IACI,gDAAgD;IAChD,mDAAmD;IACnD,0DAA0D;IAC1D,mEAAmE;IACnE,gDAAgD;IAChD,6BAA6B;CAChC;KACI,IAAI,CAAC,GAAG,CAAC;KACT,KAAK,CAAC,GAAG,CAAC,CAClB,CAAC;AAOF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAY,EAAE,CAAC;IACtD,GAAG,IAAI,GAAG,CACN,CACI,qBAAqB,CAAC,IAAI,CAAC;SACtB,SAAS,CAAC,KAAK,CAAC;SAChB,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC;SACzB,WAAW,EAAE;SACb,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,CACxC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAC1F;CACJ,CAAC;AAIF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAwB,EAAU,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAG9G,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAsB,EAAE;IAC3D,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { type Conversation } from "./fleet/conversations.js";
2
+ import type { IngestStats } from "./ingest/ingest.js";
3
+ import type { TopicFile, TopicOptions } from "./rank/files.js";
4
+ import type { GrabOptions, TurnExcerpt } from "./rank/grab.js";
5
+ import type { MatchOptions, SessionMatch } from "./rank/match.js";
6
+ import type { ForkPoint } from "./fork/fork-point.js";
7
+ import type { ForkResult } from "./fork/fork.js";
8
+ export type { ForkPoint } from "./fork/fork-point.js";
9
+ export type { ForkResult } from "./fork/fork.js";
10
+ export type { IngestStats } from "./ingest/ingest.js";
11
+ export type { GrabOptions, SessionBookends, TurnExcerpt } from "./rank/grab.js";
12
+ export type { MatchOptions, SessionMatch } from "./rank/match.js";
13
+ export type { TopicFile, TopicOptions } from "./rank/files.js";
14
+ export { readLines } from "./transcript/line-reader.js";
15
+ export { parseLine, typedPromptOf } from "./transcript/lines.js";
16
+ export { projectsDirOf } from "./transcript/slug.js";
17
+ export type { Conversation } from "./fleet/conversations.js";
18
+ export interface RecallOptions {
19
+ readonly root: string;
20
+ readonly claudeDir?: string;
21
+ readonly dbPath?: string;
22
+ readonly historyRoot?: string;
23
+ }
24
+ export interface SessionSummary {
25
+ readonly sessionId: string;
26
+ readonly title: string | undefined;
27
+ readonly lastTs: number;
28
+ readonly promptCount: number;
29
+ readonly conversation?: Conversation;
30
+ }
31
+ export interface Recall {
32
+ ingest(options?: {
33
+ budgetMs?: number;
34
+ }): Promise<IngestStats>;
35
+ filesForTopic(query: string, options?: TopicOptions): TopicFile[];
36
+ match(prompt: string, options?: MatchOptions): SessionMatch[];
37
+ grab(query: string, options?: GrabOptions): TurnExcerpt[];
38
+ forkPoint(sessionId: string, prompt?: string): ForkPoint | undefined;
39
+ fork(sessionId: string, options?: {
40
+ at?: string;
41
+ dryRun?: boolean;
42
+ }): Promise<ForkResult>;
43
+ sessions(options?: {
44
+ query?: string;
45
+ days?: number;
46
+ limit?: number;
47
+ }): SessionSummary[];
48
+ transcriptPathOf(sessionId: string): string;
49
+ close(): void;
50
+ }
51
+ export declare const createRecall: (options: RecallOptions) => Recall;
52
+ //# sourceMappingURL=recall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/recall/recall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import { join } from "node:path";
2
+ import { STATE_DIR } from "@intentic/constants";
3
+ import { conversationsBySession } from "./fleet/conversations.js";
4
+ import { selectForkPoint } from "./fork/fork-point.js";
5
+ import { materializeFork } from "./fork/fork.js";
6
+ import { ingest } from "./ingest/ingest.js";
7
+ import { rankFilesForTopic } from "./rank/files.js";
8
+ import { ftsQueryOf } from "./rank/terms.js";
9
+ import { grabExcerpts } from "./rank/grab.js";
10
+ import { matchSessions } from "./rank/match.js";
11
+ import { openRecallDb } from "./store/db.js";
12
+ import { projectsDirOf } from "./transcript/slug.js";
13
+ export { readLines } from "./transcript/line-reader.js";
14
+ export { parseLine, typedPromptOf } from "./transcript/lines.js";
15
+ export { projectsDirOf } from "./transcript/slug.js";
16
+ const DAY_MS = 24 * 60 * 60 * 1000;
17
+ export const createRecall = (options) => {
18
+ const projectsDir = projectsDirOf(options.root, options.claudeDir);
19
+ const dbPath = options.dbPath ?? join(options.root, `${STATE_DIR}/local/cache/iq/recall.db`);
20
+ let opened;
21
+ const db = () => (opened ??= openRecallDb(dbPath));
22
+ let fleet;
23
+ const conversations = () => (fleet ??= conversationsBySession(options.historyRoot));
24
+ return {
25
+ ingest: (ingestOptions) => ingest(db(), {
26
+ root: options.root,
27
+ projectsDir,
28
+ ...(ingestOptions?.budgetMs === undefined ? {} : { deadlineMs: Date.now() + ingestOptions.budgetMs }),
29
+ }),
30
+ filesForTopic: (query, topicOptions) => rankFilesForTopic(db(), query, topicOptions),
31
+ match: (prompt, matchOptions) => matchSessions(db(), prompt, matchOptions),
32
+ grab: (query, grabOptions) => grabExcerpts(db(), query, grabOptions),
33
+ forkPoint: (sessionId, prompt) => selectForkPoint(db(), options.root, sessionId, prompt),
34
+ fork(sessionId, forkOptions = {}) {
35
+ let atTurnUuid = forkOptions.at;
36
+ if (atTurnUuid !== undefined && /^\d+$/.test(atTurnUuid)) {
37
+ const row = db().get("SELECT t.uuid AS uuid FROM turns t JOIN sessions s ON s.id = t.session_id WHERE s.session_id = ? AND t.ordinal = ?", sessionId, Number(atTurnUuid));
38
+ if (row === undefined) {
39
+ throw new Error(`session ${sessionId} has no turn ${atTurnUuid}`);
40
+ }
41
+ atTurnUuid = row["uuid"];
42
+ }
43
+ return materializeFork({
44
+ transcriptPath: this.transcriptPathOf(sessionId),
45
+ ...(atTurnUuid !== undefined ? { atTurnUuid } : {}),
46
+ ...(forkOptions.dryRun !== undefined ? { dryRun: forkOptions.dryRun } : {}),
47
+ });
48
+ },
49
+ sessions(listOptions = {}) {
50
+ const sinceTs = Date.now() - (listOptions.days ?? 45) * DAY_MS;
51
+ const fts = listOptions.query === undefined ? undefined : ftsQueryOf(listOptions.query);
52
+ const filter = listOptions.query === undefined
53
+ ? undefined
54
+ : fts === undefined
55
+ ? new Set()
56
+ : new Set([
57
+ ...db()
58
+ .all("SELECT t.session_id AS id FROM turns_fts JOIN turns t ON t.id = turns_fts.rowid WHERE turns_fts MATCH ?", fts)
59
+ .map((row) => Number(row["id"])),
60
+ ...db()
61
+ .all("SELECT s.id AS id FROM sessions_fts JOIN sessions s ON s.id = sessions_fts.rowid WHERE sessions_fts MATCH ?", fts)
62
+ .map((row) => Number(row["id"])),
63
+ ]);
64
+ return (db()
65
+ .all(`SELECT s.id AS id, s.session_id AS sid, s.title AS title, s.last_ts AS last_ts, COUNT(t.id) AS prompts
66
+ FROM sessions s LEFT JOIN turns t ON t.session_id = s.id
67
+ WHERE s.last_ts >= ? GROUP BY s.id HAVING COUNT(t.id) > 0 ORDER BY s.last_ts DESC`, sinceTs)
68
+ .filter((row) => filter === undefined || filter.has(Number(row["id"])))
69
+ .slice(0, listOptions.limit ?? Number.POSITIVE_INFINITY)
70
+ .map((row) => {
71
+ const sessionId = row["sid"];
72
+ const conversation = conversations().get(sessionId);
73
+ return {
74
+ sessionId,
75
+ title: typeof row["title"] === "string" ? row["title"] : undefined,
76
+ lastTs: Number(row["last_ts"]),
77
+ promptCount: Number(row["prompts"]),
78
+ ...(conversation === undefined ? {} : { conversation }),
79
+ };
80
+ }));
81
+ },
82
+ transcriptPathOf: (sessionId) => join(projectsDir, `${sessionId}.jsonl`),
83
+ close: () => opened?.close(),
84
+ };
85
+ };
86
+ //# sourceMappingURL=recall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall.js","sourceRoot":"","sources":["../../src/recall/recall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type SqliteDb } from "@intentic/base/sqlite";
2
+ export declare const openRecallDb: (dbPath: string) => SqliteDb;
3
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/recall/store/db.ts"],"names":[],"mappings":"AACA,OAAO,EAAkC,KAAK,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAwF9F,eAAO,MAAM,YAAY,WAAY,MAAM,KAAG,QAS7C,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { rmSync } from "node:fs";
2
+ import { guardSchemaVersion, openSqlite, wrapDb } from "@intentic/base/sqlite";
3
+ const SCHEMA_VERSION = "3";
4
+ const DDL = `
5
+ CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
6
+ CREATE TABLE IF NOT EXISTS transcripts (
7
+ id INTEGER PRIMARY KEY,
8
+ path TEXT NOT NULL UNIQUE,
9
+ session_id TEXT NOT NULL,
10
+ byte_offset INTEGER NOT NULL,
11
+ mtime_ms INTEGER NOT NULL,
12
+ size INTEGER NOT NULL
13
+ );
14
+ CREATE TABLE IF NOT EXISTS sessions (
15
+ id INTEGER PRIMARY KEY,
16
+ session_id TEXT NOT NULL UNIQUE,
17
+ slug TEXT,
18
+ title TEXT,
19
+ version TEXT,
20
+ git_branch TEXT,
21
+ first_ts INTEGER NOT NULL,
22
+ last_ts INTEGER NOT NULL
23
+ );
24
+ CREATE TABLE IF NOT EXISTS turns (
25
+ id INTEGER PRIMARY KEY,
26
+ session_id INTEGER NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
27
+ uuid TEXT NOT NULL,
28
+ ordinal INTEGER NOT NULL,
29
+ ts INTEGER NOT NULL,
30
+ prompt TEXT NOT NULL,
31
+ -- The turn's closing assistant text message (head-capped at ingest): the answer, for excerpt recall.
32
+ response TEXT NOT NULL DEFAULT '',
33
+ start_byte INTEGER NOT NULL
34
+ );
35
+ -- One row per transcript line: two ingests running at once (the prompt hook's budgeted pass and the SessionStart
36
+ -- background pass) both read a transcript's offset before either writes, and each applied the same delta.
37
+ CREATE UNIQUE INDEX IF NOT EXISTS turns_session_uuid ON turns(session_id, uuid);
38
+ CREATE TABLE IF NOT EXISTS turn_files (
39
+ turn_id INTEGER NOT NULL REFERENCES turns(id) ON DELETE CASCADE,
40
+ path TEXT NOT NULL,
41
+ modified INTEGER NOT NULL DEFAULT 0,
42
+ last_ts INTEGER NOT NULL,
43
+ PRIMARY KEY (turn_id, path)
44
+ );
45
+ CREATE INDEX IF NOT EXISTS turn_files_path ON turn_files(path);
46
+ -- BM25 over typed prompts, closing assistant responses, and session titles. External-content: rows live in
47
+ -- turns/sessions; the triggers keep the FTS index in sync (they fire on FK-cascade deletes too, and on the
48
+ -- response overwrite an incremental ingest applies to a still-open turn). tokenchars keeps
49
+ -- snake_case/$identifiers whole: same setup as iq-engine's chunks_fts.
50
+ CREATE VIRTUAL TABLE IF NOT EXISTS turns_fts USING fts5(prompt, response, content='turns', content_rowid='id', tokenize="unicode61 tokenchars '_$'");
51
+ CREATE TRIGGER IF NOT EXISTS turns_fts_ai AFTER INSERT ON turns BEGIN
52
+ INSERT INTO turns_fts(rowid, prompt, response) VALUES (new.id, new.prompt, new.response);
53
+ END;
54
+ CREATE TRIGGER IF NOT EXISTS turns_fts_ad AFTER DELETE ON turns BEGIN
55
+ INSERT INTO turns_fts(turns_fts, rowid, prompt, response) VALUES ('delete', old.id, old.prompt, old.response);
56
+ END;
57
+ CREATE TRIGGER IF NOT EXISTS turns_fts_au AFTER UPDATE OF response ON turns BEGIN
58
+ INSERT INTO turns_fts(turns_fts, rowid, prompt, response) VALUES ('delete', old.id, old.prompt, old.response);
59
+ INSERT INTO turns_fts(rowid, prompt, response) VALUES (new.id, new.prompt, new.response);
60
+ END;
61
+ CREATE VIRTUAL TABLE IF NOT EXISTS sessions_fts USING fts5(title, content='sessions', content_rowid='id', tokenize="unicode61 tokenchars '_$'");
62
+ CREATE TRIGGER IF NOT EXISTS sessions_fts_ai AFTER INSERT ON sessions BEGIN
63
+ INSERT INTO sessions_fts(rowid, title) VALUES (new.id, coalesce(new.title, ''));
64
+ END;
65
+ CREATE TRIGGER IF NOT EXISTS sessions_fts_ad AFTER DELETE ON sessions BEGIN
66
+ INSERT INTO sessions_fts(sessions_fts, rowid, title) VALUES ('delete', old.id, coalesce(old.title, ''));
67
+ END;
68
+ CREATE TRIGGER IF NOT EXISTS sessions_fts_au AFTER UPDATE OF title ON sessions BEGIN
69
+ INSERT INTO sessions_fts(sessions_fts, rowid, title) VALUES ('delete', old.id, coalesce(old.title, ''));
70
+ INSERT INTO sessions_fts(rowid, title) VALUES (new.id, coalesce(new.title, ''));
71
+ END;
72
+ `;
73
+ const open = (dbPath) => {
74
+ const db = openSqlite(dbPath);
75
+ db.exec(DDL);
76
+ const wrapped = wrapDb(db);
77
+ guardSchemaVersion(wrapped, SCHEMA_VERSION, "iq recall");
78
+ return wrapped;
79
+ };
80
+ export const openRecallDb = (dbPath) => {
81
+ try {
82
+ return open(dbPath);
83
+ }
84
+ catch {
85
+ for (const suffix of ["", "-wal", "-shm"]) {
86
+ rmSync(dbPath + suffix, { force: true });
87
+ }
88
+ return open(dbPath);
89
+ }
90
+ };
91
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/recall/store/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAiB,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAK9F,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoEX,CAAC;AAEF,MAAM,IAAI,GAAG,CAAC,MAAc,EAAY,EAAE;IACtC,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAC9B,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3B,kBAAkB,CAAC,OAAO,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IACzD,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAKF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAc,EAAY,EAAE;IACrD,IAAI,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACL,KAAK,MAAM,MAAM,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;YACxC,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface TranscriptLine {
2
+ readonly json: string;
3
+ readonly endByte: number;
4
+ }
5
+ export declare function readLines(path: string, fromByte: number): AsyncGenerator<TranscriptLine>;
6
+ //# sourceMappingURL=line-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-reader.d.ts","sourceRoot":"","sources":["../../../src/recall/transcript/line-reader.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAKD,wBAAuB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAAC,cAAc,CAAC,CAkC/F"}
@@ -0,0 +1,36 @@
1
+ import { createReadStream } from "node:fs";
2
+ const MAX_LINE_BYTES = 10 * 1024 * 1024;
3
+ export async function* readLines(path, fromByte) {
4
+ let offset = fromByte;
5
+ let pending = [];
6
+ let pendingBytes = 0;
7
+ let skipping = false;
8
+ for await (const chunk of createReadStream(path, { start: fromByte })) {
9
+ let begin = 0;
10
+ for (let nl = chunk.indexOf(0x0a, begin); nl !== -1; nl = chunk.indexOf(0x0a, begin)) {
11
+ offset += pendingBytes + (nl - begin) + 1;
12
+ if (skipping) {
13
+ yield { json: "", endByte: offset };
14
+ }
15
+ else {
16
+ const tail = chunk.subarray(begin, nl);
17
+ const line = pending.length === 0 ? tail : Buffer.concat([...pending, tail]);
18
+ yield { json: line.toString("utf8"), endByte: offset };
19
+ }
20
+ pending = [];
21
+ pendingBytes = 0;
22
+ skipping = false;
23
+ begin = nl + 1;
24
+ }
25
+ const rest = chunk.subarray(begin);
26
+ pendingBytes += rest.length;
27
+ if (!skipping && pendingBytes > MAX_LINE_BYTES) {
28
+ skipping = true;
29
+ pending = [];
30
+ }
31
+ if (!skipping && rest.length > 0) {
32
+ pending.push(Buffer.from(rest));
33
+ }
34
+ }
35
+ }
36
+ //# sourceMappingURL=line-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-reader.js","sourceRoot":"","sources":["../../../src/recall/transcript/line-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAI3C,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAWxC,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,IAAY,EAAE,QAAgB;IAC3D,IAAI,MAAM,GAAG,QAAQ,CAAC;IAGtB,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,gBAAgB,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAA0B,EAAE,CAAC;QAC7F,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;YACnF,MAAM,IAAI,YAAY,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YAC1C,IAAI,QAAQ,EAAE,CAAC;gBACX,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACJ,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACvC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC7E,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YAC3D,CAAC;YACD,OAAO,GAAG,EAAE,CAAC;YACb,YAAY,GAAG,CAAC,CAAC;YACjB,QAAQ,GAAG,KAAK,CAAC;YACjB,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACnC,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,QAAQ,IAAI,YAAY,GAAG,cAAc,EAAE,CAAC;YAC7C,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,GAAG,EAAE,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAE/B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;AACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ export type Line = Record<string, unknown>;
2
+ export declare const parseLine: (json: string) => Line | undefined;
3
+ export declare const typeOf: (line: Line) => string | undefined;
4
+ export declare const uuidOf: (line: Line) => string | undefined;
5
+ export declare const parentUuidOf: (line: Line) => string | undefined;
6
+ export declare const timestampOf: (line: Line) => number | undefined;
7
+ export type PromptKind = "typed" | "command" | "local-command" | "compaction" | "interruption" | "meta" | "tool-result";
8
+ export interface Prompt {
9
+ readonly kind: PromptKind;
10
+ readonly text: string;
11
+ }
12
+ export declare const promptOf: (line: Line) => Prompt | undefined;
13
+ export declare const typedPromptOf: (line: Line) => string | undefined;
14
+ export declare const assistantTextOf: (line: Line) => string | undefined;
15
+ export interface FileTouch {
16
+ readonly path: string;
17
+ readonly modified: boolean;
18
+ }
19
+ export declare const fileTouchesOf: (line: Line) => FileTouch[];
20
+ export declare const aiTitleOf: (line: Line) => string | undefined;
21
+ export declare const leafUuidOf: (line: Line) => string | undefined;
22
+ //# sourceMappingURL=lines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../../src/recall/transcript/lines.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE3C,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,IAAI,GAAG,SAO/C,CAAC;AAOF,eAAO,MAAM,MAAM,SAAU,IAAI,KAAG,MAAM,GAAG,SAAmC,CAAC;AAEjF,eAAO,MAAM,MAAM,SAAU,IAAI,KAAG,MAAM,GAAG,SAAmC,CAAC;AAEjF,eAAO,MAAM,YAAY,SAAU,IAAI,KAAG,MAAM,GAAG,SAAyC,CAAC;AAE7F,eAAO,MAAM,WAAW,SAAU,IAAI,KAAG,MAAM,GAAG,SAOjD,CAAC;AAaF,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,eAAe,GAAG,YAAY,GAAG,cAAc,GAAG,MAAM,GAAG,aAAa,CAAC;AAExH,MAAM,WAAW,MAAM;IACnB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAE1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACzB;AAuBD,eAAO,MAAM,QAAQ,SAAU,IAAI,KAAG,MAAM,GAAG,SAyB9C,CAAC;AAIF,eAAO,MAAM,aAAa,SAAU,IAAI,KAAG,MAAM,GAAG,SAGnD,CAAC;AAIF,eAAO,MAAM,eAAe,SAAU,IAAI,KAAG,MAAM,GAAG,SAkBrD,CAAC;AAEF,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC9B;AAMD,eAAO,MAAM,aAAa,SAAU,IAAI,KAAG,SAAS,EAwCnD,CAAC;AAEF,eAAO,MAAM,SAAS,SAAU,IAAI,KAAG,MAAM,GAAG,SAAkF,CAAC;AAEnI,eAAO,MAAM,UAAU,SAAU,IAAI,KAAG,MAAM,GAAG,SAAsF,CAAC"}
@@ -0,0 +1,134 @@
1
+ export const parseLine = (json) => {
2
+ try {
3
+ const value = JSON.parse(json);
4
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
5
+ }
6
+ catch {
7
+ return undefined;
8
+ }
9
+ };
10
+ const asRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
11
+ const asString = (value) => (typeof value === "string" ? value : undefined);
12
+ export const typeOf = (line) => asString(line["type"]);
13
+ export const uuidOf = (line) => asString(line["uuid"]);
14
+ export const parentUuidOf = (line) => asString(line["parentUuid"]);
15
+ export const timestampOf = (line) => {
16
+ const raw = asString(line["timestamp"]);
17
+ if (raw === undefined) {
18
+ return undefined;
19
+ }
20
+ const ms = Date.parse(raw);
21
+ return Number.isNaN(ms) ? undefined : ms;
22
+ };
23
+ const INTERRUPTION = "[Request interrupted by user";
24
+ const kindOf = (line, text) => {
25
+ if (line["isMeta"] === true) {
26
+ return "meta";
27
+ }
28
+ if (line["isCompactSummary"] === true) {
29
+ return "compaction";
30
+ }
31
+ if (text.startsWith("<local-command-")) {
32
+ return "local-command";
33
+ }
34
+ if (text.startsWith("<command-")) {
35
+ return "command";
36
+ }
37
+ return text.startsWith(INTERRUPTION) ? "interruption" : "typed";
38
+ };
39
+ export const promptOf = (line) => {
40
+ if (typeOf(line) !== "user") {
41
+ return undefined;
42
+ }
43
+ const content = asRecord(line["message"])?.["content"];
44
+ let text;
45
+ if (typeof content === "string") {
46
+ text = content;
47
+ }
48
+ else if (Array.isArray(content)) {
49
+ const texts = [];
50
+ for (const block of content) {
51
+ const record = asRecord(block);
52
+ if (record?.["type"] === "tool_result") {
53
+ return { kind: "tool-result", text: "" };
54
+ }
55
+ const blockText = record?.["type"] === "text" ? asString(record["text"]) : undefined;
56
+ if (blockText !== undefined) {
57
+ texts.push(blockText);
58
+ }
59
+ }
60
+ text = texts.join("\n");
61
+ }
62
+ else {
63
+ return undefined;
64
+ }
65
+ return { kind: kindOf(line, text), text };
66
+ };
67
+ export const typedPromptOf = (line) => {
68
+ const prompt = promptOf(line);
69
+ return prompt?.kind === "typed" && prompt.text !== "" ? prompt.text : undefined;
70
+ };
71
+ export const assistantTextOf = (line) => {
72
+ if (typeOf(line) !== "assistant" || line["isSidechain"] === true) {
73
+ return undefined;
74
+ }
75
+ const content = asRecord(line["message"])?.["content"];
76
+ if (!Array.isArray(content)) {
77
+ return undefined;
78
+ }
79
+ const texts = [];
80
+ for (const block of content) {
81
+ const record = asRecord(block);
82
+ const text = record?.["type"] === "text" ? asString(record["text"]) : undefined;
83
+ if (text !== undefined) {
84
+ texts.push(text);
85
+ }
86
+ }
87
+ const joined = texts.join("\n");
88
+ return joined === "" ? undefined : joined;
89
+ };
90
+ const MODIFYING_TOOLS = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
91
+ export const fileTouchesOf = (line) => {
92
+ const touches = [];
93
+ const type = typeOf(line);
94
+ if (type === "assistant") {
95
+ const content = asRecord(line["message"])?.["content"];
96
+ if (Array.isArray(content)) {
97
+ for (const block of content) {
98
+ const record = asRecord(block);
99
+ if (record?.["type"] !== "tool_use") {
100
+ continue;
101
+ }
102
+ const name = asString(record["name"]) ?? "";
103
+ const input = asRecord(record["input"]);
104
+ const path = asString(input?.["file_path"]) ?? asString(input?.["notebook_path"]);
105
+ if (path !== undefined && (name === "Read" || MODIFYING_TOOLS.has(name))) {
106
+ touches.push({ path, modified: MODIFYING_TOOLS.has(name) });
107
+ }
108
+ }
109
+ }
110
+ return touches;
111
+ }
112
+ if (type === "user") {
113
+ const result = asRecord(line["toolUseResult"]);
114
+ const readPath = asString(asRecord(result?.["file"])?.["filePath"]);
115
+ if (readPath !== undefined) {
116
+ touches.push({ path: readPath, modified: false });
117
+ }
118
+ const writePath = asString(result?.["filePath"]);
119
+ if (writePath !== undefined) {
120
+ touches.push({ path: writePath, modified: true });
121
+ }
122
+ return touches;
123
+ }
124
+ if (type === "file-history-snapshot") {
125
+ const backups = asRecord(asRecord(line["snapshot"])?.["trackedFileBackups"]);
126
+ for (const path of Object.keys(backups ?? {})) {
127
+ touches.push({ path, modified: true });
128
+ }
129
+ }
130
+ return touches;
131
+ };
132
+ export const aiTitleOf = (line) => (typeOf(line) === "ai-title" ? asString(line["aiTitle"]) : undefined);
133
+ export const leafUuidOf = (line) => (typeOf(line) === "last-prompt" ? asString(line["leafUuid"]) : undefined);
134
+ //# sourceMappingURL=lines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lines.js","sourceRoot":"","sources":["../../../src/recall/transcript/lines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const slugOf: (root: string) => string;
2
+ export declare const projectsDirOf: (root: string, claudeDir?: string) => string;
3
+ //# sourceMappingURL=slug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../../src/recall/transcript/slug.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,MAAM,SAAU,MAAM,KAAG,MAA4C,CAAC;AAEnF,eAAO,MAAM,aAAa,SAAU,MAAM,cAAc,MAAM,KAAG,MAAiF,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { homedir } from "node:os";
2
+ import { join } from "node:path";
3
+ export const slugOf = (root) => root.replace(/[^a-zA-Z0-9]/g, "-");
4
+ export const projectsDirOf = (root, claudeDir) => join(claudeDir ?? join(homedir(), ".claude"), "projects", slugOf(root));
5
+ //# sourceMappingURL=slug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slug.js","sourceRoot":"","sources":["../../../src/recall/transcript/slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;AAEnF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,SAAkB,EAAU,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/iq",
3
- "version": "1.325.0",
3
+ "version": "1.327.0",
4
4
  "description": "iq, agent-native workspace search CLI: one intent-first entry point over lexical, structural, semantic, and git engines",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,15 +31,25 @@
31
31
  "default": "./dist/index.js"
32
32
  }
33
33
  },
34
+ "./transcript": {
35
+ "types": "./dist/recall/transcript/lines.d.ts",
36
+ "import": {
37
+ "@intentic/src": "./src/recall/transcript/lines.ts",
38
+ "default": "./dist/recall/transcript/lines.js"
39
+ },
40
+ "require": {
41
+ "@intentic/src": "./src/recall/transcript/lines.ts",
42
+ "default": "./dist/recall/transcript/lines.js"
43
+ }
44
+ },
34
45
  "./skill": "./plugin/skills/iq/SKILL.md",
35
46
  "./nudge": "./plugin/hooks/nudge.txt"
36
47
  },
37
48
  "dependencies": {
38
- "@intentic/agent-cli": "1.325.0",
39
- "@intentic/base": "1.325.0",
40
- "@intentic/constants": "1.325.0",
41
- "@intentic/iq-engine": "1.325.0",
42
- "@intentic/iq-recall": "1.325.0",
49
+ "@intentic/agent-cli": "1.327.0",
50
+ "@intentic/base": "1.327.0",
51
+ "@intentic/constants": "1.327.0",
52
+ "@intentic/iq-engine": "1.327.0",
43
53
  "@puristic/env": "1.6.1",
44
54
  "@stricli/core": "1.3.0",
45
55
  "tslib": "2.8.1",
@@ -49,7 +59,7 @@
49
59
  "@intentic/testing": "0.0.0",
50
60
  "@intentic/tsconfig": "0.0.0",
51
61
  "@types/bun": "1.4.2",
52
- "@types/node": "24.13.6",
62
+ "@types/node": "24.19.1",
53
63
  "@typescript/native-preview": "7.0.0-dev.20260707.2"
54
64
  },
55
65
  "scripts": {