myshell-tools 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +44 -69
  2. package/LICENSE +21 -21
  3. package/README.md +178 -318
  4. package/dist/cli.d.ts +8 -0
  5. package/dist/cli.js +130 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/cost.d.ts +36 -0
  8. package/dist/commands/cost.js +103 -0
  9. package/dist/commands/cost.js.map +1 -0
  10. package/dist/commands/doctor.d.ts +36 -0
  11. package/dist/commands/doctor.js +115 -0
  12. package/dist/commands/doctor.js.map +1 -0
  13. package/dist/commands/login.d.ts +20 -0
  14. package/dist/commands/login.js +60 -0
  15. package/dist/commands/login.js.map +1 -0
  16. package/dist/core/assess.d.ts +25 -0
  17. package/dist/core/assess.js +142 -0
  18. package/dist/core/assess.js.map +1 -0
  19. package/dist/core/classify.d.ts +19 -0
  20. package/dist/core/classify.js +80 -0
  21. package/dist/core/classify.js.map +1 -0
  22. package/dist/core/escalate.d.ts +32 -0
  23. package/dist/core/escalate.js +57 -0
  24. package/dist/core/escalate.js.map +1 -0
  25. package/dist/core/index.d.ts +13 -0
  26. package/dist/core/index.js +12 -0
  27. package/dist/core/index.js.map +1 -0
  28. package/dist/core/orchestrate.d.ts +42 -0
  29. package/dist/core/orchestrate.js +439 -0
  30. package/dist/core/orchestrate.js.map +1 -0
  31. package/dist/core/policy.d.ts +9 -0
  32. package/dist/core/policy.js +27 -0
  33. package/dist/core/policy.js.map +1 -0
  34. package/dist/core/prompt.d.ts +26 -0
  35. package/dist/core/prompt.js +125 -0
  36. package/dist/core/prompt.js.map +1 -0
  37. package/dist/core/review.d.ts +46 -0
  38. package/dist/core/review.js +148 -0
  39. package/dist/core/review.js.map +1 -0
  40. package/dist/core/route.d.ts +28 -0
  41. package/dist/core/route.js +52 -0
  42. package/dist/core/route.js.map +1 -0
  43. package/dist/core/types.d.ts +141 -0
  44. package/dist/core/types.js +14 -0
  45. package/dist/core/types.js.map +1 -0
  46. package/dist/infra/atomic.d.ts +53 -0
  47. package/dist/infra/atomic.js +171 -0
  48. package/dist/infra/atomic.js.map +1 -0
  49. package/dist/infra/clock.d.ts +9 -0
  50. package/dist/infra/clock.js +15 -0
  51. package/dist/infra/clock.js.map +1 -0
  52. package/dist/infra/index.d.ts +9 -0
  53. package/dist/infra/index.js +7 -0
  54. package/dist/infra/index.js.map +1 -0
  55. package/dist/infra/ledger.d.ts +49 -0
  56. package/dist/infra/ledger.js +90 -0
  57. package/dist/infra/ledger.js.map +1 -0
  58. package/dist/infra/paths.d.ts +28 -0
  59. package/dist/infra/paths.js +38 -0
  60. package/dist/infra/paths.js.map +1 -0
  61. package/dist/infra/pricing.d.ts +47 -0
  62. package/dist/infra/pricing.js +151 -0
  63. package/dist/infra/pricing.js.map +1 -0
  64. package/dist/infra/session.d.ts +28 -0
  65. package/dist/infra/session.js +61 -0
  66. package/dist/infra/session.js.map +1 -0
  67. package/dist/interface/render.d.ts +27 -0
  68. package/dist/interface/render.js +134 -0
  69. package/dist/interface/render.js.map +1 -0
  70. package/dist/interface/repl.d.ts +23 -0
  71. package/dist/interface/repl.js +90 -0
  72. package/dist/interface/repl.js.map +1 -0
  73. package/dist/interface/run.d.ts +20 -0
  74. package/dist/interface/run.js +31 -0
  75. package/dist/interface/run.js.map +1 -0
  76. package/dist/providers/claude-parse.d.ts +24 -0
  77. package/dist/providers/claude-parse.js +113 -0
  78. package/dist/providers/claude-parse.js.map +1 -0
  79. package/dist/providers/claude.d.ts +45 -0
  80. package/dist/providers/claude.js +122 -0
  81. package/dist/providers/claude.js.map +1 -0
  82. package/dist/providers/codex-parse.d.ts +32 -0
  83. package/dist/providers/codex-parse.js +145 -0
  84. package/dist/providers/codex-parse.js.map +1 -0
  85. package/dist/providers/codex.d.ts +44 -0
  86. package/dist/providers/codex.js +124 -0
  87. package/dist/providers/codex.js.map +1 -0
  88. package/dist/providers/detect.d.ts +49 -0
  89. package/dist/providers/detect.js +125 -0
  90. package/dist/providers/detect.js.map +1 -0
  91. package/dist/providers/errors.d.ts +49 -0
  92. package/dist/providers/errors.js +189 -0
  93. package/dist/providers/errors.js.map +1 -0
  94. package/dist/providers/index.d.ts +9 -0
  95. package/dist/providers/index.js +7 -0
  96. package/dist/providers/index.js.map +1 -0
  97. package/dist/providers/port.d.ts +74 -0
  98. package/dist/providers/port.js +16 -0
  99. package/dist/providers/port.js.map +1 -0
  100. package/dist/providers/registry.d.ts +21 -0
  101. package/dist/providers/registry.js +34 -0
  102. package/dist/providers/registry.js.map +1 -0
  103. package/dist/ui/banner.d.ts +19 -0
  104. package/dist/ui/banner.js +32 -0
  105. package/dist/ui/banner.js.map +1 -0
  106. package/dist/ui/spinner.d.ts +27 -0
  107. package/dist/ui/spinner.js +67 -0
  108. package/dist/ui/spinner.js.map +1 -0
  109. package/dist/ui/theme.d.ts +32 -0
  110. package/dist/ui/theme.js +56 -0
  111. package/dist/ui/theme.js.map +1 -0
  112. package/package.json +55 -49
  113. package/data/orchestrator.json +0 -113
  114. package/src/auth/recovery.mjs +0 -328
  115. package/src/auth/refresh.mjs +0 -373
  116. package/src/chef.mjs +0 -348
  117. package/src/cli/doctor.mjs +0 -568
  118. package/src/cli/reset.mjs +0 -447
  119. package/src/cli/status.mjs +0 -379
  120. package/src/cli.mjs +0 -429
  121. package/src/commands/doctor.mjs +0 -375
  122. package/src/commands/help.mjs +0 -324
  123. package/src/commands/status.mjs +0 -331
  124. package/src/monitor/health.mjs +0 -486
  125. package/src/monitor/performance.mjs +0 -442
  126. package/src/monitor/report.mjs +0 -535
  127. package/src/orchestrator/classify.mjs +0 -391
  128. package/src/orchestrator/confidence.mjs +0 -151
  129. package/src/orchestrator/handoffs.mjs +0 -231
  130. package/src/orchestrator/review.mjs +0 -222
  131. package/src/providers/balance.mjs +0 -201
  132. package/src/providers/claude.mjs +0 -236
  133. package/src/providers/codex.mjs +0 -255
  134. package/src/providers/detect.mjs +0 -185
  135. package/src/providers/errors.mjs +0 -373
  136. package/src/providers/select.mjs +0 -162
  137. package/src/repl-enhanced.mjs +0 -417
  138. package/src/repl.mjs +0 -321
  139. package/src/state/archive.mjs +0 -366
  140. package/src/state/atomic.mjs +0 -116
  141. package/src/state/cleanup.mjs +0 -440
  142. package/src/state/recovery.mjs +0 -461
  143. package/src/state/session.mjs +0 -147
  144. package/src/ui/errors.mjs +0 -456
  145. package/src/ui/formatter.mjs +0 -327
  146. package/src/ui/icons.mjs +0 -318
  147. package/src/ui/progress.mjs +0 -468
  148. package/templates/prompts/confidence-format.txt +0 -14
  149. package/templates/prompts/ic-with-feedback.txt +0 -41
  150. package/templates/prompts/ic.txt +0 -13
  151. package/templates/prompts/manager-review.txt +0 -40
  152. package/templates/prompts/manager.txt +0 -14
  153. package/templates/prompts/worker.txt +0 -12
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../src/infra/atomic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * src/infra/clock.ts — System clock implementation of the Clock port.
3
+ *
4
+ * This is the SINGLE place in the codebase where impure time/random globals
5
+ * (Date, Math.random, randomUUID) are allowed. All other modules receive a
6
+ * Clock via injection, keeping them pure and testable.
7
+ */
8
+ import type { Clock } from '../core/types.js';
9
+ export declare const systemClock: Clock;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * src/infra/clock.ts — System clock implementation of the Clock port.
3
+ *
4
+ * This is the SINGLE place in the codebase where impure time/random globals
5
+ * (Date, Math.random, randomUUID) are allowed. All other modules receive a
6
+ * Clock via injection, keeping them pure and testable.
7
+ */
8
+ import { randomUUID } from 'node:crypto';
9
+ export const systemClock = {
10
+ now: () => Date.now(),
11
+ isoNow: () => new Date().toISOString(),
12
+ uuid: () => randomUUID(),
13
+ random: () => Math.random(),
14
+ };
15
+ //# sourceMappingURL=clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../../src/infra/clock.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,CAAC,MAAM,WAAW,GAAU;IAChC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;IACrB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;IACtC,IAAI,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;IACxB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE;CAC5B,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { acquireLock, releaseLock, withLock, atomicWrite, atomicAppendJSONL } from './atomic.js';
2
+ export type { LockOptions } from './atomic.js';
3
+ export { getModelPricing, calculateCost, getCheapestForTier, isPricingStale, PRICING_TABLE, } from './pricing.js';
4
+ export type { ModelPricing, PricingTable } from './pricing.js';
5
+ export { systemClock } from './clock.js';
6
+ export { getStateDir, getSessionsDir, getSessionFile, getLedgerFile } from './paths.js';
7
+ export { createSessionWriter, readSession } from './session.js';
8
+ export { createLedger, readLedger, summarizeLedger } from './ledger.js';
9
+ export type { ModelSummary, LedgerSummary } from './ledger.js';
@@ -0,0 +1,7 @@
1
+ export { acquireLock, releaseLock, withLock, atomicWrite, atomicAppendJSONL } from './atomic.js';
2
+ export { getModelPricing, calculateCost, getCheapestForTier, isPricingStale, PRICING_TABLE, } from './pricing.js';
3
+ export { systemClock } from './clock.js';
4
+ export { getStateDir, getSessionsDir, getSessionFile, getLedgerFile } from './paths.js';
5
+ export { createSessionWriter, readSession } from './session.js';
6
+ export { createLedger, readLedger, summarizeLedger } from './ledger.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/infra/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEjG,OAAO,EACL,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,aAAa,GACd,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * src/infra/ledger.ts — LedgerWriter implementation, ledger reader, and summarizer.
3
+ *
4
+ * The ledger is a JSONL file at `.myshell-tools/ledger.jsonl`. Each `record` call appends
5
+ * one LedgerEntry atomically. `readLedger` re-hydrates entries (skipping malformed
6
+ * lines). `summarizeLedger` is a pure reduction used by `myshell-tools cost`.
7
+ */
8
+ import type { LedgerEntry, LedgerWriter } from '../core/types.js';
9
+ /**
10
+ * Create a LedgerWriter for the given working directory.
11
+ *
12
+ * @param opts.cwd - The project working directory (parent of `.myshell-tools/`).
13
+ */
14
+ export declare function createLedger(opts: {
15
+ cwd: string;
16
+ }): LedgerWriter;
17
+ /**
18
+ * Read all LedgerEntry records from the ledger JSONL file.
19
+ *
20
+ * Returns an empty array if the file does not exist. Malformed lines are
21
+ * silently skipped.
22
+ *
23
+ * @param cwd - The project working directory.
24
+ */
25
+ export declare function readLedger(cwd: string): Promise<LedgerEntry[]>;
26
+ /** Per-model aggregation used in the summary. */
27
+ export interface ModelSummary {
28
+ readonly calls: number;
29
+ readonly usd: number;
30
+ }
31
+ /** Aggregate summary returned by `summarizeLedger`. */
32
+ export interface LedgerSummary {
33
+ readonly totalUsd: number;
34
+ readonly calls: number;
35
+ readonly byModel: Record<string, ModelSummary>;
36
+ }
37
+ /**
38
+ * Pure reduction over a ledger entry array.
39
+ *
40
+ * Computes:
41
+ * - `totalUsd` — sum of all `entry.usd` values
42
+ * - `calls` — total number of entries
43
+ * - `byModel` — per-model breakdown keyed by `entry.model`
44
+ *
45
+ * No I/O. Safe to call in tests with hand-built arrays.
46
+ *
47
+ * @param entries - Array of LedgerEntry objects (may be empty).
48
+ */
49
+ export declare function summarizeLedger(entries: LedgerEntry[]): LedgerSummary;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * src/infra/ledger.ts — LedgerWriter implementation, ledger reader, and summarizer.
3
+ *
4
+ * The ledger is a JSONL file at `.myshell-tools/ledger.jsonl`. Each `record` call appends
5
+ * one LedgerEntry atomically. `readLedger` re-hydrates entries (skipping malformed
6
+ * lines). `summarizeLedger` is a pure reduction used by `myshell-tools cost`.
7
+ */
8
+ import { mkdir, readFile } from 'node:fs/promises';
9
+ import { atomicAppendJSONL } from './atomic.js';
10
+ import { getStateDir, getLedgerFile } from './paths.js';
11
+ /**
12
+ * Create a LedgerWriter for the given working directory.
13
+ *
14
+ * @param opts.cwd - The project working directory (parent of `.myshell-tools/`).
15
+ */
16
+ export function createLedger(opts) {
17
+ const { cwd } = opts;
18
+ return {
19
+ async record(entry) {
20
+ await mkdir(getStateDir(cwd), { recursive: true });
21
+ await atomicAppendJSONL(getLedgerFile(cwd), entry);
22
+ },
23
+ };
24
+ }
25
+ /**
26
+ * Read all LedgerEntry records from the ledger JSONL file.
27
+ *
28
+ * Returns an empty array if the file does not exist. Malformed lines are
29
+ * silently skipped.
30
+ *
31
+ * @param cwd - The project working directory.
32
+ */
33
+ export async function readLedger(cwd) {
34
+ let raw;
35
+ try {
36
+ raw = await readFile(getLedgerFile(cwd), 'utf8');
37
+ }
38
+ catch (err) {
39
+ const nodeErr = err;
40
+ if (nodeErr.code === 'ENOENT')
41
+ return [];
42
+ throw err;
43
+ }
44
+ const entries = [];
45
+ for (const line of raw.split('\n')) {
46
+ const trimmed = line.trim();
47
+ if (trimmed.length === 0)
48
+ continue;
49
+ try {
50
+ entries.push(JSON.parse(trimmed));
51
+ }
52
+ catch {
53
+ // Skip malformed lines
54
+ }
55
+ }
56
+ return entries;
57
+ }
58
+ /**
59
+ * Pure reduction over a ledger entry array.
60
+ *
61
+ * Computes:
62
+ * - `totalUsd` — sum of all `entry.usd` values
63
+ * - `calls` — total number of entries
64
+ * - `byModel` — per-model breakdown keyed by `entry.model`
65
+ *
66
+ * No I/O. Safe to call in tests with hand-built arrays.
67
+ *
68
+ * @param entries - Array of LedgerEntry objects (may be empty).
69
+ */
70
+ export function summarizeLedger(entries) {
71
+ let totalUsd = 0;
72
+ const byModel = {};
73
+ for (const entry of entries) {
74
+ totalUsd += entry.usd;
75
+ const existing = byModel[entry.model];
76
+ if (existing !== undefined) {
77
+ existing.calls += 1;
78
+ existing.usd += entry.usd;
79
+ }
80
+ else {
81
+ byModel[entry.model] = { calls: 1, usd: entry.usd };
82
+ }
83
+ }
84
+ return {
85
+ totalUsd,
86
+ calls: entries.length,
87
+ byModel,
88
+ };
89
+ }
90
+ //# sourceMappingURL=ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/infra/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAExD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAqB;IAChD,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAErB,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,KAAkB;YAC7B,MAAM,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,iBAAiB,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACrD,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAA4B,CAAC;QAC7C,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QACzC,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACnC,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAeD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,OAAsB;IACpD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,OAAO,GAAmD,EAAE,CAAC;IAEnE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC;QAEtB,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;YACpB,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;QACtD,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ;QACR,KAAK,EAAE,OAAO,CAAC,MAAM;QACrB,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * src/infra/paths.ts — Pure path helpers for myshell-tools's filesystem layout.
3
+ *
4
+ * All functions are pure path joins (no fs I/O). The canonical layout is:
5
+ * <cwd>/
6
+ * .myshell-tools/
7
+ * sessions/
8
+ * current.jsonl ← active session log
9
+ * ledger.jsonl ← cost/usage ledger
10
+ */
11
+ /**
12
+ * Returns the path to the `.myshell-tools` directory inside the given working dir.
13
+ */
14
+ export declare function getStateDir(cwd: string): string;
15
+ /**
16
+ * Returns the path to the `sessions` subdirectory inside `.myshell-tools`.
17
+ */
18
+ export declare function getSessionsDir(cwd: string): string;
19
+ /**
20
+ * Returns the path to the current session JSONL file.
21
+ * Path: <cwd>/.myshell-tools/sessions/current.jsonl
22
+ */
23
+ export declare function getSessionFile(cwd: string): string;
24
+ /**
25
+ * Returns the path to the cost/usage ledger JSONL file.
26
+ * Path: <cwd>/.myshell-tools/ledger.jsonl
27
+ */
28
+ export declare function getLedgerFile(cwd: string): string;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * src/infra/paths.ts — Pure path helpers for myshell-tools's filesystem layout.
3
+ *
4
+ * All functions are pure path joins (no fs I/O). The canonical layout is:
5
+ * <cwd>/
6
+ * .myshell-tools/
7
+ * sessions/
8
+ * current.jsonl ← active session log
9
+ * ledger.jsonl ← cost/usage ledger
10
+ */
11
+ import { join } from 'node:path';
12
+ /**
13
+ * Returns the path to the `.myshell-tools` directory inside the given working dir.
14
+ */
15
+ export function getStateDir(cwd) {
16
+ return join(cwd, '.myshell-tools');
17
+ }
18
+ /**
19
+ * Returns the path to the `sessions` subdirectory inside `.myshell-tools`.
20
+ */
21
+ export function getSessionsDir(cwd) {
22
+ return join(getStateDir(cwd), 'sessions');
23
+ }
24
+ /**
25
+ * Returns the path to the current session JSONL file.
26
+ * Path: <cwd>/.myshell-tools/sessions/current.jsonl
27
+ */
28
+ export function getSessionFile(cwd) {
29
+ return join(getSessionsDir(cwd), 'current.jsonl');
30
+ }
31
+ /**
32
+ * Returns the path to the cost/usage ledger JSONL file.
33
+ * Path: <cwd>/.myshell-tools/ledger.jsonl
34
+ */
35
+ export function getLedgerFile(cwd) {
36
+ return join(getStateDir(cwd), 'ledger.jsonl');
37
+ }
38
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/infra/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * src/infra/pricing.ts
3
+ *
4
+ * Corrected price table — Appendix A of the myshell-tools project plan.
5
+ *
6
+ * Provenance
7
+ * ----------
8
+ * Claude pricing : https://www.anthropic.com/pricing
9
+ * OpenAI pricing : https://platform.openai.com/docs/pricing
10
+ * Captured : 2026-05-29
11
+ */
12
+ export interface ModelPricing {
13
+ readonly provider: 'claude' | 'codex';
14
+ readonly model: string;
15
+ readonly aliases: readonly string[];
16
+ readonly tier: 'worker' | 'ic' | 'manager';
17
+ readonly inputPer1M: number;
18
+ readonly outputPer1M: number;
19
+ readonly contextWindow: number;
20
+ }
21
+ export interface PricingTable {
22
+ readonly asOf: string;
23
+ readonly sourceUrls: readonly string[];
24
+ readonly models: readonly ModelPricing[];
25
+ }
26
+ export declare const PRICING_TABLE: PricingTable;
27
+ /**
28
+ * Look up a model entry by exact model ID or any of its aliases.
29
+ * The lookup is case-insensitive.
30
+ */
31
+ export declare function getModelPricing(provider: string, model: string): ModelPricing | undefined;
32
+ /**
33
+ * Calculate the USD cost for a given number of input and output tokens.
34
+ */
35
+ export declare function calculateCost(inputTokens: number, outputTokens: number, pricing: ModelPricing): number;
36
+ /**
37
+ * Return the cheapest model (lowest inputPer1M) for a given tier,
38
+ * optionally restricted to the supplied provider IDs.
39
+ *
40
+ * Throws if no matching model exists.
41
+ */
42
+ export declare function getCheapestForTier(tier: 'worker' | 'ic' | 'manager', availableProviders?: string[]): ModelPricing;
43
+ /**
44
+ * Returns true when the pricing table is older than maxAgeDays (default 90).
45
+ * Useful for emitting a staleness warning at runtime.
46
+ */
47
+ export declare function isPricingStale(maxAgeDays?: number): boolean;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * src/infra/pricing.ts
3
+ *
4
+ * Corrected price table — Appendix A of the myshell-tools project plan.
5
+ *
6
+ * Provenance
7
+ * ----------
8
+ * Claude pricing : https://www.anthropic.com/pricing
9
+ * OpenAI pricing : https://platform.openai.com/docs/pricing
10
+ * Captured : 2026-05-29
11
+ */
12
+ // ---------------------------------------------------------------------------
13
+ // Data
14
+ // ---------------------------------------------------------------------------
15
+ export const PRICING_TABLE = {
16
+ asOf: '2026-05-29',
17
+ sourceUrls: [
18
+ 'https://www.anthropic.com/pricing',
19
+ 'https://platform.openai.com/docs/pricing',
20
+ ],
21
+ models: [
22
+ // ---- Anthropic / Claude ------------------------------------------------
23
+ {
24
+ provider: 'claude',
25
+ model: 'claude-opus-4-7',
26
+ aliases: ['opus', 'opus-4.7', 'claude-opus-4.7'],
27
+ tier: 'manager',
28
+ inputPer1M: 5,
29
+ outputPer1M: 25,
30
+ contextWindow: 200_000,
31
+ },
32
+ {
33
+ provider: 'claude',
34
+ model: 'claude-sonnet-4-6',
35
+ aliases: ['sonnet', 'sonnet-4.6', 'claude-sonnet-4.6'],
36
+ tier: 'ic',
37
+ inputPer1M: 3,
38
+ outputPer1M: 15,
39
+ contextWindow: 200_000,
40
+ },
41
+ {
42
+ provider: 'claude',
43
+ model: 'claude-haiku-4-5',
44
+ aliases: ['haiku', 'haiku-4.5', 'claude-haiku-4.5'],
45
+ tier: 'worker',
46
+ inputPer1M: 0.8,
47
+ outputPer1M: 4,
48
+ contextWindow: 200_000,
49
+ },
50
+ // ---- OpenAI / Codex ----------------------------------------------------
51
+ {
52
+ provider: 'codex',
53
+ model: 'gpt-5.5',
54
+ aliases: ['gpt5.5', 'gpt-5-5'],
55
+ tier: 'manager',
56
+ inputPer1M: 5,
57
+ outputPer1M: 30,
58
+ contextWindow: 128_000,
59
+ },
60
+ {
61
+ provider: 'codex',
62
+ model: 'gpt-5.4',
63
+ aliases: ['gpt5.4', 'gpt-5-4'],
64
+ tier: 'ic',
65
+ inputPer1M: 2.5,
66
+ outputPer1M: 15,
67
+ contextWindow: 128_000,
68
+ },
69
+ {
70
+ provider: 'codex',
71
+ model: 'gpt-5.4-mini',
72
+ aliases: ['gpt5.4-mini', 'gpt-5-4-mini'],
73
+ tier: 'worker',
74
+ inputPer1M: 0.75,
75
+ outputPer1M: 4.5,
76
+ contextWindow: 128_000,
77
+ },
78
+ {
79
+ provider: 'codex',
80
+ model: 'gpt-5.4-nano',
81
+ aliases: ['gpt5.4-nano', 'gpt-5-4-nano'],
82
+ tier: 'worker',
83
+ inputPer1M: 0.2,
84
+ outputPer1M: 1.25,
85
+ contextWindow: 128_000,
86
+ },
87
+ {
88
+ provider: 'codex',
89
+ model: 'gpt-5.2-codex',
90
+ aliases: ['codex', 'gpt5.2-codex', 'gpt-5-2-codex'],
91
+ tier: 'ic',
92
+ inputPer1M: 1.75,
93
+ outputPer1M: 14,
94
+ contextWindow: 128_000,
95
+ },
96
+ ],
97
+ };
98
+ // ---------------------------------------------------------------------------
99
+ // Helpers
100
+ // ---------------------------------------------------------------------------
101
+ /**
102
+ * Look up a model entry by exact model ID or any of its aliases.
103
+ * The lookup is case-insensitive.
104
+ */
105
+ export function getModelPricing(provider, model) {
106
+ const needle = model.toLowerCase();
107
+ return PRICING_TABLE.models.find((m) => m.provider === provider &&
108
+ (m.model.toLowerCase() === needle ||
109
+ m.aliases.some((a) => a.toLowerCase() === needle)));
110
+ }
111
+ /**
112
+ * Calculate the USD cost for a given number of input and output tokens.
113
+ */
114
+ export function calculateCost(inputTokens, outputTokens, pricing) {
115
+ const inputCost = (inputTokens / 1_000_000) * pricing.inputPer1M;
116
+ const outputCost = (outputTokens / 1_000_000) * pricing.outputPer1M;
117
+ return inputCost + outputCost;
118
+ }
119
+ /**
120
+ * Return the cheapest model (lowest inputPer1M) for a given tier,
121
+ * optionally restricted to the supplied provider IDs.
122
+ *
123
+ * Throws if no matching model exists.
124
+ */
125
+ export function getCheapestForTier(tier, availableProviders) {
126
+ let candidates = PRICING_TABLE.models.filter((m) => m.tier === tier);
127
+ if (availableProviders && availableProviders.length > 0) {
128
+ candidates = candidates.filter((m) => availableProviders.includes(m.provider));
129
+ }
130
+ if (candidates.length === 0) {
131
+ throw new Error(`No models available for tier "${tier}"` +
132
+ (availableProviders ? ` with providers [${availableProviders.join(', ')}]` : ''));
133
+ }
134
+ // Primary sort: inputPer1M ascending; secondary: outputPer1M ascending
135
+ return candidates.reduce((cheapest, m) => m.inputPer1M < cheapest.inputPer1M ||
136
+ (m.inputPer1M === cheapest.inputPer1M && m.outputPer1M < cheapest.outputPer1M)
137
+ ? m
138
+ : cheapest);
139
+ }
140
+ /**
141
+ * Returns true when the pricing table is older than maxAgeDays (default 90).
142
+ * Useful for emitting a staleness warning at runtime.
143
+ */
144
+ export function isPricingStale(maxAgeDays = 90) {
145
+ const asOf = new Date(PRICING_TABLE.asOf);
146
+ const now = new Date();
147
+ const diffMs = now.getTime() - asOf.getTime();
148
+ const diffDays = diffMs / (1_000 * 60 * 60 * 24);
149
+ return diffDays > maxAgeDays;
150
+ }
151
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/infra/pricing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * src/infra/session.ts — SessionWriter implementation and session reader.
3
+ *
4
+ * Sessions are persisted as JSONL files under `.myshell-tools/sessions/current.jsonl`.
5
+ * Each call to `append` writes a single line atomically using `atomicAppendJSONL`.
6
+ * `readSession` re-hydrates a session from the JSONL file, skipping any malformed
7
+ * lines so a partial write can never break a resume.
8
+ */
9
+ import type { SessionEntry, SessionWriter } from '../core/types.js';
10
+ /**
11
+ * Create a SessionWriter for the given working directory and session id.
12
+ *
13
+ * @param opts.cwd - The project working directory (parent of `.myshell-tools/`).
14
+ * @param opts.id - A unique session identifier (typically a UUID).
15
+ */
16
+ export declare function createSessionWriter(opts: {
17
+ cwd: string;
18
+ id: string;
19
+ }): SessionWriter;
20
+ /**
21
+ * Read all SessionEntry records from the current session JSONL file.
22
+ *
23
+ * Returns an empty array if the file does not exist. Malformed lines (e.g.
24
+ * caused by a partial write) are silently skipped.
25
+ *
26
+ * @param cwd - The project working directory.
27
+ */
28
+ export declare function readSession(cwd: string): Promise<SessionEntry[]>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * src/infra/session.ts — SessionWriter implementation and session reader.
3
+ *
4
+ * Sessions are persisted as JSONL files under `.myshell-tools/sessions/current.jsonl`.
5
+ * Each call to `append` writes a single line atomically using `atomicAppendJSONL`.
6
+ * `readSession` re-hydrates a session from the JSONL file, skipping any malformed
7
+ * lines so a partial write can never break a resume.
8
+ */
9
+ import { mkdir, readFile } from 'node:fs/promises';
10
+ import { atomicAppendJSONL } from './atomic.js';
11
+ import { getSessionsDir, getSessionFile } from './paths.js';
12
+ /**
13
+ * Create a SessionWriter for the given working directory and session id.
14
+ *
15
+ * @param opts.cwd - The project working directory (parent of `.myshell-tools/`).
16
+ * @param opts.id - A unique session identifier (typically a UUID).
17
+ */
18
+ export function createSessionWriter(opts) {
19
+ const { cwd, id } = opts;
20
+ return {
21
+ id,
22
+ async append(entry) {
23
+ await mkdir(getSessionsDir(cwd), { recursive: true });
24
+ await atomicAppendJSONL(getSessionFile(cwd), entry);
25
+ },
26
+ };
27
+ }
28
+ /**
29
+ * Read all SessionEntry records from the current session JSONL file.
30
+ *
31
+ * Returns an empty array if the file does not exist. Malformed lines (e.g.
32
+ * caused by a partial write) are silently skipped.
33
+ *
34
+ * @param cwd - The project working directory.
35
+ */
36
+ export async function readSession(cwd) {
37
+ let raw;
38
+ try {
39
+ raw = await readFile(getSessionFile(cwd), 'utf8');
40
+ }
41
+ catch (err) {
42
+ const nodeErr = err;
43
+ if (nodeErr.code === 'ENOENT')
44
+ return [];
45
+ throw err;
46
+ }
47
+ const entries = [];
48
+ for (const line of raw.split('\n')) {
49
+ const trimmed = line.trim();
50
+ if (trimmed.length === 0)
51
+ continue;
52
+ try {
53
+ entries.push(JSON.parse(trimmed));
54
+ }
55
+ catch {
56
+ // Skip malformed lines
57
+ }
58
+ }
59
+ return entries;
60
+ }
61
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/infra/session.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAiC;IACnE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IAEzB,OAAO;QACL,EAAE;QAEF,KAAK,CAAC,MAAM,CAAC,KAAmB;YAC9B,MAAM,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,MAAM,iBAAiB,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACtD,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAA4B,CAAC;QAC7C,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QACzC,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACnC,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * src/interface/render.ts — Human-readable event stream renderer.
3
+ *
4
+ * Consumes the AsyncIterable<CoreEvent> produced by orchestrate() and writes
5
+ * a clean, truthful transcript to an OutputSink. All displayed values come
6
+ * directly from CoreEvent data — no fabricated metrics, no hardcoded strings.
7
+ *
8
+ * Honesty Contract: confidence is rendered as a computed percentage or the
9
+ * literal word "unrated" when null. No digit-% literals appear in this file.
10
+ */
11
+ import type { CoreEvent } from '../core/types.js';
12
+ export interface OutputSink {
13
+ write(s: string): void;
14
+ readonly color: boolean;
15
+ readonly isTty: boolean;
16
+ }
17
+ /**
18
+ * Iterate events from orchestrate() and write a human-readable, truthful
19
+ * transcript to the OutputSink. Returns the success flag and the final event
20
+ * once the stream is exhausted.
21
+ */
22
+ export declare function renderStream(events: AsyncIterable<CoreEvent>, out: OutputSink): Promise<{
23
+ success: boolean;
24
+ final?: Extract<CoreEvent, {
25
+ type: 'final';
26
+ }>;
27
+ }>;