praxis-agent 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +19 -4
  2. package/dist/application/session-service.d.ts +55 -0
  3. package/dist/application/session-service.d.ts.map +1 -1
  4. package/dist/application/session-service.js +939 -39
  5. package/dist/application/session-service.js.map +1 -1
  6. package/dist/cli/interactive.d.ts +72 -8
  7. package/dist/cli/interactive.d.ts.map +1 -1
  8. package/dist/cli/interactive.js +2809 -192
  9. package/dist/cli/interactive.js.map +1 -1
  10. package/dist/cli/protocol.d.ts +1 -0
  11. package/dist/cli/protocol.d.ts.map +1 -1
  12. package/dist/cli/protocol.js.map +1 -1
  13. package/dist/cli/tui/claude-style.d.ts +157 -3
  14. package/dist/cli/tui/claude-style.d.ts.map +1 -1
  15. package/dist/cli/tui/claude-style.js +403 -16
  16. package/dist/cli/tui/claude-style.js.map +1 -1
  17. package/dist/cli/tui/clipboard.d.ts +27 -0
  18. package/dist/cli/tui/clipboard.d.ts.map +1 -0
  19. package/dist/cli/tui/clipboard.js +165 -0
  20. package/dist/cli/tui/clipboard.js.map +1 -0
  21. package/dist/cli/tui/composer-editor.d.ts +19 -0
  22. package/dist/cli/tui/composer-editor.d.ts.map +1 -0
  23. package/dist/cli/tui/composer-editor.js +99 -0
  24. package/dist/cli/tui/composer-editor.js.map +1 -0
  25. package/dist/cli/tui/composer-images.d.ts +7 -0
  26. package/dist/cli/tui/composer-images.d.ts.map +1 -0
  27. package/dist/cli/tui/composer-images.js +48 -0
  28. package/dist/cli/tui/composer-images.js.map +1 -0
  29. package/dist/cli/tui/conversation-export.d.ts +6 -0
  30. package/dist/cli/tui/conversation-export.d.ts.map +1 -0
  31. package/dist/cli/tui/conversation-export.js +76 -0
  32. package/dist/cli/tui/conversation-export.js.map +1 -0
  33. package/dist/cli/tui/external-editor.d.ts +21 -0
  34. package/dist/cli/tui/external-editor.d.ts.map +1 -0
  35. package/dist/cli/tui/external-editor.js +144 -0
  36. package/dist/cli/tui/external-editor.js.map +1 -0
  37. package/dist/cli/tui/file-picker.d.ts +33 -0
  38. package/dist/cli/tui/file-picker.d.ts.map +1 -0
  39. package/dist/cli/tui/file-picker.js +117 -0
  40. package/dist/cli/tui/file-picker.js.map +1 -0
  41. package/dist/cli/tui/git-diff.d.ts +14 -0
  42. package/dist/cli/tui/git-diff.d.ts.map +1 -0
  43. package/dist/cli/tui/git-diff.js +55 -0
  44. package/dist/cli/tui/git-diff.js.map +1 -0
  45. package/dist/cli/tui/keybindings.d.ts +14 -0
  46. package/dist/cli/tui/keybindings.d.ts.map +1 -0
  47. package/dist/cli/tui/keybindings.js +430 -0
  48. package/dist/cli/tui/keybindings.js.map +1 -0
  49. package/dist/cli/tui/permission-settings.d.ts +18 -0
  50. package/dist/cli/tui/permission-settings.d.ts.map +1 -0
  51. package/dist/cli/tui/permission-settings.js +109 -0
  52. package/dist/cli/tui/permission-settings.js.map +1 -0
  53. package/dist/cli/tui/slash-commands.d.ts +11 -0
  54. package/dist/cli/tui/slash-commands.d.ts.map +1 -0
  55. package/dist/cli/tui/slash-commands.js +188 -0
  56. package/dist/cli/tui/slash-commands.js.map +1 -0
  57. package/dist/cli/tui/terminal-suspend.d.ts +5 -0
  58. package/dist/cli/tui/terminal-suspend.d.ts.map +1 -0
  59. package/dist/cli/tui/terminal-suspend.js +9 -0
  60. package/dist/cli/tui/terminal-suspend.js.map +1 -0
  61. package/dist/cli/tui/workspace-directories.d.ts +3 -0
  62. package/dist/cli/tui/workspace-directories.d.ts.map +1 -0
  63. package/dist/cli/tui/workspace-directories.js +55 -0
  64. package/dist/cli/tui/workspace-directories.js.map +1 -0
  65. package/dist/cli.d.ts +26 -2
  66. package/dist/cli.d.ts.map +1 -1
  67. package/dist/cli.js +48 -5
  68. package/dist/cli.js.map +1 -1
  69. package/dist/compatibility/claude/compaction.d.ts +8 -0
  70. package/dist/compatibility/claude/compaction.d.ts.map +1 -1
  71. package/dist/compatibility/claude/compaction.js +45 -8
  72. package/dist/compatibility/claude/compaction.js.map +1 -1
  73. package/dist/compatibility/claude/fork.d.ts.map +1 -1
  74. package/dist/compatibility/claude/fork.js +24 -6
  75. package/dist/compatibility/claude/fork.js.map +1 -1
  76. package/dist/compatibility/claude/history.d.ts.map +1 -1
  77. package/dist/compatibility/claude/history.js +41 -1
  78. package/dist/compatibility/claude/history.js.map +1 -1
  79. package/dist/compatibility/claude/projection.d.ts +29 -1
  80. package/dist/compatibility/claude/projection.d.ts.map +1 -1
  81. package/dist/compatibility/claude/projection.js +132 -2
  82. package/dist/compatibility/claude/projection.js.map +1 -1
  83. package/dist/compatibility/claude/schema.d.ts.map +1 -1
  84. package/dist/compatibility/claude/schema.js +45 -8
  85. package/dist/compatibility/claude/schema.js.map +1 -1
  86. package/dist/compatibility/claude/translation.d.ts +7 -0
  87. package/dist/compatibility/claude/translation.d.ts.map +1 -1
  88. package/dist/compatibility/claude/translation.js +20 -0
  89. package/dist/compatibility/claude/translation.js.map +1 -1
  90. package/dist/core/runtime.d.ts +19 -0
  91. package/dist/core/runtime.d.ts.map +1 -1
  92. package/dist/core/runtime.js +30 -11
  93. package/dist/core/runtime.js.map +1 -1
  94. package/dist/extensions/claude-extensions.d.ts +12 -0
  95. package/dist/extensions/claude-extensions.d.ts.map +1 -1
  96. package/dist/extensions/claude-extensions.js +49 -0
  97. package/dist/extensions/claude-extensions.js.map +1 -1
  98. package/dist/hooks/claude-hook-tools.js +2 -2
  99. package/dist/hooks/claude-hook-tools.js.map +1 -1
  100. package/dist/persistence/claude-transcript-store.d.ts.map +1 -1
  101. package/dist/persistence/claude-transcript-store.js +12 -5
  102. package/dist/persistence/claude-transcript-store.js.map +1 -1
  103. package/dist/tools/claude-interactive-tools.d.ts +1 -0
  104. package/dist/tools/claude-interactive-tools.d.ts.map +1 -1
  105. package/dist/tools/claude-interactive-tools.js +12 -0
  106. package/dist/tools/claude-interactive-tools.js.map +1 -1
  107. package/dist/tools/local-tools.d.ts.map +1 -1
  108. package/dist/tools/local-tools.js +11 -0
  109. package/dist/tools/local-tools.js.map +1 -1
  110. package/package.json +1 -1
