@jskit-ai/assistant-core 0.2.1 → 0.2.3
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/examples/conversation/package.json +5 -5
- package/fixtures/responsive-assistant/ConversationFixture.vue +2 -2
- package/fixtures/responsive-assistant/DeliveryFixture.vue +15 -2
- package/locales/en.json +4 -2
- package/package.json +5 -5
- package/src/client/conversation/AssistantConversationElement.vue +8 -1
- package/src/client/conversation/AssistantGoalControl.vue +2 -2
- package/src/client/conversation/AssistantTranscript.vue +41 -11
- package/src/client/conversation/messageDelivery.js +23 -6
- package/src/client/lib/assistantApi.js +5 -0
- package/src/server/conversation/claudeProcess.js +171 -53
- package/src/server/conversation/claudeTurn.js +199 -63
- package/src/server/conversation/codexAuthPreflight.js +3 -0
- package/src/server/conversation/codexConfiguration.js +42 -4
- package/src/server/conversation/codexConversations.js +256 -114
- package/src/server/conversation/codexEvents.js +16 -3
- package/src/server/conversation/codexHelperThreadRecovery.js +17 -4
- package/src/server/conversation/codexHelperThreads.js +10 -1
- package/src/server/conversation/codexHomeStorage.js +69 -0
- package/src/server/conversation/codexProcess.js +7 -2
- package/src/server/conversation/codexProvider.js +57 -46
- package/src/server/conversation/codexProviderOwner.js +272 -10
- package/src/server/conversation/codexProviderSelection.js +13 -3
- package/src/server/conversation/codexRuntimeLifecycle.js +56 -4
- package/src/server/conversation/codexSessionCleanup.js +67 -20
- package/src/server/conversation/codexSessionReconciliation.js +18 -4
- package/src/server/conversation/codexTurn.js +9 -2
- package/src/server/conversation/continuity.js +34 -14
- package/src/server/conversation/openCodeClient.js +34 -0
- package/src/server/conversation/openCodeProcess.js +37 -5
- package/src/server/conversation/openCodeRuntime.js +257 -69
- package/src/server/conversation/providers/claudeDriver.js +7 -5
- package/src/server/conversation/providers/codexDriver.js +23 -16
- package/src/server/conversation/providers/opencodeDriver.js +17 -14
- package/src/server/conversation/providers/scoped.js +5 -2
- package/src/server/conversation/runtime.js +93 -6
- package/src/server/hosts/codexConfiguration.js +4 -0
- package/test/assistantScroll.browser.test.js +134 -18
- package/test/claudeConversationSession.test.js +26 -1
- package/test/claudeLifecycle.test.js +293 -0
- package/test/claudeProcess.test.js +364 -33
- package/test/claudeTurn.test.js +192 -3
- package/test/codexAccountChange.test.js +261 -0
- package/test/codexConversationsCheckpoint.test.js +3 -0
- package/test/codexEvents.test.js +23 -1
- package/test/codexHomeStorage.test.js +57 -0
- package/test/codexInteractiveArguments.test.js +9 -0
- package/test/codexLifecycleIsolation.test.js +441 -0
- package/test/codexModelCatalog.test.js +48 -2
- package/test/codexProcess.test.js +21 -0
- package/test/codexTemporaryProviderRelease.test.js +180 -0
- package/test/codexTurn.test.js +52 -1
- package/test/conversationNativeStorage.test.js +284 -0
- package/test/conversationRuntime.test.js +66 -0
- package/test/conversationSession.test.js +4 -8
- package/test/messageDelivery.browser.test.js +18 -2
- package/test/messageDelivery.test.js +34 -1
- package/test/openCodeClient.test.js +31 -0
- package/test/openCodeConnectionChange.test.js +166 -0
- package/test/openCodeProcess.test.js +36 -0
- package/test/openCodeRuntime.test.js +25 -78
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { lstat, readdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
// At process start Codex syncs the openai/plugins repository into `.tmp/plugins`
|
|
5
|
+
// and downloads plugin, app and connector catalogues into `cache/`, roughly
|
|
6
|
+
// 100-250 MB per home, refreshed and never pruned. No JSKIT conversation uses
|
|
7
|
+
// plugins or apps (helper and tool-free threads also disable them per thread),
|
|
8
|
+
// so every Codex process JSKIT launches turns both off. Codex's terminal also
|
|
9
|
+
// starts a shared app-server daemon by default (`daemon_auto_start`, 0.163),
|
|
10
|
+
// with a detached updater that keeps it running after the terminal closes; a
|
|
11
|
+
// JSKIT terminal runs its own process or its host's app-server instead.
|
|
12
|
+
const CODEX_DISABLED_PROCESS_FEATURES = Object.freeze(["plugins", "apps", "daemon_auto_start"]);
|
|
13
|
+
|
|
14
|
+
export function codexDisabledProcessFeatureArguments() {
|
|
15
|
+
return CODEX_DISABLED_PROCESS_FEATURES.flatMap((feature) => ["-c", `features.${feature}=false`]);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// What those features leave behind (Codex 0.162: core-plugins startup_sync.rs,
|
|
19
|
+
// git_policy.rs, marketplace_policy.rs and remote_catalog_cache.rs; connectors
|
|
20
|
+
// directory_cache.rs and connector_runtime persistence.rs). User-installed
|
|
21
|
+
// plugins under `plugins/` and configured marketplaces are not listed.
|
|
22
|
+
const PLUGIN_AND_APP_ENTRIES = Object.freeze([
|
|
23
|
+
[".tmp", /^(?:plugins(?:$|[.-])|git-|bundled-marketplaces$)/u],
|
|
24
|
+
["cache", /^(?:remote_plugin_catalog|codex_apps_tools|codex_apps_server_info|codex_app_directory|bundled_plugin_exclusions)$/u]
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
// A home that will not launch again keeps its auth, config, catalogue, sessions
|
|
28
|
+
// and state/goal/memory/queue/thread-history databases, which retained
|
|
29
|
+
// conversations may still read. Its diagnostic log database and temporary and
|
|
30
|
+
// cache directories serve only a running process; Codex prunes the log database
|
|
31
|
+
// (10 days, 64 MiB) only while it runs.
|
|
32
|
+
const RETIRED_HOME_ENTRIES = /^(?:logs_\d+\.sqlite(?:-wal|-shm)?|\.tmp|cache|tmp)$/u;
|
|
33
|
+
|
|
34
|
+
async function directoryNames(directory) {
|
|
35
|
+
try {
|
|
36
|
+
// Never follow a linked home or subdirectory.
|
|
37
|
+
if (!(await lstat(directory)).isDirectory()) return [];
|
|
38
|
+
return await readdir(directory);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error.code === "ENOENT") return [];
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Existing Codex-owned entries in `codexHome` that no JSKIT-launched Codex
|
|
47
|
+
* uses: plugin and app caches, or with `retired: true` everything runtime-only
|
|
48
|
+
* in a home that will not launch again. Returns sorted absolute paths; a link is
|
|
49
|
+
* returned as itself. Remove them only while no Codex process uses the home.
|
|
50
|
+
*/
|
|
51
|
+
export async function codexHomeDisposablePaths(codexHome, { retired = false } = {}) {
|
|
52
|
+
if (typeof codexHome !== "string" || !path.isAbsolute(codexHome)) {
|
|
53
|
+
throw new TypeError("An absolute Codex home is required.");
|
|
54
|
+
}
|
|
55
|
+
const found = [];
|
|
56
|
+
const names = await directoryNames(codexHome);
|
|
57
|
+
if (retired) {
|
|
58
|
+
for (const name of names) {
|
|
59
|
+
if (RETIRED_HOME_ENTRIES.test(name)) found.push(path.join(codexHome, name));
|
|
60
|
+
}
|
|
61
|
+
} else if (names.length) {
|
|
62
|
+
for (const [directory, pattern] of PLUGIN_AND_APP_ENTRIES) {
|
|
63
|
+
for (const name of await directoryNames(path.join(codexHome, directory))) {
|
|
64
|
+
if (pattern.test(name)) found.push(path.join(codexHome, directory, name));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return found.sort();
|
|
69
|
+
}
|
|
@@ -11,6 +11,7 @@ import { createConversationProcessIdentity } from "./localExecution.js";
|
|
|
11
11
|
import { isRecord, normalizePositiveInteger } from "@jskit-ai/kernel/shared/support/normalize";
|
|
12
12
|
import { normalizeNullableText } from "./normalize.js";
|
|
13
13
|
import { copyCodexProviderHome, prepareCodexModelCatalog } from "./codexConfiguration.js";
|
|
14
|
+
import { codexDisabledProcessFeatureArguments } from "./codexHomeStorage.js";
|
|
14
15
|
import { startCodexHistoryAdapter } from "./codexHistoryAdapter.js";
|
|
15
16
|
|
|
16
17
|
const CODEX_APP_SERVER_METADATA_FILE = "runtime.json";
|
|
@@ -29,14 +30,16 @@ export async function runCodexAppServerProcess({
|
|
|
29
30
|
const abortStartup = () => startup.abort();
|
|
30
31
|
process.once("SIGTERM", abortStartup);
|
|
31
32
|
process.once("SIGINT", abortStartup);
|
|
33
|
+
const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), ".codex");
|
|
32
34
|
const catalogPath = await prepareCodexModelCatalog({
|
|
33
35
|
command,
|
|
34
36
|
runtimeDir,
|
|
35
37
|
bundled,
|
|
36
38
|
additionalModels,
|
|
39
|
+
codexHome,
|
|
37
40
|
signal: startup.signal
|
|
38
41
|
});
|
|
39
|
-
const adapter = await startCodexHistoryAdapter({ token, codexHome
|
|
42
|
+
const adapter = await startCodexHistoryAdapter({ token, codexHome });
|
|
40
43
|
await writeFile(`${descriptor}.tmp`, JSON.stringify({ baseUrl: adapter.baseUrl, runtimeToken: token }), { mode: 0o600 });
|
|
41
44
|
await rename(`${descriptor}.tmp`, descriptor);
|
|
42
45
|
const child = spawn(command, [...args, "-c", `model_catalog_json=${JSON.stringify(catalogPath)}`], { stdio: "inherit" });
|
|
@@ -407,7 +410,7 @@ function codexAppServerRuntimeDirIsManaged(runtimeDir = "") {
|
|
|
407
410
|
basename.startsWith(`${CODEX_APP_SERVER_RUNTIME_DIR_NAME}-`);
|
|
408
411
|
}
|
|
409
412
|
|
|
410
|
-
async function removeCodexAppServerRuntimeDir(runtimeDir = "") {
|
|
413
|
+
export async function removeCodexAppServerRuntimeDir(runtimeDir = "") {
|
|
411
414
|
const normalizedRuntimeDir = normalizeNullableText(runtimeDir);
|
|
412
415
|
if (!codexAppServerRuntimeDirIsManaged(normalizedRuntimeDir)) {
|
|
413
416
|
return false;
|
|
@@ -1231,6 +1234,8 @@ export function createCodexAppServerRuntime({ execution, credentials, configurat
|
|
|
1231
1234
|
]),
|
|
1232
1235
|
"-c",
|
|
1233
1236
|
"check_for_update_on_startup=false",
|
|
1237
|
+
// Plugin and app startup syncs fill the home with unused catalogues.
|
|
1238
|
+
...codexDisabledProcessFeatureArguments(),
|
|
1234
1239
|
...(projectTrustOverride
|
|
1235
1240
|
? [
|
|
1236
1241
|
"-c",
|
|
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { lstat, realpath } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { CodexAppServerJsonRpcClient } from "./codexClient.js";
|
|
5
|
+
import { releaseSupersededCodexRuntime } from "./codexProviderOwner.js";
|
|
5
6
|
import {
|
|
6
7
|
createCodexAccountReader, codexAuthOutputRequiresReconnect, codexAppServerProjectHookTrustConfig,
|
|
7
8
|
codexAppServerTextHasControlCharacters, CODEX_APP_SERVER_ACCOUNT_ID_MAX_LENGTH
|
|
@@ -43,8 +44,6 @@ const CODEX_APP_SERVER_THREAD_INVENTORY_PAGE_LIMIT = 100;
|
|
|
43
44
|
const CODEX_APP_SERVER_THREAD_INVENTORY_MAX_PAGES = 100;
|
|
44
45
|
export const CODEX_APP_SERVER_THREAD_INVENTORY_MAX_COUNT = 1000;
|
|
45
46
|
export const CODEX_APP_SERVER_THREAD_INVENTORY_ID_MAX_LENGTH = 512;
|
|
46
|
-
const CODEX_APP_SERVER_THREAD_INVENTORY_MAX_ENTRY_BYTES = 64 * 1024;
|
|
47
|
-
const CODEX_APP_SERVER_THREAD_INVENTORY_MAX_TOTAL_BYTES = 2 * 1024 * 1024;
|
|
48
47
|
const CODEX_APP_SERVER_HELPER_MAX_MESSAGE_BYTES = 4 * 1024 * 1024;
|
|
49
48
|
const CODEX_APP_SERVER_SERVER_INFO_USER_AGENT_MAX_LENGTH = 512;
|
|
50
49
|
const CODEX_APP_SERVER_CHATGPT_REFRESH_METHOD = "account/chatgptAuthTokens/refresh";
|
|
@@ -337,8 +336,12 @@ async function ensureCodexAppServerThread({
|
|
|
337
336
|
throw new Error("Codex app-server did not return a thread id.");
|
|
338
337
|
}
|
|
339
338
|
stageStartedAt = Date.now();
|
|
340
|
-
await identity.write({ appServerRuntime, threadId, workdir: normalizedWorkdir,
|
|
339
|
+
const recorded = await identity.write({ appServerRuntime, threadId, workdir: normalizedWorkdir,
|
|
341
340
|
...(toolConfiguration ? { toolSchemaIdentity: toolConfiguration.toolSchemaIdentity } : {}) });
|
|
341
|
+
// The session no longer uses the runtime directory it recorded before (an
|
|
342
|
+
// earlier sign-in's). Releasing it is cleanup: a failure keeps the directory.
|
|
343
|
+
const superseded = normalizeAgentText(recorded?.supersededRuntimeDir);
|
|
344
|
+
if (superseded) await releaseSupersededCodexRuntime(superseded).catch(() => null);
|
|
342
345
|
if (providerReady) await providerReady({ provider, threadId });
|
|
343
346
|
onStage({ durationMs: Date.now() - stageStartedAt, stage: "identity-metadata" });
|
|
344
347
|
return {
|
|
@@ -570,6 +573,7 @@ async function listBoundedCodexAppServerThreadIds({
|
|
|
570
573
|
client,
|
|
571
574
|
cwd = "",
|
|
572
575
|
errorCode = "",
|
|
576
|
+
findThreadId = "",
|
|
573
577
|
label = "",
|
|
574
578
|
requestLabel = "",
|
|
575
579
|
runRequest,
|
|
@@ -603,43 +607,35 @@ async function listBoundedCodexAppServerThreadIds({
|
|
|
603
607
|
}, { signal }),
|
|
604
608
|
requestLabel
|
|
605
609
|
);
|
|
606
|
-
if (
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
"exceeded its entry limit"
|
|
615
|
-
);
|
|
610
|
+
if (!Array.isArray(response?.data) || response.data.length > CODEX_APP_SERVER_THREAD_INVENTORY_PAGE_LIMIT) {
|
|
611
|
+
throw codexAppServerThreadInventoryError(errorCode, label, "returned a malformed page");
|
|
612
|
+
}
|
|
613
|
+
// Only thread ids are retained, so only they are bounded. A search for one
|
|
614
|
+
// thread retains none and is bounded by the page limit alone.
|
|
615
|
+
if (!findThreadId && state.entryCount + response.data.length > CODEX_APP_SERVER_THREAD_INVENTORY_MAX_COUNT) {
|
|
616
|
+
throw codexAppServerThreadInventoryError(errorCode, label,
|
|
617
|
+
`exceeded its ${CODEX_APP_SERVER_THREAD_INVENTORY_MAX_COUNT}-thread limit`);
|
|
616
618
|
}
|
|
617
619
|
for (const entry of response.data) {
|
|
618
|
-
const threadId = normalizeAgentText(entry
|
|
619
|
-
const
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
620
|
+
const threadId = isRecord(entry) ? normalizeAgentText(entry.id) : "";
|
|
621
|
+
const refusal = !isRecord(entry) ? "listed an entry that is not a thread"
|
|
622
|
+
: !threadId ? "listed a thread without an id"
|
|
623
|
+
: threadId.length > CODEX_APP_SERVER_THREAD_INVENTORY_ID_MAX_LENGTH
|
|
624
|
+
? `listed a thread id longer than ${CODEX_APP_SERVER_THREAD_INVENTORY_ID_MAX_LENGTH} characters`
|
|
625
|
+
: codexAppServerTextHasControlCharacters(threadId) ? "listed a thread id with control characters"
|
|
626
|
+
: verifyCwd && normalizeAgentText(entry.cwd) !== cwd
|
|
627
|
+
? `listed thread ${threadId} outside the requested directory` : "";
|
|
628
|
+
if (refusal) {
|
|
629
|
+
throw codexAppServerThreadInventoryError(errorCode, label, refusal);
|
|
625
630
|
}
|
|
626
|
-
if (
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
entryBytes > CODEX_APP_SERVER_THREAD_INVENTORY_MAX_ENTRY_BYTES ||
|
|
633
|
-
state.totalBytes + entryBytes > CODEX_APP_SERVER_THREAD_INVENTORY_MAX_TOTAL_BYTES
|
|
634
|
-
) {
|
|
635
|
-
throw codexAppServerThreadInventoryError(
|
|
636
|
-
errorCode,
|
|
637
|
-
label,
|
|
638
|
-
"contained an invalid entry"
|
|
639
|
-
);
|
|
631
|
+
if (findThreadId) {
|
|
632
|
+
if (threadId === findThreadId) {
|
|
633
|
+
state.found = true;
|
|
634
|
+
return state;
|
|
635
|
+
}
|
|
636
|
+
continue;
|
|
640
637
|
}
|
|
641
638
|
state.entryCount += 1;
|
|
642
|
-
state.totalBytes += entryBytes;
|
|
643
639
|
state.threadIds.add(threadId);
|
|
644
640
|
}
|
|
645
641
|
const nextCursor = response.nextCursor === undefined || response.nextCursor === null || response.nextCursor === ""
|
|
@@ -734,6 +730,7 @@ export class CodexAppServerAgentProvider {
|
|
|
734
730
|
this.planUsagePending = null;
|
|
735
731
|
this.planUsageAuthGeneration = 0;
|
|
736
732
|
this.availabilityPromise = null;
|
|
733
|
+
this.stale = false;
|
|
737
734
|
this.options = options;
|
|
738
735
|
this.client = null;
|
|
739
736
|
this.connectPromise = null;
|
|
@@ -955,7 +952,22 @@ export class CodexAppServerAgentProvider {
|
|
|
955
952
|
}
|
|
956
953
|
}
|
|
957
954
|
|
|
955
|
+
// An account change leaves a runtime that is still working on the
|
|
956
|
+
// credentials it started with. Codex reads them once, so this provider
|
|
957
|
+
// finishes its running turn on them and then stops; it never re-checks,
|
|
958
|
+
// replaces or restarts its runtime, and never marks the new account invalid.
|
|
959
|
+
markStale() {
|
|
960
|
+
this.stale = true;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
staleRuntimeError() {
|
|
964
|
+
return Object.assign(new Error("Codex (OpenAI) changed account. Send your message again."), {
|
|
965
|
+
code: `${this.errorPrefix}codex_account_changed`, retryable: true
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
|
|
958
969
|
async prepareRuntime() {
|
|
970
|
+
if (this.stale) throw this.staleRuntimeError();
|
|
959
971
|
const previousRuntime = this.runtime;
|
|
960
972
|
const nextRuntime = await this.host.runtime.ensure(this.host.parameters);
|
|
961
973
|
if (this.options.modelProviderId) nextRuntime.modelProviderId = this.options.modelProviderId;
|
|
@@ -997,7 +1009,7 @@ export class CodexAppServerAgentProvider {
|
|
|
997
1009
|
}
|
|
998
1010
|
|
|
999
1011
|
async assertRuntimeAuthReady(reason = "codex-app-server") {
|
|
1000
|
-
if (this.isHelperProvider()) {
|
|
1012
|
+
if (this.isHelperProvider() || this.stale) {
|
|
1001
1013
|
return;
|
|
1002
1014
|
}
|
|
1003
1015
|
const runtime = this.runtime || {};
|
|
@@ -1047,7 +1059,7 @@ export class CodexAppServerAgentProvider {
|
|
|
1047
1059
|
error?.observed || "",
|
|
1048
1060
|
await tailTextFile(this.runtime?.logPath || "")
|
|
1049
1061
|
].filter(Boolean).join("\n");
|
|
1050
|
-
if (codexAuthOutputRequiresReconnect(observed)) {
|
|
1062
|
+
if (!this.stale && codexAuthOutputRequiresReconnect(observed)) {
|
|
1051
1063
|
const runtime = this.runtime || {};
|
|
1052
1064
|
if (runtime.runtimeDir) {
|
|
1053
1065
|
await this.stopRuntimeAndRequireDrain(reason);
|
|
@@ -1355,6 +1367,7 @@ export class CodexAppServerAgentProvider {
|
|
|
1355
1367
|
|
|
1356
1368
|
async ensureAvailable({ modelProviderId = "" } = {}) {
|
|
1357
1369
|
if (this.observationFailure) throw this.observationFailure;
|
|
1370
|
+
if (this.stale && !this.isAvailable()) throw this.staleRuntimeError();
|
|
1358
1371
|
if (this.isAvailable()) {
|
|
1359
1372
|
return {
|
|
1360
1373
|
client: this.client,
|
|
@@ -1843,8 +1856,7 @@ export class CodexAppServerAgentProvider {
|
|
|
1843
1856
|
signal,
|
|
1844
1857
|
state: {
|
|
1845
1858
|
entryCount: 0,
|
|
1846
|
-
threadIds: new Set()
|
|
1847
|
-
totalBytes: 0
|
|
1859
|
+
threadIds: new Set()
|
|
1848
1860
|
},
|
|
1849
1861
|
verifyCwd: true
|
|
1850
1862
|
});
|
|
@@ -1863,7 +1875,7 @@ export class CodexAppServerAgentProvider {
|
|
|
1863
1875
|
throw new TypeError("Codex descendant inventory requires an exact thread id.");
|
|
1864
1876
|
}
|
|
1865
1877
|
const client = await this.activeClient();
|
|
1866
|
-
const state = { entryCount: 0, threadIds: new Set()
|
|
1878
|
+
const state = { entryCount: 0, threadIds: new Set() };
|
|
1867
1879
|
for (const archived of [false, true]) {
|
|
1868
1880
|
await listBoundedCodexAppServerThreadIds({
|
|
1869
1881
|
ancestorThreadId, archived, client, state,
|
|
@@ -1878,7 +1890,7 @@ export class CodexAppServerAgentProvider {
|
|
|
1878
1890
|
async listNativeThreadsForCwd(cwd) {
|
|
1879
1891
|
if (!path.isAbsolute(cwd || "") || codexAppServerTextHasControlCharacters(cwd)) throw new TypeError("Native inventory requires an exact absolute directory.");
|
|
1880
1892
|
const client = await this.activeClient();
|
|
1881
|
-
const state = { entryCount: 0, threadIds: new Set()
|
|
1893
|
+
const state = { entryCount: 0, threadIds: new Set() };
|
|
1882
1894
|
for (const archived of [false, true]) {
|
|
1883
1895
|
await listBoundedCodexAppServerThreadIds({ archived, client, cwd, state, verifyCwd: true,
|
|
1884
1896
|
sourceKinds: CODEX_NATIVE_STORAGE_SOURCE_KINDS,
|
|
@@ -1894,13 +1906,13 @@ export class CodexAppServerAgentProvider {
|
|
|
1894
1906
|
throw new TypeError("Native existence checks require an exact thread id.");
|
|
1895
1907
|
}
|
|
1896
1908
|
const client = await this.activeClient();
|
|
1897
|
-
const state = { entryCount: 0, threadIds: new Set()
|
|
1909
|
+
const state = { entryCount: 0, found: false, threadIds: new Set() };
|
|
1898
1910
|
for (const archived of [false, true]) {
|
|
1899
|
-
await listBoundedCodexAppServerThreadIds({ archived, client, state, signal,
|
|
1911
|
+
await listBoundedCodexAppServerThreadIds({ archived, client, findThreadId: id, state, signal,
|
|
1900
1912
|
sourceKinds: CODEX_NATIVE_STORAGE_SOURCE_KINDS,
|
|
1901
1913
|
errorCode: `${this.errorPrefix}codex_retirement_inventory_invalid`, label: "native storage",
|
|
1902
1914
|
requestLabel: "codex-app-server-native-existence", runRequest: this.runRequest.bind(this) });
|
|
1903
|
-
if (state.
|
|
1915
|
+
if (state.found) return true;
|
|
1904
1916
|
}
|
|
1905
1917
|
return false;
|
|
1906
1918
|
}
|
|
@@ -1912,8 +1924,7 @@ export class CodexAppServerAgentProvider {
|
|
|
1912
1924
|
const execution = await this.currentHelperExecutionContext();
|
|
1913
1925
|
const state = {
|
|
1914
1926
|
entryCount: 0,
|
|
1915
|
-
threadIds: new Set()
|
|
1916
|
-
totalBytes: 0
|
|
1927
|
+
threadIds: new Set()
|
|
1917
1928
|
};
|
|
1918
1929
|
for (const archived of [false, true]) {
|
|
1919
1930
|
await listBoundedCodexAppServerThreadIds({
|