@undefineds.co/linx 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +91 -0
  2. package/dist/index.js +578 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/lib/account-api.js +100 -0
  5. package/dist/lib/account-api.js.map +1 -0
  6. package/dist/lib/account-session.js +30 -0
  7. package/dist/lib/account-session.js.map +1 -0
  8. package/dist/lib/ai-command.js +411 -0
  9. package/dist/lib/ai-command.js.map +1 -0
  10. package/dist/lib/chat-api.js +122 -0
  11. package/dist/lib/chat-api.js.map +1 -0
  12. package/dist/lib/codex-plugin/bridge.js +109 -0
  13. package/dist/lib/codex-plugin/bridge.js.map +1 -0
  14. package/dist/lib/codex-plugin/codex-native-proxy.js +358 -0
  15. package/dist/lib/codex-plugin/codex-native-proxy.js.map +1 -0
  16. package/dist/lib/codex-plugin/index.js +4 -0
  17. package/dist/lib/codex-plugin/index.js.map +1 -0
  18. package/dist/lib/codex-plugin/runner.js +38 -0
  19. package/dist/lib/codex-plugin/runner.js.map +1 -0
  20. package/dist/lib/credentials-store.js +74 -0
  21. package/dist/lib/credentials-store.js.map +1 -0
  22. package/dist/lib/default-model.js +8 -0
  23. package/dist/lib/default-model.js.map +1 -0
  24. package/dist/lib/login-command.js +51 -0
  25. package/dist/lib/login-command.js.map +1 -0
  26. package/dist/lib/models.js +6 -0
  27. package/dist/lib/models.js.map +1 -0
  28. package/dist/lib/oidc-auth.js +451 -0
  29. package/dist/lib/oidc-auth.js.map +1 -0
  30. package/dist/lib/oidc-session-storage.js +37 -0
  31. package/dist/lib/oidc-session-storage.js.map +1 -0
  32. package/dist/lib/pi-adapter/auth.js +38 -0
  33. package/dist/lib/pi-adapter/auth.js.map +1 -0
  34. package/dist/lib/pi-adapter/branding.js +239 -0
  35. package/dist/lib/pi-adapter/branding.js.map +1 -0
  36. package/dist/lib/pi-adapter/index.js +4 -0
  37. package/dist/lib/pi-adapter/index.js.map +1 -0
  38. package/dist/lib/pi-adapter/interactive.js +63 -0
  39. package/dist/lib/pi-adapter/interactive.js.map +1 -0
  40. package/dist/lib/pi-adapter/runtime.js +271 -0
  41. package/dist/lib/pi-adapter/runtime.js.map +1 -0
  42. package/dist/lib/pi-adapter/stream.js +314 -0
  43. package/dist/lib/pi-adapter/stream.js.map +1 -0
  44. package/dist/lib/pi-adapter/theme.js +84 -0
  45. package/dist/lib/pi-adapter/theme.js.map +1 -0
  46. package/dist/lib/pod-chat-store.js +200 -0
  47. package/dist/lib/pod-chat-store.js.map +1 -0
  48. package/dist/lib/profile-identity.js +116 -0
  49. package/dist/lib/profile-identity.js.map +1 -0
  50. package/dist/lib/prompt.js +82 -0
  51. package/dist/lib/prompt.js.map +1 -0
  52. package/dist/lib/runtime-target.js +12 -0
  53. package/dist/lib/runtime-target.js.map +1 -0
  54. package/dist/lib/solid-auth.js +55 -0
  55. package/dist/lib/solid-auth.js.map +1 -0
  56. package/dist/lib/thread-utils.js +12 -0
  57. package/dist/lib/thread-utils.js.map +1 -0
  58. package/dist/lib/watch/archive.js +110 -0
  59. package/dist/lib/watch/archive.js.map +1 -0
  60. package/dist/lib/watch/auth.js +56 -0
  61. package/dist/lib/watch/auth.js.map +1 -0
  62. package/dist/lib/watch/codex-composer.js +219 -0
  63. package/dist/lib/watch/codex-composer.js.map +1 -0
  64. package/dist/lib/watch/codex-footer.js +88 -0
  65. package/dist/lib/watch/codex-footer.js.map +1 -0
  66. package/dist/lib/watch/codex-overlay.js +154 -0
  67. package/dist/lib/watch/codex-overlay.js.map +1 -0
  68. package/dist/lib/watch/codex-request-form.js +341 -0
  69. package/dist/lib/watch/codex-request-form.js.map +1 -0
  70. package/dist/lib/watch/codex-request-input.js +187 -0
  71. package/dist/lib/watch/codex-request-input.js.map +1 -0
  72. package/dist/lib/watch/display.js +1514 -0
  73. package/dist/lib/watch/display.js.map +1 -0
  74. package/dist/lib/watch/format.js +161 -0
  75. package/dist/lib/watch/format.js.map +1 -0
  76. package/dist/lib/watch/hooks/claude.js +12 -0
  77. package/dist/lib/watch/hooks/claude.js.map +1 -0
  78. package/dist/lib/watch/hooks/codebuddy.js +18 -0
  79. package/dist/lib/watch/hooks/codebuddy.js.map +1 -0
  80. package/dist/lib/watch/hooks/codex.js +13 -0
  81. package/dist/lib/watch/hooks/codex.js.map +1 -0
  82. package/dist/lib/watch/hooks/index.js +24 -0
  83. package/dist/lib/watch/hooks/index.js.map +1 -0
  84. package/dist/lib/watch/hooks/shared.js +19 -0
  85. package/dist/lib/watch/hooks/shared.js.map +1 -0
  86. package/dist/lib/watch/index.js +10 -0
  87. package/dist/lib/watch/index.js.map +1 -0
  88. package/dist/lib/watch/pod-ai.js +168 -0
  89. package/dist/lib/watch/pod-ai.js.map +1 -0
  90. package/dist/lib/watch/pod-approval.js +578 -0
  91. package/dist/lib/watch/pod-approval.js.map +1 -0
  92. package/dist/lib/watch/pod-persistence.js +226 -0
  93. package/dist/lib/watch/pod-persistence.js.map +1 -0
  94. package/dist/lib/watch/runner.js +1124 -0
  95. package/dist/lib/watch/runner.js.map +1 -0
  96. package/dist/lib/watch/types.js +2 -0
  97. package/dist/lib/watch/types.js.map +1 -0
  98. package/dist/watch-cli.js +142 -0
  99. package/dist/watch-cli.js.map +1 -0
  100. package/package.json +38 -0
