fix(cli): restore shipped surface capabilities

This commit is contained in:
Turtle
2026-07-29 21:15:48 +08:00
parent bee0a77aad
commit 857a4941be
13 files changed
+133 -54

No files matched your search

+2 -17
View File
@@ -213,27 +213,12 @@ Examples:
resolved = resolveWeb(options)
})
// `--resume` is NOT redeclared here: an option a subcommand shares with its
// parent parses into `program.opts()` and leaves the subcommand's own options
// empty, so redeclaring it would silently drop the id. Commander therefore
// omits it from this subcommand's option list, hence the trailing help text.
program
.command('meta')
.description('work on the dsh source that runs this command, from any directory')
.addHelpText('after', '\nAccepts --resume <id> to resume a persisted session from this checkout.\n')
.action(() => {
// Commander parses the parent (default-surface) options on either side of
// the subcommand into `program.opts()`. `meta` accepts only `--resume`, so
// a leaked `--config`/`-p` is a mistyped invocation that must fail loud
// rather than silently be dropped.
const parent = program.opts<{ config?: string; configReplace?: string; prompt?: string; resume?: string }>()
if (parent.config !== undefined || parent.configReplace !== undefined || parent.prompt !== undefined) {
program.error('error: meta takes none of --config, --config-replace, or -p/--prompt')
}
// Same reason as the default surface: an empty id would start a fresh
// session downstream instead of failing the mistyped resume.
if (parent.resume === '') program.error('error: --resume needs a session id')
resolved = { mode: 'meta', ...parent.resume !== undefined && { resume: parent.resume } }
rejectParentOptions('meta')
resolved = { mode: 'meta' }
})
try {
+7 -5
View File
@@ -18,7 +18,7 @@
*/
import { randomUUID } from 'node:crypto'
import { join } from 'node:path'
import { join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import {
addHarnessSourceSection,
@@ -155,6 +155,8 @@ export async function runTui(
// selected session may belong to another workspace, so the handoff also enters
// that directory. The host is offered only when Node exposes `process.execve`
// and knows its own entry.
const resolvedConfig = config === undefined ? undefined : resolve(config)
const resolvedConfigReplace = configReplace === undefined ? undefined : resolve(configReplace)
const entry = process.argv[1]
const execve = process.execve?.bind(process)
const app: { current?: Context } = {}
@@ -172,8 +174,8 @@ export async function runTui(
`--resume=${sessionId}`,
// Both config flags must survive the handoff: resuming into a different
// tree than the session was created in would silently change the agent.
...config !== undefined ? ['--config', config] : [],
...configReplace !== undefined ? ['--config-replace', configReplace] : [],
...resolvedConfig !== undefined ? ['--config', resolvedConfig] : [],
...resolvedConfigReplace !== undefined ? ['--config-replace', resolvedConfigReplace] : [],
]
// Mint the fresh id here rather than in the app bundle: the exit line names
// the session to resume, so the launcher must know it before the tree boots.
@@ -223,11 +225,11 @@ export async function runTui(
...loadOverlayPatches(NAME, TUI_OVERLAY),
...config === undefined
? loadPersonalPatches(NAME) ?? []
: loadOverlayPatches(NAME, resolveConfigPath(config, undefined)),
: loadOverlayPatches(NAME, resolveConfigPath(resolve(config), undefined)),
]
const ctx = await boot(
NAME,
replaceTree ? resolveConfigPath(configReplace, undefined) : BASE_CONFIG,
replaceTree ? resolveConfigPath(resolve(configReplace), undefined) : BASE_CONFIG,
patches,
(hostCtx) => {
// The launcher owns session identity and the exit line: a config-mounted