@fractary/codex-cli 0.10.16 → 0.10.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var fs4 = require('fs/promises');
5
- var path2 = require('path');
6
- var yaml = require('js-yaml');
7
4
  var codex = require('@fractary/codex');
5
+ var path3 = require('path');
8
6
  var os = require('os');
7
+ var fs2 = require('fs/promises');
9
8
  var child_process = require('child_process');
10
9
  var commander = require('commander');
11
- var chalk7 = require('chalk');
10
+ var chalk10 = require('chalk');
12
11
  var crypto = require('crypto');
12
+ require('js-yaml');
13
13
  var fs = require('fs');
14
14
  var url = require('url');
15
15
 
@@ -33,21 +33,14 @@ function _interopNamespace(e) {
33
33
  return Object.freeze(n);
34
34
  }
35
35
 
36
- var fs4__namespace = /*#__PURE__*/_interopNamespace(fs4);
37
- var path2__namespace = /*#__PURE__*/_interopNamespace(path2);
38
- var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
36
+ var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
39
37
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
40
- var chalk7__default = /*#__PURE__*/_interopDefault(chalk7);
38
+ var fs2__namespace = /*#__PURE__*/_interopNamespace(fs2);
39
+ var chalk10__default = /*#__PURE__*/_interopDefault(chalk10);
41
40
  var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
42
41
 
43
42
  var __defProp = Object.defineProperty;
44
43
  var __getOwnPropNames = Object.getOwnPropertyNames;
45
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
46
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
47
- }) : x)(function(x) {
48
- if (typeof require !== "undefined") return require.apply(this, arguments);
49
- throw Error('Dynamic require of "' + x + '" is not supported');
50
- });
51
44
  var __esm = (fn, res) => function __init() {
52
45
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
53
46
  };
@@ -65,477 +58,19 @@ var init_cjs_shims = __esm({
65
58
  }
66
59
  });
67
60
 