@@ -0,0 +1,76 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { basename, resolve } from 'node:path';
3
+ function lines(text, prefix) {
4
+ const values = text.replace(/\n$/u, '').split('\n');
5
+ return values.map((line, index) => `${index === 0 ? prefix : ' '}${line}`);
6
+ }
7
+ export function conversationExportText(display, items) {
8
+ const output = [
9
+ `╭─── Praxis Code v${display.version} ───╮`,
10
+ '│ Welcome back!',
11
+ `│ ${display.model ?? 'provider default'} · ${display.effort ?? 'high'} effort`,
12
+ `│ ${display.cwd}`,
13
+ '│ Tips for getting started: Run /help for commands',
14
+ '│ Shared with Claude Code: sessions, memory, skills',
15
+ '╰───',
16
+ '',
17
+ ];
18
+ for (const item of items) {
19
+ if (item.kind === 'user')
20
+ output.push('', ...lines(item.text, '❯ '));
21
+ else if (item.kind === 'assistant')
22
+ output.push('', ...lines(item.text, '⏺ '));
23
+ else if (item.kind === 'thinking')
24
+ output.push('', ...lines(item.text, '✻ '));
25
+ else if (item.kind === 'compact')
26
+ output.push('', '✻ Conversation compacted', ...lines(item.summary, ' '));
27
+ else if (item.kind === 'tool') {
28
+ output.push('', `⏺ ${item.call.name}${item.detail ? `(${item.detail})` : ''}`);
29
+ }
30
+ else if (item.kind === 'tool-result') {
31
+ output.push(...lines(item.text, item.isError ? ' ⎿ Error: ' : ' ⎿ '));
32
+ }
33
+ else if (item.kind === 'shell') {
34
+ output.push('', `! ${item.command}`);
35
+ }
36
+ else if (item.kind === 'shell-result') {
37
+ const result = [item.stdout, item.stderr].filter(Boolean).join('\n');
38
+ output.push(...lines(result, item.isError ? ' ⎿ Error: ' : ' ⎿ '));
39
+ }
40
+ else if (item.kind === 'local-result') {
41
+ output.push(...lines(item.text, ' ⎿ '));
42
+ }
43
+ else if (item.kind === 'context') {
44
+ output.push('', `Context Usage: ${item.usedTokens}/${item.contextWindowTokens} tokens`);
45
+ }
46
+ else {
47
+ output.push(...lines(item.text, item.kind === 'warning' ? '⚠ ' : '· '));
48
+ }
49
+ }
50
+ return `${output
51
+ .join('\n')
52
+ .replace(/\n{3,}/gu, '\n\n')
53
+ .trimEnd()}\n`;
54
+ }
55
+ export function defaultConversationExportFilename(now = new Date()) {
56
+ const date = [
57
+ now.getFullYear(),
58
+ String(now.getMonth() + 1).padStart(2, '0'),
59
+ String(now.getDate()).padStart(2, '0'),
60
+ ].join('-');
61
+ const time = [now.getHours(), now.getMinutes(), now.getSeconds()]
62
+ .map((value) => String(value).padStart(2, '0'))
63
+ .join('');
64
+ return `${date}-${time}-praxis-conversation.txt`;
65
+ }
66
+ export function conversationExportPath(cwd, filename) {
67
+ const name = filename.trim();
68
+ if (!name || name === '.' || name === '..' || basename(name) !== name) {
69
+ throw new Error('Export filename must stay within the current directory');
70
+ }
71
+ return resolve(cwd, name);
72
+ }
73
+ export async function writeConversationExport(path, text) {
74
+ await writeFile(path, text, { encoding: 'utf8', flag: 'wx' });
75
+ }
76
+ //# sourceMappingURL=conversation-export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-export.js","sourceRoot":"","sources":["../../../src/cli/tui/conversation-export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface TuiEditorCommand {
2
+ command: string;
3
+ args: readonly string[];
4
+ displayName: string;
5
+ }
6
+ export interface TuiEditorResult {
7
+ content: string;
8
+ editorName: string;
9
+ }
10
+ export interface TuiEditorOptions {
11
+ cwd: string;
12
+ environment?: NodeJS.ProcessEnv;
13
+ signal?: AbortSignal;
14
+ tempRoot?: string;
15
+ }
16
+ export declare function resolveTuiEditor(environment?: NodeJS.ProcessEnv): TuiEditorCommand;
17
+ export declare function openTuiEditorFile(path: string, options: TuiEditorOptions): Promise<{
18
+ editorName: string;
19
+ }>;
20
+ export declare function editTuiPrompt(prompt: string, options: TuiEditorOptions): Promise<TuiEditorResult>;
21
+ //# sourceMappingURL=external-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-editor.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/external-editor.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAiED,wBAAgB,gBAAgB,CAC9B,WAAW,GAAE,MAAM,CAAC,UAAwB,GAC3C,gBAAgB,CAYlB;AAwCD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAIjC;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CAoB1B"}
@@ -0,0 +1,144 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { spawn } from 'node:child_process';
3
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import { basename, join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ function parseEditorCommand(value) {
7
+ const words = [];
8
+ let word = '';
9
+ let started = false;
10
+ let quote = null;
11
+ let escaped = false;
12
+ const finishWord = () => {
13
+ if (!started)
14
+ return;
15
+ words.push(word);
16
+ word = '';
17
+ started = false;
18
+ };
19
+ for (const character of value) {
20
+ if (escaped) {
21
+ word += character;
22
+ started = true;
23
+ escaped = false;
24
+ continue;
25
+ }
26
+ if (quote === 'single') {
27
+ if (character === "'")
28
+ quote = null;
29
+ else
30
+ word += character;
31
+ started = true;
32
+ continue;
33
+ }
34
+ if (quote === 'double') {
35
+ if (character === '"')
36
+ quote = null;
37
+ else if (character === '\\')
38
+ escaped = true;
39
+ else
40
+ word += character;
41
+ started = true;
42
+ continue;
43
+ }
44
+ if (character === '\\') {
45
+ escaped = true;
46
+ started = true;
47
+ }
48
+ else if (character === "'") {
49
+ quote = 'single';
50
+ started = true;
51
+ }
52
+ else if (character === '"') {
53
+ quote = 'double';
54
+ started = true;
55
+ }
56
+ else if (/\s/u.test(character)) {
57
+ finishWord();
58
+ }
59
+ else {
60
+ word += character;
61
+ started = true;
62
+ }
63
+ }
64
+ if (quote)
65
+ throw new Error('Editor command contains an unterminated quote');
66
+ if (escaped)
67
+ throw new Error('Editor command ends with an incomplete escape');
68
+ finishWord();
69
+ return words;
70
+ }
71
+ function editorDisplayName(command) {
72
+ const name = basename(command) || command;
73
+ const first = name.at(0);
74
+ return first ? first.toUpperCase() + name.slice(1) : 'Editor';
75
+ }
76
+ export function resolveTuiEditor(environment = process.env) {
77
+ const configured = [environment.VISUAL, environment.EDITOR].find((value) => value?.trim());
78
+ const words = parseEditorCommand(configured ?? 'vi');
79
+ const command = words[0];
80
+ if (!command)
81
+ throw new Error('Editor command is empty');
82
+ return {
83
+ command,
84
+ args: words.slice(1),
85
+ displayName: editorDisplayName(command),
86
+ };
87
+ }
88
+ async function runEditor(editor, promptPath, options) {
89
+ await new Promise((resolve, reject) => {
90
+ const child = spawn(editor.command, [...editor.args, promptPath], {
91
+ cwd: options.cwd,
92
+ stdio: 'inherit',
93
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
94
+ });
95
+ let settled = false;
96
+ child.once('error', (error) => {
97
+ if (settled)
98
+ return;
99
+ settled = true;
100
+ reject(error);
101
+ });
102
+ child.once('close', (code, signal) => {
103
+ if (settled)
104
+ return;
105
+ settled = true;
106
+ if (code === 0)
107
+ resolve();
108
+ else if (code !== null) {
109
+ reject(new Error(`${editor.displayName} quit unexpectedly (exit code ${code})`));
110
+ }
111
+ else {
112
+ reject(new Error(`${editor.displayName} quit unexpectedly${signal ? ` (signal ${signal})` : ''}`));
113
+ }
114
+ });
115
+ });
116
+ }
117
+ export async function openTuiEditorFile(path, options) {
118
+ const editor = resolveTuiEditor(options.environment);
119
+ await runEditor(editor, path, options);
120
+ return { editorName: editor.displayName };
121
+ }
122
+ export async function editTuiPrompt(prompt, options) {
123
+ const editor = resolveTuiEditor(options.environment);
124
+ const parent = options.tempRoot ?? tmpdir();
125
+ const directory = join(parent, `praxis-editor-${randomUUID()}`);
126
+ const promptPath = join(directory, `claude-prompt-${randomUUID()}.md`);
127
+ await mkdir(directory, { mode: 0o700, recursive: false });
128
+ try {
129
+ await writeFile(promptPath, prompt, {
130
+ encoding: 'utf8',
131
+ flag: 'wx',
132
+ mode: 0o600,
133
+ });
134
+ await runEditor(editor, promptPath, options);
135
+ return {
136
+ content: await readFile(promptPath, 'utf8'),
137
+ editorName: editor.displayName,
138
+ };
139
+ }
140
+ finally {
141
+ await rm(directory, { force: true, recursive: true });
142
+ }
143
+ }
144
+ //# sourceMappingURL=external-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-editor.js","sourceRoot":"","sources":["../../../src/cli/tui/external-editor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export interface TuiFileEntry {
2
+ path: string;
3
+ directory: boolean;
4
+ }
5
+ export interface TuiAgentEntry {
6
+ name: string;
7
+ description: string;
8
+ }
9
+ export type TuiMentionEntry = ({
10
+ kind: 'file';
11
+ } & TuiFileEntry) | ({
12
+ kind: 'agent';
13
+ } & TuiAgentEntry);
14
+ export declare function loadTuiFileEntries(cwd: string): Promise<readonly TuiFileEntry[]>;
15
+ export declare function filterTuiFileEntries(entries: readonly TuiFileEntry[], query: string): readonly TuiFileEntry[];
16
+ export declare function filterTuiMentionEntries(files: readonly TuiFileEntry[], agents: readonly TuiAgentEntry[], query: string): readonly TuiMentionEntry[];
17
+ export declare function fileReferenceAtCursor(input: string, cursor: number): {
18
+ start: number;
19
+ query: string;
20
+ } | null;
21
+ export declare function applyFileReference(input: string, cursor: number, reference: {
22
+ start: number;
23
+ }, path: string): {
24
+ text: string;
25
+ cursor: number;
26
+ };
27
+ export declare function applyMentionReference(input: string, cursor: number, reference: {
28
+ start: number;
29
+ }, entry: TuiMentionEntry): {
30
+ text: string;
31
+ cursor: number;
32
+ };
33
+ //# sourceMappingURL=file-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-picker.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/file-picker.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,MAAM,eAAe,GACzB,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAAC,GAAG,CAAC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,aAAa,CAAC,CAAA;AAEzE,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAyClC;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,KAAK,EAAE,MAAM,GACZ,SAAS,YAAY,EAAE,CAYzB;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,MAAM,EAAE,SAAS,aAAa,EAAE,EAChC,KAAK,EAAE,MAAM,GACZ,SAAS,eAAe,EAAE,CA0B5B;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUzC;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAC5B,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CASlC;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAC5B,KAAK,EAAE,eAAe,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAclC"}
@@ -0,0 +1,117 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ export async function loadTuiFileEntries(cwd) {
5
+ let stdout;
6
+ try {
7
+ const result = await execFileAsync('rg', ['--files', '--hidden', '--glob', '!.git/**'], {
8
+ cwd,
9
+ encoding: 'utf8',
10
+ maxBuffer: 4 * 1024 * 1024,
11
+ timeout: 5_000,
12
+ });
13
+ stdout = result.stdout;
14
+ }
15
+ catch (error) {
16
+ if (error &&
17
+ typeof error === 'object' &&
18
+ 'code' in error &&
19
+ error.code === 1) {
20
+ return [];
21
+ }
22
+ throw error;
23
+ }
24
+ const files = stdout
25
+ .split(/\r?\n/u)
26
+ .map((path) => path.replace(/^\.\//u, ''))
27
+ .filter(Boolean)
28
+ .slice(0, 5_000);
29
+ const directories = new Set();
30
+ for (const path of files) {
31
+ const parts = path.split('/');
32
+ for (let index = 1; index < parts.length; index += 1) {
33
+ directories.add(`${parts.slice(0, index).join('/')}/`);
34
+ }
35
+ }
36
+ return [
37
+ ...files.map((path) => ({ path, directory: false })),
38
+ ...[...directories].map((path) => ({ path, directory: true })),
39
+ ].sort((left, right) => left.path.localeCompare(right.path));
40
+ }
41
+ export function filterTuiFileEntries(entries, query) {
42
+ const normalized = query.toLowerCase();
43
+ return [...entries]
44
+ .filter((entry) => !normalized || entry.path.toLowerCase().includes(normalized))
45
+ .sort((left, right) => {
46
+ const leftPrefix = left.path.toLowerCase().startsWith(normalized);
47
+ const rightPrefix = right.path.toLowerCase().startsWith(normalized);
48
+ if (leftPrefix !== rightPrefix)
49
+ return leftPrefix ? -1 : 1;
50
+ return left.path.localeCompare(right.path);
51
+ });
52
+ }
53
+ export function filterTuiMentionEntries(files, agents, query) {
54
+ const normalized = query.toLowerCase();
55
+ const matchingAgents = [...agents]
56
+ .filter((agent) => !normalized ||
57
+ agent.name.toLowerCase().includes(normalized) ||
58
+ agent.description.toLowerCase().includes(normalized))
59
+ .sort((left, right) => {
60
+ const leftPrefix = left.name.toLowerCase().startsWith(normalized);
61
+ const rightPrefix = right.name.toLowerCase().startsWith(normalized);
62
+ if (leftPrefix !== rightPrefix)
63
+ return leftPrefix ? -1 : 1;
64
+ return left.name.localeCompare(right.name);
65
+ })
66
+ .map((agent) => ({ kind: 'agent', ...agent }));
67
+ const matchingFiles = filterTuiFileEntries(files, query).map((file) => ({
68
+ kind: 'file',
69
+ ...file,
70
+ }));
71
+ if (normalized)
72
+ return [...matchingFiles, ...matchingAgents];
73
+ return [
74
+ ...matchingFiles.filter((entry) => entry.directory),
75
+ ...matchingAgents,
76
+ ...matchingFiles.filter((entry) => !entry.directory),
77
+ ];
78
+ }
79
+ export function fileReferenceAtCursor(input, cursor) {
80
+ const characters = Array.from(input);
81
+ const boundedCursor = Math.max(0, Math.min(cursor, characters.length));
82
+ let start = boundedCursor;
83
+ while (start > 0 && !/\s/u.test(characters[start - 1] ?? ''))
84
+ start -= 1;
85
+ if (characters[start] !== '@')
86
+ return null;
87
+ return {
88
+ start,
89
+ query: characters.slice(start + 1, boundedCursor).join(''),
90
+ };
91
+ }
92
+ export function applyFileReference(input, cursor, reference, path) {
93
+ const characters = Array.from(input);
94
+ const replacement = Array.from(`@${path}`);
95
+ const text = [
96
+ ...characters.slice(0, reference.start),
97
+ ...replacement,
98
+ ...characters.slice(cursor),
99
+ ].join('');
100
+ return { text, cursor: reference.start + replacement.length };
101
+ }
102
+ export function applyMentionReference(input, cursor, reference, entry) {
103
+ if (entry.kind === 'file') {
104
+ return applyFileReference(input, cursor, reference, entry.path);
105
+ }
106
+ const characters = Array.from(input);
107
+ const replacement = Array.from(`@"${entry.name} (agent)"`);
108
+ return {
109
+ text: [
110
+ ...characters.slice(0, reference.start),
111
+ ...replacement,
112
+ ...characters.slice(cursor),
113
+ ].join(''),
114
+ cursor: reference.start + replacement.length,
115
+ };
116
+ }
117
+ //# sourceMappingURL=file-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-picker.js","sourceRoot":"","sources":["../../../src/cli/tui/file-picker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface TuiDiffFile {
2
+ path: string;
3
+ additions: number;
4
+ deletions: number;
5
+ patch: string;
6
+ }
7
+ export interface TuiDiffSnapshot {
8
+ files: readonly TuiDiffFile[];
9
+ additions: number;
10
+ deletions: number;
11
+ }
12
+ export declare function visiblePatchLines(patch: string): readonly string[];
13
+ export declare function loadGitDiff(cwd: string): Promise<TuiDiffSnapshot>;
14
+ //# sourceMappingURL=git-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-diff.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/git-diff.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,WAAW,EAAE,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAoBD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAYlE;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA+BvE"}
@@ -0,0 +1,55 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ function changedLines(patch) {
5
+ let additions = 0;
6
+ let deletions = 0;
7
+ for (const line of patch.split('\n')) {
8
+ if (line.startsWith('+') && !isNewFileHeader(line))
9
+ additions += 1;
10
+ if (line.startsWith('-') && !isOldFileHeader(line))
11
+ deletions += 1;
12
+ }
13
+ return { additions, deletions };
14
+ }
15
+ function isOldFileHeader(line) {
16
+ return /^--- (?:a\/|"a\/|\/dev\/null$)/u.test(line);
17
+ }
18
+ function isNewFileHeader(line) {
19
+ return /^\+\+\+ (?:b\/|"b\/|\/dev\/null$)/u.test(line);
20
+ }
21
+ export function visiblePatchLines(patch) {
22
+ return patch
23
+ .split('\n')
24
+ .filter((line) => line &&
25
+ !line.startsWith('diff --git ') &&
26
+ !line.startsWith('index ') &&
27
+ !isOldFileHeader(line) &&
28
+ !isNewFileHeader(line) &&
29
+ !line.startsWith('@@ '));
30
+ }
31
+ export async function loadGitDiff(cwd) {
32
+ const names = await execFileAsync('git', ['-C', cwd, 'diff', '--name-only', '-z', 'HEAD', '--'], { encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 });
33
+ const paths = names.stdout.split('\0').filter(Boolean);
34
+ const files = [];
35
+ for (const path of paths) {
36
+ const result = await execFileAsync('git', [
37
+ '-C',
38
+ cwd,
39
+ 'diff',
40
+ '--no-ext-diff',
41
+ '--no-color',
42
+ '--unified=3',
43
+ 'HEAD',
44
+ '--',
45
+ path,
46
+ ], { encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 });
47
+ files.push({ path, patch: result.stdout, ...changedLines(result.stdout) });
48
+ }
49
+ return {
50
+ files,
51
+ additions: files.reduce((total, file) => total + file.additions, 0),
52
+ deletions: files.reduce((total, file) => total + file.deletions, 0),
53
+ };
54
+ }
55
+ //# sourceMappingURL=git-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-diff.js","sourceRoot":"","sources":["../../../src/cli/tui/git-diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { Key } from 'ink';
2
+ export interface TuiKeybindingsFile {
3
+ path: string;
4
+ created: boolean;
5
+ }
6
+ export type TuiKeybindings = ReadonlyMap<string, ReadonlyMap<string, string>>;
7
+ export declare function claudeKeybindingsTemplate(): string;
8
+ export declare function defaultTuiKeybindings(): TuiKeybindings;
9
+ export declare function loadTuiKeybindings(configRoot: string): Promise<TuiKeybindings>;
10
+ export declare function resolveTuiKeybinding(bindings: TuiKeybindings, contexts: readonly string[], chord: string | null): string | undefined;
11
+ export declare function hasTuiKeybindingPrefix(bindings: TuiKeybindings, contexts: readonly string[], chord: string): boolean;
12
+ export declare function tuiKeyChord(value: string, key: Key): string | null;
13
+ export declare function ensureTuiKeybindingsFile(configRoot: string): Promise<TuiKeybindingsFile>;
14
+ //# sourceMappingURL=keybindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/keybindings.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAE9B,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAmR7E,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AA4CD,wBAAgB,qBAAqB,IAAI,cAAc,CAEtD;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,CAAC,CA+BzB;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,GAAG,SAAS,CAOpB;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,KAAK,EAAE,MAAM,GACZ,OAAO,CAOT;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CA+ClE;AAED,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,kBAAkB,CAAC,CAgB7B"}