adhdev 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/cli/index.js CHANGED
@@ -6406,6 +6406,9 @@ function promptLikelyVisible(screenText, promptSnippet) {
6406
6406
  function normalizeScreenSnapshot(text) {
6407
6407
  return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
6408
6408
  }
6409
+ function normalizeComparableMessageContent(text) {
6410
+ return String(text || "").replace(/\s+/g, " ").trim();
6411
+ }
6409
6412
  function parsePatternEntry(x) {
6410
6413
  if (x instanceof RegExp) return x;
6411
6414
  if (x && typeof x === "object" && typeof x.source === "string") {
@@ -6587,11 +6590,44 @@ var init_provider_cli_adapter = __esm({
6587
6590
  this.structuredMessages = [...this.committedMessages];
6588
6591
  }
6589
6592
  normalizeParsedMessages(parsedMessages) {
6590
- return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message) => ({
6591
- role: message.role,
6592
- content: typeof message.content === "string" ? message.content : String(message.content || ""),
6593
- timestamp: typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : Date.now()
6594
- }));
6593
+ const referenceMessages = [...this.committedMessages];
6594
+ const usedReferenceIndexes = /* @__PURE__ */ new Set();
6595
+ const now = Date.now();
6596
+ const findReferenceTimestamp = (role, content, parsedIndex) => {
6597
+ const normalizedContent = normalizeComparableMessageContent(content);
6598
+ if (!normalizedContent) return void 0;
6599
+ const sameIndex = referenceMessages[parsedIndex];
6600
+ if (sameIndex && !usedReferenceIndexes.has(parsedIndex) && sameIndex.role === role && normalizeComparableMessageContent(sameIndex.content) === normalizedContent && typeof sameIndex.timestamp === "number" && Number.isFinite(sameIndex.timestamp)) {
6601
+ usedReferenceIndexes.add(parsedIndex);
6602
+ return sameIndex.timestamp;
6603
+ }
6604
+ for (let i = 0; i < referenceMessages.length; i++) {
6605
+ if (usedReferenceIndexes.has(i)) continue;
6606
+ const candidate = referenceMessages[i];
6607
+ if (!candidate || candidate.role !== role) continue;
6608
+ const candidateContent = normalizeComparableMessageContent(candidate.content);
6609
+ if (!candidateContent) continue;
6610
+ const exactMatch = candidateContent === normalizedContent;
6611
+ const fuzzyMatch = candidateContent.includes(normalizedContent) || normalizedContent.includes(candidateContent);
6612
+ if (!exactMatch && !fuzzyMatch) continue;
6613
+ if (typeof candidate.timestamp === "number" && Number.isFinite(candidate.timestamp)) {
6614
+ usedReferenceIndexes.add(i);
6615
+ return candidate.timestamp;
6616
+ }
6617
+ }
6618
+ return void 0;
6619
+ };
6620
+ return parsedMessages.filter((message) => message && (message.role === "user" || message.role === "assistant")).map((message, index) => {
6621
+ const role = message.role;
6622
+ const content = typeof message.content === "string" ? message.content : String(message.content || "");
6623
+ const parsedTimestamp = typeof message.timestamp === "number" && Number.isFinite(message.timestamp) ? message.timestamp : void 0;
6624
+ const referenceTimestamp = parsedTimestamp ?? findReferenceTimestamp(role, content, index);
6625
+ return {
6626
+ role,
6627
+ content,
6628
+ timestamp: referenceTimestamp ?? now
6629
+ };
6630
+ });
6595
6631
  }
6596
6632
  sliceFromOffset(text, start) {
6597
6633
  if (!text) return "";
@@ -6749,11 +6785,15 @@ var init_provider_cli_adapter = __esm({
6749
6785
  let shellCmd;
6750
6786
  let shellArgs;
6751
6787
  const useShellUnix = !isWin && (!!spawnConfig.shell || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
6752
- const useShell = isWin ? !!spawnConfig.shell : useShellUnix;
6788
+ const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
6789
+ const useShell = isWin ? !!spawnConfig.shell || isCmdShim : useShellUnix;
6753
6790
  if (useShell) {
6754
6791
  if (!spawnConfig.shell && !isWin) {
6755
6792
  LOG.info("CLI", `[${this.cliType}] Using login shell (script shim or non-native binary)`);
6756
6793
  }
6794
+ if (isCmdShim) {
6795
+ LOG.info("CLI", `[${this.cliType}] Using cmd.exe shell for .cmd/.bat shim: ${binaryPath}`);
6796
+ }
6757
6797
  shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
6758
6798
  if (isWin) {
6759
6799
  shellArgs = ["/c", binaryPath, ...allArgs];
@@ -34166,6 +34206,8 @@ async function handleAutoImplement(ctx, type, req, res) {
34166
34206
  let approvalBuffer = "";
34167
34207
  let lastApprovalTime = 0;
34168
34208
  let completionSignalSeen = false;
34209
+ let autoStopTimer = null;
34210
+ let autoStopIssued = false;
34169
34211
  try {
34170
34212
  const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
34171
34213
  const normalized = normalizeCliProviderForRuntime2(agentProvider);
@@ -34203,8 +34245,37 @@ async function handleAutoImplement(ctx, type, req, res) {
34203
34245
  lastApprovalTime = Date.now();
34204
34246
  }
34205
34247
  };
34248
+ const clearAutoStopTimer = () => {
34249
+ if (autoStopTimer) {
34250
+ clearTimeout(autoStopTimer);
34251
+ autoStopTimer = null;
34252
+ }
34253
+ };
34254
+ const scheduleAutoStopForVerification = () => {
34255
+ if (!verification || command !== "codex" || completionSignalSeen || autoStopIssued) return;
34256
+ const elapsed = Date.now() - spawnedAt;
34257
+ if (elapsed < 3e4) return;
34258
+ clearAutoStopTimer();
34259
+ autoStopTimer = setTimeout(() => {
34260
+ if (!ctx.autoImplProcess || completionSignalSeen || autoStopIssued) return;
34261
+ autoStopIssued = true;
34262
+ ctx.log(`Auto-implement output quiet for 30s after ${Math.round((Date.now() - spawnedAt) / 1e3)}s. Interrupting agent and switching to daemon verification.`);
34263
+ sendAutoImplSSE(ctx, {
34264
+ event: "output",
34265
+ data: {
34266
+ chunk: "\n[\u{1F916} ADHDev Pipeline] Agent output quiet. Interrupting and running daemon verification...\n",
34267
+ stream: "stdout"
34268
+ }
34269
+ });
34270
+ try {
34271
+ ctx.autoImplProcess.kill("SIGINT");
34272
+ } catch {
34273
+ }
34274
+ }, 3e4);
34275
+ };
34206
34276
  const finalizeCliAutoImpl = async (code) => {
34207
34277
  ctx.autoImplProcess = null;
34278
+ clearAutoStopTimer();
34208
34279
  let success2 = completionSignalSeen || code === 0;
34209
34280
  let message = success2 ? completionSignalSeen && code !== 0 ? "\u2705 Auto-implement complete (completion signal)" : "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`;
34210
34281
  let verificationSummary = null;
@@ -34255,12 +34326,14 @@ async function handleAutoImplement(ctx, type, req, res) {
34255
34326
  if (isPty) {
34256
34327
  child.onData((data) => {
34257
34328
  stdout += data;
34329
+ clearAutoStopTimer();
34258
34330
  if (data.includes("\x1B[6n")) {
34259
34331
  child.write("\x1B[12;1R");
34260
34332
  ctx.log("Terminal CPR request (\\x1b[6n) intercepted in PTY, responding with dummy coordinates [12;1R]");
34261
34333
  }
34262
34334
  checkAutoApproval(data, (s) => child.write(s));
34263
34335
  sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
34336
+ scheduleAutoStopForVerification();
34264
34337
  });
34265
34338
  child.onExit(({ exitCode: code }) => {
34266
34339
  void finalizeCliAutoImpl(code);
@@ -34269,15 +34342,19 @@ async function handleAutoImplement(ctx, type, req, res) {
34269
34342
  child.stdout?.on("data", (d) => {
34270
34343
  const chunk = d.toString();
34271
34344
  stdout += chunk;
34345
+ clearAutoStopTimer();
34272
34346
  if (chunk.includes("\x1B[6n")) child.stdin?.write("\x1B[1;1R");
34273
34347
  checkAutoApproval(chunk, (s) => child.stdin?.write(s));
34274
34348
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stdout" } });
34349
+ scheduleAutoStopForVerification();
34275
34350
  });
34276
34351
  child.stderr?.on("data", (d) => {
34277
34352
  const chunk = d.toString();
34278
34353
  stderr += chunk;
34354
+ clearAutoStopTimer();
34279
34355
  checkAutoApproval(chunk, (s) => child.stdin?.write(s));
34280
34356
  sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
34357
+ scheduleAutoStopForVerification();
34281
34358
  });
34282
34359
  child.on("exit", (code) => {
34283
34360
  void finalizeCliAutoImpl(code);
@@ -39153,7 +39230,7 @@ var init_adhdev_daemon = __esm({
39153
39230
  fs17 = __toESM(require("fs"));
39154
39231
  path21 = __toESM(require("path"));
39155
39232
  import_chalk2 = __toESM(require("chalk"));
39156
- pkgVersion = "0.8.5";
39233
+ pkgVersion = "0.8.7";
39157
39234
  if (pkgVersion === "unknown") {
39158
39235
  try {
39159
39236
  const possiblePaths = [
@@ -40734,6 +40811,52 @@ function getDefaultAutoFixReference(category, type, providers) {
40734
40811
  }
40735
40812
  return "antigravity";
40736
40813
  }
40814
+ function escapeRegex2(value) {
40815
+ return String(value || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
40816
+ }
40817
+ function getCliAutoFixVerification(type, providerDir) {
40818
+ if (type !== "codex-cli") return null;
40819
+ const normalizedDir = providerDir.replace(/\\/g, "/");
40820
+ const escapedDir = escapeRegex2(normalizedDir);
40821
+ return {
40822
+ fixtureName: "codex-cli-provider-fix",
40823
+ request: {
40824
+ type,
40825
+ workingDir: providerDir,
40826
+ freshSession: true,
40827
+ autoLaunch: true,
40828
+ autoResolveApprovals: true,
40829
+ approvalButtonIndex: 0,
40830
+ timeoutMs: 9e4,
40831
+ traceLimit: 200,
40832
+ text: "Create a file at tmp/adhdev_provider_fix_test.py that prints the current working directory and the squares of 1 through 5, then run python3 tmp/adhdev_provider_fix_test.py and tell me the exact output."
40833
+ },
40834
+ inspectFields: [
40835
+ "debug.messages",
40836
+ "trace.entries[].payload.parsedLastAssistant",
40837
+ "trace.entries[].payload.detectStatus",
40838
+ "trace.entries[].payload.parsedStatus"
40839
+ ],
40840
+ lastAssistantMustContainAny: [
40841
+ "Exact output:",
40842
+ "1",
40843
+ "4",
40844
+ "9",
40845
+ "16",
40846
+ "25"
40847
+ ],
40848
+ lastAssistantMustMatchAny: [
40849
+ escapedDir
40850
+ ],
40851
+ lastAssistantMustNotContainAny: [
40852
+ "Do you trust the contents of this directory?",
40853
+ "OpenAI Codex",
40854
+ "Tip: New",
40855
+ "Summarize recent commits"
40856
+ ],
40857
+ description: "Codex CLI must classify startup/trust screens correctly, transition idle -> generating -> idle, and preserve the exact stdout block in the final assistant transcript."
40858
+ };
40859
+ }
40737
40860
  function hideCommand2(command) {
40738
40861
  command.hideHelp?.();
40739
40862
  return command;
@@ -41145,13 +41268,15 @@ function registerProviderCommands(program2) {
41145
41268
  console.log(import_chalk6.default.gray(` \u{1F4AC} Comment: ${userComment}`));
41146
41269
  }
41147
41270
  try {
41271
+ const verification = providerToFix.category === "cli" ? getCliAutoFixVerification(type, targetDir) : null;
41148
41272
  const postData = JSON.stringify({
41149
41273
  functions: functionsToFix,
41150
41274
  agent: agentName,
41151
41275
  providerDir: targetDir,
41152
41276
  ...modelName ? { model: modelName } : {},
41153
41277
  ...userComment ? { comment: userComment } : {},
41154
- reference
41278
+ reference,
41279
+ ...verification ? { verification } : {}
41155
41280
  });
41156
41281
  const startResult = await new Promise((resolve13, reject) => {
41157
41282
  const req = http3.request({
@@ -41182,6 +41307,14 @@ function registerProviderCommands(program2) {
41182
41307
  throw new Error(`Auto-Impl Failed: ${startResult.error}`);
41183
41308
  }
41184
41309
  }
41310
+ if (startResult.skipped && startResult.verification?.pass) {
41311
+ console.log(import_chalk6.default.green(`
41312
+ \u2705 Auto-Implement preflight already passes for ${type}.`));
41313
+ console.log(import_chalk6.default.gray(` Verification mode: ${startResult.verification.mode}`));
41314
+ console.log(import_chalk6.default.gray(` Provider dir: ${startResult.providerDir}`));
41315
+ console.log();
41316
+ return;
41317
+ }
41185
41318
  if (!startResult.started || !startResult.sseUrl) {
41186
41319
  throw new Error(`Unexpected response: ${JSON.stringify(startResult)}`);
41187
41320
  }