indusagi-coding-agent 0.2.12 → 0.2.14
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/.env.review.example +25 -0
- package/README.md +30 -0
- package/REVIEW_AGENT.md +137 -0
- package/dist/entry.js +1861 -979
- package/dist/guardrails.js +212 -36
- package/dist/index.js +2829 -1057
- package/dist/review-agent.js +4461 -0
- package/dist/review-server.js +4633 -0
- package/package.json +24 -7
- package/src/boot/auth-vault.ts +4 -5
- package/src/boot/contract.ts +1 -1
- package/src/boot/runners/addon-wiring.ts +111 -3
- package/src/boot/runners/benchmark-integrity.ts +107 -0
- package/src/boot/runners/repl-runner.ts +2 -1
- package/src/boot/runners/session.ts +26 -12
- package/src/boot/server-token.ts +20 -11
- package/src/boot/stages.ts +3 -6
- package/src/briefing/context-docs.ts +144 -12
- package/src/channels/oneshot.ts +6 -0
- package/src/conductor/catalog/catalog.ts +3 -1
- package/src/conductor/conductor.ts +77 -17
- package/src/conductor/contract.ts +9 -7
- package/src/conductor/index.ts +1 -1
- package/src/conductor/transcript-store/store.ts +4 -8
- package/src/console/auth-status.ts +9 -4
- package/src/console/components/AgentsView.ts +2 -2
- package/src/console/components/BackgroundAgents.ts +15 -2
- package/src/console/components/Banner.ts +20 -9
- package/src/console/components/Composer.ts +57 -82
- package/src/console/components/ScrollViewport.ts +46 -0
- package/src/console/components/TerminalConsole.ts +165 -162
- package/src/console/components/WorkingIndicator.ts +6 -5
- package/src/console/components/banner-sweep.ts +5 -1
- package/src/console/components/welcome.ts +3 -3
- package/src/console/contract.ts +10 -5
- package/src/console/index.ts +7 -7
- package/src/console/input/complete.ts +2 -2
- package/src/console/input/dir-reader.ts +3 -1
- package/src/console/input/graphemes.ts +22 -0
- package/src/console/input/keymap.ts +6 -4
- package/src/console/mount.ts +45 -3
- package/src/console/overlays/auth.ts +28 -8
- package/src/console/overlays/boards.ts +13 -40
- package/src/console/overlays/host.ts +10 -0
- package/src/console/overlays/pickers.ts +35 -30
- package/src/console/reducer.ts +12 -5
- package/src/console/slash/builtins.ts +4 -3
- package/src/console/slash/commands/integrations.ts +13 -14
- package/src/console/slash/commands/transcript.ts +3 -8
- package/src/console/slash/commands/workbench.ts +4 -4
- package/src/console/test-support.ts +48 -0
- package/src/index.ts +1 -0
- package/src/integrations/sarvam/config.ts +15 -13
- package/src/kit/external-editor.ts +17 -1
- package/src/kit/run-shell.ts +31 -0
- package/src/launch/catalog.ts +4 -2
- package/src/launch/contract.ts +1 -0
- package/src/launch/invocation/flags.ts +13 -1
- package/src/launch/invocation/read.ts +4 -3
- package/src/launch/login.ts +23 -10
- package/src/launch/oauth.ts +3 -0
- package/src/models.ts +166 -0
- package/src/review-agent/config.ts +75 -0
- package/src/review-agent/contract.ts +59 -0
- package/src/review-agent/github.ts +242 -0
- package/src/review-agent/index.ts +8 -0
- package/src/review-agent/prompt.ts +132 -0
- package/src/review-agent/reviewer.ts +118 -0
- package/src/review-agent/server.ts +221 -0
- package/src/review-agent/service.ts +165 -0
- package/src/review-agent/supabase.ts +209 -0
- package/src/review-agent/webhook.ts +76 -0
- package/src/security/private-state.ts +122 -0
- package/src/window-budget/summarize/condense.ts +4 -1
- package/src/workspace/brand.ts +1 -1
- package/src/workspace/locator.ts +2 -2
- package/supabase/migrations/20260827031803_indusagi_review_agent.sql +109 -0
- package/supabase/migrations/20260827035747_atomic_webhook_enqueue.sql +75 -0
- package/supabase/migrations/20260827040104_check_run_reconciliation.sql +8 -0
- package/supabase/migrations/20260827041049_owned_job_leases.sql +80 -0
- package/supabase/migrations/20260827042500_static_token_webhooks.sql +75 -0
package/dist/guardrails.js
CHANGED
|
@@ -812,49 +812,52 @@ function composeBriefing(input) {
|
|
|
812
812
|
}
|
|
813
813
|
|
|
814
814
|
// src/briefing/context-docs.ts
|
|
815
|
-
import {
|
|
816
|
-
import { dirname, extname, isAbsolute, join, parse, resolve } from "node:path";
|
|
815
|
+
import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, realpathSync } from "node:fs";
|
|
816
|
+
import { basename, dirname, extname, isAbsolute, join, parse, resolve, sep } from "node:path";
|
|
817
817
|
var DEFAULT_MAX_IMPORT_DEPTH = 5;
|
|
818
818
|
var DEFAULT_MAX_BYTES_PER_DOC = 4e4;
|
|
819
819
|
var CANDIDATE_FILES = ["AGENTS.md", "CLAUDE.md", "INDUSAGI.md", "CLAUDE.local.md", "AGENTS.local.md", join(".indusagi", "CLAUDE.md"), join(".claude", "CLAUDE.md")];
|
|
820
|
-
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown", ".txt", ".text", ".json", ".jsonc", ".yaml", ".yml", ".toml", ".xml", ".csv", ".html", ".htm", ".css", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".py", ".rb", ".go", ".rs", ".sh"
|
|
820
|
+
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown", ".txt", ".text", ".json", ".jsonc", ".yaml", ".yml", ".toml", ".xml", ".csv", ".html", ".htm", ".css", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".py", ".rb", ".go", ".rs", ".sh"]);
|
|
821
821
|
var IMPORT_REGEX = /(?:^|\s)@((?:[^\s\\]|\\ )+)/g;
|
|
822
|
+
var NO_FOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
823
|
+
var SECRET_BASENAMES = /* @__PURE__ */ new Set([
|
|
824
|
+
".env",
|
|
825
|
+
"credentials",
|
|
826
|
+
"credentials.json",
|
|
827
|
+
"id_rsa",
|
|
828
|
+
"id_dsa",
|
|
829
|
+
"id_ecdsa",
|
|
830
|
+
"id_ed25519"
|
|
831
|
+
]);
|
|
832
|
+
var SECRET_EXTENSIONS = /* @__PURE__ */ new Set([".key", ".pem", ".p12", ".pfx"]);
|
|
822
833
|
function shortenPath(path, cwd, home) {
|
|
823
|
-
if (cwd && path.startsWith(cwd)) {
|
|
834
|
+
if (cwd && (path === cwd || path.startsWith(`${cwd}${sep}`))) {
|
|
824
835
|
const rest = path.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
825
836
|
return rest ? `./${rest}` : ".";
|
|
826
837
|
}
|
|
827
|
-
return home && path.startsWith(home) ? `~${path.slice(home.length)}` : path;
|
|
828
|
-
}
|
|
829
|
-
function dirChain(cwd) {
|
|
830
|
-
const chain = [];
|
|
831
|
-
let current = cwd;
|
|
832
|
-
for (let i = 0; i < 256; i++) {
|
|
833
|
-
chain.push(current);
|
|
834
|
-
const parent = dirname(current);
|
|
835
|
-
if (parent === current || current === parse(current).root) break;
|
|
836
|
-
current = parent;
|
|
837
|
-
}
|
|
838
|
-
return chain.reverse();
|
|
839
|
-
}
|
|
840
|
-
function safeRealpath(path) {
|
|
841
|
-
try {
|
|
842
|
-
return realpathSync(path);
|
|
843
|
-
} catch {
|
|
844
|
-
return path;
|
|
845
|
-
}
|
|
838
|
+
return home && (path === home || path.startsWith(`${home}${sep}`)) ? `~${path.slice(home.length)}` : path;
|
|
846
839
|
}
|
|
847
840
|
function isTextFile(path) {
|
|
848
841
|
const extension = extname(path).toLowerCase();
|
|
849
842
|
return !extension || TEXT_FILE_EXTENSIONS.has(extension);
|
|
850
843
|
}
|
|
844
|
+
function isLikelySecretFile(path) {
|
|
845
|
+
const name = basename(path).toLowerCase();
|
|
846
|
+
return SECRET_BASENAMES.has(name) || name.startsWith(".env.") || SECRET_EXTENSIONS.has(extname(name));
|
|
847
|
+
}
|
|
851
848
|
function readFileBody(path) {
|
|
852
|
-
|
|
849
|
+
let fd;
|
|
853
850
|
try {
|
|
854
|
-
const
|
|
851
|
+
const before = lstatSync(path);
|
|
852
|
+
if (before.isSymbolicLink() || !before.isFile()) return null;
|
|
853
|
+
fd = openSync(path, constants.O_RDONLY | NO_FOLLOW);
|
|
854
|
+
if (!fstatSync(fd).isFile()) return null;
|
|
855
|
+
const body = readFileSync(fd, "utf8").trim();
|
|
855
856
|
return body || null;
|
|
856
857
|
} catch {
|
|
857
858
|
return null;
|
|
859
|
+
} finally {
|
|
860
|
+
if (fd !== void 0) closeSync(fd);
|
|
858
861
|
}
|
|
859
862
|
}
|
|
860
863
|
function extractImports(body, baseDir, home) {
|
|
@@ -873,23 +876,46 @@ function extractImports(body, baseDir, home) {
|
|
|
873
876
|
}
|
|
874
877
|
return out;
|
|
875
878
|
}
|
|
876
|
-
function
|
|
877
|
-
|
|
878
|
-
|
|
879
|
+
function canonicalExistingFile(path) {
|
|
880
|
+
try {
|
|
881
|
+
const before = lstatSync(path);
|
|
882
|
+
if (before.isSymbolicLink() || !before.isFile()) return null;
|
|
883
|
+
return realpathSync(path);
|
|
884
|
+
} catch {
|
|
885
|
+
return null;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function isWithin(root, candidate) {
|
|
889
|
+
return candidate === root || candidate.startsWith(`${root}${sep}`);
|
|
890
|
+
}
|
|
891
|
+
function loadTrustedDocTree(path, cwd, home, seen, depth, maxDepth, maxBytes, out, policy) {
|
|
892
|
+
if (isLikelySecretFile(path)) return;
|
|
893
|
+
const real = canonicalExistingFile(path);
|
|
894
|
+
if (real === null || seen.has(real) || isLikelySecretFile(real)) return;
|
|
895
|
+
if (!isWithin(policy.root, real) && !policy.approvedExternal.has(real)) return;
|
|
879
896
|
seen.add(real);
|
|
880
|
-
const body = readFileBody(
|
|
897
|
+
const body = readFileBody(real);
|
|
881
898
|
if (body === null) return;
|
|
882
|
-
out.push({ path: shortenPath(
|
|
899
|
+
out.push({ path: shortenPath(real, cwd, home), body: body.length > maxBytes ? body.slice(0, maxBytes) : body });
|
|
883
900
|
if (depth >= maxDepth) return;
|
|
884
|
-
for (const child of extractImports(body, dirname(
|
|
901
|
+
for (const child of extractImports(body, dirname(real), home)) {
|
|
902
|
+
loadTrustedDocTree(child, cwd, home, seen, depth + 1, maxDepth, maxBytes, out, policy);
|
|
903
|
+
}
|
|
885
904
|
}
|
|
886
|
-
function gatherContextDocs(cwd, home, opts) {
|
|
905
|
+
function gatherContextDocs(cwd, home, opts = {}) {
|
|
887
906
|
const out = [];
|
|
888
907
|
try {
|
|
908
|
+
const root = realpathSync(cwd);
|
|
909
|
+
const approvedExternal = /* @__PURE__ */ new Set();
|
|
910
|
+
for (const path of opts.approvedExternalPaths ?? []) {
|
|
911
|
+
const real = canonicalExistingFile(path);
|
|
912
|
+
if (real !== null && !isLikelySecretFile(real)) approvedExternal.add(real);
|
|
913
|
+
}
|
|
914
|
+
const policy = { root, approvedExternal };
|
|
889
915
|
const seen = /* @__PURE__ */ new Set();
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
|
|
916
|
+
for (const name of CANDIDATE_FILES) {
|
|
917
|
+
loadTrustedDocTree(join(root, name), root, home, seen, 0, opts.maxImportDepth ?? DEFAULT_MAX_IMPORT_DEPTH, opts.maxBytesPerDoc ?? DEFAULT_MAX_BYTES_PER_DOC, out, policy);
|
|
918
|
+
}
|
|
893
919
|
} catch {
|
|
894
920
|
return out;
|
|
895
921
|
}
|
|
@@ -1996,7 +2022,139 @@ import { createZeroUsage as createZeroUsage2 } from "indusagi/ai";
|
|
|
1996
2022
|
|
|
1997
2023
|
// src/conductor/catalog/catalog.ts
|
|
1998
2024
|
import { z } from "zod";
|
|
1999
|
-
import { getModels, getProviders } from "indusagi/ai";
|
|
2025
|
+
import { getModels, getProviders, modelRegistry } from "indusagi/ai";
|
|
2026
|
+
|
|
2027
|
+
// src/models.ts
|
|
2028
|
+
import { ModelRegistry } from "indusagi/ai";
|
|
2029
|
+
var GPT_6_ASTRA_BASE = {
|
|
2030
|
+
id: "gpt-6-astra",
|
|
2031
|
+
name: "GPT-6 Astra",
|
|
2032
|
+
api: "openai-responses",
|
|
2033
|
+
reasoning: true,
|
|
2034
|
+
reasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
|
|
2035
|
+
input: ["text", "image"],
|
|
2036
|
+
cost: {
|
|
2037
|
+
input: 10,
|
|
2038
|
+
cacheRead: 1,
|
|
2039
|
+
cacheWrite: 12.5,
|
|
2040
|
+
output: 50
|
|
2041
|
+
},
|
|
2042
|
+
contextWindow: 105e4,
|
|
2043
|
+
maxTokens: 128e3,
|
|
2044
|
+
longContextPricing: {
|
|
2045
|
+
threshold: 272e3,
|
|
2046
|
+
multipliers: {
|
|
2047
|
+
input: 2,
|
|
2048
|
+
cacheRead: 2,
|
|
2049
|
+
cacheWrite: 2,
|
|
2050
|
+
output: 1.5
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
};
|
|
2054
|
+
var GPT_6_SOL_BASE = {
|
|
2055
|
+
id: "gpt-6-sol",
|
|
2056
|
+
name: "GPT-6 Sol",
|
|
2057
|
+
api: "openai-responses",
|
|
2058
|
+
reasoning: true,
|
|
2059
|
+
reasoningEfforts: ["high"],
|
|
2060
|
+
input: ["text", "image"],
|
|
2061
|
+
cost: {
|
|
2062
|
+
input: 10,
|
|
2063
|
+
cacheRead: 1,
|
|
2064
|
+
cacheWrite: 12.5,
|
|
2065
|
+
output: 50
|
|
2066
|
+
},
|
|
2067
|
+
contextWindow: 105e4,
|
|
2068
|
+
maxTokens: 128e3,
|
|
2069
|
+
longContextPricing: {
|
|
2070
|
+
threshold: 272e3,
|
|
2071
|
+
multipliers: {
|
|
2072
|
+
input: 2,
|
|
2073
|
+
cacheRead: 2,
|
|
2074
|
+
cacheWrite: 2,
|
|
2075
|
+
output: 1.5
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2079
|
+
var GPT_6_LUNA_BASE = {
|
|
2080
|
+
id: "gpt-6-luna",
|
|
2081
|
+
name: "GPT-6 Luna",
|
|
2082
|
+
api: "openai-responses",
|
|
2083
|
+
reasoning: true,
|
|
2084
|
+
reasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
|
|
2085
|
+
input: ["text", "image"],
|
|
2086
|
+
cost: {
|
|
2087
|
+
input: 0.1,
|
|
2088
|
+
cacheRead: 0.01,
|
|
2089
|
+
cacheWrite: 0.125,
|
|
2090
|
+
output: 0.5
|
|
2091
|
+
},
|
|
2092
|
+
contextWindow: 105e4,
|
|
2093
|
+
maxTokens: 128e3,
|
|
2094
|
+
longContextPricing: {
|
|
2095
|
+
threshold: 272e3,
|
|
2096
|
+
multipliers: { input: 2, cacheRead: 2, cacheWrite: 2, output: 1.5 }
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
var CODING_AGENT_MODELS = [
|
|
2100
|
+
{
|
|
2101
|
+
...GPT_6_SOL_BASE,
|
|
2102
|
+
provider: "openai",
|
|
2103
|
+
baseUrl: "https://api.openai.com/v1"
|
|
2104
|
+
},
|
|
2105
|
+
{
|
|
2106
|
+
...GPT_6_SOL_BASE,
|
|
2107
|
+
api: "openai-codex-responses",
|
|
2108
|
+
provider: "openai-codex",
|
|
2109
|
+
baseUrl: "https://chatgpt.com/backend-api"
|
|
2110
|
+
},
|
|
2111
|
+
{
|
|
2112
|
+
...GPT_6_LUNA_BASE,
|
|
2113
|
+
provider: "openai",
|
|
2114
|
+
baseUrl: "https://api.openai.com/v1"
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
...GPT_6_LUNA_BASE,
|
|
2118
|
+
api: "openai-codex-responses",
|
|
2119
|
+
provider: "openai-codex",
|
|
2120
|
+
baseUrl: "https://chatgpt.com/backend-api"
|
|
2121
|
+
},
|
|
2122
|
+
{
|
|
2123
|
+
...GPT_6_ASTRA_BASE,
|
|
2124
|
+
provider: "openai",
|
|
2125
|
+
baseUrl: "https://api.openai.com/v1"
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
...GPT_6_ASTRA_BASE,
|
|
2129
|
+
api: "openai-codex-responses",
|
|
2130
|
+
provider: "openai-codex",
|
|
2131
|
+
baseUrl: "https://chatgpt.com/backend-api"
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
...GPT_6_ASTRA_BASE,
|
|
2135
|
+
provider: "codex-cli",
|
|
2136
|
+
baseUrl: "bridge:codex-cli"
|
|
2137
|
+
},
|
|
2138
|
+
{
|
|
2139
|
+
...GPT_6_ASTRA_BASE,
|
|
2140
|
+
id: "openai/gpt-6-astra",
|
|
2141
|
+
provider: "indusagi-cli",
|
|
2142
|
+
baseUrl: "bridge:indusagi-cli"
|
|
2143
|
+
},
|
|
2144
|
+
{
|
|
2145
|
+
...GPT_6_ASTRA_BASE,
|
|
2146
|
+
id: "openai-codex/gpt-6-astra",
|
|
2147
|
+
api: "openai-codex-responses",
|
|
2148
|
+
provider: "indusagi-cli",
|
|
2149
|
+
baseUrl: "bridge:indusagi-cli"
|
|
2150
|
+
}
|
|
2151
|
+
];
|
|
2152
|
+
function applyCodingAgentModelOverlay(registry) {
|
|
2153
|
+
for (const model of CODING_AGENT_MODELS) registry.registerCustomModel(model);
|
|
2154
|
+
return registry;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
// src/conductor/catalog/catalog.ts
|
|
2000
2158
|
var rawModelGate = z.object({
|
|
2001
2159
|
id: z.string().min(1),
|
|
2002
2160
|
name: z.string().min(1),
|
|
@@ -2005,6 +2163,7 @@ var rawModelGate = z.object({
|
|
|
2005
2163
|
input: z.array(z.string()).optional(),
|
|
2006
2164
|
contextWindow: z.number().optional()
|
|
2007
2165
|
});
|
|
2166
|
+
applyCodingAgentModelOverlay(modelRegistry);
|
|
2008
2167
|
|
|
2009
2168
|
// src/conductor/signal-hub/translate.ts
|
|
2010
2169
|
import { createZeroUsage } from "indusagi/ai";
|
|
@@ -2015,6 +2174,23 @@ import { ulid } from "ulid";
|
|
|
2015
2174
|
// src/conductor/transcript-store/serialize.ts
|
|
2016
2175
|
import { buildSessionContext, convertToLlm, loadEntriesFromFile, parseSessionEntries } from "indusagi/agent";
|
|
2017
2176
|
|
|
2177
|
+
// src/security/private-state.ts
|
|
2178
|
+
import {
|
|
2179
|
+
chmodSync,
|
|
2180
|
+
closeSync as closeSync2,
|
|
2181
|
+
constants as constants2,
|
|
2182
|
+
fchmodSync,
|
|
2183
|
+
fstatSync as fstatSync2,
|
|
2184
|
+
lstatSync as lstatSync2,
|
|
2185
|
+
mkdirSync as mkdirSync2,
|
|
2186
|
+
openSync as openSync2,
|
|
2187
|
+
readFileSync as readFileSync2,
|
|
2188
|
+
renameSync,
|
|
2189
|
+
rmSync as rmSync2,
|
|
2190
|
+
writeFileSync as writeFileSync2
|
|
2191
|
+
} from "node:fs";
|
|
2192
|
+
var NO_FOLLOW2 = constants2.O_NOFOLLOW ?? 0;
|
|
2193
|
+
|
|
2018
2194
|
// src/window-budget/summarize/prompt.ts
|
|
2019
2195
|
var CONDENSER_BRIEF = [
|
|
2020
2196
|
"You are a transcript recorder for a long-running coding session.",
|