@adhdev/daemon-core 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/commands/router.d.ts +19 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1070 -263
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1069 -270
- package/dist/index.mjs.map +1 -1
- package/dist/logging/log-redactor.d.ts +24 -0
- package/dist/logging/log-tail-reader.d.ts +46 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +31 -0
- package/dist/mesh/mesh-runtime-store.d.ts +18 -0
- package/dist/mesh/mesh-work-queue.d.ts +23 -0
- package/dist/providers/spec/cli-adapter.d.ts +34 -3
- package/dist/providers/spec/types.d.ts +36 -0
- package/dist/repo-mesh-types.d.ts +103 -9
- package/package.json +2 -2
- package/src/commands/chat-commands.ts +10 -2
- package/src/commands/router.ts +323 -6
- package/src/commands/stream-commands.ts +8 -0
- package/src/config/chat-history.ts +9 -0
- package/src/config/mesh-config.ts +17 -1
- package/src/index.ts +16 -2
- package/src/logging/log-redactor.ts +100 -0
- package/src/logging/log-tail-reader.ts +220 -0
- package/src/mesh/coordinator-prompt.ts +1 -0
- package/src/mesh/mesh-events-coordinator.ts +165 -9
- package/src/mesh/mesh-runtime-store.ts +52 -0
- package/src/mesh/mesh-work-queue.ts +105 -1
- package/src/providers/spec/cli-adapter.ts +155 -13
- package/src/providers/spec/fsm-driver.ts +14 -1
- package/src/providers/spec/native-history-executor.ts +114 -22
- package/src/providers/spec/types.ts +37 -0
- package/src/repo-mesh-types.ts +134 -9
package/dist/index.mjs
CHANGED
|
@@ -26,6 +26,18 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
26
26
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
27
|
|
|
28
28
|
// src/repo-mesh-types.ts
|
|
29
|
+
function normalizeMeshSchedulingStrategy(value) {
|
|
30
|
+
if (typeof value !== "string") return DEFAULT_MESH_SCHEDULING_STRATEGY;
|
|
31
|
+
const trimmed = value.trim();
|
|
32
|
+
return MESH_SCHEDULING_STRATEGIES.includes(trimmed) ? trimmed : DEFAULT_MESH_SCHEDULING_STRATEGY;
|
|
33
|
+
}
|
|
34
|
+
function resolveNodeSchedulingPriority(nodePolicy) {
|
|
35
|
+
const raw = Number(nodePolicy?.schedulingPriority);
|
|
36
|
+
return Number.isFinite(raw) ? raw : 0;
|
|
37
|
+
}
|
|
38
|
+
function resolveAutoConvergeCodeChange(policy) {
|
|
39
|
+
return policy?.autoConvergeCodeChange === true;
|
|
40
|
+
}
|
|
29
41
|
function resolveDelegatedWorkerAutoApprove(meshPolicy, nodePolicy) {
|
|
30
42
|
if (typeof nodePolicy?.delegatedWorkerAutoApprove === "boolean") {
|
|
31
43
|
return nodePolicy.delegatedWorkerAutoApprove;
|
|
@@ -53,10 +65,19 @@ function resolveProviderMaxParallel(nodePolicy, providerType) {
|
|
|
53
65
|
if (!Number.isFinite(raw) || raw < 0) return void 0;
|
|
54
66
|
return Math.floor(raw);
|
|
55
67
|
}
|
|
56
|
-
var DEFAULT_MESH_POLICY;
|
|
68
|
+
var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_REFINE_TAG, MESH_CONVERGE_FAST_FORWARD_TAG, DEFAULT_MESH_POLICY;
|
|
57
69
|
var init_repo_mesh_types = __esm({
|
|
58
70
|
"src/repo-mesh-types.ts"() {
|
|
59
71
|
"use strict";
|
|
72
|
+
MESH_SCHEDULING_STRATEGIES = [
|
|
73
|
+
"first_eligible",
|
|
74
|
+
"least_loaded",
|
|
75
|
+
"round_robin",
|
|
76
|
+
"priority_only"
|
|
77
|
+
];
|
|
78
|
+
DEFAULT_MESH_SCHEDULING_STRATEGY = "first_eligible";
|
|
79
|
+
MESH_CONVERGE_REFINE_TAG = "converge=refine";
|
|
80
|
+
MESH_CONVERGE_FAST_FORWARD_TAG = "converge=fast_forward";
|
|
60
81
|
DEFAULT_MESH_POLICY = {
|
|
61
82
|
requirePreTaskCheckpoint: false,
|
|
62
83
|
requirePostTaskCheckpoint: true,
|
|
@@ -290,10 +311,10 @@ function readInjected(value) {
|
|
|
290
311
|
}
|
|
291
312
|
function getDaemonBuildInfo() {
|
|
292
313
|
if (cached) return cached;
|
|
293
|
-
const commit = readInjected(true ? "
|
|
294
|
-
const commitShort = readInjected(true ? "
|
|
295
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
296
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
314
|
+
const commit = readInjected(true ? "35facf0367dbbe37f25a3b5589287dc757ee6213" : void 0) ?? "unknown";
|
|
315
|
+
const commitShort = readInjected(true ? "35facf03" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
316
|
+
const version = readInjected(true ? "0.9.82-rc.312" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
317
|
+
const builtAt = readInjected(true ? "2026-06-17T22:48:50.124Z" : void 0);
|
|
297
318
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
298
319
|
return cached;
|
|
299
320
|
}
|
|
@@ -1543,6 +1564,17 @@ function mergeMeshPolicy(base, patch) {
|
|
|
1543
1564
|
if (!SPAWNED_SESSION_VISIBILITY_MODES.has(String(policy.spawnedSessionVisibility))) {
|
|
1544
1565
|
policy.spawnedSessionVisibility = "visible";
|
|
1545
1566
|
}
|
|
1567
|
+
const normalizedStrategy = normalizeMeshSchedulingStrategy(policy.schedulingStrategy);
|
|
1568
|
+
if (normalizedStrategy === "first_eligible") {
|
|
1569
|
+
delete policy.schedulingStrategy;
|
|
1570
|
+
} else {
|
|
1571
|
+
policy.schedulingStrategy = normalizedStrategy;
|
|
1572
|
+
}
|
|
1573
|
+
if (policy.autoConvergeCodeChange === true) {
|
|
1574
|
+
policy.autoConvergeCodeChange = true;
|
|
1575
|
+
} else {
|
|
1576
|
+
delete policy.autoConvergeCodeChange;
|
|
1577
|
+
}
|
|
1546
1578
|
return policy;
|
|
1547
1579
|
}
|
|
1548
1580
|
function normalizeAutoFastForwardPolicy(value) {
|
|
@@ -2081,6 +2113,7 @@ var init_coordinator_prompt = __esm({
|
|
|
2081
2113
|
| \`mesh_read_debug\` | Collect a daemon-side chat/parser debug bundle for a session |
|
|
2082
2114
|
| \`mesh_task_history\` | Read the task ledger \u2014 dispatches, completions, failures. Use to understand what has been done before deciding next steps |
|
|
2083
2115
|
| \`mesh_git_status\` | Check git status on a specific node |
|
|
2116
|
+
| \`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 |
|
|
2084
2117
|
| \`mesh_fast_forward_node\` | Safely dry-run or explicitly execute an obvious clean fast-forward without launching an agent session |
|
|
2085
2118
|
| \`mesh_checkpoint\` | Create a git checkpoint on a node |
|
|
2086
2119
|
| \`mesh_approve\` | Approve/reject a pending agent action |
|
|
@@ -2833,6 +2866,7 @@ __export(mesh_work_queue_exports, {
|
|
|
2833
2866
|
recordMeshToolCall: () => recordMeshToolCall,
|
|
2834
2867
|
recordTaskAutoLaunch: () => recordTaskAutoLaunch,
|
|
2835
2868
|
requeueTask: () => requeueTask,
|
|
2869
|
+
resolveConvergeRequiredTags: () => resolveConvergeRequiredTags,
|
|
2836
2870
|
updateDirectDispatchStatus: () => updateDirectDispatchStatus,
|
|
2837
2871
|
updateSessionTaskStatus: () => updateSessionTaskStatus,
|
|
2838
2872
|
updateTaskStatus: () => updateTaskStatus,
|
|
@@ -2907,6 +2941,21 @@ function firstProviderPriority(policy) {
|
|
|
2907
2941
|
if (!Array.isArray(raw)) return void 0;
|
|
2908
2942
|
return raw.find((type) => typeof type === "string" && type.trim())?.trim();
|
|
2909
2943
|
}
|
|
2944
|
+
function roleCapabilityTags(policy, providerType) {
|
|
2945
|
+
const roles = policy && typeof policy === "object" && !Array.isArray(policy) ? policy.providerRoles : void 0;
|
|
2946
|
+
if (!Array.isArray(roles)) return [];
|
|
2947
|
+
const wantedProvider = typeof providerType === "string" && providerType.trim() ? providerType.trim().toLowerCase() : "";
|
|
2948
|
+
const out = [];
|
|
2949
|
+
for (const entry of roles) {
|
|
2950
|
+
if (!entry || typeof entry !== "object") continue;
|
|
2951
|
+
const type = typeof entry.providerType === "string" ? entry.providerType.trim().toLowerCase() : "";
|
|
2952
|
+
const role = typeof entry.role === "string" ? entry.role.trim().toLowerCase() : "";
|
|
2953
|
+
if (!role) continue;
|
|
2954
|
+
if (wantedProvider && type && type !== wantedProvider) continue;
|
|
2955
|
+
out.push(`role=${role}`);
|
|
2956
|
+
}
|
|
2957
|
+
return out;
|
|
2958
|
+
}
|
|
2910
2959
|
function buildMeshNodeCapabilityTags(node, providerType) {
|
|
2911
2960
|
const provider = typeof providerType === "string" && providerType.trim() ? providerType.trim() : firstProviderPriority(node?.policy);
|
|
2912
2961
|
const worktreeBranch = typeof node?.worktreeBranch === "string" && node.worktreeBranch.trim() ? node.worktreeBranch.trim() : null;
|
|
@@ -2918,7 +2967,25 @@ function buildMeshNodeCapabilityTags(node, providerType) {
|
|
|
2918
2967
|
// Worktree nodes automatically expose a "worktree=<branch>" tag so that
|
|
2919
2968
|
// mesh_enqueue_task with required_tags: ["worktree=<branch>"] routes
|
|
2920
2969
|
// only to the matching worktree node.
|
|
2921
|
-
...node?.isLocalWorktree === true && worktreeBranch ? [`worktree=${worktreeBranch}`] : []
|
|
2970
|
+
...node?.isLocalWorktree === true && worktreeBranch ? [`worktree=${worktreeBranch}`] : [],
|
|
2971
|
+
// Convergence routing: advertise how this node can land its work onto base.
|
|
2972
|
+
// - converge=refine: local worktree nodes (on ANY machine — refine_mesh_node
|
|
2973
|
+
// now forwards to the owning daemon) can run the Refinery merge → push →
|
|
2974
|
+
// cleanup against their own checkout, so they accept code_change tasks.
|
|
2975
|
+
// - converge=fast_forward: non-worktree nodes (the machine itself) can only
|
|
2976
|
+
// ff/push an already-converged branch; they are NOT a destination for
|
|
2977
|
+
// code_change work (a worktree is created first, and that worktree node
|
|
2978
|
+
// receives the task instead). Reuses the ordinary required-tags filter —
|
|
2979
|
+
// the load-balancing scheduler auto-injects converge=refine for code_change
|
|
2980
|
+
// so such work is hard-filtered onto refine-capable nodes.
|
|
2981
|
+
...node?.isLocalWorktree === true ? ["converge=refine"] : ["converge=fast_forward"],
|
|
2982
|
+
// Role-based routing: advertise role=<x> for each (node, provider) role
|
|
2983
|
+
// declared in policy.providerRoles. Narrowed to the selected provider when
|
|
2984
|
+
// one is given so the chosen provider must match a task's required role;
|
|
2985
|
+
// when no provider is selected, all declared roles are advertised for the
|
|
2986
|
+
// node-level eligibility scan. Reuses the ordinary required-tags filter —
|
|
2987
|
+
// no separate role field/gate.
|
|
2988
|
+
...roleCapabilityTags(node?.policy, providerType)
|
|
2922
2989
|
]);
|
|
2923
2990
|
}
|
|
2924
2991
|
function nodeSatisfiesRequiredTags(requiredTags, capabilityTags) {
|
|
@@ -2927,6 +2994,18 @@ function nodeSatisfiesRequiredTags(requiredTags, capabilityTags) {
|
|
|
2927
2994
|
const available = new Set(normalizeMeshCapabilityTags(capabilityTags));
|
|
2928
2995
|
return required.every((tag) => available.has(tag));
|
|
2929
2996
|
}
|
|
2997
|
+
function resolveConvergeRequiredTags(meshId, taskMode, explicitRequiredTags, opts) {
|
|
2998
|
+
if (taskMode !== "code_change") return explicitRequiredTags;
|
|
2999
|
+
if (typeof opts?.targetNodeId === "string" && opts.targetNodeId.trim()) return explicitRequiredTags;
|
|
3000
|
+
let optedIn = false;
|
|
3001
|
+
try {
|
|
3002
|
+
optedIn = resolveAutoConvergeCodeChange(getMesh(meshId)?.policy);
|
|
3003
|
+
} catch {
|
|
3004
|
+
optedIn = false;
|
|
3005
|
+
}
|
|
3006
|
+
if (!optedIn) return explicitRequiredTags;
|
|
3007
|
+
return normalizeMeshCapabilityTags([...explicitRequiredTags, MESH_CONVERGE_REFINE_TAG]);
|
|
3008
|
+
}
|
|
2930
3009
|
function withQueueLock(_meshId, fn) {
|
|
2931
3010
|
return MeshRuntimeStore.getInstance().transaction(fn);
|
|
2932
3011
|
}
|
|
@@ -2985,7 +3064,15 @@ function enqueueTask(meshId, message, opts) {
|
|
|
2985
3064
|
taskMode: modeValidation.taskMode,
|
|
2986
3065
|
targetNodeId: opts?.targetNodeId,
|
|
2987
3066
|
targetSessionId: opts?.targetSessionId,
|
|
2988
|
-
|
|
3067
|
+
// Convergence routing (opt-in): auto-inject converge=refine for code_change
|
|
3068
|
+
// tasks so they hard-filter onto refine-capable worktree nodes. No-op unless
|
|
3069
|
+
// the mesh opts in; explicit target_node_id / required_tags are preserved.
|
|
3070
|
+
requiredTags: resolveConvergeRequiredTags(
|
|
3071
|
+
meshId,
|
|
3072
|
+
modeValidation.taskMode,
|
|
3073
|
+
normalizeMeshCapabilityTags(opts?.requiredTags),
|
|
3074
|
+
{ targetNodeId: opts?.targetNodeId }
|
|
3075
|
+
),
|
|
2989
3076
|
...dependsOn.length > 0 ? { dependsOn } : {},
|
|
2990
3077
|
...typeof opts?.missionId === "string" && opts.missionId.trim() ? { missionId: opts.missionId.trim() } : {},
|
|
2991
3078
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3245,6 +3332,7 @@ var init_mesh_work_queue = __esm({
|
|
|
3245
3332
|
"src/mesh/mesh-work-queue.ts"() {
|
|
3246
3333
|
"use strict";
|
|
3247
3334
|
init_mesh_host_ownership();
|
|
3335
|
+
init_repo_mesh_types();
|
|
3248
3336
|
init_mesh_runtime_store();
|
|
3249
3337
|
init_mesh_config();
|
|
3250
3338
|
ACTIVE_MESH_QUEUE_STATUSES = ["pending", "assigned"];
|
|
@@ -3538,6 +3626,17 @@ var init_mesh_runtime_store = __esm({
|
|
|
3538
3626
|
|
|
3539
3627
|
CREATE INDEX IF NOT EXISTS idx_mesh_missions_mesh_status
|
|
3540
3628
|
ON mesh_missions(mesh_id, status, updated_at);
|
|
3629
|
+
|
|
3630
|
+
-- Load-balancing scheduler: per-mesh round-robin rotation cursor. When
|
|
3631
|
+
-- the schedulingStrategy is 'round_robin', several eligible nodes tied at
|
|
3632
|
+
-- the least load are rotated by this cursor so the tie-break winner cycles
|
|
3633
|
+
-- across scheduling passes instead of always favouring the same array-order
|
|
3634
|
+
-- node. Persisted (not a module Map) so rotation survives daemon restarts
|
|
3635
|
+
-- and stays a single source of truth across scheduling entry points.
|
|
3636
|
+
CREATE TABLE IF NOT EXISTS mesh_scheduler_cursor (
|
|
3637
|
+
mesh_id TEXT PRIMARY KEY,
|
|
3638
|
+
cursor INTEGER NOT NULL DEFAULT 0
|
|
3639
|
+
);
|
|
3541
3640
|
`);
|
|
3542
3641
|
}
|
|
3543
3642
|
hasCompletionFingerprint(fingerprint) {
|
|
@@ -3715,6 +3814,44 @@ var init_mesh_runtime_store = __esm({
|
|
|
3715
3814
|
`).get(meshId, nodeId);
|
|
3716
3815
|
return row !== void 0;
|
|
3717
3816
|
}
|
|
3817
|
+
/**
|
|
3818
|
+
* Count active (status='assigned') tasks on a node, regardless of provider or
|
|
3819
|
+
* task mode. This is the load metric for least-loaded / round-robin ranking:
|
|
3820
|
+
* the scheduler prefers the node with the fewest active assignments so
|
|
3821
|
+
* untargeted work spreads instead of piling onto whichever node asks first.
|
|
3822
|
+
*/
|
|
3823
|
+
nodeActiveAssignmentCount(meshId, nodeId) {
|
|
3824
|
+
const row = this.db.prepare(`
|
|
3825
|
+
SELECT COUNT(*) as count FROM mesh_queue
|
|
3826
|
+
WHERE mesh_id = ? AND status = 'assigned' AND assigned_node_id = ?
|
|
3827
|
+
`).get(meshId, nodeId);
|
|
3828
|
+
return row?.count ?? 0;
|
|
3829
|
+
}
|
|
3830
|
+
/**
|
|
3831
|
+
* Read the current per-mesh round-robin cursor (0 when unset). Used to rotate
|
|
3832
|
+
* the tie-break winner among nodes tied at the least load.
|
|
3833
|
+
*/
|
|
3834
|
+
getSchedulerCursor(meshId) {
|
|
3835
|
+
const row = this.db.prepare(
|
|
3836
|
+
"SELECT cursor FROM mesh_scheduler_cursor WHERE mesh_id = ?"
|
|
3837
|
+
).get(meshId);
|
|
3838
|
+
return row?.cursor ?? 0;
|
|
3839
|
+
}
|
|
3840
|
+
/**
|
|
3841
|
+
* Atomically advance the per-mesh round-robin cursor by one and return the
|
|
3842
|
+
* value that was current BEFORE the bump (the value the caller should rotate
|
|
3843
|
+
* by for this pass). UPSERT keeps it lock-free across concurrent passes.
|
|
3844
|
+
*/
|
|
3845
|
+
bumpSchedulerCursor(meshId) {
|
|
3846
|
+
return this.transaction(() => {
|
|
3847
|
+
const current = this.getSchedulerCursor(meshId);
|
|
3848
|
+
this.db.prepare(`
|
|
3849
|
+
INSERT INTO mesh_scheduler_cursor (mesh_id, cursor) VALUES (?, ?)
|
|
3850
|
+
ON CONFLICT(mesh_id) DO UPDATE SET cursor = excluded.cursor
|
|
3851
|
+
`).run(meshId, current + 1);
|
|
3852
|
+
return current;
|
|
3853
|
+
});
|
|
3854
|
+
}
|
|
3718
3855
|
/**
|
|
3719
3856
|
* Count active (status='assigned') tasks on a (node, provider) combination,
|
|
3720
3857
|
* matched by the assignedProviderType stamped on the payload at claim time.
|
|
@@ -5688,8 +5825,8 @@ function stripCoordinatorWrapperFile(filePath) {
|
|
|
5688
5825
|
const remaining = (existing.slice(0, openIdx) + existing.slice(closeIdx + CLOSE.length)).replace(/^\s*\n+/, "").replace(/\n+\s*$/, "");
|
|
5689
5826
|
if (!remaining.trim()) {
|
|
5690
5827
|
try {
|
|
5691
|
-
const
|
|
5692
|
-
|
|
5828
|
+
const fs31 = __require("fs");
|
|
5829
|
+
fs31.unlinkSync(filePath);
|
|
5693
5830
|
} catch {
|
|
5694
5831
|
}
|
|
5695
5832
|
} else {
|
|
@@ -8286,6 +8423,33 @@ function activeReadonlyAssignedCount(meshId) {
|
|
|
8286
8423
|
function nodeHasActiveAssignment(meshId, nodeId) {
|
|
8287
8424
|
return getQueue(meshId, { status: ["assigned"] }).some((task) => task.assignedNodeId === nodeId);
|
|
8288
8425
|
}
|
|
8426
|
+
function nodeActiveLoad(meshId, nodeId) {
|
|
8427
|
+
return MeshRuntimeStore.getInstance().nodeActiveAssignmentCount(meshId, nodeId);
|
|
8428
|
+
}
|
|
8429
|
+
function resolveSchedulingStrategy(mesh) {
|
|
8430
|
+
return normalizeMeshSchedulingStrategy(mesh?.policy?.schedulingStrategy);
|
|
8431
|
+
}
|
|
8432
|
+
function orderEligibleNodes(meshId, strategy, nodes, opts) {
|
|
8433
|
+
if (strategy === "first_eligible" || nodes.length <= 1) {
|
|
8434
|
+
return nodes;
|
|
8435
|
+
}
|
|
8436
|
+
const priorityOf = (n) => resolveNodeSchedulingPriority(n.node?.policy);
|
|
8437
|
+
let rotation = 0;
|
|
8438
|
+
if (strategy === "round_robin") {
|
|
8439
|
+
const cursor = opts?.bumpCursor ? MeshRuntimeStore.getInstance().bumpSchedulerCursor(meshId) : MeshRuntimeStore.getInstance().getSchedulerCursor(meshId);
|
|
8440
|
+
rotation = (cursor % nodes.length + nodes.length) % nodes.length;
|
|
8441
|
+
}
|
|
8442
|
+
const rotationRank = (index) => (index - rotation + nodes.length) % nodes.length;
|
|
8443
|
+
return [...nodes].sort((a, b) => {
|
|
8444
|
+
const prioDelta = priorityOf(b) - priorityOf(a);
|
|
8445
|
+
if (prioDelta !== 0) return prioDelta;
|
|
8446
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
8447
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
8448
|
+
if (loadDelta !== 0) return loadDelta;
|
|
8449
|
+
}
|
|
8450
|
+
return rotationRank(a.index) - rotationRank(b.index);
|
|
8451
|
+
});
|
|
8452
|
+
}
|
|
8289
8453
|
function activeProviderAssignedCount(meshId, nodeId, providerType) {
|
|
8290
8454
|
return getQueue(meshId, { status: ["assigned"] }).filter((task) => task.assignedNodeId === nodeId && task.assignedProviderType === providerType).length;
|
|
8291
8455
|
}
|
|
@@ -8422,7 +8586,14 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
8422
8586
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "no_node_satisfies_required_tags", nodeId: task.targetNodeId });
|
|
8423
8587
|
continue;
|
|
8424
8588
|
}
|
|
8425
|
-
|
|
8589
|
+
const strategy = resolveSchedulingStrategy(mesh);
|
|
8590
|
+
const orderedCandidateNodes = strategy === "first_eligible" ? candidateNodes : orderEligibleNodes(
|
|
8591
|
+
meshId,
|
|
8592
|
+
strategy,
|
|
8593
|
+
candidateNodes.map((node, index) => ({ nodeId: readMeshNodeId(node), node, index })).filter((c) => c.nodeId),
|
|
8594
|
+
{ bumpCursor: true }
|
|
8595
|
+
).map((c) => c.node);
|
|
8596
|
+
for (const node of orderedCandidateNodes) {
|
|
8426
8597
|
const nodeId = readMeshNodeId(node);
|
|
8427
8598
|
if (!nodeId) continue;
|
|
8428
8599
|
const launchKey = `${meshId}:${nodeId}`;
|
|
@@ -8549,6 +8720,8 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
8549
8720
|
noIdleMeshSessionAvailable: true
|
|
8550
8721
|
};
|
|
8551
8722
|
}
|
|
8723
|
+
const strategy = resolveSchedulingStrategy(mesh);
|
|
8724
|
+
const localCandidates = [];
|
|
8552
8725
|
const cliInstances = components.instanceManager.getByCategory("cli");
|
|
8553
8726
|
for (const inst of cliInstances) {
|
|
8554
8727
|
const state = inst.getState();
|
|
@@ -8571,7 +8744,7 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
8571
8744
|
const providerType = state.type || readNonEmptyString2(settings.providerType);
|
|
8572
8745
|
if (providerType) {
|
|
8573
8746
|
localIdleSessionsChecked += 1;
|
|
8574
|
-
|
|
8747
|
+
localCandidates.push({ nodeId, sessionId, providerType, origin: "local", node: mesh.nodes.find((n) => readMeshNodeId(n) === nodeId) });
|
|
8575
8748
|
} else {
|
|
8576
8749
|
skippedSessions.push({
|
|
8577
8750
|
nodeId,
|
|
@@ -8585,18 +8758,49 @@ async function triggerMeshQueue(components, meshId) {
|
|
|
8585
8758
|
remoteSessions = MeshRuntimeStore.getInstance().getRemoteIdleSessions();
|
|
8586
8759
|
} catch {
|
|
8587
8760
|
}
|
|
8761
|
+
const remoteCandidates = [];
|
|
8588
8762
|
for (const idle of remoteSessions) {
|
|
8589
8763
|
const node = mesh.nodes.find((n) => n.id === idle.nodeId);
|
|
8590
8764
|
if (node) {
|
|
8591
8765
|
remoteIdleSessionsChecked += 1;
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8766
|
+
remoteCandidates.push({ nodeId: idle.nodeId, sessionId: idle.sessionId, providerType: idle.providerType, origin: "remote", node });
|
|
8767
|
+
}
|
|
8768
|
+
}
|
|
8769
|
+
const assignIdleCandidate = (candidate) => {
|
|
8770
|
+
const assigned = tryAssignQueueTask(components, meshId, candidate.nodeId, candidate.sessionId, candidate.providerType);
|
|
8771
|
+
if (assigned && candidate.origin === "remote") {
|
|
8772
|
+
try {
|
|
8773
|
+
MeshRuntimeStore.getInstance().deleteRemoteIdleSession(candidate.nodeId, candidate.sessionId);
|
|
8774
|
+
} catch {
|
|
8598
8775
|
}
|
|
8599
8776
|
}
|
|
8777
|
+
};
|
|
8778
|
+
if (strategy === "first_eligible") {
|
|
8779
|
+
for (const candidate of localCandidates) assignIdleCandidate(candidate);
|
|
8780
|
+
for (const candidate of remoteCandidates) assignIdleCandidate(candidate);
|
|
8781
|
+
} else {
|
|
8782
|
+
const pool = [...localCandidates, ...remoteCandidates];
|
|
8783
|
+
const baseIndex = /* @__PURE__ */ new Map();
|
|
8784
|
+
pool.forEach((c, i) => {
|
|
8785
|
+
if (!baseIndex.has(c.nodeId)) baseIndex.set(c.nodeId, i);
|
|
8786
|
+
});
|
|
8787
|
+
const uniqueNodes = [...new Set(pool.map((c) => c.nodeId))].map((nodeId, index) => ({ nodeId, node: pool.find((c) => c.nodeId === nodeId)?.node, index }));
|
|
8788
|
+
const ranked = orderEligibleNodes(meshId, strategy, uniqueNodes, { bumpCursor: true });
|
|
8789
|
+
const rankIndex = new Map(ranked.map((r, i) => [r.nodeId, i]));
|
|
8790
|
+
const remaining = [...pool];
|
|
8791
|
+
while (remaining.length > 0) {
|
|
8792
|
+
remaining.sort((a, b) => {
|
|
8793
|
+
const aPrio = resolveNodeSchedulingPriority(a.node?.policy);
|
|
8794
|
+
const bPrio = resolveNodeSchedulingPriority(b.node?.policy);
|
|
8795
|
+
if (aPrio !== bPrio) return bPrio - aPrio;
|
|
8796
|
+
if (strategy === "least_loaded" || strategy === "round_robin") {
|
|
8797
|
+
const loadDelta = nodeActiveLoad(meshId, a.nodeId) - nodeActiveLoad(meshId, b.nodeId);
|
|
8798
|
+
if (loadDelta !== 0) return loadDelta;
|
|
8799
|
+
}
|
|
8800
|
+
return (rankIndex.get(a.nodeId) ?? 0) - (rankIndex.get(b.nodeId) ?? 0);
|
|
8801
|
+
});
|
|
8802
|
+
assignIdleCandidate(remaining.shift());
|
|
8803
|
+
}
|
|
8600
8804
|
}
|
|
8601
8805
|
autoLaunchStarted = await maybeAutoLaunchOneQueueSession(components, meshId, mesh);
|
|
8602
8806
|
const afterQueue = getQueue(meshId);
|
|
@@ -10651,8 +10855,8 @@ var init_pty_transport = __esm({
|
|
|
10651
10855
|
let cwd = options.cwd;
|
|
10652
10856
|
if (cwd) {
|
|
10653
10857
|
try {
|
|
10654
|
-
const
|
|
10655
|
-
const stat2 =
|
|
10858
|
+
const fs31 = __require("fs");
|
|
10859
|
+
const stat2 = fs31.statSync(cwd);
|
|
10656
10860
|
if (!stat2.isDirectory()) cwd = os11.homedir();
|
|
10657
10861
|
} catch {
|
|
10658
10862
|
cwd = os11.homedir();
|
|
@@ -10761,9 +10965,9 @@ function findBinary(name) {
|
|
|
10761
10965
|
for (const ext of exes) {
|
|
10762
10966
|
const fullPath = path17.join(p, trimmed + ext);
|
|
10763
10967
|
try {
|
|
10764
|
-
const
|
|
10765
|
-
if (
|
|
10766
|
-
const stat2 =
|
|
10968
|
+
const fs31 = __require("fs");
|
|
10969
|
+
if (fs31.existsSync(fullPath)) {
|
|
10970
|
+
const stat2 = fs31.statSync(fullPath);
|
|
10767
10971
|
if (stat2.isFile() && (isWin || stat2.mode & 73)) {
|
|
10768
10972
|
return fullPath;
|
|
10769
10973
|
}
|
|
@@ -10777,12 +10981,12 @@ function findBinary(name) {
|
|
|
10777
10981
|
function isScriptBinary(binaryPath) {
|
|
10778
10982
|
if (!path17.isAbsolute(binaryPath)) return false;
|
|
10779
10983
|
try {
|
|
10780
|
-
const
|
|
10781
|
-
const resolved =
|
|
10984
|
+
const fs31 = __require("fs");
|
|
10985
|
+
const resolved = fs31.realpathSync(binaryPath);
|
|
10782
10986
|
const head = Buffer.alloc(8);
|
|
10783
|
-
const fd =
|
|
10784
|
-
|
|
10785
|
-
|
|
10987
|
+
const fd = fs31.openSync(resolved, "r");
|
|
10988
|
+
fs31.readSync(fd, head, 0, 8, 0);
|
|
10989
|
+
fs31.closeSync(fd);
|
|
10786
10990
|
let i = 0;
|
|
10787
10991
|
if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
|
|
10788
10992
|
return head[i] === 35 && head[i + 1] === 33;
|
|
@@ -10793,12 +10997,12 @@ function isScriptBinary(binaryPath) {
|
|
|
10793
10997
|
function looksLikeMachOOrElf(filePath) {
|
|
10794
10998
|
if (!path17.isAbsolute(filePath)) return false;
|
|
10795
10999
|
try {
|
|
10796
|
-
const
|
|
10797
|
-
const resolved =
|
|
11000
|
+
const fs31 = __require("fs");
|
|
11001
|
+
const resolved = fs31.realpathSync(filePath);
|
|
10798
11002
|
const buf = Buffer.alloc(8);
|
|
10799
|
-
const fd =
|
|
10800
|
-
|
|
10801
|
-
|
|
11003
|
+
const fd = fs31.openSync(resolved, "r");
|
|
11004
|
+
fs31.readSync(fd, buf, 0, 8, 0);
|
|
11005
|
+
fs31.closeSync(fd);
|
|
10802
11006
|
let i = 0;
|
|
10803
11007
|
if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
|
|
10804
11008
|
const b = buf.subarray(i);
|
|
@@ -11972,7 +12176,7 @@ var init_cli_state_engine = __esm({
|
|
|
11972
12176
|
scheduleSettle() {
|
|
11973
12177
|
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
11974
12178
|
const epoch = this.responseEpoch;
|
|
11975
|
-
const
|
|
12179
|
+
const delay2 = Math.max(
|
|
11976
12180
|
this.timeouts.outputSettle,
|
|
11977
12181
|
this.submitPendingUntil > Date.now() ? this.submitPendingUntil - Date.now() + this.timeouts.outputSettle : 0
|
|
11978
12182
|
);
|
|
@@ -11980,7 +12184,7 @@ var init_cli_state_engine = __esm({
|
|
|
11980
12184
|
this.settleTimer = null;
|
|
11981
12185
|
if (epoch !== this.responseEpoch) return;
|
|
11982
12186
|
this.evaluateSettled(this.transport.getSnapshot());
|
|
11983
|
-
},
|
|
12187
|
+
}, delay2);
|
|
11984
12188
|
}
|
|
11985
12189
|
/** Called from sendMessage in transport once a turn scope is established. */
|
|
11986
12190
|
onTurnStarted(turnScope) {
|
|
@@ -17795,9 +17999,9 @@ function readString6(value) {
|
|
|
17795
17999
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
17796
18000
|
}
|
|
17797
18001
|
function summarizeMessage(message) {
|
|
17798
|
-
const
|
|
17799
|
-
const title =
|
|
17800
|
-
return { title: title || "(untitled task)", summary:
|
|
18002
|
+
const oneLine2 = message.replace(/\s+/g, " ").trim();
|
|
18003
|
+
const title = oneLine2.length > 96 ? `${oneLine2.slice(0, 93)}...` : oneLine2;
|
|
18004
|
+
return { title: title || "(untitled task)", summary: oneLine2 };
|
|
17801
18005
|
}
|
|
17802
18006
|
function elapsedSince(value, now) {
|
|
17803
18007
|
const started = value ? new Date(value).getTime() : Number.NaN;
|
|
@@ -20903,6 +21107,11 @@ function collapseReplayAssistantTurns(messages, historyBehavior) {
|
|
|
20903
21107
|
continue;
|
|
20904
21108
|
}
|
|
20905
21109
|
if (message.role === "assistant") {
|
|
21110
|
+
const isActivity = message.kind === "tool" || message.kind === "terminal" || message.kind === "thought";
|
|
21111
|
+
if (isActivity) {
|
|
21112
|
+
collapsed.push(message);
|
|
21113
|
+
continue;
|
|
21114
|
+
}
|
|
20906
21115
|
if (sawAssistantSinceLastUser) continue;
|
|
20907
21116
|
sawAssistantSinceLastUser = true;
|
|
20908
21117
|
collapsed.push(message);
|
|
@@ -26046,7 +26255,8 @@ function buildReadChatCommandResult(payload, args, h) {
|
|
|
26046
26255
|
const sessionIdHint = typeof args?.targetSessionId === "string" ? args.targetSessionId : typeof args?.sessionId === "string" ? args.sessionId : "";
|
|
26047
26256
|
const providerHint = typeof args?.cliType === "string" ? args.cliType : typeof args?.providerType === "string" ? args.providerType : typeof args?.agentType === "string" ? args.agentType : "";
|
|
26048
26257
|
const filteredMessages = h ? maybeHideCoordinatorPromptMessage(h, providerHint, sessionIdHint, messages) : messages;
|
|
26049
|
-
const
|
|
26258
|
+
const includeActivity = args?.includeActivity === true || args?.includeActivity === "true";
|
|
26259
|
+
const visibleMessages = includeActivity ? filteredMessages.filter((m) => isUserFacingChatMessage(m) || isActivityChatMessage(m)) : filterUserFacingChatMessages(filteredMessages);
|
|
26050
26260
|
const sync = buildFullTail(visibleMessages, normalizeReadChatTailLimit(args));
|
|
26051
26261
|
const hiddenMsgCount = Math.max(0, messages.length - visibleMessages.length);
|
|
26052
26262
|
const preservedPayloadFields = Object.fromEntries(Object.entries(payload).filter(([key]) => shouldPreserveReadChatPayloadField(key)));
|
|
@@ -28415,6 +28625,9 @@ function normalizeProviderScriptArgs(args, scriptName) {
|
|
|
28415
28625
|
}
|
|
28416
28626
|
function buildControlScriptResult(scriptName, payload) {
|
|
28417
28627
|
if (!payload || typeof payload !== "object") return {};
|
|
28628
|
+
if (payload.controlResult && typeof payload.controlResult === "object") {
|
|
28629
|
+
return { controlResult: payload.controlResult };
|
|
28630
|
+
}
|
|
28418
28631
|
const legacyListPayload = (() => {
|
|
28419
28632
|
if (Array.isArray(payload.options)) return payload;
|
|
28420
28633
|
if (/^listmodels$/i.test(scriptName) && Array.isArray(payload.models)) {
|
|
@@ -29277,7 +29490,7 @@ var DaemonCommandHandler = class {
|
|
|
29277
29490
|
return { success: false, error: "invalid type" };
|
|
29278
29491
|
}
|
|
29279
29492
|
const https = __require("https");
|
|
29280
|
-
const
|
|
29493
|
+
const fs31 = __require("fs");
|
|
29281
29494
|
const path41 = __require("path");
|
|
29282
29495
|
const crypto6 = __require("crypto");
|
|
29283
29496
|
const REGISTRY = "https://api.adhf.dev/api/v1/registry";
|
|
@@ -29321,7 +29534,7 @@ var DaemonCommandHandler = class {
|
|
|
29321
29534
|
if (!targetDir.startsWith(installRootResolved + path41.sep)) {
|
|
29322
29535
|
return { success: false, error: "install path escaped upstream root" };
|
|
29323
29536
|
}
|
|
29324
|
-
|
|
29537
|
+
fs31.mkdirSync(targetDir, { recursive: true });
|
|
29325
29538
|
let manifestProbe = {};
|
|
29326
29539
|
try {
|
|
29327
29540
|
manifestProbe = JSON.parse(manifestBody);
|
|
@@ -29346,7 +29559,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29346
29559
|
}
|
|
29347
29560
|
const targetFile = isV1 ? "provider.v1.json" : "provider.json";
|
|
29348
29561
|
const targetPath = path41.join(targetDir, targetFile);
|
|
29349
|
-
|
|
29562
|
+
fs31.writeFileSync(targetPath, manifestBody, "utf-8");
|
|
29350
29563
|
const manifestJson = JSON.parse(manifestBody);
|
|
29351
29564
|
const scriptFetch = await this.fetchProviderSources(
|
|
29352
29565
|
manifestJson,
|
|
@@ -29416,7 +29629,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29416
29629
|
const repo = source.repo;
|
|
29417
29630
|
const ref = source.ref;
|
|
29418
29631
|
const https = __require("https");
|
|
29419
|
-
const
|
|
29632
|
+
const fs31 = __require("fs");
|
|
29420
29633
|
const path41 = __require("path");
|
|
29421
29634
|
function fetchJson(url, timeoutMs) {
|
|
29422
29635
|
return new Promise((resolve24, reject) => {
|
|
@@ -29500,8 +29713,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29500
29713
|
const relInside = entry.path.startsWith(sharedDirRel + "/") ? entry.path.slice(sharedDirRel.length + 1) : entry.path;
|
|
29501
29714
|
const outPath = path41.resolve(path41.join(sharedTargetDir, relInside));
|
|
29502
29715
|
if (!outPath.startsWith(path41.resolve(sharedTargetDir) + path41.sep)) continue;
|
|
29503
|
-
|
|
29504
|
-
|
|
29716
|
+
fs31.mkdirSync(path41.dirname(outPath), { recursive: true });
|
|
29717
|
+
fs31.writeFileSync(outPath, body);
|
|
29505
29718
|
fetchedCount++;
|
|
29506
29719
|
} catch (e) {
|
|
29507
29720
|
errors.push(`fetch shared ${entry.path}: ${e?.message ?? e}`);
|
|
@@ -29539,8 +29752,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29539
29752
|
errors.push(`refusing to write outside targetDir: ${entry.path}`);
|
|
29540
29753
|
continue;
|
|
29541
29754
|
}
|
|
29542
|
-
|
|
29543
|
-
|
|
29755
|
+
fs31.mkdirSync(path41.dirname(outPath), { recursive: true });
|
|
29756
|
+
fs31.writeFileSync(outPath, body);
|
|
29544
29757
|
fetchedCount++;
|
|
29545
29758
|
} catch (e) {
|
|
29546
29759
|
errors.push(`fetch ${entry.path}: ${e?.message ?? e}`);
|
|
@@ -29568,7 +29781,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29568
29781
|
if (!["cli", "ide", "extension", "acp"].includes(category)) {
|
|
29569
29782
|
return { success: false, error: `unknown category: ${category}` };
|
|
29570
29783
|
}
|
|
29571
|
-
const
|
|
29784
|
+
const fs31 = __require("fs");
|
|
29572
29785
|
const path41 = __require("path");
|
|
29573
29786
|
try {
|
|
29574
29787
|
const installRoot = this.getUpstreamInstallRoot();
|
|
@@ -29577,10 +29790,10 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29577
29790
|
if (!targetDir.startsWith(installRootResolved + path41.sep)) {
|
|
29578
29791
|
return { success: false, error: "refusing to delete outside upstream root" };
|
|
29579
29792
|
}
|
|
29580
|
-
if (!
|
|
29793
|
+
if (!fs31.existsSync(targetDir)) {
|
|
29581
29794
|
return { success: false, error: "not installed" };
|
|
29582
29795
|
}
|
|
29583
|
-
|
|
29796
|
+
fs31.rmSync(targetDir, { recursive: true, force: true });
|
|
29584
29797
|
if (this._ctx.providerLoader) {
|
|
29585
29798
|
this._ctx.providerLoader.reload();
|
|
29586
29799
|
this._ctx.providerLoader.registerToDetector();
|
|
@@ -29596,28 +29809,28 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29596
29809
|
* the UI and by the update checker.
|
|
29597
29810
|
*/
|
|
29598
29811
|
handleListInstalledProviders(_args) {
|
|
29599
|
-
const
|
|
29812
|
+
const fs31 = __require("fs");
|
|
29600
29813
|
const path41 = __require("path");
|
|
29601
29814
|
const installRoot = this.getUpstreamInstallRoot();
|
|
29602
|
-
if (!
|
|
29815
|
+
if (!fs31.existsSync(installRoot)) return { success: true, providers: [] };
|
|
29603
29816
|
const CATEGORIES = ["cli", "ide", "extension", "acp"];
|
|
29604
29817
|
const items = [];
|
|
29605
29818
|
for (const category of CATEGORIES) {
|
|
29606
29819
|
const categoryDir = path41.join(installRoot, category);
|
|
29607
|
-
if (!
|
|
29820
|
+
if (!fs31.existsSync(categoryDir)) continue;
|
|
29608
29821
|
let entries;
|
|
29609
29822
|
try {
|
|
29610
|
-
entries =
|
|
29823
|
+
entries = fs31.readdirSync(categoryDir);
|
|
29611
29824
|
} catch {
|
|
29612
29825
|
continue;
|
|
29613
29826
|
}
|
|
29614
29827
|
for (const type of entries) {
|
|
29615
29828
|
const v1Path = path41.join(categoryDir, type, "provider.v1.json");
|
|
29616
29829
|
const v0Path = path41.join(categoryDir, type, "provider.json");
|
|
29617
|
-
const manifestPath =
|
|
29830
|
+
const manifestPath = fs31.existsSync(v1Path) ? v1Path : fs31.existsSync(v0Path) ? v0Path : null;
|
|
29618
29831
|
if (!manifestPath) continue;
|
|
29619
29832
|
try {
|
|
29620
|
-
const m = JSON.parse(
|
|
29833
|
+
const m = JSON.parse(fs31.readFileSync(manifestPath, "utf-8"));
|
|
29621
29834
|
items.push({
|
|
29622
29835
|
type,
|
|
29623
29836
|
category,
|
|
@@ -29728,7 +29941,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29728
29941
|
if (!/^@[a-z0-9_-]+$/i.test(requestedName)) {
|
|
29729
29942
|
return { success: false, error: "name must match @[a-z0-9_-]+" };
|
|
29730
29943
|
}
|
|
29731
|
-
const
|
|
29944
|
+
const fs31 = __require("fs");
|
|
29732
29945
|
const path41 = __require("path");
|
|
29733
29946
|
const { spawnSync: spawnSync2 } = __require("child_process");
|
|
29734
29947
|
const file = ext.loadExternalSources();
|
|
@@ -29739,8 +29952,8 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29739
29952
|
return { success: false, error: `source url+ref already registered (use a different name to track another ref)` };
|
|
29740
29953
|
}
|
|
29741
29954
|
const sourceDir = path41.join(ext.externalRoot(), requestedName);
|
|
29742
|
-
if (!
|
|
29743
|
-
if (
|
|
29955
|
+
if (!fs31.existsSync(ext.externalRoot())) fs31.mkdirSync(ext.externalRoot(), { recursive: true });
|
|
29956
|
+
if (fs31.existsSync(sourceDir)) {
|
|
29744
29957
|
return { success: false, error: `directory already exists: ${sourceDir} (rename or remove first)` };
|
|
29745
29958
|
}
|
|
29746
29959
|
const clone = spawnSync2("git", ["clone", "--depth=1", "--branch", ref, "--", url, sourceDir], {
|
|
@@ -29750,7 +29963,7 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29750
29963
|
});
|
|
29751
29964
|
if (clone.status !== 0) {
|
|
29752
29965
|
try {
|
|
29753
|
-
|
|
29966
|
+
fs31.rmSync(sourceDir, { recursive: true, force: true });
|
|
29754
29967
|
} catch {
|
|
29755
29968
|
}
|
|
29756
29969
|
return { success: false, error: `git clone failed: ${(clone.stderr || clone.stdout || "").trim() || "unknown error"}` };
|
|
@@ -29794,15 +30007,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
|
|
|
29794
30007
|
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
29795
30008
|
if (!name) return { success: false, error: "name is required" };
|
|
29796
30009
|
const ext = (init_external_sources(), __toCommonJS(external_sources_exports));
|
|
29797
|
-
const
|
|
30010
|
+
const fs31 = __require("fs");
|
|
29798
30011
|
const path41 = __require("path");
|
|
29799
30012
|
const file = ext.loadExternalSources();
|
|
29800
30013
|
const match = file.sources.find((s) => s.name === name);
|
|
29801
30014
|
if (!match) return { success: false, error: `source "${name}" not registered` };
|
|
29802
30015
|
const sourceDir = path41.join(ext.externalRoot(), name);
|
|
29803
|
-
if (
|
|
30016
|
+
if (fs31.existsSync(sourceDir)) {
|
|
29804
30017
|
try {
|
|
29805
|
-
|
|
30018
|
+
fs31.rmSync(sourceDir, { recursive: true, force: true });
|
|
29806
30019
|
} catch (e) {
|
|
29807
30020
|
return { success: false, error: `failed to delete ${sourceDir}: ${e?.message || e}` };
|
|
29808
30021
|
}
|
|
@@ -30265,12 +30478,12 @@ var FsmDriver = class {
|
|
|
30265
30478
|
scheduleSpawnPrime() {
|
|
30266
30479
|
const seqs = this.spec.send_on_spawn;
|
|
30267
30480
|
if (!Array.isArray(seqs) || seqs.length === 0) return;
|
|
30268
|
-
const
|
|
30481
|
+
const delay2 = Math.max(0, this.spec.send_on_spawn_delay_ms ?? 250);
|
|
30269
30482
|
setTimeout(() => {
|
|
30270
30483
|
for (const seq of seqs) {
|
|
30271
30484
|
if (typeof seq === "string" && seq.length > 0) this.adapter.send_keys(seq);
|
|
30272
30485
|
}
|
|
30273
|
-
},
|
|
30486
|
+
}, delay2);
|
|
30274
30487
|
}
|
|
30275
30488
|
dispatch(cmd) {
|
|
30276
30489
|
switch (cmd.kind) {
|
|
@@ -30636,11 +30849,11 @@ var FsmDriver = class {
|
|
|
30636
30849
|
const armed = this.delegateTimers.has(d.id);
|
|
30637
30850
|
const shouldFire = d.when_state === currentStateId;
|
|
30638
30851
|
if (shouldFire && !armed) {
|
|
30639
|
-
const
|
|
30852
|
+
const delay2 = d.after_duration_ms ?? 0;
|
|
30640
30853
|
const t = setTimeout(() => {
|
|
30641
30854
|
this.fireDelegate(d);
|
|
30642
30855
|
this.delegateTimers.delete(d.id);
|
|
30643
|
-
},
|
|
30856
|
+
}, delay2);
|
|
30644
30857
|
this.delegateTimers.set(d.id, t);
|
|
30645
30858
|
} else if (!shouldFire && armed) {
|
|
30646
30859
|
clearTimeout(this.delegateTimers.get(d.id));
|
|
@@ -30694,7 +30907,15 @@ var FsmDriver = class {
|
|
|
30694
30907
|
this.adapter.send_keys(a.keys);
|
|
30695
30908
|
return;
|
|
30696
30909
|
case "open_picker":
|
|
30697
|
-
|
|
30910
|
+
{
|
|
30911
|
+
const m = /^([\s\S]*?)([\r\n]+)$/.exec(a.trigger_keys);
|
|
30912
|
+
if (m && m[1]) {
|
|
30913
|
+
this.adapter.send_keys(m[1]);
|
|
30914
|
+
setTimeout(() => this.adapter.send_keys(m[2]), 200);
|
|
30915
|
+
} else {
|
|
30916
|
+
this.adapter.send_keys(a.trigger_keys);
|
|
30917
|
+
}
|
|
30918
|
+
}
|
|
30698
30919
|
this.pickerInProgress = { control_id: ctl.id, spec: ctl };
|
|
30699
30920
|
return;
|
|
30700
30921
|
case "attach_image": {
|
|
@@ -30879,8 +31100,7 @@ function executeJsonl(src, input) {
|
|
|
30879
31100
|
for (let i = 0; i < lines.length; i += 1) {
|
|
30880
31101
|
const rec = lines[i];
|
|
30881
31102
|
if (filter && !filter(rec)) continue;
|
|
30882
|
-
const msg
|
|
30883
|
-
if (msg) {
|
|
31103
|
+
for (const msg of projectMessages(rec, src.message_map, i, lines.length, mtime)) {
|
|
30884
31104
|
if (transcriptWorkspace) msg.workspace = transcriptWorkspace;
|
|
30885
31105
|
messages.push(msg);
|
|
30886
31106
|
}
|
|
@@ -30960,8 +31180,9 @@ function executeSqlite(src, input) {
|
|
|
30960
31180
|
const mtime = safeMtimeMs(resolved);
|
|
30961
31181
|
const messages = [];
|
|
30962
31182
|
for (let i = 0; i < messageRows.length; i += 1) {
|
|
30963
|
-
const msg
|
|
30964
|
-
|
|
31183
|
+
for (const msg of projectMessages(messageRows[i], src.message_map, i, messageRows.length, mtime)) {
|
|
31184
|
+
messages.push(msg);
|
|
31185
|
+
}
|
|
30965
31186
|
}
|
|
30966
31187
|
if (messages.length === 0) return null;
|
|
30967
31188
|
return {
|
|
@@ -31359,11 +31580,42 @@ function jsonPathGet(record, expr) {
|
|
|
31359
31580
|
}
|
|
31360
31581
|
return cur;
|
|
31361
31582
|
}
|
|
31362
|
-
function
|
|
31583
|
+
function projectMessages(record, map, index, total, sourceMtimeMs) {
|
|
31363
31584
|
const roleRaw = jsonPathGet(record, map.role);
|
|
31364
|
-
const contentRaw = jsonPathGet(record, map.content);
|
|
31365
31585
|
const role = normalizeRole(roleRaw);
|
|
31366
|
-
let
|
|
31586
|
+
let receivedAt = sourceMtimeMs - (total - 1 - index) * 1e3;
|
|
31587
|
+
if (map.timestamp_ms) {
|
|
31588
|
+
const tsRaw = jsonPathGet(record, map.timestamp_ms);
|
|
31589
|
+
const parsed = parseTimestamp(tsRaw);
|
|
31590
|
+
if (parsed != null) receivedAt = parsed;
|
|
31591
|
+
}
|
|
31592
|
+
const kindRaw = map.kind ? jsonPathGet(record, map.kind) : void 0;
|
|
31593
|
+
const kind = typeof kindRaw === "string" && kindRaw ? kindRaw : "standard";
|
|
31594
|
+
const out = [];
|
|
31595
|
+
if (map.tools) {
|
|
31596
|
+
const recordTool = projectToolBlock(record, role, map.tools);
|
|
31597
|
+
if (recordTool) {
|
|
31598
|
+
out.push({ ...recordTool, receivedAt });
|
|
31599
|
+
return out;
|
|
31600
|
+
}
|
|
31601
|
+
}
|
|
31602
|
+
const contentRaw = jsonPathGet(record, map.content);
|
|
31603
|
+
const content = cleanContent(stringifyContent(contentRaw), map);
|
|
31604
|
+
if (content) out.push({ role, content, receivedAt, kind });
|
|
31605
|
+
if (map.tools && Array.isArray(contentRaw)) {
|
|
31606
|
+
let nudge = 1;
|
|
31607
|
+
for (const block2 of contentRaw) {
|
|
31608
|
+
const tool = projectToolBlock(block2, role, map.tools);
|
|
31609
|
+
if (tool) {
|
|
31610
|
+
out.push({ ...tool, receivedAt: receivedAt + nudge });
|
|
31611
|
+
nudge += 1;
|
|
31612
|
+
}
|
|
31613
|
+
}
|
|
31614
|
+
}
|
|
31615
|
+
return out;
|
|
31616
|
+
}
|
|
31617
|
+
function cleanContent(input, map) {
|
|
31618
|
+
let content = input;
|
|
31367
31619
|
if (content && map.content_strip) {
|
|
31368
31620
|
for (const tag of map.content_strip) {
|
|
31369
31621
|
const safeTag = tag.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
@@ -31379,17 +31631,33 @@ function projectMessage(record, map, index, total, sourceMtimeMs) {
|
|
|
31379
31631
|
content = content.replace(open, "").replace(close, "");
|
|
31380
31632
|
}
|
|
31381
31633
|
}
|
|
31382
|
-
|
|
31383
|
-
|
|
31384
|
-
|
|
31385
|
-
|
|
31386
|
-
|
|
31387
|
-
|
|
31388
|
-
|
|
31634
|
+
return content ? content.trim() : "";
|
|
31635
|
+
}
|
|
31636
|
+
var DEFAULT_TOOL_CALL_TYPES = ["tool_use", "function_call", "custom_tool_call"];
|
|
31637
|
+
var DEFAULT_TOOL_RESULT_TYPES = ["tool_result", "function_call_output", "custom_tool_call_output"];
|
|
31638
|
+
function projectToolBlock(block2, role, tmap) {
|
|
31639
|
+
void role;
|
|
31640
|
+
if (block2 == null || typeof block2 !== "object") return null;
|
|
31641
|
+
const typeVal = String(jsonPathGet(block2, tmap.block_type || "$.type") ?? "");
|
|
31642
|
+
if (!typeVal) return null;
|
|
31643
|
+
const callTypes = tmap.call_types ?? DEFAULT_TOOL_CALL_TYPES;
|
|
31644
|
+
const resultTypes = tmap.result_types ?? DEFAULT_TOOL_RESULT_TYPES;
|
|
31645
|
+
if (callTypes.includes(typeVal)) {
|
|
31646
|
+
const name = String(jsonPathGet(block2, tmap.call_name || "$.name") ?? "tool").trim() || "tool";
|
|
31647
|
+
const args = oneLine(stringifyContent(jsonPathGet(block2, tmap.call_args || "$.input")), 240);
|
|
31648
|
+
const content = args ? `\u2197 ${name}: ${args}` : `\u2197 ${name}`;
|
|
31649
|
+
return { role: "assistant", content, receivedAt: 0, kind: "tool" };
|
|
31650
|
+
}
|
|
31651
|
+
if (resultTypes.includes(typeVal)) {
|
|
31652
|
+
const result = oneLine(stringifyContent(jsonPathGet(block2, tmap.result_content || "$.content")), 600);
|
|
31653
|
+
if (!result) return null;
|
|
31654
|
+
return { role: "assistant", content: `\u2198 ${result}`, receivedAt: 0, kind: "tool" };
|
|
31389
31655
|
}
|
|
31390
|
-
|
|
31391
|
-
|
|
31392
|
-
|
|
31656
|
+
return null;
|
|
31657
|
+
}
|
|
31658
|
+
function oneLine(s, max) {
|
|
31659
|
+
const flat = s.replace(/\s+/g, " ").trim();
|
|
31660
|
+
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
31393
31661
|
}
|
|
31394
31662
|
function parseTimestamp(v) {
|
|
31395
31663
|
if (v == null) return null;
|
|
@@ -31530,6 +31798,9 @@ import * as fs13 from "fs";
|
|
|
31530
31798
|
function stripAnsi3(text) {
|
|
31531
31799
|
return String(text || "").replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "");
|
|
31532
31800
|
}
|
|
31801
|
+
function delay(ms) {
|
|
31802
|
+
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
31803
|
+
}
|
|
31533
31804
|
var SpecCliAdapter = class _SpecCliAdapter {
|
|
31534
31805
|
cliType;
|
|
31535
31806
|
cliName;
|
|
@@ -31751,9 +32022,15 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
31751
32022
|
* drives the dispatch:
|
|
31752
32023
|
*
|
|
31753
32024
|
* send_keys → click_control (e.g. stop)
|
|
31754
|
-
* open_picker →
|
|
31755
|
-
*
|
|
31756
|
-
*
|
|
32025
|
+
* open_picker → two roles, driven by the screen, not a hardcoded list:
|
|
32026
|
+
* - LIST (no choice arg): open the picker, wait for it
|
|
32027
|
+
* to render, parse the on-screen options via
|
|
32028
|
+
* `extract_choices`, and return them as
|
|
32029
|
+
* `controlResult.options` (+ `currentValue`). This is
|
|
32030
|
+
* how the dashboard's Model/Mode controls learn what is
|
|
32031
|
+
* actually selectable in this CLI right now.
|
|
32032
|
+
* - SELECT (args.choiceIndex / args.choiceLabel): drive
|
|
32033
|
+
* the picker to that option using `submit_key`.
|
|
31757
32034
|
* attach_image → attach_image dispatch; expects args.blob (data url
|
|
31758
32035
|
* or base64) and args.mime
|
|
31759
32036
|
*
|
|
@@ -31778,11 +32055,128 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
31778
32055
|
this.driver.dispatch({ kind: "attach_image", blob, mime });
|
|
31779
32056
|
return Promise.resolve({ ok: true, effects: [{ type: "attached_image", controlId: ctl.id }] });
|
|
31780
32057
|
}
|
|
32058
|
+
if (action.type === "open_picker") {
|
|
32059
|
+
const choiceIndex = typeof flat.choiceIndex === "number" ? flat.choiceIndex : typeof flat.choiceIndex === "string" && flat.choiceIndex.trim() ? Number(flat.choiceIndex) : void 0;
|
|
32060
|
+
const choiceLabel = typeof flat.choiceLabel === "string" ? flat.choiceLabel : typeof flat.choice === "string" ? flat.choice : void 0;
|
|
32061
|
+
if (typeof choiceIndex === "number" && Number.isFinite(choiceIndex) || choiceLabel && choiceLabel.trim()) {
|
|
32062
|
+
return this.selectPickerChoice(ctl, action, choiceIndex, choiceLabel);
|
|
32063
|
+
}
|
|
32064
|
+
return this.openPickerAndListChoices(ctl, action);
|
|
32065
|
+
}
|
|
31781
32066
|
this.driver.dispatch({ kind: "click_control", control_id: ctl.id, payload: flat });
|
|
31782
|
-
|
|
31783
|
-
|
|
31784
|
-
|
|
31785
|
-
|
|
32067
|
+
return Promise.resolve({ ok: true, effects: [{ type: "sent_keys", controlId: ctl.id }] });
|
|
32068
|
+
}
|
|
32069
|
+
/**
|
|
32070
|
+
* Open an `open_picker` control and return the options the CLI is showing,
|
|
32071
|
+
* parsed live from the screen via `extract_choices`. Nothing is selected —
|
|
32072
|
+
* the picker is left open so a follow-up SELECT invoke can commit a choice.
|
|
32073
|
+
*/
|
|
32074
|
+
async openPickerAndListChoices(ctl, action) {
|
|
32075
|
+
this.driver.dispatch({ kind: "click_control", control_id: ctl.id });
|
|
32076
|
+
const ready = await this.waitForPickerRendered(action);
|
|
32077
|
+
const options = this.extractPickerChoices(action);
|
|
32078
|
+
const currentValue = options.find((o) => o.current)?.label;
|
|
32079
|
+
return {
|
|
32080
|
+
ok: true,
|
|
32081
|
+
effects: [{ type: "opened_picker", controlId: ctl.id }],
|
|
32082
|
+
controlResult: {
|
|
32083
|
+
options: options.map((o) => ({ value: o.label, label: o.label, current: o.current })),
|
|
32084
|
+
...currentValue ? { currentValue } : {},
|
|
32085
|
+
source: "screen-parse",
|
|
32086
|
+
...ready ? {} : { warning: "picker_render_timeout" }
|
|
32087
|
+
}
|
|
32088
|
+
};
|
|
32089
|
+
}
|
|
32090
|
+
/**
|
|
32091
|
+
* Drive an already-listable picker to a specific option. The option can be
|
|
32092
|
+
* named (choiceLabel — matched against the parsed on-screen labels) or
|
|
32093
|
+
* positional (choiceIndex — the on-screen number). The actual keystrokes
|
|
32094
|
+
* come from the spec's `submit_key` with `{index}` substituted, so the spec
|
|
32095
|
+
* — not this code — decides how a selection is keyed for each CLI.
|
|
32096
|
+
*/
|
|
32097
|
+
async selectPickerChoice(ctl, action, choiceIndex, choiceLabel) {
|
|
32098
|
+
this.driver.dispatch({ kind: "click_control", control_id: ctl.id });
|
|
32099
|
+
await this.waitForPickerRendered(action);
|
|
32100
|
+
const options = this.extractPickerChoices(action);
|
|
32101
|
+
let index = choiceIndex;
|
|
32102
|
+
if ((index == null || !Number.isFinite(index)) && choiceLabel) {
|
|
32103
|
+
const needle = choiceLabel.trim().toLowerCase();
|
|
32104
|
+
const match = options.find((o) => o.label.toLowerCase().includes(needle));
|
|
32105
|
+
if (!match) {
|
|
32106
|
+
return { ok: false, error: `choice not found on screen: ${choiceLabel}`, controlResult: { options: options.map((o) => ({ value: o.label, label: o.label })) } };
|
|
32107
|
+
}
|
|
32108
|
+
index = match.index;
|
|
32109
|
+
}
|
|
32110
|
+
if (index == null || !Number.isFinite(index)) {
|
|
32111
|
+
return { ok: false, error: "choiceIndex or choiceLabel required to select" };
|
|
32112
|
+
}
|
|
32113
|
+
const keys = (action.submit_key || "{index}\r").replace(/\{index\}/g, String(index));
|
|
32114
|
+
this.driver.dispatch({ kind: "pty_write", data: keys });
|
|
32115
|
+
const selected = options.find((o) => o.index === index);
|
|
32116
|
+
return {
|
|
32117
|
+
ok: true,
|
|
32118
|
+
effects: [{ type: "selected_choice", controlId: ctl.id }],
|
|
32119
|
+
controlResult: {
|
|
32120
|
+
ok: true,
|
|
32121
|
+
...selected ? { currentValue: selected.label } : {},
|
|
32122
|
+
selectedIndex: index
|
|
32123
|
+
}
|
|
32124
|
+
};
|
|
32125
|
+
}
|
|
32126
|
+
/** Poll the live screen until the picker's `wait_for` condition matches,
|
|
32127
|
+
* up to a short budget. Returns true if it rendered, false on timeout. */
|
|
32128
|
+
async waitForPickerRendered(action) {
|
|
32129
|
+
const wf = action.wait_for;
|
|
32130
|
+
if (!wf?.regex) {
|
|
32131
|
+
await delay(250);
|
|
32132
|
+
return true;
|
|
32133
|
+
}
|
|
32134
|
+
const re = new RegExp(wf.regex, wf.flags ?? "i");
|
|
32135
|
+
const deadline = Date.now() + 2500;
|
|
32136
|
+
while (Date.now() < deadline) {
|
|
32137
|
+
await delay(120);
|
|
32138
|
+
const hay = this.readScreenSectionText(wf.section);
|
|
32139
|
+
if (re.test(hay)) return true;
|
|
32140
|
+
}
|
|
32141
|
+
return false;
|
|
32142
|
+
}
|
|
32143
|
+
/** Parse the picker's `extract_choices` pattern against the live screen.
|
|
32144
|
+
* Each match yields { index, label, current }. `current` is true for the
|
|
32145
|
+
* line the CLI marks with its cursor glyph (❯ ›). Purely screen-driven —
|
|
32146
|
+
* no model/mode names are baked in. */
|
|
32147
|
+
extractPickerChoices(action) {
|
|
32148
|
+
const ec = action.extract_choices;
|
|
32149
|
+
if (!ec?.pattern) return [];
|
|
32150
|
+
const text = this.readScreenSectionText(ec.section);
|
|
32151
|
+
const out = [];
|
|
32152
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32153
|
+
for (const rawLine of text.split("\n")) {
|
|
32154
|
+
const line = rawLine.replace(/\r$/, "");
|
|
32155
|
+
const m = new RegExp(ec.pattern, ec.flags ?? "").exec(line);
|
|
32156
|
+
if (!m) continue;
|
|
32157
|
+
const idx = Number(m[1]);
|
|
32158
|
+
if (!Number.isFinite(idx) || seen.has(idx)) continue;
|
|
32159
|
+
const label = (m[2] ?? "").replace(/\s+/g, " ").trim();
|
|
32160
|
+
if (!label) continue;
|
|
32161
|
+
const current = /^\s*[❯›>]/.test(line) || /[✔✓●]\s*$/.test(label);
|
|
32162
|
+
seen.add(idx);
|
|
32163
|
+
out.push({ index: idx, label, current });
|
|
32164
|
+
}
|
|
32165
|
+
return out;
|
|
32166
|
+
}
|
|
32167
|
+
/** Live text of a named screen section (or the whole screen when no
|
|
32168
|
+
* section is named), resolved from the driver's current sections. */
|
|
32169
|
+
readScreenSectionText(sectionId) {
|
|
32170
|
+
try {
|
|
32171
|
+
const sections = this.driver.getSections();
|
|
32172
|
+
if (sectionId && sections) {
|
|
32173
|
+
const hit = sections.find((s) => s.id === sectionId);
|
|
32174
|
+
if (hit) return hit.text;
|
|
32175
|
+
}
|
|
32176
|
+
return this.driver.getScreen();
|
|
32177
|
+
} catch {
|
|
32178
|
+
return "";
|
|
32179
|
+
}
|
|
31786
32180
|
}
|
|
31787
32181
|
getDebugSnapshot() {
|
|
31788
32182
|
let screen = "";
|
|
@@ -38738,7 +39132,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
38738
39132
|
}
|
|
38739
39133
|
if (providerDir) {
|
|
38740
39134
|
try {
|
|
38741
|
-
const
|
|
39135
|
+
const fs31 = __require("fs");
|
|
38742
39136
|
const path41 = __require("path");
|
|
38743
39137
|
const candidates = [];
|
|
38744
39138
|
if (Array.isArray(base.compatibility)) {
|
|
@@ -38750,13 +39144,13 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
38750
39144
|
}
|
|
38751
39145
|
candidates.push(path41.join(providerDir, "specs", "default.json"));
|
|
38752
39146
|
candidates.push(path41.join(providerDir, "spec.json"));
|
|
38753
|
-
const specPath = candidates.find((p) =>
|
|
39147
|
+
const specPath = candidates.find((p) => fs31.existsSync(p));
|
|
38754
39148
|
if (specPath) {
|
|
38755
39149
|
resolved._resolvedSpecPath = specPath;
|
|
38756
39150
|
let specControls;
|
|
38757
39151
|
let nh;
|
|
38758
39152
|
try {
|
|
38759
|
-
const rawSpec = JSON.parse(
|
|
39153
|
+
const rawSpec = JSON.parse(fs31.readFileSync(specPath, "utf8"));
|
|
38760
39154
|
specControls = rawSpec.control_bar;
|
|
38761
39155
|
nh = rawSpec.native_history;
|
|
38762
39156
|
} catch {
|
|
@@ -38781,7 +39175,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
38781
39175
|
reader = (input) => executeNativeHistory(nh, input);
|
|
38782
39176
|
} else if (nh.override_path) {
|
|
38783
39177
|
const overrideFile = path41.resolve(providerDir, nh.override_path);
|
|
38784
|
-
if (
|
|
39178
|
+
if (fs31.existsSync(overrideFile)) {
|
|
38785
39179
|
try {
|
|
38786
39180
|
registerProviderScriptRootSafely(path41.dirname(path41.dirname(providerDir)));
|
|
38787
39181
|
delete __require.cache[__require.resolve(overrideFile)];
|
|
@@ -39966,7 +40360,7 @@ async function detectCurrentWorkspace(ideId) {
|
|
|
39966
40360
|
}
|
|
39967
40361
|
} else if (plat === "win32") {
|
|
39968
40362
|
try {
|
|
39969
|
-
const
|
|
40363
|
+
const fs31 = __require("fs");
|
|
39970
40364
|
const appNameMap = getMacAppIdentifiers();
|
|
39971
40365
|
const appName = appNameMap[ideId];
|
|
39972
40366
|
if (appName) {
|
|
@@ -39975,8 +40369,8 @@ async function detectCurrentWorkspace(ideId) {
|
|
|
39975
40369
|
appName,
|
|
39976
40370
|
"storage.json"
|
|
39977
40371
|
);
|
|
39978
|
-
if (
|
|
39979
|
-
const data = JSON.parse(
|
|
40372
|
+
if (fs31.existsSync(storagePath)) {
|
|
40373
|
+
const data = JSON.parse(fs31.readFileSync(storagePath, "utf-8"));
|
|
39980
40374
|
const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
|
|
39981
40375
|
if (workspaces.length > 0) {
|
|
39982
40376
|
const recent = workspaces[0];
|
|
@@ -40308,6 +40702,210 @@ cleanOldFiles();
|
|
|
40308
40702
|
// src/commands/router.ts
|
|
40309
40703
|
init_logger();
|
|
40310
40704
|
import * as yaml3 from "js-yaml";
|
|
40705
|
+
|
|
40706
|
+
// src/logging/log-tail-reader.ts
|
|
40707
|
+
init_logger();
|
|
40708
|
+
import * as fs23 from "fs";
|
|
40709
|
+
var DEFAULT_TAIL_BYTES = 64 * 1024;
|
|
40710
|
+
var MAX_TAIL_BYTES = 128 * 1024;
|
|
40711
|
+
var READ_CHUNK_BYTES = 64 * 1024;
|
|
40712
|
+
function resolveLogPath(date) {
|
|
40713
|
+
if (date instanceof Date) return getCurrentDaemonLogPath(date);
|
|
40714
|
+
if (typeof date === "string" && date.trim()) {
|
|
40715
|
+
const parsed = /* @__PURE__ */ new Date(`${date.trim()}T00:00:00.000Z`);
|
|
40716
|
+
if (!Number.isNaN(parsed.getTime())) return getCurrentDaemonLogPath(parsed);
|
|
40717
|
+
}
|
|
40718
|
+
return getCurrentDaemonLogPath();
|
|
40719
|
+
}
|
|
40720
|
+
function clampTailBytes(tailBytes) {
|
|
40721
|
+
if (!Number.isFinite(tailBytes) || tailBytes <= 0) return DEFAULT_TAIL_BYTES;
|
|
40722
|
+
return Math.min(Math.floor(tailBytes), MAX_TAIL_BYTES);
|
|
40723
|
+
}
|
|
40724
|
+
function readByteBoundedTail(filePath, limitBytes) {
|
|
40725
|
+
const fd = fs23.openSync(filePath, "r");
|
|
40726
|
+
try {
|
|
40727
|
+
const stat2 = fs23.fstatSync(fd);
|
|
40728
|
+
const size = stat2.size;
|
|
40729
|
+
if (size === 0) return { text: "", truncated: false, bytesReturned: 0 };
|
|
40730
|
+
const want = Math.min(limitBytes, size);
|
|
40731
|
+
let start = size - want;
|
|
40732
|
+
const truncated = start > 0;
|
|
40733
|
+
const buffers = [];
|
|
40734
|
+
let position = start;
|
|
40735
|
+
while (position < size) {
|
|
40736
|
+
const chunkSize = Math.min(READ_CHUNK_BYTES, size - position);
|
|
40737
|
+
const chunk = Buffer.alloc(chunkSize);
|
|
40738
|
+
fs23.readSync(fd, chunk, 0, chunkSize, position);
|
|
40739
|
+
buffers.push(chunk);
|
|
40740
|
+
position += chunkSize;
|
|
40741
|
+
}
|
|
40742
|
+
let buf = Buffer.concat(buffers);
|
|
40743
|
+
if (truncated) {
|
|
40744
|
+
const firstNewline = buf.indexOf(10);
|
|
40745
|
+
if (firstNewline >= 0) {
|
|
40746
|
+
buf = buf.subarray(firstNewline + 1);
|
|
40747
|
+
}
|
|
40748
|
+
}
|
|
40749
|
+
return { text: buf.toString("utf-8"), truncated, bytesReturned: buf.length };
|
|
40750
|
+
} finally {
|
|
40751
|
+
fs23.closeSync(fd);
|
|
40752
|
+
}
|
|
40753
|
+
}
|
|
40754
|
+
function parseLineEpochMs(line, fileDate) {
|
|
40755
|
+
const m = line.match(/^\[(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?\]/);
|
|
40756
|
+
if (!m) {
|
|
40757
|
+
const iso = line.match(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?/);
|
|
40758
|
+
if (iso) {
|
|
40759
|
+
const t = Date.parse(iso[0].replace(" ", "T"));
|
|
40760
|
+
return Number.isNaN(t) ? null : t;
|
|
40761
|
+
}
|
|
40762
|
+
return null;
|
|
40763
|
+
}
|
|
40764
|
+
const d = new Date(fileDate);
|
|
40765
|
+
d.setHours(Number(m[1]), Number(m[2]), Number(m[3]), m[4] ? Number(m[4].padEnd(3, "0")) : 0);
|
|
40766
|
+
return d.getTime();
|
|
40767
|
+
}
|
|
40768
|
+
function readDaemonLogTail(args = {}) {
|
|
40769
|
+
const platform10 = process.platform;
|
|
40770
|
+
const limitBytes = clampTailBytes(args.tailBytes);
|
|
40771
|
+
let logPath = resolveLogPath(args.date);
|
|
40772
|
+
if (!fs23.existsSync(logPath)) {
|
|
40773
|
+
const backup = logPath.replace(/\.log$/, ".1.log");
|
|
40774
|
+
if (fs23.existsSync(backup)) {
|
|
40775
|
+
logPath = backup;
|
|
40776
|
+
} else {
|
|
40777
|
+
return {
|
|
40778
|
+
success: false,
|
|
40779
|
+
error: `No daemon log file at ${logPath} (dir: ${getDaemonLogDir()})`,
|
|
40780
|
+
lines: [],
|
|
40781
|
+
truncated: false,
|
|
40782
|
+
logPath,
|
|
40783
|
+
platform: platform10,
|
|
40784
|
+
bytesReturned: 0,
|
|
40785
|
+
filtered: false
|
|
40786
|
+
};
|
|
40787
|
+
}
|
|
40788
|
+
}
|
|
40789
|
+
let raw;
|
|
40790
|
+
try {
|
|
40791
|
+
raw = readByteBoundedTail(logPath, limitBytes);
|
|
40792
|
+
} catch (e) {
|
|
40793
|
+
return {
|
|
40794
|
+
success: false,
|
|
40795
|
+
error: `Failed to read ${logPath}: ${e?.message ?? String(e)}`,
|
|
40796
|
+
lines: [],
|
|
40797
|
+
truncated: false,
|
|
40798
|
+
logPath,
|
|
40799
|
+
platform: platform10,
|
|
40800
|
+
bytesReturned: 0,
|
|
40801
|
+
filtered: false
|
|
40802
|
+
};
|
|
40803
|
+
}
|
|
40804
|
+
let lines = raw.text.split("\n");
|
|
40805
|
+
if (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
40806
|
+
const rawCount = lines.length;
|
|
40807
|
+
if (Number.isFinite(args.sinceMs)) {
|
|
40808
|
+
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();
|
|
40809
|
+
const floor = args.sinceMs;
|
|
40810
|
+
lines = lines.filter((line) => {
|
|
40811
|
+
const ts2 = parseLineEpochMs(line, fileDate);
|
|
40812
|
+
return ts2 === null || ts2 >= floor;
|
|
40813
|
+
});
|
|
40814
|
+
}
|
|
40815
|
+
let appliedGrep;
|
|
40816
|
+
if (typeof args.grep === "string" && args.grep.trim()) {
|
|
40817
|
+
appliedGrep = args.grep.trim();
|
|
40818
|
+
let re = null;
|
|
40819
|
+
try {
|
|
40820
|
+
re = new RegExp(appliedGrep, "i");
|
|
40821
|
+
} catch {
|
|
40822
|
+
re = null;
|
|
40823
|
+
}
|
|
40824
|
+
if (re) {
|
|
40825
|
+
const compiled = re;
|
|
40826
|
+
lines = lines.filter((line) => compiled.test(line));
|
|
40827
|
+
} else {
|
|
40828
|
+
const needle = appliedGrep.toLowerCase();
|
|
40829
|
+
lines = lines.filter((line) => line.toLowerCase().includes(needle));
|
|
40830
|
+
}
|
|
40831
|
+
}
|
|
40832
|
+
return {
|
|
40833
|
+
success: true,
|
|
40834
|
+
lines,
|
|
40835
|
+
truncated: raw.truncated,
|
|
40836
|
+
logPath,
|
|
40837
|
+
platform: platform10,
|
|
40838
|
+
bytesReturned: raw.bytesReturned,
|
|
40839
|
+
filtered: lines.length !== rawCount,
|
|
40840
|
+
...appliedGrep ? { grep: appliedGrep } : {}
|
|
40841
|
+
};
|
|
40842
|
+
}
|
|
40843
|
+
|
|
40844
|
+
// src/logging/log-redactor.ts
|
|
40845
|
+
var MASK = "\u2022\u2022\u2022\u2022redacted";
|
|
40846
|
+
function maskKeepTail(token) {
|
|
40847
|
+
if (token.length <= 8) return MASK;
|
|
40848
|
+
return `${MASK}${token.slice(-4)}`;
|
|
40849
|
+
}
|
|
40850
|
+
var RULES = [
|
|
40851
|
+
// `JWT_SECRET=...`, `TOKEN=...`, `API_KEY=...`, `password: ...` env/config dumps.
|
|
40852
|
+
// Captures the key + delimiter and masks only the value.
|
|
40853
|
+
{
|
|
40854
|
+
name: "key_value_secret",
|
|
40855
|
+
pattern: /\b([A-Z0-9_]*(?:SECRET|TOKEN|API[_-]?KEY|PASSWORD|PASSWD|PRIVATE[_-]?KEY|CREDENTIAL|CLIENT[_-]?SECRET)[A-Z0-9_]*)(\s*[:=]\s*)(["']?)([^\s"',;]+)\3/gi,
|
|
40856
|
+
replace: (_m, key, delim, quote) => `${key}${delim}${quote}${MASK}${quote}`
|
|
40857
|
+
},
|
|
40858
|
+
// Authorization: Bearer <token>
|
|
40859
|
+
{
|
|
40860
|
+
name: "bearer_token",
|
|
40861
|
+
pattern: /\b(Bearer\s+)([A-Za-z0-9._\-+/=]{8,})/g,
|
|
40862
|
+
replace: (_m, prefix, token) => `${prefix}${maskKeepTail(token)}`
|
|
40863
|
+
},
|
|
40864
|
+
// ADHDev credential prefixes: API key (adk_), machine secret (adm_), provider key (adp_).
|
|
40865
|
+
{
|
|
40866
|
+
name: "adhdev_prefixed_secret",
|
|
40867
|
+
pattern: /\b(ad[kmp]_)([A-Za-z0-9]{6,})/g,
|
|
40868
|
+
replace: (_m, prefix, token) => `${prefix}${maskKeepTail(prefix + token)}`
|
|
40869
|
+
},
|
|
40870
|
+
// JWT: three base64url segments separated by dots, header starts with eyJ.
|
|
40871
|
+
{
|
|
40872
|
+
name: "jwt",
|
|
40873
|
+
pattern: /\beyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}/g,
|
|
40874
|
+
replace: () => MASK
|
|
40875
|
+
},
|
|
40876
|
+
// TURN credential: a long credential value following a `credential` key in
|
|
40877
|
+
// any common shape — `credential: x`, `credential=x`, or `credential "x"`.
|
|
40878
|
+
// Mask the credential value only, preserving the key + delimiter/quote.
|
|
40879
|
+
{
|
|
40880
|
+
name: "turn_credential",
|
|
40881
|
+
pattern: /\b(credential["']?\s*(?:[:=]\s*)?["']?)([^\s"',;]{6,})/gi,
|
|
40882
|
+
replace: (_m, prefix) => `${prefix}${MASK}`
|
|
40883
|
+
},
|
|
40884
|
+
// TURN REST username:credential of the form `<expiry-ts>:<base64hmac>`,
|
|
40885
|
+
// where the hmac part is long base64. Mask the hmac.
|
|
40886
|
+
{
|
|
40887
|
+
name: "turn_rest_pair",
|
|
40888
|
+
pattern: /\b(\d{10,}:)([A-Za-z0-9+/]{20,}={0,2})\b/g,
|
|
40889
|
+
replace: (_m, prefix) => `${prefix}${MASK}`
|
|
40890
|
+
}
|
|
40891
|
+
];
|
|
40892
|
+
function redactLogLine(line) {
|
|
40893
|
+
if (!line) return line;
|
|
40894
|
+
let out = line;
|
|
40895
|
+
for (const rule of RULES) {
|
|
40896
|
+
try {
|
|
40897
|
+
out = out.replace(rule.pattern, rule.replace);
|
|
40898
|
+
} catch {
|
|
40899
|
+
}
|
|
40900
|
+
}
|
|
40901
|
+
return out;
|
|
40902
|
+
}
|
|
40903
|
+
function redactLogLines(lines) {
|
|
40904
|
+
return lines.map((line) => redactLogLine(line));
|
|
40905
|
+
}
|
|
40906
|
+
var LOG_REDACTION_RULE_NAMES = RULES.map((r) => r.name);
|
|
40907
|
+
|
|
40908
|
+
// src/commands/router.ts
|
|
40311
40909
|
init_mesh_coordinator();
|
|
40312
40910
|
init_mesh_events();
|
|
40313
40911
|
init_mesh_routing();
|
|
@@ -40404,7 +41002,7 @@ function orderMeshRefineBatchNodes(changeAreas) {
|
|
|
40404
41002
|
|
|
40405
41003
|
// src/mesh/preview-freshness.ts
|
|
40406
41004
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
40407
|
-
import { existsSync as
|
|
41005
|
+
import { existsSync as existsSync34, readFileSync as readFileSync25 } from "fs";
|
|
40408
41006
|
import { resolve as resolve19 } from "path";
|
|
40409
41007
|
var PREVIEW_DEPLOY_RECORD = ".adhdev/preview-deploy.json";
|
|
40410
41008
|
function runGit2(repoRoot, args) {
|
|
@@ -40421,7 +41019,7 @@ function runGit2(repoRoot, args) {
|
|
|
40421
41019
|
}
|
|
40422
41020
|
function readRecord6(repoRoot) {
|
|
40423
41021
|
const path41 = resolve19(repoRoot, PREVIEW_DEPLOY_RECORD);
|
|
40424
|
-
if (!
|
|
41022
|
+
if (!existsSync34(path41)) return null;
|
|
40425
41023
|
try {
|
|
40426
41024
|
const parsed = JSON.parse(readFileSync25(path41, "utf8"));
|
|
40427
41025
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
@@ -40488,7 +41086,7 @@ function buildPreviewFreshness(repoRoot) {
|
|
|
40488
41086
|
init_mesh_refine_status();
|
|
40489
41087
|
|
|
40490
41088
|
// src/mesh/mesh-init.ts
|
|
40491
|
-
import { existsSync as
|
|
41089
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync15, writeFileSync as writeFileSync17 } from "fs";
|
|
40492
41090
|
import { dirname as dirname7, join as join37 } from "path";
|
|
40493
41091
|
var MESH_INIT_REFINE_CONFIG_PATH = MESH_REFINE_CONFIG_LOCATIONS[0];
|
|
40494
41092
|
var MESH_INIT_WORKTREE_BOOTSTRAP_CONFIG_PATH = MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS[0];
|
|
@@ -40511,14 +41109,14 @@ function writeConfigFile(workspace, relativePath, config) {
|
|
|
40511
41109
|
}
|
|
40512
41110
|
function suggestMeshWorktreeBootstrapConfig(workspace) {
|
|
40513
41111
|
const commands = [];
|
|
40514
|
-
const hasPackageJson =
|
|
40515
|
-
const hasNpmLock =
|
|
41112
|
+
const hasPackageJson = existsSync35(join37(workspace, "package.json"));
|
|
41113
|
+
const hasNpmLock = existsSync35(join37(workspace, "package-lock.json"));
|
|
40516
41114
|
if (hasPackageJson) {
|
|
40517
41115
|
commands.push(
|
|
40518
41116
|
hasNpmLock ? { command: "npm", args: ["ci"] } : { command: "npm", args: ["install"] }
|
|
40519
41117
|
);
|
|
40520
41118
|
}
|
|
40521
|
-
const staleInputs = CANDIDATE_STALE_INPUTS.filter((relative5) =>
|
|
41119
|
+
const staleInputs = CANDIDATE_STALE_INPUTS.filter((relative5) => existsSync35(join37(workspace, relative5)));
|
|
40522
41120
|
if (!commands.length) {
|
|
40523
41121
|
return { commands, staleInputs };
|
|
40524
41122
|
}
|
|
@@ -40952,21 +41550,21 @@ init_build_info();
|
|
|
40952
41550
|
// src/commands/upgrade-helper.ts
|
|
40953
41551
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
40954
41552
|
import { spawn as spawn3 } from "child_process";
|
|
40955
|
-
import * as
|
|
41553
|
+
import * as fs24 from "fs";
|
|
40956
41554
|
import * as os27 from "os";
|
|
40957
41555
|
import * as path35 from "path";
|
|
40958
41556
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
40959
41557
|
function getUpgradeLogPath() {
|
|
40960
41558
|
const home = os27.homedir();
|
|
40961
41559
|
const dir = path35.join(home, ".adhdev");
|
|
40962
|
-
|
|
41560
|
+
fs24.mkdirSync(dir, { recursive: true });
|
|
40963
41561
|
return path35.join(dir, "daemon-upgrade.log");
|
|
40964
41562
|
}
|
|
40965
41563
|
function appendUpgradeLog(message) {
|
|
40966
41564
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
40967
41565
|
`;
|
|
40968
41566
|
try {
|
|
40969
|
-
|
|
41567
|
+
fs24.appendFileSync(getUpgradeLogPath(), line, "utf8");
|
|
40970
41568
|
} catch {
|
|
40971
41569
|
}
|
|
40972
41570
|
}
|
|
@@ -40974,12 +41572,12 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
40974
41572
|
const binDir = path35.dirname(nodeExecutable);
|
|
40975
41573
|
if (platform10 === "win32") {
|
|
40976
41574
|
const npmCliPath = path35.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
40977
|
-
if (
|
|
41575
|
+
if (fs24.existsSync(npmCliPath)) {
|
|
40978
41576
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
40979
41577
|
}
|
|
40980
41578
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
40981
41579
|
const candidatePath = path35.join(binDir, candidate);
|
|
40982
|
-
if (
|
|
41580
|
+
if (fs24.existsSync(candidatePath)) {
|
|
40983
41581
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
40984
41582
|
}
|
|
40985
41583
|
}
|
|
@@ -40987,7 +41585,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
40987
41585
|
}
|
|
40988
41586
|
for (const candidate of ["npm"]) {
|
|
40989
41587
|
const candidatePath = path35.join(binDir, candidate);
|
|
40990
|
-
if (
|
|
41588
|
+
if (fs24.existsSync(candidatePath)) {
|
|
40991
41589
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
40992
41590
|
}
|
|
40993
41591
|
}
|
|
@@ -40997,12 +41595,12 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
40997
41595
|
if (!currentCliPath) return null;
|
|
40998
41596
|
let resolvedPath = currentCliPath;
|
|
40999
41597
|
try {
|
|
41000
|
-
resolvedPath =
|
|
41598
|
+
resolvedPath = fs24.realpathSync.native(currentCliPath);
|
|
41001
41599
|
} catch {
|
|
41002
41600
|
}
|
|
41003
41601
|
let currentDir = resolvedPath;
|
|
41004
41602
|
try {
|
|
41005
|
-
if (
|
|
41603
|
+
if (fs24.statSync(resolvedPath).isFile()) {
|
|
41006
41604
|
currentDir = path35.dirname(resolvedPath);
|
|
41007
41605
|
}
|
|
41008
41606
|
} catch {
|
|
@@ -41011,8 +41609,8 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
41011
41609
|
while (true) {
|
|
41012
41610
|
const packageJsonPath = path35.join(currentDir, "package.json");
|
|
41013
41611
|
try {
|
|
41014
|
-
if (
|
|
41015
|
-
const parsed = JSON.parse(
|
|
41612
|
+
if (fs24.existsSync(packageJsonPath)) {
|
|
41613
|
+
const parsed = JSON.parse(fs24.readFileSync(packageJsonPath, "utf8"));
|
|
41016
41614
|
if (parsed?.name === packageName) {
|
|
41017
41615
|
const normalized = currentDir.replace(/\\/g, "/");
|
|
41018
41616
|
return normalized.includes("/node_modules/") ? currentDir : null;
|
|
@@ -41161,8 +41759,8 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
41161
41759
|
function stopSessionHostProcesses(appName) {
|
|
41162
41760
|
const pidFile = path35.join(os27.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
41163
41761
|
try {
|
|
41164
|
-
if (
|
|
41165
|
-
const pid = Number.parseInt(
|
|
41762
|
+
if (fs24.existsSync(pidFile)) {
|
|
41763
|
+
const pid = Number.parseInt(fs24.readFileSync(pidFile, "utf8").trim(), 10);
|
|
41166
41764
|
if (Number.isFinite(pid) && pid !== process.pid && isManagedSessionHostPid(pid)) {
|
|
41167
41765
|
killPid(pid);
|
|
41168
41766
|
}
|
|
@@ -41170,7 +41768,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
41170
41768
|
} catch {
|
|
41171
41769
|
} finally {
|
|
41172
41770
|
try {
|
|
41173
|
-
|
|
41771
|
+
fs24.unlinkSync(pidFile);
|
|
41174
41772
|
} catch {
|
|
41175
41773
|
}
|
|
41176
41774
|
}
|
|
@@ -41178,7 +41776,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
41178
41776
|
function removeDaemonPidFile() {
|
|
41179
41777
|
const pidFile = path35.join(os27.homedir(), ".adhdev", "daemon.pid");
|
|
41180
41778
|
try {
|
|
41181
|
-
|
|
41779
|
+
fs24.unlinkSync(pidFile);
|
|
41182
41780
|
} catch {
|
|
41183
41781
|
}
|
|
41184
41782
|
}
|
|
@@ -41196,23 +41794,23 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
41196
41794
|
if (pkgName.startsWith("@")) {
|
|
41197
41795
|
const [scope, name] = pkgName.split("/");
|
|
41198
41796
|
const scopeDir = path35.join(npmRoot, scope);
|
|
41199
|
-
if (!
|
|
41200
|
-
for (const entry of
|
|
41797
|
+
if (!fs24.existsSync(scopeDir)) return;
|
|
41798
|
+
for (const entry of fs24.readdirSync(scopeDir)) {
|
|
41201
41799
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
41202
|
-
|
|
41800
|
+
fs24.rmSync(path35.join(scopeDir, entry), { recursive: true, force: true });
|
|
41203
41801
|
appendUpgradeLog(`Removed stale scoped staging dir: ${path35.join(scopeDir, entry)}`);
|
|
41204
41802
|
}
|
|
41205
41803
|
} else {
|
|
41206
|
-
for (const entry of
|
|
41804
|
+
for (const entry of fs24.readdirSync(npmRoot)) {
|
|
41207
41805
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
41208
|
-
|
|
41806
|
+
fs24.rmSync(path35.join(npmRoot, entry), { recursive: true, force: true });
|
|
41209
41807
|
appendUpgradeLog(`Removed stale staging dir: ${path35.join(npmRoot, entry)}`);
|
|
41210
41808
|
}
|
|
41211
41809
|
}
|
|
41212
|
-
if (
|
|
41213
|
-
for (const entry of
|
|
41810
|
+
if (fs24.existsSync(binDir)) {
|
|
41811
|
+
for (const entry of fs24.readdirSync(binDir)) {
|
|
41214
41812
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
41215
|
-
|
|
41813
|
+
fs24.rmSync(path35.join(binDir, entry), { recursive: true, force: true });
|
|
41216
41814
|
appendUpgradeLog(`Removed stale bin staging entry: ${path35.join(binDir, entry)}`);
|
|
41217
41815
|
}
|
|
41218
41816
|
}
|
|
@@ -41303,7 +41901,7 @@ init_mesh_work_queue();
|
|
|
41303
41901
|
init_repo_mesh_types();
|
|
41304
41902
|
import { homedir as homedir26, hostname as osHostname } from "os";
|
|
41305
41903
|
import { basename as pathBasename, join as pathJoin, resolve as pathResolve2 } from "path";
|
|
41306
|
-
import * as
|
|
41904
|
+
import * as fs25 from "fs";
|
|
41307
41905
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
41308
41906
|
var CHANNEL_NPM_TAG = { stable: "latest", preview: "next" };
|
|
41309
41907
|
var CHANNEL_SERVER_URL = {
|
|
@@ -41629,6 +42227,12 @@ function inlineMeshCarriesTransientNodeTruth(inlineMesh) {
|
|
|
41629
42227
|
function readInlineMeshNodeId(node) {
|
|
41630
42228
|
return normalizeMeshNodeId(node) ?? "";
|
|
41631
42229
|
}
|
|
42230
|
+
function isDeadLocalWorktreeNode(node) {
|
|
42231
|
+
if (node?.isLocalWorktree !== true) return false;
|
|
42232
|
+
const workspace = readStringValue(node?.workspace);
|
|
42233
|
+
if (!workspace) return false;
|
|
42234
|
+
return !fs25.existsSync(workspace);
|
|
42235
|
+
}
|
|
41632
42236
|
function foldMeshNodeIdentityToCanonical(node) {
|
|
41633
42237
|
if (!node || typeof node !== "object" || Array.isArray(node)) return node;
|
|
41634
42238
|
const canonical = normalizeMeshNodeId(node);
|
|
@@ -41875,7 +42479,7 @@ function summarizeInlineMeshBranchConvergence(nodes) {
|
|
|
41875
42479
|
const followUps = nodes.filter((node) => {
|
|
41876
42480
|
if (readObjectRecord(node.branchConvergence).needsConvergence !== true) return false;
|
|
41877
42481
|
const workspace = typeof node.workspace === "string" ? node.workspace : "";
|
|
41878
|
-
if (workspace && !
|
|
42482
|
+
if (workspace && !fs25.existsSync(workspace)) return false;
|
|
41879
42483
|
return true;
|
|
41880
42484
|
}).map((node) => {
|
|
41881
42485
|
const convergence = readObjectRecord(node.branchConvergence);
|
|
@@ -42003,6 +42607,43 @@ function readMeshTimeoutEnvMs(name, defaultMs) {
|
|
|
42003
42607
|
}
|
|
42004
42608
|
var MESH_DIRECT_PROBE_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_TIMEOUT_MS", 25e3);
|
|
42005
42609
|
var MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS", 25e3);
|
|
42610
|
+
var MESH_DIRECT_PROBE_REUSE_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_REUSE_MS", 12e3);
|
|
42611
|
+
var MeshGitProbeCache = class {
|
|
42612
|
+
constructor(reuseMs, now = Date.now) {
|
|
42613
|
+
this.reuseMs = reuseMs;
|
|
42614
|
+
this.now = now;
|
|
42615
|
+
}
|
|
42616
|
+
inflight = /* @__PURE__ */ new Map();
|
|
42617
|
+
recent = /* @__PURE__ */ new Map();
|
|
42618
|
+
key(daemonId, workspace) {
|
|
42619
|
+
return `${daemonId}::${workspace}`;
|
|
42620
|
+
}
|
|
42621
|
+
/**
|
|
42622
|
+
* Run `probe` for this peer, but reuse a fresh recent result or an in-flight
|
|
42623
|
+
* probe for the same key when one is available. `probe` is only invoked when
|
|
42624
|
+
* neither gate is satisfied.
|
|
42625
|
+
*/
|
|
42626
|
+
async probe(daemonId, workspace, probe) {
|
|
42627
|
+
const key = this.key(daemonId, workspace);
|
|
42628
|
+
const cached2 = this.recent.get(key);
|
|
42629
|
+
if (cached2 && this.now() - cached2.at < this.reuseMs) {
|
|
42630
|
+
return cached2.value;
|
|
42631
|
+
}
|
|
42632
|
+
const existing = this.inflight.get(key);
|
|
42633
|
+
if (existing) return existing;
|
|
42634
|
+
const pending = (async () => {
|
|
42635
|
+
const result = await probe();
|
|
42636
|
+
if (result) this.recent.set(key, { at: this.now(), value: result });
|
|
42637
|
+
return result;
|
|
42638
|
+
})();
|
|
42639
|
+
this.inflight.set(key, pending);
|
|
42640
|
+
try {
|
|
42641
|
+
return await pending;
|
|
42642
|
+
} finally {
|
|
42643
|
+
if (this.inflight.get(key) === pending) this.inflight.delete(key);
|
|
42644
|
+
}
|
|
42645
|
+
}
|
|
42646
|
+
};
|
|
42006
42647
|
async function probeRemoteMeshGitStatus(args) {
|
|
42007
42648
|
if (!args.dispatchMeshCommand) return null;
|
|
42008
42649
|
const remoteResult = await Promise.race([
|
|
@@ -42046,7 +42687,8 @@ async function hydrateInlineMeshDirectTruth(args) {
|
|
|
42046
42687
|
peerAttemptedCount: 0,
|
|
42047
42688
|
peerConfirmedCount: 0,
|
|
42048
42689
|
standingEvidenceCount: 0,
|
|
42049
|
-
unavailableNodeIds: []
|
|
42690
|
+
unavailableNodeIds: [],
|
|
42691
|
+
deadNodeIds: []
|
|
42050
42692
|
};
|
|
42051
42693
|
}
|
|
42052
42694
|
const selectedCoordinatorNodeId = readStringValue(
|
|
@@ -42059,6 +42701,7 @@ async function hydrateInlineMeshDirectTruth(args) {
|
|
|
42059
42701
|
let peerConfirmedCount = 0;
|
|
42060
42702
|
let standingEvidenceCount = 0;
|
|
42061
42703
|
const unavailableNodeIds = [];
|
|
42704
|
+
const deadNodeIds = [];
|
|
42062
42705
|
for (const [nodeIndex, node] of nodes.entries()) {
|
|
42063
42706
|
const nodeId = normalizeMeshNodeId(node) || `node_${nodeIndex}`;
|
|
42064
42707
|
const workspace = readStringValue(node?.workspace);
|
|
@@ -42068,11 +42711,18 @@ async function hydrateInlineMeshDirectTruth(args) {
|
|
|
42068
42711
|
) || Boolean(
|
|
42069
42712
|
daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
|
|
42070
42713
|
) || Boolean(args.meshSource !== "local_config" && nodeIndex === 0);
|
|
42714
|
+
const isSelfDaemonNode = Boolean(
|
|
42715
|
+
daemonId && (daemonId === args.localMachineId || daemonId === args.statusInstanceId)
|
|
42716
|
+
);
|
|
42717
|
+
if ((isSelfNode || isSelfDaemonNode) && isDeadLocalWorktreeNode(node)) {
|
|
42718
|
+
deadNodeIds.push(nodeId);
|
|
42719
|
+
continue;
|
|
42720
|
+
}
|
|
42071
42721
|
if (!workspace) {
|
|
42072
42722
|
if (!isSelfNode && daemonId) unavailableNodeIds.push(nodeId);
|
|
42073
42723
|
continue;
|
|
42074
42724
|
}
|
|
42075
|
-
if (
|
|
42725
|
+
if (fs25.existsSync(workspace)) {
|
|
42076
42726
|
try {
|
|
42077
42727
|
const localGit = await getGitRepoStatus(workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
42078
42728
|
if (localGit?.isGitRepo) {
|
|
@@ -42096,7 +42746,7 @@ async function hydrateInlineMeshDirectTruth(args) {
|
|
|
42096
42746
|
continue;
|
|
42097
42747
|
}
|
|
42098
42748
|
peerAttemptedCount += 1;
|
|
42099
|
-
const
|
|
42749
|
+
const runProbe = () => probeRemoteMeshGitStatusWithRetry({
|
|
42100
42750
|
dispatchMeshCommand: args.dispatchMeshCommand,
|
|
42101
42751
|
daemonId,
|
|
42102
42752
|
workspace,
|
|
@@ -42104,6 +42754,7 @@ async function hydrateInlineMeshDirectTruth(args) {
|
|
|
42104
42754
|
retryTimeoutMs: MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS,
|
|
42105
42755
|
getConnection: args.getMeshPeerConnectionStatus
|
|
42106
42756
|
});
|
|
42757
|
+
const remoteGit = args.probeCache ? await args.probeCache.probe(daemonId, workspace, runProbe) : await runProbe();
|
|
42107
42758
|
if (remoteGit) {
|
|
42108
42759
|
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
42109
42760
|
peerConfirmedCount += 1;
|
|
@@ -42117,7 +42768,8 @@ async function hydrateInlineMeshDirectTruth(args) {
|
|
|
42117
42768
|
peerAttemptedCount,
|
|
42118
42769
|
peerConfirmedCount,
|
|
42119
42770
|
standingEvidenceCount,
|
|
42120
|
-
unavailableNodeIds
|
|
42771
|
+
unavailableNodeIds,
|
|
42772
|
+
deadNodeIds
|
|
42121
42773
|
};
|
|
42122
42774
|
}
|
|
42123
42775
|
function summarizeMeshSessionRecord(record) {
|
|
@@ -42176,7 +42828,7 @@ function readLiveMeshNodeWorkspace(args) {
|
|
|
42176
42828
|
}
|
|
42177
42829
|
function collectLiveMeshSessionRecords(args) {
|
|
42178
42830
|
const nodeWorkspace = readStringValue(args.node?.workspace);
|
|
42179
|
-
const nodeIsMissingLocalWorktree = args.node?.isLocalWorktree === true && !!nodeWorkspace && !
|
|
42831
|
+
const nodeIsMissingLocalWorktree = args.node?.isLocalWorktree === true && !!nodeWorkspace && !fs25.existsSync(nodeWorkspace);
|
|
42180
42832
|
const matches = args.liveSessionRecords.filter((record) => {
|
|
42181
42833
|
const recordNodeId = readStringValue(record?.meta?.meshNodeId);
|
|
42182
42834
|
if (recordNodeId && recordNodeId !== args.nodeId) return false;
|
|
@@ -42203,7 +42855,7 @@ function buildHistoricalMeshSessions(args) {
|
|
|
42203
42855
|
const workspace = readStringValue(node?.workspace);
|
|
42204
42856
|
if (nodeId) liveNodeIds.add(nodeId);
|
|
42205
42857
|
if (workspace) liveWorkspaces.add(workspace);
|
|
42206
|
-
if (nodeId && node?.isLocalWorktree === true && workspace && !
|
|
42858
|
+
if (nodeId && node?.isLocalWorktree === true && workspace && !fs25.existsSync(workspace)) {
|
|
42207
42859
|
missingLocalWorktreeNodeIds.add(nodeId);
|
|
42208
42860
|
}
|
|
42209
42861
|
}
|
|
@@ -42563,7 +43215,7 @@ function isSubmoduleFastForward(submoduleRepoPath, baseCommit, branchCommit) {
|
|
|
42563
43215
|
if (!baseCommit || !branchCommit) return false;
|
|
42564
43216
|
if (baseCommit === branchCommit) return true;
|
|
42565
43217
|
try {
|
|
42566
|
-
if (!
|
|
43218
|
+
if (!fs25.existsSync(submoduleRepoPath)) return false;
|
|
42567
43219
|
execFileSync6("git", ["cat-file", "-e", `${baseCommit}^{commit}`], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
42568
43220
|
execFileSync6("git", ["cat-file", "-e", `${branchCommit}^{commit}`], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
42569
43221
|
execFileSync6("git", ["merge-base", "--is-ancestor", baseCommit, branchCommit], { cwd: submoduleRepoPath, stdio: "ignore" });
|
|
@@ -42680,7 +43332,7 @@ function buildTreeWithGitlinksEqualized(repoRoot, commitish, paths, placeholderC
|
|
|
42680
43332
|
return newTree || void 0;
|
|
42681
43333
|
} finally {
|
|
42682
43334
|
try {
|
|
42683
|
-
|
|
43335
|
+
fs25.rmSync(tmpIndex, { force: true });
|
|
42684
43336
|
} catch {
|
|
42685
43337
|
}
|
|
42686
43338
|
}
|
|
@@ -42755,7 +43407,7 @@ function synthesizeTrivialFastForwardMergeTree(repoRoot, baseHead, branchHead, g
|
|
|
42755
43407
|
return newTree || void 0;
|
|
42756
43408
|
} finally {
|
|
42757
43409
|
try {
|
|
42758
|
-
|
|
43410
|
+
fs25.rmSync(tmpIndex, { force: true });
|
|
42759
43411
|
} catch {
|
|
42760
43412
|
}
|
|
42761
43413
|
}
|
|
@@ -42861,7 +43513,7 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
|
|
|
42861
43513
|
return { stdout: String(stdout || ""), stderr: String(stderr || ""), refspec };
|
|
42862
43514
|
};
|
|
42863
43515
|
const importCommitFromWorktreeSubmodule = async (submodulePath, worktreeSubmodulePath, commit) => {
|
|
42864
|
-
if (!
|
|
43516
|
+
if (!fs25.existsSync(worktreeSubmodulePath)) return false;
|
|
42865
43517
|
try {
|
|
42866
43518
|
await runGit3(worktreeSubmodulePath, ["cat-file", "-e", `${commit}^{commit}`]);
|
|
42867
43519
|
} catch {
|
|
@@ -42884,7 +43536,7 @@ async function runMeshRefineSubmoduleReachabilityGate(repoRoot, mergedTree, opti
|
|
|
42884
43536
|
reachable: false
|
|
42885
43537
|
};
|
|
42886
43538
|
try {
|
|
42887
|
-
if (!
|
|
43539
|
+
if (!fs25.existsSync(submodulePath)) {
|
|
42888
43540
|
entry.error = `Submodule checkout missing at ${gitlink.path}`;
|
|
42889
43541
|
entry.publishRequired = true;
|
|
42890
43542
|
if (options.allowAutoPublishSubmoduleMainCommits === true) {
|
|
@@ -43121,9 +43773,9 @@ async function runMeshRefineValidationGate(mesh, workspace, opts) {
|
|
|
43121
43773
|
return ["npm", "pnpm", "yarn", "bun"].includes(command) && candidate.args.some((arg) => arg === "run" || arg === "test" || arg === "exec");
|
|
43122
43774
|
};
|
|
43123
43775
|
const dependenciesLikelyMissing = (cwd) => {
|
|
43124
|
-
if (!
|
|
43125
|
-
if (
|
|
43126
|
-
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) =>
|
|
43776
|
+
if (!fs25.existsSync(pathJoin(cwd, "package.json"))) return false;
|
|
43777
|
+
if (fs25.existsSync(pathJoin(cwd, "node_modules"))) return false;
|
|
43778
|
+
return ["package-lock.json", "npm-shrinkwrap.json", "pnpm-lock.yaml", "yarn.lock", "bun.lockb", "bun.lock"].some((lock) => fs25.existsSync(pathJoin(cwd, lock)));
|
|
43127
43779
|
};
|
|
43128
43780
|
if (runLegacyBootstrapCommands) {
|
|
43129
43781
|
summary.bootstrap = { stage: "legacy" };
|
|
@@ -43225,9 +43877,9 @@ function resolveHermesUserHome() {
|
|
|
43225
43877
|
function loadHermesCoordinatorBaseConfig(targetConfigPath) {
|
|
43226
43878
|
const sourceHome = resolveHermesUserHome();
|
|
43227
43879
|
const sourceConfigPath = pathJoin(sourceHome, "config.yaml");
|
|
43228
|
-
if (!
|
|
43880
|
+
if (!fs25.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
43229
43881
|
if (pathResolve2(sourceConfigPath) === pathResolve2(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
43230
|
-
const parsed = parseMeshCoordinatorMcpConfig(
|
|
43882
|
+
const parsed = parseMeshCoordinatorMcpConfig(fs25.readFileSync(sourceConfigPath, "utf-8"), "hermes_config_yaml");
|
|
43231
43883
|
const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
|
|
43232
43884
|
return { config: baseConfig, sourceHome, sourceConfigPath };
|
|
43233
43885
|
}
|
|
@@ -43264,9 +43916,9 @@ function copyHermesCoordinatorCredentialFiles(sourceHome, targetHome) {
|
|
|
43264
43916
|
for (const fileName of [".env", "auth.json"]) {
|
|
43265
43917
|
const sourcePath = pathJoin(sourceHome, fileName);
|
|
43266
43918
|
const targetPath = pathJoin(targetHome, fileName);
|
|
43267
|
-
if (!
|
|
43919
|
+
if (!fs25.existsSync(sourcePath)) continue;
|
|
43268
43920
|
try {
|
|
43269
|
-
|
|
43921
|
+
fs25.copyFileSync(sourcePath, targetPath);
|
|
43270
43922
|
} catch (error) {
|
|
43271
43923
|
LOG.warn("MeshCoordinator", `Could not copy Hermes ${fileName} into isolated coordinator home: ${error?.message || error}`);
|
|
43272
43924
|
}
|
|
@@ -43424,8 +44076,21 @@ var DaemonCommandRouter = class {
|
|
|
43424
44076
|
* Allows the MCP server to query mesh data via get_mesh even when
|
|
43425
44077
|
* the mesh doesn't exist in the local meshes.json file. */
|
|
43426
44078
|
inlineMeshCache = /* @__PURE__ */ new Map();
|
|
44079
|
+
/** Tombstones for inline mesh nodes removed via remove_mesh_node, keyed by
|
|
44080
|
+
* meshId → set of removed nodeIds. The dashboard keeps echoing the removed
|
|
44081
|
+
* node in the inlineMesh it attaches to every command; without a tombstone,
|
|
44082
|
+
* reconcileInlineMeshCache MERGEs it straight back (resurrection). A
|
|
44083
|
+
* tombstoned node is skipped during reconcile only while its workspace is
|
|
44084
|
+
* absent from disk — a genuine re-registration (same nodeId, workspace back
|
|
44085
|
+
* on disk) clears the tombstone and merges normally, preserving clone
|
|
44086
|
+
* worktree visibility and legitimate node re-creation. */
|
|
44087
|
+
removedInlineMeshNodeIds = /* @__PURE__ */ new Map();
|
|
43427
44088
|
/** Coordinator-owned whole-mesh aggregate status snapshots. Browser callers read this by default. */
|
|
43428
44089
|
aggregateMeshStatusCache = /* @__PURE__ */ new Map();
|
|
44090
|
+
/** Shared per-peer git_status probe dedup + recently-probed reuse gate.
|
|
44091
|
+
* Spans separate mesh_status/get_mesh calls so the dashboard auto-retry
|
|
44092
|
+
* loop cannot storm a slow peer with back-to-back refreshUpstream probes. */
|
|
44093
|
+
meshGitProbeCache = new MeshGitProbeCache(MESH_DIRECT_PROBE_REUSE_MS);
|
|
43429
44094
|
/** In-memory async Refinery jobs keyed by meshId:nodeId to reject/return duplicate in-flight requests. */
|
|
43430
44095
|
runningRefineJobs = /* @__PURE__ */ new Map();
|
|
43431
44096
|
/** Terminal async Refinery jobs preserve a clear answer after the worktree node has been removed. */
|
|
@@ -43453,10 +44118,23 @@ var DaemonCommandRouter = class {
|
|
|
43453
44118
|
const unavailableNodeIds = /* @__PURE__ */ new Set();
|
|
43454
44119
|
const sourceOfTruth = readObjectRecord(snapshot.sourceOfTruth);
|
|
43455
44120
|
const directPeerTruth = readObjectRecord(sourceOfTruth.directPeerTruth);
|
|
44121
|
+
const deadNodeIds = /* @__PURE__ */ new Set();
|
|
44122
|
+
for (const node of mesh.nodes) {
|
|
44123
|
+
if (!isDeadLocalWorktreeNode(node)) continue;
|
|
44124
|
+
const deadId = readInlineMeshNodeId(node);
|
|
44125
|
+
if (deadId) deadNodeIds.add(deadId);
|
|
44126
|
+
}
|
|
44127
|
+
let droppedDeadUnavailable = false;
|
|
43456
44128
|
for (const entry of Array.isArray(directPeerTruth.unavailableNodeIds) ? directPeerTruth.unavailableNodeIds : []) {
|
|
43457
44129
|
const nodeId = readStringValue(entry);
|
|
43458
|
-
if (nodeId)
|
|
44130
|
+
if (!nodeId) continue;
|
|
44131
|
+
if (deadNodeIds.has(nodeId)) {
|
|
44132
|
+
droppedDeadUnavailable = true;
|
|
44133
|
+
continue;
|
|
44134
|
+
}
|
|
44135
|
+
unavailableNodeIds.add(nodeId);
|
|
43459
44136
|
}
|
|
44137
|
+
if (droppedDeadUnavailable) changed = true;
|
|
43460
44138
|
const nodes = snapshot.nodes.map((statusNode) => {
|
|
43461
44139
|
const nodeId = normalizeMeshNodeId(statusNode);
|
|
43462
44140
|
const inlineNode = nodeId ? inlineNodesById.get(nodeId) : void 0;
|
|
@@ -43571,7 +44249,10 @@ var DaemonCommandRouter = class {
|
|
|
43571
44249
|
}
|
|
43572
44250
|
warmInlineMeshCache(meshId, inlineMesh) {
|
|
43573
44251
|
if (!inlineMesh || typeof inlineMesh !== "object") return void 0;
|
|
43574
|
-
const sanitizedInlineMesh =
|
|
44252
|
+
const sanitizedInlineMesh = this.applyInlineMeshNodeTombstones(
|
|
44253
|
+
meshId,
|
|
44254
|
+
sanitizeInlineMesh(normalizeInlineMeshNodeIdentity(inlineMesh))
|
|
44255
|
+
);
|
|
43575
44256
|
const cached2 = this.inlineMeshCache.get(meshId);
|
|
43576
44257
|
if (cached2) {
|
|
43577
44258
|
const merged = reconcileInlineMeshCache(cached2, sanitizedInlineMesh);
|
|
@@ -43587,7 +44268,10 @@ var DaemonCommandRouter = class {
|
|
|
43587
44268
|
const cached3 = this.getCachedInlineMesh(meshId);
|
|
43588
44269
|
if (cached3) {
|
|
43589
44270
|
if (inlineMeshCarriesTransientNodeTruth(inlineMesh)) {
|
|
43590
|
-
const merged = reconcileInlineMeshCache(
|
|
44271
|
+
const merged = reconcileInlineMeshCache(
|
|
44272
|
+
cached3,
|
|
44273
|
+
this.applyInlineMeshNodeTombstones(meshId, inlineMesh)
|
|
44274
|
+
);
|
|
43591
44275
|
this.inlineMeshCache.set(meshId, sanitizeInlineMesh(normalizeInlineMeshNodeIdentity(merged)));
|
|
43592
44276
|
return { mesh: merged, inline: true, source: "inline_cache" };
|
|
43593
44277
|
}
|
|
@@ -43638,12 +44322,49 @@ var DaemonCommandRouter = class {
|
|
|
43638
44322
|
if (!mesh || !Array.isArray(mesh.nodes)) return false;
|
|
43639
44323
|
const idx = mesh.nodes.findIndex((entry) => meshNodeIdMatches(entry, nodeId));
|
|
43640
44324
|
if (idx === -1) return false;
|
|
44325
|
+
const canonicalNodeId = readInlineMeshNodeId(mesh.nodes[idx]) || nodeId;
|
|
43641
44326
|
mesh.nodes.splice(idx, 1);
|
|
43642
44327
|
mesh.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43643
44328
|
this.inlineMeshCache.set(meshId, mesh);
|
|
44329
|
+
this.tombstoneRemovedInlineMeshNode(meshId, canonicalNodeId);
|
|
44330
|
+
if (canonicalNodeId !== nodeId) this.tombstoneRemovedInlineMeshNode(meshId, nodeId);
|
|
43644
44331
|
this.invalidateAggregateMeshStatus(meshId);
|
|
43645
44332
|
return true;
|
|
43646
44333
|
}
|
|
44334
|
+
tombstoneRemovedInlineMeshNode(meshId, nodeId) {
|
|
44335
|
+
if (!nodeId) return;
|
|
44336
|
+
let set = this.removedInlineMeshNodeIds.get(meshId);
|
|
44337
|
+
if (!set) {
|
|
44338
|
+
set = /* @__PURE__ */ new Set();
|
|
44339
|
+
this.removedInlineMeshNodeIds.set(meshId, set);
|
|
44340
|
+
}
|
|
44341
|
+
set.add(nodeId);
|
|
44342
|
+
}
|
|
44343
|
+
/** Filter an incoming inline mesh against this mesh's tombstones before it is
|
|
44344
|
+
* reconciled into the cache. A tombstoned node is dropped only while its
|
|
44345
|
+
* workspace is still absent from disk; if the workspace is back (genuine
|
|
44346
|
+
* re-registration), the tombstone is cleared and the node merges normally. */
|
|
44347
|
+
applyInlineMeshNodeTombstones(meshId, incoming) {
|
|
44348
|
+
const tombstones = this.removedInlineMeshNodeIds.get(meshId);
|
|
44349
|
+
if (!tombstones?.size || !incoming || typeof incoming !== "object" || !Array.isArray(incoming.nodes)) {
|
|
44350
|
+
return incoming;
|
|
44351
|
+
}
|
|
44352
|
+
let dropped = false;
|
|
44353
|
+
const nodes = incoming.nodes.filter((node) => {
|
|
44354
|
+
const nodeId = readInlineMeshNodeId(node);
|
|
44355
|
+
if (!nodeId || !tombstones.has(nodeId)) return true;
|
|
44356
|
+
const workspace = readStringValue(node?.workspace);
|
|
44357
|
+
if (workspace && fs25.existsSync(workspace)) {
|
|
44358
|
+
tombstones.delete(nodeId);
|
|
44359
|
+
return true;
|
|
44360
|
+
}
|
|
44361
|
+
dropped = true;
|
|
44362
|
+
return false;
|
|
44363
|
+
});
|
|
44364
|
+
if (tombstones.size === 0) this.removedInlineMeshNodeIds.delete(meshId);
|
|
44365
|
+
if (!dropped) return incoming;
|
|
44366
|
+
return { ...incoming, nodes };
|
|
44367
|
+
}
|
|
43647
44368
|
normalizeMeshSessionCleanupMode(value) {
|
|
43648
44369
|
return value === "stop" || value === "delete_stopped" || value === "stop_and_delete" || value === "preserve" ? value : "preserve";
|
|
43649
44370
|
}
|
|
@@ -43666,13 +44387,13 @@ var DaemonCommandRouter = class {
|
|
|
43666
44387
|
recoveryHint: "Inspect the mesh node record before removing it, or remove stale metadata manually only after confirming no managed worktree remains."
|
|
43667
44388
|
};
|
|
43668
44389
|
}
|
|
43669
|
-
const worktreeExists =
|
|
44390
|
+
const worktreeExists = fs25.existsSync(workspace);
|
|
43670
44391
|
const sourceNode = args.node?.clonedFromNodeId ? args.mesh?.nodes?.find((n) => meshNodeIdMatches(n, args.node.clonedFromNodeId)) : args.mesh?.nodes?.find((n) => !n.isLocalWorktree);
|
|
43671
44392
|
const repoRoot = typeof sourceNode?.repoRoot === "string" && sourceNode.repoRoot.trim() ? sourceNode.repoRoot.trim() : typeof sourceNode?.workspace === "string" && sourceNode.workspace.trim() ? sourceNode.workspace.trim() : "";
|
|
43672
44393
|
if (!worktreeExists) {
|
|
43673
44394
|
return { success: true, skipped: true, removedPath: workspace, repoRoot: repoRoot || void 0, reason: "worktree_path_missing" };
|
|
43674
44395
|
}
|
|
43675
|
-
if (!repoRoot || !
|
|
44396
|
+
if (!repoRoot || !fs25.existsSync(repoRoot)) {
|
|
43676
44397
|
return {
|
|
43677
44398
|
success: false,
|
|
43678
44399
|
code: "mesh_worktree_cleanup_missing_source_repo",
|
|
@@ -43692,7 +44413,7 @@ var DaemonCommandRouter = class {
|
|
|
43692
44413
|
const normalizePath = (value) => {
|
|
43693
44414
|
const resolved = pathResolve2(value);
|
|
43694
44415
|
try {
|
|
43695
|
-
return
|
|
44416
|
+
return fs25.realpathSync(resolved);
|
|
43696
44417
|
} catch {
|
|
43697
44418
|
return resolved;
|
|
43698
44419
|
}
|
|
@@ -43778,7 +44499,7 @@ var DaemonCommandRouter = class {
|
|
|
43778
44499
|
};
|
|
43779
44500
|
} catch (deinitError) {
|
|
43780
44501
|
try {
|
|
43781
|
-
|
|
44502
|
+
fs25.rmSync(workspace, { recursive: true, force: true });
|
|
43782
44503
|
await execFileAsync4("git", ["worktree", "prune"], {
|
|
43783
44504
|
cwd: repoRoot,
|
|
43784
44505
|
encoding: "utf8",
|
|
@@ -45557,8 +46278,8 @@ ${hintLines.join("\n")}` : "",
|
|
|
45557
46278
|
if (sinceTs > 0) {
|
|
45558
46279
|
return { success: true, logs: [], totalBuffered: 0 };
|
|
45559
46280
|
}
|
|
45560
|
-
if (
|
|
45561
|
-
const content =
|
|
46281
|
+
if (fs25.existsSync(LOG_PATH)) {
|
|
46282
|
+
const content = fs25.readFileSync(LOG_PATH, "utf-8");
|
|
45562
46283
|
const allLines = content.split("\n");
|
|
45563
46284
|
const recent = allLines.slice(-count).join("\n");
|
|
45564
46285
|
return { success: true, logs: recent, totalLines: allLines.length };
|
|
@@ -46103,14 +46824,14 @@ ${hintLines.join("\n")}` : "",
|
|
|
46103
46824
|
// Settings page in the dashboard reads/writes via these two
|
|
46104
46825
|
// commands instead of going through fs from the browser.
|
|
46105
46826
|
case "list_coordinator_prompts": {
|
|
46106
|
-
const
|
|
46827
|
+
const fs31 = await import("fs");
|
|
46107
46828
|
const path41 = await import("path");
|
|
46108
46829
|
const os30 = await import("os");
|
|
46109
46830
|
const dir = path41.join(os30.homedir(), ".adhdev", "coordinator-prompts");
|
|
46110
46831
|
const entries = {};
|
|
46111
46832
|
try {
|
|
46112
|
-
if (
|
|
46113
|
-
for (const name of
|
|
46833
|
+
if (fs31.existsSync(dir)) {
|
|
46834
|
+
for (const name of fs31.readdirSync(dir)) {
|
|
46114
46835
|
const matchOverride = name.match(/^([a-zA-Z0-9_.-]+)\.md$/);
|
|
46115
46836
|
const matchAppend = name.match(/^([a-zA-Z0-9_.-]+)\.append\.md$/);
|
|
46116
46837
|
const m = matchAppend || matchOverride;
|
|
@@ -46120,7 +46841,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
46120
46841
|
const full = path41.join(dir, name);
|
|
46121
46842
|
let content = "";
|
|
46122
46843
|
try {
|
|
46123
|
-
content =
|
|
46844
|
+
content = fs31.readFileSync(full, "utf8");
|
|
46124
46845
|
} catch {
|
|
46125
46846
|
}
|
|
46126
46847
|
if (!entries[key]) entries[key] = { override: "", append: "" };
|
|
@@ -46134,7 +46855,7 @@ ${hintLines.join("\n")}` : "",
|
|
|
46134
46855
|
return { success: true, dir, entries };
|
|
46135
46856
|
}
|
|
46136
46857
|
case "write_coordinator_prompt": {
|
|
46137
|
-
const
|
|
46858
|
+
const fs31 = await import("fs");
|
|
46138
46859
|
const path41 = await import("path");
|
|
46139
46860
|
const os30 = await import("os");
|
|
46140
46861
|
const key = typeof args?.key === "string" ? args.key.trim() : "";
|
|
@@ -46147,11 +46868,11 @@ ${hintLines.join("\n")}` : "",
|
|
|
46147
46868
|
const filename = kind === "append" ? `${key}.append.md` : `${key}.md`;
|
|
46148
46869
|
const full = path41.join(dir, filename);
|
|
46149
46870
|
try {
|
|
46150
|
-
|
|
46871
|
+
fs31.mkdirSync(dir, { recursive: true });
|
|
46151
46872
|
if (content.trim()) {
|
|
46152
|
-
|
|
46153
|
-
} else if (
|
|
46154
|
-
|
|
46873
|
+
fs31.writeFileSync(full, content, { encoding: "utf8", mode: 384 });
|
|
46874
|
+
} else if (fs31.existsSync(full)) {
|
|
46875
|
+
fs31.unlinkSync(full);
|
|
46155
46876
|
}
|
|
46156
46877
|
return { success: true, path: full, kind, key };
|
|
46157
46878
|
} catch (error) {
|
|
@@ -46328,7 +47049,8 @@ ${hintLines.join("\n")}` : "",
|
|
|
46328
47049
|
getMeshPeerConnectionStatus: this.deps.getMeshPeerConnectionStatus,
|
|
46329
47050
|
statusInstanceId: this.deps.statusInstanceId,
|
|
46330
47051
|
localMachineId: loadConfig().machineId || "",
|
|
46331
|
-
probeRemotePeers
|
|
47052
|
+
probeRemotePeers,
|
|
47053
|
+
probeCache: this.meshGitProbeCache
|
|
46332
47054
|
});
|
|
46333
47055
|
const directTruthSatisfied = meshRecord.source !== "inline_bootstrap" || directTruth.directEvidenceCount > 0;
|
|
46334
47056
|
const sourceOfTruth = {
|
|
@@ -46928,10 +47650,75 @@ ${hintLines.join("\n")}` : "",
|
|
|
46928
47650
|
});
|
|
46929
47651
|
return result;
|
|
46930
47652
|
}
|
|
47653
|
+
case "get_mesh_node_logs": {
|
|
47654
|
+
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
47655
|
+
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
47656
|
+
let nodeDaemonId;
|
|
47657
|
+
if (meshId && nodeId) {
|
|
47658
|
+
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
47659
|
+
const node = meshRecord?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
47660
|
+
nodeDaemonId = typeof node?.daemonId === "string" ? node.daemonId.trim() : void 0;
|
|
47661
|
+
}
|
|
47662
|
+
const selfDaemonId = this.deps.statusInstanceId;
|
|
47663
|
+
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
|
|
47664
|
+
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
47665
|
+
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "get_mesh_node_logs", {
|
|
47666
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
47667
|
+
_meshDirectDispatch: true
|
|
47668
|
+
});
|
|
47669
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
47670
|
+
}
|
|
47671
|
+
const rawTailBytes = Number(args?.tailBytes);
|
|
47672
|
+
const tail = readDaemonLogTail({
|
|
47673
|
+
date: typeof args?.date === "string" ? args.date : void 0,
|
|
47674
|
+
tailBytes: Number.isFinite(rawTailBytes) ? Math.min(rawTailBytes, MAX_TAIL_BYTES) : void 0,
|
|
47675
|
+
grep: typeof args?.grep === "string" ? args.grep : void 0,
|
|
47676
|
+
sinceMs: Number.isFinite(Number(args?.sinceMs)) ? Number(args?.sinceMs) : void 0
|
|
47677
|
+
});
|
|
47678
|
+
if (!tail.success) {
|
|
47679
|
+
return {
|
|
47680
|
+
success: false,
|
|
47681
|
+
error: tail.error || "failed to read daemon log tail",
|
|
47682
|
+
nodeId,
|
|
47683
|
+
logPath: tail.logPath,
|
|
47684
|
+
platform: tail.platform
|
|
47685
|
+
};
|
|
47686
|
+
}
|
|
47687
|
+
const redactedLines = redactLogLines(tail.lines);
|
|
47688
|
+
return {
|
|
47689
|
+
success: true,
|
|
47690
|
+
nodeId,
|
|
47691
|
+
daemonId: selfDaemonId,
|
|
47692
|
+
logPath: tail.logPath,
|
|
47693
|
+
platform: tail.platform,
|
|
47694
|
+
lines: redactedLines,
|
|
47695
|
+
lineCount: redactedLines.length,
|
|
47696
|
+
truncated: tail.truncated,
|
|
47697
|
+
filtered: tail.filtered,
|
|
47698
|
+
bytesReturned: tail.bytesReturned,
|
|
47699
|
+
...tail.grep ? { grep: tail.grep } : {}
|
|
47700
|
+
};
|
|
47701
|
+
}
|
|
46931
47702
|
case "refine_mesh_node": {
|
|
46932
47703
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
46933
47704
|
const nodeId = typeof args?.nodeId === "string" ? args.nodeId.trim() : "";
|
|
46934
47705
|
if (!meshId || !nodeId) return { success: false, error: "meshId and nodeId required" };
|
|
47706
|
+
{
|
|
47707
|
+
const meshRecordForForward = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
47708
|
+
const forwardNode = meshRecordForForward?.mesh?.nodes?.find((n) => meshNodeIdMatches(n, nodeId));
|
|
47709
|
+
const nodeDaemonId = typeof forwardNode?.daemonId === "string" ? forwardNode.daemonId.trim() : void 0;
|
|
47710
|
+
const selfDaemonId = this.deps.statusInstanceId;
|
|
47711
|
+
const isRemote = nodeDaemonId && selfDaemonId && nodeDaemonId !== selfDaemonId;
|
|
47712
|
+
if (isRemote && this.deps.dispatchMeshCommand && !args?._meshDirectDispatch) {
|
|
47713
|
+
const callerCoordinatorDaemonId = typeof args?.coordinatorDaemonId === "string" && args.coordinatorDaemonId.trim() ? args.coordinatorDaemonId.trim() : void 0;
|
|
47714
|
+
const forwarded = await this.deps.dispatchMeshCommand(nodeDaemonId, "refine_mesh_node", {
|
|
47715
|
+
...typeof args === "object" && args !== null ? args : {},
|
|
47716
|
+
coordinatorDaemonId: callerCoordinatorDaemonId || selfDaemonId,
|
|
47717
|
+
_meshDirectDispatch: true
|
|
47718
|
+
});
|
|
47719
|
+
return forwarded ?? { success: false, error: "no response from remote node" };
|
|
47720
|
+
}
|
|
47721
|
+
}
|
|
46935
47722
|
const isDryRun = args?.dryRun !== false && args?.execute !== true;
|
|
46936
47723
|
if (isDryRun) {
|
|
46937
47724
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
@@ -47579,15 +48366,15 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47579
48366
|
}
|
|
47580
48367
|
if (cliType === "codex-cli") {
|
|
47581
48368
|
const repoMcpConfigPath = pathJoin(workspace, ".mcp.json");
|
|
47582
|
-
if (
|
|
48369
|
+
if (fs25.existsSync(repoMcpConfigPath)) {
|
|
47583
48370
|
try {
|
|
47584
48371
|
const repoMcpConfig = parseMeshCoordinatorMcpConfig(
|
|
47585
|
-
|
|
48372
|
+
fs25.readFileSync(repoMcpConfigPath, "utf-8"),
|
|
47586
48373
|
"claude_mcp_json"
|
|
47587
48374
|
);
|
|
47588
48375
|
const existingServers2 = repoMcpConfig.mcpServers;
|
|
47589
48376
|
if (existingServers2 && typeof existingServers2 === "object" && !Array.isArray(existingServers2) && existingServers2[coordinatorSetup.serverName]) {
|
|
47590
|
-
|
|
48377
|
+
fs25.writeFileSync(repoMcpConfigPath, serializeMeshCoordinatorMcpConfig({
|
|
47591
48378
|
...repoMcpConfig,
|
|
47592
48379
|
mcpServers: {
|
|
47593
48380
|
...existingServers2,
|
|
@@ -47703,7 +48490,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47703
48490
|
workspace
|
|
47704
48491
|
};
|
|
47705
48492
|
}
|
|
47706
|
-
const { existsSync:
|
|
48493
|
+
const { existsSync: existsSync44, readFileSync: readFileSync35, writeFileSync: writeFileSync23, copyFileSync: copyFileSync4, mkdirSync: mkdirSync21 } = await import("fs");
|
|
47707
48494
|
const { dirname: dirname14 } = await import("path");
|
|
47708
48495
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
47709
48496
|
const hermesManualFallback = cliType === "hermes-cli" && configFormat === "hermes_config_yaml" ? createHermesManualMeshCoordinatorSetup(meshId, workspace) : null;
|
|
@@ -47746,7 +48533,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47746
48533
|
if (hermesManualFallback) return returnManualFallback(message);
|
|
47747
48534
|
return { success: false, code: "mesh_coordinator_config_write_failed", error: message, meshId, cliType, workspace };
|
|
47748
48535
|
}
|
|
47749
|
-
const hadExistingMcpConfig =
|
|
48536
|
+
const hadExistingMcpConfig = existsSync44(mcpConfigPath);
|
|
47750
48537
|
let existingMcpConfig = hermesBaseConfig?.config || {};
|
|
47751
48538
|
if (hermesBaseConfig) {
|
|
47752
48539
|
copyHermesCoordinatorCredentialFiles(hermesBaseConfig.sourceHome, dirname14(mcpConfigPath));
|
|
@@ -47904,6 +48691,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47904
48691
|
const liveMeshSessions = partitionSessionHostRecords(Array.isArray(sessionHostRecords) ? sessionHostRecords : []).liveRuntimes;
|
|
47905
48692
|
const localMachineId = loadConfig().machineId || "";
|
|
47906
48693
|
const requireDirectPeerTruth = args?.requireDirectPeerTruth === true;
|
|
48694
|
+
const meshGitProbeCache = this.meshGitProbeCache;
|
|
47907
48695
|
const directTruth = requireDirectPeerTruth ? await hydrateInlineMeshDirectTruth({
|
|
47908
48696
|
mesh,
|
|
47909
48697
|
meshSource: meshRecord.source,
|
|
@@ -47914,14 +48702,16 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
47914
48702
|
// Standing-state model: only an explicit refresh fans
|
|
47915
48703
|
// out a blocking peer git probe. Default loads return
|
|
47916
48704
|
// held truth so one slow peer can't block the graph.
|
|
47917
|
-
probeRemotePeers: refreshRequested
|
|
48705
|
+
probeRemotePeers: refreshRequested,
|
|
48706
|
+
probeCache: meshGitProbeCache
|
|
47918
48707
|
}) : {
|
|
47919
48708
|
directEvidenceCount: 0,
|
|
47920
48709
|
localConfirmedCount: 0,
|
|
47921
48710
|
peerAttemptedCount: 0,
|
|
47922
48711
|
peerConfirmedCount: 0,
|
|
47923
48712
|
standingEvidenceCount: 0,
|
|
47924
|
-
unavailableNodeIds: []
|
|
48713
|
+
unavailableNodeIds: [],
|
|
48714
|
+
deadNodeIds: []
|
|
47925
48715
|
};
|
|
47926
48716
|
const passivePeerTruthNotAttempted = requireDirectPeerTruth && !refreshRequested && directTruth.directEvidenceCount > 0 && directTruth.peerAttemptedCount === 0;
|
|
47927
48717
|
const effectiveDirectTruth = passivePeerTruthNotAttempted ? { ...directTruth, unavailableNodeIds: [] } : directTruth;
|
|
@@ -48061,7 +48851,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48061
48851
|
}
|
|
48062
48852
|
}
|
|
48063
48853
|
if (workspace) {
|
|
48064
|
-
if (!
|
|
48854
|
+
if (!fs25.existsSync(workspace)) {
|
|
48065
48855
|
const inlineTransitGit = buildInlineMeshTransitGitStatus(node);
|
|
48066
48856
|
let remoteProbeApplied = false;
|
|
48067
48857
|
if (inlineTransitGit) {
|
|
@@ -48075,7 +48865,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48075
48865
|
}
|
|
48076
48866
|
remoteProbeApplied = true;
|
|
48077
48867
|
} else if (refreshRequested && !isSelfNode && daemonId && this.deps.dispatchMeshCommand && !directTruthUnavailableNodeIds.has(nodeId)) {
|
|
48078
|
-
const
|
|
48868
|
+
const runNodeProbe = () => probeRemoteMeshGitStatusWithRetry({
|
|
48079
48869
|
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
48080
48870
|
daemonId,
|
|
48081
48871
|
workspace,
|
|
@@ -48086,6 +48876,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48086
48876
|
status.connection = connection;
|
|
48087
48877
|
}
|
|
48088
48878
|
});
|
|
48879
|
+
const remoteGit = await meshGitProbeCache.probe(daemonId, workspace, runNodeProbe);
|
|
48089
48880
|
if (remoteGit) {
|
|
48090
48881
|
status.git = remoteGit;
|
|
48091
48882
|
status.health = remoteGit.isGitRepo ? deriveMeshNodeHealthFromGit(remoteGit) : "degraded";
|
|
@@ -48151,7 +48942,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48151
48942
|
const pendingCoordinatorEvents = getPendingMeshCoordinatorEvents(meshId, callerCoordinatorDaemonId);
|
|
48152
48943
|
const unroutableDeliveries = getRecentUnroutableDeliveries();
|
|
48153
48944
|
const previewFreshness = (() => {
|
|
48154
|
-
const localRepoRoot = nodeStatuses.map((node) => readStringValue(node?.git?.repoRoot, node?.repoRoot, node?.workspace)).find((candidate) => !!candidate &&
|
|
48945
|
+
const localRepoRoot = nodeStatuses.map((node) => readStringValue(node?.git?.repoRoot, node?.repoRoot, node?.workspace)).find((candidate) => !!candidate && fs25.existsSync(candidate));
|
|
48155
48946
|
return localRepoRoot ? buildPreviewFreshness(localRepoRoot) : void 0;
|
|
48156
48947
|
})();
|
|
48157
48948
|
const asyncRefineJobs = buildMeshAsyncRefineJobs({
|
|
@@ -48246,7 +49037,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48246
49037
|
const { deriveMeshReviewInboxItems: deriveMeshReviewInboxItems2 } = await Promise.resolve().then(() => (init_mesh_review_inbox(), mesh_review_inbox_exports));
|
|
48247
49038
|
const { readLedgerEntries: readLedgerEntries2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
48248
49039
|
const { getGitDiffSummary: getGitDiffSummary2 } = await Promise.resolve().then(() => (init_git_diff(), git_diff_exports));
|
|
48249
|
-
const { existsSync:
|
|
49040
|
+
const { existsSync: existsSync44 } = await import("fs");
|
|
48250
49041
|
const meshRecord = await this.getMeshForCommand(meshId, args?.inlineMesh, { preferInline: true });
|
|
48251
49042
|
const mesh = meshRecord?.mesh;
|
|
48252
49043
|
if (!mesh) return { success: false, error: "Mesh not found" };
|
|
@@ -48265,7 +49056,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48265
49056
|
const derivation = deriveMeshReviewInboxItems2({ nodes: nodeStatuses, ledgerEntries });
|
|
48266
49057
|
for (const item of derivation.items) {
|
|
48267
49058
|
const workspace = item.workspace;
|
|
48268
|
-
if (!workspace || !
|
|
49059
|
+
if (!workspace || !existsSync44(workspace)) continue;
|
|
48269
49060
|
const baseRef = item.defaultBranch ? `origin/${item.defaultBranch}` : "origin/main";
|
|
48270
49061
|
try {
|
|
48271
49062
|
const diffResult = await getGitDiffSummary2(workspace, { baseRef, maxFiles: 100 });
|
|
@@ -50011,7 +50802,7 @@ var ProviderInstanceManager = class {
|
|
|
50011
50802
|
};
|
|
50012
50803
|
|
|
50013
50804
|
// src/providers/version-archive.ts
|
|
50014
|
-
import * as
|
|
50805
|
+
import * as fs26 from "fs";
|
|
50015
50806
|
import * as path36 from "path";
|
|
50016
50807
|
import * as os28 from "os";
|
|
50017
50808
|
import { platform as platform8 } from "os";
|
|
@@ -50025,8 +50816,8 @@ var VersionArchive = class {
|
|
|
50025
50816
|
}
|
|
50026
50817
|
load() {
|
|
50027
50818
|
try {
|
|
50028
|
-
if (
|
|
50029
|
-
this.history = JSON.parse(
|
|
50819
|
+
if (fs26.existsSync(ARCHIVE_PATH)) {
|
|
50820
|
+
this.history = JSON.parse(fs26.readFileSync(ARCHIVE_PATH, "utf-8"));
|
|
50030
50821
|
}
|
|
50031
50822
|
} catch {
|
|
50032
50823
|
this.history = {};
|
|
@@ -50063,8 +50854,8 @@ var VersionArchive = class {
|
|
|
50063
50854
|
}
|
|
50064
50855
|
save() {
|
|
50065
50856
|
try {
|
|
50066
|
-
|
|
50067
|
-
|
|
50857
|
+
fs26.mkdirSync(path36.dirname(ARCHIVE_PATH), { recursive: true });
|
|
50858
|
+
fs26.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
50068
50859
|
} catch {
|
|
50069
50860
|
}
|
|
50070
50861
|
}
|
|
@@ -50089,8 +50880,8 @@ function findBinary2(name) {
|
|
|
50089
50880
|
for (const ext of exes) {
|
|
50090
50881
|
const fullPath = path36.join(p, name + ext);
|
|
50091
50882
|
try {
|
|
50092
|
-
if (
|
|
50093
|
-
const stat2 =
|
|
50883
|
+
if (fs26.existsSync(fullPath)) {
|
|
50884
|
+
const stat2 = fs26.statSync(fullPath);
|
|
50094
50885
|
if (stat2.isFile() && (isWin || stat2.mode & 73)) {
|
|
50095
50886
|
return fullPath;
|
|
50096
50887
|
}
|
|
@@ -50137,9 +50928,9 @@ function checkPathExists2(paths) {
|
|
|
50137
50928
|
if (p.includes("*")) {
|
|
50138
50929
|
const home = os28.homedir();
|
|
50139
50930
|
const resolved = p.replace(/\*/g, home.split(path36.sep).pop() || "");
|
|
50140
|
-
if (
|
|
50931
|
+
if (fs26.existsSync(resolved)) return resolved;
|
|
50141
50932
|
} else {
|
|
50142
|
-
if (
|
|
50933
|
+
if (fs26.existsSync(p)) return p;
|
|
50143
50934
|
}
|
|
50144
50935
|
}
|
|
50145
50936
|
return null;
|
|
@@ -50147,7 +50938,7 @@ function checkPathExists2(paths) {
|
|
|
50147
50938
|
async function getMacAppVersion(appPath) {
|
|
50148
50939
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
50149
50940
|
const plistPath = path36.join(appPath, "Contents", "Info.plist");
|
|
50150
|
-
if (!
|
|
50941
|
+
if (!fs26.existsSync(plistPath)) return null;
|
|
50151
50942
|
const raw = await runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
50152
50943
|
return raw || null;
|
|
50153
50944
|
}
|
|
@@ -50173,7 +50964,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
50173
50964
|
let resolvedBin = cliBin;
|
|
50174
50965
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
50175
50966
|
const bundled = path36.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
50176
|
-
if (provider.cli &&
|
|
50967
|
+
if (provider.cli && fs26.existsSync(bundled)) resolvedBin = bundled;
|
|
50177
50968
|
}
|
|
50178
50969
|
info.installed = !!(appPath || resolvedBin);
|
|
50179
50970
|
info.path = appPath || null;
|
|
@@ -50212,7 +51003,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
50212
51003
|
|
|
50213
51004
|
// src/daemon/dev-server.ts
|
|
50214
51005
|
import * as http2 from "http";
|
|
50215
|
-
import * as
|
|
51006
|
+
import * as fs30 from "fs";
|
|
50216
51007
|
import * as path40 from "path";
|
|
50217
51008
|
init_config();
|
|
50218
51009
|
|
|
@@ -50564,7 +51355,7 @@ init_logger();
|
|
|
50564
51355
|
|
|
50565
51356
|
// src/daemon/dev-cdp-handlers.ts
|
|
50566
51357
|
init_logger();
|
|
50567
|
-
import * as
|
|
51358
|
+
import * as fs27 from "fs";
|
|
50568
51359
|
import * as path37 from "path";
|
|
50569
51360
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
50570
51361
|
const body = await ctx.readBody(req);
|
|
@@ -50744,17 +51535,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
50744
51535
|
}
|
|
50745
51536
|
let scriptsPath = "";
|
|
50746
51537
|
const directScripts = path37.join(dir, "scripts.js");
|
|
50747
|
-
if (
|
|
51538
|
+
if (fs27.existsSync(directScripts)) {
|
|
50748
51539
|
scriptsPath = directScripts;
|
|
50749
51540
|
} else {
|
|
50750
51541
|
const scriptsDir = path37.join(dir, "scripts");
|
|
50751
|
-
if (
|
|
50752
|
-
const versions =
|
|
50753
|
-
return
|
|
51542
|
+
if (fs27.existsSync(scriptsDir)) {
|
|
51543
|
+
const versions = fs27.readdirSync(scriptsDir).filter((d) => {
|
|
51544
|
+
return fs27.statSync(path37.join(scriptsDir, d)).isDirectory();
|
|
50754
51545
|
}).sort().reverse();
|
|
50755
51546
|
for (const ver of versions) {
|
|
50756
51547
|
const p = path37.join(scriptsDir, ver, "scripts.js");
|
|
50757
|
-
if (
|
|
51548
|
+
if (fs27.existsSync(p)) {
|
|
50758
51549
|
scriptsPath = p;
|
|
50759
51550
|
break;
|
|
50760
51551
|
}
|
|
@@ -50766,7 +51557,7 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
50766
51557
|
return;
|
|
50767
51558
|
}
|
|
50768
51559
|
try {
|
|
50769
|
-
const source =
|
|
51560
|
+
const source = fs27.readFileSync(scriptsPath, "utf-8");
|
|
50770
51561
|
const hints = {};
|
|
50771
51562
|
const funcRegex = /module\.exports\.(\w+)\s*=\s*function\s+\w+\s*\(params\)/g;
|
|
50772
51563
|
let match;
|
|
@@ -51581,7 +52372,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
51581
52372
|
}
|
|
51582
52373
|
|
|
51583
52374
|
// src/daemon/dev-cli-debug.ts
|
|
51584
|
-
import * as
|
|
52375
|
+
import * as fs28 from "fs";
|
|
51585
52376
|
import * as path38 from "path";
|
|
51586
52377
|
function slugifyFixtureName(value) {
|
|
51587
52378
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -51597,10 +52388,10 @@ function getCliFixtureDir(ctx, type) {
|
|
|
51597
52388
|
function readCliFixture(ctx, type, name) {
|
|
51598
52389
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
51599
52390
|
const filePath = path38.join(fixtureDir, `${name}.json`);
|
|
51600
|
-
if (!
|
|
52391
|
+
if (!fs28.existsSync(filePath)) {
|
|
51601
52392
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
51602
52393
|
}
|
|
51603
|
-
return JSON.parse(
|
|
52394
|
+
return JSON.parse(fs28.readFileSync(filePath, "utf-8"));
|
|
51604
52395
|
}
|
|
51605
52396
|
function getExerciseTranscriptText(result) {
|
|
51606
52397
|
const parts = [];
|
|
@@ -52345,7 +53136,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
52345
53136
|
return;
|
|
52346
53137
|
}
|
|
52347
53138
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
52348
|
-
|
|
53139
|
+
fs28.mkdirSync(fixtureDir, { recursive: true });
|
|
52349
53140
|
const name = slugifyFixtureName(String(body?.name || `${type}-${Date.now()}`));
|
|
52350
53141
|
const result = await runCliExerciseInternal(ctx, { ...request, type });
|
|
52351
53142
|
const fixture = {
|
|
@@ -52373,7 +53164,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
52373
53164
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
52374
53165
|
};
|
|
52375
53166
|
const filePath = path38.join(fixtureDir, `${name}.json`);
|
|
52376
|
-
|
|
53167
|
+
fs28.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
52377
53168
|
ctx.json(res, 200, {
|
|
52378
53169
|
saved: true,
|
|
52379
53170
|
name,
|
|
@@ -52391,14 +53182,14 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
52391
53182
|
async function handleCliFixtureList(ctx, type, _req, res) {
|
|
52392
53183
|
try {
|
|
52393
53184
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
52394
|
-
if (!
|
|
53185
|
+
if (!fs28.existsSync(fixtureDir)) {
|
|
52395
53186
|
ctx.json(res, 200, { fixtures: [], count: 0 });
|
|
52396
53187
|
return;
|
|
52397
53188
|
}
|
|
52398
|
-
const fixtures =
|
|
53189
|
+
const fixtures = fs28.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
52399
53190
|
const fullPath = path38.join(fixtureDir, file);
|
|
52400
53191
|
try {
|
|
52401
|
-
const raw = JSON.parse(
|
|
53192
|
+
const raw = JSON.parse(fs28.readFileSync(fullPath, "utf-8"));
|
|
52402
53193
|
return {
|
|
52403
53194
|
name: raw.name || file.replace(/\.json$/i, ""),
|
|
52404
53195
|
path: fullPath,
|
|
@@ -52531,7 +53322,7 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
52531
53322
|
}
|
|
52532
53323
|
|
|
52533
53324
|
// src/daemon/dev-auto-implement.ts
|
|
52534
|
-
import * as
|
|
53325
|
+
import * as fs29 from "fs";
|
|
52535
53326
|
import * as path39 from "path";
|
|
52536
53327
|
import * as os29 from "os";
|
|
52537
53328
|
import { DEFAULT_SESSION_HOST_COLS as DEFAULT_SESSION_HOST_COLS7, DEFAULT_SESSION_HOST_ROWS as DEFAULT_SESSION_HOST_ROWS7 } from "@adhdev/session-host-core";
|
|
@@ -52580,10 +53371,10 @@ function resolveAutoImplReference(ctx, category, requestedReference, targetType)
|
|
|
52580
53371
|
return fallback?.type || null;
|
|
52581
53372
|
}
|
|
52582
53373
|
function getLatestScriptVersionDir(scriptsDir) {
|
|
52583
|
-
if (!
|
|
52584
|
-
const versions =
|
|
53374
|
+
if (!fs29.existsSync(scriptsDir)) return null;
|
|
53375
|
+
const versions = fs29.readdirSync(scriptsDir).filter((d) => {
|
|
52585
53376
|
try {
|
|
52586
|
-
return
|
|
53377
|
+
return fs29.statSync(path39.join(scriptsDir, d)).isDirectory();
|
|
52587
53378
|
} catch {
|
|
52588
53379
|
return false;
|
|
52589
53380
|
}
|
|
@@ -52605,13 +53396,13 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
52605
53396
|
if (!sourceDir) {
|
|
52606
53397
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
52607
53398
|
}
|
|
52608
|
-
if (!
|
|
52609
|
-
|
|
52610
|
-
|
|
53399
|
+
if (!fs29.existsSync(desiredDir)) {
|
|
53400
|
+
fs29.mkdirSync(path39.dirname(desiredDir), { recursive: true });
|
|
53401
|
+
fs29.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
52611
53402
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
52612
53403
|
}
|
|
52613
53404
|
const providerJson = path39.join(desiredDir, "provider.json");
|
|
52614
|
-
if (!
|
|
53405
|
+
if (!fs29.existsSync(providerJson)) {
|
|
52615
53406
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
52616
53407
|
}
|
|
52617
53408
|
return { dir: desiredDir };
|
|
@@ -52619,15 +53410,15 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
52619
53410
|
function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
52620
53411
|
if (!referenceType) return {};
|
|
52621
53412
|
const refDir = ctx.findProviderDir(referenceType);
|
|
52622
|
-
if (!refDir || !
|
|
53413
|
+
if (!refDir || !fs29.existsSync(refDir)) return {};
|
|
52623
53414
|
const referenceScripts = {};
|
|
52624
53415
|
const scriptsDir = path39.join(refDir, "scripts");
|
|
52625
53416
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
52626
53417
|
if (!latestDir) return referenceScripts;
|
|
52627
|
-
for (const file of
|
|
53418
|
+
for (const file of fs29.readdirSync(latestDir)) {
|
|
52628
53419
|
if (!file.endsWith(".js")) continue;
|
|
52629
53420
|
try {
|
|
52630
|
-
referenceScripts[file] =
|
|
53421
|
+
referenceScripts[file] = fs29.readFileSync(path39.join(latestDir, file), "utf-8");
|
|
52631
53422
|
} catch {
|
|
52632
53423
|
}
|
|
52633
53424
|
}
|
|
@@ -52736,15 +53527,15 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
52736
53527
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
52737
53528
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
52738
53529
|
const tmpDir = path39.join(os29.tmpdir(), "adhdev-autoimpl");
|
|
52739
|
-
if (!
|
|
53530
|
+
if (!fs29.existsSync(tmpDir)) fs29.mkdirSync(tmpDir, { recursive: true });
|
|
52740
53531
|
const promptFile = path39.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
52741
|
-
|
|
53532
|
+
fs29.writeFileSync(promptFile, prompt, "utf-8");
|
|
52742
53533
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
52743
53534
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
52744
53535
|
const spawn4 = agentProvider?.spawn;
|
|
52745
53536
|
if (!spawn4?.command) {
|
|
52746
53537
|
try {
|
|
52747
|
-
|
|
53538
|
+
fs29.unlinkSync(promptFile);
|
|
52748
53539
|
} catch {
|
|
52749
53540
|
}
|
|
52750
53541
|
ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
|
|
@@ -52846,7 +53637,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
52846
53637
|
} catch {
|
|
52847
53638
|
}
|
|
52848
53639
|
try {
|
|
52849
|
-
|
|
53640
|
+
fs29.unlinkSync(promptFile);
|
|
52850
53641
|
} catch {
|
|
52851
53642
|
}
|
|
52852
53643
|
ctx.log(`Auto-implement (ACP) ${success ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
@@ -53072,7 +53863,7 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
53072
53863
|
}
|
|
53073
53864
|
});
|
|
53074
53865
|
try {
|
|
53075
|
-
|
|
53866
|
+
fs29.unlinkSync(promptFile);
|
|
53076
53867
|
} catch {
|
|
53077
53868
|
}
|
|
53078
53869
|
ctx.log(`Auto-implement ${success ? "completed" : "failed"}: ${type} (exit: ${code})${verificationSummary ? ` verify=${verificationSummary.pass ? "pass" : "fail"}` : ""}`);
|
|
@@ -53177,10 +53968,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
53177
53968
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
53178
53969
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
53179
53970
|
lines.push("");
|
|
53180
|
-
for (const file of
|
|
53971
|
+
for (const file of fs29.readdirSync(latestScriptsDir)) {
|
|
53181
53972
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
53182
53973
|
try {
|
|
53183
|
-
const content =
|
|
53974
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file), "utf-8");
|
|
53184
53975
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
53185
53976
|
lines.push("```javascript");
|
|
53186
53977
|
lines.push(content);
|
|
@@ -53190,14 +53981,14 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
53190
53981
|
}
|
|
53191
53982
|
}
|
|
53192
53983
|
}
|
|
53193
|
-
const refFiles =
|
|
53984
|
+
const refFiles = fs29.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
53194
53985
|
if (refFiles.length > 0) {
|
|
53195
53986
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
53196
53987
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
53197
53988
|
lines.push("");
|
|
53198
53989
|
for (const file of refFiles) {
|
|
53199
53990
|
try {
|
|
53200
|
-
const content =
|
|
53991
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file), "utf-8");
|
|
53201
53992
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
53202
53993
|
lines.push("```javascript");
|
|
53203
53994
|
lines.push(content);
|
|
@@ -53242,7 +54033,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
53242
54033
|
const loadGuide = (name) => {
|
|
53243
54034
|
try {
|
|
53244
54035
|
const p = path39.join(docsDir, name);
|
|
53245
|
-
if (
|
|
54036
|
+
if (fs29.existsSync(p)) return fs29.readFileSync(p, "utf-8");
|
|
53246
54037
|
} catch {
|
|
53247
54038
|
}
|
|
53248
54039
|
return null;
|
|
@@ -53486,11 +54277,11 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
53486
54277
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
53487
54278
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
53488
54279
|
lines.push("");
|
|
53489
|
-
for (const file of
|
|
54280
|
+
for (const file of fs29.readdirSync(latestScriptsDir)) {
|
|
53490
54281
|
if (!file.endsWith(".js")) continue;
|
|
53491
54282
|
if (!targetFileNames.has(file)) continue;
|
|
53492
54283
|
try {
|
|
53493
|
-
const content =
|
|
54284
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file), "utf-8");
|
|
53494
54285
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
53495
54286
|
lines.push("```javascript");
|
|
53496
54287
|
lines.push(content);
|
|
@@ -53499,14 +54290,14 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
53499
54290
|
} catch {
|
|
53500
54291
|
}
|
|
53501
54292
|
}
|
|
53502
|
-
const refFiles =
|
|
54293
|
+
const refFiles = fs29.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
53503
54294
|
if (refFiles.length > 0) {
|
|
53504
54295
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
53505
54296
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
53506
54297
|
lines.push("");
|
|
53507
54298
|
for (const file of refFiles) {
|
|
53508
54299
|
try {
|
|
53509
|
-
const content =
|
|
54300
|
+
const content = fs29.readFileSync(path39.join(latestScriptsDir, file), "utf-8");
|
|
53510
54301
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
53511
54302
|
lines.push("```javascript");
|
|
53512
54303
|
lines.push(content);
|
|
@@ -53543,7 +54334,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
53543
54334
|
const loadGuide = (name) => {
|
|
53544
54335
|
try {
|
|
53545
54336
|
const p = path39.join(docsDir, name);
|
|
53546
|
-
if (
|
|
54337
|
+
if (fs29.existsSync(p)) return fs29.readFileSync(p, "utf-8");
|
|
53547
54338
|
} catch {
|
|
53548
54339
|
}
|
|
53549
54340
|
return null;
|
|
@@ -54283,7 +55074,7 @@ var DevServer = class _DevServer {
|
|
|
54283
55074
|
path40.join(process.cwd(), "packages/web-devconsole/dist")
|
|
54284
55075
|
];
|
|
54285
55076
|
for (const dir of candidates) {
|
|
54286
|
-
if (
|
|
55077
|
+
if (fs30.existsSync(path40.join(dir, "index.html"))) return dir;
|
|
54287
55078
|
}
|
|
54288
55079
|
return null;
|
|
54289
55080
|
}
|
|
@@ -54295,7 +55086,7 @@ var DevServer = class _DevServer {
|
|
|
54295
55086
|
}
|
|
54296
55087
|
const htmlPath = path40.join(distDir, "index.html");
|
|
54297
55088
|
try {
|
|
54298
|
-
const html =
|
|
55089
|
+
const html = fs30.readFileSync(htmlPath, "utf-8");
|
|
54299
55090
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
54300
55091
|
res.end(html);
|
|
54301
55092
|
} catch (e) {
|
|
@@ -54325,7 +55116,7 @@ var DevServer = class _DevServer {
|
|
|
54325
55116
|
return;
|
|
54326
55117
|
}
|
|
54327
55118
|
try {
|
|
54328
|
-
const content =
|
|
55119
|
+
const content = fs30.readFileSync(filePath);
|
|
54329
55120
|
const ext = path40.extname(filePath);
|
|
54330
55121
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
54331
55122
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
@@ -54434,14 +55225,14 @@ var DevServer = class _DevServer {
|
|
|
54434
55225
|
const files = [];
|
|
54435
55226
|
const scan = (d, prefix) => {
|
|
54436
55227
|
try {
|
|
54437
|
-
for (const entry of
|
|
55228
|
+
for (const entry of fs30.readdirSync(d, { withFileTypes: true })) {
|
|
54438
55229
|
if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
|
|
54439
55230
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
54440
55231
|
if (entry.isDirectory()) {
|
|
54441
55232
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
54442
55233
|
scan(path40.join(d, entry.name), rel);
|
|
54443
55234
|
} else {
|
|
54444
|
-
const stat2 =
|
|
55235
|
+
const stat2 = fs30.statSync(path40.join(d, entry.name));
|
|
54445
55236
|
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
54446
55237
|
}
|
|
54447
55238
|
}
|
|
@@ -54469,11 +55260,11 @@ var DevServer = class _DevServer {
|
|
|
54469
55260
|
this.json(res, 403, { error: "Forbidden" });
|
|
54470
55261
|
return;
|
|
54471
55262
|
}
|
|
54472
|
-
if (!
|
|
55263
|
+
if (!fs30.existsSync(fullPath) || fs30.statSync(fullPath).isDirectory()) {
|
|
54473
55264
|
this.json(res, 404, { error: `File not found: ${filePath}` });
|
|
54474
55265
|
return;
|
|
54475
55266
|
}
|
|
54476
|
-
const content =
|
|
55267
|
+
const content = fs30.readFileSync(fullPath, "utf-8");
|
|
54477
55268
|
this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
|
|
54478
55269
|
}
|
|
54479
55270
|
/** POST /api/providers/:type/file — write a file { path, content } */
|
|
@@ -54495,9 +55286,9 @@ var DevServer = class _DevServer {
|
|
|
54495
55286
|
return;
|
|
54496
55287
|
}
|
|
54497
55288
|
try {
|
|
54498
|
-
if (
|
|
54499
|
-
|
|
54500
|
-
|
|
55289
|
+
if (fs30.existsSync(fullPath)) fs30.copyFileSync(fullPath, fullPath + ".bak");
|
|
55290
|
+
fs30.mkdirSync(path40.dirname(fullPath), { recursive: true });
|
|
55291
|
+
fs30.writeFileSync(fullPath, content, "utf-8");
|
|
54501
55292
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
54502
55293
|
this.providerLoader.reload();
|
|
54503
55294
|
this.json(res, 200, { saved: true, path: filePath, chars: content.length });
|
|
@@ -54514,8 +55305,8 @@ var DevServer = class _DevServer {
|
|
|
54514
55305
|
}
|
|
54515
55306
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
54516
55307
|
const p = path40.join(dir, name);
|
|
54517
|
-
if (
|
|
54518
|
-
const source =
|
|
55308
|
+
if (fs30.existsSync(p)) {
|
|
55309
|
+
const source = fs30.readFileSync(p, "utf-8");
|
|
54519
55310
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
54520
55311
|
return;
|
|
54521
55312
|
}
|
|
@@ -54534,11 +55325,11 @@ var DevServer = class _DevServer {
|
|
|
54534
55325
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
54535
55326
|
return;
|
|
54536
55327
|
}
|
|
54537
|
-
const target =
|
|
55328
|
+
const target = fs30.existsSync(path40.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
54538
55329
|
const targetPath = path40.join(dir, target);
|
|
54539
55330
|
try {
|
|
54540
|
-
if (
|
|
54541
|
-
|
|
55331
|
+
if (fs30.existsSync(targetPath)) fs30.copyFileSync(targetPath, targetPath + ".bak");
|
|
55332
|
+
fs30.writeFileSync(targetPath, source, "utf-8");
|
|
54542
55333
|
this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
|
|
54543
55334
|
this.providerLoader.reload();
|
|
54544
55335
|
this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
|
|
@@ -54683,20 +55474,20 @@ var DevServer = class _DevServer {
|
|
|
54683
55474
|
let targetDir;
|
|
54684
55475
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
54685
55476
|
const jsonPath = path40.join(targetDir, "provider.json");
|
|
54686
|
-
if (
|
|
55477
|
+
if (fs30.existsSync(jsonPath)) {
|
|
54687
55478
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
54688
55479
|
return;
|
|
54689
55480
|
}
|
|
54690
55481
|
try {
|
|
54691
55482
|
const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version, osPaths, processNames });
|
|
54692
|
-
|
|
54693
|
-
|
|
55483
|
+
fs30.mkdirSync(targetDir, { recursive: true });
|
|
55484
|
+
fs30.writeFileSync(jsonPath, result["provider.json"], "utf-8");
|
|
54694
55485
|
const createdFiles = ["provider.json"];
|
|
54695
55486
|
if (result.files) {
|
|
54696
55487
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
54697
55488
|
const fullPath = path40.join(targetDir, relPath);
|
|
54698
|
-
|
|
54699
|
-
|
|
55489
|
+
fs30.mkdirSync(path40.dirname(fullPath), { recursive: true });
|
|
55490
|
+
fs30.writeFileSync(fullPath, content, "utf-8");
|
|
54700
55491
|
createdFiles.push(relPath);
|
|
54701
55492
|
}
|
|
54702
55493
|
}
|
|
@@ -54745,10 +55536,10 @@ var DevServer = class _DevServer {
|
|
|
54745
55536
|
}
|
|
54746
55537
|
// ─── Phase 2: Auto-Implement Backend ───
|
|
54747
55538
|
getLatestScriptVersionDir(scriptsDir) {
|
|
54748
|
-
if (!
|
|
54749
|
-
const versions =
|
|
55539
|
+
if (!fs30.existsSync(scriptsDir)) return null;
|
|
55540
|
+
const versions = fs30.readdirSync(scriptsDir).filter((d) => {
|
|
54750
55541
|
try {
|
|
54751
|
-
return
|
|
55542
|
+
return fs30.statSync(path40.join(scriptsDir, d)).isDirectory();
|
|
54752
55543
|
} catch {
|
|
54753
55544
|
return false;
|
|
54754
55545
|
}
|
|
@@ -54770,13 +55561,13 @@ var DevServer = class _DevServer {
|
|
|
54770
55561
|
if (!sourceDir) {
|
|
54771
55562
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
54772
55563
|
}
|
|
54773
|
-
if (!
|
|
54774
|
-
|
|
54775
|
-
|
|
55564
|
+
if (!fs30.existsSync(desiredDir)) {
|
|
55565
|
+
fs30.mkdirSync(path40.dirname(desiredDir), { recursive: true });
|
|
55566
|
+
fs30.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
54776
55567
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
54777
55568
|
}
|
|
54778
55569
|
const providerJson = path40.join(desiredDir, "provider.json");
|
|
54779
|
-
if (!
|
|
55570
|
+
if (!fs30.existsSync(providerJson)) {
|
|
54780
55571
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
54781
55572
|
}
|
|
54782
55573
|
return { dir: desiredDir };
|
|
@@ -54819,10 +55610,10 @@ var DevServer = class _DevServer {
|
|
|
54819
55610
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
54820
55611
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
54821
55612
|
lines.push("");
|
|
54822
|
-
for (const file of
|
|
55613
|
+
for (const file of fs30.readdirSync(latestScriptsDir)) {
|
|
54823
55614
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
54824
55615
|
try {
|
|
54825
|
-
const content =
|
|
55616
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file), "utf-8");
|
|
54826
55617
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
54827
55618
|
lines.push("```javascript");
|
|
54828
55619
|
lines.push(content);
|
|
@@ -54832,14 +55623,14 @@ var DevServer = class _DevServer {
|
|
|
54832
55623
|
}
|
|
54833
55624
|
}
|
|
54834
55625
|
}
|
|
54835
|
-
const refFiles =
|
|
55626
|
+
const refFiles = fs30.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
54836
55627
|
if (refFiles.length > 0) {
|
|
54837
55628
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
54838
55629
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
54839
55630
|
lines.push("");
|
|
54840
55631
|
for (const file of refFiles) {
|
|
54841
55632
|
try {
|
|
54842
|
-
const content =
|
|
55633
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file), "utf-8");
|
|
54843
55634
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
54844
55635
|
lines.push("```javascript");
|
|
54845
55636
|
lines.push(content);
|
|
@@ -54884,7 +55675,7 @@ var DevServer = class _DevServer {
|
|
|
54884
55675
|
const loadGuide = (name) => {
|
|
54885
55676
|
try {
|
|
54886
55677
|
const p = path40.join(docsDir, name);
|
|
54887
|
-
if (
|
|
55678
|
+
if (fs30.existsSync(p)) return fs30.readFileSync(p, "utf-8");
|
|
54888
55679
|
} catch {
|
|
54889
55680
|
}
|
|
54890
55681
|
return null;
|
|
@@ -55065,11 +55856,11 @@ var DevServer = class _DevServer {
|
|
|
55065
55856
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
55066
55857
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
55067
55858
|
lines.push("");
|
|
55068
|
-
for (const file of
|
|
55859
|
+
for (const file of fs30.readdirSync(latestScriptsDir)) {
|
|
55069
55860
|
if (!file.endsWith(".js")) continue;
|
|
55070
55861
|
if (!targetFileNames.has(file)) continue;
|
|
55071
55862
|
try {
|
|
55072
|
-
const content =
|
|
55863
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file), "utf-8");
|
|
55073
55864
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
55074
55865
|
lines.push("```javascript");
|
|
55075
55866
|
lines.push(content);
|
|
@@ -55078,14 +55869,14 @@ var DevServer = class _DevServer {
|
|
|
55078
55869
|
} catch {
|
|
55079
55870
|
}
|
|
55080
55871
|
}
|
|
55081
|
-
const refFiles =
|
|
55872
|
+
const refFiles = fs30.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
55082
55873
|
if (refFiles.length > 0) {
|
|
55083
55874
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
55084
55875
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
55085
55876
|
lines.push("");
|
|
55086
55877
|
for (const file of refFiles) {
|
|
55087
55878
|
try {
|
|
55088
|
-
const content =
|
|
55879
|
+
const content = fs30.readFileSync(path40.join(latestScriptsDir, file), "utf-8");
|
|
55089
55880
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
55090
55881
|
lines.push("```javascript");
|
|
55091
55882
|
lines.push(content);
|
|
@@ -55122,7 +55913,7 @@ var DevServer = class _DevServer {
|
|
|
55122
55913
|
const loadGuide = (name) => {
|
|
55123
55914
|
try {
|
|
55124
55915
|
const p = path40.join(docsDir, name);
|
|
55125
|
-
if (
|
|
55916
|
+
if (fs30.existsSync(p)) return fs30.readFileSync(p, "utf-8");
|
|
55126
55917
|
} catch {
|
|
55127
55918
|
}
|
|
55128
55919
|
return null;
|
|
@@ -56230,8 +57021,8 @@ async function installExtension(ide, extension) {
|
|
|
56230
57021
|
const res = await fetch(extension.vsixUrl);
|
|
56231
57022
|
if (res.ok) {
|
|
56232
57023
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
56233
|
-
const
|
|
56234
|
-
|
|
57024
|
+
const fs31 = await import("fs");
|
|
57025
|
+
fs31.writeFileSync(vsixPath, buffer);
|
|
56235
57026
|
return new Promise((resolve24) => {
|
|
56236
57027
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
56237
57028
|
exec6(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
@@ -56811,7 +57602,7 @@ import { readFileSync as readFileSync33 } from "fs";
|
|
|
56811
57602
|
import { dirname as dirname12, resolve as resolve22 } from "path";
|
|
56812
57603
|
|
|
56813
57604
|
// src/providers/sdk/v1/validators/taint.ts
|
|
56814
|
-
import { readFileSync as readFileSync34, existsSync as
|
|
57605
|
+
import { readFileSync as readFileSync34, existsSync as existsSync43 } from "fs";
|
|
56815
57606
|
import { resolve as resolve23, dirname as dirname13, join as join44 } from "path";
|
|
56816
57607
|
|
|
56817
57608
|
// src/providers/sdk/v1/validators/index.ts
|
|
@@ -56909,6 +57700,7 @@ export {
|
|
|
56909
57700
|
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
56910
57701
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
56911
57702
|
DEFAULT_MESH_POLICY,
|
|
57703
|
+
DEFAULT_MESH_SCHEDULING_STRATEGY,
|
|
56912
57704
|
DEFAULT_SESSION_HOST_APP_NAME,
|
|
56913
57705
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
56914
57706
|
DEFAULT_SESSION_HOST_READY_TIMEOUT_MS,
|
|
@@ -56934,9 +57726,12 @@ export {
|
|
|
56934
57726
|
InMemoryGitSnapshotStore,
|
|
56935
57727
|
LOG,
|
|
56936
57728
|
MAX_LEDGER_SLICE_LIMIT,
|
|
57729
|
+
MESH_CONVERGE_FAST_FORWARD_TAG,
|
|
57730
|
+
MESH_CONVERGE_REFINE_TAG,
|
|
56937
57731
|
MESH_MISSION_STATUSES,
|
|
56938
57732
|
MESH_REFINE_CONFIG_LOCATIONS,
|
|
56939
57733
|
MESH_REFINE_CONFIG_SCHEMA,
|
|
57734
|
+
MESH_SCHEDULING_STRATEGIES,
|
|
56940
57735
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS,
|
|
56941
57736
|
MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA,
|
|
56942
57737
|
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
@@ -57137,6 +57932,7 @@ export {
|
|
|
57137
57932
|
normalizeManagedStatus,
|
|
57138
57933
|
normalizeMeshCapabilityTags,
|
|
57139
57934
|
normalizeMeshDaemonRole,
|
|
57935
|
+
normalizeMeshSchedulingStrategy,
|
|
57140
57936
|
normalizeMeshTaskMode,
|
|
57141
57937
|
normalizeMeshWorkerResult,
|
|
57142
57938
|
normalizeMessageParts,
|
|
@@ -57174,7 +57970,9 @@ export {
|
|
|
57174
57970
|
resetConfig,
|
|
57175
57971
|
resetDebugRuntimeConfig,
|
|
57176
57972
|
resetState,
|
|
57973
|
+
resolveAutoConvergeCodeChange,
|
|
57177
57974
|
resolveChatMessageKind,
|
|
57975
|
+
resolveConvergeRequiredTags,
|
|
57178
57976
|
resolveCurrentGlobalInstallSurface,
|
|
57179
57977
|
resolveDebugRuntimeConfig,
|
|
57180
57978
|
resolveDelegatedWorkerAutoApprove,
|
|
@@ -57182,6 +57980,7 @@ export {
|
|
|
57182
57980
|
resolveGitRepository,
|
|
57183
57981
|
resolveMeshHostStatus,
|
|
57184
57982
|
resolveMeshRefineValidationPlan,
|
|
57983
|
+
resolveNodeSchedulingPriority,
|
|
57185
57984
|
resolveSessionHostAppName,
|
|
57186
57985
|
resolveSessionHostAppNameResolution,
|
|
57187
57986
|
resolveWorktreePath,
|