actoviq-agent-sdk 0.4.13 → 0.4.15
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/CHANGELOG.md +44 -0
- package/dist/src/cli/hadamard-tui.js +5 -4
- package/dist/src/cli/hadamard-tui.js.map +1 -1
- package/dist/src/config/modelConfigurationCatalog.d.ts +4 -0
- package/dist/src/config/modelConfigurationCatalog.d.ts.map +1 -1
- package/dist/src/config/modelConfigurationCatalog.js +8 -0
- package/dist/src/config/modelConfigurationCatalog.js.map +1 -1
- package/dist/src/config/projectSettings.d.ts +8 -1
- package/dist/src/config/projectSettings.d.ts.map +1 -1
- package/dist/src/config/projectSettings.js +15 -0
- package/dist/src/config/projectSettings.js.map +1 -1
- package/dist/src/gui/hadamardGui.d.ts.map +1 -1
- package/dist/src/gui/hadamardGui.js +58 -15
- package/dist/src/gui/hadamardGui.js.map +1 -1
- package/dist/src/memory/projectContext.d.ts +16 -11
- package/dist/src/memory/projectContext.d.ts.map +1 -1
- package/dist/src/memory/projectContext.js +45 -37
- package/dist/src/memory/projectContext.js.map +1 -1
- package/dist/src/prompts/systemPrompt.js +2 -2
- package/dist/src/prompts/systemPrompt.js.map +1 -1
- package/dist/src/runtime/agentClient.d.ts.map +1 -1
- package/dist/src/runtime/agentClient.js +36 -3
- package/dist/src/runtime/agentClient.js.map +1 -1
- package/dist/src/runtime/conversationEngine.d.ts.map +1 -1
- package/dist/src/runtime/conversationEngine.js +3 -2
- package/dist/src/runtime/conversationEngine.js.map +1 -1
- package/dist/src/tui/hadamardTui.d.ts.map +1 -1
- package/dist/src/tui/hadamardTui.js +126 -26
- package/dist/src/tui/hadamardTui.js.map +1 -1
- package/dist/src/tui/reasoningDisplay.d.ts +1 -0
- package/dist/src/tui/reasoningDisplay.d.ts.map +1 -1
- package/dist/src/tui/reasoningDisplay.js +10 -3
- package/dist/src/tui/reasoningDisplay.js.map +1 -1
- package/dist/src/tui/toolActivityDisplay.d.ts +8 -0
- package/dist/src/tui/toolActivityDisplay.d.ts.map +1 -0
- package/dist/src/tui/toolActivityDisplay.js +24 -0
- package/dist/src/tui/toolActivityDisplay.js.map +1 -0
- package/dist/src/ui/commandSurface.d.ts.map +1 -1
- package/dist/src/ui/commandSurface.js +18 -8
- package/dist/src/ui/commandSurface.js.map +1 -1
- package/package.json +3 -1
|
@@ -18,11 +18,12 @@ import { parseCrushSessionReferenceDetails } from '../parity/crushSessionHistory
|
|
|
18
18
|
import { readProjectMeta } from '../gui/projectMeta.js';
|
|
19
19
|
import { readWorkspaceRegistry } from '../gui/workspaceRegistry.js';
|
|
20
20
|
import { persistHadamardSettingsStore, resolveHadamardSettingsStore, } from '../config/hadamardSettingsStore.js';
|
|
21
|
+
import { readProjectSettings, writeProjectSettings, } from '../config/projectSettings.js';
|
|
21
22
|
import { createPreToolUseHookClassifier, readPreToolUseHooks, readPostToolUseHooks, runPostToolUseHooks, readSessionStartHooks, runSessionStartHooks } from '../hooks/userHooks.js';
|
|
22
23
|
import { parseTypedHooks } from '../hooks/hookConfig.js';
|
|
23
24
|
import { isRecord } from '../runtime/helpers.js';
|
|
24
25
|
import { getLoadedJsonConfig } from '../config/loadJsonConfigFile.js';
|
|
25
|
-
import { buildModelConfigurationCatalog, findModelConfiguration, resolveHadamardConfigurationModel, } from '../config/modelConfigurationCatalog.js';
|
|
26
|
+
import { buildModelConfigurationCatalog, findModelConfiguration, isModelCredentialConfigured, resolveHadamardConfigurationModel, } from '../config/modelConfigurationCatalog.js';
|
|
26
27
|
import { findBridgeConfig, maskApiKey, readBridgeConfigs, addBridgeConfig, removeBridgeConfig, isManagedExternalCliRuntime, } from '../parity/bridgeConfigs.js';
|
|
27
28
|
import { buildRouteModelApi } from '../router/modelRouter.js';
|
|
28
29
|
import { addMcpServer, readMcpServerConfig, removeMcpServer } from '../mcp/mcpServerConfig.js';
|
|
@@ -40,6 +41,7 @@ import { InputEditor } from './editor.js';
|
|
|
40
41
|
import { discoverHadamardPlugins } from './pluginCatalog.js';
|
|
41
42
|
import { TuiScreen } from './screen.js';
|
|
42
43
|
import { ReasoningDisplayState } from './reasoningDisplay.js';
|
|
44
|
+
import { ToolActivityDisplayState } from './toolActivityDisplay.js';
|
|
43
45
|
import { recallLatestFollowUp, restoreAbandonedFollowUp, submitActiveInput, } from './pendingInput.js';
|
|
44
46
|
import { filterTuiSelectionItems, moveTuiSelection, } from './selection.js';
|
|
45
47
|
import { StreamFlusher, formatBanner, formatCompactNotice, formatDivider, formatEditCall, formatErrorLine, formatInfoLine, formatQueuedPrompt, formatToolCall, formatToolResult, formatUserPrompt, } from './transcript.js';
|
|
@@ -172,7 +174,7 @@ export function renderRichText(text, width, opts = {}) {
|
|
|
172
174
|
}
|
|
173
175
|
return out;
|
|
174
176
|
}
|
|
175
|
-
function buildSystemPrompt(workDir) {
|
|
177
|
+
function buildSystemPrompt(workDir, projectSettings, hadamardHomeDir) {
|
|
176
178
|
let isGit = false;
|
|
177
179
|
try {
|
|
178
180
|
execSync('git rev-parse --is-inside-work-tree', { cwd: workDir, stdio: 'ignore' });
|
|
@@ -181,11 +183,14 @@ function buildSystemPrompt(workDir) {
|
|
|
181
183
|
catch {
|
|
182
184
|
// not a git repo
|
|
183
185
|
}
|
|
184
|
-
// Load
|
|
186
|
+
// Load Hadamard instruction files (AGENTS.md by default) so the agent
|
|
185
187
|
// picks up project-specific instructions — the canonical Claude Code behavior.
|
|
186
|
-
const project = loadProjectContext(workDir
|
|
188
|
+
const project = loadProjectContext(workDir, {
|
|
189
|
+
projectInstructionMode: projectSettings.context.instructionMode,
|
|
190
|
+
hadamardHomeDir,
|
|
191
|
+
});
|
|
187
192
|
const projectSection = project.text
|
|
188
|
-
? `\n\n# Project context (
|
|
193
|
+
? `\n\n# Project context (AGENTS.md)\n\nThe following instruction files are authoritative guidance for this workspace.\n\n${project.text}\n`
|
|
189
194
|
: '';
|
|
190
195
|
return (`You are Hadamard Agent, an interactive CLI agent. Working directory: ${workDir}\n\n` +
|
|
191
196
|
`<env>\nWorking directory: ${workDir}\nIs git repo: ${isGit ? 'Yes' : 'No'}\nPlatform: ${process.platform}\nDate: ${new Date().toISOString().slice(0, 10)}\n</env>\n\n` +
|
|
@@ -237,7 +242,6 @@ async function onboardCredentials(configPath) {
|
|
|
237
242
|
export async function runHadamardTui(options = {}) {
|
|
238
243
|
const workDir = path.resolve(options.workDir ?? process.cwd());
|
|
239
244
|
const permissionMode = options.permissionMode ?? 'bypassPermissions';
|
|
240
|
-
const systemPrompt = buildSystemPrompt(workDir);
|
|
241
245
|
try {
|
|
242
246
|
if (options.configPath) {
|
|
243
247
|
await loadJsonConfigFile(options.configPath);
|
|
@@ -249,6 +253,9 @@ export async function runHadamardTui(options = {}) {
|
|
|
249
253
|
catch {
|
|
250
254
|
// Missing local config is fine; env vars may carry credentials.
|
|
251
255
|
}
|
|
256
|
+
const hadamardHomeDir = resolveHadamardHome();
|
|
257
|
+
let projectSettings = await readProjectSettings(workDir, hadamardHomeDir);
|
|
258
|
+
let systemPrompt = buildSystemPrompt(workDir, projectSettings, hadamardHomeDir);
|
|
252
259
|
let applyPlanPermission = null;
|
|
253
260
|
let managedPluginRuntime = null;
|
|
254
261
|
let tools = [];
|
|
@@ -654,6 +661,8 @@ export async function runHadamardTui(options = {}) {
|
|
|
654
661
|
let spinnerTimer = null;
|
|
655
662
|
let dynamicRenderTimer = null;
|
|
656
663
|
let runStartedAt = 0;
|
|
664
|
+
let requestStartedAt = 0;
|
|
665
|
+
let providerActivitySeen = false;
|
|
657
666
|
let runToolCount = 0;
|
|
658
667
|
let lastTokenEstimate;
|
|
659
668
|
// Running token + USD totals for /cost and /usage. Per-config breakdown
|
|
@@ -665,6 +674,11 @@ export async function runHadamardTui(options = {}) {
|
|
|
665
674
|
function recordUsage(model, usage) {
|
|
666
675
|
const inT = usage?.input_tokens ?? 0;
|
|
667
676
|
const outT = usage?.output_tokens ?? 0;
|
|
677
|
+
const reportedContextTokens = inT
|
|
678
|
+
+ (usage?.cache_creation_input_tokens ?? 0)
|
|
679
|
+
+ (usage?.cache_read_input_tokens ?? 0);
|
|
680
|
+
if (reportedContextTokens > 0)
|
|
681
|
+
lastTokenEstimate = reportedContextTokens;
|
|
668
682
|
totalInputTokens += inT;
|
|
669
683
|
totalOutputTokens += outT;
|
|
670
684
|
const cost = estimateCost(model, inT, outT);
|
|
@@ -690,6 +704,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
690
704
|
let ctrlCTimer = null;
|
|
691
705
|
let streamedTextSeen = false;
|
|
692
706
|
const reasoningDisplay = new ReasoningDisplayState();
|
|
707
|
+
const toolActivityDisplay = new ToolActivityDisplayState();
|
|
693
708
|
// Track tool names by callId for PostToolUse hook context.
|
|
694
709
|
const toolCallNames = new Map();
|
|
695
710
|
// Live todo list (captured from TodoWrite tool calls). Rendered as a
|
|
@@ -1049,8 +1064,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1049
1064
|
const selected = index === menuSelected;
|
|
1050
1065
|
const command = `/${name}`.padEnd(commandWidth);
|
|
1051
1066
|
const label = selected ? `${A.inverse}${command}${A.reset}` : command;
|
|
1052
|
-
const
|
|
1053
|
-
const unavailable = running && interactiveCommandRunPolicy(commandName) === 'idle-only';
|
|
1067
|
+
const unavailable = running && interactiveCommandRunPolicy(name) === 'idle-only';
|
|
1054
1068
|
const summary = TUI_SLASH_COMMANDS[name] ?? SUBCOMMAND_DESCRIPTIONS[name] ?? '';
|
|
1055
1069
|
const description = truncateToWidth(unavailable ? `${summary} · after current run` : summary, descriptionWidth);
|
|
1056
1070
|
return `${label} ${A.dim}${description}${A.reset}`;
|
|
@@ -1068,7 +1082,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1068
1082
|
const selected = matches[Math.min(menuSelected, matches.length - 1)];
|
|
1069
1083
|
if (selected) {
|
|
1070
1084
|
const commandName = selected.split(/\s/u, 1)[0] ?? selected;
|
|
1071
|
-
const availability = interactiveCommandRunPolicy(
|
|
1085
|
+
const availability = interactiveCommandRunPolicy(selected) === 'during-run'
|
|
1072
1086
|
? 'available while working'
|
|
1073
1087
|
: 'idle session';
|
|
1074
1088
|
lines.push(`${A.dim} ${interactiveCommandUsage(commandName)} · ${availability}${A.reset}`);
|
|
@@ -1472,13 +1486,21 @@ export async function runHadamardTui(options = {}) {
|
|
|
1472
1486
|
}
|
|
1473
1487
|
running = true;
|
|
1474
1488
|
runStartedAt = Date.now();
|
|
1489
|
+
requestStartedAt = 0;
|
|
1490
|
+
providerActivitySeen = false;
|
|
1475
1491
|
runToolCount = 0;
|
|
1476
|
-
|
|
1492
|
+
toolActivityDisplay.reset();
|
|
1493
|
+
toolCallNames.clear();
|
|
1494
|
+
statusNote = 'preparing locally';
|
|
1477
1495
|
streamedTextSeen = false;
|
|
1478
1496
|
lastTokenEstimate = undefined;
|
|
1479
1497
|
abortCtrl = new AbortController();
|
|
1480
1498
|
spinnerTimer = setInterval(() => {
|
|
1481
1499
|
spinnerFrame += 1;
|
|
1500
|
+
if (requestStartedAt > 0 && !providerActivitySeen) {
|
|
1501
|
+
const waitingSeconds = Math.max(Math.round((Date.now() - requestStartedAt) / 1000), 0);
|
|
1502
|
+
statusNote = `waiting for model ${waitingSeconds}s`;
|
|
1503
|
+
}
|
|
1482
1504
|
renderDynamic();
|
|
1483
1505
|
}, 120);
|
|
1484
1506
|
appendStatic(formatUserPrompt(text));
|
|
@@ -1630,8 +1652,13 @@ export async function runHadamardTui(options = {}) {
|
|
|
1630
1652
|
case 'run.started':
|
|
1631
1653
|
streamedTextSeen = false;
|
|
1632
1654
|
reasoningDisplay.reset();
|
|
1655
|
+
toolActivityDisplay.reset();
|
|
1656
|
+
toolCallNames.clear();
|
|
1633
1657
|
return;
|
|
1634
1658
|
case 'request.started':
|
|
1659
|
+
requestStartedAt = Date.now();
|
|
1660
|
+
providerActivitySeen = false;
|
|
1661
|
+
statusNote = 'waiting for model 0s';
|
|
1635
1662
|
lastTokenEstimate = typeof data.requestTokenEstimate === 'number'
|
|
1636
1663
|
? data.requestTokenEstimate
|
|
1637
1664
|
: undefined;
|
|
@@ -1641,6 +1668,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1641
1668
|
const delta = typeof data.delta === 'string' ? data.delta : '';
|
|
1642
1669
|
if (!delta)
|
|
1643
1670
|
return;
|
|
1671
|
+
providerActivitySeen = true;
|
|
1644
1672
|
collapseReasoning();
|
|
1645
1673
|
streamedTextSeen = true;
|
|
1646
1674
|
const flushed = flusher.push(delta);
|
|
@@ -1653,11 +1681,13 @@ export async function runHadamardTui(options = {}) {
|
|
|
1653
1681
|
const delta = typeof data.delta === 'string' ? data.delta : '';
|
|
1654
1682
|
if (!delta)
|
|
1655
1683
|
return;
|
|
1684
|
+
providerActivitySeen = true;
|
|
1656
1685
|
reasoningDisplay.append(delta);
|
|
1657
1686
|
scheduleDynamicRender();
|
|
1658
1687
|
return;
|
|
1659
1688
|
}
|
|
1660
1689
|
case 'tool.input.delta': {
|
|
1690
|
+
providerActivitySeen = true;
|
|
1661
1691
|
const name = typeof data.name === 'string' && data.name ? data.name : 'tool';
|
|
1662
1692
|
const snapshot = typeof data.snapshot === 'string'
|
|
1663
1693
|
? data.snapshot.trim().replace(/\s+/g, ' ')
|
|
@@ -1668,6 +1698,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1668
1698
|
return;
|
|
1669
1699
|
}
|
|
1670
1700
|
case 'model.content': {
|
|
1701
|
+
providerActivitySeen = true;
|
|
1671
1702
|
const content = isRecord(data.content) ? data.content : undefined;
|
|
1672
1703
|
if (data.kind === 'content' && content?.type === 'thinking' && !reasoningDisplay.hasStreamedContent) {
|
|
1673
1704
|
const thinking = typeof content.thinking === 'string' ? content.thinking : '';
|
|
@@ -1677,8 +1708,11 @@ export async function runHadamardTui(options = {}) {
|
|
|
1677
1708
|
return;
|
|
1678
1709
|
}
|
|
1679
1710
|
case 'tool.started': {
|
|
1680
|
-
collapseReasoning();
|
|
1681
1711
|
const callId = typeof data.callId === 'string' ? data.callId : '';
|
|
1712
|
+
if (!toolActivityDisplay.markStarted(callId))
|
|
1713
|
+
return;
|
|
1714
|
+
providerActivitySeen = true;
|
|
1715
|
+
collapseReasoning();
|
|
1682
1716
|
const publicName = typeof data.publicName === 'string'
|
|
1683
1717
|
? data.publicName
|
|
1684
1718
|
: typeof data.name === 'string' ? data.name : 'tool';
|
|
@@ -1727,6 +1761,8 @@ export async function runHadamardTui(options = {}) {
|
|
|
1727
1761
|
case 'tool.failed':
|
|
1728
1762
|
case 'tool.rejected': {
|
|
1729
1763
|
const callId = typeof data.callId === 'string' ? data.callId : '';
|
|
1764
|
+
if (!toolActivityDisplay.markTerminal(callId))
|
|
1765
|
+
return;
|
|
1730
1766
|
const outputText = typeof data.outputText === 'string' ? data.outputText : '';
|
|
1731
1767
|
statusNote = '';
|
|
1732
1768
|
appendStatic(formatToolResult({
|
|
@@ -1739,6 +1775,8 @@ export async function runHadamardTui(options = {}) {
|
|
|
1739
1775
|
if (toolName) {
|
|
1740
1776
|
runPostToolUseHooks(() => readPostToolUseHooks(getLoadedJsonConfig()?.raw), toolName, null, outputText, sdk.config.workDir);
|
|
1741
1777
|
}
|
|
1778
|
+
if (callId)
|
|
1779
|
+
toolCallNames.delete(callId);
|
|
1742
1780
|
renderDynamic();
|
|
1743
1781
|
return;
|
|
1744
1782
|
}
|
|
@@ -1813,6 +1851,43 @@ export async function runHadamardTui(options = {}) {
|
|
|
1813
1851
|
if (selected)
|
|
1814
1852
|
await resumeSession(selected);
|
|
1815
1853
|
}
|
|
1854
|
+
async function configureContextSettings(requestedMode = '') {
|
|
1855
|
+
const normalized = requestedMode.trim().toLowerCase();
|
|
1856
|
+
let instructionMode;
|
|
1857
|
+
if (normalized === 'agents' || normalized === 'claude' || normalized === 'both') {
|
|
1858
|
+
instructionMode = normalized;
|
|
1859
|
+
}
|
|
1860
|
+
else if (normalized) {
|
|
1861
|
+
appendStatic([...formatErrorLine('usage: /context settings [agents|claude|both]'), '']);
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
else {
|
|
1865
|
+
const selected = await selectItem({
|
|
1866
|
+
title: 'Context settings',
|
|
1867
|
+
subtitle: `Current project mode: ${projectSettings.context.instructionMode}`,
|
|
1868
|
+
searchable: false,
|
|
1869
|
+
items: [
|
|
1870
|
+
{ id: 'agents', label: 'AGENTS.md', description: 'Recommended Hadamard default' },
|
|
1871
|
+
{ id: 'claude', label: 'CLAUDE.md', description: 'Project-level Claude compatibility' },
|
|
1872
|
+
{ id: 'both', label: 'AGENTS.md + CLAUDE.md', description: 'Load both project instruction formats' },
|
|
1873
|
+
],
|
|
1874
|
+
});
|
|
1875
|
+
if (selected === 'agents' || selected === 'claude' || selected === 'both') {
|
|
1876
|
+
instructionMode = selected;
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
if (!instructionMode)
|
|
1880
|
+
return;
|
|
1881
|
+
projectSettings = await writeProjectSettings(workDir, hadamardHomeDir, {
|
|
1882
|
+
context: { instructionMode },
|
|
1883
|
+
});
|
|
1884
|
+
systemPrompt = buildSystemPrompt(workDir, projectSettings, hadamardHomeDir);
|
|
1885
|
+
appendStatic([
|
|
1886
|
+
...formatInfoLine(`context instructions: ${instructionMode}`),
|
|
1887
|
+
...formatInfoLine('Global rules remain ~/.hadamard/AGENTS.md.'),
|
|
1888
|
+
'',
|
|
1889
|
+
]);
|
|
1890
|
+
}
|
|
1816
1891
|
async function chooseModel() {
|
|
1817
1892
|
const catalog = buildModelConfigurationCatalog({
|
|
1818
1893
|
model: sdk.config.model,
|
|
@@ -1923,7 +1998,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1923
1998
|
{
|
|
1924
1999
|
id: 'api-key',
|
|
1925
2000
|
label: 'API key',
|
|
1926
|
-
description: env
|
|
2001
|
+
description: isModelCredentialConfigured(env, sdk.config) ? 'configured' : 'not configured',
|
|
1927
2002
|
},
|
|
1928
2003
|
{
|
|
1929
2004
|
id: 'base-url',
|
|
@@ -3517,7 +3592,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
3517
3592
|
const spaceIndex = raw.indexOf(' ');
|
|
3518
3593
|
const name = (spaceIndex === -1 ? raw.slice(1) : raw.slice(1, spaceIndex)).toLowerCase();
|
|
3519
3594
|
const args = spaceIndex === -1 ? '' : raw.slice(spaceIndex + 1).trim();
|
|
3520
|
-
if (!canRunInteractiveCommand(
|
|
3595
|
+
if (!canRunInteractiveCommand(raw.slice(1), running)) {
|
|
3521
3596
|
appendStatic(formatInfoLine(`/${name} requires an idle session; it will be available after this run`));
|
|
3522
3597
|
return;
|
|
3523
3598
|
}
|
|
@@ -3551,10 +3626,10 @@ export async function runHadamardTui(options = {}) {
|
|
|
3551
3626
|
renderDynamic();
|
|
3552
3627
|
return;
|
|
3553
3628
|
case 'init': {
|
|
3554
|
-
// Bootstrap
|
|
3555
|
-
// write concise guidance
|
|
3629
|
+
// Bootstrap AGENTS.md by having the agent explore the repo and
|
|
3630
|
+
// write concise guidance for subsequent Hadamard sessions.
|
|
3556
3631
|
// generated file is then injected into every system prompt).
|
|
3557
|
-
await startRun('Create or update
|
|
3632
|
+
await startRun('Create or update an AGENTS.md at the repo root with concise guidance for AI coding assistants: build/test/lint/run commands, a short architecture overview, key conventions, and non-obvious gotchas. Explore with Glob, Grep, and Read first (package.json, README, existing AGENTS.md, key source dirs). If AGENTS.md already exists, improve it without discarding user-authored sections. Keep it focused and avoid filler.');
|
|
3558
3633
|
return;
|
|
3559
3634
|
}
|
|
3560
3635
|
case 'exit':
|
|
@@ -3927,9 +4002,22 @@ export async function runHadamardTui(options = {}) {
|
|
|
3927
4002
|
return;
|
|
3928
4003
|
}
|
|
3929
4004
|
case 'context': {
|
|
4005
|
+
const contextArgs = args.trim();
|
|
4006
|
+
if (contextArgs === 'setting' || contextArgs === 'settings') {
|
|
4007
|
+
await configureContextSettings();
|
|
4008
|
+
return;
|
|
4009
|
+
}
|
|
4010
|
+
if (contextArgs.startsWith('setting ') || contextArgs.startsWith('settings ')) {
|
|
4011
|
+
await configureContextSettings(contextArgs.replace(/^settings?\s+/u, ''));
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
if (contextArgs) {
|
|
4015
|
+
appendStatic([...formatErrorLine('usage: /context [settings [agents|claude|both]]'), '']);
|
|
4016
|
+
return;
|
|
4017
|
+
}
|
|
3930
4018
|
// Break down what is consuming the context window (gap #9 vs
|
|
3931
4019
|
// claude-code's /context) — usage, messages, system prompt, tools,
|
|
3932
|
-
// the loaded
|
|
4020
|
+
// the loaded project instruction sources, and the active config.
|
|
3933
4021
|
const { resolveHadamardCompactBudget } = await import('../runtime/hadamardCompact.js');
|
|
3934
4022
|
const compactBudget = resolveHadamardCompactBudget(sdk.config.compact);
|
|
3935
4023
|
const window = compactBudget.effectiveContextWindowTokens;
|
|
@@ -3941,7 +4029,10 @@ export async function runHadamardTui(options = {}) {
|
|
|
3941
4029
|
const messages = session.messages.length;
|
|
3942
4030
|
const sysChars = systemPrompt.length;
|
|
3943
4031
|
const mcpCount = toolMetadata.filter(t => t.provider === 'mcp').length;
|
|
3944
|
-
const project = loadProjectContext(sdk.config.workDir
|
|
4032
|
+
const project = loadProjectContext(sdk.config.workDir, {
|
|
4033
|
+
projectInstructionMode: projectSettings.context.instructionMode,
|
|
4034
|
+
hadamardHomeDir,
|
|
4035
|
+
});
|
|
3945
4036
|
const team = activeTeamName ?? 'none';
|
|
3946
4037
|
const router = activeRouter ? activeRouter.name : 'off';
|
|
3947
4038
|
const bridge = bridgeMode && activeBridgeConfig ? activeBridgeConfig.name : 'off';
|
|
@@ -3953,7 +4044,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
3953
4044
|
` ${A.dim}messages${A.reset} ${messages}`,
|
|
3954
4045
|
` ${A.dim}system prompt${A.reset} ~${sysChars} chars`,
|
|
3955
4046
|
` ${A.dim}tools${A.reset} ${toolMetadata.length}${mcpCount > 0 ? ` (${mcpCount} MCP)` : ''}`,
|
|
3956
|
-
` ${A.dim}
|
|
4047
|
+
` ${A.dim}instruction files${A.reset} ${project.sources.length ? project.sources.join(', ') : '(none loaded)'}`,
|
|
3957
4048
|
` ${A.dim}active${A.reset} model=${session.model} · effort=${currentEffort() ?? 'auto'} · team=${team} · router=${router} · bridge=${bridge}`,
|
|
3958
4049
|
'',
|
|
3959
4050
|
]);
|
|
@@ -4015,8 +4106,11 @@ export async function runHadamardTui(options = {}) {
|
|
|
4015
4106
|
lines.push(` ${ok(true)} permission mode ${A.dim}${currentPermissionMode()}${A.reset}`);
|
|
4016
4107
|
lines.push(` ${ok(toolMetadata.length > 0)} tools ${A.dim}${toolMetadata.length}${A.reset}`);
|
|
4017
4108
|
// Context memory
|
|
4018
|
-
const project = loadProjectContext(cfg.workDir
|
|
4019
|
-
|
|
4109
|
+
const project = loadProjectContext(cfg.workDir, {
|
|
4110
|
+
projectInstructionMode: projectSettings.context.instructionMode,
|
|
4111
|
+
hadamardHomeDir,
|
|
4112
|
+
});
|
|
4113
|
+
lines.push(` ${ok(project.sources.length > 0)} instruction files ${A.dim}${project.sources.length ? project.sources.join(', ') : '(none)'}${A.reset}`);
|
|
4020
4114
|
// Bridge runtimes
|
|
4021
4115
|
const detections = await withSpinner('detecting runtimes', detectBridgeProviders);
|
|
4022
4116
|
const avail = detections.filter(d => d.available);
|
|
@@ -4106,7 +4200,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
4106
4200
|
case 'compact': {
|
|
4107
4201
|
try {
|
|
4108
4202
|
const summaryInstructions = args || undefined;
|
|
4109
|
-
const result = await session.compact({
|
|
4203
|
+
const result = await session.compact({ summaryInstructions });
|
|
4110
4204
|
if (!result.compacted) {
|
|
4111
4205
|
appendStatic([
|
|
4112
4206
|
...formatErrorLine(result.error ?? `compact skipped: ${result.reason}`),
|
|
@@ -4969,9 +5063,12 @@ export async function runHadamardTui(options = {}) {
|
|
|
4969
5063
|
__hadamardUseDefaultTools: false,
|
|
4970
5064
|
__hadamardAllowedTools: tools.map(item => item.name),
|
|
4971
5065
|
});
|
|
5066
|
+
const assistantToolDisplay = new ToolActivityDisplayState();
|
|
4972
5067
|
for await (const event of stream) {
|
|
4973
|
-
if (event.type === 'tool.call'
|
|
5068
|
+
if (event.type === 'tool.call'
|
|
5069
|
+
&& assistantToolDisplay.markStarted(event.call.id)) {
|
|
4974
5070
|
appendStatic([`${A.dim} ⚙ ${event.call.name}${A.reset}`]);
|
|
5071
|
+
}
|
|
4975
5072
|
}
|
|
4976
5073
|
const result = await stream.result;
|
|
4977
5074
|
if (result.text)
|
|
@@ -5321,9 +5418,12 @@ export async function runHadamardTui(options = {}) {
|
|
|
5321
5418
|
__hadamardAllowedTools: managerTools.map((tool) => tool.name),
|
|
5322
5419
|
};
|
|
5323
5420
|
const stream = managerTuiSession.stream(prompt, runOptions);
|
|
5421
|
+
const managerToolDisplay = new ToolActivityDisplayState();
|
|
5324
5422
|
for await (const event of stream) {
|
|
5325
|
-
if (event.type === 'tool.call'
|
|
5423
|
+
if (event.type === 'tool.call'
|
|
5424
|
+
&& managerToolDisplay.markStarted(event.call.id)) {
|
|
5326
5425
|
appendStatic([`${A.dim} ⚡ ${event.call.name}${A.reset}`]);
|
|
5426
|
+
}
|
|
5327
5427
|
}
|
|
5328
5428
|
const result = await stream.result;
|
|
5329
5429
|
if (result.text)
|
|
@@ -5416,7 +5516,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
5416
5516
|
recalledFollowUp = null;
|
|
5417
5517
|
editor.clear();
|
|
5418
5518
|
menuSelected = 0;
|
|
5419
|
-
if (running && !canRunInteractiveCommand(
|
|
5519
|
+
if (running && !canRunInteractiveCommand(selectedCommand.slice(1), true)) {
|
|
5420
5520
|
appendStatic(formatInfoLine(`/${selectedName} requires an idle session; it will be available after this run`));
|
|
5421
5521
|
renderDynamic();
|
|
5422
5522
|
return;
|
|
@@ -5445,7 +5545,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
5445
5545
|
restoreAbandonedFollowUp(session, recalledFollowUp);
|
|
5446
5546
|
recalledFollowUp = null;
|
|
5447
5547
|
const command = text.slice(1).trim().split(/\s/u, 1)[0]?.toLowerCase() ?? '';
|
|
5448
|
-
if (!canRunInteractiveCommand(
|
|
5548
|
+
if (!canRunInteractiveCommand(text.slice(1), true)) {
|
|
5449
5549
|
appendStatic(formatInfoLine(`/${command} requires an idle session; it will be available after this run`));
|
|
5450
5550
|
renderDynamic();
|
|
5451
5551
|
return;
|