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