xovris 0.1.0 → 0.2.0
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/bin/xovris.mjs +0 -0
- package/dist/cli.js +413 -24
- package/dist/{code-DsDiCUXb.js → code-DKbqSLWT.js} +11 -5
- package/dist/{collector-join-CwjwINuL.js → collector-join-CkBmhc2w.js} +1 -1
- package/dist/{findings-BHh24V38.js → findings-CcqH4Q2I.js} +1 -1
- package/dist/{finishing-Dsc2jn0-.js → finishing-CZ013_fT.js} +1 -1
- package/dist/{gated-write-DRftDST4.js → gated-write-B8Aln6GU.js} +1 -1
- package/dist/{hunt-BmQxPIL8.js → hunt-Ce77c8DT.js} +2 -2
- package/dist/{languages-DhPS_td-.js → languages-9JrWtbQN.js} +1 -1
- package/dist/{merge-BK7G5i5Q.js → merge-B-lFy27Y.js} +3 -3
- package/dist/{review-ui-DsFuGF7B.js → review-ui-DGEc-h8N.js} +1 -1
- package/dist/{sourcemaps-tbnp_n01.js → sourcemaps-B7Knrrs4.js} +2 -2
- package/dist/{src-DPO9_Gtz.js → src-CZstFB4j.js} +1812 -74
- package/dist/{trace-DoQjPlBv.js → trace-1RWrsTAT.js} +1 -1
- package/package.json +16 -16
package/bin/xovris.mjs
CHANGED
|
File without changes
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { B as readsForShape, E as undoFixes, F as leaveBy, G as
|
|
1
|
+
import { B as readsForShape, E as undoFixes, F as leaveBy, G as workOut, H as refreshDeprecations, I as forAgents, J as readingsOf, K as assumptionsOf, L as readsForReview, M as applyGuarded, O as guardStrip, P as handOff, R as reviewChange, T as commandRunner, V as testsFirst, W as dirReader, X as parseDiff, Y as newFileDiff, h as revertOne, j as valueCopy, m as fixAll, q as probeNames, z as stackChain } from "./src-CZstFB4j.js";
|
|
2
2
|
import { a as whoami, c as Cancelled, d as ApiFailure, f as CLI_AGENT, l as clackUi, n as login, o as writeFileAtomic, p as CLI_VERSION, r as logout, s as signIn, t as apiCommand, u as Api } from "./apicmd-3jWpFhG3.js";
|
|
3
|
-
import { a as gatedWriteFile, i as gatedWrite, n as gatedRun, t as MANIFEST_FILES } from "./gated-write-
|
|
4
|
-
import { i as splitCommandLine, n as collectorAt, r as joinCollector, t as addExporter } from "./collector-join-
|
|
5
|
-
import { a as reviewSarif, i as reviewJson, n as progressLine, r as renderReview, s as styleFor, t as leftToFix } from "./review-ui-
|
|
3
|
+
import { a as gatedWriteFile, i as gatedWrite, n as gatedRun, t as MANIFEST_FILES } from "./gated-write-B8Aln6GU.js";
|
|
4
|
+
import { i as splitCommandLine, n as collectorAt, r as joinCollector, t as addExporter } from "./collector-join-CkBmhc2w.js";
|
|
5
|
+
import { a as reviewSarif, i as reviewJson, n as progressLine, r as renderReview, s as styleFor, t as leftToFix } from "./review-ui-DGEc-h8N.js";
|
|
6
6
|
import { builtinModules } from "node:module";
|
|
7
7
|
import { mkdir, mkdtemp, readFile, readdir, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
8
8
|
import { homedir, tmpdir } from "node:os";
|
|
@@ -1085,6 +1085,12 @@ function projectIngestUrl(ingestUrl, projectId) {
|
|
|
1085
1085
|
|
|
1086
1086
|
//#endregion
|
|
1087
1087
|
//#region ../stacks/src/agents.ts
|
|
1088
|
+
const MCP_SERVER_NAME = "xovris";
|
|
1089
|
+
/** UL-21: one remote MCP server for every AI tool, at its own host. */
|
|
1090
|
+
const DEFAULT_MCP_ORIGIN = "https://api.xovris.ai";
|
|
1091
|
+
function mcpUrl(apiOrigin = DEFAULT_MCP_ORIGIN) {
|
|
1092
|
+
return new URL("/v1/mcp", apiOrigin).toString();
|
|
1093
|
+
}
|
|
1088
1094
|
const AGENT_CLIENTS = [
|
|
1089
1095
|
{
|
|
1090
1096
|
id: "claude_code",
|
|
@@ -1150,6 +1156,145 @@ const AGENT_CLIENTS = [
|
|
|
1150
1156
|
kind: "config"
|
|
1151
1157
|
}
|
|
1152
1158
|
];
|
|
1159
|
+
const b64 = (s) => btoa(String.fromCharCode(...new TextEncoder().encode(s)));
|
|
1160
|
+
/** Each client's documented way to add a remote (Streamable HTTP) server; OAuth sign-in happens in the client. */
|
|
1161
|
+
function agentInstall(client, url = mcpUrl()) {
|
|
1162
|
+
switch (client) {
|
|
1163
|
+
case "claude_code": return `claude mcp add --transport http ${MCP_SERVER_NAME} ${url}`;
|
|
1164
|
+
case "codex": return `codex mcp add ${MCP_SERVER_NAME} --url ${url} && codex mcp login ${MCP_SERVER_NAME}`;
|
|
1165
|
+
case "copilot_cli": return `copilot mcp add --transport http ${MCP_SERVER_NAME} ${url}`;
|
|
1166
|
+
case "lm_studio": return `lmstudio://add_mcp?name=${MCP_SERVER_NAME}&config=${encodeURIComponent(b64(JSON.stringify({ url })))}`;
|
|
1167
|
+
case "goose": return `goose://extension?url=${encodeURIComponent(url)}&type=streamable_http&id=${MCP_SERVER_NAME}&name=Xovris&description=${encodeURIComponent("Xovris setup, incidents and issues")}`;
|
|
1168
|
+
case "vscode": return `code --add-mcp '${JSON.stringify({
|
|
1169
|
+
name: MCP_SERVER_NAME,
|
|
1170
|
+
type: "http",
|
|
1171
|
+
url
|
|
1172
|
+
})}'`;
|
|
1173
|
+
case "cursor": return `cursor://anysphere.cursor-deeplink/mcp/install?name=${MCP_SERVER_NAME}&config=${encodeURIComponent(b64(JSON.stringify({ url })))}`;
|
|
1174
|
+
case "windsurf": return JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: { serverUrl: url } } }, null, 2);
|
|
1175
|
+
case "gemini_cli": return `gemini mcp add -t http -s user ${MCP_SERVER_NAME} ${url}`;
|
|
1176
|
+
case "chatgpt":
|
|
1177
|
+
case "claude_app": return url;
|
|
1178
|
+
case "other": return JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: { url } } }, null, 2);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* G138.13: the same documented adds as argument lists a program runs (npx xovris init, after one yes) - only the clients whose add is a
|
|
1183
|
+
* command; a link or a settings block is opened or merged instead, and an app with no command is null.
|
|
1184
|
+
*/
|
|
1185
|
+
function agentInstallArgs(client, url = mcpUrl()) {
|
|
1186
|
+
switch (client) {
|
|
1187
|
+
case "claude_code": return [{
|
|
1188
|
+
cmd: "claude",
|
|
1189
|
+
args: [
|
|
1190
|
+
"mcp",
|
|
1191
|
+
"add",
|
|
1192
|
+
"--transport",
|
|
1193
|
+
"http",
|
|
1194
|
+
MCP_SERVER_NAME,
|
|
1195
|
+
url
|
|
1196
|
+
]
|
|
1197
|
+
}];
|
|
1198
|
+
case "codex": return [{
|
|
1199
|
+
cmd: "codex",
|
|
1200
|
+
args: [
|
|
1201
|
+
"mcp",
|
|
1202
|
+
"add",
|
|
1203
|
+
MCP_SERVER_NAME,
|
|
1204
|
+
"--url",
|
|
1205
|
+
url
|
|
1206
|
+
]
|
|
1207
|
+
}, {
|
|
1208
|
+
cmd: "codex",
|
|
1209
|
+
args: [
|
|
1210
|
+
"mcp",
|
|
1211
|
+
"login",
|
|
1212
|
+
MCP_SERVER_NAME
|
|
1213
|
+
]
|
|
1214
|
+
}];
|
|
1215
|
+
case "copilot_cli": return [{
|
|
1216
|
+
cmd: "copilot",
|
|
1217
|
+
args: [
|
|
1218
|
+
"mcp",
|
|
1219
|
+
"add",
|
|
1220
|
+
"--transport",
|
|
1221
|
+
"http",
|
|
1222
|
+
MCP_SERVER_NAME,
|
|
1223
|
+
url
|
|
1224
|
+
]
|
|
1225
|
+
}];
|
|
1226
|
+
case "vscode": return [{
|
|
1227
|
+
cmd: "code",
|
|
1228
|
+
args: ["--add-mcp", JSON.stringify({
|
|
1229
|
+
name: MCP_SERVER_NAME,
|
|
1230
|
+
type: "http",
|
|
1231
|
+
url
|
|
1232
|
+
})]
|
|
1233
|
+
}];
|
|
1234
|
+
case "gemini_cli": return [{
|
|
1235
|
+
cmd: "gemini",
|
|
1236
|
+
args: [
|
|
1237
|
+
"mcp",
|
|
1238
|
+
"add",
|
|
1239
|
+
"-t",
|
|
1240
|
+
"http",
|
|
1241
|
+
"-s",
|
|
1242
|
+
"user",
|
|
1243
|
+
MCP_SERVER_NAME,
|
|
1244
|
+
url
|
|
1245
|
+
]
|
|
1246
|
+
}];
|
|
1247
|
+
default: return null;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
/** NAA-27: the one package every plugin host installs (https://github.com/xovris/agent-plugins, published from packages/agent-plugins). */
|
|
1251
|
+
const PLUGIN_SOURCE = "xovris/agent-plugins";
|
|
1252
|
+
/** NAA-27: a host whose own plugin install brings Xovris whole - its tools and its way of working, from the one package - with the host's
|
|
1253
|
+
* own list that reads it back; null for a host that is given the MCP server alone (agentInstallArgs). */
|
|
1254
|
+
function agentPluginArgs(client) {
|
|
1255
|
+
switch (client) {
|
|
1256
|
+
case "claude_code": return {
|
|
1257
|
+
steps: [{
|
|
1258
|
+
cmd: "claude",
|
|
1259
|
+
args: [
|
|
1260
|
+
"plugin",
|
|
1261
|
+
"marketplace",
|
|
1262
|
+
"add",
|
|
1263
|
+
PLUGIN_SOURCE
|
|
1264
|
+
]
|
|
1265
|
+
}, {
|
|
1266
|
+
cmd: "claude",
|
|
1267
|
+
args: [
|
|
1268
|
+
"plugin",
|
|
1269
|
+
"install",
|
|
1270
|
+
`${MCP_SERVER_NAME}@${MCP_SERVER_NAME}`
|
|
1271
|
+
]
|
|
1272
|
+
}],
|
|
1273
|
+
check: {
|
|
1274
|
+
cmd: "claude",
|
|
1275
|
+
args: ["plugin", "list"],
|
|
1276
|
+
names: `${MCP_SERVER_NAME}@${MCP_SERVER_NAME}`
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
case "gemini_cli": return {
|
|
1280
|
+
steps: [{
|
|
1281
|
+
cmd: "gemini",
|
|
1282
|
+
args: [
|
|
1283
|
+
"extensions",
|
|
1284
|
+
"install",
|
|
1285
|
+
`https://github.com/${PLUGIN_SOURCE}`,
|
|
1286
|
+
"--consent"
|
|
1287
|
+
]
|
|
1288
|
+
}],
|
|
1289
|
+
check: {
|
|
1290
|
+
cmd: "gemini",
|
|
1291
|
+
args: ["extensions", "list"],
|
|
1292
|
+
names: MCP_SERVER_NAME
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
default: return null;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1153
1298
|
|
|
1154
1299
|
//#endregion
|
|
1155
1300
|
//#region ../stacks/src/status.ts
|
|
@@ -1239,7 +1384,7 @@ function doorStatus(e) {
|
|
|
1239
1384
|
};
|
|
1240
1385
|
return {
|
|
1241
1386
|
status: "unverified",
|
|
1242
|
-
why: `
|
|
1387
|
+
why: `Connect ${e.name} and Xovris confirms it works on its first real check.`,
|
|
1243
1388
|
evidenceAt: null,
|
|
1244
1389
|
offered: false
|
|
1245
1390
|
};
|
|
@@ -3632,6 +3777,215 @@ async function checksCommand(sub, o, ui, sys, secrets) {
|
|
|
3632
3777
|
}
|
|
3633
3778
|
}
|
|
3634
3779
|
|
|
3780
|
+
//#endregion
|
|
3781
|
+
//#region src/agents-init.ts
|
|
3782
|
+
function machinePlaces(env = process.env, platform = process.platform) {
|
|
3783
|
+
const home = homedir();
|
|
3784
|
+
return {
|
|
3785
|
+
home,
|
|
3786
|
+
vscodeUser: platform === "win32" ? join(env.APPDATA ?? join(home, "AppData", "Roaming"), "Code", "User") : platform === "darwin" ? join(home, "Library", "Application Support", "Code", "User") : join(env.XDG_CONFIG_HOME ?? join(home, ".config"), "Code", "User"),
|
|
3787
|
+
exists: (p) => existsSync(p),
|
|
3788
|
+
read: (p) => {
|
|
3789
|
+
try {
|
|
3790
|
+
return readFileSync(p, "utf8");
|
|
3791
|
+
} catch {
|
|
3792
|
+
return null;
|
|
3793
|
+
}
|
|
3794
|
+
},
|
|
3795
|
+
write: (p, t) => {
|
|
3796
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
3797
|
+
writeFileSync(p, t);
|
|
3798
|
+
}
|
|
3799
|
+
};
|
|
3800
|
+
}
|
|
3801
|
+
/** The command each command-line client answers to, and its MCP list (read to see whether Xovris is already there). */
|
|
3802
|
+
const COMMANDS = {
|
|
3803
|
+
claude_code: "claude",
|
|
3804
|
+
codex: "codex",
|
|
3805
|
+
gemini_cli: "gemini",
|
|
3806
|
+
copilot_cli: "copilot",
|
|
3807
|
+
vscode: "code"
|
|
3808
|
+
};
|
|
3809
|
+
const holds = (text) => text !== null && (/* @__PURE__ */ new RegExp(`["'\\s\\[.]${MCP_SERVER_NAME}["'\\s\\].=:]`)).test(text);
|
|
3810
|
+
const settings = (p) => ({
|
|
3811
|
+
cursor: {
|
|
3812
|
+
folder: join(p.home, ".cursor"),
|
|
3813
|
+
file: join(p.home, ".cursor", "mcp.json")
|
|
3814
|
+
},
|
|
3815
|
+
windsurf: {
|
|
3816
|
+
folder: join(p.home, ".codeium", "windsurf"),
|
|
3817
|
+
file: join(p.home, ".codeium", "windsurf", "mcp_config.json")
|
|
3818
|
+
},
|
|
3819
|
+
vscode: {
|
|
3820
|
+
folder: p.vscodeUser,
|
|
3821
|
+
file: join(p.vscodeUser, "mcp.json")
|
|
3822
|
+
}
|
|
3823
|
+
});
|
|
3824
|
+
/** Every coding agent on this machine, found by itself - a command that answers, or the client's own settings folder. */
|
|
3825
|
+
async function detectAgentClients(sys, places, api) {
|
|
3826
|
+
const url = mcpUrl(api);
|
|
3827
|
+
const where = settings(places);
|
|
3828
|
+
const out = [];
|
|
3829
|
+
for (const c of AGENT_CLIENTS) {
|
|
3830
|
+
const cmd = COMMANDS[c.id];
|
|
3831
|
+
const own = where[c.id];
|
|
3832
|
+
let present = false;
|
|
3833
|
+
let already = false;
|
|
3834
|
+
if (cmd) {
|
|
3835
|
+
present = (await sys.run(cmd, ["--version"], places.home).catch(() => null))?.code === 0;
|
|
3836
|
+
if (present && c.id !== "vscode") {
|
|
3837
|
+
const l = await sys.run(cmd, ["mcp", "list"], places.home).catch(() => null);
|
|
3838
|
+
already = l?.code === 0 && holds(` ${l.stdout} `);
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
if (own && places.exists(own.folder)) present = true;
|
|
3842
|
+
if (!present) continue;
|
|
3843
|
+
if (own) already ||= holds(places.read(own.file));
|
|
3844
|
+
out.push({
|
|
3845
|
+
id: c.id,
|
|
3846
|
+
name: c.name,
|
|
3847
|
+
kind: c.kind,
|
|
3848
|
+
line: agentInstall(c.id, url),
|
|
3849
|
+
already
|
|
3850
|
+
});
|
|
3851
|
+
}
|
|
3852
|
+
return out;
|
|
3853
|
+
}
|
|
3854
|
+
/** NAA-27: the host's own plugin install, each step answered and the host's own list reading Xovris back - never counted on its word. */
|
|
3855
|
+
async function pluginAdded(sys, cwd, p) {
|
|
3856
|
+
for (const s of p.steps) {
|
|
3857
|
+
const r = await sys.run(s.cmd, s.args, cwd).catch(() => ({
|
|
3858
|
+
code: 1,
|
|
3859
|
+
stdout: "",
|
|
3860
|
+
stderr: ""
|
|
3861
|
+
}));
|
|
3862
|
+
if (r.code !== 0 && !/already/i.test(`${r.stdout}\n${r.stderr}`)) return false;
|
|
3863
|
+
}
|
|
3864
|
+
const l = await sys.run(p.check.cmd, p.check.args, cwd).catch(() => null);
|
|
3865
|
+
return l?.code === 0 && l.stdout.includes(p.check.names);
|
|
3866
|
+
}
|
|
3867
|
+
/** Windsurf (and any client whose add is a settings block): Xovris merged into its own file, every server already there kept. */
|
|
3868
|
+
function mergeSettings(places, file, key, url) {
|
|
3869
|
+
const text = places.read(file);
|
|
3870
|
+
let doc = {};
|
|
3871
|
+
if (text && text.trim()) {
|
|
3872
|
+
try {
|
|
3873
|
+
doc = JSON.parse(text);
|
|
3874
|
+
} catch {
|
|
3875
|
+
return `its settings file ${file} is not JSON Xovris can read, so it was left as it was`;
|
|
3876
|
+
}
|
|
3877
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc)) return `its settings file ${file} is not a settings object, so it was left as it was`;
|
|
3878
|
+
}
|
|
3879
|
+
places.write(file, `${JSON.stringify({
|
|
3880
|
+
...doc,
|
|
3881
|
+
mcpServers: {
|
|
3882
|
+
...doc.mcpServers ?? {},
|
|
3883
|
+
[MCP_SERVER_NAME]: { [key]: url }
|
|
3884
|
+
}
|
|
3885
|
+
}, null, 2)}\n`);
|
|
3886
|
+
return null;
|
|
3887
|
+
}
|
|
3888
|
+
/**
|
|
3889
|
+
* G138.13: the offer itself - every client found said with its own add, ONE question for all of them, then each added its own way and
|
|
3890
|
+
* read back (a command's exit code and words, a link opened, a settings file written and read again). A no changes nothing.
|
|
3891
|
+
*/
|
|
3892
|
+
async function offerAgents(o, ui, sys, d) {
|
|
3893
|
+
const places = d.places ?? machinePlaces();
|
|
3894
|
+
const found = await detectAgentClients(sys, places, o.api);
|
|
3895
|
+
const todo = found.filter((f) => !f.already);
|
|
3896
|
+
const names = (xs) => xs.map((x) => x.name).join(", ");
|
|
3897
|
+
if (!found.length) return {
|
|
3898
|
+
found,
|
|
3899
|
+
added: [],
|
|
3900
|
+
failed: [],
|
|
3901
|
+
asked: false
|
|
3902
|
+
};
|
|
3903
|
+
if (!todo.length) {
|
|
3904
|
+
ui.info(`Xovris is already in ${names(found)} on this machine.`);
|
|
3905
|
+
return {
|
|
3906
|
+
found,
|
|
3907
|
+
added: [],
|
|
3908
|
+
failed: [],
|
|
3909
|
+
asked: false
|
|
3910
|
+
};
|
|
3911
|
+
}
|
|
3912
|
+
ui.note(todo.map((f) => `${f.name}: ${agentPluginArgs(f.id) ? `installs the Xovris plugin (its tools and its way of working), or adds ${f.line}` : f.kind === "config" ? `adds Xovris to its MCP settings` : f.line}`).join("\n"), "Coding agents on this machine");
|
|
3913
|
+
if (!await d.ask(`Add Xovris to ${names(todo)} now, each by its own add?`)) {
|
|
3914
|
+
ui.info("Nothing was added to your coding agents. npx xovris agents offers it again.");
|
|
3915
|
+
return {
|
|
3916
|
+
found,
|
|
3917
|
+
added: [],
|
|
3918
|
+
failed: [],
|
|
3919
|
+
asked: true
|
|
3920
|
+
};
|
|
3921
|
+
}
|
|
3922
|
+
const url = mcpUrl(o.api);
|
|
3923
|
+
const added = [];
|
|
3924
|
+
const failed = [];
|
|
3925
|
+
for (const f of todo) {
|
|
3926
|
+
const plug = agentPluginArgs(f.id);
|
|
3927
|
+
if (plug && await pluginAdded(sys, places.home, plug)) {
|
|
3928
|
+
added.push(`${f.name} (the Xovris plugin)`);
|
|
3929
|
+
continue;
|
|
3930
|
+
}
|
|
3931
|
+
const steps = agentInstallArgs(f.id, url);
|
|
3932
|
+
if (steps) {
|
|
3933
|
+
let why = null;
|
|
3934
|
+
for (const s of steps) {
|
|
3935
|
+
const r = await sys.run(s.cmd, s.args, places.home).catch((e) => ({
|
|
3936
|
+
code: 1,
|
|
3937
|
+
stdout: "",
|
|
3938
|
+
stderr: String(e?.message ?? e)
|
|
3939
|
+
}));
|
|
3940
|
+
if (r.code !== 0 && !/already exists|already configured|already added/i.test(`${r.stdout}\n${r.stderr}`)) {
|
|
3941
|
+
why = (r.stderr || r.stdout).trim().split(/\r?\n/)[0]?.slice(0, 200) || `${s.cmd} answered ${r.code}`;
|
|
3942
|
+
break;
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
if (why) failed.push({
|
|
3946
|
+
name: f.name,
|
|
3947
|
+
why
|
|
3948
|
+
});
|
|
3949
|
+
else added.push(f.name);
|
|
3950
|
+
continue;
|
|
3951
|
+
}
|
|
3952
|
+
if (f.kind === "link") {
|
|
3953
|
+
if (await sys.openUrl(f.line)) added.push(`${f.name} (its install link is open - press Install there)`);
|
|
3954
|
+
else failed.push({
|
|
3955
|
+
name: f.name,
|
|
3956
|
+
why: `Xovris opens its install link for you, and this machine has no browser to open it in. Do it yourself instead: ${f.line}`
|
|
3957
|
+
});
|
|
3958
|
+
continue;
|
|
3959
|
+
}
|
|
3960
|
+
const own = settings(places)[f.id];
|
|
3961
|
+
if (own && f.kind === "config") {
|
|
3962
|
+
const wrong = mergeSettings(places, own.file, f.id === "windsurf" ? "serverUrl" : "url", url);
|
|
3963
|
+
if (wrong) failed.push({
|
|
3964
|
+
name: f.name,
|
|
3965
|
+
why: wrong
|
|
3966
|
+
});
|
|
3967
|
+
else if (holds(places.read(own.file))) added.push(f.name);
|
|
3968
|
+
else failed.push({
|
|
3969
|
+
name: f.name,
|
|
3970
|
+
why: `its settings file ${own.file} did not read back with Xovris in it`
|
|
3971
|
+
});
|
|
3972
|
+
continue;
|
|
3973
|
+
}
|
|
3974
|
+
failed.push({
|
|
3975
|
+
name: f.name,
|
|
3976
|
+
why: `it is added in the app itself: ${f.line}`
|
|
3977
|
+
});
|
|
3978
|
+
}
|
|
3979
|
+
if (added.length) ui.success(`Xovris added to ${added.join(", ")}. Each signs in to Xovris the first time it uses it.`);
|
|
3980
|
+
for (const x of failed) ui.warn(`${x.name}: ${x.why}`);
|
|
3981
|
+
return {
|
|
3982
|
+
found,
|
|
3983
|
+
added,
|
|
3984
|
+
failed,
|
|
3985
|
+
asked: true
|
|
3986
|
+
};
|
|
3987
|
+
}
|
|
3988
|
+
|
|
3635
3989
|
//#endregion
|
|
3636
3990
|
//#region src/instrumentation.ts
|
|
3637
3991
|
const MARK = "Added by npx xovris init - remove with npx xovris remove";
|
|
@@ -5927,13 +6281,33 @@ function recordInstallFailure(manager, output, dir = process.env.XOVRIS_INSTALL_
|
|
|
5927
6281
|
|
|
5928
6282
|
//#endregion
|
|
5929
6283
|
//#region src/system.ts
|
|
6284
|
+
const META = /([()\][%!^"`<>&|;, *?])/g;
|
|
6285
|
+
const forCmd = (a, shim) => {
|
|
6286
|
+
const q = `"${a.replace(/(\\*)"/g, "$1$1\\\"").replace(/(\\*)$/, "$1$1")}"`.replace(META, "^$1");
|
|
6287
|
+
return shim ? q.replace(META, "^$1") : q;
|
|
6288
|
+
};
|
|
6289
|
+
function onPath(cmd) {
|
|
6290
|
+
if (/[\\/]/.test(cmd) || /\.\w+$/.test(cmd)) return cmd;
|
|
6291
|
+
const exts$1 = (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";");
|
|
6292
|
+
for (const dir of (process.env.PATH ?? "").split(";")) for (const e of exts$1) if (dir && existsSync(join(dir, cmd + e))) return join(dir, cmd + e);
|
|
6293
|
+
return cmd;
|
|
6294
|
+
}
|
|
6295
|
+
function commandLine(file, args) {
|
|
6296
|
+
const shim = /\.(cmd|bat)$/i.test(file);
|
|
6297
|
+
return [/[\s()&^|<>]/.test(file) ? `"${file.replace(/"/g, "")}"` : file.replace(META, "^$1"), ...args.map((a) => forCmd(a, shim))].join(" ");
|
|
6298
|
+
}
|
|
6299
|
+
function launch(cmd, args, opts) {
|
|
6300
|
+
if (process.platform !== "win32") return spawn(cmd, args, opts);
|
|
6301
|
+
return spawn(commandLine(onPath(cmd), args), {
|
|
6302
|
+
...opts,
|
|
6303
|
+
shell: true
|
|
6304
|
+
});
|
|
6305
|
+
}
|
|
5930
6306
|
function realSystem() {
|
|
5931
6307
|
return {
|
|
5932
6308
|
run: (cmd, args, cwd, env) => new Promise((resolve$1) => {
|
|
5933
|
-
const
|
|
5934
|
-
const child = spawn(cmd, win ? args.map((a) => /[\s&|<>^()]/.test(a) && !a.includes("\"") ? `"${a}"` : a) : args, {
|
|
6309
|
+
const child = launch(cmd, args, {
|
|
5935
6310
|
cwd,
|
|
5936
|
-
shell: win,
|
|
5937
6311
|
stdio: [
|
|
5938
6312
|
"ignore",
|
|
5939
6313
|
"pipe",
|
|
@@ -5946,10 +6320,10 @@ function realSystem() {
|
|
|
5946
6320
|
});
|
|
5947
6321
|
let stdout = "";
|
|
5948
6322
|
let stderr = "";
|
|
5949
|
-
child.stdout
|
|
6323
|
+
child.stdout?.on("data", (d) => {
|
|
5950
6324
|
stdout += d;
|
|
5951
6325
|
});
|
|
5952
|
-
child.stderr
|
|
6326
|
+
child.stderr?.on("data", (d) => {
|
|
5953
6327
|
stderr += d;
|
|
5954
6328
|
});
|
|
5955
6329
|
child.on("error", (e) => resolve$1({
|
|
@@ -5964,10 +6338,8 @@ function realSystem() {
|
|
|
5964
6338
|
}));
|
|
5965
6339
|
}),
|
|
5966
6340
|
handOver: (cmd, args, cwd) => new Promise((resolve$1) => {
|
|
5967
|
-
const
|
|
5968
|
-
const child = spawn(cmd, win ? args.map((a) => /[\s&|<>^()]/.test(a) && !a.includes("\"") ? `"${a}"` : a) : args, {
|
|
6341
|
+
const child = launch(cmd, args, {
|
|
5969
6342
|
cwd,
|
|
5970
|
-
shell: win,
|
|
5971
6343
|
stdio: "inherit"
|
|
5972
6344
|
});
|
|
5973
6345
|
child.on("error", () => resolve$1(127));
|
|
@@ -6054,7 +6426,7 @@ async function commitUntracked(sys, cwd, path) {
|
|
|
6054
6426
|
* backup proven on a copy, the commit made, read back by `holds`, and the tip put back by itself when it does not read back (the
|
|
6055
6427
|
* files stay staged, so nothing is lost) - never over a commit someone else made after it.
|
|
6056
6428
|
*/
|
|
6057
|
-
async function commitThroughGate(sys, cwd, id, message, holds, notHeld) {
|
|
6429
|
+
async function commitThroughGate(sys, cwd, id, message, holds$1, notHeld) {
|
|
6058
6430
|
let known = null;
|
|
6059
6431
|
const head = async () => known ??= (await sys.run("git", [
|
|
6060
6432
|
"rev-parse",
|
|
@@ -6071,7 +6443,7 @@ async function commitThroughGate(sys, cwd, id, message, holds, notHeld) {
|
|
|
6071
6443
|
changeDigest: `${id}\n${message}`,
|
|
6072
6444
|
withinGrant: true,
|
|
6073
6445
|
irreversible: false,
|
|
6074
|
-
holds: async () => made ? holds() : false,
|
|
6446
|
+
holds: async () => made ? holds$1() : false,
|
|
6075
6447
|
apply: async () => {
|
|
6076
6448
|
known = null;
|
|
6077
6449
|
const r = await sys.run("git", [
|
|
@@ -6499,6 +6871,11 @@ async function latestReach(sys, cwd) {
|
|
|
6499
6871
|
}
|
|
6500
6872
|
/** The wizard run with its one self-repair: a request the server reads as from an older wizard hands over to the latest. */
|
|
6501
6873
|
async function initWithLatest(o, ui, sys, secrets) {
|
|
6874
|
+
const code = await initOnce(o, ui, sys, secrets);
|
|
6875
|
+
if (!o.ci && (process.stdin.isTTY || o.agents)) await offerAgents(o, ui, sys, { ask: (m) => ask(o, ui, m) }).catch(() => null);
|
|
6876
|
+
return code;
|
|
6877
|
+
}
|
|
6878
|
+
async function initOnce(o, ui, sys, secrets) {
|
|
6502
6879
|
try {
|
|
6503
6880
|
return await init(o, ui, sys, secrets);
|
|
6504
6881
|
} catch (e) {
|
|
@@ -6508,6 +6885,12 @@ async function initWithLatest(o, ui, sys, secrets) {
|
|
|
6508
6885
|
return code;
|
|
6509
6886
|
}
|
|
6510
6887
|
}
|
|
6888
|
+
/** G138.13: `npx xovris agents` - the same offer on its own, any time. */
|
|
6889
|
+
async function agentsCommand(o, ui, sys) {
|
|
6890
|
+
const r = await offerAgents(o, ui, sys, { ask: (m) => ask(o, ui, m) });
|
|
6891
|
+
if (!r.found.length) ui.info("No coding agent was found on this machine - Claude Code, Codex, Gemini CLI, Copilot CLI, VS Code, Cursor and Windsurf were each looked for.");
|
|
6892
|
+
return r.failed.length ? 1 : 0;
|
|
6893
|
+
}
|
|
6511
6894
|
/** G105.01.C129: after an install the lockfile was let to change for, the manifest and lockfile are committed alone - CI then
|
|
6512
6895
|
* installs from them with its lockfile frozen, exactly as here. Other staged work is never swept in; nothing is pushed. */
|
|
6513
6896
|
async function commitDependencyFiles(cwd, manifest, ui, sys) {
|
|
@@ -7675,6 +8058,7 @@ async function reviewCommand(o, sys, out) {
|
|
|
7675
8058
|
} : r;
|
|
7676
8059
|
}
|
|
7677
8060
|
progress.step("Reviewing");
|
|
8061
|
+
await refreshDeprecations().catch(() => null);
|
|
7678
8062
|
const contents = {};
|
|
7679
8063
|
const tracked = (await sys.run("git", ["ls-files", "-z"], o.cwd)).stdout.split("\0").filter(Boolean);
|
|
7680
8064
|
const manifests = tracked.filter(readsForShape);
|
|
@@ -8146,6 +8530,7 @@ async function main(argv) {
|
|
|
8146
8530
|
wait: flag("--wait"),
|
|
8147
8531
|
localOnly: flag("--local-only"),
|
|
8148
8532
|
undo: flag("--undo"),
|
|
8533
|
+
...flag("--agents") ? { agents: true } : {},
|
|
8149
8534
|
...value("--repo") ? { repo: value("--repo") } : {},
|
|
8150
8535
|
...value("--connection") ? { connection: value("--connection") } : {},
|
|
8151
8536
|
ci: !!process.env.CI,
|
|
@@ -8177,7 +8562,7 @@ async function main(argv) {
|
|
|
8177
8562
|
}, ui, sys, secrets, io), ui);
|
|
8178
8563
|
case "logout": return logout(io);
|
|
8179
8564
|
case "sourcemaps": {
|
|
8180
|
-
const { sayUpload, uploadSourceMaps } = await import("./sourcemaps-
|
|
8565
|
+
const { sayUpload, uploadSourceMaps } = await import("./sourcemaps-B7Knrrs4.js");
|
|
8181
8566
|
const dir = positional[1] ?? "dist";
|
|
8182
8567
|
let isDir$2 = false;
|
|
8183
8568
|
try {
|
|
@@ -8214,6 +8599,10 @@ async function main(argv) {
|
|
|
8214
8599
|
idempotency: !flag("--no-idempotency")
|
|
8215
8600
|
}, { api: o.api }, sys, secrets, io);
|
|
8216
8601
|
case "init": return guarded(() => initWithLatest(o, ui, sys, secrets), ui);
|
|
8602
|
+
case "agents": return guarded(() => agentsCommand({
|
|
8603
|
+
...o,
|
|
8604
|
+
agents: true
|
|
8605
|
+
}, ui, sys), ui);
|
|
8217
8606
|
case "discover": return guarded(() => discoverCommand(o, ui, sys, flag("--json") ? io : null), ui);
|
|
8218
8607
|
case "scan": return guarded(() => scan(positional[1], ui, sys), ui);
|
|
8219
8608
|
case "receipt": return guarded(() => receiptCommand(positional[1], positional[2], value("--key"), ui, sys), ui);
|
|
@@ -8247,7 +8636,7 @@ async function main(argv) {
|
|
|
8247
8636
|
stack: flag("--stack")
|
|
8248
8637
|
}, sys, io.out);
|
|
8249
8638
|
case "merge": {
|
|
8250
|
-
const { mergeCommand } = await import("./merge-
|
|
8639
|
+
const { mergeCommand } = await import("./merge-B-lFy27Y.js");
|
|
8251
8640
|
return mergeCommand({
|
|
8252
8641
|
cwd: o.cwd,
|
|
8253
8642
|
entries: positional.slice(1),
|
|
@@ -8260,7 +8649,7 @@ async function main(argv) {
|
|
|
8260
8649
|
}
|
|
8261
8650
|
case "tests":
|
|
8262
8651
|
case "touches": {
|
|
8263
|
-
const f = await import("./finishing-
|
|
8652
|
+
const f = await import("./finishing-CZ013_fT.js");
|
|
8264
8653
|
const fo = {
|
|
8265
8654
|
cwd: o.cwd,
|
|
8266
8655
|
module: positional[1] ?? "",
|
|
@@ -8270,7 +8659,7 @@ async function main(argv) {
|
|
|
8270
8659
|
};
|
|
8271
8660
|
return command === "tests" ? f.testsCommand(fo, io.out) : f.touchesCommand(fo, io.out);
|
|
8272
8661
|
}
|
|
8273
|
-
case "resolve": return (await import("./finishing-
|
|
8662
|
+
case "resolve": return (await import("./finishing-CZ013_fT.js")).resolveCommand({
|
|
8274
8663
|
cwd: o.cwd,
|
|
8275
8664
|
module: "",
|
|
8276
8665
|
files: positional.slice(1),
|
|
@@ -8279,7 +8668,7 @@ async function main(argv) {
|
|
|
8279
8668
|
test: many("--test", "--test")
|
|
8280
8669
|
}, io.out);
|
|
8281
8670
|
case "hunt": {
|
|
8282
|
-
const { huntCommand } = await import("./hunt-
|
|
8671
|
+
const { huntCommand } = await import("./hunt-Ce77c8DT.js");
|
|
8283
8672
|
return huntCommand({
|
|
8284
8673
|
cwd: positional[1] ?? o.cwd,
|
|
8285
8674
|
env: process.env,
|
|
@@ -8290,7 +8679,7 @@ async function main(argv) {
|
|
|
8290
8679
|
}, (t) => process.stdout.write(t));
|
|
8291
8680
|
}
|
|
8292
8681
|
case "code": {
|
|
8293
|
-
const { codeCommand } = await import("./code-
|
|
8682
|
+
const { codeCommand } = await import("./code-DKbqSLWT.js");
|
|
8294
8683
|
return codeCommand({
|
|
8295
8684
|
api: o.api,
|
|
8296
8685
|
words: positional.slice(1).join(" "),
|
|
@@ -8299,7 +8688,7 @@ async function main(argv) {
|
|
|
8299
8688
|
}, sys, io);
|
|
8300
8689
|
}
|
|
8301
8690
|
case "findings": {
|
|
8302
|
-
const { findingsCommand } = await import("./findings-
|
|
8691
|
+
const { findingsCommand } = await import("./findings-CcqH4Q2I.js");
|
|
8303
8692
|
const read = {
|
|
8304
8693
|
severity: value("--severity"),
|
|
8305
8694
|
category: value("--category"),
|
|
@@ -8324,7 +8713,7 @@ async function main(argv) {
|
|
|
8324
8713
|
}, { api: o.api }, sys, secrets, io);
|
|
8325
8714
|
}
|
|
8326
8715
|
case "languages": {
|
|
8327
|
-
const { languagesCommand } = await import("./languages-
|
|
8716
|
+
const { languagesCommand } = await import("./languages-9JrWtbQN.js");
|
|
8328
8717
|
return languagesCommand({
|
|
8329
8718
|
gaps: flag("--gaps"),
|
|
8330
8719
|
json: flag("--json"),
|
|
@@ -8332,7 +8721,7 @@ async function main(argv) {
|
|
|
8332
8721
|
});
|
|
8333
8722
|
}
|
|
8334
8723
|
case "trace": {
|
|
8335
|
-
const { traceCommand } = await import("./trace-
|
|
8724
|
+
const { traceCommand } = await import("./trace-1RWrsTAT.js");
|
|
8336
8725
|
return traceCommand({
|
|
8337
8726
|
cwd: o.cwd,
|
|
8338
8727
|
fix: flag("--fix"),
|
|
@@ -22,11 +22,17 @@ async function codeCommand(a, sys, io) {
|
|
|
22
22
|
job: await r.json().catch(() => ({})) ?? {}
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
let started;
|
|
26
|
+
try {
|
|
27
|
+
started = await call("POST", "/code/tasks", {
|
|
28
|
+
words,
|
|
29
|
+
...a.repository ? { repository: a.repository } : {},
|
|
30
|
+
via: "cli"
|
|
31
|
+
});
|
|
32
|
+
} catch (e) {
|
|
33
|
+
io.err(`Xovris did not answer at ${plain(a.api, 200)} (${plain(e?.cause?.message ?? e?.message ?? e, 160)}). Nothing was started; check the address or your network and run it again.\n`);
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
30
36
|
if (started.status !== 202 || !started.job.id) {
|
|
31
37
|
io.err(`${plain(started.job.title ?? `Xovris did not take the job (${started.status})`)}. ${plain(started.job.detail ?? "")}\n${plain(started.job.next ?? "Try again in a moment.")}\n`);
|
|
32
38
|
return started.status === 400 ? 2 : 1;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as gatedService } from "./gated-write-
|
|
1
|
+
import { r as gatedService } from "./gated-write-B8Aln6GU.js";
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, resolve } from "node:path";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Z as SEVERITIES, c as FACET_AXES, l as checkFacetQuery, o as EFFORTS, s as EFFORT_UNMEASURED } from "./src-CZstFB4j.js";
|
|
2
2
|
import { i as tokenFor, u as Api } from "./apicmd-3jWpFhG3.js";
|
|
3
3
|
|
|
4
4
|
//#region src/findings.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as contentDigest, N as jobRunner, d as generateTests, f as proveResolution, k as writeProven, p as touchesFor, u as applyTouches } from "./src-
|
|
1
|
+
import { A as contentDigest, N as jobRunner, d as generateTests, f as proveResolution, k as writeProven, p as touchesFor, u as applyTouches } from "./src-CZstFB4j.js";
|
|
2
2
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
3
3
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as contentDigest, D as filesOf, M as applyGuarded, j as valueCopy, k as writeProven } from "./src-
|
|
1
|
+
import { A as contentDigest, D as filesOf, M as applyGuarded, j as valueCopy, k as writeProven } from "./src-CZstFB4j.js";
|
|
2
2
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as HUNT_CLASSES, t as huntRepository } from "./src-
|
|
2
|
-
import { o as stripAnsi, s as styleFor } from "./review-ui-
|
|
1
|
+
import { n as HUNT_CLASSES, t as huntRepository } from "./src-CZstFB4j.js";
|
|
2
|
+
import { o as stripAnsi, s as styleFor } from "./review-ui-DGEc-h8N.js";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { existsSync, statSync } from "node:fs";
|
|
5
5
|
|