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/index.js
CHANGED
|
@@ -31,6 +31,70 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
mod
|
|
32
32
|
));
|
|
33
33
|
|
|
34
|
+
// src/boot/server-token.ts
|
|
35
|
+
import { mkdir, readFile as readFile2, unlink, writeFile } from "node:fs/promises";
|
|
36
|
+
import os from "node:os";
|
|
37
|
+
import path from "node:path";
|
|
38
|
+
async function getServerToken() {
|
|
39
|
+
try {
|
|
40
|
+
const data = await readFile2(TOKEN_FILE, "utf8");
|
|
41
|
+
return JSON.parse(data);
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function storeServerToken(token) {
|
|
47
|
+
try {
|
|
48
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
49
|
+
const tokenData = {
|
|
50
|
+
access_token: token.access_token,
|
|
51
|
+
refresh_token: token.refresh_token,
|
|
52
|
+
token_type: token.token_type ?? "Bearer",
|
|
53
|
+
scope: token.scope,
|
|
54
|
+
expires_at: token.expires_in !== void 0 ? new Date(Date.now() + token.expires_in * 1e3).toISOString() : null,
|
|
55
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
56
|
+
};
|
|
57
|
+
await writeFile(TOKEN_FILE, `${JSON.stringify(tokenData, null, 2)}
|
|
58
|
+
`, {
|
|
59
|
+
encoding: "utf8",
|
|
60
|
+
mode: 384
|
|
61
|
+
});
|
|
62
|
+
return true;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error("Failed to store server token:", error.message);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function clearServerToken() {
|
|
69
|
+
try {
|
|
70
|
+
await unlink(TOKEN_FILE);
|
|
71
|
+
return true;
|
|
72
|
+
} catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function isServerTokenExpired(token) {
|
|
77
|
+
if (!token || !token.expires_at) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
const expiresAt = new Date(token.expires_at);
|
|
81
|
+
const now = /* @__PURE__ */ new Date();
|
|
82
|
+
return expiresAt.getTime() - now.getTime() < 5 * 60 * 1e3;
|
|
83
|
+
}
|
|
84
|
+
async function hasValidServerToken() {
|
|
85
|
+
const token = await getServerToken();
|
|
86
|
+
return token !== null && !isServerTokenExpired(token);
|
|
87
|
+
}
|
|
88
|
+
var INDUS_SERVER_URL, CONFIG_DIR, TOKEN_FILE;
|
|
89
|
+
var init_server_token = __esm({
|
|
90
|
+
"src/boot/server-token.ts"() {
|
|
91
|
+
"use strict";
|
|
92
|
+
INDUS_SERVER_URL = process.env.INDUS_SERVER_URL?.replace(/\/+$/, "") ?? "https://indus-server.vercel.app";
|
|
93
|
+
CONFIG_DIR = path.join(os.homedir(), ".indusagi", "agent");
|
|
94
|
+
TOKEN_FILE = path.join(CONFIG_DIR, "server-token.json");
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
34
98
|
// src/briefing/contract.ts
|
|
35
99
|
function briefingFault(kind, message, cause) {
|
|
36
100
|
return cause === void 0 ? { kind, message } : { kind, message, cause };
|
|
@@ -96,29 +160,29 @@ function bullets(lines) {
|
|
|
96
160
|
return lines.map((l) => `- ${l}`).join("\n");
|
|
97
161
|
}
|
|
98
162
|
function escapeXml(value) {
|
|
99
|
-
let
|
|
163
|
+
let out2 = "";
|
|
100
164
|
for (const ch of value) {
|
|
101
165
|
switch (ch) {
|
|
102
166
|
case "&":
|
|
103
|
-
|
|
167
|
+
out2 += "&";
|
|
104
168
|
break;
|
|
105
169
|
case "<":
|
|
106
|
-
|
|
170
|
+
out2 += "<";
|
|
107
171
|
break;
|
|
108
172
|
case ">":
|
|
109
|
-
|
|
173
|
+
out2 += ">";
|
|
110
174
|
break;
|
|
111
175
|
case '"':
|
|
112
|
-
|
|
176
|
+
out2 += """;
|
|
113
177
|
break;
|
|
114
178
|
case "'":
|
|
115
|
-
|
|
179
|
+
out2 += "'";
|
|
116
180
|
break;
|
|
117
181
|
default:
|
|
118
|
-
|
|
182
|
+
out2 += ch;
|
|
119
183
|
}
|
|
120
184
|
}
|
|
121
|
-
return
|
|
185
|
+
return out2;
|
|
122
186
|
}
|
|
123
187
|
function hasTool(ctx, id) {
|
|
124
188
|
return (ctx.tools ?? []).some((t) => t.name === id);
|
|
@@ -553,7 +617,7 @@ function buildMacroScope(raw) {
|
|
|
553
617
|
return { args, all: args.join(" "), raw };
|
|
554
618
|
}
|
|
555
619
|
function splitArguments(raw) {
|
|
556
|
-
const
|
|
620
|
+
const out2 = [];
|
|
557
621
|
let current = "";
|
|
558
622
|
let inWord = false;
|
|
559
623
|
let quote = null;
|
|
@@ -575,7 +639,7 @@ function splitArguments(raw) {
|
|
|
575
639
|
}
|
|
576
640
|
if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v") {
|
|
577
641
|
if (inWord) {
|
|
578
|
-
|
|
642
|
+
out2.push(current);
|
|
579
643
|
current = "";
|
|
580
644
|
inWord = false;
|
|
581
645
|
}
|
|
@@ -584,33 +648,33 @@ function splitArguments(raw) {
|
|
|
584
648
|
current += ch;
|
|
585
649
|
inWord = true;
|
|
586
650
|
}
|
|
587
|
-
if (inWord)
|
|
588
|
-
return
|
|
651
|
+
if (inWord) out2.push(current);
|
|
652
|
+
return out2;
|
|
589
653
|
}
|
|
590
654
|
function resolveTokens(tokens, scope) {
|
|
591
|
-
let
|
|
655
|
+
let out2 = "";
|
|
592
656
|
for (const token of tokens) {
|
|
593
657
|
switch (token.kind) {
|
|
594
658
|
case "literal":
|
|
595
|
-
|
|
659
|
+
out2 += token.text;
|
|
596
660
|
break;
|
|
597
661
|
case "positional": {
|
|
598
662
|
const value = scope.args[token.index - 1];
|
|
599
|
-
if (value !== void 0)
|
|
663
|
+
if (value !== void 0) out2 += value;
|
|
600
664
|
break;
|
|
601
665
|
}
|
|
602
666
|
case "all":
|
|
603
|
-
|
|
667
|
+
out2 += scope.all;
|
|
604
668
|
break;
|
|
605
669
|
case "slice": {
|
|
606
670
|
const from = Math.max(0, token.start - 1);
|
|
607
671
|
const slice = token.length === void 0 ? scope.args.slice(from) : scope.args.slice(from, from + Math.max(0, token.length));
|
|
608
|
-
|
|
672
|
+
out2 += slice.join(" ");
|
|
609
673
|
break;
|
|
610
674
|
}
|
|
611
675
|
}
|
|
612
676
|
}
|
|
613
|
-
return
|
|
677
|
+
return out2;
|
|
614
678
|
}
|
|
615
679
|
function applyMacros(body, raw) {
|
|
616
680
|
return resolveTokens(scanMacroBody(body), buildMacroScope(raw));
|
|
@@ -660,18 +724,18 @@ function loadMacros(dir, opts = {}) {
|
|
|
660
724
|
}
|
|
661
725
|
return macros;
|
|
662
726
|
}
|
|
663
|
-
function readMacroFile(
|
|
727
|
+
function readMacroFile(path4, origin, label2) {
|
|
664
728
|
let text;
|
|
665
729
|
try {
|
|
666
|
-
text = readFileSync(
|
|
730
|
+
text = readFileSync(path4, "utf8");
|
|
667
731
|
} catch (cause) {
|
|
668
|
-
throw briefingFault("macro_invalid", `could not read macro file at ${
|
|
732
|
+
throw briefingFault("macro_invalid", `could not read macro file at ${path4}`, cause);
|
|
669
733
|
}
|
|
670
734
|
const { frontmatter, body } = splitFrontmatter(text);
|
|
671
|
-
const name = basename2(
|
|
735
|
+
const name = basename2(path4).replace(/\.md$/i, "");
|
|
672
736
|
const declared = typeof frontmatter.description === "string" ? frontmatter.description.trim() : "";
|
|
673
737
|
const description = declared.length > 0 ? `${declared} (${label2})` : deriveDescription(body, label2);
|
|
674
|
-
return { name, description, body, origin, source:
|
|
738
|
+
return { name, description, body, origin, source: path4 };
|
|
675
739
|
}
|
|
676
740
|
function deriveDescription(body, label2) {
|
|
677
741
|
const firstLine = body.split("\n").find((l) => l.trim().length > 0)?.trim() ?? "";
|
|
@@ -810,41 +874,41 @@ function checkFrontmatterKeys(frontmatter) {
|
|
|
810
874
|
return null;
|
|
811
875
|
}
|
|
812
876
|
function projectFrontmatter(raw) {
|
|
813
|
-
const
|
|
814
|
-
if (typeof raw.name === "string")
|
|
815
|
-
if (typeof raw.description === "string")
|
|
816
|
-
if (typeof raw.license === "string")
|
|
817
|
-
if (typeof raw.compatibility === "string")
|
|
877
|
+
const out2 = {};
|
|
878
|
+
if (typeof raw.name === "string") out2.name = raw.name.trim();
|
|
879
|
+
if (typeof raw.description === "string") out2.description = raw.description.trim();
|
|
880
|
+
if (typeof raw.license === "string") out2.license = raw.license.trim();
|
|
881
|
+
if (typeof raw.compatibility === "string") out2.compatibility = raw.compatibility.trim();
|
|
818
882
|
if (typeof raw.metadata === "object" && raw.metadata !== null) {
|
|
819
|
-
|
|
883
|
+
out2.metadata = raw.metadata;
|
|
820
884
|
}
|
|
821
885
|
const tools = raw["allowed-tools"];
|
|
822
886
|
if (typeof tools === "string") {
|
|
823
887
|
const list = tools.split(/[\s,]+/).map((t) => t.trim()).filter((t) => t.length > 0);
|
|
824
|
-
if (list.length > 0)
|
|
888
|
+
if (list.length > 0) out2.allowedTools = list;
|
|
825
889
|
} else if (Array.isArray(tools)) {
|
|
826
|
-
|
|
890
|
+
out2.allowedTools = tools.map((t) => String(t));
|
|
827
891
|
}
|
|
828
892
|
const flag = raw["disable-model-invocation"];
|
|
829
|
-
if (flag === true || flag === "true")
|
|
830
|
-
return
|
|
893
|
+
if (flag === true || flag === "true") out2.disableModelInvocation = true;
|
|
894
|
+
return out2;
|
|
831
895
|
}
|
|
832
896
|
function diag(kind, location, detail) {
|
|
833
897
|
return { kind, location, detail };
|
|
834
898
|
}
|
|
835
899
|
function parseCandidate(candidate, origin) {
|
|
836
|
-
const { path:
|
|
900
|
+
const { path: path4, dirName } = candidate;
|
|
837
901
|
let text;
|
|
838
902
|
try {
|
|
839
|
-
text = readFileSync2(
|
|
903
|
+
text = readFileSync2(path4, "utf8");
|
|
840
904
|
} catch (cause) {
|
|
841
905
|
const detail = `could not read the skill file (${describeCause(cause)})`;
|
|
842
|
-
return { card: null, diagnostic: diag("invalid",
|
|
906
|
+
return { card: null, diagnostic: diag("invalid", path4, detail) };
|
|
843
907
|
}
|
|
844
908
|
const { frontmatter, body } = splitFrontmatter(text);
|
|
845
909
|
const keyProblem = checkFrontmatterKeys(frontmatter);
|
|
846
910
|
if (keyProblem !== null) {
|
|
847
|
-
return { card: null, diagnostic: diag("invalid",
|
|
911
|
+
return { card: null, diagnostic: diag("invalid", path4, keyProblem) };
|
|
848
912
|
}
|
|
849
913
|
const fm = projectFrontmatter(frontmatter);
|
|
850
914
|
const declaredName = fm.name ?? "";
|
|
@@ -852,22 +916,22 @@ function parseCandidate(candidate, origin) {
|
|
|
852
916
|
const name = fromDir ? dirName : declaredName;
|
|
853
917
|
const nameProblem = checkName(name, dirName, fromDir);
|
|
854
918
|
if (nameProblem !== null) {
|
|
855
|
-
return { card: null, diagnostic: diag("invalid",
|
|
919
|
+
return { card: null, diagnostic: diag("invalid", path4, nameProblem) };
|
|
856
920
|
}
|
|
857
921
|
const description = fm.description ?? "";
|
|
858
922
|
const descProblem = checkDescription(description);
|
|
859
923
|
if (descProblem !== null) {
|
|
860
|
-
return { card: null, diagnostic: diag("invalid",
|
|
924
|
+
return { card: null, diagnostic: diag("invalid", path4, descProblem) };
|
|
861
925
|
}
|
|
862
926
|
const card = {
|
|
863
927
|
name,
|
|
864
928
|
description,
|
|
865
929
|
body,
|
|
866
|
-
location:
|
|
930
|
+
location: path4,
|
|
867
931
|
origin,
|
|
868
932
|
frontmatter: fm
|
|
869
933
|
};
|
|
870
|
-
return { card, diagnostic: diag("loaded",
|
|
934
|
+
return { card, diagnostic: diag("loaded", path4, `loaded skill "${name}"`) };
|
|
871
935
|
}
|
|
872
936
|
function describeCause(cause) {
|
|
873
937
|
if (cause instanceof Error) return cause.message;
|
|
@@ -940,15 +1004,15 @@ var init_skills = __esm({
|
|
|
940
1004
|
// src/briefing/context-docs.ts
|
|
941
1005
|
import { existsSync, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
942
1006
|
import { dirname as dirname4, extname as extname2, isAbsolute as isAbsolute2, join as join6, parse, resolve as resolve2 } from "node:path";
|
|
943
|
-
function shortenPath(
|
|
944
|
-
if (cwd.length > 0 &&
|
|
945
|
-
const rest =
|
|
1007
|
+
function shortenPath(path4, cwd, home) {
|
|
1008
|
+
if (cwd.length > 0 && path4.startsWith(cwd)) {
|
|
1009
|
+
const rest = path4.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
946
1010
|
return rest.length > 0 ? `./${rest}` : ".";
|
|
947
1011
|
}
|
|
948
|
-
if (home.length > 0 &&
|
|
949
|
-
return `~${
|
|
1012
|
+
if (home.length > 0 && path4.startsWith(home)) {
|
|
1013
|
+
return `~${path4.slice(home.length)}`;
|
|
950
1014
|
}
|
|
951
|
-
return
|
|
1015
|
+
return path4;
|
|
952
1016
|
}
|
|
953
1017
|
function dirChain(cwd) {
|
|
954
1018
|
const chain = [];
|
|
@@ -961,15 +1025,15 @@ function dirChain(cwd) {
|
|
|
961
1025
|
}
|
|
962
1026
|
return chain.reverse();
|
|
963
1027
|
}
|
|
964
|
-
function safeRealpath(
|
|
1028
|
+
function safeRealpath(path4) {
|
|
965
1029
|
try {
|
|
966
|
-
return realpathSync2(
|
|
1030
|
+
return realpathSync2(path4);
|
|
967
1031
|
} catch {
|
|
968
|
-
return
|
|
1032
|
+
return path4;
|
|
969
1033
|
}
|
|
970
1034
|
}
|
|
971
|
-
function isTextFile(
|
|
972
|
-
const ext = extname2(
|
|
1035
|
+
function isTextFile(path4) {
|
|
1036
|
+
const ext = extname2(path4).toLowerCase();
|
|
973
1037
|
return ext.length === 0 || TEXT_FILE_EXTENSIONS.has(ext);
|
|
974
1038
|
}
|
|
975
1039
|
function readFileBody(absPath) {
|
|
@@ -984,7 +1048,7 @@ function readFileBody(absPath) {
|
|
|
984
1048
|
return trimmed.length > 0 ? trimmed : null;
|
|
985
1049
|
}
|
|
986
1050
|
function extractImports(body, baseDir, home) {
|
|
987
|
-
const
|
|
1051
|
+
const out2 = [];
|
|
988
1052
|
IMPORT_REGEX.lastIndex = 0;
|
|
989
1053
|
let match;
|
|
990
1054
|
while ((match = IMPORT_REGEX.exec(body)) !== null) {
|
|
@@ -1003,26 +1067,26 @@ function extractImports(body, baseDir, home) {
|
|
|
1003
1067
|
abs = resolve2(baseDir, spec);
|
|
1004
1068
|
}
|
|
1005
1069
|
if (!isTextFile(abs)) continue;
|
|
1006
|
-
|
|
1070
|
+
out2.push(abs);
|
|
1007
1071
|
}
|
|
1008
|
-
return
|
|
1072
|
+
return out2;
|
|
1009
1073
|
}
|
|
1010
|
-
function loadDocTree(absPath, cwd, home, seen, depth, maxDepth, maxBytes,
|
|
1074
|
+
function loadDocTree(absPath, cwd, home, seen, depth, maxDepth, maxBytes, out2) {
|
|
1011
1075
|
const real = safeRealpath(absPath);
|
|
1012
1076
|
if (seen.has(real)) return;
|
|
1013
1077
|
seen.add(real);
|
|
1014
1078
|
const body = readFileBody(absPath);
|
|
1015
1079
|
if (body === null) return;
|
|
1016
1080
|
const clipped = body.length > maxBytes ? body.slice(0, maxBytes) : body;
|
|
1017
|
-
|
|
1081
|
+
out2.push({ path: shortenPath(absPath, cwd, home), body: clipped });
|
|
1018
1082
|
if (depth >= maxDepth) return;
|
|
1019
1083
|
const baseDir = dirname4(absPath);
|
|
1020
1084
|
for (const child of extractImports(body, baseDir, home)) {
|
|
1021
|
-
loadDocTree(child, cwd, home, seen, depth + 1, maxDepth, maxBytes,
|
|
1085
|
+
loadDocTree(child, cwd, home, seen, depth + 1, maxDepth, maxBytes, out2);
|
|
1022
1086
|
}
|
|
1023
1087
|
}
|
|
1024
1088
|
function gatherContextDocs(cwd, home, opts) {
|
|
1025
|
-
const
|
|
1089
|
+
const out2 = [];
|
|
1026
1090
|
try {
|
|
1027
1091
|
const maxDepth = opts?.maxImportDepth ?? DEFAULT_MAX_IMPORT_DEPTH;
|
|
1028
1092
|
const maxBytes = opts?.maxBytesPerDoc ?? DEFAULT_MAX_BYTES_PER_DOC;
|
|
@@ -1033,13 +1097,13 @@ function gatherContextDocs(cwd, home, opts) {
|
|
|
1033
1097
|
if (dir.length === 0) continue;
|
|
1034
1098
|
for (const name of CANDIDATE_FILES) {
|
|
1035
1099
|
const candidate = join6(dir, name);
|
|
1036
|
-
loadDocTree(candidate, cwd, home, seen, 0, maxDepth, maxBytes,
|
|
1100
|
+
loadDocTree(candidate, cwd, home, seen, 0, maxDepth, maxBytes, out2);
|
|
1037
1101
|
}
|
|
1038
1102
|
}
|
|
1039
1103
|
} catch {
|
|
1040
|
-
return
|
|
1104
|
+
return out2;
|
|
1041
1105
|
}
|
|
1042
|
-
return
|
|
1106
|
+
return out2;
|
|
1043
1107
|
}
|
|
1044
1108
|
var DEFAULT_MAX_IMPORT_DEPTH, DEFAULT_MAX_BYTES_PER_DOC, CANDIDATE_FILES, TEXT_FILE_EXTENSIONS, IMPORT_REGEX;
|
|
1045
1109
|
var init_context_docs = __esm({
|
|
@@ -1229,13 +1293,15 @@ var init_transcript = __esm({
|
|
|
1229
1293
|
}
|
|
1230
1294
|
};
|
|
1231
1295
|
compactCommand = {
|
|
1232
|
-
name
|
|
1296
|
+
// `compact` is the canonical name — it is what users type (and what the
|
|
1297
|
+
// suggestion list shows); the longer forms stay reachable as aliases.
|
|
1298
|
+
name: "compact",
|
|
1233
1299
|
summary: "Condense the conversation context",
|
|
1234
|
-
aliases: ["condense", "
|
|
1300
|
+
aliases: ["condense", "summarize-context"],
|
|
1235
1301
|
takesArgs: true,
|
|
1236
1302
|
run(ctx) {
|
|
1237
1303
|
const instructions = ctx.args.trim();
|
|
1238
|
-
const busyText = instructions.length > 0 ? `
|
|
1304
|
+
const busyText = instructions.length > 0 ? `Compacting with guidance: ${instructions} \u2014 Esc to cancel` : "Compacting conversation context... Press Esc to cancel.";
|
|
1239
1305
|
ctx.setStatus({ kind: "busy", text: busyText });
|
|
1240
1306
|
void (async () => {
|
|
1241
1307
|
try {
|
|
@@ -1244,14 +1310,29 @@ var init_transcript = __esm({
|
|
|
1244
1310
|
`printf '%s' ${JSON.stringify(`Compaction guidance: ${instructions}`)}`
|
|
1245
1311
|
);
|
|
1246
1312
|
}
|
|
1247
|
-
await ctx.conductor.condense()
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1313
|
+
switch (await ctx.conductor.condense()) {
|
|
1314
|
+
case "condensed":
|
|
1315
|
+
ctx.setStatus(
|
|
1316
|
+
info(
|
|
1317
|
+
instructions.length > 0 ? "Context condensed (guidance recorded for the agent)." : "Context condensed."
|
|
1318
|
+
)
|
|
1319
|
+
);
|
|
1320
|
+
break;
|
|
1321
|
+
case "nothing":
|
|
1322
|
+
ctx.setStatus(warn("Nothing to compact yet."));
|
|
1323
|
+
break;
|
|
1324
|
+
case "cancelled":
|
|
1325
|
+
ctx.setStatus(warn("Compaction cancelled."));
|
|
1326
|
+
break;
|
|
1327
|
+
case "busy":
|
|
1328
|
+
ctx.setStatus(warn("A turn is running \u2014 press Esc to stop it first, then /compact."));
|
|
1329
|
+
break;
|
|
1330
|
+
case "failed":
|
|
1331
|
+
ctx.setStatus(warn("Compaction failed; the transcript is unchanged."));
|
|
1332
|
+
break;
|
|
1333
|
+
}
|
|
1253
1334
|
} catch {
|
|
1254
|
-
ctx.setStatus(warn("
|
|
1335
|
+
ctx.setStatus(warn("Compaction failed; the transcript is unchanged."));
|
|
1255
1336
|
}
|
|
1256
1337
|
})();
|
|
1257
1338
|
return HANDLED;
|
|
@@ -1291,7 +1372,8 @@ var init_transcript = __esm({
|
|
|
1291
1372
|
costCommand = {
|
|
1292
1373
|
name: "cost",
|
|
1293
1374
|
summary: "Show session cost and token usage",
|
|
1294
|
-
|
|
1375
|
+
// `usage` is intentionally NOT an alias here: `/usage` is the server-tier
|
|
1376
|
+
// quota command (see integrations.ts). `/cost` shows this session's local stats.
|
|
1295
1377
|
run(ctx) {
|
|
1296
1378
|
const stats = ctx.conductor.stats();
|
|
1297
1379
|
const t = stats.tokens;
|
|
@@ -1482,9 +1564,9 @@ function runDebug(ctx) {
|
|
|
1482
1564
|
const jsonl = records.map((r) => JSON.stringify(r)).join("\n") + "\n";
|
|
1483
1565
|
try {
|
|
1484
1566
|
const dir = mkdtempSync(join7(tmpdir(), "indus-debug-"));
|
|
1485
|
-
const
|
|
1486
|
-
writeFileSync(
|
|
1487
|
-
ctx.setStatus(info(`Diagnostics written to ${
|
|
1567
|
+
const path4 = join7(dir, `session-${stats.sessionId || "unknown"}.jsonl`);
|
|
1568
|
+
writeFileSync(path4, jsonl, "utf8");
|
|
1569
|
+
ctx.setStatus(info(`Diagnostics written to ${path4}`));
|
|
1488
1570
|
} catch (cause) {
|
|
1489
1571
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
1490
1572
|
ctx.setStatus(warn(`Could not write the diagnostics log (${detail}).`));
|
|
@@ -1553,6 +1635,7 @@ var init_workbench = __esm({
|
|
|
1553
1635
|
["Ctrl+J", "Insert a newline"],
|
|
1554
1636
|
["Ctrl+Z", "Suspend the process"],
|
|
1555
1637
|
["Alt+Up", "Pull the newest queued input back into the composer"],
|
|
1638
|
+
["Ctrl+X", "Run the newest queued message NOW (stops the current run)"],
|
|
1556
1639
|
["! <cmd>", "Run a shell command (kept in context)"],
|
|
1557
1640
|
["!! <cmd>", "Run a shell command (excluded from context)"]
|
|
1558
1641
|
];
|
|
@@ -1637,6 +1720,60 @@ var init_workbench = __esm({
|
|
|
1637
1720
|
}
|
|
1638
1721
|
});
|
|
1639
1722
|
|
|
1723
|
+
// src/boot/runners/server-mode.ts
|
|
1724
|
+
function isGatewayEligibleProvider(provider) {
|
|
1725
|
+
return GATEWAY_ELIGIBLE_PROVIDERS.has(provider);
|
|
1726
|
+
}
|
|
1727
|
+
function serverTierProviders() {
|
|
1728
|
+
return [...GATEWAY_ELIGIBLE_PROVIDERS];
|
|
1729
|
+
}
|
|
1730
|
+
async function hasUsableLocalKey(provider, vault) {
|
|
1731
|
+
try {
|
|
1732
|
+
const accounts = [];
|
|
1733
|
+
const def = await vault.defaultAccount(provider);
|
|
1734
|
+
if (def !== void 0 && def.length > 0) accounts.push(def);
|
|
1735
|
+
for (const account of await vault.listAccounts(provider)) {
|
|
1736
|
+
if (!accounts.includes(account)) accounts.push(account);
|
|
1737
|
+
}
|
|
1738
|
+
for (const account of accounts) {
|
|
1739
|
+
const key = await vault.readUsableKey(provider, account);
|
|
1740
|
+
if (typeof key === "string" && key.length > 0) return true;
|
|
1741
|
+
}
|
|
1742
|
+
} catch {
|
|
1743
|
+
}
|
|
1744
|
+
return false;
|
|
1745
|
+
}
|
|
1746
|
+
async function resolveServerMode(_ctx, provider, vault) {
|
|
1747
|
+
if (!isGatewayEligibleProvider(provider)) return { serverMode: false };
|
|
1748
|
+
if (await hasUsableLocalKey(provider, vault)) return { serverMode: false };
|
|
1749
|
+
if (!await hasValidServerToken()) return { serverMode: false };
|
|
1750
|
+
const token = await getServerToken();
|
|
1751
|
+
const access = token?.access_token;
|
|
1752
|
+
if (typeof access !== "string" || access.length === 0) return { serverMode: false };
|
|
1753
|
+
return { serverMode: true, token: access };
|
|
1754
|
+
}
|
|
1755
|
+
async function resolveServerGatewayUrls(ctx, vault) {
|
|
1756
|
+
const map = {};
|
|
1757
|
+
for (const provider of GATEWAY_ELIGIBLE_PROVIDERS) {
|
|
1758
|
+
const result = await resolveServerMode(ctx, provider, vault);
|
|
1759
|
+
if (result.serverMode) {
|
|
1760
|
+
map[provider] = `${INDUS_SERVER_URL}/gateway/${provider}`;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
return map;
|
|
1764
|
+
}
|
|
1765
|
+
var GATEWAY_ELIGIBLE_PROVIDERS;
|
|
1766
|
+
var init_server_mode = __esm({
|
|
1767
|
+
"src/boot/runners/server-mode.ts"() {
|
|
1768
|
+
"use strict";
|
|
1769
|
+
init_server_token();
|
|
1770
|
+
GATEWAY_ELIGIBLE_PROVIDERS = /* @__PURE__ */ new Set([
|
|
1771
|
+
"minimax",
|
|
1772
|
+
"sarvam"
|
|
1773
|
+
]);
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
|
|
1640
1777
|
// src/capability-deck/contract.ts
|
|
1641
1778
|
function capabilityId(raw) {
|
|
1642
1779
|
return raw;
|
|
@@ -9272,14 +9409,14 @@ Poll it with action:"poll", id:"${h.id}".`
|
|
|
9272
9409
|
case "poll": {
|
|
9273
9410
|
const h = params.id ? table.get(params.id) : void 0;
|
|
9274
9411
|
if (!h) return errResult("poll", `No background process with id "${params.id ?? ""}".`);
|
|
9275
|
-
const
|
|
9276
|
-
const
|
|
9412
|
+
const out2 = drainBuffer(h.stdout, params.sinceLast ?? false);
|
|
9413
|
+
const err2 = drainBuffer(h.stderr, params.sinceLast ?? false);
|
|
9277
9414
|
const parts = [`Process ${h.id} \u2014 ${statusLine(h)}`];
|
|
9278
|
-
if (
|
|
9279
|
-
${
|
|
9280
|
-
if (
|
|
9281
|
-
${
|
|
9282
|
-
if (
|
|
9415
|
+
if (out2.length) parts.push(`--- stdout ---
|
|
9416
|
+
${out2.join("\n")}`);
|
|
9417
|
+
if (err2.length) parts.push(`--- stderr ---
|
|
9418
|
+
${err2.join("\n")}`);
|
|
9419
|
+
if (out2.length === 0 && err2.length === 0) parts.push("(no new output)");
|
|
9283
9420
|
return {
|
|
9284
9421
|
content: [{ type: "text", text: parts.join("\n") }],
|
|
9285
9422
|
details: { action: "poll", ok: true, id: h.id, state: h.state, exitCode: h.exitCode }
|
|
@@ -9359,8 +9496,8 @@ var init_bg_process_card = __esm({
|
|
|
9359
9496
|
handle.signal = sig;
|
|
9360
9497
|
handle.state = sig ? "signalled" : "exited";
|
|
9361
9498
|
});
|
|
9362
|
-
child.on("error", (
|
|
9363
|
-
pushLines(handle.stderr, `spawn error: ${String(
|
|
9499
|
+
child.on("error", (err2) => {
|
|
9500
|
+
pushLines(handle.stderr, `spawn error: ${String(err2)}`);
|
|
9364
9501
|
handle.state = "exited";
|
|
9365
9502
|
});
|
|
9366
9503
|
this.handles.set(id, handle);
|
|
@@ -9700,6 +9837,10 @@ function createStructuredOutputTool({
|
|
|
9700
9837
|
name,
|
|
9701
9838
|
label: "Structured Output",
|
|
9702
9839
|
description: "Return the final machine-readable result for this subagent task.",
|
|
9840
|
+
// Pure in-memory capture — no filesystem/shell/network mutation — so the
|
|
9841
|
+
// subagent permission gate auto-allows it in every mode (a schema-bound
|
|
9842
|
+
// workflow must be able to land its result even under `default`/`plan`).
|
|
9843
|
+
readOnly: true,
|
|
9703
9844
|
parameters: schema,
|
|
9704
9845
|
async execute(_toolCallId, params) {
|
|
9705
9846
|
capture.value = params;
|
|
@@ -9807,13 +9948,13 @@ function assembleTree(header, blocks, logLines, maxLines) {
|
|
|
9807
9948
|
if (1 + keptLen + summaryCost + logLines.length <= maxLines) break;
|
|
9808
9949
|
folded.add(i);
|
|
9809
9950
|
}
|
|
9810
|
-
const
|
|
9811
|
-
if (folded.size)
|
|
9951
|
+
const out2 = [header];
|
|
9952
|
+
if (folded.size) out2.push(` \u2026 ${folded.size} earlier phases done`);
|
|
9812
9953
|
blocks.forEach((b, i) => {
|
|
9813
|
-
if (!folded.has(i))
|
|
9954
|
+
if (!folded.has(i)) out2.push(...baseRow(b));
|
|
9814
9955
|
});
|
|
9815
|
-
|
|
9816
|
-
return
|
|
9956
|
+
out2.push(...logLines);
|
|
9957
|
+
return out2;
|
|
9817
9958
|
}
|
|
9818
9959
|
function compactPhaseLine(marker, phase, done, agents, now) {
|
|
9819
9960
|
const prefix = ` ${marker} ${phase} ${done}/${agents.length}`;
|
|
@@ -9897,7 +10038,7 @@ var init_display = __esm({
|
|
|
9897
10038
|
|
|
9898
10039
|
// src/workflow-engine/engine.ts
|
|
9899
10040
|
import vm2 from "node:vm";
|
|
9900
|
-
import
|
|
10041
|
+
import os2 from "node:os";
|
|
9901
10042
|
async function runWorkflow(script, options) {
|
|
9902
10043
|
const started = Date.now();
|
|
9903
10044
|
const { meta, body } = parseWorkflowScript(script);
|
|
@@ -10067,7 +10208,7 @@ ${body}
|
|
|
10067
10208
|
};
|
|
10068
10209
|
}
|
|
10069
10210
|
function defaultConcurrency() {
|
|
10070
|
-
const count =
|
|
10211
|
+
const count = os2.cpus()?.length;
|
|
10071
10212
|
return typeof count === "number" && count > 0 ? count : 8;
|
|
10072
10213
|
}
|
|
10073
10214
|
function createLimiter(limit) {
|
|
@@ -10745,8 +10886,8 @@ function memoryBackend() {
|
|
|
10745
10886
|
}
|
|
10746
10887
|
function fsBackend(dir) {
|
|
10747
10888
|
const fileOf = async (sessionId) => {
|
|
10748
|
-
const
|
|
10749
|
-
return
|
|
10889
|
+
const path4 = await import("node:path");
|
|
10890
|
+
return path4.join(dir, `${sessionId}.ndjson`);
|
|
10750
10891
|
};
|
|
10751
10892
|
return {
|
|
10752
10893
|
locate: (sessionId) => `${dir}/${sessionId}.ndjson`,
|
|
@@ -11159,6 +11300,73 @@ var init_skill_parse = __esm({
|
|
|
11159
11300
|
}
|
|
11160
11301
|
});
|
|
11161
11302
|
|
|
11303
|
+
// src/conductor/quota-error.ts
|
|
11304
|
+
function collectErrorSignals(error) {
|
|
11305
|
+
const statuses = [];
|
|
11306
|
+
const parts = [];
|
|
11307
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11308
|
+
const visit = (value, depth) => {
|
|
11309
|
+
if (value === null || value === void 0 || depth > 6) return;
|
|
11310
|
+
if (typeof value === "string") {
|
|
11311
|
+
parts.push(value);
|
|
11312
|
+
return;
|
|
11313
|
+
}
|
|
11314
|
+
if (typeof value === "number") {
|
|
11315
|
+
statuses.push(value);
|
|
11316
|
+
return;
|
|
11317
|
+
}
|
|
11318
|
+
if (typeof value !== "object") return;
|
|
11319
|
+
if (seen.has(value)) return;
|
|
11320
|
+
seen.add(value);
|
|
11321
|
+
const obj = value;
|
|
11322
|
+
for (const key of ["status", "statusCode", "code"]) {
|
|
11323
|
+
const raw = obj[key];
|
|
11324
|
+
if (typeof raw === "number") statuses.push(raw);
|
|
11325
|
+
else if (typeof raw === "string" && /^\d+$/.test(raw)) statuses.push(Number(raw));
|
|
11326
|
+
}
|
|
11327
|
+
if (typeof obj.message === "string") parts.push(obj.message);
|
|
11328
|
+
visit(obj.cause, depth + 1);
|
|
11329
|
+
visit(obj.error, depth + 1);
|
|
11330
|
+
visit(obj.response, depth + 1);
|
|
11331
|
+
visit(obj.body, depth + 1);
|
|
11332
|
+
visit(obj.data, depth + 1);
|
|
11333
|
+
};
|
|
11334
|
+
visit(error, 0);
|
|
11335
|
+
try {
|
|
11336
|
+
parts.push(JSON.stringify(error));
|
|
11337
|
+
} catch {
|
|
11338
|
+
}
|
|
11339
|
+
if (error instanceof Error && typeof error.stack === "string") parts.push(error.stack);
|
|
11340
|
+
return { statuses, text: parts.join(" ").toLowerCase() };
|
|
11341
|
+
}
|
|
11342
|
+
function isQuotaFault(error) {
|
|
11343
|
+
const { statuses, text } = collectErrorSignals(error);
|
|
11344
|
+
if (!text.includes(QUOTA_MARKER)) return false;
|
|
11345
|
+
return statuses.includes(429) || text.includes(QUOTA_MARKER);
|
|
11346
|
+
}
|
|
11347
|
+
function parseUsedLimit(text) {
|
|
11348
|
+
const used = text.match(/"used"\s*:\s*(\d+)/);
|
|
11349
|
+
const limit = text.match(/"limit"\s*:\s*(\d+)/);
|
|
11350
|
+
if (used && limit) {
|
|
11351
|
+
return { used: Number(used[1]), limit: Number(limit[1]) };
|
|
11352
|
+
}
|
|
11353
|
+
return void 0;
|
|
11354
|
+
}
|
|
11355
|
+
function quotaErrorMessage(error) {
|
|
11356
|
+
if (!isQuotaFault(error)) return void 0;
|
|
11357
|
+
const { text } = collectErrorSignals(error);
|
|
11358
|
+
const numbers = parseUsedLimit(text);
|
|
11359
|
+
const usage = numbers ? ` (${numbers.used}/${numbers.limit} tokens this month)` : "";
|
|
11360
|
+
return `You've hit your indus usage limit${usage}. Add your own API key with \`indus signin <provider>\`, or upgrade your plan.`;
|
|
11361
|
+
}
|
|
11362
|
+
var QUOTA_MARKER;
|
|
11363
|
+
var init_quota_error = __esm({
|
|
11364
|
+
"src/conductor/quota-error.ts"() {
|
|
11365
|
+
"use strict";
|
|
11366
|
+
QUOTA_MARKER = "quota_exceeded";
|
|
11367
|
+
}
|
|
11368
|
+
});
|
|
11369
|
+
|
|
11162
11370
|
// src/capability-deck/cards/plan-file.ts
|
|
11163
11371
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
11164
11372
|
import { join as join8 } from "node:path";
|
|
@@ -11174,14 +11382,14 @@ function writePlan(sessionDir, plan) {
|
|
|
11174
11382
|
const dir = join8(sessionDir, PLANS_DIRNAME);
|
|
11175
11383
|
mkdirSync2(dir, { recursive: true });
|
|
11176
11384
|
const stamp = Date.now().toString(36);
|
|
11177
|
-
const
|
|
11178
|
-
writeFileSync2(
|
|
11385
|
+
const path4 = join8(dir, `${stamp}-${planSlug(plan)}.md`);
|
|
11386
|
+
writeFileSync2(path4, plan.endsWith("\n") ? plan : `${plan}
|
|
11179
11387
|
`, { encoding: "utf8", mode: 384 });
|
|
11180
|
-
return
|
|
11388
|
+
return path4;
|
|
11181
11389
|
}
|
|
11182
|
-
function readPlan(
|
|
11390
|
+
function readPlan(path4) {
|
|
11183
11391
|
try {
|
|
11184
|
-
return readFileSync5(
|
|
11392
|
+
return readFileSync5(path4, "utf8");
|
|
11185
11393
|
} catch {
|
|
11186
11394
|
return void 0;
|
|
11187
11395
|
}
|
|
@@ -11432,10 +11640,10 @@ function flattenMessage(message) {
|
|
|
11432
11640
|
return `${TURN_MARK} ${tag} (${message.toolName}): ${text}`;
|
|
11433
11641
|
}
|
|
11434
11642
|
case "bashExecution": {
|
|
11435
|
-
const
|
|
11643
|
+
const out2 = tidy(message.output);
|
|
11436
11644
|
const code = message.exitCode ?? "n/a";
|
|
11437
11645
|
return `${TURN_MARK} shell$ ${tidy(message.command)} [exit ${code}]
|
|
11438
|
-
${
|
|
11646
|
+
${out2}`;
|
|
11439
11647
|
}
|
|
11440
11648
|
case "custom": {
|
|
11441
11649
|
const text = tidy(readContent(message.content));
|
|
@@ -11559,7 +11767,8 @@ async function summarize(messages, deps = {}) {
|
|
|
11559
11767
|
const options = {
|
|
11560
11768
|
reasoning: "high",
|
|
11561
11769
|
...deps.maxTokens !== void 0 ? { maxTokens: deps.maxTokens } : {},
|
|
11562
|
-
...deps.signal ? { signal: deps.signal } : {}
|
|
11770
|
+
...deps.signal ? { signal: deps.signal } : {},
|
|
11771
|
+
...deps.apiKey !== void 0 ? { apiKey: deps.apiKey } : {}
|
|
11563
11772
|
};
|
|
11564
11773
|
const complete = deps.complete ?? completeSimple;
|
|
11565
11774
|
const reply = await complete(deps.model, context, options);
|
|
@@ -11721,8 +11930,8 @@ function collectVisibleReadPaths(kept, readToolName) {
|
|
|
11721
11930
|
if (!isRecord4(block2) || block2.type !== "toolCall") continue;
|
|
11722
11931
|
if (block2.name !== readToolName) continue;
|
|
11723
11932
|
const args = isRecord4(block2.arguments) ? block2.arguments : void 0;
|
|
11724
|
-
const
|
|
11725
|
-
if (
|
|
11933
|
+
const path4 = args && typeof args.path === "string" ? args.path : "";
|
|
11934
|
+
if (path4.length > 0) paths.add(path4);
|
|
11726
11935
|
}
|
|
11727
11936
|
}
|
|
11728
11937
|
return paths;
|
|
@@ -11738,8 +11947,8 @@ function collectDroppedReads(dropped, readToolName) {
|
|
|
11738
11947
|
if (block2.name !== readToolName) continue;
|
|
11739
11948
|
const id = typeof block2.id === "string" ? block2.id : "";
|
|
11740
11949
|
const args = isRecord4(block2.arguments) ? block2.arguments : void 0;
|
|
11741
|
-
const
|
|
11742
|
-
if (id.length > 0 &&
|
|
11950
|
+
const path4 = args && typeof args.path === "string" ? args.path : "";
|
|
11951
|
+
if (id.length > 0 && path4.length > 0) calls.set(id, { path: path4, order: i });
|
|
11743
11952
|
}
|
|
11744
11953
|
}
|
|
11745
11954
|
if (calls.size === 0) return [];
|
|
@@ -11834,7 +12043,7 @@ var init_window_budget = __esm({
|
|
|
11834
12043
|
});
|
|
11835
12044
|
|
|
11836
12045
|
// src/conductor/diagnostics.ts
|
|
11837
|
-
import * as
|
|
12046
|
+
import * as path2 from "node:path";
|
|
11838
12047
|
import { existsSync as existsSync2 } from "node:fs";
|
|
11839
12048
|
function createDiagnosticKey(d) {
|
|
11840
12049
|
const { start, end } = d.range;
|
|
@@ -11951,7 +12160,7 @@ async function runTscDiagnostics(cwd, signal) {
|
|
|
11951
12160
|
const spawn3 = await loadSpawn();
|
|
11952
12161
|
if (spawn3 === void 0) return [];
|
|
11953
12162
|
if (signal?.aborted) return [];
|
|
11954
|
-
const bin =
|
|
12163
|
+
const bin = path2.join(cwd, "node_modules", ".bin", "tsc");
|
|
11955
12164
|
const output = await captureOutput(
|
|
11956
12165
|
spawn3,
|
|
11957
12166
|
bin,
|
|
@@ -11969,7 +12178,7 @@ function parseTscOutput(output, cwd) {
|
|
|
11969
12178
|
const m = re.exec(raw);
|
|
11970
12179
|
if (m === null) continue;
|
|
11971
12180
|
const [, file, lineStr, colStr, sevWord, code, message] = m;
|
|
11972
|
-
const uri =
|
|
12181
|
+
const uri = path2.isAbsolute(file) ? file : path2.resolve(cwd, file);
|
|
11973
12182
|
const line = Math.max(0, Number(lineStr) - 1);
|
|
11974
12183
|
const character = Math.max(0, Number(colStr) - 1);
|
|
11975
12184
|
const diagnostic = {
|
|
@@ -11990,7 +12199,7 @@ async function runEslintDiagnostics(files, cwd, signal) {
|
|
|
11990
12199
|
const spawn3 = await loadSpawn();
|
|
11991
12200
|
if (spawn3 === void 0) return [];
|
|
11992
12201
|
if (signal?.aborted) return [];
|
|
11993
|
-
const bin =
|
|
12202
|
+
const bin = path2.join(cwd, "node_modules", ".bin", "eslint");
|
|
11994
12203
|
const output = await captureOutput(
|
|
11995
12204
|
spawn3,
|
|
11996
12205
|
bin,
|
|
@@ -12011,10 +12220,10 @@ function parseEslintOutput(output, cwd) {
|
|
|
12011
12220
|
} catch {
|
|
12012
12221
|
return [];
|
|
12013
12222
|
}
|
|
12014
|
-
const
|
|
12223
|
+
const out2 = [];
|
|
12015
12224
|
for (const file of parsed) {
|
|
12016
12225
|
if (!Array.isArray(file.messages) || file.messages.length === 0) continue;
|
|
12017
|
-
const uri =
|
|
12226
|
+
const uri = path2.isAbsolute(file.filePath) ? file.filePath : path2.resolve(cwd, file.filePath);
|
|
12018
12227
|
const diagnostics = [];
|
|
12019
12228
|
for (const msg of file.messages) {
|
|
12020
12229
|
const line = Math.max(0, (msg.line ?? 1) - 1);
|
|
@@ -12032,9 +12241,9 @@ function parseEslintOutput(output, cwd) {
|
|
|
12032
12241
|
...msg.ruleId ? { code: msg.ruleId } : {}
|
|
12033
12242
|
});
|
|
12034
12243
|
}
|
|
12035
|
-
if (diagnostics.length > 0)
|
|
12244
|
+
if (diagnostics.length > 0) out2.push({ uri, diagnostics });
|
|
12036
12245
|
}
|
|
12037
|
-
return
|
|
12246
|
+
return out2;
|
|
12038
12247
|
}
|
|
12039
12248
|
function captureOutput(spawn3, bin, args, cwd, signal) {
|
|
12040
12249
|
return new Promise((resolve8) => {
|
|
@@ -12081,11 +12290,11 @@ function captureOutput(spawn3, bin, args, cwd, signal) {
|
|
|
12081
12290
|
});
|
|
12082
12291
|
}
|
|
12083
12292
|
function isTypeScriptOrJs(filePath) {
|
|
12084
|
-
return TS_JS_EXTENSIONS.has(
|
|
12293
|
+
return TS_JS_EXTENSIONS.has(path2.extname(filePath).toLowerCase());
|
|
12085
12294
|
}
|
|
12086
12295
|
function hasTsConfig(cwd) {
|
|
12087
12296
|
try {
|
|
12088
|
-
return existsSync2(
|
|
12297
|
+
return existsSync2(path2.join(cwd, "tsconfig.json"));
|
|
12089
12298
|
} catch {
|
|
12090
12299
|
return false;
|
|
12091
12300
|
}
|
|
@@ -12103,7 +12312,7 @@ function hasEslintConfig(cwd) {
|
|
|
12103
12312
|
".eslintrc.yml",
|
|
12104
12313
|
".eslintrc.yaml"
|
|
12105
12314
|
];
|
|
12106
|
-
return candidates.some((name) => existsSync2(
|
|
12315
|
+
return candidates.some((name) => existsSync2(path2.join(cwd, name)));
|
|
12107
12316
|
} catch {
|
|
12108
12317
|
return false;
|
|
12109
12318
|
}
|
|
@@ -12193,7 +12402,7 @@ var init_diagnostics = __esm({
|
|
|
12193
12402
|
if (!this.#enabled) return [];
|
|
12194
12403
|
if (editedPaths.length === 0) return [];
|
|
12195
12404
|
const all = await this.#runAll(signal);
|
|
12196
|
-
const editedSet = new Set(editedPaths.map((p) =>
|
|
12405
|
+
const editedSet = new Set(editedPaths.map((p) => path2.resolve(this.#cwd, p)));
|
|
12197
12406
|
if (this.#baseline === void 0) {
|
|
12198
12407
|
this.#baseline = /* @__PURE__ */ new Map();
|
|
12199
12408
|
for (const file of all) {
|
|
@@ -12218,7 +12427,7 @@ var init_diagnostics = __esm({
|
|
|
12218
12427
|
* re-surface (e.g. the agent edited it again). The baseline is left intact.
|
|
12219
12428
|
*/
|
|
12220
12429
|
clearDeliveredForFile(uri) {
|
|
12221
|
-
this.#delivered.delete(
|
|
12430
|
+
this.#delivered.delete(path2.resolve(this.#cwd, uri));
|
|
12222
12431
|
}
|
|
12223
12432
|
/** Drop all cross-turn state and the baseline (re-seeds on the next run). */
|
|
12224
12433
|
reset() {
|
|
@@ -12261,7 +12470,7 @@ var init_diagnostics = __esm({
|
|
|
12261
12470
|
// src/conductor/conductor.ts
|
|
12262
12471
|
import { Agent } from "indusagi/agent";
|
|
12263
12472
|
import { createZeroUsage as createZeroUsage2 } from "indusagi/ai";
|
|
12264
|
-
import * as
|
|
12473
|
+
import * as path3 from "node:path";
|
|
12265
12474
|
function reduceState(prev, action) {
|
|
12266
12475
|
switch (action.type) {
|
|
12267
12476
|
case "phase":
|
|
@@ -12320,7 +12529,7 @@ function createSessionConductor(options, deps = {}) {
|
|
|
12320
12529
|
const approvalHolder = { resolver: void 0 };
|
|
12321
12530
|
const approvalDelegate = async (toolName, input, opts) => {
|
|
12322
12531
|
const installed = approvalHolder.resolver;
|
|
12323
|
-
if (installed === void 0) return "
|
|
12532
|
+
if (installed === void 0) return "unavailable";
|
|
12324
12533
|
return installed(toolName, input, opts);
|
|
12325
12534
|
};
|
|
12326
12535
|
const gate = options.canUseTool?.(
|
|
@@ -12341,7 +12550,11 @@ function buildLiveAgent(options, deps, gate) {
|
|
|
12341
12550
|
if (card === void 0) {
|
|
12342
12551
|
throw new Error(`createSessionConductor: no model matches "${options.modelId}"`);
|
|
12343
12552
|
}
|
|
12344
|
-
return new LazyAgent(card.model, options, gate);
|
|
12553
|
+
return new LazyAgent(withGatewayBaseUrl(card.model, options.gatewayBaseUrls), options, gate);
|
|
12554
|
+
}
|
|
12555
|
+
function withGatewayBaseUrl(model, gatewayBaseUrls) {
|
|
12556
|
+
const url = gatewayBaseUrls?.[model.provider];
|
|
12557
|
+
return url ? { ...model, baseUrl: url } : model;
|
|
12345
12558
|
}
|
|
12346
12559
|
function makeAgent(model, options, gate) {
|
|
12347
12560
|
const agent = new Agent({
|
|
@@ -12431,7 +12644,7 @@ ${outcome.output}`.trimEnd();
|
|
|
12431
12644
|
timestamp: Date.now()
|
|
12432
12645
|
};
|
|
12433
12646
|
}
|
|
12434
|
-
var noopCondense, DEFAULT_RETRY, MAX_CONSECUTIVE_CONDENSE_FAILURES, THINKING_LADDER, DEFAULT_THINKING, PERMISSION_CYCLE, SessionConductorImpl, LazyAgent;
|
|
12647
|
+
var noopCondense, DEFAULT_RETRY, MAX_CONSECUTIVE_CONDENSE_FAILURES, MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT, THINKING_LADDER, DEFAULT_THINKING, PERMISSION_CYCLE, SessionConductorImpl, LazyAgent;
|
|
12435
12648
|
var init_conductor = __esm({
|
|
12436
12649
|
"src/conductor/conductor.ts"() {
|
|
12437
12650
|
"use strict";
|
|
@@ -12440,12 +12653,14 @@ var init_conductor = __esm({
|
|
|
12440
12653
|
init_signal_hub();
|
|
12441
12654
|
init_transcript_store();
|
|
12442
12655
|
init_skill_parse();
|
|
12656
|
+
init_quota_error();
|
|
12443
12657
|
init_plan_file();
|
|
12444
12658
|
init_window_budget();
|
|
12445
12659
|
init_diagnostics();
|
|
12446
12660
|
noopCondense = (messages) => messages;
|
|
12447
12661
|
DEFAULT_RETRY = { maxAttempts: 2, baseDelayMs: 250 };
|
|
12448
12662
|
MAX_CONSECUTIVE_CONDENSE_FAILURES = 3;
|
|
12663
|
+
MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT = 3;
|
|
12449
12664
|
THINKING_LADDER = ["off", "low", "medium", "high"];
|
|
12450
12665
|
DEFAULT_THINKING = "off";
|
|
12451
12666
|
PERMISSION_CYCLE = ["default", "acceptEdits", "plan", "bypass"];
|
|
@@ -12477,6 +12692,29 @@ var init_conductor = __esm({
|
|
|
12477
12692
|
* to 0 on the next successful condense.
|
|
12478
12693
|
*/
|
|
12479
12694
|
#condenseFailures = 0;
|
|
12695
|
+
/**
|
|
12696
|
+
* The cancel handle for an in-flight MANUAL condense (`/compact`), or
|
|
12697
|
+
* `undefined` when none is running. {@link cancelCondense} (and {@link abort},
|
|
12698
|
+
* so a user's Esc stops a compaction the same way it stops a turn) abort it;
|
|
12699
|
+
* {@link #runCondense} then discards the digest and reports `"cancelled"`.
|
|
12700
|
+
*/
|
|
12701
|
+
#condenseAbort;
|
|
12702
|
+
/**
|
|
12703
|
+
* The session's per-call credential resolver (the same one the framework
|
|
12704
|
+
* Agent uses). The condense seam resolves the bound model's key through it so
|
|
12705
|
+
* the summarizer's model call authenticates exactly like a turn — including
|
|
12706
|
+
* server-tier sessions, whose ONLY credential is the vended session token
|
|
12707
|
+
* (no env var exists for the summarizer to fall back to).
|
|
12708
|
+
*/
|
|
12709
|
+
#getApiKey;
|
|
12710
|
+
/**
|
|
12711
|
+
* Whether the next in-flight-turn abort is an EXPECTED steer (Ctrl+X ran
|
|
12712
|
+
* {@link steerNow}): the unwinding turn consumes the rejection quietly —
|
|
12713
|
+
* no terminal fault, no error toast, no busy-spinner drop — because the
|
|
12714
|
+
* steered turn takes over immediately. Reset at every turn start so a stale
|
|
12715
|
+
* flag can never swallow a genuine later fault.
|
|
12716
|
+
*/
|
|
12717
|
+
#steerPending = false;
|
|
12480
12718
|
/**
|
|
12481
12719
|
* Canonical id of the model to fall back to when the bound model is overloaded
|
|
12482
12720
|
* (HTTP 529), or `undefined` when no `--fallback-model` was configured. When
|
|
@@ -12484,6 +12722,20 @@ var init_conductor = __esm({
|
|
|
12484
12722
|
* and retries instead of surfacing a terminal fault.
|
|
12485
12723
|
*/
|
|
12486
12724
|
#fallbackModelId;
|
|
12725
|
+
/**
|
|
12726
|
+
* Base URL of the indus model gateway to route this session through ("server
|
|
12727
|
+
* mode"), or `undefined` for the normal direct-to-provider path. When set,
|
|
12728
|
+
* every model bind clones the framework model with its `baseUrl` swapped to
|
|
12729
|
+
* this URL (see {@link withGatewayBaseUrl}) so requests flow through the
|
|
12730
|
+
* quota-enforcing server while the session token (vended by `getApiKey`)
|
|
12731
|
+
* authenticates them. Absent leaves the local-key path byte-for-byte unchanged.
|
|
12732
|
+
*
|
|
12733
|
+
* Not `readonly`: {@link updateGatewayBaseUrls} replaces this map when a
|
|
12734
|
+
* mid-session sign-in changes which providers are gateway-eligible, so a
|
|
12735
|
+
* later rebind (see `#bindModel`/`#applyModelCard`) picks up the fresh
|
|
12736
|
+
* routing without waiting for a full conductor rebuild.
|
|
12737
|
+
*/
|
|
12738
|
+
#gatewayBaseUrls;
|
|
12487
12739
|
/**
|
|
12488
12740
|
* Whether the one-shot fallback swap has already fired for the CURRENT turn.
|
|
12489
12741
|
* Reset to `false` at the top of every {@link #runTurn} (not per attempt) so a
|
|
@@ -12535,6 +12787,13 @@ var init_conductor = __esm({
|
|
|
12535
12787
|
* {@link #runPostEditDiagnostics} at the turn-end seam.
|
|
12536
12788
|
*/
|
|
12537
12789
|
#editedThisTurn = /* @__PURE__ */ new Set();
|
|
12790
|
+
/**
|
|
12791
|
+
* How many diagnostics follow-ups have been auto-injected since the last REAL
|
|
12792
|
+
* user prompt. Reset by {@link submit}; capped by
|
|
12793
|
+
* {@link MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT} so a model that cannot satisfy a
|
|
12794
|
+
* checker can never be re-prompted forever without the user asking again.
|
|
12795
|
+
*/
|
|
12796
|
+
#diagnosticFollowUps = 0;
|
|
12538
12797
|
/**
|
|
12539
12798
|
* The mode captured the moment plan mode was entered, restored when plan mode is
|
|
12540
12799
|
* left. `undefined` whenever the session is not in (or paused from) plan mode.
|
|
@@ -12574,6 +12833,7 @@ var init_conductor = __esm({
|
|
|
12574
12833
|
this.#hub = deps.hub ?? new SignalHub();
|
|
12575
12834
|
this.#matcher = deps.matcher;
|
|
12576
12835
|
this.#condense = deps.condense ?? noopCondense;
|
|
12836
|
+
this.#getApiKey = options.getApiKey;
|
|
12577
12837
|
this.#retry = deps.retry ?? DEFAULT_RETRY;
|
|
12578
12838
|
this.#autoCompact = options.autoCompact ?? true;
|
|
12579
12839
|
this.#sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -12581,6 +12841,7 @@ var init_conductor = __esm({
|
|
|
12581
12841
|
this.#modeHolder = modeHolder ?? { mode: options.permissionMode ?? "default" };
|
|
12582
12842
|
this.#approvalHolder = approvalHolder ?? { resolver: void 0 };
|
|
12583
12843
|
this.#fallbackModelId = options.fallbackModelId;
|
|
12844
|
+
this.#gatewayBaseUrls = options.gatewayBaseUrls;
|
|
12584
12845
|
this.#workspace = options.workspace ?? process.cwd();
|
|
12585
12846
|
this.#plansDir = options.plansDir;
|
|
12586
12847
|
this.#checkpoint = options.checkpoint;
|
|
@@ -12597,7 +12858,10 @@ var init_conductor = __esm({
|
|
|
12597
12858
|
// no fault initially
|
|
12598
12859
|
};
|
|
12599
12860
|
const initial = this.#matcher?.resolveCard(options.modelId);
|
|
12600
|
-
this.#boundModel =
|
|
12861
|
+
this.#boundModel = withGatewayBaseUrl(
|
|
12862
|
+
initial?.model ?? agent.state.model,
|
|
12863
|
+
this.#gatewayBaseUrls
|
|
12864
|
+
);
|
|
12601
12865
|
}
|
|
12602
12866
|
/* ---- public surface ---- */
|
|
12603
12867
|
subscribe(handler) {
|
|
@@ -12620,12 +12884,18 @@ var init_conductor = __esm({
|
|
|
12620
12884
|
return [...this.#matcher.resolveAll("")];
|
|
12621
12885
|
}
|
|
12622
12886
|
abort() {
|
|
12887
|
+
if (this.#queue.length > 0) {
|
|
12888
|
+
this.#queue.length = 0;
|
|
12889
|
+
this.#hub.emit({ kind: "queue", count: 0 });
|
|
12890
|
+
}
|
|
12891
|
+
this.#condenseAbort?.abort();
|
|
12623
12892
|
this.#agent.abort();
|
|
12624
12893
|
this.#dispatch({ type: "fault", fault: conductorFault("aborted", "turn aborted by caller") });
|
|
12625
12894
|
this.#hub.emit({ kind: "fault", fault: conductorFault("aborted", "turn aborted by caller") });
|
|
12626
12895
|
this.#hub.emit({ kind: "idle" });
|
|
12627
12896
|
}
|
|
12628
12897
|
async submit(input) {
|
|
12898
|
+
this.#diagnosticFollowUps = 0;
|
|
12629
12899
|
if (this.#busy) {
|
|
12630
12900
|
this.enqueue(input);
|
|
12631
12901
|
return this.#state;
|
|
@@ -12660,6 +12930,22 @@ var init_conductor = __esm({
|
|
|
12660
12930
|
this.#hub.emit({ kind: "queue", count: this.#queue.length });
|
|
12661
12931
|
return popped.text;
|
|
12662
12932
|
}
|
|
12933
|
+
steerNow() {
|
|
12934
|
+
const promoted = this.#queue.pop();
|
|
12935
|
+
if (promoted === void 0) return false;
|
|
12936
|
+
this.#queue.unshift({ mode: "steer", text: promoted.text });
|
|
12937
|
+
this.#hub.emit({ kind: "queue", count: this.#queue.length });
|
|
12938
|
+
if (this.#busy) {
|
|
12939
|
+
this.#steerPending = true;
|
|
12940
|
+
this.#condenseAbort?.abort();
|
|
12941
|
+
this.#agent.abort();
|
|
12942
|
+
return true;
|
|
12943
|
+
}
|
|
12944
|
+
const next = this.#takeNext();
|
|
12945
|
+
this.#hub.emit({ kind: "queue", count: this.#queue.length });
|
|
12946
|
+
void this.submit(next.text);
|
|
12947
|
+
return true;
|
|
12948
|
+
}
|
|
12663
12949
|
/**
|
|
12664
12950
|
* Drain the pending-input queue in order, running each entry as its own turn.
|
|
12665
12951
|
* `steer`-mode entries are taken ahead of plain follow-ups so an interrupt is
|
|
@@ -12697,6 +12983,7 @@ var init_conductor = __esm({
|
|
|
12697
12983
|
const prompt = skill ? skill.body : input;
|
|
12698
12984
|
this.#inFlightTools.length = 0;
|
|
12699
12985
|
this.#fallbackTried = false;
|
|
12986
|
+
this.#steerPending = false;
|
|
12700
12987
|
this.#checkpoint?.setActiveNodeId(this.#store.head.leaf);
|
|
12701
12988
|
this.#dispatch({ type: "phase", phase: "streaming" });
|
|
12702
12989
|
if (this.#diagnostics !== void 0 && !this.#diagnostics.hasBaseline) {
|
|
@@ -12708,7 +12995,7 @@ var init_conductor = __esm({
|
|
|
12708
12995
|
const baseline = this.#agent.state.messages.length;
|
|
12709
12996
|
const clean = await this.#runWithRetry(prompt);
|
|
12710
12997
|
if (!clean) {
|
|
12711
|
-
this.#hub.emit({ kind: "idle" });
|
|
12998
|
+
if (this.#queue.length === 0) this.#hub.emit({ kind: "idle" });
|
|
12712
12999
|
return this.#state;
|
|
12713
13000
|
}
|
|
12714
13001
|
await this.#persistTail(baseline);
|
|
@@ -12722,7 +13009,7 @@ var init_conductor = __esm({
|
|
|
12722
13009
|
this.#dispatch({ type: "head", head: this.#store.head });
|
|
12723
13010
|
}
|
|
12724
13011
|
await this.#runPlanHandshakes();
|
|
12725
|
-
this.#hub.emit({ kind: "idle" });
|
|
13012
|
+
if (this.#queue.length === 0) this.#hub.emit({ kind: "idle" });
|
|
12726
13013
|
return this.#state;
|
|
12727
13014
|
}
|
|
12728
13015
|
async newSession() {
|
|
@@ -12732,6 +13019,7 @@ var init_conductor = __esm({
|
|
|
12732
13019
|
this.#queue.length = 0;
|
|
12733
13020
|
this.#inFlightTools.length = 0;
|
|
12734
13021
|
this.#condenseFailures = 0;
|
|
13022
|
+
this.#diagnosticFollowUps = 0;
|
|
12735
13023
|
this.#agent.replaceMessages([]);
|
|
12736
13024
|
this.#store.startNewSession(newSessionId());
|
|
12737
13025
|
this.#sessionName = void 0;
|
|
@@ -12772,6 +13060,19 @@ var init_conductor = __esm({
|
|
|
12772
13060
|
selectModel(id) {
|
|
12773
13061
|
this.#bindModel(id);
|
|
12774
13062
|
}
|
|
13063
|
+
/**
|
|
13064
|
+
* Replace the server-tier gateway routing map and immediately re-bind the
|
|
13065
|
+
* currently selected model against it, so a mid-session sign-in (`/login` ->
|
|
13066
|
+
* "Indus Server") takes effect on the very next turn instead of requiring a
|
|
13067
|
+
* session restart. Re-resolves the current model's catalog card via
|
|
13068
|
+
* {@link #bindModel} rather than mutating `#boundModel` directly, so the
|
|
13069
|
+
* rebind goes through the exact same path as `selectModel`/`cycleModel`
|
|
13070
|
+
* (tool deck, thinking level, and state dispatch all stay consistent).
|
|
13071
|
+
*/
|
|
13072
|
+
updateGatewayBaseUrls(map) {
|
|
13073
|
+
this.#gatewayBaseUrls = map;
|
|
13074
|
+
this.#bindModel(this.#state.modelId);
|
|
13075
|
+
}
|
|
12775
13076
|
/**
|
|
12776
13077
|
* Resolve a model by canonical id, bind it on the agent for subsequent turns,
|
|
12777
13078
|
* track the full model object, and record the new id in state. A miss surfaces
|
|
@@ -12795,8 +13096,9 @@ var init_conductor = __esm({
|
|
|
12795
13096
|
* so it must resolve its own card and call straight into here.
|
|
12796
13097
|
*/
|
|
12797
13098
|
#applyModelCard(card) {
|
|
12798
|
-
|
|
12799
|
-
this.#
|
|
13099
|
+
const model = withGatewayBaseUrl(card.model, this.#gatewayBaseUrls);
|
|
13100
|
+
this.#agent.setModel(model);
|
|
13101
|
+
this.#boundModel = model;
|
|
12800
13102
|
this.#agent.setThinkingLevel?.(this.#thinking);
|
|
12801
13103
|
this.#dispatch({ type: "model", modelId: card.id });
|
|
12802
13104
|
}
|
|
@@ -12825,7 +13127,10 @@ var init_conductor = __esm({
|
|
|
12825
13127
|
fault: conductorFault(
|
|
12826
13128
|
"model",
|
|
12827
13129
|
`Switched to ${card.id} due to high demand for ${previous}`
|
|
12828
|
-
)
|
|
13130
|
+
),
|
|
13131
|
+
// The turn keeps running on the fallback model — this is an in-turn
|
|
13132
|
+
// notice, not the turn's end, so a busy/in-flight indicator must survive it.
|
|
13133
|
+
transient: true
|
|
12829
13134
|
});
|
|
12830
13135
|
return true;
|
|
12831
13136
|
}
|
|
@@ -12852,11 +13157,32 @@ var init_conductor = __esm({
|
|
|
12852
13157
|
return true;
|
|
12853
13158
|
} catch (error) {
|
|
12854
13159
|
unsubscribe();
|
|
13160
|
+
if (this.#steerPending) {
|
|
13161
|
+
this.#steerPending = false;
|
|
13162
|
+
return false;
|
|
13163
|
+
}
|
|
13164
|
+
if (isQuotaFault(error)) {
|
|
13165
|
+
const fault2 = conductorFault(
|
|
13166
|
+
"model",
|
|
13167
|
+
quotaErrorMessage(error) ?? "You've hit your indus usage limit.",
|
|
13168
|
+
error
|
|
13169
|
+
);
|
|
13170
|
+
this.#dispatch({ type: "fault", fault: fault2 });
|
|
13171
|
+
this.#hub.emit({ kind: "fault", fault: fault2 });
|
|
13172
|
+
return false;
|
|
13173
|
+
}
|
|
12855
13174
|
if (attempt < this.#retry.maxAttempts && isTransient(error)) {
|
|
12856
13175
|
attempt++;
|
|
12857
13176
|
this.#hub.emit({
|
|
12858
13177
|
kind: "fault",
|
|
12859
|
-
fault: conductorFault("model", `transient model fault; retry ${attempt}`, error)
|
|
13178
|
+
fault: conductorFault("model", `transient model fault; retry ${attempt}`, error),
|
|
13179
|
+
// The retry loop is about to try again on the SAME turn — this is an
|
|
13180
|
+
// in-turn notice, not the turn's end. Without this flag the console
|
|
13181
|
+
// clears its busy/in-flight indicator here and never sets it back
|
|
13182
|
+
// (busy only flips true again at the START of the next turn), so the
|
|
13183
|
+
// agent looks "stuck" for the rest of a turn that is actually still
|
|
13184
|
+
// retrying/streaming underneath.
|
|
13185
|
+
transient: true
|
|
12860
13186
|
});
|
|
12861
13187
|
await this.#sleep(this.#retry.baseDelayMs * 2 ** (attempt - 1));
|
|
12862
13188
|
continue;
|
|
@@ -12892,6 +13218,7 @@ var init_conductor = __esm({
|
|
|
12892
13218
|
this.#capturePlanSignals(event.result);
|
|
12893
13219
|
}
|
|
12894
13220
|
for (const signal of translateAgentEvent(event)) {
|
|
13221
|
+
if (signal.kind === "fault" && this.#steerPending) continue;
|
|
12895
13222
|
if (signal.kind === "turn_end") {
|
|
12896
13223
|
this.#dispatch({
|
|
12897
13224
|
type: "usage",
|
|
@@ -12918,7 +13245,7 @@ var init_conductor = __esm({
|
|
|
12918
13245
|
const raw = args?.path;
|
|
12919
13246
|
if (typeof raw !== "string" || raw.length === 0) return;
|
|
12920
13247
|
if (!isTypeScriptOrJs(raw)) return;
|
|
12921
|
-
this.#editedThisTurn.add(
|
|
13248
|
+
this.#editedThisTurn.add(path3.resolve(this.#workspace, raw));
|
|
12922
13249
|
}
|
|
12923
13250
|
/* ---- plan mode ---- */
|
|
12924
13251
|
/**
|
|
@@ -13064,8 +13391,13 @@ var init_conductor = __esm({
|
|
|
13064
13391
|
* Invariants:
|
|
13065
13392
|
* - **never faults the turn** — every failure (a slow/absent checker, a
|
|
13066
13393
|
* parse error) is swallowed and the set is always cleared in `finally`;
|
|
13067
|
-
* - **
|
|
13068
|
-
*
|
|
13394
|
+
* - **can never loop forever** — a diagnostic key is delivered AT MOST ONCE
|
|
13395
|
+
* per session (the engine's delivered ledger is never cleared here; a
|
|
13396
|
+
* "fix" turn that fails to eliminate the same error is NOT re-prompted
|
|
13397
|
+
* with it), and even genuinely new errors stop re-prompting after
|
|
13398
|
+
* {@link MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT} consecutive follow-ups —
|
|
13399
|
+
* the agent must not keep running itself after its final report just
|
|
13400
|
+
* because a checker stays red;
|
|
13069
13401
|
* - inert when diagnostics are disabled (`#diagnostics === undefined`).
|
|
13070
13402
|
*/
|
|
13071
13403
|
async #runPostEditDiagnostics() {
|
|
@@ -13074,11 +13406,15 @@ var init_conductor = __esm({
|
|
|
13074
13406
|
this.#editedThisTurn.clear();
|
|
13075
13407
|
return;
|
|
13076
13408
|
}
|
|
13409
|
+
if (this.#diagnosticFollowUps >= MAX_DIAGNOSTIC_FOLLOWUPS_PER_PROMPT) {
|
|
13410
|
+
this.#editedThisTurn.clear();
|
|
13411
|
+
return;
|
|
13412
|
+
}
|
|
13077
13413
|
const edited = [...this.#editedThisTurn];
|
|
13078
13414
|
try {
|
|
13079
|
-
for (const uri of edited) engine.clearDeliveredForFile(uri);
|
|
13080
13415
|
const files = await engine.newDiagnostics(edited);
|
|
13081
13416
|
if (files.length > 0) {
|
|
13417
|
+
this.#diagnosticFollowUps++;
|
|
13082
13418
|
this.enqueue(
|
|
13083
13419
|
"Diagnostics for files you just changed (fix these before continuing):\n\n" + formatDiagnosticsSummary(files),
|
|
13084
13420
|
"followUp"
|
|
@@ -13115,12 +13451,29 @@ var init_conductor = __esm({
|
|
|
13115
13451
|
}
|
|
13116
13452
|
/**
|
|
13117
13453
|
* Manually drive the same condense path the auto-compactor uses, regardless of
|
|
13118
|
-
* the auto-compaction flag or the soft threshold
|
|
13119
|
-
*
|
|
13120
|
-
*
|
|
13454
|
+
* the auto-compaction flag or the soft threshold, and report the outcome.
|
|
13455
|
+
*
|
|
13456
|
+
* Runs under the busy flag so a prompt submitted mid-compaction QUEUES (and
|
|
13457
|
+
* drains once the condense settles) instead of racing the rebind; is
|
|
13458
|
+
* cancellable via {@link cancelCondense} (the result is discarded); and
|
|
13459
|
+
* refuses (`"busy"`) while a real turn is in flight rather than condensing a
|
|
13460
|
+
* branch that is still growing.
|
|
13121
13461
|
*/
|
|
13122
13462
|
async condense() {
|
|
13123
|
-
|
|
13463
|
+
if (this.#busy) return "busy";
|
|
13464
|
+
this.#busy = true;
|
|
13465
|
+
this.#condenseAbort = new AbortController();
|
|
13466
|
+
try {
|
|
13467
|
+
const outcome = await this.#runCondense(true, this.#condenseAbort.signal);
|
|
13468
|
+
await this.#drainQueue();
|
|
13469
|
+
return outcome;
|
|
13470
|
+
} finally {
|
|
13471
|
+
this.#condenseAbort = void 0;
|
|
13472
|
+
this.#busy = false;
|
|
13473
|
+
}
|
|
13474
|
+
}
|
|
13475
|
+
cancelCondense() {
|
|
13476
|
+
this.#condenseAbort?.abort();
|
|
13124
13477
|
}
|
|
13125
13478
|
/* ---- branch navigation ---- */
|
|
13126
13479
|
async fork(entryId) {
|
|
@@ -13321,27 +13674,51 @@ var init_conductor = __esm({
|
|
|
13321
13674
|
* to a local stub). A throw surfaces an `overflow` fault and bumps the
|
|
13322
13675
|
* consecutive-failure counter (the circuit breaker); a clean run resets it.
|
|
13323
13676
|
*/
|
|
13324
|
-
async #runCondense(force) {
|
|
13677
|
+
async #runCondense(force, signal) {
|
|
13325
13678
|
const branch = this.#store.pathTo();
|
|
13679
|
+
const prior = this.#state.phase;
|
|
13326
13680
|
this.#dispatch({ type: "phase", phase: "condensing" });
|
|
13327
|
-
this.#hub.emit({ kind: "compacted" });
|
|
13328
13681
|
try {
|
|
13329
13682
|
const before = branch.map((entry) => entry.content);
|
|
13683
|
+
let apiKey;
|
|
13684
|
+
if (this.#boundModel !== void 0 && this.#getApiKey !== void 0) {
|
|
13685
|
+
try {
|
|
13686
|
+
apiKey = await this.#getApiKey(String(this.#boundModel.provider));
|
|
13687
|
+
} catch {
|
|
13688
|
+
}
|
|
13689
|
+
}
|
|
13330
13690
|
const after = await this.#condense(before, {
|
|
13331
13691
|
force,
|
|
13332
13692
|
...this.#boundModel !== void 0 ? { model: this.#boundModel } : {},
|
|
13333
|
-
contextTokens: this.#state.contextTokens
|
|
13693
|
+
contextTokens: this.#state.contextTokens,
|
|
13694
|
+
...signal !== void 0 ? { signal } : {},
|
|
13695
|
+
...apiKey !== void 0 ? { apiKey } : {}
|
|
13334
13696
|
});
|
|
13335
|
-
if (
|
|
13336
|
-
this.#
|
|
13337
|
-
|
|
13697
|
+
if (signal?.aborted) {
|
|
13698
|
+
this.#dispatch({ type: "phase", phase: prior });
|
|
13699
|
+
return "cancelled";
|
|
13338
13700
|
}
|
|
13701
|
+
if (after.length >= before.length) {
|
|
13702
|
+
this.#condenseFailures = 0;
|
|
13703
|
+
this.#dispatch({ type: "phase", phase: prior });
|
|
13704
|
+
return "nothing";
|
|
13705
|
+
}
|
|
13706
|
+
this.#agent.replaceMessages([...after]);
|
|
13707
|
+
await this.#persistCondenseBoundary(branch, after);
|
|
13339
13708
|
this.#condenseFailures = 0;
|
|
13709
|
+
if (force) {
|
|
13710
|
+
this.#dispatch({ type: "usage", usage: createZeroUsage2(), contextTokens: 0 });
|
|
13711
|
+
await this.#persistUsage();
|
|
13712
|
+
}
|
|
13713
|
+
this.#hub.emit({ kind: "compacted", manual: force });
|
|
13714
|
+
this.#dispatch({ type: "phase", phase: prior });
|
|
13715
|
+
return "condensed";
|
|
13340
13716
|
} catch (error) {
|
|
13341
13717
|
this.#condenseFailures++;
|
|
13342
13718
|
const fault = conductorFault("overflow", "auto-condense failed", error);
|
|
13343
13719
|
this.#dispatch({ type: "fault", fault });
|
|
13344
13720
|
this.#hub.emit({ kind: "fault", fault });
|
|
13721
|
+
return "failed";
|
|
13345
13722
|
}
|
|
13346
13723
|
}
|
|
13347
13724
|
/**
|
|
@@ -13690,11 +14067,11 @@ function consumeWrapperOptions(rest, wrapper) {
|
|
|
13690
14067
|
}
|
|
13691
14068
|
function parseBashCommand(command) {
|
|
13692
14069
|
if (typeof command !== "string" || command.trim().length === 0) return [];
|
|
13693
|
-
const
|
|
13694
|
-
parseInto(command,
|
|
13695
|
-
return
|
|
14070
|
+
const out2 = [];
|
|
14071
|
+
parseInto(command, out2);
|
|
14072
|
+
return out2;
|
|
13696
14073
|
}
|
|
13697
|
-
function parseInto(command,
|
|
14074
|
+
function parseInto(command, out2) {
|
|
13698
14075
|
for (const slice of splitTopLevel(command)) {
|
|
13699
14076
|
const { outer, inner } = extractSubshells(slice);
|
|
13700
14077
|
if (outer.length > 0) {
|
|
@@ -13703,7 +14080,7 @@ function parseInto(command, out) {
|
|
|
13703
14080
|
const { rest, elevated } = stripWrappers(argv);
|
|
13704
14081
|
const name = rest[0];
|
|
13705
14082
|
if (name !== void 0 && name.length > 0) {
|
|
13706
|
-
|
|
14083
|
+
out2.push({
|
|
13707
14084
|
name: name.toLowerCase(),
|
|
13708
14085
|
args: rest.slice(1),
|
|
13709
14086
|
elevated,
|
|
@@ -13713,7 +14090,7 @@ function parseInto(command, out) {
|
|
|
13713
14090
|
}
|
|
13714
14091
|
}
|
|
13715
14092
|
for (const body of inner) {
|
|
13716
|
-
if (body.trim().length > 0) parseInto(body,
|
|
14093
|
+
if (body.trim().length > 0) parseInto(body, out2);
|
|
13717
14094
|
}
|
|
13718
14095
|
}
|
|
13719
14096
|
}
|
|
@@ -14017,8 +14394,18 @@ function resolveRuleDecision(toolName, input, rules, mode, readOnlyExtra) {
|
|
|
14017
14394
|
}
|
|
14018
14395
|
return "ask";
|
|
14019
14396
|
}
|
|
14397
|
+
function allowAlwaysRuleStrings(toolName, input) {
|
|
14398
|
+
if (isBashTool(toolName)) {
|
|
14399
|
+
const bag = input;
|
|
14400
|
+
const command = typeof input === "string" ? input : bag !== null && typeof bag === "object" && typeof bag.command === "string" ? bag.command : "";
|
|
14401
|
+
if (command.length > 0) {
|
|
14402
|
+
return bashSubcommandSubjects(command).map((subject) => `${toolName}(${subject})`);
|
|
14403
|
+
}
|
|
14404
|
+
}
|
|
14405
|
+
return [toolName];
|
|
14406
|
+
}
|
|
14020
14407
|
function noResolverMessage(toolName) {
|
|
14021
|
-
return `Tool "${toolName}" requires approval, but
|
|
14408
|
+
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.`;
|
|
14022
14409
|
}
|
|
14023
14410
|
function declinedMessage(toolName) {
|
|
14024
14411
|
return `Tool "${toolName}" was denied by the user.`;
|
|
@@ -14060,15 +14447,34 @@ function createPermissionGate(config) {
|
|
|
14060
14447
|
} catch {
|
|
14061
14448
|
choice = "deny";
|
|
14062
14449
|
}
|
|
14063
|
-
if (choice === "
|
|
14064
|
-
|
|
14450
|
+
if (choice === "allow-once" || choice === "allow-always") {
|
|
14451
|
+
if (choice === "allow-always" && config.appendAllowRule) {
|
|
14452
|
+
for (const raw of allowAlwaysRuleStrings(toolName, input)) {
|
|
14453
|
+
config.appendAllowRule(makeRule("allow", raw));
|
|
14454
|
+
}
|
|
14455
|
+
}
|
|
14456
|
+
return { behavior: "allow" };
|
|
14065
14457
|
}
|
|
14066
|
-
if (choice === "
|
|
14067
|
-
|
|
14458
|
+
if (choice === "unavailable") {
|
|
14459
|
+
return { behavior: "deny", message: noResolverMessage(toolName) };
|
|
14068
14460
|
}
|
|
14069
|
-
return { behavior: "
|
|
14461
|
+
return { behavior: "deny", message: declinedMessage(toolName) };
|
|
14070
14462
|
};
|
|
14071
14463
|
}
|
|
14464
|
+
function collectReadOnlyToolNames(tools) {
|
|
14465
|
+
const names = /* @__PURE__ */ new Set();
|
|
14466
|
+
for (const tool of tools) {
|
|
14467
|
+
if (tool.readOnly === true) names.add(tool.name);
|
|
14468
|
+
}
|
|
14469
|
+
return names;
|
|
14470
|
+
}
|
|
14471
|
+
function createSubagentPermissionGate(policy, tools) {
|
|
14472
|
+
return createPermissionGate({
|
|
14473
|
+
rules: policy.rules,
|
|
14474
|
+
mode: policy.mode,
|
|
14475
|
+
readOnlyToolNames: collectReadOnlyToolNames(tools)
|
|
14476
|
+
});
|
|
14477
|
+
}
|
|
14072
14478
|
var READ_ONLY_TOOL_NAMES, EDIT_TOOL_NAMES;
|
|
14073
14479
|
var init_permissions = __esm({
|
|
14074
14480
|
"src/conductor/permissions.ts"() {
|
|
@@ -14102,14 +14508,17 @@ __export(conductor_exports, {
|
|
|
14102
14508
|
SignalHub: () => SignalHub,
|
|
14103
14509
|
TRANSCRIPT_SCHEMA: () => TRANSCRIPT_SCHEMA,
|
|
14104
14510
|
TranscriptStore: () => TranscriptStore,
|
|
14511
|
+
allowAlwaysRuleStrings: () => allowAlwaysRuleStrings,
|
|
14105
14512
|
areDiagnosticsEqual: () => areDiagnosticsEqual,
|
|
14106
14513
|
bashSubcommandSubjects: () => bashSubcommandSubjects,
|
|
14107
14514
|
canonicalId: () => canonicalId,
|
|
14108
14515
|
catastrophicReason: () => catastrophicReason,
|
|
14516
|
+
collectReadOnlyToolNames: () => collectReadOnlyToolNames,
|
|
14109
14517
|
conductorFault: () => conductorFault,
|
|
14110
14518
|
createDiagnosticKey: () => createDiagnosticKey,
|
|
14111
14519
|
createPermissionGate: () => createPermissionGate,
|
|
14112
14520
|
createSessionConductor: () => createSessionConductor,
|
|
14521
|
+
createSubagentPermissionGate: () => createSubagentPermissionGate,
|
|
14113
14522
|
deduplicateAndCap: () => deduplicateAndCap,
|
|
14114
14523
|
evaluateCatastrophic: () => evaluateCatastrophic,
|
|
14115
14524
|
formatDiagnosticsSummary: () => formatDiagnosticsSummary,
|
|
@@ -14136,7 +14545,8 @@ __export(conductor_exports, {
|
|
|
14136
14545
|
runTscDiagnostics: () => runTscDiagnostics,
|
|
14137
14546
|
toCardRef: () => toCardRef,
|
|
14138
14547
|
toolMatchesRule: () => toolMatchesRule,
|
|
14139
|
-
translateAgentEvent: () => translateAgentEvent
|
|
14548
|
+
translateAgentEvent: () => translateAgentEvent,
|
|
14549
|
+
withGatewayBaseUrl: () => withGatewayBaseUrl
|
|
14140
14550
|
});
|
|
14141
14551
|
var init_conductor2 = __esm({
|
|
14142
14552
|
"src/conductor/index.ts"() {
|
|
@@ -14214,13 +14624,22 @@ function createWorkflowAgentRunner(opts) {
|
|
|
14214
14624
|
if (model === void 0) {
|
|
14215
14625
|
throw new Error(`no model resolved for workflow subagent: ${options.model ?? opts.modelId}`);
|
|
14216
14626
|
}
|
|
14627
|
+
const gatewayBaseUrls = await opts.getGatewayBaseUrls?.();
|
|
14628
|
+
const tools = buildTools();
|
|
14217
14629
|
agent = new Agent2({
|
|
14218
14630
|
initialState: {
|
|
14219
|
-
model,
|
|
14631
|
+
model: withGatewayBaseUrl(model, gatewayBaseUrls),
|
|
14220
14632
|
systemPrompt: system,
|
|
14221
|
-
tools
|
|
14633
|
+
tools
|
|
14222
14634
|
},
|
|
14223
|
-
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {}
|
|
14635
|
+
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {},
|
|
14636
|
+
// Gate the subagent's inner tool loop with the parent session's live
|
|
14637
|
+
// policy (rules + current mode). Resolver-less: `ask` denies — a
|
|
14638
|
+
// subagent cannot prompt — while deny rules, plan mode, and the
|
|
14639
|
+
// catastrophic-bash blocklist are enforced per inner tool call. The
|
|
14640
|
+
// `structured_output` capture tool is flagged readOnly, so a
|
|
14641
|
+
// schema-bound workflow still lands its result in every mode.
|
|
14642
|
+
...opts.permissionPolicy !== void 0 ? { canUseTool: createSubagentPermissionGate(opts.permissionPolicy, tools) } : {}
|
|
14224
14643
|
});
|
|
14225
14644
|
}
|
|
14226
14645
|
const activity = { tokensIn: 0, tokensOut: 0, toolCount: 0 };
|
|
@@ -14874,12 +15293,12 @@ function withdrawServer(ledger, server, at = (/* @__PURE__ */ new Date()).toISOS
|
|
|
14874
15293
|
return { log, snapshot: reduceLedger(log), nextSeq: seq };
|
|
14875
15294
|
}
|
|
14876
15295
|
function liveCapabilitiesForServer(ledger, server) {
|
|
14877
|
-
const
|
|
15296
|
+
const out2 = [];
|
|
14878
15297
|
for (const key of liveKeysForServer(ledger, server)) {
|
|
14879
15298
|
const cap = ledger.snapshot.live.get(key);
|
|
14880
|
-
if (cap !== void 0)
|
|
15299
|
+
if (cap !== void 0) out2.push(cap);
|
|
14881
15300
|
}
|
|
14882
|
-
return
|
|
15301
|
+
return out2;
|
|
14883
15302
|
}
|
|
14884
15303
|
function liveCapabilities(ledger) {
|
|
14885
15304
|
return [...ledger.snapshot.live.values()];
|
|
@@ -14898,11 +15317,11 @@ function liveKeysForServer(ledger, server) {
|
|
|
14898
15317
|
lastServer.set(entry.key, entry.server);
|
|
14899
15318
|
}
|
|
14900
15319
|
}
|
|
14901
|
-
const
|
|
15320
|
+
const out2 = [];
|
|
14902
15321
|
for (const key of ledger.snapshot.live.keys()) {
|
|
14903
|
-
if (lastServer.get(key) === server)
|
|
15322
|
+
if (lastServer.get(key) === server) out2.push(key);
|
|
14904
15323
|
}
|
|
14905
|
-
return
|
|
15324
|
+
return out2;
|
|
14906
15325
|
}
|
|
14907
15326
|
var init_ledger = __esm({
|
|
14908
15327
|
"src/capability-deck/bridge-ledger/ledger.ts"() {
|
|
@@ -15321,11 +15740,11 @@ function escapeChar(ch) {
|
|
|
15321
15740
|
}
|
|
15322
15741
|
}
|
|
15323
15742
|
function escapeHtml(text) {
|
|
15324
|
-
let
|
|
15743
|
+
let out2 = "";
|
|
15325
15744
|
for (const ch of text) {
|
|
15326
|
-
|
|
15745
|
+
out2 += escapeChar(ch) ?? ch;
|
|
15327
15746
|
}
|
|
15328
|
-
return
|
|
15747
|
+
return out2;
|
|
15329
15748
|
}
|
|
15330
15749
|
function classesFor(state) {
|
|
15331
15750
|
const classes = [];
|
|
@@ -15371,15 +15790,15 @@ function paintSgr(input) {
|
|
|
15371
15790
|
if (input.length === 0) return "";
|
|
15372
15791
|
const tokens = tokenizeSgr(input);
|
|
15373
15792
|
let state = { ...SGR_INITIAL_STATE };
|
|
15374
|
-
let
|
|
15793
|
+
let out2 = "";
|
|
15375
15794
|
for (const token of tokens) {
|
|
15376
15795
|
if (token.kind === "sgr") {
|
|
15377
15796
|
state = foldSgr(state, token.params);
|
|
15378
15797
|
} else {
|
|
15379
|
-
|
|
15798
|
+
out2 += renderRun(token.text, state);
|
|
15380
15799
|
}
|
|
15381
15800
|
}
|
|
15382
|
-
return
|
|
15801
|
+
return out2;
|
|
15383
15802
|
}
|
|
15384
15803
|
var BASE_PALETTE, BRIGHT_PALETTE, PALETTE_16, CODE_TABLE, SGR_CODE_TABLE, ESC, CLASS_PREFIX, FLAG_CLASSES;
|
|
15385
15804
|
var init_sgr = __esm({
|
|
@@ -15593,13 +16012,13 @@ function escapeRegExp(text) {
|
|
|
15593
16012
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15594
16013
|
}
|
|
15595
16014
|
function fill(template, values) {
|
|
15596
|
-
let
|
|
16015
|
+
let out2 = template;
|
|
15597
16016
|
for (const token of Object.values(SHELL_SLOTS)) {
|
|
15598
16017
|
const value = values[token] ?? "";
|
|
15599
16018
|
const marker = new RegExp(`\\{\\{${escapeRegExp(token)}\\}\\}`, "g");
|
|
15600
|
-
|
|
16019
|
+
out2 = out2.replace(marker, () => value);
|
|
15601
16020
|
}
|
|
15602
|
-
return
|
|
16021
|
+
return out2;
|
|
15603
16022
|
}
|
|
15604
16023
|
var PAGE_STYLES, CLIENT_SCRIPT, PAGE_SHELL;
|
|
15605
16024
|
var init_template = __esm({
|
|
@@ -15877,8 +16296,8 @@ function configuredMarked() {
|
|
|
15877
16296
|
return marked;
|
|
15878
16297
|
}
|
|
15879
16298
|
function renderMarkdown(md, source) {
|
|
15880
|
-
const
|
|
15881
|
-
return typeof
|
|
16299
|
+
const out2 = md.parse(source, { async: false });
|
|
16300
|
+
return typeof out2 === "string" ? out2 : "";
|
|
15882
16301
|
}
|
|
15883
16302
|
function renderImage(part) {
|
|
15884
16303
|
const src = `data:${escapeHtml2(part.mimeType)};base64,${part.data}`;
|
|
@@ -16056,8 +16475,9 @@ var init_transcript_export = __esm({
|
|
|
16056
16475
|
|
|
16057
16476
|
// src/console/slash/commands/integrations.ts
|
|
16058
16477
|
import { spawnSync } from "node:child_process";
|
|
16059
|
-
import { writeFileSync as writeFileSync3 } from "node:fs";
|
|
16060
|
-
import {
|
|
16478
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
|
|
16479
|
+
import { homedir as homedir2 } from "node:os";
|
|
16480
|
+
import { join as join10, resolve as resolve5 } from "node:path";
|
|
16061
16481
|
import {
|
|
16062
16482
|
createMCPAgentToolFactory,
|
|
16063
16483
|
loadMCPConfig,
|
|
@@ -16116,13 +16536,13 @@ function exportTranscriptHtml(ctx, target) {
|
|
|
16116
16536
|
if (messages.length === 0) {
|
|
16117
16537
|
return { ok: false, reason: "Nothing to export yet \u2014 the transcript is empty." };
|
|
16118
16538
|
}
|
|
16119
|
-
const
|
|
16539
|
+
const path4 = target.length > 0 ? resolve5(process.cwd(), target) : defaultExportPath();
|
|
16120
16540
|
try {
|
|
16121
16541
|
const html = publishTranscript(toPublishEntries(messages), {
|
|
16122
16542
|
title: "Session Transcript"
|
|
16123
16543
|
});
|
|
16124
|
-
writeFileSync3(
|
|
16125
|
-
return { ok: true, path:
|
|
16544
|
+
writeFileSync3(path4, html, "utf-8");
|
|
16545
|
+
return { ok: true, path: path4 };
|
|
16126
16546
|
} catch (cause) {
|
|
16127
16547
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
16128
16548
|
return { ok: false, reason: `Could not write the HTML export: ${message}` };
|
|
@@ -16345,7 +16765,7 @@ function runShare(ctx) {
|
|
|
16345
16765
|
});
|
|
16346
16766
|
return HANDLED;
|
|
16347
16767
|
}
|
|
16348
|
-
function
|
|
16768
|
+
function runLogin2(ctx) {
|
|
16349
16769
|
const provider = ctx.args.trim().toLowerCase();
|
|
16350
16770
|
if (provider.length > 0) {
|
|
16351
16771
|
ctx.openModal("signIn", { providerId: provider });
|
|
@@ -16354,10 +16774,82 @@ function runLogin(ctx) {
|
|
|
16354
16774
|
}
|
|
16355
16775
|
return HANDLED;
|
|
16356
16776
|
}
|
|
16777
|
+
function hasLocalProviderKey(provider) {
|
|
16778
|
+
if (provider.length === 0) return false;
|
|
16779
|
+
try {
|
|
16780
|
+
const file = join10(homedir2(), ".indusagi", "agent", "auth.json");
|
|
16781
|
+
const vault = JSON.parse(readFileSync6(file, "utf8"));
|
|
16782
|
+
const entry = vault[provider];
|
|
16783
|
+
return entry !== null && typeof entry === "object" && Object.keys(entry).length > 0;
|
|
16784
|
+
} catch {
|
|
16785
|
+
return false;
|
|
16786
|
+
}
|
|
16787
|
+
}
|
|
16788
|
+
function runStatus(ctx) {
|
|
16789
|
+
const modelId = ctx.conductor.snapshot().modelId;
|
|
16790
|
+
const provider = modelId.includes("/") ? modelId.split("/")[0] : modelId;
|
|
16791
|
+
void (async () => {
|
|
16792
|
+
let signedIn = false;
|
|
16793
|
+
try {
|
|
16794
|
+
signedIn = await hasValidServerToken();
|
|
16795
|
+
} catch {
|
|
16796
|
+
signedIn = false;
|
|
16797
|
+
}
|
|
16798
|
+
const eligible = isGatewayEligibleProvider(provider);
|
|
16799
|
+
const localKey = hasLocalProviderKey(provider);
|
|
16800
|
+
const viaServer = signedIn && eligible && !localKey;
|
|
16801
|
+
if (viaServer) {
|
|
16802
|
+
ctx.setStatus(
|
|
16803
|
+
info(`\u25CF server tier \u2014 ${modelId} routing via ${INDUS_SERVER_URL} (signed in)`)
|
|
16804
|
+
);
|
|
16805
|
+
} else if (localKey) {
|
|
16806
|
+
ctx.setStatus(
|
|
16807
|
+
info(`\u25CB local key \u2014 ${modelId}${signedIn ? " (signed in to server)" : ""}`)
|
|
16808
|
+
);
|
|
16809
|
+
} else if (!signedIn) {
|
|
16810
|
+
ctx.setStatus(
|
|
16811
|
+
warn(`signed out \u2014 ${modelId} has no key. Run /login to use the server tier.`)
|
|
16812
|
+
);
|
|
16813
|
+
} else {
|
|
16814
|
+
ctx.setStatus(
|
|
16815
|
+
info(`signed in \u2014 ${modelId} (${provider} is not gateway-eligible; needs a local key)`)
|
|
16816
|
+
);
|
|
16817
|
+
}
|
|
16818
|
+
})();
|
|
16819
|
+
return HANDLED;
|
|
16820
|
+
}
|
|
16821
|
+
function runUsage(ctx) {
|
|
16822
|
+
void (async () => {
|
|
16823
|
+
const token = await getServerToken();
|
|
16824
|
+
if (!token?.access_token) {
|
|
16825
|
+
ctx.setStatus(warn("Not signed in to the server \u2014 run /login to use the server tier."));
|
|
16826
|
+
return;
|
|
16827
|
+
}
|
|
16828
|
+
try {
|
|
16829
|
+
const res = await fetch(`${INDUS_SERVER_URL}/api/usage`, {
|
|
16830
|
+
headers: { Authorization: `Bearer ${token.access_token}` }
|
|
16831
|
+
});
|
|
16832
|
+
if (!res.ok) {
|
|
16833
|
+
ctx.setStatus(warn(`Couldn't read usage (HTTP ${res.status}).`));
|
|
16834
|
+
return;
|
|
16835
|
+
}
|
|
16836
|
+
const u = await res.json();
|
|
16837
|
+
const pct = u.limit > 0 ? Math.round(u.used / u.limit * 100) : 0;
|
|
16838
|
+
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");
|
|
16839
|
+
ctx.setStatus(u.allowed ? info(line) : warn(line));
|
|
16840
|
+
} catch (cause) {
|
|
16841
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
16842
|
+
ctx.setStatus(warn(`Usage check failed: ${message}`));
|
|
16843
|
+
}
|
|
16844
|
+
})();
|
|
16845
|
+
return HANDLED;
|
|
16846
|
+
}
|
|
16357
16847
|
var CLIPBOARD_WRITERS, PUBLISH_ROLES, mcpPool, mcpServers, memoryEnabled, MEMORY_SUBS, COMPOSIO_ENV_KEY, composioGateway, composioResolved, COMPOSIO_NO_KEY, COMPOSIO_SUBS, runMemory, runComposio, integrationCommands;
|
|
16358
16848
|
var init_integrations = __esm({
|
|
16359
16849
|
"src/console/slash/commands/integrations.ts"() {
|
|
16360
16850
|
"use strict";
|
|
16851
|
+
init_server_token();
|
|
16852
|
+
init_server_mode();
|
|
16361
16853
|
init_capability_deck();
|
|
16362
16854
|
init_transcript_export();
|
|
16363
16855
|
init_shared();
|
|
@@ -16549,17 +17041,31 @@ var init_integrations = __esm({
|
|
|
16549
17041
|
summary: "Sign in to a model provider.",
|
|
16550
17042
|
takesArgs: true,
|
|
16551
17043
|
run(ctx) {
|
|
16552
|
-
return
|
|
17044
|
+
return runLogin2(ctx);
|
|
16553
17045
|
}
|
|
16554
17046
|
},
|
|
16555
17047
|
{
|
|
16556
17048
|
name: "logout",
|
|
16557
|
-
summary: "Sign out
|
|
17049
|
+
summary: "Sign out: pick a provider account or the Indus Server session to clear.",
|
|
16558
17050
|
run(ctx) {
|
|
16559
17051
|
ctx.openModal("signOut");
|
|
16560
17052
|
return HANDLED;
|
|
16561
17053
|
}
|
|
16562
17054
|
},
|
|
17055
|
+
{
|
|
17056
|
+
name: "status",
|
|
17057
|
+
summary: "Show the server session and whether this model uses the server.",
|
|
17058
|
+
run(ctx) {
|
|
17059
|
+
return runStatus(ctx);
|
|
17060
|
+
}
|
|
17061
|
+
},
|
|
17062
|
+
{
|
|
17063
|
+
name: "usage",
|
|
17064
|
+
summary: "Show your server usage this month (tokens used / limit / cost).",
|
|
17065
|
+
run(ctx) {
|
|
17066
|
+
return runUsage(ctx);
|
|
17067
|
+
}
|
|
17068
|
+
},
|
|
16563
17069
|
{
|
|
16564
17070
|
name: "mcp",
|
|
16565
17071
|
summary: "Manage MCP servers and their tools.",
|
|
@@ -16684,19 +17190,19 @@ __export(builtins_exports, {
|
|
|
16684
17190
|
FAMILY: () => FAMILY,
|
|
16685
17191
|
SLASH_COMMANDS: () => SLASH_COMMANDS
|
|
16686
17192
|
});
|
|
16687
|
-
import { homedir as
|
|
16688
|
-
import { join as
|
|
17193
|
+
import { homedir as homedir3 } from "node:os";
|
|
17194
|
+
import { join as join11 } from "node:path";
|
|
16689
17195
|
function dynamicRoots() {
|
|
16690
|
-
const home =
|
|
17196
|
+
const home = homedir3();
|
|
16691
17197
|
const cwd = process.cwd();
|
|
16692
17198
|
return {
|
|
16693
17199
|
skills: [
|
|
16694
|
-
{ dir:
|
|
16695
|
-
{ dir:
|
|
17200
|
+
{ dir: join11(cwd, PROJECT_DIR, "skills"), origin: "project" },
|
|
17201
|
+
{ dir: join11(home, PROJECT_DIR, "skills"), origin: "user" }
|
|
16696
17202
|
],
|
|
16697
17203
|
macros: [
|
|
16698
|
-
{ dir:
|
|
16699
|
-
{ dir:
|
|
17204
|
+
{ dir: join11(cwd, PROJECT_DIR, "commands"), origin: "project", label: "project" },
|
|
17205
|
+
{ dir: join11(home, PROJECT_DIR, "commands"), origin: "user", label: "user" }
|
|
16700
17206
|
]
|
|
16701
17207
|
};
|
|
16702
17208
|
}
|
|
@@ -16813,7 +17319,7 @@ var BRAND = Object.freeze({
|
|
|
16813
17319
|
envShareViewer: "INDUSAGI_SHARE_VIEWER_URL",
|
|
16814
17320
|
shareViewerUrl: "https://buildwithindusagi.ai/session/"
|
|
16815
17321
|
});
|
|
16816
|
-
var VERSION = "0.2.
|
|
17322
|
+
var VERSION = "0.2.4";
|
|
16817
17323
|
|
|
16818
17324
|
// src/workspace/locator.ts
|
|
16819
17325
|
import { homedir } from "node:os";
|
|
@@ -17328,6 +17834,12 @@ var FLAG_SPECS = [
|
|
|
17328
17834
|
group: "tools",
|
|
17329
17835
|
describe: "Attach an external MCP server endpoint (comma-separated or repeated)."
|
|
17330
17836
|
},
|
|
17837
|
+
{
|
|
17838
|
+
name: "--permission-mode",
|
|
17839
|
+
kind: "string",
|
|
17840
|
+
group: "tools",
|
|
17841
|
+
describe: "Open in the given permission mode: default, acceptEdits, plan, or bypass. On headless runs (--print/--json) `default` denies tools that would prompt."
|
|
17842
|
+
},
|
|
17331
17843
|
/* ---- Meta ------------------------------------------------------------ */
|
|
17332
17844
|
{
|
|
17333
17845
|
name: "--help",
|
|
@@ -17676,8 +18188,8 @@ var AttachmentError = class extends Error {
|
|
|
17676
18188
|
if (detail.cause !== void 0) this.cause = detail.cause;
|
|
17677
18189
|
}
|
|
17678
18190
|
};
|
|
17679
|
-
function extensionOf(
|
|
17680
|
-
return extname(
|
|
18191
|
+
function extensionOf(path4) {
|
|
18192
|
+
return extname(path4).toLowerCase();
|
|
17681
18193
|
}
|
|
17682
18194
|
function isMissing(error) {
|
|
17683
18195
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
@@ -17888,7 +18400,7 @@ function doConfig(store, io) {
|
|
|
17888
18400
|
}
|
|
17889
18401
|
|
|
17890
18402
|
// src/launch/credentials.ts
|
|
17891
|
-
import { createInterface } from "node:readline/promises";
|
|
18403
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
17892
18404
|
import { getEnvApiKey, getOAuthProvider as getOAuthProvider2 } from "indusagi/ai";
|
|
17893
18405
|
|
|
17894
18406
|
// src/launch/oauth.ts
|
|
@@ -17901,6 +18413,256 @@ import {
|
|
|
17901
18413
|
openaiCodexOAuthProvider,
|
|
17902
18414
|
registerOAuthProvider
|
|
17903
18415
|
} from "indusagi/ai";
|
|
18416
|
+
|
|
18417
|
+
// src/launch/login.ts
|
|
18418
|
+
init_server_token();
|
|
18419
|
+
import { createInterface } from "node:readline/promises";
|
|
18420
|
+
import chalk from "chalk";
|
|
18421
|
+
var INDUS_CLIENT_ID = process.env.INDUS_CLIENT_ID ?? "indus-cli";
|
|
18422
|
+
var USER_AGENT = "indus CLI";
|
|
18423
|
+
var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
18424
|
+
var DEVICE_SCOPE = "openid profile email";
|
|
18425
|
+
var EXIT_OK = 0;
|
|
18426
|
+
var EXIT_FAILURE = 1;
|
|
18427
|
+
var SERVER_TIER_PROVIDER_ID = "indus-server";
|
|
18428
|
+
var LoginError = class extends Error {
|
|
18429
|
+
};
|
|
18430
|
+
function out(line = "") {
|
|
18431
|
+
process.stdout.write(`${line}
|
|
18432
|
+
`);
|
|
18433
|
+
}
|
|
18434
|
+
function err(line) {
|
|
18435
|
+
process.stderr.write(`${line}
|
|
18436
|
+
`);
|
|
18437
|
+
}
|
|
18438
|
+
function sleep(ms) {
|
|
18439
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
18440
|
+
}
|
|
18441
|
+
async function postJson(url, body) {
|
|
18442
|
+
const res = await fetch(url, {
|
|
18443
|
+
method: "POST",
|
|
18444
|
+
headers: {
|
|
18445
|
+
"content-type": "application/json",
|
|
18446
|
+
accept: "application/json",
|
|
18447
|
+
"user-agent": USER_AGENT
|
|
18448
|
+
},
|
|
18449
|
+
body: JSON.stringify(body)
|
|
18450
|
+
});
|
|
18451
|
+
const data = await res.json().catch(() => ({}));
|
|
18452
|
+
return { status: res.status, data };
|
|
18453
|
+
}
|
|
18454
|
+
function parseLoginArgs(tail) {
|
|
18455
|
+
let serverUrl = INDUS_SERVER_URL;
|
|
18456
|
+
let clientId = INDUS_CLIENT_ID;
|
|
18457
|
+
for (let i = 0; i < tail.length; i++) {
|
|
18458
|
+
const token = tail[i];
|
|
18459
|
+
const eq = token.indexOf("=");
|
|
18460
|
+
const name = eq >= 0 ? token.slice(0, eq) : token;
|
|
18461
|
+
const inline = eq >= 0 ? token.slice(eq + 1) : void 0;
|
|
18462
|
+
const take = () => inline !== void 0 ? inline : tail[++i];
|
|
18463
|
+
if (name === "--server-url") {
|
|
18464
|
+
const value = take();
|
|
18465
|
+
if (value) serverUrl = value;
|
|
18466
|
+
} else if (name === "--client-id") {
|
|
18467
|
+
const value = take();
|
|
18468
|
+
if (value) clientId = value;
|
|
18469
|
+
}
|
|
18470
|
+
}
|
|
18471
|
+
return { serverUrl: serverUrl.replace(/\/+$/, ""), clientId };
|
|
18472
|
+
}
|
|
18473
|
+
async function confirm(prompt, defaultValue) {
|
|
18474
|
+
if (!process.stdin.isTTY) return defaultValue;
|
|
18475
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
18476
|
+
try {
|
|
18477
|
+
const hint = defaultValue ? "Y/n" : "y/N";
|
|
18478
|
+
const answer = (await rl.question(`${prompt} [${hint}] `)).trim().toLowerCase();
|
|
18479
|
+
if (answer === "") return defaultValue;
|
|
18480
|
+
return answer === "y" || answer === "yes";
|
|
18481
|
+
} finally {
|
|
18482
|
+
rl.close();
|
|
18483
|
+
}
|
|
18484
|
+
}
|
|
18485
|
+
async function requestDeviceCode(serverUrl, clientId) {
|
|
18486
|
+
const { status, data } = await postJson(`${serverUrl}/api/auth/device/code`, {
|
|
18487
|
+
client_id: clientId,
|
|
18488
|
+
scope: DEVICE_SCOPE
|
|
18489
|
+
});
|
|
18490
|
+
if (status >= 400 || typeof data.device_code !== "string") {
|
|
18491
|
+
const e = data;
|
|
18492
|
+
throw new LoginError(
|
|
18493
|
+
`Authorization request failed: ${e.error_description ?? e.error ?? e.message ?? `HTTP ${status}`}`
|
|
18494
|
+
);
|
|
18495
|
+
}
|
|
18496
|
+
return data;
|
|
18497
|
+
}
|
|
18498
|
+
async function pollForToken(serverUrl, clientId, device) {
|
|
18499
|
+
let intervalMs = Math.max(1, device.interval ?? 5) * 1e3;
|
|
18500
|
+
const deadline = Date.now() + device.expires_in * 1e3;
|
|
18501
|
+
while (Date.now() < deadline) {
|
|
18502
|
+
await sleep(intervalMs);
|
|
18503
|
+
const { data } = await postJson(`${serverUrl}/api/auth/device/token`, {
|
|
18504
|
+
grant_type: DEVICE_GRANT_TYPE,
|
|
18505
|
+
device_code: device.device_code,
|
|
18506
|
+
client_id: clientId
|
|
18507
|
+
});
|
|
18508
|
+
if (typeof data.access_token === "string") {
|
|
18509
|
+
return data;
|
|
18510
|
+
}
|
|
18511
|
+
const code = data.error;
|
|
18512
|
+
switch (code) {
|
|
18513
|
+
case "authorization_pending":
|
|
18514
|
+
case void 0:
|
|
18515
|
+
break;
|
|
18516
|
+
case "slow_down":
|
|
18517
|
+
intervalMs += 5e3;
|
|
18518
|
+
break;
|
|
18519
|
+
case "access_denied":
|
|
18520
|
+
throw new LoginError("Authorization was denied.");
|
|
18521
|
+
case "expired_token":
|
|
18522
|
+
throw new LoginError("Device code expired. Run `indus login` again.");
|
|
18523
|
+
default:
|
|
18524
|
+
throw new LoginError(
|
|
18525
|
+
`Authorization error: ${data.error_description ?? code}`
|
|
18526
|
+
);
|
|
18527
|
+
}
|
|
18528
|
+
}
|
|
18529
|
+
throw new LoginError("Timed out waiting for authorization. Run `indus login` again.");
|
|
18530
|
+
}
|
|
18531
|
+
async function runServerTierLogin(callbacks, serverUrl = INDUS_SERVER_URL, clientId = INDUS_CLIENT_ID) {
|
|
18532
|
+
const device = await requestDeviceCode(serverUrl, clientId);
|
|
18533
|
+
callbacks.onAuth({
|
|
18534
|
+
url: device.verification_uri_complete ?? device.verification_uri,
|
|
18535
|
+
instructions: `Enter code ${device.user_code} to authorize this device.`
|
|
18536
|
+
});
|
|
18537
|
+
callbacks.onProgress?.("Waiting for authorization...");
|
|
18538
|
+
const token = await pollForToken(serverUrl, clientId, device);
|
|
18539
|
+
await storeServerToken(token);
|
|
18540
|
+
callbacks.onProgress?.("Server sign-in complete.");
|
|
18541
|
+
}
|
|
18542
|
+
async function doLogin(args) {
|
|
18543
|
+
const { serverUrl, clientId } = args;
|
|
18544
|
+
out();
|
|
18545
|
+
out(chalk.bold.cyan(" indus login"));
|
|
18546
|
+
out(chalk.dim(` ${serverUrl}`));
|
|
18547
|
+
out();
|
|
18548
|
+
const existing = await getServerToken();
|
|
18549
|
+
if (existing && !isServerTokenExpired(existing)) {
|
|
18550
|
+
const again = await confirm(
|
|
18551
|
+
chalk.yellow("Already authenticated. Log in again?"),
|
|
18552
|
+
false
|
|
18553
|
+
);
|
|
18554
|
+
if (!again) {
|
|
18555
|
+
out(chalk.dim(" Login cancelled \u2014 existing session preserved."));
|
|
18556
|
+
return EXIT_OK;
|
|
18557
|
+
}
|
|
18558
|
+
}
|
|
18559
|
+
try {
|
|
18560
|
+
out(chalk.dim(" Requesting device authorization..."));
|
|
18561
|
+
const device = await requestDeviceCode(serverUrl, clientId);
|
|
18562
|
+
const url = device.verification_uri_complete ?? device.verification_uri;
|
|
18563
|
+
out();
|
|
18564
|
+
out(` ${chalk.bold("Open this URL to authorize:")}`);
|
|
18565
|
+
out(` ${chalk.green.underline(url)}`);
|
|
18566
|
+
out();
|
|
18567
|
+
out(` ${chalk.bold("Verification code:")} ${chalk.bold.cyan(device.user_code)}`);
|
|
18568
|
+
out(
|
|
18569
|
+
chalk.dim(
|
|
18570
|
+
` Expires in ${Math.max(1, Math.floor(device.expires_in / 60))} min \xB7 polling every ${Math.max(
|
|
18571
|
+
1,
|
|
18572
|
+
device.interval ?? 5
|
|
18573
|
+
)}s`
|
|
18574
|
+
)
|
|
18575
|
+
);
|
|
18576
|
+
out();
|
|
18577
|
+
out(chalk.dim(" Waiting for authorization..."));
|
|
18578
|
+
const token = await pollForToken(serverUrl, clientId, device);
|
|
18579
|
+
const saved = await storeServerToken(token);
|
|
18580
|
+
out();
|
|
18581
|
+
out(chalk.green.bold(" Authentication successful."));
|
|
18582
|
+
if (saved) {
|
|
18583
|
+
out(chalk.dim(` Token stored at ${TOKEN_FILE}`));
|
|
18584
|
+
} else {
|
|
18585
|
+
out(
|
|
18586
|
+
chalk.yellow(
|
|
18587
|
+
" Warning: could not write the token to disk \u2014 you may need to log in again."
|
|
18588
|
+
)
|
|
18589
|
+
);
|
|
18590
|
+
}
|
|
18591
|
+
out();
|
|
18592
|
+
return EXIT_OK;
|
|
18593
|
+
} catch (error) {
|
|
18594
|
+
const message = error instanceof LoginError ? error.message : error instanceof Error ? error.message : String(error);
|
|
18595
|
+
err("");
|
|
18596
|
+
err(chalk.red(` Login failed: ${message}`));
|
|
18597
|
+
err("");
|
|
18598
|
+
return EXIT_FAILURE;
|
|
18599
|
+
}
|
|
18600
|
+
}
|
|
18601
|
+
async function doLogout() {
|
|
18602
|
+
const cleared = await clearServerToken();
|
|
18603
|
+
if (cleared) {
|
|
18604
|
+
out(chalk.green(" Logged out \u2014 server session token removed."));
|
|
18605
|
+
} else {
|
|
18606
|
+
out(chalk.dim(" No stored session token to remove."));
|
|
18607
|
+
}
|
|
18608
|
+
return EXIT_OK;
|
|
18609
|
+
}
|
|
18610
|
+
async function doWhoami(args) {
|
|
18611
|
+
const token = await getServerToken();
|
|
18612
|
+
if (!token || isServerTokenExpired(token)) {
|
|
18613
|
+
err(chalk.yellow(" Not logged in. Run `indus login` first."));
|
|
18614
|
+
return EXIT_FAILURE;
|
|
18615
|
+
}
|
|
18616
|
+
try {
|
|
18617
|
+
const res = await fetch(`${args.serverUrl}/api/user/me`, {
|
|
18618
|
+
method: "GET",
|
|
18619
|
+
headers: {
|
|
18620
|
+
authorization: `Bearer ${token.access_token}`,
|
|
18621
|
+
accept: "application/json",
|
|
18622
|
+
"user-agent": USER_AGENT
|
|
18623
|
+
}
|
|
18624
|
+
});
|
|
18625
|
+
if (res.status === 401) {
|
|
18626
|
+
err(chalk.yellow(" Session expired or invalid. Run `indus login` again."));
|
|
18627
|
+
return EXIT_FAILURE;
|
|
18628
|
+
}
|
|
18629
|
+
if (!res.ok) {
|
|
18630
|
+
err(chalk.red(` Could not fetch account: HTTP ${res.status}`));
|
|
18631
|
+
return EXIT_FAILURE;
|
|
18632
|
+
}
|
|
18633
|
+
const user = await res.json();
|
|
18634
|
+
out();
|
|
18635
|
+
out(chalk.bold(" Signed in as:"));
|
|
18636
|
+
out(` ${chalk.bold(user.name || user.email)} ${chalk.dim(`<${user.email}>`)}`);
|
|
18637
|
+
out(` ${chalk.dim("plan:")} ${user.plan}`);
|
|
18638
|
+
out(
|
|
18639
|
+
` ${chalk.dim("monthly token limit:")} ${user.monthlyTokenLimit.toLocaleString()}`
|
|
18640
|
+
);
|
|
18641
|
+
out();
|
|
18642
|
+
return EXIT_OK;
|
|
18643
|
+
} catch (error) {
|
|
18644
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18645
|
+
err(chalk.red(` Could not reach the server: ${message}`));
|
|
18646
|
+
return EXIT_FAILURE;
|
|
18647
|
+
}
|
|
18648
|
+
}
|
|
18649
|
+
async function runLogin(ctx) {
|
|
18650
|
+
const verb = ctx.argv[0];
|
|
18651
|
+
if (verb !== "login" && verb !== "logout" && verb !== "whoami") {
|
|
18652
|
+
return void 0;
|
|
18653
|
+
}
|
|
18654
|
+
const args = parseLoginArgs(ctx.argv.slice(1));
|
|
18655
|
+
switch (verb) {
|
|
18656
|
+
case "login":
|
|
18657
|
+
return doLogin(args);
|
|
18658
|
+
case "logout":
|
|
18659
|
+
return doLogout();
|
|
18660
|
+
case "whoami":
|
|
18661
|
+
return doWhoami(args);
|
|
18662
|
+
}
|
|
18663
|
+
}
|
|
18664
|
+
|
|
18665
|
+
// src/launch/oauth.ts
|
|
17904
18666
|
var BUILT_IN_OAUTH = [
|
|
17905
18667
|
{ provider: anthropicOAuthProvider, label: "Anthropic (Claude sign-in)" },
|
|
17906
18668
|
{ provider: openaiCodexOAuthProvider, label: "OpenAI (ChatGPT sign-in)" },
|
|
@@ -17942,6 +18704,11 @@ function oauthClientIdEnvVar(providerId) {
|
|
|
17942
18704
|
return OAUTH_CLIENT_ID_WIRING[providerId]?.envVar;
|
|
17943
18705
|
}
|
|
17944
18706
|
function listLoginProviders() {
|
|
18707
|
+
const serverTier = {
|
|
18708
|
+
id: SERVER_TIER_PROVIDER_ID,
|
|
18709
|
+
label: "Indus Server (sign in for server-tier model access)",
|
|
18710
|
+
authKind: "oauth"
|
|
18711
|
+
};
|
|
17945
18712
|
const oauth = getOAuthProviders().map((provider) => ({
|
|
17946
18713
|
id: provider.id,
|
|
17947
18714
|
label: OAUTH_LABELS[provider.id] ?? provider.name,
|
|
@@ -17952,7 +18719,7 @@ function listLoginProviders() {
|
|
|
17952
18719
|
label: entry.label,
|
|
17953
18720
|
authKind: "apiKey"
|
|
17954
18721
|
}));
|
|
17955
|
-
return [...oauth, ...apiKey];
|
|
18722
|
+
return [serverTier, ...oauth, ...apiKey];
|
|
17956
18723
|
}
|
|
17957
18724
|
function isWebUrl(url) {
|
|
17958
18725
|
try {
|
|
@@ -18008,6 +18775,10 @@ function openLoginUrl(url) {
|
|
|
18008
18775
|
return tryAt(0);
|
|
18009
18776
|
}
|
|
18010
18777
|
async function startOAuthLogin(providerId, callbacks, vault, account = "default") {
|
|
18778
|
+
if (providerId === SERVER_TIER_PROVIDER_ID) {
|
|
18779
|
+
await runServerTierLogin(callbacks);
|
|
18780
|
+
return { provider: providerId, account, madeDefault: true };
|
|
18781
|
+
}
|
|
18011
18782
|
const provider = getOAuthProvider(providerId);
|
|
18012
18783
|
if (provider === void 0) {
|
|
18013
18784
|
throw new Error(`No browser sign-in is available for "${providerId}".`);
|
|
@@ -18031,7 +18802,7 @@ function defaultCredentialIo() {
|
|
|
18031
18802
|
process.stdout.write(line.endsWith("\n") ? line : line + "\n");
|
|
18032
18803
|
},
|
|
18033
18804
|
async ask(prompt) {
|
|
18034
|
-
const rl =
|
|
18805
|
+
const rl = createInterface2({
|
|
18035
18806
|
input: process.stdin,
|
|
18036
18807
|
output: process.stdout
|
|
18037
18808
|
});
|
|
@@ -18042,14 +18813,14 @@ function defaultCredentialIo() {
|
|
|
18042
18813
|
}
|
|
18043
18814
|
},
|
|
18044
18815
|
async askSecret(prompt) {
|
|
18045
|
-
const rl =
|
|
18816
|
+
const rl = createInterface2({
|
|
18046
18817
|
input: process.stdin,
|
|
18047
18818
|
output: process.stdout
|
|
18048
18819
|
});
|
|
18049
|
-
const
|
|
18820
|
+
const out2 = process.stdout;
|
|
18050
18821
|
let muted = false;
|
|
18051
|
-
const original =
|
|
18052
|
-
|
|
18822
|
+
const original = out2.write.bind(out2);
|
|
18823
|
+
out2.write = ((chunk, ...args) => {
|
|
18053
18824
|
if (muted && typeof chunk === "string") return true;
|
|
18054
18825
|
return original(chunk, ...args);
|
|
18055
18826
|
});
|
|
@@ -18060,8 +18831,8 @@ function defaultCredentialIo() {
|
|
|
18060
18831
|
return value.trim();
|
|
18061
18832
|
} finally {
|
|
18062
18833
|
muted = false;
|
|
18063
|
-
|
|
18064
|
-
|
|
18834
|
+
out2.write = original;
|
|
18835
|
+
out2.write("\n");
|
|
18065
18836
|
rl.close();
|
|
18066
18837
|
}
|
|
18067
18838
|
}
|
|
@@ -18225,8 +18996,8 @@ function validateAccountName(name) {
|
|
|
18225
18996
|
}
|
|
18226
18997
|
var DEFAULT_ACCOUNT = "default";
|
|
18227
18998
|
function asVerb(token) {
|
|
18228
|
-
if (token === "signin"
|
|
18229
|
-
if (token === "signout"
|
|
18999
|
+
if (token === "signin") return "signin";
|
|
19000
|
+
if (token === "signout") return "signout";
|
|
18230
19001
|
return void 0;
|
|
18231
19002
|
}
|
|
18232
19003
|
async function runCredentialCommand(argv, opts) {
|
|
@@ -18637,7 +19408,7 @@ function printModelCatalog(io = defaultCatalogIo(), filter = {}, source = regist
|
|
|
18637
19408
|
}
|
|
18638
19409
|
|
|
18639
19410
|
// src/launch/pickers.ts
|
|
18640
|
-
import { createInterface as
|
|
19411
|
+
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
18641
19412
|
import { createElement } from "indusagi/react-host";
|
|
18642
19413
|
import { render } from "indusagi/react-host/ink";
|
|
18643
19414
|
import { StartupSessionPicker } from "indusagi/react-ink";
|
|
@@ -18725,7 +19496,7 @@ function defaultSettingsBrowseIo() {
|
|
|
18725
19496
|
process.stdout.write(line.endsWith("\n") ? line : line + "\n");
|
|
18726
19497
|
},
|
|
18727
19498
|
async pause(prompt) {
|
|
18728
|
-
const rl =
|
|
19499
|
+
const rl = createInterface3({
|
|
18729
19500
|
input: process.stdin,
|
|
18730
19501
|
output: process.stdout
|
|
18731
19502
|
});
|
|
@@ -18739,7 +19510,7 @@ function defaultSettingsBrowseIo() {
|
|
|
18739
19510
|
}
|
|
18740
19511
|
function renderSection(title, paths) {
|
|
18741
19512
|
if (paths.length === 0) return [`${title}: (none)`];
|
|
18742
|
-
return [`${title}:`, ...paths.map((
|
|
19513
|
+
return [`${title}:`, ...paths.map((path4) => ` - ${path4}`)];
|
|
18743
19514
|
}
|
|
18744
19515
|
function renderSettingsListing(opts) {
|
|
18745
19516
|
const lines = [];
|
|
@@ -19058,6 +19829,14 @@ function consoleReducer(state, event) {
|
|
|
19058
19829
|
return setBuffer(state, event.text);
|
|
19059
19830
|
case "buffer:insert":
|
|
19060
19831
|
return insertBuffer(state, event.text);
|
|
19832
|
+
case "buffer:replaceSpan": {
|
|
19833
|
+
const at = state.buffer.indexOf(event.find);
|
|
19834
|
+
if (at < 0) return state;
|
|
19835
|
+
const buffer = state.buffer.slice(0, at) + event.replaceWith + state.buffer.slice(at + event.find.length);
|
|
19836
|
+
const spanEnd = at + event.find.length;
|
|
19837
|
+
const caret = state.caret >= spanEnd ? state.caret + (event.replaceWith.length - event.find.length) : state.caret > at ? at + event.replaceWith.length : state.caret;
|
|
19838
|
+
return { ...state, buffer, caret: clamp(caret, buffer.length) };
|
|
19839
|
+
}
|
|
19061
19840
|
case "buffer:erasePrev":
|
|
19062
19841
|
return erasePrev(state);
|
|
19063
19842
|
case "buffer:eraseNext":
|
|
@@ -19384,7 +20163,8 @@ var DEFAULT_SLASH_REGISTRY = buildRegistry(SLASH_COMMANDS);
|
|
|
19384
20163
|
// src/console/input/keymap.ts
|
|
19385
20164
|
var NO_INTENT = { verb: "none" };
|
|
19386
20165
|
function typed(text) {
|
|
19387
|
-
|
|
20166
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
20167
|
+
return normalized.length === 0 ? NO_INTENT : { verb: "text:type", text: normalized };
|
|
19388
20168
|
}
|
|
19389
20169
|
function isPrintable(input) {
|
|
19390
20170
|
if (input.length === 0) return false;
|
|
@@ -19419,6 +20199,8 @@ function readKey(input, key) {
|
|
|
19419
20199
|
return { verb: "input:externalEditor" };
|
|
19420
20200
|
case "r":
|
|
19421
20201
|
return { verb: "overlay:open", overlay: "sessions" };
|
|
20202
|
+
case "x":
|
|
20203
|
+
return { verb: "queue:steer" };
|
|
19422
20204
|
case "l":
|
|
19423
20205
|
return { verb: "overlay:open", overlay: "models" };
|
|
19424
20206
|
case "o":
|
|
@@ -19461,8 +20243,10 @@ function advanceChord(latch, intent) {
|
|
|
19461
20243
|
}
|
|
19462
20244
|
|
|
19463
20245
|
// src/console/input/paste.ts
|
|
19464
|
-
var PASTE_THRESHOLDS = { lines:
|
|
20246
|
+
var PASTE_THRESHOLDS = { lines: 10, chars: 1001 };
|
|
19465
20247
|
var PASTE_BURST_GAP_MS = 24;
|
|
20248
|
+
var PASTE_CONTINUATION_MS = 250;
|
|
20249
|
+
var PASTE_MARKER_LINE_CAP = 1e3;
|
|
19466
20250
|
function pasteMarker(ordinal, lineCount) {
|
|
19467
20251
|
return `[Pasted text #${ordinal}${lineCount > 0 ? ` +${lineCount} lines` : ""}]`;
|
|
19468
20252
|
}
|
|
@@ -19490,6 +20274,19 @@ function coalescePaste(body, vault = EMPTY_PASTE_VAULT) {
|
|
|
19490
20274
|
bodies.set(ordinal, body);
|
|
19491
20275
|
return { marker, vault: { bodies, minted: ordinal } };
|
|
19492
20276
|
}
|
|
20277
|
+
function appendToPaste(ordinal, extra, vault) {
|
|
20278
|
+
const body = (vault.bodies.get(ordinal) ?? "") + extra;
|
|
20279
|
+
const lineCount = body.length === 0 ? 0 : lineBreaks(body) + 1;
|
|
20280
|
+
const marker = pasteMarker(ordinal, lineCount);
|
|
20281
|
+
const bodies = new Map(vault.bodies);
|
|
20282
|
+
bodies.set(ordinal, body);
|
|
20283
|
+
return { marker, vault: { bodies, minted: vault.minted } };
|
|
20284
|
+
}
|
|
20285
|
+
function pasteLines(vault, ordinal) {
|
|
20286
|
+
const body = vault.bodies.get(ordinal);
|
|
20287
|
+
if (body === void 0 || body.length === 0) return 0;
|
|
20288
|
+
return lineBreaks(body) + 1;
|
|
20289
|
+
}
|
|
19493
20290
|
function expandMarkers(buffer, vault) {
|
|
19494
20291
|
if (vault.bodies.size === 0) return buffer;
|
|
19495
20292
|
return buffer.replace(markerScanner(), (_match, ordinalStr) => {
|
|
@@ -19611,10 +20408,11 @@ function createDirReader(cwd = process.cwd()) {
|
|
|
19611
20408
|
|
|
19612
20409
|
// src/console/components/TerminalConsole.tsx
|
|
19613
20410
|
init_workflow_engine();
|
|
20411
|
+
init_window_budget();
|
|
19614
20412
|
import { execFileSync } from "node:child_process";
|
|
19615
|
-
import { homedir as
|
|
19616
|
-
import React3, { useEffect as
|
|
19617
|
-
import { Box as Box10, useInput as useInput3 } from "indusagi/react-host/ink";
|
|
20413
|
+
import { homedir as homedir6 } from "node:os";
|
|
20414
|
+
import React3, { useEffect as useEffect7, useMemo as useMemo2, useState as useState8 } from "indusagi/react-host";
|
|
20415
|
+
import { Box as Box10, Text as Text10, useInput as useInput3 } from "indusagi/react-host/ink";
|
|
19618
20416
|
import {
|
|
19619
20417
|
MessageList,
|
|
19620
20418
|
StreamingMarkdown,
|
|
@@ -19622,7 +20420,7 @@ import {
|
|
|
19622
20420
|
} from "indusagi/react-ink";
|
|
19623
20421
|
|
|
19624
20422
|
// src/console/components/Banner.tsx
|
|
19625
|
-
import { homedir as
|
|
20423
|
+
import { homedir as homedir4 } from "node:os";
|
|
19626
20424
|
import { basename as basename4 } from "node:path";
|
|
19627
20425
|
import { Box, Text } from "indusagi/react-host/ink";
|
|
19628
20426
|
import { ChangelogBlock } from "indusagi/react-ink";
|
|
@@ -19665,9 +20463,9 @@ var TIPS = [
|
|
|
19665
20463
|
"Use /skills to discover specialized helpers for the task at hand"
|
|
19666
20464
|
];
|
|
19667
20465
|
var WHATS_NEW = [
|
|
19668
|
-
"
|
|
19669
|
-
"
|
|
19670
|
-
"
|
|
20466
|
+
"Ctrl+X runs your newest queued message NOW \u2014 the current run stops cleanly",
|
|
20467
|
+
"/compact shows live progress, resets to a fresh screen, and lists carried files",
|
|
20468
|
+
'"Allow always" is remembered for the session; sub-agents respect your permission mode'
|
|
19671
20469
|
];
|
|
19672
20470
|
function wrapIndex(seed, len) {
|
|
19673
20471
|
if (len <= 0) return 0;
|
|
@@ -19799,7 +20597,7 @@ function Mascot({
|
|
|
19799
20597
|
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)) });
|
|
19800
20598
|
}
|
|
19801
20599
|
function shortenWorkspace(workspace) {
|
|
19802
|
-
const home =
|
|
20600
|
+
const home = homedir4();
|
|
19803
20601
|
if (home.length > 0 && workspace.startsWith(home)) {
|
|
19804
20602
|
return `~${workspace.slice(home.length)}`;
|
|
19805
20603
|
}
|
|
@@ -19939,6 +20737,43 @@ function Banner({
|
|
|
19939
20737
|
] });
|
|
19940
20738
|
}
|
|
19941
20739
|
|
|
20740
|
+
// src/console/auth-status.ts
|
|
20741
|
+
init_server_token();
|
|
20742
|
+
init_server_mode();
|
|
20743
|
+
import { useEffect, useState } from "indusagi/react-host";
|
|
20744
|
+
function useAuthenticatedProviders(services, refreshKey) {
|
|
20745
|
+
const [authed, setAuthed] = useState(null);
|
|
20746
|
+
useEffect(() => {
|
|
20747
|
+
if (!services) return;
|
|
20748
|
+
let live = true;
|
|
20749
|
+
void (async () => {
|
|
20750
|
+
const found = /* @__PURE__ */ new Set();
|
|
20751
|
+
try {
|
|
20752
|
+
for (const provider of services.listLoginProviders()) {
|
|
20753
|
+
try {
|
|
20754
|
+
if ((await services.vault.listAccounts(provider.id)).length > 0) {
|
|
20755
|
+
found.add(provider.id);
|
|
20756
|
+
}
|
|
20757
|
+
} catch {
|
|
20758
|
+
}
|
|
20759
|
+
}
|
|
20760
|
+
} catch {
|
|
20761
|
+
}
|
|
20762
|
+
try {
|
|
20763
|
+
if (await hasValidServerToken()) {
|
|
20764
|
+
for (const provider of serverTierProviders()) found.add(provider);
|
|
20765
|
+
}
|
|
20766
|
+
} catch {
|
|
20767
|
+
}
|
|
20768
|
+
if (live) setAuthed(found);
|
|
20769
|
+
})();
|
|
20770
|
+
return () => {
|
|
20771
|
+
live = false;
|
|
20772
|
+
};
|
|
20773
|
+
}, [refreshKey]);
|
|
20774
|
+
return authed;
|
|
20775
|
+
}
|
|
20776
|
+
|
|
19942
20777
|
// src/console/components/BackgroundAgents.tsx
|
|
19943
20778
|
import { Box as Box2, Text as Text2 } from "indusagi/react-host/ink";
|
|
19944
20779
|
import { splitAssistantMessage } from "indusagi/react-ink";
|
|
@@ -20033,7 +20868,7 @@ function BackgroundAgents({ theme, runs, tokens, now }) {
|
|
|
20033
20868
|
}
|
|
20034
20869
|
|
|
20035
20870
|
// src/console/components/AgentsView.tsx
|
|
20036
|
-
import { useState } from "indusagi/react-host";
|
|
20871
|
+
import { useState as useState2 } from "indusagi/react-host";
|
|
20037
20872
|
import { Box as Box3, Text as Text3, useInput } from "indusagi/react-host/ink";
|
|
20038
20873
|
import { wrapSelectionIndex } from "indusagi/react-ink";
|
|
20039
20874
|
import { jsx as jsx3, jsxs as jsxs3 } from "indusagi/react-host/jsx-runtime";
|
|
@@ -20077,7 +20912,7 @@ function ActivityRow({
|
|
|
20077
20912
|
}
|
|
20078
20913
|
function AgentsView({ theme, runs, activity, tokens, now, onExit }) {
|
|
20079
20914
|
const clock = now ?? Date.now();
|
|
20080
|
-
const [selectedIndex, setSelectedIndex] =
|
|
20915
|
+
const [selectedIndex, setSelectedIndex] = useState2(runs.length > 0 ? 1 : 0);
|
|
20081
20916
|
const rowCount = runs.length + 1;
|
|
20082
20917
|
const index = Math.min(selectedIndex, rowCount - 1);
|
|
20083
20918
|
const viewed = index > 0 ? runs[index - 1] : void 0;
|
|
@@ -20248,7 +21083,7 @@ function StatusBar({
|
|
|
20248
21083
|
}
|
|
20249
21084
|
|
|
20250
21085
|
// src/console/components/WorkingIndicator.tsx
|
|
20251
|
-
import React, { useEffect, useState as
|
|
21086
|
+
import React, { useEffect as useEffect2, useState as useState3 } from "indusagi/react-host";
|
|
20252
21087
|
import { Box as Box6, Text as Text6 } from "indusagi/react-host/ink";
|
|
20253
21088
|
import { jsx as jsx6, jsxs as jsxs6 } from "indusagi/react-host/jsx-runtime";
|
|
20254
21089
|
var { useRef } = React;
|
|
@@ -20306,10 +21141,10 @@ function WorkingIndicator({
|
|
|
20306
21141
|
busy,
|
|
20307
21142
|
phase
|
|
20308
21143
|
}) {
|
|
20309
|
-
const [frame, setFrame] =
|
|
21144
|
+
const [frame, setFrame] = useState3(0);
|
|
20310
21145
|
const startRef = useRef(null);
|
|
20311
21146
|
const wordOffsetRef = useRef(0);
|
|
20312
|
-
|
|
21147
|
+
useEffect2(() => {
|
|
20313
21148
|
if (!busy) {
|
|
20314
21149
|
startRef.current = null;
|
|
20315
21150
|
return;
|
|
@@ -20344,7 +21179,7 @@ var APPROVAL_CHOICES = [
|
|
|
20344
21179
|
{
|
|
20345
21180
|
id: "allow-always",
|
|
20346
21181
|
label: "Allow always",
|
|
20347
|
-
description: "run it and remember
|
|
21182
|
+
description: "run it and remember this action for the session"
|
|
20348
21183
|
},
|
|
20349
21184
|
{ id: "deny", label: "Deny", description: "block this call" }
|
|
20350
21185
|
];
|
|
@@ -20446,7 +21281,8 @@ function ApprovalOverlays(props) {
|
|
|
20446
21281
|
}
|
|
20447
21282
|
|
|
20448
21283
|
// src/console/overlays/auth.tsx
|
|
20449
|
-
|
|
21284
|
+
init_server_token();
|
|
21285
|
+
import React2, { useEffect as useEffect3, useState as useState4 } from "indusagi/react-host";
|
|
20450
21286
|
import { Box as Box8, Text as Text8 } from "indusagi/react-host/ink";
|
|
20451
21287
|
import {
|
|
20452
21288
|
DialogFrame,
|
|
@@ -20469,7 +21305,7 @@ function SignInDialog(props) {
|
|
|
20469
21305
|
}
|
|
20470
21306
|
})();
|
|
20471
21307
|
const direct = requestedProvider !== void 0 ? providers.find((p) => p.id === requestedProvider) : void 0;
|
|
20472
|
-
|
|
21308
|
+
useEffect3(() => {
|
|
20473
21309
|
if (direct === void 0) return;
|
|
20474
21310
|
dispatch2({
|
|
20475
21311
|
type: "modal:open",
|
|
@@ -20500,13 +21336,25 @@ function SignInDialog(props) {
|
|
|
20500
21336
|
}
|
|
20501
21337
|
);
|
|
20502
21338
|
}
|
|
21339
|
+
var SERVER_TIER_ACCOUNT_ID = "server-session";
|
|
20503
21340
|
function SignOutDialog(props) {
|
|
20504
21341
|
const { services, closeModal } = props;
|
|
20505
|
-
const [accounts, setAccounts] =
|
|
20506
|
-
|
|
21342
|
+
const [accounts, setAccounts] = useState4([]);
|
|
21343
|
+
useEffect3(() => {
|
|
20507
21344
|
let live = true;
|
|
20508
21345
|
void (async () => {
|
|
20509
21346
|
const rows = [];
|
|
21347
|
+
try {
|
|
21348
|
+
const token = await getServerToken();
|
|
21349
|
+
if (token) {
|
|
21350
|
+
rows.push({
|
|
21351
|
+
provider: SERVER_TIER_PROVIDER_ID,
|
|
21352
|
+
accountId: SERVER_TIER_ACCOUNT_ID,
|
|
21353
|
+
label: "Indus Server \xB7 signed in"
|
|
21354
|
+
});
|
|
21355
|
+
}
|
|
21356
|
+
} catch {
|
|
21357
|
+
}
|
|
20510
21358
|
try {
|
|
20511
21359
|
for (const provider of services.listLoginProviders()) {
|
|
20512
21360
|
let names = [];
|
|
@@ -20539,7 +21387,11 @@ function SignOutDialog(props) {
|
|
|
20539
21387
|
onClose: closeModal,
|
|
20540
21388
|
onSelect: async (account) => {
|
|
20541
21389
|
try {
|
|
20542
|
-
|
|
21390
|
+
if (account.provider === SERVER_TIER_PROVIDER_ID) {
|
|
21391
|
+
await clearServerToken();
|
|
21392
|
+
} else {
|
|
21393
|
+
await services.vault.remove(account.provider, account.accountId);
|
|
21394
|
+
}
|
|
20543
21395
|
} catch {
|
|
20544
21396
|
}
|
|
20545
21397
|
closeModal();
|
|
@@ -20577,12 +21429,12 @@ function OAuthFlowDialog(props) {
|
|
|
20577
21429
|
return providerId;
|
|
20578
21430
|
}
|
|
20579
21431
|
})();
|
|
20580
|
-
const [state, setState] =
|
|
21432
|
+
const [state, setState] = useState4(
|
|
20581
21433
|
() => seedOAuthState(providerId, providerName, mode)
|
|
20582
21434
|
);
|
|
20583
21435
|
const pending = useRef2(null);
|
|
20584
21436
|
const merge = (next) => setState((prev) => ({ ...prev, ...next }));
|
|
20585
|
-
|
|
21437
|
+
useEffect3(() => {
|
|
20586
21438
|
if (mode !== "oauth") return;
|
|
20587
21439
|
let live = true;
|
|
20588
21440
|
const safeMerge = (next) => {
|
|
@@ -20620,6 +21472,7 @@ function OAuthFlowDialog(props) {
|
|
|
20620
21472
|
void (async () => {
|
|
20621
21473
|
try {
|
|
20622
21474
|
await services.startOAuthLogin(providerId, callbacks, services.vault);
|
|
21475
|
+
await services.refreshGatewayRouting();
|
|
20623
21476
|
selectProviderModel(services, providerId);
|
|
20624
21477
|
if (live) {
|
|
20625
21478
|
dispatch2({
|
|
@@ -20763,21 +21616,47 @@ function readEntryMode(payload) {
|
|
|
20763
21616
|
}
|
|
20764
21617
|
|
|
20765
21618
|
// src/console/overlays/pickers.tsx
|
|
20766
|
-
import { useEffect as
|
|
21619
|
+
import { useEffect as useEffect5, useState as useState6 } from "indusagi/react-host";
|
|
20767
21620
|
import {
|
|
20768
21621
|
ScopedModelsDialog,
|
|
20769
21622
|
ThemeDialog as ThemeDialog2
|
|
20770
21623
|
} from "indusagi/react-ink";
|
|
20771
21624
|
|
|
20772
21625
|
// src/console/overlays/boards.tsx
|
|
20773
|
-
|
|
20774
|
-
import
|
|
21626
|
+
init_server_mode();
|
|
21627
|
+
import chalk2 from "chalk";
|
|
21628
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
21629
|
+
import { homedir as homedir5 } from "node:os";
|
|
21630
|
+
import { join as join12 } from "node:path";
|
|
21631
|
+
import { useEffect as useEffect4, useMemo, useState as useState5 } from "indusagi/react-host";
|
|
20775
21632
|
import { Box as Box9, Text as Text9, useInput as useInput2 } from "indusagi/react-host/ink";
|
|
20776
21633
|
import {
|
|
20777
21634
|
matchesSearchQuery,
|
|
20778
21635
|
wrapSelectionIndex as wrapSelectionIndex2
|
|
20779
21636
|
} from "indusagi/react-ink";
|
|
20780
21637
|
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "indusagi/react-host/jsx-runtime";
|
|
21638
|
+
function readServerTierInfo() {
|
|
21639
|
+
let signedIn = false;
|
|
21640
|
+
try {
|
|
21641
|
+
const file = join12(homedir5(), ".indusagi", "agent", "server-token.json");
|
|
21642
|
+
const token = JSON.parse(readFileSync7(file, "utf8"));
|
|
21643
|
+
signedIn = typeof token.expires_at === "string" && new Date(token.expires_at).getTime() - Date.now() > 5 * 60 * 1e3;
|
|
21644
|
+
} catch {
|
|
21645
|
+
signedIn = false;
|
|
21646
|
+
}
|
|
21647
|
+
const localKeys = /* @__PURE__ */ new Set();
|
|
21648
|
+
try {
|
|
21649
|
+
const file = join12(homedir5(), ".indusagi", "agent", "auth.json");
|
|
21650
|
+
const vault = JSON.parse(readFileSync7(file, "utf8"));
|
|
21651
|
+
for (const [provider, entry] of Object.entries(vault)) {
|
|
21652
|
+
if (entry !== null && typeof entry === "object" && Object.keys(entry).length > 0) {
|
|
21653
|
+
localKeys.add(provider);
|
|
21654
|
+
}
|
|
21655
|
+
}
|
|
21656
|
+
} catch {
|
|
21657
|
+
}
|
|
21658
|
+
return { signedIn, localKeys };
|
|
21659
|
+
}
|
|
20781
21660
|
function truncate(text, width) {
|
|
20782
21661
|
if (text.length <= width) return text;
|
|
20783
21662
|
if (width <= 1) return text.slice(0, width);
|
|
@@ -20786,7 +21665,7 @@ function truncate(text, width) {
|
|
|
20786
21665
|
function tabPill(theme, text) {
|
|
20787
21666
|
const accent = theme.colors["accent"] ?? "#f7a23f";
|
|
20788
21667
|
try {
|
|
20789
|
-
return
|
|
21668
|
+
return chalk2.bgHex(accent).hex("#1a120a").bold(` ${text} `);
|
|
20790
21669
|
} catch {
|
|
20791
21670
|
return theme.color("accent", text);
|
|
20792
21671
|
}
|
|
@@ -20895,16 +21774,16 @@ function nextValue(values, current, direction) {
|
|
|
20895
21774
|
return values[(at + direction + values.length) % values.length];
|
|
20896
21775
|
}
|
|
20897
21776
|
function SettingsBoard({ theme, items, onClose }) {
|
|
20898
|
-
const [query, setQuery] =
|
|
20899
|
-
const [selectedIndex, setSelectedIndex] =
|
|
21777
|
+
const [query, setQuery] = useState5("");
|
|
21778
|
+
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
20900
21779
|
const filtered = useMemo(
|
|
20901
21780
|
() => items.filter(
|
|
20902
21781
|
(item) => matchesSearchQuery(`${item.label} ${item.description} ${item.value} ${item.values.join(" ")}`, query)
|
|
20903
21782
|
),
|
|
20904
21783
|
[items, query]
|
|
20905
21784
|
);
|
|
20906
|
-
|
|
20907
|
-
|
|
21785
|
+
useEffect4(() => setSelectedIndex(0), [query]);
|
|
21786
|
+
useEffect4(() => {
|
|
20908
21787
|
if (selectedIndex >= filtered.length) setSelectedIndex(0);
|
|
20909
21788
|
}, [filtered.length, selectedIndex]);
|
|
20910
21789
|
const cycle = (direction) => {
|
|
@@ -20954,12 +21833,20 @@ function modelMatches(model, query) {
|
|
|
20954
21833
|
return matchesSearchQuery(`${model.provider} ${model.id} ${model.name ?? ""}`, query);
|
|
20955
21834
|
}
|
|
20956
21835
|
function ModelBoard({ theme, models, onClose, onSelect, search }) {
|
|
20957
|
-
const [query, setQuery] =
|
|
20958
|
-
const [selectedIndex, setSelectedIndex] =
|
|
20959
|
-
|
|
20960
|
-
const
|
|
20961
|
-
|
|
20962
|
-
|
|
21836
|
+
const [query, setQuery] = useState5(search ?? "");
|
|
21837
|
+
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
21838
|
+
useEffect4(() => setQuery(search ?? ""), [search]);
|
|
21839
|
+
const serverTier = useMemo(readServerTierInfo, []);
|
|
21840
|
+
const isServerTier = (provider) => serverTier.signedIn && isGatewayEligibleProvider(provider) && !serverTier.localKeys.has(provider);
|
|
21841
|
+
const available = useMemo(
|
|
21842
|
+
() => models.filter(
|
|
21843
|
+
(model) => serverTier.localKeys.has(model.provider) || isServerTier(model.provider)
|
|
21844
|
+
),
|
|
21845
|
+
[models, serverTier]
|
|
21846
|
+
);
|
|
21847
|
+
const filtered = useMemo(() => available.filter((model) => modelMatches(model, query)), [available, query]);
|
|
21848
|
+
useEffect4(() => setSelectedIndex(0), [query]);
|
|
21849
|
+
useEffect4(() => {
|
|
20963
21850
|
if (selectedIndex >= filtered.length) setSelectedIndex(0);
|
|
20964
21851
|
}, [filtered.length, selectedIndex]);
|
|
20965
21852
|
useInput2((input, key) => {
|
|
@@ -20977,13 +21864,16 @@ function ModelBoard({ theme, models, onClose, onSelect, search }) {
|
|
|
20977
21864
|
});
|
|
20978
21865
|
const { start, budget, below } = windowAround(filtered.length, selectedIndex);
|
|
20979
21866
|
const visible = filtered.slice(start, start + budget);
|
|
20980
|
-
const list = filtered.length === 0 ? /* @__PURE__ */ jsx9(Text9, { children: theme.muted(
|
|
21867
|
+
const list = filtered.length === 0 ? /* @__PURE__ */ jsx9(Text9, { children: theme.muted(
|
|
21868
|
+
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."
|
|
21869
|
+
) }) : /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: visible.map((model, index) => {
|
|
20981
21870
|
const isSelected = start + index === selectedIndex;
|
|
20982
21871
|
return /* @__PURE__ */ jsxs8(Box9, { children: [
|
|
20983
21872
|
/* @__PURE__ */ jsx9(Box9, { width: 2, children: /* @__PURE__ */ jsx9(Text9, { children: isSelected ? theme.color("accent", "\u203A") : " " }) }),
|
|
20984
|
-
/* @__PURE__ */ jsx9(Text9, { bold: isSelected, children: theme.color("text",
|
|
20985
|
-
model.name ? /* @__PURE__ */ jsx9(Text9, { children: theme.dim(` ${model.name}`) }) : null
|
|
20986
|
-
|
|
21873
|
+
/* @__PURE__ */ jsx9(Text9, { bold: isSelected, children: theme.color("text", model.id) }),
|
|
21874
|
+
model.name ? /* @__PURE__ */ jsx9(Text9, { children: theme.dim(` ${model.name}`) }) : null,
|
|
21875
|
+
isServerTier(model.provider) ? /* @__PURE__ */ jsx9(Text9, { children: theme.color("accent", " \u2B21 server") }) : null
|
|
21876
|
+
] }, model.id);
|
|
20987
21877
|
}) });
|
|
20988
21878
|
return /* @__PURE__ */ jsx9(
|
|
20989
21879
|
BoardShell,
|
|
@@ -21070,13 +21960,13 @@ var SETTING_KEYS = Object.freeze(
|
|
|
21070
21960
|
);
|
|
21071
21961
|
|
|
21072
21962
|
// src/settings/manager.ts
|
|
21073
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as
|
|
21074
|
-
import { dirname as dirname5, join as
|
|
21963
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
21964
|
+
import { dirname as dirname5, join as join13 } from "node:path";
|
|
21075
21965
|
function loadTier(filePath) {
|
|
21076
21966
|
if (!existsSync3(filePath)) return {};
|
|
21077
21967
|
let raw;
|
|
21078
21968
|
try {
|
|
21079
|
-
raw =
|
|
21969
|
+
raw = readFileSync8(filePath, "utf-8");
|
|
21080
21970
|
} catch {
|
|
21081
21971
|
return {};
|
|
21082
21972
|
}
|
|
@@ -21127,7 +22017,7 @@ var PreferenceStore = class _PreferenceStore {
|
|
|
21127
22017
|
static fromWorkspace(workspace, cwd = process.cwd()) {
|
|
21128
22018
|
return new _PreferenceStore({
|
|
21129
22019
|
global: workspace.settingsPath,
|
|
21130
|
-
project:
|
|
22020
|
+
project: join13(cwd, BRAND.profileDirName, "settings.json")
|
|
21131
22021
|
});
|
|
21132
22022
|
}
|
|
21133
22023
|
/** The two resolved file locations this store reads and writes. */
|
|
@@ -21196,11 +22086,11 @@ var PreferenceStore = class _PreferenceStore {
|
|
|
21196
22086
|
}
|
|
21197
22087
|
};
|
|
21198
22088
|
function stripUndefined(tier) {
|
|
21199
|
-
const
|
|
22089
|
+
const out2 = {};
|
|
21200
22090
|
for (const [key, value] of Object.entries(tier)) {
|
|
21201
|
-
if (value !== void 0)
|
|
22091
|
+
if (value !== void 0) out2[key] = value;
|
|
21202
22092
|
}
|
|
21203
|
-
return
|
|
22093
|
+
return out2;
|
|
21204
22094
|
}
|
|
21205
22095
|
|
|
21206
22096
|
// src/console/overlays/pickers.tsx
|
|
@@ -21243,38 +22133,12 @@ function listModels(services) {
|
|
|
21243
22133
|
return [];
|
|
21244
22134
|
}
|
|
21245
22135
|
}
|
|
21246
|
-
function useAuthenticatedProviders(services) {
|
|
21247
|
-
const [authed, setAuthed] = useState5(null);
|
|
21248
|
-
useEffect4(() => {
|
|
21249
|
-
if (!services) return;
|
|
21250
|
-
let live = true;
|
|
21251
|
-
void (async () => {
|
|
21252
|
-
const found = /* @__PURE__ */ new Set();
|
|
21253
|
-
try {
|
|
21254
|
-
for (const provider of services.listLoginProviders()) {
|
|
21255
|
-
try {
|
|
21256
|
-
if ((await services.vault.listAccounts(provider.id)).length > 0) {
|
|
21257
|
-
found.add(provider.id);
|
|
21258
|
-
}
|
|
21259
|
-
} catch {
|
|
21260
|
-
}
|
|
21261
|
-
}
|
|
21262
|
-
} catch {
|
|
21263
|
-
}
|
|
21264
|
-
if (live) setAuthed(found);
|
|
21265
|
-
})();
|
|
21266
|
-
return () => {
|
|
21267
|
-
live = false;
|
|
21268
|
-
};
|
|
21269
|
-
}, []);
|
|
21270
|
-
return authed;
|
|
21271
|
-
}
|
|
21272
22136
|
function ModelPicker(props) {
|
|
21273
22137
|
const { services, theme, closeModal } = props;
|
|
21274
22138
|
const authed = useAuthenticatedProviders(services);
|
|
21275
22139
|
if (!services) return null;
|
|
21276
22140
|
const all = listModels(services);
|
|
21277
|
-
const models = authed
|
|
22141
|
+
const models = authed === null ? all : all.filter((model) => authed.has(model.provider));
|
|
21278
22142
|
return /* @__PURE__ */ jsx10(
|
|
21279
22143
|
ModelBoard,
|
|
21280
22144
|
{
|
|
@@ -21294,15 +22158,15 @@ function ModelPicker(props) {
|
|
|
21294
22158
|
function readScopedPayload(payload) {
|
|
21295
22159
|
if (payload === null || typeof payload !== "object") return {};
|
|
21296
22160
|
const record = payload;
|
|
21297
|
-
const
|
|
21298
|
-
if (record.focus === "summary")
|
|
21299
|
-
if (record.intent === "reset")
|
|
21300
|
-
return
|
|
22161
|
+
const out2 = {};
|
|
22162
|
+
if (record.focus === "summary") out2.focus = "summary";
|
|
22163
|
+
if (record.intent === "reset") out2.intent = "reset";
|
|
22164
|
+
return out2;
|
|
21301
22165
|
}
|
|
21302
22166
|
function ScopedModelPicker(props) {
|
|
21303
22167
|
const { services, dispatch: dispatch2, closeModal, modal } = props;
|
|
21304
22168
|
const payload = readScopedPayload(modal.payload);
|
|
21305
|
-
|
|
22169
|
+
useEffect5(() => {
|
|
21306
22170
|
if (!services || payload.intent !== "reset") return;
|
|
21307
22171
|
try {
|
|
21308
22172
|
services.settings.set("enabledModels", []);
|
|
@@ -21358,7 +22222,7 @@ function currentScheme(services) {
|
|
|
21358
22222
|
}
|
|
21359
22223
|
function ThemePicker(props) {
|
|
21360
22224
|
const { services, dispatch: dispatch2, closeModal } = props;
|
|
21361
|
-
const [originalScheme] =
|
|
22225
|
+
const [originalScheme] = useState6(
|
|
21362
22226
|
() => services ? currentScheme(services) : null
|
|
21363
22227
|
);
|
|
21364
22228
|
if (!services) return null;
|
|
@@ -21389,7 +22253,7 @@ function SettingsPicker(props) {
|
|
|
21389
22253
|
const { services, theme, dispatch: dispatch2, closeModal } = props;
|
|
21390
22254
|
if (!services) return null;
|
|
21391
22255
|
const settings = services.settings;
|
|
21392
|
-
const [, setVersion] =
|
|
22256
|
+
const [, setVersion] = useState6(0);
|
|
21393
22257
|
const bump = () => setVersion((n) => n + 1);
|
|
21394
22258
|
const onOff = (flag) => flag ? "on" : "off";
|
|
21395
22259
|
const toggleRow = (id, key, label2, description, live) => ({
|
|
@@ -21571,7 +22435,7 @@ function PickerOverlays(props) {
|
|
|
21571
22435
|
}
|
|
21572
22436
|
|
|
21573
22437
|
// src/console/overlays/sessions.tsx
|
|
21574
|
-
import { useEffect as
|
|
22438
|
+
import { useEffect as useEffect6, useState as useState7 } from "indusagi/react-host";
|
|
21575
22439
|
import {
|
|
21576
22440
|
SessionDialog,
|
|
21577
22441
|
TreeDialog,
|
|
@@ -21593,8 +22457,8 @@ function toSessionInfo(row) {
|
|
|
21593
22457
|
}
|
|
21594
22458
|
function SessionPicker(props) {
|
|
21595
22459
|
const { services, closeModal } = props;
|
|
21596
|
-
const [sessions, setSessions] =
|
|
21597
|
-
|
|
22460
|
+
const [sessions, setSessions] = useState7([]);
|
|
22461
|
+
useEffect6(() => {
|
|
21598
22462
|
let live = true;
|
|
21599
22463
|
void (async () => {
|
|
21600
22464
|
try {
|
|
@@ -21654,8 +22518,8 @@ function SessionPicker(props) {
|
|
|
21654
22518
|
}
|
|
21655
22519
|
function BranchTree(props) {
|
|
21656
22520
|
const { services, closeModal } = props;
|
|
21657
|
-
const [items, setItems] =
|
|
21658
|
-
|
|
22521
|
+
const [items, setItems] = useState7([]);
|
|
22522
|
+
useEffect6(() => {
|
|
21659
22523
|
let live = true;
|
|
21660
22524
|
void (async () => {
|
|
21661
22525
|
try {
|
|
@@ -21706,8 +22570,8 @@ function BranchTree(props) {
|
|
|
21706
22570
|
}
|
|
21707
22571
|
function PriorTurns(props) {
|
|
21708
22572
|
const { services, closeModal } = props;
|
|
21709
|
-
const [items, setItems] =
|
|
21710
|
-
|
|
22573
|
+
const [items, setItems] = useState7([]);
|
|
22574
|
+
useEffect6(() => {
|
|
21711
22575
|
let live = true;
|
|
21712
22576
|
void (async () => {
|
|
21713
22577
|
try {
|
|
@@ -21805,34 +22669,40 @@ function approvalQueueReducer(state, event) {
|
|
|
21805
22669
|
function activeApproval(state) {
|
|
21806
22670
|
return state.entries[0];
|
|
21807
22671
|
}
|
|
22672
|
+
function modeReleasesApprovals(mode) {
|
|
22673
|
+
return mode === "bypass" || mode === "bypassPermissions";
|
|
22674
|
+
}
|
|
22675
|
+
|
|
22676
|
+
// src/console/components/TerminalConsole.tsx
|
|
22677
|
+
init_conductor2();
|
|
21808
22678
|
|
|
21809
22679
|
// src/console/startup.ts
|
|
21810
22680
|
init_briefing();
|
|
21811
|
-
import { existsSync as existsSync4, readFileSync as
|
|
21812
|
-
import { join as
|
|
22681
|
+
import { existsSync as existsSync4, readFileSync as readFileSync9 } from "node:fs";
|
|
22682
|
+
import { join as join14 } from "node:path";
|
|
21813
22683
|
var PROFILE_DIR = ".indusagi";
|
|
21814
22684
|
var CONTEXT_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
21815
22685
|
function skillRoots(cwd, home) {
|
|
21816
22686
|
return [
|
|
21817
|
-
{ dir:
|
|
21818
|
-
{ dir:
|
|
22687
|
+
{ dir: join14(cwd, PROFILE_DIR, "skills"), origin: "project" },
|
|
22688
|
+
{ dir: join14(home, PROFILE_DIR, "skills"), origin: "user" }
|
|
21819
22689
|
];
|
|
21820
22690
|
}
|
|
21821
22691
|
function macroRoots(cwd, home) {
|
|
21822
22692
|
return [
|
|
21823
|
-
{ dir:
|
|
21824
|
-
{ dir:
|
|
22693
|
+
{ dir: join14(cwd, PROFILE_DIR, "commands"), origin: "project", label: "project" },
|
|
22694
|
+
{ dir: join14(home, PROFILE_DIR, "commands"), origin: "user", label: "user" }
|
|
21825
22695
|
];
|
|
21826
22696
|
}
|
|
21827
|
-
function shortenPath2(
|
|
21828
|
-
if (cwd.length > 0 &&
|
|
21829
|
-
const rest =
|
|
22697
|
+
function shortenPath2(path4, cwd, home) {
|
|
22698
|
+
if (cwd.length > 0 && path4.startsWith(cwd)) {
|
|
22699
|
+
const rest = path4.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
21830
22700
|
return rest.length > 0 ? `./${rest}` : ".";
|
|
21831
22701
|
}
|
|
21832
|
-
if (home.length > 0 &&
|
|
21833
|
-
return `~${
|
|
22702
|
+
if (home.length > 0 && path4.startsWith(home)) {
|
|
22703
|
+
return `~${path4.slice(home.length)}`;
|
|
21834
22704
|
}
|
|
21835
|
-
return
|
|
22705
|
+
return path4;
|
|
21836
22706
|
}
|
|
21837
22707
|
var MAX_SECTION_LINES = 6;
|
|
21838
22708
|
function capLines(lines) {
|
|
@@ -21847,17 +22717,17 @@ function section(title, lines) {
|
|
|
21847
22717
|
}
|
|
21848
22718
|
function gatherContext(cwd, home) {
|
|
21849
22719
|
const seen = /* @__PURE__ */ new Set();
|
|
21850
|
-
const
|
|
22720
|
+
const out2 = [];
|
|
21851
22721
|
for (const root of [cwd, home]) {
|
|
21852
22722
|
if (root.length === 0) continue;
|
|
21853
22723
|
for (const name of CONTEXT_FILES) {
|
|
21854
|
-
const
|
|
21855
|
-
if (seen.has(
|
|
21856
|
-
seen.add(
|
|
21857
|
-
if (existsSync4(
|
|
22724
|
+
const path4 = join14(root, name);
|
|
22725
|
+
if (seen.has(path4)) continue;
|
|
22726
|
+
seen.add(path4);
|
|
22727
|
+
if (existsSync4(path4)) out2.push(shortenPath2(path4, cwd, home));
|
|
21858
22728
|
}
|
|
21859
22729
|
}
|
|
21860
|
-
return
|
|
22730
|
+
return out2;
|
|
21861
22731
|
}
|
|
21862
22732
|
function gatherSkills(cwd, home) {
|
|
21863
22733
|
let cards = [];
|
|
@@ -21933,7 +22803,7 @@ function gatherChangelog(inputs) {
|
|
|
21933
22803
|
if (lastSeenVersion !== void 0 && lastSeenVersion === version) return none2;
|
|
21934
22804
|
let raw;
|
|
21935
22805
|
try {
|
|
21936
|
-
raw =
|
|
22806
|
+
raw = readFileSync9(changelogPath, "utf-8");
|
|
21937
22807
|
} catch {
|
|
21938
22808
|
return none2;
|
|
21939
22809
|
}
|
|
@@ -21969,11 +22839,11 @@ __export(kit_exports, {
|
|
|
21969
22839
|
});
|
|
21970
22840
|
|
|
21971
22841
|
// src/kit/tool-fetch.ts
|
|
21972
|
-
import { join as
|
|
22842
|
+
import { join as join15 } from "node:path";
|
|
21973
22843
|
var KIT_USER_AGENT = "indusagi-kit-provisioner/1.0";
|
|
21974
22844
|
function resolveManagedBinaryPath(binDir, bin, platform = process.platform) {
|
|
21975
22845
|
const fileName = platform === "win32" ? `${bin}.exe` : bin;
|
|
21976
|
-
return
|
|
22846
|
+
return join15(binDir, fileName);
|
|
21977
22847
|
}
|
|
21978
22848
|
function pickReleaseAsset(descriptor, release) {
|
|
21979
22849
|
for (const asset of release.assets) {
|
|
@@ -22055,9 +22925,9 @@ function buildShellCommand(args) {
|
|
|
22055
22925
|
|
|
22056
22926
|
// src/kit/clipboard-image.ts
|
|
22057
22927
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
22058
|
-
import { readFileSync as
|
|
22928
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22059
22929
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
22060
|
-
import { join as
|
|
22930
|
+
import { join as join16 } from "node:path";
|
|
22061
22931
|
var READ_TIMEOUT_MS = 3e3;
|
|
22062
22932
|
var MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
22063
22933
|
function captureStdout(command, args) {
|
|
@@ -22066,9 +22936,9 @@ function captureStdout(command, args) {
|
|
|
22066
22936
|
maxBuffer: MAX_BUFFER_BYTES
|
|
22067
22937
|
});
|
|
22068
22938
|
if (result.error || result.status !== 0) return null;
|
|
22069
|
-
const
|
|
22070
|
-
if (!Buffer.isBuffer(
|
|
22071
|
-
return
|
|
22939
|
+
const out2 = result.stdout;
|
|
22940
|
+
if (!Buffer.isBuffer(out2) || out2.length === 0) return null;
|
|
22941
|
+
return out2;
|
|
22072
22942
|
}
|
|
22073
22943
|
function captureViaOsascript() {
|
|
22074
22944
|
const result = spawnSync2(
|
|
@@ -22100,10 +22970,10 @@ function captureViaOsascript() {
|
|
|
22100
22970
|
{ timeout: READ_TIMEOUT_MS, encoding: "utf8" }
|
|
22101
22971
|
);
|
|
22102
22972
|
if (result.error || result.status !== 0) return null;
|
|
22103
|
-
const
|
|
22104
|
-
if (
|
|
22973
|
+
const path4 = String(result.stdout ?? "").trim();
|
|
22974
|
+
if (path4.length === 0) return null;
|
|
22105
22975
|
try {
|
|
22106
|
-
const bytes =
|
|
22976
|
+
const bytes = readFileSync10(path4);
|
|
22107
22977
|
return bytes.length > 0 ? bytes : null;
|
|
22108
22978
|
} catch {
|
|
22109
22979
|
return null;
|
|
@@ -22130,10 +23000,10 @@ function readClipboardImage(options = {}) {
|
|
|
22130
23000
|
if (bytes === null) return null;
|
|
22131
23001
|
const dir = options.dir ?? tmpdir2();
|
|
22132
23002
|
const name = `indus-clipboard-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.png`;
|
|
22133
|
-
const
|
|
23003
|
+
const path4 = join16(dir, name);
|
|
22134
23004
|
try {
|
|
22135
|
-
writeFileSync5(
|
|
22136
|
-
return
|
|
23005
|
+
writeFileSync5(path4, bytes);
|
|
23006
|
+
return path4;
|
|
22137
23007
|
} catch {
|
|
22138
23008
|
return null;
|
|
22139
23009
|
}
|
|
@@ -22141,9 +23011,9 @@ function readClipboardImage(options = {}) {
|
|
|
22141
23011
|
|
|
22142
23012
|
// src/kit/external-editor.ts
|
|
22143
23013
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
22144
|
-
import { readFileSync as
|
|
23014
|
+
import { readFileSync as readFileSync11, unlinkSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
22145
23015
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
22146
|
-
import { join as
|
|
23016
|
+
import { join as join17 } from "node:path";
|
|
22147
23017
|
var FALLBACK_EDITOR = "vi";
|
|
22148
23018
|
function resolveEditor(env) {
|
|
22149
23019
|
const configured = env.VISUAL || env.EDITOR || FALLBACK_EDITOR;
|
|
@@ -22154,18 +23024,18 @@ function openInExternalEditor(buffer, options = {}) {
|
|
|
22154
23024
|
const env = options.env ?? process.env;
|
|
22155
23025
|
const dir = options.dir ?? tmpdir3();
|
|
22156
23026
|
const name = `indus-editor-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.md`;
|
|
22157
|
-
const
|
|
23027
|
+
const path4 = join17(dir, name);
|
|
22158
23028
|
const [editor, ...editorArgs] = resolveEditor(env);
|
|
22159
23029
|
try {
|
|
22160
|
-
writeFileSync6(
|
|
22161
|
-
const result = spawnSync3(editor, [...editorArgs,
|
|
23030
|
+
writeFileSync6(path4, buffer, "utf8");
|
|
23031
|
+
const result = spawnSync3(editor, [...editorArgs, path4], { stdio: "inherit" });
|
|
22162
23032
|
if (result.error || result.status !== 0) return null;
|
|
22163
|
-
return
|
|
23033
|
+
return readFileSync11(path4, "utf8").replace(/\n$/, "");
|
|
22164
23034
|
} catch {
|
|
22165
23035
|
return null;
|
|
22166
23036
|
} finally {
|
|
22167
23037
|
try {
|
|
22168
|
-
unlinkSync(
|
|
23038
|
+
unlinkSync(path4);
|
|
22169
23039
|
} catch {
|
|
22170
23040
|
}
|
|
22171
23041
|
}
|
|
@@ -22181,16 +23051,16 @@ var CHROME_ROWS = 14;
|
|
|
22181
23051
|
var MODAL_CHROME_ROWS = 24;
|
|
22182
23052
|
var MIN_VISIBLE_ROWS = 8;
|
|
22183
23053
|
var FALLBACK_CONTEXT_WINDOW = 2e5;
|
|
22184
|
-
var PASTE_BURST_MS =
|
|
23054
|
+
var PASTE_BURST_MS = PASTE_BURST_GAP_MS;
|
|
22185
23055
|
var BRACKETED_PASTE = /\x1b?\[20[01]~/g;
|
|
22186
23056
|
function readBranch() {
|
|
22187
23057
|
try {
|
|
22188
|
-
const
|
|
23058
|
+
const out2 = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
22189
23059
|
cwd: process.cwd(),
|
|
22190
23060
|
encoding: "utf8",
|
|
22191
23061
|
stdio: ["ignore", "pipe", "ignore"]
|
|
22192
23062
|
}).trim();
|
|
22193
|
-
return
|
|
23063
|
+
return out2.length > 0 ? out2 : null;
|
|
22194
23064
|
} catch {
|
|
22195
23065
|
return null;
|
|
22196
23066
|
}
|
|
@@ -22298,6 +23168,19 @@ function renderToolUpdateText(details) {
|
|
|
22298
23168
|
const text = details.text;
|
|
22299
23169
|
return typeof text === "string" ? text : void 0;
|
|
22300
23170
|
}
|
|
23171
|
+
function permissionModeStatusText(mode) {
|
|
23172
|
+
switch (mode) {
|
|
23173
|
+
case "plan":
|
|
23174
|
+
return "Permission mode: PLAN \u2014 read-only research; mutating tools are blocked. Shift+Tab to cycle.";
|
|
23175
|
+
case "bypass":
|
|
23176
|
+
case "bypassPermissions":
|
|
23177
|
+
return "Permission mode: BYPASS \u2014 every tool auto-allowed (unsafe). Shift+Tab to cycle.";
|
|
23178
|
+
case "acceptEdits":
|
|
23179
|
+
return "Permission mode: ACCEPT-EDITS \u2014 edits auto-approved. Shift+Tab to cycle.";
|
|
23180
|
+
default:
|
|
23181
|
+
return "Permission mode: DEFAULT \u2014 tools prompt as usual. Shift+Tab to cycle.";
|
|
23182
|
+
}
|
|
23183
|
+
}
|
|
22301
23184
|
function TerminalConsole(props) {
|
|
22302
23185
|
const { conductor, theme, slash, verbose, onExit, initialInput, services } = props;
|
|
22303
23186
|
const adapter = theme.adapter;
|
|
@@ -22308,22 +23191,23 @@ function TerminalConsole(props) {
|
|
|
22308
23191
|
const chord = useRef3(NO_CHORD);
|
|
22309
23192
|
const chordTimer = useRef3(null);
|
|
22310
23193
|
const paste = useRef3(EMPTY_PASTE_VAULT);
|
|
23194
|
+
const activePaste = useRef3(null);
|
|
22311
23195
|
const burst = useRef3("");
|
|
22312
23196
|
const burstTimer = useRef3(null);
|
|
22313
23197
|
const liveAnswer = useRef3(null);
|
|
22314
23198
|
const liveReason = useRef3(null);
|
|
22315
23199
|
const rowSeed = useRef3(0);
|
|
22316
23200
|
const ctrlCAt = useRef3(0);
|
|
22317
|
-
const [highlight, setHighlight] =
|
|
22318
|
-
const [toolExecutions, setToolExecutions] =
|
|
22319
|
-
const [taskTokens, setTaskTokens] =
|
|
22320
|
-
const [subagentActivity, setSubagentActivity] =
|
|
22321
|
-
const [expandTools, setExpandTools] =
|
|
22322
|
-
const [agentsOpen, setAgentsOpen] =
|
|
22323
|
-
const [terminalRows, setTerminalRows] =
|
|
23201
|
+
const [highlight, setHighlight] = useState8(0);
|
|
23202
|
+
const [toolExecutions, setToolExecutions] = useState8({});
|
|
23203
|
+
const [taskTokens, setTaskTokens] = useState8({});
|
|
23204
|
+
const [subagentActivity, setSubagentActivity] = useState8({});
|
|
23205
|
+
const [expandTools, setExpandTools] = useState8(false);
|
|
23206
|
+
const [agentsOpen, setAgentsOpen] = useState8(false);
|
|
23207
|
+
const [terminalRows, setTerminalRows] = useState8(
|
|
22324
23208
|
() => process.stdout.rows ?? FALLBACK_TERMINAL_ROWS
|
|
22325
23209
|
);
|
|
22326
|
-
const [, forceTick] =
|
|
23210
|
+
const [, forceTick] = useState8(0);
|
|
22327
23211
|
const pulse = useCallback(() => forceTick((n) => n + 1), []);
|
|
22328
23212
|
const dirReader = useMemo2(() => createDirReader(process.cwd()), []);
|
|
22329
23213
|
const [approvalQueue, dispatchApproval] = useReducer(
|
|
@@ -22349,7 +23233,11 @@ function TerminalConsole(props) {
|
|
|
22349
23233
|
(toolName, input, opts) => new Promise((resolve8) => {
|
|
22350
23234
|
approvalSeed.current += 1;
|
|
22351
23235
|
const id = `ap_${approvalSeed.current}`;
|
|
22352
|
-
const request = {
|
|
23236
|
+
const request = {
|
|
23237
|
+
toolName,
|
|
23238
|
+
input,
|
|
23239
|
+
suggestions: allowAlwaysRuleStrings(toolName, input)
|
|
23240
|
+
};
|
|
22353
23241
|
approvalResolvers.current.set(id, resolve8);
|
|
22354
23242
|
const signal = opts.signal;
|
|
22355
23243
|
if (signal !== void 0) {
|
|
@@ -22368,7 +23256,7 @@ function TerminalConsole(props) {
|
|
|
22368
23256
|
}),
|
|
22369
23257
|
[settleApproval]
|
|
22370
23258
|
);
|
|
22371
|
-
|
|
23259
|
+
useEffect7(() => {
|
|
22372
23260
|
conductor.setApprovalResolver(requestApproval);
|
|
22373
23261
|
return () => {
|
|
22374
23262
|
conductor.setApprovalResolver(void 0);
|
|
@@ -22378,7 +23266,7 @@ function TerminalConsole(props) {
|
|
|
22378
23266
|
const head = activeApproval(approvalQueue);
|
|
22379
23267
|
const headId = head?.id;
|
|
22380
23268
|
const approvalModalOpen = useRef3(false);
|
|
22381
|
-
|
|
23269
|
+
useEffect7(() => {
|
|
22382
23270
|
if (head === void 0) {
|
|
22383
23271
|
if (approvalModalOpen.current) {
|
|
22384
23272
|
approvalModalOpen.current = false;
|
|
@@ -22396,7 +23284,17 @@ function TerminalConsole(props) {
|
|
|
22396
23284
|
}
|
|
22397
23285
|
});
|
|
22398
23286
|
}, [headId, settleApproval]);
|
|
22399
|
-
|
|
23287
|
+
const cyclePermission = useCallback(() => {
|
|
23288
|
+
const now = conductor.cyclePermissionMode();
|
|
23289
|
+
let text = permissionModeStatusText(now);
|
|
23290
|
+
if (modeReleasesApprovals(now) && approvalResolvers.current.size > 0) {
|
|
23291
|
+
const parked = [...approvalResolvers.current.keys()];
|
|
23292
|
+
for (const id of parked) settleApproval(id, "allow-once");
|
|
23293
|
+
text += ` Released ${parked.length} pending approval${parked.length === 1 ? "" : "s"}.`;
|
|
23294
|
+
}
|
|
23295
|
+
dispatch2({ type: "status:set", status: { kind: "info", text } });
|
|
23296
|
+
}, [conductor, settleApproval]);
|
|
23297
|
+
useEffect7(() => {
|
|
22400
23298
|
const off = conductor.subscribe((signal) => {
|
|
22401
23299
|
switch (signal.kind) {
|
|
22402
23300
|
case "prompt": {
|
|
@@ -22502,7 +23400,30 @@ function TerminalConsole(props) {
|
|
|
22502
23400
|
break;
|
|
22503
23401
|
}
|
|
22504
23402
|
case "compacted": {
|
|
22505
|
-
|
|
23403
|
+
if (signal.manual) {
|
|
23404
|
+
const carried = [];
|
|
23405
|
+
for (const message of conductor.messages()) {
|
|
23406
|
+
const content = message.content;
|
|
23407
|
+
if (typeof content === "string" && content.startsWith(RESTORED_FILE_PREFIX)) {
|
|
23408
|
+
const firstLine = content.slice(RESTORED_FILE_PREFIX.length).split("\n", 1)[0];
|
|
23409
|
+
if (firstLine) carried.push(firstLine.trim());
|
|
23410
|
+
}
|
|
23411
|
+
}
|
|
23412
|
+
setCompactNote(carried);
|
|
23413
|
+
visibleFrom.current = conductor.messages().length;
|
|
23414
|
+
liveAnswer.current = null;
|
|
23415
|
+
liveReason.current = null;
|
|
23416
|
+
answerText.current = "";
|
|
23417
|
+
reasonText.current = "";
|
|
23418
|
+
dispatch2({ type: "rows:set", rows: [] });
|
|
23419
|
+
}
|
|
23420
|
+
dispatch2({
|
|
23421
|
+
type: "status:set",
|
|
23422
|
+
status: {
|
|
23423
|
+
kind: "info",
|
|
23424
|
+
text: signal.manual ? "Conversation condensed." : "Auto-compacted older history to stay within the context window (automatic \u2014 you didn't run /compact)."
|
|
23425
|
+
}
|
|
23426
|
+
});
|
|
22506
23427
|
break;
|
|
22507
23428
|
}
|
|
22508
23429
|
case "persisted": {
|
|
@@ -22510,6 +23431,10 @@ function TerminalConsole(props) {
|
|
|
22510
23431
|
break;
|
|
22511
23432
|
}
|
|
22512
23433
|
case "fault": {
|
|
23434
|
+
if (signal.transient) {
|
|
23435
|
+
dispatch2({ type: "status:set", status: { kind: "warning", text: signal.fault.message } });
|
|
23436
|
+
break;
|
|
23437
|
+
}
|
|
22513
23438
|
liveAnswer.current = null;
|
|
22514
23439
|
liveReason.current = null;
|
|
22515
23440
|
dispatch2({ type: "busy:set", busy: false });
|
|
@@ -22529,12 +23454,14 @@ function TerminalConsole(props) {
|
|
|
22529
23454
|
}, [conductor]);
|
|
22530
23455
|
const answerText = useRef3("");
|
|
22531
23456
|
const reasonText = useRef3("");
|
|
23457
|
+
const visibleFrom = useRef3(0);
|
|
23458
|
+
const [compactNote, setCompactNote] = useState8(null);
|
|
22532
23459
|
const completion = useMemo2(
|
|
22533
23460
|
() => completeAt(state.buffer, state.caret, slash, dirReader),
|
|
22534
23461
|
[state.buffer, state.caret, slash, dirReader]
|
|
22535
23462
|
);
|
|
22536
23463
|
const suggestions = completion.suggestions;
|
|
22537
|
-
|
|
23464
|
+
useEffect7(() => {
|
|
22538
23465
|
if (highlight >= suggestions.length) setHighlight(0);
|
|
22539
23466
|
}, [suggestions.length, highlight]);
|
|
22540
23467
|
const submit = useCallback(
|
|
@@ -22558,10 +23485,10 @@ function TerminalConsole(props) {
|
|
|
22558
23485
|
text: `Shell exited ${outcome.exitCode}.`
|
|
22559
23486
|
}
|
|
22560
23487
|
});
|
|
22561
|
-
}).catch((
|
|
23488
|
+
}).catch((err2) => {
|
|
22562
23489
|
dispatch2({
|
|
22563
23490
|
type: "status:set",
|
|
22564
|
-
status: { kind: "error", text:
|
|
23491
|
+
status: { kind: "error", text: err2 instanceof Error ? err2.message : String(err2) }
|
|
22565
23492
|
});
|
|
22566
23493
|
});
|
|
22567
23494
|
return;
|
|
@@ -22599,15 +23526,23 @@ function TerminalConsole(props) {
|
|
|
22599
23526
|
const id = freshRowId(rowSeed.current++);
|
|
22600
23527
|
dispatch2({ type: "rows:append", row: { id, kind: "prompt", text } });
|
|
22601
23528
|
dispatch2({ type: "busy:set", busy: true });
|
|
23529
|
+
if (conductor.snapshot().phase === "condensing") {
|
|
23530
|
+
dispatch2({
|
|
23531
|
+
type: "status:set",
|
|
23532
|
+
status: { kind: "info", text: "Queued message for after compaction." }
|
|
23533
|
+
});
|
|
23534
|
+
}
|
|
23535
|
+
setCompactNote(null);
|
|
23536
|
+
activePaste.current = null;
|
|
22602
23537
|
answerText.current = "";
|
|
22603
23538
|
reasonText.current = "";
|
|
22604
23539
|
try {
|
|
22605
23540
|
await conductor.submit(text);
|
|
22606
|
-
} catch (
|
|
23541
|
+
} catch (err2) {
|
|
22607
23542
|
dispatch2({ type: "busy:set", busy: false });
|
|
22608
23543
|
dispatch2({
|
|
22609
23544
|
type: "status:set",
|
|
22610
|
-
status: { kind: "error", text:
|
|
23545
|
+
status: { kind: "error", text: err2 instanceof Error ? err2.message : String(err2) }
|
|
22611
23546
|
});
|
|
22612
23547
|
}
|
|
22613
23548
|
pulse();
|
|
@@ -22623,12 +23558,29 @@ function TerminalConsole(props) {
|
|
|
22623
23558
|
const text = burst.current;
|
|
22624
23559
|
if (text.length === 0) return;
|
|
22625
23560
|
burst.current = "";
|
|
22626
|
-
|
|
23561
|
+
const now = Date.now();
|
|
23562
|
+
const active = activePaste.current;
|
|
23563
|
+
if (active !== null && now <= active.until && text.length > 1 && pasteLines(paste.current, active.ordinal) < PASTE_MARKER_LINE_CAP) {
|
|
23564
|
+
const captured = appendToPaste(active.ordinal, text, paste.current);
|
|
23565
|
+
paste.current = captured.vault;
|
|
23566
|
+
dispatch2({ type: "buffer:replaceSpan", find: active.marker, replaceWith: captured.marker });
|
|
23567
|
+
activePaste.current = {
|
|
23568
|
+
ordinal: active.ordinal,
|
|
23569
|
+
marker: captured.marker,
|
|
23570
|
+
until: now + PASTE_CONTINUATION_MS
|
|
23571
|
+
};
|
|
23572
|
+
} else if (text.length > 1 && (classifyPaste(text) === "coalesce" || active !== null && now <= active.until)) {
|
|
22627
23573
|
const captured = coalescePaste(text, paste.current);
|
|
22628
23574
|
paste.current = captured.vault;
|
|
22629
23575
|
dispatch2({ type: "buffer:insert", text: captured.marker });
|
|
23576
|
+
activePaste.current = {
|
|
23577
|
+
ordinal: captured.vault.minted,
|
|
23578
|
+
marker: captured.marker,
|
|
23579
|
+
until: now + PASTE_CONTINUATION_MS
|
|
23580
|
+
};
|
|
22630
23581
|
} else {
|
|
22631
23582
|
dispatch2({ type: "buffer:insert", text });
|
|
23583
|
+
activePaste.current = null;
|
|
22632
23584
|
}
|
|
22633
23585
|
setHighlight(0);
|
|
22634
23586
|
}, []);
|
|
@@ -22644,14 +23596,14 @@ function TerminalConsole(props) {
|
|
|
22644
23596
|
chordTimer.current = null;
|
|
22645
23597
|
}
|
|
22646
23598
|
}, []);
|
|
22647
|
-
|
|
23599
|
+
useEffect7(
|
|
22648
23600
|
() => () => {
|
|
22649
23601
|
if (chordTimer.current !== null) clearTimeout(chordTimer.current);
|
|
22650
23602
|
if (burstTimer.current !== null) clearTimeout(burstTimer.current);
|
|
22651
23603
|
},
|
|
22652
23604
|
[]
|
|
22653
23605
|
);
|
|
22654
|
-
|
|
23606
|
+
useEffect7(() => {
|
|
22655
23607
|
const onResize = () => setTerminalRows(process.stdout.rows ?? FALLBACK_TERMINAL_ROWS);
|
|
22656
23608
|
process.stdout.on("resize", onResize);
|
|
22657
23609
|
return () => {
|
|
@@ -22659,7 +23611,7 @@ function TerminalConsole(props) {
|
|
|
22659
23611
|
};
|
|
22660
23612
|
}, []);
|
|
22661
23613
|
const titleName = conductor.sessionName();
|
|
22662
|
-
|
|
23614
|
+
useEffect7(() => {
|
|
22663
23615
|
writeTerminalTitle(titleName && titleName.length > 0 ? titleName : "indus console");
|
|
22664
23616
|
}, [titleName]);
|
|
22665
23617
|
const requestExit = useCallback(() => {
|
|
@@ -22785,7 +23737,7 @@ function TerminalConsole(props) {
|
|
|
22785
23737
|
}
|
|
22786
23738
|
} else if (state.modal.kind !== "none") {
|
|
22787
23739
|
dispatch2({ type: "modal:close" });
|
|
22788
|
-
} else if (state.busy) {
|
|
23740
|
+
} else if (state.busy || conductor.snapshot().phase === "condensing") {
|
|
22789
23741
|
denyAllApprovals();
|
|
22790
23742
|
conductor.abort();
|
|
22791
23743
|
} else if (suggestions.length > 0) {
|
|
@@ -22821,12 +23773,9 @@ function TerminalConsole(props) {
|
|
|
22821
23773
|
dispatch2({ type: "status:set", status: { kind: "info", text: `Reasoning effort: ${level}.` } });
|
|
22822
23774
|
return;
|
|
22823
23775
|
}
|
|
22824
|
-
case "mode:cyclePermission":
|
|
22825
|
-
|
|
22826
|
-
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.";
|
|
22827
|
-
dispatch2({ type: "status:set", status: { kind: "info", text } });
|
|
23776
|
+
case "mode:cyclePermission":
|
|
23777
|
+
cyclePermission();
|
|
22828
23778
|
return;
|
|
22829
|
-
}
|
|
22830
23779
|
case "view:toggleReasoning":
|
|
22831
23780
|
dispatch2({ type: "toggle:reasoning" });
|
|
22832
23781
|
return;
|
|
@@ -22839,11 +23788,25 @@ function TerminalConsole(props) {
|
|
|
22839
23788
|
}
|
|
22840
23789
|
return;
|
|
22841
23790
|
}
|
|
23791
|
+
case "queue:steer": {
|
|
23792
|
+
if (conductor.steerNow()) {
|
|
23793
|
+
dispatch2({
|
|
23794
|
+
type: "status:set",
|
|
23795
|
+
status: { kind: "info", text: "Running your queued message now \u2014 current run stopped." }
|
|
23796
|
+
});
|
|
23797
|
+
} else {
|
|
23798
|
+
dispatch2({
|
|
23799
|
+
type: "status:set",
|
|
23800
|
+
status: { kind: "warning", text: "No queued message to run \u2014 type one first, then Ctrl+X." }
|
|
23801
|
+
});
|
|
23802
|
+
}
|
|
23803
|
+
return;
|
|
23804
|
+
}
|
|
22842
23805
|
case "input:pasteImage": {
|
|
22843
|
-
const
|
|
22844
|
-
if (
|
|
23806
|
+
const path4 = readClipboardImage();
|
|
23807
|
+
if (path4 !== null) {
|
|
22845
23808
|
const sep = state.buffer.length > 0 && !/\s$/.test(state.buffer) ? " " : "";
|
|
22846
|
-
dispatch2({ type: "buffer:insert", text: `${sep}${
|
|
23809
|
+
dispatch2({ type: "buffer:insert", text: `${sep}${path4}` });
|
|
22847
23810
|
} else {
|
|
22848
23811
|
dispatch2({ type: "status:set", status: { kind: "warning", text: "No image on the clipboard." } });
|
|
22849
23812
|
}
|
|
@@ -22872,20 +23835,30 @@ function TerminalConsole(props) {
|
|
|
22872
23835
|
return;
|
|
22873
23836
|
}
|
|
22874
23837
|
}, { isActive: state.modal.kind === "none" && !agentsOpen });
|
|
23838
|
+
useInput3((_rawInput, key) => {
|
|
23839
|
+
if (key.tab && key.shift) cyclePermission();
|
|
23840
|
+
}, { isActive: state.modal.kind === "approval" });
|
|
22875
23841
|
const seeded = useRef3(false);
|
|
22876
|
-
|
|
23842
|
+
useEffect7(() => {
|
|
22877
23843
|
if (seeded.current) return;
|
|
22878
23844
|
seeded.current = true;
|
|
23845
|
+
const opening = conductor.permissionMode();
|
|
23846
|
+
if (opening !== "default") {
|
|
23847
|
+
dispatch2({
|
|
23848
|
+
type: "status:set",
|
|
23849
|
+
status: { kind: "warning", text: permissionModeStatusText(opening) }
|
|
23850
|
+
});
|
|
23851
|
+
}
|
|
22879
23852
|
if (initialInput && initialInput.trim().length > 0) {
|
|
22880
23853
|
void runTurn(initialInput);
|
|
22881
23854
|
}
|
|
22882
23855
|
}, []);
|
|
22883
|
-
const
|
|
23856
|
+
const allMessages = [...conductor.messages()];
|
|
23857
|
+
if (allMessages.length < visibleFrom.current) visibleFrom.current = 0;
|
|
23858
|
+
const liveMessages = allMessages.slice(visibleFrom.current);
|
|
22884
23859
|
const agentRuns = deriveAgentRuns(liveMessages);
|
|
22885
23860
|
const snapshot = projectSnapshot(conductor, liveMessages, services);
|
|
22886
23861
|
const branch = useMemo2(() => readBranch(), []);
|
|
22887
|
-
const modalOpen = state.modal.kind !== "none";
|
|
22888
|
-
const maxItems = transcriptHeight(terminalRows, modalOpen, agentPanelRows(agentRuns));
|
|
22889
23862
|
const pendingMessages = conductor.pendingInputs().map((entry, index) => ({
|
|
22890
23863
|
id: `pending-${index}-${entry.mode}`,
|
|
22891
23864
|
mode: entry.mode,
|
|
@@ -22895,12 +23868,21 @@ function TerminalConsole(props) {
|
|
|
22895
23868
|
const SHOW_TOOL_ACTIVITY = false;
|
|
22896
23869
|
const runningTools = Object.values(toolExecutions).some((t) => t.status === "running");
|
|
22897
23870
|
const showTaskPanel = SHOW_TOOL_ACTIVITY && runningTools || pendingMessages.length > 0;
|
|
23871
|
+
const modalOpen = state.modal.kind !== "none";
|
|
23872
|
+
const streamingAnswerRows = liveAnswer.current !== null && answerText.current ? Math.min(6, answerText.current.split("\n").length + 1) : 0;
|
|
23873
|
+
const taskPanelRows = showTaskPanel ? 2 + Math.min(pendingMessages.length, 8) : 0;
|
|
23874
|
+
const workingIndicatorRows = state.busy ? 2 : 0;
|
|
23875
|
+
const maxItems = transcriptHeight(
|
|
23876
|
+
terminalRows,
|
|
23877
|
+
modalOpen,
|
|
23878
|
+
agentPanelRows(agentRuns) + streamingAnswerRows + taskPanelRows + workingIndicatorRows
|
|
23879
|
+
);
|
|
22898
23880
|
const providerCount = countProviders(conductor);
|
|
22899
23881
|
const lastSeenVersion = services?.settings.get("lastSeenVersion") ?? "";
|
|
22900
23882
|
const startupMap = useMemo2(
|
|
22901
23883
|
() => gatherStartup({
|
|
22902
23884
|
cwd: process.cwd(),
|
|
22903
|
-
home:
|
|
23885
|
+
home: homedir6(),
|
|
22904
23886
|
version: VERSION,
|
|
22905
23887
|
lastSeenVersion
|
|
22906
23888
|
}),
|
|
@@ -22909,8 +23891,8 @@ function TerminalConsole(props) {
|
|
|
22909
23891
|
const quietStartup = (services?.settings.get("quietStartup") ?? false) && !verbose;
|
|
22910
23892
|
const sweep = (services?.settings.get("logoSweep") ?? false) && !(services?.settings.get("reducedMotion") ?? false) && Boolean(process.stdout.isTTY);
|
|
22911
23893
|
const welcomeSeed = PINNED_WELCOME_SEED;
|
|
22912
|
-
const [welcomeName, setWelcomeName] =
|
|
22913
|
-
|
|
23894
|
+
const [welcomeName, setWelcomeName] = useState8(void 0);
|
|
23895
|
+
useEffect7(() => {
|
|
22914
23896
|
if (!services) return;
|
|
22915
23897
|
let live = true;
|
|
22916
23898
|
const provider = services.settings.get("defaultProvider");
|
|
@@ -22922,6 +23904,12 @@ function TerminalConsole(props) {
|
|
|
22922
23904
|
live = false;
|
|
22923
23905
|
};
|
|
22924
23906
|
}, [services]);
|
|
23907
|
+
const authedProviders = useAuthenticatedProviders(services, state.status);
|
|
23908
|
+
const boundModelId = conductor.snapshot().modelId;
|
|
23909
|
+
const boundProvider = boundModelId.includes("/") ? boundModelId.split("/")[0] : boundModelId;
|
|
23910
|
+
const modelAuthed = authedProviders === null || authedProviders.has(boundProvider);
|
|
23911
|
+
const bannerModelId = modelAuthed ? boundModelId : "no authenticated model \u2014 run /login";
|
|
23912
|
+
const statusBarSnapshot = modelAuthed || !snapshot.model ? snapshot : { ...snapshot, model: { ...snapshot.model, provider: "no model", id: "run /login" } };
|
|
22925
23913
|
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
22926
23914
|
agentsOpen ? (
|
|
22927
23915
|
// The drill-in agents view replaces the transcript while open; it owns
|
|
@@ -22941,7 +23929,7 @@ function TerminalConsole(props) {
|
|
|
22941
23929
|
Banner,
|
|
22942
23930
|
{
|
|
22943
23931
|
theme: adapter,
|
|
22944
|
-
modelId:
|
|
23932
|
+
modelId: bannerModelId,
|
|
22945
23933
|
workspace: process.cwd(),
|
|
22946
23934
|
version: VERSION,
|
|
22947
23935
|
verbose,
|
|
@@ -22955,6 +23943,23 @@ function TerminalConsole(props) {
|
|
|
22955
23943
|
variantSeed: welcomeSeed
|
|
22956
23944
|
}
|
|
22957
23945
|
),
|
|
23946
|
+
compactNote !== null ? /* @__PURE__ */ jsxs10(
|
|
23947
|
+
Box10,
|
|
23948
|
+
{
|
|
23949
|
+
flexDirection: "column",
|
|
23950
|
+
borderStyle: "round",
|
|
23951
|
+
borderColor: adapter.colors["borderMuted"],
|
|
23952
|
+
paddingX: 1,
|
|
23953
|
+
marginBottom: 1,
|
|
23954
|
+
children: [
|
|
23955
|
+
/* @__PURE__ */ jsx13(Text10, { children: adapter.color("accent", "\u25C6 Context condensed \u2014 fresh session, history summarized") }),
|
|
23956
|
+
compactNote.length > 0 ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
23957
|
+
/* @__PURE__ */ jsx13(Text10, { children: adapter.muted("Files carried into the new context:") }),
|
|
23958
|
+
compactNote.map((file, index) => /* @__PURE__ */ jsx13(Text10, { children: adapter.muted(` \xB7 ${file}`) }, index))
|
|
23959
|
+
] }) : /* @__PURE__ */ jsx13(Text10, { children: adapter.muted("No files re-attached; the summary digest carries the history.") })
|
|
23960
|
+
]
|
|
23961
|
+
}
|
|
23962
|
+
) : null,
|
|
22958
23963
|
/* @__PURE__ */ jsx13(
|
|
22959
23964
|
MessageList,
|
|
22960
23965
|
{
|
|
@@ -22978,7 +23983,14 @@ function TerminalConsole(props) {
|
|
|
22978
23983
|
pendingMessages
|
|
22979
23984
|
}
|
|
22980
23985
|
) : null,
|
|
22981
|
-
/* @__PURE__ */ jsx13(
|
|
23986
|
+
/* @__PURE__ */ jsx13(
|
|
23987
|
+
WorkingIndicator,
|
|
23988
|
+
{
|
|
23989
|
+
theme: adapter,
|
|
23990
|
+
busy: state.busy || conductor.snapshot().phase === "condensing",
|
|
23991
|
+
phase: conductor.snapshot().phase
|
|
23992
|
+
}
|
|
23993
|
+
),
|
|
22982
23994
|
/* @__PURE__ */ jsx13(
|
|
22983
23995
|
Composer,
|
|
22984
23996
|
{
|
|
@@ -22994,7 +24006,7 @@ function TerminalConsole(props) {
|
|
|
22994
24006
|
StatusBar,
|
|
22995
24007
|
{
|
|
22996
24008
|
theme: adapter,
|
|
22997
|
-
snapshot,
|
|
24009
|
+
snapshot: statusBarSnapshot,
|
|
22998
24010
|
branch,
|
|
22999
24011
|
providerCount,
|
|
23000
24012
|
status: state.status,
|
|
@@ -23049,8 +24061,8 @@ __export(sessions_exports, {
|
|
|
23049
24061
|
|
|
23050
24062
|
// src/sessions/library.ts
|
|
23051
24063
|
init_conductor2();
|
|
23052
|
-
import { mkdir, readFile as
|
|
23053
|
-
import { basename as basename5, join as
|
|
24064
|
+
import { mkdir as mkdir2, readFile as readFile3, readdir, rename, rm, stat as stat2 } from "node:fs/promises";
|
|
24065
|
+
import { basename as basename5, join as join18 } from "node:path";
|
|
23054
24066
|
var SESSION_FILE_EXT = ".ndjson";
|
|
23055
24067
|
var PREVIEW_LIMIT = 72;
|
|
23056
24068
|
var SessionLibrary = class {
|
|
@@ -23110,7 +24122,7 @@ var SessionLibrary = class {
|
|
|
23110
24122
|
if (!await this.#missing(toPath)) {
|
|
23111
24123
|
throw new Error(`SessionLibrary.rename: session "${toId}" already exists`);
|
|
23112
24124
|
}
|
|
23113
|
-
await
|
|
24125
|
+
await mkdir2(this.#dir, { recursive: true });
|
|
23114
24126
|
await rename(fromPath, toPath);
|
|
23115
24127
|
return toPath;
|
|
23116
24128
|
}
|
|
@@ -23119,14 +24131,14 @@ var SessionLibrary = class {
|
|
|
23119
24131
|
* there was nothing to delete — never throws on an already-absent session.
|
|
23120
24132
|
*/
|
|
23121
24133
|
async remove(id) {
|
|
23122
|
-
const
|
|
23123
|
-
if (await this.#missing(
|
|
23124
|
-
await rm(
|
|
24134
|
+
const path4 = this.pathOf(id);
|
|
24135
|
+
if (await this.#missing(path4)) return false;
|
|
24136
|
+
await rm(path4, { force: true });
|
|
23125
24137
|
return true;
|
|
23126
24138
|
}
|
|
23127
24139
|
/** Absolute path a session id persists to. */
|
|
23128
24140
|
pathOf(id) {
|
|
23129
|
-
return
|
|
24141
|
+
return join18(this.#dir, `${id}${SESSION_FILE_EXT}`);
|
|
23130
24142
|
}
|
|
23131
24143
|
/**
|
|
23132
24144
|
* Flatten a loaded transcript into an ordered {@link BranchNode} list for a
|
|
@@ -23150,9 +24162,9 @@ var SessionLibrary = class {
|
|
|
23150
24162
|
for (const node of nodes) {
|
|
23151
24163
|
if (node.parent !== null) hasChildren.add(node.parent);
|
|
23152
24164
|
}
|
|
23153
|
-
const
|
|
24165
|
+
const out2 = [];
|
|
23154
24166
|
const walk = (entry, depth) => {
|
|
23155
|
-
|
|
24167
|
+
out2.push({
|
|
23156
24168
|
id: entry.id,
|
|
23157
24169
|
parent: entry.parent,
|
|
23158
24170
|
label: labelFor(entry, depth),
|
|
@@ -23167,7 +24179,7 @@ var SessionLibrary = class {
|
|
|
23167
24179
|
for (const root of childrenOf.get(null) ?? []) {
|
|
23168
24180
|
walk(root, 0);
|
|
23169
24181
|
}
|
|
23170
|
-
return
|
|
24182
|
+
return out2;
|
|
23171
24183
|
}
|
|
23172
24184
|
/**
|
|
23173
24185
|
* Extract the user prompts along a loaded transcript's active branch as fork
|
|
@@ -23178,14 +24190,14 @@ var SessionLibrary = class {
|
|
|
23178
24190
|
* text, projecting each to a {@link PriorTurn} a forking picker can offer.
|
|
23179
24191
|
*/
|
|
23180
24192
|
priorTurns(store) {
|
|
23181
|
-
const
|
|
24193
|
+
const out2 = [];
|
|
23182
24194
|
for (const entry of store.pathTo()) {
|
|
23183
24195
|
if (entry.role !== "user") continue;
|
|
23184
24196
|
const text = messageText(entry.content).trim();
|
|
23185
24197
|
if (text.length === 0) continue;
|
|
23186
|
-
|
|
24198
|
+
out2.push({ entryId: entry.id, text, preview: previewOf(text) });
|
|
23187
24199
|
}
|
|
23188
|
-
return
|
|
24200
|
+
return out2;
|
|
23189
24201
|
}
|
|
23190
24202
|
/* ---- internals ---- */
|
|
23191
24203
|
/** Bare session ids present in the directory (no extension), or `[]`. */
|
|
@@ -23200,41 +24212,41 @@ var SessionLibrary = class {
|
|
|
23200
24212
|
}
|
|
23201
24213
|
/** Catalog row from file metadata only — no parse. */
|
|
23202
24214
|
async #shallowRow(id) {
|
|
23203
|
-
const
|
|
23204
|
-
const meta = await this.#fileMeta(
|
|
23205
|
-
return { id, path:
|
|
24215
|
+
const path4 = this.pathOf(id);
|
|
24216
|
+
const meta = await this.#fileMeta(path4);
|
|
24217
|
+
return { id, path: path4, ...meta };
|
|
23206
24218
|
}
|
|
23207
24219
|
/** Catalog row enriched by opening the transcript and reducing its text. */
|
|
23208
24220
|
async #deepRow(id) {
|
|
23209
|
-
const
|
|
23210
|
-
const meta = await this.#fileMeta(
|
|
24221
|
+
const path4 = this.pathOf(id);
|
|
24222
|
+
const meta = await this.#fileMeta(path4);
|
|
23211
24223
|
const store = await this.open(id);
|
|
23212
|
-
if (store === null) return { id, path:
|
|
24224
|
+
if (store === null) return { id, path: path4, ...meta };
|
|
23213
24225
|
const branch = store.pathTo();
|
|
23214
24226
|
const conversational = branch.filter(isConversational);
|
|
23215
24227
|
const opener = conversational.find((entry) => entry.role === "user");
|
|
23216
24228
|
const preview2 = opener ? previewOf(messageText(opener.content)) : void 0;
|
|
23217
24229
|
return {
|
|
23218
24230
|
id,
|
|
23219
|
-
path:
|
|
24231
|
+
path: path4,
|
|
23220
24232
|
...meta,
|
|
23221
24233
|
messageCount: conversational.length,
|
|
23222
24234
|
...preview2 ? { preview: preview2, name: preview2 } : {}
|
|
23223
24235
|
};
|
|
23224
24236
|
}
|
|
23225
24237
|
/** Best-effort `{ size, lastModified }`; empty object when the file is gone. */
|
|
23226
|
-
async #fileMeta(
|
|
24238
|
+
async #fileMeta(path4) {
|
|
23227
24239
|
try {
|
|
23228
|
-
const info2 = await stat2(
|
|
24240
|
+
const info2 = await stat2(path4);
|
|
23229
24241
|
return { size: info2.size, lastModified: info2.mtimeMs };
|
|
23230
24242
|
} catch {
|
|
23231
24243
|
return {};
|
|
23232
24244
|
}
|
|
23233
24245
|
}
|
|
23234
24246
|
/** True when a path does not resolve to a readable file. */
|
|
23235
|
-
async #missing(
|
|
24247
|
+
async #missing(path4) {
|
|
23236
24248
|
try {
|
|
23237
|
-
await
|
|
24249
|
+
await readFile3(path4);
|
|
23238
24250
|
return false;
|
|
23239
24251
|
} catch {
|
|
23240
24252
|
return true;
|
|
@@ -23289,7 +24301,7 @@ function previewOf(text, limit = PREVIEW_LIMIT) {
|
|
|
23289
24301
|
}
|
|
23290
24302
|
|
|
23291
24303
|
// src/boot/auth-vault.ts
|
|
23292
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
24304
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
|
|
23293
24305
|
import { dirname as dirname6 } from "node:path";
|
|
23294
24306
|
import {
|
|
23295
24307
|
ensureFreshOAuthCredentials,
|
|
@@ -23313,9 +24325,9 @@ function normaliseRecord(value) {
|
|
|
23313
24325
|
}
|
|
23314
24326
|
return void 0;
|
|
23315
24327
|
}
|
|
23316
|
-
function readAuthFile(
|
|
24328
|
+
function readAuthFile(path4) {
|
|
23317
24329
|
try {
|
|
23318
|
-
const text =
|
|
24330
|
+
const text = readFileSync12(path4, "utf8");
|
|
23319
24331
|
const parsed = JSON.parse(text);
|
|
23320
24332
|
if (parsed === null || typeof parsed !== "object") return {};
|
|
23321
24333
|
const file = {};
|
|
@@ -23333,9 +24345,9 @@ function readAuthFile(path3) {
|
|
|
23333
24345
|
return {};
|
|
23334
24346
|
}
|
|
23335
24347
|
}
|
|
23336
|
-
function writeAuthFile(
|
|
23337
|
-
mkdirSync4(dirname6(
|
|
23338
|
-
writeFileSync7(
|
|
24348
|
+
function writeAuthFile(path4, data) {
|
|
24349
|
+
mkdirSync4(dirname6(path4), { recursive: true });
|
|
24350
|
+
writeFileSync7(path4, `${JSON.stringify(data, null, 2)}
|
|
23339
24351
|
`, { mode: 384 });
|
|
23340
24352
|
}
|
|
23341
24353
|
function toCredentials(record) {
|
|
@@ -23429,11 +24441,14 @@ function createAuthVault(authPath) {
|
|
|
23429
24441
|
};
|
|
23430
24442
|
}
|
|
23431
24443
|
|
|
24444
|
+
// src/boot/runners/repl-runner.ts
|
|
24445
|
+
init_server_mode();
|
|
24446
|
+
|
|
23432
24447
|
// src/boot/runners/session.ts
|
|
23433
24448
|
init_conductor2();
|
|
23434
|
-
import { existsSync as existsSync6, readFileSync as
|
|
23435
|
-
import { homedir as
|
|
23436
|
-
import { join as
|
|
24449
|
+
import { existsSync as existsSync6, readFileSync as readFileSync15 } from "node:fs";
|
|
24450
|
+
import { homedir as homedir8 } from "node:os";
|
|
24451
|
+
import { join as join21 } from "node:path";
|
|
23437
24452
|
init_capability_deck();
|
|
23438
24453
|
init_task_card();
|
|
23439
24454
|
init_workflow_card();
|
|
@@ -23464,7 +24479,7 @@ function argPreview(args) {
|
|
|
23464
24479
|
return ` (${oneLine2(String(text), 56)})`;
|
|
23465
24480
|
}
|
|
23466
24481
|
function buildActivity(messages) {
|
|
23467
|
-
const
|
|
24482
|
+
const out2 = [];
|
|
23468
24483
|
for (const message of messages) {
|
|
23469
24484
|
if (message.role !== "assistant") continue;
|
|
23470
24485
|
const content = message.content;
|
|
@@ -23472,14 +24487,50 @@ function buildActivity(messages) {
|
|
|
23472
24487
|
for (const part of content) {
|
|
23473
24488
|
const p = part;
|
|
23474
24489
|
if (p.type === "text" && typeof p.text === "string" && p.text.trim() || p.type === "thinking" && typeof p.thinking === "string" && p.thinking.trim()) {
|
|
23475
|
-
|
|
24490
|
+
out2.push({ tone: "reason", text: oneLine2(p.text ?? p.thinking) });
|
|
23476
24491
|
} else if (p.type === "toolCall" && typeof p.name === "string") {
|
|
23477
24492
|
const name = p.name.charAt(0).toUpperCase() + p.name.slice(1);
|
|
23478
|
-
|
|
24493
|
+
out2.push({ tone: "tool", text: `${name}${argPreview(p.arguments)}` });
|
|
23479
24494
|
}
|
|
23480
24495
|
}
|
|
23481
24496
|
}
|
|
23482
|
-
return
|
|
24497
|
+
return out2.slice(-14);
|
|
24498
|
+
}
|
|
24499
|
+
var MAX_PARALLEL_TASKS = (() => {
|
|
24500
|
+
const n = parseInt(process.env.INDUS_MAX_PARALLEL_TASKS ?? "", 10);
|
|
24501
|
+
return Number.isFinite(n) && n >= 1 ? n : 2;
|
|
24502
|
+
})();
|
|
24503
|
+
var MAX_REPORT_CHARS = (() => {
|
|
24504
|
+
const n = parseInt(process.env.INDUS_MAX_DELEGATE_REPORT_CHARS ?? "", 10);
|
|
24505
|
+
return Number.isFinite(n) && n >= 1e3 ? n : 48e3;
|
|
24506
|
+
})();
|
|
24507
|
+
var activeTasks = 0;
|
|
24508
|
+
var taskQueue = [];
|
|
24509
|
+
async function acquireTaskSlot() {
|
|
24510
|
+
if (activeTasks < MAX_PARALLEL_TASKS) {
|
|
24511
|
+
activeTasks++;
|
|
24512
|
+
} else {
|
|
24513
|
+
await new Promise((resolve8) => taskQueue.push(resolve8));
|
|
24514
|
+
}
|
|
24515
|
+
let released = false;
|
|
24516
|
+
return () => {
|
|
24517
|
+
if (released) return;
|
|
24518
|
+
released = true;
|
|
24519
|
+
const next = taskQueue.shift();
|
|
24520
|
+
if (next) next();
|
|
24521
|
+
else activeTasks--;
|
|
24522
|
+
};
|
|
24523
|
+
}
|
|
24524
|
+
function clampReport(report) {
|
|
24525
|
+
if (report.length <= MAX_REPORT_CHARS) return report;
|
|
24526
|
+
const head = Math.floor(MAX_REPORT_CHARS * 0.7);
|
|
24527
|
+
const tail = MAX_REPORT_CHARS - head;
|
|
24528
|
+
const omitted = report.length - MAX_REPORT_CHARS;
|
|
24529
|
+
return `${report.slice(0, head)}
|
|
24530
|
+
|
|
24531
|
+
\u2026[delegate report truncated \u2014 ${omitted} characters omitted to protect parent context]\u2026
|
|
24532
|
+
|
|
24533
|
+
${report.slice(report.length - tail)}`;
|
|
23483
24534
|
}
|
|
23484
24535
|
function finalAssistantText2(messages) {
|
|
23485
24536
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -23507,48 +24558,65 @@ function createDelegateRunner(opts) {
|
|
|
23507
24558
|
|
|
23508
24559
|
Context:
|
|
23509
24560
|
${request.context}` : request.objective;
|
|
23510
|
-
const
|
|
23511
|
-
|
|
23512
|
-
// `model` is defined here: the early-return above guaranteed it when
|
|
23513
|
-
// no `spawn` seam was given.
|
|
23514
|
-
model,
|
|
23515
|
-
systemPrompt: opts.system,
|
|
23516
|
-
// The sub-agent's deck — the `'authoring'` profile excludes the
|
|
23517
|
-
// `task` card, so the sub-agent cannot recurse into delegation.
|
|
23518
|
-
tools: opts.tools?.() ?? provisionDeck("authoring", { cwd: opts.cwd }).tools()
|
|
23519
|
-
},
|
|
23520
|
-
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {}
|
|
23521
|
-
});
|
|
23522
|
-
const onAbort = () => agent.abort();
|
|
23523
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
23524
|
-
let lastSignature = "";
|
|
23525
|
-
const reportProgress = () => {
|
|
23526
|
-
if (!onProgress) return;
|
|
23527
|
-
const tokens = sumTokens(agent.state.messages);
|
|
23528
|
-
const activity = buildActivity(agent.state.messages);
|
|
23529
|
-
const signature2 = `${tokens}:${activity.length}`;
|
|
23530
|
-
if (signature2 !== lastSignature) {
|
|
23531
|
-
lastSignature = signature2;
|
|
23532
|
-
onProgress({ tokens, activity });
|
|
23533
|
-
}
|
|
23534
|
-
};
|
|
23535
|
-
const offProgress = onProgress ? agent.subscribe?.(reportProgress) : void 0;
|
|
24561
|
+
const gatewayBaseUrls = await opts.getGatewayBaseUrls?.();
|
|
24562
|
+
const releaseSlot = await acquireTaskSlot();
|
|
23536
24563
|
try {
|
|
23537
|
-
|
|
23538
|
-
|
|
23539
|
-
|
|
23540
|
-
|
|
23541
|
-
|
|
24564
|
+
if (signal?.aborted) {
|
|
24565
|
+
return { ok: false, report: "delegation aborted" };
|
|
24566
|
+
}
|
|
24567
|
+
let agent = opts.spawn?.(request.objective, request.context);
|
|
24568
|
+
if (agent === void 0) {
|
|
24569
|
+
const tools = opts.tools?.() ?? provisionDeck("authoring", { cwd: opts.cwd }).tools();
|
|
24570
|
+
agent = new Agent3({
|
|
24571
|
+
initialState: {
|
|
24572
|
+
// `model` is defined here: the early-return above guaranteed it when
|
|
24573
|
+
// no `spawn` seam was given. In server mode, route it through the
|
|
24574
|
+
// gateway (freshly resolved above) rather than the raw provider url.
|
|
24575
|
+
model: withGatewayBaseUrl(model, gatewayBaseUrls),
|
|
24576
|
+
systemPrompt: opts.system,
|
|
24577
|
+
tools
|
|
24578
|
+
},
|
|
24579
|
+
...opts.getApiKey ? { getApiKey: opts.getApiKey } : {},
|
|
24580
|
+
// Gate the sub-agent's inner tool loop with the parent session's live
|
|
24581
|
+
// policy (rules + current mode). Resolver-less: `ask` denies — a
|
|
24582
|
+
// sub-agent cannot prompt the user — while deny rules, plan mode, and
|
|
24583
|
+
// the catastrophic-bash blocklist are enforced per inner tool call.
|
|
24584
|
+
...opts.permissionPolicy !== void 0 ? { canUseTool: createSubagentPermissionGate(opts.permissionPolicy, tools) } : {}
|
|
24585
|
+
});
|
|
24586
|
+
}
|
|
24587
|
+
const onAbort = () => agent.abort();
|
|
24588
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
24589
|
+
let lastSignature = "";
|
|
24590
|
+
const reportProgress = () => {
|
|
24591
|
+
if (!onProgress) return;
|
|
24592
|
+
const tokens = sumTokens(agent.state.messages);
|
|
24593
|
+
const activity = buildActivity(agent.state.messages);
|
|
24594
|
+
const signature2 = `${tokens}:${activity.length}`;
|
|
24595
|
+
if (signature2 !== lastSignature) {
|
|
24596
|
+
lastSignature = signature2;
|
|
24597
|
+
onProgress({ tokens, activity });
|
|
24598
|
+
}
|
|
24599
|
+
};
|
|
24600
|
+
const offProgress = onProgress ? agent.subscribe?.(reportProgress) : void 0;
|
|
24601
|
+
try {
|
|
24602
|
+
await agent.prompt(objective);
|
|
24603
|
+
reportProgress();
|
|
24604
|
+
} catch (cause) {
|
|
24605
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
24606
|
+
return { ok: false, report: clampReport(message || "delegation failed") };
|
|
24607
|
+
} finally {
|
|
24608
|
+
offProgress?.();
|
|
24609
|
+
signal?.removeEventListener("abort", onAbort);
|
|
24610
|
+
}
|
|
24611
|
+
const error = agent.state.error;
|
|
24612
|
+
const report = finalAssistantText2(agent.state.messages);
|
|
24613
|
+
return {
|
|
24614
|
+
ok: error === void 0 && report.length > 0,
|
|
24615
|
+
report: clampReport(error ?? (report || "(no output)"))
|
|
24616
|
+
};
|
|
23542
24617
|
} finally {
|
|
23543
|
-
|
|
23544
|
-
signal?.removeEventListener("abort", onAbort);
|
|
24618
|
+
releaseSlot();
|
|
23545
24619
|
}
|
|
23546
|
-
const error = agent.state.error;
|
|
23547
|
-
const report = finalAssistantText2(agent.state.messages);
|
|
23548
|
-
return {
|
|
23549
|
-
ok: error === void 0 && report.length > 0,
|
|
23550
|
-
report: error ?? (report || "(no output)")
|
|
23551
|
-
};
|
|
23552
24620
|
}
|
|
23553
24621
|
};
|
|
23554
24622
|
}
|
|
@@ -23659,7 +24727,7 @@ var CheckpointStore = class {
|
|
|
23659
24727
|
snapshotFor(nodeId) {
|
|
23660
24728
|
const paths = this.byNode.get(nodeId);
|
|
23661
24729
|
if (paths === void 0) return [];
|
|
23662
|
-
return [...paths].map(([
|
|
24730
|
+
return [...paths].map(([path4, previous]) => ({ path: path4, previous }));
|
|
23663
24731
|
}
|
|
23664
24732
|
/** Whether a node has ANY recorded file snapshot (the picker's restore gate). */
|
|
23665
24733
|
hasSnapshot(nodeId) {
|
|
@@ -23684,15 +24752,15 @@ var CheckpointStore = class {
|
|
|
23684
24752
|
restore(nodeId) {
|
|
23685
24753
|
const snapshots = this.snapshotFor(nodeId);
|
|
23686
24754
|
const restored = [];
|
|
23687
|
-
for (const { path:
|
|
24755
|
+
for (const { path: path4, previous } of snapshots) {
|
|
23688
24756
|
try {
|
|
23689
24757
|
if (previous === null) {
|
|
23690
|
-
rmSync(
|
|
24758
|
+
rmSync(path4, { force: true });
|
|
23691
24759
|
} else {
|
|
23692
|
-
mkdirSync5(dirname7(
|
|
23693
|
-
writeFileSync8(
|
|
24760
|
+
mkdirSync5(dirname7(path4), { recursive: true });
|
|
24761
|
+
writeFileSync8(path4, previous, "utf8");
|
|
23694
24762
|
}
|
|
23695
|
-
restored.push(
|
|
24763
|
+
restored.push(path4);
|
|
23696
24764
|
} catch {
|
|
23697
24765
|
}
|
|
23698
24766
|
}
|
|
@@ -23755,7 +24823,7 @@ function addonFault(kind, message, detail) {
|
|
|
23755
24823
|
|
|
23756
24824
|
// src/addons/sandbox.ts
|
|
23757
24825
|
import { createJiti } from "jiti";
|
|
23758
|
-
import { homedir as
|
|
24826
|
+
import { homedir as homedir7 } from "node:os";
|
|
23759
24827
|
import { isAbsolute as isAbsolute4, resolve as resolvePathSegments } from "node:path";
|
|
23760
24828
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
|
|
23761
24829
|
var typeboxNamespace = __toESM(require_cjs(), 1);
|
|
@@ -23795,17 +24863,17 @@ var INVISIBLE_CODE_POINTS = [
|
|
|
23795
24863
|
];
|
|
23796
24864
|
var INVISIBLE_SET = new Set(INVISIBLE_CODE_POINTS);
|
|
23797
24865
|
function scrubInvisible(raw) {
|
|
23798
|
-
let
|
|
24866
|
+
let out2 = "";
|
|
23799
24867
|
for (const char of raw) {
|
|
23800
24868
|
const code = char.codePointAt(0);
|
|
23801
24869
|
if (code !== void 0 && INVISIBLE_SET.has(code)) {
|
|
23802
24870
|
continue;
|
|
23803
24871
|
}
|
|
23804
|
-
|
|
24872
|
+
out2 += char;
|
|
23805
24873
|
}
|
|
23806
|
-
return
|
|
24874
|
+
return out2.trim();
|
|
23807
24875
|
}
|
|
23808
|
-
function expandPath(raw, home =
|
|
24876
|
+
function expandPath(raw, home = homedir7()) {
|
|
23809
24877
|
const cleaned = scrubInvisible(raw);
|
|
23810
24878
|
if (cleaned === "~") {
|
|
23811
24879
|
return home;
|
|
@@ -23815,7 +24883,7 @@ function expandPath(raw, home = homedir5()) {
|
|
|
23815
24883
|
}
|
|
23816
24884
|
return cleaned;
|
|
23817
24885
|
}
|
|
23818
|
-
function resolvePath(raw, base = process.cwd(), home =
|
|
24886
|
+
function resolvePath(raw, base = process.cwd(), home = homedir7()) {
|
|
23819
24887
|
const expanded = expandPath(raw, home);
|
|
23820
24888
|
return isAbsolute4(expanded) ? resolvePathSegments(expanded) : resolvePathSegments(base, expanded);
|
|
23821
24889
|
}
|
|
@@ -23837,9 +24905,9 @@ function resolveSpecifierPath(specifier) {
|
|
|
23837
24905
|
function buildAliasMap() {
|
|
23838
24906
|
const map = {};
|
|
23839
24907
|
for (const specifier of BUNDLED_NAMESPACES) {
|
|
23840
|
-
const
|
|
23841
|
-
if (
|
|
23842
|
-
map[specifier] =
|
|
24908
|
+
const path4 = resolveSpecifierPath(specifier);
|
|
24909
|
+
if (path4 !== void 0) {
|
|
24910
|
+
map[specifier] = path4;
|
|
23843
24911
|
}
|
|
23844
24912
|
}
|
|
23845
24913
|
return map;
|
|
@@ -23885,10 +24953,10 @@ function isObject(value) {
|
|
|
23885
24953
|
function createJitiLoader(options = {}) {
|
|
23886
24954
|
const jiti = createJiti(import.meta.url, jitiOptionsForRuntime());
|
|
23887
24955
|
const base = options.base ?? process.cwd();
|
|
23888
|
-
const home = options.home ??
|
|
24956
|
+
const home = options.home ?? homedir7();
|
|
23889
24957
|
return {
|
|
23890
|
-
async load(
|
|
23891
|
-
const absolute = resolvePath(
|
|
24958
|
+
async load(path4) {
|
|
24959
|
+
const absolute = resolvePath(path4, base, home);
|
|
23892
24960
|
const specifier = pathToFileURL(absolute).href;
|
|
23893
24961
|
const imported = await jiti.import(specifier);
|
|
23894
24962
|
const manifest = toManifest(imported);
|
|
@@ -23903,8 +24971,8 @@ function createJitiLoader(options = {}) {
|
|
|
23903
24971
|
}
|
|
23904
24972
|
|
|
23905
24973
|
// src/addons/manifest.ts
|
|
23906
|
-
import { readFileSync as
|
|
23907
|
-
import { basename as basename6, extname as extname4, isAbsolute as isAbsolute5, join as
|
|
24974
|
+
import { readFileSync as readFileSync13, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
|
|
24975
|
+
import { basename as basename6, extname as extname4, isAbsolute as isAbsolute5, join as join19, resolve as resolve7 } from "node:path";
|
|
23908
24976
|
var ENTRY_EXTENSIONS = [
|
|
23909
24977
|
".ts",
|
|
23910
24978
|
".tsx",
|
|
@@ -23921,9 +24989,9 @@ function isHidden(name) {
|
|
|
23921
24989
|
function hasEntryExtension(name) {
|
|
23922
24990
|
return ENTRY_EXTENSIONS.includes(extname4(name).toLowerCase());
|
|
23923
24991
|
}
|
|
23924
|
-
function entryKind(
|
|
24992
|
+
function entryKind(path4) {
|
|
23925
24993
|
try {
|
|
23926
|
-
const stat3 = statSync4(
|
|
24994
|
+
const stat3 = statSync4(path4);
|
|
23927
24995
|
if (stat3.isDirectory()) return "directory";
|
|
23928
24996
|
if (stat3.isFile()) return "file";
|
|
23929
24997
|
return void 0;
|
|
@@ -23939,12 +25007,12 @@ function listNames(dir) {
|
|
|
23939
25007
|
}
|
|
23940
25008
|
}
|
|
23941
25009
|
function readManifestEntry(packageDir) {
|
|
23942
|
-
const manifestPath =
|
|
25010
|
+
const manifestPath = join19(packageDir, "package.json");
|
|
23943
25011
|
if (entryKind(manifestPath) !== "file") {
|
|
23944
25012
|
return void 0;
|
|
23945
25013
|
}
|
|
23946
25014
|
try {
|
|
23947
|
-
const parsed = JSON.parse(
|
|
25015
|
+
const parsed = JSON.parse(readFileSync13(manifestPath, "utf8"));
|
|
23948
25016
|
if (typeof parsed !== "object" || parsed === null) {
|
|
23949
25017
|
return void 0;
|
|
23950
25018
|
}
|
|
@@ -23964,7 +25032,7 @@ function resolvePackageEntry(packageDir) {
|
|
|
23964
25032
|
}
|
|
23965
25033
|
for (const base of INDEX_BASENAMES) {
|
|
23966
25034
|
for (const ext of ENTRY_EXTENSIONS) {
|
|
23967
|
-
const candidate =
|
|
25035
|
+
const candidate = join19(packageDir, `${base}${ext}`);
|
|
23968
25036
|
if (entryKind(candidate) === "file") {
|
|
23969
25037
|
return candidate;
|
|
23970
25038
|
}
|
|
@@ -23976,13 +25044,13 @@ function resolveTopLevelEntry(dir, name) {
|
|
|
23976
25044
|
if (isHidden(name)) {
|
|
23977
25045
|
return void 0;
|
|
23978
25046
|
}
|
|
23979
|
-
const
|
|
23980
|
-
const kind = entryKind(
|
|
25047
|
+
const path4 = join19(dir, name);
|
|
25048
|
+
const kind = entryKind(path4);
|
|
23981
25049
|
if (kind === "file") {
|
|
23982
|
-
return hasEntryExtension(name) ?
|
|
25050
|
+
return hasEntryExtension(name) ? path4 : void 0;
|
|
23983
25051
|
}
|
|
23984
25052
|
if (kind === "directory") {
|
|
23985
|
-
return resolvePackageEntry(
|
|
25053
|
+
return resolvePackageEntry(path4);
|
|
23986
25054
|
}
|
|
23987
25055
|
return void 0;
|
|
23988
25056
|
}
|
|
@@ -23999,7 +25067,7 @@ function discoverAddons(dir) {
|
|
|
23999
25067
|
function deriveAddonId(entryPath) {
|
|
24000
25068
|
const file = basename6(entryPath);
|
|
24001
25069
|
const stem = file.slice(0, file.length - extname4(file).length);
|
|
24002
|
-
const label2 = INDEX_BASENAMES.includes(stem) ? basename6(
|
|
25070
|
+
const label2 = INDEX_BASENAMES.includes(stem) ? basename6(join19(entryPath, "..")) : stem;
|
|
24003
25071
|
return addonId(label2.length > 0 ? label2 : entryPath);
|
|
24004
25072
|
}
|
|
24005
25073
|
function addonsDirFor(workspace, dir = ADDONS_DIR) {
|
|
@@ -24016,12 +25084,12 @@ function discoverSources(discovery) {
|
|
|
24016
25084
|
}
|
|
24017
25085
|
const seen = /* @__PURE__ */ new Set();
|
|
24018
25086
|
const sources = [];
|
|
24019
|
-
for (const
|
|
24020
|
-
if (seen.has(
|
|
25087
|
+
for (const path4 of paths) {
|
|
25088
|
+
if (seen.has(path4)) {
|
|
24021
25089
|
continue;
|
|
24022
25090
|
}
|
|
24023
|
-
seen.add(
|
|
24024
|
-
sources.push({ id: deriveAddonId(
|
|
25091
|
+
seen.add(path4);
|
|
25092
|
+
sources.push({ id: deriveAddonId(path4), path: path4 });
|
|
24025
25093
|
}
|
|
24026
25094
|
return sources;
|
|
24027
25095
|
}
|
|
@@ -24764,8 +25832,8 @@ function concatAddonTools(deck, bundle) {
|
|
|
24764
25832
|
|
|
24765
25833
|
// src/boot/runners/memdir.ts
|
|
24766
25834
|
init_capability_deck();
|
|
24767
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as
|
|
24768
|
-
import { join as
|
|
25835
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "node:fs";
|
|
25836
|
+
import { join as join20 } from "node:path";
|
|
24769
25837
|
var MEMORY_ENTRYPOINT = "MEMORY.md";
|
|
24770
25838
|
var MAX_ENTRYPOINT_LINES = 200;
|
|
24771
25839
|
var MAX_ENTRYPOINT_BYTES = 25e3;
|
|
@@ -24791,19 +25859,19 @@ function truncateEntrypointContent(raw) {
|
|
|
24791
25859
|
}
|
|
24792
25860
|
function memoryDirFor(workspace, cwd) {
|
|
24793
25861
|
const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
24794
|
-
return
|
|
25862
|
+
return join20(workspace.profileDir, "memory", `--${slug}--`);
|
|
24795
25863
|
}
|
|
24796
25864
|
var DiskMemoryStore = class {
|
|
24797
25865
|
constructor(memDir) {
|
|
24798
25866
|
this.memDir = memDir;
|
|
24799
|
-
this.file =
|
|
25867
|
+
this.file = join20(memDir, MEMORY_ENTRYPOINT);
|
|
24800
25868
|
}
|
|
24801
25869
|
memDir;
|
|
24802
25870
|
file;
|
|
24803
25871
|
/** The current note, or `""` when no file has been written yet. */
|
|
24804
25872
|
read() {
|
|
24805
25873
|
try {
|
|
24806
|
-
return existsSync5(this.file) ?
|
|
25874
|
+
return existsSync5(this.file) ? readFileSync14(this.file, "utf8") : "";
|
|
24807
25875
|
} catch {
|
|
24808
25876
|
return "";
|
|
24809
25877
|
}
|
|
@@ -24824,9 +25892,9 @@ ${line}`;
|
|
|
24824
25892
|
function loadMemoryDoc(memDir) {
|
|
24825
25893
|
let raw;
|
|
24826
25894
|
try {
|
|
24827
|
-
const file =
|
|
25895
|
+
const file = join20(memDir, MEMORY_ENTRYPOINT);
|
|
24828
25896
|
if (!existsSync5(file)) return void 0;
|
|
24829
|
-
raw =
|
|
25897
|
+
raw = readFileSync14(file, "utf8");
|
|
24830
25898
|
} catch {
|
|
24831
25899
|
return void 0;
|
|
24832
25900
|
}
|
|
@@ -24838,11 +25906,13 @@ function loadMemoryDoc(memDir) {
|
|
|
24838
25906
|
// src/boot/runners/session.ts
|
|
24839
25907
|
init_briefing();
|
|
24840
25908
|
init_window_budget();
|
|
25909
|
+
init_server_token();
|
|
25910
|
+
init_server_mode();
|
|
24841
25911
|
function authenticatedProviders(ctx) {
|
|
24842
25912
|
try {
|
|
24843
|
-
const
|
|
24844
|
-
if (!existsSync6(
|
|
24845
|
-
const data = JSON.parse(
|
|
25913
|
+
const path4 = ctx.workspace.authPath;
|
|
25914
|
+
if (!existsSync6(path4)) return [];
|
|
25915
|
+
const data = JSON.parse(readFileSync15(path4, "utf8"));
|
|
24846
25916
|
return Object.keys(data).filter((id) => {
|
|
24847
25917
|
const accounts = data[id];
|
|
24848
25918
|
return id.length > 0 && accounts !== null && typeof accounts === "object" && Object.keys(accounts).length > 0;
|
|
@@ -24859,8 +25929,18 @@ var PREFERRED_DEFAULT = {
|
|
|
24859
25929
|
"claude-sonnet-4-0",
|
|
24860
25930
|
"claude-opus-4-5"
|
|
24861
25931
|
],
|
|
24862
|
-
openai: ["gpt-5.1", "gpt-4.1", "gpt-4o"]
|
|
25932
|
+
openai: ["gpt-5.1", "gpt-4.1", "gpt-4o"],
|
|
25933
|
+
minimax: ["MiniMax-M3", "MiniMax-M2.7", "MiniMax-M2.5"],
|
|
25934
|
+
sarvam: ["sarvam-105b", "sarvam-30b"]
|
|
24863
25935
|
};
|
|
25936
|
+
function hasServerSessionSync() {
|
|
25937
|
+
try {
|
|
25938
|
+
const token = JSON.parse(readFileSync15(TOKEN_FILE, "utf8"));
|
|
25939
|
+
return typeof token.expires_at === "string" && new Date(token.expires_at).getTime() - Date.now() > 5 * 60 * 1e3;
|
|
25940
|
+
} catch {
|
|
25941
|
+
return false;
|
|
25942
|
+
}
|
|
25943
|
+
}
|
|
24864
25944
|
function providerDefaultModel(catalog, provider) {
|
|
24865
25945
|
const cards = catalog.byProvider(provider);
|
|
24866
25946
|
if (cards.length === 0) return void 0;
|
|
@@ -24880,6 +25960,12 @@ function resolveModelId(ctx) {
|
|
|
24880
25960
|
const id = providerDefaultModel(catalog, provider);
|
|
24881
25961
|
if (id !== void 0) return id;
|
|
24882
25962
|
}
|
|
25963
|
+
if (hasServerSessionSync()) {
|
|
25964
|
+
for (const provider of serverTierProviders()) {
|
|
25965
|
+
const id = providerDefaultModel(catalog, provider);
|
|
25966
|
+
if (id !== void 0) return id;
|
|
25967
|
+
}
|
|
25968
|
+
}
|
|
24883
25969
|
const card = new ModelMatcher(catalog).resolve({});
|
|
24884
25970
|
return card?.id ?? "";
|
|
24885
25971
|
}
|
|
@@ -24904,9 +25990,9 @@ var PROVIDER_ENV = {
|
|
|
24904
25990
|
};
|
|
24905
25991
|
function primeProviderEnv(ctx) {
|
|
24906
25992
|
try {
|
|
24907
|
-
const
|
|
24908
|
-
if (!existsSync6(
|
|
24909
|
-
const data = JSON.parse(
|
|
25993
|
+
const path4 = ctx.workspace.authPath;
|
|
25994
|
+
if (!existsSync6(path4)) return;
|
|
25995
|
+
const data = JSON.parse(readFileSync15(path4, "utf8"));
|
|
24910
25996
|
for (const [provider, accounts] of Object.entries(data)) {
|
|
24911
25997
|
if (provider.startsWith("_") || accounts === null || typeof accounts !== "object") continue;
|
|
24912
25998
|
const envVar = PROVIDER_ENV[provider];
|
|
@@ -24921,7 +26007,7 @@ function primeProviderEnv(ctx) {
|
|
|
24921
26007
|
} catch {
|
|
24922
26008
|
}
|
|
24923
26009
|
}
|
|
24924
|
-
function buildKeyResolver(vault, requestedAccount) {
|
|
26010
|
+
function buildKeyResolver(ctx, vault, requestedAccount) {
|
|
24925
26011
|
return async (provider) => {
|
|
24926
26012
|
try {
|
|
24927
26013
|
const candidates = [
|
|
@@ -24934,6 +26020,8 @@ function buildKeyResolver(vault, requestedAccount) {
|
|
|
24934
26020
|
const key = await vault.readUsableKey(provider, account);
|
|
24935
26021
|
if (key) return key;
|
|
24936
26022
|
}
|
|
26023
|
+
const server = await resolveServerMode(ctx, provider, vault);
|
|
26024
|
+
if (server.serverMode && server.token) return server.token;
|
|
24937
26025
|
return void 0;
|
|
24938
26026
|
} catch {
|
|
24939
26027
|
return void 0;
|
|
@@ -24946,7 +26034,7 @@ function resolveThinkingLevel(raw) {
|
|
|
24946
26034
|
}
|
|
24947
26035
|
function resolveText(value) {
|
|
24948
26036
|
try {
|
|
24949
|
-
if (existsSync6(value)) return
|
|
26037
|
+
if (existsSync6(value)) return readFileSync15(value, "utf8");
|
|
24950
26038
|
} catch {
|
|
24951
26039
|
}
|
|
24952
26040
|
return value;
|
|
@@ -24954,8 +26042,8 @@ function resolveText(value) {
|
|
|
24954
26042
|
var PROFILE_DIR2 = ".indusagi";
|
|
24955
26043
|
function skillRoots2(cwd) {
|
|
24956
26044
|
return [
|
|
24957
|
-
{ dir:
|
|
24958
|
-
{ dir:
|
|
26045
|
+
{ dir: join21(cwd, PROFILE_DIR2, "skills"), origin: "project" },
|
|
26046
|
+
{ dir: join21(homedir8(), PROFILE_DIR2, "skills"), origin: "user" }
|
|
24959
26047
|
];
|
|
24960
26048
|
}
|
|
24961
26049
|
function gatherModelSkills(cwd) {
|
|
@@ -24987,7 +26075,7 @@ function selectTools(cwd, inv, runner, memoryStore, checkpoint, workflowRunner)
|
|
|
24987
26075
|
}
|
|
24988
26076
|
function composeSystem(tools, inv, cwd, skills = [], memoryDoc) {
|
|
24989
26077
|
const contextDocs = [
|
|
24990
|
-
...gatherContextDocs(cwd,
|
|
26078
|
+
...gatherContextDocs(cwd, homedir8()),
|
|
24991
26079
|
...memoryDoc ? [memoryDoc] : []
|
|
24992
26080
|
];
|
|
24993
26081
|
const base = inv.system !== void 0 ? resolveText(inv.system) : composeBriefing({ tools, contextDocs, skills });
|
|
@@ -25005,9 +26093,9 @@ async function loadMcpTools(inv, cwd) {
|
|
|
25005
26093
|
console.error = () => {
|
|
25006
26094
|
};
|
|
25007
26095
|
try {
|
|
25008
|
-
for (const
|
|
26096
|
+
for (const path4 of paths) {
|
|
25009
26097
|
try {
|
|
25010
|
-
const servers = loadMCPConfig2(
|
|
26098
|
+
const servers = loadMCPConfig2(path4);
|
|
25011
26099
|
if (servers.length === 0) continue;
|
|
25012
26100
|
const pool = new MCPClientPool2({ servers });
|
|
25013
26101
|
await pool.connectAll();
|
|
@@ -25026,7 +26114,7 @@ async function loadMcpTools(inv, cwd) {
|
|
|
25026
26114
|
}
|
|
25027
26115
|
function sessionScopeDir(sessionsRoot, cwd) {
|
|
25028
26116
|
const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
25029
|
-
return
|
|
26117
|
+
return join21(sessionsRoot, `--${slug}--`);
|
|
25030
26118
|
}
|
|
25031
26119
|
function lastUserTurnStart(messages) {
|
|
25032
26120
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -25036,7 +26124,11 @@ function lastUserTurnStart(messages) {
|
|
|
25036
26124
|
}
|
|
25037
26125
|
var condenseTranscript = async (messages, opts) => {
|
|
25038
26126
|
const model = opts?.model;
|
|
25039
|
-
const deps = model ? {
|
|
26127
|
+
const deps = model ? {
|
|
26128
|
+
model,
|
|
26129
|
+
...opts?.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
|
|
26130
|
+
...opts?.signal !== void 0 ? { signal: opts.signal } : {}
|
|
26131
|
+
} : {};
|
|
25040
26132
|
const cleared = clearStaleToolResults(messages);
|
|
25041
26133
|
if (opts?.force) {
|
|
25042
26134
|
const cut = lastUserTurnStart(cleared);
|
|
@@ -25084,10 +26176,8 @@ function readOnlyNamesFromDeck(tools) {
|
|
|
25084
26176
|
}
|
|
25085
26177
|
return names;
|
|
25086
26178
|
}
|
|
25087
|
-
function buildPermissionGate(
|
|
25088
|
-
|
|
25089
|
-
const mode = resolveDefaultMode(store);
|
|
25090
|
-
if (rules.length === 0 && (mode === "default" || mode === "bypass") && !planReachable) {
|
|
26179
|
+
function buildPermissionGate(rules, mode, tools, planReachable = false) {
|
|
26180
|
+
if (rules.length === 0 && mode === "bypass" && !planReachable) {
|
|
25091
26181
|
return void 0;
|
|
25092
26182
|
}
|
|
25093
26183
|
const readOnlyToolNames = readOnlyNamesFromDeck(tools);
|
|
@@ -25097,9 +26187,17 @@ function buildPermissionGate(store, tools, planReachable = false) {
|
|
|
25097
26187
|
// The conductor's stable approval delegate: denies until the interactive
|
|
25098
26188
|
// console installs a resolver via setApprovalResolver, then routes `ask`.
|
|
25099
26189
|
...requestApproval !== void 0 ? { requestApproval } : {},
|
|
26190
|
+
// Session-scoped memory for `allow-always`: push into the SAME live array
|
|
26191
|
+
// the gate (and the sub-agent gates) re-scan per call. Never persisted.
|
|
26192
|
+
appendAllowRule: (rule) => rules.push(rule),
|
|
25100
26193
|
readOnlyToolNames
|
|
25101
26194
|
});
|
|
25102
26195
|
}
|
|
26196
|
+
function resolveOpeningMode(inv, store) {
|
|
26197
|
+
const raw = inv.flags["permission-mode"];
|
|
26198
|
+
if (typeof raw === "string" && isPermissionMode(raw)) return raw;
|
|
26199
|
+
return resolveDefaultMode(store);
|
|
26200
|
+
}
|
|
25103
26201
|
async function buildSessionConductor(ctx) {
|
|
25104
26202
|
primeProviderEnv(ctx);
|
|
25105
26203
|
const inv = ctx.invocation;
|
|
@@ -25110,12 +26208,35 @@ async function buildSessionConductor(ctx) {
|
|
|
25110
26208
|
const memDir = memoryDirFor(ctx.workspace, cwd);
|
|
25111
26209
|
const memoryStore = new DiskMemoryStore(memDir);
|
|
25112
26210
|
const memoryDoc = loadMemoryDoc(memDir);
|
|
25113
|
-
const
|
|
26211
|
+
const vault = createAuthVault(ctx.workspace.authPath);
|
|
26212
|
+
const getApiKey = buildKeyResolver(ctx, vault, inv.account);
|
|
26213
|
+
const gatewayBaseUrls = await resolveServerGatewayUrls(ctx, vault);
|
|
26214
|
+
const settings = PreferenceStore.fromWorkspace(ctx.workspace, cwd);
|
|
26215
|
+
const permissionRules = gatherPermissionRules(settings);
|
|
26216
|
+
const permissionMode = resolveOpeningMode(inv, settings);
|
|
26217
|
+
let liveConductor;
|
|
26218
|
+
const subagentPolicy = {
|
|
26219
|
+
rules: permissionRules,
|
|
26220
|
+
mode: () => liveConductor?.permissionMode() ?? permissionMode
|
|
26221
|
+
};
|
|
25114
26222
|
const surveyBriefing = composeBriefing({
|
|
25115
26223
|
tools: provisionDeck("authoring", { cwd }).tools()
|
|
25116
26224
|
});
|
|
25117
|
-
const runner = createDelegateRunner({
|
|
25118
|
-
|
|
26225
|
+
const runner = createDelegateRunner({
|
|
26226
|
+
modelId,
|
|
26227
|
+
getApiKey,
|
|
26228
|
+
system: surveyBriefing,
|
|
26229
|
+
cwd,
|
|
26230
|
+
getGatewayBaseUrls: () => resolveServerGatewayUrls(ctx, vault),
|
|
26231
|
+
permissionPolicy: subagentPolicy
|
|
26232
|
+
});
|
|
26233
|
+
const workflowRunner = createWorkflowAgentRunner({
|
|
26234
|
+
modelId,
|
|
26235
|
+
getApiKey,
|
|
26236
|
+
cwd,
|
|
26237
|
+
getGatewayBaseUrls: () => resolveServerGatewayUrls(ctx, vault),
|
|
26238
|
+
permissionPolicy: subagentPolicy
|
|
26239
|
+
});
|
|
25119
26240
|
const addons = await buildAddonHost(ctx);
|
|
25120
26241
|
const checkpoint = createCheckpointStore();
|
|
25121
26242
|
const deck = [
|
|
@@ -25127,11 +26248,9 @@ async function buildSessionConductor(ctx) {
|
|
|
25127
26248
|
const system = composeSystem(tools, inv, cwd, skills, memoryDoc);
|
|
25128
26249
|
const thinking = resolveThinkingLevel(inv.thinking);
|
|
25129
26250
|
const fallbackModelId = inv.fallbackModelId;
|
|
25130
|
-
const settings = PreferenceStore.fromWorkspace(ctx.workspace, cwd);
|
|
25131
|
-
const permissionMode = resolveDefaultMode(settings);
|
|
25132
26251
|
const planReachable = inv.mode === "repl";
|
|
25133
|
-
const canUseTool = buildPermissionGate(
|
|
25134
|
-
|
|
26252
|
+
const canUseTool = buildPermissionGate(permissionRules, permissionMode, tools, planReachable);
|
|
26253
|
+
const conductor = createSessionConductor(
|
|
25135
26254
|
{
|
|
25136
26255
|
modelId,
|
|
25137
26256
|
tools,
|
|
@@ -25149,12 +26268,19 @@ async function buildSessionConductor(ctx) {
|
|
|
25149
26268
|
...canUseTool !== void 0 ? { canUseTool } : {},
|
|
25150
26269
|
...thinking !== void 0 ? { thinking } : {},
|
|
25151
26270
|
...workspace ? { workspace } : {},
|
|
25152
|
-
...fallbackModelId !== void 0 ? { fallbackModelId } : {}
|
|
26271
|
+
...fallbackModelId !== void 0 ? { fallbackModelId } : {},
|
|
26272
|
+
// When server mode is active for the bound model's provider, hand the
|
|
26273
|
+
// conductor the gateway base url. A4 (`conductor.ts`) clones `card.model`
|
|
26274
|
+
// with this `baseUrl` so the existing model card routes through the indus
|
|
26275
|
+
// gateway; absent (the local-key path) the conductor binds the card as-is.
|
|
26276
|
+
...Object.keys(gatewayBaseUrls).length > 0 ? { gatewayBaseUrls } : {}
|
|
25153
26277
|
},
|
|
25154
26278
|
// The live condense hook: `/compact` and auto-compaction fold older turns
|
|
25155
26279
|
// into a digest. (Tests that build conductors directly keep the no-op default.)
|
|
25156
26280
|
{ condense: condenseTranscript }
|
|
25157
26281
|
);
|
|
26282
|
+
liveConductor = conductor;
|
|
26283
|
+
return conductor;
|
|
25158
26284
|
}
|
|
25159
26285
|
function oneshotPrompts(ctx) {
|
|
25160
26286
|
const prompts = [];
|
|
@@ -25166,9 +26292,10 @@ function oneshotPrompts(ctx) {
|
|
|
25166
26292
|
}
|
|
25167
26293
|
|
|
25168
26294
|
// src/boot/runners/repl-runner.ts
|
|
25169
|
-
var
|
|
26295
|
+
var EXIT_OK2 = 0;
|
|
25170
26296
|
function buildOverlayServices(ctx, conductor) {
|
|
25171
26297
|
const cwd = ctx.invocation.cwd ?? process.cwd();
|
|
26298
|
+
const vault = createAuthVault(ctx.workspace.authPath);
|
|
25172
26299
|
return {
|
|
25173
26300
|
conductor,
|
|
25174
26301
|
settings: PreferenceStore.fromWorkspace(ctx.workspace, cwd),
|
|
@@ -25178,7 +26305,11 @@ function buildOverlayServices(ctx, conductor) {
|
|
|
25178
26305
|
listLoginProviders,
|
|
25179
26306
|
startOAuthLogin,
|
|
25180
26307
|
openLoginUrl,
|
|
25181
|
-
vault
|
|
26308
|
+
vault,
|
|
26309
|
+
async refreshGatewayRouting() {
|
|
26310
|
+
const map = await resolveServerGatewayUrls(ctx, vault);
|
|
26311
|
+
conductor.updateGatewayBaseUrls(map);
|
|
26312
|
+
}
|
|
25182
26313
|
};
|
|
25183
26314
|
}
|
|
25184
26315
|
function toResumeRef(row) {
|
|
@@ -25255,7 +26386,7 @@ var replRunner = {
|
|
|
25255
26386
|
conductor,
|
|
25256
26387
|
initialInput === void 0 ? { services } : { initialInput, services }
|
|
25257
26388
|
);
|
|
25258
|
-
return
|
|
26389
|
+
return EXIT_OK2;
|
|
25259
26390
|
}
|
|
25260
26391
|
};
|
|
25261
26392
|
|
|
@@ -25401,10 +26532,10 @@ var inertDialog = Object.freeze({
|
|
|
25401
26532
|
tell(_kind, _payload) {
|
|
25402
26533
|
}
|
|
25403
26534
|
});
|
|
25404
|
-
var
|
|
26535
|
+
var EXIT_OK3 = 0;
|
|
25405
26536
|
var EXIT_FAULT = 1;
|
|
25406
26537
|
function exitCodeFor(state) {
|
|
25407
|
-
return state.phase === "faulted" ? EXIT_FAULT :
|
|
26538
|
+
return state.phase === "faulted" ? EXIT_FAULT : EXIT_OK3;
|
|
25408
26539
|
}
|
|
25409
26540
|
function textStrategy() {
|
|
25410
26541
|
let answer = "";
|
|
@@ -25813,7 +26944,7 @@ var oneshotRunner = {
|
|
|
25813
26944
|
};
|
|
25814
26945
|
|
|
25815
26946
|
// src/boot/runners/link-runner.ts
|
|
25816
|
-
var
|
|
26947
|
+
var EXIT_OK4 = 0;
|
|
25817
26948
|
var STDOUT2 = {
|
|
25818
26949
|
write(chunk, cb) {
|
|
25819
26950
|
return process.stdout.write(chunk, cb);
|
|
@@ -25831,7 +26962,7 @@ var linkRunner = {
|
|
|
25831
26962
|
out: STDOUT2
|
|
25832
26963
|
});
|
|
25833
26964
|
await server.done;
|
|
25834
|
-
return
|
|
26965
|
+
return EXIT_OK4;
|
|
25835
26966
|
}
|
|
25836
26967
|
};
|
|
25837
26968
|
|
|
@@ -25847,8 +26978,8 @@ function selectRunner(inv) {
|
|
|
25847
26978
|
}
|
|
25848
26979
|
|
|
25849
26980
|
// src/boot/boot.ts
|
|
25850
|
-
var
|
|
25851
|
-
var
|
|
26981
|
+
var EXIT_OK5 = 0;
|
|
26982
|
+
var EXIT_FAILURE2 = 1;
|
|
25852
26983
|
function seedContext(argv) {
|
|
25853
26984
|
const workspace = createWorkspace();
|
|
25854
26985
|
const invocation = tokenizeInvocation(argv);
|
|
@@ -25890,7 +27021,7 @@ async function runCredential(ctx) {
|
|
|
25890
27021
|
`);
|
|
25891
27022
|
return EXIT_CREDENTIAL_FAULT;
|
|
25892
27023
|
}
|
|
25893
|
-
return
|
|
27024
|
+
return EXIT_OK5;
|
|
25894
27025
|
}
|
|
25895
27026
|
async function runPackage(ctx) {
|
|
25896
27027
|
const result = await runPackageCommand(ctx.argv, {
|
|
@@ -25899,7 +27030,7 @@ async function runPackage(ctx) {
|
|
|
25899
27030
|
if (!result.handled) {
|
|
25900
27031
|
return void 0;
|
|
25901
27032
|
}
|
|
25902
|
-
return result.code ??
|
|
27033
|
+
return result.code ?? EXIT_OK5;
|
|
25903
27034
|
}
|
|
25904
27035
|
async function boot(argv) {
|
|
25905
27036
|
const seeded = seedContext(argv);
|
|
@@ -25907,22 +27038,26 @@ async function boot(argv) {
|
|
|
25907
27038
|
if (credential !== void 0) {
|
|
25908
27039
|
return credential;
|
|
25909
27040
|
}
|
|
27041
|
+
const login = await runLogin(seeded);
|
|
27042
|
+
if (login !== void 0) {
|
|
27043
|
+
return login;
|
|
27044
|
+
}
|
|
25910
27045
|
const pkg = await runPackage(seeded);
|
|
25911
27046
|
if (pkg !== void 0) {
|
|
25912
27047
|
return pkg;
|
|
25913
27048
|
}
|
|
25914
27049
|
if (wantsHelp(seeded.invocation)) {
|
|
25915
27050
|
renderHelp();
|
|
25916
|
-
return
|
|
27051
|
+
return EXIT_OK5;
|
|
25917
27052
|
}
|
|
25918
27053
|
if (wantsVersion(seeded.invocation)) {
|
|
25919
27054
|
renderVersion();
|
|
25920
|
-
return
|
|
27055
|
+
return EXIT_OK5;
|
|
25921
27056
|
}
|
|
25922
27057
|
if (seeded.invocation.listModels) {
|
|
25923
27058
|
const filter = seeded.invocation.listModelsFilter;
|
|
25924
27059
|
printModelCatalog(void 0, filter !== void 0 ? { search: filter } : {});
|
|
25925
|
-
return
|
|
27060
|
+
return EXIT_OK5;
|
|
25926
27061
|
}
|
|
25927
27062
|
const ctx = await runStages(seeded);
|
|
25928
27063
|
try {
|
|
@@ -25932,7 +27067,7 @@ async function boot(argv) {
|
|
|
25932
27067
|
const message = error instanceof Error ? error.message : String(error);
|
|
25933
27068
|
process.stderr.write(`${BRAND.name}: ${message}
|
|
25934
27069
|
`);
|
|
25935
|
-
return
|
|
27070
|
+
return EXIT_FAILURE2;
|
|
25936
27071
|
} finally {
|
|
25937
27072
|
await drainClosables(ctx);
|
|
25938
27073
|
}
|
|
@@ -27135,14 +28270,14 @@ function keyMatches(rule, key) {
|
|
|
27135
28270
|
return matcher.test(key);
|
|
27136
28271
|
}
|
|
27137
28272
|
function applyValueRules(rules, text) {
|
|
27138
|
-
let
|
|
28273
|
+
let out2 = text;
|
|
27139
28274
|
for (const rule of rules) {
|
|
27140
28275
|
const pattern = rule.value;
|
|
27141
28276
|
if (pattern === void 0) continue;
|
|
27142
28277
|
if (pattern.global || pattern.sticky) pattern.lastIndex = 0;
|
|
27143
|
-
|
|
28278
|
+
out2 = out2.replace(pattern, REDACTED_TOKEN);
|
|
27144
28279
|
}
|
|
27145
|
-
return
|
|
28280
|
+
return out2;
|
|
27146
28281
|
}
|
|
27147
28282
|
function createRedactor(rules = DEFAULT_REDACTION_RULES, options = {}) {
|
|
27148
28283
|
const frozenRules = Object.freeze([...rules]);
|
|
@@ -27174,12 +28309,12 @@ function createRedactor(rules = DEFAULT_REDACTION_RULES, options = {}) {
|
|
|
27174
28309
|
return Object.freeze(value.map((item) => scrubNode(item, void 0)));
|
|
27175
28310
|
}
|
|
27176
28311
|
if (value !== null && typeof value === "object") {
|
|
27177
|
-
const
|
|
28312
|
+
const out2 = {};
|
|
27178
28313
|
for (const [k, v] of Object.entries(value)) {
|
|
27179
28314
|
if (isOmitted(k)) continue;
|
|
27180
|
-
|
|
28315
|
+
out2[k] = scrubNode(v, k);
|
|
27181
28316
|
}
|
|
27182
|
-
return Object.freeze(
|
|
28317
|
+
return Object.freeze(out2);
|
|
27183
28318
|
}
|
|
27184
28319
|
return value;
|
|
27185
28320
|
}
|
|
@@ -27187,12 +28322,12 @@ function createRedactor(rules = DEFAULT_REDACTION_RULES, options = {}) {
|
|
|
27187
28322
|
return scrubNode(value, void 0);
|
|
27188
28323
|
}
|
|
27189
28324
|
function scrubAttributes(attributes) {
|
|
27190
|
-
const
|
|
28325
|
+
const out2 = {};
|
|
27191
28326
|
for (const [k, v] of Object.entries(attributes)) {
|
|
27192
28327
|
if (isOmitted(k)) continue;
|
|
27193
|
-
|
|
28328
|
+
out2[k] = scrubNode(v, k);
|
|
27194
28329
|
}
|
|
27195
|
-
return Object.freeze(
|
|
28330
|
+
return Object.freeze(out2);
|
|
27196
28331
|
}
|
|
27197
28332
|
function scrubFault(fault) {
|
|
27198
28333
|
const scrubbed = {
|
|
@@ -27297,7 +28432,7 @@ function createConsoleSink(options = {}) {
|
|
|
27297
28432
|
}
|
|
27298
28433
|
|
|
27299
28434
|
// src/insight/sinks/file.ts
|
|
27300
|
-
import { open, mkdir as
|
|
28435
|
+
import { open, mkdir as mkdir3 } from "node:fs/promises";
|
|
27301
28436
|
import { dirname as dirname8 } from "node:path";
|
|
27302
28437
|
function createFileSink(options) {
|
|
27303
28438
|
const id = options.id ?? "file";
|
|
@@ -27310,7 +28445,7 @@ function createFileSink(options) {
|
|
|
27310
28445
|
for await (const signal of stream) {
|
|
27311
28446
|
if (handle === null) {
|
|
27312
28447
|
if (options.mkdirp ?? true) {
|
|
27313
|
-
await
|
|
28448
|
+
await mkdir3(dirname8(options.path), { recursive: true });
|
|
27314
28449
|
}
|
|
27315
28450
|
handle = await open(options.path, mode);
|
|
27316
28451
|
}
|