@adhdev/daemon-standalone 1.0.29-rc.1 → 1.0.29-rc.3
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/index.js +405 -108
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/public/assets/{index-D9aov25q.js → index-BnsnvtGz.js} +46 -46
- package/public/index.html +1 -1
- package/vendor/mcp-server/index.js +54 -18
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -33311,10 +33311,10 @@ var require_dist3 = __commonJS({
|
|
|
33311
33311
|
}
|
|
33312
33312
|
function getDaemonBuildInfo() {
|
|
33313
33313
|
if (cached2) return cached2;
|
|
33314
|
-
const commit = readInjected(true ? "
|
|
33315
|
-
const commitShort = readInjected(true ? "
|
|
33316
|
-
const version2 = readInjected(true ? "1.0.29-rc.
|
|
33317
|
-
const builtAt = readInjected(true ? "2026-
|
|
33314
|
+
const commit = readInjected(true ? "8ee046ce7156a829d1038a65cb48221ca9bedb64" : void 0) ?? "unknown";
|
|
33315
|
+
const commitShort = readInjected(true ? "8ee046ce" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
33316
|
+
const version2 = readInjected(true ? "1.0.29-rc.3" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
33317
|
+
const builtAt = readInjected(true ? "2026-08-01T13:27:48.513Z" : void 0);
|
|
33318
33318
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
33319
33319
|
return cached2;
|
|
33320
33320
|
}
|
|
@@ -36155,20 +36155,40 @@ ${error48.message || ""}`;
|
|
|
36155
36155
|
let hostDaemonId = readString3(raw?.hostDaemonId);
|
|
36156
36156
|
let hostNodeId = readString3(raw?.hostNodeId);
|
|
36157
36157
|
const hostAddress = readString3(raw?.hostAddress);
|
|
36158
|
+
let hostSynthesized = false;
|
|
36159
|
+
const nodes = Array.isArray(meshRecord?.nodes) ? meshRecord.nodes : [];
|
|
36160
|
+
const nodeDaemonIdOf = (node) => {
|
|
36161
|
+
const record2 = readObject(node);
|
|
36162
|
+
return readString3(record2?.daemonId) ?? readString3(record2?.daemon_id);
|
|
36163
|
+
};
|
|
36164
|
+
if (role === "host" && !hostDaemonId) {
|
|
36165
|
+
const declaredHostNode = nodes.find((n) => normalizeMeshDaemonRole(readObject(n)?.role) === "host");
|
|
36166
|
+
if (declaredHostNode) {
|
|
36167
|
+
const declaredDaemonId = nodeDaemonIdOf(declaredHostNode);
|
|
36168
|
+
if (declaredDaemonId) {
|
|
36169
|
+
hostDaemonId = declaredDaemonId;
|
|
36170
|
+
if (!hostNodeId) hostNodeId = readString3(readObject(declaredHostNode)?.id);
|
|
36171
|
+
}
|
|
36172
|
+
}
|
|
36173
|
+
}
|
|
36158
36174
|
const localDaemonId = readString3(opts?.localDaemonId);
|
|
36159
|
-
|
|
36175
|
+
const hasForeignDaemonNode = localDaemonId ? nodes.some((n) => {
|
|
36176
|
+
const nodeDaemonId = nodeDaemonIdOf(n);
|
|
36177
|
+
return nodeDaemonId ? !daemonIdsEquivalent(nodeDaemonId, localDaemonId) : false;
|
|
36178
|
+
}) : false;
|
|
36179
|
+
if (role === "host" && !hostDaemonId && !hostNodeId && localDaemonId && !hasForeignDaemonNode) {
|
|
36160
36180
|
hostDaemonId = localDaemonId;
|
|
36161
|
-
|
|
36162
|
-
|
|
36163
|
-
|
|
36164
|
-
|
|
36165
|
-
|
|
36166
|
-
|
|
36167
|
-
|
|
36168
|
-
}
|
|
36181
|
+
hostSynthesized = true;
|
|
36182
|
+
const selfNode = nodes.find((n) => {
|
|
36183
|
+
const nodeDaemonId = nodeDaemonIdOf(n);
|
|
36184
|
+
return nodeDaemonId ? daemonIdsEquivalent(nodeDaemonId, localDaemonId) : false;
|
|
36185
|
+
});
|
|
36186
|
+
const selfNodeId = readString3(readObject(selfNode)?.id);
|
|
36187
|
+
if (selfNodeId) hostNodeId = selfNodeId;
|
|
36169
36188
|
}
|
|
36170
36189
|
if (hostDaemonId) normalized.hostDaemonId = hostDaemonId;
|
|
36171
36190
|
if (hostNodeId) normalized.hostNodeId = hostNodeId;
|
|
36191
|
+
if (hostSynthesized) normalized.hostSynthesized = true;
|
|
36172
36192
|
if (hostAddress) normalized.hostAddress = hostAddress;
|
|
36173
36193
|
if (pairing) {
|
|
36174
36194
|
const status = pairing.status === "pairing" || pairing.status === "paired" || pairing.status === "rejected" || pairing.status === "revoked" ? pairing.status : "not_configured";
|
|
@@ -36235,6 +36255,7 @@ ${error48.message || ""}`;
|
|
|
36235
36255
|
normalizeRepoIdentity: () => normalizeRepoIdentity,
|
|
36236
36256
|
removeMagiKindPanel: () => removeMagiKindPanel,
|
|
36237
36257
|
removeNode: () => removeNode,
|
|
36258
|
+
resolveScopedMeshId: () => resolveScopedMeshId,
|
|
36238
36259
|
setDifficultyBrains: () => setDifficultyBrains,
|
|
36239
36260
|
setMagiKindPanel: () => setMagiKindPanel,
|
|
36240
36261
|
tokenIdForManualPairing: () => tokenIdForManualPairing,
|
|
@@ -36265,15 +36286,41 @@ ${error48.message || ""}`;
|
|
|
36265
36286
|
}
|
|
36266
36287
|
function migrateLoadedMeshConfig(config2) {
|
|
36267
36288
|
let changed = false;
|
|
36289
|
+
if (foldLegacyTopLevelMeshSetting(config2, "magiKindPanels", "mesh_magi_kind_panel_set({ meshId, task_kind, slots })")) changed = true;
|
|
36290
|
+
if (foldLegacyTopLevelMeshSetting(config2, "difficultyBrains", "difficulty_brains_set({ meshId, difficultyBrains })")) changed = true;
|
|
36268
36291
|
for (const mesh of config2.meshes) {
|
|
36269
36292
|
if (!mesh || !Array.isArray(mesh.nodes)) continue;
|
|
36293
|
+
const brains = normalizeDifficultyBrainMap(mesh.difficultyBrains);
|
|
36294
|
+
const ownerBrains = Object.keys(brains).length > 0 ? brains : { ...DEFAULT_DIFFICULTY_BRAINS };
|
|
36270
36295
|
for (const node of mesh.nodes) {
|
|
36271
|
-
if (migrateProviderRolesToSlots(node?.policy)) changed = true;
|
|
36296
|
+
if (migrateProviderRolesToSlots(node?.policy, ownerBrains)) changed = true;
|
|
36272
36297
|
}
|
|
36273
36298
|
}
|
|
36274
36299
|
return changed;
|
|
36275
36300
|
}
|
|
36276
|
-
function
|
|
36301
|
+
function foldLegacyTopLevelMeshSetting(config2, key2, rebindHint) {
|
|
36302
|
+
const root = config2;
|
|
36303
|
+
const legacy = root[key2];
|
|
36304
|
+
if (!legacy || typeof legacy !== "object" || Array.isArray(legacy)) {
|
|
36305
|
+
if (key2 in root) {
|
|
36306
|
+
delete root[key2];
|
|
36307
|
+
return true;
|
|
36308
|
+
}
|
|
36309
|
+
return false;
|
|
36310
|
+
}
|
|
36311
|
+
delete root[key2];
|
|
36312
|
+
const entryKeys = Object.keys(legacy);
|
|
36313
|
+
if (config2.meshes.length === 1 && entryKeys.length > 0) {
|
|
36314
|
+
const mesh = config2.meshes[0];
|
|
36315
|
+
mesh[key2] = { ...legacy, ...mesh[key2] ?? {} };
|
|
36316
|
+
} else if (entryKeys.length > 0) {
|
|
36317
|
+
console.warn(
|
|
36318
|
+
`[mesh-config] Dropped legacy top-level ${key2} (keys: ${entryKeys.join(", ")}) \u2014 ${config2.meshes.length} meshes are configured, so the owning mesh cannot be determined. Re-apply it per mesh with ${rebindHint}.`
|
|
36319
|
+
);
|
|
36320
|
+
}
|
|
36321
|
+
return true;
|
|
36322
|
+
}
|
|
36323
|
+
function migrateProviderRolesToSlots(policy, ownerDifficultyBrains) {
|
|
36277
36324
|
if (!policy || typeof policy !== "object" || Array.isArray(policy)) return false;
|
|
36278
36325
|
const p = policy;
|
|
36279
36326
|
const rawRoles = p.providerRoles;
|
|
@@ -36296,12 +36343,7 @@ ${error48.message || ""}`;
|
|
|
36296
36343
|
}
|
|
36297
36344
|
p.slots = explicitSlots;
|
|
36298
36345
|
} else if (roleCap.size) {
|
|
36299
|
-
|
|
36300
|
-
try {
|
|
36301
|
-
difficultyBrains = getDifficultyBrains();
|
|
36302
|
-
} catch {
|
|
36303
|
-
difficultyBrains = void 0;
|
|
36304
|
-
}
|
|
36346
|
+
const difficultyBrains = ownerDifficultyBrains;
|
|
36305
36347
|
const priority = Array.isArray(p.providerPriority) ? p.providerPriority.map((t) => typeof t === "string" ? t.trim() : "").filter(Boolean) : [];
|
|
36306
36348
|
const derived = deriveSlotsFromLegacy({ providerPriority: priority, difficultyBrains });
|
|
36307
36349
|
const slots = derived.length ? derived : [...roleCap.values()].map((r) => ({ provider: r.provider }));
|
|
@@ -36640,6 +36682,7 @@ ${error48.message || ""}`;
|
|
|
36640
36682
|
const idx = mesh.nodes.findIndex((n) => n.id === nodeId);
|
|
36641
36683
|
if (idx === -1) return false;
|
|
36642
36684
|
mesh.nodes.splice(idx, 1);
|
|
36685
|
+
pruneMagiKindPanelsForRemovedNode(mesh, nodeId);
|
|
36643
36686
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
36644
36687
|
saveMeshConfig(config2);
|
|
36645
36688
|
return true;
|
|
@@ -36696,7 +36739,8 @@ ${error48.message || ""}`;
|
|
|
36696
36739
|
}
|
|
36697
36740
|
return s2;
|
|
36698
36741
|
}
|
|
36699
|
-
function normalizeMagiSlots(slots) {
|
|
36742
|
+
function normalizeMagiSlots(slots, knownNodeIds) {
|
|
36743
|
+
const allowed = knownNodeIds ? new Set(knownNodeIds) : void 0;
|
|
36700
36744
|
if (!Array.isArray(slots) || slots.length === 0) {
|
|
36701
36745
|
throw new Error("invalid_magi_kind_panel: slots must be a non-empty array");
|
|
36702
36746
|
}
|
|
@@ -36713,6 +36757,11 @@ ${error48.message || ""}`;
|
|
|
36713
36757
|
throw new Error(`invalid_magi_kind_panel: slot[${idx}].provider is required`);
|
|
36714
36758
|
}
|
|
36715
36759
|
const nodeId = typeof s2.nodeId === "string" && s2.nodeId.trim() ? s2.nodeId.trim() : void 0;
|
|
36760
|
+
if (nodeId && allowed && !allowed.has(nodeId)) {
|
|
36761
|
+
throw new Error(
|
|
36762
|
+
`invalid_magi_kind_panel: slot[${idx}].nodeId '${nodeId}' is not a node of this mesh (known: ${[...allowed].join(", ") || "(none)"}). Pin a node from this mesh, or omit nodeId to let the fan-out pick any node offering the provider.`
|
|
36763
|
+
);
|
|
36764
|
+
}
|
|
36716
36765
|
const model = typeof s2.model === "string" && s2.model.trim() ? s2.model.trim() : void 0;
|
|
36717
36766
|
const capabilityTags = normalizeCapabilityTags(s2.capabilityTags);
|
|
36718
36767
|
const n = normalizeReplicaCount(s2.n);
|
|
@@ -36725,32 +36774,51 @@ ${error48.message || ""}`;
|
|
|
36725
36774
|
};
|
|
36726
36775
|
});
|
|
36727
36776
|
}
|
|
36728
|
-
function
|
|
36729
|
-
|
|
36777
|
+
function resolveScopedMeshId(config2) {
|
|
36778
|
+
const meshes = (config2 ?? loadMeshConfig({ persistMigrations: false })).meshes;
|
|
36779
|
+
return meshes.length === 1 ? meshes[0].id : void 0;
|
|
36780
|
+
}
|
|
36781
|
+
function resolveScopedMesh(config2, meshId) {
|
|
36782
|
+
const id = meshId?.trim() || resolveScopedMeshId(config2);
|
|
36783
|
+
if (!id) return void 0;
|
|
36784
|
+
return config2.meshes.find((m) => m.id === id);
|
|
36785
|
+
}
|
|
36786
|
+
function listMagiKindPanels(meshId) {
|
|
36787
|
+
const config2 = loadMeshConfig();
|
|
36788
|
+
return resolveScopedMesh(config2, meshId)?.magiKindPanels ?? {};
|
|
36730
36789
|
}
|
|
36731
|
-
function listMagiKindPanelsReadOnly() {
|
|
36732
|
-
|
|
36790
|
+
function listMagiKindPanelsReadOnly(meshId) {
|
|
36791
|
+
const config2 = loadMeshConfig({ persistMigrations: false });
|
|
36792
|
+
return resolveScopedMesh(config2, meshId)?.magiKindPanels ?? {};
|
|
36733
36793
|
}
|
|
36734
|
-
function getMagiKindPanel(kind) {
|
|
36794
|
+
function getMagiKindPanel(kind, meshId) {
|
|
36735
36795
|
let key2;
|
|
36736
36796
|
try {
|
|
36737
36797
|
key2 = normalizeMagiTaskKindKey(kind);
|
|
36738
36798
|
} catch {
|
|
36739
36799
|
return void 0;
|
|
36740
36800
|
}
|
|
36741
|
-
|
|
36801
|
+
const config2 = loadMeshConfig();
|
|
36802
|
+
return resolveScopedMesh(config2, meshId)?.magiKindPanels?.[key2];
|
|
36742
36803
|
}
|
|
36743
|
-
function setMagiKindPanel(kind, slots) {
|
|
36804
|
+
function setMagiKindPanel(kind, slots, meshId) {
|
|
36744
36805
|
const key2 = normalizeMagiTaskKindKey(kind);
|
|
36745
|
-
const normalized = normalizeMagiSlots(slots);
|
|
36746
36806
|
const stored = loadMeshConfig();
|
|
36747
|
-
const
|
|
36807
|
+
const mesh = resolveScopedMesh(stored, meshId);
|
|
36808
|
+
if (!mesh) {
|
|
36809
|
+
throw new Error(
|
|
36810
|
+
meshId?.trim() ? `invalid_magi_kind_panel: mesh '${meshId.trim()}' not found` : `magi_kind_panel_mesh_ambiguous: this machine hosts ${stored.meshes.length} meshes, so a MAGI kind-panel write must name its mesh explicitly (meshId). Panels are per mesh.`
|
|
36811
|
+
);
|
|
36812
|
+
}
|
|
36813
|
+
const normalized = normalizeMagiSlots(slots, mesh.nodes.map((n) => n.id));
|
|
36814
|
+
const map3 = mesh.magiKindPanels ?? {};
|
|
36748
36815
|
map3[key2] = normalized;
|
|
36749
|
-
|
|
36816
|
+
mesh.magiKindPanels = map3;
|
|
36817
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
36750
36818
|
saveMeshConfig(stored);
|
|
36751
36819
|
return normalized;
|
|
36752
36820
|
}
|
|
36753
|
-
function removeMagiKindPanel(kind) {
|
|
36821
|
+
function removeMagiKindPanel(kind, meshId) {
|
|
36754
36822
|
let key2;
|
|
36755
36823
|
try {
|
|
36756
36824
|
key2 = normalizeMagiTaskKindKey(kind);
|
|
@@ -36758,21 +36826,47 @@ ${error48.message || ""}`;
|
|
|
36758
36826
|
return false;
|
|
36759
36827
|
}
|
|
36760
36828
|
const stored = loadMeshConfig();
|
|
36761
|
-
|
|
36762
|
-
|
|
36829
|
+
const mesh = resolveScopedMesh(stored, meshId);
|
|
36830
|
+
if (!mesh?.magiKindPanels?.[key2]) return false;
|
|
36831
|
+
delete mesh.magiKindPanels[key2];
|
|
36832
|
+
if (Object.keys(mesh.magiKindPanels).length === 0) delete mesh.magiKindPanels;
|
|
36833
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
36763
36834
|
saveMeshConfig(stored);
|
|
36764
36835
|
return true;
|
|
36765
36836
|
}
|
|
36766
|
-
function
|
|
36767
|
-
const
|
|
36837
|
+
function pruneMagiKindPanelsForRemovedNode(mesh, nodeId) {
|
|
36838
|
+
const panels = mesh.magiKindPanels;
|
|
36839
|
+
if (!panels) return false;
|
|
36840
|
+
let changed = false;
|
|
36841
|
+
for (const [kind, slots] of Object.entries(panels)) {
|
|
36842
|
+
if (!Array.isArray(slots)) continue;
|
|
36843
|
+
const kept = slots.filter((slot) => slot.nodeId !== nodeId);
|
|
36844
|
+
if (kept.length === slots.length) continue;
|
|
36845
|
+
changed = true;
|
|
36846
|
+
if (kept.length === 0) delete panels[kind];
|
|
36847
|
+
else panels[kind] = kept;
|
|
36848
|
+
}
|
|
36849
|
+
if (changed && Object.keys(panels).length === 0) delete mesh.magiKindPanels;
|
|
36850
|
+
return changed;
|
|
36851
|
+
}
|
|
36852
|
+
function getDifficultyBrains(meshId) {
|
|
36853
|
+
const config2 = loadMeshConfig();
|
|
36854
|
+
const stored = resolveScopedMesh(config2, meshId)?.difficultyBrains;
|
|
36768
36855
|
const normalized = normalizeDifficultyBrainMap(stored);
|
|
36769
36856
|
return Object.keys(normalized).length > 0 ? normalized : { ...DEFAULT_DIFFICULTY_BRAINS };
|
|
36770
36857
|
}
|
|
36771
|
-
function setDifficultyBrains(map3) {
|
|
36858
|
+
function setDifficultyBrains(map3, meshId) {
|
|
36772
36859
|
const normalized = normalizeDifficultyBrainMap(map3);
|
|
36773
36860
|
const stored = loadMeshConfig();
|
|
36774
|
-
|
|
36775
|
-
|
|
36861
|
+
const mesh = resolveScopedMesh(stored, meshId);
|
|
36862
|
+
if (!mesh) {
|
|
36863
|
+
throw new Error(
|
|
36864
|
+
meshId?.trim() ? `invalid_difficulty_brains: mesh '${meshId.trim()}' not found` : `difficulty_brains_mesh_ambiguous: this machine hosts ${stored.meshes.length} meshes, so a difficulty-brain write must name its mesh explicitly (meshId). Presets are per mesh \u2014 they decide which model a task runs on, so writing to the wrong mesh changes what it costs.`
|
|
36865
|
+
);
|
|
36866
|
+
}
|
|
36867
|
+
if (Object.keys(normalized).length > 0) mesh.difficultyBrains = normalized;
|
|
36868
|
+
else delete mesh.difficultyBrains;
|
|
36869
|
+
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
36776
36870
|
saveMeshConfig(stored);
|
|
36777
36871
|
return normalized;
|
|
36778
36872
|
}
|
|
@@ -36808,12 +36902,12 @@ ${error48.message || ""}`;
|
|
|
36808
36902
|
return true;
|
|
36809
36903
|
});
|
|
36810
36904
|
}
|
|
36811
|
-
function resolveNodeCapabilitySlots(node) {
|
|
36905
|
+
function resolveNodeCapabilitySlots(node, meshId) {
|
|
36812
36906
|
const explicit = normalizeNodeCapabilitySlots(node?.policy?.slots);
|
|
36813
36907
|
if (explicit.length) return explicit;
|
|
36814
36908
|
let difficultyBrains;
|
|
36815
36909
|
try {
|
|
36816
|
-
difficultyBrains = getDifficultyBrains();
|
|
36910
|
+
difficultyBrains = getDifficultyBrains(meshId);
|
|
36817
36911
|
} catch {
|
|
36818
36912
|
difficultyBrains = void 0;
|
|
36819
36913
|
}
|
|
@@ -40828,7 +40922,7 @@ Next step: ${nextStep}`;
|
|
|
40828
40922
|
const taskDifficulty = isMeshTaskDifficulty(opts?.difficulty) ? opts.difficulty : void 0;
|
|
40829
40923
|
if (isMeshTaskDifficulty(opts?.difficulty)) {
|
|
40830
40924
|
try {
|
|
40831
|
-
const preset = getDifficultyBrains()[opts.difficulty];
|
|
40925
|
+
const preset = getDifficultyBrains(meshId)[opts.difficulty];
|
|
40832
40926
|
if (preset) {
|
|
40833
40927
|
if (!effectiveModel && preset.model) effectiveModel = preset.model;
|
|
40834
40928
|
if (!effectiveThinkingLevel && preset.thinkingLevel) effectiveThinkingLevel = preset.thinkingLevel;
|
|
@@ -54047,6 +54141,77 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
54047
54141
|
]);
|
|
54048
54142
|
}
|
|
54049
54143
|
});
|
|
54144
|
+
function normalizeLiteral(model) {
|
|
54145
|
+
return model.toLowerCase().replace(/[_/\\().,]+/g, " ").replace(/-+/g, " ").replace(/\s+/g, " ").trim();
|
|
54146
|
+
}
|
|
54147
|
+
function canonicalizeModelName(model) {
|
|
54148
|
+
if (typeof model !== "string") return void 0;
|
|
54149
|
+
const literal2 = normalizeLiteral(model);
|
|
54150
|
+
if (!literal2) return void 0;
|
|
54151
|
+
const tokens = literal2.split(" ").filter((t) => t && !MODIFIER_WORDS.has(t));
|
|
54152
|
+
const family = CLAUDE_FAMILIES.find((f) => tokens.includes(f));
|
|
54153
|
+
let version2;
|
|
54154
|
+
if (family) {
|
|
54155
|
+
const after = tokens.slice(tokens.indexOf(family) + 1).filter((t) => /^\d+$/.test(t));
|
|
54156
|
+
if (after.length) version2 = after.join(".");
|
|
54157
|
+
else {
|
|
54158
|
+
const dotted = tokens.find((t) => /^\d+(\.\d+)+$/.test(t));
|
|
54159
|
+
if (dotted) version2 = dotted;
|
|
54160
|
+
}
|
|
54161
|
+
}
|
|
54162
|
+
return { family, version: version2, literal: literal2 };
|
|
54163
|
+
}
|
|
54164
|
+
function modelNamesEquivalent(a, b) {
|
|
54165
|
+
const ca = canonicalizeModelName(a);
|
|
54166
|
+
const cb = canonicalizeModelName(b);
|
|
54167
|
+
if (!ca || !cb) return false;
|
|
54168
|
+
if (ca.family && cb.family) {
|
|
54169
|
+
if (ca.family !== cb.family) return false;
|
|
54170
|
+
if (ca.version && cb.version) return ca.version === cb.version;
|
|
54171
|
+
return true;
|
|
54172
|
+
}
|
|
54173
|
+
if (ca.family || cb.family) return false;
|
|
54174
|
+
return ca.literal === cb.literal;
|
|
54175
|
+
}
|
|
54176
|
+
function isModelAllowedBySlot(model, slot) {
|
|
54177
|
+
if (!slot) return true;
|
|
54178
|
+
const declared = typeof slot.model === "string" ? slot.model.trim() : "";
|
|
54179
|
+
const requested = typeof model === "string" ? model.trim() : "";
|
|
54180
|
+
if (!declared) return !requested;
|
|
54181
|
+
if (!requested) return true;
|
|
54182
|
+
return modelNamesEquivalent(requested, declared);
|
|
54183
|
+
}
|
|
54184
|
+
function decideSlotForModel(input) {
|
|
54185
|
+
const { requestedModel, slots } = input;
|
|
54186
|
+
const declaring = slots.filter((s2) => isModelAllowedBySlot(requestedModel, s2.slot));
|
|
54187
|
+
if (!declaring.length) {
|
|
54188
|
+
const declaredModels = slots.map((s2) => typeof s2.slot.model === "string" && s2.slot.model.trim() ? s2.slot.model.trim() : "(provider default)").filter((v, i, a) => a.indexOf(v) === i);
|
|
54189
|
+
return { outcome: "notify", reason: SLOT_MODEL_ABSENT_SKIP_REASON, declaredModels };
|
|
54190
|
+
}
|
|
54191
|
+
const free = declaring.find((s2) => s2.available);
|
|
54192
|
+
if (free) {
|
|
54193
|
+
const declared = typeof free.slot.model === "string" && free.slot.model.trim() ? free.slot.model.trim() : void 0;
|
|
54194
|
+
return { outcome: "run", slot: free.slot, model: declared };
|
|
54195
|
+
}
|
|
54196
|
+
return {
|
|
54197
|
+
outcome: "wait",
|
|
54198
|
+
reason: SLOT_MODEL_BUSY_SKIP_REASON,
|
|
54199
|
+
busySlots: declaring.map((s2) => s2.slot)
|
|
54200
|
+
};
|
|
54201
|
+
}
|
|
54202
|
+
var CLAUDE_FAMILIES;
|
|
54203
|
+
var MODIFIER_WORDS;
|
|
54204
|
+
var SLOT_MODEL_BUSY_SKIP_REASON;
|
|
54205
|
+
var SLOT_MODEL_ABSENT_SKIP_REASON;
|
|
54206
|
+
var init_slot_model_enforcement = __esm2({
|
|
54207
|
+
"src/mesh/slot-model-enforcement.ts"() {
|
|
54208
|
+
"use strict";
|
|
54209
|
+
CLAUDE_FAMILIES = ["opus", "sonnet", "haiku"];
|
|
54210
|
+
MODIFIER_WORDS = /* @__PURE__ */ new Set(["thinking", "latest", "preview", "claude", "anthropic"]);
|
|
54211
|
+
SLOT_MODEL_BUSY_SKIP_REASON = "slot_for_model_busy";
|
|
54212
|
+
SLOT_MODEL_ABSENT_SKIP_REASON = "no_slot_declares_requested_model";
|
|
54213
|
+
}
|
|
54214
|
+
});
|
|
54050
54215
|
function encodeDuplicateMeshDispatchCode(holderSessionId) {
|
|
54051
54216
|
const holder = typeof holderSessionId === "string" ? holderSessionId.trim() : "";
|
|
54052
54217
|
return holder ? `${DUPLICATE_MESH_DISPATCH_CODE}:${holder}` : DUPLICATE_MESH_DISPATCH_CODE;
|
|
@@ -54395,7 +54560,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
54395
54560
|
return false;
|
|
54396
54561
|
}
|
|
54397
54562
|
const capabilityTags = buildMeshNodeCapabilityTags(node, providerType);
|
|
54398
|
-
const providerMaxParallel = resolveProviderMaxParallel(resolveNodeCapabilitySlots(node), providerType);
|
|
54563
|
+
const providerMaxParallel = resolveProviderMaxParallel(resolveNodeCapabilitySlots(node, meshId), providerType);
|
|
54399
54564
|
const nodeIsWorktree = node?.isLocalWorktree === true;
|
|
54400
54565
|
const assignedTranscriptProfile = resolveClaimingSessionTranscriptProfile(components, sessionId);
|
|
54401
54566
|
const task = claimNextTask(meshId, nodeId, sessionId, capabilityTags, {
|
|
@@ -54696,6 +54861,10 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
54696
54861
|
summary: "the node's workspace is dirty, so auto-launch is blocked to avoid clobbering uncommitted changes",
|
|
54697
54862
|
nextAction: "Clean or commit the node's working tree (or fast-forward it); the task will then auto-assign."
|
|
54698
54863
|
};
|
|
54864
|
+
if (reason === SLOT_MODEL_ABSENT_SKIP_REASON) return {
|
|
54865
|
+
summary: "no capability slot on the node declares the model this task resolved to (its difficulty\u2192brain preset picked a model the node was never configured to run)",
|
|
54866
|
+
nextAction: "Re-enqueue with a difficulty/model the node's slots declare, target a node that declares this model, or add a slot for it. The task is NOT run on a substitute model \u2014 an undeclared model is never launched."
|
|
54867
|
+
};
|
|
54699
54868
|
return {
|
|
54700
54869
|
summary: `it cannot be dispatched (${reason})`,
|
|
54701
54870
|
nextAction: "Inspect the node/mesh state with mesh_status and resolve the blocker, or re-enqueue the task."
|
|
@@ -54887,8 +55056,8 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
54887
55056
|
}
|
|
54888
55057
|
return score;
|
|
54889
55058
|
}
|
|
54890
|
-
function bestSlotForTask(node, task) {
|
|
54891
|
-
const slots = resolveNodeCapabilitySlots(node);
|
|
55059
|
+
function bestSlotForTask(node, task, meshId) {
|
|
55060
|
+
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
54892
55061
|
if (!slots.length) return null;
|
|
54893
55062
|
let best = null;
|
|
54894
55063
|
for (const slot of slots) {
|
|
@@ -54897,8 +55066,8 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
54897
55066
|
}
|
|
54898
55067
|
return best;
|
|
54899
55068
|
}
|
|
54900
|
-
function nodeFitnessForTask(node, task) {
|
|
54901
|
-
return bestSlotForTask(node, task)?.score ?? 0;
|
|
55069
|
+
function nodeFitnessForTask(node, task, meshId) {
|
|
55070
|
+
return bestSlotForTask(node, task, meshId)?.score ?? 0;
|
|
54902
55071
|
}
|
|
54903
55072
|
function orderEligibleNodes(meshId, strategy, nodes, opts) {
|
|
54904
55073
|
if (strategy === "first_eligible" || nodes.length <= 1) {
|
|
@@ -54907,7 +55076,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
54907
55076
|
if (strategy === "fitness" && opts?.task) {
|
|
54908
55077
|
const task = opts.task;
|
|
54909
55078
|
return [...nodes].sort((a, b) => {
|
|
54910
|
-
const fitDelta = nodeFitnessForTask(b.node, task) - nodeFitnessForTask(a.node, task);
|
|
55079
|
+
const fitDelta = nodeFitnessForTask(b.node, task, meshId) - nodeFitnessForTask(a.node, task, meshId);
|
|
54911
55080
|
if (fitDelta !== 0) return fitDelta;
|
|
54912
55081
|
const prioDelta = resolveNodeSchedulingPriority(b.node?.policy) - resolveNodeSchedulingPriority(a.node?.policy);
|
|
54913
55082
|
if (prioDelta !== 0) return prioDelta;
|
|
@@ -54936,6 +55105,13 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
54936
55105
|
function activeProviderAssignedCount(meshId, nodeId, providerType) {
|
|
54937
55106
|
return getQueue(meshId, { status: ["assigned"] }).filter((task) => daemonIdsEquivalent(task.assignedNodeId, nodeId) && task.assignedProviderType === providerType).length;
|
|
54938
55107
|
}
|
|
55108
|
+
function slotHasCapacity(meshId, nodeId, node, slot) {
|
|
55109
|
+
const providerType = typeof slot.provider === "string" ? slot.provider.trim() : "";
|
|
55110
|
+
if (!providerType) return false;
|
|
55111
|
+
const cap = resolveProviderMaxParallel(resolveNodeCapabilitySlots(node, meshId), providerType);
|
|
55112
|
+
if (cap === void 0) return true;
|
|
55113
|
+
return activeProviderAssignedCount(meshId, nodeId, providerType) < cap;
|
|
55114
|
+
}
|
|
54939
55115
|
function sessionHasActiveAssignment(meshId, sessionId) {
|
|
54940
55116
|
if (getQueue(meshId, { status: ["assigned"] }).some((task) => sessionIdsEquivalent(task.assignedSessionId, sessionId))) {
|
|
54941
55117
|
return true;
|
|
@@ -55073,10 +55249,10 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
55073
55249
|
retractActionableSkipIfPreviouslyNotified(meshId, taskId);
|
|
55074
55250
|
}
|
|
55075
55251
|
}
|
|
55076
|
-
async function resolveUsableProvider(components, nodeId, node, requiredTags, task) {
|
|
55252
|
+
async function resolveUsableProvider(components, nodeId, node, meshId, requiredTags, task) {
|
|
55077
55253
|
const providerLoader = components.providerLoader;
|
|
55078
55254
|
if (!providerLoader) return { reason: "provider_loader_unavailable" };
|
|
55079
|
-
const slots = resolveNodeCapabilitySlots(node);
|
|
55255
|
+
const slots = resolveNodeCapabilitySlots(node, meshId);
|
|
55080
55256
|
if (!slots.length) return { reason: "missing_provider_priority" };
|
|
55081
55257
|
const orderedSlots = task ? [...slots].sort((a, b) => scoreSlotForTask(b, task) - scoreSlotForTask(a, task)) : slots;
|
|
55082
55258
|
const failed = [];
|
|
@@ -55110,7 +55286,12 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
55110
55286
|
return {
|
|
55111
55287
|
providerType: normalizedType,
|
|
55112
55288
|
...slot.model ? { model: slot.model } : {},
|
|
55113
|
-
...slot.thinkingLevel ? { thinkingLevel: slot.thinkingLevel } : {}
|
|
55289
|
+
...slot.thinkingLevel ? { thinkingLevel: slot.thinkingLevel } : {},
|
|
55290
|
+
// The slot that won selection. Returned so the caller can enforce
|
|
55291
|
+
// "the launch model must be one this slot declares" — a preset
|
|
55292
|
+
// model must not widen what the operator configured. See
|
|
55293
|
+
// slot-model-enforcement.ts.
|
|
55294
|
+
slot
|
|
55114
55295
|
};
|
|
55115
55296
|
}
|
|
55116
55297
|
failed.push(`${requestedType}: not detected`);
|
|
@@ -55247,7 +55428,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
55247
55428
|
if (task.targetNodeId && !meshNodeIdMatches(node, task.targetNodeId)) return false;
|
|
55248
55429
|
if (task.taskMode === "convergence" && node?.isLocalWorktree === true) return false;
|
|
55249
55430
|
if (task.requiredTags?.length) {
|
|
55250
|
-
const slotProviders = resolveNodeCapabilitySlots(node).map((s2) => s2.provider).filter(Boolean);
|
|
55431
|
+
const slotProviders = resolveNodeCapabilitySlots(node, meshId).map((s2) => s2.provider).filter(Boolean);
|
|
55251
55432
|
const priorities = slotProviders.length ? slotProviders : normalizeProviderPriority2(node?.policy);
|
|
55252
55433
|
const providerCandidates = priorities.length ? priorities : [void 0];
|
|
55253
55434
|
return providerCandidates.some(
|
|
@@ -55336,18 +55517,36 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
55336
55517
|
}
|
|
55337
55518
|
autoLaunchInProgress.add(launchKey);
|
|
55338
55519
|
try {
|
|
55339
|
-
const resolved = await resolveUsableProvider(components, nodeId, node, task.requiredTags, { difficulty: task.difficulty, requiredTags: task.requiredTags });
|
|
55520
|
+
const resolved = await resolveUsableProvider(components, nodeId, node, meshId, task.requiredTags, { difficulty: task.difficulty, requiredTags: task.requiredTags });
|
|
55340
55521
|
if (!resolved.providerType) {
|
|
55341
55522
|
markSkip(nodeId, resolved.reason || "provider_unusable");
|
|
55342
55523
|
continue;
|
|
55343
55524
|
}
|
|
55344
|
-
const
|
|
55525
|
+
const requestedModel = typeof task.model === "string" && task.model.trim() ? task.model.trim() : resolved.model;
|
|
55345
55526
|
const effectiveThinkingLevel = typeof task.thinkingLevel === "string" && task.thinkingLevel.trim() ? task.thinkingLevel.trim() : resolved.thinkingLevel;
|
|
55527
|
+
const slotDecision = decideSlotForModel({
|
|
55528
|
+
requestedModel,
|
|
55529
|
+
slots: resolveNodeCapabilitySlots(node, meshId).map((slot) => ({
|
|
55530
|
+
slot,
|
|
55531
|
+
available: slotHasCapacity(meshId, nodeId, node, slot)
|
|
55532
|
+
}))
|
|
55533
|
+
});
|
|
55534
|
+
if (slotDecision.outcome === "wait") {
|
|
55535
|
+
LOG2.info("MeshQueue", `SLOT MODEL GUARD: model '${requestedModel}' is declared on node ${nodeId} but every matching slot is at its maxParallel cap (task ${task.id}); leaving the task queued until a slot goes idle`);
|
|
55536
|
+
markSkip(nodeId, slotDecision.reason, { providerType: resolved.providerType });
|
|
55537
|
+
continue;
|
|
55538
|
+
}
|
|
55539
|
+
if (slotDecision.outcome === "notify") {
|
|
55540
|
+
LOG2.warn("MeshQueue", `SLOT MODEL GUARD: no slot on node ${nodeId} declares model '${requestedModel}' (declared: ${slotDecision.declaredModels.join(", ") || "none"}) for task ${task.id}; not launching \u2014 surfacing to the coordinator to re-drive`);
|
|
55541
|
+
markSkip(nodeId, slotDecision.reason, { providerType: resolved.providerType });
|
|
55542
|
+
continue;
|
|
55543
|
+
}
|
|
55544
|
+
const rawEffectiveModel = slotDecision.model;
|
|
55346
55545
|
const effectiveModel = isModelCompatibleWithProvider(rawEffectiveModel, resolved.providerType) ? rawEffectiveModel : void 0;
|
|
55347
55546
|
if (rawEffectiveModel && effectiveModel === void 0) {
|
|
55348
55547
|
LOG2.info("MeshQueue", `CODEX-400 GUARD: dropped incompatible launch model '${rawEffectiveModel}' for non-Anthropic provider '${resolved.providerType}' on node ${nodeId} (task ${task.id}); provider will use its own default model`);
|
|
55349
55548
|
}
|
|
55350
|
-
const providerCap = resolveProviderMaxParallel(resolveNodeCapabilitySlots(node), resolved.providerType);
|
|
55549
|
+
const providerCap = resolveProviderMaxParallel(resolveNodeCapabilitySlots(node, meshId), resolved.providerType);
|
|
55351
55550
|
if (providerCap !== void 0 && activeProviderAssignedCount(meshId, nodeId, resolved.providerType) >= providerCap) {
|
|
55352
55551
|
markSkip(nodeId, "max_provider_parallel_reached", { providerType: resolved.providerType });
|
|
55353
55552
|
continue;
|
|
@@ -55441,7 +55640,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
55441
55640
|
const requiredTags = Array.isArray(task.requiredTags) ? task.requiredTags.filter((t) => !!t) : [];
|
|
55442
55641
|
const routingDecision = {
|
|
55443
55642
|
source: "autoLaunch",
|
|
55444
|
-
fitnessScore: nodeFitnessForTask(node, { difficulty: task.difficulty, requiredTags: task.requiredTags }),
|
|
55643
|
+
fitnessScore: nodeFitnessForTask(node, { difficulty: task.difficulty, requiredTags: task.requiredTags }, meshId),
|
|
55445
55644
|
...skippedCandidates.length ? { skippedCandidates } : {},
|
|
55446
55645
|
requiredTagsResult: {
|
|
55447
55646
|
required: requiredTags,
|
|
@@ -55885,6 +56084,7 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
55885
56084
|
init_mesh_clone_grace();
|
|
55886
56085
|
init_mesh_task_inflight();
|
|
55887
56086
|
init_model_provider_compat();
|
|
56087
|
+
init_slot_model_enforcement();
|
|
55888
56088
|
init_mesh_turn_ledger();
|
|
55889
56089
|
init_mesh_duplicate_dispatch();
|
|
55890
56090
|
IDLE_AUTO_FAST_FORWARD_THROTTLE_MS = 30 * 60 * 1e3;
|
|
@@ -55917,7 +56117,13 @@ The mesh has no work in flight. For each mission, decide its outcome: continue i
|
|
|
55917
56117
|
"provider_loader_unavailable",
|
|
55918
56118
|
"provider_priority_unusable",
|
|
55919
56119
|
"provider_unusable",
|
|
55920
|
-
"dirty_workspace"
|
|
56120
|
+
"dirty_workspace",
|
|
56121
|
+
// SLOT MODEL GUARD (absent): no slot on the node declares the task's model.
|
|
56122
|
+
// Permanent — no amount of waiting produces a slot, so the coordinator must
|
|
56123
|
+
// re-drive (adjust difficulty, target another node, ask the owner). Its
|
|
56124
|
+
// busy counterpart SLOT_MODEL_BUSY_SKIP_REASON is deliberately NOT listed:
|
|
56125
|
+
// that one clears on its own when the slot goes idle.
|
|
56126
|
+
SLOT_MODEL_ABSENT_SKIP_REASON
|
|
55921
56127
|
];
|
|
55922
56128
|
TRANSIENT_TARGET_NODE_BOOTSTRAP_PENDING_REASON = "target_node_bootstrap_pending";
|
|
55923
56129
|
lastActionableSkipNotified = /* @__PURE__ */ new Map();
|
|
@@ -71152,6 +71358,7 @@ ${lastSnapshot}`;
|
|
|
71152
71358
|
buildChatMessageSignature: () => buildChatMessageSignature,
|
|
71153
71359
|
buildChatTailDeliverySignature: () => buildChatTailDeliverySignature,
|
|
71154
71360
|
buildClaudeInteractiveToolResult: () => buildClaudeInteractiveToolResult,
|
|
71361
|
+
buildCloudStatusReportPayload: () => buildCloudStatusReportPayload,
|
|
71155
71362
|
buildCompactStaleDirectWorkSummary: () => buildCompactStaleDirectWorkSummary,
|
|
71156
71363
|
buildCoordinatorSystemPrompt: () => buildCoordinatorSystemPrompt,
|
|
71157
71364
|
buildIdleReminderMessage: () => buildIdleReminderMessage,
|
|
@@ -71451,6 +71658,7 @@ ${lastSnapshot}`;
|
|
|
71451
71658
|
resolveNotBefore: () => resolveNotBefore,
|
|
71452
71659
|
resolveProviderChannel: () => resolveProviderChannel,
|
|
71453
71660
|
resolveProviderMaxParallel: () => resolveProviderMaxParallel,
|
|
71661
|
+
resolveScopedMeshId: () => resolveScopedMeshId,
|
|
71454
71662
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
71455
71663
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution2,
|
|
71456
71664
|
resolveSessionTurnPresentation: () => resolveSessionTurnPresentation,
|
|
@@ -73026,7 +73234,7 @@ ${lastSnapshot}`;
|
|
|
73026
73234
|
const bootstrapLoaded = loadMeshWorktreeBootstrapConfig(mesh, workspace);
|
|
73027
73235
|
let magiKindPanels = {};
|
|
73028
73236
|
try {
|
|
73029
|
-
magiKindPanels = listMagiKindPanelsReadOnly();
|
|
73237
|
+
magiKindPanels = listMagiKindPanelsReadOnly(typeof mesh?.id === "string" ? mesh.id : void 0);
|
|
73030
73238
|
} catch {
|
|
73031
73239
|
magiKindPanels = {};
|
|
73032
73240
|
}
|
|
@@ -87981,6 +88189,48 @@ ${body}
|
|
|
87981
88189
|
}
|
|
87982
88190
|
return screenText;
|
|
87983
88191
|
}
|
|
88192
|
+
/**
|
|
88193
|
+
* Is `reread` a re-render of the SAME picker page as `landed`?
|
|
88194
|
+
*
|
|
88195
|
+
* Guards the return-pass screenText swap in captureClaudeTuiPrompt, which
|
|
88196
|
+
* replaces a page's entire raw screen and therefore must never be handed a
|
|
88197
|
+
* frame belonging to a different question.
|
|
88198
|
+
*
|
|
88199
|
+
* WHAT WE COMPARE — the question line, via the same parser the capture
|
|
88200
|
+
* itself uses (readFocusedClaudeTuiQuestion). Rationale:
|
|
88201
|
+
* - The question text is the one field that is per-page, always rendered
|
|
88202
|
+
* (it is the parse anchor — a page without it yields no question at all),
|
|
88203
|
+
* and stable across the redraw we are waiting on. The redraw races the
|
|
88204
|
+
* option-row GLYPH COLUMN, not the question line.
|
|
88205
|
+
* - The header is NOT usable on its own: on the headered variant every page
|
|
88206
|
+
* renders the identical nav line, and `page.header` is assigned by index
|
|
88207
|
+
* from that shared line rather than read from the page body — so it is
|
|
88208
|
+
* equal across pages by construction and would accept any frame.
|
|
88209
|
+
* - The option-label set is rejected as the primary key: it is drawn in the
|
|
88210
|
+
* very region that is mid-redraw, and rows can be clipped or scrolled out
|
|
88211
|
+
* of the captured frame (the same truncation that forced the headerless
|
|
88212
|
+
* parser to stop requiring the freeform escape hatch). Comparing it would
|
|
88213
|
+
* reject legitimate repairs — exactly the frames this pass exists to fix.
|
|
88214
|
+
*
|
|
88215
|
+
* STRICTNESS — deliberately asymmetric, because the two error directions are
|
|
88216
|
+
* not equally costly. Wrongly ALLOWING a swap corrupts a question into a
|
|
88217
|
+
* duplicate of another (the reported user-visible defect). Wrongly BLOCKING
|
|
88218
|
+
* one merely leaves the forward-pass capture in place — at worst a
|
|
88219
|
+
* multi-select page stays flagged single-select, which the live status-tick
|
|
88220
|
+
* upgrade (maybeUpgradeClaudeTuiMultiSelect) then repairs anyway. So this
|
|
88221
|
+
* blocks only on POSITIVE EVIDENCE of a different page: if either side fails
|
|
88222
|
+
* to parse we return true and defer to the pre-existing glyph gate, keeping
|
|
88223
|
+
* behaviour identical to before for every frame whose identity we cannot
|
|
88224
|
+
* read. Comparison is whitespace-normalised so a reflow or trailing-pad
|
|
88225
|
+
* difference does not read as a different question.
|
|
88226
|
+
*/
|
|
88227
|
+
claudeTuiPagesLookLikeSameQuestion(landed, reread) {
|
|
88228
|
+
const landedQuestion = readFocusedClaudeTuiQuestion(landed.screenText);
|
|
88229
|
+
const rereadQuestion = readFocusedClaudeTuiQuestion(reread);
|
|
88230
|
+
if (!landedQuestion || !rereadQuestion) return true;
|
|
88231
|
+
const normalize4 = (text) => text.replace(/\s+/g, " ").trim();
|
|
88232
|
+
return normalize4(landedQuestion.question) === normalize4(rereadQuestion.question);
|
|
88233
|
+
}
|
|
87984
88234
|
async captureClaudeTuiPrompt(firstScreen, headers) {
|
|
87985
88235
|
const pages = [{ screenText: firstScreen, header: headers[0] }];
|
|
87986
88236
|
for (let index = 1; index < headers.length; index += 1) {
|
|
@@ -87993,7 +88243,7 @@ ${body}
|
|
|
87993
88243
|
await new Promise((resolve29) => setTimeout(resolve29, _SpecCliAdapter.CLAUDE_TUI_PAGE_POLL_INTERVAL_MS));
|
|
87994
88244
|
const reread = await this.snapshotSettledClaudeTuiPage();
|
|
87995
88245
|
const landed = pages[index - 1];
|
|
87996
|
-
if (landed && !detectClaudeTuiMultiSelect(landed.screenText) && detectClaudeTuiMultiSelect(reread)) {
|
|
88246
|
+
if (landed && !detectClaudeTuiMultiSelect(landed.screenText) && detectClaudeTuiMultiSelect(reread) && this.claudeTuiPagesLookLikeSameQuestion(landed, reread)) {
|
|
87997
88247
|
landed.screenText = reread;
|
|
87998
88248
|
}
|
|
87999
88249
|
}
|
|
@@ -101184,19 +101434,37 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
101184
101434
|
}
|
|
101185
101435
|
},
|
|
101186
101436
|
// ─── MAGI kind → panel bindings (MAGI-KIND-PANEL, machine-local config) ───
|
|
101187
|
-
// Per-task_kind slot lists in ~/.adhdev/meshes.json
|
|
101188
|
-
// MAGI panel-resolution surface (the former
|
|
101189
|
-
// removed).
|
|
101437
|
+
// Per-task_kind slot lists stored PER MESH in ~/.adhdev/meshes.json
|
|
101438
|
+
// (`meshes[].magiKindPanels`) — the SOLE MAGI panel-resolution surface (the former
|
|
101439
|
+
// named-panel magi_panel_* handlers were removed). `meshId` is optional on all three
|
|
101440
|
+
// so existing callers keep working: it resolves to the sole mesh on a single-mesh
|
|
101441
|
+
// machine, and is REQUIRED (loud error, never a silent pick) when several meshes
|
|
101442
|
+
// exist. Owner-only gating: intentionally NOT listed in
|
|
101190
101443
|
// canPeerUsePrivilegedShareCommand (daemon-cloud data-channel-router), so a peer
|
|
101191
101444
|
// holding ANY share permission hits its `default → false` branch — identical
|
|
101192
101445
|
// owner-only gating to create_mesh / update_mesh / list_meshes. A trusted peer (no
|
|
101193
101446
|
// permission = the owner) passes the top `!permission → true` guard. set/remove are
|
|
101194
101447
|
// WRITE commands; list is read-only. normalizeMagiSlots (inside setMagiKindPanel)
|
|
101195
|
-
// surfaces invalid_magi_kind_panel: … messages verbatim for the editor
|
|
101196
|
-
|
|
101448
|
+
// surfaces invalid_magi_kind_panel: … messages verbatim for the editor, including
|
|
101449
|
+
// a nodeId that is not a member of the target mesh.
|
|
101450
|
+
magi_kind_panel_list: async (_ctx, args) => {
|
|
101451
|
+
const requestedMeshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
101197
101452
|
try {
|
|
101198
|
-
const { listMagiKindPanels: listMagiKindPanels2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101199
|
-
|
|
101453
|
+
const { listMagiKindPanels: listMagiKindPanels2, resolveScopedMeshId: resolveScopedMeshId2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101454
|
+
const meshId = requestedMeshId || resolveScopedMeshId2();
|
|
101455
|
+
return {
|
|
101456
|
+
success: true,
|
|
101457
|
+
kindPanels: listMagiKindPanels2(requestedMeshId || void 0),
|
|
101458
|
+
scope: {
|
|
101459
|
+
kind: "mesh",
|
|
101460
|
+
storage: "machine_local",
|
|
101461
|
+
meshId: meshId ?? null,
|
|
101462
|
+
resolvedFrom: requestedMeshId ? "explicit" : meshId ? "sole_mesh" : "ambiguous",
|
|
101463
|
+
...requestedMeshId || meshId ? {} : {
|
|
101464
|
+
note: "Several meshes are configured and no meshId was given, so no panels could be read. Pass meshId."
|
|
101465
|
+
}
|
|
101466
|
+
}
|
|
101467
|
+
};
|
|
101200
101468
|
} catch (e) {
|
|
101201
101469
|
return { success: false, error: e.message };
|
|
101202
101470
|
}
|
|
@@ -101204,10 +101472,12 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
101204
101472
|
magi_kind_panel_set: async (_ctx, args) => {
|
|
101205
101473
|
const kind = typeof args?.kind === "string" ? args.kind.trim() : "";
|
|
101206
101474
|
if (!kind) return { success: false, error: "invalid_magi_kind_panel: task_kind is required" };
|
|
101475
|
+
const requestedMeshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
101207
101476
|
try {
|
|
101208
|
-
const { setMagiKindPanel: setMagiKindPanel2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101209
|
-
const slots = setMagiKindPanel2(kind, args?.slots);
|
|
101210
|
-
|
|
101477
|
+
const { setMagiKindPanel: setMagiKindPanel2, resolveScopedMeshId: resolveScopedMeshId2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101478
|
+
const slots = setMagiKindPanel2(kind, args?.slots, requestedMeshId || void 0);
|
|
101479
|
+
const meshId = requestedMeshId || resolveScopedMeshId2();
|
|
101480
|
+
return { success: true, kind, slots, meshId: meshId ?? null };
|
|
101211
101481
|
} catch (e) {
|
|
101212
101482
|
return { success: false, error: e.message };
|
|
101213
101483
|
}
|
|
@@ -101215,30 +101485,52 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
101215
101485
|
magi_kind_panel_remove: async (_ctx, args) => {
|
|
101216
101486
|
const kind = typeof args?.kind === "string" ? args.kind.trim() : "";
|
|
101217
101487
|
if (!kind) return { success: false, error: "invalid_magi_kind_panel: task_kind is required" };
|
|
101488
|
+
const requestedMeshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
101218
101489
|
try {
|
|
101219
|
-
const { removeMagiKindPanel: removeMagiKindPanel2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101220
|
-
const removed = removeMagiKindPanel2(kind);
|
|
101221
|
-
|
|
101490
|
+
const { removeMagiKindPanel: removeMagiKindPanel2, resolveScopedMeshId: resolveScopedMeshId2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101491
|
+
const removed = removeMagiKindPanel2(kind, requestedMeshId || void 0);
|
|
101492
|
+
const meshId = requestedMeshId || resolveScopedMeshId2();
|
|
101493
|
+
return { success: true, removed, meshId: meshId ?? null };
|
|
101222
101494
|
} catch (e) {
|
|
101223
101495
|
return { success: false, error: e.message };
|
|
101224
101496
|
}
|
|
101225
101497
|
},
|
|
101226
|
-
// ─── Brain routing: per-difficulty brain presets (machine-local) ───
|
|
101227
|
-
// getDifficultyBrains returns the seeded defaults when
|
|
101228
|
-
// so the editor always shows a usable mapping. set replaces the whole
|
|
101229
|
-
|
|
101498
|
+
// ─── Brain routing: per-difficulty brain presets (PER MESH, machine-local) ───
|
|
101499
|
+
// getDifficultyBrains returns the seeded defaults when the mesh has nothing
|
|
101500
|
+
// configured, so the editor always shows a usable mapping. set replaces the whole
|
|
101501
|
+
// map for ONE mesh. `meshId` is optional and resolves to the sole mesh, so
|
|
101502
|
+
// existing callers keep working; with several meshes a write must name its mesh
|
|
101503
|
+
// (these presets choose the model a task runs on — writing to the wrong mesh
|
|
101504
|
+
// changes what that mesh costs).
|
|
101505
|
+
difficulty_brains_get: async (_ctx, args) => {
|
|
101506
|
+
const requestedMeshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
101230
101507
|
try {
|
|
101231
|
-
const { getDifficultyBrains: getDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101232
|
-
|
|
101508
|
+
const { getDifficultyBrains: getDifficultyBrains2, resolveScopedMeshId: resolveScopedMeshId2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101509
|
+
const meshId = requestedMeshId || resolveScopedMeshId2();
|
|
101510
|
+
return {
|
|
101511
|
+
success: true,
|
|
101512
|
+
difficultyBrains: getDifficultyBrains2(requestedMeshId || void 0),
|
|
101513
|
+
scope: {
|
|
101514
|
+
kind: "mesh",
|
|
101515
|
+
storage: "machine_local",
|
|
101516
|
+
meshId: meshId ?? null,
|
|
101517
|
+
resolvedFrom: requestedMeshId ? "explicit" : meshId ? "sole_mesh" : "ambiguous",
|
|
101518
|
+
...requestedMeshId || meshId ? {} : {
|
|
101519
|
+
note: "Several meshes are configured and no meshId was given, so these are the shipped defaults, not any mesh's saved presets. Pass meshId."
|
|
101520
|
+
}
|
|
101521
|
+
}
|
|
101522
|
+
};
|
|
101233
101523
|
} catch (e) {
|
|
101234
101524
|
return { success: false, error: e.message };
|
|
101235
101525
|
}
|
|
101236
101526
|
},
|
|
101237
101527
|
difficulty_brains_set: async (_ctx, args) => {
|
|
101528
|
+
const requestedMeshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
101238
101529
|
try {
|
|
101239
|
-
const { setDifficultyBrains: setDifficultyBrains2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101240
|
-
const difficultyBrains = setDifficultyBrains2(args?.difficultyBrains);
|
|
101241
|
-
|
|
101530
|
+
const { setDifficultyBrains: setDifficultyBrains2, resolveScopedMeshId: resolveScopedMeshId2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
101531
|
+
const difficultyBrains = setDifficultyBrains2(args?.difficultyBrains, requestedMeshId || void 0);
|
|
101532
|
+
const meshId = requestedMeshId || resolveScopedMeshId2();
|
|
101533
|
+
return { success: true, difficultyBrains, meshId: meshId ?? null };
|
|
101242
101534
|
} catch (e) {
|
|
101243
101535
|
return { success: false, error: e.message };
|
|
101244
101536
|
}
|
|
@@ -102889,10 +103181,10 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
102889
103181
|
return void 0;
|
|
102890
103182
|
}
|
|
102891
103183
|
};
|
|
102892
|
-
const loadMagiKindPanelsBestEffort = async () => {
|
|
103184
|
+
const loadMagiKindPanelsBestEffort = async (forMeshId) => {
|
|
102893
103185
|
try {
|
|
102894
103186
|
const { listMagiKindPanels: listMagiKindPanels2 } = await Promise.resolve().then(() => (init_mesh_config(), mesh_config_exports));
|
|
102895
|
-
return listMagiKindPanels2();
|
|
103187
|
+
return listMagiKindPanels2(forMeshId);
|
|
102896
103188
|
} catch {
|
|
102897
103189
|
return void 0;
|
|
102898
103190
|
}
|
|
@@ -102994,7 +103286,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
102994
103286
|
if (coordinatorSetup.kind === "cli_command") {
|
|
102995
103287
|
let cliCmdSystemPrompt = "";
|
|
102996
103288
|
try {
|
|
102997
|
-
cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildEffectiveOperatingNotes(mesh.id), magiKindPanels: await loadMagiKindPanelsBestEffort() });
|
|
103289
|
+
cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildEffectiveOperatingNotes(mesh.id), magiKindPanels: await loadMagiKindPanelsBestEffort(meshId) });
|
|
102998
103290
|
} catch (error48) {
|
|
102999
103291
|
const message = error48?.message || String(error48);
|
|
103000
103292
|
LOG2.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
@@ -103191,7 +103483,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
103191
103483
|
}
|
|
103192
103484
|
let systemPrompt = "";
|
|
103193
103485
|
try {
|
|
103194
|
-
systemPrompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildEffectiveOperatingNotes(mesh.id), magiKindPanels: await loadMagiKindPanelsBestEffort() });
|
|
103486
|
+
systemPrompt = buildCoordinatorSystemPrompt2({ mesh: effectiveMesh, coordinatorCliType: cliType, userInstruction: extraSystemPrompt || void 0, missionSection: buildMissionSectionBestEffort(mesh.id), recentActivity: await buildRecentActivityBestEffort(mesh.id), operatingNotes: await buildEffectiveOperatingNotes(mesh.id), magiKindPanels: await loadMagiKindPanelsBestEffort(meshId) });
|
|
103195
103487
|
} catch (error48) {
|
|
103196
103488
|
const message = error48?.message || String(error48);
|
|
103197
103489
|
LOG2.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
|
|
@@ -109175,6 +109467,32 @@ ${e?.stderr || ""}`;
|
|
|
109175
109467
|
init_logger();
|
|
109176
109468
|
init_runtime_defaults();
|
|
109177
109469
|
init_snapshot();
|
|
109470
|
+
function buildCloudStatusReportPayload(sessions, p2p, timestamp2) {
|
|
109471
|
+
const list = Array.isArray(sessions) ? sessions : [];
|
|
109472
|
+
return {
|
|
109473
|
+
sessions: list.map((raw) => {
|
|
109474
|
+
const session = raw || {};
|
|
109475
|
+
return {
|
|
109476
|
+
id: session.id,
|
|
109477
|
+
parentId: session.parentId ?? null,
|
|
109478
|
+
providerType: session.providerType,
|
|
109479
|
+
providerName: session.providerName || session.providerType,
|
|
109480
|
+
kind: session.kind,
|
|
109481
|
+
transport: session.transport,
|
|
109482
|
+
status: session.status,
|
|
109483
|
+
workspace: session.workspace ?? null,
|
|
109484
|
+
cdpConnected: session.cdpConnected,
|
|
109485
|
+
// Forward surfaceHidden/muted so the server can gate push notifications
|
|
109486
|
+
// for coordinator-hidden and user-muted sessions (the WS path is the
|
|
109487
|
+
// only one the server sees). Both are plain booleans, not content.
|
|
109488
|
+
surfaceHidden: session.surfaceHidden,
|
|
109489
|
+
muted: session.muted
|
|
109490
|
+
};
|
|
109491
|
+
}),
|
|
109492
|
+
p2p,
|
|
109493
|
+
timestamp: timestamp2
|
|
109494
|
+
};
|
|
109495
|
+
}
|
|
109178
109496
|
var DaemonStatusReporter = class {
|
|
109179
109497
|
deps;
|
|
109180
109498
|
log;
|
|
@@ -109388,28 +109706,7 @@ ${e?.stderr || ""}`;
|
|
|
109388
109706
|
}
|
|
109389
109707
|
if (opts?.p2pOnly) return;
|
|
109390
109708
|
if (!serverConnected || !serverConn) return;
|
|
109391
|
-
const
|
|
109392
|
-
const wsPayload = {
|
|
109393
|
-
sessions: payloadSessions.map((session) => ({
|
|
109394
|
-
id: session.id,
|
|
109395
|
-
parentId: session.parentId,
|
|
109396
|
-
providerType: session.providerType,
|
|
109397
|
-
providerName: session.providerName || session.providerType,
|
|
109398
|
-
kind: session.kind,
|
|
109399
|
-
transport: session.transport,
|
|
109400
|
-
status: session.status,
|
|
109401
|
-
workspace: session.workspace ?? null,
|
|
109402
|
-
title: session.title,
|
|
109403
|
-
cdpConnected: session.cdpConnected,
|
|
109404
|
-
summaryMetadata: session.summaryMetadata,
|
|
109405
|
-
settings: session.settings,
|
|
109406
|
-
// Forward surfaceHidden so the server can gate push notifications for
|
|
109407
|
-
// coordinator-hidden sessions (the WS path is the only one the server sees).
|
|
109408
|
-
surfaceHidden: session.surfaceHidden
|
|
109409
|
-
})),
|
|
109410
|
-
p2p: payload.p2p,
|
|
109411
|
-
timestamp: now
|
|
109412
|
-
};
|
|
109709
|
+
const wsPayload = buildCloudStatusReportPayload(payload.sessions, payload.p2p, now);
|
|
109413
109710
|
const wsHash = this.simpleHash(JSON.stringify({
|
|
109414
109711
|
...wsPayload,
|
|
109415
109712
|
timestamp: void 0
|