myshell-tools 2.0.0-alpha.0 → 2.1.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 (60) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +6 -3
  3. package/dist/cli.js +85 -30
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/doctor.d.ts +3 -2
  6. package/dist/commands/doctor.js +9 -5
  7. package/dist/commands/doctor.js.map +1 -1
  8. package/dist/commands/login.d.ts +20 -0
  9. package/dist/commands/login.js +60 -0
  10. package/dist/commands/login.js.map +1 -0
  11. package/dist/core/orchestrate.js +80 -28
  12. package/dist/core/orchestrate.js.map +1 -1
  13. package/dist/core/policy.d.ts +10 -0
  14. package/dist/core/policy.js +40 -0
  15. package/dist/core/policy.js.map +1 -1
  16. package/dist/core/review.d.ts +5 -0
  17. package/dist/core/review.js +2 -2
  18. package/dist/core/review.js.map +1 -1
  19. package/dist/infra/atomic.d.ts +0 -3
  20. package/dist/infra/atomic.js +1 -1
  21. package/dist/infra/atomic.js.map +1 -1
  22. package/dist/infra/config.d.ts +23 -0
  23. package/dist/infra/config.js +64 -0
  24. package/dist/infra/config.js.map +1 -0
  25. package/dist/infra/conversation-store.d.ts +42 -0
  26. package/dist/infra/conversation-store.js +14 -0
  27. package/dist/infra/conversation-store.js.map +1 -0
  28. package/dist/infra/conversations.d.ts +18 -0
  29. package/dist/infra/conversations.js +296 -0
  30. package/dist/infra/conversations.js.map +1 -0
  31. package/dist/infra/insights.d.ts +66 -0
  32. package/dist/infra/insights.js +105 -0
  33. package/dist/infra/insights.js.map +1 -0
  34. package/dist/infra/ledger.d.ts +4 -6
  35. package/dist/infra/ledger.js.map +1 -1
  36. package/dist/interface/menu.d.ts +112 -0
  37. package/dist/interface/menu.js +622 -0
  38. package/dist/interface/menu.js.map +1 -0
  39. package/dist/providers/claude.d.ts +4 -13
  40. package/dist/providers/claude.js +5 -4
  41. package/dist/providers/claude.js.map +1 -1
  42. package/dist/providers/codex.d.ts +6 -12
  43. package/dist/providers/codex.js +6 -4
  44. package/dist/providers/codex.js.map +1 -1
  45. package/dist/providers/detect.d.ts +63 -14
  46. package/dist/providers/detect.js +123 -27
  47. package/dist/providers/detect.js.map +1 -1
  48. package/dist/ui/tui.d.ts +127 -0
  49. package/dist/ui/tui.js +316 -0
  50. package/dist/ui/tui.js.map +1 -0
  51. package/package.json +4 -1
  52. package/dist/core/index.d.ts +0 -13
  53. package/dist/core/index.js +0 -12
  54. package/dist/core/index.js.map +0 -1
  55. package/dist/infra/index.d.ts +0 -9
  56. package/dist/infra/index.js +0 -7
  57. package/dist/infra/index.js.map +0 -1
  58. package/dist/providers/index.d.ts +0 -9
  59. package/dist/providers/index.js +0 -7
  60. package/dist/providers/index.js.map +0 -1
@@ -24,4 +24,44 @@ export const DEFAULT_POLICY = {
24
24
  manager: ['claude', 'codex'],
25
25
  },
26
26
  };