68
- // src/config/migrate-config.ts
69
- var migrate_config_exports = {};
70
- __export(migrate_config_exports, {
71
- getDefaultYamlConfig: () => getDefaultYamlConfig,
72
- isLegacyConfig: () => isLegacyConfig,
73
- migrateConfig: () => migrateConfig,
74
- readYamlConfig: () => codex.readCodexConfig,
75
- writeYamlConfig: () => writeYamlConfig
76
- });
77
- async function isLegacyConfig(configPath) {
78
- try {
79
- const content = await fs4__namespace.readFile(configPath, "utf-8");
80
- const config = JSON.parse(content);
81
- return config.version === "3.0" || config.organizationSlug !== void 0 || config.directories !== void 0 || config.rules !== void 0;
82
- } catch {
83
- return false;
84
- }
85
- }
86
- async function migrateConfig(legacyConfigPath, options) {
87
- const warnings = [];
88
- try {
89
- const content = await fs4__namespace.readFile(legacyConfigPath, "utf-8");
90
- const legacy = JSON.parse(content);
91
- let backupPath;
92
- if (options?.createBackup !== false) {
93
- const suffix = options?.backupSuffix || (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
94
- backupPath = `${legacyConfigPath}.backup-${suffix}`;
95
- await fs4__namespace.writeFile(backupPath, content, "utf-8");
96
- }
97
- const yamlConfig = {
98
- organization: legacy.organization || legacy.organizationSlug || "default"
99
- };
100
- if (legacy.cache) {
101
- yamlConfig.cacheDir = legacy.cache.directory || ".fractary/codex/cache";
102
- }
103
- if (legacy.storage?.providers) {
104
- yamlConfig.storage = [];
105
- for (const [type, config] of Object.entries(legacy.storage.providers)) {
106
- if (type === "github") {
107
- const githubConfig = config;
108
- yamlConfig.storage.push({
109
- type: "github",
110
- token: githubConfig.token || "${GITHUB_TOKEN}",
111
- apiBaseUrl: githubConfig.baseUrl || "https://api.github.com",
112
- branch: githubConfig.branch || "main",
113
- priority: 50
114
- });
115
- } else if (type === "http") {
116
- const httpConfig = config;
117
- yamlConfig.storage.push({
118
- type: "http",
119
- baseUrl: httpConfig.baseUrl,
120
- headers: httpConfig.headers,
121
- timeout: httpConfig.timeout || 3e4,
122
- priority: 100
123
- });
124
- } else if (type === "local") {
125
- const localConfig = config;
126
- yamlConfig.storage.push({
127
- type: "local",
128
- basePath: localConfig.basePath || "./knowledge",
129
- followSymlinks: localConfig.followSymlinks || false,
130
- priority: 10
131
- });
132
- } else {
133
- warnings.push(`Unknown storage provider type: ${type}`);
134
- }
135
- }
136
- if (yamlConfig.storage.length === 0) {
137
- yamlConfig.storage.push({
138
- type: "github",
139
- token: "${GITHUB_TOKEN}",
140
- apiBaseUrl: "https://api.github.com",
141
- branch: "main",
142
- priority: 50
143
- });
144
- warnings.push("No storage providers found, added default GitHub provider");
145
- }
146
- }
147
- if (legacy.types?.custom && Array.isArray(legacy.types.custom)) {
148
- yamlConfig.types = {
149
- custom: {}
150
- };
151
- for (const customType of legacy.types.custom) {
152
- if (customType.name) {
153
- yamlConfig.types.custom[customType.name] = {
154
- description: customType.description,
155
- patterns: customType.patterns || [],
156
- defaultTtl: customType.defaultTtl,
157
- archiveAfterDays: customType.archiveAfterDays,
158
- archiveStorage: customType.archiveStorage
159
- };
160
- }
161
- }
162
- }
163
- if (legacy.sync) {
164
- yamlConfig.sync = {
165
- bidirectional: true,
166
- conflictResolution: "prompt",
167
- exclude: [
168
- "node_modules/**",
169
- ".git/**",
170
- "**/*.log",
171
- ".env"
172
- ]
173
- };
174
- if (legacy.sync.environments) {
175
- warnings.push("Sync environments are not directly supported in v3.0 - please configure sync rules manually");
176
- }
177
- }
178
- if (legacy.mcp) {
179
- yamlConfig.mcp = {
180
- enabled: legacy.mcp.enabled || false,
181
- port: legacy.mcp.port || 3e3
182
- };
183
- }
184
- return {
185
- success: true,
186
- yamlConfig,
187
- warnings,
188
- backupPath
189
- };
190
- } catch (error) {
191
- throw new Error(
192
- `Migration failed: ${error instanceof Error ? error.message : String(error)}`
193
- );
194
- }
195
- }
196
- async function writeYamlConfig(config, outputPath) {
197
- const dir = path2__namespace.dirname(outputPath);
198
- await fs4__namespace.mkdir(dir, { recursive: true });
199
- const yamlContent = yaml__namespace.dump(config, {
200
- indent: 2,
201
- lineWidth: 80,
202
- noRefs: true,
203
- sortKeys: false
204
- });
205
- await fs4__namespace.writeFile(outputPath, yamlContent, "utf-8");
206
- }
207
- function getDefaultYamlConfig(organization) {
208
- return {
209
- organization,
210
- cacheDir: ".fractary/codex/cache",
211
- storage: [
212
- {
213
- type: "local",
214
- basePath: "./knowledge",
215
- followSymlinks: false,
216
- priority: 10
217
- },
218
- {
219
- type: "github",
220
- token: "${GITHUB_TOKEN}",
221
- apiBaseUrl: "https://api.github.com",
222
- branch: "main",
223
- priority: 50
224
- },
225
- {
226
- type: "http",
227
- baseUrl: "https://codex.example.com",
228
- timeout: 3e4,
229
- priority: 100
230
- }
231
- ],
232
- types: {
233
- custom: {}
234
- },
235
- permissions: {
236
- default: "read",
237
- rules: [
238
- {
239
- pattern: "internal/**",
240
- permission: "none"
241
- },
242
- {
243
- pattern: "public/**",
244
- permission: "read"
245
- }
246
- ]
247
- },
248
- sync: {
249
- bidirectional: true,
250
- conflictResolution: "prompt",
251
- exclude: [
252
- "node_modules/**",
253
- ".git/**",
254
- "**/*.log",
255
- ".env"
256
- ]
257
- },
258
- mcp: {
259
- enabled: false,
260
- port: 3e3
261
- }
262
- };
263
- }
264
- var init_migrate_config = __esm({
265
- "src/config/migrate-config.ts"() {
266
- init_cjs_shims();
267
- }
268
- });
269
-
270
- // src/config/config-types.ts
271
- var config_types_exports = {};
272
- __export(config_types_exports, {
273
- parseDuration: () => codex.parseDuration,
274
- parseSize: () => codex.parseSize,
275
- resolveEnvVars: () => codex.expandEnvVars,
276
- resolveEnvVarsInConfig: () => codex.expandEnvVarsInConfig
277
- });
278
- var init_config_types = __esm({
279
- "src/config/config-types.ts"() {
280
- init_cjs_shims();
281
- }
282
- });
283
-
284
61
  // src/client/codex-client.ts
285
62
  var codex_client_exports = {};
286
63
  __export(codex_client_exports, {
287
- CodexClient: () => CodexClient,
64
+ CodexClient: () => codex.CodexClient,
288
65
  CodexError: () => codex.CodexError,
289
66
  ConfigurationError: () => codex.ConfigurationError,
290
67
  PermissionDeniedError: () => codex.PermissionDeniedError,
291
- ValidationError: () => codex.ValidationError
68
+ ValidationError: () => codex.ValidationError,
69
+ createCodexClient: () => codex.createCodexClient
292
70
  });
293
- var CodexClient;
294
71
  var init_codex_client = __esm({
295
72
  "src/client/codex-client.ts"() {
296
73
  init_cjs_shims();
297
- CodexClient = class _CodexClient {
298
- cache;
299
- storage;
300
- types;
301
- organization;
302
- /**
303
- * Private constructor - use CodexClient.create() instead
304
- */
305
- constructor(cache, storage, types, organization) {
306
- this.cache = cache;
307
- this.storage = storage;
308
- this.types = types;
309
- this.organization = organization;
310
- }
311
- /**
312
- * Create a new CodexClient instance
313
- *
314
- * @param options - Optional configuration
315
- * @returns Promise resolving to CodexClient instance
316
- *
317
- * @example
318
- * ```typescript
319
- * const client = await CodexClient.create();
320
- * ```
321
- */
322
- static async create(options) {
323
- const {
324
- CacheManager,
325
- createStorageManager,
326
- createDefaultRegistry,
327
- CodexError: CodexError2,
328
- ConfigurationError: ConfigurationError2
329
- } = await import('@fractary/codex');
330
- const { readYamlConfig } = await Promise.resolve().then(() => (init_migrate_config(), migrate_config_exports));
331
- const { resolveEnvVarsInConfig } = await Promise.resolve().then(() => (init_config_types(), config_types_exports));
332
- try {
333
- const configPath = path2__namespace.join(process.cwd(), ".fractary", "config.yaml");
334
- let config;
335
- try {
336
- config = await readYamlConfig(configPath);
337
- config = resolveEnvVarsInConfig(config);
338
- } catch (error) {
339
- throw new ConfigurationError2(
340
- `Failed to load configuration from ${configPath}. Run "fractary-codex configure" to create a configuration.`
341
- );
342
- }
343
- const organization = options?.organizationSlug || config.organization;
344
- const cacheDir = options?.cacheDir || config.cacheDir || ".codex-cache";
345
- const storageConfig = {};
346
- if (config.storage && Array.isArray(config.storage)) {
347
- for (const provider of config.storage) {
348
- if (provider.type === "github") {
349
- storageConfig.github = {
350
- token: provider.token || process.env.GITHUB_TOKEN,
351
- apiBaseUrl: provider.apiBaseUrl || "https://api.github.com",
352
- branch: provider.branch || "main"
353
- };
354
- } else if (provider.type === "http") {
355
- storageConfig.http = {
356
- baseUrl: provider.baseUrl,
357
- headers: provider.headers,
358
- timeout: provider.timeout || 3e4
359
- };
360
- } else if (provider.type === "local") {
361
- storageConfig.local = {
362
- basePath: provider.basePath || "./knowledge",
363
- followSymlinks: provider.followSymlinks || false
364
- };
365
- }
366
- }
367
- }
368
- const storage = createStorageManager(storageConfig);
369
- const cache = new CacheManager({
370
- cacheDir,
371
- defaultTtl: 86400,
372
- // 24 hours
373
- maxMemoryEntries: 100,
374
- maxMemorySize: 50 * 1024 * 1024,
375
- // 50MB
376
- enablePersistence: true
377
- });
378
- cache.setStorageManager(storage);
379
- const types = createDefaultRegistry();
380
- if (config.types?.custom) {
381
- for (const [name, customType] of Object.entries(config.types.custom)) {
382
- const ct = customType;
383
- types.register({
384
- name,
385
- description: ct.description || `Custom type: ${name}`,
386
- patterns: ct.patterns || [],
387
- defaultTtl: ct.defaultTtl || 86400,
388
- archiveAfterDays: ct.archiveAfterDays !== void 0 ? ct.archiveAfterDays : null,
389
- archiveStorage: ct.archiveStorage || null
390
- });
391
- }
392
- }
393
- return new _CodexClient(cache, storage, types, organization);
394
- } catch (error) {
395
- if (error instanceof CodexError2) {
396
- throw error;
397
- }
398
- throw new CodexError2(
399
- `Failed to initialize CodexClient: ${error instanceof Error ? error.message : String(error)}`
400
- );
401
- }
402
- }
403
- /**
404
- * Fetch a document by codex:// URI
405
- *
406
- * This method:
407
- * 1. Validates the URI format
408
- * 2. Resolves the URI to a reference
409
- * 3. Uses CacheManager.get() which handles cache-first fetch
410
- *
411
- * @param uri - Codex URI (e.g., codex://org/project/path/to/file.md)
412
- * @param options - Fetch options
413
- * @returns Promise resolving to fetch result
414
- *
415
- * @throws {CodexError} If URI format is invalid or fetch fails
416
- *
417
- * @example
418
- * ```typescript
419
- * const result = await client.fetch('codex://fractary/codex/docs/README.md');
420
- * console.log(result.content.toString());
421
- * ```
422
- */
423
- async fetch(uri, options) {
424
- const { validateUri, resolveReference, CodexError: CodexError2 } = await import('@fractary/codex');
425
- if (!validateUri(uri)) {
426
- throw new CodexError2(`Invalid codex URI: ${uri}`);
427
- }
428
- const resolved = resolveReference(uri);
429
- if (!resolved) {
430
- throw new CodexError2(`Failed to resolve URI: ${uri}`);
431
- }
432
- try {
433
- if (options?.bypassCache) {
434
- const result2 = await this.storage.fetch(resolved);
435
- return {
436
- content: result2.content,
437
- fromCache: false,
438
- metadata: {
439
- fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
440
- contentLength: result2.size
441
- }
442
- };
443
- }
444
- const result = await this.cache.get(resolved, {
445
- ttl: options?.ttl
446
- });
447
- return {
448
- content: result.content,
449
- fromCache: true,
450
- // CacheManager.get handles cache logic
451
- metadata: {
452
- contentLength: result.size
453
- }
454
- };
455
- } catch (error) {
456
- throw new CodexError2(
457
- `Failed to fetch ${uri}: ${error instanceof Error ? error.message : String(error)}`
458
- );
459
- }
460
- }
461
- /**
462
- * Invalidate cache entries
463
- *
464
- * @param pattern - Optional glob pattern to match entries
465
- * If not provided, clears all entries
466
- *
467
- * @example
468
- * ```typescript
469
- * // Clear all cache
470
- * await client.invalidateCache();
471
- *
472
- * // Clear specific URI
473
- * await client.invalidateCache('codex://fractary/codex/docs/README.md');
474
- * ```
475
- */
476
- async invalidateCache(pattern) {
477
- if (pattern) {
478
- await this.cache.invalidate(pattern);
479
- } else {
480
- await this.cache.clear();
481
- }
482
- }
483
- /**
484
- * Get cache statistics
485
- *
486
- * @returns Promise resolving to cache stats
487
- *
488
- * @example
489
- * ```typescript
490
- * const stats = await client.getCacheStats();
491
- * console.log(`Cache entries: ${stats.totalEntries}`);
492
- * console.log(`Total size: ${stats.totalSize}`);
493
- * ```
494
- */
495
- async getCacheStats() {
496
- return this.cache.getStats();
497
- }
498
- /**
499
- * Get the type registry
500
- *
501
- * Provides access to built-in and custom artifact types
502
- *
503
- * @returns TypeRegistry instance
504
- *
505
- * @example
506
- * ```typescript
507
- * const registry = client.getTypeRegistry();
508
- * const types = registry.list();
509
- * ```
510
- */
511
- getTypeRegistry() {
512
- return this.types;
513
- }
514
- /**
515
- * Get the cache manager (for advanced operations)
516
- *
517
- * @returns CacheManager instance
518
- */
519
- getCacheManager() {
520
- return this.cache;
521
- }
522
- /**
523
- * Get the storage manager (for advanced operations)
524
- *
525
- * @returns StorageManager instance
526
- */
527
- getStorageManager() {
528
- return this.storage;
529
- }
530
- /**
531
- * Get the organization slug
532
- *
533
- * @returns Organization slug string
534
- */
535
- getOrganization() {
536
- return this.organization;
537
- }
538
- };
539
74
  }
540
75
  });
541
76
 
@@ -600,7 +135,7 @@ function getTempCodexPath(config) {
600
135
  const codexRepo = config.codex_repo || "codex";
601
136
  const sanitizedOrg = sanitizePathComponent(config.organization);
602
137
  const sanitizedRepo = sanitizePathComponent(codexRepo);
603
- return path2__namespace.join(
138
+ return path3__namespace.join(
604
139
  os__namespace.tmpdir(),
605
140
  "fractary-codex-clone",
606
141
  `${sanitizedOrg}-${sanitizedRepo}-${process.pid}`
@@ -608,8 +143,8 @@ function getTempCodexPath(config) {
608
143
  }
609
144
  async function isValidGitRepo(repoPath) {
610
145
  try {
611
- const gitDir = path2__namespace.join(repoPath, ".git");
612
- const stats = await fs4__namespace.stat(gitDir);
146
+ const gitDir = path3__namespace.join(repoPath, ".git");
147
+ const stats = await fs2__namespace.stat(gitDir);
613
148
  return stats.isDirectory();
614
149
  } catch {
615
150
  return false;
@@ -641,8 +176,8 @@ async function execGit(repoPath, args) {
641
176
  }
642
177
  }
643
178
  async function gitClone(url, targetPath, options) {
644
- const parentDir = path2__namespace.dirname(targetPath);
645
- await fs4__namespace.mkdir(parentDir, { recursive: true });
179
+ const parentDir = path3__namespace.dirname(targetPath);
180
+ await fs2__namespace.mkdir(parentDir, { recursive: true });
646
181
  const args = ["clone"];
647
182
  if (options?.depth) {
648
183
  if (!Number.isInteger(options.depth) || options.depth <= 0) {
@@ -689,12 +224,12 @@ async function ensureCodexCloned(config, options) {
689
224
  } catch (error) {
690
225
  console.warn(`Failed to update existing clone: ${error.message}`);
691
226
  console.warn(`Removing and cloning fresh...`);
692
- await fs4__namespace.rm(tempPath, { recursive: true, force: true });
227
+ await fs2__namespace.rm(tempPath, { recursive: true, force: true });
693
228
  }
694
229
  }
695
230
  const repoUrl = getCodexRepoUrl(config);
696
231
  try {
697
- await fs4__namespace.rm(tempPath, { recursive: true, force: true });
232
+ await fs2__namespace.rm(tempPath, { recursive: true, force: true });
698
233
  } catch (error) {
699
234
  console.warn(`Could not remove existing directory ${tempPath}: ${error.message}`);
700
235
  }
@@ -717,539 +252,304 @@ init_cjs_shims();
717
252
  // src/commands/config/index.ts
718
253
  init_cjs_shims();
719
254
 
720
- // src/commands/config/init.ts
721
- init_cjs_shims();
722
-
723
- // src/config/unified-config.ts
255
+ // src/commands/config/initialize.ts
724
256
  init_cjs_shims();
725
- function sanitizeForS3BucketName(name) {
726
- return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-").substring(0, 63);
727
- }
728
- function getDefaultUnifiedConfig(organization, project, codexRepo) {
729
- const sanitizedProject = sanitizeForS3BucketName(project);
730
- return {
731
- file: {
732
- schema_version: codex.CONFIG_SCHEMA_VERSION,
733
- sources: {
734
- specs: {
735
- type: "s3",
736
- bucket: `${sanitizedProject}-files`,
737
- prefix: "specs/",
738
- region: "us-east-1",
739
- local: {
740
- base_path: ".fractary/specs"
741
- },
742
- push: {
743
- compress: false,
744
- keep_local: true
745
- },
746
- auth: {
747
- profile: "default"
748
- }
749
- },
750
- logs: {
751
- type: "s3",
752
- bucket: `${sanitizedProject}-files`,
753
- prefix: "logs/",
754
- region: "us-east-1",
755
- local: {
756
- base_path: ".fractary/logs"
757
- },
758
- push: {
759
- compress: true,
760
- keep_local: true
761
- },
762
- auth: {
763
- profile: "default"
764
- }
765
- }
766
- }
767
- },
768
- codex: {
769
- schema_version: codex.CONFIG_SCHEMA_VERSION,
770
- organization,
771
- project,
772
- codex_repo: codexRepo,
773
- remotes: {
774
- // The codex repository - uses same token as git operations
775
- [`${organization}/${codexRepo}`]: {
776
- token: "${GITHUB_TOKEN}"
777
- }
778
- }
779
- }
780
- };
781
- }
782
- async function readUnifiedConfig(configPath) {
783
- try {
784
- const content = await fs4__namespace.readFile(configPath, "utf-8");
785
- const config = yaml__namespace.load(content);
786
- return config;
787
- } catch (error) {
788
- if (error.code === "ENOENT") {
789
- return null;
790
- }
791
- throw error;
792
- }
793
- }
794
- async function writeUnifiedConfig(config, outputPath) {
795
- const dir = path2__namespace.dirname(outputPath);
796
- await fs4__namespace.mkdir(dir, { recursive: true });
797
- const yamlContent = yaml__namespace.dump(config, {
798
- indent: 2,
799
- lineWidth: 120,
800
- noRefs: true,
801
- sortKeys: false
802
- });
803
- await fs4__namespace.writeFile(outputPath, yamlContent, "utf-8");
804
- }
805
- function mergeUnifiedConfigs(existing, updates) {
806
- const merged = {};
807
- if (updates.file || existing.file) {
808
- merged.file = {
809
- schema_version: updates.file?.schema_version || existing.file?.schema_version || codex.CONFIG_SCHEMA_VERSION,
810
- sources: {
811
- ...existing.file?.sources || {},
812
- ...updates.file?.sources || {}
813
- }
814
- };
815
- }
816
- if (updates.codex || existing.codex) {
817
- merged.codex = {
818
- schema_version: updates.codex?.schema_version || existing.codex?.schema_version || codex.CONFIG_SCHEMA_VERSION,
819
- organization: updates.codex?.organization || existing.codex?.organization || "default",
820
- project: updates.codex?.project || existing.codex?.project || "default",
821
- codex_repo: updates.codex?.codex_repo || existing.codex?.codex_repo || "",
822
- remotes: {
823
- ...existing.codex?.remotes || {},
824
- ...updates.codex?.remotes || {}
825
- }
826
- };
827
- }
828
- return merged;
829
- }
830
- async function initializeUnifiedConfig(configPath, organization, project, codexRepo, options) {
831
- const existingConfig = await readUnifiedConfig(configPath);
832
- if (existingConfig && !options?.force) {
833
- const defaultConfig = getDefaultUnifiedConfig(organization, project, codexRepo);
834
- const merged = mergeUnifiedConfigs(existingConfig, defaultConfig);
835
- await writeUnifiedConfig(merged, configPath);
836
- return {
837
- created: false,
838
- merged: true,
839
- config: merged
840
- };
841
- }
842
- const config = getDefaultUnifiedConfig(organization, project, codexRepo);
843
- await writeUnifiedConfig(config, configPath);
844
- return {
845
- created: true,
846
- merged: false,
847
- config
848
- };
849
- }
850
-
851
- // src/config/gitignore-utils.ts
852
- init_cjs_shims();
853
- var DEFAULT_FRACTARY_GITIGNORE = `# .fractary/.gitignore
854
- # This file is managed by multiple plugins - each plugin manages its own section
855
-
856
- # ===== fractary-codex (managed) =====
857
- codex/cache/
858
- # ===== end fractary-codex =====
859
- `;
860
- async function readFractaryGitignore(projectRoot) {
861
- const gitignorePath = path2__namespace.join(projectRoot, ".fractary", ".gitignore");
862
- try {
863
- return await fs4__namespace.readFile(gitignorePath, "utf-8");
864
- } catch (error) {
865
- if (error.code === "ENOENT") {
866
- return null;
867
- }
868
- throw error;
869
- }
870
- }
871
- async function writeFractaryGitignore(projectRoot, content) {
872
- const gitignorePath = path2__namespace.join(projectRoot, ".fractary", ".gitignore");
873
- await fs4__namespace.mkdir(path2__namespace.join(projectRoot, ".fractary"), { recursive: true });
874
- await fs4__namespace.writeFile(gitignorePath, content, "utf-8");
875
- }
876
- function normalizeCachePath(cachePath) {
877
- let normalized = cachePath.replace(/\\/g, "/");
878
- normalized = normalized.replace(/^\.fractary\//, "");
879
- if (!normalized.endsWith("/")) {
880
- normalized += "/";
881
- }
882
- return normalized;
883
- }
884
- function isCachePathIgnored(gitignoreContent, cachePath) {
885
- const normalized = normalizeCachePath(cachePath);
886
- const lines = gitignoreContent.split("\n").map((l) => l.trim());
887
- return lines.some((line) => {
888
- if (line.startsWith("#") || line === "") return false;
889
- let normalizedLine = line.replace(/\\/g, "/");
890
- if (!normalizedLine.endsWith("/")) {
891
- normalizedLine += "/";
892
- }
893
- return normalizedLine === normalized;
894
- });
895
- }
896
- function addCachePathToGitignore(gitignoreContent, cachePath, comment) {
897
- const normalized = normalizeCachePath(cachePath);
898
- if (isCachePathIgnored(gitignoreContent, cachePath)) {
899
- return gitignoreContent;
900
- }
901
- let addition = "";
902
- {
903
- addition += `
904
- # ${comment}
905
- `;
906
- }
907
- addition += normalized + "\n";
908
- return gitignoreContent.trimEnd() + addition;
909
- }
910
- async function ensureCachePathIgnored(projectRoot, cachePath) {
911
- const gitignorePath = path2__namespace.join(projectRoot, ".fractary", ".gitignore");
912
- let relativeCachePath = cachePath;
913
- if (path2__namespace.isAbsolute(cachePath)) {
914
- relativeCachePath = path2__namespace.relative(path2__namespace.join(projectRoot, ".fractary"), cachePath);
915
- }
916
- relativeCachePath = normalizeCachePath(relativeCachePath);
917
- let content = await readFractaryGitignore(projectRoot);
918
- const gitignoreExists = content !== null;
919
- if (!gitignoreExists) {
920
- content = DEFAULT_FRACTARY_GITIGNORE;
921
- if (!isCachePathIgnored(content, relativeCachePath)) {
922
- content = addCachePathToGitignore(content, relativeCachePath, "Custom cache directory");
923
- }
924
- await writeFractaryGitignore(projectRoot, content);
925
- return {
926
- created: true,
927
- updated: false,
928
- alreadyIgnored: false,
929
- gitignorePath
930
- };
931
- }
932
- if (isCachePathIgnored(content, relativeCachePath)) {
933
- return {
934
- created: false,
935
- updated: false,
936
- alreadyIgnored: true,
937
- gitignorePath
938
- };
939
- }
940
- content = addCachePathToGitignore(content, relativeCachePath, "Custom cache directory");
941
- await writeFractaryGitignore(projectRoot, content);
942
- return {
943
- created: false,
944
- updated: true,
945
- alreadyIgnored: false,
946
- gitignorePath
947
- };
948
- }
949
-
950
- // src/commands/config/init.ts
951
- function validateNameFormat(name, type) {
952
- if (!name || typeof name !== "string") {
953
- throw new Error(`${type} name is required`);
954
- }
955
- if (name.length > 100) {
956
- throw new Error(`${type} name too long (max 100 characters)`);
957
- }
958
- const safePattern = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
959
- if (!safePattern.test(name)) {
960
- throw new Error(
961
- `Invalid ${type} name format: "${name}". Must start with alphanumeric and contain only: a-z, A-Z, 0-9, ., -, _`
962
- );
963
- }
964
- }
965
- async function getOrgFromGitRemote() {
966
- try {
967
- const { execSync } = __require("child_process");
968
- const remote = execSync("git remote get-url origin 2>/dev/null", { encoding: "utf-8" }).trim();
969
- const sshMatch = remote.match(/git@github\.com:([^/]+)\//);
970
- const httpsMatch = remote.match(/github\.com\/([^/]+)\//);
971
- return sshMatch?.[1] || httpsMatch?.[1] || null;
972
- } catch {
973
- return null;
974
- }
975
- }
976
- async function discoverCodexRepo(org) {
977
- try {
978
- validateNameFormat(org, "organization");
979
- } catch (error) {
980
- return { repo: null, error: "unknown", message: error.message };
981
- }
982
- try {
983
- const { execSync } = __require("child_process");
984
- try {
985
- execSync("gh --version", { encoding: "utf-8", stdio: "pipe" });
986
- } catch {
987
- return {
988
- repo: null,
989
- error: "gh_not_installed",
990
- message: "GitHub CLI (gh) is not installed. Install from https://cli.github.com/"
991
- };
992
- }
993
- try {
994
- execSync("gh auth status", { encoding: "utf-8", stdio: "pipe" });
995
- } catch {
996
- return {
997
- repo: null,
998
- error: "auth_failed",
999
- message: "GitHub CLI not authenticated. Run: gh auth login"
1000
- };
1001
- }
1002
- const result = execSync(
1003
- `gh repo list ${org} --json name --jq '.[].name | select(startswith("codex."))' 2>&1`,
1004
- { encoding: "utf-8" }
1005
- ).trim();
1006
- if (result.includes("Could not resolve to an Organization") || result.includes("Not Found")) {
1007
- return {
1008
- repo: null,
1009
- error: "org_not_found",
1010
- message: `Organization '${org}' not found on GitHub`
1011
- };
1012
- }
1013
- const repos = result.split("\n").filter(Boolean);
1014
- if (repos.length === 0) {
1015
- return {
1016
- repo: null,
1017
- error: "no_repos_found",
1018
- message: `No codex.* repositories found in organization '${org}'`
1019
- };
1020
- }
1021
- return { repo: repos[0] };
1022
- } catch (error) {
1023
- return {
1024
- repo: null,
1025
- error: "unknown",
1026
- message: error.message || "Unknown error during discovery"
1027
- };
1028
- }
1029
- }
1030
- async function fileExists(filePath) {
1031
- try {
1032
- await fs4__namespace.access(filePath);
1033
- return true;
1034
- } catch {
1035
- return false;
1036
- }
1037
- }
1038
- async function installMcpServer(projectRoot, configPath = ".fractary/config.yaml", options = {}) {
1039
- const mcpJsonPath = path2__namespace.join(projectRoot, ".mcp.json");
1040
- const { backup = true } = options;
1041
- let existingConfig = { mcpServers: {} };
1042
- let backupPath;
1043
- let migrated = false;
1044
- if (await fileExists(mcpJsonPath)) {
257
+ function configInitializeCommand() {
258
+ const cmd = new commander.Command("config-init");
259
+ cmd.description("Initialize codex section in .fractary/config.yaml (requires base config from @fractary/core)").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--project <name>", "Project name (default: derived from directory)").option("--codex-repo <name>", 'Codex repository name (e.g., "codex.fractary.com")').option("--sync-preset <name>", "Sync preset (standard, minimal)", "standard").option("--force", "Overwrite existing codex section").option("--no-mcp", "Skip MCP server installation").option("--json", "Output as JSON").action(async (options) => {
1045
260
  try {
1046
- const content = await fs4__namespace.readFile(mcpJsonPath, "utf-8");
1047
- existingConfig = JSON.parse(content);
1048
- if (backup) {
1049
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 18);
1050
- const suffix = Math.random().toString(36).substring(2, 6);
1051
- backupPath = `${mcpJsonPath}.backup.${timestamp}-${suffix}`;
1052
- await fs4__namespace.writeFile(backupPath, content);
1053
- }
1054
- } catch {
1055
- console.log(chalk7__default.default.yellow("\u26A0 Warning: .mcp.json contains invalid JSON, starting fresh"));
1056
- existingConfig = { mcpServers: {} };
1057
- }
1058
- }
1059
- if (!existingConfig.mcpServers) {
1060
- existingConfig.mcpServers = {};
1061
- }
1062
- const existing = existingConfig.mcpServers["fractary-codex"];
1063
- if (existing) {
1064
- const existingCommand = existing.command;
1065
- const existingArgs = existing.args || [];
1066
- if (existingCommand === "npx" && existingArgs.includes("@fractary/codex-mcp")) {
1067
- return {
1068
- installed: false,
1069
- migrated: false,
1070
- alreadyInstalled: true,
1071
- backupPath
1072
- };
1073
- }
1074
- if (existingCommand === "node" || existingArgs.includes("@fractary/codex")) {
1075
- migrated = true;
1076
- }
1077
- }
1078
- existingConfig.mcpServers["fractary-codex"] = {
1079
- command: "npx",
1080
- args: ["-y", "@fractary/codex-mcp", "--config", configPath]
1081
- };
1082
- await fs4__namespace.writeFile(
1083
- mcpJsonPath,
1084
- JSON.stringify(existingConfig, null, 2) + "\n"
1085
- );
1086
- return {
1087
- installed: true,
1088
- migrated,
1089
- alreadyInstalled: false,
1090
- backupPath
1091
- };
1092
- }
1093
- function configureCommand() {
1094
- const cmd = new commander.Command("configure");
1095
- cmd.description("Initialize unified Fractary configuration (.fractary/config.yaml)").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--project <name>", "Project name (default: derived from directory)").option("--codex-repo <name>", 'Codex repository name (e.g., "codex.fractary.com")').option("--force", "Overwrite existing configuration").option("--no-mcp", "Skip MCP server installation").action(async (options) => {
1096
- try {
1097
- console.log(chalk7__default.default.blue("Initializing unified Fractary configuration...\n"));
261
+ const configManager = codex.createConfigManager(process.cwd());
262
+ if (!options.json) {
263
+ console.log(chalk10__default.default.blue("Initializing codex configuration...\n"));
264
+ }
1098
265
  let org = options.org;
1099
266
  if (!org) {
1100
- org = await getOrgFromGitRemote();
267
+ org = await configManager.detectOrganization();
1101
268
  }
1102
269
  if (!org) {
1103
270
  try {
1104
- const { resolveOrganization } = await import('@fractary/codex');
1105
- org = resolveOrganization({
1106
- repoName: path2__namespace.basename(process.cwd())
271
+ org = codex.resolveOrganization({
272
+ repoName: path3__namespace.basename(process.cwd())
1107
273
  });
1108
274
  } catch {
1109
275
  }
1110
276
  }
1111
277
  if (!org) {
1112
- org = path2__namespace.basename(process.cwd()).split("-")[0] || "default";
1113
- console.log(chalk7__default.default.yellow(`\u26A0 Could not detect organization, using: ${org}`));
1114
- console.log(chalk7__default.default.dim(" Use --org <slug> to specify explicitly\n"));
1115
- } else {
1116
- console.log(chalk7__default.default.dim(`Organization: ${chalk7__default.default.cyan(org)}
278
+ org = path3__namespace.basename(process.cwd()).split("-")[0] || "default";
279
+ if (!options.json) {
280
+ console.log(chalk10__default.default.yellow(`\u26A0 Could not detect organization, using: ${org}`));
281
+ console.log(chalk10__default.default.dim(" Use --org <slug> to specify explicitly\n"));
282
+ }
283
+ } else if (!options.json) {
284
+ console.log(chalk10__default.default.dim(`Organization: ${chalk10__default.default.cyan(org)}
1117
285
  `));
1118
286
  }
1119
- try {
1120
- validateNameFormat(org, "organization");
1121
- } catch (error) {
1122
- console.error(chalk7__default.default.red("Error:"), error.message);
287
+ const orgValidation = codex.validateNameFormat(org, "organization");
288
+ if (!orgValidation.valid) {
289
+ if (options.json) {
290
+ console.log(JSON.stringify({ error: orgValidation.error }, null, 2));
291
+ } else {
292
+ console.error(chalk10__default.default.red("Error:"), orgValidation.error);
293
+ }
1123
294
  process.exit(1);
1124
295
  }
1125
296
  let project = options.project;
1126
297
  if (!project) {
1127
- project = path2__namespace.basename(process.cwd());
1128
- console.log(chalk7__default.default.dim(`Project: ${chalk7__default.default.cyan(project)}
298
+ project = configManager.detectProject();
299
+ if (!options.json) {
300
+ console.log(chalk10__default.default.dim(`Project: ${chalk10__default.default.cyan(project)}
1129
301
  `));
302
+ }
1130
303
  }
1131
304
  let codexRepo = options.codexRepo;
1132
305
  if (codexRepo) {
1133
- try {
1134
- validateNameFormat(codexRepo, "repository");
1135
- } catch (error) {
1136
- console.error(chalk7__default.default.red("Error:"), error.message);
306
+ const repoValidation = codex.validateNameFormat(codexRepo, "repository");
307
+ if (!repoValidation.valid) {
308
+ if (options.json) {
309
+ console.log(JSON.stringify({ error: repoValidation.error }, null, 2));
310
+ } else {
311
+ console.error(chalk10__default.default.red("Error:"), repoValidation.error);
312
+ }
1137
313
  process.exit(1);
1138
314
  }
1139
- console.log(chalk7__default.default.dim(`Codex repository: ${chalk7__default.default.cyan(codexRepo)}
315
+ if (!options.json) {
316
+ console.log(chalk10__default.default.dim(`Codex repository: ${chalk10__default.default.cyan(codexRepo)}
1140
317
  `));
318
+ }
1141
319
  } else {
1142
- const discoveryResult = await discoverCodexRepo(org);
320
+ const discoveryResult = await configManager.discoverCodexRepo(org);
1143
321
  if (discoveryResult.repo) {
1144
322
  codexRepo = discoveryResult.repo;
1145
- console.log(chalk7__default.default.dim(`Codex repository: ${chalk7__default.default.cyan(codexRepo)} (auto-discovered)
1146
- `));
1147
- } else {
1148
- if (discoveryResult.error === "gh_not_installed") {
1149
- console.log(chalk7__default.default.dim(` Note: ${discoveryResult.message}
1150
- `));
1151
- } else if (discoveryResult.error === "auth_failed") {
1152
- console.log(chalk7__default.default.dim(` Note: ${discoveryResult.message}
323
+ if (!options.json) {
324
+ console.log(chalk10__default.default.dim(`Codex repository: ${chalk10__default.default.cyan(codexRepo)} (auto-discovered)
1153
325
  `));
1154
- } else if (discoveryResult.error === "org_not_found") {
1155
- console.log(chalk7__default.default.dim(` Note: ${discoveryResult.message}
326
+ }
327
+ } else if (!options.json) {
328
+ if (discoveryResult.message) {
329
+ console.log(chalk10__default.default.dim(` Note: ${discoveryResult.message}
1156
330
  `));
1157
331
  }
1158
332
  }
1159
333
  }
1160
334
  if (!codexRepo) {
1161
- console.log(chalk7__default.default.yellow(`\u26A0 Could not discover codex repository in organization '${org}'`));
1162
- console.log(chalk7__default.default.dim(" Use --codex-repo <name> to specify explicitly"));
1163
- console.log(chalk7__default.default.dim(" Expected naming convention: codex.{org}.{tld} (e.g., codex.fractary.com)\n"));
1164
335
  codexRepo = `codex.${org}.com`;
1165
- console.log(chalk7__default.default.dim(` Using default: ${chalk7__default.default.cyan(codexRepo)}
336
+ if (!options.json) {
337
+ console.log(chalk10__default.default.yellow(`\u26A0 Could not discover codex repository in organization '${org}'`));
338
+ console.log(chalk10__default.default.dim(` Using default: ${chalk10__default.default.cyan(codexRepo)}
1166
339
  `));
340
+ }
1167
341
  }
1168
- const configPath = path2__namespace.join(process.cwd(), ".fractary", "config.yaml");
1169
- const configExists = await fileExists(configPath);
1170
- if (configExists && !options.force) {
1171
- console.log(chalk7__default.default.yellow(`\u26A0 Configuration already exists at .fractary/config.yaml`));
1172
- console.log(chalk7__default.default.dim("Merging with existing configuration...\n"));
1173
- }
1174
- console.log("Creating directory structure...");
1175
- const dirs = [
1176
- ".fractary",
1177
- ".fractary/specs",
1178
- ".fractary/logs",
1179
- ".fractary/codex",
1180
- ".fractary/codex/cache"
1181
- ];
1182
- for (const dir of dirs) {
1183
- await fs4__namespace.mkdir(path2__namespace.join(process.cwd(), dir), { recursive: true });
1184
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(dir + "/"));
1185
- }
1186
- const gitignoreResult = await ensureCachePathIgnored(process.cwd(), ".fractary/codex/cache");
1187
- if (gitignoreResult.created) {
1188
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".fractary/.gitignore (created)"));
1189
- } else if (gitignoreResult.updated) {
1190
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".fractary/.gitignore (updated)"));
1191
- } else {
1192
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".fractary/.gitignore (exists)"));
1193
- }
1194
- console.log("\nInitializing configuration...");
1195
- const result = await initializeUnifiedConfig(
1196
- configPath,
1197
- org,
342
+ const result = await configManager.initializeCodexSection({
343
+ organization: org,
1198
344
  project,
1199
345
  codexRepo,
1200
- { force: options.force }
1201
- );
1202
- if (result.created) {
1203
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".fractary/config.yaml (created)"));
1204
- } else if (result.merged) {
1205
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".fractary/config.yaml (merged with existing)"));
1206
- }
1207
- if (options.mcp !== false) {
1208
- console.log("\nConfiguring MCP server...");
1209
- const mcpResult = await installMcpServer(process.cwd(), ".fractary/config.yaml");
1210
- if (mcpResult.alreadyInstalled) {
1211
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".mcp.json (already configured)"));
1212
- } else if (mcpResult.migrated) {
1213
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".mcp.json (migrated from old format)"));
1214
- if (mcpResult.backupPath) {
1215
- console.log(chalk7__default.default.dim(` Backup: ${path2__namespace.basename(mcpResult.backupPath)}`));
1216
- }
1217
- } else if (mcpResult.installed) {
1218
- console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".mcp.json (created)"));
346
+ syncPreset: options.syncPreset,
347
+ force: options.force,
348
+ skipMcp: options.mcp === false
349
+ });
350
+ if (options.json) {
351
+ console.log(
352
+ JSON.stringify(
353
+ {
354
+ success: true,
355
+ configPath: result.configPath,
356
+ codexSectionCreated: result.codexSectionCreated,
357
+ organization: org,
358
+ project,
359
+ codexRepo,
360
+ directories: result.directories,
361
+ gitignore: result.gitignore,
362
+ mcp: result.mcp
363
+ },
364
+ null,
365
+ 2
366
+ )
367
+ );
368
+ return;
369
+ }
370
+ console.log("Setting up codex directories...");
371
+ for (const dir of result.directories.created) {
372
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(dir + "/"));
373
+ }
374
+ for (const dir of result.directories.alreadyExisted) {
375
+ console.log(chalk10__default.default.dim(" " + dir + "/ (exists)"));
376
+ }
377
+ if (result.gitignore.created) {
378
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".fractary/.gitignore (created)"));
379
+ } else if (result.gitignore.updated) {
380
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".fractary/.gitignore (updated)"));
381
+ } else {
382
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".fractary/.gitignore (exists)"));
383
+ }
384
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".fractary/config.yaml (codex section added)"));
385
+ if (result.mcp) {
386
+ if (result.mcp.alreadyInstalled) {
387
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".mcp.json (already configured)"));
388
+ } else if (result.mcp.migrated) {
389
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".mcp.json (migrated from old format)"));
390
+ } else if (result.mcp.installed) {
391
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".mcp.json (created)"));
1219
392
  }
