@cortexkit/aft-opencode 0.19.6 → 0.20.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/bg-notifications.d.ts +11 -0
- package/dist/bg-notifications.d.ts.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/index.d.ts +29 -1
- package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/types.d.ts +18 -0
- package/dist/hooks/auto-update-checker/types.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +383 -175
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/hoisted.d.ts +12 -7
- package/dist/tools/hoisted.d.ts.map +1 -1
- package/dist/tools/search.d.ts +12 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tui.js +7 -7
- package/dist/workflow-hints.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -7803,10 +7803,10 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
7803
7803
|
});
|
|
7804
7804
|
|
|
7805
7805
|
// src/index.ts
|
|
7806
|
-
import { existsSync as
|
|
7806
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
|
|
7807
7807
|
import { createRequire as createRequire2 } from "module";
|
|
7808
7808
|
import { homedir as homedir11 } from "os";
|
|
7809
|
-
import { join as
|
|
7809
|
+
import { join as join19 } from "path";
|
|
7810
7810
|
|
|
7811
7811
|
// ../aft-bridge/dist/active-logger.js
|
|
7812
7812
|
var active;
|
|
@@ -7942,6 +7942,7 @@ class BinaryBridge {
|
|
|
7942
7942
|
onVersionMismatch;
|
|
7943
7943
|
onConfigureWarnings;
|
|
7944
7944
|
onBashCompletion;
|
|
7945
|
+
onBashLongRunning;
|
|
7945
7946
|
configureWarningClients = new Map;
|
|
7946
7947
|
restartResetTimer = null;
|
|
7947
7948
|
errorPrefix;
|
|
@@ -7955,6 +7956,7 @@ class BinaryBridge {
|
|
|
7955
7956
|
this.onVersionMismatch = options?.onVersionMismatch;
|
|
7956
7957
|
this.onConfigureWarnings = options?.onConfigureWarnings;
|
|
7957
7958
|
this.onBashCompletion = options?.onBashCompletion;
|
|
7959
|
+
this.onBashLongRunning = options?.onBashLongRunning;
|
|
7958
7960
|
this.errorPrefix = options?.errorPrefix ?? "[aft-bridge]";
|
|
7959
7961
|
}
|
|
7960
7962
|
get restartCount() {
|
|
@@ -8267,6 +8269,10 @@ class BinaryBridge {
|
|
|
8267
8269
|
this.onBashCompletion?.(response, this);
|
|
8268
8270
|
continue;
|
|
8269
8271
|
}
|
|
8272
|
+
if (response.type === "bash_long_running") {
|
|
8273
|
+
this.onBashLongRunning?.(response, this);
|
|
8274
|
+
continue;
|
|
8275
|
+
}
|
|
8270
8276
|
if (response.type === "configure_warnings") {
|
|
8271
8277
|
this.handleConfigureWarningsFrame(response).catch((err) => {
|
|
8272
8278
|
warn(`configure warning delivery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -9091,7 +9097,8 @@ class BridgePool {
|
|
|
9091
9097
|
minVersion: options.minVersion,
|
|
9092
9098
|
onVersionMismatch: options.onVersionMismatch,
|
|
9093
9099
|
onConfigureWarnings: options.onConfigureWarnings,
|
|
9094
|
-
onBashCompletion: options.onBashCompletion
|
|
9100
|
+
onBashCompletion: options.onBashCompletion,
|
|
9101
|
+
onBashLongRunning: options.onBashLongRunning
|
|
9095
9102
|
};
|
|
9096
9103
|
this.configOverrides = configOverrides;
|
|
9097
9104
|
if (Number.isFinite(this.idleTimeoutMs)) {
|
|
@@ -9905,20 +9912,26 @@ async function handlePushedBgCompletion(drainContext, completion) {
|
|
|
9905
9912
|
ingestBgCompletions(drainContext.sessionID, [completion]);
|
|
9906
9913
|
await triggerWakeIfPending(drainContext, true);
|
|
9907
9914
|
}
|
|
9915
|
+
async function handlePushedBgLongRunning(drainContext, reminder) {
|
|
9916
|
+
stateFor(drainContext.sessionID).pendingLongRunning.push(reminder);
|
|
9917
|
+
await triggerWakeIfPending(drainContext, true);
|
|
9918
|
+
}
|
|
9908
9919
|
async function appendInTurnBgCompletions(drainContext, output) {
|
|
9909
9920
|
if (!output)
|
|
9910
9921
|
return;
|
|
9911
9922
|
const state = stateFor(drainContext.sessionID);
|
|
9912
|
-
if (state.outstandingTaskIds.size === 0 && state.pendingCompletions.length === 0)
|
|
9923
|
+
if (state.outstandingTaskIds.size === 0 && state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0) {
|
|
9913
9924
|
return;
|
|
9925
|
+
}
|
|
9914
9926
|
if (state.outstandingTaskIds.size > 0) {
|
|
9915
9927
|
await drainCompletions(drainContext);
|
|
9916
9928
|
}
|
|
9917
|
-
if (state.pendingCompletions.length === 0)
|
|
9929
|
+
if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
9918
9930
|
return;
|
|
9919
|
-
const reminder =
|
|
9931
|
+
const reminder = formatCombinedSystemReminder(state.pendingCompletions, state.pendingLongRunning);
|
|
9920
9932
|
output.output = appendReminder(output.output ?? "", reminder);
|
|
9921
9933
|
state.pendingCompletions = [];
|
|
9934
|
+
state.pendingLongRunning = [];
|
|
9922
9935
|
}
|
|
9923
9936
|
async function handleIdleBgCompletions(drainContext) {
|
|
9924
9937
|
await triggerWakeIfPending(drainContext, false);
|
|
@@ -9930,7 +9943,7 @@ async function triggerWakeIfPending(drainContext, skipDrain) {
|
|
|
9930
9943
|
if (!skipDrain && state.outstandingTaskIds.size > 0) {
|
|
9931
9944
|
await drainCompletions(drainContext);
|
|
9932
9945
|
}
|
|
9933
|
-
if (state.pendingCompletions.length === 0)
|
|
9946
|
+
if (state.pendingCompletions.length === 0 && state.pendingLongRunning.length === 0)
|
|
9934
9947
|
return;
|
|
9935
9948
|
scheduleWake(state, async (reminder) => {
|
|
9936
9949
|
const client = drainContext.client;
|
|
@@ -9975,6 +9988,23 @@ For truncated tasks, use bash_status({ taskId: "..." }) to retrieve full output.
|
|
|
9975
9988
|
${bullets}${tail}
|
|
9976
9989
|
</system-reminder>`;
|
|
9977
9990
|
}
|
|
9991
|
+
function formatLongRunningReminder(reminders) {
|
|
9992
|
+
const bullets = reminders.map((reminder) => `- ${reminder.task_id} still running after ${formatDurationMs(reminder.elapsed_ms)}: ${shorten(reminder.command, 120)}`).join(`
|
|
9993
|
+
`);
|
|
9994
|
+
return `<system-reminder>
|
|
9995
|
+
[BACKGROUND BASH STILL RUNNING]
|
|
9996
|
+
${bullets}
|
|
9997
|
+
Use bash_status({ taskId: "..." }) to inspect output or bash_kill({ taskId: "..." }) to terminate.
|
|
9998
|
+
</system-reminder>`;
|
|
9999
|
+
}
|
|
10000
|
+
function formatCombinedSystemReminder(completions, longRunning) {
|
|
10001
|
+
if (completions.length === 0)
|
|
10002
|
+
return formatLongRunningReminder(longRunning);
|
|
10003
|
+
if (longRunning.length === 0)
|
|
10004
|
+
return formatSystemReminder(completions);
|
|
10005
|
+
return `${formatSystemReminder(completions)}
|
|
10006
|
+
${formatLongRunningReminder(longRunning)}`;
|
|
10007
|
+
}
|
|
9978
10008
|
function extractSessionID(value) {
|
|
9979
10009
|
if (!value || typeof value !== "object")
|
|
9980
10010
|
return;
|
|
@@ -10008,7 +10038,8 @@ async function drainCompletions({ ctx, directory, sessionID }) {
|
|
|
10008
10038
|
}
|
|
10009
10039
|
function scheduleWake(state, sendWake, onSendFailure) {
|
|
10010
10040
|
const now = Date.now();
|
|
10011
|
-
|
|
10041
|
+
const pendingCount = state.pendingCompletions.length + state.pendingLongRunning.length;
|
|
10042
|
+
if (state.debounceTimer && pendingCount <= state.scheduledCompletionCount) {
|
|
10012
10043
|
return;
|
|
10013
10044
|
}
|
|
10014
10045
|
if (state.firstCompletionAt === null) {
|
|
@@ -10018,14 +10049,16 @@ function scheduleWake(state, sendWake, onSendFailure) {
|
|
|
10018
10049
|
const previousFireAt = state.scheduledFireAt ?? now;
|
|
10019
10050
|
state.scheduledFireAt = Math.min(previousFireAt + DEBOUNCE_STEP_MS, state.firstCompletionAt + DEBOUNCE_CAP_MS);
|
|
10020
10051
|
}
|
|
10021
|
-
state.scheduledCompletionCount =
|
|
10052
|
+
state.scheduledCompletionCount = pendingCount;
|
|
10022
10053
|
if (state.debounceTimer)
|
|
10023
10054
|
clearTimeout(state.debounceTimer);
|
|
10024
10055
|
const delay = state.retryDelayMs ?? Math.max(0, (state.scheduledFireAt ?? now) - now);
|
|
10025
10056
|
state.debounceTimer = setTimeout(() => {
|
|
10026
10057
|
const pending = state.pendingCompletions;
|
|
10027
|
-
const
|
|
10058
|
+
const pendingLongRunning = state.pendingLongRunning;
|
|
10059
|
+
const reminder = formatCombinedSystemReminder(pending, pendingLongRunning);
|
|
10028
10060
|
state.pendingCompletions = [];
|
|
10061
|
+
state.pendingLongRunning = [];
|
|
10029
10062
|
state.debounceTimer = null;
|
|
10030
10063
|
state.firstCompletionAt = null;
|
|
10031
10064
|
state.scheduledFireAt = null;
|
|
@@ -10035,6 +10068,7 @@ function scheduleWake(state, sendWake, onSendFailure) {
|
|
|
10035
10068
|
state.wakeFiredThisIdle = true;
|
|
10036
10069
|
}).catch((err) => {
|
|
10037
10070
|
state.pendingCompletions = [...pending, ...state.pendingCompletions];
|
|
10071
|
+
state.pendingLongRunning = [...pendingLongRunning, ...state.pendingLongRunning];
|
|
10038
10072
|
state.retryDelayMs = Math.min((delay || DEBOUNCE_STEP_MS) * 2, DEBOUNCE_CAP_MS);
|
|
10039
10073
|
onSendFailure(err);
|
|
10040
10074
|
scheduleWake(state, sendWake, onSendFailure);
|
|
@@ -10051,6 +10085,7 @@ function stateFor(sessionID) {
|
|
|
10051
10085
|
state = {
|
|
10052
10086
|
outstandingTaskIds: new Set,
|
|
10053
10087
|
pendingCompletions: [],
|
|
10088
|
+
pendingLongRunning: [],
|
|
10054
10089
|
debounceTimer: null,
|
|
10055
10090
|
wakeFiredThisIdle: false,
|
|
10056
10091
|
firstCompletionAt: null,
|
|
@@ -10101,6 +10136,17 @@ function appendReminder(output, reminder) {
|
|
|
10101
10136
|
|
|
10102
10137
|
${reminder}` : reminder;
|
|
10103
10138
|
}
|
|
10139
|
+
function formatDurationMs(ms) {
|
|
10140
|
+
if (!Number.isFinite(ms) || ms < 1000)
|
|
10141
|
+
return `${Math.max(0, Math.round(ms))}ms`;
|
|
10142
|
+
const totalSeconds = Math.round(ms / 1000);
|
|
10143
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
10144
|
+
const seconds = totalSeconds % 60;
|
|
10145
|
+
return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`;
|
|
10146
|
+
}
|
|
10147
|
+
function shorten(value, limit) {
|
|
10148
|
+
return value.length <= limit ? value : `${value.slice(0, limit - 1)}\u2026`;
|
|
10149
|
+
}
|
|
10104
10150
|
function formatCompletion(completion) {
|
|
10105
10151
|
const status = formatStatus(completion);
|
|
10106
10152
|
const duration = formatDuration(completion);
|
|
@@ -23739,7 +23785,9 @@ var ExperimentalConfigSchema = exports_external.object({
|
|
|
23739
23785
|
bash: exports_external.object({
|
|
23740
23786
|
rewrite: exports_external.boolean().optional(),
|
|
23741
23787
|
compress: exports_external.boolean().optional(),
|
|
23742
|
-
background: exports_external.boolean().optional()
|
|
23788
|
+
background: exports_external.boolean().optional(),
|
|
23789
|
+
long_running_reminder_enabled: exports_external.boolean().optional(),
|
|
23790
|
+
long_running_reminder_interval_ms: exports_external.number().int().positive().optional()
|
|
23743
23791
|
}).optional(),
|
|
23744
23792
|
lsp_ty: exports_external.boolean().optional()
|
|
23745
23793
|
});
|
|
@@ -23820,6 +23868,12 @@ function resolveExperimentalConfigForConfigure(config2) {
|
|
|
23820
23868
|
if (config2.experimental?.bash?.background !== undefined) {
|
|
23821
23869
|
overrides.experimental_bash_background = config2.experimental.bash.background;
|
|
23822
23870
|
}
|
|
23871
|
+
if (config2.experimental?.bash?.long_running_reminder_enabled !== undefined) {
|
|
23872
|
+
overrides.bash_long_running_reminder_enabled = config2.experimental.bash.long_running_reminder_enabled;
|
|
23873
|
+
}
|
|
23874
|
+
if (config2.experimental?.bash?.long_running_reminder_interval_ms !== undefined) {
|
|
23875
|
+
overrides.bash_long_running_reminder_interval_ms = config2.experimental.bash.long_running_reminder_interval_ms;
|
|
23876
|
+
}
|
|
23823
23877
|
if (config2.experimental?.lsp_ty !== undefined) {
|
|
23824
23878
|
overrides.experimental_lsp_ty = config2.experimental.lsp_ty;
|
|
23825
23879
|
}
|
|
@@ -24150,6 +24204,10 @@ function loadAftConfig(projectDirectory) {
|
|
|
24150
24204
|
return config2;
|
|
24151
24205
|
}
|
|
24152
24206
|
|
|
24207
|
+
// src/hooks/auto-update-checker/index.ts
|
|
24208
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, renameSync as renameSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
24209
|
+
import { dirname as dirname4, join as join11 } from "path";
|
|
24210
|
+
|
|
24153
24211
|
// src/hooks/auto-update-checker/cache.ts
|
|
24154
24212
|
var import_comment_json3 = __toESM(require_src2(), 1);
|
|
24155
24213
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -24547,6 +24605,9 @@ async function runNpmInstallSafe(installDir, options = {}) {
|
|
|
24547
24605
|
}
|
|
24548
24606
|
|
|
24549
24607
|
// src/hooks/auto-update-checker/index.ts
|
|
24608
|
+
var DEFAULT_CHECK_INTERVAL_MS = 60 * 60 * 1000;
|
|
24609
|
+
var DEFAULT_INIT_DELAY_MS = 5000;
|
|
24610
|
+
var TIMESTAMP_FILENAME = "last-update-check.json";
|
|
24550
24611
|
function createAutoUpdateCheckerHook(ctx, options = {}) {
|
|
24551
24612
|
const {
|
|
24552
24613
|
enabled = true,
|
|
@@ -24554,40 +24615,68 @@ function createAutoUpdateCheckerHook(ctx, options = {}) {
|
|
|
24554
24615
|
autoUpdate = true,
|
|
24555
24616
|
npmRegistryUrl = NPM_REGISTRY_URL,
|
|
24556
24617
|
fetchTimeoutMs = NPM_FETCH_TIMEOUT,
|
|
24557
|
-
signal = new AbortController().signal
|
|
24618
|
+
signal = new AbortController().signal,
|
|
24619
|
+
storageDir = null,
|
|
24620
|
+
checkIntervalMs = DEFAULT_CHECK_INTERVAL_MS,
|
|
24621
|
+
initDelayMs = DEFAULT_INIT_DELAY_MS
|
|
24558
24622
|
} = options;
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24562
|
-
|
|
24563
|
-
|
|
24564
|
-
|
|
24565
|
-
|
|
24566
|
-
|
|
24567
|
-
|
|
24568
|
-
|
|
24569
|
-
|
|
24570
|
-
|
|
24571
|
-
|
|
24572
|
-
|
|
24573
|
-
|
|
24574
|
-
|
|
24575
|
-
|
|
24576
|
-
|
|
24577
|
-
|
|
24578
|
-
|
|
24579
|
-
|
|
24580
|
-
|
|
24581
|
-
};
|
|
24623
|
+
if (!enabled) {
|
|
24624
|
+
return async (_input) => {};
|
|
24625
|
+
}
|
|
24626
|
+
const initTimer = setTimeout(() => {
|
|
24627
|
+
maybeRunCheck(ctx, {
|
|
24628
|
+
showStartupToast,
|
|
24629
|
+
autoUpdate,
|
|
24630
|
+
npmRegistryUrl,
|
|
24631
|
+
fetchTimeoutMs,
|
|
24632
|
+
signal,
|
|
24633
|
+
storageDir,
|
|
24634
|
+
checkIntervalMs,
|
|
24635
|
+
initDelayMs
|
|
24636
|
+
}).catch((err) => {
|
|
24637
|
+
warn2(`[auto-update-checker] Background update check failed: ${String(err)}`);
|
|
24638
|
+
});
|
|
24639
|
+
}, initDelayMs);
|
|
24640
|
+
if (typeof initTimer === "object" && initTimer !== null && "unref" in initTimer) {
|
|
24641
|
+
initTimer.unref();
|
|
24642
|
+
}
|
|
24643
|
+
signal.addEventListener("abort", () => {
|
|
24644
|
+
clearTimeout(initTimer);
|
|
24645
|
+
}, { once: true });
|
|
24646
|
+
return async (_input) => {};
|
|
24582
24647
|
}
|
|
24583
|
-
function
|
|
24584
|
-
if (
|
|
24585
|
-
return
|
|
24586
|
-
|
|
24587
|
-
|
|
24588
|
-
return
|
|
24589
|
-
|
|
24590
|
-
|
|
24648
|
+
async function maybeRunCheck(ctx, options) {
|
|
24649
|
+
if (options.signal.aborted)
|
|
24650
|
+
return;
|
|
24651
|
+
if (!claimCheckSlot(options.storageDir, options.checkIntervalMs)) {
|
|
24652
|
+
log2("[auto-update-checker] Skipping check (another instance ran one recently)");
|
|
24653
|
+
return;
|
|
24654
|
+
}
|
|
24655
|
+
await runStartupCheck(ctx, options);
|
|
24656
|
+
}
|
|
24657
|
+
function claimCheckSlot(storageDir, intervalMs) {
|
|
24658
|
+
if (!storageDir)
|
|
24659
|
+
return true;
|
|
24660
|
+
try {
|
|
24661
|
+
const file2 = join11(storageDir, TIMESTAMP_FILENAME);
|
|
24662
|
+
if (existsSync8(file2)) {
|
|
24663
|
+
try {
|
|
24664
|
+
const raw = JSON.parse(readFileSync6(file2, "utf-8"));
|
|
24665
|
+
const last = typeof raw.lastCheckedMs === "number" ? raw.lastCheckedMs : 0;
|
|
24666
|
+
if (Number.isFinite(last) && Date.now() - last < intervalMs) {
|
|
24667
|
+
return false;
|
|
24668
|
+
}
|
|
24669
|
+
} catch {}
|
|
24670
|
+
}
|
|
24671
|
+
mkdirSync5(dirname4(file2), { recursive: true });
|
|
24672
|
+
const tmp = `${file2}.tmp.${process.pid}`;
|
|
24673
|
+
writeFileSync6(tmp, JSON.stringify({ lastCheckedMs: Date.now() }), "utf-8");
|
|
24674
|
+
renameSync3(tmp, file2);
|
|
24675
|
+
return true;
|
|
24676
|
+
} catch (err) {
|
|
24677
|
+
warn2(`[auto-update-checker] Could not coordinate via timestamp file: ${String(err)}`);
|
|
24678
|
+
return true;
|
|
24679
|
+
}
|
|
24591
24680
|
}
|
|
24592
24681
|
async function runStartupCheck(ctx, options) {
|
|
24593
24682
|
if (options.signal.aborted)
|
|
@@ -24675,43 +24764,43 @@ import { createReadStream, statSync as statSync4 } from "fs";
|
|
|
24675
24764
|
// src/lsp-cache.ts
|
|
24676
24765
|
import {
|
|
24677
24766
|
closeSync as closeSync2,
|
|
24678
|
-
mkdirSync as
|
|
24767
|
+
mkdirSync as mkdirSync6,
|
|
24679
24768
|
openSync as openSync2,
|
|
24680
|
-
readFileSync as
|
|
24769
|
+
readFileSync as readFileSync7,
|
|
24681
24770
|
statSync as statSync3,
|
|
24682
24771
|
unlinkSync as unlinkSync5,
|
|
24683
|
-
writeFileSync as
|
|
24772
|
+
writeFileSync as writeFileSync7
|
|
24684
24773
|
} from "fs";
|
|
24685
24774
|
import { homedir as homedir8 } from "os";
|
|
24686
|
-
import { join as
|
|
24775
|
+
import { join as join12 } from "path";
|
|
24687
24776
|
function aftCacheBase() {
|
|
24688
24777
|
const override = process.env.AFT_CACHE_DIR;
|
|
24689
24778
|
if (override && override.length > 0)
|
|
24690
24779
|
return override;
|
|
24691
24780
|
if (process.platform === "win32") {
|
|
24692
24781
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
24693
|
-
const base2 = localAppData ||
|
|
24694
|
-
return
|
|
24782
|
+
const base2 = localAppData || join12(homedir8(), "AppData", "Local");
|
|
24783
|
+
return join12(base2, "aft");
|
|
24695
24784
|
}
|
|
24696
|
-
const base = process.env.XDG_CACHE_HOME ||
|
|
24697
|
-
return
|
|
24785
|
+
const base = process.env.XDG_CACHE_HOME || join12(homedir8(), ".cache");
|
|
24786
|
+
return join12(base, "aft");
|
|
24698
24787
|
}
|
|
24699
24788
|
function lspCacheRoot() {
|
|
24700
|
-
return
|
|
24789
|
+
return join12(aftCacheBase(), "lsp-packages");
|
|
24701
24790
|
}
|
|
24702
24791
|
function lspPackageDir(npmPackage) {
|
|
24703
|
-
return
|
|
24792
|
+
return join12(lspCacheRoot(), encodeURIComponent(npmPackage));
|
|
24704
24793
|
}
|
|
24705
24794
|
function lspBinaryPath(npmPackage, binary) {
|
|
24706
|
-
return
|
|
24795
|
+
return join12(lspPackageDir(npmPackage), "node_modules", ".bin", binary);
|
|
24707
24796
|
}
|
|
24708
24797
|
function lspBinDir(npmPackage) {
|
|
24709
|
-
return
|
|
24798
|
+
return join12(lspPackageDir(npmPackage), "node_modules", ".bin");
|
|
24710
24799
|
}
|
|
24711
24800
|
function isInstalled(npmPackage, binary) {
|
|
24712
24801
|
for (const candidate of lspBinaryCandidates(binary)) {
|
|
24713
24802
|
try {
|
|
24714
|
-
if (statSync3(
|
|
24803
|
+
if (statSync3(join12(lspBinDir(npmPackage), candidate)).isFile())
|
|
24715
24804
|
return true;
|
|
24716
24805
|
} catch {}
|
|
24717
24806
|
}
|
|
@@ -24725,23 +24814,23 @@ function lspBinaryCandidates(binary) {
|
|
|
24725
24814
|
var INSTALLED_META_FILE = ".aft-installed";
|
|
24726
24815
|
function writeInstalledMetaIn(installDir, version2, sha256) {
|
|
24727
24816
|
try {
|
|
24728
|
-
|
|
24817
|
+
mkdirSync6(installDir, { recursive: true });
|
|
24729
24818
|
const meta3 = {
|
|
24730
24819
|
version: version2,
|
|
24731
24820
|
installedAt: new Date().toISOString(),
|
|
24732
24821
|
...sha256 ? { sha256 } : {}
|
|
24733
24822
|
};
|
|
24734
|
-
|
|
24823
|
+
writeFileSync7(join12(installDir, INSTALLED_META_FILE), JSON.stringify(meta3), "utf8");
|
|
24735
24824
|
} catch (err) {
|
|
24736
24825
|
log2(`[lsp-cache] failed to write installed-meta in ${installDir}: ${err}`);
|
|
24737
24826
|
}
|
|
24738
24827
|
}
|
|
24739
24828
|
function readInstalledMetaIn(installDir) {
|
|
24740
|
-
const path2 =
|
|
24829
|
+
const path2 = join12(installDir, INSTALLED_META_FILE);
|
|
24741
24830
|
try {
|
|
24742
24831
|
if (!statSync3(path2).isFile())
|
|
24743
24832
|
return null;
|
|
24744
|
-
const raw =
|
|
24833
|
+
const raw = readFileSync7(path2, "utf8");
|
|
24745
24834
|
const parsed = JSON.parse(raw);
|
|
24746
24835
|
if (typeof parsed.version !== "string" || parsed.version.length === 0)
|
|
24747
24836
|
return null;
|
|
@@ -24761,17 +24850,17 @@ function readInstalledMeta(packageKey) {
|
|
|
24761
24850
|
return readInstalledMetaIn(lspPackageDir(packageKey));
|
|
24762
24851
|
}
|
|
24763
24852
|
function lockPath(npmPackage) {
|
|
24764
|
-
return
|
|
24853
|
+
return join12(lspPackageDir(npmPackage), ".aft-installing");
|
|
24765
24854
|
}
|
|
24766
24855
|
var STALE_LOCK_MS2 = 30 * 60 * 1000;
|
|
24767
24856
|
function acquireInstallLock(lockKey) {
|
|
24768
|
-
|
|
24857
|
+
mkdirSync6(lspPackageDir(lockKey), { recursive: true });
|
|
24769
24858
|
const lock = lockPath(lockKey);
|
|
24770
24859
|
const tryClaim = () => {
|
|
24771
24860
|
try {
|
|
24772
24861
|
const fd = openSync2(lock, "wx");
|
|
24773
24862
|
try {
|
|
24774
|
-
|
|
24863
|
+
writeFileSync7(fd, `${process.pid}
|
|
24775
24864
|
${new Date().toISOString()}
|
|
24776
24865
|
`);
|
|
24777
24866
|
} finally {
|
|
@@ -24791,7 +24880,7 @@ ${new Date().toISOString()}
|
|
|
24791
24880
|
let owningPid = null;
|
|
24792
24881
|
let lockMtimeMs = 0;
|
|
24793
24882
|
try {
|
|
24794
|
-
const raw =
|
|
24883
|
+
const raw = readFileSync7(lock, "utf8");
|
|
24795
24884
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
24796
24885
|
const parsed = Number.parseInt(firstLine, 10);
|
|
24797
24886
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -24829,7 +24918,7 @@ function releaseInstallLock(lockKey) {
|
|
|
24829
24918
|
try {
|
|
24830
24919
|
let owningPid = null;
|
|
24831
24920
|
try {
|
|
24832
|
-
const raw =
|
|
24921
|
+
const raw = readFileSync7(lock, "utf8");
|
|
24833
24922
|
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
24834
24923
|
const parsed = Number.parseInt(firstLine, 10);
|
|
24835
24924
|
if (Number.isFinite(parsed) && parsed > 0)
|
|
@@ -24868,9 +24957,9 @@ async function withInstallLock(lockKey, task) {
|
|
|
24868
24957
|
}
|
|
24869
24958
|
var VERSION_CHECK_FILE = ".aft-version-check";
|
|
24870
24959
|
function readVersionCheck(npmPackage) {
|
|
24871
|
-
const file2 =
|
|
24960
|
+
const file2 = join12(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
24872
24961
|
try {
|
|
24873
|
-
const raw =
|
|
24962
|
+
const raw = readFileSync7(file2, "utf8");
|
|
24874
24963
|
const parsed = JSON.parse(raw);
|
|
24875
24964
|
if (typeof parsed.last_checked === "string") {
|
|
24876
24965
|
return {
|
|
@@ -24884,13 +24973,13 @@ function readVersionCheck(npmPackage) {
|
|
|
24884
24973
|
}
|
|
24885
24974
|
}
|
|
24886
24975
|
function writeVersionCheck(npmPackage, latest) {
|
|
24887
|
-
|
|
24888
|
-
const file2 =
|
|
24976
|
+
mkdirSync6(lspPackageDir(npmPackage), { recursive: true });
|
|
24977
|
+
const file2 = join12(lspPackageDir(npmPackage), VERSION_CHECK_FILE);
|
|
24889
24978
|
const record2 = {
|
|
24890
24979
|
last_checked: new Date().toISOString(),
|
|
24891
24980
|
latest_eligible: latest
|
|
24892
24981
|
};
|
|
24893
|
-
|
|
24982
|
+
writeFileSync7(file2, JSON.stringify(record2, null, 2));
|
|
24894
24983
|
}
|
|
24895
24984
|
function shouldRecheckVersion(record2, weeklyCheckIntervalMs = 7 * 24 * 60 * 60 * 1000) {
|
|
24896
24985
|
if (!record2)
|
|
@@ -25033,8 +25122,8 @@ var NPM_LSP_TABLE = [
|
|
|
25033
25122
|
];
|
|
25034
25123
|
|
|
25035
25124
|
// src/lsp-project-relevance.ts
|
|
25036
|
-
import { existsSync as
|
|
25037
|
-
import { join as
|
|
25125
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
|
|
25126
|
+
import { join as join13 } from "path";
|
|
25038
25127
|
var MAX_WALK_DIRS = 200;
|
|
25039
25128
|
var MAX_WALK_DEPTH = 4;
|
|
25040
25129
|
var NOISE_DIRS = new Set([
|
|
@@ -25051,7 +25140,7 @@ function hasRootMarker(projectRoot, rootMarkers) {
|
|
|
25051
25140
|
if (!rootMarkers)
|
|
25052
25141
|
return false;
|
|
25053
25142
|
for (const marker of rootMarkers) {
|
|
25054
|
-
if (
|
|
25143
|
+
if (existsSync9(join13(projectRoot, marker)))
|
|
25055
25144
|
return true;
|
|
25056
25145
|
}
|
|
25057
25146
|
return false;
|
|
@@ -25077,7 +25166,7 @@ function relevantExtensionsInProject(projectRoot, extToServer) {
|
|
|
25077
25166
|
for (const entry of entries) {
|
|
25078
25167
|
if (entry.isDirectory()) {
|
|
25079
25168
|
if (current.depth < MAX_WALK_DEPTH && !NOISE_DIRS.has(entry.name.toLowerCase())) {
|
|
25080
|
-
queue.push({ dir:
|
|
25169
|
+
queue.push({ dir: join13(current.dir, entry.name), depth: current.depth + 1 });
|
|
25081
25170
|
}
|
|
25082
25171
|
continue;
|
|
25083
25172
|
}
|
|
@@ -25416,18 +25505,18 @@ import {
|
|
|
25416
25505
|
copyFileSync as copyFileSync3,
|
|
25417
25506
|
createReadStream as createReadStream2,
|
|
25418
25507
|
createWriteStream as createWriteStream2,
|
|
25419
|
-
existsSync as
|
|
25508
|
+
existsSync as existsSync10,
|
|
25420
25509
|
lstatSync as lstatSync2,
|
|
25421
|
-
mkdirSync as
|
|
25510
|
+
mkdirSync as mkdirSync7,
|
|
25422
25511
|
readdirSync as readdirSync4,
|
|
25423
25512
|
readlinkSync as readlinkSync2,
|
|
25424
25513
|
realpathSync as realpathSync3,
|
|
25425
|
-
renameSync as
|
|
25514
|
+
renameSync as renameSync4,
|
|
25426
25515
|
rmSync as rmSync3,
|
|
25427
25516
|
statSync as statSync5,
|
|
25428
25517
|
unlinkSync as unlinkSync6
|
|
25429
25518
|
} from "fs";
|
|
25430
|
-
import { dirname as
|
|
25519
|
+
import { dirname as dirname5, join as join14, relative as relative2, resolve as resolve3 } from "path";
|
|
25431
25520
|
import { Readable as Readable2 } from "stream";
|
|
25432
25521
|
import { pipeline as pipeline2 } from "stream/promises";
|
|
25433
25522
|
|
|
@@ -25517,25 +25606,25 @@ function detectHostPlatform() {
|
|
|
25517
25606
|
|
|
25518
25607
|
// src/lsp-github-install.ts
|
|
25519
25608
|
function ghCacheRoot() {
|
|
25520
|
-
return
|
|
25609
|
+
return join14(aftCacheBase(), "lsp-binaries");
|
|
25521
25610
|
}
|
|
25522
25611
|
function ghPackageDir(spec) {
|
|
25523
|
-
return
|
|
25612
|
+
return join14(ghCacheRoot(), spec.id);
|
|
25524
25613
|
}
|
|
25525
25614
|
function ghBinDir(spec) {
|
|
25526
|
-
return
|
|
25615
|
+
return join14(ghPackageDir(spec), "bin");
|
|
25527
25616
|
}
|
|
25528
25617
|
function ghExtractDir(spec) {
|
|
25529
|
-
return
|
|
25618
|
+
return join14(ghPackageDir(spec), "extracted");
|
|
25530
25619
|
}
|
|
25531
25620
|
function ghBinaryPath(spec, platform2) {
|
|
25532
25621
|
const ext = platform2 === "win32" ? ".exe" : "";
|
|
25533
|
-
return
|
|
25622
|
+
return join14(ghBinDir(spec), `${spec.binary}${ext}`);
|
|
25534
25623
|
}
|
|
25535
25624
|
function isGithubInstalled(spec, platform2) {
|
|
25536
25625
|
for (const candidate of ghBinaryCandidates(spec, platform2)) {
|
|
25537
25626
|
try {
|
|
25538
|
-
if (statSync5(
|
|
25627
|
+
if (statSync5(join14(ghBinDir(spec), candidate)).isFile())
|
|
25539
25628
|
return true;
|
|
25540
25629
|
} catch {}
|
|
25541
25630
|
}
|
|
@@ -25723,7 +25812,7 @@ async function downloadFile(url2, destPath, fetchImpl, assetSize, signal) {
|
|
|
25723
25812
|
if (Number.isFinite(advertised) && advertised > MAX_DOWNLOAD_BYTES2) {
|
|
25724
25813
|
throw new Error(`Content-Length ${advertised} exceeds max ${MAX_DOWNLOAD_BYTES2}`);
|
|
25725
25814
|
}
|
|
25726
|
-
|
|
25815
|
+
mkdirSync7(dirname5(destPath), { recursive: true });
|
|
25727
25816
|
let bytesWritten = 0;
|
|
25728
25817
|
const guard = new TransformStream({
|
|
25729
25818
|
transform(chunk, controller) {
|
|
@@ -25758,7 +25847,7 @@ function validateExtraction(stagingRoot) {
|
|
|
25758
25847
|
throw new Error(`failed to read staging dir ${dir}: ${err}`);
|
|
25759
25848
|
}
|
|
25760
25849
|
for (const entry of entries) {
|
|
25761
|
-
const full =
|
|
25850
|
+
const full = join14(dir, entry);
|
|
25762
25851
|
let lst;
|
|
25763
25852
|
try {
|
|
25764
25853
|
lst = lstatSync2(full);
|
|
@@ -25802,14 +25891,14 @@ function extractArchiveSafely(archivePath, destDir, archiveType) {
|
|
|
25802
25891
|
try {
|
|
25803
25892
|
rmSync3(stagingDir, { recursive: true, force: true });
|
|
25804
25893
|
} catch {}
|
|
25805
|
-
|
|
25894
|
+
mkdirSync7(stagingDir, { recursive: true });
|
|
25806
25895
|
try {
|
|
25807
25896
|
runPlatformExtractor(archivePath, stagingDir, archiveType);
|
|
25808
25897
|
validateExtraction(stagingDir);
|
|
25809
25898
|
try {
|
|
25810
25899
|
rmSync3(destDir, { recursive: true, force: true });
|
|
25811
25900
|
} catch {}
|
|
25812
|
-
|
|
25901
|
+
renameSync4(stagingDir, destDir);
|
|
25813
25902
|
} catch (err) {
|
|
25814
25903
|
try {
|
|
25815
25904
|
rmSync3(stagingDir, { recursive: true, force: true });
|
|
@@ -25862,7 +25951,7 @@ async function downloadAndInstall(spec, tag, assets, platform2, arch, fetchImpl,
|
|
|
25862
25951
|
}
|
|
25863
25952
|
const pkgDir = ghPackageDir(spec);
|
|
25864
25953
|
const extractDir = ghExtractDir(spec);
|
|
25865
|
-
const archivePath =
|
|
25954
|
+
const archivePath = join14(pkgDir, expected.name);
|
|
25866
25955
|
log2(`[lsp] downloading ${spec.id} ${tag} \u2192 ${matchingAsset.url}`);
|
|
25867
25956
|
try {
|
|
25868
25957
|
await downloadFile(matchingAsset.url, archivePath, fetchImpl, matchingAsset.size, signal);
|
|
@@ -25901,13 +25990,13 @@ async function downloadAndInstall(spec, tag, assets, platform2, arch, fetchImpl,
|
|
|
25901
25990
|
unlinkSync6(archivePath);
|
|
25902
25991
|
} catch {}
|
|
25903
25992
|
}
|
|
25904
|
-
const innerBinaryPath =
|
|
25905
|
-
if (!
|
|
25993
|
+
const innerBinaryPath = join14(extractDir, spec.binaryPathInArchive(platform2, arch, version2));
|
|
25994
|
+
if (!existsSync10(innerBinaryPath)) {
|
|
25906
25995
|
error2(`[lsp] ${spec.id}: extracted binary not found at ${innerBinaryPath}`);
|
|
25907
25996
|
return null;
|
|
25908
25997
|
}
|
|
25909
25998
|
const targetBinary = ghBinaryPath(spec, platform2);
|
|
25910
|
-
|
|
25999
|
+
mkdirSync7(dirname5(targetBinary), { recursive: true });
|
|
25911
26000
|
try {
|
|
25912
26001
|
copyFileSync3(innerBinaryPath, targetBinary);
|
|
25913
26002
|
if (platform2 !== "win32") {
|
|
@@ -25984,7 +26073,7 @@ function runGithubAutoInstall(relevantServers, config2, fetchImpl = fetch) {
|
|
|
25984
26073
|
if (!host) {
|
|
25985
26074
|
for (const spec of GITHUB_LSP_TABLE) {
|
|
25986
26075
|
try {
|
|
25987
|
-
if (
|
|
26076
|
+
if (existsSync10(ghBinDir(spec))) {
|
|
25988
26077
|
cachedBinDirs.push(ghBinDir(spec));
|
|
25989
26078
|
}
|
|
25990
26079
|
} catch {}
|
|
@@ -26147,9 +26236,9 @@ function normalizeToolMap(tools) {
|
|
|
26147
26236
|
}
|
|
26148
26237
|
|
|
26149
26238
|
// src/notifications.ts
|
|
26150
|
-
import { existsSync as
|
|
26239
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
26151
26240
|
import { homedir as homedir9, platform as platform2 } from "os";
|
|
26152
|
-
import { join as
|
|
26241
|
+
import { join as join15 } from "path";
|
|
26153
26242
|
function isTuiMode() {
|
|
26154
26243
|
return process.env.OPENCODE_CLIENT === "cli";
|
|
26155
26244
|
}
|
|
@@ -26173,25 +26262,25 @@ function getDesktopStatePath() {
|
|
|
26173
26262
|
const os2 = platform2();
|
|
26174
26263
|
const home = homedir9();
|
|
26175
26264
|
if (os2 === "darwin") {
|
|
26176
|
-
return
|
|
26265
|
+
return join15(home, "Library", "Application Support", "ai.opencode.desktop", "opencode.global.dat");
|
|
26177
26266
|
}
|
|
26178
26267
|
if (os2 === "linux") {
|
|
26179
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ||
|
|
26180
|
-
return
|
|
26268
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || join15(home, ".config");
|
|
26269
|
+
return join15(xdgConfig, "ai.opencode.desktop", "opencode.global.dat");
|
|
26181
26270
|
}
|
|
26182
26271
|
if (os2 === "win32") {
|
|
26183
|
-
const appData = process.env.APPDATA ||
|
|
26184
|
-
return
|
|
26272
|
+
const appData = process.env.APPDATA || join15(home, "AppData", "Roaming");
|
|
26273
|
+
return join15(appData, "ai.opencode.desktop", "opencode.global.dat");
|
|
26185
26274
|
}
|
|
26186
26275
|
return null;
|
|
26187
26276
|
}
|
|
26188
26277
|
function readDesktopState(directory) {
|
|
26189
26278
|
const statePath = getDesktopStatePath();
|
|
26190
|
-
if (!statePath || !
|
|
26279
|
+
if (!statePath || !existsSync11(statePath)) {
|
|
26191
26280
|
return { sessionId: null, serverUrl: null };
|
|
26192
26281
|
}
|
|
26193
26282
|
try {
|
|
26194
|
-
const raw =
|
|
26283
|
+
const raw = readFileSync8(statePath, "utf-8");
|
|
26195
26284
|
const state = JSON.parse(raw);
|
|
26196
26285
|
let serverUrl = null;
|
|
26197
26286
|
const serverStr = state.server;
|
|
@@ -26285,10 +26374,10 @@ async function sendWarning(opts, message) {
|
|
|
26285
26374
|
}
|
|
26286
26375
|
async function sendFeatureAnnouncement(opts, version2, features, storageDir) {
|
|
26287
26376
|
if (storageDir) {
|
|
26288
|
-
const versionFile =
|
|
26377
|
+
const versionFile = join15(storageDir, "last_announced_version");
|
|
26289
26378
|
try {
|
|
26290
|
-
if (
|
|
26291
|
-
const lastVersion =
|
|
26379
|
+
if (existsSync11(versionFile)) {
|
|
26380
|
+
const lastVersion = readFileSync8(versionFile, "utf-8").trim();
|
|
26292
26381
|
if (lastVersion === version2)
|
|
26293
26382
|
return;
|
|
26294
26383
|
}
|
|
@@ -26308,17 +26397,17 @@ async function sendFeatureAnnouncement(opts, version2, features, storageDir) {
|
|
|
26308
26397
|
}
|
|
26309
26398
|
if (storageDir) {
|
|
26310
26399
|
try {
|
|
26311
|
-
|
|
26312
|
-
|
|
26400
|
+
mkdirSync8(storageDir, { recursive: true });
|
|
26401
|
+
writeFileSync8(join15(storageDir, "last_announced_version"), version2);
|
|
26313
26402
|
} catch {}
|
|
26314
26403
|
}
|
|
26315
26404
|
}
|
|
26316
26405
|
function readWarnedTools(storageDir) {
|
|
26317
26406
|
try {
|
|
26318
|
-
const warnedToolsPath =
|
|
26319
|
-
if (!
|
|
26407
|
+
const warnedToolsPath = join15(storageDir, WARNED_TOOLS_FILE);
|
|
26408
|
+
if (!existsSync11(warnedToolsPath))
|
|
26320
26409
|
return {};
|
|
26321
|
-
const parsed = JSON.parse(
|
|
26410
|
+
const parsed = JSON.parse(readFileSync8(warnedToolsPath, "utf-8"));
|
|
26322
26411
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
26323
26412
|
return {};
|
|
26324
26413
|
const warned = {};
|
|
@@ -26334,9 +26423,9 @@ function readWarnedTools(storageDir) {
|
|
|
26334
26423
|
}
|
|
26335
26424
|
function writeWarnedTools(storageDir, warned) {
|
|
26336
26425
|
try {
|
|
26337
|
-
|
|
26338
|
-
const warnedToolsPath =
|
|
26339
|
-
|
|
26426
|
+
mkdirSync8(storageDir, { recursive: true });
|
|
26427
|
+
const warnedToolsPath = join15(storageDir, WARNED_TOOLS_FILE);
|
|
26428
|
+
writeFileSync8(warnedToolsPath, `${JSON.stringify(warned, null, 2)}
|
|
26340
26429
|
`);
|
|
26341
26430
|
} catch {}
|
|
26342
26431
|
}
|
|
@@ -26429,20 +26518,20 @@ async function cleanupWarnings(opts) {
|
|
|
26429
26518
|
|
|
26430
26519
|
// src/shared/rpc-server.ts
|
|
26431
26520
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
26432
|
-
import { mkdirSync as
|
|
26521
|
+
import { mkdirSync as mkdirSync9, renameSync as renameSync5, unlinkSync as unlinkSync7, writeFileSync as writeFileSync9 } from "fs";
|
|
26433
26522
|
import { createServer } from "http";
|
|
26434
|
-
import { dirname as
|
|
26523
|
+
import { dirname as dirname6 } from "path";
|
|
26435
26524
|
|
|
26436
26525
|
// src/shared/rpc-utils.ts
|
|
26437
26526
|
import { createHash as createHash5 } from "crypto";
|
|
26438
|
-
import { join as
|
|
26527
|
+
import { join as join16 } from "path";
|
|
26439
26528
|
function projectHash(directory) {
|
|
26440
26529
|
const normalized = directory.replace(/\/+$/, "");
|
|
26441
26530
|
return createHash5("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
26442
26531
|
}
|
|
26443
26532
|
function rpcPortFilePath(storageDir, directory) {
|
|
26444
26533
|
const hash2 = projectHash(directory);
|
|
26445
|
-
return
|
|
26534
|
+
return join16(storageDir, "rpc", hash2, "port");
|
|
26446
26535
|
}
|
|
26447
26536
|
|
|
26448
26537
|
// src/shared/rpc-server.ts
|
|
@@ -26475,11 +26564,11 @@ class AftRpcServer {
|
|
|
26475
26564
|
this.token = randomBytes2(32).toString("hex");
|
|
26476
26565
|
this.server = server;
|
|
26477
26566
|
try {
|
|
26478
|
-
const dir =
|
|
26479
|
-
|
|
26567
|
+
const dir = dirname6(this.portFilePath);
|
|
26568
|
+
mkdirSync9(dir, { recursive: true });
|
|
26480
26569
|
const tmpPath = `${this.portFilePath}.tmp`;
|
|
26481
|
-
|
|
26482
|
-
|
|
26570
|
+
writeFileSync9(tmpPath, JSON.stringify({ port: this.port, token: this.token }), "utf-8");
|
|
26571
|
+
renameSync5(tmpPath, this.portFilePath);
|
|
26483
26572
|
log2(`RPC server listening on 127.0.0.1:${this.port}`);
|
|
26484
26573
|
} catch (err) {
|
|
26485
26574
|
warn2(`Failed to write RPC port file: ${err}`);
|
|
@@ -26774,21 +26863,21 @@ function formatStatusMarkdown(status) {
|
|
|
26774
26863
|
|
|
26775
26864
|
// src/shared/tui-config.ts
|
|
26776
26865
|
var import_comment_json4 = __toESM(require_src2(), 1);
|
|
26777
|
-
import { existsSync as
|
|
26778
|
-
import { dirname as
|
|
26866
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "fs";
|
|
26867
|
+
import { dirname as dirname7, join as join18 } from "path";
|
|
26779
26868
|
|
|
26780
26869
|
// src/shared/opencode-config-dir.ts
|
|
26781
26870
|
import { homedir as homedir10 } from "os";
|
|
26782
|
-
import { join as
|
|
26871
|
+
import { join as join17, resolve as resolve4 } from "path";
|
|
26783
26872
|
function getCliConfigDir() {
|
|
26784
26873
|
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
26785
26874
|
if (envConfigDir) {
|
|
26786
26875
|
return resolve4(envConfigDir);
|
|
26787
26876
|
}
|
|
26788
26877
|
if (process.platform === "win32") {
|
|
26789
|
-
return
|
|
26878
|
+
return join17(homedir10(), ".config", "opencode");
|
|
26790
26879
|
}
|
|
26791
|
-
return
|
|
26880
|
+
return join17(process.env.XDG_CONFIG_HOME || join17(homedir10(), ".config"), "opencode");
|
|
26792
26881
|
}
|
|
26793
26882
|
function getOpenCodeConfigDir2(_options) {
|
|
26794
26883
|
return getCliConfigDir();
|
|
@@ -26797,10 +26886,10 @@ function getOpenCodeConfigPaths(options) {
|
|
|
26797
26886
|
const configDir = getOpenCodeConfigDir2(options);
|
|
26798
26887
|
return {
|
|
26799
26888
|
configDir,
|
|
26800
|
-
configJson:
|
|
26801
|
-
configJsonc:
|
|
26802
|
-
packageJson:
|
|
26803
|
-
omoConfig:
|
|
26889
|
+
configJson: join17(configDir, "opencode.json"),
|
|
26890
|
+
configJsonc: join17(configDir, "opencode.jsonc"),
|
|
26891
|
+
packageJson: join17(configDir, "package.json"),
|
|
26892
|
+
omoConfig: join17(configDir, "magic-context.jsonc")
|
|
26804
26893
|
};
|
|
26805
26894
|
}
|
|
26806
26895
|
|
|
@@ -26809,11 +26898,11 @@ var PLUGIN_NAME = "@cortexkit/aft-opencode";
|
|
|
26809
26898
|
var PLUGIN_ENTRY = `${PLUGIN_NAME}@latest`;
|
|
26810
26899
|
function resolveTuiConfigPath() {
|
|
26811
26900
|
const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
26812
|
-
const jsoncPath =
|
|
26813
|
-
const jsonPath =
|
|
26814
|
-
if (
|
|
26901
|
+
const jsoncPath = join18(configDir, "tui.jsonc");
|
|
26902
|
+
const jsonPath = join18(configDir, "tui.json");
|
|
26903
|
+
if (existsSync12(jsoncPath))
|
|
26815
26904
|
return jsoncPath;
|
|
26816
|
-
if (
|
|
26905
|
+
if (existsSync12(jsonPath))
|
|
26817
26906
|
return jsonPath;
|
|
26818
26907
|
return jsonPath;
|
|
26819
26908
|
}
|
|
@@ -26821,8 +26910,8 @@ function ensureTuiPluginEntry() {
|
|
|
26821
26910
|
try {
|
|
26822
26911
|
const configPath = resolveTuiConfigPath();
|
|
26823
26912
|
let config2 = {};
|
|
26824
|
-
if (
|
|
26825
|
-
config2 = import_comment_json4.parse(
|
|
26913
|
+
if (existsSync12(configPath)) {
|
|
26914
|
+
config2 = import_comment_json4.parse(readFileSync9(configPath, "utf-8")) ?? {};
|
|
26826
26915
|
}
|
|
26827
26916
|
const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((value) => typeof value === "string") : [];
|
|
26828
26917
|
if (plugins.some((plugin) => plugin === PLUGIN_NAME || plugin.startsWith(`${PLUGIN_NAME}@`) || plugin.includes("opencode-plugin") || plugin.includes("aft-opencode"))) {
|
|
@@ -26830,8 +26919,8 @@ function ensureTuiPluginEntry() {
|
|
|
26830
26919
|
}
|
|
26831
26920
|
plugins.push(PLUGIN_ENTRY);
|
|
26832
26921
|
config2.plugin = plugins;
|
|
26833
|
-
|
|
26834
|
-
|
|
26922
|
+
mkdirSync10(dirname7(configPath), { recursive: true });
|
|
26923
|
+
writeFileSync10(configPath, `${import_comment_json4.stringify(config2, null, 2)}
|
|
26835
26924
|
`);
|
|
26836
26925
|
log2(`[aft-plugin] added TUI plugin entry to ${configPath}`);
|
|
26837
26926
|
return true;
|
|
@@ -27568,8 +27657,9 @@ ${chunk.old_lines.join(`
|
|
|
27568
27657
|
import { tool as tool3 } from "@opencode-ai/plugin";
|
|
27569
27658
|
var z3 = tool3.schema;
|
|
27570
27659
|
var METADATA_PREVIEW_LIMIT = 30 * 1024;
|
|
27571
|
-
var
|
|
27572
|
-
var
|
|
27660
|
+
var FOREGROUND_WAIT_WINDOW_MS = 5000;
|
|
27661
|
+
var FOREGROUND_POLL_INTERVAL_MS = 100;
|
|
27662
|
+
var BASH_TRANSPORT_TIMEOUT_MS = 30000;
|
|
27573
27663
|
var BASH_DESCRIPTION = `Hoisted bash tool with output compression, command rewriting to AFT tools, and optional background execution. By default, output is compressed; pass compressed: false for raw output. Pass background: true to spawn in the background and get a task_id for bash_status/bash_kill.`;
|
|
27574
27664
|
async function withPermissionLoop(ctx, runtime, params, bridgeCall, options) {
|
|
27575
27665
|
const first = await bridgeCall(ctx, runtime, "bash", params, options);
|
|
@@ -27598,7 +27688,7 @@ function createBashTool(ctx) {
|
|
|
27598
27688
|
description: BASH_DESCRIPTION,
|
|
27599
27689
|
args: {
|
|
27600
27690
|
command: z3.string().describe("Shell command to execute through AFT's unified bash schema. Supports normal shell syntax, pipes, redirection, and command rewriting to dedicated AFT tools when available."),
|
|
27601
|
-
timeout: z3.number().optional().describe("
|
|
27691
|
+
timeout: z3.number().int().positive().optional().describe("Hard kill cap in milliseconds (positive integer). When omitted, the task can run up to 30 minutes. Foreground bash returns inline if the command finishes within ~5s; otherwise it's automatically promoted to background and a completion reminder is delivered when the task actually finishes."),
|
|
27602
27692
|
workdir: z3.string().optional().describe("Working directory for command execution. Relative paths resolve through the bridge; defaults to the current tool context/project root when omitted."),
|
|
27603
27693
|
description: z3.string().optional().describe("Short 5-10 word human-readable summary shown in OpenCode UI metadata instead of raw shell syntax."),
|
|
27604
27694
|
background: z3.boolean().optional().describe("When true, spawn the command in the background and return a task_id for bash_status/bash_kill instead of waiting for completion. Defaults to false."),
|
|
@@ -27618,10 +27708,11 @@ function createBashTool(ctx) {
|
|
|
27618
27708
|
env: shellEnv?.env ?? {},
|
|
27619
27709
|
description,
|
|
27620
27710
|
background: args.background,
|
|
27711
|
+
notify_on_completion: args.background === true,
|
|
27621
27712
|
compressed: args.compressed,
|
|
27622
27713
|
permissions_requested: true
|
|
27623
27714
|
}, callBridge, {
|
|
27624
|
-
transportTimeoutMs:
|
|
27715
|
+
transportTimeoutMs: BASH_TRANSPORT_TIMEOUT_MS,
|
|
27625
27716
|
keepBridgeOnTimeout: true,
|
|
27626
27717
|
onProgress: ({ text }) => {
|
|
27627
27718
|
accumulatedOutput = preview(accumulatedOutput + text);
|
|
@@ -27634,17 +27725,58 @@ function createBashTool(ctx) {
|
|
|
27634
27725
|
if (data.status === "running" && typeof data.task_id === "string") {
|
|
27635
27726
|
const callID2 = getCallID(context);
|
|
27636
27727
|
const taskId = data.task_id;
|
|
27637
|
-
|
|
27638
|
-
|
|
27639
|
-
|
|
27640
|
-
|
|
27641
|
-
|
|
27642
|
-
|
|
27643
|
-
|
|
27644
|
-
|
|
27645
|
-
|
|
27728
|
+
if (args.background === true) {
|
|
27729
|
+
trackBgTask(context.sessionID, taskId);
|
|
27730
|
+
const startedLine = formatBackgroundLaunch(taskId);
|
|
27731
|
+
const metadataPayload2 = { description, output: startedLine, status: "running", taskId };
|
|
27732
|
+
metadata?.(metadataPayload2);
|
|
27733
|
+
if (callID2) {
|
|
27734
|
+
storeToolMetadata(context.sessionID, callID2, {
|
|
27735
|
+
title: description ?? shortenCommand(command),
|
|
27736
|
+
metadata: metadataPayload2
|
|
27737
|
+
});
|
|
27738
|
+
}
|
|
27739
|
+
return startedLine;
|
|
27740
|
+
}
|
|
27741
|
+
const argTimeout = args.timeout;
|
|
27742
|
+
const waitTimeoutMs = argTimeout !== undefined ? Math.min(argTimeout, FOREGROUND_WAIT_WINDOW_MS) : FOREGROUND_WAIT_WINDOW_MS;
|
|
27743
|
+
const startedAt = Date.now();
|
|
27744
|
+
while (true) {
|
|
27745
|
+
const status = await callBridge(ctx, context, "bash_status", { task_id: taskId });
|
|
27746
|
+
if (status.success === false) {
|
|
27747
|
+
throw new Error(status.message ?? "bash_status failed");
|
|
27748
|
+
}
|
|
27749
|
+
if (isTerminalStatus(status.status)) {
|
|
27750
|
+
const rendered2 = formatForegroundResult(status);
|
|
27751
|
+
const metadataPayload2 = foregroundMetadata(description, status, rendered2);
|
|
27752
|
+
metadata?.(metadataPayload2);
|
|
27753
|
+
if (callID2) {
|
|
27754
|
+
storeToolMetadata(context.sessionID, callID2, {
|
|
27755
|
+
title: description ?? shortenCommand(command),
|
|
27756
|
+
metadata: metadataPayload2
|
|
27757
|
+
});
|
|
27758
|
+
}
|
|
27759
|
+
return rendered2;
|
|
27760
|
+
}
|
|
27761
|
+
if (Date.now() - startedAt >= waitTimeoutMs) {
|
|
27762
|
+
const promoted = await callBridge(ctx, context, "bash_promote", { task_id: taskId });
|
|
27763
|
+
if (promoted.success === false) {
|
|
27764
|
+
throw new Error(promoted.message ?? "bash_promote failed");
|
|
27765
|
+
}
|
|
27766
|
+
trackBgTask(context.sessionID, taskId);
|
|
27767
|
+
const message = formatPromotionMessage(taskId, args.timeout);
|
|
27768
|
+
const metadataPayload2 = { description, output: message, status: "running", taskId };
|
|
27769
|
+
metadata?.(metadataPayload2);
|
|
27770
|
+
if (callID2) {
|
|
27771
|
+
storeToolMetadata(context.sessionID, callID2, {
|
|
27772
|
+
title: description ?? shortenCommand(command),
|
|
27773
|
+
metadata: metadataPayload2
|
|
27774
|
+
});
|
|
27775
|
+
}
|
|
27776
|
+
return message;
|
|
27777
|
+
}
|
|
27778
|
+
await sleep(FOREGROUND_POLL_INTERVAL_MS);
|
|
27646
27779
|
}
|
|
27647
|
-
return startedLine;
|
|
27648
27780
|
}
|
|
27649
27781
|
const output = data.output ?? "";
|
|
27650
27782
|
const metadataOutput = preview(output);
|
|
@@ -27731,13 +27863,53 @@ function createBashKillTool(ctx) {
|
|
|
27731
27863
|
}
|
|
27732
27864
|
};
|
|
27733
27865
|
}
|
|
27734
|
-
function bashTransportTimeoutMs(timeout) {
|
|
27735
|
-
const bashTimeout = timeout ?? DEFAULT_BASH_TIMEOUT_MS;
|
|
27736
|
-
return Math.max(30000, bashTimeout + BASH_TRANSPORT_TIMEOUT_OVERHEAD_MS);
|
|
27737
|
-
}
|
|
27738
27866
|
function preview(output) {
|
|
27739
27867
|
return output.length <= METADATA_PREVIEW_LIMIT ? output : output.slice(-METADATA_PREVIEW_LIMIT);
|
|
27740
27868
|
}
|
|
27869
|
+
function isTerminalStatus(status) {
|
|
27870
|
+
return status === "completed" || status === "failed" || status === "killed" || status === "timed_out";
|
|
27871
|
+
}
|
|
27872
|
+
function formatBackgroundLaunch(taskId) {
|
|
27873
|
+
return `Background task started: ${taskId}. A completion reminder will be delivered automatically; don't poll bash_status.`;
|
|
27874
|
+
}
|
|
27875
|
+
function formatPromotionMessage(taskId, timeout) {
|
|
27876
|
+
const waited = timeout !== undefined ? Math.min(timeout, FOREGROUND_WAIT_WINDOW_MS) : FOREGROUND_WAIT_WINDOW_MS;
|
|
27877
|
+
return `Foreground bash didn't finish within ${waited}ms and was promoted to background: ${taskId}. A completion reminder will be delivered automatically; use bash_status({ taskId: "${taskId}" }) to inspect output or bash_kill({ taskId: "${taskId}" }) to terminate.`;
|
|
27878
|
+
}
|
|
27879
|
+
function formatForegroundResult(data) {
|
|
27880
|
+
const output = data.output_preview ?? "";
|
|
27881
|
+
const outputPath = data.output_path;
|
|
27882
|
+
const truncated = data.output_truncated === true;
|
|
27883
|
+
const status = data.status;
|
|
27884
|
+
const exit = data.exit_code;
|
|
27885
|
+
let rendered = output;
|
|
27886
|
+
if (truncated && outputPath) {
|
|
27887
|
+
rendered += `
|
|
27888
|
+
[output truncated; full output at ${outputPath}]`;
|
|
27889
|
+
}
|
|
27890
|
+
if (status === "timed_out") {
|
|
27891
|
+
rendered += `
|
|
27892
|
+
[command timed out]`;
|
|
27893
|
+
}
|
|
27894
|
+
if (typeof exit === "number" && exit !== 0) {
|
|
27895
|
+
rendered += `
|
|
27896
|
+
[exit code: ${exit}]`;
|
|
27897
|
+
}
|
|
27898
|
+
return rendered;
|
|
27899
|
+
}
|
|
27900
|
+
function foregroundMetadata(description, data, rendered) {
|
|
27901
|
+
const outputPath = data.output_path;
|
|
27902
|
+
return {
|
|
27903
|
+
description,
|
|
27904
|
+
output: preview(rendered),
|
|
27905
|
+
exit: data.exit_code,
|
|
27906
|
+
truncated: data.output_truncated,
|
|
27907
|
+
...outputPath ? { outputPath } : {}
|
|
27908
|
+
};
|
|
27909
|
+
}
|
|
27910
|
+
function sleep(ms) {
|
|
27911
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
27912
|
+
}
|
|
27741
27913
|
function getCallID(ctx) {
|
|
27742
27914
|
const c = ctx;
|
|
27743
27915
|
return c.callID ?? c.callId ?? c.call_id;
|
|
@@ -28797,8 +28969,6 @@ function hoistedTools(ctx) {
|
|
|
28797
28969
|
const anyBashExperimental = bashRewrite || bashCompress || bashBackground;
|
|
28798
28970
|
if (anyBashExperimental) {
|
|
28799
28971
|
tools.bash = createBashTool(ctx);
|
|
28800
|
-
}
|
|
28801
|
-
if (bashBackground) {
|
|
28802
28972
|
tools.bash_status = createBashStatusTool(ctx);
|
|
28803
28973
|
tools.bash_kill = createBashKillTool(ctx);
|
|
28804
28974
|
}
|
|
@@ -29445,6 +29615,36 @@ function normalizeGlob(pattern) {
|
|
|
29445
29615
|
}
|
|
29446
29616
|
return pattern;
|
|
29447
29617
|
}
|
|
29618
|
+
function splitIncludeArg(raw) {
|
|
29619
|
+
const out = [];
|
|
29620
|
+
let depth = 0;
|
|
29621
|
+
let buf = "";
|
|
29622
|
+
for (const ch of raw) {
|
|
29623
|
+
if (ch === "{") {
|
|
29624
|
+
depth++;
|
|
29625
|
+
buf += ch;
|
|
29626
|
+
continue;
|
|
29627
|
+
}
|
|
29628
|
+
if (ch === "}") {
|
|
29629
|
+
if (depth > 0)
|
|
29630
|
+
depth--;
|
|
29631
|
+
buf += ch;
|
|
29632
|
+
continue;
|
|
29633
|
+
}
|
|
29634
|
+
if (ch === "," && depth === 0) {
|
|
29635
|
+
const trimmed = buf.trim();
|
|
29636
|
+
if (trimmed.length > 0)
|
|
29637
|
+
out.push(trimmed);
|
|
29638
|
+
buf = "";
|
|
29639
|
+
continue;
|
|
29640
|
+
}
|
|
29641
|
+
buf += ch;
|
|
29642
|
+
}
|
|
29643
|
+
const tail = buf.trim();
|
|
29644
|
+
if (tail.length > 0)
|
|
29645
|
+
out.push(tail);
|
|
29646
|
+
return out;
|
|
29647
|
+
}
|
|
29448
29648
|
function searchTools(ctx) {
|
|
29449
29649
|
const grepTool = {
|
|
29450
29650
|
description: "Search file contents using regular expressions. Returns matching lines with file paths, line numbers, and context.",
|
|
@@ -29457,7 +29657,7 @@ function searchTools(ctx) {
|
|
|
29457
29657
|
const response = await callBridge(ctx, context, "grep", {
|
|
29458
29658
|
pattern: args.pattern,
|
|
29459
29659
|
case_sensitive: true,
|
|
29460
|
-
include: args.include ? String(args.include)
|
|
29660
|
+
include: args.include ? splitIncludeArg(String(args.include)).map(normalizeGlob).filter(Boolean) : undefined,
|
|
29461
29661
|
path: args.path,
|
|
29462
29662
|
max_results: 100
|
|
29463
29663
|
});
|
|
@@ -29707,12 +29907,8 @@ function buildWorkflowHints(opts) {
|
|
|
29707
29907
|
].join(`
|
|
29708
29908
|
`));
|
|
29709
29909
|
}
|
|
29710
|
-
if (hasBash) {
|
|
29711
|
-
|
|
29712
|
-
sections.push(`**Long-running commands** (builds, installs, full test suites): \`${bashName}({ background: true })\` returns immediately with a \`taskId\`. A completion reminder is delivered automatically \u2014 do not poll \`${bashStatusName}({ taskId })\`. Use \`${bashStatusName}\` only after the reminder arrives, or to inspect a task you already know is complete.`);
|
|
29713
|
-
} else {
|
|
29714
|
-
sections.push(`**Long-running bash commands**: foreground \`${bashName}\` times out after 30 seconds. Pass \`timeout\` in milliseconds to extend it for commands you know will take longer.`);
|
|
29715
|
-
}
|
|
29910
|
+
if (hasBash && hasBgBash) {
|
|
29911
|
+
sections.push(`**Long-running commands** (builds, installs, full test suites): \`${bashName}({ background: true })\` returns immediately with a \`taskId\`. A completion reminder is delivered automatically \u2014 do not poll \`${bashStatusName}({ taskId })\`. Use \`${bashStatusName}\` only after the reminder arrives, or to inspect a task you already know is complete.`);
|
|
29716
29912
|
}
|
|
29717
29913
|
if (sections.length === 0) {
|
|
29718
29914
|
return null;
|
|
@@ -29839,8 +30035,8 @@ var plugin = async (input) => {
|
|
|
29839
30035
|
if (aftConfig.max_callgraph_files !== undefined)
|
|
29840
30036
|
configOverrides.max_callgraph_files = aftConfig.max_callgraph_files;
|
|
29841
30037
|
const isFastembedSemanticBackend = (aftConfig.semantic?.backend ?? "fastembed") === "fastembed";
|
|
29842
|
-
const dataHome = process.env.XDG_DATA_HOME ||
|
|
29843
|
-
configOverrides.storage_dir =
|
|
30038
|
+
const dataHome = process.env.XDG_DATA_HOME || join19(homedir11(), ".local", "share");
|
|
30039
|
+
configOverrides.storage_dir = join19(dataHome, "opencode", "storage", "plugin", "aft");
|
|
29844
30040
|
let onnxRuntimePromise = null;
|
|
29845
30041
|
if (aftConfig.semantic_search && isFastembedSemanticBackend) {
|
|
29846
30042
|
const storageDir2 = configOverrides.storage_dir;
|
|
@@ -29916,7 +30112,7 @@ ${lines}
|
|
|
29916
30112
|
warn2(`[lsp] auto-install setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
29917
30113
|
}
|
|
29918
30114
|
let versionUpgradeAttempted = null;
|
|
29919
|
-
const
|
|
30115
|
+
const poolOptions = {
|
|
29920
30116
|
errorPrefix: "[aft-plugin]",
|
|
29921
30117
|
minVersion: PLUGIN_VERSION,
|
|
29922
30118
|
onVersionMismatch: (binaryVersion, minVersion) => {
|
|
@@ -29959,8 +30155,19 @@ ${lines}
|
|
|
29959
30155
|
client: input.client,
|
|
29960
30156
|
isActive: () => bridge.hasPendingRequests()
|
|
29961
30157
|
}, completion);
|
|
30158
|
+
},
|
|
30159
|
+
onBashLongRunning: (reminder, bridge) => {
|
|
30160
|
+
const sessionDir = getSessionDirectoryCached(reminder.session_id) ?? input.directory;
|
|
30161
|
+
handlePushedBgLongRunning({
|
|
30162
|
+
ctx,
|
|
30163
|
+
directory: sessionDir,
|
|
30164
|
+
sessionID: reminder.session_id,
|
|
30165
|
+
client: input.client,
|
|
30166
|
+
isActive: () => bridge.hasPendingRequests()
|
|
30167
|
+
}, reminder);
|
|
29962
30168
|
}
|
|
29963
|
-
}
|
|
30169
|
+
};
|
|
30170
|
+
const pool = new BridgePool(binaryPath, poolOptions, configOverrides);
|
|
29964
30171
|
const ctx = {
|
|
29965
30172
|
pool,
|
|
29966
30173
|
client: input.client,
|
|
@@ -30036,10 +30243,10 @@ ${lines}
|
|
|
30036
30243
|
return { show: false };
|
|
30037
30244
|
}
|
|
30038
30245
|
if (storageDir) {
|
|
30039
|
-
const versionFile =
|
|
30246
|
+
const versionFile = join19(storageDir, "last_announced_version");
|
|
30040
30247
|
try {
|
|
30041
|
-
if (
|
|
30042
|
-
const lastVersion =
|
|
30248
|
+
if (existsSync14(versionFile)) {
|
|
30249
|
+
const lastVersion = readFileSync10(versionFile, "utf-8").trim();
|
|
30043
30250
|
if (lastVersion === ANNOUNCEMENT_VERSION)
|
|
30044
30251
|
return { show: false };
|
|
30045
30252
|
}
|
|
@@ -30050,8 +30257,8 @@ ${lines}
|
|
|
30050
30257
|
rpcServer.handle("mark-announced", async () => {
|
|
30051
30258
|
if (storageDir && ANNOUNCEMENT_VERSION) {
|
|
30052
30259
|
try {
|
|
30053
|
-
|
|
30054
|
-
|
|
30260
|
+
mkdirSync11(storageDir, { recursive: true });
|
|
30261
|
+
writeFileSync11(join19(storageDir, "last_announced_version"), ANNOUNCEMENT_VERSION);
|
|
30055
30262
|
} catch {}
|
|
30056
30263
|
}
|
|
30057
30264
|
return { success: true };
|
|
@@ -30135,7 +30342,8 @@ Install: ${getManualInstallHint()}`).catch(() => {});
|
|
|
30135
30342
|
const autoUpdateEventHook = createAutoUpdateCheckerHook(input, {
|
|
30136
30343
|
enabled: true,
|
|
30137
30344
|
autoUpdate: aftConfig.auto_update ?? true,
|
|
30138
|
-
signal: autoUpdateAbort.signal
|
|
30345
|
+
signal: autoUpdateAbort.signal,
|
|
30346
|
+
storageDir: ctx.storageDir
|
|
30139
30347
|
});
|
|
30140
30348
|
const HINTS_TOOL_NAMES = [
|
|
30141
30349
|
"aft_outline",
|