@adhdev/daemon-core 0.8.5 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -877,6 +877,9 @@ function promptLikelyVisible(screenText, promptSnippet) {
877
877
  function normalizeScreenSnapshot(text) {
878
878
  return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
879
879
  }
880
+ function normalizeComparableMessageContent(text) {
881
+ return String(text || "").replace(/\s+/g, " ").trim();
882
+ }
880
883
  function parsePatternEntry(x) {
881
884
  if (x instanceof RegExp) return x;
882
885
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -1058,11 +1061,44 @@ var init_provider_cli_adapter = __esm({
1058
1061
  this.structuredMessages = [...this.committedMessages];
1059
1062
  }
1060
1063
  normalizeParsedMessages(parsedMessages) {
1061
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
1062
- role: message.role,
1063
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
1064
- timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
1065
- }));
1064
+ const referenceMessages = [...this.committedMessages];
1065
+ const usedReferenceIndexes = /* @__PURE__ */ new Set();
1066
+ const now = Date.now();
1067
+ const findReferenceTimestamp = (role, content, parsedIndex) => {
1068
+ const normalizedContent = normalizeComparableMessageContent(content);
1069
+ if (!normalizedContent) return void 0;
1070
+ const sameIndex = referenceMessages[parsedIndex];
1071
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
1072
+ usedReferenceIndexes.add(parsedIndex);
1073
+ return sameIndex.timestamp;
1074
+ }
1075
+ for (let i = 0; i < referenceMessages.length; i++) {
1076
+ if (usedReferenceIndexes.has(i)) continue;
1077
+ const candidate = referenceMessages[i];
1078
+ if (!candidate || candidate.role !== role) continue;
1079
+ const candidateContent = normalizeComparableMessageContent(candidate.content);
1080
+ if (!candidateContent) continue;
1081
+ const exactMatch = candidateContent === normalizedContent;
1082
+ const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
1083
+ if (!exactMatch && !fuzzyMatch) continue;
1084
+ if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
1085
+ usedReferenceIndexes.add(i);
1086
+ return candidate.timestamp;
1087
+ }
1088
+ }
1089
+ return void 0;
1090
+ };
1091
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
1092
+ const role = message.role;
1093
+ const content = typeof message.content === "string" ? message.content : String(message.content || "");
1094
+ const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
1095
+ const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
1096
+ return {
1097
+ role,
1098
+ content,
1099
+ timestamp: referenceTimestamp ?? now
1100
+ };
1101
+ });
1066
1102
  }
1067
1103
  sliceFromOffset(text, start) {
1068
1104
  if (!text) return "";
@@ -1220,11 +1256,15 @@ var init_provider_cli_adapter = __esm({
1220
1256
  let shellCmd;
1221
1257
  let shellArgs;
1222
1258
  const useShellUnix = !isWin && (!!spawnConfig.shell || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
1223
- const useShell = isWin ? !!spawnConfig.shell : useShellUnix;
1259
+ const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
1260
+ const useShell = isWin ? !!spawnConfig.shell || isCmdShim : useShellUnix;
1224
1261
  if (useShell) {
1225
1262
  if (!spawnConfig.shell && !isWin) {
1226
1263
  LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
1227
1264
  }
1265
+ if (isCmdShim) {
1266
+ LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell for .cmd/.bat shim: ${binaryPath}`);
1267
+ }
1228
1268
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
1229
1269
  if (isWin) {
1230
1270
  shellArgs = ["/c", binaryPath, ...allArgs];
@@ -15896,6 +15936,8 @@ async function handleAutoImplement(ctx, type, req, res) {
15896
15936
  let approvalBuffer = "";
15897
15937
  let lastApprovalTime = 0;
15898
15938
  let completionSignalSeen = false;
15939
+ let autoStopTimer = null;
15940
+ let autoStopIssued = false;
15899
15941
  try {
15900
15942
  const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
15901
15943
  const normalized = normalizeCliProviderForRuntime2(agentProvider);
@@ -15933,8 +15975,37 @@ async function handleAutoImplement(ctx, type, req, res) {
15933
15975
  lastApprovalTime = Date.now();
15934
15976
  }
15935
15977
  };
15978
+ const clearAutoStopTimer = () => {
15979
+ if (autoStopTimer) {
15980
+ clearTimeout(autoStopTimer);
15981
+ autoStopTimer = null;
15982
+ }
15983
+ };
15984
+ const scheduleAutoStopForVerification = () => {
15985
+ if (!verification || command !== "codex" || completionSignalSeen || autoStopIssued) return;
15986
+ const elapsed = Date.now() - spawnedAt;
15987
+ if (elapsed < 3e4) return;
15988
+ clearAutoStopTimer();
15989
+ autoStopTimer = setTimeout(() => {
15990
+ if (!ctx.autoImplProcess || completionSignalSeen || autoStopIssued) return;
15991
+ autoStopIssued = true;
15992
+ ctx.log(`Auto-implement output quiet for 30s after ${Math.round((Date.now() - spawnedAt) / 1e3)}s. Interrupting agent and switching to daemon verification.`);
15993
+ sendAutoImplSSE(ctx, {
15994
+ event: "output",
15995
+ data: {
15996
+ chunk: "\n[\u{1F916} ADHDev Pipeline] Agent output quiet. Interrupting and running daemon verification...\n",
15997
+ stream: "stdout"
15998
+ }
15999
+ });
16000
+ try {
16001
+ ctx.autoImplProcess.kill("SIGINT");
16002
+ } catch {
16003
+ }
16004
+ }, 3e4);
16005
+ };
15936
16006
  const finalizeCliAutoImpl = async (code) => {
15937
16007
  ctx.autoImplProcess = null;
16008
+ clearAutoStopTimer();
15938
16009
  let success = completionSignalSeen || code === 0;
15939
16010
  let message = success ? completionSignalSeen && code !== 0 ? "\u2705 Auto-implement complete (completion signal)" : "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`;
15940
16011
  let verificationSummary = null;
@@ -15985,12 +16056,14 @@ async function handleAutoImplement(ctx, type, req, res) {
15985
16056
  if (isPty) {
15986
16057
  child.onData((data) => {
15987
16058
  stdout += data;
16059
+ clearAutoStopTimer();
15988
16060
  if (data.includes("\x1B[6n")) {
15989
16061
  child.write("\x1B[12;1R");
15990
16062
  ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
15991
16063
  }
15992
16064
  checkAutoApproval(data, (s) => child.write(s));
15993
16065
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
16066
+ scheduleAutoStopForVerification();
15994
16067
  });
15995
16068
  child.onExit(({ exitCode: code }) => {
15996
16069
  void finalizeCliAutoImpl(code);
@@ -15999,15 +16072,19 @@ async function handleAutoImplement(ctx, type, req, res) {
15999
16072
  child.stdout?.on("data", (d) => {
16000
16073
  const chunk = d.toString();
16001
16074
  stdout += chunk;
16075
+ clearAutoStopTimer();
16002
16076
  if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
16003
16077
  checkAutoApproval(chunk, (s) => child.stdin?.write(s));
16004
16078
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
16079
+ scheduleAutoStopForVerification();
16005
16080
  });
16006
16081
  child.stderr?.on("data", (d) => {
16007
16082
  const chunk = d.toString();
16008
16083
  stderr += chunk;
16084
+ clearAutoStopTimer();
16009
16085
  checkAutoApproval(chunk, (s) => child.stdin?.write(s));
16010
16086
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
16087
+ scheduleAutoStopForVerification();
16011
16088
  });
16012
16089
  child.on("exit", (code) => {
16013
16090
  void finalizeCliAutoImpl(code);