1220
393
  }
1221
- console.log(chalk7__default.default.green("\n\u2713 Unified configuration initialized successfully!\n"));
1222
- console.log(chalk7__default.default.bold("Configuration:"));
1223
- console.log(chalk7__default.default.dim(` Organization: ${org}`));
1224
- console.log(chalk7__default.default.dim(` Project: ${project}`));
1225
- console.log(chalk7__default.default.dim(` Codex Repository: ${codexRepo}`));
1226
- console.log(chalk7__default.default.dim(` Config: .fractary/config.yaml`));
1227
- console.log(chalk7__default.default.bold("\nFile plugin sources:"));
1228
- console.log(chalk7__default.default.dim(" - specs: .fractary/specs/ \u2192 S3"));
1229
- console.log(chalk7__default.default.dim(" - logs: .fractary/logs/ \u2192 S3"));
1230
- console.log(chalk7__default.default.bold("\nCodex plugin:"));
1231
- console.log(chalk7__default.default.dim(" - Cache: .fractary/codex/cache/"));
1232
- console.log(chalk7__default.default.dim(" - MCP Server: @fractary/codex-mcp (via npx)"));
1233
- console.log(chalk7__default.default.dim(" - Remotes: codex repo configured"));
1234
- console.log(chalk7__default.default.bold("\nGit Authentication:"));
1235
- console.log(chalk7__default.default.dim(" Codex sync uses your existing git credentials."));
1236
- console.log(chalk7__default.default.dim(" Ensure you have access to the codex repository:"));
1237
- console.log(chalk7__default.default.dim(` gh repo view ${org}/${codexRepo}`));
1238
- console.log(chalk7__default.default.dim(" Or set GITHUB_TOKEN environment variable."));
1239
- console.log(chalk7__default.default.bold("\nNext steps:"));
1240
- console.log(chalk7__default.default.dim(" 1. Restart Claude Code to load the MCP server"));
1241
- console.log(chalk7__default.default.dim(" 2. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
1242
- console.log(chalk7__default.default.dim(" 3. Configure AWS credentials for S3 access (if using file plugin)"));
1243
- console.log(chalk7__default.default.dim(" 4. Edit .fractary/config.yaml to add external project remotes"));
1244
- console.log(chalk7__default.default.dim(" 5. Reference docs via codex:// URIs (auto-fetched by MCP)"));
394
+ console.log(chalk10__default.default.green("\n\u2713 Codex configuration initialized successfully!\n"));
395
+ console.log(chalk10__default.default.bold("Configuration:"));
396
+ console.log(chalk10__default.default.dim(` Organization: ${org}`));
397
+ console.log(chalk10__default.default.dim(` Project: ${project}`));
398
+ console.log(chalk10__default.default.dim(` Codex Repository: ${codexRepo}`));
399
+ console.log(chalk10__default.default.bold("\nNext steps:"));
400
+ console.log(chalk10__default.default.dim(" 1. Restart Claude Code to load the MCP server"));
401
+ console.log(chalk10__default.default.dim(` 2. Verify codex repository access: gh repo view ${org}/${codexRepo}`));
402
+ console.log(chalk10__default.default.dim(" 3. Run first sync: /fractary-codex:sync --from-codex --dry-run"));
1245
403
  } catch (error) {
1246
- console.error(chalk7__default.default.red("Error:"), error.message);
404
+ if (options.json) {
405
+ console.log(JSON.stringify({ error: error.message }, null, 2));
406
+ } else {
407
+ console.error(chalk10__default.default.red("Error:"), error.message);
408
+ }
1247
409
  process.exit(1);
1248
410
  }
1249
411
  });
