@spool-lab/core 0.4.1 → 0.4.12

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 (111) hide show
  1. package/dist/db/db.d.ts +19 -0
  2. package/dist/db/db.d.ts.map +1 -1
  3. package/dist/db/db.js +210 -15
  4. package/dist/db/db.js.map +1 -1
  5. package/dist/db/queries.d.ts +36 -10
  6. package/dist/db/queries.d.ts.map +1 -1
  7. package/dist/db/queries.js +96 -75
  8. package/dist/db/queries.js.map +1 -1
  9. package/dist/db/share-drafts.d.ts +51 -0
  10. package/dist/db/share-drafts.d.ts.map +1 -0
  11. package/dist/db/share-drafts.js +47 -0
  12. package/dist/db/share-drafts.js.map +1 -0
  13. package/dist/doctor/checks/config.d.ts +3 -0
  14. package/dist/doctor/checks/config.d.ts.map +1 -0
  15. package/dist/doctor/checks/config.js +123 -0
  16. package/dist/doctor/checks/config.js.map +1 -0
  17. package/dist/doctor/checks/db.d.ts +3 -0
  18. package/dist/doctor/checks/db.d.ts.map +1 -0
  19. package/dist/doctor/checks/db.js +225 -0
  20. package/dist/doctor/checks/db.js.map +1 -0
  21. package/dist/doctor/checks/env.d.ts +3 -0
  22. package/dist/doctor/checks/env.d.ts.map +1 -0
  23. package/dist/doctor/checks/env.js +70 -0
  24. package/dist/doctor/checks/env.js.map +1 -0
  25. package/dist/doctor/checks/index.d.ts +3 -0
  26. package/dist/doctor/checks/index.d.ts.map +1 -0
  27. package/dist/doctor/checks/index.js +13 -0
  28. package/dist/doctor/checks/index.js.map +1 -0
  29. package/dist/doctor/checks/native.d.ts +3 -0
  30. package/dist/doctor/checks/native.d.ts.map +1 -0
  31. package/dist/doctor/checks/native.js +42 -0
  32. package/dist/doctor/checks/native.js.map +1 -0
  33. package/dist/doctor/checks/versions.d.ts +3 -0
  34. package/dist/doctor/checks/versions.d.ts.map +1 -0
  35. package/dist/doctor/checks/versions.js +79 -0
  36. package/dist/doctor/checks/versions.js.map +1 -0
  37. package/dist/doctor/index.d.ts +3 -0
  38. package/dist/doctor/index.d.ts.map +1 -0
  39. package/dist/doctor/index.js +3 -0
  40. package/dist/doctor/index.js.map +1 -0
  41. package/dist/doctor/preflight.d.ts +18 -0
  42. package/dist/doctor/preflight.d.ts.map +1 -0
  43. package/dist/doctor/preflight.js +27 -0
  44. package/dist/doctor/preflight.js.map +1 -0
  45. package/dist/doctor/runner.d.ts +12 -0
  46. package/dist/doctor/runner.d.ts.map +1 -0
  47. package/dist/doctor/runner.js +37 -0
  48. package/dist/doctor/runner.js.map +1 -0
  49. package/dist/doctor/types.d.ts +27 -0
  50. package/dist/doctor/types.d.ts.map +1 -0
  51. package/dist/doctor/types.js +2 -0
  52. package/dist/doctor/types.js.map +1 -0
  53. package/dist/index.d.ts +5 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +5 -0
  56. package/dist/index.js.map +1 -1
  57. package/dist/migrations/agent-search-cleanup.d.ts +36 -0
  58. package/dist/migrations/agent-search-cleanup.d.ts.map +1 -0
  59. package/dist/migrations/agent-search-cleanup.js +182 -0
  60. package/dist/migrations/agent-search-cleanup.js.map +1 -0
  61. package/dist/migrations/worktree-identity-upgrade.d.ts +31 -0
  62. package/dist/migrations/worktree-identity-upgrade.d.ts.map +1 -0
  63. package/dist/migrations/worktree-identity-upgrade.js +22 -0
  64. package/dist/migrations/worktree-identity-upgrade.js.map +1 -0
  65. package/dist/parsers/claude.d.ts.map +1 -1
  66. package/dist/parsers/claude.js +25 -12
  67. package/dist/parsers/claude.js.map +1 -1
  68. package/dist/parsers/codex.d.ts.map +1 -1
  69. package/dist/parsers/codex.js +32 -5
  70. package/dist/parsers/codex.js.map +1 -1
  71. package/dist/parsers/gemini.d.ts.map +1 -1
  72. package/dist/parsers/gemini.js +5 -5
  73. package/dist/parsers/gemini.js.map +1 -1
  74. package/dist/parsers/spool-prelude.d.ts +16 -0
  75. package/dist/parsers/spool-prelude.d.ts.map +1 -0
  76. package/dist/parsers/spool-prelude.js +21 -0
  77. package/dist/parsers/spool-prelude.js.map +1 -0
  78. package/dist/projects/display-name.d.ts +2 -0
  79. package/dist/projects/display-name.d.ts.map +1 -0
  80. package/dist/projects/display-name.js +8 -0
  81. package/dist/projects/display-name.js.map +1 -0
  82. package/dist/projects/fs.d.ts +3 -0
  83. package/dist/projects/fs.d.ts.map +1 -0
  84. package/dist/projects/fs.js +20 -0
  85. package/dist/projects/fs.js.map +1 -0
  86. package/dist/projects/groups.d.ts +4 -0
  87. package/dist/projects/groups.d.ts.map +1 -0
  88. package/dist/projects/groups.js +20 -0
  89. package/dist/projects/groups.js.map +1 -0
  90. package/dist/projects/identity-synthesizers.d.ts +22 -0
  91. package/dist/projects/identity-synthesizers.d.ts.map +1 -0
  92. package/dist/projects/identity-synthesizers.js +29 -0
  93. package/dist/projects/identity-synthesizers.js.map +1 -0
  94. package/dist/projects/identity.d.ts +16 -0
  95. package/dist/projects/identity.d.ts.map +1 -0
  96. package/dist/projects/identity.js +172 -0
  97. package/dist/projects/identity.js.map +1 -0
  98. package/dist/projects/sessions.d.ts +12 -0
  99. package/dist/projects/sessions.d.ts.map +1 -0
  100. package/dist/projects/sessions.js +47 -0
  101. package/dist/projects/sessions.js.map +1 -0
  102. package/dist/projects/worktree-resolvers.d.ts +19 -0
  103. package/dist/projects/worktree-resolvers.d.ts.map +1 -0
  104. package/dist/projects/worktree-resolvers.js +65 -0
  105. package/dist/projects/worktree-resolvers.js.map +1 -0
  106. package/dist/sync/syncer.d.ts.map +1 -1
  107. package/dist/sync/syncer.js +11 -3
  108. package/dist/sync/syncer.js.map +1 -1
  109. package/dist/types.d.ts +15 -6
  110. package/dist/types.d.ts.map +1 -1
  111. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { dirname, join } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
