@jinion/cli 0.0.0-stage → 0.4.524

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 (192) hide show
  1. package/CHANGELOG.md +249 -0
  2. package/bin/jinion.js +15 -0
  3. package/dist/app/activity.js +50 -0
  4. package/dist/app/activity.js.map +1 -0
  5. package/dist/app/announcements.js +21 -0
  6. package/dist/app/announcements.js.map +1 -0
  7. package/dist/app/api.js +26 -0
  8. package/dist/app/api.js.map +1 -0
  9. package/dist/app/app.js +99 -0
  10. package/dist/app/app.js.map +1 -0
  11. package/dist/app/aside.js +52 -0
  12. package/dist/app/aside.js.map +1 -0
  13. package/dist/app/claude-notes.js +19 -0
  14. package/dist/app/claude-notes.js.map +1 -0
  15. package/dist/app/dialogs.js +43 -0
  16. package/dist/app/dialogs.js.map +1 -0
  17. package/dist/app/keys.js +79 -0
  18. package/dist/app/keys.js.map +1 -0
  19. package/dist/app/prompt-area.js +56 -0
  20. package/dist/app/prompt-area.js.map +1 -0
  21. package/dist/app/release-notes.js +20 -0
  22. package/dist/app/release-notes.js.map +1 -0
  23. package/dist/app/settings-file.js +7 -0
  24. package/dist/app/settings-file.js.map +1 -0
  25. package/dist/app/shortcuts.js +31 -0
  26. package/dist/app/shortcuts.js.map +1 -0
  27. package/dist/app/sidebar.js +50 -0
  28. package/dist/app/sidebar.js.map +1 -0
  29. package/dist/app/status-line.js +29 -0
  30. package/dist/app/status-line.js.map +1 -0
  31. package/dist/app/task-line.js +19 -0
  32. package/dist/app/task-line.js.map +1 -0
  33. package/dist/app/updates.js +17 -0
  34. package/dist/app/updates.js.map +1 -0
  35. package/dist/app/use-screen.js +24 -0
  36. package/dist/app/use-screen.js.map +1 -0
  37. package/dist/app/views.js +68 -0
  38. package/dist/app/views.js.map +1 -0
  39. package/dist/main.js +124 -0
  40. package/dist/main.js.map +1 -0
  41. package/dist/panels/account/account-picker.js +118 -0
  42. package/dist/panels/account/account-picker.js.map +1 -0
  43. package/dist/panels/account/describe.js +14 -0
  44. package/dist/panels/account/describe.js.map +1 -0
  45. package/dist/panels/account/sign-in-view.js +8 -0
  46. package/dist/panels/account/sign-in-view.js.map +1 -0
  47. package/dist/panels/account/use-sign-in.js +46 -0
  48. package/dist/panels/account/use-sign-in.js.map +1 -0
  49. package/dist/panels/context.js +55 -0
  50. package/dist/panels/context.js.map +1 -0
  51. package/dist/panels/diff/change-list.js +48 -0
  52. package/dist/panels/diff/change-list.js.map +1 -0
  53. package/dist/panels/diff/current-view.js +47 -0
  54. package/dist/panels/diff/current-view.js.map +1 -0
  55. package/dist/panels/diff/diff-panel.js +22 -0
  56. package/dist/panels/diff/diff-panel.js.map +1 -0
  57. package/dist/panels/diff/file-diff.js +19 -0
  58. package/dist/panels/diff/file-diff.js.map +1 -0
  59. package/dist/panels/diff/views.js +29 -0
  60. package/dist/panels/diff/views.js.map +1 -0
  61. package/dist/panels/feedback.js +67 -0
  62. package/dist/panels/feedback.js.map +1 -0
  63. package/dist/panels/help.js +79 -0
  64. package/dist/panels/help.js.map +1 -0
  65. package/dist/panels/map.js +80 -0
  66. package/dist/panels/map.js.map +1 -0
  67. package/dist/panels/mcp.js +129 -0
  68. package/dist/panels/mcp.js.map +1 -0
  69. package/dist/panels/memory.js +55 -0
  70. package/dist/panels/memory.js.map +1 -0
  71. package/dist/panels/mode.js +36 -0
  72. package/dist/panels/mode.js.map +1 -0
  73. package/dist/panels/model.js +20 -0
  74. package/dist/panels/model.js.map +1 -0
  75. package/dist/panels/onboarding/claude-setup-panel.js +68 -0
  76. package/dist/panels/onboarding/claude-setup-panel.js.map +1 -0
  77. package/dist/panels/onboarding/onboarding-panel.js +56 -0
  78. package/dist/panels/onboarding/onboarding-panel.js.map +1 -0
  79. package/dist/panels/onboarding/use-onboarding.js +65 -0
  80. package/dist/panels/onboarding/use-onboarding.js.map +1 -0
  81. package/dist/panels/profile.js +31 -0
  82. package/dist/panels/profile.js.map +1 -0
  83. package/dist/panels/release-notes.js +60 -0
  84. package/dist/panels/release-notes.js.map +1 -0
  85. package/dist/panels/resume.js +52 -0
  86. package/dist/panels/resume.js.map +1 -0
  87. package/dist/panels/rewind/changes.js +20 -0
  88. package/dist/panels/rewind/changes.js.map +1 -0
  89. package/dist/panels/rewind/rewind-panel.js +93 -0
  90. package/dist/panels/rewind/rewind-panel.js.map +1 -0
  91. package/dist/panels/sign-in/sign-in-panel.js +56 -0
  92. package/dist/panels/sign-in/sign-in-panel.js.map +1 -0
  93. package/dist/panels/sign-in/use-jinion-sign-in.js +69 -0
  94. package/dist/panels/sign-in/use-jinion-sign-in.js.map +1 -0
  95. package/dist/panels/statusline.js +94 -0
  96. package/dist/panels/statusline.js.map +1 -0
  97. package/dist/panels/tasks/output.js +23 -0
  98. package/dist/panels/tasks/output.js.map +1 -0
  99. package/dist/panels/tasks/task-output.js +29 -0
  100. package/dist/panels/tasks/task-output.js.map +1 -0
  101. package/dist/panels/tasks/tasks-panel.js +75 -0
  102. package/dist/panels/tasks/tasks-panel.js.map +1 -0
  103. package/dist/panels/terminal-setup.js +41 -0
  104. package/dist/panels/terminal-setup.js.map +1 -0
  105. package/dist/panels/usage/section.js +16 -0
  106. package/dist/panels/usage/section.js.map +1 -0
  107. package/dist/panels/usage/stats-view.js +52 -0
  108. package/dist/panels/usage/stats-view.js.map +1 -0
  109. package/dist/panels/usage/usage-panel.js +68 -0
  110. package/dist/panels/usage/usage-panel.js.map +1 -0
  111. package/dist/panels/usage/usage-view.js +51 -0
  112. package/dist/panels/usage/usage-view.js.map +1 -0
  113. package/dist/prompt/attachments.js +91 -0
  114. package/dist/prompt/attachments.js.map +1 -0
  115. package/dist/prompt/draft.js +24 -0
  116. package/dist/prompt/draft.js.map +1 -0
  117. package/dist/prompt/images.js +84 -0
  118. package/dist/prompt/images.js.map +1 -0
  119. package/dist/prompt/pasted-path.js +19 -0
  120. package/dist/prompt/pasted-path.js.map +1 -0
  121. package/dist/prompt/use-prompt.js +62 -0
  122. package/dist/prompt/use-prompt.js.map +1 -0
  123. package/dist/serve.js +38 -0
  124. package/dist/serve.js.map +1 -0
  125. package/dist/state/session.js +93 -0
  126. package/dist/state/session.js.map +1 -0
  127. package/dist/status/data.js +39 -0
  128. package/dist/status/data.js.map +1 -0
  129. package/dist/status/git.js +18 -0
  130. package/dist/status/git.js.map +1 -0
  131. package/dist/status/items.js +8 -0
  132. package/dist/status/items.js.map +1 -0
  133. package/dist/status/line.js +25 -0
  134. package/dist/status/line.js.map +1 -0
  135. package/dist/status/saved.js +8 -0
  136. package/dist/status/saved.js.map +1 -0
  137. package/dist/status/segment.js +2 -0
  138. package/dist/status/segment.js.map +1 -0
  139. package/dist/status/segments/conversation.js +71 -0
  140. package/dist/status/segments/conversation.js.map +1 -0
  141. package/dist/status/segments/git.js +33 -0
  142. package/dist/status/segments/git.js.map +1 -0
  143. package/dist/status/segments/identity.js +71 -0
  144. package/dist/status/segments/identity.js.map +1 -0
  145. package/dist/status/segments/index.js +27 -0
  146. package/dist/status/segments/index.js.map +1 -0
  147. package/dist/status/segments/usage.js +61 -0
  148. package/dist/status/segments/usage.js.map +1 -0
  149. package/dist/terminal/apple-terminal.js +65 -0
  150. package/dist/terminal/apple-terminal.js.map +1 -0
  151. package/dist/ui/banner.js +36 -0
  152. package/dist/ui/banner.js.map +1 -0
  153. package/dist/ui/entries/changes-card.js +27 -0
  154. package/dist/ui/entries/changes-card.js.map +1 -0
  155. package/dist/ui/entries/entry-view.js +82 -0
  156. package/dist/ui/entries/entry-view.js.map +1 -0
  157. package/dist/ui/entries/status-entries.js +33 -0
  158. package/dist/ui/entries/status-entries.js.map +1 -0
  159. package/dist/ui/entries/tools/agent-view.js +39 -0
  160. package/dist/ui/entries/tools/agent-view.js.map +1 -0
  161. package/dist/ui/entries/tools/mcp-view.js +10 -0
  162. package/dist/ui/entries/tools/mcp-view.js.map +1 -0
  163. package/dist/ui/entries/tools/result-preview.js +19 -0
  164. package/dist/ui/entries/tools/result-preview.js.map +1 -0
  165. package/dist/ui/entries/tools/search.js +42 -0
  166. package/dist/ui/entries/tools/search.js.map +1 -0
  167. package/dist/ui/entries/tools/shell-footer.js +36 -0
  168. package/dist/ui/entries/tools/shell-footer.js.map +1 -0
  169. package/dist/ui/entries/tools/tool-view.js +47 -0
  170. package/dist/ui/entries/tools/tool-view.js.map +1 -0
  171. package/dist/ui/entries/tools/web.js +41 -0
  172. package/dist/ui/entries/tools/web.js.map +1 -0
  173. package/dist/ui/modes.js +13 -0
  174. package/dist/ui/modes.js.map +1 -0
  175. package/dist/ui/task-marks.js +7 -0
  176. package/dist/ui/task-marks.js.map +1 -0
  177. package/dist/ui/use-async.js +17 -0
  178. package/dist/ui/use-async.js.map +1 -0
  179. package/dist/ui/use-map-overview.js +27 -0
  180. package/dist/ui/use-map-overview.js.map +1 -0
  181. package/dist/ui/use-pager.js +25 -0
  182. package/dist/ui/use-pager.js.map +1 -0
  183. package/dist/ui/use-project-files.js +18 -0
  184. package/dist/ui/use-project-files.js.map +1 -0
  185. package/dist/ui/use-workdir.js +9 -0
  186. package/dist/ui/use-workdir.js.map +1 -0
  187. package/dist/update/updater.js +68 -0
  188. package/dist/update/updater.js.map +1 -0
  189. package/dist/update/versions.js +31 -0
  190. package/dist/update/versions.js.map +1 -0
  191. package/package.json +35 -3
  192. package/README.md +0 -3
