@adhdev/daemon-core 1.0.18-rc.16 → 1.0.18-rc.18
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/cli-manager.d.ts +9 -0
- package/dist/config/mesh-json-config.d.ts +62 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +919 -421
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +880 -391
- package/dist/index.mjs.map +1 -1
- package/dist/providers/auto-approve-modes.d.ts +14 -0
- package/dist/providers/cli-provider-instance.d.ts +4 -0
- package/dist/providers/contracts.d.ts +17 -0
- package/dist/providers/provider-schema.d.ts +1 -0
- package/dist/repo-mesh-types.d.ts +38 -6
- package/dist/shared-types.d.ts +3 -1
- package/package.json +3 -3
- package/src/commands/cli-manager.ts +54 -8
- package/src/commands/med-family/mesh-crud.ts +155 -0
- package/src/config/mesh-json-config.ts +103 -0
- package/src/index.ts +21 -1
- package/src/mesh/mesh-event-forwarding.ts +18 -2
- package/src/mesh/mesh-queue-assignment.ts +66 -9
- package/src/providers/auto-approve-modes.ts +97 -0
- package/src/providers/cli-provider-instance.ts +45 -13
- package/src/providers/contracts.ts +25 -1
- package/src/providers/provider-schema.ts +83 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +44 -0
- package/src/repo-mesh-types.ts +112 -12
- package/src/shared-types.ts +3 -1
- package/src/status/snapshot.ts +2 -0
package/dist/index.mjs
CHANGED
|
@@ -25,6 +25,62 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
25
25
|
};
|
|
26
26
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
27
|
|
|
28
|
+
// src/providers/auto-approve-modes.ts
|
|
29
|
+
function isKnownDangerousLaunchArg(arg) {
|
|
30
|
+
const normalized = arg.trim();
|
|
31
|
+
if (KNOWN_DANGEROUS_LAUNCH_ARGS.has(normalized)) return true;
|
|
32
|
+
return normalized.startsWith("--dangerously-skip-permissions=") || normalized.startsWith("--dangerously-bypass-approvals-and-sandbox=");
|
|
33
|
+
}
|
|
34
|
+
function deriveAutoApproveModeRisk(mode) {
|
|
35
|
+
return Array.isArray(mode.launchArgs) && mode.launchArgs.some(isKnownDangerousLaunchArg) ? "dangerous" : mode.risk;
|
|
36
|
+
}
|
|
37
|
+
function inactiveMode(modeId = "") {
|
|
38
|
+
return { active: false, strategy: "pty-parse-default", modeId };
|
|
39
|
+
}
|
|
40
|
+
function resolveConfiguredMode(provider, mode, settings) {
|
|
41
|
+
if (mode.strategy === "post-boot-command") return inactiveMode(mode.id);
|
|
42
|
+
if (settings?.launchedByCoordinator === true && settings.delegatedWorkerDangerousModeAllow !== true && deriveAutoApproveModeRisk(mode) === "dangerous") {
|
|
43
|
+
const fallback = provider.autoApproveModes?.modes.find((candidate) => candidate.strategy === "pty-parse-default" && deriveAutoApproveModeRisk(candidate) !== "dangerous");
|
|
44
|
+
return fallback ? { active: true, strategy: fallback.strategy, modeId: fallback.id } : inactiveMode(mode.id);
|
|
45
|
+
}
|
|
46
|
+
return { active: true, strategy: mode.strategy, modeId: mode.id };
|
|
47
|
+
}
|
|
48
|
+
function resolveProviderAutoApproveMode(provider, settings) {
|
|
49
|
+
const config = provider.autoApproveModes;
|
|
50
|
+
const explicitModeId = settings?.autoApproveMode;
|
|
51
|
+
if (typeof explicitModeId === "string") {
|
|
52
|
+
const mode = config?.modes.find((candidate) => candidate.id === explicitModeId);
|
|
53
|
+
if (!mode) return inactiveMode(explicitModeId);
|
|
54
|
+
return resolveConfiguredMode(provider, mode, settings);
|
|
55
|
+
}
|
|
56
|
+
const explicitLegacy = settings?.autoApprove;
|
|
57
|
+
const providerLegacyDefault = provider.settings?.autoApprove?.default;
|
|
58
|
+
const legacyActive = typeof explicitLegacy === "boolean" ? explicitLegacy : typeof providerLegacyDefault === "boolean" ? providerLegacyDefault : false;
|
|
59
|
+
if (!legacyActive) return inactiveMode();
|
|
60
|
+
if (!config) {
|
|
61
|
+
return { active: true, strategy: "pty-parse-default", modeId: "legacy" };
|
|
62
|
+
}
|
|
63
|
+
const defaultMode = config.modes.find((mode) => mode.id === config.default);
|
|
64
|
+
if (!defaultMode) return inactiveMode(config.default);
|
|
65
|
+
return resolveConfiguredMode(provider, defaultMode, settings);
|
|
66
|
+
}
|
|
67
|
+
function findProviderAutoApproveMode(provider, modeId) {
|
|
68
|
+
return provider?.autoApproveModes?.modes.find((mode) => mode.id === modeId);
|
|
69
|
+
}
|
|
70
|
+
var KNOWN_DANGEROUS_LAUNCH_ARGS;
|
|
71
|
+
var init_auto_approve_modes = __esm({
|
|
72
|
+
"src/providers/auto-approve-modes.ts"() {
|
|
73
|
+
"use strict";
|
|
74
|
+
KNOWN_DANGEROUS_LAUNCH_ARGS = /* @__PURE__ */ new Set([
|
|
75
|
+
"--dangerously-skip-permissions",
|
|
76
|
+
"--dangerously-bypass-approvals-and-sandbox",
|
|
77
|
+
"bypassPermissions",
|
|
78
|
+
"sandbox_mode=danger-full-access",
|
|
79
|
+
"approval_policy=never"
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
28
84
|
// src/repo-mesh-types.ts
|
|
29
85
|
function normalizeMeshSchedulingStrategy(value) {
|
|
30
86
|
if (typeof value !== "string") return DEFAULT_MESH_SCHEDULING_STRATEGY;
|
|
@@ -111,6 +167,11 @@ function mergeAndNormalizePolicy(base, patch) {
|
|
|
111
167
|
} else {
|
|
112
168
|
delete policy.autoConvergeCodeChange;
|
|
113
169
|
}
|
|
170
|
+
if (policy.delegatedWorkerDangerousModeAllow === true) {
|
|
171
|
+
policy.delegatedWorkerDangerousModeAllow = true;
|
|
172
|
+
} else {
|
|
173
|
+
delete policy.delegatedWorkerDangerousModeAllow;
|
|
174
|
+
}
|
|
114
175
|
if (policy.coordinatorIdlePushPolicy === "auto_silent_on_dispatch") {
|
|
115
176
|
policy.coordinatorIdlePushPolicy = "auto_silent_on_dispatch";
|
|
116
177
|
} else {
|
|
@@ -118,14 +179,38 @@ function mergeAndNormalizePolicy(base, patch) {
|
|
|
118
179
|
}
|
|
119
180
|
return policy;
|
|
120
181
|
}
|
|
121
|
-
function resolveDelegatedWorkerAutoApprove(meshPolicy, nodePolicy) {
|
|
182
|
+
function resolveDelegatedWorkerAutoApprove(meshPolicy, nodePolicy, provider, repoConfig, providerType) {
|
|
183
|
+
let enabled = true;
|
|
122
184
|
if (typeof nodePolicy?.delegatedWorkerAutoApprove === "boolean") {
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
185
|
+
enabled = nodePolicy.delegatedWorkerAutoApprove;
|
|
186
|
+
} else if (typeof meshPolicy?.delegatedWorkerAutoApprove === "boolean") {
|
|
187
|
+
enabled = meshPolicy.delegatedWorkerAutoApprove;
|
|
188
|
+
}
|
|
189
|
+
if (!enabled) return false;
|
|
190
|
+
const modes = provider?.autoApproveModes;
|
|
191
|
+
if (!modes) return true;
|
|
192
|
+
const requestedModeRaw = typeof providerType === "string" ? repoConfig?.providerDefaults?.autoApproveModes?.[providerType.trim()] : void 0;
|
|
193
|
+
const requestedModeId = typeof requestedModeRaw === "string" && requestedModeRaw.trim() ? requestedModeRaw.trim() : "";
|
|
194
|
+
const requestedMode = requestedModeId ? modes.modes.find((mode) => mode.id === requestedModeId) : void 0;
|
|
195
|
+
const selectedMode = requestedMode ?? modes.modes.find((mode) => mode.id === modes.default);
|
|
196
|
+
if (!selectedMode || selectedMode.strategy === "post-boot-command") return false;
|
|
197
|
+
const dangerousAllowed = resolveDelegatedWorkerDangerousModeAllow(meshPolicy, nodePolicy);
|
|
198
|
+
if (deriveAutoApproveModeRisk(selectedMode) === "dangerous" && !dangerousAllowed) {
|
|
199
|
+
const ptyFallback = modes.modes.find((mode) => mode.strategy === "pty-parse-default" && deriveAutoApproveModeRisk(mode) !== "dangerous");
|
|
200
|
+
return ptyFallback?.id || false;
|
|
201
|
+
}
|
|
202
|
+
return selectedMode.id;
|
|
203
|
+
}
|
|
204
|
+
function resolveDelegatedWorkerDangerousModeAllow(meshPolicy, nodePolicy) {
|
|
205
|
+
if (typeof nodePolicy?.delegatedWorkerDangerousModeAllow === "boolean") {
|
|
206
|
+
return nodePolicy.delegatedWorkerDangerousModeAllow;
|
|
207
|
+
}
|
|
208
|
+
return meshPolicy?.delegatedWorkerDangerousModeAllow === true;
|
|
209
|
+
}
|
|
210
|
+
function delegatedWorkerAutoApproveSettings(meshPolicy, nodePolicy, provider, repoConfig, providerType) {
|
|
211
|
+
const resolved = resolveDelegatedWorkerAutoApprove(meshPolicy, nodePolicy, provider, repoConfig, providerType);
|
|
212
|
+
const delegatedWorkerDangerousModeAllow = resolveDelegatedWorkerDangerousModeAllow(meshPolicy, nodePolicy);
|
|
213
|
+
return typeof resolved === "string" ? { autoApprove: void 0, autoApproveMode: resolved, delegatedWorkerDangerousModeAllow } : { autoApprove: resolved, autoApproveMode: void 0, delegatedWorkerDangerousModeAllow };
|
|
129
214
|
}
|
|
130
215
|
function resolveAllowSendKeysDestructive(meshPolicy, nodePolicy) {
|
|
131
216
|
if (typeof nodePolicy?.allowSendKeysDestructive === "boolean") {
|
|
@@ -155,6 +240,7 @@ var MESH_SCHEDULING_STRATEGIES, DEFAULT_MESH_SCHEDULING_STRATEGY, MESH_CONVERGE_
|
|
|
155
240
|
var init_repo_mesh_types = __esm({
|
|
156
241
|
"src/repo-mesh-types.ts"() {
|
|
157
242
|
"use strict";
|
|
243
|
+
init_auto_approve_modes();
|
|
158
244
|
MESH_SCHEDULING_STRATEGIES = [
|
|
159
245
|
"first_eligible",
|
|
160
246
|
"least_loaded",
|
|
@@ -182,6 +268,7 @@ var init_repo_mesh_types = __esm({
|
|
|
182
268
|
// any specific session manually; that override is preserved per-device.
|
|
183
269
|
spawnedSessionVisibility: "hidden",
|
|
184
270
|
delegatedWorkerAutoApprove: true,
|
|
271
|
+
delegatedWorkerDangerousModeAllow: false,
|
|
185
272
|
sessionCleanupOnNodeRemove: "preserve",
|
|
186
273
|
// MAGI auto-launches a worker session per pinned replica target with no idle
|
|
187
274
|
// session; those stay idle-LIVE after their turn. Default ON (stop_and_delete)
|
|
@@ -221,6 +308,267 @@ var init_repo_mesh_types = __esm({
|
|
|
221
308
|
}
|
|
222
309
|
});
|
|
223
310
|
|
|
311
|
+
// src/config/mesh-json-config.ts
|
|
312
|
+
var mesh_json_config_exports = {};
|
|
313
|
+
__export(mesh_json_config_exports, {
|
|
314
|
+
MESH_JSON_CONFIG_LOCATIONS: () => MESH_JSON_CONFIG_LOCATIONS,
|
|
315
|
+
MESH_JSON_CONFIG_SCHEMA: () => MESH_JSON_CONFIG_SCHEMA,
|
|
316
|
+
MESH_JSON_PROVIDER_DEFAULTS_EXAMPLE: () => MESH_JSON_PROVIDER_DEFAULTS_EXAMPLE,
|
|
317
|
+
applyRepoMeshConfig: () => applyRepoMeshConfig,
|
|
318
|
+
buildMeshJsonConfigScaffold: () => buildMeshJsonConfigScaffold,
|
|
319
|
+
loadRepoMeshJsonConfig: () => loadRepoMeshJsonConfig,
|
|
320
|
+
mergeEffectiveCoordinatorConfig: () => mergeEffectiveCoordinatorConfig,
|
|
321
|
+
mergeEffectiveOperatingNotes: () => mergeEffectiveOperatingNotes,
|
|
322
|
+
normalizeRepoMeshDeclarativeConfig: () => normalizeRepoMeshDeclarativeConfig,
|
|
323
|
+
serializeMeshJsonConfigScaffold: () => serializeMeshJsonConfigScaffold
|
|
324
|
+
});
|
|
325
|
+
import { existsSync, readFileSync } from "fs";
|
|
326
|
+
import { join } from "path";
|
|
327
|
+
import * as yaml from "js-yaml";
|
|
328
|
+
function isRecord(value) {
|
|
329
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
330
|
+
}
|
|
331
|
+
function parseConfigText(path46, text) {
|
|
332
|
+
if (/\.json$/i.test(path46)) return JSON.parse(text);
|
|
333
|
+
return yaml.load(text);
|
|
334
|
+
}
|
|
335
|
+
function normalizeOperatingNote(value) {
|
|
336
|
+
if (!isRecord(value)) return null;
|
|
337
|
+
const text = typeof value.text === "string" ? value.text.trim() : "";
|
|
338
|
+
if (!text) return null;
|
|
339
|
+
const category = value.category === "provider_quirk" || value.category === "pattern_to_avoid" || value.category === "recovery_lesson" ? value.category : void 0;
|
|
340
|
+
return {
|
|
341
|
+
text,
|
|
342
|
+
...category ? { category } : {},
|
|
343
|
+
...typeof value.createdAt === "string" ? { createdAt: value.createdAt } : {},
|
|
344
|
+
...typeof value.sourceCoordinator === "string" ? { sourceCoordinator: value.sourceCoordinator } : {},
|
|
345
|
+
// Operating-notes lifecycle: a repo-declared note may pin itself or set an
|
|
346
|
+
// explicit expiry, same as a runtime-recorded one. Phase 2 (b)/(c): it may
|
|
347
|
+
// also declare supersedes/subjectKey to retire an earlier note or group
|
|
348
|
+
// same-subject notes for folding.
|
|
349
|
+
...value.pinned === true ? { pinned: true } : {},
|
|
350
|
+
...typeof value.expiresAt === "string" ? { expiresAt: value.expiresAt } : {},
|
|
351
|
+
...typeof value.supersedes === "string" ? { supersedes: value.supersedes } : {},
|
|
352
|
+
...typeof value.subjectKey === "string" ? { subjectKey: value.subjectKey } : {}
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function normalizeRepoMeshDeclarativeConfig(parsed) {
|
|
356
|
+
const errors = [];
|
|
357
|
+
if (!isRecord(parsed)) return { valid: false, errors: ["config must be an object"] };
|
|
358
|
+
if (parsed.version !== 1) {
|
|
359
|
+
return { valid: false, errors: [`version must be 1 (got ${JSON.stringify(parsed.version)})`] };
|
|
360
|
+
}
|
|
361
|
+
const config = { version: 1 };
|
|
362
|
+
if (parsed.coordinator !== void 0) {
|
|
363
|
+
if (isRecord(parsed.coordinator)) {
|
|
364
|
+
const coord = {};
|
|
365
|
+
const c = parsed.coordinator;
|
|
366
|
+
if (typeof c.systemPromptOverride === "string") coord.systemPromptOverride = c.systemPromptOverride;
|
|
367
|
+
if (typeof c.systemPromptAppend === "string") coord.systemPromptAppend = c.systemPromptAppend;
|
|
368
|
+
if (Number.isFinite(Number(c.maxPromptChars))) coord.maxPromptChars = Number(c.maxPromptChars);
|
|
369
|
+
config.coordinator = coord;
|
|
370
|
+
} else {
|
|
371
|
+
errors.push("coordinator must be an object when provided");
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (parsed.operatingNotes !== void 0) {
|
|
375
|
+
if (Array.isArray(parsed.operatingNotes)) {
|
|
376
|
+
const notes = parsed.operatingNotes.map(normalizeOperatingNote).filter((n) => n !== null);
|
|
377
|
+
if (notes.length) config.operatingNotes = notes;
|
|
378
|
+
} else {
|
|
379
|
+
errors.push("operatingNotes must be an array when provided");
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (parsed.limits !== void 0) {
|
|
383
|
+
if (isRecord(parsed.limits)) {
|
|
384
|
+
const limits = {};
|
|
385
|
+
if (Number.isFinite(Number(parsed.limits.maxNoteChars))) limits.maxNoteChars = Number(parsed.limits.maxNoteChars);
|
|
386
|
+
if (Number.isFinite(Number(parsed.limits.maxNotes))) limits.maxNotes = Number(parsed.limits.maxNotes);
|
|
387
|
+
if (Object.keys(limits).length) config.limits = limits;
|
|
388
|
+
} else {
|
|
389
|
+
errors.push("limits must be an object when provided");
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (parsed.providerDefaults !== void 0) {
|
|
393
|
+
if (isRecord(parsed.providerDefaults)) {
|
|
394
|
+
const pd = {};
|
|
395
|
+
const rawModes = parsed.providerDefaults.autoApproveModes;
|
|
396
|
+
if (rawModes !== void 0) {
|
|
397
|
+
if (isRecord(rawModes)) {
|
|
398
|
+
const modes = {};
|
|
399
|
+
for (const [providerType, modeId] of Object.entries(rawModes)) {
|
|
400
|
+
const type = typeof providerType === "string" ? providerType.trim() : "";
|
|
401
|
+
const id = typeof modeId === "string" ? modeId.trim() : "";
|
|
402
|
+
if (type && id) modes[type] = id;
|
|
403
|
+
}
|
|
404
|
+
if (Object.keys(modes).length) pd.autoApproveModes = modes;
|
|
405
|
+
} else {
|
|
406
|
+
errors.push("providerDefaults.autoApproveModes must be an object when provided");
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (Object.keys(pd).length) config.providerDefaults = pd;
|
|
410
|
+
} else {
|
|
411
|
+
errors.push("providerDefaults must be an object when provided");
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return { valid: true, config, errors };
|
|
415
|
+
}
|
|
416
|
+
function loadRepoMeshJsonConfig(workspace) {
|
|
417
|
+
const bases = [];
|
|
418
|
+
const ws = typeof workspace === "string" ? workspace.trim() : "";
|
|
419
|
+
if (ws) bases.push(ws);
|
|
420
|
+
let cwd = "";
|
|
421
|
+
try {
|
|
422
|
+
cwd = process.cwd();
|
|
423
|
+
} catch {
|
|
424
|
+
}
|
|
425
|
+
if (cwd && cwd !== ws) bases.push(cwd);
|
|
426
|
+
for (const base of bases) {
|
|
427
|
+
for (const relative5 of MESH_JSON_CONFIG_LOCATIONS) {
|
|
428
|
+
const configPath = join(base, relative5);
|
|
429
|
+
if (!existsSync(configPath)) continue;
|
|
430
|
+
try {
|
|
431
|
+
const parsed = parseConfigText(configPath, readFileSync(configPath, "utf-8"));
|
|
432
|
+
const result = normalizeRepoMeshDeclarativeConfig(parsed);
|
|
433
|
+
if (!result.valid || !result.config) {
|
|
434
|
+
return { source: relative5, sourceType: "invalid", path: configPath, error: result.errors.join("; ") };
|
|
435
|
+
}
|
|
436
|
+
return { config: result.config, source: relative5, sourceType: "repo_file", path: configPath };
|
|
437
|
+
} catch (error) {
|
|
438
|
+
return { source: relative5, sourceType: "invalid", path: configPath, error: error?.message || String(error) };
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
source: "unavailable",
|
|
444
|
+
sourceType: "unavailable",
|
|
445
|
+
error: `No repo mesh config found. Checked: ${MESH_JSON_CONFIG_LOCATIONS.join(", ")}`
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
function mergeEffectiveCoordinatorConfig(repoCoord, localCoord) {
|
|
449
|
+
const out = { ...localCoord || {} };
|
|
450
|
+
const localOverride = localCoord?.systemPromptOverride?.trim();
|
|
451
|
+
const repoOverride = repoCoord?.systemPromptOverride?.trim();
|
|
452
|
+
if (localOverride) {
|
|
453
|
+
out.systemPromptOverride = localCoord.systemPromptOverride;
|
|
454
|
+
} else if (repoOverride) {
|
|
455
|
+
out.systemPromptOverride = repoCoord.systemPromptOverride;
|
|
456
|
+
} else {
|
|
457
|
+
delete out.systemPromptOverride;
|
|
458
|
+
}
|
|
459
|
+
const repoAppend = repoCoord?.systemPromptAppend?.trim() ? repoCoord.systemPromptAppend.trim() : "";
|
|
460
|
+
const localAppendRaw = localCoord?.systemPromptAppend ?? localCoord?.systemPromptSuffix;
|
|
461
|
+
const localAppend = localAppendRaw?.trim() ? localAppendRaw.trim() : "";
|
|
462
|
+
const stacked = [repoAppend, localAppend].filter(Boolean).join("\n\n");
|
|
463
|
+
if (stacked) {
|
|
464
|
+
out.systemPromptAppend = stacked;
|
|
465
|
+
delete out.systemPromptSuffix;
|
|
466
|
+
}
|
|
467
|
+
return out;
|
|
468
|
+
}
|
|
469
|
+
function mergeEffectiveOperatingNotes(repoNotes, ledgerNotes) {
|
|
470
|
+
const usable = (notes) => Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
|
|
471
|
+
const repo = usable(repoNotes);
|
|
472
|
+
const ledger = usable(ledgerNotes);
|
|
473
|
+
const ledgerTexts = new Set(ledger.map((n) => n.text.trim()));
|
|
474
|
+
const repoKept = repo.filter((n) => !ledgerTexts.has(n.text.trim()));
|
|
475
|
+
const merged = [...repoKept, ...ledger];
|
|
476
|
+
return merged.length ? merged : void 0;
|
|
477
|
+
}
|
|
478
|
+
function applyRepoMeshConfig(mesh, repoConfig) {
|
|
479
|
+
if (!repoConfig) return mesh;
|
|
480
|
+
return {
|
|
481
|
+
...mesh,
|
|
482
|
+
coordinator: mergeEffectiveCoordinatorConfig(repoConfig.coordinator, mesh.coordinator)
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function buildMeshJsonConfigScaffold(mesh) {
|
|
486
|
+
const scaffold = { version: 1 };
|
|
487
|
+
const coord = {};
|
|
488
|
+
const override = mesh.coordinator?.systemPromptOverride;
|
|
489
|
+
if (typeof override === "string" && override.trim()) coord.systemPromptOverride = override;
|
|
490
|
+
const append = mesh.coordinator?.systemPromptAppend ?? mesh.coordinator?.systemPromptSuffix;
|
|
491
|
+
if (typeof append === "string" && append.trim()) coord.systemPromptAppend = append;
|
|
492
|
+
if (Object.keys(coord).length) scaffold.coordinator = coord;
|
|
493
|
+
return scaffold;
|
|
494
|
+
}
|
|
495
|
+
function serializeMeshJsonConfigScaffold(config) {
|
|
496
|
+
return JSON.stringify(config, null, 2);
|
|
497
|
+
}
|
|
498
|
+
var MESH_JSON_CONFIG_LOCATIONS, MESH_JSON_CONFIG_SCHEMA, MESH_JSON_PROVIDER_DEFAULTS_EXAMPLE;
|
|
499
|
+
var init_mesh_json_config = __esm({
|
|
500
|
+
"src/config/mesh-json-config.ts"() {
|
|
501
|
+
"use strict";
|
|
502
|
+
MESH_JSON_CONFIG_LOCATIONS = [
|
|
503
|
+
".adhdev/mesh.json",
|
|
504
|
+
".adhdev/mesh.yaml",
|
|
505
|
+
".adhdev/mesh.yml"
|
|
506
|
+
];
|
|
507
|
+
MESH_JSON_CONFIG_SCHEMA = {
|
|
508
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
509
|
+
title: "ADHDev Repo Mesh Declarative Config",
|
|
510
|
+
type: "object",
|
|
511
|
+
additionalProperties: false,
|
|
512
|
+
required: ["version"],
|
|
513
|
+
properties: {
|
|
514
|
+
version: { const: 1 },
|
|
515
|
+
coordinator: {
|
|
516
|
+
type: "object",
|
|
517
|
+
additionalProperties: false,
|
|
518
|
+
properties: {
|
|
519
|
+
systemPromptOverride: { type: "string" },
|
|
520
|
+
systemPromptAppend: { type: "string" },
|
|
521
|
+
maxPromptChars: { type: "number", minimum: 1 }
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
operatingNotes: {
|
|
525
|
+
type: "array",
|
|
526
|
+
maxItems: 200,
|
|
527
|
+
items: {
|
|
528
|
+
type: "object",
|
|
529
|
+
additionalProperties: false,
|
|
530
|
+
required: ["text"],
|
|
531
|
+
properties: {
|
|
532
|
+
text: { type: "string", minLength: 1 },
|
|
533
|
+
category: { enum: ["provider_quirk", "pattern_to_avoid", "recovery_lesson"] },
|
|
534
|
+
createdAt: { type: "string" },
|
|
535
|
+
sourceCoordinator: { type: "string" }
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
},
|
|
539
|
+
limits: {
|
|
540
|
+
type: "object",
|
|
541
|
+
additionalProperties: false,
|
|
542
|
+
properties: {
|
|
543
|
+
maxNoteChars: { type: "number", minimum: 1 },
|
|
544
|
+
maxNotes: { type: "number", minimum: 1 }
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
providerDefaults: {
|
|
548
|
+
type: "object",
|
|
549
|
+
additionalProperties: false,
|
|
550
|
+
properties: {
|
|
551
|
+
// providerType → requested auto-approve mode ID. Mode IDs are
|
|
552
|
+
// validated against the live provider spec at resolve time; an
|
|
553
|
+
// unknown ID is ignored (provider default is used), so the schema
|
|
554
|
+
// only constrains the shape (string→string), not the ID values.
|
|
555
|
+
autoApproveModes: {
|
|
556
|
+
type: "object",
|
|
557
|
+
additionalProperties: { type: "string" }
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
MESH_JSON_PROVIDER_DEFAULTS_EXAMPLE = {
|
|
564
|
+
autoApproveModes: {
|
|
565
|
+
"claude-cli": "accept-edits",
|
|
566
|
+
"codex-cli": "auto"
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
224
572
|
// src/git/git-executor.ts
|
|
225
573
|
var git_executor_exports = {};
|
|
226
574
|
__export(git_executor_exports, {
|
|
@@ -437,10 +785,10 @@ function readInjected(value) {
|
|
|
437
785
|
}
|
|
438
786
|
function getDaemonBuildInfo() {
|
|
439
787
|
if (cached) return cached;
|
|
440
|
-
const commit = readInjected(true ? "
|
|
441
|
-
const commitShort = readInjected(true ? "
|
|
442
|
-
const version = readInjected(true ? "1.0.18-rc.
|
|
443
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
788
|
+
const commit = readInjected(true ? "56b83deb250a8ea89ba1a7ec587720e165d20062" : void 0) ?? "unknown";
|
|
789
|
+
const commitShort = readInjected(true ? "56b83deb" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
790
|
+
const version = readInjected(true ? "1.0.18-rc.18" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
791
|
+
const builtAt = readInjected(true ? "2026-07-23T06:00:17.638Z" : void 0);
|
|
444
792
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
445
793
|
return cached;
|
|
446
794
|
}
|
|
@@ -452,17 +800,17 @@ var init_build_info = __esm({
|
|
|
452
800
|
});
|
|
453
801
|
|
|
454
802
|
// src/git/change-impact-config.ts
|
|
455
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
456
|
-
import { join } from "path";
|
|
457
|
-
import * as
|
|
458
|
-
function
|
|
803
|
+
import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
|
|
804
|
+
import { join as join2 } from "path";
|
|
805
|
+
import * as yaml2 from "js-yaml";
|
|
806
|
+
function isRecord2(value) {
|
|
459
807
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
460
808
|
}
|
|
461
809
|
function isStringArray(value) {
|
|
462
810
|
return Array.isArray(value) && value.every((v) => typeof v === "string" && v.length > 0);
|
|
463
811
|
}
|
|
464
812
|
function validateTarget(value, key2, errors) {
|
|
465
|
-
if (!
|
|
813
|
+
if (!isRecord2(value)) {
|
|
466
814
|
errors.push(`impactTargets.${key2} must be an object`);
|
|
467
815
|
return void 0;
|
|
468
816
|
}
|
|
@@ -478,7 +826,7 @@ function validateTarget(value, key2, errors) {
|
|
|
478
826
|
}
|
|
479
827
|
function validateChangeImpactConfig(raw, source = "inline") {
|
|
480
828
|
const errors = [];
|
|
481
|
-
if (!
|
|
829
|
+
if (!isRecord2(raw)) {
|
|
482
830
|
return { valid: false, errors: [`${source}: config must be an object`] };
|
|
483
831
|
}
|
|
484
832
|
const config = {};
|
|
@@ -495,7 +843,7 @@ function validateChangeImpactConfig(raw, source = "inline") {
|
|
|
495
843
|
else errors.push("nonRuntimeRootFilePatterns must be an array of non-empty strings");
|
|
496
844
|
}
|
|
497
845
|
if (raw.impactTargets !== void 0) {
|
|
498
|
-
if (!
|
|
846
|
+
if (!isRecord2(raw.impactTargets)) {
|
|
499
847
|
errors.push("impactTargets must be an object");
|
|
500
848
|
} else {
|
|
501
849
|
const targets = {};
|
|
@@ -517,23 +865,23 @@ function validateChangeImpactConfig(raw, source = "inline") {
|
|
|
517
865
|
}
|
|
518
866
|
return { valid: errors.length === 0, errors, config: errors.length === 0 ? config : void 0 };
|
|
519
867
|
}
|
|
520
|
-
function
|
|
868
|
+
function parseConfigText2(path46, text) {
|
|
521
869
|
if (/\.json$/i.test(path46)) return JSON.parse(text);
|
|
522
|
-
return
|
|
870
|
+
return yaml2.load(text);
|
|
523
871
|
}
|
|
524
872
|
function loadChangeImpactConfig(repoRoot) {
|
|
525
873
|
for (const relative5 of CHANGE_IMPACT_CONFIG_LOCATIONS) {
|
|
526
|
-
const configPath =
|
|
527
|
-
if (!
|
|
874
|
+
const configPath = join2(repoRoot, relative5);
|
|
875
|
+
if (!existsSync2(configPath)) continue;
|
|
528
876
|
try {
|
|
529
|
-
const text =
|
|
877
|
+
const text = readFileSync2(configPath, "utf-8");
|
|
530
878
|
let mtimeMs = 0;
|
|
531
879
|
try {
|
|
532
880
|
mtimeMs = statSync(configPath).mtimeMs;
|
|
533
881
|
} catch {
|
|
534
882
|
mtimeMs = text.length;
|
|
535
883
|
}
|
|
536
|
-
const parsed =
|
|
884
|
+
const parsed = parseConfigText2(configPath, text);
|
|
537
885
|
const validation = validateChangeImpactConfig(parsed, relative5);
|
|
538
886
|
if (!validation.valid) {
|
|
539
887
|
return {
|
|
@@ -602,10 +950,10 @@ function suggestChangeImpactConfig(repoRoot) {
|
|
|
602
950
|
const daemon = /* @__PURE__ */ new Set();
|
|
603
951
|
const web = /* @__PURE__ */ new Set();
|
|
604
952
|
const unclassified = [];
|
|
605
|
-
const roots = ["packages",
|
|
953
|
+
const roots = ["packages", join2("oss", "packages")];
|
|
606
954
|
for (const rel of roots) {
|
|
607
|
-
const packagesRoot =
|
|
608
|
-
if (!
|
|
955
|
+
const packagesRoot = join2(repoRoot, rel);
|
|
956
|
+
if (!existsSync2(packagesRoot)) continue;
|
|
609
957
|
for (const name of listPackageDirs(packagesRoot)) {
|
|
610
958
|
if (/(^web[-.]|[-.]web$)/i.test(name) || /dashboard|frontend|ui$/i.test(name)) {
|
|
611
959
|
web.add(name);
|
|
@@ -693,7 +1041,7 @@ var init_change_impact_config = __esm({
|
|
|
693
1041
|
});
|
|
694
1042
|
|
|
695
1043
|
// src/git/git-status.ts
|
|
696
|
-
import { join as
|
|
1044
|
+
import { join as join3 } from "path";
|
|
697
1045
|
function statusCacheKey(workspace, options) {
|
|
698
1046
|
const includeSubmodules = options.includeSubmodules !== false;
|
|
699
1047
|
const refreshUpstream = options.refreshUpstream === true;
|
|
@@ -876,7 +1224,7 @@ async function refineVerdictThroughSubmodules(repoPath, fromRef, toRef, options,
|
|
|
876
1224
|
}
|
|
877
1225
|
let subVerdict;
|
|
878
1226
|
try {
|
|
879
|
-
subVerdict = await classifyChangedPackages(
|
|
1227
|
+
subVerdict = await classifyChangedPackages(join3(repoPath, subPath), range.from, range.to, {
|
|
880
1228
|
...options,
|
|
881
1229
|
// Do not force the root's injected config onto the submodule — let it resolve
|
|
882
1230
|
// its own .adhdev/change-impact.* (or fall back to defaults).
|
|
@@ -1641,8 +1989,8 @@ __export(config_exports, {
|
|
|
1641
1989
|
updateConfig: () => updateConfig
|
|
1642
1990
|
});
|
|
1643
1991
|
import { homedir } from "os";
|
|
1644
|
-
import { join as
|
|
1645
|
-
import { existsSync as
|
|
1992
|
+
import { join as join4 } from "path";
|
|
1993
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync, chmodSync } from "fs";
|
|
1646
1994
|
import { randomUUID } from "crypto";
|
|
1647
1995
|
function resolveProviderSourceMode(providerSourceMode, legacyDisableUpstream) {
|
|
1648
1996
|
if (providerSourceMode === "normal" || providerSourceMode === "no-upstream") {
|
|
@@ -1739,25 +2087,25 @@ function ensureMachineId(config) {
|
|
|
1739
2087
|
}
|
|
1740
2088
|
function getConfigDir() {
|
|
1741
2089
|
const override = process.env.ADHDEV_CONFIG_DIR;
|
|
1742
|
-
const dir = override && override.trim() ? override.trim() :
|
|
1743
|
-
if (!
|
|
2090
|
+
const dir = override && override.trim() ? override.trim() : join4(homedir(), ".adhdev");
|
|
2091
|
+
if (!existsSync3(dir)) {
|
|
1744
2092
|
mkdirSync(dir, { recursive: true });
|
|
1745
2093
|
}
|
|
1746
2094
|
return dir;
|
|
1747
2095
|
}
|
|
1748
2096
|
function getDaemonDataDir() {
|
|
1749
|
-
const dir =
|
|
1750
|
-
if (!
|
|
2097
|
+
const dir = join4(getConfigDir(), "daemon");
|
|
2098
|
+
if (!existsSync3(dir)) {
|
|
1751
2099
|
mkdirSync(dir, { recursive: true });
|
|
1752
2100
|
}
|
|
1753
2101
|
return dir;
|
|
1754
2102
|
}
|
|
1755
2103
|
function getConfigPath() {
|
|
1756
|
-
return
|
|
2104
|
+
return join4(getConfigDir(), "config.json");
|
|
1757
2105
|
}
|
|
1758
2106
|
function migrateStateToStateFile(raw) {
|
|
1759
|
-
const statePath =
|
|
1760
|
-
if (
|
|
2107
|
+
const statePath = join4(getConfigDir(), "state.json");
|
|
2108
|
+
if (existsSync3(statePath)) return;
|
|
1761
2109
|
const recentActivity = Array.isArray(raw.recentActivity) ? raw.recentActivity : [];
|
|
1762
2110
|
const savedProviderSessions = Array.isArray(raw.savedProviderSessions) ? raw.savedProviderSessions : [];
|
|
1763
2111
|
const legacySessionReads = isPlainObject(raw.recentSessionReads) ? raw.recentSessionReads : {};
|
|
@@ -1781,7 +2129,7 @@ function migrateStateToStateFile(raw) {
|
|
|
1781
2129
|
}
|
|
1782
2130
|
function loadConfig() {
|
|
1783
2131
|
const configPath = getConfigPath();
|
|
1784
|
-
if (!
|
|
2132
|
+
if (!existsSync3(configPath)) {
|
|
1785
2133
|
const initialized = ensureMachineId({ ...DEFAULT_CONFIG });
|
|
1786
2134
|
try {
|
|
1787
2135
|
saveConfig(initialized.config);
|
|
@@ -1790,7 +2138,7 @@ function loadConfig() {
|
|
|
1790
2138
|
return initialized.config;
|
|
1791
2139
|
}
|
|
1792
2140
|
try {
|
|
1793
|
-
const raw =
|
|
2141
|
+
const raw = readFileSync3(configPath, "utf-8");
|
|
1794
2142
|
const parsed = JSON.parse(raw);
|
|
1795
2143
|
migrateStateToStateFile(parsed);
|
|
1796
2144
|
const normalizedInput = normalizeConfig(parsed);
|
|
@@ -1812,7 +2160,7 @@ function saveConfig(config) {
|
|
|
1812
2160
|
const configPath = getConfigPath();
|
|
1813
2161
|
const dir = getConfigDir();
|
|
1814
2162
|
const normalized = normalizeConfig(config);
|
|
1815
|
-
if (!
|
|
2163
|
+
if (!existsSync3(dir)) {
|
|
1816
2164
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
1817
2165
|
}
|
|
1818
2166
|
writeFileSync(configPath, JSON.stringify(normalized, null, 2), { encoding: "utf-8", mode: 384 });
|
|
@@ -1888,7 +2236,7 @@ __export(git_worktree_exports, {
|
|
|
1888
2236
|
});
|
|
1889
2237
|
import * as path4 from "path";
|
|
1890
2238
|
import { mkdir } from "fs/promises";
|
|
1891
|
-
import { existsSync as
|
|
2239
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1892
2240
|
import { execFile as execFile2 } from "child_process";
|
|
1893
2241
|
import { promisify as promisify2 } from "util";
|
|
1894
2242
|
function resolveWorktreePath(repoRoot, meshName, branch) {
|
|
@@ -1981,7 +2329,7 @@ async function createWorktree(opts) {
|
|
|
1981
2329
|
const { repoRoot, branch, baseBranch, meshName } = opts;
|
|
1982
2330
|
const remote = (opts.remote || "origin").trim() || "origin";
|
|
1983
2331
|
const targetDir = opts.targetDir || resolveWorktreePath(repoRoot, meshName, branch);
|
|
1984
|
-
if (
|
|
2332
|
+
if (existsSync4(targetDir)) {
|
|
1985
2333
|
throw new Error(`Worktree target directory already exists: ${targetDir}`);
|
|
1986
2334
|
}
|
|
1987
2335
|
await mkdir(path4.dirname(targetDir), { recursive: true });
|
|
@@ -2006,7 +2354,7 @@ async function createWorktree(opts) {
|
|
|
2006
2354
|
} catch (error) {
|
|
2007
2355
|
const stderr = typeof error.stderr === "string" ? error.stderr : "";
|
|
2008
2356
|
if (/already exists/i.test(stderr)) {
|
|
2009
|
-
if (
|
|
2357
|
+
if (existsSync4(targetDir)) {
|
|
2010
2358
|
throw new Error(`Worktree target directory was created concurrently: ${targetDir}`);
|
|
2011
2359
|
}
|
|
2012
2360
|
throw new Error(`Branch '${branch}' already exists or is checked out in another worktree`);
|
|
@@ -2021,7 +2369,7 @@ async function createWorktree(opts) {
|
|
|
2021
2369
|
};
|
|
2022
2370
|
}
|
|
2023
2371
|
async function removeWorktree(repoRoot, worktreePath, opts = {}) {
|
|
2024
|
-
if (!
|
|
2372
|
+
if (!existsSync4(worktreePath)) {
|
|
2025
2373
|
await pruneWorktrees(repoRoot);
|
|
2026
2374
|
return { success: true, removedPath: worktreePath };
|
|
2027
2375
|
}
|
|
@@ -3276,17 +3624,17 @@ __export(mesh_config_exports, {
|
|
|
3276
3624
|
updateMesh: () => updateMesh,
|
|
3277
3625
|
updateNode: () => updateNode
|
|
3278
3626
|
});
|
|
3279
|
-
import { existsSync as
|
|
3280
|
-
import { join as
|
|
3627
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
3628
|
+
import { join as join7 } from "path";
|
|
3281
3629
|
import { randomBytes, randomUUID as randomUUID3 } from "crypto";
|
|
3282
3630
|
function getMeshConfigPath() {
|
|
3283
|
-
return
|
|
3631
|
+
return join7(getConfigDir(), "meshes.json");
|
|
3284
3632
|
}
|
|
3285
3633
|
function loadMeshConfig() {
|
|
3286
3634
|
const path46 = getMeshConfigPath();
|
|
3287
|
-
if (!
|
|
3635
|
+
if (!existsSync6(path46)) return { meshes: [] };
|
|
3288
3636
|
try {
|
|
3289
|
-
const raw = JSON.parse(
|
|
3637
|
+
const raw = JSON.parse(readFileSync4(path46, "utf-8"));
|
|
3290
3638
|
if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
|
|
3291
3639
|
const config = raw;
|
|
3292
3640
|
const migrated = migrateLoadedMeshConfig(config);
|
|
@@ -4890,8 +5238,8 @@ var init_contracts = __esm({
|
|
|
4890
5238
|
});
|
|
4891
5239
|
|
|
4892
5240
|
// src/mesh/mesh-events-pending.ts
|
|
4893
|
-
import { appendFileSync, existsSync as
|
|
4894
|
-
import { join as
|
|
5241
|
+
import { appendFileSync, existsSync as existsSync8, readFileSync as readFileSync5, renameSync as renameSync2, statSync as statSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
5242
|
+
import { join as join9 } from "path";
|
|
4895
5243
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
4896
5244
|
function normalizeCoordinatorDaemonIds(coordinatorDaemonId) {
|
|
4897
5245
|
return expandDaemonIdForms(coordinatorDaemonId);
|
|
@@ -5114,9 +5462,9 @@ function getPendingEventsPath(meshId, coordinatorDaemonId) {
|
|
|
5114
5462
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5115
5463
|
if (coordinatorDaemonId) {
|
|
5116
5464
|
const safeDaemon = coordinatorDaemonId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5117
|
-
return
|
|
5465
|
+
return join9(getLedgerDir(), `${safe}-${safeDaemon}.pending-events.jsonl`);
|
|
5118
5466
|
}
|
|
5119
|
-
return
|
|
5467
|
+
return join9(getLedgerDir(), `${safe}.pending-events.jsonl`);
|
|
5120
5468
|
}
|
|
5121
5469
|
function readPendingMeshCoordinatorEventsFromDisk(meshId, coordinatorDaemonId) {
|
|
5122
5470
|
if (!meshId) return [];
|
|
@@ -5125,9 +5473,9 @@ function readPendingMeshCoordinatorEventsFromDisk(meshId, coordinatorDaemonId) {
|
|
|
5125
5473
|
const paths = primaryDaemonId ? [getPendingEventsPath(meshId, primaryDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
5126
5474
|
const events = [];
|
|
5127
5475
|
for (const path46 of paths) {
|
|
5128
|
-
if (!
|
|
5476
|
+
if (!existsSync8(path46)) continue;
|
|
5129
5477
|
try {
|
|
5130
|
-
const raw =
|
|
5478
|
+
const raw = readFileSync5(path46, "utf-8");
|
|
5131
5479
|
const parsed = raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
5132
5480
|
try {
|
|
5133
5481
|
return [JSON.parse(line)];
|
|
@@ -5217,9 +5565,9 @@ function prunePendingMeshCoordinatorEventsRetention() {
|
|
|
5217
5565
|
}
|
|
5218
5566
|
function trimPendingEventsIfNeeded(path46) {
|
|
5219
5567
|
try {
|
|
5220
|
-
if (!
|
|
5568
|
+
if (!existsSync8(path46)) return;
|
|
5221
5569
|
if (statSync4(path46).size <= MAX_PENDING_EVENTS_BYTES) return;
|
|
5222
|
-
const lines =
|
|
5570
|
+
const lines = readFileSync5(path46, "utf-8").split("\n").filter(Boolean);
|
|
5223
5571
|
if (lines.length <= MAX_PENDING_EVENTS_KEEP) return;
|
|
5224
5572
|
const dropped = lines.slice(0, lines.length - MAX_PENDING_EVENTS_KEEP);
|
|
5225
5573
|
for (const line of dropped) {
|
|
@@ -5386,7 +5734,7 @@ function atomicDrainFile(path46) {
|
|
|
5386
5734
|
return null;
|
|
5387
5735
|
}
|
|
5388
5736
|
try {
|
|
5389
|
-
const content =
|
|
5737
|
+
const content = readFileSync5(tmpPath, "utf-8");
|
|
5390
5738
|
try {
|
|
5391
5739
|
unlinkSync2(tmpPath);
|
|
5392
5740
|
} catch {
|
|
@@ -5409,7 +5757,7 @@ function selectiveDrainFile(path46, predicate) {
|
|
|
5409
5757
|
}
|
|
5410
5758
|
let content;
|
|
5411
5759
|
try {
|
|
5412
|
-
content =
|
|
5760
|
+
content = readFileSync5(tmpPath, "utf-8");
|
|
5413
5761
|
} catch {
|
|
5414
5762
|
try {
|
|
5415
5763
|
unlinkSync2(tmpPath);
|
|
@@ -5440,7 +5788,7 @@ function selectiveDrainFile(path46, predicate) {
|
|
|
5440
5788
|
unlinkSync2(tmpPath);
|
|
5441
5789
|
} catch {
|
|
5442
5790
|
try {
|
|
5443
|
-
if (
|
|
5791
|
+
if (existsSync8(tmpPath) && !existsSync8(path46)) renameSync2(tmpPath, path46);
|
|
5444
5792
|
} catch {
|
|
5445
5793
|
}
|
|
5446
5794
|
return [];
|
|
@@ -5668,7 +6016,7 @@ function clearPendingMeshCoordinatorEvents(meshId, coordinatorDaemonId) {
|
|
|
5668
6016
|
}
|
|
5669
6017
|
const paths = coordinatorDaemonId ? [getPendingEventsPath(meshId, coordinatorDaemonId), getPendingEventsPath(meshId)] : [getPendingEventsPath(meshId)];
|
|
5670
6018
|
for (const path46 of paths) {
|
|
5671
|
-
if (
|
|
6019
|
+
if (existsSync8(path46)) try {
|
|
5672
6020
|
unlinkSync2(path46);
|
|
5673
6021
|
} catch {
|
|
5674
6022
|
}
|
|
@@ -7018,8 +7366,8 @@ var init_mesh_work_queue = __esm({
|
|
|
7018
7366
|
});
|
|
7019
7367
|
|
|
7020
7368
|
// src/mesh/mesh-runtime-store.ts
|
|
7021
|
-
import { existsSync as
|
|
7022
|
-
import { dirname as dirname2, join as
|
|
7369
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync3, statSync as statSync5, unlinkSync as unlinkSync3 } from "fs";
|
|
7370
|
+
import { dirname as dirname2, join as join10 } from "path";
|
|
7023
7371
|
function loadDatabaseCtor() {
|
|
7024
7372
|
if (DatabaseCtor) return DatabaseCtor;
|
|
7025
7373
|
DatabaseCtor = loadBetterSqlite3();
|
|
@@ -7029,13 +7377,13 @@ function safeMeshId(meshId) {
|
|
|
7029
7377
|
return meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7030
7378
|
}
|
|
7031
7379
|
function legacyQueuePath(meshId) {
|
|
7032
|
-
return
|
|
7380
|
+
return join10(getLedgerDir(), `${safeMeshId(meshId)}.queue.json`);
|
|
7033
7381
|
}
|
|
7034
7382
|
function cleanupStrayRootRuntimeDb(canonicalPath) {
|
|
7035
7383
|
try {
|
|
7036
|
-
const strayPath =
|
|
7384
|
+
const strayPath = join10(getConfigDir(), "mesh-runtime.db");
|
|
7037
7385
|
if (strayPath === canonicalPath) return;
|
|
7038
|
-
if (!
|
|
7386
|
+
if (!existsSync9(strayPath)) return;
|
|
7039
7387
|
if (statSync5(strayPath).size !== 0) return;
|
|
7040
7388
|
unlinkSync3(strayPath);
|
|
7041
7389
|
if (!loggedStrayCleanup) {
|
|
@@ -7051,16 +7399,16 @@ function cleanupStrayRootRuntimeDb(canonicalPath) {
|
|
|
7051
7399
|
}
|
|
7052
7400
|
function meshRuntimeStorePath() {
|
|
7053
7401
|
const dir = getLedgerDir();
|
|
7054
|
-
const nextPath =
|
|
7402
|
+
const nextPath = join10(dir, "mesh-runtime.db");
|
|
7055
7403
|
cleanupStrayRootRuntimeDb(nextPath);
|
|
7056
|
-
if (
|
|
7057
|
-
const legacyPath =
|
|
7058
|
-
if (!
|
|
7404
|
+
if (existsSync9(nextPath)) return nextPath;
|
|
7405
|
+
const legacyPath = join10(dir, "beads.db");
|
|
7406
|
+
if (!existsSync9(legacyPath)) return nextPath;
|
|
7059
7407
|
try {
|
|
7060
7408
|
renameSync3(legacyPath, nextPath);
|
|
7061
7409
|
for (const suffix of ["-wal", "-shm"]) {
|
|
7062
7410
|
const legacyCompanion = `${legacyPath}${suffix}`;
|
|
7063
|
-
if (
|
|
7411
|
+
if (existsSync9(legacyCompanion)) {
|
|
7064
7412
|
renameSync3(legacyCompanion, `${nextPath}${suffix}`);
|
|
7065
7413
|
}
|
|
7066
7414
|
}
|
|
@@ -7072,7 +7420,7 @@ function meshRuntimeStorePath() {
|
|
|
7072
7420
|
`Legacy beads.db\u2192mesh-runtime.db migration failed; using existing DB in-place to avoid data loss: ${err?.message || err}`
|
|
7073
7421
|
);
|
|
7074
7422
|
}
|
|
7075
|
-
return
|
|
7423
|
+
return existsSync9(nextPath) ? nextPath : legacyPath;
|
|
7076
7424
|
}
|
|
7077
7425
|
return nextPath;
|
|
7078
7426
|
}
|
|
@@ -7126,7 +7474,7 @@ var init_mesh_runtime_store = __esm({
|
|
|
7126
7474
|
// 50 MB
|
|
7127
7475
|
constructor(dbPath) {
|
|
7128
7476
|
const dir = dirname2(dbPath);
|
|
7129
|
-
if (!
|
|
7477
|
+
if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
|
|
7130
7478
|
this.dbPath = dbPath;
|
|
7131
7479
|
this.db = new (loadDatabaseCtor())(dbPath);
|
|
7132
7480
|
this.db.pragma("journal_mode = WAL");
|
|
@@ -7505,7 +7853,7 @@ var init_mesh_runtime_store = __esm({
|
|
|
7505
7853
|
this.walWriteCounter = 0;
|
|
7506
7854
|
try {
|
|
7507
7855
|
const walPath = `${this.dbPath}-wal`;
|
|
7508
|
-
if (!
|
|
7856
|
+
if (!existsSync9(walPath)) return;
|
|
7509
7857
|
const size = statSync5(walPath).size;
|
|
7510
7858
|
if (size < _MeshRuntimeStore.WAL_MAX_BYTES) return;
|
|
7511
7859
|
process.stderr.write(
|
|
@@ -7522,9 +7870,9 @@ var init_mesh_runtime_store = __esm({
|
|
|
7522
7870
|
const count = this.db.prepare("SELECT COUNT(*) AS count FROM mesh_queue WHERE mesh_id = ?").get(meshId);
|
|
7523
7871
|
if (count.count > 0) return;
|
|
7524
7872
|
const path46 = legacyQueuePath(meshId);
|
|
7525
|
-
if (!
|
|
7873
|
+
if (!existsSync9(path46)) return;
|
|
7526
7874
|
try {
|
|
7527
|
-
const entries = JSON.parse(
|
|
7875
|
+
const entries = JSON.parse(readFileSync6(path46, "utf-8"));
|
|
7528
7876
|
if (!Array.isArray(entries)) return;
|
|
7529
7877
|
const insert = this.db.prepare(`
|
|
7530
7878
|
INSERT OR REPLACE INTO mesh_queue (
|
|
@@ -8955,8 +9303,8 @@ __export(mesh_ledger_exports, {
|
|
|
8955
9303
|
readOperatingNotes: () => readOperatingNotes,
|
|
8956
9304
|
tombstoneOperatingNote: () => tombstoneOperatingNote
|
|
8957
9305
|
});
|
|
8958
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
8959
|
-
import { join as
|
|
9306
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync7, statSync as statSync6, renameSync as renameSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
9307
|
+
import { join as join11 } from "path";
|
|
8960
9308
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
8961
9309
|
import { EventEmitter } from "events";
|
|
8962
9310
|
function isIntentionalCleanupStopEntry(entry) {
|
|
@@ -8979,35 +9327,35 @@ function isNoteExpired(note, now) {
|
|
|
8979
9327
|
return now - created >= ttlDays * MS_PER_DAY;
|
|
8980
9328
|
}
|
|
8981
9329
|
function getLedgerDir() {
|
|
8982
|
-
const dir =
|
|
8983
|
-
if (!
|
|
9330
|
+
const dir = join11(getConfigDir(), LEDGER_DIR_NAME);
|
|
9331
|
+
if (!existsSync10(dir)) {
|
|
8984
9332
|
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
8985
9333
|
}
|
|
8986
9334
|
return dir;
|
|
8987
9335
|
}
|
|
8988
9336
|
function getLedgerPath(meshId) {
|
|
8989
9337
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8990
|
-
return
|
|
9338
|
+
return join11(getLedgerDir(), `${safe}.jsonl`);
|
|
8991
9339
|
}
|
|
8992
9340
|
function getRotatedPath(meshId, index) {
|
|
8993
9341
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8994
|
-
return
|
|
9342
|
+
return join11(getLedgerDir(), `${safe}.${index}.jsonl`);
|
|
8995
9343
|
}
|
|
8996
9344
|
function getArchivePath(meshId) {
|
|
8997
9345
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8998
|
-
return
|
|
9346
|
+
return join11(getLedgerDir(), `${safe}.archive.jsonl`);
|
|
8999
9347
|
}
|
|
9000
9348
|
function getRotatedArchivePath(meshId, index) {
|
|
9001
9349
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9002
|
-
return
|
|
9350
|
+
return join11(getLedgerDir(), `${safe}.archive.${index}.jsonl`);
|
|
9003
9351
|
}
|
|
9004
9352
|
function getArchivedCountsPath(meshId) {
|
|
9005
9353
|
const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9006
|
-
return
|
|
9354
|
+
return join11(getLedgerDir(), `${safe}.archived-counts.json`);
|
|
9007
9355
|
}
|
|
9008
9356
|
function rotateArchiveFile(meshId, archivePath) {
|
|
9009
9357
|
let index = 1;
|
|
9010
|
-
while (
|
|
9358
|
+
while (existsSync10(getRotatedArchivePath(meshId, index))) {
|
|
9011
9359
|
index++;
|
|
9012
9360
|
if (index > 5) break;
|
|
9013
9361
|
}
|
|
@@ -9021,9 +9369,9 @@ function rotateArchiveFile(meshId, archivePath) {
|
|
|
9021
9369
|
}
|
|
9022
9370
|
function readArchivedCounts(meshId) {
|
|
9023
9371
|
const path46 = getArchivedCountsPath(meshId);
|
|
9024
|
-
if (!
|
|
9372
|
+
if (!existsSync10(path46)) return { taskCompleted: 0, taskFailed: 0, taskStalled: 0, recoveryAttempted: 0, totalArchived: 0, lastArchivedAt: "" };
|
|
9025
9373
|
try {
|
|
9026
|
-
return JSON.parse(
|
|
9374
|
+
return JSON.parse(readFileSync7(path46, "utf-8"));
|
|
9027
9375
|
} catch {
|
|
9028
9376
|
return { taskCompleted: 0, taskFailed: 0, taskStalled: 0, recoveryAttempted: 0, totalArchived: 0, lastArchivedAt: "" };
|
|
9029
9377
|
}
|
|
@@ -9062,7 +9410,7 @@ Valid status values: \`completed\` | \`failed\` | \`blocked\` | \`partial\`.`;
|
|
|
9062
9410
|
}
|
|
9063
9411
|
function compactLedger(meshId) {
|
|
9064
9412
|
const filePath = getLedgerPath(meshId);
|
|
9065
|
-
if (!
|
|
9413
|
+
if (!existsSync10(filePath)) return { archivedCount: 0, retainedCount: 0 };
|
|
9066
9414
|
const cutoff = Date.now() - ARCHIVE_TERMINAL_OLDER_THAN_MS;
|
|
9067
9415
|
const entries = readLedgerEntries(meshId);
|
|
9068
9416
|
const keep = [];
|
|
@@ -9077,7 +9425,7 @@ function compactLedger(meshId) {
|
|
|
9077
9425
|
if (archive.length === 0) return { archivedCount: 0, retainedCount: keep.length };
|
|
9078
9426
|
const archivePath = getArchivePath(meshId);
|
|
9079
9427
|
try {
|
|
9080
|
-
if (
|
|
9428
|
+
if (existsSync10(archivePath) && statSync6(archivePath).size > 50 * 1024 * 1024) {
|
|
9081
9429
|
rotateArchiveFile(meshId, archivePath);
|
|
9082
9430
|
}
|
|
9083
9431
|
const archiveLines = archive.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
@@ -9268,7 +9616,7 @@ function appendLedgerEntry(meshId, partial) {
|
|
|
9268
9616
|
...partial
|
|
9269
9617
|
};
|
|
9270
9618
|
const filePath = getLedgerPath(meshId);
|
|
9271
|
-
if (
|
|
9619
|
+
if (existsSync10(filePath)) {
|
|
9272
9620
|
try {
|
|
9273
9621
|
const stat2 = statSync6(filePath);
|
|
9274
9622
|
if (stat2.size >= MAX_FILE_SIZE_BYTES) {
|
|
@@ -9456,10 +9804,10 @@ function appendRemoteLedgerEntries(meshId, entries) {
|
|
|
9456
9804
|
}
|
|
9457
9805
|
function readLedgerFile(meshId) {
|
|
9458
9806
|
const filePath = getLedgerPath(meshId);
|
|
9459
|
-
if (!
|
|
9807
|
+
if (!existsSync10(filePath)) return [];
|
|
9460
9808
|
let content;
|
|
9461
9809
|
try {
|
|
9462
|
-
content =
|
|
9810
|
+
content = readFileSync7(filePath, "utf-8");
|
|
9463
9811
|
} catch {
|
|
9464
9812
|
return [];
|
|
9465
9813
|
}
|
|
@@ -9724,7 +10072,7 @@ function getSessionRecoveryContext(meshId, opts) {
|
|
|
9724
10072
|
}
|
|
9725
10073
|
function rotateLedgerFile(meshId, currentPath) {
|
|
9726
10074
|
let index = 1;
|
|
9727
|
-
while (
|
|
10075
|
+
while (existsSync10(getRotatedPath(meshId, index))) {
|
|
9728
10076
|
index++;
|
|
9729
10077
|
if (index > 10) break;
|
|
9730
10078
|
}
|
|
@@ -10729,10 +11077,10 @@ __export(mesh_coordinator_exports, {
|
|
|
10729
11077
|
resolveMeshCoordinatorSetup: () => resolveMeshCoordinatorSetup,
|
|
10730
11078
|
stripCoordinatorWrapperFile: () => stripCoordinatorWrapperFile
|
|
10731
11079
|
});
|
|
10732
|
-
import { existsSync as
|
|
11080
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
10733
11081
|
import * as os4 from "os";
|
|
10734
11082
|
import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
|
|
10735
|
-
import { basename as basename2, isAbsolute as isAbsolute4, join as
|
|
11083
|
+
import { basename as basename2, isAbsolute as isAbsolute4, join as join13, resolve as resolve7 } from "path";
|
|
10736
11084
|
function isHermesProvider(provider, cliType) {
|
|
10737
11085
|
const type = cliType?.trim() || provider?.type?.trim() || "";
|
|
10738
11086
|
return type === HERMES_CLI_TYPE;
|
|
@@ -10752,7 +11100,7 @@ function resolveHermesMeshCoordinatorSetup(options) {
|
|
|
10752
11100
|
reason: "Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode"
|
|
10753
11101
|
};
|
|
10754
11102
|
}
|
|
10755
|
-
const configPath =
|
|
11103
|
+
const configPath = join13(resolveHermesCoordinatorHome(options.meshId, options.workspace), "config.yaml");
|
|
10756
11104
|
if (!configPath.trim()) {
|
|
10757
11105
|
return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace);
|
|
10758
11106
|
}
|
|
@@ -10899,14 +11247,14 @@ function resolveHermesCoordinatorHome(meshId, workspace) {
|
|
|
10899
11247
|
const key2 = `${meshId || "mesh"}
|
|
10900
11248
|
${resolve7(workspace || os4.tmpdir())}`;
|
|
10901
11249
|
const hash = shortHash(key2);
|
|
10902
|
-
return
|
|
11250
|
+
return join13(os4.tmpdir(), `adhdev-hermes-mesh-coordinator-${hash}`);
|
|
10903
11251
|
}
|
|
10904
11252
|
function resolveMcpConfigPath(configPath, workspace) {
|
|
10905
11253
|
const trimmed = configPath.trim();
|
|
10906
11254
|
if (trimmed === "~") return os4.homedir();
|
|
10907
|
-
if (trimmed.startsWith("~/")) return
|
|
11255
|
+
if (trimmed.startsWith("~/")) return join13(os4.homedir(), trimmed.slice(2));
|
|
10908
11256
|
if (isAbsolute4(trimmed)) return trimmed;
|
|
10909
|
-
return
|
|
11257
|
+
return join13(workspace, trimmed);
|
|
10910
11258
|
}
|
|
10911
11259
|
function resolveAdhdevMcpServerLaunch(options) {
|
|
10912
11260
|
const directEntryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath);
|
|
@@ -10977,7 +11325,7 @@ function applyInjectionRule(systemPrompt, injection, ctx) {
|
|
|
10977
11325
|
}
|
|
10978
11326
|
case "context_file": {
|
|
10979
11327
|
if (!injection.path) return {};
|
|
10980
|
-
const target = isAbsolute4(injection.path) ? injection.path :
|
|
11328
|
+
const target = isAbsolute4(injection.path) ? injection.path : join13(ctx.workspace, injection.path);
|
|
10981
11329
|
const wrapper = injection.wrapper && injection.wrapper.includes("{prompt}") ? injection.wrapper : "{prompt}";
|
|
10982
11330
|
const managedNote = "> _Managed by adhdev mesh coordinator \u2014 do not hand-edit this block. Changes inside the sentinels are overwritten on next coordinator launch._";
|
|
10983
11331
|
const promptWithNote = `${managedNote}
|
|
@@ -10986,8 +11334,8 @@ ${systemPrompt}`;
|
|
|
10986
11334
|
const rendered = wrapper.replace(/\{prompt\}/g, promptWithNote);
|
|
10987
11335
|
const sentinel = wrapper.split("{prompt}")[0].trim();
|
|
10988
11336
|
try {
|
|
10989
|
-
if (
|
|
10990
|
-
const existing =
|
|
11337
|
+
if (existsSync11(target)) {
|
|
11338
|
+
const existing = readFileSync9(target, "utf-8");
|
|
10991
11339
|
if (sentinel && existing.includes(sentinel)) {
|
|
10992
11340
|
const closing = wrapper.split("{prompt}")[1]?.trim();
|
|
10993
11341
|
const safeOpen = sentinel.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
@@ -11017,8 +11365,8 @@ function stripCoordinatorWrapperFile(filePath) {
|
|
|
11017
11365
|
const OPEN = "<!-- adhdev-mesh-coordinator-prompt -->";
|
|
11018
11366
|
const CLOSE = "<!-- /adhdev-mesh-coordinator-prompt -->";
|
|
11019
11367
|
try {
|
|
11020
|
-
if (!
|
|
11021
|
-
const existing =
|
|
11368
|
+
if (!existsSync11(filePath)) return;
|
|
11369
|
+
const existing = readFileSync9(filePath, "utf-8");
|
|
11022
11370
|
const openIdx = existing.indexOf(OPEN);
|
|
11023
11371
|
if (openIdx < 0) return;
|
|
11024
11372
|
const closeIdx = existing.indexOf(CLOSE, openIdx);
|
|
@@ -11121,16 +11469,16 @@ var init_mesh_coordinator = __esm({
|
|
|
11121
11469
|
});
|
|
11122
11470
|
|
|
11123
11471
|
// src/mesh/coordinator-registry.ts
|
|
11124
|
-
import { join as
|
|
11125
|
-
import { existsSync as
|
|
11472
|
+
import { join as join14 } from "path";
|
|
11473
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
11126
11474
|
function getRegistryPath() {
|
|
11127
|
-
return
|
|
11475
|
+
return join14(getDaemonDataDir(), "mesh-coordinators.json");
|
|
11128
11476
|
}
|
|
11129
11477
|
function loadMeshCoordinatorRegistry() {
|
|
11130
11478
|
const path46 = getRegistryPath();
|
|
11131
|
-
if (!
|
|
11479
|
+
if (!existsSync12(path46)) return;
|
|
11132
11480
|
try {
|
|
11133
|
-
const raw = JSON.parse(
|
|
11481
|
+
const raw = JSON.parse(readFileSync10(path46, "utf-8"));
|
|
11134
11482
|
if (!Array.isArray(raw)) return;
|
|
11135
11483
|
_registry.clear();
|
|
11136
11484
|
for (const entry of raw) {
|
|
@@ -11186,9 +11534,9 @@ var init_coordinator_registry = __esm({
|
|
|
11186
11534
|
});
|
|
11187
11535
|
|
|
11188
11536
|
// src/mesh/refine-config.ts
|
|
11189
|
-
import { existsSync as
|
|
11190
|
-
import { join as
|
|
11191
|
-
import * as
|
|
11537
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
|
|
11538
|
+
import { join as join15 } from "path";
|
|
11539
|
+
import * as yaml3 from "js-yaml";
|
|
11192
11540
|
function isMeshConfigRecord(value) {
|
|
11193
11541
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
11194
11542
|
}
|
|
@@ -11272,14 +11620,14 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
11272
11620
|
const rejectedCommands = [];
|
|
11273
11621
|
const deprecationWarnings = [];
|
|
11274
11622
|
let bootstrapMode = "inherit";
|
|
11275
|
-
if (!
|
|
11623
|
+
if (!isRecord3(config)) return { valid: false, errors: ["config must be an object"], bootstrapCommands, commands, rejectedCommands, bootstrapMode, deprecationWarnings };
|
|
11276
11624
|
if (config.version !== 1) errors.push("version must be 1");
|
|
11277
11625
|
if (config.allowAutoPublishSubmoduleMainCommits !== void 0 && typeof config.allowAutoPublishSubmoduleMainCommits !== "boolean") {
|
|
11278
11626
|
errors.push("allowAutoPublishSubmoduleMainCommits must be a boolean when provided");
|
|
11279
11627
|
}
|
|
11280
11628
|
const validation = config.validation;
|
|
11281
|
-
if (validation !== void 0 && !
|
|
11282
|
-
const rawBootstrapMode =
|
|
11629
|
+
if (validation !== void 0 && !isRecord3(validation)) errors.push("validation must be an object");
|
|
11630
|
+
const rawBootstrapMode = isRecord3(validation) ? validation.bootstrap : void 0;
|
|
11283
11631
|
if (rawBootstrapMode !== void 0) {
|
|
11284
11632
|
if (rawBootstrapMode === "inherit" || rawBootstrapMode === "skip") {
|
|
11285
11633
|
bootstrapMode = rawBootstrapMode;
|
|
@@ -11287,8 +11635,8 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
11287
11635
|
errors.push("validation.bootstrap must be 'inherit' or 'skip' when provided");
|
|
11288
11636
|
}
|
|
11289
11637
|
}
|
|
11290
|
-
const rawCommands =
|
|
11291
|
-
const rawBootstrapCommands =
|
|
11638
|
+
const rawCommands = isRecord3(validation) ? validation.commands : void 0;
|
|
11639
|
+
const rawBootstrapCommands = isRecord3(validation) ? validation.bootstrapCommands : void 0;
|
|
11292
11640
|
if (rawCommands !== void 0 && !Array.isArray(rawCommands)) errors.push("validation.commands must be an array");
|
|
11293
11641
|
if (rawBootstrapCommands !== void 0 && !Array.isArray(rawBootstrapCommands)) errors.push("validation.bootstrapCommands must be an array");
|
|
11294
11642
|
if (Array.isArray(rawBootstrapCommands) && rawBootstrapCommands.length > 0) {
|
|
@@ -11311,9 +11659,9 @@ function validateMeshRefineConfig(config, source = "inline") {
|
|
|
11311
11659
|
if (rejectedCommands.length) errors.push("one or more validation commands are invalid");
|
|
11312
11660
|
return { valid: errors.length === 0, errors, bootstrapCommands, commands, rejectedCommands, bootstrapMode, deprecationWarnings };
|
|
11313
11661
|
}
|
|
11314
|
-
function
|
|
11662
|
+
function parseConfigText3(path46, text) {
|
|
11315
11663
|
if (/\.json$/i.test(path46)) return JSON.parse(text);
|
|
11316
|
-
return
|
|
11664
|
+
return yaml3.load(text);
|
|
11317
11665
|
}
|
|
11318
11666
|
function loadMeshRefineConfig(mesh, workspace) {
|
|
11319
11667
|
const policy = mesh?.policy && typeof mesh.policy === "object" && !Array.isArray(mesh.policy) ? mesh.policy : {};
|
|
@@ -11324,10 +11672,10 @@ function loadMeshRefineConfig(mesh, workspace) {
|
|
|
11324
11672
|
return { config: inline, source: "mesh.policy.refineConfig", sourceType: "mesh_policy" };
|
|
11325
11673
|
}
|
|
11326
11674
|
for (const relative5 of MESH_REFINE_CONFIG_LOCATIONS) {
|
|
11327
|
-
const configPath =
|
|
11328
|
-
if (!
|
|
11675
|
+
const configPath = join15(workspace, relative5);
|
|
11676
|
+
if (!existsSync13(configPath)) continue;
|
|
11329
11677
|
try {
|
|
11330
|
-
const parsed =
|
|
11678
|
+
const parsed = parseConfigText3(configPath, readFileSync11(configPath, "utf-8"));
|
|
11331
11679
|
const validation = validateMeshRefineConfig(parsed, relative5);
|
|
11332
11680
|
if (!validation.valid) return { source: relative5, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
|
|
11333
11681
|
return { config: parsed, source: relative5, sourceType: "repo_file", path: configPath };
|
|
@@ -11343,20 +11691,20 @@ function loadMeshRefineConfig(mesh, workspace) {
|
|
|
11343
11691
|
}
|
|
11344
11692
|
function readPackageScripts(workspace) {
|
|
11345
11693
|
try {
|
|
11346
|
-
const parsed = JSON.parse(
|
|
11347
|
-
return
|
|
11694
|
+
const parsed = JSON.parse(readFileSync11(join15(workspace, "package.json"), "utf-8"));
|
|
11695
|
+
return isRecord3(parsed?.scripts) ? parsed.scripts : {};
|
|
11348
11696
|
} catch {
|
|
11349
11697
|
return {};
|
|
11350
11698
|
}
|
|
11351
11699
|
}
|
|
11352
11700
|
function collectProjectContextSuggestions(mesh) {
|
|
11353
11701
|
const commands = mesh?.projectContext?.commands;
|
|
11354
|
-
if (!
|
|
11702
|
+
if (!isRecord3(commands)) return [];
|
|
11355
11703
|
const suggestions = [];
|
|
11356
11704
|
for (const category of MESH_REFINE_VALIDATION_CATEGORIES) {
|
|
11357
11705
|
const entries = Array.isArray(commands[category]) ? commands[category] : [];
|
|
11358
11706
|
for (const entry of entries) {
|
|
11359
|
-
if (
|
|
11707
|
+
if (isRecord3(entry) && typeof entry.command === "string") suggestions.push({ command: entry.command, category });
|
|
11360
11708
|
}
|
|
11361
11709
|
}
|
|
11362
11710
|
return suggestions;
|
|
@@ -11418,7 +11766,7 @@ function resolveMeshRefineValidationPlan(mesh, workspace) {
|
|
|
11418
11766
|
unavailableReason: validation.commands.length ? void 0 : "validation_unavailable: repo mesh/refine config has no validation.commands"
|
|
11419
11767
|
};
|
|
11420
11768
|
}
|
|
11421
|
-
var MESH_REFINE_VALIDATION_CATEGORIES, MESH_REFINE_VALIDATION_SCOPES, MESH_REFINE_CONFIG_LOCATIONS, MESH_REFINE_CONFIG_SCHEMA, SHELL_METACHAR_RE, SAFE_TOKEN_RE, SAFE_WIN32_EXEC_TOKEN_RE,
|
|
11769
|
+
var MESH_REFINE_VALIDATION_CATEGORIES, MESH_REFINE_VALIDATION_SCOPES, MESH_REFINE_CONFIG_LOCATIONS, MESH_REFINE_CONFIG_SCHEMA, SHELL_METACHAR_RE, SAFE_TOKEN_RE, SAFE_WIN32_EXEC_TOKEN_RE, isRecord3;
|
|
11422
11770
|
var init_refine_config = __esm({
|
|
11423
11771
|
"src/mesh/refine-config.ts"() {
|
|
11424
11772
|
"use strict";
|
|
@@ -11512,13 +11860,13 @@ var init_refine_config = __esm({
|
|
|
11512
11860
|
SHELL_METACHAR_RE = /[;&|<>`$\n\r'"]/;
|
|
11513
11861
|
SAFE_TOKEN_RE = /^[A-Za-z0-9_@./:=+-]+$/;
|
|
11514
11862
|
SAFE_WIN32_EXEC_TOKEN_RE = /^[A-Za-z0-9_@./:=+\\-]+$/;
|
|
11515
|
-
|
|
11863
|
+
isRecord3 = isMeshConfigRecord;
|
|
11516
11864
|
}
|
|
11517
11865
|
});
|
|
11518
11866
|
|
|
11519
11867
|
// src/cli-adapters/resolve-executable.ts
|
|
11520
11868
|
import { execFileSync } from "child_process";
|
|
11521
|
-
import { existsSync as
|
|
11869
|
+
import { existsSync as existsSync14 } from "fs";
|
|
11522
11870
|
import * as path10 from "path";
|
|
11523
11871
|
function resolveWin32GlobalBin(trimmed) {
|
|
11524
11872
|
if (path10.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\")) {
|
|
@@ -11534,7 +11882,7 @@ function resolveWin32GlobalBin(trimmed) {
|
|
|
11534
11882
|
if (!dir) continue;
|
|
11535
11883
|
for (const ext of WIN_EXEC_EXT) {
|
|
11536
11884
|
const full = path10.join(dir, trimmed + ext);
|
|
11537
|
-
if (
|
|
11885
|
+
if (existsSync14(full)) return full;
|
|
11538
11886
|
}
|
|
11539
11887
|
}
|
|
11540
11888
|
return null;
|
|
@@ -11551,7 +11899,7 @@ function resolveWin32Executable(command) {
|
|
|
11551
11899
|
if (process.platform !== "win32") return command;
|
|
11552
11900
|
const trimmed = (command || "").trim();
|
|
11553
11901
|
if (!trimmed) return command;
|
|
11554
|
-
if (path10.isAbsolute(trimmed) &&
|
|
11902
|
+
if (path10.isAbsolute(trimmed) && existsSync14(trimmed)) return trimmed;
|
|
11555
11903
|
try {
|
|
11556
11904
|
const out = execFileSync("where", [trimmed], {
|
|
11557
11905
|
encoding: "utf8",
|
|
@@ -11627,12 +11975,12 @@ __export(worktree_bootstrap_config_exports, {
|
|
|
11627
11975
|
shouldDeferDispatchForBootstrap: () => shouldDeferDispatchForBootstrap,
|
|
11628
11976
|
validateMeshWorktreeBootstrapConfig: () => validateMeshWorktreeBootstrapConfig
|
|
11629
11977
|
});
|
|
11630
|
-
import { existsSync as
|
|
11631
|
-
import { join as
|
|
11978
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
|
|
11979
|
+
import { join as join17, resolve as pathResolve } from "path";
|
|
11632
11980
|
import { execFile as execFile3, execFileSync as execFileSync2 } from "child_process";
|
|
11633
11981
|
import { createHash as createHash2 } from "crypto";
|
|
11634
11982
|
import { promisify as promisify3 } from "util";
|
|
11635
|
-
import * as
|
|
11983
|
+
import * as yaml4 from "js-yaml";
|
|
11636
11984
|
function getRegisteredSubmodulePaths(workspace) {
|
|
11637
11985
|
const paths = /* @__PURE__ */ new Set();
|
|
11638
11986
|
try {
|
|
@@ -11747,7 +12095,7 @@ function isWorktreeBootstrapStaleRunning(node, nowMs = Date.now()) {
|
|
|
11747
12095
|
if (!Number.isFinite(startedMs)) return false;
|
|
11748
12096
|
if (nowMs - startedMs <= WORKTREE_BOOTSTRAP_STALE_RUNNING_MS) return false;
|
|
11749
12097
|
const workspace = typeof node?.workspace === "string" ? node.workspace.trim() : "";
|
|
11750
|
-
if (!workspace || !
|
|
12098
|
+
if (!workspace || !existsSync15(workspace)) return false;
|
|
11751
12099
|
try {
|
|
11752
12100
|
const out = execFileSync2(resolveWin32Executable("git"), ["status", "--porcelain"], {
|
|
11753
12101
|
cwd: workspace,
|
|
@@ -11768,9 +12116,9 @@ function shouldDeferDispatchForBootstrap(node, nowMs = Date.now()) {
|
|
|
11768
12116
|
if (node?.worktreeBootstrap?.status !== "running") return false;
|
|
11769
12117
|
return !isWorktreeBootstrapStaleRunning(node, nowMs);
|
|
11770
12118
|
}
|
|
11771
|
-
function
|
|
12119
|
+
function parseConfigText4(path46, text) {
|
|
11772
12120
|
if (/\.json$/i.test(path46)) return JSON.parse(text);
|
|
11773
|
-
return
|
|
12121
|
+
return yaml4.load(text);
|
|
11774
12122
|
}
|
|
11775
12123
|
function truncateOutput(value) {
|
|
11776
12124
|
const text = typeof value === "string" ? value : value == null ? "" : String(value);
|
|
@@ -11810,10 +12158,10 @@ function loadMeshWorktreeBootstrapConfig(mesh, workspace) {
|
|
|
11810
12158
|
return { config: inline, source: "mesh.policy.worktreeBootstrapConfig", sourceType: "mesh_policy" };
|
|
11811
12159
|
}
|
|
11812
12160
|
for (const relative5 of MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS) {
|
|
11813
|
-
const configPath =
|
|
11814
|
-
if (!
|
|
12161
|
+
const configPath = join17(workspace, relative5);
|
|
12162
|
+
if (!existsSync15(configPath)) continue;
|
|
11815
12163
|
try {
|
|
11816
|
-
const parsed =
|
|
12164
|
+
const parsed = parseConfigText4(configPath, readFileSync12(configPath, "utf-8"));
|
|
11817
12165
|
const validation = validateMeshWorktreeBootstrapConfig(parsed, relative5);
|
|
11818
12166
|
if (!validation.valid) return { source: relative5, sourceType: "invalid", path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join("; ")) };
|
|
11819
12167
|
return { config: parsed, source: relative5, sourceType: "repo_file", path: configPath };
|
|
@@ -11826,9 +12174,9 @@ function loadMeshWorktreeBootstrapConfig(mesh, workspace) {
|
|
|
11826
12174
|
function computeStaleInputsDigest(workspace, staleInputs) {
|
|
11827
12175
|
const digest = {};
|
|
11828
12176
|
for (const relative5 of staleInputs ?? []) {
|
|
11829
|
-
const filePath =
|
|
12177
|
+
const filePath = join17(workspace, relative5);
|
|
11830
12178
|
try {
|
|
11831
|
-
digest[relative5] = createHash2("sha256").update(
|
|
12179
|
+
digest[relative5] = createHash2("sha256").update(readFileSync12(filePath)).digest("hex");
|
|
11832
12180
|
} catch {
|
|
11833
12181
|
digest[relative5] = "absent";
|
|
11834
12182
|
}
|
|
@@ -11899,10 +12247,10 @@ async function runMeshWorktreeBootstrap(mesh, workspace) {
|
|
|
11899
12247
|
staleInputs: loaded.config.staleInputs
|
|
11900
12248
|
};
|
|
11901
12249
|
const staleInputPaths = loaded.config.staleInputs ?? [];
|
|
11902
|
-
const initiallyAbsent = staleInputPaths.filter((p) => !
|
|
12250
|
+
const initiallyAbsent = staleInputPaths.filter((p) => !existsSync15(join17(workspace, p)));
|
|
11903
12251
|
for (const command of validation.commands) {
|
|
11904
12252
|
if (initiallyAbsent.length > 0) {
|
|
11905
|
-
const appearedNow = initiallyAbsent.filter((p) =>
|
|
12253
|
+
const appearedNow = initiallyAbsent.filter((p) => existsSync15(join17(workspace, p)));
|
|
11906
12254
|
if (appearedNow.length > 0) {
|
|
11907
12255
|
state.status = "stale";
|
|
11908
12256
|
state.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -12025,224 +12373,6 @@ var init_worktree_bootstrap_config = __esm({
|
|
|
12025
12373
|
}
|
|
12026
12374
|
});
|
|
12027
12375
|
|
|
12028
|
-
// src/config/mesh-json-config.ts
|
|
12029
|
-
var mesh_json_config_exports = {};
|
|
12030
|
-
__export(mesh_json_config_exports, {
|
|
12031
|
-
MESH_JSON_CONFIG_LOCATIONS: () => MESH_JSON_CONFIG_LOCATIONS,
|
|
12032
|
-
MESH_JSON_CONFIG_SCHEMA: () => MESH_JSON_CONFIG_SCHEMA,
|
|
12033
|
-
applyRepoMeshConfig: () => applyRepoMeshConfig,
|
|
12034
|
-
buildMeshJsonConfigScaffold: () => buildMeshJsonConfigScaffold,
|
|
12035
|
-
loadRepoMeshJsonConfig: () => loadRepoMeshJsonConfig,
|
|
12036
|
-
mergeEffectiveCoordinatorConfig: () => mergeEffectiveCoordinatorConfig,
|
|
12037
|
-
mergeEffectiveOperatingNotes: () => mergeEffectiveOperatingNotes,
|
|
12038
|
-
normalizeRepoMeshDeclarativeConfig: () => normalizeRepoMeshDeclarativeConfig,
|
|
12039
|
-
serializeMeshJsonConfigScaffold: () => serializeMeshJsonConfigScaffold
|
|
12040
|
-
});
|
|
12041
|
-
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
|
|
12042
|
-
import { join as join17 } from "path";
|
|
12043
|
-
import * as yaml4 from "js-yaml";
|
|
12044
|
-
function isRecord3(value) {
|
|
12045
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
12046
|
-
}
|
|
12047
|
-
function parseConfigText4(path46, text) {
|
|
12048
|
-
if (/\.json$/i.test(path46)) return JSON.parse(text);
|
|
12049
|
-
return yaml4.load(text);
|
|
12050
|
-
}
|
|
12051
|
-
function normalizeOperatingNote(value) {
|
|
12052
|
-
if (!isRecord3(value)) return null;
|
|
12053
|
-
const text = typeof value.text === "string" ? value.text.trim() : "";
|
|
12054
|
-
if (!text) return null;
|
|
12055
|
-
const category = value.category === "provider_quirk" || value.category === "pattern_to_avoid" || value.category === "recovery_lesson" ? value.category : void 0;
|
|
12056
|
-
return {
|
|
12057
|
-
text,
|
|
12058
|
-
...category ? { category } : {},
|
|
12059
|
-
...typeof value.createdAt === "string" ? { createdAt: value.createdAt } : {},
|
|
12060
|
-
...typeof value.sourceCoordinator === "string" ? { sourceCoordinator: value.sourceCoordinator } : {},
|
|
12061
|
-
// Operating-notes lifecycle: a repo-declared note may pin itself or set an
|
|
12062
|
-
// explicit expiry, same as a runtime-recorded one. Phase 2 (b)/(c): it may
|
|
12063
|
-
// also declare supersedes/subjectKey to retire an earlier note or group
|
|
12064
|
-
// same-subject notes for folding.
|
|
12065
|
-
...value.pinned === true ? { pinned: true } : {},
|
|
12066
|
-
...typeof value.expiresAt === "string" ? { expiresAt: value.expiresAt } : {},
|
|
12067
|
-
...typeof value.supersedes === "string" ? { supersedes: value.supersedes } : {},
|
|
12068
|
-
...typeof value.subjectKey === "string" ? { subjectKey: value.subjectKey } : {}
|
|
12069
|
-
};
|
|
12070
|
-
}
|
|
12071
|
-
function normalizeRepoMeshDeclarativeConfig(parsed) {
|
|
12072
|
-
const errors = [];
|
|
12073
|
-
if (!isRecord3(parsed)) return { valid: false, errors: ["config must be an object"] };
|
|
12074
|
-
if (parsed.version !== 1) {
|
|
12075
|
-
return { valid: false, errors: [`version must be 1 (got ${JSON.stringify(parsed.version)})`] };
|
|
12076
|
-
}
|
|
12077
|
-
const config = { version: 1 };
|
|
12078
|
-
if (parsed.coordinator !== void 0) {
|
|
12079
|
-
if (isRecord3(parsed.coordinator)) {
|
|
12080
|
-
const coord = {};
|
|
12081
|
-
const c = parsed.coordinator;
|
|
12082
|
-
if (typeof c.systemPromptOverride === "string") coord.systemPromptOverride = c.systemPromptOverride;
|
|
12083
|
-
if (typeof c.systemPromptAppend === "string") coord.systemPromptAppend = c.systemPromptAppend;
|
|
12084
|
-
if (Number.isFinite(Number(c.maxPromptChars))) coord.maxPromptChars = Number(c.maxPromptChars);
|
|
12085
|
-
config.coordinator = coord;
|
|
12086
|
-
} else {
|
|
12087
|
-
errors.push("coordinator must be an object when provided");
|
|
12088
|
-
}
|
|
12089
|
-
}
|
|
12090
|
-
if (parsed.operatingNotes !== void 0) {
|
|
12091
|
-
if (Array.isArray(parsed.operatingNotes)) {
|
|
12092
|
-
const notes = parsed.operatingNotes.map(normalizeOperatingNote).filter((n) => n !== null);
|
|
12093
|
-
if (notes.length) config.operatingNotes = notes;
|
|
12094
|
-
} else {
|
|
12095
|
-
errors.push("operatingNotes must be an array when provided");
|
|
12096
|
-
}
|
|
12097
|
-
}
|
|
12098
|
-
if (parsed.limits !== void 0) {
|
|
12099
|
-
if (isRecord3(parsed.limits)) {
|
|
12100
|
-
const limits = {};
|
|
12101
|
-
if (Number.isFinite(Number(parsed.limits.maxNoteChars))) limits.maxNoteChars = Number(parsed.limits.maxNoteChars);
|
|
12102
|
-
if (Number.isFinite(Number(parsed.limits.maxNotes))) limits.maxNotes = Number(parsed.limits.maxNotes);
|
|
12103
|
-
if (Object.keys(limits).length) config.limits = limits;
|
|
12104
|
-
} else {
|
|
12105
|
-
errors.push("limits must be an object when provided");
|
|
12106
|
-
}
|
|
12107
|
-
}
|
|
12108
|
-
return { valid: true, config, errors };
|
|
12109
|
-
}
|
|
12110
|
-
function loadRepoMeshJsonConfig(workspace) {
|
|
12111
|
-
const bases = [];
|
|
12112
|
-
const ws = typeof workspace === "string" ? workspace.trim() : "";
|
|
12113
|
-
if (ws) bases.push(ws);
|
|
12114
|
-
let cwd = "";
|
|
12115
|
-
try {
|
|
12116
|
-
cwd = process.cwd();
|
|
12117
|
-
} catch {
|
|
12118
|
-
}
|
|
12119
|
-
if (cwd && cwd !== ws) bases.push(cwd);
|
|
12120
|
-
for (const base of bases) {
|
|
12121
|
-
for (const relative5 of MESH_JSON_CONFIG_LOCATIONS) {
|
|
12122
|
-
const configPath = join17(base, relative5);
|
|
12123
|
-
if (!existsSync15(configPath)) continue;
|
|
12124
|
-
try {
|
|
12125
|
-
const parsed = parseConfigText4(configPath, readFileSync12(configPath, "utf-8"));
|
|
12126
|
-
const result = normalizeRepoMeshDeclarativeConfig(parsed);
|
|
12127
|
-
if (!result.valid || !result.config) {
|
|
12128
|
-
return { source: relative5, sourceType: "invalid", path: configPath, error: result.errors.join("; ") };
|
|
12129
|
-
}
|
|
12130
|
-
return { config: result.config, source: relative5, sourceType: "repo_file", path: configPath };
|
|
12131
|
-
} catch (error) {
|
|
12132
|
-
return { source: relative5, sourceType: "invalid", path: configPath, error: error?.message || String(error) };
|
|
12133
|
-
}
|
|
12134
|
-
}
|
|
12135
|
-
}
|
|
12136
|
-
return {
|
|
12137
|
-
source: "unavailable",
|
|
12138
|
-
sourceType: "unavailable",
|
|
12139
|
-
error: `No repo mesh config found. Checked: ${MESH_JSON_CONFIG_LOCATIONS.join(", ")}`
|
|
12140
|
-
};
|
|
12141
|
-
}
|
|
12142
|
-
function mergeEffectiveCoordinatorConfig(repoCoord, localCoord) {
|
|
12143
|
-
const out = { ...localCoord || {} };
|
|
12144
|
-
const localOverride = localCoord?.systemPromptOverride?.trim();
|
|
12145
|
-
const repoOverride = repoCoord?.systemPromptOverride?.trim();
|
|
12146
|
-
if (localOverride) {
|
|
12147
|
-
out.systemPromptOverride = localCoord.systemPromptOverride;
|
|
12148
|
-
} else if (repoOverride) {
|
|
12149
|
-
out.systemPromptOverride = repoCoord.systemPromptOverride;
|
|
12150
|
-
} else {
|
|
12151
|
-
delete out.systemPromptOverride;
|
|
12152
|
-
}
|
|
12153
|
-
const repoAppend = repoCoord?.systemPromptAppend?.trim() ? repoCoord.systemPromptAppend.trim() : "";
|
|
12154
|
-
const localAppendRaw = localCoord?.systemPromptAppend ?? localCoord?.systemPromptSuffix;
|
|
12155
|
-
const localAppend = localAppendRaw?.trim() ? localAppendRaw.trim() : "";
|
|
12156
|
-
const stacked = [repoAppend, localAppend].filter(Boolean).join("\n\n");
|
|
12157
|
-
if (stacked) {
|
|
12158
|
-
out.systemPromptAppend = stacked;
|
|
12159
|
-
delete out.systemPromptSuffix;
|
|
12160
|
-
}
|
|
12161
|
-
return out;
|
|
12162
|
-
}
|
|
12163
|
-
function mergeEffectiveOperatingNotes(repoNotes, ledgerNotes) {
|
|
12164
|
-
const usable = (notes) => Array.isArray(notes) ? notes.filter((n) => n && typeof n.text === "string" && n.text.trim()) : [];
|
|
12165
|
-
const repo = usable(repoNotes);
|
|
12166
|
-
const ledger = usable(ledgerNotes);
|
|
12167
|
-
const ledgerTexts = new Set(ledger.map((n) => n.text.trim()));
|
|
12168
|
-
const repoKept = repo.filter((n) => !ledgerTexts.has(n.text.trim()));
|
|
12169
|
-
const merged = [...repoKept, ...ledger];
|
|
12170
|
-
return merged.length ? merged : void 0;
|
|
12171
|
-
}
|
|
12172
|
-
function applyRepoMeshConfig(mesh, repoConfig) {
|
|
12173
|
-
if (!repoConfig) return mesh;
|
|
12174
|
-
return {
|
|
12175
|
-
...mesh,
|
|
12176
|
-
coordinator: mergeEffectiveCoordinatorConfig(repoConfig.coordinator, mesh.coordinator)
|
|
12177
|
-
};
|
|
12178
|
-
}
|
|
12179
|
-
function buildMeshJsonConfigScaffold(mesh) {
|
|
12180
|
-
const scaffold = { version: 1 };
|
|
12181
|
-
const coord = {};
|
|
12182
|
-
const override = mesh.coordinator?.systemPromptOverride;
|
|
12183
|
-
if (typeof override === "string" && override.trim()) coord.systemPromptOverride = override;
|
|
12184
|
-
const append = mesh.coordinator?.systemPromptAppend ?? mesh.coordinator?.systemPromptSuffix;
|
|
12185
|
-
if (typeof append === "string" && append.trim()) coord.systemPromptAppend = append;
|
|
12186
|
-
if (Object.keys(coord).length) scaffold.coordinator = coord;
|
|
12187
|
-
return scaffold;
|
|
12188
|
-
}
|
|
12189
|
-
function serializeMeshJsonConfigScaffold(config) {
|
|
12190
|
-
return JSON.stringify(config, null, 2);
|
|
12191
|
-
}
|
|
12192
|
-
var MESH_JSON_CONFIG_LOCATIONS, MESH_JSON_CONFIG_SCHEMA;
|
|
12193
|
-
var init_mesh_json_config = __esm({
|
|
12194
|
-
"src/config/mesh-json-config.ts"() {
|
|
12195
|
-
"use strict";
|
|
12196
|
-
MESH_JSON_CONFIG_LOCATIONS = [
|
|
12197
|
-
".adhdev/mesh.json",
|
|
12198
|
-
".adhdev/mesh.yaml",
|
|
12199
|
-
".adhdev/mesh.yml"
|
|
12200
|
-
];
|
|
12201
|
-
MESH_JSON_CONFIG_SCHEMA = {
|
|
12202
|
-
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
12203
|
-
title: "ADHDev Repo Mesh Declarative Config",
|
|
12204
|
-
type: "object",
|
|
12205
|
-
additionalProperties: false,
|
|
12206
|
-
required: ["version"],
|
|
12207
|
-
properties: {
|
|
12208
|
-
version: { const: 1 },
|
|
12209
|
-
coordinator: {
|
|
12210
|
-
type: "object",
|
|
12211
|
-
additionalProperties: false,
|
|
12212
|
-
properties: {
|
|
12213
|
-
systemPromptOverride: { type: "string" },
|
|
12214
|
-
systemPromptAppend: { type: "string" },
|
|
12215
|
-
maxPromptChars: { type: "number", minimum: 1 }
|
|
12216
|
-
}
|
|
12217
|
-
},
|
|
12218
|
-
operatingNotes: {
|
|
12219
|
-
type: "array",
|
|
12220
|
-
maxItems: 200,
|
|
12221
|
-
items: {
|
|
12222
|
-
type: "object",
|
|
12223
|
-
additionalProperties: false,
|
|
12224
|
-
required: ["text"],
|
|
12225
|
-
properties: {
|
|
12226
|
-
text: { type: "string", minLength: 1 },
|
|
12227
|
-
category: { enum: ["provider_quirk", "pattern_to_avoid", "recovery_lesson"] },
|
|
12228
|
-
createdAt: { type: "string" },
|
|
12229
|
-
sourceCoordinator: { type: "string" }
|
|
12230
|
-
}
|
|
12231
|
-
}
|
|
12232
|
-
},
|
|
12233
|
-
limits: {
|
|
12234
|
-
type: "object",
|
|
12235
|
-
additionalProperties: false,
|
|
12236
|
-
properties: {
|
|
12237
|
-
maxNoteChars: { type: "number", minimum: 1 },
|
|
12238
|
-
maxNotes: { type: "number", minimum: 1 }
|
|
12239
|
-
}
|
|
12240
|
-
}
|
|
12241
|
-
}
|
|
12242
|
-
};
|
|
12243
|
-
}
|
|
12244
|
-
});
|
|
12245
|
-
|
|
12246
12376
|
// src/mesh/mesh-fast-forward.ts
|
|
12247
12377
|
async function fastForwardMeshNode(args) {
|
|
12248
12378
|
const workspace = typeof args.workspace === "string" ? args.workspace.trim() : "";
|
|
@@ -16576,6 +16706,16 @@ function __resetIdleAutoFastForwardForTests() {
|
|
|
16576
16706
|
continuousAutoFastForwardLastScan.clear();
|
|
16577
16707
|
autoFastForwardWorkspaceLease.clear();
|
|
16578
16708
|
}
|
|
16709
|
+
function loadRepoConfigForNode(node) {
|
|
16710
|
+
const workspace = typeof node?.workspace === "string" && node.workspace.trim() ? node.workspace.trim() : "";
|
|
16711
|
+
if (!workspace) return null;
|
|
16712
|
+
try {
|
|
16713
|
+
const result = loadRepoMeshJsonConfig(workspace);
|
|
16714
|
+
return result.sourceType === "repo_file" && result.config ? result.config : null;
|
|
16715
|
+
} catch {
|
|
16716
|
+
return null;
|
|
16717
|
+
}
|
|
16718
|
+
}
|
|
16579
16719
|
function getMeshWithCache(components, meshId) {
|
|
16580
16720
|
const localMesh = getMesh(meshId);
|
|
16581
16721
|
const cachedMesh = components.router?.getCachedInlineMesh(meshId);
|
|
@@ -16835,7 +16975,13 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
|
|
|
16835
16975
|
meshNodeFor: meshId,
|
|
16836
16976
|
meshNodeId: nodeId,
|
|
16837
16977
|
launchedByCoordinator: true,
|
|
16838
|
-
|
|
16978
|
+
...delegatedWorkerAutoApproveSettings(
|
|
16979
|
+
mesh?.policy,
|
|
16980
|
+
node?.policy,
|
|
16981
|
+
components.providerLoader?.getMeta(providerType),
|
|
16982
|
+
loadRepoConfigForNode(node),
|
|
16983
|
+
providerType
|
|
16984
|
+
),
|
|
16839
16985
|
...localDaemonId ? { meshCoordinatorDaemonId: localDaemonId } : {},
|
|
16840
16986
|
// COMPLETION-PROPAGATION F5: (re)stamp the coordinator SESSION anchor from THIS
|
|
16841
16987
|
// task's sourceCoordinatorSessionId with PRIORITY — a manually-launched (or reused)
|
|
@@ -17273,10 +17419,10 @@ function liveSessionCountForNode(components, meshId, nodeId) {
|
|
|
17273
17419
|
}
|
|
17274
17420
|
return count;
|
|
17275
17421
|
}
|
|
17276
|
-
function nodeHasLiveSessionPendingClaim(components, meshId, nodeId) {
|
|
17422
|
+
function nodeHasLiveSessionPendingClaim(components, meshId, nodeId, task, node) {
|
|
17277
17423
|
if (inWindowAutoLaunchSessionIdsForNode(meshId, nodeId).length > 0) return true;
|
|
17278
17424
|
const busySessionIds = new Set(
|
|
17279
|
-
getQueue(meshId, { status: ["assigned"] }).filter((
|
|
17425
|
+
getQueue(meshId, { status: ["assigned"] }).filter((task2) => daemonIdsEquivalent(task2.assignedNodeId, nodeId)).map((task2) => readNonEmptyString(task2.assignedSessionId)).filter(Boolean)
|
|
17280
17426
|
);
|
|
17281
17427
|
return components.instanceManager.getByCategory("cli").some((inst) => {
|
|
17282
17428
|
const state = inst.getState();
|
|
@@ -17289,6 +17435,12 @@ function nodeHasLiveSessionPendingClaim(components, meshId, nodeId) {
|
|
|
17289
17435
|
if (isTerminalSessionStatus(status)) return false;
|
|
17290
17436
|
const sessionId = readNonEmptyString(state.instanceId);
|
|
17291
17437
|
if (sessionId && busySessionIds.has(sessionId)) return false;
|
|
17438
|
+
if (task.requiredTags?.length) {
|
|
17439
|
+
const sessionProviderType = state.type || readNonEmptyString(settings.providerType);
|
|
17440
|
+
if (sessionProviderType && !nodeSatisfiesRequiredTags(task.requiredTags, buildMeshNodeCapabilityTags(node, sessionProviderType))) {
|
|
17441
|
+
return false;
|
|
17442
|
+
}
|
|
17443
|
+
}
|
|
17292
17444
|
return true;
|
|
17293
17445
|
});
|
|
17294
17446
|
}
|
|
@@ -17569,7 +17721,7 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
17569
17721
|
sweepExpiredCooldowns();
|
|
17570
17722
|
continue;
|
|
17571
17723
|
}
|
|
17572
|
-
if (nodeHasLiveSessionPendingClaim(components, meshId, nodeId)) {
|
|
17724
|
+
if (nodeHasLiveSessionPendingClaim(components, meshId, nodeId, task, node)) {
|
|
17573
17725
|
markAutoLaunch(meshId, task.id, { status: "skipped", reason: "node_has_live_session_pending_claim", nodeId });
|
|
17574
17726
|
continue;
|
|
17575
17727
|
}
|
|
@@ -17608,8 +17760,14 @@ async function maybeAutoLaunchOneQueueSession(components, meshId, mesh) {
|
|
|
17608
17760
|
spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || "hidden",
|
|
17609
17761
|
// Coordinator-dispatched worker: auto-approve unless mesh/node policy
|
|
17610
17762
|
// opts out (default true). Lands in settingsOverride and beats the
|
|
17611
|
-
// global per-provider-type
|
|
17612
|
-
|
|
17763
|
+
// global per-provider-type boolean/mode through explicit opposite-key clearing.
|
|
17764
|
+
...delegatedWorkerAutoApproveSettings(
|
|
17765
|
+
mesh?.policy,
|
|
17766
|
+
node?.policy,
|
|
17767
|
+
components.providerLoader?.getMeta(resolved.providerType),
|
|
17768
|
+
loadRepoConfigForNode(node),
|
|
17769
|
+
resolved.providerType
|
|
17770
|
+
),
|
|
17613
17771
|
launchedByCoordinator: true,
|
|
17614
17772
|
autoLaunchedForQueueTaskId: task.id
|
|
17615
17773
|
};
|
|
@@ -18073,6 +18231,7 @@ var init_mesh_queue_assignment = __esm({
|
|
|
18073
18231
|
init_mesh_event_trace();
|
|
18074
18232
|
init_mesh_warmup_deadline();
|
|
18075
18233
|
init_repo_mesh_types();
|
|
18234
|
+
init_mesh_json_config();
|
|
18076
18235
|
init_dist();
|
|
18077
18236
|
init_mesh_node_slots();
|
|
18078
18237
|
init_mesh_events_stale();
|
|
@@ -20449,6 +20608,7 @@ function buildAvailableProviders(providerLoader) {
|
|
|
20449
20608
|
...provider.lastDetection !== void 0 ? { lastDetection: provider.lastDetection } : {},
|
|
20450
20609
|
...provider.lastVerification !== void 0 ? { lastVerification: provider.lastVerification } : {},
|
|
20451
20610
|
...provider.meshCoordinator !== void 0 ? { meshCoordinator: provider.meshCoordinator } : {},
|
|
20611
|
+
...provider.autoApproveModes !== void 0 ? { autoApproveModes: provider.autoApproveModes } : {},
|
|
20452
20612
|
...trust ? {
|
|
20453
20613
|
trust,
|
|
20454
20614
|
trustDescription: describeTrust2(trust),
|
|
@@ -21627,7 +21787,24 @@ function injectMeshSystemMessage(components, args) {
|
|
|
21627
21787
|
spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || "hidden",
|
|
21628
21788
|
// Coordinator-dispatched recovery relaunch: same auto-approve
|
|
21629
21789
|
// policy as the primary worker launch path.
|
|
21630
|
-
|
|
21790
|
+
...delegatedWorkerAutoApproveSettings(
|
|
21791
|
+
mesh?.policy,
|
|
21792
|
+
node?.policy,
|
|
21793
|
+
components.providerLoader?.getMeta(recoveryContext.failedProviderType),
|
|
21794
|
+
// Recovery relaunch: same repo-declared requested mode as the
|
|
21795
|
+
// primary path. node.workspace missing → null → provider default.
|
|
21796
|
+
(() => {
|
|
21797
|
+
const ws = typeof node?.workspace === "string" && node.workspace.trim() ? node.workspace.trim() : "";
|
|
21798
|
+
if (!ws) return null;
|
|
21799
|
+
try {
|
|
21800
|
+
const r = loadRepoMeshJsonConfig(ws);
|
|
21801
|
+
return r.sourceType === "repo_file" && r.config ? r.config : null;
|
|
21802
|
+
} catch {
|
|
21803
|
+
return null;
|
|
21804
|
+
}
|
|
21805
|
+
})(),
|
|
21806
|
+
recoveryContext.failedProviderType
|
|
21807
|
+
),
|
|
21631
21808
|
launchedByCoordinator: true
|
|
21632
21809
|
}
|
|
21633
21810
|
}).catch((e) => LOG.error("MeshRecovery", `Failed to auto-relaunch session for ${node.id}: ${e?.message}`));
|
|
@@ -22017,6 +22194,7 @@ var init_mesh_event_forwarding = __esm({
|
|
|
22017
22194
|
init_mesh_event_trace();
|
|
22018
22195
|
init_snapshot();
|
|
22019
22196
|
init_repo_mesh_types();
|
|
22197
|
+
init_mesh_json_config();
|
|
22020
22198
|
init_dist();
|
|
22021
22199
|
init_mesh_events_stale();
|
|
22022
22200
|
init_mesh_task_inflight();
|
|
@@ -24287,6 +24465,20 @@ var init_provider_schema = __esm({
|
|
|
24287
24465
|
}
|
|
24288
24466
|
}
|
|
24289
24467
|
},
|
|
24468
|
+
autoApproveModes: {
|
|
24469
|
+
type: "object",
|
|
24470
|
+
description: "Provider-specific auto-approve choices and their launch/runtime strategy.",
|
|
24471
|
+
required: ["default", "modes"],
|
|
24472
|
+
additionalProperties: false,
|
|
24473
|
+
properties: {
|
|
24474
|
+
default: { type: "string", minLength: 1 },
|
|
24475
|
+
modes: {
|
|
24476
|
+
type: "array",
|
|
24477
|
+
minItems: 1,
|
|
24478
|
+
items: { $ref: "#/$defs/autoApproveMode" }
|
|
24479
|
+
}
|
|
24480
|
+
}
|
|
24481
|
+
},
|
|
24290
24482
|
sendDelayMs: {
|
|
24291
24483
|
type: "number",
|
|
24292
24484
|
minimum: 0,
|
|
@@ -24660,6 +24852,36 @@ var init_provider_schema = __esm({
|
|
|
24660
24852
|
}
|
|
24661
24853
|
},
|
|
24662
24854
|
$defs: {
|
|
24855
|
+
autoApproveMode: {
|
|
24856
|
+
type: "object",
|
|
24857
|
+
required: ["id", "label", "strategy", "risk"],
|
|
24858
|
+
additionalProperties: false,
|
|
24859
|
+
properties: {
|
|
24860
|
+
id: { type: "string", minLength: 1 },
|
|
24861
|
+
label: { type: "string", minLength: 1 },
|
|
24862
|
+
strategy: { enum: ["pty-parse-default", "launch-args", "post-boot-command"] },
|
|
24863
|
+
risk: { enum: ["safe", "caution", "dangerous"] },
|
|
24864
|
+
warning: { type: "string", minLength: 1 },
|
|
24865
|
+
launchArgs: {
|
|
24866
|
+
type: "array",
|
|
24867
|
+
items: { type: "string", minLength: 1 }
|
|
24868
|
+
},
|
|
24869
|
+
removeArgs: {
|
|
24870
|
+
type: "array",
|
|
24871
|
+
items: { type: "string", minLength: 1 }
|
|
24872
|
+
}
|
|
24873
|
+
},
|
|
24874
|
+
allOf: [
|
|
24875
|
+
{
|
|
24876
|
+
if: { properties: { strategy: { const: "launch-args" } }, required: ["strategy"] },
|
|
24877
|
+
then: { required: ["launchArgs"], properties: { launchArgs: { minItems: 1 } } }
|
|
24878
|
+
},
|
|
24879
|
+
{
|
|
24880
|
+
if: { properties: { risk: { const: "dangerous" } }, required: ["risk"] },
|
|
24881
|
+
then: { required: ["warning"] }
|
|
24882
|
+
}
|
|
24883
|
+
]
|
|
24884
|
+
},
|
|
24663
24885
|
patternList: {
|
|
24664
24886
|
type: "array",
|
|
24665
24887
|
items: {
|
|
@@ -30768,6 +30990,7 @@ function detectClaudeAskUserQuestionPromptFromJson(value, providerType = "claude
|
|
|
30768
30990
|
|
|
30769
30991
|
// src/index.ts
|
|
30770
30992
|
init_repo_mesh_types();
|
|
30993
|
+
init_mesh_json_config();
|
|
30771
30994
|
|
|
30772
30995
|
// src/git/index.ts
|
|
30773
30996
|
init_git_executor();
|
|
@@ -49005,6 +49228,7 @@ function formatMarkerTimestamp(timestamp) {
|
|
|
49005
49228
|
}
|
|
49006
49229
|
|
|
49007
49230
|
// src/providers/cli-provider-instance.ts
|
|
49231
|
+
init_auto_approve_modes();
|
|
49008
49232
|
function approvalModalSignature(message, affirmativeAnchor) {
|
|
49009
49233
|
return [typeof message === "string" ? message.trim() : "", affirmativeAnchor].join("::");
|
|
49010
49234
|
}
|
|
@@ -50985,7 +51209,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
50985
51209
|
* resolveModal, so a plain turn that never saw an approval always returns false.
|
|
50986
51210
|
*/
|
|
50987
51211
|
inApprovalResumeGrace(now = Date.now()) {
|
|
50988
|
-
if (!this.isAutonomousMeshSession() || !this.
|
|
51212
|
+
if (!this.isAutonomousMeshSession() || !this.shouldUsePtyAutoApprove()) return false;
|
|
50989
51213
|
const resolvedAt = typeof this.adapter?.lastApprovalResolvedAt === "number" ? this.adapter.lastApprovalResolvedAt : 0;
|
|
50990
51214
|
if (resolvedAt <= 0) return false;
|
|
50991
51215
|
return now - resolvedAt < _CliProviderInstance.APPROVAL_RESUME_GRACE_MS;
|
|
@@ -51090,7 +51314,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51090
51314
|
return;
|
|
51091
51315
|
}
|
|
51092
51316
|
const latestStatus = this.adapter.getStatus({ allowParse: false });
|
|
51093
|
-
const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.
|
|
51317
|
+
const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldUsePtyAutoApprove();
|
|
51094
51318
|
const latestVisibleStatus = latestAutoApproveActive || this.autoApproveBusy ? "generating" : latestStatus.status;
|
|
51095
51319
|
LOG.debug("CLI", `[${this.type}] flush attempt: adapterStatus=${latestStatus.status} latestVisible=${latestVisibleStatus} generatingStartedAt=${this.generatingStartedAt} isWaitingForResponse=${!!this.adapter?.isWaitingForResponse} hasPartial=${!!this.adapter.getPartialResponse?.()}`);
|
|
51096
51320
|
if (latestVisibleStatus !== "idle") {
|
|
@@ -51360,7 +51584,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51360
51584
|
* session, where a human answers the prompt, is returned untouched).
|
|
51361
51585
|
*/
|
|
51362
51586
|
stabilizeFlappingApprovalStatus(adapterStatus, now = Date.now()) {
|
|
51363
|
-
if (!this.isAutonomousMeshSession() || !this.
|
|
51587
|
+
if (!this.isAutonomousMeshSession() || !this.shouldUsePtyAutoApprove()) return adapterStatus;
|
|
51364
51588
|
const rawStatus = adapterStatus?.status;
|
|
51365
51589
|
const resolvedAt = typeof this.adapter?.lastApprovalResolvedAt === "number" ? this.adapter.lastApprovalResolvedAt : 0;
|
|
51366
51590
|
if (rawStatus === "waiting_approval") {
|
|
@@ -51390,7 +51614,11 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51390
51614
|
return adapterStatus;
|
|
51391
51615
|
}
|
|
51392
51616
|
maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
|
|
51393
|
-
if (
|
|
51617
|
+
if (!this.shouldUsePtyAutoApprove()) {
|
|
51618
|
+
this.resetPtyAutoApproveState();
|
|
51619
|
+
return false;
|
|
51620
|
+
}
|
|
51621
|
+
if (adapterStatus?.status === "waiting_approval" && this.shouldUsePtyAutoApprove() && this.manualAttendance.isAttended(now)) {
|
|
51394
51622
|
this.lastAutoApprovalSignature = "";
|
|
51395
51623
|
this.pendingAutoApprovalSignature = "";
|
|
51396
51624
|
this.pendingAutoApprovalSince = 0;
|
|
@@ -51405,7 +51633,7 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
51405
51633
|
}, this.manualAttendance.remainingMs(now) + 20);
|
|
51406
51634
|
return false;
|
|
51407
51635
|
}
|
|
51408
|
-
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.
|
|
51636
|
+
const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldUsePtyAutoApprove();
|
|
51409
51637
|
if (!autoApproveActive) {
|
|
51410
51638
|
this.lastAutoApprovalSignature = "";
|
|
51411
51639
|
if (this.pendingAutoApprovalSince) {
|
|
@@ -52100,15 +52328,34 @@ ${buttons.join("\n")}`;
|
|
|
52100
52328
|
get cliName() {
|
|
52101
52329
|
return this.provider.name;
|
|
52102
52330
|
}
|
|
52331
|
+
resolveAutoApproveMode() {
|
|
52332
|
+
return resolveProviderAutoApproveMode(this.provider, this.settings);
|
|
52333
|
+
}
|
|
52334
|
+
/** Legacy boolean view retained for internal/test compatibility. */
|
|
52103
52335
|
shouldAutoApprove() {
|
|
52104
|
-
|
|
52105
|
-
|
|
52336
|
+
return this.resolveAutoApproveMode().active;
|
|
52337
|
+
}
|
|
52338
|
+
shouldUsePtyAutoApprove() {
|
|
52339
|
+
const resolved = this.resolveAutoApproveMode();
|
|
52340
|
+
return this.shouldAutoApprove() && resolved.strategy === "pty-parse-default";
|
|
52341
|
+
}
|
|
52342
|
+
resetPtyAutoApproveState() {
|
|
52343
|
+
this.lastAutoApprovalSignature = "";
|
|
52344
|
+
this.pendingAutoApprovalSignature = "";
|
|
52345
|
+
this.pendingAutoApprovalSince = 0;
|
|
52346
|
+
this.autoApproveInactiveSince = 0;
|
|
52347
|
+
this.autoApproveMaskSince = 0;
|
|
52348
|
+
this.stalledApprovalNudgeEpisode = 0;
|
|
52349
|
+
this.autoApproveLastModalSeenAt = 0;
|
|
52350
|
+
this.autoApproveBusy = false;
|
|
52351
|
+
if (this.autoApproveSettleTimer) {
|
|
52352
|
+
clearTimeout(this.autoApproveSettleTimer);
|
|
52353
|
+
this.autoApproveSettleTimer = null;
|
|
52106
52354
|
}
|
|
52107
|
-
|
|
52108
|
-
|
|
52109
|
-
|
|
52355
|
+
if (this.autoApproveBusyTimer) {
|
|
52356
|
+
clearTimeout(this.autoApproveBusyTimer);
|
|
52357
|
+
this.autoApproveBusyTimer = null;
|
|
52110
52358
|
}
|
|
52111
|
-
return false;
|
|
52112
52359
|
}
|
|
52113
52360
|
/** @see ProviderInstance.noteManualInteraction */
|
|
52114
52361
|
noteManualInteraction(now = Date.now(), opts) {
|
|
@@ -52124,7 +52371,7 @@ ${buttons.join("\n")}`;
|
|
|
52124
52371
|
* CLI-specific modal text.
|
|
52125
52372
|
*/
|
|
52126
52373
|
autoApproveEffectivelyActive(status, now = Date.now()) {
|
|
52127
|
-
return status === "waiting_approval" && this.
|
|
52374
|
+
return status === "waiting_approval" && this.shouldUsePtyAutoApprove() && !this.manualAttendance.isAttended(now);
|
|
52128
52375
|
}
|
|
52129
52376
|
// STATUS-MISMATCH: true once the current auto-approve episode has been masking
|
|
52130
52377
|
// waiting_approval behind `generating` for longer than AUTO_APPROVE_MASK_STALL_MS without
|
|
@@ -52134,7 +52381,7 @@ ${buttons.join("\n")}`;
|
|
|
52134
52381
|
// maybeAutoApproveStatus (driven by getState + the recheck timer during a waiting episode);
|
|
52135
52382
|
// this read is side-effect-free so getStatusMetadata can consult it too.
|
|
52136
52383
|
autoApproveMaskStalled(now = Date.now()) {
|
|
52137
|
-
return this.autoApproveMaskSince > 0 && now - this.autoApproveMaskSince > _CliProviderInstance.AUTO_APPROVE_MASK_STALL_MS;
|
|
52384
|
+
return this.shouldUsePtyAutoApprove() && this.autoApproveMaskSince > 0 && now - this.autoApproveMaskSince > _CliProviderInstance.AUTO_APPROVE_MASK_STALL_MS;
|
|
52138
52385
|
}
|
|
52139
52386
|
/**
|
|
52140
52387
|
* NOTIF-APPROVAL-MASKED (Q1b): surface a delegated worker's STALLED auto-approve modal
|
|
@@ -52158,6 +52405,7 @@ ${buttons.join("\n")}`;
|
|
|
52158
52405
|
* mask-clock value) so a modal that flaps between parsed/unparsed states is announced once.
|
|
52159
52406
|
*/
|
|
52160
52407
|
maybeEmitStalledApprovalNudge(adapterStatus, now) {
|
|
52408
|
+
if (!this.shouldUsePtyAutoApprove()) return;
|
|
52161
52409
|
if (!this.isMeshWorkerSession()) return;
|
|
52162
52410
|
if (adapterStatus?.status !== "waiting_approval") return;
|
|
52163
52411
|
if (!this.autoApproveMaskStalled(now)) return;
|
|
@@ -53703,6 +53951,7 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
53703
53951
|
}
|
|
53704
53952
|
|
|
53705
53953
|
// src/commands/cli-manager.ts
|
|
53954
|
+
init_auto_approve_modes();
|
|
53706
53955
|
function isExplicitCommand(command) {
|
|
53707
53956
|
const trimmed = command.trim();
|
|
53708
53957
|
return path30.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
@@ -53929,6 +54178,24 @@ function expandThinkingLaunchArgs(template, level, levelMap) {
|
|
|
53929
54178
|
const mapped = levelMap && typeof levelMap[raw] === "string" && levelMap[raw].trim() ? levelMap[raw].trim() : raw;
|
|
53930
54179
|
return template.map((part) => part.includes("{{level}}") ? part.replace("{{level}}", mapped) : part);
|
|
53931
54180
|
}
|
|
54181
|
+
function matchesRemovedLaunchArg(arg, removeArg) {
|
|
54182
|
+
return arg === removeArg || removeArg.startsWith("--") && arg.startsWith(`${removeArg}=`);
|
|
54183
|
+
}
|
|
54184
|
+
function applyAutoApproveModeLaunchArgs(provider, cliArgs, settings) {
|
|
54185
|
+
if (!provider) return { provider, cliArgs };
|
|
54186
|
+
const resolved = resolveProviderAutoApproveMode(provider, settings);
|
|
54187
|
+
if (!resolved.active || resolved.strategy !== "launch-args") return { provider, cliArgs };
|
|
54188
|
+
const mode = findProviderAutoApproveMode(provider, resolved.modeId);
|
|
54189
|
+
if (!mode || !Array.isArray(mode.launchArgs) || mode.launchArgs.length === 0) return { provider, cliArgs };
|
|
54190
|
+
const removeArgs = Array.isArray(mode.removeArgs) ? mode.removeArgs : [];
|
|
54191
|
+
const baseArgs = provider.spawn?.args;
|
|
54192
|
+
const filteredBaseArgs = Array.isArray(baseArgs) && removeArgs.length > 0 ? baseArgs.filter((arg) => !removeArgs.some((removeArg) => matchesRemovedLaunchArg(arg, removeArg))) : baseArgs;
|
|
54193
|
+
const launchProvider = filteredBaseArgs === baseArgs ? provider : { ...provider, spawn: { ...provider.spawn, args: filteredBaseArgs } };
|
|
54194
|
+
return {
|
|
54195
|
+
provider: launchProvider,
|
|
54196
|
+
cliArgs: [...mode.launchArgs, ...cliArgs || []]
|
|
54197
|
+
};
|
|
54198
|
+
}
|
|
53932
54199
|
function readSubcommandSessionId(args, subcommands) {
|
|
53933
54200
|
const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
|
|
53934
54201
|
if (resumeIndex < 0) return void 0;
|
|
@@ -54359,22 +54626,30 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
54359
54626
|
if (provider) {
|
|
54360
54627
|
console.log(colorize("cyan", ` \u{1F4E6} Using provider: ${provider.name} (${provider.type})`));
|
|
54361
54628
|
}
|
|
54362
|
-
const
|
|
54363
|
-
|
|
54629
|
+
const launchSettings = {
|
|
54630
|
+
...this.providerLoader.getSettings(normalizedType),
|
|
54631
|
+
...options?.settingsOverride || {}
|
|
54632
|
+
};
|
|
54633
|
+
const versionResolvedProvider = provider ? this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider : void 0;
|
|
54634
|
+
const autoApproveLaunch = applyAutoApproveModeLaunchArgs(versionResolvedProvider, cliArgs, launchSettings);
|
|
54635
|
+
const launchProvider = autoApproveLaunch.provider || provider;
|
|
54636
|
+
const cliArgsWithAutoApprove = autoApproveLaunch.cliArgs;
|
|
54637
|
+
const modelLaunchArgs = expandModelLaunchArgs(launchProvider?.modelLaunchArgs, initialModel);
|
|
54638
|
+
const cliArgsWithModel = modelLaunchArgs ? [...modelLaunchArgs, ...cliArgsWithAutoApprove || []] : cliArgsWithAutoApprove;
|
|
54364
54639
|
if (initialModel && !modelLaunchArgs) {
|
|
54365
54640
|
LOG.warn("CLI", `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template \u2014 launching without model selection.`);
|
|
54366
54641
|
}
|
|
54367
54642
|
const initialThinkingLevel = options?.initialThinkingLevel;
|
|
54368
|
-
const thinkingLaunchArgs = expandThinkingLaunchArgs(
|
|
54643
|
+
const thinkingLaunchArgs = expandThinkingLaunchArgs(launchProvider?.thinkingLaunchArgs, initialThinkingLevel, launchProvider?.thinkingLevelMap);
|
|
54369
54644
|
const cliArgsWithBrain = thinkingLaunchArgs ? [...thinkingLaunchArgs, ...cliArgsWithModel || []] : cliArgsWithModel;
|
|
54370
54645
|
if (initialThinkingLevel && !thinkingLaunchArgs) {
|
|
54371
54646
|
LOG.warn("CLI", `[${normalizedType}] initialThinkingLevel='${initialThinkingLevel}' requested but provider declares no thinkingLaunchArgs template \u2014 launching without thinking-level selection.`);
|
|
54372
54647
|
}
|
|
54373
|
-
const sessionBinding = resolveCliSessionBinding(
|
|
54648
|
+
const sessionBinding = resolveCliSessionBinding(launchProvider, normalizedType, cliArgsWithBrain, options?.resumeSessionId);
|
|
54374
54649
|
const resolvedCliArgs = sessionBinding.cliArgs;
|
|
54375
54650
|
const instanceManager = this.deps.getInstanceManager();
|
|
54376
|
-
if (
|
|
54377
|
-
const resolvedProvider =
|
|
54651
|
+
if (launchProvider && instanceManager) {
|
|
54652
|
+
const resolvedProvider = launchProvider;
|
|
54378
54653
|
await this.registerCliInstance(
|
|
54379
54654
|
key2,
|
|
54380
54655
|
normalizedType,
|
|
@@ -54382,7 +54657,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
54382
54657
|
resolvedDir,
|
|
54383
54658
|
resolvedCliArgs,
|
|
54384
54659
|
resolvedProvider,
|
|
54385
|
-
|
|
54660
|
+
launchSettings,
|
|
54386
54661
|
false,
|
|
54387
54662
|
{
|
|
54388
54663
|
providerSessionId: sessionBinding.providerSessionId,
|
|
@@ -55221,6 +55496,7 @@ init_hash();
|
|
|
55221
55496
|
init_logger();
|
|
55222
55497
|
|
|
55223
55498
|
// src/providers/provider-schema.ts
|
|
55499
|
+
init_auto_approve_modes();
|
|
55224
55500
|
init_open_panel_support();
|
|
55225
55501
|
var VALID_CAPABILITY_MEDIA_TYPES = /* @__PURE__ */ new Set(["text", "image", "audio", "video", "resource"]);
|
|
55226
55502
|
var VALID_INPUT_STRATEGIES2 = /* @__PURE__ */ new Set(["native", "native_acp", "resource_link", "text_fallback", "paste", "upload"]);
|
|
@@ -55286,6 +55562,7 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
|
|
|
55286
55562
|
"providerVersion",
|
|
55287
55563
|
"status",
|
|
55288
55564
|
"details",
|
|
55565
|
+
"autoApproveModes",
|
|
55289
55566
|
"modelLaunchArgs",
|
|
55290
55567
|
"modelOptions",
|
|
55291
55568
|
"thinkingLaunchArgs",
|
|
@@ -55347,6 +55624,7 @@ function validateProviderDefinition(raw) {
|
|
|
55347
55624
|
validateCapabilities(provider, controls, errors);
|
|
55348
55625
|
validateNativeHistory(provider.nativeHistory, errors);
|
|
55349
55626
|
validateMeshCoordinator(provider.meshCoordinator, errors);
|
|
55627
|
+
validateAutoApproveModes(provider.autoApproveModes, errors);
|
|
55350
55628
|
for (const control of controls) {
|
|
55351
55629
|
validateControl(control, errors);
|
|
55352
55630
|
}
|
|
@@ -55355,6 +55633,75 @@ function validateProviderDefinition(raw) {
|
|
|
55355
55633
|
}
|
|
55356
55634
|
return { errors, warnings };
|
|
55357
55635
|
}
|
|
55636
|
+
function validateAutoApproveModes(raw, errors) {
|
|
55637
|
+
if (raw === void 0) return;
|
|
55638
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
55639
|
+
errors.push("autoApproveModes must be an object");
|
|
55640
|
+
return;
|
|
55641
|
+
}
|
|
55642
|
+
const config = raw;
|
|
55643
|
+
const defaultModeId = typeof config.default === "string" ? config.default.trim() : "";
|
|
55644
|
+
if (!defaultModeId) {
|
|
55645
|
+
errors.push("autoApproveModes.default must be a non-empty string");
|
|
55646
|
+
} else {
|
|
55647
|
+
config.default = defaultModeId;
|
|
55648
|
+
}
|
|
55649
|
+
if (!Array.isArray(config.modes) || config.modes.length === 0) {
|
|
55650
|
+
errors.push("autoApproveModes.modes must be a non-empty array");
|
|
55651
|
+
return;
|
|
55652
|
+
}
|
|
55653
|
+
const ids = /* @__PURE__ */ new Set();
|
|
55654
|
+
for (const [index, rawMode] of config.modes.entries()) {
|
|
55655
|
+
const prefix = `autoApproveModes.modes[${index}]`;
|
|
55656
|
+
if (!rawMode || typeof rawMode !== "object" || Array.isArray(rawMode)) {
|
|
55657
|
+
errors.push(`${prefix} must be an object`);
|
|
55658
|
+
continue;
|
|
55659
|
+
}
|
|
55660
|
+
const mode = rawMode;
|
|
55661
|
+
const id = typeof mode.id === "string" ? mode.id.trim() : "";
|
|
55662
|
+
if (!id) {
|
|
55663
|
+
errors.push(`${prefix}.id must be a non-empty string`);
|
|
55664
|
+
} else if (ids.has(id)) {
|
|
55665
|
+
errors.push(`${prefix}.id must be unique (duplicate: ${id})`);
|
|
55666
|
+
} else {
|
|
55667
|
+
ids.add(id);
|
|
55668
|
+
mode.id = id;
|
|
55669
|
+
}
|
|
55670
|
+
if (typeof mode.label !== "string" || !mode.label.trim()) {
|
|
55671
|
+
errors.push(`${prefix}.label must be a non-empty string`);
|
|
55672
|
+
}
|
|
55673
|
+
const strategy = mode.strategy;
|
|
55674
|
+
if (!["pty-parse-default", "launch-args", "post-boot-command"].includes(String(strategy))) {
|
|
55675
|
+
errors.push(`${prefix}.strategy must be one of: pty-parse-default, launch-args, post-boot-command`);
|
|
55676
|
+
} else if (strategy === "post-boot-command") {
|
|
55677
|
+
errors.push(`${prefix}.strategy post-boot-command is reserved and unsupported in v1`);
|
|
55678
|
+
}
|
|
55679
|
+
const risk = mode.risk;
|
|
55680
|
+
if (!["safe", "caution", "dangerous"].includes(String(risk))) {
|
|
55681
|
+
errors.push(`${prefix}.risk must be one of: safe, caution, dangerous`);
|
|
55682
|
+
}
|
|
55683
|
+
for (const field of ["launchArgs", "removeArgs"]) {
|
|
55684
|
+
const value = mode[field];
|
|
55685
|
+
if (value !== void 0 && (!Array.isArray(value) || value.some((arg) => typeof arg !== "string" || !arg.trim()))) {
|
|
55686
|
+
errors.push(`${prefix}.${field} must be an array of non-empty strings when provided`);
|
|
55687
|
+
}
|
|
55688
|
+
}
|
|
55689
|
+
if (strategy === "launch-args" && (!Array.isArray(mode.launchArgs) || mode.launchArgs.length === 0)) {
|
|
55690
|
+
errors.push(`${prefix}.launchArgs must be a non-empty array for launch-args strategy`);
|
|
55691
|
+
}
|
|
55692
|
+
if (["safe", "caution", "dangerous"].includes(String(risk)) && deriveAutoApproveModeRisk(mode) === "dangerous") {
|
|
55693
|
+
mode.risk = "dangerous";
|
|
55694
|
+
}
|
|
55695
|
+
if (mode.risk === "dangerous" && (typeof mode.warning !== "string" || !mode.warning.trim())) {
|
|
55696
|
+
errors.push(`${prefix}.warning is required for dangerous modes`);
|
|
55697
|
+
} else if (mode.warning !== void 0 && (typeof mode.warning !== "string" || !mode.warning.trim())) {
|
|
55698
|
+
errors.push(`${prefix}.warning must be a non-empty string when provided`);
|
|
55699
|
+
}
|
|
55700
|
+
}
|
|
55701
|
+
if (defaultModeId && !ids.has(defaultModeId)) {
|
|
55702
|
+
errors.push(`autoApproveModes.default must reference an existing mode id: ${defaultModeId}`);
|
|
55703
|
+
}
|
|
55704
|
+
}
|
|
55358
55705
|
function validateCapabilities(provider, controls, errors) {
|
|
55359
55706
|
const capabilities = provider.capabilities;
|
|
55360
55707
|
if (provider.contractVersion === 2) {
|
|
@@ -59964,6 +60311,139 @@ var meshCrudHandlers = {
|
|
|
59964
60311
|
return { success: false, error: e.message };
|
|
59965
60312
|
}
|
|
59966
60313
|
},
|
|
60314
|
+
// READ path for `.adhdev/mesh.json` — returns the currently-committed repo
|
|
60315
|
+
// config (parsed + normalized) for a workspace so a UI can render/edit the
|
|
60316
|
+
// existing declarative zones (notably `providerDefaults.autoApproveModes`)
|
|
60317
|
+
// WITHOUT re-deriving them from the machine-local scaffold. Never writes.
|
|
60318
|
+
// `config` is undefined when no repo file exists (sourceType 'unavailable') or
|
|
60319
|
+
// it is unparseable (sourceType 'invalid', with the parse error surfaced).
|
|
60320
|
+
read_mesh_json_config: async (_ctx, args) => {
|
|
60321
|
+
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
60322
|
+
try {
|
|
60323
|
+
const { loadRepoMeshJsonConfig: loadRepoMeshJsonConfig2 } = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
|
|
60324
|
+
const loaded = loadRepoMeshJsonConfig2(workspace);
|
|
60325
|
+
return {
|
|
60326
|
+
success: true,
|
|
60327
|
+
workspace,
|
|
60328
|
+
sourceType: loaded.sourceType,
|
|
60329
|
+
source: loaded.source,
|
|
60330
|
+
...loaded.path ? { path: loaded.path } : {},
|
|
60331
|
+
...loaded.error ? { error: loaded.error } : {},
|
|
60332
|
+
config: loaded.config,
|
|
60333
|
+
// Convenience projection so the UI does not have to reach into config.
|
|
60334
|
+
providerDefaults: loaded.config?.providerDefaults
|
|
60335
|
+
};
|
|
60336
|
+
} catch (e) {
|
|
60337
|
+
return { success: false, error: e.message };
|
|
60338
|
+
}
|
|
60339
|
+
},
|
|
60340
|
+
// Partial-edit WRITE path for `.adhdev/mesh.json` `providerDefaults` — a
|
|
60341
|
+
// READ-MODIFY-WRITE that preserves operator hand-edits. Unlike
|
|
60342
|
+
// write_mesh_json_config (which rebuilds the WHOLE file from the machine-local
|
|
60343
|
+
// scaffold and can silently drop hand-edited zones), this parses the existing
|
|
60344
|
+
// repo file, merges ONLY the providerDefaults.autoApproveModes zone, and
|
|
60345
|
+
// re-serializes — coordinator prompt, operating notes and limits authored in
|
|
60346
|
+
// the repo are carried through untouched. Defaults to dry-run.
|
|
60347
|
+
//
|
|
60348
|
+
// args: { workspace?, autoApproveModes: Record<providerType,modeId>, write?, merge? }
|
|
60349
|
+
// merge=true (default): per-provider merge into the existing map; a modeId of
|
|
60350
|
+
// '' | null removes that provider's entry. merge=false: REPLACE the whole
|
|
60351
|
+
// autoApproveModes map with the supplied one.
|
|
60352
|
+
set_mesh_provider_defaults: async (_ctx, args) => {
|
|
60353
|
+
const workspace = typeof args?.workspace === "string" && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
60354
|
+
const write = args?.write === true;
|
|
60355
|
+
const merge = args?.merge !== false;
|
|
60356
|
+
const inputModes = args?.autoApproveModes;
|
|
60357
|
+
if (inputModes !== void 0 && (typeof inputModes !== "object" || inputModes === null || Array.isArray(inputModes))) {
|
|
60358
|
+
return { success: false, error: "autoApproveModes must be an object (providerType \u2192 modeId) when provided" };
|
|
60359
|
+
}
|
|
60360
|
+
try {
|
|
60361
|
+
const {
|
|
60362
|
+
loadRepoMeshJsonConfig: loadRepoMeshJsonConfig2,
|
|
60363
|
+
normalizeRepoMeshDeclarativeConfig: normalizeRepoMeshDeclarativeConfig2,
|
|
60364
|
+
MESH_JSON_CONFIG_LOCATIONS: MESH_JSON_CONFIG_LOCATIONS2
|
|
60365
|
+
} = await Promise.resolve().then(() => (init_mesh_json_config(), mesh_json_config_exports));
|
|
60366
|
+
const { existsSync: existsSync57, readFileSync: readFileSync44, mkdirSync: mkdirSync23, writeFileSync: writeFileSync25 } = await import("fs");
|
|
60367
|
+
const { dirname: dirname19, join: join54 } = await import("path");
|
|
60368
|
+
const yaml6 = await import("js-yaml");
|
|
60369
|
+
const relativePath = MESH_JSON_CONFIG_LOCATIONS2[0];
|
|
60370
|
+
let baseDoc = { version: 1 };
|
|
60371
|
+
let existingPath = join54(workspace, relativePath);
|
|
60372
|
+
let existedAsYaml = false;
|
|
60373
|
+
for (const relative5 of MESH_JSON_CONFIG_LOCATIONS2) {
|
|
60374
|
+
const candidate = join54(workspace, relative5);
|
|
60375
|
+
if (!existsSync57(candidate)) continue;
|
|
60376
|
+
try {
|
|
60377
|
+
const text = readFileSync44(candidate, "utf-8");
|
|
60378
|
+
const parsed = /\.json$/i.test(candidate) ? JSON.parse(text) : yaml6.load(text);
|
|
60379
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
60380
|
+
baseDoc = parsed;
|
|
60381
|
+
existingPath = candidate;
|
|
60382
|
+
existedAsYaml = !/\.json$/i.test(candidate);
|
|
60383
|
+
}
|
|
60384
|
+
} catch (e) {
|
|
60385
|
+
return { success: false, error: `existing ${relative5} is unparseable, refusing to overwrite: ${e?.message || e}` };
|
|
60386
|
+
}
|
|
60387
|
+
break;
|
|
60388
|
+
}
|
|
60389
|
+
const existingPd = baseDoc.providerDefaults && typeof baseDoc.providerDefaults === "object" && !Array.isArray(baseDoc.providerDefaults) ? baseDoc.providerDefaults : {};
|
|
60390
|
+
const existingModes = existingPd.autoApproveModes && typeof existingPd.autoApproveModes === "object" && !Array.isArray(existingPd.autoApproveModes) ? { ...existingPd.autoApproveModes } : {};
|
|
60391
|
+
const nextModes = merge ? existingModes : {};
|
|
60392
|
+
if (inputModes) {
|
|
60393
|
+
for (const [providerType, modeId] of Object.entries(inputModes)) {
|
|
60394
|
+
const type = typeof providerType === "string" ? providerType.trim() : "";
|
|
60395
|
+
if (!type) continue;
|
|
60396
|
+
const id = typeof modeId === "string" ? modeId.trim() : "";
|
|
60397
|
+
if (id) nextModes[type] = id;
|
|
60398
|
+
else delete nextModes[type];
|
|
60399
|
+
}
|
|
60400
|
+
}
|
|
60401
|
+
const nextDoc = { ...baseDoc, version: 1 };
|
|
60402
|
+
if (Object.keys(nextModes).length) {
|
|
60403
|
+
nextDoc.providerDefaults = { ...existingPd, autoApproveModes: nextModes };
|
|
60404
|
+
} else {
|
|
60405
|
+
if (nextDoc.providerDefaults) {
|
|
60406
|
+
const { autoApproveModes, ...restPd } = nextDoc.providerDefaults;
|
|
60407
|
+
if (Object.keys(restPd).length) nextDoc.providerDefaults = restPd;
|
|
60408
|
+
else delete nextDoc.providerDefaults;
|
|
60409
|
+
}
|
|
60410
|
+
}
|
|
60411
|
+
const validation = normalizeRepoMeshDeclarativeConfig2(nextDoc);
|
|
60412
|
+
if (!validation.valid) {
|
|
60413
|
+
return { success: false, error: `merged mesh.json is invalid: ${validation.errors.join("; ")}` };
|
|
60414
|
+
}
|
|
60415
|
+
const absolutePath = existingPath;
|
|
60416
|
+
const serialized = existedAsYaml ? yaml6.dump(nextDoc, { indent: 2 }) : `${JSON.stringify(nextDoc, null, 2)}
|
|
60417
|
+
`;
|
|
60418
|
+
if (!write) {
|
|
60419
|
+
return {
|
|
60420
|
+
success: true,
|
|
60421
|
+
written: false,
|
|
60422
|
+
dryRun: true,
|
|
60423
|
+
path: absolutePath,
|
|
60424
|
+
relativePath,
|
|
60425
|
+
merge,
|
|
60426
|
+
providerDefaults: nextDoc.providerDefaults,
|
|
60427
|
+
preview: serialized,
|
|
60428
|
+
note: "Dry-run: nothing written. Re-run with write=true to persist. Only the providerDefaults zone is merged; other repo zones are preserved."
|
|
60429
|
+
};
|
|
60430
|
+
}
|
|
60431
|
+
mkdirSync23(dirname19(absolutePath), { recursive: true });
|
|
60432
|
+
writeFileSync25(absolutePath, serialized, "utf-8");
|
|
60433
|
+
return {
|
|
60434
|
+
success: true,
|
|
60435
|
+
written: true,
|
|
60436
|
+
dryRun: false,
|
|
60437
|
+
path: absolutePath,
|
|
60438
|
+
relativePath,
|
|
60439
|
+
merge,
|
|
60440
|
+
providerDefaults: nextDoc.providerDefaults,
|
|
60441
|
+
note: "Wrote providerDefaults into .adhdev/mesh.json (read-modify-write; other zones preserved). Commit it to the repo."
|
|
60442
|
+
};
|
|
60443
|
+
} catch (e) {
|
|
60444
|
+
return { success: false, error: e.message };
|
|
60445
|
+
}
|
|
60446
|
+
},
|
|
59967
60447
|
delete_mesh: async (_ctx, args) => {
|
|
59968
60448
|
const meshId = typeof args?.meshId === "string" ? args.meshId.trim() : "";
|
|
59969
60449
|
if (!meshId) return { success: false, error: "meshId required" };
|
|
@@ -76096,6 +76576,9 @@ export {
|
|
|
76096
76576
|
MAX_LEDGER_SLICE_LIMIT,
|
|
76097
76577
|
MESH_CONVERGE_FAST_FORWARD_TAG,
|
|
76098
76578
|
MESH_CONVERGE_REFINE_TAG,
|
|
76579
|
+
MESH_JSON_CONFIG_LOCATIONS,
|
|
76580
|
+
MESH_JSON_CONFIG_SCHEMA,
|
|
76581
|
+
MESH_JSON_PROVIDER_DEFAULTS_EXAMPLE,
|
|
76099
76582
|
MESH_MAX_PARALLEL_TASKS_MAX,
|
|
76100
76583
|
MESH_MAX_PARALLEL_TASKS_MIN,
|
|
76101
76584
|
MESH_MISSION_LIST_HISTORY_ID_LIMIT,
|
|
@@ -76155,6 +76638,7 @@ export {
|
|
|
76155
76638
|
buildMeshActiveWorkSummary,
|
|
76156
76639
|
buildMeshAsyncRefineJobs,
|
|
76157
76640
|
buildMeshHostRequiredFailure,
|
|
76641
|
+
buildMeshJsonConfigScaffold,
|
|
76158
76642
|
buildMeshLedgerReconciliationEvidence,
|
|
76159
76643
|
buildMeshLedgerReplicaEvidence,
|
|
76160
76644
|
buildMeshMagiActivity,
|
|
@@ -76205,6 +76689,7 @@ export {
|
|
|
76205
76689
|
createSessionDelivery,
|
|
76206
76690
|
createWorktree,
|
|
76207
76691
|
daemonIdsEquivalent,
|
|
76692
|
+
delegatedWorkerAutoApproveSettings,
|
|
76208
76693
|
deleteDirectDispatchesByTaskId,
|
|
76209
76694
|
deleteMesh,
|
|
76210
76695
|
deriveMeshNodeHealthFromGit,
|
|
@@ -76318,6 +76803,7 @@ export {
|
|
|
76318
76803
|
loadMeshCoordinatorRegistry,
|
|
76319
76804
|
loadMeshRefineConfig,
|
|
76320
76805
|
loadMeshWorktreeBootstrapConfig,
|
|
76806
|
+
loadRepoMeshJsonConfig,
|
|
76321
76807
|
loadRepoSettings,
|
|
76322
76808
|
loadState,
|
|
76323
76809
|
logCommand,
|
|
@@ -76358,6 +76844,7 @@ export {
|
|
|
76358
76844
|
normalizeMeshWorkerResult,
|
|
76359
76845
|
normalizeMessageParts,
|
|
76360
76846
|
normalizeRepoIdentity,
|
|
76847
|
+
normalizeRepoMeshDeclarativeConfig,
|
|
76361
76848
|
normalizeSessionModalFields,
|
|
76362
76849
|
parsePorcelainV2Status,
|
|
76363
76850
|
parseProviderSourceConfigUpdate,
|
|
@@ -76404,6 +76891,7 @@ export {
|
|
|
76404
76891
|
resolveCurrentGlobalInstallSurface,
|
|
76405
76892
|
resolveDebugRuntimeConfig,
|
|
76406
76893
|
resolveDelegatedWorkerAutoApprove,
|
|
76894
|
+
resolveDelegatedWorkerDangerousModeAllow,
|
|
76407
76895
|
resolveDeliveryDecision,
|
|
76408
76896
|
resolveEffectiveMeshNodeHealth,
|
|
76409
76897
|
resolveGitRepository,
|
|
@@ -76427,6 +76915,7 @@ export {
|
|
|
76427
76915
|
runMeshWorktreeBootstrap,
|
|
76428
76916
|
saveConfig,
|
|
76429
76917
|
saveState,
|
|
76918
|
+
serializeMeshJsonConfigScaffold,
|
|
76430
76919
|
serializeV2EnvelopeToWire,
|
|
76431
76920
|
setDebugRuntimeConfig,
|
|
76432
76921
|
setLogLevel,
|