@glbgpt/cli 0.1.0-test.1

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 (173) hide show
  1. package/README.md +111 -0
  2. package/dist/src/auth/authClient.d.ts +32 -0
  3. package/dist/src/auth/authClient.js +88 -0
  4. package/dist/src/auth/authClient.js.map +1 -0
  5. package/dist/src/auth/credentialStore.d.ts +22 -0
  6. package/dist/src/auth/credentialStore.js +51 -0
  7. package/dist/src/auth/credentialStore.js.map +1 -0
  8. package/dist/src/auth/loginFlow.d.ts +30 -0
  9. package/dist/src/auth/loginFlow.js +43 -0
  10. package/dist/src/auth/loginFlow.js.map +1 -0
  11. package/dist/src/auth/loopbackServer.d.ts +41 -0
  12. package/dist/src/auth/loopbackServer.js +141 -0
  13. package/dist/src/auth/loopbackServer.js.map +1 -0
  14. package/dist/src/auth/token.d.ts +8 -0
  15. package/dist/src/auth/token.js +15 -0
  16. package/dist/src/auth/token.js.map +1 -0
  17. package/dist/src/commands/accountCommand.d.ts +2 -0
  18. package/dist/src/commands/accountCommand.js +56 -0
  19. package/dist/src/commands/accountCommand.js.map +1 -0
  20. package/dist/src/commands/configCommand.d.ts +4 -0
  21. package/dist/src/commands/configCommand.js +53 -0
  22. package/dist/src/commands/configCommand.js.map +1 -0
  23. package/dist/src/commands/execCommand.d.ts +32 -0
  24. package/dist/src/commands/execCommand.js +122 -0
  25. package/dist/src/commands/execCommand.js.map +1 -0
  26. package/dist/src/commands/loginCommand.d.ts +11 -0
  27. package/dist/src/commands/loginCommand.js +96 -0
  28. package/dist/src/commands/loginCommand.js.map +1 -0
  29. package/dist/src/commands/mediaCommand.d.ts +41 -0
  30. package/dist/src/commands/mediaCommand.js +277 -0
  31. package/dist/src/commands/mediaCommand.js.map +1 -0
  32. package/dist/src/config/configFile.d.ts +30 -0
  33. package/dist/src/config/configFile.js +54 -0
  34. package/dist/src/config/configFile.js.map +1 -0
  35. package/dist/src/config/env.d.ts +6 -0
  36. package/dist/src/config/env.js +24 -0
  37. package/dist/src/config/env.js.map +1 -0
  38. package/dist/src/config/paths.d.ts +6 -0
  39. package/dist/src/config/paths.js +16 -0
  40. package/dist/src/config/paths.js.map +1 -0
  41. package/dist/src/core/catalog.d.ts +49 -0
  42. package/dist/src/core/catalog.js +96 -0
  43. package/dist/src/core/catalog.js.map +1 -0
  44. package/dist/src/core/httpChatBackend.d.ts +31 -0
  45. package/dist/src/core/httpChatBackend.js +134 -0
  46. package/dist/src/core/httpChatBackend.js.map +1 -0
  47. package/dist/src/core/id.d.ts +2 -0
  48. package/dist/src/core/id.js +5 -0
  49. package/dist/src/core/id.js.map +1 -0
  50. package/dist/src/core/runChat.d.ts +28 -0
  51. package/dist/src/core/runChat.js +49 -0
  52. package/dist/src/core/runChat.js.map +1 -0
  53. package/dist/src/core/session.d.ts +44 -0
  54. package/dist/src/core/session.js +70 -0
  55. package/dist/src/core/session.js.map +1 -0
  56. package/dist/src/core/sessionStore.d.ts +39 -0
  57. package/dist/src/core/sessionStore.js +106 -0
  58. package/dist/src/core/sessionStore.js.map +1 -0
  59. package/dist/src/core/toolRegistry.d.ts +19 -0
  60. package/dist/src/core/toolRegistry.js +53 -0
  61. package/dist/src/core/toolRegistry.js.map +1 -0
  62. package/dist/src/core/tools/generateImage.d.ts +10 -0
  63. package/dist/src/core/tools/generateImage.js +34 -0
  64. package/dist/src/core/tools/generateImage.js.map +1 -0
  65. package/dist/src/core/turnLoop.d.ts +31 -0
  66. package/dist/src/core/turnLoop.js +155 -0
  67. package/dist/src/core/turnLoop.js.map +1 -0
  68. package/dist/src/core/types.d.ts +137 -0
  69. package/dist/src/core/types.js +9 -0
  70. package/dist/src/core/types.js.map +1 -0
  71. package/dist/src/exec/input.d.ts +35 -0
  72. package/dist/src/exec/input.js +85 -0
  73. package/dist/src/exec/input.js.map +1 -0
  74. package/dist/src/exec/output.d.ts +39 -0
  75. package/dist/src/exec/output.js +84 -0
  76. package/dist/src/exec/output.js.map +1 -0
  77. package/dist/src/index.d.ts +2 -0
  78. package/dist/src/index.js +253 -0
  79. package/dist/src/index.js.map +1 -0
  80. package/dist/src/mcp/server.d.ts +38 -0
  81. package/dist/src/mcp/server.js +99 -0
  82. package/dist/src/mcp/server.js.map +1 -0
  83. package/dist/src/media/aiApiClient.d.ts +53 -0
  84. package/dist/src/media/aiApiClient.js +97 -0
  85. package/dist/src/media/aiApiClient.js.map +1 -0
  86. package/dist/src/media/errors.d.ts +7 -0
  87. package/dist/src/media/errors.js +70 -0
  88. package/dist/src/media/errors.js.map +1 -0
  89. package/dist/src/media/executor.d.ts +50 -0
  90. package/dist/src/media/executor.js +55 -0
  91. package/dist/src/media/executor.js.map +1 -0
  92. package/dist/src/media/generateImageTool.d.ts +19 -0
  93. package/dist/src/media/generateImageTool.js +120 -0
  94. package/dist/src/media/generateImageTool.js.map +1 -0
  95. package/dist/src/media/manifest.d.ts +23 -0
  96. package/dist/src/media/manifest.js +558 -0
  97. package/dist/src/media/manifest.js.map +1 -0
  98. package/dist/src/media/resolution.d.ts +13 -0
  99. package/dist/src/media/resolution.js +42 -0
  100. package/dist/src/media/resolution.js.map +1 -0
  101. package/dist/src/media/taskLedger.d.ts +17 -0
  102. package/dist/src/media/taskLedger.js +44 -0
  103. package/dist/src/media/taskLedger.js.map +1 -0
  104. package/dist/src/media/taskManager.d.ts +52 -0
  105. package/dist/src/media/taskManager.js +130 -0
  106. package/dist/src/media/taskManager.js.map +1 -0
  107. package/dist/src/media/types.d.ts +80 -0
  108. package/dist/src/media/types.js +15 -0
  109. package/dist/src/media/types.js.map +1 -0
  110. package/dist/src/tui/App.d.ts +34 -0
  111. package/dist/src/tui/App.js +540 -0
  112. package/dist/src/tui/App.js.map +1 -0
  113. package/dist/src/tui/MultilineInput.d.ts +36 -0
  114. package/dist/src/tui/MultilineInput.js +221 -0
  115. package/dist/src/tui/MultilineInput.js.map +1 -0
  116. package/dist/src/tui/atPopup.d.ts +21 -0
  117. package/dist/src/tui/atPopup.js +55 -0
  118. package/dist/src/tui/atPopup.js.map +1 -0
  119. package/dist/src/tui/attachments.d.ts +24 -0
  120. package/dist/src/tui/attachments.js +91 -0
  121. package/dist/src/tui/attachments.js.map +1 -0
  122. package/dist/src/tui/branding.d.ts +22 -0
  123. package/dist/src/tui/branding.js +119 -0
  124. package/dist/src/tui/branding.js.map +1 -0
  125. package/dist/src/tui/chatController.d.ts +188 -0
  126. package/dist/src/tui/chatController.js +614 -0
  127. package/dist/src/tui/chatController.js.map +1 -0
  128. package/dist/src/tui/commands.d.ts +13 -0
  129. package/dist/src/tui/commands.js +22 -0
  130. package/dist/src/tui/commands.js.map +1 -0
  131. package/dist/src/tui/confirmationBridge.d.ts +23 -0
  132. package/dist/src/tui/confirmationBridge.js +47 -0
  133. package/dist/src/tui/confirmationBridge.js.map +1 -0
  134. package/dist/src/tui/inputHistory.d.ts +7 -0
  135. package/dist/src/tui/inputHistory.js +64 -0
  136. package/dist/src/tui/inputHistory.js.map +1 -0
  137. package/dist/src/tui/markdown.d.ts +1 -0
  138. package/dist/src/tui/markdown.js +143 -0
  139. package/dist/src/tui/markdown.js.map +1 -0
  140. package/dist/src/tui/models.d.ts +30 -0
  141. package/dist/src/tui/models.js +54 -0
  142. package/dist/src/tui/models.js.map +1 -0
  143. package/dist/src/tui/run.d.ts +29 -0
  144. package/dist/src/tui/run.js +212 -0
  145. package/dist/src/tui/run.js.map +1 -0
  146. package/dist/src/tui/slashMedia.d.ts +36 -0
  147. package/dist/src/tui/slashMedia.js +86 -0
  148. package/dist/src/tui/slashMedia.js.map +1 -0
  149. package/dist/src/tui/visualLines.d.ts +38 -0
  150. package/dist/src/tui/visualLines.js +110 -0
  151. package/dist/src/tui/visualLines.js.map +1 -0
  152. package/dist/src/util/clipboardImage.d.ts +6 -0
  153. package/dist/src/util/clipboardImage.js +69 -0
  154. package/dist/src/util/clipboardImage.js.map +1 -0
  155. package/dist/src/util/hyperlink.d.ts +10 -0
  156. package/dist/src/util/hyperlink.js +33 -0
  157. package/dist/src/util/hyperlink.js.map +1 -0
  158. package/dist/src/util/imageRef.d.ts +15 -0
  159. package/dist/src/util/imageRef.js +46 -0
  160. package/dist/src/util/imageRef.js.map +1 -0
  161. package/dist/src/util/inlineImage.d.ts +13 -0
  162. package/dist/src/util/inlineImage.js +56 -0
  163. package/dist/src/util/inlineImage.js.map +1 -0
  164. package/dist/src/util/openBrowser.d.ts +5 -0
  165. package/dist/src/util/openBrowser.js +23 -0
  166. package/dist/src/util/openBrowser.js.map +1 -0
  167. package/dist/src/util/retry.d.ts +43 -0
  168. package/dist/src/util/retry.js +116 -0
  169. package/dist/src/util/retry.js.map +1 -0
  170. package/dist/src/version.d.ts +6 -0
  171. package/dist/src/version.js +16 -0
  172. package/dist/src/version.js.map +1 -0
  173. package/package.json +45 -0
