feat(setup): clarify setup flow from user-feedback session
- Container step: duration hint + 3-line rolling output window with 60s stall detector that offers "keep waiting" vs "ask Claude" - First chat: reframed as a try-out with sandbox-model explainer (wakes on message, sleeps when idle, context persists) - Timezone: auto-detected non-UTC zones now get an explicit confirm from the user instead of silent persist - Outro: added always-on warning + prominent "check your DM" banner when a channel was configured; directive last line - Discord: always show token-location reminder even when user says they have one; new "do you have a server?" branch walks through server creation if not - All select prompts: custom brightSelect renderer keeps inactive option labels at full brightness (was dim gray); adds @clack/core as a direct dep Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -102,12 +102,19 @@ export class StatusStream {
|
||||
* raw log file (level 3) and parsed for status blocks (level 2 summary).
|
||||
* The onBlock callback fires per status block as they close so the UI can
|
||||
* react mid-stream.
|
||||
*
|
||||
* `onLine`, if provided, fires for every line from stdout + stderr (minus
|
||||
* status-block control lines) so callers can render a rolling tail. Status
|
||||
* block lines are still parsed by the `StatusStream` — they're just
|
||||
* excluded from the line feed so they don't fill the user-facing window
|
||||
* with `=== NANOCLAW SETUP: …` noise.
|
||||
*/
|
||||
export function spawnStep(
|
||||
stepName: string,
|
||||
extra: string[],
|
||||
onBlock: (block: Block) => void,
|
||||
rawLogPath: string,
|
||||
onLine?: (line: string) => void,
|
||||
): Promise<StepResult> {
|
||||
return new Promise((resolve) => {
|
||||
const args = ['exec', 'tsx', 'setup/index.ts', '--step', stepName];
|
||||
@@ -118,13 +125,34 @@ export function spawnStep(
|
||||
const raw = fs.createWriteStream(rawLogPath, { flags: 'w' });
|
||||
raw.write(`# ${stepName} — ${new Date().toISOString()}\n\n`);
|
||||
|
||||
// Per-line forwarder for the optional onLine callback. We keep our own
|
||||
// buffer (separate from StatusStream's) so the parser still gets raw
|
||||
// chunks and isn't forced through a line-by-line path it doesn't need.
|
||||
let lineBuf = '';
|
||||
const pushLines = (chunk: string): void => {
|
||||
if (!onLine) return;
|
||||
lineBuf += chunk;
|
||||
let idx: number;
|
||||
while ((idx = lineBuf.indexOf('\n')) !== -1) {
|
||||
const line = lineBuf.slice(0, idx).replace(/\r/g, '');
|
||||
lineBuf = lineBuf.slice(idx + 1);
|
||||
if (line.startsWith('=== NANOCLAW SETUP:')) continue;
|
||||
if (line.startsWith('=== END ===')) continue;
|
||||
if (line.trim()) onLine(line);
|
||||
}
|
||||
};
|
||||
|
||||
child.stdout.on('data', (chunk: Buffer) => {
|
||||
stream.write(chunk.toString('utf-8'));
|
||||
const s = chunk.toString('utf-8');
|
||||
stream.write(s);
|
||||
raw.write(chunk);
|
||||
pushLines(s);
|
||||
});
|
||||
child.stderr.on('data', (chunk: Buffer) => {
|
||||
stream.transcript += chunk.toString('utf-8');
|
||||
const s = chunk.toString('utf-8');
|
||||
stream.transcript += s;
|
||||
raw.write(chunk);
|
||||
pushLines(s);
|
||||
});
|
||||
|
||||
child.on('close', (code) => {
|
||||
|
||||
Reference in New Issue
Block a user