27
+ /**
28
+ * Named policy presets selectable from the Settings screen.
29
+ *
30
+ * - cost-saver : raises escalation thresholds so it rarely escalates; stays
31
+ * on cheaper worker/IC tiers as long as possible.
32
+ * - balanced : identical to DEFAULT_POLICY; good for most work.
33
+ * - quality-first: lowers escalation thresholds so it escalates sooner and
34
+ * reviews more; prioritises quality over token cost.
35
+ */
36
+ export const POLICY_PRESETS = {
37
+ 'cost-saver': {
38
+ maxAttempts: 4,
39
+ escalateBelowConfidence: {
40
+ low: 0.2,
41
+ medium: 0.3,
42
+ high: 0.5,
43
+ critical: 0.65,
44
+ },
45
+ providerOrderByTier: {
46
+ worker: ['claude', 'codex'],
47
+ ic: ['claude', 'codex'],
48
+ manager: ['claude', 'codex'],
49
+ },
50
+ },
51
+ 'balanced': DEFAULT_POLICY,
52
+ 'quality-first': {
53
+ maxAttempts: 3,
54
+ escalateBelowConfidence: {
55
+ low: 0.6,
56
+ medium: 0.7,
57
+ high: 0.85,
58
+ critical: 0.92,
59
+ },
60
+ providerOrderByTier: {
61
+ worker: ['claude', 'codex'],
62
+ ic: ['claude', 'codex'],
63
+ manager: ['claude', 'codex'],
64
+ },
65
+ },
66
+ };
27
67
  //# sourceMappingURL=policy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/core/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,WAAW,EAAE,CAAC;IAEd,4EAA4E;IAC5E,6EAA6E;IAC7E,uBAAuB,EAAE;QACvB,GAAG,EAAE,GAAG;QACR,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,GAAG;KACd;IAED,8EAA8E;IAC9E,2EAA2E;IAC3E,2EAA2E;IAC3E,mBAAmB,EAAE;QACnB,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC3B,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;QACvB,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC7B;CACF,CAAC"}
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/core/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,WAAW,EAAE,CAAC;IAEd,4EAA4E;IAC5E,6EAA6E;IAC7E,uBAAuB,EAAE;QACvB,GAAG,EAAE,GAAG;QACR,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,GAAG;KACd;IAED,8EAA8E;IAC9E,2EAA2E;IAC3E,2EAA2E;IAC3E,mBAAmB,EAAE;QACnB,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC3B,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;QACvB,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC7B;CACF,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAgE;IACzF,YAAY,EAAE;QACZ,WAAW,EAAE,CAAC;QACd,uBAAuB,EAAE;YACvB,GAAG,EAAE,GAAG;YACR,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;SACf;QACD,mBAAmB,EAAE;YACnB,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC3B,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YACvB,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;SAC7B;KACF;IAED,UAAU,EAAE,cAAc;IAE1B,eAAe,EAAE;QACf,WAAW,EAAE,CAAC;QACd,uBAAuB,EAAE;YACvB,GAAG,EAAE,GAAG;YACR,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,IAAI;YACV,QAAQ,EAAE,IAAI;SACf;QACD,mBAAmB,EAAE;YACnB,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC3B,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YACvB,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;SAC7B;KACF;CACF,CAAC"}
@@ -16,11 +16,16 @@
16
16
  * - `approve` : IC output is acceptable; proceed to final.
17
17
  * - `revise` : IC output needs changes; retry IC with the reviewer's notes.
18
18
  * - `escalate` : The issue is beyond IC scope; escalate to manager tier.
19
+ * - `parsed` : True when a real verdict envelope was found and validated;
20
+ * false when the fail-open default was used. Callers should
21
+ * treat `parsed === false` on high/critical risk as
22
+ * inconclusive rather than approved.
19
23
  */
20
24
  export interface ReviewVerdict {
21
25
  readonly verdict: 'approve' | 'revise' | 'escalate';
22
26
  readonly notes: string;
23
27
  readonly confidence: number | null;
28
+ readonly parsed: boolean;
24
29
  }
25
30
  /**
26
31
  * Build a manager-style prompt asking the reviewer to critically assess the
@@ -61,7 +61,7 @@ confidence: your honest estimate that your review is complete and correct (1.0 =
61
61
  }
62
62
  const VALID_VERDICTS = new Set(['approve', 'revise', 'escalate']);
63
63
  /** Fail-open default used whenever the envelope is absent or malformed. */
