@adhdev/daemon-standalone 0.9.82-rc.310 → 0.9.82-rc.312
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 +1059 -262
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/index-Cw4o3csc.css +1 -0
- package/public/assets/index-DiyV4rNX.js +113 -0
- package/public/assets/index-jzEwV60L.js +114 -0
- package/public/index.html +2 -2
- package/vendor/mcp-server/index.js +41 -0
- package/vendor/mcp-server/index.js.map +1 -1
package/dist/index.js
CHANGED
|
@@ -29735,6 +29735,18 @@ var require_dist3 = __commonJS({
|
|
|
29735
29735
|
mod
|
|
29736
29736
|
));
|
|
29737
29737
|
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
29738
|
+
function normalizeMeshSchedulingStrategy(value) {
|
|
29739
|
+
if (typeof value !== "string") return DEFAULT_MESH_SCHEDULING_STRATEGY;
|
|
29740
|
+
const trimmed = value.trim();
|
|
29741
|
+
return MESH_SCHEDULING_STRATEGIES.includes(trimmed) ? trimmed : DEFAULT_MESH_SCHEDULING_STRATEGY;
|
|
29742
|
+
}
|
|
29743
|
+
function resolveNodeSchedulingPriority(nodePolicy) {
|
|
29744
|
+
const raw = Number(nodePolicy?.schedulingPriority);
|
|
29745
|
+
return Number.isFinite(raw) ? raw : 0;
|
|
29746
|
+
}
|
|
29747
|
+
function resolveAutoConvergeCodeChange(policy) {
|
|
29748
|
+
return policy?.autoConvergeCodeChange === true;
|
|
29749
|
+
}
|
|
29738
29750
|
function resolveDelegatedWorkerAutoApprove(meshPolicy, nodePolicy) {
|
|
29739
29751
|
if (typeof nodePolicy?.delegatedWorkerAutoApprove === "boolean") {
|
|
29740
29752
|
return nodePolicy.delegatedWorkerAutoApprove;
|
|
@@ -29762,10 +29774,23 @@ var require_dist3 = __commonJS({
|
|
|
29762
29774
|
if (!Number.isFinite(raw) || raw < 0) return void 0;
|
|
29763
29775
|
return Math.floor(raw);
|
|
29764
29776
|
}
|
|
29777
|
+
var MESH_SCHEDULING_STRATEGIES;
|
|
29778
|
+
var DEFAULT_MESH_SCHEDULING_STRATEGY;
|
|
29779
|
+
var MESH_CONVERGE_REFINE_TAG;
|
|
29780
|
+
var MESH_CONVERGE_FAST_FORWARD_TAG;
|
|
29765
29781
|
var DEFAULT_MESH_POLICY;
|
|
29766
29782
|
var init_repo_mesh_types = __esm2({
|
|
29767
29783
|
"src/repo-mesh-types.ts"() {
|
|
29768
29784
|
"use strict";
|
|
29785
|
+
MESH_SCHEDULING_STRATEGIES = [
|
|
29786
|
+
"first_eligible",
|
|
29787
|
+
"least_loaded",
|
|
29788
|
+
"round_robin",
|
|
29789
|
+
"priority_only"
|
|
29790
|
+
];
|
|
29791
|
+
DEFAULT_MESH_SCHEDULING_STRATEGY = "first_eligible";
|
|
29792
|
+
MESH_CONVERGE_REFINE_TAG = "converge=refine";
|
|
29793
|
+
MESH_CONVERGE_FAST_FORWARD_TAG = "converge=fast_forward";
|
|
29769
29794
|
DEFAULT_MESH_POLICY = {
|
|
29770
29795
|
requirePreTaskCheckpoint: false,
|
|
29771
29796
|
requirePostTaskCheckpoint: true,
|
|
@@ -30004,10 +30029,10 @@ var require_dist3 = __commonJS({
|
|
|
30004
30029
|
}
|
|
30005
30030
|
function getDaemonBuildInfo() {
|
|
30006
30031
|
if (cached2) return cached2;
|
|
30007
|
-
const commit = readInjected(true ? "
|
|
30008
|
-
const commitShort = readInjected(true ? "
|
|
30009
|
-
const version2 = readInjected(true ? "0.9.82-rc.
|
|
30010
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
30032
|
+
const commit = readInjected(true ? "35facf0367dbbe37f25a3b5589287dc757ee6213" : void 0) ?? "unknown";
|
|
30033
|
+
const commitShort = readInjected(true ? "35facf03" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
30034
|
+
const version2 = readInjected(true ? "0.9.82-rc.312" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
30035
|
+
const builtAt = readInjected(true ? "2026-06-17T22:49:21.710Z" : void 0);
|
|
30011
30036
|
cached2 = builtAt ? { commit, commitShort, version: version2, builtAt } : { commit, commitShort, version: version2 };
|
|
30012
30037
|
return cached2;
|
|
30013
30038
|
}
|
|
@@ -31261,6 +31286,17 @@ ${error48.message || ""}`;
|
|
|
31261
31286
|
if (!SPAWNED_SESSION_VISIBILITY_MODES.has(String(policy.spawnedSessionVisibility))) {
|
|
31262
31287
|
policy.spawnedSessionVisibility = "visible";
|
|
31263
31288
|
}
|
|
31289
|
+
const normalizedStrategy = normalizeMeshSchedulingStrategy(policy.schedulingStrategy);
|
|
31290
|
+
if (normalizedStrategy === "first_eligible") {
|
|
31291
|
+
delete policy.schedulingStrategy;
|
|
31292
|
+
} else {
|
|
31293
|
+
policy.schedulingStrategy = normalizedStrategy;
|
|
31294
|
+
}
|
|
31295
|
+
if (policy.autoConvergeCodeChange === true) {
|
|
31296
|
+
policy.autoConvergeCodeChange = true;
|
|
31297
|
+
} else {
|
|
31298
|
+
delete policy.autoConvergeCodeChange;
|
|
31299
|
+
}
|
|
31264
31300
|
return policy;
|
|
31265
31301
|
}
|
|
31266
31302
|
function normalizeAutoFastForwardPolicy(value) {
|
|
@@ -31809,6 +31845,7 @@ ${rules.join("\n")}`;
|
|
|
31809
31845
|
| \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
|
|
31810
31846
|
| \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
|
|
31811
31847
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
31848
|
+
| \`mesh_read_node_logs\` | Fetch a remote node's daemon log tail directly over P2P (grep/since/byte-bounded, secrets redacted) \u2014 no session/PowerShell needed to debug a node's daemon |
|
|
31812
31849
|
| \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
|
|
31813
31850
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
31814
31851
|
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
@@ -32573,6 +32610,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
32573
32610
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
32574
32611
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
32575
32612
|
requeueTask: () => requeueTask,
|
|
32613
|
+
resolveConvergeRequiredTags: () => resolveConvergeRequiredTags,
|
|
32576
32614
|
updateDirectDispatchStatus: () => updateDirectDispatchStatus,
|
|
32577
32615
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
32578
32616
|
updateTaskStatus: () => updateTaskStatus,
|
|
@@ -32646,6 +32684,21 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
32646
32684
|
if (!Array.isArray(raw)) return void 0;
|
|
32647
32685
|
return raw.find((type) => typeof type === "string" && type.trim())?.trim();
|
|
32648
32686
|
}
|
|
32687
|
+
function roleCapabilityTags(policy, providerType) {
|
|
32688
|
+
const roles = policy && typeof policy === "object" && !Array.isArray(policy) ? policy.providerRoles : void 0;
|
|
32689
|
+
if (!Array.isArray(roles)) return [];
|
|
32690
|
+
const wantedProvider = typeof providerType === "string" && providerType.trim() ? providerType.trim().toLowerCase() : "";
|
|
32691
|
+
const out = [];
|
|
32692
|
+
for (const entry of roles) {
|
|
32693
|
+
if (!entry || typeof entry !== "object") continue;
|
|
32694
|
+
const type = typeof entry.providerType === "string" ? entry.providerType.trim().toLowerCase() : "";
|
|
32695
|
+
const role = typeof entry.role === "string" ? entry.role.trim().toLowerCase() : "";
|
|
32696
|
+
if (!role) continue;
|
|
32697
|
+
if (wantedProvider && type && type !== wantedProvider) continue;
|
|
32698
|
+
out.push(`role=${role}`);
|
|
32699
|
+
}
|
|
32700
|
+
return out;
|
|
32701
|
+
}
|
|
32649
32702
|
function buildMeshNodeCapabilityTags(node, providerType) {
|
|
32650
32703
|
const provider = typeof providerType === "string" && providerType.trim() ? providerType.trim() : firstProviderPriority(node?.policy);
|
|
32651
32704
|
const worktreeBranch = typeof node?.worktreeBranch === "string" && node.worktreeBranch.trim() ? node.worktreeBranch.trim() : null;
|
|
@@ -32657,7 +32710,25 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
32657
32710
|
// Worktree nodes automatically expose a "worktree=<branch>" tag so that
|
|
32658
32711
|
// mesh_enqueue_task with required_tags: ["worktree=<branch>"] routes
|
|
32659
32712
|
// only to the matching worktree node.
|
|
32660
|
-
...node?.isLocalWorktree === true && worktreeBranch ? [`worktree=${worktreeBranch}`] : []
|
|
32713
|
+
...node?.isLocalWorktree === true && worktreeBranch ? [`worktree=${worktreeBranch}`] : [],
|
|
32714
|
+
// Convergence routing: advertise how this node can land its work onto base.
|
|
32715
|
+
// - converge=refine: local worktree nodes (on ANY machine — refine_mesh_node
|
|
32716
|
+
// now forwards to the owning daemon) can run the Refinery merge → push →
|
|
32717
|
+
// cleanup against their own checkout, so they accept code_change tasks.
|
|
32718
|
+
// - converge=fast_forward: non-worktree nodes (the machine itself) can only
|
|
32719
|
+
// ff/push an already-converged branch; they are NOT a destination for
|
|
32720
|
+
// code_change work (a worktree is created first, and that worktree node
|
|
32721
|
+
// receives the task instead). Reuses the ordinary required-tags filter —
|
|
32722
|
+
// the load-balancing scheduler auto-injects converge=refine for code_change
|
|
32723
|
+
// so such work is hard-filtered onto refine-capable nodes.
|
|
32724
|
+
...node?.isLocalWorktree === true ? ["converge=refine"] : ["converge=fast_forward"],
|
|
32725
|
+
// Role-based routing: advertise role=<x> for each (node, provider) role
|
|
32726
|
+
// declared in policy.providerRoles. Narrowed to the selected provider when
|
|
32727
|
+
// one is given so the chosen provider must match a task's required role;
|
|
32728
|
+
// when no provider is selected, all declared roles are advertised for the
|
|
32729
|
+
// node-level eligibility scan. Reuses the ordinary required-tags filter —
|
|
32730
|
+
// no separate role field/gate.
|
|
32731
|
+
...roleCapabilityTags(node?.policy, providerType)
|
|
32661
32732
|
]);
|
|
32662
32733
|
}
|
|
32663
32734
|
function nodeSatisfiesRequiredTags(requiredTags, capabilityTags) {
|
|
@@ -32666,6 +32737,18 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
32666
32737
|
const available = new Set(normalizeMeshCapabilityTags(capabilityTags));
|
|
32667
32738
|
return required2.every((tag) => available.has(tag));
|
|
32668
32739
|
}
|
|
32740
|
+
function resolveConvergeRequiredTags(meshId, taskMode, explicitRequiredTags, opts) {
|
|
32741
|
+
if (taskMode !== "code_change") return explicitRequiredTags;
|
|
32742
|
+
if (typeof opts?.targetNodeId === "string" && opts.targetNodeId.trim()) return explicitRequiredTags;
|
|
32743
|
+
let optedIn = false;
|
|
32744
|
+
try {
|
|
32745
|
+
optedIn = resolveAutoConvergeCodeChange(getMesh(meshId)?.policy);
|
|
32746
|
+
} catch {
|
|
32747
|
+
optedIn = false;
|
|
32748
|
+
}
|
|
32749
|
+
if (!optedIn) return explicitRequiredTags;
|
|
32750
|
+
return normalizeMeshCapabilityTags([...explicitRequiredTags, MESH_CONVERGE_REFINE_TAG]);
|
|
32751
|
+
}
|
|
32669
32752
|
function withQueueLock(_meshId, fn) {
|
|
32670
32753
|
return MeshRuntimeStore.getInstance().transaction(fn);
|
|
32671
32754
|
}
|
|
@@ -32724,7 +32807,15 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
32724
32807
|
taskMode: modeValidation.taskMode,
|
|
32725
32808
|
targetNodeId: opts?.targetNodeId,
|
|
32726
32809
|
targetSessionId: opts?.targetSessionId,
|
|
32727
|
-
|
|
32810
|
+
// Convergence routing (opt-in): auto-inject converge=refine for code_change
|
|
32811
|
+
// tasks so they hard-filter onto refine-capable worktree nodes. No-op unless
|
|
32812
|
+
// the mesh opts in; explicit target_node_id / required_tags are preserved.
|
|
32813
|
+
requiredTags: resolveConvergeRequiredTags(
|
|
32814
|
+
meshId,
|
|
32815
|
+
modeValidation.taskMode,
|
|
32816
|
+
normalizeMeshCapabilityTags(opts?.requiredTags),
|
|
32817
|
+
{ targetNodeId: opts?.targetNodeId }
|
|
32818
|
+
),
|
|
32728
32819
|
...dependsOn.length > 0 ? { dependsOn } : {},
|
|
32729
32820
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
32730
32821
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -32992,6 +33083,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
32992
33083
|
"use strict";
|
|
32993
33084
|
import_crypto5 = require("crypto");
|
|
32994
33085
|
init_mesh_host_ownership();
|
|
33086
|
+
init_repo_mesh_types();
|
|
32995
33087
|
init_mesh_runtime_store();
|
|
32996
33088
|
init_mesh_config();
|
|
32997
33089
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
@@ -33289,6 +33381,17 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
33289
33381
|
|
|
33290
33382
|
CREATE INDEX IF NOT EXISTS idx_mesh_missions_mesh_status
|
|
33291
33383
|
ON mesh_missions(mesh_id, status, updated_at);
|
|
33384
|
+
|
|
33385
|
+
-- Load-balancing scheduler: per-mesh round-robin rotation cursor. When
|
|
33386
|
+
-- the schedulingStrategy is 'round_robin', several eligible nodes tied at
|
|
33387
|
+
-- the least load are rotated by this cursor so the tie-break winner cycles
|
|
33388
|
+
-- across scheduling passes instead of always favouring the same array-order
|
|
33389
|
+
-- node. Persisted (not a module Map) so rotation survives daemon restarts
|
|
33390
|
+
-- and stays a single source of truth across scheduling entry points.
|
|
33391
|
+
CREATE TABLE IF NOT EXISTS mesh_scheduler_cursor (
|
|
33392
|
+
mesh_id TEXT PRIMARY KEY,
|
|
33393
|
+
cursor INTEGER NOT NULL DEFAULT 0
|
|
33394
|
+
);
|
|
33292
33395
|
`);
|
|
33293
33396
|
}
|
|
33294
33397
|
hasCompletionFingerprint(fingerprint) {
|
|
@@ -33466,6 +33569,44 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
33466
33569
|
`).get(meshId, nodeId);
|
|
33467
33570
|
return row !== void 0;
|
|
33468
33571
|
}
|
|
33572
|
+
/**
|
|
33573
|
+
* Count active (status='assigned') tasks on a node, regardless of provider or
|
|
33574
|
+
* task mode. This is the load metric for least-loaded / round-robin ranking:
|
|
33575
|
+
* the scheduler prefers the node with the fewest active assignments so
|
|
33576
|
+
* untargeted work spreads instead of piling onto whichever node asks first.
|
|
33577
|
+
*/
|
|
33578
|
+
nodeActiveAssignmentCount(meshId, nodeId) {
|
|
33579
|
+
const row = this.db.prepare(`
|
|
33580
|
+
SELECT COUNT(*) as count FROM mesh_queue
|
|
33581
|
+
WHERE mesh_id = ? AND status = 'assigned' AND assigned_node_id = ?
|
|
33582
|
+
`).get(meshId, nodeId);
|
|
33583
|
+
return row?.count ?? 0;
|
|
33584
|
+
}
|
|
33585
|
+
/**
|
|
33586
|
+
* Read the current per-mesh round-robin cursor (0 when unset). Used to rotate
|
|
33587
|
+
* the tie-break winner among nodes tied at the least load.
|
|
33588
|
+
*/
|
|
33589
|
+
getSchedulerCursor(meshId) {
|
|
33590
|
+
const row = this.db.prepare(
|
|
33591
|
+
"SELECT cursor FROM mesh_scheduler_cursor WHERE mesh_id = ?"
|
|
33592
|
+
).get(meshId);
|
|
33593
|
+
return row?.cursor ?? 0;
|
|
33594
|
+
}
|
|
33595
|
+
/**
|
|
33596
|
+
* Atomically advance the per-mesh round-robin cursor by one and return the
|
|
33597
|
+
* value that was current BEFORE the bump (the value the caller should rotate
|
|
33598
|
+
* by for this pass). UPSERT keeps it lock-free across concurrent passes.
|
|
33599
|
+
*/
|
|
33600
|
+
bumpSchedulerCursor(meshId) {
|
|
33601
|
+
return this.transaction(() => {
|
|
33602
|
+
const current = this.getSchedulerCursor(meshId);
|
|
33603
|
+
this.db.prepare(`
|
|
33604
|
+
INSERT INTO mesh_scheduler_cursor (mesh_id, cursor) VALUES (?, ?)
|
|
33605
|
+
ON CONFLICT(mesh_id) DO UPDATE SET cursor = excluded.cursor
|
|
33606
|
+
`).run(meshId, current + 1);
|
|
33607
|
+
return current;
|
|
33608
|
+
});
|
|
33609
|
+
}
|
|
33469
33610
|
/**
|
|
33470
33611
|
* Count active (status='assigned') tasks on a (node, provider) combination,
|
|
33471
33612
|
* matched by the assignedProviderType stamped on the payload at claim time.
|
|
@@ -35445,8 +35586,8 @@ ${rendered}`, "utf-8");
|
|
|
35445
35586
|
const remaining = (existing.slice(0, openIdx) + existing.slice(closeIdx + CLOSE.length)).replace(/^\s*\n+/, "").replace(/\n+\s*$/, "");
|
|
35446
35587
|
if (!remaining.trim()) {
|
|
35447
35588
|
try {
|
|
35448
|
-
const
|
|
35449
|
-
|
|
35589
|
+
const fs31 = require("fs");
|
|
35590
|
+
fs31.unlinkSync(filePath);
|
|
35450
35591
|
} catch {
|
|
35451
35592
|
}
|
|
35452
35593
|
} else {
|
|
@@ -38051,6 +38192,33 @@ Next step: ${nextStep}`;
|
|
|
38051
38192
|
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
38052
38193
|
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
|
|
38053
38194
|
}
|
|
38195
|
+
function nodeActiveLoad(meshId, nodeId) {
|
|
38196
|
+
return MeshRuntimeStore.getInstance().nodeActiveAssignmentCount(meshId, nodeId);
|
|
38197
|
+
}
|
|
38198
|
+
function resolveSchedulingStrategy(mesh) {
|
|
38199
|
+
return normalizeMeshSchedulingStrategy(mesh?.policy?.schedulingStrategy);
|
|
38200
|
+
}
|
|
38201
|
+
function orderEligibleNodes(meshId, strategy, nodes, opts) {
|
|
38202
|
+
if (strategy === "first_eligible" || nodes.length <= 1) {
|
|
38203
|
+
return nodes;
|
|
38204
|
+
}
|
|
38205
|
+
const priorityOf = (n) => resolveNodeSchedulingPriority(n.node?.policy);
|
|
38206
|
+
let rotation = 0;
|
|
38207
|
+
if (strategy === "round_robin") {
|
|
38208
|
+
const cursor = opts?.bumpCursor ? MeshRuntimeStore.getInstance().bumpSchedulerCursor(meshId) : MeshRuntimeStore.getInstance().getSchedulerCursor(meshId);
|
|
38209
|
+
rotation = (cursor % nodes.length + nodes.length) % nodes.length;
|
|
38210
|
+
}
|
|
38211
|
+
const rotationRank = (index) => (index - rotation + nodes.length) % nodes.length;
|
|
38212
|
+
return [...nodes].sort((a, b) => {
|
|
38213
|
+
const prioDelta = priorityOf(b) - priorityOf(a);
|
|
38214
|
+
if (prioDelta !== 0) return prioDelta;
|
|
38215
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
38216
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
38217
|
+
if (loadDelta !== 0) return loadDelta;
|
|
38218
|
+
}
|
|
38219
|
+
return rotationRank(a.index) - rotationRank(b.index);
|
|
38220
|
+
});
|
|
38221
|
+
}
|
|
38054
38222
|
function activeProviderAssignedCount(meshId, nodeId, providerType) {
|
|
38055
38223
|
return getQueue(meshId, { status: ["assigned"] }).filter((task) => task.assignedNodeId === nodeId && task.assignedProviderType === providerType).length;
|
|
38056
38224
|
}
|
|
@@ -38187,7 +38355,14 @@ Next step: ${nextStep}`;
|
|
|
38187
38355
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "no_node_satisfies_required_tags", nodeId: task.targetNodeId });
|
|
38188
38356
|
continue;
|
|
38189
38357
|
}
|
|
38190
|
-
|
|
38358
|
+
const strategy = resolveSchedulingStrategy(mesh);
|
|
38359
|
+
const orderedCandidateNodes = strategy === "first_eligible" ? candidateNodes : orderEligibleNodes(
|
|
38360
|
+
meshId,
|
|
38361
|
+
strategy,
|
|
38362
|
+
candidateNodes.map((node, index) => ({ nodeId: readMeshNodeId(node), node, index })).filter((c) => c.nodeId),
|
|
38363
|
+
{ bumpCursor: true }
|
|
38364
|
+
).map((c) => c.node);
|
|
38365
|
+
for (const node of orderedCandidateNodes) {
|
|
38191
38366
|
const nodeId = readMeshNodeId(node);
|
|
38192
38367
|
if (!nodeId) continue;
|
|
38193
38368
|
const launchKey = `${meshId}:${nodeId}`;
|
|
@@ -38314,6 +38489,8 @@ Next step: ${nextStep}`;
|
|
|
38314
38489
|
noIdleMeshSessionAvailable: true
|
|
38315
38490
|
};
|
|
38316
38491
|
}
|
|
38492
|
+
const strategy = resolveSchedulingStrategy(mesh);
|
|
38493
|
+
const localCandidates = [];
|
|
38317
38494
|
const cliInstances = components.instanceManager.getByCategory("cli");
|
|
38318
38495
|
for (const inst of cliInstances) {
|
|
38319
38496
|
const state = inst.getState();
|
|
@@ -38336,7 +38513,7 @@ Next step: ${nextStep}`;
|
|
|
38336
38513
|
const providerType = state.type || readNonEmptyString2(settings.providerType);
|
|
38337
38514
|
if (providerType) {
|
|
38338
38515
|
localIdleSessionsChecked += 1;
|
|
38339
|
-
|
|
38516
|
+
localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) => readMeshNodeId(n) === nodeId) });
|
|
38340
38517
|
} else {
|
|
38341
38518
|
skippedSessions.push({
|
|
38342
38519
|
nodeId,
|
|
@@ -38350,18 +38527,49 @@ Next step: ${nextStep}`;
|
|
|
38350
38527
|
remoteSessions = MeshRuntimeStore.getInstance().getRemoteIdleSessions();
|
|
38351
38528
|
} catch {
|
|
38352
38529
|
}
|
|
38530
|
+
const remoteCandidates = [];
|
|
38353
38531
|
for (const idle of remoteSessions) {
|
|
38354
38532
|
const node = mesh.nodes.find((n) => n.id === idle.nodeId);
|
|
38355
38533
|
if (node) {
|
|
38356
38534
|
remoteIdleSessionsChecked += 1;
|
|
38357
|
-
|
|
38358
|
-
|
|
38359
|
-
|
|
38360
|
-
|
|
38361
|
-
|
|
38362
|
-
|
|
38535
|
+
remoteCandidates.push({ nodeId: idle.nodeId, sessionId: idle.sessionId, providerType: idle.providerType, origin: "remote", node });
|
|
38536
|
+
}
|
|
38537
|
+
}
|
|
38538
|
+
const assignIdleCandidate = (candidate) => {
|
|
38539
|
+
const assigned = tryAssignQueueTask(components, meshId, candidate.nodeId, candidate.sessionId, candidate.providerType);
|
|
38540
|
+
if (assigned && candidate.origin === "remote") {
|
|
38541
|
+
try {
|
|
38542
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(candidate.nodeId, candidate.sessionId);
|
|
38543
|
+
} catch {
|
|
38363
38544
|
}
|
|
38364
38545
|
}
|
|
38546
|
+
};
|
|
38547
|
+
if (strategy === "first_eligible") {
|
|
38548
|
+
for (const candidate of localCandidates) assignIdleCandidate(candidate);
|
|
38549
|
+
for (const candidate of remoteCandidates) assignIdleCandidate(candidate);
|
|
38550
|
+
} else {
|
|
38551
|
+
const pool = [...localCandidates, ...remoteCandidates];
|
|
38552
|
+
const baseIndex = /* @__PURE__ */ new Map();
|
|
38553
|
+
pool.forEach((c, i) => {
|
|
38554
|
+
if (!baseIndex.has(c.nodeId)) baseIndex.set(c.nodeId, i);
|
|
38555
|
+
});
|
|
38556
|
+
const uniqueNodes = [...new Set(pool.map((c) => c.nodeId))].map((nodeId, index) => ({ nodeId, node: pool.find((c) => c.nodeId === nodeId)?.node, index }));
|
|
38557
|
+
const ranked = orderEligibleNodes(meshId, strategy, uniqueNodes, { bumpCursor: true });
|
|
38558
|
+
const rankIndex = new Map(ranked.map((r, i) => [r.nodeId, i]));
|
|
38559
|
+
const remaining = [...pool];
|
|
38560
|
+
while (remaining.length > 0) {
|
|
38561
|
+
remaining.sort((a, b) => {
|
|
38562
|
+
const aPrio = resolveNodeSchedulingPriority(a.node?.policy);
|
|
38563
|
+
const bPrio = resolveNodeSchedulingPriority(b.node?.policy);
|
|
38564
|
+
if (aPrio !== bPrio) return bPrio - aPrio;
|
|
38565
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
38566
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
38567
|
+
if (loadDelta !== 0) return loadDelta;
|
|
38568
|
+
}
|
|
38569
|
+
return (rankIndex.get(a.nodeId) ?? 0) - (rankIndex.get(b.nodeId) ?? 0);
|
|
38570
|
+
});
|
|
38571
|
+
assignIdleCandidate(remaining.shift());
|
|
38572
|
+
}
|
|
38365
38573
|
}
|
|
38366
38574
|
autoLaunchStarted = await maybeAutoLaunchOneQueueSession(components, meshId, mesh);
|
|
38367
38575
|
const afterQueue = getQueue(meshId);
|
|
@@ -40424,8 +40632,8 @@ Next step: ${nextStep}`;
|
|
|
40424
40632
|
let cwd = options.cwd;
|
|
40425
40633
|
if (cwd) {
|
|
40426
40634
|
try {
|
|
40427
|
-
const
|
|
40428
|
-
const stat2 =
|
|
40635
|
+
const fs31 = require("fs");
|
|
40636
|
+
const stat2 = fs31.statSync(cwd);
|
|
40429
40637
|
if (!stat2.isDirectory()) cwd = os11.homedir();
|
|
40430
40638
|
} catch {
|
|
40431
40639
|
cwd = os11.homedir();
|
|
@@ -40530,9 +40738,9 @@ Next step: ${nextStep}`;
|
|
|
40530
40738
|
for (const ext of exes) {
|
|
40531
40739
|
const fullPath = path17.join(p, trimmed + ext);
|
|
40532
40740
|
try {
|
|
40533
|
-
const
|
|
40534
|
-
if (
|
|
40535
|
-
const stat2 =
|
|
40741
|
+
const fs31 = require("fs");
|
|
40742
|
+
if (fs31.existsSync(fullPath)) {
|
|
40743
|
+
const stat2 = fs31.statSync(fullPath);
|
|
40536
40744
|
if (stat2.isFile() && (isWin || stat2.mode & 73)) {
|
|
40537
40745
|
return fullPath;
|
|
40538
40746
|
}
|
|
@@ -40546,12 +40754,12 @@ Next step: ${nextStep}`;
|
|
|
40546
40754
|
function isScriptBinary(binaryPath) {
|
|
40547
40755
|
if (!path17.isAbsolute(binaryPath)) return false;
|
|
40548
40756
|
try {
|
|
40549
|
-
const
|
|
40550
|
-
const resolved =
|
|
40757
|
+
const fs31 = require("fs");
|
|
40758
|
+
const resolved = fs31.realpathSync(binaryPath);
|
|
40551
40759
|
const head = Buffer.alloc(8);
|
|
40552
|
-
const fd =
|
|
40553
|
-
|
|
40554
|
-
|
|
40760
|
+
const fd = fs31.openSync(resolved, "r");
|
|
40761
|
+
fs31.readSync(fd, head, 0, 8, 0);
|
|
40762
|
+
fs31.closeSync(fd);
|
|
40555
40763
|
let i = 0;
|
|
40556
40764
|
if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
|
|
40557
40765
|
return head[i] === 35 && head[i + 1] === 33;
|
|
@@ -40562,12 +40770,12 @@ Next step: ${nextStep}`;
|
|
|
40562
40770
|
function looksLikeMachOOrElf(filePath) {
|
|
40563
40771
|
if (!path17.isAbsolute(filePath)) return false;
|
|
40564
40772
|
try {
|
|
40565
|
-
const
|
|
40566
|
-
const resolved =
|
|
40773
|
+
const fs31 = require("fs");
|
|
40774
|
+
const resolved = fs31.realpathSync(filePath);
|
|
40567
40775
|
const buf = Buffer.alloc(8);
|
|
40568
|
-
const fd =
|
|
40569
|
-
|
|
40570
|
-
|
|
40776
|
+
const fd = fs31.openSync(resolved, "r");
|
|
40777
|
+
fs31.readSync(fd, buf, 0, 8, 0);
|
|
40778
|
+
fs31.closeSync(fd);
|
|
40571
40779
|
let i = 0;
|
|
40572
40780
|
if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
|
|
40573
40781
|
const b = buf.subarray(i);
|
|
@@ -41743,7 +41951,7 @@ ${cont}` : cont;
|
|
|
41743
41951
|
scheduleSettle() {
|
|
41744
41952
|
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
41745
41953
|
const epoch = this.responseEpoch;
|
|
41746
|
-
const
|
|
41954
|
+
const delay2 = Math.max(
|
|
41747
41955
|
this.timeouts.outputSettle,
|
|
41748
41956
|
this.submitPendingUntil > Date.now() ? this.submitPendingUntil - Date.now() + this.timeouts.outputSettle : 0
|
|
41749
41957
|
);
|
|
@@ -41751,7 +41959,7 @@ ${cont}` : cont;
|
|
|
41751
41959
|
this.settleTimer = null;
|
|
41752
41960
|
if (epoch !== this.responseEpoch) return;
|
|
41753
41961
|
this.evaluateSettled(this.transport.getSnapshot());
|
|
41754
|
-
},
|
|
41962
|
+
}, delay2);
|
|
41755
41963
|
}
|
|
41756
41964
|
/** Called from sendMessage in transport once a turn scope is established. */
|
|
41757
41965
|
onTurnStarted(turnScope) {
|
|
@@ -45262,6 +45470,7 @@ ${lastSnapshot}`;
|
|
|
45262
45470
|
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS: () => DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
45263
45471
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS2,
|
|
45264
45472
|
DEFAULT_MESH_POLICY: () => DEFAULT_MESH_POLICY,
|
|
45473
|
+
DEFAULT_MESH_SCHEDULING_STRATEGY: () => DEFAULT_MESH_SCHEDULING_STRATEGY,
|
|
45265
45474
|
DEFAULT_SESSION_HOST_APP_NAME: () => DEFAULT_SESSION_HOST_APP_NAME,
|
|
45266
45475
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS2,
|
|
45267
45476
|
DEFAULT_SESSION_HOST_READY_TIMEOUT_MS: () => DEFAULT_SESSION_HOST_READY_TIMEOUT_MS2,
|
|
@@ -45287,9 +45496,12 @@ ${lastSnapshot}`;
|
|
|
45287
45496
|
InMemoryGitSnapshotStore: () => InMemoryGitSnapshotStore,
|
|
45288
45497
|
LOG: () => LOG2,
|
|
45289
45498
|
MAX_LEDGER_SLICE_LIMIT: () => MAX_LEDGER_SLICE_LIMIT,
|
|
45499
|
+
MESH_CONVERGE_FAST_FORWARD_TAG: () => MESH_CONVERGE_FAST_FORWARD_TAG,
|
|
45500
|
+
MESH_CONVERGE_REFINE_TAG: () => MESH_CONVERGE_REFINE_TAG,
|
|
45290
45501
|
MESH_MISSION_STATUSES: () => MESH_MISSION_STATUSES,
|
|
45291
45502
|
MESH_REFINE_CONFIG_LOCATIONS: () => MESH_REFINE_CONFIG_LOCATIONS,
|
|
45292
45503
|
MESH_REFINE_CONFIG_SCHEMA: () => MESH_REFINE_CONFIG_SCHEMA,
|
|
45504
|
+
MESH_SCHEDULING_STRATEGIES: () => MESH_SCHEDULING_STRATEGIES,
|
|
45293
45505
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS: () => MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS,
|
|
45294
45506
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA: () => MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA,
|
|
45295
45507
|
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS: () => MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
@@ -45490,6 +45702,7 @@ ${lastSnapshot}`;
|
|
|
45490
45702
|
normalizeManagedStatus: () => normalizeManagedStatus,
|
|
45491
45703
|
normalizeMeshCapabilityTags: () => normalizeMeshCapabilityTags,
|
|
45492
45704
|
normalizeMeshDaemonRole: () => normalizeMeshDaemonRole,
|
|
45705
|
+
normalizeMeshSchedulingStrategy: () => normalizeMeshSchedulingStrategy,
|
|
45493
45706
|
normalizeMeshTaskMode: () => normalizeMeshTaskMode,
|
|
45494
45707
|
normalizeMeshWorkerResult: () => normalizeMeshWorkerResult,
|
|
45495
45708
|
normalizeMessageParts: () => normalizeMessageParts,
|
|
@@ -45527,7 +45740,9 @@ ${lastSnapshot}`;
|
|
|
45527
45740
|
resetConfig: () => resetConfig,
|
|
45528
45741
|
resetDebugRuntimeConfig: () => resetDebugRuntimeConfig,
|
|
45529
45742
|
resetState: () => resetState,
|
|
45743
|
+
resolveAutoConvergeCodeChange: () => resolveAutoConvergeCodeChange,
|
|
45530
45744
|
resolveChatMessageKind: () => resolveChatMessageKind,
|
|
45745
|
+
resolveConvergeRequiredTags: () => resolveConvergeRequiredTags,
|
|
45531
45746
|
resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
|
|
45532
45747
|
resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
|
|
45533
45748
|
resolveDelegatedWorkerAutoApprove: () => resolveDelegatedWorkerAutoApprove,
|
|
@@ -45535,6 +45750,7 @@ ${lastSnapshot}`;
|
|
|
45535
45750
|
resolveGitRepository: () => resolveGitRepository,
|
|
45536
45751
|
resolveMeshHostStatus: () => resolveMeshHostStatus,
|
|
45537
45752
|
resolveMeshRefineValidationPlan: () => resolveMeshRefineValidationPlan,
|
|
45753
|
+
resolveNodeSchedulingPriority: () => resolveNodeSchedulingPriority,
|
|
45538
45754
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
45539
45755
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution2,
|
|
45540
45756
|
resolveWorktreePath: () => resolveWorktreePath,
|
|
@@ -47863,9 +48079,9 @@ ${lastSnapshot}`;
|
|
|
47863
48079
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
47864
48080
|
}
|
|
47865
48081
|
function summarizeMessage(message) {
|
|
47866
|
-
const
|
|
47867
|
-
const title =
|
|
47868
|
-
return { title: title || "(untitled task)", summary:
|
|
48082
|
+
const oneLine2 = message.replace(/\s+/g, " ").trim();
|
|
48083
|
+
const title = oneLine2.length > 96 ? `${oneLine2.slice(0, 93)}...` : oneLine2;
|
|
48084
|
+
return { title: title || "(untitled task)", summary: oneLine2 };
|
|
47869
48085
|
}
|
|
47870
48086
|
function elapsedSince(value, now) {
|
|
47871
48087
|
const started = value ? new Date(value).getTime() : Number.NaN;
|
|
@@ -50937,6 +51153,11 @@ ${cleanBody}`;
|
|
|
50937
51153
|
continue;
|
|
50938
51154
|
}
|
|
50939
51155
|
if (message.role === "assistant") {
|
|
51156
|
+
const isActivity = message.kind === "tool" || message.kind === "terminal" || message.kind === "thought";
|
|
51157
|
+
if (isActivity) {
|
|
51158
|
+
collapsed.push(message);
|
|
51159
|
+
continue;
|
|
51160
|
+
}
|
|
50940
51161
|
if (sawAssistantSinceLastUser) continue;
|
|
50941
51162
|
sawAssistantSinceLastUser = true;
|
|
50942
51163
|
collapsed.push(message);
|
|
@@ -56028,7 +56249,8 @@ ${effect.notification.body || ""}`.trim();
|
|
|
56028
56249
|
const sessionIdHint = typeof args?.targetSessionId === "string" ? args.targetSessionId : typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
56029
56250
|
const providerHint = typeof args?.cliType === "string" ? args.cliType : typeof args?.providerType === "string" ? args.providerType : typeof args?.agentType === "string" ? args.agentType : "";
|
|
56030
56251
|
const filteredMessages = h ? maybeHideCoordinatorPromptMessage(h, providerHint, sessionIdHint, messages) : messages;
|
|
56031
|
-
const
|
|
56252
|
+
const includeActivity = args?.includeActivity === true || args?.includeActivity === "true";
|
|
56253
|
+
const visibleMessages = includeActivity ? filteredMessages.filter((m) => isUserFacingChatMessage(m) || isActivityChatMessage(m)) : filterUserFacingChatMessages(filteredMessages);
|
|
56032
56254
|
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
56033
56255
|
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
56034
56256
|
const preservedPayloadFields = Object.fromEntries(Object.entries(payload).filter(([key]) => shouldPreserveReadChatPayloadField(key)));
|
|
@@ -58387,6 +58609,9 @@ ${effect.notification.body || ""}`.trim();
|
|
|
58387
58609
|
}
|
|
58388
58610
|
function buildControlScriptResult(scriptName, payload) {
|
|
58389
58611
|
if (!payload || typeof payload !== "object") return {};
|
|
58612
|
+
if (payload.controlResult && typeof payload.controlResult === "object") {
|
|
58613
|
+
return { controlResult: payload.controlResult };
|
|
58614
|
+
}
|
|
58390
58615
|
const legacyListPayload = (() => {
|
|
58391
58616
|
if (Array.isArray(payload.options)) return payload;
|
|
58392
58617
|
if (/^listmodels$/i.test(scriptName) && Array.isArray(payload.models)) {
|
|
@@ -59245,7 +59470,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
59245
59470
|
return { success: false, error: "invalid type" };
|
|
59246
59471
|
}
|
|
59247
59472
|
const https = require("https");
|
|
59248
|
-
const
|
|
59473
|
+
const fs31 = require("fs");
|
|
59249
59474
|
const path41 = require("path");
|
|
59250
59475
|
const crypto6 = require("crypto");
|
|
59251
59476
|
const REGISTRY = "https://api.adhf.dev/api/v1/registry";
|
|
@@ -59289,7 +59514,7 @@ ${effect.notification.body || ""}`.trim();
|
|
|
59289
59514
|
if (!targetDir.startsWith(installRootResolved + path41.sep)) {
|
|
59290
59515
|
return { success: false, error: "install path escaped upstream root" };
|
|
59291
59516
|
}
|
|
59292
|
-
|
|
59517
|
+
fs31.mkdirSync(targetDir, { recursive: true });
|
|
59293
59518
|
let manifestProbe = {};
|
|
59294
59519
|
try {
|
|
59295
59520
|
manifestProbe = JSON.parse(manifestBody);
|
|
@@ -59314,7 +59539,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59314
59539
|
}
|
|
59315
59540
|
const targetFile = isV1 ? "provider.v1.json" : "provider.json";
|
|
59316
59541
|
const targetPath = path41.join(targetDir, targetFile);
|
|
59317
|
-
|
|
59542
|
+
fs31.writeFileSync(targetPath, manifestBody, "utf-8");
|
|
59318
59543
|
const manifestJson = JSON.parse(manifestBody);
|
|
59319
59544
|
const scriptFetch = await this.fetchProviderSources(
|
|
59320
59545
|
manifestJson,
|
|
@@ -59384,7 +59609,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59384
59609
|
const repo = source.repo;
|
|
59385
59610
|
const ref = source.ref;
|
|
59386
59611
|
const https = require("https");
|
|
59387
|
-
const
|
|
59612
|
+
const fs31 = require("fs");
|
|
59388
59613
|
const path41 = require("path");
|
|
59389
59614
|
function fetchJson(url2, timeoutMs) {
|
|
59390
59615
|
return new Promise((resolve24, reject) => {
|
|
@@ -59468,8 +59693,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59468
59693
|
const relInside = entry.path.startsWith(sharedDirRel + "/") ? entry.path.slice(sharedDirRel.length + 1) : entry.path;
|
|
59469
59694
|
const outPath = path41.resolve(path41.join(sharedTargetDir, relInside));
|
|
59470
59695
|
if (!outPath.startsWith(path41.resolve(sharedTargetDir) + path41.sep)) continue;
|
|
59471
|
-
|
|
59472
|
-
|
|
59696
|
+
fs31.mkdirSync(path41.dirname(outPath), { recursive: true });
|
|
59697
|
+
fs31.writeFileSync(outPath, body);
|
|
59473
59698
|
fetchedCount++;
|
|
59474
59699
|
} catch (e) {
|
|
59475
59700
|
errors.push(`fetch shared ${entry.path}: ${e?.message ?? e}`);
|
|
@@ -59507,8 +59732,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59507
59732
|
errors.push(`refusing to write outside targetDir: ${entry.path}`);
|
|
59508
59733
|
continue;
|
|
59509
59734
|
}
|
|
59510
|
-
|
|
59511
|
-
|
|
59735
|
+
fs31.mkdirSync(path41.dirname(outPath), { recursive: true });
|
|
59736
|
+
fs31.writeFileSync(outPath, body);
|
|
59512
59737
|
fetchedCount++;
|
|
59513
59738
|
} catch (e) {
|
|
59514
59739
|
errors.push(`fetch ${entry.path}: ${e?.message ?? e}`);
|
|
@@ -59536,7 +59761,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59536
59761
|
if (!["cli", "ide", "extension", "acp"].includes(category)) {
|
|
59537
59762
|
return { success: false, error: `unknown category: ${category}` };
|
|
59538
59763
|
}
|
|
59539
|
-
const
|
|
59764
|
+
const fs31 = require("fs");
|
|
59540
59765
|
const path41 = require("path");
|
|
59541
59766
|
try {
|
|
59542
59767
|
const installRoot = this.getUpstreamInstallRoot();
|
|
@@ -59545,10 +59770,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59545
59770
|
if (!targetDir.startsWith(installRootResolved + path41.sep)) {
|
|
59546
59771
|
return { success: false, error: "refusing to delete outside upstream root" };
|
|
59547
59772
|
}
|
|
59548
|
-
if (!
|
|
59773
|
+
if (!fs31.existsSync(targetDir)) {
|
|
59549
59774
|
return { success: false, error: "not installed" };
|
|
59550
59775
|
}
|
|
59551
|
-
|
|
59776
|
+
fs31.rmSync(targetDir, { recursive: true, force: true });
|
|
59552
59777
|
if (this._ctx.providerLoader) {
|
|
59553
59778
|
this._ctx.providerLoader.reload();
|
|
59554
59779
|
this._ctx.providerLoader.registerToDetector();
|
|
@@ -59564,28 +59789,28 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59564
59789
|
* the UI and by the update checker.
|
|
59565
59790
|
*/
|
|
59566
59791
|
handleListInstalledProviders(_args) {
|
|
59567
|
-
const
|
|
59792
|
+
const fs31 = require("fs");
|
|
59568
59793
|
const path41 = require("path");
|
|
59569
59794
|
const installRoot = this.getUpstreamInstallRoot();
|
|
59570
|
-
if (!
|
|
59795
|
+
if (!fs31.existsSync(installRoot)) return { success: true, providers: [] };
|
|
59571
59796
|
const CATEGORIES = ["cli", "ide", "extension", "acp"];
|
|
59572
59797
|
const items = [];
|
|
59573
59798
|
for (const category of CATEGORIES) {
|
|
59574
59799
|
const categoryDir = path41.join(installRoot, category);
|
|
59575
|
-
if (!
|
|
59800
|
+
if (!fs31.existsSync(categoryDir)) continue;
|
|
59576
59801
|
let entries;
|
|
59577
59802
|
try {
|
|
59578
|
-
entries =
|
|
59803
|
+
entries = fs31.readdirSync(categoryDir);
|
|
59579
59804
|
} catch {
|
|
59580
59805
|
continue;
|
|
59581
59806
|
}
|
|
59582
59807
|
for (const type of entries) {
|
|
59583
59808
|
const v1Path = path41.join(categoryDir, type, "provider.v1.json");
|
|
59584
59809
|
const v0Path = path41.join(categoryDir, type, "provider.json");
|
|
59585
|
-
const manifestPath =
|
|
59810
|
+
const manifestPath = fs31.existsSync(v1Path) ? v1Path : fs31.existsSync(v0Path) ? v0Path : null;
|
|
59586
59811
|
if (!manifestPath) continue;
|
|
59587
59812
|
try {
|
|
59588
|
-
const m = JSON.parse(
|
|
59813
|
+
const m = JSON.parse(fs31.readFileSync(manifestPath, "utf-8"));
|
|
59589
59814
|
items.push({
|
|
59590
59815
|
type,
|
|
59591
59816
|
category,
|
|
@@ -59696,7 +59921,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59696
59921
|
if (!/^@[a-z0-9_-]+$/i.test(requestedName)) {
|
|
59697
59922
|
return { success: false, error: "name must match @[a-z0-9_-]+" };
|
|
59698
59923
|
}
|
|
59699
|
-
const
|
|
59924
|
+
const fs31 = require("fs");
|
|
59700
59925
|
const path41 = require("path");
|
|
59701
59926
|
const { spawnSync: spawnSync2 } = require("child_process");
|
|
59702
59927
|
const file2 = ext.loadExternalSources();
|
|
@@ -59707,8 +59932,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59707
59932
|
return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
|
|
59708
59933
|
}
|
|
59709
59934
|
const sourceDir = path41.join(ext.externalRoot(), requestedName);
|
|
59710
|
-
if (!
|
|
59711
|
-
if (
|
|
59935
|
+
if (!fs31.existsSync(ext.externalRoot())) fs31.mkdirSync(ext.externalRoot(), { recursive: true });
|
|
59936
|
+
if (fs31.existsSync(sourceDir)) {
|
|
59712
59937
|
return { success: false, error: `directory already exists: ${sourceDir} (rename or remove first)` };
|
|
59713
59938
|
}
|
|
59714
59939
|
const clone2 = spawnSync2("git", ["clone", "--depth=1", "--branch", ref, "--", url2, sourceDir], {
|
|
@@ -59718,7 +59943,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59718
59943
|
});
|
|
59719
59944
|
if (clone2.status !== 0) {
|
|
59720
59945
|
try {
|
|
59721
|
-
|
|
59946
|
+
fs31.rmSync(sourceDir, { recursive: true, force: true });
|
|
59722
59947
|
} catch {
|
|
59723
59948
|
}
|
|
59724
59949
|
return { success: false, error: `git clone failed: ${(clone2.stderr || clone2.stdout || "").trim() || "unknown error"}` };
|
|
@@ -59762,15 +59987,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
59762
59987
|
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
59763
59988
|
if (!name) return { success: false, error: "name is required" };
|
|
59764
59989
|
const ext = (init_external_sources(), __toCommonJS2(external_sources_exports));
|
|
59765
|
-
const
|
|
59990
|
+
const fs31 = require("fs");
|
|
59766
59991
|
const path41 = require("path");
|
|
59767
59992
|
const file2 = ext.loadExternalSources();
|
|
59768
59993
|
const match = file2.sources.find((s) => s.name === name);
|
|
59769
59994
|
if (!match) return { success: false, error: `source "${name}" not registered` };
|
|
59770
59995
|
const sourceDir = path41.join(ext.externalRoot(), name);
|
|
59771
|
-
if (
|
|
59996
|
+
if (fs31.existsSync(sourceDir)) {
|
|
59772
59997
|
try {
|
|
59773
|
-
|
|
59998
|
+
fs31.rmSync(sourceDir, { recursive: true, force: true });
|
|
59774
59999
|
} catch (e) {
|
|
59775
60000
|
return { success: false, error: `failed to delete ${sourceDir}: ${e?.message || e}` };
|
|
59776
60001
|
}
|
|
@@ -60217,12 +60442,12 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
60217
60442
|
scheduleSpawnPrime() {
|
|
60218
60443
|
const seqs = this.spec.send_on_spawn;
|
|
60219
60444
|
if (!Array.isArray(seqs) || seqs.length === 0) return;
|
|
60220
|
-
const
|
|
60445
|
+
const delay2 = Math.max(0, this.spec.send_on_spawn_delay_ms ?? 250);
|
|
60221
60446
|
setTimeout(() => {
|
|
60222
60447
|
for (const seq of seqs) {
|
|
60223
60448
|
if (typeof seq === "string" && seq.length > 0) this.adapter.send_keys(seq);
|
|
60224
60449
|
}
|
|
60225
|
-
},
|
|
60450
|
+
}, delay2);
|
|
60226
60451
|
}
|
|
60227
60452
|
dispatch(cmd) {
|
|
60228
60453
|
switch (cmd.kind) {
|
|
@@ -60588,11 +60813,11 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
60588
60813
|
const armed = this.delegateTimers.has(d.id);
|
|
60589
60814
|
const shouldFire = d.when_state === currentStateId;
|
|
60590
60815
|
if (shouldFire && !armed) {
|
|
60591
|
-
const
|
|
60816
|
+
const delay2 = d.after_duration_ms ?? 0;
|
|
60592
60817
|
const t = setTimeout(() => {
|
|
60593
60818
|
this.fireDelegate(d);
|
|
60594
60819
|
this.delegateTimers.delete(d.id);
|
|
60595
|
-
},
|
|
60820
|
+
}, delay2);
|
|
60596
60821
|
this.delegateTimers.set(d.id, t);
|
|
60597
60822
|
} else if (!shouldFire && armed) {
|
|
60598
60823
|
clearTimeout(this.delegateTimers.get(d.id));
|
|
@@ -60646,7 +60871,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
60646
60871
|
this.adapter.send_keys(a.keys);
|
|
60647
60872
|
return;
|
|
60648
60873
|
case "open_picker":
|
|
60649
|
-
|
|
60874
|
+
{
|
|
60875
|
+
const m = /^([\s\S]*?)([\r\n]+)$/.exec(a.trigger_keys);
|
|
60876
|
+
if (m && m[1]) {
|
|
60877
|
+
this.adapter.send_keys(m[1]);
|
|
60878
|
+
setTimeout(() => this.adapter.send_keys(m[2]), 200);
|
|
60879
|
+
} else {
|
|
60880
|
+
this.adapter.send_keys(a.trigger_keys);
|
|
60881
|
+
}
|
|
60882
|
+
}
|
|
60650
60883
|
this.pickerInProgress = { control_id: ctl.id, spec: ctl };
|
|
60651
60884
|
return;
|
|
60652
60885
|
case "attach_image": {
|
|
@@ -60829,8 +61062,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
60829
61062
|
for (let i = 0; i < lines.length; i += 1) {
|
|
60830
61063
|
const rec = lines[i];
|
|
60831
61064
|
if (filter && !filter(rec)) continue;
|
|
60832
|
-
const msg
|
|
60833
|
-
if (msg) {
|
|
61065
|
+
for (const msg of projectMessages(rec, src.message_map, i, lines.length, mtime)) {
|
|
60834
61066
|
if (transcriptWorkspace) msg.workspace = transcriptWorkspace;
|
|
60835
61067
|
messages.push(msg);
|
|
60836
61068
|
}
|
|
@@ -60910,8 +61142,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
60910
61142
|
const mtime = safeMtimeMs(resolved);
|
|
60911
61143
|
const messages = [];
|
|
60912
61144
|
for (let i = 0; i < messageRows.length; i += 1) {
|
|
60913
|
-
const msg
|
|
60914
|
-
|
|
61145
|
+
for (const msg of projectMessages(messageRows[i], src.message_map, i, messageRows.length, mtime)) {
|
|
61146
|
+
messages.push(msg);
|
|
61147
|
+
}
|
|
60915
61148
|
}
|
|
60916
61149
|
if (messages.length === 0) return null;
|
|
60917
61150
|
return {
|
|
@@ -61309,11 +61542,42 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
61309
61542
|
}
|
|
61310
61543
|
return cur;
|
|
61311
61544
|
}
|
|
61312
|
-
function
|
|
61545
|
+
function projectMessages(record2, map2, index, total, sourceMtimeMs) {
|
|
61313
61546
|
const roleRaw = jsonPathGet(record2, map2.role);
|
|
61314
|
-
const contentRaw = jsonPathGet(record2, map2.content);
|
|
61315
61547
|
const role = normalizeRole(roleRaw);
|
|
61316
|
-
let
|
|
61548
|
+
let receivedAt = sourceMtimeMs - (total - 1 - index) * 1e3;
|
|
61549
|
+
if (map2.timestamp_ms) {
|
|
61550
|
+
const tsRaw = jsonPathGet(record2, map2.timestamp_ms);
|
|
61551
|
+
const parsed = parseTimestamp(tsRaw);
|
|
61552
|
+
if (parsed != null) receivedAt = parsed;
|
|
61553
|
+
}
|
|
61554
|
+
const kindRaw = map2.kind ? jsonPathGet(record2, map2.kind) : void 0;
|
|
61555
|
+
const kind = typeof kindRaw === "string" && kindRaw ? kindRaw : "standard";
|
|
61556
|
+
const out = [];
|
|
61557
|
+
if (map2.tools) {
|
|
61558
|
+
const recordTool = projectToolBlock(record2, role, map2.tools);
|
|
61559
|
+
if (recordTool) {
|
|
61560
|
+
out.push({ ...recordTool, receivedAt });
|
|
61561
|
+
return out;
|
|
61562
|
+
}
|
|
61563
|
+
}
|
|
61564
|
+
const contentRaw = jsonPathGet(record2, map2.content);
|
|
61565
|
+
const content = cleanContent(stringifyContent(contentRaw), map2);
|
|
61566
|
+
if (content) out.push({ role, content, receivedAt, kind });
|
|
61567
|
+
if (map2.tools && Array.isArray(contentRaw)) {
|
|
61568
|
+
let nudge = 1;
|
|
61569
|
+
for (const block2 of contentRaw) {
|
|
61570
|
+
const tool = projectToolBlock(block2, role, map2.tools);
|
|
61571
|
+
if (tool) {
|
|
61572
|
+
out.push({ ...tool, receivedAt: receivedAt + nudge });
|
|
61573
|
+
nudge += 1;
|
|
61574
|
+
}
|
|
61575
|
+
}
|
|
61576
|
+
}
|
|
61577
|
+
return out;
|
|
61578
|
+
}
|
|
61579
|
+
function cleanContent(input, map2) {
|
|
61580
|
+
let content = input;
|
|
61317
61581
|
if (content && map2.content_strip) {
|
|
61318
61582
|
for (const tag of map2.content_strip) {
|
|
61319
61583
|
const safeTag = tag.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
@@ -61329,17 +61593,33 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
61329
61593
|
content = content.replace(open, "").replace(close, "");
|
|
61330
61594
|
}
|
|
61331
61595
|
}
|
|
61332
|
-
|
|
61333
|
-
|
|
61334
|
-
|
|
61335
|
-
|
|
61336
|
-
|
|
61337
|
-
|
|
61338
|
-
|
|
61596
|
+
return content ? content.trim() : "";
|
|
61597
|
+
}
|
|
61598
|
+
var DEFAULT_TOOL_CALL_TYPES = ["tool_use", "function_call", "custom_tool_call"];
|
|
61599
|
+
var DEFAULT_TOOL_RESULT_TYPES = ["tool_result", "function_call_output", "custom_tool_call_output"];
|
|
61600
|
+
function projectToolBlock(block2, role, tmap) {
|
|
61601
|
+
void role;
|
|
61602
|
+
if (block2 == null || typeof block2 !== "object") return null;
|
|
61603
|
+
const typeVal = String(jsonPathGet(block2, tmap.block_type || "$.type") ?? "");
|
|
61604
|
+
if (!typeVal) return null;
|
|
61605
|
+
const callTypes = tmap.call_types ?? DEFAULT_TOOL_CALL_TYPES;
|
|
61606
|
+
const resultTypes = tmap.result_types ?? DEFAULT_TOOL_RESULT_TYPES;
|
|
61607
|
+
if (callTypes.includes(typeVal)) {
|
|
61608
|
+
const name = String(jsonPathGet(block2, tmap.call_name || "$.name") ?? "tool").trim() || "tool";
|
|
61609
|
+
const args = oneLine(stringifyContent(jsonPathGet(block2, tmap.call_args || "$.input")), 240);
|
|
61610
|
+
const content = args ? `\u2197 ${name}: ${args}` : `\u2197 ${name}`;
|
|
61611
|
+
return { role: "assistant", content, receivedAt: 0, kind: "tool" };
|
|
61612
|
+
}
|
|
61613
|
+
if (resultTypes.includes(typeVal)) {
|
|
61614
|
+
const result = oneLine(stringifyContent(jsonPathGet(block2, tmap.result_content || "$.content")), 600);
|
|
61615
|
+
if (!result) return null;
|
|
61616
|
+
return { role: "assistant", content: `\u2198 ${result}`, receivedAt: 0, kind: "tool" };
|
|
61339
61617
|
}
|
|
61340
|
-
|
|
61341
|
-
|
|
61342
|
-
|
|
61618
|
+
return null;
|
|
61619
|
+
}
|
|
61620
|
+
function oneLine(s, max) {
|
|
61621
|
+
const flat = s.replace(/\s+/g, " ").trim();
|
|
61622
|
+
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
61343
61623
|
}
|
|
61344
61624
|
function parseTimestamp(v) {
|
|
61345
61625
|
if (v == null) return null;
|
|
@@ -61478,6 +61758,9 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
61478
61758
|
function stripAnsi3(text) {
|
|
61479
61759
|
return String(text || "").replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
61480
61760
|
}
|
|
61761
|
+
function delay(ms) {
|
|
61762
|
+
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
61763
|
+
}
|
|
61481
61764
|
var SpecCliAdapter = class _SpecCliAdapter {
|
|
61482
61765
|
cliType;
|
|
61483
61766
|
cliName;
|
|
@@ -61699,9 +61982,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
61699
61982
|
* drives the dispatch:
|
|
61700
61983
|
*
|
|
61701
61984
|
* send_keys → click_control (e.g. stop)
|
|
61702
|
-
* open_picker →
|
|
61703
|
-
*
|
|
61704
|
-
*
|
|
61985
|
+
* open_picker → two roles, driven by the screen, not a hardcoded list:
|
|
61986
|
+
* - LIST (no choice arg): open the picker, wait for it
|
|
61987
|
+
* to render, parse the on-screen options via
|
|
61988
|
+
* `extract_choices`, and return them as
|
|
61989
|
+
* `controlResult.options` (+ `currentValue`). This is
|
|
61990
|
+
* how the dashboard's Model/Mode controls learn what is
|
|
61991
|
+
* actually selectable in this CLI right now.
|
|
61992
|
+
* - SELECT (args.choiceIndex / args.choiceLabel): drive
|
|
61993
|
+
* the picker to that option using `submit_key`.
|
|
61705
61994
|
* attach_image → attach_image dispatch; expects args.blob (data url
|
|
61706
61995
|
* or base64) and args.mime
|
|
61707
61996
|
*
|
|
@@ -61726,11 +62015,128 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
61726
62015
|
this.driver.dispatch({ kind: "attach_image", blob, mime });
|
|
61727
62016
|
return Promise.resolve({ ok: true, effects: [{ type: "attached_image", controlId: ctl.id }] });
|
|
61728
62017
|
}
|
|
62018
|
+
if (action.type === "open_picker") {
|
|
62019
|
+
const choiceIndex = typeof flat.choiceIndex === "number" ? flat.choiceIndex : typeof flat.choiceIndex === "string" && flat.choiceIndex.trim() ? Number(flat.choiceIndex) : void 0;
|
|
62020
|
+
const choiceLabel = typeof flat.choiceLabel === "string" ? flat.choiceLabel : typeof flat.choice === "string" ? flat.choice : void 0;
|
|
62021
|
+
if (typeof choiceIndex === "number" && Number.isFinite(choiceIndex) || choiceLabel && choiceLabel.trim()) {
|
|
62022
|
+
return this.selectPickerChoice(ctl, action, choiceIndex, choiceLabel);
|
|
62023
|
+
}
|
|
62024
|
+
return this.openPickerAndListChoices(ctl, action);
|
|
62025
|
+
}
|
|
61729
62026
|
this.driver.dispatch({ kind: "click_control", control_id: ctl.id, payload: flat });
|
|
61730
|
-
|
|
61731
|
-
|
|
61732
|
-
|
|
61733
|
-
|
|
62027
|
+
return Promise.resolve({ ok: true, effects: [{ type: "sent_keys", controlId: ctl.id }] });
|
|
62028
|
+
}
|
|
62029
|
+
/**
|
|
62030
|
+
* Open an `open_picker` control and return the options the CLI is showing,
|
|
62031
|
+
* parsed live from the screen via `extract_choices`. Nothing is selected —
|
|
62032
|
+
* the picker is left open so a follow-up SELECT invoke can commit a choice.
|
|
62033
|
+
*/
|
|
62034
|
+
async openPickerAndListChoices(ctl, action) {
|
|
62035
|
+
this.driver.dispatch({ kind: "click_control", control_id: ctl.id });
|
|
62036
|
+
const ready = await this.waitForPickerRendered(action);
|
|
62037
|
+
const options = this.extractPickerChoices(action);
|
|
62038
|
+
const currentValue = options.find((o) => o.current)?.label;
|
|
62039
|
+
return {
|
|
62040
|
+
ok: true,
|
|
62041
|
+
effects: [{ type: "opened_picker", controlId: ctl.id }],
|
|
62042
|
+
controlResult: {
|
|
62043
|
+
options: options.map((o) => ({ value: o.label, label: o.label, current: o.current })),
|
|
62044
|
+
...currentValue ? { currentValue } : {},
|
|
62045
|
+
source: "screen-parse",
|
|
62046
|
+
...ready ? {} : { warning: "picker_render_timeout" }
|
|
62047
|
+
}
|
|
62048
|
+
};
|
|
62049
|
+
}
|
|
62050
|
+
/**
|
|
62051
|
+
* Drive an already-listable picker to a specific option. The option can be
|
|
62052
|
+
* named (choiceLabel — matched against the parsed on-screen labels) or
|
|
62053
|
+
* positional (choiceIndex — the on-screen number). The actual keystrokes
|
|
62054
|
+
* come from the spec's `submit_key` with `{index}` substituted, so the spec
|
|
62055
|
+
* — not this code — decides how a selection is keyed for each CLI.
|
|
62056
|
+
*/
|
|
62057
|
+
async selectPickerChoice(ctl, action, choiceIndex, choiceLabel) {
|
|
62058
|
+
this.driver.dispatch({ kind: "click_control", control_id: ctl.id });
|
|
62059
|
+
await this.waitForPickerRendered(action);
|
|
62060
|
+
const options = this.extractPickerChoices(action);
|
|
62061
|
+
let index = choiceIndex;
|
|
62062
|
+
if ((index == null || !Number.isFinite(index)) && choiceLabel) {
|
|
62063
|
+
const needle = choiceLabel.trim().toLowerCase();
|
|
62064
|
+
const match = options.find((o) => o.label.toLowerCase().includes(needle));
|
|
62065
|
+
if (!match) {
|
|
62066
|
+
return { ok: false, error: `choice not found on screen: ${choiceLabel}`, controlResult: { options: options.map((o) => ({ value: o.label, label: o.label })) } };
|
|
62067
|
+
}
|
|
62068
|
+
index = match.index;
|
|
62069
|
+
}
|
|
62070
|
+
if (index == null || !Number.isFinite(index)) {
|
|
62071
|
+
return { ok: false, error: "choiceIndex or choiceLabel required to select" };
|
|
62072
|
+
}
|
|
62073
|
+
const keys = (action.submit_key || "{index}\r").replace(/\{index\}/g, String(index));
|
|
62074
|
+
this.driver.dispatch({ kind: "pty_write", data: keys });
|
|
62075
|
+
const selected = options.find((o) => o.index === index);
|
|
62076
|
+
return {
|
|
62077
|
+
ok: true,
|
|
62078
|
+
effects: [{ type: "selected_choice", controlId: ctl.id }],
|
|
62079
|
+
controlResult: {
|
|
62080
|
+
ok: true,
|
|
62081
|
+
...selected ? { currentValue: selected.label } : {},
|
|
62082
|
+
selectedIndex: index
|
|
62083
|
+
}
|
|
62084
|
+
};
|
|
62085
|
+
}
|
|
62086
|
+
/** Poll the live screen until the picker's `wait_for` condition matches,
|
|
62087
|
+
* up to a short budget. Returns true if it rendered, false on timeout. */
|
|
62088
|
+
async waitForPickerRendered(action) {
|
|
62089
|
+
const wf = action.wait_for;
|
|
62090
|
+
if (!wf?.regex) {
|
|
62091
|
+
await delay(250);
|
|
62092
|
+
return true;
|
|
62093
|
+
}
|
|
62094
|
+
const re = new RegExp(wf.regex, wf.flags ?? "i");
|
|
62095
|
+
const deadline = Date.now() + 2500;
|
|
62096
|
+
while (Date.now() < deadline) {
|
|
62097
|
+
await delay(120);
|
|
62098
|
+
const hay = this.readScreenSectionText(wf.section);
|
|
62099
|
+
if (re.test(hay)) return true;
|
|
62100
|
+
}
|
|
62101
|
+
return false;
|
|
62102
|
+
}
|
|
62103
|
+
/** Parse the picker's `extract_choices` pattern against the live screen.
|
|
62104
|
+
* Each match yields { index, label, current }. `current` is true for the
|
|
62105
|
+
* line the CLI marks with its cursor glyph (❯ ›). Purely screen-driven —
|
|
62106
|
+
* no model/mode names are baked in. */
|
|
62107
|
+
extractPickerChoices(action) {
|
|
62108
|
+
const ec = action.extract_choices;
|
|
62109
|
+
if (!ec?.pattern) return [];
|
|
62110
|
+
const text = this.readScreenSectionText(ec.section);
|
|
62111
|
+
const out = [];
|
|
62112
|
+
const seen = /* @__PURE__ */ new Set();
|
|
62113
|
+
for (const rawLine of text.split("\n")) {
|
|
62114
|
+
const line = rawLine.replace(/\r$/, "");
|
|
62115
|
+
const m = new RegExp(ec.pattern, ec.flags ?? "").exec(line);
|
|
62116
|
+
if (!m) continue;
|
|
62117
|
+
const idx = Number(m[1]);
|
|
62118
|
+
if (!Number.isFinite(idx) || seen.has(idx)) continue;
|
|
62119
|
+
const label = (m[2] ?? "").replace(/\s+/g, " ").trim();
|
|
62120
|
+
if (!label) continue;
|
|
62121
|
+
const current = /^\s*[❯›>]/.test(line) || /[✔✓●]\s*$/.test(label);
|
|
62122
|
+
seen.add(idx);
|
|
62123
|
+
out.push({ index: idx, label, current });
|
|
62124
|
+
}
|
|
62125
|
+
return out;
|
|
62126
|
+
}
|
|
62127
|
+
/** Live text of a named screen section (or the whole screen when no
|
|
62128
|
+
* section is named), resolved from the driver's current sections. */
|
|
62129
|
+
readScreenSectionText(sectionId) {
|
|
62130
|
+
try {
|
|
62131
|
+
const sections = this.driver.getSections();
|
|
62132
|
+
if (sectionId && sections) {
|
|
62133
|
+
const hit = sections.find((s) => s.id === sectionId);
|
|
62134
|
+
if (hit) return hit.text;
|
|
62135
|
+
}
|
|
62136
|
+
return this.driver.getScreen();
|
|
62137
|
+
} catch {
|
|
62138
|
+
return "";
|
|
62139
|
+
}
|
|
61734
62140
|
}
|
|
61735
62141
|
getDebugSnapshot() {
|
|
61736
62142
|
let screen = "";
|
|
@@ -68643,7 +69049,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
68643
69049
|
}
|
|
68644
69050
|
if (providerDir) {
|
|
68645
69051
|
try {
|
|
68646
|
-
const
|
|
69052
|
+
const fs31 = require("fs");
|
|
68647
69053
|
const path41 = require("path");
|
|
68648
69054
|
const candidates = [];
|
|
68649
69055
|
if (Array.isArray(base.compatibility)) {
|
|
@@ -68655,13 +69061,13 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
68655
69061
|
}
|
|
68656
69062
|
candidates.push(path41.join(providerDir, "specs", "default.json"));
|
|
68657
69063
|
candidates.push(path41.join(providerDir, "spec.json"));
|
|
68658
|
-
const specPath = candidates.find((p) =>
|
|
69064
|
+
const specPath = candidates.find((p) => fs31.existsSync(p));
|
|
68659
69065
|
if (specPath) {
|
|
68660
69066
|
resolved._resolvedSpecPath = specPath;
|
|
68661
69067
|
let specControls;
|
|
68662
69068
|
let nh;
|
|
68663
69069
|
try {
|
|
68664
|
-
const rawSpec = JSON.parse(
|
|
69070
|
+
const rawSpec = JSON.parse(fs31.readFileSync(specPath, "utf8"));
|
|
68665
69071
|
specControls = rawSpec.control_bar;
|
|
68666
69072
|
nh = rawSpec.native_history;
|
|
68667
69073
|
} catch {
|
|
@@ -68686,7 +69092,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
68686
69092
|
reader = (input) => executeNativeHistory(nh, input);
|
|
68687
69093
|
} else if (nh.override_path) {
|
|
68688
69094
|
const overrideFile = path41.resolve(providerDir, nh.override_path);
|
|
68689
|
-
if (
|
|
69095
|
+
if (fs31.existsSync(overrideFile)) {
|
|
68690
69096
|
try {
|
|
68691
69097
|
registerProviderScriptRootSafely(path41.dirname(path41.dirname(providerDir)));
|
|
68692
69098
|
delete require.cache[require.resolve(overrideFile)];
|
|
@@ -69867,7 +70273,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
69867
70273
|
}
|
|
69868
70274
|
} else if (plat === "win32") {
|
|
69869
70275
|
try {
|
|
69870
|
-
const
|
|
70276
|
+
const fs31 = require("fs");
|
|
69871
70277
|
const appNameMap = getMacAppIdentifiers();
|
|
69872
70278
|
const appName = appNameMap[ideId];
|
|
69873
70279
|
if (appName) {
|
|
@@ -69876,8 +70282,8 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
69876
70282
|
appName,
|
|
69877
70283
|
"storage.json"
|
|
69878
70284
|
);
|
|
69879
|
-
if (
|
|
69880
|
-
const data = JSON.parse(
|
|
70285
|
+
if (fs31.existsSync(storagePath)) {
|
|
70286
|
+
const data = JSON.parse(fs31.readFileSync(storagePath, "utf-8"));
|
|
69881
70287
|
const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
|
|
69882
70288
|
if (workspaces.length > 0) {
|
|
69883
70289
|
const recent = workspaces[0];
|
|
@@ -70203,6 +70609,204 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
70203
70609
|
cleanOldFiles();
|
|
70204
70610
|
var yaml3 = __toESM2(require_js_yaml());
|
|
70205
70611
|
init_logger();
|
|
70612
|
+
var fs23 = __toESM2(require("fs"));
|
|
70613
|
+
init_logger();
|
|
70614
|
+
var DEFAULT_TAIL_BYTES = 64 * 1024;
|
|
70615
|
+
var MAX_TAIL_BYTES = 128 * 1024;
|
|
70616
|
+
var READ_CHUNK_BYTES = 64 * 1024;
|
|
70617
|
+
function resolveLogPath(date5) {
|
|
70618
|
+
if (date5 instanceof Date) return getCurrentDaemonLogPath(date5);
|
|
70619
|
+
if (typeof date5 === "string" && date5.trim()) {
|
|
70620
|
+
const parsed = /* @__PURE__ */ new Date(`${date5.trim()}T00:00:00.000Z`);
|
|
70621
|
+
if (!Number.isNaN(parsed.getTime())) return getCurrentDaemonLogPath(parsed);
|
|
70622
|
+
}
|
|
70623
|
+
return getCurrentDaemonLogPath();
|
|
70624
|
+
}
|
|
70625
|
+
function clampTailBytes(tailBytes) {
|
|
70626
|
+
if (!Number.isFinite(tailBytes) || tailBytes <= 0) return DEFAULT_TAIL_BYTES;
|
|
70627
|
+
return Math.min(Math.floor(tailBytes), MAX_TAIL_BYTES);
|
|
70628
|
+
}
|
|
70629
|
+
function readByteBoundedTail(filePath, limitBytes) {
|
|
70630
|
+
const fd = fs23.openSync(filePath, "r");
|
|
70631
|
+
try {
|
|
70632
|
+
const stat2 = fs23.fstatSync(fd);
|
|
70633
|
+
const size = stat2.size;
|
|
70634
|
+
if (size === 0) return { text: "", truncated: false, bytesReturned: 0 };
|
|
70635
|
+
const want = Math.min(limitBytes, size);
|
|
70636
|
+
let start = size - want;
|
|
70637
|
+
const truncated = start > 0;
|
|
70638
|
+
const buffers = [];
|
|
70639
|
+
let position = start;
|
|
70640
|
+
while (position < size) {
|
|
70641
|
+
const chunkSize = Math.min(READ_CHUNK_BYTES, size - position);
|
|
70642
|
+
const chunk = Buffer.alloc(chunkSize);
|
|
70643
|
+
fs23.readSync(fd, chunk, 0, chunkSize, position);
|
|
70644
|
+
buffers.push(chunk);
|
|
70645
|
+
position += chunkSize;
|
|
70646
|
+
}
|
|
70647
|
+
let buf = Buffer.concat(buffers);
|
|
70648
|
+
if (truncated) {
|
|
70649
|
+
const firstNewline = buf.indexOf(10);
|
|
70650
|
+
if (firstNewline >= 0) {
|
|
70651
|
+
buf = buf.subarray(firstNewline + 1);
|
|
70652
|
+
}
|
|
70653
|
+
}
|
|
70654
|
+
return { text: buf.toString("utf-8"), truncated, bytesReturned: buf.length };
|
|
70655
|
+
} finally {
|
|
70656
|
+
fs23.closeSync(fd);
|
|
70657
|
+
}
|
|
70658
|
+
}
|
|
70659
|
+
function parseLineEpochMs(line, fileDate) {
|
|
70660
|
+
const m = line.match(/^\[(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?\]/);
|
|
70661
|
+
if (!m) {
|
|
70662
|
+
const iso = line.match(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?/);
|
|
70663
|
+
if (iso) {
|
|
70664
|
+
const t = Date.parse(iso[0].replace(" ", "T"));
|
|
70665
|
+
return Number.isNaN(t) ? null : t;
|
|
70666
|
+
}
|
|
70667
|
+
return null;
|
|
70668
|
+
}
|
|
70669
|
+
const d = new Date(fileDate);
|
|
70670
|
+
d.setHours(Number(m[1]), Number(m[2]), Number(m[3]), m[4] ? Number(m[4].padEnd(3, "0")) : 0);
|
|
70671
|
+
return d.getTime();
|
|
70672
|
+
}
|
|
70673
|
+
function readDaemonLogTail(args = {}) {
|
|
70674
|
+
const platform10 = process.platform;
|
|
70675
|
+
const limitBytes = clampTailBytes(args.tailBytes);
|
|
70676
|
+
let logPath = resolveLogPath(args.date);
|
|
70677
|
+
if (!fs23.existsSync(logPath)) {
|
|
70678
|
+
const backup = logPath.replace(/\.log$/, ".1.log");
|
|
70679
|
+
if (fs23.existsSync(backup)) {
|
|
70680
|
+
logPath = backup;
|
|
70681
|
+
} else {
|
|
70682
|
+
return {
|
|
70683
|
+
success: false,
|
|
70684
|
+
error: `No daemon log file at ${logPath} (dir: ${getDaemonLogDir()})`,
|
|
70685
|
+
lines: [],
|
|
70686
|
+
truncated: false,
|
|
70687
|
+
logPath,
|
|
70688
|
+
platform: platform10,
|
|
70689
|
+
bytesReturned: 0,
|
|
70690
|
+
filtered: false
|
|
70691
|
+
};
|
|
70692
|
+
}
|
|
70693
|
+
}
|
|
70694
|
+
let raw;
|
|
70695
|
+
try {
|
|
70696
|
+
raw = readByteBoundedTail(logPath, limitBytes);
|
|
70697
|
+
} catch (e) {
|
|
70698
|
+
return {
|
|
70699
|
+
success: false,
|
|
70700
|
+
error: `Failed to read ${logPath}: ${e?.message ?? String(e)}`,
|
|
70701
|
+
lines: [],
|
|
70702
|
+
truncated: false,
|
|
70703
|
+
logPath,
|
|
70704
|
+
platform: platform10,
|
|
70705
|
+
bytesReturned: 0,
|
|
70706
|
+
filtered: false
|
|
70707
|
+
};
|
|
70708
|
+
}
|
|
70709
|
+
let lines = raw.text.split("\n");
|
|
70710
|
+
if (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
70711
|
+
const rawCount = lines.length;
|
|
70712
|
+
if (Number.isFinite(args.sinceMs)) {
|
|
70713
|
+
const fileDate = args.date instanceof Date ? args.date : typeof args.date === "string" && args.date.trim() ? /* @__PURE__ */ new Date(`${args.date.trim()}T00:00:00.000Z`) : /* @__PURE__ */ new Date();
|
|
70714
|
+
const floor = args.sinceMs;
|
|
70715
|
+
lines = lines.filter((line) => {
|
|
70716
|
+
const ts2 = parseLineEpochMs(line, fileDate);
|
|
70717
|
+
return ts2 === null || ts2 >= floor;
|
|
70718
|
+
});
|
|
70719
|
+
}
|
|
70720
|
+
let appliedGrep;
|
|
70721
|
+
if (typeof args.grep === "string" && args.grep.trim()) {
|
|
70722
|
+
appliedGrep = args.grep.trim();
|
|
70723
|
+
let re = null;
|
|
70724
|
+
try {
|
|
70725
|
+
re = new RegExp(appliedGrep, "i");
|
|
70726
|
+
} catch {
|
|
70727
|
+
re = null;
|
|
70728
|
+
}
|
|
70729
|
+
if (re) {
|
|
70730
|
+
const compiled = re;
|
|
70731
|
+
lines = lines.filter((line) => compiled.test(line));
|
|
70732
|
+
} else {
|
|
70733
|
+
const needle = appliedGrep.toLowerCase();
|
|
70734
|
+
lines = lines.filter((line) => line.toLowerCase().includes(needle));
|
|
70735
|
+
}
|
|
70736
|
+
}
|
|
70737
|
+
return {
|
|
70738
|
+
success: true,
|
|
70739
|
+
lines,
|
|
70740
|
+
truncated: raw.truncated,
|
|
70741
|
+
logPath,
|
|
70742
|
+
platform: platform10,
|
|
70743
|
+
bytesReturned: raw.bytesReturned,
|
|
70744
|
+
filtered: lines.length !== rawCount,
|
|
70745
|
+
...appliedGrep ? { grep: appliedGrep } : {}
|
|
70746
|
+
};
|
|
70747
|
+
}
|
|
70748
|
+
var MASK = "\u2022\u2022\u2022\u2022redacted";
|
|
70749
|
+
function maskKeepTail(token) {
|
|
70750
|
+
if (token.length <= 8) return MASK;
|
|
70751
|
+
return `${MASK}${token.slice(-4)}`;
|
|
70752
|
+
}
|
|
70753
|
+
var RULES = [
|
|
70754
|
+
// `JWT_SECRET=...`, `TOKEN=...`, `API_KEY=...`, `password: ...` env/config dumps.
|
|
70755
|
+
// Captures the key + delimiter and masks only the value.
|
|
70756
|
+
{
|
|
70757
|
+
name: "key_value_secret",
|
|
70758
|
+
pattern: /\b([A-Z0-9_]*(?:SECRET|TOKEN|API[_-]?KEY|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL|CLIENT[_-]?SECRET)[A-Z0-9_]*)(\s*[:=]\s*)(["']?)([^\s"',;]+)\3/gi,
|
|
70759
|
+
replace: (_m, key, delim, quote) => `${key}${delim}${quote}${MASK}${quote}`
|
|
70760
|
+
},
|
|
70761
|
+
// Authorization: Bearer <token>
|
|
70762
|
+
{
|
|
70763
|
+
name: "bearer_token",
|
|
70764
|
+
pattern: /\b(Bearer\s+)([A-Za-z0-9._\-+/=]{8,})/g,
|
|
70765
|
+
replace: (_m, prefix, token) => `${prefix}${maskKeepTail(token)}`
|
|
70766
|
+
},
|
|
70767
|
+
// ADHDev credential prefixes: API key (adk_), machine secret (adm_), provider key (adp_).
|
|
70768
|
+
{
|
|
70769
|
+
name: "adhdev_prefixed_secret",
|
|
70770
|
+
pattern: /\b(ad[kmp]_)([A-Za-z0-9]{6,})/g,
|
|
70771
|
+
replace: (_m, prefix, token) => `${prefix}${maskKeepTail(prefix + token)}`
|
|
70772
|
+
},
|
|
70773
|
+
// JWT: three base64url segments separated by dots, header starts with eyJ.
|
|
70774
|
+
{
|
|
70775
|
+
name: "jwt",
|
|
70776
|
+
pattern: /\beyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}/g,
|
|
70777
|
+
replace: () => MASK
|
|
70778
|
+
},
|
|
70779
|
+
// TURN credential: a long credential value following a `credential` key in
|
|
70780
|
+
// any common shape — `credential: x`, `credential=x`, or `credential "x"`.
|
|
70781
|
+
// Mask the credential value only, preserving the key + delimiter/quote.
|
|
70782
|
+
{
|
|
70783
|
+
name: "turn_credential",
|
|
70784
|
+
pattern: /\b(credential["']?\s*(?:[:=]\s*)?["']?)([^\s"',;]{6,})/gi,
|
|
70785
|
+
replace: (_m, prefix) => `${prefix}${MASK}`
|
|
70786
|
+
},
|
|
70787
|
+
// TURN REST username:credential of the form `<expiry-ts>:<base64hmac>`,
|
|
70788
|
+
// where the hmac part is long base64. Mask the hmac.
|
|
70789
|
+
{
|
|
70790
|
+
name: "turn_rest_pair",
|
|
70791
|
+
pattern: /\b(\d{10,}:)([A-Za-z0-9+/]{20,}={0,2})\b/g,
|
|
70792
|
+
replace: (_m, prefix) => `${prefix}${MASK}`
|
|
70793
|
+
}
|
|
70794
|
+
];
|
|
70795
|
+
function redactLogLine(line) {
|
|
70796
|
+
if (!line) return line;
|
|
70797
|
+
let out = line;
|
|
70798
|
+
for (const rule of RULES) {
|
|
70799
|
+
try {
|
|
70800
|
+
out = out.replace(rule.pattern, rule.replace);
|
|
70801
|
+
} catch {
|
|
70802
|
+
}
|
|
70803
|
+
}
|
|
70804
|
+
return out;
|
|
70805
|
+
}
|
|
70806
|
+
function redactLogLines(lines) {
|
|
70807
|
+
return lines.map((line) => redactLogLine(line));
|
|
70808
|
+
}
|
|
70809
|
+
var LOG_REDACTION_RULE_NAMES = RULES.map((r) => r.name);
|
|
70206
70810
|
init_mesh_coordinator();
|
|
70207
70811
|
init_mesh_events();
|
|
70208
70812
|
init_mesh_routing();
|
|
@@ -70833,21 +71437,21 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
70833
71437
|
init_build_info();
|
|
70834
71438
|
var import_child_process8 = require("child_process");
|
|
70835
71439
|
var import_child_process9 = require("child_process");
|
|
70836
|
-
var
|
|
71440
|
+
var fs24 = __toESM2(require("fs"));
|
|
70837
71441
|
var os27 = __toESM2(require("os"));
|
|
70838
71442
|
var path35 = __toESM2(require("path"));
|
|
70839
71443
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
70840
71444
|
function getUpgradeLogPath() {
|
|
70841
71445
|
const home = os27.homedir();
|
|
70842
71446
|
const dir = path35.join(home, ".adhdev");
|
|
70843
|
-
|
|
71447
|
+
fs24.mkdirSync(dir, { recursive: true });
|
|
70844
71448
|
return path35.join(dir, "daemon-upgrade.log");
|
|
70845
71449
|
}
|
|
70846
71450
|
function appendUpgradeLog(message) {
|
|
70847
71451
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
70848
71452
|
`;
|
|
70849
71453
|
try {
|
|
70850
|
-
|
|
71454
|
+
fs24.appendFileSync(getUpgradeLogPath(), line, "utf8");
|
|
70851
71455
|
} catch {
|
|
70852
71456
|
}
|
|
70853
71457
|
}
|
|
@@ -70855,12 +71459,12 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
70855
71459
|
const binDir = path35.dirname(nodeExecutable);
|
|
70856
71460
|
if (platform10 === "win32") {
|
|
70857
71461
|
const npmCliPath = path35.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
70858
|
-
if (
|
|
71462
|
+
if (fs24.existsSync(npmCliPath)) {
|
|
70859
71463
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
70860
71464
|
}
|
|
70861
71465
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
70862
71466
|
const candidatePath = path35.join(binDir, candidate);
|
|
70863
|
-
if (
|
|
71467
|
+
if (fs24.existsSync(candidatePath)) {
|
|
70864
71468
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
70865
71469
|
}
|
|
70866
71470
|
}
|
|
@@ -70868,7 +71472,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
70868
71472
|
}
|
|
70869
71473
|
for (const candidate of ["npm"]) {
|
|
70870
71474
|
const candidatePath = path35.join(binDir, candidate);
|
|
70871
|
-
if (
|
|
71475
|
+
if (fs24.existsSync(candidatePath)) {
|
|
70872
71476
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
70873
71477
|
}
|
|
70874
71478
|
}
|
|
@@ -70878,12 +71482,12 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
70878
71482
|
if (!currentCliPath) return null;
|
|
70879
71483
|
let resolvedPath = currentCliPath;
|
|
70880
71484
|
try {
|
|
70881
|
-
resolvedPath =
|
|
71485
|
+
resolvedPath = fs24.realpathSync.native(currentCliPath);
|
|
70882
71486
|
} catch {
|
|
70883
71487
|
}
|
|
70884
71488
|
let currentDir = resolvedPath;
|
|
70885
71489
|
try {
|
|
70886
|
-
if (
|
|
71490
|
+
if (fs24.statSync(resolvedPath).isFile()) {
|
|
70887
71491
|
currentDir = path35.dirname(resolvedPath);
|
|
70888
71492
|
}
|
|
70889
71493
|
} catch {
|
|
@@ -70892,8 +71496,8 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
70892
71496
|
while (true) {
|
|
70893
71497
|
const packageJsonPath = path35.join(currentDir, "package.json");
|
|
70894
71498
|
try {
|
|
70895
|
-
if (
|
|
70896
|
-
const parsed = JSON.parse(
|
|
71499
|
+
if (fs24.existsSync(packageJsonPath)) {
|
|
71500
|
+
const parsed = JSON.parse(fs24.readFileSync(packageJsonPath, "utf8"));
|
|
70897
71501
|
if (parsed?.name === packageName) {
|
|
70898
71502
|
const normalized = currentDir.replace(/\\/g, "/");
|
|
70899
71503
|
return normalized.includes("/node_modules/") ? currentDir : null;
|
|
@@ -71042,8 +71646,8 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71042
71646
|
function stopSessionHostProcesses(appName) {
|
|
71043
71647
|
const pidFile = path35.join(os27.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
71044
71648
|
try {
|
|
71045
|
-
if (
|
|
71046
|
-
const pid = Number.parseInt(
|
|
71649
|
+
if (fs24.existsSync(pidFile)) {
|
|
71650
|
+
const pid = Number.parseInt(fs24.readFileSync(pidFile, "utf8").trim(), 10);
|
|
71047
71651
|
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
|
|
71048
71652
|
killPid2(pid);
|
|
71049
71653
|
}
|
|
@@ -71051,7 +71655,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71051
71655
|
} catch {
|
|
71052
71656
|
} finally {
|
|
71053
71657
|
try {
|
|
71054
|
-
|
|
71658
|
+
fs24.unlinkSync(pidFile);
|
|
71055
71659
|
} catch {
|
|
71056
71660
|
}
|
|
71057
71661
|
}
|
|
@@ -71059,7 +71663,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71059
71663
|
function removeDaemonPidFile() {
|
|
71060
71664
|
const pidFile = path35.join(os27.homedir(), ".adhdev", "daemon.pid");
|
|
71061
71665
|
try {
|
|
71062
|
-
|
|
71666
|
+
fs24.unlinkSync(pidFile);
|
|
71063
71667
|
} catch {
|
|
71064
71668
|
}
|
|
71065
71669
|
}
|
|
@@ -71077,23 +71681,23 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71077
71681
|
if (pkgName.startsWith("@")) {
|
|
71078
71682
|
const [scope, name] = pkgName.split("/");
|
|
71079
71683
|
const scopeDir = path35.join(npmRoot, scope);
|
|
71080
|
-
if (!
|
|
71081
|
-
for (const entry of
|
|
71684
|
+
if (!fs24.existsSync(scopeDir)) return;
|
|
71685
|
+
for (const entry of fs24.readdirSync(scopeDir)) {
|
|
71082
71686
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
71083
|
-
|
|
71687
|
+
fs24.rmSync(path35.join(scopeDir, entry), { recursive: true, force: true });
|
|
71084
71688
|
appendUpgradeLog(`Removed stale scoped staging dir: ${path35.join(scopeDir, entry)}`);
|
|
71085
71689
|
}
|
|
71086
71690
|
} else {
|
|
71087
|
-
for (const entry of
|
|
71691
|
+
for (const entry of fs24.readdirSync(npmRoot)) {
|
|
71088
71692
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
71089
|
-
|
|
71693
|
+
fs24.rmSync(path35.join(npmRoot, entry), { recursive: true, force: true });
|
|
71090
71694
|
appendUpgradeLog(`Removed stale staging dir: ${path35.join(npmRoot, entry)}`);
|
|
71091
71695
|
}
|
|
71092
71696
|
}
|
|
71093
|
-
if (
|
|
71094
|
-
for (const entry of
|
|
71697
|
+
if (fs24.existsSync(binDir)) {
|
|
71698
|
+
for (const entry of fs24.readdirSync(binDir)) {
|
|
71095
71699
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
71096
|
-
|
|
71700
|
+
fs24.rmSync(path35.join(binDir, entry), { recursive: true, force: true });
|
|
71097
71701
|
appendUpgradeLog(`Removed stale bin staging entry: ${path35.join(binDir, entry)}`);
|
|
71098
71702
|
}
|
|
71099
71703
|
}
|
|
@@ -71182,7 +71786,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71182
71786
|
init_repo_mesh_types();
|
|
71183
71787
|
var import_os3 = require("os");
|
|
71184
71788
|
var import_path11 = require("path");
|
|
71185
|
-
var
|
|
71789
|
+
var fs25 = __toESM2(require("fs"));
|
|
71186
71790
|
var import_node_child_process6 = require("child_process");
|
|
71187
71791
|
var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
|
|
71188
71792
|
var CHANNEL_SERVER_URL = {
|
|
@@ -71508,6 +72112,12 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71508
72112
|
function readInlineMeshNodeId(node) {
|
|
71509
72113
|
return normalizeMeshNodeId(node) ?? "";
|
|
71510
72114
|
}
|
|
72115
|
+
function isDeadLocalWorktreeNode(node) {
|
|
72116
|
+
if (node?.isLocalWorktree !== true) return false;
|
|
72117
|
+
const workspace = readStringValue(node?.workspace);
|
|
72118
|
+
if (!workspace) return false;
|
|
72119
|
+
return !fs25.existsSync(workspace);
|
|
72120
|
+
}
|
|
71511
72121
|
function foldMeshNodeIdentityToCanonical(node) {
|
|
71512
72122
|
if (!node || typeof node !== "object" || Array.isArray(node)) return node;
|
|
71513
72123
|
const canonical = normalizeMeshNodeId(node);
|
|
@@ -71754,7 +72364,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71754
72364
|
const followUps = nodes.filter((node) => {
|
|
71755
72365
|
if (readObjectRecord(node.branchConvergence).needsConvergence !== true) return false;
|
|
71756
72366
|
const workspace = typeof node.workspace === "string" ? node.workspace : "";
|
|
71757
|
-
if (workspace && !
|
|
72367
|
+
if (workspace && !fs25.existsSync(workspace)) return false;
|
|
71758
72368
|
return true;
|
|
71759
72369
|
}).map((node) => {
|
|
71760
72370
|
const convergence = readObjectRecord(node.branchConvergence);
|
|
@@ -71882,6 +72492,43 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71882
72492
|
}
|
|
71883
72493
|
var MESH_DIRECT_PROBE_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_TIMEOUT_MS", 25e3);
|
|
71884
72494
|
var MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS", 25e3);
|
|
72495
|
+
var MESH_DIRECT_PROBE_REUSE_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_REUSE_MS", 12e3);
|
|
72496
|
+
var MeshGitProbeCache = class {
|
|
72497
|
+
constructor(reuseMs, now = Date.now) {
|
|
72498
|
+
this.reuseMs = reuseMs;
|
|
72499
|
+
this.now = now;
|
|
72500
|
+
}
|
|
72501
|
+
inflight = /* @__PURE__ */ new Map();
|
|
72502
|
+
recent = /* @__PURE__ */ new Map();
|
|
72503
|
+
key(daemonId, workspace) {
|
|
72504
|
+
return `${daemonId}::${workspace}`;
|
|
72505
|
+
}
|
|
72506
|
+
/**
|
|
72507
|
+
* Run `probe` for this peer, but reuse a fresh recent result or an in-flight
|
|
72508
|
+
* probe for the same key when one is available. `probe` is only invoked when
|
|
72509
|
+
* neither gate is satisfied.
|
|
72510
|
+
*/
|
|
72511
|
+
async probe(daemonId, workspace, probe) {
|
|
72512
|
+
const key = this.key(daemonId, workspace);
|
|
72513
|
+
const cached22 = this.recent.get(key);
|
|
72514
|
+
if (cached22 && this.now() - cached22.at < this.reuseMs) {
|
|
72515
|
+
return cached22.value;
|
|
72516
|
+
}
|
|
72517
|
+
const existing = this.inflight.get(key);
|
|
72518
|
+
if (existing) return existing;
|
|
72519
|
+
const pending = (async () => {
|
|
72520
|
+
const result = await probe();
|
|
72521
|
+
if (result) this.recent.set(key, { at: this.now(), value: result });
|
|
72522
|
+
return result;
|
|
72523
|
+
})();
|
|
72524
|
+
this.inflight.set(key, pending);
|
|
72525
|
+
try {
|
|
72526
|
+
return await pending;
|
|
72527
|
+
} finally {
|
|
72528
|
+
if (this.inflight.get(key) === pending) this.inflight.delete(key);
|
|
72529
|
+
}
|
|
72530
|
+
}
|
|
72531
|
+
};
|
|
71885
72532
|
async function probeRemoteMeshGitStatus(args) {
|
|
71886
72533
|
if (!args.dispatchMeshCommand) return null;
|
|
71887
72534
|
const remoteResult = await Promise.race([
|
|
@@ -71925,7 +72572,8 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71925
72572
|
peerAttemptedCount: 0,
|
|
71926
72573
|
peerConfirmedCount: 0,
|
|
71927
72574
|
standingEvidenceCount: 0,
|
|
71928
|
-
unavailableNodeIds: []
|
|
72575
|
+
unavailableNodeIds: [],
|
|
72576
|
+
deadNodeIds: []
|
|
71929
72577
|
};
|
|
71930
72578
|
}
|
|
71931
72579
|
const selectedCoordinatorNodeId = readStringValue(
|
|
@@ -71938,6 +72586,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71938
72586
|
let peerConfirmedCount = 0;
|
|
71939
72587
|
let standingEvidenceCount = 0;
|
|
71940
72588
|
const unavailableNodeIds = [];
|
|
72589
|
+
const deadNodeIds = [];
|
|
71941
72590
|
for (const [nodeIndex, node] of nodes.entries()) {
|
|
71942
72591
|
const nodeId = normalizeMeshNodeId(node) || `node_${nodeIndex}`;
|
|
71943
72592
|
const workspace = readStringValue(node?.workspace);
|
|
@@ -71947,11 +72596,18 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71947
72596
|
) || Boolean(
|
|
71948
72597
|
daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
|
|
71949
72598
|
) || Boolean(args.meshSource !== "local_config" && nodeIndex === 0);
|
|
72599
|
+
const isSelfDaemonNode = Boolean(
|
|
72600
|
+
daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
|
|
72601
|
+
);
|
|
72602
|
+
if ((isSelfNode || isSelfDaemonNode) && isDeadLocalWorktreeNode(node)) {
|
|
72603
|
+
deadNodeIds.push(nodeId);
|
|
72604
|
+
continue;
|
|
72605
|
+
}
|
|
71950
72606
|
if (!workspace) {
|
|
71951
72607
|
if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
|
|
71952
72608
|
continue;
|
|
71953
72609
|
}
|
|
71954
|
-
if (
|
|
72610
|
+
if (fs25.existsSync(workspace)) {
|
|
71955
72611
|
try {
|
|
71956
72612
|
const localGit = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
71957
72613
|
if (localGit?.isGitRepo) {
|
|
@@ -71975,7 +72631,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71975
72631
|
continue;
|
|
71976
72632
|
}
|
|
71977
72633
|
peerAttemptedCount += 1;
|
|
71978
|
-
const
|
|
72634
|
+
const runProbe = () => probeRemoteMeshGitStatusWithRetry({
|
|
71979
72635
|
dispatchMeshCommand: args.dispatchMeshCommand,
|
|
71980
72636
|
daemonId,
|
|
71981
72637
|
workspace,
|
|
@@ -71983,6 +72639,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71983
72639
|
retryTimeoutMs: MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS,
|
|
71984
72640
|
getConnection: args.getMeshPeerConnectionStatus
|
|
71985
72641
|
});
|
|
72642
|
+
const remoteGit = args.probeCache ? await args.probeCache.probe(daemonId, workspace, runProbe) : await runProbe();
|
|
71986
72643
|
if (remoteGit) {
|
|
71987
72644
|
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
71988
72645
|
peerConfirmedCount += 1;
|
|
@@ -71996,7 +72653,8 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
71996
72653
|
peerAttemptedCount,
|
|
71997
72654
|
peerConfirmedCount,
|
|
71998
72655
|
standingEvidenceCount,
|
|
71999
|
-
unavailableNodeIds
|
|
72656
|
+
unavailableNodeIds,
|
|
72657
|
+
deadNodeIds
|
|
72000
72658
|
};
|
|
72001
72659
|
}
|
|
72002
72660
|
function summarizeMeshSessionRecord(record2) {
|
|
@@ -72055,7 +72713,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
72055
72713
|
}
|
|
72056
72714
|
function collectLiveMeshSessionRecords(args) {
|
|
72057
72715
|
const nodeWorkspace = readStringValue(args.node?.workspace);
|
|
72058
|
-
const nodeIsMissingLocalWorktree = args.node?.isLocalWorktree === true && !!nodeWorkspace && !
|
|
72716
|
+
const nodeIsMissingLocalWorktree = args.node?.isLocalWorktree === true && !!nodeWorkspace && !fs25.existsSync(nodeWorkspace);
|
|
72059
72717
|
const matches = args.liveSessionRecords.filter((record2) => {
|
|
72060
72718
|
const recordNodeId = readStringValue(record2?.meta?.meshNodeId);
|
|
72061
72719
|
if (recordNodeId && recordNodeId !== args.nodeId) return false;
|
|
@@ -72082,7 +72740,7 @@ ${formatManifestValidationIssues2(validation2.issues)}`);
|
|
|
72082
72740
|
const workspace = readStringValue(node?.workspace);
|
|
72083
72741
|
if (nodeId) liveNodeIds.add(nodeId);
|
|
72084
72742
|
if (workspace) liveWorkspaces.add(workspace);
|
|
72085
|
-
if (nodeId && node?.isLocalWorktree === true && workspace && !
|
|
72743
|
+
if (nodeId && node?.isLocalWorktree === true && workspace && !fs25.existsSync(workspace)) {
|
|
72086
72744
|
missingLocalWorktreeNodeIds.add(nodeId);
|
|
72087
72745
|
}
|
|
72088
72746
|
}
|
|
@@ -72442,7 +73100,7 @@ ${e?.stderr || ""}`
|
|
|
72442
73100
|
if (!baseCommit || !branchCommit) return false;
|
|
72443
73101
|
if (baseCommit === branchCommit) return true;
|
|
72444
73102
|
try {
|
|
72445
|
-
if (!
|
|
73103
|
+
if (!fs25.existsSync(submoduleRepoPath)) return false;
|
|
72446
73104
|
(0, import_node_child_process6.execFileSync)("git", ["cat-file", "-e", `${baseCommit}^{commit}`], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
72447
73105
|
(0, import_node_child_process6.execFileSync)("git", ["cat-file", "-e", `${branchCommit}^{commit}`], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
72448
73106
|
(0, import_node_child_process6.execFileSync)("git", ["merge-base", "--is-ancestor", baseCommit, branchCommit], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
@@ -72559,7 +73217,7 @@ ${e?.stderr || ""}`
|
|
|
72559
73217
|
return newTree || void 0;
|
|
72560
73218
|
} finally {
|
|
72561
73219
|
try {
|
|
72562
|
-
|
|
73220
|
+
fs25.rmSync(tmpIndex, { force: true });
|
|
72563
73221
|
} catch {
|
|
72564
73222
|
}
|
|
72565
73223
|
}
|
|
@@ -72634,7 +73292,7 @@ ${e?.stderr || ""}`
|
|
|
72634
73292
|
return newTree || void 0;
|
|
72635
73293
|
} finally {
|
|
72636
73294
|
try {
|
|
72637
|
-
|
|
73295
|
+
fs25.rmSync(tmpIndex, { force: true });
|
|
72638
73296
|
} catch {
|
|
72639
73297
|
}
|
|
72640
73298
|
}
|
|
@@ -72740,7 +73398,7 @@ ${e?.stderr || ""}`
|
|
|
72740
73398
|
return { stdout: String(stdout || ""), stderr: String(stderr || ""), refspec };
|
|
72741
73399
|
};
|
|
72742
73400
|
const importCommitFromWorktreeSubmodule = async (submodulePath, worktreeSubmodulePath, commit) => {
|
|
72743
|
-
if (!
|
|
73401
|
+
if (!fs25.existsSync(worktreeSubmodulePath)) return false;
|
|
72744
73402
|
try {
|
|
72745
73403
|
await runGit3(worktreeSubmodulePath, ["cat-file", "-e", `${commit}^{commit}`]);
|
|
72746
73404
|
} catch {
|
|
@@ -72763,7 +73421,7 @@ ${e?.stderr || ""}`
|
|
|
72763
73421
|
reachable: false
|
|
72764
73422
|
};
|
|
72765
73423
|
try {
|
|
72766
|
-
if (!
|
|
73424
|
+
if (!fs25.existsSync(submodulePath)) {
|
|
72767
73425
|
entry.error = `Submodule checkout missing at ${gitlink.path}`;
|
|
72768
73426
|
entry.publishRequired = true;
|
|
72769
73427
|
if (options.allowAutoPublishSubmoduleMainCommits === true) {
|
|
@@ -73000,9 +73658,9 @@ ${e?.stderr || ""}`
|
|
|
73000
73658
|
return ["npm", "pnpm", "yarn", "bun"].includes(command) && candidate.args.some((arg) => arg === "run" || arg === "test" || arg === "exec");
|
|
73001
73659
|
};
|
|
73002
73660
|
const dependenciesLikelyMissing = (cwd) => {
|
|
73003
|
-
if (!
|
|
73004
|
-
if (
|
|
73005
|
-
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) =>
|
|
73661
|
+
if (!fs25.existsSync((0, import_path11.join)(cwd, "package.json"))) return false;
|
|
73662
|
+
if (fs25.existsSync((0, import_path11.join)(cwd, "node_modules"))) return false;
|
|
73663
|
+
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs25.existsSync((0, import_path11.join)(cwd, lock)));
|
|
73006
73664
|
};
|
|
73007
73665
|
if (runLegacyBootstrapCommands) {
|
|
73008
73666
|
summary.bootstrap = { stage: "legacy" };
|
|
@@ -73104,9 +73762,9 @@ ${e?.stderr || ""}`
|
|
|
73104
73762
|
function loadHermesCoordinatorBaseConfig(targetConfigPath) {
|
|
73105
73763
|
const sourceHome = resolveHermesUserHome();
|
|
73106
73764
|
const sourceConfigPath = (0, import_path11.join)(sourceHome, "config.yaml");
|
|
73107
|
-
if (!
|
|
73765
|
+
if (!fs25.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
73108
73766
|
if ((0, import_path11.resolve)(sourceConfigPath) === (0, import_path11.resolve)(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
73109
|
-
const parsed = parseMeshCoordinatorMcpConfig(
|
|
73767
|
+
const parsed = parseMeshCoordinatorMcpConfig(fs25.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
|
|
73110
73768
|
const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
|
|
73111
73769
|
return { config: baseConfig, sourceHome, sourceConfigPath };
|
|
73112
73770
|
}
|
|
@@ -73143,9 +73801,9 @@ ${e?.stderr || ""}`
|
|
|
73143
73801
|
for (const fileName of [".env", "auth.json"]) {
|
|
73144
73802
|
const sourcePath = (0, import_path11.join)(sourceHome, fileName);
|
|
73145
73803
|
const targetPath = (0, import_path11.join)(targetHome, fileName);
|
|
73146
|
-
if (!
|
|
73804
|
+
if (!fs25.existsSync(sourcePath)) continue;
|
|
73147
73805
|
try {
|
|
73148
|
-
|
|
73806
|
+
fs25.copyFileSync(sourcePath, targetPath);
|
|
73149
73807
|
} catch (error48) {
|
|
73150
73808
|
LOG2.warn("MeshCoordinator", `Could not copy Hermes ${fileName} into isolated coordinator home: ${error48?.message || error48}`);
|
|
73151
73809
|
}
|
|
@@ -73303,8 +73961,21 @@ ${e?.stderr || ""}`
|
|
|
73303
73961
|
* Allows the MCP server to query mesh data via get_mesh even when
|
|
73304
73962
|
* the mesh doesn't exist in the local meshes.json file. */
|
|
73305
73963
|
inlineMeshCache = /* @__PURE__ */ new Map();
|
|
73964
|
+
/** Tombstones for inline mesh nodes removed via remove_mesh_node, keyed by
|
|
73965
|
+
* meshId → set of removed nodeIds. The dashboard keeps echoing the removed
|
|
73966
|
+
* node in the inlineMesh it attaches to every command; without a tombstone,
|
|
73967
|
+
* reconcileInlineMeshCache MERGEs it straight back (resurrection). A
|
|
73968
|
+
* tombstoned node is skipped during reconcile only while its workspace is
|
|
73969
|
+
* absent from disk — a genuine re-registration (same nodeId, workspace back
|
|
73970
|
+
* on disk) clears the tombstone and merges normally, preserving clone
|
|
73971
|
+
* worktree visibility and legitimate node re-creation. */
|
|
73972
|
+
removedInlineMeshNodeIds = /* @__PURE__ */ new Map();
|
|
73306
73973
|
/** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
|
|
73307
73974
|
aggregateMeshStatusCache = /* @__PURE__ */ new Map();
|
|
73975
|
+
/** Shared per-peer git_status probe dedup + recently-probed reuse gate.
|
|
73976
|
+
* Spans separate mesh_status/get_mesh calls so the dashboard auto-retry
|
|
73977
|
+
* loop cannot storm a slow peer with back-to-back refreshUpstream probes. */
|
|
73978
|
+
meshGitProbeCache = new MeshGitProbeCache(MESH_DIRECT_PROBE_REUSE_MS);
|
|
73308
73979
|
/** In-memory async Refinery jobs keyed by meshId:nodeId to reject/return duplicate in-flight requests. */
|
|
73309
73980
|
runningRefineJobs = /* @__PURE__ */ new Map();
|
|
73310
73981
|
/** Terminal async Refinery jobs preserve a clear answer after the worktree node has been removed. */
|
|
@@ -73332,10 +74003,23 @@ ${e?.stderr || ""}`
|
|
|
73332
74003
|
const unavailableNodeIds = /* @__PURE__ */ new Set();
|
|
73333
74004
|
const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
|
|
73334
74005
|
const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
|
|
74006
|
+
const deadNodeIds = /* @__PURE__ */ new Set();
|
|
74007
|
+
for (const node of mesh.nodes) {
|
|
74008
|
+
if (!isDeadLocalWorktreeNode(node)) continue;
|
|
74009
|
+
const deadId = readInlineMeshNodeId(node);
|
|
74010
|
+
if (deadId) deadNodeIds.add(deadId);
|
|
74011
|
+
}
|
|
74012
|
+
let droppedDeadUnavailable = false;
|
|
73335
74013
|
for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
|
|
73336
74014
|
const nodeId = readStringValue(entry);
|
|
73337
|
-
if (nodeId)
|
|
74015
|
+
if (!nodeId) continue;
|
|
74016
|
+
if (deadNodeIds.has(nodeId)) {
|
|
74017
|
+
droppedDeadUnavailable = true;
|
|
74018
|
+
continue;
|
|
74019
|
+
}
|
|
74020
|
+
unavailableNodeIds.add(nodeId);
|
|
73338
74021
|
}
|
|
74022
|
+
if (droppedDeadUnavailable) changed = true;
|
|
73339
74023
|
const nodes = snapshot.nodes.map((statusNode) => {
|
|
73340
74024
|
const nodeId = normalizeMeshNodeId(statusNode);
|
|
73341
74025
|
const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
|
|
@@ -73450,7 +74134,10 @@ ${e?.stderr || ""}`
|
|
|
73450
74134
|
}
|
|
73451
74135
|
warmInlineMeshCache(meshId, inlineMesh) {
|
|
73452
74136
|
if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
|
|
73453
|
-
const sanitizedInlineMesh =
|
|
74137
|
+
const sanitizedInlineMesh = this.applyInlineMeshNodeTombstones(
|
|
74138
|
+
meshId,
|
|
74139
|
+
sanitizeInlineMesh(normalizeInlineMeshNodeIdentity(inlineMesh))
|
|
74140
|
+
);
|
|
73454
74141
|
const cached22 = this.inlineMeshCache.get(meshId);
|
|
73455
74142
|
if (cached22) {
|
|
73456
74143
|
const merged = reconcileInlineMeshCache(cached22, sanitizedInlineMesh);
|
|
@@ -73466,7 +74153,10 @@ ${e?.stderr || ""}`
|
|
|
73466
74153
|
const cached3 = this.getCachedInlineMesh(meshId);
|
|
73467
74154
|
if (cached3) {
|
|
73468
74155
|
if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
|
|
73469
|
-
const merged = reconcileInlineMeshCache(
|
|
74156
|
+
const merged = reconcileInlineMeshCache(
|
|
74157
|
+
cached3,
|
|
74158
|
+
this.applyInlineMeshNodeTombstones(meshId, inlineMesh)
|
|
74159
|
+
);
|
|
73470
74160
|
this.inlineMeshCache.set(meshId, sanitizeInlineMesh(normalizeInlineMeshNodeIdentity(merged)));
|
|
73471
74161
|
return { mesh: merged, inline: true, source: "inline_cache" };
|
|
73472
74162
|
}
|
|
@@ -73517,12 +74207,49 @@ ${e?.stderr || ""}`
|
|
|
73517
74207
|
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
73518
74208
|
const idx = mesh.nodes.findIndex((entry) => meshNodeIdMatches(entry, nodeId));
|
|
73519
74209
|
if (idx === -1) return false;
|
|
74210
|
+
const canonicalNodeId = readInlineMeshNodeId(mesh.nodes[idx]) || nodeId;
|
|
73520
74211
|
mesh.nodes.splice(idx, 1);
|
|
73521
74212
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
73522
74213
|
this.inlineMeshCache.set(meshId, mesh);
|
|
74214
|
+
this.tombstoneRemovedInlineMeshNode(meshId, canonicalNodeId);
|
|
74215
|
+
if (canonicalNodeId !== nodeId) this.tombstoneRemovedInlineMeshNode(meshId, nodeId);
|
|
73523
74216
|
this.invalidateAggregateMeshStatus(meshId);
|
|
73524
74217
|
return true;
|
|
73525
74218
|
}
|
|
74219
|
+
tombstoneRemovedInlineMeshNode(meshId, nodeId) {
|
|
74220
|
+
if (!nodeId) return;
|
|
74221
|
+
let set2 = this.removedInlineMeshNodeIds.get(meshId);
|
|
74222
|
+
if (!set2) {
|
|
74223
|
+
set2 = /* @__PURE__ */ new Set();
|
|
74224
|
+
this.removedInlineMeshNodeIds.set(meshId, set2);
|
|
74225
|
+
}
|
|
74226
|
+
set2.add(nodeId);
|
|
74227
|
+
}
|
|
74228
|
+
/** Filter an incoming inline mesh against this mesh's tombstones before it is
|
|
74229
|
+
* reconciled into the cache. A tombstoned node is dropped only while its
|
|
74230
|
+
* workspace is still absent from disk; if the workspace is back (genuine
|
|
74231
|
+
* re-registration), the tombstone is cleared and the node merges normally. */
|
|
74232
|
+
applyInlineMeshNodeTombstones(meshId, incoming) {
|
|
74233
|
+
const tombstones = this.removedInlineMeshNodeIds.get(meshId);
|
|
74234
|
+
if (!tombstones?.size || !incoming || typeof incoming !== "object" || !Array.isArray(incoming.nodes)) {
|
|
74235
|
+
return incoming;
|
|
74236
|
+
}
|
|
74237
|
+
let dropped = false;
|
|
74238
|
+
const nodes = incoming.nodes.filter((node) => {
|
|
74239
|
+
const nodeId = readInlineMeshNodeId(node);
|
|
74240
|
+
if (!nodeId || !tombstones.has(nodeId)) return true;
|
|
74241
|
+
const workspace = readStringValue(node?.workspace);
|
|
74242
|
+
if (workspace && fs25.existsSync(workspace)) {
|
|
74243
|
+
tombstones.delete(nodeId);
|
|
74244
|
+
return true;
|
|
74245
|
+
}
|
|
74246
|
+
dropped = true;
|
|
74247
|
+
return false;
|
|
74248
|
+
});
|
|
74249
|
+
if (tombstones.size === 0) this.removedInlineMeshNodeIds.delete(meshId);
|
|
74250
|
+
if (!dropped) return incoming;
|
|
74251
|
+
return { ...incoming, nodes };
|
|
74252
|
+
}
|
|
73526
74253
|
normalizeMeshSessionCleanupMode(value) {
|
|
73527
74254
|
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
73528
74255
|
}
|
|
@@ -73545,13 +74272,13 @@ ${e?.stderr || ""}`
|
|
|
73545
74272
|
recoveryHint: "Inspect the mesh node record before removing it, or remove stale metadata manually only after confirming no managed worktree remains."
|
|
73546
74273
|
};
|
|
73547
74274
|
}
|
|
73548
|
-
const worktreeExists =
|
|
74275
|
+
const worktreeExists = fs25.existsSync(workspace);
|
|
73549
74276
|
const sourceNode = args.node?.clonedFromNodeId ? args.mesh?.nodes?.find((n) => meshNodeIdMatches(n, args.node.clonedFromNodeId)) : args.mesh?.nodes?.find((n) => !n.isLocalWorktree);
|
|
73550
74277
|
const repoRoot = typeof sourceNode?.repoRoot === "string" && sourceNode.repoRoot.trim() ? sourceNode.repoRoot.trim() : typeof sourceNode?.workspace === "string" && sourceNode.workspace.trim() ? sourceNode.workspace.trim() : "";
|
|
73551
74278
|
if (!worktreeExists) {
|
|
73552
74279
|
return { success: true, skipped: true, removedPath: workspace, repoRoot: repoRoot || void 0, reason: "worktree_path_missing" };
|
|
73553
74280
|
}
|
|
73554
|
-
if (!repoRoot || !
|
|
74281
|
+
if (!repoRoot || !fs25.existsSync(repoRoot)) {
|
|
73555
74282
|
return {
|
|
73556
74283
|
success: false,
|
|
73557
74284
|
code: "mesh_worktree_cleanup_missing_source_repo",
|
|
@@ -73571,7 +74298,7 @@ ${e?.stderr || ""}`
|
|
|
73571
74298
|
const normalizePath = (value) => {
|
|
73572
74299
|
const resolved = (0, import_path11.resolve)(value);
|
|
73573
74300
|
try {
|
|
73574
|
-
return
|
|
74301
|
+
return fs25.realpathSync(resolved);
|
|
73575
74302
|
} catch {
|
|
73576
74303
|
return resolved;
|
|
73577
74304
|
}
|
|
@@ -73657,7 +74384,7 @@ ${e?.stderr || ""}`
|
|
|
73657
74384
|
};
|
|
73658
74385
|
} catch (deinitError) {
|
|
73659
74386
|
try {
|
|
73660
|
-
|
|
74387
|
+
fs25.rmSync(workspace, { recursive: true, force: true });
|
|
73661
74388
|
await execFileAsync4("git", ["worktree", "prune"], {
|
|
73662
74389
|
cwd: repoRoot,
|
|
73663
74390
|
encoding: "utf8",
|
|
@@ -75436,8 +76163,8 @@ ${hintLines.join("\n")}` : "",
|
|
|
75436
76163
|
if (sinceTs > 0) {
|
|
75437
76164
|
return { success: true, logs: [], totalBuffered: 0 };
|
|
75438
76165
|
}
|
|
75439
|
-
if (
|
|
75440
|
-
const content =
|
|
76166
|
+
if (fs25.existsSync(LOG_PATH)) {
|
|
76167
|
+
const content = fs25.readFileSync(LOG_PATH, "utf-8");
|
|
75441
76168
|
const allLines = content.split("\n");
|
|
75442
76169
|
const recent = allLines.slice(-count).join("\n");
|
|
75443
76170
|
return { success: true, logs: recent, totalLines: allLines.length };
|
|
@@ -75982,14 +76709,14 @@ ${hintLines.join("\n")}` : "",
|
|
|
75982
76709
|
// Settings page in the dashboard reads/writes via these two
|
|
75983
76710
|
// commands instead of going through fs from the browser.
|
|
75984
76711
|
case "list_coordinator_prompts": {
|
|
75985
|
-
const
|
|
76712
|
+
const fs31 = await import("fs");
|
|
75986
76713
|
const path41 = await import("path");
|
|
75987
76714
|
const os30 = await import("os");
|
|
75988
76715
|
const dir = path41.join(os30.homedir(), ".adhdev", "coordinator-prompts");
|
|
75989
76716
|
const entries = {};
|
|
75990
76717
|
try {
|
|
75991
|
-
if (
|
|
75992
|
-
for (const name of
|
|
76718
|
+
if (fs31.existsSync(dir)) {
|
|
76719
|
+
for (const name of fs31.readdirSync(dir)) {
|
|
75993
76720
|
const matchOverride = name.match(/^([a-zA-Z0-9_.-]+)\.md$/);
|
|
75994
76721
|
const matchAppend = name.match(/^([a-zA-Z0-9_.-]+)\.append\.md$/);
|
|
75995
76722
|
const m = matchAppend || matchOverride;
|
|
@@ -75999,7 +76726,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
75999
76726
|
const full = path41.join(dir, name);
|
|
76000
76727
|
let content = "";
|
|
76001
76728
|
try {
|
|
76002
|
-
content =
|
|
76729
|
+
content = fs31.readFileSync(full, "utf8");
|
|
76003
76730
|
} catch {
|
|
76004
76731
|
}
|
|
76005
76732
|
if (!entries[key]) entries[key] = { override: "", append: "" };
|
|
@@ -76013,7 +76740,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
76013
76740
|
return { success: true, dir, entries };
|
|
76014
76741
|
}
|
|
76015
76742
|
case "write_coordinator_prompt": {
|
|
76016
|
-
const
|
|
76743
|
+
const fs31 = await import("fs");
|
|
76017
76744
|
const path41 = await import("path");
|
|
76018
76745
|
const os30 = await import("os");
|
|
76019
76746
|
const key = typeof args?.key === "string" ? args.key.trim() : "";
|
|
@@ -76026,11 +76753,11 @@ ${hintLines.join("\n")}` : "",
|
|
|
76026
76753
|
const filename = kind === "append" ? `${key}.append.md` : `${key}.md`;
|
|
76027
76754
|
const full = path41.join(dir, filename);
|
|
76028
76755
|
try {
|
|
76029
|
-
|
|
76756
|
+
fs31.mkdirSync(dir, { recursive: true });
|
|
76030
76757
|
if (content.trim()) {
|
|
76031
|
-
|
|
76032
|
-
} else if (
|
|
76033
|
-
|
|
76758
|
+
fs31.writeFileSync(full, content, { encoding: "utf8", mode: 384 });
|
|
76759
|
+
} else if (fs31.existsSync(full)) {
|
|
76760
|
+
fs31.unlinkSync(full);
|
|
76034
76761
|
}
|
|
76035
76762
|
return { success: true, path: full, kind, key };
|
|
76036
76763
|
} catch (error48) {
|
|
@@ -76207,7 +76934,8 @@ ${hintLines.join("\n")}` : "",
|
|
|
76207
76934
|
getMeshPeerConnectionStatus: this.deps.getMeshPeerConnectionStatus,
|
|
76208
76935
|
statusInstanceId: this.deps.statusInstanceId,
|
|
76209
76936
|
localMachineId: loadConfig2().machineId || "",
|
|
76210
|
-
probeRemotePeers
|
|
76937
|
+
probeRemotePeers,
|
|
76938
|
+
probeCache: this.meshGitProbeCache
|
|
76211
76939
|
});
|
|
76212
76940
|
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
76213
76941
|
const sourceOfTruth = {
|
|
@@ -76807,10 +77535,75 @@ ${hintLines.join("\n")}` : "",
|
|
|
76807
77535
|
});
|
|
76808
77536
|
return result;
|
|
76809
77537
|
}
|
|
77538
|
+
case "get_mesh_node_logs": {
|
|
77539
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
77540
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
77541
|
+
let nodeDaemonId;
|
|
77542
|
+
if (meshId && nodeId) {
|
|
77543
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
77544
|
+
const node = meshRecord?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
77545
|
+
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
77546
|
+
}
|
|
77547
|
+
const selfDaemonId = this.deps.statusInstanceId;
|
|
77548
|
+
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
|
|
77549
|
+
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
77550
|
+
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
|
|
77551
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
77552
|
+
_meshDirectDispatch: true
|
|
77553
|
+
});
|
|
77554
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
77555
|
+
}
|
|
77556
|
+
const rawTailBytes = Number(args?.tailBytes);
|
|
77557
|
+
const tail = readDaemonLogTail({
|
|
77558
|
+
date: typeof args?.date === "string" ? args.date : void 0,
|
|
77559
|
+
tailBytes: Number.isFinite(rawTailBytes) ? Math.min(rawTailBytes, MAX_TAIL_BYTES) : void 0,
|
|
77560
|
+
grep: typeof args?.grep === "string" ? args.grep : void 0,
|
|
77561
|
+
sinceMs: Number.isFinite(Number(args?.sinceMs)) ? Number(args?.sinceMs) : void 0
|
|
77562
|
+
});
|
|
77563
|
+
if (!tail.success) {
|
|
77564
|
+
return {
|
|
77565
|
+
success: false,
|
|
77566
|
+
error: tail.error || "failed to read daemon log tail",
|
|
77567
|
+
nodeId,
|
|
77568
|
+
logPath: tail.logPath,
|
|
77569
|
+
platform: tail.platform
|
|
77570
|
+
};
|
|
77571
|
+
}
|
|
77572
|
+
const redactedLines = redactLogLines(tail.lines);
|
|
77573
|
+
return {
|
|
77574
|
+
success: true,
|
|
77575
|
+
nodeId,
|
|
77576
|
+
daemonId: selfDaemonId,
|
|
77577
|
+
logPath: tail.logPath,
|
|
77578
|
+
platform: tail.platform,
|
|
77579
|
+
lines: redactedLines,
|
|
77580
|
+
lineCount: redactedLines.length,
|
|
77581
|
+
truncated: tail.truncated,
|
|
77582
|
+
filtered: tail.filtered,
|
|
77583
|
+
bytesReturned: tail.bytesReturned,
|
|
77584
|
+
...tail.grep ? { grep: tail.grep } : {}
|
|
77585
|
+
};
|
|
77586
|
+
}
|
|
76810
77587
|
case "refine_mesh_node": {
|
|
76811
77588
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
76812
77589
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
76813
77590
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
77591
|
+
{
|
|
77592
|
+
const meshRecordForForward = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
77593
|
+
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
77594
|
+
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
77595
|
+
const selfDaemonId = this.deps.statusInstanceId;
|
|
77596
|
+
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
|
|
77597
|
+
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
77598
|
+
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
77599
|
+
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
77600
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
77601
|
+
coordinatorDaemonId: callerCoordinatorDaemonId || selfDaemonId,
|
|
77602
|
+
_meshDirectDispatch: true
|
|
77603
|
+
});
|
|
77604
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
77605
|
+
}
|
|
77606
|
+
}
|
|
76814
77607
|
const isDryRun = args?.dryRun !== false && args?.execute !== true;
|
|
76815
77608
|
if (isDryRun) {
|
|
76816
77609
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
@@ -77458,15 +78251,15 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77458
78251
|
}
|
|
77459
78252
|
if (cliType === "codex-cli") {
|
|
77460
78253
|
const repoMcpConfigPath = (0, import_path11.join)(workspace, ".mcp.json");
|
|
77461
|
-
if (
|
|
78254
|
+
if (fs25.existsSync(repoMcpConfigPath)) {
|
|
77462
78255
|
try {
|
|
77463
78256
|
const repoMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
77464
|
-
|
|
78257
|
+
fs25.readFileSync(repoMcpConfigPath, "utf-8"),
|
|
77465
78258
|
"claude_mcp_json"
|
|
77466
78259
|
);
|
|
77467
78260
|
const existingServers2 = repoMcpConfig.mcpServers;
|
|
77468
78261
|
if (existingServers2 && typeof existingServers2 === "object" && !Array.isArray(existingServers2) && existingServers2[coordinatorSetup.serverName]) {
|
|
77469
|
-
|
|
78262
|
+
fs25.writeFileSync(repoMcpConfigPath, serializeMeshCoordinatorMcpConfig({
|
|
77470
78263
|
...repoMcpConfig,
|
|
77471
78264
|
mcpServers: {
|
|
77472
78265
|
...existingServers2,
|
|
@@ -77582,7 +78375,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77582
78375
|
workspace
|
|
77583
78376
|
};
|
|
77584
78377
|
}
|
|
77585
|
-
const { existsSync:
|
|
78378
|
+
const { existsSync: existsSync44, readFileSync: readFileSync35, writeFileSync: writeFileSync23, copyFileSync: copyFileSync4, mkdirSync: mkdirSync21 } = await import("fs");
|
|
77586
78379
|
const { dirname: dirname14 } = await import("path");
|
|
77587
78380
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
77588
78381
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -77625,7 +78418,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77625
78418
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
77626
78419
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
77627
78420
|
}
|
|
77628
|
-
const hadExistingMcpConfig =
|
|
78421
|
+
const hadExistingMcpConfig = existsSync44(mcpConfigPath);
|
|
77629
78422
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
77630
78423
|
if (hermesBaseConfig) {
|
|
77631
78424
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname14(mcpConfigPath));
|
|
@@ -77783,6 +78576,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77783
78576
|
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
77784
78577
|
const localMachineId = loadConfig2().machineId || "";
|
|
77785
78578
|
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
78579
|
+
const meshGitProbeCache = this.meshGitProbeCache;
|
|
77786
78580
|
const directTruth = requireDirectPeerTruth ? await hydrateInlineMeshDirectTruth({
|
|
77787
78581
|
mesh,
|
|
77788
78582
|
meshSource: meshRecord.source,
|
|
@@ -77793,14 +78587,16 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77793
78587
|
// Standing-state model: only an explicit refresh fans
|
|
77794
78588
|
// out a blocking peer git probe. Default loads return
|
|
77795
78589
|
// held truth so one slow peer can't block the graph.
|
|
77796
|
-
probeRemotePeers: refreshRequested
|
|
78590
|
+
probeRemotePeers: refreshRequested,
|
|
78591
|
+
probeCache: meshGitProbeCache
|
|
77797
78592
|
}) : {
|
|
77798
78593
|
directEvidenceCount: 0,
|
|
77799
78594
|
localConfirmedCount: 0,
|
|
77800
78595
|
peerAttemptedCount: 0,
|
|
77801
78596
|
peerConfirmedCount: 0,
|
|
77802
78597
|
standingEvidenceCount: 0,
|
|
77803
|
-
unavailableNodeIds: []
|
|
78598
|
+
unavailableNodeIds: [],
|
|
78599
|
+
deadNodeIds: []
|
|
77804
78600
|
};
|
|
77805
78601
|
const passivePeerTruthNotAttempted = requireDirectPeerTruth && !refreshRequested && directTruth.directEvidenceCount > 0 && directTruth.peerAttemptedCount === 0;
|
|
77806
78602
|
const effectiveDirectTruth = passivePeerTruthNotAttempted ? { ...directTruth, unavailableNodeIds: [] } : directTruth;
|
|
@@ -77940,7 +78736,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77940
78736
|
}
|
|
77941
78737
|
}
|
|
77942
78738
|
if (workspace) {
|
|
77943
|
-
if (!
|
|
78739
|
+
if (!fs25.existsSync(workspace)) {
|
|
77944
78740
|
const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
|
|
77945
78741
|
let remoteProbeApplied = false;
|
|
77946
78742
|
if (inlineTransitGit) {
|
|
@@ -77954,7 +78750,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77954
78750
|
}
|
|
77955
78751
|
remoteProbeApplied = true;
|
|
77956
78752
|
} else if (refreshRequested && !isSelfNode && daemonId && this.deps.dispatchMeshCommand && !directTruthUnavailableNodeIds.has(nodeId)) {
|
|
77957
|
-
const
|
|
78753
|
+
const runNodeProbe = () => probeRemoteMeshGitStatusWithRetry({
|
|
77958
78754
|
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
77959
78755
|
daemonId,
|
|
77960
78756
|
workspace,
|
|
@@ -77965,6 +78761,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
77965
78761
|
status.connection = connection;
|
|
77966
78762
|
}
|
|
77967
78763
|
});
|
|
78764
|
+
const remoteGit = await meshGitProbeCache.probe(daemonId, workspace, runNodeProbe);
|
|
77968
78765
|
if (remoteGit) {
|
|
77969
78766
|
status.git = remoteGit;
|
|
77970
78767
|
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
@@ -78030,7 +78827,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
78030
78827
|
const pendingCoordinatorEvents = getPendingMeshCoordinatorEvents(meshId, callerCoordinatorDaemonId);
|
|
78031
78828
|
const unroutableDeliveries = getRecentUnroutableDeliveries();
|
|
78032
78829
|
const previewFreshness = (() => {
|
|
78033
|
-
const localRepoRoot = nodeStatuses.map((node) => readStringValue(node?.git?.repoRoot, node?.repoRoot, node?.workspace)).find((candidate) => !!candidate &&
|
|
78830
|
+
const localRepoRoot = nodeStatuses.map((node) => readStringValue(node?.git?.repoRoot, node?.repoRoot, node?.workspace)).find((candidate) => !!candidate && fs25.existsSync(candidate));
|
|
78034
78831
|
return localRepoRoot ? buildPreviewFreshness(localRepoRoot) : void 0;
|
|
78035
78832
|
})();
|
|
78036
78833
|
const asyncRefineJobs = buildMeshAsyncRefineJobs({
|
|
@@ -78125,7 +78922,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
78125
78922
|
const { deriveMeshReviewInboxItems: deriveMeshReviewInboxItems2 } = await Promise.resolve().then(() => (init_mesh_review_inbox(), mesh_review_inbox_exports));
|
|
78126
78923
|
const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
78127
78924
|
const { getGitDiffSummary: getGitDiffSummary2 } = await Promise.resolve().then(() => (init_git_diff(), git_diff_exports));
|
|
78128
|
-
const { existsSync:
|
|
78925
|
+
const { existsSync: existsSync44 } = await import("fs");
|
|
78129
78926
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
78130
78927
|
const mesh = meshRecord?.mesh;
|
|
78131
78928
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
@@ -78144,7 +78941,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
78144
78941
|
const derivation = deriveMeshReviewInboxItems2({ nodes: nodeStatuses, ledgerEntries });
|
|
78145
78942
|
for (const item of derivation.items) {
|
|
78146
78943
|
const workspace = item.workspace;
|
|
78147
|
-
if (!workspace || !
|
|
78944
|
+
if (!workspace || !existsSync44(workspace)) continue;
|
|
78148
78945
|
const baseRef = item.defaultBranch ? `origin/${item.defaultBranch}` : "origin/main";
|
|
78149
78946
|
try {
|
|
78150
78947
|
const diffResult = await getGitDiffSummary2(workspace, { baseRef, maxFiles: 100 });
|
|
@@ -79868,7 +80665,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
79868
80665
|
this.eventListeners = [];
|
|
79869
80666
|
}
|
|
79870
80667
|
};
|
|
79871
|
-
var
|
|
80668
|
+
var fs26 = __toESM2(require("fs"));
|
|
79872
80669
|
var path36 = __toESM2(require("path"));
|
|
79873
80670
|
var os28 = __toESM2(require("os"));
|
|
79874
80671
|
var import_os4 = require("os");
|
|
@@ -79882,8 +80679,8 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
79882
80679
|
}
|
|
79883
80680
|
load() {
|
|
79884
80681
|
try {
|
|
79885
|
-
if (
|
|
79886
|
-
this.history = JSON.parse(
|
|
80682
|
+
if (fs26.existsSync(ARCHIVE_PATH)) {
|
|
80683
|
+
this.history = JSON.parse(fs26.readFileSync(ARCHIVE_PATH, "utf-8"));
|
|
79887
80684
|
}
|
|
79888
80685
|
} catch {
|
|
79889
80686
|
this.history = {};
|
|
@@ -79920,8 +80717,8 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
79920
80717
|
}
|
|
79921
80718
|
save() {
|
|
79922
80719
|
try {
|
|
79923
|
-
|
|
79924
|
-
|
|
80720
|
+
fs26.mkdirSync(path36.dirname(ARCHIVE_PATH), { recursive: true });
|
|
80721
|
+
fs26.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
79925
80722
|
} catch {
|
|
79926
80723
|
}
|
|
79927
80724
|
}
|
|
@@ -79946,8 +80743,8 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
79946
80743
|
for (const ext of exes) {
|
|
79947
80744
|
const fullPath = path36.join(p, name + ext);
|
|
79948
80745
|
try {
|
|
79949
|
-
if (
|
|
79950
|
-
const stat2 =
|
|
80746
|
+
if (fs26.existsSync(fullPath)) {
|
|
80747
|
+
const stat2 = fs26.statSync(fullPath);
|
|
79951
80748
|
if (stat2.isFile() && (isWin || stat2.mode & 73)) {
|
|
79952
80749
|
return fullPath;
|
|
79953
80750
|
}
|
|
@@ -79994,9 +80791,9 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
79994
80791
|
if (p.includes("*")) {
|
|
79995
80792
|
const home = os28.homedir();
|
|
79996
80793
|
const resolved = p.replace(/\*/g, home.split(path36.sep).pop() || "");
|
|
79997
|
-
if (
|
|
80794
|
+
if (fs26.existsSync(resolved)) return resolved;
|
|
79998
80795
|
} else {
|
|
79999
|
-
if (
|
|
80796
|
+
if (fs26.existsSync(p)) return p;
|
|
80000
80797
|
}
|
|
80001
80798
|
}
|
|
80002
80799
|
return null;
|
|
@@ -80004,7 +80801,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
80004
80801
|
async function getMacAppVersion(appPath) {
|
|
80005
80802
|
if ((0, import_os4.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
80006
80803
|
const plistPath = path36.join(appPath, "Contents", "Info.plist");
|
|
80007
|
-
if (!
|
|
80804
|
+
if (!fs26.existsSync(plistPath)) return null;
|
|
80008
80805
|
const raw = await runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
80009
80806
|
return raw || null;
|
|
80010
80807
|
}
|
|
@@ -80030,7 +80827,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
80030
80827
|
let resolvedBin = cliBin;
|
|
80031
80828
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
80032
80829
|
const bundled = path36.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
80033
|
-
if (provider.cli &&
|
|
80830
|
+
if (provider.cli && fs26.existsSync(bundled)) resolvedBin = bundled;
|
|
80034
80831
|
}
|
|
80035
80832
|
info.installed = !!(appPath || resolvedBin);
|
|
80036
80833
|
info.path = appPath || null;
|
|
@@ -80067,7 +80864,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
80067
80864
|
return results;
|
|
80068
80865
|
}
|
|
80069
80866
|
var http2 = __toESM2(require("http"));
|
|
80070
|
-
var
|
|
80867
|
+
var fs30 = __toESM2(require("fs"));
|
|
80071
80868
|
var path40 = __toESM2(require("path"));
|
|
80072
80869
|
init_config();
|
|
80073
80870
|
function generateFiles(type, name, category, opts = {}) {
|
|
@@ -80412,7 +81209,7 @@ async (params) => {
|
|
|
80412
81209
|
};
|
|
80413
81210
|
}
|
|
80414
81211
|
init_logger();
|
|
80415
|
-
var
|
|
81212
|
+
var fs27 = __toESM2(require("fs"));
|
|
80416
81213
|
var path37 = __toESM2(require("path"));
|
|
80417
81214
|
init_logger();
|
|
80418
81215
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
@@ -80593,17 +81390,17 @@ async (params) => {
|
|
|
80593
81390
|
}
|
|
80594
81391
|
let scriptsPath = "";
|
|
80595
81392
|
const directScripts = path37.join(dir, "scripts.js");
|
|
80596
|
-
if (
|
|
81393
|
+
if (fs27.existsSync(directScripts)) {
|
|
80597
81394
|
scriptsPath = directScripts;
|
|
80598
81395
|
} else {
|
|
80599
81396
|
const scriptsDir = path37.join(dir, "scripts");
|
|
80600
|
-
if (
|
|
80601
|
-
const versions =
|
|
80602
|
-
return
|
|
81397
|
+
if (fs27.existsSync(scriptsDir)) {
|
|
81398
|
+
const versions = fs27.readdirSync(scriptsDir).filter((d) => {
|
|
81399
|
+
return fs27.statSync(path37.join(scriptsDir, d)).isDirectory();
|
|
80603
81400
|
}).sort().reverse();
|
|
80604
81401
|
for (const ver of versions) {
|
|
80605
81402
|
const p = path37.join(scriptsDir, ver, "scripts.js");
|
|
80606
|
-
if (
|
|
81403
|
+
if (fs27.existsSync(p)) {
|
|
80607
81404
|
scriptsPath = p;
|
|
80608
81405
|
break;
|
|
80609
81406
|
}
|
|
@@ -80615,7 +81412,7 @@ async (params) => {
|
|
|
80615
81412
|
return;
|
|
80616
81413
|
}
|
|
80617
81414
|
try {
|
|
80618
|
-
const source =
|
|
81415
|
+
const source = fs27.readFileSync(scriptsPath, "utf-8");
|
|
80619
81416
|
const hints = {};
|
|
80620
81417
|
const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
|
|
80621
81418
|
let match;
|
|
@@ -81428,7 +82225,7 @@ async (params) => {
|
|
|
81428
82225
|
ctx.json(res, 500, { error: `DOM context collection failed: ${e.message}` });
|
|
81429
82226
|
}
|
|
81430
82227
|
}
|
|
81431
|
-
var
|
|
82228
|
+
var fs28 = __toESM2(require("fs"));
|
|
81432
82229
|
var path38 = __toESM2(require("path"));
|
|
81433
82230
|
function slugifyFixtureName(value) {
|
|
81434
82231
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -81444,10 +82241,10 @@ async (params) => {
|
|
|
81444
82241
|
function readCliFixture(ctx, type, name) {
|
|
81445
82242
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
81446
82243
|
const filePath = path38.join(fixtureDir, `${name}.json`);
|
|
81447
|
-
if (!
|
|
82244
|
+
if (!fs28.existsSync(filePath)) {
|
|
81448
82245
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
81449
82246
|
}
|
|
81450
|
-
return JSON.parse(
|
|
82247
|
+
return JSON.parse(fs28.readFileSync(filePath, "utf-8"));
|
|
81451
82248
|
}
|
|
81452
82249
|
function getExerciseTranscriptText(result) {
|
|
81453
82250
|
const parts = [];
|
|
@@ -82192,7 +82989,7 @@ async (params) => {
|
|
|
82192
82989
|
return;
|
|
82193
82990
|
}
|
|
82194
82991
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
82195
|
-
|
|
82992
|
+
fs28.mkdirSync(fixtureDir, { recursive: true });
|
|
82196
82993
|
const name = slugifyFixtureName(String(body?.name || `${type}-${Date.now()}`));
|
|
82197
82994
|
const result = await runCliExerciseInternal(ctx, { ...request, type });
|
|
82198
82995
|
const fixture = {
|
|
@@ -82220,7 +83017,7 @@ async (params) => {
|
|
|
82220
83017
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
82221
83018
|
};
|
|
82222
83019
|
const filePath = path38.join(fixtureDir, `${name}.json`);
|
|
82223
|
-
|
|
83020
|
+
fs28.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
82224
83021
|
ctx.json(res, 200, {
|
|
82225
83022
|
saved: true,
|
|
82226
83023
|
name,
|
|
@@ -82238,14 +83035,14 @@ async (params) => {
|
|
|
82238
83035
|
async function handleCliFixtureList(ctx, type, _req, res) {
|
|
82239
83036
|
try {
|
|
82240
83037
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
82241
|
-
if (!
|
|
83038
|
+
if (!fs28.existsSync(fixtureDir)) {
|
|
82242
83039
|
ctx.json(res, 200, { fixtures: [], count: 0 });
|
|
82243
83040
|
return;
|
|
82244
83041
|
}
|
|
82245
|
-
const fixtures =
|
|
83042
|
+
const fixtures = fs28.readdirSync(fixtureDir).filter((file2) => file2.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file2) => {
|
|
82246
83043
|
const fullPath = path38.join(fixtureDir, file2);
|
|
82247
83044
|
try {
|
|
82248
|
-
const raw = JSON.parse(
|
|
83045
|
+
const raw = JSON.parse(fs28.readFileSync(fullPath, "utf-8"));
|
|
82249
83046
|
return {
|
|
82250
83047
|
name: raw.name || file2.replace(/\.json$/i, ""),
|
|
82251
83048
|
path: fullPath,
|
|
@@ -82376,7 +83173,7 @@ async (params) => {
|
|
|
82376
83173
|
ctx.json(res, 500, { error: `Raw send failed: ${e.message}` });
|
|
82377
83174
|
}
|
|
82378
83175
|
}
|
|
82379
|
-
var
|
|
83176
|
+
var fs29 = __toESM2(require("fs"));
|
|
82380
83177
|
var path39 = __toESM2(require("path"));
|
|
82381
83178
|
var os29 = __toESM2(require("os"));
|
|
82382
83179
|
var import_session_host_core8 = require_dist();
|
|
@@ -82425,10 +83222,10 @@ async (params) => {
|
|
|
82425
83222
|
return fallback?.type || null;
|
|
82426
83223
|
}
|
|
82427
83224
|
function getLatestScriptVersionDir(scriptsDir) {
|
|
82428
|
-
if (!
|
|
82429
|
-
const versions =
|
|
83225
|
+
if (!fs29.existsSync(scriptsDir)) return null;
|
|
83226
|
+
const versions = fs29.readdirSync(scriptsDir).filter((d) => {
|
|
82430
83227
|
try {
|
|
82431
|
-
return
|
|
83228
|
+
return fs29.statSync(path39.join(scriptsDir, d)).isDirectory();
|
|
82432
83229
|
} catch {
|
|
82433
83230
|
return false;
|
|
82434
83231
|
}
|
|
@@ -82450,13 +83247,13 @@ async (params) => {
|
|
|
82450
83247
|
if (!sourceDir) {
|
|
82451
83248
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
82452
83249
|
}
|
|
82453
|
-
if (!
|
|
82454
|
-
|
|
82455
|
-
|
|
83250
|
+
if (!fs29.existsSync(desiredDir)) {
|
|
83251
|
+
fs29.mkdirSync(path39.dirname(desiredDir), { recursive: true });
|
|
83252
|
+
fs29.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
82456
83253
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
82457
83254
|
}
|
|
82458
83255
|
const providerJson = path39.join(desiredDir, "provider.json");
|
|
82459
|
-
if (!
|
|
83256
|
+
if (!fs29.existsSync(providerJson)) {
|
|
82460
83257
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
82461
83258
|
}
|
|
82462
83259
|
return { dir: desiredDir };
|
|
@@ -82464,15 +83261,15 @@ async (params) => {
|
|
|
82464
83261
|
function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
82465
83262
|
if (!referenceType) return {};
|
|
82466
83263
|
const refDir = ctx.findProviderDir(referenceType);
|
|
82467
|
-
if (!refDir || !
|
|
83264
|
+
if (!refDir || !fs29.existsSync(refDir)) return {};
|
|
82468
83265
|
const referenceScripts = {};
|
|
82469
83266
|
const scriptsDir = path39.join(refDir, "scripts");
|
|
82470
83267
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
82471
83268
|
if (!latestDir) return referenceScripts;
|
|
82472
|
-
for (const file2 of
|
|
83269
|
+
for (const file2 of fs29.readdirSync(latestDir)) {
|
|
82473
83270
|
if (!file2.endsWith(".js")) continue;
|
|
82474
83271
|
try {
|
|
82475
|
-
referenceScripts[file2] =
|
|
83272
|
+
referenceScripts[file2] = fs29.readFileSync(path39.join(latestDir, file2), "utf-8");
|
|
82476
83273
|
} catch {
|
|
82477
83274
|
}
|
|
82478
83275
|
}
|
|
@@ -82581,15 +83378,15 @@ async (params) => {
|
|
|
82581
83378
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
82582
83379
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
82583
83380
|
const tmpDir = path39.join(os29.tmpdir(), "adhdev-autoimpl");
|
|
82584
|
-
if (!
|
|
83381
|
+
if (!fs29.existsSync(tmpDir)) fs29.mkdirSync(tmpDir, { recursive: true });
|
|
82585
83382
|
const promptFile = path39.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
82586
|
-
|
|
83383
|
+
fs29.writeFileSync(promptFile, prompt, "utf-8");
|
|
82587
83384
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
82588
83385
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
82589
83386
|
const spawn4 = agentProvider?.spawn;
|
|
82590
83387
|
if (!spawn4?.command) {
|
|
82591
83388
|
try {
|
|
82592
|
-
|
|
83389
|
+
fs29.unlinkSync(promptFile);
|
|
82593
83390
|
} catch {
|
|
82594
83391
|
}
|
|
82595
83392
|
ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
|
|
@@ -82691,7 +83488,7 @@ async (params) => {
|
|
|
82691
83488
|
} catch {
|
|
82692
83489
|
}
|
|
82693
83490
|
try {
|
|
82694
|
-
|
|
83491
|
+
fs29.unlinkSync(promptFile);
|
|
82695
83492
|
} catch {
|
|
82696
83493
|
}
|
|
82697
83494
|
ctx.log(`Auto-implement (ACP) ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
@@ -82917,7 +83714,7 @@ async (params) => {
|
|
|
82917
83714
|
}
|
|
82918
83715
|
});
|
|
82919
83716
|
try {
|
|
82920
|
-
|
|
83717
|
+
fs29.unlinkSync(promptFile);
|
|
82921
83718
|
} catch {
|
|
82922
83719
|
}
|
|
82923
83720
|
ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})${verificationSummary ? ` verify=${verificationSummary.pass ? "pass" : "fail"}` : ""}`);
|
|
@@ -83022,10 +83819,10 @@ async (params) => {
|
|
|
83022
83819
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
83023
83820
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
83024
83821
|
lines.push("");
|
|
83025
|
-
for (const file2 of
|
|
83822
|
+
for (const file2 of fs29.readdirSync(latestScriptsDir)) {
|
|
83026
83823
|
if (file2.endsWith(".js") && targetFileNames.has(file2)) {
|
|
83027
83824
|
try {
|
|
83028
|
-
const content =
|
|
83825
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file2), "utf-8");
|
|
83029
83826
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
83030
83827
|
lines.push("```javascript");
|
|
83031
83828
|
lines.push(content);
|
|
@@ -83035,14 +83832,14 @@ async (params) => {
|
|
|
83035
83832
|
}
|
|
83036
83833
|
}
|
|
83037
83834
|
}
|
|
83038
|
-
const refFiles =
|
|
83835
|
+
const refFiles = fs29.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
83039
83836
|
if (refFiles.length > 0) {
|
|
83040
83837
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
83041
83838
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
83042
83839
|
lines.push("");
|
|
83043
83840
|
for (const file2 of refFiles) {
|
|
83044
83841
|
try {
|
|
83045
|
-
const content =
|
|
83842
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file2), "utf-8");
|
|
83046
83843
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
83047
83844
|
lines.push("```javascript");
|
|
83048
83845
|
lines.push(content);
|
|
@@ -83087,7 +83884,7 @@ async (params) => {
|
|
|
83087
83884
|
const loadGuide = (name) => {
|
|
83088
83885
|
try {
|
|
83089
83886
|
const p = path39.join(docsDir, name);
|
|
83090
|
-
if (
|
|
83887
|
+
if (fs29.existsSync(p)) return fs29.readFileSync(p, "utf-8");
|
|
83091
83888
|
} catch {
|
|
83092
83889
|
}
|
|
83093
83890
|
return null;
|
|
@@ -83331,11 +84128,11 @@ async (params) => {
|
|
|
83331
84128
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
83332
84129
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
83333
84130
|
lines.push("");
|
|
83334
|
-
for (const file2 of
|
|
84131
|
+
for (const file2 of fs29.readdirSync(latestScriptsDir)) {
|
|
83335
84132
|
if (!file2.endsWith(".js")) continue;
|
|
83336
84133
|
if (!targetFileNames.has(file2)) continue;
|
|
83337
84134
|
try {
|
|
83338
|
-
const content =
|
|
84135
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file2), "utf-8");
|
|
83339
84136
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
83340
84137
|
lines.push("```javascript");
|
|
83341
84138
|
lines.push(content);
|
|
@@ -83344,14 +84141,14 @@ async (params) => {
|
|
|
83344
84141
|
} catch {
|
|
83345
84142
|
}
|
|
83346
84143
|
}
|
|
83347
|
-
const refFiles =
|
|
84144
|
+
const refFiles = fs29.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
83348
84145
|
if (refFiles.length > 0) {
|
|
83349
84146
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
83350
84147
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
83351
84148
|
lines.push("");
|
|
83352
84149
|
for (const file2 of refFiles) {
|
|
83353
84150
|
try {
|
|
83354
|
-
const content =
|
|
84151
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file2), "utf-8");
|
|
83355
84152
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
83356
84153
|
lines.push("```javascript");
|
|
83357
84154
|
lines.push(content);
|
|
@@ -83388,7 +84185,7 @@ async (params) => {
|
|
|
83388
84185
|
const loadGuide = (name) => {
|
|
83389
84186
|
try {
|
|
83390
84187
|
const p = path39.join(docsDir, name);
|
|
83391
|
-
if (
|
|
84188
|
+
if (fs29.existsSync(p)) return fs29.readFileSync(p, "utf-8");
|
|
83392
84189
|
} catch {
|
|
83393
84190
|
}
|
|
83394
84191
|
return null;
|
|
@@ -84126,7 +84923,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84126
84923
|
path40.join(process.cwd(), "packages/web-devconsole/dist")
|
|
84127
84924
|
];
|
|
84128
84925
|
for (const dir of candidates) {
|
|
84129
|
-
if (
|
|
84926
|
+
if (fs30.existsSync(path40.join(dir, "index.html"))) return dir;
|
|
84130
84927
|
}
|
|
84131
84928
|
return null;
|
|
84132
84929
|
}
|
|
@@ -84138,7 +84935,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84138
84935
|
}
|
|
84139
84936
|
const htmlPath = path40.join(distDir, "index.html");
|
|
84140
84937
|
try {
|
|
84141
|
-
const html =
|
|
84938
|
+
const html = fs30.readFileSync(htmlPath, "utf-8");
|
|
84142
84939
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
84143
84940
|
res.end(html);
|
|
84144
84941
|
} catch (e) {
|
|
@@ -84168,7 +84965,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84168
84965
|
return;
|
|
84169
84966
|
}
|
|
84170
84967
|
try {
|
|
84171
|
-
const content =
|
|
84968
|
+
const content = fs30.readFileSync(filePath);
|
|
84172
84969
|
const ext = path40.extname(filePath);
|
|
84173
84970
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
84174
84971
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
@@ -84277,14 +85074,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84277
85074
|
const files = [];
|
|
84278
85075
|
const scan = (d, prefix) => {
|
|
84279
85076
|
try {
|
|
84280
|
-
for (const entry of
|
|
85077
|
+
for (const entry of fs30.readdirSync(d, { withFileTypes: true })) {
|
|
84281
85078
|
if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
|
|
84282
85079
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
84283
85080
|
if (entry.isDirectory()) {
|
|
84284
85081
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
84285
85082
|
scan(path40.join(d, entry.name), rel);
|
|
84286
85083
|
} else {
|
|
84287
|
-
const stat2 =
|
|
85084
|
+
const stat2 = fs30.statSync(path40.join(d, entry.name));
|
|
84288
85085
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
84289
85086
|
}
|
|
84290
85087
|
}
|
|
@@ -84312,11 +85109,11 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84312
85109
|
this.json(res, 403, { error: "Forbidden" });
|
|
84313
85110
|
return;
|
|
84314
85111
|
}
|
|
84315
|
-
if (!
|
|
85112
|
+
if (!fs30.existsSync(fullPath) || fs30.statSync(fullPath).isDirectory()) {
|
|
84316
85113
|
this.json(res, 404, { error: `File not found: ${filePath}` });
|
|
84317
85114
|
return;
|
|
84318
85115
|
}
|
|
84319
|
-
const content =
|
|
85116
|
+
const content = fs30.readFileSync(fullPath, "utf-8");
|
|
84320
85117
|
this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
|
|
84321
85118
|
}
|
|
84322
85119
|
/** POST /api/providers/:type/file — write a file { path, content } */
|
|
@@ -84338,9 +85135,9 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84338
85135
|
return;
|
|
84339
85136
|
}
|
|
84340
85137
|
try {
|
|
84341
|
-
if (
|
|
84342
|
-
|
|
84343
|
-
|
|
85138
|
+
if (fs30.existsSync(fullPath)) fs30.copyFileSync(fullPath, fullPath + ".bak");
|
|
85139
|
+
fs30.mkdirSync(path40.dirname(fullPath), { recursive: true });
|
|
85140
|
+
fs30.writeFileSync(fullPath, content, "utf-8");
|
|
84344
85141
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
84345
85142
|
this.providerLoader.reload();
|
|
84346
85143
|
this.json(res, 200, { saved: true, path: filePath, chars: content.length });
|
|
@@ -84357,8 +85154,8 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84357
85154
|
}
|
|
84358
85155
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
84359
85156
|
const p = path40.join(dir, name);
|
|
84360
|
-
if (
|
|
84361
|
-
const source =
|
|
85157
|
+
if (fs30.existsSync(p)) {
|
|
85158
|
+
const source = fs30.readFileSync(p, "utf-8");
|
|
84362
85159
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
84363
85160
|
return;
|
|
84364
85161
|
}
|
|
@@ -84377,11 +85174,11 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84377
85174
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
84378
85175
|
return;
|
|
84379
85176
|
}
|
|
84380
|
-
const target =
|
|
85177
|
+
const target = fs30.existsSync(path40.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
84381
85178
|
const targetPath = path40.join(dir, target);
|
|
84382
85179
|
try {
|
|
84383
|
-
if (
|
|
84384
|
-
|
|
85180
|
+
if (fs30.existsSync(targetPath)) fs30.copyFileSync(targetPath, targetPath + ".bak");
|
|
85181
|
+
fs30.writeFileSync(targetPath, source, "utf-8");
|
|
84385
85182
|
this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
|
|
84386
85183
|
this.providerLoader.reload();
|
|
84387
85184
|
this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
|
|
@@ -84526,20 +85323,20 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84526
85323
|
let targetDir;
|
|
84527
85324
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
84528
85325
|
const jsonPath = path40.join(targetDir, "provider.json");
|
|
84529
|
-
if (
|
|
85326
|
+
if (fs30.existsSync(jsonPath)) {
|
|
84530
85327
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
84531
85328
|
return;
|
|
84532
85329
|
}
|
|
84533
85330
|
try {
|
|
84534
85331
|
const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2, osPaths, processNames });
|
|
84535
|
-
|
|
84536
|
-
|
|
85332
|
+
fs30.mkdirSync(targetDir, { recursive: true });
|
|
85333
|
+
fs30.writeFileSync(jsonPath, result["provider.json"], "utf-8");
|
|
84537
85334
|
const createdFiles = ["provider.json"];
|
|
84538
85335
|
if (result.files) {
|
|
84539
85336
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
84540
85337
|
const fullPath = path40.join(targetDir, relPath);
|
|
84541
|
-
|
|
84542
|
-
|
|
85338
|
+
fs30.mkdirSync(path40.dirname(fullPath), { recursive: true });
|
|
85339
|
+
fs30.writeFileSync(fullPath, content, "utf-8");
|
|
84543
85340
|
createdFiles.push(relPath);
|
|
84544
85341
|
}
|
|
84545
85342
|
}
|
|
@@ -84588,10 +85385,10 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84588
85385
|
}
|
|
84589
85386
|
// ─── Phase 2: Auto-Implement Backend ───
|
|
84590
85387
|
getLatestScriptVersionDir(scriptsDir) {
|
|
84591
|
-
if (!
|
|
84592
|
-
const versions =
|
|
85388
|
+
if (!fs30.existsSync(scriptsDir)) return null;
|
|
85389
|
+
const versions = fs30.readdirSync(scriptsDir).filter((d) => {
|
|
84593
85390
|
try {
|
|
84594
|
-
return
|
|
85391
|
+
return fs30.statSync(path40.join(scriptsDir, d)).isDirectory();
|
|
84595
85392
|
} catch {
|
|
84596
85393
|
return false;
|
|
84597
85394
|
}
|
|
@@ -84613,13 +85410,13 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84613
85410
|
if (!sourceDir) {
|
|
84614
85411
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
84615
85412
|
}
|
|
84616
|
-
if (!
|
|
84617
|
-
|
|
84618
|
-
|
|
85413
|
+
if (!fs30.existsSync(desiredDir)) {
|
|
85414
|
+
fs30.mkdirSync(path40.dirname(desiredDir), { recursive: true });
|
|
85415
|
+
fs30.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
84619
85416
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
84620
85417
|
}
|
|
84621
85418
|
const providerJson = path40.join(desiredDir, "provider.json");
|
|
84622
|
-
if (!
|
|
85419
|
+
if (!fs30.existsSync(providerJson)) {
|
|
84623
85420
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
84624
85421
|
}
|
|
84625
85422
|
return { dir: desiredDir };
|
|
@@ -84662,10 +85459,10 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84662
85459
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
84663
85460
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
84664
85461
|
lines.push("");
|
|
84665
|
-
for (const file2 of
|
|
85462
|
+
for (const file2 of fs30.readdirSync(latestScriptsDir)) {
|
|
84666
85463
|
if (file2.endsWith(".js") && targetFileNames.has(file2)) {
|
|
84667
85464
|
try {
|
|
84668
|
-
const content =
|
|
85465
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file2), "utf-8");
|
|
84669
85466
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
84670
85467
|
lines.push("```javascript");
|
|
84671
85468
|
lines.push(content);
|
|
@@ -84675,14 +85472,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84675
85472
|
}
|
|
84676
85473
|
}
|
|
84677
85474
|
}
|
|
84678
|
-
const refFiles =
|
|
85475
|
+
const refFiles = fs30.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
84679
85476
|
if (refFiles.length > 0) {
|
|
84680
85477
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
84681
85478
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
84682
85479
|
lines.push("");
|
|
84683
85480
|
for (const file2 of refFiles) {
|
|
84684
85481
|
try {
|
|
84685
|
-
const content =
|
|
85482
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file2), "utf-8");
|
|
84686
85483
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
84687
85484
|
lines.push("```javascript");
|
|
84688
85485
|
lines.push(content);
|
|
@@ -84727,7 +85524,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84727
85524
|
const loadGuide = (name) => {
|
|
84728
85525
|
try {
|
|
84729
85526
|
const p = path40.join(docsDir, name);
|
|
84730
|
-
if (
|
|
85527
|
+
if (fs30.existsSync(p)) return fs30.readFileSync(p, "utf-8");
|
|
84731
85528
|
} catch {
|
|
84732
85529
|
}
|
|
84733
85530
|
return null;
|
|
@@ -84908,11 +85705,11 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84908
85705
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
84909
85706
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
84910
85707
|
lines.push("");
|
|
84911
|
-
for (const file2 of
|
|
85708
|
+
for (const file2 of fs30.readdirSync(latestScriptsDir)) {
|
|
84912
85709
|
if (!file2.endsWith(".js")) continue;
|
|
84913
85710
|
if (!targetFileNames.has(file2)) continue;
|
|
84914
85711
|
try {
|
|
84915
|
-
const content =
|
|
85712
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file2), "utf-8");
|
|
84916
85713
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
84917
85714
|
lines.push("```javascript");
|
|
84918
85715
|
lines.push(content);
|
|
@@ -84921,14 +85718,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84921
85718
|
} catch {
|
|
84922
85719
|
}
|
|
84923
85720
|
}
|
|
84924
|
-
const refFiles =
|
|
85721
|
+
const refFiles = fs30.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
84925
85722
|
if (refFiles.length > 0) {
|
|
84926
85723
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
84927
85724
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
84928
85725
|
lines.push("");
|
|
84929
85726
|
for (const file2 of refFiles) {
|
|
84930
85727
|
try {
|
|
84931
|
-
const content =
|
|
85728
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file2), "utf-8");
|
|
84932
85729
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
84933
85730
|
lines.push("```javascript");
|
|
84934
85731
|
lines.push(content);
|
|
@@ -84965,7 +85762,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
84965
85762
|
const loadGuide = (name) => {
|
|
84966
85763
|
try {
|
|
84967
85764
|
const p = path40.join(docsDir, name);
|
|
84968
|
-
if (
|
|
85765
|
+
if (fs30.existsSync(p)) return fs30.readFileSync(p, "utf-8");
|
|
84969
85766
|
} catch {
|
|
84970
85767
|
}
|
|
84971
85768
|
return null;
|
|
@@ -86052,8 +86849,8 @@ data: ${JSON.stringify(msg.data)}
|
|
|
86052
86849
|
const res = await fetch(extension.vsixUrl);
|
|
86053
86850
|
if (res.ok) {
|
|
86054
86851
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
86055
|
-
const
|
|
86056
|
-
|
|
86852
|
+
const fs31 = await import("fs");
|
|
86853
|
+
fs31.writeFileSync(vsixPath, buffer);
|
|
86057
86854
|
return new Promise((resolve24) => {
|
|
86058
86855
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
86059
86856
|
(0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
|