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