@compilr-dev/cli 0.6.1 → 0.6.3
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/CHANGELOG.md +104 -0
- package/README.md +12 -0
- package/dist/commands-v2/handlers/core.js +2 -2
- package/dist/commands-v2/handlers/index.d.ts +1 -0
- package/dist/commands-v2/handlers/index.js +5 -2
- package/dist/commands-v2/handlers/perf.d.ts +9 -0
- package/dist/commands-v2/handlers/perf.js +66 -0
- package/dist/commands-v2/handlers/project.js +2 -3
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/index.js +14 -8
- package/dist/repl-v2.js +5 -1
- package/dist/session/project-session-manager.js +1 -1
- package/dist/slash-autocomplete.js +18 -16
- package/dist/tabbed-menu.js +8 -7
- package/dist/ui/base/overlay-base.js +2 -1
- package/dist/ui/overlay/impl/artifact-detail-overlay-v2.js +12 -7
- package/dist/ui/overlay/impl/config-overlay-v2.js +2 -2
- package/dist/ui/overlay/impl/document-detail-overlay-v2.js +12 -8
- package/dist/ui/overlay/impl/pending-overlay-v2.js +4 -1
- package/dist/ui/overlay-manager.js +7 -6
- package/dist/ui/terminal-render-item.js +2 -1
- package/dist/ui/terminal-renderer.js +1 -2
- package/dist/ui/terminal-ui.js +6 -4
- package/dist/ui/terminal.d.ts +9 -0
- package/dist/ui/terminal.js +28 -15
- package/dist/utils/update-checker.d.ts +6 -1
- package/dist/utils/update-checker.js +16 -1
- package/package.json +5 -4
- package/dist/.tsbuildinfo.app +0 -1
- package/dist/.tsbuildinfo.data +0 -1
- package/dist/.tsbuildinfo.domain +0 -1
- package/dist/.tsbuildinfo.foundation +0 -1
- package/dist/guide/guide-content.d.ts +0 -23
- package/dist/guide/guide-content.js +0 -196
- package/dist/multi-agent/activity.d.ts +0 -21
- package/dist/multi-agent/activity.js +0 -34
- package/dist/multi-agent/agent-selection.d.ts +0 -55
- package/dist/multi-agent/agent-selection.js +0 -90
- package/dist/multi-agent/artifacts.d.ts +0 -197
- package/dist/multi-agent/artifacts.js +0 -379
- package/dist/multi-agent/collision-utils.d.ts +0 -16
- package/dist/multi-agent/collision-utils.js +0 -28
- package/dist/multi-agent/context-resolver.d.ts +0 -97
- package/dist/multi-agent/context-resolver.js +0 -316
- package/dist/multi-agent/mention-parser.d.ts +0 -64
- package/dist/multi-agent/mention-parser.js +0 -146
- package/dist/multi-agent/shared-context.d.ts +0 -293
- package/dist/multi-agent/shared-context.js +0 -671
- package/dist/multi-agent/skill-requirements.d.ts +0 -66
- package/dist/multi-agent/skill-requirements.js +0 -178
- package/dist/multi-agent/task-assignment.d.ts +0 -69
- package/dist/multi-agent/task-assignment.js +0 -123
- package/dist/multi-agent/task-suggestion.d.ts +0 -31
- package/dist/multi-agent/task-suggestion.js +0 -72
- package/dist/multi-agent/team-agent.d.ts +0 -201
- package/dist/multi-agent/team-agent.js +0 -488
- package/dist/multi-agent/team.d.ts +0 -286
- package/dist/multi-agent/team.js +0 -610
- package/dist/multi-agent/tool-config.d.ts +0 -110
- package/dist/multi-agent/tool-config.js +0 -661
- package/dist/multi-agent/types.d.ts +0 -211
- package/dist/multi-agent/types.js +0 -617
- package/dist/tools/guide-tool.d.ts +0 -12
- package/dist/tools/guide-tool.js +0 -59
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@compilr-dev/cli` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
> **Beta notice:** versions in the `0.x` range may contain breaking changes
|
|
9
|
+
> between minors. Read each release entry before upgrading.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## [Unreleased]
|
|
14
|
+
|
|
15
|
+
## [0.6.2] — 2026-04-25
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Respect the [`NO_COLOR`](https://no-color.org) standard — `NO_COLOR=1 compilr ...`
|
|
19
|
+
now produces uncolored output instead of being silently overridden by
|
|
20
|
+
`FORCE_COLOR=3`. Restores accessibility for screen readers, low-contrast
|
|
21
|
+
terminals, log redirection, and CI environments.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Lower minimum supported Node from `>=22.0.0` to `>=20.0.0` — Node 20 is the
|
|
25
|
+
active LTS line and the codebase uses no v22-only APIs. Restores compatibility
|
|
26
|
+
for users still on Node 20 LTS.
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
- Documented opt-outs for the npm registry update check. Set any of the
|
|
30
|
+
following to skip the network call on startup:
|
|
31
|
+
- `COMPILR_NO_UPDATE_CHECK=1` (project-specific)
|
|
32
|
+
- `NO_UPDATE_NOTIFIER=1` (de-facto standard from `update-notifier`)
|
|
33
|
+
- `CI=true` (auto-respected in CI)
|
|
34
|
+
- `CHANGELOG.md` shipped in the published tarball (this file).
|
|
35
|
+
|
|
36
|
+
### Removed
|
|
37
|
+
- TypeScript incremental build caches (`*.tsbuildinfo`) no longer ship in the
|
|
38
|
+
npm tarball. Tarball is now ~760 KB compressed (previously ~1 MB) — about
|
|
39
|
+
~660 KB lighter on disk after install.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## [0.6.1] — 2026-04-21
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
- Resolved `npm audit` vulnerabilities in transitive deps (`hono`, `protobufjs`).
|
|
47
|
+
|
|
48
|
+
## [0.6.0] — 2026-04-19
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
- **Major:** CLI now builds on `createCompilrAgent` from `@compilr-dev/sdk`
|
|
52
|
+
(universal agent runtime). All agent setup, tool assembly, capability
|
|
53
|
+
loading, and team coordination flow through the SDK. CLI source dropped
|
|
54
|
+
from ~3.5 K LOC of agent wiring to a thin adapter.
|
|
55
|
+
- Logging is now structured JSON via `@compilr-dev/logger` (Pino) — no more
|
|
56
|
+
raw `console.log` from diagnostic paths. Logs are scrubbed for secrets.
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
- Plan Mode V2 — permission-blocking + tool-based transitions for safer
|
|
60
|
+
multi-step planning workflows. Plan can now be approved/edited from
|
|
61
|
+
inside the CLI.
|
|
62
|
+
- `/app` command — terminal app model viewer overlay (entities, fields,
|
|
63
|
+
relationships, layout, config). Aligned columns, no emojis.
|
|
64
|
+
- Custom agent wizard Step 5 — free-text custom instructions added per agent.
|
|
65
|
+
- Template support in custom agent wizard — `Ctrl+T` to save as template,
|
|
66
|
+
list UI to load existing templates.
|
|
67
|
+
- Guide tool migrated to SDK (`createGuideTool({ environment, additionalEntries })`).
|
|
68
|
+
- Removed two-repo and guided-workflow options from the wizard — both are
|
|
69
|
+
always single-repo + flexible now.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
- Credential encryption now survives container restarts (master key
|
|
73
|
+
derivation hardened).
|
|
74
|
+
- `/app` overlay — aligned columns, layout/config in summary, no emojis.
|
|
75
|
+
- Agent IDs may contain dashes.
|
|
76
|
+
|
|
77
|
+
## [0.5.x] — 2026-03 → 2026-04
|
|
78
|
+
|
|
79
|
+
Highlights from the 0.5 line:
|
|
80
|
+
|
|
81
|
+
- Migrated more code paths to `@compilr-dev/sdk` (anchors, MCP, permissions,
|
|
82
|
+
SQLite repositories, capability loading).
|
|
83
|
+
- Pin API replaces the older anchor API for project state injection.
|
|
84
|
+
- Multi-terminal session awareness, dynamic capability loading with
|
|
85
|
+
auto-load on filtered tool use, observation masking, tool input
|
|
86
|
+
compaction, and tool result auto-delegation.
|
|
87
|
+
- Multi-LLM support across 9 providers (Claude, OpenAI, Gemini, Groq,
|
|
88
|
+
Fireworks, Together, Perplexity, OpenRouter, Ollama).
|
|
89
|
+
- Multi-agent teams (delegate, delegate_background, $mention routing,
|
|
90
|
+
/team dashboard, background queues).
|
|
91
|
+
|
|
92
|
+
For commit-level detail of the 0.5 line, see git log between v0.5.0 and v0.6.0.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Earlier versions
|
|
97
|
+
|
|
98
|
+
The `0.4.x` and prior series were rapid pre-MVP iterations. See the git
|
|
99
|
+
history for details.
|
|
100
|
+
|
|
101
|
+
[Unreleased]: https://github.com/compilr-dev/cli/compare/v0.6.2...HEAD
|
|
102
|
+
[0.6.2]: https://github.com/compilr-dev/cli/compare/v0.6.1...v0.6.2
|
|
103
|
+
[0.6.1]: https://github.com/compilr-dev/cli/compare/v0.6.0...v0.6.1
|
|
104
|
+
[0.6.0]: https://github.com/compilr-dev/cli/compare/v0.5.17...v0.6.0
|
package/README.md
CHANGED
|
@@ -217,6 +217,18 @@ export GOOGLE_API_KEY="..." # Google Gemini
|
|
|
217
217
|
|
|
218
218
|
Environment variables take priority over stored keys.
|
|
219
219
|
|
|
220
|
+
### Behavior Environment Variables
|
|
221
|
+
|
|
222
|
+
The CLI honors several standard environment variables for accessibility,
|
|
223
|
+
privacy, and CI use:
|
|
224
|
+
|
|
225
|
+
| Variable | Effect |
|
|
226
|
+
|---|---|
|
|
227
|
+
| `NO_COLOR=1` | Disable all ANSI colors. Honors the [no-color.org](https://no-color.org) standard. |
|
|
228
|
+
| `COMPILR_NO_UPDATE_CHECK=1` | Skip the npm registry update check at startup. |
|
|
229
|
+
| `NO_UPDATE_NOTIFIER=1` | Same as above. De-facto standard from `update-notifier`. |
|
|
230
|
+
| `CI=true` | Auto-skips the update check (no nag in CI environments). |
|
|
231
|
+
|
|
220
232
|
### Project Configuration
|
|
221
233
|
|
|
222
234
|
Create a `COMPILR.md` file in your project root to provide context:
|
|
@@ -171,8 +171,8 @@ export const menuCommand = {
|
|
|
171
171
|
console.log(s.muted(' Run: npm update -g @compilr-dev/cli'));
|
|
172
172
|
console.log('');
|
|
173
173
|
}
|
|
174
|
-
// Dashboard loop
|
|
175
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
174
|
+
// Dashboard loop — returns to dashboard after sub-commands until user exits or continues
|
|
175
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop; exit happens via internal break/return
|
|
176
176
|
while (true) {
|
|
177
177
|
const dashboard = new DashboardOverlayV2();
|
|
178
178
|
const result = await ctx.ui.showOverlay(dashboard);
|
|
@@ -11,7 +11,7 @@ import { debugCommands } from './debug.js';
|
|
|
11
11
|
import { sessionCommands } from './session.js';
|
|
12
12
|
import { resetCommands } from './reset.js';
|
|
13
13
|
import { teamCommands } from './team.js';
|
|
14
|
-
import { gamesCommand } from './games.js';
|
|
14
|
+
// import { gamesCommand } from './games.js'; // Temporarily disabled — Tetris copyright concerns
|
|
15
15
|
import { tasksCommand } from './tasks.js';
|
|
16
16
|
import { backgroundCommands } from './background.js';
|
|
17
17
|
import { filterCommands } from './filter.js';
|
|
@@ -21,6 +21,7 @@ import { terminalsCommands } from './terminals.js';
|
|
|
21
21
|
import { notificationsCommands } from './notifications.js';
|
|
22
22
|
import { mcpCommands } from './mcp.js';
|
|
23
23
|
import { delegationsCommands } from './delegations.js';
|
|
24
|
+
import { perfCommands } from './perf.js';
|
|
24
25
|
// Re-export individual modules
|
|
25
26
|
export * from './core.js';
|
|
26
27
|
export * from './settings.js';
|
|
@@ -40,6 +41,7 @@ export * from './terminals.js';
|
|
|
40
41
|
export * from './notifications.js';
|
|
41
42
|
export * from './mcp.js';
|
|
42
43
|
export * from './delegations.js';
|
|
44
|
+
export * from './perf.js';
|
|
43
45
|
// All commands combined
|
|
44
46
|
export const allCommands = [
|
|
45
47
|
...coreCommands,
|
|
@@ -50,7 +52,7 @@ export const allCommands = [
|
|
|
50
52
|
...sessionCommands,
|
|
51
53
|
...resetCommands,
|
|
52
54
|
...teamCommands,
|
|
53
|
-
gamesCommand,
|
|
55
|
+
// gamesCommand, // Temporarily disabled — Tetris copyright concerns
|
|
54
56
|
tasksCommand,
|
|
55
57
|
...backgroundCommands,
|
|
56
58
|
...filterCommands,
|
|
@@ -60,4 +62,5 @@ export const allCommands = [
|
|
|
60
62
|
...notificationsCommands,
|
|
61
63
|
...mcpCommands,
|
|
62
64
|
...delegationsCommands,
|
|
65
|
+
...perfCommands,
|
|
63
66
|
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /perf Command
|
|
3
|
+
*
|
|
4
|
+
* Display the most recent CLI startup-performance profile.
|
|
5
|
+
* The profile is captured automatically and written to
|
|
6
|
+
* ~/.compilr-dev/startup-perf.log on every launch.
|
|
7
|
+
*/
|
|
8
|
+
import type { CommandHandlerV2 } from '../types.js';
|
|
9
|
+
export declare const perfCommands: CommandHandlerV2[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /perf Command
|
|
3
|
+
*
|
|
4
|
+
* Display the most recent CLI startup-performance profile.
|
|
5
|
+
* The profile is captured automatically and written to
|
|
6
|
+
* ~/.compilr-dev/startup-perf.log on every launch.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import pc from 'picocolors';
|
|
11
|
+
import { getDataPath } from '../../settings/paths.js';
|
|
12
|
+
const perfCommand = {
|
|
13
|
+
name: 'perf',
|
|
14
|
+
description: 'Show the latest startup-performance profile',
|
|
15
|
+
details: 'Display the timing breakdown captured during this CLI launch. ' +
|
|
16
|
+
'Useful for diagnosing slow startups (cold cache, heavy MCP servers, ' +
|
|
17
|
+
'large project DBs). The profile is overwritten on every launch.',
|
|
18
|
+
examples: [{ code: '/perf', description: 'Show the most recent startup profile' }],
|
|
19
|
+
execute(_args, ctx) {
|
|
20
|
+
const logPath = path.join(getDataPath(), 'startup-perf.log');
|
|
21
|
+
if (!fs.existsSync(logPath)) {
|
|
22
|
+
ctx.ui.print({
|
|
23
|
+
type: 'info',
|
|
24
|
+
message: 'No startup profile found. (Profile is written on the next launch.)',
|
|
25
|
+
});
|
|
26
|
+
return Promise.resolve(true);
|
|
27
|
+
}
|
|
28
|
+
let content;
|
|
29
|
+
try {
|
|
30
|
+
content = fs.readFileSync(logPath, 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
ctx.ui.print({
|
|
34
|
+
type: 'warning',
|
|
35
|
+
message: `Could not read startup profile: ${String(err)}`,
|
|
36
|
+
});
|
|
37
|
+
return Promise.resolve(true);
|
|
38
|
+
}
|
|
39
|
+
if (!content.trim()) {
|
|
40
|
+
ctx.ui.print({ type: 'info', message: 'Startup profile is empty.' });
|
|
41
|
+
return Promise.resolve(true);
|
|
42
|
+
}
|
|
43
|
+
// Print the profile, dimming the path footer.
|
|
44
|
+
const lines = content.split('\n');
|
|
45
|
+
const out = [];
|
|
46
|
+
for (const line of lines) {
|
|
47
|
+
if (line.startsWith('===')) {
|
|
48
|
+
out.push(pc.bold(line));
|
|
49
|
+
}
|
|
50
|
+
else if (line.startsWith('Slow steps')) {
|
|
51
|
+
out.push(pc.yellow(line));
|
|
52
|
+
}
|
|
53
|
+
else if (line.startsWith('Total:')) {
|
|
54
|
+
out.push(pc.cyan(line));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
out.push(line);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
out.push('');
|
|
61
|
+
out.push(pc.dim(` Profile: ${logPath}`));
|
|
62
|
+
ctx.ui.print({ type: 'raw-lines', lines: out });
|
|
63
|
+
return Promise.resolve(true);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
export const perfCommands = [perfCommand];
|
|
@@ -178,9 +178,8 @@ export const initCommand = {
|
|
|
178
178
|
'Type to enter values in input steps',
|
|
179
179
|
],
|
|
180
180
|
async execute(_args, ctx) {
|
|
181
|
-
// Show onboarding wizard (same as first-run experience)
|
|
182
|
-
//
|
|
183
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
181
|
+
// Show onboarding wizard (same as first-run experience).
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop; exit happens via internal break/return
|
|
184
183
|
while (true) {
|
|
185
184
|
const wizard = new OnboardingWizardOverlayV2();
|
|
186
185
|
const result = await ctx.ui.showOverlay(wizard);
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Force color output for all chalk-based libraries (cli-highlight, marked-terminal, etc.)
|
|
3
|
-
// This must be set BEFORE any imports that use chalk
|
|
4
|
-
|
|
3
|
+
// This must be set BEFORE any imports that use chalk.
|
|
4
|
+
// Respect the NO_COLOR standard (https://no-color.org) — never override an explicit user opt-out.
|
|
5
|
+
if (!process.env.NO_COLOR) {
|
|
6
|
+
process.env.FORCE_COLOR = '3';
|
|
7
|
+
}
|
|
5
8
|
/**
|
|
6
9
|
* @compilr-dev/cli
|
|
7
10
|
*
|
|
@@ -85,7 +88,7 @@ function showHelp() {
|
|
|
85
88
|
console.log(`
|
|
86
89
|
@compilr-dev/cli v${VERSION}
|
|
87
90
|
|
|
88
|
-
Usage:
|
|
91
|
+
Usage: compilr [options]
|
|
89
92
|
|
|
90
93
|
Options:
|
|
91
94
|
--provider, -p <provider> LLM provider (claude, openai, gemini, ollama)
|
|
@@ -100,13 +103,16 @@ Environment Variables:
|
|
|
100
103
|
ANTHROPIC_API_KEY Required for Claude provider
|
|
101
104
|
OPENAI_API_KEY Required for OpenAI provider
|
|
102
105
|
GOOGLE_AI_API_KEY Required for Gemini provider
|
|
106
|
+
NO_COLOR Disable ANSI colors
|
|
107
|
+
COMPILR_NO_UPDATE_CHECK Skip the npm registry update check at startup
|
|
108
|
+
CI Auto-skips the update check
|
|
103
109
|
|
|
104
110
|
Examples:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
compilr
|
|
112
|
+
compilr --model claude-sonnet-4-6
|
|
113
|
+
compilr --provider gemini --model gemini-2.0-flash
|
|
114
|
+
compilr --minimal --show-filtering
|
|
115
|
+
compilr --update
|
|
110
116
|
`);
|
|
111
117
|
}
|
|
112
118
|
// =============================================================================
|
package/dist/repl-v2.js
CHANGED
|
@@ -3358,8 +3358,12 @@ export class ReplV2 {
|
|
|
3358
3358
|
// Only run main() when executed directly (not when imported)
|
|
3359
3359
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
3360
3360
|
const repl = new ReplV2();
|
|
3361
|
-
// Handle SIGINT
|
|
3361
|
+
// Handle SIGINT — restore raw mode before exit so the parent shell
|
|
3362
|
+
// doesn't inherit a broken terminal state.
|
|
3362
3363
|
process.on('SIGINT', () => {
|
|
3364
|
+
if (process.stdin.isTTY) {
|
|
3365
|
+
process.stdin.setRawMode(false);
|
|
3366
|
+
}
|
|
3363
3367
|
console.log('\n\nInterrupted\n');
|
|
3364
3368
|
process.exit(0);
|
|
3365
3369
|
});
|
|
@@ -387,7 +387,7 @@ export class ProjectSessionManager {
|
|
|
387
387
|
else if (Array.isArray(lastUserMsg.content)) {
|
|
388
388
|
const textBlock = lastUserMsg.content.find((b) => b.type === 'text');
|
|
389
389
|
if (textBlock?.type === 'text') {
|
|
390
|
-
preview = textBlock.text;
|
|
390
|
+
preview = (textBlock).text;
|
|
391
391
|
}
|
|
392
392
|
}
|
|
393
393
|
}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* - Proper wrapping for long input
|
|
10
10
|
*/
|
|
11
11
|
import pc from 'picocolors';
|
|
12
|
+
import { ttyWrite } from './ui/terminal.js';
|
|
12
13
|
// ANSI escape codes for terminal control
|
|
13
14
|
const ANSI = {
|
|
14
15
|
HIDE_CURSOR: '\x1B[?25l',
|
|
@@ -83,7 +84,7 @@ function renderDropdown(state, promptLen, currentLine, totalLines, hasSeparators
|
|
|
83
84
|
if (hasSeparators)
|
|
84
85
|
linesToMoveDown += 1;
|
|
85
86
|
if (linesToMoveDown > 0) {
|
|
86
|
-
|
|
87
|
+
ttyWrite(ANSI.MOVE_DOWN(linesToMoveDown));
|
|
87
88
|
}
|
|
88
89
|
process.stdout.write('\n');
|
|
89
90
|
const visible = state.matches.slice(0, MAX_VISIBLE);
|
|
@@ -98,8 +99,8 @@ function renderDropdown(state, promptLen, currentLine, totalLines, hasSeparators
|
|
|
98
99
|
// Move back up to cursor position
|
|
99
100
|
const linesRendered = visible.length;
|
|
100
101
|
const linesToMoveUp = linesRendered + linesToMoveDown + 1;
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
ttyWrite(ANSI.MOVE_UP(linesToMoveUp));
|
|
103
|
+
ttyWrite(ANSI.MOVE_TO_COLUMN(promptLen + state.cursorPos + 1));
|
|
103
104
|
return linesRendered;
|
|
104
105
|
}
|
|
105
106
|
/**
|
|
@@ -113,16 +114,17 @@ function clearDropdown(dropdownLines, currentLine, totalLines, hasSeparators) {
|
|
|
113
114
|
if (hasSeparators)
|
|
114
115
|
linesToMoveDown += 1;
|
|
115
116
|
if (linesToMoveDown > 0) {
|
|
116
|
-
|
|
117
|
+
ttyWrite(ANSI.MOVE_DOWN(linesToMoveDown));
|
|
117
118
|
}
|
|
118
119
|
process.stdout.write('\n');
|
|
119
120
|
// Clear dropdown lines
|
|
120
121
|
for (let i = 0; i < dropdownLines; i++) {
|
|
121
|
-
|
|
122
|
+
ttyWrite(ANSI.CLEAR_LINE);
|
|
123
|
+
process.stdout.write('\n');
|
|
122
124
|
}
|
|
123
125
|
// Move back up
|
|
124
126
|
const linesToMoveUp = dropdownLines + linesToMoveDown + 1;
|
|
125
|
-
|
|
127
|
+
ttyWrite(ANSI.MOVE_UP(linesToMoveUp));
|
|
126
128
|
}
|
|
127
129
|
/**
|
|
128
130
|
* Create interactive input with autocomplete
|
|
@@ -198,13 +200,13 @@ export function createInteractiveInput(prompt, onSubmit, showSeparator = true, g
|
|
|
198
200
|
const termWidth = getTerminalWidth();
|
|
199
201
|
// Clear previous render
|
|
200
202
|
if (linesAboveCursor > 0) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
ttyWrite('\r');
|
|
204
|
+
ttyWrite(ANSI.MOVE_UP(linesAboveCursor));
|
|
203
205
|
}
|
|
204
206
|
else {
|
|
205
|
-
|
|
207
|
+
ttyWrite('\r');
|
|
206
208
|
}
|
|
207
|
-
|
|
209
|
+
ttyWrite(ANSI.CLEAR_TO_END_OF_SCREEN);
|
|
208
210
|
// Render todos
|
|
209
211
|
renderedTodoLines = renderTodoSection();
|
|
210
212
|
// Render top separator
|
|
@@ -246,10 +248,10 @@ export function createInteractiveInput(prompt, onSubmit, showSeparator = true, g
|
|
|
246
248
|
}
|
|
247
249
|
linesToMoveUp += (currentLinePhysical - 1 - cursorPhysicalRow);
|
|
248
250
|
if (linesToMoveUp > 0) {
|
|
249
|
-
|
|
251
|
+
ttyWrite(ANSI.MOVE_UP(linesToMoveUp));
|
|
250
252
|
}
|
|
251
253
|
const cursorCol = (cursorAbsPos % termWidth) + 1;
|
|
252
|
-
|
|
254
|
+
ttyWrite(ANSI.MOVE_TO_COLUMN(cursorCol));
|
|
253
255
|
// Track cursor position for next render
|
|
254
256
|
linesAboveCursor = physicalLinesRendered + physicalLinesBeforeCursor + cursorPhysicalRow;
|
|
255
257
|
}
|
|
@@ -339,9 +341,9 @@ export function createInteractiveInput(prompt, onSubmit, showSeparator = true, g
|
|
|
339
341
|
dropdownLines = 0;
|
|
340
342
|
// Clear display
|
|
341
343
|
if (linesAboveCursor > 0) {
|
|
342
|
-
|
|
344
|
+
ttyWrite('\r' + ANSI.MOVE_UP(linesAboveCursor));
|
|
343
345
|
}
|
|
344
|
-
|
|
346
|
+
ttyWrite('\r' + ANSI.CLEAR_TO_END_OF_SCREEN);
|
|
345
347
|
// Print clean input
|
|
346
348
|
for (let i = 0; i < state.lines.length; i++) {
|
|
347
349
|
const linePrompt = i === 0 ? prompt : pc.dim(' \\ ');
|
|
@@ -494,7 +496,7 @@ export function createInteractiveInput(prompt, onSubmit, showSeparator = true, g
|
|
|
494
496
|
if (isLeftArrow) {
|
|
495
497
|
if (state.cursorPos > 0) {
|
|
496
498
|
state.cursorPos--;
|
|
497
|
-
|
|
499
|
+
ttyWrite('\x1B[D');
|
|
498
500
|
}
|
|
499
501
|
else if (state.currentLine > 0) {
|
|
500
502
|
state.currentLine--;
|
|
@@ -507,7 +509,7 @@ export function createInteractiveInput(prompt, onSubmit, showSeparator = true, g
|
|
|
507
509
|
if (isRightArrow) {
|
|
508
510
|
if (state.cursorPos < state.lines[state.currentLine].length) {
|
|
509
511
|
state.cursorPos++;
|
|
510
|
-
|
|
512
|
+
ttyWrite('\x1B[C');
|
|
511
513
|
}
|
|
512
514
|
else if (state.currentLine < state.lines.length - 1) {
|
|
513
515
|
state.currentLine++;
|
package/dist/tabbed-menu.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import pc from 'picocolors';
|
|
8
8
|
import { getCustomCommandRegistry } from './commands/index.js';
|
|
9
9
|
import { truncate } from './ui/base/index.js';
|
|
10
|
+
import { ttyWrite } from './ui/terminal.js';
|
|
10
11
|
// ANSI escape codes
|
|
11
12
|
const ANSI = {
|
|
12
13
|
HIDE_CURSOR: '\x1B[?25l',
|
|
@@ -201,11 +202,11 @@ function render(state, prevLineCount) {
|
|
|
201
202
|
// Clear previous render
|
|
202
203
|
if (prevLineCount > 0) {
|
|
203
204
|
// Move to column 1, move up to first line, clear everything below
|
|
204
|
-
|
|
205
|
+
ttyWrite('\r');
|
|
205
206
|
if (prevLineCount > 1) {
|
|
206
|
-
|
|
207
|
+
ttyWrite(ANSI.MOVE_UP(prevLineCount - 1));
|
|
207
208
|
}
|
|
208
|
-
|
|
209
|
+
ttyWrite(ANSI.CLEAR_TO_END);
|
|
209
210
|
}
|
|
210
211
|
// Render new content
|
|
211
212
|
process.stdout.write(lines.join('\n'));
|
|
@@ -283,7 +284,7 @@ export function showHelpMenu() {
|
|
|
283
284
|
// Start on a new line (menu appears below the prompt)
|
|
284
285
|
process.stdout.write('\n');
|
|
285
286
|
// Hide cursor during menu display
|
|
286
|
-
|
|
287
|
+
ttyWrite(ANSI.HIDE_CURSOR);
|
|
287
288
|
// Store original raw mode state
|
|
288
289
|
const wasRawMode = process.stdin.isRaw;
|
|
289
290
|
// Enable raw mode
|
|
@@ -298,13 +299,13 @@ export function showHelpMenu() {
|
|
|
298
299
|
// lineCount lines with lineCount-1 newlines between them, plus the initial \n we added
|
|
299
300
|
// So cursor is (lineCount-1)+1 = lineCount lines below where "You: /help" ended
|
|
300
301
|
if (lineCount > 0) {
|
|
301
|
-
|
|
302
|
-
|
|
302
|
+
ttyWrite(ANSI.MOVE_UP(lineCount));
|
|
303
|
+
ttyWrite(ANSI.CLEAR_TO_END);
|
|
303
304
|
}
|
|
304
305
|
// Print newline so next prompt appears on fresh line
|
|
305
306
|
process.stdout.write('\n');
|
|
306
307
|
// Show cursor
|
|
307
|
-
|
|
308
|
+
ttyWrite(ANSI.SHOW_CURSOR);
|
|
308
309
|
// Restore raw mode to original state
|
|
309
310
|
if (process.stdin.isTTY && !wasRawMode) {
|
|
310
311
|
process.stdin.setRawMode(false);
|
|
@@ -42,6 +42,7 @@ import * as terminal from '../terminal.js';
|
|
|
42
42
|
import { getStyles } from '../../themes/index.js';
|
|
43
43
|
import { OverlayLifecycle } from './overlay-lifecycle.js';
|
|
44
44
|
import { debugLog } from '../../utils/debug-log.js';
|
|
45
|
+
import { ttyWrite } from '../terminal.js';
|
|
45
46
|
// =============================================================================
|
|
46
47
|
// BaseOverlay Abstract Class
|
|
47
48
|
// =============================================================================
|
|
@@ -150,7 +151,7 @@ export class BaseOverlay {
|
|
|
150
151
|
this.state.maxLineCount = 0;
|
|
151
152
|
// Explicitly move cursor to home and save position
|
|
152
153
|
// This ensures we're at (0,0) regardless of what clearScreen() did
|
|
153
|
-
|
|
154
|
+
ttyWrite('\x1b[H');
|
|
154
155
|
terminal.saveCursor();
|
|
155
156
|
}
|
|
156
157
|
// ===========================================================================
|
|
@@ -14,6 +14,7 @@ import { markedTerminal } from 'marked-terminal';
|
|
|
14
14
|
import { BaseOverlayV2 } from '../../base/overlay-base-v2.js';
|
|
15
15
|
import { getCurrentTheme } from '../../../themes/index.js';
|
|
16
16
|
import * as terminal from '../../terminal.js';
|
|
17
|
+
import { ttyWrite } from '../../terminal.js';
|
|
17
18
|
import { ARTIFACT_TYPE_LABELS } from '../../constants/labels.js';
|
|
18
19
|
// =============================================================================
|
|
19
20
|
// Alternate Screen Buffer Management
|
|
@@ -22,14 +23,14 @@ let inAlternateScreen = false;
|
|
|
22
23
|
function enterAlternateScreen() {
|
|
23
24
|
if (inAlternateScreen)
|
|
24
25
|
return;
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
ttyWrite('\x1b[?1049h'); // Switch to alternate screen
|
|
27
|
+
ttyWrite('\x1b[H'); // Move cursor to home
|
|
27
28
|
inAlternateScreen = true;
|
|
28
29
|
}
|
|
29
30
|
function exitAlternateScreen() {
|
|
30
31
|
if (!inAlternateScreen)
|
|
31
32
|
return;
|
|
32
|
-
|
|
33
|
+
ttyWrite('\x1b[?1049l'); // Switch back to main screen
|
|
33
34
|
inAlternateScreen = false;
|
|
34
35
|
}
|
|
35
36
|
// Ensure we exit alternate screen on process termination
|
|
@@ -42,10 +43,14 @@ function setupAlternateScreenCleanup() {
|
|
|
42
43
|
cleanup();
|
|
43
44
|
process.exit(130);
|
|
44
45
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
// Windows doesn't deliver SIGTERM — Node silently ignores the listener
|
|
47
|
+
// there, but we add the platform guard for clarity.
|
|
48
|
+
if (process.platform !== 'win32') {
|
|
49
|
+
process.on('SIGTERM', () => {
|
|
50
|
+
cleanup();
|
|
51
|
+
process.exit(143);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
49
54
|
}
|
|
50
55
|
setupAlternateScreenCleanup();
|
|
51
56
|
// =============================================================================
|
|
@@ -611,9 +611,9 @@ export class ConfigOverlayV2 extends BaseOverlayV2 {
|
|
|
611
611
|
*/
|
|
612
612
|
toggleOrCycleItem() {
|
|
613
613
|
const item = this.state.configItems[this.state.selectedItem];
|
|
614
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
614
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- selectedItem can briefly point past array end during async re-render
|
|
615
615
|
if (!item)
|
|
616
|
-
return null;
|
|
616
|
+
return null;
|
|
617
617
|
if (item.type === 'boolean') {
|
|
618
618
|
const newValue = !item.value;
|
|
619
619
|
item.value = newValue;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import chalk from 'chalk';
|
|
15
15
|
import hljs from 'highlight.js';
|
|
16
|
+
import { ttyWrite } from '../../terminal.js';
|
|
16
17
|
// =============================================================================
|
|
17
18
|
// Alternate Screen Buffer Management
|
|
18
19
|
// =============================================================================
|
|
@@ -20,14 +21,14 @@ let inAlternateScreen = false;
|
|
|
20
21
|
function enterAlternateScreen() {
|
|
21
22
|
if (inAlternateScreen)
|
|
22
23
|
return;
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
ttyWrite('\x1b[?1049h'); // Switch to alternate screen
|
|
25
|
+
ttyWrite('\x1b[H'); // Move cursor to home
|
|
25
26
|
inAlternateScreen = true;
|
|
26
27
|
}
|
|
27
28
|
function exitAlternateScreen() {
|
|
28
29
|
if (!inAlternateScreen)
|
|
29
30
|
return;
|
|
30
|
-
|
|
31
|
+
ttyWrite('\x1b[?1049l'); // Switch back to main screen
|
|
31
32
|
inAlternateScreen = false;
|
|
32
33
|
}
|
|
33
34
|
// Ensure we exit alternate screen on process termination
|
|
@@ -42,11 +43,14 @@ function setupAlternateScreenCleanup() {
|
|
|
42
43
|
cleanup();
|
|
43
44
|
process.exit(130);
|
|
44
45
|
});
|
|
45
|
-
// Handle termination
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
process.
|
|
49
|
-
|
|
46
|
+
// Handle termination (Windows doesn't deliver SIGTERM — Node silently
|
|
47
|
+
// ignores the listener there, but we add the platform guard for clarity)
|
|
48
|
+
if (process.platform !== 'win32') {
|
|
49
|
+
process.on('SIGTERM', () => {
|
|
50
|
+
cleanup();
|
|
51
|
+
process.exit(143);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
50
54
|
// Handle uncaught exceptions
|
|
51
55
|
process.on('uncaughtException', (err) => {
|
|
52
56
|
cleanup();
|
|
@@ -203,7 +203,10 @@ export class PendingOverlayV2 extends BaseOverlayV2 {
|
|
|
203
203
|
const agentLabel = `$${req.agentId}`;
|
|
204
204
|
const ctx = req.context;
|
|
205
205
|
const filePath = ctx?.input
|
|
206
|
-
? (
|
|
206
|
+
? (() => {
|
|
207
|
+
const input = ctx.input;
|
|
208
|
+
return (input.filePath ?? input.file_path ?? input.path ?? '');
|
|
209
|
+
})()
|
|
207
210
|
: '';
|
|
208
211
|
const fileName = filePath.split('/').pop() || filePath;
|
|
209
212
|
// Header
|