@vohongtho.infotech/code-intel 1.0.1 → 1.0.2
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/README.md +24 -3
- package/dist/cli/hook.js +348 -0
- package/dist/cli/hook.js.map +1 -0
- package/dist/cli/main.js +1039 -46
- package/dist/cli/main.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +229 -112
- package/dist/index.js.map +1 -1
- package/dist/web/assets/{es-Bu8iwdFw.js → es-DiINqj58.js} +1 -1
- package/dist/web/assets/index-CzWucUxe.js +354 -0
- package/dist/web/assets/index-D3zJQH9-.css +2 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -2
- package/dist/web/assets/index-C9M6YLlS.css +0 -2
- package/dist/web/assets/index-CKc3HEpe.js +0 -354
package/dist/index.d.ts
CHANGED
|
@@ -202,9 +202,20 @@ declare function detectOverrides(graph: KnowledgeGraph): CodeEdge[];
|
|
|
202
202
|
|
|
203
203
|
interface LLMConfig {
|
|
204
204
|
/** Which provider to use. Default: 'ollama'. */
|
|
205
|
-
provider?: 'openai' | 'anthropic' | 'ollama';
|
|
205
|
+
provider?: 'openai' | 'anthropic' | 'ollama' | 'custom';
|
|
206
206
|
/** Model name / ID passed to the provider. Each provider has its own default. */
|
|
207
207
|
model?: string;
|
|
208
|
+
/**
|
|
209
|
+
* For 'custom' provider: the base URL of the OpenAI-compatible API.
|
|
210
|
+
* e.g. 'http://localhost:1234/v1' (LM Studio), 'https://api.groq.com/openai/v1', etc.
|
|
211
|
+
*/
|
|
212
|
+
baseUrl?: string;
|
|
213
|
+
/**
|
|
214
|
+
* API key / token for the provider.
|
|
215
|
+
* For 'custom': passed as Bearer token. For 'openai': falls back to $OPENAI_API_KEY.
|
|
216
|
+
* For 'ollama': not needed.
|
|
217
|
+
*/
|
|
218
|
+
apiKey?: string;
|
|
208
219
|
/** Max concurrent LLM calls per batch. Default: 20. */
|
|
209
220
|
batchSize?: number;
|
|
210
221
|
/**
|
package/dist/index.js
CHANGED
|
@@ -528,7 +528,7 @@ var init_logger = __esm({
|
|
|
528
528
|
const isProduction = process.env.NODE_ENV === "production";
|
|
529
529
|
const logLevel = process.env.LOG_LEVEL ?? "info";
|
|
530
530
|
const transports = [];
|
|
531
|
-
transports.push(new winston.transports.Console());
|
|
531
|
+
transports.push(new winston.transports.Console({ stderrLevels: ["error", "warn", "info", "http", "verbose", "debug", "silly"] }));
|
|
532
532
|
if (!isProduction) {
|
|
533
533
|
try {
|
|
534
534
|
if (!fs26.existsSync(_Logger.LOG_DIR)) {
|
|
@@ -2635,6 +2635,49 @@ var init_anthropic = __esm({
|
|
|
2635
2635
|
}
|
|
2636
2636
|
});
|
|
2637
2637
|
|
|
2638
|
+
// src/llm/providers/custom.ts
|
|
2639
|
+
var custom_exports = {};
|
|
2640
|
+
__export(custom_exports, {
|
|
2641
|
+
CustomProvider: () => CustomProvider
|
|
2642
|
+
});
|
|
2643
|
+
var CustomProvider;
|
|
2644
|
+
var init_custom = __esm({
|
|
2645
|
+
"src/llm/providers/custom.ts"() {
|
|
2646
|
+
CustomProvider = class {
|
|
2647
|
+
modelName;
|
|
2648
|
+
baseUrl;
|
|
2649
|
+
apiKey;
|
|
2650
|
+
constructor(baseUrl, model, apiKey = "") {
|
|
2651
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
2652
|
+
this.modelName = model;
|
|
2653
|
+
this.apiKey = apiKey;
|
|
2654
|
+
}
|
|
2655
|
+
async summarize(prompt) {
|
|
2656
|
+
const url = `${this.baseUrl}/chat/completions`;
|
|
2657
|
+
const headers = {
|
|
2658
|
+
"Content-Type": "application/json"
|
|
2659
|
+
};
|
|
2660
|
+
if (this.apiKey) {
|
|
2661
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
2662
|
+
}
|
|
2663
|
+
const body = JSON.stringify({
|
|
2664
|
+
model: this.modelName,
|
|
2665
|
+
messages: [{ role: "user", content: prompt }],
|
|
2666
|
+
max_tokens: 200,
|
|
2667
|
+
temperature: 0.3
|
|
2668
|
+
});
|
|
2669
|
+
const res = await fetch(url, { method: "POST", headers, body });
|
|
2670
|
+
if (!res.ok) {
|
|
2671
|
+
const text = await res.text().catch(() => res.statusText);
|
|
2672
|
+
throw new Error(`Custom LLM API error ${res.status}: ${text}`);
|
|
2673
|
+
}
|
|
2674
|
+
const data = await res.json();
|
|
2675
|
+
return data.choices?.[0]?.message?.content?.trim() ?? "";
|
|
2676
|
+
}
|
|
2677
|
+
};
|
|
2678
|
+
}
|
|
2679
|
+
});
|
|
2680
|
+
|
|
2638
2681
|
// src/llm/providers/ollama.ts
|
|
2639
2682
|
var ollama_exports = {};
|
|
2640
2683
|
__export(ollama_exports, {
|
|
@@ -2678,7 +2721,7 @@ __export(factory_exports, {
|
|
|
2678
2721
|
createLLMProvider: () => createLLMProvider
|
|
2679
2722
|
});
|
|
2680
2723
|
async function createLLMProvider(config = {}) {
|
|
2681
|
-
const { provider = "ollama", model } = config;
|
|
2724
|
+
const { provider = "ollama", model, baseUrl, apiKey } = config;
|
|
2682
2725
|
switch (provider) {
|
|
2683
2726
|
case "openai": {
|
|
2684
2727
|
const { OpenAIProvider: OpenAIProvider2 } = await Promise.resolve().then(() => (init_openai(), openai_exports));
|
|
@@ -2688,6 +2731,13 @@ async function createLLMProvider(config = {}) {
|
|
|
2688
2731
|
const { AnthropicProvider: AnthropicProvider2 } = await Promise.resolve().then(() => (init_anthropic(), anthropic_exports));
|
|
2689
2732
|
return new AnthropicProvider2(model);
|
|
2690
2733
|
}
|
|
2734
|
+
case "custom": {
|
|
2735
|
+
const { CustomProvider: CustomProvider2 } = await Promise.resolve().then(() => (init_custom(), custom_exports));
|
|
2736
|
+
const url = baseUrl ?? "http://localhost:1234/v1";
|
|
2737
|
+
const mdl = model ?? "default";
|
|
2738
|
+
const key = apiKey ?? "";
|
|
2739
|
+
return new CustomProvider2(url, mdl, key);
|
|
2740
|
+
}
|
|
2691
2741
|
case "ollama":
|
|
2692
2742
|
default: {
|
|
2693
2743
|
const { OllamaProvider: OllamaProvider2 } = await Promise.resolve().then(() => (init_ollama(), ollama_exports));
|
|
@@ -2821,109 +2871,6 @@ var init_db_manager = __esm({
|
|
|
2821
2871
|
}
|
|
2822
2872
|
});
|
|
2823
2873
|
|
|
2824
|
-
// src/multi-repo/group-registry.ts
|
|
2825
|
-
var group_registry_exports = {};
|
|
2826
|
-
__export(group_registry_exports, {
|
|
2827
|
-
addMember: () => addMember,
|
|
2828
|
-
deleteGroup: () => deleteGroup,
|
|
2829
|
-
groupExists: () => groupExists,
|
|
2830
|
-
listGroups: () => listGroups,
|
|
2831
|
-
loadGroup: () => loadGroup,
|
|
2832
|
-
loadSyncResult: () => loadSyncResult,
|
|
2833
|
-
removeMember: () => removeMember,
|
|
2834
|
-
saveGroup: () => saveGroup,
|
|
2835
|
-
saveSyncResult: () => saveSyncResult
|
|
2836
|
-
});
|
|
2837
|
-
function groupFile(name) {
|
|
2838
|
-
return path32.join(GROUPS_DIR, `${name}.json`);
|
|
2839
|
-
}
|
|
2840
|
-
function loadGroup(name) {
|
|
2841
|
-
try {
|
|
2842
|
-
return JSON.parse(fs26.readFileSync(groupFile(name), "utf-8"));
|
|
2843
|
-
} catch {
|
|
2844
|
-
return null;
|
|
2845
|
-
}
|
|
2846
|
-
}
|
|
2847
|
-
function saveGroup(group) {
|
|
2848
|
-
fs26.mkdirSync(GROUPS_DIR, { recursive: true });
|
|
2849
|
-
fs26.writeFileSync(groupFile(group.name), JSON.stringify(group, null, 2) + "\n");
|
|
2850
|
-
}
|
|
2851
|
-
function listGroups() {
|
|
2852
|
-
const groups = [];
|
|
2853
|
-
try {
|
|
2854
|
-
for (const file of fs26.readdirSync(GROUPS_DIR)) {
|
|
2855
|
-
if (!file.endsWith(".json") || file.endsWith(".sync.json")) continue;
|
|
2856
|
-
try {
|
|
2857
|
-
const g = JSON.parse(
|
|
2858
|
-
fs26.readFileSync(path32.join(GROUPS_DIR, file), "utf-8")
|
|
2859
|
-
);
|
|
2860
|
-
groups.push(g);
|
|
2861
|
-
} catch {
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
} catch {
|
|
2865
|
-
}
|
|
2866
|
-
return groups;
|
|
2867
|
-
}
|
|
2868
|
-
function deleteGroup(name) {
|
|
2869
|
-
try {
|
|
2870
|
-
fs26.unlinkSync(groupFile(name));
|
|
2871
|
-
} catch {
|
|
2872
|
-
}
|
|
2873
|
-
try {
|
|
2874
|
-
fs26.unlinkSync(path32.join(GROUPS_DIR, `${name}.sync.json`));
|
|
2875
|
-
} catch {
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
function groupExists(name) {
|
|
2879
|
-
return fs26.existsSync(groupFile(name));
|
|
2880
|
-
}
|
|
2881
|
-
function addMember(groupName, member) {
|
|
2882
|
-
const group = loadGroup(groupName);
|
|
2883
|
-
if (!group) throw new Error(`Group "${groupName}" not found.`);
|
|
2884
|
-
const idx = group.members.findIndex((m) => m.groupPath === member.groupPath);
|
|
2885
|
-
if (idx >= 0) {
|
|
2886
|
-
group.members[idx] = member;
|
|
2887
|
-
} else {
|
|
2888
|
-
group.members.push(member);
|
|
2889
|
-
}
|
|
2890
|
-
saveGroup(group);
|
|
2891
|
-
return group;
|
|
2892
|
-
}
|
|
2893
|
-
function removeMember(groupName, groupPath) {
|
|
2894
|
-
const group = loadGroup(groupName);
|
|
2895
|
-
if (!group) throw new Error(`Group "${groupName}" not found.`);
|
|
2896
|
-
const before = group.members.length;
|
|
2897
|
-
group.members = group.members.filter((m) => m.groupPath !== groupPath);
|
|
2898
|
-
if (group.members.length === before) {
|
|
2899
|
-
throw new Error(`No member at path "${groupPath}" in group "${groupName}".`);
|
|
2900
|
-
}
|
|
2901
|
-
saveGroup(group);
|
|
2902
|
-
return group;
|
|
2903
|
-
}
|
|
2904
|
-
function saveSyncResult(result) {
|
|
2905
|
-
fs26.mkdirSync(GROUPS_DIR, { recursive: true });
|
|
2906
|
-
fs26.writeFileSync(
|
|
2907
|
-
path32.join(GROUPS_DIR, `${result.groupName}.sync.json`),
|
|
2908
|
-
JSON.stringify(result, null, 2) + "\n"
|
|
2909
|
-
);
|
|
2910
|
-
}
|
|
2911
|
-
function loadSyncResult(groupName) {
|
|
2912
|
-
try {
|
|
2913
|
-
return JSON.parse(
|
|
2914
|
-
fs26.readFileSync(path32.join(GROUPS_DIR, `${groupName}.sync.json`), "utf-8")
|
|
2915
|
-
);
|
|
2916
|
-
} catch {
|
|
2917
|
-
return null;
|
|
2918
|
-
}
|
|
2919
|
-
}
|
|
2920
|
-
var GROUPS_DIR;
|
|
2921
|
-
var init_group_registry = __esm({
|
|
2922
|
-
"src/multi-repo/group-registry.ts"() {
|
|
2923
|
-
GROUPS_DIR = path32.join(os13.homedir(), ".code-intel", "groups");
|
|
2924
|
-
}
|
|
2925
|
-
});
|
|
2926
|
-
|
|
2927
2874
|
// src/multi-repo/graph-from-db.ts
|
|
2928
2875
|
var graph_from_db_exports = {};
|
|
2929
2876
|
__export(graph_from_db_exports, {
|
|
@@ -4585,6 +4532,7 @@ var init_codes = __esm({
|
|
|
4585
4532
|
RATE_LIMIT_EXCEEDED: "CI-1100",
|
|
4586
4533
|
PAYLOAD_TOO_LARGE: "CI-1101",
|
|
4587
4534
|
INVALID_REQUEST: "CI-1200",
|
|
4535
|
+
CONFLICT: "CI-1409",
|
|
4588
4536
|
// Config (CI-2xxx)
|
|
4589
4537
|
CONFIG_INVALID: "CI-2000",
|
|
4590
4538
|
CONFIG_NOT_FOUND: "CI-2001",
|
|
@@ -7611,9 +7559,90 @@ function getDbPath(repoDir) {
|
|
|
7611
7559
|
function getVectorDbPath(repoDir) {
|
|
7612
7560
|
return path32.join(repoDir, ".code-intel", "vector.db");
|
|
7613
7561
|
}
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7562
|
+
var GROUPS_DIR = path32.join(os13.homedir(), ".code-intel", "groups");
|
|
7563
|
+
function groupFile(name) {
|
|
7564
|
+
return path32.join(GROUPS_DIR, `${name}.json`);
|
|
7565
|
+
}
|
|
7566
|
+
function loadGroup(name) {
|
|
7567
|
+
try {
|
|
7568
|
+
return JSON.parse(fs26.readFileSync(groupFile(name), "utf-8"));
|
|
7569
|
+
} catch {
|
|
7570
|
+
return null;
|
|
7571
|
+
}
|
|
7572
|
+
}
|
|
7573
|
+
function saveGroup(group) {
|
|
7574
|
+
fs26.mkdirSync(GROUPS_DIR, { recursive: true });
|
|
7575
|
+
fs26.writeFileSync(groupFile(group.name), JSON.stringify(group, null, 2) + "\n");
|
|
7576
|
+
}
|
|
7577
|
+
function listGroups() {
|
|
7578
|
+
const groups = [];
|
|
7579
|
+
try {
|
|
7580
|
+
for (const file of fs26.readdirSync(GROUPS_DIR)) {
|
|
7581
|
+
if (!file.endsWith(".json") || file.endsWith(".sync.json")) continue;
|
|
7582
|
+
try {
|
|
7583
|
+
const g = JSON.parse(
|
|
7584
|
+
fs26.readFileSync(path32.join(GROUPS_DIR, file), "utf-8")
|
|
7585
|
+
);
|
|
7586
|
+
groups.push(g);
|
|
7587
|
+
} catch {
|
|
7588
|
+
}
|
|
7589
|
+
}
|
|
7590
|
+
} catch {
|
|
7591
|
+
}
|
|
7592
|
+
return groups;
|
|
7593
|
+
}
|
|
7594
|
+
function deleteGroup(name) {
|
|
7595
|
+
try {
|
|
7596
|
+
fs26.unlinkSync(groupFile(name));
|
|
7597
|
+
} catch {
|
|
7598
|
+
}
|
|
7599
|
+
try {
|
|
7600
|
+
fs26.unlinkSync(path32.join(GROUPS_DIR, `${name}.sync.json`));
|
|
7601
|
+
} catch {
|
|
7602
|
+
}
|
|
7603
|
+
}
|
|
7604
|
+
function groupExists(name) {
|
|
7605
|
+
return fs26.existsSync(groupFile(name));
|
|
7606
|
+
}
|
|
7607
|
+
function addMember(groupName, member) {
|
|
7608
|
+
const group = loadGroup(groupName);
|
|
7609
|
+
if (!group) throw new Error(`Group "${groupName}" not found.`);
|
|
7610
|
+
const idx = group.members.findIndex((m) => m.groupPath === member.groupPath);
|
|
7611
|
+
if (idx >= 0) {
|
|
7612
|
+
group.members[idx] = member;
|
|
7613
|
+
} else {
|
|
7614
|
+
group.members.push(member);
|
|
7615
|
+
}
|
|
7616
|
+
saveGroup(group);
|
|
7617
|
+
return group;
|
|
7618
|
+
}
|
|
7619
|
+
function removeMember(groupName, groupPath) {
|
|
7620
|
+
const group = loadGroup(groupName);
|
|
7621
|
+
if (!group) throw new Error(`Group "${groupName}" not found.`);
|
|
7622
|
+
const before = group.members.length;
|
|
7623
|
+
group.members = group.members.filter((m) => m.groupPath !== groupPath);
|
|
7624
|
+
if (group.members.length === before) {
|
|
7625
|
+
throw new Error(`No member at path "${groupPath}" in group "${groupName}".`);
|
|
7626
|
+
}
|
|
7627
|
+
saveGroup(group);
|
|
7628
|
+
return group;
|
|
7629
|
+
}
|
|
7630
|
+
function saveSyncResult(result) {
|
|
7631
|
+
fs26.mkdirSync(GROUPS_DIR, { recursive: true });
|
|
7632
|
+
fs26.writeFileSync(
|
|
7633
|
+
path32.join(GROUPS_DIR, `${result.groupName}.sync.json`),
|
|
7634
|
+
JSON.stringify(result, null, 2) + "\n"
|
|
7635
|
+
);
|
|
7636
|
+
}
|
|
7637
|
+
function loadSyncResult(groupName) {
|
|
7638
|
+
try {
|
|
7639
|
+
return JSON.parse(
|
|
7640
|
+
fs26.readFileSync(path32.join(GROUPS_DIR, `${groupName}.sync.json`), "utf-8")
|
|
7641
|
+
);
|
|
7642
|
+
} catch {
|
|
7643
|
+
return null;
|
|
7644
|
+
}
|
|
7645
|
+
}
|
|
7617
7646
|
init_db_manager();
|
|
7618
7647
|
init_knowledge_graph();
|
|
7619
7648
|
init_graph_from_db();
|
|
@@ -9992,7 +10021,6 @@ function parseDiff(diffText) {
|
|
|
9992
10021
|
}
|
|
9993
10022
|
return result;
|
|
9994
10023
|
}
|
|
9995
|
-
init_group_registry();
|
|
9996
10024
|
init_knowledge_graph();
|
|
9997
10025
|
init_graph_from_db();
|
|
9998
10026
|
init_logger();
|
|
@@ -12289,6 +12317,97 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
|
|
|
12289
12317
|
}
|
|
12290
12318
|
res.json(result);
|
|
12291
12319
|
});
|
|
12320
|
+
app.post("/api/v1/groups", requireAuth, requireRole("analyst"), (req, res) => {
|
|
12321
|
+
const { name } = req.body;
|
|
12322
|
+
if (!name || !name.trim()) {
|
|
12323
|
+
res.status(400).json({ error: { code: ErrorCodes.INVALID_REQUEST, message: "Group name is required" } });
|
|
12324
|
+
return;
|
|
12325
|
+
}
|
|
12326
|
+
const trimmed = name.trim();
|
|
12327
|
+
if (groupExists(trimmed)) {
|
|
12328
|
+
res.status(409).json({ error: { code: ErrorCodes.CONFLICT, message: `Group "${trimmed}" already exists` } });
|
|
12329
|
+
return;
|
|
12330
|
+
}
|
|
12331
|
+
const group = { name: trimmed, createdAt: (/* @__PURE__ */ new Date()).toISOString(), members: [] };
|
|
12332
|
+
saveGroup(group);
|
|
12333
|
+
res.status(201).json(group);
|
|
12334
|
+
});
|
|
12335
|
+
app.delete("/api/v1/groups/:name", requireAuth, requireRole("analyst"), (req, res) => {
|
|
12336
|
+
const groupName = req.params["name"];
|
|
12337
|
+
if (!groupExists(groupName)) {
|
|
12338
|
+
res.status(404).json({ error: { code: ErrorCodes.NOT_FOUND, message: "Group not found" } });
|
|
12339
|
+
return;
|
|
12340
|
+
}
|
|
12341
|
+
deleteGroup(groupName);
|
|
12342
|
+
res.status(204).end();
|
|
12343
|
+
});
|
|
12344
|
+
app.patch("/api/v1/groups/:name", requireAuth, requireRole("analyst"), (req, res) => {
|
|
12345
|
+
const groupName = req.params["name"];
|
|
12346
|
+
const group = loadGroup(groupName);
|
|
12347
|
+
if (!group) {
|
|
12348
|
+
res.status(404).json({ error: { code: ErrorCodes.NOT_FOUND, message: "Group not found" } });
|
|
12349
|
+
return;
|
|
12350
|
+
}
|
|
12351
|
+
const { name } = req.body;
|
|
12352
|
+
if (!name || !name.trim()) {
|
|
12353
|
+
res.status(400).json({ error: { code: ErrorCodes.INVALID_REQUEST, message: "New name is required" } });
|
|
12354
|
+
return;
|
|
12355
|
+
}
|
|
12356
|
+
const newName = name.trim();
|
|
12357
|
+
if (newName !== group.name && groupExists(newName)) {
|
|
12358
|
+
res.status(409).json({ error: { code: ErrorCodes.CONFLICT, message: `Group "${newName}" already exists` } });
|
|
12359
|
+
return;
|
|
12360
|
+
}
|
|
12361
|
+
if (newName !== group.name) {
|
|
12362
|
+
deleteGroup(group.name);
|
|
12363
|
+
group.name = newName;
|
|
12364
|
+
}
|
|
12365
|
+
saveGroup(group);
|
|
12366
|
+
res.json(group);
|
|
12367
|
+
});
|
|
12368
|
+
app.post("/api/v1/groups/:name/members", requireAuth, requireRole("analyst"), (req, res) => {
|
|
12369
|
+
const groupName = req.params["name"];
|
|
12370
|
+
const group = loadGroup(groupName);
|
|
12371
|
+
if (!group) {
|
|
12372
|
+
res.status(404).json({ error: { code: ErrorCodes.NOT_FOUND, message: "Group not found" } });
|
|
12373
|
+
return;
|
|
12374
|
+
}
|
|
12375
|
+
const { groupPath, registryName } = req.body;
|
|
12376
|
+
if (!groupPath || !registryName) {
|
|
12377
|
+
res.status(400).json({ error: { code: ErrorCodes.INVALID_REQUEST, message: "groupPath and registryName are required" } });
|
|
12378
|
+
return;
|
|
12379
|
+
}
|
|
12380
|
+
const registry = loadRegistry();
|
|
12381
|
+
if (!registry.find((r) => r.name === registryName)) {
|
|
12382
|
+
res.status(400).json({ error: { code: ErrorCodes.INVALID_REQUEST, message: `Repo "${registryName}" not found in registry. Run code-intel analyze first.` } });
|
|
12383
|
+
return;
|
|
12384
|
+
}
|
|
12385
|
+
try {
|
|
12386
|
+
const updated = addMember(groupName, { groupPath, registryName });
|
|
12387
|
+
res.json(updated);
|
|
12388
|
+
} catch (err) {
|
|
12389
|
+
res.status(400).json({ error: { code: ErrorCodes.INVALID_REQUEST, message: err instanceof Error ? err.message : String(err) } });
|
|
12390
|
+
}
|
|
12391
|
+
});
|
|
12392
|
+
app.delete("/api/v1/groups/:name/members", requireAuth, requireRole("analyst"), (req, res) => {
|
|
12393
|
+
const groupName = req.params["name"];
|
|
12394
|
+
const group = loadGroup(groupName);
|
|
12395
|
+
if (!group) {
|
|
12396
|
+
res.status(404).json({ error: { code: ErrorCodes.NOT_FOUND, message: "Group not found" } });
|
|
12397
|
+
return;
|
|
12398
|
+
}
|
|
12399
|
+
const { groupPath } = req.body;
|
|
12400
|
+
if (!groupPath) {
|
|
12401
|
+
res.status(400).json({ error: { code: ErrorCodes.INVALID_REQUEST, message: "groupPath is required" } });
|
|
12402
|
+
return;
|
|
12403
|
+
}
|
|
12404
|
+
try {
|
|
12405
|
+
const updated = removeMember(groupName, groupPath);
|
|
12406
|
+
res.json(updated);
|
|
12407
|
+
} catch (err) {
|
|
12408
|
+
res.status(400).json({ error: { code: ErrorCodes.INVALID_REQUEST, message: err instanceof Error ? err.message : String(err) } });
|
|
12409
|
+
}
|
|
12410
|
+
});
|
|
12292
12411
|
app.post("/api/v1/groups/:name/sync", async (req, res) => {
|
|
12293
12412
|
const group = loadGroup(req.params.name);
|
|
12294
12413
|
if (!group) {
|
|
@@ -12299,8 +12418,7 @@ function createApp(graph, repoName, workspaceRoot, watcherState) {
|
|
|
12299
12418
|
const result = await syncGroup(group);
|
|
12300
12419
|
saveSyncResult(result);
|
|
12301
12420
|
group.lastSync = result.syncedAt;
|
|
12302
|
-
|
|
12303
|
-
saveGroup2(group);
|
|
12421
|
+
saveGroup(group);
|
|
12304
12422
|
res.json(result);
|
|
12305
12423
|
} catch (err) {
|
|
12306
12424
|
res.status(500).json({ error: { code: ErrorCodes.INTERNAL_ERROR, message: err instanceof Error ? err.message : String(err) } });
|
|
@@ -12800,7 +12918,6 @@ async function startHttpServer(graph, repoName, port = 4747, workspaceRoot, watc
|
|
|
12800
12918
|
}
|
|
12801
12919
|
|
|
12802
12920
|
// src/multi-repo/index.ts
|
|
12803
|
-
init_group_registry();
|
|
12804
12921
|
init_graph_from_db();
|
|
12805
12922
|
|
|
12806
12923
|
// src/multi-repo/cross-repo-search.ts
|