@fractary/codex-cli 0.10.14 → 0.10.16
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 +11 -15
- package/dist/cli.cjs +181 -534
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +176 -529
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import * as
|
|
2
|
+
import * as path3 from 'path';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
5
|
+
import * as fs4 from 'fs/promises';
|
|
6
|
+
import * as yaml from 'js-yaml';
|
|
7
7
|
import { readCodexConfig, CONFIG_SCHEMA_VERSION, expandEnvVarsInConfig, expandEnvVars, parseSize, parseDuration, ValidationError, PermissionDeniedError, ConfigurationError, CodexError } from '@fractary/codex';
|
|
8
8
|
import * as os from 'os';
|
|
9
9
|
import { spawn } from 'child_process';
|
|
@@ -43,7 +43,7 @@ __export(migrate_config_exports, {
|
|
|
43
43
|
});
|
|
44
44
|
async function isLegacyConfig(configPath) {
|
|
45
45
|
try {
|
|
46
|
-
const content = await
|
|
46
|
+
const content = await fs4.readFile(configPath, "utf-8");
|
|
47
47
|
const config = JSON.parse(content);
|
|
48
48
|
return config.version === "3.0" || config.organizationSlug !== void 0 || config.directories !== void 0 || config.rules !== void 0;
|
|
49
49
|
} catch {
|
|
@@ -53,13 +53,13 @@ async function isLegacyConfig(configPath) {
|
|
|
53
53
|
async function migrateConfig(legacyConfigPath, options) {
|
|
54
54
|
const warnings = [];
|
|
55
55
|
try {
|
|
56
|
-
const content = await
|
|
56
|
+
const content = await fs4.readFile(legacyConfigPath, "utf-8");
|
|
57
57
|
const legacy = JSON.parse(content);
|
|
58
58
|
let backupPath;
|
|
59
59
|
if (options?.createBackup !== false) {
|
|
60
60
|
const suffix = options?.backupSuffix || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
61
61
|
backupPath = `${legacyConfigPath}.backup-${suffix}`;
|
|
62
|
-
await
|
|
62
|
+
await fs4.writeFile(backupPath, content, "utf-8");
|
|
63
63
|
}
|
|
64
64
|
const yamlConfig = {
|
|
65
65
|
organization: legacy.organization || legacy.organizationSlug || "default"
|
|
@@ -161,15 +161,15 @@ async function migrateConfig(legacyConfigPath, options) {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
async function writeYamlConfig(config, outputPath) {
|
|
164
|
-
const dir =
|
|
165
|
-
await
|
|
166
|
-
const yamlContent =
|
|
164
|
+
const dir = path3.dirname(outputPath);
|
|
165
|
+
await fs4.mkdir(dir, { recursive: true });
|
|
166
|
+
const yamlContent = yaml.dump(config, {
|
|
167
167
|
indent: 2,
|
|
168
168
|
lineWidth: 80,
|
|
169
169
|
noRefs: true,
|
|
170
170
|
sortKeys: false
|
|
171
171
|
});
|
|
172
|
-
await
|
|
172
|
+
await fs4.writeFile(outputPath, yamlContent, "utf-8");
|
|
173
173
|
}
|
|
174
174
|
function getDefaultYamlConfig(organization) {
|
|
175
175
|
return {
|
|
@@ -297,14 +297,14 @@ var init_codex_client = __esm({
|
|
|
297
297
|
const { readYamlConfig } = await Promise.resolve().then(() => (init_migrate_config(), migrate_config_exports));
|
|
298
298
|
const { resolveEnvVarsInConfig } = await Promise.resolve().then(() => (init_config_types(), config_types_exports));
|
|
299
299
|
try {
|
|
300
|
-
const configPath =
|
|
300
|
+
const configPath = path3.join(process.cwd(), ".fractary", "config.yaml");
|
|
301
301
|
let config;
|
|
302
302
|
try {
|
|
303
303
|
config = await readYamlConfig(configPath);
|
|
304
304
|
config = resolveEnvVarsInConfig(config);
|
|
305
305
|
} catch (error) {
|
|
306
306
|
throw new ConfigurationError2(
|
|
307
|
-
`Failed to load configuration from ${configPath}. Run "fractary
|
|
307
|
+
`Failed to load configuration from ${configPath}. Run "fractary-codex configure" to create a configuration.`
|
|
308
308
|
);
|
|
309
309
|
}
|
|
310
310
|
const organization = options?.organizationSlug || config.organization;
|
|
@@ -567,7 +567,7 @@ function getTempCodexPath(config) {
|
|
|
567
567
|
const codexRepo = config.codex_repo || "codex";
|
|
568
568
|
const sanitizedOrg = sanitizePathComponent(config.organization);
|
|
569
569
|
const sanitizedRepo = sanitizePathComponent(codexRepo);
|
|
570
|
-
return
|
|
570
|
+
return path3.join(
|
|
571
571
|
os.tmpdir(),
|
|
572
572
|
"fractary-codex-clone",
|
|
573
573
|
`${sanitizedOrg}-${sanitizedRepo}-${process.pid}`
|
|
@@ -575,8 +575,8 @@ function getTempCodexPath(config) {
|
|
|
575
575
|
}
|
|
576
576
|
async function isValidGitRepo(repoPath) {
|
|
577
577
|
try {
|
|
578
|
-
const gitDir =
|
|
579
|
-
const stats = await
|
|
578
|
+
const gitDir = path3.join(repoPath, ".git");
|
|
579
|
+
const stats = await fs4.stat(gitDir);
|
|
580
580
|
return stats.isDirectory();
|
|
581
581
|
} catch {
|
|
582
582
|
return false;
|
|
@@ -608,8 +608,8 @@ async function execGit(repoPath, args) {
|
|
|
608
608
|
}
|
|
609
609
|
}
|
|
610
610
|
async function gitClone(url, targetPath, options) {
|
|
611
|
-
const parentDir =
|
|
612
|
-
await
|
|
611
|
+
const parentDir = path3.dirname(targetPath);
|
|
612
|
+
await fs4.mkdir(parentDir, { recursive: true });
|
|
613
613
|
const args = ["clone"];
|
|
614
614
|
if (options?.depth) {
|
|
615
615
|
if (!Number.isInteger(options.depth) || options.depth <= 0) {
|
|
@@ -656,12 +656,12 @@ async function ensureCodexCloned(config, options) {
|
|
|
656
656
|
} catch (error) {
|
|
657
657
|
console.warn(`Failed to update existing clone: ${error.message}`);
|
|
658
658
|
console.warn(`Removing and cloning fresh...`);
|
|
659
|
-
await
|
|
659
|
+
await fs4.rm(tempPath, { recursive: true, force: true });
|
|
660
660
|
}
|
|
661
661
|
}
|
|
662
662
|
const repoUrl = getCodexRepoUrl(config);
|
|
663
663
|
try {
|
|
664
|
-
await
|
|
664
|
+
await fs4.rm(tempPath, { recursive: true, force: true });
|
|
665
665
|
} catch (error) {
|
|
666
666
|
console.warn(`Could not remove existing directory ${tempPath}: ${error.message}`);
|
|
667
667
|
}
|
|
@@ -681,100 +681,6 @@ var init_codex_repository = __esm({
|
|
|
681
681
|
// src/cli.ts
|
|
682
682
|
init_esm_shims();
|
|
683
683
|
|
|
684
|
-
// src/commands/document/index.ts
|
|
685
|
-
init_esm_shims();
|
|
686
|
-
|
|
687
|
-
// src/commands/document/fetch.ts
|
|
688
|
-
init_esm_shims();
|
|
689
|
-
|
|
690
|
-
// src/client/get-client.ts
|
|
691
|
-
init_esm_shims();
|
|
692
|
-
var clientInstance = null;
|
|
693
|
-
async function getClient(options) {
|
|
694
|
-
if (!clientInstance) {
|
|
695
|
-
const { CodexClient: CodexClient2 } = await Promise.resolve().then(() => (init_codex_client(), codex_client_exports));
|
|
696
|
-
clientInstance = await CodexClient2.create(options);
|
|
697
|
-
}
|
|
698
|
-
return clientInstance;
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// src/commands/document/fetch.ts
|
|
702
|
-
function hashContent(content) {
|
|
703
|
-
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
704
|
-
}
|
|
705
|
-
function fetchCommand() {
|
|
706
|
-
const cmd = new Command("fetch");
|
|
707
|
-
cmd.description("Fetch a document by codex:// URI reference").argument("<uri>", "Codex URI (e.g., codex://org/project/docs/file.md)").option("--bypass-cache", "Skip cache and fetch directly from source").option("--ttl <seconds>", "Override default TTL (in seconds)", parseInt).option("--json", "Output as JSON with metadata").option("--output <file>", "Write content to file instead of stdout").action(async (uri, options) => {
|
|
708
|
-
try {
|
|
709
|
-
const { validateUri } = await import('@fractary/codex');
|
|
710
|
-
if (!validateUri(uri)) {
|
|
711
|
-
console.error(chalk7.red("Error: Invalid URI format"));
|
|
712
|
-
console.log(chalk7.dim("Expected: codex://org/project/path/to/file.md"));
|
|
713
|
-
console.log(chalk7.dim("Example: codex://fractary/codex/docs/api.md"));
|
|
714
|
-
process.exit(1);
|
|
715
|
-
}
|
|
716
|
-
const client = await getClient();
|
|
717
|
-
if (!options.json && !options.bypassCache) {
|
|
718
|
-
console.error(chalk7.dim(`Fetching ${uri}...`));
|
|
719
|
-
}
|
|
720
|
-
const result = await client.fetch(uri, {
|
|
721
|
-
bypassCache: options.bypassCache,
|
|
722
|
-
ttl: options.ttl
|
|
723
|
-
});
|
|
724
|
-
if (options.json) {
|
|
725
|
-
const output = {
|
|
726
|
-
uri,
|
|
727
|
-
content: result.content.toString("utf-8"),
|
|
728
|
-
metadata: {
|
|
729
|
-
fromCache: result.fromCache,
|
|
730
|
-
fetchedAt: result.metadata?.fetchedAt,
|
|
731
|
-
expiresAt: result.metadata?.expiresAt,
|
|
732
|
-
contentLength: result.metadata?.contentLength || result.content.length,
|
|
733
|
-
contentHash: hashContent(result.content)
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
console.log(JSON.stringify(output, null, 2));
|
|
737
|
-
} else if (options.output) {
|
|
738
|
-
await fs.writeFile(options.output, result.content);
|
|
739
|
-
console.log(chalk7.green("\u2713"), `Written to ${options.output}`);
|
|
740
|
-
console.log(chalk7.dim(` Size: ${result.content.length} bytes`));
|
|
741
|
-
if (result.fromCache) {
|
|
742
|
-
console.log(chalk7.dim(" Source: cache"));
|
|
743
|
-
} else {
|
|
744
|
-
console.log(chalk7.dim(" Source: storage"));
|
|
745
|
-
}
|
|
746
|
-
} else {
|
|
747
|
-
if (result.fromCache && !options.bypassCache) {
|
|
748
|
-
console.error(chalk7.green("\u2713"), chalk7.dim("from cache\n"));
|
|
749
|
-
} else {
|
|
750
|
-
console.error(chalk7.green("\u2713"), chalk7.dim("fetched\n"));
|
|
751
|
-
}
|
|
752
|
-
console.log(result.content.toString("utf-8"));
|
|
753
|
-
}
|
|
754
|
-
} catch (error) {
|
|
755
|
-
console.error(chalk7.red("Error:"), error.message);
|
|
756
|
-
if (error.message.includes("Failed to load configuration")) {
|
|
757
|
-
console.log(chalk7.dim('\nRun "fractary codex init" to create a configuration.'));
|
|
758
|
-
} else if (error.message.includes("GITHUB_TOKEN")) {
|
|
759
|
-
console.log(chalk7.dim('\nSet your GitHub token: export GITHUB_TOKEN="your_token"'));
|
|
760
|
-
} else if (error.message.includes("not found") || error.message.includes("404")) {
|
|
761
|
-
console.log(chalk7.dim("\nThe document may not exist or you may not have access."));
|
|
762
|
-
console.log(chalk7.dim("Check the URI and ensure your storage providers are configured correctly."));
|
|
763
|
-
}
|
|
764
|
-
process.exit(1);
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
return cmd;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
// src/commands/document/index.ts
|
|
771
|
-
function documentCommand() {
|
|
772
|
-
const cmd = new Command("document");
|
|
773
|
-
cmd.description("Manage document operations");
|
|
774
|
-
cmd.addCommand(fetchCommand());
|
|
775
|
-
return cmd;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
684
|
// src/commands/config/index.ts
|
|
779
685
|
init_esm_shims();
|
|
780
686
|
|
|
@@ -842,8 +748,8 @@ function getDefaultUnifiedConfig(organization, project, codexRepo) {
|
|
|
842
748
|
}
|
|
843
749
|
async function readUnifiedConfig(configPath) {
|
|
844
750
|
try {
|
|
845
|
-
const content = await
|
|
846
|
-
const config =
|
|
751
|
+
const content = await fs4.readFile(configPath, "utf-8");
|
|
752
|
+
const config = yaml.load(content);
|
|
847
753
|
return config;
|
|
848
754
|
} catch (error) {
|
|
849
755
|
if (error.code === "ENOENT") {
|
|
@@ -853,15 +759,15 @@ async function readUnifiedConfig(configPath) {
|
|
|
853
759
|
}
|
|
854
760
|
}
|
|
855
761
|
async function writeUnifiedConfig(config, outputPath) {
|
|
856
|
-
const dir =
|
|
857
|
-
await
|
|
858
|
-
const yamlContent =
|
|
762
|
+
const dir = path3.dirname(outputPath);
|
|
763
|
+
await fs4.mkdir(dir, { recursive: true });
|
|
764
|
+
const yamlContent = yaml.dump(config, {
|
|
859
765
|
indent: 2,
|
|
860
766
|
lineWidth: 120,
|
|
861
767
|
noRefs: true,
|
|
862
768
|
sortKeys: false
|
|
863
769
|
});
|
|
864
|
-
await
|
|
770
|
+
await fs4.writeFile(outputPath, yamlContent, "utf-8");
|
|
865
771
|
}
|
|
866
772
|
function mergeUnifiedConfigs(existing, updates) {
|
|
867
773
|
const merged = {};
|
|
@@ -919,9 +825,9 @@ codex/cache/
|
|
|
919
825
|
# ===== end fractary-codex =====
|
|
920
826
|
`;
|
|
921
827
|
async function readFractaryGitignore(projectRoot) {
|
|
922
|
-
const gitignorePath =
|
|
828
|
+
const gitignorePath = path3.join(projectRoot, ".fractary", ".gitignore");
|
|
923
829
|
try {
|
|
924
|
-
return await
|
|
830
|
+
return await fs4.readFile(gitignorePath, "utf-8");
|
|
925
831
|
} catch (error) {
|
|
926
832
|
if (error.code === "ENOENT") {
|
|
927
833
|
return null;
|
|
@@ -930,9 +836,9 @@ async function readFractaryGitignore(projectRoot) {
|
|
|
930
836
|
}
|
|
931
837
|
}
|
|
932
838
|
async function writeFractaryGitignore(projectRoot, content) {
|
|
933
|
-
const gitignorePath =
|
|
934
|
-
await
|
|
935
|
-
await
|
|
839
|
+
const gitignorePath = path3.join(projectRoot, ".fractary", ".gitignore");
|
|
840
|
+
await fs4.mkdir(path3.join(projectRoot, ".fractary"), { recursive: true });
|
|
841
|
+
await fs4.writeFile(gitignorePath, content, "utf-8");
|
|
936
842
|
}
|
|
937
843
|
function normalizeCachePath(cachePath) {
|
|
938
844
|
let normalized = cachePath.replace(/\\/g, "/");
|
|
@@ -969,10 +875,10 @@ function addCachePathToGitignore(gitignoreContent, cachePath, comment) {
|
|
|
969
875
|
return gitignoreContent.trimEnd() + addition;
|
|
970
876
|
}
|
|
971
877
|
async function ensureCachePathIgnored(projectRoot, cachePath) {
|
|
972
|
-
const gitignorePath =
|
|
878
|
+
const gitignorePath = path3.join(projectRoot, ".fractary", ".gitignore");
|
|
973
879
|
let relativeCachePath = cachePath;
|
|
974
|
-
if (
|
|
975
|
-
relativeCachePath =
|
|
880
|
+
if (path3.isAbsolute(cachePath)) {
|
|
881
|
+
relativeCachePath = path3.relative(path3.join(projectRoot, ".fractary"), cachePath);
|
|
976
882
|
}
|
|
977
883
|
relativeCachePath = normalizeCachePath(relativeCachePath);
|
|
978
884
|
let content = await readFractaryGitignore(projectRoot);
|
|
@@ -1090,27 +996,27 @@ async function discoverCodexRepo(org) {
|
|
|
1090
996
|
}
|
|
1091
997
|
async function fileExists(filePath) {
|
|
1092
998
|
try {
|
|
1093
|
-
await
|
|
999
|
+
await fs4.access(filePath);
|
|
1094
1000
|
return true;
|
|
1095
1001
|
} catch {
|
|
1096
1002
|
return false;
|
|
1097
1003
|
}
|
|
1098
1004
|
}
|
|
1099
1005
|
async function installMcpServer(projectRoot, configPath = ".fractary/config.yaml", options = {}) {
|
|
1100
|
-
const mcpJsonPath =
|
|
1006
|
+
const mcpJsonPath = path3.join(projectRoot, ".mcp.json");
|
|
1101
1007
|
const { backup = true } = options;
|
|
1102
1008
|
let existingConfig = { mcpServers: {} };
|
|
1103
1009
|
let backupPath;
|
|
1104
1010
|
let migrated = false;
|
|
1105
1011
|
if (await fileExists(mcpJsonPath)) {
|
|
1106
1012
|
try {
|
|
1107
|
-
const content = await
|
|
1013
|
+
const content = await fs4.readFile(mcpJsonPath, "utf-8");
|
|
1108
1014
|
existingConfig = JSON.parse(content);
|
|
1109
1015
|
if (backup) {
|
|
1110
1016
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 18);
|
|
1111
1017
|
const suffix = Math.random().toString(36).substring(2, 6);
|
|
1112
1018
|
backupPath = `${mcpJsonPath}.backup.${timestamp}-${suffix}`;
|
|
1113
|
-
await
|
|
1019
|
+
await fs4.writeFile(backupPath, content);
|
|
1114
1020
|
}
|
|
1115
1021
|
} catch {
|
|
1116
1022
|
console.log(chalk7.yellow("\u26A0 Warning: .mcp.json contains invalid JSON, starting fresh"));
|
|
@@ -1140,7 +1046,7 @@ async function installMcpServer(projectRoot, configPath = ".fractary/config.yaml
|
|
|
1140
1046
|
command: "npx",
|
|
1141
1047
|
args: ["-y", "@fractary/codex-mcp", "--config", configPath]
|
|
1142
1048
|
};
|
|
1143
|
-
await
|
|
1049
|
+
await fs4.writeFile(
|
|
1144
1050
|
mcpJsonPath,
|
|
1145
1051
|
JSON.stringify(existingConfig, null, 2) + "\n"
|
|
1146
1052
|
);
|
|
@@ -1151,8 +1057,8 @@ async function installMcpServer(projectRoot, configPath = ".fractary/config.yaml
|
|
|
1151
1057
|
backupPath
|
|
1152
1058
|
};
|
|
1153
1059
|
}
|
|
1154
|
-
function
|
|
1155
|
-
const cmd = new Command("
|
|
1060
|
+
function configureCommand() {
|
|
1061
|
+
const cmd = new Command("configure");
|
|
1156
1062
|
cmd.description("Initialize unified Fractary configuration (.fractary/config.yaml)").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--project <name>", "Project name (default: derived from directory)").option("--codex-repo <name>", 'Codex repository name (e.g., "codex.fractary.com")').option("--force", "Overwrite existing configuration").option("--no-mcp", "Skip MCP server installation").action(async (options) => {
|
|
1157
1063
|
try {
|
|
1158
1064
|
console.log(chalk7.blue("Initializing unified Fractary configuration...\n"));
|
|
@@ -1164,13 +1070,13 @@ function initCommand() {
|
|
|
1164
1070
|
try {
|
|
1165
1071
|
const { resolveOrganization } = await import('@fractary/codex');
|
|
1166
1072
|
org = resolveOrganization({
|
|
1167
|
-
repoName:
|
|
1073
|
+
repoName: path3.basename(process.cwd())
|
|
1168
1074
|
});
|
|
1169
1075
|
} catch {
|
|
1170
1076
|
}
|
|
1171
1077
|
}
|
|
1172
1078
|
if (!org) {
|
|
1173
|
-
org =
|
|
1079
|
+
org = path3.basename(process.cwd()).split("-")[0] || "default";
|
|
1174
1080
|
console.log(chalk7.yellow(`\u26A0 Could not detect organization, using: ${org}`));
|
|
1175
1081
|
console.log(chalk7.dim(" Use --org <slug> to specify explicitly\n"));
|
|
1176
1082
|
} else {
|
|
@@ -1185,7 +1091,7 @@ function initCommand() {
|
|
|
1185
1091
|
}
|
|
1186
1092
|
let project = options.project;
|
|
1187
1093
|
if (!project) {
|
|
1188
|
-
project =
|
|
1094
|
+
project = path3.basename(process.cwd());
|
|
1189
1095
|
console.log(chalk7.dim(`Project: ${chalk7.cyan(project)}
|
|
1190
1096
|
`));
|
|
1191
1097
|
}
|
|
@@ -1226,7 +1132,7 @@ function initCommand() {
|
|
|
1226
1132
|
console.log(chalk7.dim(` Using default: ${chalk7.cyan(codexRepo)}
|
|
1227
1133
|
`));
|
|
1228
1134
|
}
|
|
1229
|
-
const configPath =
|
|
1135
|
+
const configPath = path3.join(process.cwd(), ".fractary", "config.yaml");
|
|
1230
1136
|
const configExists = await fileExists(configPath);
|
|
1231
1137
|
if (configExists && !options.force) {
|
|
1232
1138
|
console.log(chalk7.yellow(`\u26A0 Configuration already exists at .fractary/config.yaml`));
|
|
@@ -1241,7 +1147,7 @@ function initCommand() {
|
|
|
1241
1147
|
".fractary/codex/cache"
|
|
1242
1148
|
];
|
|
1243
1149
|
for (const dir of dirs) {
|
|
1244
|
-
await
|
|
1150
|
+
await fs4.mkdir(path3.join(process.cwd(), dir), { recursive: true });
|
|
1245
1151
|
console.log(chalk7.green("\u2713"), chalk7.dim(dir + "/"));
|
|
1246
1152
|
}
|
|
1247
1153
|
const gitignoreResult = await ensureCachePathIgnored(process.cwd(), ".fractary/codex/cache");
|
|
@@ -1273,7 +1179,7 @@ function initCommand() {
|
|
|
1273
1179
|
} else if (mcpResult.migrated) {
|
|
1274
1180
|
console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (migrated from old format)"));
|
|
1275
1181
|
if (mcpResult.backupPath) {
|
|
1276
|
-
console.log(chalk7.dim(` Backup: ${
|
|
1182
|
+
console.log(chalk7.dim(` Backup: ${path3.basename(mcpResult.backupPath)}`));
|
|
1277
1183
|
}
|
|
1278
1184
|
} else if (mcpResult.installed) {
|
|
1279
1185
|
console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (created)"));
|
|
@@ -1311,11 +1217,89 @@ function initCommand() {
|
|
|
1311
1217
|
return cmd;
|
|
1312
1218
|
}
|
|
1313
1219
|
|
|
1314
|
-
// src/commands/
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1220
|
+
// src/commands/document/index.ts
|
|
1221
|
+
init_esm_shims();
|
|
1222
|
+
|
|
1223
|
+
// src/commands/document/fetch.ts
|
|
1224
|
+
init_esm_shims();
|
|
1225
|
+
|
|
1226
|
+
// src/client/get-client.ts
|
|
1227
|
+
init_esm_shims();
|
|
1228
|
+
var clientInstance = null;
|
|
1229
|
+
async function getClient(options) {
|
|
1230
|
+
if (!clientInstance) {
|
|
1231
|
+
const { CodexClient: CodexClient2 } = await Promise.resolve().then(() => (init_codex_client(), codex_client_exports));
|
|
1232
|
+
clientInstance = await CodexClient2.create(options);
|
|
1233
|
+
}
|
|
1234
|
+
return clientInstance;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// src/commands/document/fetch.ts
|
|
1238
|
+
function hashContent(content) {
|
|
1239
|
+
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
1240
|
+
}
|
|
1241
|
+
function documentFetchCommand() {
|
|
1242
|
+
const cmd = new Command("document-fetch");
|
|
1243
|
+
cmd.description("Fetch a document by codex:// URI reference").argument("<uri>", "Codex URI (e.g., codex://org/project/docs/file.md)").option("--bypass-cache", "Skip cache and fetch directly from source").option("--ttl <seconds>", "Override default TTL (in seconds)", parseInt).option("--json", "Output as JSON with metadata").option("--output <file>", "Write content to file instead of stdout").action(async (uri, options) => {
|
|
1244
|
+
try {
|
|
1245
|
+
const { validateUri } = await import('@fractary/codex');
|
|
1246
|
+
if (!validateUri(uri)) {
|
|
1247
|
+
console.error(chalk7.red("Error: Invalid URI format"));
|
|
1248
|
+
console.log(chalk7.dim("Expected: codex://org/project/path/to/file.md"));
|
|
1249
|
+
console.log(chalk7.dim("Example: codex://fractary/codex/docs/api.md"));
|
|
1250
|
+
process.exit(1);
|
|
1251
|
+
}
|
|
1252
|
+
const client = await getClient();
|
|
1253
|
+
if (!options.json && !options.bypassCache) {
|
|
1254
|
+
console.error(chalk7.dim(`Fetching ${uri}...`));
|
|
1255
|
+
}
|
|
1256
|
+
const result = await client.fetch(uri, {
|
|
1257
|
+
bypassCache: options.bypassCache,
|
|
1258
|
+
ttl: options.ttl
|
|
1259
|
+
});
|
|
1260
|
+
if (options.json) {
|
|
1261
|
+
const output = {
|
|
1262
|
+
uri,
|
|
1263
|
+
content: result.content.toString("utf-8"),
|
|
1264
|
+
metadata: {
|
|
1265
|
+
fromCache: result.fromCache,
|
|
1266
|
+
fetchedAt: result.metadata?.fetchedAt,
|
|
1267
|
+
expiresAt: result.metadata?.expiresAt,
|
|
1268
|
+
contentLength: result.metadata?.contentLength || result.content.length,
|
|
1269
|
+
contentHash: hashContent(result.content)
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
console.log(JSON.stringify(output, null, 2));
|
|
1273
|
+
} else if (options.output) {
|
|
1274
|
+
await fs4.writeFile(options.output, result.content);
|
|
1275
|
+
console.log(chalk7.green("\u2713"), `Written to ${options.output}`);
|
|
1276
|
+
console.log(chalk7.dim(` Size: ${result.content.length} bytes`));
|
|
1277
|
+
if (result.fromCache) {
|
|
1278
|
+
console.log(chalk7.dim(" Source: cache"));
|
|
1279
|
+
} else {
|
|
1280
|
+
console.log(chalk7.dim(" Source: storage"));
|
|
1281
|
+
}
|
|
1282
|
+
} else {
|
|
1283
|
+
if (result.fromCache && !options.bypassCache) {
|
|
1284
|
+
console.error(chalk7.green("\u2713"), chalk7.dim("from cache\n"));
|
|
1285
|
+
} else {
|
|
1286
|
+
console.error(chalk7.green("\u2713"), chalk7.dim("fetched\n"));
|
|
1287
|
+
}
|
|
1288
|
+
console.log(result.content.toString("utf-8"));
|
|
1289
|
+
}
|
|
1290
|
+
} catch (error) {
|
|
1291
|
+
console.error(chalk7.red("Error:"), error.message);
|
|
1292
|
+
if (error.message.includes("Failed to load configuration")) {
|
|
1293
|
+
console.log(chalk7.dim('\nRun "fractary-codex configure" to create a configuration.'));
|
|
1294
|
+
} else if (error.message.includes("GITHUB_TOKEN")) {
|
|
1295
|
+
console.log(chalk7.dim('\nSet your GitHub token: export GITHUB_TOKEN="your_token"'));
|
|
1296
|
+
} else if (error.message.includes("not found") || error.message.includes("404")) {
|
|
1297
|
+
console.log(chalk7.dim("\nThe document may not exist or you may not have access."));
|
|
1298
|
+
console.log(chalk7.dim("Check the URI and ensure your storage providers are configured correctly."));
|
|
1299
|
+
}
|
|
1300
|
+
process.exit(1);
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1319
1303
|
return cmd;
|
|
1320
1304
|
}
|
|
1321
1305
|
|
|
@@ -1330,7 +1314,7 @@ function formatSize(bytes) {
|
|
|
1330
1314
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1331
1315
|
}
|
|
1332
1316
|
function cacheListCommand() {
|
|
1333
|
-
const cmd = new Command("list");
|
|
1317
|
+
const cmd = new Command("cache-list");
|
|
1334
1318
|
cmd.description("List cache information").option("--json", "Output as JSON").action(async (options) => {
|
|
1335
1319
|
try {
|
|
1336
1320
|
const client = await getClient();
|
|
@@ -1369,8 +1353,8 @@ function cacheListCommand() {
|
|
|
1369
1353
|
console.log(`Cache health: ${healthColor(`${healthPercent.toFixed(0)}% fresh`)}`);
|
|
1370
1354
|
console.log("");
|
|
1371
1355
|
console.log(chalk7.dim("Note: Individual cache entries are managed by the SDK."));
|
|
1372
|
-
console.log(chalk7.dim('Use "fractary
|
|
1373
|
-
console.log(chalk7.dim('Use "fractary
|
|
1356
|
+
console.log(chalk7.dim('Use "fractary-codex cache-stats" for detailed statistics.'));
|
|
1357
|
+
console.log(chalk7.dim('Use "fractary-codex cache-clear" to clear cache entries.'));
|
|
1374
1358
|
} catch (error) {
|
|
1375
1359
|
console.error(chalk7.red("Error:"), error.message);
|
|
1376
1360
|
process.exit(1);
|
|
@@ -1382,7 +1366,7 @@ function cacheListCommand() {
|
|
|
1382
1366
|
// src/commands/cache/clear.ts
|
|
1383
1367
|
init_esm_shims();
|
|
1384
1368
|
function cacheClearCommand() {
|
|
1385
|
-
const cmd = new Command("clear");
|
|
1369
|
+
const cmd = new Command("cache-clear");
|
|
1386
1370
|
cmd.description("Clear cache entries").option("--all", "Clear entire cache").option("--pattern <glob>", 'Clear entries matching URI pattern (e.g., "codex://fractary/*")').option("--dry-run", "Show what would be cleared without actually clearing").action(async (options) => {
|
|
1387
1371
|
try {
|
|
1388
1372
|
const client = await getClient();
|
|
@@ -1402,8 +1386,8 @@ function cacheClearCommand() {
|
|
|
1402
1386
|
console.log(chalk7.dim(' --pattern Clear entries matching pattern (e.g., "codex://fractary/*")'));
|
|
1403
1387
|
console.log("");
|
|
1404
1388
|
console.log(chalk7.dim("Examples:"));
|
|
1405
|
-
console.log(chalk7.dim(" fractary
|
|
1406
|
-
console.log(chalk7.dim(' fractary
|
|
1389
|
+
console.log(chalk7.dim(" fractary-codex cache-clear --all"));
|
|
1390
|
+
console.log(chalk7.dim(' fractary-codex cache-clear --pattern "codex://fractary/cli/*"'));
|
|
1407
1391
|
return;
|
|
1408
1392
|
}
|
|
1409
1393
|
if (options.dryRun) {
|
|
@@ -1455,7 +1439,7 @@ function formatSize3(bytes) {
|
|
|
1455
1439
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1456
1440
|
}
|
|
1457
1441
|
function cacheStatsCommand() {
|
|
1458
|
-
const cmd = new Command("stats");
|
|
1442
|
+
const cmd = new Command("cache-stats");
|
|
1459
1443
|
cmd.description("Display cache statistics").option("--json", "Output as JSON").action(async (options) => {
|
|
1460
1444
|
try {
|
|
1461
1445
|
const client = await getClient();
|
|
@@ -1476,7 +1460,7 @@ function cacheStatsCommand() {
|
|
|
1476
1460
|
const healthColor = healthPercent > 80 ? chalk7.green : healthPercent > 50 ? chalk7.yellow : chalk7.red;
|
|
1477
1461
|
console.log(`Cache health: ${healthColor(`${healthPercent.toFixed(0)}% fresh`)}`);
|
|
1478
1462
|
if (stats.expiredCount > 0) {
|
|
1479
|
-
console.log(chalk7.dim('\nRun "fractary
|
|
1463
|
+
console.log(chalk7.dim('\nRun "fractary-codex cache-clear --pattern <pattern>" to clean up entries.'));
|
|
1480
1464
|
}
|
|
1481
1465
|
if (stats.entryCount === 0) {
|
|
1482
1466
|
console.log(chalk7.dim("\nNo cached entries. Fetch some documents to populate the cache."));
|
|
@@ -1494,15 +1478,15 @@ init_esm_shims();
|
|
|
1494
1478
|
init_migrate_config();
|
|
1495
1479
|
async function fileExists2(filePath) {
|
|
1496
1480
|
try {
|
|
1497
|
-
await
|
|
1481
|
+
await fs4.access(filePath);
|
|
1498
1482
|
return true;
|
|
1499
1483
|
} catch {
|
|
1500
1484
|
return false;
|
|
1501
1485
|
}
|
|
1502
1486
|
}
|
|
1503
1487
|
async function checkConfiguration() {
|
|
1504
|
-
const configPath =
|
|
1505
|
-
const legacyConfigPath =
|
|
1488
|
+
const configPath = path3.join(process.cwd(), ".fractary", "config.yaml");
|
|
1489
|
+
const legacyConfigPath = path3.join(process.cwd(), ".fractary", "plugins", "codex", "config.json");
|
|
1506
1490
|
try {
|
|
1507
1491
|
if (!await fileExists2(configPath)) {
|
|
1508
1492
|
if (await fileExists2(legacyConfigPath)) {
|
|
@@ -1510,14 +1494,14 @@ async function checkConfiguration() {
|
|
|
1510
1494
|
name: "Configuration",
|
|
1511
1495
|
status: "warn",
|
|
1512
1496
|
message: "Legacy JSON configuration detected",
|
|
1513
|
-
details:
|
|
1497
|
+
details: "Migration from legacy JSON format may be required"
|
|
1514
1498
|
};
|
|
1515
1499
|
}
|
|
1516
1500
|
return {
|
|
1517
1501
|
name: "Configuration",
|
|
1518
1502
|
status: "fail",
|
|
1519
1503
|
message: "No configuration found",
|
|
1520
|
-
details: 'Run "fractary
|
|
1504
|
+
details: 'Run "fractary-codex configure" to create configuration'
|
|
1521
1505
|
};
|
|
1522
1506
|
}
|
|
1523
1507
|
const config = await readCodexConfig(configPath);
|
|
@@ -1609,7 +1593,7 @@ async function checkCache() {
|
|
|
1609
1593
|
}
|
|
1610
1594
|
}
|
|
1611
1595
|
async function checkStorage() {
|
|
1612
|
-
const configPath =
|
|
1596
|
+
const configPath = path3.join(process.cwd(), ".fractary", "config.yaml");
|
|
1613
1597
|
try {
|
|
1614
1598
|
const config = await readCodexConfig(configPath);
|
|
1615
1599
|
const providers = config.storage || [];
|
|
@@ -1673,8 +1657,8 @@ function formatSize4(bytes) {
|
|
|
1673
1657
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1674
1658
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1675
1659
|
}
|
|
1676
|
-
function
|
|
1677
|
-
const cmd = new Command("health");
|
|
1660
|
+
function cacheHealthCommand() {
|
|
1661
|
+
const cmd = new Command("cache-health");
|
|
1678
1662
|
cmd.description("Run diagnostics on codex setup").option("--json", "Output as JSON").action(async (options) => {
|
|
1679
1663
|
try {
|
|
1680
1664
|
const checks = [];
|
|
@@ -1717,8 +1701,7 @@ function healthCommand() {
|
|
|
1717
1701
|
if (failed > 0 || warned > 0) {
|
|
1718
1702
|
console.log("");
|
|
1719
1703
|
console.log(chalk7.dim("Run checks individually for more details:"));
|
|
1720
|
-
console.log(chalk7.dim(" fractary
|
|
1721
|
-
console.log(chalk7.dim(" fractary codex types list"));
|
|
1704
|
+
console.log(chalk7.dim(" fractary-codex cache-stats"));
|
|
1722
1705
|
}
|
|
1723
1706
|
if (failed > 0) {
|
|
1724
1707
|
process.exit(1);
|
|
@@ -1731,17 +1714,6 @@ function healthCommand() {
|
|
|
1731
1714
|
return cmd;
|
|
1732
1715
|
}
|
|
1733
1716
|
|
|
1734
|
-
// src/commands/cache/index.ts
|
|
1735
|
-
function cacheCommand() {
|
|
1736
|
-
const cmd = new Command("cache");
|
|
1737
|
-
cmd.description("Manage the codex document cache");
|
|
1738
|
-
cmd.addCommand(cacheListCommand());
|
|
1739
|
-
cmd.addCommand(cacheClearCommand());
|
|
1740
|
-
cmd.addCommand(cacheStatsCommand());
|
|
1741
|
-
cmd.addCommand(healthCommand());
|
|
1742
|
-
return cmd;
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
1717
|
// src/commands/sync.ts
|
|
1746
1718
|
init_esm_shims();
|
|
1747
1719
|
init_migrate_config();
|
|
@@ -1765,15 +1737,15 @@ function formatDuration(ms) {
|
|
|
1765
1737
|
}
|
|
1766
1738
|
function syncCommand() {
|
|
1767
1739
|
const cmd = new Command("sync");
|
|
1768
|
-
cmd.description("Sync single project with codex repository").argument("[name]", "Project name (auto-detected if not provided)").option("--env <env>", "Target environment (dev/test/staging/prod)", "prod").option("--dry-run", "Show what would sync without executing").option("--direction <dir>", "Sync direction (to-codex/from-codex/bidirectional)", "bidirectional").option("--include <pattern>", "Include files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--exclude <pattern>", "Exclude files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--force", "Force sync without checking timestamps").option("--json", "Output as JSON").action(async (name, options) => {
|
|
1740
|
+
cmd.description("Sync single project with codex repository").argument("[name]", "Project name (auto-detected if not provided)").option("--env <env>", "Target environment (dev/test/staging/prod)", "prod").option("--dry-run", "Show what would sync without executing").option("--direction <dir>", "Sync direction (to-codex/from-codex/bidirectional)", "bidirectional").option("--include <pattern>", "Include files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--exclude <pattern>", "Exclude files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--force", "Force sync without checking timestamps").option("--json", "Output as JSON").option("--work-id <id>", "GitHub issue number or URL to scope sync to").action(async (name, options) => {
|
|
1769
1741
|
try {
|
|
1770
|
-
const configPath =
|
|
1742
|
+
const configPath = path3.join(process.cwd(), ".fractary", "config.yaml");
|
|
1771
1743
|
let config;
|
|
1772
1744
|
try {
|
|
1773
1745
|
config = await readCodexConfig(configPath);
|
|
1774
1746
|
} catch (error) {
|
|
1775
1747
|
console.error(chalk7.red("Error:"), "Codex not initialized.");
|
|
1776
|
-
console.log(chalk7.dim('Run "fractary
|
|
1748
|
+
console.log(chalk7.dim('Run "fractary-codex configure" first.'));
|
|
1777
1749
|
process.exit(1);
|
|
1778
1750
|
}
|
|
1779
1751
|
const { createSyncManager, createLocalStorage, detectCurrentProject } = await import('@fractary/codex');
|
|
@@ -1804,7 +1776,7 @@ function syncCommand() {
|
|
|
1804
1776
|
const syncManager = createSyncManager({
|
|
1805
1777
|
localStorage,
|
|
1806
1778
|
config: config.sync,
|
|
1807
|
-
manifestPath:
|
|
1779
|
+
manifestPath: path3.join(process.cwd(), ".fractary", ".codex-sync-manifest.json")
|
|
1808
1780
|
});
|
|
1809
1781
|
const defaultToCodexPatterns = [
|
|
1810
1782
|
"docs/**/*.md",
|
|
@@ -1839,7 +1811,7 @@ function syncCommand() {
|
|
|
1839
1811
|
}
|
|
1840
1812
|
const targetFiles = await Promise.all(
|
|
1841
1813
|
Array.from(matchedFilePaths).map(async (filePath) => {
|
|
1842
|
-
const fullPath =
|
|
1814
|
+
const fullPath = path3.join(sourceDir, filePath);
|
|
1843
1815
|
const stats = await import('fs/promises').then((fs8) => fs8.stat(fullPath));
|
|
1844
1816
|
return {
|
|
1845
1817
|
path: filePath,
|
|
@@ -1942,15 +1914,18 @@ function syncCommand() {
|
|
|
1942
1914
|
syncOptions
|
|
1943
1915
|
);
|
|
1944
1916
|
plan.source = sourceDir;
|
|
1945
|
-
plan.target =
|
|
1917
|
+
plan.target = path3.join(codexRepoPath, "projects", projectName);
|
|
1946
1918
|
}
|
|
1947
1919
|
if (plan.totalFiles === 0) {
|
|
1948
1920
|
if (options.json) {
|
|
1949
1921
|
console.log(JSON.stringify({
|
|
1950
1922
|
project: projectName,
|
|
1951
1923
|
organization: config.organization,
|
|
1924
|
+
workId: options.workId || null,
|
|
1952
1925
|
files: [],
|
|
1953
|
-
synced: 0
|
|
1926
|
+
synced: 0,
|
|
1927
|
+
status: "success",
|
|
1928
|
+
message: "No files to sync"
|
|
1954
1929
|
}, null, 2));
|
|
1955
1930
|
} else {
|
|
1956
1931
|
console.log(chalk7.yellow("No files to sync."));
|
|
@@ -1965,6 +1940,7 @@ function syncCommand() {
|
|
|
1965
1940
|
branch: targetBranch,
|
|
1966
1941
|
direction,
|
|
1967
1942
|
dryRun: options.dryRun || false,
|
|
1943
|
+
workId: options.workId || null,
|
|
1968
1944
|
plan: {
|
|
1969
1945
|
totalFiles: plan.totalFiles,
|
|
1970
1946
|
totalBytes: plan.totalBytes,
|
|
@@ -1979,12 +1955,24 @@ function syncCommand() {
|
|
|
1979
1955
|
}))
|
|
1980
1956
|
};
|
|
1981
1957
|
if (options.dryRun) {
|
|
1982
|
-
console.log(JSON.stringify(
|
|
1958
|
+
console.log(JSON.stringify({
|
|
1959
|
+
...output,
|
|
1960
|
+
status: "success"
|
|
1961
|
+
}, null, 2));
|
|
1983
1962
|
return;
|
|
1984
1963
|
}
|
|
1985
1964
|
const result2 = await syncManager.executePlan(plan, syncOptions);
|
|
1965
|
+
let status;
|
|
1966
|
+
if (!result2.success && result2.synced === 0) {
|
|
1967
|
+
status = "failure";
|
|
1968
|
+
} else if (!result2.success || result2.failed > 0 || plan.conflicts.length > 0) {
|
|
1969
|
+
status = "warning";
|
|
1970
|
+
} else {
|
|
1971
|
+
status = "success";
|
|
1972
|
+
}
|
|
1986
1973
|
console.log(JSON.stringify({
|
|
1987
1974
|
...output,
|
|
1975
|
+
status,
|
|
1988
1976
|
result: {
|
|
1989
1977
|
success: result2.success,
|
|
1990
1978
|
synced: result2.synced,
|
|
@@ -2118,349 +2106,6 @@ Total: ${plan.totalFiles} files (${formatBytes(plan.totalBytes)})`));
|
|
|
2118
2106
|
});
|
|
2119
2107
|
return cmd;
|
|
2120
2108
|
}
|
|
2121
|
-
|
|
2122
|
-
// src/commands/types/index.ts
|
|
2123
|
-
init_esm_shims();
|
|
2124
|
-
|
|
2125
|
-
// src/commands/types/list.ts
|
|
2126
|
-
init_esm_shims();
|
|
2127
|
-
function formatTtl(seconds) {
|
|
2128
|
-
if (seconds < 60) return `${seconds}s`;
|
|
2129
|
-
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
2130
|
-
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
2131
|
-
return `${Math.floor(seconds / 86400)}d`;
|
|
2132
|
-
}
|
|
2133
|
-
function typesListCommand() {
|
|
2134
|
-
const cmd = new Command("list");
|
|
2135
|
-
cmd.description("List all artifact types").option("--json", "Output as JSON").option("--custom-only", "Show only custom types").option("--builtin-only", "Show only built-in types").action(async (options) => {
|
|
2136
|
-
try {
|
|
2137
|
-
const client = await getClient();
|
|
2138
|
-
const registry = client.getTypeRegistry();
|
|
2139
|
-
const allTypes = registry.list();
|
|
2140
|
-
let types = allTypes;
|
|
2141
|
-
if (options.customOnly) {
|
|
2142
|
-
types = allTypes.filter((t) => !registry.isBuiltIn(t.name));
|
|
2143
|
-
} else if (options.builtinOnly) {
|
|
2144
|
-
types = allTypes.filter((t) => registry.isBuiltIn(t.name));
|
|
2145
|
-
}
|
|
2146
|
-
if (options.json) {
|
|
2147
|
-
const builtinCount = types.filter((t) => registry.isBuiltIn(t.name)).length;
|
|
2148
|
-
const customCount = types.length - builtinCount;
|
|
2149
|
-
console.log(JSON.stringify({
|
|
2150
|
-
count: types.length,
|
|
2151
|
-
builtinCount,
|
|
2152
|
-
customCount,
|
|
2153
|
-
types: types.map((t) => ({
|
|
2154
|
-
name: t.name,
|
|
2155
|
-
description: t.description,
|
|
2156
|
-
patterns: t.patterns,
|
|
2157
|
-
defaultTtl: t.defaultTtl,
|
|
2158
|
-
ttl: formatTtl(t.defaultTtl),
|
|
2159
|
-
builtin: registry.isBuiltIn(t.name),
|
|
2160
|
-
archiveAfterDays: t.archiveAfterDays,
|
|
2161
|
-
archiveStorage: t.archiveStorage
|
|
2162
|
-
}))
|
|
2163
|
-
}, null, 2));
|
|
2164
|
-
return;
|
|
2165
|
-
}
|
|
2166
|
-
if (types.length === 0) {
|
|
2167
|
-
console.log(chalk7.yellow("No types found."));
|
|
2168
|
-
return;
|
|
2169
|
-
}
|
|
2170
|
-
console.log(chalk7.bold("Artifact Types\n"));
|
|
2171
|
-
const builtinTypes = types.filter((t) => registry.isBuiltIn(t.name));
|
|
2172
|
-
const customTypes = types.filter((t) => !registry.isBuiltIn(t.name));
|
|
2173
|
-
if (builtinTypes.length > 0 && !options.customOnly) {
|
|
2174
|
-
console.log(chalk7.bold("Built-in Types"));
|
|
2175
|
-
console.log(chalk7.dim("\u2500".repeat(70)));
|
|
2176
|
-
for (const type of builtinTypes) {
|
|
2177
|
-
const patternStr = type.patterns[0] || "";
|
|
2178
|
-
console.log(` ${chalk7.cyan(type.name.padEnd(12))} ${patternStr.padEnd(30)} ${chalk7.dim(`TTL: ${formatTtl(type.defaultTtl)}`)}`);
|
|
2179
|
-
console.log(` ${chalk7.dim(" ".repeat(12) + type.description)}`);
|
|
2180
|
-
}
|
|
2181
|
-
console.log("");
|
|
2182
|
-
}
|
|
2183
|
-
if (customTypes.length > 0 && !options.builtinOnly) {
|
|
2184
|
-
console.log(chalk7.bold("Custom Types"));
|
|
2185
|
-
console.log(chalk7.dim("\u2500".repeat(70)));
|
|
2186
|
-
for (const type of customTypes) {
|
|
2187
|
-
const patternStr = type.patterns[0] || "";
|
|
2188
|
-
console.log(` ${chalk7.green(type.name.padEnd(12))} ${patternStr.padEnd(30)} ${chalk7.dim(`TTL: ${formatTtl(type.defaultTtl)}`)}`);
|
|
2189
|
-
console.log(` ${chalk7.dim(" ".repeat(12) + type.description)}`);
|
|
2190
|
-
}
|
|
2191
|
-
console.log("");
|
|
2192
|
-
}
|
|
2193
|
-
console.log(chalk7.dim(`Total: ${types.length} types (${builtinTypes.length} built-in, ${customTypes.length} custom)`));
|
|
2194
|
-
} catch (error) {
|
|
2195
|
-
console.error(chalk7.red("Error:"), error.message);
|
|
2196
|
-
process.exit(1);
|
|
2197
|
-
}
|
|
2198
|
-
});
|
|
2199
|
-
return cmd;
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
// src/commands/types/show.ts
|
|
2203
|
-
init_esm_shims();
|
|
2204
|
-
function formatTtl2(seconds) {
|
|
2205
|
-
if (seconds < 60) return `${seconds}s`;
|
|
2206
|
-
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
2207
|
-
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
2208
|
-
return `${Math.floor(seconds / 86400)}d`;
|
|
2209
|
-
}
|
|
2210
|
-
function typesShowCommand() {
|
|
2211
|
-
const cmd = new Command("show");
|
|
2212
|
-
cmd.description("Show details for a specific type").argument("<name>", "Type name").option("--json", "Output as JSON").action(async (name, options) => {
|
|
2213
|
-
try {
|
|
2214
|
-
const client = await getClient();
|
|
2215
|
-
const registry = client.getTypeRegistry();
|
|
2216
|
-
const type = registry.get(name);
|
|
2217
|
-
if (!type) {
|
|
2218
|
-
console.error(chalk7.red("Error:"), `Type "${name}" not found.`);
|
|
2219
|
-
console.log(chalk7.dim('Run "fractary codex types list" to see available types.'));
|
|
2220
|
-
process.exit(1);
|
|
2221
|
-
}
|
|
2222
|
-
const isBuiltin = registry.isBuiltIn(name);
|
|
2223
|
-
if (options.json) {
|
|
2224
|
-
console.log(JSON.stringify({
|
|
2225
|
-
name: type.name,
|
|
2226
|
-
builtin: isBuiltin,
|
|
2227
|
-
description: type.description,
|
|
2228
|
-
patterns: type.patterns,
|
|
2229
|
-
defaultTtl: type.defaultTtl,
|
|
2230
|
-
ttl: formatTtl2(type.defaultTtl),
|
|
2231
|
-
archiveAfterDays: type.archiveAfterDays,
|
|
2232
|
-
archiveStorage: type.archiveStorage,
|
|
2233
|
-
syncPatterns: type.syncPatterns,
|
|
2234
|
-
excludePatterns: type.excludePatterns
|
|
2235
|
-
}, null, 2));
|
|
2236
|
-
return;
|
|
2237
|
-
}
|
|
2238
|
-
const nameColor = isBuiltin ? chalk7.cyan : chalk7.green;
|
|
2239
|
-
console.log(chalk7.bold(`Type: ${nameColor(name)}
|
|
2240
|
-
`));
|
|
2241
|
-
console.log(` ${chalk7.dim("Source:")} ${isBuiltin ? "Built-in" : "Custom"}`);
|
|
2242
|
-
console.log(` ${chalk7.dim("Description:")} ${type.description}`);
|
|
2243
|
-
console.log(` ${chalk7.dim("TTL:")} ${formatTtl2(type.defaultTtl)} (${type.defaultTtl} seconds)`);
|
|
2244
|
-
console.log("");
|
|
2245
|
-
console.log(chalk7.bold("Patterns"));
|
|
2246
|
-
for (const pattern of type.patterns) {
|
|
2247
|
-
console.log(` ${chalk7.dim("\u2022")} ${pattern}`);
|
|
2248
|
-
}
|
|
2249
|
-
if (type.archiveAfterDays !== null) {
|
|
2250
|
-
console.log("");
|
|
2251
|
-
console.log(chalk7.bold("Archive Settings"));
|
|
2252
|
-
console.log(` ${chalk7.dim("After:")} ${type.archiveAfterDays} days`);
|
|
2253
|
-
console.log(` ${chalk7.dim("Storage:")} ${type.archiveStorage || "not set"}`);
|
|
2254
|
-
}
|
|
2255
|
-
if (type.syncPatterns && type.syncPatterns.length > 0) {
|
|
2256
|
-
console.log("");
|
|
2257
|
-
console.log(chalk7.bold("Sync Patterns"));
|
|
2258
|
-
for (const pattern of type.syncPatterns) {
|
|
2259
|
-
console.log(` ${chalk7.dim("\u2022")} ${pattern}`);
|
|
2260
|
-
}
|
|
2261
|
-
}
|
|
2262
|
-
if (type.excludePatterns && type.excludePatterns.length > 0) {
|
|
2263
|
-
console.log("");
|
|
2264
|
-
console.log(chalk7.bold("Exclude Patterns"));
|
|
2265
|
-
for (const pattern of type.excludePatterns) {
|
|
2266
|
-
console.log(` ${chalk7.dim("\u2022")} ${pattern}`);
|
|
2267
|
-
}
|
|
2268
|
-
}
|
|
2269
|
-
} catch (error) {
|
|
2270
|
-
console.error(chalk7.red("Error:"), error.message);
|
|
2271
|
-
process.exit(1);
|
|
2272
|
-
}
|
|
2273
|
-
});
|
|
2274
|
-
return cmd;
|
|
2275
|
-
}
|
|
2276
|
-
|
|
2277
|
-
// src/commands/types/add.ts
|
|
2278
|
-
init_esm_shims();
|
|
2279
|
-
init_migrate_config();
|
|
2280
|
-
function isValidTypeName(name) {
|
|
2281
|
-
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
2282
|
-
}
|
|
2283
|
-
function parseTtl(ttl) {
|
|
2284
|
-
const match = ttl.match(/^(\d+)([smhd])$/);
|
|
2285
|
-
if (!match) {
|
|
2286
|
-
throw new Error("Invalid TTL format");
|
|
2287
|
-
}
|
|
2288
|
-
const value = parseInt(match[1], 10);
|
|
2289
|
-
const unit = match[2];
|
|
2290
|
-
switch (unit) {
|
|
2291
|
-
case "s":
|
|
2292
|
-
return value;
|
|
2293
|
-
case "m":
|
|
2294
|
-
return value * 60;
|
|
2295
|
-
case "h":
|
|
2296
|
-
return value * 3600;
|
|
2297
|
-
case "d":
|
|
2298
|
-
return value * 86400;
|
|
2299
|
-
default:
|
|
2300
|
-
throw new Error("Unknown TTL unit");
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
function formatTtl3(seconds) {
|
|
2304
|
-
if (seconds < 60) return `${seconds}s`;
|
|
2305
|
-
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
2306
|
-
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
2307
|
-
return `${Math.floor(seconds / 86400)}d`;
|
|
2308
|
-
}
|
|
2309
|
-
function typesAddCommand() {
|
|
2310
|
-
const cmd = new Command("add");
|
|
2311
|
-
cmd.description("Add a custom artifact type").argument("<name>", "Type name (lowercase, alphanumeric with hyphens)").requiredOption("--pattern <glob>", "File pattern (glob syntax)").option("--ttl <duration>", 'Cache TTL (e.g., "24h", "7d")', "24h").option("--description <text>", "Type description").option("--json", "Output as JSON").action(async (name, options) => {
|
|
2312
|
-
try {
|
|
2313
|
-
if (!isValidTypeName(name)) {
|
|
2314
|
-
console.error(chalk7.red("Error:"), "Invalid type name.");
|
|
2315
|
-
console.log(chalk7.dim("Type name must be lowercase, start with a letter, and contain only letters, numbers, and hyphens."));
|
|
2316
|
-
process.exit(1);
|
|
2317
|
-
}
|
|
2318
|
-
const client = await getClient();
|
|
2319
|
-
const registry = client.getTypeRegistry();
|
|
2320
|
-
if (registry.isBuiltIn(name)) {
|
|
2321
|
-
console.error(chalk7.red("Error:"), `Cannot override built-in type "${name}".`);
|
|
2322
|
-
const builtinNames = registry.list().filter((t) => registry.isBuiltIn(t.name)).map((t) => t.name);
|
|
2323
|
-
console.log(chalk7.dim("Built-in types: " + builtinNames.join(", ")));
|
|
2324
|
-
process.exit(1);
|
|
2325
|
-
}
|
|
2326
|
-
if (registry.has(name)) {
|
|
2327
|
-
console.error(chalk7.red("Error:"), `Custom type "${name}" already exists.`);
|
|
2328
|
-
console.log(chalk7.dim('Use "fractary codex types remove" first to remove it.'));
|
|
2329
|
-
process.exit(1);
|
|
2330
|
-
}
|
|
2331
|
-
let ttlSeconds;
|
|
2332
|
-
try {
|
|
2333
|
-
ttlSeconds = parseTtl(options.ttl);
|
|
2334
|
-
} catch {
|
|
2335
|
-
console.error(chalk7.red("Error:"), "Invalid TTL format.");
|
|
2336
|
-
console.log(chalk7.dim("Expected format: <number><unit> where unit is s (seconds), m (minutes), h (hours), or d (days)"));
|
|
2337
|
-
console.log(chalk7.dim("Examples: 30m, 24h, 7d"));
|
|
2338
|
-
process.exit(1);
|
|
2339
|
-
}
|
|
2340
|
-
const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
|
|
2341
|
-
const config = await readCodexConfig(configPath);
|
|
2342
|
-
if (!config.types) {
|
|
2343
|
-
config.types = { custom: {} };
|
|
2344
|
-
}
|
|
2345
|
-
if (!config.types.custom) {
|
|
2346
|
-
config.types.custom = {};
|
|
2347
|
-
}
|
|
2348
|
-
config.types.custom[name] = {
|
|
2349
|
-
description: options.description || `Custom type: ${name}`,
|
|
2350
|
-
patterns: [options.pattern],
|
|
2351
|
-
defaultTtl: ttlSeconds
|
|
2352
|
-
};
|
|
2353
|
-
await writeYamlConfig(config, configPath);
|
|
2354
|
-
if (options.json) {
|
|
2355
|
-
console.log(JSON.stringify({
|
|
2356
|
-
success: true,
|
|
2357
|
-
type: {
|
|
2358
|
-
name,
|
|
2359
|
-
description: config.types.custom[name].description,
|
|
2360
|
-
patterns: config.types.custom[name].patterns,
|
|
2361
|
-
defaultTtl: ttlSeconds,
|
|
2362
|
-
ttl: formatTtl3(ttlSeconds),
|
|
2363
|
-
builtin: false
|
|
2364
|
-
},
|
|
2365
|
-
message: "Custom type added successfully. Changes will take effect on next CLI invocation."
|
|
2366
|
-
}, null, 2));
|
|
2367
|
-
return;
|
|
2368
|
-
}
|
|
2369
|
-
console.log(chalk7.green("\u2713"), `Added custom type "${chalk7.cyan(name)}"`);
|
|
2370
|
-
console.log("");
|
|
2371
|
-
console.log(` ${chalk7.dim("Pattern:")} ${options.pattern}`);
|
|
2372
|
-
console.log(` ${chalk7.dim("TTL:")} ${formatTtl3(ttlSeconds)} (${ttlSeconds} seconds)`);
|
|
2373
|
-
if (options.description) {
|
|
2374
|
-
console.log(` ${chalk7.dim("Description:")} ${options.description}`);
|
|
2375
|
-
}
|
|
2376
|
-
console.log("");
|
|
2377
|
-
console.log(chalk7.dim("Note: Custom type will be available on next CLI invocation."));
|
|
2378
|
-
} catch (error) {
|
|
2379
|
-
console.error(chalk7.red("Error:"), error.message);
|
|
2380
|
-
if (error.message.includes("Failed to load configuration")) {
|
|
2381
|
-
console.log(chalk7.dim('\nRun "fractary codex init" to create a configuration.'));
|
|
2382
|
-
}
|
|
2383
|
-
process.exit(1);
|
|
2384
|
-
}
|
|
2385
|
-
});
|
|
2386
|
-
return cmd;
|
|
2387
|
-
}
|
|
2388
|
-
|
|
2389
|
-
// src/commands/types/remove.ts
|
|
2390
|
-
init_esm_shims();
|
|
2391
|
-
init_migrate_config();
|
|
2392
|
-
function typesRemoveCommand() {
|
|
2393
|
-
const cmd = new Command("remove");
|
|
2394
|
-
cmd.description("Remove a custom artifact type").argument("<name>", "Type name to remove").option("--json", "Output as JSON").option("--force", "Skip confirmation").action(async (name, options) => {
|
|
2395
|
-
try {
|
|
2396
|
-
const client = await getClient();
|
|
2397
|
-
const registry = client.getTypeRegistry();
|
|
2398
|
-
if (registry.isBuiltIn(name)) {
|
|
2399
|
-
console.error(chalk7.red("Error:"), `Cannot remove built-in type "${name}".`);
|
|
2400
|
-
console.log(chalk7.dim("Built-in types are permanent and cannot be removed."));
|
|
2401
|
-
process.exit(1);
|
|
2402
|
-
}
|
|
2403
|
-
if (!registry.has(name)) {
|
|
2404
|
-
console.error(chalk7.red("Error:"), `Custom type "${name}" not found.`);
|
|
2405
|
-
console.log(chalk7.dim('Run "fractary codex types list --custom-only" to see custom types.'));
|
|
2406
|
-
process.exit(1);
|
|
2407
|
-
}
|
|
2408
|
-
const typeInfo = registry.get(name);
|
|
2409
|
-
const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
|
|
2410
|
-
const config = await readCodexConfig(configPath);
|
|
2411
|
-
if (!config.types?.custom?.[name]) {
|
|
2412
|
-
console.error(chalk7.red("Error:"), `Custom type "${name}" not found in configuration.`);
|
|
2413
|
-
process.exit(1);
|
|
2414
|
-
}
|
|
2415
|
-
delete config.types.custom[name];
|
|
2416
|
-
if (Object.keys(config.types.custom).length === 0) {
|
|
2417
|
-
delete config.types.custom;
|
|
2418
|
-
}
|
|
2419
|
-
if (config.types && Object.keys(config.types).length === 0) {
|
|
2420
|
-
delete config.types;
|
|
2421
|
-
}
|
|
2422
|
-
await writeYamlConfig(config, configPath);
|
|
2423
|
-
if (options.json) {
|
|
2424
|
-
console.log(JSON.stringify({
|
|
2425
|
-
success: true,
|
|
2426
|
-
removed: {
|
|
2427
|
-
name: typeInfo.name,
|
|
2428
|
-
description: typeInfo.description,
|
|
2429
|
-
patterns: typeInfo.patterns,
|
|
2430
|
-
defaultTtl: typeInfo.defaultTtl
|
|
2431
|
-
},
|
|
2432
|
-
message: "Custom type removed successfully. Changes will take effect on next CLI invocation."
|
|
2433
|
-
}, null, 2));
|
|
2434
|
-
return;
|
|
2435
|
-
}
|
|
2436
|
-
console.log(chalk7.green("\u2713"), `Removed custom type "${chalk7.cyan(name)}"`);
|
|
2437
|
-
console.log("");
|
|
2438
|
-
console.log(chalk7.dim("Removed configuration:"));
|
|
2439
|
-
console.log(` ${chalk7.dim("Pattern:")} ${typeInfo.patterns.join(", ")}`);
|
|
2440
|
-
console.log(` ${chalk7.dim("Description:")} ${typeInfo.description}`);
|
|
2441
|
-
console.log("");
|
|
2442
|
-
console.log(chalk7.dim("Note: Custom type will be removed on next CLI invocation."));
|
|
2443
|
-
} catch (error) {
|
|
2444
|
-
console.error(chalk7.red("Error:"), error.message);
|
|
2445
|
-
if (error.message.includes("Failed to load configuration")) {
|
|
2446
|
-
console.log(chalk7.dim('\nRun "fractary codex init" to create a configuration.'));
|
|
2447
|
-
}
|
|
2448
|
-
process.exit(1);
|
|
2449
|
-
}
|
|
2450
|
-
});
|
|
2451
|
-
return cmd;
|
|
2452
|
-
}
|
|
2453
|
-
|
|
2454
|
-
// src/commands/types/index.ts
|
|
2455
|
-
function typesCommand() {
|
|
2456
|
-
const cmd = new Command("types");
|
|
2457
|
-
cmd.description("Manage artifact type registry");
|
|
2458
|
-
cmd.addCommand(typesListCommand());
|
|
2459
|
-
cmd.addCommand(typesShowCommand());
|
|
2460
|
-
cmd.addCommand(typesAddCommand());
|
|
2461
|
-
cmd.addCommand(typesRemoveCommand());
|
|
2462
|
-
return cmd;
|
|
2463
|
-
}
|
|
2464
2109
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
2465
2110
|
var __dirname2 = dirname(__filename2);
|
|
2466
2111
|
var packageJson = JSON.parse(readFileSync(join(__dirname2, "../package.json"), "utf-8"));
|
|
@@ -2468,11 +2113,13 @@ var VERSION = packageJson.version;
|
|
|
2468
2113
|
function createCLI() {
|
|
2469
2114
|
const program = new Command("fractary-codex");
|
|
2470
2115
|
program.description("Centralized knowledge management and distribution for AI agents").version(VERSION);
|
|
2471
|
-
program.addCommand(
|
|
2472
|
-
program.addCommand(
|
|
2473
|
-
program.addCommand(
|
|
2116
|
+
program.addCommand(configureCommand());
|
|
2117
|
+
program.addCommand(documentFetchCommand());
|
|
2118
|
+
program.addCommand(cacheListCommand());
|
|
2119
|
+
program.addCommand(cacheClearCommand());
|
|
2120
|
+
program.addCommand(cacheStatsCommand());
|
|
2121
|
+
program.addCommand(cacheHealthCommand());
|
|
2474
2122
|
program.addCommand(syncCommand());
|
|
2475
|
-
program.addCommand(typesCommand());
|
|
2476
2123
|
return program;
|
|
2477
2124
|
}
|
|
2478
2125
|
async function main() {
|