shark-ai 0.2.0 → 0.2.1
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/dist/bin/shark.js +60 -93
- package/dist/bin/shark.js.map +1 -1
- package/dist/{chunk-4UPBRJYA.js → chunk-R3MIUNVD.js} +333 -174
- package/dist/chunk-R3MIUNVD.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-4UPBRJYA.js.map +0 -1
package/dist/bin/shark.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager,
|
|
4
|
+
FileLogger,
|
|
4
5
|
colors,
|
|
5
6
|
configCommand,
|
|
6
7
|
loginCommand,
|
|
7
8
|
tokenStorage,
|
|
8
9
|
tui
|
|
9
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-R3MIUNVD.js";
|
|
10
11
|
|
|
11
12
|
// src/core/error/crash-handler.ts
|
|
12
13
|
import fs from "fs";
|
|
@@ -267,41 +268,6 @@ var initCommand = new Command("init").description("Initialize a new Shark projec
|
|
|
267
268
|
// src/core/api/stackspot-client.ts
|
|
268
269
|
var STACKSPOT_AGENT_API_BASE = "https://genai-inference-app.stackspot.com";
|
|
269
270
|
|
|
270
|
-
// src/core/debug/file-logger.ts
|
|
271
|
-
import fs3 from "fs";
|
|
272
|
-
import path3 from "path";
|
|
273
|
-
var FileLogger = class {
|
|
274
|
-
static logPath = path3.resolve(process.cwd(), "shark-debug.log");
|
|
275
|
-
static enabled = true;
|
|
276
|
-
// Enabled by default for this debugging session
|
|
277
|
-
static init() {
|
|
278
|
-
try {
|
|
279
|
-
fs3.writeFileSync(this.logPath, `--- Shark CLI Debug Log Started at ${(/* @__PURE__ */ new Date()).toISOString()} ---
|
|
280
|
-
`);
|
|
281
|
-
} catch (e) {
|
|
282
|
-
console.error("Failed to initialize debug log:", e);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
static log(category, message, data) {
|
|
286
|
-
if (!this.enabled) return;
|
|
287
|
-
try {
|
|
288
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
289
|
-
let logEntry = `[${timestamp}] [${category.toUpperCase()}] ${message}
|
|
290
|
-
`;
|
|
291
|
-
if (data !== void 0) {
|
|
292
|
-
if (typeof data === "object") {
|
|
293
|
-
logEntry += JSON.stringify(data, null, 2) + "\n";
|
|
294
|
-
} else {
|
|
295
|
-
logEntry += String(data) + "\n";
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
logEntry += "-".repeat(40) + "\n";
|
|
299
|
-
fs3.appendFileSync(this.logPath, logEntry);
|
|
300
|
-
} catch (e) {
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
|
|
305
271
|
// src/core/api/sse-client.ts
|
|
306
272
|
var SSEClient = class {
|
|
307
273
|
/**
|
|
@@ -760,17 +726,17 @@ async function interactiveBusinessAnalyst() {
|
|
|
760
726
|
}
|
|
761
727
|
|
|
762
728
|
// src/core/agents/specification-agent.ts
|
|
763
|
-
import
|
|
729
|
+
import fs4 from "fs";
|
|
764
730
|
|
|
765
731
|
// src/core/agents/agent-tools.ts
|
|
766
|
-
import
|
|
767
|
-
import
|
|
732
|
+
import fs3 from "fs";
|
|
733
|
+
import path3 from "path";
|
|
768
734
|
import fg from "fast-glob";
|
|
769
735
|
function handleListFiles(dirPath) {
|
|
770
736
|
try {
|
|
771
|
-
const fullPath =
|
|
772
|
-
if (!
|
|
773
|
-
const items =
|
|
737
|
+
const fullPath = path3.resolve(process.cwd(), dirPath);
|
|
738
|
+
if (!fs3.existsSync(fullPath)) return `Error: Directory ${dirPath} does not exist.`;
|
|
739
|
+
const items = fs3.readdirSync(fullPath, { withFileTypes: true });
|
|
774
740
|
return items.map((item) => {
|
|
775
741
|
return `${item.isDirectory() ? "[DIR]" : "[FILE]"} ${item.name}`;
|
|
776
742
|
}).join("\n");
|
|
@@ -780,11 +746,11 @@ function handleListFiles(dirPath) {
|
|
|
780
746
|
}
|
|
781
747
|
function handleReadFile(filePath) {
|
|
782
748
|
try {
|
|
783
|
-
const fullPath =
|
|
784
|
-
if (!
|
|
785
|
-
const stats =
|
|
749
|
+
const fullPath = path3.resolve(process.cwd(), filePath);
|
|
750
|
+
if (!fs3.existsSync(fullPath)) return `Error: File ${filePath} does not exist.`;
|
|
751
|
+
const stats = fs3.statSync(fullPath);
|
|
786
752
|
if (stats.size > 100 * 1024) return `Error: File too large to read (${stats.size} bytes). Limit is 100KB.`;
|
|
787
|
-
return
|
|
753
|
+
return fs3.readFileSync(fullPath, "utf-8");
|
|
788
754
|
} catch (e) {
|
|
789
755
|
return `Error reading file: ${e.message}`;
|
|
790
756
|
}
|
|
@@ -799,11 +765,11 @@ function handleSearchFile(pattern) {
|
|
|
799
765
|
}
|
|
800
766
|
}
|
|
801
767
|
function startSmartReplace(filePath, newContent, targetContent, tui2) {
|
|
802
|
-
if (!
|
|
768
|
+
if (!fs3.existsSync(filePath)) {
|
|
803
769
|
tui2.log.error(`\u274C File not found for modification: ${filePath}`);
|
|
804
770
|
return false;
|
|
805
771
|
}
|
|
806
|
-
const currentFileContent =
|
|
772
|
+
const currentFileContent = fs3.readFileSync(filePath, "utf-8");
|
|
807
773
|
if (!currentFileContent.includes(targetContent)) {
|
|
808
774
|
tui2.log.error(`\u274C Target content not found in ${filePath}. Modification aborted.`);
|
|
809
775
|
console.log(colors.dim("--- Target Content Expected ---"));
|
|
@@ -816,7 +782,7 @@ function startSmartReplace(filePath, newContent, targetContent, tui2) {
|
|
|
816
782
|
return false;
|
|
817
783
|
}
|
|
818
784
|
const updatedContent = currentFileContent.replace(targetContent, newContent);
|
|
819
|
-
|
|
785
|
+
fs3.writeFileSync(filePath, updatedContent);
|
|
820
786
|
tui2.log.success(`\u2705 Smart Replace Applied: ${filePath}`);
|
|
821
787
|
return true;
|
|
822
788
|
}
|
|
@@ -877,21 +843,21 @@ async function interactiveSpecificationAgent(options = {}) {
|
|
|
877
843
|
let briefingContent = "";
|
|
878
844
|
let briefingPath = options.briefingPath;
|
|
879
845
|
if (!briefingPath) {
|
|
880
|
-
const files =
|
|
846
|
+
const files = fs4.readdirSync(process.cwd());
|
|
881
847
|
const defaultBriefing = files.find((f) => f.endsWith("_briefing.md"));
|
|
882
848
|
briefingPath = await tui.text({
|
|
883
849
|
message: "Path to Briefing file (Leave empty to skip)",
|
|
884
850
|
initialValue: defaultBriefing || "",
|
|
885
851
|
placeholder: "e.g., todo-list_briefing.md",
|
|
886
852
|
validate: (val) => {
|
|
887
|
-
if (val && !
|
|
853
|
+
if (val && !fs4.existsSync(val)) return "File not found";
|
|
888
854
|
}
|
|
889
855
|
});
|
|
890
856
|
}
|
|
891
857
|
if (tui.isCancel(briefingPath)) return;
|
|
892
858
|
if (briefingPath) {
|
|
893
859
|
try {
|
|
894
|
-
briefingContent =
|
|
860
|
+
briefingContent = fs4.readFileSync(briefingPath, "utf-8");
|
|
895
861
|
tui.log.info(`Loaded briefing: ${colors.bold(briefingPath)}`);
|
|
896
862
|
} catch (e) {
|
|
897
863
|
tui.log.error(`Failed to read briefing: ${e}`);
|
|
@@ -980,7 +946,7 @@ ${result}
|
|
|
980
946
|
if (action.path) {
|
|
981
947
|
try {
|
|
982
948
|
if (action.type === "create_file") {
|
|
983
|
-
|
|
949
|
+
fs4.writeFileSync(action.path, action.content || "");
|
|
984
950
|
tui.log.success(`\u2705 Created: ${action.path}`);
|
|
985
951
|
executionResults += `[Action create_file(${action.path})]: Success
|
|
986
952
|
|
|
@@ -992,14 +958,14 @@ ${result}
|
|
|
992
958
|
|
|
993
959
|
`;
|
|
994
960
|
} else {
|
|
995
|
-
|
|
961
|
+
fs4.writeFileSync(action.path, action.content || "");
|
|
996
962
|
tui.log.success(`\u2705 Overwritten: ${action.path}`);
|
|
997
963
|
executionResults += `[Action modify_file(${action.path})]: Success (Overwrite)
|
|
998
964
|
|
|
999
965
|
`;
|
|
1000
966
|
}
|
|
1001
967
|
} else if (action.type === "delete_file") {
|
|
1002
|
-
|
|
968
|
+
fs4.unlinkSync(action.path);
|
|
1003
969
|
tui.log.success(`\u2705 Deleted: ${action.path}`);
|
|
1004
970
|
executionResults += `[Action delete_file(${action.path})]: Success
|
|
1005
971
|
|
|
@@ -1119,8 +1085,8 @@ async function callSpecAgentApi(prompt, onChunk, agentId) {
|
|
|
1119
1085
|
import { Command as Command2 } from "commander";
|
|
1120
1086
|
|
|
1121
1087
|
// src/core/agents/scan-agent.ts
|
|
1122
|
-
import
|
|
1123
|
-
import
|
|
1088
|
+
import fs5 from "fs";
|
|
1089
|
+
import path4 from "path";
|
|
1124
1090
|
var AGENT_TYPE3 = "scan_agent";
|
|
1125
1091
|
var AGENT_ID3 = process.env.STACKSPOT_SCAN_AGENT_ID || "01KEQ9AHWB550J2244YBH3QATN";
|
|
1126
1092
|
async function interactiveScanAgent(options = {}) {
|
|
@@ -1131,29 +1097,29 @@ async function interactiveScanAgent(options = {}) {
|
|
|
1131
1097
|
const projectRoot = process.cwd();
|
|
1132
1098
|
let outputFile;
|
|
1133
1099
|
if (options.output) {
|
|
1134
|
-
outputFile =
|
|
1100
|
+
outputFile = path4.resolve(process.cwd(), options.output);
|
|
1135
1101
|
} else {
|
|
1136
|
-
const outputDir =
|
|
1137
|
-
if (!
|
|
1138
|
-
const stat =
|
|
1102
|
+
const outputDir = path4.resolve(projectRoot, "_sharkrc");
|
|
1103
|
+
if (!fs5.existsSync(outputDir)) {
|
|
1104
|
+
const stat = fs5.existsSync(outputDir) ? fs5.statSync(outputDir) : null;
|
|
1139
1105
|
if (stat && stat.isFile()) {
|
|
1140
1106
|
tui.log.warning(`Warning: '_sharkrc' exists as a file. Using '_bmad/project-context' instead to avoid overwrite.`);
|
|
1141
|
-
const fallbackDir =
|
|
1142
|
-
if (!
|
|
1143
|
-
outputFile =
|
|
1107
|
+
const fallbackDir = path4.resolve(projectRoot, "_bmad/project-context");
|
|
1108
|
+
if (!fs5.existsSync(fallbackDir)) fs5.mkdirSync(fallbackDir, { recursive: true });
|
|
1109
|
+
outputFile = path4.join(fallbackDir, "project-context.md");
|
|
1144
1110
|
} else {
|
|
1145
|
-
|
|
1146
|
-
outputFile =
|
|
1111
|
+
fs5.mkdirSync(outputDir, { recursive: true });
|
|
1112
|
+
outputFile = path4.join(outputDir, "project-context.md");
|
|
1147
1113
|
}
|
|
1148
1114
|
} else {
|
|
1149
|
-
|
|
1150
|
-
outputFile =
|
|
1115
|
+
fs5.mkdirSync(outputDir, { recursive: true });
|
|
1116
|
+
outputFile = path4.join(outputDir, "project-context.md");
|
|
1151
1117
|
}
|
|
1152
1118
|
}
|
|
1153
1119
|
tui.log.info(`Scanning project at: ${colors.bold(projectRoot)}`);
|
|
1154
1120
|
tui.log.info(`Output targeted at: ${colors.bold(outputFile)}`);
|
|
1155
1121
|
tui.log.info(`Language: ${colors.bold(language)}`);
|
|
1156
|
-
const configFileRelative =
|
|
1122
|
+
const configFileRelative = path4.relative(projectRoot, outputFile);
|
|
1157
1123
|
const superPrompt = `
|
|
1158
1124
|
You are the **Scan Agent**, an expert software architect and analyst.
|
|
1159
1125
|
Your mission is to explore this project's codebase and generate a comprehensive context file that will be used by other AI agents (specifically a Developer Agent) to understand how to work on this project.
|
|
@@ -1247,22 +1213,22 @@ ${result}
|
|
|
1247
1213
|
|
|
1248
1214
|
`;
|
|
1249
1215
|
} else if (action.type === "create_file" || action.type === "modify_file") {
|
|
1250
|
-
const resolvedActionPath =
|
|
1251
|
-
const resolvedTargetPath =
|
|
1216
|
+
const resolvedActionPath = path4.resolve(action.path || "");
|
|
1217
|
+
const resolvedTargetPath = path4.resolve(targetPath);
|
|
1252
1218
|
let isTarget = resolvedActionPath === resolvedTargetPath;
|
|
1253
|
-
if (!isTarget &&
|
|
1254
|
-
tui.log.warning(`Agent targeted '${action.path}' but we enforce '${
|
|
1219
|
+
if (!isTarget && path4.basename(action.path || "") === "project-context.md") {
|
|
1220
|
+
tui.log.warning(`Agent targeted '${action.path}' but we enforce '${path4.relative(process.cwd(), targetPath)}'. Redirecting write.`);
|
|
1255
1221
|
isTarget = true;
|
|
1256
1222
|
action.path = targetPath;
|
|
1257
1223
|
}
|
|
1258
1224
|
if (isTarget) {
|
|
1259
1225
|
const finalPath = targetPath;
|
|
1260
1226
|
if (action.type === "create_file") {
|
|
1261
|
-
|
|
1227
|
+
fs5.writeFileSync(finalPath, action.content || "");
|
|
1262
1228
|
tui.log.success(`\u2705 Generated Context: ${finalPath}`);
|
|
1263
1229
|
fileCreated = true;
|
|
1264
1230
|
} else {
|
|
1265
|
-
|
|
1231
|
+
fs5.writeFileSync(finalPath, action.content || "");
|
|
1266
1232
|
tui.log.success(`\u2705 Updated Context: ${finalPath}`);
|
|
1267
1233
|
fileCreated = true;
|
|
1268
1234
|
}
|
|
@@ -1356,8 +1322,8 @@ var scanCommand = new Command2("scan").description("Analyze the project and gene
|
|
|
1356
1322
|
import { Command as Command3 } from "commander";
|
|
1357
1323
|
|
|
1358
1324
|
// src/core/agents/developer-agent.ts
|
|
1359
|
-
import
|
|
1360
|
-
import
|
|
1325
|
+
import fs6 from "fs";
|
|
1326
|
+
import path5 from "path";
|
|
1361
1327
|
var AGENT_TYPE4 = "developer_agent";
|
|
1362
1328
|
var AGENT_ID4 = process.env.STACKSPOT_DEV_AGENT_ID || "01KEQCGJ65YENRA4QBXVN1YFFX";
|
|
1363
1329
|
async function interactiveDeveloperAgent(options = {}) {
|
|
@@ -1369,12 +1335,12 @@ async function interactiveDeveloperAgent(options = {}) {
|
|
|
1369
1335
|
}
|
|
1370
1336
|
const projectRoot = process.cwd();
|
|
1371
1337
|
let contextContent = "";
|
|
1372
|
-
const defaultContextPath =
|
|
1373
|
-
const specificContextPath = options.context ?
|
|
1374
|
-
if (
|
|
1338
|
+
const defaultContextPath = path5.resolve(projectRoot, "_sharkrc", "project-context.md");
|
|
1339
|
+
const specificContextPath = options.context ? path5.resolve(projectRoot, options.context) : defaultContextPath;
|
|
1340
|
+
if (fs6.existsSync(specificContextPath)) {
|
|
1375
1341
|
try {
|
|
1376
|
-
contextContent =
|
|
1377
|
-
tui.log.info(`\u{1F4D8} Context loaded from: ${colors.dim(
|
|
1342
|
+
contextContent = fs6.readFileSync(specificContextPath, "utf-8");
|
|
1343
|
+
tui.log.info(`\u{1F4D8} Context loaded from: ${colors.dim(path5.relative(projectRoot, specificContextPath))}`);
|
|
1378
1344
|
} catch (e) {
|
|
1379
1345
|
tui.log.warning(`Failed to read context file: ${e}`);
|
|
1380
1346
|
}
|
|
@@ -1466,11 +1432,11 @@ ${result}
|
|
|
1466
1432
|
});
|
|
1467
1433
|
if (confirm) {
|
|
1468
1434
|
if (filePath) {
|
|
1469
|
-
const targetPath =
|
|
1470
|
-
const dir =
|
|
1471
|
-
if (!
|
|
1435
|
+
const targetPath = path5.resolve(projectRoot, filePath);
|
|
1436
|
+
const dir = path5.dirname(targetPath);
|
|
1437
|
+
if (!fs6.existsSync(dir)) fs6.mkdirSync(dir, { recursive: true });
|
|
1472
1438
|
if (isCreate) {
|
|
1473
|
-
|
|
1439
|
+
fs6.writeFileSync(targetPath, action.content || "");
|
|
1474
1440
|
tui.log.success(`\u2705 Created: ${filePath}`);
|
|
1475
1441
|
executionResults += `[Action create_file(${filePath})]: Success
|
|
1476
1442
|
|
|
@@ -1540,6 +1506,7 @@ User Reply: ${userReply}`;
|
|
|
1540
1506
|
} catch (e) {
|
|
1541
1507
|
spinner.stop("Error");
|
|
1542
1508
|
tui.log.error(e.message);
|
|
1509
|
+
FileLogger.log("DEV_AGENT", "Main Loop Error", e);
|
|
1543
1510
|
keepGoing = false;
|
|
1544
1511
|
}
|
|
1545
1512
|
}
|
|
@@ -1593,8 +1560,8 @@ var devCommand = new Command3("dev").description("Starts the Shark Developer Age
|
|
|
1593
1560
|
import { Command as Command4 } from "commander";
|
|
1594
1561
|
|
|
1595
1562
|
// src/core/agents/qa-agent.ts
|
|
1596
|
-
import
|
|
1597
|
-
import
|
|
1563
|
+
import fs7 from "fs";
|
|
1564
|
+
import path6 from "path";
|
|
1598
1565
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
1599
1566
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
1600
1567
|
var AGENT_TYPE5 = "qa_agent";
|
|
@@ -1658,9 +1625,9 @@ async function runQAAgent(options) {
|
|
|
1658
1625
|
}
|
|
1659
1626
|
let projectContext = "";
|
|
1660
1627
|
try {
|
|
1661
|
-
const contextPath =
|
|
1662
|
-
if (
|
|
1663
|
-
projectContext =
|
|
1628
|
+
const contextPath = path6.join(process.cwd(), "_sharkrc", "project-context.md");
|
|
1629
|
+
if (fs7.existsSync(contextPath)) {
|
|
1630
|
+
projectContext = fs7.readFileSync(contextPath, "utf-8");
|
|
1664
1631
|
tui.log.info(`\u{1F4D8} Context loaded from: _sharkrc/project-context.md`);
|
|
1665
1632
|
}
|
|
1666
1633
|
} catch (e) {
|
|
@@ -1769,8 +1736,8 @@ ${projectContext}
|
|
|
1769
1736
|
break;
|
|
1770
1737
|
case "create_file":
|
|
1771
1738
|
if (action.path && action.content) {
|
|
1772
|
-
const fullPath =
|
|
1773
|
-
|
|
1739
|
+
const fullPath = path6.resolve(process.cwd(), action.path);
|
|
1740
|
+
fs7.writeFileSync(fullPath, action.content);
|
|
1774
1741
|
tui.log.success(`File created: ${action.path}`);
|
|
1775
1742
|
result = "File created successfully.";
|
|
1776
1743
|
}
|