@adhdev/daemon-standalone 0.7.46 → 0.8.0
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 +1739 -237
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/index-C-G2T3m8.css +1 -0
- package/public/assets/index-VNHAnmKl.js +62 -0
- package/public/index.html +2 -2
- package/vendor/session-host-daemon/index.js +14 -3
- package/vendor/session-host-daemon/index.js.map +1 -1
- package/vendor/session-host-daemon/index.mjs +14 -3
- package/vendor/session-host-daemon/index.mjs.map +1 -1
- package/public/assets/index-B7gMWsoX.js +0 -68
- package/public/assets/index-DiWCXoGV.css +0 -1
package/dist/index.js
CHANGED
|
@@ -27570,7 +27570,7 @@ var require_dist = __commonJS({
|
|
|
27570
27570
|
};
|
|
27571
27571
|
}
|
|
27572
27572
|
};
|
|
27573
|
-
var
|
|
27573
|
+
var os6 = __toESM2(require("os"));
|
|
27574
27574
|
var path22 = __toESM2(require("path"));
|
|
27575
27575
|
var net3 = __toESM2(require("net"));
|
|
27576
27576
|
var import_crypto22 = require("crypto");
|
|
@@ -27583,7 +27583,7 @@ var require_dist = __commonJS({
|
|
|
27583
27583
|
}
|
|
27584
27584
|
return {
|
|
27585
27585
|
kind: "unix",
|
|
27586
|
-
path: path22.join(
|
|
27586
|
+
path: path22.join(os6.tmpdir(), `${appName}-session-host.sock`)
|
|
27587
27587
|
};
|
|
27588
27588
|
}
|
|
27589
27589
|
function serializeEnvelope3(envelope) {
|
|
@@ -28488,10 +28488,10 @@ var require_dist2 = __commonJS({
|
|
|
28488
28488
|
normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime
|
|
28489
28489
|
});
|
|
28490
28490
|
function stripAnsi(str) {
|
|
28491
|
-
return str.replace(/\x1B\[
|
|
28491
|
+
return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
|
|
28492
28492
|
}
|
|
28493
28493
|
function stripTerminalNoise(str) {
|
|
28494
|
-
return String(str || "").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, "").replace(/(^|[\s([])(?:\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\[\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d{1,4};\?)(?=$|[\s)\]])/g, "$1").replace(/\r+/g, "\n").replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").replace(/ {2,}/g, " ");
|
|
28494
|
+
return String(str || "").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, "").replace(/(^|[\s([])(?:\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\[\??\d{1,4}(?:;\d{1,4})*[A-Za-z])(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d{1,4};\?)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d+\$r[0-9;\" ]*[A-Za-z]?)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:>\|[A-Za-z0-9_.:-]+(?:\([^)]*\))?)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:[A-Z]\d(?:\s+[A-Z]\d)+)(?=$|[\s)\]])/g, "$1").replace(/(^|[\s([])(?:\d+;[^\s)\]]+)(?=$|[\s)\]])/g, "$1").replace(/\r+/g, "\n").replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").replace(/ {2,}/g, " ");
|
|
28495
28495
|
}
|
|
28496
28496
|
function sanitizeTerminalText(str) {
|
|
28497
28497
|
return stripTerminalNoise(stripAnsi(str));
|
|
@@ -28534,12 +28534,12 @@ var require_dist2 = __commonJS({
|
|
|
28534
28534
|
function isScriptBinary(binaryPath) {
|
|
28535
28535
|
if (!path7.isAbsolute(binaryPath)) return false;
|
|
28536
28536
|
try {
|
|
28537
|
-
const
|
|
28538
|
-
const resolved =
|
|
28537
|
+
const fs15 = require("fs");
|
|
28538
|
+
const resolved = fs15.realpathSync(binaryPath);
|
|
28539
28539
|
const head = Buffer.alloc(8);
|
|
28540
|
-
const fd =
|
|
28541
|
-
|
|
28542
|
-
|
|
28540
|
+
const fd = fs15.openSync(resolved, "r");
|
|
28541
|
+
fs15.readSync(fd, head, 0, 8, 0);
|
|
28542
|
+
fs15.closeSync(fd);
|
|
28543
28543
|
let i = 0;
|
|
28544
28544
|
if (head[0] === 239 && head[1] === 187 && head[2] === 191) i = 3;
|
|
28545
28545
|
return head[i] === 35 && head[i + 1] === 33;
|
|
@@ -28550,12 +28550,12 @@ var require_dist2 = __commonJS({
|
|
|
28550
28550
|
function looksLikeMachOOrElf(filePath) {
|
|
28551
28551
|
if (!path7.isAbsolute(filePath)) return false;
|
|
28552
28552
|
try {
|
|
28553
|
-
const
|
|
28554
|
-
const resolved =
|
|
28553
|
+
const fs15 = require("fs");
|
|
28554
|
+
const resolved = fs15.realpathSync(filePath);
|
|
28555
28555
|
const buf = Buffer.alloc(8);
|
|
28556
|
-
const fd =
|
|
28557
|
-
|
|
28558
|
-
|
|
28556
|
+
const fd = fs15.openSync(resolved, "r");
|
|
28557
|
+
fs15.readSync(fd, buf, 0, 8, 0);
|
|
28558
|
+
fs15.closeSync(fd);
|
|
28559
28559
|
let i = 0;
|
|
28560
28560
|
if (buf[0] === 239 && buf[1] === 187 && buf[2] === 191) i = 3;
|
|
28561
28561
|
const b2 = buf.subarray(i);
|
|
@@ -28608,6 +28608,9 @@ var require_dist2 = __commonJS({
|
|
|
28608
28608
|
).length;
|
|
28609
28609
|
return matched >= required2;
|
|
28610
28610
|
}
|
|
28611
|
+
function normalizeScreenSnapshot(text) {
|
|
28612
|
+
return sanitizeTerminalText(String(text || "")).replace(/\s+/g, " ").trim();
|
|
28613
|
+
}
|
|
28611
28614
|
function parsePatternEntry(x) {
|
|
28612
28615
|
if (x instanceof RegExp) return x;
|
|
28613
28616
|
if (x && typeof x === "object" && typeof x.source === "string") {
|
|
@@ -28650,14 +28653,14 @@ var require_dist2 = __commonJS({
|
|
|
28650
28653
|
pty2 = require("node-pty");
|
|
28651
28654
|
if (os8.platform() !== "win32") {
|
|
28652
28655
|
try {
|
|
28653
|
-
const
|
|
28656
|
+
const fs15 = require("fs");
|
|
28654
28657
|
const ptyDir = path7.resolve(path7.dirname(require.resolve("node-pty")), "..");
|
|
28655
28658
|
const platformArch = `${os8.platform()}-${os8.arch()}`;
|
|
28656
28659
|
const helper = path7.join(ptyDir, "prebuilds", platformArch, "spawn-helper");
|
|
28657
|
-
if (
|
|
28658
|
-
const stat4 =
|
|
28660
|
+
if (fs15.existsSync(helper)) {
|
|
28661
|
+
const stat4 = fs15.statSync(helper);
|
|
28659
28662
|
if (!(stat4.mode & 73)) {
|
|
28660
|
-
|
|
28663
|
+
fs15.chmodSync(helper, stat4.mode | 493);
|
|
28661
28664
|
LOG2.info("CLI", "[node-pty] Fixed spawn-helper permissions");
|
|
28662
28665
|
}
|
|
28663
28666
|
}
|
|
@@ -28691,10 +28694,25 @@ var require_dist2 = __commonJS({
|
|
|
28691
28694
|
this.sendDelayMs = typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0;
|
|
28692
28695
|
this.sendKey = typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r";
|
|
28693
28696
|
this.submitStrategy = provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo";
|
|
28697
|
+
this.providerResolutionMeta = {
|
|
28698
|
+
type: provider.type,
|
|
28699
|
+
name: provider.name,
|
|
28700
|
+
resolvedVersion: provider._resolvedVersion || null,
|
|
28701
|
+
resolvedOs: provider._resolvedOs || null,
|
|
28702
|
+
providerDir: provider._resolvedProviderDir || null,
|
|
28703
|
+
scriptDir: provider._resolvedScriptDir || null,
|
|
28704
|
+
scriptsPath: provider._resolvedScriptsPath || null,
|
|
28705
|
+
scriptsSource: provider._resolvedScriptsSource || null,
|
|
28706
|
+
versionWarning: provider._versionWarning || null
|
|
28707
|
+
};
|
|
28694
28708
|
this.cliScripts = provider.scripts || {};
|
|
28695
28709
|
const scriptNames = Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function");
|
|
28696
28710
|
if (scriptNames.length > 0) {
|
|
28697
28711
|
LOG2.info("CLI", `[${this.cliType}] CLI scripts: [${scriptNames.join(", ")}]`);
|
|
28712
|
+
LOG2.info(
|
|
28713
|
+
"CLI",
|
|
28714
|
+
`[${this.cliType}] Provider resolution: providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"} source=${this.providerResolutionMeta.scriptsSource || "-"} version=${this.providerResolutionMeta.resolvedVersion || "-"}`
|
|
28715
|
+
);
|
|
28698
28716
|
} else {
|
|
28699
28717
|
LOG2.warn("CLI", `[${this.cliType}] \u26A0 No CLI scripts loaded! Provider needs scripts/{version}/scripts.js`);
|
|
28700
28718
|
}
|
|
@@ -28727,6 +28745,10 @@ var require_dist2 = __commonJS({
|
|
|
28727
28745
|
ptyOutputBuffer = "";
|
|
28728
28746
|
ptyOutputFlushTimer = null;
|
|
28729
28747
|
pendingTerminalQueryTail = "";
|
|
28748
|
+
lastOutputAt = 0;
|
|
28749
|
+
lastNonEmptyOutputAt = 0;
|
|
28750
|
+
lastScreenChangeAt = 0;
|
|
28751
|
+
lastScreenSnapshot = "";
|
|
28730
28752
|
// Server log forwarding
|
|
28731
28753
|
serverConn = null;
|
|
28732
28754
|
logBuffer = [];
|
|
@@ -28747,6 +28769,7 @@ var require_dist2 = __commonJS({
|
|
|
28747
28769
|
submitRetryTimer = null;
|
|
28748
28770
|
submitRetryUsed = false;
|
|
28749
28771
|
submitRetryPromptSnippet = "";
|
|
28772
|
+
idleFinishCandidate = null;
|
|
28750
28773
|
// Resize redraw suppression
|
|
28751
28774
|
resizeSuppressUntil = 0;
|
|
28752
28775
|
// Debug: status transition history
|
|
@@ -28762,6 +28785,12 @@ var require_dist2 = __commonJS({
|
|
|
28762
28785
|
/** Max accumulated buffer size (last 50KB) */
|
|
28763
28786
|
static MAX_ACCUMULATED_BUFFER = 5e4;
|
|
28764
28787
|
currentTurnScope = null;
|
|
28788
|
+
traceEntries = [];
|
|
28789
|
+
traceSeq = 0;
|
|
28790
|
+
traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
28791
|
+
static MAX_TRACE_ENTRIES = 250;
|
|
28792
|
+
providerResolutionMeta;
|
|
28793
|
+
static IDLE_FINISH_CONFIRM_MS = 900;
|
|
28765
28794
|
syncMessageViews() {
|
|
28766
28795
|
this.messages = [...this.committedMessages];
|
|
28767
28796
|
this.structuredMessages = [...this.committedMessages];
|
|
@@ -28797,8 +28826,89 @@ var require_dist2 = __commonJS({
|
|
|
28797
28826
|
this.currentStatus = status;
|
|
28798
28827
|
this.statusHistory.push({ status, at: Date.now(), trigger });
|
|
28799
28828
|
if (this.statusHistory.length > 50) this.statusHistory.shift();
|
|
28829
|
+
this.recordTrace("status", {
|
|
28830
|
+
previousStatus: prev,
|
|
28831
|
+
trigger: trigger || null
|
|
28832
|
+
});
|
|
28800
28833
|
LOG2.info("CLI", `[${this.cliType}] status: ${prev} \u2192 ${status}${trigger ? ` (${trigger})` : ""}`);
|
|
28801
28834
|
}
|
|
28835
|
+
clearIdleFinishCandidate(reason) {
|
|
28836
|
+
if (!this.idleFinishCandidate) return;
|
|
28837
|
+
this.recordTrace("idle_candidate_reset", {
|
|
28838
|
+
reason,
|
|
28839
|
+
candidate: this.idleFinishCandidate
|
|
28840
|
+
});
|
|
28841
|
+
this.idleFinishCandidate = null;
|
|
28842
|
+
}
|
|
28843
|
+
armIdleFinishCandidate(assistantLength) {
|
|
28844
|
+
const now = Date.now();
|
|
28845
|
+
this.idleFinishCandidate = {
|
|
28846
|
+
armedAt: now,
|
|
28847
|
+
lastOutputAt: this.lastOutputAt,
|
|
28848
|
+
lastScreenChangeAt: this.lastScreenChangeAt,
|
|
28849
|
+
responseEpoch: this.responseEpoch,
|
|
28850
|
+
assistantLength
|
|
28851
|
+
};
|
|
28852
|
+
this.recordTrace("idle_candidate_armed", {
|
|
28853
|
+
confirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
|
|
28854
|
+
candidate: this.idleFinishCandidate,
|
|
28855
|
+
...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
|
|
28856
|
+
});
|
|
28857
|
+
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
28858
|
+
this.settleTimer = setTimeout(() => {
|
|
28859
|
+
this.settleTimer = null;
|
|
28860
|
+
this.settledBuffer = this.recentOutputBuffer;
|
|
28861
|
+
this.evaluateSettled();
|
|
28862
|
+
}, _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS);
|
|
28863
|
+
}
|
|
28864
|
+
summarizeTraceText(text, max = 800) {
|
|
28865
|
+
const value = sanitizeTerminalText(String(text || ""));
|
|
28866
|
+
if (value.length <= max) return value;
|
|
28867
|
+
return `\u2026${value.slice(-max)}`;
|
|
28868
|
+
}
|
|
28869
|
+
summarizeTraceMessages(messages, limit = 3) {
|
|
28870
|
+
return messages.slice(-limit).map((message) => ({
|
|
28871
|
+
role: message.role,
|
|
28872
|
+
content: this.summarizeTraceText(message.content, 240),
|
|
28873
|
+
timestamp: message.timestamp
|
|
28874
|
+
}));
|
|
28875
|
+
}
|
|
28876
|
+
buildTraceParseSnapshot(scope, partialResponse = "") {
|
|
28877
|
+
const scopedBuffer = scope ? this.sliceFromOffset(this.accumulatedBuffer, scope.bufferStart) || this.accumulatedBuffer : this.accumulatedBuffer;
|
|
28878
|
+
const scopedRawBuffer = scope ? this.sliceFromOffset(this.accumulatedRawBuffer, scope.rawBufferStart) || this.accumulatedRawBuffer : this.accumulatedRawBuffer;
|
|
28879
|
+
return {
|
|
28880
|
+
currentTurnScope: scope || null,
|
|
28881
|
+
responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
|
|
28882
|
+
partialResponse: this.summarizeTraceText(partialResponse || this.responseBuffer, 1200),
|
|
28883
|
+
turnBuffer: this.summarizeTraceText(scopedBuffer, 1600),
|
|
28884
|
+
turnRawPreview: this.summarizeTraceText(scopedRawBuffer, 1600),
|
|
28885
|
+
turnSanitizedRawPreview: this.summarizeTraceText(sanitizeTerminalText(scopedRawBuffer), 1600)
|
|
28886
|
+
};
|
|
28887
|
+
}
|
|
28888
|
+
recordTrace(type, payload = {}) {
|
|
28889
|
+
const entry = {
|
|
28890
|
+
id: ++this.traceSeq,
|
|
28891
|
+
at: Date.now(),
|
|
28892
|
+
type,
|
|
28893
|
+
status: this.currentStatus,
|
|
28894
|
+
isWaitingForResponse: this.isWaitingForResponse,
|
|
28895
|
+
activeModal: this.activeModal ? { message: this.activeModal.message, buttons: [...this.activeModal.buttons] } : null,
|
|
28896
|
+
payload
|
|
28897
|
+
};
|
|
28898
|
+
this.traceEntries.push(entry);
|
|
28899
|
+
if (this.traceEntries.length > _ProviderCliAdapter.MAX_TRACE_ENTRIES) {
|
|
28900
|
+
this.traceEntries.splice(0, this.traceEntries.length - _ProviderCliAdapter.MAX_TRACE_ENTRIES);
|
|
28901
|
+
}
|
|
28902
|
+
}
|
|
28903
|
+
resetTraceSession() {
|
|
28904
|
+
this.traceEntries = [];
|
|
28905
|
+
this.traceSeq = 0;
|
|
28906
|
+
this.traceSessionId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
28907
|
+
this.recordTrace("session_start", {
|
|
28908
|
+
providerType: this.cliType,
|
|
28909
|
+
workingDir: this.workingDir
|
|
28910
|
+
});
|
|
28911
|
+
}
|
|
28802
28912
|
// Resolved timeouts
|
|
28803
28913
|
timeouts;
|
|
28804
28914
|
// Provider approval key mapping
|
|
@@ -28844,6 +28954,7 @@ var require_dist2 = __commonJS({
|
|
|
28844
28954
|
const isWin = os8.platform() === "win32";
|
|
28845
28955
|
const allArgs = [...spawnConfig.args, ...this.extraArgs];
|
|
28846
28956
|
LOG2.info("CLI", `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
28957
|
+
this.resetTraceSession();
|
|
28847
28958
|
let shellCmd;
|
|
28848
28959
|
let shellArgs;
|
|
28849
28960
|
const useShellUnix = !isWin && (!!spawnConfig.shell || !path7.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
@@ -28869,6 +28980,14 @@ var require_dist2 = __commonJS({
|
|
|
28869
28980
|
cwd: this.workingDir,
|
|
28870
28981
|
env: buildCliSpawnEnv(process.env, spawnConfig.env)
|
|
28871
28982
|
};
|
|
28983
|
+
this.recordTrace("spawn", {
|
|
28984
|
+
shellCommand: shellCmd,
|
|
28985
|
+
shellArgs,
|
|
28986
|
+
cwd: ptyOpts.cwd,
|
|
28987
|
+
cols: ptyOpts.cols,
|
|
28988
|
+
rows: ptyOpts.rows,
|
|
28989
|
+
providerResolution: this.providerResolutionMeta
|
|
28990
|
+
});
|
|
28872
28991
|
try {
|
|
28873
28992
|
this.ptyProcess = this.transportFactory.spawn(shellCmd, shellArgs, ptyOpts);
|
|
28874
28993
|
} catch (err) {
|
|
@@ -28911,6 +29030,7 @@ var require_dist2 = __commonJS({
|
|
|
28911
29030
|
this.ptyProcess.onExit(({ exitCode }) => {
|
|
28912
29031
|
LOG2.info("CLI", `[${this.cliType}] Exit code ${exitCode}`);
|
|
28913
29032
|
this.flushPendingOutputParse();
|
|
29033
|
+
this.recordTrace("exit", { exitCode });
|
|
28914
29034
|
this.ptyProcess = null;
|
|
28915
29035
|
this.setStatus("stopped", "pty_exit");
|
|
28916
29036
|
this.ready = false;
|
|
@@ -28926,6 +29046,9 @@ var require_dist2 = __commonJS({
|
|
|
28926
29046
|
this.currentTurnScope = null;
|
|
28927
29047
|
this.ready = false;
|
|
28928
29048
|
await this.ptyProcess.ready;
|
|
29049
|
+
this.recordTrace("ready", {
|
|
29050
|
+
runtimeMeta: this.getRuntimeMetadata()
|
|
29051
|
+
});
|
|
28929
29052
|
this.setStatus("idle", "pty_ready");
|
|
28930
29053
|
this.onStatusChange?.();
|
|
28931
29054
|
}
|
|
@@ -28933,6 +29056,24 @@ var require_dist2 = __commonJS({
|
|
|
28933
29056
|
handleOutput(rawData) {
|
|
28934
29057
|
this.terminalScreen.write(rawData);
|
|
28935
29058
|
const cleanData = sanitizeTerminalText(rawData);
|
|
29059
|
+
const now = Date.now();
|
|
29060
|
+
const normalizedScreenSnapshot = normalizeScreenSnapshot(this.terminalScreen.getText());
|
|
29061
|
+
this.lastOutputAt = now;
|
|
29062
|
+
if (cleanData.trim()) this.lastNonEmptyOutputAt = now;
|
|
29063
|
+
if (normalizedScreenSnapshot !== this.lastScreenSnapshot) {
|
|
29064
|
+
this.lastScreenSnapshot = normalizedScreenSnapshot;
|
|
29065
|
+
this.lastScreenChangeAt = now;
|
|
29066
|
+
}
|
|
29067
|
+
if (this.idleFinishCandidate && (rawData.length > 0 || cleanData.length > 0)) {
|
|
29068
|
+
this.clearIdleFinishCandidate("new_output");
|
|
29069
|
+
}
|
|
29070
|
+
this.recordTrace("output", {
|
|
29071
|
+
rawLength: rawData.length,
|
|
29072
|
+
cleanLength: cleanData.length,
|
|
29073
|
+
rawPreview: this.summarizeTraceText(rawData, 300),
|
|
29074
|
+
cleanPreview: this.summarizeTraceText(cleanData, 300),
|
|
29075
|
+
screenText: this.summarizeTraceText(this.terminalScreen.getText(), 1200)
|
|
29076
|
+
});
|
|
28936
29077
|
if (this.isWaitingForResponse && cleanData) {
|
|
28937
29078
|
this.responseBuffer = (this.responseBuffer + cleanData).slice(-8e3);
|
|
28938
29079
|
}
|
|
@@ -28950,11 +29091,17 @@ var require_dist2 = __commonJS({
|
|
|
28950
29091
|
this.startupBuffer += cleanData;
|
|
28951
29092
|
const elapsed = Date.now() - this.spawnAt;
|
|
28952
29093
|
const scriptStatus = this.runDetectStatus(this.startupBuffer);
|
|
28953
|
-
const
|
|
29094
|
+
const screenText = this.terminalScreen.getText() || "";
|
|
29095
|
+
const hasInteractivePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
29096
|
+
const startupStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
29097
|
+
const isReady = (scriptStatus === "idle" || scriptStatus === "waiting_approval") && hasInteractivePrompt && startupStableMs >= 700 || elapsed > 8e3 || this.startupBuffer.length > 12e3;
|
|
28954
29098
|
if (isReady) {
|
|
28955
29099
|
this.startupParseGate = false;
|
|
28956
29100
|
this.ready = true;
|
|
28957
|
-
LOG2.info(
|
|
29101
|
+
LOG2.info(
|
|
29102
|
+
"CLI",
|
|
29103
|
+
`[${this.cliType}] Startup ready (${elapsed}ms, scriptStatus=${scriptStatus}, prompt=${hasInteractivePrompt}, stableMs=${startupStableMs}) providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
|
|
29104
|
+
);
|
|
28958
29105
|
this.onStatusChange?.();
|
|
28959
29106
|
}
|
|
28960
29107
|
}
|
|
@@ -28999,6 +29146,41 @@ var require_dist2 = __commonJS({
|
|
|
28999
29146
|
if (!text.trim()) return false;
|
|
29000
29147
|
return /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(text) || /⏎\s+send/i.test(text) || /\?\s*for\s*shortcuts/i.test(text) || /Type your message(?:\s+or\s+@path\/to\/file)?/i.test(text) || /workspace\s*\(\/directory\)/i.test(text) || /for\s*shortcuts/i.test(text);
|
|
29001
29148
|
}
|
|
29149
|
+
async waitForInteractivePrompt(maxWaitMs = 5e3) {
|
|
29150
|
+
const startedAt = Date.now();
|
|
29151
|
+
let loggedWait = false;
|
|
29152
|
+
while (Date.now() - startedAt < maxWaitMs) {
|
|
29153
|
+
const screenText = this.terminalScreen.getText() || "";
|
|
29154
|
+
const hasPrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
29155
|
+
const stableMs = this.lastScreenChangeAt ? Date.now() - this.lastScreenChangeAt : 0;
|
|
29156
|
+
const recentlyOutput = this.lastNonEmptyOutputAt ? Date.now() - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
29157
|
+
const status = this.runDetectStatus(this.recentOutputBuffer) || this.currentStatus;
|
|
29158
|
+
const startupLikelyActive = /Welcome back|Tips for getting|Recent activity|Claude Code v\d/i.test(screenText);
|
|
29159
|
+
const interactiveReady = hasPrompt && stableMs >= 700 && recentlyOutput >= 350 && status !== "starting" && status !== "generating";
|
|
29160
|
+
if (interactiveReady) {
|
|
29161
|
+
if (loggedWait) {
|
|
29162
|
+
LOG2.info(
|
|
29163
|
+
"CLI",
|
|
29164
|
+
`[${this.cliType}] Interactive prompt ready after ${Date.now() - startedAt}ms (stableMs=${stableMs}, recentOutputMs=${recentlyOutput}, startup=${startupLikelyActive})`
|
|
29165
|
+
);
|
|
29166
|
+
}
|
|
29167
|
+
return;
|
|
29168
|
+
}
|
|
29169
|
+
if (!loggedWait && Date.now() - startedAt >= 400) {
|
|
29170
|
+
loggedWait = true;
|
|
29171
|
+
LOG2.info(
|
|
29172
|
+
"CLI",
|
|
29173
|
+
`[${this.cliType}] Waiting for interactive prompt: hasPrompt=${hasPrompt} stableMs=${stableMs} recentOutputMs=${recentlyOutput} status=${status} startup=${startupLikelyActive} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)}`
|
|
29174
|
+
);
|
|
29175
|
+
}
|
|
29176
|
+
await new Promise((resolve10) => setTimeout(resolve10, 50));
|
|
29177
|
+
}
|
|
29178
|
+
const finalScreenText = this.terminalScreen.getText() || "";
|
|
29179
|
+
LOG2.warn(
|
|
29180
|
+
"CLI",
|
|
29181
|
+
`[${this.cliType}] Interactive prompt wait timed out after ${maxWaitMs}ms; proceeding with screen=${JSON.stringify(this.summarizeTraceText(finalScreenText, 240)).slice(0, 280)}`
|
|
29182
|
+
);
|
|
29183
|
+
}
|
|
29002
29184
|
evaluateSettled() {
|
|
29003
29185
|
const now = Date.now();
|
|
29004
29186
|
if (this.submitPendingUntil > now || this.responseSettleIgnoreUntil > now) {
|
|
@@ -29016,6 +29198,30 @@ var require_dist2 = __commonJS({
|
|
|
29016
29198
|
const modal = this.runParseApproval(tail);
|
|
29017
29199
|
const rawScriptStatus = this.runDetectStatus(tail);
|
|
29018
29200
|
const scriptStatus = rawScriptStatus;
|
|
29201
|
+
const parsedTranscript = this.parseCurrentTranscript(
|
|
29202
|
+
this.committedMessages,
|
|
29203
|
+
this.responseBuffer,
|
|
29204
|
+
this.currentTurnScope
|
|
29205
|
+
);
|
|
29206
|
+
const parsedMessages = Array.isArray(parsedTranscript?.messages) ? this.normalizeParsedMessages(parsedTranscript.messages) : [];
|
|
29207
|
+
const lastParsedAssistant = [...parsedMessages].reverse().find((message) => message.role === "assistant");
|
|
29208
|
+
this.recordTrace("settled", {
|
|
29209
|
+
tail: this.summarizeTraceText(tail, 500),
|
|
29210
|
+
screenText: this.summarizeTraceText(screenText, 1200),
|
|
29211
|
+
detectStatus: scriptStatus,
|
|
29212
|
+
parsedStatus: parsedTranscript?.status || null,
|
|
29213
|
+
parsedMessageCount: parsedMessages.length,
|
|
29214
|
+
parsedLastAssistant: lastParsedAssistant ? this.summarizeTraceText(lastParsedAssistant.content, 280) : "",
|
|
29215
|
+
parsedActiveModal: parsedTranscript?.activeModal ?? null,
|
|
29216
|
+
approval: modal,
|
|
29217
|
+
...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
|
|
29218
|
+
});
|
|
29219
|
+
if (this.currentTurnScope && !lastParsedAssistant) {
|
|
29220
|
+
LOG2.info(
|
|
29221
|
+
"CLI",
|
|
29222
|
+
`[${this.cliType}] Settled without assistant: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} screen=${JSON.stringify(this.summarizeTraceText(screenText, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"}`
|
|
29223
|
+
);
|
|
29224
|
+
}
|
|
29019
29225
|
if (!scriptStatus) return;
|
|
29020
29226
|
const prevStatus = this.currentStatus;
|
|
29021
29227
|
const clearPendingScriptStatus = () => {
|
|
@@ -29051,6 +29257,7 @@ var require_dist2 = __commonJS({
|
|
|
29051
29257
|
clearPendingScriptStatus();
|
|
29052
29258
|
}
|
|
29053
29259
|
if (scriptStatus === "waiting_approval") {
|
|
29260
|
+
this.clearIdleFinishCandidate("waiting_approval");
|
|
29054
29261
|
const inCooldown = this.lastApprovalResolvedAt && Date.now() - this.lastApprovalResolvedAt < this.timeouts.approvalCooldown;
|
|
29055
29262
|
const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
29056
29263
|
if ((inCooldown || visibleIdlePrompt) && !modal) {
|
|
@@ -29084,6 +29291,7 @@ var require_dist2 = __commonJS({
|
|
|
29084
29291
|
}
|
|
29085
29292
|
}
|
|
29086
29293
|
if (scriptStatus === "generating") {
|
|
29294
|
+
this.clearIdleFinishCandidate("generating");
|
|
29087
29295
|
const effectiveScreenText = screenText || this.accumulatedBuffer;
|
|
29088
29296
|
const noActiveTurn = !this.currentTurnScope;
|
|
29089
29297
|
const looksIdleChrome = /(^|\n)\s*[❯›>]\s*(?:\n|$)/m.test(effectiveScreenText) || /accept edits on/i.test(effectiveScreenText) && (/Update available!/i.test(screenText) || /\/effort/i.test(screenText) || /^.*➜\s+\S+/m.test(effectiveScreenText));
|
|
@@ -29120,13 +29328,58 @@ var require_dist2 = __commonJS({
|
|
|
29120
29328
|
this.lastApprovalResolvedAt = Date.now();
|
|
29121
29329
|
}
|
|
29122
29330
|
if (this.isWaitingForResponse) {
|
|
29331
|
+
const visibleIdlePrompt = this.looksLikeVisibleIdlePrompt(screenText);
|
|
29332
|
+
const quietForMs = this.lastNonEmptyOutputAt ? now - this.lastNonEmptyOutputAt : Number.MAX_SAFE_INTEGER;
|
|
29333
|
+
const screenStableMs = this.lastScreenChangeAt ? now - this.lastScreenChangeAt : 0;
|
|
29334
|
+
const hasAssistantTurn = !!lastParsedAssistant;
|
|
29335
|
+
const assistantLength = lastParsedAssistant?.content?.length || 0;
|
|
29336
|
+
const idleQuietThresholdMs = Math.max(220, this.timeouts.outputSettle);
|
|
29337
|
+
const idleStableThresholdMs = Math.max(120, Math.min(220, this.timeouts.outputSettle));
|
|
29338
|
+
const idleReady = visibleIdlePrompt && !modal && hasAssistantTurn && quietForMs >= idleQuietThresholdMs && screenStableMs >= idleStableThresholdMs;
|
|
29339
|
+
const candidate = this.idleFinishCandidate;
|
|
29340
|
+
const candidateQuiet = !!candidate && candidate.responseEpoch === this.responseEpoch && candidate.lastOutputAt === this.lastOutputAt && candidate.lastScreenChangeAt === this.lastScreenChangeAt && assistantLength >= candidate.assistantLength && now - candidate.armedAt >= _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS;
|
|
29341
|
+
const canFinishImmediately = idleReady && candidateQuiet;
|
|
29342
|
+
this.recordTrace("idle_decision", {
|
|
29343
|
+
visibleIdlePrompt,
|
|
29344
|
+
quietForMs,
|
|
29345
|
+
screenStableMs,
|
|
29346
|
+
hasAssistantTurn,
|
|
29347
|
+
assistantLength,
|
|
29348
|
+
hasModal: !!modal,
|
|
29349
|
+
idleQuietThresholdMs,
|
|
29350
|
+
idleStableThresholdMs,
|
|
29351
|
+
idleReady,
|
|
29352
|
+
idleFinishConfirmMs: _ProviderCliAdapter.IDLE_FINISH_CONFIRM_MS,
|
|
29353
|
+
idleFinishCandidate: candidate,
|
|
29354
|
+
candidateQuiet,
|
|
29355
|
+
canFinishImmediately,
|
|
29356
|
+
submitPendingUntil: this.submitPendingUntil,
|
|
29357
|
+
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
29358
|
+
...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
|
|
29359
|
+
});
|
|
29360
|
+
if (canFinishImmediately) {
|
|
29361
|
+
this.clearIdleFinishCandidate("finish_response");
|
|
29362
|
+
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
29363
|
+
this.finishResponse();
|
|
29364
|
+
return;
|
|
29365
|
+
}
|
|
29366
|
+
if (idleReady) {
|
|
29367
|
+
if (!candidate) {
|
|
29368
|
+
this.armIdleFinishCandidate(assistantLength);
|
|
29369
|
+
return;
|
|
29370
|
+
}
|
|
29371
|
+
} else {
|
|
29372
|
+
this.clearIdleFinishCandidate("idle_not_ready");
|
|
29373
|
+
}
|
|
29123
29374
|
if (this.idleTimeout) clearTimeout(this.idleTimeout);
|
|
29124
29375
|
this.idleTimeout = setTimeout(() => {
|
|
29125
29376
|
if (this.isWaitingForResponse && this.currentStatus !== "waiting_approval") {
|
|
29377
|
+
this.clearIdleFinishCandidate("idle_timeout_finish");
|
|
29126
29378
|
this.finishResponse();
|
|
29127
29379
|
}
|
|
29128
29380
|
}, this.timeouts.idleFinish);
|
|
29129
29381
|
} else if (prevStatus !== "idle") {
|
|
29382
|
+
this.clearIdleFinishCandidate("idle_without_response");
|
|
29130
29383
|
this.setStatus("idle", "script_detect");
|
|
29131
29384
|
this.onStatusChange?.();
|
|
29132
29385
|
}
|
|
@@ -29135,6 +29388,10 @@ var require_dist2 = __commonJS({
|
|
|
29135
29388
|
finishResponse() {
|
|
29136
29389
|
if (this.submitPendingUntil > Date.now()) return;
|
|
29137
29390
|
if (this.responseSettleIgnoreUntil > Date.now()) return;
|
|
29391
|
+
this.clearIdleFinishCandidate("finish_response_enter");
|
|
29392
|
+
this.recordTrace("finish_response", {
|
|
29393
|
+
...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
|
|
29394
|
+
});
|
|
29138
29395
|
this.commitCurrentTranscript();
|
|
29139
29396
|
if (this.responseTimeout) {
|
|
29140
29397
|
clearTimeout(this.responseTimeout);
|
|
@@ -29171,6 +29428,20 @@ var require_dist2 = __commonJS({
|
|
|
29171
29428
|
if (parsed && Array.isArray(parsed.messages)) {
|
|
29172
29429
|
this.committedMessages = this.normalizeParsedMessages(parsed.messages);
|
|
29173
29430
|
this.syncMessageViews();
|
|
29431
|
+
const lastAssistant = [...this.committedMessages].reverse().find((message) => message.role === "assistant");
|
|
29432
|
+
this.recordTrace("commit_transcript", {
|
|
29433
|
+
parsedStatus: parsed.status || null,
|
|
29434
|
+
messageCount: this.committedMessages.length,
|
|
29435
|
+
lastAssistant: lastAssistant ? this.summarizeTraceText(lastAssistant.content, 320) : "",
|
|
29436
|
+
messages: this.summarizeTraceMessages(this.committedMessages),
|
|
29437
|
+
...this.buildTraceParseSnapshot(this.currentTurnScope, this.responseBuffer)
|
|
29438
|
+
});
|
|
29439
|
+
if (!lastAssistant && this.currentTurnScope) {
|
|
29440
|
+
LOG2.warn(
|
|
29441
|
+
"CLI",
|
|
29442
|
+
`[${this.cliType}] Commit without assistant turn: prompt=${JSON.stringify(this.currentTurnScope.prompt).slice(0, 140)} responseBuffer=${JSON.stringify(this.summarizeTraceText(this.responseBuffer, 220)).slice(0, 260)} providerDir=${this.providerResolutionMeta.providerDir || "-"} scriptDir=${this.providerResolutionMeta.scriptDir || "-"} scriptsPath=${this.providerResolutionMeta.scriptsPath || "-"}`
|
|
29443
|
+
);
|
|
29444
|
+
}
|
|
29174
29445
|
}
|
|
29175
29446
|
}
|
|
29176
29447
|
// ─── Script Execution ──────────────────────────
|
|
@@ -29294,16 +29565,23 @@ ${data.message || ""}`.trim();
|
|
|
29294
29565
|
}
|
|
29295
29566
|
if (!this.ready) throw new Error(`${this.cliName} not ready (status: ${this.currentStatus})`);
|
|
29296
29567
|
if (this.isWaitingForResponse) return;
|
|
29568
|
+
await this.waitForInteractivePrompt();
|
|
29297
29569
|
this.committedMessages.push({ role: "user", content: text, timestamp: Date.now() });
|
|
29298
29570
|
this.syncMessageViews();
|
|
29299
29571
|
this.isWaitingForResponse = true;
|
|
29300
29572
|
this.responseBuffer = "";
|
|
29573
|
+
this.clearIdleFinishCandidate("send_message");
|
|
29301
29574
|
this.currentTurnScope = {
|
|
29302
29575
|
prompt: text,
|
|
29303
29576
|
startedAt: Date.now(),
|
|
29304
29577
|
bufferStart: this.accumulatedBuffer.length,
|
|
29305
29578
|
rawBufferStart: this.accumulatedRawBuffer.length
|
|
29306
29579
|
};
|
|
29580
|
+
this.recordTrace("send_message", {
|
|
29581
|
+
text: this.summarizeTraceText(text, 500),
|
|
29582
|
+
estimatedLines: estimatePromptDisplayLines(text),
|
|
29583
|
+
turnScope: this.currentTurnScope
|
|
29584
|
+
});
|
|
29307
29585
|
LOG2.info("CLI", `[${this.cliType}] sendMessage turn scope buffer=${this.currentTurnScope.bufferStart} raw=${this.currentTurnScope.rawBufferStart} prompt=${JSON.stringify(text).slice(0, 120)}`);
|
|
29308
29586
|
this.submitRetryUsed = false;
|
|
29309
29587
|
this.submitRetryPromptSnippet = extractPromptRetrySnippet(text);
|
|
@@ -29333,6 +29611,11 @@ ${data.message || ""}`.trim();
|
|
|
29333
29611
|
const submit = () => {
|
|
29334
29612
|
if (!this.ptyProcess) return;
|
|
29335
29613
|
this.submitPendingUntil = 0;
|
|
29614
|
+
this.recordTrace("submit_write", {
|
|
29615
|
+
mode: "submit_key",
|
|
29616
|
+
sendKey: this.sendKey,
|
|
29617
|
+
screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
|
|
29618
|
+
});
|
|
29336
29619
|
this.ptyProcess.write(this.sendKey);
|
|
29337
29620
|
const retrySubmitIfStuck = (attempt) => {
|
|
29338
29621
|
this.submitRetryTimer = null;
|
|
@@ -29344,6 +29627,12 @@ ${data.message || ""}`.trim();
|
|
|
29344
29627
|
if (/Esc to interrupt|Do you want to proceed|This command requires approval|Allow Codex to|Approve and run now|Always approve this session|Running…|Running\.\.\./i.test(screenText)) return;
|
|
29345
29628
|
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
29346
29629
|
LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt ${attempt})`);
|
|
29630
|
+
this.recordTrace("submit_write", {
|
|
29631
|
+
mode: "submit_retry",
|
|
29632
|
+
attempt,
|
|
29633
|
+
sendKey: this.sendKey,
|
|
29634
|
+
screenText: this.summarizeTraceText(screenText, 500)
|
|
29635
|
+
});
|
|
29347
29636
|
this.ptyProcess.write(this.sendKey);
|
|
29348
29637
|
if (attempt >= 3) {
|
|
29349
29638
|
this.submitRetryUsed = true;
|
|
@@ -29356,6 +29645,12 @@ ${data.message || ""}`.trim();
|
|
|
29356
29645
|
};
|
|
29357
29646
|
if (this.submitStrategy === "immediate") {
|
|
29358
29647
|
this.submitPendingUntil = 0;
|
|
29648
|
+
this.recordTrace("submit_write", {
|
|
29649
|
+
mode: "immediate",
|
|
29650
|
+
text: this.summarizeTraceText(text, 500),
|
|
29651
|
+
sendKey: this.sendKey,
|
|
29652
|
+
screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
|
|
29653
|
+
});
|
|
29359
29654
|
this.ptyProcess.write(text + this.sendKey);
|
|
29360
29655
|
this.submitRetryTimer = setTimeout(() => {
|
|
29361
29656
|
this.submitRetryTimer = null;
|
|
@@ -29366,6 +29661,12 @@ ${data.message || ""}`.trim();
|
|
|
29366
29661
|
if (!promptLikelyVisible(screenText, normalizedPromptSnippet)) return;
|
|
29367
29662
|
LOG2.info("CLI", `[${this.cliType}] Retrying submit key for stuck prompt (attempt 1)`);
|
|
29368
29663
|
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
29664
|
+
this.recordTrace("submit_write", {
|
|
29665
|
+
mode: "immediate_retry",
|
|
29666
|
+
attempt: 1,
|
|
29667
|
+
sendKey: this.sendKey,
|
|
29668
|
+
screenText: this.summarizeTraceText(screenText, 500)
|
|
29669
|
+
});
|
|
29369
29670
|
this.ptyProcess.write(this.sendKey);
|
|
29370
29671
|
this.submitRetryUsed = true;
|
|
29371
29672
|
}, retryDelayMs);
|
|
@@ -29376,6 +29677,12 @@ ${data.message || ""}`.trim();
|
|
|
29376
29677
|
this.submitPendingUntil = Date.now() + submitDelayMs;
|
|
29377
29678
|
}
|
|
29378
29679
|
this.ptyProcess.write(text);
|
|
29680
|
+
this.recordTrace("submit_write", {
|
|
29681
|
+
mode: "type_then_submit",
|
|
29682
|
+
text: this.summarizeTraceText(text, 500),
|
|
29683
|
+
sendKey: this.sendKey,
|
|
29684
|
+
screenText: this.summarizeTraceText(this.terminalScreen.getText(), 500)
|
|
29685
|
+
});
|
|
29379
29686
|
const submitStartedAt = Date.now();
|
|
29380
29687
|
let lastNormalizedScreen = "";
|
|
29381
29688
|
let lastScreenChangeAt = submitStartedAt;
|
|
@@ -29476,6 +29783,7 @@ ${data.message || ""}`.trim();
|
|
|
29476
29783
|
});
|
|
29477
29784
|
}
|
|
29478
29785
|
shutdown() {
|
|
29786
|
+
this.clearIdleFinishCandidate("shutdown");
|
|
29479
29787
|
if (this.settleTimer) {
|
|
29480
29788
|
clearTimeout(this.settleTimer);
|
|
29481
29789
|
this.settleTimer = null;
|
|
@@ -29516,6 +29824,7 @@ ${data.message || ""}`.trim();
|
|
|
29516
29824
|
}
|
|
29517
29825
|
}
|
|
29518
29826
|
detach() {
|
|
29827
|
+
this.clearIdleFinishCandidate("detach");
|
|
29519
29828
|
if (this.settleTimer) {
|
|
29520
29829
|
clearTimeout(this.settleTimer);
|
|
29521
29830
|
this.settleTimer = null;
|
|
@@ -29556,6 +29865,7 @@ ${data.message || ""}`.trim();
|
|
|
29556
29865
|
this.onStatusChange?.();
|
|
29557
29866
|
}
|
|
29558
29867
|
clearHistory() {
|
|
29868
|
+
this.clearIdleFinishCandidate("clear_history");
|
|
29559
29869
|
this.committedMessages = [];
|
|
29560
29870
|
this.syncMessageViews();
|
|
29561
29871
|
this.accumulatedBuffer = "";
|
|
@@ -29585,10 +29895,19 @@ ${data.message || ""}`.trim();
|
|
|
29585
29895
|
return this.ready;
|
|
29586
29896
|
}
|
|
29587
29897
|
writeRaw(data) {
|
|
29898
|
+
this.recordTrace("write_raw", {
|
|
29899
|
+
keys: JSON.stringify(data),
|
|
29900
|
+
length: data.length
|
|
29901
|
+
});
|
|
29588
29902
|
this.ptyProcess?.write(data);
|
|
29589
29903
|
}
|
|
29590
29904
|
resolveModal(buttonIndex) {
|
|
29591
29905
|
if (!this.ptyProcess || this.currentStatus !== "waiting_approval" && !this.activeModal) return;
|
|
29906
|
+
this.clearIdleFinishCandidate("resolve_modal");
|
|
29907
|
+
this.recordTrace("resolve_modal", {
|
|
29908
|
+
buttonIndex,
|
|
29909
|
+
activeModal: this.activeModal
|
|
29910
|
+
});
|
|
29592
29911
|
this.activeModal = null;
|
|
29593
29912
|
this.lastApprovalResolvedAt = Date.now();
|
|
29594
29913
|
this.responseSettleIgnoreUntil = Date.now() + this.timeouts.outputSettle + 400;
|
|
@@ -29620,6 +29939,7 @@ ${data.message || ""}`.trim();
|
|
|
29620
29939
|
return {
|
|
29621
29940
|
type: this.cliType,
|
|
29622
29941
|
name: this.cliName,
|
|
29942
|
+
providerResolution: this.providerResolutionMeta,
|
|
29623
29943
|
status: this.currentStatus,
|
|
29624
29944
|
ready: this.ready,
|
|
29625
29945
|
startupParseGate: this.startupParseGate,
|
|
@@ -29639,6 +29959,10 @@ ${data.message || ""}`.trim();
|
|
|
29639
29959
|
rawBufferPreview: this.accumulatedRawBuffer.slice(-1e3),
|
|
29640
29960
|
sanitizedRawPreview: sanitizeTerminalText(this.accumulatedRawBuffer).slice(-1e3),
|
|
29641
29961
|
responseBuffer: this.responseBuffer.slice(-1e3),
|
|
29962
|
+
lastOutputAt: this.lastOutputAt,
|
|
29963
|
+
lastNonEmptyOutputAt: this.lastNonEmptyOutputAt,
|
|
29964
|
+
lastScreenChangeAt: this.lastScreenChangeAt,
|
|
29965
|
+
lastScreenSnapshot: this.lastScreenSnapshot.slice(-500),
|
|
29642
29966
|
isWaitingForResponse: this.isWaitingForResponse,
|
|
29643
29967
|
activeModal: this.activeModal,
|
|
29644
29968
|
lastApprovalResolvedAt: this.lastApprovalResolvedAt,
|
|
@@ -29650,6 +29974,8 @@ ${data.message || ""}`.trim();
|
|
|
29650
29974
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
29651
29975
|
hasCliScripts: this.hasCliScripts(),
|
|
29652
29976
|
scriptNames: Object.keys(this.cliScripts).filter((k) => typeof this.cliScripts[k] === "function"),
|
|
29977
|
+
traceSessionId: this.traceSessionId,
|
|
29978
|
+
traceEntryCount: this.traceEntries.length,
|
|
29653
29979
|
statusHistory: this.statusHistory.slice(-30),
|
|
29654
29980
|
timeouts: this.timeouts,
|
|
29655
29981
|
pendingOutputParseBufferLength: this.pendingOutputParseBuffer.length,
|
|
@@ -29657,6 +29983,25 @@ ${data.message || ""}`.trim();
|
|
|
29657
29983
|
ptyAlive: !!this.ptyProcess
|
|
29658
29984
|
};
|
|
29659
29985
|
}
|
|
29986
|
+
getTraceState(limit = 120) {
|
|
29987
|
+
const cappedLimit = Math.max(1, Math.min(500, Number.isFinite(limit) ? Math.floor(limit) : 120));
|
|
29988
|
+
return {
|
|
29989
|
+
sessionId: this.traceSessionId,
|
|
29990
|
+
providerResolution: this.providerResolutionMeta,
|
|
29991
|
+
entryCount: this.traceEntries.length,
|
|
29992
|
+
entries: this.traceEntries.slice(-cappedLimit),
|
|
29993
|
+
screenText: this.summarizeTraceText(this.terminalScreen.getText(), 4e3),
|
|
29994
|
+
recentOutputBuffer: this.summarizeTraceText(this.recentOutputBuffer, 1e3),
|
|
29995
|
+
responseBuffer: this.summarizeTraceText(this.responseBuffer, 1200),
|
|
29996
|
+
status: this.currentStatus,
|
|
29997
|
+
activeModal: this.activeModal,
|
|
29998
|
+
currentTurnScope: this.currentTurnScope,
|
|
29999
|
+
messages: this.summarizeTraceMessages(this.committedMessages, 5)
|
|
30000
|
+
};
|
|
30001
|
+
}
|
|
30002
|
+
getProviderResolutionMeta() {
|
|
30003
|
+
return { ...this.providerResolutionMeta };
|
|
30004
|
+
}
|
|
29660
30005
|
respondToTerminalQueries(data) {
|
|
29661
30006
|
if (!this.ptyProcess || !data) return;
|
|
29662
30007
|
const combined = this.pendingTerminalQueryTail + data;
|
|
@@ -29752,22 +30097,22 @@ ${data.message || ""}`.trim();
|
|
|
29752
30097
|
});
|
|
29753
30098
|
module2.exports = __toCommonJS2(index_exports);
|
|
29754
30099
|
init_config();
|
|
29755
|
-
var
|
|
29756
|
-
var
|
|
30100
|
+
var fs4 = __toESM2(require("fs"));
|
|
30101
|
+
var os6 = __toESM2(require("os"));
|
|
29757
30102
|
var path5 = __toESM2(require("path"));
|
|
29758
30103
|
var import_crypto22 = require("crypto");
|
|
29759
30104
|
var MAX_WORKSPACES = 50;
|
|
29760
30105
|
function expandPath(p) {
|
|
29761
30106
|
const t = (p || "").trim();
|
|
29762
30107
|
if (!t) return "";
|
|
29763
|
-
if (t.startsWith("~")) return path5.join(
|
|
30108
|
+
if (t.startsWith("~")) return path5.join(os6.homedir(), t.slice(1).replace(/^\//, ""));
|
|
29764
30109
|
return path5.resolve(t);
|
|
29765
30110
|
}
|
|
29766
30111
|
function validateWorkspacePath(absPath) {
|
|
29767
30112
|
try {
|
|
29768
30113
|
if (!absPath) return { ok: false, error: "Path required" };
|
|
29769
|
-
if (!
|
|
29770
|
-
const st2 =
|
|
30114
|
+
if (!fs4.existsSync(absPath)) return { ok: false, error: "Path does not exist" };
|
|
30115
|
+
const st2 = fs4.statSync(absPath);
|
|
29771
30116
|
if (!st2.isDirectory()) return { ok: false, error: "Not a directory" };
|
|
29772
30117
|
return { ok: true };
|
|
29773
30118
|
} catch (e) {
|
|
@@ -29833,7 +30178,7 @@ ${data.message || ""}`.trim();
|
|
|
29833
30178
|
};
|
|
29834
30179
|
}
|
|
29835
30180
|
if (a.useHome === true) {
|
|
29836
|
-
return { ok: true, path:
|
|
30181
|
+
return { ok: true, path: os6.homedir(), source: "home" };
|
|
29837
30182
|
}
|
|
29838
30183
|
return {
|
|
29839
30184
|
ok: false,
|
|
@@ -29874,9 +30219,9 @@ ${data.message || ""}`.trim();
|
|
|
29874
30219
|
const abs = expandPath(rawPath);
|
|
29875
30220
|
const createIfMissing = options?.createIfMissing === true;
|
|
29876
30221
|
if (!abs) return { error: "Path required" };
|
|
29877
|
-
if (!
|
|
30222
|
+
if (!fs4.existsSync(abs) && createIfMissing) {
|
|
29878
30223
|
try {
|
|
29879
|
-
|
|
30224
|
+
fs4.mkdirSync(abs, { recursive: true });
|
|
29880
30225
|
} catch (e) {
|
|
29881
30226
|
return { error: e?.message || "Could not create directory" };
|
|
29882
30227
|
}
|
|
@@ -31824,6 +32169,7 @@ ${data.message || ""}`.trim();
|
|
|
31824
32169
|
role: msg.role,
|
|
31825
32170
|
content: msg.content || "",
|
|
31826
32171
|
kind: typeof msg.kind === "string" ? msg.kind : void 0,
|
|
32172
|
+
senderName: typeof msg.senderName === "string" ? msg.senderName : void 0,
|
|
31827
32173
|
agent: agentType,
|
|
31828
32174
|
instanceId,
|
|
31829
32175
|
historySessionId: effectiveHistoryKey,
|
|
@@ -31862,6 +32208,7 @@ ${data.message || ""}`.trim();
|
|
|
31862
32208
|
kind: "system",
|
|
31863
32209
|
content,
|
|
31864
32210
|
receivedAt: options.receivedAt,
|
|
32211
|
+
senderName: options.senderName,
|
|
31865
32212
|
historyDedupKey: options.dedupKey
|
|
31866
32213
|
}],
|
|
31867
32214
|
options.sessionTitle,
|
|
@@ -33192,6 +33539,12 @@ ${data.message || ""}`.trim();
|
|
|
33192
33539
|
function getTargetedCliAdapter(h, args, providerType) {
|
|
33193
33540
|
return h.getCliAdapter(args?.targetSessionId || providerType || h.currentSession?.providerType || h.currentManagerKey);
|
|
33194
33541
|
}
|
|
33542
|
+
function getTargetInstance(h, args) {
|
|
33543
|
+
const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
|
|
33544
|
+
const sessionId = targetSessionId || h.currentSession?.sessionId || "";
|
|
33545
|
+
if (!sessionId) return null;
|
|
33546
|
+
return h.ctx.instanceManager?.getInstance(sessionId);
|
|
33547
|
+
}
|
|
33195
33548
|
function getTargetTransport(h, provider) {
|
|
33196
33549
|
if (h.currentSession?.transport) return h.currentSession.transport;
|
|
33197
33550
|
switch (provider?.category) {
|
|
@@ -33934,6 +34287,7 @@ ${data.message || ""}`.trim();
|
|
|
33934
34287
|
adapter.writeRaw?.(keys);
|
|
33935
34288
|
}
|
|
33936
34289
|
LOG2.info("Command", `[resolveAction] CLI PTY \u2192 buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}"`);
|
|
34290
|
+
getTargetInstance(h, args)?.recordApprovalSelection?.(buttons[buttonIndex] ?? button);
|
|
33937
34291
|
return { success: true, buttonIndex, button: buttons[buttonIndex] ?? button };
|
|
33938
34292
|
}
|
|
33939
34293
|
if (isExtensionTransport(transport) && h.agentStream && h.getCdp() && h.currentSession?.sessionId) {
|
|
@@ -34015,9 +34369,9 @@ ${data.message || ""}`.trim();
|
|
|
34015
34369
|
}
|
|
34016
34370
|
return { success: false, error: "resolveAction script not available for this provider" };
|
|
34017
34371
|
}
|
|
34018
|
-
var
|
|
34372
|
+
var fs42 = __toESM2(require("fs"));
|
|
34019
34373
|
var path6 = __toESM2(require("path"));
|
|
34020
|
-
var
|
|
34374
|
+
var os62 = __toESM2(require("os"));
|
|
34021
34375
|
var KEY_TO_VK = {
|
|
34022
34376
|
Backspace: 8,
|
|
34023
34377
|
Tab: 9,
|
|
@@ -34244,7 +34598,7 @@ ${data.message || ""}`.trim();
|
|
|
34244
34598
|
return { success: true, agents };
|
|
34245
34599
|
}
|
|
34246
34600
|
function resolveSafePath(requestedPath) {
|
|
34247
|
-
const home =
|
|
34601
|
+
const home = os62.homedir();
|
|
34248
34602
|
let resolved;
|
|
34249
34603
|
if (requestedPath.startsWith("~")) {
|
|
34250
34604
|
resolved = path6.join(home, requestedPath.slice(1));
|
|
@@ -34258,7 +34612,7 @@ ${data.message || ""}`.trim();
|
|
|
34258
34612
|
async function handleFileRead(h, args) {
|
|
34259
34613
|
try {
|
|
34260
34614
|
const filePath = resolveSafePath(args?.path);
|
|
34261
|
-
const content =
|
|
34615
|
+
const content = fs42.readFileSync(filePath, "utf-8");
|
|
34262
34616
|
return { success: true, content, path: filePath };
|
|
34263
34617
|
} catch (e) {
|
|
34264
34618
|
return { success: false, error: e.message };
|
|
@@ -34267,8 +34621,8 @@ ${data.message || ""}`.trim();
|
|
|
34267
34621
|
async function handleFileWrite(h, args) {
|
|
34268
34622
|
try {
|
|
34269
34623
|
const filePath = resolveSafePath(args?.path);
|
|
34270
|
-
|
|
34271
|
-
|
|
34624
|
+
fs42.mkdirSync(path6.dirname(filePath), { recursive: true });
|
|
34625
|
+
fs42.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
34272
34626
|
return { success: true, path: filePath };
|
|
34273
34627
|
} catch (e) {
|
|
34274
34628
|
return { success: false, error: e.message };
|
|
@@ -34277,11 +34631,11 @@ ${data.message || ""}`.trim();
|
|
|
34277
34631
|
async function handleFileList(h, args) {
|
|
34278
34632
|
try {
|
|
34279
34633
|
const dirPath = resolveSafePath(args?.path || ".");
|
|
34280
|
-
const entries =
|
|
34634
|
+
const entries = fs42.readdirSync(dirPath, { withFileTypes: true });
|
|
34281
34635
|
const files = entries.map((e) => ({
|
|
34282
34636
|
name: e.name,
|
|
34283
34637
|
type: e.isDirectory() ? "directory" : "file",
|
|
34284
|
-
size: e.isFile() ?
|
|
34638
|
+
size: e.isFile() ? fs42.statSync(path6.join(dirPath, e.name)).size : void 0
|
|
34285
34639
|
}));
|
|
34286
34640
|
return { success: true, files, path: dirPath };
|
|
34287
34641
|
} catch (e) {
|
|
@@ -35095,6 +35449,7 @@ ${data.message || ""}`.trim();
|
|
|
35095
35449
|
generatingDebouncePending = null;
|
|
35096
35450
|
lastApprovalEventAt = 0;
|
|
35097
35451
|
historyWriter;
|
|
35452
|
+
runtimeMessages = [];
|
|
35098
35453
|
instanceId;
|
|
35099
35454
|
presentationMode;
|
|
35100
35455
|
providerSessionId;
|
|
@@ -35157,6 +35512,7 @@ ${data.message || ""}`.trim();
|
|
|
35157
35512
|
}
|
|
35158
35513
|
const runtime = this.adapter.getRuntimeMetadata();
|
|
35159
35514
|
const parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
|
|
35515
|
+
const mergedMessages = this.mergeConversationMessages(parsedMessages);
|
|
35160
35516
|
const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
|
|
35161
35517
|
if (parsedMessages.length > 0) {
|
|
35162
35518
|
let messagesToSave = parsedMessages;
|
|
@@ -35186,7 +35542,7 @@ ${data.message || ""}`.trim();
|
|
|
35186
35542
|
id: `${this.type}_${this.workingDir}`,
|
|
35187
35543
|
title: parsedStatus?.title || dirName,
|
|
35188
35544
|
status: parsedStatus?.status || adapterStatus.status,
|
|
35189
|
-
messages:
|
|
35545
|
+
messages: mergedMessages,
|
|
35190
35546
|
activeModal: parsedStatus?.activeModal ?? adapterStatus.activeModal,
|
|
35191
35547
|
inputContent: ""
|
|
35192
35548
|
},
|
|
@@ -35285,6 +35641,11 @@ ${data.message || ""}`.trim();
|
|
|
35285
35641
|
const approvalCooldown = 5e3;
|
|
35286
35642
|
if (this.lastStatus !== "waiting_approval" && (!this.lastApprovalEventAt || now - this.lastApprovalEventAt > approvalCooldown)) {
|
|
35287
35643
|
this.lastApprovalEventAt = now;
|
|
35644
|
+
this.appendRuntimeSystemMessage(
|
|
35645
|
+
this.formatApprovalRequestMessage(modal?.message, modal?.buttons),
|
|
35646
|
+
`approval_request:${now}`,
|
|
35647
|
+
now
|
|
35648
|
+
);
|
|
35288
35649
|
this.pushEvent({
|
|
35289
35650
|
event: "agent:waiting_approval",
|
|
35290
35651
|
chatTitle,
|
|
@@ -35356,11 +35717,71 @@ ${data.message || ""}`.trim();
|
|
|
35356
35717
|
get cliName() {
|
|
35357
35718
|
return this.provider.name;
|
|
35358
35719
|
}
|
|
35720
|
+
recordApprovalSelection(buttonText) {
|
|
35721
|
+
const cleanButton = String(buttonText || "").trim();
|
|
35722
|
+
if (!cleanButton) return;
|
|
35723
|
+
const now = Date.now();
|
|
35724
|
+
this.appendRuntimeSystemMessage(
|
|
35725
|
+
`Approval selected: ${cleanButton}`,
|
|
35726
|
+
`approval_selection:${now}:${cleanButton}`,
|
|
35727
|
+
now
|
|
35728
|
+
);
|
|
35729
|
+
}
|
|
35359
35730
|
formatMarkerTimestamp(timestamp) {
|
|
35360
35731
|
const date5 = new Date(timestamp);
|
|
35361
35732
|
const pad = (value) => String(value).padStart(2, "0");
|
|
35362
35733
|
return `${date5.getFullYear()}-${pad(date5.getMonth() + 1)}-${pad(date5.getDate())} ${pad(date5.getHours())}:${pad(date5.getMinutes())}:${pad(date5.getSeconds())}`;
|
|
35363
35734
|
}
|
|
35735
|
+
appendRuntimeSystemMessage(content, dedupKey, receivedAt = Date.now()) {
|
|
35736
|
+
const normalizedContent = String(content || "").trim();
|
|
35737
|
+
if (!normalizedContent) return;
|
|
35738
|
+
if (this.runtimeMessages.some((entry) => entry.key === dedupKey)) return;
|
|
35739
|
+
this.runtimeMessages.push({
|
|
35740
|
+
key: dedupKey,
|
|
35741
|
+
message: {
|
|
35742
|
+
role: "system",
|
|
35743
|
+
senderName: "System",
|
|
35744
|
+
content: normalizedContent,
|
|
35745
|
+
receivedAt,
|
|
35746
|
+
timestamp: receivedAt
|
|
35747
|
+
}
|
|
35748
|
+
});
|
|
35749
|
+
if (this.runtimeMessages.length > 50) {
|
|
35750
|
+
this.runtimeMessages = this.runtimeMessages.slice(-50);
|
|
35751
|
+
}
|
|
35752
|
+
this.historyWriter.appendNewMessages(
|
|
35753
|
+
this.type,
|
|
35754
|
+
[{
|
|
35755
|
+
role: "system",
|
|
35756
|
+
senderName: "System",
|
|
35757
|
+
content: normalizedContent,
|
|
35758
|
+
receivedAt,
|
|
35759
|
+
historyDedupKey: dedupKey
|
|
35760
|
+
}],
|
|
35761
|
+
this.adapter.getScriptParsedStatus?.()?.title || this.workingDir.split("/").filter(Boolean).pop() || "session",
|
|
35762
|
+
this.instanceId,
|
|
35763
|
+
this.providerSessionId
|
|
35764
|
+
);
|
|
35765
|
+
}
|
|
35766
|
+
mergeConversationMessages(parsedMessages) {
|
|
35767
|
+
if (this.runtimeMessages.length === 0) return parsedMessages;
|
|
35768
|
+
return [...parsedMessages, ...this.runtimeMessages.map((entry) => entry.message)].map((message, index) => ({ message, index })).sort((a, b2) => {
|
|
35769
|
+
const aTime = a.message.receivedAt || a.message.timestamp || 0;
|
|
35770
|
+
const bTime = b2.message.receivedAt || b2.message.timestamp || 0;
|
|
35771
|
+
if (aTime !== bTime) return aTime - bTime;
|
|
35772
|
+
return a.index - b2.index;
|
|
35773
|
+
}).map((entry) => entry.message);
|
|
35774
|
+
}
|
|
35775
|
+
formatApprovalRequestMessage(modalMessage, buttons) {
|
|
35776
|
+
const lines = ["Approval requested"];
|
|
35777
|
+
const cleanMessage = String(modalMessage || "").trim();
|
|
35778
|
+
if (cleanMessage) lines.push(cleanMessage);
|
|
35779
|
+
const labels = (buttons || []).map((button) => String(button || "").trim()).filter(Boolean);
|
|
35780
|
+
if (labels.length > 0) {
|
|
35781
|
+
lines.push(labels.map((label) => `[${label}]`).join(" "));
|
|
35782
|
+
}
|
|
35783
|
+
return lines.join("\n");
|
|
35784
|
+
}
|
|
35364
35785
|
promoteProviderSessionId(sessionId) {
|
|
35365
35786
|
const nextSessionId = String(sessionId || "").trim();
|
|
35366
35787
|
if (!nextSessionId || nextSessionId === this.providerSessionId) return;
|
|
@@ -37364,6 +37785,7 @@ ${installInfo}`
|
|
|
37364
37785
|
resolve(type, context) {
|
|
37365
37786
|
const base = this.providers.get(type);
|
|
37366
37787
|
if (!base) return void 0;
|
|
37788
|
+
const providerDir = this.findProviderDirInternal(type) || void 0;
|
|
37367
37789
|
const currentOs = context?.os || process.platform;
|
|
37368
37790
|
const currentVersion = context?.version ?? this.versionArchive?.getLatest(type) ?? void 0;
|
|
37369
37791
|
const resolved = JSON.parse(JSON.stringify(base));
|
|
@@ -37373,6 +37795,9 @@ ${installInfo}`
|
|
|
37373
37795
|
if (base.scripts) {
|
|
37374
37796
|
resolved.scripts = { ...base.scripts };
|
|
37375
37797
|
}
|
|
37798
|
+
if (providerDir) {
|
|
37799
|
+
resolved._resolvedProviderDir = providerDir;
|
|
37800
|
+
}
|
|
37376
37801
|
if (base.os?.[currentOs]) {
|
|
37377
37802
|
const osOverride = base.os[currentOs];
|
|
37378
37803
|
if (osOverride.scripts) {
|
|
@@ -37393,6 +37818,12 @@ ${installInfo}`
|
|
|
37393
37818
|
if (loaded) {
|
|
37394
37819
|
resolved.scripts = loaded;
|
|
37395
37820
|
this.log(` [compatibility] ${type} v${currentVersion} \u2192 ${entry.scriptDir}`);
|
|
37821
|
+
resolved._resolvedScriptDir = entry.scriptDir;
|
|
37822
|
+
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
37823
|
+
if (providerDir) {
|
|
37824
|
+
const fullDir = path10.join(providerDir, entry.scriptDir);
|
|
37825
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
|
|
37826
|
+
}
|
|
37396
37827
|
matched = true;
|
|
37397
37828
|
}
|
|
37398
37829
|
break;
|
|
@@ -37403,6 +37834,12 @@ ${installInfo}`
|
|
|
37403
37834
|
if (loaded) {
|
|
37404
37835
|
resolved.scripts = loaded;
|
|
37405
37836
|
this.log(` [compatibility] ${type} v${currentVersion} \u2192 default: ${base.defaultScriptDir}`);
|
|
37837
|
+
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
37838
|
+
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
37839
|
+
if (providerDir) {
|
|
37840
|
+
const fullDir = path10.join(providerDir, base.defaultScriptDir);
|
|
37841
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
|
|
37842
|
+
}
|
|
37406
37843
|
}
|
|
37407
37844
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
37408
37845
|
}
|
|
@@ -37415,6 +37852,12 @@ ${installInfo}`
|
|
|
37415
37852
|
if (loaded) {
|
|
37416
37853
|
resolved.scripts = loaded;
|
|
37417
37854
|
this.log(` [version override] ${type} ${range} \u2192 ${dirOverride}`);
|
|
37855
|
+
resolved._resolvedScriptDir = dirOverride;
|
|
37856
|
+
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
37857
|
+
if (providerDir) {
|
|
37858
|
+
const fullDir = path10.join(providerDir, dirOverride);
|
|
37859
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
|
|
37860
|
+
}
|
|
37418
37861
|
}
|
|
37419
37862
|
} else if (override.scripts) {
|
|
37420
37863
|
resolved.scripts = { ...resolved.scripts, ...override.scripts };
|
|
@@ -37426,6 +37869,12 @@ ${installInfo}`
|
|
|
37426
37869
|
if (loaded) {
|
|
37427
37870
|
resolved.scripts = loaded;
|
|
37428
37871
|
this.log(` [compatibility] ${type} no version detected \u2192 default: ${base.defaultScriptDir}`);
|
|
37872
|
+
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
37873
|
+
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
37874
|
+
if (providerDir) {
|
|
37875
|
+
const fullDir = path10.join(providerDir, base.defaultScriptDir);
|
|
37876
|
+
resolved._resolvedScriptsPath = fs6.existsSync(path10.join(fullDir, "scripts.js")) ? path10.join(fullDir, "scripts.js") : fullDir;
|
|
37877
|
+
}
|
|
37429
37878
|
}
|
|
37430
37879
|
}
|
|
37431
37880
|
if (base.overrides) {
|
|
@@ -37494,6 +37943,9 @@ ${installInfo}`
|
|
|
37494
37943
|
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
37495
37944
|
});
|
|
37496
37945
|
const handleChange = (filePath) => {
|
|
37946
|
+
if (/[\/\\]fixtures[\/\\]/.test(filePath)) {
|
|
37947
|
+
return;
|
|
37948
|
+
}
|
|
37497
37949
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
37498
37950
|
this.log(`File changed: ${path10.basename(filePath)}, reloading...`);
|
|
37499
37951
|
this.reload();
|
|
@@ -38184,7 +38636,7 @@ ${installInfo}`
|
|
|
38184
38636
|
}
|
|
38185
38637
|
} else if (plat === "win32") {
|
|
38186
38638
|
try {
|
|
38187
|
-
const
|
|
38639
|
+
const fs15 = require("fs");
|
|
38188
38640
|
const appNameMap = getMacAppIdentifiers();
|
|
38189
38641
|
const appName = appNameMap[ideId];
|
|
38190
38642
|
if (appName) {
|
|
@@ -38193,8 +38645,8 @@ ${installInfo}`
|
|
|
38193
38645
|
appName,
|
|
38194
38646
|
"storage.json"
|
|
38195
38647
|
);
|
|
38196
|
-
if (
|
|
38197
|
-
const data = JSON.parse(
|
|
38648
|
+
if (fs15.existsSync(storagePath)) {
|
|
38649
|
+
const data = JSON.parse(fs15.readFileSync(storagePath, "utf-8"));
|
|
38198
38650
|
const workspaces = data?.openedPathsList?.workspaces3 || data?.openedPathsList?.entries || [];
|
|
38199
38651
|
if (workspaces.length > 0) {
|
|
38200
38652
|
const recent = workspaces[0];
|
|
@@ -38654,7 +39106,7 @@ ${installInfo}`
|
|
|
38654
39106
|
function getNpmExecutable() {
|
|
38655
39107
|
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
38656
39108
|
}
|
|
38657
|
-
function
|
|
39109
|
+
function killPid2(pid) {
|
|
38658
39110
|
try {
|
|
38659
39111
|
if (process.platform === "win32") {
|
|
38660
39112
|
(0, import_child_process7.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
@@ -38683,7 +39135,7 @@ ${installInfo}`
|
|
|
38683
39135
|
if (fs8.existsSync(pidFile)) {
|
|
38684
39136
|
const pid = Number.parseInt(fs8.readFileSync(pidFile, "utf8").trim(), 10);
|
|
38685
39137
|
if (Number.isFinite(pid)) {
|
|
38686
|
-
|
|
39138
|
+
killPid2(pid);
|
|
38687
39139
|
}
|
|
38688
39140
|
}
|
|
38689
39141
|
} catch {
|
|
@@ -38699,7 +39151,7 @@ ${installInfo}`
|
|
|
38699
39151
|
for (const line of raw.split("\n")) {
|
|
38700
39152
|
const pid = Number.parseInt(line.trim(), 10);
|
|
38701
39153
|
if (Number.isFinite(pid)) {
|
|
38702
|
-
|
|
39154
|
+
killPid2(pid);
|
|
38703
39155
|
}
|
|
38704
39156
|
}
|
|
38705
39157
|
} catch {
|
|
@@ -40354,8 +40806,8 @@ ${installInfo}`
|
|
|
40354
40806
|
return results;
|
|
40355
40807
|
}
|
|
40356
40808
|
var http2 = __toESM2(require("http"));
|
|
40357
|
-
var
|
|
40358
|
-
var
|
|
40809
|
+
var fs14 = __toESM2(require("fs"));
|
|
40810
|
+
var path18 = __toESM2(require("path"));
|
|
40359
40811
|
function generateFiles(type, name, category, opts = {}) {
|
|
40360
40812
|
const { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2 = "0.1" } = opts;
|
|
40361
40813
|
if (category === "cli" || category === "acp") {
|
|
@@ -41690,6 +42142,162 @@ async (params) => {
|
|
|
41690
42142
|
ctx.json(res, 500, { error: `DOM context collection failed: ${e.message}` });
|
|
41691
42143
|
}
|
|
41692
42144
|
}
|
|
42145
|
+
var fs12 = __toESM2(require("fs"));
|
|
42146
|
+
var path16 = __toESM2(require("path"));
|
|
42147
|
+
function slugifyFixtureName(value) {
|
|
42148
|
+
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
42149
|
+
return normalized || `fixture-${Date.now()}`;
|
|
42150
|
+
}
|
|
42151
|
+
function getCliFixtureDir(ctx, type) {
|
|
42152
|
+
const providerDir = ctx.providerLoader.findProviderDir(type);
|
|
42153
|
+
if (!providerDir) {
|
|
42154
|
+
throw new Error(`Provider directory not found for '${type}'`);
|
|
42155
|
+
}
|
|
42156
|
+
return path16.join(providerDir, "fixtures");
|
|
42157
|
+
}
|
|
42158
|
+
function readCliFixture(ctx, type, name) {
|
|
42159
|
+
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
42160
|
+
const filePath = path16.join(fixtureDir, `${name}.json`);
|
|
42161
|
+
if (!fs12.existsSync(filePath)) {
|
|
42162
|
+
throw new Error(`Fixture not found: ${filePath}`);
|
|
42163
|
+
}
|
|
42164
|
+
return JSON.parse(fs12.readFileSync(filePath, "utf-8"));
|
|
42165
|
+
}
|
|
42166
|
+
function getExerciseTranscriptText(result) {
|
|
42167
|
+
const parts = [];
|
|
42168
|
+
const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
|
|
42169
|
+
const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
|
|
42170
|
+
for (const message of [...debugMessages, ...traceMessages]) {
|
|
42171
|
+
if (!message || typeof message.content !== "string") continue;
|
|
42172
|
+
parts.push(message.content);
|
|
42173
|
+
}
|
|
42174
|
+
if (typeof result?.debug?.partialResponse === "string") parts.push(result.debug.partialResponse);
|
|
42175
|
+
if (typeof result?.trace?.responseBuffer === "string") parts.push(result.trace.responseBuffer);
|
|
42176
|
+
return parts.join("\n");
|
|
42177
|
+
}
|
|
42178
|
+
function getExerciseLastAssistant(result) {
|
|
42179
|
+
const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
|
|
42180
|
+
const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
|
|
42181
|
+
for (const messages of [debugMessages, traceMessages]) {
|
|
42182
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
42183
|
+
const message = messages[i];
|
|
42184
|
+
if (message?.role === "assistant" && typeof message.content === "string" && message.content.trim()) {
|
|
42185
|
+
return message.content;
|
|
42186
|
+
}
|
|
42187
|
+
}
|
|
42188
|
+
}
|
|
42189
|
+
return "";
|
|
42190
|
+
}
|
|
42191
|
+
function getExerciseMessageCount(result) {
|
|
42192
|
+
const debugMessages = Array.isArray(result?.debug?.messages) ? result.debug.messages : [];
|
|
42193
|
+
const traceMessages = Array.isArray(result?.trace?.messages) ? result.trace.messages : [];
|
|
42194
|
+
return Math.max(debugMessages.length, traceMessages.length);
|
|
42195
|
+
}
|
|
42196
|
+
function compileFixtureRegex(source) {
|
|
42197
|
+
const value = String(source || "").trim();
|
|
42198
|
+
if (!value) return null;
|
|
42199
|
+
const delimited = value.match(/^\/([\s\S]+)\/([dgimsuvy]*)$/);
|
|
42200
|
+
try {
|
|
42201
|
+
if (delimited) {
|
|
42202
|
+
return new RegExp(delimited[1], delimited[2]);
|
|
42203
|
+
}
|
|
42204
|
+
return new RegExp(value, "m");
|
|
42205
|
+
} catch {
|
|
42206
|
+
return null;
|
|
42207
|
+
}
|
|
42208
|
+
}
|
|
42209
|
+
function statusesContainSequence(actual, expected) {
|
|
42210
|
+
if (!expected.length) return true;
|
|
42211
|
+
let index = 0;
|
|
42212
|
+
for (const status of actual) {
|
|
42213
|
+
if (status === expected[index]) index += 1;
|
|
42214
|
+
if (index >= expected.length) return true;
|
|
42215
|
+
}
|
|
42216
|
+
return false;
|
|
42217
|
+
}
|
|
42218
|
+
function validateCliFixtureResult(result, assertions) {
|
|
42219
|
+
const failures = [];
|
|
42220
|
+
const transcriptText = getExerciseTranscriptText(result);
|
|
42221
|
+
const lastAssistant = getExerciseLastAssistant(result);
|
|
42222
|
+
const mustContainAny = assertions.mustContainAny || [];
|
|
42223
|
+
const mustNotContainAny = assertions.mustNotContainAny || [];
|
|
42224
|
+
const mustMatchAny = assertions.mustMatchAny || [];
|
|
42225
|
+
const mustNotMatchAny = assertions.mustNotMatchAny || [];
|
|
42226
|
+
const lastAssistantMustContainAny = assertions.lastAssistantMustContainAny || [];
|
|
42227
|
+
const lastAssistantMustNotContainAny = assertions.lastAssistantMustNotContainAny || [];
|
|
42228
|
+
const lastAssistantMustMatchAny = assertions.lastAssistantMustMatchAny || [];
|
|
42229
|
+
const lastAssistantMustNotMatchAny = assertions.lastAssistantMustNotMatchAny || [];
|
|
42230
|
+
const statusesSeen = Array.isArray(result?.statusesSeen) ? result.statusesSeen.map((value) => String(value)) : [];
|
|
42231
|
+
if (assertions.requireNotTimedOut !== false && result?.timedOut) {
|
|
42232
|
+
failures.push("Exercise timed out");
|
|
42233
|
+
}
|
|
42234
|
+
const missingRequired = mustContainAny.filter((value) => !transcriptText.includes(value));
|
|
42235
|
+
if (missingRequired.length > 0) {
|
|
42236
|
+
failures.push(`Missing required substrings: ${missingRequired.join(", ")}`);
|
|
42237
|
+
}
|
|
42238
|
+
const presentBanned = mustNotContainAny.filter((value) => transcriptText.includes(value));
|
|
42239
|
+
if (presentBanned.length > 0) {
|
|
42240
|
+
failures.push(`Found banned substrings: ${presentBanned.join(", ")}`);
|
|
42241
|
+
}
|
|
42242
|
+
const missingRegex = mustMatchAny.filter((value) => {
|
|
42243
|
+
const regex = compileFixtureRegex(value);
|
|
42244
|
+
return !regex || !regex.test(transcriptText);
|
|
42245
|
+
});
|
|
42246
|
+
if (missingRegex.length > 0) {
|
|
42247
|
+
failures.push(`Missing required regex matches: ${missingRegex.join(", ")}`);
|
|
42248
|
+
}
|
|
42249
|
+
const presentBannedRegex = mustNotMatchAny.filter((value) => {
|
|
42250
|
+
const regex = compileFixtureRegex(value);
|
|
42251
|
+
return !!regex && regex.test(transcriptText);
|
|
42252
|
+
});
|
|
42253
|
+
if (presentBannedRegex.length > 0) {
|
|
42254
|
+
failures.push(`Found banned regex matches: ${presentBannedRegex.join(", ")}`);
|
|
42255
|
+
}
|
|
42256
|
+
const missingLastAssistant = lastAssistantMustContainAny.filter((value) => !lastAssistant.includes(value));
|
|
42257
|
+
if (missingLastAssistant.length > 0) {
|
|
42258
|
+
failures.push(`Missing required lastAssistant substrings: ${missingLastAssistant.join(", ")}`);
|
|
42259
|
+
}
|
|
42260
|
+
const presentBannedLastAssistant = lastAssistantMustNotContainAny.filter((value) => lastAssistant.includes(value));
|
|
42261
|
+
if (presentBannedLastAssistant.length > 0) {
|
|
42262
|
+
failures.push(`Found banned lastAssistant substrings: ${presentBannedLastAssistant.join(", ")}`);
|
|
42263
|
+
}
|
|
42264
|
+
const missingLastAssistantRegex = lastAssistantMustMatchAny.filter((value) => {
|
|
42265
|
+
const regex = compileFixtureRegex(value);
|
|
42266
|
+
return !regex || !regex.test(lastAssistant);
|
|
42267
|
+
});
|
|
42268
|
+
if (missingLastAssistantRegex.length > 0) {
|
|
42269
|
+
failures.push(`Missing required lastAssistant regex matches: ${missingLastAssistantRegex.join(", ")}`);
|
|
42270
|
+
}
|
|
42271
|
+
const presentBannedLastAssistantRegex = lastAssistantMustNotMatchAny.filter((value) => {
|
|
42272
|
+
const regex = compileFixtureRegex(value);
|
|
42273
|
+
return !!regex && regex.test(lastAssistant);
|
|
42274
|
+
});
|
|
42275
|
+
if (presentBannedLastAssistantRegex.length > 0) {
|
|
42276
|
+
failures.push(`Found banned lastAssistant regex matches: ${presentBannedLastAssistantRegex.join(", ")}`);
|
|
42277
|
+
}
|
|
42278
|
+
if (assertions.statusesSeen?.length && !statusesContainSequence(statusesSeen, assertions.statusesSeen)) {
|
|
42279
|
+
failures.push(`Expected statuses sequence not observed: ${assertions.statusesSeen.join(" -> ")}`);
|
|
42280
|
+
}
|
|
42281
|
+
if (result && typeof result === "object") {
|
|
42282
|
+
result.lastAssistant = lastAssistant;
|
|
42283
|
+
}
|
|
42284
|
+
return failures;
|
|
42285
|
+
}
|
|
42286
|
+
function getCliProviderResolutionMeta(ctx, type, adapter) {
|
|
42287
|
+
const adapterMeta = typeof adapter?.getProviderResolutionMeta === "function" ? adapter.getProviderResolutionMeta() : adapter?.getDebugState?.()?.providerResolution || null;
|
|
42288
|
+
const resolvedProvider = ctx.providerLoader.resolve(type);
|
|
42289
|
+
if (!adapterMeta && !resolvedProvider) return null;
|
|
42290
|
+
return {
|
|
42291
|
+
type,
|
|
42292
|
+
providerDir: adapterMeta?.providerDir || resolvedProvider?._resolvedProviderDir || ctx.providerLoader.findProviderDir(type),
|
|
42293
|
+
scriptDir: adapterMeta?.scriptDir || resolvedProvider?._resolvedScriptDir || null,
|
|
42294
|
+
scriptsPath: adapterMeta?.scriptsPath || resolvedProvider?._resolvedScriptsPath || null,
|
|
42295
|
+
scriptsSource: adapterMeta?.scriptsSource || resolvedProvider?._resolvedScriptsSource || null,
|
|
42296
|
+
resolvedVersion: adapterMeta?.resolvedVersion || resolvedProvider?._resolvedVersion || null,
|
|
42297
|
+
resolvedOs: adapterMeta?.resolvedOs || resolvedProvider?._resolvedOs || null,
|
|
42298
|
+
versionWarning: adapterMeta?.versionWarning || resolvedProvider?._versionWarning || null
|
|
42299
|
+
};
|
|
42300
|
+
}
|
|
41693
42301
|
function findCliTarget(ctx, type, instanceId) {
|
|
41694
42302
|
if (!ctx.instanceManager) return null;
|
|
41695
42303
|
const cliStates = ctx.instanceManager.collectAllStates().filter((s15) => s15.category === "cli" || s15.category === "acp");
|
|
@@ -41698,6 +42306,331 @@ async (params) => {
|
|
|
41698
42306
|
const matches = cliStates.filter((s15) => s15.type === type);
|
|
41699
42307
|
return matches[matches.length - 1] || null;
|
|
41700
42308
|
}
|
|
42309
|
+
function getCliTargetBundle(ctx, type, instanceId) {
|
|
42310
|
+
if (!ctx.instanceManager) return null;
|
|
42311
|
+
const target = findCliTarget(ctx, type, instanceId);
|
|
42312
|
+
if (!target) return null;
|
|
42313
|
+
const instance = ctx.instanceManager.getInstance(target.instanceId);
|
|
42314
|
+
if (!instance) return null;
|
|
42315
|
+
const adapter = instance.getAdapter?.() || instance.adapter;
|
|
42316
|
+
if (!adapter) return null;
|
|
42317
|
+
return { target, instance, adapter };
|
|
42318
|
+
}
|
|
42319
|
+
function sleep(ms2) {
|
|
42320
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms2));
|
|
42321
|
+
}
|
|
42322
|
+
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
42323
|
+
const startedAt = Date.now();
|
|
42324
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
42325
|
+
const bundle = getCliTargetBundle(ctx, type, instanceId);
|
|
42326
|
+
if (bundle) {
|
|
42327
|
+
const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
|
|
42328
|
+
const startupParseGate = !!debug?.startupParseGate;
|
|
42329
|
+
const adapterReady = !!debug?.ready;
|
|
42330
|
+
const visibleStatusReady = bundle.target.status === "generating" || bundle.target.status === "waiting_approval";
|
|
42331
|
+
const idleReady = bundle.target.status === "idle" && !startupParseGate;
|
|
42332
|
+
if (adapterReady || visibleStatusReady || idleReady) {
|
|
42333
|
+
return bundle;
|
|
42334
|
+
}
|
|
42335
|
+
}
|
|
42336
|
+
await sleep(100);
|
|
42337
|
+
}
|
|
42338
|
+
return getCliTargetBundle(ctx, type, instanceId);
|
|
42339
|
+
}
|
|
42340
|
+
async function runCliExerciseInternal(ctx, body) {
|
|
42341
|
+
if (!ctx.cliManager) {
|
|
42342
|
+
throw new Error("CliManager not available");
|
|
42343
|
+
}
|
|
42344
|
+
if (!ctx.instanceManager) {
|
|
42345
|
+
throw new Error("InstanceManager not available");
|
|
42346
|
+
}
|
|
42347
|
+
const {
|
|
42348
|
+
type,
|
|
42349
|
+
text,
|
|
42350
|
+
instanceId: requestedInstanceId,
|
|
42351
|
+
workingDir,
|
|
42352
|
+
args,
|
|
42353
|
+
autoLaunch = true,
|
|
42354
|
+
freshSession = true,
|
|
42355
|
+
autoResolveApprovals = true,
|
|
42356
|
+
approvalButtonIndex = 0,
|
|
42357
|
+
timeoutMs = 45e3,
|
|
42358
|
+
readyTimeoutMs = 15e3,
|
|
42359
|
+
idleSettledMs = 1200,
|
|
42360
|
+
traceLimit = 160,
|
|
42361
|
+
stopWhenDone = false
|
|
42362
|
+
} = body || {};
|
|
42363
|
+
if (!type) {
|
|
42364
|
+
throw new Error("type required (e.g. claude-cli, codex-cli)");
|
|
42365
|
+
}
|
|
42366
|
+
if (!text || typeof text !== "string") {
|
|
42367
|
+
throw new Error("text required (prompt to send to the CLI)");
|
|
42368
|
+
}
|
|
42369
|
+
let resolvedInstanceId = requestedInstanceId;
|
|
42370
|
+
if (freshSession) {
|
|
42371
|
+
const staleTargets = ctx.instanceManager.collectAllStates().filter((state) => (state.category === "cli" || state.category === "acp") && state.type === type).map((state) => state.instanceId);
|
|
42372
|
+
for (const staleId of staleTargets) {
|
|
42373
|
+
ctx.instanceManager.removeInstance(staleId);
|
|
42374
|
+
}
|
|
42375
|
+
resolvedInstanceId = void 0;
|
|
42376
|
+
}
|
|
42377
|
+
let bundle = getCliTargetBundle(ctx, type, resolvedInstanceId);
|
|
42378
|
+
if (!bundle && autoLaunch) {
|
|
42379
|
+
const launchArgs = [type, workingDir || process.cwd(), Array.isArray(args) ? args : []];
|
|
42380
|
+
let launched = null;
|
|
42381
|
+
let lastLaunchError = null;
|
|
42382
|
+
for (let attempt = 1; attempt <= 2; attempt += 1) {
|
|
42383
|
+
try {
|
|
42384
|
+
launched = await ctx.cliManager.startSession(...launchArgs);
|
|
42385
|
+
lastLaunchError = null;
|
|
42386
|
+
break;
|
|
42387
|
+
} catch (error48) {
|
|
42388
|
+
lastLaunchError = error48 instanceof Error ? error48 : new Error(String(error48?.message || error48));
|
|
42389
|
+
const message = String(lastLaunchError.message || "");
|
|
42390
|
+
const retryable = /ECONNREFUSED|session-host|Session host/i.test(message);
|
|
42391
|
+
if (!retryable || attempt === 2) break;
|
|
42392
|
+
await sleep(1e3);
|
|
42393
|
+
}
|
|
42394
|
+
}
|
|
42395
|
+
if (!launched) {
|
|
42396
|
+
throw lastLaunchError || new Error(`Failed to start ${type}`);
|
|
42397
|
+
}
|
|
42398
|
+
resolvedInstanceId = launched.runtimeSessionId;
|
|
42399
|
+
bundle = await waitForCliReady(ctx, type, resolvedInstanceId, Math.max(1e3, readyTimeoutMs));
|
|
42400
|
+
}
|
|
42401
|
+
if (!bundle) {
|
|
42402
|
+
throw new Error(`No running instance found for: ${resolvedInstanceId || type}`);
|
|
42403
|
+
}
|
|
42404
|
+
const initialDebug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
|
|
42405
|
+
const initialTrace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
|
|
42406
|
+
const providerResolution = getCliProviderResolutionMeta(ctx, bundle.target.type, bundle.adapter);
|
|
42407
|
+
const preTraceCount = Number(initialTrace?.entryCount || 0);
|
|
42408
|
+
const startAt = Date.now();
|
|
42409
|
+
const statusesSeen = [];
|
|
42410
|
+
const approvalsResolved = [];
|
|
42411
|
+
let lastStatus = "";
|
|
42412
|
+
let lastModalKey = "";
|
|
42413
|
+
let idleSince = 0;
|
|
42414
|
+
let sawBusy = false;
|
|
42415
|
+
ctx.instanceManager.sendEvent(bundle.target.instanceId, "send_message", { text });
|
|
42416
|
+
while (Date.now() - startAt < Math.max(1e3, timeoutMs)) {
|
|
42417
|
+
await sleep(150);
|
|
42418
|
+
bundle = getCliTargetBundle(ctx, type, bundle.target.instanceId);
|
|
42419
|
+
if (!bundle) {
|
|
42420
|
+
throw new Error("CLI instance disappeared during exercise");
|
|
42421
|
+
}
|
|
42422
|
+
const debug = typeof bundle.adapter.getDebugState === "function" ? bundle.adapter.getDebugState() : null;
|
|
42423
|
+
const trace = typeof bundle.adapter.getTraceState === "function" ? bundle.adapter.getTraceState(traceLimit) : null;
|
|
42424
|
+
const status = String(debug?.status || bundle.target.status || "unknown");
|
|
42425
|
+
const traceEntries = Array.isArray(trace?.entries) ? trace.entries : [];
|
|
42426
|
+
const sawSendMessage = traceEntries.some((entry) => entry?.type === "send_message");
|
|
42427
|
+
const sawSubmitWrite = traceEntries.some((entry) => entry?.type === "submit_write");
|
|
42428
|
+
const hasTurnStarted = sawSendMessage || sawSubmitWrite || !!debug?.currentTurnScope;
|
|
42429
|
+
if (status !== lastStatus) {
|
|
42430
|
+
statusesSeen.push(status);
|
|
42431
|
+
lastStatus = status;
|
|
42432
|
+
}
|
|
42433
|
+
if (status === "generating" || status === "waiting_approval") {
|
|
42434
|
+
sawBusy = true;
|
|
42435
|
+
idleSince = 0;
|
|
42436
|
+
}
|
|
42437
|
+
const modal = debug?.activeModal || trace?.activeModal || null;
|
|
42438
|
+
if (autoResolveApprovals && status === "waiting_approval" && modal && Array.isArray(modal.buttons) && modal.buttons.length > 0) {
|
|
42439
|
+
const clampedIndex = Math.max(0, Math.min(Number(approvalButtonIndex) || 0, modal.buttons.length - 1));
|
|
42440
|
+
const modalKey = JSON.stringify({
|
|
42441
|
+
message: modal.message || "",
|
|
42442
|
+
buttons: modal.buttons,
|
|
42443
|
+
index: clampedIndex
|
|
42444
|
+
});
|
|
42445
|
+
if (modalKey !== lastModalKey && typeof bundle.adapter.resolveModal === "function") {
|
|
42446
|
+
lastModalKey = modalKey;
|
|
42447
|
+
approvalsResolved.push({
|
|
42448
|
+
at: Date.now(),
|
|
42449
|
+
buttonIndex: clampedIndex,
|
|
42450
|
+
label: modal.buttons[clampedIndex] || null
|
|
42451
|
+
});
|
|
42452
|
+
bundle.adapter.resolveModal(clampedIndex);
|
|
42453
|
+
continue;
|
|
42454
|
+
}
|
|
42455
|
+
}
|
|
42456
|
+
const traceCount = Number(trace?.entryCount || 0);
|
|
42457
|
+
const hasProgress = hasTurnStarted && (traceCount > preTraceCount || statusesSeen.length > 1 || approvalsResolved.length > 0);
|
|
42458
|
+
if (status === "idle" && hasProgress && sawBusy) {
|
|
42459
|
+
if (!idleSince) idleSince = Date.now();
|
|
42460
|
+
if (Date.now() - idleSince >= Math.max(200, idleSettledMs)) {
|
|
42461
|
+
const payload2 = {
|
|
42462
|
+
exercised: true,
|
|
42463
|
+
instanceId: bundle.target.instanceId,
|
|
42464
|
+
providerState: {
|
|
42465
|
+
type: bundle.target.type,
|
|
42466
|
+
name: bundle.target.name,
|
|
42467
|
+
status: bundle.target.status,
|
|
42468
|
+
mode: "mode" in bundle.target ? bundle.target.mode : void 0
|
|
42469
|
+
},
|
|
42470
|
+
providerResolution,
|
|
42471
|
+
initialDebug,
|
|
42472
|
+
initialTrace,
|
|
42473
|
+
debug,
|
|
42474
|
+
trace,
|
|
42475
|
+
statusesSeen,
|
|
42476
|
+
approvalsResolved,
|
|
42477
|
+
elapsedMs: Date.now() - startAt,
|
|
42478
|
+
timedOut: false
|
|
42479
|
+
};
|
|
42480
|
+
payload2.lastAssistant = getExerciseLastAssistant(payload2);
|
|
42481
|
+
payload2.messageCount = getExerciseMessageCount(payload2);
|
|
42482
|
+
if (stopWhenDone) {
|
|
42483
|
+
ctx.instanceManager.removeInstance(bundle.target.instanceId);
|
|
42484
|
+
}
|
|
42485
|
+
return payload2;
|
|
42486
|
+
}
|
|
42487
|
+
} else if (status === "idle" && hasProgress) {
|
|
42488
|
+
if (!idleSince) idleSince = Date.now();
|
|
42489
|
+
if (Date.now() - idleSince >= Math.max(500, idleSettledMs) && Date.now() - startAt >= 750) {
|
|
42490
|
+
const payload2 = {
|
|
42491
|
+
exercised: true,
|
|
42492
|
+
instanceId: bundle.target.instanceId,
|
|
42493
|
+
providerState: {
|
|
42494
|
+
type: bundle.target.type,
|
|
42495
|
+
name: bundle.target.name,
|
|
42496
|
+
status: bundle.target.status,
|
|
42497
|
+
mode: "mode" in bundle.target ? bundle.target.mode : void 0
|
|
42498
|
+
},
|
|
42499
|
+
providerResolution,
|
|
42500
|
+
initialDebug,
|
|
42501
|
+
initialTrace,
|
|
42502
|
+
debug,
|
|
42503
|
+
trace,
|
|
42504
|
+
statusesSeen,
|
|
42505
|
+
approvalsResolved,
|
|
42506
|
+
elapsedMs: Date.now() - startAt,
|
|
42507
|
+
timedOut: false
|
|
42508
|
+
};
|
|
42509
|
+
payload2.lastAssistant = getExerciseLastAssistant(payload2);
|
|
42510
|
+
payload2.messageCount = getExerciseMessageCount(payload2);
|
|
42511
|
+
if (stopWhenDone) {
|
|
42512
|
+
ctx.instanceManager.removeInstance(bundle.target.instanceId);
|
|
42513
|
+
}
|
|
42514
|
+
return payload2;
|
|
42515
|
+
}
|
|
42516
|
+
} else {
|
|
42517
|
+
idleSince = 0;
|
|
42518
|
+
}
|
|
42519
|
+
}
|
|
42520
|
+
const finalBundle = getCliTargetBundle(ctx, type, bundle.target.instanceId) || bundle;
|
|
42521
|
+
const finalDebug = typeof finalBundle.adapter.getDebugState === "function" ? finalBundle.adapter.getDebugState() : null;
|
|
42522
|
+
const finalTrace = typeof finalBundle.adapter.getTraceState === "function" ? finalBundle.adapter.getTraceState(traceLimit) : null;
|
|
42523
|
+
if (stopWhenDone) {
|
|
42524
|
+
ctx.instanceManager.removeInstance(finalBundle.target.instanceId);
|
|
42525
|
+
}
|
|
42526
|
+
const payload = {
|
|
42527
|
+
exercised: true,
|
|
42528
|
+
instanceId: finalBundle.target.instanceId,
|
|
42529
|
+
providerState: {
|
|
42530
|
+
type: finalBundle.target.type,
|
|
42531
|
+
name: finalBundle.target.name,
|
|
42532
|
+
status: finalBundle.target.status,
|
|
42533
|
+
mode: "mode" in finalBundle.target ? finalBundle.target.mode : void 0
|
|
42534
|
+
},
|
|
42535
|
+
providerResolution: getCliProviderResolutionMeta(ctx, finalBundle.target.type, finalBundle.adapter),
|
|
42536
|
+
initialDebug,
|
|
42537
|
+
initialTrace,
|
|
42538
|
+
debug: finalDebug,
|
|
42539
|
+
trace: finalTrace,
|
|
42540
|
+
statusesSeen,
|
|
42541
|
+
approvalsResolved,
|
|
42542
|
+
elapsedMs: Date.now() - startAt,
|
|
42543
|
+
timedOut: true
|
|
42544
|
+
};
|
|
42545
|
+
payload.lastAssistant = getExerciseLastAssistant(payload);
|
|
42546
|
+
payload.messageCount = getExerciseMessageCount(payload);
|
|
42547
|
+
return payload;
|
|
42548
|
+
}
|
|
42549
|
+
async function runCliAutoImplVerification(ctx, type, verification) {
|
|
42550
|
+
const assertions = {
|
|
42551
|
+
mustContainAny: verification?.mustContainAny || [],
|
|
42552
|
+
mustNotContainAny: verification?.mustNotContainAny || [],
|
|
42553
|
+
mustMatchAny: verification?.mustMatchAny || [],
|
|
42554
|
+
mustNotMatchAny: verification?.mustNotMatchAny || [],
|
|
42555
|
+
lastAssistantMustContainAny: verification?.lastAssistantMustContainAny || [],
|
|
42556
|
+
lastAssistantMustNotContainAny: verification?.lastAssistantMustNotContainAny || [],
|
|
42557
|
+
lastAssistantMustMatchAny: verification?.lastAssistantMustMatchAny || [],
|
|
42558
|
+
lastAssistantMustNotMatchAny: verification?.lastAssistantMustNotMatchAny || [],
|
|
42559
|
+
requireNotTimedOut: true
|
|
42560
|
+
};
|
|
42561
|
+
const rawFixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
|
|
42562
|
+
if (rawFixtureNames.length > 0) {
|
|
42563
|
+
const results = [];
|
|
42564
|
+
for (const rawFixtureName2 of rawFixtureNames) {
|
|
42565
|
+
const name = slugifyFixtureName(rawFixtureName2);
|
|
42566
|
+
const fixture = readCliFixture(ctx, type, name);
|
|
42567
|
+
const mergedAssertions = {
|
|
42568
|
+
...fixture.assertions,
|
|
42569
|
+
...assertions
|
|
42570
|
+
};
|
|
42571
|
+
const result2 = await runCliExerciseInternal(ctx, {
|
|
42572
|
+
...fixture.request,
|
|
42573
|
+
type
|
|
42574
|
+
});
|
|
42575
|
+
const failures2 = validateCliFixtureResult(result2, mergedAssertions);
|
|
42576
|
+
results.push({
|
|
42577
|
+
fixtureName: name,
|
|
42578
|
+
pass: failures2.length === 0,
|
|
42579
|
+
failures: failures2,
|
|
42580
|
+
result: result2,
|
|
42581
|
+
assertions: mergedAssertions,
|
|
42582
|
+
fixture
|
|
42583
|
+
});
|
|
42584
|
+
}
|
|
42585
|
+
const firstFailure = results.find((item) => !item.pass) || results[results.length - 1];
|
|
42586
|
+
return {
|
|
42587
|
+
mode: "fixture_replay_suite",
|
|
42588
|
+
pass: results.every((item) => item.pass),
|
|
42589
|
+
failures: results.flatMap((item) => item.failures.map((failure) => `${item.fixtureName}: ${failure}`)),
|
|
42590
|
+
result: firstFailure.result,
|
|
42591
|
+
assertions: firstFailure.assertions,
|
|
42592
|
+
fixture: firstFailure.fixture,
|
|
42593
|
+
results
|
|
42594
|
+
};
|
|
42595
|
+
}
|
|
42596
|
+
const rawFixtureName = String(verification?.fixtureName || "").trim();
|
|
42597
|
+
if (rawFixtureName) {
|
|
42598
|
+
const name = slugifyFixtureName(rawFixtureName);
|
|
42599
|
+
try {
|
|
42600
|
+
const fixture = readCliFixture(ctx, type, name);
|
|
42601
|
+
const mergedAssertions = {
|
|
42602
|
+
...fixture.assertions,
|
|
42603
|
+
...assertions
|
|
42604
|
+
};
|
|
42605
|
+
const result2 = await runCliExerciseInternal(ctx, {
|
|
42606
|
+
...fixture.request,
|
|
42607
|
+
type
|
|
42608
|
+
});
|
|
42609
|
+
const failures2 = validateCliFixtureResult(result2, mergedAssertions);
|
|
42610
|
+
return {
|
|
42611
|
+
mode: "fixture_replay",
|
|
42612
|
+
pass: failures2.length === 0,
|
|
42613
|
+
failures: failures2,
|
|
42614
|
+
result: result2,
|
|
42615
|
+
assertions: mergedAssertions,
|
|
42616
|
+
fixture
|
|
42617
|
+
};
|
|
42618
|
+
} catch {
|
|
42619
|
+
}
|
|
42620
|
+
}
|
|
42621
|
+
const result = await runCliExerciseInternal(ctx, {
|
|
42622
|
+
...verification?.request || {},
|
|
42623
|
+
type
|
|
42624
|
+
});
|
|
42625
|
+
const failures = validateCliFixtureResult(result, assertions);
|
|
42626
|
+
return {
|
|
42627
|
+
mode: "exercise",
|
|
42628
|
+
pass: failures.length === 0,
|
|
42629
|
+
failures,
|
|
42630
|
+
result,
|
|
42631
|
+
assertions
|
|
42632
|
+
};
|
|
42633
|
+
}
|
|
41701
42634
|
async function handleCliStatus(ctx, _req, res) {
|
|
41702
42635
|
if (!ctx.instanceManager) {
|
|
41703
42636
|
ctx.json(res, 503, { error: "InstanceManager not available (daemon not fully initialized)" });
|
|
@@ -41836,12 +42769,14 @@ async (params) => {
|
|
|
41836
42769
|
status: target.status,
|
|
41837
42770
|
mode: "mode" in target ? target.mode : void 0
|
|
41838
42771
|
},
|
|
42772
|
+
providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
|
|
41839
42773
|
debug: debugState
|
|
41840
42774
|
});
|
|
41841
42775
|
} else {
|
|
41842
42776
|
ctx.json(res, 200, {
|
|
41843
42777
|
instanceId: target.instanceId,
|
|
41844
42778
|
providerState: target,
|
|
42779
|
+
providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
|
|
41845
42780
|
debug: null,
|
|
41846
42781
|
message: "No debug state available (adapter.getDebugState not found)"
|
|
41847
42782
|
});
|
|
@@ -41850,6 +42785,191 @@ async (params) => {
|
|
|
41850
42785
|
ctx.json(res, 500, { error: `Debug state failed: ${e.message}` });
|
|
41851
42786
|
}
|
|
41852
42787
|
}
|
|
42788
|
+
async function handleCliTrace(ctx, type, req, res) {
|
|
42789
|
+
if (!ctx.instanceManager) {
|
|
42790
|
+
ctx.json(res, 503, { error: "InstanceManager not available" });
|
|
42791
|
+
return;
|
|
42792
|
+
}
|
|
42793
|
+
const target = findCliTarget(ctx, type);
|
|
42794
|
+
if (!target) {
|
|
42795
|
+
const allStates = ctx.instanceManager.collectAllStates();
|
|
42796
|
+
ctx.json(res, 404, {
|
|
42797
|
+
error: `No running instance for: ${type}`,
|
|
42798
|
+
available: allStates.filter((s15) => s15.category === "cli" || s15.category === "acp").map((s15) => s15.type)
|
|
42799
|
+
});
|
|
42800
|
+
return;
|
|
42801
|
+
}
|
|
42802
|
+
const instance = ctx.instanceManager.getInstance(target.instanceId);
|
|
42803
|
+
if (!instance) {
|
|
42804
|
+
ctx.json(res, 404, { error: `Instance not found: ${target.instanceId}` });
|
|
42805
|
+
return;
|
|
42806
|
+
}
|
|
42807
|
+
try {
|
|
42808
|
+
const adapter = instance.getAdapter?.() || instance.adapter;
|
|
42809
|
+
const url2 = new URL(req.url || "/", "http://127.0.0.1");
|
|
42810
|
+
const limit = parseInt(url2.searchParams.get("limit") || "120", 10);
|
|
42811
|
+
if (adapter && typeof adapter.getTraceState === "function") {
|
|
42812
|
+
const trace = adapter.getTraceState(limit);
|
|
42813
|
+
const debug = typeof adapter.getDebugState === "function" ? adapter.getDebugState() : null;
|
|
42814
|
+
ctx.json(res, 200, {
|
|
42815
|
+
instanceId: target.instanceId,
|
|
42816
|
+
providerState: {
|
|
42817
|
+
type: target.type,
|
|
42818
|
+
name: target.name,
|
|
42819
|
+
status: target.status,
|
|
42820
|
+
mode: "mode" in target ? target.mode : void 0
|
|
42821
|
+
},
|
|
42822
|
+
providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
|
|
42823
|
+
debug,
|
|
42824
|
+
trace
|
|
42825
|
+
});
|
|
42826
|
+
} else {
|
|
42827
|
+
ctx.json(res, 200, {
|
|
42828
|
+
instanceId: target.instanceId,
|
|
42829
|
+
providerState: target,
|
|
42830
|
+
providerResolution: getCliProviderResolutionMeta(ctx, target.type, adapter),
|
|
42831
|
+
debug: typeof adapter?.getDebugState === "function" ? adapter.getDebugState() : null,
|
|
42832
|
+
trace: null,
|
|
42833
|
+
message: "No trace state available (adapter.getTraceState not found)"
|
|
42834
|
+
});
|
|
42835
|
+
}
|
|
42836
|
+
} catch (e) {
|
|
42837
|
+
ctx.json(res, 500, { error: `Trace state failed: ${e.message}` });
|
|
42838
|
+
}
|
|
42839
|
+
}
|
|
42840
|
+
async function handleCliExercise(ctx, req, res) {
|
|
42841
|
+
try {
|
|
42842
|
+
const body = await ctx.readBody(req);
|
|
42843
|
+
const result = await runCliExerciseInternal(ctx, body || {});
|
|
42844
|
+
ctx.json(res, 200, result);
|
|
42845
|
+
} catch (e) {
|
|
42846
|
+
ctx.json(res, 500, { error: `Exercise failed: ${e.message}` });
|
|
42847
|
+
}
|
|
42848
|
+
}
|
|
42849
|
+
async function handleCliFixtureCapture(ctx, req, res) {
|
|
42850
|
+
try {
|
|
42851
|
+
const body = await ctx.readBody(req);
|
|
42852
|
+
const type = String(body?.type || "");
|
|
42853
|
+
const request = body?.request || {};
|
|
42854
|
+
if (!type) {
|
|
42855
|
+
ctx.json(res, 400, { error: "type required" });
|
|
42856
|
+
return;
|
|
42857
|
+
}
|
|
42858
|
+
if (!request?.text) {
|
|
42859
|
+
ctx.json(res, 400, { error: "request.text required" });
|
|
42860
|
+
return;
|
|
42861
|
+
}
|
|
42862
|
+
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
42863
|
+
fs12.mkdirSync(fixtureDir, { recursive: true });
|
|
42864
|
+
const name = slugifyFixtureName(String(body?.name || `${type}-${Date.now()}`));
|
|
42865
|
+
const result = await runCliExerciseInternal(ctx, { ...request, type });
|
|
42866
|
+
const fixture = {
|
|
42867
|
+
version: 1,
|
|
42868
|
+
kind: "cli-exercise-fixture",
|
|
42869
|
+
name,
|
|
42870
|
+
type,
|
|
42871
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42872
|
+
providerDir: ctx.providerLoader.findProviderDir(type),
|
|
42873
|
+
providerResolution: result?.providerResolution || null,
|
|
42874
|
+
request: { ...request, type },
|
|
42875
|
+
result,
|
|
42876
|
+
assertions: {
|
|
42877
|
+
mustContainAny: Array.isArray(body?.assertions?.mustContainAny) ? body.assertions.mustContainAny : [],
|
|
42878
|
+
mustNotContainAny: Array.isArray(body?.assertions?.mustNotContainAny) ? body.assertions.mustNotContainAny : [],
|
|
42879
|
+
mustMatchAny: Array.isArray(body?.assertions?.mustMatchAny) ? body.assertions.mustMatchAny : [],
|
|
42880
|
+
mustNotMatchAny: Array.isArray(body?.assertions?.mustNotMatchAny) ? body.assertions.mustNotMatchAny : [],
|
|
42881
|
+
lastAssistantMustContainAny: Array.isArray(body?.assertions?.lastAssistantMustContainAny) ? body.assertions.lastAssistantMustContainAny : [],
|
|
42882
|
+
lastAssistantMustNotContainAny: Array.isArray(body?.assertions?.lastAssistantMustNotContainAny) ? body.assertions.lastAssistantMustNotContainAny : [],
|
|
42883
|
+
lastAssistantMustMatchAny: Array.isArray(body?.assertions?.lastAssistantMustMatchAny) ? body.assertions.lastAssistantMustMatchAny : [],
|
|
42884
|
+
lastAssistantMustNotMatchAny: Array.isArray(body?.assertions?.lastAssistantMustNotMatchAny) ? body.assertions.lastAssistantMustNotMatchAny : [],
|
|
42885
|
+
statusesSeen: Array.isArray(body?.assertions?.statusesSeen) ? body.assertions.statusesSeen : void 0,
|
|
42886
|
+
requireNotTimedOut: body?.assertions?.requireNotTimedOut !== false
|
|
42887
|
+
},
|
|
42888
|
+
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
42889
|
+
};
|
|
42890
|
+
const filePath = path16.join(fixtureDir, `${name}.json`);
|
|
42891
|
+
fs12.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
42892
|
+
ctx.json(res, 200, {
|
|
42893
|
+
saved: true,
|
|
42894
|
+
name,
|
|
42895
|
+
path: filePath,
|
|
42896
|
+
fixture,
|
|
42897
|
+
verification: {
|
|
42898
|
+
pass: validateCliFixtureResult(result, fixture.assertions).length === 0,
|
|
42899
|
+
failures: validateCliFixtureResult(result, fixture.assertions)
|
|
42900
|
+
}
|
|
42901
|
+
});
|
|
42902
|
+
} catch (e) {
|
|
42903
|
+
ctx.json(res, 500, { error: `Fixture capture failed: ${e.message}` });
|
|
42904
|
+
}
|
|
42905
|
+
}
|
|
42906
|
+
async function handleCliFixtureList(ctx, type, _req, res) {
|
|
42907
|
+
try {
|
|
42908
|
+
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
42909
|
+
if (!fs12.existsSync(fixtureDir)) {
|
|
42910
|
+
ctx.json(res, 200, { fixtures: [], count: 0 });
|
|
42911
|
+
return;
|
|
42912
|
+
}
|
|
42913
|
+
const fixtures = fs12.readdirSync(fixtureDir).filter((file2) => file2.endsWith(".json")).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file2) => {
|
|
42914
|
+
const fullPath = path16.join(fixtureDir, file2);
|
|
42915
|
+
try {
|
|
42916
|
+
const raw = JSON.parse(fs12.readFileSync(fullPath, "utf-8"));
|
|
42917
|
+
return {
|
|
42918
|
+
name: raw.name || file2.replace(/\.json$/i, ""),
|
|
42919
|
+
path: fullPath,
|
|
42920
|
+
createdAt: raw.createdAt || null,
|
|
42921
|
+
notes: raw.notes || null,
|
|
42922
|
+
requestText: raw.request?.text || "",
|
|
42923
|
+
assertions: raw.assertions || {}
|
|
42924
|
+
};
|
|
42925
|
+
} catch {
|
|
42926
|
+
return {
|
|
42927
|
+
name: file2.replace(/\.json$/i, ""),
|
|
42928
|
+
path: fullPath,
|
|
42929
|
+
createdAt: null,
|
|
42930
|
+
notes: "Unreadable fixture",
|
|
42931
|
+
requestText: "",
|
|
42932
|
+
assertions: {}
|
|
42933
|
+
};
|
|
42934
|
+
}
|
|
42935
|
+
});
|
|
42936
|
+
ctx.json(res, 200, { fixtures, count: fixtures.length });
|
|
42937
|
+
} catch (e) {
|
|
42938
|
+
ctx.json(res, 500, { error: `Fixture list failed: ${e.message}` });
|
|
42939
|
+
}
|
|
42940
|
+
}
|
|
42941
|
+
async function handleCliFixtureReplay(ctx, req, res) {
|
|
42942
|
+
try {
|
|
42943
|
+
const body = await ctx.readBody(req);
|
|
42944
|
+
const type = String(body?.type || "");
|
|
42945
|
+
const rawName = String(body?.name || "").trim();
|
|
42946
|
+
if (!type || !rawName) {
|
|
42947
|
+
ctx.json(res, 400, { error: "type and name required" });
|
|
42948
|
+
return;
|
|
42949
|
+
}
|
|
42950
|
+
const name = slugifyFixtureName(rawName);
|
|
42951
|
+
const fixture = readCliFixture(ctx, type, name);
|
|
42952
|
+
const result = await runCliExerciseInternal(ctx, {
|
|
42953
|
+
...fixture.request,
|
|
42954
|
+
type
|
|
42955
|
+
});
|
|
42956
|
+
const assertions = {
|
|
42957
|
+
...fixture.assertions,
|
|
42958
|
+
...body?.assertions || {}
|
|
42959
|
+
};
|
|
42960
|
+
const failures = validateCliFixtureResult(result, assertions);
|
|
42961
|
+
ctx.json(res, 200, {
|
|
42962
|
+
replayed: true,
|
|
42963
|
+
pass: failures.length === 0,
|
|
42964
|
+
failures,
|
|
42965
|
+
fixture,
|
|
42966
|
+
result,
|
|
42967
|
+
assertions
|
|
42968
|
+
});
|
|
42969
|
+
} catch (e) {
|
|
42970
|
+
ctx.json(res, 500, { error: `Fixture replay failed: ${e.message}` });
|
|
42971
|
+
}
|
|
42972
|
+
}
|
|
41853
42973
|
async function handleCliResolve(ctx, req, res) {
|
|
41854
42974
|
const body = await ctx.readBody(req);
|
|
41855
42975
|
const { type, buttonIndex, instanceId } = body;
|
|
@@ -41924,9 +43044,29 @@ async (params) => {
|
|
|
41924
43044
|
ctx.json(res, 500, { error: `Raw send failed: ${e.message}` });
|
|
41925
43045
|
}
|
|
41926
43046
|
}
|
|
41927
|
-
var
|
|
41928
|
-
var
|
|
43047
|
+
var fs13 = __toESM2(require("fs"));
|
|
43048
|
+
var path17 = __toESM2(require("path"));
|
|
41929
43049
|
var os17 = __toESM2(require("os"));
|
|
43050
|
+
function getAutoImplPid(ctx) {
|
|
43051
|
+
const proc = ctx.autoImplProcess;
|
|
43052
|
+
return proc && typeof proc.pid === "number" && proc.pid > 0 ? proc.pid : null;
|
|
43053
|
+
}
|
|
43054
|
+
function isPidAlive(pid) {
|
|
43055
|
+
try {
|
|
43056
|
+
process.kill(pid, 0);
|
|
43057
|
+
return true;
|
|
43058
|
+
} catch (error48) {
|
|
43059
|
+
return error48?.code === "EPERM";
|
|
43060
|
+
}
|
|
43061
|
+
}
|
|
43062
|
+
function clearStaleAutoImplState(ctx, reason) {
|
|
43063
|
+
if (!ctx.autoImplStatus.running && !ctx.autoImplProcess) return;
|
|
43064
|
+
const pid = getAutoImplPid(ctx);
|
|
43065
|
+
if (pid && isPidAlive(pid)) return;
|
|
43066
|
+
ctx.log(`Clearing stale auto-implement state: ${reason}${pid ? ` (pid ${pid})` : ""}`);
|
|
43067
|
+
ctx.autoImplProcess = null;
|
|
43068
|
+
ctx.autoImplStatus.running = false;
|
|
43069
|
+
}
|
|
41930
43070
|
function getDefaultAutoImplReference(ctx, category, type) {
|
|
41931
43071
|
if (category === "cli") {
|
|
41932
43072
|
return type === "codex-cli" ? "claude-cli" : "codex-cli";
|
|
@@ -41942,45 +43082,45 @@ async (params) => {
|
|
|
41942
43082
|
return fallback?.type || null;
|
|
41943
43083
|
}
|
|
41944
43084
|
function getLatestScriptVersionDir(scriptsDir) {
|
|
41945
|
-
if (!
|
|
41946
|
-
const versions =
|
|
43085
|
+
if (!fs13.existsSync(scriptsDir)) return null;
|
|
43086
|
+
const versions = fs13.readdirSync(scriptsDir).filter((d) => {
|
|
41947
43087
|
try {
|
|
41948
|
-
return
|
|
43088
|
+
return fs13.statSync(path17.join(scriptsDir, d)).isDirectory();
|
|
41949
43089
|
} catch {
|
|
41950
43090
|
return false;
|
|
41951
43091
|
}
|
|
41952
43092
|
}).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
41953
43093
|
if (versions.length === 0) return null;
|
|
41954
|
-
return
|
|
43094
|
+
return path17.join(scriptsDir, versions[0]);
|
|
41955
43095
|
}
|
|
41956
43096
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
41957
|
-
const canonicalUserDir =
|
|
41958
|
-
const desiredDir = requestedDir ?
|
|
41959
|
-
const upstreamRoot =
|
|
41960
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
43097
|
+
const canonicalUserDir = path17.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
43098
|
+
const desiredDir = requestedDir ? path17.resolve(requestedDir) : canonicalUserDir;
|
|
43099
|
+
const upstreamRoot = path17.resolve(ctx.providerLoader.getUpstreamDir());
|
|
43100
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path17.sep}`)) {
|
|
41961
43101
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
41962
43102
|
}
|
|
41963
|
-
if (
|
|
43103
|
+
if (path17.basename(desiredDir) !== type) {
|
|
41964
43104
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
41965
43105
|
}
|
|
41966
43106
|
const sourceDir = ctx.findProviderDir(type);
|
|
41967
43107
|
if (!sourceDir) {
|
|
41968
43108
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
41969
43109
|
}
|
|
41970
|
-
if (!
|
|
41971
|
-
|
|
41972
|
-
|
|
43110
|
+
if (!fs13.existsSync(desiredDir)) {
|
|
43111
|
+
fs13.mkdirSync(path17.dirname(desiredDir), { recursive: true });
|
|
43112
|
+
fs13.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
41973
43113
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
41974
43114
|
}
|
|
41975
|
-
const providerJson =
|
|
41976
|
-
if (!
|
|
43115
|
+
const providerJson = path17.join(desiredDir, "provider.json");
|
|
43116
|
+
if (!fs13.existsSync(providerJson)) {
|
|
41977
43117
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
41978
43118
|
}
|
|
41979
43119
|
try {
|
|
41980
|
-
const providerData = JSON.parse(
|
|
43120
|
+
const providerData = JSON.parse(fs13.readFileSync(providerJson, "utf-8"));
|
|
41981
43121
|
if (providerData.disableUpstream !== true) {
|
|
41982
43122
|
providerData.disableUpstream = true;
|
|
41983
|
-
|
|
43123
|
+
fs13.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
|
|
41984
43124
|
}
|
|
41985
43125
|
} catch (error48) {
|
|
41986
43126
|
return {
|
|
@@ -41993,15 +43133,15 @@ async (params) => {
|
|
|
41993
43133
|
function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
41994
43134
|
if (!referenceType) return {};
|
|
41995
43135
|
const refDir = ctx.findProviderDir(referenceType);
|
|
41996
|
-
if (!refDir || !
|
|
43136
|
+
if (!refDir || !fs13.existsSync(refDir)) return {};
|
|
41997
43137
|
const referenceScripts = {};
|
|
41998
|
-
const scriptsDir =
|
|
43138
|
+
const scriptsDir = path17.join(refDir, "scripts");
|
|
41999
43139
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
42000
43140
|
if (!latestDir) return referenceScripts;
|
|
42001
|
-
for (const file2 of
|
|
43141
|
+
for (const file2 of fs13.readdirSync(latestDir)) {
|
|
42002
43142
|
if (!file2.endsWith(".js")) continue;
|
|
42003
43143
|
try {
|
|
42004
|
-
referenceScripts[file2] =
|
|
43144
|
+
referenceScripts[file2] = fs13.readFileSync(path17.join(latestDir, file2), "utf-8");
|
|
42005
43145
|
} catch {
|
|
42006
43146
|
}
|
|
42007
43147
|
}
|
|
@@ -42009,11 +43149,20 @@ async (params) => {
|
|
|
42009
43149
|
}
|
|
42010
43150
|
async function handleAutoImplement(ctx, type, req, res) {
|
|
42011
43151
|
const body = await ctx.readBody(req);
|
|
42012
|
-
const {
|
|
43152
|
+
const {
|
|
43153
|
+
agent = "claude-cli",
|
|
43154
|
+
functions,
|
|
43155
|
+
reference,
|
|
43156
|
+
model,
|
|
43157
|
+
comment,
|
|
43158
|
+
providerDir: requestedProviderDir,
|
|
43159
|
+
verification
|
|
43160
|
+
} = body;
|
|
42013
43161
|
if (!functions || !Array.isArray(functions) || functions.length === 0) {
|
|
42014
43162
|
ctx.json(res, 400, { error: 'functions[] is required (e.g. ["readChat", "sendMessage"])' });
|
|
42015
43163
|
return;
|
|
42016
43164
|
}
|
|
43165
|
+
clearStaleAutoImplState(ctx, "new auto-implement request");
|
|
42017
43166
|
if (ctx.autoImplStatus.running) {
|
|
42018
43167
|
ctx.json(res, 409, { error: "Auto-implement already in progress", type: ctx.autoImplStatus.type });
|
|
42019
43168
|
return;
|
|
@@ -42031,7 +43180,55 @@ async (params) => {
|
|
|
42031
43180
|
return;
|
|
42032
43181
|
}
|
|
42033
43182
|
const providerDir = writableProvider.dir;
|
|
43183
|
+
ctx.autoImplStatus = { running: false, type, progress: [] };
|
|
43184
|
+
if (provider.category === "cli" && verification && (verification.fixtureName || verification.fixtureNames && verification.fixtureNames.length > 0)) {
|
|
43185
|
+
sendAutoImplSSE(ctx, {
|
|
43186
|
+
event: "progress",
|
|
43187
|
+
data: {
|
|
43188
|
+
function: "_preflight",
|
|
43189
|
+
status: "verifying",
|
|
43190
|
+
message: "Running preflight verification before spawning agent..."
|
|
43191
|
+
}
|
|
43192
|
+
});
|
|
43193
|
+
try {
|
|
43194
|
+
const preflight = await runCliAutoImplVerification(ctx, type, verification);
|
|
43195
|
+
sendAutoImplSSE(ctx, { event: "verification", data: preflight });
|
|
43196
|
+
if (preflight.pass) {
|
|
43197
|
+
sendAutoImplSSE(ctx, {
|
|
43198
|
+
event: "complete",
|
|
43199
|
+
data: {
|
|
43200
|
+
success: true,
|
|
43201
|
+
exitCode: 0,
|
|
43202
|
+
functions,
|
|
43203
|
+
message: `\u2705 No-op: exact ${preflight.mode} already passes`,
|
|
43204
|
+
verification: preflight,
|
|
43205
|
+
skipped: true
|
|
43206
|
+
}
|
|
43207
|
+
});
|
|
43208
|
+
ctx.json(res, 200, {
|
|
43209
|
+
started: false,
|
|
43210
|
+
skipped: true,
|
|
43211
|
+
type,
|
|
43212
|
+
functions,
|
|
43213
|
+
providerDir,
|
|
43214
|
+
verification: preflight,
|
|
43215
|
+
message: "Preflight verification already passes. No auto-implement run needed."
|
|
43216
|
+
});
|
|
43217
|
+
return;
|
|
43218
|
+
}
|
|
43219
|
+
} catch (error48) {
|
|
43220
|
+
sendAutoImplSSE(ctx, {
|
|
43221
|
+
event: "progress",
|
|
43222
|
+
data: {
|
|
43223
|
+
function: "_preflight",
|
|
43224
|
+
status: "verify_failed",
|
|
43225
|
+
message: `Preflight verification errored, continuing to agent run: ${error48?.message || error48}`
|
|
43226
|
+
}
|
|
43227
|
+
});
|
|
43228
|
+
}
|
|
43229
|
+
}
|
|
42034
43230
|
try {
|
|
43231
|
+
ctx.autoImplStatus = { running: true, type, progress: ctx.autoImplStatus.progress };
|
|
42035
43232
|
const resolvedReference = resolveAutoImplReference(ctx, provider.category, reference, type);
|
|
42036
43233
|
sendAutoImplSSE(ctx, {
|
|
42037
43234
|
event: "progress",
|
|
@@ -42051,17 +43248,17 @@ async (params) => {
|
|
|
42051
43248
|
}
|
|
42052
43249
|
});
|
|
42053
43250
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
42054
|
-
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference);
|
|
42055
|
-
const tmpDir =
|
|
42056
|
-
if (!
|
|
42057
|
-
const promptFile =
|
|
42058
|
-
|
|
43251
|
+
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
43252
|
+
const tmpDir = path17.join(os17.tmpdir(), "adhdev-autoimpl");
|
|
43253
|
+
if (!fs13.existsSync(tmpDir)) fs13.mkdirSync(tmpDir, { recursive: true });
|
|
43254
|
+
const promptFile = path17.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
43255
|
+
fs13.writeFileSync(promptFile, prompt, "utf-8");
|
|
42059
43256
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
42060
43257
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
42061
43258
|
const spawn4 = agentProvider?.spawn;
|
|
42062
43259
|
if (!spawn4?.command) {
|
|
42063
43260
|
try {
|
|
42064
|
-
|
|
43261
|
+
fs13.unlinkSync(promptFile);
|
|
42065
43262
|
} catch {
|
|
42066
43263
|
}
|
|
42067
43264
|
ctx.json(res, 400, { error: `Agent '${agent}' has no spawn config. Select a CLI provider with a spawn configuration.` });
|
|
@@ -42070,7 +43267,8 @@ async (params) => {
|
|
|
42070
43267
|
const agentCategory = agentProvider?.category;
|
|
42071
43268
|
if (agentCategory === "acp") {
|
|
42072
43269
|
sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning ACP agent: ${spawn4.command} ${(spawn4.args || []).join(" ")}` } });
|
|
42073
|
-
ctx.autoImplStatus =
|
|
43270
|
+
ctx.autoImplStatus.running = true;
|
|
43271
|
+
ctx.autoImplStatus.type = type;
|
|
42074
43272
|
const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
|
|
42075
43273
|
const { Readable: Readable2, Writable: Writable2 } = await import("stream");
|
|
42076
43274
|
const { spawn: spawnFn2 } = await import("child_process");
|
|
@@ -42162,7 +43360,7 @@ async (params) => {
|
|
|
42162
43360
|
} catch {
|
|
42163
43361
|
}
|
|
42164
43362
|
try {
|
|
42165
|
-
|
|
43363
|
+
fs13.unlinkSync(promptFile);
|
|
42166
43364
|
} catch {
|
|
42167
43365
|
}
|
|
42168
43366
|
ctx.log(`Auto-implement (ACP) ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
@@ -42240,7 +43438,8 @@ async (params) => {
|
|
|
42240
43438
|
}
|
|
42241
43439
|
}
|
|
42242
43440
|
sendAutoImplSSE(ctx, { event: "progress", data: { function: "_init", status: "spawning", message: `Spawning agent: ${shellCmd.substring(0, 200)}... (prompt: ${prompt.length} chars)` } });
|
|
42243
|
-
ctx.autoImplStatus =
|
|
43441
|
+
ctx.autoImplStatus.running = true;
|
|
43442
|
+
ctx.autoImplStatus.type = type;
|
|
42244
43443
|
const spawnedAt = Date.now();
|
|
42245
43444
|
let child;
|
|
42246
43445
|
let isPty = false;
|
|
@@ -42283,6 +43482,7 @@ async (params) => {
|
|
|
42283
43482
|
let approvalKeys = { 0: "y\r" };
|
|
42284
43483
|
let approvalBuffer = "";
|
|
42285
43484
|
let lastApprovalTime = 0;
|
|
43485
|
+
let completionSignalSeen = false;
|
|
42286
43486
|
try {
|
|
42287
43487
|
const { normalizeCliProviderForRuntime: normalizeCliProviderForRuntime2 } = await Promise.resolve().then(() => (init_provider_cli_adapter(), provider_cli_adapter_exports));
|
|
42288
43488
|
const normalized = normalizeCliProviderForRuntime2(agentProvider);
|
|
@@ -42296,6 +43496,7 @@ async (params) => {
|
|
|
42296
43496
|
approvalBuffer = (approvalBuffer + cleanData).slice(-1500);
|
|
42297
43497
|
const elapsed = Date.now() - spawnedAt;
|
|
42298
43498
|
if (elapsed > 15e3 && cleanData.includes("_PIPELINE_COMPLETE_SIGNAL_")) {
|
|
43499
|
+
completionSignalSeen = true;
|
|
42299
43500
|
ctx.log(`Agent finished task after ${Math.round(elapsed / 1e3)}s. Terminating interactive CLI session to unblock pipeline.`);
|
|
42300
43501
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk: `
|
|
42301
43502
|
[\u{1F916} ADHDev Pipeline] Completion token detected. Proceeding...
|
|
@@ -42319,6 +43520,55 @@ async (params) => {
|
|
|
42319
43520
|
lastApprovalTime = Date.now();
|
|
42320
43521
|
}
|
|
42321
43522
|
};
|
|
43523
|
+
const finalizeCliAutoImpl = async (code) => {
|
|
43524
|
+
ctx.autoImplProcess = null;
|
|
43525
|
+
let success2 = completionSignalSeen || code === 0;
|
|
43526
|
+
let message = success2 ? completionSignalSeen && code !== 0 ? "\u2705 Auto-implement complete (completion signal)" : "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`;
|
|
43527
|
+
let verificationSummary = null;
|
|
43528
|
+
try {
|
|
43529
|
+
ctx.providerLoader.reload();
|
|
43530
|
+
} catch {
|
|
43531
|
+
}
|
|
43532
|
+
if (provider.category === "cli" && verification) {
|
|
43533
|
+
sendAutoImplSSE(ctx, {
|
|
43534
|
+
event: "progress",
|
|
43535
|
+
data: {
|
|
43536
|
+
function: "_verify",
|
|
43537
|
+
status: "running",
|
|
43538
|
+
message: "Running exact post-patch verification..."
|
|
43539
|
+
}
|
|
43540
|
+
});
|
|
43541
|
+
try {
|
|
43542
|
+
verificationSummary = await runCliAutoImplVerification(ctx, type, verification);
|
|
43543
|
+
sendAutoImplSSE(ctx, { event: "verification", data: verificationSummary });
|
|
43544
|
+
success2 = verificationSummary.pass;
|
|
43545
|
+
message = verificationSummary.pass ? `\u2705 Auto-implement complete (${verificationSummary.mode})` : `\u274C Post-patch verification failed (${verificationSummary.mode}): ${verificationSummary.failures.join("; ") || "unknown failure"}`;
|
|
43546
|
+
} catch (error48) {
|
|
43547
|
+
success2 = false;
|
|
43548
|
+
message = `\u274C Post-patch verification error: ${error48?.message || error48}`;
|
|
43549
|
+
sendAutoImplSSE(ctx, {
|
|
43550
|
+
event: "verification",
|
|
43551
|
+
data: { pass: false, error: error48?.message || String(error48) }
|
|
43552
|
+
});
|
|
43553
|
+
}
|
|
43554
|
+
}
|
|
43555
|
+
ctx.autoImplStatus.running = false;
|
|
43556
|
+
sendAutoImplSSE(ctx, {
|
|
43557
|
+
event: "complete",
|
|
43558
|
+
data: {
|
|
43559
|
+
success: success2,
|
|
43560
|
+
exitCode: code,
|
|
43561
|
+
functions,
|
|
43562
|
+
message,
|
|
43563
|
+
verification: verificationSummary
|
|
43564
|
+
}
|
|
43565
|
+
});
|
|
43566
|
+
try {
|
|
43567
|
+
fs13.unlinkSync(promptFile);
|
|
43568
|
+
} catch {
|
|
43569
|
+
}
|
|
43570
|
+
ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})${verificationSummary ? ` verify=${verificationSummary.pass ? "pass" : "fail"}` : ""}`);
|
|
43571
|
+
};
|
|
42322
43572
|
if (isPty) {
|
|
42323
43573
|
child.onData((data) => {
|
|
42324
43574
|
stdout += data;
|
|
@@ -42330,21 +43580,7 @@ async (params) => {
|
|
|
42330
43580
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk: data, stream: "stdout" } });
|
|
42331
43581
|
});
|
|
42332
43582
|
child.onExit(({ exitCode: code }) => {
|
|
42333
|
-
|
|
42334
|
-
ctx.autoImplStatus.running = false;
|
|
42335
|
-
const success2 = code === 0;
|
|
42336
|
-
sendAutoImplSSE(ctx, {
|
|
42337
|
-
event: "complete",
|
|
42338
|
-
data: { success: success2, exitCode: code, functions, message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})` }
|
|
42339
|
-
});
|
|
42340
|
-
try {
|
|
42341
|
-
ctx.providerLoader.reload();
|
|
42342
|
-
} catch {
|
|
42343
|
-
}
|
|
42344
|
-
try {
|
|
42345
|
-
fs12.unlinkSync(promptFile);
|
|
42346
|
-
} catch {
|
|
42347
|
-
}
|
|
43583
|
+
void finalizeCliAutoImpl(code);
|
|
42348
43584
|
});
|
|
42349
43585
|
} else {
|
|
42350
43586
|
child.stdout?.on("data", (d) => {
|
|
@@ -42361,27 +43597,7 @@ async (params) => {
|
|
|
42361
43597
|
sendAutoImplSSE(ctx, { event: "output", data: { chunk, stream: "stderr" } });
|
|
42362
43598
|
});
|
|
42363
43599
|
child.on("exit", (code) => {
|
|
42364
|
-
|
|
42365
|
-
ctx.autoImplStatus.running = false;
|
|
42366
|
-
const success2 = code === 0;
|
|
42367
|
-
sendAutoImplSSE(ctx, {
|
|
42368
|
-
event: "complete",
|
|
42369
|
-
data: {
|
|
42370
|
-
success: success2,
|
|
42371
|
-
exitCode: code,
|
|
42372
|
-
functions,
|
|
42373
|
-
message: success2 ? "\u2705 Auto-implement complete" : `\u274C Agent exited (code: ${code})`
|
|
42374
|
-
}
|
|
42375
|
-
});
|
|
42376
|
-
try {
|
|
42377
|
-
ctx.providerLoader.reload();
|
|
42378
|
-
} catch {
|
|
42379
|
-
}
|
|
42380
|
-
try {
|
|
42381
|
-
fs12.unlinkSync(promptFile);
|
|
42382
|
-
} catch {
|
|
42383
|
-
}
|
|
42384
|
-
ctx.log(`Auto-implement ${success2 ? "completed" : "failed"}: ${type} (exit: ${code})`);
|
|
43600
|
+
void finalizeCliAutoImpl(code);
|
|
42385
43601
|
});
|
|
42386
43602
|
}
|
|
42387
43603
|
ctx.json(res, 202, {
|
|
@@ -42398,9 +43614,9 @@ async (params) => {
|
|
|
42398
43614
|
ctx.json(res, 500, { error: `Auto-implement failed: ${e.message}` });
|
|
42399
43615
|
}
|
|
42400
43616
|
}
|
|
42401
|
-
function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType) {
|
|
43617
|
+
function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, userComment, referenceType, verification) {
|
|
42402
43618
|
if (provider.category === "cli") {
|
|
42403
|
-
return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType);
|
|
43619
|
+
return buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification);
|
|
42404
43620
|
}
|
|
42405
43621
|
const lines = [];
|
|
42406
43622
|
lines.push("You are implementing browser automation scripts for an IDE provider.");
|
|
@@ -42425,7 +43641,7 @@ async (params) => {
|
|
|
42425
43641
|
setMode: "set_mode.js"
|
|
42426
43642
|
};
|
|
42427
43643
|
const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
|
|
42428
|
-
const scriptsDir =
|
|
43644
|
+
const scriptsDir = path17.join(providerDir, "scripts");
|
|
42429
43645
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
42430
43646
|
if (latestScriptsDir) {
|
|
42431
43647
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -42433,10 +43649,10 @@ async (params) => {
|
|
|
42433
43649
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
42434
43650
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
42435
43651
|
lines.push("");
|
|
42436
|
-
for (const file2 of
|
|
43652
|
+
for (const file2 of fs13.readdirSync(latestScriptsDir)) {
|
|
42437
43653
|
if (file2.endsWith(".js") && targetFileNames.has(file2)) {
|
|
42438
43654
|
try {
|
|
42439
|
-
const content =
|
|
43655
|
+
const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
|
|
42440
43656
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
42441
43657
|
lines.push("```javascript");
|
|
42442
43658
|
lines.push(content);
|
|
@@ -42446,14 +43662,14 @@ async (params) => {
|
|
|
42446
43662
|
}
|
|
42447
43663
|
}
|
|
42448
43664
|
}
|
|
42449
|
-
const refFiles =
|
|
43665
|
+
const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
42450
43666
|
if (refFiles.length > 0) {
|
|
42451
43667
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
42452
43668
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
42453
43669
|
lines.push("");
|
|
42454
43670
|
for (const file2 of refFiles) {
|
|
42455
43671
|
try {
|
|
42456
|
-
const content =
|
|
43672
|
+
const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
|
|
42457
43673
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
42458
43674
|
lines.push("```javascript");
|
|
42459
43675
|
lines.push(content);
|
|
@@ -42494,11 +43710,11 @@ async (params) => {
|
|
|
42494
43710
|
lines.push("");
|
|
42495
43711
|
}
|
|
42496
43712
|
}
|
|
42497
|
-
const docsDir =
|
|
43713
|
+
const docsDir = path17.join(providerDir, "../../docs");
|
|
42498
43714
|
const loadGuide = (name) => {
|
|
42499
43715
|
try {
|
|
42500
|
-
const p =
|
|
42501
|
-
if (
|
|
43716
|
+
const p = path17.join(docsDir, name);
|
|
43717
|
+
if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
|
|
42502
43718
|
} catch {
|
|
42503
43719
|
}
|
|
42504
43720
|
return null;
|
|
@@ -42656,8 +43872,69 @@ async (params) => {
|
|
|
42656
43872
|
lines.push("Start NOW. Do not ask for permission. Explore the DOM -> Code -> Test.");
|
|
42657
43873
|
return lines.join("\n");
|
|
42658
43874
|
}
|
|
42659
|
-
function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType) {
|
|
43875
|
+
function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, referenceScripts, userComment, referenceType, verification) {
|
|
42660
43876
|
const lines = [];
|
|
43877
|
+
const defaultExercisePayload = {
|
|
43878
|
+
type,
|
|
43879
|
+
workingDir: providerDir,
|
|
43880
|
+
freshSession: true,
|
|
43881
|
+
autoLaunch: true,
|
|
43882
|
+
autoResolveApprovals: true,
|
|
43883
|
+
approvalButtonIndex: 0,
|
|
43884
|
+
timeoutMs: 45e3,
|
|
43885
|
+
traceLimit: 200,
|
|
43886
|
+
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."
|
|
43887
|
+
};
|
|
43888
|
+
const exercisePayload = {
|
|
43889
|
+
...defaultExercisePayload,
|
|
43890
|
+
...verification?.request || {},
|
|
43891
|
+
type,
|
|
43892
|
+
workingDir: providerDir
|
|
43893
|
+
};
|
|
43894
|
+
const exerciseJson = JSON.stringify(exercisePayload).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
|
|
43895
|
+
const verificationInspectFields = verification?.inspectFields?.length ? verification.inspectFields : [
|
|
43896
|
+
"debug.messages",
|
|
43897
|
+
"trace.entries[].payload.parsedLastAssistant",
|
|
43898
|
+
"trace.entries[].payload.lastAssistant"
|
|
43899
|
+
];
|
|
43900
|
+
const verificationMustContainAny = verification?.mustContainAny || [];
|
|
43901
|
+
const verificationMustNotContainAny = verification?.mustNotContainAny || [];
|
|
43902
|
+
const verificationMustMatchAny = verification?.mustMatchAny || [];
|
|
43903
|
+
const verificationMustNotMatchAny = verification?.mustNotMatchAny || [];
|
|
43904
|
+
const verificationLastAssistantMustContainAny = verification?.lastAssistantMustContainAny || [];
|
|
43905
|
+
const verificationLastAssistantMustNotContainAny = verification?.lastAssistantMustNotContainAny || [];
|
|
43906
|
+
const verificationLastAssistantMustMatchAny = verification?.lastAssistantMustMatchAny || [];
|
|
43907
|
+
const verificationLastAssistantMustNotMatchAny = verification?.lastAssistantMustNotMatchAny || [];
|
|
43908
|
+
const quotedMustContain = verificationMustContainAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43909
|
+
const quotedMustNotContain = verificationMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43910
|
+
const quotedMustMatch = verificationMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43911
|
+
const quotedMustNotMatch = verificationMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43912
|
+
const quotedLastAssistantMustContain = verificationLastAssistantMustContainAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43913
|
+
const quotedLastAssistantMustNotContain = verificationLastAssistantMustNotContainAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43914
|
+
const quotedLastAssistantMustMatch = verificationLastAssistantMustMatchAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43915
|
+
const quotedLastAssistantMustNotMatch = verificationLastAssistantMustNotMatchAny.map((value) => JSON.stringify(value)).join(", ");
|
|
43916
|
+
const fixtureName = verification?.fixtureName || `${type}-provider-fix`;
|
|
43917
|
+
const fixtureNames = Array.isArray(verification?.fixtureNames) ? verification.fixtureNames.map((value) => String(value || "").trim()).filter(Boolean) : [];
|
|
43918
|
+
const fixtureCaptureJson = JSON.stringify({
|
|
43919
|
+
type,
|
|
43920
|
+
name: fixtureName,
|
|
43921
|
+
request: exercisePayload,
|
|
43922
|
+
assertions: {
|
|
43923
|
+
mustContainAny: verificationMustContainAny,
|
|
43924
|
+
mustNotContainAny: verificationMustNotContainAny,
|
|
43925
|
+
mustMatchAny: verificationMustMatchAny,
|
|
43926
|
+
mustNotMatchAny: verificationMustNotMatchAny,
|
|
43927
|
+
lastAssistantMustContainAny: verificationLastAssistantMustContainAny,
|
|
43928
|
+
lastAssistantMustNotContainAny: verificationLastAssistantMustNotContainAny,
|
|
43929
|
+
lastAssistantMustMatchAny: verificationLastAssistantMustMatchAny,
|
|
43930
|
+
lastAssistantMustNotMatchAny: verificationLastAssistantMustNotMatchAny,
|
|
43931
|
+
requireNotTimedOut: true
|
|
43932
|
+
}
|
|
43933
|
+
}).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
|
|
43934
|
+
const fixtureReplayJson = JSON.stringify({
|
|
43935
|
+
type,
|
|
43936
|
+
name: fixtureName
|
|
43937
|
+
}).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
|
|
42661
43938
|
lines.push("You are implementing PTY parsing scripts for a CLI provider.");
|
|
42662
43939
|
lines.push("Be concise. Do NOT explain your reasoning. Edit files directly and verify with the local DevServer.");
|
|
42663
43940
|
lines.push("");
|
|
@@ -42671,7 +43948,7 @@ async (params) => {
|
|
|
42671
43948
|
parseApproval: "parse_approval.js"
|
|
42672
43949
|
};
|
|
42673
43950
|
const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
|
|
42674
|
-
const scriptsDir =
|
|
43951
|
+
const scriptsDir = path17.join(providerDir, "scripts");
|
|
42675
43952
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
42676
43953
|
if (latestScriptsDir) {
|
|
42677
43954
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -42679,11 +43956,11 @@ async (params) => {
|
|
|
42679
43956
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
42680
43957
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
42681
43958
|
lines.push("");
|
|
42682
|
-
for (const file2 of
|
|
43959
|
+
for (const file2 of fs13.readdirSync(latestScriptsDir)) {
|
|
42683
43960
|
if (!file2.endsWith(".js")) continue;
|
|
42684
43961
|
if (!targetFileNames.has(file2)) continue;
|
|
42685
43962
|
try {
|
|
42686
|
-
const content =
|
|
43963
|
+
const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
|
|
42687
43964
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
42688
43965
|
lines.push("```javascript");
|
|
42689
43966
|
lines.push(content);
|
|
@@ -42692,14 +43969,14 @@ async (params) => {
|
|
|
42692
43969
|
} catch {
|
|
42693
43970
|
}
|
|
42694
43971
|
}
|
|
42695
|
-
const refFiles =
|
|
43972
|
+
const refFiles = fs13.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
42696
43973
|
if (refFiles.length > 0) {
|
|
42697
43974
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
42698
43975
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
42699
43976
|
lines.push("");
|
|
42700
43977
|
for (const file2 of refFiles) {
|
|
42701
43978
|
try {
|
|
42702
|
-
const content =
|
|
43979
|
+
const content = fs13.readFileSync(path17.join(latestScriptsDir, file2), "utf-8");
|
|
42703
43980
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
42704
43981
|
lines.push("```javascript");
|
|
42705
43982
|
lines.push(content);
|
|
@@ -42732,17 +44009,17 @@ async (params) => {
|
|
|
42732
44009
|
lines.push("");
|
|
42733
44010
|
}
|
|
42734
44011
|
}
|
|
42735
|
-
const docsDir =
|
|
44012
|
+
const docsDir = path17.join(providerDir, "../../docs");
|
|
42736
44013
|
const loadGuide = (name) => {
|
|
42737
44014
|
try {
|
|
42738
|
-
const p =
|
|
42739
|
-
if (
|
|
44015
|
+
const p = path17.join(docsDir, name);
|
|
44016
|
+
if (fs13.existsSync(p)) return fs13.readFileSync(p, "utf-8");
|
|
42740
44017
|
} catch {
|
|
42741
44018
|
}
|
|
42742
44019
|
return null;
|
|
42743
44020
|
};
|
|
42744
44021
|
const providerGuide = loadGuide("PROVIDER_GUIDE.md");
|
|
42745
|
-
if (providerGuide) {
|
|
44022
|
+
if (providerGuide && provider.category !== "cli") {
|
|
42746
44023
|
lines.push("## Documentation: PROVIDER_GUIDE.md");
|
|
42747
44024
|
lines.push("```markdown");
|
|
42748
44025
|
lines.push(providerGuide);
|
|
@@ -42784,6 +44061,11 @@ async (params) => {
|
|
|
42784
44061
|
lines.push("13. After the first successful live repro, stop broad diagnosis. Edit the scripts, reload, and verify. Do not burn tokens on repeated re-inspection without code changes.");
|
|
42785
44062
|
lines.push("14. If the visible current screen is clean and sufficient, do NOT fall back to complex buffer heuristics. Simpler current-screen parsing is preferred.");
|
|
42786
44063
|
lines.push("15. Before changing parser logic, verify whether `provider.json` submit/approval behavior (`sendDelayMs`, `approvalKeys`, submit strategy) is the simpler and more correct fix.");
|
|
44064
|
+
lines.push('16. Do NOT patch transcript bugs by piling up one-off literal string exceptions (`includes("foo")`, `=== "bar"`, ad hoc allowlists/denylists) for every observed variant. Model the UI as PATTERN FAMILIES using reusable regex classifiers and normalization first.');
|
|
44065
|
+
lines.push("17. If you find yourself adding a second or third near-duplicate literal check for spinner words, tool headers, approval prompts, footer chrome, or OSC residue, STOP and replace them with a broader regex or helper classifier.");
|
|
44066
|
+
lines.push('18. Prefer a small number of named classifiers such as "status line", "tool header", "tool detail", "footer chrome", "approval cue", "prompt line", and "OSC residue" over a long chain of unrelated string checks.');
|
|
44067
|
+
lines.push("19. Literal string checks are allowed only for stable proper nouns or exact product chrome that cannot be expressed safely as a broader pattern. Everything else should generalize.");
|
|
44068
|
+
lines.push("20. When a bug comes from noisy PTY text, first normalize and classify the line family; do NOT just append another special-case substring to the parser.");
|
|
42787
44069
|
lines.push("");
|
|
42788
44070
|
lines.push("## Task");
|
|
42789
44071
|
lines.push(`Edit files in \`${providerDir}\` to implement: **${functions.join(", ")}**`);
|
|
@@ -42791,35 +44073,145 @@ async (params) => {
|
|
|
42791
44073
|
lines.push("## Verification API");
|
|
42792
44074
|
lines.push("Use the DevServer CLI debug endpoints, not DOM/CDP routes.");
|
|
42793
44075
|
lines.push("");
|
|
42794
|
-
lines.push("### 1.
|
|
44076
|
+
lines.push("### 1. Preferred: run a full autonomous repro");
|
|
44077
|
+
lines.push("Use the exercise endpoint first. It launches a fresh CLI session, sends the repro prompt, auto-resolves approvals, waits for the session to settle, and returns the final debug + trace payload in one response.");
|
|
42795
44078
|
lines.push("```bash");
|
|
42796
|
-
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/
|
|
44079
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
|
|
42797
44080
|
lines.push(' -H "Content-Type: application/json" \\');
|
|
42798
|
-
lines.push(` -d '
|
|
44081
|
+
lines.push(` -d '${exerciseJson}'`);
|
|
42799
44082
|
lines.push("```");
|
|
42800
44083
|
lines.push("");
|
|
44084
|
+
if (verification?.description) {
|
|
44085
|
+
lines.push("Verification intent:");
|
|
44086
|
+
lines.push(verification.description);
|
|
44087
|
+
lines.push("");
|
|
44088
|
+
}
|
|
44089
|
+
lines.push("Read the JSON response carefully. It already includes:");
|
|
44090
|
+
lines.push("1. `instanceId`");
|
|
44091
|
+
lines.push("2. `statusesSeen` and `approvalsResolved`");
|
|
44092
|
+
lines.push("3. `debug` for the final settled state");
|
|
44093
|
+
lines.push("4. `trace.entries` for the repro turn");
|
|
44094
|
+
lines.push("");
|
|
44095
|
+
lines.push("Save the response to a temp file and inspect the exact parsed transcript fields before editing:");
|
|
44096
|
+
lines.push("```bash");
|
|
44097
|
+
lines.push(`EXERCISE_JSON=$(mktemp)`);
|
|
44098
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/exercise \\`);
|
|
44099
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
44100
|
+
lines.push(` -d '${exerciseJson}' > "$EXERCISE_JSON"`);
|
|
44101
|
+
lines.push(`jq '{timedOut,statusesSeen,approvalsResolved,inspect:{${verificationInspectFields.map((field, index) => `f${index + 1}: .${field}`).join(", ")}}}' "$EXERCISE_JSON"`);
|
|
44102
|
+
lines.push("```");
|
|
44103
|
+
lines.push("");
|
|
44104
|
+
if (verificationMustContainAny.length > 0 || verificationMustNotContainAny.length > 0 || verificationMustMatchAny.length > 0 || verificationMustNotMatchAny.length > 0 || verificationLastAssistantMustContainAny.length > 0 || verificationLastAssistantMustNotContainAny.length > 0 || verificationLastAssistantMustMatchAny.length > 0 || verificationLastAssistantMustNotMatchAny.length > 0) {
|
|
44105
|
+
lines.push("The exact repro below is mandatory. Do NOT declare success unless these transcript assertions pass on the exercise JSON from the PATCHED provider.");
|
|
44106
|
+
lines.push("```bash");
|
|
44107
|
+
if (verificationMustContainAny.length > 0) {
|
|
44108
|
+
lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const required=[${quotedMustContain}];const missing=required.filter(v=>!text.includes(v));if(missing.length){console.error("Missing required substrings:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44109
|
+
}
|
|
44110
|
+
if (verificationMustNotContainAny.length > 0) {
|
|
44111
|
+
lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const banned=[${quotedMustNotContain}];const hits=banned.filter(v=>text.includes(v));if(hits.length){console.error("Found banned substrings:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44112
|
+
}
|
|
44113
|
+
if (verificationMustMatchAny.length > 0) {
|
|
44114
|
+
lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const required=[${quotedMustMatch}].map(v=>new RegExp(v,"m"));const missing=required.filter(v=>!v.test(text)).map(v=>String(v));if(missing.length){console.error("Missing required regex matches:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44115
|
+
}
|
|
44116
|
+
if (verificationMustNotMatchAny.length > 0) {
|
|
44117
|
+
lines.push(`node -e 'const fs=require("fs");const text=fs.readFileSync(process.argv[1],"utf8");const banned=[${quotedMustNotMatch}].map(v=>new RegExp(v,"m"));const hits=banned.filter(v=>v.test(text)).map(v=>String(v));if(hits.length){console.error("Found banned regex matches:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44118
|
+
}
|
|
44119
|
+
if (verificationLastAssistantMustContainAny.length > 0) {
|
|
44120
|
+
lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const required=[${quotedLastAssistantMustContain}];const missing=required.filter(v=>!text.includes(v));if(missing.length){console.error("Missing required lastAssistant substrings:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44121
|
+
}
|
|
44122
|
+
if (verificationLastAssistantMustNotContainAny.length > 0) {
|
|
44123
|
+
lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const banned=[${quotedLastAssistantMustNotContain}];const hits=banned.filter(v=>text.includes(v));if(hits.length){console.error("Found banned lastAssistant substrings:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44124
|
+
}
|
|
44125
|
+
if (verificationLastAssistantMustMatchAny.length > 0) {
|
|
44126
|
+
lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const required=[${quotedLastAssistantMustMatch}].map(v=>new RegExp(v,"m"));const missing=required.filter(v=>!v.test(text)).map(v=>String(v));if(missing.length){console.error("Missing required lastAssistant regex matches:\\n"+missing.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44127
|
+
}
|
|
44128
|
+
if (verificationLastAssistantMustNotMatchAny.length > 0) {
|
|
44129
|
+
lines.push(`node -e 'const fs=require("fs");const payload=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));const text=String(payload.lastAssistant||"");const banned=[${quotedLastAssistantMustNotMatch}].map(v=>new RegExp(v,"m"));const hits=banned.filter(v=>v.test(text)).map(v=>String(v));if(hits.length){console.error("Found banned lastAssistant regex matches:\\n"+hits.join("\\n"));process.exit(1);}' "$EXERCISE_JSON"`);
|
|
44130
|
+
}
|
|
44131
|
+
lines.push("```");
|
|
44132
|
+
lines.push("");
|
|
44133
|
+
}
|
|
44134
|
+
lines.push("If you need a manual follow-up repro after patching, use the SAME endpoint again with the SAME prompt and compare the new trace to the previous one.");
|
|
44135
|
+
lines.push("");
|
|
44136
|
+
lines.push("### 1b. Persist or replay the exact repro as a reusable fixture");
|
|
44137
|
+
if (fixtureNames.length > 0) {
|
|
44138
|
+
lines.push(`Replay this exact fixture suite before editing, and replay the SAME suite again after patching. Do not declare success unless EVERY fixture passes: ${fixtureNames.map((name) => `\`${name}\``).join(", ")}.`);
|
|
44139
|
+
for (const name of fixtureNames) {
|
|
44140
|
+
const replayJson = JSON.stringify({ type, name }).replace(/\\/g, "\\\\").replace(/'/g, `'\\''`);
|
|
44141
|
+
lines.push("```bash");
|
|
44142
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
|
|
44143
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
44144
|
+
lines.push(` -d '${replayJson}'`);
|
|
44145
|
+
lines.push("```");
|
|
44146
|
+
lines.push("");
|
|
44147
|
+
}
|
|
44148
|
+
lines.push("Do not create new fixtures unless one of the listed fixtures is missing or stale.");
|
|
44149
|
+
} else if (verification?.fixtureName) {
|
|
44150
|
+
lines.push(`Replay the EXISTING saved fixture \`${fixtureName}\` before editing, and replay the SAME fixture again after patching. Do not declare success unless that exact fixture passes.`);
|
|
44151
|
+
lines.push("```bash");
|
|
44152
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
|
|
44153
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
44154
|
+
lines.push(` -d '${fixtureReplayJson}'`);
|
|
44155
|
+
lines.push("```");
|
|
44156
|
+
lines.push("");
|
|
44157
|
+
lines.push("Only if the named fixture is missing or outdated should you recapture it. Prefer replaying the existing failing fixture over creating a new one.");
|
|
44158
|
+
lines.push("```bash");
|
|
44159
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
|
|
44160
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
44161
|
+
lines.push(` -d '${fixtureCaptureJson}'`);
|
|
44162
|
+
lines.push("```");
|
|
44163
|
+
} else {
|
|
44164
|
+
lines.push("Capture the exact exercise once before editing. After patching, replay THIS fixture and do not declare success unless replay passes.");
|
|
44165
|
+
lines.push("```bash");
|
|
44166
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/capture \\`);
|
|
44167
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
44168
|
+
lines.push(` -d '${fixtureCaptureJson}'`);
|
|
44169
|
+
lines.push("");
|
|
44170
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/fixture/replay \\`);
|
|
44171
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
44172
|
+
lines.push(` -d '${fixtureReplayJson}'`);
|
|
44173
|
+
lines.push("```");
|
|
44174
|
+
}
|
|
44175
|
+
lines.push("");
|
|
44176
|
+
lines.push("The capture endpoint saves the exact request, initial result, and transcript assertions into the provider directory. The replay endpoint reruns the SAME exercise against your patched scripts and returns pass/fail.");
|
|
44177
|
+
lines.push("");
|
|
42801
44178
|
lines.push("### 2. Inspect parsed + raw adapter state");
|
|
42802
44179
|
lines.push("```bash");
|
|
44180
|
+
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/launch \\`);
|
|
44181
|
+
lines.push(' -H "Content-Type: application/json" \\');
|
|
44182
|
+
lines.push(` -d '{"type":"${type}","workingDir":"${providerDir.replace(/\\/g, "\\\\")}"}'`);
|
|
42803
44183
|
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
|
|
44184
|
+
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
|
|
42804
44185
|
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
|
|
42805
44186
|
lines.push("```");
|
|
42806
44187
|
lines.push("");
|
|
44188
|
+
lines.push("The CLI trace endpoint is the primary debugging source. Read it BEFORE editing any parser code.");
|
|
44189
|
+
lines.push("Use the trace timeline to find the latest `settled` or `commit_transcript` frame for the repro turn and inspect these fields first:");
|
|
44190
|
+
lines.push("1. `payload.screenText`");
|
|
44191
|
+
lines.push("2. `payload.detectStatus` and `payload.parsedStatus`");
|
|
44192
|
+
lines.push("3. `payload.parsedLastAssistant`");
|
|
44193
|
+
lines.push("4. `payload.approval` / `payload.parsedActiveModal`");
|
|
44194
|
+
lines.push("5. `payload.rawPreview` only when control-sequence residue matters");
|
|
44195
|
+
lines.push("");
|
|
42807
44196
|
lines.push("The debug payload should be read in this priority order:");
|
|
42808
44197
|
lines.push("1. `screenText` / current visible state");
|
|
42809
44198
|
lines.push("2. parsed `status`, `messages`, `activeModal`");
|
|
42810
44199
|
lines.push("3. `rawBuffer` only for style/control-sequence cues");
|
|
42811
44200
|
lines.push("4. `buffer` only when the current screen is insufficient");
|
|
42812
44201
|
lines.push("");
|
|
42813
|
-
lines.push("
|
|
44202
|
+
lines.push("If the bug is transcript corruption, quote the exact bad `parsedLastAssistant` or bad committed assistant message from the trace and patch against that concrete failure.");
|
|
44203
|
+
lines.push("Do NOT guess based only on the final chat bubble or a truncated UI preview.");
|
|
42814
44204
|
lines.push("");
|
|
42815
|
-
lines.push("
|
|
44205
|
+
lines.push("Extract the current `instanceId` from the exercise, launch, or status response and keep using it below.");
|
|
44206
|
+
lines.push("");
|
|
44207
|
+
lines.push("### 3. Manual fallback only: send a realistic approval-triggering prompt");
|
|
42816
44208
|
lines.push("```bash");
|
|
42817
44209
|
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
|
|
42818
44210
|
lines.push(' -H "Content-Type: application/json" \\');
|
|
42819
44211
|
lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","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."}'`);
|
|
42820
44212
|
lines.push("```");
|
|
42821
44213
|
lines.push("");
|
|
42822
|
-
lines.push("### 4.
|
|
44214
|
+
lines.push("### 4. Manual fallback only: if approval appears, resolve it until the CLI reaches idle");
|
|
42823
44215
|
lines.push("```bash");
|
|
42824
44216
|
lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
|
|
42825
44217
|
lines.push(' -H "Content-Type: application/json" \\');
|
|
@@ -42829,10 +44221,14 @@ async (params) => {
|
|
|
42829
44221
|
lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
|
|
42830
44222
|
lines.push("```");
|
|
42831
44223
|
lines.push("");
|
|
42832
|
-
lines.push("Use `resolve` when the parsed modal buttons are correct. Use `raw` when the CLI expects a literal keystroke like `1`, `y`, or Enter. Repeat until idle.");
|
|
44224
|
+
lines.push("Use `resolve` when the parsed modal buttons are correct. Use `raw` when the CLI expects a literal keystroke like `1`, `y`, or Enter. Repeat until idle. Prefer the exercise endpoint instead of doing this by hand.");
|
|
42833
44225
|
lines.push("");
|
|
42834
44226
|
lines.push("### Patch Discipline");
|
|
42835
44227
|
lines.push("Once the repro is confirmed, immediately edit the target files. Avoid loops where you keep re-reading long files or re-running the same debug commands without changing code.");
|
|
44228
|
+
lines.push("For CLI transcript bugs, reproduce once with the exercise endpoint, inspect the returned trace once, patch immediately, then re-run the SAME exercise and compare the new `commit_transcript` frame.");
|
|
44229
|
+
lines.push("If the patched run still fails the exact required/banned substring checks above, the task is NOT complete even if the CLI exits normally.");
|
|
44230
|
+
lines.push("When you patch, write down the pattern family you are fixing: e.g. spinner/status, tool block, approval modal, footer chrome, OSC/control residue, prompt echo, or long-output continuation. Patch that family once instead of adding case-by-case literals.");
|
|
44231
|
+
lines.push('Bad fix pattern: add another `includes("Drizzling")` or `includes("Show more (")` check. Good fix pattern: broaden the regex/helper that recognizes spinner words, collapsed tool overflow lines, or footer chrome as a family.');
|
|
42836
44232
|
lines.push("");
|
|
42837
44233
|
lines.push("### 5. Verify the side effects outside the CLI");
|
|
42838
44234
|
lines.push("```bash");
|
|
@@ -42857,6 +44253,8 @@ async (params) => {
|
|
|
42857
44253
|
lines.push("7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.");
|
|
42858
44254
|
lines.push("8. Confirm the parser still works after a redraw or scroll change without duplicating transcript history.");
|
|
42859
44255
|
lines.push("9. Confirm the implementation prefers current-screen signals over stale history when both are present.");
|
|
44256
|
+
lines.push("10. For transcript-cleanliness bugs, confirm the latest `commit_transcript` trace frame no longer contains tool headers, approval prompts, OSC residue like `0;`, or footer chrome unless they are truly user-facing answer content.");
|
|
44257
|
+
lines.push("11. Confirm the implementation uses generalized pattern classifiers or regexes for noisy UI families instead of accumulating one-off literal string exceptions for each observed sample.");
|
|
42860
44258
|
lines.push("");
|
|
42861
44259
|
if (userComment) {
|
|
42862
44260
|
lines.push("## \u26A0\uFE0F User Instructions (HIGH PRIORITY)");
|
|
@@ -42865,10 +44263,11 @@ async (params) => {
|
|
|
42865
44263
|
lines.push(userComment);
|
|
42866
44264
|
lines.push("");
|
|
42867
44265
|
}
|
|
42868
|
-
lines.push("Start NOW. Launch the CLI, inspect PTY state, edit the scripts, and verify via the CLI debug endpoints.");
|
|
44266
|
+
lines.push("Start NOW. Launch the CLI, inspect the trace and PTY state, edit the scripts, and verify via the CLI debug + trace endpoints.");
|
|
42869
44267
|
return lines.join("\n");
|
|
42870
44268
|
}
|
|
42871
44269
|
function handleAutoImplSSE(ctx, type, req, res) {
|
|
44270
|
+
clearStaleAutoImplState(ctx, "SSE connection opened");
|
|
42872
44271
|
res.writeHead(200, {
|
|
42873
44272
|
"Content-Type": "text/event-stream",
|
|
42874
44273
|
"Cache-Control": "no-cache",
|
|
@@ -42890,6 +44289,7 @@ data: ${JSON.stringify(p.data)}
|
|
|
42890
44289
|
});
|
|
42891
44290
|
}
|
|
42892
44291
|
function handleAutoImplCancel(ctx, _type, _req, res) {
|
|
44292
|
+
clearStaleAutoImplState(ctx, "cancel request");
|
|
42893
44293
|
if (ctx.autoImplProcess) {
|
|
42894
44294
|
ctx.autoImplProcess.kill("SIGTERM");
|
|
42895
44295
|
setTimeout(() => {
|
|
@@ -42971,11 +44371,16 @@ data: ${JSON.stringify(msg.data)}
|
|
|
42971
44371
|
{ method: "GET", pattern: "/api/cli/status", handler: (q2, s15) => this.handleCliStatus(q2, s15) },
|
|
42972
44372
|
{ method: "POST", pattern: "/api/cli/launch", handler: (q2, s15) => this.handleCliLaunch(q2, s15) },
|
|
42973
44373
|
{ method: "POST", pattern: "/api/cli/send", handler: (q2, s15) => this.handleCliSend(q2, s15) },
|
|
44374
|
+
{ method: "POST", pattern: "/api/cli/exercise", handler: (q2, s15) => this.handleCliExercise(q2, s15) },
|
|
44375
|
+
{ method: "POST", pattern: "/api/cli/fixture/capture", handler: (q2, s15) => this.handleCliFixtureCapture(q2, s15) },
|
|
44376
|
+
{ method: "POST", pattern: "/api/cli/fixture/replay", handler: (q2, s15) => this.handleCliFixtureReplay(q2, s15) },
|
|
42974
44377
|
{ method: "POST", pattern: "/api/cli/resolve", handler: (q2, s15) => this.handleCliResolve(q2, s15) },
|
|
42975
44378
|
{ method: "POST", pattern: "/api/cli/raw", handler: (q2, s15) => this.handleCliRaw(q2, s15) },
|
|
42976
44379
|
{ method: "POST", pattern: "/api/cli/stop", handler: (q2, s15) => this.handleCliStop(q2, s15) },
|
|
42977
44380
|
{ method: "GET", pattern: "/api/cli/events", handler: (q2, s15) => this.handleCliSSE(q2, s15) },
|
|
42978
44381
|
{ method: "GET", pattern: /^\/api\/cli\/debug\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliDebug(p[0], q2, s15) },
|
|
44382
|
+
{ method: "GET", pattern: /^\/api\/cli\/trace\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliTrace(p[0], q2, s15) },
|
|
44383
|
+
{ method: "GET", pattern: /^\/api\/cli\/fixtures\/([^/]+)$/, handler: (q2, s15, p) => this.handleCliFixtureList(p[0], q2, s15) },
|
|
42979
44384
|
// Dynamic routes (provider :type param)
|
|
42980
44385
|
{ method: "POST", pattern: /^\/api\/providers\/([^/]+)\/script$/, handler: (q2, s15, p) => this.handleRunScript(p[0], q2, s15) },
|
|
42981
44386
|
{ method: "GET", pattern: /^\/api\/providers\/([^/]+)\/files$/, handler: (q2, s15, p) => this.handleListFiles(p[0], q2, s15) },
|
|
@@ -43009,8 +44414,8 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43009
44414
|
}
|
|
43010
44415
|
getEndpointList() {
|
|
43011
44416
|
return this.routes.map((r) => {
|
|
43012
|
-
const
|
|
43013
|
-
return `${r.method.padEnd(5)} ${
|
|
44417
|
+
const path19 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
44418
|
+
return `${r.method.padEnd(5)} ${path19}`;
|
|
43014
44419
|
});
|
|
43015
44420
|
}
|
|
43016
44421
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -43292,12 +44697,12 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43292
44697
|
// ─── DevConsole SPA ───
|
|
43293
44698
|
getConsoleDistDir() {
|
|
43294
44699
|
const candidates = [
|
|
43295
|
-
|
|
43296
|
-
|
|
43297
|
-
|
|
44700
|
+
path18.resolve(__dirname, "../../web-devconsole/dist"),
|
|
44701
|
+
path18.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
44702
|
+
path18.join(process.cwd(), "packages/web-devconsole/dist")
|
|
43298
44703
|
];
|
|
43299
44704
|
for (const dir of candidates) {
|
|
43300
|
-
if (
|
|
44705
|
+
if (fs14.existsSync(path18.join(dir, "index.html"))) return dir;
|
|
43301
44706
|
}
|
|
43302
44707
|
return null;
|
|
43303
44708
|
}
|
|
@@ -43307,9 +44712,9 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43307
44712
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
43308
44713
|
return;
|
|
43309
44714
|
}
|
|
43310
|
-
const htmlPath =
|
|
44715
|
+
const htmlPath = path18.join(distDir, "index.html");
|
|
43311
44716
|
try {
|
|
43312
|
-
const html =
|
|
44717
|
+
const html = fs14.readFileSync(htmlPath, "utf-8");
|
|
43313
44718
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
43314
44719
|
res.end(html);
|
|
43315
44720
|
} catch (e) {
|
|
@@ -43332,15 +44737,15 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43332
44737
|
this.json(res, 404, { error: "Not found" });
|
|
43333
44738
|
return;
|
|
43334
44739
|
}
|
|
43335
|
-
const safePath =
|
|
43336
|
-
const filePath =
|
|
44740
|
+
const safePath = path18.normalize(pathname).replace(/^\.\.\//, "");
|
|
44741
|
+
const filePath = path18.join(distDir, safePath);
|
|
43337
44742
|
if (!filePath.startsWith(distDir)) {
|
|
43338
44743
|
this.json(res, 403, { error: "Forbidden" });
|
|
43339
44744
|
return;
|
|
43340
44745
|
}
|
|
43341
44746
|
try {
|
|
43342
|
-
const content =
|
|
43343
|
-
const ext =
|
|
44747
|
+
const content = fs14.readFileSync(filePath);
|
|
44748
|
+
const ext = path18.extname(filePath);
|
|
43344
44749
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
43345
44750
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
43346
44751
|
res.end(content);
|
|
@@ -43448,14 +44853,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43448
44853
|
const files = [];
|
|
43449
44854
|
const scan = (d, prefix) => {
|
|
43450
44855
|
try {
|
|
43451
|
-
for (const entry of
|
|
44856
|
+
for (const entry of fs14.readdirSync(d, { withFileTypes: true })) {
|
|
43452
44857
|
if (entry.name.startsWith(".") || entry.name.endsWith(".bak")) continue;
|
|
43453
44858
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
43454
44859
|
if (entry.isDirectory()) {
|
|
43455
44860
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
43456
|
-
scan(
|
|
44861
|
+
scan(path18.join(d, entry.name), rel);
|
|
43457
44862
|
} else {
|
|
43458
|
-
const stat4 =
|
|
44863
|
+
const stat4 = fs14.statSync(path18.join(d, entry.name));
|
|
43459
44864
|
files.push({ path: rel, size: stat4.size, type: "file" });
|
|
43460
44865
|
}
|
|
43461
44866
|
}
|
|
@@ -43478,16 +44883,16 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43478
44883
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
43479
44884
|
return;
|
|
43480
44885
|
}
|
|
43481
|
-
const fullPath =
|
|
44886
|
+
const fullPath = path18.resolve(dir, path18.normalize(filePath));
|
|
43482
44887
|
if (!fullPath.startsWith(dir)) {
|
|
43483
44888
|
this.json(res, 403, { error: "Forbidden" });
|
|
43484
44889
|
return;
|
|
43485
44890
|
}
|
|
43486
|
-
if (!
|
|
44891
|
+
if (!fs14.existsSync(fullPath) || fs14.statSync(fullPath).isDirectory()) {
|
|
43487
44892
|
this.json(res, 404, { error: `File not found: ${filePath}` });
|
|
43488
44893
|
return;
|
|
43489
44894
|
}
|
|
43490
|
-
const content =
|
|
44895
|
+
const content = fs14.readFileSync(fullPath, "utf-8");
|
|
43491
44896
|
this.json(res, 200, { type, path: filePath, content, lines: content.split("\n").length });
|
|
43492
44897
|
}
|
|
43493
44898
|
/** POST /api/providers/:type/file — write a file { path, content } */
|
|
@@ -43503,15 +44908,15 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43503
44908
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
43504
44909
|
return;
|
|
43505
44910
|
}
|
|
43506
|
-
const fullPath =
|
|
44911
|
+
const fullPath = path18.resolve(dir, path18.normalize(filePath));
|
|
43507
44912
|
if (!fullPath.startsWith(dir)) {
|
|
43508
44913
|
this.json(res, 403, { error: "Forbidden" });
|
|
43509
44914
|
return;
|
|
43510
44915
|
}
|
|
43511
44916
|
try {
|
|
43512
|
-
if (
|
|
43513
|
-
|
|
43514
|
-
|
|
44917
|
+
if (fs14.existsSync(fullPath)) fs14.copyFileSync(fullPath, fullPath + ".bak");
|
|
44918
|
+
fs14.mkdirSync(path18.dirname(fullPath), { recursive: true });
|
|
44919
|
+
fs14.writeFileSync(fullPath, content, "utf-8");
|
|
43515
44920
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
43516
44921
|
this.providerLoader.reload();
|
|
43517
44922
|
this.json(res, 200, { saved: true, path: filePath, chars: content.length });
|
|
@@ -43527,9 +44932,9 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43527
44932
|
return;
|
|
43528
44933
|
}
|
|
43529
44934
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
43530
|
-
const p =
|
|
43531
|
-
if (
|
|
43532
|
-
const source =
|
|
44935
|
+
const p = path18.join(dir, name);
|
|
44936
|
+
if (fs14.existsSync(p)) {
|
|
44937
|
+
const source = fs14.readFileSync(p, "utf-8");
|
|
43533
44938
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
43534
44939
|
return;
|
|
43535
44940
|
}
|
|
@@ -43548,11 +44953,11 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43548
44953
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
43549
44954
|
return;
|
|
43550
44955
|
}
|
|
43551
|
-
const target =
|
|
43552
|
-
const targetPath =
|
|
44956
|
+
const target = fs14.existsSync(path18.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
44957
|
+
const targetPath = path18.join(dir, target);
|
|
43553
44958
|
try {
|
|
43554
|
-
if (
|
|
43555
|
-
|
|
44959
|
+
if (fs14.existsSync(targetPath)) fs14.copyFileSync(targetPath, targetPath + ".bak");
|
|
44960
|
+
fs14.writeFileSync(targetPath, source, "utf-8");
|
|
43556
44961
|
this.log(`Saved provider: ${targetPath} (${source.length} chars)`);
|
|
43557
44962
|
this.providerLoader.reload();
|
|
43558
44963
|
this.json(res, 200, { saved: true, path: targetPath, chars: source.length });
|
|
@@ -43709,21 +45114,21 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43709
45114
|
}
|
|
43710
45115
|
let targetDir;
|
|
43711
45116
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
43712
|
-
const jsonPath =
|
|
43713
|
-
if (
|
|
45117
|
+
const jsonPath = path18.join(targetDir, "provider.json");
|
|
45118
|
+
if (fs14.existsSync(jsonPath)) {
|
|
43714
45119
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
43715
45120
|
return;
|
|
43716
45121
|
}
|
|
43717
45122
|
try {
|
|
43718
45123
|
const result = generateFiles(type, name, category, { cdpPorts, cli, processName, installPath, binary, extensionId, version: version2, osPaths, processNames });
|
|
43719
|
-
|
|
43720
|
-
|
|
45124
|
+
fs14.mkdirSync(targetDir, { recursive: true });
|
|
45125
|
+
fs14.writeFileSync(jsonPath, result["provider.json"], "utf-8");
|
|
43721
45126
|
const createdFiles = ["provider.json"];
|
|
43722
45127
|
if (result.files) {
|
|
43723
45128
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
43724
|
-
const fullPath =
|
|
43725
|
-
|
|
43726
|
-
|
|
45129
|
+
const fullPath = path18.join(targetDir, relPath);
|
|
45130
|
+
fs14.mkdirSync(path18.dirname(fullPath), { recursive: true });
|
|
45131
|
+
fs14.writeFileSync(fullPath, content, "utf-8");
|
|
43727
45132
|
createdFiles.push(relPath);
|
|
43728
45133
|
}
|
|
43729
45134
|
}
|
|
@@ -43772,45 +45177,45 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43772
45177
|
}
|
|
43773
45178
|
// ─── Phase 2: Auto-Implement Backend ───
|
|
43774
45179
|
getLatestScriptVersionDir(scriptsDir) {
|
|
43775
|
-
if (!
|
|
43776
|
-
const versions =
|
|
45180
|
+
if (!fs14.existsSync(scriptsDir)) return null;
|
|
45181
|
+
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
43777
45182
|
try {
|
|
43778
|
-
return
|
|
45183
|
+
return fs14.statSync(path18.join(scriptsDir, d)).isDirectory();
|
|
43779
45184
|
} catch {
|
|
43780
45185
|
return false;
|
|
43781
45186
|
}
|
|
43782
45187
|
}).sort((a, b2) => b2.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
43783
45188
|
if (versions.length === 0) return null;
|
|
43784
|
-
return
|
|
45189
|
+
return path18.join(scriptsDir, versions[0]);
|
|
43785
45190
|
}
|
|
43786
45191
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
43787
|
-
const canonicalUserDir =
|
|
43788
|
-
const desiredDir = requestedDir ?
|
|
43789
|
-
const upstreamRoot =
|
|
43790
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
45192
|
+
const canonicalUserDir = path18.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
45193
|
+
const desiredDir = requestedDir ? path18.resolve(requestedDir) : canonicalUserDir;
|
|
45194
|
+
const upstreamRoot = path18.resolve(this.providerLoader.getUpstreamDir());
|
|
45195
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path18.sep}`)) {
|
|
43791
45196
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
43792
45197
|
}
|
|
43793
|
-
if (
|
|
45198
|
+
if (path18.basename(desiredDir) !== type) {
|
|
43794
45199
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
43795
45200
|
}
|
|
43796
45201
|
const sourceDir = this.findProviderDir(type);
|
|
43797
45202
|
if (!sourceDir) {
|
|
43798
45203
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
43799
45204
|
}
|
|
43800
|
-
if (!
|
|
43801
|
-
|
|
43802
|
-
|
|
45205
|
+
if (!fs14.existsSync(desiredDir)) {
|
|
45206
|
+
fs14.mkdirSync(path18.dirname(desiredDir), { recursive: true });
|
|
45207
|
+
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
43803
45208
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
43804
45209
|
}
|
|
43805
|
-
const providerJson =
|
|
43806
|
-
if (!
|
|
45210
|
+
const providerJson = path18.join(desiredDir, "provider.json");
|
|
45211
|
+
if (!fs14.existsSync(providerJson)) {
|
|
43807
45212
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
43808
45213
|
}
|
|
43809
45214
|
try {
|
|
43810
|
-
const providerData = JSON.parse(
|
|
45215
|
+
const providerData = JSON.parse(fs14.readFileSync(providerJson, "utf-8"));
|
|
43811
45216
|
if (providerData.disableUpstream !== true) {
|
|
43812
45217
|
providerData.disableUpstream = true;
|
|
43813
|
-
|
|
45218
|
+
fs14.writeFileSync(providerJson, JSON.stringify(providerData, null, 2));
|
|
43814
45219
|
}
|
|
43815
45220
|
} catch (error48) {
|
|
43816
45221
|
return {
|
|
@@ -43850,7 +45255,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43850
45255
|
setMode: "set_mode.js"
|
|
43851
45256
|
};
|
|
43852
45257
|
const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
|
|
43853
|
-
const scriptsDir =
|
|
45258
|
+
const scriptsDir = path18.join(providerDir, "scripts");
|
|
43854
45259
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
43855
45260
|
if (latestScriptsDir) {
|
|
43856
45261
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -43858,10 +45263,10 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43858
45263
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
43859
45264
|
lines.push("These are the ONLY files you are allowed to modify. Replace the TODO stubs with working implementations.");
|
|
43860
45265
|
lines.push("");
|
|
43861
|
-
for (const file2 of
|
|
45266
|
+
for (const file2 of fs14.readdirSync(latestScriptsDir)) {
|
|
43862
45267
|
if (file2.endsWith(".js") && targetFileNames.has(file2)) {
|
|
43863
45268
|
try {
|
|
43864
|
-
const content =
|
|
45269
|
+
const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
|
|
43865
45270
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
43866
45271
|
lines.push("```javascript");
|
|
43867
45272
|
lines.push(content);
|
|
@@ -43871,14 +45276,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43871
45276
|
}
|
|
43872
45277
|
}
|
|
43873
45278
|
}
|
|
43874
|
-
const refFiles =
|
|
45279
|
+
const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
43875
45280
|
if (refFiles.length > 0) {
|
|
43876
45281
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
43877
45282
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
43878
45283
|
lines.push("");
|
|
43879
45284
|
for (const file2 of refFiles) {
|
|
43880
45285
|
try {
|
|
43881
|
-
const content =
|
|
45286
|
+
const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
|
|
43882
45287
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
43883
45288
|
lines.push("```javascript");
|
|
43884
45289
|
lines.push(content);
|
|
@@ -43919,11 +45324,11 @@ data: ${JSON.stringify(msg.data)}
|
|
|
43919
45324
|
lines.push("");
|
|
43920
45325
|
}
|
|
43921
45326
|
}
|
|
43922
|
-
const docsDir =
|
|
45327
|
+
const docsDir = path18.join(providerDir, "../../docs");
|
|
43923
45328
|
const loadGuide = (name) => {
|
|
43924
45329
|
try {
|
|
43925
|
-
const p =
|
|
43926
|
-
if (
|
|
45330
|
+
const p = path18.join(docsDir, name);
|
|
45331
|
+
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
43927
45332
|
} catch {
|
|
43928
45333
|
}
|
|
43929
45334
|
return null;
|
|
@@ -44096,7 +45501,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44096
45501
|
parseApproval: "parse_approval.js"
|
|
44097
45502
|
};
|
|
44098
45503
|
const targetFileNames = new Set(functions.map((fn2) => funcToFile[fn2]).filter(Boolean));
|
|
44099
|
-
const scriptsDir =
|
|
45504
|
+
const scriptsDir = path18.join(providerDir, "scripts");
|
|
44100
45505
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
44101
45506
|
if (latestScriptsDir) {
|
|
44102
45507
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -44104,11 +45509,11 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44104
45509
|
lines.push("## \u270F\uFE0F Target Files (EDIT THESE)");
|
|
44105
45510
|
lines.push("These are the ONLY files you are allowed to modify. Replace TODO or heuristic-only logic with working PTY-aware implementations.");
|
|
44106
45511
|
lines.push("");
|
|
44107
|
-
for (const file2 of
|
|
45512
|
+
for (const file2 of fs14.readdirSync(latestScriptsDir)) {
|
|
44108
45513
|
if (!file2.endsWith(".js")) continue;
|
|
44109
45514
|
if (!targetFileNames.has(file2)) continue;
|
|
44110
45515
|
try {
|
|
44111
|
-
const content =
|
|
45516
|
+
const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
|
|
44112
45517
|
lines.push(`### \`${file2}\` \u270F\uFE0F EDIT`);
|
|
44113
45518
|
lines.push("```javascript");
|
|
44114
45519
|
lines.push(content);
|
|
@@ -44117,14 +45522,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44117
45522
|
} catch {
|
|
44118
45523
|
}
|
|
44119
45524
|
}
|
|
44120
|
-
const refFiles =
|
|
45525
|
+
const refFiles = fs14.readdirSync(latestScriptsDir).filter((f) => f.endsWith(".js") && !targetFileNames.has(f));
|
|
44121
45526
|
if (refFiles.length > 0) {
|
|
44122
45527
|
lines.push("## \u{1F512} Other Scripts (REFERENCE ONLY \u2014 DO NOT EDIT)");
|
|
44123
45528
|
lines.push("These files are shown for context only. Do NOT modify them under any circumstances.");
|
|
44124
45529
|
lines.push("");
|
|
44125
45530
|
for (const file2 of refFiles) {
|
|
44126
45531
|
try {
|
|
44127
|
-
const content =
|
|
45532
|
+
const content = fs14.readFileSync(path18.join(latestScriptsDir, file2), "utf-8");
|
|
44128
45533
|
lines.push(`### \`${file2}\` \u{1F512}`);
|
|
44129
45534
|
lines.push("```javascript");
|
|
44130
45535
|
lines.push(content);
|
|
@@ -44157,11 +45562,11 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44157
45562
|
lines.push("");
|
|
44158
45563
|
}
|
|
44159
45564
|
}
|
|
44160
|
-
const docsDir =
|
|
45565
|
+
const docsDir = path18.join(providerDir, "../../docs");
|
|
44161
45566
|
const loadGuide = (name) => {
|
|
44162
45567
|
try {
|
|
44163
|
-
const p =
|
|
44164
|
-
if (
|
|
45568
|
+
const p = path18.join(docsDir, name);
|
|
45569
|
+
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
44165
45570
|
} catch {
|
|
44166
45571
|
}
|
|
44167
45572
|
return null;
|
|
@@ -44226,6 +45631,7 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44226
45631
|
lines.push("### 2. Inspect parsed + raw adapter state");
|
|
44227
45632
|
lines.push("```bash");
|
|
44228
45633
|
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/debug/${type}`);
|
|
45634
|
+
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/trace/${type}`);
|
|
44229
45635
|
lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
|
|
44230
45636
|
lines.push("```");
|
|
44231
45637
|
lines.push("");
|
|
@@ -44360,6 +45766,16 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44360
45766
|
async handleCliSend(req, res) {
|
|
44361
45767
|
return handleCliSend(this, req, res);
|
|
44362
45768
|
}
|
|
45769
|
+
/** POST /api/cli/exercise — launch/send/approve/wait helper for provider-fix loops */
|
|
45770
|
+
async handleCliExercise(req, res) {
|
|
45771
|
+
return handleCliExercise(this, req, res);
|
|
45772
|
+
}
|
|
45773
|
+
async handleCliFixtureCapture(req, res) {
|
|
45774
|
+
return handleCliFixtureCapture(this, req, res);
|
|
45775
|
+
}
|
|
45776
|
+
async handleCliFixtureReplay(req, res) {
|
|
45777
|
+
return handleCliFixtureReplay(this, req, res);
|
|
45778
|
+
}
|
|
44363
45779
|
/** POST /api/cli/stop — stop a running CLI { type } */
|
|
44364
45780
|
async handleCliStop(req, res) {
|
|
44365
45781
|
return handleCliStop(this, req, res);
|
|
@@ -44383,6 +45799,13 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44383
45799
|
async handleCliDebug(type, _req, res) {
|
|
44384
45800
|
return handleCliDebug(this, type, _req, res);
|
|
44385
45801
|
}
|
|
45802
|
+
/** GET /api/cli/trace/:type — recent CLI trace timeline plus current debug snapshot */
|
|
45803
|
+
async handleCliTrace(type, _req, res) {
|
|
45804
|
+
return handleCliTrace(this, type, _req, res);
|
|
45805
|
+
}
|
|
45806
|
+
async handleCliFixtureList(type, _req, res) {
|
|
45807
|
+
return handleCliFixtureList(this, type, _req, res);
|
|
45808
|
+
}
|
|
44386
45809
|
/** POST /api/cli/resolve — resolve an approval modal { type, buttonIndex } */
|
|
44387
45810
|
async handleCliResolve(req, res) {
|
|
44388
45811
|
return handleCliResolve(this, req, res);
|
|
@@ -44549,7 +45972,18 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44549
45972
|
});
|
|
44550
45973
|
}
|
|
44551
45974
|
async boot() {
|
|
44552
|
-
|
|
45975
|
+
if (typeof this.options.ensureReady === "function") {
|
|
45976
|
+
await this.options.ensureReady();
|
|
45977
|
+
}
|
|
45978
|
+
try {
|
|
45979
|
+
await this.client.connect();
|
|
45980
|
+
} catch (error48) {
|
|
45981
|
+
if (typeof this.options.ensureReady !== "function") {
|
|
45982
|
+
throw error48;
|
|
45983
|
+
}
|
|
45984
|
+
await this.options.ensureReady();
|
|
45985
|
+
await this.client.connect();
|
|
45986
|
+
}
|
|
44553
45987
|
this.unsubscribe = this.client.onEvent((event) => this.handleEvent(event));
|
|
44554
45988
|
let record2 = null;
|
|
44555
45989
|
if (this.options.attachExisting) {
|
|
@@ -44924,8 +46358,8 @@ data: ${JSON.stringify(msg.data)}
|
|
|
44924
46358
|
const res = await fetch(extension.vsixUrl);
|
|
44925
46359
|
if (res.ok) {
|
|
44926
46360
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
44927
|
-
const
|
|
44928
|
-
|
|
46361
|
+
const fs15 = await import("fs");
|
|
46362
|
+
fs15.writeFileSync(vsixPath, buffer);
|
|
44929
46363
|
return new Promise((resolve10) => {
|
|
44930
46364
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
44931
46365
|
(0, import_child_process10.exec)(cmd, { timeout: 6e4 }, (error48, _stdout, stderr) => {
|
|
@@ -45238,15 +46672,18 @@ data: ${JSON.stringify(msg.data)}
|
|
|
45238
46672
|
var import_http = require("http");
|
|
45239
46673
|
var import_ws = require("ws");
|
|
45240
46674
|
var path4 = __toESM(require("path"));
|
|
45241
|
-
var
|
|
45242
|
-
var
|
|
46675
|
+
var fs3 = __toESM(require("fs"));
|
|
46676
|
+
var os5 = __toESM(require("os"));
|
|
45243
46677
|
var import_daemon_core2 = __toESM(require_dist2());
|
|
45244
46678
|
|
|
45245
46679
|
// src/session-host.ts
|
|
45246
46680
|
var import_child_process = require("child_process");
|
|
46681
|
+
var fs2 = __toESM(require("fs"));
|
|
46682
|
+
var os2 = __toESM(require("os"));
|
|
45247
46683
|
var path = __toESM(require("path"));
|
|
45248
46684
|
var import_daemon_core = __toESM(require_dist2());
|
|
45249
46685
|
var SESSION_HOST_APP_NAME = process.env.ADHDEV_SESSION_HOST_NAME || "adhdev";
|
|
46686
|
+
var SESSION_HOST_START_TIMEOUT_MS = 15e3;
|
|
45250
46687
|
function buildSessionHostEnv(baseEnv) {
|
|
45251
46688
|
const env = {};
|
|
45252
46689
|
for (const [key, value] of Object.entries(baseEnv)) {
|
|
@@ -45267,12 +46704,58 @@ function resolveSessionHostEntry() {
|
|
|
45267
46704
|
path.resolve(__dirname, "../../vendor/session-host-daemon/index.js")
|
|
45268
46705
|
];
|
|
45269
46706
|
for (const candidate of localCandidates) {
|
|
45270
|
-
if (
|
|
46707
|
+
if (fs2.existsSync(candidate)) {
|
|
45271
46708
|
return candidate;
|
|
45272
46709
|
}
|
|
45273
46710
|
}
|
|
45274
46711
|
return require.resolve("@adhdev/session-host-daemon");
|
|
45275
46712
|
}
|
|
46713
|
+
function getSessionHostPidFile() {
|
|
46714
|
+
return path.join(os2.homedir(), ".adhdev", `${SESSION_HOST_APP_NAME}-session-host.pid`);
|
|
46715
|
+
}
|
|
46716
|
+
function killPid(pid) {
|
|
46717
|
+
try {
|
|
46718
|
+
if (process.platform === "win32") {
|
|
46719
|
+
(0, import_child_process.execFileSync)("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
46720
|
+
} else {
|
|
46721
|
+
process.kill(pid, "SIGTERM");
|
|
46722
|
+
}
|
|
46723
|
+
return true;
|
|
46724
|
+
} catch {
|
|
46725
|
+
return false;
|
|
46726
|
+
}
|
|
46727
|
+
}
|
|
46728
|
+
function stopSessionHost() {
|
|
46729
|
+
let stopped = false;
|
|
46730
|
+
const pidFile = getSessionHostPidFile();
|
|
46731
|
+
try {
|
|
46732
|
+
if (fs2.existsSync(pidFile)) {
|
|
46733
|
+
const pid = Number.parseInt(fs2.readFileSync(pidFile, "utf8").trim(), 10);
|
|
46734
|
+
if (Number.isFinite(pid)) {
|
|
46735
|
+
stopped = killPid(pid) || stopped;
|
|
46736
|
+
}
|
|
46737
|
+
}
|
|
46738
|
+
} catch {
|
|
46739
|
+
} finally {
|
|
46740
|
+
try {
|
|
46741
|
+
fs2.unlinkSync(pidFile);
|
|
46742
|
+
} catch {
|
|
46743
|
+
}
|
|
46744
|
+
}
|
|
46745
|
+
if (process.platform !== "win32") {
|
|
46746
|
+
try {
|
|
46747
|
+
const raw = (0, import_child_process.execFileSync)("pgrep", ["-f", "session-host-daemon"], { encoding: "utf8" }).trim();
|
|
46748
|
+
for (const line of raw.split("\n")) {
|
|
46749
|
+
const pid = Number.parseInt(line.trim(), 10);
|
|
46750
|
+
if (Number.isFinite(pid)) {
|
|
46751
|
+
stopped = killPid(pid) || stopped;
|
|
46752
|
+
}
|
|
46753
|
+
}
|
|
46754
|
+
} catch {
|
|
46755
|
+
}
|
|
46756
|
+
}
|
|
46757
|
+
return stopped;
|
|
46758
|
+
}
|
|
45276
46759
|
async function runSessionHostCli(args) {
|
|
45277
46760
|
const entry = resolveSessionHostEntry();
|
|
45278
46761
|
const child = (0, import_child_process.spawn)(process.execPath, [entry, ...args], {
|
|
@@ -45285,19 +46768,34 @@ async function runSessionHostCli(args) {
|
|
|
45285
46768
|
});
|
|
45286
46769
|
}
|
|
45287
46770
|
async function ensureSessionHostReady() {
|
|
45288
|
-
|
|
45289
|
-
|
|
45290
|
-
|
|
45291
|
-
|
|
45292
|
-
|
|
45293
|
-
|
|
45294
|
-
|
|
45295
|
-
|
|
45296
|
-
|
|
45297
|
-
|
|
45298
|
-
|
|
45299
|
-
|
|
45300
|
-
|
|
46771
|
+
const spawnHost = () => {
|
|
46772
|
+
const entry = resolveSessionHostEntry();
|
|
46773
|
+
const child = (0, import_child_process.spawn)(process.execPath, [entry], {
|
|
46774
|
+
detached: true,
|
|
46775
|
+
stdio: "ignore",
|
|
46776
|
+
windowsHide: true,
|
|
46777
|
+
env: buildSessionHostEnv(process.env)
|
|
46778
|
+
});
|
|
46779
|
+
child.unref();
|
|
46780
|
+
};
|
|
46781
|
+
try {
|
|
46782
|
+
return await (0, import_daemon_core.ensureSessionHostReady)({
|
|
46783
|
+
appName: SESSION_HOST_APP_NAME,
|
|
46784
|
+
spawnHost,
|
|
46785
|
+
timeoutMs: SESSION_HOST_START_TIMEOUT_MS
|
|
46786
|
+
});
|
|
46787
|
+
} catch (error48) {
|
|
46788
|
+
stopSessionHost();
|
|
46789
|
+
return (0, import_daemon_core.ensureSessionHostReady)({
|
|
46790
|
+
appName: SESSION_HOST_APP_NAME,
|
|
46791
|
+
spawnHost,
|
|
46792
|
+
timeoutMs: SESSION_HOST_START_TIMEOUT_MS
|
|
46793
|
+
}).catch((retryError) => {
|
|
46794
|
+
const initialMessage = error48 instanceof Error ? error48.message : String(error48);
|
|
46795
|
+
const retryMessage = retryError instanceof Error ? retryError.message : String(retryError);
|
|
46796
|
+
throw new Error(`Session host failed to start after retry (${initialMessage}; retry: ${retryMessage})`);
|
|
46797
|
+
});
|
|
46798
|
+
}
|
|
45301
46799
|
}
|
|
45302
46800
|
async function listHostedCliRuntimes(endpoint) {
|
|
45303
46801
|
return (0, import_daemon_core.listHostedCliRuntimes)(endpoint);
|
|
@@ -45315,7 +46813,7 @@ async function proxySessionHostAttach(target, options = {}) {
|
|
|
45315
46813
|
}
|
|
45316
46814
|
|
|
45317
46815
|
// ../session-host-core/dist/index.mjs
|
|
45318
|
-
var
|
|
46816
|
+
var os3 = __toESM(require("os"), 1);
|
|
45319
46817
|
var path2 = __toESM(require("path"), 1);
|
|
45320
46818
|
var net = __toESM(require("net"), 1);
|
|
45321
46819
|
var import_crypto = require("crypto");
|
|
@@ -45328,7 +46826,7 @@ function getDefaultSessionHostEndpoint(appName = "adhdev") {
|
|
|
45328
46826
|
}
|
|
45329
46827
|
return {
|
|
45330
46828
|
kind: "unix",
|
|
45331
|
-
path: path2.join(
|
|
46829
|
+
path: path2.join(os3.tmpdir(), `${appName}-session-host.sock`)
|
|
45332
46830
|
};
|
|
45333
46831
|
}
|
|
45334
46832
|
function serializeEnvelope(envelope) {
|
|
@@ -45612,7 +47110,7 @@ if (pkgVersion === "unknown") {
|
|
|
45612
47110
|
];
|
|
45613
47111
|
for (const candidate of possiblePaths) {
|
|
45614
47112
|
try {
|
|
45615
|
-
const data = JSON.parse(
|
|
47113
|
+
const data = JSON.parse(fs3.readFileSync(candidate, "utf-8"));
|
|
45616
47114
|
if (data.version) {
|
|
45617
47115
|
pkgVersion = data.version;
|
|
45618
47116
|
break;
|
|
@@ -45714,6 +47212,10 @@ var StandaloneServer = class {
|
|
|
45714
47212
|
},
|
|
45715
47213
|
createPtyTransportFactory: ({ runtimeId, providerType, workspace, cliArgs, providerSessionId, attachExisting }) => new import_daemon_core2.SessionHostPtyTransportFactory({
|
|
45716
47214
|
endpoint: sessionHostEndpoint,
|
|
47215
|
+
ensureReady: async () => {
|
|
47216
|
+
const activeEndpoint = await this.ensureActiveSessionHostEndpoint();
|
|
47217
|
+
this.sessionHostEndpoint = activeEndpoint;
|
|
47218
|
+
},
|
|
45717
47219
|
clientId: `daemon-${process.pid}`,
|
|
45718
47220
|
runtimeId,
|
|
45719
47221
|
providerType,
|
|
@@ -45972,7 +47474,7 @@ var StandaloneServer = class {
|
|
|
45972
47474
|
if (publicDir) {
|
|
45973
47475
|
const filePath = url2 === "/" ? "/index.html" : url2;
|
|
45974
47476
|
const fullPath = path4.join(publicDir, filePath);
|
|
45975
|
-
if (
|
|
47477
|
+
if (fs3.existsSync(fullPath) && fs3.statSync(fullPath).isFile()) {
|
|
45976
47478
|
const ext = path4.extname(fullPath);
|
|
45977
47479
|
const mimeTypes = {
|
|
45978
47480
|
".html": "text/html",
|
|
@@ -45985,13 +47487,13 @@ var StandaloneServer = class {
|
|
|
45985
47487
|
".woff2": "font/woff2"
|
|
45986
47488
|
};
|
|
45987
47489
|
res.writeHead(200, { "Content-Type": mimeTypes[ext] || "application/octet-stream" });
|
|
45988
|
-
|
|
47490
|
+
fs3.createReadStream(fullPath).pipe(res);
|
|
45989
47491
|
return;
|
|
45990
47492
|
}
|
|
45991
47493
|
const indexPath = path4.join(publicDir, "index.html");
|
|
45992
|
-
if (
|
|
47494
|
+
if (fs3.existsSync(indexPath) && !url2.startsWith("/api/")) {
|
|
45993
47495
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
45994
|
-
|
|
47496
|
+
fs3.createReadStream(indexPath).pipe(res);
|
|
45995
47497
|
return;
|
|
45996
47498
|
}
|
|
45997
47499
|
}
|
|
@@ -46251,7 +47753,7 @@ var StandaloneServer = class {
|
|
|
46251
47753
|
}
|
|
46252
47754
|
// ─── Network ───
|
|
46253
47755
|
getLanIPs() {
|
|
46254
|
-
const interfaces =
|
|
47756
|
+
const interfaces = os5.networkInterfaces();
|
|
46255
47757
|
const ips = [];
|
|
46256
47758
|
for (const iface of Object.values(interfaces)) {
|
|
46257
47759
|
if (!iface) continue;
|
|
@@ -46370,7 +47872,7 @@ Runtime commands:
|
|
|
46370
47872
|
path4.join(process.cwd(), "public")
|
|
46371
47873
|
];
|
|
46372
47874
|
for (const candidate of candidates) {
|
|
46373
|
-
if (
|
|
47875
|
+
if (fs3.existsSync(path4.join(candidate, "index.html"))) {
|
|
46374
47876
|
options.publicDir = candidate;
|
|
46375
47877
|
break;
|
|
46376
47878
|
}
|