@adhdev/daemon-core 0.9.82-rc.483 → 0.9.82-rc.485
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-adapters/provider-cli-adapter.d.ts +3 -0
- package/dist/commands/cli-manager.d.ts +20 -0
- package/dist/config/mesh-config.d.ts +14 -1
- package/dist/index.js +365 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +365 -19
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-events-pending.d.ts +12 -0
- package/dist/mesh/mesh-runtime-store.d.ts +14 -0
- package/dist/mesh/mesh-work-queue.d.ts +17 -0
- package/dist/providers/cli-provider-instance.d.ts +14 -0
- package/dist/providers/contracts.d.ts +47 -0
- package/dist/repo-mesh-types.d.ts +10 -1
- package/dist/shared-types.d.ts +4 -0
- package/package.json +3 -3
- package/src/cli-adapters/provider-cli-adapter.ts +70 -1
- package/src/commands/cli-manager.ts +64 -3
- package/src/commands/med-family/mesh-crud.ts +24 -0
- package/src/config/mesh-config.ts +30 -1
- package/src/mesh/coordinator-prompt.ts +36 -0
- package/src/mesh/mesh-events-pending.ts +35 -1
- package/src/mesh/mesh-queue-assignment.ts +96 -4
- package/src/mesh/mesh-reconcile-loop.ts +69 -1
- package/src/mesh/mesh-runtime-store.ts +22 -0
- package/src/mesh/mesh-work-queue.ts +36 -3
- package/src/providers/cli-provider-instance.ts +46 -0
- package/src/providers/contracts.ts +47 -0
- package/src/providers/provider-schema.ts +6 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +29 -0
- package/src/repo-mesh-types.ts +10 -1
- package/src/shared-types.ts +4 -0
- package/src/status/snapshot.ts +4 -0
package/dist/index.mjs
CHANGED
|
@@ -404,10 +404,10 @@ function readInjected(value) {
|
|
|
404
404
|
}
|
|
405
405
|
function getDaemonBuildInfo() {
|
|
406
406
|
if (cached) return cached;
|
|
407
|
-
const commit = readInjected(true ? "
|
|
408
|
-
const commitShort = readInjected(true ? "
|
|
409
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
410
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
407
|
+
const commit = readInjected(true ? "ddf2eb6eafcf949165edfda2c3cf7c77597fa6f8" : void 0) ?? "unknown";
|
|
408
|
+
const commitShort = readInjected(true ? "ddf2eb6e" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
409
|
+
const version = readInjected(true ? "0.9.82-rc.485" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
410
|
+
const builtAt = readInjected(true ? "2026-07-08T15:14:11.978Z" : void 0);
|
|
411
411
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
412
412
|
return cached;
|
|
413
413
|
}
|
|
@@ -2765,12 +2765,45 @@ function summarizeGitShape(status) {
|
|
|
2765
2765
|
submodules
|
|
2766
2766
|
};
|
|
2767
2767
|
}
|
|
2768
|
-
|
|
2768
|
+
function isMeshTaskDifficulty(value) {
|
|
2769
|
+
return typeof value === "string" && MESH_TASK_DIFFICULTIES.includes(value);
|
|
2770
|
+
}
|
|
2771
|
+
function normalizeThinkingLevel(value) {
|
|
2772
|
+
const v = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
2773
|
+
return v === "low" || v === "medium" || v === "high" ? v : void 0;
|
|
2774
|
+
}
|
|
2775
|
+
function normalizeBrainSlot(raw) {
|
|
2776
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
2777
|
+
const provider = typeof r.provider === "string" ? r.provider.trim() : "";
|
|
2778
|
+
const model = typeof r.model === "string" ? r.model.trim() : "";
|
|
2779
|
+
const thinkingLevel = normalizeThinkingLevel(r.thinkingLevel);
|
|
2780
|
+
return {
|
|
2781
|
+
...provider ? { provider } : {},
|
|
2782
|
+
...model ? { model } : {},
|
|
2783
|
+
...thinkingLevel ? { thinkingLevel } : {}
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
function normalizeDifficultyBrainMap(raw) {
|
|
2787
|
+
const out = {};
|
|
2788
|
+
if (!raw || typeof raw !== "object") return out;
|
|
2789
|
+
for (const key2 of MESH_TASK_DIFFICULTIES) {
|
|
2790
|
+
const slot = normalizeBrainSlot(raw[key2]);
|
|
2791
|
+
if (slot.provider || slot.model || slot.thinkingLevel) out[key2] = slot;
|
|
2792
|
+
}
|
|
2793
|
+
return out;
|
|
2794
|
+
}
|
|
2795
|
+
var DAEMON_ID_PREFIXES, MAGI_RAW_ANSWER_CAP, MESH_TASK_DIFFICULTIES, DEFAULT_DIFFICULTY_BRAINS, CANONICAL_MESH_TOOL_NAMES, CANONICAL_MESH_TOOL_COUNT;
|
|
2769
2796
|
var init_dist = __esm({
|
|
2770
2797
|
"../mesh-shared/dist/index.mjs"() {
|
|
2771
2798
|
"use strict";
|
|
2772
2799
|
DAEMON_ID_PREFIXES = ["daemon_", "standalone_"];
|
|
2773
2800
|
MAGI_RAW_ANSWER_CAP = 4e3;
|
|
2801
|
+
MESH_TASK_DIFFICULTIES = ["easy", "medium", "difficult", "freeform"];
|
|
2802
|
+
DEFAULT_DIFFICULTY_BRAINS = {
|
|
2803
|
+
easy: { model: "haiku", thinkingLevel: "low" },
|
|
2804
|
+
medium: { model: "sonnet", thinkingLevel: "medium" },
|
|
2805
|
+
difficult: { model: "opus", thinkingLevel: "high" }
|
|
2806
|
+
};
|
|
2774
2807
|
CANONICAL_MESH_TOOL_NAMES = [
|
|
2775
2808
|
"mesh_status",
|
|
2776
2809
|
"mesh_list_nodes",
|
|
@@ -2911,6 +2944,7 @@ __export(mesh_config_exports, {
|
|
|
2911
2944
|
createMesh: () => createMesh,
|
|
2912
2945
|
createMeshHostPairingToken: () => createMeshHostPairingToken,
|
|
2913
2946
|
deleteMesh: () => deleteMesh,
|
|
2947
|
+
getDifficultyBrains: () => getDifficultyBrains,
|
|
2914
2948
|
getMagiKindPanel: () => getMagiKindPanel,
|
|
2915
2949
|
getMesh: () => getMesh,
|
|
2916
2950
|
getMeshByRepo: () => getMeshByRepo,
|
|
@@ -2921,6 +2955,7 @@ __export(mesh_config_exports, {
|
|
|
2921
2955
|
normalizeRepoIdentity: () => normalizeRepoIdentity,
|
|
2922
2956
|
removeMagiKindPanel: () => removeMagiKindPanel,
|
|
2923
2957
|
removeNode: () => removeNode,
|
|
2958
|
+
setDifficultyBrains: () => setDifficultyBrains,
|
|
2924
2959
|
setMagiKindPanel: () => setMagiKindPanel,
|
|
2925
2960
|
tokenIdForManualPairing: () => tokenIdForManualPairing,
|
|
2926
2961
|
updateMesh: () => updateMesh,
|
|
@@ -3399,12 +3434,26 @@ function removeMagiKindPanel(kind) {
|
|
|
3399
3434
|
saveMeshConfig(stored);
|
|
3400
3435
|
return true;
|
|
3401
3436
|
}
|
|
3437
|
+
function getDifficultyBrains() {
|
|
3438
|
+
const stored = loadMeshConfig().difficultyBrains;
|
|
3439
|
+
const normalized = normalizeDifficultyBrainMap(stored);
|
|
3440
|
+
return Object.keys(normalized).length > 0 ? normalized : { ...DEFAULT_DIFFICULTY_BRAINS };
|
|
3441
|
+
}
|
|
3442
|
+
function setDifficultyBrains(map) {
|
|
3443
|
+
const normalized = normalizeDifficultyBrainMap(map);
|
|
3444
|
+
const stored = loadMeshConfig();
|
|
3445
|
+
if (Object.keys(normalized).length > 0) stored.difficultyBrains = normalized;
|
|
3446
|
+
else delete stored.difficultyBrains;
|
|
3447
|
+
saveMeshConfig(stored);
|
|
3448
|
+
return normalized;
|
|
3449
|
+
}
|
|
3402
3450
|
var mergeMeshPolicy, MAGI_KIND_PANEL_KINDS, MAX_MAGI_KIND_SLOTS;
|
|
3403
3451
|
var init_mesh_config = __esm({
|
|
3404
3452
|
"src/config/mesh-config.ts"() {
|
|
3405
3453
|
"use strict";
|
|
3406
3454
|
init_hash();
|
|
3407
3455
|
init_config();
|
|
3456
|
+
init_dist();
|
|
3408
3457
|
init_repo_mesh_types();
|
|
3409
3458
|
init_mesh_host_ownership();
|
|
3410
3459
|
mergeMeshPolicy = mergeAndNormalizePolicy;
|
|
@@ -3504,6 +3553,7 @@ Default branch: \`${mesh.defaultBranch}\`` : ""}`);
|
|
|
3504
3553
|
if (operatingNotes) sections.push(operatingNotes);
|
|
3505
3554
|
}
|
|
3506
3555
|
sections.push(buildPolicySection(mergeAndNormalizePolicy(void 0, mesh.policy)));
|
|
3556
|
+
sections.push(buildBrainPresetsSection());
|
|
3507
3557
|
sections.push(TOOLS_SECTION);
|
|
3508
3558
|
sections.push(TOOL_EXPOSURE_PREFLIGHT_SECTION);
|
|
3509
3559
|
sections.push(WORKFLOW_SECTION);
|
|
@@ -3692,6 +3742,34 @@ function truncateNote(text) {
|
|
|
3692
3742
|
if (text.length <= OPERATING_NOTE_MAX_CHARS) return text;
|
|
3693
3743
|
return `${text.slice(0, OPERATING_NOTE_MAX_CHARS).trimEnd()}\u2026 [truncated]`;
|
|
3694
3744
|
}
|
|
3745
|
+
function buildBrainPresetsSection() {
|
|
3746
|
+
let brains;
|
|
3747
|
+
try {
|
|
3748
|
+
brains = getDifficultyBrains();
|
|
3749
|
+
} catch {
|
|
3750
|
+
brains = {};
|
|
3751
|
+
}
|
|
3752
|
+
const lines = [
|
|
3753
|
+
"## Brain presets",
|
|
3754
|
+
"",
|
|
3755
|
+
"When you pass `difficulty` on `mesh_enqueue_task`, it resolves to this model / thinking level (an explicit model/thinkingLevel on the task overrides it). Pick easy for trivial work to save tokens, difficult for hard reasoning.",
|
|
3756
|
+
""
|
|
3757
|
+
];
|
|
3758
|
+
for (const key2 of MESH_TASK_DIFFICULTIES) {
|
|
3759
|
+
const slot = brains[key2];
|
|
3760
|
+
if (!slot || !slot.provider && !slot.model && !slot.thinkingLevel) {
|
|
3761
|
+
lines.push(`- **${key2}**: (no preset \u2014 ordinary routing)`);
|
|
3762
|
+
continue;
|
|
3763
|
+
}
|
|
3764
|
+
const parts = [
|
|
3765
|
+
slot.provider ? `provider: \`${slot.provider}\`` : "",
|
|
3766
|
+
slot.model ? `model: \`${slot.model}\`` : "",
|
|
3767
|
+
slot.thinkingLevel ? `thinking: \`${slot.thinkingLevel}\`` : ""
|
|
3768
|
+
].filter(Boolean).join(" | ");
|
|
3769
|
+
lines.push(`- **${key2}**: ${parts}`);
|
|
3770
|
+
}
|
|
3771
|
+
return lines.join("\n");
|
|
3772
|
+
}
|
|
3695
3773
|
function buildPolicySection(policy) {
|
|
3696
3774
|
const rules = [];
|
|
3697
3775
|
if (policy.requirePreTaskCheckpoint) rules.push("- Create a git checkpoint **before** starting each task");
|
|
@@ -3720,6 +3798,7 @@ function buildRulesSection(coordinatorCliType) {
|
|
|
3720
3798
|
- **Front-load task messages.** Include everything the agent needs (files, problem, expected fix) in \`mesh_enqueue_task\` / \`mesh_send_task\`. Append a structured result request at the end: ask the worker to conclude with a JSON block containing \`status\`, \`changedFiles\`, \`gitStatus\`, \`validationResults\`, \`errors\`, \`nextAction\`. The daemon parses this automatically; you can read it from \`mesh_task_history\`.
|
|
3721
3799
|
- **Reuse idle sessions.** For follow-up, retry, commit/push, or cleanup on the same issue, send only the delta to the existing idle session. Start fresh only for independent work, provider mismatch, transcript contamination, or required worktree isolation.
|
|
3722
3800
|
- **Worktree affinity.** A worktree is a durable per-branch workspace; keep all of a branch's code_change/fix/review work on its worktree node by targeting \`required_tags: ["worktree=<branch>"]\` or \`target_node_id\`. Get the id/branch from the \`mesh_clone_node\` result or a live \`mesh_status\` \u2014 the Configured Nodes snapshot won't list a worktree cloned after launch. Untargeted same-branch follow-ups drift to the base node. Only \`convergence\` (merge/push) runs on the base, never pinned to the worktree.
|
|
3801
|
+
- **Classify task difficulty to save tokens.** For each task you enqueue, judge its execution difficulty and pass \`difficulty\`: \`easy\` (extraction, renames, doc tweaks, trivial fixes), \`medium\` (ordinary feature/bugfix work), \`difficult\` (architecture, tricky debugging, multi-file refactors, subtle reasoning), or \`freeform\`. The mesh's per-difficulty brain preset then runs easy tasks on a cheaper model at low reasoning effort and hard tasks on a stronger model at high effort \u2014 real token savings on simple work. The current presets are shown in the "Brain presets" section below. You may still pass an explicit \`model\`/\`thinkingLevel\` to override the preset for one task.
|
|
3723
3802
|
- **Respect explicit provider requests.** Map: Hermes \u2192 \`hermes-cli\`, Claude/Claude Code \u2192 \`claude-cli\`, Codex \u2192 \`codex-cli\`, Gemini \u2192 \`gemini-cli\`, Antigravity \u2192 \`antigravity-cli\`. Never substitute the coordinator's own runtime.
|
|
3724
3803
|
- **Verify via git, not source.** Use \`mesh_git_status\` to confirm side effects. Treat agent summaries as self-reports, not verification.
|
|
3725
3804
|
- **Limit parallelism.** Start with 1\u20132 tasks; scale only on success. Never duplicate a session because \`mesh_read_chat\` shows no final message while tool/terminal activity is ongoing. This caps *concurrent* load \u2014 it does not mean serialize independent work: when a new, independent request arrives and there is headroom under \`maxParallelTasks\`, dispatch it right away rather than waiting for an in-flight task or a user nudge (read-only diagnosis especially, since it has no merge cost).
|
|
@@ -3746,6 +3825,8 @@ var init_coordinator_prompt = __esm({
|
|
|
3746
3825
|
"src/mesh/coordinator-prompt.ts"() {
|
|
3747
3826
|
"use strict";
|
|
3748
3827
|
init_repo_mesh_types();
|
|
3828
|
+
init_mesh_config();
|
|
3829
|
+
init_dist();
|
|
3749
3830
|
PROMPT_SOFT_CAP_BYTES = 60 * 1024;
|
|
3750
3831
|
OPERATING_NOTES_PROMPT_CAP = 20;
|
|
3751
3832
|
OPERATING_NOTE_MAX_CHARS = 300;
|
|
@@ -5741,6 +5822,18 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5741
5822
|
const priority = normalizeMeshTaskPriority(opts?.priority);
|
|
5742
5823
|
const notBefore = resolveNotBefore(opts?.notBefore);
|
|
5743
5824
|
const maxRetries = typeof opts?.maxRetries === "number" && Number.isFinite(opts.maxRetries) && opts.maxRetries >= 0 ? Math.floor(opts.maxRetries) : void 0;
|
|
5825
|
+
let effectiveModel = typeof opts?.model === "string" && opts.model.trim() ? opts.model.trim() : void 0;
|
|
5826
|
+
let effectiveThinkingLevel = typeof opts?.thinkingLevel === "string" && opts.thinkingLevel.trim() ? opts.thinkingLevel.trim() : void 0;
|
|
5827
|
+
if (isMeshTaskDifficulty(opts?.difficulty)) {
|
|
5828
|
+
try {
|
|
5829
|
+
const preset = getDifficultyBrains()[opts.difficulty];
|
|
5830
|
+
if (preset) {
|
|
5831
|
+
if (!effectiveModel && preset.model) effectiveModel = preset.model;
|
|
5832
|
+
if (!effectiveThinkingLevel && preset.thinkingLevel) effectiveThinkingLevel = preset.thinkingLevel;
|
|
5833
|
+
}
|
|
5834
|
+
} catch {
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5744
5837
|
const result = withQueueLock(meshId, () => {
|
|
5745
5838
|
if (MeshRuntimeStore.getInstance().findQueueEntryById(meshId, id)) {
|
|
5746
5839
|
throw new Error(`duplicate_task_id: task '${id}' already exists in mesh '${meshId}'`);
|
|
@@ -5772,7 +5865,8 @@ function enqueueTask(meshId, message, opts) {
|
|
|
5772
5865
|
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
5773
5866
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
5774
5867
|
...typeof opts?.consensusGroupId === "string" && opts.consensusGroupId.trim() ? { consensusGroupId: opts.consensusGroupId.trim() } : {},
|
|
5775
|
-
...
|
|
5868
|
+
...effectiveModel ? { model: effectiveModel } : {},
|
|
5869
|
+
...effectiveThinkingLevel ? { thinkingLevel: effectiveThinkingLevel } : {},
|
|
5776
5870
|
...typeof opts?.sourceCoordinatorSessionId === "string" && opts.sourceCoordinatorSessionId.trim() ? { sourceCoordinatorSessionId: opts.sourceCoordinatorSessionId.trim() } : {},
|
|
5777
5871
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5778
5872
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7346,6 +7440,27 @@ var init_mesh_runtime_store = __esm({
|
|
|
7346
7440
|
`).get(meshId, taskId);
|
|
7347
7441
|
return !!row;
|
|
7348
7442
|
}
|
|
7443
|
+
/**
|
|
7444
|
+
* DELIVERED-NOT-CONSUMED re-drive support: true when at least one delivery record for
|
|
7445
|
+
* the task has reached a CONSUMED status ('acked' / 'completed'). Distinct from
|
|
7446
|
+
* {@link taskHasConfirmedDelivery} ('delivered' | 'acked' | 'completed'): a delivery is
|
|
7447
|
+
* flipped to 'delivered' the instant the transport hands the dispatch off, but only
|
|
7448
|
+
* flipped to 'acked' when the worker's agent:generating_started event arrives (see the
|
|
7449
|
+
* generating_started handler in mesh-event-forwarding) — i.e. when the session has
|
|
7450
|
+
* actually begun the turn. That distinction is the cross-daemon consumption signal the
|
|
7451
|
+
* short-grace re-drive uses: a row whose delivery is 'delivered' but never 'acked' was
|
|
7452
|
+
* handed to a REMOTE worker that never started generating — the remote autoLaunch
|
|
7453
|
+
* delivered≠consumed gap — even when the session's busy verdict is UNKNOWN (not locally
|
|
7454
|
+
* observable). Indexed by (mesh_id, task_id).
|
|
7455
|
+
*/
|
|
7456
|
+
taskDeliveryConsumed(meshId, taskId) {
|
|
7457
|
+
const row = this.db.prepare(`
|
|
7458
|
+
SELECT 1 FROM mesh_session_delivery
|
|
7459
|
+
WHERE mesh_id = ? AND task_id = ? AND status IN ('acked','completed')
|
|
7460
|
+
LIMIT 1
|
|
7461
|
+
`).get(meshId, taskId);
|
|
7462
|
+
return !!row;
|
|
7463
|
+
}
|
|
7349
7464
|
expireStaleSessionDeliveries(meshId) {
|
|
7350
7465
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7351
7466
|
this.db.prepare(`
|
|
@@ -8438,7 +8553,8 @@ function routeV2EventsForDrainer(events, drainer, ctx) {
|
|
|
8438
8553
|
}
|
|
8439
8554
|
if (validated.scope !== "unicast") {
|
|
8440
8555
|
if (validated.scope === "broadcast" && isTerminalTaskEvent(validated.event)) {
|
|
8441
|
-
|
|
8556
|
+
const deliverSelfFallback = event.dispatchedBySelfFallback && daemonIdsEquivalent(validated.dispatchedBy.daemonId, drainer.daemonId);
|
|
8557
|
+
if (deliverSelfFallback || identityDeliversTo(validated.dispatchedBy, drainer)) {
|
|
8442
8558
|
ctx.batchSeen.add(eventId);
|
|
8443
8559
|
bump("v2Delivered");
|
|
8444
8560
|
kept.push(event);
|
|
@@ -8710,13 +8826,15 @@ function stampPendingEventV2(event, hint) {
|
|
|
8710
8826
|
scope: hint?.scope ?? (selfFallback ? "broadcast" : void 0)
|
|
8711
8827
|
});
|
|
8712
8828
|
if (!stamp) return event;
|
|
8829
|
+
const dispatchedBySelfFallback = selfFallback && stamp.scope === "broadcast";
|
|
8713
8830
|
return {
|
|
8714
8831
|
...event,
|
|
8715
8832
|
protocolVersion: stamp.protocolVersion,
|
|
8716
8833
|
eventId: stamp.eventId,
|
|
8717
8834
|
scope: stamp.scope,
|
|
8718
8835
|
dispatchedBy: stamp.dispatchedBy,
|
|
8719
|
-
...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {}
|
|
8836
|
+
...stamp.intendedFor ? { intendedFor: stamp.intendedFor } : {},
|
|
8837
|
+
...dispatchedBySelfFallback ? { dispatchedBySelfFallback: true } : {}
|
|
8720
8838
|
};
|
|
8721
8839
|
}
|
|
8722
8840
|
function readCoordinatorIdentityFromWire(raw) {
|
|
@@ -15240,6 +15358,24 @@ function getMeshWithCache(components, meshId) {
|
|
|
15240
15358
|
if (!cachedMesh) return localMesh;
|
|
15241
15359
|
return mergeInlineCacheOnlyNodes(localMesh, cachedMesh);
|
|
15242
15360
|
}
|
|
15361
|
+
function bootstrapEpochMs(bootstrap) {
|
|
15362
|
+
const raw = readNonEmptyString2(bootstrap?.startedAt) || readNonEmptyString2(bootstrap?.completedAt);
|
|
15363
|
+
if (!raw) return 0;
|
|
15364
|
+
const parsed = Date.parse(raw);
|
|
15365
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
15366
|
+
}
|
|
15367
|
+
function inlineBootstrapIsFresher(inlineBootstrap, configBootstrap) {
|
|
15368
|
+
const inlineStatus = readNonEmptyString2(inlineBootstrap?.status);
|
|
15369
|
+
if (!inlineStatus) return false;
|
|
15370
|
+
const configStatus = readNonEmptyString2(configBootstrap?.status);
|
|
15371
|
+
const inlineTerminal = BOOTSTRAP_TERMINAL_STATUSES.has(inlineStatus);
|
|
15372
|
+
const configTerminal = !!configStatus && BOOTSTRAP_TERMINAL_STATUSES.has(configStatus);
|
|
15373
|
+
if (configTerminal) {
|
|
15374
|
+
return inlineTerminal && inlineStatus !== configStatus && bootstrapEpochMs(inlineBootstrap) > bootstrapEpochMs(configBootstrap);
|
|
15375
|
+
}
|
|
15376
|
+
if (inlineTerminal) return true;
|
|
15377
|
+
return bootstrapEpochMs(inlineBootstrap) > bootstrapEpochMs(configBootstrap);
|
|
15378
|
+
}
|
|
15243
15379
|
function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
|
|
15244
15380
|
const localNodes = Array.isArray(localMesh?.nodes) ? localMesh.nodes : [];
|
|
15245
15381
|
const cachedNodes = Array.isArray(cachedMesh?.nodes) ? cachedMesh.nodes : [];
|
|
@@ -15249,8 +15385,23 @@ function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
|
|
|
15249
15385
|
if (!cachedId) return false;
|
|
15250
15386
|
return !localNodes.some((localNode) => meshNodeIdMatches(localNode, cachedId));
|
|
15251
15387
|
});
|
|
15252
|
-
|
|
15253
|
-
|
|
15388
|
+
let overlaidLocalNodes = localNodes;
|
|
15389
|
+
let overlaid = false;
|
|
15390
|
+
for (let i = 0; i < localNodes.length; i++) {
|
|
15391
|
+
const localNode = localNodes[i];
|
|
15392
|
+
const localId = readMeshNodeId(localNode);
|
|
15393
|
+
if (!localId) continue;
|
|
15394
|
+
const inlineMatch = cachedNodes.find((cachedNode) => meshNodeIdMatches(cachedNode, localId));
|
|
15395
|
+
if (!inlineMatch) continue;
|
|
15396
|
+
if (!inlineBootstrapIsFresher(inlineMatch.worktreeBootstrap, localNode.worktreeBootstrap)) continue;
|
|
15397
|
+
if (!overlaid) {
|
|
15398
|
+
overlaidLocalNodes = [...localNodes];
|
|
15399
|
+
overlaid = true;
|
|
15400
|
+
}
|
|
15401
|
+
overlaidLocalNodes[i] = { ...localNode, worktreeBootstrap: inlineMatch.worktreeBootstrap };
|
|
15402
|
+
}
|
|
15403
|
+
if (!cacheOnly.length && !overlaid) return localMesh;
|
|
15404
|
+
return { ...localMesh, nodes: [...overlaidLocalNodes, ...cacheOnly] };
|
|
15254
15405
|
}
|
|
15255
15406
|
function warnDispatchWarmupGetterMissingOnce(daemonId) {
|
|
15256
15407
|
if (dispatchWarmupGetterMissingWarned.has(daemonId)) return;
|
|
@@ -16120,7 +16271,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16120
16271
|
settings: remoteSettings,
|
|
16121
16272
|
// MAGI-KIND-PANEL model axis: forward the task's model override so the
|
|
16122
16273
|
// remote worker session launches with it (initialModel). Best-effort.
|
|
16123
|
-
...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
|
|
16274
|
+
...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {},
|
|
16275
|
+
// BRAIN-ROUTING thinking axis: forward the task's thinking level (initialThinkingLevel).
|
|
16276
|
+
...typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? { initialThinkingLevel: task.thinkingLevel.trim() } : {}
|
|
16124
16277
|
});
|
|
16125
16278
|
} catch (e) {
|
|
16126
16279
|
markAutoLaunch(meshId, task.id, { status: "failed", reason: `remote_launch_dispatch_failed: ${e?.message || String(e)}`, nodeId, providerType: resolved.providerType });
|
|
@@ -16149,7 +16302,9 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
16149
16302
|
settings: launchSettings,
|
|
16150
16303
|
// MAGI-KIND-PANEL model axis: local launch forwards the task's model
|
|
16151
16304
|
// override as initialModel (CLI → modelLaunchArgs; ACP → setConfigOption).
|
|
16152
|
-
...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {}
|
|
16305
|
+
...typeof task.model === "string" && task.model.trim() ? { initialModel: task.model.trim() } : {},
|
|
16306
|
+
// BRAIN-ROUTING thinking axis: forward the task's thinking level (initialThinkingLevel).
|
|
16307
|
+
...typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? { initialThinkingLevel: task.thinkingLevel.trim() } : {}
|
|
16153
16308
|
});
|
|
16154
16309
|
if (!launchResult?.success) {
|
|
16155
16310
|
const reason = launchResult?.error || "launch_cli_failed";
|
|
@@ -16387,7 +16542,7 @@ function runIdleMaintenanceThenAssignQueue(components, args) {
|
|
|
16387
16542
|
});
|
|
16388
16543
|
});
|
|
16389
16544
|
}
|
|
16390
|
-
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, LOCAL_LAUNCH_READY_TIMEOUT_MS, LOCAL_LAUNCH_READY_POLL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, AUTO_LAUNCH_AWAIT_CLAIM_BACKOFF_CAP_CYCLES, AUTO_LAUNCH_REMOTE_IDLE_TTL_MS, autoLaunchAwaitClaimBackoff, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, ACTIONABLE_SKIP_REASON_PREFIXES, TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON, lastActionableSkipNotified;
|
|
16545
|
+
var IDLE_AUTO_FAST_FORWARD_THROTTLE_MS, idleAutoFastForwardLastAttempt, BOOTSTRAP_TERMINAL_STATUSES, DISPATCH_CONFIRM_TIMEOUT_MS, DISPATCH_CONNECT_TIMEOUT_MS, dispatchWarmupGetterMissingWarned, LOCAL_LAUNCH_READY_TIMEOUT_MS, LOCAL_LAUNCH_READY_POLL_MS, autoLaunchInProgress, autoLaunchCooldownUntil, AUTO_LAUNCH_COOLDOWN_MS, AUTO_LAUNCH_AWAIT_CLAIM_MS, AUTO_LAUNCH_AWAIT_CLAIM_BACKOFF_CAP_CYCLES, AUTO_LAUNCH_REMOTE_IDLE_TTL_MS, autoLaunchAwaitClaimBackoff, lastAutoLaunchLedgerKey, AUTO_LAUNCH_LEDGER_DEDUP_MAX, ACTIONABLE_SKIP_REASON_PREFIXES, TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON, lastActionableSkipNotified;
|
|
16391
16546
|
var init_mesh_queue_assignment = __esm({
|
|
16392
16547
|
"src/mesh/mesh-queue-assignment.ts"() {
|
|
16393
16548
|
"use strict";
|
|
@@ -16414,6 +16569,7 @@ var init_mesh_queue_assignment = __esm({
|
|
|
16414
16569
|
init_mesh_task_inflight();
|
|
16415
16570
|
IDLE_AUTO_FAST_FORWARD_THROTTLE_MS = 30 * 60 * 1e3;
|
|
16416
16571
|
idleAutoFastForwardLastAttempt = /* @__PURE__ */ new Map();
|
|
16572
|
+
BOOTSTRAP_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["complete", "failed"]);
|
|
16417
16573
|
DISPATCH_CONFIRM_TIMEOUT_MS = 12e4;
|
|
16418
16574
|
DISPATCH_CONNECT_TIMEOUT_MS = MESH_CONNECT_TIMEOUT_MS;
|
|
16419
16575
|
dispatchWarmupGetterMissingWarned = /* @__PURE__ */ new Set();
|
|
@@ -18709,6 +18865,8 @@ function buildAvailableProviders(providerLoader) {
|
|
|
18709
18865
|
...sourceLayer ? { sourceLayer } : {},
|
|
18710
18866
|
...sourceName ? { sourceName } : {},
|
|
18711
18867
|
...provider.providerVersion ? { providerVersion: provider.providerVersion } : {},
|
|
18868
|
+
...Array.isArray(provider.modelOptions) && provider.modelOptions.length ? { modelOptions: provider.modelOptions } : {},
|
|
18869
|
+
...Array.isArray(provider.thinkingLevelOptions) && provider.thinkingLevelOptions.length ? { thinkingLevelOptions: provider.thinkingLevelOptions } : {},
|
|
18712
18870
|
...provider.binary ? { binary: provider.binary } : {},
|
|
18713
18871
|
...provider.status ? { status: provider.status } : {},
|
|
18714
18872
|
...provider.details ? { details: provider.details } : {},
|
|
@@ -21045,7 +21203,34 @@ function recoverStrandedAssignedDispatches(components, meshId, store) {
|
|
|
21045
21203
|
for (const row of assigned) {
|
|
21046
21204
|
const dispatchedAtMs = Date.parse(row.dispatchTimestamp ?? "");
|
|
21047
21205
|
if (!Number.isFinite(dispatchedAtMs)) continue;
|
|
21048
|
-
|
|
21206
|
+
const ageMs = nowMs - dispatchedAtMs;
|
|
21207
|
+
if (ageMs >= ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS && ageMs < ASSIGNED_STRANDED_DEADLINE_MS && store.taskHasConfirmedDelivery(meshId, row.id) && !store.taskDeliveryConsumed(meshId, row.id)) {
|
|
21208
|
+
const terminal2 = findTerminalLedgerEvidenceForTask({ meshId, taskId: row.id });
|
|
21209
|
+
if (terminal2) {
|
|
21210
|
+
const status = terminal2.kind === "task_completed" ? "completed" : "failed";
|
|
21211
|
+
updateTaskStatus(meshId, row.id, status);
|
|
21212
|
+
continue;
|
|
21213
|
+
}
|
|
21214
|
+
const verdict = row.assignedSessionId ? resolveSessionBusyVerdict(components, row.assignedSessionId) : "IDLE_CONFIRMED";
|
|
21215
|
+
if (verdict !== "GENERATING") {
|
|
21216
|
+
const redriven = reclaimStrandedAssignedTask(meshId, row.id, {
|
|
21217
|
+
reason: "delivered_not_consumed_redrive",
|
|
21218
|
+
ageMs
|
|
21219
|
+
});
|
|
21220
|
+
if (redriven) {
|
|
21221
|
+
LOG.warn("MeshReconcile", `Re-drove delivered-but-unconsumed task ${row.id} on mesh ${meshId} (node=${row.assignedNodeId ?? "?"} session=${row.assignedSessionId ?? "?"}, delivered but no generating_started in ${Math.round(ageMs / 1e3)}s, verdict ${verdict} \u2192 ${redriven.status})`);
|
|
21222
|
+
traceMeshEventDrop("assigned_delivered_not_consumed_redrive", {
|
|
21223
|
+
taskId: row.id,
|
|
21224
|
+
sessionId: row.assignedSessionId,
|
|
21225
|
+
nodeId: row.assignedNodeId,
|
|
21226
|
+
meshId,
|
|
21227
|
+
event: "agent:generating_started"
|
|
21228
|
+
}, `delivered_not_consumed ${Math.round(ageMs / 1e3)}s \u2192 ${redriven.status}`);
|
|
21229
|
+
continue;
|
|
21230
|
+
}
|
|
21231
|
+
}
|
|
21232
|
+
}
|
|
21233
|
+
if (ageMs < ASSIGNED_STRANDED_DEADLINE_MS) continue;
|
|
21049
21234
|
const terminal = findTerminalLedgerEvidenceForTask({
|
|
21050
21235
|
meshId,
|
|
21051
21236
|
taskId: row.id
|
|
@@ -21560,7 +21745,7 @@ function setupMeshReconcileLoop(components) {
|
|
|
21560
21745
|
}
|
|
21561
21746
|
};
|
|
21562
21747
|
}
|
|
21563
|
-
var coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
|
|
21748
|
+
var coordinatorModalParkState, heldEventLedgerRecorded, ASSIGNED_STRANDED_DEADLINE_MS, DELIVERED_NO_TURN_DEADLINE_MS, ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS, RECLAIM_UNKNOWN_GRACE_TICKS, deliveredNoTurnUnknownStreak, ZOMBIE_ASSIGNED_MIN_AGE_MS, STRICT_SESSION_MATCH_TTL_MS, unresolvedForwardRejectionCounts, MAX_FORWARD_REJECTIONS, UNRESOLVED_FORWARD_NUDGE_DELAY_MS, unresolvedForwardNudgeTimer, unresolvedForwardNudgeRunning;
|
|
21564
21749
|
var init_mesh_reconcile_loop = __esm({
|
|
21565
21750
|
"src/mesh/mesh-reconcile-loop.ts"() {
|
|
21566
21751
|
"use strict";
|
|
@@ -21590,6 +21775,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
21590
21775
|
heldEventLedgerRecorded = /* @__PURE__ */ new Set();
|
|
21591
21776
|
ASSIGNED_STRANDED_DEADLINE_MS = 5 * 6e4;
|
|
21592
21777
|
DELIVERED_NO_TURN_DEADLINE_MS = 15 * 6e4;
|
|
21778
|
+
ASSIGNED_DELIVERED_UNCONSUMED_REDRIVE_MS = 25e3;
|
|
21593
21779
|
RECLAIM_UNKNOWN_GRACE_TICKS = 3;
|
|
21594
21780
|
deliveredNoTurnUnknownStreak = /* @__PURE__ */ new Map();
|
|
21595
21781
|
ZOMBIE_ASSIGNED_MIN_AGE_MS = 30 * 60 * 1e3;
|
|
@@ -21865,6 +22051,35 @@ var init_provider_schema = __esm({
|
|
|
21865
22051
|
items: { type: "string" },
|
|
21866
22052
|
description: "Template for expanding an initialModel selection into launch args. '{{model}}' is substituted with the model string (e.g. ['--model', '{{model}}'] \u2192 --model opus). Applied at launch when a model is requested for this CLI provider (MAGI kind-panel model axis). Absent \u2192 no launch-time model selection."
|
|
21867
22053
|
},
|
|
22054
|
+
modelOptions: {
|
|
22055
|
+
type: "array",
|
|
22056
|
+
items: { type: "string" },
|
|
22057
|
+
description: "Suggested model values shown as dropdown options in the new-session dialog (brain-routing model axis), e.g. ['opus','sonnet','haiku']. Advisory \u2014 the UI still accepts free text, so a stale list never blocks an accepted model."
|
|
22058
|
+
},
|
|
22059
|
+
thinkingLaunchArgs: {
|
|
22060
|
+
type: "array",
|
|
22061
|
+
items: { type: "string" },
|
|
22062
|
+
description: "Template for expanding an initialThinkingLevel selection into launch args (brain-routing thinking axis, parallel to modelLaunchArgs). '{{level}}' is substituted with the provider-mapped reasoning-effort value (e.g. ['--effort', '{{level}}'] \u2192 --effort high; ['-c', 'model_reasoning_effort={{level}}']). Applied at launch when a thinking level is requested. Absent \u2192 no launch-time thinking selection."
|
|
22063
|
+
},
|
|
22064
|
+
thinkingLevelMap: {
|
|
22065
|
+
type: "object",
|
|
22066
|
+
properties: {
|
|
22067
|
+
low: { type: "string" },
|
|
22068
|
+
medium: { type: "string" },
|
|
22069
|
+
high: { type: "string" }
|
|
22070
|
+
},
|
|
22071
|
+
additionalProperties: false,
|
|
22072
|
+
description: "Optional map from the standard thinking levels (low/medium/high) to this provider's own reasoning-effort vocabulary, used to fill {{level}} in thinkingLaunchArgs. A level absent from the map passes through unchanged."
|
|
22073
|
+
},
|
|
22074
|
+
thinkingLevelOptions: {
|
|
22075
|
+
type: "array",
|
|
22076
|
+
items: { type: "string" },
|
|
22077
|
+
description: "Reasoning-effort values this provider accepts, shown as the thinking-level dropdown in the new-session dialog (e.g. ['low','medium','high','max']). Absent \u2192 the UI falls back to standard low/medium/high. Provider's own vocabulary, passed through verbatim."
|
|
22078
|
+
},
|
|
22079
|
+
thinkingControlId: {
|
|
22080
|
+
type: "string",
|
|
22081
|
+
description: "For a provider with no thinkingLaunchArgs but a runtime reasoning-effort control (e.g. hermes 'reasoning'), the controls[].id to drive at launch for the thinking level. The control's setScript is invoked with { value: <mapped level> }."
|
|
22082
|
+
},
|
|
21868
22083
|
scriptCallBudgetMs: {
|
|
21869
22084
|
type: "integer",
|
|
21870
22085
|
minimum: 1,
|
|
@@ -25299,6 +25514,13 @@ var init_provider_cli_adapter = __esm({
|
|
|
25299
25514
|
lastScreenSnapshot = "";
|
|
25300
25515
|
lastScreenText = "";
|
|
25301
25516
|
lastScreenSnapshotReadAt = Number.NEGATIVE_INFINITY;
|
|
25517
|
+
// (FALSEIDLE Path-C) Count of CONSECUTIVE getStatus polls that observed a
|
|
25518
|
+
// gate-eligible static-idle screen (detect=idle, no modal, quiet, empty
|
|
25519
|
+
// partial buffer). For a mesh/autonomous worker we require several such
|
|
25520
|
+
// polls in a row before confirming static-idle (see getStatus), so a
|
|
25521
|
+
// single momentarily-silent point-sample of a still-live turn cannot flip
|
|
25522
|
+
// it. Reset to 0 the instant any poll is ineligible.
|
|
25523
|
+
staticIdlePollStreak = 0;
|
|
25302
25524
|
// Server log forwarding
|
|
25303
25525
|
serverConn = null;
|
|
25304
25526
|
logBuffer = [];
|
|
@@ -25364,6 +25586,13 @@ var init_provider_cli_adapter = __esm({
|
|
|
25364
25586
|
static MAX_ACCUMULATED_BUFFER = 262144;
|
|
25365
25587
|
parsedStatusCache = null;
|
|
25366
25588
|
static SCREEN_SNAPSHOT_MIN_INTERVAL_MS = 250;
|
|
25589
|
+
// (FALSEIDLE Path-C) Consecutive gate-eligible getStatus polls a mesh/autonomous
|
|
25590
|
+
// session must show before the poll-static-idle confirm fires. 2 = one extra
|
|
25591
|
+
// status tick of hysteresis: enough to reject a single momentary-silence
|
|
25592
|
+
// point-sample of a still-live turn, cheap enough not to materially delay a
|
|
25593
|
+
// genuine boot-wedge release (the wedge screen is stably static, so it clears
|
|
25594
|
+
// every consecutive poll and confirms on the 2nd).
|
|
25595
|
+
static STATIC_IDLE_POLL_CONFIRM_COUNT = 2;
|
|
25367
25596
|
providerResolutionMeta;
|
|
25368
25597
|
getBufferState() {
|
|
25369
25598
|
const build = (droppedChars, maxChars) => droppedChars > 0 ? { truncated: true, droppedChars, maxChars } : void 0;
|
|
@@ -25435,6 +25664,18 @@ ${lastSnapshot}`;
|
|
|
25435
25664
|
getStatusActivityHoldMs() {
|
|
25436
25665
|
return this.timeouts.statusActivityHold;
|
|
25437
25666
|
}
|
|
25667
|
+
// (FALSEIDLE Path-C) Whether this session is a mesh worker or coordinator's
|
|
25668
|
+
// own autonomous session. Mirrors CliProviderInstance.isAutonomousMeshSession
|
|
25669
|
+
// over the runtimeSettings the instance mirrors down via updateRuntimeSettings
|
|
25670
|
+
// (meshNodeFor / meshActiveTaskId / meshNodeId / launchedByCoordinator =
|
|
25671
|
+
// isMeshWorkerSession, plus meshCoordinatorFor for the coordinator's own turn).
|
|
25672
|
+
// Such a session has no human at the keyboard to correct a premature idle, so
|
|
25673
|
+
// the poll-static-idle confirm is debounced for it (multiple consecutive idle
|
|
25674
|
+
// polls) rather than fired on a single point-sample.
|
|
25675
|
+
isAutonomousMeshSession() {
|
|
25676
|
+
const s2 = this.runtimeSettings;
|
|
25677
|
+
return !!(s2?.meshNodeFor || s2?.meshActiveTaskId || s2?.meshNodeId || s2?.launchedByCoordinator || s2?.meshCoordinatorFor);
|
|
25678
|
+
}
|
|
25438
25679
|
// Resolved timeouts
|
|
25439
25680
|
timeouts;
|
|
25440
25681
|
// Provider approval key mapping
|
|
@@ -25822,14 +26063,27 @@ ${lastSnapshot}`;
|
|
|
25822
26063
|
if (allowParse && this.engine.currentStatus === "generating" && !this.engine.currentTurnScope && !this.engine.activeModal) {
|
|
25823
26064
|
const now = Date.now();
|
|
25824
26065
|
const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
26066
|
+
let eligible = false;
|
|
25825
26067
|
if (quietForMs >= this.getStatusActivityHoldMs()) {
|
|
25826
26068
|
const screenText = this.terminalScreen.getText();
|
|
25827
26069
|
const pollDetect = this.runDetectStatus(screenText || this.recentOutputBuffer);
|
|
25828
26070
|
const pollModal = this.runParseApproval(screenText) || this.runParseApproval(this.recentOutputBuffer);
|
|
25829
|
-
|
|
26071
|
+
const partial = this.getPartialResponse();
|
|
26072
|
+
const partialPending = typeof partial === "string" && partial.trim().length > 0;
|
|
26073
|
+
eligible = pollDetect === "idle" && !pollModal && !partialPending;
|
|
26074
|
+
}
|
|
26075
|
+
if (eligible) {
|
|
26076
|
+
const requiredStreak = this.isAutonomousMeshSession() ? _ProviderCliAdapter.STATIC_IDLE_POLL_CONFIRM_COUNT : 1;
|
|
26077
|
+
this.staticIdlePollStreak += 1;
|
|
26078
|
+
if (this.staticIdlePollStreak >= requiredStreak) {
|
|
25830
26079
|
this.engine.confirmPollStaticIdle("poll_static_idle");
|
|
26080
|
+
this.staticIdlePollStreak = 0;
|
|
25831
26081
|
}
|
|
26082
|
+
} else {
|
|
26083
|
+
this.staticIdlePollStreak = 0;
|
|
25832
26084
|
}
|
|
26085
|
+
} else {
|
|
26086
|
+
this.staticIdlePollStreak = 0;
|
|
25833
26087
|
}
|
|
25834
26088
|
let effectiveStatus = this.projectEffectiveStatus(startupModal);
|
|
25835
26089
|
let effectiveModal = startupModal || this.engine.activeModal;
|
|
@@ -44548,6 +44802,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44548
44802
|
this.presentationMode = "chat";
|
|
44549
44803
|
this.providerSessionId = options?.providerSessionId;
|
|
44550
44804
|
this.launchMode = options?.launchMode || "new";
|
|
44805
|
+
this.initialThinkingLevel = options?.initialThinkingLevel;
|
|
44551
44806
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
44552
44807
|
this.adapter = createCliAdapter(provider, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
44553
44808
|
if (this.providerSessionId) {
|
|
@@ -44769,6 +45024,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44769
45024
|
presentationMode;
|
|
44770
45025
|
providerSessionId;
|
|
44771
45026
|
launchMode;
|
|
45027
|
+
initialThinkingLevel;
|
|
44772
45028
|
startedAt = Date.now();
|
|
44773
45029
|
onProviderSessionResolved;
|
|
44774
45030
|
refreshProviderDefinition(provider) {
|
|
@@ -44797,6 +45053,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
44797
45053
|
});
|
|
44798
45054
|
await this.adapter.spawn();
|
|
44799
45055
|
await this.enforceFreshSessionLaunchIfNeeded();
|
|
45056
|
+
await this.applyInitialThinkingLevelViaControl();
|
|
44800
45057
|
this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
|
|
44801
45058
|
if (this.providerSessionId && this.shouldHydrateExistingProviderHistory()) {
|
|
44802
45059
|
this.restorePersistedHistoryFromCurrentSession();
|
|
@@ -45414,6 +45671,43 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
45414
45671
|
}
|
|
45415
45672
|
this.applyProviderResponse(parsed.payload, { phase: "immediate" });
|
|
45416
45673
|
}
|
|
45674
|
+
/**
|
|
45675
|
+
* BRAIN-ROUTING (runtime-control thinking axis): for a provider that selects
|
|
45676
|
+
* reasoning effort via a runtime control instead of a launch arg (e.g. hermes
|
|
45677
|
+
* `reasoning`), apply the requested initialThinkingLevel after spawn by invoking
|
|
45678
|
+
* that control's setScript. The provider names the control via thinkingControlId.
|
|
45679
|
+
* The standard level is mapped through thinkingLevelMap first (same as the
|
|
45680
|
+
* launch-arg path). Best-effort: any failure logs and never blocks launch.
|
|
45681
|
+
*/
|
|
45682
|
+
async applyInitialThinkingLevelViaControl() {
|
|
45683
|
+
const level = typeof this.initialThinkingLevel === "string" ? this.initialThinkingLevel.trim() : "";
|
|
45684
|
+
if (!level) return;
|
|
45685
|
+
const controlId = this.provider.thinkingControlId;
|
|
45686
|
+
if (!controlId) return;
|
|
45687
|
+
const controls = Array.isArray(this.provider.controls) ? this.provider.controls : [];
|
|
45688
|
+
const control = controls.find((c) => c && c.id === controlId);
|
|
45689
|
+
if (!control || !control.setScript) return;
|
|
45690
|
+
const map = this.provider.thinkingLevelMap;
|
|
45691
|
+
const mapped = map && typeof map[level] === "string" && map[level].trim() ? map[level].trim() : level;
|
|
45692
|
+
try {
|
|
45693
|
+
await waitForCliAdapterReady(this.adapter);
|
|
45694
|
+
const raw = await this.adapter.invokeScript(control.setScript, { value: mapped });
|
|
45695
|
+
const parsed = parseCliScriptResult(raw);
|
|
45696
|
+
if (!parsed.success) {
|
|
45697
|
+
LOG.warn("CLI", `[${this.type}] thinking control '${controlId}' set to '${mapped}' failed: ${parsed.payload?.error || "unknown"}`);
|
|
45698
|
+
return;
|
|
45699
|
+
}
|
|
45700
|
+
const cliCommand = getCliScriptCommand(parsed.payload);
|
|
45701
|
+
if (cliCommand?.type === "send_message" && cliCommand.text) {
|
|
45702
|
+
await this.adapter.sendMessage(cliCommand.text);
|
|
45703
|
+
} else if (cliCommand?.type === "pty_write" && cliCommand.text) {
|
|
45704
|
+
await this.adapter.writeRaw(cliCommand.text + "\r");
|
|
45705
|
+
}
|
|
45706
|
+
LOG.info("CLI", `[${this.type}] applied thinking level '${mapped}' via control '${controlId}'`);
|
|
45707
|
+
} catch (e) {
|
|
45708
|
+
LOG.warn("CLI", `[${this.type}] thinking control apply threw: ${e?.message || e}`);
|
|
45709
|
+
}
|
|
45710
|
+
}
|
|
45417
45711
|
completionHasFinalAssistantMessage(messages, turnStartedAt) {
|
|
45418
45712
|
const visibleMessages = (Array.isArray(messages) ? messages : []).filter((message) => isUserFacingChatMessage(message));
|
|
45419
45713
|
const lastVisible = visibleMessages[visibleMessages.length - 1];
|
|
@@ -48525,7 +48819,13 @@ function expandResumeArgs(template, sessionId) {
|
|
|
48525
48819
|
function expandModelLaunchArgs(template, model) {
|
|
48526
48820
|
const m = typeof model === "string" ? model.trim() : "";
|
|
48527
48821
|
if (!m || !Array.isArray(template) || template.length === 0) return void 0;
|
|
48528
|
-
return template.map((part) => part
|
|
48822
|
+
return template.map((part) => part.includes("{{model}}") ? part.split("{{model}}").join(m) : part);
|
|
48823
|
+
}
|
|
48824
|
+
function expandThinkingLaunchArgs(template, level, levelMap) {
|
|
48825
|
+
const raw = typeof level === "string" ? level.trim() : "";
|
|
48826
|
+
if (!raw || !Array.isArray(template) || template.length === 0) return void 0;
|
|
48827
|
+
const mapped = levelMap && typeof levelMap[raw] === "string" && levelMap[raw].trim() ? levelMap[raw].trim() : raw;
|
|
48828
|
+
return template.map((part) => part.includes("{{level}}") ? part.replace("{{level}}", mapped) : part);
|
|
48529
48829
|
}
|
|
48530
48830
|
function readSubcommandSessionId(args, subcommands) {
|
|
48531
48831
|
const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
|
|
@@ -48909,6 +49209,15 @@ ${installInfo}`
|
|
|
48909
49209
|
LOG.warn("CLI", `[ACP] Initial model set failed: ${e?.message}`);
|
|
48910
49210
|
}
|
|
48911
49211
|
}
|
|
49212
|
+
if (options?.initialThinkingLevel) {
|
|
49213
|
+
const lvl = options.initialThinkingLevel;
|
|
49214
|
+
try {
|
|
49215
|
+
await acpInstance.setConfigOption("thought_level", lvl);
|
|
49216
|
+
console.log(colorize("green", ` \u{1F9E0} Initial thinking level set: ${lvl}`));
|
|
49217
|
+
} catch (e) {
|
|
49218
|
+
LOG.warn("CLI", `[ACP] Initial thinking level set failed (provider may not support thought_level): ${e?.message}`);
|
|
49219
|
+
}
|
|
49220
|
+
}
|
|
48912
49221
|
this.persistRecentActivity({
|
|
48913
49222
|
kind: "acp",
|
|
48914
49223
|
providerType: normalizedType,
|
|
@@ -48944,7 +49253,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
48944
49253
|
if (initialModel && !modelLaunchArgs) {
|
|
48945
49254
|
LOG.warn("CLI", `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template \u2014 launching without model selection.`);
|
|
48946
49255
|
}
|
|
48947
|
-
const
|
|
49256
|
+
const initialThinkingLevel = options?.initialThinkingLevel;
|
|
49257
|
+
const thinkingLaunchArgs = expandThinkingLaunchArgs(provider?.thinkingLaunchArgs, initialThinkingLevel, provider?.thinkingLevelMap);
|
|
49258
|
+
const cliArgsWithBrain = thinkingLaunchArgs ? [...thinkingLaunchArgs, ...cliArgsWithModel || []] : cliArgsWithModel;
|
|
49259
|
+
if (initialThinkingLevel && !thinkingLaunchArgs) {
|
|
49260
|
+
LOG.warn("CLI", `[${normalizedType}] initialThinkingLevel='${initialThinkingLevel}' requested but provider declares no thinkingLaunchArgs template \u2014 launching without thinking-level selection.`);
|
|
49261
|
+
}
|
|
49262
|
+
const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgsWithBrain, options?.resumeSessionId);
|
|
48948
49263
|
const resolvedCliArgs = sessionBinding.cliArgs;
|
|
48949
49264
|
const instanceManager = this.deps.getInstanceManager();
|
|
48950
49265
|
if (provider && instanceManager) {
|
|
@@ -48962,6 +49277,10 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
48962
49277
|
providerSessionId: sessionBinding.providerSessionId,
|
|
48963
49278
|
launchMode: sessionBinding.launchMode,
|
|
48964
49279
|
extraEnv: options?.extraEnv,
|
|
49280
|
+
// BRAIN-ROUTING: for a provider with no thinkingLaunchArgs but a
|
|
49281
|
+
// runtime reasoning control (hermes), apply the level post-launch.
|
|
49282
|
+
// The launch-arg providers (claude/codex) already consumed it at spawn.
|
|
49283
|
+
...options?.initialThinkingLevel && !provider?.thinkingLaunchArgs ? { initialThinkingLevel: options.initialThinkingLevel } : {},
|
|
48965
49284
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
48966
49285
|
this.persistRecentActivity({
|
|
48967
49286
|
kind: "cli",
|
|
@@ -49309,7 +49628,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
49309
49628
|
{
|
|
49310
49629
|
resumeSessionId: args?.resumeSessionId,
|
|
49311
49630
|
settingsOverride,
|
|
49312
|
-
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env
|
|
49631
|
+
extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env,
|
|
49632
|
+
...typeof args?.initialThinkingLevel === "string" && args.initialThinkingLevel.trim() ? { initialThinkingLevel: args.initialThinkingLevel.trim() } : {}
|
|
49313
49633
|
}
|
|
49314
49634
|
);
|
|
49315
49635
|
return {
|
|
@@ -49754,6 +50074,12 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
|
|
|
49754
50074
|
"providerVersion",
|
|
49755
50075
|
"status",
|
|
49756
50076
|
"details",
|
|
50077
|
+
"modelLaunchArgs",
|
|
50078
|
+
"modelOptions",
|
|
50079
|
+
"thinkingLaunchArgs",
|
|
50080
|
+
"thinkingLevelMap",
|
|
50081
|
+
"thinkingLevelOptions",
|
|
50082
|
+
"thinkingControlId",
|
|
49757
50083
|
"sendDelayMs",
|
|
49758
50084
|
"sendKey",
|
|
49759
50085
|
"submitStrategy",
|
|
@@ -54467,6 +54793,26 @@ var meshCrudHandlers = {
|
|
|
54467
54793
|
return { success: false, error: e.message };
|
|
54468
54794
|
}
|
|
54469
54795
|
},
|
|
54796
|
+
// ─── Brain routing: per-difficulty brain presets (machine-local) ───
|
|
54797
|
+
// getDifficultyBrains returns the seeded defaults when nothing is configured,
|
|
54798
|
+
// so the editor always shows a usable mapping. set replaces the whole map.
|
|
54799
|
+
difficulty_brains_get: async (_ctx, _args) => {
|
|
54800
|
+
try {
|
|
54801
|
+
const { getDifficultyBrains: getDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
54802
|
+
return { success: true, difficultyBrains: getDifficultyBrains2() };
|
|
54803
|
+
} catch (e) {
|
|
54804
|
+
return { success: false, error: e.message };
|
|
54805
|
+
}
|
|
54806
|
+
},
|
|
54807
|
+
difficulty_brains_set: async (_ctx, args) => {
|
|
54808
|
+
try {
|
|
54809
|
+
const { setDifficultyBrains: setDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
54810
|
+
const difficultyBrains = setDifficultyBrains2(args?.difficultyBrains);
|
|
54811
|
+
return { success: true, difficultyBrains };
|
|
54812
|
+
} catch (e) {
|
|
54813
|
+
return { success: false, error: e.message };
|
|
54814
|
+
}
|
|
54815
|
+
},
|
|
54470
54816
|
add_mesh_node: async (ctx, args) => {
|
|
54471
54817
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
54472
54818
|
const workspace = typeof args?.workspace === "string" ? args.workspace.trim() : "";
|