1250
412
  return cmd;
1251
413
  }
1252
414
 
415
+ // src/commands/config/update.ts
416
+ init_cjs_shims();
417
+ function configUpdateCommand() {
418
+ const cmd = new commander.Command("config-update");
419
+ cmd.description("Update codex configuration fields in .fractary/config.yaml").option("--org <slug>", "Update organization slug").option("--project <name>", "Update project name").option("--codex-repo <name>", "Update codex repository name").option("--sync-preset <name>", "Update sync preset (standard, minimal)").option("--no-mcp", "Skip MCP server update").option("--json", "Output as JSON").action(async (options) => {
420
+ try {
421
+ const configManager = codex.createConfigManager(process.cwd());
422
+ const updateOptions = {
423
+ skipMcp: options.mcp === false
424
+ };
425
+ let hasUpdates = false;
426
+ if (options.org !== void 0) {
427
+ updateOptions.organization = options.org;
428
+ hasUpdates = true;
429
+ }
430
+ if (options.project !== void 0) {
431
+ updateOptions.project = options.project;
432
+ hasUpdates = true;
433
+ }
434
+ if (options.codexRepo !== void 0) {
435
+ updateOptions.codexRepo = options.codexRepo;
436
+ hasUpdates = true;
437
+ }
438
+ if (options.syncPreset !== void 0) {
439
+ updateOptions.syncPreset = options.syncPreset;
440
+ hasUpdates = true;
441
+ }
442
+ if (!hasUpdates) {
443
+ if (options.json) {
444
+ console.log(JSON.stringify({ error: "No fields to update. Provide at least one of: --org, --project, --codex-repo, --sync-preset" }, null, 2));
445
+ } else {
446
+ console.error(chalk10__default.default.red("Error:"), "No fields to update. Provide at least one of: --org, --project, --codex-repo, --sync-preset");
447
+ }
448
+ process.exit(1);
449
+ }
450
+ if (!options.json) {
451
+ console.log(chalk10__default.default.blue("Updating codex configuration...\n"));
452
+ }
453
+ const result = await configManager.updateCodexSection(updateOptions);
454
+ if (options.json) {
455
+ console.log(
456
+ JSON.stringify(
457
+ {
458
+ success: true,
459
+ configPath: result.configPath,
460
+ fieldsUpdated: result.fieldsUpdated,
461
+ mcp: result.mcp
462
+ },
463
+ null,
464
+ 2
465
+ )
466
+ );
467
+ return;
468
+ }
469
+ if (result.fieldsUpdated.length === 0) {
470
+ console.log(chalk10__default.default.yellow("No fields were updated."));
471
+ return;
472
+ }
473
+ for (const field of result.fieldsUpdated) {
474
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(`Updated: ${field}`));
475
+ }
476
+ if (result.mcp) {
477
+ if (result.mcp.alreadyInstalled) {
478
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".mcp.json (already configured)"));
479
+ } else if (result.mcp.installed) {
480
+ console.log(chalk10__default.default.green("\u2713"), chalk10__default.default.dim(".mcp.json (updated)"));
481
+ }
482
+ }
483
+ console.log(chalk10__default.default.green("\n\u2713 Codex configuration updated successfully!"));
484
+ } catch (error) {
485
+ if (options.json) {
486
+ console.log(JSON.stringify({ error: error.message }, null, 2));
487
+ } else {
488
+ console.error(chalk10__default.default.red("Error:"), error.message);
489
+ }
490
+ process.exit(1);
491
+ }
492
+ });
493
+ return cmd;
494
+ }
495
+
496
+ // src/commands/config/validate.ts
497
+ init_cjs_shims();
498
+ function configValidateCommand() {
499
+ const cmd = new commander.Command("config-validate");
500
+ cmd.description("Validate codex configuration in .fractary/config.yaml (read-only)").option("--json", "Output as JSON").action(async (options) => {
501
+ try {
502
+ const configManager = codex.createConfigManager(process.cwd());
503
+ if (!options.json) {
504
+ console.log(chalk10__default.default.blue("Validating codex configuration...\n"));
505
+ }
506
+ const result = await configManager.validateCodexConfig();
507
+ if (options.json) {
508
+ console.log(JSON.stringify(result, null, 2));
509
+ if (!result.valid) {
510
+ process.exit(1);
511
+ }
512
+ return;
513
+ }
514
+ if (result.errors.length > 0) {
515
+ console.log(chalk10__default.default.red.bold("Errors:"));
516
+ for (const error of result.errors) {
517
+ console.log(chalk10__default.default.red(" \u2717"), `${error.field}: ${error.message}`);
518
+ }
519
+ console.log();
520
+ }
521
+ if (result.warnings.length > 0) {
522
+ console.log(chalk10__default.default.yellow.bold("Warnings:"));
523
+ for (const warning of result.warnings) {
524
+ console.log(chalk10__default.default.yellow(" \u26A0"), `${warning.field}: ${warning.message}`);
525
+ }
526
+ console.log();
527
+ }
528
+ if (result.valid) {
529
+ if (result.warnings.length === 0) {
530
+ console.log(chalk10__default.default.green("\u2713 Codex configuration is valid with no warnings."));
531
+ } else {
532
+ console.log(chalk10__default.default.green("\u2713 Codex configuration is valid"), chalk10__default.default.yellow(`(${result.warnings.length} warning${result.warnings.length > 1 ? "s" : ""})`));
533
+ }
534
+ } else {
535
+ console.log(chalk10__default.default.red(`\u2717 Codex configuration is invalid (${result.errors.length} error${result.errors.length > 1 ? "s" : ""})`));
536
+ process.exit(1);
537
+ }
538
+ } catch (error) {
539
+ if (options.json) {
540
+ console.log(JSON.stringify({ error: error.message }, null, 2));
541
+ } else {
542
+ console.error(chalk10__default.default.red("Error:"), error.message);
543
+ }
544
+ process.exit(1);
545
+ }
546
+ });
547
+ return cmd;
548
+ }
549
+
550
+ // src/commands/config/init.ts
551
+ init_cjs_shims();
552
+
1253
553
  // src/commands/document/index.ts
1254
554
  init_cjs_shims();
1255
555
 