@@ -0,0 +1,110 @@
1
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { createWatchSessionId, WATCH_EVENTS_FILE_NAME, WATCH_HOME_DIRNAME, WATCH_SESSIONS_DIRNAME, WATCH_SESSION_FILE_NAME, } from '@undefineds.co/models/watch';
5
+ function getWatchHome() {
6
+ const watchOverride = process.env.LINX_WATCH_HOME?.trim();
7
+ if (watchOverride) {
8
+ return watchOverride;
9
+ }
10
+ return join(homedir(), '.linx', WATCH_HOME_DIRNAME);
11
+ }
12
+ function ensureDir(path) {
13
+ if (!existsSync(path)) {
14
+ mkdirSync(path, { recursive: true });
15
+ }
16
+ }
17
+ function sessionsDir() {
18
+ const dir = join(getWatchHome(), WATCH_SESSIONS_DIRNAME);
19
+ ensureDir(dir);
20
+ return dir;
21
+ }
22
+ function sessionPath(id) {
23
+ return join(sessionsDir(), id);
24
+ }
25
+ function sessionJsonPath(id) {
26
+ return join(sessionPath(id), WATCH_SESSION_FILE_NAME);
27
+ }
28
+ function readSessionJson(id) {
29
+ try {
30
+ const raw = readFileSync(sessionJsonPath(id), 'utf-8');
31
+ return JSON.parse(raw);
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ export function createWatchSession(options, plan) {
38
+ const id = createWatchSessionId();
39
+ const archiveDir = sessionPath(id);
40
+ const eventsFile = join(archiveDir, WATCH_EVENTS_FILE_NAME);
41
+ ensureDir(archiveDir);
42
+ const record = {
43
+ id,
44
+ backend: options.backend,
45
+ runtime: options.runtime ?? 'local',
46
+ transport: options.transport ?? 'acp',
47
+ mode: options.mode,
48
+ cwd: options.cwd,
49
+ model: options.model,
50
+ prompt: options.prompt,
51
+ passthroughArgs: [...options.passthroughArgs],
52
+ credentialSource: options.credentialSource ?? 'auto',
53
+ resolvedCredentialSource: options.resolvedCredentialSource,
54
+ approvalSource: options.approvalSource ?? 'hybrid',
55
+ command: plan.command,
56
+ args: [...plan.args],
57
+ status: 'running',
58
+ startedAt: new Date().toISOString(),
59
+ archiveDir,
60
+ eventsFile,
61
+ };
62
+ writeWatchSession(record);
63
+ return record;
64
+ }
65
+ export function writeWatchSession(record) {
66
+ ensureDir(record.archiveDir);
67
+ writeFileSync(join(record.archiveDir, WATCH_SESSION_FILE_NAME), `${JSON.stringify(record, null, 2)}\n`);
68
+ }
69
+ export function appendWatchEvent(record, entry) {
70
+ appendFileSync(record.eventsFile, `${JSON.stringify(entry)}\n`);
71
+ }
72
+ export function finishWatchSession(record, updates) {
73
+ const next = {
74
+ ...record,
75
+ status: updates.status,
76
+ exitCode: updates.exitCode ?? record.exitCode ?? null,
77
+ signal: updates.signal ?? record.signal ?? null,
78
+ error: updates.error,
79
+ endedAt: new Date().toISOString(),
80
+ };
81
+ writeWatchSession(next);
82
+ return next;
83
+ }
84
+ export function listWatchSessions() {
85
+ const dir = sessionsDir();
86
+ return readdirSync(dir)
87
+ .map((name) => readSessionJson(name))
88
+ .filter((item) => item !== null)
89
+ .sort((left, right) => right.startedAt.localeCompare(left.startedAt));
90
+ }
91
+ export function loadWatchSession(id) {
92
+ return readSessionJson(id);
93
+ }
94
+ export function loadWatchEvents(id) {
95
+ const record = loadWatchSession(id);
96
+ if (!record) {
97
+ return [];
98
+ }
99
+ try {
100
+ return readFileSync(record.eventsFile, 'utf-8')
101
+ .split('\n')
102
+ .map((line) => line.trim())
103
+ .filter(Boolean)
104
+ .map((line) => JSON.parse(line));
105
+ }
106
+ catch {
107
+ return [];
108
+ }
109
+ }
110
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../../src/lib/watch/archive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { detectWatchAuthFailure as detectSharedWatchAuthFailure, parseWatchClaudeAuthStatus, } from '@undefineds.co/models/watch';
3
+ async function runCommandCapture(command, args) {
4
+ return new Promise((resolve) => {
5
+ const child = spawn(command, args, {
6
+ stdio: ['ignore', 'pipe', 'pipe'],
7
+ env: process.env,
8
+ });
9
+ let stdout = '';
10
+ let stderr = '';
11
+ let settled = false;
12
+ const finish = (result) => {
13
+ if (settled) {
14
+ return;
15
+ }
16
+ settled = true;
17
+ clearTimeout(timer);
18
+ resolve(result);
19
+ };
20
+ child.stdout.setEncoding('utf-8');
21
+ child.stderr.setEncoding('utf-8');
22
+ child.stdout.on('data', (chunk) => {
23
+ stdout += chunk;
24
+ });
25
+ child.stderr.on('data', (chunk) => {
26
+ stderr += chunk;
27
+ });
28
+ child.on('error', (error) => {
29
+ finish({ stdout, stderr, code: null, error });
30
+ });
31
+ child.on('exit', (code) => {
32
+ finish({ stdout, stderr, code });
33
+ });
34
+ const timer = setTimeout(() => {
35
+ child.kill('SIGTERM');
36
+ finish({ stdout, stderr, code: null, error: new Error(`Timed out running ${command}`) });
37
+ }, 4000);
38
+ });
39
+ }
40
+ export async function preflightWatchAuth(backend) {
41
+ if (backend !== 'claude') {
42
+ return { state: 'unknown' };
43
+ }
44
+ const result = await runCommandCapture('claude', ['auth', 'status', '--json']);
45
+ if (result.error) {
46
+ return { state: 'unknown' };
47
+ }
48
+ return parseWatchClaudeAuthStatus(result.stdout);
49
+ }
50
+ export function detectWatchAuthFailure(backend, line) {
51
+ return detectSharedWatchAuthFailure(backend, line);
52
+ }
53
+ export const __internal = {
54
+ parseClaudeAuthStatus: parseWatchClaudeAuthStatus,
55
+ };
56
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/lib/watch/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,219 @@
1
+ // Directly inspired by codex-rs/tui/src/bottom_pane/chat_composer.rs.
2
+ // This keeps watch input state in a dedicated module so the TUI can grow
3
+ // toward Codex behavior without burying editing logic inside display.ts.
4
+ const DEFAULT_PLACEHOLDER = 'Ask LinX to do anything';
5
+ const ANSWER_PLACEHOLDER = 'Type your answer';
6
+ const MAX_HISTORY_ENTRIES = 100;
7
+ const DEFAULT_PROMPT_PREFIX = '› ';
8
+ function chunkText(text, firstWidth, continuationWidth) {
9
+ const safeFirstWidth = Math.max(1, firstWidth);
10
+ const safeContinuationWidth = Math.max(1, continuationWidth);
11
+ const logicalLines = text.split('\n');
12
+ const chunks = [];
13
+ logicalLines.forEach((logicalLine, logicalIndex) => {
14
+ const width = logicalIndex === 0 ? safeFirstWidth : safeContinuationWidth;
15
+ const fallback = logicalLine.length === 0 ? [''] : [];
16
+ if (logicalLine.length === 0) {
17
+ chunks.push(...fallback);
18
+ return;
19
+ }
20
+ let remaining = logicalLine;
21
+ while (remaining.length > width) {
22
+ chunks.push(remaining.slice(0, width));
23
+ remaining = remaining.slice(width);
24
+ }
25
+ chunks.push(remaining);
26
+ });
27
+ return chunks.length > 0 ? chunks : [''];
28
+ }
29
+ function locateCursor(value, cursor, firstWidth, continuationWidth) {
30
+ const safeCursor = Math.max(0, Math.min(cursor, value.length));
31
+ const safeFirstWidth = Math.max(1, firstWidth);
32
+ const safeContinuationWidth = Math.max(1, continuationWidth);
33
+ const logicalLines = value.split('\n');
34
+ let remaining = safeCursor;
35
+ let row = 0;
36
+ for (let lineIndex = 0; lineIndex < logicalLines.length; lineIndex += 1) {
37
+ const logicalLine = logicalLines[lineIndex] ?? '';
38
+ const width = lineIndex === 0 ? safeFirstWidth : safeContinuationWidth;
39
+ const segments = logicalLine.length === 0 ? [''] : chunkText(logicalLine, width, width);
40
+ for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex += 1) {
41
+ const segment = segments[segmentIndex] ?? '';
42
+ if (remaining <= segment.length) {
43
+ return { row, columnInText: remaining };
44
+ }
45
+ remaining -= segment.length;
46
+ row += 1;
47
+ }
48
+ if (lineIndex < logicalLines.length - 1) {
49
+ if (remaining === 0) {
50
+ return { row, columnInText: 0 };
51
+ }
52
+ remaining -= 1;
53
+ if (remaining < 0) {
54
+ return { row, columnInText: 0 };
55
+ }
56
+ }
57
+ }
58
+ const lastLine = chunkText(value, safeFirstWidth, safeContinuationWidth).at(-1) ?? '';
59
+ return {
60
+ row: Math.max(0, chunkText(value, safeFirstWidth, safeContinuationWidth).length - 1),
61
+ columnInText: lastLine.length,
62
+ };
63
+ }
64
+ export function placeholderForPrompt(prompt) {
65
+ const normalized = prompt.trim().toLowerCase();
66
+ if (normalized.startsWith('answer')) {
67
+ return ANSWER_PLACEHOLDER;
68
+ }
69
+ return DEFAULT_PLACEHOLDER;
70
+ }
71
+ export class CodexComposer {
72
+ value = '';
73
+ cursor = 0;
74
+ history = [];
75
+ historyIndex = null;
76
+ draftBeforeHistory = '';
77
+ placeholder = DEFAULT_PLACEHOLDER;
78
+ promptPrefix = DEFAULT_PROMPT_PREFIX;
79
+ beginPrompt(prompt) {
80
+ this.value = '';
81
+ this.cursor = 0;
82
+ this.historyIndex = null;
83
+ this.draftBeforeHistory = '';
84
+ this.placeholder = placeholderForPrompt(prompt);
85
+ this.promptPrefix = DEFAULT_PROMPT_PREFIX;
86
+ }
87
+ text() {
88
+ return this.value;
89
+ }
90
+ cursorIndex() {
91
+ return this.cursor;
92
+ }
93
+ hasDraft() {
94
+ return this.value.trim().length > 0;
95
+ }
96
+ isBrowsingHistory() {
97
+ return this.historyIndex !== null;
98
+ }
99
+ setText(value, cursor = value.length) {
100
+ this.value = value;
101
+ this.cursor = Math.max(0, Math.min(cursor, value.length));
102
+ }
103
+ recordSubmission(value) {
104
+ const safeValue = value.trim();
105
+ if (!safeValue) {
106
+ this.historyIndex = null;
107
+ this.draftBeforeHistory = '';
108
+ return;
109
+ }
110
+ if (this.history.at(-1) !== safeValue) {
111
+ this.history.push(safeValue);
112
+ if (this.history.length > MAX_HISTORY_ENTRIES) {
113
+ this.history.splice(0, this.history.length - MAX_HISTORY_ENTRIES);
114
+ }
115
+ }
116
+ this.historyIndex = null;
117
+ this.draftBeforeHistory = '';
118
+ }
119
+ insert(text) {
120
+ if (!text) {
121
+ return;
122
+ }
123
+ this.value = `${this.value.slice(0, this.cursor)}${text}${this.value.slice(this.cursor)}`;
124
+ this.cursor += text.length;
125
+ this.historyIndex = null;
126
+ }
127
+ backspace() {
128
+ if (this.cursor === 0) {
129
+ return;
130
+ }
131
+ this.value = `${this.value.slice(0, this.cursor - 1)}${this.value.slice(this.cursor)}`;
132
+ this.cursor -= 1;
133
+ this.historyIndex = null;
134
+ }
135
+ deleteForward() {
136
+ if (this.cursor >= this.value.length) {
137
+ return;
138
+ }
139
+ this.value = `${this.value.slice(0, this.cursor)}${this.value.slice(this.cursor + 1)}`;
140
+ this.historyIndex = null;
141
+ }
142
+ moveLeft() {
143
+ this.cursor = Math.max(0, this.cursor - 1);
144
+ }
145
+ moveRight() {
146
+ this.cursor = Math.min(this.value.length, this.cursor + 1);
147
+ }
148
+ moveToStart() {
149
+ this.cursor = 0;
150
+ }
151
+ moveToEnd() {
152
+ this.cursor = this.value.length;
153
+ }
154
+ deleteToStart() {
155
+ if (this.cursor === 0) {
156
+ return;
157
+ }
158
+ this.value = this.value.slice(this.cursor);
159
+ this.cursor = 0;
160
+ this.historyIndex = null;
161
+ }
162
+ deleteToEnd() {
163
+ if (this.cursor >= this.value.length) {
164
+ return;
165
+ }
166
+ this.value = this.value.slice(0, this.cursor);
167
+ this.historyIndex = null;
168
+ }
169
+ navigateHistory(direction) {
170
+ if (this.history.length === 0) {
171
+ return false;
172
+ }
173
+ if (direction === 'up') {
174
+ if (this.historyIndex === null) {
175
+ this.draftBeforeHistory = this.value;
176
+ this.historyIndex = this.history.length - 1;
177
+ }
178
+ else if (this.historyIndex > 0) {
179
+ this.historyIndex -= 1;
180
+ }
181
+ }
182
+ else if (this.historyIndex === null) {
183
+ return false;
184
+ }
185
+ else if (this.historyIndex < this.history.length - 1) {
186
+ this.historyIndex += 1;
187
+ }
188
+ else {
189
+ this.historyIndex = null;
190
+ this.setText(this.draftBeforeHistory);
191
+ return true;
192
+ }
193
+ const nextValue = this.historyIndex === null
194
+ ? this.draftBeforeHistory
195
+ : (this.history[this.historyIndex] ?? '');
196
+ this.setText(nextValue);
197
+ return true;
198
+ }
199
+ render(width) {
200
+ const safeWidth = Math.max(4, width);
201
+ const contentWidth = Math.max(1, safeWidth - this.promptPrefix.length);
202
+ const visibleText = this.value.length > 0 ? this.value : this.placeholder;
203
+ const chunks = chunkText(visibleText, contentWidth, contentWidth);
204
+ const lines = chunks.map((chunk, index) => ({
205
+ prefix: index === 0 ? this.promptPrefix : ' '.repeat(this.promptPrefix.length),
206
+ text: chunk,
207
+ isPlaceholder: this.value.length === 0,
208
+ }));
209
+ const cursor = this.value.length === 0
210
+ ? { row: 0, columnInText: 0 }
211
+ : locateCursor(this.value, this.cursor, contentWidth, contentWidth);
212
+ return {
213
+ lines,
214
+ cursorRow: cursor.row,
215
+ cursorCol: this.promptPrefix.length + cursor.columnInText + 1,
216
+ };
217
+ }
218
+ }
219
+ //# sourceMappingURL=codex-composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-composer.js","sourceRoot":"","sources":["../../../src/lib/watch/codex-composer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ // Directly adapted from codex-rs/tui/src/bottom_pane/footer.rs.
2
+ // This keeps the single-line footer layout rules close to Codex while
3
+ // letting LinX provide its own left/right footer text.
4
+ export const FOOTER_INDENT_COLS = 2;
5
+ const FOOTER_CONTEXT_GAP_COLS = 1;
6
+ function safeSlice(text, width) {
7
+ if (width <= 0) {
8
+ return '';
9
+ }
10
+ if (text.length <= width) {
11
+ return text;
12
+ }
13
+ if (width <= 3) {
14
+ return text.slice(0, width);
15
+ }
16
+ return `${text.slice(0, width - 3)}...`;
17
+ }
18
+ export function leftFits(width, leftWidth) {
19
+ const maxWidth = Math.max(0, width - FOOTER_INDENT_COLS);
20
+ return leftWidth <= maxWidth;
21
+ }
22
+ export function rightAlignedX(width, contentWidth) {
23
+ if (width <= 0 || contentWidth <= 0) {
24
+ return null;
25
+ }
26
+ const maxWidth = Math.max(0, width - FOOTER_INDENT_COLS);
27
+ if (maxWidth === 0) {
28
+ return null;
29
+ }
30
+ if (contentWidth >= maxWidth) {
31
+ return FOOTER_INDENT_COLS;
32
+ }
33
+ return Math.max(FOOTER_INDENT_COLS, width - contentWidth - FOOTER_INDENT_COLS);
34
+ }
35
+ export function canShowLeftWithContext(width, leftWidth, contextWidth) {
36
+ const contextX = rightAlignedX(width, contextWidth);
37
+ if (contextX === null || leftWidth === 0) {
38
+ return true;
39
+ }
40
+ const leftExtent = FOOTER_INDENT_COLS + leftWidth + FOOTER_CONTEXT_GAP_COLS;
41
+ return leftExtent <= contextX;
42
+ }
43
+ export function singleLineFooterLayout(width, left, context) {
44
+ const safeLeft = left.trim();
45
+ const safeContext = context?.trim() ?? '';
46
+ const leftWidth = safeLeft.length;
47
+ const contextWidth = safeContext.length;
48
+ if (!safeContext) {
49
+ return { left: safeSlice(safeLeft, Math.max(0, width - FOOTER_INDENT_COLS)), showContext: false };
50
+ }
51
+ if (leftWidth > 0 && canShowLeftWithContext(width, leftWidth, contextWidth)) {
52
+ return { left: safeLeft, showContext: true };
53
+ }
54
+ if (leftWidth > 0 && leftFits(width, leftWidth)) {
55
+ return { left: safeLeft, showContext: false };
56
+ }
57
+ return { left: '', showContext: true };
58
+ }
59
+ export function renderFooterLine(props, width) {
60
+ const leftText = props.mode === 'ComposerHasDraft' ? props.draftHint : props.emptyHint;
61
+ const layout = singleLineFooterLayout(width, leftText, props.context);
62
+ const cells = Array.from({ length: Math.max(0, width) }, () => ' ');
63
+ if (layout.left) {
64
+ const clippedLeft = safeSlice(layout.left, Math.max(0, width - FOOTER_INDENT_COLS));
65
+ for (const [index, char] of [...clippedLeft].entries()) {
66
+ const target = FOOTER_INDENT_COLS + index;
67
+ if (target >= width) {
68
+ break;
69
+ }
70
+ cells[target] = char;
71
+ }
72
+ }
73
+ if (layout.showContext && props.context) {
74
+ const context = safeSlice(props.context, Math.max(0, width - FOOTER_INDENT_COLS));
75
+ const start = rightAlignedX(width, context.length);
76
+ if (start !== null) {
77
+ for (const [index, char] of [...context].entries()) {
78
+ const target = start + index;
79
+ if (target >= width) {
80
+ break;
81
+ }
82
+ cells[target] = char;
83
+ }
84
+ }
85
+ }
86
+ return cells.join('');
87
+ }
88
+ //# sourceMappingURL=codex-footer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-footer.js","sourceRoot":"","sources":["../../../src/lib/watch/codex-footer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ // Directly adapted from codex-rs/tui/src/bottom_pane/approval_overlay.rs and
2
+ // bottom_pane/list_selection_view.rs concepts. This is a minimal TS port of the
3
+ // centered selection overlay structure used by Codex.
4
+ function clip(text, width) {
5
+ if (width <= 0) {
6
+ return '';
7
+ }
8
+ if (text.length <= width) {
9
+ return text;
10
+ }
11
+ if (width <= 3) {
12
+ return text.slice(0, width);
13
+ }
14
+ return `${text.slice(0, width - 3)}...`;
15
+ }
16
+ function wrapText(text, width) {
17
+ if (width <= 1) {
18
+ return [text.slice(0, Math.max(width, 0))];
19
+ }
20
+ const lines = [];
21
+ for (const rawLine of text.split('\n')) {
22
+ let remaining = rawLine || ' ';
23
+ while (remaining.length > width) {
24
+ lines.push(remaining.slice(0, width));
25
+ remaining = remaining.slice(width);
26
+ }
27
+ lines.push(remaining);
28
+ }
29
+ return lines;
30
+ }
31
+ function boxLine(left, text, right, width) {
32
+ const innerWidth = Math.max(0, width - 2);
33
+ return `${left}${clip(text, innerWidth).padEnd(innerWidth, ' ')}${right}`;
34
+ }
35
+ function padLine(text, width) {
36
+ return clip(text, width).padEnd(width, ' ');
37
+ }
38
+ export function overlayOptionLabel(option) {
39
+ const shortcutText = option.shortcuts && option.shortcuts.length > 0
40
+ ? ` [${option.shortcuts.join('/')}]`
41
+ : '';
42
+ const descriptionText = option.description ? ` - ${option.description}` : '';
43
+ return `${option.label}${shortcutText}${descriptionText}`;
44
+ }
45
+ export function overlayHeight(state) {
46
+ return 5 + state.body.length + state.options.length;
47
+ }
48
+ function clippedBodyRows(rows, maxRows) {
49
+ if (rows.length <= maxRows) {
50
+ return { rows, hidden: false };
51
+ }
52
+ if (maxRows <= 0) {
53
+ return { rows: [], hidden: true };
54
+ }
55
+ if (maxRows === 1) {
56
+ return { rows: ['...'], hidden: true };
57
+ }
58
+ return {
59
+ rows: [...rows.slice(0, maxRows - 1), '...'],
60
+ hidden: true,
61
+ };
62
+ }
63
+ function optionBlocks(state, width) {
64
+ return state.options.map((option, index) => {
65
+ const marker = index === state.selectedIndex ? '> ' : ' ';
66
+ const wrapped = wrapText(overlayOptionLabel(option), Math.max(1, width - marker.length));
67
+ return {
68
+ optionIndex: index,
69
+ lines: wrapped.map((line, lineIndex) => padLine(`${lineIndex === 0 ? marker : ' '.repeat(marker.length)}${line}`, width)),
70
+ };
71
+ });
72
+ }
73
+ function visibleOptionRows(blocks, selectedIndex, maxRows) {
74
+ if (blocks.length === 0) {
75
+ return { rows: [], optionsHidden: false };
76
+ }
77
+ if (maxRows <= 0) {
78
+ return { rows: [], optionsHidden: true };
79
+ }
80
+ const clampedSelected = Math.max(0, Math.min(selectedIndex, blocks.length - 1));
81
+ const totalRows = blocks.reduce((sum, block) => sum + block.lines.length, 0);
82
+ if (totalRows <= maxRows) {
83
+ return {
84
+ rows: blocks.flatMap((block) => block.lines),
85
+ optionsHidden: false,
86
+ };
87
+ }
88
+ let start = clampedSelected;
89
+ let end = clampedSelected;
90
+ let usedRows = blocks[clampedSelected]?.lines.length ?? 0;
91
+ while (true) {
92
+ let expanded = false;
93
+ if (start > 0) {
94
+ const previousRows = blocks[start - 1]?.lines.length ?? 0;
95
+ if (usedRows + previousRows <= maxRows) {
96
+ start -= 1;
97
+ usedRows += previousRows;
98
+ expanded = true;
99
+ }
100
+ }
101
+ if (end < blocks.length - 1) {
102
+ const nextRows = blocks[end + 1]?.lines.length ?? 0;
103
+ if (usedRows + nextRows <= maxRows) {
104
+ end += 1;
105
+ usedRows += nextRows;
106
+ expanded = true;
107
+ }
108
+ }
109
+ if (!expanded) {
110
+ break;
111
+ }
112
+ }
113
+ if (usedRows > maxRows) {
114
+ return {
115
+ rows: (blocks[clampedSelected]?.lines ?? []).slice(0, maxRows),
116
+ optionsHidden: true,
117
+ };
118
+ }
119
+ return {
120
+ rows: blocks.slice(start, end + 1).flatMap((block) => block.lines),
121
+ optionsHidden: start > 0 || end < blocks.length - 1,
122
+ };
123
+ }
124
+ export function renderCodexOverlay(state, width, maxHeight) {
125
+ const outerWidth = Math.max(24, Math.min(width, 88));
126
+ const innerWidth = Math.max(0, outerWidth - 4);
127
+ const bodyLines = state.body.flatMap((line) => wrapText(line, innerWidth)).map((line) => padLine(line, innerWidth));
128
+ const blocks = optionBlocks(state, innerWidth);
129
+ const selectedBlockRows = blocks[Math.max(0, Math.min(state.selectedIndex, Math.max(blocks.length - 1, 0)))]?.lines.length ?? 0;
130
+ const baseFixedRows = 5;
131
+ const boundedContentRows = maxHeight > 0 ? Math.max(0, maxHeight - baseFixedRows) : Number.POSITIVE_INFINITY;
132
+ const bodyBudget = Number.isFinite(boundedContentRows)
133
+ ? Math.max(0, boundedContentRows - selectedBlockRows)
134
+ : bodyLines.length;
135
+ const clippedBody = clippedBodyRows(bodyLines, bodyBudget);
136
+ const optionViewportRows = Number.isFinite(boundedContentRows)
137
+ ? Math.max(0, boundedContentRows - clippedBody.rows.length)
138
+ : blocks.reduce((sum, block) => sum + block.lines.length, 0);
139
+ const visibleOptions = visibleOptionRows(blocks, state.selectedIndex, optionViewportRows);
140
+ const footerHint = [
141
+ state.footerHint ?? '↑/↓ move | Enter confirm | Esc cancel',
142
+ ...(visibleOptions.optionsHidden ? [`option ${Math.max(1, state.selectedIndex + 1)}/${state.options.length}`] : []),
143
+ ].join(' | ');
144
+ return [
145
+ boxLine('┌', ` ${state.title} `, '┐', outerWidth),
146
+ ...clippedBody.rows.map((line) => boxLine('│', ` ${line} `, '│', outerWidth)),
147
+ boxLine('│', ''.padEnd(innerWidth + 2, ' '), '│', outerWidth),
148
+ ...visibleOptions.rows.map((line) => boxLine('│', ` ${line} `, '│', outerWidth)),
149
+ boxLine('│', ''.padEnd(innerWidth + 2, ' '), '│', outerWidth),
150
+ boxLine('│', ` ${padLine(footerHint, innerWidth)} `, '│', outerWidth),
151
+ boxLine('└', ''.padEnd(innerWidth + 2, '─'), '┘', outerWidth),
152
+ ];
153
+ }
154
+ //# sourceMappingURL=codex-overlay.js.map