@adhdev/daemon-core 0.8.52 → 0.8.54

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.
Files changed (48) hide show
  1. package/dist/commands/cli-manager.d.ts +8 -1
  2. package/dist/index.d.ts +5 -1
  3. package/dist/index.js +896 -299
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +887 -300
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/providers/acp-provider-instance.d.ts +2 -1
  8. package/dist/providers/cli-provider-instance.d.ts +3 -1
  9. package/dist/providers/cli-script-results.d.ts +8 -0
  10. package/dist/providers/contracts.d.ts +58 -9
  11. package/dist/providers/control-effects.d.ts +4 -1
  12. package/dist/providers/io-contracts.d.ts +91 -0
  13. package/dist/providers/provider-schema.d.ts +5 -0
  14. package/dist/session-host/runtime-surface.d.ts +16 -0
  15. package/dist/session-host/startup-restore-policy.d.ts +1 -0
  16. package/dist/shared-types.d.ts +6 -0
  17. package/dist/types.d.ts +3 -3
  18. package/node_modules/@adhdev/session-host-core/dist/index.d.mts +16 -1
  19. package/node_modules/@adhdev/session-host-core/dist/index.d.ts +16 -1
  20. package/node_modules/@adhdev/session-host-core/dist/index.js +59 -0
  21. package/node_modules/@adhdev/session-host-core/dist/index.js.map +1 -1
  22. package/node_modules/@adhdev/session-host-core/dist/index.mjs +54 -0
  23. package/node_modules/@adhdev/session-host-core/dist/index.mjs.map +1 -1
  24. package/node_modules/@adhdev/session-host-core/package.json +1 -1
  25. package/package.json +1 -1
  26. package/src/commands/cdp-commands.ts +27 -0
  27. package/src/commands/chat-commands.ts +7 -2
  28. package/src/commands/cli-manager.ts +9 -5
  29. package/src/commands/handler.ts +1 -9
  30. package/src/commands/stream-commands.ts +26 -36
  31. package/src/daemon/dev-server.ts +4 -18
  32. package/src/index.d.ts +3 -0
  33. package/src/index.ts +12 -1
  34. package/src/providers/acp-provider-instance.ts +156 -14
  35. package/src/providers/cli-provider-instance.ts +54 -5
  36. package/src/providers/cli-script-results.ts +39 -0
  37. package/src/providers/contracts.ts +72 -19
  38. package/src/providers/control-effects.ts +86 -1
  39. package/src/providers/io-contracts.ts +340 -0
  40. package/src/providers/provider-loader.ts +18 -13
  41. package/src/providers/provider-schema.ts +154 -0
  42. package/src/session-host/runtime-surface.ts +80 -0
  43. package/src/session-host/startup-restore-policy.d.ts +1 -0
  44. package/src/session-host/startup-restore-policy.js +7 -0
  45. package/src/session-host/startup-restore-policy.ts +7 -0
  46. package/src/shared-types.ts +6 -0
  47. package/src/status/builders.ts +5 -81
  48. package/src/types.ts +3 -3
package/dist/index.mjs CHANGED
@@ -5085,6 +5085,61 @@ function normalizeProviderEffects(data) {
5085
5085
  }
5086
5086
  return effects;
5087
5087
  }
5088
+ function normalizeControlListResult(data) {
5089
+ if (data && typeof data === "object" && Array.isArray(data.options)) {
5090
+ return {
5091
+ options: normalizeControlOptions(data.options),
5092
+ ...isScalarControlValue(data.currentValue) ? { currentValue: data.currentValue } : {},
5093
+ ...typeof data.error === "string" ? { error: data.error } : {}
5094
+ };
5095
+ }
5096
+ const rawOptions = Array.isArray(data?.models) ? data.models : Array.isArray(data?.modes) ? data.modes : Array.isArray(data?.options) ? data.options : [];
5097
+ const options = normalizeControlOptions(rawOptions);
5098
+ return {
5099
+ options,
5100
+ ...isScalarControlValue(data?.current) ? { currentValue: data.current } : {},
5101
+ ...isScalarControlValue(data?.currentValue) ? { currentValue: data.currentValue } : {},
5102
+ ...typeof data?.error === "string" ? { error: data.error } : {}
5103
+ };
5104
+ }
5105
+ function normalizeControlSetResult(data) {
5106
+ const currentValue = isScalarControlValue(data?.currentValue) ? data.currentValue : isScalarControlValue(data?.value) ? data.value : void 0;
5107
+ return {
5108
+ ok: data?.ok === true || data?.success === true,
5109
+ ...currentValue !== void 0 ? { currentValue } : {},
5110
+ ...Array.isArray(data?.effects) ? { effects: normalizeProviderEffects(data) } : {},
5111
+ ...typeof data?.error === "string" ? { error: data.error } : {}
5112
+ };
5113
+ }
5114
+ function normalizeControlInvokeResult(data) {
5115
+ const currentValue = isScalarControlValue(data?.currentValue) ? data.currentValue : isScalarControlValue(data?.value) ? data.value : void 0;
5116
+ return {
5117
+ ok: data?.ok === true || data?.success === true,
5118
+ ...currentValue !== void 0 ? { currentValue } : {},
5119
+ ...Array.isArray(data?.effects) ? { effects: normalizeProviderEffects(data) } : {},
5120
+ ...typeof data?.error === "string" ? { error: data.error } : {}
5121
+ };
5122
+ }
5123
+ function normalizeControlOptions(options) {
5124
+ return options.map((option) => normalizeControlOption(option)).filter((option) => !!option);
5125
+ }
5126
+ function normalizeControlOption(option) {
5127
+ if (typeof option === "string") {
5128
+ return { value: option, label: option };
5129
+ }
5130
+ if (!option || typeof option !== "object") return null;
5131
+ const record = option;
5132
+ const value = typeof record.value === "string" ? record.value : typeof record.id === "string" ? record.id : null;
5133
+ if (!value) return null;
5134
+ const label = typeof record.label === "string" ? record.label : typeof record.name === "string" ? record.name : value;
5135
+ const normalized = { value, label };
5136
+ if (typeof record.description === "string") normalized.description = record.description;
5137
+ if (typeof record.group === "string") normalized.group = record.group;
5138
+ return normalized;
5139
+ }
5140
+ function isScalarControlValue(value) {
5141
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
5142
+ }
5088
5143
  function normalizeControlValue(value) {
5089
5144
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
5090
5145
  return value;
@@ -7076,50 +7131,6 @@ function isCdpConnected(cdpManagers, key) {
7076
7131
  }
7077
7132
  return false;
7078
7133
  }
