@jvittechs/jai1-cli 1.0.1 → 1.0.3
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/cli.js +77 -30
- package/dist/cli.js.map +1 -1
- package/package.json +12 -12
- package/scripts/redmine-sync-issue.sh +0 -0
package/dist/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ var NetworkError = class extends Jai1Error {
|
|
|
33
33
|
// package.json
|
|
34
34
|
var package_default = {
|
|
35
35
|
name: "@jvittechs/jai1-cli",
|
|
36
|
-
version: "1.0.
|
|
36
|
+
version: "1.0.3",
|
|
37
37
|
description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Please contact TeamAI for usage instructions.",
|
|
38
38
|
type: "module",
|
|
39
39
|
bin: {
|
|
@@ -969,24 +969,24 @@ trigger: ${trigger}
|
|
|
969
969
|
name: "OpenCode",
|
|
970
970
|
icon: "\u{1F4BB}",
|
|
971
971
|
basePath: ".opencode",
|
|
972
|
-
rulesPath:
|
|
973
|
-
|
|
974
|
-
|
|
972
|
+
rulesPath: null,
|
|
973
|
+
// OpenCode uses AGENTS.md for rules
|
|
974
|
+
workflowsPath: null,
|
|
975
|
+
commandsPath: "command",
|
|
976
|
+
// Note: singular "command" not "commands"
|
|
975
977
|
fileExtension: ".md",
|
|
976
978
|
generateFrontmatter: (opts) => {
|
|
977
|
-
|
|
978
|
-
if (opts.
|
|
979
|
-
|
|
980
|
-
} else if (opts.alwaysApply) {
|
|
981
|
-
trigger = "always_on";
|
|
982
|
-
} else if (opts.globs && opts.globs.length > 0) {
|
|
983
|
-
trigger = opts.globs[0];
|
|
984
|
-
} else {
|
|
985
|
-
trigger = "always_on";
|
|
979
|
+
const lines = ["---"];
|
|
980
|
+
if (opts.description) {
|
|
981
|
+
lines.push(`description: ${opts.description}`);
|
|
986
982
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
983
|
+
const agent = opts.agent ?? "code";
|
|
984
|
+
lines.push(`agent: ${agent}`);
|
|
985
|
+
if (opts.model) {
|
|
986
|
+
lines.push(`model: ${opts.model}`);
|
|
987
|
+
}
|
|
988
|
+
lines.push("---");
|
|
989
|
+
return lines.join("\n");
|
|
990
990
|
}
|
|
991
991
|
}
|
|
992
992
|
};
|
|
@@ -1031,7 +1031,8 @@ var MigrateIdeService = class {
|
|
|
1031
1031
|
}
|
|
1032
1032
|
const files = await fs4.readdir(presetDir);
|
|
1033
1033
|
for (const file of files) {
|
|
1034
|
-
if (!file.endsWith(".mdc")) continue;
|
|
1034
|
+
if (!file.endsWith(".md") && !file.endsWith(".mdc")) continue;
|
|
1035
|
+
if (file === "preset.json") continue;
|
|
1035
1036
|
const filepath = path.join(presetDir, file);
|
|
1036
1037
|
const stat = await fs4.stat(filepath);
|
|
1037
1038
|
if (!stat.isFile()) continue;
|
|
@@ -1042,7 +1043,7 @@ var MigrateIdeService = class {
|
|
|
1042
1043
|
frontmatter = data;
|
|
1043
1044
|
} catch {
|
|
1044
1045
|
}
|
|
1045
|
-
const name = path.basename(file, ".mdc");
|
|
1046
|
+
const name = file.endsWith(".mdc") ? path.basename(file, ".mdc") : path.basename(file, ".md");
|
|
1046
1047
|
const trigger = this.extractTrigger(frontmatter);
|
|
1047
1048
|
const alwaysApply = this.isAlwaysTrigger(trigger);
|
|
1048
1049
|
items.push({
|
|
@@ -1404,7 +1405,7 @@ var UnifiedApplyApp = ({
|
|
|
1404
1405
|
}, [components, searchQuery, activePackageFilter]);
|
|
1405
1406
|
useInput((input5, key) => {
|
|
1406
1407
|
if (viewState === "done") {
|
|
1407
|
-
if (key.return || input5 === "q" || key.escape) {
|
|
1408
|
+
if (key.return || input5 === "q" && key.ctrl || key.escape) {
|
|
1408
1409
|
onExit();
|
|
1409
1410
|
}
|
|
1410
1411
|
return;
|
|
@@ -1412,7 +1413,7 @@ var UnifiedApplyApp = ({
|
|
|
1412
1413
|
if (viewState === "summary") {
|
|
1413
1414
|
if (key.return) {
|
|
1414
1415
|
setViewState("ide-sync");
|
|
1415
|
-
} else if (input5 === "s" || input5 === "q" || key.escape) {
|
|
1416
|
+
} else if (input5 === "s" || input5 === "q" && key.ctrl || key.escape) {
|
|
1416
1417
|
onExit();
|
|
1417
1418
|
}
|
|
1418
1419
|
return;
|
|
@@ -1443,7 +1444,7 @@ var UnifiedApplyApp = ({
|
|
|
1443
1444
|
if (selectedIdes.size > 0) {
|
|
1444
1445
|
handleIdeSync();
|
|
1445
1446
|
}
|
|
1446
|
-
} else if (input5 === "s" || input5 === "q" || key.escape) {
|
|
1447
|
+
} else if (input5 === "s" || input5 === "q" && key.ctrl || key.escape) {
|
|
1447
1448
|
onExit();
|
|
1448
1449
|
}
|
|
1449
1450
|
return;
|
|
@@ -1467,7 +1468,7 @@ var UnifiedApplyApp = ({
|
|
|
1467
1468
|
}
|
|
1468
1469
|
return;
|
|
1469
1470
|
}
|
|
1470
|
-
if (key.escape || input5 === "q") {
|
|
1471
|
+
if (key.escape || input5 === "q" && key.ctrl) {
|
|
1471
1472
|
onExit();
|
|
1472
1473
|
return;
|
|
1473
1474
|
}
|
|
@@ -1629,7 +1630,7 @@ var UnifiedApplyApp = ({
|
|
|
1629
1630
|
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "\u{1F4E6} Installing Components")), /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(ProgressBar, { current: installStats.completed, total: installStats.total, width: 50 })), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1, height: 10 }, installProgress.slice(-8).map((item) => /* @__PURE__ */ React3.createElement(Box2, { key: item.filepath }, /* @__PURE__ */ React3.createElement(StatusIcon, { status: item.status === "success" ? "success" : item.status === "error" ? "error" : item.status === "downloading" ? "loading" : "pending" }), /* @__PURE__ */ React3.createElement(Text3, null, " ", item.filepath), item.error && /* @__PURE__ */ React3.createElement(Text3, { color: "red", dimColor: true }, " (", item.error, ")")))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4CA} ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, installStats.added, " added"), " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, installStats.updated, " updated"), " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, installStats.failed, " failed"))));
|
|
1630
1631
|
}
|
|
1631
1632
|
if (viewState === "summary") {
|
|
1632
|
-
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "\u2705 Installation Complete!")), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, installStats.total, " components processed:"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, installStats.added), " newly added"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, installStats.updated), " updated"), installStats.failed > 0 && /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, installStats.failed), " failed")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4C1} Location: ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, process.cwd(), "/.jai1"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "yellow" }, "\u{1F4E6} Next Step: Sync to IDE(s)?"), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "Sync .jai1/ content to your IDE directories (rules, workflows)")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[Enter] Select IDE(s) to sync \xB7 [S/Q] Skip and exit")));
|
|
1633
|
+
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "\u2705 Installation Complete!")), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, installStats.total, " components processed:"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, installStats.added), " newly added"), /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, installStats.updated), " updated"), installStats.failed > 0 && /* @__PURE__ */ React3.createElement(Text3, null, " \u2514\u2500 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, installStats.failed), " failed")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4C1} Location: ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, process.cwd(), "/.jai1"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "yellow" }, "\u{1F4E6} Next Step: Sync to IDE(s)?"), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "Sync .jai1/ content to your IDE directories (rules, workflows)")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[Enter] Select IDE(s) to sync \xB7 [S/Ctrl+Q] Skip and exit")));
|
|
1633
1634
|
}
|
|
1634
1635
|
if (viewState === "ide-sync") {
|
|
1635
1636
|
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "\u{1F504} Select IDE(s) to Sync")), /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "Sync .jai1/ content (rules, workflows) to IDE-specific directories")), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1 }, availableIdes.map((ide, i) => {
|
|
@@ -1637,7 +1638,7 @@ var UnifiedApplyApp = ({
|
|
|
1637
1638
|
const isCursor = i === ideCursorIndex;
|
|
1638
1639
|
const isChecked = selectedIdes.has(ide);
|
|
1639
1640
|
return /* @__PURE__ */ React3.createElement(Box2, { key: ide }, /* @__PURE__ */ React3.createElement(Text3, { color: isCursor ? "cyan" : "white" }, isCursor ? "\u276F " : " ", isChecked ? "[\u2713]" : "[ ]", " ", ideConfig.icon, " ", ideConfig.name));
|
|
1640
|
-
})), selectedIdes.size > 0 && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "Selected: ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, selectedIdes.size), " IDE(s)")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[\u2191\u2193] Navigate \xB7 [\u2423] Toggle \xB7 [A] Select all \xB7 [C] Clear \xB7 [Enter] Sync \xB7 [S/Q] Skip")));
|
|
1641
|
+
})), selectedIdes.size > 0 && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "Selected: ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, selectedIdes.size), " IDE(s)")), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "[\u2191\u2193] Navigate \xB7 [\u2423] Toggle \xB7 [A] Select all \xB7 [C] Clear \xB7 [Enter] Sync \xB7 [S/Ctrl+Q] Skip")));
|
|
1641
1642
|
}
|
|
1642
1643
|
if (viewState === "syncing") {
|
|
1643
1644
|
return /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "cyan" }, "\u{1F504} Syncing to IDE(s)")), /* @__PURE__ */ React3.createElement(Box2, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(ProgressBar, { current: syncStats.completed, total: syncStats.total, width: 50 })), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 1, height: 10 }, syncProgress.slice(-8).map((item, idx) => /* @__PURE__ */ React3.createElement(Box2, { key: `${item.targetPath}-${idx}` }, /* @__PURE__ */ React3.createElement(StatusIcon, { status: item.status === "success" ? "success" : item.status === "error" ? "error" : item.status === "syncing" ? "loading" : "pending" }), /* @__PURE__ */ React3.createElement(Text3, null, " ", item.targetPath), item.error && /* @__PURE__ */ React3.createElement(Text3, { color: "red", dimColor: true }, " (", item.error, ")")))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, "\u{1F4CA} ", /* @__PURE__ */ React3.createElement(Text3, { color: "green" }, syncStats.created, " created"), " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "cyan" }, syncStats.updated, " updated"), syncStats.skipped > 0 && /* @__PURE__ */ React3.createElement(React3.Fragment, null, " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "yellow" }, syncStats.skipped, " skipped")), syncStats.errors > 0 && /* @__PURE__ */ React3.createElement(React3.Fragment, null, " \xB7 ", /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, syncStats.errors, " errors")))));
|
|
@@ -1673,7 +1674,7 @@ var UnifiedApplyApp = ({
|
|
|
1673
1674
|
const isChecked = selectedPaths.has(comp.filepath);
|
|
1674
1675
|
const isInstalled = installedPaths.has(comp.filepath);
|
|
1675
1676
|
return /* @__PURE__ */ React3.createElement(Box2, { key: comp.filepath }, /* @__PURE__ */ React3.createElement(Text3, { color: isCursor ? "cyan" : "white" }, isCursor ? "\u276F " : " ", isChecked ? "[\u2713]" : "[ ]", " ", comp.filepath), /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " ", isInstalled ? "\u2713 installed" : "\u25CB new"));
|
|
1676
|
-
}), filteredComponents.length === 0 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No components match your search")), selectedPaths.size > 0 && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Selected: ", selectedPaths.size, " components"), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2 }, Array.from(selectedPaths).slice(0, 4).map((fp) => /* @__PURE__ */ React3.createElement(Text3, { key: fp, dimColor: true }, "\u{1F4CC} ", fp)), selectedPaths.size > 4 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " ... and ", selectedPaths.size - 4, " more"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, focusArea === "packages" && "[\u2190\u2192] Browse packages \xB7 [\u2423/Enter] Select package", focusArea === "components" && "[\u2191\u2193] Navigate \xB7 [\u2423] Toggle", focusArea === "search" && "Type to search...", " \xB7 [Tab] Switch area \xB7 [A] All \xB7 [C] Clear \xB7 [Enter] Apply \xB7 [Q] Quit")));
|
|
1677
|
+
}), filteredComponents.length === 0 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "No components match your search")), selectedPaths.size > 0 && /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React3.createElement(Text3, { bold: true }, "Selected: ", selectedPaths.size, " components"), /* @__PURE__ */ React3.createElement(Box2, { flexDirection: "column", marginLeft: 2 }, Array.from(selectedPaths).slice(0, 4).map((fp) => /* @__PURE__ */ React3.createElement(Text3, { key: fp, dimColor: true }, "\u{1F4CC} ", fp)), selectedPaths.size > 4 && /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, " ... and ", selectedPaths.size - 4, " more"))), /* @__PURE__ */ React3.createElement(Box2, { marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, focusArea === "packages" && "[\u2190\u2192] Browse packages \xB7 [\u2423/Enter] Select package", focusArea === "components" && "[\u2191\u2193] Navigate \xB7 [\u2423] Toggle", focusArea === "search" && "Type to search...", " \xB7 [Tab] Switch area \xB7 [A] All \xB7 [C] Clear \xB7 [Enter] Apply \xB7 [Ctrl+Q] Quit")));
|
|
1677
1678
|
};
|
|
1678
1679
|
|
|
1679
1680
|
// src/commands/apply.ts
|
|
@@ -3355,6 +3356,19 @@ var IDE_FORMATS = {
|
|
|
3355
3356
|
supportsReference: false,
|
|
3356
3357
|
dependencies: ["agentsmd"]
|
|
3357
3358
|
// Gemini requires AGENTS.md
|
|
3359
|
+
},
|
|
3360
|
+
opencode: {
|
|
3361
|
+
id: "opencode",
|
|
3362
|
+
name: "OpenCode",
|
|
3363
|
+
description: "OpenCode (AGENTS.md + .opencode/command/)",
|
|
3364
|
+
rulesPath: ".",
|
|
3365
|
+
// Uses AGENTS.md
|
|
3366
|
+
workflowsPath: ".opencode/command",
|
|
3367
|
+
fileExtension: ".md",
|
|
3368
|
+
metadataFormat: "yaml-frontmatter",
|
|
3369
|
+
supportsReference: true,
|
|
3370
|
+
dependencies: ["agentsmd"]
|
|
3371
|
+
// OpenCode requires AGENTS.md for rules
|
|
3358
3372
|
}
|
|
3359
3373
|
};
|
|
3360
3374
|
|
|
@@ -3405,6 +3419,20 @@ var IdeDetectionService = class {
|
|
|
3405
3419
|
detection.confidence = exists ? "high" : "low";
|
|
3406
3420
|
return detection;
|
|
3407
3421
|
}
|
|
3422
|
+
if (ideId === "opencode") {
|
|
3423
|
+
const hasAgents = await this.pathExists("AGENTS.md");
|
|
3424
|
+
const commandPath = join4(this.projectPath, ".opencode/command");
|
|
3425
|
+
const hasCommands = await this.pathExists(commandPath);
|
|
3426
|
+
detection.hasRules = hasAgents;
|
|
3427
|
+
detection.ruleCount = hasAgents ? 1 : 0;
|
|
3428
|
+
if (hasCommands) {
|
|
3429
|
+
detection.hasWorkflows = true;
|
|
3430
|
+
detection.workflowCount = await this.countFiles(commandPath, ".md");
|
|
3431
|
+
}
|
|
3432
|
+
detection.detected = hasAgents || hasCommands && detection.workflowCount > 0;
|
|
3433
|
+
detection.confidence = detection.detected ? hasAgents && hasCommands ? "high" : "medium" : "low";
|
|
3434
|
+
return detection;
|
|
3435
|
+
}
|
|
3408
3436
|
const rulesPath = join4(this.projectPath, format.rulesPath);
|
|
3409
3437
|
const rulesExist = await this.pathExists(rulesPath);
|
|
3410
3438
|
if (rulesExist) {
|
|
@@ -3480,6 +3508,13 @@ var IdeDetectionService = class {
|
|
|
3480
3508
|
if (await this.pathExists("GEMINI.md")) {
|
|
3481
3509
|
detected.push(ideId);
|
|
3482
3510
|
}
|
|
3511
|
+
} else if (ideId === "opencode") {
|
|
3512
|
+
const hasAgents = await this.pathExists("AGENTS.md");
|
|
3513
|
+
const commandPath = join4(this.projectPath, ".opencode/command");
|
|
3514
|
+
const hasCommands = await this.pathExists(commandPath);
|
|
3515
|
+
if (hasAgents || hasCommands) {
|
|
3516
|
+
detected.push(ideId);
|
|
3517
|
+
}
|
|
3483
3518
|
} else {
|
|
3484
3519
|
const rulesPath = join4(this.projectPath, format.rulesPath);
|
|
3485
3520
|
if (await this.pathExists(rulesPath)) {
|
|
@@ -3573,6 +3608,15 @@ var IdeDetectionService = class {
|
|
|
3573
3608
|
priority: "high"
|
|
3574
3609
|
});
|
|
3575
3610
|
}
|
|
3611
|
+
const hasOpenCodeConfig = await this.pathExists(join4(this.projectPath, ".opencode"));
|
|
3612
|
+
if (hasOpenCodeConfig) {
|
|
3613
|
+
suggestions.push({
|
|
3614
|
+
ideId: "opencode",
|
|
3615
|
+
name: "OpenCode",
|
|
3616
|
+
reason: ".opencode directory detected",
|
|
3617
|
+
priority: "high"
|
|
3618
|
+
});
|
|
3619
|
+
}
|
|
3576
3620
|
return suggestions;
|
|
3577
3621
|
}
|
|
3578
3622
|
};
|
|
@@ -3624,6 +3668,8 @@ async function runStatus(options) {
|
|
|
3624
3668
|
console.log(` Location: AGENTS.md`);
|
|
3625
3669
|
} else if (ide.id === "gemini") {
|
|
3626
3670
|
console.log(` Location: GEMINI.md`);
|
|
3671
|
+
} else if (ide.id === "opencode") {
|
|
3672
|
+
console.log(` Location: AGENTS.md + .opencode/command/`);
|
|
3627
3673
|
} else {
|
|
3628
3674
|
console.log(` Location: ${format.rulesPath}/`);
|
|
3629
3675
|
}
|
|
@@ -3851,7 +3897,7 @@ var Footer = ({ focusArea, isSearchOpen = false }) => {
|
|
|
3851
3897
|
{ key: "Enter", action: "Select" },
|
|
3852
3898
|
{ key: "\u2192/Tab", action: "Content" },
|
|
3853
3899
|
{ key: "/", action: "Search" },
|
|
3854
|
-
{ key: "q", action: "Quit" }
|
|
3900
|
+
{ key: "Ctrl+q", action: "Quit" }
|
|
3855
3901
|
];
|
|
3856
3902
|
}
|
|
3857
3903
|
return [
|
|
@@ -10178,7 +10224,7 @@ var UtilsApp = ({ onExit }) => {
|
|
|
10178
10224
|
setSelectedIndex((prev) => prev < MENU_ITEMS2.length - 1 ? prev + 1 : 0);
|
|
10179
10225
|
} else if (key.return) {
|
|
10180
10226
|
setActiveView(MENU_ITEMS2[selectedIndex].id);
|
|
10181
|
-
} else if (input5 === "q" || key.escape) {
|
|
10227
|
+
} else if (input5 === "q" && key.ctrl || key.escape) {
|
|
10182
10228
|
onExit();
|
|
10183
10229
|
exit();
|
|
10184
10230
|
}
|
|
@@ -10193,7 +10239,7 @@ var UtilsApp = ({ onExit }) => {
|
|
|
10193
10239
|
marginBottom: 1
|
|
10194
10240
|
},
|
|
10195
10241
|
/* @__PURE__ */ React41.createElement(Text36, { bold: true, color: "cyan" }, "\u{1F6E0}\uFE0F Developer Utilities - Interactive Mode"),
|
|
10196
|
-
/* @__PURE__ */ React41.createElement(Box36, { marginLeft: "auto" }, /* @__PURE__ */ React41.createElement(Text36, { dimColor: true }, "Press
|
|
10242
|
+
/* @__PURE__ */ React41.createElement(Box36, { marginLeft: "auto" }, /* @__PURE__ */ React41.createElement(Text36, { dimColor: true }, "Press Ctrl+Q to quit"))
|
|
10197
10243
|
), /* @__PURE__ */ React41.createElement(Box36, { flexGrow: 1 }, /* @__PURE__ */ React41.createElement(
|
|
10198
10244
|
Box36,
|
|
10199
10245
|
{
|
|
@@ -10252,7 +10298,7 @@ var WelcomeView = ({ selectedItem }) => {
|
|
|
10252
10298
|
marginBottom: 2
|
|
10253
10299
|
},
|
|
10254
10300
|
/* @__PURE__ */ React41.createElement(Box36, { flexDirection: "column" }, /* @__PURE__ */ React41.createElement(Text36, { bold: true, color: "yellow" }, selectedItem.icon, " ", selectedItem.label), /* @__PURE__ */ React41.createElement(Text36, { dimColor: true }, selectedItem.description))
|
|
10255
|
-
), /* @__PURE__ */ React41.createElement(Box36, { marginBottom: 1 }, /* @__PURE__ */ React41.createElement(Text36, { bold: true }, "Quick Actions:")), /* @__PURE__ */ React41.createElement(Box36, { flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Press ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "Enter"), " to open selected utility"), /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Use ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "\u2191/\u2193"), " or ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "j/k"), " to navigate"), /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Press ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "Esc"), " to go back or quit"), /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Press ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "
|
|
10301
|
+
), /* @__PURE__ */ React41.createElement(Box36, { marginBottom: 1 }, /* @__PURE__ */ React41.createElement(Text36, { bold: true }, "Quick Actions:")), /* @__PURE__ */ React41.createElement(Box36, { flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Press ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "Enter"), " to open selected utility"), /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Use ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "\u2191/\u2193"), " or ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "j/k"), " to navigate"), /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Press ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "Esc"), " to go back or quit"), /* @__PURE__ */ React41.createElement(Text36, null, "\u2022 Press ", /* @__PURE__ */ React41.createElement(Text36, { color: "green" }, "Ctrl+Q"), " to quit anytime")), /* @__PURE__ */ React41.createElement(Box36, { marginTop: 2 }, /* @__PURE__ */ React41.createElement(Text36, { dimColor: true }, "\u{1F4A1} Tip: Each utility provides an interactive interface for easy usage.")));
|
|
10256
10302
|
};
|
|
10257
10303
|
var ActiveUtilityView = ({ utilityType }) => {
|
|
10258
10304
|
switch (utilityType) {
|
|
@@ -11645,7 +11691,8 @@ function createKitCreateCommand() {
|
|
|
11645
11691
|
{ name: "Cursor", value: "cursor" },
|
|
11646
11692
|
{ name: "Windsurf", value: "windsurf" },
|
|
11647
11693
|
{ name: "Claude Code", value: "claude-code" },
|
|
11648
|
-
{ name: "Antigravity", value: "antigravity" }
|
|
11694
|
+
{ name: "Antigravity", value: "antigravity" },
|
|
11695
|
+
{ name: "OpenCode", value: "opencode" }
|
|
11649
11696
|
];
|
|
11650
11697
|
let selectedIdes = [];
|
|
11651
11698
|
if (isAutoMode) {
|