lsd-pi 1.1.4 → 1.1.6
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/README.md +2 -1
- package/dist/headless-ui.js +2 -0
- package/dist/onboarding.js +11 -8
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/await-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/cancel-job-tool.js +7 -0
- package/dist/resources/extensions/cache-timer/index.js +5 -0
- package/dist/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/dist/resources/extensions/codex-rotate/README.md +9 -3
- package/dist/resources/extensions/codex-rotate/commands.js +15 -8
- package/dist/resources/extensions/codex-rotate/index.js +17 -8
- package/dist/resources/extensions/memory/auto-extract.js +196 -80
- package/dist/resources/extensions/memory/dream.js +86 -19
- package/dist/resources/extensions/shared/rtk.js +89 -87
- package/dist/resources/extensions/subagent/index.js +33 -7
- package/dist/startup-model-validation.js +12 -2
- package/dist/update-check.js +2 -2
- package/dist/update-cmd.js +3 -3
- package/dist/welcome-screen.js +43 -14
- package/package.json +3 -2
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +43 -4
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts +48 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js +173 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +16 -3
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +18 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.js +2 -2
- package/packages/pi-coding-agent/dist/core/tool-approval.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +23 -2
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +50 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js +289 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +36 -22
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +3 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +23 -62
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts +39 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +182 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +36 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -77
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +4 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +49 -13
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +27 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +251 -39
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts +10 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts +7 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js.map +1 -0
- package/packages/pi-coding-agent/package.json +9 -4
- package/packages/pi-coding-agent/src/core/agent-session.clear-queue.test.ts +50 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +50 -4
- package/packages/pi-coding-agent/src/core/extensions/types.ts +1 -1
- package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
- package/packages/pi-coding-agent/src/core/pty-executor.ts +229 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +16 -3
- package/packages/pi-coding-agent/src/core/settings-manager.ts +27 -0
- package/packages/pi-coding-agent/src/core/tool-approval.ts +2 -2
- package/packages/pi-coding-agent/src/core/tools/index.ts +35 -2
- package/packages/pi-coding-agent/src/core/tools/pty.ts +354 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +37 -24
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +22 -70
- package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +224 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +45 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +104 -81
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +5 -19
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +55 -13
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +296 -48
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +2 -2
- package/packages/pi-coding-agent/src/utils/terminal-screen.ts +77 -0
- package/packages/pi-coding-agent/src/utils/terminal-serializer.ts +72 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js +105 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +4 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +57 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/loader.d.ts +26 -6
- package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/loader.js +178 -18
- package/packages/pi-tui/dist/components/loader.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +65 -3
- package/packages/pi-tui/src/components/loader.ts +196 -19
- package/pkg/dist/modes/interactive/theme/themes.js +2 -2
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/cancel-job-tool.ts +8 -0
- package/src/resources/extensions/cache-timer/index.ts +102 -96
- package/src/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/src/resources/extensions/codex-rotate/README.md +9 -3
- package/src/resources/extensions/codex-rotate/commands.ts +335 -329
- package/src/resources/extensions/codex-rotate/index.ts +85 -75
- package/src/resources/extensions/memory/auto-extract.ts +330 -204
- package/src/resources/extensions/memory/dream.ts +88 -21
- package/src/resources/extensions/memory/tests/auto-extract.test.ts +200 -144
- package/src/resources/extensions/shared/rtk.js +112 -0
- package/src/resources/extensions/subagent/index.ts +35 -6
|
@@ -1,110 +1,112 @@
|
|
|
1
|
-
import { spawnSync } from
|
|
2
|
-
import { existsSync } from
|
|
3
|
-
import { homedir } from
|
|
4
|
-
import { delimiter, join } from
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
1
|
+
import { spawnSync } from 'node:child_process'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { delimiter, join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
const GSD_RTK_PATH_ENV = 'GSD_RTK_PATH'
|
|
7
|
+
const GSD_RTK_DISABLED_ENV = 'GSD_RTK_DISABLED'
|
|
8
|
+
const GSD_RTK_REWRITE_TIMEOUT_MS_ENV = 'GSD_RTK_REWRITE_TIMEOUT_MS'
|
|
9
|
+
const RTK_TELEMETRY_DISABLED_ENV = 'RTK_TELEMETRY_DISABLED'
|
|
10
|
+
const RTK_REWRITE_TIMEOUT_MS = 5_000
|
|
11
|
+
|
|
10
12
|
function isTruthy(value) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
13
|
+
if (!value) return false
|
|
14
|
+
const normalized = value.trim().toLowerCase()
|
|
15
|
+
return normalized === '1' || normalized === 'true' || normalized === 'yes'
|
|
15
16
|
}
|
|
17
|
+
|
|
16
18
|
function getRewriteTimeoutMs(env = process.env) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
return RTK_REWRITE_TIMEOUT_MS;
|
|
19
|
+
const configured = Number.parseInt(env[GSD_RTK_REWRITE_TIMEOUT_MS_ENV] ?? '', 10)
|
|
20
|
+
if (Number.isFinite(configured) && configured > 0) return configured
|
|
21
|
+
return RTK_REWRITE_TIMEOUT_MS
|
|
22
22
|
}
|
|
23
|
+
|
|
23
24
|
export function isRtkEnabled(env = process.env) {
|
|
24
|
-
|
|
25
|
+
return !isTruthy(env[GSD_RTK_DISABLED_ENV])
|
|
25
26
|
}
|
|
27
|
+
|
|
26
28
|
export function buildRtkEnv(env = process.env) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
return {
|
|
30
|
+
...env,
|
|
31
|
+
[RTK_TELEMETRY_DISABLED_ENV]: '1',
|
|
32
|
+
}
|
|
31
33
|
}
|
|
34
|
+
|
|
32
35
|
function getManagedRtkDir(env = process.env) {
|
|
33
|
-
|
|
36
|
+
return join(env.GSD_HOME || join(homedir(), '.lsd'), 'agent', 'bin')
|
|
34
37
|
}
|
|
38
|
+
|
|
35
39
|
function getRtkBinaryName(platform = process.platform) {
|
|
36
|
-
|
|
40
|
+
return platform === 'win32' ? 'rtk.exe' : 'rtk'
|
|
37
41
|
}
|
|
42
|
+
|
|
38
43
|
function getPathValue(env) {
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === 'path')
|
|
45
|
+
return pathKey ? env[pathKey] : env.PATH
|
|
41
46
|
}
|
|
47
|
+
|
|
42
48
|
function resolvePathCandidates(pathValue) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
.filter(Boolean);
|
|
49
|
+
if (!pathValue) return []
|
|
50
|
+
return pathValue
|
|
51
|
+
.split(delimiter)
|
|
52
|
+
.map((part) => part.trim())
|
|
53
|
+
.filter(Boolean)
|
|
49
54
|
}
|
|
55
|
+
|
|
50
56
|
function resolveSystemRtkPath(pathValue, platform = process.platform) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
}
|
|
57
|
+
const candidates = platform === 'win32'
|
|
58
|
+
? ['rtk.exe', 'rtk.cmd', 'rtk.bat', 'rtk']
|
|
59
|
+
: ['rtk']
|
|
60
|
+
|
|
61
|
+
for (const dir of resolvePathCandidates(pathValue)) {
|
|
62
|
+
for (const candidate of candidates) {
|
|
63
|
+
const fullPath = join(dir, candidate)
|
|
64
|
+
if (existsSync(fullPath)) return fullPath
|
|
61
65
|
}
|
|
62
|
-
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null
|
|
63
69
|
}
|
|
70
|
+
|
|
64
71
|
export function resolveRtkBinaryPath(options = {}) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (existsSync(managedCmd)) {
|
|
81
|
-
return managedCmd;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return resolveSystemRtkPath(options.pathValue ?? getPathValue(env), platform);
|
|
72
|
+
const env = options.env ?? process.env
|
|
73
|
+
const platform = options.platform ?? process.platform
|
|
74
|
+
|
|
75
|
+
const explicitPath = options.binaryPath ?? env[GSD_RTK_PATH_ENV]
|
|
76
|
+
if (explicitPath && existsSync(explicitPath)) return explicitPath
|
|
77
|
+
|
|
78
|
+
const managedDir = getManagedRtkDir(env)
|
|
79
|
+
const managedPath = join(managedDir, getRtkBinaryName(platform))
|
|
80
|
+
if (existsSync(managedPath)) return managedPath
|
|
81
|
+
if (platform === 'win32') {
|
|
82
|
+
const managedCmd = join(managedDir, 'rtk.cmd')
|
|
83
|
+
if (existsSync(managedCmd)) return managedCmd
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return resolveSystemRtkPath(options.pathValue ?? getPathValue(env), platform)
|
|
85
87
|
}
|
|
88
|
+
|
|
86
89
|
export function rewriteCommandWithRtk(command, options = {}) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return rewritten || command;
|
|
90
|
+
const env = options.env ?? process.env
|
|
91
|
+
|
|
92
|
+
if (!command.trim()) return command
|
|
93
|
+
if (!isRtkEnabled(env)) return command
|
|
94
|
+
|
|
95
|
+
const binaryPath = options.binaryPath ?? resolveRtkBinaryPath({ env })
|
|
96
|
+
if (!binaryPath) return command
|
|
97
|
+
|
|
98
|
+
const run = options.spawnSyncImpl ?? spawnSync
|
|
99
|
+
const result = run(binaryPath, ['rewrite', command], {
|
|
100
|
+
encoding: 'utf-8',
|
|
101
|
+
env: buildRtkEnv(env),
|
|
102
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
103
|
+
timeout: getRewriteTimeoutMs(env),
|
|
104
|
+
shell: /\.(cmd|bat)$/i.test(binaryPath),
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
if (result.error) return command
|
|
108
|
+
if (result.status !== 0 && result.status !== 3) return command
|
|
109
|
+
|
|
110
|
+
const rewritten = (result.stdout ?? '').trimEnd()
|
|
111
|
+
return rewritten || command
|
|
110
112
|
}
|
|
@@ -96,7 +96,7 @@ function formatBackgroundSubagentResults(jobs) {
|
|
|
96
96
|
}
|
|
97
97
|
return parts.join("\n\n---\n\n");
|
|
98
98
|
}
|
|
99
|
-
async function awaitBackgroundSubagents(manager, jobIds, timeoutSeconds = DEFAULT_AWAIT_SUBAGENT_TIMEOUT_SECONDS) {
|
|
99
|
+
async function awaitBackgroundSubagents(manager, jobIds, timeoutSeconds = DEFAULT_AWAIT_SUBAGENT_TIMEOUT_SECONDS, signal) {
|
|
100
100
|
const timeoutMs = timeoutSeconds * 1000;
|
|
101
101
|
let watched;
|
|
102
102
|
if (jobIds && jobIds.length > 0) {
|
|
@@ -128,23 +128,40 @@ async function awaitBackgroundSubagents(manager, jobIds, timeoutSeconds = DEFAUL
|
|
|
128
128
|
return formatBackgroundSubagentResults(watched);
|
|
129
129
|
}
|
|
130
130
|
const TIMEOUT_SENTINEL = Symbol("timeout");
|
|
131
|
+
const ABORT_SENTINEL = Symbol("abort");
|
|
131
132
|
const timeoutPromise = new Promise((resolve) => {
|
|
132
133
|
const timer = setTimeout(() => resolve(TIMEOUT_SENTINEL), timeoutMs);
|
|
133
134
|
if (typeof timer === "object" && "unref" in timer)
|
|
134
135
|
timer.unref();
|
|
135
136
|
});
|
|
137
|
+
const abortPromise = signal
|
|
138
|
+
? new Promise((resolve) => {
|
|
139
|
+
if (signal.aborted) {
|
|
140
|
+
resolve(ABORT_SENTINEL);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
signal.addEventListener("abort", () => resolve(ABORT_SENTINEL), { once: true });
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
: null;
|
|
136
147
|
const raceResult = await Promise.race([
|
|
137
148
|
Promise.race(running.map((job) => job.promise)).then(() => "completed"),
|
|
138
149
|
timeoutPromise,
|
|
150
|
+
...(abortPromise ? [abortPromise] : []),
|
|
139
151
|
]);
|
|
140
152
|
const timedOut = raceResult === TIMEOUT_SENTINEL;
|
|
153
|
+
const wasAborted = raceResult === ABORT_SENTINEL;
|
|
141
154
|
const completed = watched.filter((job) => job.status !== "running");
|
|
142
155
|
const stillRunning = watched.filter((job) => job.status === "running");
|
|
143
156
|
let result = formatBackgroundSubagentResults(completed);
|
|
144
157
|
if (stillRunning.length > 0) {
|
|
145
158
|
result += `\n\n**Still running:** ${stillRunning.map((job) => `${job.id} (${job.agentName})`).join(", ")}`;
|
|
146
159
|
}
|
|
147
|
-
if (
|
|
160
|
+
if (wasAborted) {
|
|
161
|
+
result += `\n\n⎋ **Cancelled** — subagents are still running in the background. ` +
|
|
162
|
+
`Use \`await_subagent\` or \`/subagents wait\` again later.`;
|
|
163
|
+
}
|
|
164
|
+
else if (timedOut) {
|
|
148
165
|
result += `\n\n⏱ **Timed out** after ${timeoutSeconds}s waiting for subagents to finish. ` +
|
|
149
166
|
`Subagents are still running in the background. ` +
|
|
150
167
|
`Use \`await_subagent\` or \`/subagents wait\` again later.`;
|
|
@@ -658,10 +675,11 @@ export default function (pi) {
|
|
|
658
675
|
const output = job.status === "completed"
|
|
659
676
|
? (job.resultSummary ?? "(no output)")
|
|
660
677
|
: `Error: ${job.stderr ?? "unknown error"}`;
|
|
678
|
+
const modelInfo = job.model ? ` · ${job.model}` : "";
|
|
661
679
|
pi.sendMessage({
|
|
662
680
|
customType: "background_subagent_result",
|
|
663
681
|
content: [
|
|
664
|
-
`**Background subagent ${statusEmoji}: ${job.id}** (${job.agentName}, ${elapsed}s)`,
|
|
682
|
+
`**Background subagent ${statusEmoji}: ${job.id}** (${job.agentName}, ${elapsed}s${modelInfo})`,
|
|
665
683
|
`> ${taskPreview}`,
|
|
666
684
|
"",
|
|
667
685
|
output,
|
|
@@ -776,7 +794,8 @@ export default function (pi) {
|
|
|
776
794
|
for (const job of running) {
|
|
777
795
|
const elapsed = ((Date.now() - job.startedAt) / 1000).toFixed(0);
|
|
778
796
|
const preview = job.task.length > 50 ? `${job.task.slice(0, 50)}…` : job.task;
|
|
779
|
-
|
|
797
|
+
const modelSuffix = job.model ? ` · ${job.model}` : "";
|
|
798
|
+
lines.push(`- **${job.id}** [${job.agentName}${modelSuffix}] ${elapsed}s — ${preview}`);
|
|
780
799
|
}
|
|
781
800
|
}
|
|
782
801
|
if (done.length > 0) {
|
|
@@ -815,9 +834,9 @@ export default function (pi) {
|
|
|
815
834
|
"Use a shorter timeout when polling and a longer timeout when the user explicitly wants to wait here.",
|
|
816
835
|
],
|
|
817
836
|
parameters: AwaitSubagentParams,
|
|
818
|
-
async execute(_toolCallId, params) {
|
|
837
|
+
async execute(_toolCallId, params, signal) {
|
|
819
838
|
const manager = getBgManager();
|
|
820
|
-
const output = await awaitBackgroundSubagents(manager, params.jobs, params.timeout ?? DEFAULT_AWAIT_SUBAGENT_TIMEOUT_SECONDS);
|
|
839
|
+
const output = await awaitBackgroundSubagents(manager, params.jobs, params.timeout ?? DEFAULT_AWAIT_SUBAGENT_TIMEOUT_SECONDS, signal);
|
|
821
840
|
return {
|
|
822
841
|
content: [{ type: "text", text: output }],
|
|
823
842
|
details: undefined,
|
|
@@ -1047,6 +1066,11 @@ export default function (pi) {
|
|
|
1047
1066
|
isError: true,
|
|
1048
1067
|
};
|
|
1049
1068
|
}
|
|
1069
|
+
// Pre-resolve model so we can show it in the launch message
|
|
1070
|
+
const bgPreferences = loadEffectivePreferences()?.preferences;
|
|
1071
|
+
const bgSettingsBudgetModel = readBudgetSubagentModelFromSettings();
|
|
1072
|
+
const bgResolvedModelCfg = resolveConfiguredSubagentModel(agentForBg, bgPreferences, bgSettingsBudgetModel);
|
|
1073
|
+
const bgInferredModel = resolveSubagentModel({ name: agentForBg.name, model: bgResolvedModelCfg }, { overrideModel: params.model, parentModel: ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined });
|
|
1050
1074
|
let jobId;
|
|
1051
1075
|
try {
|
|
1052
1076
|
jobId = runSubagentInBackground(manager, agents, params.agent, params.task, params.cwd, params.model, { defaultCwd: ctx.cwd, model: ctx.model ? { provider: ctx.model.provider, id: ctx.model.id } : undefined }, async (bgSignal) => {
|
|
@@ -1067,8 +1091,9 @@ export default function (pi) {
|
|
|
1067
1091
|
isError: true,
|
|
1068
1092
|
};
|
|
1069
1093
|
}
|
|
1094
|
+
const bgModelLine = bgInferredModel ? `\nModel: ${bgInferredModel}` : "";
|
|
1070
1095
|
return {
|
|
1071
|
-
content: [{ type: "text", text: `Background subagent started. Job ID: **${jobId}**\nAgent: ${params.agent}\nUse \`await_subagent\` to wait, \`/subagents wait ${jobId}\` to block in the TUI, or \`/subagents cancel ${jobId}\` to stop it.` }],
|
|
1096
|
+
content: [{ type: "text", text: `Background subagent started. Job ID: **${jobId}**\nAgent: ${params.agent}${bgModelLine}\nUse \`await_subagent\` to wait, \`/subagents wait ${jobId}\` to block in the TUI, or \`/subagents cancel ${jobId}\` to stop it.` }],
|
|
1072
1097
|
details: makeDetails("single")([]),
|
|
1073
1098
|
};
|
|
1074
1099
|
}
|
|
@@ -1180,6 +1205,7 @@ export default function (pi) {
|
|
|
1180
1205
|
theme.fg("accent", agentName) +
|
|
1181
1206
|
theme.fg("muted", ` [${scope}]`);
|
|
1182
1207
|
text += `\n ${theme.fg("dim", preview)}`;
|
|
1208
|
+
text += `\n ${theme.fg("muted", "(Ctrl+B to background)")}`;
|
|
1183
1209
|
return new Text(text, 0, 0);
|
|
1184
1210
|
},
|
|
1185
1211
|
renderResult(result, { expanded }, theme) {
|
|
@@ -31,9 +31,19 @@ export function validateConfiguredModel(modelRegistry, settingsManager) {
|
|
|
31
31
|
// Model not configured at all, or removed from registry — pick a fallback.
|
|
32
32
|
// Only fires when the model is genuinely unknown (not just temporarily unavailable).
|
|
33
33
|
const piDefault = getPiDefaultModelAndProvider();
|
|
34
|
-
const preferred = (
|
|
35
|
-
? availableModels.find((m) => m.provider ===
|
|
34
|
+
const preferred = (configuredProvider === 'openai'
|
|
35
|
+
? availableModels.find((m) => m.provider === 'openai' && m.id === 'gpt-5.4') ||
|
|
36
|
+
availableModels.find((m) => m.provider === 'openai' && m.id === 'gpt-5.4-mini') ||
|
|
37
|
+
availableModels.find((m) => m.provider === 'openai')
|
|
36
38
|
: undefined) ||
|
|
39
|
+
(configuredProvider === 'anthropic'
|
|
40
|
+
? availableModels.find((m) => m.provider === 'anthropic' && m.id === 'claude-opus-4-6') ||
|
|
41
|
+
availableModels.find((m) => m.provider === 'anthropic' && m.id.includes('opus')) ||
|
|
42
|
+
availableModels.find((m) => m.provider === 'anthropic')
|
|
43
|
+
: undefined) ||
|
|
44
|
+
(piDefault
|
|
45
|
+
? availableModels.find((m) => m.provider === piDefault.provider && m.id === piDefault.model)
|
|
46
|
+
: undefined) ||
|
|
37
47
|
availableModels.find((m) => m.provider === 'openai' && m.id === 'gpt-5.4') ||
|
|
38
48
|
availableModels.find((m) => m.provider === 'openai' && m.id === 'gpt-5.4-mini') ||
|
|
39
49
|
availableModels.find((m) => m.provider === 'openai') ||
|
package/dist/update-check.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } from 'node
|
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { appRoot } from './app-paths.js';
|
|
5
|
-
import {
|
|
5
|
+
import { execFileSync } from 'node:child_process';
|
|
6
6
|
const CACHE_FILE = join(appRoot, '.update-check');
|
|
7
7
|
const NPM_PACKAGE_NAME = 'lsd-pi';
|
|
8
8
|
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
@@ -186,7 +186,7 @@ export async function checkAndPromptForUpdates(options = {}) {
|
|
|
186
186
|
if (choice === '1') {
|
|
187
187
|
process.stderr.write(`\n ${chalk.dim('Running:')} npm install -g ${NPM_PACKAGE_NAME}@latest\n\n`);
|
|
188
188
|
try {
|
|
189
|
-
|
|
189
|
+
execFileSync('npm', ['install', '-g', `${NPM_PACKAGE_NAME}@latest`], { stdio: 'inherit' });
|
|
190
190
|
process.stderr.write(`\n ${chalk.green.bold(`✓ Updated to v${latestVersion}`)}\n\n`);
|
|
191
191
|
return true;
|
|
192
192
|
}
|
package/dist/update-cmd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import { compareSemver } from './update-check.js';
|
|
3
3
|
const NPM_PACKAGE = 'lsd-pi';
|
|
4
4
|
export async function runUpdate() {
|
|
@@ -13,7 +13,7 @@ export async function runUpdate() {
|
|
|
13
13
|
// Fetch latest version
|
|
14
14
|
let latest;
|
|
15
15
|
try {
|
|
16
|
-
latest =
|
|
16
|
+
latest = execFileSync('npm', ['view', NPM_PACKAGE, 'version'], {
|
|
17
17
|
encoding: 'utf-8',
|
|
18
18
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
19
19
|
}).trim();
|
|
@@ -28,7 +28,7 @@ export async function runUpdate() {
|
|
|
28
28
|
}
|
|
29
29
|
process.stdout.write(`${dim}Updating:${reset} v${current} → ${bold}v${latest}${reset}\n`);
|
|
30
30
|
try {
|
|
31
|
-
|
|
31
|
+
execFileSync('npm', ['install', '-g', `${NPM_PACKAGE}@latest`], {
|
|
32
32
|
stdio: 'inherit',
|
|
33
33
|
});
|
|
34
34
|
process.stdout.write(`\n${green}${bold}Updated to v${latest}${reset}\n`);
|
package/dist/welcome-screen.js
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
import os from 'node:os';
|
|
9
9
|
import chalk from 'chalk';
|
|
10
10
|
import { GSD_LOGO_SEGMENTS } from './logo.js';
|
|
11
|
-
import { brandNameChalk, LSD_BLUE, LSD_PINK, LSD_YELLOW } from './lsd-brand.js';
|
|
12
11
|
import { accentHex } from './cli-theme.js';
|
|
13
12
|
function getShortCwd() {
|
|
14
13
|
const cwd = process.cwd();
|
|
@@ -23,6 +22,28 @@ function visLen(s) {
|
|
|
23
22
|
function rpad(s, w) {
|
|
24
23
|
return s + ' '.repeat(Math.max(0, w - visLen(s)));
|
|
25
24
|
}
|
|
25
|
+
function parseHex(hex) {
|
|
26
|
+
const raw = hex.trim().replace(/^#/, '');
|
|
27
|
+
const full = raw.length === 3 ? raw.split('').map((c) => c + c).join('') : raw;
|
|
28
|
+
if (!/^[0-9a-fA-F]{6}$/.test(full))
|
|
29
|
+
return null;
|
|
30
|
+
return [
|
|
31
|
+
parseInt(full.slice(0, 2), 16),
|
|
32
|
+
parseInt(full.slice(2, 4), 16),
|
|
33
|
+
parseInt(full.slice(4, 6), 16),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
function mixHex(baseHex, tintHex, tintWeight = 0.5) {
|
|
37
|
+
const base = parseHex(baseHex);
|
|
38
|
+
const tint = parseHex(tintHex);
|
|
39
|
+
if (!base || !tint)
|
|
40
|
+
return baseHex;
|
|
41
|
+
const w = Math.min(1, Math.max(0, tintWeight));
|
|
42
|
+
const mix = (a, b) => Math.round(a * (1 - w) + b * w);
|
|
43
|
+
const [r, g, b] = [mix(base[0], tint[0]), mix(base[1], tint[1]), mix(base[2], tint[2])];
|
|
44
|
+
const toHex = (n) => n.toString(16).padStart(2, '0');
|
|
45
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
46
|
+
}
|
|
26
47
|
export function printWelcomeScreen(opts) {
|
|
27
48
|
if (!process.stderr.isTTY)
|
|
28
49
|
return;
|
|
@@ -31,26 +52,34 @@ export function printWelcomeScreen(opts) {
|
|
|
31
52
|
const termWidth = Math.min((process.stderr.columns || 80) - 1, 200);
|
|
32
53
|
// Narrow terminal fallback
|
|
33
54
|
if (termWidth < 70) {
|
|
34
|
-
process.stderr.write(`\n
|
|
55
|
+
process.stderr.write(`\n Looks Sort of Done v${version}\n ${shortCwd}\n\n`);
|
|
35
56
|
return;
|
|
36
57
|
}
|
|
37
|
-
// ──
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const PINK = LSD_PINK;
|
|
58
|
+
// ── Theme-adaptive palette ───────────────────────────────────────────────
|
|
59
|
+
// Keep welcome colors anchored to the active CLI theme accent so the banner
|
|
60
|
+
// feels native regardless of custom themes.
|
|
41
61
|
const ACCENT = accentHex();
|
|
62
|
+
const LOGO_EDGE = chalk.hex(mixHex(ACCENT, '#111111', 0.55));
|
|
63
|
+
const LOGO_CENTER = chalk.hex(mixHex(ACCENT, '#ffffff', 0.3));
|
|
64
|
+
const TITLE_BASE = chalk.bold;
|
|
65
|
+
const TITLE_MARK = chalk.hex(mixHex(ACCENT, '#ffffff', 0.35)).bold;
|
|
66
|
+
const VERSION = chalk.dim;
|
|
67
|
+
const META = chalk.dim;
|
|
68
|
+
const TOOLS = chalk.dim;
|
|
42
69
|
// ── Panel widths ────────────────────────────────────────────────────────────
|
|
43
70
|
// Layout: 1 leading space + LEFT_INNER logo content + 1 inner divider + RIGHT_INNER info
|
|
44
71
|
// Total: 1 + LEFT_INNER + 1 + RIGHT_INNER = termWidth
|
|
45
72
|
const LEFT_INNER = 34;
|
|
46
73
|
const RIGHT_INNER = termWidth - LEFT_INNER - 2; // 2 = leading space + inner divider
|
|
47
74
|
// ── Bar/divider chars (matching GLYPH.separator + widget ui.bar() style) ────
|
|
48
|
-
const H = '─'
|
|
75
|
+
const H = '─';
|
|
76
|
+
const DV = '│';
|
|
77
|
+
const DS = '├';
|
|
49
78
|
// ── Left rows: blank + 6 logo lines + blank (8 total) ───────────────────────
|
|
50
79
|
const leftRows = [null, ...GSD_LOGO_SEGMENTS, null];
|
|
51
80
|
// ── Right rows (8 total, null = divider) ────────────────────────────────────
|
|
52
|
-
const titleLeft = ` ${
|
|
53
|
-
const titleRight =
|
|
81
|
+
const titleLeft = ` ${TITLE_MARK('L')}${TITLE_BASE('ooks Sort of ')}${TITLE_MARK('D')}${TITLE_BASE('one')}`;
|
|
82
|
+
const titleRight = VERSION(`v${version}`);
|
|
54
83
|
const titleFill = RIGHT_INNER - visLen(titleLeft) - visLen(titleRight);
|
|
55
84
|
const titleRow = titleLeft + ' '.repeat(Math.max(1, titleFill)) + titleRight;
|
|
56
85
|
const toolParts = [];
|
|
@@ -65,15 +94,15 @@ export function printWelcomeScreen(opts) {
|
|
|
65
94
|
if (process.env.CONTEXT7_API_KEY)
|
|
66
95
|
toolParts.push('Context7 ✓');
|
|
67
96
|
// Tools summary row
|
|
68
|
-
const toolsLeft = toolParts.length > 0 ?
|
|
97
|
+
const toolsLeft = toolParts.length > 0 ? TOOLS(' ' + toolParts.join(' · ')) : '';
|
|
69
98
|
const footerRow = rpad(toolsLeft, RIGHT_INNER);
|
|
70
99
|
const DIVIDER = null;
|
|
71
100
|
const rightRows = [
|
|
72
101
|
titleRow,
|
|
73
102
|
DIVIDER,
|
|
74
|
-
modelName ? ` Model ${
|
|
75
|
-
provider ? ` Provider ${
|
|
76
|
-
` Directory ${
|
|
103
|
+
modelName ? ` Model ${META(modelName)}` : '',
|
|
104
|
+
provider ? ` Provider ${META(provider)}` : '',
|
|
105
|
+
` Directory ${META(shortCwd)}`,
|
|
77
106
|
DIVIDER,
|
|
78
107
|
footerRow,
|
|
79
108
|
'',
|
|
@@ -85,7 +114,7 @@ export function printWelcomeScreen(opts) {
|
|
|
85
114
|
for (let i = 0; i < 8; i++) {
|
|
86
115
|
const row = leftRows[i];
|
|
87
116
|
const lContent = row
|
|
88
|
-
? rpad(
|
|
117
|
+
? rpad(LOGO_EDGE(row[0]) + LOGO_CENTER(row[1]) + LOGO_EDGE(row[2]), LEFT_INNER)
|
|
89
118
|
: ' '.repeat(LEFT_INNER);
|
|
90
119
|
const rRow = rightRows[i];
|
|
91
120
|
if (rRow === null) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lsd-pi",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "LSD —
|
|
3
|
+
"version": "1.1.6",
|
|
4
|
+
"description": "LSD — Looks Sort of Done coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
"@gsd-build/engine-linux-arm64-gnu": ">=2.10.2",
|
|
141
141
|
"@gsd-build/engine-linux-x64-gnu": ">=2.10.2",
|
|
142
142
|
"@gsd-build/engine-win32-x64-msvc": ">=2.10.2",
|
|
143
|
+
"@lydell/node-pty": "^1.2.0-beta.3",
|
|
143
144
|
"fsevents": "~2.3.3",
|
|
144
145
|
"koffi": "^2.9.0"
|
|
145
146
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session.clear-queue.test.d.ts","sourceRoot":"","sources":["../../src/core/agent-session.clear-queue.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it, mock } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { AgentSession } from "./agent-session.js";
|
|
4
|
+
describe("AgentSession.clearQueue", () => {
|
|
5
|
+
it("avoids duplicate queued prompts when session and agent queues mirror the same user message", () => {
|
|
6
|
+
const clearAllQueues = mock.fn(() => { });
|
|
7
|
+
const fakeSession = {
|
|
8
|
+
_steeringMessages: ["make it in the main accent color"],
|
|
9
|
+
_followUpMessages: [],
|
|
10
|
+
agent: {
|
|
11
|
+
drainUserMessages: () => ({
|
|
12
|
+
steering: [{ role: "user", content: [{ type: "text", text: "make it in the main accent color" }] }],
|
|
13
|
+
followUp: [],
|
|
14
|
+
}),
|
|
15
|
+
clearAllQueues,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
const result = AgentSession.prototype.clearQueue.call(fakeSession);
|
|
19
|
+
assert.deepEqual(result, {
|
|
20
|
+
steering: ["make it in the main accent color"],
|
|
21
|
+
followUp: [],
|
|
22
|
+
});
|
|
23
|
+
assert.deepEqual(fakeSession._steeringMessages, []);
|
|
24
|
+
assert.deepEqual(fakeSession._followUpMessages, []);
|
|
25
|
+
assert.equal(clearAllQueues.mock.callCount(), 1);
|
|
26
|
+
});
|
|
27
|
+
it("keeps extra preserved messages that are not present in session-tracked arrays", () => {
|
|
28
|
+
const fakeSession = {
|
|
29
|
+
_steeringMessages: ["first"],
|
|
30
|
+
_followUpMessages: [],
|
|
31
|
+
agent: {
|
|
32
|
+
drainUserMessages: () => ({
|
|
33
|
+
steering: [
|
|
34
|
+
{ role: "user", content: [{ type: "text", text: "first" }] },
|
|
35
|
+
{ role: "user", content: [{ type: "text", text: "second" }] },
|
|
36
|
+
],
|
|
37
|
+
followUp: [],
|
|
38
|
+
}),
|
|
39
|
+
clearAllQueues: () => { },
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const result = AgentSession.prototype.clearQueue.call(fakeSession);
|
|
43
|
+
assert.deepEqual(result.steering, ["first", "second"]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=agent-session.clear-queue.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-session.clear-queue.test.js","sourceRoot":"","sources":["../../src/core/agent-session.clear-queue.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,4FAA4F,EAAE,GAAG,EAAE;QACrG,MAAM,cAAc,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG;YACnB,iBAAiB,EAAE,CAAC,kCAAkC,CAAC;YACvD,iBAAiB,EAAE,EAAE;YACrB,KAAK,EAAE;gBACN,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC;oBACzB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kCAAkC,EAAE,CAAC,EAAE,CAAC;oBACnG,QAAQ,EAAE,EAAE;iBACZ,CAAC;gBACF,cAAc;aACd;SACM,CAAC;QAET,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEnE,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE;YACxB,QAAQ,EAAE,CAAC,kCAAkC,CAAC;YAC9C,QAAQ,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACxF,MAAM,WAAW,GAAG;YACnB,iBAAiB,EAAE,CAAC,OAAO,CAAC;YAC5B,iBAAiB,EAAE,EAAE;YACrB,KAAK,EAAE;gBACN,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC;oBACzB,QAAQ,EAAE;wBACT,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE;wBAC5D,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE;qBAC7D;oBACD,QAAQ,EAAE,EAAE;iBACZ,CAAC;gBACF,cAAc,EAAE,GAAG,EAAE,GAAE,CAAC;aACxB;SACM,CAAC;QAET,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACnE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { describe, it, mock } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { AgentSession } from \"./agent-session.js\";\n\ndescribe(\"AgentSession.clearQueue\", () => {\n\tit(\"avoids duplicate queued prompts when session and agent queues mirror the same user message\", () => {\n\t\tconst clearAllQueues = mock.fn(() => {});\n\t\tconst fakeSession = {\n\t\t\t_steeringMessages: [\"make it in the main accent color\"],\n\t\t\t_followUpMessages: [],\n\t\t\tagent: {\n\t\t\t\tdrainUserMessages: () => ({\n\t\t\t\t\tsteering: [{ role: \"user\", content: [{ type: \"text\", text: \"make it in the main accent color\" }] }],\n\t\t\t\t\tfollowUp: [],\n\t\t\t\t}),\n\t\t\t\tclearAllQueues,\n\t\t\t},\n\t\t} as any;\n\n\t\tconst result = AgentSession.prototype.clearQueue.call(fakeSession);\n\n\t\tassert.deepEqual(result, {\n\t\t\tsteering: [\"make it in the main accent color\"],\n\t\t\tfollowUp: [],\n\t\t});\n\t\tassert.deepEqual(fakeSession._steeringMessages, []);\n\t\tassert.deepEqual(fakeSession._followUpMessages, []);\n\t\tassert.equal(clearAllQueues.mock.callCount(), 1);\n\t});\n\n\tit(\"keeps extra preserved messages that are not present in session-tracked arrays\", () => {\n\t\tconst fakeSession = {\n\t\t\t_steeringMessages: [\"first\"],\n\t\t\t_followUpMessages: [],\n\t\t\tagent: {\n\t\t\t\tdrainUserMessages: () => ({\n\t\t\t\t\tsteering: [\n\t\t\t\t\t\t{ role: \"user\", content: [{ type: \"text\", text: \"first\" }] },\n\t\t\t\t\t\t{ role: \"user\", content: [{ type: \"text\", text: \"second\" }] },\n\t\t\t\t\t],\n\t\t\t\t\tfollowUp: [],\n\t\t\t\t}),\n\t\t\t\tclearAllQueues: () => {},\n\t\t\t},\n\t\t} as any;\n\n\t\tconst result = AgentSession.prototype.clearQueue.call(fakeSession);\n\t\tassert.deepEqual(result.steering, [\"first\", \"second\"]);\n\t});\n});\n"]}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import type { Agent, AgentEvent, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@gsd/pi-agent-core";
|
|
16
16
|
import type { ImageContent, Model, TextContent } from "@gsd/pi-ai";
|
|
17
17
|
import { type BashResult } from "./bash-executor.js";
|
|
18
|
+
import { type PtyExecutionSession } from "./pty-executor.js";
|
|
18
19
|
import { type CompactionResult } from "./compaction/index.js";
|
|
19
20
|
import { type ContextUsage, type ExtensionCommandContextActions, type ExtensionErrorListener, ExtensionRunner, type ExtensionUIContext, type InputSource, type ShutdownHandler, type ToolDefinition, type ToolInfo } from "./extensions/index.js";
|
|
20
21
|
import type { CustomMessage } from "./messages.js";
|
|
@@ -548,6 +549,13 @@ export declare class AgentSession {
|
|
|
548
549
|
operations?: BashOperations;
|
|
549
550
|
loginShell?: boolean;
|
|
550
551
|
}): Promise<BashResult>;
|
|
552
|
+
executeBashInteractive(command: string, options?: {
|
|
553
|
+
onChunk?: (chunk: string) => void;
|
|
554
|
+
cols?: number;
|
|
555
|
+
rows?: number;
|
|
556
|
+
loginShell?: boolean;
|
|
557
|
+
}): Promise<PtyExecutionSession>;
|
|
558
|
+
clearBashAbortController(): void;
|
|
551
559
|
/**
|
|
552
560
|
* Record a bash execution result in session history.
|
|
553
561
|
* Used by executeBash and by extensions that handle bash execution themselves.
|