7079
- function buildFallbackControls(providerControls, serverModel, serverMode, acpConfigOptions, acpModes) {
7080
- if (providerControls && providerControls.length > 0) return providerControls;
7081
- const controls = [];
7082
- const isAcp = !!(acpConfigOptions || acpModes);
7083
- const modelFromAcp = acpConfigOptions?.find((c) => c.category === "model");
7084
- if (!isAcp || modelFromAcp) {
7085
- controls.push({
7086
- id: "model",
7087
- type: "select",
7088
- label: "Model",
7089
- icon: "\u{1F916}",
7090
- placement: "bar",
7091
- dynamic: !modelFromAcp,
7092
- listScript: "listModels",
7093
- setScript: "setModel",
7094
- readFrom: "model",
7095
- ...modelFromAcp && {
7096
- options: modelFromAcp.options.map((o) => ({ value: o.value, label: o.name || o.value }))
7097
- }
7098
- });
7099
- }
7100
- const modeFromAcp = acpModes && acpModes.length > 0;
7101
- const thoughtFromAcp = !modeFromAcp && acpConfigOptions?.find((c) => c.category !== "model");
7102
- if (!isAcp || modeFromAcp || thoughtFromAcp) {
7103
- controls.push({
7104
- id: "mode",
7105
- type: thoughtFromAcp ? "cycle" : "select",
7106
- label: thoughtFromAcp ? "Thinking" : "Mode",
7107
- icon: thoughtFromAcp ? "\u{1F9E0}" : "\u26A1",
7108
- placement: "bar",
7109
- dynamic: !modeFromAcp && !thoughtFromAcp,
7110
- listScript: "listModes",
7111
- setScript: thoughtFromAcp ? "setThinkingLevel" : "setMode",
7112
- readFrom: "mode",
7113
- ...modeFromAcp && {
7114
- options: acpModes.map((m) => ({ value: m.id, label: m.name || m.id }))
7115
- },
7116
- ...thoughtFromAcp && {
7117
- options: thoughtFromAcp.options.map((o) => ({ value: o.value, label: o.name || o.value }))
7118
- }
7119
- });
7120
- }
7121
- return controls;
7122
- }
7123
7134
  var IDE_SESSION_CAPABILITIES = [
7124
7135
  "read_chat",
7125
7136
  "send_message",
@@ -7188,11 +7199,7 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
7188
7199
  currentAutoApprove: state.currentAutoApprove,
7189
7200
  ...includeSessionControls && {
7190
7201
  controlValues: state.controlValues,
7191
- providerControls: buildFallbackControls(
7192
- state.providerControls,
7193
- state.currentModel,
7194
- state.currentPlan
7195
- )
7202
+ providerControls: state.providerControls
7196
7203
  },
7197
7204
  errorMessage: state.errorMessage,
7198
7205
  errorReason: state.errorReason,
@@ -7222,11 +7229,7 @@ function buildExtensionAgentSession(parent, ext, options) {
7222
7229
  currentPlan: ext.currentPlan,
7223
7230
  ...includeSessionControls && {
7224
7231
  controlValues: ext.controlValues,
7225
- providerControls: buildFallbackControls(
7226
- ext.providerControls,
7227
- ext.currentModel,
7228
- ext.currentPlan
7229
- )
7232
+ providerControls: ext.providerControls
7230
7233
  },
7231
7234
  errorMessage: ext.errorMessage,
7232
7235
  errorReason: ext.errorReason,
@@ -7267,9 +7270,7 @@ function buildCliSession(state, options) {
7267
7270
  },
7268
7271
  ...includeSessionControls && {
7269
7272
  controlValues: state.controlValues,
7270
- providerControls: buildFallbackControls(
7271
- state.providerControls
7272
- )
7273
+ providerControls: state.providerControls
7273
7274
  },
7274
7275
  errorMessage: state.errorMessage,
7275
7276
  errorReason: state.errorReason,
@@ -7301,13 +7302,7 @@ function buildAcpSession(state, options) {
7301
7302
  acpConfigOptions: state.acpConfigOptions,
7302
7303
  acpModes: state.acpModes,
7303
7304
  controlValues: state.controlValues,
7304
- providerControls: buildFallbackControls(
7305
- state.providerControls,
7306
- state.currentModel,
7307
- state.currentPlan,
7308
- state.acpConfigOptions,
7309
- state.acpModes
7310
- )
7305
+ providerControls: state.providerControls
7311
7306
  },
7312
7307
  errorMessage: state.errorMessage,
7313
7308
  errorReason: state.errorReason,
@@ -7390,10 +7385,217 @@ function reconcileIdeRuntimeSessions(instanceManager, sessionRegistry) {
7390
7385
  // src/commands/handler.ts
7391
7386
  init_logger();
7392
7387
 
7388
+ // src/providers/io-contracts.ts
7389
+ function normalizeInputEnvelope(input) {
7390
+ const normalized = normalizeInputEnvelopePayload(input);
7391
+ const textFallback = normalized.textFallback ?? flattenInputParts(normalized.parts);
7392
+ return {
7393
+ parts: normalized.parts,
7394
+ textFallback,
7395
+ ...normalized.metadata ? { metadata: normalized.metadata } : {}
7396
+ };
7397
+ }
7398
+ function normalizeMessageParts(content) {
7399
+ if (typeof content === "string") return [{ type: "text", text: content }];
7400
+ if (!Array.isArray(content)) {
7401
+ if (content && typeof content === "object" && typeof content.text === "string") {
7402
+ return [{ type: "text", text: String(content.text) }];
7403
+ }
7404
+ return [];
7405
+ }
7406
+ const parts = [];
7407
+ for (const raw of content) {
7408
+ if (typeof raw === "string") {
7409
+ parts.push({ type: "text", text: raw });
7410
+ continue;
7411
+ }
7412
+ if (!raw || typeof raw !== "object") continue;
7413
+ const part = normalizeMessagePartObject(raw);
7414
+ if (part) parts.push(part);
7415
+ }
7416
+ return parts;
7417
+ }
7418
+ function flattenMessageParts(parts) {
7419
+ return parts.map((part) => {
7420
+ if (part.type === "text") return part.text;
7421
+ if (part.type === "resource") return part.resource.text || "";
7422
+ return "";
7423
+ }).filter((value) => value.length > 0).join("\n");
7424
+ }
7425
+ function normalizeInputEnvelopePayload(input) {
7426
+ if (typeof input === "string") {
7427
+ return { parts: [{ type: "text", text: input }], textFallback: input };
7428
+ }
7429
+ if (!input || typeof input !== "object") {
7430
+ return { parts: [], textFallback: "" };
7431
+ }
7432
+ const record = input;
7433
+ const nestedInput = record.input;
7434
+ if (nestedInput && typeof nestedInput === "object") {
7435
+ const nested = nestedInput;
7436
+ return {
7437
+ parts: normalizeInputParts(nested.parts ?? nested.prompt),
7438
+ textFallback: typeof nested.textFallback === "string" ? nested.textFallback : void 0,
7439
+ metadata: normalizeInputMetadata(nested.metadata)
7440
+ };
7441
+ }
7442
+ const directText = typeof record.text === "string" ? record.text : typeof record.message === "string" ? record.message : void 0;
7443
+ if (directText !== void 0) {
7444
+ return { parts: [{ type: "text", text: directText }], textFallback: directText };
7445
+ }
7446
+ const directParts = normalizeInputParts(record.parts ?? record.prompt);
7447
+ return {
7448
+ parts: directParts,
7449
+ textFallback: typeof record.textFallback === "string" ? record.textFallback : void 0,
7450
+ metadata: normalizeInputMetadata(record.metadata)
7451
+ };
7452
+ }
7453
+ function normalizeInputMetadata(value) {
7454
+ if (!value || typeof value !== "object") return void 0;
7455
+ const record = value;
7456
+ const metadata = {};
7457
+ if (record.source === "dashboard" || record.source === "shortcut_api" || record.source === "provider_script" || record.source === "session_replay") {
7458
+ metadata.source = record.source;
7459
+ }
7460
+ if (typeof record.clientTimestamp === "number" && Number.isFinite(record.clientTimestamp)) {
7461
+ metadata.clientTimestamp = record.clientTimestamp;
7462
+ }
7463
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
7464
+ }
7465
+ function normalizeInputParts(value) {
7466
+ if (!Array.isArray(value)) return [];
7467
+ const parts = [];
7468
+ for (const raw of value) {
7469
+ if (typeof raw === "string") {
7470
+ parts.push({ type: "text", text: raw });
7471
+ continue;
7472
+ }
7473
+ if (!raw || typeof raw !== "object") continue;
7474
+ const part = normalizeInputPartObject(raw);
7475
+ if (part) parts.push(part);
7476
+ }
7477
+ return parts;
7478
+ }
7479
+ function normalizeInputPartObject(raw) {
7480
+ const type = raw.type;
7481
+ if (type === "text" && typeof raw.text === "string") {
7482
+ return { type, text: raw.text };
7483
+ }
7484
+ if (type === "image" && typeof raw.mimeType === "string") {
7485
+ return {
7486
+ type,
7487
+ mimeType: raw.mimeType,
7488
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7489
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7490
+ ...typeof raw.alt === "string" ? { alt: raw.alt } : {}
7491
+ };
7492
+ }
7493
+ if (type === "audio" && typeof raw.mimeType === "string") {
7494
+ return {
7495
+ type,
7496
+ mimeType: raw.mimeType,
7497
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7498
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7499
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7500
+ };
7501
+ }
7502
+ if (type === "video" && typeof raw.mimeType === "string") {
7503
+ return {
7504
+ type,
7505
+ mimeType: raw.mimeType,
7506
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7507
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7508
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7509
+ };
7510
+ }
7511
+ if (type === "resource" && typeof raw.uri === "string") {
7512
+ return {
7513
+ type,
7514
+ uri: raw.uri,
7515
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7516
+ ...typeof raw.name === "string" ? { name: raw.name } : {},
7517
+ ...typeof raw.text === "string" ? { text: raw.text } : {},
7518
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
7519
+ };
7520
+ }
7521
+ if (type === "resource_link" && typeof raw.uri === "string") {
7522
+ return {
7523
+ type: "resource",
7524
+ uri: raw.uri,
7525
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7526
+ ...typeof raw.name === "string" ? { name: raw.name } : {}
7527
+ };
7528
+ }
7529
+ return null;
7530
+ }
7531
+ function normalizeMessagePartObject(raw) {
7532
+ const type = raw.type;
7533
+ if (type === "text" && typeof raw.text === "string") {
7534
+ return { type, text: raw.text };
7535
+ }
7536
+ if (type === "image" && typeof raw.mimeType === "string") {
7537
+ return {
7538
+ type,
7539
+ mimeType: raw.mimeType,
7540
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7541
+ ...typeof raw.data === "string" ? { data: raw.data } : {}
7542
+ };
7543
+ }
7544
+ if (type === "audio" && typeof raw.mimeType === "string") {
7545
+ return {
7546
+ type,
7547
+ mimeType: raw.mimeType,
7548
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7549
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7550
+ ...typeof raw.transcript === "string" ? { transcript: raw.transcript } : {}
7551
+ };
7552
+ }
7553
+ if (type === "video" && typeof raw.mimeType === "string") {
7554
+ return {
7555
+ type,
7556
+ mimeType: raw.mimeType,
7557
+ ...typeof raw.uri === "string" ? { uri: raw.uri } : {},
7558
+ ...typeof raw.data === "string" ? { data: raw.data } : {},
7559
+ ...typeof raw.posterUri === "string" ? { posterUri: raw.posterUri } : {}
7560
+ };
7561
+ }
7562
+ if (type === "resource_link" && typeof raw.uri === "string" && typeof raw.name === "string") {
7563
+ return {
7564
+ type,
7565
+ uri: raw.uri,
7566
+ name: raw.name,
7567
+ ...typeof raw.mimeType === "string" ? { mimeType: raw.mimeType } : {},
7568
+ ...typeof raw.size === "number" ? { size: raw.size } : {}
7569
+ };
7570
+ }
7571
+ if (type === "resource" && raw.resource && typeof raw.resource === "object") {
7572
+ const resource = raw.resource;
7573
+ if (typeof resource.uri !== "string") return null;
7574
+ return {
7575
+ type,
7576
+ resource: {
7577
+ uri: resource.uri,
7578
+ ...typeof resource.mimeType === "string" || resource.mimeType === null ? { mimeType: resource.mimeType } : {},
7579
+ ...typeof resource.text === "string" ? { text: resource.text } : {},
7580
+ ...typeof resource.blob === "string" ? { blob: resource.blob } : {}
7581
+ }
7582
+ };
7583
+ }
7584
+ return null;
7585
+ }
7586
+ function flattenInputParts(parts) {
7587
+ return parts.map((part) => {
7588
+ if (part.type === "text") return part.text;
7589
+ if (part.type === "audio") return part.transcript || "";
7590
+ if (part.type === "resource") return part.text || "";
7591
+ return "";
7592
+ }).filter((value) => value.length > 0).join("\n");
7593
+ }
7594
+
7393
7595
  // src/providers/contracts.ts
7394
7596
  function flattenContent(content) {
7395
7597
  if (typeof content === "string") return content;
7396
- return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
7598
+ return flattenMessageParts(normalizeMessageParts(content));
7397
7599
  }
7398
7600
 
7399
7601
  // src/commands/chat-commands.ts
@@ -7582,6 +7784,9 @@ function buildRecentSendKey(h, args, provider, text) {
7582
7784
  const target = args?.targetSessionId || args?.agentType || h.currentSession?.providerType || h.currentProviderType || h.currentManagerKey || "unknown";
7583
7785
  return `${transport}:${target}:${text.trim()}`;
7584
7786
  }
7787
+ function getSendChatInputEnvelope(args) {
7788
+ return normalizeInputEnvelope(args?.input ? { input: args.input } : args);
7789
+ }
7585
7790
  function getHistorySessionId(h, args) {
7586
7791
  const explicit = typeof args?.historySessionId === "string" ? args.historySessionId.trim() : "";
7587
7792
  if (explicit) return explicit;
@@ -7986,7 +8191,8 @@ async function handleReadChat(h, args) {
7986
8191
  return buildReadChatCommandResult({ messages: [], status: "idle" }, args);
7987
8192
  }
7988
8193
  async function handleSendChat(h, args) {
7989
- const text = args?.text || args?.message;
8194
+ const input = getSendChatInputEnvelope(args);
8195
+ const text = input.textFallback;
7990
8196
  if (!text) return { success: false, error: "text required" };
7991
8197
  const _log = (msg) => LOG.debug("Command", `[send_chat] ${msg}`);
7992
8198
  const provider = h.getProvider(args?.agentType);
@@ -8926,6 +9132,21 @@ function listDirectoryEntriesSafe(dirPath) {
8926
9132
  }
8927
9133
  return files;
8928
9134
  }
9135
+ function listWindowsDriveEntries(excludePath) {
9136
+ const excluded = typeof excludePath === "string" ? excludePath.toLowerCase() : "";
9137
+ const drives = [];
9138
+ for (let code = 65; code <= 90; code += 1) {
9139
+ const letter = String.fromCharCode(code);
9140
+ const root = `${letter}:\\`;
9141
+ try {
9142
+ if (!fs4.existsSync(root)) continue;
9143
+ if (excluded && root.toLowerCase() === excluded) continue;
9144
+ drives.push({ name: `${letter}:`, type: "directory", path: root });
9145
+ } catch {
9146
+ }
9147
+ }
9148
+ return drives;
9149
+ }
8929
9150
  async function handleFileRead(h, args) {
8930
9151
  try {
8931
9152
  const filePath = resolveSafePath(args?.path);
@@ -8958,12 +9179,51 @@ async function handleFileListBrowse(h, args) {
8958
9179
  try {
8959
9180
  const dirPath = resolveSafePath(args?.path || ".");
8960
9181
  const files = listDirectoryEntriesSafe(dirPath).filter((entry) => entry.type === "directory").sort((a, b) => a.name.localeCompare(b.name));
9182
+ if (process.platform === "win32" && /^[A-Za-z]:\\?$/.test(dirPath)) {
9183
+ const driveEntries = listWindowsDriveEntries(dirPath);
9184
+ return {
9185
+ success: true,
9186
+ files: [...driveEntries, ...files],
9187
+ path: dirPath
9188
+ };
9189
+ }
8961
9190
  return { success: true, files, path: dirPath };
8962
9191
  } catch (e) {
8963
9192
  return { success: false, error: e.message };
8964
9193
  }
8965
9194
  }
8966
9195
 
9196
+ // src/providers/cli-script-results.ts
9197
+ function parseCliScriptResult(result) {
9198
+ if (typeof result === "string") {
9199
+ try {
9200
+ const parsed = JSON.parse(result);
9201
+ if (parsed && typeof parsed === "object" && parsed.success === false) {
9202
+ return { success: false, payload: parsed };
9203
+ }
9204
+ return { success: true, payload: parsed };
9205
+ } catch {
9206
+ return { success: true, payload: { result } };
9207
+ }
9208
+ }
9209
+ if (result && typeof result === "object" && "success" in result && result.success === false) {
9210
+ return { success: false, payload: result };
9211
+ }
9212
+ return { success: true, payload: result };
9213
+ }
9214
+ function getCliScriptCommand(payload) {
9215
+ if (!payload || typeof payload !== "object") return null;
9216
+ if (typeof payload.sendMessage === "string" && payload.sendMessage.trim()) {
9217
+ return { type: "send_message", text: payload.sendMessage.trim() };
9218
+ }
9219
+ const command = payload.command;
9220
+ if (!command || typeof command !== "object") return null;
9221
+ if (command.type !== "send_message" && command.type !== "pty_write") return null;
9222
+ const text = typeof command.text === "string" ? command.text.trim() : typeof command.message === "string" ? command.message.trim() : "";
9223
+ if (!text) return null;
9224
+ return { type: command.type, text };
9225
+ }
9226
+
8967
9227
  // src/commands/stream-commands.ts
8968
9228
  init_logger();
8969
9229
  function getCliPresentationMode(h, targetSessionId) {
@@ -9054,34 +9314,19 @@ function normalizeProviderScriptArgs(args) {
9054
9314
  }
9055
9315
  return normalizedArgs;
9056
9316
  }
9057
- function parseScriptResult(result) {
9058
- if (typeof result === "string") {
9059
- try {
9060
- const parsed = JSON.parse(result);
9061
- if (parsed && typeof parsed === "object" && parsed.success === false) {
9062
- return { success: false, payload: parsed };
9063
- }
9064
- return { success: true, payload: parsed };
9065
- } catch {
9066
- return { success: true, payload: { result } };
9067
- }
9317
+ function buildControlScriptResult(scriptName, payload) {
9318
+ if (!payload || typeof payload !== "object") return {};
9319
+ if (Array.isArray(payload.options) || Array.isArray(payload.models) || Array.isArray(payload.modes)) {
9320
+ return { controlResult: normalizeControlListResult(payload) };
9068
9321
  }
9069
- if (result && typeof result === "object" && "success" in result && result.success === false) {
9070
- return { success: false, payload: result };
9322
+ const looksLikeValueMutation = /^set|^change/i.test(scriptName) || payload.currentValue !== void 0 || payload.value !== void 0;
9323
+ if (looksLikeValueMutation) {
9324
+ return { controlResult: normalizeControlSetResult(payload) };
9071
9325
  }
9072
- return { success: true, payload: result };
9073
- }
9074
- function getCliScriptCommand(payload) {
9075
- if (!payload || typeof payload !== "object") return null;
9076
- if (typeof payload.sendMessage === "string" && payload.sendMessage.trim()) {
9077
- return { type: "send_message", text: payload.sendMessage.trim() };
9326
+ if (payload.ok !== void 0 || payload.success !== void 0 || Array.isArray(payload.effects)) {
9327
+ return { controlResult: normalizeControlInvokeResult(payload) };
9078
9328
  }
9079
- const command = payload.command;
9080
- if (!command || typeof command !== "object") return null;
9081
- if (command.type !== "send_message" && command.type !== "pty_write") return null;
9082
- const text = typeof command.text === "string" ? command.text.trim() : typeof command.message === "string" ? command.message.trim() : "";
9083
- if (!text) return null;
9084
- return { type: command.type, text };
9329
+ return {};
9085
9330
  }
9086
9331
  function applyProviderPatch(h, args, payload) {
9087
9332
  if (!payload || typeof payload !== "object") return;
@@ -9115,7 +9360,7 @@ async function executeProviderScript(h, args, scriptName) {
9115
9360
  }
9116
9361
  try {
9117
9362
  const raw = await adapter.invokeScript(actualScriptName, normalizedArgs);
9118
- const parsed = parseScriptResult(raw);
9363
+ const parsed = parseCliScriptResult(raw);
9119
9364
  if (!parsed.success) {
9120
9365
  return { success: false, ...parsed.payload || {} };
9121
9366
  }
@@ -9126,7 +9371,11 @@ async function executeProviderScript(h, args, scriptName) {
9126
9371
  adapter.writeRaw(cliCommand.text + "\r");
9127
9372
  }
9128
9373
  applyProviderPatch(h, args, parsed.payload);
9129
- return { success: true, ...parsed.payload && typeof parsed.payload === "object" ? parsed.payload : { result: parsed.payload } };
9374
+ return {
9375
+ success: true,
9376
+ ...parsed.payload && typeof parsed.payload === "object" ? parsed.payload : { result: parsed.payload },
9377
+ ...buildControlScriptResult(scriptName, parsed.payload)
9378
+ };
9130
9379
  } catch (e) {
9131
9380
  return { success: false, error: `Script execution failed: ${e.message}` };
9132
9381
  }
@@ -9189,7 +9438,7 @@ async function executeProviderScript(h, args, scriptName) {
9189
9438
  if (parsed && typeof parsed === "object" && parsed.success === false) {
9190
9439
  return { success: false, ...parsed };
9191
9440
  }
9192
- return { success: true, ...parsed };
9441
+ return { success: true, ...parsed, ...buildControlScriptResult(scriptName, parsed) };
9193
9442
  } catch {
9194
9443
  return { success: true, result };
9195
9444
  }
@@ -9200,9 +9449,6 @@ async function executeProviderScript(h, args, scriptName) {
9200
9449
  return { success: false, error: `Script execution failed: ${e.message}` };
9201
9450
  }
9202
9451
  }
9203
- async function handleExtensionScript(h, args, scriptName) {
9204
- return executeProviderScript(h, args, scriptName);
9205
- }
9206
9452
  async function handleProviderScript(h, args) {
9207
9453
  const scriptName = typeof args?.scriptName === "string" ? args.scriptName.trim() : "";
9208
9454
  if (!scriptName) return { success: false, error: "scriptName is required" };
@@ -9645,11 +9891,7 @@ var DaemonCommandHandler = class {
9645
9891
  "focus_session",
9646
9892
  "pty_input",
9647
9893
  "pty_resize",
9648
- "invoke_provider_script",
9649
- "list_extension_models",
9650
- "set_extension_model",
9651
- "list_extension_modes",
9652
- "set_extension_mode"
9894
+ "invoke_provider_script"
9653
9895
  ]);
9654
9896
  if (this._currentRoute.sessionLookupFailed && sessionScopedCommands.has(cmd)) {
9655
9897
  const result2 = {
@@ -9761,17 +10003,9 @@ var DaemonCommandHandler = class {
9761
10003
  return handleGetIdeExtensions(this, args);
9762
10004
  case "set_ide_extension":
9763
10005
  return handleSetIdeExtension(this, args);
9764
- // ─── Extension Model / Mode Control (stream-commands.ts) ──────────
10006
+ // ─── Provider control execution (stream-commands.ts) ──────────
9765
10007
  case "invoke_provider_script":
9766
10008
  return handleProviderScript(this, args);
9767
- case "list_extension_models":
9768
- return handleExtensionScript(this, args, "listModels");
9769
- case "set_extension_model":
9770
- return handleExtensionScript(this, args, "setModel");
9771
- case "list_extension_modes":
9772
- return handleExtensionScript(this, args, "listModes");
9773
- case "set_extension_mode":
9774
- return handleExtensionScript(this, args, "setMode");
9775
10009
  // ─── Provider Auto-Fix / Clone (DevServer proxy) ──────────
9776
10010
  case "provider_auto_fix":
9777
10011
  return this.proxyDevServerPost(args, "auto-implement");
@@ -9889,18 +10123,18 @@ var DaemonCommandHandler = class {
9889
10123
  // src/commands/cli-manager.ts
9890
10124
  init_provider_cli_adapter();
9891
10125
  import * as os12 from "os";
9892
- import * as path12 from "path";
10126
+ import * as path13 from "path";
9893
10127
  import * as crypto4 from "crypto";
9894
10128
  import chalk from "chalk";
9895
10129
  init_config();
9896
10130
 
9897
10131
  // src/providers/cli-provider-instance.ts
9898
- init_provider_cli_adapter();
9899
10132
  import * as os11 from "os";
9900
10133
  import * as path11 from "path";
9901
10134
  import * as crypto3 from "crypto";
9902
10135
  import * as fs5 from "fs";
9903
10136
  import { createRequire } from "module";
10137
+ init_provider_cli_adapter();
9904
10138
  init_logger();
9905
10139
  var CachedDatabaseSync = null;
9906
10140
  function getDatabaseSync() {
@@ -9913,6 +10147,23 @@ function getDatabaseSync() {
9913
10147
  }
9914
10148
  return CachedDatabaseSync;
9915
10149
  }
10150
+ function getForcedNewSessionScriptName(provider, launchMode) {
10151
+ if (!provider || launchMode !== "new") return null;
10152
+ const resume = provider.resume;
10153
+ if (!resume?.supported) return null;
10154
+ if (Array.isArray(resume.newSessionArgs) && resume.newSessionArgs.length > 0) return null;
10155
+ const controls = Array.isArray(provider.controls) ? provider.controls : [];
10156
+ for (const control of controls) {
10157
+ if (control?.type !== "action") continue;
10158
+ const invokeScript = typeof control?.invokeScript === "string" ? control.invokeScript.trim() : "";
10159
+ if (!invokeScript) continue;
10160
+ const controlId = typeof control?.id === "string" ? control.id.trim() : "";
10161
+ if (controlId === "new_session" || /^new.?session$/i.test(invokeScript)) {
10162
+ return invokeScript;
10163
+ }
10164
+ }
10165
+ return null;
10166
+ }
9916
10167
  var CliProviderInstance = class {
9917
10168
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
9918
10169
  this.provider = provider;
@@ -9971,6 +10222,7 @@ var CliProviderInstance = class {
9971
10222
  this.detectStatusTransition();
9972
10223
  });
9973
10224
  await this.adapter.spawn();
10225
+ await this.enforceFreshSessionLaunchIfNeeded();
9974
10226
  this.maybeAppendRuntimeRecoveryMessage(this.adapter.getRuntimeMetadata());
9975
10227
  if (this.providerSessionId) {
9976
10228
  this.historyWriter.compactHistorySession(this.type, this.providerSessionId);
@@ -10162,10 +10414,13 @@ var CliProviderInstance = class {
10162
10414
  });
10163
10415
  }
10164
10416
  onEvent(event, data) {
10165
- if (event === "send_message" && data?.text) {
10166
- void this.adapter.sendMessage(data.text).catch((e) => {
10167
- LOG.warn("CLI", `[${this.type}] send_message failed: ${e?.message || e}`);
10168
- });
10417
+ if (event === "send_message") {
10418
+ const input = normalizeInputEnvelope(data);
10419
+ if (input.textFallback) {
10420
+ void this.adapter.sendMessage(input.textFallback).catch((e) => {
10421
+ LOG.warn("CLI", `[${this.type}] send_message failed: ${e?.message || e}`);
10422
+ });
10423
+ }
10169
10424
  } else if (event === "server_connected" && data?.serverConn) {
10170
10425
  this.adapter.setServerConn(data.serverConn);
10171
10426
  } else if (event === "resolve_action" && data) {
@@ -10183,6 +10438,23 @@ var CliProviderInstance = class {
10183
10438
  }
10184
10439
  completedDebounceTimer = null;
10185
10440
  completedDebouncePending = null;
10441
+ async enforceFreshSessionLaunchIfNeeded() {
10442
+ const scriptName = getForcedNewSessionScriptName(this.provider, this.launchMode);
10443
+ if (!scriptName) return;
10444
+ LOG.info("CLI", `[${this.type}] forcing fresh session launch via script: ${scriptName}`);
10445
+ const raw = await this.adapter.invokeScript(scriptName, {});
10446
+ const parsed = parseCliScriptResult(raw);
10447
+ if (!parsed.success) {
10448
+ throw new Error(parsed.payload?.error || `Failed to invoke fresh-session script '${scriptName}'`);
10449
+ }
10450
+ const cliCommand = getCliScriptCommand(parsed.payload);
10451
+ if (cliCommand?.type === "send_message" && cliCommand.text) {
10452
+ await this.adapter.sendMessage(cliCommand.text);
10453
+ } else if (cliCommand?.type === "pty_write" && cliCommand.text) {
10454
+ this.adapter.writeRaw(cliCommand.text + "\r");
10455
+ }
10456
+ this.applyProviderResponse(parsed.payload, { phase: "immediate" });
10457
+ }
10186
10458
  detectStatusTransition() {
10187
10459
  const now = Date.now();
10188
10460
  const adapterStatus = this.adapter.getStatus();
@@ -10566,6 +10838,7 @@ ${effect.notification.body || ""}`.trim();
10566
10838
  };
10567
10839
 
10568
10840
  // src/providers/acp-provider-instance.ts
10841
+ import * as path12 from "path";
10569
10842
  import { Readable, Writable } from "stream";
10570
10843
  import { spawn } from "child_process";
10571
10844
  import {
@@ -10575,6 +10848,101 @@ import {
10575
10848
  PROTOCOL_VERSION
10576
10849
  } from "@agentclientprotocol/sdk";
10577
10850
  init_logger();
10851
+ function getPromptCapabilityFlags(agentCapabilities) {
10852
+ const prompt = agentCapabilities?.promptCapabilities || {};
10853
+ return {
10854
+ image: prompt.image === true,
10855
+ audio: prompt.audio === true,
10856
+ embeddedContext: prompt.embeddedContext === true
10857
+ };
10858
+ }
10859
+ function getResourceNameFromUri(uri, fallback) {
10860
+ try {
10861
+ if (uri.startsWith("file://")) {
10862
+ return path12.basename(new URL(uri).pathname) || fallback;
10863
+ }
10864
+ return path12.basename(uri) || fallback;
10865
+ } catch {
10866
+ return fallback;
10867
+ }
10868
+ }
10869
+ function inputPartToResourceLink(part, fallbackName) {
10870
+ if (!part.uri) return null;
10871
+ return {
10872
+ type: "resource_link",
10873
+ uri: part.uri,
10874
+ name: getResourceNameFromUri(part.uri, fallbackName),
10875
+ ...part.mimeType ? { mimeType: part.mimeType } : {}
10876
+ };
10877
+ }
10878
+ function appendPromptText(promptParts, text) {
10879
+ const normalized = typeof text === "string" ? text.trim() : "";
10880
+ if (!normalized) return;
10881
+ const last = promptParts[promptParts.length - 1];
10882
+ if (last?.type === "text" && last.text === normalized) return;
10883
+ promptParts.push({ type: "text", text: normalized });
10884
+ }
10885
+ function buildAcpPromptParts(input, agentCapabilities) {
10886
+ const caps = getPromptCapabilityFlags(agentCapabilities);
10887
+ const promptParts = [];
10888
+ for (const part of input.parts) {
10889
+ if (part.type === "text") {
10890
+ promptParts.push({ type: "text", text: part.text });
10891
+ continue;
10892
+ }
10893
+ if (part.type === "image") {
10894
+ if (caps.image && part.data) {
10895
+ promptParts.push({
10896
+ type: "image",
10897
+ data: part.data,
10898
+ mimeType: part.mimeType,
10899
+ ...part.uri ? { uri: part.uri } : {}
10900
+ });
10901
+ continue;
10902
+ }
10903
+ const fallback = inputPartToResourceLink(part, "image");
10904
+ if (fallback) promptParts.push(fallback);
10905
+ appendPromptText(promptParts, part.alt || (!part.uri ? `Attached image (${part.mimeType})` : void 0));
10906
+ continue;
10907
+ }
10908
+ if (part.type === "audio") {
10909
+ if (caps.audio && part.data) {
10910
+ promptParts.push({
10911
+ type: "audio",
10912
+ data: part.data,
10913
+ mimeType: part.mimeType
10914
+ });
10915
+ continue;
10916
+ }
10917
+ const fallback = inputPartToResourceLink(part, "audio");
10918
+ if (fallback) promptParts.push(fallback);
10919
+ appendPromptText(promptParts, part.transcript || (!part.uri ? `Attached audio (${part.mimeType})` : void 0));
10920
+ continue;
10921
+ }
10922
+ if (part.type === "resource") {
10923
+ if (caps.embeddedContext && (part.text || part.data)) {
10924
+ promptParts.push({
10925
+ type: "resource",
10926
+ resource: part.text ? { uri: part.uri, text: part.text, mimeType: part.mimeType ?? null } : { uri: part.uri, blob: part.data || "", mimeType: part.mimeType ?? null }
10927
+ });
10928
+ continue;
10929
+ }
10930
+ const fallback = inputPartToResourceLink(part, part.name || "resource");
10931
+ if (fallback) promptParts.push(fallback);
10932
+ appendPromptText(promptParts, part.text || (!part.uri && part.name ? part.name : void 0));
10933
+ continue;
10934
+ }
10935
+ if (part.type === "video") {
10936
+ const fallback = inputPartToResourceLink(part, "video");
10937
+ if (fallback) promptParts.push(fallback);
10938
+ appendPromptText(promptParts, !part.uri ? `Attached video (${part.mimeType})` : void 0);
10939
+ }
10940
+ }
10941
+ if (!promptParts.some((part) => part.type === "text") && input.textFallback) {
10942
+ promptParts.unshift({ type: "text", text: input.textFallback });
10943
+ }
10944
+ return promptParts;
10945
+ }
10578
10946
  var AcpProviderInstance = class {
10579
10947
  constructor(provider, workingDir, cliArgs = []) {
10580
10948
  this.cliArgs = cliArgs;
@@ -10703,8 +11071,10 @@ var AcpProviderInstance = class {
10703
11071
  };
10704
11072
  }
10705
11073
  onEvent(event, data) {
10706
- if (event === "send_message" && data?.text) {
10707
- this.sendPrompt(data.text).catch(
11074
+ if (event === "send_message") {
11075
+ const input = normalizeInputEnvelope(data);
11076
+ const promptParts = buildAcpPromptParts(input, this.agentCapabilities);
11077
+ this.sendPrompt(input.textFallback, promptParts.length > 0 ? promptParts : void 0).catch(
10708
11078
  (e) => this.log.warn(`[${this.type}] sendPrompt error: ${e?.message}`)
10709
11079
  );
10710
11080
  } else if (event === "resolve_action") {
@@ -11129,18 +11499,34 @@ var AcpProviderInstance = class {
11129
11499
  this.log.warn(`[${this.type}] Cannot send prompt: no active connection/session`);
11130
11500
  return;
11131
11501
  }
11132
- let promptParts;
11133
- if (contentBlocks && contentBlocks.length > 0) {
11134
- promptParts = contentBlocks.map((b) => {
11135
- if (b.type === "text") return { type: "text", text: b.text };
11136
- if (b.type === "image") return { type: "image", data: b.data, mimeType: b.mimeType };
11137
- if (b.type === "resource_link") return { type: "resource_link", uri: b.uri, name: b.name };
11138
- if (b.type === "resource") return { type: "resource", resource: b.resource };
11139
- return { type: "text", text: flattenContent([b]) };
11140
- });
11141
- } else {
11142
- promptParts = [{ type: "text", text }];
11143
- }
11502
+ const promptParts = contentBlocks && contentBlocks.length > 0 ? contentBlocks.map((b) => {
11503
+ if (b.type === "text") return { type: "text", text: b.text };
11504
+ if (b.type === "image") {
11505
+ return {
11506
+ type: "image",
11507
+ data: b.data,
11508
+ mimeType: b.mimeType,
11509
+ ...b.uri ? { uri: b.uri } : {}
11510
+ };
11511
+ }
11512
+ if (b.type === "audio") {
11513
+ return {
11514
+ type: "audio",
11515
+ data: b.data,
11516
+ mimeType: b.mimeType
11517
+ };
11518
+ }
11519
+ if (b.type === "resource_link") {
11520
+ return {
11521
+ type: "resource_link",
11522
+ uri: b.uri,
11523
+ name: b.name,
11524
+ ...b.mimeType ? { mimeType: b.mimeType } : {}
11525
+ };
11526
+ }
11527
+ if (b.type === "resource") return { type: "resource", resource: b.resource };
11528
+ return { type: "text", text: flattenContent([b]) };
11529
+ }) : [{ type: "text", text }];
11144
11530
  this.messages.push({
11145
11531
  role: "user",
11146
11532
  content: contentBlocks && contentBlocks.length > 0 ? contentBlocks : text,
@@ -11204,6 +11590,13 @@ var AcpProviderInstance = class {
11204
11590
  this.partialBlocks.push({
11205
11591
  type: "image",
11206
11592
  data: content.data,
11593
+ mimeType: content.mimeType,
11594
+ ...content.uri ? { uri: content.uri } : {}
11595
+ });
11596
+ } else if (content.type === "audio") {
11597
+ this.partialBlocks.push({
11598
+ type: "audio",
11599
+ data: content.data,
11207
11600
  mimeType: content.mimeType
11208
11601
  });
11209
11602
  } else if (content.type === "resource_link") {
@@ -11595,7 +11988,7 @@ function resolveCliSessionBinding(provider, normalizedType, cliArgs, requestedRe
11595
11988
  };
11596
11989
  }
11597
11990
  if (!supportsExplicitSessionStart(resume)) {
11598
- return { cliArgs: baseArgs, launchMode: "manual" };
11991
+ return { cliArgs: baseArgs, launchMode: "new" };
11599
11992
  }
11600
11993
  const providerSessionId = crypto4.randomUUID();
11601
11994
  const newSessionArgs = expandResumeArgs(resume.newSessionArgs, providerSessionId);
@@ -11743,7 +12136,7 @@ var DaemonCliManager = class {
11743
12136
  async startSession(cliType, workingDir, cliArgs, initialModel, options) {
11744
12137
  const trimmed = (workingDir || "").trim();
11745
12138
  if (!trimmed) throw new Error("working directory required");
11746
- const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path12.resolve(trimmed);
12139
+ const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os12.homedir()) : path13.resolve(trimmed);
11747
12140
  const normalizedType = this.providerLoader.resolveAlias(cliType);
11748
12141
  const provider = this.providerLoader.getByAlias(cliType);
11749
12142
  const key = crypto4.randomUUID();
@@ -11791,7 +12184,8 @@ ${installInfo}`
11791
12184
  instanceManager2.removeInstance(key);
11792
12185
  },
11793
12186
  sendMessage: async (text) => {
11794
- acpInstance.onEvent("send_message", { text });
12187
+ const input = normalizeInputEnvelope(text);
12188
+ acpInstance.onEvent("send_message", { input });
11795
12189
  },
11796
12190
  getStatus: () => {
11797
12191
  const state = acpInstance.getState();
@@ -12200,7 +12594,8 @@ Run 'adhdev doctor' for detailed diagnostics.`
12200
12594
  if (!found) throw new Error(`CLI agent not running: ${agentType}`);
12201
12595
  const { adapter, key } = found;
12202
12596
  if (action === "send_chat") {
12203
- const message = args.message || args.text;
12597
+ const input = normalizeInputEnvelope(args?.input ? { input: args.input } : args);
12598
+ const message = input.textFallback;
12204
12599
  if (!message) throw new Error("message required for send_chat");
12205
12600
  await adapter.sendMessage(message);
12206
12601
  return { success: true, status: "generating" };
@@ -12222,14 +12617,144 @@ Run 'adhdev doctor' for detailed diagnostics.`
12222
12617
  import { execSync as execSync4, spawn as spawn2 } from "child_process";
12223
12618
  import * as net from "net";
12224
12619
  import * as os14 from "os";
12225
- import * as path14 from "path";
12620
+ import * as path15 from "path";
12226
12621
 
12227
12622
  // src/providers/provider-loader.ts
12228
12623
  import * as fs6 from "fs";
12229
- import * as path13 from "path";
12624
+ import * as path14 from "path";
12230
12625
  import * as os13 from "os";
12231
12626
  import * as chokidar from "chokidar";
12232
12627
  init_logger();
12628
+
12629
+ // src/providers/provider-schema.ts
12630
+ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
12631
+ "type",
12632
+ "name",
12633
+ "category",
12634
+ "aliases",
12635
+ "cdpPorts",
12636
+ "targetFilter",
12637
+ "cli",
12638
+ "icon",
12639
+ "displayName",
12640
+ "install",
12641
+ "versionCommand",
12642
+ "testedVersions",
12643
+ "processNames",
12644
+ "launch",
12645
+ "paths",
12646
+ "extensionId",
12647
+ "extensionIdPattern",
12648
+ "extensionIdPattern_flags",
12649
+ "compatibility",
12650
+ "defaultScriptDir",
12651
+ "binary",
12652
+ "spawn",
12653
+ "approvalKeys",
12654
+ "patterns",
12655
+ "cleanOutput",
12656
+ "resume",
12657
+ "sessionProbe",
12658
+ "approvalPositiveHints",
12659
+ "scripts",
12660
+ "vscodeCommands",
12661
+ "inputMethod",
12662
+ "inputSelector",
12663
+ "webviewMatchText",
12664
+ "os",
12665
+ "versions",
12666
+ "overrides",
12667
+ "settings",
12668
+ "controls",
12669
+ "staticConfigOptions",
12670
+ "spawnArgBuilder",
12671
+ "auth",
12672
+ "contractVersion",
12673
+ "capabilities",
12674
+ "providerVersion",
12675
+ "status",
12676
+ "details",
12677
+ "sendDelayMs",
12678
+ "sendKey",
12679
+ "submitStrategy",
12680
+ "disableUpstream"
12681
+ ]);
12682
+ var VALUE_CONTROL_TYPES = /* @__PURE__ */ new Set(["select", "toggle", "cycle", "slider"]);
12683
+ function validateProviderDefinition(raw) {
12684
+ const errors = [];
12685
+ const warnings = [];
12686
+ if (!raw || typeof raw !== "object") {
12687
+ return { errors: ["Provider definition must be an object"], warnings };
12688
+ }
12689
+ const provider = raw;
12690
+ if (!provider.type) errors.push("Missing required field: type");
12691
+ if (!provider.name) errors.push("Missing required field: name");
12692
+ if (!provider.category) {
12693
+ errors.push("Missing required field: category");
12694
+ } else if (!["ide", "extension", "cli", "acp"].includes(String(provider.category))) {
12695
+ errors.push(`Invalid category: ${String(provider.category)}`);
12696
+ }
12697
+ for (const key of Object.keys(provider)) {
12698
+ if (!KNOWN_PROVIDER_FIELDS.has(key)) {
12699
+ warnings.push(`Unknown provider field: ${key}`);
12700
+ }
12701
+ }
12702
+ const category = provider.category;
12703
+ if (category === "cli" || category === "acp") {
12704
+ const spawn4 = provider.spawn;
12705
+ const command = spawn4 && typeof spawn4 === "object" ? spawn4.command : void 0;
12706
+ if (!spawn4 || typeof spawn4 !== "object") {
12707
+ errors.push(`${String(category).toUpperCase()}/CLI providers must have spawn config`);
12708
+ } else if (typeof command !== "string" || !command.trim()) {
12709
+ errors.push("spawn.command is required");
12710
+ }
12711
+ }
12712
+ if ((category === "ide" || category === "extension") && provider.cdpPorts !== void 0) {
12713
+ if (!Array.isArray(provider.cdpPorts) || provider.cdpPorts.length === 0) {
12714
+ warnings.push("IDE/Extension providers should have cdpPorts");
12715
+ }
12716
+ }
12717
+ if (category === "extension" && !provider.extensionId) {
12718
+ warnings.push("Extension providers should have extensionId");
12719
+ }
12720
+ for (const control of Array.isArray(provider.controls) ? provider.controls : []) {
12721
+ validateControl(control, errors);
12722
+ }
12723
+ return { errors, warnings };
12724
+ }
12725
+ function validateControl(control, errors) {
12726
+ if (!control || typeof control !== "object") {
12727
+ errors.push("controls: each control must be an object");
12728
+ return;
12729
+ }
12730
+ const id = typeof control.id === "string" && control.id.trim() ? control.id.trim() : "unknown";
12731
+ const prefix = `controls.${id}`;
12732
+ if (!control.id || !String(control.id).trim()) errors.push(`${prefix}: id is required`);
12733
+ if (!control.type) errors.push(`${prefix}: type is required`);
12734
+ if (!control.label || !String(control.label).trim()) errors.push(`${prefix}: label is required`);
12735
+ if (!control.placement) errors.push(`${prefix}: placement is required`);
12736
+ if (control.dynamic && !control.listScript) {
12737
+ errors.push(`${prefix}: dynamic controls require listScript`);
12738
+ }
12739
+ if (VALUE_CONTROL_TYPES.has(control.type) && !control.setScript) {
12740
+ errors.push(`${prefix}: ${control.type} controls require setScript`);
12741
+ }
12742
+ if (control.type === "action" && !control.invokeScript) {
12743
+ errors.push(`${prefix}: action controls require invokeScript`);
12744
+ }
12745
+ if (control.type === "slider") {
12746
+ if (typeof control.min !== "number" || typeof control.max !== "number") {
12747
+ errors.push(`${prefix}: slider controls require numeric min and max`);
12748
+ } else if (control.min > control.max) {
12749
+ errors.push(`${prefix}: slider min cannot exceed max`);
12750
+ }
12751
+ }
12752
+ if (control.readFrom !== void 0 && (typeof control.readFrom !== "string" || !control.readFrom.trim())) {
12753
+ errors.push(`${prefix}: readFrom must be a non-empty string when provided`);
12754
+ }
12755
+ }
12756
+
12757
+ // src/providers/provider-loader.ts
12233
12758
  var ProviderLoader = class _ProviderLoader {
12234
12759
  providers = /* @__PURE__ */ new Map();
12235
12760
  providerAvailability = /* @__PURE__ */ new Map();
@@ -12248,12 +12773,12 @@ var ProviderLoader = class _ProviderLoader {
12248
12773
  static META_FILE = ".meta.json";
12249
12774
  constructor(options) {
12250
12775
  this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
12251
- const defaultProvidersDir = path13.join(os13.homedir(), ".adhdev", "providers");
12776
+ const defaultProvidersDir = path14.join(os13.homedir(), ".adhdev", "providers");
12252
12777
  if (options?.userDir) {
12253
12778
  this.userDir = options.userDir;
12254
12779
  this.log(`Config 'providerDir' applied: ${this.userDir}`);
12255
12780
  } else {
12256
- const localRepoPath = path13.resolve(__dirname, "../../../../../adhdev-providers");
12781
+ const localRepoPath = path14.resolve(__dirname, "../../../../../adhdev-providers");
12257
12782
  if (fs6.existsSync(localRepoPath)) {
12258
12783
  this.userDir = localRepoPath;
12259
12784
  this.log(`Auto-detected local public repository: ${this.userDir} (Dev workspace speedup)`);
@@ -12262,7 +12787,7 @@ var ProviderLoader = class _ProviderLoader {
12262
12787
  this.log(`Using default user providers directory: ${this.userDir}`);
12263
12788
  }
12264
12789
  }
12265
- this.upstreamDir = path13.join(defaultProvidersDir, ".upstream");
12790
+ this.upstreamDir = path14.join(defaultProvidersDir, ".upstream");
12266
12791
  this.disableUpstream = options?.disableUpstream ?? false;
12267
12792
  }
12268
12793
  log(msg) {
@@ -12292,7 +12817,7 @@ var ProviderLoader = class _ProviderLoader {
12292
12817
  * Canonical provider directory shape for a given root.
12293
12818
  */
12294
12819
  getProviderDir(root, category, type) {
12295
- return path13.join(root, category, type);
12820
+ return path14.join(root, category, type);
12296
12821
  }
12297
12822
  /**
12298
12823
  * Canonical user override directory for a provider.
@@ -12319,7 +12844,7 @@ var ProviderLoader = class _ProviderLoader {
12319
12844
  resolveProviderFile(type, ...segments) {
12320
12845
  const dir = this.findProviderDirInternal(type);
12321
12846
  if (!dir) return null;
12322
- return path13.join(dir, ...segments);
12847
+ return path14.join(dir, ...segments);
12323
12848
  }
12324
12849
  /**
12325
12850
  * Load all providers (3-tier priority)
@@ -12358,7 +12883,7 @@ var ProviderLoader = class _ProviderLoader {
12358
12883
  if (!fs6.existsSync(this.upstreamDir)) return false;
12359
12884
  try {
12360
12885
  return fs6.readdirSync(this.upstreamDir).some(
12361
- (d) => fs6.statSync(path13.join(this.upstreamDir, d)).isDirectory()
12886
+ (d) => fs6.statSync(path14.join(this.upstreamDir, d)).isDirectory()
12362
12887
  );
12363
12888
  } catch {
12364
12889
  return false;
@@ -12673,8 +13198,8 @@ var ProviderLoader = class _ProviderLoader {
12673
13198
  resolved._resolvedScriptDir = entry.scriptDir;
12674
13199
  resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
12675
13200
  if (providerDir) {
12676
- const fullDir = path13.join(providerDir, entry.scriptDir);
12677
- resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
13201
+ const fullDir = path14.join(providerDir, entry.scriptDir);
13202
+ resolved._resolvedScriptsPath = fs6.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
12678
13203
  }
12679
13204
  matched = true;
12680
13205
  }
@@ -12689,8 +13214,8 @@ var ProviderLoader = class _ProviderLoader {
12689
13214
  resolved._resolvedScriptDir = base.defaultScriptDir;
12690
13215
  resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
12691
13216
  if (providerDir) {
12692
- const fullDir = path13.join(providerDir, base.defaultScriptDir);
12693
- resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
13217
+ const fullDir = path14.join(providerDir, base.defaultScriptDir);
13218
+ resolved._resolvedScriptsPath = fs6.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
12694
13219
  }
12695
13220
  }
12696
13221
  resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
@@ -12707,8 +13232,8 @@ var ProviderLoader = class _ProviderLoader {
12707
13232
  resolved._resolvedScriptDir = dirOverride;
12708
13233
  resolved._resolvedScriptsSource = `versions:${range}`;
12709
13234
  if (providerDir) {
12710
- const fullDir = path13.join(providerDir, dirOverride);
12711
- resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
13235
+ const fullDir = path14.join(providerDir, dirOverride);
13236
+ resolved._resolvedScriptsPath = fs6.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
12712
13237
  }
12713
13238
  }
12714
13239
  } else if (override.scripts) {
@@ -12724,8 +13249,8 @@ var ProviderLoader = class _ProviderLoader {
12724
13249
  resolved._resolvedScriptDir = base.defaultScriptDir;
12725
13250
  resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
12726
13251
  if (providerDir) {
12727
- const fullDir = path13.join(providerDir, base.defaultScriptDir);
12728
- resolved._resolvedScriptsPath = fs6.existsSync(path13.join(fullDir, "scripts.js")) ? path13.join(fullDir, "scripts.js") : fullDir;
13252
+ const fullDir = path14.join(providerDir, base.defaultScriptDir);
13253
+ resolved._resolvedScriptsPath = fs6.existsSync(path14.join(fullDir, "scripts.js")) ? path14.join(fullDir, "scripts.js") : fullDir;
12729
13254
  }
12730
13255
  }
12731
13256
  }
@@ -12750,14 +13275,14 @@ var ProviderLoader = class _ProviderLoader {
12750
13275
  this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
12751
13276
  return null;
12752
13277
  }
12753
- const dir = path13.join(providerDir, scriptDir);
13278
+ const dir = path14.join(providerDir, scriptDir);
12754
13279
  if (!fs6.existsSync(dir)) {
12755
13280
  this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
12756
13281
  return null;
12757
13282
  }
12758
13283
  const cached = this.scriptsCache.get(dir);
12759
13284
  if (cached) return cached;
12760
- const scriptsJs = path13.join(dir, "scripts.js");
13285
+ const scriptsJs = path14.join(dir, "scripts.js");
12761
13286
  if (fs6.existsSync(scriptsJs)) {
12762
13287
  try {
12763
13288
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -12799,7 +13324,7 @@ var ProviderLoader = class _ProviderLoader {
12799
13324
  return;
12800
13325
  }
12801
13326
  if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
12802
- this.log(`File changed: ${path13.basename(filePath)}, reloading...`);
13327
+ this.log(`File changed: ${path14.basename(filePath)}, reloading...`);
12803
13328
  this.reload();
12804
13329
  }
12805
13330
  };
@@ -12854,7 +13379,7 @@ var ProviderLoader = class _ProviderLoader {
12854
13379
  }
12855
13380
  const https = __require("https");
12856
13381
  const { execSync: execSync7 } = __require("child_process");
12857
- const metaPath = path13.join(this.upstreamDir, _ProviderLoader.META_FILE);
13382
+ const metaPath = path14.join(this.upstreamDir, _ProviderLoader.META_FILE);
12858
13383
  let prevEtag = "";
12859
13384
  let prevTimestamp = 0;
12860
13385
  try {
@@ -12914,17 +13439,17 @@ var ProviderLoader = class _ProviderLoader {
12914
13439
  return { updated: false };
12915
13440
  }
12916
13441
  this.log("Downloading latest providers from GitHub...");
12917
- const tmpTar = path13.join(os13.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
12918
- const tmpExtract = path13.join(os13.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
13442
+ const tmpTar = path14.join(os13.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
13443
+ const tmpExtract = path14.join(os13.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
12919
13444
  await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
12920
13445
  fs6.mkdirSync(tmpExtract, { recursive: true });
12921
13446
  execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
12922
13447
  const extracted = fs6.readdirSync(tmpExtract);
12923
13448
  const rootDir = extracted.find(
12924
- (d) => fs6.statSync(path13.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
13449
+ (d) => fs6.statSync(path14.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
12925
13450
  );
12926
13451
  if (!rootDir) throw new Error("Unexpected tarball structure");
12927
- const sourceDir = path13.join(tmpExtract, rootDir);
13452
+ const sourceDir = path14.join(tmpExtract, rootDir);
12928
13453
  const backupDir = this.upstreamDir + ".bak";
12929
13454
  if (fs6.existsSync(this.upstreamDir)) {
12930
13455
  if (fs6.existsSync(backupDir)) fs6.rmSync(backupDir, { recursive: true, force: true });
@@ -12999,8 +13524,8 @@ var ProviderLoader = class _ProviderLoader {
12999
13524
  copyDirRecursive(src, dest) {
13000
13525
  fs6.mkdirSync(dest, { recursive: true });
13001
13526
  for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
13002
- const srcPath = path13.join(src, entry.name);
13003
- const destPath = path13.join(dest, entry.name);
13527
+ const srcPath = path14.join(src, entry.name);
13528
+ const destPath = path14.join(dest, entry.name);
13004
13529
  if (entry.isDirectory()) {
13005
13530
  this.copyDirRecursive(srcPath, destPath);
13006
13531
  } else {
@@ -13011,7 +13536,7 @@ var ProviderLoader = class _ProviderLoader {
13011
13536
  /** .meta.json save */
13012
13537
  writeMeta(metaPath, etag, timestamp) {
13013
13538
  try {
13014
- fs6.mkdirSync(path13.dirname(metaPath), { recursive: true });
13539
+ fs6.mkdirSync(path14.dirname(metaPath), { recursive: true });
13015
13540
  fs6.writeFileSync(metaPath, JSON.stringify({
13016
13541
  etag,
13017
13542
  timestamp,
@@ -13028,7 +13553,7 @@ var ProviderLoader = class _ProviderLoader {
13028
13553
  const scan = (d) => {
13029
13554
  try {
13030
13555
  for (const entry of fs6.readdirSync(d, { withFileTypes: true })) {
13031
- if (entry.isDirectory()) scan(path13.join(d, entry.name));
13556
+ if (entry.isDirectory()) scan(path14.join(d, entry.name));
13032
13557
  else if (entry.name === "provider.json") count++;
13033
13558
  }
13034
13559
  } catch {
@@ -13213,17 +13738,17 @@ var ProviderLoader = class _ProviderLoader {
13213
13738
  for (const root of searchRoots) {
13214
13739
  if (!fs6.existsSync(root)) continue;
13215
13740
  const candidate = this.getProviderDir(root, cat, type);
13216
- if (fs6.existsSync(path13.join(candidate, "provider.json"))) return candidate;
13217
- const catDir = path13.join(root, cat);
13741
+ if (fs6.existsSync(path14.join(candidate, "provider.json"))) return candidate;
13742
+ const catDir = path14.join(root, cat);
13218
13743
  if (fs6.existsSync(catDir)) {
13219
13744
  try {
13220
13745
  for (const entry of fs6.readdirSync(catDir, { withFileTypes: true })) {
13221
13746
  if (!entry.isDirectory()) continue;
13222
- const jsonPath = path13.join(catDir, entry.name, "provider.json");
13747
+ const jsonPath = path14.join(catDir, entry.name, "provider.json");
13223
13748
  if (fs6.existsSync(jsonPath)) {
13224
13749
  try {
13225
13750
  const data = JSON.parse(fs6.readFileSync(jsonPath, "utf-8"));
13226
- if (data.type === type) return path13.join(catDir, entry.name);
13751
+ if (data.type === type) return path14.join(catDir, entry.name);
13227
13752
  } catch {
13228
13753
  }
13229
13754
  }
@@ -13240,7 +13765,7 @@ var ProviderLoader = class _ProviderLoader {
13240
13765
  * (template substitution is NOT applied here — scripts.js handles that)
13241
13766
  */
13242
13767
  buildScriptWrappersFromDir(dir) {
13243
- const scriptsJs = path13.join(dir, "scripts.js");
13768
+ const scriptsJs = path14.join(dir, "scripts.js");
13244
13769
  if (fs6.existsSync(scriptsJs)) {
13245
13770
  try {
13246
13771
  delete __require.cache[__require.resolve(scriptsJs)];
@@ -13254,7 +13779,7 @@ var ProviderLoader = class _ProviderLoader {
13254
13779
  for (const file of fs6.readdirSync(dir)) {
13255
13780
  if (!file.endsWith(".js")) continue;
13256
13781
  const scriptName = toCamel(file.replace(".js", ""));
13257
- const filePath = path13.join(dir, file);
13782
+ const filePath = path14.join(dir, file);
13258
13783
  result[scriptName] = (...args) => {
13259
13784
  try {
13260
13785
  let content = fs6.readFileSync(filePath, "utf-8");
@@ -13314,24 +13839,28 @@ var ProviderLoader = class _ProviderLoader {
13314
13839
  }
13315
13840
  const hasJson = entries.some((e) => e.name === "provider.json");
13316
13841
  if (hasJson) {
13317
- const jsonPath = path13.join(d, "provider.json");
13842
+ const jsonPath = path14.join(d, "provider.json");
13318
13843
  try {
13319
13844
  const raw = fs6.readFileSync(jsonPath, "utf-8");
13320
13845
  const mod = JSON.parse(raw);
13321
- if (!mod.type || !mod.name || !mod.category) {
13322
- this.log(`\u26A0 Invalid provider at ${jsonPath}: missing type/name/category`);
13846
+ if (typeof mod.extensionIdPattern === "string") {
13847
+ const flags = mod.extensionIdPattern_flags || "";
13848
+ mod.extensionIdPattern = new RegExp(mod.extensionIdPattern, flags);
13849
+ }
13850
+ const { extensionIdPattern_flags, extensionIdPattern, ...providerFields } = mod;
13851
+ const normalizedProvider = {
13852
+ ...providerFields,
13853
+ ...extensionIdPattern instanceof RegExp ? { extensionIdPattern } : {}
13854
+ };
13855
+ const validation = validateProviderDefinition(normalizedProvider);
13856
+ for (const warning of validation.warnings) {
13857
+ this.log(`\u26A0 ${jsonPath}: ${warning}`);
13858
+ }
13859
+ if (validation.errors.length > 0) {
13860
+ this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
13323
13861
  } else {
13324
- if (typeof mod.extensionIdPattern === "string") {
13325
- const flags = mod.extensionIdPattern_flags || "";
13326
- mod.extensionIdPattern = new RegExp(mod.extensionIdPattern, flags);
13327
- }
13328
- const { extensionIdPattern_flags, extensionIdPattern, ...providerFields } = mod;
13329
- const normalizedProvider = {
13330
- ...providerFields,
13331
- ...extensionIdPattern instanceof RegExp ? { extensionIdPattern } : {}
13332
- };
13333
13862
  const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
13334
- const scriptsPath = path13.join(d, "scripts.js");
13863
+ const scriptsPath = path14.join(d, "scripts.js");
13335
13864
  if (!hasCompatibility && fs6.existsSync(scriptsPath)) {
13336
13865
  try {
13337
13866
  delete __require.cache[__require.resolve(scriptsPath)];
@@ -13357,7 +13886,7 @@ var ProviderLoader = class _ProviderLoader {
13357
13886
  if (!entry.isDirectory()) continue;
13358
13887
  if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
13359
13888
  if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
13360
- scan(path13.join(d, entry.name));
13889
+ scan(path14.join(d, entry.name));
13361
13890
  }
13362
13891
  }
13363
13892
  };
@@ -13615,8 +14144,8 @@ function detectCurrentWorkspace(ideId) {
13615
14144
  const appNameMap = getMacAppIdentifiers();
13616
14145
  const appName = appNameMap[ideId];
13617
14146
  if (appName) {
13618
- const storagePath = path14.join(
13619
- process.env.APPDATA || path14.join(os14.homedir(), "AppData", "Roaming"),
14147
+ const storagePath = path15.join(
14148
+ process.env.APPDATA || path15.join(os14.homedir(), "AppData", "Roaming"),
13620
14149
  appName,
13621
14150
  "storage.json"
13622
14151
  );
@@ -13794,9 +14323,9 @@ init_logger();
13794
14323
 
13795
14324
  // src/logging/command-log.ts
13796
14325
  import * as fs7 from "fs";
13797
- import * as path15 from "path";
14326
+ import * as path16 from "path";
13798
14327
  import * as os15 from "os";
13799
- var LOG_DIR2 = process.platform === "win32" ? path15.join(process.env.LOCALAPPDATA || process.env.APPDATA || path15.join(os15.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path15.join(os15.homedir(), "Library", "Logs", "adhdev") : path15.join(os15.homedir(), ".local", "share", "adhdev", "logs");
14328
+ var LOG_DIR2 = process.platform === "win32" ? path16.join(process.env.LOCALAPPDATA || process.env.APPDATA || path16.join(os15.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path16.join(os15.homedir(), "Library", "Logs", "adhdev") : path16.join(os15.homedir(), ".local", "share", "adhdev", "logs");
13800
14329
  var MAX_FILE_SIZE = 5 * 1024 * 1024;
13801
14330
  var MAX_DAYS = 7;
13802
14331
  try {
@@ -13834,13 +14363,13 @@ function getDateStr2() {
13834
14363
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
13835
14364
  }
13836
14365
  var currentDate2 = getDateStr2();
13837
- var currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
14366
+ var currentFile = path16.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13838
14367
  var writeCount2 = 0;
13839
14368
  function checkRotation() {
13840
14369
  const today = getDateStr2();
13841
14370
  if (today !== currentDate2) {
13842
14371
  currentDate2 = today;
13843
- currentFile = path15.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
14372
+ currentFile = path16.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
13844
14373
  cleanOldFiles();
13845
14374
  }
13846
14375
  }
@@ -13854,7 +14383,7 @@ function cleanOldFiles() {
13854
14383
  const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
13855
14384
  if (dateMatch && dateMatch[1] < cutoffStr) {
13856
14385
  try {
13857
- fs7.unlinkSync(path15.join(LOG_DIR2, file));
14386
+ fs7.unlinkSync(path16.join(LOG_DIR2, file));
13858
14387
  } catch {
13859
14388
  }
13860
14389
  }
@@ -14171,13 +14700,13 @@ import { execFileSync } from "child_process";
14171
14700
  import { spawn as spawn3 } from "child_process";
14172
14701
  import * as fs8 from "fs";
14173
14702
  import * as os17 from "os";
14174
- import * as path16 from "path";
14703
+ import * as path17 from "path";
14175
14704
  var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
14176
14705
  function getUpgradeLogPath() {
14177
14706
  const home = os17.homedir();
14178
- const dir = path16.join(home, ".adhdev");
14707
+ const dir = path17.join(home, ".adhdev");
14179
14708
  fs8.mkdirSync(dir, { recursive: true });
14180
- return path16.join(dir, "daemon-upgrade.log");
14709
+ return path17.join(dir, "daemon-upgrade.log");
14181
14710
  }
14182
14711
  function appendUpgradeLog(message) {
14183
14712
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
@@ -14217,7 +14746,7 @@ async function waitForPidExit(pid, timeoutMs) {
14217
14746
  }
14218
14747
  }
14219
14748
  function stopSessionHostProcesses(appName) {
14220
- const pidFile = path16.join(os17.homedir(), ".adhdev", `${appName}-session-host.pid`);
14749
+ const pidFile = path17.join(os17.homedir(), ".adhdev", `${appName}-session-host.pid`);
14221
14750
  try {
14222
14751
  if (fs8.existsSync(pidFile)) {
14223
14752
  const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
@@ -14246,7 +14775,7 @@ function stopSessionHostProcesses(appName) {
14246
14775
  }
14247
14776
  }
14248
14777
  function removeDaemonPidFile() {
14249
- const pidFile = path16.join(os17.homedir(), ".adhdev", "daemon.pid");
14778
+ const pidFile = path17.join(os17.homedir(), ".adhdev", "daemon.pid");
14250
14779
  try {
14251
14780
  fs8.unlinkSync(pidFile);
14252
14781
  } catch {
@@ -14257,7 +14786,7 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
14257
14786
  const npmRoot = execFileSync(getNpmExecutable(), ["root", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
14258
14787
  if (!npmRoot) return;
14259
14788
  const npmPrefix = execFileSync(getNpmExecutable(), ["prefix", "-g"], { encoding: "utf8", ...npmExecOpts }).trim();
14260
- const binDir = process.platform === "win32" ? npmPrefix : path16.join(npmPrefix, "bin");
14789
+ const binDir = process.platform === "win32" ? npmPrefix : path17.join(npmPrefix, "bin");
14261
14790
  const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
14262
14791
  const binNames = /* @__PURE__ */ new Set([packageBaseName]);
14263
14792
  if (pkgName === "@adhdev/daemon-standalone") {
@@ -14265,25 +14794,25 @@ function cleanupStaleGlobalInstallDirs(pkgName) {
14265
14794
  }
14266
14795
  if (pkgName.startsWith("@")) {
14267
14796
  const [scope, name] = pkgName.split("/");
14268
- const scopeDir = path16.join(npmRoot, scope);
14797
+ const scopeDir = path17.join(npmRoot, scope);
14269
14798
  if (!fs8.existsSync(scopeDir)) return;
14270
14799
  for (const entry of fs8.readdirSync(scopeDir)) {
14271
14800
  if (!entry.startsWith(`.${name}-`)) continue;
14272
- fs8.rmSync(path16.join(scopeDir, entry), { recursive: true, force: true });
14273
- appendUpgradeLog(`Removed stale scoped staging dir: ${path16.join(scopeDir, entry)}`);
14801
+ fs8.rmSync(path17.join(scopeDir, entry), { recursive: true, force: true });
14802
+ appendUpgradeLog(`Removed stale scoped staging dir: ${path17.join(scopeDir, entry)}`);
14274
14803
  }
14275
14804
  } else {
14276
14805
  for (const entry of fs8.readdirSync(npmRoot)) {
14277
14806
  if (!entry.startsWith(`.${pkgName}-`)) continue;
14278
- fs8.rmSync(path16.join(npmRoot, entry), { recursive: true, force: true });
14279
- appendUpgradeLog(`Removed stale staging dir: ${path16.join(npmRoot, entry)}`);
14807
+ fs8.rmSync(path17.join(npmRoot, entry), { recursive: true, force: true });
14808
+ appendUpgradeLog(`Removed stale staging dir: ${path17.join(npmRoot, entry)}`);
14280
14809
  }
14281
14810
  }
14282
14811
  if (fs8.existsSync(binDir)) {
14283
14812
  for (const entry of fs8.readdirSync(binDir)) {
14284
14813
  if (![...binNames].some((name) => entry.startsWith(`.${name}-`))) continue;
14285
- fs8.rmSync(path16.join(binDir, entry), { recursive: true, force: true });
14286
- appendUpgradeLog(`Removed stale bin staging entry: ${path16.join(binDir, entry)}`);
14814
+ fs8.rmSync(path17.join(binDir, entry), { recursive: true, force: true });
14815
+ appendUpgradeLog(`Removed stale bin staging entry: ${path17.join(binDir, entry)}`);
14287
14816
  }
14288
14817
  }
14289
14818
  }
@@ -16161,11 +16690,11 @@ var ProviderInstanceManager = class {
16161
16690
 
16162
16691
  // src/providers/version-archive.ts
16163
16692
  import * as fs10 from "fs";
16164
- import * as path17 from "path";
16693
+ import * as path18 from "path";
16165
16694
  import * as os18 from "os";
16166
16695
  import { execSync as execSync5 } from "child_process";
16167
16696
  import { platform as platform8 } from "os";
16168
- var ARCHIVE_PATH = path17.join(os18.homedir(), ".adhdev", "version-history.json");
16697
+ var ARCHIVE_PATH = path18.join(os18.homedir(), ".adhdev", "version-history.json");
16169
16698
  var MAX_ENTRIES_PER_PROVIDER = 20;
16170
16699
  var VersionArchive = class {
16171
16700
  history = {};
@@ -16212,7 +16741,7 @@ var VersionArchive = class {
16212
16741
  }
16213
16742
  save() {
16214
16743
  try {
16215
- fs10.mkdirSync(path17.dirname(ARCHIVE_PATH), { recursive: true });
16744
+ fs10.mkdirSync(path18.dirname(ARCHIVE_PATH), { recursive: true });
16216
16745
  fs10.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
16217
16746
  } catch {
16218
16747
  }
@@ -16269,7 +16798,7 @@ function checkPathExists2(paths) {
16269
16798
  for (const p of paths) {
16270
16799
  if (p.includes("*")) {
16271
16800
  const home = os18.homedir();
16272
- const resolved = p.replace(/\*/g, home.split(path17.sep).pop() || "");
16801
+ const resolved = p.replace(/\*/g, home.split(path18.sep).pop() || "");
16273
16802
  if (fs10.existsSync(resolved)) return resolved;
16274
16803
  } else {
16275
16804
  if (fs10.existsSync(p)) return p;
@@ -16279,7 +16808,7 @@ function checkPathExists2(paths) {
16279
16808
  }
16280
16809
  function getMacAppVersion(appPath) {
16281
16810
  if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
16282
- const plistPath = path17.join(appPath, "Contents", "Info.plist");
16811
+ const plistPath = path18.join(appPath, "Contents", "Info.plist");
16283
16812
  if (!fs10.existsSync(plistPath)) return null;
16284
16813
  const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
16285
16814
  return raw || null;
@@ -16305,7 +16834,7 @@ async function detectAllVersions(loader, archive) {
16305
16834
  const cliBin = provider.cli ? findBinary2(provider.cli) : null;
16306
16835
  let resolvedBin = cliBin;
16307
16836
  if (!resolvedBin && appPath && currentOs === "darwin") {
16308
- const bundled = path17.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
16837
+ const bundled = path18.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
16309
16838
  if (provider.cli && fs10.existsSync(bundled)) resolvedBin = bundled;
16310
16839
  }
16311
16840
  info.installed = !!(appPath || resolvedBin);
@@ -16346,7 +16875,7 @@ async function detectAllVersions(loader, archive) {
16346
16875
  // src/daemon/dev-server.ts
16347
16876
  import * as http2 from "http";
16348
16877
  import * as fs14 from "fs";
16349
- import * as path21 from "path";
16878
+ import * as path22 from "path";
16350
16879
 
16351
16880
  // src/daemon/scaffold-template.ts
16352
16881
  function generateFiles(type, name, category, opts = {}) {
@@ -16683,7 +17212,7 @@ init_logger();
16683
17212
  // src/daemon/dev-cdp-handlers.ts
16684
17213
  init_logger();
16685
17214
  import * as fs11 from "fs";
16686
- import * as path18 from "path";
17215
+ import * as path19 from "path";
16687
17216
  async function handleCdpEvaluate(ctx, req, res) {
16688
17217
  const body = await ctx.readBody(req);
16689
17218
  const { expression, timeout, ideType } = body;
@@ -16861,17 +17390,17 @@ async function handleScriptHints(ctx, type, _req, res) {
16861
17390
  return;
16862
17391
  }
16863
17392
  let scriptsPath = "";
16864
- const directScripts = path18.join(dir, "scripts.js");
17393
+ const directScripts = path19.join(dir, "scripts.js");
16865
17394
  if (fs11.existsSync(directScripts)) {
16866
17395
  scriptsPath = directScripts;
16867
17396
  } else {
16868
- const scriptsDir = path18.join(dir, "scripts");
17397
+ const scriptsDir = path19.join(dir, "scripts");
16869
17398
  if (fs11.existsSync(scriptsDir)) {
16870
17399
  const versions = fs11.readdirSync(scriptsDir).filter((d) => {
16871
- return fs11.statSync(path18.join(scriptsDir, d)).isDirectory();
17400
+ return fs11.statSync(path19.join(scriptsDir, d)).isDirectory();
16872
17401
  }).sort().reverse();
16873
17402
  for (const ver of versions) {
16874
- const p = path18.join(scriptsDir, ver, "scripts.js");
17403
+ const p = path19.join(scriptsDir, ver, "scripts.js");
16875
17404
  if (fs11.existsSync(p)) {
16876
17405
  scriptsPath = p;
16877
17406
  break;
@@ -17700,7 +18229,7 @@ async function handleDomContext(ctx, type, req, res) {
17700
18229
 
17701
18230
  // src/daemon/dev-cli-debug.ts
17702
18231
  import * as fs12 from "fs";
17703
- import * as path19 from "path";
18232
+ import * as path20 from "path";
17704
18233
  function slugifyFixtureName(value) {
17705
18234
  const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
17706
18235
  return normalized || `fixture-${Date.now()}`;
@@ -17710,11 +18239,11 @@ function getCliFixtureDir(ctx, type) {
17710
18239
  if (!providerDir) {
17711
18240
  throw new Error(`Provider directory not found for '${type}'`);
17712
18241
  }
17713
- return path19.join(providerDir, "fixtures");
18242
+ return path20.join(providerDir, "fixtures");
17714
18243
  }
17715
18244
  function readCliFixture(ctx, type, name) {
17716
18245
  const fixtureDir = getCliFixtureDir(ctx, type);
17717
- const filePath = path19.join(fixtureDir, `${name}.json`);
18246
+ const filePath = path20.join(fixtureDir, `${name}.json`);
17718
18247
  if (!fs12.existsSync(filePath)) {
17719
18248
  throw new Error(`Fixture not found: ${filePath}`);
17720
18249
  }
@@ -18482,7 +19011,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
18482
19011
  },
18483
19012
  notes: typeof body?.notes === "string" ? body.notes : void 0
18484
19013
  };
18485
- const filePath = path19.join(fixtureDir, `${name}.json`);
19014
+ const filePath = path20.join(fixtureDir, `${name}.json`);
18486
19015
  fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
18487
19016
  ctx.json(res, 200, {
18488
19017
  saved: true,
@@ -18506,7 +19035,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
18506
19035
  return;
18507
19036
  }
18508
19037
  const fixtures = fs12.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
18509
- const fullPath = path19.join(fixtureDir, file);
19038
+ const fullPath = path20.join(fixtureDir, file);
18510
19039
  try {
18511
19040
  const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
18512
19041
  return {
@@ -18642,7 +19171,7 @@ async function handleCliRaw(ctx, req, res) {
18642
19171
 
18643
19172
  // src/daemon/dev-auto-implement.ts
18644
19173
  import * as fs13 from "fs";
18645
- import * as path20 from "path";
19174
+ import * as path21 from "path";
18646
19175
  import * as os19 from "os";
18647
19176
  function getAutoImplPid(ctx) {
18648
19177
  const pid = ctx.autoImplProcess?.pid;
@@ -18699,22 +19228,22 @@ function getLatestScriptVersionDir(scriptsDir) {
18699
19228
  if (!fs13.existsSync(scriptsDir)) return null;
18700
19229
  const versions = fs13.readdirSync(scriptsDir).filter((d) => {
18701
19230
  try {
18702
- return fs13.statSync(path20.join(scriptsDir, d)).isDirectory();
19231
+ return fs13.statSync(path21.join(scriptsDir, d)).isDirectory();
18703
19232
  } catch {
18704
19233
  return false;
18705
19234
  }
18706
19235
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
18707
19236
  if (versions.length === 0) return null;
18708
- return path20.join(scriptsDir, versions[0]);
19237
+ return path21.join(scriptsDir, versions[0]);
18709
19238
  }
18710
19239
  function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
18711
- const canonicalUserDir = path20.resolve(ctx.providerLoader.getUserProviderDir(category, type));
18712
- const desiredDir = requestedDir ? path20.resolve(requestedDir) : canonicalUserDir;
18713
- const upstreamRoot = path20.resolve(ctx.providerLoader.getUpstreamDir());
18714
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path20.sep}`)) {
19240
+ const canonicalUserDir = path21.resolve(ctx.providerLoader.getUserProviderDir(category, type));
19241
+ const desiredDir = requestedDir ? path21.resolve(requestedDir) : canonicalUserDir;
19242
+ const upstreamRoot = path21.resolve(ctx.providerLoader.getUpstreamDir());
19243
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path21.sep}`)) {
18715
19244
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
18716
19245
  }
18717
- if (path20.basename(desiredDir) !== type) {
19246
+ if (path21.basename(desiredDir) !== type) {
18718
19247
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
18719
19248
  }
18720
19249
  const sourceDir = ctx.findProviderDir(type);
@@ -18722,11 +19251,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
18722
19251
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
18723
19252
  }
18724
19253
  if (!fs13.existsSync(desiredDir)) {
18725
- fs13.mkdirSync(path20.dirname(desiredDir), { recursive: true });
19254
+ fs13.mkdirSync(path21.dirname(desiredDir), { recursive: true });
18726
19255
  fs13.cpSync(sourceDir, desiredDir, { recursive: true });
18727
19256
  ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
18728
19257
  }
18729
- const providerJson = path20.join(desiredDir, "provider.json");
19258
+ const providerJson = path21.join(desiredDir, "provider.json");
18730
19259
  if (!fs13.existsSync(providerJson)) {
18731
19260
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
18732
19261
  }
@@ -18749,13 +19278,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
18749
19278
  const refDir = ctx.findProviderDir(referenceType);
18750
19279
  if (!refDir || !fs13.existsSync(refDir)) return {};
18751
19280
  const referenceScripts = {};
18752
- const scriptsDir = path20.join(refDir, "scripts");
19281
+ const scriptsDir = path21.join(refDir, "scripts");
18753
19282
  const latestDir = getLatestScriptVersionDir(scriptsDir);
18754
19283
  if (!latestDir) return referenceScripts;
18755
19284
  for (const file of fs13.readdirSync(latestDir)) {
18756
19285
  if (!file.endsWith(".js")) continue;
18757
19286
  try {
18758
- referenceScripts[file] = fs13.readFileSync(path20.join(latestDir, file), "utf-8");
19287
+ referenceScripts[file] = fs13.readFileSync(path21.join(latestDir, file), "utf-8");
18759
19288
  } catch {
18760
19289
  }
18761
19290
  }
@@ -18863,9 +19392,9 @@ async function handleAutoImplement(ctx, type, req, res) {
18863
19392
  });
18864
19393
  const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
18865
19394
  const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
18866
- const tmpDir = path20.join(os19.tmpdir(), "adhdev-autoimpl");
19395
+ const tmpDir = path21.join(os19.tmpdir(), "adhdev-autoimpl");
18867
19396
  if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
18868
- const promptFile = path20.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
19397
+ const promptFile = path21.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
18869
19398
  fs13.writeFileSync(promptFile, prompt, "utf-8");
18870
19399
  ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
18871
19400
  const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
@@ -19302,7 +19831,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
19302
19831
  setMode: "set_mode.js"
19303
19832
  };
19304
19833
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
19305
- const scriptsDir = path20.join(providerDir, "scripts");
19834
+ const scriptsDir = path21.join(providerDir, "scripts");
19306
19835
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
19307
19836
  if (latestScriptsDir) {
19308
19837
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -19313,7 +19842,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
19313
19842
  for (const file of fs13.readdirSync(latestScriptsDir)) {
19314
19843
  if (file.endsWith(".js") && targetFileNames.has(file)) {
19315
19844
  try {
19316
- const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
19845
+ const content = fs13.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
19317
19846
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
19318
19847
  lines.push("```javascript");
19319
19848
  lines.push(content);
@@ -19330,7 +19859,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
19330
19859
  lines.push("");
19331
19860
  for (const file of refFiles) {
19332
19861
  try {
19333
- const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
19862
+ const content = fs13.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
19334
19863
  lines.push(`### \`${file}\` \u{1F512}`);
19335
19864
  lines.push("```javascript");
19336
19865
  lines.push(content);
@@ -19371,10 +19900,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
19371
19900
  lines.push("");
19372
19901
  }
19373
19902
  }
19374
- const docsDir = path20.join(providerDir, "../../docs");
19903
+ const docsDir = path21.join(providerDir, "../../docs");
19375
19904
  const loadGuide = (name) => {
19376
19905
  try {
19377
- const p = path20.join(docsDir, name);
19906
+ const p = path21.join(docsDir, name);
19378
19907
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
19379
19908
  } catch {
19380
19909
  }
@@ -19611,7 +20140,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
19611
20140
  parseApproval: "parse_approval.js"
19612
20141
  };
19613
20142
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
19614
- const scriptsDir = path20.join(providerDir, "scripts");
20143
+ const scriptsDir = path21.join(providerDir, "scripts");
19615
20144
  const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
19616
20145
  if (latestScriptsDir) {
19617
20146
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -19623,7 +20152,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
19623
20152
  if (!file.endsWith(".js")) continue;
19624
20153
  if (!targetFileNames.has(file)) continue;
19625
20154
  try {
19626
- const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20155
+ const content = fs13.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
19627
20156
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
19628
20157
  lines.push("```javascript");
19629
20158
  lines.push(content);
@@ -19639,7 +20168,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
19639
20168
  lines.push("");
19640
20169
  for (const file of refFiles) {
19641
20170
  try {
19642
- const content = fs13.readFileSync(path20.join(latestScriptsDir, file), "utf-8");
20171
+ const content = fs13.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
19643
20172
  lines.push(`### \`${file}\` \u{1F512}`);
19644
20173
  lines.push("```javascript");
19645
20174
  lines.push(content);
@@ -19672,10 +20201,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
19672
20201
  lines.push("");
19673
20202
  }
19674
20203
  }
19675
- const docsDir = path20.join(providerDir, "../../docs");
20204
+ const docsDir = path21.join(providerDir, "../../docs");
19676
20205
  const loadGuide = (name) => {
19677
20206
  try {
19678
- const p = path20.join(docsDir, name);
20207
+ const p = path21.join(docsDir, name);
19679
20208
  if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
19680
20209
  } catch {
19681
20210
  }
@@ -20118,8 +20647,8 @@ var DevServer = class _DevServer {
20118
20647
  }
20119
20648
  getEndpointList() {
20120
20649
  return this.routes.map((r) => {
20121
- const path22 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
20122
- return `${r.method.padEnd(5)} ${path22}`;
20650
+ const path23 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
20651
+ return `${r.method.padEnd(5)} ${path23}`;
20123
20652
  });
20124
20653
  }
20125
20654
  async start(port = DEV_SERVER_PORT) {
@@ -20374,12 +20903,12 @@ var DevServer = class _DevServer {
20374
20903
  // ─── DevConsole SPA ───
20375
20904
  getConsoleDistDir() {
20376
20905
  const candidates = [
20377
- path21.resolve(__dirname, "../../web-devconsole/dist"),
20378
- path21.resolve(__dirname, "../../../web-devconsole/dist"),
20379
- path21.join(process.cwd(), "packages/web-devconsole/dist")
20906
+ path22.resolve(__dirname, "../../web-devconsole/dist"),
20907
+ path22.resolve(__dirname, "../../../web-devconsole/dist"),
20908
+ path22.join(process.cwd(), "packages/web-devconsole/dist")
20380
20909
  ];
20381
20910
  for (const dir of candidates) {
20382
- if (fs14.existsSync(path21.join(dir, "index.html"))) return dir;
20911
+ if (fs14.existsSync(path22.join(dir, "index.html"))) return dir;
20383
20912
  }
20384
20913
  return null;
20385
20914
  }
@@ -20389,7 +20918,7 @@ var DevServer = class _DevServer {
20389
20918
  this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
20390
20919
  return;
20391
20920
  }
20392
- const htmlPath = path21.join(distDir, "index.html");
20921
+ const htmlPath = path22.join(distDir, "index.html");
20393
20922
  try {
20394
20923
  const html = fs14.readFileSync(htmlPath, "utf-8");
20395
20924
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
@@ -20414,15 +20943,15 @@ var DevServer = class _DevServer {
20414
20943
  this.json(res, 404, { error: "Not found" });
20415
20944
  return;
20416
20945
  }
20417
- const safePath = path21.normalize(pathname).replace(/^\.\.\//, "");
20418
- const filePath = path21.join(distDir, safePath);
20946
+ const safePath = path22.normalize(pathname).replace(/^\.\.\//, "");
20947
+ const filePath = path22.join(distDir, safePath);
20419
20948
  if (!filePath.startsWith(distDir)) {
20420
20949
  this.json(res, 403, { error: "Forbidden" });
20421
20950
  return;
20422
20951
  }
20423
20952
  try {
20424
20953
  const content = fs14.readFileSync(filePath);
20425
- const ext = path21.extname(filePath);
20954
+ const ext = path22.extname(filePath);
20426
20955
  const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
20427
20956
  res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
20428
20957
  res.end(content);
@@ -20535,9 +21064,9 @@ var DevServer = class _DevServer {
20535
21064
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
20536
21065
  if (entry.isDirectory()) {
20537
21066
  files.push({ path: rel, size: 0, type: "dir" });
20538
- scan(path21.join(d, entry.name), rel);
21067
+ scan(path22.join(d, entry.name), rel);
20539
21068
  } else {
20540
- const stat = fs14.statSync(path21.join(d, entry.name));
21069
+ const stat = fs14.statSync(path22.join(d, entry.name));
20541
21070
  files.push({ path: rel, size: stat.size, type: "file" });
20542
21071
  }
20543
21072
  }
@@ -20560,7 +21089,7 @@ var DevServer = class _DevServer {
20560
21089
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
20561
21090
  return;
20562
21091
  }
20563
- const fullPath = path21.resolve(dir, path21.normalize(filePath));
21092
+ const fullPath = path22.resolve(dir, path22.normalize(filePath));
20564
21093
  if (!fullPath.startsWith(dir)) {
20565
21094
  this.json(res, 403, { error: "Forbidden" });
20566
21095
  return;
@@ -20585,14 +21114,14 @@ var DevServer = class _DevServer {
20585
21114
  this.json(res, 404, { error: `Provider directory not found: ${type}` });
20586
21115
  return;
20587
21116
  }
20588
- const fullPath = path21.resolve(dir, path21.normalize(filePath));
21117
+ const fullPath = path22.resolve(dir, path22.normalize(filePath));
20589
21118
  if (!fullPath.startsWith(dir)) {
20590
21119
  this.json(res, 403, { error: "Forbidden" });
20591
21120
  return;
20592
21121
  }
20593
21122
  try {
20594
21123
  if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
20595
- fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
21124
+ fs14.mkdirSync(path22.dirname(fullPath), { recursive: true });
20596
21125
  fs14.writeFileSync(fullPath, content, "utf-8");
20597
21126
  this.log(`File saved: ${fullPath} (${content.length} chars)`);
20598
21127
  this.providerLoader.reload();
@@ -20609,7 +21138,7 @@ var DevServer = class _DevServer {
20609
21138
  return;
20610
21139
  }
20611
21140
  for (const name of ["scripts.js", "provider.json"]) {
20612
- const p = path21.join(dir, name);
21141
+ const p = path22.join(dir, name);
20613
21142
  if (fs14.existsSync(p)) {
20614
21143
  const source = fs14.readFileSync(p, "utf-8");
20615
21144
  this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
@@ -20630,8 +21159,8 @@ var DevServer = class _DevServer {
20630
21159
  this.json(res, 404, { error: `Provider not found: ${type}` });
20631
21160
  return;
20632
21161
  }
20633
- const target = fs14.existsSync(path21.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
20634
- const targetPath = path21.join(dir, target);
21162
+ const target = fs14.existsSync(path22.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
21163
+ const targetPath = path22.join(dir, target);
20635
21164
  try {
20636
21165
  if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
20637
21166
  fs14.writeFileSync(targetPath, source, "utf-8");
@@ -20659,22 +21188,9 @@ var DevServer = class _DevServer {
20659
21188
  const warnings = [];
20660
21189
  try {
20661
21190
  const config = typeof content === "string" ? JSON.parse(content) : content;
20662
- if (!config.type) errors.push("Missing required field: type");
20663
- if (!config.name) errors.push("Missing required field: name");
20664
- if (!config.category) errors.push("Missing required field: category");
20665
- else if (!["ide", "extension", "cli", "acp"].includes(config.category)) errors.push(`Invalid category: ${config.category}`);
20666
- if (config.category === "ide" || config.category === "extension") {
20667
- if (!config.cdpPorts || !Array.isArray(config.cdpPorts) || config.cdpPorts.length === 0)
20668
- warnings.push("IDE/Extension providers should have cdpPorts");
20669
- if (config.category === "extension" && !config.extensionId)
20670
- warnings.push("Extension providers should have extensionId");
20671
- }
20672
- if (config.category === "acp" || config.category === "cli") {
20673
- if (!config.spawn) errors.push("ACP/CLI providers must have spawn config");
20674
- else {
20675
- if (!config.spawn.command) errors.push("spawn.command is required");
20676
- }
20677
- }
21191
+ const validation = validateProviderDefinition(config);
21192
+ errors.push(...validation.errors);
21193
+ warnings.push(...validation.warnings);
20678
21194
  if (config.settings) {
20679
21195
  for (const [key, val] of Object.entries(config.settings)) {
20680
21196
  const s = val;
@@ -20791,7 +21307,7 @@ var DevServer = class _DevServer {
20791
21307
  }
20792
21308
  let targetDir;
20793
21309
  targetDir = this.providerLoader.getUserProviderDir(category, type);
20794
- const jsonPath = path21.join(targetDir, "provider.json");
21310
+ const jsonPath = path22.join(targetDir, "provider.json");
20795
21311
  if (fs14.existsSync(jsonPath)) {
20796
21312
  this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
20797
21313
  return;
@@ -20803,8 +21319,8 @@ var DevServer = class _DevServer {
20803
21319
  const createdFiles = ["provider.json"];
20804
21320
  if (result.files) {
20805
21321
  for (const [relPath, content] of Object.entries(result.files)) {
20806
- const fullPath = path21.join(targetDir, relPath);
20807
- fs14.mkdirSync(path21.dirname(fullPath), { recursive: true });
21322
+ const fullPath = path22.join(targetDir, relPath);
21323
+ fs14.mkdirSync(path22.dirname(fullPath), { recursive: true });
20808
21324
  fs14.writeFileSync(fullPath, content, "utf-8");
20809
21325
  createdFiles.push(relPath);
20810
21326
  }
@@ -20857,22 +21373,22 @@ var DevServer = class _DevServer {
20857
21373
  if (!fs14.existsSync(scriptsDir)) return null;
20858
21374
  const versions = fs14.readdirSync(scriptsDir).filter((d) => {
20859
21375
  try {
20860
- return fs14.statSync(path21.join(scriptsDir, d)).isDirectory();
21376
+ return fs14.statSync(path22.join(scriptsDir, d)).isDirectory();
20861
21377
  } catch {
20862
21378
  return false;
20863
21379
  }
20864
21380
  }).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
20865
21381
  if (versions.length === 0) return null;
20866
- return path21.join(scriptsDir, versions[0]);
21382
+ return path22.join(scriptsDir, versions[0]);
20867
21383
  }
20868
21384
  resolveAutoImplWritableProviderDir(category, type, requestedDir) {
20869
- const canonicalUserDir = path21.resolve(this.providerLoader.getUserProviderDir(category, type));
20870
- const desiredDir = requestedDir ? path21.resolve(requestedDir) : canonicalUserDir;
20871
- const upstreamRoot = path21.resolve(this.providerLoader.getUpstreamDir());
20872
- if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path21.sep}`)) {
21385
+ const canonicalUserDir = path22.resolve(this.providerLoader.getUserProviderDir(category, type));
21386
+ const desiredDir = requestedDir ? path22.resolve(requestedDir) : canonicalUserDir;
21387
+ const upstreamRoot = path22.resolve(this.providerLoader.getUpstreamDir());
21388
+ if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path22.sep}`)) {
20873
21389
  return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
20874
21390
  }
20875
- if (path21.basename(desiredDir) !== type) {
21391
+ if (path22.basename(desiredDir) !== type) {
20876
21392
  return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
20877
21393
  }
20878
21394
  const sourceDir = this.findProviderDir(type);
@@ -20880,11 +21396,11 @@ var DevServer = class _DevServer {
20880
21396
  return { dir: null, reason: `Provider source directory not found for '${type}'` };
20881
21397
  }
20882
21398
  if (!fs14.existsSync(desiredDir)) {
20883
- fs14.mkdirSync(path21.dirname(desiredDir), { recursive: true });
21399
+ fs14.mkdirSync(path22.dirname(desiredDir), { recursive: true });
20884
21400
  fs14.cpSync(sourceDir, desiredDir, { recursive: true });
20885
21401
  this.log(`Auto-implement writable copy created: ${desiredDir}`);
20886
21402
  }
20887
- const providerJson = path21.join(desiredDir, "provider.json");
21403
+ const providerJson = path22.join(desiredDir, "provider.json");
20888
21404
  if (!fs14.existsSync(providerJson)) {
20889
21405
  return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
20890
21406
  }
@@ -20932,7 +21448,7 @@ var DevServer = class _DevServer {
20932
21448
  setMode: "set_mode.js"
20933
21449
  };
20934
21450
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
20935
- const scriptsDir = path21.join(providerDir, "scripts");
21451
+ const scriptsDir = path22.join(providerDir, "scripts");
20936
21452
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
20937
21453
  if (latestScriptsDir) {
20938
21454
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -20943,7 +21459,7 @@ var DevServer = class _DevServer {
20943
21459
  for (const file of fs14.readdirSync(latestScriptsDir)) {
20944
21460
  if (file.endsWith(".js") && targetFileNames.has(file)) {
20945
21461
  try {
20946
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
21462
+ const content = fs14.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
20947
21463
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
20948
21464
  lines.push("```javascript");
20949
21465
  lines.push(content);
@@ -20960,7 +21476,7 @@ var DevServer = class _DevServer {
20960
21476
  lines.push("");
20961
21477
  for (const file of refFiles) {
20962
21478
  try {
20963
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
21479
+ const content = fs14.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
20964
21480
  lines.push(`### \`${file}\` \u{1F512}`);
20965
21481
  lines.push("```javascript");
20966
21482
  lines.push(content);
@@ -21001,10 +21517,10 @@ var DevServer = class _DevServer {
21001
21517
  lines.push("");
21002
21518
  }
21003
21519
  }
21004
- const docsDir = path21.join(providerDir, "../../docs");
21520
+ const docsDir = path22.join(providerDir, "../../docs");
21005
21521
  const loadGuide = (name) => {
21006
21522
  try {
21007
- const p = path21.join(docsDir, name);
21523
+ const p = path22.join(docsDir, name);
21008
21524
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
21009
21525
  } catch {
21010
21526
  }
@@ -21178,7 +21694,7 @@ var DevServer = class _DevServer {
21178
21694
  parseApproval: "parse_approval.js"
21179
21695
  };
21180
21696
  const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
21181
- const scriptsDir = path21.join(providerDir, "scripts");
21697
+ const scriptsDir = path22.join(providerDir, "scripts");
21182
21698
  const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
21183
21699
  if (latestScriptsDir) {
21184
21700
  lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
@@ -21190,7 +21706,7 @@ var DevServer = class _DevServer {
21190
21706
  if (!file.endsWith(".js")) continue;
21191
21707
  if (!targetFileNames.has(file)) continue;
21192
21708
  try {
21193
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
21709
+ const content = fs14.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
21194
21710
  lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
21195
21711
  lines.push("```javascript");
21196
21712
  lines.push(content);
@@ -21206,7 +21722,7 @@ var DevServer = class _DevServer {
21206
21722
  lines.push("");
21207
21723
  for (const file of refFiles) {
21208
21724
  try {
21209
- const content = fs14.readFileSync(path21.join(latestScriptsDir, file), "utf-8");
21725
+ const content = fs14.readFileSync(path22.join(latestScriptsDir, file), "utf-8");
21210
21726
  lines.push(`### \`${file}\` \u{1F512}`);
21211
21727
  lines.push("```javascript");
21212
21728
  lines.push(content);
@@ -21239,10 +21755,10 @@ var DevServer = class _DevServer {
21239
21755
  lines.push("");
21240
21756
  }
21241
21757
  }
21242
- const docsDir = path21.join(providerDir, "../../docs");
21758
+ const docsDir = path22.join(providerDir, "../../docs");
21243
21759
  const loadGuide = (name) => {
21244
21760
  try {
21245
- const p = path21.join(docsDir, name);
21761
+ const p = path22.join(docsDir, name);
21246
21762
  if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
21247
21763
  } catch {
21248
21764
  }
@@ -21955,6 +22471,67 @@ async function listHostedCliRuntimes(endpoint) {
21955
22471
  }
21956
22472
  }
21957
22473
 
22474
+ // src/session-host/runtime-surface.ts
22475
+ var LIVE_LIFECYCLES = /* @__PURE__ */ new Set(["starting", "running", "stopping", "interrupted"]);
22476
+ function isSessionHostLiveRuntime(record) {
22477
+ const lifecycle = String(record?.lifecycle || "").trim();
22478
+ return LIVE_LIFECYCLES.has(lifecycle);
22479
+ }
22480
+ function getSessionHostRecoveryLabel(meta) {
22481
+ const recoveryState = typeof meta?.runtimeRecoveryState === "string" ? String(meta.runtimeRecoveryState).trim() : "";
22482
+ if (!recoveryState) return null;
22483
+ if (recoveryState === "auto_resumed") return "restored after restart";
22484
+ if (recoveryState === "resume_failed") return "restore failed";
22485
+ if (recoveryState === "host_restart_interrupted") return "host restart interrupted";
22486
+ if (recoveryState === "orphan_snapshot") return "snapshot recovered";
22487
+ return recoveryState.replace(/_/g, " ");
22488
+ }
22489
+ function isSessionHostRecoverySnapshot(record) {
22490
+ if (!record) return false;
22491
+ if (isSessionHostLiveRuntime(record)) return false;
22492
+ const lifecycle = String(record.lifecycle || "").trim();
22493
+ if (lifecycle && lifecycle !== "stopped" && lifecycle !== "failed") {
22494
+ return false;
22495
+ }
22496
+ const meta = record.meta || void 0;
22497
+ if (meta?.restoredFromStorage === true) return true;
22498
+ return getSessionHostRecoveryLabel(meta) !== null;
22499
+ }
22500
+ function getSessionHostSurfaceKind(record) {
22501
+ if (isSessionHostLiveRuntime(record)) return "live_runtime";
22502
+ if (isSessionHostRecoverySnapshot(record)) return "recovery_snapshot";
22503
+ return "inactive_record";
22504
+ }
22505
+ function partitionSessionHostRecords(records) {
22506
+ const liveRuntimes = [];
22507
+ const recoverySnapshots = [];
22508
+ const inactiveRecords = [];
22509
+ for (const record of records) {
22510
+ const kind = getSessionHostSurfaceKind(record);
22511
+ if (kind === "live_runtime") {
22512
+ liveRuntimes.push(record);
22513
+ } else if (kind === "recovery_snapshot") {
22514
+ recoverySnapshots.push(record);
22515
+ } else {
22516
+ inactiveRecords.push(record);
22517
+ }
22518
+ }
22519
+ return {
22520
+ liveRuntimes,
22521
+ recoverySnapshots,
22522
+ inactiveRecords
22523
+ };
22524
+ }
22525
+ function partitionSessionHostDiagnosticsSessions(records) {
22526
+ return partitionSessionHostRecords(records || []);
22527
+ }
22528
+
22529
+ // src/session-host/startup-restore-policy.js
22530
+ function shouldAutoRestoreHostedSessionsOnStartup(env = process.env) {
22531
+ const raw = typeof env.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP === "string" ? env.ADHDEV_RESTORE_HOSTED_SESSIONS_ON_STARTUP.trim().toLowerCase() : "";
22532
+ return raw === "1" || raw === "true" || raw === "yes";
22533
+ }
22534
+
21958
22535
  // src/installer.ts
21959
22536
  import { execSync as execSync6, exec as exec2 } from "child_process";
21960
22537
  var EXTENSION_CATALOG = [
@@ -22460,6 +23037,7 @@ export {
22460
23037
  detectIDEs,
22461
23038
  ensureSessionHostReady,
22462
23039
  findCdpManager,
23040
+ flattenMessageParts,
22463
23041
  forwardAgentStreamsToIdeInstance,
22464
23042
  getAIExtensions,
22465
23043
  getAvailableIdeIds,
@@ -22473,6 +23051,8 @@ export {
22473
23051
  getRecentDebugTrace,
22474
23052
  getRecentLogs,
22475
23053
  getSavedProviderSessions,
23054
+ getSessionHostRecoveryLabel,
23055
+ getSessionHostSurfaceKind,
22476
23056
  getWorkspaceState,
22477
23057
  hasCdpManager,
22478
23058
  initDaemonComponents,
@@ -22483,6 +23063,8 @@ export {
22483
23063
  isIdeRunning,
22484
23064
  isManagedStatusWaiting,
22485
23065
  isManagedStatusWorking,
23066
+ isSessionHostLiveRuntime,
23067
+ isSessionHostRecoverySnapshot,
22486
23068
  isSetupComplete,
22487
23069
  killIdeProcess,
22488
23070
  launchIDE,
@@ -22494,7 +23076,11 @@ export {
22494
23076
  markSetupComplete,
22495
23077
  maybeRunDaemonUpgradeHelperFromEnv,
22496
23078
  normalizeActiveChatData,
23079
+ normalizeInputEnvelope,
22497
23080
  normalizeManagedStatus,
23081
+ normalizeMessageParts,
23082
+ partitionSessionHostDiagnosticsSessions,
23083
+ partitionSessionHostRecords,
22498
23084
  probeCdpPort,
22499
23085
  readChatHistory,
22500
23086
  recordDebugTrace,
@@ -22509,6 +23095,7 @@ export {
22509
23095
  setDebugRuntimeConfig,
22510
23096
  setLogLevel,
22511
23097
  setupIdeInstance,
23098
+ shouldAutoRestoreHostedSessionsOnStartup,
22512
23099
  shouldCollectTraceCategory,
22513
23100
  shutdownDaemonComponents,
22514
23101
  spawnDetachedDaemonUpgradeHelper,