perchai-cli 2.4.49 → 2.4.51
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/perch.mjs +798 -651
- package/package.json +1 -1
package/dist/perch.mjs
CHANGED
|
@@ -75918,6 +75918,7 @@ function isTurnAbortedError(error) {
|
|
|
75918
75918
|
var TURN_STOPPED_BY_USER_MESSAGE;
|
|
75919
75919
|
var init_turnAbort = __esm({
|
|
75920
75920
|
"features/perchTerminal/runtime/turnAbort.ts"() {
|
|
75921
|
+
"use strict";
|
|
75921
75922
|
TURN_STOPPED_BY_USER_MESSAGE = "Turn stopped by user.";
|
|
75922
75923
|
}
|
|
75923
75924
|
});
|
|
@@ -76223,6 +76224,7 @@ function getToolDisplayName(toolName) {
|
|
|
76223
76224
|
var NON_MODULE_TOOL_OWNERS, TOOL_RISK, TOOL_DISPLAY_NAMES;
|
|
76224
76225
|
var init_catalog = __esm({
|
|
76225
76226
|
"features/perchTerminal/runtime/toolSystem/catalog.ts"() {
|
|
76227
|
+
"use strict";
|
|
76226
76228
|
init_toolNames();
|
|
76227
76229
|
NON_MODULE_TOOL_OWNERS = {
|
|
76228
76230
|
[TOOL_NAMES.listSources]: "lane",
|
|
@@ -91827,6 +91829,7 @@ function listFinancialPlaybooks() {
|
|
|
91827
91829
|
var AP_AUDIT_PACKET_DEF, PLAYBOOKS;
|
|
91828
91830
|
var init_registry2 = __esm({
|
|
91829
91831
|
"features/perchTerminal/runtime/financialPlaybooks/registry.ts"() {
|
|
91832
|
+
"use strict";
|
|
91830
91833
|
init_managedWorkflowRegistry2();
|
|
91831
91834
|
init_toolNames();
|
|
91832
91835
|
AP_AUDIT_PACKET_DEF = {
|
|
@@ -119507,6 +119510,21 @@ var init_browserSession = __esm({
|
|
|
119507
119510
|
}
|
|
119508
119511
|
});
|
|
119509
119512
|
|
|
119513
|
+
// features/perchTerminal/runtime/cliAuthRefreshRegistry.ts
|
|
119514
|
+
function setCliModelProxyAuthRefresher(fn) {
|
|
119515
|
+
refresher = fn;
|
|
119516
|
+
}
|
|
119517
|
+
function refreshCliModelProxyAuth() {
|
|
119518
|
+
return refresher ? refresher() : Promise.resolve(null);
|
|
119519
|
+
}
|
|
119520
|
+
var refresher;
|
|
119521
|
+
var init_cliAuthRefreshRegistry = __esm({
|
|
119522
|
+
"features/perchTerminal/runtime/cliAuthRefreshRegistry.ts"() {
|
|
119523
|
+
"use strict";
|
|
119524
|
+
refresher = null;
|
|
119525
|
+
}
|
|
119526
|
+
});
|
|
119527
|
+
|
|
119510
119528
|
// features/perchTerminal/runtime/roostUserSelectionClient.ts
|
|
119511
119529
|
function coerceSelection(raw) {
|
|
119512
119530
|
const choice = normalizeRoostModelChoice(raw?.choice);
|
|
@@ -119546,507 +119564,6 @@ var init_roostUserSelectionClient = __esm({
|
|
|
119546
119564
|
}
|
|
119547
119565
|
});
|
|
119548
119566
|
|
|
119549
|
-
// features/perchTerminal/runtime/cliHost/cliAuthSession.ts
|
|
119550
|
-
var cliAuthSession_exports = {};
|
|
119551
|
-
__export(cliAuthSession_exports, {
|
|
119552
|
-
clearStoredCliAuthSession: () => clearStoredCliAuthSession,
|
|
119553
|
-
isStoredCliAuthSessionUsable: () => isStoredCliAuthSessionUsable,
|
|
119554
|
-
parseStoredCliAuthSession: () => parseStoredCliAuthSession,
|
|
119555
|
-
readStoredCliAuthSession: () => readStoredCliAuthSession,
|
|
119556
|
-
writeStoredCliAuthSession: () => writeStoredCliAuthSession
|
|
119557
|
-
});
|
|
119558
|
-
import { execFile } from "node:child_process";
|
|
119559
|
-
import fs9 from "node:fs/promises";
|
|
119560
|
-
import os from "node:os";
|
|
119561
|
-
import path10 from "node:path";
|
|
119562
|
-
import { promisify } from "node:util";
|
|
119563
|
-
async function readStoredCliAuthSession() {
|
|
119564
|
-
const raw = shouldUseFallbackAuthFile() ? await readFallbackSecret().catch(() => null) : process.platform === "darwin" ? await readKeychainSecret().catch(() => null) : await readFallbackSecret().catch(() => null);
|
|
119565
|
-
return parseStoredCliAuthSession(raw);
|
|
119566
|
-
}
|
|
119567
|
-
async function writeStoredCliAuthSession(session) {
|
|
119568
|
-
const raw = JSON.stringify(session);
|
|
119569
|
-
if (process.platform === "darwin" && !shouldUseFallbackAuthFile()) {
|
|
119570
|
-
await execFileAsync("security", [
|
|
119571
|
-
"add-generic-password",
|
|
119572
|
-
"-U",
|
|
119573
|
-
"-s",
|
|
119574
|
-
KEYCHAIN_SERVICE,
|
|
119575
|
-
"-a",
|
|
119576
|
-
KEYCHAIN_ACCOUNT,
|
|
119577
|
-
"-w",
|
|
119578
|
-
raw
|
|
119579
|
-
]);
|
|
119580
|
-
return;
|
|
119581
|
-
}
|
|
119582
|
-
await writeFallbackSecret(raw);
|
|
119583
|
-
}
|
|
119584
|
-
async function clearStoredCliAuthSession() {
|
|
119585
|
-
if (process.platform === "darwin" && !shouldUseFallbackAuthFile()) {
|
|
119586
|
-
await execFileAsync("security", [
|
|
119587
|
-
"delete-generic-password",
|
|
119588
|
-
"-s",
|
|
119589
|
-
KEYCHAIN_SERVICE,
|
|
119590
|
-
"-a",
|
|
119591
|
-
KEYCHAIN_ACCOUNT
|
|
119592
|
-
]).catch(() => void 0);
|
|
119593
|
-
return;
|
|
119594
|
-
}
|
|
119595
|
-
await fs9.rm(fallbackSessionPath(), { force: true }).catch(() => void 0);
|
|
119596
|
-
}
|
|
119597
|
-
function shouldUseFallbackAuthFile() {
|
|
119598
|
-
return Boolean(process.env.PERCH_CLI_AUTH_DIR?.trim());
|
|
119599
|
-
}
|
|
119600
|
-
function isStoredCliAuthSessionUsable(session, nowSeconds = Math.floor(Date.now() / 1e3)) {
|
|
119601
|
-
if (!session?.accessToken?.trim()) return false;
|
|
119602
|
-
if (!session.appUrl?.trim()) return false;
|
|
119603
|
-
if (!session.expiresAt) return true;
|
|
119604
|
-
return session.expiresAt > nowSeconds + 90;
|
|
119605
|
-
}
|
|
119606
|
-
function parseStoredCliAuthSession(raw) {
|
|
119607
|
-
if (!raw?.trim()) return null;
|
|
119608
|
-
try {
|
|
119609
|
-
const parsed = JSON.parse(raw);
|
|
119610
|
-
if (parsed.version !== 1) return null;
|
|
119611
|
-
if (!parsed.appUrl || !parsed.accessToken || !parsed.updatedAt) return null;
|
|
119612
|
-
return {
|
|
119613
|
-
version: 1,
|
|
119614
|
-
appUrl: parsed.appUrl,
|
|
119615
|
-
accessToken: parsed.accessToken,
|
|
119616
|
-
refreshToken: parsed.refreshToken ?? null,
|
|
119617
|
-
expiresAt: typeof parsed.expiresAt === "number" ? parsed.expiresAt : null,
|
|
119618
|
-
userId: parsed.userId ?? null,
|
|
119619
|
-
email: parsed.email ?? null,
|
|
119620
|
-
updatedAt: parsed.updatedAt
|
|
119621
|
-
};
|
|
119622
|
-
} catch {
|
|
119623
|
-
return null;
|
|
119624
|
-
}
|
|
119625
|
-
}
|
|
119626
|
-
async function readKeychainSecret() {
|
|
119627
|
-
const { stdout } = await execFileAsync("security", [
|
|
119628
|
-
"find-generic-password",
|
|
119629
|
-
"-s",
|
|
119630
|
-
KEYCHAIN_SERVICE,
|
|
119631
|
-
"-a",
|
|
119632
|
-
KEYCHAIN_ACCOUNT,
|
|
119633
|
-
"-w"
|
|
119634
|
-
]);
|
|
119635
|
-
return stdout.trim() || null;
|
|
119636
|
-
}
|
|
119637
|
-
function fallbackSessionPath() {
|
|
119638
|
-
const base = process.env.PERCH_CLI_AUTH_DIR?.trim() || path10.join(os.homedir(), ".perch");
|
|
119639
|
-
return path10.join(base, "cli-auth-session.json");
|
|
119640
|
-
}
|
|
119641
|
-
async function readFallbackSecret() {
|
|
119642
|
-
return await fs9.readFile(fallbackSessionPath(), "utf8");
|
|
119643
|
-
}
|
|
119644
|
-
async function writeFallbackSecret(raw) {
|
|
119645
|
-
const filePath = fallbackSessionPath();
|
|
119646
|
-
await fs9.mkdir(path10.dirname(filePath), { recursive: true, mode: 448 });
|
|
119647
|
-
await fs9.writeFile(filePath, raw, { mode: 384 });
|
|
119648
|
-
}
|
|
119649
|
-
var execFileAsync, KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT;
|
|
119650
|
-
var init_cliAuthSession = __esm({
|
|
119651
|
-
"features/perchTerminal/runtime/cliHost/cliAuthSession.ts"() {
|
|
119652
|
-
"use strict";
|
|
119653
|
-
execFileAsync = promisify(execFile);
|
|
119654
|
-
KEYCHAIN_SERVICE = "app.perchai.cli-auth";
|
|
119655
|
-
KEYCHAIN_ACCOUNT = "default";
|
|
119656
|
-
}
|
|
119657
|
-
});
|
|
119658
|
-
|
|
119659
|
-
// features/perchTerminal/runtime/publicModelDefault.ts
|
|
119660
|
-
function parsePublicModelDefaultPayload(value) {
|
|
119661
|
-
const raw = value && typeof value === "object" ? value : {};
|
|
119662
|
-
const selection = sanitizeFounderModelSelection(
|
|
119663
|
-
raw.selection ?? DEFAULT_FOUNDER_MODEL_SELECTION
|
|
119664
|
-
);
|
|
119665
|
-
return {
|
|
119666
|
-
selection,
|
|
119667
|
-
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : null,
|
|
119668
|
-
updatedBy: typeof raw.updatedBy === "string" ? raw.updatedBy : null
|
|
119669
|
-
};
|
|
119670
|
-
}
|
|
119671
|
-
var init_publicModelDefault = __esm({
|
|
119672
|
-
"features/perchTerminal/runtime/publicModelDefault.ts"() {
|
|
119673
|
-
"use strict";
|
|
119674
|
-
init_modelRegistry();
|
|
119675
|
-
}
|
|
119676
|
-
});
|
|
119677
|
-
|
|
119678
|
-
// features/perchTerminal/runtime/cliHost/modelConnection.ts
|
|
119679
|
-
async function connectCliModelProxy(input = {}) {
|
|
119680
|
-
const storedSession = input.storedSession === void 0 ? await readStoredCliAuthSession() : input.storedSession;
|
|
119681
|
-
const usableStoredSession = await ensureFreshCliAuthSession({
|
|
119682
|
-
session: storedSession,
|
|
119683
|
-
fetchImpl: input.fetchImpl
|
|
119684
|
-
});
|
|
119685
|
-
const appUrl = resolveCliAppUrl(input.appUrl, usableStoredSession?.appUrl ?? null);
|
|
119686
|
-
if (!appUrl) return noCliModelConnection();
|
|
119687
|
-
if (!usableStoredSession?.accessToken) return noCliModelConnection(appUrl);
|
|
119688
|
-
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
119689
|
-
if (typeof fetchImpl !== "function") return noCliModelConnection(appUrl);
|
|
119690
|
-
const selection = await fetchPublicModelDefaultSelection(
|
|
119691
|
-
appUrl,
|
|
119692
|
-
fetchImpl,
|
|
119693
|
-
usableStoredSession?.accessToken ?? null
|
|
119694
|
-
);
|
|
119695
|
-
if (!selection) return noCliModelConnection(appUrl);
|
|
119696
|
-
const priorProxy = process.env[MODEL_PROXY_ENV];
|
|
119697
|
-
const priorToken = process.env[MODEL_PROXY_TOKEN_ENV];
|
|
119698
|
-
process.env[MODEL_PROXY_ENV] = appUrl;
|
|
119699
|
-
if (usableStoredSession?.accessToken) {
|
|
119700
|
-
process.env[MODEL_PROXY_TOKEN_ENV] = usableStoredSession.accessToken;
|
|
119701
|
-
}
|
|
119702
|
-
return {
|
|
119703
|
-
appUrl,
|
|
119704
|
-
authenticated: !!usableStoredSession?.accessToken,
|
|
119705
|
-
userId: usableStoredSession?.userId ?? null,
|
|
119706
|
-
email: usableStoredSession?.email ?? null,
|
|
119707
|
-
founderModelSelection: selection,
|
|
119708
|
-
restore: () => {
|
|
119709
|
-
if (priorProxy === void 0) {
|
|
119710
|
-
delete process.env[MODEL_PROXY_ENV];
|
|
119711
|
-
} else {
|
|
119712
|
-
process.env[MODEL_PROXY_ENV] = priorProxy;
|
|
119713
|
-
}
|
|
119714
|
-
if (priorToken === void 0) {
|
|
119715
|
-
delete process.env[MODEL_PROXY_TOKEN_ENV];
|
|
119716
|
-
} else {
|
|
119717
|
-
process.env[MODEL_PROXY_TOKEN_ENV] = priorToken;
|
|
119718
|
-
}
|
|
119719
|
-
}
|
|
119720
|
-
};
|
|
119721
|
-
}
|
|
119722
|
-
function resolveCliAppUrl(explicit, stored) {
|
|
119723
|
-
const raw = explicit?.trim() || process.env[CLI_APP_URL_ENV]?.trim() || process.env[FALLBACK_APP_URL_ENV]?.trim() || stored?.trim() || DEFAULT_CLI_APP_URL;
|
|
119724
|
-
if (!raw) return null;
|
|
119725
|
-
const withProtocol = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
|
|
119726
|
-
try {
|
|
119727
|
-
const url = new URL(withProtocol);
|
|
119728
|
-
url.pathname = url.pathname.replace(/\/+$/, "");
|
|
119729
|
-
url.search = "";
|
|
119730
|
-
url.hash = "";
|
|
119731
|
-
return url.toString().replace(/\/+$/, "");
|
|
119732
|
-
} catch {
|
|
119733
|
-
return null;
|
|
119734
|
-
}
|
|
119735
|
-
}
|
|
119736
|
-
async function fetchPublicModelDefaultSelection(appUrl, fetchImpl, accessToken) {
|
|
119737
|
-
const url = `${appUrl}/api/perch-terminal/public-model-default`;
|
|
119738
|
-
const controller = new AbortController();
|
|
119739
|
-
const timeout = setTimeout(() => controller.abort(), 3500);
|
|
119740
|
-
try {
|
|
119741
|
-
const response = await fetchImpl(url, {
|
|
119742
|
-
method: "GET",
|
|
119743
|
-
headers: {
|
|
119744
|
-
Accept: "application/json",
|
|
119745
|
-
...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
|
|
119746
|
-
},
|
|
119747
|
-
signal: controller.signal
|
|
119748
|
-
});
|
|
119749
|
-
if (!response.ok) return null;
|
|
119750
|
-
const body = await response.json();
|
|
119751
|
-
if (!body || typeof body !== "object") return null;
|
|
119752
|
-
const record = body;
|
|
119753
|
-
if (record.ok !== true) return null;
|
|
119754
|
-
return parsePublicModelDefaultPayload({ selection: record.selection }).selection;
|
|
119755
|
-
} catch {
|
|
119756
|
-
return null;
|
|
119757
|
-
} finally {
|
|
119758
|
-
clearTimeout(timeout);
|
|
119759
|
-
}
|
|
119760
|
-
}
|
|
119761
|
-
function noCliModelConnection(appUrl = null) {
|
|
119762
|
-
return {
|
|
119763
|
-
appUrl,
|
|
119764
|
-
authenticated: false,
|
|
119765
|
-
userId: null,
|
|
119766
|
-
email: null,
|
|
119767
|
-
founderModelSelection: null,
|
|
119768
|
-
restore: () => {
|
|
119769
|
-
}
|
|
119770
|
-
};
|
|
119771
|
-
}
|
|
119772
|
-
var MODEL_PROXY_ENV, MODEL_PROXY_TOKEN_ENV, CLI_APP_URL_ENV, FALLBACK_APP_URL_ENV, DEFAULT_CLI_APP_URL;
|
|
119773
|
-
var init_modelConnection = __esm({
|
|
119774
|
-
"features/perchTerminal/runtime/cliHost/modelConnection.ts"() {
|
|
119775
|
-
"use strict";
|
|
119776
|
-
init_publicModelDefault();
|
|
119777
|
-
init_cliAuthSession();
|
|
119778
|
-
init_cliAuthRefresh();
|
|
119779
|
-
MODEL_PROXY_ENV = "PERCH_MODEL_CALL_PROXY_URL";
|
|
119780
|
-
MODEL_PROXY_TOKEN_ENV = "PERCH_MODEL_CALL_PROXY_TOKEN";
|
|
119781
|
-
CLI_APP_URL_ENV = "PERCH_CLI_APP_URL";
|
|
119782
|
-
FALLBACK_APP_URL_ENV = "PERCH_APP_URL";
|
|
119783
|
-
DEFAULT_CLI_APP_URL = "https://app.perchai.app";
|
|
119784
|
-
}
|
|
119785
|
-
});
|
|
119786
|
-
|
|
119787
|
-
// features/perchTerminal/runtime/cliHost/cliStandaloneOAuth.ts
|
|
119788
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
119789
|
-
import http from "node:http";
|
|
119790
|
-
import { promisify as promisify2 } from "node:util";
|
|
119791
|
-
async function runCliStandaloneOAuthLogin(input) {
|
|
119792
|
-
const appUrl = resolveCliAppUrl(input.appUrl, null);
|
|
119793
|
-
if (!appUrl) {
|
|
119794
|
-
return { ok: false, code: "invalid_app_url", error: "Invalid Perch app URL." };
|
|
119795
|
-
}
|
|
119796
|
-
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
119797
|
-
if (typeof fetchImpl !== "function") {
|
|
119798
|
-
return { ok: false, code: "fetch_unavailable", error: "This Node runtime does not expose fetch." };
|
|
119799
|
-
}
|
|
119800
|
-
const config = await fetchCliAuthConfig(appUrl, fetchImpl);
|
|
119801
|
-
if (!config.ok || !config.supabaseUrl || !config.supabaseAnonKey) {
|
|
119802
|
-
return {
|
|
119803
|
-
ok: false,
|
|
119804
|
-
code: "auth_config_unavailable",
|
|
119805
|
-
error: "The Perch app did not return CLI auth configuration."
|
|
119806
|
-
};
|
|
119807
|
-
}
|
|
119808
|
-
const provider = selectOAuthProvider(config.providers ?? [], input.provider);
|
|
119809
|
-
if (!provider) {
|
|
119810
|
-
return {
|
|
119811
|
-
ok: false,
|
|
119812
|
-
code: "oauth_provider_unavailable",
|
|
119813
|
-
error: "No supported CLI OAuth provider is enabled for this Perch app."
|
|
119814
|
-
};
|
|
119815
|
-
}
|
|
119816
|
-
const callback = await createOAuthCallbackServer({
|
|
119817
|
-
host: config.redirectHost?.trim() || "127.0.0.1",
|
|
119818
|
-
timeoutMs: input.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS
|
|
119819
|
-
});
|
|
119820
|
-
try {
|
|
119821
|
-
const memoryStorage = createMemoryAuthStorage();
|
|
119822
|
-
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey, {
|
|
119823
|
-
auth: {
|
|
119824
|
-
flowType: "pkce",
|
|
119825
|
-
autoRefreshToken: false,
|
|
119826
|
-
detectSessionInUrl: false,
|
|
119827
|
-
persistSession: true,
|
|
119828
|
-
storage: memoryStorage
|
|
119829
|
-
}
|
|
119830
|
-
});
|
|
119831
|
-
const { data, error } = await supabase.auth.signInWithOAuth({
|
|
119832
|
-
provider,
|
|
119833
|
-
options: {
|
|
119834
|
-
redirectTo: callback.redirectTo,
|
|
119835
|
-
skipBrowserRedirect: true,
|
|
119836
|
-
data: { signup_source: "cli" }
|
|
119837
|
-
}
|
|
119838
|
-
});
|
|
119839
|
-
if (error || !data.url) {
|
|
119840
|
-
return {
|
|
119841
|
-
ok: false,
|
|
119842
|
-
code: "oauth_start_failed",
|
|
119843
|
-
error: error?.message ?? "Supabase did not return an OAuth URL."
|
|
119844
|
-
};
|
|
119845
|
-
}
|
|
119846
|
-
await (input.openExternal ?? openExternal)(data.url);
|
|
119847
|
-
const callbackResult = await callback.waitForCode();
|
|
119848
|
-
if (!callbackResult.ok) {
|
|
119849
|
-
return callbackResult;
|
|
119850
|
-
}
|
|
119851
|
-
const exchanged = await supabase.auth.exchangeCodeForSession(callbackResult.code);
|
|
119852
|
-
if (exchanged.error || !exchanged.data.session) {
|
|
119853
|
-
return {
|
|
119854
|
-
ok: false,
|
|
119855
|
-
code: "oauth_exchange_failed",
|
|
119856
|
-
error: exchanged.error?.message ?? "Supabase did not return a CLI session."
|
|
119857
|
-
};
|
|
119858
|
-
}
|
|
119859
|
-
const session = storedSessionFromSupabaseSession({
|
|
119860
|
-
appUrl,
|
|
119861
|
-
accessToken: exchanged.data.session.access_token,
|
|
119862
|
-
refreshToken: exchanged.data.session.refresh_token,
|
|
119863
|
-
expiresAt: exchanged.data.session.expires_at ?? null,
|
|
119864
|
-
userId: exchanged.data.session.user.id,
|
|
119865
|
-
email: exchanged.data.session.user.email ?? null
|
|
119866
|
-
});
|
|
119867
|
-
await writeStoredCliAuthSession(session);
|
|
119868
|
-
return { ok: true, session };
|
|
119869
|
-
} finally {
|
|
119870
|
-
await callback.close();
|
|
119871
|
-
}
|
|
119872
|
-
}
|
|
119873
|
-
async function fetchCliAuthConfig(appUrl, fetchImpl = globalThis.fetch) {
|
|
119874
|
-
const response = await fetchImpl(`${appUrl}/api/perch-terminal/cli-auth/config`, {
|
|
119875
|
-
method: "GET",
|
|
119876
|
-
headers: { Accept: "application/json" }
|
|
119877
|
-
});
|
|
119878
|
-
if (!response.ok) return { ok: false };
|
|
119879
|
-
return await response.json();
|
|
119880
|
-
}
|
|
119881
|
-
function selectOAuthProvider(providers, preferred) {
|
|
119882
|
-
const available = new Set(providers);
|
|
119883
|
-
if (preferred && available.has(preferred)) return preferred;
|
|
119884
|
-
if (available.has("google")) return "google";
|
|
119885
|
-
if (available.has("github")) return "github";
|
|
119886
|
-
return null;
|
|
119887
|
-
}
|
|
119888
|
-
function storedSessionFromSupabaseSession(input) {
|
|
119889
|
-
return {
|
|
119890
|
-
version: 1,
|
|
119891
|
-
appUrl: input.appUrl,
|
|
119892
|
-
accessToken: input.accessToken,
|
|
119893
|
-
refreshToken: input.refreshToken ?? null,
|
|
119894
|
-
expiresAt: input.expiresAt ?? null,
|
|
119895
|
-
userId: input.userId ?? null,
|
|
119896
|
-
email: input.email ?? null,
|
|
119897
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
119898
|
-
};
|
|
119899
|
-
}
|
|
119900
|
-
function createMemoryAuthStorage() {
|
|
119901
|
-
const values2 = /* @__PURE__ */ new Map();
|
|
119902
|
-
return {
|
|
119903
|
-
getItem: (key) => values2.get(key) ?? null,
|
|
119904
|
-
setItem: (key, value) => {
|
|
119905
|
-
values2.set(key, value);
|
|
119906
|
-
},
|
|
119907
|
-
removeItem: (key) => {
|
|
119908
|
-
values2.delete(key);
|
|
119909
|
-
}
|
|
119910
|
-
};
|
|
119911
|
-
}
|
|
119912
|
-
async function createOAuthCallbackServer(input) {
|
|
119913
|
-
let resolveResult = null;
|
|
119914
|
-
const resultPromise = new Promise((resolve5) => {
|
|
119915
|
-
resolveResult = resolve5;
|
|
119916
|
-
});
|
|
119917
|
-
const server = http.createServer((request, response) => {
|
|
119918
|
-
const requestUrl = new URL(request.url ?? "/", `http://${input.host}`);
|
|
119919
|
-
if (requestUrl.pathname !== CALLBACK_PATH) {
|
|
119920
|
-
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
119921
|
-
response.end("Not found");
|
|
119922
|
-
return;
|
|
119923
|
-
}
|
|
119924
|
-
const code = requestUrl.searchParams.get("code");
|
|
119925
|
-
const error = requestUrl.searchParams.get("error_description") ?? requestUrl.searchParams.get("error");
|
|
119926
|
-
if (!code) {
|
|
119927
|
-
response.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
119928
|
-
response.end(renderCallbackHtml(false));
|
|
119929
|
-
resolveResult?.({
|
|
119930
|
-
ok: false,
|
|
119931
|
-
code: "oauth_callback_missing_code",
|
|
119932
|
-
error: error ?? "OAuth callback did not include a code."
|
|
119933
|
-
});
|
|
119934
|
-
resolveResult = null;
|
|
119935
|
-
return;
|
|
119936
|
-
}
|
|
119937
|
-
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
119938
|
-
response.end(renderCallbackHtml(true));
|
|
119939
|
-
resolveResult?.({ ok: true, code });
|
|
119940
|
-
resolveResult = null;
|
|
119941
|
-
});
|
|
119942
|
-
await new Promise((resolve5, reject2) => {
|
|
119943
|
-
server.once("error", reject2);
|
|
119944
|
-
server.listen(0, input.host, () => {
|
|
119945
|
-
server.off("error", reject2);
|
|
119946
|
-
resolve5();
|
|
119947
|
-
});
|
|
119948
|
-
});
|
|
119949
|
-
const address = server.address();
|
|
119950
|
-
const redirectTo = `http://${input.host}:${address.port}${CALLBACK_PATH}`;
|
|
119951
|
-
const timeout = setTimeout(() => {
|
|
119952
|
-
resolveResult?.({
|
|
119953
|
-
ok: false,
|
|
119954
|
-
code: "oauth_timeout",
|
|
119955
|
-
error: "Timed out waiting for browser sign-in to complete."
|
|
119956
|
-
});
|
|
119957
|
-
resolveResult = null;
|
|
119958
|
-
}, input.timeoutMs);
|
|
119959
|
-
return {
|
|
119960
|
-
redirectTo,
|
|
119961
|
-
waitForCode: async () => resultPromise,
|
|
119962
|
-
close: async () => {
|
|
119963
|
-
clearTimeout(timeout);
|
|
119964
|
-
await new Promise((resolve5) => server.close(() => resolve5()));
|
|
119965
|
-
}
|
|
119966
|
-
};
|
|
119967
|
-
}
|
|
119968
|
-
function renderCallbackHtml(ok) {
|
|
119969
|
-
const title = ok ? "Perch CLI signed in" : "Perch CLI sign-in failed";
|
|
119970
|
-
const message = ok ? "You can close this tab and return to your terminal." : "Return to your terminal and try again.";
|
|
119971
|
-
return `<!doctype html><html><head><meta charset="utf-8"><title>${title}</title></head><body style="font-family:system-ui;padding:32px;background:#100d0b;color:#fff8f0"><h1>${title}</h1><p>${message}</p></body></html>`;
|
|
119972
|
-
}
|
|
119973
|
-
async function openExternal(url) {
|
|
119974
|
-
if (process.platform === "darwin") {
|
|
119975
|
-
await execFileAsync2("open", [url]);
|
|
119976
|
-
} else if (process.platform === "win32") {
|
|
119977
|
-
await execFileAsync2("cmd", ["/c", "start", "", url]);
|
|
119978
|
-
} else {
|
|
119979
|
-
await execFileAsync2("xdg-open", [url]);
|
|
119980
|
-
}
|
|
119981
|
-
}
|
|
119982
|
-
var execFileAsync2, DEFAULT_LOGIN_TIMEOUT_MS, CALLBACK_PATH;
|
|
119983
|
-
var init_cliStandaloneOAuth = __esm({
|
|
119984
|
-
"features/perchTerminal/runtime/cliHost/cliStandaloneOAuth.ts"() {
|
|
119985
|
-
"use strict";
|
|
119986
|
-
init_dist4();
|
|
119987
|
-
init_modelConnection();
|
|
119988
|
-
init_cliAuthSession();
|
|
119989
|
-
execFileAsync2 = promisify2(execFile2);
|
|
119990
|
-
DEFAULT_LOGIN_TIMEOUT_MS = 12e4;
|
|
119991
|
-
CALLBACK_PATH = "/callback";
|
|
119992
|
-
}
|
|
119993
|
-
});
|
|
119994
|
-
|
|
119995
|
-
// features/perchTerminal/runtime/cliHost/cliAuthRefresh.ts
|
|
119996
|
-
var cliAuthRefresh_exports = {};
|
|
119997
|
-
__export(cliAuthRefresh_exports, {
|
|
119998
|
-
ensureFreshCliAuthSession: () => ensureFreshCliAuthSession
|
|
119999
|
-
});
|
|
120000
|
-
async function ensureFreshCliAuthSession(input) {
|
|
120001
|
-
const session = input.session;
|
|
120002
|
-
if (!session?.accessToken?.trim()) return null;
|
|
120003
|
-
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
120004
|
-
const stillUsable = !session.expiresAt || session.expiresAt > nowSeconds + 90;
|
|
120005
|
-
if (stillUsable && !input.forceRefresh) return session;
|
|
120006
|
-
if (!session.refreshToken?.trim()) return null;
|
|
120007
|
-
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
120008
|
-
if (typeof fetchImpl !== "function") return null;
|
|
120009
|
-
const appUrl = session.appUrl?.trim();
|
|
120010
|
-
if (!appUrl) return null;
|
|
120011
|
-
const config = await fetchCliAuthConfig(appUrl, fetchImpl).catch(() => ({ ok: false }));
|
|
120012
|
-
if (!config.ok || !config.supabaseUrl || !config.supabaseAnonKey) return null;
|
|
120013
|
-
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey, {
|
|
120014
|
-
auth: {
|
|
120015
|
-
autoRefreshToken: false,
|
|
120016
|
-
detectSessionInUrl: false,
|
|
120017
|
-
persistSession: false
|
|
120018
|
-
}
|
|
120019
|
-
});
|
|
120020
|
-
try {
|
|
120021
|
-
const { data, error } = await supabase.auth.refreshSession({
|
|
120022
|
-
refresh_token: session.refreshToken
|
|
120023
|
-
});
|
|
120024
|
-
if (error || !data.session) return null;
|
|
120025
|
-
const refreshed = {
|
|
120026
|
-
version: 1,
|
|
120027
|
-
appUrl: session.appUrl,
|
|
120028
|
-
accessToken: data.session.access_token,
|
|
120029
|
-
refreshToken: data.session.refresh_token ?? session.refreshToken,
|
|
120030
|
-
expiresAt: data.session.expires_at ?? null,
|
|
120031
|
-
userId: data.session.user?.id ?? session.userId ?? null,
|
|
120032
|
-
email: data.session.user?.email ?? session.email ?? null,
|
|
120033
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
120034
|
-
};
|
|
120035
|
-
await writeStoredCliAuthSession(refreshed);
|
|
120036
|
-
return refreshed;
|
|
120037
|
-
} catch {
|
|
120038
|
-
return null;
|
|
120039
|
-
}
|
|
120040
|
-
}
|
|
120041
|
-
var init_cliAuthRefresh = __esm({
|
|
120042
|
-
"features/perchTerminal/runtime/cliHost/cliAuthRefresh.ts"() {
|
|
120043
|
-
"use strict";
|
|
120044
|
-
init_dist4();
|
|
120045
|
-
init_cliStandaloneOAuth();
|
|
120046
|
-
init_cliAuthSession();
|
|
120047
|
-
}
|
|
120048
|
-
});
|
|
120049
|
-
|
|
120050
119567
|
// features/perchTerminal/runtime/modelRouter.ts
|
|
120051
119568
|
function roostUserSelectionBodyFields() {
|
|
120052
119569
|
const selection = getEffectiveRoostUserSelection();
|
|
@@ -120344,17 +119861,7 @@ async function syncModelProxyAuthAfter401() {
|
|
|
120344
119861
|
await syncBrowserAuthSession();
|
|
120345
119862
|
return null;
|
|
120346
119863
|
}
|
|
120347
|
-
|
|
120348
|
-
const { ensureFreshCliAuthSession: ensureFreshCliAuthSession2 } = await Promise.resolve().then(() => (init_cliAuthRefresh(), cliAuthRefresh_exports));
|
|
120349
|
-
const fresh = await ensureFreshCliAuthSession2({
|
|
120350
|
-
session: await readStoredCliAuthSession2(),
|
|
120351
|
-
forceRefresh: true
|
|
120352
|
-
});
|
|
120353
|
-
if (!fresh?.accessToken?.trim()) return null;
|
|
120354
|
-
if (typeof process !== "undefined") {
|
|
120355
|
-
process.env[MODEL_CALL_PROXY_TOKEN_ENV] = fresh.accessToken;
|
|
120356
|
-
}
|
|
120357
|
-
return fresh.accessToken;
|
|
119864
|
+
return refreshCliModelProxyAuth();
|
|
120358
119865
|
}
|
|
120359
119866
|
function withModelProxyAuthHeader(init, token) {
|
|
120360
119867
|
if (!token?.trim()) return init;
|
|
@@ -120515,6 +120022,7 @@ var init_modelRouter = __esm({
|
|
|
120515
120022
|
init_contextMeter();
|
|
120516
120023
|
init_inferenceUsageRecorder();
|
|
120517
120024
|
init_browserSession();
|
|
120025
|
+
init_cliAuthRefreshRegistry();
|
|
120518
120026
|
init_roostUserSelectionClient();
|
|
120519
120027
|
init_providerModelStep();
|
|
120520
120028
|
init_toolCallNormalizer();
|
|
@@ -214765,8 +214273,8 @@ var init_barSeries = __esm({
|
|
|
214765
214273
|
});
|
|
214766
214274
|
|
|
214767
214275
|
// lib/perchMarketDesk/data/fixtureStore.ts
|
|
214768
|
-
import
|
|
214769
|
-
import
|
|
214276
|
+
import fs9 from "node:fs";
|
|
214277
|
+
import path10 from "node:path";
|
|
214770
214278
|
function createFixtureStore(input) {
|
|
214771
214279
|
const instruments = [...input.instruments].sort((a, b2) => a.ticker.localeCompare(b2.ticker));
|
|
214772
214280
|
const seriesByTicker = /* @__PURE__ */ new Map();
|
|
@@ -214813,22 +214321,22 @@ function createFixtureStore(input) {
|
|
|
214813
214321
|
};
|
|
214814
214322
|
}
|
|
214815
214323
|
function loadFixtureStoreFromDir(dir) {
|
|
214816
|
-
const instrumentsPath =
|
|
214817
|
-
const instruments = JSON.parse(
|
|
214324
|
+
const instrumentsPath = path10.join(dir, "instruments.json");
|
|
214325
|
+
const instruments = JSON.parse(fs9.readFileSync(instrumentsPath, "utf8"));
|
|
214818
214326
|
const bars = [];
|
|
214819
|
-
const barsDir =
|
|
214820
|
-
for (const file of
|
|
214327
|
+
const barsDir = path10.join(dir, "bars");
|
|
214328
|
+
for (const file of fs9.readdirSync(barsDir)) {
|
|
214821
214329
|
if (!file.endsWith(".json")) continue;
|
|
214822
|
-
const ticker =
|
|
214823
|
-
const rows = JSON.parse(
|
|
214330
|
+
const ticker = path10.basename(file, ".json");
|
|
214331
|
+
const rows = JSON.parse(fs9.readFileSync(path10.join(barsDir, file), "utf8"));
|
|
214824
214332
|
for (const row of rows) bars.push({ ...row, ticker: row.ticker ?? ticker });
|
|
214825
214333
|
}
|
|
214826
214334
|
let fundamentals;
|
|
214827
|
-
const fundamentalsPath =
|
|
214828
|
-
if (
|
|
214829
|
-
fundamentals = JSON.parse(
|
|
214335
|
+
const fundamentalsPath = path10.join(dir, "fundamentals.json");
|
|
214336
|
+
if (fs9.existsSync(fundamentalsPath)) {
|
|
214337
|
+
fundamentals = JSON.parse(fs9.readFileSync(fundamentalsPath, "utf8"));
|
|
214830
214338
|
}
|
|
214831
|
-
return createFixtureStore({ instruments, bars, fundamentals, label: `dir:${
|
|
214339
|
+
return createFixtureStore({ instruments, bars, fundamentals, label: `dir:${path10.basename(dir)}` });
|
|
214832
214340
|
}
|
|
214833
214341
|
var init_fixtureStore = __esm({
|
|
214834
214342
|
"lib/perchMarketDesk/data/fixtureStore.ts"() {
|
|
@@ -224252,7 +223760,13 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
224252
223760
|
turnInput: input
|
|
224253
223761
|
};
|
|
224254
223762
|
const modelCall = options.plannerModelCall ?? defaultFlockPlannerModelCall(llmCtx);
|
|
224255
|
-
|
|
223763
|
+
const plannerTimeoutMs = options.plannerTimeoutMs ?? FLOCK_PLANNER_TIMEOUT_MS;
|
|
223764
|
+
const first2 = await runLlmPlannerWithTimeout(llmCtx, modelCall, plannerTimeoutMs);
|
|
223765
|
+
plan = first2.plan;
|
|
223766
|
+
if (!plan && !first2.timedOut) {
|
|
223767
|
+
const retry = await runLlmPlannerWithTimeout(llmCtx, modelCall, plannerTimeoutMs);
|
|
223768
|
+
plan = retry.plan;
|
|
223769
|
+
}
|
|
224256
223770
|
}
|
|
224257
223771
|
if (!plan) {
|
|
224258
223772
|
plan = (options.planFn ?? planFlock)(task, {
|
|
@@ -224356,7 +223870,7 @@ async function runFlockTurn(input, deps, options = {}) {
|
|
|
224356
223870
|
toolCallsReserved += reservedToolCalls;
|
|
224357
223871
|
emitWorkerUpdate(emit, plan, worker, "running");
|
|
224358
223872
|
try {
|
|
224359
|
-
turnInput = await
|
|
223873
|
+
turnInput = deps.refreshTurnInput ? await deps.refreshTurnInput(turnInput) : turnInput;
|
|
224360
223874
|
const context = contextOverride ?? buildWorkerContext(worker, sharedContext, outputByFlockWorkerId, plan);
|
|
224361
223875
|
const objective = worker.role === "worker" && contextContainsSources(context) ? `${worker.objective}
|
|
224362
223876
|
${FLOCK_GROUNDING_CONTRACT}` : worker.objective;
|
|
@@ -224483,14 +223997,25 @@ ${FLOCK_GROUNDING_CONTRACT}` : worker.objective;
|
|
|
224483
223997
|
const workersFailed = outcomes.filter((outcome) => outcome.status === "failed").length + workersBlocked;
|
|
224484
223998
|
const flockStatus = userCancelled || wallTimeHit && workersDone === 0 ? "cancelled" : workersFailed === 0 && workersDone === plan.workers.length ? "completed" : workersDone > 0 ? "partial" : "failed";
|
|
224485
223999
|
const permissionHint = workersBlocked > 0 && (turnInput.permissionMode ?? "default") === "default" ? "\n\nTip: flock workers inherit default permissions \u2014 run `/permission take_the_wheel` before `/flock` so bash redirects and file writes do not stall on approval gates." : "";
|
|
224000
|
+
const deterministicSummary = buildFlockSummary(
|
|
224001
|
+
plan,
|
|
224002
|
+
[...outcomes, ...revisionOutcomes],
|
|
224003
|
+
flockStatus,
|
|
224004
|
+
toolCallsUsed,
|
|
224005
|
+
wallTimeHit
|
|
224006
|
+
);
|
|
224007
|
+
const synthesisModelCall = options.synthesisModelCall !== void 0 ? options.synthesisModelCall : options.plannerModelCall === void 0 ? defaultFlockSynthesisModelCall(input, plan.flockId) : null;
|
|
224008
|
+
let summaryBody = deterministicSummary;
|
|
224009
|
+
if (synthesisModelCall && !userCancelled && workersDone > 0) {
|
|
224010
|
+
const synthesized = await runFlockSynthesisWithTimeout(
|
|
224011
|
+
synthesisModelCall,
|
|
224012
|
+
buildFlockSynthesisPrompt(task, [...outcomes, ...revisionOutcomes], revisionReport),
|
|
224013
|
+
FLOCK_SYNTHESIS_TIMEOUT_MS
|
|
224014
|
+
);
|
|
224015
|
+
if (synthesized) summaryBody = synthesized;
|
|
224016
|
+
}
|
|
224486
224017
|
const assistantText = [
|
|
224487
|
-
|
|
224488
|
-
plan,
|
|
224489
|
-
[...outcomes, ...revisionOutcomes],
|
|
224490
|
-
flockStatus,
|
|
224491
|
-
toolCallsUsed,
|
|
224492
|
-
wallTimeHit
|
|
224493
|
-
),
|
|
224018
|
+
summaryBody,
|
|
224494
224019
|
...buildVerificationSection(revisionReport),
|
|
224495
224020
|
...modelOverrides.applied.map(
|
|
224496
224021
|
(override) => `Model override: ${override.displayName} ran on ${override.label}.`
|
|
@@ -224532,6 +224057,89 @@ ${FLOCK_GROUNDING_CONTRACT}` : worker.objective;
|
|
|
224532
224057
|
}
|
|
224533
224058
|
}
|
|
224534
224059
|
}
|
|
224060
|
+
async function runLlmPlannerWithTimeout(ctx, modelCall, timeoutMs) {
|
|
224061
|
+
let timer;
|
|
224062
|
+
const timeout = new Promise((resolve5) => {
|
|
224063
|
+
timer = setTimeout(() => resolve5("timeout"), Math.max(1, timeoutMs));
|
|
224064
|
+
});
|
|
224065
|
+
try {
|
|
224066
|
+
const race = await Promise.race([
|
|
224067
|
+
runLlmFlockPlanner(ctx, modelCall).then((plan) => ({ plan })).catch(() => ({ plan: null })),
|
|
224068
|
+
timeout
|
|
224069
|
+
]);
|
|
224070
|
+
if (race === "timeout") return { plan: null, timedOut: true };
|
|
224071
|
+
return { plan: race.plan, timedOut: false };
|
|
224072
|
+
} finally {
|
|
224073
|
+
if (timer) clearTimeout(timer);
|
|
224074
|
+
}
|
|
224075
|
+
}
|
|
224076
|
+
function defaultFlockSynthesisModelCall(input, flockId) {
|
|
224077
|
+
return async ({ systemPrompt, userPrompt }) => {
|
|
224078
|
+
const result2 = await runModelToolLoop({
|
|
224079
|
+
lane: "chat",
|
|
224080
|
+
founderModelSelection: input.founderModelSelection ?? null,
|
|
224081
|
+
systemPrompt,
|
|
224082
|
+
messages: [{ role: "user", content: userPrompt }],
|
|
224083
|
+
tools: [],
|
|
224084
|
+
workspaceRoot: input.activeRootPath ?? "",
|
|
224085
|
+
desktopConnected: input.desktopConnected,
|
|
224086
|
+
cliLocalTools: input.cliLocalTools === true,
|
|
224087
|
+
activeRootPath: input.activeRootPath,
|
|
224088
|
+
permissionMode: input.permissionMode,
|
|
224089
|
+
workspaceId: input.workspaceId,
|
|
224090
|
+
threadId: input.threadId,
|
|
224091
|
+
supabaseConfigured: input.supabaseConfigured,
|
|
224092
|
+
supabase: input.supabase ?? null,
|
|
224093
|
+
cliServerAppUrl: input.cliServerAppUrl ?? null,
|
|
224094
|
+
cliServerAccessToken: input.cliServerAccessToken ?? null,
|
|
224095
|
+
runId: flockId,
|
|
224096
|
+
chatMode: "ask",
|
|
224097
|
+
maxIterations: 1,
|
|
224098
|
+
onEvent: () => {
|
|
224099
|
+
}
|
|
224100
|
+
});
|
|
224101
|
+
return { ok: result2.ok, text: result2.text };
|
|
224102
|
+
};
|
|
224103
|
+
}
|
|
224104
|
+
function buildFlockSynthesisPrompt(task, outcomes, revisionReport) {
|
|
224105
|
+
const results = outcomes.filter((outcome) => outcome.status === "done" && outcome.result).map((outcome) => {
|
|
224106
|
+
const raw = outcome.result?.structuredOutput ?? outcome.result?.summary ?? "";
|
|
224107
|
+
const serialized = typeof raw === "string" ? raw : JSON.stringify(raw);
|
|
224108
|
+
return {
|
|
224109
|
+
role: outcome.worker.displayName,
|
|
224110
|
+
output: serialized.slice(0, FLOCK_SYNTHESIS_MAX_OUTPUT_PER_WORKER)
|
|
224111
|
+
};
|
|
224112
|
+
});
|
|
224113
|
+
const verification = revisionReport ? {
|
|
224114
|
+
verdict: revisionReport.recheckFindings?.verdict ?? revisionReport.findings.verdict ?? null,
|
|
224115
|
+
issues: (revisionReport.recheckFindings?.issues ?? revisionReport.findings.issues).slice(0, 6),
|
|
224116
|
+
revised: revisionReport.revised
|
|
224117
|
+
} : null;
|
|
224118
|
+
const systemPrompt = [
|
|
224119
|
+
"You are the coordinator that just ran a Flock: a team of sub-agents that worked in parallel on the user's task.",
|
|
224120
|
+
"The sub-agents have finished. Write the final answer to the user in your own voice \u2014 clear, direct, friendly, first person.",
|
|
224121
|
+
"Lead with what the user asked for. Present the actual results and fold in any important verification caveats.",
|
|
224122
|
+
"Do not mention sub-agents, workers, roles, nicknames, IDs, or orchestration mechanics unless directly useful to the user.",
|
|
224123
|
+
"Synthesize only from the provided results \u2014 do not invent facts and do not say you will do further work."
|
|
224124
|
+
].join("\n");
|
|
224125
|
+
const userPrompt = JSON.stringify({ task, results, verification });
|
|
224126
|
+
return { systemPrompt, userPrompt };
|
|
224127
|
+
}
|
|
224128
|
+
async function runFlockSynthesisWithTimeout(call, prompt, timeoutMs) {
|
|
224129
|
+
let timer;
|
|
224130
|
+
const timeout = new Promise((resolve5) => {
|
|
224131
|
+
timer = setTimeout(() => resolve5("timeout"), Math.max(1, timeoutMs));
|
|
224132
|
+
});
|
|
224133
|
+
try {
|
|
224134
|
+
const race = await Promise.race([
|
|
224135
|
+
call(prompt).then((result2) => result2.ok && result2.text.trim() ? result2.text.trim() : null).catch(() => null),
|
|
224136
|
+
timeout
|
|
224137
|
+
]);
|
|
224138
|
+
return race === "timeout" ? null : race;
|
|
224139
|
+
} finally {
|
|
224140
|
+
if (timer) clearTimeout(timer);
|
|
224141
|
+
}
|
|
224142
|
+
}
|
|
224535
224143
|
function emitPlanEvent(emit, plan) {
|
|
224536
224144
|
emit({
|
|
224537
224145
|
type: "flock_plan_ready",
|
|
@@ -224761,36 +224369,16 @@ function flockWorkerStatusFromSpawnResult(result2) {
|
|
|
224761
224369
|
if (result2.usabilityStatus === "needs_user_input") return "blocked";
|
|
224762
224370
|
return "done";
|
|
224763
224371
|
}
|
|
224764
|
-
async function refreshFlockCliAuth(input) {
|
|
224765
|
-
if (input.cliLocalTools !== true) return input;
|
|
224766
|
-
const stored = await readStoredCliAuthSession();
|
|
224767
|
-
if (!stored?.accessToken?.trim()) return input;
|
|
224768
|
-
const turnToken = input.cliServerAccessToken?.trim();
|
|
224769
|
-
if (turnToken && turnToken !== stored.accessToken) return input;
|
|
224770
|
-
const fresh = await ensureFreshCliAuthSession({ session: stored });
|
|
224771
|
-
if (!fresh?.accessToken?.trim()) return input;
|
|
224772
|
-
if (fresh.accessToken === input.cliServerAccessToken) return input;
|
|
224773
|
-
if (typeof process !== "undefined") {
|
|
224774
|
-
process.env.PERCH_MODEL_CALL_PROXY_TOKEN = fresh.accessToken;
|
|
224775
|
-
}
|
|
224776
|
-
return {
|
|
224777
|
-
...input,
|
|
224778
|
-
cliServerAccessToken: fresh.accessToken,
|
|
224779
|
-
marketDeskProxyAccessToken: input.marketDeskProxyAccessToken ?? fresh.accessToken
|
|
224780
|
-
};
|
|
224781
|
-
}
|
|
224782
224372
|
function now11() {
|
|
224783
224373
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
224784
224374
|
}
|
|
224785
|
-
var FLOCK_GROUNDING_CONTRACT;
|
|
224375
|
+
var FLOCK_PLANNER_TIMEOUT_MS, FLOCK_SYNTHESIS_TIMEOUT_MS, FLOCK_SYNTHESIS_MAX_OUTPUT_PER_WORKER, FLOCK_GROUNDING_CONTRACT;
|
|
224786
224376
|
var init_runFlockTurn = __esm({
|
|
224787
224377
|
"features/perchTerminal/runtime/flock/runFlockTurn.ts"() {
|
|
224788
224378
|
"use strict";
|
|
224789
224379
|
init_operatorStream();
|
|
224790
224380
|
init_runRegistry();
|
|
224791
224381
|
init_spawnWorker2();
|
|
224792
|
-
init_cliAuthSession();
|
|
224793
|
-
init_cliAuthRefresh();
|
|
224794
224382
|
init_registry();
|
|
224795
224383
|
init_flockCommand();
|
|
224796
224384
|
init_flockLimits();
|
|
@@ -224798,6 +224386,10 @@ var init_runFlockTurn = __esm({
|
|
|
224798
224386
|
init_flockLlmPlanner();
|
|
224799
224387
|
init_flockPlanner();
|
|
224800
224388
|
init_flockRoles();
|
|
224389
|
+
init_toolLoop();
|
|
224390
|
+
FLOCK_PLANNER_TIMEOUT_MS = 35e3;
|
|
224391
|
+
FLOCK_SYNTHESIS_TIMEOUT_MS = 3e4;
|
|
224392
|
+
FLOCK_SYNTHESIS_MAX_OUTPUT_PER_WORKER = 2e3;
|
|
224801
224393
|
FLOCK_GROUNDING_CONTRACT = [
|
|
224802
224394
|
"Grounding contract: your context includes sources[] gathered by research.",
|
|
224803
224395
|
"Every nontrivial factual claim in the draft must carry an inline [n] marker mapping to one of those sources, with a numbered source list at the end.",
|
|
@@ -233104,9 +232696,9 @@ var init_backgroundTaskTypes = __esm({
|
|
|
233104
232696
|
});
|
|
233105
232697
|
|
|
233106
232698
|
// features/perchTerminal/runtime/background/backgroundTaskRegistry.ts
|
|
233107
|
-
import
|
|
233108
|
-
import
|
|
233109
|
-
import
|
|
232699
|
+
import fs10 from "node:fs";
|
|
232700
|
+
import os from "node:os";
|
|
232701
|
+
import path11 from "node:path";
|
|
233110
232702
|
function isTerminalStatus(status) {
|
|
233111
232703
|
return status !== "running";
|
|
233112
232704
|
}
|
|
@@ -233163,19 +232755,19 @@ function runtimeMs(record) {
|
|
|
233163
232755
|
function readOutputPreview(outputPath, previewBytes = BACKGROUND_TASK_BOUNDS.previewBytes) {
|
|
233164
232756
|
if (!outputPath) return { preview: "", truncated: false };
|
|
233165
232757
|
try {
|
|
233166
|
-
const stat2 =
|
|
233167
|
-
const fd =
|
|
232758
|
+
const stat2 = fs10.statSync(outputPath);
|
|
232759
|
+
const fd = fs10.openSync(outputPath, "r");
|
|
233168
232760
|
try {
|
|
233169
232761
|
if (stat2.size <= previewBytes) {
|
|
233170
232762
|
const buf2 = Buffer.alloc(stat2.size);
|
|
233171
|
-
|
|
232763
|
+
fs10.readSync(fd, buf2, 0, stat2.size, 0);
|
|
233172
232764
|
return { preview: buf2.toString("utf8"), truncated: false };
|
|
233173
232765
|
}
|
|
233174
232766
|
const buf = Buffer.alloc(previewBytes);
|
|
233175
|
-
|
|
232767
|
+
fs10.readSync(fd, buf, 0, previewBytes, stat2.size - previewBytes);
|
|
233176
232768
|
return { preview: buf.toString("utf8"), truncated: true };
|
|
233177
232769
|
} finally {
|
|
233178
|
-
|
|
232770
|
+
fs10.closeSync(fd);
|
|
233179
232771
|
}
|
|
233180
232772
|
} catch {
|
|
233181
232773
|
return { preview: "", truncated: false };
|
|
@@ -233210,28 +232802,26 @@ function getBackgroundTaskStore() {
|
|
|
233210
232802
|
var STORE_FILE, BackgroundTaskStore, singleton;
|
|
233211
232803
|
var init_backgroundTaskRegistry = __esm({
|
|
233212
232804
|
"features/perchTerminal/runtime/background/backgroundTaskRegistry.ts"() {
|
|
232805
|
+
"use strict";
|
|
233213
232806
|
init_backgroundTaskTypes();
|
|
233214
232807
|
STORE_FILE = "background-tasks.json";
|
|
233215
232808
|
BackgroundTaskStore = class {
|
|
233216
|
-
baseDir;
|
|
233217
|
-
storePath;
|
|
233218
|
-
outputDir;
|
|
233219
|
-
records = /* @__PURE__ */ new Map();
|
|
233220
|
-
loaded = false;
|
|
233221
232809
|
constructor(options = {}) {
|
|
233222
|
-
this.
|
|
233223
|
-
this.
|
|
233224
|
-
this.
|
|
232810
|
+
this.records = /* @__PURE__ */ new Map();
|
|
232811
|
+
this.loaded = false;
|
|
232812
|
+
this.baseDir = options.baseDir ?? path11.join(os.homedir(), ".perch");
|
|
232813
|
+
this.storePath = path11.join(this.baseDir, STORE_FILE);
|
|
232814
|
+
this.outputDir = path11.join(this.baseDir, "background-output");
|
|
233225
232815
|
}
|
|
233226
232816
|
ensureDirs() {
|
|
233227
|
-
|
|
233228
|
-
|
|
232817
|
+
fs10.mkdirSync(this.baseDir, { recursive: true });
|
|
232818
|
+
fs10.mkdirSync(this.outputDir, { recursive: true });
|
|
233229
232819
|
}
|
|
233230
232820
|
load() {
|
|
233231
232821
|
if (this.loaded) return;
|
|
233232
232822
|
this.loaded = true;
|
|
233233
232823
|
try {
|
|
233234
|
-
const raw =
|
|
232824
|
+
const raw = fs10.readFileSync(this.storePath, "utf8");
|
|
233235
232825
|
const parsed = JSON.parse(raw);
|
|
233236
232826
|
const tasks = Array.isArray(parsed.tasks) ? parsed.tasks : [];
|
|
233237
232827
|
this.records = new Map(tasks.map((t) => [t.taskId, t]));
|
|
@@ -233243,11 +232833,11 @@ var init_backgroundTaskRegistry = __esm({
|
|
|
233243
232833
|
this.ensureDirs();
|
|
233244
232834
|
const tasks = Array.from(this.records.values());
|
|
233245
232835
|
const tmp = `${this.storePath}.tmp`;
|
|
233246
|
-
|
|
233247
|
-
|
|
232836
|
+
fs10.writeFileSync(tmp, JSON.stringify({ version: 1, tasks }, null, 2), "utf8");
|
|
232837
|
+
fs10.renameSync(tmp, this.storePath);
|
|
233248
232838
|
}
|
|
233249
232839
|
outputPathFor(taskId) {
|
|
233250
|
-
return
|
|
232840
|
+
return path11.join(this.outputDir, `${taskId}.log`);
|
|
233251
232841
|
}
|
|
233252
232842
|
list() {
|
|
233253
232843
|
this.load();
|
|
@@ -233409,14 +232999,14 @@ var init_backgroundWakeController = __esm({
|
|
|
233409
232999
|
|
|
233410
233000
|
// features/perchTerminal/runtime/background/runBackgroundCommand.ts
|
|
233411
233001
|
import { spawn as spawn2 } from "node:child_process";
|
|
233412
|
-
import
|
|
233413
|
-
import
|
|
233002
|
+
import fs11 from "node:fs";
|
|
233003
|
+
import path12 from "node:path";
|
|
233414
233004
|
function newTaskId() {
|
|
233415
233005
|
return `bg-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
|
|
233416
233006
|
}
|
|
233417
233007
|
function createCappedWriter(filePath, maxBytes) {
|
|
233418
|
-
|
|
233419
|
-
const stream =
|
|
233008
|
+
fs11.mkdirSync(path12.dirname(filePath), { recursive: true });
|
|
233009
|
+
const stream = fs11.createWriteStream(filePath, { flags: "w" });
|
|
233420
233010
|
let written = 0;
|
|
233421
233011
|
let truncated = false;
|
|
233422
233012
|
return {
|
|
@@ -233589,10 +233179,10 @@ var init_runBackgroundCommand = __esm({
|
|
|
233589
233179
|
|
|
233590
233180
|
// features/perchTerminal/runtime/cliHost/nodeLocalBridge.ts
|
|
233591
233181
|
import { spawn as spawn3 } from "node:child_process";
|
|
233592
|
-
import
|
|
233182
|
+
import fs12 from "node:fs";
|
|
233593
233183
|
import fsp from "node:fs/promises";
|
|
233594
|
-
import
|
|
233595
|
-
import
|
|
233184
|
+
import os2 from "node:os";
|
|
233185
|
+
import path13 from "node:path";
|
|
233596
233186
|
function installCliNodeLocalBridge(input) {
|
|
233597
233187
|
const globalRef = globalThis;
|
|
233598
233188
|
const previous = globalRef.__PERCH_TEST_DESKTOP_BRIDGE__;
|
|
@@ -233606,7 +233196,7 @@ function installCliNodeLocalBridge(input) {
|
|
|
233606
233196
|
};
|
|
233607
233197
|
}
|
|
233608
233198
|
function readCliProjectMemoryState(workspaceRoot) {
|
|
233609
|
-
const root2 =
|
|
233199
|
+
const root2 = path13.resolve(expandHome4(workspaceRoot));
|
|
233610
233200
|
if (!isCliProjectMemoryAvailable(root2)) {
|
|
233611
233201
|
return {
|
|
233612
233202
|
available: false,
|
|
@@ -233621,7 +233211,7 @@ function readCliProjectMemoryState(workspaceRoot) {
|
|
|
233621
233211
|
};
|
|
233622
233212
|
}
|
|
233623
233213
|
function createCliNodeLocalBridge(input) {
|
|
233624
|
-
const workspaceRoot =
|
|
233214
|
+
const workspaceRoot = path13.resolve(input.workspaceRoot);
|
|
233625
233215
|
const now23 = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
233626
233216
|
const sandboxHandlers = /* @__PURE__ */ new Map();
|
|
233627
233217
|
const emitSandboxEvent = (event) => {
|
|
@@ -233635,7 +233225,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233635
233225
|
cwd: workspaceRoot,
|
|
233636
233226
|
projectRoot: workspaceRoot,
|
|
233637
233227
|
shellPath: process.env.SHELL || "/bin/zsh",
|
|
233638
|
-
shellName:
|
|
233228
|
+
shellName: path13.basename(process.env.SHELL || "zsh"),
|
|
233639
233229
|
path: process.env.PATH || "",
|
|
233640
233230
|
status: "running",
|
|
233641
233231
|
backend: "spawn-fallback",
|
|
@@ -233662,7 +233252,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233662
233252
|
capabilities: ["local-files", "local-shell"]
|
|
233663
233253
|
}),
|
|
233664
233254
|
checkFsAccess: async (request) => {
|
|
233665
|
-
const absolutePath =
|
|
233255
|
+
const absolutePath = path13.resolve(expandHome4(request.absolutePath));
|
|
233666
233256
|
return {
|
|
233667
233257
|
decision: "allow",
|
|
233668
233258
|
reason: "Allowed by Perch CLI local filesystem access.",
|
|
@@ -233680,7 +233270,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233680
233270
|
ok: true,
|
|
233681
233271
|
directory: workspaceRoot,
|
|
233682
233272
|
fileName: request.fileName,
|
|
233683
|
-
absolutePath:
|
|
233273
|
+
absolutePath: path13.join(workspaceRoot, request.fileName),
|
|
233684
233274
|
source: "approved_root"
|
|
233685
233275
|
}),
|
|
233686
233276
|
validateWorkspaceRoot: async () => ({
|
|
@@ -233769,7 +233359,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233769
233359
|
writeWorkspaceFile: async (request) => {
|
|
233770
233360
|
const baseRoot = resolveRequestRoot(workspaceRoot, request.workspaceRoot);
|
|
233771
233361
|
const target = resolveWritePath(baseRoot, request.relativePath);
|
|
233772
|
-
await fsp.mkdir(
|
|
233362
|
+
await fsp.mkdir(path13.dirname(target), { recursive: true });
|
|
233773
233363
|
const flag = request.overwrite === true ? "w" : "wx";
|
|
233774
233364
|
const payload = request.encoding === "base64" && typeof request.contentBase64 === "string" ? Buffer.from(request.contentBase64, "base64") : request.content ?? "";
|
|
233775
233365
|
try {
|
|
@@ -233789,14 +233379,14 @@ function createCliNodeLocalBridge(input) {
|
|
|
233789
233379
|
moveLocalFile: async (request) => {
|
|
233790
233380
|
const src = resolveReadPath(workspaceRoot, request.src);
|
|
233791
233381
|
const dest = resolveWritePath(workspaceRoot, request.dest);
|
|
233792
|
-
await fsp.mkdir(
|
|
233382
|
+
await fsp.mkdir(path13.dirname(dest), { recursive: true });
|
|
233793
233383
|
await fsp.rename(src, dest);
|
|
233794
233384
|
return { ok: true, fromPath: src, toPath: dest };
|
|
233795
233385
|
},
|
|
233796
233386
|
copyLocalFile: async (request) => {
|
|
233797
233387
|
const src = resolveReadPath(workspaceRoot, request.src);
|
|
233798
233388
|
const dest = resolveWritePath(workspaceRoot, request.dest);
|
|
233799
|
-
await fsp.mkdir(
|
|
233389
|
+
await fsp.mkdir(path13.dirname(dest), { recursive: true });
|
|
233800
233390
|
await fsp.copyFile(src, dest);
|
|
233801
233391
|
return { ok: true, fromPath: src, toPath: dest };
|
|
233802
233392
|
},
|
|
@@ -233821,7 +233411,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233821
233411
|
const pattern = request.pattern?.trim() || "**/*";
|
|
233822
233412
|
const regex2 = globToRegex(pattern);
|
|
233823
233413
|
const files = await collectFiles(root2, { maxVisits: Math.max(maxResults * 20, 1e3) });
|
|
233824
|
-
const matches = files.map((file) =>
|
|
233414
|
+
const matches = files.map((file) => path13.relative(root2, file).replace(/\\/g, "/")).filter((relative2) => regex2.test(relative2)).slice(0, maxResults);
|
|
233825
233415
|
return {
|
|
233826
233416
|
ok: true,
|
|
233827
233417
|
matches,
|
|
@@ -233844,7 +233434,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233844
233434
|
const files = await collectFiles(root2, { maxVisits: 5e3 });
|
|
233845
233435
|
const matches = [];
|
|
233846
233436
|
for (const file of files) {
|
|
233847
|
-
const relative2 =
|
|
233437
|
+
const relative2 = path13.relative(root2, file).replace(/\\/g, "/");
|
|
233848
233438
|
if (includeRegex && !includeRegex.test(relative2)) continue;
|
|
233849
233439
|
const text = await readTextFileIfReasonable(file);
|
|
233850
233440
|
if (text === null) continue;
|
|
@@ -233883,7 +233473,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233883
233473
|
const stat2 = await safeStat(target);
|
|
233884
233474
|
return {
|
|
233885
233475
|
ok: true,
|
|
233886
|
-
relativePath:
|
|
233476
|
+
relativePath: path13.isAbsolute(request.relativePath) || request.relativePath.startsWith("~") ? target : path13.relative(baseRoot, target) || ".",
|
|
233887
233477
|
exists: Boolean(stat2),
|
|
233888
233478
|
isFile: stat2?.isFile() ?? false,
|
|
233889
233479
|
isDirectory: stat2?.isDirectory() ?? false,
|
|
@@ -233917,7 +233507,7 @@ function createCliNodeLocalBridge(input) {
|
|
|
233917
233507
|
return {
|
|
233918
233508
|
ok: true,
|
|
233919
233509
|
data: buffer.toString("base64"),
|
|
233920
|
-
fileName:
|
|
233510
|
+
fileName: path13.relative(workspaceRoot, target) || path13.basename(target),
|
|
233921
233511
|
mimeType: inferMimeType(target),
|
|
233922
233512
|
sizeBytes: stat2.size,
|
|
233923
233513
|
encoding: "base64"
|
|
@@ -234013,7 +233603,7 @@ async function runCliPrepareAPEvidence(workspaceRoot, request) {
|
|
|
234013
233603
|
topCases: (artifact.cases ?? []).slice(0, 12),
|
|
234014
233604
|
duplicateCases: result2.payload.duplicateCases,
|
|
234015
233605
|
controlGraph: result2.payload.controlGraph,
|
|
234016
|
-
relativeOutputDir: typeof artifact.outputDir === "string" ?
|
|
233606
|
+
relativeOutputDir: typeof artifact.outputDir === "string" ? path13.basename(artifact.outputDir) : null,
|
|
234017
233607
|
approvedRootMatch: true
|
|
234018
233608
|
},
|
|
234019
233609
|
executionHost: "electron_desktop",
|
|
@@ -234102,7 +233692,7 @@ async function prepareCliSandboxInputs(workspaceRoot, request) {
|
|
|
234102
233692
|
const jobId = request.jobId?.trim() || `cli-sandbox-${Date.now()}`;
|
|
234103
233693
|
const maxFiles = Math.max(1, Math.min(request.maxFiles ?? 20, 100));
|
|
234104
233694
|
const maxBytesPerFile = Math.max(1, Math.min(request.maxBytesPerFile ?? 20 * 1024 * 1024, 50 * 1024 * 1024));
|
|
234105
|
-
const tempDir = await fsp.mkdtemp(
|
|
233695
|
+
const tempDir = await fsp.mkdtemp(path13.join(os2.tmpdir(), `${jobId}-`));
|
|
234106
233696
|
const entries = [];
|
|
234107
233697
|
const skipped = [];
|
|
234108
233698
|
for (const localSourceId of request.localSourceIds.slice(0, maxFiles)) {
|
|
@@ -234116,13 +233706,13 @@ async function prepareCliSandboxInputs(workspaceRoot, request) {
|
|
|
234116
233706
|
skipped.push({ localSourceId, reason: `File is too large: ${stat2.size} bytes.` });
|
|
234117
233707
|
continue;
|
|
234118
233708
|
}
|
|
234119
|
-
const relativePath = safeSandboxRelativePath(
|
|
234120
|
-
const tempPath =
|
|
234121
|
-
await fsp.mkdir(
|
|
233709
|
+
const relativePath = safeSandboxRelativePath(path13.isAbsolute(localSourceId) || localSourceId.startsWith("~") ? path13.basename(sourcePath) : path13.relative(workspaceRoot, sourcePath));
|
|
233710
|
+
const tempPath = path13.join(tempDir, relativePath);
|
|
233711
|
+
await fsp.mkdir(path13.dirname(tempPath), { recursive: true });
|
|
234122
233712
|
await fsp.copyFile(sourcePath, tempPath);
|
|
234123
233713
|
entries.push({
|
|
234124
233714
|
localSourceId,
|
|
234125
|
-
fileName:
|
|
233715
|
+
fileName: path13.basename(sourcePath),
|
|
234126
233716
|
relativePath,
|
|
234127
233717
|
tempPath,
|
|
234128
233718
|
sizeBytes: stat2.size,
|
|
@@ -234160,11 +233750,11 @@ async function runCliSandboxCodeJob(workspaceRoot, request, onEvent) {
|
|
|
234160
233750
|
getApprovedRoot: (rootId) => rootId === CLI_ROOT_ID ? { id: CLI_ROOT_ID, path: workspaceRoot, approvedAt: (/* @__PURE__ */ new Date()).toISOString() } : null,
|
|
234161
233751
|
isPathSafe: (_rootPath, targetPath) => !targetPath.split(/[\\/]+/).includes(".."),
|
|
234162
233752
|
isInsideApprovedRoot: (filePath) => {
|
|
234163
|
-
const absolute =
|
|
233753
|
+
const absolute = path13.resolve(expandHome4(filePath));
|
|
234164
233754
|
if (isInside(workspaceRoot, absolute)) {
|
|
234165
233755
|
return { id: CLI_ROOT_ID, path: workspaceRoot, approvedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
234166
233756
|
}
|
|
234167
|
-
return { id: "cli-absolute-root", path:
|
|
233757
|
+
return { id: "cli-absolute-root", path: path13.dirname(absolute), approvedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
234168
233758
|
},
|
|
234169
233759
|
shouldIgnore: (fileName) => IGNORED_DIRS.has(fileName),
|
|
234170
233760
|
guessMimeType: inferMimeType,
|
|
@@ -234207,7 +233797,7 @@ function safeSandboxRelativePath(value) {
|
|
|
234207
233797
|
return clean || "input";
|
|
234208
233798
|
}
|
|
234209
233799
|
function guessCliFileType(filePath) {
|
|
234210
|
-
const ext =
|
|
233800
|
+
const ext = path13.extname(filePath).toLowerCase();
|
|
234211
233801
|
if ([".xlsx", ".xls"].includes(ext)) return "spreadsheet";
|
|
234212
233802
|
if (ext === ".csv" || ext === ".tsv") return "csv";
|
|
234213
233803
|
if (ext === ".pdf") return "pdf";
|
|
@@ -234226,7 +233816,7 @@ async function readCliProjectMemoryBridge(workspaceRoot) {
|
|
|
234226
233816
|
return { ok: true, meta: state.meta };
|
|
234227
233817
|
}
|
|
234228
233818
|
async function writeCliProjectMemory(workspaceRoot, patch) {
|
|
234229
|
-
const root2 =
|
|
233819
|
+
const root2 = path13.resolve(expandHome4(workspaceRoot));
|
|
234230
233820
|
if (!isCliProjectMemoryAvailable(root2)) {
|
|
234231
233821
|
return {
|
|
234232
233822
|
ok: false,
|
|
@@ -234242,12 +233832,12 @@ async function writeCliProjectMemory(workspaceRoot, patch) {
|
|
|
234242
233832
|
lastOpenedThreadId: patch.lastOpenedThreadId !== void 0 ? patch.lastOpenedThreadId : current.lastOpenedThreadId,
|
|
234243
233833
|
memorySummary: patch.memorySummary !== void 0 ? patch.memorySummary : current.memorySummary
|
|
234244
233834
|
};
|
|
234245
|
-
await fsp.mkdir(
|
|
233835
|
+
await fsp.mkdir(path13.join(root2, PERCH_DIR), { recursive: true });
|
|
234246
233836
|
await atomicWriteCliUtf8(getCliProjectFilePath(root2), JSON.stringify(next, null, 2));
|
|
234247
233837
|
return { ok: true, meta: enrichCliProjectMeta(root2, next) };
|
|
234248
233838
|
}
|
|
234249
233839
|
async function writeCliMemoryFile(workspaceRoot, request) {
|
|
234250
|
-
const root2 =
|
|
233840
|
+
const root2 = path13.resolve(expandHome4(workspaceRoot));
|
|
234251
233841
|
if (!isCliProjectMemoryAvailable(root2)) {
|
|
234252
233842
|
return {
|
|
234253
233843
|
ok: false,
|
|
@@ -234259,8 +233849,8 @@ async function writeCliMemoryFile(workspaceRoot, request) {
|
|
|
234259
233849
|
}
|
|
234260
233850
|
const fileName = normalizeCliMemoryFileName(request.fileName);
|
|
234261
233851
|
if (!fileName) return { ok: false, error: "Invalid memory file name." };
|
|
234262
|
-
const relativePath =
|
|
234263
|
-
const fullPath =
|
|
233852
|
+
const relativePath = path13.join(PERCH_DIR, MEMORY_DIR, fileName);
|
|
233853
|
+
const fullPath = path13.join(root2, relativePath);
|
|
234264
233854
|
const existing = await fsp.readFile(fullPath, "utf8").catch(() => "");
|
|
234265
233855
|
let nextContent;
|
|
234266
233856
|
try {
|
|
@@ -234273,7 +233863,7 @@ async function writeCliMemoryFile(workspaceRoot, request) {
|
|
|
234273
233863
|
}
|
|
234274
233864
|
const capError = assertCliMemoryWithinCap(nextContent);
|
|
234275
233865
|
if (capError) return { ok: false, error: capError };
|
|
234276
|
-
await fsp.mkdir(
|
|
233866
|
+
await fsp.mkdir(path13.dirname(fullPath), { recursive: true });
|
|
234277
233867
|
await atomicWriteCliUtf8(fullPath, nextContent);
|
|
234278
233868
|
const updatedFile = readCliTextMemoryFile(root2, relativePath, MAX_MEMORY_BYTES);
|
|
234279
233869
|
return {
|
|
@@ -234299,17 +233889,17 @@ function defaultCliProjectMeta() {
|
|
|
234299
233889
|
}
|
|
234300
233890
|
function isCliProjectMemoryAvailable(root2) {
|
|
234301
233891
|
try {
|
|
234302
|
-
return
|
|
233892
|
+
return fs12.statSync(path13.join(root2, PERCH_DIR)).isDirectory();
|
|
234303
233893
|
} catch {
|
|
234304
233894
|
return false;
|
|
234305
233895
|
}
|
|
234306
233896
|
}
|
|
234307
233897
|
function getCliProjectFilePath(root2) {
|
|
234308
|
-
return
|
|
233898
|
+
return path13.join(root2, PERCH_DIR, PROJECT_FILE);
|
|
234309
233899
|
}
|
|
234310
233900
|
function loadCliStoredMeta(root2) {
|
|
234311
233901
|
try {
|
|
234312
|
-
const raw =
|
|
233902
|
+
const raw = fs12.readFileSync(getCliProjectFilePath(root2), "utf8");
|
|
234313
233903
|
return { ...defaultCliProjectMeta(), ...JSON.parse(raw) };
|
|
234314
233904
|
} catch {
|
|
234315
233905
|
return defaultCliProjectMeta();
|
|
@@ -234317,7 +233907,7 @@ function loadCliStoredMeta(root2) {
|
|
|
234317
233907
|
}
|
|
234318
233908
|
function enrichCliProjectMeta(root2, base) {
|
|
234319
233909
|
const perchMd = readCliFirstExisting(root2, [
|
|
234320
|
-
|
|
233910
|
+
path13.join(PERCH_DIR, PERCH_INDEX_FILE),
|
|
234321
233911
|
PERCH_INDEX_FILE
|
|
234322
233912
|
], MAX_TEXT_BYTES);
|
|
234323
233913
|
const rules = readCliRules(root2);
|
|
@@ -234428,10 +234018,10 @@ function readCliFirstExisting(root2, relativePaths, maxBytes) {
|
|
|
234428
234018
|
return null;
|
|
234429
234019
|
}
|
|
234430
234020
|
function readCliRules(root2) {
|
|
234431
|
-
const dirPath =
|
|
234021
|
+
const dirPath = path13.join(root2, PERCH_DIR, RULES_DIR);
|
|
234432
234022
|
try {
|
|
234433
|
-
return
|
|
234434
|
-
fileName:
|
|
234023
|
+
return fs12.readdirSync(dirPath).filter((name) => [".md", ".txt"].includes(path13.extname(name).toLowerCase())).slice(0, 40).map((name) => readCliTextMemoryFile(root2, path13.join(PERCH_DIR, RULES_DIR, name), MAX_TEXT_BYTES)).filter((file) => file.found).map((file) => ({
|
|
234024
|
+
fileName: path13.basename(file.relativePath),
|
|
234435
234025
|
relativePath: file.relativePath,
|
|
234436
234026
|
content: file.content,
|
|
234437
234027
|
sizeBytes: file.sizeBytes,
|
|
@@ -234442,15 +234032,15 @@ function readCliRules(root2) {
|
|
|
234442
234032
|
}
|
|
234443
234033
|
}
|
|
234444
234034
|
function readCliMemoryFiles(root2) {
|
|
234445
|
-
const memoryDir =
|
|
234035
|
+
const memoryDir = path13.join(root2, PERCH_DIR, MEMORY_DIR);
|
|
234446
234036
|
const discovered = /* @__PURE__ */ new Set();
|
|
234447
234037
|
const memoryFiles = [];
|
|
234448
234038
|
try {
|
|
234449
|
-
for (const name of
|
|
234450
|
-
const ext =
|
|
234039
|
+
for (const name of fs12.readdirSync(memoryDir).slice(0, MAX_MEMORY_FILES)) {
|
|
234040
|
+
const ext = path13.extname(name).toLowerCase();
|
|
234451
234041
|
if (ext !== ".md" && ext !== ".txt") continue;
|
|
234452
234042
|
discovered.add(name);
|
|
234453
|
-
memoryFiles.push(readCliTextMemoryFile(root2,
|
|
234043
|
+
memoryFiles.push(readCliTextMemoryFile(root2, path13.join(PERCH_DIR, MEMORY_DIR, name), MAX_MEMORY_BYTES));
|
|
234454
234044
|
}
|
|
234455
234045
|
} catch {
|
|
234456
234046
|
}
|
|
@@ -234458,20 +234048,20 @@ function readCliMemoryFiles(root2) {
|
|
|
234458
234048
|
memoryFiles,
|
|
234459
234049
|
missingMemoryFiles: EXPECTED_MEMORY_FILES.filter((name) => !discovered.has(name)).map((name) => ({
|
|
234460
234050
|
fileName: name,
|
|
234461
|
-
relativePath:
|
|
234051
|
+
relativePath: path13.join(PERCH_DIR, MEMORY_DIR, name),
|
|
234462
234052
|
reason: "expected project memory file was not found"
|
|
234463
234053
|
}))
|
|
234464
234054
|
};
|
|
234465
234055
|
}
|
|
234466
234056
|
function readCliTextMemoryFile(root2, relativePath, maxBytes) {
|
|
234467
|
-
const fullPath =
|
|
234468
|
-
const fileName =
|
|
234057
|
+
const fullPath = path13.join(root2, relativePath);
|
|
234058
|
+
const fileName = path13.basename(relativePath);
|
|
234469
234059
|
try {
|
|
234470
|
-
const stat2 =
|
|
234060
|
+
const stat2 = fs12.statSync(fullPath);
|
|
234471
234061
|
if (!stat2.isFile()) {
|
|
234472
234062
|
return { fileName, relativePath, content: "", found: false, error: "not a regular file" };
|
|
234473
234063
|
}
|
|
234474
|
-
const content =
|
|
234064
|
+
const content = fs12.readFileSync(fullPath, "utf8");
|
|
234475
234065
|
if (stat2.size > maxBytes) {
|
|
234476
234066
|
return {
|
|
234477
234067
|
fileName,
|
|
@@ -234593,7 +234183,7 @@ function terminateProcessGroup(child, signal) {
|
|
|
234593
234183
|
}
|
|
234594
234184
|
function resolveReadPath(root2, inputPath) {
|
|
234595
234185
|
const expanded = expandHome4(inputPath || ".");
|
|
234596
|
-
return
|
|
234186
|
+
return path13.resolve(path13.isAbsolute(expanded) ? expanded : path13.join(root2, expanded));
|
|
234597
234187
|
}
|
|
234598
234188
|
function resolveRequestRoot(defaultRoot, requestRoot) {
|
|
234599
234189
|
const trimmed = requestRoot?.trim();
|
|
@@ -234601,25 +234191,25 @@ function resolveRequestRoot(defaultRoot, requestRoot) {
|
|
|
234601
234191
|
}
|
|
234602
234192
|
function resolveWritePath(root2, inputPath) {
|
|
234603
234193
|
const expanded = expandHome4(inputPath || ".");
|
|
234604
|
-
return
|
|
234194
|
+
return path13.resolve(path13.isAbsolute(expanded) ? expanded : path13.join(root2, expanded));
|
|
234605
234195
|
}
|
|
234606
234196
|
function displayPath(root2, target, requestedPath) {
|
|
234607
234197
|
const expanded = expandHome4(requestedPath || ".");
|
|
234608
|
-
if (
|
|
234609
|
-
return
|
|
234198
|
+
if (path13.isAbsolute(expanded) || requestedPath.startsWith("~")) return target;
|
|
234199
|
+
return path13.relative(root2, target) || path13.basename(target);
|
|
234610
234200
|
}
|
|
234611
234201
|
function resolveLocalSourceId(root2, localSourceId) {
|
|
234612
234202
|
const raw = localSourceId.includes("::") ? localSourceId.split("::").slice(1).join("::") : localSourceId;
|
|
234613
234203
|
return resolveReadPath(root2, raw);
|
|
234614
234204
|
}
|
|
234615
234205
|
function expandHome4(inputPath) {
|
|
234616
|
-
if (inputPath === "~") return
|
|
234617
|
-
if (inputPath.startsWith("~/")) return
|
|
234206
|
+
if (inputPath === "~") return os2.homedir();
|
|
234207
|
+
if (inputPath.startsWith("~/")) return path13.join(os2.homedir(), inputPath.slice(2));
|
|
234618
234208
|
return inputPath;
|
|
234619
234209
|
}
|
|
234620
234210
|
function isInside(root2, candidate) {
|
|
234621
|
-
const relative2 =
|
|
234622
|
-
return relative2 === "" || !relative2.startsWith("..") && !
|
|
234211
|
+
const relative2 = path13.relative(path13.resolve(root2), path13.resolve(candidate));
|
|
234212
|
+
return relative2 === "" || !relative2.startsWith("..") && !path13.isAbsolute(relative2);
|
|
234623
234213
|
}
|
|
234624
234214
|
async function safeStat(target) {
|
|
234625
234215
|
try {
|
|
@@ -234636,7 +234226,7 @@ async function collectFiles(root2, options) {
|
|
|
234636
234226
|
for (const entry of entries) {
|
|
234637
234227
|
if (result2.length >= options.maxVisits) return;
|
|
234638
234228
|
if (entry.name.startsWith(".") && entry.name !== ".env") continue;
|
|
234639
|
-
const absolute =
|
|
234229
|
+
const absolute = path13.join(dir, entry.name);
|
|
234640
234230
|
if (entry.isDirectory()) {
|
|
234641
234231
|
if (!IGNORED_DIRS.has(entry.name)) await walk2(absolute);
|
|
234642
234232
|
} else if (entry.isFile()) {
|
|
@@ -234692,14 +234282,14 @@ function sanitizeMaxResults(value) {
|
|
|
234692
234282
|
return Math.max(1, Math.min(typeof value === "number" ? Math.floor(value) : DEFAULT_MAX_RESULTS, 1e3));
|
|
234693
234283
|
}
|
|
234694
234284
|
function localSourceEntry(root2, file, absoluteId = false) {
|
|
234695
|
-
const stat2 =
|
|
234696
|
-
const relativePath =
|
|
234697
|
-
const extension2 =
|
|
234285
|
+
const stat2 = fs12.statSync(file);
|
|
234286
|
+
const relativePath = path13.relative(root2, file);
|
|
234287
|
+
const extension2 = path13.extname(file).toLowerCase();
|
|
234698
234288
|
return {
|
|
234699
234289
|
localSourceId: absoluteId ? file : `${CLI_ROOT_ID}::${relativePath}`,
|
|
234700
234290
|
rootId: absoluteId ? "cli-absolute-root" : CLI_ROOT_ID,
|
|
234701
234291
|
relativePath,
|
|
234702
|
-
fileName:
|
|
234292
|
+
fileName: path13.basename(file),
|
|
234703
234293
|
extension: extension2,
|
|
234704
234294
|
sizeBytes: stat2.size,
|
|
234705
234295
|
modifiedAt: stat2.mtime.toISOString(),
|
|
@@ -234708,7 +234298,7 @@ function localSourceEntry(root2, file, absoluteId = false) {
|
|
|
234708
234298
|
};
|
|
234709
234299
|
}
|
|
234710
234300
|
function inferMimeType(file) {
|
|
234711
|
-
const ext =
|
|
234301
|
+
const ext = path13.extname(file).toLowerCase();
|
|
234712
234302
|
if (ext === ".pdf") return "application/pdf";
|
|
234713
234303
|
if (ext === ".json") return "application/json";
|
|
234714
234304
|
if (ext === ".csv") return "text/csv";
|
|
@@ -234768,6 +234358,550 @@ var init_nodeLocalBridge = __esm({
|
|
|
234768
234358
|
}
|
|
234769
234359
|
});
|
|
234770
234360
|
|
|
234361
|
+
// features/perchTerminal/runtime/cliHost/cliAuthSession.ts
|
|
234362
|
+
import { execFile } from "node:child_process";
|
|
234363
|
+
import fs13 from "node:fs/promises";
|
|
234364
|
+
import os3 from "node:os";
|
|
234365
|
+
import path14 from "node:path";
|
|
234366
|
+
import { promisify } from "node:util";
|
|
234367
|
+
async function readStoredCliAuthSession() {
|
|
234368
|
+
const raw = shouldUseFallbackAuthFile() ? await readFallbackSecret().catch(() => null) : process.platform === "darwin" ? await readKeychainSecret().catch(() => null) : await readFallbackSecret().catch(() => null);
|
|
234369
|
+
return parseStoredCliAuthSession(raw);
|
|
234370
|
+
}
|
|
234371
|
+
async function writeStoredCliAuthSession(session) {
|
|
234372
|
+
const raw = JSON.stringify(session);
|
|
234373
|
+
if (process.platform === "darwin" && !shouldUseFallbackAuthFile()) {
|
|
234374
|
+
await execFileAsync("security", [
|
|
234375
|
+
"add-generic-password",
|
|
234376
|
+
"-U",
|
|
234377
|
+
"-s",
|
|
234378
|
+
KEYCHAIN_SERVICE,
|
|
234379
|
+
"-a",
|
|
234380
|
+
KEYCHAIN_ACCOUNT,
|
|
234381
|
+
"-w",
|
|
234382
|
+
raw
|
|
234383
|
+
]);
|
|
234384
|
+
return;
|
|
234385
|
+
}
|
|
234386
|
+
await writeFallbackSecret(raw);
|
|
234387
|
+
}
|
|
234388
|
+
async function clearStoredCliAuthSession() {
|
|
234389
|
+
if (process.platform === "darwin" && !shouldUseFallbackAuthFile()) {
|
|
234390
|
+
await execFileAsync("security", [
|
|
234391
|
+
"delete-generic-password",
|
|
234392
|
+
"-s",
|
|
234393
|
+
KEYCHAIN_SERVICE,
|
|
234394
|
+
"-a",
|
|
234395
|
+
KEYCHAIN_ACCOUNT
|
|
234396
|
+
]).catch(() => void 0);
|
|
234397
|
+
return;
|
|
234398
|
+
}
|
|
234399
|
+
await fs13.rm(fallbackSessionPath(), { force: true }).catch(() => void 0);
|
|
234400
|
+
}
|
|
234401
|
+
function shouldUseFallbackAuthFile() {
|
|
234402
|
+
return Boolean(process.env.PERCH_CLI_AUTH_DIR?.trim());
|
|
234403
|
+
}
|
|
234404
|
+
function isStoredCliAuthSessionUsable(session, nowSeconds = Math.floor(Date.now() / 1e3)) {
|
|
234405
|
+
if (!session?.accessToken?.trim()) return false;
|
|
234406
|
+
if (!session.appUrl?.trim()) return false;
|
|
234407
|
+
if (!session.expiresAt) return true;
|
|
234408
|
+
return session.expiresAt > nowSeconds + 90;
|
|
234409
|
+
}
|
|
234410
|
+
function parseStoredCliAuthSession(raw) {
|
|
234411
|
+
if (!raw?.trim()) return null;
|
|
234412
|
+
try {
|
|
234413
|
+
const parsed = JSON.parse(raw);
|
|
234414
|
+
if (parsed.version !== 1) return null;
|
|
234415
|
+
if (!parsed.appUrl || !parsed.accessToken || !parsed.updatedAt) return null;
|
|
234416
|
+
return {
|
|
234417
|
+
version: 1,
|
|
234418
|
+
appUrl: parsed.appUrl,
|
|
234419
|
+
accessToken: parsed.accessToken,
|
|
234420
|
+
refreshToken: parsed.refreshToken ?? null,
|
|
234421
|
+
expiresAt: typeof parsed.expiresAt === "number" ? parsed.expiresAt : null,
|
|
234422
|
+
userId: parsed.userId ?? null,
|
|
234423
|
+
email: parsed.email ?? null,
|
|
234424
|
+
updatedAt: parsed.updatedAt
|
|
234425
|
+
};
|
|
234426
|
+
} catch {
|
|
234427
|
+
return null;
|
|
234428
|
+
}
|
|
234429
|
+
}
|
|
234430
|
+
async function readKeychainSecret() {
|
|
234431
|
+
const { stdout } = await execFileAsync("security", [
|
|
234432
|
+
"find-generic-password",
|
|
234433
|
+
"-s",
|
|
234434
|
+
KEYCHAIN_SERVICE,
|
|
234435
|
+
"-a",
|
|
234436
|
+
KEYCHAIN_ACCOUNT,
|
|
234437
|
+
"-w"
|
|
234438
|
+
]);
|
|
234439
|
+
return stdout.trim() || null;
|
|
234440
|
+
}
|
|
234441
|
+
function fallbackSessionPath() {
|
|
234442
|
+
const base = process.env.PERCH_CLI_AUTH_DIR?.trim() || path14.join(os3.homedir(), ".perch");
|
|
234443
|
+
return path14.join(base, "cli-auth-session.json");
|
|
234444
|
+
}
|
|
234445
|
+
async function readFallbackSecret() {
|
|
234446
|
+
return await fs13.readFile(fallbackSessionPath(), "utf8");
|
|
234447
|
+
}
|
|
234448
|
+
async function writeFallbackSecret(raw) {
|
|
234449
|
+
const filePath = fallbackSessionPath();
|
|
234450
|
+
await fs13.mkdir(path14.dirname(filePath), { recursive: true, mode: 448 });
|
|
234451
|
+
await fs13.writeFile(filePath, raw, { mode: 384 });
|
|
234452
|
+
}
|
|
234453
|
+
var execFileAsync, KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT;
|
|
234454
|
+
var init_cliAuthSession = __esm({
|
|
234455
|
+
"features/perchTerminal/runtime/cliHost/cliAuthSession.ts"() {
|
|
234456
|
+
"use strict";
|
|
234457
|
+
execFileAsync = promisify(execFile);
|
|
234458
|
+
KEYCHAIN_SERVICE = "app.perchai.cli-auth";
|
|
234459
|
+
KEYCHAIN_ACCOUNT = "default";
|
|
234460
|
+
}
|
|
234461
|
+
});
|
|
234462
|
+
|
|
234463
|
+
// features/perchTerminal/runtime/publicModelDefault.ts
|
|
234464
|
+
function parsePublicModelDefaultPayload(value) {
|
|
234465
|
+
const raw = value && typeof value === "object" ? value : {};
|
|
234466
|
+
const selection = sanitizeFounderModelSelection(
|
|
234467
|
+
raw.selection ?? DEFAULT_FOUNDER_MODEL_SELECTION
|
|
234468
|
+
);
|
|
234469
|
+
return {
|
|
234470
|
+
selection,
|
|
234471
|
+
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : null,
|
|
234472
|
+
updatedBy: typeof raw.updatedBy === "string" ? raw.updatedBy : null
|
|
234473
|
+
};
|
|
234474
|
+
}
|
|
234475
|
+
var init_publicModelDefault = __esm({
|
|
234476
|
+
"features/perchTerminal/runtime/publicModelDefault.ts"() {
|
|
234477
|
+
"use strict";
|
|
234478
|
+
init_modelRegistry();
|
|
234479
|
+
}
|
|
234480
|
+
});
|
|
234481
|
+
|
|
234482
|
+
// features/perchTerminal/runtime/cliHost/installCliModelProxyAuthRefresh.ts
|
|
234483
|
+
function installCliModelProxyAuthRefresh() {
|
|
234484
|
+
setCliModelProxyAuthRefresher(async () => {
|
|
234485
|
+
const fresh = await ensureFreshCliAuthSession({
|
|
234486
|
+
session: await readStoredCliAuthSession(),
|
|
234487
|
+
forceRefresh: true
|
|
234488
|
+
});
|
|
234489
|
+
if (!fresh?.accessToken?.trim()) return null;
|
|
234490
|
+
if (typeof process !== "undefined") {
|
|
234491
|
+
process.env[MODEL_CALL_PROXY_TOKEN_ENV2] = fresh.accessToken;
|
|
234492
|
+
}
|
|
234493
|
+
return fresh.accessToken;
|
|
234494
|
+
});
|
|
234495
|
+
return () => setCliModelProxyAuthRefresher(null);
|
|
234496
|
+
}
|
|
234497
|
+
var MODEL_CALL_PROXY_TOKEN_ENV2;
|
|
234498
|
+
var init_installCliModelProxyAuthRefresh = __esm({
|
|
234499
|
+
"features/perchTerminal/runtime/cliHost/installCliModelProxyAuthRefresh.ts"() {
|
|
234500
|
+
"use strict";
|
|
234501
|
+
init_cliAuthRefreshRegistry();
|
|
234502
|
+
init_cliAuthRefresh();
|
|
234503
|
+
init_cliAuthSession();
|
|
234504
|
+
MODEL_CALL_PROXY_TOKEN_ENV2 = "PERCH_MODEL_CALL_PROXY_TOKEN";
|
|
234505
|
+
}
|
|
234506
|
+
});
|
|
234507
|
+
|
|
234508
|
+
// features/perchTerminal/runtime/cliHost/modelConnection.ts
|
|
234509
|
+
async function connectCliModelProxy(input = {}) {
|
|
234510
|
+
installCliModelProxyAuthRefresh();
|
|
234511
|
+
const storedSession = input.storedSession === void 0 ? await readStoredCliAuthSession() : input.storedSession;
|
|
234512
|
+
const usableStoredSession = await ensureFreshCliAuthSession({
|
|
234513
|
+
session: storedSession,
|
|
234514
|
+
fetchImpl: input.fetchImpl
|
|
234515
|
+
});
|
|
234516
|
+
const appUrl = resolveCliAppUrl(input.appUrl, usableStoredSession?.appUrl ?? null);
|
|
234517
|
+
if (!appUrl) return noCliModelConnection();
|
|
234518
|
+
if (!usableStoredSession?.accessToken) return noCliModelConnection(appUrl);
|
|
234519
|
+
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
234520
|
+
if (typeof fetchImpl !== "function") return noCliModelConnection(appUrl);
|
|
234521
|
+
const selection = await fetchPublicModelDefaultSelection(
|
|
234522
|
+
appUrl,
|
|
234523
|
+
fetchImpl,
|
|
234524
|
+
usableStoredSession?.accessToken ?? null
|
|
234525
|
+
);
|
|
234526
|
+
if (!selection) return noCliModelConnection(appUrl);
|
|
234527
|
+
const priorProxy = process.env[MODEL_PROXY_ENV];
|
|
234528
|
+
const priorToken = process.env[MODEL_PROXY_TOKEN_ENV];
|
|
234529
|
+
process.env[MODEL_PROXY_ENV] = appUrl;
|
|
234530
|
+
if (usableStoredSession?.accessToken) {
|
|
234531
|
+
process.env[MODEL_PROXY_TOKEN_ENV] = usableStoredSession.accessToken;
|
|
234532
|
+
}
|
|
234533
|
+
return {
|
|
234534
|
+
appUrl,
|
|
234535
|
+
authenticated: !!usableStoredSession?.accessToken,
|
|
234536
|
+
userId: usableStoredSession?.userId ?? null,
|
|
234537
|
+
email: usableStoredSession?.email ?? null,
|
|
234538
|
+
founderModelSelection: selection,
|
|
234539
|
+
restore: () => {
|
|
234540
|
+
if (priorProxy === void 0) {
|
|
234541
|
+
delete process.env[MODEL_PROXY_ENV];
|
|
234542
|
+
} else {
|
|
234543
|
+
process.env[MODEL_PROXY_ENV] = priorProxy;
|
|
234544
|
+
}
|
|
234545
|
+
if (priorToken === void 0) {
|
|
234546
|
+
delete process.env[MODEL_PROXY_TOKEN_ENV];
|
|
234547
|
+
} else {
|
|
234548
|
+
process.env[MODEL_PROXY_TOKEN_ENV] = priorToken;
|
|
234549
|
+
}
|
|
234550
|
+
}
|
|
234551
|
+
};
|
|
234552
|
+
}
|
|
234553
|
+
function resolveCliAppUrl(explicit, stored) {
|
|
234554
|
+
const raw = explicit?.trim() || process.env[CLI_APP_URL_ENV]?.trim() || process.env[FALLBACK_APP_URL_ENV]?.trim() || stored?.trim() || DEFAULT_CLI_APP_URL;
|
|
234555
|
+
if (!raw) return null;
|
|
234556
|
+
const withProtocol = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
|
|
234557
|
+
try {
|
|
234558
|
+
const url = new URL(withProtocol);
|
|
234559
|
+
url.pathname = url.pathname.replace(/\/+$/, "");
|
|
234560
|
+
url.search = "";
|
|
234561
|
+
url.hash = "";
|
|
234562
|
+
return url.toString().replace(/\/+$/, "");
|
|
234563
|
+
} catch {
|
|
234564
|
+
return null;
|
|
234565
|
+
}
|
|
234566
|
+
}
|
|
234567
|
+
async function fetchPublicModelDefaultSelection(appUrl, fetchImpl, accessToken) {
|
|
234568
|
+
const url = `${appUrl}/api/perch-terminal/public-model-default`;
|
|
234569
|
+
const controller = new AbortController();
|
|
234570
|
+
const timeout = setTimeout(() => controller.abort(), 3500);
|
|
234571
|
+
try {
|
|
234572
|
+
const response = await fetchImpl(url, {
|
|
234573
|
+
method: "GET",
|
|
234574
|
+
headers: {
|
|
234575
|
+
Accept: "application/json",
|
|
234576
|
+
...accessToken ? { Authorization: `Bearer ${accessToken}` } : {}
|
|
234577
|
+
},
|
|
234578
|
+
signal: controller.signal
|
|
234579
|
+
});
|
|
234580
|
+
if (!response.ok) return null;
|
|
234581
|
+
const body = await response.json();
|
|
234582
|
+
if (!body || typeof body !== "object") return null;
|
|
234583
|
+
const record = body;
|
|
234584
|
+
if (record.ok !== true) return null;
|
|
234585
|
+
return parsePublicModelDefaultPayload({ selection: record.selection }).selection;
|
|
234586
|
+
} catch {
|
|
234587
|
+
return null;
|
|
234588
|
+
} finally {
|
|
234589
|
+
clearTimeout(timeout);
|
|
234590
|
+
}
|
|
234591
|
+
}
|
|
234592
|
+
function noCliModelConnection(appUrl = null) {
|
|
234593
|
+
return {
|
|
234594
|
+
appUrl,
|
|
234595
|
+
authenticated: false,
|
|
234596
|
+
userId: null,
|
|
234597
|
+
email: null,
|
|
234598
|
+
founderModelSelection: null,
|
|
234599
|
+
restore: () => {
|
|
234600
|
+
}
|
|
234601
|
+
};
|
|
234602
|
+
}
|
|
234603
|
+
var MODEL_PROXY_ENV, MODEL_PROXY_TOKEN_ENV, CLI_APP_URL_ENV, FALLBACK_APP_URL_ENV, DEFAULT_CLI_APP_URL;
|
|
234604
|
+
var init_modelConnection = __esm({
|
|
234605
|
+
"features/perchTerminal/runtime/cliHost/modelConnection.ts"() {
|
|
234606
|
+
"use strict";
|
|
234607
|
+
init_publicModelDefault();
|
|
234608
|
+
init_cliAuthSession();
|
|
234609
|
+
init_cliAuthRefresh();
|
|
234610
|
+
init_installCliModelProxyAuthRefresh();
|
|
234611
|
+
MODEL_PROXY_ENV = "PERCH_MODEL_CALL_PROXY_URL";
|
|
234612
|
+
MODEL_PROXY_TOKEN_ENV = "PERCH_MODEL_CALL_PROXY_TOKEN";
|
|
234613
|
+
CLI_APP_URL_ENV = "PERCH_CLI_APP_URL";
|
|
234614
|
+
FALLBACK_APP_URL_ENV = "PERCH_APP_URL";
|
|
234615
|
+
DEFAULT_CLI_APP_URL = "https://app.perchai.app";
|
|
234616
|
+
}
|
|
234617
|
+
});
|
|
234618
|
+
|
|
234619
|
+
// features/perchTerminal/runtime/cliHost/cliStandaloneOAuth.ts
|
|
234620
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
234621
|
+
import http from "node:http";
|
|
234622
|
+
import { promisify as promisify2 } from "node:util";
|
|
234623
|
+
async function runCliStandaloneOAuthLogin(input) {
|
|
234624
|
+
const appUrl = resolveCliAppUrl(input.appUrl, null);
|
|
234625
|
+
if (!appUrl) {
|
|
234626
|
+
return { ok: false, code: "invalid_app_url", error: "Invalid Perch app URL." };
|
|
234627
|
+
}
|
|
234628
|
+
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
234629
|
+
if (typeof fetchImpl !== "function") {
|
|
234630
|
+
return { ok: false, code: "fetch_unavailable", error: "This Node runtime does not expose fetch." };
|
|
234631
|
+
}
|
|
234632
|
+
const config = await fetchCliAuthConfig(appUrl, fetchImpl);
|
|
234633
|
+
if (!config.ok || !config.supabaseUrl || !config.supabaseAnonKey) {
|
|
234634
|
+
return {
|
|
234635
|
+
ok: false,
|
|
234636
|
+
code: "auth_config_unavailable",
|
|
234637
|
+
error: "The Perch app did not return CLI auth configuration."
|
|
234638
|
+
};
|
|
234639
|
+
}
|
|
234640
|
+
const provider = selectOAuthProvider(config.providers ?? [], input.provider);
|
|
234641
|
+
if (!provider) {
|
|
234642
|
+
return {
|
|
234643
|
+
ok: false,
|
|
234644
|
+
code: "oauth_provider_unavailable",
|
|
234645
|
+
error: "No supported CLI OAuth provider is enabled for this Perch app."
|
|
234646
|
+
};
|
|
234647
|
+
}
|
|
234648
|
+
const callback = await createOAuthCallbackServer({
|
|
234649
|
+
host: config.redirectHost?.trim() || "127.0.0.1",
|
|
234650
|
+
timeoutMs: input.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS
|
|
234651
|
+
});
|
|
234652
|
+
try {
|
|
234653
|
+
const memoryStorage = createMemoryAuthStorage();
|
|
234654
|
+
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey, {
|
|
234655
|
+
auth: {
|
|
234656
|
+
flowType: "pkce",
|
|
234657
|
+
autoRefreshToken: false,
|
|
234658
|
+
detectSessionInUrl: false,
|
|
234659
|
+
persistSession: true,
|
|
234660
|
+
storage: memoryStorage
|
|
234661
|
+
}
|
|
234662
|
+
});
|
|
234663
|
+
const { data, error } = await supabase.auth.signInWithOAuth({
|
|
234664
|
+
provider,
|
|
234665
|
+
options: {
|
|
234666
|
+
redirectTo: callback.redirectTo,
|
|
234667
|
+
skipBrowserRedirect: true,
|
|
234668
|
+
data: { signup_source: "cli" }
|
|
234669
|
+
}
|
|
234670
|
+
});
|
|
234671
|
+
if (error || !data.url) {
|
|
234672
|
+
return {
|
|
234673
|
+
ok: false,
|
|
234674
|
+
code: "oauth_start_failed",
|
|
234675
|
+
error: error?.message ?? "Supabase did not return an OAuth URL."
|
|
234676
|
+
};
|
|
234677
|
+
}
|
|
234678
|
+
await (input.openExternal ?? openExternal)(data.url);
|
|
234679
|
+
const callbackResult = await callback.waitForCode();
|
|
234680
|
+
if (!callbackResult.ok) {
|
|
234681
|
+
return callbackResult;
|
|
234682
|
+
}
|
|
234683
|
+
const exchanged = await supabase.auth.exchangeCodeForSession(callbackResult.code);
|
|
234684
|
+
if (exchanged.error || !exchanged.data.session) {
|
|
234685
|
+
return {
|
|
234686
|
+
ok: false,
|
|
234687
|
+
code: "oauth_exchange_failed",
|
|
234688
|
+
error: exchanged.error?.message ?? "Supabase did not return a CLI session."
|
|
234689
|
+
};
|
|
234690
|
+
}
|
|
234691
|
+
const session = storedSessionFromSupabaseSession({
|
|
234692
|
+
appUrl,
|
|
234693
|
+
accessToken: exchanged.data.session.access_token,
|
|
234694
|
+
refreshToken: exchanged.data.session.refresh_token,
|
|
234695
|
+
expiresAt: exchanged.data.session.expires_at ?? null,
|
|
234696
|
+
userId: exchanged.data.session.user.id,
|
|
234697
|
+
email: exchanged.data.session.user.email ?? null
|
|
234698
|
+
});
|
|
234699
|
+
await writeStoredCliAuthSession(session);
|
|
234700
|
+
return { ok: true, session };
|
|
234701
|
+
} finally {
|
|
234702
|
+
await callback.close();
|
|
234703
|
+
}
|
|
234704
|
+
}
|
|
234705
|
+
async function fetchCliAuthConfig(appUrl, fetchImpl = globalThis.fetch) {
|
|
234706
|
+
const response = await fetchImpl(`${appUrl}/api/perch-terminal/cli-auth/config`, {
|
|
234707
|
+
method: "GET",
|
|
234708
|
+
headers: { Accept: "application/json" }
|
|
234709
|
+
});
|
|
234710
|
+
if (!response.ok) return { ok: false };
|
|
234711
|
+
return await response.json();
|
|
234712
|
+
}
|
|
234713
|
+
function selectOAuthProvider(providers, preferred) {
|
|
234714
|
+
const available = new Set(providers);
|
|
234715
|
+
if (preferred && available.has(preferred)) return preferred;
|
|
234716
|
+
if (available.has("google")) return "google";
|
|
234717
|
+
if (available.has("github")) return "github";
|
|
234718
|
+
return null;
|
|
234719
|
+
}
|
|
234720
|
+
function storedSessionFromSupabaseSession(input) {
|
|
234721
|
+
return {
|
|
234722
|
+
version: 1,
|
|
234723
|
+
appUrl: input.appUrl,
|
|
234724
|
+
accessToken: input.accessToken,
|
|
234725
|
+
refreshToken: input.refreshToken ?? null,
|
|
234726
|
+
expiresAt: input.expiresAt ?? null,
|
|
234727
|
+
userId: input.userId ?? null,
|
|
234728
|
+
email: input.email ?? null,
|
|
234729
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
234730
|
+
};
|
|
234731
|
+
}
|
|
234732
|
+
function createMemoryAuthStorage() {
|
|
234733
|
+
const values2 = /* @__PURE__ */ new Map();
|
|
234734
|
+
return {
|
|
234735
|
+
getItem: (key) => values2.get(key) ?? null,
|
|
234736
|
+
setItem: (key, value) => {
|
|
234737
|
+
values2.set(key, value);
|
|
234738
|
+
},
|
|
234739
|
+
removeItem: (key) => {
|
|
234740
|
+
values2.delete(key);
|
|
234741
|
+
}
|
|
234742
|
+
};
|
|
234743
|
+
}
|
|
234744
|
+
async function createOAuthCallbackServer(input) {
|
|
234745
|
+
let resolveResult = null;
|
|
234746
|
+
const resultPromise = new Promise((resolve5) => {
|
|
234747
|
+
resolveResult = resolve5;
|
|
234748
|
+
});
|
|
234749
|
+
const server = http.createServer((request, response) => {
|
|
234750
|
+
const requestUrl = new URL(request.url ?? "/", `http://${input.host}`);
|
|
234751
|
+
if (requestUrl.pathname !== CALLBACK_PATH) {
|
|
234752
|
+
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
234753
|
+
response.end("Not found");
|
|
234754
|
+
return;
|
|
234755
|
+
}
|
|
234756
|
+
const code = requestUrl.searchParams.get("code");
|
|
234757
|
+
const error = requestUrl.searchParams.get("error_description") ?? requestUrl.searchParams.get("error");
|
|
234758
|
+
if (!code) {
|
|
234759
|
+
response.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
234760
|
+
response.end(renderCallbackHtml(false));
|
|
234761
|
+
resolveResult?.({
|
|
234762
|
+
ok: false,
|
|
234763
|
+
code: "oauth_callback_missing_code",
|
|
234764
|
+
error: error ?? "OAuth callback did not include a code."
|
|
234765
|
+
});
|
|
234766
|
+
resolveResult = null;
|
|
234767
|
+
return;
|
|
234768
|
+
}
|
|
234769
|
+
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
234770
|
+
response.end(renderCallbackHtml(true));
|
|
234771
|
+
resolveResult?.({ ok: true, code });
|
|
234772
|
+
resolveResult = null;
|
|
234773
|
+
});
|
|
234774
|
+
await new Promise((resolve5, reject2) => {
|
|
234775
|
+
server.once("error", reject2);
|
|
234776
|
+
server.listen(0, input.host, () => {
|
|
234777
|
+
server.off("error", reject2);
|
|
234778
|
+
resolve5();
|
|
234779
|
+
});
|
|
234780
|
+
});
|
|
234781
|
+
const address = server.address();
|
|
234782
|
+
const redirectTo = `http://${input.host}:${address.port}${CALLBACK_PATH}`;
|
|
234783
|
+
const timeout = setTimeout(() => {
|
|
234784
|
+
resolveResult?.({
|
|
234785
|
+
ok: false,
|
|
234786
|
+
code: "oauth_timeout",
|
|
234787
|
+
error: "Timed out waiting for browser sign-in to complete."
|
|
234788
|
+
});
|
|
234789
|
+
resolveResult = null;
|
|
234790
|
+
}, input.timeoutMs);
|
|
234791
|
+
return {
|
|
234792
|
+
redirectTo,
|
|
234793
|
+
waitForCode: async () => resultPromise,
|
|
234794
|
+
close: async () => {
|
|
234795
|
+
clearTimeout(timeout);
|
|
234796
|
+
await new Promise((resolve5) => server.close(() => resolve5()));
|
|
234797
|
+
}
|
|
234798
|
+
};
|
|
234799
|
+
}
|
|
234800
|
+
function renderCallbackHtml(ok) {
|
|
234801
|
+
const title = ok ? "Perch CLI signed in" : "Perch CLI sign-in failed";
|
|
234802
|
+
const message = ok ? "You can close this tab and return to your terminal." : "Return to your terminal and try again.";
|
|
234803
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>${title}</title></head><body style="font-family:system-ui;padding:32px;background:#100d0b;color:#fff8f0"><h1>${title}</h1><p>${message}</p></body></html>`;
|
|
234804
|
+
}
|
|
234805
|
+
async function openExternal(url) {
|
|
234806
|
+
if (process.platform === "darwin") {
|
|
234807
|
+
await execFileAsync2("open", [url]);
|
|
234808
|
+
} else if (process.platform === "win32") {
|
|
234809
|
+
await execFileAsync2("cmd", ["/c", "start", "", url]);
|
|
234810
|
+
} else {
|
|
234811
|
+
await execFileAsync2("xdg-open", [url]);
|
|
234812
|
+
}
|
|
234813
|
+
}
|
|
234814
|
+
var execFileAsync2, DEFAULT_LOGIN_TIMEOUT_MS, CALLBACK_PATH;
|
|
234815
|
+
var init_cliStandaloneOAuth = __esm({
|
|
234816
|
+
"features/perchTerminal/runtime/cliHost/cliStandaloneOAuth.ts"() {
|
|
234817
|
+
"use strict";
|
|
234818
|
+
init_dist4();
|
|
234819
|
+
init_modelConnection();
|
|
234820
|
+
init_cliAuthSession();
|
|
234821
|
+
execFileAsync2 = promisify2(execFile2);
|
|
234822
|
+
DEFAULT_LOGIN_TIMEOUT_MS = 12e4;
|
|
234823
|
+
CALLBACK_PATH = "/callback";
|
|
234824
|
+
}
|
|
234825
|
+
});
|
|
234826
|
+
|
|
234827
|
+
// features/perchTerminal/runtime/cliHost/cliAuthRefresh.ts
|
|
234828
|
+
async function ensureFreshCliAuthSession(input) {
|
|
234829
|
+
const session = input.session;
|
|
234830
|
+
if (!session?.accessToken?.trim()) return null;
|
|
234831
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
234832
|
+
const stillUsable = !session.expiresAt || session.expiresAt > nowSeconds + 90;
|
|
234833
|
+
if (stillUsable && !input.forceRefresh) return session;
|
|
234834
|
+
if (!session.refreshToken?.trim()) return null;
|
|
234835
|
+
const fetchImpl = input.fetchImpl ?? globalThis.fetch;
|
|
234836
|
+
if (typeof fetchImpl !== "function") return null;
|
|
234837
|
+
const appUrl = session.appUrl?.trim();
|
|
234838
|
+
if (!appUrl) return null;
|
|
234839
|
+
const config = await fetchCliAuthConfig(appUrl, fetchImpl).catch(() => ({ ok: false }));
|
|
234840
|
+
if (!config.ok || !config.supabaseUrl || !config.supabaseAnonKey) return null;
|
|
234841
|
+
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey, {
|
|
234842
|
+
auth: {
|
|
234843
|
+
autoRefreshToken: false,
|
|
234844
|
+
detectSessionInUrl: false,
|
|
234845
|
+
persistSession: false
|
|
234846
|
+
}
|
|
234847
|
+
});
|
|
234848
|
+
try {
|
|
234849
|
+
const { data, error } = await supabase.auth.refreshSession({
|
|
234850
|
+
refresh_token: session.refreshToken
|
|
234851
|
+
});
|
|
234852
|
+
if (error || !data.session) return null;
|
|
234853
|
+
const refreshed = {
|
|
234854
|
+
version: 1,
|
|
234855
|
+
appUrl: session.appUrl,
|
|
234856
|
+
accessToken: data.session.access_token,
|
|
234857
|
+
refreshToken: data.session.refresh_token ?? session.refreshToken,
|
|
234858
|
+
expiresAt: data.session.expires_at ?? null,
|
|
234859
|
+
userId: data.session.user?.id ?? session.userId ?? null,
|
|
234860
|
+
email: data.session.user?.email ?? session.email ?? null,
|
|
234861
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
234862
|
+
};
|
|
234863
|
+
await writeStoredCliAuthSession(refreshed);
|
|
234864
|
+
return refreshed;
|
|
234865
|
+
} catch {
|
|
234866
|
+
return null;
|
|
234867
|
+
}
|
|
234868
|
+
}
|
|
234869
|
+
var init_cliAuthRefresh = __esm({
|
|
234870
|
+
"features/perchTerminal/runtime/cliHost/cliAuthRefresh.ts"() {
|
|
234871
|
+
"use strict";
|
|
234872
|
+
init_dist4();
|
|
234873
|
+
init_cliStandaloneOAuth();
|
|
234874
|
+
init_cliAuthSession();
|
|
234875
|
+
}
|
|
234876
|
+
});
|
|
234877
|
+
|
|
234878
|
+
// features/perchTerminal/runtime/cliHost/refreshCliTurnAuth.ts
|
|
234879
|
+
async function refreshCliTurnAuth(input) {
|
|
234880
|
+
if (input.cliLocalTools !== true) return input;
|
|
234881
|
+
const stored = await readStoredCliAuthSession();
|
|
234882
|
+
if (!stored?.accessToken?.trim()) return input;
|
|
234883
|
+
const turnToken = input.cliServerAccessToken?.trim();
|
|
234884
|
+
if (turnToken && turnToken !== stored.accessToken) return input;
|
|
234885
|
+
const fresh = await ensureFreshCliAuthSession({ session: stored });
|
|
234886
|
+
if (!fresh?.accessToken?.trim()) return input;
|
|
234887
|
+
if (fresh.accessToken === input.cliServerAccessToken) return input;
|
|
234888
|
+
if (typeof process !== "undefined") {
|
|
234889
|
+
process.env.PERCH_MODEL_CALL_PROXY_TOKEN = fresh.accessToken;
|
|
234890
|
+
}
|
|
234891
|
+
return {
|
|
234892
|
+
...input,
|
|
234893
|
+
cliServerAccessToken: fresh.accessToken,
|
|
234894
|
+
marketDeskProxyAccessToken: input.marketDeskProxyAccessToken ?? fresh.accessToken
|
|
234895
|
+
};
|
|
234896
|
+
}
|
|
234897
|
+
var init_refreshCliTurnAuth = __esm({
|
|
234898
|
+
"features/perchTerminal/runtime/cliHost/refreshCliTurnAuth.ts"() {
|
|
234899
|
+
"use strict";
|
|
234900
|
+
init_cliAuthSession();
|
|
234901
|
+
init_cliAuthRefresh();
|
|
234902
|
+
}
|
|
234903
|
+
});
|
|
234904
|
+
|
|
234771
234905
|
// features/perchTerminal/runtime/cliHost/runCliTurn.ts
|
|
234772
234906
|
import path15 from "node:path";
|
|
234773
234907
|
async function runPerchCliTurn(input, options = {}) {
|
|
@@ -234790,7 +234924,8 @@ async function runPerchCliTurn(input, options = {}) {
|
|
|
234790
234924
|
onEvent: input.onEvent,
|
|
234791
234925
|
onContextSnapshot: (snapshot) => {
|
|
234792
234926
|
latestContextSnapshot = snapshot;
|
|
234793
|
-
}
|
|
234927
|
+
},
|
|
234928
|
+
refreshTurnInput: input.cliLocalTools !== false ? refreshCliTurnAuth : void 0
|
|
234794
234929
|
});
|
|
234795
234930
|
const restoreLocalBridge = input.cliLocalTools === false ? null : installCliNodeLocalBridge({ workspaceRoot: cwd2 });
|
|
234796
234931
|
try {
|
|
@@ -234877,6 +235012,7 @@ function buildCliTurnDeps(input) {
|
|
|
234877
235012
|
input.onEvent?.(event);
|
|
234878
235013
|
},
|
|
234879
235014
|
onContextAssembled: input.onContextSnapshot,
|
|
235015
|
+
...input.refreshTurnInput ? { refreshTurnInput: input.refreshTurnInput } : {},
|
|
234880
235016
|
persistUserMessage: async () => null,
|
|
234881
235017
|
persistAssistantMessage: async () => null,
|
|
234882
235018
|
createWorkflowRun: async () => null,
|
|
@@ -234932,6 +235068,7 @@ var init_runCliTurn = __esm({
|
|
|
234932
235068
|
init_runOperatorTurn();
|
|
234933
235069
|
init_nodeLocalBridge();
|
|
234934
235070
|
init_nodeLocalBridge();
|
|
235071
|
+
init_refreshCliTurnAuth();
|
|
234935
235072
|
}
|
|
234936
235073
|
});
|
|
234937
235074
|
|
|
@@ -289942,9 +290079,17 @@ function flockEventToCliRow(event) {
|
|
|
289942
290079
|
switch (event.type) {
|
|
289943
290080
|
case "flock_run_started":
|
|
289944
290081
|
return { id: null, text: "gathering the flock\u2026", tone: "accent" };
|
|
289945
|
-
case "flock_plan_ready":
|
|
290082
|
+
case "flock_plan_ready": {
|
|
289946
290083
|
if (!event.accepted) return null;
|
|
289947
|
-
|
|
290084
|
+
const names = event.workers.map((worker) => worker.displayName);
|
|
290085
|
+
const shown = names.slice(0, 4).join(", ");
|
|
290086
|
+
const extra = names.length > 4 ? ` +${names.length - 4} more` : "";
|
|
290087
|
+
return {
|
|
290088
|
+
id: null,
|
|
290089
|
+
text: `flock plan \xB7 ${event.workers.length} agents \xB7 ${shown}${extra}`,
|
|
290090
|
+
tone: "accent"
|
|
290091
|
+
};
|
|
290092
|
+
}
|
|
289948
290093
|
case "flock_worker_update":
|
|
289949
290094
|
return {
|
|
289950
290095
|
id: `flock-${event.flockId}-${event.flockWorkerId}`,
|
|
@@ -290440,18 +290585,18 @@ async function runReadlineInteractivePerchCli(writer, deps, options) {
|
|
|
290440
290585
|
trimRecentMessages(state.recentMessages);
|
|
290441
290586
|
recordCliUsageRunId(state, result2.runId);
|
|
290442
290587
|
state.contextSnapshot = result2.contextSnapshot ?? state.contextSnapshot;
|
|
290443
|
-
|
|
290588
|
+
void admitCliLearningMemory(connection, {
|
|
290444
290589
|
prompt: turnPrompt,
|
|
290445
290590
|
assistantText: result2.assistantText,
|
|
290446
290591
|
status: result2.status,
|
|
290447
290592
|
personaId: state.personaId,
|
|
290448
290593
|
threadId: result2.threadId,
|
|
290449
290594
|
runId: result2.runId
|
|
290595
|
+
}).then((admitted) => {
|
|
290596
|
+
if (admitted > 0) writeModeLine(writer, "memory", `saved ${admitted}`);
|
|
290597
|
+
}).catch(() => {
|
|
290450
290598
|
});
|
|
290451
290599
|
await persistInteractiveCliState(state);
|
|
290452
|
-
if (admitted > 0) {
|
|
290453
|
-
writeModeLine(writer, "memory", `saved ${admitted}`);
|
|
290454
|
-
}
|
|
290455
290600
|
};
|
|
290456
290601
|
try {
|
|
290457
290602
|
while (true) {
|
|
@@ -291153,17 +291298,19 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
291153
291298
|
trimRecentMessages(state.recentMessages);
|
|
291154
291299
|
recordCliUsageRunId(state, result2.runId);
|
|
291155
291300
|
state.contextSnapshot = result2.contextSnapshot ?? state.contextSnapshot;
|
|
291156
|
-
|
|
291301
|
+
void admitCliLearningMemory(connection, {
|
|
291157
291302
|
prompt,
|
|
291158
291303
|
assistantText,
|
|
291159
291304
|
status: result2.status,
|
|
291160
291305
|
personaId: state.personaId,
|
|
291161
291306
|
threadId: result2.threadId,
|
|
291162
291307
|
runId: result2.runId
|
|
291308
|
+
}).then((admitted) => {
|
|
291309
|
+
if (admitted > 0) {
|
|
291310
|
+
addItem({ label: "memory", text: `saved ${admitted}`, tone: "muted" });
|
|
291311
|
+
}
|
|
291312
|
+
}).catch(() => {
|
|
291163
291313
|
});
|
|
291164
|
-
if (admitted > 0) {
|
|
291165
|
-
addItem({ label: "memory", text: `saved ${admitted}`, tone: "muted" });
|
|
291166
|
-
}
|
|
291167
291314
|
await persistInteractiveCliState(state);
|
|
291168
291315
|
} catch (error) {
|
|
291169
291316
|
addItem({ label: "stop", text: humanizeCliError(errorMessage(error)), tone: "danger" });
|