indusagi-coding-agent 0.2.3 → 0.2.4
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/CHANGELOG.md +25 -0
- package/dist/entry.js +1733 -572
- package/dist/guardrails.js +21 -6
- package/dist/index.js +1687 -552
- package/dist/types/boot/heap.d.ts +31 -0
- package/dist/types/boot/runners/delegate-runner.d.ts +21 -1
- package/dist/types/boot/runners/server-mode.d.ts +71 -0
- package/dist/types/boot/runners/session.d.ts +24 -1
- package/dist/types/boot/runners/session.test.d.ts +6 -1
- package/dist/types/boot/server-token.d.ts +97 -0
- package/dist/types/capability-deck/contract.d.ts +7 -6
- package/dist/types/conductor/conductor.d.ts +24 -0
- package/dist/types/conductor/contract.d.ts +71 -7
- package/dist/types/conductor/index.d.ts +3 -3
- package/dist/types/conductor/permissions.d.ts +74 -4
- package/dist/types/conductor/post-edit-diagnostics.test.d.ts +8 -3
- package/dist/types/conductor/quota-error.d.ts +35 -0
- package/dist/types/console/auth-status.d.ts +28 -0
- package/dist/types/console/components/TerminalConsole.d.ts +0 -5
- package/dist/types/console/contract.d.ts +13 -0
- package/dist/types/console/input/index.d.ts +1 -1
- package/dist/types/console/input/keymap.d.ts +1 -1
- package/dist/types/console/input/paste.d.ts +53 -1
- package/dist/types/console/overlays/approval-queue.d.ts +18 -1
- package/dist/types/console/overlays/index.d.ts +1 -1
- package/dist/types/launch/login.d.ts +68 -0
- package/dist/types/launch/oauth.test.d.ts +20 -0
- package/dist/types/window-budget/summarize/condense.d.ts +6 -0
- package/dist/types/workflow-engine/agent-runner.d.ts +20 -1
- package/dist/types/workspace/brand.d.ts +1 -1
- package/package.json +2 -2
package/dist/entry.js
CHANGED
|
@@ -32,6 +32,70 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
32
32
|
mod
|
|
33
33
|
));
|
|
34
34
|
|
|
35
|
+
// src/boot/server-token.ts
|
|
36
|
+
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
37
|
+
import os from "node:os";
|
|
38
|
+
import path from "node:path";
|
|
39
|
+
async function getServerToken() {
|
|
40
|
+
try {
|
|
41
|
+
const data = await readFile(TOKEN_FILE, "utf8");
|
|
42
|
+
return JSON.parse(data);
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function storeServerToken(token) {
|
|
48
|
+
try {
|
|
49
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
50
|
+
const tokenData = {
|
|
51
|
+
access_token: token.access_token,
|
|
52
|
+
refresh_token: token.refresh_token,
|
|
53
|
+
token_type: token.token_type ?? "Bearer",
|
|
54
|
+
scope: token.scope,
|
|
55
|
+
expires_at: token.expires_in !== void 0 ? new Date(Date.now() + token.expires_in * 1e3).toISOString() : null,
|
|
56
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
57
|
+
};
|
|
58
|
+
await writeFile(TOKEN_FILE, `${JSON.stringify(tokenData, null, 2)}
|
|
59
|
+
`, {
|
|
60
|
+
encoding: "utf8",
|
|
61
|
+
mode: 384
|
|
62
|
+
});
|
|
63
|
+
return true;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("Failed to store server token:", error.message);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function clearServerToken() {
|
|
70
|
+
try {
|
|
71
|
+
await unlink(TOKEN_FILE);
|
|
72
|
+
return true;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function isServerTokenExpired(token) {
|
|
78
|
+
if (!token || !token.expires_at) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
const expiresAt = new Date(token.expires_at);
|
|
82
|
+
const now = /* @__PURE__ */ new Date();
|
|
83
|
+
return expiresAt.getTime() - now.getTime() < 5 * 60 * 1e3;
|
|
84
|
+
}
|
|
85
|
+
async function hasValidServerToken() {
|
|
86
|
+
const token = await getServerToken();
|
|
87
|
+
return token !== null && !isServerTokenExpired(token);
|
|
88
|
+
}
|
|
89
|
+
var INDUS_SERVER_URL, CONFIG_DIR, TOKEN_FILE;
|
|
90
|
+
var init_server_token = __esm({
|
|
91
|
+
"src/boot/server-token.ts"() {
|
|
92
|
+
"use strict";
|
|
93
|
+
INDUS_SERVER_URL = process.env.INDUS_SERVER_URL?.replace(/\/+$/, "") ?? "https://indus-server.vercel.app";
|
|
94
|
+
CONFIG_DIR = path.join(os.homedir(), ".indusagi", "agent");
|
|
95
|
+
TOKEN_FILE = path.join(CONFIG_DIR, "server-token.json");
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
35
99
|
// src/briefing/contract.ts
|
|
36
100
|
function briefingFault(kind, message, cause) {
|
|
37
101
|
return cause === void 0 ? { kind, message } : { kind, message, cause };
|
|
@@ -97,29 +161,29 @@ function bullets(lines) {
|
|
|
97
161
|
return lines.map((l) => `- ${l}`).join("\n");
|
|
98
162
|
}
|
|
99
163
|
function escapeXml(value) {
|
|
100
|
-
let
|
|
164
|
+
let out2 = "";
|
|
101
165
|
for (const ch of value) {
|
|
102
166
|
switch (ch) {
|
|
103
167
|
case "&":
|
|
104
|
-
|
|
168
|
+
out2 += "&";
|
|
105
169
|
break;
|
|
106
170
|
case "<":
|
|
107
|
-
|
|
171
|
+
out2 += "<";
|
|
108
172
|
break;
|
|
109
173
|
case ">":
|
|
110
|
-
|
|
174
|
+
out2 += ">";
|
|
111
175
|
break;
|
|
112
176
|
case '"':
|
|
113
|
-
|
|
177
|
+
out2 += """;
|
|
114
178
|
break;
|
|
115
179
|
case "'":
|
|
116
|
-
|
|
180
|
+
out2 += "'";
|
|
117
181
|
break;
|
|
118
182
|
default:
|
|
119
|
-
|
|
183
|
+
out2 += ch;
|
|
120
184
|
}
|
|
121
185
|
}
|
|
122
|
-
return
|
|
186
|
+
return out2;
|
|
123
187
|
}
|
|
124
188
|
function hasTool(ctx, id) {
|
|
125
189
|
return (ctx.tools ?? []).some((t) => t.name === id);
|
|
@@ -554,7 +618,7 @@ function buildMacroScope(raw) {
|
|
|
554
618
|
return { args, all: args.join(" "), raw };
|
|
555
619
|
}
|
|
556
620
|
function splitArguments(raw) {
|
|
557
|
-
const
|
|
621
|
+
const out2 = [];
|
|
558
622
|
let current = "";
|
|
559
623
|
let inWord = false;
|
|
560
624
|
let quote = null;
|
|
@@ -576,7 +640,7 @@ function splitArguments(raw) {
|
|
|
576
640
|
}
|
|
577
641
|
if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v") {
|
|
578
642
|
if (inWord) {
|
|
579
|
-
|
|
643
|
+
out2.push(current);
|
|
580
644
|
current = "";
|
|
581
645
|
inWord = false;
|
|
582
646
|
}
|
|
@@ -585,33 +649,33 @@ function splitArguments(raw) {
|
|
|
585
649
|
current += ch;
|
|
586
650
|
inWord = true;
|
|
587
651
|
}
|
|
588
|
-
if (inWord)
|
|
589
|
-
return
|
|
652
|
+
if (inWord) out2.push(current);
|
|
653
|
+
return out2;
|
|
590
654
|
}
|
|
591
655
|
function resolveTokens(tokens, scope) {
|
|
592
|
-
let
|
|
656
|
+
let out2 = "";
|
|
593
657
|
for (const token of tokens) {
|
|
594
658
|
switch (token.kind) {
|
|
595
659
|
case "literal":
|
|
596
|
-
|
|
660
|
+
out2 += token.text;
|
|
597
661
|
break;
|
|
598
662
|
case "positional": {
|
|
599
663
|
const value = scope.args[token.index - 1];
|
|
600
|
-
if (value !== void 0)
|
|
664
|
+
if (value !== void 0) out2 += value;
|
|
601
665
|
break;
|
|
602
666
|
}
|
|
603
667
|
case "all":
|
|
604
|
-
|
|
668
|
+
out2 += scope.all;
|
|
605
669
|
break;
|
|
606
670
|
case "slice": {
|
|
607
671
|
const from = Math.max(0, token.start - 1);
|
|
608
672
|
const slice = token.length === void 0 ? scope.args.slice(from) : scope.args.slice(from, from + Math.max(0, token.length));
|
|
609
|
-
|
|
673
|
+
out2 += slice.join(" ");
|
|
610
674
|
break;
|
|
611
675
|
}
|
|
612
676
|
}
|
|
613
677
|
}
|
|
614
|
-
return
|
|
678
|
+
return out2;
|
|
615
679
|
}
|
|
616
680
|
function applyMacros(body, raw) {
|
|
617
681
|
return resolveTokens(scanMacroBody(body), buildMacroScope(raw));
|
|
@@ -644,18 +708,18 @@ function loadMacros(dir, opts = {}) {
|
|
|
644
708
|
}
|
|
645
709
|
return macros;
|
|
646
710
|
}
|
|
647
|
-
function readMacroFile(
|
|
711
|
+
function readMacroFile(path4, origin, label) {
|
|
648
712
|
let text;
|
|
649
713
|
try {
|
|
650
|
-
text = readFileSync(
|
|
714
|
+
text = readFileSync(path4, "utf8");
|
|
651
715
|
} catch (cause) {
|
|
652
|
-
throw briefingFault("macro_invalid", `could not read macro file at ${
|
|
716
|
+
throw briefingFault("macro_invalid", `could not read macro file at ${path4}`, cause);
|
|
653
717
|
}
|
|
654
718
|
const { frontmatter, body } = splitFrontmatter(text);
|
|
655
|
-
const name = basename2(
|
|
719
|
+
const name = basename2(path4).replace(/\.md$/i, "");
|
|
656
720
|
const declared = typeof frontmatter.description === "string" ? frontmatter.description.trim() : "";
|
|
657
721
|
const description = declared.length > 0 ? `${declared} (${label})` : deriveDescription(body, label);
|
|
658
|
-
return { name, description, body, origin, source:
|
|
722
|
+
return { name, description, body, origin, source: path4 };
|
|
659
723
|
}
|
|
660
724
|
function deriveDescription(body, label) {
|
|
661
725
|
const firstLine = body.split("\n").find((l) => l.trim().length > 0)?.trim() ?? "";
|
|
@@ -794,41 +858,41 @@ function checkFrontmatterKeys(frontmatter) {
|
|
|
794
858
|
return null;
|
|
795
859
|
}
|
|
796
860
|
function projectFrontmatter(raw) {
|
|
797
|
-
const
|
|
798
|
-
if (typeof raw.name === "string")
|
|
799
|
-
if (typeof raw.description === "string")
|
|
800
|
-
if (typeof raw.license === "string")
|
|
801
|
-
if (typeof raw.compatibility === "string")
|
|
861
|
+
const out2 = {};
|
|
862
|
+
if (typeof raw.name === "string") out2.name = raw.name.trim();
|
|
863
|
+
if (typeof raw.description === "string") out2.description = raw.description.trim();
|
|
864
|
+
if (typeof raw.license === "string") out2.license = raw.license.trim();
|
|
865
|
+
if (typeof raw.compatibility === "string") out2.compatibility = raw.compatibility.trim();
|
|
802
866
|
if (typeof raw.metadata === "object" && raw.metadata !== null) {
|
|
803
|
-
|
|
867
|
+
out2.metadata = raw.metadata;
|
|
804
868
|
}
|
|
805
869
|
const tools = raw["allowed-tools"];
|
|
806
870
|
if (typeof tools === "string") {
|
|
807
871
|
const list = tools.split(/[\s,]+/).map((t) => t.trim()).filter((t) => t.length > 0);
|
|
808
|
-
if (list.length > 0)
|
|
872
|
+
if (list.length > 0) out2.allowedTools = list;
|
|
809
873
|
} else if (Array.isArray(tools)) {
|
|
810
|
-
|
|
874
|
+
out2.allowedTools = tools.map((t) => String(t));
|
|
811
875
|
}
|
|
812
876
|
const flag = raw["disable-model-invocation"];
|
|
813
|
-
if (flag === true || flag === "true")
|
|
814
|
-
return
|
|
877
|
+
if (flag === true || flag === "true") out2.disableModelInvocation = true;
|
|
878
|
+
return out2;
|
|
815
879
|
}
|
|
816
880
|
function diag(kind, location, detail) {
|
|
817
881
|
return { kind, location, detail };
|
|
818
882
|
}
|
|
819
883
|
function parseCandidate(candidate, origin) {
|
|
820
|
-
const { path:
|
|
884
|
+
const { path: path4, dirName } = candidate;
|
|
821
885
|
let text;
|
|
822
886
|
try {
|
|
823
|
-
text = readFileSync2(
|
|
887
|
+
text = readFileSync2(path4, "utf8");
|
|
824
888
|
} catch (cause) {
|
|
825
889
|
const detail = `could not read the skill file (${describeCause(cause)})`;
|
|
826
|
-
return { card: null, diagnostic: diag("invalid",
|
|
890
|
+
return { card: null, diagnostic: diag("invalid", path4, detail) };
|
|
827
891
|
}
|
|
828
892
|
const { frontmatter, body } = splitFrontmatter(text);
|
|
829
893
|
const keyProblem = checkFrontmatterKeys(frontmatter);
|
|
830
894
|
if (keyProblem !== null) {
|
|
831
|
-
return { card: null, diagnostic: diag("invalid",
|
|
895
|
+
return { card: null, diagnostic: diag("invalid", path4, keyProblem) };
|
|
832
896
|
}
|
|
833
897
|
const fm = projectFrontmatter(frontmatter);
|
|
834
898
|
const declaredName = fm.name ?? "";
|
|
@@ -836,22 +900,22 @@ function parseCandidate(candidate, origin) {
|
|
|
836
900
|
const name = fromDir ? dirName : declaredName;
|
|
837
901
|
const nameProblem = checkName(name, dirName, fromDir);
|
|
838
902
|
if (nameProblem !== null) {
|
|
839
|
-
return { card: null, diagnostic: diag("invalid",
|
|
903
|
+
return { card: null, diagnostic: diag("invalid", path4, nameProblem) };
|
|
840
904
|
}
|
|
841
905
|
const description = fm.description ?? "";
|
|
842
906
|
const descProblem = checkDescription(description);
|
|
843
907
|
if (descProblem !== null) {
|
|
844
|
-
return { card: null, diagnostic: diag("invalid",
|
|
908
|
+
return { card: null, diagnostic: diag("invalid", path4, descProblem) };
|
|
845
909
|
}
|
|
846
910
|
const card = {
|
|
847
911
|
name,
|
|
848
912
|
description,
|
|
849
913
|
body,
|
|
850
|
-
location:
|
|
914
|
+
location: path4,
|
|
851
915
|
origin,
|
|
852
916
|
frontmatter: fm
|
|
853
917
|
};
|
|
854
|
-
return { card, diagnostic: diag("loaded",
|
|
918
|
+
return { card, diagnostic: diag("loaded", path4, `loaded skill "${name}"`) };
|
|
855
919
|
}
|
|
856
920
|
function describeCause(cause) {
|
|
857
921
|
if (cause instanceof Error) return cause.message;
|
|
@@ -924,15 +988,15 @@ var init_skills = __esm({
|
|
|
924
988
|
// src/briefing/context-docs.ts
|
|
925
989
|
import { existsSync, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
926
990
|
import { dirname as dirname3, extname, isAbsolute as isAbsolute2, join as join6, parse, resolve as resolve2 } from "node:path";
|
|
927
|
-
function shortenPath(
|
|
928
|
-
if (cwd.length > 0 &&
|
|
929
|
-
const rest =
|
|
991
|
+
function shortenPath(path4, cwd, home) {
|
|
992
|
+
if (cwd.length > 0 && path4.startsWith(cwd)) {
|
|
993
|
+
const rest = path4.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
930
994
|
return rest.length > 0 ? `./${rest}` : ".";
|
|
931
995
|
}
|
|
932
|
-
if (home.length > 0 &&
|
|
933
|
-
return `~${
|
|
996
|
+
if (home.length > 0 && path4.startsWith(home)) {
|
|
997
|
+
return `~${path4.slice(home.length)}`;
|
|
934
998
|
}
|
|
935
|
-
return
|
|
999
|
+
return path4;
|
|
936
1000
|
}
|
|
937
1001
|
function dirChain(cwd) {
|
|
938
1002
|
const chain = [];
|
|
@@ -945,15 +1009,15 @@ function dirChain(cwd) {
|
|
|
945
1009
|
}
|
|
946
1010
|
return chain.reverse();
|
|
947
1011
|
}
|
|
948
|
-
function safeRealpath(
|
|
1012
|
+
function safeRealpath(path4) {
|
|
949
1013
|
try {
|
|
950
|
-
return realpathSync2(
|
|
1014
|
+
return realpathSync2(path4);
|
|
951
1015
|
} catch {
|
|
952
|
-
return
|
|
1016
|
+
return path4;
|
|
953
1017
|
}
|
|
954
1018
|
}
|
|
955
|
-
function isTextFile(
|
|
956
|
-
const ext = extname(
|
|
1019
|
+
function isTextFile(path4) {
|
|
1020
|
+
const ext = extname(path4).toLowerCase();
|
|
957
1021
|
return ext.length === 0 || TEXT_FILE_EXTENSIONS.has(ext);
|
|
958
1022
|
}
|
|
959
1023
|
function readFileBody(absPath) {
|
|
@@ -968,7 +1032,7 @@ function readFileBody(absPath) {
|
|
|
968
1032
|
return trimmed.length > 0 ? trimmed : null;
|
|
969
1033
|
}
|
|
970
1034
|
function extractImports(body, baseDir, home) {
|
|
971
|
-
const
|
|
1035
|
+
const out2 = [];
|
|
972
1036
|
IMPORT_REGEX.lastIndex = 0;
|
|
973
1037
|
let match;
|
|
974
1038
|
while ((match = IMPORT_REGEX.exec(body)) !== null) {
|
|
@@ -987,26 +1051,26 @@ function extractImports(body, baseDir, home) {
|
|
|
987
1051
|
abs = resolve2(baseDir, spec);
|
|
988
1052
|
}
|
|
989
1053
|
if (!isTextFile(abs)) continue;
|
|
990
|
-
|
|
1054
|
+
out2.push(abs);
|
|
991
1055
|
}
|
|
992
|
-
return
|
|
1056
|
+
return out2;
|
|
993
1057
|
}
|
|
994
|
-
function loadDocTree(absPath, cwd, home, seen, depth, maxDepth, maxBytes,
|
|
1058
|
+
function loadDocTree(absPath, cwd, home, seen, depth, maxDepth, maxBytes, out2) {
|
|
995
1059
|
const real = safeRealpath(absPath);
|
|
996
1060
|
if (seen.has(real)) return;
|
|
997
1061
|
seen.add(real);
|
|
998
1062
|
const body = readFileBody(absPath);
|
|
999
1063
|
if (body === null) return;
|
|
1000
1064
|
const clipped = body.length > maxBytes ? body.slice(0, maxBytes) : body;
|
|
1001
|
-
|
|
1065
|
+
out2.push({ path: shortenPath(absPath, cwd, home), body: clipped });
|
|
1002
1066
|
if (depth >= maxDepth) return;
|
|
1003
1067
|
const baseDir = dirname3(absPath);
|
|
1004
1068
|
for (const child of extractImports(body, baseDir, home)) {
|
|
1005
|
-
loadDocTree(child, cwd, home, seen, depth + 1, maxDepth, maxBytes,
|
|
1069
|
+
loadDocTree(child, cwd, home, seen, depth + 1, maxDepth, maxBytes, out2);
|
|
1006
1070
|
}
|
|
1007
1071
|
}
|
|
1008
1072
|
function gatherContextDocs(cwd, home, opts) {
|
|
1009
|
-
const
|
|
1073
|
+
const out2 = [];
|
|
1010
1074
|
try {
|
|
1011
1075
|
const maxDepth = opts?.maxImportDepth ?? DEFAULT_MAX_IMPORT_DEPTH;
|
|
1012
1076
|
const maxBytes = opts?.maxBytesPerDoc ?? DEFAULT_MAX_BYTES_PER_DOC;
|
|
@@ -1017,13 +1081,13 @@ function gatherContextDocs(cwd, home, opts) {
|
|
|
1017
1081
|
if (dir.length === 0) continue;
|
|
1018
1082
|
for (const name of CANDIDATE_FILES) {
|
|
1019
1083
|
const candidate = join6(dir, name);
|
|
1020
|
-
loadDocTree(candidate, cwd, home, seen, 0, maxDepth, maxBytes,
|
|
1084
|
+
loadDocTree(candidate, cwd, home, seen, 0, maxDepth, maxBytes, out2);
|
|
1021
1085
|
}
|
|
1022
1086
|
}
|
|
1023
1087
|
} catch {
|
|
1024
|
-
return
|
|
1088
|
+
return out2;
|
|
1025
1089
|
}
|
|
1026
|
-
return
|
|
1090
|
+
return out2;
|
|
1027
1091
|
}
|
|
1028
1092
|
var DEFAULT_MAX_IMPORT_DEPTH, DEFAULT_MAX_BYTES_PER_DOC, CANDIDATE_FILES, TEXT_FILE_EXTENSIONS, IMPORT_REGEX;
|
|
1029
1093
|
var init_context_docs = __esm({
|
|
@@ -1190,13 +1254,15 @@ var init_transcript = __esm({
|
|
|
1190
1254
|
}
|
|
1191
1255
|
};
|
|
1192
1256
|
compactCommand = {
|
|
1193
|
-
name
|
|
1257
|
+
// `compact` is the canonical name — it is what users type (and what the
|
|
1258
|
+
// suggestion list shows); the longer forms stay reachable as aliases.
|
|
1259
|
+
name: "compact",
|
|
1194
1260
|
summary: "Condense the conversation context",
|
|
1195
|
-
aliases: ["condense", "
|
|
1261
|
+
aliases: ["condense", "summarize-context"],
|
|
1196
1262
|
takesArgs: true,
|
|
1197
1263
|
run(ctx) {
|
|
1198
1264
|
const instructions = ctx.args.trim();
|
|
1199
|
-
const busyText = instructions.length > 0 ? `
|
|
1265
|
+
const busyText = instructions.length > 0 ? `Compacting with guidance: ${instructions} \u2014 Esc to cancel` : "Compacting conversation context... Press Esc to cancel.";
|
|
1200
1266
|
ctx.setStatus({ kind: "busy", text: busyText });
|
|
1201
1267
|
void (async () => {
|
|
1202
1268
|
try {
|
|
@@ -1205,14 +1271,29 @@ var init_transcript = __esm({
|
|
|
1205
1271
|
`printf '%s' ${JSON.stringify(`Compaction guidance: ${instructions}`)}`
|
|
1206
1272
|
);
|
|
1207
1273
|
}
|
|
1208
|
-
await ctx.conductor.condense()
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1274
|
+
switch (await ctx.conductor.condense()) {
|
|
1275
|
+
case "condensed":
|
|
1276
|
+
ctx.setStatus(
|
|
1277
|
+
info(
|
|
1278
|
+
instructions.length > 0 ? "Context condensed (guidance recorded for the agent)." : "Context condensed."
|
|
1279
|
+
)
|
|
1280
|
+
);
|
|
1281
|
+
break;
|
|
1282
|
+
case "nothing":
|
|
1283
|
+
ctx.setStatus(warn("Nothing to compact yet."));
|
|
1284
|
+
break;
|
|
1285
|
+
case "cancelled":
|
|
1286
|
+
ctx.setStatus(warn("Compaction cancelled."));
|
|
1287
|
+
break;
|
|
1288
|
+
case "busy":
|
|
1289
|
+
ctx.setStatus(warn("A turn is running \u2014 press Esc to stop it first, then /compact."));
|
|
1290
|
+
break;
|
|
1291
|
+
case "failed":
|
|
1292
|
+
ctx.setStatus(warn("Compaction failed; the transcript is unchanged."));
|
|
1293
|
+
break;
|
|
1294
|
+
}
|
|
1214
1295
|
} catch {
|
|
1215
|
-
ctx.setStatus(warn("
|
|
1296
|
+
ctx.setStatus(warn("Compaction failed; the transcript is unchanged."));
|
|
1216
1297
|
}
|
|
1217
1298
|
})();
|
|
1218
1299
|
return HANDLED;
|
|
@@ -1252,7 +1333,8 @@ var init_transcript = __esm({
|
|
|
1252
1333
|
costCommand = {
|
|
1253
1334
|
name: "cost",
|
|
1254
1335
|
summary: "Show session cost and token usage",
|
|
1255
|
-
|
|
1336
|
+
// `usage` is intentionally NOT an alias here: `/usage` is the server-tier
|
|
1337
|
+
// quota command (see integrations.ts). `/cost` shows this session's local stats.
|
|
1256
1338
|
run(ctx) {
|
|
1257
1339
|
const stats = ctx.conductor.stats();
|
|
1258
1340
|
const t = stats.tokens;
|
|
@@ -1443,9 +1525,9 @@ function runDebug(ctx) {
|
|
|
1443
1525
|
const jsonl = records.map((r) => JSON.stringify(r)).join("\n") + "\n";
|
|
1444
1526
|
try {
|
|
1445
1527
|
const dir = mkdtempSync(join7(tmpdir(), "indus-debug-"));
|
|
1446
|
-
const
|
|
1447
|
-
writeFileSync(
|
|
1448
|
-
ctx.setStatus(info(`Diagnostics written to ${
|
|
1528
|
+
const path4 = join7(dir, `session-${stats.sessionId || "unknown"}.jsonl`);
|
|
1529
|
+
writeFileSync(path4, jsonl, "utf8");
|
|
1530
|
+
ctx.setStatus(info(`Diagnostics written to ${path4}`));
|
|
1449
1531
|
} catch (cause) {
|
|
1450
1532
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
1451
1533
|
ctx.setStatus(warn(`Could not write the diagnostics log (${detail}).`));
|
|
@@ -1514,6 +1596,7 @@ var init_workbench = __esm({
|
|
|
1514
1596
|
["Ctrl+J", "Insert a newline"],
|
|
1515
1597
|
["Ctrl+Z", "Suspend the process"],
|
|
1516
1598
|
["Alt+Up", "Pull the newest queued input back into the composer"],
|
|
1599
|
+
["Ctrl+X", "Run the newest queued message NOW (stops the current run)"],
|
|
1517
1600
|
["! <cmd>", "Run a shell command (kept in context)"],
|
|
1518
1601
|
["!! <cmd>", "Run a shell command (excluded from context)"]
|
|
1519
1602
|
];
|
|
@@ -1598,6 +1681,60 @@ var init_workbench = __esm({
|
|
|
1598
1681
|
}
|
|
1599
1682
|
});
|
|
1600
1683
|
|
|
1684
|
+
// src/boot/runners/server-mode.ts
|
|
1685
|
+
function isGatewayEligibleProvider(provider) {
|
|
1686
|
+
return GATEWAY_ELIGIBLE_PROVIDERS.has(provider);
|
|
1687
|
+
}
|
|
1688
|
+
function serverTierProviders() {
|
|
1689
|
+
return [...GATEWAY_ELIGIBLE_PROVIDERS];
|
|
1690
|
+
}
|
|
1691
|
+
async function hasUsableLocalKey(provider, vault) {
|
|
1692
|
+
try {
|
|
1693
|
+
const accounts = [];
|
|
1694
|
+
const def = await vault.defaultAccount(provider);
|
|
1695
|
+
if (def !== void 0 && def.length > 0) accounts.push(def);
|
|
1696
|
+
for (const account of await vault.listAccounts(provider)) {
|
|
1697
|
+
if (!accounts.includes(account)) accounts.push(account);
|
|
1698
|
+
}
|
|
1699
|
+
for (const account of accounts) {
|
|
1700
|
+
const key = await vault.readUsableKey(provider, account);
|
|
1701
|
+
if (typeof key === "string" && key.length > 0) return true;
|
|
1702
|
+
}
|
|
1703
|
+
} catch {
|
|
1704
|
+
}
|
|
1705
|
+
return false;
|
|
1706
|
+
}
|
|
1707
|
+
async function resolveServerMode(_ctx, provider, vault) {
|
|
1708
|
+
if (!isGatewayEligibleProvider(provider)) return { serverMode: false };
|
|
1709
|
+
if (await hasUsableLocalKey(provider, vault)) return { serverMode: false };
|
|
1710
|
+
if (!await hasValidServerToken()) return { serverMode: false };
|
|
1711
|
+
const token = await getServerToken();
|
|
1712
|
+
const access = token?.access_token;
|
|
1713
|
+
if (typeof access !== "string" || access.length === 0) return { serverMode: false };
|
|
1714
|
+
return { serverMode: true, token: access };
|
|
1715
|
+
}
|
|
1716
|
+
async function resolveServerGatewayUrls(ctx, vault) {
|
|
1717
|
+
const map = {};
|
|
1718
|
+
for (const provider of GATEWAY_ELIGIBLE_PROVIDERS) {
|
|
1719
|
+
const result = await resolveServerMode(ctx, provider, vault);
|
|
1720
|
+
if (result.serverMode) {
|
|
1721
|
+
map[provider] = `${INDUS_SERVER_URL}/gateway/${provider}`;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
return map;
|
|
1725
|
+
}
|
|
1726
|
+
var GATEWAY_ELIGIBLE_PROVIDERS;
|
|
1727
|
+
var init_server_mode = __esm({
|
|
1728
|
+
"src/boot/runners/server-mode.ts"() {
|
|
1729
|
+
"use strict";
|
|
1730
|
+
init_server_token();
|
|
1731
|
+
GATEWAY_ELIGIBLE_PROVIDERS = /* @__PURE__ */ new Set([
|
|
1732
|
+
"minimax",
|
|
1733
|
+
"sarvam"
|
|
1734
|
+
]);
|
|
1735
|
+
}
|
|
1736
|
+
});
|
|
1737
|
+
|
|
1601
1738
|
// src/capability-deck/contract.ts
|
|
1602
1739
|
function capabilityId(raw) {
|
|
1603
1740
|
return raw;
|
|
@@ -9173,14 +9310,14 @@ Poll it with action:"poll", id:"${h.id}".`
|
|
|
9173
9310
|
case "poll": {
|
|
9174
9311
|
const h = params.id ? table.get(params.id) : void 0;
|
|
9175
9312
|
if (!h) return errResult("poll", `No background process with id "${params.id ?? ""}".`);
|
|
9176
|
-
const
|
|
9177
|
-
const
|
|
9313
|
+
const out2 = drainBuffer(h.stdout, params.sinceLast ?? false);
|
|
9314
|
+
const err2 = drainBuffer(h.stderr, params.sinceLast ?? false);
|
|
9178
9315
|
const parts = [`Process ${h.id} \u2014 ${statusLine(h)}`];
|
|
9179
|
-
if (
|
|
9180
|
-
${
|
|
9181
|
-
if (
|
|
9182
|
-
${
|
|
9183
|
-
if (
|
|
9316
|
+
if (out2.length) parts.push(`--- stdout ---
|
|
9317
|
+
${out2.join("\n")}`);
|
|
9318
|
+
if (err2.length) parts.push(`--- stderr ---
|
|
9319
|
+
${err2.join("\n")}`);
|
|
9320
|
+
if (out2.length === 0 && err2.length === 0) parts.push("(no new output)");
|
|
9184
9321
|
return {
|
|
9185
9322
|
content: [{ type: "text", text: parts.join("\n") }],
|
|
9186
9323
|
details: { action: "poll", ok: true, id: h.id, state: h.state, exitCode: h.exitCode }
|
|
@@ -9260,8 +9397,8 @@ var init_bg_process_card = __esm({
|
|
|
9260
9397
|
handle.signal = sig;
|
|
9261
9398
|
handle.state = sig ? "signalled" : "exited";
|
|
9262
9399
|
});
|
|
9263
|
-
child.on("error", (
|
|
9264
|
-
pushLines(handle.stderr, `spawn error: ${String(
|
|
9400
|
+
child.on("error", (err2) => {
|
|
9401
|
+
pushLines(handle.stderr, `spawn error: ${String(err2)}`);
|
|
9265
9402
|
handle.state = "exited";
|
|
9266
9403
|
});
|
|
9267
9404
|
this.handles.set(id, handle);
|
|
@@ -9601,6 +9738,10 @@ function createStructuredOutputTool({
|
|
|
9601
9738
|
name,
|
|
9602
9739
|
label: "Structured Output",
|
|
9603
9740
|
description: "Return the final machine-readable result for this subagent task.",
|
|
9741
|
+
// Pure in-memory capture — no filesystem/shell/network mutation — so the
|
|
9742
|
+
// subagent permission gate auto-allows it in every mode (a schema-bound
|
|
9743
|
+
// workflow must be able to land its result even under `default`/`plan`).
|
|
9744
|
+
readOnly: true,
|
|
9604
9745
|
parameters: schema,
|
|
9605
9746
|
async execute(_toolCallId, params) {
|
|
9606
9747
|
capture.value = params;
|
|
@@ -9708,13 +9849,13 @@ function assembleTree(header, blocks, logLines, maxLines) {
|
|
|
9708
9849
|
if (1 + keptLen + summaryCost + logLines.length <= maxLines) break;
|
|
9709
9850
|
folded.add(i);
|
|
9710
9851
|
}
|
|
9711
|
-
const
|
|
9712
|
-
if (folded.size)
|
|
9852
|
+
const out2 = [header];
|
|
9853
|
+
if (folded.size) out2.push(` \u2026 ${folded.size} earlier phases done`);
|
|
9713
9854
|
blocks.forEach((b, i) => {
|
|
9714
|
-
if (!folded.has(i))
|
|
9855
|
+
if (!folded.has(i)) out2.push(...baseRow(b));
|
|
9715
9856
|
});
|
|
9716
|
-
|
|
9717
|
-
return
|
|
9857
|
+
out2.push(...logLines);
|
|
9858
|
+
return out2;
|
|
9718
9859
|
}
|
|
9719
9860
|
function compactPhaseLine(marker, phase, done, agents, now) {
|
|
9720
9861
|
const prefix = ` ${marker} ${phase} ${done}/${agents.length}`;
|
|
@@ -9798,7 +9939,7 @@ var init_display = __esm({
|
|
|
9798
9939
|
|
|
9799
9940
|
// src/workflow-engine/engine.ts
|
|
9800
9941
|
import vm2 from "node:vm";
|
|
9801
|
-
import
|
|
9942
|
+
import os2 from "node:os";
|
|
9802
9943
|
async function runWorkflow(script, options) {
|
|
9803
9944
|
const started = Date.now();
|
|
9804
9945
|
const { meta, body } = parseWorkflowScript(script);
|
|
@@ -9968,7 +10109,7 @@ ${body}
|
|
|
9968
10109
|
};
|
|
9969
10110
|
}
|
|
9970
10111
|
function defaultConcurrency() {
|
|
9971
|
-
const count =
|
|
10112
|
+
const count = os2.cpus()?.length;
|
|
9972
10113
|
return typeof count === "number" && count > 0 ? count : 8;
|
|
9973
10114
|
}
|
|
9974
10115
|
function createLimiter(limit) {
|
|
@@ -10646,8 +10787,8 @@ function memoryBackend() {
|
|
|
10646
10787
|
}
|
|
10647
10788
|
function fsBackend(dir) {
|
|
10648
10789
|
const fileOf = async (sessionId) => {
|
|
10649
|
-
const
|
|
10650
|
-
return
|
|
10790
|
+
const path4 = await import("node:path");
|
|
10791
|
+
return path4.join(dir, `${sessionId}.ndjson`);
|
|
10651
10792
|
};
|
|
10652
10793
|
return {
|
|
10653
10794
|
locate: (sessionId) => `${dir}/${sessionId}.ndjson`,
|
|
@@ -11060,6 +11201,73 @@ var init_skill_parse = __esm({
|
|
|
11060
11201
|
}
|
|
11061
11202
|
});
|
|
11062
11203
|
|
|
11204
|
+
// src/conductor/quota-error.ts
|
|
11205
|
+
function collectErrorSignals(error) {
|
|
11206
|
+
const statuses = [];
|
|
11207
|
+
const parts = [];
|
|
11208
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11209
|
+
const visit = (value, depth) => {
|
|
11210
|
+
if (value === null || value === void 0 || depth > 6) return;
|
|
11211
|
+
if (typeof value === "string") {
|
|
11212
|
+
parts.push(value);
|
|
11213
|
+
return;
|
|
11214
|
+
}
|
|
11215
|
+
if (typeof value === "number") {
|
|
11216
|
+
statuses.push(value);
|
|
11217
|
+
return;
|
|
11218
|
+
}
|
|
11219
|
+
if (typeof value !== "object") return;
|
|
11220
|
+
if (seen.has(value)) return;
|
|
11221
|
+
seen.add(value);
|
|
11222
|
+
const obj = value;
|
|
11223
|
+
for (const key of ["status", "statusCode", "code"]) {
|
|
11224
|
+
const raw = obj[key];
|
|
11225
|
+
if (typeof raw === "number") statuses.push(raw);
|
|
11226
|
+
else if (typeof raw === "string" && /^\d+$/.test(raw)) statuses.push(Number(raw));
|
|
11227
|
+
}
|
|
11228
|
+
if (typeof obj.message === "string") parts.push(obj.message);
|
|
11229
|
+
visit(obj.cause, depth + 1);
|
|
11230
|
+
visit(obj.error, depth + 1);
|
|
11231
|
+
visit(obj.response, depth + 1);
|
|
11232
|
+
visit(obj.body, depth + 1);
|
|
11233
|
+
visit(obj.data, depth + 1);
|
|
11234
|
+
};
|
|
11235
|
+
visit(error, 0);
|
|
11236
|
+
try {
|
|
11237
|
+
parts.push(JSON.stringify(error));
|
|
11238
|
+
} catch {
|
|
11239
|
+
}
|
|
11240
|
+
if (error instanceof Error && typeof error.stack === "string") parts.push(error.stack);
|
|
11241
|
+
return { statuses, text: parts.join(" ").toLowerCase() };
|
|
11242
|
+
}
|
|
11243
|
+
function isQuotaFault(error) {
|
|
11244
|
+
const { statuses, text } = collectErrorSignals(error);
|
|
11245
|
+
if (!text.includes(QUOTA_MARKER)) return false;
|
|
11246
|
+
return statuses.includes(429) || text.includes(QUOTA_MARKER);
|
|
11247
|
+
}
|
|
11248
|
+
function parseUsedLimit(text) {
|
|
11249
|
+
const used = text.match(/"used"\s*:\s*(\d+)/);
|
|
11250
|
+
const limit = text.match(/"limit"\s*:\s*(\d+)/);
|
|
11251
|
+
if (used && limit) {
|
|
11252
|
+
return { used: Number(used[1]), limit: Number(limit[1]) };
|
|
11253
|
+
}
|
|
11254
|
+
return void 0;
|
|
11255
|
+
}
|
|
11256
|
+
function quotaErrorMessage(error) {
|
|
11257
|
+
if (!isQuotaFault(error)) return void 0;
|
|
11258
|
+
const { text } = collectErrorSignals(error);
|
|
11259
|
+
const numbers = parseUsedLimit(text);
|
|
11260
|
+
const usage = numbers ? ` (${numbers.used}/${numbers.limit} tokens this month)` : "";
|
|
11261
|
+
return `You've hit your indus usage limit${usage}. Add your own API key with \`indus signin <provider>\`, or upgrade your plan.`;
|
|
11262
|
+
}
|
|
11263
|
+
var QUOTA_MARKER;
|
|
11264
|
+
var init_quota_error = __esm({
|
|
11265
|
+
"src/conductor/quota-error.ts"() {
|
|
11266
|
+
"use strict";
|
|
11267
|
+
QUOTA_MARKER = "quota_exceeded";
|
|
11268
|
+
}
|
|
11269
|
+
});
|
|
11270
|
+
|
|
11063
11271
|
// src/capability-deck/cards/plan-file.ts
|
|
11064
11272
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
11065
11273
|
import { join as join8 } from "node:path";
|
|
@@ -11072,10 +11280,10 @@ function writePlan(sessionDir, plan) {
|
|
|
11072
11280
|
const dir = join8(sessionDir, PLANS_DIRNAME);
|
|
11073
11281
|
mkdirSync2(dir, { recursive: true });
|
|
11074
11282
|
const stamp = Date.now().toString(36);
|
|
11075
|
-
const
|
|
11076
|
-
writeFileSync2(
|
|
11283
|
+
const path4 = join8(dir, `${stamp}-${planSlug(plan)}.md`);
|
|
11284
|
+
writeFileSync2(path4, plan.endsWith("\n") ? plan : `${plan}
|
|
11077
11285
|
`, { encoding: "utf8", mode: 384 });
|
|
11078
|
-
return
|
|
11286
|
+
return path4;
|
|
11079
11287
|
}
|
|
11080
11288
|
var PLANS_DIRNAME, MAX_SLUG_LEN;
|
|
11081
11289
|
var init_plan_file = __esm({
|
|
@@ -11323,10 +11531,10 @@ function flattenMessage(message) {
|
|
|
11323
11531
|
return `${TURN_MARK} ${tag} (${message.toolName}): ${text}`;
|
|
11324
11532
|
}
|
|
11325
11533
|
case "bashExecution": {
|
|
11326
|
-
const
|
|
11534
|
+
const out2 = tidy(message.output);
|
|
11327
11535
|
const code = message.exitCode ?? "n/a";
|
|
11328
11536
|
return `${TURN_MARK} shell$ ${tidy(message.command)} [exit ${code}]
|
|
11329
|
-
${
|
|
11537
|
+
${out2}`;
|
|
11330
11538
|
}
|
|
11331
11539
|
case "custom": {
|
|
11332
11540
|
const text = tidy(readContent(message.content));
|
|
@@ -11450,7 +11658,8 @@ async function summarize(messages, deps = {}) {
|
|
|
11450
11658
|
const options = {
|
|
11451
11659
|
reasoning: "high",
|
|
11452
11660
|
...deps.maxTokens !== void 0 ? { maxTokens: deps.maxTokens } : {},
|
|
11453
|
-
...deps.signal ? { signal: deps.signal } : {}
|
|
11661
|
+
...deps.signal ? { signal: deps.signal } : {},
|
|
11662
|
+
...deps.apiKey !== void 0 ? { apiKey: deps.apiKey } : {}
|
|
11454
11663
|
};
|
|
11455
11664
|
const complete = deps.complete ?? completeSimple;
|
|
11456
11665
|
const reply = await complete(deps.model, context, options);
|
|
@@ -11593,8 +11802,8 @@ function collectVisibleReadPaths(kept, readToolName) {
|
|
|
11593
11802
|
if (!isRecord4(block2) || block2.type !== "toolCall") continue;
|
|
11594
11803
|
if (block2.name !== readToolName) continue;
|
|
11595
11804
|
const args = isRecord4(block2.arguments) ? block2.arguments : void 0;
|
|
11596
|
-
const
|
|
11597
|
-
if (
|
|
11805
|
+
const path4 = args && typeof args.path === "string" ? args.path : "";
|
|
11806
|
+
if (path4.length > 0) paths.add(path4);
|
|
11598
11807
|
}
|
|
11599
11808
|
}
|
|
11600
11809
|
return paths;
|
|
@@ -11610,8 +11819,8 @@ function collectDroppedReads(dropped, readToolName) {
|
|
|
11610
11819
|
if (block2.name !== readToolName) continue;
|
|
11611
11820
|
const id = typeof block2.id === "string" ? block2.id : "";
|
|
11612
11821
|
const args = isRecord4(block2.arguments) ? block2.arguments : void 0;
|
|
11613
|
-
const
|
|
11614
|
-
if (id.length > 0 &&
|
|
11822
|
+
const path4 = args && typeof args.path === "string" ? args.path : "";
|
|
11823
|
+
if (id.length > 0 && path4.length > 0) calls.set(id, { path: path4, order: i });
|
|
11615
11824
|
}
|
|
11616
11825
|
}
|
|
11617
11826
|
if (calls.size === 0) return [];
|
|
@@ -11684,7 +11893,7 @@ var init_window_budget = __esm({
|
|
|
11684
11893
|
});
|
|
11685
11894
|
|
|
11686
11895
|
// src/conductor/diagnostics.ts
|
|
11687
|
-
import * as
|
|
11896
|
+
import * as path2 from "node:path";
|
|
11688
11897
|
import { existsSync as existsSync2 } from "node:fs";
|
|
11689
11898
|
function createDiagnosticKey(d) {
|
|
11690
11899
|
const { start, end } = d.range;
|
|
@@ -11798,7 +12007,7 @@ async function runTscDiagnostics(cwd, signal) {
|
|
|
11798
12007
|
const spawn3 = await loadSpawn();
|
|
11799
12008
|
if (spawn3 === void 0) return [];
|
|
11800
12009
|
if (signal?.aborted) return [];
|
|
11801
|
-
const bin =
|
|
12010
|
+
const bin = path2.join(cwd, "node_modules", ".bin", "tsc");
|
|
11802
12011
|
const output = await captureOutput(
|
|
11803
12012
|
spawn3,
|
|
11804
12013
|
bin,
|
|
@@ -11816,7 +12025,7 @@ function parseTscOutput(output, cwd) {
|
|
|
11816
12025
|
const m = re.exec(raw);
|
|
11817
12026
|
if (m === null) continue;
|
|
11818
12027
|
const [, file, lineStr, colStr, sevWord, code, message] = m;
|
|
11819
|
-
const uri =
|
|
12028
|
+
const uri = path2.isAbsolute(file) ? file : path2.resolve(cwd, file);
|
|
11820
12029
|
const line = Math.max(0, Number(lineStr) - 1);
|
|
11821
12030
|
const character = Math.max(0, Number(colStr) - 1);
|
|
11822
12031
|
const diagnostic = {
|
|
@@ -11837,7 +12046,7 @@ async function runEslintDiagnostics(files, cwd, signal) {
|
|
|
11837
12046
|
const spawn3 = await loadSpawn();
|
|
11838
12047
|
if (spawn3 === void 0) return [];
|
|
11839
12048
|
if (signal?.aborted) return [];
|
|
11840
|
-
const bin =
|
|
12049
|
+
const bin = path2.join(cwd, "node_modules", ".bin", "eslint");
|
|
11841
12050
|
const output = await captureOutput(
|
|
11842
12051
|
spawn3,
|
|
11843
12052
|
bin,
|
|
@@ -11858,10 +12067,10 @@ function parseEslintOutput(output, cwd) {
|
|
|
11858
12067
|
} catch {
|
|
11859
12068
|
return [];
|
|
11860
12069
|
}
|
|
11861
|
-
const
|
|
12070
|
+
const out2 = [];
|
|
11862
12071
|
for (const file of parsed) {
|
|
11863
12072
|
if (!Array.isArray(file.messages) || file.messages.length === 0) continue;
|
|
11864
|
-
const uri =
|
|
12073
|
+
const uri = path2.isAbsolute(file.filePath) ? file.filePath : path2.resolve(cwd, file.filePath);
|
|
11865
12074
|
const diagnostics = [];
|
|
11866
12075
|
for (const msg of file.messages) {
|
|
11867
12076
|
const line = Math.max(0, (msg.line ?? 1) - 1);
|
|
@@ -11879,9 +12088,9 @@ function parseEslintOutput(output, cwd) {
|
|
|
11879
12088
|
...msg.ruleId ? { code: msg.ruleId } : {}
|
|
11880
12089
|
});
|
|
11881
12090
|
}
|
|
11882
|
-
if (diagnostics.length > 0)
|
|
12091
|
+
if (diagnostics.length > 0) out2.push({ uri, diagnostics });
|
|
11883
12092
|
}
|
|
11884
|
-
return
|
|
12093
|
+
return out2;
|
|
11885
12094
|
}
|
|
11886
12095
|
function captureOutput(spawn3, bin, args, cwd, signal) {
|
|
11887
12096
|
return new Promise((resolve8) => {
|
|
@@ -11928,11 +12137,11 @@ function captureOutput(spawn3, bin, args, cwd, signal) {
|
|
|
11928
12137
|
});
|
|
11929
12138
|
}
|
|
11930
12139
|
function isTypeScriptOrJs(filePath) {
|
|
11931
|
-
return TS_JS_EXTENSIONS.has(
|
|
12140
|
+
return TS_JS_EXTENSIONS.has(path2.extname(filePath).toLowerCase());
|
|
11932
12141
|
}
|
|
11933
12142
|
function hasTsConfig(cwd) {
|
|
11934
12143
|
try {
|
|
11935
|
-
return existsSync2(
|
|
12144
|
+
return existsSync2(path2.join(cwd, "tsconfig.json"));
|
|
11936
12145
|
} catch {
|
|
11937
12146
|
return false;
|
|
11938
12147
|
}
|
|
@@ -11950,7 +12159,7 @@ function hasEslintConfig(cwd) {
|
|
|
11950
12159
|
".eslintrc.yml",
|
|
11951
12160
|
".eslintrc.yaml"
|
|
11952
12161
|
];
|
|
11953
|
-
return candidates.some((name) => existsSync2(
|
|
12162
|
+
return candidates.some((name) => existsSync2(path2.join(cwd, name)));
|
|
11954
12163
|
} catch {
|
|
11955
12164
|
return false;
|
|
11956
12165
|
}
|
|
@@ -12040,7 +12249,7 @@ var init_diagnostics = __esm({
|
|
|
12040
12249
|
if (!this.#enabled) return [];
|
|
12041
12250
|
if (editedPaths.length === 0) return [];
|
|
12042
12251
|
const all = await this.#runAll(signal);
|
|
12043
|
-
const editedSet = new Set(editedPaths.map((p) =>
|
|
12252
|
+
const editedSet = new Set(editedPaths.map((p) => path2.resolve(this.#cwd, p)));
|
|
12044
12253
|
if (this.#baseline === void 0) {
|
|
12045
12254
|
this.#baseline = /* @__PURE__ */ new Map();
|
|
12046
12255
|
for (const file of all) {
|
|
@@ -12065,7 +12274,7 @@ var init_diagnostics = __esm({
|
|
|
12065
12274
|
* re-surface (e.g. the agent edited it again). The baseline is left intact.
|
|
12066
12275
|
*/
|
|
12067
12276
|
clearDeliveredForFile(uri) {
|
|
12068
|
-
this.#delivered.delete(
|
|
12277
|
+
this.#delivered.delete(path2.resolve(this.#cwd, uri));
|
|
12069
12278
|
}
|
|
12070
12279
|
/** Drop all cross-turn state and the baseline (re-seeds on the next run). */
|
|
12071
12280
|
reset() {
|
|
@@ -12108,7 +12317,7 @@ var init_diagnostics = __esm({
|
|
|
12108
12317
|
// src/conductor/conductor.ts
|
|
12109
12318
|
import { Agent } from "indusagi/agent";
|
|
12110
12319
|
import { createZeroUsage as createZeroUsage2 } from "indusagi/ai";
|
|
12111
|
-
import * as
|
|
12320
|
+
import * as path3 from "node:path";
|
|
12112
12321
|
function reduceState(prev, action) {
|
|
12113
12322
|
switch (action.type) {
|
|
12114
12323
|
case "phase":
|
|
@@ -12167,7 +12376,7 @@ function createSessionConductor(options, deps = {}) {
|
|
|
12167
12376
|
const approvalHolder = { resolver: void 0 };
|
|
12168
12377
|
const approvalDelegate = async (toolName, input, opts) => {
|
|
12169
12378
|
const installed = approvalHolder.resolver;
|
|
12170
|
-
if (installed === void 0) return "
|
|
12379
|
+
if (installed === void 0) return "unavailable";
|
|
12171
12380
|
return installed(toolName, input, opts);
|
|
12172
12381
|
};
|
|
12173
12382
|
const gate = options.canUseTool?.(
|
|
@@ -12188,7 +12397,11 @@ function buildLiveAgent(options, deps, gate) {
|
|
|
12188
12397
|
if (card === void 0) {
|
|
12189
12398
|
throw new Error(`createSessionConductor: no model matches "${options.modelId}"`);
|
|
12190
12399
|
}
|
|
12191
|
-
return new LazyAgent(card.model, options, gate);
|
|
12400
|
+
return new LazyAgent(withGatewayBaseUrl(card.model, options.gatewayBaseUrls), options, gate);
|
|
12401
|
+
}
|
|
12402
|
+
function withGatewayBaseUrl(model, gatewayBaseUrls) {
|
|
12403
|
+
const url = gatewayBaseUrls?.[model.provider];
|
|
12404
|
+
return url ? { ...model, baseUrl: url } : model;
|
|
12192
12405
|
}
|
|
12193
12406
|
function makeAgent(model, options, gate) {
|
|
12194
12407
|
const agent = new Agent({
|
|
@@ -12278,7 +12491,7 @@ ${outcome.output}`.trimEnd();
|
|
|
12278
12491
|
timestamp: Date.now()
|
|
12279
12492
|
};
|
|
12280
12493
|
}
|
|
12281
|
-
var noopCondense, DEFAULT_RETRY, MAX_CONSECUTIVE_CONDENSE_FAILURES, THINKING_LADDER, DEFAULT_THINKING, PERMISSION_CYCLE, SessionConductorImpl, LazyAgent;
|
|
12494
|
+
var noopCondense, DEFAULT_RETRY, MAX_CONSECUTIVE_CONDENSE_FAILURES, MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT, THINKING_LADDER, DEFAULT_THINKING, PERMISSION_CYCLE, SessionConductorImpl, LazyAgent;
|
|
12282
12495
|
var init_conductor = __esm({
|
|
12283
12496
|
"src/conductor/conductor.ts"() {
|
|
12284
12497
|
"use strict";
|
|
@@ -12287,12 +12500,14 @@ var init_conductor = __esm({
|
|
|
12287
12500
|
init_signal_hub();
|
|
12288
12501
|
init_transcript_store();
|
|
12289
12502
|
init_skill_parse();
|
|
12503
|
+
init_quota_error();
|
|
12290
12504
|
init_plan_file();
|
|
12291
12505
|
init_window_budget();
|
|
12292
12506
|
init_diagnostics();
|
|
12293
12507
|
noopCondense = (messages) => messages;
|
|
12294
12508
|
DEFAULT_RETRY = { maxAttempts: 2, baseDelayMs: 250 };
|
|
12295
12509
|
MAX_CONSECUTIVE_CONDENSE_FAILURES = 3;
|
|
12510
|
+
MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT = 3;
|
|
12296
12511
|
THINKING_LADDER = ["off", "low", "medium", "high"];
|
|
12297
12512
|
DEFAULT_THINKING = "off";
|
|
12298
12513
|
PERMISSION_CYCLE = ["default", "acceptEdits", "plan", "bypass"];
|
|
@@ -12324,6 +12539,29 @@ var init_conductor = __esm({
|
|
|
12324
12539
|
* to 0 on the next successful condense.
|
|
12325
12540
|
*/
|
|
12326
12541
|
#condenseFailures = 0;
|
|
12542
|
+
/**
|
|
12543
|
+
* The cancel handle for an in-flight MANUAL condense (`/compact`), or
|
|
12544
|
+
* `undefined` when none is running. {@link cancelCondense} (and {@link abort},
|
|
12545
|
+
* so a user's Esc stops a compaction the same way it stops a turn) abort it;
|
|
12546
|
+
* {@link #runCondense} then discards the digest and reports `"cancelled"`.
|
|
12547
|
+
*/
|
|
12548
|
+
#condenseAbort;
|
|
12549
|
+
/**
|
|
12550
|
+
* The session's per-call credential resolver (the same one the framework
|
|
12551
|
+
* Agent uses). The condense seam resolves the bound model's key through it so
|
|
12552
|
+
* the summarizer's model call authenticates exactly like a turn — including
|
|
12553
|
+
* server-tier sessions, whose ONLY credential is the vended session token
|
|
12554
|
+
* (no env var exists for the summarizer to fall back to).
|
|
12555
|
+
*/
|
|
12556
|
+
#getApiKey;
|
|
12557
|
+
/**
|
|
12558
|
+
* Whether the next in-flight-turn abort is an EXPECTED steer (Ctrl+X ran
|
|
12559
|
+
* {@link steerNow}): the unwinding turn consumes the rejection quietly —
|
|
12560
|
+
* no terminal fault, no error toast, no busy-spinner drop — because the
|
|
12561
|
+
* steered turn takes over immediately. Reset at every turn start so a stale
|
|
12562
|
+
* flag can never swallow a genuine later fault.
|
|
12563
|
+
*/
|
|
12564
|
+
#steerPending = false;
|
|
12327
12565
|
/**
|
|
12328
12566
|
* Canonical id of the model to fall back to when the bound model is overloaded
|
|
12329
12567
|
* (HTTP 529), or `undefined` when no `--fallback-model` was configured. When
|
|
@@ -12331,6 +12569,20 @@ var init_conductor = __esm({
|
|
|
12331
12569
|
* and retries instead of surfacing a terminal fault.
|
|
12332
12570
|
*/
|
|
12333
12571
|
#fallbackModelId;
|
|
12572
|
+
/**
|
|
12573
|
+
* Base URL of the indus model gateway to route this session through ("server
|
|
12574
|
+
* mode"), or `undefined` for the normal direct-to-provider path. When set,
|
|
12575
|
+
* every model bind clones the framework model with its `baseUrl` swapped to
|
|
12576
|
+
* this URL (see {@link withGatewayBaseUrl}) so requests flow through the
|
|
12577
|
+
* quota-enforcing server while the session token (vended by `getApiKey`)
|
|
12578
|
+
* authenticates them. Absent leaves the local-key path byte-for-byte unchanged.
|
|
12579
|
+
*
|
|
12580
|
+
* Not `readonly`: {@link updateGatewayBaseUrls} replaces this map when a
|
|
12581
|
+
* mid-session sign-in changes which providers are gateway-eligible, so a
|
|
12582
|
+
* later rebind (see `#bindModel`/`#applyModelCard`) picks up the fresh
|
|
12583
|
+
* routing without waiting for a full conductor rebuild.
|
|
12584
|
+
*/
|
|
12585
|
+
#gatewayBaseUrls;
|
|
12334
12586
|
/**
|
|
12335
12587
|
* Whether the one-shot fallback swap has already fired for the CURRENT turn.
|
|
12336
12588
|
* Reset to `false` at the top of every {@link #runTurn} (not per attempt) so a
|
|
@@ -12382,6 +12634,13 @@ var init_conductor = __esm({
|
|
|
12382
12634
|
* {@link #runPostEditDiagnostics} at the turn-end seam.
|
|
12383
12635
|
*/
|
|
12384
12636
|
#editedThisTurn = /* @__PURE__ */ new Set();
|
|
12637
|
+
/**
|
|
12638
|
+
* How many diagnostics follow-ups have been auto-injected since the last REAL
|
|
12639
|
+
* user prompt. Reset by {@link submit}; capped by
|
|
12640
|
+
* {@link MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT} so a model that cannot satisfy a
|
|
12641
|
+
* checker can never be re-prompted forever without the user asking again.
|
|
12642
|
+
*/
|
|
12643
|
+
#diagnosticFollowUps = 0;
|
|
12385
12644
|
/**
|
|
12386
12645
|
* The mode captured the moment plan mode was entered, restored when plan mode is
|
|
12387
12646
|
* left. `undefined` whenever the session is not in (or paused from) plan mode.
|
|
@@ -12421,6 +12680,7 @@ var init_conductor = __esm({
|
|
|
12421
12680
|
this.#hub = deps.hub ?? new SignalHub();
|
|
12422
12681
|
this.#matcher = deps.matcher;
|
|
12423
12682
|
this.#condense = deps.condense ?? noopCondense;
|
|
12683
|
+
this.#getApiKey = options.getApiKey;
|
|
12424
12684
|
this.#retry = deps.retry ?? DEFAULT_RETRY;
|
|
12425
12685
|
this.#autoCompact = options.autoCompact ?? true;
|
|
12426
12686
|
this.#sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -12428,6 +12688,7 @@ var init_conductor = __esm({
|
|
|
12428
12688
|
this.#modeHolder = modeHolder ?? { mode: options.permissionMode ?? "default" };
|
|
12429
12689
|
this.#approvalHolder = approvalHolder ?? { resolver: void 0 };
|
|
12430
12690
|
this.#fallbackModelId = options.fallbackModelId;
|
|
12691
|
+
this.#gatewayBaseUrls = options.gatewayBaseUrls;
|
|
12431
12692
|
this.#workspace = options.workspace ?? process.cwd();
|
|
12432
12693
|
this.#plansDir = options.plansDir;
|
|
12433
12694
|
this.#checkpoint = options.checkpoint;
|
|
@@ -12444,7 +12705,10 @@ var init_conductor = __esm({
|
|
|
12444
12705
|
// no fault initially
|
|
12445
12706
|
};
|
|
12446
12707
|
const initial = this.#matcher?.resolveCard(options.modelId);
|
|
12447
|
-
this.#boundModel =
|
|
12708
|
+
this.#boundModel = withGatewayBaseUrl(
|
|
12709
|
+
initial?.model ?? agent.state.model,
|
|
12710
|
+
this.#gatewayBaseUrls
|
|
12711
|
+
);
|
|
12448
12712
|
}
|
|
12449
12713
|
/* ---- public surface ---- */
|
|
12450
12714
|
subscribe(handler) {
|
|
@@ -12467,12 +12731,18 @@ var init_conductor = __esm({
|
|
|
12467
12731
|
return [...this.#matcher.resolveAll("")];
|
|
12468
12732
|
}
|
|
12469
12733
|
abort() {
|
|
12734
|
+
if (this.#queue.length > 0) {
|
|
12735
|
+
this.#queue.length = 0;
|
|
12736
|
+
this.#hub.emit({ kind: "queue", count: 0 });
|
|
12737
|
+
}
|
|
12738
|
+
this.#condenseAbort?.abort();
|
|
12470
12739
|
this.#agent.abort();
|
|
12471
12740
|
this.#dispatch({ type: "fault", fault: conductorFault("aborted", "turn aborted by caller") });
|
|
12472
12741
|
this.#hub.emit({ kind: "fault", fault: conductorFault("aborted", "turn aborted by caller") });
|
|
12473
12742
|
this.#hub.emit({ kind: "idle" });
|
|
12474
12743
|
}
|
|
12475
12744
|
async submit(input) {
|
|
12745
|
+
this.#diagnosticFollowUps = 0;
|
|
12476
12746
|
if (this.#busy) {
|
|
12477
12747
|
this.enqueue(input);
|
|
12478
12748
|
return this.#state;
|
|
@@ -12507,6 +12777,22 @@ var init_conductor = __esm({
|
|
|
12507
12777
|
this.#hub.emit({ kind: "queue", count: this.#queue.length });
|
|
12508
12778
|
return popped.text;
|
|
12509
12779
|
}
|
|
12780
|
+
steerNow() {
|
|
12781
|
+
const promoted = this.#queue.pop();
|
|
12782
|
+
if (promoted === void 0) return false;
|
|
12783
|
+
this.#queue.unshift({ mode: "steer", text: promoted.text });
|
|
12784
|
+
this.#hub.emit({ kind: "queue", count: this.#queue.length });
|
|
12785
|
+
if (this.#busy) {
|
|
12786
|
+
this.#steerPending = true;
|
|
12787
|
+
this.#condenseAbort?.abort();
|
|
12788
|
+
this.#agent.abort();
|
|
12789
|
+
return true;
|
|
12790
|
+
}
|
|
12791
|
+
const next = this.#takeNext();
|
|
12792
|
+
this.#hub.emit({ kind: "queue", count: this.#queue.length });
|
|
12793
|
+
void this.submit(next.text);
|
|
12794
|
+
return true;
|
|
12795
|
+
}
|
|
12510
12796
|
/**
|
|
12511
12797
|
* Drain the pending-input queue in order, running each entry as its own turn.
|
|
12512
12798
|
* `steer`-mode entries are taken ahead of plain follow-ups so an interrupt is
|
|
@@ -12544,6 +12830,7 @@ var init_conductor = __esm({
|
|
|
12544
12830
|
const prompt = skill ? skill.body : input;
|
|
12545
12831
|
this.#inFlightTools.length = 0;
|
|
12546
12832
|
this.#fallbackTried = false;
|
|
12833
|
+
this.#steerPending = false;
|
|
12547
12834
|
this.#checkpoint?.setActiveNodeId(this.#store.head.leaf);
|
|
12548
12835
|
this.#dispatch({ type: "phase", phase: "streaming" });
|
|
12549
12836
|
if (this.#diagnostics !== void 0 && !this.#diagnostics.hasBaseline) {
|
|
@@ -12555,7 +12842,7 @@ var init_conductor = __esm({
|
|
|
12555
12842
|
const baseline = this.#agent.state.messages.length;
|
|
12556
12843
|
const clean = await this.#runWithRetry(prompt);
|
|
12557
12844
|
if (!clean) {
|
|
12558
|
-
this.#hub.emit({ kind: "idle" });
|
|
12845
|
+
if (this.#queue.length === 0) this.#hub.emit({ kind: "idle" });
|
|
12559
12846
|
return this.#state;
|
|
12560
12847
|
}
|
|
12561
12848
|
await this.#persistTail(baseline);
|
|
@@ -12569,7 +12856,7 @@ var init_conductor = __esm({
|
|
|
12569
12856
|
this.#dispatch({ type: "head", head: this.#store.head });
|
|
12570
12857
|
}
|
|
12571
12858
|
await this.#runPlanHandshakes();
|
|
12572
|
-
this.#hub.emit({ kind: "idle" });
|
|
12859
|
+
if (this.#queue.length === 0) this.#hub.emit({ kind: "idle" });
|
|
12573
12860
|
return this.#state;
|
|
12574
12861
|
}
|
|
12575
12862
|
async newSession() {
|
|
@@ -12579,6 +12866,7 @@ var init_conductor = __esm({
|
|
|
12579
12866
|
this.#queue.length = 0;
|
|
12580
12867
|
this.#inFlightTools.length = 0;
|
|
12581
12868
|
this.#condenseFailures = 0;
|
|
12869
|
+
this.#diagnosticFollowUps = 0;
|
|
12582
12870
|
this.#agent.replaceMessages([]);
|
|
12583
12871
|
this.#store.startNewSession(newSessionId());
|
|
12584
12872
|
this.#sessionName = void 0;
|
|
@@ -12619,6 +12907,19 @@ var init_conductor = __esm({
|
|
|
12619
12907
|
selectModel(id) {
|
|
12620
12908
|
this.#bindModel(id);
|
|
12621
12909
|
}
|
|
12910
|
+
/**
|
|
12911
|
+
* Replace the server-tier gateway routing map and immediately re-bind the
|
|
12912
|
+
* currently selected model against it, so a mid-session sign-in (`/login` ->
|
|
12913
|
+
* "Indus Server") takes effect on the very next turn instead of requiring a
|
|
12914
|
+
* session restart. Re-resolves the current model's catalog card via
|
|
12915
|
+
* {@link #bindModel} rather than mutating `#boundModel` directly, so the
|
|
12916
|
+
* rebind goes through the exact same path as `selectModel`/`cycleModel`
|
|
12917
|
+
* (tool deck, thinking level, and state dispatch all stay consistent).
|
|
12918
|
+
*/
|
|
12919
|
+
updateGatewayBaseUrls(map) {
|
|
12920
|
+
this.#gatewayBaseUrls = map;
|
|
12921
|
+
this.#bindModel(this.#state.modelId);
|
|
12922
|
+
}
|
|
12622
12923
|
/**
|
|
12623
12924
|
* Resolve a model by canonical id, bind it on the agent for subsequent turns,
|
|
12624
12925
|
* track the full model object, and record the new id in state. A miss surfaces
|
|
@@ -12642,8 +12943,9 @@ var init_conductor = __esm({
|
|
|
12642
12943
|
* so it must resolve its own card and call straight into here.
|
|
12643
12944
|
*/
|
|
12644
12945
|
#applyModelCard(card) {
|
|
12645
|
-
|
|
12646
|
-
this.#
|
|
12946
|
+
const model = withGatewayBaseUrl(card.model, this.#gatewayBaseUrls);
|
|
12947
|
+
this.#agent.setModel(model);
|
|
12948
|
+
this.#boundModel = model;
|
|
12647
12949
|
this.#agent.setThinkingLevel?.(this.#thinking);
|
|
12648
12950
|
this.#dispatch({ type: "model", modelId: card.id });
|
|
12649
12951
|
}
|
|
@@ -12672,7 +12974,10 @@ var init_conductor = __esm({
|
|
|
12672
12974
|
fault: conductorFault(
|
|
12673
12975
|
"model",
|
|
12674
12976
|
`Switched to ${card.id} due to high demand for ${previous}`
|
|
12675
|
-
)
|
|
12977
|
+
),
|
|
12978
|
+
// The turn keeps running on the fallback model — this is an in-turn
|
|
12979
|
+
// notice, not the turn's end, so a busy/in-flight indicator must survive it.
|
|
12980
|
+
transient: true
|
|
12676
12981
|
});
|
|
12677
12982
|
return true;
|
|
12678
12983
|
}
|
|
@@ -12699,11 +13004,32 @@ var init_conductor = __esm({
|
|
|
12699
13004
|
return true;
|
|
12700
13005
|
} catch (error) {
|
|
12701
13006
|
unsubscribe();
|
|
13007
|
+
if (this.#steerPending) {
|
|
13008
|
+
this.#steerPending = false;
|
|
13009
|
+
return false;
|
|
13010
|
+
}
|
|
13011
|
+
if (isQuotaFault(error)) {
|
|
13012
|
+
const fault2 = conductorFault(
|
|
13013
|
+
"model",
|
|
13014
|
+
quotaErrorMessage(error) ?? "You've hit your indus usage limit.",
|
|
13015
|
+
error
|
|
13016
|
+
);
|
|
13017
|
+
this.#dispatch({ type: "fault", fault: fault2 });
|
|
13018
|
+
this.#hub.emit({ kind: "fault", fault: fault2 });
|
|
13019
|
+
return false;
|
|
13020
|
+
}
|
|
12702
13021
|
if (attempt < this.#retry.maxAttempts && isTransient(error)) {
|
|
12703
13022
|
attempt++;
|
|
12704
13023
|
this.#hub.emit({
|
|
12705
13024
|
kind: "fault",
|
|
12706
|
-
fault: conductorFault("model", `transient model fault; retry ${attempt}`, error)
|
|
13025
|
+
fault: conductorFault("model", `transient model fault; retry ${attempt}`, error),
|
|
13026
|
+
// The retry loop is about to try again on the SAME turn — this is an
|
|
13027
|
+
// in-turn notice, not the turn's end. Without this flag the console
|
|
13028
|
+
// clears its busy/in-flight indicator here and never sets it back
|
|
13029
|
+
// (busy only flips true again at the START of the next turn), so the
|
|
13030
|
+
// agent looks "stuck" for the rest of a turn that is actually still
|
|
13031
|
+
// retrying/streaming underneath.
|
|
13032
|
+
transient: true
|
|
12707
13033
|
});
|
|
12708
13034
|
await this.#sleep(this.#retry.baseDelayMs * 2 ** (attempt - 1));
|
|
12709
13035
|
continue;
|
|
@@ -12739,6 +13065,7 @@ var init_conductor = __esm({
|
|
|
12739
13065
|
this.#capturePlanSignals(event.result);
|
|
12740
13066
|
}
|
|
12741
13067
|
for (const signal of translateAgentEvent(event)) {
|
|
13068
|
+
if (signal.kind === "fault" && this.#steerPending) continue;
|
|
12742
13069
|
if (signal.kind === "turn_end") {
|
|
12743
13070
|
this.#dispatch({
|
|
12744
13071
|
type: "usage",
|
|
@@ -12765,7 +13092,7 @@ var init_conductor = __esm({
|
|
|
12765
13092
|
const raw = args?.path;
|
|
12766
13093
|
if (typeof raw !== "string" || raw.length === 0) return;
|
|
12767
13094
|
if (!isTypeScriptOrJs(raw)) return;
|
|
12768
|
-
this.#editedThisTurn.add(
|
|
13095
|
+
this.#editedThisTurn.add(path3.resolve(this.#workspace, raw));
|
|
12769
13096
|
}
|
|
12770
13097
|
/* ---- plan mode ---- */
|
|
12771
13098
|
/**
|
|
@@ -12911,8 +13238,13 @@ var init_conductor = __esm({
|
|
|
12911
13238
|
* Invariants:
|
|
12912
13239
|
* - **never faults the turn** — every failure (a slow/absent checker, a
|
|
12913
13240
|
* parse error) is swallowed and the set is always cleared in `finally`;
|
|
12914
|
-
* - **
|
|
12915
|
-
*
|
|
13241
|
+
* - **can never loop forever** — a diagnostic key is delivered AT MOST ONCE
|
|
13242
|
+
* per session (the engine's delivered ledger is never cleared here; a
|
|
13243
|
+
* "fix" turn that fails to eliminate the same error is NOT re-prompted
|
|
13244
|
+
* with it), and even genuinely new errors stop re-prompting after
|
|
13245
|
+
* {@link MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT} consecutive follow-ups —
|
|
13246
|
+
* the agent must not keep running itself after its final report just
|
|
13247
|
+
* because a checker stays red;
|
|
12916
13248
|
* - inert when diagnostics are disabled (`#diagnostics === undefined`).
|
|
12917
13249
|
*/
|
|
12918
13250
|
async #runPostEditDiagnostics() {
|
|
@@ -12921,11 +13253,15 @@ var init_conductor = __esm({
|
|
|
12921
13253
|
this.#editedThisTurn.clear();
|
|
12922
13254
|
return;
|
|
12923
13255
|
}
|
|
13256
|
+
if (this.#diagnosticFollowUps >= MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT) {
|
|
13257
|
+
this.#editedThisTurn.clear();
|
|
13258
|
+
return;
|
|
13259
|
+
}
|
|
12924
13260
|
const edited = [...this.#editedThisTurn];
|
|
12925
13261
|
try {
|
|
12926
|
-
for (const uri of edited) engine.clearDeliveredForFile(uri);
|
|
12927
13262
|
const files = await engine.newDiagnostics(edited);
|
|
12928
13263
|
if (files.length > 0) {
|
|
13264
|
+
this.#diagnosticFollowUps++;
|
|
12929
13265
|
this.enqueue(
|
|
12930
13266
|
"Diagnostics for files you just changed (fix these before continuing):\n\n" + formatDiagnosticsSummary(files),
|
|
12931
13267
|
"followUp"
|
|
@@ -12962,12 +13298,29 @@ var init_conductor = __esm({
|
|
|
12962
13298
|
}
|
|
12963
13299
|
/**
|
|
12964
13300
|
* Manually drive the same condense path the auto-compactor uses, regardless of
|
|
12965
|
-
* the auto-compaction flag or the soft threshold
|
|
12966
|
-
*
|
|
12967
|
-
*
|
|
13301
|
+
* the auto-compaction flag or the soft threshold, and report the outcome.
|
|
13302
|
+
*
|
|
13303
|
+
* Runs under the busy flag so a prompt submitted mid-compaction QUEUES (and
|
|
13304
|
+
* drains once the condense settles) instead of racing the rebind; is
|
|
13305
|
+
* cancellable via {@link cancelCondense} (the result is discarded); and
|
|
13306
|
+
* refuses (`"busy"`) while a real turn is in flight rather than condensing a
|
|
13307
|
+
* branch that is still growing.
|
|
12968
13308
|
*/
|
|
12969
13309
|
async condense() {
|
|
12970
|
-
|
|
13310
|
+
if (this.#busy) return "busy";
|
|
13311
|
+
this.#busy = true;
|
|
13312
|
+
this.#condenseAbort = new AbortController();
|
|
13313
|
+
try {
|
|
13314
|
+
const outcome = await this.#runCondense(true, this.#condenseAbort.signal);
|
|
13315
|
+
await this.#drainQueue();
|
|
13316
|
+
return outcome;
|
|
13317
|
+
} finally {
|
|
13318
|
+
this.#condenseAbort = void 0;
|
|
13319
|
+
this.#busy = false;
|
|
13320
|
+
}
|
|
13321
|
+
}
|
|
13322
|
+
cancelCondense() {
|
|
13323
|
+
this.#condenseAbort?.abort();
|
|
12971
13324
|
}
|
|
12972
13325
|
/* ---- branch navigation ---- */
|
|
12973
13326
|
async fork(entryId) {
|
|
@@ -13168,27 +13521,51 @@ var init_conductor = __esm({
|
|
|
13168
13521
|
* to a local stub). A throw surfaces an `overflow` fault and bumps the
|
|
13169
13522
|
* consecutive-failure counter (the circuit breaker); a clean run resets it.
|
|
13170
13523
|
*/
|
|
13171
|
-
async #runCondense(force) {
|
|
13524
|
+
async #runCondense(force, signal) {
|
|
13172
13525
|
const branch = this.#store.pathTo();
|
|
13526
|
+
const prior = this.#state.phase;
|
|
13173
13527
|
this.#dispatch({ type: "phase", phase: "condensing" });
|
|
13174
|
-
this.#hub.emit({ kind: "compacted" });
|
|
13175
13528
|
try {
|
|
13176
13529
|
const before = branch.map((entry) => entry.content);
|
|
13530
|
+
let apiKey;
|
|
13531
|
+
if (this.#boundModel !== void 0 && this.#getApiKey !== void 0) {
|
|
13532
|
+
try {
|
|
13533
|
+
apiKey = await this.#getApiKey(String(this.#boundModel.provider));
|
|
13534
|
+
} catch {
|
|
13535
|
+
}
|
|
13536
|
+
}
|
|
13177
13537
|
const after = await this.#condense(before, {
|
|
13178
13538
|
force,
|
|
13179
13539
|
...this.#boundModel !== void 0 ? { model: this.#boundModel } : {},
|
|
13180
|
-
contextTokens: this.#state.contextTokens
|
|
13540
|
+
contextTokens: this.#state.contextTokens,
|
|
13541
|
+
...signal !== void 0 ? { signal } : {},
|
|
13542
|
+
...apiKey !== void 0 ? { apiKey } : {}
|
|
13181
13543
|
});
|
|
13182
|
-
if (
|
|
13183
|
-
this.#
|
|
13184
|
-
|
|
13544
|
+
if (signal?.aborted) {
|
|
13545
|
+
this.#dispatch({ type: "phase", phase: prior });
|
|
13546
|
+
return "cancelled";
|
|
13185
13547
|
}
|
|
13548
|
+
if (after.length >= before.length) {
|
|
13549
|
+
this.#condenseFailures = 0;
|
|
13550
|
+
this.#dispatch({ type: "phase", phase: prior });
|
|
13551
|
+
return "nothing";
|
|
13552
|
+
}
|
|
13553
|
+
this.#agent.replaceMessages([...after]);
|
|
13554
|
+
await this.#persistCondenseBoundary(branch, after);
|
|
13186
13555
|
this.#condenseFailures = 0;
|
|
13556
|
+
if (force) {
|
|
13557
|
+
this.#dispatch({ type: "usage", usage: createZeroUsage2(), contextTokens: 0 });
|
|
13558
|
+
await this.#persistUsage();
|
|
13559
|
+
}
|
|
13560
|
+
this.#hub.emit({ kind: "compacted", manual: force });
|
|
13561
|
+
this.#dispatch({ type: "phase", phase: prior });
|
|
13562
|
+
return "condensed";
|
|
13187
13563
|
} catch (error) {
|
|
13188
13564
|
this.#condenseFailures++;
|
|
13189
13565
|
const fault = conductorFault("overflow", "auto-condense failed", error);
|
|
13190
13566
|
this.#dispatch({ type: "fault", fault });
|
|
13191
13567
|
this.#hub.emit({ kind: "fault", fault });
|
|
13568
|
+
return "failed";
|
|
13192
13569
|
}
|
|
13193
13570
|
}
|
|
13194
13571
|
/**
|
|
@@ -13486,8 +13863,8 @@ function tokenizeArgv(slice) {
|
|
|
13486
13863
|
flush();
|
|
13487
13864
|
return tokens;
|
|
13488
13865
|
}
|
|
13489
|
-
function stripWrappers(
|
|
13490
|
-
const rest = [...
|
|
13866
|
+
function stripWrappers(argv2) {
|
|
13867
|
+
const rest = [...argv2];
|
|
13491
13868
|
let elevated = false;
|
|
13492
13869
|
for (; ; ) {
|
|
13493
13870
|
const head = rest[0];
|
|
@@ -13537,20 +13914,20 @@ function consumeWrapperOptions(rest, wrapper) {
|
|
|
13537
13914
|
}
|
|
13538
13915
|
function parseBashCommand(command) {
|
|
13539
13916
|
if (typeof command !== "string" || command.trim().length === 0) return [];
|
|
13540
|
-
const
|
|
13541
|
-
parseInto(command,
|
|
13542
|
-
return
|
|
13917
|
+
const out2 = [];
|
|
13918
|
+
parseInto(command, out2);
|
|
13919
|
+
return out2;
|
|
13543
13920
|
}
|
|
13544
|
-
function parseInto(command,
|
|
13921
|
+
function parseInto(command, out2) {
|
|
13545
13922
|
for (const slice of splitTopLevel(command)) {
|
|
13546
13923
|
const { outer, inner } = extractSubshells(slice);
|
|
13547
13924
|
if (outer.length > 0) {
|
|
13548
|
-
const
|
|
13549
|
-
if (
|
|
13550
|
-
const { rest, elevated } = stripWrappers(
|
|
13925
|
+
const argv2 = tokenizeArgv(outer);
|
|
13926
|
+
if (argv2.length > 0) {
|
|
13927
|
+
const { rest, elevated } = stripWrappers(argv2);
|
|
13551
13928
|
const name = rest[0];
|
|
13552
13929
|
if (name !== void 0 && name.length > 0) {
|
|
13553
|
-
|
|
13930
|
+
out2.push({
|
|
13554
13931
|
name: name.toLowerCase(),
|
|
13555
13932
|
args: rest.slice(1),
|
|
13556
13933
|
elevated,
|
|
@@ -13560,7 +13937,7 @@ function parseInto(command, out) {
|
|
|
13560
13937
|
}
|
|
13561
13938
|
}
|
|
13562
13939
|
for (const body of inner) {
|
|
13563
|
-
if (body.trim().length > 0) parseInto(body,
|
|
13940
|
+
if (body.trim().length > 0) parseInto(body, out2);
|
|
13564
13941
|
}
|
|
13565
13942
|
}
|
|
13566
13943
|
}
|
|
@@ -13861,8 +14238,18 @@ function resolveRuleDecision(toolName, input, rules, mode, readOnlyExtra) {
|
|
|
13861
14238
|
}
|
|
13862
14239
|
return "ask";
|
|
13863
14240
|
}
|
|
14241
|
+
function allowAlwaysRuleStrings(toolName, input) {
|
|
14242
|
+
if (isBashTool(toolName)) {
|
|
14243
|
+
const bag = input;
|
|
14244
|
+
const command = typeof input === "string" ? input : bag !== null && typeof bag === "object" && typeof bag.command === "string" ? bag.command : "";
|
|
14245
|
+
if (command.length > 0) {
|
|
14246
|
+
return bashSubcommandSubjects(command).map((subject) => `${toolName}(${subject})`);
|
|
14247
|
+
}
|
|
14248
|
+
}
|
|
14249
|
+
return [toolName];
|
|
14250
|
+
}
|
|
13864
14251
|
function noResolverMessage(toolName) {
|
|
13865
|
-
return `Tool "${toolName}" requires approval, but
|
|
14252
|
+
return `Tool "${toolName}" requires approval, but no interactive approval prompt is available here (a non-interactive run, or a sub-agent). Denying. Add an allow rule under permissions.allow in settings, or run with --permission-mode acceptEdits/bypass, to permit it.`;
|
|
13866
14253
|
}
|
|
13867
14254
|
function declinedMessage(toolName) {
|
|
13868
14255
|
return `Tool "${toolName}" was denied by the user.`;
|
|
@@ -13904,15 +14291,34 @@ function createPermissionGate(config) {
|
|
|
13904
14291
|
} catch {
|
|
13905
14292
|
choice = "deny";
|
|
13906
14293
|
}
|
|
13907
|
-
if (choice === "
|
|
13908
|
-
|
|
14294
|
+
if (choice === "allow-once" || choice === "allow-always") {
|
|
14295
|
+
if (choice === "allow-always" && config.appendAllowRule) {
|
|
14296
|
+
for (const raw of allowAlwaysRuleStrings(toolName, input)) {
|
|
14297
|
+
config.appendAllowRule(makeRule("allow", raw));
|
|
14298
|
+
}
|
|
14299
|
+
}
|
|
14300
|
+
return { behavior: "allow" };
|
|
13909
14301
|
}
|
|
13910
|
-
if (choice === "
|
|
13911
|
-
|
|
14302
|
+
if (choice === "unavailable") {
|
|
14303
|
+
return { behavior: "deny", message: noResolverMessage(toolName) };
|
|
13912
14304
|
}
|
|
13913
|
-
return { behavior: "
|
|
14305
|
+
return { behavior: "deny", message: declinedMessage(toolName) };
|
|
13914
14306
|
};
|
|
13915
14307
|
}
|
|
14308
|
+
function collectReadOnlyToolNames(tools) {
|
|
14309
|
+
const names = /* @__PURE__ */ new Set();
|
|
14310
|
+
for (const tool of tools) {
|
|
14311
|
+
if (tool.readOnly === true) names.add(tool.name);
|
|
14312
|
+
}
|
|
14313
|
+
return names;
|
|
14314
|
+
}
|
|
14315
|
+
function createSubagentPermissionGate(policy, tools) {
|
|
14316
|
+
return createPermissionGate({
|
|
14317
|
+
rules: policy.rules,
|
|
14318
|
+
mode: policy.mode,
|
|
14319
|
+
readOnlyToolNames: collectReadOnlyToolNames(tools)
|
|
14320
|
+
});
|
|
14321
|
+
}
|
|
13916
14322
|
var READ_ONLY_TOOL_NAMES, EDIT_TOOL_NAMES;
|
|
13917
14323
|
var init_permissions = __esm({
|
|
13918
14324
|
"src/conductor/permissions.ts"() {
|
|
@@ -14009,13 +14415,22 @@ function createWorkflowAgentRunner(opts) {
|
|
|
14009
14415
|
if (model === void 0) {
|
|
14010
14416
|
throw new Error(`no model resolved for workflow subagent: ${options.model ?? opts.modelId}`);
|
|
14011
14417
|
}
|
|
14418
|
+
const gatewayBaseUrls = await opts.getGatewayBaseUrls?.();
|
|
14419
|
+
const tools = buildTools();
|
|
14012
14420
|
agent = new Agent2({
|
|
14013
14421
|
initialState: {
|
|
14014
|
-
model,
|
|
14422
|
+
model: withGatewayBaseUrl(model, gatewayBaseUrls),
|
|
14015
14423
|
systemPrompt: system,
|
|
14016
|
-
tools
|
|
14424
|
+
tools
|
|
14017
14425
|
},
|
|
14018
|
-
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {}
|
|
14426
|
+
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {},
|
|
14427
|
+
// Gate the subagent's inner tool loop with the parent session's live
|
|
14428
|
+
// policy (rules + current mode). Resolver-less: `ask` denies — a
|
|
14429
|
+
// subagent cannot prompt — while deny rules, plan mode, and the
|
|
14430
|
+
// catastrophic-bash blocklist are enforced per inner tool call. The
|
|
14431
|
+
// `structured_output` capture tool is flagged readOnly, so a
|
|
14432
|
+
// schema-bound workflow still lands its result in every mode.
|
|
14433
|
+
...opts.permissionPolicy !== void 0 ? { canUseTool: createSubagentPermissionGate(opts.permissionPolicy, tools) } : {}
|
|
14019
14434
|
});
|
|
14020
14435
|
}
|
|
14021
14436
|
const activity = { tokensIn: 0, tokensOut: 0, toolCount: 0 };
|
|
@@ -14858,11 +15273,11 @@ function escapeChar(ch) {
|
|
|
14858
15273
|
}
|
|
14859
15274
|
}
|
|
14860
15275
|
function escapeHtml(text) {
|
|
14861
|
-
let
|
|
15276
|
+
let out2 = "";
|
|
14862
15277
|
for (const ch of text) {
|
|
14863
|
-
|
|
15278
|
+
out2 += escapeChar(ch) ?? ch;
|
|
14864
15279
|
}
|
|
14865
|
-
return
|
|
15280
|
+
return out2;
|
|
14866
15281
|
}
|
|
14867
15282
|
function classesFor(state) {
|
|
14868
15283
|
const classes = [];
|
|
@@ -14908,15 +15323,15 @@ function paintSgr(input) {
|
|
|
14908
15323
|
if (input.length === 0) return "";
|
|
14909
15324
|
const tokens = tokenizeSgr(input);
|
|
14910
15325
|
let state = { ...SGR_INITIAL_STATE };
|
|
14911
|
-
let
|
|
15326
|
+
let out2 = "";
|
|
14912
15327
|
for (const token of tokens) {
|
|
14913
15328
|
if (token.kind === "sgr") {
|
|
14914
15329
|
state = foldSgr(state, token.params);
|
|
14915
15330
|
} else {
|
|
14916
|
-
|
|
15331
|
+
out2 += renderRun(token.text, state);
|
|
14917
15332
|
}
|
|
14918
15333
|
}
|
|
14919
|
-
return
|
|
15334
|
+
return out2;
|
|
14920
15335
|
}
|
|
14921
15336
|
var BASE_PALETTE, BRIGHT_PALETTE, PALETTE_16, CODE_TABLE, ESC, CLASS_PREFIX, FLAG_CLASSES;
|
|
14922
15337
|
var init_sgr = __esm({
|
|
@@ -15129,13 +15544,13 @@ function escapeRegExp(text) {
|
|
|
15129
15544
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15130
15545
|
}
|
|
15131
15546
|
function fill(template, values) {
|
|
15132
|
-
let
|
|
15547
|
+
let out2 = template;
|
|
15133
15548
|
for (const token of Object.values(SHELL_SLOTS)) {
|
|
15134
15549
|
const value = values[token] ?? "";
|
|
15135
15550
|
const marker = new RegExp(`\\{\\{${escapeRegExp(token)}\\}\\}`, "g");
|
|
15136
|
-
|
|
15551
|
+
out2 = out2.replace(marker, () => value);
|
|
15137
15552
|
}
|
|
15138
|
-
return
|
|
15553
|
+
return out2;
|
|
15139
15554
|
}
|
|
15140
15555
|
var PAGE_STYLES, CLIENT_SCRIPT, PAGE_SHELL;
|
|
15141
15556
|
var init_template = __esm({
|
|
@@ -15413,8 +15828,8 @@ function configuredMarked() {
|
|
|
15413
15828
|
return marked;
|
|
15414
15829
|
}
|
|
15415
15830
|
function renderMarkdown(md, source) {
|
|
15416
|
-
const
|
|
15417
|
-
return typeof
|
|
15831
|
+
const out2 = md.parse(source, { async: false });
|
|
15832
|
+
return typeof out2 === "string" ? out2 : "";
|
|
15418
15833
|
}
|
|
15419
15834
|
function renderImage(part) {
|
|
15420
15835
|
const src = `data:${escapeHtml2(part.mimeType)};base64,${part.data}`;
|
|
@@ -15571,8 +15986,9 @@ var init_transcript_export = __esm({
|
|
|
15571
15986
|
|
|
15572
15987
|
// src/console/slash/commands/integrations.ts
|
|
15573
15988
|
import { spawnSync } from "node:child_process";
|
|
15574
|
-
import { writeFileSync as writeFileSync3 } from "node:fs";
|
|
15575
|
-
import {
|
|
15989
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
|
|
15990
|
+
import { homedir as homedir2 } from "node:os";
|
|
15991
|
+
import { join as join10, resolve as resolve5 } from "node:path";
|
|
15576
15992
|
import {
|
|
15577
15993
|
createMCPAgentToolFactory,
|
|
15578
15994
|
loadMCPConfig,
|
|
@@ -15631,13 +16047,13 @@ function exportTranscriptHtml(ctx, target) {
|
|
|
15631
16047
|
if (messages.length === 0) {
|
|
15632
16048
|
return { ok: false, reason: "Nothing to export yet \u2014 the transcript is empty." };
|
|
15633
16049
|
}
|
|
15634
|
-
const
|
|
16050
|
+
const path4 = target.length > 0 ? resolve5(process.cwd(), target) : defaultExportPath();
|
|
15635
16051
|
try {
|
|
15636
16052
|
const html = publishTranscript(toPublishEntries(messages), {
|
|
15637
16053
|
title: "Session Transcript"
|
|
15638
16054
|
});
|
|
15639
|
-
writeFileSync3(
|
|
15640
|
-
return { ok: true, path:
|
|
16055
|
+
writeFileSync3(path4, html, "utf-8");
|
|
16056
|
+
return { ok: true, path: path4 };
|
|
15641
16057
|
} catch (cause) {
|
|
15642
16058
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
15643
16059
|
return { ok: false, reason: `Could not write the HTML export: ${message}` };
|
|
@@ -15860,7 +16276,7 @@ function runShare(ctx) {
|
|
|
15860
16276
|
});
|
|
15861
16277
|
return HANDLED;
|
|
15862
16278
|
}
|
|
15863
|
-
function
|
|
16279
|
+
function runLogin2(ctx) {
|
|
15864
16280
|
const provider = ctx.args.trim().toLowerCase();
|
|
15865
16281
|
if (provider.length > 0) {
|
|
15866
16282
|
ctx.openModal("signIn", { providerId: provider });
|
|
@@ -15869,10 +16285,82 @@ function runLogin(ctx) {
|
|
|
15869
16285
|
}
|
|
15870
16286
|
return HANDLED;
|
|
15871
16287
|
}
|
|
16288
|
+
function hasLocalProviderKey(provider) {
|
|
16289
|
+
if (provider.length === 0) return false;
|
|
16290
|
+
try {
|
|
16291
|
+
const file = join10(homedir2(), ".indusagi", "agent", "auth.json");
|
|
16292
|
+
const vault = JSON.parse(readFileSync6(file, "utf8"));
|
|
16293
|
+
const entry = vault[provider];
|
|
16294
|
+
return entry !== null && typeof entry === "object" && Object.keys(entry).length > 0;
|
|
16295
|
+
} catch {
|
|
16296
|
+
return false;
|
|
16297
|
+
}
|
|
16298
|
+
}
|
|
16299
|
+
function runStatus(ctx) {
|
|
16300
|
+
const modelId = ctx.conductor.snapshot().modelId;
|
|
16301
|
+
const provider = modelId.includes("/") ? modelId.split("/")[0] : modelId;
|
|
16302
|
+
void (async () => {
|
|
16303
|
+
let signedIn = false;
|
|
16304
|
+
try {
|
|
16305
|
+
signedIn = await hasValidServerToken();
|
|
16306
|
+
} catch {
|
|
16307
|
+
signedIn = false;
|
|
16308
|
+
}
|
|
16309
|
+
const eligible = isGatewayEligibleProvider(provider);
|
|
16310
|
+
const localKey = hasLocalProviderKey(provider);
|
|
16311
|
+
const viaServer = signedIn && eligible && !localKey;
|
|
16312
|
+
if (viaServer) {
|
|
16313
|
+
ctx.setStatus(
|
|
16314
|
+
info(`\u25CF server tier \u2014 ${modelId} routing via ${INDUS_SERVER_URL} (signed in)`)
|
|
16315
|
+
);
|
|
16316
|
+
} else if (localKey) {
|
|
16317
|
+
ctx.setStatus(
|
|
16318
|
+
info(`\u25CB local key \u2014 ${modelId}${signedIn ? " (signed in to server)" : ""}`)
|
|
16319
|
+
);
|
|
16320
|
+
} else if (!signedIn) {
|
|
16321
|
+
ctx.setStatus(
|
|
16322
|
+
warn(`signed out \u2014 ${modelId} has no key. Run /login to use the server tier.`)
|
|
16323
|
+
);
|
|
16324
|
+
} else {
|
|
16325
|
+
ctx.setStatus(
|
|
16326
|
+
info(`signed in \u2014 ${modelId} (${provider} is not gateway-eligible; needs a local key)`)
|
|
16327
|
+
);
|
|
16328
|
+
}
|
|
16329
|
+
})();
|
|
16330
|
+
return HANDLED;
|
|
16331
|
+
}
|
|
16332
|
+
function runUsage(ctx) {
|
|
16333
|
+
void (async () => {
|
|
16334
|
+
const token = await getServerToken();
|
|
16335
|
+
if (!token?.access_token) {
|
|
16336
|
+
ctx.setStatus(warn("Not signed in to the server \u2014 run /login to use the server tier."));
|
|
16337
|
+
return;
|
|
16338
|
+
}
|
|
16339
|
+
try {
|
|
16340
|
+
const res = await fetch(`${INDUS_SERVER_URL}/api/usage`, {
|
|
16341
|
+
headers: { Authorization: `Bearer ${token.access_token}` }
|
|
16342
|
+
});
|
|
16343
|
+
if (!res.ok) {
|
|
16344
|
+
ctx.setStatus(warn(`Couldn't read usage (HTTP ${res.status}).`));
|
|
16345
|
+
return;
|
|
16346
|
+
}
|
|
16347
|
+
const u = await res.json();
|
|
16348
|
+
const pct = u.limit > 0 ? Math.round(u.used / u.limit * 100) : 0;
|
|
16349
|
+
const line = `Usage this month: ${u.used.toLocaleString()} / ${u.limit.toLocaleString()} tokens (${pct}%) \xB7 ${u.remaining.toLocaleString()} left \xB7 ${u.requests} reqs \xB7 $${(u.costUsd ?? 0).toFixed(4)}` + (u.allowed ? "" : " \xB7 LIMIT REACHED \u2014 requests are blocked");
|
|
16350
|
+
ctx.setStatus(u.allowed ? info(line) : warn(line));
|
|
16351
|
+
} catch (cause) {
|
|
16352
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
16353
|
+
ctx.setStatus(warn(`Usage check failed: ${message}`));
|
|
16354
|
+
}
|
|
16355
|
+
})();
|
|
16356
|
+
return HANDLED;
|
|
16357
|
+
}
|
|
15872
16358
|
var CLIPBOARD_WRITERS, PUBLISH_ROLES, mcpPool, mcpServers, memoryEnabled, MEMORY_SUBS, COMPOSIO_ENV_KEY, composioGateway, composioResolved, COMPOSIO_NO_KEY, COMPOSIO_SUBS, runMemory, runComposio, integrationCommands;
|
|
15873
16359
|
var init_integrations = __esm({
|
|
15874
16360
|
"src/console/slash/commands/integrations.ts"() {
|
|
15875
16361
|
"use strict";
|
|
16362
|
+
init_server_token();
|
|
16363
|
+
init_server_mode();
|
|
15876
16364
|
init_capability_deck();
|
|
15877
16365
|
init_transcript_export();
|
|
15878
16366
|
init_shared();
|
|
@@ -16064,17 +16552,31 @@ var init_integrations = __esm({
|
|
|
16064
16552
|
summary: "Sign in to a model provider.",
|
|
16065
16553
|
takesArgs: true,
|
|
16066
16554
|
run(ctx) {
|
|
16067
|
-
return
|
|
16555
|
+
return runLogin2(ctx);
|
|
16068
16556
|
}
|
|
16069
16557
|
},
|
|
16070
16558
|
{
|
|
16071
16559
|
name: "logout",
|
|
16072
|
-
summary: "Sign out
|
|
16560
|
+
summary: "Sign out: pick a provider account or the Indus Server session to clear.",
|
|
16073
16561
|
run(ctx) {
|
|
16074
16562
|
ctx.openModal("signOut");
|
|
16075
16563
|
return HANDLED;
|
|
16076
16564
|
}
|
|
16077
16565
|
},
|
|
16566
|
+
{
|
|
16567
|
+
name: "status",
|
|
16568
|
+
summary: "Show the server session and whether this model uses the server.",
|
|
16569
|
+
run(ctx) {
|
|
16570
|
+
return runStatus(ctx);
|
|
16571
|
+
}
|
|
16572
|
+
},
|
|
16573
|
+
{
|
|
16574
|
+
name: "usage",
|
|
16575
|
+
summary: "Show your server usage this month (tokens used / limit / cost).",
|
|
16576
|
+
run(ctx) {
|
|
16577
|
+
return runUsage(ctx);
|
|
16578
|
+
}
|
|
16579
|
+
},
|
|
16078
16580
|
{
|
|
16079
16581
|
name: "mcp",
|
|
16080
16582
|
summary: "Manage MCP servers and their tools.",
|
|
@@ -16199,19 +16701,19 @@ __export(builtins_exports, {
|
|
|
16199
16701
|
FAMILY: () => FAMILY,
|
|
16200
16702
|
SLASH_COMMANDS: () => SLASH_COMMANDS
|
|
16201
16703
|
});
|
|
16202
|
-
import { homedir as
|
|
16203
|
-
import { join as
|
|
16704
|
+
import { homedir as homedir3 } from "node:os";
|
|
16705
|
+
import { join as join11 } from "node:path";
|
|
16204
16706
|
function dynamicRoots() {
|
|
16205
|
-
const home =
|
|
16707
|
+
const home = homedir3();
|
|
16206
16708
|
const cwd = process.cwd();
|
|
16207
16709
|
return {
|
|
16208
16710
|
skills: [
|
|
16209
|
-
{ dir:
|
|
16210
|
-
{ dir:
|
|
16711
|
+
{ dir: join11(cwd, PROJECT_DIR, "skills"), origin: "project" },
|
|
16712
|
+
{ dir: join11(home, PROJECT_DIR, "skills"), origin: "user" }
|
|
16211
16713
|
],
|
|
16212
16714
|
macros: [
|
|
16213
|
-
{ dir:
|
|
16214
|
-
{ dir:
|
|
16715
|
+
{ dir: join11(cwd, PROJECT_DIR, "commands"), origin: "project", label: "project" },
|
|
16716
|
+
{ dir: join11(home, PROJECT_DIR, "commands"), origin: "user", label: "user" }
|
|
16215
16717
|
]
|
|
16216
16718
|
};
|
|
16217
16719
|
}
|
|
@@ -16274,7 +16776,7 @@ var init_builtins = __esm({
|
|
|
16274
16776
|
// src/entry.ts
|
|
16275
16777
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
16276
16778
|
import { realpathSync as realpathSync3 } from "node:fs";
|
|
16277
|
-
import { argv as processArgv, env } from "node:process";
|
|
16779
|
+
import { argv as processArgv, env as env2 } from "node:process";
|
|
16278
16780
|
|
|
16279
16781
|
// src/workspace/brand.ts
|
|
16280
16782
|
var BRAND = Object.freeze({
|
|
@@ -16289,7 +16791,7 @@ var BRAND = Object.freeze({
|
|
|
16289
16791
|
envShareViewer: "INDUSAGI_SHARE_VIEWER_URL",
|
|
16290
16792
|
shareViewerUrl: "https://buildwithindusagi.ai/session/"
|
|
16291
16793
|
});
|
|
16292
|
-
var VERSION = "0.2.
|
|
16794
|
+
var VERSION = "0.2.4";
|
|
16293
16795
|
|
|
16294
16796
|
// src/workspace/locator.ts
|
|
16295
16797
|
import { homedir } from "node:os";
|
|
@@ -16321,8 +16823,8 @@ var DIRECTORY_KEYS = [
|
|
|
16321
16823
|
"themesDir",
|
|
16322
16824
|
"exportTemplateDir"
|
|
16323
16825
|
];
|
|
16324
|
-
function resolveProfileRoot(brand, home, cwd,
|
|
16325
|
-
const override =
|
|
16826
|
+
function resolveProfileRoot(brand, home, cwd, env3) {
|
|
16827
|
+
const override = env3[brand.envProfileDir]?.trim();
|
|
16326
16828
|
if (override) {
|
|
16327
16829
|
return expandHome(override, home, cwd);
|
|
16328
16830
|
}
|
|
@@ -16344,8 +16846,8 @@ function createWorkspace(overrides = {}) {
|
|
|
16344
16846
|
const brand = overrides.brand ?? BRAND;
|
|
16345
16847
|
const home = overrides.home ?? homedir();
|
|
16346
16848
|
const cwd = overrides.cwd ?? process.cwd();
|
|
16347
|
-
const
|
|
16348
|
-
const profileRoot = resolveProfileRoot(brand, home, cwd,
|
|
16849
|
+
const env3 = overrides.env ?? process.env;
|
|
16850
|
+
const profileRoot = resolveProfileRoot(brand, home, cwd, env3);
|
|
16349
16851
|
const entries = Object.keys(LAYOUT).map((key) => {
|
|
16350
16852
|
const segments = LAYOUT[key];
|
|
16351
16853
|
const absolute = segments.length === 0 ? profileRoot : join(profileRoot, ...segments);
|
|
@@ -16730,6 +17232,12 @@ var FLAG_SPECS = [
|
|
|
16730
17232
|
group: "tools",
|
|
16731
17233
|
describe: "Attach an external MCP server endpoint (comma-separated or repeated)."
|
|
16732
17234
|
},
|
|
17235
|
+
{
|
|
17236
|
+
name: "--permission-mode",
|
|
17237
|
+
kind: "string",
|
|
17238
|
+
group: "tools",
|
|
17239
|
+
describe: "Open in the given permission mode: default, acceptEdits, plan, or bypass. On headless runs (--print/--json) `default` denies tools that would prompt."
|
|
17240
|
+
},
|
|
16733
17241
|
/* ---- Meta ------------------------------------------------------------ */
|
|
16734
17242
|
{
|
|
16735
17243
|
name: "--help",
|
|
@@ -16812,7 +17320,7 @@ function accumulateList(state, key, items) {
|
|
|
16812
17320
|
const base = Array.isArray(prior) ? prior : [];
|
|
16813
17321
|
state.flags[key] = [...base, ...items];
|
|
16814
17322
|
}
|
|
16815
|
-
function applyFlag(spec, inline,
|
|
17323
|
+
function applyFlag(spec, inline, argv2, i, state) {
|
|
16816
17324
|
const key = flagKey(spec.name);
|
|
16817
17325
|
if (spec.kind === "boolean") {
|
|
16818
17326
|
state.flags[key] = true;
|
|
@@ -16821,7 +17329,7 @@ function applyFlag(spec, inline, argv, i, state) {
|
|
|
16821
17329
|
let value = inline;
|
|
16822
17330
|
let consumed = i;
|
|
16823
17331
|
if (value === void 0) {
|
|
16824
|
-
const next =
|
|
17332
|
+
const next = argv2[i + 1];
|
|
16825
17333
|
if (next !== void 0 && !isFlagToken(next)) {
|
|
16826
17334
|
value = next;
|
|
16827
17335
|
consumed = i + 1;
|
|
@@ -16871,11 +17379,11 @@ function resolveTools(flags) {
|
|
|
16871
17379
|
if (raw === void 0) return void 0;
|
|
16872
17380
|
return raw.filter((name) => isToolName(name));
|
|
16873
17381
|
}
|
|
16874
|
-
function readInvocation(
|
|
17382
|
+
function readInvocation(argv2) {
|
|
16875
17383
|
const state = { flags: {}, positionals: [], fileRefs: [] };
|
|
16876
17384
|
let optionsTerminated = false;
|
|
16877
|
-
for (let i = 0; i <
|
|
16878
|
-
const token =
|
|
17385
|
+
for (let i = 0; i < argv2.length; i += 1) {
|
|
17386
|
+
const token = argv2[i];
|
|
16879
17387
|
if (optionsTerminated) {
|
|
16880
17388
|
pushPositional(state, token);
|
|
16881
17389
|
continue;
|
|
@@ -16895,7 +17403,7 @@ function readInvocation(argv) {
|
|
|
16895
17403
|
const { name, inline } = splitInline(token);
|
|
16896
17404
|
const spec = TOKEN_INDEX.get(name);
|
|
16897
17405
|
if (spec) {
|
|
16898
|
-
i = applyFlag(spec, inline,
|
|
17406
|
+
i = applyFlag(spec, inline, argv2, i, state);
|
|
16899
17407
|
continue;
|
|
16900
17408
|
}
|
|
16901
17409
|
if (isShortCluster(token) && applyShortCluster(token, state)) {
|
|
@@ -17044,11 +17552,11 @@ function writeSources(store, sources) {
|
|
|
17044
17552
|
function readSource(rest) {
|
|
17045
17553
|
return rest.find((token) => !token.startsWith("-"));
|
|
17046
17554
|
}
|
|
17047
|
-
async function runPackageCommand(
|
|
17048
|
-
const command = asPackageCommand(
|
|
17555
|
+
async function runPackageCommand(argv2, opts) {
|
|
17556
|
+
const command = asPackageCommand(argv2[0]);
|
|
17049
17557
|
if (command === void 0) return { handled: false };
|
|
17050
17558
|
const io = opts.io ?? defaultPackageIo();
|
|
17051
|
-
const rest =
|
|
17559
|
+
const rest = argv2.slice(1);
|
|
17052
17560
|
switch (command) {
|
|
17053
17561
|
case "install":
|
|
17054
17562
|
return doInstall(rest, opts.store, io);
|
|
@@ -17128,7 +17636,7 @@ function doConfig(store, io) {
|
|
|
17128
17636
|
}
|
|
17129
17637
|
|
|
17130
17638
|
// src/launch/credentials.ts
|
|
17131
|
-
import { createInterface } from "node:readline/promises";
|
|
17639
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
17132
17640
|
import { getEnvApiKey, getOAuthProvider as getOAuthProvider2 } from "indusagi/ai";
|
|
17133
17641
|
|
|
17134
17642
|
// src/launch/oauth.ts
|
|
@@ -17141,6 +17649,256 @@ import {
|
|
|
17141
17649
|
openaiCodexOAuthProvider,
|
|
17142
17650
|
registerOAuthProvider
|
|
17143
17651
|
} from "indusagi/ai";
|
|
17652
|
+
|
|
17653
|
+
// src/launch/login.ts
|
|
17654
|
+
init_server_token();
|
|
17655
|
+
import { createInterface } from "node:readline/promises";
|
|
17656
|
+
import chalk from "chalk";
|
|
17657
|
+
var INDUS_CLIENT_ID = process.env.INDUS_CLIENT_ID ?? "indus-cli";
|
|
17658
|
+
var USER_AGENT = "indus CLI";
|
|
17659
|
+
var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
17660
|
+
var DEVICE_SCOPE = "openid profile email";
|
|
17661
|
+
var EXIT_OK = 0;
|
|
17662
|
+
var EXIT_FAILURE = 1;
|
|
17663
|
+
var SERVER_TIER_PROVIDER_ID = "indus-server";
|
|
17664
|
+
var LoginError = class extends Error {
|
|
17665
|
+
};
|
|
17666
|
+
function out(line = "") {
|
|
17667
|
+
process.stdout.write(`${line}
|
|
17668
|
+
`);
|
|
17669
|
+
}
|
|
17670
|
+
function err(line) {
|
|
17671
|
+
process.stderr.write(`${line}
|
|
17672
|
+
`);
|
|
17673
|
+
}
|
|
17674
|
+
function sleep(ms) {
|
|
17675
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
17676
|
+
}
|
|
17677
|
+
async function postJson(url, body) {
|
|
17678
|
+
const res = await fetch(url, {
|
|
17679
|
+
method: "POST",
|
|
17680
|
+
headers: {
|
|
17681
|
+
"content-type": "application/json",
|
|
17682
|
+
accept: "application/json",
|
|
17683
|
+
"user-agent": USER_AGENT
|
|
17684
|
+
},
|
|
17685
|
+
body: JSON.stringify(body)
|
|
17686
|
+
});
|
|
17687
|
+
const data = await res.json().catch(() => ({}));
|
|
17688
|
+
return { status: res.status, data };
|
|
17689
|
+
}
|
|
17690
|
+
function parseLoginArgs(tail) {
|
|
17691
|
+
let serverUrl = INDUS_SERVER_URL;
|
|
17692
|
+
let clientId = INDUS_CLIENT_ID;
|
|
17693
|
+
for (let i = 0; i < tail.length; i++) {
|
|
17694
|
+
const token = tail[i];
|
|
17695
|
+
const eq = token.indexOf("=");
|
|
17696
|
+
const name = eq >= 0 ? token.slice(0, eq) : token;
|
|
17697
|
+
const inline = eq >= 0 ? token.slice(eq + 1) : void 0;
|
|
17698
|
+
const take = () => inline !== void 0 ? inline : tail[++i];
|
|
17699
|
+
if (name === "--server-url") {
|
|
17700
|
+
const value = take();
|
|
17701
|
+
if (value) serverUrl = value;
|
|
17702
|
+
} else if (name === "--client-id") {
|
|
17703
|
+
const value = take();
|
|
17704
|
+
if (value) clientId = value;
|
|
17705
|
+
}
|
|
17706
|
+
}
|
|
17707
|
+
return { serverUrl: serverUrl.replace(/\/+$/, ""), clientId };
|
|
17708
|
+
}
|
|
17709
|
+
async function confirm(prompt, defaultValue) {
|
|
17710
|
+
if (!process.stdin.isTTY) return defaultValue;
|
|
17711
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
17712
|
+
try {
|
|
17713
|
+
const hint = defaultValue ? "Y/n" : "y/N";
|
|
17714
|
+
const answer = (await rl.question(`${prompt} [${hint}] `)).trim().toLowerCase();
|
|
17715
|
+
if (answer === "") return defaultValue;
|
|
17716
|
+
return answer === "y" || answer === "yes";
|
|
17717
|
+
} finally {
|
|
17718
|
+
rl.close();
|
|
17719
|
+
}
|
|
17720
|
+
}
|
|
17721
|
+
async function requestDeviceCode(serverUrl, clientId) {
|
|
17722
|
+
const { status, data } = await postJson(`${serverUrl}/api/auth/device/code`, {
|
|
17723
|
+
client_id: clientId,
|
|
17724
|
+
scope: DEVICE_SCOPE
|
|
17725
|
+
});
|
|
17726
|
+
if (status >= 400 || typeof data.device_code !== "string") {
|
|
17727
|
+
const e = data;
|
|
17728
|
+
throw new LoginError(
|
|
17729
|
+
`Authorization request failed: ${e.error_description ?? e.error ?? e.message ?? `HTTP ${status}`}`
|
|
17730
|
+
);
|
|
17731
|
+
}
|
|
17732
|
+
return data;
|
|
17733
|
+
}
|
|
17734
|
+
async function pollForToken(serverUrl, clientId, device) {
|
|
17735
|
+
let intervalMs = Math.max(1, device.interval ?? 5) * 1e3;
|
|
17736
|
+
const deadline = Date.now() + device.expires_in * 1e3;
|
|
17737
|
+
while (Date.now() < deadline) {
|
|
17738
|
+
await sleep(intervalMs);
|
|
17739
|
+
const { data } = await postJson(`${serverUrl}/api/auth/device/token`, {
|
|
17740
|
+
grant_type: DEVICE_GRANT_TYPE,
|
|
17741
|
+
device_code: device.device_code,
|
|
17742
|
+
client_id: clientId
|
|
17743
|
+
});
|
|
17744
|
+
if (typeof data.access_token === "string") {
|
|
17745
|
+
return data;
|
|
17746
|
+
}
|
|
17747
|
+
const code = data.error;
|
|
17748
|
+
switch (code) {
|
|
17749
|
+
case "authorization_pending":
|
|
17750
|
+
case void 0:
|
|
17751
|
+
break;
|
|
17752
|
+
case "slow_down":
|
|
17753
|
+
intervalMs += 5e3;
|
|
17754
|
+
break;
|
|
17755
|
+
case "access_denied":
|
|
17756
|
+
throw new LoginError("Authorization was denied.");
|
|
17757
|
+
case "expired_token":
|
|
17758
|
+
throw new LoginError("Device code expired. Run `indus login` again.");
|
|
17759
|
+
default:
|
|
17760
|
+
throw new LoginError(
|
|
17761
|
+
`Authorization error: ${data.error_description ?? code}`
|
|
17762
|
+
);
|
|
17763
|
+
}
|
|
17764
|
+
}
|
|
17765
|
+
throw new LoginError("Timed out waiting for authorization. Run `indus login` again.");
|
|
17766
|
+
}
|
|
17767
|
+
async function runServerTierLogin(callbacks, serverUrl = INDUS_SERVER_URL, clientId = INDUS_CLIENT_ID) {
|
|
17768
|
+
const device = await requestDeviceCode(serverUrl, clientId);
|
|
17769
|
+
callbacks.onAuth({
|
|
17770
|
+
url: device.verification_uri_complete ?? device.verification_uri,
|
|
17771
|
+
instructions: `Enter code ${device.user_code} to authorize this device.`
|
|
17772
|
+
});
|
|
17773
|
+
callbacks.onProgress?.("Waiting for authorization...");
|
|
17774
|
+
const token = await pollForToken(serverUrl, clientId, device);
|
|
17775
|
+
await storeServerToken(token);
|
|
17776
|
+
callbacks.onProgress?.("Server sign-in complete.");
|
|
17777
|
+
}
|
|
17778
|
+
async function doLogin(args) {
|
|
17779
|
+
const { serverUrl, clientId } = args;
|
|
17780
|
+
out();
|
|
17781
|
+
out(chalk.bold.cyan(" indus login"));
|
|
17782
|
+
out(chalk.dim(` ${serverUrl}`));
|
|
17783
|
+
out();
|
|
17784
|
+
const existing = await getServerToken();
|
|
17785
|
+
if (existing && !isServerTokenExpired(existing)) {
|
|
17786
|
+
const again = await confirm(
|
|
17787
|
+
chalk.yellow("Already authenticated. Log in again?"),
|
|
17788
|
+
false
|
|
17789
|
+
);
|
|
17790
|
+
if (!again) {
|
|
17791
|
+
out(chalk.dim(" Login cancelled \u2014 existing session preserved."));
|
|
17792
|
+
return EXIT_OK;
|
|
17793
|
+
}
|
|
17794
|
+
}
|
|
17795
|
+
try {
|
|
17796
|
+
out(chalk.dim(" Requesting device authorization..."));
|
|
17797
|
+
const device = await requestDeviceCode(serverUrl, clientId);
|
|
17798
|
+
const url = device.verification_uri_complete ?? device.verification_uri;
|
|
17799
|
+
out();
|
|
17800
|
+
out(` ${chalk.bold("Open this URL to authorize:")}`);
|
|
17801
|
+
out(` ${chalk.green.underline(url)}`);
|
|
17802
|
+
out();
|
|
17803
|
+
out(` ${chalk.bold("Verification code:")} ${chalk.bold.cyan(device.user_code)}`);
|
|
17804
|
+
out(
|
|
17805
|
+
chalk.dim(
|
|
17806
|
+
` Expires in ${Math.max(1, Math.floor(device.expires_in / 60))} min \xB7 polling every ${Math.max(
|
|
17807
|
+
1,
|
|
17808
|
+
device.interval ?? 5
|
|
17809
|
+
)}s`
|
|
17810
|
+
)
|
|
17811
|
+
);
|
|
17812
|
+
out();
|
|
17813
|
+
out(chalk.dim(" Waiting for authorization..."));
|
|
17814
|
+
const token = await pollForToken(serverUrl, clientId, device);
|
|
17815
|
+
const saved = await storeServerToken(token);
|
|
17816
|
+
out();
|
|
17817
|
+
out(chalk.green.bold(" Authentication successful."));
|
|
17818
|
+
if (saved) {
|
|
17819
|
+
out(chalk.dim(` Token stored at ${TOKEN_FILE}`));
|
|
17820
|
+
} else {
|
|
17821
|
+
out(
|
|
17822
|
+
chalk.yellow(
|
|
17823
|
+
" Warning: could not write the token to disk \u2014 you may need to log in again."
|
|
17824
|
+
)
|
|
17825
|
+
);
|
|
17826
|
+
}
|
|
17827
|
+
out();
|
|
17828
|
+
return EXIT_OK;
|
|
17829
|
+
} catch (error) {
|
|
17830
|
+
const message = error instanceof LoginError ? error.message : error instanceof Error ? error.message : String(error);
|
|
17831
|
+
err("");
|
|
17832
|
+
err(chalk.red(` Login failed: ${message}`));
|
|
17833
|
+
err("");
|
|
17834
|
+
return EXIT_FAILURE;
|
|
17835
|
+
}
|
|
17836
|
+
}
|
|
17837
|
+
async function doLogout() {
|
|
17838
|
+
const cleared = await clearServerToken();
|
|
17839
|
+
if (cleared) {
|
|
17840
|
+
out(chalk.green(" Logged out \u2014 server session token removed."));
|
|
17841
|
+
} else {
|
|
17842
|
+
out(chalk.dim(" No stored session token to remove."));
|
|
17843
|
+
}
|
|
17844
|
+
return EXIT_OK;
|
|
17845
|
+
}
|
|
17846
|
+
async function doWhoami(args) {
|
|
17847
|
+
const token = await getServerToken();
|
|
17848
|
+
if (!token || isServerTokenExpired(token)) {
|
|
17849
|
+
err(chalk.yellow(" Not logged in. Run `indus login` first."));
|
|
17850
|
+
return EXIT_FAILURE;
|
|
17851
|
+
}
|
|
17852
|
+
try {
|
|
17853
|
+
const res = await fetch(`${args.serverUrl}/api/user/me`, {
|
|
17854
|
+
method: "GET",
|
|
17855
|
+
headers: {
|
|
17856
|
+
authorization: `Bearer ${token.access_token}`,
|
|
17857
|
+
accept: "application/json",
|
|
17858
|
+
"user-agent": USER_AGENT
|
|
17859
|
+
}
|
|
17860
|
+
});
|
|
17861
|
+
if (res.status === 401) {
|
|
17862
|
+
err(chalk.yellow(" Session expired or invalid. Run `indus login` again."));
|
|
17863
|
+
return EXIT_FAILURE;
|
|
17864
|
+
}
|
|
17865
|
+
if (!res.ok) {
|
|
17866
|
+
err(chalk.red(` Could not fetch account: HTTP ${res.status}`));
|
|
17867
|
+
return EXIT_FAILURE;
|
|
17868
|
+
}
|
|
17869
|
+
const user = await res.json();
|
|
17870
|
+
out();
|
|
17871
|
+
out(chalk.bold(" Signed in as:"));
|
|
17872
|
+
out(` ${chalk.bold(user.name || user.email)} ${chalk.dim(`<${user.email}>`)}`);
|
|
17873
|
+
out(` ${chalk.dim("plan:")} ${user.plan}`);
|
|
17874
|
+
out(
|
|
17875
|
+
` ${chalk.dim("monthly token limit:")} ${user.monthlyTokenLimit.toLocaleString()}`
|
|
17876
|
+
);
|
|
17877
|
+
out();
|
|
17878
|
+
return EXIT_OK;
|
|
17879
|
+
} catch (error) {
|
|
17880
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17881
|
+
err(chalk.red(` Could not reach the server: ${message}`));
|
|
17882
|
+
return EXIT_FAILURE;
|
|
17883
|
+
}
|
|
17884
|
+
}
|
|
17885
|
+
async function runLogin(ctx) {
|
|
17886
|
+
const verb = ctx.argv[0];
|
|
17887
|
+
if (verb !== "login" && verb !== "logout" && verb !== "whoami") {
|
|
17888
|
+
return void 0;
|
|
17889
|
+
}
|
|
17890
|
+
const args = parseLoginArgs(ctx.argv.slice(1));
|
|
17891
|
+
switch (verb) {
|
|
17892
|
+
case "login":
|
|
17893
|
+
return doLogin(args);
|
|
17894
|
+
case "logout":
|
|
17895
|
+
return doLogout();
|
|
17896
|
+
case "whoami":
|
|
17897
|
+
return doWhoami(args);
|
|
17898
|
+
}
|
|
17899
|
+
}
|
|
17900
|
+
|
|
17901
|
+
// src/launch/oauth.ts
|
|
17144
17902
|
var BUILT_IN_OAUTH = [
|
|
17145
17903
|
{ provider: anthropicOAuthProvider, label: "Anthropic (Claude sign-in)" },
|
|
17146
17904
|
{ provider: openaiCodexOAuthProvider, label: "OpenAI (ChatGPT sign-in)" },
|
|
@@ -17182,6 +17940,11 @@ function oauthClientIdEnvVar(providerId) {
|
|
|
17182
17940
|
return OAUTH_CLIENT_ID_WIRING[providerId]?.envVar;
|
|
17183
17941
|
}
|
|
17184
17942
|
function listLoginProviders() {
|
|
17943
|
+
const serverTier = {
|
|
17944
|
+
id: SERVER_TIER_PROVIDER_ID,
|
|
17945
|
+
label: "Indus Server (sign in for server-tier model access)",
|
|
17946
|
+
authKind: "oauth"
|
|
17947
|
+
};
|
|
17185
17948
|
const oauth = getOAuthProviders().map((provider) => ({
|
|
17186
17949
|
id: provider.id,
|
|
17187
17950
|
label: OAUTH_LABELS[provider.id] ?? provider.name,
|
|
@@ -17192,7 +17955,7 @@ function listLoginProviders() {
|
|
|
17192
17955
|
label: entry.label,
|
|
17193
17956
|
authKind: "apiKey"
|
|
17194
17957
|
}));
|
|
17195
|
-
return [...oauth, ...apiKey];
|
|
17958
|
+
return [serverTier, ...oauth, ...apiKey];
|
|
17196
17959
|
}
|
|
17197
17960
|
function isWebUrl(url) {
|
|
17198
17961
|
try {
|
|
@@ -17248,6 +18011,10 @@ function openLoginUrl(url) {
|
|
|
17248
18011
|
return tryAt(0);
|
|
17249
18012
|
}
|
|
17250
18013
|
async function startOAuthLogin(providerId, callbacks, vault, account = "default") {
|
|
18014
|
+
if (providerId === SERVER_TIER_PROVIDER_ID) {
|
|
18015
|
+
await runServerTierLogin(callbacks);
|
|
18016
|
+
return { provider: providerId, account, madeDefault: true };
|
|
18017
|
+
}
|
|
17251
18018
|
const provider = getOAuthProvider(providerId);
|
|
17252
18019
|
if (provider === void 0) {
|
|
17253
18020
|
throw new Error(`No browser sign-in is available for "${providerId}".`);
|
|
@@ -17271,7 +18038,7 @@ function defaultCredentialIo() {
|
|
|
17271
18038
|
process.stdout.write(line.endsWith("\n") ? line : line + "\n");
|
|
17272
18039
|
},
|
|
17273
18040
|
async ask(prompt) {
|
|
17274
|
-
const rl =
|
|
18041
|
+
const rl = createInterface2({
|
|
17275
18042
|
input: process.stdin,
|
|
17276
18043
|
output: process.stdout
|
|
17277
18044
|
});
|
|
@@ -17282,14 +18049,14 @@ function defaultCredentialIo() {
|
|
|
17282
18049
|
}
|
|
17283
18050
|
},
|
|
17284
18051
|
async askSecret(prompt) {
|
|
17285
|
-
const rl =
|
|
18052
|
+
const rl = createInterface2({
|
|
17286
18053
|
input: process.stdin,
|
|
17287
18054
|
output: process.stdout
|
|
17288
18055
|
});
|
|
17289
|
-
const
|
|
18056
|
+
const out2 = process.stdout;
|
|
17290
18057
|
let muted = false;
|
|
17291
|
-
const original =
|
|
17292
|
-
|
|
18058
|
+
const original = out2.write.bind(out2);
|
|
18059
|
+
out2.write = ((chunk, ...args) => {
|
|
17293
18060
|
if (muted && typeof chunk === "string") return true;
|
|
17294
18061
|
return original(chunk, ...args);
|
|
17295
18062
|
});
|
|
@@ -17300,8 +18067,8 @@ function defaultCredentialIo() {
|
|
|
17300
18067
|
return value.trim();
|
|
17301
18068
|
} finally {
|
|
17302
18069
|
muted = false;
|
|
17303
|
-
|
|
17304
|
-
|
|
18070
|
+
out2.write = original;
|
|
18071
|
+
out2.write("\n");
|
|
17305
18072
|
rl.close();
|
|
17306
18073
|
}
|
|
17307
18074
|
}
|
|
@@ -17465,15 +18232,15 @@ function validateAccountName(name) {
|
|
|
17465
18232
|
}
|
|
17466
18233
|
var DEFAULT_ACCOUNT = "default";
|
|
17467
18234
|
function asVerb(token) {
|
|
17468
|
-
if (token === "signin"
|
|
17469
|
-
if (token === "signout"
|
|
18235
|
+
if (token === "signin") return "signin";
|
|
18236
|
+
if (token === "signout") return "signout";
|
|
17470
18237
|
return void 0;
|
|
17471
18238
|
}
|
|
17472
|
-
async function runCredentialCommand(
|
|
17473
|
-
const verb = asVerb(
|
|
18239
|
+
async function runCredentialCommand(argv2, opts) {
|
|
18240
|
+
const verb = asVerb(argv2[0]);
|
|
17474
18241
|
if (verb === void 0) return { handled: false };
|
|
17475
18242
|
const io = opts.io ?? defaultCredentialIo();
|
|
17476
|
-
const rest =
|
|
18243
|
+
const rest = argv2.slice(1);
|
|
17477
18244
|
const { provider: namedProvider, account, method, list } = readVerbFlags(rest);
|
|
17478
18245
|
if (verb === "signin" && list) {
|
|
17479
18246
|
try {
|
|
@@ -17877,7 +18644,7 @@ function printModelCatalog(io = defaultCatalogIo(), filter = {}, source = regist
|
|
|
17877
18644
|
}
|
|
17878
18645
|
|
|
17879
18646
|
// src/launch/pickers.ts
|
|
17880
|
-
import { createInterface as
|
|
18647
|
+
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
17881
18648
|
import { createElement } from "indusagi/react-host";
|
|
17882
18649
|
import { render } from "indusagi/react-host/ink";
|
|
17883
18650
|
import { StartupSessionPicker } from "indusagi/react-ink";
|
|
@@ -17997,8 +18764,8 @@ function projectInvocation(launch) {
|
|
|
17997
18764
|
rest: launch.positionals
|
|
17998
18765
|
};
|
|
17999
18766
|
}
|
|
18000
|
-
function tokenizeInvocation(
|
|
18001
|
-
return projectInvocation(readInvocation(
|
|
18767
|
+
function tokenizeInvocation(argv2) {
|
|
18768
|
+
return projectInvocation(readInvocation(argv2));
|
|
18002
18769
|
}
|
|
18003
18770
|
function wantsHelp(inv) {
|
|
18004
18771
|
return inv.flags.help === true;
|
|
@@ -18180,6 +18947,14 @@ function consoleReducer(state, event) {
|
|
|
18180
18947
|
return setBuffer(state, event.text);
|
|
18181
18948
|
case "buffer:insert":
|
|
18182
18949
|
return insertBuffer(state, event.text);
|
|
18950
|
+
case "buffer:replaceSpan": {
|
|
18951
|
+
const at = state.buffer.indexOf(event.find);
|
|
18952
|
+
if (at < 0) return state;
|
|
18953
|
+
const buffer = state.buffer.slice(0, at) + event.replaceWith + state.buffer.slice(at + event.find.length);
|
|
18954
|
+
const spanEnd = at + event.find.length;
|
|
18955
|
+
const caret = state.caret >= spanEnd ? state.caret + (event.replaceWith.length - event.find.length) : state.caret > at ? at + event.replaceWith.length : state.caret;
|
|
18956
|
+
return { ...state, buffer, caret: clamp(caret, buffer.length) };
|
|
18957
|
+
}
|
|
18183
18958
|
case "buffer:erasePrev":
|
|
18184
18959
|
return erasePrev(state);
|
|
18185
18960
|
case "buffer:eraseNext":
|
|
@@ -18483,7 +19258,8 @@ var DEFAULT_SLASH_REGISTRY = buildRegistry(SLASH_COMMANDS);
|
|
|
18483
19258
|
// src/console/input/keymap.ts
|
|
18484
19259
|
var NO_INTENT = { verb: "none" };
|
|
18485
19260
|
function typed(text) {
|
|
18486
|
-
|
|
19261
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
19262
|
+
return normalized.length === 0 ? NO_INTENT : { verb: "text:type", text: normalized };
|
|
18487
19263
|
}
|
|
18488
19264
|
function isPrintable(input) {
|
|
18489
19265
|
if (input.length === 0) return false;
|
|
@@ -18518,6 +19294,8 @@ function readKey(input, key) {
|
|
|
18518
19294
|
return { verb: "input:externalEditor" };
|
|
18519
19295
|
case "r":
|
|
18520
19296
|
return { verb: "overlay:open", overlay: "sessions" };
|
|
19297
|
+
case "x":
|
|
19298
|
+
return { verb: "queue:steer" };
|
|
18521
19299
|
case "l":
|
|
18522
19300
|
return { verb: "overlay:open", overlay: "models" };
|
|
18523
19301
|
case "o":
|
|
@@ -18560,7 +19338,10 @@ function advanceChord(latch, intent) {
|
|
|
18560
19338
|
}
|
|
18561
19339
|
|
|
18562
19340
|
// src/console/input/paste.ts
|
|
18563
|
-
var PASTE_THRESHOLDS = { lines:
|
|
19341
|
+
var PASTE_THRESHOLDS = { lines: 10, chars: 1001 };
|
|
19342
|
+
var PASTE_BURST_GAP_MS = 24;
|
|
19343
|
+
var PASTE_CONTINUATION_MS = 250;
|
|
19344
|
+
var PASTE_MARKER_LINE_CAP = 1e3;
|
|
18564
19345
|
function pasteMarker(ordinal, lineCount) {
|
|
18565
19346
|
return `[Pasted text #${ordinal}${lineCount > 0 ? ` +${lineCount} lines` : ""}]`;
|
|
18566
19347
|
}
|
|
@@ -18588,6 +19369,19 @@ function coalescePaste(body, vault = EMPTY_PASTE_VAULT) {
|
|
|
18588
19369
|
bodies.set(ordinal, body);
|
|
18589
19370
|
return { marker, vault: { bodies, minted: ordinal } };
|
|
18590
19371
|
}
|
|
19372
|
+
function appendToPaste(ordinal, extra, vault) {
|
|
19373
|
+
const body = (vault.bodies.get(ordinal) ?? "") + extra;
|
|
19374
|
+
const lineCount = body.length === 0 ? 0 : lineBreaks(body) + 1;
|
|
19375
|
+
const marker = pasteMarker(ordinal, lineCount);
|
|
19376
|
+
const bodies = new Map(vault.bodies);
|
|
19377
|
+
bodies.set(ordinal, body);
|
|
19378
|
+
return { marker, vault: { bodies, minted: vault.minted } };
|
|
19379
|
+
}
|
|
19380
|
+
function pasteLines(vault, ordinal) {
|
|
19381
|
+
const body = vault.bodies.get(ordinal);
|
|
19382
|
+
if (body === void 0 || body.length === 0) return 0;
|
|
19383
|
+
return lineBreaks(body) + 1;
|
|
19384
|
+
}
|
|
18591
19385
|
function expandMarkers(buffer, vault) {
|
|
18592
19386
|
if (vault.bodies.size === 0) return buffer;
|
|
18593
19387
|
return buffer.replace(markerScanner(), (_match, ordinalStr) => {
|
|
@@ -18709,10 +19503,11 @@ function createDirReader(cwd = process.cwd()) {
|
|
|
18709
19503
|
|
|
18710
19504
|
// src/console/components/TerminalConsole.tsx
|
|
18711
19505
|
init_workflow_engine();
|
|
19506
|
+
init_window_budget();
|
|
18712
19507
|
import { execFileSync } from "node:child_process";
|
|
18713
|
-
import { homedir as
|
|
18714
|
-
import React3, { useEffect as
|
|
18715
|
-
import { Box as Box10, useInput as useInput3 } from "indusagi/react-host/ink";
|
|
19508
|
+
import { homedir as homedir7 } from "node:os";
|
|
19509
|
+
import React3, { useEffect as useEffect7, useMemo as useMemo2, useState as useState8 } from "indusagi/react-host";
|
|
19510
|
+
import { Box as Box10, Text as Text10, useInput as useInput3 } from "indusagi/react-host/ink";
|
|
18716
19511
|
import {
|
|
18717
19512
|
MessageList,
|
|
18718
19513
|
StreamingMarkdown,
|
|
@@ -18720,7 +19515,7 @@ import {
|
|
|
18720
19515
|
} from "indusagi/react-ink";
|
|
18721
19516
|
|
|
18722
19517
|
// src/console/components/Banner.tsx
|
|
18723
|
-
import { homedir as
|
|
19518
|
+
import { homedir as homedir4 } from "node:os";
|
|
18724
19519
|
import { basename as basename4 } from "node:path";
|
|
18725
19520
|
import { Box, Text } from "indusagi/react-host/ink";
|
|
18726
19521
|
import { ChangelogBlock } from "indusagi/react-ink";
|
|
@@ -18763,9 +19558,9 @@ var TIPS = [
|
|
|
18763
19558
|
"Use /skills to discover specialized helpers for the task at hand"
|
|
18764
19559
|
];
|
|
18765
19560
|
var WHATS_NEW = [
|
|
18766
|
-
"
|
|
18767
|
-
"
|
|
18768
|
-
"
|
|
19561
|
+
"Ctrl+X runs your newest queued message NOW \u2014 the current run stops cleanly",
|
|
19562
|
+
"/compact shows live progress, resets to a fresh screen, and lists carried files",
|
|
19563
|
+
'"Allow always" is remembered for the session; sub-agents respect your permission mode'
|
|
18769
19564
|
];
|
|
18770
19565
|
function wrapIndex(seed, len) {
|
|
18771
19566
|
if (len <= 0) return 0;
|
|
@@ -18894,7 +19689,7 @@ function Mascot({
|
|
|
18894
19689
|
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", alignItems: "center", marginY: 1, children: mascotRows(face).map((row, rowIndex) => /* @__PURE__ */ jsx(Box, { children: row.map((seg, segIndex) => /* @__PURE__ */ jsx(Text, { children: paintMascot(theme, seg.tone, seg.text) }, segIndex)) }, rowIndex)) });
|
|
18895
19690
|
}
|
|
18896
19691
|
function shortenWorkspace(workspace) {
|
|
18897
|
-
const home =
|
|
19692
|
+
const home = homedir4();
|
|
18898
19693
|
if (home.length > 0 && workspace.startsWith(home)) {
|
|
18899
19694
|
return `~${workspace.slice(home.length)}`;
|
|
18900
19695
|
}
|
|
@@ -19034,6 +19829,43 @@ function Banner({
|
|
|
19034
19829
|
] });
|
|
19035
19830
|
}
|
|
19036
19831
|
|
|
19832
|
+
// src/console/auth-status.ts
|
|
19833
|
+
init_server_token();
|
|
19834
|
+
init_server_mode();
|
|
19835
|
+
import { useEffect, useState } from "indusagi/react-host";
|
|
19836
|
+
function useAuthenticatedProviders(services, refreshKey) {
|
|
19837
|
+
const [authed, setAuthed] = useState(null);
|
|
19838
|
+
useEffect(() => {
|
|
19839
|
+
if (!services) return;
|
|
19840
|
+
let live = true;
|
|
19841
|
+
void (async () => {
|
|
19842
|
+
const found = /* @__PURE__ */ new Set();
|
|
19843
|
+
try {
|
|
19844
|
+
for (const provider of services.listLoginProviders()) {
|
|
19845
|
+
try {
|
|
19846
|
+
if ((await services.vault.listAccounts(provider.id)).length > 0) {
|
|
19847
|
+
found.add(provider.id);
|
|
19848
|
+
}
|
|
19849
|
+
} catch {
|
|
19850
|
+
}
|
|
19851
|
+
}
|
|
19852
|
+
} catch {
|
|
19853
|
+
}
|
|
19854
|
+
try {
|
|
19855
|
+
if (await hasValidServerToken()) {
|
|
19856
|
+
for (const provider of serverTierProviders()) found.add(provider);
|
|
19857
|
+
}
|
|
19858
|
+
} catch {
|
|
19859
|
+
}
|
|
19860
|
+
if (live) setAuthed(found);
|
|
19861
|
+
})();
|
|
19862
|
+
return () => {
|
|
19863
|
+
live = false;
|
|
19864
|
+
};
|
|
19865
|
+
}, [refreshKey]);
|
|
19866
|
+
return authed;
|
|
19867
|
+
}
|
|
19868
|
+
|
|
19037
19869
|
// src/console/components/BackgroundAgents.tsx
|
|
19038
19870
|
import { Box as Box2, Text as Text2 } from "indusagi/react-host/ink";
|
|
19039
19871
|
import { splitAssistantMessage } from "indusagi/react-ink";
|
|
@@ -19128,7 +19960,7 @@ function BackgroundAgents({ theme, runs, tokens, now }) {
|
|
|
19128
19960
|
}
|
|
19129
19961
|
|
|
19130
19962
|
// src/console/components/AgentsView.tsx
|
|
19131
|
-
import { useState } from "indusagi/react-host";
|
|
19963
|
+
import { useState as useState2 } from "indusagi/react-host";
|
|
19132
19964
|
import { Box as Box3, Text as Text3, useInput } from "indusagi/react-host/ink";
|
|
19133
19965
|
import { wrapSelectionIndex } from "indusagi/react-ink";
|
|
19134
19966
|
import { jsx as jsx3, jsxs as jsxs3 } from "indusagi/react-host/jsx-runtime";
|
|
@@ -19172,7 +20004,7 @@ function ActivityRow({
|
|
|
19172
20004
|
}
|
|
19173
20005
|
function AgentsView({ theme, runs, activity, tokens, now, onExit }) {
|
|
19174
20006
|
const clock = now ?? Date.now();
|
|
19175
|
-
const [selectedIndex, setSelectedIndex] =
|
|
20007
|
+
const [selectedIndex, setSelectedIndex] = useState2(runs.length > 0 ? 1 : 0);
|
|
19176
20008
|
const rowCount = runs.length + 1;
|
|
19177
20009
|
const index = Math.min(selectedIndex, rowCount - 1);
|
|
19178
20010
|
const viewed = index > 0 ? runs[index - 1] : void 0;
|
|
@@ -19343,7 +20175,7 @@ function StatusBar({
|
|
|
19343
20175
|
}
|
|
19344
20176
|
|
|
19345
20177
|
// src/console/components/WorkingIndicator.tsx
|
|
19346
|
-
import React, { useEffect, useState as
|
|
20178
|
+
import React, { useEffect as useEffect2, useState as useState3 } from "indusagi/react-host";
|
|
19347
20179
|
import { Box as Box6, Text as Text6 } from "indusagi/react-host/ink";
|
|
19348
20180
|
import { jsx as jsx6, jsxs as jsxs6 } from "indusagi/react-host/jsx-runtime";
|
|
19349
20181
|
var { useRef } = React;
|
|
@@ -19401,10 +20233,10 @@ function WorkingIndicator({
|
|
|
19401
20233
|
busy,
|
|
19402
20234
|
phase
|
|
19403
20235
|
}) {
|
|
19404
|
-
const [frame, setFrame] =
|
|
20236
|
+
const [frame, setFrame] = useState3(0);
|
|
19405
20237
|
const startRef = useRef(null);
|
|
19406
20238
|
const wordOffsetRef = useRef(0);
|
|
19407
|
-
|
|
20239
|
+
useEffect2(() => {
|
|
19408
20240
|
if (!busy) {
|
|
19409
20241
|
startRef.current = null;
|
|
19410
20242
|
return;
|
|
@@ -19439,7 +20271,7 @@ var APPROVAL_CHOICES = [
|
|
|
19439
20271
|
{
|
|
19440
20272
|
id: "allow-always",
|
|
19441
20273
|
label: "Allow always",
|
|
19442
|
-
description: "run it and remember
|
|
20274
|
+
description: "run it and remember this action for the session"
|
|
19443
20275
|
},
|
|
19444
20276
|
{ id: "deny", label: "Deny", description: "block this call" }
|
|
19445
20277
|
];
|
|
@@ -19541,7 +20373,8 @@ function ApprovalOverlays(props) {
|
|
|
19541
20373
|
}
|
|
19542
20374
|
|
|
19543
20375
|
// src/console/overlays/auth.tsx
|
|
19544
|
-
|
|
20376
|
+
init_server_token();
|
|
20377
|
+
import React2, { useEffect as useEffect3, useState as useState4 } from "indusagi/react-host";
|
|
19545
20378
|
import { Box as Box8, Text as Text8 } from "indusagi/react-host/ink";
|
|
19546
20379
|
import {
|
|
19547
20380
|
DialogFrame,
|
|
@@ -19564,7 +20397,7 @@ function SignInDialog(props) {
|
|
|
19564
20397
|
}
|
|
19565
20398
|
})();
|
|
19566
20399
|
const direct = requestedProvider !== void 0 ? providers.find((p) => p.id === requestedProvider) : void 0;
|
|
19567
|
-
|
|
20400
|
+
useEffect3(() => {
|
|
19568
20401
|
if (direct === void 0) return;
|
|
19569
20402
|
dispatch2({
|
|
19570
20403
|
type: "modal:open",
|
|
@@ -19595,13 +20428,25 @@ function SignInDialog(props) {
|
|
|
19595
20428
|
}
|
|
19596
20429
|
);
|
|
19597
20430
|
}
|
|
20431
|
+
var SERVER_TIER_ACCOUNT_ID = "server-session";
|
|
19598
20432
|
function SignOutDialog(props) {
|
|
19599
20433
|
const { services, closeModal } = props;
|
|
19600
|
-
const [accounts, setAccounts] =
|
|
19601
|
-
|
|
20434
|
+
const [accounts, setAccounts] = useState4([]);
|
|
20435
|
+
useEffect3(() => {
|
|
19602
20436
|
let live = true;
|
|
19603
20437
|
void (async () => {
|
|
19604
20438
|
const rows = [];
|
|
20439
|
+
try {
|
|
20440
|
+
const token = await getServerToken();
|
|
20441
|
+
if (token) {
|
|
20442
|
+
rows.push({
|
|
20443
|
+
provider: SERVER_TIER_PROVIDER_ID,
|
|
20444
|
+
accountId: SERVER_TIER_ACCOUNT_ID,
|
|
20445
|
+
label: "Indus Server \xB7 signed in"
|
|
20446
|
+
});
|
|
20447
|
+
}
|
|
20448
|
+
} catch {
|
|
20449
|
+
}
|
|
19605
20450
|
try {
|
|
19606
20451
|
for (const provider of services.listLoginProviders()) {
|
|
19607
20452
|
let names = [];
|
|
@@ -19634,7 +20479,11 @@ function SignOutDialog(props) {
|
|
|
19634
20479
|
onClose: closeModal,
|
|
19635
20480
|
onSelect: async (account) => {
|
|
19636
20481
|
try {
|
|
19637
|
-
|
|
20482
|
+
if (account.provider === SERVER_TIER_PROVIDER_ID) {
|
|
20483
|
+
await clearServerToken();
|
|
20484
|
+
} else {
|
|
20485
|
+
await services.vault.remove(account.provider, account.accountId);
|
|
20486
|
+
}
|
|
19638
20487
|
} catch {
|
|
19639
20488
|
}
|
|
19640
20489
|
closeModal();
|
|
@@ -19672,12 +20521,12 @@ function OAuthFlowDialog(props) {
|
|
|
19672
20521
|
return providerId;
|
|
19673
20522
|
}
|
|
19674
20523
|
})();
|
|
19675
|
-
const [state, setState] =
|
|
20524
|
+
const [state, setState] = useState4(
|
|
19676
20525
|
() => seedOAuthState(providerId, providerName, mode)
|
|
19677
20526
|
);
|
|
19678
20527
|
const pending = useRef2(null);
|
|
19679
20528
|
const merge = (next) => setState((prev) => ({ ...prev, ...next }));
|
|
19680
|
-
|
|
20529
|
+
useEffect3(() => {
|
|
19681
20530
|
if (mode !== "oauth") return;
|
|
19682
20531
|
let live = true;
|
|
19683
20532
|
const safeMerge = (next) => {
|
|
@@ -19715,6 +20564,7 @@ function OAuthFlowDialog(props) {
|
|
|
19715
20564
|
void (async () => {
|
|
19716
20565
|
try {
|
|
19717
20566
|
await services.startOAuthLogin(providerId, callbacks, services.vault);
|
|
20567
|
+
await services.refreshGatewayRouting();
|
|
19718
20568
|
selectProviderModel(services, providerId);
|
|
19719
20569
|
if (live) {
|
|
19720
20570
|
dispatch2({
|
|
@@ -19858,21 +20708,47 @@ function readEntryMode(payload) {
|
|
|
19858
20708
|
}
|
|
19859
20709
|
|
|
19860
20710
|
// src/console/overlays/pickers.tsx
|
|
19861
|
-
import { useEffect as
|
|
20711
|
+
import { useEffect as useEffect5, useState as useState6 } from "indusagi/react-host";
|
|
19862
20712
|
import {
|
|
19863
20713
|
ScopedModelsDialog,
|
|
19864
20714
|
ThemeDialog as ThemeDialog2
|
|
19865
20715
|
} from "indusagi/react-ink";
|
|
19866
20716
|
|
|
19867
20717
|
// src/console/overlays/boards.tsx
|
|
19868
|
-
|
|
19869
|
-
import
|
|
20718
|
+
init_server_mode();
|
|
20719
|
+
import chalk2 from "chalk";
|
|
20720
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
20721
|
+
import { homedir as homedir5 } from "node:os";
|
|
20722
|
+
import { join as join12 } from "node:path";
|
|
20723
|
+
import { useEffect as useEffect4, useMemo, useState as useState5 } from "indusagi/react-host";
|
|
19870
20724
|
import { Box as Box9, Text as Text9, useInput as useInput2 } from "indusagi/react-host/ink";
|
|
19871
20725
|
import {
|
|
19872
20726
|
matchesSearchQuery,
|
|
19873
20727
|
wrapSelectionIndex as wrapSelectionIndex2
|
|
19874
20728
|
} from "indusagi/react-ink";
|
|
19875
20729
|
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "indusagi/react-host/jsx-runtime";
|
|
20730
|
+
function readServerTierInfo() {
|
|
20731
|
+
let signedIn = false;
|
|
20732
|
+
try {
|
|
20733
|
+
const file = join12(homedir5(), ".indusagi", "agent", "server-token.json");
|
|
20734
|
+
const token = JSON.parse(readFileSync7(file, "utf8"));
|
|
20735
|
+
signedIn = typeof token.expires_at === "string" && new Date(token.expires_at).getTime() - Date.now() > 5 * 60 * 1e3;
|
|
20736
|
+
} catch {
|
|
20737
|
+
signedIn = false;
|
|
20738
|
+
}
|
|
20739
|
+
const localKeys = /* @__PURE__ */ new Set();
|
|
20740
|
+
try {
|
|
20741
|
+
const file = join12(homedir5(), ".indusagi", "agent", "auth.json");
|
|
20742
|
+
const vault = JSON.parse(readFileSync7(file, "utf8"));
|
|
20743
|
+
for (const [provider, entry] of Object.entries(vault)) {
|
|
20744
|
+
if (entry !== null && typeof entry === "object" && Object.keys(entry).length > 0) {
|
|
20745
|
+
localKeys.add(provider);
|
|
20746
|
+
}
|
|
20747
|
+
}
|
|
20748
|
+
} catch {
|
|
20749
|
+
}
|
|
20750
|
+
return { signedIn, localKeys };
|
|
20751
|
+
}
|
|
19876
20752
|
function truncate(text, width) {
|
|
19877
20753
|
if (text.length <= width) return text;
|
|
19878
20754
|
if (width <= 1) return text.slice(0, width);
|
|
@@ -19881,7 +20757,7 @@ function truncate(text, width) {
|
|
|
19881
20757
|
function tabPill(theme, text) {
|
|
19882
20758
|
const accent = theme.colors["accent"] ?? "#f7a23f";
|
|
19883
20759
|
try {
|
|
19884
|
-
return
|
|
20760
|
+
return chalk2.bgHex(accent).hex("#1a120a").bold(` ${text} `);
|
|
19885
20761
|
} catch {
|
|
19886
20762
|
return theme.color("accent", text);
|
|
19887
20763
|
}
|
|
@@ -19990,16 +20866,16 @@ function nextValue(values, current, direction) {
|
|
|
19990
20866
|
return values[(at + direction + values.length) % values.length];
|
|
19991
20867
|
}
|
|
19992
20868
|
function SettingsBoard({ theme, items, onClose }) {
|
|
19993
|
-
const [query, setQuery] =
|
|
19994
|
-
const [selectedIndex, setSelectedIndex] =
|
|
20869
|
+
const [query, setQuery] = useState5("");
|
|
20870
|
+
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
19995
20871
|
const filtered = useMemo(
|
|
19996
20872
|
() => items.filter(
|
|
19997
20873
|
(item) => matchesSearchQuery(`${item.label} ${item.description} ${item.value} ${item.values.join(" ")}`, query)
|
|
19998
20874
|
),
|
|
19999
20875
|
[items, query]
|
|
20000
20876
|
);
|
|
20001
|
-
|
|
20002
|
-
|
|
20877
|
+
useEffect4(() => setSelectedIndex(0), [query]);
|
|
20878
|
+
useEffect4(() => {
|
|
20003
20879
|
if (selectedIndex >= filtered.length) setSelectedIndex(0);
|
|
20004
20880
|
}, [filtered.length, selectedIndex]);
|
|
20005
20881
|
const cycle = (direction) => {
|
|
@@ -20049,12 +20925,20 @@ function modelMatches(model, query) {
|
|
|
20049
20925
|
return matchesSearchQuery(`${model.provider} ${model.id} ${model.name ?? ""}`, query);
|
|
20050
20926
|
}
|
|
20051
20927
|
function ModelBoard({ theme, models, onClose, onSelect, search }) {
|
|
20052
|
-
const [query, setQuery] =
|
|
20053
|
-
const [selectedIndex, setSelectedIndex] =
|
|
20054
|
-
|
|
20055
|
-
const
|
|
20056
|
-
|
|
20057
|
-
|
|
20928
|
+
const [query, setQuery] = useState5(search ?? "");
|
|
20929
|
+
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
20930
|
+
useEffect4(() => setQuery(search ?? ""), [search]);
|
|
20931
|
+
const serverTier = useMemo(readServerTierInfo, []);
|
|
20932
|
+
const isServerTier = (provider) => serverTier.signedIn && isGatewayEligibleProvider(provider) && !serverTier.localKeys.has(provider);
|
|
20933
|
+
const available = useMemo(
|
|
20934
|
+
() => models.filter(
|
|
20935
|
+
(model) => serverTier.localKeys.has(model.provider) || isServerTier(model.provider)
|
|
20936
|
+
),
|
|
20937
|
+
[models, serverTier]
|
|
20938
|
+
);
|
|
20939
|
+
const filtered = useMemo(() => available.filter((model) => modelMatches(model, query)), [available, query]);
|
|
20940
|
+
useEffect4(() => setSelectedIndex(0), [query]);
|
|
20941
|
+
useEffect4(() => {
|
|
20058
20942
|
if (selectedIndex >= filtered.length) setSelectedIndex(0);
|
|
20059
20943
|
}, [filtered.length, selectedIndex]);
|
|
20060
20944
|
useInput2((input, key) => {
|
|
@@ -20072,13 +20956,16 @@ function ModelBoard({ theme, models, onClose, onSelect, search }) {
|
|
|
20072
20956
|
});
|
|
20073
20957
|
const { start, budget, below } = windowAround(filtered.length, selectedIndex);
|
|
20074
20958
|
const visible = filtered.slice(start, start + budget);
|
|
20075
|
-
const list = filtered.length === 0 ? /* @__PURE__ */ jsx9(Text9, { children: theme.muted(
|
|
20959
|
+
const list = filtered.length === 0 ? /* @__PURE__ */ jsx9(Text9, { children: theme.muted(
|
|
20960
|
+
available.length === 0 ? "No models available \u2014 sign in with a provider key or run /login to use the server tier." : "No models matched the search."
|
|
20961
|
+
) }) : /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: visible.map((model, index) => {
|
|
20076
20962
|
const isSelected = start + index === selectedIndex;
|
|
20077
20963
|
return /* @__PURE__ */ jsxs8(Box9, { children: [
|
|
20078
20964
|
/* @__PURE__ */ jsx9(Box9, { width: 2, children: /* @__PURE__ */ jsx9(Text9, { children: isSelected ? theme.color("accent", "\u203A") : " " }) }),
|
|
20079
|
-
/* @__PURE__ */ jsx9(Text9, { bold: isSelected, children: theme.color("text",
|
|
20080
|
-
model.name ? /* @__PURE__ */ jsx9(Text9, { children: theme.dim(` ${model.name}`) }) : null
|
|
20081
|
-
|
|
20965
|
+
/* @__PURE__ */ jsx9(Text9, { bold: isSelected, children: theme.color("text", model.id) }),
|
|
20966
|
+
model.name ? /* @__PURE__ */ jsx9(Text9, { children: theme.dim(` ${model.name}`) }) : null,
|
|
20967
|
+
isServerTier(model.provider) ? /* @__PURE__ */ jsx9(Text9, { children: theme.color("accent", " \u2B21 server") }) : null
|
|
20968
|
+
] }, model.id);
|
|
20082
20969
|
}) });
|
|
20083
20970
|
return /* @__PURE__ */ jsx9(
|
|
20084
20971
|
BoardShell,
|
|
@@ -20137,13 +21024,13 @@ var SETTING_KEYS = Object.freeze(
|
|
|
20137
21024
|
);
|
|
20138
21025
|
|
|
20139
21026
|
// src/settings/manager.ts
|
|
20140
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as
|
|
20141
|
-
import { dirname as dirname4, join as
|
|
21027
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
21028
|
+
import { dirname as dirname4, join as join13 } from "node:path";
|
|
20142
21029
|
function loadTier(filePath) {
|
|
20143
21030
|
if (!existsSync3(filePath)) return {};
|
|
20144
21031
|
let raw;
|
|
20145
21032
|
try {
|
|
20146
|
-
raw =
|
|
21033
|
+
raw = readFileSync8(filePath, "utf-8");
|
|
20147
21034
|
} catch {
|
|
20148
21035
|
return {};
|
|
20149
21036
|
}
|
|
@@ -20194,7 +21081,7 @@ var PreferenceStore = class _PreferenceStore {
|
|
|
20194
21081
|
static fromWorkspace(workspace, cwd = process.cwd()) {
|
|
20195
21082
|
return new _PreferenceStore({
|
|
20196
21083
|
global: workspace.settingsPath,
|
|
20197
|
-
project:
|
|
21084
|
+
project: join13(cwd, BRAND.profileDirName, "settings.json")
|
|
20198
21085
|
});
|
|
20199
21086
|
}
|
|
20200
21087
|
/** The two resolved file locations this store reads and writes. */
|
|
@@ -20263,11 +21150,11 @@ var PreferenceStore = class _PreferenceStore {
|
|
|
20263
21150
|
}
|
|
20264
21151
|
};
|
|
20265
21152
|
function stripUndefined(tier) {
|
|
20266
|
-
const
|
|
21153
|
+
const out2 = {};
|
|
20267
21154
|
for (const [key, value] of Object.entries(tier)) {
|
|
20268
|
-
if (value !== void 0)
|
|
21155
|
+
if (value !== void 0) out2[key] = value;
|
|
20269
21156
|
}
|
|
20270
|
-
return
|
|
21157
|
+
return out2;
|
|
20271
21158
|
}
|
|
20272
21159
|
|
|
20273
21160
|
// src/console/overlays/pickers.tsx
|
|
@@ -20310,38 +21197,12 @@ function listModels(services) {
|
|
|
20310
21197
|
return [];
|
|
20311
21198
|
}
|
|
20312
21199
|
}
|
|
20313
|
-
function useAuthenticatedProviders(services) {
|
|
20314
|
-
const [authed, setAuthed] = useState5(null);
|
|
20315
|
-
useEffect4(() => {
|
|
20316
|
-
if (!services) return;
|
|
20317
|
-
let live = true;
|
|
20318
|
-
void (async () => {
|
|
20319
|
-
const found = /* @__PURE__ */ new Set();
|
|
20320
|
-
try {
|
|
20321
|
-
for (const provider of services.listLoginProviders()) {
|
|
20322
|
-
try {
|
|
20323
|
-
if ((await services.vault.listAccounts(provider.id)).length > 0) {
|
|
20324
|
-
found.add(provider.id);
|
|
20325
|
-
}
|
|
20326
|
-
} catch {
|
|
20327
|
-
}
|
|
20328
|
-
}
|
|
20329
|
-
} catch {
|
|
20330
|
-
}
|
|
20331
|
-
if (live) setAuthed(found);
|
|
20332
|
-
})();
|
|
20333
|
-
return () => {
|
|
20334
|
-
live = false;
|
|
20335
|
-
};
|
|
20336
|
-
}, []);
|
|
20337
|
-
return authed;
|
|
20338
|
-
}
|
|
20339
21200
|
function ModelPicker(props) {
|
|
20340
21201
|
const { services, theme, closeModal } = props;
|
|
20341
21202
|
const authed = useAuthenticatedProviders(services);
|
|
20342
21203
|
if (!services) return null;
|
|
20343
21204
|
const all = listModels(services);
|
|
20344
|
-
const models = authed
|
|
21205
|
+
const models = authed === null ? all : all.filter((model) => authed.has(model.provider));
|
|
20345
21206
|
return /* @__PURE__ */ jsx10(
|
|
20346
21207
|
ModelBoard,
|
|
20347
21208
|
{
|
|
@@ -20361,15 +21222,15 @@ function ModelPicker(props) {
|
|
|
20361
21222
|
function readScopedPayload(payload) {
|
|
20362
21223
|
if (payload === null || typeof payload !== "object") return {};
|
|
20363
21224
|
const record = payload;
|
|
20364
|
-
const
|
|
20365
|
-
if (record.focus === "summary")
|
|
20366
|
-
if (record.intent === "reset")
|
|
20367
|
-
return
|
|
21225
|
+
const out2 = {};
|
|
21226
|
+
if (record.focus === "summary") out2.focus = "summary";
|
|
21227
|
+
if (record.intent === "reset") out2.intent = "reset";
|
|
21228
|
+
return out2;
|
|
20368
21229
|
}
|
|
20369
21230
|
function ScopedModelPicker(props) {
|
|
20370
21231
|
const { services, dispatch: dispatch2, closeModal, modal } = props;
|
|
20371
21232
|
const payload = readScopedPayload(modal.payload);
|
|
20372
|
-
|
|
21233
|
+
useEffect5(() => {
|
|
20373
21234
|
if (!services || payload.intent !== "reset") return;
|
|
20374
21235
|
try {
|
|
20375
21236
|
services.settings.set("enabledModels", []);
|
|
@@ -20425,7 +21286,7 @@ function currentScheme(services) {
|
|
|
20425
21286
|
}
|
|
20426
21287
|
function ThemePicker(props) {
|
|
20427
21288
|
const { services, dispatch: dispatch2, closeModal } = props;
|
|
20428
|
-
const [originalScheme] =
|
|
21289
|
+
const [originalScheme] = useState6(
|
|
20429
21290
|
() => services ? currentScheme(services) : null
|
|
20430
21291
|
);
|
|
20431
21292
|
if (!services) return null;
|
|
@@ -20456,7 +21317,7 @@ function SettingsPicker(props) {
|
|
|
20456
21317
|
const { services, theme, dispatch: dispatch2, closeModal } = props;
|
|
20457
21318
|
if (!services) return null;
|
|
20458
21319
|
const settings = services.settings;
|
|
20459
|
-
const [, setVersion] =
|
|
21320
|
+
const [, setVersion] = useState6(0);
|
|
20460
21321
|
const bump = () => setVersion((n) => n + 1);
|
|
20461
21322
|
const onOff = (flag) => flag ? "on" : "off";
|
|
20462
21323
|
const toggleRow = (id, key, label, description, live) => ({
|
|
@@ -20638,7 +21499,7 @@ function PickerOverlays(props) {
|
|
|
20638
21499
|
}
|
|
20639
21500
|
|
|
20640
21501
|
// src/console/overlays/sessions.tsx
|
|
20641
|
-
import { useEffect as
|
|
21502
|
+
import { useEffect as useEffect6, useState as useState7 } from "indusagi/react-host";
|
|
20642
21503
|
import {
|
|
20643
21504
|
SessionDialog,
|
|
20644
21505
|
TreeDialog,
|
|
@@ -20660,8 +21521,8 @@ function toSessionInfo(row) {
|
|
|
20660
21521
|
}
|
|
20661
21522
|
function SessionPicker(props) {
|
|
20662
21523
|
const { services, closeModal } = props;
|
|
20663
|
-
const [sessions, setSessions] =
|
|
20664
|
-
|
|
21524
|
+
const [sessions, setSessions] = useState7([]);
|
|
21525
|
+
useEffect6(() => {
|
|
20665
21526
|
let live = true;
|
|
20666
21527
|
void (async () => {
|
|
20667
21528
|
try {
|
|
@@ -20721,8 +21582,8 @@ function SessionPicker(props) {
|
|
|
20721
21582
|
}
|
|
20722
21583
|
function BranchTree(props) {
|
|
20723
21584
|
const { services, closeModal } = props;
|
|
20724
|
-
const [items, setItems] =
|
|
20725
|
-
|
|
21585
|
+
const [items, setItems] = useState7([]);
|
|
21586
|
+
useEffect6(() => {
|
|
20726
21587
|
let live = true;
|
|
20727
21588
|
void (async () => {
|
|
20728
21589
|
try {
|
|
@@ -20773,8 +21634,8 @@ function BranchTree(props) {
|
|
|
20773
21634
|
}
|
|
20774
21635
|
function PriorTurns(props) {
|
|
20775
21636
|
const { services, closeModal } = props;
|
|
20776
|
-
const [items, setItems] =
|
|
20777
|
-
|
|
21637
|
+
const [items, setItems] = useState7([]);
|
|
21638
|
+
useEffect6(() => {
|
|
20778
21639
|
let live = true;
|
|
20779
21640
|
void (async () => {
|
|
20780
21641
|
try {
|
|
@@ -20872,34 +21733,40 @@ function approvalQueueReducer(state, event) {
|
|
|
20872
21733
|
function activeApproval(state) {
|
|
20873
21734
|
return state.entries[0];
|
|
20874
21735
|
}
|
|
21736
|
+
function modeReleasesApprovals(mode) {
|
|
21737
|
+
return mode === "bypass" || mode === "bypassPermissions";
|
|
21738
|
+
}
|
|
21739
|
+
|
|
21740
|
+
// src/console/components/TerminalConsole.tsx
|
|
21741
|
+
init_conductor2();
|
|
20875
21742
|
|
|
20876
21743
|
// src/console/startup.ts
|
|
20877
21744
|
init_briefing();
|
|
20878
|
-
import { existsSync as existsSync4, readFileSync as
|
|
20879
|
-
import { join as
|
|
21745
|
+
import { existsSync as existsSync4, readFileSync as readFileSync9 } from "node:fs";
|
|
21746
|
+
import { join as join14 } from "node:path";
|
|
20880
21747
|
var PROFILE_DIR = ".indusagi";
|
|
20881
21748
|
var CONTEXT_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
20882
21749
|
function skillRoots(cwd, home) {
|
|
20883
21750
|
return [
|
|
20884
|
-
{ dir:
|
|
20885
|
-
{ dir:
|
|
21751
|
+
{ dir: join14(cwd, PROFILE_DIR, "skills"), origin: "project" },
|
|
21752
|
+
{ dir: join14(home, PROFILE_DIR, "skills"), origin: "user" }
|
|
20886
21753
|
];
|
|
20887
21754
|
}
|
|
20888
21755
|
function macroRoots(cwd, home) {
|
|
20889
21756
|
return [
|
|
20890
|
-
{ dir:
|
|
20891
|
-
{ dir:
|
|
21757
|
+
{ dir: join14(cwd, PROFILE_DIR, "commands"), origin: "project", label: "project" },
|
|
21758
|
+
{ dir: join14(home, PROFILE_DIR, "commands"), origin: "user", label: "user" }
|
|
20892
21759
|
];
|
|
20893
21760
|
}
|
|
20894
|
-
function shortenPath2(
|
|
20895
|
-
if (cwd.length > 0 &&
|
|
20896
|
-
const rest =
|
|
21761
|
+
function shortenPath2(path4, cwd, home) {
|
|
21762
|
+
if (cwd.length > 0 && path4.startsWith(cwd)) {
|
|
21763
|
+
const rest = path4.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
20897
21764
|
return rest.length > 0 ? `./${rest}` : ".";
|
|
20898
21765
|
}
|
|
20899
|
-
if (home.length > 0 &&
|
|
20900
|
-
return `~${
|
|
21766
|
+
if (home.length > 0 && path4.startsWith(home)) {
|
|
21767
|
+
return `~${path4.slice(home.length)}`;
|
|
20901
21768
|
}
|
|
20902
|
-
return
|
|
21769
|
+
return path4;
|
|
20903
21770
|
}
|
|
20904
21771
|
var MAX_SECTION_LINES = 6;
|
|
20905
21772
|
function capLines(lines) {
|
|
@@ -20914,17 +21781,17 @@ function section(title, lines) {
|
|
|
20914
21781
|
}
|
|
20915
21782
|
function gatherContext(cwd, home) {
|
|
20916
21783
|
const seen = /* @__PURE__ */ new Set();
|
|
20917
|
-
const
|
|
21784
|
+
const out2 = [];
|
|
20918
21785
|
for (const root of [cwd, home]) {
|
|
20919
21786
|
if (root.length === 0) continue;
|
|
20920
21787
|
for (const name of CONTEXT_FILES) {
|
|
20921
|
-
const
|
|
20922
|
-
if (seen.has(
|
|
20923
|
-
seen.add(
|
|
20924
|
-
if (existsSync4(
|
|
21788
|
+
const path4 = join14(root, name);
|
|
21789
|
+
if (seen.has(path4)) continue;
|
|
21790
|
+
seen.add(path4);
|
|
21791
|
+
if (existsSync4(path4)) out2.push(shortenPath2(path4, cwd, home));
|
|
20925
21792
|
}
|
|
20926
21793
|
}
|
|
20927
|
-
return
|
|
21794
|
+
return out2;
|
|
20928
21795
|
}
|
|
20929
21796
|
function gatherSkills(cwd, home) {
|
|
20930
21797
|
let cards = [];
|
|
@@ -21342,7 +22209,7 @@ function addonFault(kind, message, detail) {
|
|
|
21342
22209
|
|
|
21343
22210
|
// src/addons/sandbox.ts
|
|
21344
22211
|
import { createJiti } from "jiti";
|
|
21345
|
-
import { homedir as
|
|
22212
|
+
import { homedir as homedir6 } from "node:os";
|
|
21346
22213
|
import { isAbsolute as isAbsolute4, resolve as resolvePathSegments } from "node:path";
|
|
21347
22214
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
21348
22215
|
var typeboxNamespace = __toESM(require_cjs(), 1);
|
|
@@ -21382,17 +22249,17 @@ var INVISIBLE_CODE_POINTS = [
|
|
|
21382
22249
|
];
|
|
21383
22250
|
var INVISIBLE_SET = new Set(INVISIBLE_CODE_POINTS);
|
|
21384
22251
|
function scrubInvisible(raw) {
|
|
21385
|
-
let
|
|
22252
|
+
let out2 = "";
|
|
21386
22253
|
for (const char of raw) {
|
|
21387
22254
|
const code = char.codePointAt(0);
|
|
21388
22255
|
if (code !== void 0 && INVISIBLE_SET.has(code)) {
|
|
21389
22256
|
continue;
|
|
21390
22257
|
}
|
|
21391
|
-
|
|
22258
|
+
out2 += char;
|
|
21392
22259
|
}
|
|
21393
|
-
return
|
|
22260
|
+
return out2.trim();
|
|
21394
22261
|
}
|
|
21395
|
-
function expandPath(raw, home =
|
|
22262
|
+
function expandPath(raw, home = homedir6()) {
|
|
21396
22263
|
const cleaned = scrubInvisible(raw);
|
|
21397
22264
|
if (cleaned === "~") {
|
|
21398
22265
|
return home;
|
|
@@ -21402,7 +22269,7 @@ function expandPath(raw, home = homedir4()) {
|
|
|
21402
22269
|
}
|
|
21403
22270
|
return cleaned;
|
|
21404
22271
|
}
|
|
21405
|
-
function resolvePath(raw, base = process.cwd(), home =
|
|
22272
|
+
function resolvePath(raw, base = process.cwd(), home = homedir6()) {
|
|
21406
22273
|
const expanded = expandPath(raw, home);
|
|
21407
22274
|
return isAbsolute4(expanded) ? resolvePathSegments(expanded) : resolvePathSegments(base, expanded);
|
|
21408
22275
|
}
|
|
@@ -21424,9 +22291,9 @@ function resolveSpecifierPath(specifier) {
|
|
|
21424
22291
|
function buildAliasMap() {
|
|
21425
22292
|
const map = {};
|
|
21426
22293
|
for (const specifier of BUNDLED_NAMESPACES) {
|
|
21427
|
-
const
|
|
21428
|
-
if (
|
|
21429
|
-
map[specifier] =
|
|
22294
|
+
const path4 = resolveSpecifierPath(specifier);
|
|
22295
|
+
if (path4 !== void 0) {
|
|
22296
|
+
map[specifier] = path4;
|
|
21430
22297
|
}
|
|
21431
22298
|
}
|
|
21432
22299
|
return map;
|
|
@@ -21472,10 +22339,10 @@ function isObject(value) {
|
|
|
21472
22339
|
function createJitiLoader(options = {}) {
|
|
21473
22340
|
const jiti = createJiti(import.meta.url, jitiOptionsForRuntime());
|
|
21474
22341
|
const base = options.base ?? process.cwd();
|
|
21475
|
-
const home = options.home ??
|
|
22342
|
+
const home = options.home ?? homedir6();
|
|
21476
22343
|
return {
|
|
21477
|
-
async load(
|
|
21478
|
-
const absolute = resolvePath(
|
|
22344
|
+
async load(path4) {
|
|
22345
|
+
const absolute = resolvePath(path4, base, home);
|
|
21479
22346
|
const specifier = pathToFileURL(absolute).href;
|
|
21480
22347
|
const imported = await jiti.import(specifier);
|
|
21481
22348
|
const manifest = toManifest(imported);
|
|
@@ -21490,8 +22357,8 @@ function createJitiLoader(options = {}) {
|
|
|
21490
22357
|
}
|
|
21491
22358
|
|
|
21492
22359
|
// src/addons/manifest.ts
|
|
21493
|
-
import { readFileSync as
|
|
21494
|
-
import { basename as basename5, extname as extname3, isAbsolute as isAbsolute5, join as
|
|
22360
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
|
|
22361
|
+
import { basename as basename5, extname as extname3, isAbsolute as isAbsolute5, join as join15, resolve as resolve7 } from "node:path";
|
|
21495
22362
|
var ENTRY_EXTENSIONS = [
|
|
21496
22363
|
".ts",
|
|
21497
22364
|
".tsx",
|
|
@@ -21508,9 +22375,9 @@ function isHidden(name) {
|
|
|
21508
22375
|
function hasEntryExtension(name) {
|
|
21509
22376
|
return ENTRY_EXTENSIONS.includes(extname3(name).toLowerCase());
|
|
21510
22377
|
}
|
|
21511
|
-
function entryKind(
|
|
22378
|
+
function entryKind(path4) {
|
|
21512
22379
|
try {
|
|
21513
|
-
const stat2 = statSync4(
|
|
22380
|
+
const stat2 = statSync4(path4);
|
|
21514
22381
|
if (stat2.isDirectory()) return "directory";
|
|
21515
22382
|
if (stat2.isFile()) return "file";
|
|
21516
22383
|
return void 0;
|
|
@@ -21526,12 +22393,12 @@ function listNames(dir) {
|
|
|
21526
22393
|
}
|
|
21527
22394
|
}
|
|
21528
22395
|
function readManifestEntry(packageDir) {
|
|
21529
|
-
const manifestPath =
|
|
22396
|
+
const manifestPath = join15(packageDir, "package.json");
|
|
21530
22397
|
if (entryKind(manifestPath) !== "file") {
|
|
21531
22398
|
return void 0;
|
|
21532
22399
|
}
|
|
21533
22400
|
try {
|
|
21534
|
-
const parsed = JSON.parse(
|
|
22401
|
+
const parsed = JSON.parse(readFileSync10(manifestPath, "utf8"));
|
|
21535
22402
|
if (typeof parsed !== "object" || parsed === null) {
|
|
21536
22403
|
return void 0;
|
|
21537
22404
|
}
|
|
@@ -21551,7 +22418,7 @@ function resolvePackageEntry(packageDir) {
|
|
|
21551
22418
|
}
|
|
21552
22419
|
for (const base of INDEX_BASENAMES) {
|
|
21553
22420
|
for (const ext of ENTRY_EXTENSIONS) {
|
|
21554
|
-
const candidate =
|
|
22421
|
+
const candidate = join15(packageDir, `${base}${ext}`);
|
|
21555
22422
|
if (entryKind(candidate) === "file") {
|
|
21556
22423
|
return candidate;
|
|
21557
22424
|
}
|
|
@@ -21563,13 +22430,13 @@ function resolveTopLevelEntry(dir, name) {
|
|
|
21563
22430
|
if (isHidden(name)) {
|
|
21564
22431
|
return void 0;
|
|
21565
22432
|
}
|
|
21566
|
-
const
|
|
21567
|
-
const kind = entryKind(
|
|
22433
|
+
const path4 = join15(dir, name);
|
|
22434
|
+
const kind = entryKind(path4);
|
|
21568
22435
|
if (kind === "file") {
|
|
21569
|
-
return hasEntryExtension(name) ?
|
|
22436
|
+
return hasEntryExtension(name) ? path4 : void 0;
|
|
21570
22437
|
}
|
|
21571
22438
|
if (kind === "directory") {
|
|
21572
|
-
return resolvePackageEntry(
|
|
22439
|
+
return resolvePackageEntry(path4);
|
|
21573
22440
|
}
|
|
21574
22441
|
return void 0;
|
|
21575
22442
|
}
|
|
@@ -21586,7 +22453,7 @@ function discoverAddons(dir) {
|
|
|
21586
22453
|
function deriveAddonId(entryPath) {
|
|
21587
22454
|
const file = basename5(entryPath);
|
|
21588
22455
|
const stem = file.slice(0, file.length - extname3(file).length);
|
|
21589
|
-
const label = INDEX_BASENAMES.includes(stem) ? basename5(
|
|
22456
|
+
const label = INDEX_BASENAMES.includes(stem) ? basename5(join15(entryPath, "..")) : stem;
|
|
21590
22457
|
return addonId(label.length > 0 ? label : entryPath);
|
|
21591
22458
|
}
|
|
21592
22459
|
function addonsDirFor(workspace, dir = ADDONS_DIR) {
|
|
@@ -21603,12 +22470,12 @@ function discoverSources(discovery) {
|
|
|
21603
22470
|
}
|
|
21604
22471
|
const seen = /* @__PURE__ */ new Set();
|
|
21605
22472
|
const sources = [];
|
|
21606
|
-
for (const
|
|
21607
|
-
if (seen.has(
|
|
22473
|
+
for (const path4 of paths) {
|
|
22474
|
+
if (seen.has(path4)) {
|
|
21608
22475
|
continue;
|
|
21609
22476
|
}
|
|
21610
|
-
seen.add(
|
|
21611
|
-
sources.push({ id: deriveAddonId(
|
|
22477
|
+
seen.add(path4);
|
|
22478
|
+
sources.push({ id: deriveAddonId(path4), path: path4 });
|
|
21612
22479
|
}
|
|
21613
22480
|
return sources;
|
|
21614
22481
|
}
|
|
@@ -22392,10 +23259,10 @@ var inertDialog = Object.freeze({
|
|
|
22392
23259
|
tell(_kind, _payload) {
|
|
22393
23260
|
}
|
|
22394
23261
|
});
|
|
22395
|
-
var
|
|
23262
|
+
var EXIT_OK2 = 0;
|
|
22396
23263
|
var EXIT_FAULT = 1;
|
|
22397
23264
|
function exitCodeFor(state) {
|
|
22398
|
-
return state.phase === "faulted" ? EXIT_FAULT :
|
|
23265
|
+
return state.phase === "faulted" ? EXIT_FAULT : EXIT_OK2;
|
|
22399
23266
|
}
|
|
22400
23267
|
function textStrategy() {
|
|
22401
23268
|
let answer = "";
|
|
@@ -22740,14 +23607,14 @@ function keyMatches(rule, key) {
|
|
|
22740
23607
|
return matcher.test(key);
|
|
22741
23608
|
}
|
|
22742
23609
|
function applyValueRules(rules, text) {
|
|
22743
|
-
let
|
|
23610
|
+
let out2 = text;
|
|
22744
23611
|
for (const rule of rules) {
|
|
22745
23612
|
const pattern = rule.value;
|
|
22746
23613
|
if (pattern === void 0) continue;
|
|
22747
23614
|
if (pattern.global || pattern.sticky) pattern.lastIndex = 0;
|
|
22748
|
-
|
|
23615
|
+
out2 = out2.replace(pattern, REDACTED_TOKEN);
|
|
22749
23616
|
}
|
|
22750
|
-
return
|
|
23617
|
+
return out2;
|
|
22751
23618
|
}
|
|
22752
23619
|
function createRedactor(rules = DEFAULT_REDACTION_RULES, options = {}) {
|
|
22753
23620
|
const frozenRules = Object.freeze([...rules]);
|
|
@@ -22779,12 +23646,12 @@ function createRedactor(rules = DEFAULT_REDACTION_RULES, options = {}) {
|
|
|
22779
23646
|
return Object.freeze(value.map((item) => scrubNode(item, void 0)));
|
|
22780
23647
|
}
|
|
22781
23648
|
if (value !== null && typeof value === "object") {
|
|
22782
|
-
const
|
|
23649
|
+
const out2 = {};
|
|
22783
23650
|
for (const [k, v] of Object.entries(value)) {
|
|
22784
23651
|
if (isOmitted(k)) continue;
|
|
22785
|
-
|
|
23652
|
+
out2[k] = scrubNode(v, k);
|
|
22786
23653
|
}
|
|
22787
|
-
return Object.freeze(
|
|
23654
|
+
return Object.freeze(out2);
|
|
22788
23655
|
}
|
|
22789
23656
|
return value;
|
|
22790
23657
|
}
|
|
@@ -22792,12 +23659,12 @@ function createRedactor(rules = DEFAULT_REDACTION_RULES, options = {}) {
|
|
|
22792
23659
|
return scrubNode(value, void 0);
|
|
22793
23660
|
}
|
|
22794
23661
|
function scrubAttributes(attributes) {
|
|
22795
|
-
const
|
|
23662
|
+
const out2 = {};
|
|
22796
23663
|
for (const [k, v] of Object.entries(attributes)) {
|
|
22797
23664
|
if (isOmitted(k)) continue;
|
|
22798
|
-
|
|
23665
|
+
out2[k] = scrubNode(v, k);
|
|
22799
23666
|
}
|
|
22800
|
-
return Object.freeze(
|
|
23667
|
+
return Object.freeze(out2);
|
|
22801
23668
|
}
|
|
22802
23669
|
function scrubFault(fault) {
|
|
22803
23670
|
const scrubbed = {
|
|
@@ -22837,9 +23704,9 @@ var IMAGE_SNIFF_BYTES = PNG_SIGNATURE.length;
|
|
|
22837
23704
|
|
|
22838
23705
|
// src/kit/clipboard-image.ts
|
|
22839
23706
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
22840
|
-
import { readFileSync as
|
|
23707
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22841
23708
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
22842
|
-
import { join as
|
|
23709
|
+
import { join as join16 } from "node:path";
|
|
22843
23710
|
var READ_TIMEOUT_MS = 3e3;
|
|
22844
23711
|
var MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
22845
23712
|
function captureStdout(command, args) {
|
|
@@ -22848,9 +23715,9 @@ function captureStdout(command, args) {
|
|
|
22848
23715
|
maxBuffer: MAX_BUFFER_BYTES
|
|
22849
23716
|
});
|
|
22850
23717
|
if (result.error || result.status !== 0) return null;
|
|
22851
|
-
const
|
|
22852
|
-
if (!Buffer.isBuffer(
|
|
22853
|
-
return
|
|
23718
|
+
const out2 = result.stdout;
|
|
23719
|
+
if (!Buffer.isBuffer(out2) || out2.length === 0) return null;
|
|
23720
|
+
return out2;
|
|
22854
23721
|
}
|
|
22855
23722
|
function captureViaOsascript() {
|
|
22856
23723
|
const result = spawnSync2(
|
|
@@ -22882,21 +23749,21 @@ function captureViaOsascript() {
|
|
|
22882
23749
|
{ timeout: READ_TIMEOUT_MS, encoding: "utf8" }
|
|
22883
23750
|
);
|
|
22884
23751
|
if (result.error || result.status !== 0) return null;
|
|
22885
|
-
const
|
|
22886
|
-
if (
|
|
23752
|
+
const path4 = String(result.stdout ?? "").trim();
|
|
23753
|
+
if (path4.length === 0) return null;
|
|
22887
23754
|
try {
|
|
22888
|
-
const bytes =
|
|
23755
|
+
const bytes = readFileSync11(path4);
|
|
22889
23756
|
return bytes.length > 0 ? bytes : null;
|
|
22890
23757
|
} catch {
|
|
22891
23758
|
return null;
|
|
22892
23759
|
}
|
|
22893
23760
|
}
|
|
22894
|
-
function readClipboardBytes(platform,
|
|
23761
|
+
function readClipboardBytes(platform, env3) {
|
|
22895
23762
|
if (platform === "darwin") {
|
|
22896
23763
|
return captureStdout("pngpaste", ["-"]) ?? captureViaOsascript();
|
|
22897
23764
|
}
|
|
22898
23765
|
if (platform === "linux") {
|
|
22899
|
-
const wayland = Boolean(
|
|
23766
|
+
const wayland = Boolean(env3.WAYLAND_DISPLAY) || env3.XDG_SESSION_TYPE === "wayland";
|
|
22900
23767
|
if (wayland) {
|
|
22901
23768
|
const fromWayland = captureStdout("wl-paste", ["--type", "image/png", "--no-newline"]);
|
|
22902
23769
|
if (fromWayland) return fromWayland;
|
|
@@ -22907,15 +23774,15 @@ function readClipboardBytes(platform, env2) {
|
|
|
22907
23774
|
}
|
|
22908
23775
|
function readClipboardImage(options = {}) {
|
|
22909
23776
|
const platform = options.platform ?? process.platform;
|
|
22910
|
-
const
|
|
22911
|
-
const bytes = readClipboardBytes(platform,
|
|
23777
|
+
const env3 = options.env ?? process.env;
|
|
23778
|
+
const bytes = readClipboardBytes(platform, env3);
|
|
22912
23779
|
if (bytes === null) return null;
|
|
22913
23780
|
const dir = options.dir ?? tmpdir2();
|
|
22914
23781
|
const name = `indus-clipboard-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.png`;
|
|
22915
|
-
const
|
|
23782
|
+
const path4 = join16(dir, name);
|
|
22916
23783
|
try {
|
|
22917
|
-
writeFileSync5(
|
|
22918
|
-
return
|
|
23784
|
+
writeFileSync5(path4, bytes);
|
|
23785
|
+
return path4;
|
|
22919
23786
|
} catch {
|
|
22920
23787
|
return null;
|
|
22921
23788
|
}
|
|
@@ -22923,31 +23790,31 @@ function readClipboardImage(options = {}) {
|
|
|
22923
23790
|
|
|
22924
23791
|
// src/kit/external-editor.ts
|
|
22925
23792
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
22926
|
-
import { readFileSync as
|
|
23793
|
+
import { readFileSync as readFileSync12, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
22927
23794
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
22928
|
-
import { join as
|
|
23795
|
+
import { join as join17 } from "node:path";
|
|
22929
23796
|
var FALLBACK_EDITOR = "vi";
|
|
22930
|
-
function resolveEditor(
|
|
22931
|
-
const configured =
|
|
23797
|
+
function resolveEditor(env3) {
|
|
23798
|
+
const configured = env3.VISUAL || env3.EDITOR || FALLBACK_EDITOR;
|
|
22932
23799
|
const parts = configured.split(/\s+/).filter((part) => part.length > 0);
|
|
22933
23800
|
return parts.length > 0 ? parts : [FALLBACK_EDITOR];
|
|
22934
23801
|
}
|
|
22935
23802
|
function openInExternalEditor(buffer, options = {}) {
|
|
22936
|
-
const
|
|
23803
|
+
const env3 = options.env ?? process.env;
|
|
22937
23804
|
const dir = options.dir ?? tmpdir3();
|
|
22938
23805
|
const name = `indus-editor-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.md`;
|
|
22939
|
-
const
|
|
22940
|
-
const [editor, ...editorArgs] = resolveEditor(
|
|
23806
|
+
const path4 = join17(dir, name);
|
|
23807
|
+
const [editor, ...editorArgs] = resolveEditor(env3);
|
|
22941
23808
|
try {
|
|
22942
|
-
writeFileSync6(
|
|
22943
|
-
const result = spawnSync3(editor, [...editorArgs,
|
|
23809
|
+
writeFileSync6(path4, buffer, "utf8");
|
|
23810
|
+
const result = spawnSync3(editor, [...editorArgs, path4], { stdio: "inherit" });
|
|
22944
23811
|
if (result.error || result.status !== 0) return null;
|
|
22945
|
-
return
|
|
23812
|
+
return readFileSync12(path4, "utf8").replace(/\n$/, "");
|
|
22946
23813
|
} catch {
|
|
22947
23814
|
return null;
|
|
22948
23815
|
} finally {
|
|
22949
23816
|
try {
|
|
22950
|
-
unlinkSync(
|
|
23817
|
+
unlinkSync(path4);
|
|
22951
23818
|
} catch {
|
|
22952
23819
|
}
|
|
22953
23820
|
}
|
|
@@ -22955,8 +23822,8 @@ function openInExternalEditor(buffer, options = {}) {
|
|
|
22955
23822
|
|
|
22956
23823
|
// src/sessions/library.ts
|
|
22957
23824
|
init_conductor2();
|
|
22958
|
-
import { mkdir, readFile, readdir, rename, rm, stat } from "node:fs/promises";
|
|
22959
|
-
import { basename as basename6, join as
|
|
23825
|
+
import { mkdir as mkdir2, readFile as readFile2, readdir, rename, rm, stat } from "node:fs/promises";
|
|
23826
|
+
import { basename as basename6, join as join18 } from "node:path";
|
|
22960
23827
|
var SESSION_FILE_EXT = ".ndjson";
|
|
22961
23828
|
var PREVIEW_LIMIT = 72;
|
|
22962
23829
|
var SessionLibrary = class {
|
|
@@ -23016,7 +23883,7 @@ var SessionLibrary = class {
|
|
|
23016
23883
|
if (!await this.#missing(toPath)) {
|
|
23017
23884
|
throw new Error(`SessionLibrary.rename: session "${toId}" already exists`);
|
|
23018
23885
|
}
|
|
23019
|
-
await
|
|
23886
|
+
await mkdir2(this.#dir, { recursive: true });
|
|
23020
23887
|
await rename(fromPath, toPath);
|
|
23021
23888
|
return toPath;
|
|
23022
23889
|
}
|
|
@@ -23025,14 +23892,14 @@ var SessionLibrary = class {
|
|
|
23025
23892
|
* there was nothing to delete — never throws on an already-absent session.
|
|
23026
23893
|
*/
|
|
23027
23894
|
async remove(id) {
|
|
23028
|
-
const
|
|
23029
|
-
if (await this.#missing(
|
|
23030
|
-
await rm(
|
|
23895
|
+
const path4 = this.pathOf(id);
|
|
23896
|
+
if (await this.#missing(path4)) return false;
|
|
23897
|
+
await rm(path4, { force: true });
|
|
23031
23898
|
return true;
|
|
23032
23899
|
}
|
|
23033
23900
|
/** Absolute path a session id persists to. */
|
|
23034
23901
|
pathOf(id) {
|
|
23035
|
-
return
|
|
23902
|
+
return join18(this.#dir, `${id}${SESSION_FILE_EXT}`);
|
|
23036
23903
|
}
|
|
23037
23904
|
/**
|
|
23038
23905
|
* Flatten a loaded transcript into an ordered {@link BranchNode} list for a
|
|
@@ -23056,9 +23923,9 @@ var SessionLibrary = class {
|
|
|
23056
23923
|
for (const node of nodes) {
|
|
23057
23924
|
if (node.parent !== null) hasChildren.add(node.parent);
|
|
23058
23925
|
}
|
|
23059
|
-
const
|
|
23926
|
+
const out2 = [];
|
|
23060
23927
|
const walk = (entry, depth) => {
|
|
23061
|
-
|
|
23928
|
+
out2.push({
|
|
23062
23929
|
id: entry.id,
|
|
23063
23930
|
parent: entry.parent,
|
|
23064
23931
|
label: labelFor(entry, depth),
|
|
@@ -23073,7 +23940,7 @@ var SessionLibrary = class {
|
|
|
23073
23940
|
for (const root of childrenOf.get(null) ?? []) {
|
|
23074
23941
|
walk(root, 0);
|
|
23075
23942
|
}
|
|
23076
|
-
return
|
|
23943
|
+
return out2;
|
|
23077
23944
|
}
|
|
23078
23945
|
/**
|
|
23079
23946
|
* Extract the user prompts along a loaded transcript's active branch as fork
|
|
@@ -23084,14 +23951,14 @@ var SessionLibrary = class {
|
|
|
23084
23951
|
* text, projecting each to a {@link PriorTurn} a forking picker can offer.
|
|
23085
23952
|
*/
|
|
23086
23953
|
priorTurns(store) {
|
|
23087
|
-
const
|
|
23954
|
+
const out2 = [];
|
|
23088
23955
|
for (const entry of store.pathTo()) {
|
|
23089
23956
|
if (entry.role !== "user") continue;
|
|
23090
23957
|
const text = messageText(entry.content).trim();
|
|
23091
23958
|
if (text.length === 0) continue;
|
|
23092
|
-
|
|
23959
|
+
out2.push({ entryId: entry.id, text, preview: previewOf(text) });
|
|
23093
23960
|
}
|
|
23094
|
-
return
|
|
23961
|
+
return out2;
|
|
23095
23962
|
}
|
|
23096
23963
|
/* ---- internals ---- */
|
|
23097
23964
|
/** Bare session ids present in the directory (no extension), or `[]`. */
|
|
@@ -23106,41 +23973,41 @@ var SessionLibrary = class {
|
|
|
23106
23973
|
}
|
|
23107
23974
|
/** Catalog row from file metadata only — no parse. */
|
|
23108
23975
|
async #shallowRow(id) {
|
|
23109
|
-
const
|
|
23110
|
-
const meta = await this.#fileMeta(
|
|
23111
|
-
return { id, path:
|
|
23976
|
+
const path4 = this.pathOf(id);
|
|
23977
|
+
const meta = await this.#fileMeta(path4);
|
|
23978
|
+
return { id, path: path4, ...meta };
|
|
23112
23979
|
}
|
|
23113
23980
|
/** Catalog row enriched by opening the transcript and reducing its text. */
|
|
23114
23981
|
async #deepRow(id) {
|
|
23115
|
-
const
|
|
23116
|
-
const meta = await this.#fileMeta(
|
|
23982
|
+
const path4 = this.pathOf(id);
|
|
23983
|
+
const meta = await this.#fileMeta(path4);
|
|
23117
23984
|
const store = await this.open(id);
|
|
23118
|
-
if (store === null) return { id, path:
|
|
23985
|
+
if (store === null) return { id, path: path4, ...meta };
|
|
23119
23986
|
const branch = store.pathTo();
|
|
23120
23987
|
const conversational = branch.filter(isConversational);
|
|
23121
23988
|
const opener = conversational.find((entry) => entry.role === "user");
|
|
23122
23989
|
const preview2 = opener ? previewOf(messageText(opener.content)) : void 0;
|
|
23123
23990
|
return {
|
|
23124
23991
|
id,
|
|
23125
|
-
path:
|
|
23992
|
+
path: path4,
|
|
23126
23993
|
...meta,
|
|
23127
23994
|
messageCount: conversational.length,
|
|
23128
23995
|
...preview2 ? { preview: preview2, name: preview2 } : {}
|
|
23129
23996
|
};
|
|
23130
23997
|
}
|
|
23131
23998
|
/** Best-effort `{ size, lastModified }`; empty object when the file is gone. */
|
|
23132
|
-
async #fileMeta(
|
|
23999
|
+
async #fileMeta(path4) {
|
|
23133
24000
|
try {
|
|
23134
|
-
const info2 = await stat(
|
|
24001
|
+
const info2 = await stat(path4);
|
|
23135
24002
|
return { size: info2.size, lastModified: info2.mtimeMs };
|
|
23136
24003
|
} catch {
|
|
23137
24004
|
return {};
|
|
23138
24005
|
}
|
|
23139
24006
|
}
|
|
23140
24007
|
/** True when a path does not resolve to a readable file. */
|
|
23141
|
-
async #missing(
|
|
24008
|
+
async #missing(path4) {
|
|
23142
24009
|
try {
|
|
23143
|
-
await
|
|
24010
|
+
await readFile2(path4);
|
|
23144
24011
|
return false;
|
|
23145
24012
|
} catch {
|
|
23146
24013
|
return true;
|
|
@@ -23204,16 +24071,16 @@ var CHROME_ROWS = 14;
|
|
|
23204
24071
|
var MODAL_CHROME_ROWS = 24;
|
|
23205
24072
|
var MIN_VISIBLE_ROWS = 8;
|
|
23206
24073
|
var FALLBACK_CONTEXT_WINDOW = 2e5;
|
|
23207
|
-
var PASTE_BURST_MS =
|
|
24074
|
+
var PASTE_BURST_MS = PASTE_BURST_GAP_MS;
|
|
23208
24075
|
var BRACKETED_PASTE = /\x1b?\[20[01]~/g;
|
|
23209
24076
|
function readBranch() {
|
|
23210
24077
|
try {
|
|
23211
|
-
const
|
|
24078
|
+
const out2 = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
23212
24079
|
cwd: process.cwd(),
|
|
23213
24080
|
encoding: "utf8",
|
|
23214
24081
|
stdio: ["ignore", "pipe", "ignore"]
|
|
23215
24082
|
}).trim();
|
|
23216
|
-
return
|
|
24083
|
+
return out2.length > 0 ? out2 : null;
|
|
23217
24084
|
} catch {
|
|
23218
24085
|
return null;
|
|
23219
24086
|
}
|
|
@@ -23321,6 +24188,19 @@ function renderToolUpdateText(details) {
|
|
|
23321
24188
|
const text = details.text;
|
|
23322
24189
|
return typeof text === "string" ? text : void 0;
|
|
23323
24190
|
}
|
|
24191
|
+
function permissionModeStatusText(mode) {
|
|
24192
|
+
switch (mode) {
|
|
24193
|
+
case "plan":
|
|
24194
|
+
return "Permission mode: PLAN \u2014 read-only research; mutating tools are blocked. Shift+Tab to cycle.";
|
|
24195
|
+
case "bypass":
|
|
24196
|
+
case "bypassPermissions":
|
|
24197
|
+
return "Permission mode: BYPASS \u2014 every tool auto-allowed (unsafe). Shift+Tab to cycle.";
|
|
24198
|
+
case "acceptEdits":
|
|
24199
|
+
return "Permission mode: ACCEPT-EDITS \u2014 edits auto-approved. Shift+Tab to cycle.";
|
|
24200
|
+
default:
|
|
24201
|
+
return "Permission mode: DEFAULT \u2014 tools prompt as usual. Shift+Tab to cycle.";
|
|
24202
|
+
}
|
|
24203
|
+
}
|
|
23324
24204
|
function TerminalConsole(props) {
|
|
23325
24205
|
const { conductor, theme, slash, verbose, onExit, initialInput, services } = props;
|
|
23326
24206
|
const adapter = theme.adapter;
|
|
@@ -23331,22 +24211,23 @@ function TerminalConsole(props) {
|
|
|
23331
24211
|
const chord = useRef3(NO_CHORD);
|
|
23332
24212
|
const chordTimer = useRef3(null);
|
|
23333
24213
|
const paste = useRef3(EMPTY_PASTE_VAULT);
|
|
24214
|
+
const activePaste = useRef3(null);
|
|
23334
24215
|
const burst = useRef3("");
|
|
23335
24216
|
const burstTimer = useRef3(null);
|
|
23336
24217
|
const liveAnswer = useRef3(null);
|
|
23337
24218
|
const liveReason = useRef3(null);
|
|
23338
24219
|
const rowSeed = useRef3(0);
|
|
23339
24220
|
const ctrlCAt = useRef3(0);
|
|
23340
|
-
const [highlight, setHighlight] =
|
|
23341
|
-
const [toolExecutions, setToolExecutions] =
|
|
23342
|
-
const [taskTokens, setTaskTokens] =
|
|
23343
|
-
const [subagentActivity, setSubagentActivity] =
|
|
23344
|
-
const [expandTools, setExpandTools] =
|
|
23345
|
-
const [agentsOpen, setAgentsOpen] =
|
|
23346
|
-
const [terminalRows, setTerminalRows] =
|
|
24221
|
+
const [highlight, setHighlight] = useState8(0);
|
|
24222
|
+
const [toolExecutions, setToolExecutions] = useState8({});
|
|
24223
|
+
const [taskTokens, setTaskTokens] = useState8({});
|
|
24224
|
+
const [subagentActivity, setSubagentActivity] = useState8({});
|
|
24225
|
+
const [expandTools, setExpandTools] = useState8(false);
|
|
24226
|
+
const [agentsOpen, setAgentsOpen] = useState8(false);
|
|
24227
|
+
const [terminalRows, setTerminalRows] = useState8(
|
|
23347
24228
|
() => process.stdout.rows ?? FALLBACK_TERMINAL_ROWS
|
|
23348
24229
|
);
|
|
23349
|
-
const [, forceTick] =
|
|
24230
|
+
const [, forceTick] = useState8(0);
|
|
23350
24231
|
const pulse = useCallback(() => forceTick((n) => n + 1), []);
|
|
23351
24232
|
const dirReader = useMemo2(() => createDirReader(process.cwd()), []);
|
|
23352
24233
|
const [approvalQueue, dispatchApproval] = useReducer(
|
|
@@ -23372,7 +24253,11 @@ function TerminalConsole(props) {
|
|
|
23372
24253
|
(toolName, input, opts) => new Promise((resolve8) => {
|
|
23373
24254
|
approvalSeed.current += 1;
|
|
23374
24255
|
const id = `ap_${approvalSeed.current}`;
|
|
23375
|
-
const request = {
|
|
24256
|
+
const request = {
|
|
24257
|
+
toolName,
|
|
24258
|
+
input,
|
|
24259
|
+
suggestions: allowAlwaysRuleStrings(toolName, input)
|
|
24260
|
+
};
|
|
23376
24261
|
approvalResolvers.current.set(id, resolve8);
|
|
23377
24262
|
const signal = opts.signal;
|
|
23378
24263
|
if (signal !== void 0) {
|
|
@@ -23391,7 +24276,7 @@ function TerminalConsole(props) {
|
|
|
23391
24276
|
}),
|
|
23392
24277
|
[settleApproval]
|
|
23393
24278
|
);
|
|
23394
|
-
|
|
24279
|
+
useEffect7(() => {
|
|
23395
24280
|
conductor.setApprovalResolver(requestApproval);
|
|
23396
24281
|
return () => {
|
|
23397
24282
|
conductor.setApprovalResolver(void 0);
|
|
@@ -23401,7 +24286,7 @@ function TerminalConsole(props) {
|
|
|
23401
24286
|
const head = activeApproval(approvalQueue);
|
|
23402
24287
|
const headId = head?.id;
|
|
23403
24288
|
const approvalModalOpen = useRef3(false);
|
|
23404
|
-
|
|
24289
|
+
useEffect7(() => {
|
|
23405
24290
|
if (head === void 0) {
|
|
23406
24291
|
if (approvalModalOpen.current) {
|
|
23407
24292
|
approvalModalOpen.current = false;
|
|
@@ -23419,7 +24304,17 @@ function TerminalConsole(props) {
|
|
|
23419
24304
|
}
|
|
23420
24305
|
});
|
|
23421
24306
|
}, [headId, settleApproval]);
|
|
23422
|
-
|
|
24307
|
+
const cyclePermission = useCallback(() => {
|
|
24308
|
+
const now = conductor.cyclePermissionMode();
|
|
24309
|
+
let text = permissionModeStatusText(now);
|
|
24310
|
+
if (modeReleasesApprovals(now) && approvalResolvers.current.size > 0) {
|
|
24311
|
+
const parked = [...approvalResolvers.current.keys()];
|
|
24312
|
+
for (const id of parked) settleApproval(id, "allow-once");
|
|
24313
|
+
text += ` Released ${parked.length} pending approval${parked.length === 1 ? "" : "s"}.`;
|
|
24314
|
+
}
|
|
24315
|
+
dispatch2({ type: "status:set", status: { kind: "info", text } });
|
|
24316
|
+
}, [conductor, settleApproval]);
|
|
24317
|
+
useEffect7(() => {
|
|
23423
24318
|
const off = conductor.subscribe((signal) => {
|
|
23424
24319
|
switch (signal.kind) {
|
|
23425
24320
|
case "prompt": {
|
|
@@ -23525,7 +24420,30 @@ function TerminalConsole(props) {
|
|
|
23525
24420
|
break;
|
|
23526
24421
|
}
|
|
23527
24422
|
case "compacted": {
|
|
23528
|
-
|
|
24423
|
+
if (signal.manual) {
|
|
24424
|
+
const carried = [];
|
|
24425
|
+
for (const message of conductor.messages()) {
|
|
24426
|
+
const content = message.content;
|
|
24427
|
+
if (typeof content === "string" && content.startsWith(RESTORED_FILE_PREFIX)) {
|
|
24428
|
+
const firstLine = content.slice(RESTORED_FILE_PREFIX.length).split("\n", 1)[0];
|
|
24429
|
+
if (firstLine) carried.push(firstLine.trim());
|
|
24430
|
+
}
|
|
24431
|
+
}
|
|
24432
|
+
setCompactNote(carried);
|
|
24433
|
+
visibleFrom.current = conductor.messages().length;
|
|
24434
|
+
liveAnswer.current = null;
|
|
24435
|
+
liveReason.current = null;
|
|
24436
|
+
answerText.current = "";
|
|
24437
|
+
reasonText.current = "";
|
|
24438
|
+
dispatch2({ type: "rows:set", rows: [] });
|
|
24439
|
+
}
|
|
24440
|
+
dispatch2({
|
|
24441
|
+
type: "status:set",
|
|
24442
|
+
status: {
|
|
24443
|
+
kind: "info",
|
|
24444
|
+
text: signal.manual ? "Conversation condensed." : "Auto-compacted older history to stay within the context window (automatic \u2014 you didn't run /compact)."
|
|
24445
|
+
}
|
|
24446
|
+
});
|
|
23529
24447
|
break;
|
|
23530
24448
|
}
|
|
23531
24449
|
case "persisted": {
|
|
@@ -23533,6 +24451,10 @@ function TerminalConsole(props) {
|
|
|
23533
24451
|
break;
|
|
23534
24452
|
}
|
|
23535
24453
|
case "fault": {
|
|
24454
|
+
if (signal.transient) {
|
|
24455
|
+
dispatch2({ type: "status:set", status: { kind: "warning", text: signal.fault.message } });
|
|
24456
|
+
break;
|
|
24457
|
+
}
|
|
23536
24458
|
liveAnswer.current = null;
|
|
23537
24459
|
liveReason.current = null;
|
|
23538
24460
|
dispatch2({ type: "busy:set", busy: false });
|
|
@@ -23552,12 +24474,14 @@ function TerminalConsole(props) {
|
|
|
23552
24474
|
}, [conductor]);
|
|
23553
24475
|
const answerText = useRef3("");
|
|
23554
24476
|
const reasonText = useRef3("");
|
|
24477
|
+
const visibleFrom = useRef3(0);
|
|
24478
|
+
const [compactNote, setCompactNote] = useState8(null);
|
|
23555
24479
|
const completion = useMemo2(
|
|
23556
24480
|
() => completeAt(state.buffer, state.caret, slash, dirReader),
|
|
23557
24481
|
[state.buffer, state.caret, slash, dirReader]
|
|
23558
24482
|
);
|
|
23559
24483
|
const suggestions = completion.suggestions;
|
|
23560
|
-
|
|
24484
|
+
useEffect7(() => {
|
|
23561
24485
|
if (highlight >= suggestions.length) setHighlight(0);
|
|
23562
24486
|
}, [suggestions.length, highlight]);
|
|
23563
24487
|
const submit = useCallback(
|
|
@@ -23581,10 +24505,10 @@ function TerminalConsole(props) {
|
|
|
23581
24505
|
text: `Shell exited ${outcome.exitCode}.`
|
|
23582
24506
|
}
|
|
23583
24507
|
});
|
|
23584
|
-
}).catch((
|
|
24508
|
+
}).catch((err2) => {
|
|
23585
24509
|
dispatch2({
|
|
23586
24510
|
type: "status:set",
|
|
23587
|
-
status: { kind: "error", text:
|
|
24511
|
+
status: { kind: "error", text: err2 instanceof Error ? err2.message : String(err2) }
|
|
23588
24512
|
});
|
|
23589
24513
|
});
|
|
23590
24514
|
return;
|
|
@@ -23622,15 +24546,23 @@ function TerminalConsole(props) {
|
|
|
23622
24546
|
const id = freshRowId(rowSeed.current++);
|
|
23623
24547
|
dispatch2({ type: "rows:append", row: { id, kind: "prompt", text } });
|
|
23624
24548
|
dispatch2({ type: "busy:set", busy: true });
|
|
24549
|
+
if (conductor.snapshot().phase === "condensing") {
|
|
24550
|
+
dispatch2({
|
|
24551
|
+
type: "status:set",
|
|
24552
|
+
status: { kind: "info", text: "Queued message for after compaction." }
|
|
24553
|
+
});
|
|
24554
|
+
}
|
|
24555
|
+
setCompactNote(null);
|
|
24556
|
+
activePaste.current = null;
|
|
23625
24557
|
answerText.current = "";
|
|
23626
24558
|
reasonText.current = "";
|
|
23627
24559
|
try {
|
|
23628
24560
|
await conductor.submit(text);
|
|
23629
|
-
} catch (
|
|
24561
|
+
} catch (err2) {
|
|
23630
24562
|
dispatch2({ type: "busy:set", busy: false });
|
|
23631
24563
|
dispatch2({
|
|
23632
24564
|
type: "status:set",
|
|
23633
|
-
status: { kind: "error", text:
|
|
24565
|
+
status: { kind: "error", text: err2 instanceof Error ? err2.message : String(err2) }
|
|
23634
24566
|
});
|
|
23635
24567
|
}
|
|
23636
24568
|
pulse();
|
|
@@ -23646,12 +24578,29 @@ function TerminalConsole(props) {
|
|
|
23646
24578
|
const text = burst.current;
|
|
23647
24579
|
if (text.length === 0) return;
|
|
23648
24580
|
burst.current = "";
|
|
23649
|
-
|
|
24581
|
+
const now = Date.now();
|
|
24582
|
+
const active = activePaste.current;
|
|
24583
|
+
if (active !== null && now <= active.until && text.length > 1 && pasteLines(paste.current, active.ordinal) < PASTE_MARKER_LINE_CAP) {
|
|
24584
|
+
const captured = appendToPaste(active.ordinal, text, paste.current);
|
|
24585
|
+
paste.current = captured.vault;
|
|
24586
|
+
dispatch2({ type: "buffer:replaceSpan", find: active.marker, replaceWith: captured.marker });
|
|
24587
|
+
activePaste.current = {
|
|
24588
|
+
ordinal: active.ordinal,
|
|
24589
|
+
marker: captured.marker,
|
|
24590
|
+
until: now + PASTE_CONTINUATION_MS
|
|
24591
|
+
};
|
|
24592
|
+
} else if (text.length > 1 && (classifyPaste(text) === "coalesce" || active !== null && now <= active.until)) {
|
|
23650
24593
|
const captured = coalescePaste(text, paste.current);
|
|
23651
24594
|
paste.current = captured.vault;
|
|
23652
24595
|
dispatch2({ type: "buffer:insert", text: captured.marker });
|
|
24596
|
+
activePaste.current = {
|
|
24597
|
+
ordinal: captured.vault.minted,
|
|
24598
|
+
marker: captured.marker,
|
|
24599
|
+
until: now + PASTE_CONTINUATION_MS
|
|
24600
|
+
};
|
|
23653
24601
|
} else {
|
|
23654
24602
|
dispatch2({ type: "buffer:insert", text });
|
|
24603
|
+
activePaste.current = null;
|
|
23655
24604
|
}
|
|
23656
24605
|
setHighlight(0);
|
|
23657
24606
|
}, []);
|
|
@@ -23667,14 +24616,14 @@ function TerminalConsole(props) {
|
|
|
23667
24616
|
chordTimer.current = null;
|
|
23668
24617
|
}
|
|
23669
24618
|
}, []);
|
|
23670
|
-
|
|
24619
|
+
useEffect7(
|
|
23671
24620
|
() => () => {
|
|
23672
24621
|
if (chordTimer.current !== null) clearTimeout(chordTimer.current);
|
|
23673
24622
|
if (burstTimer.current !== null) clearTimeout(burstTimer.current);
|
|
23674
24623
|
},
|
|
23675
24624
|
[]
|
|
23676
24625
|
);
|
|
23677
|
-
|
|
24626
|
+
useEffect7(() => {
|
|
23678
24627
|
const onResize = () => setTerminalRows(process.stdout.rows ?? FALLBACK_TERMINAL_ROWS);
|
|
23679
24628
|
process.stdout.on("resize", onResize);
|
|
23680
24629
|
return () => {
|
|
@@ -23682,7 +24631,7 @@ function TerminalConsole(props) {
|
|
|
23682
24631
|
};
|
|
23683
24632
|
}, []);
|
|
23684
24633
|
const titleName = conductor.sessionName();
|
|
23685
|
-
|
|
24634
|
+
useEffect7(() => {
|
|
23686
24635
|
writeTerminalTitle(titleName && titleName.length > 0 ? titleName : "indus console");
|
|
23687
24636
|
}, [titleName]);
|
|
23688
24637
|
const requestExit = useCallback(() => {
|
|
@@ -23808,7 +24757,7 @@ function TerminalConsole(props) {
|
|
|
23808
24757
|
}
|
|
23809
24758
|
} else if (state.modal.kind !== "none") {
|
|
23810
24759
|
dispatch2({ type: "modal:close" });
|
|
23811
|
-
} else if (state.busy) {
|
|
24760
|
+
} else if (state.busy || conductor.snapshot().phase === "condensing") {
|
|
23812
24761
|
denyAllApprovals();
|
|
23813
24762
|
conductor.abort();
|
|
23814
24763
|
} else if (suggestions.length > 0) {
|
|
@@ -23844,12 +24793,9 @@ function TerminalConsole(props) {
|
|
|
23844
24793
|
dispatch2({ type: "status:set", status: { kind: "info", text: `Reasoning effort: ${level}.` } });
|
|
23845
24794
|
return;
|
|
23846
24795
|
}
|
|
23847
|
-
case "mode:cyclePermission":
|
|
23848
|
-
|
|
23849
|
-
const text = now === "plan" ? "Permission mode: PLAN \u2014 read-only research; mutating tools are blocked. Shift+Tab to cycle." : now === "bypass" || now === "bypassPermissions" ? "Permission mode: BYPASS \u2014 every tool auto-allowed (unsafe). Shift+Tab to cycle." : now === "acceptEdits" ? "Permission mode: ACCEPT-EDITS \u2014 edits auto-approved. Shift+Tab to cycle." : "Permission mode: DEFAULT \u2014 tools prompt as usual. Shift+Tab to cycle.";
|
|
23850
|
-
dispatch2({ type: "status:set", status: { kind: "info", text } });
|
|
24796
|
+
case "mode:cyclePermission":
|
|
24797
|
+
cyclePermission();
|
|
23851
24798
|
return;
|
|
23852
|
-
}
|
|
23853
24799
|
case "view:toggleReasoning":
|
|
23854
24800
|
dispatch2({ type: "toggle:reasoning" });
|
|
23855
24801
|
return;
|
|
@@ -23862,11 +24808,25 @@ function TerminalConsole(props) {
|
|
|
23862
24808
|
}
|
|
23863
24809
|
return;
|
|
23864
24810
|
}
|
|
24811
|
+
case "queue:steer": {
|
|
24812
|
+
if (conductor.steerNow()) {
|
|
24813
|
+
dispatch2({
|
|
24814
|
+
type: "status:set",
|
|
24815
|
+
status: { kind: "info", text: "Running your queued message now \u2014 current run stopped." }
|
|
24816
|
+
});
|
|
24817
|
+
} else {
|
|
24818
|
+
dispatch2({
|
|
24819
|
+
type: "status:set",
|
|
24820
|
+
status: { kind: "warning", text: "No queued message to run \u2014 type one first, then Ctrl+X." }
|
|
24821
|
+
});
|
|
24822
|
+
}
|
|
24823
|
+
return;
|
|
24824
|
+
}
|
|
23865
24825
|
case "input:pasteImage": {
|
|
23866
|
-
const
|
|
23867
|
-
if (
|
|
24826
|
+
const path4 = readClipboardImage();
|
|
24827
|
+
if (path4 !== null) {
|
|
23868
24828
|
const sep = state.buffer.length > 0 && !/\s$/.test(state.buffer) ? " " : "";
|
|
23869
|
-
dispatch2({ type: "buffer:insert", text: `${sep}${
|
|
24829
|
+
dispatch2({ type: "buffer:insert", text: `${sep}${path4}` });
|
|
23870
24830
|
} else {
|
|
23871
24831
|
dispatch2({ type: "status:set", status: { kind: "warning", text: "No image on the clipboard." } });
|
|
23872
24832
|
}
|
|
@@ -23895,20 +24855,30 @@ function TerminalConsole(props) {
|
|
|
23895
24855
|
return;
|
|
23896
24856
|
}
|
|
23897
24857
|
}, { isActive: state.modal.kind === "none" && !agentsOpen });
|
|
24858
|
+
useInput3((_rawInput, key) => {
|
|
24859
|
+
if (key.tab && key.shift) cyclePermission();
|
|
24860
|
+
}, { isActive: state.modal.kind === "approval" });
|
|
23898
24861
|
const seeded = useRef3(false);
|
|
23899
|
-
|
|
24862
|
+
useEffect7(() => {
|
|
23900
24863
|
if (seeded.current) return;
|
|
23901
24864
|
seeded.current = true;
|
|
24865
|
+
const opening = conductor.permissionMode();
|
|
24866
|
+
if (opening !== "default") {
|
|
24867
|
+
dispatch2({
|
|
24868
|
+
type: "status:set",
|
|
24869
|
+
status: { kind: "warning", text: permissionModeStatusText(opening) }
|
|
24870
|
+
});
|
|
24871
|
+
}
|
|
23902
24872
|
if (initialInput && initialInput.trim().length > 0) {
|
|
23903
24873
|
void runTurn(initialInput);
|
|
23904
24874
|
}
|
|
23905
24875
|
}, []);
|
|
23906
|
-
const
|
|
24876
|
+
const allMessages = [...conductor.messages()];
|
|
24877
|
+
if (allMessages.length < visibleFrom.current) visibleFrom.current = 0;
|
|
24878
|
+
const liveMessages = allMessages.slice(visibleFrom.current);
|
|
23907
24879
|
const agentRuns = deriveAgentRuns(liveMessages);
|
|
23908
24880
|
const snapshot = projectSnapshot2(conductor, liveMessages, services);
|
|
23909
24881
|
const branch = useMemo2(() => readBranch(), []);
|
|
23910
|
-
const modalOpen = state.modal.kind !== "none";
|
|
23911
|
-
const maxItems = transcriptHeight(terminalRows, modalOpen, agentPanelRows(agentRuns));
|
|
23912
24882
|
const pendingMessages = conductor.pendingInputs().map((entry, index) => ({
|
|
23913
24883
|
id: `pending-${index}-${entry.mode}`,
|
|
23914
24884
|
mode: entry.mode,
|
|
@@ -23918,12 +24888,21 @@ function TerminalConsole(props) {
|
|
|
23918
24888
|
const SHOW_TOOL_ACTIVITY = false;
|
|
23919
24889
|
const runningTools = Object.values(toolExecutions).some((t) => t.status === "running");
|
|
23920
24890
|
const showTaskPanel = SHOW_TOOL_ACTIVITY && runningTools || pendingMessages.length > 0;
|
|
24891
|
+
const modalOpen = state.modal.kind !== "none";
|
|
24892
|
+
const streamingAnswerRows = liveAnswer.current !== null && answerText.current ? Math.min(6, answerText.current.split("\n").length + 1) : 0;
|
|
24893
|
+
const taskPanelRows = showTaskPanel ? 2 + Math.min(pendingMessages.length, 8) : 0;
|
|
24894
|
+
const workingIndicatorRows = state.busy ? 2 : 0;
|
|
24895
|
+
const maxItems = transcriptHeight(
|
|
24896
|
+
terminalRows,
|
|
24897
|
+
modalOpen,
|
|
24898
|
+
agentPanelRows(agentRuns) + streamingAnswerRows + taskPanelRows + workingIndicatorRows
|
|
24899
|
+
);
|
|
23921
24900
|
const providerCount = countProviders(conductor);
|
|
23922
24901
|
const lastSeenVersion = services?.settings.get("lastSeenVersion") ?? "";
|
|
23923
24902
|
const startupMap = useMemo2(
|
|
23924
24903
|
() => gatherStartup({
|
|
23925
24904
|
cwd: process.cwd(),
|
|
23926
|
-
home:
|
|
24905
|
+
home: homedir7(),
|
|
23927
24906
|
version: VERSION,
|
|
23928
24907
|
lastSeenVersion
|
|
23929
24908
|
}),
|
|
@@ -23932,8 +24911,8 @@ function TerminalConsole(props) {
|
|
|
23932
24911
|
const quietStartup = (services?.settings.get("quietStartup") ?? false) && !verbose;
|
|
23933
24912
|
const sweep = (services?.settings.get("logoSweep") ?? false) && !(services?.settings.get("reducedMotion") ?? false) && Boolean(process.stdout.isTTY);
|
|
23934
24913
|
const welcomeSeed = PINNED_WELCOME_SEED;
|
|
23935
|
-
const [welcomeName, setWelcomeName] =
|
|
23936
|
-
|
|
24914
|
+
const [welcomeName, setWelcomeName] = useState8(void 0);
|
|
24915
|
+
useEffect7(() => {
|
|
23937
24916
|
if (!services) return;
|
|
23938
24917
|
let live = true;
|
|
23939
24918
|
const provider = services.settings.get("defaultProvider");
|
|
@@ -23945,6 +24924,12 @@ function TerminalConsole(props) {
|
|
|
23945
24924
|
live = false;
|
|
23946
24925
|
};
|
|
23947
24926
|
}, [services]);
|
|
24927
|
+
const authedProviders = useAuthenticatedProviders(services, state.status);
|
|
24928
|
+
const boundModelId = conductor.snapshot().modelId;
|
|
24929
|
+
const boundProvider = boundModelId.includes("/") ? boundModelId.split("/")[0] : boundModelId;
|
|
24930
|
+
const modelAuthed = authedProviders === null || authedProviders.has(boundProvider);
|
|
24931
|
+
const bannerModelId = modelAuthed ? boundModelId : "no authenticated model \u2014 run /login";
|
|
24932
|
+
const statusBarSnapshot = modelAuthed || !snapshot.model ? snapshot : { ...snapshot, model: { ...snapshot.model, provider: "no model", id: "run /login" } };
|
|
23948
24933
|
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
23949
24934
|
agentsOpen ? (
|
|
23950
24935
|
// The drill-in agents view replaces the transcript while open; it owns
|
|
@@ -23964,7 +24949,7 @@ function TerminalConsole(props) {
|
|
|
23964
24949
|
Banner,
|
|
23965
24950
|
{
|
|
23966
24951
|
theme: adapter,
|
|
23967
|
-
modelId:
|
|
24952
|
+
modelId: bannerModelId,
|
|
23968
24953
|
workspace: process.cwd(),
|
|
23969
24954
|
version: VERSION,
|
|
23970
24955
|
verbose,
|
|
@@ -23978,6 +24963,23 @@ function TerminalConsole(props) {
|
|
|
23978
24963
|
variantSeed: welcomeSeed
|
|
23979
24964
|
}
|
|
23980
24965
|
),
|
|
24966
|
+
compactNote !== null ? /* @__PURE__ */ jsxs10(
|
|
24967
|
+
Box10,
|
|
24968
|
+
{
|
|
24969
|
+
flexDirection: "column",
|
|
24970
|
+
borderStyle: "round",
|
|
24971
|
+
borderColor: adapter.colors["borderMuted"],
|
|
24972
|
+
paddingX: 1,
|
|
24973
|
+
marginBottom: 1,
|
|
24974
|
+
children: [
|
|
24975
|
+
/* @__PURE__ */ jsx13(Text10, { children: adapter.color("accent", "\u25C6 Context condensed \u2014 fresh session, history summarized") }),
|
|
24976
|
+
compactNote.length > 0 ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
24977
|
+
/* @__PURE__ */ jsx13(Text10, { children: adapter.muted("Files carried into the new context:") }),
|
|
24978
|
+
compactNote.map((file, index) => /* @__PURE__ */ jsx13(Text10, { children: adapter.muted(` \xB7 ${file}`) }, index))
|
|
24979
|
+
] }) : /* @__PURE__ */ jsx13(Text10, { children: adapter.muted("No files re-attached; the summary digest carries the history.") })
|
|
24980
|
+
]
|
|
24981
|
+
}
|
|
24982
|
+
) : null,
|
|
23981
24983
|
/* @__PURE__ */ jsx13(
|
|
23982
24984
|
MessageList,
|
|
23983
24985
|
{
|
|
@@ -24001,7 +25003,14 @@ function TerminalConsole(props) {
|
|
|
24001
25003
|
pendingMessages
|
|
24002
25004
|
}
|
|
24003
25005
|
) : null,
|
|
24004
|
-
/* @__PURE__ */ jsx13(
|
|
25006
|
+
/* @__PURE__ */ jsx13(
|
|
25007
|
+
WorkingIndicator,
|
|
25008
|
+
{
|
|
25009
|
+
theme: adapter,
|
|
25010
|
+
busy: state.busy || conductor.snapshot().phase === "condensing",
|
|
25011
|
+
phase: conductor.snapshot().phase
|
|
25012
|
+
}
|
|
25013
|
+
),
|
|
24005
25014
|
/* @__PURE__ */ jsx13(
|
|
24006
25015
|
Composer,
|
|
24007
25016
|
{
|
|
@@ -24017,7 +25026,7 @@ function TerminalConsole(props) {
|
|
|
24017
25026
|
StatusBar,
|
|
24018
25027
|
{
|
|
24019
25028
|
theme: adapter,
|
|
24020
|
-
snapshot,
|
|
25029
|
+
snapshot: statusBarSnapshot,
|
|
24021
25030
|
branch,
|
|
24022
25031
|
providerCount,
|
|
24023
25032
|
status: state.status,
|
|
@@ -24065,7 +25074,7 @@ async function mountConsole(conductor, opts = {}) {
|
|
|
24065
25074
|
}
|
|
24066
25075
|
|
|
24067
25076
|
// src/boot/auth-vault.ts
|
|
24068
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
25077
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24069
25078
|
import { dirname as dirname5 } from "node:path";
|
|
24070
25079
|
import {
|
|
24071
25080
|
ensureFreshOAuthCredentials,
|
|
@@ -24089,9 +25098,9 @@ function normaliseRecord(value) {
|
|
|
24089
25098
|
}
|
|
24090
25099
|
return void 0;
|
|
24091
25100
|
}
|
|
24092
|
-
function readAuthFile(
|
|
25101
|
+
function readAuthFile(path4) {
|
|
24093
25102
|
try {
|
|
24094
|
-
const text =
|
|
25103
|
+
const text = readFileSync13(path4, "utf8");
|
|
24095
25104
|
const parsed = JSON.parse(text);
|
|
24096
25105
|
if (parsed === null || typeof parsed !== "object") return {};
|
|
24097
25106
|
const file = {};
|
|
@@ -24109,9 +25118,9 @@ function readAuthFile(path3) {
|
|
|
24109
25118
|
return {};
|
|
24110
25119
|
}
|
|
24111
25120
|
}
|
|
24112
|
-
function writeAuthFile(
|
|
24113
|
-
mkdirSync4(dirname5(
|
|
24114
|
-
writeFileSync7(
|
|
25121
|
+
function writeAuthFile(path4, data) {
|
|
25122
|
+
mkdirSync4(dirname5(path4), { recursive: true });
|
|
25123
|
+
writeFileSync7(path4, `${JSON.stringify(data, null, 2)}
|
|
24115
25124
|
`, { mode: 384 });
|
|
24116
25125
|
}
|
|
24117
25126
|
function toCredentials(record) {
|
|
@@ -24205,11 +25214,14 @@ function createAuthVault(authPath) {
|
|
|
24205
25214
|
};
|
|
24206
25215
|
}
|
|
24207
25216
|
|
|
25217
|
+
// src/boot/runners/repl-runner.ts
|
|
25218
|
+
init_server_mode();
|
|
25219
|
+
|
|
24208
25220
|
// src/boot/runners/session.ts
|
|
24209
25221
|
init_conductor2();
|
|
24210
|
-
import { existsSync as existsSync6, readFileSync as
|
|
24211
|
-
import { homedir as
|
|
24212
|
-
import { join as
|
|
25222
|
+
import { existsSync as existsSync6, readFileSync as readFileSync15 } from "node:fs";
|
|
25223
|
+
import { homedir as homedir8 } from "node:os";
|
|
25224
|
+
import { join as join20 } from "node:path";
|
|
24213
25225
|
init_capability_deck();
|
|
24214
25226
|
init_task_card();
|
|
24215
25227
|
init_workflow_card();
|
|
@@ -24240,7 +25252,7 @@ function argPreview(args) {
|
|
|
24240
25252
|
return ` (${oneLine2(String(text), 56)})`;
|
|
24241
25253
|
}
|
|
24242
25254
|
function buildActivity(messages) {
|
|
24243
|
-
const
|
|
25255
|
+
const out2 = [];
|
|
24244
25256
|
for (const message of messages) {
|
|
24245
25257
|
if (message.role !== "assistant") continue;
|
|
24246
25258
|
const content = message.content;
|
|
@@ -24248,14 +25260,50 @@ function buildActivity(messages) {
|
|
|
24248
25260
|
for (const part of content) {
|
|
24249
25261
|
const p = part;
|
|
24250
25262
|
if (p.type === "text" && typeof p.text === "string" && p.text.trim() || p.type === "thinking" && typeof p.thinking === "string" && p.thinking.trim()) {
|
|
24251
|
-
|
|
25263
|
+
out2.push({ tone: "reason", text: oneLine2(p.text ?? p.thinking) });
|
|
24252
25264
|
} else if (p.type === "toolCall" && typeof p.name === "string") {
|
|
24253
25265
|
const name = p.name.charAt(0).toUpperCase() + p.name.slice(1);
|
|
24254
|
-
|
|
25266
|
+
out2.push({ tone: "tool", text: `${name}${argPreview(p.arguments)}` });
|
|
24255
25267
|
}
|
|
24256
25268
|
}
|
|
24257
25269
|
}
|
|
24258
|
-
return
|
|
25270
|
+
return out2.slice(-14);
|
|
25271
|
+
}
|
|
25272
|
+
var MAX_PARALLEL_TASKS = (() => {
|
|
25273
|
+
const n = parseInt(process.env.INDUS_MAX_PARALLEL_TASKS ?? "", 10);
|
|
25274
|
+
return Number.isFinite(n) && n >= 1 ? n : 2;
|
|
25275
|
+
})();
|
|
25276
|
+
var MAX_REPORT_CHARS = (() => {
|
|
25277
|
+
const n = parseInt(process.env.INDUS_MAX_DELEGATE_REPORT_CHARS ?? "", 10);
|
|
25278
|
+
return Number.isFinite(n) && n >= 1e3 ? n : 48e3;
|
|
25279
|
+
})();
|
|
25280
|
+
var activeTasks = 0;
|
|
25281
|
+
var taskQueue = [];
|
|
25282
|
+
async function acquireTaskSlot() {
|
|
25283
|
+
if (activeTasks < MAX_PARALLEL_TASKS) {
|
|
25284
|
+
activeTasks++;
|
|
25285
|
+
} else {
|
|
25286
|
+
await new Promise((resolve8) => taskQueue.push(resolve8));
|
|
25287
|
+
}
|
|
25288
|
+
let released = false;
|
|
25289
|
+
return () => {
|
|
25290
|
+
if (released) return;
|
|
25291
|
+
released = true;
|
|
25292
|
+
const next = taskQueue.shift();
|
|
25293
|
+
if (next) next();
|
|
25294
|
+
else activeTasks--;
|
|
25295
|
+
};
|
|
25296
|
+
}
|
|
25297
|
+
function clampReport(report) {
|
|
25298
|
+
if (report.length <= MAX_REPORT_CHARS) return report;
|
|
25299
|
+
const head = Math.floor(MAX_REPORT_CHARS * 0.7);
|
|
25300
|
+
const tail = MAX_REPORT_CHARS - head;
|
|
25301
|
+
const omitted = report.length - MAX_REPORT_CHARS;
|
|
25302
|
+
return `${report.slice(0, head)}
|
|
25303
|
+
|
|
25304
|
+
\u2026[delegate report truncated \u2014 ${omitted} characters omitted to protect parent context]\u2026
|
|
25305
|
+
|
|
25306
|
+
${report.slice(report.length - tail)}`;
|
|
24259
25307
|
}
|
|
24260
25308
|
function finalAssistantText2(messages) {
|
|
24261
25309
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -24283,48 +25331,65 @@ function createDelegateRunner(opts) {
|
|
|
24283
25331
|
|
|
24284
25332
|
Context:
|
|
24285
25333
|
${request.context}` : request.objective;
|
|
24286
|
-
const
|
|
24287
|
-
|
|
24288
|
-
// `model` is defined here: the early-return above guaranteed it when
|
|
24289
|
-
// no `spawn` seam was given.
|
|
24290
|
-
model,
|
|
24291
|
-
systemPrompt: opts.system,
|
|
24292
|
-
// The sub-agent's deck — the `'authoring'` profile excludes the
|
|
24293
|
-
// `task` card, so the sub-agent cannot recurse into delegation.
|
|
24294
|
-
tools: opts.tools?.() ?? provisionDeck("authoring", { cwd: opts.cwd }).tools()
|
|
24295
|
-
},
|
|
24296
|
-
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {}
|
|
24297
|
-
});
|
|
24298
|
-
const onAbort = () => agent.abort();
|
|
24299
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
24300
|
-
let lastSignature = "";
|
|
24301
|
-
const reportProgress = () => {
|
|
24302
|
-
if (!onProgress) return;
|
|
24303
|
-
const tokens = sumTokens(agent.state.messages);
|
|
24304
|
-
const activity = buildActivity(agent.state.messages);
|
|
24305
|
-
const signature2 = `${tokens}:${activity.length}`;
|
|
24306
|
-
if (signature2 !== lastSignature) {
|
|
24307
|
-
lastSignature = signature2;
|
|
24308
|
-
onProgress({ tokens, activity });
|
|
24309
|
-
}
|
|
24310
|
-
};
|
|
24311
|
-
const offProgress = onProgress ? agent.subscribe?.(reportProgress) : void 0;
|
|
25334
|
+
const gatewayBaseUrls = await opts.getGatewayBaseUrls?.();
|
|
25335
|
+
const releaseSlot = await acquireTaskSlot();
|
|
24312
25336
|
try {
|
|
24313
|
-
|
|
24314
|
-
|
|
24315
|
-
|
|
24316
|
-
|
|
24317
|
-
|
|
25337
|
+
if (signal?.aborted) {
|
|
25338
|
+
return { ok: false, report: "delegation aborted" };
|
|
25339
|
+
}
|
|
25340
|
+
let agent = opts.spawn?.(request.objective, request.context);
|
|
25341
|
+
if (agent === void 0) {
|
|
25342
|
+
const tools = opts.tools?.() ?? provisionDeck("authoring", { cwd: opts.cwd }).tools();
|
|
25343
|
+
agent = new Agent3({
|
|
25344
|
+
initialState: {
|
|
25345
|
+
// `model` is defined here: the early-return above guaranteed it when
|
|
25346
|
+
// no `spawn` seam was given. In server mode, route it through the
|
|
25347
|
+
// gateway (freshly resolved above) rather than the raw provider url.
|
|
25348
|
+
model: withGatewayBaseUrl(model, gatewayBaseUrls),
|
|
25349
|
+
systemPrompt: opts.system,
|
|
25350
|
+
tools
|
|
25351
|
+
},
|
|
25352
|
+
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {},
|
|
25353
|
+
// Gate the sub-agent's inner tool loop with the parent session's live
|
|
25354
|
+
// policy (rules + current mode). Resolver-less: `ask` denies — a
|
|
25355
|
+
// sub-agent cannot prompt the user — while deny rules, plan mode, and
|
|
25356
|
+
// the catastrophic-bash blocklist are enforced per inner tool call.
|
|
25357
|
+
...opts.permissionPolicy !== void 0 ? { canUseTool: createSubagentPermissionGate(opts.permissionPolicy, tools) } : {}
|
|
25358
|
+
});
|
|
25359
|
+
}
|
|
25360
|
+
const onAbort = () => agent.abort();
|
|
25361
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
25362
|
+
let lastSignature = "";
|
|
25363
|
+
const reportProgress = () => {
|
|
25364
|
+
if (!onProgress) return;
|
|
25365
|
+
const tokens = sumTokens(agent.state.messages);
|
|
25366
|
+
const activity = buildActivity(agent.state.messages);
|
|
25367
|
+
const signature2 = `${tokens}:${activity.length}`;
|
|
25368
|
+
if (signature2 !== lastSignature) {
|
|
25369
|
+
lastSignature = signature2;
|
|
25370
|
+
onProgress({ tokens, activity });
|
|
25371
|
+
}
|
|
25372
|
+
};
|
|
25373
|
+
const offProgress = onProgress ? agent.subscribe?.(reportProgress) : void 0;
|
|
25374
|
+
try {
|
|
25375
|
+
await agent.prompt(objective);
|
|
25376
|
+
reportProgress();
|
|
25377
|
+
} catch (cause) {
|
|
25378
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
25379
|
+
return { ok: false, report: clampReport(message || "delegation failed") };
|
|
25380
|
+
} finally {
|
|
25381
|
+
offProgress?.();
|
|
25382
|
+
signal?.removeEventListener("abort", onAbort);
|
|
25383
|
+
}
|
|
25384
|
+
const error = agent.state.error;
|
|
25385
|
+
const report = finalAssistantText2(agent.state.messages);
|
|
25386
|
+
return {
|
|
25387
|
+
ok: error === void 0 && report.length > 0,
|
|
25388
|
+
report: clampReport(error ?? (report || "(no output)"))
|
|
25389
|
+
};
|
|
24318
25390
|
} finally {
|
|
24319
|
-
|
|
24320
|
-
signal?.removeEventListener("abort", onAbort);
|
|
25391
|
+
releaseSlot();
|
|
24321
25392
|
}
|
|
24322
|
-
const error = agent.state.error;
|
|
24323
|
-
const report = finalAssistantText2(agent.state.messages);
|
|
24324
|
-
return {
|
|
24325
|
-
ok: error === void 0 && report.length > 0,
|
|
24326
|
-
report: error ?? (report || "(no output)")
|
|
24327
|
-
};
|
|
24328
25393
|
}
|
|
24329
25394
|
};
|
|
24330
25395
|
}
|
|
@@ -24435,7 +25500,7 @@ var CheckpointStore = class {
|
|
|
24435
25500
|
snapshotFor(nodeId) {
|
|
24436
25501
|
const paths = this.byNode.get(nodeId);
|
|
24437
25502
|
if (paths === void 0) return [];
|
|
24438
|
-
return [...paths].map(([
|
|
25503
|
+
return [...paths].map(([path4, previous]) => ({ path: path4, previous }));
|
|
24439
25504
|
}
|
|
24440
25505
|
/** Whether a node has ANY recorded file snapshot (the picker's restore gate). */
|
|
24441
25506
|
hasSnapshot(nodeId) {
|
|
@@ -24460,15 +25525,15 @@ var CheckpointStore = class {
|
|
|
24460
25525
|
restore(nodeId) {
|
|
24461
25526
|
const snapshots = this.snapshotFor(nodeId);
|
|
24462
25527
|
const restored = [];
|
|
24463
|
-
for (const { path:
|
|
25528
|
+
for (const { path: path4, previous } of snapshots) {
|
|
24464
25529
|
try {
|
|
24465
25530
|
if (previous === null) {
|
|
24466
|
-
rmSync(
|
|
25531
|
+
rmSync(path4, { force: true });
|
|
24467
25532
|
} else {
|
|
24468
|
-
mkdirSync5(dirname6(
|
|
24469
|
-
writeFileSync8(
|
|
25533
|
+
mkdirSync5(dirname6(path4), { recursive: true });
|
|
25534
|
+
writeFileSync8(path4, previous, "utf8");
|
|
24470
25535
|
}
|
|
24471
|
-
restored.push(
|
|
25536
|
+
restored.push(path4);
|
|
24472
25537
|
} catch {
|
|
24473
25538
|
}
|
|
24474
25539
|
}
|
|
@@ -24527,8 +25592,8 @@ function concatAddonTools(deck, bundle) {
|
|
|
24527
25592
|
|
|
24528
25593
|
// src/boot/runners/memdir.ts
|
|
24529
25594
|
init_capability_deck();
|
|
24530
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as
|
|
24531
|
-
import { join as
|
|
25595
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
|
|
25596
|
+
import { join as join19 } from "node:path";
|
|
24532
25597
|
var MEMORY_ENTRYPOINT = "MEMORY.md";
|
|
24533
25598
|
var MAX_ENTRYPOINT_LINES = 200;
|
|
24534
25599
|
var MAX_ENTRYPOINT_BYTES = 25e3;
|
|
@@ -24554,19 +25619,19 @@ function truncateEntrypointContent(raw) {
|
|
|
24554
25619
|
}
|
|
24555
25620
|
function memoryDirFor(workspace, cwd) {
|
|
24556
25621
|
const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24557
|
-
return
|
|
25622
|
+
return join19(workspace.profileDir, "memory", `--${slug}--`);
|
|
24558
25623
|
}
|
|
24559
25624
|
var DiskMemoryStore = class {
|
|
24560
25625
|
constructor(memDir) {
|
|
24561
25626
|
this.memDir = memDir;
|
|
24562
|
-
this.file =
|
|
25627
|
+
this.file = join19(memDir, MEMORY_ENTRYPOINT);
|
|
24563
25628
|
}
|
|
24564
25629
|
memDir;
|
|
24565
25630
|
file;
|
|
24566
25631
|
/** The current note, or `""` when no file has been written yet. */
|
|
24567
25632
|
read() {
|
|
24568
25633
|
try {
|
|
24569
|
-
return existsSync5(this.file) ?
|
|
25634
|
+
return existsSync5(this.file) ? readFileSync14(this.file, "utf8") : "";
|
|
24570
25635
|
} catch {
|
|
24571
25636
|
return "";
|
|
24572
25637
|
}
|
|
@@ -24587,9 +25652,9 @@ ${line}`;
|
|
|
24587
25652
|
function loadMemoryDoc(memDir) {
|
|
24588
25653
|
let raw;
|
|
24589
25654
|
try {
|
|
24590
|
-
const file =
|
|
25655
|
+
const file = join19(memDir, MEMORY_ENTRYPOINT);
|
|
24591
25656
|
if (!existsSync5(file)) return void 0;
|
|
24592
|
-
raw =
|
|
25657
|
+
raw = readFileSync14(file, "utf8");
|
|
24593
25658
|
} catch {
|
|
24594
25659
|
return void 0;
|
|
24595
25660
|
}
|
|
@@ -24601,11 +25666,13 @@ function loadMemoryDoc(memDir) {
|
|
|
24601
25666
|
// src/boot/runners/session.ts
|
|
24602
25667
|
init_briefing();
|
|
24603
25668
|
init_window_budget();
|
|
25669
|
+
init_server_token();
|
|
25670
|
+
init_server_mode();
|
|
24604
25671
|
function authenticatedProviders(ctx) {
|
|
24605
25672
|
try {
|
|
24606
|
-
const
|
|
24607
|
-
if (!existsSync6(
|
|
24608
|
-
const data = JSON.parse(
|
|
25673
|
+
const path4 = ctx.workspace.authPath;
|
|
25674
|
+
if (!existsSync6(path4)) return [];
|
|
25675
|
+
const data = JSON.parse(readFileSync15(path4, "utf8"));
|
|
24609
25676
|
return Object.keys(data).filter((id) => {
|
|
24610
25677
|
const accounts = data[id];
|
|
24611
25678
|
return id.length > 0 && accounts !== null && typeof accounts === "object" && Object.keys(accounts).length > 0;
|
|
@@ -24622,8 +25689,18 @@ var PREFERRED_DEFAULT = {
|
|
|
24622
25689
|
"claude-sonnet-4-0",
|
|
24623
25690
|
"claude-opus-4-5"
|
|
24624
25691
|
],
|
|
24625
|
-
openai: ["gpt-5.1", "gpt-4.1", "gpt-4o"]
|
|
25692
|
+
openai: ["gpt-5.1", "gpt-4.1", "gpt-4o"],
|
|
25693
|
+
minimax: ["MiniMax-M3", "MiniMax-M2.7", "MiniMax-M2.5"],
|
|
25694
|
+
sarvam: ["sarvam-105b", "sarvam-30b"]
|
|
24626
25695
|
};
|
|
25696
|
+
function hasServerSessionSync() {
|
|
25697
|
+
try {
|
|
25698
|
+
const token = JSON.parse(readFileSync15(TOKEN_FILE, "utf8"));
|
|
25699
|
+
return typeof token.expires_at === "string" && new Date(token.expires_at).getTime() - Date.now() > 5 * 60 * 1e3;
|
|
25700
|
+
} catch {
|
|
25701
|
+
return false;
|
|
25702
|
+
}
|
|
25703
|
+
}
|
|
24627
25704
|
function providerDefaultModel(catalog, provider) {
|
|
24628
25705
|
const cards = catalog.byProvider(provider);
|
|
24629
25706
|
if (cards.length === 0) return void 0;
|
|
@@ -24643,6 +25720,12 @@ function resolveModelId(ctx) {
|
|
|
24643
25720
|
const id = providerDefaultModel(catalog, provider);
|
|
24644
25721
|
if (id !== void 0) return id;
|
|
24645
25722
|
}
|
|
25723
|
+
if (hasServerSessionSync()) {
|
|
25724
|
+
for (const provider of serverTierProviders()) {
|
|
25725
|
+
const id = providerDefaultModel(catalog, provider);
|
|
25726
|
+
if (id !== void 0) return id;
|
|
25727
|
+
}
|
|
25728
|
+
}
|
|
24646
25729
|
const card = new ModelMatcher(catalog).resolve({});
|
|
24647
25730
|
return card?.id ?? "";
|
|
24648
25731
|
}
|
|
@@ -24667,9 +25750,9 @@ var PROVIDER_ENV = {
|
|
|
24667
25750
|
};
|
|
24668
25751
|
function primeProviderEnv(ctx) {
|
|
24669
25752
|
try {
|
|
24670
|
-
const
|
|
24671
|
-
if (!existsSync6(
|
|
24672
|
-
const data = JSON.parse(
|
|
25753
|
+
const path4 = ctx.workspace.authPath;
|
|
25754
|
+
if (!existsSync6(path4)) return;
|
|
25755
|
+
const data = JSON.parse(readFileSync15(path4, "utf8"));
|
|
24673
25756
|
for (const [provider, accounts] of Object.entries(data)) {
|
|
24674
25757
|
if (provider.startsWith("_") || accounts === null || typeof accounts !== "object") continue;
|
|
24675
25758
|
const envVar = PROVIDER_ENV[provider];
|
|
@@ -24684,7 +25767,7 @@ function primeProviderEnv(ctx) {
|
|
|
24684
25767
|
} catch {
|
|
24685
25768
|
}
|
|
24686
25769
|
}
|
|
24687
|
-
function buildKeyResolver(vault, requestedAccount) {
|
|
25770
|
+
function buildKeyResolver(ctx, vault, requestedAccount) {
|
|
24688
25771
|
return async (provider) => {
|
|
24689
25772
|
try {
|
|
24690
25773
|
const candidates = [
|
|
@@ -24697,6 +25780,8 @@ function buildKeyResolver(vault, requestedAccount) {
|
|
|
24697
25780
|
const key = await vault.readUsableKey(provider, account);
|
|
24698
25781
|
if (key) return key;
|
|
24699
25782
|
}
|
|
25783
|
+
const server = await resolveServerMode(ctx, provider, vault);
|
|
25784
|
+
if (server.serverMode && server.token) return server.token;
|
|
24700
25785
|
return void 0;
|
|
24701
25786
|
} catch {
|
|
24702
25787
|
return void 0;
|
|
@@ -24709,7 +25794,7 @@ function resolveThinkingLevel(raw) {
|
|
|
24709
25794
|
}
|
|
24710
25795
|
function resolveText(value) {
|
|
24711
25796
|
try {
|
|
24712
|
-
if (existsSync6(value)) return
|
|
25797
|
+
if (existsSync6(value)) return readFileSync15(value, "utf8");
|
|
24713
25798
|
} catch {
|
|
24714
25799
|
}
|
|
24715
25800
|
return value;
|
|
@@ -24717,8 +25802,8 @@ function resolveText(value) {
|
|
|
24717
25802
|
var PROFILE_DIR2 = ".indusagi";
|
|
24718
25803
|
function skillRoots2(cwd) {
|
|
24719
25804
|
return [
|
|
24720
|
-
{ dir:
|
|
24721
|
-
{ dir:
|
|
25805
|
+
{ dir: join20(cwd, PROFILE_DIR2, "skills"), origin: "project" },
|
|
25806
|
+
{ dir: join20(homedir8(), PROFILE_DIR2, "skills"), origin: "user" }
|
|
24722
25807
|
];
|
|
24723
25808
|
}
|
|
24724
25809
|
function gatherModelSkills(cwd) {
|
|
@@ -24750,7 +25835,7 @@ function selectTools(cwd, inv, runner, memoryStore, checkpoint, workflowRunner)
|
|
|
24750
25835
|
}
|
|
24751
25836
|
function composeSystem(tools, inv, cwd, skills = [], memoryDoc) {
|
|
24752
25837
|
const contextDocs = [
|
|
24753
|
-
...gatherContextDocs(cwd,
|
|
25838
|
+
...gatherContextDocs(cwd, homedir8()),
|
|
24754
25839
|
...memoryDoc ? [memoryDoc] : []
|
|
24755
25840
|
];
|
|
24756
25841
|
const base = inv.system !== void 0 ? resolveText(inv.system) : composeBriefing({ tools, contextDocs, skills });
|
|
@@ -24768,9 +25853,9 @@ async function loadMcpTools(inv, cwd) {
|
|
|
24768
25853
|
console.error = () => {
|
|
24769
25854
|
};
|
|
24770
25855
|
try {
|
|
24771
|
-
for (const
|
|
25856
|
+
for (const path4 of paths) {
|
|
24772
25857
|
try {
|
|
24773
|
-
const servers = loadMCPConfig2(
|
|
25858
|
+
const servers = loadMCPConfig2(path4);
|
|
24774
25859
|
if (servers.length === 0) continue;
|
|
24775
25860
|
const pool = new MCPClientPool2({ servers });
|
|
24776
25861
|
await pool.connectAll();
|
|
@@ -24789,7 +25874,7 @@ async function loadMcpTools(inv, cwd) {
|
|
|
24789
25874
|
}
|
|
24790
25875
|
function sessionScopeDir(sessionsRoot, cwd) {
|
|
24791
25876
|
const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24792
|
-
return
|
|
25877
|
+
return join20(sessionsRoot, `--${slug}--`);
|
|
24793
25878
|
}
|
|
24794
25879
|
function lastUserTurnStart(messages) {
|
|
24795
25880
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -24799,7 +25884,11 @@ function lastUserTurnStart(messages) {
|
|
|
24799
25884
|
}
|
|
24800
25885
|
var condenseTranscript = async (messages, opts) => {
|
|
24801
25886
|
const model = opts?.model;
|
|
24802
|
-
const deps = model ? {
|
|
25887
|
+
const deps = model ? {
|
|
25888
|
+
model,
|
|
25889
|
+
...opts?.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
|
|
25890
|
+
...opts?.signal !== void 0 ? { signal: opts.signal } : {}
|
|
25891
|
+
} : {};
|
|
24803
25892
|
const cleared = clearStaleToolResults(messages);
|
|
24804
25893
|
if (opts?.force) {
|
|
24805
25894
|
const cut = lastUserTurnStart(cleared);
|
|
@@ -24847,10 +25936,8 @@ function readOnlyNamesFromDeck(tools) {
|
|
|
24847
25936
|
}
|
|
24848
25937
|
return names;
|
|
24849
25938
|
}
|
|
24850
|
-
function buildPermissionGate(
|
|
24851
|
-
|
|
24852
|
-
const mode = resolveDefaultMode(store);
|
|
24853
|
-
if (rules.length === 0 && (mode === "default" || mode === "bypass") && !planReachable) {
|
|
25939
|
+
function buildPermissionGate(rules, mode, tools, planReachable = false) {
|
|
25940
|
+
if (rules.length === 0 && mode === "bypass" && !planReachable) {
|
|
24854
25941
|
return void 0;
|
|
24855
25942
|
}
|
|
24856
25943
|
const readOnlyToolNames = readOnlyNamesFromDeck(tools);
|
|
@@ -24860,9 +25947,17 @@ function buildPermissionGate(store, tools, planReachable = false) {
|
|
|
24860
25947
|
// The conductor's stable approval delegate: denies until the interactive
|
|
24861
25948
|
// console installs a resolver via setApprovalResolver, then routes `ask`.
|
|
24862
25949
|
...requestApproval !== void 0 ? { requestApproval } : {},
|
|
25950
|
+
// Session-scoped memory for `allow-always`: push into the SAME live array
|
|
25951
|
+
// the gate (and the sub-agent gates) re-scan per call. Never persisted.
|
|
25952
|
+
appendAllowRule: (rule) => rules.push(rule),
|
|
24863
25953
|
readOnlyToolNames
|
|
24864
25954
|
});
|
|
24865
25955
|
}
|
|
25956
|
+
function resolveOpeningMode(inv, store) {
|
|
25957
|
+
const raw = inv.flags["permission-mode"];
|
|
25958
|
+
if (typeof raw === "string" && isPermissionMode(raw)) return raw;
|
|
25959
|
+
return resolveDefaultMode(store);
|
|
25960
|
+
}
|
|
24866
25961
|
async function buildSessionConductor(ctx) {
|
|
24867
25962
|
primeProviderEnv(ctx);
|
|
24868
25963
|
const inv = ctx.invocation;
|
|
@@ -24873,12 +25968,35 @@ async function buildSessionConductor(ctx) {
|
|
|
24873
25968
|
const memDir = memoryDirFor(ctx.workspace, cwd);
|
|
24874
25969
|
const memoryStore = new DiskMemoryStore(memDir);
|
|
24875
25970
|
const memoryDoc = loadMemoryDoc(memDir);
|
|
24876
|
-
const
|
|
25971
|
+
const vault = createAuthVault(ctx.workspace.authPath);
|
|
25972
|
+
const getApiKey = buildKeyResolver(ctx, vault, inv.account);
|
|
25973
|
+
const gatewayBaseUrls = await resolveServerGatewayUrls(ctx, vault);
|
|
25974
|
+
const settings = PreferenceStore.fromWorkspace(ctx.workspace, cwd);
|
|
25975
|
+
const permissionRules = gatherPermissionRules(settings);
|
|
25976
|
+
const permissionMode = resolveOpeningMode(inv, settings);
|
|
25977
|
+
let liveConductor;
|
|
25978
|
+
const subagentPolicy = {
|
|
25979
|
+
rules: permissionRules,
|
|
25980
|
+
mode: () => liveConductor?.permissionMode() ?? permissionMode
|
|
25981
|
+
};
|
|
24877
25982
|
const surveyBriefing = composeBriefing({
|
|
24878
25983
|
tools: provisionDeck("authoring", { cwd }).tools()
|
|
24879
25984
|
});
|
|
24880
|
-
const runner = createDelegateRunner({
|
|
24881
|
-
|
|
25985
|
+
const runner = createDelegateRunner({
|
|
25986
|
+
modelId,
|
|
25987
|
+
getApiKey,
|
|
25988
|
+
system: surveyBriefing,
|
|
25989
|
+
cwd,
|
|
25990
|
+
getGatewayBaseUrls: () => resolveServerGatewayUrls(ctx, vault),
|
|
25991
|
+
permissionPolicy: subagentPolicy
|
|
25992
|
+
});
|
|
25993
|
+
const workflowRunner = createWorkflowAgentRunner({
|
|
25994
|
+
modelId,
|
|
25995
|
+
getApiKey,
|
|
25996
|
+
cwd,
|
|
25997
|
+
getGatewayBaseUrls: () => resolveServerGatewayUrls(ctx, vault),
|
|
25998
|
+
permissionPolicy: subagentPolicy
|
|
25999
|
+
});
|
|
24882
26000
|
const addons = await buildAddonHost(ctx);
|
|
24883
26001
|
const checkpoint = createCheckpointStore();
|
|
24884
26002
|
const deck = [
|
|
@@ -24890,11 +26008,9 @@ async function buildSessionConductor(ctx) {
|
|
|
24890
26008
|
const system = composeSystem(tools, inv, cwd, skills, memoryDoc);
|
|
24891
26009
|
const thinking = resolveThinkingLevel(inv.thinking);
|
|
24892
26010
|
const fallbackModelId = inv.fallbackModelId;
|
|
24893
|
-
const settings = PreferenceStore.fromWorkspace(ctx.workspace, cwd);
|
|
24894
|
-
const permissionMode = resolveDefaultMode(settings);
|
|
24895
26011
|
const planReachable = inv.mode === "repl";
|
|
24896
|
-
const canUseTool = buildPermissionGate(
|
|
24897
|
-
|
|
26012
|
+
const canUseTool = buildPermissionGate(permissionRules, permissionMode, tools, planReachable);
|
|
26013
|
+
const conductor = createSessionConductor(
|
|
24898
26014
|
{
|
|
24899
26015
|
modelId,
|
|
24900
26016
|
tools,
|
|
@@ -24912,12 +26028,19 @@ async function buildSessionConductor(ctx) {
|
|
|
24912
26028
|
...canUseTool !== void 0 ? { canUseTool } : {},
|
|
24913
26029
|
...thinking !== void 0 ? { thinking } : {},
|
|
24914
26030
|
...workspace ? { workspace } : {},
|
|
24915
|
-
...fallbackModelId !== void 0 ? { fallbackModelId } : {}
|
|
26031
|
+
...fallbackModelId !== void 0 ? { fallbackModelId } : {},
|
|
26032
|
+
// When server mode is active for the bound model's provider, hand the
|
|
26033
|
+
// conductor the gateway base url. A4 (`conductor.ts`) clones `card.model`
|
|
26034
|
+
// with this `baseUrl` so the existing model card routes through the indus
|
|
26035
|
+
// gateway; absent (the local-key path) the conductor binds the card as-is.
|
|
26036
|
+
...Object.keys(gatewayBaseUrls).length > 0 ? { gatewayBaseUrls } : {}
|
|
24916
26037
|
},
|
|
24917
26038
|
// The live condense hook: `/compact` and auto-compaction fold older turns
|
|
24918
26039
|
// into a digest. (Tests that build conductors directly keep the no-op default.)
|
|
24919
26040
|
{ condense: condenseTranscript }
|
|
24920
26041
|
);
|
|
26042
|
+
liveConductor = conductor;
|
|
26043
|
+
return conductor;
|
|
24921
26044
|
}
|
|
24922
26045
|
function oneshotPrompts(ctx) {
|
|
24923
26046
|
const prompts = [];
|
|
@@ -24929,9 +26052,10 @@ function oneshotPrompts(ctx) {
|
|
|
24929
26052
|
}
|
|
24930
26053
|
|
|
24931
26054
|
// src/boot/runners/repl-runner.ts
|
|
24932
|
-
var
|
|
26055
|
+
var EXIT_OK3 = 0;
|
|
24933
26056
|
function buildOverlayServices(ctx, conductor) {
|
|
24934
26057
|
const cwd = ctx.invocation.cwd ?? process.cwd();
|
|
26058
|
+
const vault = createAuthVault(ctx.workspace.authPath);
|
|
24935
26059
|
return {
|
|
24936
26060
|
conductor,
|
|
24937
26061
|
settings: PreferenceStore.fromWorkspace(ctx.workspace, cwd),
|
|
@@ -24941,7 +26065,11 @@ function buildOverlayServices(ctx, conductor) {
|
|
|
24941
26065
|
listLoginProviders,
|
|
24942
26066
|
startOAuthLogin,
|
|
24943
26067
|
openLoginUrl,
|
|
24944
|
-
vault
|
|
26068
|
+
vault,
|
|
26069
|
+
async refreshGatewayRouting() {
|
|
26070
|
+
const map = await resolveServerGatewayUrls(ctx, vault);
|
|
26071
|
+
conductor.updateGatewayBaseUrls(map);
|
|
26072
|
+
}
|
|
24945
26073
|
};
|
|
24946
26074
|
}
|
|
24947
26075
|
function toResumeRef(row) {
|
|
@@ -25018,7 +26146,7 @@ var replRunner = {
|
|
|
25018
26146
|
conductor,
|
|
25019
26147
|
initialInput === void 0 ? { services } : { initialInput, services }
|
|
25020
26148
|
);
|
|
25021
|
-
return
|
|
26149
|
+
return EXIT_OK3;
|
|
25022
26150
|
}
|
|
25023
26151
|
};
|
|
25024
26152
|
|
|
@@ -25059,7 +26187,7 @@ var oneshotRunner = {
|
|
|
25059
26187
|
};
|
|
25060
26188
|
|
|
25061
26189
|
// src/boot/runners/link-runner.ts
|
|
25062
|
-
var
|
|
26190
|
+
var EXIT_OK4 = 0;
|
|
25063
26191
|
var STDOUT2 = {
|
|
25064
26192
|
write(chunk, cb) {
|
|
25065
26193
|
return process.stdout.write(chunk, cb);
|
|
@@ -25077,7 +26205,7 @@ var linkRunner = {
|
|
|
25077
26205
|
out: STDOUT2
|
|
25078
26206
|
});
|
|
25079
26207
|
await server.done;
|
|
25080
|
-
return
|
|
26208
|
+
return EXIT_OK4;
|
|
25081
26209
|
}
|
|
25082
26210
|
};
|
|
25083
26211
|
|
|
@@ -25093,13 +26221,13 @@ function selectRunner(inv) {
|
|
|
25093
26221
|
}
|
|
25094
26222
|
|
|
25095
26223
|
// src/boot/boot.ts
|
|
25096
|
-
var
|
|
25097
|
-
var
|
|
25098
|
-
function seedContext(
|
|
26224
|
+
var EXIT_OK5 = 0;
|
|
26225
|
+
var EXIT_FAILURE2 = 1;
|
|
26226
|
+
function seedContext(argv2) {
|
|
25099
26227
|
const workspace = createWorkspace();
|
|
25100
|
-
const invocation = tokenizeInvocation(
|
|
26228
|
+
const invocation = tokenizeInvocation(argv2);
|
|
25101
26229
|
return {
|
|
25102
|
-
argv,
|
|
26230
|
+
argv: argv2,
|
|
25103
26231
|
workspace,
|
|
25104
26232
|
brand: BRAND,
|
|
25105
26233
|
invocation,
|
|
@@ -25136,7 +26264,7 @@ async function runCredential(ctx) {
|
|
|
25136
26264
|
`);
|
|
25137
26265
|
return EXIT_CREDENTIAL_FAULT;
|
|
25138
26266
|
}
|
|
25139
|
-
return
|
|
26267
|
+
return EXIT_OK5;
|
|
25140
26268
|
}
|
|
25141
26269
|
async function runPackage(ctx) {
|
|
25142
26270
|
const result = await runPackageCommand(ctx.argv, {
|
|
@@ -25145,30 +26273,34 @@ async function runPackage(ctx) {
|
|
|
25145
26273
|
if (!result.handled) {
|
|
25146
26274
|
return void 0;
|
|
25147
26275
|
}
|
|
25148
|
-
return result.code ??
|
|
26276
|
+
return result.code ?? EXIT_OK5;
|
|
25149
26277
|
}
|
|
25150
|
-
async function boot(
|
|
25151
|
-
const seeded = seedContext(
|
|
26278
|
+
async function boot(argv2) {
|
|
26279
|
+
const seeded = seedContext(argv2);
|
|
25152
26280
|
const credential = await runCredential(seeded);
|
|
25153
26281
|
if (credential !== void 0) {
|
|
25154
26282
|
return credential;
|
|
25155
26283
|
}
|
|
26284
|
+
const login = await runLogin(seeded);
|
|
26285
|
+
if (login !== void 0) {
|
|
26286
|
+
return login;
|
|
26287
|
+
}
|
|
25156
26288
|
const pkg = await runPackage(seeded);
|
|
25157
26289
|
if (pkg !== void 0) {
|
|
25158
26290
|
return pkg;
|
|
25159
26291
|
}
|
|
25160
26292
|
if (wantsHelp(seeded.invocation)) {
|
|
25161
26293
|
renderHelp();
|
|
25162
|
-
return
|
|
26294
|
+
return EXIT_OK5;
|
|
25163
26295
|
}
|
|
25164
26296
|
if (wantsVersion(seeded.invocation)) {
|
|
25165
26297
|
renderVersion();
|
|
25166
|
-
return
|
|
26298
|
+
return EXIT_OK5;
|
|
25167
26299
|
}
|
|
25168
26300
|
if (seeded.invocation.listModels) {
|
|
25169
26301
|
const filter = seeded.invocation.listModelsFilter;
|
|
25170
26302
|
printModelCatalog(void 0, filter !== void 0 ? { search: filter } : {});
|
|
25171
|
-
return
|
|
26303
|
+
return EXIT_OK5;
|
|
25172
26304
|
}
|
|
25173
26305
|
const ctx = await runStages(seeded);
|
|
25174
26306
|
try {
|
|
@@ -25178,19 +26310,47 @@ async function boot(argv) {
|
|
|
25178
26310
|
const message = error instanceof Error ? error.message : String(error);
|
|
25179
26311
|
process.stderr.write(`${BRAND.name}: ${message}
|
|
25180
26312
|
`);
|
|
25181
|
-
return
|
|
26313
|
+
return EXIT_FAILURE2;
|
|
25182
26314
|
} finally {
|
|
25183
26315
|
await drainClosables(ctx);
|
|
25184
26316
|
}
|
|
25185
26317
|
}
|
|
25186
26318
|
|
|
26319
|
+
// src/boot/heap.ts
|
|
26320
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
26321
|
+
import { argv, env, execArgv, execPath, exit } from "node:process";
|
|
26322
|
+
function targetHeapMb() {
|
|
26323
|
+
const raw = parseInt(env.INDUS_MAX_HEAP_MB ?? "", 10);
|
|
26324
|
+
if (Number.isFinite(raw)) return Math.max(0, raw);
|
|
26325
|
+
return 4096;
|
|
26326
|
+
}
|
|
26327
|
+
function alreadyRaised() {
|
|
26328
|
+
return env.INDUS_HEAP_BOOSTED === "1" || (env.NODE_OPTIONS ?? "").includes("--max-old-space-size") || execArgv.some(
|
|
26329
|
+
(a) => a.startsWith("--max-old-space-size") || a.startsWith("--max_old_space_size")
|
|
26330
|
+
);
|
|
26331
|
+
}
|
|
26332
|
+
function ensureHeapHeadroom() {
|
|
26333
|
+
const mb = targetHeapMb();
|
|
26334
|
+
if (mb === 0 || alreadyRaised()) return;
|
|
26335
|
+
const entry = argv[1];
|
|
26336
|
+
if (!entry) return;
|
|
26337
|
+
const result = spawnSync4(
|
|
26338
|
+
execPath,
|
|
26339
|
+
[`--max-old-space-size=${mb}`, ...execArgv, entry, ...argv.slice(2)],
|
|
26340
|
+
{ stdio: "inherit", env: { ...env, INDUS_HEAP_BOOSTED: "1" } }
|
|
26341
|
+
);
|
|
26342
|
+
if (result.error) return;
|
|
26343
|
+
if (typeof result.status === "number") exit(result.status);
|
|
26344
|
+
exit(result.signal ? 1 : 0);
|
|
26345
|
+
}
|
|
26346
|
+
|
|
25187
26347
|
// src/entry.ts
|
|
25188
26348
|
var MCP_NOISE_MARKER = "[MCP]";
|
|
25189
26349
|
function installMcpNoiseFilter() {
|
|
25190
26350
|
const self = installMcpNoiseFilter;
|
|
25191
26351
|
if (self.installed) return;
|
|
25192
26352
|
self.installed = true;
|
|
25193
|
-
if (
|
|
26353
|
+
if (env2[BRAND.envDebug]) return;
|
|
25194
26354
|
const carriesMcpNoise = (args) => typeof args[0] === "string" && args[0].includes(MCP_NOISE_MARKER);
|
|
25195
26355
|
const wrap = (original) => (...args) => {
|
|
25196
26356
|
if (carriesMcpNoise(args)) return;
|
|
@@ -25211,6 +26371,7 @@ function isProgramEntry() {
|
|
|
25211
26371
|
process.title = BRAND.binNames[0];
|
|
25212
26372
|
installMcpNoiseFilter();
|
|
25213
26373
|
if (isProgramEntry()) {
|
|
26374
|
+
ensureHeapHeadroom();
|
|
25214
26375
|
void boot(processArgv.slice(2)).then((code) => {
|
|
25215
26376
|
process.exitCode = code;
|
|
25216
26377
|
process.stdout.write("", () => process.exit(code));
|