fix(setup): isolate scratch agent with hardcoded _ping-test folder

- Scratch agent uses fixed folder `_ping-test` so it can never collide
  with a real agent on re-runs
- Added --folder flag to init-cli-agent.ts and cli-agent step wrapper
- Delete always targets `_ping-test` exactly — no re-derivation needed
- Removed normalizeName coupling and FOLDER status field (no longer needed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gabi-simons
2026-04-29 14:45:42 +00:00
committed by exe.dev user
parent 8c5d67cc78
commit 8542c484f6
4 changed files with 24 additions and 13 deletions
+4 -3
View File
@@ -1,9 +1,10 @@
/** /**
* Delete the scratch CLI agent created during setup's ping-pong test. * Delete the scratch CLI agent created during setup's ping-pong test.
* *
* Removes the agent group, its messaging_group_agents wiring, any * Dynamically finds and removes all rows referencing the agent group
* agent_destinations rows, and the groups/<folder>/ directory. Leaves the * (any table with an agent_group_id column), deletes the agent group
* CLI messaging group intact so it can be reused for a new agent. * itself, and removes the groups/<folder>/ directory. Leaves the CLI
* messaging group intact so it can be reused for a new agent.
* *
* Usage: * Usage:
* pnpm exec tsx scripts/delete-cli-agent.ts --folder <folder-name> * pnpm exec tsx scripts/delete-cli-agent.ts --folder <folder-name>
+7 -1
View File
@@ -41,11 +41,13 @@ const CLI_SYNTHETIC_USER_ID = `${CLI_CHANNEL}:${CLI_PLATFORM_ID}`;
interface Args { interface Args {
displayName: string; displayName: string;
agentName: string; agentName: string;
folder?: string;
} }
function parseArgs(argv: string[]): Args { function parseArgs(argv: string[]): Args {
let displayName: string | undefined; let displayName: string | undefined;
let agentName: string | undefined; let agentName: string | undefined;
let folder: string | undefined;
for (let i = 0; i < argv.length; i++) { for (let i = 0; i < argv.length; i++) {
const key = argv[i]; const key = argv[i];
const val = argv[i + 1]; const val = argv[i + 1];
@@ -55,6 +57,9 @@ function parseArgs(argv: string[]): Args {
} else if (key === '--agent-name') { } else if (key === '--agent-name') {
agentName = val; agentName = val;
i++; i++;
} else if (key === '--folder') {
folder = val;
i++;
} }
} }
@@ -67,6 +72,7 @@ function parseArgs(argv: string[]): Args {
return { return {
displayName, displayName,
agentName: agentName?.trim() || displayName, agentName: agentName?.trim() || displayName,
folder,
}; };
} }
@@ -95,7 +101,7 @@ async function main(): Promise<void> {
const promotedToOwner = false; const promotedToOwner = false;
// 2. Agent group + filesystem. // 2. Agent group + filesystem.
const folder = `cli-with-${normalizeName(args.displayName)}`; const folder = args.folder || `cli-with-${normalizeName(args.displayName)}`;
let ag: AgentGroup | undefined = getAgentGroupByFolder(folder); let ag: AgentGroup | undefined = getAgentGroupByFolder(folder);
if (!ag) { if (!ag) {
const agId = generateId('ag'); const agId = generateId('ag');
+2 -3
View File
@@ -351,7 +351,7 @@ async function main(): Promise<void> {
running: 'Preparing connection test…', running: 'Preparing connection test…',
done: 'Ready to test.', done: 'Ready to test.',
}, },
['--display-name', displayName!, '--agent-name', CLI_AGENT_NAME], ['--display-name', displayName!, '--agent-name', CLI_AGENT_NAME, '--folder', '_ping-test'],
); );
if (!res.ok) { if (!res.ok) {
await fail( await fail(
@@ -372,8 +372,7 @@ async function main(): Promise<void> {
const ping = await confirmAssistantResponds(); const ping = await confirmAssistantResponds();
if (ping === 'ok') { if (ping === 'ok') {
phEmit('first_chat_ready'); phEmit('first_chat_ready');
const scratchFolder = res.terminal?.fields.FOLDER ?? ''; spawnSync('pnpm', ['exec', 'tsx', 'scripts/delete-cli-agent.ts', '--folder', '_ping-test'], {
spawnSync('pnpm', ['exec', 'tsx', 'scripts/delete-cli-agent.ts', '--folder', scratchFolder], {
stdio: 'ignore', stdio: 'ignore',
}); });
const next = ensureAnswer( const next = ensureAnswer(
+11 -6
View File
@@ -8,6 +8,7 @@
* Args: * Args:
* --display-name <name> (required) operator's display name * --display-name <name> (required) operator's display name
* --agent-name <name> (optional) agent persona name, defaults to display-name * --agent-name <name> (optional) agent persona name, defaults to display-name
* --folder <name> (optional) explicit folder name, defaults to cli-with-<normalized-display-name>
*/ */
import { execFileSync } from 'child_process'; import { execFileSync } from 'child_process';
import path from 'path'; import path from 'path';
@@ -18,9 +19,11 @@ import { emitStatus } from './status.js';
function parseArgs(args: string[]): { function parseArgs(args: string[]): {
displayName: string; displayName: string;
agentName?: string; agentName?: string;
folder?: string;
} { } {
let displayName: string | undefined; let displayName: string | undefined;
let agentName: string | undefined; let agentName: string | undefined;
let folder: string | undefined;
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
const key = args[i]; const key = args[i];
@@ -34,6 +37,10 @@ function parseArgs(args: string[]): {
agentName = val; agentName = val;
i++; i++;
break; break;
case '--folder':
folder = val;
i++;
break;
} }
} }
@@ -46,23 +53,23 @@ function parseArgs(args: string[]): {
process.exit(2); process.exit(2);
} }
return { displayName, agentName }; return { displayName, agentName, folder };
} }
export async function run(args: string[]): Promise<void> { export async function run(args: string[]): Promise<void> {
const { displayName, agentName } = parseArgs(args); const { displayName, agentName, folder } = parseArgs(args);
const projectRoot = process.cwd(); const projectRoot = process.cwd();
const script = path.join(projectRoot, 'scripts', 'init-cli-agent.ts'); const script = path.join(projectRoot, 'scripts', 'init-cli-agent.ts');
const scriptArgs = ['exec', 'tsx', script, '--display-name', displayName]; const scriptArgs = ['exec', 'tsx', script, '--display-name', displayName];
if (agentName) scriptArgs.push('--agent-name', agentName); if (agentName) scriptArgs.push('--agent-name', agentName);
if (folder) scriptArgs.push('--folder', folder);
log.info('Invoking init-cli-agent', { displayName, agentName }); log.info('Invoking init-cli-agent', { displayName, agentName });
let stdout = '';
try { try {
stdout = execFileSync('pnpm', scriptArgs, { execFileSync('pnpm', scriptArgs, {
cwd: projectRoot, cwd: projectRoot,
stdio: ['ignore', 'pipe', 'pipe'], stdio: ['ignore', 'pipe', 'pipe'],
encoding: 'utf-8', encoding: 'utf-8',
@@ -83,11 +90,9 @@ export async function run(args: string[]): Promise<void> {
process.exit(1); process.exit(1);
} }
const folderMatch = stdout.match(/@ groups\/(\S+)/);
emitStatus('CLI_AGENT', { emitStatus('CLI_AGENT', {
DISPLAY_NAME: displayName, DISPLAY_NAME: displayName,
AGENT_NAME: agentName || displayName, AGENT_NAME: agentName || displayName,
FOLDER: folderMatch?.[1] ?? '',
CHANNEL: 'cli/local', CHANNEL: 'cli/local',
STATUS: 'success', STATUS: 'success',
LOG: 'logs/setup.log', LOG: 'logs/setup.log',