counselors 0.4.9 → 0.4.11
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/dist/cli.js +80 -13
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -218,7 +218,7 @@ var SAFE_ID_RE = /^[a-zA-Z0-9._-]+$/;
|
|
|
218
218
|
function sanitizePath(p) {
|
|
219
219
|
return p.replace(/[\x00-\x08\x0A-\x1F]/g, "");
|
|
220
220
|
}
|
|
221
|
-
var VERSION = true ? "0.4.
|
|
221
|
+
var VERSION = true ? "0.4.11" : "0.0.0-dev";
|
|
222
222
|
|
|
223
223
|
// src/types.ts
|
|
224
224
|
import { z } from "zod";
|
|
@@ -397,10 +397,14 @@ async function selectModelDetails(toolId, models) {
|
|
|
397
397
|
name: m.recommended ? `${m.name} (Recommended)` : m.name,
|
|
398
398
|
value: String(i)
|
|
399
399
|
}));
|
|
400
|
+
choices.push({ name: "Custom model...", value: "__custom__" });
|
|
400
401
|
const idx = await select({
|
|
401
402
|
message: `Select model for ${toolId}:`,
|
|
402
403
|
choices
|
|
403
404
|
});
|
|
405
|
+
if (idx === "__custom__") {
|
|
406
|
+
return { id: "__custom__" };
|
|
407
|
+
}
|
|
404
408
|
const model = models[Number(idx)];
|
|
405
409
|
return {
|
|
406
410
|
id: model.id,
|
|
@@ -615,6 +619,7 @@ import { existsSync as existsSync3 } from "fs";
|
|
|
615
619
|
|
|
616
620
|
// src/adapters/base.ts
|
|
617
621
|
var BaseAdapter = class {
|
|
622
|
+
modelFlag = "-m";
|
|
618
623
|
getEffectiveReadOnlyLevel(_toolConfig) {
|
|
619
624
|
return this.readOnly.level;
|
|
620
625
|
}
|
|
@@ -713,6 +718,7 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
713
718
|
commands = ["claude"];
|
|
714
719
|
installUrl = "https://docs.anthropic.com/en/docs/claude-code";
|
|
715
720
|
readOnly = { level: "enforced" };
|
|
721
|
+
modelFlag = "--model";
|
|
716
722
|
models = [
|
|
717
723
|
{
|
|
718
724
|
id: "opus",
|
|
@@ -2127,6 +2133,8 @@ var ENV_ALLOWLIST = [
|
|
|
2127
2133
|
"GEMINI_API_KEY",
|
|
2128
2134
|
"GOOGLE_API_KEY",
|
|
2129
2135
|
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
2136
|
+
"GOOGLE_CLOUD_PROJECT",
|
|
2137
|
+
"GOOGLE_CLOUD_LOCATION",
|
|
2130
2138
|
"AMP_API_KEY",
|
|
2131
2139
|
// Proxy
|
|
2132
2140
|
"HTTP_PROXY",
|
|
@@ -2155,7 +2163,7 @@ function normalizeWindowsPathForComparison(path) {
|
|
|
2155
2163
|
const withoutTrailing = normalized === root ? normalized : normalized.replace(/[\\/]+$/, "");
|
|
2156
2164
|
return withoutTrailing.toLowerCase();
|
|
2157
2165
|
}
|
|
2158
|
-
function execute(invocation, timeoutMs) {
|
|
2166
|
+
function execute(invocation, timeoutMs, onSpawn) {
|
|
2159
2167
|
return new Promise((resolve7) => {
|
|
2160
2168
|
const start = Date.now();
|
|
2161
2169
|
let stdout = "";
|
|
@@ -2193,6 +2201,7 @@ function execute(invocation, timeoutMs) {
|
|
|
2193
2201
|
shell: false,
|
|
2194
2202
|
windowsHide: true
|
|
2195
2203
|
});
|
|
2204
|
+
onSpawn?.(child.pid);
|
|
2196
2205
|
const stdoutStream = child.stdout;
|
|
2197
2206
|
const stderrStream = child.stderr;
|
|
2198
2207
|
const stdinStream = child.stdin;
|
|
@@ -2314,13 +2323,16 @@ async function executeTest(adapter, toolConfig, toolName) {
|
|
|
2314
2323
|
const cmdStr = [invocation.cmd, ...invocation.args].map(quote).join(" ");
|
|
2315
2324
|
const command = invocation.stdin != null ? `echo ${quote(invocation.stdin)} | ${cmdStr}` : cmdStr;
|
|
2316
2325
|
const result = await execute(invocation, TEST_TIMEOUT);
|
|
2317
|
-
const
|
|
2326
|
+
const echoedPrompt = result.stdout.includes("User instructions");
|
|
2327
|
+
const passed = result.exitCode === 0 && result.stdout.includes("OK") && !echoedPrompt;
|
|
2318
2328
|
let error2;
|
|
2319
2329
|
if (!passed) {
|
|
2320
2330
|
if (result.timedOut) {
|
|
2321
2331
|
error2 = `Timed out after ${TEST_TIMEOUT / 1e3}s`;
|
|
2322
2332
|
} else if (result.exitCode !== 0) {
|
|
2323
2333
|
error2 = result.stderr.trim() || `Process exited with code ${result.exitCode}`;
|
|
2334
|
+
} else if (echoedPrompt) {
|
|
2335
|
+
error2 = "Tool echoed the prompt instead of a model response (check model access)";
|
|
2324
2336
|
} else if (result.stderr.trim()) {
|
|
2325
2337
|
error2 = result.stderr.slice(0, 500);
|
|
2326
2338
|
} else {
|
|
@@ -2640,8 +2652,9 @@ async function dispatch(options) {
|
|
|
2640
2652
|
const isAmp = (toolConfig.adapter ?? id) === "amp";
|
|
2641
2653
|
const usageBefore = isAmp ? await captureAmpUsage() : null;
|
|
2642
2654
|
debug(`Dispatching ${id}`);
|
|
2643
|
-
|
|
2644
|
-
|
|
2655
|
+
const result = await execute(invocation, toolTimeoutMs, (pid) => {
|
|
2656
|
+
onProgress?.({ toolId: id, event: "started", pid });
|
|
2657
|
+
});
|
|
2645
2658
|
const usageAfter = isAmp ? await captureAmpUsage() : null;
|
|
2646
2659
|
const cost = isAmp && usageBefore && usageAfter ? computeAmpCostFromSnapshots(usageBefore, usageAfter) : void 0;
|
|
2647
2660
|
const safeId = sanitizeId(id);
|
|
@@ -2827,6 +2840,7 @@ var ProgressDisplay = class {
|
|
|
2827
2840
|
frame = 0;
|
|
2828
2841
|
lineCount = 0;
|
|
2829
2842
|
isTTY;
|
|
2843
|
+
infoNotePrinted = false;
|
|
2830
2844
|
constructor(toolIds, outputDir) {
|
|
2831
2845
|
this.isTTY = Boolean(process.stderr.isTTY);
|
|
2832
2846
|
this.outputDir = outputDir;
|
|
@@ -2848,15 +2862,22 @@ var ProgressDisplay = class {
|
|
|
2848
2862
|
} else {
|
|
2849
2863
|
process.stderr.write(` Output: ${this.outputDir}
|
|
2850
2864
|
`);
|
|
2865
|
+
process.stderr.write(` \u2139 This may take more than 10 minutes
|
|
2866
|
+
`);
|
|
2867
|
+
process.stderr.write(` PID: ${process.pid}
|
|
2868
|
+
`);
|
|
2869
|
+
this.infoNotePrinted = true;
|
|
2851
2870
|
}
|
|
2852
2871
|
}
|
|
2853
|
-
start(toolId) {
|
|
2872
|
+
start(toolId, pid) {
|
|
2854
2873
|
const tool = this.tools.get(toolId);
|
|
2855
2874
|
if (!tool) return;
|
|
2856
2875
|
tool.status = "running";
|
|
2857
2876
|
tool.startedAt = Date.now();
|
|
2877
|
+
tool.pid = pid;
|
|
2858
2878
|
if (!this.isTTY) {
|
|
2859
|
-
|
|
2879
|
+
const pidStr = pid ? `PID ${pid} ` : "";
|
|
2880
|
+
process.stderr.write(` \u25B8 ${pidStr}${toolId} started
|
|
2860
2881
|
`);
|
|
2861
2882
|
}
|
|
2862
2883
|
}
|
|
@@ -2892,6 +2913,18 @@ var ProgressDisplay = class {
|
|
|
2892
2913
|
render() {
|
|
2893
2914
|
const lines = [];
|
|
2894
2915
|
lines.push(` ${DIM}Output: ${this.outputDir}${RESET}`);
|
|
2916
|
+
if (!this.infoNotePrinted) {
|
|
2917
|
+
const anyStarted = this.order.some(
|
|
2918
|
+
(id) => this.tools.get(id).status !== "pending"
|
|
2919
|
+
);
|
|
2920
|
+
if (anyStarted) {
|
|
2921
|
+
this.infoNotePrinted = true;
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
if (this.infoNotePrinted) {
|
|
2925
|
+
lines.push(` \u2139 This may take more than 10 minutes`);
|
|
2926
|
+
lines.push(` PID: ${process.pid}`);
|
|
2927
|
+
}
|
|
2895
2928
|
for (const id of this.order) {
|
|
2896
2929
|
const tool = this.tools.get(id);
|
|
2897
2930
|
lines.push(this.formatLine(tool));
|
|
@@ -2919,8 +2952,10 @@ var ProgressDisplay = class {
|
|
|
2919
2952
|
case "running": {
|
|
2920
2953
|
const spinner = SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length];
|
|
2921
2954
|
const elapsed = tool.startedAt ? ((Date.now() - tool.startedAt) / 1e3).toFixed(1) : "0.0";
|
|
2922
|
-
const
|
|
2923
|
-
|
|
2955
|
+
const pidPrefix = tool.pid ? `PID ${tool.pid} ` : "";
|
|
2956
|
+
const fullLabel = `${pidPrefix}${label}`;
|
|
2957
|
+
const pad = " ".repeat(Math.max(0, 40 - fullLabel.length));
|
|
2958
|
+
return ` ${spinner} ${fullLabel}${pad}running ${elapsed.padStart(6)}s`;
|
|
2924
2959
|
}
|
|
2925
2960
|
case "done": {
|
|
2926
2961
|
const r = tool.report;
|
|
@@ -3155,7 +3190,8 @@ function registerRunCommand(program2) {
|
|
|
3155
3190
|
readOnlyPolicy,
|
|
3156
3191
|
cwd,
|
|
3157
3192
|
onProgress: (event) => {
|
|
3158
|
-
if (event.event === "started")
|
|
3193
|
+
if (event.event === "started")
|
|
3194
|
+
display.start(event.toolId, event.pid);
|
|
3159
3195
|
if (event.event === "completed")
|
|
3160
3196
|
display.complete(event.toolId, event.report);
|
|
3161
3197
|
}
|
|
@@ -3321,6 +3357,8 @@ Use \`timeout: 600000\` (10 minutes). Counselors dispatches to the selected agen
|
|
|
3321
3357
|
|
|
3322
3358
|
**Important**: Use \`-f\` (file mode) so the prompt is sent as-is without wrapping. Use \`--json\` to get structured output for parsing.
|
|
3323
3359
|
|
|
3360
|
+
**Timing**: Sessions commonly take more than 10 minutes. Counselors prints each child process PID alongside the agent name in its progress output (e.g. \`PID 12345 claude\`). If a run seems stuck, you can verify processes are still alive with \`ps -p <PID>\` (macOS/Linux) or \`tasklist /FI "PID eq <PID>"\` (Windows).
|
|
3361
|
+
|
|
3324
3362
|
---
|
|
3325
3363
|
|
|
3326
3364
|
## Phase 5: Read Results
|
|
@@ -3435,8 +3473,26 @@ async function addBuiltInTool(toolId, config, nameOverride) {
|
|
|
3435
3473
|
return;
|
|
3436
3474
|
}
|
|
3437
3475
|
const selectedModel = await selectModelDetails(toolId, adapter.models);
|
|
3438
|
-
|
|
3439
|
-
|
|
3476
|
+
let extraFlags;
|
|
3477
|
+
let defaultName;
|
|
3478
|
+
if (selectedModel.id === "__custom__") {
|
|
3479
|
+
const modelId = await promptInput("Model identifier:");
|
|
3480
|
+
if (!modelId.trim()) {
|
|
3481
|
+
error("No model identifier provided.");
|
|
3482
|
+
process.exitCode = 1;
|
|
3483
|
+
return;
|
|
3484
|
+
}
|
|
3485
|
+
const extraInput = await promptInput(
|
|
3486
|
+
"Extra flags (optional, space-separated):"
|
|
3487
|
+
);
|
|
3488
|
+
const parsedExtra = extraInput.trim() ? extraInput.trim().split(/\s+/) : [];
|
|
3489
|
+
extraFlags = [adapter.modelFlag ?? "-m", modelId.trim(), ...parsedExtra];
|
|
3490
|
+
defaultName = nameOverride ?? `${toolId}-${sanitizeId(modelId.trim())}`;
|
|
3491
|
+
} else {
|
|
3492
|
+
extraFlags = selectedModel.extraFlags;
|
|
3493
|
+
const fallbackName = selectedModel.id.startsWith(`${toolId}-`) ? selectedModel.id : `${toolId}-${selectedModel.id}`;
|
|
3494
|
+
defaultName = nameOverride ?? selectedModel.compoundId ?? fallbackName;
|
|
3495
|
+
}
|
|
3440
3496
|
let name = nameOverride ?? await promptInput("Tool name:", defaultName);
|
|
3441
3497
|
if (!SAFE_ID_RE.test(name)) {
|
|
3442
3498
|
error(
|
|
@@ -3467,7 +3523,7 @@ async function addBuiltInTool(toolId, config, nameOverride) {
|
|
|
3467
3523
|
binary: discovery.path,
|
|
3468
3524
|
readOnly: { level: adapter.readOnly.level },
|
|
3469
3525
|
adapter: toolId,
|
|
3470
|
-
...
|
|
3526
|
+
...extraFlags ? { extraFlags } : {}
|
|
3471
3527
|
};
|
|
3472
3528
|
const updated = addToolToConfig(config, name, toolConfig);
|
|
3473
3529
|
saveConfig(updated);
|
|
@@ -3475,6 +3531,17 @@ async function addBuiltInTool(toolId, config, nameOverride) {
|
|
|
3475
3531
|
copyAmpSettings();
|
|
3476
3532
|
}
|
|
3477
3533
|
success(`Added "${name}" to config.`);
|
|
3534
|
+
if (selectedModel.id === "__custom__") {
|
|
3535
|
+
info("Testing tool configuration...");
|
|
3536
|
+
const testAdapter = resolveAdapter(name, toolConfig);
|
|
3537
|
+
const result = await executeTest(testAdapter, toolConfig, name);
|
|
3538
|
+
info(formatTestResults([result]));
|
|
3539
|
+
if (!result.passed) {
|
|
3540
|
+
warn(
|
|
3541
|
+
"The tool was saved to your config but the test failed. You may need to check your API access or flags."
|
|
3542
|
+
);
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3478
3545
|
}
|
|
3479
3546
|
async function collectCustomConfig(config, presetId) {
|
|
3480
3547
|
let binaryPath = null;
|