@cortexkit/aft-opencode 0.37.2 → 0.39.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 +398 -114
- package/dist/shared/rpc-client.d.ts.map +1 -1
- package/dist/shared/rpc-server.d.ts +3 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/shared/status.d.ts.map +1 -1
- package/dist/shutdown-hooks.d.ts +17 -0
- package/dist/shutdown-hooks.d.ts.map +1 -1
- package/dist/tools/_shared.d.ts.map +1 -1
- package/dist/tools/ast.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tui.js +28 -2
- package/package.json +8 -8
- package/src/shared/rpc-client.ts +7 -0
- package/src/shared/rpc-server.ts +39 -0
- package/src/shared/status.ts +4 -6
- package/src/tui/index.tsx +2 -4
- package/src/tui/sidebar.tsx +7 -13
package/dist/index.js
CHANGED
|
@@ -11607,25 +11607,26 @@ function maybeAppendConflictsHint(output) {
|
|
|
11607
11607
|
return output;
|
|
11608
11608
|
return output + CONFLICT_HINT;
|
|
11609
11609
|
}
|
|
11610
|
-
function
|
|
11611
|
-
const
|
|
11612
|
-
if (
|
|
11610
|
+
function commandInvokesCodeSearch(command) {
|
|
11611
|
+
const statements = splitTopLevelStatements(command);
|
|
11612
|
+
if (statements === null)
|
|
11613
11613
|
return false;
|
|
11614
|
-
const
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11614
|
+
for (const statement of statements) {
|
|
11615
|
+
const firstStage = firstPipelineStage(statement);
|
|
11616
|
+
if (firstStage === null)
|
|
11617
|
+
continue;
|
|
11618
|
+
const firstToken = readShellToken(firstStage, skipSpaces(firstStage, 0));
|
|
11619
|
+
if (firstToken === null)
|
|
11620
|
+
continue;
|
|
11621
|
+
if (firstToken.token === "grep" || firstToken.token === "rg")
|
|
11622
|
+
return true;
|
|
11623
|
+
}
|
|
11624
|
+
return false;
|
|
11624
11625
|
}
|
|
11625
11626
|
function maybeAppendGrepSearchHint(output, command, aftSearchRegistered) {
|
|
11626
11627
|
if (output === "")
|
|
11627
11628
|
return output;
|
|
11628
|
-
if (!
|
|
11629
|
+
if (!commandInvokesCodeSearch(command))
|
|
11629
11630
|
return output;
|
|
11630
11631
|
if (output.includes(GREP_SEARCH_HINT_PREFIX))
|
|
11631
11632
|
return output;
|
|
@@ -11634,21 +11635,78 @@ function maybeAppendGrepSearchHint(output, command, aftSearchRegistered) {
|
|
|
11634
11635
|
|
|
11635
11636
|
${hint}`;
|
|
11636
11637
|
}
|
|
11637
|
-
function
|
|
11638
|
-
const
|
|
11639
|
-
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
|
|
11643
|
-
|
|
11644
|
-
|
|
11638
|
+
function splitTopLevelStatements(command) {
|
|
11639
|
+
const statements = [];
|
|
11640
|
+
let start = 0;
|
|
11641
|
+
let quote = "none";
|
|
11642
|
+
let escaped = false;
|
|
11643
|
+
let inBacktick = false;
|
|
11644
|
+
let parenDepth = 0;
|
|
11645
|
+
for (let index = 0;index < command.length; index++) {
|
|
11646
|
+
const ch = command[index];
|
|
11647
|
+
if (escaped) {
|
|
11648
|
+
escaped = false;
|
|
11649
|
+
continue;
|
|
11650
|
+
}
|
|
11651
|
+
if (quote === "single") {
|
|
11652
|
+
if (ch === "'")
|
|
11653
|
+
quote = "none";
|
|
11654
|
+
continue;
|
|
11655
|
+
}
|
|
11656
|
+
if (quote === "double") {
|
|
11657
|
+
if (ch === "\\")
|
|
11658
|
+
escaped = true;
|
|
11659
|
+
else if (ch === '"')
|
|
11660
|
+
quote = "none";
|
|
11661
|
+
continue;
|
|
11662
|
+
}
|
|
11663
|
+
if (inBacktick) {
|
|
11664
|
+
if (ch === "`")
|
|
11665
|
+
inBacktick = false;
|
|
11666
|
+
continue;
|
|
11667
|
+
}
|
|
11668
|
+
if (ch === "\\") {
|
|
11669
|
+
escaped = true;
|
|
11670
|
+
continue;
|
|
11671
|
+
}
|
|
11672
|
+
if (ch === "'") {
|
|
11673
|
+
quote = "single";
|
|
11674
|
+
continue;
|
|
11675
|
+
}
|
|
11676
|
+
if (ch === '"') {
|
|
11677
|
+
quote = "double";
|
|
11678
|
+
continue;
|
|
11679
|
+
}
|
|
11680
|
+
if (ch === "`") {
|
|
11681
|
+
inBacktick = true;
|
|
11682
|
+
continue;
|
|
11683
|
+
}
|
|
11684
|
+
if (ch === "(") {
|
|
11685
|
+
parenDepth++;
|
|
11686
|
+
continue;
|
|
11687
|
+
}
|
|
11688
|
+
if (ch === ")") {
|
|
11689
|
+
if (parenDepth > 0)
|
|
11690
|
+
parenDepth--;
|
|
11691
|
+
continue;
|
|
11692
|
+
}
|
|
11693
|
+
if (parenDepth > 0)
|
|
11694
|
+
continue;
|
|
11695
|
+
const next = command[index + 1];
|
|
11696
|
+
if (ch === "&" && next === "&" || ch === "|" && next === "|") {
|
|
11697
|
+
statements.push(command.slice(start, index));
|
|
11698
|
+
index++;
|
|
11699
|
+
start = index + 1;
|
|
11700
|
+
} else if (ch === ";" || ch === `
|
|
11701
|
+
` || ch === "&") {
|
|
11702
|
+
statements.push(command.slice(start, index));
|
|
11703
|
+
start = index + 1;
|
|
11704
|
+
}
|
|
11705
|
+
}
|
|
11706
|
+
if (quote !== "none" || inBacktick || escaped)
|
|
11645
11707
|
return null;
|
|
11646
|
-
|
|
11647
|
-
|
|
11648
|
-
const afterDir = skipSpaces(command, dir.end);
|
|
11649
|
-
if (!command.startsWith("&&", afterDir))
|
|
11650
|
-
return command;
|
|
11651
|
-
return command.slice(afterDir + 2).trim();
|
|
11708
|
+
statements.push(command.slice(start));
|
|
11709
|
+
return statements;
|
|
11652
11710
|
}
|
|
11653
11711
|
function firstPipelineStage(command) {
|
|
11654
11712
|
let quote = "none";
|
|
@@ -14250,37 +14308,67 @@ var GREP_GUARD_FLAGS = new Set([
|
|
|
14250
14308
|
function maybeStripCompressorPipe(command, compressionEnabled) {
|
|
14251
14309
|
if (!compressionEnabled)
|
|
14252
14310
|
return { command, stripped: false };
|
|
14253
|
-
|
|
14254
|
-
return { command, stripped: false };
|
|
14255
|
-
const chain = splitTopLevelAndChain(command);
|
|
14311
|
+
const chain = splitTopLevelCommandChain(command);
|
|
14256
14312
|
if (chain === null)
|
|
14257
14313
|
return { command, stripped: false };
|
|
14258
|
-
|
|
14259
|
-
const
|
|
14260
|
-
const
|
|
14261
|
-
|
|
14314
|
+
let stripped = false;
|
|
14315
|
+
const droppedFilterChains = [];
|
|
14316
|
+
const rebuilt = chain.map(({ segment, separator }) => {
|
|
14317
|
+
const result = stripSinglePipelineSegment(segment);
|
|
14318
|
+
if (result.stripped) {
|
|
14319
|
+
stripped = true;
|
|
14320
|
+
droppedFilterChains.push(result.filters);
|
|
14321
|
+
}
|
|
14322
|
+
return `${result.segment}${separator}`;
|
|
14323
|
+
}).join("");
|
|
14324
|
+
if (!stripped)
|
|
14262
14325
|
return { command, stripped: false };
|
|
14326
|
+
return {
|
|
14327
|
+
command: rebuilt,
|
|
14328
|
+
stripped: true,
|
|
14329
|
+
note: formatStripNote(droppedFilterChains)
|
|
14330
|
+
};
|
|
14331
|
+
}
|
|
14332
|
+
function stripSinglePipelineSegment(segment) {
|
|
14333
|
+
const leading = /^\s*/.exec(segment)?.[0] ?? "";
|
|
14334
|
+
const trailing = /\s*$/.exec(segment)?.[0] ?? "";
|
|
14335
|
+
const coreStart = leading.length;
|
|
14336
|
+
const coreEnd = segment.length - trailing.length;
|
|
14337
|
+
if (coreEnd <= coreStart)
|
|
14338
|
+
return { segment, stripped: false };
|
|
14339
|
+
const core = segment.slice(coreStart, coreEnd);
|
|
14340
|
+
if (containsUnsplittableConstruct(core))
|
|
14341
|
+
return { segment, stripped: false };
|
|
14342
|
+
if (hasUnquotedBackground(core))
|
|
14343
|
+
return { segment, stripped: false };
|
|
14344
|
+
const stages = splitTopLevelPipeline(core);
|
|
14345
|
+
if (stages.length < 2)
|
|
14346
|
+
return { segment, stripped: false };
|
|
14263
14347
|
const firstStage = stages[0]?.trim() ?? "";
|
|
14264
14348
|
if (!isCompressorHandledRunner(firstStage))
|
|
14265
|
-
return {
|
|
14349
|
+
return { segment, stripped: false };
|
|
14266
14350
|
const filterStages = stages.slice(1).map((stage) => stage.trim());
|
|
14267
14351
|
for (const stage of filterStages) {
|
|
14268
14352
|
if (!filterStageIsSafeToDrop(stage))
|
|
14269
|
-
return {
|
|
14353
|
+
return { segment, stripped: false };
|
|
14270
14354
|
}
|
|
14271
|
-
const filters = filterStages.join(" | ");
|
|
14272
|
-
const rebuilt = [...prefix, firstStage].join(" && ");
|
|
14273
14355
|
return {
|
|
14274
|
-
|
|
14356
|
+
segment: `${leading}${firstStage}${trailing}`,
|
|
14275
14357
|
stripped: true,
|
|
14276
|
-
|
|
14358
|
+
filters: filterStages.join(" | ")
|
|
14277
14359
|
};
|
|
14278
14360
|
}
|
|
14279
|
-
function
|
|
14361
|
+
function formatStripNote(droppedFilterChains) {
|
|
14362
|
+
const filters = droppedFilterChains.map((filter) => `\`| ${filter}\``).join(", ");
|
|
14363
|
+
return `[AFT dropped ${filters} (compressed:false to keep)]`;
|
|
14364
|
+
}
|
|
14365
|
+
function splitTopLevelCommandChain(command) {
|
|
14280
14366
|
const segments = [];
|
|
14281
14367
|
let start = 0;
|
|
14282
14368
|
let quote = null;
|
|
14283
14369
|
let escaped = false;
|
|
14370
|
+
let inBacktick = false;
|
|
14371
|
+
let parenDepth = 0;
|
|
14284
14372
|
for (let index = 0;index < command.length; index++) {
|
|
14285
14373
|
const char = command[index];
|
|
14286
14374
|
const next = command[index + 1];
|
|
@@ -14288,6 +14376,13 @@ function splitTopLevelAndChain(command) {
|
|
|
14288
14376
|
escaped = false;
|
|
14289
14377
|
continue;
|
|
14290
14378
|
}
|
|
14379
|
+
if (inBacktick) {
|
|
14380
|
+
if (char === "\\")
|
|
14381
|
+
escaped = true;
|
|
14382
|
+
else if (char === "`")
|
|
14383
|
+
inBacktick = false;
|
|
14384
|
+
continue;
|
|
14385
|
+
}
|
|
14291
14386
|
if (char === "\\" && quote !== "'") {
|
|
14292
14387
|
escaped = true;
|
|
14293
14388
|
continue;
|
|
@@ -14301,26 +14396,47 @@ function splitTopLevelAndChain(command) {
|
|
|
14301
14396
|
quote = char;
|
|
14302
14397
|
continue;
|
|
14303
14398
|
}
|
|
14304
|
-
if (char === "
|
|
14305
|
-
|
|
14306
|
-
start = index + 2;
|
|
14307
|
-
index++;
|
|
14399
|
+
if (char === "`") {
|
|
14400
|
+
inBacktick = true;
|
|
14308
14401
|
continue;
|
|
14309
14402
|
}
|
|
14310
|
-
if (char === "
|
|
14311
|
-
|
|
14312
|
-
|
|
14313
|
-
|
|
14403
|
+
if (char === "(") {
|
|
14404
|
+
parenDepth++;
|
|
14405
|
+
continue;
|
|
14406
|
+
}
|
|
14407
|
+
if (char === ")") {
|
|
14408
|
+
if (parenDepth === 0)
|
|
14409
|
+
return null;
|
|
14410
|
+
parenDepth--;
|
|
14411
|
+
continue;
|
|
14412
|
+
}
|
|
14413
|
+
if (parenDepth > 0)
|
|
14414
|
+
continue;
|
|
14314
14415
|
if (char === `
|
|
14315
14416
|
` || char === "\r")
|
|
14316
14417
|
return null;
|
|
14317
|
-
if (char === "
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
14418
|
+
if (char === "#" && (index === 0 || command[index - 1] === " " || command[index - 1] === "\t"))
|
|
14419
|
+
return null;
|
|
14420
|
+
if (char === "&" && next === "&") {
|
|
14421
|
+
segments.push({ segment: command.slice(start, index), separator: "&&" });
|
|
14422
|
+
start = index + 2;
|
|
14423
|
+
index++;
|
|
14424
|
+
continue;
|
|
14425
|
+
}
|
|
14426
|
+
if (char === "|" && next === "|") {
|
|
14427
|
+
segments.push({ segment: command.slice(start, index), separator: "||" });
|
|
14428
|
+
start = index + 2;
|
|
14429
|
+
index++;
|
|
14430
|
+
continue;
|
|
14431
|
+
}
|
|
14432
|
+
if (char === ";") {
|
|
14433
|
+
segments.push({ segment: command.slice(start, index), separator: ";" });
|
|
14434
|
+
start = index + 1;
|
|
14321
14435
|
}
|
|
14322
14436
|
}
|
|
14323
|
-
|
|
14437
|
+
if (escaped || quote || inBacktick || parenDepth !== 0)
|
|
14438
|
+
return null;
|
|
14439
|
+
segments.push({ segment: command.slice(start), separator: "" });
|
|
14324
14440
|
return segments;
|
|
14325
14441
|
}
|
|
14326
14442
|
function splitTopLevelPipeline(command) {
|
|
@@ -14383,13 +14499,13 @@ function isCompressorHandledRunner(stage) {
|
|
|
14383
14499
|
args = args.slice(1);
|
|
14384
14500
|
const sub = args[0];
|
|
14385
14501
|
const subNext = args[1];
|
|
14386
|
-
return sub === "test" || sub === "run" &&
|
|
14502
|
+
return sub === "test" || sub === "run" && isJsVerificationScript(subNext);
|
|
14387
14503
|
}
|
|
14388
14504
|
if (first === "npm" || first === "pnpm") {
|
|
14389
|
-
return second === "test" || second === "run" &&
|
|
14505
|
+
return second === "test" || second === "run" && isJsVerificationScript(third);
|
|
14390
14506
|
}
|
|
14391
14507
|
if (first === "yarn") {
|
|
14392
|
-
return
|
|
14508
|
+
return isJsVerificationScript(second) || second === "run" && isJsVerificationScript(third);
|
|
14393
14509
|
}
|
|
14394
14510
|
if (first === "deno")
|
|
14395
14511
|
return ["test", "lint", "check", "bench"].includes(second ?? "");
|
|
@@ -14467,8 +14583,10 @@ function hasBuildTask(args, tasks) {
|
|
|
14467
14583
|
}
|
|
14468
14584
|
return sawAllowed;
|
|
14469
14585
|
}
|
|
14470
|
-
function
|
|
14471
|
-
|
|
14586
|
+
function isJsVerificationScript(token) {
|
|
14587
|
+
if (!token)
|
|
14588
|
+
return false;
|
|
14589
|
+
return token.startsWith("test") || token === "typecheck" || token.startsWith("typecheck:");
|
|
14472
14590
|
}
|
|
14473
14591
|
var XCODEBUILD_VALUE_FLAGS = new Set([
|
|
14474
14592
|
"-scheme",
|
|
@@ -33127,6 +33245,7 @@ function writeTerminal(terminal, data) {
|
|
|
33127
33245
|
// src/shared/rpc-server.ts
|
|
33128
33246
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
33129
33247
|
import {
|
|
33248
|
+
existsSync as existsSync14,
|
|
33130
33249
|
mkdirSync as mkdirSync10,
|
|
33131
33250
|
readdirSync as readdirSync5,
|
|
33132
33251
|
readFileSync as readFileSync13,
|
|
@@ -33185,6 +33304,8 @@ function parseRpcPortRecord(content) {
|
|
|
33185
33304
|
}
|
|
33186
33305
|
|
|
33187
33306
|
// src/shared/rpc-server.ts
|
|
33307
|
+
var PORT_FILE_HEARTBEAT_MS = 15000;
|
|
33308
|
+
|
|
33188
33309
|
class AftRpcServer {
|
|
33189
33310
|
server = null;
|
|
33190
33311
|
port = 0;
|
|
@@ -33192,6 +33313,7 @@ class AftRpcServer {
|
|
|
33192
33313
|
handlers = new Map;
|
|
33193
33314
|
portFilePath;
|
|
33194
33315
|
portsDir;
|
|
33316
|
+
heartbeatTimer = null;
|
|
33195
33317
|
instanceId;
|
|
33196
33318
|
constructor(storageDir, directory) {
|
|
33197
33319
|
this.portsDir = rpcPortFileDir(storageDir, directory);
|
|
@@ -33229,6 +33351,8 @@ class AftRpcServer {
|
|
|
33229
33351
|
}), { encoding: "utf-8", mode: 384 });
|
|
33230
33352
|
renameSync8(tmpPath, this.portFilePath);
|
|
33231
33353
|
log2(`RPC server listening on 127.0.0.1:${this.port}`);
|
|
33354
|
+
this.heartbeatTimer = setInterval(() => this.ensurePortFile(), PORT_FILE_HEARTBEAT_MS);
|
|
33355
|
+
this.heartbeatTimer.unref?.();
|
|
33232
33356
|
this.sweepDeadPortFiles();
|
|
33233
33357
|
} catch (err) {
|
|
33234
33358
|
warn2(`Failed to write RPC port file: ${err}`);
|
|
@@ -33263,7 +33387,28 @@ class AftRpcServer {
|
|
|
33263
33387
|
} catch {}
|
|
33264
33388
|
}
|
|
33265
33389
|
}
|
|
33390
|
+
ensurePortFile() {
|
|
33391
|
+
if (!this.server || this.token === null)
|
|
33392
|
+
return;
|
|
33393
|
+
try {
|
|
33394
|
+
if (existsSync14(this.portFilePath))
|
|
33395
|
+
return;
|
|
33396
|
+
const tmpPath = `${this.portFilePath}.tmp`;
|
|
33397
|
+
writeFileSync10(tmpPath, JSON.stringify({
|
|
33398
|
+
port: this.port,
|
|
33399
|
+
token: this.token,
|
|
33400
|
+
pid: process.pid,
|
|
33401
|
+
started_at: Date.now()
|
|
33402
|
+
}), { encoding: "utf-8", mode: 384 });
|
|
33403
|
+
renameSync8(tmpPath, this.portFilePath);
|
|
33404
|
+
log2(`RPC port file was missing; rewrote ${this.portFilePath}`);
|
|
33405
|
+
} catch {}
|
|
33406
|
+
}
|
|
33266
33407
|
stop() {
|
|
33408
|
+
if (this.heartbeatTimer) {
|
|
33409
|
+
clearInterval(this.heartbeatTimer);
|
|
33410
|
+
this.heartbeatTimer = null;
|
|
33411
|
+
}
|
|
33267
33412
|
if (this.server) {
|
|
33268
33413
|
this.server.close();
|
|
33269
33414
|
this.server = null;
|
|
@@ -33622,7 +33767,7 @@ function formatStatusMarkdown(status) {
|
|
|
33622
33767
|
}
|
|
33623
33768
|
if (status.status_bar) {
|
|
33624
33769
|
const sb = status.status_bar;
|
|
33625
|
-
lines.push("", `### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`, `- **Errors:** ${formatCount(sb.errors)}`, `- **Warnings:** ${formatCount(sb.warnings)}`, `- **Duplicates:** ${formatCount(sb.duplicates)}`, `- **TODOs:** ${formatCount(sb.todos)}`);
|
|
33770
|
+
lines.push("", `### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`, `- **Errors:** ${formatCount(sb.errors)}`, `- **Warnings:** ${formatCount(sb.warnings)}`, `- **Dead code:** ${formatCount(sb.dead_code)}`, `- **Unused exports:** ${formatCount(sb.unused_exports)}`, `- **Duplicates:** ${formatCount(sb.duplicates)}`, `- **TODOs:** ${formatCount(sb.todos)}`);
|
|
33626
33771
|
}
|
|
33627
33772
|
lines.push("", "### Current session", `- **ID:** \`${status.session.id}\``, `- **Tracked files:** ${formatCount(status.session.tracked_files)}`, `- **Checkpoints:** ${formatCount(status.session.checkpoints)}`, `- **Project checkpoints (all sessions):** ${formatCount(status.checkpoints_total)}`);
|
|
33628
33773
|
return lines.join(`
|
|
@@ -33631,7 +33776,7 @@ function formatStatusMarkdown(status) {
|
|
|
33631
33776
|
|
|
33632
33777
|
// src/shared/tui-config.ts
|
|
33633
33778
|
var import_comment_json4 = __toESM(require_src2(), 1);
|
|
33634
|
-
import { existsSync as
|
|
33779
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "node:fs";
|
|
33635
33780
|
import { dirname as dirname10, join as join21 } from "node:path";
|
|
33636
33781
|
|
|
33637
33782
|
// src/shared/opencode-config-dir.ts
|
|
@@ -33668,9 +33813,9 @@ function resolveTuiConfigPath() {
|
|
|
33668
33813
|
const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
33669
33814
|
const jsoncPath = join21(configDir, "tui.jsonc");
|
|
33670
33815
|
const jsonPath = join21(configDir, "tui.json");
|
|
33671
|
-
if (
|
|
33816
|
+
if (existsSync15(jsoncPath))
|
|
33672
33817
|
return jsoncPath;
|
|
33673
|
-
if (
|
|
33818
|
+
if (existsSync15(jsonPath))
|
|
33674
33819
|
return jsonPath;
|
|
33675
33820
|
return jsonPath;
|
|
33676
33821
|
}
|
|
@@ -33678,7 +33823,7 @@ function ensureTuiPluginEntry() {
|
|
|
33678
33823
|
try {
|
|
33679
33824
|
const configPath = resolveTuiConfigPath();
|
|
33680
33825
|
let config2 = {};
|
|
33681
|
-
if (
|
|
33826
|
+
if (existsSync15(configPath)) {
|
|
33682
33827
|
config2 = import_comment_json4.parse(readFileSync14(configPath, "utf-8")) ?? {};
|
|
33683
33828
|
}
|
|
33684
33829
|
const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((value) => typeof value === "string") : [];
|
|
@@ -33730,6 +33875,12 @@ async function runCleanups(reason) {
|
|
|
33730
33875
|
runningCleanups = false;
|
|
33731
33876
|
}
|
|
33732
33877
|
}
|
|
33878
|
+
var SIGNAL_EXIT_CODES = { SIGINT: 130, SIGTERM: 143, SIGHUP: 129 };
|
|
33879
|
+
var SIGNAL_CLEANUP_TIMEOUT_MS = 5000;
|
|
33880
|
+
function shouldForceExit(otherListenerCount) {
|
|
33881
|
+
return otherListenerCount === 0;
|
|
33882
|
+
}
|
|
33883
|
+
var signalShutdownStarted = false;
|
|
33733
33884
|
function installProcessHandlers() {
|
|
33734
33885
|
const state = getState();
|
|
33735
33886
|
if (state.installed)
|
|
@@ -33737,9 +33888,27 @@ function installProcessHandlers() {
|
|
|
33737
33888
|
state.installed = true;
|
|
33738
33889
|
const signals = ["SIGTERM", "SIGINT", "SIGHUP"];
|
|
33739
33890
|
for (const sig of signals) {
|
|
33740
|
-
|
|
33741
|
-
|
|
33742
|
-
|
|
33891
|
+
const handler = () => {
|
|
33892
|
+
const others = process.listenerCount(sig) - 1;
|
|
33893
|
+
if (!shouldForceExit(others)) {
|
|
33894
|
+
const names = process.listeners(sig).filter((fn) => fn !== handler).map((fn) => fn.name || fn.toString().slice(0, 80).replace(/\s+/g, " ")).join(" | ");
|
|
33895
|
+
log2(`${sig}: deferring termination to ${others} other listener(s); cleanup only. Others: ${names}`);
|
|
33896
|
+
runCleanups(sig);
|
|
33897
|
+
return;
|
|
33898
|
+
}
|
|
33899
|
+
if (signalShutdownStarted) {
|
|
33900
|
+
process.exit(SIGNAL_EXIT_CODES[sig]);
|
|
33901
|
+
}
|
|
33902
|
+
signalShutdownStarted = true;
|
|
33903
|
+
process.exitCode = SIGNAL_EXIT_CODES[sig];
|
|
33904
|
+
const timeout = new Promise((resolve5) => {
|
|
33905
|
+
setTimeout(resolve5, SIGNAL_CLEANUP_TIMEOUT_MS);
|
|
33906
|
+
});
|
|
33907
|
+
Promise.race([runCleanups(sig), timeout]).finally(() => {
|
|
33908
|
+
process.exit(SIGNAL_EXIT_CODES[sig]);
|
|
33909
|
+
});
|
|
33910
|
+
};
|
|
33911
|
+
process.on(sig, handler);
|
|
33743
33912
|
}
|
|
33744
33913
|
process.on("beforeExit", () => {
|
|
33745
33914
|
runCleanups("beforeExit");
|
|
@@ -33910,7 +34079,15 @@ ${candidates.map((candidate) => ` - ${candidate}`).join(`
|
|
|
33910
34079
|
`);
|
|
33911
34080
|
}
|
|
33912
34081
|
function collectStructuredExtras(response) {
|
|
33913
|
-
const reserved = new Set([
|
|
34082
|
+
const reserved = new Set([
|
|
34083
|
+
"id",
|
|
34084
|
+
"success",
|
|
34085
|
+
"code",
|
|
34086
|
+
"message",
|
|
34087
|
+
"data",
|
|
34088
|
+
"status_bar",
|
|
34089
|
+
"bg_completions"
|
|
34090
|
+
]);
|
|
33914
34091
|
const extras = {};
|
|
33915
34092
|
for (const [key, value] of Object.entries(response)) {
|
|
33916
34093
|
if (reserved.has(key))
|
|
@@ -34190,16 +34367,24 @@ async function checkAstPathsPermission(context, paths) {
|
|
|
34190
34367
|
}
|
|
34191
34368
|
return;
|
|
34192
34369
|
}
|
|
34193
|
-
var SUPPORTED_LANGS = [
|
|
34370
|
+
var SUPPORTED_LANGS = [
|
|
34371
|
+
"typescript",
|
|
34372
|
+
"tsx",
|
|
34373
|
+
"javascript",
|
|
34374
|
+
"python",
|
|
34375
|
+
"rust",
|
|
34376
|
+
"go",
|
|
34377
|
+
"pascal"
|
|
34378
|
+
];
|
|
34194
34379
|
function astTools(ctx) {
|
|
34195
34380
|
const searchTool = {
|
|
34196
|
-
description: `Search code patterns across filesystem using AST-aware matching. Supports
|
|
34381
|
+
description: `Search code patterns across filesystem using AST-aware matching. Supports 7 languages.
|
|
34197
34382
|
|
|
34198
34383
|
` + `Use meta-variables: $VAR matches a single AST node, $$$ matches multiple nodes (variadic).
|
|
34199
34384
|
` + `IMPORTANT: Patterns must be complete AST nodes (valid code fragments).
|
|
34200
34385
|
` + `For functions, include params and body: 'export async function $NAME($$$) { $$$ }' not just 'export async function $NAME'.
|
|
34201
34386
|
|
|
34202
|
-
` + "Examples: pattern='console.log($MSG)' lang='typescript', pattern='async function $NAME($$$) { $$$ }' lang='javascript', pattern='def $FUNC($$$): $$$' lang='python'",
|
|
34387
|
+
` + "Examples: pattern='console.log($MSG)' lang='typescript', pattern='async function $NAME($$$) { $$$ }' lang='javascript', pattern='def $FUNC($$$): $$$' lang='python', pattern='Writeln($MSG);' lang='pascal'",
|
|
34203
34388
|
args: {
|
|
34204
34389
|
pattern: z3.string().describe("AST pattern with meta-variables ($VAR, $$$). Must be complete AST node."),
|
|
34205
34390
|
lang: z3.enum(SUPPORTED_LANGS).describe("Target language"),
|
|
@@ -35745,6 +35930,91 @@ var z8 = tool8.schema;
|
|
|
35745
35930
|
function diagnosticsOnEditDefault(ctx) {
|
|
35746
35931
|
return ctx.config.lsp?.diagnostics_on_edit ?? false;
|
|
35747
35932
|
}
|
|
35933
|
+
async function readCurrentFileForPreview(filePath) {
|
|
35934
|
+
try {
|
|
35935
|
+
return await fs6.promises.readFile(filePath, "utf-8");
|
|
35936
|
+
} catch (error50) {
|
|
35937
|
+
if (error50 && typeof error50 === "object" && "code" in error50 && error50.code === "ENOENT") {
|
|
35938
|
+
return "";
|
|
35939
|
+
}
|
|
35940
|
+
throw error50;
|
|
35941
|
+
}
|
|
35942
|
+
}
|
|
35943
|
+
function previewDiffFromResponse(data, filePath) {
|
|
35944
|
+
const previewDiff = data.preview_diff;
|
|
35945
|
+
if (typeof previewDiff === "string")
|
|
35946
|
+
return previewDiff;
|
|
35947
|
+
const diff = data.diff;
|
|
35948
|
+
if (typeof diff?.before === "string" && typeof diff.after === "string") {
|
|
35949
|
+
return buildUnifiedDiff(filePath, diff.before, diff.after);
|
|
35950
|
+
}
|
|
35951
|
+
return "";
|
|
35952
|
+
}
|
|
35953
|
+
function virtualPatchContent(virtualFiles, filePath) {
|
|
35954
|
+
return virtualFiles.has(filePath) ? virtualFiles.get(filePath) ?? null : undefined;
|
|
35955
|
+
}
|
|
35956
|
+
async function readPatchPreviewContent(virtualFiles, filePath, action, patchPath) {
|
|
35957
|
+
const virtualContent = virtualPatchContent(virtualFiles, filePath);
|
|
35958
|
+
if (virtualContent !== undefined) {
|
|
35959
|
+
if (virtualContent === null) {
|
|
35960
|
+
throw new Error(`Failed to ${action} ${patchPath}: file not found: ${filePath}`);
|
|
35961
|
+
}
|
|
35962
|
+
return virtualContent;
|
|
35963
|
+
}
|
|
35964
|
+
try {
|
|
35965
|
+
return await fs6.promises.readFile(filePath, "utf-8");
|
|
35966
|
+
} catch (error50) {
|
|
35967
|
+
throw new Error(`Failed to ${action} ${patchPath}: ${formatError2(error50)}`);
|
|
35968
|
+
}
|
|
35969
|
+
}
|
|
35970
|
+
async function buildApplyPatchPreview(hunks, projectRoot) {
|
|
35971
|
+
const virtualFiles = new Map;
|
|
35972
|
+
const patches = [];
|
|
35973
|
+
let firstFilePath = "";
|
|
35974
|
+
for (const hunk of hunks) {
|
|
35975
|
+
const filePath = resolvePathFromProjectRoot(projectRoot, hunk.path);
|
|
35976
|
+
if (!firstFilePath)
|
|
35977
|
+
firstFilePath = filePath;
|
|
35978
|
+
switch (hunk.type) {
|
|
35979
|
+
case "add": {
|
|
35980
|
+
const virtualContent = virtualPatchContent(virtualFiles, filePath);
|
|
35981
|
+
const exists = virtualContent !== undefined ? virtualContent !== null : fs6.existsSync(filePath);
|
|
35982
|
+
if (exists) {
|
|
35983
|
+
throw new Error(`Failed to create ${hunk.path}: file already exists. Use *** Update File: to modify, or *** Delete File: first if you want to replace it entirely.`);
|
|
35984
|
+
}
|
|
35985
|
+
const after = hunk.contents.endsWith(`
|
|
35986
|
+
`) ? hunk.contents : `${hunk.contents}
|
|
35987
|
+
`;
|
|
35988
|
+
patches.push(buildUnifiedDiff(filePath, "", after));
|
|
35989
|
+
virtualFiles.set(filePath, after);
|
|
35990
|
+
break;
|
|
35991
|
+
}
|
|
35992
|
+
case "delete": {
|
|
35993
|
+
const before = await readPatchPreviewContent(virtualFiles, filePath, "delete", hunk.path);
|
|
35994
|
+
patches.push(buildUnifiedDiff(filePath, before, ""));
|
|
35995
|
+
virtualFiles.set(filePath, null);
|
|
35996
|
+
break;
|
|
35997
|
+
}
|
|
35998
|
+
case "update": {
|
|
35999
|
+
const before = await readPatchPreviewContent(virtualFiles, filePath, "update", hunk.path);
|
|
36000
|
+
let after;
|
|
36001
|
+
try {
|
|
36002
|
+
after = applyUpdateChunks(before, filePath, hunk.chunks);
|
|
36003
|
+
} catch (error50) {
|
|
36004
|
+
throw new Error(`Failed to update ${hunk.path}: ${formatError2(error50)}`);
|
|
36005
|
+
}
|
|
36006
|
+
const targetPath = hunk.move_path ? resolvePathFromProjectRoot(projectRoot, hunk.move_path) : filePath;
|
|
36007
|
+
patches.push(buildUnifiedDiff(targetPath, before, after));
|
|
36008
|
+
if (hunk.move_path)
|
|
36009
|
+
virtualFiles.set(filePath, null);
|
|
36010
|
+
virtualFiles.set(targetPath, after);
|
|
36011
|
+
break;
|
|
36012
|
+
}
|
|
36013
|
+
}
|
|
36014
|
+
}
|
|
36015
|
+
return { filepath: firstFilePath || projectRoot, diff: patches.join(`
|
|
36016
|
+
`) };
|
|
36017
|
+
}
|
|
35748
36018
|
var READ_DESCRIPTION = `Read file contents or list directory entries.
|
|
35749
36019
|
|
|
35750
36020
|
Use either startLine/endLine OR offset/limit to read a section of a file.
|
|
@@ -35889,16 +36159,18 @@ function createWriteTool(ctx, editToolName = "edit") {
|
|
|
35889
36159
|
const filePath = resolvePathFromProjectRoot(projectRoot, file2);
|
|
35890
36160
|
const relPath = path4.relative(projectRoot, filePath);
|
|
35891
36161
|
{
|
|
35892
|
-
const
|
|
35893
|
-
if (
|
|
35894
|
-
return permissionDeniedResponse(
|
|
35895
|
-
}
|
|
35896
|
-
await
|
|
35897
|
-
|
|
35898
|
-
|
|
35899
|
-
|
|
35900
|
-
|
|
35901
|
-
})
|
|
36162
|
+
const denial2 = await assertExternalDirectoryPermission(context, filePath);
|
|
36163
|
+
if (denial2)
|
|
36164
|
+
return permissionDeniedResponse(denial2);
|
|
36165
|
+
}
|
|
36166
|
+
const currentContent = await readCurrentFileForPreview(filePath);
|
|
36167
|
+
const previewDiff = buildUnifiedDiff(filePath, currentContent, content);
|
|
36168
|
+
const denial = await askEditPermission(context, [relPath], {
|
|
36169
|
+
filepath: filePath,
|
|
36170
|
+
diff: previewDiff
|
|
36171
|
+
});
|
|
36172
|
+
if (denial)
|
|
36173
|
+
return permissionDeniedResponse(denial);
|
|
35902
36174
|
const data = await callBridge(ctx, context, "write", {
|
|
35903
36175
|
file: filePath,
|
|
35904
36176
|
content,
|
|
@@ -36038,16 +36310,10 @@ function createEditTool(ctx, writeToolName = "write") {
|
|
|
36038
36310
|
const filePath = resolvePathFromProjectRoot(projectRoot, file2);
|
|
36039
36311
|
const relPath = path4.relative(projectRoot, filePath);
|
|
36040
36312
|
{
|
|
36041
|
-
const
|
|
36042
|
-
if (
|
|
36043
|
-
return permissionDeniedResponse(
|
|
36313
|
+
const denial2 = await assertExternalDirectoryPermission(context, filePath);
|
|
36314
|
+
if (denial2)
|
|
36315
|
+
return permissionDeniedResponse(denial2);
|
|
36044
36316
|
}
|
|
36045
|
-
await runAsk(context.ask({
|
|
36046
|
-
permission: "edit",
|
|
36047
|
-
patterns: [relPath],
|
|
36048
|
-
always: ["*"],
|
|
36049
|
-
metadata: { filepath: filePath }
|
|
36050
|
-
}));
|
|
36051
36317
|
const params = { file: filePath };
|
|
36052
36318
|
let command;
|
|
36053
36319
|
if (typeof args.appendContent === "string") {
|
|
@@ -36090,6 +36356,21 @@ function createEditTool(ctx, writeToolName = "write") {
|
|
|
36090
36356
|
const hint = typeof args.content === "string" ? ` To write the whole file, use the '${writeToolName}' tool. To edit existing content, provide 'oldString' (and optionally 'newString'), 'symbol' + 'content', or an 'edits' array.` : " Provide 'oldString' (+ optional 'newString'), 'symbol' + 'content', or an 'edits' array.";
|
|
36091
36357
|
throw new Error(`edit: no edit mode resolved from arguments.${hint}`);
|
|
36092
36358
|
}
|
|
36359
|
+
const previewData = await callBridge(ctx, context, command, {
|
|
36360
|
+
...params,
|
|
36361
|
+
preview: true,
|
|
36362
|
+
include_diff_content: true
|
|
36363
|
+
});
|
|
36364
|
+
if (previewData.success === false) {
|
|
36365
|
+
throw new Error(previewData.message || "edit preview failed");
|
|
36366
|
+
}
|
|
36367
|
+
const previewDiff = previewDiffFromResponse(previewData, filePath);
|
|
36368
|
+
const denial = await askEditPermission(context, [relPath], {
|
|
36369
|
+
filepath: filePath,
|
|
36370
|
+
diff: previewDiff
|
|
36371
|
+
});
|
|
36372
|
+
if (denial)
|
|
36373
|
+
return permissionDeniedResponse(denial);
|
|
36093
36374
|
params.diagnostics = diagnosticsOnEditDefault(ctx);
|
|
36094
36375
|
params.include_diff_content = true;
|
|
36095
36376
|
const data = await callBridge(ctx, context, command, params);
|
|
@@ -36253,17 +36534,18 @@ function createApplyPatchTool(ctx) {
|
|
|
36253
36534
|
if (asked.has(filePath))
|
|
36254
36535
|
continue;
|
|
36255
36536
|
asked.add(filePath);
|
|
36256
|
-
const
|
|
36257
|
-
if (
|
|
36258
|
-
return permissionDeniedResponse(
|
|
36537
|
+
const denial2 = await assertExternalDirectoryPermission(context, filePath);
|
|
36538
|
+
if (denial2)
|
|
36539
|
+
return permissionDeniedResponse(denial2);
|
|
36259
36540
|
}
|
|
36260
36541
|
}
|
|
36261
|
-
await
|
|
36262
|
-
|
|
36263
|
-
|
|
36264
|
-
|
|
36265
|
-
|
|
36266
|
-
|
|
36542
|
+
const preview2 = await buildApplyPatchPreview(hunks, projectRoot);
|
|
36543
|
+
const denial = await askEditPermission(context, relPaths, {
|
|
36544
|
+
filepath: preview2.filepath,
|
|
36545
|
+
diff: preview2.diff
|
|
36546
|
+
});
|
|
36547
|
+
if (denial)
|
|
36548
|
+
return permissionDeniedResponse(denial);
|
|
36267
36549
|
const checkpointPaths = Array.from(affectedAbs).filter((abs) => !newlyCreatedAbs.has(abs));
|
|
36268
36550
|
const checkpointName = `apply_patch_${Date.now()}`;
|
|
36269
36551
|
let checkpointCreated = false;
|
|
@@ -36635,16 +36917,18 @@ function aftPrefixedTools(ctx) {
|
|
|
36635
36917
|
const filePath = resolvePathFromProjectRoot(projectRoot, file2);
|
|
36636
36918
|
const relPath = path4.relative(projectRoot, filePath);
|
|
36637
36919
|
{
|
|
36638
|
-
const
|
|
36639
|
-
if (
|
|
36640
|
-
return permissionDeniedResponse(
|
|
36920
|
+
const denial2 = await assertExternalDirectoryPermission(context, filePath);
|
|
36921
|
+
if (denial2)
|
|
36922
|
+
return permissionDeniedResponse(denial2);
|
|
36641
36923
|
}
|
|
36642
|
-
await
|
|
36643
|
-
|
|
36644
|
-
|
|
36645
|
-
|
|
36646
|
-
|
|
36647
|
-
})
|
|
36924
|
+
const currentContent = await readCurrentFileForPreview(filePath);
|
|
36925
|
+
const previewDiff = buildUnifiedDiff(filePath, currentContent, normalizedArgs.content);
|
|
36926
|
+
const denial = await askEditPermission(context, [relPath], {
|
|
36927
|
+
filepath: filePath,
|
|
36928
|
+
diff: previewDiff
|
|
36929
|
+
});
|
|
36930
|
+
if (denial)
|
|
36931
|
+
return permissionDeniedResponse(denial);
|
|
36648
36932
|
const writeParams = {
|
|
36649
36933
|
file: filePath,
|
|
36650
36934
|
content: normalizedArgs.content,
|
|
@@ -38091,12 +38375,12 @@ var PLUGIN_VERSION = (() => {
|
|
|
38091
38375
|
return "0.0.0";
|
|
38092
38376
|
}
|
|
38093
38377
|
})();
|
|
38094
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
38378
|
+
var ANNOUNCEMENT_VERSION = "0.39.0";
|
|
38095
38379
|
var ANNOUNCEMENT_FEATURES = [
|
|
38096
|
-
"
|
|
38097
|
-
"
|
|
38098
|
-
"
|
|
38099
|
-
"
|
|
38380
|
+
"Accurate Rust dead code: constructors and associated functions reached through receiver-type inference are no longer mis-reported as dead.",
|
|
38381
|
+
"Code Health scans reparse only the file you changed instead of the whole project on every edit — a single-file edit dropped from ~3s of scan work to ~130ms on this repo, byte-identical results.",
|
|
38382
|
+
"R language support in outline, zoom, and the AST tools.",
|
|
38383
|
+
"Edit approval prompts now show the pending diff instead of 'No diff provided', so you can review a change before approving it."
|
|
38100
38384
|
];
|
|
38101
38385
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/DSa65w8wuf";
|
|
38102
38386
|
var plugin = async (input) => initializePluginForDirectory(input);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-client.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;CACvC;AA4BD,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,iBAAiB,CAA6B;gBAE1C,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKjD,iFAAiF;IAC3E,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,CAAC,CAAC;YA8CC,OAAO;IAsBrB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAM5B,4CAA4C;IACtC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IASrC;;;;OAIG;YACW,gBAAgB;IAwB9B,OAAO,CAAC,gBAAgB;IAwDxB,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-client.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;CACvC;AA4BD,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,iBAAiB,CAA6B;gBAE1C,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKjD,iFAAiF;IAC3E,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,CAAC,CAAC;YA8CC,OAAO;IAsBrB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAM5B,4CAA4C;IACtC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IASrC;;;;OAIG;YACW,gBAAgB;IAwB9B,OAAO,CAAC,gBAAgB;IAwDxB,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,iBAAiB;YA6BX,WAAW;YAkCX,gBAAgB;IAmB9B,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -6,6 +6,7 @@ export declare class AftRpcServer {
|
|
|
6
6
|
private handlers;
|
|
7
7
|
private portFilePath;
|
|
8
8
|
private portsDir;
|
|
9
|
+
private heartbeatTimer;
|
|
9
10
|
/** Unique per-instance ID — distinguishes our entry from duplicate plugin loads. */
|
|
10
11
|
private instanceId;
|
|
11
12
|
constructor(storageDir: string, directory: string);
|
|
@@ -20,6 +21,8 @@ export declare class AftRpcServer {
|
|
|
20
21
|
* Never touches our own freshly written file.
|
|
21
22
|
*/
|
|
22
23
|
private sweepDeadPortFiles;
|
|
24
|
+
/** Rewrite the port file if it disappeared (wrongful deletion recovery). */
|
|
25
|
+
private ensurePortFile;
|
|
23
26
|
/** Stop the server and clean up port file. */
|
|
24
27
|
stop(): void;
|
|
25
28
|
private dispatch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-server.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rpc-server.d.ts","sourceRoot":"","sources":["../../src/shared/rpc-server.ts"],"names":[],"mappings":"AAeA,KAAK,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAIxF,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAA+C;IACrE,oFAAoF;IACpF,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAMjD,sCAAsC;IACtC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI;IAIjD,6DAA6D;IACvD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAkE9B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IA6B1B,4EAA4E;IAC5E,OAAO,CAAC,cAAc;IAsBtB,8CAA8C;IAC9C,IAAI,IAAI,IAAI;IAiBZ,OAAO,CAAC,QAAQ;CAoEjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/shared/status.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/shared/status.ts"],"names":[],"mappings":"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"}
|
package/dist/shutdown-hooks.d.ts
CHANGED
|
@@ -16,6 +16,23 @@
|
|
|
16
16
|
*/
|
|
17
17
|
type Cleanup = () => Promise<void> | void;
|
|
18
18
|
export declare function runCleanups(reason: string): Promise<void>;
|
|
19
|
+
/** Conventional exit codes for fatal signals (128 + signal number). */
|
|
20
|
+
export declare const SIGNAL_EXIT_CODES: {
|
|
21
|
+
readonly SIGINT: 130;
|
|
22
|
+
readonly SIGTERM: 143;
|
|
23
|
+
readonly SIGHUP: 129;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Decide whether AFT's handler must terminate the process after cleanup.
|
|
27
|
+
*
|
|
28
|
+
* Registering ANY listener for SIGINT/SIGTERM/SIGHUP disables Node/Bun's
|
|
29
|
+
* default terminate-on-signal behavior. If AFT's listener is the only one,
|
|
30
|
+
* the default was suppressed solely by us, so we must exit or the host hangs
|
|
31
|
+
* forever (OpenCode serve + Desktop /event SSE hung on Ctrl-C until SIGKILL).
|
|
32
|
+
* If the host or another plugin also listens, terminating is THEIR call —
|
|
33
|
+
* forcing an exit here would race a host's graceful shutdown.
|
|
34
|
+
*/
|
|
35
|
+
export declare function shouldForceExit(otherListenerCount: number): boolean;
|
|
19
36
|
/**
|
|
20
37
|
* Register a shutdown cleanup. Call from plugin initialization; returned
|
|
21
38
|
* function unregisters (use in `dispose` so plugin reloads don't leak).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shutdown-hooks.d.ts","sourceRoot":"","sources":["../src/shutdown-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,KAAK,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAoB1C,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB/D;
|
|
1
|
+
{"version":3,"file":"shutdown-hooks.d.ts","sourceRoot":"","sources":["../src/shutdown-hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,KAAK,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAoB1C,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB/D;AAED,uEAAuE;AACvE,eAAO,MAAM,iBAAiB;;;;CAAsD,CAAC;AAKrF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAEnE;AA2DD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,OAAO,GAAG,MAAM,IAAI,CAO/D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAUhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,KAAG,GACR,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,OAAO,EACV,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"_shared.d.ts","sourceRoot":"","sources":["../../src/tools/_shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAUhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,KAAG,GACR,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,OAAO,EACV,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAepB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMpD;AAMD,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAIhD,OAAO,EAAE,+BAA+B,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AA2B3F,8EAA8E;AAC9E,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACnC,MAAM,CAsDR;AAiCD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAW3D;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQjD;AAED;;2BAE2B;AAC3B,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtF;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,YAAY,CAEhF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAgClC;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAE9F"}
|
package/dist/tools/ast.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/tools/ast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/tools/ast.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAqEjD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAwS3E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,qBAAqB,CAAC;AAItE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"hoisted.d.ts","sourceRoot":"","sources":["../../src/tools/hoisted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,qBAAqB,CAAC;AAItE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAyEjD,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,GAAI,IAAI,MAAM,EAAE,QAAQ,MAAM,EAAE,OAAO,MAAM,KAAG,MAChD,CAAC;AA8YtC;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,cAAc,CAwJjE;AAmnCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CA0B/E;AAMD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAkGnF"}
|
package/dist/tui.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/tui/index.tsx
|
|
2
2
|
import { createMemo as createMemo2, createSignal as createSignal2, onCleanup as onCleanup2 } from "solid-js";
|
|
3
3
|
// package.json
|
|
4
|
-
var version = "0.
|
|
4
|
+
var version = "0.39.0";
|
|
5
5
|
|
|
6
6
|
// src/shared/rpc-client.ts
|
|
7
7
|
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
@@ -248,6 +248,8 @@ class AftRpcClient {
|
|
|
248
248
|
return;
|
|
249
249
|
}
|
|
250
250
|
this.stalePortFailures.delete(key);
|
|
251
|
+
if (info.pid === undefined || isPidAlive(info.pid))
|
|
252
|
+
return;
|
|
251
253
|
try {
|
|
252
254
|
const current = this.parsePortFile(info.path);
|
|
253
255
|
if (current?.port === info.port && current.token === info.token) {
|
|
@@ -599,7 +601,7 @@ function collapsedHealthLights(statusBar) {
|
|
|
599
601
|
if (!statusBar)
|
|
600
602
|
return null;
|
|
601
603
|
const diagnostics = statusBar.errors > 0 ? "err" : statusBar.warnings > 0 ? "warn" : "ok";
|
|
602
|
-
const code = statusBar.duplicates > 0 ? "warn" : "ok";
|
|
604
|
+
const code = statusBar.dead_code > 0 || statusBar.unused_exports > 0 || statusBar.duplicates > 0 ? "warn" : "ok";
|
|
603
605
|
const todos = statusBar.todos > 0 ? "warn" : "ok";
|
|
604
606
|
return { diagnostics, code, todos };
|
|
605
607
|
}
|
|
@@ -1022,6 +1024,18 @@ var SidebarContent = (props) => {
|
|
|
1022
1024
|
value: formatCount(statusBar().warnings),
|
|
1023
1025
|
tone: statusBar().warnings > 0 ? "warn" : "muted"
|
|
1024
1026
|
}, undefined, false, undefined, this),
|
|
1027
|
+
/* @__PURE__ */ jsxDEV(StatRow, {
|
|
1028
|
+
theme: props.theme,
|
|
1029
|
+
label: "Dead Code",
|
|
1030
|
+
value: formatCount(statusBar().dead_code),
|
|
1031
|
+
tone: "muted"
|
|
1032
|
+
}, undefined, false, undefined, this),
|
|
1033
|
+
/* @__PURE__ */ jsxDEV(StatRow, {
|
|
1034
|
+
theme: props.theme,
|
|
1035
|
+
label: "Unused Exports",
|
|
1036
|
+
value: formatCount(statusBar().unused_exports),
|
|
1037
|
+
tone: "muted"
|
|
1038
|
+
}, undefined, false, undefined, this),
|
|
1025
1039
|
/* @__PURE__ */ jsxDEV(StatRow, {
|
|
1026
1040
|
theme: props.theme,
|
|
1027
1041
|
label: "Duplicates",
|
|
@@ -1556,6 +1570,18 @@ var StatusDialog = (props) => {
|
|
|
1556
1570
|
value: formatCountShort(status().status_bar.warnings),
|
|
1557
1571
|
tone: status().status_bar.warnings > 0 ? "warn" : "muted"
|
|
1558
1572
|
}, undefined, false, undefined, this),
|
|
1573
|
+
/* @__PURE__ */ jsxDEV2(R, {
|
|
1574
|
+
theme: t(),
|
|
1575
|
+
label: "Dead Code",
|
|
1576
|
+
value: formatCountShort(status().status_bar.dead_code),
|
|
1577
|
+
tone: "muted"
|
|
1578
|
+
}, undefined, false, undefined, this),
|
|
1579
|
+
/* @__PURE__ */ jsxDEV2(R, {
|
|
1580
|
+
theme: t(),
|
|
1581
|
+
label: "Unused Exports",
|
|
1582
|
+
value: formatCountShort(status().status_bar.unused_exports),
|
|
1583
|
+
tone: "muted"
|
|
1584
|
+
}, undefined, false, undefined, this),
|
|
1559
1585
|
/* @__PURE__ */ jsxDEV2(R, {
|
|
1560
1586
|
theme: t(),
|
|
1561
1587
|
label: "Duplicates",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/aft-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for Agent File Tools (AFT) — tree-sitter and lsp powered code analysis",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,19 +30,19 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@clack/prompts": "^1.2.0",
|
|
33
|
-
"@cortexkit/aft-bridge": "0.
|
|
33
|
+
"@cortexkit/aft-bridge": "0.39.0",
|
|
34
34
|
"@xterm/headless": "^5.5.0",
|
|
35
35
|
"comment-json": "^4.6.2",
|
|
36
36
|
"undici": "^7.25.0",
|
|
37
37
|
"zod": "^4.1.8"
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
|
-
"@cortexkit/aft-darwin-arm64": "0.
|
|
41
|
-
"@cortexkit/aft-darwin-x64": "0.
|
|
42
|
-
"@cortexkit/aft-linux-arm64": "0.
|
|
43
|
-
"@cortexkit/aft-linux-x64": "0.
|
|
44
|
-
"@cortexkit/aft-win32-arm64": "0.
|
|
45
|
-
"@cortexkit/aft-win32-x64": "0.
|
|
40
|
+
"@cortexkit/aft-darwin-arm64": "0.39.0",
|
|
41
|
+
"@cortexkit/aft-darwin-x64": "0.39.0",
|
|
42
|
+
"@cortexkit/aft-linux-arm64": "0.39.0",
|
|
43
|
+
"@cortexkit/aft-linux-x64": "0.39.0",
|
|
44
|
+
"@cortexkit/aft-win32-arm64": "0.39.0",
|
|
45
|
+
"@cortexkit/aft-win32-x64": "0.39.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@opencode-ai/plugin": "^1.15.11",
|
package/src/shared/rpc-client.ts
CHANGED
|
@@ -281,6 +281,13 @@ export class AftRpcClient {
|
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
this.stalePortFailures.delete(key);
|
|
284
|
+
// Deletion requires a provably-dead owner. Health checks time out under
|
|
285
|
+
// host load (blocked event loop during builds/streaming), and unlinking a
|
|
286
|
+
// LIVE server's port file is permanent: the server only wrote it at
|
|
287
|
+
// startup, so the sidebar could never reconnect until host restart
|
|
288
|
+
// (issue #110). Live-pid and pid-less files are skipped this round and
|
|
289
|
+
// retried on the next poll instead.
|
|
290
|
+
if (info.pid === undefined || isPidAlive(info.pid)) return;
|
|
284
291
|
try {
|
|
285
292
|
// Do not unlink a replacement written after the failed health checks.
|
|
286
293
|
const current = this.parsePortFile(info.path);
|
package/src/shared/rpc-server.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import {
|
|
3
|
+
existsSync,
|
|
3
4
|
mkdirSync,
|
|
4
5
|
readdirSync,
|
|
5
6
|
readFileSync,
|
|
@@ -14,6 +15,8 @@ import { isPidAlive, parseRpcPortRecord, rpcPortFileDir } from "./rpc-utils";
|
|
|
14
15
|
|
|
15
16
|
type RpcHandler = (params: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
16
17
|
|
|
18
|
+
const PORT_FILE_HEARTBEAT_MS = 15_000;
|
|
19
|
+
|
|
17
20
|
export class AftRpcServer {
|
|
18
21
|
private server: Server | null = null;
|
|
19
22
|
private port = 0;
|
|
@@ -21,6 +24,7 @@ export class AftRpcServer {
|
|
|
21
24
|
private handlers = new Map<string, RpcHandler>();
|
|
22
25
|
private portFilePath: string;
|
|
23
26
|
private portsDir: string;
|
|
27
|
+
private heartbeatTimer: ReturnType<typeof setInterval> | null = null;
|
|
24
28
|
/** Unique per-instance ID — distinguishes our entry from duplicate plugin loads. */
|
|
25
29
|
private instanceId: string;
|
|
26
30
|
|
|
@@ -75,6 +79,14 @@ export class AftRpcServer {
|
|
|
75
79
|
);
|
|
76
80
|
renameSync(tmpPath, this.portFilePath);
|
|
77
81
|
log(`RPC server listening on 127.0.0.1:${this.port}`);
|
|
82
|
+
// Self-heal: the port file is this server's only discoverability
|
|
83
|
+
// record, and historically it was written exactly once — anything
|
|
84
|
+
// that deleted it (a client misjudging a load-induced health-check
|
|
85
|
+
// timeout as staleness, cache cleanup, manual sweeps) silently
|
|
86
|
+
// orphaned the server until host restart (issue #110: sidebar stuck
|
|
87
|
+
// on the lazy placeholder forever). Recreate it if it goes missing.
|
|
88
|
+
this.heartbeatTimer = setInterval(() => this.ensurePortFile(), PORT_FILE_HEARTBEAT_MS);
|
|
89
|
+
this.heartbeatTimer.unref?.();
|
|
78
90
|
// Hygiene: sweep dead siblings while we're here. The client only
|
|
79
91
|
// reclaims dead-pid files on a cold port scan, and it caches the
|
|
80
92
|
// first warm port afterwards — so crash/restart leftovers piled up
|
|
@@ -129,8 +141,35 @@ export class AftRpcServer {
|
|
|
129
141
|
}
|
|
130
142
|
}
|
|
131
143
|
|
|
144
|
+
/** Rewrite the port file if it disappeared (wrongful deletion recovery). */
|
|
145
|
+
private ensurePortFile(): void {
|
|
146
|
+
if (!this.server || this.token === null) return;
|
|
147
|
+
try {
|
|
148
|
+
if (existsSync(this.portFilePath)) return;
|
|
149
|
+
const tmpPath = `${this.portFilePath}.tmp`;
|
|
150
|
+
writeFileSync(
|
|
151
|
+
tmpPath,
|
|
152
|
+
JSON.stringify({
|
|
153
|
+
port: this.port,
|
|
154
|
+
token: this.token,
|
|
155
|
+
pid: process.pid,
|
|
156
|
+
started_at: Date.now(),
|
|
157
|
+
}),
|
|
158
|
+
{ encoding: "utf-8", mode: 0o600 },
|
|
159
|
+
);
|
|
160
|
+
renameSync(tmpPath, this.portFilePath);
|
|
161
|
+
log(`RPC port file was missing; rewrote ${this.portFilePath}`);
|
|
162
|
+
} catch {
|
|
163
|
+
// best-effort; retried on the next heartbeat
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
132
167
|
/** Stop the server and clean up port file. */
|
|
133
168
|
stop(): void {
|
|
169
|
+
if (this.heartbeatTimer) {
|
|
170
|
+
clearInterval(this.heartbeatTimer);
|
|
171
|
+
this.heartbeatTimer = null;
|
|
172
|
+
}
|
|
134
173
|
if (this.server) {
|
|
135
174
|
this.server.close();
|
|
136
175
|
this.server = null;
|
package/src/shared/status.ts
CHANGED
|
@@ -337,9 +337,8 @@ export function formatStatusDialogMessage(status: AftStatusSnapshot): string {
|
|
|
337
337
|
`Code Health${sb.tier2_stale ? " (~ stale)" : ""}`,
|
|
338
338
|
`- errors: ${formatCount(sb.errors)}`,
|
|
339
339
|
`- warnings: ${formatCount(sb.warnings)}`,
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// `- unused exports: ${formatCount(sb.unused_exports)}`,
|
|
340
|
+
`- dead code: ${formatCount(sb.dead_code)}`,
|
|
341
|
+
`- unused exports: ${formatCount(sb.unused_exports)}`,
|
|
343
342
|
`- duplicates: ${formatCount(sb.duplicates)}`,
|
|
344
343
|
`- todos: ${formatCount(sb.todos)}`,
|
|
345
344
|
);
|
|
@@ -447,9 +446,8 @@ export function formatStatusMarkdown(status: AftStatusSnapshot): string {
|
|
|
447
446
|
`### Code Health${sb.tier2_stale ? " (~ stale)" : ""}`,
|
|
448
447
|
`- **Errors:** ${formatCount(sb.errors)}`,
|
|
449
448
|
`- **Warnings:** ${formatCount(sb.warnings)}`,
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
// `- **Unused exports:** ${formatCount(sb.unused_exports)}`,
|
|
449
|
+
`- **Dead code:** ${formatCount(sb.dead_code)}`,
|
|
450
|
+
`- **Unused exports:** ${formatCount(sb.unused_exports)}`,
|
|
453
451
|
`- **Duplicates:** ${formatCount(sb.duplicates)}`,
|
|
454
452
|
`- **TODOs:** ${formatCount(sb.todos)}`,
|
|
455
453
|
);
|
package/src/tui/index.tsx
CHANGED
|
@@ -507,9 +507,7 @@ const StatusDialog = (props: StatusDialogProps) => {
|
|
|
507
507
|
value={formatCountShort(status()!.status_bar!.warnings)}
|
|
508
508
|
tone={status()!.status_bar!.warnings > 0 ? "warn" : "muted"}
|
|
509
509
|
/>
|
|
510
|
-
|
|
511
|
-
(current scanner over-reports on barrel re-exports). Restore both. */}
|
|
512
|
-
{/* <R
|
|
510
|
+
<R
|
|
513
511
|
theme={t()}
|
|
514
512
|
label="Dead Code"
|
|
515
513
|
value={formatCountShort(status()!.status_bar!.dead_code)}
|
|
@@ -520,7 +518,7 @@ const StatusDialog = (props: StatusDialogProps) => {
|
|
|
520
518
|
label="Unused Exports"
|
|
521
519
|
value={formatCountShort(status()!.status_bar!.unused_exports)}
|
|
522
520
|
tone="muted"
|
|
523
|
-
/>
|
|
521
|
+
/>
|
|
524
522
|
<R
|
|
525
523
|
theme={t()}
|
|
526
524
|
label="Duplicates"
|
package/src/tui/sidebar.tsx
CHANGED
|
@@ -185,11 +185,8 @@ export type HealthLightTone = "ok" | "warn" | "err";
|
|
|
185
185
|
export interface HealthLights {
|
|
186
186
|
// Diagnostics: red if any errors, yellow if any warnings, else green.
|
|
187
187
|
diagnostics: HealthLightTone;
|
|
188
|
-
// Code cruft: yellow if there is any
|
|
189
|
-
// cruft is not a build failure.
|
|
190
|
-
// temporarily excluded from this signal (and the expanded rows below) until
|
|
191
|
-
// the oxc-based resolver lands and makes those counts trustworthy on real
|
|
192
|
-
// TS/JS codebases. Restore them here when that engine ships.
|
|
188
|
+
// Code cruft: yellow if there is any dead code, unused export, or duplicate,
|
|
189
|
+
// green when zero. Never red — cruft is not a build failure.
|
|
193
190
|
code: HealthLightTone;
|
|
194
191
|
// TODOs: yellow if any, else green.
|
|
195
192
|
todos: HealthLightTone;
|
|
@@ -202,8 +199,9 @@ export function collapsedHealthLights(statusBar: StatusBar | undefined): HealthL
|
|
|
202
199
|
const diagnostics: HealthLightTone =
|
|
203
200
|
statusBar.errors > 0 ? "err" : statusBar.warnings > 0 ? "warn" : "ok";
|
|
204
201
|
const code: HealthLightTone =
|
|
205
|
-
|
|
206
|
-
|
|
202
|
+
statusBar.dead_code > 0 || statusBar.unused_exports > 0 || statusBar.duplicates > 0
|
|
203
|
+
? "warn"
|
|
204
|
+
: "ok";
|
|
207
205
|
const todos: HealthLightTone = statusBar.todos > 0 ? "warn" : "ok";
|
|
208
206
|
return { diagnostics, code, todos };
|
|
209
207
|
}
|
|
@@ -744,11 +742,7 @@ const SidebarContent = (props: {
|
|
|
744
742
|
value={formatCount(statusBar()!.warnings)}
|
|
745
743
|
tone={statusBar()!.warnings > 0 ? "warn" : "muted"}
|
|
746
744
|
/>
|
|
747
|
-
|
|
748
|
-
oxc-based resolver lands and makes these trustworthy on real
|
|
749
|
-
TS/JS codebases (current tree-sitter scanner over-reports via
|
|
750
|
-
barrel re-export gaps). Restore both rows when that ships. */}
|
|
751
|
-
{/* <StatRow
|
|
745
|
+
<StatRow
|
|
752
746
|
theme={props.theme}
|
|
753
747
|
label="Dead Code"
|
|
754
748
|
value={formatCount(statusBar()!.dead_code)}
|
|
@@ -759,7 +753,7 @@ const SidebarContent = (props: {
|
|
|
759
753
|
label="Unused Exports"
|
|
760
754
|
value={formatCount(statusBar()!.unused_exports)}
|
|
761
755
|
tone="muted"
|
|
762
|
-
/>
|
|
756
|
+
/>
|
|
763
757
|
<StatRow
|
|
764
758
|
theme={props.theme}
|
|
765
759
|
label="Duplicates"
|