@fractary/codex-cli 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/cli.cjs +932 -1187
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +927 -1183
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var fs = require('fs/promises');
|
|
5
|
-
var
|
|
5
|
+
var path3 = require('path');
|
|
6
6
|
var yaml = require('js-yaml');
|
|
7
7
|
var codex = require('@fractary/codex');
|
|
8
8
|
var commander = require('commander');
|
|
9
|
-
var
|
|
10
|
-
var
|
|
9
|
+
var chalk8 = require('chalk');
|
|
10
|
+
var crypto = require('crypto');
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
13
|
|
|
@@ -30,9 +30,10 @@ function _interopNamespace(e) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
33
|
-
var
|
|
33
|
+
var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
|
|
34
34
|
var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
|
|
35
|
-
var
|
|
35
|
+
var chalk8__default = /*#__PURE__*/_interopDefault(chalk8);
|
|
36
|
+
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
36
37
|
|
|
37
38
|
var __defProp = Object.defineProperty;
|
|
38
39
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -185,7 +186,7 @@ async function migrateConfig(legacyConfigPath, options) {
|
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
async function writeYamlConfig(config, outputPath) {
|
|
188
|
-
const dir =
|
|
189
|
+
const dir = path3__namespace.dirname(outputPath);
|
|
189
190
|
await fs__namespace.mkdir(dir, { recursive: true });
|
|
190
191
|
const yamlContent = yaml__namespace.dump(config, {
|
|
191
192
|
indent: 2,
|
|
@@ -409,7 +410,7 @@ var init_codex_client = __esm({
|
|
|
409
410
|
const { readYamlConfig: readYamlConfig2 } = await Promise.resolve().then(() => (init_migrate_config(), migrate_config_exports));
|
|
410
411
|
const { resolveEnvVarsInConfig: resolveEnvVarsInConfig2 } = await Promise.resolve().then(() => (init_config_types(), config_types_exports));
|
|
411
412
|
try {
|
|
412
|
-
const configPath =
|
|
413
|
+
const configPath = path3__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
413
414
|
let config;
|
|
414
415
|
try {
|
|
415
416
|
config = await readYamlConfig2(configPath);
|
|
@@ -621,13 +622,110 @@ var init_codex_client = __esm({
|
|
|
621
622
|
// src/cli.ts
|
|
622
623
|
init_cjs_shims();
|
|
623
624
|
|
|
624
|
-
// src/commands/
|
|
625
|
+
// src/commands/document/index.ts
|
|
626
|
+
init_cjs_shims();
|
|
627
|
+
|
|
628
|
+
// src/commands/document/fetch.ts
|
|
629
|
+
init_cjs_shims();
|
|
630
|
+
|
|
631
|
+
// src/client/get-client.ts
|
|
632
|
+
init_cjs_shims();
|
|
633
|
+
var clientInstance = null;
|
|
634
|
+
async function getClient(options) {
|
|
635
|
+
if (!clientInstance) {
|
|
636
|
+
const { CodexClient: CodexClient2 } = await Promise.resolve().then(() => (init_codex_client(), codex_client_exports));
|
|
637
|
+
clientInstance = await CodexClient2.create(options);
|
|
638
|
+
}
|
|
639
|
+
return clientInstance;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// src/commands/document/fetch.ts
|
|
643
|
+
function hashContent(content) {
|
|
644
|
+
return crypto__namespace.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
645
|
+
}
|
|
646
|
+
function fetchCommand() {
|
|
647
|
+
const cmd = new commander.Command("fetch");
|
|
648
|
+
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) => {
|
|
649
|
+
try {
|
|
650
|
+
const { validateUri } = await import('@fractary/codex');
|
|
651
|
+
if (!validateUri(uri)) {
|
|
652
|
+
console.error(chalk8__default.default.red("Error: Invalid URI format"));
|
|
653
|
+
console.log(chalk8__default.default.dim("Expected: codex://org/project/path/to/file.md"));
|
|
654
|
+
console.log(chalk8__default.default.dim("Example: codex://fractary/codex/docs/api.md"));
|
|
655
|
+
process.exit(1);
|
|
656
|
+
}
|
|
657
|
+
const client = await getClient();
|
|
658
|
+
if (!options.json && !options.bypassCache) {
|
|
659
|
+
console.error(chalk8__default.default.dim(`Fetching ${uri}...`));
|
|
660
|
+
}
|
|
661
|
+
const result = await client.fetch(uri, {
|
|
662
|
+
bypassCache: options.bypassCache,
|
|
663
|
+
ttl: options.ttl
|
|
664
|
+
});
|
|
665
|
+
if (options.json) {
|
|
666
|
+
const output = {
|
|
667
|
+
uri,
|
|
668
|
+
content: result.content.toString("utf-8"),
|
|
669
|
+
metadata: {
|
|
670
|
+
fromCache: result.fromCache,
|
|
671
|
+
fetchedAt: result.metadata?.fetchedAt,
|
|
672
|
+
expiresAt: result.metadata?.expiresAt,
|
|
673
|
+
contentLength: result.metadata?.contentLength || result.content.length,
|
|
674
|
+
contentHash: hashContent(result.content)
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
console.log(JSON.stringify(output, null, 2));
|
|
678
|
+
} else if (options.output) {
|
|
679
|
+
await fs__namespace.writeFile(options.output, result.content);
|
|
680
|
+
console.log(chalk8__default.default.green("\u2713"), `Written to ${options.output}`);
|
|
681
|
+
console.log(chalk8__default.default.dim(` Size: ${result.content.length} bytes`));
|
|
682
|
+
if (result.fromCache) {
|
|
683
|
+
console.log(chalk8__default.default.dim(" Source: cache"));
|
|
684
|
+
} else {
|
|
685
|
+
console.log(chalk8__default.default.dim(" Source: storage"));
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
if (result.fromCache && !options.bypassCache) {
|
|
689
|
+
console.error(chalk8__default.default.green("\u2713"), chalk8__default.default.dim("from cache\n"));
|
|
690
|
+
} else {
|
|
691
|
+
console.error(chalk8__default.default.green("\u2713"), chalk8__default.default.dim("fetched\n"));
|
|
692
|
+
}
|
|
693
|
+
console.log(result.content.toString("utf-8"));
|
|
694
|
+
}
|
|
695
|
+
} catch (error) {
|
|
696
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
697
|
+
if (error.message.includes("Failed to load configuration")) {
|
|
698
|
+
console.log(chalk8__default.default.dim('\nRun "fractary codex init" to create a configuration.'));
|
|
699
|
+
} else if (error.message.includes("GITHUB_TOKEN")) {
|
|
700
|
+
console.log(chalk8__default.default.dim('\nSet your GitHub token: export GITHUB_TOKEN="your_token"'));
|
|
701
|
+
} else if (error.message.includes("not found") || error.message.includes("404")) {
|
|
702
|
+
console.log(chalk8__default.default.dim("\nThe document may not exist or you may not have access."));
|
|
703
|
+
console.log(chalk8__default.default.dim("Check the URI and ensure your storage providers are configured correctly."));
|
|
704
|
+
}
|
|
705
|
+
process.exit(1);
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
return cmd;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/commands/document/index.ts
|
|
712
|
+
function documentCommand() {
|
|
713
|
+
const cmd = new commander.Command("document");
|
|
714
|
+
cmd.description("Manage document operations");
|
|
715
|
+
cmd.addCommand(fetchCommand());
|
|
716
|
+
return cmd;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// src/commands/config/index.ts
|
|
720
|
+
init_cjs_shims();
|
|
721
|
+
|
|
722
|
+
// src/commands/config/init.ts
|
|
625
723
|
init_cjs_shims();
|
|
626
724
|
init_migrate_config();
|
|
627
725
|
async function getOrgFromGitRemote() {
|
|
628
726
|
try {
|
|
629
|
-
const { execSync
|
|
630
|
-
const remote =
|
|
727
|
+
const { execSync } = __require("child_process");
|
|
728
|
+
const remote = execSync("git remote get-url origin 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
631
729
|
const sshMatch = remote.match(/git@github\.com:([^/]+)\//);
|
|
632
730
|
const httpsMatch = remote.match(/github\.com\/([^/]+)\//);
|
|
633
731
|
return sshMatch?.[1] || httpsMatch?.[1] || null;
|
|
@@ -647,7 +745,7 @@ function initCommand() {
|
|
|
647
745
|
const cmd = new commander.Command("init");
|
|
648
746
|
cmd.description("Initialize Codex v3.0 with YAML configuration").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--mcp", "Enable MCP server registration").option("--force", "Overwrite existing configuration").action(async (options) => {
|
|
649
747
|
try {
|
|
650
|
-
console.log(
|
|
748
|
+
console.log(chalk8__default.default.blue("Initializing Codex v3.0 (YAML format)...\n"));
|
|
651
749
|
let org = options.org;
|
|
652
750
|
if (!org) {
|
|
653
751
|
org = await getOrgFromGitRemote();
|
|
@@ -656,32 +754,32 @@ function initCommand() {
|
|
|
656
754
|
try {
|
|
657
755
|
const { resolveOrganization } = await import('@fractary/codex');
|
|
658
756
|
org = resolveOrganization({
|
|
659
|
-
repoName:
|
|
757
|
+
repoName: path3__namespace.basename(process.cwd())
|
|
660
758
|
});
|
|
661
759
|
} catch {
|
|
662
760
|
}
|
|
663
761
|
}
|
|
664
762
|
if (!org) {
|
|
665
|
-
org =
|
|
666
|
-
console.log(
|
|
667
|
-
console.log(
|
|
763
|
+
org = path3__namespace.basename(process.cwd()).split("-")[0] || "default";
|
|
764
|
+
console.log(chalk8__default.default.yellow(`\u26A0 Could not detect organization, using: ${org}`));
|
|
765
|
+
console.log(chalk8__default.default.dim(" Use --org <slug> to specify explicitly\n"));
|
|
668
766
|
} else {
|
|
669
|
-
console.log(
|
|
767
|
+
console.log(chalk8__default.default.dim(`Organization: ${chalk8__default.default.cyan(org)}
|
|
670
768
|
`));
|
|
671
769
|
}
|
|
672
|
-
const configDir =
|
|
673
|
-
const configPath =
|
|
770
|
+
const configDir = path3__namespace.join(process.cwd(), ".fractary");
|
|
771
|
+
const configPath = path3__namespace.join(configDir, "codex.yaml");
|
|
674
772
|
const configExists = await fileExists(configPath);
|
|
675
|
-
const legacyConfigPath =
|
|
773
|
+
const legacyConfigPath = path3__namespace.join(process.cwd(), ".fractary", "plugins", "codex", "config.json");
|
|
676
774
|
const legacyExists = await fileExists(legacyConfigPath);
|
|
677
775
|
if (configExists && !options.force) {
|
|
678
|
-
console.log(
|
|
679
|
-
console.log(
|
|
776
|
+
console.log(chalk8__default.default.yellow("\u26A0 Configuration already exists at .fractary/codex.yaml"));
|
|
777
|
+
console.log(chalk8__default.default.dim("Use --force to overwrite"));
|
|
680
778
|
process.exit(1);
|
|
681
779
|
}
|
|
682
780
|
if (legacyExists && !configExists) {
|
|
683
|
-
console.log(
|
|
684
|
-
console.log(
|
|
781
|
+
console.log(chalk8__default.default.yellow("\u26A0 Legacy configuration detected at .fractary/plugins/codex/config.json"));
|
|
782
|
+
console.log(chalk8__default.default.dim('Run "fractary codex migrate" to upgrade to YAML format\n'));
|
|
685
783
|
}
|
|
686
784
|
console.log("Creating directory structure...");
|
|
687
785
|
const dirs = [
|
|
@@ -689,8 +787,8 @@ function initCommand() {
|
|
|
689
787
|
".codex-cache"
|
|
690
788
|
];
|
|
691
789
|
for (const dir of dirs) {
|
|
692
|
-
await fs__namespace.mkdir(
|
|
693
|
-
console.log(
|
|
790
|
+
await fs__namespace.mkdir(path3__namespace.join(process.cwd(), dir), { recursive: true });
|
|
791
|
+
console.log(chalk8__default.default.green("\u2713"), chalk8__default.default.dim(dir + "/"));
|
|
694
792
|
}
|
|
695
793
|
console.log("\nCreating YAML configuration...");
|
|
696
794
|
const config = getDefaultYamlConfig(org);
|
|
@@ -698,113 +796,183 @@ function initCommand() {
|
|
|
698
796
|
config.mcp.enabled = true;
|
|
699
797
|
}
|
|
700
798
|
await writeYamlConfig(config, configPath);
|
|
701
|
-
console.log(
|
|
702
|
-
console.log(
|
|
703
|
-
console.log(
|
|
704
|
-
console.log(
|
|
705
|
-
console.log(
|
|
706
|
-
console.log(
|
|
799
|
+
console.log(chalk8__default.default.green("\u2713"), chalk8__default.default.dim(".fractary/codex.yaml"));
|
|
800
|
+
console.log(chalk8__default.default.green("\n\u2713 Codex v3.0 initialized successfully!\n"));
|
|
801
|
+
console.log(chalk8__default.default.bold("Configuration:"));
|
|
802
|
+
console.log(chalk8__default.default.dim(` Organization: ${org}`));
|
|
803
|
+
console.log(chalk8__default.default.dim(` Cache: .codex-cache/`));
|
|
804
|
+
console.log(chalk8__default.default.dim(` Config: .fractary/codex.yaml`));
|
|
707
805
|
if (options.mcp) {
|
|
708
|
-
console.log(
|
|
709
|
-
}
|
|
710
|
-
console.log(
|
|
711
|
-
console.log(
|
|
712
|
-
console.log(
|
|
713
|
-
console.log(
|
|
714
|
-
console.log(
|
|
715
|
-
console.log(
|
|
716
|
-
console.log(
|
|
717
|
-
console.log(
|
|
718
|
-
console.log(
|
|
806
|
+
console.log(chalk8__default.default.dim(` MCP Server: Enabled (port 3000)`));
|
|
807
|
+
}
|
|
808
|
+
console.log(chalk8__default.default.bold("\nStorage providers configured:"));
|
|
809
|
+
console.log(chalk8__default.default.dim(" - Local filesystem (./knowledge)"));
|
|
810
|
+
console.log(chalk8__default.default.dim(" - GitHub (requires GITHUB_TOKEN)"));
|
|
811
|
+
console.log(chalk8__default.default.dim(" - HTTP endpoint"));
|
|
812
|
+
console.log(chalk8__default.default.bold("\nNext steps:"));
|
|
813
|
+
console.log(chalk8__default.default.dim(' 1. Set your GitHub token: export GITHUB_TOKEN="your_token"'));
|
|
814
|
+
console.log(chalk8__default.default.dim(" 2. Edit .fractary/codex.yaml to configure storage providers"));
|
|
815
|
+
console.log(chalk8__default.default.dim(" 3. Fetch a document: fractary codex fetch codex://org/project/path"));
|
|
816
|
+
console.log(chalk8__default.default.dim(" 4. Check cache: fractary codex cache list"));
|
|
719
817
|
if (legacyExists) {
|
|
720
|
-
console.log(
|
|
721
|
-
console.log(
|
|
818
|
+
console.log(chalk8__default.default.yellow("\n\u26A0 Legacy config detected:"));
|
|
819
|
+
console.log(chalk8__default.default.dim(' Run "fractary codex migrate" to convert your existing config'));
|
|
722
820
|
}
|
|
723
821
|
} catch (error) {
|
|
724
|
-
console.error(
|
|
822
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
725
823
|
process.exit(1);
|
|
726
824
|
}
|
|
727
825
|
});
|
|
728
826
|
return cmd;
|
|
729
827
|
}
|
|
730
828
|
|
|
731
|
-
// src/commands/
|
|
829
|
+
// src/commands/config/migrate.ts
|
|
732
830
|
init_cjs_shims();
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
clientInstance = await CodexClient2.create(options);
|
|
831
|
+
init_migrate_config();
|
|
832
|
+
async function fileExists2(filePath) {
|
|
833
|
+
try {
|
|
834
|
+
await fs__namespace.access(filePath);
|
|
835
|
+
return true;
|
|
836
|
+
} catch {
|
|
837
|
+
return false;
|
|
741
838
|
}
|
|
742
|
-
return clientInstance;
|
|
743
839
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
function hashContent(content) {
|
|
747
|
-
const crypto = __require("crypto");
|
|
748
|
-
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
840
|
+
async function readFileContent(filePath) {
|
|
841
|
+
return fs__namespace.readFile(filePath, "utf-8");
|
|
749
842
|
}
|
|
750
|
-
function
|
|
751
|
-
const cmd = new commander.Command("
|
|
752
|
-
cmd.description("
|
|
843
|
+
function migrateCommand() {
|
|
844
|
+
const cmd = new commander.Command("migrate");
|
|
845
|
+
cmd.description("Migrate legacy JSON configuration to v3.0 YAML format").option("--dry-run", "Show migration plan without executing").option("--no-backup", "Skip creating backup of old config").option("--json", "Output as JSON").action(async (options) => {
|
|
753
846
|
try {
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
847
|
+
const legacyConfigPath = path3__namespace.join(process.cwd(), ".fractary", "plugins", "codex", "config.json");
|
|
848
|
+
const newConfigPath = path3__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
849
|
+
if (!await fileExists2(legacyConfigPath)) {
|
|
850
|
+
if (options.json) {
|
|
851
|
+
console.log(JSON.stringify({
|
|
852
|
+
status: "no_config",
|
|
853
|
+
message: "No legacy configuration file found",
|
|
854
|
+
path: legacyConfigPath
|
|
855
|
+
}));
|
|
856
|
+
} else {
|
|
857
|
+
console.log(chalk8__default.default.yellow("\u26A0 No legacy configuration file found."));
|
|
858
|
+
console.log(chalk8__default.default.dim(` Expected: ${legacyConfigPath}`));
|
|
859
|
+
console.log(chalk8__default.default.dim('\nRun "fractary codex init" to create a new v3.0 YAML configuration.'));
|
|
860
|
+
}
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (await fileExists2(newConfigPath) && !options.dryRun) {
|
|
864
|
+
if (options.json) {
|
|
865
|
+
console.log(JSON.stringify({
|
|
866
|
+
status: "already_migrated",
|
|
867
|
+
message: "YAML configuration already exists",
|
|
868
|
+
path: newConfigPath
|
|
869
|
+
}));
|
|
870
|
+
} else {
|
|
871
|
+
console.log(chalk8__default.default.yellow("\u26A0 YAML configuration already exists."));
|
|
872
|
+
console.log(chalk8__default.default.dim(` Path: ${newConfigPath}`));
|
|
873
|
+
console.log(chalk8__default.default.dim('\nUse "fractary codex init --force" to recreate.'));
|
|
874
|
+
}
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
const legacyContent = await readFileContent(legacyConfigPath);
|
|
878
|
+
let legacyConfig;
|
|
879
|
+
try {
|
|
880
|
+
legacyConfig = JSON.parse(legacyContent);
|
|
881
|
+
} catch {
|
|
882
|
+
console.error(chalk8__default.default.red("Error:"), "Invalid JSON in legacy config file.");
|
|
759
883
|
process.exit(1);
|
|
760
884
|
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
885
|
+
if (!options.json && !options.dryRun) {
|
|
886
|
+
console.log(chalk8__default.default.blue("Migrating Codex configuration to v3.0 YAML format...\n"));
|
|
887
|
+
}
|
|
888
|
+
const migrationResult = await migrateConfig(
|
|
889
|
+
legacyConfigPath,
|
|
890
|
+
{
|
|
891
|
+
createBackup: options.backup !== false,
|
|
892
|
+
backupSuffix: (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")
|
|
893
|
+
}
|
|
894
|
+
);
|
|
895
|
+
if (!options.json) {
|
|
896
|
+
console.log(chalk8__default.default.bold("Legacy Configuration:"));
|
|
897
|
+
console.log(chalk8__default.default.dim(` Path: ${legacyConfigPath}`));
|
|
898
|
+
console.log(chalk8__default.default.dim(` Organization: ${legacyConfig.organization || legacyConfig.organizationSlug || "unknown"}`));
|
|
899
|
+
console.log("");
|
|
900
|
+
console.log(chalk8__default.default.bold("Migration Changes:"));
|
|
901
|
+
console.log(chalk8__default.default.green(" + Format: JSON \u2192 YAML"));
|
|
902
|
+
console.log(chalk8__default.default.green(" + Location: .fractary/plugins/codex/ \u2192 .fractary/"));
|
|
903
|
+
console.log(chalk8__default.default.green(" + File: config.json \u2192 codex.yaml"));
|
|
904
|
+
console.log(chalk8__default.default.green(" + Storage: Multi-provider configuration"));
|
|
905
|
+
console.log(chalk8__default.default.green(" + Cache: Modern cache management"));
|
|
906
|
+
console.log(chalk8__default.default.green(" + Types: Custom type registry"));
|
|
907
|
+
if (migrationResult.warnings.length > 0) {
|
|
908
|
+
console.log("");
|
|
909
|
+
console.log(chalk8__default.default.yellow("Warnings:"));
|
|
910
|
+
for (const warning of migrationResult.warnings) {
|
|
911
|
+
console.log(chalk8__default.default.yellow(" \u26A0"), chalk8__default.default.dim(warning));
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
console.log("");
|
|
915
|
+
if (options.dryRun) {
|
|
916
|
+
console.log(chalk8__default.default.blue("Dry run - no changes made."));
|
|
917
|
+
console.log(chalk8__default.default.dim("Run without --dry-run to execute migration."));
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
764
920
|
}
|
|
765
|
-
const result = await client.fetch(uri, {
|
|
766
|
-
bypassCache: options.bypassCache,
|
|
767
|
-
ttl: options.ttl
|
|
768
|
-
});
|
|
769
921
|
if (options.json) {
|
|
770
922
|
const output = {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
923
|
+
status: options.dryRun ? "migration_ready" : "migrated",
|
|
924
|
+
dryRun: options.dryRun || false,
|
|
925
|
+
legacyConfig: {
|
|
926
|
+
path: legacyConfigPath,
|
|
927
|
+
organization: legacyConfig.organization || legacyConfig.organizationSlug
|
|
928
|
+
},
|
|
929
|
+
newConfig: {
|
|
930
|
+
path: newConfigPath,
|
|
931
|
+
organization: migrationResult.yamlConfig.organization
|
|
932
|
+
},
|
|
933
|
+
warnings: migrationResult.warnings,
|
|
934
|
+
backupPath: migrationResult.backupPath
|
|
780
935
|
};
|
|
781
936
|
console.log(JSON.stringify(output, null, 2));
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
console.log(chalk6__default.default.green("\u2713"), `Written to ${options.output}`);
|
|
785
|
-
console.log(chalk6__default.default.dim(` Size: ${result.content.length} bytes`));
|
|
786
|
-
if (result.fromCache) {
|
|
787
|
-
console.log(chalk6__default.default.dim(" Source: cache"));
|
|
788
|
-
} else {
|
|
789
|
-
console.log(chalk6__default.default.dim(" Source: storage"));
|
|
937
|
+
if (options.dryRun) {
|
|
938
|
+
return;
|
|
790
939
|
}
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
940
|
+
}
|
|
941
|
+
if (!options.dryRun) {
|
|
942
|
+
await writeYamlConfig(migrationResult.yamlConfig, newConfigPath);
|
|
943
|
+
const cacheDir = path3__namespace.join(process.cwd(), ".codex-cache");
|
|
944
|
+
await fs__namespace.mkdir(cacheDir, { recursive: true });
|
|
945
|
+
if (!options.json) {
|
|
946
|
+
console.log(chalk8__default.default.green("\u2713"), "YAML configuration created");
|
|
947
|
+
console.log(chalk8__default.default.green("\u2713"), "Cache directory initialized");
|
|
948
|
+
if (migrationResult.backupPath) {
|
|
949
|
+
console.log(chalk8__default.default.green("\u2713"), "Legacy config backed up");
|
|
950
|
+
}
|
|
951
|
+
console.log("");
|
|
952
|
+
console.log(chalk8__default.default.bold("New Configuration:"));
|
|
953
|
+
console.log(chalk8__default.default.dim(` Path: ${newConfigPath}`));
|
|
954
|
+
console.log(chalk8__default.default.dim(` Organization: ${migrationResult.yamlConfig.organization}`));
|
|
955
|
+
console.log(chalk8__default.default.dim(` Cache: ${migrationResult.yamlConfig.cacheDir || ".codex-cache"}`));
|
|
956
|
+
console.log(chalk8__default.default.dim(` Storage Providers: ${migrationResult.yamlConfig.storage?.length || 0}`));
|
|
957
|
+
console.log("");
|
|
958
|
+
console.log(chalk8__default.default.bold("Next Steps:"));
|
|
959
|
+
console.log(chalk8__default.default.dim(" 1. Review the new configuration: .fractary/codex.yaml"));
|
|
960
|
+
console.log(chalk8__default.default.dim(' 2. Set your GitHub token: export GITHUB_TOKEN="your_token"'));
|
|
961
|
+
console.log(chalk8__default.default.dim(" 3. Test fetching: fractary codex fetch codex://org/project/path"));
|
|
962
|
+
if (migrationResult.backupPath) {
|
|
963
|
+
console.log("");
|
|
964
|
+
console.log(chalk8__default.default.dim(`Backup saved: ${path3__namespace.basename(migrationResult.backupPath)}`));
|
|
965
|
+
}
|
|
796
966
|
}
|
|
797
|
-
console.log(result.content.toString("utf-8"));
|
|
798
967
|
}
|
|
799
968
|
} catch (error) {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
} else
|
|
806
|
-
console.
|
|
807
|
-
console.log(chalk6__default.default.dim("Check the URI and ensure your storage providers are configured correctly."));
|
|
969
|
+
if (options.json) {
|
|
970
|
+
console.log(JSON.stringify({
|
|
971
|
+
status: "error",
|
|
972
|
+
message: error.message
|
|
973
|
+
}));
|
|
974
|
+
} else {
|
|
975
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
808
976
|
}
|
|
809
977
|
process.exit(1);
|
|
810
978
|
}
|
|
@@ -812,6 +980,15 @@ function fetchCommand() {
|
|
|
812
980
|
return cmd;
|
|
813
981
|
}
|
|
814
982
|
|
|
983
|
+
// src/commands/config/index.ts
|
|
984
|
+
function configCommand() {
|
|
985
|
+
const cmd = new commander.Command("config");
|
|
986
|
+
cmd.description("Manage configuration");
|
|
987
|
+
cmd.addCommand(initCommand());
|
|
988
|
+
cmd.addCommand(migrateCommand());
|
|
989
|
+
return cmd;
|
|
990
|
+
}
|
|
991
|
+
|
|
815
992
|
// src/commands/cache/index.ts
|
|
816
993
|
init_cjs_shims();
|
|
817
994
|
|
|
@@ -832,8 +1009,8 @@ function cacheListCommand() {
|
|
|
832
1009
|
if (options.json) {
|
|
833
1010
|
console.log(JSON.stringify({ entries: 0, message: "Cache is empty" }));
|
|
834
1011
|
} else {
|
|
835
|
-
console.log(
|
|
836
|
-
console.log(
|
|
1012
|
+
console.log(chalk8__default.default.yellow("Cache is empty."));
|
|
1013
|
+
console.log(chalk8__default.default.dim("Fetch some documents to populate the cache."));
|
|
837
1014
|
}
|
|
838
1015
|
return;
|
|
839
1016
|
}
|
|
@@ -847,25 +1024,25 @@ function cacheListCommand() {
|
|
|
847
1024
|
}, null, 2));
|
|
848
1025
|
return;
|
|
849
1026
|
}
|
|
850
|
-
console.log(
|
|
851
|
-
console.log(
|
|
852
|
-
console.log(` Total: ${
|
|
853
|
-
console.log(` Fresh: ${
|
|
854
|
-
console.log(` Stale: ${stats.staleCount > 0 ?
|
|
855
|
-
console.log(` Expired: ${stats.expiredCount > 0 ?
|
|
1027
|
+
console.log(chalk8__default.default.bold("Cache Overview\n"));
|
|
1028
|
+
console.log(chalk8__default.default.bold("Entries:"));
|
|
1029
|
+
console.log(` Total: ${chalk8__default.default.cyan(stats.entryCount.toString())} entries`);
|
|
1030
|
+
console.log(` Fresh: ${chalk8__default.default.green(stats.freshCount.toString())} entries`);
|
|
1031
|
+
console.log(` Stale: ${stats.staleCount > 0 ? chalk8__default.default.yellow(stats.staleCount.toString()) : chalk8__default.default.dim("0")} entries`);
|
|
1032
|
+
console.log(` Expired: ${stats.expiredCount > 0 ? chalk8__default.default.red(stats.expiredCount.toString()) : chalk8__default.default.dim("0")} entries`);
|
|
856
1033
|
console.log("");
|
|
857
|
-
console.log(
|
|
858
|
-
console.log(` Total size: ${
|
|
1034
|
+
console.log(chalk8__default.default.bold("Storage:"));
|
|
1035
|
+
console.log(` Total size: ${chalk8__default.default.cyan(formatSize(stats.totalSize))}`);
|
|
859
1036
|
console.log("");
|
|
860
1037
|
const healthPercent = stats.entryCount > 0 ? stats.freshCount / stats.entryCount * 100 : 100;
|
|
861
|
-
const healthColor = healthPercent > 80 ?
|
|
1038
|
+
const healthColor = healthPercent > 80 ? chalk8__default.default.green : healthPercent > 50 ? chalk8__default.default.yellow : chalk8__default.default.red;
|
|
862
1039
|
console.log(`Cache health: ${healthColor(`${healthPercent.toFixed(0)}% fresh`)}`);
|
|
863
1040
|
console.log("");
|
|
864
|
-
console.log(
|
|
865
|
-
console.log(
|
|
866
|
-
console.log(
|
|
1041
|
+
console.log(chalk8__default.default.dim("Note: Individual cache entries are managed by the SDK."));
|
|
1042
|
+
console.log(chalk8__default.default.dim('Use "fractary codex cache stats" for detailed statistics.'));
|
|
1043
|
+
console.log(chalk8__default.default.dim('Use "fractary codex cache clear" to clear cache entries.'));
|
|
867
1044
|
} catch (error) {
|
|
868
|
-
console.error(
|
|
1045
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
869
1046
|
process.exit(1);
|
|
870
1047
|
}
|
|
871
1048
|
});
|
|
@@ -881,7 +1058,7 @@ function cacheClearCommand() {
|
|
|
881
1058
|
const client = await getClient();
|
|
882
1059
|
const statsBefore = await client.getCacheStats();
|
|
883
1060
|
if (statsBefore.entryCount === 0) {
|
|
884
|
-
console.log(
|
|
1061
|
+
console.log(chalk8__default.default.yellow("Cache is already empty. Nothing to clear."));
|
|
885
1062
|
return;
|
|
886
1063
|
}
|
|
887
1064
|
let pattern;
|
|
@@ -890,45 +1067,45 @@ function cacheClearCommand() {
|
|
|
890
1067
|
} else if (options.pattern) {
|
|
891
1068
|
pattern = options.pattern;
|
|
892
1069
|
} else {
|
|
893
|
-
console.log(
|
|
894
|
-
console.log(
|
|
895
|
-
console.log(
|
|
1070
|
+
console.log(chalk8__default.default.yellow("Please specify what to clear:"));
|
|
1071
|
+
console.log(chalk8__default.default.dim(" --all Clear entire cache"));
|
|
1072
|
+
console.log(chalk8__default.default.dim(' --pattern Clear entries matching pattern (e.g., "codex://fractary/*")'));
|
|
896
1073
|
console.log("");
|
|
897
|
-
console.log(
|
|
898
|
-
console.log(
|
|
899
|
-
console.log(
|
|
1074
|
+
console.log(chalk8__default.default.dim("Examples:"));
|
|
1075
|
+
console.log(chalk8__default.default.dim(" fractary codex cache clear --all"));
|
|
1076
|
+
console.log(chalk8__default.default.dim(' fractary codex cache clear --pattern "codex://fractary/cli/*"'));
|
|
900
1077
|
return;
|
|
901
1078
|
}
|
|
902
1079
|
if (options.dryRun) {
|
|
903
|
-
console.log(
|
|
1080
|
+
console.log(chalk8__default.default.blue("Dry run - would clear:\n"));
|
|
904
1081
|
if (pattern) {
|
|
905
|
-
console.log(
|
|
906
|
-
console.log(
|
|
1082
|
+
console.log(chalk8__default.default.dim(` Pattern: ${pattern}`));
|
|
1083
|
+
console.log(chalk8__default.default.dim(` This would invalidate matching cache entries`));
|
|
907
1084
|
} else {
|
|
908
|
-
console.log(
|
|
1085
|
+
console.log(chalk8__default.default.dim(` All cache entries (${statsBefore.entryCount} entries)`));
|
|
909
1086
|
}
|
|
910
|
-
console.log(
|
|
1087
|
+
console.log(chalk8__default.default.dim(`
|
|
911
1088
|
Total size: ${formatSize2(statsBefore.totalSize)}`));
|
|
912
1089
|
return;
|
|
913
1090
|
}
|
|
914
1091
|
if (pattern) {
|
|
915
|
-
console.log(
|
|
1092
|
+
console.log(chalk8__default.default.blue(`Clearing cache entries matching pattern: ${pattern}
|
|
916
1093
|
`));
|
|
917
1094
|
await client.invalidateCache(pattern);
|
|
918
1095
|
} else {
|
|
919
|
-
console.log(
|
|
1096
|
+
console.log(chalk8__default.default.blue(`Clearing entire cache (${statsBefore.entryCount} entries)...
|
|
920
1097
|
`));
|
|
921
1098
|
await client.invalidateCache();
|
|
922
1099
|
}
|
|
923
1100
|
const statsAfter = await client.getCacheStats();
|
|
924
1101
|
const entriesCleared = statsBefore.entryCount - statsAfter.entryCount;
|
|
925
1102
|
const sizeFreed = statsBefore.totalSize - statsAfter.totalSize;
|
|
926
|
-
console.log(
|
|
1103
|
+
console.log(chalk8__default.default.green(`\u2713 Cleared ${entriesCleared} entries (${formatSize2(sizeFreed)} freed)`));
|
|
927
1104
|
if (statsAfter.entryCount > 0) {
|
|
928
|
-
console.log(
|
|
1105
|
+
console.log(chalk8__default.default.dim(` Remaining: ${statsAfter.entryCount} entries (${formatSize2(statsAfter.totalSize)})`));
|
|
929
1106
|
}
|
|
930
1107
|
} catch (error) {
|
|
931
|
-
console.error(
|
|
1108
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
932
1109
|
process.exit(1);
|
|
933
1110
|
}
|
|
934
1111
|
});
|
|
@@ -957,93 +1134,333 @@ function cacheStatsCommand() {
|
|
|
957
1134
|
console.log(JSON.stringify(stats, null, 2));
|
|
958
1135
|
return;
|
|
959
1136
|
}
|
|
960
|
-
console.log(
|
|
961
|
-
console.log(
|
|
962
|
-
console.log(` Total entries: ${
|
|
963
|
-
console.log(` Total size: ${
|
|
964
|
-
console.log(` Fresh entries: ${
|
|
965
|
-
console.log(` Stale entries: ${stats.staleCount > 0 ?
|
|
966
|
-
console.log(` Expired entries: ${stats.expiredCount > 0 ?
|
|
1137
|
+
console.log(chalk8__default.default.bold("Cache Statistics\n"));
|
|
1138
|
+
console.log(chalk8__default.default.bold("Overview"));
|
|
1139
|
+
console.log(` Total entries: ${chalk8__default.default.cyan(stats.entryCount.toString())}`);
|
|
1140
|
+
console.log(` Total size: ${chalk8__default.default.cyan(formatSize3(stats.totalSize))}`);
|
|
1141
|
+
console.log(` Fresh entries: ${chalk8__default.default.green(stats.freshCount.toString())}`);
|
|
1142
|
+
console.log(` Stale entries: ${stats.staleCount > 0 ? chalk8__default.default.yellow(stats.staleCount.toString()) : chalk8__default.default.dim("0")}`);
|
|
1143
|
+
console.log(` Expired entries: ${stats.expiredCount > 0 ? chalk8__default.default.red(stats.expiredCount.toString()) : chalk8__default.default.dim("0")}`);
|
|
967
1144
|
console.log("");
|
|
968
1145
|
const healthPercent = stats.entryCount > 0 ? stats.freshCount / stats.entryCount * 100 : 100;
|
|
969
|
-
const healthColor = healthPercent > 80 ?
|
|
1146
|
+
const healthColor = healthPercent > 80 ? chalk8__default.default.green : healthPercent > 50 ? chalk8__default.default.yellow : chalk8__default.default.red;
|
|
970
1147
|
console.log(`Cache health: ${healthColor(`${healthPercent.toFixed(0)}% fresh`)}`);
|
|
971
1148
|
if (stats.expiredCount > 0) {
|
|
972
|
-
console.log(
|
|
1149
|
+
console.log(chalk8__default.default.dim('\nRun "fractary codex cache clear --pattern <pattern>" to clean up entries.'));
|
|
973
1150
|
}
|
|
974
1151
|
if (stats.entryCount === 0) {
|
|
975
|
-
console.log(
|
|
1152
|
+
console.log(chalk8__default.default.dim("\nNo cached entries. Fetch some documents to populate the cache."));
|
|
976
1153
|
}
|
|
977
1154
|
} catch (error) {
|
|
978
|
-
console.error(
|
|
1155
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
979
1156
|
process.exit(1);
|
|
980
1157
|
}
|
|
981
1158
|
});
|
|
982
1159
|
return cmd;
|
|
983
1160
|
}
|
|
984
1161
|
|
|
985
|
-
// src/commands/cache/
|
|
986
|
-
function cacheCommand() {
|
|
987
|
-
const cmd = new commander.Command("cache");
|
|
988
|
-
cmd.description("Manage the codex document cache");
|
|
989
|
-
cmd.addCommand(cacheListCommand());
|
|
990
|
-
cmd.addCommand(cacheClearCommand());
|
|
991
|
-
cmd.addCommand(cacheStatsCommand());
|
|
992
|
-
return cmd;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
// src/commands/sync/index.ts
|
|
996
|
-
init_cjs_shims();
|
|
997
|
-
|
|
998
|
-
// src/commands/sync/project.ts
|
|
1162
|
+
// src/commands/cache/health.ts
|
|
999
1163
|
init_cjs_shims();
|
|
1000
1164
|
init_migrate_config();
|
|
1001
|
-
function
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
}
|
|
1008
|
-
return envMap[env] || env;
|
|
1009
|
-
}
|
|
1010
|
-
function formatBytes(bytes) {
|
|
1011
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
1012
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1013
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1014
|
-
}
|
|
1015
|
-
function formatDuration(ms) {
|
|
1016
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
1017
|
-
return `${(ms / 1e3).toFixed(1)}s`;
|
|
1165
|
+
async function fileExists3(filePath) {
|
|
1166
|
+
try {
|
|
1167
|
+
await fs__namespace.access(filePath);
|
|
1168
|
+
return true;
|
|
1169
|
+
} catch {
|
|
1170
|
+
return false;
|
|
1171
|
+
}
|
|
1018
1172
|
}
|
|
1019
|
-
function
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
}
|
|
1173
|
+
async function checkConfiguration() {
|
|
1174
|
+
const configPath = path3__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1175
|
+
const legacyConfigPath = path3__namespace.join(process.cwd(), ".fractary", "plugins", "codex", "config.json");
|
|
1176
|
+
try {
|
|
1177
|
+
if (!await fileExists3(configPath)) {
|
|
1178
|
+
if (await fileExists3(legacyConfigPath)) {
|
|
1179
|
+
return {
|
|
1180
|
+
name: "Configuration",
|
|
1181
|
+
status: "warn",
|
|
1182
|
+
message: "Legacy JSON configuration detected",
|
|
1183
|
+
details: 'Run "fractary codex migrate" to upgrade to YAML format'
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
return {
|
|
1187
|
+
name: "Configuration",
|
|
1188
|
+
status: "fail",
|
|
1189
|
+
message: "No configuration found",
|
|
1190
|
+
details: 'Run "fractary codex init" to create configuration'
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
const config = await readYamlConfig(configPath);
|
|
1194
|
+
if (!config.organization) {
|
|
1195
|
+
return {
|
|
1196
|
+
name: "Configuration",
|
|
1197
|
+
status: "warn",
|
|
1198
|
+
message: "No organization configured",
|
|
1199
|
+
details: "Organization slug is required"
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
const providerCount = config.storage?.length || 0;
|
|
1203
|
+
if (providerCount === 0) {
|
|
1204
|
+
return {
|
|
1205
|
+
name: "Configuration",
|
|
1206
|
+
status: "warn",
|
|
1207
|
+
message: "No storage providers configured",
|
|
1208
|
+
details: "At least one storage provider is recommended"
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
return {
|
|
1212
|
+
name: "Configuration",
|
|
1213
|
+
status: "pass",
|
|
1214
|
+
message: "Valid YAML configuration",
|
|
1215
|
+
details: `Organization: ${config.organization}, ${providerCount} storage provider(s)`
|
|
1216
|
+
};
|
|
1217
|
+
} catch (error) {
|
|
1218
|
+
return {
|
|
1219
|
+
name: "Configuration",
|
|
1220
|
+
status: "fail",
|
|
1221
|
+
message: "Invalid configuration",
|
|
1222
|
+
details: error.message
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
async function checkSDKClient() {
|
|
1227
|
+
try {
|
|
1228
|
+
const client = await getClient();
|
|
1229
|
+
const organization = client.getOrganization();
|
|
1230
|
+
return {
|
|
1231
|
+
name: "SDK Client",
|
|
1232
|
+
status: "pass",
|
|
1233
|
+
message: "CodexClient initialized successfully",
|
|
1234
|
+
details: `Organization: ${organization}`
|
|
1235
|
+
};
|
|
1236
|
+
} catch (error) {
|
|
1237
|
+
return {
|
|
1238
|
+
name: "SDK Client",
|
|
1239
|
+
status: "fail",
|
|
1240
|
+
message: "Failed to initialize CodexClient",
|
|
1241
|
+
details: error.message
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
async function checkCache() {
|
|
1246
|
+
try {
|
|
1247
|
+
const client = await getClient();
|
|
1248
|
+
const stats = await client.getCacheStats();
|
|
1249
|
+
if (stats.entryCount === 0) {
|
|
1250
|
+
return {
|
|
1251
|
+
name: "Cache",
|
|
1252
|
+
status: "warn",
|
|
1253
|
+
message: "Cache is empty",
|
|
1254
|
+
details: "Fetch some documents to populate cache"
|
|
1255
|
+
};
|
|
1256
|
+
}
|
|
1257
|
+
const healthPercent = stats.entryCount > 0 ? stats.freshCount / stats.entryCount * 100 : 100;
|
|
1258
|
+
if (healthPercent < 50) {
|
|
1259
|
+
return {
|
|
1260
|
+
name: "Cache",
|
|
1261
|
+
status: "warn",
|
|
1262
|
+
message: `${stats.entryCount} entries (${healthPercent.toFixed(0)}% fresh)`,
|
|
1263
|
+
details: `${stats.expiredCount} expired, ${stats.staleCount} stale`
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
return {
|
|
1267
|
+
name: "Cache",
|
|
1268
|
+
status: "pass",
|
|
1269
|
+
message: `${stats.entryCount} entries (${healthPercent.toFixed(0)}% fresh)`,
|
|
1270
|
+
details: `${formatSize4(stats.totalSize)} total`
|
|
1271
|
+
};
|
|
1272
|
+
} catch (error) {
|
|
1273
|
+
return {
|
|
1274
|
+
name: "Cache",
|
|
1275
|
+
status: "fail",
|
|
1276
|
+
message: "Cache check failed",
|
|
1277
|
+
details: error.message
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
async function checkStorage() {
|
|
1282
|
+
const configPath = path3__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1283
|
+
try {
|
|
1284
|
+
const config = await readYamlConfig(configPath);
|
|
1285
|
+
const providers = config.storage || [];
|
|
1286
|
+
if (providers.length === 0) {
|
|
1287
|
+
return {
|
|
1288
|
+
name: "Storage",
|
|
1289
|
+
status: "warn",
|
|
1290
|
+
message: "No storage providers configured",
|
|
1291
|
+
details: "Configure at least one provider in .fractary/codex.yaml"
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
const providerTypes = providers.map((p) => p.type).join(", ");
|
|
1295
|
+
const hasGitHub = providers.some((p) => p.type === "github");
|
|
1296
|
+
if (hasGitHub && !process.env.GITHUB_TOKEN) {
|
|
1297
|
+
return {
|
|
1298
|
+
name: "Storage",
|
|
1299
|
+
status: "warn",
|
|
1300
|
+
message: `${providers.length} provider(s): ${providerTypes}`,
|
|
1301
|
+
details: "GITHUB_TOKEN not set (required for GitHub provider)"
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
name: "Storage",
|
|
1306
|
+
status: "pass",
|
|
1307
|
+
message: `${providers.length} provider(s): ${providerTypes}`,
|
|
1308
|
+
details: "All configured providers available"
|
|
1309
|
+
};
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
return {
|
|
1312
|
+
name: "Storage",
|
|
1313
|
+
status: "fail",
|
|
1314
|
+
message: "Storage check failed",
|
|
1315
|
+
details: error.message
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
async function checkTypes() {
|
|
1320
|
+
try {
|
|
1321
|
+
const client = await getClient();
|
|
1322
|
+
const registry = client.getTypeRegistry();
|
|
1323
|
+
const allTypes = registry.list();
|
|
1324
|
+
const builtinCount = allTypes.filter((t) => registry.isBuiltIn(t.name)).length;
|
|
1325
|
+
const customCount = allTypes.length - builtinCount;
|
|
1326
|
+
return {
|
|
1327
|
+
name: "Type Registry",
|
|
1328
|
+
status: "pass",
|
|
1329
|
+
message: `${allTypes.length} types registered`,
|
|
1330
|
+
details: `${builtinCount} built-in, ${customCount} custom`
|
|
1331
|
+
};
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
return {
|
|
1334
|
+
name: "Type Registry",
|
|
1335
|
+
status: "fail",
|
|
1336
|
+
message: "Type registry check failed",
|
|
1337
|
+
details: error.message
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
function formatSize4(bytes) {
|
|
1342
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1343
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1344
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1345
|
+
}
|
|
1346
|
+
function healthCommand() {
|
|
1347
|
+
const cmd = new commander.Command("health");
|
|
1348
|
+
cmd.description("Run diagnostics on codex setup").option("--json", "Output as JSON").action(async (options) => {
|
|
1349
|
+
try {
|
|
1350
|
+
const checks = [];
|
|
1351
|
+
checks.push(await checkConfiguration());
|
|
1352
|
+
checks.push(await checkSDKClient());
|
|
1353
|
+
checks.push(await checkCache());
|
|
1354
|
+
checks.push(await checkStorage());
|
|
1355
|
+
checks.push(await checkTypes());
|
|
1356
|
+
const passed = checks.filter((c) => c.status === "pass").length;
|
|
1357
|
+
const warned = checks.filter((c) => c.status === "warn").length;
|
|
1358
|
+
const failed = checks.filter((c) => c.status === "fail").length;
|
|
1359
|
+
if (options.json) {
|
|
1360
|
+
console.log(JSON.stringify({
|
|
1361
|
+
summary: {
|
|
1362
|
+
total: checks.length,
|
|
1363
|
+
passed,
|
|
1364
|
+
warned,
|
|
1365
|
+
failed,
|
|
1366
|
+
healthy: failed === 0
|
|
1367
|
+
},
|
|
1368
|
+
checks
|
|
1369
|
+
}, null, 2));
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
console.log(chalk8__default.default.bold("Codex Health Check\n"));
|
|
1373
|
+
for (const check of checks) {
|
|
1374
|
+
const icon = check.status === "pass" ? chalk8__default.default.green("\u2713") : check.status === "warn" ? chalk8__default.default.yellow("\u26A0") : chalk8__default.default.red("\u2717");
|
|
1375
|
+
const statusColor = check.status === "pass" ? chalk8__default.default.green : check.status === "warn" ? chalk8__default.default.yellow : chalk8__default.default.red;
|
|
1376
|
+
console.log(`${icon} ${chalk8__default.default.bold(check.name)}`);
|
|
1377
|
+
console.log(` ${statusColor(check.message)}`);
|
|
1378
|
+
if (check.details) {
|
|
1379
|
+
console.log(` ${chalk8__default.default.dim(check.details)}`);
|
|
1380
|
+
}
|
|
1381
|
+
console.log("");
|
|
1382
|
+
}
|
|
1383
|
+
console.log(chalk8__default.default.dim("\u2500".repeat(60)));
|
|
1384
|
+
const overallStatus = failed > 0 ? chalk8__default.default.red("UNHEALTHY") : warned > 0 ? chalk8__default.default.yellow("DEGRADED") : chalk8__default.default.green("HEALTHY");
|
|
1385
|
+
console.log(`Status: ${overallStatus}`);
|
|
1386
|
+
console.log(chalk8__default.default.dim(`${passed} passed, ${warned} warnings, ${failed} failed`));
|
|
1387
|
+
if (failed > 0 || warned > 0) {
|
|
1388
|
+
console.log("");
|
|
1389
|
+
console.log(chalk8__default.default.dim("Run checks individually for more details:"));
|
|
1390
|
+
console.log(chalk8__default.default.dim(" fractary codex cache stats"));
|
|
1391
|
+
console.log(chalk8__default.default.dim(" fractary codex types list"));
|
|
1392
|
+
}
|
|
1393
|
+
if (failed > 0) {
|
|
1394
|
+
process.exit(1);
|
|
1395
|
+
}
|
|
1396
|
+
} catch (error) {
|
|
1397
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
1398
|
+
process.exit(1);
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
return cmd;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// src/commands/cache/index.ts
|
|
1405
|
+
function cacheCommand() {
|
|
1406
|
+
const cmd = new commander.Command("cache");
|
|
1407
|
+
cmd.description("Manage the codex document cache");
|
|
1408
|
+
cmd.addCommand(cacheListCommand());
|
|
1409
|
+
cmd.addCommand(cacheClearCommand());
|
|
1410
|
+
cmd.addCommand(cacheStatsCommand());
|
|
1411
|
+
cmd.addCommand(healthCommand());
|
|
1412
|
+
return cmd;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
// src/commands/sync.ts
|
|
1416
|
+
init_cjs_shims();
|
|
1417
|
+
init_migrate_config();
|
|
1418
|
+
function getEnvironmentBranch(config, env) {
|
|
1419
|
+
const envMap = config.sync?.environments || {
|
|
1420
|
+
dev: "develop",
|
|
1421
|
+
test: "test",
|
|
1422
|
+
staging: "staging",
|
|
1423
|
+
prod: "main"
|
|
1424
|
+
};
|
|
1425
|
+
return envMap[env] || env;
|
|
1426
|
+
}
|
|
1427
|
+
function formatBytes(bytes) {
|
|
1428
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
1429
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1430
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1431
|
+
}
|
|
1432
|
+
function formatDuration(ms) {
|
|
1433
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
1434
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
1435
|
+
}
|
|
1436
|
+
function syncCommand() {
|
|
1437
|
+
const cmd = new commander.Command("sync");
|
|
1438
|
+
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) => {
|
|
1439
|
+
try {
|
|
1440
|
+
const configPath = path3__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1441
|
+
let config;
|
|
1442
|
+
try {
|
|
1443
|
+
config = await readYamlConfig(configPath);
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
console.error(chalk8__default.default.red("Error:"), "Codex not initialized.");
|
|
1446
|
+
console.log(chalk8__default.default.dim('Run "fractary codex init" first.'));
|
|
1447
|
+
process.exit(1);
|
|
1448
|
+
}
|
|
1449
|
+
const { createSyncManager, createLocalStorage, detectCurrentProject } = await import('@fractary/codex');
|
|
1450
|
+
let projectName = name;
|
|
1038
1451
|
if (!projectName) {
|
|
1039
|
-
|
|
1040
|
-
|
|
1452
|
+
const detected = detectCurrentProject();
|
|
1453
|
+
projectName = detected.project || null;
|
|
1454
|
+
}
|
|
1455
|
+
if (!projectName) {
|
|
1456
|
+
console.error(chalk8__default.default.red("Error:"), "Could not determine project name.");
|
|
1457
|
+
console.log(chalk8__default.default.dim("Provide project name as argument or run from a git repository."));
|
|
1041
1458
|
process.exit(1);
|
|
1042
1459
|
}
|
|
1043
1460
|
const validDirections = ["to-codex", "from-codex", "bidirectional"];
|
|
1044
1461
|
if (!validDirections.includes(options.direction)) {
|
|
1045
|
-
console.error(
|
|
1046
|
-
console.log(
|
|
1462
|
+
console.error(chalk8__default.default.red("Error:"), `Invalid direction: ${options.direction}`);
|
|
1463
|
+
console.log(chalk8__default.default.dim("Valid options: to-codex, from-codex, bidirectional"));
|
|
1047
1464
|
process.exit(1);
|
|
1048
1465
|
}
|
|
1049
1466
|
const direction = options.direction;
|
|
@@ -1054,7 +1471,7 @@ function syncProjectCommand() {
|
|
|
1054
1471
|
const syncManager = createSyncManager({
|
|
1055
1472
|
localStorage,
|
|
1056
1473
|
config: config.sync,
|
|
1057
|
-
manifestPath:
|
|
1474
|
+
manifestPath: path3__namespace.join(process.cwd(), ".fractary", ".codex-sync-manifest.json")
|
|
1058
1475
|
});
|
|
1059
1476
|
const defaultPatterns = config.sync?.include || [
|
|
1060
1477
|
"docs/**/*.md",
|
|
@@ -1107,7 +1524,7 @@ function syncProjectCommand() {
|
|
|
1107
1524
|
synced: 0
|
|
1108
1525
|
}, null, 2));
|
|
1109
1526
|
} else {
|
|
1110
|
-
console.log(
|
|
1527
|
+
console.log(chalk8__default.default.yellow("No files to sync."));
|
|
1111
1528
|
}
|
|
1112
1529
|
return;
|
|
1113
1530
|
}
|
|
@@ -1150,364 +1567,90 @@ function syncProjectCommand() {
|
|
|
1150
1567
|
}, null, 2));
|
|
1151
1568
|
return;
|
|
1152
1569
|
}
|
|
1153
|
-
console.log(
|
|
1154
|
-
console.log(` Project: ${
|
|
1155
|
-
console.log(` Organization: ${
|
|
1156
|
-
console.log(` Environment: ${
|
|
1157
|
-
console.log(` Direction: ${
|
|
1158
|
-
console.log(` Files: ${
|
|
1159
|
-
console.log(` Total size: ${
|
|
1570
|
+
console.log(chalk8__default.default.bold("Sync Plan\n"));
|
|
1571
|
+
console.log(` Project: ${chalk8__default.default.cyan(projectName)}`);
|
|
1572
|
+
console.log(` Organization: ${chalk8__default.default.cyan(config.organization)}`);
|
|
1573
|
+
console.log(` Environment: ${chalk8__default.default.cyan(options.env)} (${targetBranch})`);
|
|
1574
|
+
console.log(` Direction: ${chalk8__default.default.cyan(direction)}`);
|
|
1575
|
+
console.log(` Files: ${chalk8__default.default.cyan(plan.totalFiles.toString())}`);
|
|
1576
|
+
console.log(` Total size: ${chalk8__default.default.cyan(formatBytes(plan.totalBytes))}`);
|
|
1160
1577
|
if (plan.estimatedTime) {
|
|
1161
|
-
console.log(` Est. time: ${
|
|
1578
|
+
console.log(` Est. time: ${chalk8__default.default.dim(formatDuration(plan.estimatedTime))}`);
|
|
1162
1579
|
}
|
|
1163
1580
|
console.log("");
|
|
1164
1581
|
if (plan.conflicts.length > 0) {
|
|
1165
|
-
console.log(
|
|
1582
|
+
console.log(chalk8__default.default.yellow(`\u26A0 ${plan.conflicts.length} conflicts detected:`));
|
|
1166
1583
|
for (const conflict of plan.conflicts.slice(0, 5)) {
|
|
1167
|
-
console.log(
|
|
1584
|
+
console.log(chalk8__default.default.yellow(` \u2022 ${conflict.path}`));
|
|
1168
1585
|
}
|
|
1169
1586
|
if (plan.conflicts.length > 5) {
|
|
1170
|
-
console.log(
|
|
1587
|
+
console.log(chalk8__default.default.dim(` ... and ${plan.conflicts.length - 5} more`));
|
|
1171
1588
|
}
|
|
1172
1589
|
console.log("");
|
|
1173
1590
|
}
|
|
1174
1591
|
if (plan.skipped.length > 0) {
|
|
1175
|
-
console.log(
|
|
1592
|
+
console.log(chalk8__default.default.dim(`${plan.skipped.length} files skipped (no changes)`));
|
|
1176
1593
|
console.log("");
|
|
1177
1594
|
}
|
|
1178
1595
|
if (options.dryRun) {
|
|
1179
|
-
console.log(
|
|
1596
|
+
console.log(chalk8__default.default.blue("Dry run - would sync:\n"));
|
|
1180
1597
|
const filesToShow = plan.files.slice(0, 10);
|
|
1181
1598
|
for (const file of filesToShow) {
|
|
1182
1599
|
const arrow = direction === "to-codex" ? "\u2192" : direction === "from-codex" ? "\u2190" : "\u2194";
|
|
1183
|
-
const opColor = file.operation === "create" ?
|
|
1600
|
+
const opColor = file.operation === "create" ? chalk8__default.default.green : file.operation === "update" ? chalk8__default.default.yellow : chalk8__default.default.dim;
|
|
1184
1601
|
console.log(
|
|
1185
|
-
|
|
1602
|
+
chalk8__default.default.dim(` ${arrow}`),
|
|
1186
1603
|
opColor(file.operation.padEnd(7)),
|
|
1187
1604
|
file.path,
|
|
1188
|
-
|
|
1605
|
+
chalk8__default.default.dim(`(${formatBytes(file.size || 0)})`)
|
|
1189
1606
|
);
|
|
1190
1607
|
}
|
|
1191
1608
|
if (plan.files.length > 10) {
|
|
1192
|
-
console.log(
|
|
1193
|
-
}
|
|
1194
|
-
console.log(chalk6__default.default.dim(`
|
|
1195
|
-
Total: ${plan.totalFiles} files (${formatBytes(plan.totalBytes)})`));
|
|
1196
|
-
console.log(chalk6__default.default.dim("Run without --dry-run to execute sync."));
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
|
-
console.log(chalk6__default.default.blue("Syncing...\n"));
|
|
1200
|
-
const startTime = Date.now();
|
|
1201
|
-
const result = await syncManager.executePlan(plan, syncOptions);
|
|
1202
|
-
const duration = Date.now() - startTime;
|
|
1203
|
-
console.log("");
|
|
1204
|
-
if (result.success) {
|
|
1205
|
-
console.log(chalk6__default.default.green(`\u2713 Sync completed successfully`));
|
|
1206
|
-
console.log(chalk6__default.default.dim(` Synced: ${result.synced} files`));
|
|
1207
|
-
if (result.skipped > 0) {
|
|
1208
|
-
console.log(chalk6__default.default.dim(` Skipped: ${result.skipped} files`));
|
|
1209
|
-
}
|
|
1210
|
-
console.log(chalk6__default.default.dim(` Duration: ${formatDuration(duration)}`));
|
|
1211
|
-
} else {
|
|
1212
|
-
console.log(chalk6__default.default.yellow(`\u26A0 Sync completed with errors`));
|
|
1213
|
-
console.log(chalk6__default.default.green(` Synced: ${result.synced} files`));
|
|
1214
|
-
console.log(chalk6__default.default.red(` Failed: ${result.failed} files`));
|
|
1215
|
-
if (result.skipped > 0) {
|
|
1216
|
-
console.log(chalk6__default.default.dim(` Skipped: ${result.skipped} files`));
|
|
1217
|
-
}
|
|
1218
|
-
if (result.errors.length > 0) {
|
|
1219
|
-
console.log("");
|
|
1220
|
-
console.log(chalk6__default.default.red("Errors:"));
|
|
1221
|
-
for (const error of result.errors.slice(0, 5)) {
|
|
1222
|
-
console.log(chalk6__default.default.red(` \u2022 ${error.path}: ${error.error}`));
|
|
1223
|
-
}
|
|
1224
|
-
if (result.errors.length > 5) {
|
|
1225
|
-
console.log(chalk6__default.default.dim(` ... and ${result.errors.length - 5} more errors`));
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
} catch (error) {
|
|
1230
|
-
console.error(chalk6__default.default.red("Error:"), error.message);
|
|
1231
|
-
process.exit(1);
|
|
1232
|
-
}
|
|
1233
|
-
});
|
|
1234
|
-
return cmd;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
// src/commands/sync/org.ts
|
|
1238
|
-
init_cjs_shims();
|
|
1239
|
-
init_migrate_config();
|
|
1240
|
-
function getEnvironmentBranch2(config, env) {
|
|
1241
|
-
const envMap = config.sync?.environments || {
|
|
1242
|
-
dev: "develop",
|
|
1243
|
-
test: "test",
|
|
1244
|
-
staging: "staging",
|
|
1245
|
-
prod: "main"
|
|
1246
|
-
};
|
|
1247
|
-
return envMap[env] || env;
|
|
1248
|
-
}
|
|
1249
|
-
async function discoverRepos(org) {
|
|
1250
|
-
try {
|
|
1251
|
-
const output = child_process.execSync(
|
|
1252
|
-
`gh repo list ${org} --json name,url,defaultBranchRef --limit 100`,
|
|
1253
|
-
{ encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
1254
|
-
);
|
|
1255
|
-
const repos = JSON.parse(output);
|
|
1256
|
-
return repos.map((repo) => ({
|
|
1257
|
-
name: repo.name,
|
|
1258
|
-
url: repo.url,
|
|
1259
|
-
defaultBranch: repo.defaultBranchRef?.name || "main"
|
|
1260
|
-
}));
|
|
1261
|
-
} catch (error) {
|
|
1262
|
-
throw new Error(`Failed to discover repos: ${error.message}. Ensure GitHub CLI is installed and authenticated.`);
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
function shouldExclude(repoName, excludePatterns) {
|
|
1266
|
-
for (const pattern of excludePatterns) {
|
|
1267
|
-
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
|
|
1268
|
-
if (regex.test(repoName)) {
|
|
1269
|
-
return true;
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
return false;
|
|
1273
|
-
}
|
|
1274
|
-
async function syncRepository(repo, config, direction, syncOptions) {
|
|
1275
|
-
const startTime = Date.now();
|
|
1276
|
-
try {
|
|
1277
|
-
const { createSyncManager, createLocalStorage } = await import('@fractary/codex');
|
|
1278
|
-
const repoDir = path2__namespace.join(process.cwd(), "..", repo.name);
|
|
1279
|
-
const localStorage = createLocalStorage({
|
|
1280
|
-
baseDir: repoDir
|
|
1281
|
-
});
|
|
1282
|
-
const syncManager = createSyncManager({
|
|
1283
|
-
localStorage,
|
|
1284
|
-
config: config.sync,
|
|
1285
|
-
manifestPath: path2__namespace.join(repoDir, ".fractary", ".codex-sync-manifest.json")
|
|
1286
|
-
});
|
|
1287
|
-
const includePatterns = config.sync?.include || [
|
|
1288
|
-
"docs/**/*.md",
|
|
1289
|
-
"specs/**/*.md",
|
|
1290
|
-
".fractary/standards/**",
|
|
1291
|
-
".fractary/templates/**"
|
|
1292
|
-
];
|
|
1293
|
-
const allFiles = await syncManager.listLocalFiles(repoDir);
|
|
1294
|
-
const targetFiles = allFiles.filter((file) => {
|
|
1295
|
-
for (const pattern of includePatterns) {
|
|
1296
|
-
const regex = new RegExp("^" + pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*") + "$");
|
|
1297
|
-
if (regex.test(file.path)) {
|
|
1298
|
-
return true;
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
return false;
|
|
1302
|
-
});
|
|
1303
|
-
const plan = await syncManager.createPlan(
|
|
1304
|
-
config.organization,
|
|
1305
|
-
repo.name,
|
|
1306
|
-
repoDir,
|
|
1307
|
-
targetFiles,
|
|
1308
|
-
syncOptions
|
|
1309
|
-
);
|
|
1310
|
-
if (plan.totalFiles === 0) {
|
|
1311
|
-
return {
|
|
1312
|
-
repo: repo.name,
|
|
1313
|
-
status: "skipped",
|
|
1314
|
-
filesSynced: 0,
|
|
1315
|
-
duration: Date.now() - startTime
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
const result = await syncManager.executePlan(plan, syncOptions);
|
|
1319
|
-
return {
|
|
1320
|
-
repo: repo.name,
|
|
1321
|
-
status: result.success ? "success" : "error",
|
|
1322
|
-
filesSynced: result.synced,
|
|
1323
|
-
duration: Date.now() - startTime,
|
|
1324
|
-
error: result.success ? void 0 : `${result.failed} files failed`
|
|
1325
|
-
};
|
|
1326
|
-
} catch (error) {
|
|
1327
|
-
return {
|
|
1328
|
-
repo: repo.name,
|
|
1329
|
-
status: "error",
|
|
1330
|
-
duration: Date.now() - startTime,
|
|
1331
|
-
error: error.message
|
|
1332
|
-
};
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
function syncOrgCommand() {
|
|
1336
|
-
const cmd = new commander.Command("org");
|
|
1337
|
-
cmd.description("Sync all projects in organization with codex repository").option("--env <env>", "Target environment (dev/test/staging/prod)", "prod").option("--dry-run", "Show what would sync without executing").option("--exclude <pattern>", "Exclude repos matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--parallel <n>", "Number of parallel syncs", parseInt, 3).option("--direction <dir>", "Sync direction (to-codex/from-codex/bidirectional)", "bidirectional").option("--json", "Output as JSON").action(async (options) => {
|
|
1338
|
-
try {
|
|
1339
|
-
const configPath = path2__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1340
|
-
let config;
|
|
1341
|
-
try {
|
|
1342
|
-
config = await readYamlConfig(configPath);
|
|
1343
|
-
} catch (error) {
|
|
1344
|
-
console.error(chalk6__default.default.red("Error:"), "Codex not initialized.");
|
|
1345
|
-
console.log(chalk6__default.default.dim('Run "fractary codex init" first.'));
|
|
1346
|
-
process.exit(1);
|
|
1347
|
-
}
|
|
1348
|
-
const validDirections = ["to-codex", "from-codex", "bidirectional"];
|
|
1349
|
-
if (!validDirections.includes(options.direction)) {
|
|
1350
|
-
console.error(chalk6__default.default.red("Error:"), `Invalid direction: ${options.direction}`);
|
|
1351
|
-
console.log(chalk6__default.default.dim("Valid options: to-codex, from-codex, bidirectional"));
|
|
1352
|
-
process.exit(1);
|
|
1353
|
-
}
|
|
1354
|
-
const direction = options.direction;
|
|
1355
|
-
const org = config.organization;
|
|
1356
|
-
const targetBranch = getEnvironmentBranch2(config, options.env);
|
|
1357
|
-
const excludePatterns = [
|
|
1358
|
-
...config.sync?.exclude || [],
|
|
1359
|
-
...options.exclude
|
|
1360
|
-
];
|
|
1361
|
-
if (!options.json) {
|
|
1362
|
-
console.log(chalk6__default.default.bold("Organization Sync\n"));
|
|
1363
|
-
console.log(` Organization: ${chalk6__default.default.cyan(org)}`);
|
|
1364
|
-
console.log(` Environment: ${chalk6__default.default.cyan(options.env)} (${targetBranch})`);
|
|
1365
|
-
console.log(` Direction: ${chalk6__default.default.cyan(direction)}`);
|
|
1366
|
-
console.log(` Parallelism: ${chalk6__default.default.cyan(options.parallel.toString())}`);
|
|
1367
|
-
if (excludePatterns.length > 0) {
|
|
1368
|
-
console.log(` Excluding: ${chalk6__default.default.dim(excludePatterns.join(", "))}`);
|
|
1369
|
-
}
|
|
1370
|
-
console.log("");
|
|
1371
|
-
console.log(chalk6__default.default.dim("Discovering repositories..."));
|
|
1372
|
-
}
|
|
1373
|
-
let repos;
|
|
1374
|
-
try {
|
|
1375
|
-
repos = await discoverRepos(org);
|
|
1376
|
-
} catch (error) {
|
|
1377
|
-
if (options.json) {
|
|
1378
|
-
console.log(JSON.stringify({ error: error.message }));
|
|
1379
|
-
} else {
|
|
1380
|
-
console.error(chalk6__default.default.red("Error:"), error.message);
|
|
1381
|
-
}
|
|
1382
|
-
process.exit(1);
|
|
1383
|
-
}
|
|
1384
|
-
const eligibleRepos = repos.filter((repo) => !shouldExclude(repo.name, excludePatterns));
|
|
1385
|
-
const excludedRepos = repos.filter((repo) => shouldExclude(repo.name, excludePatterns));
|
|
1386
|
-
if (!options.json) {
|
|
1387
|
-
console.log(chalk6__default.default.dim(`Found ${repos.length} repositories (${excludedRepos.length} excluded)
|
|
1388
|
-
`));
|
|
1389
|
-
}
|
|
1390
|
-
if (options.dryRun) {
|
|
1391
|
-
if (options.json) {
|
|
1392
|
-
console.log(JSON.stringify({
|
|
1393
|
-
organization: org,
|
|
1394
|
-
environment: options.env,
|
|
1395
|
-
branch: targetBranch,
|
|
1396
|
-
direction,
|
|
1397
|
-
dryRun: true,
|
|
1398
|
-
repos: {
|
|
1399
|
-
total: repos.length,
|
|
1400
|
-
eligible: eligibleRepos.map((r) => r.name),
|
|
1401
|
-
excluded: excludedRepos.map((r) => r.name)
|
|
1402
|
-
}
|
|
1403
|
-
}, null, 2));
|
|
1404
|
-
} else {
|
|
1405
|
-
console.log(chalk6__default.default.blue("Dry run - would sync:\n"));
|
|
1406
|
-
for (const repo of eligibleRepos) {
|
|
1407
|
-
console.log(chalk6__default.default.green(" \u2713"), repo.name);
|
|
1408
|
-
}
|
|
1409
|
-
if (excludedRepos.length > 0) {
|
|
1410
|
-
console.log("");
|
|
1411
|
-
console.log(chalk6__default.default.dim("Excluded:"));
|
|
1412
|
-
for (const repo of excludedRepos) {
|
|
1413
|
-
console.log(chalk6__default.default.dim(` - ${repo.name}`));
|
|
1414
|
-
}
|
|
1415
|
-
}
|
|
1416
|
-
console.log(chalk6__default.default.dim(`
|
|
1417
|
-
Total: ${eligibleRepos.length} repos would be synced`));
|
|
1418
|
-
console.log(chalk6__default.default.dim("Run without --dry-run to execute sync."));
|
|
1419
|
-
}
|
|
1420
|
-
return;
|
|
1421
|
-
}
|
|
1422
|
-
if (!options.json) {
|
|
1423
|
-
console.log(chalk6__default.default.blue("Syncing repositories...\n"));
|
|
1424
|
-
}
|
|
1425
|
-
const results = [];
|
|
1426
|
-
const syncOptions = {
|
|
1427
|
-
direction,
|
|
1428
|
-
dryRun: false,
|
|
1429
|
-
force: false
|
|
1430
|
-
};
|
|
1431
|
-
for (let i = 0; i < eligibleRepos.length; i += options.parallel) {
|
|
1432
|
-
const batch = eligibleRepos.slice(i, i + options.parallel);
|
|
1433
|
-
const batchResults = await Promise.all(
|
|
1434
|
-
batch.map((repo) => syncRepository(repo, config, direction, syncOptions))
|
|
1435
|
-
);
|
|
1436
|
-
for (const result of batchResults) {
|
|
1437
|
-
results.push(result);
|
|
1438
|
-
if (!options.json) {
|
|
1439
|
-
if (result.status === "success") {
|
|
1440
|
-
console.log(
|
|
1441
|
-
chalk6__default.default.green(" \u2713"),
|
|
1442
|
-
result.repo,
|
|
1443
|
-
chalk6__default.default.dim(`(${result.filesSynced} files in ${result.duration}ms)`)
|
|
1444
|
-
);
|
|
1445
|
-
} else if (result.status === "skipped") {
|
|
1446
|
-
console.log(
|
|
1447
|
-
chalk6__default.default.dim(" -"),
|
|
1448
|
-
result.repo,
|
|
1449
|
-
chalk6__default.default.dim("(no files to sync)")
|
|
1450
|
-
);
|
|
1451
|
-
} else if (result.status === "error") {
|
|
1452
|
-
console.log(
|
|
1453
|
-
chalk6__default.default.red(" \u2717"),
|
|
1454
|
-
result.repo,
|
|
1455
|
-
chalk6__default.default.red(`(${result.error})`)
|
|
1456
|
-
);
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1609
|
+
console.log(chalk8__default.default.dim(` ... and ${plan.files.length - 10} more files`));
|
|
1459
1610
|
}
|
|
1611
|
+
console.log(chalk8__default.default.dim(`
|
|
1612
|
+
Total: ${plan.totalFiles} files (${formatBytes(plan.totalBytes)})`));
|
|
1613
|
+
console.log(chalk8__default.default.dim("Run without --dry-run to execute sync."));
|
|
1614
|
+
return;
|
|
1460
1615
|
}
|
|
1461
|
-
|
|
1462
|
-
const
|
|
1463
|
-
const
|
|
1464
|
-
const
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
successful: successful.length,
|
|
1474
|
-
skipped: skipped.length,
|
|
1475
|
-
failed: failed.length,
|
|
1476
|
-
filesSynced: totalFiles,
|
|
1477
|
-
details: results
|
|
1478
|
-
}
|
|
1479
|
-
}, null, 2));
|
|
1616
|
+
console.log(chalk8__default.default.blue("Syncing...\n"));
|
|
1617
|
+
const startTime = Date.now();
|
|
1618
|
+
const result = await syncManager.executePlan(plan, syncOptions);
|
|
1619
|
+
const duration = Date.now() - startTime;
|
|
1620
|
+
console.log("");
|
|
1621
|
+
if (result.success) {
|
|
1622
|
+
console.log(chalk8__default.default.green(`\u2713 Sync completed successfully`));
|
|
1623
|
+
console.log(chalk8__default.default.dim(` Synced: ${result.synced} files`));
|
|
1624
|
+
if (result.skipped > 0) {
|
|
1625
|
+
console.log(chalk8__default.default.dim(` Skipped: ${result.skipped} files`));
|
|
1626
|
+
}
|
|
1627
|
+
console.log(chalk8__default.default.dim(` Duration: ${formatDuration(duration)}`));
|
|
1480
1628
|
} else {
|
|
1481
|
-
console.log(
|
|
1482
|
-
console.log(
|
|
1483
|
-
|
|
1484
|
-
|
|
1629
|
+
console.log(chalk8__default.default.yellow(`\u26A0 Sync completed with errors`));
|
|
1630
|
+
console.log(chalk8__default.default.green(` Synced: ${result.synced} files`));
|
|
1631
|
+
console.log(chalk8__default.default.red(` Failed: ${result.failed} files`));
|
|
1632
|
+
if (result.skipped > 0) {
|
|
1633
|
+
console.log(chalk8__default.default.dim(` Skipped: ${result.skipped} files`));
|
|
1485
1634
|
}
|
|
1486
|
-
if (
|
|
1487
|
-
console.log(
|
|
1635
|
+
if (result.errors.length > 0) {
|
|
1636
|
+
console.log("");
|
|
1637
|
+
console.log(chalk8__default.default.red("Errors:"));
|
|
1638
|
+
for (const error of result.errors.slice(0, 5)) {
|
|
1639
|
+
console.log(chalk8__default.default.red(` \u2022 ${error.path}: ${error.error}`));
|
|
1640
|
+
}
|
|
1641
|
+
if (result.errors.length > 5) {
|
|
1642
|
+
console.log(chalk8__default.default.dim(` ... and ${result.errors.length - 5} more errors`));
|
|
1643
|
+
}
|
|
1488
1644
|
}
|
|
1489
1645
|
}
|
|
1490
1646
|
} catch (error) {
|
|
1491
|
-
|
|
1492
|
-
console.log(JSON.stringify({ error: error.message }));
|
|
1493
|
-
} else {
|
|
1494
|
-
console.error(chalk6__default.default.red("Error:"), error.message);
|
|
1495
|
-
}
|
|
1647
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
1496
1648
|
process.exit(1);
|
|
1497
1649
|
}
|
|
1498
1650
|
});
|
|
1499
1651
|
return cmd;
|
|
1500
1652
|
}
|
|
1501
1653
|
|
|
1502
|
-
// src/commands/sync/index.ts
|
|
1503
|
-
function syncCommand() {
|
|
1504
|
-
const cmd = new commander.Command("sync");
|
|
1505
|
-
cmd.description("Synchronize with codex repository");
|
|
1506
|
-
cmd.addCommand(syncProjectCommand());
|
|
1507
|
-
cmd.addCommand(syncOrgCommand());
|
|
1508
|
-
return cmd;
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
1654
|
// src/commands/types/index.ts
|
|
1512
1655
|
init_cjs_shims();
|
|
1513
1656
|
|
|
@@ -1533,713 +1676,306 @@ function typesListCommand() {
|
|
|
1533
1676
|
types = allTypes.filter((t) => registry.isBuiltIn(t.name));
|
|
1534
1677
|
}
|
|
1535
1678
|
if (options.json) {
|
|
1536
|
-
const builtinCount = types.filter((t) => registry.isBuiltIn(t.name)).length;
|
|
1537
|
-
const customCount = types.length - builtinCount;
|
|
1538
|
-
console.log(JSON.stringify({
|
|
1539
|
-
count: types.length,
|
|
1540
|
-
builtinCount,
|
|
1541
|
-
customCount,
|
|
1542
|
-
types: types.map((t) => ({
|
|
1543
|
-
name: t.name,
|
|
1544
|
-
description: t.description,
|
|
1545
|
-
patterns: t.patterns,
|
|
1546
|
-
defaultTtl: t.defaultTtl,
|
|
1547
|
-
ttl: formatTtl(t.defaultTtl),
|
|
1548
|
-
builtin: registry.isBuiltIn(t.name),
|
|
1549
|
-
archiveAfterDays: t.archiveAfterDays,
|
|
1550
|
-
archiveStorage: t.archiveStorage
|
|
1551
|
-
}))
|
|
1552
|
-
}, null, 2));
|
|
1553
|
-
return;
|
|
1554
|
-
}
|
|
1555
|
-
if (types.length === 0) {
|
|
1556
|
-
console.log(chalk6__default.default.yellow("No types found."));
|
|
1557
|
-
return;
|
|
1558
|
-
}
|
|
1559
|
-
console.log(chalk6__default.default.bold("Artifact Types\n"));
|
|
1560
|
-
const builtinTypes = types.filter((t) => registry.isBuiltIn(t.name));
|
|
1561
|
-
const customTypes = types.filter((t) => !registry.isBuiltIn(t.name));
|
|
1562
|
-
if (builtinTypes.length > 0 && !options.customOnly) {
|
|
1563
|
-
console.log(chalk6__default.default.bold("Built-in Types"));
|
|
1564
|
-
console.log(chalk6__default.default.dim("\u2500".repeat(70)));
|
|
1565
|
-
for (const type of builtinTypes) {
|
|
1566
|
-
const patternStr = type.patterns[0] || "";
|
|
1567
|
-
console.log(` ${chalk6__default.default.cyan(type.name.padEnd(12))} ${patternStr.padEnd(30)} ${chalk6__default.default.dim(`TTL: ${formatTtl(type.defaultTtl)}`)}`);
|
|
1568
|
-
console.log(` ${chalk6__default.default.dim(" ".repeat(12) + type.description)}`);
|
|
1569
|
-
}
|
|
1570
|
-
console.log("");
|
|
1571
|
-
}
|
|
1572
|
-
if (customTypes.length > 0 && !options.builtinOnly) {
|
|
1573
|
-
console.log(chalk6__default.default.bold("Custom Types"));
|
|
1574
|
-
console.log(chalk6__default.default.dim("\u2500".repeat(70)));
|
|
1575
|
-
for (const type of customTypes) {
|
|
1576
|
-
const patternStr = type.patterns[0] || "";
|
|
1577
|
-
console.log(` ${chalk6__default.default.green(type.name.padEnd(12))} ${patternStr.padEnd(30)} ${chalk6__default.default.dim(`TTL: ${formatTtl(type.defaultTtl)}`)}`);
|
|
1578
|
-
console.log(` ${chalk6__default.default.dim(" ".repeat(12) + type.description)}`);
|
|
1579
|
-
}
|
|
1580
|
-
console.log("");
|
|
1581
|
-
}
|
|
1582
|
-
console.log(chalk6__default.default.dim(`Total: ${types.length} types (${builtinTypes.length} built-in, ${customTypes.length} custom)`));
|
|
1583
|
-
} catch (error) {
|
|
1584
|
-
console.error(chalk6__default.default.red("Error:"), error.message);
|
|
1585
|
-
process.exit(1);
|
|
1586
|
-
}
|
|
1587
|
-
});
|
|
1588
|
-
return cmd;
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
// src/commands/types/show.ts
|
|
1592
|
-
init_cjs_shims();
|
|
1593
|
-
function formatTtl2(seconds) {
|
|
1594
|
-
if (seconds < 60) return `${seconds}s`;
|
|
1595
|
-
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
1596
|
-
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
1597
|
-
return `${Math.floor(seconds / 86400)}d`;
|
|
1598
|
-
}
|
|
1599
|
-
function typesShowCommand() {
|
|
1600
|
-
const cmd = new commander.Command("show");
|
|
1601
|
-
cmd.description("Show details for a specific type").argument("<name>", "Type name").option("--json", "Output as JSON").action(async (name, options) => {
|
|
1602
|
-
try {
|
|
1603
|
-
const client = await getClient();
|
|
1604
|
-
const registry = client.getTypeRegistry();
|
|
1605
|
-
const type = registry.get(name);
|
|
1606
|
-
if (!type) {
|
|
1607
|
-
console.error(chalk6__default.default.red("Error:"), `Type "${name}" not found.`);
|
|
1608
|
-
console.log(chalk6__default.default.dim('Run "fractary codex types list" to see available types.'));
|
|
1609
|
-
process.exit(1);
|
|
1610
|
-
}
|
|
1611
|
-
const isBuiltin = registry.isBuiltIn(name);
|
|
1612
|
-
if (options.json) {
|
|
1613
|
-
console.log(JSON.stringify({
|
|
1614
|
-
name: type.name,
|
|
1615
|
-
builtin: isBuiltin,
|
|
1616
|
-
description: type.description,
|
|
1617
|
-
patterns: type.patterns,
|
|
1618
|
-
defaultTtl: type.defaultTtl,
|
|
1619
|
-
ttl: formatTtl2(type.defaultTtl),
|
|
1620
|
-
archiveAfterDays: type.archiveAfterDays,
|
|
1621
|
-
archiveStorage: type.archiveStorage,
|
|
1622
|
-
syncPatterns: type.syncPatterns,
|
|
1623
|
-
excludePatterns: type.excludePatterns
|
|
1624
|
-
}, null, 2));
|
|
1625
|
-
return;
|
|
1626
|
-
}
|
|
1627
|
-
const nameColor = isBuiltin ? chalk6__default.default.cyan : chalk6__default.default.green;
|
|
1628
|
-
console.log(chalk6__default.default.bold(`Type: ${nameColor(name)}
|
|
1629
|
-
`));
|
|
1630
|
-
console.log(` ${chalk6__default.default.dim("Source:")} ${isBuiltin ? "Built-in" : "Custom"}`);
|
|
1631
|
-
console.log(` ${chalk6__default.default.dim("Description:")} ${type.description}`);
|
|
1632
|
-
console.log(` ${chalk6__default.default.dim("TTL:")} ${formatTtl2(type.defaultTtl)} (${type.defaultTtl} seconds)`);
|
|
1633
|
-
console.log("");
|
|
1634
|
-
console.log(chalk6__default.default.bold("Patterns"));
|
|
1635
|
-
for (const pattern of type.patterns) {
|
|
1636
|
-
console.log(` ${chalk6__default.default.dim("\u2022")} ${pattern}`);
|
|
1637
|
-
}
|
|
1638
|
-
if (type.archiveAfterDays !== null) {
|
|
1639
|
-
console.log("");
|
|
1640
|
-
console.log(chalk6__default.default.bold("Archive Settings"));
|
|
1641
|
-
console.log(` ${chalk6__default.default.dim("After:")} ${type.archiveAfterDays} days`);
|
|
1642
|
-
console.log(` ${chalk6__default.default.dim("Storage:")} ${type.archiveStorage || "not set"}`);
|
|
1643
|
-
}
|
|
1644
|
-
if (type.syncPatterns && type.syncPatterns.length > 0) {
|
|
1645
|
-
console.log("");
|
|
1646
|
-
console.log(chalk6__default.default.bold("Sync Patterns"));
|
|
1647
|
-
for (const pattern of type.syncPatterns) {
|
|
1648
|
-
console.log(` ${chalk6__default.default.dim("\u2022")} ${pattern}`);
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
if (type.excludePatterns && type.excludePatterns.length > 0) {
|
|
1652
|
-
console.log("");
|
|
1653
|
-
console.log(chalk6__default.default.bold("Exclude Patterns"));
|
|
1654
|
-
for (const pattern of type.excludePatterns) {
|
|
1655
|
-
console.log(` ${chalk6__default.default.dim("\u2022")} ${pattern}`);
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
} catch (error) {
|
|
1659
|
-
console.error(chalk6__default.default.red("Error:"), error.message);
|
|
1660
|
-
process.exit(1);
|
|
1661
|
-
}
|
|
1662
|
-
});
|
|
1663
|
-
return cmd;
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
// src/commands/types/add.ts
|
|
1667
|
-
init_cjs_shims();
|
|
1668
|
-
init_migrate_config();
|
|
1669
|
-
function isValidTypeName(name) {
|
|
1670
|
-
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
1671
|
-
}
|
|
1672
|
-
function parseTtl(ttl) {
|
|
1673
|
-
const match = ttl.match(/^(\d+)([smhd])$/);
|
|
1674
|
-
if (!match) {
|
|
1675
|
-
throw new Error("Invalid TTL format");
|
|
1676
|
-
}
|
|
1677
|
-
const value = parseInt(match[1], 10);
|
|
1678
|
-
const unit = match[2];
|
|
1679
|
-
switch (unit) {
|
|
1680
|
-
case "s":
|
|
1681
|
-
return value;
|
|
1682
|
-
case "m":
|
|
1683
|
-
return value * 60;
|
|
1684
|
-
case "h":
|
|
1685
|
-
return value * 3600;
|
|
1686
|
-
case "d":
|
|
1687
|
-
return value * 86400;
|
|
1688
|
-
default:
|
|
1689
|
-
throw new Error("Unknown TTL unit");
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
function formatTtl3(seconds) {
|
|
1693
|
-
if (seconds < 60) return `${seconds}s`;
|
|
1694
|
-
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
1695
|
-
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
1696
|
-
return `${Math.floor(seconds / 86400)}d`;
|
|
1697
|
-
}
|
|
1698
|
-
function typesAddCommand() {
|
|
1699
|
-
const cmd = new commander.Command("add");
|
|
1700
|
-
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) => {
|
|
1701
|
-
try {
|
|
1702
|
-
if (!isValidTypeName(name)) {
|
|
1703
|
-
console.error(chalk6__default.default.red("Error:"), "Invalid type name.");
|
|
1704
|
-
console.log(chalk6__default.default.dim("Type name must be lowercase, start with a letter, and contain only letters, numbers, and hyphens."));
|
|
1705
|
-
process.exit(1);
|
|
1706
|
-
}
|
|
1707
|
-
const client = await getClient();
|
|
1708
|
-
const registry = client.getTypeRegistry();
|
|
1709
|
-
if (registry.isBuiltIn(name)) {
|
|
1710
|
-
console.error(chalk6__default.default.red("Error:"), `Cannot override built-in type "${name}".`);
|
|
1711
|
-
const builtinNames = registry.list().filter((t) => registry.isBuiltIn(t.name)).map((t) => t.name);
|
|
1712
|
-
console.log(chalk6__default.default.dim("Built-in types: " + builtinNames.join(", ")));
|
|
1713
|
-
process.exit(1);
|
|
1714
|
-
}
|
|
1715
|
-
if (registry.has(name)) {
|
|
1716
|
-
console.error(chalk6__default.default.red("Error:"), `Custom type "${name}" already exists.`);
|
|
1717
|
-
console.log(chalk6__default.default.dim('Use "fractary codex types remove" first to remove it.'));
|
|
1718
|
-
process.exit(1);
|
|
1719
|
-
}
|
|
1720
|
-
let ttlSeconds;
|
|
1721
|
-
try {
|
|
1722
|
-
ttlSeconds = parseTtl(options.ttl);
|
|
1723
|
-
} catch {
|
|
1724
|
-
console.error(chalk6__default.default.red("Error:"), "Invalid TTL format.");
|
|
1725
|
-
console.log(chalk6__default.default.dim("Expected format: <number><unit> where unit is s (seconds), m (minutes), h (hours), or d (days)"));
|
|
1726
|
-
console.log(chalk6__default.default.dim("Examples: 30m, 24h, 7d"));
|
|
1727
|
-
process.exit(1);
|
|
1728
|
-
}
|
|
1729
|
-
const configPath = path2__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1730
|
-
const config = await readYamlConfig(configPath);
|
|
1731
|
-
if (!config.types) {
|
|
1732
|
-
config.types = { custom: {} };
|
|
1733
|
-
}
|
|
1734
|
-
if (!config.types.custom) {
|
|
1735
|
-
config.types.custom = {};
|
|
1736
|
-
}
|
|
1737
|
-
config.types.custom[name] = {
|
|
1738
|
-
description: options.description || `Custom type: ${name}`,
|
|
1739
|
-
patterns: [options.pattern],
|
|
1740
|
-
defaultTtl: ttlSeconds
|
|
1741
|
-
};
|
|
1742
|
-
await writeYamlConfig(config, configPath);
|
|
1743
|
-
if (options.json) {
|
|
1744
|
-
console.log(JSON.stringify({
|
|
1745
|
-
success: true,
|
|
1746
|
-
type: {
|
|
1747
|
-
name,
|
|
1748
|
-
description: config.types.custom[name].description,
|
|
1749
|
-
patterns: config.types.custom[name].patterns,
|
|
1750
|
-
defaultTtl: ttlSeconds,
|
|
1751
|
-
ttl: formatTtl3(ttlSeconds),
|
|
1752
|
-
builtin: false
|
|
1753
|
-
},
|
|
1754
|
-
message: "Custom type added successfully. Changes will take effect on next CLI invocation."
|
|
1755
|
-
}, null, 2));
|
|
1756
|
-
return;
|
|
1757
|
-
}
|
|
1758
|
-
console.log(chalk6__default.default.green("\u2713"), `Added custom type "${chalk6__default.default.cyan(name)}"`);
|
|
1759
|
-
console.log("");
|
|
1760
|
-
console.log(` ${chalk6__default.default.dim("Pattern:")} ${options.pattern}`);
|
|
1761
|
-
console.log(` ${chalk6__default.default.dim("TTL:")} ${formatTtl3(ttlSeconds)} (${ttlSeconds} seconds)`);
|
|
1762
|
-
if (options.description) {
|
|
1763
|
-
console.log(` ${chalk6__default.default.dim("Description:")} ${options.description}`);
|
|
1764
|
-
}
|
|
1765
|
-
console.log("");
|
|
1766
|
-
console.log(chalk6__default.default.dim("Note: Custom type will be available on next CLI invocation."));
|
|
1767
|
-
} catch (error) {
|
|
1768
|
-
console.error(chalk6__default.default.red("Error:"), error.message);
|
|
1769
|
-
if (error.message.includes("Failed to load configuration")) {
|
|
1770
|
-
console.log(chalk6__default.default.dim('\nRun "fractary codex init" to create a configuration.'));
|
|
1771
|
-
}
|
|
1772
|
-
process.exit(1);
|
|
1773
|
-
}
|
|
1774
|
-
});
|
|
1775
|
-
return cmd;
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
// src/commands/types/remove.ts
|
|
1779
|
-
init_cjs_shims();
|
|
1780
|
-
init_migrate_config();
|
|
1781
|
-
function typesRemoveCommand() {
|
|
1782
|
-
const cmd = new commander.Command("remove");
|
|
1783
|
-
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) => {
|
|
1784
|
-
try {
|
|
1785
|
-
const client = await getClient();
|
|
1786
|
-
const registry = client.getTypeRegistry();
|
|
1787
|
-
if (registry.isBuiltIn(name)) {
|
|
1788
|
-
console.error(chalk6__default.default.red("Error:"), `Cannot remove built-in type "${name}".`);
|
|
1789
|
-
console.log(chalk6__default.default.dim("Built-in types are permanent and cannot be removed."));
|
|
1790
|
-
process.exit(1);
|
|
1791
|
-
}
|
|
1792
|
-
if (!registry.has(name)) {
|
|
1793
|
-
console.error(chalk6__default.default.red("Error:"), `Custom type "${name}" not found.`);
|
|
1794
|
-
console.log(chalk6__default.default.dim('Run "fractary codex types list --custom-only" to see custom types.'));
|
|
1795
|
-
process.exit(1);
|
|
1796
|
-
}
|
|
1797
|
-
const typeInfo = registry.get(name);
|
|
1798
|
-
const configPath = path2__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1799
|
-
const config = await readYamlConfig(configPath);
|
|
1800
|
-
if (!config.types?.custom?.[name]) {
|
|
1801
|
-
console.error(chalk6__default.default.red("Error:"), `Custom type "${name}" not found in configuration.`);
|
|
1802
|
-
process.exit(1);
|
|
1803
|
-
}
|
|
1804
|
-
delete config.types.custom[name];
|
|
1805
|
-
if (Object.keys(config.types.custom).length === 0) {
|
|
1806
|
-
delete config.types.custom;
|
|
1807
|
-
}
|
|
1808
|
-
if (config.types && Object.keys(config.types).length === 0) {
|
|
1809
|
-
delete config.types;
|
|
1810
|
-
}
|
|
1811
|
-
await writeYamlConfig(config, configPath);
|
|
1812
|
-
if (options.json) {
|
|
1679
|
+
const builtinCount = types.filter((t) => registry.isBuiltIn(t.name)).length;
|
|
1680
|
+
const customCount = types.length - builtinCount;
|
|
1813
1681
|
console.log(JSON.stringify({
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1682
|
+
count: types.length,
|
|
1683
|
+
builtinCount,
|
|
1684
|
+
customCount,
|
|
1685
|
+
types: types.map((t) => ({
|
|
1686
|
+
name: t.name,
|
|
1687
|
+
description: t.description,
|
|
1688
|
+
patterns: t.patterns,
|
|
1689
|
+
defaultTtl: t.defaultTtl,
|
|
1690
|
+
ttl: formatTtl(t.defaultTtl),
|
|
1691
|
+
builtin: registry.isBuiltIn(t.name),
|
|
1692
|
+
archiveAfterDays: t.archiveAfterDays,
|
|
1693
|
+
archiveStorage: t.archiveStorage
|
|
1694
|
+
}))
|
|
1822
1695
|
}, null, 2));
|
|
1823
1696
|
return;
|
|
1824
1697
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
console.log(
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1698
|
+
if (types.length === 0) {
|
|
1699
|
+
console.log(chalk8__default.default.yellow("No types found."));
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
console.log(chalk8__default.default.bold("Artifact Types\n"));
|
|
1703
|
+
const builtinTypes = types.filter((t) => registry.isBuiltIn(t.name));
|
|
1704
|
+
const customTypes = types.filter((t) => !registry.isBuiltIn(t.name));
|
|
1705
|
+
if (builtinTypes.length > 0 && !options.customOnly) {
|
|
1706
|
+
console.log(chalk8__default.default.bold("Built-in Types"));
|
|
1707
|
+
console.log(chalk8__default.default.dim("\u2500".repeat(70)));
|
|
1708
|
+
for (const type of builtinTypes) {
|
|
1709
|
+
const patternStr = type.patterns[0] || "";
|
|
1710
|
+
console.log(` ${chalk8__default.default.cyan(type.name.padEnd(12))} ${patternStr.padEnd(30)} ${chalk8__default.default.dim(`TTL: ${formatTtl(type.defaultTtl)}`)}`);
|
|
1711
|
+
console.log(` ${chalk8__default.default.dim(" ".repeat(12) + type.description)}`);
|
|
1712
|
+
}
|
|
1713
|
+
console.log("");
|
|
1714
|
+
}
|
|
1715
|
+
if (customTypes.length > 0 && !options.builtinOnly) {
|
|
1716
|
+
console.log(chalk8__default.default.bold("Custom Types"));
|
|
1717
|
+
console.log(chalk8__default.default.dim("\u2500".repeat(70)));
|
|
1718
|
+
for (const type of customTypes) {
|
|
1719
|
+
const patternStr = type.patterns[0] || "";
|
|
1720
|
+
console.log(` ${chalk8__default.default.green(type.name.padEnd(12))} ${patternStr.padEnd(30)} ${chalk8__default.default.dim(`TTL: ${formatTtl(type.defaultTtl)}`)}`);
|
|
1721
|
+
console.log(` ${chalk8__default.default.dim(" ".repeat(12) + type.description)}`);
|
|
1722
|
+
}
|
|
1723
|
+
console.log("");
|
|
1836
1724
|
}
|
|
1725
|
+
console.log(chalk8__default.default.dim(`Total: ${types.length} types (${builtinTypes.length} built-in, ${customTypes.length} custom)`));
|
|
1726
|
+
} catch (error) {
|
|
1727
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
1837
1728
|
process.exit(1);
|
|
1838
1729
|
}
|
|
1839
1730
|
});
|
|
1840
1731
|
return cmd;
|
|
1841
1732
|
}
|
|
1842
1733
|
|
|
1843
|
-
// src/commands/types/
|
|
1844
|
-
function typesCommand() {
|
|
1845
|
-
const cmd = new commander.Command("types");
|
|
1846
|
-
cmd.description("Manage artifact type registry");
|
|
1847
|
-
cmd.addCommand(typesListCommand());
|
|
1848
|
-
cmd.addCommand(typesShowCommand());
|
|
1849
|
-
cmd.addCommand(typesAddCommand());
|
|
1850
|
-
cmd.addCommand(typesRemoveCommand());
|
|
1851
|
-
return cmd;
|
|
1852
|
-
}
|
|
1853
|
-
|
|
1854
|
-
// src/commands/health.ts
|
|
1734
|
+
// src/commands/types/show.ts
|
|
1855
1735
|
init_cjs_shims();
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
} catch {
|
|
1862
|
-
return false;
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
async function checkConfiguration() {
|
|
1866
|
-
const configPath = path2__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1867
|
-
const legacyConfigPath = path2__namespace.join(process.cwd(), ".fractary", "plugins", "codex", "config.json");
|
|
1868
|
-
try {
|
|
1869
|
-
if (!await fileExists2(configPath)) {
|
|
1870
|
-
if (await fileExists2(legacyConfigPath)) {
|
|
1871
|
-
return {
|
|
1872
|
-
name: "Configuration",
|
|
1873
|
-
status: "warn",
|
|
1874
|
-
message: "Legacy JSON configuration detected",
|
|
1875
|
-
details: 'Run "fractary codex migrate" to upgrade to YAML format'
|
|
1876
|
-
};
|
|
1877
|
-
}
|
|
1878
|
-
return {
|
|
1879
|
-
name: "Configuration",
|
|
1880
|
-
status: "fail",
|
|
1881
|
-
message: "No configuration found",
|
|
1882
|
-
details: 'Run "fractary codex init" to create configuration'
|
|
1883
|
-
};
|
|
1884
|
-
}
|
|
1885
|
-
const config = await readYamlConfig(configPath);
|
|
1886
|
-
if (!config.organization) {
|
|
1887
|
-
return {
|
|
1888
|
-
name: "Configuration",
|
|
1889
|
-
status: "warn",
|
|
1890
|
-
message: "No organization configured",
|
|
1891
|
-
details: "Organization slug is required"
|
|
1892
|
-
};
|
|
1893
|
-
}
|
|
1894
|
-
const providerCount = config.storage?.length || 0;
|
|
1895
|
-
if (providerCount === 0) {
|
|
1896
|
-
return {
|
|
1897
|
-
name: "Configuration",
|
|
1898
|
-
status: "warn",
|
|
1899
|
-
message: "No storage providers configured",
|
|
1900
|
-
details: "At least one storage provider is recommended"
|
|
1901
|
-
};
|
|
1902
|
-
}
|
|
1903
|
-
return {
|
|
1904
|
-
name: "Configuration",
|
|
1905
|
-
status: "pass",
|
|
1906
|
-
message: "Valid YAML configuration",
|
|
1907
|
-
details: `Organization: ${config.organization}, ${providerCount} storage provider(s)`
|
|
1908
|
-
};
|
|
1909
|
-
} catch (error) {
|
|
1910
|
-
return {
|
|
1911
|
-
name: "Configuration",
|
|
1912
|
-
status: "fail",
|
|
1913
|
-
message: "Invalid configuration",
|
|
1914
|
-
details: error.message
|
|
1915
|
-
};
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
async function checkSDKClient() {
|
|
1919
|
-
try {
|
|
1920
|
-
const client = await getClient();
|
|
1921
|
-
const organization = client.getOrganization();
|
|
1922
|
-
return {
|
|
1923
|
-
name: "SDK Client",
|
|
1924
|
-
status: "pass",
|
|
1925
|
-
message: "CodexClient initialized successfully",
|
|
1926
|
-
details: `Organization: ${organization}`
|
|
1927
|
-
};
|
|
1928
|
-
} catch (error) {
|
|
1929
|
-
return {
|
|
1930
|
-
name: "SDK Client",
|
|
1931
|
-
status: "fail",
|
|
1932
|
-
message: "Failed to initialize CodexClient",
|
|
1933
|
-
details: error.message
|
|
1934
|
-
};
|
|
1935
|
-
}
|
|
1936
|
-
}
|
|
1937
|
-
async function checkCache() {
|
|
1938
|
-
try {
|
|
1939
|
-
const client = await getClient();
|
|
1940
|
-
const stats = await client.getCacheStats();
|
|
1941
|
-
if (stats.entryCount === 0) {
|
|
1942
|
-
return {
|
|
1943
|
-
name: "Cache",
|
|
1944
|
-
status: "warn",
|
|
1945
|
-
message: "Cache is empty",
|
|
1946
|
-
details: "Fetch some documents to populate cache"
|
|
1947
|
-
};
|
|
1948
|
-
}
|
|
1949
|
-
const healthPercent = stats.entryCount > 0 ? stats.freshCount / stats.entryCount * 100 : 100;
|
|
1950
|
-
if (healthPercent < 50) {
|
|
1951
|
-
return {
|
|
1952
|
-
name: "Cache",
|
|
1953
|
-
status: "warn",
|
|
1954
|
-
message: `${stats.entryCount} entries (${healthPercent.toFixed(0)}% fresh)`,
|
|
1955
|
-
details: `${stats.expiredCount} expired, ${stats.staleCount} stale`
|
|
1956
|
-
};
|
|
1957
|
-
}
|
|
1958
|
-
return {
|
|
1959
|
-
name: "Cache",
|
|
1960
|
-
status: "pass",
|
|
1961
|
-
message: `${stats.entryCount} entries (${healthPercent.toFixed(0)}% fresh)`,
|
|
1962
|
-
details: `${formatSize4(stats.totalSize)} total`
|
|
1963
|
-
};
|
|
1964
|
-
} catch (error) {
|
|
1965
|
-
return {
|
|
1966
|
-
name: "Cache",
|
|
1967
|
-
status: "fail",
|
|
1968
|
-
message: "Cache check failed",
|
|
1969
|
-
details: error.message
|
|
1970
|
-
};
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
async function checkStorage() {
|
|
1974
|
-
const configPath = path2__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1975
|
-
try {
|
|
1976
|
-
const config = await readYamlConfig(configPath);
|
|
1977
|
-
const providers = config.storage || [];
|
|
1978
|
-
if (providers.length === 0) {
|
|
1979
|
-
return {
|
|
1980
|
-
name: "Storage",
|
|
1981
|
-
status: "warn",
|
|
1982
|
-
message: "No storage providers configured",
|
|
1983
|
-
details: "Configure at least one provider in .fractary/codex.yaml"
|
|
1984
|
-
};
|
|
1985
|
-
}
|
|
1986
|
-
const providerTypes = providers.map((p) => p.type).join(", ");
|
|
1987
|
-
const hasGitHub = providers.some((p) => p.type === "github");
|
|
1988
|
-
if (hasGitHub && !process.env.GITHUB_TOKEN) {
|
|
1989
|
-
return {
|
|
1990
|
-
name: "Storage",
|
|
1991
|
-
status: "warn",
|
|
1992
|
-
message: `${providers.length} provider(s): ${providerTypes}`,
|
|
1993
|
-
details: "GITHUB_TOKEN not set (required for GitHub provider)"
|
|
1994
|
-
};
|
|
1995
|
-
}
|
|
1996
|
-
return {
|
|
1997
|
-
name: "Storage",
|
|
1998
|
-
status: "pass",
|
|
1999
|
-
message: `${providers.length} provider(s): ${providerTypes}`,
|
|
2000
|
-
details: "All configured providers available"
|
|
2001
|
-
};
|
|
2002
|
-
} catch (error) {
|
|
2003
|
-
return {
|
|
2004
|
-
name: "Storage",
|
|
2005
|
-
status: "fail",
|
|
2006
|
-
message: "Storage check failed",
|
|
2007
|
-
details: error.message
|
|
2008
|
-
};
|
|
2009
|
-
}
|
|
2010
|
-
}
|
|
2011
|
-
async function checkTypes() {
|
|
2012
|
-
try {
|
|
2013
|
-
const client = await getClient();
|
|
2014
|
-
const registry = client.getTypeRegistry();
|
|
2015
|
-
const allTypes = registry.list();
|
|
2016
|
-
const builtinCount = allTypes.filter((t) => registry.isBuiltIn(t.name)).length;
|
|
2017
|
-
const customCount = allTypes.length - builtinCount;
|
|
2018
|
-
return {
|
|
2019
|
-
name: "Type Registry",
|
|
2020
|
-
status: "pass",
|
|
2021
|
-
message: `${allTypes.length} types registered`,
|
|
2022
|
-
details: `${builtinCount} built-in, ${customCount} custom`
|
|
2023
|
-
};
|
|
2024
|
-
} catch (error) {
|
|
2025
|
-
return {
|
|
2026
|
-
name: "Type Registry",
|
|
2027
|
-
status: "fail",
|
|
2028
|
-
message: "Type registry check failed",
|
|
2029
|
-
details: error.message
|
|
2030
|
-
};
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2033
|
-
function formatSize4(bytes) {
|
|
2034
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
2035
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
2036
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1736
|
+
function formatTtl2(seconds) {
|
|
1737
|
+
if (seconds < 60) return `${seconds}s`;
|
|
1738
|
+
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
1739
|
+
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
1740
|
+
return `${Math.floor(seconds / 86400)}d`;
|
|
2037
1741
|
}
|
|
2038
|
-
function
|
|
2039
|
-
const cmd = new commander.Command("
|
|
2040
|
-
cmd.description("
|
|
1742
|
+
function typesShowCommand() {
|
|
1743
|
+
const cmd = new commander.Command("show");
|
|
1744
|
+
cmd.description("Show details for a specific type").argument("<name>", "Type name").option("--json", "Output as JSON").action(async (name, options) => {
|
|
2041
1745
|
try {
|
|
2042
|
-
const
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
const
|
|
1746
|
+
const client = await getClient();
|
|
1747
|
+
const registry = client.getTypeRegistry();
|
|
1748
|
+
const type = registry.get(name);
|
|
1749
|
+
if (!type) {
|
|
1750
|
+
console.error(chalk8__default.default.red("Error:"), `Type "${name}" not found.`);
|
|
1751
|
+
console.log(chalk8__default.default.dim('Run "fractary codex types list" to see available types.'));
|
|
1752
|
+
process.exit(1);
|
|
1753
|
+
}
|
|
1754
|
+
const isBuiltin = registry.isBuiltIn(name);
|
|
2051
1755
|
if (options.json) {
|
|
2052
1756
|
console.log(JSON.stringify({
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
1757
|
+
name: type.name,
|
|
1758
|
+
builtin: isBuiltin,
|
|
1759
|
+
description: type.description,
|
|
1760
|
+
patterns: type.patterns,
|
|
1761
|
+
defaultTtl: type.defaultTtl,
|
|
1762
|
+
ttl: formatTtl2(type.defaultTtl),
|
|
1763
|
+
archiveAfterDays: type.archiveAfterDays,
|
|
1764
|
+
archiveStorage: type.archiveStorage,
|
|
1765
|
+
syncPatterns: type.syncPatterns,
|
|
1766
|
+
excludePatterns: type.excludePatterns
|
|
2061
1767
|
}, null, 2));
|
|
2062
1768
|
return;
|
|
2063
1769
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
1770
|
+
const nameColor = isBuiltin ? chalk8__default.default.cyan : chalk8__default.default.green;
|
|
1771
|
+
console.log(chalk8__default.default.bold(`Type: ${nameColor(name)}
|
|
1772
|
+
`));
|
|
1773
|
+
console.log(` ${chalk8__default.default.dim("Source:")} ${isBuiltin ? "Built-in" : "Custom"}`);
|
|
1774
|
+
console.log(` ${chalk8__default.default.dim("Description:")} ${type.description}`);
|
|
1775
|
+
console.log(` ${chalk8__default.default.dim("TTL:")} ${formatTtl2(type.defaultTtl)} (${type.defaultTtl} seconds)`);
|
|
1776
|
+
console.log("");
|
|
1777
|
+
console.log(chalk8__default.default.bold("Patterns"));
|
|
1778
|
+
for (const pattern of type.patterns) {
|
|
1779
|
+
console.log(` ${chalk8__default.default.dim("\u2022")} ${pattern}`);
|
|
1780
|
+
}
|
|
1781
|
+
if (type.archiveAfterDays !== null) {
|
|
2073
1782
|
console.log("");
|
|
1783
|
+
console.log(chalk8__default.default.bold("Archive Settings"));
|
|
1784
|
+
console.log(` ${chalk8__default.default.dim("After:")} ${type.archiveAfterDays} days`);
|
|
1785
|
+
console.log(` ${chalk8__default.default.dim("Storage:")} ${type.archiveStorage || "not set"}`);
|
|
2074
1786
|
}
|
|
2075
|
-
|
|
2076
|
-
const overallStatus = failed > 0 ? chalk6__default.default.red("UNHEALTHY") : warned > 0 ? chalk6__default.default.yellow("DEGRADED") : chalk6__default.default.green("HEALTHY");
|
|
2077
|
-
console.log(`Status: ${overallStatus}`);
|
|
2078
|
-
console.log(chalk6__default.default.dim(`${passed} passed, ${warned} warnings, ${failed} failed`));
|
|
2079
|
-
if (failed > 0 || warned > 0) {
|
|
1787
|
+
if (type.syncPatterns && type.syncPatterns.length > 0) {
|
|
2080
1788
|
console.log("");
|
|
2081
|
-
console.log(
|
|
2082
|
-
|
|
2083
|
-
|
|
1789
|
+
console.log(chalk8__default.default.bold("Sync Patterns"));
|
|
1790
|
+
for (const pattern of type.syncPatterns) {
|
|
1791
|
+
console.log(` ${chalk8__default.default.dim("\u2022")} ${pattern}`);
|
|
1792
|
+
}
|
|
2084
1793
|
}
|
|
2085
|
-
if (
|
|
2086
|
-
|
|
1794
|
+
if (type.excludePatterns && type.excludePatterns.length > 0) {
|
|
1795
|
+
console.log("");
|
|
1796
|
+
console.log(chalk8__default.default.bold("Exclude Patterns"));
|
|
1797
|
+
for (const pattern of type.excludePatterns) {
|
|
1798
|
+
console.log(` ${chalk8__default.default.dim("\u2022")} ${pattern}`);
|
|
1799
|
+
}
|
|
2087
1800
|
}
|
|
2088
1801
|
} catch (error) {
|
|
2089
|
-
console.error(
|
|
1802
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
2090
1803
|
process.exit(1);
|
|
2091
1804
|
}
|
|
2092
1805
|
});
|
|
2093
1806
|
return cmd;
|
|
2094
1807
|
}
|
|
2095
1808
|
|
|
2096
|
-
// src/commands/
|
|
1809
|
+
// src/commands/types/add.ts
|
|
2097
1810
|
init_cjs_shims();
|
|
2098
1811
|
init_migrate_config();
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
1812
|
+
function isValidTypeName(name) {
|
|
1813
|
+
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
1814
|
+
}
|
|
1815
|
+
function parseTtl(ttl) {
|
|
1816
|
+
const match = ttl.match(/^(\d+)([smhd])$/);
|
|
1817
|
+
if (!match) {
|
|
1818
|
+
throw new Error("Invalid TTL format");
|
|
1819
|
+
}
|
|
1820
|
+
const value = parseInt(match[1], 10);
|
|
1821
|
+
const unit = match[2];
|
|
1822
|
+
switch (unit) {
|
|
1823
|
+
case "s":
|
|
1824
|
+
return value;
|
|
1825
|
+
case "m":
|
|
1826
|
+
return value * 60;
|
|
1827
|
+
case "h":
|
|
1828
|
+
return value * 3600;
|
|
1829
|
+
case "d":
|
|
1830
|
+
return value * 86400;
|
|
1831
|
+
default:
|
|
1832
|
+
throw new Error("Unknown TTL unit");
|
|
2105
1833
|
}
|
|
2106
1834
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
1835
|
+
function formatTtl3(seconds) {
|
|
1836
|
+
if (seconds < 60) return `${seconds}s`;
|
|
1837
|
+
if (seconds < 3600) return `${Math.floor(seconds / 60)}m`;
|
|
1838
|
+
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
1839
|
+
return `${Math.floor(seconds / 86400)}d`;
|
|
2109
1840
|
}
|
|
2110
|
-
function
|
|
2111
|
-
const cmd = new commander.Command("
|
|
2112
|
-
cmd.description("
|
|
1841
|
+
function typesAddCommand() {
|
|
1842
|
+
const cmd = new commander.Command("add");
|
|
1843
|
+
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) => {
|
|
2113
1844
|
try {
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
console.log(JSON.stringify({
|
|
2119
|
-
status: "no_config",
|
|
2120
|
-
message: "No legacy configuration file found",
|
|
2121
|
-
path: legacyConfigPath
|
|
2122
|
-
}));
|
|
2123
|
-
} else {
|
|
2124
|
-
console.log(chalk6__default.default.yellow("\u26A0 No legacy configuration file found."));
|
|
2125
|
-
console.log(chalk6__default.default.dim(` Expected: ${legacyConfigPath}`));
|
|
2126
|
-
console.log(chalk6__default.default.dim('\nRun "fractary codex init" to create a new v3.0 YAML configuration.'));
|
|
2127
|
-
}
|
|
2128
|
-
return;
|
|
1845
|
+
if (!isValidTypeName(name)) {
|
|
1846
|
+
console.error(chalk8__default.default.red("Error:"), "Invalid type name.");
|
|
1847
|
+
console.log(chalk8__default.default.dim("Type name must be lowercase, start with a letter, and contain only letters, numbers, and hyphens."));
|
|
1848
|
+
process.exit(1);
|
|
2129
1849
|
}
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
} else {
|
|
2138
|
-
console.log(chalk6__default.default.yellow("\u26A0 YAML configuration already exists."));
|
|
2139
|
-
console.log(chalk6__default.default.dim(` Path: ${newConfigPath}`));
|
|
2140
|
-
console.log(chalk6__default.default.dim('\nUse "fractary codex init --force" to recreate.'));
|
|
2141
|
-
}
|
|
2142
|
-
return;
|
|
1850
|
+
const client = await getClient();
|
|
1851
|
+
const registry = client.getTypeRegistry();
|
|
1852
|
+
if (registry.isBuiltIn(name)) {
|
|
1853
|
+
console.error(chalk8__default.default.red("Error:"), `Cannot override built-in type "${name}".`);
|
|
1854
|
+
const builtinNames = registry.list().filter((t) => registry.isBuiltIn(t.name)).map((t) => t.name);
|
|
1855
|
+
console.log(chalk8__default.default.dim("Built-in types: " + builtinNames.join(", ")));
|
|
1856
|
+
process.exit(1);
|
|
2143
1857
|
}
|
|
2144
|
-
|
|
2145
|
-
|
|
1858
|
+
if (registry.has(name)) {
|
|
1859
|
+
console.error(chalk8__default.default.red("Error:"), `Custom type "${name}" already exists.`);
|
|
1860
|
+
console.log(chalk8__default.default.dim('Use "fractary codex types remove" first to remove it.'));
|
|
1861
|
+
process.exit(1);
|
|
1862
|
+
}
|
|
1863
|
+
let ttlSeconds;
|
|
2146
1864
|
try {
|
|
2147
|
-
|
|
1865
|
+
ttlSeconds = parseTtl(options.ttl);
|
|
2148
1866
|
} catch {
|
|
2149
|
-
console.error(
|
|
1867
|
+
console.error(chalk8__default.default.red("Error:"), "Invalid TTL format.");
|
|
1868
|
+
console.log(chalk8__default.default.dim("Expected format: <number><unit> where unit is s (seconds), m (minutes), h (hours), or d (days)"));
|
|
1869
|
+
console.log(chalk8__default.default.dim("Examples: 30m, 24h, 7d"));
|
|
2150
1870
|
process.exit(1);
|
|
2151
1871
|
}
|
|
2152
|
-
|
|
2153
|
-
|
|
1872
|
+
const configPath = path3__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1873
|
+
const config = await readYamlConfig(configPath);
|
|
1874
|
+
if (!config.types) {
|
|
1875
|
+
config.types = { custom: {} };
|
|
2154
1876
|
}
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
{
|
|
2158
|
-
createBackup: options.backup !== false,
|
|
2159
|
-
backupSuffix: (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")
|
|
2160
|
-
}
|
|
2161
|
-
);
|
|
2162
|
-
if (!options.json) {
|
|
2163
|
-
console.log(chalk6__default.default.bold("Legacy Configuration:"));
|
|
2164
|
-
console.log(chalk6__default.default.dim(` Path: ${legacyConfigPath}`));
|
|
2165
|
-
console.log(chalk6__default.default.dim(` Organization: ${legacyConfig.organization || legacyConfig.organizationSlug || "unknown"}`));
|
|
2166
|
-
console.log("");
|
|
2167
|
-
console.log(chalk6__default.default.bold("Migration Changes:"));
|
|
2168
|
-
console.log(chalk6__default.default.green(" + Format: JSON \u2192 YAML"));
|
|
2169
|
-
console.log(chalk6__default.default.green(" + Location: .fractary/plugins/codex/ \u2192 .fractary/"));
|
|
2170
|
-
console.log(chalk6__default.default.green(" + File: config.json \u2192 codex.yaml"));
|
|
2171
|
-
console.log(chalk6__default.default.green(" + Storage: Multi-provider configuration"));
|
|
2172
|
-
console.log(chalk6__default.default.green(" + Cache: Modern cache management"));
|
|
2173
|
-
console.log(chalk6__default.default.green(" + Types: Custom type registry"));
|
|
2174
|
-
if (migrationResult.warnings.length > 0) {
|
|
2175
|
-
console.log("");
|
|
2176
|
-
console.log(chalk6__default.default.yellow("Warnings:"));
|
|
2177
|
-
for (const warning of migrationResult.warnings) {
|
|
2178
|
-
console.log(chalk6__default.default.yellow(" \u26A0"), chalk6__default.default.dim(warning));
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
console.log("");
|
|
2182
|
-
if (options.dryRun) {
|
|
2183
|
-
console.log(chalk6__default.default.blue("Dry run - no changes made."));
|
|
2184
|
-
console.log(chalk6__default.default.dim("Run without --dry-run to execute migration."));
|
|
2185
|
-
return;
|
|
2186
|
-
}
|
|
1877
|
+
if (!config.types.custom) {
|
|
1878
|
+
config.types.custom = {};
|
|
2187
1879
|
}
|
|
1880
|
+
config.types.custom[name] = {
|
|
1881
|
+
description: options.description || `Custom type: ${name}`,
|
|
1882
|
+
patterns: [options.pattern],
|
|
1883
|
+
defaultTtl: ttlSeconds
|
|
1884
|
+
};
|
|
1885
|
+
await writeYamlConfig(config, configPath);
|
|
2188
1886
|
if (options.json) {
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
organization: migrationResult.yamlConfig.organization
|
|
1887
|
+
console.log(JSON.stringify({
|
|
1888
|
+
success: true,
|
|
1889
|
+
type: {
|
|
1890
|
+
name,
|
|
1891
|
+
description: config.types.custom[name].description,
|
|
1892
|
+
patterns: config.types.custom[name].patterns,
|
|
1893
|
+
defaultTtl: ttlSeconds,
|
|
1894
|
+
ttl: formatTtl3(ttlSeconds),
|
|
1895
|
+
builtin: false
|
|
2199
1896
|
},
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
console.log(JSON.stringify(output, null, 2));
|
|
2204
|
-
if (options.dryRun) {
|
|
2205
|
-
return;
|
|
2206
|
-
}
|
|
1897
|
+
message: "Custom type added successfully. Changes will take effect on next CLI invocation."
|
|
1898
|
+
}, null, 2));
|
|
1899
|
+
return;
|
|
2207
1900
|
}
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
console.log(chalk6__default.default.green("\u2713"), "Cache directory initialized");
|
|
2215
|
-
if (migrationResult.backupPath) {
|
|
2216
|
-
console.log(chalk6__default.default.green("\u2713"), "Legacy config backed up");
|
|
2217
|
-
}
|
|
2218
|
-
console.log("");
|
|
2219
|
-
console.log(chalk6__default.default.bold("New Configuration:"));
|
|
2220
|
-
console.log(chalk6__default.default.dim(` Path: ${newConfigPath}`));
|
|
2221
|
-
console.log(chalk6__default.default.dim(` Organization: ${migrationResult.yamlConfig.organization}`));
|
|
2222
|
-
console.log(chalk6__default.default.dim(` Cache: ${migrationResult.yamlConfig.cacheDir || ".codex-cache"}`));
|
|
2223
|
-
console.log(chalk6__default.default.dim(` Storage Providers: ${migrationResult.yamlConfig.storage?.length || 0}`));
|
|
2224
|
-
console.log("");
|
|
2225
|
-
console.log(chalk6__default.default.bold("Next Steps:"));
|
|
2226
|
-
console.log(chalk6__default.default.dim(" 1. Review the new configuration: .fractary/codex.yaml"));
|
|
2227
|
-
console.log(chalk6__default.default.dim(' 2. Set your GitHub token: export GITHUB_TOKEN="your_token"'));
|
|
2228
|
-
console.log(chalk6__default.default.dim(" 3. Test fetching: fractary codex fetch codex://org/project/path"));
|
|
2229
|
-
if (migrationResult.backupPath) {
|
|
2230
|
-
console.log("");
|
|
2231
|
-
console.log(chalk6__default.default.dim(`Backup saved: ${path2__namespace.basename(migrationResult.backupPath)}`));
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
1901
|
+
console.log(chalk8__default.default.green("\u2713"), `Added custom type "${chalk8__default.default.cyan(name)}"`);
|
|
1902
|
+
console.log("");
|
|
1903
|
+
console.log(` ${chalk8__default.default.dim("Pattern:")} ${options.pattern}`);
|
|
1904
|
+
console.log(` ${chalk8__default.default.dim("TTL:")} ${formatTtl3(ttlSeconds)} (${ttlSeconds} seconds)`);
|
|
1905
|
+
if (options.description) {
|
|
1906
|
+
console.log(` ${chalk8__default.default.dim("Description:")} ${options.description}`);
|
|
2234
1907
|
}
|
|
1908
|
+
console.log("");
|
|
1909
|
+
console.log(chalk8__default.default.dim("Note: Custom type will be available on next CLI invocation."));
|
|
2235
1910
|
} catch (error) {
|
|
1911
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
1912
|
+
if (error.message.includes("Failed to load configuration")) {
|
|
1913
|
+
console.log(chalk8__default.default.dim('\nRun "fractary codex init" to create a configuration.'));
|
|
1914
|
+
}
|
|
1915
|
+
process.exit(1);
|
|
1916
|
+
}
|
|
1917
|
+
});
|
|
1918
|
+
return cmd;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
// src/commands/types/remove.ts
|
|
1922
|
+
init_cjs_shims();
|
|
1923
|
+
init_migrate_config();
|
|
1924
|
+
function typesRemoveCommand() {
|
|
1925
|
+
const cmd = new commander.Command("remove");
|
|
1926
|
+
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) => {
|
|
1927
|
+
try {
|
|
1928
|
+
const client = await getClient();
|
|
1929
|
+
const registry = client.getTypeRegistry();
|
|
1930
|
+
if (registry.isBuiltIn(name)) {
|
|
1931
|
+
console.error(chalk8__default.default.red("Error:"), `Cannot remove built-in type "${name}".`);
|
|
1932
|
+
console.log(chalk8__default.default.dim("Built-in types are permanent and cannot be removed."));
|
|
1933
|
+
process.exit(1);
|
|
1934
|
+
}
|
|
1935
|
+
if (!registry.has(name)) {
|
|
1936
|
+
console.error(chalk8__default.default.red("Error:"), `Custom type "${name}" not found.`);
|
|
1937
|
+
console.log(chalk8__default.default.dim('Run "fractary codex types list --custom-only" to see custom types.'));
|
|
1938
|
+
process.exit(1);
|
|
1939
|
+
}
|
|
1940
|
+
const typeInfo = registry.get(name);
|
|
1941
|
+
const configPath = path3__namespace.join(process.cwd(), ".fractary", "codex.yaml");
|
|
1942
|
+
const config = await readYamlConfig(configPath);
|
|
1943
|
+
if (!config.types?.custom?.[name]) {
|
|
1944
|
+
console.error(chalk8__default.default.red("Error:"), `Custom type "${name}" not found in configuration.`);
|
|
1945
|
+
process.exit(1);
|
|
1946
|
+
}
|
|
1947
|
+
delete config.types.custom[name];
|
|
1948
|
+
if (Object.keys(config.types.custom).length === 0) {
|
|
1949
|
+
delete config.types.custom;
|
|
1950
|
+
}
|
|
1951
|
+
if (config.types && Object.keys(config.types).length === 0) {
|
|
1952
|
+
delete config.types;
|
|
1953
|
+
}
|
|
1954
|
+
await writeYamlConfig(config, configPath);
|
|
2236
1955
|
if (options.json) {
|
|
2237
1956
|
console.log(JSON.stringify({
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
1957
|
+
success: true,
|
|
1958
|
+
removed: {
|
|
1959
|
+
name: typeInfo.name,
|
|
1960
|
+
description: typeInfo.description,
|
|
1961
|
+
patterns: typeInfo.patterns,
|
|
1962
|
+
defaultTtl: typeInfo.defaultTtl
|
|
1963
|
+
},
|
|
1964
|
+
message: "Custom type removed successfully. Changes will take effect on next CLI invocation."
|
|
1965
|
+
}, null, 2));
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
console.log(chalk8__default.default.green("\u2713"), `Removed custom type "${chalk8__default.default.cyan(name)}"`);
|
|
1969
|
+
console.log("");
|
|
1970
|
+
console.log(chalk8__default.default.dim("Removed configuration:"));
|
|
1971
|
+
console.log(` ${chalk8__default.default.dim("Pattern:")} ${typeInfo.patterns.join(", ")}`);
|
|
1972
|
+
console.log(` ${chalk8__default.default.dim("Description:")} ${typeInfo.description}`);
|
|
1973
|
+
console.log("");
|
|
1974
|
+
console.log(chalk8__default.default.dim("Note: Custom type will be removed on next CLI invocation."));
|
|
1975
|
+
} catch (error) {
|
|
1976
|
+
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
1977
|
+
if (error.message.includes("Failed to load configuration")) {
|
|
1978
|
+
console.log(chalk8__default.default.dim('\nRun "fractary codex init" to create a configuration.'));
|
|
2243
1979
|
}
|
|
2244
1980
|
process.exit(1);
|
|
2245
1981
|
}
|
|
@@ -2247,17 +1983,26 @@ function migrateCommand() {
|
|
|
2247
1983
|
return cmd;
|
|
2248
1984
|
}
|
|
2249
1985
|
|
|
1986
|
+
// src/commands/types/index.ts
|
|
1987
|
+
function typesCommand() {
|
|
1988
|
+
const cmd = new commander.Command("types");
|
|
1989
|
+
cmd.description("Manage artifact type registry");
|
|
1990
|
+
cmd.addCommand(typesListCommand());
|
|
1991
|
+
cmd.addCommand(typesShowCommand());
|
|
1992
|
+
cmd.addCommand(typesAddCommand());
|
|
1993
|
+
cmd.addCommand(typesRemoveCommand());
|
|
1994
|
+
return cmd;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
2250
1997
|
// src/cli.ts
|
|
2251
1998
|
function createCLI() {
|
|
2252
1999
|
const program = new commander.Command("fractary-codex");
|
|
2253
|
-
program.description("Centralized knowledge management and distribution for AI agents").version("0.
|
|
2254
|
-
program.addCommand(
|
|
2255
|
-
program.addCommand(
|
|
2000
|
+
program.description("Centralized knowledge management and distribution for AI agents").version("0.3.0");
|
|
2001
|
+
program.addCommand(documentCommand());
|
|
2002
|
+
program.addCommand(configCommand());
|
|
2256
2003
|
program.addCommand(cacheCommand());
|
|
2257
2004
|
program.addCommand(syncCommand());
|
|
2258
2005
|
program.addCommand(typesCommand());
|
|
2259
|
-
program.addCommand(healthCommand());
|
|
2260
|
-
program.addCommand(migrateCommand());
|
|
2261
2006
|
return program;
|
|
2262
2007
|
}
|
|
2263
2008
|
async function main() {
|