@agi_inc/cli 0.5.9 → 0.5.11
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/index.mjs +747 -81
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/index.tsx
|
|
2
2
|
import React10 from "react";
|
|
3
3
|
import { render } from "ink";
|
|
4
|
-
import { isBinaryAvailable } from "@agi_inc/agi-js";
|
|
4
|
+
import { isBinaryAvailable as isBinaryAvailable2 } from "@agi_inc/agi-js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
7
|
import yargs from "yargs";
|
|
@@ -288,7 +288,7 @@ async function parseArgs() {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
// src/app/App.tsx
|
|
291
|
-
import React9, { useEffect as useEffect5, useState as useState7, useCallback as useCallback3, useMemo as useMemo2 } from "react";
|
|
291
|
+
import React9, { useEffect as useEffect5, useState as useState7, useCallback as useCallback3, useMemo as useMemo2, useRef as useRef3 } from "react";
|
|
292
292
|
import { Box as Box8, Text as Text9, useApp } from "ink";
|
|
293
293
|
|
|
294
294
|
// src/hooks/useAgent.ts
|
|
@@ -674,8 +674,447 @@ import { Text as Text6, Box as Box5, useInput as useInput4 } from "ink";
|
|
|
674
674
|
import TextInput2 from "ink-text-input";
|
|
675
675
|
|
|
676
676
|
// src/commands/slash.ts
|
|
677
|
-
import { readFileSync as
|
|
678
|
-
import { basename } from "path";
|
|
677
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
678
|
+
import { basename as basename2 } from "path";
|
|
679
|
+
import os5 from "os";
|
|
680
|
+
import { isBinaryAvailable } from "@agi_inc/agi-js";
|
|
681
|
+
|
|
682
|
+
// src/history.ts
|
|
683
|
+
import fs2 from "fs";
|
|
684
|
+
import path2 from "path";
|
|
685
|
+
import os2 from "os";
|
|
686
|
+
var HISTORY_DIR = path2.join(os2.homedir(), ".agi");
|
|
687
|
+
var HISTORY_FILE = path2.join(HISTORY_DIR, "history.json");
|
|
688
|
+
var MAX_ENTRIES = 200;
|
|
689
|
+
function ensureDir() {
|
|
690
|
+
if (!fs2.existsSync(HISTORY_DIR)) {
|
|
691
|
+
fs2.mkdirSync(HISTORY_DIR, { recursive: true, mode: 448 });
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
function loadHistory() {
|
|
695
|
+
try {
|
|
696
|
+
const raw = fs2.readFileSync(HISTORY_FILE, "utf-8");
|
|
697
|
+
const data = JSON.parse(raw);
|
|
698
|
+
if (Array.isArray(data)) return data;
|
|
699
|
+
} catch {
|
|
700
|
+
}
|
|
701
|
+
return [];
|
|
702
|
+
}
|
|
703
|
+
function appendHistory(entry) {
|
|
704
|
+
ensureDir();
|
|
705
|
+
const history = loadHistory();
|
|
706
|
+
history.push(entry);
|
|
707
|
+
const trimmed = history.slice(-MAX_ENTRIES);
|
|
708
|
+
fs2.writeFileSync(HISTORY_FILE, JSON.stringify(trimmed, null, 2) + "\n", {
|
|
709
|
+
mode: 384
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
function clearHistory() {
|
|
713
|
+
try {
|
|
714
|
+
fs2.unlinkSync(HISTORY_FILE);
|
|
715
|
+
} catch {
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
function formatHistory(entries, limit = 20) {
|
|
719
|
+
if (entries.length === 0) return " No history yet.";
|
|
720
|
+
const recent = entries.slice(-limit).reverse();
|
|
721
|
+
const lines = ["", " Recent sessions:", ""];
|
|
722
|
+
for (const entry of recent) {
|
|
723
|
+
const date = new Date(entry.timestamp);
|
|
724
|
+
const timeStr = date.toLocaleDateString("en-US", {
|
|
725
|
+
month: "short",
|
|
726
|
+
day: "numeric"
|
|
727
|
+
}) + " " + date.toLocaleTimeString("en-US", {
|
|
728
|
+
hour: "2-digit",
|
|
729
|
+
minute: "2-digit",
|
|
730
|
+
hour12: false
|
|
731
|
+
});
|
|
732
|
+
const status = entry.success === true ? "\u25CF" : entry.success === false ? "\u2715" : "\u25CB";
|
|
733
|
+
const duration = entry.durationMs ? ` (${Math.round(entry.durationMs / 1e3)}s)` : "";
|
|
734
|
+
const goal = entry.goal.length > 55 ? entry.goal.slice(0, 55) + "\u2026" : entry.goal;
|
|
735
|
+
lines.push(` ${status} ${timeStr} ${goal}${duration}`);
|
|
736
|
+
}
|
|
737
|
+
lines.push("");
|
|
738
|
+
if (entries.length > limit) {
|
|
739
|
+
lines.push(` Showing ${limit} of ${entries.length} entries`);
|
|
740
|
+
lines.push("");
|
|
741
|
+
}
|
|
742
|
+
return lines.join("\n");
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// src/project.ts
|
|
746
|
+
import { readFileSync as readFileSync2, existsSync, readdirSync } from "fs";
|
|
747
|
+
import { join as join2, basename } from "path";
|
|
748
|
+
|
|
749
|
+
// src/skills.ts
|
|
750
|
+
import fs3 from "fs";
|
|
751
|
+
import path3 from "path";
|
|
752
|
+
import os3 from "os";
|
|
753
|
+
function parseFrontmatter(content) {
|
|
754
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
755
|
+
if (!match) return { meta: {}, body: content.trim() };
|
|
756
|
+
const meta = {};
|
|
757
|
+
for (const line of match[1].split("\n")) {
|
|
758
|
+
const colonIdx = line.indexOf(":");
|
|
759
|
+
if (colonIdx > 0) {
|
|
760
|
+
const key = line.slice(0, colonIdx).trim();
|
|
761
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
762
|
+
meta[key] = value;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return { meta, body: match[2].trim() };
|
|
766
|
+
}
|
|
767
|
+
var NAME_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
768
|
+
function isValidSkillName(name) {
|
|
769
|
+
if (name.length > 64) return false;
|
|
770
|
+
if (!NAME_RE.test(name)) return false;
|
|
771
|
+
if (name.includes("--")) return false;
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
function discoverSkillsInDir(skillsDir, scope) {
|
|
775
|
+
const skills = [];
|
|
776
|
+
if (!fs3.existsSync(skillsDir)) return skills;
|
|
777
|
+
let entries;
|
|
778
|
+
try {
|
|
779
|
+
entries = fs3.readdirSync(skillsDir);
|
|
780
|
+
} catch {
|
|
781
|
+
return skills;
|
|
782
|
+
}
|
|
783
|
+
for (const entry of entries) {
|
|
784
|
+
const skillDir = path3.join(skillsDir, entry);
|
|
785
|
+
const skillFile = path3.join(skillDir, "SKILL.md");
|
|
786
|
+
try {
|
|
787
|
+
if (!fs3.statSync(skillDir).isDirectory()) continue;
|
|
788
|
+
if (!fs3.existsSync(skillFile)) continue;
|
|
789
|
+
} catch {
|
|
790
|
+
continue;
|
|
791
|
+
}
|
|
792
|
+
if (!isValidSkillName(entry)) continue;
|
|
793
|
+
try {
|
|
794
|
+
const content = fs3.readFileSync(skillFile, "utf-8");
|
|
795
|
+
const { meta } = parseFrontmatter(content);
|
|
796
|
+
const name = meta["name"] || entry;
|
|
797
|
+
if (name !== entry) continue;
|
|
798
|
+
const description = meta["description"] || "";
|
|
799
|
+
if (!description) continue;
|
|
800
|
+
skills.push({
|
|
801
|
+
name,
|
|
802
|
+
description,
|
|
803
|
+
path: skillFile,
|
|
804
|
+
root: skillDir,
|
|
805
|
+
scope,
|
|
806
|
+
license: meta["license"],
|
|
807
|
+
compatibility: meta["compatibility"],
|
|
808
|
+
userInvocable: meta["user-invocable"] !== "false",
|
|
809
|
+
argumentHint: meta["argument-hint"],
|
|
810
|
+
metadata: Object.keys(meta).length > 0 ? meta : void 0
|
|
811
|
+
});
|
|
812
|
+
} catch {
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return skills;
|
|
816
|
+
}
|
|
817
|
+
function discoverSkills(cwd = process.cwd()) {
|
|
818
|
+
const personalDir = path3.join(os3.homedir(), ".agi", "skills");
|
|
819
|
+
const projectDir = path3.join(cwd, ".agi", "skills");
|
|
820
|
+
const personal = discoverSkillsInDir(personalDir, "personal");
|
|
821
|
+
const project = discoverSkillsInDir(projectDir, "project");
|
|
822
|
+
const byName = /* @__PURE__ */ new Map();
|
|
823
|
+
for (const skill of personal) byName.set(skill.name, skill);
|
|
824
|
+
for (const skill of project) byName.set(skill.name, skill);
|
|
825
|
+
return Array.from(byName.values());
|
|
826
|
+
}
|
|
827
|
+
function loadSkill(skill) {
|
|
828
|
+
const content = fs3.readFileSync(skill.path, "utf-8");
|
|
829
|
+
const { body } = parseFrontmatter(content);
|
|
830
|
+
return { ...skill, body };
|
|
831
|
+
}
|
|
832
|
+
function generateSkillsPrompt(skills) {
|
|
833
|
+
if (skills.length === 0) return "";
|
|
834
|
+
const lines = ["<available_skills>"];
|
|
835
|
+
for (const skill of skills) {
|
|
836
|
+
lines.push(" <skill>");
|
|
837
|
+
lines.push(` <name>${skill.name}</name>`);
|
|
838
|
+
lines.push(` <description>${skill.description}</description>`);
|
|
839
|
+
lines.push(` <location>${skill.path}</location>`);
|
|
840
|
+
lines.push(" </skill>");
|
|
841
|
+
}
|
|
842
|
+
lines.push("</available_skills>");
|
|
843
|
+
return lines.join("\n");
|
|
844
|
+
}
|
|
845
|
+
function formatSkillsList(skills) {
|
|
846
|
+
if (skills.length === 0) return " No skills found.";
|
|
847
|
+
const lines = ["", " Available skills:", ""];
|
|
848
|
+
for (const skill of skills) {
|
|
849
|
+
const scope = skill.scope === "personal" ? "~" : ".";
|
|
850
|
+
const hint = skill.argumentHint ? ` ${skill.argumentHint}` : "";
|
|
851
|
+
lines.push(` ${scope} /${skill.name}${hint}`);
|
|
852
|
+
lines.push(` ${skill.description}`);
|
|
853
|
+
}
|
|
854
|
+
lines.push("");
|
|
855
|
+
return lines.join("\n");
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// src/project.ts
|
|
859
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
860
|
+
var INSTRUCTION_FILES = ["AGI.md", ".agi/AGI.md", ".agi/instructions.md"];
|
|
861
|
+
function loadRules(cwd) {
|
|
862
|
+
const rulesDir = join2(cwd, ".agi", "rules");
|
|
863
|
+
if (!existsSync(rulesDir)) return [];
|
|
864
|
+
const rules = [];
|
|
865
|
+
try {
|
|
866
|
+
const files = readdirSync(rulesDir).filter((f) => f.endsWith(".md")).sort();
|
|
867
|
+
for (const file of files) {
|
|
868
|
+
const filePath = join2(rulesDir, file);
|
|
869
|
+
try {
|
|
870
|
+
const raw = readFileSync2(filePath, "utf-8");
|
|
871
|
+
const name = basename(file, ".md");
|
|
872
|
+
let content = raw.trim();
|
|
873
|
+
let paths;
|
|
874
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
875
|
+
if (fmMatch) {
|
|
876
|
+
const meta = fmMatch[1];
|
|
877
|
+
content = fmMatch[2].trim();
|
|
878
|
+
const pathsMatch = meta.match(/^paths:\s*(.+)$/m);
|
|
879
|
+
if (pathsMatch) {
|
|
880
|
+
paths = pathsMatch[1].split(",").map((p) => p.trim()).filter(Boolean);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (content) {
|
|
884
|
+
rules.push({ name, path: filePath, content, paths });
|
|
885
|
+
}
|
|
886
|
+
} catch {
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
} catch {
|
|
890
|
+
}
|
|
891
|
+
return rules;
|
|
892
|
+
}
|
|
893
|
+
function loadProjectConfig(cwd = process.cwd()) {
|
|
894
|
+
let instructions = null;
|
|
895
|
+
let instructionsPath = null;
|
|
896
|
+
for (const relPath of INSTRUCTION_FILES) {
|
|
897
|
+
const fullPath = join2(cwd, relPath);
|
|
898
|
+
if (existsSync(fullPath)) {
|
|
899
|
+
try {
|
|
900
|
+
instructions = readFileSync2(fullPath, "utf-8").trim();
|
|
901
|
+
instructionsPath = fullPath;
|
|
902
|
+
break;
|
|
903
|
+
} catch {
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
const agiDir = join2(cwd, ".agi");
|
|
908
|
+
const agiDirExists = existsSync(agiDir);
|
|
909
|
+
const commandFiles = [];
|
|
910
|
+
const commandsDir = join2(cwd, ".agi", "commands");
|
|
911
|
+
if (existsSync(commandsDir)) {
|
|
912
|
+
try {
|
|
913
|
+
const files = readdirSync(commandsDir);
|
|
914
|
+
for (const file of files) {
|
|
915
|
+
if (file.endsWith(".md")) {
|
|
916
|
+
commandFiles.push(join2(commandsDir, file));
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
} catch {
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
const rules = loadRules(cwd);
|
|
923
|
+
const skills = discoverSkills(cwd);
|
|
924
|
+
return {
|
|
925
|
+
instructions,
|
|
926
|
+
instructionsPath,
|
|
927
|
+
agiDir: agiDirExists ? agiDir : null,
|
|
928
|
+
commandFiles,
|
|
929
|
+
rules,
|
|
930
|
+
skills
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function withProjectInstructions(goal, config) {
|
|
934
|
+
const sections = [];
|
|
935
|
+
if (config.instructions) {
|
|
936
|
+
sections.push(
|
|
937
|
+
"--- Project Instructions (from " + (config.instructionsPath ?? "AGI.md") + ") ---",
|
|
938
|
+
config.instructions,
|
|
939
|
+
"--- End Project Instructions ---"
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
if (config.rules.length > 0) {
|
|
943
|
+
sections.push("--- Project Rules ---");
|
|
944
|
+
for (const rule of config.rules) {
|
|
945
|
+
sections.push(`[${rule.name}]`);
|
|
946
|
+
sections.push(rule.content);
|
|
947
|
+
sections.push("");
|
|
948
|
+
}
|
|
949
|
+
sections.push("--- End Project Rules ---");
|
|
950
|
+
}
|
|
951
|
+
if (config.skills.length > 0) {
|
|
952
|
+
sections.push(generateSkillsPrompt(config.skills));
|
|
953
|
+
}
|
|
954
|
+
if (sections.length === 0) return goal;
|
|
955
|
+
sections.push("", "Task: " + goal);
|
|
956
|
+
return sections.join("\n");
|
|
957
|
+
}
|
|
958
|
+
function initProject(cwd = process.cwd()) {
|
|
959
|
+
const created = [];
|
|
960
|
+
const agiMd = join2(cwd, "AGI.md");
|
|
961
|
+
if (!existsSync(agiMd)) {
|
|
962
|
+
writeFileSync(
|
|
963
|
+
agiMd,
|
|
964
|
+
[
|
|
965
|
+
"# Project Instructions",
|
|
966
|
+
"",
|
|
967
|
+
"<!-- Add project-specific instructions for the AGI agent here. -->",
|
|
968
|
+
"<!-- These instructions are loaded automatically when you run `agi`. -->",
|
|
969
|
+
""
|
|
970
|
+
].join("\n")
|
|
971
|
+
);
|
|
972
|
+
created.push("AGI.md");
|
|
973
|
+
}
|
|
974
|
+
const dirs = [
|
|
975
|
+
".agi",
|
|
976
|
+
".agi/commands",
|
|
977
|
+
".agi/rules",
|
|
978
|
+
".agi/skills"
|
|
979
|
+
];
|
|
980
|
+
for (const dir of dirs) {
|
|
981
|
+
const fullPath = join2(cwd, dir);
|
|
982
|
+
if (!existsSync(fullPath)) {
|
|
983
|
+
mkdirSync(fullPath, { recursive: true });
|
|
984
|
+
created.push(dir + "/");
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
const gitignore = join2(cwd, ".agi", ".gitignore");
|
|
988
|
+
if (!existsSync(gitignore)) {
|
|
989
|
+
writeFileSync(
|
|
990
|
+
gitignore,
|
|
991
|
+
[
|
|
992
|
+
"# Local files that should not be committed",
|
|
993
|
+
"local.md",
|
|
994
|
+
""
|
|
995
|
+
].join("\n")
|
|
996
|
+
);
|
|
997
|
+
created.push(".agi/.gitignore");
|
|
998
|
+
}
|
|
999
|
+
return created;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/userConfig.ts
|
|
1003
|
+
import fs4 from "fs";
|
|
1004
|
+
import path4 from "path";
|
|
1005
|
+
import os4 from "os";
|
|
1006
|
+
var CONFIG_DIR = path4.join(os4.homedir(), ".agi");
|
|
1007
|
+
var CONFIG_FILE = path4.join(CONFIG_DIR, "config.json");
|
|
1008
|
+
var VALID_KEYS = [
|
|
1009
|
+
"model",
|
|
1010
|
+
"verbose",
|
|
1011
|
+
"noConfirm",
|
|
1012
|
+
"compact",
|
|
1013
|
+
"theme"
|
|
1014
|
+
];
|
|
1015
|
+
function ensureDir2() {
|
|
1016
|
+
if (!fs4.existsSync(CONFIG_DIR)) {
|
|
1017
|
+
fs4.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
function loadUserConfig() {
|
|
1021
|
+
try {
|
|
1022
|
+
const raw = fs4.readFileSync(CONFIG_FILE, "utf-8");
|
|
1023
|
+
return JSON.parse(raw);
|
|
1024
|
+
} catch {
|
|
1025
|
+
return {};
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
function saveUserConfig(config) {
|
|
1029
|
+
ensureDir2();
|
|
1030
|
+
fs4.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", {
|
|
1031
|
+
mode: 384
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
function setConfigValue(key, value) {
|
|
1035
|
+
if (!VALID_KEYS.includes(key)) {
|
|
1036
|
+
return ` Unknown key "${key}". Valid keys: ${VALID_KEYS.join(", ")}`;
|
|
1037
|
+
}
|
|
1038
|
+
const config = loadUserConfig();
|
|
1039
|
+
if (key === "verbose" || key === "noConfirm" || key === "compact") {
|
|
1040
|
+
const bool = value.toLowerCase();
|
|
1041
|
+
if (bool !== "true" && bool !== "false" && bool !== "on" && bool !== "off") {
|
|
1042
|
+
return ` "${key}" must be true/false or on/off`;
|
|
1043
|
+
}
|
|
1044
|
+
config[key] = bool === "true" || bool === "on";
|
|
1045
|
+
} else {
|
|
1046
|
+
config[key] = value;
|
|
1047
|
+
}
|
|
1048
|
+
saveUserConfig(config);
|
|
1049
|
+
return ` Config: ${key} = ${value} (saved to ~/.agi/config.json)`;
|
|
1050
|
+
}
|
|
1051
|
+
function formatConfig(config) {
|
|
1052
|
+
const lines = ["", " User configuration (~/.agi/config.json):", ""];
|
|
1053
|
+
if (Object.keys(config).length === 0) {
|
|
1054
|
+
lines.push(" (no custom configuration \u2014 using defaults)");
|
|
1055
|
+
} else {
|
|
1056
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1057
|
+
lines.push(` ${key.padEnd(14)} ${String(value)}`);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
lines.push("");
|
|
1061
|
+
lines.push(" Set with: /config <key> <value>");
|
|
1062
|
+
lines.push(` Keys: ${VALID_KEYS.join(", ")}`);
|
|
1063
|
+
lines.push("");
|
|
1064
|
+
return lines.join("\n");
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// src/hooks.ts
|
|
1068
|
+
import fs5 from "fs";
|
|
1069
|
+
import path5 from "path";
|
|
1070
|
+
import { execSync as execSync2 } from "child_process";
|
|
1071
|
+
var loadedHooks = null;
|
|
1072
|
+
function loadHooks(cwd = process.cwd()) {
|
|
1073
|
+
if (loadedHooks) return loadedHooks;
|
|
1074
|
+
const hooksFile = path5.join(cwd, ".agi", "hooks.json");
|
|
1075
|
+
try {
|
|
1076
|
+
const raw = fs5.readFileSync(hooksFile, "utf-8");
|
|
1077
|
+
loadedHooks = JSON.parse(raw);
|
|
1078
|
+
return loadedHooks;
|
|
1079
|
+
} catch {
|
|
1080
|
+
loadedHooks = { hooks: {} };
|
|
1081
|
+
return loadedHooks;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
function runHooks(event, env = {}) {
|
|
1085
|
+
const config = loadedHooks || loadHooks();
|
|
1086
|
+
const entries = config.hooks[event];
|
|
1087
|
+
if (!entries || entries.length === 0) return;
|
|
1088
|
+
for (const entry of entries) {
|
|
1089
|
+
try {
|
|
1090
|
+
execSync2(entry.command, {
|
|
1091
|
+
stdio: "ignore",
|
|
1092
|
+
timeout: 5e3,
|
|
1093
|
+
env: { ...process.env, ...env, AGI_HOOK_EVENT: event }
|
|
1094
|
+
});
|
|
1095
|
+
} catch {
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
function formatHooks() {
|
|
1100
|
+
const config = loadedHooks || loadHooks();
|
|
1101
|
+
const events = Object.keys(config.hooks);
|
|
1102
|
+
if (events.length === 0) {
|
|
1103
|
+
return " No hooks configured. Add hooks in .agi/hooks.json";
|
|
1104
|
+
}
|
|
1105
|
+
const lines = ["", " Configured hooks:", ""];
|
|
1106
|
+
for (const event of events) {
|
|
1107
|
+
const entries = config.hooks[event] || [];
|
|
1108
|
+
lines.push(` ${event} (${entries.length} hook${entries.length !== 1 ? "s" : ""}):`);
|
|
1109
|
+
for (const entry of entries) {
|
|
1110
|
+
lines.push(` \u25B8 ${entry.command}`);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
lines.push("");
|
|
1114
|
+
return lines.join("\n");
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// src/commands/slash.ts
|
|
679
1118
|
var VALID_MODELS = ["claude-sonnet", "claude-opus"];
|
|
680
1119
|
var builtinCommands = [
|
|
681
1120
|
{
|
|
@@ -689,8 +1128,9 @@ var builtinCommands = [
|
|
|
689
1128
|
" Available commands:",
|
|
690
1129
|
""
|
|
691
1130
|
];
|
|
692
|
-
const builtins = all.filter((c) => !c.isUserDefined);
|
|
1131
|
+
const builtins = all.filter((c) => !c.isUserDefined && !c.isSkill);
|
|
693
1132
|
const userDefined = all.filter((c) => c.isUserDefined);
|
|
1133
|
+
const skills = all.filter((c) => c.isSkill);
|
|
694
1134
|
for (const cmd of builtins) {
|
|
695
1135
|
const aliases = cmd.aliases?.length ? ` (${cmd.aliases.map((a) => "/" + a).join(", ")})` : "";
|
|
696
1136
|
const usage = cmd.usage ? ` ${cmd.usage}` : "";
|
|
@@ -707,6 +1147,65 @@ var builtinCommands = [
|
|
|
707
1147
|
lines.push(` ${cmd.description}`);
|
|
708
1148
|
}
|
|
709
1149
|
}
|
|
1150
|
+
if (skills.length > 0) {
|
|
1151
|
+
lines.push("");
|
|
1152
|
+
lines.push(" Skills (.agi/skills/):");
|
|
1153
|
+
lines.push("");
|
|
1154
|
+
for (const cmd of skills) {
|
|
1155
|
+
const usage = cmd.usage ? ` ${cmd.usage}` : "";
|
|
1156
|
+
lines.push(` /${cmd.name}${usage}`);
|
|
1157
|
+
lines.push(` ${cmd.description}`);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
lines.push("");
|
|
1161
|
+
return lines.join("\n");
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
name: "history",
|
|
1166
|
+
aliases: ["hist"],
|
|
1167
|
+
description: "Show session history",
|
|
1168
|
+
usage: "[clear]",
|
|
1169
|
+
execute: (args) => {
|
|
1170
|
+
if (args.trim().toLowerCase() === "clear") {
|
|
1171
|
+
clearHistory();
|
|
1172
|
+
return " History cleared.";
|
|
1173
|
+
}
|
|
1174
|
+
const entries = loadHistory();
|
|
1175
|
+
return formatHistory(entries);
|
|
1176
|
+
}
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
name: "status",
|
|
1180
|
+
aliases: ["info"],
|
|
1181
|
+
description: "Show environment and session info",
|
|
1182
|
+
execute: (_args, ctx) => {
|
|
1183
|
+
const lines = ["", " Environment:", ""];
|
|
1184
|
+
lines.push(` Version ${ctx.version || "unknown"}`);
|
|
1185
|
+
lines.push(` Model ${ctx.model}`);
|
|
1186
|
+
lines.push(` Working dir ${process.cwd().replace(os5.homedir(), "~")}`);
|
|
1187
|
+
lines.push(` Node.js ${process.version}`);
|
|
1188
|
+
lines.push(` Platform ${process.platform} ${process.arch}`);
|
|
1189
|
+
lines.push(` Driver ${isBinaryAvailable() ? "\u2714 available" : "\u2718 not found"}`);
|
|
1190
|
+
lines.push(` API key ${process.env.AGI_API_KEY ? "\u2714 set" : process.env.ANTHROPIC_API_KEY ? "\u2714 set (ANTHROPIC_API_KEY)" : "\u2718 not set"}`);
|
|
1191
|
+
lines.push("");
|
|
1192
|
+
lines.push(" Session:");
|
|
1193
|
+
lines.push("");
|
|
1194
|
+
lines.push(` Verbose ${ctx.verbose ? "on" : "off"}`);
|
|
1195
|
+
lines.push(` Auto-confirm ${ctx.noConfirm ? "on" : "off"}`);
|
|
1196
|
+
lines.push(` Compact mode ${ctx.compact ? "on" : "off"}`);
|
|
1197
|
+
if (ctx.projectConfig) {
|
|
1198
|
+
lines.push("");
|
|
1199
|
+
lines.push(" Project:");
|
|
1200
|
+
lines.push("");
|
|
1201
|
+
lines.push(` Instructions ${ctx.projectConfig.instructionsPath?.replace(process.cwd(), ".") || "none"}`);
|
|
1202
|
+
lines.push(` Rules ${ctx.projectConfig.rules.length} loaded`);
|
|
1203
|
+
lines.push(` Commands ${ctx.projectConfig.commandFiles.length} custom`);
|
|
1204
|
+
lines.push(` Skills ${ctx.projectConfig.skills.length} discovered`);
|
|
1205
|
+
}
|
|
1206
|
+
const history = loadHistory();
|
|
1207
|
+
lines.push("");
|
|
1208
|
+
lines.push(` History ${history.length} past sessions`);
|
|
710
1209
|
lines.push("");
|
|
711
1210
|
return lines.join("\n");
|
|
712
1211
|
}
|
|
@@ -737,6 +1236,14 @@ var builtinCommands = [
|
|
|
737
1236
|
return ` Verbose output ${!ctx.verbose ? "on" : "off"}`;
|
|
738
1237
|
}
|
|
739
1238
|
},
|
|
1239
|
+
{
|
|
1240
|
+
name: "compact",
|
|
1241
|
+
description: "Toggle compact output mode",
|
|
1242
|
+
execute: (_args, ctx) => {
|
|
1243
|
+
ctx.setCompact(!ctx.compact);
|
|
1244
|
+
return ` Compact mode ${!ctx.compact ? "on" : "off"}`;
|
|
1245
|
+
}
|
|
1246
|
+
},
|
|
740
1247
|
{
|
|
741
1248
|
name: "confirm",
|
|
742
1249
|
description: "Toggle auto-confirm mode",
|
|
@@ -745,6 +1252,133 @@ var builtinCommands = [
|
|
|
745
1252
|
return ` Auto-confirm ${!ctx.noConfirm ? "on" : "off"}`;
|
|
746
1253
|
}
|
|
747
1254
|
},
|
|
1255
|
+
{
|
|
1256
|
+
name: "init",
|
|
1257
|
+
description: "Initialize AGI.md and .agi/ project structure",
|
|
1258
|
+
execute: () => {
|
|
1259
|
+
const created = initProject();
|
|
1260
|
+
if (created.length === 0) {
|
|
1261
|
+
return " Project already initialized \u2014 AGI.md and .agi/ exist.";
|
|
1262
|
+
}
|
|
1263
|
+
const lines = ["", " Initialized project:", ""];
|
|
1264
|
+
for (const item of created) {
|
|
1265
|
+
lines.push(` \u2714 Created ${item}`);
|
|
1266
|
+
}
|
|
1267
|
+
lines.push("");
|
|
1268
|
+
lines.push(" Edit AGI.md to add project instructions for the agent.");
|
|
1269
|
+
lines.push(" Add custom commands in .agi/commands/*.md");
|
|
1270
|
+
lines.push(" Add rules in .agi/rules/*.md");
|
|
1271
|
+
lines.push(" Add skills in .agi/skills/<name>/SKILL.md");
|
|
1272
|
+
lines.push("");
|
|
1273
|
+
return lines.join("\n");
|
|
1274
|
+
}
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
name: "doctor",
|
|
1278
|
+
aliases: ["check"],
|
|
1279
|
+
description: "Check system health and configuration",
|
|
1280
|
+
execute: (_args, ctx) => {
|
|
1281
|
+
const checks = [];
|
|
1282
|
+
const hasKey = !!(process.env.AGI_API_KEY || process.env.ANTHROPIC_API_KEY);
|
|
1283
|
+
checks.push({
|
|
1284
|
+
label: "API key",
|
|
1285
|
+
ok: hasKey,
|
|
1286
|
+
detail: hasKey ? "configured" : "missing \u2014 run `agi login` or set AGI_API_KEY"
|
|
1287
|
+
});
|
|
1288
|
+
const hasDriver = isBinaryAvailable();
|
|
1289
|
+
checks.push({
|
|
1290
|
+
label: "Driver binary",
|
|
1291
|
+
ok: hasDriver,
|
|
1292
|
+
detail: hasDriver ? "found" : "not found \u2014 reinstall @agi_inc/cli"
|
|
1293
|
+
});
|
|
1294
|
+
const nodeVer = process.versions.node;
|
|
1295
|
+
const [major] = nodeVer.split(".").map(Number);
|
|
1296
|
+
checks.push({
|
|
1297
|
+
label: "Node.js",
|
|
1298
|
+
ok: major >= 18,
|
|
1299
|
+
detail: `v${nodeVer}${major < 18 ? " \u2014 v18+ required" : ""}`
|
|
1300
|
+
});
|
|
1301
|
+
if (ctx.projectConfig) {
|
|
1302
|
+
checks.push({
|
|
1303
|
+
label: "Project instructions",
|
|
1304
|
+
ok: !!ctx.projectConfig.instructions,
|
|
1305
|
+
detail: ctx.projectConfig.instructionsPath?.replace(process.cwd(), ".") || "none \u2014 run /init"
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
const lines = ["", " System health:", ""];
|
|
1309
|
+
for (const check of checks) {
|
|
1310
|
+
const icon = check.ok ? "\u2714" : "\u2718";
|
|
1311
|
+
const color = check.ok ? "" : "";
|
|
1312
|
+
lines.push(` ${icon} ${check.label.padEnd(22)} ${check.detail}`);
|
|
1313
|
+
}
|
|
1314
|
+
const allOk = checks.every((c) => c.ok);
|
|
1315
|
+
lines.push("");
|
|
1316
|
+
lines.push(allOk ? " All checks passed." : " Some checks failed \u2014 see above.");
|
|
1317
|
+
lines.push("");
|
|
1318
|
+
return lines.join("\n");
|
|
1319
|
+
}
|
|
1320
|
+
},
|
|
1321
|
+
{
|
|
1322
|
+
name: "skills",
|
|
1323
|
+
description: "List discovered skills",
|
|
1324
|
+
execute: (_args, ctx) => {
|
|
1325
|
+
if (!ctx.projectConfig) return " No project config loaded.";
|
|
1326
|
+
return formatSkillsList(ctx.projectConfig.skills);
|
|
1327
|
+
}
|
|
1328
|
+
},
|
|
1329
|
+
{
|
|
1330
|
+
name: "config",
|
|
1331
|
+
aliases: ["cfg"],
|
|
1332
|
+
description: "Show or set persistent config",
|
|
1333
|
+
usage: "[key] [value]",
|
|
1334
|
+
execute: (args) => {
|
|
1335
|
+
const parts = args.trim().split(/\s+/);
|
|
1336
|
+
if (!args.trim()) {
|
|
1337
|
+
const config = loadUserConfig();
|
|
1338
|
+
return formatConfig(config);
|
|
1339
|
+
}
|
|
1340
|
+
if (parts.length === 1) {
|
|
1341
|
+
const config = loadUserConfig();
|
|
1342
|
+
const val = config[parts[0]];
|
|
1343
|
+
if (val === void 0) return ` ${parts[0]} is not set`;
|
|
1344
|
+
return ` ${parts[0]} = ${String(val)}`;
|
|
1345
|
+
}
|
|
1346
|
+
return setConfigValue(parts[0], parts.slice(1).join(" "));
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
name: "redo",
|
|
1351
|
+
aliases: ["r"],
|
|
1352
|
+
description: "Re-run the last goal",
|
|
1353
|
+
execute: (_args, ctx) => {
|
|
1354
|
+
if (!ctx.lastGoal) return " No previous goal to re-run.";
|
|
1355
|
+
if (!ctx.runGoal) return " Error: cannot run goals in this context";
|
|
1356
|
+
ctx.runGoal(ctx.lastGoal);
|
|
1357
|
+
return null;
|
|
1358
|
+
}
|
|
1359
|
+
},
|
|
1360
|
+
{
|
|
1361
|
+
name: "hooks",
|
|
1362
|
+
description: "Show configured hooks",
|
|
1363
|
+
execute: () => {
|
|
1364
|
+
return formatHooks();
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
name: "bug",
|
|
1369
|
+
description: "Report a bug or issue",
|
|
1370
|
+
execute: () => {
|
|
1371
|
+
return [
|
|
1372
|
+
"",
|
|
1373
|
+
" Report issues at:",
|
|
1374
|
+
" https://github.com/agi-inc/cli/issues",
|
|
1375
|
+
"",
|
|
1376
|
+
" Include: agi version, OS, Node.js version, and steps to reproduce.",
|
|
1377
|
+
" Run /doctor to check your environment.",
|
|
1378
|
+
""
|
|
1379
|
+
].join("\n");
|
|
1380
|
+
}
|
|
1381
|
+
},
|
|
748
1382
|
{
|
|
749
1383
|
name: "clear",
|
|
750
1384
|
aliases: ["c"],
|
|
@@ -764,7 +1398,7 @@ var builtinCommands = [
|
|
|
764
1398
|
}
|
|
765
1399
|
}
|
|
766
1400
|
];
|
|
767
|
-
function
|
|
1401
|
+
function parseFrontmatter2(content) {
|
|
768
1402
|
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
769
1403
|
if (!match) return { meta: {}, body: content.trim() };
|
|
770
1404
|
const meta = {};
|
|
@@ -782,9 +1416,9 @@ function loadUserCommands(commandFiles) {
|
|
|
782
1416
|
const userCommands = [];
|
|
783
1417
|
for (const filePath of commandFiles) {
|
|
784
1418
|
try {
|
|
785
|
-
const content =
|
|
786
|
-
const { meta, body } =
|
|
787
|
-
const name =
|
|
1419
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
1420
|
+
const { meta, body } = parseFrontmatter2(content);
|
|
1421
|
+
const name = basename2(filePath, ".md");
|
|
788
1422
|
const description = meta["description"] || body.split("\n")[0].slice(0, 60);
|
|
789
1423
|
const usage = meta["argument-hint"];
|
|
790
1424
|
userCommands.push({
|
|
@@ -810,6 +1444,26 @@ function loadUserCommands(commandFiles) {
|
|
|
810
1444
|
}
|
|
811
1445
|
return userCommands;
|
|
812
1446
|
}
|
|
1447
|
+
function loadSkillCommands(skills) {
|
|
1448
|
+
return skills.filter((s) => s.userInvocable).map((skill) => ({
|
|
1449
|
+
name: skill.name,
|
|
1450
|
+
description: skill.description,
|
|
1451
|
+
usage: skill.argumentHint,
|
|
1452
|
+
isSkill: true,
|
|
1453
|
+
execute: (args, ctx) => {
|
|
1454
|
+
if (!ctx.runGoal) return ` Error: cannot run skill commands in this context`;
|
|
1455
|
+
const loaded = loadSkill(skill);
|
|
1456
|
+
let prompt = loaded.body;
|
|
1457
|
+
prompt = prompt.replace(/\$ARGUMENTS/g, args);
|
|
1458
|
+
const argParts = args.split(/\s+/).filter(Boolean);
|
|
1459
|
+
for (let i = 0; i < argParts.length; i++) {
|
|
1460
|
+
prompt = prompt.replace(new RegExp(`\\$${i + 1}`, "g"), argParts[i]);
|
|
1461
|
+
}
|
|
1462
|
+
ctx.runGoal(prompt);
|
|
1463
|
+
return null;
|
|
1464
|
+
}
|
|
1465
|
+
}));
|
|
1466
|
+
}
|
|
813
1467
|
var allCommands = [...builtinCommands];
|
|
814
1468
|
var commandMap = /* @__PURE__ */ new Map();
|
|
815
1469
|
function rebuildMap() {
|
|
@@ -843,10 +1497,12 @@ function getAllCommands() {
|
|
|
843
1497
|
}
|
|
844
1498
|
|
|
845
1499
|
// src/components/PromptInput.tsx
|
|
846
|
-
var PromptInput = ({ onSubmit }) => {
|
|
1500
|
+
var PromptInput = ({ onSubmit, goalHistory = [] }) => {
|
|
847
1501
|
const [value, setValue] = useState5("");
|
|
848
1502
|
const [selectedIndex, setSelectedIndex] = useState5(-1);
|
|
849
1503
|
const [inputKey, setInputKey] = useState5(0);
|
|
1504
|
+
const [historyIndex, setHistoryIndex] = useState5(-1);
|
|
1505
|
+
const savedInput = useRef2("");
|
|
850
1506
|
const showSuggestions = value.startsWith("/") && value.length > 0 && !value.includes(" ");
|
|
851
1507
|
const suggestions = showSuggestions ? getAllCommands().filter((cmd) => {
|
|
852
1508
|
const typed = value.slice(1).toLowerCase();
|
|
@@ -872,19 +1528,41 @@ var PromptInput = ({ onSubmit }) => {
|
|
|
872
1528
|
}
|
|
873
1529
|
};
|
|
874
1530
|
useInput4((input, key) => {
|
|
875
|
-
if (
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
1531
|
+
if (showSuggestions && suggestions.length > 0) {
|
|
1532
|
+
if (key.downArrow) {
|
|
1533
|
+
setSelectedIndex(
|
|
1534
|
+
(prev) => prev < suggestions.length - 1 ? prev + 1 : 0
|
|
1535
|
+
);
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
if (key.upArrow) {
|
|
1539
|
+
setSelectedIndex(
|
|
1540
|
+
(prev) => prev > 0 ? prev - 1 : suggestions.length - 1
|
|
1541
|
+
);
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
if (key.tab) {
|
|
1545
|
+
completeSelected();
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
return;
|
|
880
1549
|
}
|
|
881
|
-
if (key.upArrow) {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
1550
|
+
if (key.upArrow && goalHistory.length > 0) {
|
|
1551
|
+
if (historyIndex === -1) {
|
|
1552
|
+
savedInput.current = value;
|
|
1553
|
+
}
|
|
1554
|
+
const next = Math.min(historyIndex + 1, goalHistory.length - 1);
|
|
1555
|
+
setHistoryIndex(next);
|
|
1556
|
+
pendingValue.current = goalHistory[next];
|
|
1557
|
+
setInputKey((k) => k + 1);
|
|
1558
|
+
return;
|
|
885
1559
|
}
|
|
886
|
-
if (key.
|
|
887
|
-
|
|
1560
|
+
if (key.downArrow && historyIndex >= 0) {
|
|
1561
|
+
const next = historyIndex - 1;
|
|
1562
|
+
setHistoryIndex(next);
|
|
1563
|
+
pendingValue.current = next === -1 ? savedInput.current : goalHistory[next];
|
|
1564
|
+
setInputKey((k) => k + 1);
|
|
1565
|
+
return;
|
|
888
1566
|
}
|
|
889
1567
|
});
|
|
890
1568
|
const handleSubmit = () => {
|
|
@@ -902,6 +1580,8 @@ var PromptInput = ({ onSubmit }) => {
|
|
|
902
1580
|
pendingValue.current = "";
|
|
903
1581
|
setInputKey((k) => k + 1);
|
|
904
1582
|
setSelectedIndex(-1);
|
|
1583
|
+
setHistoryIndex(-1);
|
|
1584
|
+
savedInput.current = "";
|
|
905
1585
|
}
|
|
906
1586
|
};
|
|
907
1587
|
const visibleSuggestions = suggestions.slice(0, 6);
|
|
@@ -1034,57 +1714,6 @@ var Logo = ({
|
|
|
1034
1714
|
)), info[r] != null && /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, null, " "), info[r]))));
|
|
1035
1715
|
};
|
|
1036
1716
|
|
|
1037
|
-
// src/project.ts
|
|
1038
|
-
import { readFileSync as readFileSync3, existsSync, readdirSync } from "fs";
|
|
1039
|
-
import { join as join2 } from "path";
|
|
1040
|
-
var INSTRUCTION_FILES = ["AGI.md", ".agi/AGI.md", ".agi/instructions.md"];
|
|
1041
|
-
function loadProjectConfig(cwd = process.cwd()) {
|
|
1042
|
-
let instructions = null;
|
|
1043
|
-
let instructionsPath = null;
|
|
1044
|
-
for (const relPath of INSTRUCTION_FILES) {
|
|
1045
|
-
const fullPath = join2(cwd, relPath);
|
|
1046
|
-
if (existsSync(fullPath)) {
|
|
1047
|
-
try {
|
|
1048
|
-
instructions = readFileSync3(fullPath, "utf-8").trim();
|
|
1049
|
-
instructionsPath = fullPath;
|
|
1050
|
-
break;
|
|
1051
|
-
} catch {
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
const agiDir = join2(cwd, ".agi");
|
|
1056
|
-
const agiDirExists = existsSync(agiDir);
|
|
1057
|
-
const commandFiles = [];
|
|
1058
|
-
const commandsDir = join2(cwd, ".agi", "commands");
|
|
1059
|
-
if (existsSync(commandsDir)) {
|
|
1060
|
-
try {
|
|
1061
|
-
const files = readdirSync(commandsDir);
|
|
1062
|
-
for (const file of files) {
|
|
1063
|
-
if (file.endsWith(".md")) {
|
|
1064
|
-
commandFiles.push(join2(commandsDir, file));
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
} catch {
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
return {
|
|
1071
|
-
instructions,
|
|
1072
|
-
instructionsPath,
|
|
1073
|
-
agiDir: agiDirExists ? agiDir : null,
|
|
1074
|
-
commandFiles
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
function withProjectInstructions(goal, config) {
|
|
1078
|
-
if (!config.instructions) return goal;
|
|
1079
|
-
return [
|
|
1080
|
-
"--- Project Instructions (from " + (config.instructionsPath ?? "AGI.md") + ") ---",
|
|
1081
|
-
config.instructions,
|
|
1082
|
-
"--- End Project Instructions ---",
|
|
1083
|
-
"",
|
|
1084
|
-
"Task: " + goal
|
|
1085
|
-
].join("\n");
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
1717
|
// src/app/App.tsx
|
|
1089
1718
|
import { createRequire } from "module";
|
|
1090
1719
|
var require2 = createRequire(import.meta.url);
|
|
@@ -1093,18 +1722,32 @@ var App = ({ args }) => {
|
|
|
1093
1722
|
const { exit } = useApp();
|
|
1094
1723
|
const [phase, setPhase] = useState7(args.goal ? "executing" : "input");
|
|
1095
1724
|
const [currentGoal, setCurrentGoal] = useState7(args.goal ?? "");
|
|
1725
|
+
const [goalHistory, setGoalHistory] = useState7([]);
|
|
1726
|
+
const userConfig = useMemo2(() => loadUserConfig(), []);
|
|
1727
|
+
useMemo2(() => loadHooks(), []);
|
|
1728
|
+
useEffect5(() => {
|
|
1729
|
+
runHooks("SessionStart");
|
|
1730
|
+
}, []);
|
|
1096
1731
|
const projectConfig = useMemo2(() => {
|
|
1097
1732
|
const config = loadProjectConfig();
|
|
1733
|
+
const cmds = [];
|
|
1098
1734
|
if (config.commandFiles.length > 0) {
|
|
1099
|
-
|
|
1100
|
-
|
|
1735
|
+
cmds.push(...loadUserCommands(config.commandFiles));
|
|
1736
|
+
}
|
|
1737
|
+
if (config.skills.length > 0) {
|
|
1738
|
+
cmds.push(...loadSkillCommands(config.skills));
|
|
1739
|
+
}
|
|
1740
|
+
if (cmds.length > 0) {
|
|
1741
|
+
registerCommands(cmds);
|
|
1101
1742
|
}
|
|
1102
1743
|
return config;
|
|
1103
1744
|
}, []);
|
|
1104
|
-
const [model, setModel] = useState7(args.model);
|
|
1105
|
-
const [verbose, setVerbose] = useState7(args.verbose);
|
|
1106
|
-
const [noConfirm, setNoConfirm] = useState7(args.noConfirm);
|
|
1745
|
+
const [model, setModel] = useState7(args.model !== "claude-sonnet" ? args.model : userConfig.model ?? args.model);
|
|
1746
|
+
const [verbose, setVerbose] = useState7(args.verbose || (userConfig.verbose ?? false));
|
|
1747
|
+
const [noConfirm, setNoConfirm] = useState7(args.noConfirm || (userConfig.noConfirm ?? false));
|
|
1748
|
+
const [compact, setCompact] = useState7(userConfig.compact ?? false);
|
|
1107
1749
|
const [commandMessage, setCommandMessage] = useState7(null);
|
|
1750
|
+
const taskStartTime = useRef3(null);
|
|
1108
1751
|
const {
|
|
1109
1752
|
state,
|
|
1110
1753
|
step,
|
|
@@ -1122,17 +1765,34 @@ var App = ({ args }) => {
|
|
|
1122
1765
|
model,
|
|
1123
1766
|
verbose,
|
|
1124
1767
|
noConfirm,
|
|
1125
|
-
onFinished: () => {
|
|
1768
|
+
onFinished: (result) => {
|
|
1769
|
+
if (currentGoal) {
|
|
1770
|
+
const entry = {
|
|
1771
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1772
|
+
goal: currentGoal,
|
|
1773
|
+
model,
|
|
1774
|
+
durationMs: taskStartTime.current ? Date.now() - taskStartTime.current : void 0,
|
|
1775
|
+
success: result?.success
|
|
1776
|
+
};
|
|
1777
|
+
appendHistory(entry);
|
|
1778
|
+
taskStartTime.current = null;
|
|
1779
|
+
runHooks("TaskComplete", {
|
|
1780
|
+
AGI_GOAL: currentGoal,
|
|
1781
|
+
AGI_SUCCESS: String(result?.success ?? "")
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1126
1784
|
setPhase("input");
|
|
1127
1785
|
}
|
|
1128
1786
|
});
|
|
1129
1787
|
useEffect5(() => {
|
|
1130
1788
|
if (phase === "executing" && currentGoal) {
|
|
1789
|
+
taskStartTime.current = Date.now();
|
|
1131
1790
|
start(withProjectInstructions(currentGoal, projectConfig));
|
|
1132
1791
|
}
|
|
1133
1792
|
}, [phase, currentGoal, start, projectConfig]);
|
|
1134
1793
|
const runGoal = useCallback3((goal) => {
|
|
1135
1794
|
setCommandMessage(null);
|
|
1795
|
+
setGoalHistory((prev) => [goal, ...prev.filter((g) => g !== goal)]);
|
|
1136
1796
|
setCurrentGoal(goal);
|
|
1137
1797
|
setPhase("executing");
|
|
1138
1798
|
}, []);
|
|
@@ -1140,12 +1800,17 @@ var App = ({ args }) => {
|
|
|
1140
1800
|
model,
|
|
1141
1801
|
verbose,
|
|
1142
1802
|
noConfirm,
|
|
1803
|
+
compact,
|
|
1143
1804
|
setModel,
|
|
1144
1805
|
setVerbose,
|
|
1145
1806
|
setNoConfirm,
|
|
1807
|
+
setCompact,
|
|
1146
1808
|
clearEvents,
|
|
1147
1809
|
quit: () => exit(),
|
|
1148
|
-
runGoal
|
|
1810
|
+
runGoal,
|
|
1811
|
+
projectConfig,
|
|
1812
|
+
version: CLI_VERSION,
|
|
1813
|
+
lastGoal: goalHistory[0]
|
|
1149
1814
|
};
|
|
1150
1815
|
const handleSubmitGoal = useCallback3(
|
|
1151
1816
|
(input) => {
|
|
@@ -1159,6 +1824,7 @@ var App = ({ args }) => {
|
|
|
1159
1824
|
return;
|
|
1160
1825
|
}
|
|
1161
1826
|
setCommandMessage(null);
|
|
1827
|
+
setGoalHistory((prev) => [input, ...prev.filter((g) => g !== input)]);
|
|
1162
1828
|
setCurrentGoal(input);
|
|
1163
1829
|
setPhase("executing");
|
|
1164
1830
|
},
|
|
@@ -1184,7 +1850,7 @@ var App = ({ args }) => {
|
|
|
1184
1850
|
if (state === "paused") return "thinking";
|
|
1185
1851
|
return "active";
|
|
1186
1852
|
})();
|
|
1187
|
-
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, phase === "input" && events.length === 0 && /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Logo, { version: CLI_VERSION, model, cwd: process.cwd(), mood: logoMood }), projectConfig.instructions && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, marginLeft: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "\u25B8 loaded "), /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, projectConfig.instructionsPath)), projectConfig.commandFiles.length > 0 && /* @__PURE__ */ React9.createElement(Box8, { marginLeft: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "\u25B8 "), /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, projectConfig.commandFiles.length), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " custom command(s) from .agi/commands/"))), phase === "executing" && /* @__PURE__ */ React9.createElement(StatusBar, { state, step, goal: currentGoal }), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(EventDisplay, { events }), phase === "executing" && state === "running" && /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " \u2503 "), /* @__PURE__ */ React9.createElement(Spinner, null)), phase === "executing" && state === "paused" && /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " \u2503 "), /* @__PURE__ */ React9.createElement(Text9, { color: "yellow", bold: true }, "\u25AE\u25AE"), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " paused \u2014 space to resume"))), pendingConfirm && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(ConfirmDialog, { reason: pendingConfirm, onConfirm: respondConfirm })), pendingQuestion && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(QuestionDialog, { question: pendingQuestion, onAnswer: respondAnswer })), commandMessage && phase === "input" && /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, commandMessage)), phase === "input" && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(PromptInput, { onSubmit: handleSubmitGoal })), phase === "executing" && !isTerminal && !pendingConfirm && !pendingQuestion && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " space pause \xB7 q stop \xB7 ^c quit")));
|
|
1853
|
+
return /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, phase === "input" && events.length === 0 && /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Logo, { version: CLI_VERSION, model, cwd: process.cwd(), mood: logoMood }), projectConfig.instructions && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1, marginLeft: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "\u25B8 loaded "), /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, projectConfig.instructionsPath)), projectConfig.rules.length > 0 && /* @__PURE__ */ React9.createElement(Box8, { marginLeft: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "\u25B8 "), /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, projectConfig.rules.length), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " rule(s) from .agi/rules/")), projectConfig.commandFiles.length > 0 && /* @__PURE__ */ React9.createElement(Box8, { marginLeft: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "\u25B8 "), /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, projectConfig.commandFiles.length), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " custom command(s) from .agi/commands/")), projectConfig.skills.length > 0 && /* @__PURE__ */ React9.createElement(Box8, { marginLeft: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "\u25B8 "), /* @__PURE__ */ React9.createElement(Text9, { color: "green" }, projectConfig.skills.length), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " skill(s) from .agi/skills/"))), phase === "executing" && /* @__PURE__ */ React9.createElement(StatusBar, { state, step, goal: currentGoal }), /* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React9.createElement(EventDisplay, { events, maxEvents: compact ? 6 : 12 }), phase === "executing" && state === "running" && /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " \u2503 "), /* @__PURE__ */ React9.createElement(Spinner, null)), phase === "executing" && state === "paused" && /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " \u2503 "), /* @__PURE__ */ React9.createElement(Text9, { color: "yellow", bold: true }, "\u25AE\u25AE"), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " paused \u2014 space to resume"))), pendingConfirm && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(ConfirmDialog, { reason: pendingConfirm, onConfirm: respondConfirm })), pendingQuestion && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(QuestionDialog, { question: pendingQuestion, onAnswer: respondAnswer })), commandMessage && phase === "input" && /* @__PURE__ */ React9.createElement(Box8, null, /* @__PURE__ */ React9.createElement(Text9, { color: "gray" }, commandMessage)), phase === "input" && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(PromptInput, { onSubmit: handleSubmitGoal, goalHistory })), phase === "executing" && !isTerminal && !pendingConfirm && !pendingQuestion && /* @__PURE__ */ React9.createElement(Box8, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, " space pause \xB7 q stop \xB7 ^c quit")));
|
|
1188
1854
|
};
|
|
1189
1855
|
|
|
1190
1856
|
// src/index.tsx
|
|
@@ -1207,7 +1873,7 @@ async function main() {
|
|
|
1207
1873
|
if (!process.env.AGI_API_KEY && !process.env.ANTHROPIC_API_KEY) {
|
|
1208
1874
|
process.env.AGI_API_KEY = apiKey;
|
|
1209
1875
|
}
|
|
1210
|
-
if (!
|
|
1876
|
+
if (!isBinaryAvailable2()) {
|
|
1211
1877
|
console.error("Error: AGI driver binary not found");
|
|
1212
1878
|
console.error("");
|
|
1213
1879
|
console.error("The driver binary is required for local agent execution.");
|