tenbrains 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 (183) hide show
  1. package/AGENTS.md +112 -0
  2. package/README.md +218 -0
  3. package/dist/ai/analyzer.d.ts +28 -0
  4. package/dist/ai/analyzer.d.ts.map +1 -0
  5. package/dist/ai/analyzer.js +35 -0
  6. package/dist/ai/analyzer.js.map +1 -0
  7. package/dist/ai/client.d.ts +12 -0
  8. package/dist/ai/client.d.ts.map +1 -0
  9. package/dist/ai/client.js +152 -0
  10. package/dist/ai/client.js.map +1 -0
  11. package/dist/ai/json.d.ts +7 -0
  12. package/dist/ai/json.d.ts.map +1 -0
  13. package/dist/ai/json.js +57 -0
  14. package/dist/ai/json.js.map +1 -0
  15. package/dist/ai/mock.d.ts +6 -0
  16. package/dist/ai/mock.d.ts.map +1 -0
  17. package/dist/ai/mock.js +66 -0
  18. package/dist/ai/mock.js.map +1 -0
  19. package/dist/ai/prompts.d.ts +19 -0
  20. package/dist/ai/prompts.d.ts.map +1 -0
  21. package/dist/ai/prompts.js +40 -0
  22. package/dist/ai/prompts.js.map +1 -0
  23. package/dist/ai/providers.d.ts +22 -0
  24. package/dist/ai/providers.d.ts.map +1 -0
  25. package/dist/ai/providers.js +56 -0
  26. package/dist/ai/providers.js.map +1 -0
  27. package/dist/ai/resolve.d.ts +24 -0
  28. package/dist/ai/resolve.d.ts.map +1 -0
  29. package/dist/ai/resolve.js +33 -0
  30. package/dist/ai/resolve.js.map +1 -0
  31. package/dist/bin/preflight.d.ts +2 -0
  32. package/dist/bin/preflight.d.ts.map +1 -0
  33. package/dist/bin/preflight.js +11 -0
  34. package/dist/bin/preflight.js.map +1 -0
  35. package/dist/bin/tenbrains.d.ts +3 -0
  36. package/dist/bin/tenbrains.d.ts.map +1 -0
  37. package/dist/bin/tenbrains.js +9 -0
  38. package/dist/bin/tenbrains.js.map +1 -0
  39. package/dist/cli.d.ts +4 -0
  40. package/dist/cli.d.ts.map +1 -0
  41. package/dist/cli.js +554 -0
  42. package/dist/cli.js.map +1 -0
  43. package/dist/commands/analyze.d.ts +7 -0
  44. package/dist/commands/analyze.d.ts.map +1 -0
  45. package/dist/commands/analyze.js +204 -0
  46. package/dist/commands/analyze.js.map +1 -0
  47. package/dist/commands/bookmark.d.ts +9 -0
  48. package/dist/commands/bookmark.d.ts.map +1 -0
  49. package/dist/commands/bookmark.js +120 -0
  50. package/dist/commands/bookmark.js.map +1 -0
  51. package/dist/commands/config.d.ts +15 -0
  52. package/dist/commands/config.d.ts.map +1 -0
  53. package/dist/commands/config.js +142 -0
  54. package/dist/commands/config.js.map +1 -0
  55. package/dist/commands/db.d.ts +9 -0
  56. package/dist/commands/db.d.ts.map +1 -0
  57. package/dist/commands/db.js +64 -0
  58. package/dist/commands/db.js.map +1 -0
  59. package/dist/commands/digest.d.ts +19 -0
  60. package/dist/commands/digest.d.ts.map +1 -0
  61. package/dist/commands/digest.js +71 -0
  62. package/dist/commands/digest.js.map +1 -0
  63. package/dist/commands/import.d.ts +11 -0
  64. package/dist/commands/import.d.ts.map +1 -0
  65. package/dist/commands/import.js +78 -0
  66. package/dist/commands/import.js.map +1 -0
  67. package/dist/commands/learn.d.ts +9 -0
  68. package/dist/commands/learn.d.ts.map +1 -0
  69. package/dist/commands/learn.js +149 -0
  70. package/dist/commands/learn.js.map +1 -0
  71. package/dist/commands/manifest.d.ts +13 -0
  72. package/dist/commands/manifest.d.ts.map +1 -0
  73. package/dist/commands/manifest.js +62 -0
  74. package/dist/commands/manifest.js.map +1 -0
  75. package/dist/commands/record.d.ts +10 -0
  76. package/dist/commands/record.d.ts.map +1 -0
  77. package/dist/commands/record.js +37 -0
  78. package/dist/commands/record.js.map +1 -0
  79. package/dist/commands/search.d.ts +5 -0
  80. package/dist/commands/search.d.ts.map +1 -0
  81. package/dist/commands/search.js +33 -0
  82. package/dist/commands/search.js.map +1 -0
  83. package/dist/commands/shared.d.ts +9 -0
  84. package/dist/commands/shared.d.ts.map +1 -0
  85. package/dist/commands/shared.js +13 -0
  86. package/dist/commands/shared.js.map +1 -0
  87. package/dist/commands/suggest.d.ts +9 -0
  88. package/dist/commands/suggest.d.ts.map +1 -0
  89. package/dist/commands/suggest.js +102 -0
  90. package/dist/commands/suggest.js.map +1 -0
  91. package/dist/commands/takeaway.d.ts +9 -0
  92. package/dist/commands/takeaway.d.ts.map +1 -0
  93. package/dist/commands/takeaway.js +167 -0
  94. package/dist/commands/takeaway.js.map +1 -0
  95. package/dist/core/config.d.ts +52 -0
  96. package/dist/core/config.d.ts.map +1 -0
  97. package/dist/core/config.js +180 -0
  98. package/dist/core/config.js.map +1 -0
  99. package/dist/core/context.d.ts +28 -0
  100. package/dist/core/context.d.ts.map +1 -0
  101. package/dist/core/context.js +40 -0
  102. package/dist/core/context.js.map +1 -0
  103. package/dist/core/errors.d.ts +33 -0
  104. package/dist/core/errors.d.ts.map +1 -0
  105. package/dist/core/errors.js +82 -0
  106. package/dist/core/errors.js.map +1 -0
  107. package/dist/core/input.d.ts +9 -0
  108. package/dist/core/input.d.ts.map +1 -0
  109. package/dist/core/input.js +47 -0
  110. package/dist/core/input.js.map +1 -0
  111. package/dist/core/opts.d.ts +8 -0
  112. package/dist/core/opts.d.ts.map +1 -0
  113. package/dist/core/opts.js +38 -0
  114. package/dist/core/opts.js.map +1 -0
  115. package/dist/core/output.d.ts +58 -0
  116. package/dist/core/output.d.ts.map +1 -0
  117. package/dist/core/output.js +76 -0
  118. package/dist/core/output.js.map +1 -0
  119. package/dist/core/paths.d.ts +20 -0
  120. package/dist/core/paths.d.ts.map +1 -0
  121. package/dist/core/paths.js +31 -0
  122. package/dist/core/paths.js.map +1 -0
  123. package/dist/core/text.d.ts +10 -0
  124. package/dist/core/text.d.ts.map +1 -0
  125. package/dist/core/text.js +132 -0
  126. package/dist/core/text.js.map +1 -0
  127. package/dist/core/validate.d.ts +5 -0
  128. package/dist/core/validate.d.ts.map +1 -0
  129. package/dist/core/validate.js +17 -0
  130. package/dist/core/validate.js.map +1 -0
  131. package/dist/db/database.d.ts +27 -0
  132. package/dist/db/database.d.ts.map +1 -0
  133. package/dist/db/database.js +90 -0
  134. package/dist/db/database.js.map +1 -0
  135. package/dist/db/fts.d.ts +12 -0
  136. package/dist/db/fts.d.ts.map +1 -0
  137. package/dist/db/fts.js +42 -0
  138. package/dist/db/fts.js.map +1 -0
  139. package/dist/db/migrations.d.ts +20 -0
  140. package/dist/db/migrations.d.ts.map +1 -0
  141. package/dist/db/migrations.js +243 -0
  142. package/dist/db/migrations.js.map +1 -0
  143. package/dist/db/repositories.d.ts +130 -0
  144. package/dist/db/repositories.d.ts.map +1 -0
  145. package/dist/db/repositories.js +418 -0
  146. package/dist/db/repositories.js.map +1 -0
  147. package/dist/domain/learn.d.ts +25 -0
  148. package/dist/domain/learn.d.ts.map +1 -0
  149. package/dist/domain/learn.js +85 -0
  150. package/dist/domain/learn.js.map +1 -0
  151. package/dist/domain/schemas.d.ts +169 -0
  152. package/dist/domain/schemas.d.ts.map +1 -0
  153. package/dist/domain/schemas.js +54 -0
  154. package/dist/domain/schemas.js.map +1 -0
  155. package/dist/domain/search.d.ts +32 -0
  156. package/dist/domain/search.d.ts.map +1 -0
  157. package/dist/domain/search.js +77 -0
  158. package/dist/domain/search.js.map +1 -0
  159. package/dist/domain/suggest.d.ts +17 -0
  160. package/dist/domain/suggest.d.ts.map +1 -0
  161. package/dist/domain/suggest.js +114 -0
  162. package/dist/domain/suggest.js.map +1 -0
  163. package/dist/domain/tags.d.ts +9 -0
  164. package/dist/domain/tags.d.ts.map +1 -0
  165. package/dist/domain/tags.js +40 -0
  166. package/dist/domain/tags.js.map +1 -0
  167. package/dist/domain/types.d.ts +84 -0
  168. package/dist/domain/types.d.ts.map +1 -0
  169. package/dist/domain/types.js +2 -0
  170. package/dist/domain/types.js.map +1 -0
  171. package/dist/index.d.ts +19 -0
  172. package/dist/index.d.ts.map +1 -0
  173. package/dist/index.js +18 -0
  174. package/dist/index.js.map +1 -0
  175. package/dist/x/archive.d.ts +32 -0
  176. package/dist/x/archive.d.ts.map +1 -0
  177. package/dist/x/archive.js +108 -0
  178. package/dist/x/archive.js.map +1 -0
  179. package/dist/x/client.d.ts +61 -0
  180. package/dist/x/client.d.ts.map +1 -0
  181. package/dist/x/client.js +321 -0
  182. package/dist/x/client.js.map +1 -0
  183. package/package.json +58 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest.d.ts","sourceRoot":"","sources":["../../src/commands/suggest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAAE,KAAK,IAAI,EAAuC,MAAM,iBAAiB,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AASvD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CAWjF;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CAiB7E;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CA0B7E;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CAYhF;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CAgC5E"}
