@buildaharness/aielia 0.3.8 → 0.3.9
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 +6 -3
- package/dist/action-approval-service.d.ts +2 -0
- package/dist/ask-draft.d.ts +22 -0
- package/dist/assistant-options.d.ts +35 -0
- package/dist/assistant-session.d.ts +1 -1
- package/dist/{bin-DETwedpj.js → bin-CCwDFxDe.js} +118 -247
- package/dist/bin-CCwDFxDe.js.map +1 -0
- package/dist/cli-config.d.ts +2 -2
- package/dist/cli-session.d.ts +2 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1 -1
- package/dist/commands.d.ts +32 -0
- package/dist/config-keys.d.ts +43 -0
- package/dist/doctor-checks.d.ts +1 -2
- package/dist/fact-extraction.d.ts +4 -0
- package/dist/goal-graph-store.d.ts +6 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +199 -148
- package/dist/index.js.map +1 -1
- package/dist/llm-client-factory.d.ts +13 -0
- package/dist/memory-service.d.ts +2 -0
- package/dist/model-pricing.d.ts +12 -9
- package/dist/node-display-names.d.ts +1 -1
- package/dist/project-command.d.ts +16 -0
- package/dist/{provider-setup-wX2IBw2X.js → provider-setup-Cy9dwqrd.js} +13504 -13034
- package/dist/provider-setup-Cy9dwqrd.js.map +1 -0
- package/dist/proxy-health.d.ts +8 -0
- package/dist/redact-url.d.ts +2 -0
- package/dist/reply-audit.d.ts +2 -0
- package/dist/response-service.d.ts +10 -0
- package/dist/run-explain.d.ts +58 -0
- package/dist/{tui-app-CcxiwZyM.js → tui-app-Dt72u8vZ.js} +3 -3
- package/dist/{tui-app-CcxiwZyM.js.map → tui-app-Dt72u8vZ.js.map} +1 -1
- package/dist/turn-cost.d.ts +12 -0
- package/dist/turn-presentation.d.ts +86 -0
- package/dist/undo-action-command.d.ts +12 -0
- package/dist/undo-plan.d.ts +13 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/bin-DETwedpj.js.map +0 -1
- package/dist/provider-setup-wX2IBw2X.js.map +0 -1
|
@@ -7,8 +7,8 @@ import { createInterface } from "node:readline";
|
|
|
7
7
|
import { rename, stat, realpath, readdir, mkdir, unlink, writeFile, readFile } from "node:fs/promises";
|
|
8
8
|
import { homedir, tmpdir } from "node:os";
|
|
9
9
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
10
|
-
import { OPENROUTER_DEFAULT_MODEL, OPENAI_DEFAULT_MODEL, ANTHROPIC_DEFAULT_MODEL, InMemoryReminderStore, FileSystemAdapter, FileSystemExperienceStore
|
|
11
|
-
import {
|
|
10
|
+
import { OPENROUTER_DEFAULT_MODEL, OPENAI_DEFAULT_MODEL, ANTHROPIC_DEFAULT_MODEL, InMemoryReminderStore, FileSystemAdapter, FileSystemExperienceStore } from "@buildaharness/runtime";
|
|
11
|
+
import { af as buildClaudePrompt, co as stripJsonCodeFence, c2 as recallToolEnabled, bw as lexicalOffEnvValue, a as ALREADY_STAGED_ACTION_TOOL, cn as stagedActionInput, bT as parseClaudeCliOutput, cp as stripMcpToolPrefix, bE as memoryStatusChecks, bR as normalizePlanNodes, V as PROVIDER_SETUP, ao as cleanApiKey, ah as checkApiKeyFormat, aG as envOverridesFromProcessEnv, c6 as resolveConfig, cl as shouldLaunchTuiApp, t as DEFAULT_TUI_MODE, a8 as applyLayerSettings, cj as sanitizeLayerChoices, cu as testApiKey, cx as validateConfig, aW as findInvalidNumericSettings, f as ConfigValidationError, be as formatSpendCapStatus, br as isPlanGraphEnabled, X as PersonalAssistant, ae as buildAssistantOptions, cq as stripTerminalControls, bn as isGoalGraphEnabled, b$ as planToSnapshot, ar as createLlmClient, au as createSmtpSender, at as createResendSender, aZ as formatConfigListing, bm as isConfigKey, e as CONFIG_KEYS, x as ENV_VAR_FOR_CONFIG_KEY, bU as parseConfigValue, g as ConfigValueParseError, ai as checkProxyHealth, a$ as formatDoctorReport, a_ as formatCostSummary, bW as parseProjectCommand, b1 as formatGoalGraphState, bd as formatSearchResults, b6 as formatMemoryHistory, b9 as formatMemoryStatus, b8 as formatMemoryPendingOutcome, b4 as formatMemoryArchive, bY as parseUndoActionCommand, bh as formatUndoLogListing, c0 as planUndo, ax as defaultExportFilename, bg as formatTranscriptMarkdown, aj as classifyError, bf as formatStatus, b2 as formatHelp, aS as explainSteps, aR as explainSources, aP as explainLayers, b3 as formatLayerListing, cA as withLayerChoice, O as LayerSettingError, aT as explainWhy, bt as isQuitCommand, P as LiveSteeringChannel, ay as defaultMemoryExportFilename, b5 as formatMemoryExport, bD as memoryAuditLogEnabled, ba as formatMemorySummary, aa as approvalLabels, U as NO_TRACE, R as MISSING_PLAN_APPROVAL_ID_REASON, c1 as presentTurnResult, bb as formatNextSteps, aQ as explainPlan, bH as nodeToLayer, L as LAYER_DISPLAY_NAME, bG as nodeDisplayName, j as DEFAULT_CLARIFICATION_REASON, aE as emptyDraft, aC as draftToAnswer, bS as orderedOptions, cz as withCostEstimate, C as CLI_FEATURES, ad as braveSearch } from "./provider-setup-Cy9dwqrd.js";
|
|
12
12
|
import { spawn } from "node:child_process";
|
|
13
13
|
import { createServer, connect } from "node:net";
|
|
14
14
|
import { createRequire } from "node:module";
|
|
@@ -129,7 +129,7 @@ function createNodeFsBackend() {
|
|
|
129
129
|
}
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
-
const CLI_VERSION = "0.3.
|
|
132
|
+
const CLI_VERSION = "0.3.9";
|
|
133
133
|
function seaCacheDir(version, home = homedir()) {
|
|
134
134
|
return join(home, ".buildaharness", "personal-assistant", "sea-cache", version);
|
|
135
135
|
}
|
|
@@ -699,22 +699,6 @@ class NodeConfigStore {
|
|
|
699
699
|
}
|
|
700
700
|
}
|
|
701
701
|
const DOCTOR_CHECK_TIMEOUT_MS = 3e3;
|
|
702
|
-
async function checkProxyHealth(proxyUrl) {
|
|
703
|
-
const label = `proxy reachable (${redactUrlCredentials(proxyUrl)}/health)`;
|
|
704
|
-
const controller = new AbortController();
|
|
705
|
-
const timeout = setTimeout(() => controller.abort(), DOCTOR_CHECK_TIMEOUT_MS);
|
|
706
|
-
try {
|
|
707
|
-
const res = await fetch(`${proxyUrl}/health`, { signal: controller.signal });
|
|
708
|
-
if (!res.ok) return { label, ok: false, detail: `HTTP ${res.status}` };
|
|
709
|
-
const body = await res.json().catch(() => void 0);
|
|
710
|
-
return (body == null ? void 0 : body.status) === "ok" ? { label, ok: true } : { label, ok: false, detail: "unexpected response body" };
|
|
711
|
-
} catch (err) {
|
|
712
|
-
const timedOut = err instanceof Error && err.name === "AbortError";
|
|
713
|
-
return { label, ok: false, detail: timedOut ? "timed out" : err instanceof Error ? err.message : String(err) };
|
|
714
|
-
} finally {
|
|
715
|
-
clearTimeout(timeout);
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
702
|
function checkClaudeCli(claudePath) {
|
|
719
703
|
const label = `claude binary (${claudePath})`;
|
|
720
704
|
return new Promise((resolvePromise) => {
|
|
@@ -3475,81 +3459,45 @@ function buildEmailSender(config) {
|
|
|
3475
3459
|
return void 0;
|
|
3476
3460
|
}
|
|
3477
3461
|
function buildLlmClient(config, workspaceRoot, remindersFile) {
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
case "anthropic":
|
|
3488
|
-
return new AnthropicLLMClient({ apiKey: config.apiKey ?? "" });
|
|
3489
|
-
case "openai":
|
|
3490
|
-
return new OpenAICompatibleLLMClient({ apiKey: config.apiKey ?? "", baseUrl: OPENAI_BASE_URL, defaultModel: OPENAI_DEFAULT_MODEL });
|
|
3491
|
-
case "openrouter":
|
|
3492
|
-
return new OpenAICompatibleLLMClient({
|
|
3493
|
-
apiKey: config.apiKey ?? "",
|
|
3494
|
-
baseUrl: OPENROUTER_BASE_URL,
|
|
3495
|
-
defaultModel: OPENROUTER_DEFAULT_MODEL,
|
|
3496
|
-
extraHeaders: OPENROUTER_EXTRA_HEADERS
|
|
3497
|
-
});
|
|
3498
|
-
case "proxy":
|
|
3499
|
-
return new LLMClient({ proxyUrl: config.proxyUrl, authToken: config.authToken });
|
|
3500
|
-
}
|
|
3462
|
+
return createLlmClient(config, {
|
|
3463
|
+
claudeCli: () => new ClaudeCliLLMClient({
|
|
3464
|
+
fileTools: { workspaceRoot },
|
|
3465
|
+
remindersFile,
|
|
3466
|
+
shellTools: config.enableShell ? { workspaceRoot } : void 0,
|
|
3467
|
+
webTools: config.enableWeb ? { braveApiKey: config.braveApiKey } : void 0,
|
|
3468
|
+
actionTools: config.enableEmail ? { workspaceRoot } : void 0
|
|
3469
|
+
})
|
|
3470
|
+
});
|
|
3501
3471
|
}
|
|
3502
3472
|
async function buildAssistant(config, { backend, dataDir, remindersFile }) {
|
|
3503
3473
|
const workspaceRoot = config.workspaceRoot ?? process.cwd();
|
|
3504
3474
|
if (backend === defaultBackend) excludeAieliaStateFromGit(workspaceRoot);
|
|
3505
3475
|
const search = (query) => braveSearch(query, config.braveApiKey);
|
|
3506
3476
|
const llmClient = buildLlmClient(config, workspaceRoot, remindersFile);
|
|
3507
|
-
return PersonalAssistant.create(
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
return sendEmail ? { backend, workspaceRoot, sendEmail } : void 0;
|
|
3532
|
-
})(),
|
|
3533
|
-
dangerouslySkipPermissions: config.dangerouslySkipPermissions,
|
|
3534
|
-
// Opt-in durable record of tool calls/results and approvals (see activity-log.ts).
|
|
3535
|
-
onDebugLog: activityLogEnabled(process.env) ? createActivityLogger(join(dataDir, "activity-log.jsonl")) : void 0,
|
|
3536
|
-
spendCap: config.sessionCostLimitUsd !== void 0 || config.sessionCallLimit !== void 0 ? { sessionCostLimitUsd: config.sessionCostLimitUsd, sessionCallLimit: config.sessionCallLimit } : void 0,
|
|
3537
|
-
// Resolved through the shared config seam (cli-config.ts's envOverridesFromProcessEnv reads
|
|
3538
|
-
// ASSISTANT_ONE_LOOP into config.oneLoopMode; /config set oneLoopMode persists it) so the CLI,
|
|
3539
|
-
// chat-ui, and the Tauri desktop build all decide this the same way. Undefined here means
|
|
3540
|
-
// PersonalAssistant falls back to DEFAULT_ONE_LOOP_MODE.
|
|
3541
|
-
oneLoopMode: config.oneLoopMode,
|
|
3542
|
-
layerPolicyMode: config.layerPolicyMode,
|
|
3543
|
-
// R7: turn-end next-step options and DONE-thread suggestions. Undefined config means the
|
|
3544
|
-
// package default (enabled); PersonalAssistant itself defaults to disabled, so this is where
|
|
3545
|
-
// the front end opts in.
|
|
3546
|
-
goalGraphSuggestMode: isGoalGraphSuggestEnabled(config.goalGraphSuggestMode) ? "enabled" : "disabled",
|
|
3547
|
-
// P11 of the internal plan — resolved through the same shared config
|
|
3548
|
-
// seam as oneLoopMode above (ASSISTANT_PLAN_MODE / `/config set planMode`). Undefined here
|
|
3549
|
-
// means PersonalAssistant falls back to DEFAULT_PLAN_MODE ('legacy').
|
|
3550
|
-
planMode: config.planMode,
|
|
3551
|
-
ambiguityGuardMode: config.ambiguityGuardMode
|
|
3552
|
-
});
|
|
3477
|
+
return PersonalAssistant.create(
|
|
3478
|
+
buildAssistantOptions(config, {
|
|
3479
|
+
llmClient,
|
|
3480
|
+
workspaceRoot,
|
|
3481
|
+
features: CLI_FEATURES,
|
|
3482
|
+
memory: new FileSystemAdapter({ backend, baseDir: dataDir, namespace: "transcripts" }),
|
|
3483
|
+
experienceStore: await FileSystemExperienceStore.create({ backend, baseDir: dataDir, namespace: "experience" }),
|
|
3484
|
+
checkpointStore: new FileSystemAdapter({ backend, baseDir: dataDir, namespace: "checkpoints" }),
|
|
3485
|
+
reminderStore: new InMemoryReminderStore(new FileSystemAdapter({ backend, baseDir: dataDir, namespace: "reminders" })),
|
|
3486
|
+
fileTools: { backend, workspaceRoot },
|
|
3487
|
+
webTools: config.enableWeb ? { search } : void 0,
|
|
3488
|
+
// executeCommand is the real child_process.spawn-based implementation (shell-executor.ts) —
|
|
3489
|
+
// wired in here, not inside assistant.ts, so the browser build never needs node:child_process.
|
|
3490
|
+
shellTools: config.enableShell ? { backend, workspaceRoot, timeoutMs: config.shellTimeoutMs, networkAllowlist: config.shellNetworkAllowlist, executeCommand: runApprovedShellCommand } : void 0,
|
|
3491
|
+
// The Resend/SMTP transport is wired in here, not inside assistant.ts, so the browser build
|
|
3492
|
+
// never needs nodemailer or a mail server — same split as shellTools' executeCommand.
|
|
3493
|
+
actionTools: (() => {
|
|
3494
|
+
const sendEmail = buildEmailSender(config);
|
|
3495
|
+
return sendEmail ? { backend, workspaceRoot, sendEmail } : void 0;
|
|
3496
|
+
})(),
|
|
3497
|
+
// Opt-in durable record of tool calls/results and approvals (see activity-log.ts).
|
|
3498
|
+
onDebugLog: activityLogEnabled(process.env) ? createActivityLogger(join(dataDir, "activity-log.jsonl")) : void 0
|
|
3499
|
+
})
|
|
3500
|
+
);
|
|
3553
3501
|
}
|
|
3554
3502
|
async function runCli(options = {}) {
|
|
3555
3503
|
const dataDir = options.dataDir ?? defaultDataDir;
|
|
@@ -3651,6 +3599,7 @@ Fix it by setting the missing value (in the config file under ${dataDir}, or via
|
|
|
3651
3599
|
rl.prompt();
|
|
3652
3600
|
let lastTrace;
|
|
3653
3601
|
let lastSources;
|
|
3602
|
+
let lastAnswerClaim;
|
|
3654
3603
|
let lastPlanStatus;
|
|
3655
3604
|
let pendingPlanApproval;
|
|
3656
3605
|
let lastTurnUsage;
|
|
@@ -3663,33 +3612,17 @@ Fix it by setting the missing value (in the config file under ${dataDir}, or via
|
|
|
3663
3612
|
{ key: "a", label: "Yes, don't ask again this session" },
|
|
3664
3613
|
{ key: "n", label: "No" }
|
|
3665
3614
|
];
|
|
3666
|
-
function
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
}
|
|
3671
|
-
const PLAN_TASK_STATUS_ICON = {
|
|
3672
|
-
PENDING: "○",
|
|
3673
|
-
RUNNING: "▶",
|
|
3674
|
-
COMPLETE: "✓",
|
|
3675
|
-
FAILED: "✗",
|
|
3676
|
-
BLOCKED: "✗",
|
|
3677
|
-
HUMAN_REQUIRED: "~"
|
|
3678
|
-
};
|
|
3679
|
-
function printPlan() {
|
|
3615
|
+
function priceUsage(usage) {
|
|
3616
|
+
return withCostEstimate(usage, { backend: config.llmBackend, model: config.model });
|
|
3617
|
+
}
|
|
3618
|
+
function printPlan(goalGraph) {
|
|
3680
3619
|
if (!lastPlanStatus) {
|
|
3681
|
-
printSafe(
|
|
3620
|
+
printSafe(`
|
|
3621
|
+
${explainPlan({ ...lastTurnExplainInput(), goalGraph }).join("\n")}
|
|
3622
|
+
`);
|
|
3682
3623
|
return;
|
|
3683
3624
|
}
|
|
3684
|
-
const lines = [
|
|
3685
|
-
PLAN_LINE_PREFIX,
|
|
3686
|
-
`Plan: ${lastPlanStatus.templateName ?? "custom plan"} (${lastPlanStatus.completionPct.toFixed(1)}% complete)`,
|
|
3687
|
-
...lastPlanStatus.tasks.flatMap((task) => [
|
|
3688
|
-
` ${PLAN_TASK_STATUS_ICON[task.status] ?? "?"} [${task.status}] ${task.id} — ${task.description}`,
|
|
3689
|
-
...task.note ? [` not accepted as done: ${task.note}`] : []
|
|
3690
|
-
]),
|
|
3691
|
-
`Success criteria: ${lastPlanStatus.successCriteria}`
|
|
3692
|
-
];
|
|
3625
|
+
const lines = [PLAN_LINE_PREFIX, ...explainPlan(lastTurnExplainInput())];
|
|
3693
3626
|
console.log(stripTerminalControls(`
|
|
3694
3627
|
${lines.join("\n")}
|
|
3695
3628
|
`));
|
|
@@ -3704,7 +3637,7 @@ ${lines.join("\n")}
|
|
|
3704
3637
|
const result = await assistant.sketchPlan("cli", request);
|
|
3705
3638
|
console.log(stripTerminalControls(`Aielia> ${result.reply ?? "(no reply)"}
|
|
3706
3639
|
`));
|
|
3707
|
-
if (result.usage) lastTurnUsage =
|
|
3640
|
+
if (result.usage) lastTurnUsage = priceUsage(result.usage);
|
|
3708
3641
|
}
|
|
3709
3642
|
const PLAN_APPROVAL_OPTIONS = [
|
|
3710
3643
|
{ key: "y", label: "Approve" },
|
|
@@ -3769,7 +3702,7 @@ ${lines.join("\n")}
|
|
|
3769
3702
|
}
|
|
3770
3703
|
pendingPlanApproval = void 0;
|
|
3771
3704
|
lastTrace = void 0;
|
|
3772
|
-
lastNoTraceReason =
|
|
3705
|
+
lastNoTraceReason = NO_TRACE.planApproval(decision === "decline" ? "declined" : "approved");
|
|
3773
3706
|
await handleTurn(message, false, void 0, void 0, void 0, id, decision, edits);
|
|
3774
3707
|
}
|
|
3775
3708
|
async function loadPlanGraphNodes(live, threadId) {
|
|
@@ -3837,86 +3770,38 @@ ${result.lines.join("\n")}
|
|
|
3837
3770
|
printPlanApproval(pendingPlanApproval.snapshot);
|
|
3838
3771
|
return;
|
|
3839
3772
|
}
|
|
3840
|
-
printPlan();
|
|
3773
|
+
printPlan(lastPlanStatus ? void 0 : await assistant.getGoalGraphState("cli"));
|
|
3841
3774
|
}
|
|
3842
|
-
function
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
return `Batch: ${batchBudget.itemCount} items — ${found} found, ${notFound} not found, ${truncated} truncated (${batchBudget.totalCallsUsed} calls used, projected ~${Math.ceil(batchBudget.projectedTotal)})`;
|
|
3775
|
+
function lastTurnExplainInput() {
|
|
3776
|
+
return {
|
|
3777
|
+
trace: lastTrace,
|
|
3778
|
+
noTraceReason: lastNoTraceReason,
|
|
3779
|
+
answerClaim: lastAnswerClaim,
|
|
3780
|
+
memoryInjection: assistant.getLastMemoryInjection(),
|
|
3781
|
+
sources: lastSources,
|
|
3782
|
+
toolSteps: lastTurnToolSteps,
|
|
3783
|
+
planStatus: lastPlanStatus
|
|
3784
|
+
};
|
|
3853
3785
|
}
|
|
3854
3786
|
function printWhy() {
|
|
3855
|
-
const memoryLine = formatMemoryInjection(assistant.getLastMemoryInjection());
|
|
3856
|
-
if (!lastTrace) {
|
|
3857
|
-
printSafe(`
|
|
3858
|
-
${lastNoTraceReason ?? "No harness trace for the last turn (nothing to explain yet, or it took the fast path)."}
|
|
3859
|
-
${memoryLine}
|
|
3860
|
-
`);
|
|
3861
|
-
return;
|
|
3862
|
-
}
|
|
3863
3787
|
printSafe(`
|
|
3864
|
-
${
|
|
3865
|
-
|
|
3866
|
-
if (chain.length > 0) {
|
|
3867
|
-
printSafe(" " + chain.map((item) => `${LAYER_SHORT_CODE[item.layer]} (${item.reason})`).join(" > "));
|
|
3868
|
-
}
|
|
3869
|
-
if (lastTrace.batchBudget) {
|
|
3870
|
-
printSafe(" " + batchBudgetSummaryLine(lastTrace.batchBudget));
|
|
3871
|
-
}
|
|
3872
|
-
printSafe(memoryLine);
|
|
3873
|
-
printSafe("");
|
|
3788
|
+
${explainWhy(lastTurnExplainInput()).join("\n")}
|
|
3789
|
+
`);
|
|
3874
3790
|
}
|
|
3875
3791
|
function printLayers() {
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
${lastNoTraceReason ?? "No harness trace for the last turn (nothing to explain yet, or it took the fast path)."}
|
|
3792
|
+
printSafe(`
|
|
3793
|
+
${explainLayers(lastTurnExplainInput()).join("\n")}
|
|
3879
3794
|
`);
|
|
3880
|
-
return;
|
|
3881
|
-
}
|
|
3882
|
-
printSafe("");
|
|
3883
|
-
const byLayer = new Map(lastTrace.layerActivity.map((e) => [e.layer, e]));
|
|
3884
|
-
for (const layer of LAYER_ORDER) {
|
|
3885
|
-
const e = byLayer.get(layer);
|
|
3886
|
-
const mark = (e == null ? void 0 : e.fired) ? "✓" : "·";
|
|
3887
|
-
const reason = (e == null ? void 0 : e.reason) ?? "not evaluated this turn";
|
|
3888
|
-
printSafe(` [${mark}] ${LAYER_DISPLAY_NAME[layer].padEnd(22)} ${reason}`);
|
|
3889
|
-
}
|
|
3890
|
-
if (lastTrace.batchBudget) {
|
|
3891
|
-
printSafe("");
|
|
3892
|
-
printSafe(` ${batchBudgetSummaryLine(lastTrace.batchBudget)}`);
|
|
3893
|
-
const STATUS_MARK = {
|
|
3894
|
-
found: "✓",
|
|
3895
|
-
not_found: "✗",
|
|
3896
|
-
truncated_while_productive: "~"
|
|
3897
|
-
};
|
|
3898
|
-
for (const outcome of lastTrace.batchBudget.perItemOutcomes) {
|
|
3899
|
-
printSafe(` [${STATUS_MARK[outcome.status]}] ${outcome.item.padEnd(30)} ${outcome.status} (${outcome.callsUsed} calls)`);
|
|
3900
|
-
}
|
|
3901
|
-
}
|
|
3902
|
-
printSafe("");
|
|
3903
3795
|
}
|
|
3904
|
-
const SOURCE_TOOL_LABEL = {
|
|
3905
|
-
read_file: "Read",
|
|
3906
|
-
list_directory: "Listed",
|
|
3907
|
-
web_search: "Searched",
|
|
3908
|
-
fetch_url: "Fetched"
|
|
3909
|
-
};
|
|
3910
3796
|
function printSources() {
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
printSafe("");
|
|
3797
|
+
printSafe(`
|
|
3798
|
+
${explainSources(lastTurnExplainInput()).join("\n")}
|
|
3799
|
+
`);
|
|
3800
|
+
}
|
|
3801
|
+
function printSteps() {
|
|
3802
|
+
printSafe(`
|
|
3803
|
+
${explainSteps(lastTurnExplainInput()).join("\n")}
|
|
3804
|
+
`);
|
|
3920
3805
|
}
|
|
3921
3806
|
function printHelp() {
|
|
3922
3807
|
printSafe(`
|
|
@@ -3991,12 +3876,12 @@ ${formatStatus({ config, overriddenKeys, transcriptLength: transcript.length, pl
|
|
|
3991
3876
|
}
|
|
3992
3877
|
}
|
|
3993
3878
|
async function handleUndo() {
|
|
3994
|
-
const
|
|
3995
|
-
if (
|
|
3879
|
+
const plan = planUndo(await assistant.getTranscript("cli"));
|
|
3880
|
+
if (plan.nothingToUndo) {
|
|
3996
3881
|
printSafe("\nNothing to undo.\n");
|
|
3997
3882
|
return;
|
|
3998
3883
|
}
|
|
3999
|
-
const wasPendingApproval =
|
|
3884
|
+
const { wasPendingApproval } = plan;
|
|
4000
3885
|
const undoneReminders = lastTurnToolSteps.filter((s) => s.tool === "create_reminder");
|
|
4001
3886
|
const result = await assistant.undoLastTurn("cli");
|
|
4002
3887
|
if (!result.undone) {
|
|
@@ -4015,14 +3900,15 @@ ${formatStatus({ config, overriddenKeys, transcriptLength: transcript.length, pl
|
|
|
4015
3900
|
);
|
|
4016
3901
|
}
|
|
4017
3902
|
async function handleUndoAction(args) {
|
|
4018
|
-
|
|
3903
|
+
const command = parseUndoActionCommand(args);
|
|
3904
|
+
if (command.kind === "list") {
|
|
4019
3905
|
const entries = await assistant.listUndoLogEntries();
|
|
4020
3906
|
printSafe(`
|
|
4021
3907
|
${formatUndoLogListing(entries)}
|
|
4022
3908
|
`);
|
|
4023
3909
|
return;
|
|
4024
3910
|
}
|
|
4025
|
-
const staged = await assistant.stageUndoAction(
|
|
3911
|
+
const staged = await assistant.stageUndoAction(command.id);
|
|
4026
3912
|
if (staged.status === "error") {
|
|
4027
3913
|
printSafe(`
|
|
4028
3914
|
✗ ${staged.message}
|
|
@@ -4033,7 +3919,7 @@ ${formatUndoLogListing(entries)}
|
|
|
4033
3919
|
[needs approval — revert] ${staged.reason}`));
|
|
4034
3920
|
const confirmed = await askYesNo("Apply this revert? (y/N) ");
|
|
4035
3921
|
lastTrace = void 0;
|
|
4036
|
-
lastNoTraceReason =
|
|
3922
|
+
lastNoTraceReason = NO_TRACE.stagedAction("revert", confirmed ? "approved" : "declined");
|
|
4037
3923
|
await handleTurn("", confirmed, staged.pendingActionId);
|
|
4038
3924
|
}
|
|
4039
3925
|
async function printMemory() {
|
|
@@ -4252,24 +4138,8 @@ ${formatDoctorReport(checks)}
|
|
|
4252
4138
|
}
|
|
4253
4139
|
lastTurnToolSteps.push(step);
|
|
4254
4140
|
}
|
|
4255
|
-
function emptyClarificationDraft() {
|
|
4256
|
-
return { selectedLabels: [], editText: "", freeText: "" };
|
|
4257
|
-
}
|
|
4258
|
-
function orderedAskOptions(question) {
|
|
4259
|
-
const options2 = question.options ?? [];
|
|
4260
|
-
return options2.map((option, index) => ({ option, index })).sort((a, b) => Number(b.option.recommended ?? false) - Number(a.option.recommended ?? false) || a.index - b.index).map(({ option }) => option);
|
|
4261
|
-
}
|
|
4262
|
-
function clarificationDraftToAnswer(questionId, draft) {
|
|
4263
|
-
if (draft.selectedLabels.length > 0) {
|
|
4264
|
-
return draft.editText.trim() ? { questionId, kind: "selected_with_edit", selectedLabels: draft.selectedLabels, editText: draft.editText.trim() } : { questionId, kind: "selected", selectedLabels: draft.selectedLabels };
|
|
4265
|
-
}
|
|
4266
|
-
if (draft.freeText.trim()) {
|
|
4267
|
-
return { questionId, kind: "free_text", freeText: draft.freeText.trim() };
|
|
4268
|
-
}
|
|
4269
|
-
return null;
|
|
4270
|
-
}
|
|
4271
4141
|
function printClarificationQuestion(question, draft, index, total) {
|
|
4272
|
-
const options2 =
|
|
4142
|
+
const options2 = orderedOptions(question);
|
|
4273
4143
|
const allowFreeText = question.allowFreeText !== false;
|
|
4274
4144
|
printSafe("");
|
|
4275
4145
|
if (question.header) console.log(stripTerminalControls(`[${question.header}]`));
|
|
@@ -4299,9 +4169,10 @@ ${formatDoctorReport(checks)}
|
|
|
4299
4169
|
const pendingClarificationId = result.pendingClarificationId;
|
|
4300
4170
|
if (questions.length === 0 || !pendingClarificationId) {
|
|
4301
4171
|
lastTrace = void 0;
|
|
4302
|
-
|
|
4172
|
+
const unanswerable = presentTurnResult(result);
|
|
4173
|
+
lastNoTraceReason = unanswerable.noTraceReason;
|
|
4303
4174
|
console.log(stripTerminalControls(`
|
|
4304
|
-
[needs clarification] ${
|
|
4175
|
+
[needs clarification] ${unanswerable.kind === "escalation" ? unanswerable.reason : DEFAULT_CLARIFICATION_REASON}
|
|
4305
4176
|
`));
|
|
4306
4177
|
return;
|
|
4307
4178
|
}
|
|
@@ -4318,7 +4189,7 @@ ${formatDoctorReport(checks)}
|
|
|
4318
4189
|
}
|
|
4319
4190
|
printSafe(`
|
|
4320
4191
|
[needs clarification] ${questions.length} question${questions.length === 1 ? "" : "s"} to answer.`);
|
|
4321
|
-
const drafts = new Map(questions.map((q2) => [q2.id,
|
|
4192
|
+
const drafts = new Map(questions.map((q2) => [q2.id, emptyDraft()]));
|
|
4322
4193
|
let index = 0;
|
|
4323
4194
|
while (true) {
|
|
4324
4195
|
const question = questions[index];
|
|
@@ -4333,7 +4204,7 @@ ${formatDoctorReport(checks)}
|
|
|
4333
4204
|
return;
|
|
4334
4205
|
}
|
|
4335
4206
|
if (lower === "s" || lower === "submit") {
|
|
4336
|
-
const answers = questions.map((q2) =>
|
|
4207
|
+
const answers = questions.map((q2) => draftToAnswer(q2.id, drafts.get(q2.id)));
|
|
4337
4208
|
const missing = questions.filter((q2, i) => answers[i] === null);
|
|
4338
4209
|
if (missing.length > 0) {
|
|
4339
4210
|
printSafe(`
|
|
@@ -4368,7 +4239,7 @@ Still need an answer for: ${missing.map((q2) => q2.question).join("; ")}
|
|
|
4368
4239
|
}
|
|
4369
4240
|
const editMatch = /^e(\d+)$/i.exec(token);
|
|
4370
4241
|
if (editMatch) {
|
|
4371
|
-
const options2 =
|
|
4242
|
+
const options2 = orderedOptions(question);
|
|
4372
4243
|
const option = options2[Number(editMatch[1]) - 1];
|
|
4373
4244
|
if (!option) {
|
|
4374
4245
|
printSafe(`
|
|
@@ -4388,7 +4259,7 @@ Select option ${editMatch[1]} first, then add a note with e${editMatch[1]}.
|
|
|
4388
4259
|
}
|
|
4389
4260
|
const toggleMatch = /^t(\d+)$/i.exec(token) ?? /^(\d+)$/.exec(token);
|
|
4390
4261
|
if (toggleMatch) {
|
|
4391
|
-
const options2 =
|
|
4262
|
+
const options2 = orderedOptions(question);
|
|
4392
4263
|
const option = options2[Number(toggleMatch[1]) - 1];
|
|
4393
4264
|
if (!option) {
|
|
4394
4265
|
printSafe(`
|
|
@@ -4459,8 +4330,7 @@ Unrecognized input "${token}".
|
|
|
4459
4330
|
});
|
|
4460
4331
|
if (!streamedAnyTokens) clearProgress();
|
|
4461
4332
|
if (result.status === "needs_approval" && result.pendingActionId) {
|
|
4462
|
-
const kindLabel
|
|
4463
|
-
const promptText = result.pendingActionKind === "shell" ? "Run this command?" : result.pendingActionKind === "email" ? "Send this email?" : result.pendingActionKind === "batch" ? "Continue?" : "Apply this write?";
|
|
4333
|
+
const { kindLabel, promptText } = approvalLabels(result.pendingActionKind);
|
|
4464
4334
|
console.log(stripTerminalControls(`
|
|
4465
4335
|
[needs approval — ${kindLabel}] ${result.reason}`));
|
|
4466
4336
|
let confirmed;
|
|
@@ -4473,7 +4343,7 @@ Unrecognized input "${token}".
|
|
|
4473
4343
|
if (decision === "a" && result.pendingActionKind) rememberedActionKinds.add(result.pendingActionKind);
|
|
4474
4344
|
}
|
|
4475
4345
|
lastTrace = void 0;
|
|
4476
|
-
lastNoTraceReason =
|
|
4346
|
+
lastNoTraceReason = NO_TRACE.stagedAction(kindLabel, confirmed ? "approved" : "declined");
|
|
4477
4347
|
await handleTurn(message, confirmed, result.pendingActionId);
|
|
4478
4348
|
return;
|
|
4479
4349
|
}
|
|
@@ -4494,7 +4364,7 @@ Unrecognized input "${token}".
|
|
|
4494
4364
|
await handleTurn(message, true);
|
|
4495
4365
|
} else {
|
|
4496
4366
|
lastTrace = void 0;
|
|
4497
|
-
lastNoTraceReason = "
|
|
4367
|
+
lastNoTraceReason = NO_TRACE.messageApproval("declined");
|
|
4498
4368
|
await assistant.recordDeclinedRequest("cli", message, result.reason ?? "This request needed approval.");
|
|
4499
4369
|
printSafe("Cancelled.\n");
|
|
4500
4370
|
}
|
|
@@ -4507,7 +4377,7 @@ Unrecognized input "${token}".
|
|
|
4507
4377
|
if (result.status === "needs_plan_approval") {
|
|
4508
4378
|
if (!result.planApprovalId) {
|
|
4509
4379
|
printSafe(`
|
|
4510
|
-
[needs plan approval] ${result.reason ??
|
|
4380
|
+
[needs plan approval] ${result.reason ?? MISSING_PLAN_APPROVAL_ID_REASON}
|
|
4511
4381
|
`);
|
|
4512
4382
|
return;
|
|
4513
4383
|
}
|
|
@@ -4518,7 +4388,7 @@ ${result.reason}`);
|
|
|
4518
4388
|
if (snapshot) printPlanApproval(snapshot);
|
|
4519
4389
|
pendingPlanApproval = { id, message, snapshot };
|
|
4520
4390
|
lastTrace = void 0;
|
|
4521
|
-
lastNoTraceReason =
|
|
4391
|
+
lastNoTraceReason = NO_TRACE.planApproval(void 0, " (pending /plan approve|decline|edit)");
|
|
4522
4392
|
if (!snapshot) {
|
|
4523
4393
|
printSafe("Decide with /plan approve or /plan decline.\n");
|
|
4524
4394
|
return;
|
|
@@ -4541,44 +4411,48 @@ ${result.reason}`);
|
|
|
4541
4411
|
} else {
|
|
4542
4412
|
decision = "decline";
|
|
4543
4413
|
}
|
|
4544
|
-
lastNoTraceReason =
|
|
4414
|
+
lastNoTraceReason = NO_TRACE.planApproval(decision === "decline" ? "declined" : "approved");
|
|
4545
4415
|
await handleTurn(message, false, void 0, void 0, void 0, id, decision, edits);
|
|
4546
4416
|
return;
|
|
4547
4417
|
}
|
|
4548
4418
|
if (result.status === "escalated") {
|
|
4549
4419
|
lastTrace = void 0;
|
|
4550
|
-
|
|
4420
|
+
const escalation = presentTurnResult(result);
|
|
4421
|
+
lastNoTraceReason = escalation.noTraceReason;
|
|
4551
4422
|
console.log(stripTerminalControls(`
|
|
4552
|
-
[escalated] ${result.reason}
|
|
4423
|
+
[escalated] ${escalation.kind === "escalation" ? escalation.reason : result.reason}
|
|
4553
4424
|
`));
|
|
4554
4425
|
return;
|
|
4555
4426
|
}
|
|
4556
4427
|
if (!pendingActionId) {
|
|
4557
4428
|
lastTrace = result.harnessSkipped ? void 0 : result.trace;
|
|
4558
|
-
|
|
4429
|
+
lastAnswerClaim = result.answerClaim;
|
|
4430
|
+
lastNoTraceReason = result.harnessSkipped ? NO_TRACE.fastPath : void 0;
|
|
4559
4431
|
}
|
|
4560
4432
|
lastSources = result.sources;
|
|
4561
4433
|
if (!pendingActionId && (!result.harnessSkipped || result.planStatus)) lastPlanStatus = result.planStatus;
|
|
4562
|
-
lastTurnUsage = result.usage ?
|
|
4434
|
+
lastTurnUsage = result.usage ? priceUsage(result.usage) : void 0;
|
|
4435
|
+
const shown = presentTurnResult(result);
|
|
4436
|
+
const hints = shown.kind === "reply" ? shown.hints : {};
|
|
4563
4437
|
const riskSuffix = result.riskLevel && result.riskLevel !== "LOW" ? ` [risk: ${result.riskLevel}]` : "";
|
|
4564
|
-
const sourcesHint =
|
|
4565
|
-
const planHint =
|
|
4566
|
-
const contradictionNotice =
|
|
4438
|
+
const sourcesHint = hints.sourcesCount ? ` (${hints.sourcesCount} source${hints.sourcesCount > 1 ? "s" : ""} — /sources)` : "";
|
|
4439
|
+
const planHint = hints.planCompletionPct !== void 0 ? ` (plan: ${hints.planCompletionPct.toFixed(0)}% — /plan)` : "";
|
|
4440
|
+
const contradictionNotice = hints.contradictionNotice ? `
|
|
4567
4441
|
|
|
4568
|
-
${
|
|
4569
|
-
const reviewNotice = (
|
|
4442
|
+
${hints.contradictionNotice}` : "";
|
|
4443
|
+
const reviewNotice = (hints.reviewNotice ? `
|
|
4570
4444
|
|
|
4571
|
-
${
|
|
4445
|
+
${hints.reviewNotice}` : "") + (hints.auditNotice ? `
|
|
4572
4446
|
|
|
4573
|
-
${
|
|
4574
|
-
lastNextSteps =
|
|
4447
|
+
${hints.auditNotice}` : "");
|
|
4448
|
+
lastNextSteps = hints.nextSteps;
|
|
4575
4449
|
const nextStepsBlock = lastNextSteps ? `
|
|
4576
4450
|
|
|
4577
4451
|
${formatNextSteps(lastNextSteps)}` : "";
|
|
4578
4452
|
if (streamedAnyTokens) {
|
|
4579
|
-
const pausedNoteText =
|
|
4453
|
+
const pausedNoteText = hints.pausedNote ? `
|
|
4580
4454
|
|
|
4581
|
-
${
|
|
4455
|
+
${hints.pausedNote}` : "";
|
|
4582
4456
|
process.stdout.write(stripTerminalControls(`${pausedNoteText}${riskSuffix}${sourcesHint}${planHint}${contradictionNotice}${reviewNotice}${nextStepsBlock}
|
|
4583
4457
|
|
|
4584
4458
|
`));
|
|
@@ -4800,17 +4674,12 @@ ${config.model ?? "(using each backend's default)"}
|
|
|
4800
4674
|
await handleConfigCommand(["set", "model", args.join(" ")]);
|
|
4801
4675
|
}
|
|
4802
4676
|
async function handleProject(args) {
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
${
|
|
4677
|
+
const command = parseProjectCommand(args, assistant.getActiveProject());
|
|
4678
|
+
if (command.kind === "show") printSafe(`
|
|
4679
|
+
${command.message}
|
|
4806
4680
|
`);
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
if (args[0] === "clear") {
|
|
4810
|
-
await handleConfigCommand(["reset", "activeProject"]);
|
|
4811
|
-
return;
|
|
4812
|
-
}
|
|
4813
|
-
await handleConfigCommand(["set", "activeProject", args.join(" ")]);
|
|
4681
|
+
else if (command.kind === "clear") await handleConfigCommand(["reset", "activeProject"]);
|
|
4682
|
+
else await handleConfigCommand(["set", "activeProject", command.project]);
|
|
4814
4683
|
}
|
|
4815
4684
|
let turnInProgress = false;
|
|
4816
4685
|
let lastNextSteps;
|
|
@@ -4820,6 +4689,7 @@ ${assistant.getActiveProject() || "(none)"}
|
|
|
4820
4689
|
// Bare /layers is the last-turn fired/skipped view; its subcommands (settings/on/off/reset) edit the on/off choices.
|
|
4821
4690
|
"/layers": (args) => args.length === 0 ? printLayers() : handleLayers(args),
|
|
4822
4691
|
"/sources": () => printSources(),
|
|
4692
|
+
"/steps": () => printSteps(),
|
|
4823
4693
|
"/plan": (args) => handlePlan(args),
|
|
4824
4694
|
"/help": () => printHelp(),
|
|
4825
4695
|
"/clear": () => handleClear(),
|
|
@@ -4909,6 +4779,7 @@ ${assistant.getActiveProject() || "(none)"}
|
|
|
4909
4779
|
});
|
|
4910
4780
|
rl.resume();
|
|
4911
4781
|
return {
|
|
4782
|
+
commandNames: Object.keys(commands),
|
|
4912
4783
|
dispatchLine: async (line) => {
|
|
4913
4784
|
const message = line.trim();
|
|
4914
4785
|
if (!message) return;
|
|
@@ -4972,7 +4843,7 @@ async function mainInner(argv) {
|
|
|
4972
4843
|
});
|
|
4973
4844
|
}
|
|
4974
4845
|
if (shouldLaunchTuiApp(config.tuiMode ?? DEFAULT_TUI_MODE, Boolean(process.stdout.isTTY), Boolean(process.stdin.isTTY))) {
|
|
4975
|
-
const { runTuiApp } = await import("./tui-app-
|
|
4846
|
+
const { runTuiApp } = await import("./tui-app-Dt72u8vZ.js");
|
|
4976
4847
|
await runTuiApp();
|
|
4977
4848
|
return;
|
|
4978
4849
|
}
|
|
@@ -4999,4 +4870,4 @@ export {
|
|
|
4999
4870
|
sanitizeLabel as s,
|
|
5000
4871
|
toLines as t
|
|
5001
4872
|
};
|
|
5002
|
-
//# sourceMappingURL=bin-
|
|
4873
|
+
//# sourceMappingURL=bin-CCwDFxDe.js.map
|