@jinion/cli 0.0.0-stage → 0.3.491
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.
- package/bin/jinion.js +4 -0
- package/dist/app/activity.js +50 -0
- package/dist/app/activity.js.map +1 -0
- package/dist/app/announcements.js +21 -0
- package/dist/app/announcements.js.map +1 -0
- package/dist/app/api.js +26 -0
- package/dist/app/api.js.map +1 -0
- package/dist/app/app.js +91 -0
- package/dist/app/app.js.map +1 -0
- package/dist/app/aside.js +52 -0
- package/dist/app/aside.js.map +1 -0
- package/dist/app/dialogs.js +43 -0
- package/dist/app/dialogs.js.map +1 -0
- package/dist/app/keys.js +79 -0
- package/dist/app/keys.js.map +1 -0
- package/dist/app/prompt-area.js +56 -0
- package/dist/app/prompt-area.js.map +1 -0
- package/dist/app/shortcuts.js +31 -0
- package/dist/app/shortcuts.js.map +1 -0
- package/dist/app/sidebar.js +50 -0
- package/dist/app/sidebar.js.map +1 -0
- package/dist/app/status-line.js +23 -0
- package/dist/app/status-line.js.map +1 -0
- package/dist/app/task-line.js +19 -0
- package/dist/app/task-line.js.map +1 -0
- package/dist/app/use-screen.js +24 -0
- package/dist/app/use-screen.js.map +1 -0
- package/dist/app/views.js +62 -0
- package/dist/app/views.js.map +1 -0
- package/dist/main.js +122 -0
- package/dist/main.js.map +1 -0
- package/dist/panels/account/account-picker.js +118 -0
- package/dist/panels/account/account-picker.js.map +1 -0
- package/dist/panels/account/describe.js +14 -0
- package/dist/panels/account/describe.js.map +1 -0
- package/dist/panels/account/sign-in-view.js +8 -0
- package/dist/panels/account/sign-in-view.js.map +1 -0
- package/dist/panels/account/use-sign-in.js +46 -0
- package/dist/panels/account/use-sign-in.js.map +1 -0
- package/dist/panels/context.js +55 -0
- package/dist/panels/context.js.map +1 -0
- package/dist/panels/diff/change-list.js +48 -0
- package/dist/panels/diff/change-list.js.map +1 -0
- package/dist/panels/diff/current-view.js +47 -0
- package/dist/panels/diff/current-view.js.map +1 -0
- package/dist/panels/diff/diff-panel.js +22 -0
- package/dist/panels/diff/diff-panel.js.map +1 -0
- package/dist/panels/diff/file-diff.js +19 -0
- package/dist/panels/diff/file-diff.js.map +1 -0
- package/dist/panels/diff/views.js +29 -0
- package/dist/panels/diff/views.js.map +1 -0
- package/dist/panels/feedback.js +67 -0
- package/dist/panels/feedback.js.map +1 -0
- package/dist/panels/help.js +79 -0
- package/dist/panels/help.js.map +1 -0
- package/dist/panels/mcp.js +129 -0
- package/dist/panels/mcp.js.map +1 -0
- package/dist/panels/memory.js +55 -0
- package/dist/panels/memory.js.map +1 -0
- package/dist/panels/mode.js +36 -0
- package/dist/panels/mode.js.map +1 -0
- package/dist/panels/model.js +20 -0
- package/dist/panels/model.js.map +1 -0
- package/dist/panels/onboarding/onboarding-panel.js +56 -0
- package/dist/panels/onboarding/onboarding-panel.js.map +1 -0
- package/dist/panels/onboarding/use-onboarding.js +65 -0
- package/dist/panels/onboarding/use-onboarding.js.map +1 -0
- package/dist/panels/profile.js +31 -0
- package/dist/panels/profile.js.map +1 -0
- package/dist/panels/resume.js +52 -0
- package/dist/panels/resume.js.map +1 -0
- package/dist/panels/rewind/changes.js +20 -0
- package/dist/panels/rewind/changes.js.map +1 -0
- package/dist/panels/rewind/rewind-panel.js +93 -0
- package/dist/panels/rewind/rewind-panel.js.map +1 -0
- package/dist/panels/sign-in/sign-in-panel.js +56 -0
- package/dist/panels/sign-in/sign-in-panel.js.map +1 -0
- package/dist/panels/sign-in/use-jinion-sign-in.js +69 -0
- package/dist/panels/sign-in/use-jinion-sign-in.js.map +1 -0
- package/dist/panels/statusline.js +94 -0
- package/dist/panels/statusline.js.map +1 -0
- package/dist/panels/tasks/output.js +23 -0
- package/dist/panels/tasks/output.js.map +1 -0
- package/dist/panels/tasks/task-output.js +29 -0
- package/dist/panels/tasks/task-output.js.map +1 -0
- package/dist/panels/tasks/tasks-panel.js +75 -0
- package/dist/panels/tasks/tasks-panel.js.map +1 -0
- package/dist/panels/terminal-setup.js +41 -0
- package/dist/panels/terminal-setup.js.map +1 -0
- package/dist/panels/usage/section.js +16 -0
- package/dist/panels/usage/section.js.map +1 -0
- package/dist/panels/usage/stats-view.js +52 -0
- package/dist/panels/usage/stats-view.js.map +1 -0
- package/dist/panels/usage/usage-panel.js +68 -0
- package/dist/panels/usage/usage-panel.js.map +1 -0
- package/dist/panels/usage/usage-view.js +51 -0
- package/dist/panels/usage/usage-view.js.map +1 -0
- package/dist/prompt/attachments.js +91 -0
- package/dist/prompt/attachments.js.map +1 -0
- package/dist/prompt/draft.js +24 -0
- package/dist/prompt/draft.js.map +1 -0
- package/dist/prompt/images.js +84 -0
- package/dist/prompt/images.js.map +1 -0
- package/dist/prompt/pasted-path.js +19 -0
- package/dist/prompt/pasted-path.js.map +1 -0
- package/dist/prompt/use-prompt.js +62 -0
- package/dist/prompt/use-prompt.js.map +1 -0
- package/dist/serve.js +38 -0
- package/dist/serve.js.map +1 -0
- package/dist/state/session.js +91 -0
- package/dist/state/session.js.map +1 -0
- package/dist/status/data.js +39 -0
- package/dist/status/data.js.map +1 -0
- package/dist/status/git.js +18 -0
- package/dist/status/git.js.map +1 -0
- package/dist/status/items.js +8 -0
- package/dist/status/items.js.map +1 -0
- package/dist/status/line.js +25 -0
- package/dist/status/line.js.map +1 -0
- package/dist/status/saved.js +8 -0
- package/dist/status/saved.js.map +1 -0
- package/dist/status/segment.js +2 -0
- package/dist/status/segment.js.map +1 -0
- package/dist/status/segments/conversation.js +71 -0
- package/dist/status/segments/conversation.js.map +1 -0
- package/dist/status/segments/git.js +33 -0
- package/dist/status/segments/git.js.map +1 -0
- package/dist/status/segments/identity.js +71 -0
- package/dist/status/segments/identity.js.map +1 -0
- package/dist/status/segments/index.js +27 -0
- package/dist/status/segments/index.js.map +1 -0
- package/dist/status/segments/usage.js +61 -0
- package/dist/status/segments/usage.js.map +1 -0
- package/dist/terminal/apple-terminal.js +68 -0
- package/dist/terminal/apple-terminal.js.map +1 -0
- package/dist/ui/banner.js +24 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/entries/changes-card.js +27 -0
- package/dist/ui/entries/changes-card.js.map +1 -0
- package/dist/ui/entries/entry-view.js +82 -0
- package/dist/ui/entries/entry-view.js.map +1 -0
- package/dist/ui/entries/status-entries.js +33 -0
- package/dist/ui/entries/status-entries.js.map +1 -0
- package/dist/ui/entries/tools/agent-view.js +39 -0
- package/dist/ui/entries/tools/agent-view.js.map +1 -0
- package/dist/ui/entries/tools/mcp-view.js +10 -0
- package/dist/ui/entries/tools/mcp-view.js.map +1 -0
- package/dist/ui/entries/tools/result-preview.js +19 -0
- package/dist/ui/entries/tools/result-preview.js.map +1 -0
- package/dist/ui/entries/tools/search.js +42 -0
- package/dist/ui/entries/tools/search.js.map +1 -0
- package/dist/ui/entries/tools/shell-footer.js +36 -0
- package/dist/ui/entries/tools/shell-footer.js.map +1 -0
- package/dist/ui/entries/tools/tool-view.js +47 -0
- package/dist/ui/entries/tools/tool-view.js.map +1 -0
- package/dist/ui/entries/tools/web.js +41 -0
- package/dist/ui/entries/tools/web.js.map +1 -0
- package/dist/ui/modes.js +13 -0
- package/dist/ui/modes.js.map +1 -0
- package/dist/ui/task-marks.js +7 -0
- package/dist/ui/task-marks.js.map +1 -0
- package/dist/ui/use-async.js +17 -0
- package/dist/ui/use-async.js.map +1 -0
- package/dist/ui/use-pager.js +25 -0
- package/dist/ui/use-pager.js.map +1 -0
- package/dist/ui/use-project-files.js +18 -0
- package/dist/ui/use-project-files.js.map +1 -0
- package/dist/ui/use-workdir.js +9 -0
- package/dist/ui/use-workdir.js.map +1 -0
- package/package.json +34 -3
- package/README.md +0 -3
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useAtomValue } from 'jotai';
|
|
4
|
+
import { plural } from '@jinion/core/lib/format';
|
|
5
|
+
import { useApi } from '../../app/api.js';
|
|
6
|
+
import { editTurnsAtom } from '../../state/session.js';
|
|
7
|
+
import { useAsync } from '../../ui/use-async.js';
|
|
8
|
+
import { useWorkdir } from '../../ui/use-workdir.js';
|
|
9
|
+
import { totals } from './views.js';
|
|
10
|
+
export function useCurrentView() {
|
|
11
|
+
const api = useApi();
|
|
12
|
+
const cwd = useWorkdir();
|
|
13
|
+
const turns = useAtomValue(editTurnsAtom);
|
|
14
|
+
const edited = useMemo(() => new Set(turns.flatMap((turn) => turn.edits.map((change) => resolve(cwd, change.path)))), [turns, cwd]);
|
|
15
|
+
const read = useAsync(() => api.inSession('git/changes', {}), []);
|
|
16
|
+
if (read.state !== 'done')
|
|
17
|
+
return { label: 'Current', empty: 'Looking for changes…' };
|
|
18
|
+
const repos = read.value;
|
|
19
|
+
if (repos.length === 0)
|
|
20
|
+
return { label: 'Current', rows: [], empty: 'There is no git repository here or in the folders below.' };
|
|
21
|
+
const [only] = repos;
|
|
22
|
+
const grouped = repos.length > 1 || only.repo.path !== '';
|
|
23
|
+
const what = (repo) => (repo.since ? `${repo.branch} · what it adds to ${repo.since.against}` : repo.branch);
|
|
24
|
+
const rows = repos.flatMap((repo) => repo.changes.map((change) => ({
|
|
25
|
+
key: change.absolute,
|
|
26
|
+
group: grouped ? { label: repo.repo.label, aside: what(repo) } : undefined,
|
|
27
|
+
file: change.file,
|
|
28
|
+
kind: change.kind,
|
|
29
|
+
insertions: change.insertions,
|
|
30
|
+
deletions: change.deletions,
|
|
31
|
+
binary: change.binary,
|
|
32
|
+
agent: edited.has(change.absolute),
|
|
33
|
+
where: `${repo.repo.path ? `${repo.repo.path}/` : ''}${change.file}`,
|
|
34
|
+
patch: () => api.inSession('git/diff', { file: change.absolute }),
|
|
35
|
+
})));
|
|
36
|
+
// Repositories without changes have no rows, so they are named under the list.
|
|
37
|
+
const clean = rows.length > 0 && grouped ? repos.filter((repo) => repo.changes.length === 0) : [];
|
|
38
|
+
const repositories = plural(repos.length, 'repository', 'repositories');
|
|
39
|
+
return {
|
|
40
|
+
label: 'Current',
|
|
41
|
+
rows,
|
|
42
|
+
subtitle: [grouped ? repositories : what(only), ...totals(rows)].filter(Boolean).join(' · '),
|
|
43
|
+
empty: `No changes since the last commit in ${grouped ? repositories : 'this repository'}.`,
|
|
44
|
+
note: clean.length > 0 ? `No changes in ${clean.map((repo) => repo.repo.label).join(', ')}.` : undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=current-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"current-view.js","sourceRoot":"","sources":["../../../src/panels/diff/current-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { editTurnsAtom } from '../../state/session.js';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { useAtomValue } from 'jotai';
|
|
5
|
+
import { ChangeList } from './change-list.js';
|
|
6
|
+
import { useCurrentView } from './current-view.js';
|
|
7
|
+
import { FileDiff } from './file-diff.js';
|
|
8
|
+
import { turnView } from './views.js';
|
|
9
|
+
/** As in Claude Code, plus a view per turn with just its edits. */
|
|
10
|
+
export function DiffPanel({ turn, file }) {
|
|
11
|
+
const current = useCurrentView();
|
|
12
|
+
const turns = useAtomValue(editTurnsAtom);
|
|
13
|
+
// Kept by the turn's id, so a turn that ends while the panel is open doesn't move what is shown.
|
|
14
|
+
const [activeTurn, setActiveTurn] = useState(() => (turns.some((candidate) => candidate.id === turn) ? turn : undefined));
|
|
15
|
+
const views = [current, ...turns.map(turnView)];
|
|
16
|
+
const active = Math.max(0, views.findIndex((view) => view.turn === activeTurn));
|
|
17
|
+
const [open, setOpen] = useState(() => views[active]?.rows?.find((row) => row.file === file));
|
|
18
|
+
if (open)
|
|
19
|
+
return _jsx(FileDiff, { row: open, onBack: () => setOpen(undefined) });
|
|
20
|
+
return (_jsx(ChangeList, { views: views, active: active, onSwitch: (step) => setActiveTurn(views[Math.min(views.length - 1, Math.max(0, active + step))]?.turn), onOpen: setOpen }, active));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=diff-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-panel.js","sourceRoot":"","sources":["../../../src/panels/diff/diff-panel.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAkB,MAAM,YAAY,CAAC;AAOtD,mEAAmE;AACnE,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAkB;IACtD,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IAE1C,iGAAiG;IACjG,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAE1H,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC;IAChF,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAwB,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;IAErH,IAAI,IAAI;QAAE,OAAO,KAAC,QAAQ,IAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,GAAI,CAAC;IAE3E,OAAO,CACL,KAAC,UAAU,IAET,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EACtG,MAAM,EAAE,OAAO,IAJV,MAAM,CAKX,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Diff, extension, Panel, parsePatch, Text, useInput, useTheme } from '@jinion/tui';
|
|
3
|
+
import { PAGER_HINTS, usePager } from '../../ui/use-pager.js';
|
|
4
|
+
import { useAsync } from '../../ui/use-async.js';
|
|
5
|
+
export const CHROME_ROWS = 8;
|
|
6
|
+
export function FileDiff({ row, onBack }) {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
const read = useAsync(() => row.patch().catch(() => ''), [row]);
|
|
9
|
+
const patch = read.state === 'done' ? read.value : undefined;
|
|
10
|
+
const lines = patch ? parsePatch(patch).length : 0;
|
|
11
|
+
const pager = usePager(lines, { chrome: CHROME_ROWS });
|
|
12
|
+
useInput((_, key) => {
|
|
13
|
+
if (key.escape)
|
|
14
|
+
return onBack();
|
|
15
|
+
pager.scroll(key);
|
|
16
|
+
});
|
|
17
|
+
return (_jsx(Panel, { title: "Diff", subtitle: [row.where, pager.range].filter(Boolean).join(' · '), grow: true, hints: [...PAGER_HINTS, ['Esc', 'back']], children: patch === undefined ? (_jsx(Text, { color: theme.muted, children: "Reading the diff\u2026" })) : row.binary ? (_jsx(Text, { color: theme.muted, children: "A binary file; there are no lines to show." })) : lines === 0 ? (_jsx(Text, { color: theme.muted, children: "No line changes, e.g. only the file's mode changed." })) : (_jsx(Diff, { patch: patch, language: extension(row.file), window: { start: pager.top, rows: pager.view } })) }));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=file-diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-diff.js","sourceRoot":"","sources":["../../../src/panels/diff/file-diff.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAE7B,MAAM,UAAU,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAsC;IAC1E,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IAEzB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IAEvD,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAClB,IAAI,GAAG,CAAC,MAAM;YAAE,OAAO,MAAM,EAAE,CAAC;QAEhC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,KAAK,IAAC,KAAK,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,QAAC,KAAK,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,YAC9H,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CACrB,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,uCAA0B,CACnD,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CACf,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,2DAAmD,CAC5E,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAChB,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,CAAC,KAAK,oEAA4D,CACrF,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAI,CACtG,GACK,CACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { changedFiles } from '@jinion/core/conversation/edits';
|
|
2
|
+
import { plural } from '@jinion/core/lib/format';
|
|
3
|
+
import { firstFilledLine, truncate } from '@jinion/core/lib/text';
|
|
4
|
+
const TURN_LABEL = 24;
|
|
5
|
+
export function turnView(turn) {
|
|
6
|
+
const rows = changedFiles(turn.edits).map((file) => ({
|
|
7
|
+
key: file.path,
|
|
8
|
+
file: file.path,
|
|
9
|
+
kind: file.created ? 'added' : 'modified',
|
|
10
|
+
insertions: file.added,
|
|
11
|
+
deletions: file.removed,
|
|
12
|
+
where: file.path,
|
|
13
|
+
patch: async () => file.patch,
|
|
14
|
+
}));
|
|
15
|
+
const prompt = firstFilledLine(turn.prompt);
|
|
16
|
+
return {
|
|
17
|
+
label: truncate(prompt, TURN_LABEL),
|
|
18
|
+
turn: turn.id,
|
|
19
|
+
rows,
|
|
20
|
+
subtitle: [`“${truncate(prompt, 60)}”`, ...totals(rows)].join(' · '),
|
|
21
|
+
empty: '',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function totals(rows) {
|
|
25
|
+
const insertions = rows.reduce((total, row) => total + row.insertions, 0);
|
|
26
|
+
const deletions = rows.reduce((total, row) => total + row.deletions, 0);
|
|
27
|
+
return [plural(rows.length, 'file'), `+${insertions} -${deletions}`];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=views.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views.js","sourceRoot":"","sources":["../../../src/panels/diff/views.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAiB,MAAM,iCAAiC,CAAC;AAE9E,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,UAAU,GAAG,EAAE,CAAC;AAwBtB,MAAM,UAAU,QAAQ,CAAC,IAAc;IACrC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CACvC,CAAC,IAAI,EAAa,EAAE,CAAC,CAAC;QACpB,GAAG,EAAE,IAAI,CAAC,IAAI;QACd,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU;QACzC,UAAU,EAAE,IAAI,CAAC,KAAK;QACtB,SAAS,EAAE,IAAI,CAAC,OAAO;QACvB,KAAK,EAAE,IAAI,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK;KAC9B,CAAC,CACH,CAAC;IAEF,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5C,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;QACnC,IAAI,EAAE,IAAI,CAAC,EAAE;QACb,IAAI;QACJ,QAAQ,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACpE,KAAK,EAAE,EAAE;KACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAiB;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAExE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, ChoiceList, Panel, PromptInput, Text, useChoiceList, useInput, usePanel, useTheme } from '@jinion/tui';
|
|
4
|
+
import { errorMessage } from '@jinion/core/lib/errors';
|
|
5
|
+
import { useApi } from '../app/api.js';
|
|
6
|
+
const RATINGS = ['liked', 'disliked', 'note'];
|
|
7
|
+
const SHARING = ['share', 'keep'];
|
|
8
|
+
/** About the turn that begins with `entry`: a rating, a note, and whether its conversation goes along; about Jinion without one. */
|
|
9
|
+
export function FeedbackPanel({ entry }) {
|
|
10
|
+
const api = useApi();
|
|
11
|
+
const theme = useTheme();
|
|
12
|
+
const { close } = usePanel();
|
|
13
|
+
const [step, setStep] = useState(entry ? { kind: 'rate' } : { kind: 'note', rating: 'note' });
|
|
14
|
+
const [note, setNote] = useState('');
|
|
15
|
+
const send = (kind, share = false) => {
|
|
16
|
+
setStep({ kind: 'sending' });
|
|
17
|
+
api.inSession('session/feedback', { ...(entry && { entry }), kind, ...(note.trim() && { note: note.trim() }), share }).then(() => {
|
|
18
|
+
close();
|
|
19
|
+
api.act(api.inSession('session/notice', { text: 'Thanks for the feedback. We read every one.', tone: 'muted' }));
|
|
20
|
+
}, (error) => setStep({ kind: 'failed', problem: `Couldn’t send it: ${errorMessage(error)}` }));
|
|
21
|
+
};
|
|
22
|
+
const rate = useChoiceList({
|
|
23
|
+
keys: RATINGS,
|
|
24
|
+
mode: 'single',
|
|
25
|
+
isActive: step.kind === 'rate',
|
|
26
|
+
onCancel: close,
|
|
27
|
+
onSubmit: ([kind]) => (kind === 'liked' ? send('liked') : setStep({ kind: 'note', rating: kind })),
|
|
28
|
+
});
|
|
29
|
+
const share = useChoiceList({
|
|
30
|
+
keys: SHARING,
|
|
31
|
+
mode: 'single',
|
|
32
|
+
isActive: step.kind === 'share',
|
|
33
|
+
onCancel: close,
|
|
34
|
+
onSubmit: ([choice]) => step.kind === 'share' && send(step.rating, choice === 'share'),
|
|
35
|
+
});
|
|
36
|
+
useInput((_, key) => {
|
|
37
|
+
if (key.escape)
|
|
38
|
+
close();
|
|
39
|
+
}, { isActive: step.kind !== 'rate' && step.kind !== 'share' });
|
|
40
|
+
const submitNote = () => {
|
|
41
|
+
if (step.kind !== 'note')
|
|
42
|
+
return;
|
|
43
|
+
if (step.rating === 'note' && !note.trim())
|
|
44
|
+
return;
|
|
45
|
+
entry ? setStep({ kind: 'share', rating: step.rating }) : send('note');
|
|
46
|
+
};
|
|
47
|
+
return (_jsxs(Panel, { title: "Feedback", subtitle: entry ? 'The last answer' : 'Jinion', hints: hintsOf(step), children: [step.kind === 'rate' && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.muted, children: "How did the last answer go?" }), _jsx(ChoiceList, { list: rate, limit: RATINGS.length, choices: [
|
|
48
|
+
{ key: 'liked', label: _jsx(Text, { children: "It was good" }) },
|
|
49
|
+
{ key: 'disliked', label: _jsx(Text, { children: "It wasn\u2019t good" }), description: 'Tell us what went wrong, if you like' },
|
|
50
|
+
{ key: 'note', label: _jsx(Text, { children: "Just leave a note" }) },
|
|
51
|
+
] })] })), step.kind === 'note' && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.muted, children: step.rating === 'disliked' ? 'What went wrong? Enter to skip.' : entry ? 'What would you like to tell us?' : 'What would you like to tell us about Jinion?' }), _jsxs(Box, { children: [_jsx(Text, { color: theme.muted, children: '> ' }), _jsx(PromptInput, { value: note, onChange: setNote, onSubmit: submitNote, placeholder: "A sentence is plenty", paddingX: 0 })] })] })), step.kind === 'share' && (_jsxs(_Fragment, { children: [_jsx(Text, { color: theme.muted, children: "Send this conversation along? It helps us see what happened." }), _jsx(ChoiceList, { list: share, limit: SHARING.length, choices: [
|
|
52
|
+
{
|
|
53
|
+
key: 'share',
|
|
54
|
+
label: _jsx(Text, { children: "Send it" }),
|
|
55
|
+
description: 'Your message, the reply, and the names of the steps it took. Never file contents or command output.',
|
|
56
|
+
},
|
|
57
|
+
{ key: 'keep', label: _jsx(Text, { children: "Just my feedback" }) },
|
|
58
|
+
] })] })), step.kind === 'sending' && _jsx(Text, { color: theme.muted, children: "Sending\u2026" }), step.kind === 'failed' && _jsx(Text, { color: theme.error, children: step.problem })] }));
|
|
59
|
+
}
|
|
60
|
+
function hintsOf(step) {
|
|
61
|
+
if (step.kind === 'note')
|
|
62
|
+
return [['Enter', 'continue'], ['Esc', 'cancel']];
|
|
63
|
+
if (step.kind === 'rate' || step.kind === 'share')
|
|
64
|
+
return [['Enter', 'continue'], ['Up/Down', 'move'], ['Esc', 'cancel']];
|
|
65
|
+
return [['Esc', 'close']];
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.js","sourceRoot":"","sources":["../../src/panels/feedback.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { Box, ListRow, Panel, Prose, SelectList, Tabs, Text, useInput, useListNavigation, usePanel, useTabs, useTheme } from '@jinion/tui';
|
|
4
|
+
import { useAtomValue, useSetAtom } from 'jotai';
|
|
5
|
+
import { requiresArgument } from '@jinion/core/prompt/command-completion';
|
|
6
|
+
import { skillGroup, sortSkills } from '@jinion/core/prompt/skills';
|
|
7
|
+
import { useApi } from '../app/api.js';
|
|
8
|
+
import { SHORTCUTS } from '../app/shortcuts.js';
|
|
9
|
+
import { draftAtom } from '../prompt/draft.js';
|
|
10
|
+
import { skillsAtom } from '../state/session.js';
|
|
11
|
+
const SHORTCUT_COLUMNS = 3;
|
|
12
|
+
export function HelpPanel({ topic = '' }) {
|
|
13
|
+
const api = useApi();
|
|
14
|
+
const { close } = usePanel();
|
|
15
|
+
const skills = sortSkills(useAtomValue(skillsAtom));
|
|
16
|
+
const setDraft = useSetAtom(draftAtom);
|
|
17
|
+
const mention = (skill) => ({
|
|
18
|
+
label: `$${skill.name}`,
|
|
19
|
+
hint: skill.argumentHint,
|
|
20
|
+
description: skill.description,
|
|
21
|
+
aside: skillGroup(skill),
|
|
22
|
+
pick: () => setDraft(`$${skill.name} `),
|
|
23
|
+
});
|
|
24
|
+
const groups = [
|
|
25
|
+
{
|
|
26
|
+
label: 'Commands',
|
|
27
|
+
items: api.initialized.commands.map((command) => ({
|
|
28
|
+
label: `/${command.name}`,
|
|
29
|
+
hint: command.argumentHint,
|
|
30
|
+
description: command.description,
|
|
31
|
+
aside: command.aliases?.map((alias) => `/${alias}`).join(' '),
|
|
32
|
+
pick: () => requiresArgument(command) ? setDraft(`/${command.name} `) : api.act(api.inSession('session/submit', { text: `/${command.name}` })),
|
|
33
|
+
})),
|
|
34
|
+
},
|
|
35
|
+
{ label: 'Skills', items: skills.filter((skill) => skill.source === 'skill').map(mention) },
|
|
36
|
+
{ label: 'MCP prompts', items: skills.filter((skill) => skill.source === 'mcp').map(mention) },
|
|
37
|
+
].filter((group) => group.items.length > 0);
|
|
38
|
+
const tabs = ['General', ...groups.map((group) => group.label)];
|
|
39
|
+
const [tab] = useTabs(tabs.length, {
|
|
40
|
+
initial: Math.max(0, tabs.findIndex((label) => label.toLowerCase().startsWith(topic.trim().toLowerCase() || '\0'))),
|
|
41
|
+
});
|
|
42
|
+
const items = tab === 0 ? [] : groups[tab - 1].items;
|
|
43
|
+
const [selected, setSelected] = useListNavigation(items.length, { isActive: tab > 0 });
|
|
44
|
+
const hints = tab === 0
|
|
45
|
+
? [
|
|
46
|
+
['Left/Right', 'switch tab'],
|
|
47
|
+
['Esc', 'close'],
|
|
48
|
+
]
|
|
49
|
+
: [
|
|
50
|
+
['Enter', groups[tab - 1]?.label === 'Commands' ? 'run' : 'insert'],
|
|
51
|
+
['Up/Down', 'move'],
|
|
52
|
+
['Left/Right', 'switch tab'],
|
|
53
|
+
['Esc', 'close'],
|
|
54
|
+
];
|
|
55
|
+
useEffect(() => setSelected(0), [tab, setSelected]);
|
|
56
|
+
useInput((_, key) => {
|
|
57
|
+
if (key.escape)
|
|
58
|
+
return close();
|
|
59
|
+
const item = items[selected];
|
|
60
|
+
if (!key.return || !item)
|
|
61
|
+
return;
|
|
62
|
+
close();
|
|
63
|
+
item.pick();
|
|
64
|
+
});
|
|
65
|
+
return (_jsx(Panel, { title: "Help", header: _jsx(Tabs, { tabs: tabs, active: tab }), hints: hints, children: tab === 0 ? _jsx(General, {}) : _jsx(ItemList, { items: items, selected: selected }) }));
|
|
66
|
+
}
|
|
67
|
+
function General() {
|
|
68
|
+
const theme = useTheme();
|
|
69
|
+
const perColumn = Math.ceil(SHORTCUTS.length / SHORTCUT_COLUMNS);
|
|
70
|
+
const columns = Array.from({ length: SHORTCUT_COLUMNS }, (_, index) => SHORTCUTS.slice(index * perColumn, (index + 1) * perColumn));
|
|
71
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Prose, { children: "Jinion reads your codebase, edits files and runs commands, right from your terminal." }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Shortcuts" }), _jsx(Box, { children: columns.map((column, index) => (_jsx(Box, { flexDirection: "column", flexGrow: 1, flexBasis: 0, children: column.map(([keys, action]) => (_jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { color: theme.selection, children: keys }), _jsxs(Text, { color: theme.muted, children: [" ", action] })] }, keys))) }, index))) }), _jsx(Text, { children: " " }), _jsxs(Text, { color: theme.muted, children: ["Docs and updates: ", _jsx(Text, { color: theme.link, children: "https://jinion.co" })] })] }));
|
|
72
|
+
}
|
|
73
|
+
function ItemList({ items, selected }) {
|
|
74
|
+
const theme = useTheme();
|
|
75
|
+
const width = (item) => item.label.length + (item.hint ? item.hint.length + 1 : 0);
|
|
76
|
+
const labelWidth = Math.min(32, Math.max(...items.map(width)));
|
|
77
|
+
return (_jsx(SelectList, { items: items, selected: selected, limit: 10, renderItem: (item, state) => (_jsx(ListRow, { selected: state.selected, labelWidth: labelWidth, label: _jsxs(Text, { children: [item.label, item.hint && _jsxs(Text, { color: theme.muted, children: [" ", item.hint] })] }), description: item.description, aside: item.aside })) }));
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/panels/help.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Box, ChoiceList, choiceIndent, Panel, Text, useChoiceList, useInput, usePanel, useTheme } from '@jinion/tui';
|
|
4
|
+
import { errorMessage } from '@jinion/core/lib/errors';
|
|
5
|
+
import { plural } from '@jinion/core/lib/format';
|
|
6
|
+
import { truncate } from '@jinion/core/lib/text';
|
|
7
|
+
import { useAtomValue } from 'jotai';
|
|
8
|
+
import { useApi } from '../app/api.js';
|
|
9
|
+
import { agentAtom } from '../state/session.js';
|
|
10
|
+
const VISIBLE = 10;
|
|
11
|
+
const LABEL_WIDTH = 18;
|
|
12
|
+
const TOOLS_SHOWN = 8;
|
|
13
|
+
const POLL_MS = 1_500;
|
|
14
|
+
/** Changes apply from the next turn, when the agent connects again. */
|
|
15
|
+
export function McpPanel() {
|
|
16
|
+
const api = useApi();
|
|
17
|
+
const agent = useAtomValue(agentAtom);
|
|
18
|
+
const theme = useTheme();
|
|
19
|
+
const { close } = usePanel();
|
|
20
|
+
const [servers, setServers] = useState();
|
|
21
|
+
const [failure, setFailure] = useState();
|
|
22
|
+
const [signing, setSigning] = useState();
|
|
23
|
+
// Bumped after a sign-in, so the list comes in again.
|
|
24
|
+
const [loads, setLoads] = useState(0);
|
|
25
|
+
// Servers the user toggled keep their check when the list comes in again.
|
|
26
|
+
const touched = useRef(new Set());
|
|
27
|
+
const signingName = useRef(undefined);
|
|
28
|
+
const list = useChoiceList({
|
|
29
|
+
keys: (servers ?? []).map((server) => server.name),
|
|
30
|
+
mode: 'multiple',
|
|
31
|
+
isActive: !signing,
|
|
32
|
+
onCancel: close,
|
|
33
|
+
onToggle: (name) => void touched.current.add(name),
|
|
34
|
+
onSubmit: (checked) => {
|
|
35
|
+
close();
|
|
36
|
+
api.act(api.request('mcp/save', { enabled: checked }));
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
const choices = (servers ?? []).map((server) => {
|
|
40
|
+
const checked = list.isChecked(server.name);
|
|
41
|
+
return {
|
|
42
|
+
key: server.name,
|
|
43
|
+
label: (_jsxs(Text, { children: [truncate(server.label, LABEL_WIDTH - 2).padEnd(LABEL_WIDTH), checked === server.enabled ? describe(server, theme) : _jsxs(Text, { color: theme.muted, children: [checked ? 'turns on' : 'turns off', " on save"] })] })),
|
|
44
|
+
aside: server.source,
|
|
45
|
+
editor: _jsx(Details, { server: server, indent: choiceIndent(list) }),
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
const on = servers?.filter((server) => list.isChecked(server.name)).length ?? 0;
|
|
49
|
+
const focused = servers?.find((server) => server.name === list.focus);
|
|
50
|
+
const canSignIn = focused?.status === 'needs-auth' && focused.signIn !== 'elsewhere';
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const stopLink = api.client.on('mcp/sign-in-link', ({ name, url }) => setSigning((now) => (now?.name === name ? { ...now, link: url } : now)));
|
|
53
|
+
return () => {
|
|
54
|
+
stopLink();
|
|
55
|
+
if (signingName.current)
|
|
56
|
+
api.act(api.request('mcp/sign-in-cancel', { name: signingName.current }));
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
let timer;
|
|
61
|
+
let open = true;
|
|
62
|
+
const load = () => api.request('mcp/servers', {}).then((next) => {
|
|
63
|
+
if (!open)
|
|
64
|
+
return;
|
|
65
|
+
setServers(next);
|
|
66
|
+
for (const server of next)
|
|
67
|
+
if (!touched.current.has(server.name))
|
|
68
|
+
list.setChecked(server.name, server.enabled);
|
|
69
|
+
if (next.some((server) => server.status === 'pending'))
|
|
70
|
+
timer = setTimeout(load, POLL_MS);
|
|
71
|
+
}, (error) => open && setFailure(errorMessage(error)));
|
|
72
|
+
void load();
|
|
73
|
+
return () => {
|
|
74
|
+
open = false;
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
};
|
|
77
|
+
}, [loads]);
|
|
78
|
+
useInput((input) => {
|
|
79
|
+
if (input !== 'l' || !focused || !canSignIn)
|
|
80
|
+
return;
|
|
81
|
+
const { name, label } = focused;
|
|
82
|
+
signingName.current = name;
|
|
83
|
+
setSigning({ name, label });
|
|
84
|
+
void api
|
|
85
|
+
.request('mcp/sign-in', { name })
|
|
86
|
+
.catch(() => { })
|
|
87
|
+
.finally(() => {
|
|
88
|
+
if (signingName.current === name)
|
|
89
|
+
signingName.current = undefined;
|
|
90
|
+
setSigning(undefined);
|
|
91
|
+
setLoads((count) => count + 1);
|
|
92
|
+
});
|
|
93
|
+
}, { isActive: !signing });
|
|
94
|
+
useInput((_, key) => {
|
|
95
|
+
if (key.escape && signing)
|
|
96
|
+
api.act(api.request('mcp/sign-in-cancel', { name: signing.name }));
|
|
97
|
+
}, { isActive: signing !== undefined });
|
|
98
|
+
if (signing) {
|
|
99
|
+
return (_jsxs(Panel, { title: "MCP servers", subtitle: signing.label, hints: [['Esc', 'cancel']], children: [_jsxs(Text, { children: ["Signing in to ", _jsx(Text, { bold: true, children: signing.label }), ". Finish it in your browser."] }), signing.link && (_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: "If the browser didn't open: " }), _jsx(Text, { color: theme.code, children: signing.link })] }))] }));
|
|
100
|
+
}
|
|
101
|
+
return (_jsx(Panel, { title: "MCP servers", subtitle: servers ? `${on} of ${servers.length} on` : undefined, header: _jsx(Text, { color: theme.muted, children: "Checked servers connect from the next turn. Their tools load when the agent needs them, so a server costs little context until it's used." }), hints: [
|
|
102
|
+
['Space', 'on/off'],
|
|
103
|
+
['Enter', 'save'],
|
|
104
|
+
...(canSignIn ? [['l', 'sign in']] : []),
|
|
105
|
+
['Up/Down', 'move'],
|
|
106
|
+
['Esc', 'cancel'],
|
|
107
|
+
], children: failure ? (_jsxs(Text, { color: theme.error, children: ["Couldn't list the servers: ", failure] })) : servers ? (_jsx(ChoiceList, { list: list, choices: choices, limit: VISIBLE, empty: "No MCP servers yet. Add them with `claude mcp add`, in ~/.jinion/mcp.json or in the project's .mcp.json." })) : (_jsxs(Text, { color: theme.muted, children: ["Asking ", agent.name, " about its servers\u2026"] })) }));
|
|
108
|
+
}
|
|
109
|
+
function describe(server, theme) {
|
|
110
|
+
switch (server.status) {
|
|
111
|
+
case 'connected':
|
|
112
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: theme.success, children: "connected" }), _jsxs(Text, { color: theme.muted, children: [" \u00B7 ", plural(server.tools.length, 'tool')] })] }));
|
|
113
|
+
case 'pending':
|
|
114
|
+
return _jsx(Text, { color: theme.muted, children: "connecting\u2026" });
|
|
115
|
+
case 'needs-auth':
|
|
116
|
+
return _jsx(Text, { color: theme.warning, children: "not signed in" });
|
|
117
|
+
case 'failed':
|
|
118
|
+
return _jsx(Text, { color: theme.error, children: "failed to connect" });
|
|
119
|
+
case 'off':
|
|
120
|
+
return _jsx(Text, { color: theme.muted, children: server.source === 'project' ? 'off until you turn it on (from .mcp.json)' : 'off' });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function Details({ server, indent }) {
|
|
124
|
+
const theme = useTheme();
|
|
125
|
+
const tools = server.tools.slice(0, TOOLS_SHOWN).join(', ');
|
|
126
|
+
const more = server.tools.length - TOOLS_SHOWN;
|
|
127
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: indent, marginBottom: 1, children: [server.target && (_jsx(Text, { color: theme.muted, wrap: "truncate-end", children: server.target })), server.error && _jsx(Text, { color: theme.error, children: server.error }), server.status === 'needs-auth' && server.signIn !== 'elsewhere' && (_jsxs(Text, { color: theme.muted, children: ["Press l to sign in to ", server.label, " in the browser."] })), tools && (_jsxs(Text, { wrap: "truncate-end", children: [tools, more > 0 && _jsxs(Text, { color: theme.muted, children: [" \u2026 ", more, " more"] })] }))] }));
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/panels/mcp.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Box, ChoiceList, choiceIndent, Panel, Prose, Text, useChoiceList, useInput, usePanel, useTheme } from '@jinion/tui';
|
|
4
|
+
import { plural } from '@jinion/core/lib/format';
|
|
5
|
+
import { tildify } from '@jinion/core/lib/paths';
|
|
6
|
+
import { useApi } from '../app/api.js';
|
|
7
|
+
const PREVIEW_LINES = 12;
|
|
8
|
+
export function MemoryPanel() {
|
|
9
|
+
const api = useApi();
|
|
10
|
+
const theme = useTheme();
|
|
11
|
+
const { close } = usePanel();
|
|
12
|
+
const [notes, setNotes] = useState([]);
|
|
13
|
+
const [open, setOpen] = useState();
|
|
14
|
+
const [forgetting, setForgetting] = useState();
|
|
15
|
+
const refresh = () => api.request('memory/list', {}).then(setNotes, () => setNotes([]));
|
|
16
|
+
useEffect(() => void refresh(), []);
|
|
17
|
+
const keys = notes.map((memory) => `${memory.scope}/${memory.id}`);
|
|
18
|
+
const list = useChoiceList({
|
|
19
|
+
keys,
|
|
20
|
+
mode: 'single',
|
|
21
|
+
onCancel: close,
|
|
22
|
+
onSubmit: ([key]) => setOpen(open === key ? undefined : key),
|
|
23
|
+
});
|
|
24
|
+
const choices = notes.map((memory) => {
|
|
25
|
+
const key = `${memory.scope}/${memory.id}`;
|
|
26
|
+
const lines = memory.content.split('\n');
|
|
27
|
+
return {
|
|
28
|
+
key,
|
|
29
|
+
label: memory.title,
|
|
30
|
+
description: `${memory.scope} · ${memory.type} · ${memory.description}`,
|
|
31
|
+
aside: forgetting === key ? _jsx(Text, { color: theme.error, children: "press d again to forget" }) : memory.updated,
|
|
32
|
+
editor: open === key ? (_jsxs(Box, { flexDirection: "column", paddingLeft: choiceIndent(list), marginBottom: 1, children: [_jsx(Prose, { children: lines.slice(0, PREVIEW_LINES).join('\n') }), lines.length > PREVIEW_LINES && _jsxs(Text, { color: theme.muted, children: ["\u2026 ", lines.length - PREVIEW_LINES, " more lines"] }), _jsx(Text, { color: theme.muted, children: tildify(memory.path) })] })) : undefined,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
useInput((input) => {
|
|
36
|
+
if (input !== 'd' || !list.focus)
|
|
37
|
+
return setForgetting(undefined);
|
|
38
|
+
if (forgetting !== list.focus)
|
|
39
|
+
return setForgetting(list.focus);
|
|
40
|
+
const memory = notes.find((note) => `${note.scope}/${note.id}` === list.focus);
|
|
41
|
+
setForgetting(undefined);
|
|
42
|
+
if (!memory)
|
|
43
|
+
return;
|
|
44
|
+
const forgotten = api.request('memory/forget', { scope: memory.scope, id: memory.id });
|
|
45
|
+
api.act(forgotten);
|
|
46
|
+
void forgotten.finally(refresh);
|
|
47
|
+
});
|
|
48
|
+
return (_jsx(Panel, { title: "Memory", subtitle: plural(notes.length, 'note'), hints: [
|
|
49
|
+
['Enter', 'open'],
|
|
50
|
+
['d', 'forget'],
|
|
51
|
+
['Up/Down', 'move'],
|
|
52
|
+
['Esc', 'close'],
|
|
53
|
+
], children: _jsx(ChoiceList, { list: list, choices: choices, limit: 6, empty: "No notes yet. The agent saves them as it learns, /remember adds one, and /memory import brings in Claude Code's." }) }));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/panels/memory.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ChoiceList, Panel, Text, useChoiceList, usePanel, useTheme } from '@jinion/tui';
|
|
3
|
+
import { useAtomValue } from 'jotai';
|
|
4
|
+
import { MODES } from '@jinion/core/agent/modes';
|
|
5
|
+
import { useApi } from '../app/api.js';
|
|
6
|
+
import { agentAtom, modeAtom } from '../state/session.js';
|
|
7
|
+
import { modeColor } from '../ui/modes.js';
|
|
8
|
+
export function ModePicker() {
|
|
9
|
+
const api = useApi();
|
|
10
|
+
const theme = useTheme();
|
|
11
|
+
const { close } = usePanel();
|
|
12
|
+
const current = useAtomValue(modeAtom);
|
|
13
|
+
const { modes: available, name } = useAtomValue(agentAtom);
|
|
14
|
+
const list = useChoiceList({
|
|
15
|
+
keys: available,
|
|
16
|
+
mode: 'single',
|
|
17
|
+
initialFocus: current,
|
|
18
|
+
onCancel: close,
|
|
19
|
+
onSubmit: ([mode]) => {
|
|
20
|
+
close();
|
|
21
|
+
if (mode)
|
|
22
|
+
api.act(api.inSession('session/mode', { mode: mode }));
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
return (_jsx(Panel, { title: "Mode", subtitle: name, hints: [
|
|
26
|
+
['Enter', 'select'],
|
|
27
|
+
['Up/Down', 'move'],
|
|
28
|
+
['Esc', 'cancel'],
|
|
29
|
+
], children: _jsx(ChoiceList, { list: list, limit: available.length, choices: available.map((mode) => ({
|
|
30
|
+
key: mode,
|
|
31
|
+
label: _jsx(Text, { color: modeColor(theme, mode), children: MODES[mode].name }),
|
|
32
|
+
description: MODES[mode].description,
|
|
33
|
+
aside: mode === current ? 'current' : undefined,
|
|
34
|
+
})) }) }));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.js","sourceRoot":"","sources":["../../src/panels/mode.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAErC,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IAE3D,MAAM,IAAI,GAAG,aAAa,CAAC;QACzB,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,OAAO;QACrB,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE;YACnB,KAAK,EAAE,CAAC;YACR,IAAI,IAAI;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,IAAiB,EAAE,CAAC,CAAC,CAAC;QAChF,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,KAAK,IACJ,KAAK,EAAC,MAAM,EACZ,QAAQ,EAAE,IAAI,EACd,KAAK,EAAE;YACL,CAAC,OAAO,EAAE,QAAQ,CAAC;YACnB,CAAC,SAAS,EAAE,MAAM,CAAC;YACnB,CAAC,KAAK,EAAE,QAAQ,CAAC;SAClB,YAED,KAAC,UAAU,IACT,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,SAAS,CAAC,MAAM,EACvB,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAChC,GAAG,EAAE,IAAI;gBACT,KAAK,EAAE,KAAC,IAAI,IAAC,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,YAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,GAAQ;gBACrE,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW;gBACpC,KAAK,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;aAChD,CAAC,CAAC,GACH,GACI,CACT,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { usePanel } from '@jinion/tui';
|
|
3
|
+
import { ModelPanel } from '@jinion/tui/chat';
|
|
4
|
+
import { useAtomValue } from 'jotai';
|
|
5
|
+
import { useApi } from '../app/api.js';
|
|
6
|
+
import { agentAtom, agentsAtom, allModelsAtom, selectionAtom } from '../state/session.js';
|
|
7
|
+
/** Every backend's models, under its name; one of another backend moves the conversation there. */
|
|
8
|
+
export function ModelPicker() {
|
|
9
|
+
const api = useApi();
|
|
10
|
+
const { close } = usePanel();
|
|
11
|
+
const agents = useAtomValue(agentsAtom);
|
|
12
|
+
const models = useAtomValue(allModelsAtom);
|
|
13
|
+
const agent = useAtomValue(agentAtom);
|
|
14
|
+
const selection = useAtomValue(selectionAtom);
|
|
15
|
+
return (_jsx(ModelPanel, { groups: agents.map(({ name }) => ({ name, models: models[name] })), current: { ...selection, group: agent.name }, subtitle: agents.length > 1 ? undefined : agent.name, onSelect: (next, group) => {
|
|
16
|
+
close();
|
|
17
|
+
api.act(api.inSession('session/model', { selection: next, agent: group }));
|
|
18
|
+
}, onCancel: close }));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/panels/model.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE1F,mGAAmG;AACnG,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IAE9C,OAAO,CACL,KAAC,UAAU,IACT,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAClE,OAAO,EAAE,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAC5C,QAAQ,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EACpD,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACxB,KAAK,EAAE,CAAC;YACR,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC7E,CAAC,EACD,QAAQ,EAAE,KAAK,GACf,CACH,CAAC;AACJ,CAAC"}
|