@@ -0,0 +1,91 @@
1
+ import { realpathSync } from 'node:fs';
2
+ import { basename, isAbsolute, relative } from 'node:path';
3
+ import { createContext, useContext } from 'react';
4
+ import { PastedFiles, PastedImages, PastedTexts } from '@jinion/tui/chat';
5
+ import { attachmentKind } from '@jinion/core/attachments/kinds';
6
+ import { errorMessage } from '@jinion/core/lib/errors';
7
+ import { clipboardImage, imageFromPaste } from './images.js';
8
+ import { pastedFile } from './pasted-path.js';
9
+ /**
10
+ * What was pasted into the prompt, shown there as placeholders. Kept for the whole run, so a message recalled from
11
+ * history still carries its pastes, images and files.
12
+ */
13
+ export class Attachments {
14
+ host;
15
+ texts = new PastedTexts();
16
+ images = new PastedImages();
17
+ files = new PastedFiles();
18
+ constructor(host) {
19
+ this.host = host;
20
+ }
21
+ /**
22
+ * `text` as typed, with what goes to the agent when the pastes in it make that differ: pasted text in full, images,
23
+ * and each file as `[File #1]`, numbered in the order they stand, with its id for the core to say what it is.
24
+ */
25
+ async submission(text) {
26
+ const files = this.files.in(text);
27
+ await Promise.all(files.map(({ file }) => file.settled));
28
+ // A file the core didn't take stays in the message as it was typed.
29
+ const sent = files.filter(({ file }) => file.id !== undefined);
30
+ const expanded = sent.reduce((prompt, { placeholder }, index) => prompt.replaceAll(placeholder, `[File #${index + 1}]`), this.texts.expand(text));
31
+ const images = this.images.in(text);
32
+ if (expanded === text && images.length === 0)
33
+ return { text };
34
+ return { text, prompt: { text: expanded, images }, ...(sent.length > 0 && { attachments: sent.map(({ file }) => file.id) }) };
35
+ }
36
+ /** A pasted path goes in as the image it names, or as the file, when that is one the agent is better handed. */
37
+ pastePath(text) {
38
+ try {
39
+ const image = imageFromPaste(text);
40
+ if (image)
41
+ return this.images.add(image);
42
+ const path = pastedFile(text);
43
+ return path && this.goesAlong(path) ? this.attach(path) : undefined;
44
+ }
45
+ catch (error) {
46
+ this.host.notice(errorMessage(error), 'warning');
47
+ return undefined;
48
+ }
49
+ }
50
+ async pasteClipboard() {
51
+ try {
52
+ const image = await clipboardImage();
53
+ if (image)
54
+ return this.images.add(image);
55
+ this.host.notice('There is no image on the clipboard. Text pastes with your terminal’s paste, e.g. cmd+v.', 'muted');
56
+ }
57
+ catch (error) {
58
+ this.host.notice(errorMessage(error), 'warning');
59
+ }
60
+ return undefined;
61
+ }
62
+ /**
63
+ * A file from outside where the session works is attached, and so is a recording, a PDF or a workbook from inside,
64
+ * which the core makes readable. Any other file of the project stays the path it is: the agent reads and changes
65
+ * it where it is, not a copy of it.
66
+ */
67
+ goesAlong(path) {
68
+ // By where both really are: a folder reached through a link, as a temporary one on macOS, is named two ways.
69
+ const file = realpathSync(path);
70
+ const inside = this.host.folders().some((folder) => {
71
+ const from = relative(realpathSync(folder), file);
72
+ return !from.startsWith('..') && !isAbsolute(from);
73
+ });
74
+ return !inside || attachmentKind(path) !== 'file';
75
+ }
76
+ attach(path) {
77
+ const file = { settled: Promise.resolve() };
78
+ file.settled = this.host.attach(basename(path), path).then((attachment) => {
79
+ file.id = attachment.id;
80
+ }, (error) => this.host.notice(errorMessage(error), 'warning'));
81
+ return this.files.add(basename(path), file);
82
+ }
83
+ }
84
+ export const AttachmentsContext = createContext(undefined);
85
+ export function useAttachments() {
86
+ const attachments = useContext(AttachmentsContext);
87
+ if (!attachments)
88
+ throw new Error('useAttachments() must be called inside <App>.');
89
+ return attachments;
90
+ }
91
+ //# sourceMappingURL=attachments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../src/prompt/attachments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { atom } from 'jotai';
2
+ import { shownAtom } from '../state/session.js';
3
+ /** Each session's draft. It is the client's: the core only puts text in it, e.g. the message a rewind went back to. */
4
+ export const draftsAtom = atom({});
5
+ /** The sessions whose draft holds their queued messages, taken back to edit; sent, it goes back in the queue. */
6
+ export const requeuesAtom = atom({});
7
+ /** The draft of the session the user looks at. */
8
+ export const draftAtom = atom((get) => get(draftsAtom)[get(shownAtom).id] ?? '', (get, set, update) => {
9
+ const session = get(shownAtom).id;
10
+ const next = typeof update === 'function' ? update(get(draftsAtom)[session] ?? '') : update;
11
+ set(draftsAtom, (drafts) => ({ ...drafts, [session]: next }));
12
+ // An emptied draft no longer holds the queued messages.
13
+ if (next === '')
14
+ set(requeuesAtom, ({ [session]: _, ...rest }) => rest);
15
+ });
16
+ /** Whether the shown session's draft holds its queued messages. */
17
+ export const requeueAtom = atom((get) => get(requeuesAtom)[get(shownAtom).id] ?? false);
18
+ /** What was sent, in every session, for `up` to bring back. */
19
+ export const historyAtom = atom([]);
20
+ export function fillDraft(drafts, session, text, fill) {
21
+ const draft = fill === 'replace' ? text : [text, drafts[session]].filter(Boolean).join('\n');
22
+ return { ...drafts, [session]: draft };
23
+ }
24
+ //# sourceMappingURL=draft.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/prompt/draft.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuB,MAAM,OAAO,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,uHAAuH;AACvH,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAyB,EAAE,CAAC,CAAC;AAE3D,iHAAiH;AACjH,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAA0B,EAAE,CAAC,CAAC;AAE9D,kDAAkD;AAClD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAC3B,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EACjD,CAAC,GAAG,EAAE,GAAG,EAAE,MAA8B,EAAE,EAAE;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAE5F,GAAG,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9D,wDAAwD;IACxD,IAAI,IAAI,KAAK,EAAE;QAAE,GAAG,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAC1E,CAAC,CACF,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC;AAExF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAW,EAAE,CAAC,CAAC;AAE9C,MAAM,UAAU,SAAS,CAAC,MAA8B,EAAE,OAAe,EAAE,IAAY,EAAE,IAAgB;IACvG,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE7F,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,84 @@
1
+ import { execFile, execFileSync } from 'node:child_process';
2
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { extname, join } from 'node:path';
5
+ import { pastedFile } from './pasted-path.js';
6
+ const MEDIA_TYPES = {
7
+ '.png': 'image/png',
8
+ '.jpg': 'image/jpeg',
9
+ '.jpeg': 'image/jpeg',
10
+ '.gif': 'image/gif',
11
+ '.webp': 'image/webp',
12
+ };
13
+ /** Claude takes images up to 5 MB once encoded, and base64 makes them a third bigger. */
14
+ const MAX_BYTES = 3_750_000;
15
+ const SHRINK_TO = 2048;
16
+ /** The image a pasted path names, read to go in the prompt; nothing for a file of another kind. */
17
+ export function imageFromPaste(text) {
18
+ const path = pastedFile(text);
19
+ const mediaType = path && MEDIA_TYPES[extname(path).toLowerCase()];
20
+ if (!path || !mediaType)
21
+ return undefined;
22
+ return fitting(readFileSync(path), mediaType);
23
+ }
24
+ export async function clipboardImage() {
25
+ const png = await clipboardPng();
26
+ return png && png.length > 0 ? fitting(png, 'image/png') : undefined;
27
+ }
28
+ function clipboardPng() {
29
+ if (process.platform === 'darwin') {
30
+ const folder = mkdtempSync(join(tmpdir(), 'jinion-clipboard-'));
31
+ const file = join(folder, 'clipboard.png');
32
+ // AppleScript writes the clipboard's PNG data to a file, and fails when the clipboard holds no image.
33
+ const script = [
34
+ 'set png to (the clipboard as «class PNGf»)',
35
+ `set out to open for access POSIX file "${file}" with write permission`,
36
+ 'set eof out to 0',
37
+ 'write png to out',
38
+ 'close access out',
39
+ ];
40
+ return new Promise((resolve) => {
41
+ execFile('osascript', script.flatMap((line) => ['-e', line]), (error) => {
42
+ resolve(error || !existsSync(file) ? undefined : readFileSync(file));
43
+ rmSync(folder, { recursive: true, force: true });
44
+ });
45
+ });
46
+ }
47
+ if (process.platform === 'linux') {
48
+ const read = (command, args) => new Promise((resolve) => {
49
+ execFile(command, args, { encoding: 'buffer', maxBuffer: 64 * 1024 * 1024 }, (error, stdout) => resolve(error ? undefined : stdout));
50
+ });
51
+ return read('wl-paste', ['--type', 'image/png']).then((png) => png ?? read('xclip', ['-selection', 'clipboard', '-t', 'image/png', '-o']));
52
+ }
53
+ return Promise.resolve(undefined);
54
+ }
55
+ function fitting(bytes, mediaType) {
56
+ if (bytes.length <= MAX_BYTES)
57
+ return { mediaType, data: bytes.toString('base64') };
58
+ const smaller = shrink(bytes);
59
+ if (!smaller || smaller.length > MAX_BYTES) {
60
+ throw new Error(`The image is ${(bytes.length / 1_000_000).toFixed(1)} MB; Claude takes images up to 3.7 MB.`);
61
+ }
62
+ return { mediaType: 'image/jpeg', data: smaller.toString('base64') };
63
+ }
64
+ function shrink(bytes) {
65
+ if (process.platform !== 'darwin')
66
+ return undefined;
67
+ const folder = mkdtempSync(join(tmpdir(), 'jinion-image-'));
68
+ try {
69
+ const source = join(folder, 'source');
70
+ const target = join(folder, 'target.jpg');
71
+ writeFileSync(source, bytes);
72
+ execFileSync('sips', ['-Z', String(SHRINK_TO), '-s', 'format', 'jpeg', '-s', 'formatOptions', '80', source, '--out', target], {
73
+ stdio: 'ignore',
74
+ });
75
+ return readFileSync(target);
76
+ }
77
+ catch {
78
+ return undefined;
79
+ }
80
+ finally {
81
+ rmSync(folder, { recursive: true, force: true });
82
+ }
83
+ }
84
+ //# sourceMappingURL=images.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/prompt/images.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,WAAW,GAA2B;IAC1C,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;CACtB,CAAC;AAEF,yFAAyF;AACzF,MAAM,SAAS,GAAG,SAAS,CAAC;AAE5B,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB,mGAAmG;AACnG,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAE1C,OAAO,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,GAAG,GAAG,MAAM,YAAY,EAAE,CAAC;IAEjC,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAE3C,sGAAsG;QACtG,MAAM,MAAM,GAAG;YACb,4CAA4C;YAC5C,0CAA0C,IAAI,yBAAyB;YACvE,kBAAkB;YAClB,kBAAkB;YAClB,kBAAkB;SACnB,CAAC;QAEF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE;gBACtE,OAAO,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;gBACrE,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnD,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,IAAc,EAAE,EAAE,CAC/C,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,EAAE;YAC1C,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAC7F,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CACpC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEL,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CACnD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CACpF,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,OAAO,CAAC,KAAa,EAAE,SAAiB;IAC/C,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;IAEpF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwC,CAAC,CAAC;IACjH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAEpD,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAE1C,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAE7B,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE;YAC5H,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;QAEH,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { isAbsolute, join } from 'node:path';
4
+ /**
5
+ * The file whose path a paste is, when it is one and nothing else: terminals paste a dragged file's path quoted, with
6
+ * backslashes before spaces, or as a `file://` URL.
7
+ */
8
+ export function pastedFile(text) {
9
+ let path = text.trim();
10
+ if (!path || path.includes('\n'))
11
+ return undefined;
12
+ if (path.startsWith('file://'))
13
+ path = decodeURIComponent(path.slice('file://'.length));
14
+ path = path.replace(/^(['"])(.*)\1$/, '$2').replace(/\\(.)/g, '$1');
15
+ if (path.startsWith('~/'))
16
+ path = join(homedir(), path.slice(2));
17
+ return isAbsolute(path) && existsSync(path) && statSync(path).isFile() ? path : undefined;
18
+ }
19
+ //# sourceMappingURL=pasted-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pasted-path.js","sourceRoot":"","sources":["../../src/prompt/pasted-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE7C;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACvB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAEnD,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACxF,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpE,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjE,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5F,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { useStore } from 'jotai';
2
+ import { queueAtom, shownAtom, steeringAtom } from '../state/session.js';
3
+ import { useApi } from '../app/api.js';
4
+ import { useAttachments } from './attachments.js';
5
+ import { draftAtom, draftsAtom, fillDraft, historyAtom, requeueAtom, requeuesAtom } from './draft.js';
6
+ /** Sends the draft of the session the user looks at; what is sent goes to the history and leaves the prompt. */
7
+ export function usePrompt() {
8
+ const api = useApi();
9
+ const attachments = useAttachments();
10
+ const store = useStore();
11
+ const take = (value = store.get(draftAtom)) => {
12
+ const text = value.trim();
13
+ if (!text)
14
+ return undefined;
15
+ store.set(historyAtom, (history) => [...history, text]);
16
+ store.set(draftAtom, '');
17
+ return text;
18
+ };
19
+ const queue = (value) => {
20
+ const text = take(value);
21
+ if (text)
22
+ api.act(attachments.submission(text).then((submission) => api.inSession('session/queue', submission)));
23
+ };
24
+ return {
25
+ /** Queued messages taken back to edit go back in the queue, and are sent as any message once the turn has ended. */
26
+ submit(value) {
27
+ if (store.get(requeueAtom))
28
+ return queue(value);
29
+ const text = take(value);
30
+ if (text)
31
+ api.act(attachments.submission(text).then((submission) => api.inSession('session/submit', submission)));
32
+ },
33
+ queue,
34
+ /** Kept in the history, so `up` brings it back. */
35
+ clear() {
36
+ take();
37
+ },
38
+ /**
39
+ * Takes back into the prompt, as one, the steered messages the agent hasn't read yet and then the queued ones. Sent
40
+ * again, they steer the turn when any of them did, and go back in the queue when all were queued.
41
+ */
42
+ takeBack() {
43
+ const session = store.get(shownAtom).id;
44
+ const queued = store.get(queueAtom);
45
+ const steering = store.get(steeringAtom).length > 0;
46
+ api.act(Promise.all([
47
+ steering ? api.inSession('session/unsteer', {}) : [],
48
+ Promise.all(queued.map(({ text }) => api.inSession('session/unqueue', { text }))),
49
+ ]).then(([steered, unqueued]) => {
50
+ // The agent may have read them, or the turn ended and sent them, meanwhile.
51
+ const texts = [...steered, ...unqueued.flatMap((submission) => (submission ? [submission.text] : []))];
52
+ if (texts.length === 0)
53
+ return;
54
+ // Before anything typed since, as the core puts them back when a turn stops.
55
+ store.set(draftsAtom, (drafts) => fillDraft(drafts, session, texts.join('\n'), 'prepend'));
56
+ if (steered.length === 0)
57
+ store.set(requeuesAtom, (all) => ({ ...all, [session]: true }));
58
+ }));
59
+ },
60
+ };
61
+ }
62
+ //# sourceMappingURL=use-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-prompt.js","sourceRoot":"","sources":["../../src/prompt/use-prompt.ts"],"names":[],"mappings":"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"}
package/dist/serve.js ADDED
@@ -0,0 +1,38 @@
1
+ import { newToken, removeServerFile, writeServerFile } from '@jinion/core/api/server-file';
2
+ import { streamTransport } from '@jinion/core/api/stream-transport';
3
+ import { listenWebSocket } from '@jinion/core/api/websocket';
4
+ import { tildify } from '@jinion/core/lib/paths';
5
+ /**
6
+ * `jinion serve`: the core without a screen, for clients to drive. Resolves once it has stopped, on ctrl+c or when the
7
+ * stdio client goes; what it says goes to stderr, since stdout may carry the API.
8
+ */
9
+ export async function serve(server, options) {
10
+ const { cwd, version, stdio } = options;
11
+ if (stdio) {
12
+ const transport = streamTransport(process.stdin, process.stdout);
13
+ const connection = server.connect(transport);
14
+ await new Promise((resolve) => {
15
+ connection.peer.onClose(resolve);
16
+ stopOnSignal(() => transport.close());
17
+ });
18
+ return server.app.quit();
19
+ }
20
+ const token = newToken();
21
+ const listening = await listenWebSocket({ port: options.port, token, origins: options.origins }, (transport) => server.connect(transport));
22
+ const file = writeServerFile({ url: listening.url, token, cwd, pid: process.pid, version });
23
+ console.error(`jinion serves ${tildify(cwd)} at ${listening.url}`);
24
+ console.error(`Clients find its token in ${tildify(file)}, which only you can read. jinion --attach shows it here; ctrl+c stops it.`);
25
+ await new Promise((resolve) => stopOnSignal(resolve));
26
+ try {
27
+ await server.app.quit();
28
+ await listening.close();
29
+ }
30
+ finally {
31
+ removeServerFile(file);
32
+ }
33
+ }
34
+ function stopOnSignal(stop) {
35
+ process.once('SIGINT', stop);
36
+ process.once('SIGTERM', stop);
37
+ }
38
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE3F,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAYjD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,MAAoB,EAAE,OAAqB;IACrE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAExC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACjE,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAE7C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACjC,YAAY,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3I,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAE5F,OAAO,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,GAAG,CAAC,OAAO,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,CAAC,6BAA6B,OAAO,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;IAEtI,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;YAAS,CAAC;QACT,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,IAAgB;IACpC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,93 @@
1
+ import { atom } from 'jotai';
2
+ import { modelLabel, modelName } from '@jinion/core/agent/models';
3
+ import { editTurns } from '@jinion/core/conversation/edits';
4
+ import { skillMention } from '@jinion/core/prompt/skills';
5
+ /** Set once as the app starts; everything below reads the client's store through it. */
6
+ export const clientAtom = atom(undefined);
7
+ function client(get) {
8
+ const found = get(clientAtom);
9
+ if (!found)
10
+ throw new Error('The app has no client yet.');
11
+ return found;
12
+ }
13
+ /** The session the app shows: the active one, once the client holds it. */
14
+ export const shownAtom = atom((get) => {
15
+ const following = client(get);
16
+ const id = get(following.shownAtom);
17
+ const snapshot = id === undefined ? undefined : get(following.session(id));
18
+ if (id === undefined || !snapshot)
19
+ throw new Error('No session is shown yet.');
20
+ return { id, ...snapshot };
21
+ });
22
+ export const sessionAtom = atom((get) => get(shownAtom).state);
23
+ /** Every open session, in the order they opened; the client follows them all. */
24
+ export const tabsAtom = atom((get) => {
25
+ const following = client(get);
26
+ const shown = get(following.shownAtom);
27
+ return get(following.sessionsAtom).sessions.map(({ id, title, working }) => ({
28
+ id,
29
+ title,
30
+ working,
31
+ waiting: get(following.session(id))?.fields.dialog !== undefined,
32
+ shown: id === shown,
33
+ }));
34
+ });
35
+ export const entriesAtom = atom((get) => get(sessionAtom).entries);
36
+ export const todosAtom = atom((get) => get(sessionAtom).todos);
37
+ export const worktreeAtom = atom((get) => get(sessionAtom).worktree);
38
+ export const busySinceAtom = atom((get) => get(sessionAtom).busySince);
39
+ export const busyAtom = atom((get) => get(busySinceAtom) !== undefined);
40
+ export const editTurnsAtom = atom((get) => editTurns(get(entriesAtom)));
41
+ const fields = (get) => get(shownAtom).fields;
42
+ /** From the moment a turn starts until it ends, also before its first event. */
43
+ export const workingAtom = atom((get) => fields(get).working);
44
+ export const queueAtom = atom((get) => fields(get).queue);
45
+ /** Steered into the running turn; each joins the conversation once the agent reads it. */
46
+ export const steeringAtom = atom((get) => fields(get).steering ?? []);
47
+ /** The files put with the session's messages that the core is still reading, each with what is being done to it. */
48
+ export const readingAtom = atom((get) => (fields(get).attachments ?? []).filter((file) => file.reading !== undefined));
49
+ export const selectionAtom = atom((get) => fields(get).selection);
50
+ export const modeAtom = atom((get) => fields(get).mode);
51
+ /** Includes the command or subagent the turn waits for, as `foreground`. */
52
+ export const tasksAtom = atom((get) => fields(get).tasks);
53
+ export const backgroundTasksAtom = atom((get) => get(tasksAtom).filter((task) => !task.foreground));
54
+ export const waitsOnForegroundTaskAtom = atom((get) => get(tasksAtom).some((task) => task.foreground && task.status === 'running'));
55
+ export const dialogAtom = atom((get) => fields(get).dialog);
56
+ function app(get) {
57
+ const found = get(client(get).appAtom);
58
+ if (!found)
59
+ throw new Error('The client is not initialized yet.');
60
+ return found;
61
+ }
62
+ /** The backend the shown session runs on, with what it and the session on it can do. */
63
+ export const agentAtom = atom((get) => {
64
+ const { agent: name, features } = fields(get);
65
+ const info = app(get).agents.find((candidate) => candidate.name === name);
66
+ if (!info)
67
+ throw new Error(`The server didn't describe ${name}.`);
68
+ return { ...info, features: { ...info.features, ...features } };
69
+ });
70
+ /** Whether `up` in an empty prompt has messages to take back: queued ones, or steered ones the agent can give back. */
71
+ export const takeBackAtom = atom((get) => get(queueAtom).length > 0 || (get(steeringAtom).length > 0 && get(agentAtom).features.unsteer === true));
72
+ export const agentsAtom = atom((get) => app(get).agents);
73
+ /** Every backend's models, by backend; one is missing until it has listed them. */
74
+ export const allModelsAtom = atom((get) => app(get).models);
75
+ export const modelsAtom = atom((get) => app(get).models[get(agentAtom).name]);
76
+ export const accountAtom = atom((get) => app(get).accounts[get(agentAtom).name]);
77
+ export const identityAtom = atom((get) => app(get).identities[get(agentAtom).name]);
78
+ const noSkills = [];
79
+ export const skillsAtom = atom((get) => app(get).skills[get(agentAtom).name] ?? noSkills);
80
+ export const seenLimitsAtom = atom((get) => app(get).seenLimits);
81
+ /** Who is signed in to Jinion's own account; null until someone is, and the app shows only its sign-in until then. */
82
+ export const jinionUserAtom = atom((get) => app(get).jinionUser ?? null);
83
+ const noAnnouncements = [];
84
+ /** What the Jinion team says now that this user hasn't put away. */
85
+ export const announcementsAtom = atom((get) => app(get).announcements ?? noAnnouncements);
86
+ /** Whether onboarding offered Claude Code's setup, in this app or the desktop one; until then it comes before the app. */
87
+ export const claudeSetupOfferedAtom = atom((get) => app(get).claudeSetupOffered === true);
88
+ /** The default for new sessions, which `ctrl+g` turns on and off. */
89
+ export const worktreesAtom = atom((get) => app(get).worktrees);
90
+ export const mentionAtom = atom((get) => skillMention(get(skillsAtom)));
91
+ export const modelNameAtom = atom((get) => modelName(get(selectionAtom), get(modelsAtom)));
92
+ export const modelLabelAtom = atom((get) => modelLabel(get(selectionAtom), get(modelsAtom)));
93
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/state/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { useTheme } from '@jinion/tui';
3
+ import { atom, useAtomValue } from 'jotai';
4
+ import { limitsKey } from '@jinion/core/agent/usage';
5
+ import { useApi } from '../app/api.js';
6
+ import { accountAtom, agentAtom, identityAtom, modeAtom, modelNameAtom, seenLimitsAtom, selectionAtom, sessionAtom } from '../state/session.js';
7
+ /** Set by the status line, which runs `git status` only while a shown segment needs it. */
8
+ export const gitStatusAtom = atom(undefined);
9
+ export function useStatusData(now = Date.now()) {
10
+ const { info } = useApi().initialized;
11
+ const agent = useAtomValue(agentAtom);
12
+ const account = useAtomValue(accountAtom);
13
+ const seen = useAtomValue(seenLimitsAtom);
14
+ return {
15
+ version: info.version,
16
+ cwd: info.cwd,
17
+ agent: agent.name,
18
+ model: { name: useAtomValue(modelNameAtom), selection: useAtomValue(selectionAtom) },
19
+ mode: useAtomValue(modeAtom),
20
+ account: useAtomValue(identityAtom),
21
+ session: useAtomValue(sessionAtom),
22
+ git: useAtomValue(gitStatusAtom),
23
+ limits: seen[limitsKey(agent.name, account)]?.windows,
24
+ now,
25
+ theme: useTheme(),
26
+ };
27
+ }
28
+ export function useNow(active, interval = 15_000) {
29
+ const [now, setNow] = useState(Date.now);
30
+ useEffect(() => {
31
+ if (!active)
32
+ return;
33
+ setNow(Date.now());
34
+ const timer = setInterval(() => setNow(Date.now()), interval);
35
+ return () => clearInterval(timer);
36
+ }, [active, interval]);
37
+ return now;
38
+ }
39
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/status/data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGhJ,2FAA2F;AAC3F,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAwB,SAAS,CAAC,CAAC;AAEpE,MAAM,UAAU,aAAa,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC5C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,WAAW,CAAC;IACtC,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;IAE1C,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,KAAK,EAAE,KAAK,CAAC,IAAI;QACjB,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,aAAa,CAAC,EAAE;QACpF,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC;QAC5B,OAAO,EAAE,YAAY,CAAC,YAAY,CAAC;QACnC,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC;QAClC,GAAG,EAAE,YAAY,CAAC,aAAa,CAAC;QAChC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO;QACrD,GAAG;QACH,KAAK,EAAE,QAAQ,EAAE;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,MAAe,EAAE,QAAQ,GAAG,MAAM;IACvD,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEzC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAEnB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;QAE9D,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvB,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { useApi } from '../app/api.js';
3
+ /** Of the folder the shown session works in, read again as `folder` or `refresh` changes; the last one stays shown meanwhile. */
4
+ export function useGitStatus(folder, enabled, refresh) {
5
+ const api = useApi();
6
+ const [status, setStatus] = useState();
7
+ useEffect(() => {
8
+ if (!enabled)
9
+ return;
10
+ let current = true;
11
+ api.inSession('git/status', {}).then((found) => current && setStatus(found ?? undefined), () => { });
12
+ return () => {
13
+ current = false;
14
+ };
15
+ }, [folder, enabled, refresh]);
16
+ return enabled ? status : undefined;
17
+ }
18
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/status/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,iIAAiI;AACjI,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,OAAgB,EAAE,OAAgB;IAC7E,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IAErB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,EAAa,CAAC;IAElD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,IAAI,OAAO,GAAG,IAAI,CAAC;QAEnB,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,IAAI,CAClC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,IAAI,SAAS,CAAC,KAAK,IAAI,SAAS,CAAC,EACnD,GAAG,EAAE,GAAE,CAAC,CACT,CAAC;QAEF,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAE/B,OAAO,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { atom } from 'jotai';
2
+ import { persistedAtom } from '@jinion/core/lib/persisted';
3
+ import { DEFAULT_STATUS_LINE, knownItems } from './line.js';
4
+ import { loadStatusLine, saveStatusLine } from './saved.js';
5
+ export const statusItemsAtom = persistedAtom(() => knownItems(loadStatusLine() ?? DEFAULT_STATUS_LINE), saveStatusLine);
6
+ export const statusPreviewAtom = atom(undefined);
7
+ export const shownStatusItemsAtom = atom((get) => get(statusPreviewAtom) ?? get(statusItemsAtom));
8
+ //# sourceMappingURL=items.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"items.js","sourceRoot":"","sources":["../../src/status/items.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAmB,MAAM,YAAY,CAAC;AAE7E,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,cAAc,EAAE,IAAI,mBAAmB,CAAC,EAAE,cAAc,CAAC,CAAC;AAExH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAA2B,SAAS,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { findSegment } from './segments/index.js';
2
+ export const DEFAULT_STATUS_LINE = [
3
+ { id: 'brand', side: 'left' },
4
+ { id: 'model', side: 'left' },
5
+ { id: 'directory', side: 'left' },
6
+ { id: 'worktree', side: 'left' },
7
+ { id: 'context', side: 'left' },
8
+ { id: 'cost', side: 'left' },
9
+ { id: 'title', side: 'right' },
10
+ ];
11
+ export function renderStatusLine(items, data) {
12
+ const left = [];
13
+ const right = [];
14
+ for (const item of items) {
15
+ const node = findSegment(item.id)?.render(data, styleOf(item));
16
+ if (node === undefined || node === null || node === false || node === '')
17
+ continue;
18
+ (item.side === 'right' ? right : left).push(node);
19
+ }
20
+ return { left, right };
21
+ }
22
+ export const styleOf = (item) => item.style ?? findSegment(item.id)?.styles?.[0]?.id ?? '';
23
+ /** Settings can name segments a later version dropped. */
24
+ export const knownItems = (items) => items.filter((item) => findSegment(item.id));
25
+ //# sourceMappingURL=line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line.js","sourceRoot":"","sources":["../../src/status/line.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAC/C,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE;IAC7B,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE;IAC7B,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;IACjC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE;IAChC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE;IAC/B,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;IAC5B,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE;CAC/B,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,KAAmB,EAAE,IAAgB;IACpE,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAgB,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/D,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,EAAE;YAAE,SAAS;QAEnF,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;AAEvG,0DAA0D;AAC1D,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAmB,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { join } from 'node:path';
2
+ import { readJson, updateJson } from '@jinion/core/lib/json-file';
3
+ import { jinionHome } from '@jinion/core/lib/paths';
4
+ /** The layout is this app's own, kept in the user's settings file beside what the core keeps there. */
5
+ const file = () => join(jinionHome(), 'settings.json');
6
+ export const loadStatusLine = () => readJson(file(), {}).statusLine;
7
+ export const saveStatusLine = (statusLine) => updateJson(file(), {}, (current) => ({ ...current, statusLine }));
8
+ //# sourceMappingURL=saved.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saved.js","sourceRoot":"","sources":["../../src/status/saved.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAWpD,uGAAuG;AACvG,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,eAAe,CAAC,CAAC;AAEvD,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAgC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC;AAEnG,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,UAAwB,EAAE,EAAE,CAAC,UAAU,CAAS,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const levelColor = (theme, used) => (used >= 0.8 ? theme.error : used >= 0.5 ? theme.warning : theme.success);
2
+ //# sourceMappingURL=segment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"segment.js","sourceRoot":"","sources":["../../src/status/segment.ts"],"names":[],"mappings":"AAsCA,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAY,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC"}