64
- const FAIL_OPEN = { verdict: 'approve', notes: '', confidence: null };
64
+ const FAIL_OPEN = { verdict: 'approve', notes: '', confidence: null, parsed: false };
65
65
  /**
66
66
  * Attempt to extract the last JSON object from `text` that contains a `verdict` key.
67
67
  * Returns null if no valid envelope is found.
@@ -143,6 +143,6 @@ export function parseReviewVerdict(output) {
143
143
  if (typeof envelope.confidence === 'number' && isFinite(envelope.confidence)) {
144
144
  confidence = Math.min(1, Math.max(0, envelope.confidence));
145
145
  }
146
- return { verdict, notes, confidence };
146
+ return { verdict, notes, confidence, parsed: true };
147
147
  }
148
148
  //# sourceMappingURL=review.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/core/review.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/core/review.ts"],"names":[],"mappings":"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"}
@@ -15,9 +15,6 @@ export interface LockOptions {
15
15
  export declare class LockTimeoutError extends Error {
16
16
  constructor(lockPath: string, timeoutMs: number);
17
17
  }
18
- export declare class AtomicWriteError extends Error {
19
- constructor(filePath: string, cause: unknown);
20
- }
21
18
  /**
22
19
  * Acquire a `.lock` file using `O_EXCL` for atomic creation.
23
20
  * Retries with exponential backoff until `timeoutMs` is reached.
@@ -15,7 +15,7 @@ export class LockTimeoutError extends Error {
15
15
  this.name = 'LockTimeoutError';
16
16
  }
17
17
  }
18
- export class AtomicWriteError extends Error {
18
+ class AtomicWriteError extends Error {
19
19
  constructor(filePath, cause) {
20
20
  super(`Atomic write failed for: ${filePath} — ${cause instanceof Error ? cause.message : String(cause)}`);
21
21
  this.name = 'AtomicWriteError';
@@ -1 +1 @@
1
- {"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../src/infra/atomic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../src/infra/atomic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * src/infra/config.ts — Global app configuration persisted at
3
+ * <homeDir>/.myshell-tools/config.json.
4
+ *
5
+ * Reads merge over defaults so that new keys added in future versions are
6
+ * always present even when the on-disk file pre-dates them.
7
+ */
8
+ export interface AppConfig {
9
+ onboarded: boolean;
10
+ setAsDefault: boolean;
11
+ /** Active routing mode. Absent → use DEFAULT_POLICY (same as 'balanced'). */
12
+ mode?: 'cost-saver' | 'balanced' | 'quality-first';
13
+ }
14
+ /**
15
+ * Load the global app config. Returns defaults merged with any on-disk
16
+ * values so unknown/corrupt files never throw and new keys are always present.
17
+ */
18
+ export declare function loadConfig(homeDir?: string): Promise<AppConfig>;
19
+ /**
20
+ * Persist the app config atomically. Creates the `.myshell-tools` directory
21
+ * if it does not exist.
22
+ */
23
+ export declare function saveConfig(config: AppConfig, homeDir?: string): Promise<void>;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * src/infra/config.ts — Global app configuration persisted at
3
+ * <homeDir>/.myshell-tools/config.json.
4
+ *
5
+ * Reads merge over defaults so that new keys added in future versions are
6
+ * always present even when the on-disk file pre-dates them.
7
+ */
8
+ import { mkdir, readFile } from 'node:fs/promises';
9
+ import { homedir } from 'node:os';
10
+ import { join } from 'node:path';
11
+ import { atomicWrite } from './atomic.js';
12
+ // ---------------------------------------------------------------------------
13
+ // Defaults
14
+ // ---------------------------------------------------------------------------
15
+ const DEFAULTS = {
16
+ onboarded: false,
17
+ setAsDefault: false,
18
+ };
19
+ // ---------------------------------------------------------------------------
20
+ // Path helpers
21
+ // ---------------------------------------------------------------------------
22
+ function getConfigDir(homeDir) {
23
+ return join(homeDir, '.myshell-tools');
24
+ }
25
+ function getConfigPath(homeDir) {
26
+ return join(getConfigDir(homeDir), 'config.json');
27
+ }
28
+ // ---------------------------------------------------------------------------
29
+ // Public API
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Load the global app config. Returns defaults merged with any on-disk
33
+ * values so unknown/corrupt files never throw and new keys are always present.
34
+ */
35
+ export async function loadConfig(homeDir) {
36
+ const home = homeDir ?? homedir();
37
+ let raw;
38
+ try {
39
+ raw = await readFile(getConfigPath(home), 'utf8');
40
+ }
41
+ catch {
42
+ // Missing file — return defaults
43
+ return { ...DEFAULTS };
44
+ }
45
+ try {
46
+ const parsed = JSON.parse(raw);
47
+ // Merge: defaults first, then on-disk values (new keys default safely)
48
+ return { ...DEFAULTS, ...parsed };
49
+ }
50
+ catch {
51
+ // Corrupt JSON — return defaults
52
+ return { ...DEFAULTS };
53
+ }
54
+ }
55
+ /**
56
+ * Persist the app config atomically. Creates the `.myshell-tools` directory
57
+ * if it does not exist.
58
+ */
59
+ export async function saveConfig(config, homeDir) {
60
+ const home = homeDir ?? homedir();
61
+ await mkdir(getConfigDir(home), { recursive: true });
62
+ await atomicWrite(getConfigPath(home), JSON.stringify(config, null, 2));
63
+ }
64
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/infra/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAa1C,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E,MAAM,QAAQ,GAAc;IAC1B,SAAS,EAAE,KAAK;IAChB,YAAY,EAAE,KAAK;CACpB,CAAC;AAEF,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,SAAS,YAAY,CAAC,OAAe;IACnC,OAAO,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,CAAC;AACpD,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAgB;IAC/C,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC;IAClC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,iCAAiC;QACjC,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;QACrD,uEAAuE;QACvE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,iCAAiC;QACjC,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAiB,EAAE,OAAgB;IAClE,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC;IAClC,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * src/infra/conversation-store.ts — the persistent conversation contract.
3
+ *
4
+ * The menu UX manages multiple named, persistent conversations. This is the
5
+ * port both the file-backed implementation (infra) and the menu (interface)
6
+ * build against. Conversations live in a GLOBAL store (the user's home dir) so
7
+ * they follow the user across projects; each one is an append-only message log
8
+ * plus lightweight metadata.
9
+ *
10
+ * A conversation's `SessionWriter` is what gets injected into orchestrate() so a
11
+ * run's messages persist into that conversation.
12
+ */
13
+ import type { SessionEntry, SessionWriter } from '../core/types.js';
14
+ export interface ConversationMeta {
15
+ readonly id: string;
16
+ readonly title: string;
17
+ readonly createdAt: string;
18
+ readonly updatedAt: string;
19
+ readonly messageCount: number;
20
+ /** Whether this conversation is pinned (sorted to the top of the list). */
21
+ readonly pinned: boolean;
22
+ /** Optional short category tag (e.g. "ui", "refactor"); null when unset. */
23
+ readonly category: string | null;
24
+ }
25
+ export interface ConversationStore {
26
+ /** All conversations, pinned first then most-recently-updated first. */
27
+ list(): Promise<ConversationMeta[]>;
28
+ /** Create a new conversation; returns its metadata (with a fresh id). */
29
+ create(title: string): Promise<ConversationMeta>;
30
+ /** Read a conversation's full message history (oldest first); [] if missing. */
31
+ load(id: string): Promise<SessionEntry[]>;
32
+ /** Rename a conversation. No-op if the id does not exist. */
33
+ rename(id: string, title: string): Promise<void>;
34
+ /** Delete a conversation and its messages. No-op if missing. */
35
+ remove(id: string): Promise<void>;
36
+ /** A SessionWriter bound to `id` — appends entries and bumps updatedAt/count. */
37
+ writer(id: string): SessionWriter;
38
+ /** Pin or unpin a conversation. No-op if the id does not exist. */
39
+ setPinned(id: string, pinned: boolean): Promise<void>;
40
+ /** Set or clear the category tag for a conversation. No-op if id missing. */
41
+ setCategory(id: string, category: string | null): Promise<void>;
42
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * src/infra/conversation-store.ts — the persistent conversation contract.
3
+ *
4
+ * The menu UX manages multiple named, persistent conversations. This is the
5
+ * port both the file-backed implementation (infra) and the menu (interface)
6
+ * build against. Conversations live in a GLOBAL store (the user's home dir) so
7
+ * they follow the user across projects; each one is an append-only message log
8
+ * plus lightweight metadata.
9
+ *
10
+ * A conversation's `SessionWriter` is what gets injected into orchestrate() so a
11
+ * run's messages persist into that conversation.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=conversation-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-store.js","sourceRoot":"","sources":["../../src/infra/conversation-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * src/infra/conversations.ts — File-backed ConversationStore implementation.
3
+ *
4
+ * Storage layout under <homeDir>/.myshell-tools/conversations/:
5
+ * index.json — JSON array of ConversationMeta, newest first
6
+ * index.json.lock — advisory lock for concurrent index mutations
7
+ * <id>.jsonl — one SessionEntry per line (append-only message log)
8
+ */
9
+ import type { Clock } from '../core/types.js';
10
+ import type { ConversationStore } from './conversation-store.js';
11
+ /**
12
+ * Create a file-backed ConversationStore that persists conversations under
13
+ * `<homeDir ?? os.homedir()>/.myshell-tools/conversations/`.
14
+ */
15
+ export declare function createFileConversationStore(opts: {
16
+ homeDir?: string;
17
+ clock: Clock;
18
+ }): ConversationStore;
@@ -0,0 +1,296 @@
1
+ /**
2
+ * src/infra/conversations.ts — File-backed ConversationStore implementation.
3
+ *
4
+ * Storage layout under <homeDir>/.myshell-tools/conversations/:
5
+ * index.json — JSON array of ConversationMeta, newest first
6
+ * index.json.lock — advisory lock for concurrent index mutations
7
+ * <id>.jsonl — one SessionEntry per line (append-only message log)
8
+ */
9
+ import { mkdir, readFile, unlink } from 'node:fs/promises';
10
+ import { homedir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ import { atomicAppendJSONL, atomicWrite, withLock } from './atomic.js';
13
+ // ---------------------------------------------------------------------------
14
+ // Path helpers (local — conversations dir lives in homeDir, not cwd)
15
+ // ---------------------------------------------------------------------------
16
+ function getConversationsDir(homeDir) {
17
+ return join(homeDir, '.myshell-tools', 'conversations');
18
+ }
19
+ function getIndexPath(homeDir) {
20
+ return join(getConversationsDir(homeDir), 'index.json');
21
+ }
22
+ function getIndexLockPath(homeDir) {
23
+ return join(getConversationsDir(homeDir), 'index.json.lock');
24
+ }
25
+ function getMessagePath(homeDir, id) {
26
+ return join(getConversationsDir(homeDir), `${id}.jsonl`);
27
+ }
28
+ // ---------------------------------------------------------------------------
29
+ // Internal index helpers
30
+ // ---------------------------------------------------------------------------
31
+ async function ensureDir(homeDir) {
32
+ await mkdir(getConversationsDir(homeDir), { recursive: true });
33
+ }
34
+ /**
35
+ * Normalise a raw index entry that may be missing fields added in later
36
+ * versions (pinned, category). Old on-disk entries that predate these fields
37
+ * will be migrated transparently on read so existing stores keep working.
38
+ */
39
+ function normaliseMeta(raw) {
40
+ const r = raw;
41
+ return {
42
+ id: String(r['id'] ?? ''),
43
+ title: String(r['title'] ?? ''),
44
+ createdAt: String(r['createdAt'] ?? ''),
45
+ updatedAt: String(r['updatedAt'] ?? ''),
46
+ messageCount: typeof r['messageCount'] === 'number' ? r['messageCount'] : 0,
47
+ pinned: typeof r['pinned'] === 'boolean' ? r['pinned'] : false,
48
+ category: typeof r['category'] === 'string' ? r['category'] : null,
49
+ };
50
+ }
51
+ async function readIndex(homeDir) {
52
+ try {
53
+ const raw = await readFile(getIndexPath(homeDir), 'utf8');
54
+ const parsed = JSON.parse(raw);
55
+ if (!Array.isArray(parsed))
56
+ return [];
57
+ return parsed.map(normaliseMeta);
58
+ }
59
+ catch {
60
+ return [];
61
+ }
62
+ }
63
+ async function writeIndex(homeDir, index) {
64
+ await atomicWrite(getIndexPath(homeDir), JSON.stringify(index, null, 2));
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Title extraction: trim + truncate to 80 chars
68
+ // ---------------------------------------------------------------------------
69
+ const MAX_TITLE_LEN = 80;
70
+ function deriveTitle(content) {
71
+ const trimmed = content.trim();
72
+ return trimmed.length <= MAX_TITLE_LEN ? trimmed : trimmed.slice(0, MAX_TITLE_LEN);
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Factory
76
+ // ---------------------------------------------------------------------------
77
+ /**
78
+ * Create a file-backed ConversationStore that persists conversations under
79
+ * `<homeDir ?? os.homedir()>/.myshell-tools/conversations/`.
80
+ */
81
+ export function createFileConversationStore(opts) {
82
+ const { clock } = opts;
83
+ const home = opts.homeDir ?? homedir();
84
+ return {
85
+ // -----------------------------------------------------------------------
86
+ // list
87
+ // -----------------------------------------------------------------------
88
+ async list() {
89
+ const index = await readIndex(home);
90
+ return [...index].sort((a, b) => {
91
+ // Pinned items always come before unpinned
92
+ if (a.pinned !== b.pinned)
93
+ return a.pinned ? -1 : 1;
94
+ // Within the same pin group, most-recently-updated first
95
+ return a.updatedAt < b.updatedAt ? 1 : -1;
96
+ });
97
+ },
98
+ // -----------------------------------------------------------------------
99
+ // create
100
+ // -----------------------------------------------------------------------
101
+ async create(title) {
102
+ await ensureDir(home);
103
+ const id = clock.uuid();
104
+ const now = clock.isoNow();
105
+ const meta = {
106
+ id,
107
+ title,
108
+ createdAt: now,
109
+ updatedAt: now,
110
+ messageCount: 0,
111
+ pinned: false,
112
+ category: null,
113
+ };
114
+ await withLock(getIndexLockPath(home), async () => {
115
+ const index = await readIndex(home);
116
+ await writeIndex(home, [meta, ...index]);
117
+ });
118
+ return meta;
119
+ },
120
+ // -----------------------------------------------------------------------
121
+ // load
122
+ // -----------------------------------------------------------------------
123
+ async load(id) {
124
+ let raw;
125
+ try {
126
+ raw = await readFile(getMessagePath(home, id), 'utf8');
127
+ }
128
+ catch (err) {
129
+ const nodeErr = err;
130
+ if (nodeErr.code === 'ENOENT')
131
+ return [];
132
+ throw err;
133
+ }
134
+ const entries = [];
135
+ for (const line of raw.split('\n')) {
136
+ const trimmed = line.trim();
137
+ if (trimmed.length === 0)
138
+ continue;
139
+ try {
140
+ entries.push(JSON.parse(trimmed));
141
+ }
142
+ catch {
143
+ // Skip malformed lines
144
+ }
145
+ }
146
+ return entries;
147
+ },
148
+ // -----------------------------------------------------------------------
149
+ // writer
150
+ // -----------------------------------------------------------------------
151
+ writer(id) {
152
+ return {
153
+ id,
154
+ async append(entry) {
155
+ await ensureDir(home);
156
+ // Append the entry to the conversation's JSONL file
157
+ await atomicAppendJSONL(getMessagePath(home, id), entry);
158
+ // Update index under lock
159
+ await withLock(getIndexLockPath(home), async () => {
160
+ const index = await readIndex(home);
161
+ const idx = index.findIndex((m) => m.id === id);
162
+ if (idx === -1)
163
+ return;
164
+ const existing = index[idx];
165
+ if (existing === undefined)
166
+ return;
167
+ const updatedAt = clock.isoNow();
168
+ const messageCount = existing.messageCount + 1;
169
+ // If this is a user message and the title is still the placeholder,
170
+ // use the message content as the title (first user message wins).
171
+ let title = existing.title;
172
+ if (entry.role === 'user' &&
173
+ entry.content &&
174
+ (title.trim().length === 0 || title === existing.title) &&
175
+ existing.messageCount === 0) {
176
+ title = deriveTitle(entry.content);
177
+ }
178
+ const updated = {
179
+ id: existing.id,
180
+ title,
181
+ createdAt: existing.createdAt,
182
+ updatedAt,
183
+ messageCount,
184
+ pinned: existing.pinned,
185
+ category: existing.category,
186
+ };
187
+ const newIndex = [...index];
188
+ newIndex[idx] = updated;
189
+ await writeIndex(home, newIndex);
190
+ });
191
+ },
192
+ };
193
+ },
194
+ // -----------------------------------------------------------------------
195
+ // rename
196
+ // -----------------------------------------------------------------------
197
+ async rename(id, title) {
198
+ await withLock(getIndexLockPath(home), async () => {
199
+ const index = await readIndex(home);
200
+ const idx = index.findIndex((m) => m.id === id);
201
+ if (idx === -1)
202
+ return;
203
+ const existing = index[idx];
204
+ if (existing === undefined)
205
+ return;
206
+ const updated = {
207
+ id: existing.id,
208
+ title,
209
+ createdAt: existing.createdAt,
210
+ updatedAt: existing.updatedAt,
211
+ messageCount: existing.messageCount,
212
+ pinned: existing.pinned,
213
+ category: existing.category,
214
+ };
215
+ const newIndex = [...index];
216
+ newIndex[idx] = updated;
217
+ await writeIndex(home, newIndex);
218
+ });
219
+ },
220
+ // -----------------------------------------------------------------------
221
+ // remove
222
+ // -----------------------------------------------------------------------
223
+ async remove(id) {
224
+ // Best-effort delete of message file
225
+ try {
226
+ await unlink(getMessagePath(home, id));
227
+ }
228
+ catch {
229
+ // Missing or already gone — ignore
230
+ }
231
+ // Remove from index under lock
232
+ await withLock(getIndexLockPath(home), async () => {
233
+ const index = await readIndex(home);
234
+ const filtered = index.filter((m) => m.id !== id);
235
+ if (filtered.length === index.length)
236
+ return; // not found, no-op
237
+ await writeIndex(home, filtered);
238
+ });
239
+ },
240
+ // -----------------------------------------------------------------------
241
+ // setPinned
242
+ // -----------------------------------------------------------------------
243
+ async setPinned(id, pinned) {
244
+ await ensureDir(home);
245
+ await withLock(getIndexLockPath(home), async () => {
246
+ const index = await readIndex(home);
247
+ const idx = index.findIndex((m) => m.id === id);
248
+ if (idx === -1)
249
+ return; // no-op if missing
250
+ const existing = index[idx];
251
+ if (existing === undefined)
252
+ return;
253
+ const updated = {
254
+ id: existing.id,
255
+ title: existing.title,
256
+ createdAt: existing.createdAt,
257
+ updatedAt: existing.updatedAt,
258
+ messageCount: existing.messageCount,
259
+ pinned,
260
+ category: existing.category,
261
+ };
262
+ const newIndex = [...index];
263
+ newIndex[idx] = updated;
264
+ await writeIndex(home, newIndex);
265
+ });
266
+ },
267
+ // -----------------------------------------------------------------------
268
+ // setCategory
269
+ // -----------------------------------------------------------------------
270
+ async setCategory(id, category) {
271
+ await ensureDir(home);
272
+ await withLock(getIndexLockPath(home), async () => {
273
+ const index = await readIndex(home);
274
+ const idx = index.findIndex((m) => m.id === id);
275
+ if (idx === -1)
276
+ return; // no-op if missing
277
+ const existing = index[idx];
278
+ if (existing === undefined)
279
+ return;
280
+ const updated = {
281
+ id: existing.id,
282
+ title: existing.title,
283
+ createdAt: existing.createdAt,
284
+ updatedAt: existing.updatedAt,
285
+ messageCount: existing.messageCount,
286
+ pinned: existing.pinned,
287
+ category,
288
+ };
289
+ const newIndex = [...index];
290
+ newIndex[idx] = updated;
291
+ await writeIndex(home, newIndex);
292
+ });
293
+ },
294
+ };
295
+ }
296
+ //# sourceMappingURL=conversations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../src/infra/conversations.ts"],"names":[],"mappings":"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"}