@@ -0,0 +1,22 @@
1
+ export const SLASH_COMMANDS = [
2
+ { name: 'model', args: '', description: 'switch the chat model' },
3
+ { name: 'models', args: '', description: 'list all chat, image, and video models' },
4
+ { name: 'image', args: '<prompt> [--ar --res -m ...]', description: 'generate an image (asks before spending)' },
5
+ { name: 'video', args: '<prompt> [--duration ...]', description: 'generate a video (asks before spending)' },
6
+ { name: 'tasks', args: '', description: 'running and recent generation tasks' },
7
+ { name: 'status', args: '', description: 'session, model, and account status' },
8
+ { name: 'account', args: '', description: 'account email, plan, and balance' },
9
+ { name: 'transactions', args: '', description: 'recent spend (authoritative billing)' },
10
+ { name: 'cost', args: '', description: "this session's tokens and estimated media credits" },
11
+ { name: 'login', args: '[--no-browser]', description: 're-authenticate (e.g. after the token expires)' },
12
+ { name: 'logout', args: '', description: 'sign out (clears local credentials)' },
13
+ { name: 'new', args: '', description: 'start a new conversation' },
14
+ { name: 'resume', args: '', description: 'switch to a previous conversation' },
15
+ { name: 'help', args: '', description: 'show all commands' },
16
+ { name: 'exit', args: '', description: 'quit' },
17
+ ];
18
+ /** Commands whose name starts with the typed token (token excludes the leading '/'). */
19
+ export function filterCommands(token) {
20
+ return SLASH_COMMANDS.filter((c) => c.name.startsWith(token));
21
+ }
22
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/tui/commands.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,cAAc,GAAuB;IAChD,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,uBAAuB,EAAE;IACjE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,wCAAwC,EAAE;IACnF,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,8BAA8B,EAAE,WAAW,EAAE,0CAA0C,EAAE;IAChH,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,2BAA2B,EAAE,WAAW,EAAE,yCAAyC,EAAE;IAC5G,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,qCAAqC,EAAE;IAC/E,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,oCAAoC,EAAE;IAC/E,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,kCAAkC,EAAE;IAC9E,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,sCAAsC,EAAE;IACvF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,mDAAmD,EAAE;IAC5F,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,EAAE,gDAAgD,EAAE;IACxG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,qCAAqC,EAAE;IAChF,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,0BAA0B,EAAE;IAClE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,mCAAmC,EAAE;IAC9E,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE;IAC5D,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE;CAChD,CAAC;AAEF,wFAAwF;AACxF,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { Confirmer, ConfirmInfo } from '../media/executor.js';
2
+ /**
3
+ * Bridges an async tool confirmation to the interactive TUI.
4
+ *
5
+ * When a paid media tool runs mid-turn, its Confirmer calls {@link request}, which parks a promise
6
+ * and notifies subscribers. The App renders a confirmation block; the user's Generate/Cancel choice
7
+ * calls {@link resolve}, settling the parked promise so the tool proceeds or aborts.
8
+ */
9
+ export declare class ConfirmationBridge {
10
+ private pending;
11
+ private readonly subscribers;
12
+ request(info: ConfirmInfo): Promise<boolean>;
13
+ resolve(approved: boolean): void;
14
+ current(): ConfirmInfo | null;
15
+ subscribe(cb: () => void): () => void;
16
+ private emit;
17
+ }
18
+ /** Confirmer that routes through the TUI bridge (chat paid-media confirmation). */
19
+ export declare class TuiConfirmer implements Confirmer {
20
+ private readonly bridge;
21
+ constructor(bridge: ConfirmationBridge);
22
+ confirm(info: ConfirmInfo): Promise<boolean>;
23
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Bridges an async tool confirmation to the interactive TUI.
3
+ *
4
+ * When a paid media tool runs mid-turn, its Confirmer calls {@link request}, which parks a promise
5
+ * and notifies subscribers. The App renders a confirmation block; the user's Generate/Cancel choice
6
+ * calls {@link resolve}, settling the parked promise so the tool proceeds or aborts.
7
+ */
8
+ export class ConfirmationBridge {
9
+ pending = null;
10
+ subscribers = new Set();
11
+ request(info) {
12
+ // Defensive: if a prior confirmation is somehow still pending, decline it so its promise settles.
13
+ this.pending?.resolve(false);
14
+ return new Promise((resolve) => {
15
+ this.pending = { info, resolve };
16
+ this.emit();
17
+ });
18
+ }
19
+ resolve(approved) {
20
+ const p = this.pending;
21
+ this.pending = null;
22
+ this.emit();
23
+ p?.resolve(approved);
24
+ }
25
+ current() {
26
+ return this.pending?.info ?? null;
27
+ }
28
+ subscribe(cb) {
29
+ this.subscribers.add(cb);
30
+ return () => this.subscribers.delete(cb);
31
+ }
32
+ emit() {
33
+ for (const cb of this.subscribers)
34
+ cb();
35
+ }
36
+ }
37
+ /** Confirmer that routes through the TUI bridge (chat paid-media confirmation). */
38
+ export class TuiConfirmer {
39
+ bridge;
40
+ constructor(bridge) {
41
+ this.bridge = bridge;
42
+ }
43
+ confirm(info) {
44
+ return this.bridge.request(info);
45
+ }
46
+ }
47
+ //# sourceMappingURL=confirmationBridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"confirmationBridge.js","sourceRoot":"","sources":["../../../src/tui/confirmationBridge.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,kBAAkB;IACrB,OAAO,GAAuE,IAAI,CAAC;IAC1E,WAAW,GAAG,IAAI,GAAG,EAAc,CAAC;IAErD,OAAO,CAAC,IAAiB;QACvB,kGAAkG;QAClG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7B,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;YACtC,IAAI,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,QAAiB;QACvB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;IACpC,CAAC;IAED,SAAS,CAAC,EAAc;QACtB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzB,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAEO,IAAI;QACV,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,WAAW;YAAE,EAAE,EAAE,CAAC;IAC1C,CAAC;CACF;AAED,mFAAmF;AACnF,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAC3D,OAAO,CAAC,IAAiB;QACvB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ export interface InputHistory {
2
+ /** Entries, oldest → newest. */
3
+ load(): Promise<string[]>;
4
+ /** Append one submitted input (fire-and-forget safe). */
5
+ append(entry: string): Promise<void>;
6
+ }
7
+ export declare function createInputHistory(file?: string): InputHistory;
@@ -0,0 +1,64 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { configDir } from '../config/paths.js';
4
+ /**
5
+ * Persistent input history for the composer (↑/↓ recall), one line of JSON per entry at
6
+ * ~/.config/glbgpt/input-history.jsonl. Newest last on disk.
7
+ *
8
+ * Writes are APPEND-ONLY (Claude Code's history.ts appends under a lock; append-only makes
9
+ * concurrent writers — two TUIs, rapid submits — loss-free without one): a read-modify-write
10
+ * cycle here would drop entries whenever two appends interleave. The file is compacted back
11
+ * to MAX_ENTRIES on load once it grows well past the cap.
12
+ */
13
+ const MAX_ENTRIES = 100;
14
+ const COMPACT_AT = MAX_ENTRIES * 3;
15
+ export function createInputHistory(file = path.join(configDir(), 'input-history.jsonl')) {
16
+ let lastAppended; // in-process duplicate guard (no read-back needed)
17
+ return {
18
+ async load() {
19
+ try {
20
+ const text = await fs.readFile(file, 'utf8');
21
+ const lines = text.split('\n').filter((l) => l.trim());
22
+ const entries = lines
23
+ .map((l) => {
24
+ try {
25
+ const v = JSON.parse(l);
26
+ return typeof v === 'string' ? v : null;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ })
32
+ .filter((v) => v !== null);
33
+ const recent = entries.slice(-MAX_ENTRIES);
34
+ if (entries.length >= COMPACT_AT) {
35
+ // Best-effort compaction — losing a race here only means a larger file, never lost entries.
36
+ void fs
37
+ .writeFile(file, recent.map((e) => JSON.stringify(e)).join('\n') + '\n', 'utf8')
38
+ .catch(() => { });
39
+ }
40
+ lastAppended = recent.at(-1);
41
+ return recent;
42
+ }
43
+ catch {
44
+ return [];
45
+ }
46
+ },
47
+ async append(entry) {
48
+ if (!entry.trim())
49
+ return;
50
+ // Skip immediate duplicates (retyping the same prompt shouldn't stack).
51
+ if (entry === lastAppended)
52
+ return;
53
+ lastAppended = entry;
54
+ try {
55
+ await fs.mkdir(path.dirname(file), { recursive: true });
56
+ await fs.appendFile(file, JSON.stringify(entry) + '\n', 'utf8');
57
+ }
58
+ catch {
59
+ // History is a convenience — never let it break input handling.
60
+ }
61
+ },
62
+ };
63
+ }
64
+ //# sourceMappingURL=inputHistory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputHistory.js","sourceRoot":"","sources":["../../../src/tui/inputHistory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C;;;;;;;;GAQG;AAEH,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,UAAU,GAAG,WAAW,GAAG,CAAC,CAAC;AASnC,MAAM,UAAU,kBAAkB,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,qBAAqB,CAAC;IACrF,IAAI,YAAgC,CAAC,CAAC,mDAAmD;IAEzF,OAAO;QACL,KAAK,CAAC,IAAI;YACR,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACvD,MAAM,OAAO,GAAG,KAAK;qBAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;oBACT,IAAI,CAAC;wBACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;wBACxB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC1C,CAAC;oBAAC,MAAM,CAAC;wBACP,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC,CAAC;qBACD,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;gBAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC;gBAC3C,IAAI,OAAO,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;oBACjC,4FAA4F;oBAC5F,KAAK,EAAE;yBACJ,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC;yBAC/E,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACrB,CAAC;gBACD,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7B,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,KAAa;YACxB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;gBAAE,OAAO;YAC1B,wEAAwE;YACxE,IAAI,KAAK,KAAK,YAAY;gBAAE,OAAO;YACnC,YAAY,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACxD,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;YAClE,CAAC;YAAC,MAAM,CAAC;gBACP,gEAAgE;YAClE,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function applyMarkdown(content: string): string;
@@ -0,0 +1,143 @@
1
+ import { marked } from 'marked';
2
+ import { highlight, supportsLanguage } from 'cli-highlight';
3
+ /**
4
+ * Markdown → ANSI for assistant bubbles (Claude Code-style: marked lexer + a small
5
+ * hand-written token formatter; the resulting string goes into one Ink <Text>).
6
+ *
7
+ * Renders the subset models actually emit: headings, bold/italic, inline code, fenced
8
+ * code blocks, lists, blockquotes, links, hr. Unknown tokens fall back to their raw
9
+ * text so streaming-incomplete markdown never crashes or disappears.
10
+ */
11
+ const B = '\x1b[1m';
12
+ const DIM = '\x1b[2m';
13
+ const IT = '\x1b[3m';
14
+ const UL = '\x1b[4m';
15
+ const CYAN = '\x1b[36m';
16
+ const GRAY = '\x1b[90m';
17
+ const R = '\x1b[0m';
18
+ let configured = false;
19
+ function configure() {
20
+ if (configured)
21
+ return;
22
+ configured = true;
23
+ // The model often writes ~5 for "approximately 5" — never parse strikethrough.
24
+ marked.use({ tokenizer: { del: () => undefined } });
25
+ }
26
+ export function applyMarkdown(content) {
27
+ configure();
28
+ try {
29
+ return marked
30
+ .lexer(content)
31
+ .map((t) => block(t))
32
+ .join('')
33
+ .replace(/\n{3,}/g, '\n\n')
34
+ .trimEnd();
35
+ }
36
+ catch {
37
+ return content; // never let a parser hiccup eat the message
38
+ }
39
+ }
40
+ function block(token, listDepth = 0) {
41
+ switch (token.type) {
42
+ case 'heading': {
43
+ const t = token;
44
+ return `${B}${UL}${inlineAll(t.tokens)}${R}\n\n`;
45
+ }
46
+ case 'paragraph':
47
+ return `${inlineAll(token.tokens)}\n\n`;
48
+ case 'code': {
49
+ const t = token;
50
+ const lang = t.lang ? `${GRAY}${t.lang}${R}\n` : '';
51
+ const body = highlightCode(t.text, t.lang)
52
+ .split('\n')
53
+ .map((l) => `${GRAY}│${R} ${l}`)
54
+ .join('\n');
55
+ return `${lang}${body}\n\n`;
56
+ }
57
+ case 'blockquote': {
58
+ const t = token;
59
+ const inner = (t.tokens ?? []).map((x) => block(x)).join('').trimEnd();
60
+ return inner
61
+ .split('\n')
62
+ .map((l) => `${GRAY}▌ ${l}${R}`)
63
+ .join('\n') + '\n\n';
64
+ }
65
+ case 'list': {
66
+ const t = token;
67
+ const indent = ' '.repeat(listDepth);
68
+ const items = t.items
69
+ .map((item, i) => {
70
+ const bullet = t.ordered ? `${Number(t.start || 1) + i}.` : '•';
71
+ const body = (item.tokens ?? [])
72
+ .map((x) => (x.type === 'list' ? '\n' + block(x, listDepth + 1) : blockInline(x)))
73
+ .join('')
74
+ .trimEnd();
75
+ return `${indent}${GRAY}${bullet}${R} ${body}`;
76
+ })
77
+ .join('\n');
78
+ return `${items}\n\n`;
79
+ }
80
+ case 'space':
81
+ return '';
82
+ case 'hr':
83
+ return `${GRAY}${'─'.repeat(24)}${R}\n\n`;
84
+ default:
85
+ return 'tokens' in token && token.tokens ? inlineAll(token.tokens) : (token.raw ?? '');
86
+ }
87
+ }
88
+ /** Render a block token inline-ish (used inside list items where paragraphs shouldn't add gaps). */
89
+ function blockInline(token) {
90
+ if (token.type === 'text' && 'tokens' in token && token.tokens)
91
+ return inlineAll(token.tokens);
92
+ if (token.type === 'paragraph')
93
+ return inlineAll(token.tokens);
94
+ return block(token).trimEnd();
95
+ }
96
+ /**
97
+ * Syntax-highlight a fenced block (Claude Code uses the same cli-highlight); cyan fallback.
98
+ * Only LABELED fences are highlighted: auto-detection scores the block against ~190 grammars
99
+ * and this runs per streaming delta on the open assistant bubble — unlabeled blocks would peg
100
+ * the render loop and flicker as the guessed language flips while the block grows.
101
+ */
102
+ function highlightCode(code, lang) {
103
+ try {
104
+ if (lang && supportsLanguage(lang))
105
+ return highlight(code, { language: lang });
106
+ }
107
+ catch {
108
+ /* fall through to the plain fallback */
109
+ }
110
+ return code
111
+ .split('\n')
112
+ .map((l) => `${CYAN}${l}${R}`)
113
+ .join('\n');
114
+ }
115
+ function inlineAll(tokens) {
116
+ return (tokens ?? []).map((t) => inline(t)).join('');
117
+ }
118
+ function inline(token) {
119
+ switch (token.type) {
120
+ case 'strong':
121
+ return `${B}${inlineAll(token.tokens)}${R}`;
122
+ case 'em':
123
+ return `${IT}${inlineAll(token.tokens)}${R}`;
124
+ case 'codespan':
125
+ return `${CYAN}${token.text}${R}`;
126
+ case 'link': {
127
+ const t = token;
128
+ const text = inlineAll(t.tokens);
129
+ return t.href && t.href !== text ? `${UL}${text}${R} ${GRAY}(${t.href})${R}` : `${UL}${text}${R}`;
130
+ }
131
+ case 'text': {
132
+ const t = token;
133
+ return t.tokens ? inlineAll(t.tokens) : t.text;
134
+ }
135
+ case 'escape':
136
+ return token.text;
137
+ case 'br':
138
+ return '\n';
139
+ default:
140
+ return 'raw' in token ? (token.raw ?? '') : '';
141
+ }
142
+ }
143
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/tui/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Chat models available in the TUI.
3
+ *
4
+ * Contract §5: only models that actually work for the current account may be listed.
5
+ * The backend whitelist (`platform.ai.cli.chat.models`) is the authority — since
6
+ * 2026-07-16 it is SERVED to the CLI via GET /ai-api/cli/v1/models (src/core/catalog.ts)
7
+ * and applied here at startup. The baked-in list below is the offline/unauthenticated
8
+ * fallback; keep it to models verified end to end.
9
+ */
10
+ export interface ModelInfo {
11
+ id: string;
12
+ label: string;
13
+ }
14
+ /** Baked-in fallback (offline / no token / first run before the catalog cache exists). */
15
+ export declare const CHAT_MODELS: ModelInfo[];
16
+ export declare const DEFAULT_CHAT_MODEL = "gpt-5.6-sol";
17
+ /** Replace the chat list with the server-driven catalog (id/label; label falls back to id). */
18
+ export declare function applyChatCatalog(models: ModelInfo[], defaultId: string): void;
19
+ /** The chat models currently in effect (server-driven when available, else baked-in). */
20
+ export declare function getChatModels(): ModelInfo[];
21
+ /** The default chat model currently in effect. */
22
+ export declare function getDefaultChatModel(): string;
23
+ /** Test hook: restore the baked-in list. */
24
+ export declare function resetChatCatalog(): void;
25
+ /**
26
+ * Resolve a chat model id, erroring with close candidates on a typo (no silent fuzzy match).
27
+ * Mirrors the media manifest's resolveModel UX. The backend whitelist is authoritative;
28
+ * this is a fast, friendly client-side guard over the currently-effective list.
29
+ */
30
+ export declare function resolveChatModel(id: string): string;
@@ -0,0 +1,54 @@
1
+ /** Baked-in fallback (offline / no token / first run before the catalog cache exists). */
2
+ export const CHAT_MODELS = [
3
+ // All three verified end to end on 2026-07-15: backend whitelist (application-newtest.yml),
4
+ // robot pricing rows (703-705), live reply + billing row each.
5
+ { id: 'gpt-5.6-sol', label: 'gpt-5.6-sol — balanced reasoning' },
6
+ { id: 'gpt-5.6-luna', label: 'gpt-5.6-luna — fastest, cheapest' },
7
+ { id: 'gpt-5.6-terra', label: 'gpt-5.6-terra — mid-tier' },
8
+ ];
9
+ export const DEFAULT_CHAT_MODEL = 'gpt-5.6-sol';
10
+ // Server-driven state (applied by src/core/catalog.ts; module-level so every consumer —
11
+ // TUI selector, exec, MCP — sees the same list without threading it through).
12
+ let currentModels = CHAT_MODELS;
13
+ let currentDefault = DEFAULT_CHAT_MODEL;
14
+ /** Replace the chat list with the server-driven catalog (id/label; label falls back to id). */
15
+ export function applyChatCatalog(models, defaultId) {
16
+ if (models.length === 0)
17
+ return; // never apply an empty list — keep the fallback
18
+ currentModels = models.map((m) => ({ id: m.id, label: m.label || m.id }));
19
+ currentDefault = currentModels.some((m) => m.id === defaultId) ? defaultId : currentModels[0].id;
20
+ }
21
+ /** The chat models currently in effect (server-driven when available, else baked-in). */
22
+ export function getChatModels() {
23
+ return currentModels;
24
+ }
25
+ /** The default chat model currently in effect. */
26
+ export function getDefaultChatModel() {
27
+ return currentDefault;
28
+ }
29
+ /** Test hook: restore the baked-in list. */
30
+ export function resetChatCatalog() {
31
+ currentModels = CHAT_MODELS;
32
+ currentDefault = DEFAULT_CHAT_MODEL;
33
+ }
34
+ /**
35
+ * Resolve a chat model id, erroring with close candidates on a typo (no silent fuzzy match).
36
+ * Mirrors the media manifest's resolveModel UX. The backend whitelist is authoritative;
37
+ * this is a fast, friendly client-side guard over the currently-effective list.
38
+ */
39
+ export function resolveChatModel(id) {
40
+ const ids = currentModels.map((m) => m.id);
41
+ if (ids.includes(id))
42
+ return id;
43
+ // Suggest a model on a substring overlap or a shared prefix (catches typos like a dropped letter).
44
+ const candidates = ids.filter((mid) => mid.includes(id) || id.includes(mid) || commonPrefixLen(mid, id) >= 5);
45
+ const hint = candidates.length ? ` Did you mean: ${candidates.join(', ')}?` : ` Available: ${ids.join(', ')}.`;
46
+ throw new Error(`Unknown chat model "${id}".${hint}`);
47
+ }
48
+ function commonPrefixLen(a, b) {
49
+ let i = 0;
50
+ while (i < a.length && i < b.length && a[i] === b[i])
51
+ i += 1;
52
+ return i;
53
+ }
54
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../../src/tui/models.ts"],"names":[],"mappings":"AAcA,0FAA0F;AAC1F,MAAM,CAAC,MAAM,WAAW,GAAgB;IACtC,4FAA4F;IAC5F,+DAA+D;IAC/D,EAAE,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,kCAAkC,EAAE;IAChE,EAAE,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,kCAAkC,EAAE;IACjE,EAAE,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,0BAA0B,EAAE;CAC3D,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAAC;AAEhD,wFAAwF;AACxF,8EAA8E;AAC9E,IAAI,aAAa,GAAgB,WAAW,CAAC;AAC7C,IAAI,cAAc,GAAW,kBAAkB,CAAC;AAEhD,+FAA+F;AAC/F,MAAM,UAAU,gBAAgB,CAAC,MAAmB,EAAE,SAAiB;IACrE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,gDAAgD;IACjF,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1E,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACnG,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,aAAa;IAC3B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,mBAAmB;IACjC,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,gBAAgB;IAC9B,aAAa,GAAG,WAAW,CAAC;IAC5B,cAAc,GAAG,kBAAkB,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC3C,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,mGAAmG;IACnG,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAC3B,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAC/E,CAAC;IACF,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAC/G,MAAM,IAAI,KAAK,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,eAAe,CAAC,CAAS,EAAE,CAAS;IAC3C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAAE,CAAC,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { Session } from '../core/session.js';
2
+ import type { ChatBackend } from '../core/types.js';
3
+ import type { ClientTool } from '../core/types.js';
4
+ export interface RunTuiOptions {
5
+ initialPrompt?: string;
6
+ /** Override the backend (used by tests). Defaults to HttpChatBackend from stored credentials/env. */
7
+ backend?: ChatBackend;
8
+ /** Override the generate_image tool (tests use the stub). */
9
+ imageTool?: ClientTool;
10
+ /** Resume this session instead of starting a new one. */
11
+ session?: Session;
12
+ /** Persisted transcript for the resumed session (from loadResumeSession). */
13
+ timeline?: unknown[];
14
+ }
15
+ /**
16
+ * Wire the chat engine to the Ink TUI and render it.
17
+ *
18
+ * The token comes from stored credentials (`glbgpt login`), or the GLBGPT_TOKEN env
19
+ * override. GLBGPT_BASE_URL points at test vs prod.
20
+ */
21
+ export declare function runTui(options?: RunTuiOptions): Promise<void>;
22
+ /**
23
+ * Load a session for `resume`. `target` is a session id, or "last"/undefined for the
24
+ * most recent one. Returns null when no matching session exists.
25
+ */
26
+ export declare function loadResumeSession(target?: string): Promise<{
27
+ session: Session;
28
+ timeline?: unknown[];
29
+ } | null>;