@fractary/codex-cli 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -13
- package/dist/cli.cjs +268 -31
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +267 -31
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ Options:
|
|
|
42
42
|
**Example:**
|
|
43
43
|
```bash
|
|
44
44
|
fractary-codex init
|
|
45
|
-
# Creates .fractary/codex.yaml and .codex
|
|
45
|
+
# Creates .fractary/codex/config.yaml and .fractary/codex/cache/
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### `fetch` - Fetch Documents
|
|
@@ -153,6 +153,41 @@ Options:
|
|
|
153
153
|
--parallel <n> Number of parallel sync operations (default: 3)
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
**Routing-Aware Sync (v4.1+):**
|
|
157
|
+
|
|
158
|
+
When using `--from-codex` direction, the sync command uses **routing-aware file discovery** to find all files across the entire codex that should sync to your project based on `codex_sync_include` frontmatter patterns.
|
|
159
|
+
|
|
160
|
+
How it works:
|
|
161
|
+
1. Clones the entire codex repository to a temporary directory (`/tmp/fractary-codex-clone/`)
|
|
162
|
+
2. Scans ALL markdown files in the codex recursively
|
|
163
|
+
3. Evaluates `codex_sync_include` patterns in each file's frontmatter
|
|
164
|
+
4. Returns only files that match your project name or pattern
|
|
165
|
+
|
|
166
|
+
**Example frontmatter in source files:**
|
|
167
|
+
```yaml
|
|
168
|
+
---
|
|
169
|
+
codex_sync_include: ['*'] # Syncs to ALL projects
|
|
170
|
+
codex_sync_include: ['lake-*', 'api-*'] # Syncs to lake-* and api-* projects
|
|
171
|
+
codex_sync_exclude: ['*-test'] # Except *-test projects
|
|
172
|
+
---
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Trade-offs:**
|
|
176
|
+
- **Efficient for discovery**: Finds all relevant files across hundreds of projects
|
|
177
|
+
- **Inefficient for execution**: Clones entire codex repository (uses shallow clone for speed)
|
|
178
|
+
- **Best practice**: Use `codex://` URI references + cache purging for most workflows; use sync occasionally when needed
|
|
179
|
+
|
|
180
|
+
**Recommended workflow:**
|
|
181
|
+
```bash
|
|
182
|
+
# Primary: Reference files via codex:// URIs (no sync needed)
|
|
183
|
+
fractary-codex fetch codex://org/project/path/file.md
|
|
184
|
+
|
|
185
|
+
# When you need latest versions: Purge cache
|
|
186
|
+
fractary-codex cache clear --pattern "codex://org/project/*"
|
|
187
|
+
|
|
188
|
+
# Then MCP will re-fetch fresh content automatically
|
|
189
|
+
```
|
|
190
|
+
|
|
156
191
|
### `types` - Type Registry Management
|
|
157
192
|
|
|
158
193
|
Manage custom artifact types for classification and caching.
|
|
@@ -234,11 +269,11 @@ Options:
|
|
|
234
269
|
|
|
235
270
|
## Configuration
|
|
236
271
|
|
|
237
|
-
Codex uses `.fractary/codex.yaml` for configuration:
|
|
272
|
+
Codex uses `.fractary/codex/config.yaml` for configuration:
|
|
238
273
|
|
|
239
274
|
```yaml
|
|
240
275
|
organization: myorg
|
|
241
|
-
cacheDir: .codex
|
|
276
|
+
cacheDir: .fractary/codex/cache
|
|
242
277
|
|
|
243
278
|
storage:
|
|
244
279
|
- type: github
|
|
@@ -328,16 +363,6 @@ All commands use lazy-loading to avoid SDK initialization overhead for simple op
|
|
|
328
363
|
|
|
329
364
|
MIT
|
|
330
365
|
|
|
331
|
-
## Documentation
|
|
332
|
-
|
|
333
|
-
- [Command Reference](../docs/guides/command-reference.md) - Complete command reference for all interfaces
|
|
334
|
-
- [API Reference](../docs/guides/api-reference.md) - Complete API documentation
|
|
335
|
-
- [CLI Integration Guide](../docs/guides/cli-integration.md) - How to integrate into CLI applications
|
|
336
|
-
- [Configuration Guide](../docs/guides/configuration.md) - Configuration reference
|
|
337
|
-
- [Naming Conventions](../docs/guides/naming-conventions.md) - Naming standards across all interfaces
|
|
338
|
-
- [MCP Migration Guide](../docs/guides/mcp-migration-guide.md) - Migrating to new MCP tool names
|
|
339
|
-
- [Troubleshooting](../docs/guides/troubleshooting.md) - Common issues and solutions
|
|
340
|
-
|
|
341
366
|
## Links
|
|
342
367
|
|
|
343
368
|
- [GitHub Repository](https://github.com/fractary/codex)
|
package/dist/cli.cjs
CHANGED
|
@@ -5,6 +5,8 @@ var fs = require('fs/promises');
|
|
|
5
5
|
var path3 = require('path');
|
|
6
6
|
var yaml = require('js-yaml');
|
|
7
7
|
var codex = require('@fractary/codex');
|
|
8
|
+
var os = require('os');
|
|
9
|
+
var child_process = require('child_process');
|
|
8
10
|
var commander = require('commander');
|
|
9
11
|
var chalk8 = require('chalk');
|
|
10
12
|
var crypto = require('crypto');
|
|
@@ -32,6 +34,7 @@ function _interopNamespace(e) {
|
|
|
32
34
|
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
33
35
|
var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
|
|
34
36
|
var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
|
|
37
|
+
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
35
38
|
var chalk8__default = /*#__PURE__*/_interopDefault(chalk8);
|
|
36
39
|
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
37
40
|
|
|
@@ -90,7 +93,7 @@ async function migrateConfig(legacyConfigPath, options) {
|
|
|
90
93
|
organization: legacy.organization || legacy.organizationSlug || "default"
|
|
91
94
|
};
|
|
92
95
|
if (legacy.cache) {
|
|
93
|
-
yamlConfig.cacheDir = legacy.cache.directory || ".codex
|
|
96
|
+
yamlConfig.cacheDir = legacy.cache.directory || ".fractary/codex/cache";
|
|
94
97
|
}
|
|
95
98
|
if (legacy.storage?.providers) {
|
|
96
99
|
yamlConfig.storage = [];
|
|
@@ -199,7 +202,7 @@ async function writeYamlConfig(config, outputPath) {
|
|
|
199
202
|
function getDefaultYamlConfig(organization) {
|
|
200
203
|
return {
|
|
201
204
|
organization,
|
|
202
|
-
cacheDir: ".codex
|
|
205
|
+
cacheDir: ".fractary/codex/cache",
|
|
203
206
|
storage: [
|
|
204
207
|
{
|
|
205
208
|
type: "local",
|
|
@@ -619,6 +622,178 @@ var init_codex_client = __esm({
|
|
|
619
622
|
}
|
|
620
623
|
});
|
|
621
624
|
|
|
625
|
+
// src/utils/codex-repository.ts
|
|
626
|
+
var codex_repository_exports = {};
|
|
627
|
+
__export(codex_repository_exports, {
|
|
628
|
+
ensureCodexCloned: () => ensureCodexCloned,
|
|
629
|
+
getCodexRepoUrl: () => getCodexRepoUrl,
|
|
630
|
+
getTempCodexPath: () => getTempCodexPath,
|
|
631
|
+
isValidGitRepo: () => isValidGitRepo
|
|
632
|
+
});
|
|
633
|
+
function spawnAsync(command, args, options) {
|
|
634
|
+
return new Promise((resolve, reject) => {
|
|
635
|
+
const child = child_process.spawn(command, args, {
|
|
636
|
+
...options,
|
|
637
|
+
env: process.env
|
|
638
|
+
});
|
|
639
|
+
let stdout = "";
|
|
640
|
+
let stderr = "";
|
|
641
|
+
child.stdout.on("data", (data) => {
|
|
642
|
+
stdout += data.toString();
|
|
643
|
+
});
|
|
644
|
+
child.stderr.on("data", (data) => {
|
|
645
|
+
stderr += data.toString();
|
|
646
|
+
});
|
|
647
|
+
child.on("error", (error) => {
|
|
648
|
+
reject(error);
|
|
649
|
+
});
|
|
650
|
+
child.on("close", (code) => {
|
|
651
|
+
if (code !== 0) {
|
|
652
|
+
const error = new Error(stderr || `Command exited with code ${code}`);
|
|
653
|
+
error.code = code;
|
|
654
|
+
reject(error);
|
|
655
|
+
} else {
|
|
656
|
+
resolve(stdout);
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
function sanitizePathComponent(component) {
|
|
662
|
+
if (!component || typeof component !== "string") {
|
|
663
|
+
throw new Error("Path component must be a non-empty string");
|
|
664
|
+
}
|
|
665
|
+
const sanitized = component.replace(/\.\./g, "").replace(/[/\\]/g, "").trim();
|
|
666
|
+
if (!sanitized) {
|
|
667
|
+
throw new Error(`Invalid path component: ${component}`);
|
|
668
|
+
}
|
|
669
|
+
return sanitized;
|
|
670
|
+
}
|
|
671
|
+
function validateGitHubName(name, type) {
|
|
672
|
+
if (!name || typeof name !== "string") {
|
|
673
|
+
throw new Error(`GitHub ${type} name must be a non-empty string`);
|
|
674
|
+
}
|
|
675
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(name)) {
|
|
676
|
+
throw new Error(`Invalid GitHub ${type} name: ${name}. Must contain only alphanumeric characters, hyphens, underscores, and dots.`);
|
|
677
|
+
}
|
|
678
|
+
if (name.startsWith(".") || name.startsWith("-")) {
|
|
679
|
+
throw new Error(`GitHub ${type} name cannot start with a dot or hyphen: ${name}`);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
function getTempCodexPath(config) {
|
|
683
|
+
const codexRepo = config.codex_repository || "codex";
|
|
684
|
+
const sanitizedOrg = sanitizePathComponent(config.organization);
|
|
685
|
+
const sanitizedRepo = sanitizePathComponent(codexRepo);
|
|
686
|
+
return path3__namespace.join(
|
|
687
|
+
os__namespace.tmpdir(),
|
|
688
|
+
"fractary-codex-clone",
|
|
689
|
+
`${sanitizedOrg}-${sanitizedRepo}-${process.pid}`
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
async function isValidGitRepo(repoPath) {
|
|
693
|
+
try {
|
|
694
|
+
const gitDir = path3__namespace.join(repoPath, ".git");
|
|
695
|
+
const stats = await fs__namespace.stat(gitDir);
|
|
696
|
+
return stats.isDirectory();
|
|
697
|
+
} catch {
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
function getCodexRepoUrl(config) {
|
|
702
|
+
const codexRepo = config.codex_repository || "codex";
|
|
703
|
+
validateGitHubName(config.organization, "organization");
|
|
704
|
+
validateGitHubName(codexRepo, "repository");
|
|
705
|
+
return `https://github.com/${config.organization}/${codexRepo}.git`;
|
|
706
|
+
}
|
|
707
|
+
async function execGit(repoPath, args) {
|
|
708
|
+
try {
|
|
709
|
+
const stdout = await spawnAsync("git", args, {
|
|
710
|
+
cwd: repoPath
|
|
711
|
+
});
|
|
712
|
+
return stdout;
|
|
713
|
+
} catch (error) {
|
|
714
|
+
if (error.code === "ENOENT") {
|
|
715
|
+
throw new Error(`Git command not found. Ensure git is installed and in PATH.`);
|
|
716
|
+
}
|
|
717
|
+
if (error.code === "EACCES") {
|
|
718
|
+
throw new Error(`Permission denied accessing repository at ${repoPath}`);
|
|
719
|
+
}
|
|
720
|
+
if (error.code === 128) {
|
|
721
|
+
throw new Error(`Git authentication failed. Check your credentials and repository access.`);
|
|
722
|
+
}
|
|
723
|
+
throw error;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
async function gitClone(url, targetPath, options) {
|
|
727
|
+
const parentDir = path3__namespace.dirname(targetPath);
|
|
728
|
+
await fs__namespace.mkdir(parentDir, { recursive: true });
|
|
729
|
+
const args = ["clone"];
|
|
730
|
+
if (options?.depth) {
|
|
731
|
+
if (!Number.isInteger(options.depth) || options.depth <= 0) {
|
|
732
|
+
throw new Error(`Invalid depth parameter: ${options.depth}. Must be a positive integer.`);
|
|
733
|
+
}
|
|
734
|
+
args.push("--depth", String(options.depth));
|
|
735
|
+
}
|
|
736
|
+
if (options?.branch) {
|
|
737
|
+
if (!/^[\w\-./]+$/.test(options.branch)) {
|
|
738
|
+
throw new Error(`Invalid branch name: ${options.branch}`);
|
|
739
|
+
}
|
|
740
|
+
args.push("--branch", options.branch);
|
|
741
|
+
}
|
|
742
|
+
args.push("--single-branch");
|
|
743
|
+
args.push(url, targetPath);
|
|
744
|
+
await spawnAsync("git", args, { cwd: parentDir });
|
|
745
|
+
}
|
|
746
|
+
async function gitFetch(repoPath, branch) {
|
|
747
|
+
{
|
|
748
|
+
if (!/^[\w\-./]+$/.test(branch)) {
|
|
749
|
+
throw new Error(`Invalid branch name: ${branch}`);
|
|
750
|
+
}
|
|
751
|
+
await execGit(repoPath, ["fetch", "origin", `${branch}:${branch}`]);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
async function gitCheckout(repoPath, branch) {
|
|
755
|
+
if (!/^[\w\-./]+$/.test(branch)) {
|
|
756
|
+
throw new Error(`Invalid branch name: ${branch}`);
|
|
757
|
+
}
|
|
758
|
+
await execGit(repoPath, ["checkout", branch]);
|
|
759
|
+
}
|
|
760
|
+
async function gitPull(repoPath) {
|
|
761
|
+
await execGit(repoPath, ["pull"]);
|
|
762
|
+
}
|
|
763
|
+
async function ensureCodexCloned(config, options) {
|
|
764
|
+
const tempPath = getTempCodexPath(config);
|
|
765
|
+
const branch = options?.branch || "main";
|
|
766
|
+
if (await isValidGitRepo(tempPath) && !options?.force) {
|
|
767
|
+
try {
|
|
768
|
+
await gitFetch(tempPath, branch);
|
|
769
|
+
await gitCheckout(tempPath, branch);
|
|
770
|
+
await gitPull(tempPath);
|
|
771
|
+
return tempPath;
|
|
772
|
+
} catch (error) {
|
|
773
|
+
console.warn(`Failed to update existing clone: ${error.message}`);
|
|
774
|
+
console.warn(`Removing and cloning fresh...`);
|
|
775
|
+
await fs__namespace.rm(tempPath, { recursive: true, force: true });
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
const repoUrl = getCodexRepoUrl(config);
|
|
779
|
+
try {
|
|
780
|
+
await fs__namespace.rm(tempPath, { recursive: true, force: true });
|
|
781
|
+
} catch (error) {
|
|
782
|
+
console.warn(`Could not remove existing directory ${tempPath}: ${error.message}`);
|
|
783
|
+
}
|
|
784
|
+
await gitClone(repoUrl, tempPath, {
|
|
785
|
+
branch,
|
|
786
|
+
depth: 1
|
|
787
|
+
// Shallow clone for efficiency
|
|
788
|
+
});
|
|
789
|
+
return tempPath;
|
|
790
|
+
}
|
|
791
|
+
var init_codex_repository = __esm({
|
|
792
|
+
"src/utils/codex-repository.ts"() {
|
|
793
|
+
init_cjs_shims();
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
|
|
622
797
|
// src/cli.ts
|
|
623
798
|
init_cjs_shims();
|
|
624
799
|
|
|
@@ -767,24 +942,18 @@ function initCommand() {
|
|
|
767
942
|
console.log(chalk8__default.default.dim(`Organization: ${chalk8__default.default.cyan(org)}
|
|
768
943
|
`));
|
|
769
944
|
}
|
|
770
|
-
const configDir = path3__namespace.join(process.cwd(), ".fractary");
|
|
771
|
-
const configPath = path3__namespace.join(configDir, "
|
|
945
|
+
const configDir = path3__namespace.join(process.cwd(), ".fractary", "codex");
|
|
946
|
+
const configPath = path3__namespace.join(configDir, "config.yaml");
|
|
772
947
|
const configExists = await fileExists(configPath);
|
|
773
|
-
const legacyConfigPath = path3__namespace.join(process.cwd(), ".fractary", "plugins", "codex", "config.json");
|
|
774
|
-
const legacyExists = await fileExists(legacyConfigPath);
|
|
775
948
|
if (configExists && !options.force) {
|
|
776
|
-
console.log(chalk8__default.default.yellow("\u26A0 Configuration already exists at .fractary/codex.yaml"));
|
|
949
|
+
console.log(chalk8__default.default.yellow("\u26A0 Configuration already exists at .fractary/codex/config.yaml"));
|
|
777
950
|
console.log(chalk8__default.default.dim("Use --force to overwrite"));
|
|
778
951
|
process.exit(1);
|
|
779
952
|
}
|
|
780
|
-
if (legacyExists && !configExists) {
|
|
781
|
-
console.log(chalk8__default.default.yellow("\u26A0 Legacy configuration detected at .fractary/plugins/codex/config.json"));
|
|
782
|
-
console.log(chalk8__default.default.dim('Run "fractary codex migrate" to upgrade to YAML format\n'));
|
|
783
|
-
}
|
|
784
953
|
console.log("Creating directory structure...");
|
|
785
954
|
const dirs = [
|
|
786
|
-
".fractary",
|
|
787
|
-
".codex
|
|
955
|
+
".fractary/codex",
|
|
956
|
+
".fractary/codex/cache"
|
|
788
957
|
];
|
|
789
958
|
for (const dir of dirs) {
|
|
790
959
|
await fs__namespace.mkdir(path3__namespace.join(process.cwd(), dir), { recursive: true });
|
|
@@ -796,12 +965,12 @@ function initCommand() {
|
|
|
796
965
|
config.mcp.enabled = true;
|
|
797
966
|
}
|
|
798
967
|
await writeYamlConfig(config, configPath);
|
|
799
|
-
console.log(chalk8__default.default.green("\u2713"), chalk8__default.default.dim(".fractary/codex.yaml"));
|
|
800
|
-
console.log(chalk8__default.default.green("\n\u2713 Codex
|
|
968
|
+
console.log(chalk8__default.default.green("\u2713"), chalk8__default.default.dim(".fractary/codex/config.yaml"));
|
|
969
|
+
console.log(chalk8__default.default.green("\n\u2713 Codex v4.0 initialized successfully!\n"));
|
|
801
970
|
console.log(chalk8__default.default.bold("Configuration:"));
|
|
802
971
|
console.log(chalk8__default.default.dim(` Organization: ${org}`));
|
|
803
|
-
console.log(chalk8__default.default.dim(` Cache: .codex
|
|
804
|
-
console.log(chalk8__default.default.dim(` Config: .fractary/codex.yaml`));
|
|
972
|
+
console.log(chalk8__default.default.dim(` Cache: .fractary/codex/cache/`));
|
|
973
|
+
console.log(chalk8__default.default.dim(` Config: .fractary/codex/config.yaml`));
|
|
805
974
|
if (options.mcp) {
|
|
806
975
|
console.log(chalk8__default.default.dim(` MCP Server: Enabled (port 3000)`));
|
|
807
976
|
}
|
|
@@ -811,13 +980,9 @@ function initCommand() {
|
|
|
811
980
|
console.log(chalk8__default.default.dim(" - HTTP endpoint"));
|
|
812
981
|
console.log(chalk8__default.default.bold("\nNext steps:"));
|
|
813
982
|
console.log(chalk8__default.default.dim(' 1. Set your GitHub token: export GITHUB_TOKEN="your_token"'));
|
|
814
|
-
console.log(chalk8__default.default.dim(" 2. Edit .fractary/codex.yaml to configure storage providers"));
|
|
983
|
+
console.log(chalk8__default.default.dim(" 2. Edit .fractary/codex/config.yaml to configure storage providers"));
|
|
815
984
|
console.log(chalk8__default.default.dim(" 3. Fetch a document: fractary codex fetch codex://org/project/path"));
|
|
816
985
|
console.log(chalk8__default.default.dim(" 4. Check cache: fractary codex cache list"));
|
|
817
|
-
if (legacyExists) {
|
|
818
|
-
console.log(chalk8__default.default.yellow("\n\u26A0 Legacy config detected:"));
|
|
819
|
-
console.log(chalk8__default.default.dim(' Run "fractary codex migrate" to convert your existing config'));
|
|
820
|
-
}
|
|
821
986
|
} catch (error) {
|
|
822
987
|
console.error(chalk8__default.default.red("Error:"), error.message);
|
|
823
988
|
process.exit(1);
|
|
@@ -1450,7 +1615,7 @@ function syncCommand() {
|
|
|
1450
1615
|
let projectName = name;
|
|
1451
1616
|
if (!projectName) {
|
|
1452
1617
|
const detected = detectCurrentProject();
|
|
1453
|
-
projectName = detected.project ||
|
|
1618
|
+
projectName = detected.project || void 0;
|
|
1454
1619
|
}
|
|
1455
1620
|
if (!projectName) {
|
|
1456
1621
|
console.error(chalk8__default.default.red("Error:"), "Could not determine project name.");
|
|
@@ -1473,7 +1638,7 @@ function syncCommand() {
|
|
|
1473
1638
|
config: config.sync,
|
|
1474
1639
|
manifestPath: path3__namespace.join(process.cwd(), ".fractary", ".codex-sync-manifest.json")
|
|
1475
1640
|
});
|
|
1476
|
-
const defaultPatterns =
|
|
1641
|
+
const defaultPatterns = [
|
|
1477
1642
|
"docs/**/*.md",
|
|
1478
1643
|
"specs/**/*.md",
|
|
1479
1644
|
".fractary/standards/**",
|
|
@@ -1508,13 +1673,71 @@ function syncCommand() {
|
|
|
1508
1673
|
include: includePatterns,
|
|
1509
1674
|
exclude: excludePatterns
|
|
1510
1675
|
};
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1676
|
+
let plan;
|
|
1677
|
+
let routingScan;
|
|
1678
|
+
if (direction === "from-codex") {
|
|
1679
|
+
let codexRepoPath;
|
|
1680
|
+
try {
|
|
1681
|
+
const { ensureCodexCloned: ensureCodexCloned2 } = await Promise.resolve().then(() => (init_codex_repository(), codex_repository_exports));
|
|
1682
|
+
if (!options.json) {
|
|
1683
|
+
console.log(chalk8__default.default.blue("\u2139 Cloning/updating codex repository..."));
|
|
1684
|
+
}
|
|
1685
|
+
codexRepoPath = await ensureCodexCloned2(config, {
|
|
1686
|
+
branch: targetBranch
|
|
1687
|
+
});
|
|
1688
|
+
if (!options.json) {
|
|
1689
|
+
console.log(chalk8__default.default.dim(` Codex cloned to: ${codexRepoPath}`));
|
|
1690
|
+
console.log(chalk8__default.default.dim(" Scanning for files routing to this project...\n"));
|
|
1691
|
+
} else {
|
|
1692
|
+
console.log(JSON.stringify({
|
|
1693
|
+
info: "Routing-aware sync: cloned codex repository and scanning for files targeting this project",
|
|
1694
|
+
codexPath: codexRepoPath
|
|
1695
|
+
}, null, 2));
|
|
1696
|
+
}
|
|
1697
|
+
} catch (error) {
|
|
1698
|
+
console.error(chalk8__default.default.red("Error:"), "Failed to clone codex repository");
|
|
1699
|
+
console.error(chalk8__default.default.dim(` ${error.message}`));
|
|
1700
|
+
console.log(chalk8__default.default.yellow("\nTroubleshooting:"));
|
|
1701
|
+
if (error.message.includes("Git command not found")) {
|
|
1702
|
+
console.log(chalk8__default.default.dim(" Git is not installed or not in PATH."));
|
|
1703
|
+
console.log(chalk8__default.default.dim(" Install git: https://git-scm.com/downloads"));
|
|
1704
|
+
} else if (error.message.includes("authentication failed") || error.message.includes("Authentication failed")) {
|
|
1705
|
+
console.log(chalk8__default.default.dim(" GitHub authentication is required for private repositories."));
|
|
1706
|
+
console.log(chalk8__default.default.dim(" 1. Check auth status: gh auth status"));
|
|
1707
|
+
console.log(chalk8__default.default.dim(" 2. Login if needed: gh auth login"));
|
|
1708
|
+
console.log(chalk8__default.default.dim(" 3. Or set GITHUB_TOKEN environment variable"));
|
|
1709
|
+
} else if (error.message.includes("Permission denied")) {
|
|
1710
|
+
console.log(chalk8__default.default.dim(" Permission denied accessing repository files."));
|
|
1711
|
+
console.log(chalk8__default.default.dim(" 1. Check file/directory permissions"));
|
|
1712
|
+
console.log(chalk8__default.default.dim(" 2. Ensure you have access to the repository"));
|
|
1713
|
+
} else if (error.message.includes("not found") || error.message.includes("does not exist")) {
|
|
1714
|
+
console.log(chalk8__default.default.dim(` Repository not found: ${config.organization}/${config.codex_repository || "codex"}`));
|
|
1715
|
+
console.log(chalk8__default.default.dim(" 1. Verify the repository exists on GitHub"));
|
|
1716
|
+
console.log(chalk8__default.default.dim(" 2. Check organization and repository names in config"));
|
|
1717
|
+
} else {
|
|
1718
|
+
console.log(chalk8__default.default.dim(" 1. Ensure git is installed: git --version"));
|
|
1719
|
+
console.log(chalk8__default.default.dim(" 2. Check GitHub auth: gh auth status"));
|
|
1720
|
+
console.log(chalk8__default.default.dim(` 3. Verify repo exists: ${config.organization}/${config.codex_repository || "codex"}`));
|
|
1721
|
+
}
|
|
1722
|
+
process.exit(1);
|
|
1723
|
+
}
|
|
1724
|
+
const planWithRouting = await syncManager.createRoutingAwarePlan(
|
|
1725
|
+
config.organization,
|
|
1726
|
+
projectName,
|
|
1727
|
+
codexRepoPath,
|
|
1728
|
+
syncOptions
|
|
1729
|
+
);
|
|
1730
|
+
plan = planWithRouting;
|
|
1731
|
+
routingScan = planWithRouting.routingScan;
|
|
1732
|
+
} else {
|
|
1733
|
+
plan = await syncManager.createPlan(
|
|
1734
|
+
config.organization,
|
|
1735
|
+
projectName,
|
|
1736
|
+
sourceDir,
|
|
1737
|
+
targetFiles,
|
|
1738
|
+
syncOptions
|
|
1739
|
+
);
|
|
1740
|
+
}
|
|
1518
1741
|
if (plan.totalFiles === 0) {
|
|
1519
1742
|
if (options.json) {
|
|
1520
1743
|
console.log(JSON.stringify({
|
|
@@ -1577,6 +1800,20 @@ function syncCommand() {
|
|
|
1577
1800
|
if (plan.estimatedTime) {
|
|
1578
1801
|
console.log(` Est. time: ${chalk8__default.default.dim(formatDuration(plan.estimatedTime))}`);
|
|
1579
1802
|
}
|
|
1803
|
+
if (routingScan) {
|
|
1804
|
+
console.log("");
|
|
1805
|
+
console.log(chalk8__default.default.bold("Routing Statistics\n"));
|
|
1806
|
+
console.log(` Scanned: ${chalk8__default.default.cyan(routingScan.stats.totalScanned.toString())} files`);
|
|
1807
|
+
console.log(` Matched: ${chalk8__default.default.cyan(routingScan.stats.totalMatched.toString())} files`);
|
|
1808
|
+
console.log(` Source projects: ${chalk8__default.default.cyan(routingScan.stats.sourceProjects.length.toString())}`);
|
|
1809
|
+
if (routingScan.stats.sourceProjects.length > 0) {
|
|
1810
|
+
console.log(chalk8__default.default.dim(` ${routingScan.stats.sourceProjects.slice(0, 5).join(", ")}`));
|
|
1811
|
+
if (routingScan.stats.sourceProjects.length > 5) {
|
|
1812
|
+
console.log(chalk8__default.default.dim(` ... and ${routingScan.stats.sourceProjects.length - 5} more`));
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
console.log(` Scan time: ${chalk8__default.default.dim(formatDuration(routingScan.stats.durationMs))}`);
|
|
1816
|
+
}
|
|
1580
1817
|
console.log("");
|
|
1581
1818
|
if (plan.conflicts.length > 0) {
|
|
1582
1819
|
console.log(chalk8__default.default.yellow(`\u26A0 ${plan.conflicts.length} conflicts detected:`));
|