@@ -1277,14 +577,14 @@ function documentFetchCommand() {
1277
577
  try {
1278
578
  const { validateUri } = await import('@fractary/codex');
1279
579
  if (!validateUri(uri)) {
1280
- console.error(chalk7__default.default.red("Error: Invalid URI format"));
1281
- console.log(chalk7__default.default.dim("Expected: codex://org/project/path/to/file.md"));
1282
- console.log(chalk7__default.default.dim("Example: codex://fractary/codex/docs/api.md"));
580
+ console.error(chalk10__default.default.red("Error: Invalid URI format"));
581
+ console.log(chalk10__default.default.dim("Expected: codex://org/project/path/to/file.md"));
582
+ console.log(chalk10__default.default.dim("Example: codex://fractary/codex/docs/api.md"));
1283
583
  process.exit(1);
1284
584
  }
1285
585
  const client = await getClient();
1286
586
  if (!options.json && !options.bypassCache) {
1287
- console.error(chalk7__default.default.dim(`Fetching ${uri}...`));
587
+ console.error(chalk10__default.default.dim(`Fetching ${uri}...`));
1288
588
  }
1289
589
  const result = await client.fetch(uri, {
1290
590
  bypassCache: options.bypassCache,
@@ -1304,31 +604,31 @@ function documentFetchCommand() {
1304
604
  };
1305
605
  console.log(JSON.stringify(output, null, 2));
1306
606
  } else if (options.output) {
1307
- await fs4__namespace.writeFile(options.output, result.content);
1308
- console.log(chalk7__default.default.green("\u2713"), `Written to ${options.output}`);
1309
- console.log(chalk7__default.default.dim(` Size: ${result.content.length} bytes`));
607
+ await fs2__namespace.writeFile(options.output, result.content);
608
+ console.log(chalk10__default.default.green("\u2713"), `Written to ${options.output}`);
609
+ console.log(chalk10__default.default.dim(` Size: ${result.content.length} bytes`));
1310
610
  if (result.fromCache) {
1311
- console.log(chalk7__default.default.dim(" Source: cache"));
611
+ console.log(chalk10__default.default.dim(" Source: cache"));
1312
612
  } else {
1313
- console.log(chalk7__default.default.dim(" Source: storage"));
613
+ console.log(chalk10__default.default.dim(" Source: storage"));
1314
614
  }
1315
615
  } else {
1316
616
  if (result.fromCache && !options.bypassCache) {
1317
- console.error(chalk7__default.default.green("\u2713"), chalk7__default.default.dim("from cache\n"));
617
+ console.error(chalk10__default.default.green("\u2713"), chalk10__default.default.dim("from cache\n"));
1318
618
  } else {
1319
- console.error(chalk7__default.default.green("\u2713"), chalk7__default.default.dim("fetched\n"));
619
+ console.error(chalk10__default.default.green("\u2713"), chalk10__default.default.dim("fetched\n"));
1320
620
  }
1321
621
  console.log(result.content.toString("utf-8"));
1322
622
  }
1323
623
  } catch (error) {
1324
- console.error(chalk7__default.default.red("Error:"), error.message);
624
+ console.error(chalk10__default.default.red("Error:"), error.message);
1325
625
  if (error.message.includes("Failed to load configuration")) {
1326
- console.log(chalk7__default.default.dim('\nRun "fractary-codex configure" to create a configuration.'));
626
+ console.log(chalk10__default.default.dim('\nRun "fractary-codex configure" to create a configuration.'));
1327
627
  } else if (error.message.includes("GITHUB_TOKEN")) {
1328
- console.log(chalk7__default.default.dim('\nSet your GitHub token: export GITHUB_TOKEN="your_token"'));
628
+ console.log(chalk10__default.default.dim('\nSet your GitHub token: export GITHUB_TOKEN="your_token"'));
1329
629
  } else if (error.message.includes("not found") || error.message.includes("404")) {
1330
- console.log(chalk7__default.default.dim("\nThe document may not exist or you may not have access."));
1331
- console.log(chalk7__default.default.dim("Check the URI and ensure your storage providers are configured correctly."));
630
+ console.log(chalk10__default.default.dim("\nThe document may not exist or you may not have access."));
631
+ console.log(chalk10__default.default.dim("Check the URI and ensure your storage providers are configured correctly."));
1332
632
  }
1333
633
  process.exit(1);
1334
634
  }
@@ -1341,55 +641,116 @@ init_cjs_shims();
1341
641
 
1342
642
  // src/commands/cache/list.ts
1343
643
  init_cjs_shims();
1344
- function formatSize(bytes) {
1345
- if (bytes < 1024) return `${bytes} B`;
1346
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1347
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
644
+ function formatTtl(seconds) {
645
+ if (seconds < 0) {
646
+ const expired = -seconds;
647
+ if (expired < 60) return chalk10__default.default.red(`expired ${expired}s ago`);
648
+ if (expired < 3600) return chalk10__default.default.red(`expired ${Math.floor(expired / 60)}m ago`);
649
+ return chalk10__default.default.red(`expired ${Math.floor(expired / 3600)}h ago`);
650
+ }
651
+ if (seconds < 60) return chalk10__default.default.green(`${seconds}s`);
652
+ if (seconds < 3600) return chalk10__default.default.green(`${Math.floor(seconds / 60)}m`);
653
+ if (seconds < 86400) return chalk10__default.default.yellow(`${Math.floor(seconds / 3600)}h`);
654
+ return chalk10__default.default.dim(`${Math.floor(seconds / 86400)}d`);
655
+ }
656
+ function formatStatus(status) {
657
+ switch (status) {
658
+ case "fresh":
659
+ return chalk10__default.default.green("fresh");
660
+ case "stale":
661
+ return chalk10__default.default.yellow("stale");
662
+ case "expired":
663
+ return chalk10__default.default.red("expired");
664
+ }
1348
665
  }
1349
666
  function cacheListCommand() {
1350
667
  const cmd = new commander.Command("cache-list");
1351
- cmd.description("List cache information").option("--json", "Output as JSON").action(async (options) => {
668
+ cmd.description("List cache entries").option("--json", "Output as JSON").option("--status <status>", "Filter by status (fresh, stale, expired, all)", "all").option("--limit <n>", "Maximum number of entries to show", parseInt).option("--sort <field>", "Sort by field (uri, size, createdAt, expiresAt)", "uri").option("--desc", "Sort in descending order").option("--verbose", "Show detailed entry information").action(async (options) => {
1352
669
  try {
1353
670
  const client = await getClient();
1354
- const stats = await client.getCacheStats();
1355
- if (stats.entryCount === 0) {
671
+ const listOptions = {
672
+ status: options.status,
673
+ limit: options.limit,
674
+ sortBy: options.sort,
675
+ sortDirection: options.desc ? "desc" : "asc"
676
+ };
677
+ const result = await client.listCacheEntries(listOptions);
678
+ if (result.total === 0) {
1356
679
  if (options.json) {
1357
- console.log(JSON.stringify({ entries: 0, message: "Cache is empty" }));
680
+ console.log(JSON.stringify({ entries: [], total: 0, message: "Cache is empty" }));
1358
681
  } else {
1359
- console.log(chalk7__default.default.yellow("Cache is empty."));
1360
- console.log(chalk7__default.default.dim("Fetch some documents to populate the cache."));
682
+ console.log(chalk10__default.default.yellow("Cache is empty."));
683
+ console.log(chalk10__default.default.dim("Fetch some documents to populate the cache."));
1361
684
  }
1362
685
  return;
1363
686
  }
1364
687
  if (options.json) {
1365
- console.log(JSON.stringify({
1366
- entryCount: stats.entryCount,
1367
- totalSize: stats.totalSize,
1368
- freshCount: stats.freshCount,
1369
- staleCount: stats.staleCount,
1370
- expiredCount: stats.expiredCount
1371
- }, null, 2));
688
+ console.log(JSON.stringify(result, null, 2));
1372
689
  return;
1373
690
  }
1374
- console.log(chalk7__default.default.bold("Cache Overview\n"));
1375
- console.log(chalk7__default.default.bold("Entries:"));
1376
- console.log(` Total: ${chalk7__default.default.cyan(stats.entryCount.toString())} entries`);
1377
- console.log(` Fresh: ${chalk7__default.default.green(stats.freshCount.toString())} entries`);
1378
- console.log(` Stale: ${stats.staleCount > 0 ? chalk7__default.default.yellow(stats.staleCount.toString()) : chalk7__default.default.dim("0")} entries`);
1379
- console.log(` Expired: ${stats.expiredCount > 0 ? chalk7__default.default.red(stats.expiredCount.toString()) : chalk7__default.default.dim("0")} entries`);
1380
- console.log("");
1381
- console.log(chalk7__default.default.bold("Storage:"));
1382
- console.log(` Total size: ${chalk7__default.default.cyan(formatSize(stats.totalSize))}`);
1383
- console.log("");
1384
- const healthPercent = stats.entryCount > 0 ? stats.freshCount / stats.entryCount * 100 : 100;
1385
- const healthColor = healthPercent > 80 ? chalk7__default.default.green : healthPercent > 50 ? chalk7__default.default.yellow : chalk7__default.default.red;
1386
- console.log(`Cache health: ${healthColor(`${healthPercent.toFixed(0)}% fresh`)}`);
691
+ console.log(chalk10__default.default.bold(`Cache Entries (${result.entries.length} of ${result.total})
692
+ `));
693
+ if (options.verbose) {
694
+ for (const entry of result.entries) {
695
+ console.log(chalk10__default.default.cyan(entry.uri));
696
+ console.log(` Status: ${formatStatus(entry.status)}`);
697
+ console.log(` Size: ${codex.formatBytes(entry.size)}`);
698
+ console.log(` Content-Type: ${chalk10__default.default.dim(entry.contentType)}`);
699
+ console.log(` TTL: ${formatTtl(entry.remainingTtl)}`);
700
+ console.log(` In Memory: ${entry.inMemory ? chalk10__default.default.green("yes") : chalk10__default.default.dim("no")}`);
701
+ console.log("");
702
+ }
703
+ } else {
704
+ const maxUriLen = Math.min(
705
+ 60,
706
+ Math.max(...result.entries.map((e) => e.uri.length))
707
+ );
708
+ console.log(
709
+ chalk10__default.default.dim(
710
+ `${"URI".padEnd(maxUriLen)} ${"STATUS".padEnd(8)} ${"SIZE".padEnd(10)} TTL`
711
+ )
712
+ );
713
+ console.log(chalk10__default.default.dim("\u2500".repeat(maxUriLen + 35)));
714
+ for (const entry of result.entries) {
715
+ const uri = entry.uri.length > maxUriLen ? "..." + entry.uri.slice(-(maxUriLen - 3)) : entry.uri.padEnd(maxUriLen);
716
+ console.log(
717
+ `${chalk10__default.default.cyan(uri)} ${formatStatus(entry.status).padEnd(17)} ${codex.formatBytes(entry.size).padEnd(10)} ${formatTtl(entry.remainingTtl)}`
718
+ );
719
+ }
720
+ }
721
+ if (result.hasMore) {
722
+ console.log("");
723
+ console.log(
724
+ chalk10__default.default.dim(
725
+ `Showing ${result.entries.length} of ${result.total} entries. Use --limit to see more.`
726
+ )
727
+ );
728
+ }
729
+ const stats = await client.getCacheStats();
1387
730
  console.log("");
1388
- console.log(chalk7__default.default.dim("Note: Individual cache entries are managed by the SDK."));
1389
- console.log(chalk7__default.default.dim('Use "fractary-codex cache-stats" for detailed statistics.'));
1390
- console.log(chalk7__default.default.dim('Use "fractary-codex cache-clear" to clear cache entries.'));
731
+ console.log(chalk10__default.default.dim("\u2500".repeat(60)));
732
+ console.log(
733
+ chalk10__default.default.dim(
734
+ `Total: ${stats.entryCount} entries (${codex.formatBytes(stats.totalSize)}) | ${stats.freshCount} fresh, ${stats.staleCount} stale, ${stats.expiredCount} expired`
735
+ )
736
+ );
1391
737
  } catch (error) {
1392
- console.error(chalk7__default.default.red("Error:"), error.message);
738
+ const errorMessage = error.message || "Unknown error";
739
+ if (errorMessage.includes("ENOENT") || errorMessage.includes("not found")) {
740
+ console.error(chalk10__default.default.red("Error:"), "Cache directory not accessible");
741
+ console.error(chalk10__default.default.dim('Run "fractary-codex configure" to initialize the cache.'));
742
+ } else if (errorMessage.includes("EACCES") || errorMessage.includes("permission")) {
743
+ console.error(chalk10__default.default.red("Error:"), "Permission denied accessing cache directory");
744
+ console.error(chalk10__default.default.dim("Check file permissions for .fractary/codex/cache/"));
745
+ } else if (errorMessage.includes("ENOSPC")) {
746
+ console.error(chalk10__default.default.red("Error:"), "No space left on device");
747
+ console.error(chalk10__default.default.dim("Free up disk space and try again."));
748
+ } else if (errorMessage.includes("parse") || errorMessage.includes("JSON")) {
749
+ console.error(chalk10__default.default.red("Error:"), "Failed to parse cache metadata");
750
+ console.error(chalk10__default.default.dim('The cache may be corrupted. Try "fractary-codex cache-clear".'));
751
+ } else {
752
+ console.error(chalk10__default.default.red("Error:"), errorMessage);
753
+ }
1393
754
  process.exit(1);
1394
755
  }
1395
756
  });
@@ -1405,7 +766,7 @@ function cacheClearCommand() {
1405
766
  const client = await getClient();
1406
767
  const statsBefore = await client.getCacheStats();
1407
768
  if (statsBefore.entryCount === 0) {
1408
- console.log(chalk7__default.default.yellow("Cache is already empty. Nothing to clear."));
769
+ console.log(chalk10__default.default.yellow("Cache is already empty. Nothing to clear."));
1409
770
  return;
1410
771
  }
1411
772
  let pattern;
@@ -1414,63 +775,53 @@ function cacheClearCommand() {
1414
775
  } else if (options.pattern) {
1415
776
  pattern = options.pattern;
1416
777
  } else {
1417
- console.log(chalk7__default.default.yellow("Please specify what to clear:"));
1418
- console.log(chalk7__default.default.dim(" --all Clear entire cache"));
1419
- console.log(chalk7__default.default.dim(' --pattern Clear entries matching pattern (e.g., "codex://fractary/*")'));
778
+ console.log(chalk10__default.default.yellow("Please specify what to clear:"));
779
+ console.log(chalk10__default.default.dim(" --all Clear entire cache"));
780
+ console.log(chalk10__default.default.dim(' --pattern Clear entries matching pattern (e.g., "codex://fractary/*")'));
1420
781
  console.log("");
1421
- console.log(chalk7__default.default.dim("Examples:"));
1422
- console.log(chalk7__default.default.dim(" fractary-codex cache-clear --all"));
1423
- console.log(chalk7__default.default.dim(' fractary-codex cache-clear --pattern "codex://fractary/cli/*"'));
782
+ console.log(chalk10__default.default.dim("Examples:"));
783
+ console.log(chalk10__default.default.dim(" fractary-codex cache-clear --all"));
784
+ console.log(chalk10__default.default.dim(' fractary-codex cache-clear --pattern "codex://fractary/cli/*"'));
1424
785
  return;
1425
786
  }
1426
787
  if (options.dryRun) {
1427
- console.log(chalk7__default.default.blue("Dry run - would clear:\n"));
788
+ console.log(chalk10__default.default.blue("Dry run - would clear:\n"));
1428
789
  if (pattern) {
1429
- console.log(chalk7__default.default.dim(` Pattern: ${pattern}`));
1430
- console.log(chalk7__default.default.dim(` This would invalidate matching cache entries`));
790
+ console.log(chalk10__default.default.dim(` Pattern: ${pattern}`));
791
+ console.log(chalk10__default.default.dim(` This would invalidate matching cache entries`));
1431
792
  } else {
1432
- console.log(chalk7__default.default.dim(` All cache entries (${statsBefore.entryCount} entries)`));
793
+ console.log(chalk10__default.default.dim(` All cache entries (${statsBefore.entryCount} entries)`));
1433
794
  }
1434
- console.log(chalk7__default.default.dim(`
1435
- Total size: ${formatSize2(statsBefore.totalSize)}`));
795
+ console.log(chalk10__default.default.dim(`
796
+ Total size: ${codex.formatBytes(statsBefore.totalSize)}`));
1436
797
  return;
1437
798
  }
1438
799
  if (pattern) {
1439
- console.log(chalk7__default.default.blue(`Clearing cache entries matching pattern: ${pattern}
800
+ console.log(chalk10__default.default.blue(`Clearing cache entries matching pattern: ${pattern}
1440
801
  `));
1441
802
  await client.invalidateCache(pattern);
1442
803
  } else {
1443
- console.log(chalk7__default.default.blue(`Clearing entire cache (${statsBefore.entryCount} entries)...
804
+ console.log(chalk10__default.default.blue(`Clearing entire cache (${statsBefore.entryCount} entries)...
1444
805
  `));
1445
806
  await client.invalidateCache();
1446
807
  }
1447
808
  const statsAfter = await client.getCacheStats();
1448
809
  const entriesCleared = statsBefore.entryCount - statsAfter.entryCount;
1449
810
  const sizeFreed = statsBefore.totalSize - statsAfter.totalSize;
1450
- console.log(chalk7__default.default.green(`\u2713 Cleared ${entriesCleared} entries (${formatSize2(sizeFreed)} freed)`));
811
+ console.log(chalk10__default.default.green(`\u2713 Cleared ${entriesCleared} entries (${codex.formatBytes(sizeFreed)} freed)`));
1451
812
  if (statsAfter.entryCount > 0) {
1452
- console.log(chalk7__default.default.dim(` Remaining: ${statsAfter.entryCount} entries (${formatSize2(statsAfter.totalSize)})`));
813
+ console.log(chalk10__default.default.dim(` Remaining: ${statsAfter.entryCount} entries (${codex.formatBytes(statsAfter.totalSize)})`));
1453
814
  }
1454
815
  } catch (error) {
1455
- console.error(chalk7__default.default.red("Error:"), error.message);
816
+ console.error(chalk10__default.default.red("Error:"), error.message);
1456
817
  process.exit(1);
1457
818
  }
1458
819
  });
1459
820
  return cmd;
1460
821
  }
1461
- function formatSize2(bytes) {
1462
- if (bytes < 1024) return `${bytes} B`;
1463
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1464
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1465
- }
1466
822
 
1467
823
  // src/commands/cache/stats.ts
1468
824
  init_cjs_shims();
1469
- function formatSize3(bytes) {
1470
- if (bytes < 1024) return `${bytes} B`;
1471
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1472
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1473
- }
1474
825
  function cacheStatsCommand() {
1475
826
  const cmd = new commander.Command("cache-stats");
1476
827
  cmd.description("Display cache statistics").option("--json", "Output as JSON").action(async (options) => {
@@ -1481,25 +832,25 @@ function cacheStatsCommand() {
1481
832
  console.log(JSON.stringify(stats, null, 2));
1482
833
  return;
1483
834
  }
1484
- console.log(chalk7__default.default.bold("Cache Statistics\n"));
1485
- console.log(chalk7__default.default.bold("Overview"));
1486
- console.log(` Total entries: ${chalk7__default.default.cyan(stats.entryCount.toString())}`);
1487
- console.log(` Total size: ${chalk7__default.default.cyan(formatSize3(stats.totalSize))}`);
1488
- console.log(` Fresh entries: ${chalk7__default.default.green(stats.freshCount.toString())}`);
1489
- console.log(` Stale entries: ${stats.staleCount > 0 ? chalk7__default.default.yellow(stats.staleCount.toString()) : chalk7__default.default.dim("0")}`);
1490
- console.log(` Expired entries: ${stats.expiredCount > 0 ? chalk7__default.default.red(stats.expiredCount.toString()) : chalk7__default.default.dim("0")}`);
835
+ console.log(chalk10__default.default.bold("Cache Statistics\n"));
836
+ console.log(chalk10__default.default.bold("Overview"));
837
+ console.log(` Total entries: ${chalk10__default.default.cyan(stats.entryCount.toString())}`);
838
+ console.log(` Total size: ${chalk10__default.default.cyan(codex.formatBytes(stats.totalSize))}`);
839
+ console.log(` Fresh entries: ${chalk10__default.default.green(stats.freshCount.toString())}`);
840
+ console.log(` Stale entries: ${stats.staleCount > 0 ? chalk10__default.default.yellow(stats.staleCount.toString()) : chalk10__default.default.dim("0")}`);
841
+ console.log(` Expired entries: ${stats.expiredCount > 0 ? chalk10__default.default.red(stats.expiredCount.toString()) : chalk10__default.default.dim("0")}`);
1491
842
  console.log("");
1492
843
  const healthPercent = stats.entryCount > 0 ? stats.freshCount / stats.entryCount * 100 : 100;
1493
- const healthColor = healthPercent > 80 ? chalk7__default.default.green : healthPercent > 50 ? chalk7__default.default.yellow : chalk7__default.default.red;
844
+ const healthColor = healthPercent > 80 ? chalk10__default.default.green : healthPercent > 50 ? chalk10__default.default.yellow : chalk10__default.default.red;
1494
845
  console.log(`Cache health: ${healthColor(`${healthPercent.toFixed(0)}% fresh`)}`);
1495
846
  if (stats.expiredCount > 0) {
1496
- console.log(chalk7__default.default.dim('\nRun "fractary-codex cache-clear --pattern <pattern>" to clean up entries.'));
847
+ console.log(chalk10__default.default.dim('\nRun "fractary-codex cache-clear --pattern <pattern>" to clean up entries.'));
1497
848
  }
1498
849
  if (stats.entryCount === 0) {
1499
- console.log(chalk7__default.default.dim("\nNo cached entries. Fetch some documents to populate the cache."));
850
+ console.log(chalk10__default.default.dim("\nNo cached entries. Fetch some documents to populate the cache."));
1500
851
  }
1501
852
  } catch (error) {
1502
- console.error(chalk7__default.default.red("Error:"), error.message);
853
+ console.error(chalk10__default.default.red("Error:"), error.message);
1503
854
  process.exit(1);
1504
855
  }
1505
856
  });
@@ -1508,239 +859,81 @@ function cacheStatsCommand() {
1508
859
 
1509
860
  // src/commands/cache/health.ts
1510
861
  init_cjs_shims();
1511
- init_migrate_config();
1512
- async function fileExists2(filePath) {
1513
- try {
1514
- await fs4__namespace.access(filePath);
1515
- return true;
1516
- } catch {
1517
- return false;
1518
- }
1519
- }
1520
- async function checkConfiguration() {
1521
- const configPath = path2__namespace.join(process.cwd(), ".fractary", "config.yaml");
1522
- const legacyConfigPath = path2__namespace.join(process.cwd(), ".fractary", "plugins", "codex", "config.json");
1523
- try {
1524
- if (!await fileExists2(configPath)) {
1525
- if (await fileExists2(legacyConfigPath)) {
1526
- return {
1527
- name: "Configuration",
1528
- status: "warn",
1529
- message: "Legacy JSON configuration detected",
1530
- details: "Migration from legacy JSON format may be required"
1531
- };
1532
- }
1533
- return {
1534
- name: "Configuration",
1535
- status: "fail",
1536
- message: "No configuration found",
1537
- details: 'Run "fractary-codex configure" to create configuration'
1538
- };
1539
- }
1540
- const config = await codex.readCodexConfig(configPath);
1541
- if (!config.organization) {
1542
- return {
1543
- name: "Configuration",
1544
- status: "warn",
1545
- message: "No organization configured",
1546
- details: "Organization slug is required"
1547
- };
1548
- }
1549
- const providerCount = config.storage?.length || 0;
1550
- if (providerCount === 0) {
1551
- return {
1552
- name: "Configuration",
1553
- status: "warn",
1554
- message: "No storage providers configured",
1555
- details: "At least one storage provider is recommended"
1556
- };
1557
- }
1558
- return {
1559
- name: "Configuration",
1560
- status: "pass",
1561
- message: "Valid YAML configuration",
1562
- details: `Organization: ${config.organization}, ${providerCount} storage provider(s)`
1563
- };
1564
- } catch (error) {
1565
- return {
1566
- name: "Configuration",
1567
- status: "fail",
1568
- message: "Invalid configuration",
1569
- details: error.message
1570
- };
1571
- }
1572
- }
1573
- async function checkSDKClient() {
1574
- try {
1575
- const client = await getClient();
1576
- const organization = client.getOrganization();
1577
- return {
1578
- name: "SDK Client",
1579
- status: "pass",
1580
- message: "CodexClient initialized successfully",
1581
- details: `Organization: ${organization}`
1582
- };
1583
- } catch (error) {
1584
- return {
1585
- name: "SDK Client",
1586
- status: "fail",
1587
- message: "Failed to initialize CodexClient",
1588
- details: error.message
1589
- };
1590
- }
1591
- }
1592
- async function checkCache() {
1593
- try {
1594
- const client = await getClient();
1595
- const stats = await client.getCacheStats();
1596
- if (stats.entryCount === 0) {
1597
- return {
1598
- name: "Cache",
1599
- status: "warn",
1600
- message: "Cache is empty",
1601
- details: "Fetch some documents to populate cache"
1602
- };
1603
- }
1604
- const healthPercent = stats.entryCount > 0 ? stats.freshCount / stats.entryCount * 100 : 100;
1605
- if (healthPercent < 50) {
1606
- return {
1607
- name: "Cache",
1608
- status: "warn",
1609
- message: `${stats.entryCount} entries (${healthPercent.toFixed(0)}% fresh)`,
1610
- details: `${stats.expiredCount} expired, ${stats.staleCount} stale`
1611
- };
1612
- }
1613
- return {
1614
- name: "Cache",
1615
- status: "pass",
1616
- message: `${stats.entryCount} entries (${healthPercent.toFixed(0)}% fresh)`,
1617
- details: `${formatSize4(stats.totalSize)} total`
1618
- };
1619
- } catch (error) {
1620
- return {
1621
- name: "Cache",
1622
- status: "fail",
1623
- message: "Cache check failed",
1624
- details: error.message
1625
- };
1626
- }
1627
- }
1628
- async function checkStorage() {
1629
- const configPath = path2__namespace.join(process.cwd(), ".fractary", "config.yaml");
1630
- try {
1631
- const config = await codex.readCodexConfig(configPath);
1632
- const providers = config.storage || [];
1633
- if (providers.length === 0) {
1634
- return {
1635
- name: "Storage",
1636
- status: "warn",
1637
- message: "No storage providers configured",
1638
- details: "Configure at least one provider in .fractary/config.yaml"
1639
- };
1640
- }
1641
- const providerTypes = providers.map((p) => p.type).join(", ");
1642
- const hasGitHub = providers.some((p) => p.type === "github");
1643
- if (hasGitHub && !process.env.GITHUB_TOKEN) {
1644
- return {
1645
- name: "Storage",
1646
- status: "warn",
1647
- message: `${providers.length} provider(s): ${providerTypes}`,
1648
- details: "GITHUB_TOKEN not set (required for GitHub provider)"
1649
- };
1650
- }
1651
- return {
1652
- name: "Storage",
1653
- status: "pass",
1654
- message: `${providers.length} provider(s): ${providerTypes}`,
1655
- details: "All configured providers available"
1656
- };
1657
- } catch (error) {
1658
- return {
1659
- name: "Storage",
1660
- status: "fail",
1661
- message: "Storage check failed",
1662
- details: error.message
1663
- };
1664
- }
1665
- }
1666
- async function checkTypes() {
1667
- try {
1668
- const client = await getClient();
1669
- const registry = client.getTypeRegistry();
1670
- const allTypes = registry.list();
1671
- const builtinCount = allTypes.filter((t) => registry.isBuiltIn(t.name)).length;
1672
- const customCount = allTypes.length - builtinCount;
1673
- return {
1674
- name: "Type Registry",
1675
- status: "pass",
1676
- message: `${allTypes.length} types registered`,
1677
- details: `${builtinCount} built-in, ${customCount} custom`
1678
- };
1679
- } catch (error) {
1680
- return {
1681
- name: "Type Registry",
1682
- status: "fail",
1683
- message: "Type registry check failed",
1684
- details: error.message
1685
- };
1686
- }
1687
- }
1688
- function formatSize4(bytes) {
1689
- if (bytes < 1024) return `${bytes} B`;
1690
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1691
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1692
- }
1693
862
  function cacheHealthCommand() {
1694
863
  const cmd = new commander.Command("cache-health");
1695
864
  cmd.description("Run diagnostics on codex setup").option("--json", "Output as JSON").action(async (options) => {
1696
865
  try {
866
+ const healthChecker = codex.createHealthChecker({
867
+ projectRoot: process.cwd()
868
+ });
1697
869
  const checks = [];
1698
- checks.push(await checkConfiguration());
1699
- checks.push(await checkSDKClient());
1700
- checks.push(await checkCache());
1701
- checks.push(await checkStorage());
1702
- checks.push(await checkTypes());
1703
- const passed = checks.filter((c) => c.status === "pass").length;
1704
- const warned = checks.filter((c) => c.status === "warn").length;
1705
- const failed = checks.filter((c) => c.status === "fail").length;
870
+ checks.push(await healthChecker.checkConfiguration());
871
+ checks.push(await healthChecker.checkStorage());
872
+ try {
873
+ const client = await getClient();
874
+ const organization = client.getOrganization();
875
+ checks.push({
876
+ name: "SDK Client",
877
+ status: "pass",
878
+ message: "CodexClient initialized successfully",
879
+ details: `Organization: ${organization}`
880
+ });
881
+ const cacheStats = await client.getCacheStats();
882
+ checks.push(healthChecker.checkCacheFromStats(cacheStats));
883
+ const registry = client.getTypeRegistry();
884
+ checks.push(healthChecker.checkTypesFromRegistry(registry));
885
+ } catch (error) {
886
+ checks.push({
887
+ name: "SDK Client",
888
+ status: "fail",
889
+ message: "Failed to initialize CodexClient",
890
+ details: error.message
891
+ });
892
+ checks.push({
893
+ name: "Cache",
894
+ status: "warn",
895
+ message: "Cache check skipped",
896
+ details: "SDK client not available"
897
+ });
898
+ checks.push({
899
+ name: "Type Registry",
900
+ status: "warn",
901
+ message: "Type registry check skipped",
902
+ details: "SDK client not available"
903
+ });
904
+ }
905
+ const result = healthChecker.summarize(checks);
1706
906
  if (options.json) {
1707
- console.log(JSON.stringify({
1708
- summary: {
1709
- total: checks.length,
1710
- passed,
1711
- warned,
1712
- failed,
1713
- healthy: failed === 0
1714
- },
1715
- checks
1716
- }, null, 2));
907
+ console.log(JSON.stringify(result, null, 2));
1717
908
  return;
1718
909
  }
1719
- console.log(chalk7__default.default.bold("Codex Health Check\n"));
1720
- for (const check of checks) {
1721
- const icon = check.status === "pass" ? chalk7__default.default.green("\u2713") : check.status === "warn" ? chalk7__default.default.yellow("\u26A0") : chalk7__default.default.red("\u2717");
1722
- const statusColor = check.status === "pass" ? chalk7__default.default.green : check.status === "warn" ? chalk7__default.default.yellow : chalk7__default.default.red;
1723
- console.log(`${icon} ${chalk7__default.default.bold(check.name)}`);
910
+ console.log(chalk10__default.default.bold("Codex Health Check\n"));
911
+ for (const check of result.checks) {
912
+ const icon = check.status === "pass" ? chalk10__default.default.green("\u2713") : check.status === "warn" ? chalk10__default.default.yellow("\u26A0") : chalk10__default.default.red("\u2717");
913
+ const statusColor = check.status === "pass" ? chalk10__default.default.green : check.status === "warn" ? chalk10__default.default.yellow : chalk10__default.default.red;
914
+ console.log(`${icon} ${chalk10__default.default.bold(check.name)}`);
1724
915
  console.log(` ${statusColor(check.message)}`);
1725
916
  if (check.details) {
1726
- console.log(` ${chalk7__default.default.dim(check.details)}`);
917
+ console.log(` ${chalk10__default.default.dim(check.details)}`);
1727
918
  }
1728
919
  console.log("");
1729
920
  }
1730
- console.log(chalk7__default.default.dim("\u2500".repeat(60)));
1731
- const overallStatus = failed > 0 ? chalk7__default.default.red("UNHEALTHY") : warned > 0 ? chalk7__default.default.yellow("DEGRADED") : chalk7__default.default.green("HEALTHY");
921
+ console.log(chalk10__default.default.dim("\u2500".repeat(60)));
922
+ const overallStatus = result.summary.status === "unhealthy" ? chalk10__default.default.red("UNHEALTHY") : result.summary.status === "degraded" ? chalk10__default.default.yellow("DEGRADED") : chalk10__default.default.green("HEALTHY");
1732
923
  console.log(`Status: ${overallStatus}`);
1733
- console.log(chalk7__default.default.dim(`${passed} passed, ${warned} warnings, ${failed} failed`));
1734
- if (failed > 0 || warned > 0) {
924
+ console.log(
925
+ chalk10__default.default.dim(`${result.summary.passed} passed, ${result.summary.warned} warnings, ${result.summary.failed} failed`)
926
+ );
927
+ if (result.summary.failed > 0 || result.summary.warned > 0) {
1735
928
  console.log("");
1736
- console.log(chalk7__default.default.dim("Run checks individually for more details:"));
1737
- console.log(chalk7__default.default.dim(" fractary-codex cache-stats"));
929
+ console.log(chalk10__default.default.dim("Run checks individually for more details:"));
930
+ console.log(chalk10__default.default.dim(" fractary-codex cache-stats"));
1738
931
  }
1739
- if (failed > 0) {
932
+ if (result.summary.failed > 0) {
1740
933
  process.exit(1);
1741
934
  }
1742
935
  } catch (error) {
1743
- console.error(chalk7__default.default.red("Error:"), error.message);
936
+ console.error(chalk10__default.default.red("Error:"), error.message);
1744
937
  process.exit(1);
1745
938
  }
1746
939
  });
@@ -1749,7 +942,11 @@ function cacheHealthCommand() {
1749
942
 
1750
943
  // src/commands/sync.ts
1751
944
  init_cjs_shims();
1752
- init_migrate_config();
945
+
946
+ // src/config/migrate-config.ts
947
+ init_cjs_shims();
948
+
949
+ // src/commands/sync.ts
1753
950
  function getEnvironmentBranch(config, env) {
1754
951
  const envMap = config.sync?.environments || {
1755
952
  dev: "develop",
@@ -1759,26 +956,17 @@ function getEnvironmentBranch(config, env) {
1759
956
  };
1760
957
  return envMap[env] || env;
1761
958
  }
1762
- function formatBytes(bytes) {
1763
- if (bytes < 1024) return `${bytes} B`;
1764
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1765
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1766
- }
1767
- function formatDuration(ms) {
1768
- if (ms < 1e3) return `${ms}ms`;
1769
- return `${(ms / 1e3).toFixed(1)}s`;
1770
- }
1771
959
  function syncCommand() {
1772
960
  const cmd = new commander.Command("sync");
1773
961
  cmd.description("Sync single project with codex repository").argument("[name]", "Project name (auto-detected if not provided)").option("--env <env>", "Target environment (dev/test/staging/prod)", "prod").option("--dry-run", "Show what would sync without executing").option("--direction <dir>", "Sync direction (to-codex/from-codex/bidirectional)", "bidirectional").option("--include <pattern>", "Include files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--exclude <pattern>", "Exclude files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--force", "Force sync without checking timestamps").option("--json", "Output as JSON").option("--work-id <id>", "GitHub issue number or URL to scope sync to").action(async (name, options) => {
1774
962
  try {
1775
- const configPath = path2__namespace.join(process.cwd(), ".fractary", "config.yaml");
963
+ const configPath = path3__namespace.join(process.cwd(), ".fractary", "config.yaml");
1776
964
  let config;
1777
965
  try {
1778
966
  config = await codex.readCodexConfig(configPath);
1779
967
  } catch (error) {
1780
- console.error(chalk7__default.default.red("Error:"), "Codex not initialized.");
1781
- console.log(chalk7__default.default.dim('Run "fractary-codex configure" first.'));
968
+ console.error(chalk10__default.default.red("Error:"), "Codex not initialized.");
969
+ console.log(chalk10__default.default.dim('Run "fractary-codex configure" first.'));
1782
970
  process.exit(1);
1783
971
  }
1784
972
  const { createSyncManager, createLocalStorage, detectCurrentProject } = await import('@fractary/codex');
@@ -1791,14 +979,14 @@ function syncCommand() {
1791
979
  projectName = detected.project || void 0;
1792
980
  }
1793
981
  if (!projectName) {
1794
- console.error(chalk7__default.default.red("Error:"), "Could not determine project name.");
1795
- console.log(chalk7__default.default.dim("Provide project name as argument, set codex.project in config, or run from a git repository."));
982
+ console.error(chalk10__default.default.red("Error:"), "Could not determine project name.");
983
+ console.log(chalk10__default.default.dim("Provide project name as argument, set codex.project in config, or run from a git repository."));
1796
984
  process.exit(1);
1797
985
  }
1798
986
  const validDirections = ["to-codex", "from-codex", "bidirectional"];
1799
987
  if (!validDirections.includes(options.direction)) {
1800
- console.error(chalk7__default.default.red("Error:"), `Invalid direction: ${options.direction}`);
1801
- console.log(chalk7__default.default.dim("Valid options: to-codex, from-codex, bidirectional"));
988
+ console.error(chalk10__default.default.red("Error:"), `Invalid direction: ${options.direction}`);
989
+ console.log(chalk10__default.default.dim("Valid options: to-codex, from-codex, bidirectional"));
1802
990
  process.exit(1);
1803
991
  }
1804
992
  const direction = options.direction;
@@ -1809,7 +997,7 @@ function syncCommand() {
1809
997
  const syncManager = createSyncManager({
1810
998
  localStorage,
1811
999
  config: config.sync,
1812
- manifestPath: path2__namespace.join(process.cwd(), ".fractary", ".codex-sync-manifest.json")
1000
+ manifestPath: path3__namespace.join(process.cwd(), ".fractary", ".codex-sync-manifest.json")
1813
1001
  });
1814
1002
  const defaultToCodexPatterns = [
1815
1003
  "docs/**/*.md",
@@ -1839,13 +1027,13 @@ function syncCommand() {
1839
1027
  });
1840
1028
  matches.forEach((match) => matchedFilePaths.add(match));
1841
1029
  } catch (error) {
1842
- console.error(chalk7__default.default.yellow(`Warning: Invalid pattern "${pattern}": ${error.message}`));
1030
+ console.error(chalk10__default.default.yellow(`Warning: Invalid pattern "${pattern}": ${error.message}`));
1843
1031
  }
1844
1032
  }
1845
1033
  const targetFiles = await Promise.all(
1846
1034
  Array.from(matchedFilePaths).map(async (filePath) => {
1847
- const fullPath = path2__namespace.join(sourceDir, filePath);
1848
- const stats = await import('fs/promises').then((fs8) => fs8.stat(fullPath));
1035
+ const fullPath = path3__namespace.join(sourceDir, filePath);
1036
+ const stats = await import('fs/promises').then((fs3) => fs3.stat(fullPath));
1849
1037
  return {
1850
1038
  path: filePath,
1851
1039
  size: stats.size,
@@ -1869,14 +1057,14 @@ function syncCommand() {
1869
1057
  try {
1870
1058
  const { ensureCodexCloned: ensureCodexCloned2 } = await Promise.resolve().then(() => (init_codex_repository(), codex_repository_exports));
1871
1059
  if (!options.json) {
1872
- console.log(chalk7__default.default.blue("\u2139 Cloning/updating codex repository..."));
1060
+ console.log(chalk10__default.default.blue("\u2139 Cloning/updating codex repository..."));
1873
1061
  }
1874
1062
  codexRepoPath = await ensureCodexCloned2(config, {
1875
1063
  branch: targetBranch
1876
1064
  });
1877
1065
  if (!options.json) {
1878
- console.log(chalk7__default.default.dim(` Codex cloned to: ${codexRepoPath}`));
1879
- console.log(chalk7__default.default.dim(" Scanning for files routing to this project...\n"));
1066
+ console.log(chalk10__default.default.dim(` Codex cloned to: ${codexRepoPath}`));
1067
+ console.log(chalk10__default.default.dim(" Scanning for files routing to this project...\n"));
1880
1068
  } else {
1881
1069
  console.log(JSON.stringify({
1882
1070
  info: "Routing-aware sync: cloned codex repository and scanning for files targeting this project",
@@ -1884,29 +1072,29 @@ function syncCommand() {
1884
1072
  }, null, 2));
1885
1073
  }
1886
1074
  } catch (error) {
1887
- console.error(chalk7__default.default.red("Error:"), "Failed to clone codex repository");
1888
- console.error(chalk7__default.default.dim(` ${error.message}`));
1889
- console.log(chalk7__default.default.yellow("\nTroubleshooting:"));
1075
+ console.error(chalk10__default.default.red("Error:"), "Failed to clone codex repository");
1076
+ console.error(chalk10__default.default.dim(` ${error.message}`));
1077
+ console.log(chalk10__default.default.yellow("\nTroubleshooting:"));
1890
1078
  if (error.message.includes("Git command not found")) {
1891
- console.log(chalk7__default.default.dim(" Git is not installed or not in PATH."));
1892
- console.log(chalk7__default.default.dim(" Install git: https://git-scm.com/downloads"));
1079
+ console.log(chalk10__default.default.dim(" Git is not installed or not in PATH."));
1080
+ console.log(chalk10__default.default.dim(" Install git: https://git-scm.com/downloads"));
1893
1081
  } else if (error.message.includes("authentication failed") || error.message.includes("Authentication failed")) {
1894
- console.log(chalk7__default.default.dim(" GitHub authentication is required for private repositories."));
1895
- console.log(chalk7__default.default.dim(" 1. Check auth status: gh auth status"));
1896
- console.log(chalk7__default.default.dim(" 2. Login if needed: gh auth login"));
1897
- console.log(chalk7__default.default.dim(" 3. Or set GITHUB_TOKEN environment variable"));
1082
+ console.log(chalk10__default.default.dim(" GitHub authentication is required for private repositories."));
1083
+ console.log(chalk10__default.default.dim(" 1. Check auth status: gh auth status"));
1084
+ console.log(chalk10__default.default.dim(" 2. Login if needed: gh auth login"));
1085
+ console.log(chalk10__default.default.dim(" 3. Or set GITHUB_TOKEN environment variable"));
1898
1086
  } else if (error.message.includes("Permission denied")) {
1899
- console.log(chalk7__default.default.dim(" Permission denied accessing repository files."));
1900
- console.log(chalk7__default.default.dim(" 1. Check file/directory permissions"));
1901
- console.log(chalk7__default.default.dim(" 2. Ensure you have access to the repository"));
1087
+ console.log(chalk10__default.default.dim(" Permission denied accessing repository files."));
1088
+ console.log(chalk10__default.default.dim(" 1. Check file/directory permissions"));
1089
+ console.log(chalk10__default.default.dim(" 2. Ensure you have access to the repository"));
1902
1090
  } else if (error.message.includes("not found") || error.message.includes("does not exist")) {
1903
- console.log(chalk7__default.default.dim(` Repository not found: ${config.organization}/${config.codex_repo || "codex"}`));
1904
- console.log(chalk7__default.default.dim(" 1. Verify the repository exists on GitHub"));
1905
- console.log(chalk7__default.default.dim(" 2. Check organization and repository names in config"));
1091
+ console.log(chalk10__default.default.dim(` Repository not found: ${config.organization}/${config.codex_repo || "codex"}`));
1092
+ console.log(chalk10__default.default.dim(" 1. Verify the repository exists on GitHub"));
1093
+ console.log(chalk10__default.default.dim(" 2. Check organization and repository names in config"));
1906
1094
  } else {
1907
- console.log(chalk7__default.default.dim(" 1. Ensure git is installed: git --version"));
1908
- console.log(chalk7__default.default.dim(" 2. Check GitHub auth: gh auth status"));
1909
- console.log(chalk7__default.default.dim(` 3. Verify repo exists: ${config.organization}/${config.codex_repo || "codex"}`));
1095
+ console.log(chalk10__default.default.dim(" 1. Ensure git is installed: git --version"));
1096
+ console.log(chalk10__default.default.dim(" 2. Check GitHub auth: gh auth status"));
1097
+ console.log(chalk10__default.default.dim(` 3. Verify repo exists: ${config.organization}/${config.codex_repo || "codex"}`));
1910
1098
  }
1911
1099
  process.exit(1);
1912
1100
  }
@@ -1925,17 +1113,17 @@ function syncCommand() {
1925
1113
  try {
1926
1114
  const { ensureCodexCloned: ensureCodexCloned2 } = await Promise.resolve().then(() => (init_codex_repository(), codex_repository_exports));
1927
1115
  if (!options.json) {
1928
- console.log(chalk7__default.default.blue("\u2139 Cloning/updating codex repository..."));
1116
+ console.log(chalk10__default.default.blue("\u2139 Cloning/updating codex repository..."));
1929
1117
  }
1930
1118
  codexRepoPath = await ensureCodexCloned2(config, {
1931
1119
  branch: targetBranch
1932
1120
  });
1933
1121
  if (!options.json) {
1934
- console.log(chalk7__default.default.dim(` Codex cloned to: ${codexRepoPath}`));
1122
+ console.log(chalk10__default.default.dim(` Codex cloned to: ${codexRepoPath}`));
1935
1123
  }
1936
1124
  } catch (error) {
1937
- console.error(chalk7__default.default.red("Error:"), "Failed to clone codex repository");
1938
- console.error(chalk7__default.default.dim(` ${error.message}`));
1125
+ console.error(chalk10__default.default.red("Error:"), "Failed to clone codex repository");
1126
+ console.error(chalk10__default.default.dim(` ${error.message}`));
1939
1127
  process.exit(1);
1940
1128
  }
1941
1129
  plan = await syncManager.createPlan(
@@ -1947,7 +1135,7 @@ function syncCommand() {
1947
1135
  syncOptions
1948
1136
  );
1949
1137
  plan.source = sourceDir;
1950
- plan.target = path2__namespace.join(codexRepoPath, "projects", projectName);
1138
+ plan.target = path3__namespace.join(codexRepoPath, "projects", projectName);
1951
1139
  }
1952
1140
  if (plan.totalFiles === 0) {
1953
1141
  if (options.json) {
@@ -1961,7 +1149,7 @@ function syncCommand() {
1961
1149
  message: "No files to sync"
1962
1150
  }, null, 2));
1963
1151
  } else {
1964
- console.log(chalk7__default.default.yellow("No files to sync."));
1152
+ console.log(chalk10__default.default.yellow("No files to sync."));
1965
1153
  }
1966
1154
  return;
1967
1155
  }
@@ -2017,81 +1205,81 @@ function syncCommand() {
2017
1205
  }, null, 2));
2018
1206
  return;
2019
1207
  }
2020
- console.log(chalk7__default.default.bold("Sync Plan\n"));
2021
- console.log(` Project: ${chalk7__default.default.cyan(projectName)}`);
2022
- console.log(` Organization: ${chalk7__default.default.cyan(config.organization)}`);
2023
- console.log(` Environment: ${chalk7__default.default.cyan(options.env)} (${targetBranch})`);
2024
- console.log(` Direction: ${chalk7__default.default.cyan(direction)}`);
2025
- console.log(` Files: ${chalk7__default.default.cyan(plan.totalFiles.toString())}`);
2026
- console.log(` Total size: ${chalk7__default.default.cyan(formatBytes(plan.totalBytes))}`);
1208
+ console.log(chalk10__default.default.bold("Sync Plan\n"));
1209
+ console.log(` Project: ${chalk10__default.default.cyan(projectName)}`);
1210
+ console.log(` Organization: ${chalk10__default.default.cyan(config.organization)}`);
1211
+ console.log(` Environment: ${chalk10__default.default.cyan(options.env)} (${targetBranch})`);
1212
+ console.log(` Direction: ${chalk10__default.default.cyan(direction)}`);
1213
+ console.log(` Files: ${chalk10__default.default.cyan(plan.totalFiles.toString())}`);
1214
+ console.log(` Total size: ${chalk10__default.default.cyan(codex.formatBytes(plan.totalBytes))}`);
2027
1215
  if (plan.estimatedTime) {
2028
- console.log(` Est. time: ${chalk7__default.default.dim(formatDuration(plan.estimatedTime))}`);
1216
+ console.log(` Est. time: ${chalk10__default.default.dim(codex.formatDuration(plan.estimatedTime))}`);
2029
1217
  }
2030
1218
  if (routingScan) {
2031
1219
  console.log("");
2032
- console.log(chalk7__default.default.bold("Routing Statistics\n"));
2033
- console.log(` Scanned: ${chalk7__default.default.cyan(routingScan.stats.totalScanned.toString())} files`);
2034
- console.log(` Matched: ${chalk7__default.default.cyan(routingScan.stats.totalMatched.toString())} files`);
2035
- console.log(` Source projects: ${chalk7__default.default.cyan(routingScan.stats.sourceProjects.length.toString())}`);
1220
+ console.log(chalk10__default.default.bold("Routing Statistics\n"));
1221
+ console.log(` Scanned: ${chalk10__default.default.cyan(routingScan.stats.totalScanned.toString())} files`);
1222
+ console.log(` Matched: ${chalk10__default.default.cyan(routingScan.stats.totalMatched.toString())} files`);
1223
+ console.log(` Source projects: ${chalk10__default.default.cyan(routingScan.stats.sourceProjects.length.toString())}`);
2036
1224
  if (routingScan.stats.sourceProjects.length > 0) {
2037
- console.log(chalk7__default.default.dim(` ${routingScan.stats.sourceProjects.slice(0, 5).join(", ")}`));
1225
+ console.log(chalk10__default.default.dim(` ${routingScan.stats.sourceProjects.slice(0, 5).join(", ")}`));
2038
1226
  if (routingScan.stats.sourceProjects.length > 5) {
2039
- console.log(chalk7__default.default.dim(` ... and ${routingScan.stats.sourceProjects.length - 5} more`));
1227
+ console.log(chalk10__default.default.dim(` ... and ${routingScan.stats.sourceProjects.length - 5} more`));
2040
1228
  }
2041
1229
  }
2042
- console.log(` Scan time: ${chalk7__default.default.dim(formatDuration(routingScan.stats.durationMs))}`);
1230
+ console.log(` Scan time: ${chalk10__default.default.dim(codex.formatDuration(routingScan.stats.durationMs))}`);
2043
1231
  }
2044
1232
  console.log("");
2045
1233
  if (plan.conflicts.length > 0) {
2046
- console.log(chalk7__default.default.yellow(`\u26A0 ${plan.conflicts.length} conflicts detected:`));
1234
+ console.log(chalk10__default.default.yellow(`\u26A0 ${plan.conflicts.length} conflicts detected:`));
2047
1235
  for (const conflict of plan.conflicts.slice(0, 5)) {
2048
- console.log(chalk7__default.default.yellow(` \u2022 ${conflict.path}`));
1236
+ console.log(chalk10__default.default.yellow(` \u2022 ${conflict.path}`));
2049
1237
  }
2050
1238
  if (plan.conflicts.length > 5) {
2051
- console.log(chalk7__default.default.dim(` ... and ${plan.conflicts.length - 5} more`));
1239
+ console.log(chalk10__default.default.dim(` ... and ${plan.conflicts.length - 5} more`));
2052
1240
  }
2053
1241
  console.log("");
2054
1242
  }
2055
1243
  if (plan.skipped.length > 0) {
2056
- console.log(chalk7__default.default.dim(`${plan.skipped.length} files skipped (no changes)`));
1244
+ console.log(chalk10__default.default.dim(`${plan.skipped.length} files skipped (no changes)`));
2057
1245
  console.log("");
2058
1246
  }
2059
1247
  if (options.dryRun) {
2060
- console.log(chalk7__default.default.blue("Dry run - would sync:\n"));
1248
+ console.log(chalk10__default.default.blue("Dry run - would sync:\n"));
2061
1249
  const filesToShow = plan.files.slice(0, 10);
2062
1250
  for (const file of filesToShow) {
2063
1251
  const arrow = direction === "to-codex" ? "\u2192" : direction === "from-codex" ? "\u2190" : "\u2194";
2064
- const opColor = file.operation === "create" ? chalk7__default.default.green : file.operation === "update" ? chalk7__default.default.yellow : chalk7__default.default.dim;
1252
+ const opColor = file.operation === "create" ? chalk10__default.default.green : file.operation === "update" ? chalk10__default.default.yellow : chalk10__default.default.dim;
2065
1253
  console.log(
2066
- chalk7__default.default.dim(` ${arrow}`),
1254
+ chalk10__default.default.dim(` ${arrow}`),
2067
1255
  opColor(file.operation.padEnd(7)),
2068
1256
  file.path,
2069
- chalk7__default.default.dim(`(${formatBytes(file.size || 0)})`)
1257
+ chalk10__default.default.dim(`(${codex.formatBytes(file.size || 0)})`)
2070
1258
  );
2071
1259
  }
2072
1260
  if (plan.files.length > 10) {
2073
- console.log(chalk7__default.default.dim(` ... and ${plan.files.length - 10} more files`));
1261
+ console.log(chalk10__default.default.dim(` ... and ${plan.files.length - 10} more files`));
2074
1262
  }
2075
- console.log(chalk7__default.default.dim(`
2076
- Total: ${plan.totalFiles} files (${formatBytes(plan.totalBytes)})`));
2077
- console.log(chalk7__default.default.dim("Run without --dry-run to execute sync."));
1263
+ console.log(chalk10__default.default.dim(`
1264
+ Total: ${plan.totalFiles} files (${codex.formatBytes(plan.totalBytes)})`));
1265
+ console.log(chalk10__default.default.dim("Run without --dry-run to execute sync."));
2078
1266
  return;
2079
1267
  }
2080
- console.log(chalk7__default.default.blue("Syncing...\n"));
1268
+ console.log(chalk10__default.default.blue("Syncing...\n"));
2081
1269
  const startTime = Date.now();
2082
1270
  const result = await syncManager.executePlan(plan, syncOptions);
2083
1271
  const duration = Date.now() - startTime;
2084
1272
  if (direction === "to-codex" && codexRepoPath && result.synced > 0) {
2085
1273
  try {
2086
1274
  if (!options.json) {
2087
- console.log(chalk7__default.default.blue("Committing and pushing to codex..."));
1275
+ console.log(chalk10__default.default.blue("Committing and pushing to codex..."));
2088
1276
  }
2089
1277
  const { RepoManager } = await import('@fractary/core/repo');
2090
1278
  const repoManager = new RepoManager({ platform: "github" }, codexRepoPath);
2091
1279
  repoManager.stageAll();
2092
1280
  if (repoManager.isClean()) {
2093
1281
  if (!options.json) {
2094
- console.log(chalk7__default.default.dim(" No changes to push - codex is already up to date"));
1282
+ console.log(chalk10__default.default.dim(" No changes to push - codex is already up to date"));
2095
1283
  }
2096
1284
  } else {
2097
1285
  repoManager.commit({
@@ -2099,54 +1287,56 @@ Total: ${plan.totalFiles} files (${formatBytes(plan.totalBytes)})`));
2099
1287
  });
2100
1288
  repoManager.push({});
2101
1289
  if (!options.json) {
2102
- console.log(chalk7__default.default.dim(" Changes pushed to codex repository"));
1290
+ console.log(chalk10__default.default.dim(" Changes pushed to codex repository"));
2103
1291
  }
2104
1292
  }
2105
1293
  } catch (error) {
2106
- console.error(chalk7__default.default.red("Error pushing to codex:"), error.message);
1294
+ console.error(chalk10__default.default.red("Error pushing to codex:"), error.message);
2107
1295
  }
2108
1296
  }
2109
1297
  console.log("");
2110
1298
  if (result.success) {
2111
- console.log(chalk7__default.default.green(`\u2713 Sync completed successfully`));
2112
- console.log(chalk7__default.default.dim(` Synced: ${result.synced} files`));
1299
+ console.log(chalk10__default.default.green(`\u2713 Sync completed successfully`));
1300
+ console.log(chalk10__default.default.dim(` Synced: ${result.synced} files`));
2113
1301
  if (result.skipped > 0) {
2114
- console.log(chalk7__default.default.dim(` Skipped: ${result.skipped} files`));
1302
+ console.log(chalk10__default.default.dim(` Skipped: ${result.skipped} files`));
2115
1303
  }
2116
- console.log(chalk7__default.default.dim(` Duration: ${formatDuration(duration)}`));
1304
+ console.log(chalk10__default.default.dim(` Duration: ${codex.formatDuration(duration)}`));
2117
1305
  } else {
2118
- console.log(chalk7__default.default.yellow(`\u26A0 Sync completed with errors`));
2119
- console.log(chalk7__default.default.green(` Synced: ${result.synced} files`));
2120
- console.log(chalk7__default.default.red(` Failed: ${result.failed} files`));
1306
+ console.log(chalk10__default.default.yellow(`\u26A0 Sync completed with errors`));
1307
+ console.log(chalk10__default.default.green(` Synced: ${result.synced} files`));
1308
+ console.log(chalk10__default.default.red(` Failed: ${result.failed} files`));
2121
1309
  if (result.skipped > 0) {
2122
- console.log(chalk7__default.default.dim(` Skipped: ${result.skipped} files`));
1310
+ console.log(chalk10__default.default.dim(` Skipped: ${result.skipped} files`));
2123
1311
  }
2124
1312
  if (result.errors.length > 0) {
2125
1313
  console.log("");
2126
- console.log(chalk7__default.default.red("Errors:"));
1314
+ console.log(chalk10__default.default.red("Errors:"));
2127
1315
  for (const error of result.errors.slice(0, 5)) {
2128
- console.log(chalk7__default.default.red(` \u2022 ${error.path}: ${error.error}`));
1316
+ console.log(chalk10__default.default.red(` \u2022 ${error.path}: ${error.error}`));
2129
1317
  }
2130
1318
  if (result.errors.length > 5) {
2131
- console.log(chalk7__default.default.dim(` ... and ${result.errors.length - 5} more errors`));
1319
+ console.log(chalk10__default.default.dim(` ... and ${result.errors.length - 5} more errors`));
2132
1320
  }
2133
1321
  }
2134
1322
  }
2135
1323
  } catch (error) {
2136
- console.error(chalk7__default.default.red("Error:"), error.message);
1324
+ console.error(chalk10__default.default.red("Error:"), error.message);
2137
1325
  process.exit(1);
2138
1326
  }
2139
1327
  });
2140
1328
  return cmd;
2141
1329
  }
2142
1330
  var __filename2 = url.fileURLToPath(importMetaUrl);
2143
- var __dirname$1 = path2.dirname(__filename2);
2144
- var packageJson = JSON.parse(fs.readFileSync(path2.join(__dirname$1, "../package.json"), "utf-8"));
1331
+ var __dirname$1 = path3.dirname(__filename2);
1332
+ var packageJson = JSON.parse(fs.readFileSync(path3.join(__dirname$1, "../package.json"), "utf-8"));
2145
1333
  var VERSION = packageJson.version;
2146
1334
  function createCLI() {
2147
1335
  const program = new commander.Command("fractary-codex");
2148
1336
  program.description("Centralized knowledge management and distribution for AI agents").version(VERSION);
2149
- program.addCommand(configureCommand());
1337
+ program.addCommand(configInitializeCommand());
1338
+ program.addCommand(configUpdateCommand());
1339
+ program.addCommand(configValidateCommand());
2150
1340
  program.addCommand(documentFetchCommand());
2151
1341
  program.addCommand(cacheListCommand());
2152
1342
  program.addCommand(cacheClearCommand());