+ import { stripSpoolSystemPrelude } from './spool-prelude.js';
4
5
  const GEMINI_INDEXABLE_TYPES = new Set(['user', 'gemini', 'info', 'warning', 'error']);
5
6
  export function loadGeminiSession(filePath) {
6
7
  const raw = readFileSync(filePath, 'utf8');
@@ -74,14 +75,14 @@ function toParsedRole(type) {
74
75
  }
75
76
  function extractText(content) {
76
77
  if (typeof content === 'string')
77
- return content.trim();
78
+ return stripSpoolSystemPrelude(content);
78
79
  if (content && typeof content === 'object' && !Array.isArray(content)) {
79
80
  const text = content['text'];
80
- return typeof text === 'string' ? text.trim() : '';
81
+ return typeof text === 'string' ? stripSpoolSystemPrelude(text) : '';
81
82
  }
82
83
  if (!Array.isArray(content))
83
84
  return '';
84
- return content
85
+ return stripSpoolSystemPrelude(content
85
86
  .map(item => {
86
87
  if (typeof item === 'string')
87
88
  return item;
@@ -91,8 +92,7 @@ function extractText(content) {
91
92
  return typeof text === 'string' ? text : '';
92
93
  })
93
94
  .filter(Boolean)
94
- .join('\n')
95
- .trim();
95
+ .join('\n'));
96
96
  }
97
97
  function extractToolNames(toolCalls) {
98
98
  if (!Array.isArray(toolCalls))
@@ -1 +1 @@
1
- {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/parsers/gemini.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/parsers/gemini.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Spool wraps its agent-search system instructions in this marker before
3
+ * sending them to ACP, so the parsers can strip them back out when indexing
4
+ * the on-disk JSONL. Without the marker, our system prompt would appear as
5
+ * the first user message in every agent-search session — polluting the
6
+ * derived title, the FTS index, and the session detail view.
7
+ *
8
+ * The user's actual query is sent OUTSIDE the marker block (at the end of
9
+ * the message text), so after stripping the prelude only the bare query
10
+ * remains.
11
+ */
12
+ export declare const SPOOL_SYSTEM_PRELUDE_OPEN = "<spool-system-prelude>";
13
+ export declare const SPOOL_SYSTEM_PRELUDE_CLOSE = "</spool-system-prelude>";
14
+ export declare function wrapSpoolSystemPrelude(systemBody: string, userQuery: string): string;
15
+ export declare function stripSpoolSystemPrelude(text: string): string;
16
+ //# sourceMappingURL=spool-prelude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spool-prelude.d.ts","sourceRoot":"","sources":["../../src/parsers/spool-prelude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,2BAA2B,CAAA;AACjE,eAAO,MAAM,0BAA0B,4BAA4B,CAAA;AAEnE,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpF;AAID,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5D"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Spool wraps its agent-search system instructions in this marker before
3
+ * sending them to ACP, so the parsers can strip them back out when indexing
4
+ * the on-disk JSONL. Without the marker, our system prompt would appear as
5
+ * the first user message in every agent-search session — polluting the
6
+ * derived title, the FTS index, and the session detail view.
7
+ *
8
+ * The user's actual query is sent OUTSIDE the marker block (at the end of
9
+ * the message text), so after stripping the prelude only the bare query
10
+ * remains.
11
+ */
12
+ export const SPOOL_SYSTEM_PRELUDE_OPEN = '<spool-system-prelude>';
13
+ export const SPOOL_SYSTEM_PRELUDE_CLOSE = '</spool-system-prelude>';
14
+ export function wrapSpoolSystemPrelude(systemBody, userQuery) {
15
+ return `${SPOOL_SYSTEM_PRELUDE_OPEN}\n${systemBody}\n${SPOOL_SYSTEM_PRELUDE_CLOSE}\n\n${userQuery}`;
16
+ }
17
+ const STRIP_RE = /<spool-system-prelude>[\s\S]*?<\/spool-system-prelude>/g;
18
+ export function stripSpoolSystemPrelude(text) {
19
+ return text.replace(STRIP_RE, '').trim();
20
+ }
21
+ //# sourceMappingURL=spool-prelude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spool-prelude.js","sourceRoot":"","sources":["../../src/parsers/spool-prelude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,wBAAwB,CAAA;AACjE,MAAM,CAAC,MAAM,0BAA0B,GAAG,yBAAyB,CAAA;AAEnE,MAAM,UAAU,sBAAsB,CAAC,UAAkB,EAAE,SAAiB;IAC1E,OAAO,GAAG,yBAAyB,KAAK,UAAU,KAAK,0BAA0B,OAAO,SAAS,EAAE,CAAA;AACrG,CAAC;AAED,MAAM,QAAQ,GAAG,yDAAyD,CAAA;AAE1E,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function fallbackDisplayName(input: string): string;
2
+ //# sourceMappingURL=display-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-name.d.ts","sourceRoot":"","sources":["../../src/projects/display-name.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKzD"}
@@ -0,0 +1,8 @@
1
+ export function fallbackDisplayName(input) {
2
+ if (input === '/')
3
+ return '(root)';
4
+ const trimmed = input.replace(/\/+$/, '');
5
+ const parts = trimmed.split('/').filter(Boolean);
6
+ return parts[parts.length - 1] ?? trimmed;
7
+ }
8
+ //# sourceMappingURL=display-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-name.js","sourceRoot":"","sources":["../../src/projects/display-name.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAA;IAClC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAChD,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,OAAO,CAAA;AAC3C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { IdentityFs } from './identity.js';
2
+ export declare const realFs: IdentityFs;
3
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/projects/fs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,eAAO,MAAM,MAAM,EAAE,UAWpB,CAAA"}
@@ -0,0 +1,20 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { spawnSync } from 'node:child_process';
3
+ export const realFs = {
4
+ exists: existsSync,
5
+ readText: (p) => {
6
+ try {
7
+ return readFileSync(p, 'utf8');
8
+ }
9
+ catch {
10
+ return null;
11
+ }
12
+ },
13
+ spawn: (cmd, args, opts) => {
14
+ // 5s timeout: a hung `git config` (e.g. ssh-agent passphrase prompt,
15
+ // network-mounted repo) must not block session indexing.
16
+ const r = spawnSync(cmd, args, { cwd: opts.cwd, encoding: 'utf8', timeout: 5000 });
17
+ return { stdout: r.stdout ?? '', exitCode: r.status ?? 1 };
18
+ },
19
+ };
20
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/projects/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAG9C,MAAM,CAAC,MAAM,MAAM,GAAe;IAChC,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QACd,IAAI,CAAC;YAAC,OAAO,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAA;QAAC,CAAC;IAC9D,CAAC;IACD,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACzB,qEAAqE;QACrE,yDAAyD;QACzD,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAClF,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,CAAA;IAC5D,CAAC;CACF,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { ProjectGroup } from '../types.js';
3
+ export declare function listProjectGroups(db: Database.Database): ProjectGroup[];
4
+ //# sourceMappingURL=groups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../src/projects/groups.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAsC,MAAM,aAAa,CAAA;AAEnF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,YAAY,EAAE,CAyBvE"}
@@ -0,0 +1,20 @@
1
+ export function listProjectGroups(db) {
2
+ const rows = db.prepare(`
3
+ SELECT identity_kind, identity_key, display_name, sources_csv,
4
+ session_count, last_session_at
5
+ FROM project_groups_v
6
+ ORDER BY
7
+ CASE identity_kind WHEN 'loose' THEN 1 ELSE 0 END,
8
+ last_session_at IS NULL,
9
+ last_session_at DESC
10
+ `).all();
11
+ return rows.map(r => ({
12
+ identityKind: r.identity_kind,
13
+ identityKey: r.identity_key,
14
+ displayName: r.display_name,
15
+ sources: (r.sources_csv ?? '').split(',').filter(Boolean),
16
+ sessionCount: r.session_count,
17
+ lastSessionAt: r.last_session_at,
18
+ }));
19
+ }
20
+ //# sourceMappingURL=groups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.js","sourceRoot":"","sources":["../../src/projects/groups.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,iBAAiB,CAAC,EAAqB;IACrD,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;GAQvB,CAAC,CAAC,GAAG,EAOJ,CAAA;IACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpB,YAAY,EAAE,CAAC,CAAC,aAAa;QAC7B,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,WAAW,EAAE,CAAC,CAAC,YAAY;QAC3B,OAAO,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAoB;QAC5E,YAAY,EAAE,CAAC,CAAC,aAAa;QAC7B,aAAa,EAAE,CAAC,CAAC,eAAe;KACjC,CAAC,CAAC,CAAA;AACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { ProjectIdentity } from '../types.js';
2
+ /**
3
+ * Collapses sessions whose cwd is a known "scratch workspace" pattern into a
4
+ * single synthetic project — the workspace dir itself carries no useful
5
+ * identity signal (no .git, no manifest), so without this each chat shows up
6
+ * as its own sidebar entry.
7
+ *
8
+ * Each synthesizer matches a cwd and returns a stable identity shared by all
9
+ * sessions in that scope. Returns null to defer to the next rule.
10
+ */
11
+ export interface IdentitySynthesizer {
12
+ name: string;
13
+ synthesize(cwd: string): ProjectIdentity | null;
14
+ }
15
+ /**
16
+ * Codex desktop creates one disposable workspace per non-project chat at
17
+ * `~/Documents/Codex/<YYYY-MM-DD>/<slug>/`. Group every such chat under a
18
+ * single synthetic "Codex" project so they don't litter the sidebar.
19
+ */
20
+ export declare const codexScratchSynthesizer: IdentitySynthesizer;
21
+ export declare const DEFAULT_SYNTHESIZERS: readonly IdentitySynthesizer[];
22
+ //# sourceMappingURL=identity-synthesizers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-synthesizers.d.ts","sourceRoot":"","sources":["../../src/projects/identity-synthesizers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAOlD;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAAA;CAChD;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAYrC,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,SAAS,mBAAmB,EAE7D,CAAA"}
@@ -0,0 +1,29 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ // Resolved at call time so process.env.HOME overrides take effect in tests.
4
+ function getHome() {
5
+ return process.env['HOME'] || homedir();
6
+ }
7
+ /**
8
+ * Codex desktop creates one disposable workspace per non-project chat at
9
+ * `~/Documents/Codex/<YYYY-MM-DD>/<slug>/`. Group every such chat under a
10
+ * single synthetic "Codex" project so they don't litter the sidebar.
11
+ */
12
+ export const codexScratchSynthesizer = {
13
+ name: 'codex-scratch',
14
+ synthesize(cwd) {
15
+ const root = join(getHome(), 'Documents', 'Codex');
16
+ if (!cwd.startsWith(root + '/'))
17
+ return null;
18
+ return {
19
+ kind: 'synthetic',
20
+ key: 'codex:scratch',
21
+ displayName: 'Codex Chats',
22
+ displayPath: root,
23
+ };
24
+ },
25
+ };
26
+ export const DEFAULT_SYNTHESIZERS = Object.freeze([
27
+ codexScratchSynthesizer,
28
+ ]);
29
+ //# sourceMappingURL=identity-synthesizers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-synthesizers.js","sourceRoot":"","sources":["../../src/projects/identity-synthesizers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,4EAA4E;AAC5E,SAAS,OAAO;IACd,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,CAAA;AACzC,CAAC;AAgBD;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAwB;IAC1D,IAAI,EAAE,eAAe;IACrB,UAAU,CAAC,GAAW;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;QAClD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QAC5C,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,GAAG,EAAE,eAAe;YACpB,WAAW,EAAE,aAAa;YAC1B,WAAW,EAAE,IAAI;SAClB,CAAA;IACH,CAAC;CACF,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAmC,MAAM,CAAC,MAAM,CAAC;IAChF,uBAAuB;CACxB,CAAC,CAAA"}
@@ -0,0 +1,16 @@
1
+ import type { ProjectIdentity } from '../types.js';
2
+ import { type WorktreeUpstreamResolver } from './worktree-resolvers.js';
3
+ import { type IdentitySynthesizer } from './identity-synthesizers.js';
4
+ export interface IdentityFs {
5
+ exists(path: string): boolean;
6
+ readText(path: string): string | null;
7
+ spawn(cmd: string, args: string[], opts: {
8
+ cwd: string;
9
+ }): {
10
+ stdout: string;
11
+ exitCode: number;
12
+ };
13
+ }
14
+ export declare function normalizeGitRemote(url: string): string | null;
15
+ export declare function computeIdentity(cwd: string | null, fs: IdentityFs, resolvers?: readonly WorktreeUpstreamResolver[], synthesizers?: readonly IdentitySynthesizer[]): ProjectIdentity;
16
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/projects/identity.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAuB,MAAM,aAAa,CAAA;AAEvE,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAC1F,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAE3F,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACrC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAChG;AAgBD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU7D;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,EAAE,EAAE,UAAU,EACd,SAAS,GAAE,SAAS,wBAAwB,EAAsB,EAClE,YAAY,GAAE,SAAS,mBAAmB,EAAyB,GAClE,eAAe,CA6EjB"}
@@ -0,0 +1,172 @@
1
+ import { homedir } from 'node:os';
2
+ import { dirname, join, isAbsolute, resolve } from 'node:path';
3
+ import { fallbackDisplayName } from './display-name.js';
4
+ import { DEFAULT_RESOLVERS } from './worktree-resolvers.js';
5
+ import { DEFAULT_SYNTHESIZERS } from './identity-synthesizers.js';
6
+ const MANIFESTS = [
7
+ 'package.json', 'Cargo.toml', 'pyproject.toml',
8
+ 'go.mod', 'Gemfile', 'pom.xml', 'build.gradle',
9
+ ];
10
+ const PARSEABLE_MANIFESTS = [
11
+ 'package.json', 'Cargo.toml', 'pyproject.toml',
12
+ ];
13
+ const LOOSE_DIRS = new Set([
14
+ '/tmp', '/private/tmp',
15
+ ]);
16
+ const LOOSE_HOME_DIRS = ['Desktop', 'Downloads', 'Documents'];
17
+ export function normalizeGitRemote(url) {
18
+ if (!url)
19
+ return null;
20
+ let s = url.trim().replace(/\.git$/, '');
21
+ // git@host:owner/repo → host/owner/repo
22
+ const sshMatch = s.match(/^[^@]+@([^:]+):(.+)$/);
23
+ if (sshMatch)
24
+ s = `${sshMatch[1]}/${sshMatch[2]}`;
25
+ // strip protocol + credentials
26
+ s = s.replace(/^[a-z]+:\/\/(?:[^@/]*@)?/i, '');
27
+ if (!s.includes('/'))
28
+ return null;
29
+ return s.toLowerCase();
30
+ }
31
+ export function computeIdentity(cwd, fs, resolvers = DEFAULT_RESOLVERS, synthesizers = DEFAULT_SYNTHESIZERS) {
32
+ if (!cwd)
33
+ return loose();
34
+ const home = homedir();
35
+ if (cwd === home || LOOSE_DIRS.has(cwd))
36
+ return loose();
37
+ if (LOOSE_HOME_DIRS.some(d => cwd === join(home, d)))
38
+ return loose();
39
+ // 1. git
40
+ const gitRoot = findGitRoot(cwd, fs);
41
+ if (gitRoot) {
42
+ const remote = fs.spawn('git', ['config', '--get', 'remote.origin.url'], { cwd: gitRoot });
43
+ if (remote.exitCode === 0) {
44
+ const norm = normalizeGitRemote(remote.stdout.trim());
45
+ if (norm) {
46
+ return {
47
+ kind: 'git_remote',
48
+ key: norm,
49
+ displayName: deriveDisplayName({ kind: 'git_remote', key: norm, gitRoot, fs }),
50
+ };
51
+ }
52
+ }
53
+ const common = fs.spawn('git', ['rev-parse', '--git-common-dir'], { cwd: gitRoot });
54
+ if (common.exitCode === 0) {
55
+ const raw = common.stdout.trim();
56
+ if (raw) {
57
+ const key = isAbsolute(raw) ? raw : resolve(gitRoot, raw);
58
+ return {
59
+ kind: 'git_common_dir',
60
+ key,
61
+ displayName: deriveDisplayName({ kind: 'git_common_dir', key, gitRoot, fs }),
62
+ };
63
+ }
64
+ }
65
+ }
66
+ // 2. manifest
67
+ const manifestDir = findManifestDir(cwd, fs);
68
+ if (manifestDir) {
69
+ return {
70
+ kind: 'manifest_path',
71
+ key: manifestDir,
72
+ displayName: deriveDisplayName({ kind: 'manifest_path', key: manifestDir, fs }),
73
+ };
74
+ }
75
+ // 3. worktree resolvers — recover identity for sessions whose cwd has been
76
+ // deleted (e.g. superset/git worktree torn down before Spool synced). The
77
+ // resolver returns the upstream main-repo path; we recurse with empty
78
+ // resolvers to prevent loops and to ensure the upstream goes through the
79
+ // normal git/manifest detection on a real, existing path.
80
+ if (!fs.exists(cwd) && resolvers.length > 0) {
81
+ for (const r of resolvers) {
82
+ const upstream = r.resolve(cwd);
83
+ if (!upstream || !fs.exists(upstream))
84
+ continue;
85
+ const id = computeIdentity(upstream, fs, [], []);
86
+ if (id.kind === 'git_remote' || id.kind === 'git_common_dir' || id.kind === 'manifest_path') {
87
+ return id;
88
+ }
89
+ }
90
+ }
91
+ // 4. identity synthesizers — collapse known scratch-workspace patterns
92
+ // (e.g. Codex desktop's per-chat temp dirs under ~/Documents/Codex/<date>/)
93
+ // into a single synthetic project. Only runs when no real project signal
94
+ // was found above; a chat that happens to live inside a real git repo or
95
+ // manifest still groups under that repo.
96
+ for (const s of synthesizers) {
97
+ const id = s.synthesize(cwd);
98
+ if (id)
99
+ return id;
100
+ }
101
+ // 5. path
102
+ return {
103
+ kind: 'path',
104
+ key: cwd,
105
+ displayName: fallbackDisplayName(cwd),
106
+ };
107
+ }
108
+ function loose() {
109
+ return { kind: 'loose', key: 'loose', displayName: 'Loose' };
110
+ }
111
+ function findGitRoot(start, fs) {
112
+ let cur = start;
113
+ while (cur && cur !== '/') {
114
+ if (fs.exists(join(cur, '.git')))
115
+ return cur;
116
+ const parent = dirname(cur);
117
+ if (parent === cur)
118
+ break;
119
+ cur = parent;
120
+ }
121
+ return null;
122
+ }
123
+ function findManifestDir(start, fs) {
124
+ let cur = start;
125
+ while (cur && cur !== '/') {
126
+ for (const m of MANIFESTS) {
127
+ if (fs.exists(join(cur, m)))
128
+ return cur;
129
+ }
130
+ const parent = dirname(cur);
131
+ if (parent === cur)
132
+ break;
133
+ cur = parent;
134
+ }
135
+ return null;
136
+ }
137
+ function deriveDisplayName(input) {
138
+ // Try manifest name first
139
+ const dir = input.gitRoot ?? (input.kind === 'manifest_path' ? input.key : null);
140
+ if (dir) {
141
+ for (const m of PARSEABLE_MANIFESTS) {
142
+ const p = join(dir, m);
143
+ if (input.fs.exists(p)) {
144
+ const name = parseManifestName(m, input.fs.readText(p) ?? '');
145
+ if (name)
146
+ return name;
147
+ }
148
+ }
149
+ }
150
+ // git remote → last segment
151
+ if (input.kind === 'git_remote') {
152
+ const parts = input.key.split('/');
153
+ return parts[parts.length - 1] || input.key;
154
+ }
155
+ // common-dir or path → containing dir name
156
+ if (input.gitRoot)
157
+ return fallbackDisplayName(input.gitRoot);
158
+ return fallbackDisplayName(input.key);
159
+ }
160
+ function parseManifestName(file, text) {
161
+ if (!text)
162
+ return null;
163
+ if (file === 'package.json' || file === 'Cargo.toml' || file === 'pyproject.toml') {
164
+ // Cheap regex: find name = "x" or "name": "x"
165
+ const m = text.match(/"name"\s*:\s*"([^"]+)"/) ||
166
+ text.match(/^\s*name\s*=\s*"([^"]+)"/m);
167
+ if (m && m[1])
168
+ return m[1];
169
+ }
170
+ return null;
171
+ }
172
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/projects/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { Session, SessionSource } from '../types.js';
3
+ export type ProjectSessionSortOrder = 'recent' | 'oldest' | 'most_messages' | 'title';
4
+ export interface ListSessionsByIdentityOptions {
5
+ sources?: SessionSource[];
6
+ sortOrder?: ProjectSessionSortOrder;
7
+ limit?: number;
8
+ excludePinned?: boolean;
9
+ }
10
+ export declare function listSessionsByIdentity(db: Database.Database, identityKey: string, options?: ListSessionsByIdentityOptions): Session[];
11
+ export declare function listPinnedSessionsByIdentity(db: Database.Database, identityKey: string): Session[];
12
+ //# sourceMappingURL=sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/projects/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGzD,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAA;AAErF,MAAM,WAAW,6BAA6B;IAC5C,OAAO,CAAC,EAAE,aAAa,EAAE,CAAA;IACzB,SAAS,CAAC,EAAE,uBAAuB,CAAA;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,6BAAkC,GAC1C,OAAO,EAAE,CA2BX;AAED,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,EAAE,CAQX"}
@@ -0,0 +1,47 @@
1
+ import { SESSION_SELECT, rowToSession } from '../db/queries.js';
2
+ export function listSessionsByIdentity(db, identityKey, options = {}) {
3
+ const { sources, sortOrder = 'recent', limit = 500, excludePinned = false } = options;
4
+ const conditions = ['p.identity_key = ?', 's.message_count > 0'];
5
+ const params = [identityKey];
6
+ if (sources && sources.length > 0) {
7
+ const placeholders = sources.map(() => '?').join(',');
8
+ conditions.push(`src.name IN (${placeholders})`);
9
+ params.push(...sources);
10
+ }
11
+ if (excludePinned) {
12
+ conditions.push('NOT EXISTS (SELECT 1 FROM pins WHERE pins.session_uuid = s.session_uuid)');
13
+ }
14
+ const orderBy = orderByClause(sortOrder);
15
+ const sql = `
16
+ ${SESSION_SELECT}
17
+ WHERE ${conditions.join(' AND ')}
18
+ ORDER BY ${orderBy}
19
+ LIMIT ?
20
+ `;
21
+ params.push(limit);
22
+ const rows = db.prepare(sql).all(...params);
23
+ return rows.map(rowToSession);
24
+ }
25
+ export function listPinnedSessionsByIdentity(db, identityKey) {
26
+ const rows = db.prepare(`
27
+ ${SESSION_SELECT}
28
+ JOIN pins ON pins.session_uuid = s.session_uuid
29
+ WHERE p.identity_key = ? AND s.message_count > 0
30
+ ORDER BY pins.pinned_at DESC
31
+ `).all(identityKey);
32
+ return rows.map(rowToSession);
33
+ }
34
+ function orderByClause(sortOrder) {
35
+ switch (sortOrder) {
36
+ case 'oldest':
37
+ return 's.started_at ASC';
38
+ case 'most_messages':
39
+ return 's.message_count DESC, s.started_at DESC';
40
+ case 'title':
41
+ return 'COALESCE(NULLIF(s.title, \'\'), \'\') ASC, s.started_at DESC';
42
+ case 'recent':
43
+ default:
44
+ return 's.started_at DESC';
45
+ }
46
+ }
47
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/projects/sessions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAW/D,MAAM,UAAU,sBAAsB,CACpC,EAAqB,EACrB,WAAmB,EACnB,UAAyC,EAAE;IAE3C,MAAM,EAAE,OAAO,EAAE,SAAS,GAAG,QAAQ,EAAE,KAAK,GAAG,GAAG,EAAE,aAAa,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IAErF,MAAM,UAAU,GAAa,CAAC,oBAAoB,EAAE,qBAAqB,CAAC,CAAA;IAC1E,MAAM,MAAM,GAAc,CAAC,WAAW,CAAC,CAAA;IAEvC,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACrD,UAAU,CAAC,IAAI,CAAC,gBAAgB,YAAY,GAAG,CAAC,CAAA;QAChD,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAA;IACzB,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,UAAU,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAA;IAC7F,CAAC;IAED,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;IACxC,MAAM,GAAG,GAAG;MACR,cAAc;YACR,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;eACrB,OAAO;;GAEnB,CAAA;IACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAElB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAmC,CAAA;IAC7E,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,EAAqB,EACrB,WAAmB;IAEnB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;MACpB,cAAc;;;;GAIjB,CAAC,CAAC,GAAG,CAAC,WAAW,CAAmC,CAAA;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;AAC/B,CAAC;AAED,SAAS,aAAa,CAAC,SAAkC;IACvD,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO,kBAAkB,CAAA;QAC3B,KAAK,eAAe;YAClB,OAAO,yCAAyC,CAAA;QAClD,KAAK,OAAO;YACV,OAAO,8DAA8D,CAAA;QACvE,KAAK,QAAQ,CAAC;QACd;YACE,OAAO,mBAAmB,CAAA;IAC9B,CAAC;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Recovers the upstream main-repo path of a worktree session whose `cwd`
3
+ * has already been deleted at sync time. This is the only signal that lets
4
+ * Spool group such sessions under their real project — Claude Code's JSONL
5
+ * carries `cwd` and `gitBranch` but no remote URL.
6
+ *
7
+ * Each implementation reads a worktree-tool-specific persistent store. If
8
+ * the store is missing or the cwd doesn't match anything, return null and
9
+ * the next resolver in the chain (or the existing path-kind fallback) wins.
10
+ */
11
+ export interface WorktreeUpstreamResolver {
12
+ name: string;
13
+ resolve(cwd: string): string | null;
14
+ }
15
+ /** Test hook: reset the in-process cache so tests can stub the DB. */
16
+ export declare function _resetSupersetCacheForTests(): void;
17
+ export declare const supersetResolver: WorktreeUpstreamResolver;
18
+ export declare const DEFAULT_RESOLVERS: readonly WorktreeUpstreamResolver[];
19
+ //# sourceMappingURL=worktree-resolvers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-resolvers.d.ts","sourceRoot":"","sources":["../../src/projects/worktree-resolvers.ts"],"names":[],"mappings":"AAYA;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CACpC;AAwCD,sEAAsE;AACtE,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED,eAAO,MAAM,gBAAgB,EAAE,wBAgB9B,CAAA;AAED,eAAO,MAAM,iBAAiB,EAAE,SAAS,wBAAwB,EAE/D,CAAA"}
@@ -0,0 +1,65 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import Database from 'better-sqlite3';
5
+ // Resolve home at call time (not module load) so tests can redirect via
6
+ // process.env.HOME. node:os.homedir() reads the OS user info on POSIX and
7
+ // ignores HOME, hence the explicit check first.
8
+ function getHome() {
9
+ return process.env['HOME'] || homedir();
10
+ }
11
+ function supersetDbPath() { return join(getHome(), '.superset', 'local.db'); }
12
+ function supersetDefaultBase() { return join(getHome(), '.superset', 'worktrees'); }
13
+ let _supersetCache = null;
14
+ function loadSupersetProjects() {
15
+ if (_supersetCache)
16
+ return _supersetCache;
17
+ const dbPath = supersetDbPath();
18
+ if (!existsSync(dbPath))
19
+ return null;
20
+ let db = null;
21
+ try {
22
+ db = new Database(dbPath, { readonly: true, fileMustExist: true });
23
+ const settings = db.prepare(`SELECT worktree_base_dir FROM settings WHERE id = 1`).get();
24
+ const globalBase = settings?.worktree_base_dir || supersetDefaultBase();
25
+ const projects = db.prepare(`SELECT name, main_repo_path, worktree_base_dir FROM projects`).all();
26
+ _supersetCache = { projects, globalBase };
27
+ return _supersetCache;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ finally {
33
+ try {
34
+ db?.close();
35
+ }
36
+ catch { /* ignore */ }
37
+ }
38
+ }
39
+ /** Test hook: reset the in-process cache so tests can stub the DB. */
40
+ export function _resetSupersetCacheForTests() {
41
+ _supersetCache = null;
42
+ }
43
+ export const supersetResolver = {
44
+ name: 'superset',
45
+ resolve(cwd) {
46
+ const data = loadSupersetProjects();
47
+ if (!data)
48
+ return null;
49
+ for (const p of data.projects) {
50
+ if (!p.main_repo_path)
51
+ continue;
52
+ const base = p.worktree_base_dir || data.globalBase;
53
+ // Convention enforced by superset: <base>/<project-name>/<branch>
54
+ const projectDir = join(base, p.name);
55
+ if (cwd === projectDir || cwd.startsWith(projectDir + '/')) {
56
+ return p.main_repo_path;
57
+ }
58
+ }
59
+ return null;
60
+ },
61
+ };
62
+ export const DEFAULT_RESOLVERS = Object.freeze([
63
+ supersetResolver,
64
+ ]);
65
+ //# sourceMappingURL=worktree-resolvers.js.map