@@ -0,0 +1,102 @@
1
+ import { CliError } from "../core/errors.js";
2
+ import { resolveTextInput } from "../core/input.js";
3
+ import { optNumber, optString, requireString } from "../core/opts.js";
4
+ import { parseOrThrow } from "../core/validate.js";
5
+ import { PostInputSchema } from "../domain/schemas.js";
6
+ import { generateSuggestions } from "../domain/suggest.js";
7
+ import { suggestTags } from "../domain/tags.js";
8
+ const VALID_STATUSES = ["pending", "saved", "dismissed"];
9
+ export function suggestGenerateCommand(ctx, opts) {
10
+ const limit = optNumber(opts, "limit", 10);
11
+ const result = generateSuggestions(ctx.store(), { limit });
12
+ return {
13
+ data: result,
14
+ meta: { created: result.created, updated: result.updated, persisted: true },
15
+ human: () => result.suggestions.length === 0
16
+ ? "No suggestions. Analyze and bookmark some posts first."
17
+ : result.suggestions.map((s) => `[${s.score.toFixed(1)}] ${s.reason} (${s.id})`).join("\n"),
18
+ };
19
+ }
20
+ export function suggestListCommand(ctx, opts) {
21
+ const store = ctx.store();
22
+ const limit = optNumber(opts, "limit", 10);
23
+ const statusOpt = optString(opts, "status") ?? "pending";
24
+ if (statusOpt !== "all" && !VALID_STATUSES.includes(statusOpt)) {
25
+ throw new CliError("USAGE", `Invalid --status "${statusOpt}". Use pending|saved|dismissed|all.`);
26
+ }
27
+ const suggestions = store.suggestions
28
+ .list(statusOpt, limit)
29
+ .map((suggestion) => ({ ...suggestion, post: store.posts.findById(suggestion.postId) }));
30
+ return {
31
+ data: { suggestions, count: suggestions.length },
32
+ meta: { status: statusOpt, limit },
33
+ };
34
+ }
35
+ export function suggestSaveCommand(ctx, opts) {
36
+ const store = ctx.store();
37
+ const id = requireString(opts, "id", "<id>");
38
+ const suggestion = store.suggestions.findById(id);
39
+ if (!suggestion) {
40
+ throw new CliError("NOT_FOUND", `No suggestion with id ${id}.`, { details: { id } });
41
+ }
42
+ const updated = store.suggestions.setStatus(id, "saved");
43
+ // Saving a suggestion materializes it as a bookmark (the feedback loop).
44
+ let bookmark = store.bookmarks.findByPostId(suggestion.postId);
45
+ if (!bookmark) {
46
+ const post = store.posts.findById(suggestion.postId);
47
+ const tags = post ? suggestTags(post, store.analyses.latestForPost(post.id)) : [];
48
+ bookmark = store.bookmarks.create({
49
+ postId: suggestion.postId,
50
+ tags,
51
+ source: "suggestion",
52
+ });
53
+ }
54
+ return {
55
+ data: { suggestion: updated, bookmark },
56
+ meta: { bookmarkId: bookmark.id, persisted: true },
57
+ human: () => `Saved suggestion ${id} → bookmark ${bookmark?.id}.`,
58
+ };
59
+ }
60
+ export function suggestDismissCommand(ctx, opts) {
61
+ const store = ctx.store();
62
+ const id = requireString(opts, "id", "<id>");
63
+ if (!store.suggestions.findById(id)) {
64
+ throw new CliError("NOT_FOUND", `No suggestion with id ${id}.`, { details: { id } });
65
+ }
66
+ const updated = store.suggestions.setStatus(id, "dismissed");
67
+ return {
68
+ data: { suggestion: updated },
69
+ meta: { persisted: true },
70
+ human: () => `Dismissed suggestion ${id}.`,
71
+ };
72
+ }
73
+ export function suggestAddCommand(ctx, opts) {
74
+ const store = ctx.store();
75
+ const postId = optString(opts, "postId");
76
+ let resolvedPostId;
77
+ if (postId) {
78
+ if (!store.posts.findById(postId)) {
79
+ throw new CliError("NOT_FOUND", `No post with id ${postId}.`, { details: { postId } });
80
+ }
81
+ resolvedPostId = postId;
82
+ }
83
+ else {
84
+ const text = resolveTextInput(requireString(opts, "text", "--text or --post-id"));
85
+ const input = parseOrThrow(PostInputSchema, {
86
+ text,
87
+ url: optString(opts, "url"),
88
+ externalId: optString(opts, "id"),
89
+ authorUsername: optString(opts, "author"),
90
+ }, "Invalid post input.");
91
+ resolvedPostId = store.posts.ingest(input).post.id;
92
+ }
93
+ const reason = optString(opts, "reason") ?? "Manually added candidate.";
94
+ const score = optNumber(opts, "score", 1);
95
+ const suggestion = store.suggestions.upsert({ postId: resolvedPostId, reason, score });
96
+ return {
97
+ data: { suggestion },
98
+ meta: { suggestionId: suggestion.id, persisted: true },
99
+ human: () => `Added suggestion ${suggestion.id} for post ${resolvedPostId}.`,
100
+ };
101
+ }
102
+ //# sourceMappingURL=suggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest.js","sourceRoot":"","sources":["../../src/commands/suggest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAa,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEjF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,MAAM,cAAc,GAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AAE7E,MAAM,UAAU,sBAAsB,CAAC,GAAe,EAAE,IAAU;IAChE,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE;QAC3E,KAAK,EAAE,GAAG,EAAE,CACV,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;YAC7B,CAAC,CAAC,wDAAwD;YAC1D,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;KAChG,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAe,EAAE,IAAU;IAC5D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,SAAS,CAAC;IACzD,IAAI,SAAS,KAAK,KAAK,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,SAA6B,CAAC,EAAE,CAAC;QACnF,MAAM,IAAI,QAAQ,CAChB,OAAO,EACP,qBAAqB,SAAS,qCAAqC,CACpE,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW;SAClC,IAAI,CAAC,SAAqC,EAAE,KAAK,CAAC;SAClD,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3F,OAAO;QACL,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE;QAChD,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAe,EAAE,IAAU;IAC5D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IAC1B,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,yBAAyB,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAEzD,yEAAyE;IACzE,IAAI,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC/D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;YAChC,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,IAAI;YACJ,MAAM,EAAE,YAAY;SACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE;QACvC,IAAI,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;QAClD,KAAK,EAAE,GAAG,EAAE,CAAC,oBAAoB,EAAE,eAAe,QAAQ,EAAE,EAAE,GAAG;KAClE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAe,EAAE,IAAU;IAC/D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IAC1B,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,yBAAyB,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IAC7D,OAAO;QACL,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE;QAC7B,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;QACzB,KAAK,EAAE,GAAG,EAAE,CAAC,wBAAwB,EAAE,GAAG;KAC3C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAe,EAAE,IAAU;IAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,IAAI,cAAsB,CAAC;IAC3B,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,mBAAmB,MAAM,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,cAAc,GAAG,MAAM,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,gBAAgB,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC;QAClF,MAAM,KAAK,GAAG,YAAY,CACxB,eAAe,EACf;YACE,IAAI;YACJ,GAAG,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC;YAC3B,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;YACjC,cAAc,EAAE,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC;SAC1C,EACD,qBAAqB,CACtB,CAAC;QACF,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IACrD,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,2BAA2B,CAAC;IACxE,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACvF,OAAO;QACL,IAAI,EAAE,EAAE,UAAU,EAAE;QACpB,IAAI,EAAE,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;QACtD,KAAK,EAAE,GAAG,EAAE,CAAC,oBAAoB,UAAU,CAAC,EAAE,aAAa,cAAc,GAAG;KAC7E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { RunContext } from "../core/context.js";
2
+ import { type Opts } from "../core/opts.js";
3
+ import type { CommandResult } from "../core/output.js";
4
+ export declare function takeawayFollowCommand(ctx: RunContext, opts: Opts): CommandResult;
5
+ export declare function takeawayUnfollowCommand(ctx: RunContext, opts: Opts): CommandResult;
6
+ export declare function takeawayListCommand(ctx: RunContext, _opts: Opts): CommandResult;
7
+ export declare function takeawayRefreshCommand(ctx: RunContext, opts: Opts): Promise<CommandResult>;
8
+ export declare function takeawayShowCommand(ctx: RunContext, opts: Opts): CommandResult;
9
+ //# sourceMappingURL=takeaway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"takeaway.d.ts","sourceRoot":"","sources":["../../src/commands/takeaway.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,OAAO,EAAE,KAAK,IAAI,EAAgD,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAuBvD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CAYhF;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CASlF;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,GAAG,aAAa,CAuB/E;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CA6FhG;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,GAAG,aAAa,CAkC9E"}
@@ -0,0 +1,167 @@
1
+ import { summarizeAccount } from "../ai/analyzer.js";
2
+ import { resolveProvider } from "../ai/resolve.js";
3
+ import { CliError } from "../core/errors.js";
4
+ import { resolveJsonInput } from "../core/input.js";
5
+ import { optBool, optNumber, optString, requireString } from "../core/opts.js";
6
+ import { parseOrThrow } from "../core/validate.js";
7
+ import { TakeawayPostsInputSchema } from "../domain/schemas.js";
8
+ import { fetchAccountTimeline } from "../x/client.js";
9
+ import { resolveXBearer } from "./shared.js";
10
+ function normalizeUsername(raw) {
11
+ return raw.trim().replace(/^@/, "");
12
+ }
13
+ function requireAccount(ctx, username) {
14
+ const account = ctx.store().accounts.findByUsername(username);
15
+ if (!account) {
16
+ throw new CliError("NOT_FOUND", `Not following @${username}. Run "tenbrains takeaway follow ${username}" first.`, { details: { username } });
17
+ }
18
+ return account;
19
+ }
20
+ export function takeawayFollowCommand(ctx, opts) {
21
+ const username = normalizeUsername(requireString(opts, "username", "<username>"));
22
+ const store = ctx.store();
23
+ if (store.accounts.findByUsername(username)) {
24
+ throw new CliError("CONFLICT", `Already following @${username}.`, { details: { username } });
25
+ }
26
+ const account = store.accounts.create(username, optString(opts, "name"));
27
+ return {
28
+ data: { account },
29
+ meta: { accountId: account.id, persisted: true },
30
+ human: () => `Following @${account.username} (${account.id}).`,
31
+ };
32
+ }
33
+ export function takeawayUnfollowCommand(ctx, opts) {
34
+ const username = normalizeUsername(requireString(opts, "username", "<username>"));
35
+ const account = requireAccount(ctx, username);
36
+ ctx.store().accounts.delete(account.id);
37
+ return {
38
+ data: { unfollowed: account.username, accountId: account.id },
39
+ meta: { persisted: true },
40
+ human: () => `Unfollowed @${account.username}.`,
41
+ };
42
+ }
43
+ export function takeawayListCommand(ctx, _opts) {
44
+ const store = ctx.store();
45
+ const accounts = store.accounts.list().map((account) => {
46
+ const latest = store.snapshots.latestByAccount(account.id);
47
+ return {
48
+ ...account,
49
+ latestSnapshot: latest
50
+ ? { id: latest.id, summary: latest.summary, createdAt: latest.createdAt }
51
+ : null,
52
+ };
53
+ });
54
+ return {
55
+ data: { accounts, count: accounts.length },
56
+ human: () => accounts.length === 0
57
+ ? "No accounts followed yet."
58
+ : accounts
59
+ .map((a) => `@${a.username}${a.latestSnapshot ? `: ${a.latestSnapshot.summary}` : " (no takeaway yet)"}`)
60
+ .join("\n"),
61
+ };
62
+ }
63
+ export async function takeawayRefreshCommand(ctx, opts) {
64
+ const username = normalizeUsername(requireString(opts, "username", "<username>"));
65
+ const account = requireAccount(ctx, username);
66
+ const resolved = resolveProvider(ctx.config, {
67
+ provider: optString(opts, "provider"),
68
+ model: optString(opts, "model"),
69
+ apiKey: optString(opts, "apiKey"),
70
+ });
71
+ const store = ctx.store();
72
+ const postsOpt = optString(opts, "posts");
73
+ let posts;
74
+ let source = "supplied";
75
+ if (postsOpt !== undefined) {
76
+ posts = parseOrThrow(TakeawayPostsInputSchema, resolveJsonInput(postsOpt), "Invalid posts input. Expected a JSON array of { text, externalId?, url?, postedAt? }.");
77
+ }
78
+ else {
79
+ const bearer = resolveXBearer(ctx, opts);
80
+ if (!bearer) {
81
+ throw new CliError("MISSING_CREDENTIALS", "No --posts supplied and no X Bearer token configured. Provide --posts <json>, or run `tenbrains setup --x-bearer <token>` to fetch the timeline (a paid X API tier is usually required for timeline reads).");
82
+ }
83
+ const count = optNumber(opts, "count", 20);
84
+ ctx.logger.info(`Fetching up to ${count} recent posts for @${username} from X…`);
85
+ const fetched = await fetchAccountTimeline(account.username, bearer, count);
86
+ if (fetched.length === 0) {
87
+ throw new CliError("NOT_FOUND", `No recent original posts found for @${username}.`);
88
+ }
89
+ posts = fetched.map((tweet) => ({
90
+ text: tweet.text,
91
+ externalId: tweet.externalId,
92
+ url: tweet.url,
93
+ postedAt: tweet.postedAt,
94
+ }));
95
+ source = "x:api";
96
+ }
97
+ const sourcePostIds = [];
98
+ for (const input of posts) {
99
+ const { post } = store.posts.ingest({
100
+ text: input.text,
101
+ externalId: input.externalId,
102
+ url: input.url,
103
+ postedAt: input.postedAt,
104
+ authorUsername: account.username,
105
+ });
106
+ sourcePostIds.push(post.id);
107
+ }
108
+ ctx.logger.info(`Summarizing ${posts.length} posts for @${username}…`);
109
+ const outcome = await summarizeAccount(resolved, {
110
+ account: { username: account.username, name: account.name ?? undefined },
111
+ posts: posts.map((p) => ({ text: p.text, postedAt: p.postedAt })),
112
+ });
113
+ const snapshot = store.snapshots.create({
114
+ accountId: account.id,
115
+ provider: resolved.provider,
116
+ model: resolved.model,
117
+ summary: outcome.result.summary,
118
+ takeaways: outcome.result.takeaways,
119
+ sourcePostIds,
120
+ mock: outcome.mock,
121
+ });
122
+ store.accounts.touch(account.id);
123
+ return {
124
+ data: { account, snapshot },
125
+ meta: {
126
+ snapshotId: snapshot.id,
127
+ provider: resolved.provider,
128
+ model: resolved.model,
129
+ mock: outcome.mock,
130
+ postCount: sourcePostIds.length,
131
+ source,
132
+ persisted: true,
133
+ },
134
+ human: () => [
135
+ `@${account.username}: ${snapshot.summary}`,
136
+ ...snapshot.takeaways.map((t) => ` - ${t}`),
137
+ ].join("\n"),
138
+ };
139
+ }
140
+ export function takeawayShowCommand(ctx, opts) {
141
+ const username = normalizeUsername(requireString(opts, "username", "<username>"));
142
+ const account = requireAccount(ctx, username);
143
+ const store = ctx.store();
144
+ if (optBool(opts, "history")) {
145
+ const limit = optNumber(opts, "limit", 20);
146
+ const snapshots = store.snapshots.listByAccount(account.id, limit);
147
+ return {
148
+ data: { account, snapshots, count: snapshots.length },
149
+ meta: { limit },
150
+ };
151
+ }
152
+ const snapshot = store.snapshots.latestByAccount(account.id);
153
+ if (!snapshot) {
154
+ throw new CliError("NOT_FOUND", `No takeaway snapshot yet for @${username}. Run "tenbrains takeaway refresh ${username} --posts ...".`, { details: { username } });
155
+ }
156
+ const sourcePosts = snapshot.sourcePostIds
157
+ .map((id) => store.posts.findById(id))
158
+ .filter((p) => p !== null);
159
+ return {
160
+ data: { account, snapshot, sourcePosts },
161
+ human: () => [
162
+ `@${account.username}: ${snapshot.summary}`,
163
+ ...snapshot.takeaways.map((t) => ` - ${t}`),
164
+ ].join("\n"),
165
+ };
166
+ }
167
+ //# sourceMappingURL=takeaway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"takeaway.js","sourceRoot":"","sources":["../../src/commands/takeaway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { type ProviderId } from "../ai/providers.js";
2
+ export interface ProviderConfig {
3
+ apiKey?: string;
4
+ model?: string;
5
+ }
6
+ export interface TenbrainsConfig {
7
+ defaultProvider?: ProviderId;
8
+ defaultModel?: string;
9
+ providers?: Partial<Record<ProviderId, ProviderConfig>>;
10
+ /** X (Twitter) API credentials, used for timeline reads and tweet fetches. */
11
+ x?: {
12
+ bearerToken?: string;
13
+ };
14
+ updatedAt?: string;
15
+ }
16
+ /**
17
+ * Whether a config key holds a secret and must be redacted by default. Matches
18
+ * the last dot-segment so compound names like `x.bearerToken` are caught too.
19
+ */
20
+ export declare function isSecretKey(key: string): boolean;
21
+ export declare const REDACTED = "********";
22
+ export declare function redactValue(value: unknown): unknown;
23
+ /**
24
+ * Persisted CLI configuration: default provider/model plus per-provider API
25
+ * keys. Written atomically with 0600 permissions. This is the single store the
26
+ * CLI manages on the user's behalf — credentials are collected through commands
27
+ * (`setup` / `config set`), never by asking the user to edit a file directly.
28
+ */
29
+ export declare class ConfigStore {
30
+ readonly filePath: string;
31
+ private readonly dirPath;
32
+ constructor(options?: {
33
+ configDir?: string | undefined;
34
+ });
35
+ read(): TenbrainsConfig;
36
+ private write;
37
+ /** Read a value by dot-path (e.g. "defaultProvider", "providers.openai.apiKey"). */
38
+ get(key: string): unknown;
39
+ /** Set a value by dot-path, validating known typed keys. Returns the new config. */
40
+ set(key: string, value: string): TenbrainsConfig;
41
+ /** Remove a value by dot-path. Returns whether anything was removed. */
42
+ unset(key: string): boolean;
43
+ /** Full config as a flat list of entries, with secrets redacted unless reveal. */
44
+ entries(reveal: boolean): Array<{
45
+ key: string;
46
+ value: unknown;
47
+ }>;
48
+ getDefaultProvider(): ProviderId | undefined;
49
+ getProviderConfig(provider: ProviderId): ProviderConfig;
50
+ getXBearer(): string | undefined;
51
+ }
52
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AAIrF,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,CAAC,EAAE,UAAU,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;IACxD,8EAA8E;IAC9E,CAAC,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGhD;AAED,eAAO,MAAM,QAAQ,aAAa,CAAC;AAEnC,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMnD;AAED;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAO;IAK5D,IAAI,IAAI,eAAe;IAsBvB,OAAO,CAAC,KAAK;IASb,oFAAoF;IACpF,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,oFAAoF;IACpF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe;IAQhD,wEAAwE;IACxE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAS3B,kFAAkF;IAClF,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAUhE,kBAAkB,IAAI,UAAU,GAAG,SAAS;IAK5C,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,cAAc;IAIvD,UAAU,IAAI,MAAM,GAAG,SAAS;CAIjC"}
@@ -0,0 +1,180 @@
1
+ import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import { PROVIDER_CATALOG, isProviderId } from "../ai/providers.js";
3
+ import { CliError } from "./errors.js";
4
+ import { resolveConfigDir, resolveConfigFile } from "./paths.js";
5
+ /**
6
+ * Whether a config key holds a secret and must be redacted by default. Matches
7
+ * the last dot-segment so compound names like `x.bearerToken` are caught too.
8
+ */
9
+ export function isSecretKey(key) {
10
+ const last = key.split(".").pop() ?? "";
11
+ return /(api_?key|token|secret|password|bearer)$/i.test(last);
12
+ }
13
+ export const REDACTED = "********";
14
+ export function redactValue(value) {
15
+ if (typeof value !== "string" || value.length === 0) {
16
+ return value;
17
+ }
18
+ const tail = value.slice(-4);
19
+ return `${REDACTED}${tail}`;
20
+ }
21
+ /**
22
+ * Persisted CLI configuration: default provider/model plus per-provider API
23
+ * keys. Written atomically with 0600 permissions. This is the single store the
24
+ * CLI manages on the user's behalf — credentials are collected through commands
25
+ * (`setup` / `config set`), never by asking the user to edit a file directly.
26
+ */
27
+ export class ConfigStore {
28
+ filePath;
29
+ dirPath;
30
+ constructor(options = {}) {
31
+ this.filePath = resolveConfigFile({ configDir: options.configDir });
32
+ this.dirPath = resolveConfigDir({ configDir: options.configDir });
33
+ }
34
+ read() {
35
+ let raw;
36
+ try {
37
+ raw = readFileSync(this.filePath, "utf8");
38
+ }
39
+ catch (error) {
40
+ if (isNotFound(error)) {
41
+ return {};
42
+ }
43
+ throw new CliError("CONFIG_ERROR", `Failed to read config at ${this.filePath}`, {
44
+ cause: error,
45
+ });
46
+ }
47
+ try {
48
+ const parsed = JSON.parse(raw);
49
+ return parsed && typeof parsed === "object" ? parsed : {};
50
+ }
51
+ catch (error) {
52
+ throw new CliError("CONFIG_ERROR", `Config file is not valid JSON: ${this.filePath}`, {
53
+ cause: error,
54
+ });
55
+ }
56
+ }
57
+ write(config) {
58
+ const next = { ...config, updatedAt: new Date().toISOString() };
59
+ mkdirSync(this.dirPath, { recursive: true });
60
+ const tmp = `${this.filePath}.${process.pid}.tmp`;
61
+ writeFileSync(tmp, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 });
62
+ chmodSync(tmp, 0o600);
63
+ renameSync(tmp, this.filePath);
64
+ }
65
+ /** Read a value by dot-path (e.g. "defaultProvider", "providers.openai.apiKey"). */
66
+ get(key) {
67
+ return getPath(this.read(), key);
68
+ }
69
+ /** Set a value by dot-path, validating known typed keys. Returns the new config. */
70
+ set(key, value) {
71
+ const config = this.read();
72
+ validateAssignment(key, value);
73
+ setPath(config, key, value);
74
+ this.write(config);
75
+ return config;
76
+ }
77
+ /** Remove a value by dot-path. Returns whether anything was removed. */
78
+ unset(key) {
79
+ const config = this.read();
80
+ const removed = deletePath(config, key);
81
+ if (removed) {
82
+ this.write(config);
83
+ }
84
+ return removed;
85
+ }
86
+ /** Full config as a flat list of entries, with secrets redacted unless reveal. */
87
+ entries(reveal) {
88
+ const flat = flatten(this.read());
89
+ return flat.map(({ key, value }) => ({
90
+ key,
91
+ value: !reveal && isSecretKey(key) ? redactValue(value) : value,
92
+ }));
93
+ }
94
+ // --- typed accessors -------------------------------------------------------
95
+ getDefaultProvider() {
96
+ const value = this.read().defaultProvider;
97
+ return value && isProviderId(value) ? value : undefined;
98
+ }
99
+ getProviderConfig(provider) {
100
+ return this.read().providers?.[provider] ?? {};
101
+ }
102
+ getXBearer() {
103
+ const token = this.read().x?.bearerToken?.trim();
104
+ return token || undefined;
105
+ }
106
+ }
107
+ function validateAssignment(key, value) {
108
+ if (key === "defaultProvider" && !isProviderId(value)) {
109
+ throw new CliError("VALIDATION", `Unknown provider "${value}". Valid: ${Object.keys(PROVIDER_CATALOG).join(", ")}.`, { details: { key, value } });
110
+ }
111
+ const providerMatch = /^providers\.([^.]+)\.(apiKey|model)$/.exec(key);
112
+ if (providerMatch && !isProviderId(providerMatch[1] ?? "")) {
113
+ throw new CliError("VALIDATION", `Unknown provider "${providerMatch[1]}" in key "${key}".`, {
114
+ details: { key },
115
+ });
116
+ }
117
+ }
118
+ // --- dot-path helpers --------------------------------------------------------
119
+ function getPath(obj, key) {
120
+ const parts = key.split(".");
121
+ let cursor = obj;
122
+ for (const part of parts) {
123
+ if (cursor === null || typeof cursor !== "object") {
124
+ return undefined;
125
+ }
126
+ cursor = cursor[part];
127
+ }
128
+ return cursor;
129
+ }
130
+ function setPath(obj, key, value) {
131
+ const parts = key.split(".");
132
+ let cursor = obj;
133
+ for (let i = 0; i < parts.length - 1; i += 1) {
134
+ const part = parts[i];
135
+ const existing = cursor[part];
136
+ if (existing === null || typeof existing !== "object") {
137
+ cursor[part] = {};
138
+ }
139
+ cursor = cursor[part];
140
+ }
141
+ cursor[parts[parts.length - 1]] = value;
142
+ }
143
+ function deletePath(obj, key) {
144
+ const parts = key.split(".");
145
+ let cursor = obj;
146
+ for (let i = 0; i < parts.length - 1; i += 1) {
147
+ const part = parts[i];
148
+ const existing = cursor[part];
149
+ if (existing === null || typeof existing !== "object") {
150
+ return false;
151
+ }
152
+ cursor = existing;
153
+ }
154
+ const leaf = parts[parts.length - 1];
155
+ if (Object.prototype.hasOwnProperty.call(cursor, leaf)) {
156
+ delete cursor[leaf];
157
+ return true;
158
+ }
159
+ return false;
160
+ }
161
+ function flatten(obj, prefix = "") {
162
+ const out = [];
163
+ for (const [k, v] of Object.entries(obj)) {
164
+ const key = prefix ? `${prefix}.${k}` : k;
165
+ if (v !== null && typeof v === "object" && !Array.isArray(v)) {
166
+ out.push(...flatten(v, key));
167
+ }
168
+ else {
169
+ out.push({ key, value: v });
170
+ }
171
+ }
172
+ return out;
173
+ }
174
+ function isNotFound(error) {
175
+ return (typeof error === "object" &&
176
+ error !== null &&
177
+ "code" in error &&
178
+ error.code === "ENOENT");
179
+ }
180
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { Store } from "../db/repositories.js";
2
+ import { ConfigStore } from "./config.js";
3
+ import { Logger, type OutputMode } from "./output.js";
4
+ export interface GlobalOptions {
5
+ json: boolean;
6
+ pretty: boolean;
7
+ quiet: boolean;
8
+ dbPath?: string | undefined;
9
+ configDir?: string | undefined;
10
+ }
11
+ /**
12
+ * Per-invocation runtime: output mode, logger, config store, and a lazily
13
+ * opened database. Commands that don't touch persistence (config, manifest)
14
+ * never open the DB.
15
+ */
16
+ export declare class RunContext {
17
+ readonly options: GlobalOptions;
18
+ readonly mode: OutputMode;
19
+ readonly logger: Logger;
20
+ readonly config: ConfigStore;
21
+ private database;
22
+ private storeInstance;
23
+ constructor(options: GlobalOptions);
24
+ dbPath(): string;
25
+ store(): Store;
26
+ close(): void;
27
+ }
28
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAGtD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED;;;;GAIG;AACH,qBAAa,UAAU;IAOT,QAAQ,CAAC,OAAO,EAAE,aAAa;IAN3C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,aAAa,CAAsB;gBAEtB,OAAO,EAAE,aAAa;IAM3C,MAAM,IAAI,MAAM;IAIhB,KAAK,IAAI,KAAK;IAQd,KAAK,IAAI,IAAI;CAKd"}
@@ -0,0 +1,40 @@
1
+ import { Database } from "../db/database.js";
2
+ import { Store } from "../db/repositories.js";
3
+ import { ConfigStore } from "./config.js";
4
+ import { Logger } from "./output.js";
5
+ import { resolveDbPath } from "./paths.js";
6
+ /**
7
+ * Per-invocation runtime: output mode, logger, config store, and a lazily
8
+ * opened database. Commands that don't touch persistence (config, manifest)
9
+ * never open the DB.
10
+ */
11
+ export class RunContext {
12
+ options;
13
+ mode;
14
+ logger;
15
+ config;
16
+ database = null;
17
+ storeInstance = null;
18
+ constructor(options) {
19
+ this.options = options;
20
+ this.mode = options.pretty && !options.json ? "pretty" : "json";
21
+ this.logger = new Logger(this.mode, options.quiet);
22
+ this.config = new ConfigStore({ configDir: options.configDir });
23
+ }
24
+ dbPath() {
25
+ return resolveDbPath({ dbPath: this.options.dbPath });
26
+ }
27
+ store() {
28
+ if (!this.storeInstance) {
29
+ this.database = Database.open({ path: this.dbPath() });
30
+ this.storeInstance = new Store(this.database);
31
+ }
32
+ return this.storeInstance;
33
+ }
34
+ close() {
35
+ this.database?.close();
36
+ this.database = null;
37
+ this.storeInstance = null;
38
+ }
39
+ }
40
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAmB,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAU3C;;;;GAIG;AACH,MAAM,OAAO,UAAU;IAOA;IANZ,IAAI,CAAa;IACjB,MAAM,CAAS;IACf,MAAM,CAAc;IACrB,QAAQ,GAAoB,IAAI,CAAC;IACjC,aAAa,GAAiB,IAAI,CAAC;IAE3C,YAAqB,OAAsB;QAAtB,YAAO,GAAP,OAAO,CAAe;QACzC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QAChE,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,MAAM;QACJ,OAAO,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACvD,IAAI,CAAC,aAAa,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;CACF"}