ferix-code 0.0.2-beta.23 → 0.0.2-beta.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +18 -18
- package/dist/index.js +328 -279
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -330,9 +330,9 @@ declare const isContentBlockStart: (u: unknown, overrideOptions?: effect_SchemaA
|
|
|
330
330
|
readonly text?: string | undefined;
|
|
331
331
|
} | {
|
|
332
332
|
readonly type: "tool_use";
|
|
333
|
+
readonly name: string;
|
|
333
334
|
readonly input?: unknown;
|
|
334
335
|
readonly id?: string | undefined;
|
|
335
|
-
readonly name: string;
|
|
336
336
|
};
|
|
337
337
|
};
|
|
338
338
|
declare const isContentBlockDelta: (u: unknown, overrideOptions?: effect_SchemaAST.ParseOptions | number) => u is {
|
|
@@ -358,9 +358,9 @@ declare const isAssistantMessage: (u: unknown, overrideOptions?: effect_SchemaAS
|
|
|
358
358
|
readonly text: string;
|
|
359
359
|
} | {
|
|
360
360
|
readonly type: "tool_use";
|
|
361
|
+
readonly name: string;
|
|
361
362
|
readonly input: unknown;
|
|
362
363
|
readonly id?: string | undefined;
|
|
363
|
-
readonly name: string;
|
|
364
364
|
})[];
|
|
365
365
|
};
|
|
366
366
|
};
|
|
@@ -378,9 +378,9 @@ declare const isInputJsonDelta: (u: unknown, overrideOptions?: effect_SchemaAST.
|
|
|
378
378
|
};
|
|
379
379
|
declare const isToolUseContentBlock: (u: unknown, overrideOptions?: effect_SchemaAST.ParseOptions | number) => u is {
|
|
380
380
|
readonly type: "tool_use";
|
|
381
|
+
readonly name: string;
|
|
381
382
|
readonly input: unknown;
|
|
382
383
|
readonly id?: string | undefined;
|
|
383
|
-
readonly name: string;
|
|
384
384
|
};
|
|
385
385
|
declare const isTextContentBlock: (u: unknown, overrideOptions?: effect_SchemaAST.ParseOptions | number) => u is {
|
|
386
386
|
readonly type: "text";
|
|
@@ -397,9 +397,9 @@ declare const decodeClaudeCliEvent: (u: unknown, overrideOptions?: effect_Schema
|
|
|
397
397
|
readonly text?: string | undefined;
|
|
398
398
|
} | {
|
|
399
399
|
readonly type: "tool_use";
|
|
400
|
+
readonly name: string;
|
|
400
401
|
readonly input?: unknown;
|
|
401
402
|
readonly id?: string | undefined;
|
|
402
|
-
readonly name: string;
|
|
403
403
|
};
|
|
404
404
|
} | {
|
|
405
405
|
readonly type: "content_block_delta";
|
|
@@ -422,9 +422,9 @@ declare const decodeClaudeCliEvent: (u: unknown, overrideOptions?: effect_Schema
|
|
|
422
422
|
readonly text: string;
|
|
423
423
|
} | {
|
|
424
424
|
readonly type: "tool_use";
|
|
425
|
+
readonly name: string;
|
|
425
426
|
readonly input: unknown;
|
|
426
427
|
readonly id?: string | undefined;
|
|
427
|
-
readonly name: string;
|
|
428
428
|
})[];
|
|
429
429
|
};
|
|
430
430
|
} | {
|
|
@@ -439,9 +439,9 @@ declare const decodeClaudeCliEventSync: (u: unknown, overrideOptions?: effect_Sc
|
|
|
439
439
|
readonly text?: string | undefined;
|
|
440
440
|
} | {
|
|
441
441
|
readonly type: "tool_use";
|
|
442
|
+
readonly name: string;
|
|
442
443
|
readonly input?: unknown;
|
|
443
444
|
readonly id?: string | undefined;
|
|
444
|
-
readonly name: string;
|
|
445
445
|
};
|
|
446
446
|
} | {
|
|
447
447
|
readonly type: "content_block_delta";
|
|
@@ -464,9 +464,9 @@ declare const decodeClaudeCliEventSync: (u: unknown, overrideOptions?: effect_Sc
|
|
|
464
464
|
readonly text: string;
|
|
465
465
|
} | {
|
|
466
466
|
readonly type: "tool_use";
|
|
467
|
+
readonly name: string;
|
|
467
468
|
readonly input: unknown;
|
|
468
469
|
readonly id?: string | undefined;
|
|
469
|
-
readonly name: string;
|
|
470
470
|
})[];
|
|
471
471
|
};
|
|
472
472
|
} | {
|
|
@@ -1604,15 +1604,15 @@ declare const isBashToolInput: (u: unknown, overrideOptions?: effect_SchemaAST.P
|
|
|
1604
1604
|
readonly [x: string]: unknown;
|
|
1605
1605
|
};
|
|
1606
1606
|
declare const isGlobToolInput: (u: unknown, overrideOptions?: effect_SchemaAST.ParseOptions | number) => u is {
|
|
1607
|
-
readonly pattern: string;
|
|
1608
1607
|
readonly path?: string | undefined;
|
|
1608
|
+
readonly pattern: string;
|
|
1609
1609
|
} & {
|
|
1610
1610
|
readonly [x: string]: unknown;
|
|
1611
1611
|
};
|
|
1612
1612
|
declare const isGrepToolInput: (u: unknown, overrideOptions?: effect_SchemaAST.ParseOptions | number) => u is {
|
|
1613
1613
|
readonly type?: string | undefined;
|
|
1614
|
-
readonly pattern: string;
|
|
1615
1614
|
readonly path?: string | undefined;
|
|
1615
|
+
readonly pattern: string;
|
|
1616
1616
|
readonly glob?: string | undefined;
|
|
1617
1617
|
readonly output_mode?: "content" | "files_with_matches" | "count" | undefined;
|
|
1618
1618
|
} & {
|
|
@@ -1728,8 +1728,8 @@ interface ValidatedToolUseEvent {
|
|
|
1728
1728
|
readonly input: AnyToolInput;
|
|
1729
1729
|
}
|
|
1730
1730
|
declare const decodeLLMEvent: (u: unknown, overrideOptions?: effect_SchemaAST.ParseOptions) => effect_Effect.Effect<{
|
|
1731
|
-
readonly _tag: "Text";
|
|
1732
1731
|
readonly text: string;
|
|
1732
|
+
readonly _tag: "Text";
|
|
1733
1733
|
} | {
|
|
1734
1734
|
readonly _tag: "ToolStart";
|
|
1735
1735
|
readonly tool: string;
|
|
@@ -1903,17 +1903,17 @@ declare const decodePlan: (u: unknown, overrideOptions?: effect_SchemaAST.ParseO
|
|
|
1903
1903
|
readonly context?: string | undefined;
|
|
1904
1904
|
readonly tasks: readonly {
|
|
1905
1905
|
readonly phases: readonly {
|
|
1906
|
-
readonly status: "
|
|
1906
|
+
readonly status: "failed" | "pending" | "in_progress" | "done";
|
|
1907
1907
|
readonly id: string;
|
|
1908
1908
|
readonly description: string;
|
|
1909
1909
|
}[];
|
|
1910
|
-
readonly status: "planning" | "
|
|
1910
|
+
readonly status: "planning" | "failed" | "pending" | "in_progress" | "done" | "skipped";
|
|
1911
1911
|
readonly attempts: number;
|
|
1912
1912
|
readonly id: string;
|
|
1913
1913
|
readonly description: string;
|
|
1914
1914
|
readonly title: string;
|
|
1915
1915
|
readonly criteria: readonly {
|
|
1916
|
-
readonly status: "
|
|
1916
|
+
readonly status: "failed" | "pending" | "passed";
|
|
1917
1917
|
readonly id: string;
|
|
1918
1918
|
readonly description: string;
|
|
1919
1919
|
readonly failureReason?: string | undefined;
|
|
@@ -1929,17 +1929,17 @@ declare const decodePlanData: (u: unknown, overrideOptions?: effect_SchemaAST.Pa
|
|
|
1929
1929
|
readonly context?: string | undefined;
|
|
1930
1930
|
readonly tasks: readonly {
|
|
1931
1931
|
readonly phases: readonly {
|
|
1932
|
-
readonly status: "
|
|
1932
|
+
readonly status: "failed" | "pending" | "in_progress" | "done";
|
|
1933
1933
|
readonly id: string;
|
|
1934
1934
|
readonly description: string;
|
|
1935
1935
|
}[];
|
|
1936
|
-
readonly status: "planning" | "
|
|
1936
|
+
readonly status: "planning" | "failed" | "pending" | "in_progress" | "done" | "skipped";
|
|
1937
1937
|
readonly attempts: number;
|
|
1938
1938
|
readonly id: string;
|
|
1939
1939
|
readonly description: string;
|
|
1940
1940
|
readonly title: string;
|
|
1941
1941
|
readonly criteria: readonly {
|
|
1942
|
-
readonly status: "
|
|
1942
|
+
readonly status: "failed" | "pending" | "passed";
|
|
1943
1943
|
readonly id: string;
|
|
1944
1944
|
readonly description: string;
|
|
1945
1945
|
readonly failureReason?: string | undefined;
|
|
@@ -2382,8 +2382,8 @@ declare const decodeSignal: (u: unknown, overrideOptions?: effect_SchemaAST.Pars
|
|
|
2382
2382
|
} | {
|
|
2383
2383
|
readonly _tag: "LoopComplete";
|
|
2384
2384
|
} | {
|
|
2385
|
-
readonly _tag: "SessionNameDefined";
|
|
2386
2385
|
readonly name: string;
|
|
2386
|
+
readonly _tag: "SessionNameDefined";
|
|
2387
2387
|
} | {
|
|
2388
2388
|
readonly _tag: "Learning";
|
|
2389
2389
|
readonly content: string;
|
|
@@ -2449,8 +2449,8 @@ declare const decodeSignalSync: (u: unknown, overrideOptions?: effect_SchemaAST.
|
|
|
2449
2449
|
} | {
|
|
2450
2450
|
readonly _tag: "LoopComplete";
|
|
2451
2451
|
} | {
|
|
2452
|
-
readonly _tag: "SessionNameDefined";
|
|
2453
2452
|
readonly name: string;
|
|
2453
|
+
readonly _tag: "SessionNameDefined";
|
|
2454
2454
|
} | {
|
|
2455
2455
|
readonly _tag: "Learning";
|
|
2456
2456
|
readonly content: string;
|
package/dist/index.js
CHANGED
|
@@ -70,6 +70,8 @@ var init_registry = __esm({
|
|
|
70
70
|
|
|
71
71
|
// src/index.ts
|
|
72
72
|
init_esm_shims();
|
|
73
|
+
import { access as access3, readdir as readdir2, readFile as readFile7 } from "fs/promises";
|
|
74
|
+
import { dirname as dirname2, join as join7, resolve } from "path";
|
|
73
75
|
|
|
74
76
|
// ../sync/dist/index.js
|
|
75
77
|
init_esm_shims();
|
|
@@ -149,12 +151,6 @@ var decodeSkillReposResponse = S.decodeUnknown(
|
|
|
149
151
|
var CONVEX_URL_PROD = "https://groovy-mallard-649.convex.cloud";
|
|
150
152
|
var CONVEX_URL_DEV = "https://majestic-gnu-964.convex.cloud";
|
|
151
153
|
var getConvexUrl = (dev) => dev ? CONVEX_URL_DEV : CONVEX_URL_PROD;
|
|
152
|
-
var NON_NPM_VERSION_PREFIXES = [
|
|
153
|
-
"workspace:",
|
|
154
|
-
"file:",
|
|
155
|
-
"link:",
|
|
156
|
-
"portal:"
|
|
157
|
-
];
|
|
158
154
|
|
|
159
155
|
// ../sync/dist/chunk-3LE2T6D2.js
|
|
160
156
|
init_esm_shims();
|
|
@@ -6116,7 +6112,7 @@ var findSkillRepos = (orgs, dev) => Effect.gen(function* () {
|
|
|
6116
6112
|
return validated;
|
|
6117
6113
|
});
|
|
6118
6114
|
|
|
6119
|
-
// ../sync/dist/chunk-
|
|
6115
|
+
// ../sync/dist/chunk-FXKCLMLB.js
|
|
6120
6116
|
init_esm_shims();
|
|
6121
6117
|
import { exec } from "child_process";
|
|
6122
6118
|
import { promisify } from "util";
|
|
@@ -6126,7 +6122,7 @@ var installSingleSkill = (repo, options) => Effect2.tryPromise({
|
|
|
6126
6122
|
try: async () => {
|
|
6127
6123
|
const repoId = `${repo.owner}/${repo.repo}`;
|
|
6128
6124
|
const globalFlag = options.global === true ? " --global" : "";
|
|
6129
|
-
const command = `npx skills add ${repoId}${globalFlag}`;
|
|
6125
|
+
const command = `npx skills add ${repoId}${globalFlag} --yes`;
|
|
6130
6126
|
await execAsync(command);
|
|
6131
6127
|
return repoId;
|
|
6132
6128
|
},
|
|
@@ -6180,202 +6176,18 @@ var resolvePackageOrgs = (packageNames, dev) => Effect3.gen(function* () {
|
|
|
6180
6176
|
});
|
|
6181
6177
|
|
|
6182
6178
|
// ../sync/dist/index.js
|
|
6183
|
-
import { access, readdir, readFile } from "fs/promises";
|
|
6184
|
-
import { dirname, join, resolve } from "path";
|
|
6185
6179
|
import { Effect as Effect4, Schema as S4 } from "effect";
|
|
6186
|
-
var validateFileExists = (filePath) => Effect4.tryPromise({
|
|
6187
|
-
try: async () => {
|
|
6188
|
-
const absolutePath = resolve(filePath);
|
|
6189
|
-
await access(absolutePath);
|
|
6190
|
-
return absolutePath;
|
|
6191
|
-
},
|
|
6192
|
-
catch: () => new PackageJsonError({
|
|
6193
|
-
message: `File not found: ${filePath}`,
|
|
6194
|
-
path: filePath
|
|
6195
|
-
})
|
|
6196
|
-
});
|
|
6197
|
-
var readFileContent = (absolutePath) => Effect4.tryPromise({
|
|
6198
|
-
try: async () => await readFile(absolutePath, "utf-8"),
|
|
6199
|
-
catch: (error) => new PackageJsonError({
|
|
6200
|
-
message: `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,
|
|
6201
|
-
path: absolutePath,
|
|
6202
|
-
cause: error
|
|
6203
|
-
})
|
|
6204
|
-
});
|
|
6205
|
-
var parseJson = (content, path2) => Effect4.try({
|
|
6206
|
-
try: () => JSON.parse(content),
|
|
6207
|
-
catch: (error) => new PackageJsonError({
|
|
6208
|
-
message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
6209
|
-
path: path2,
|
|
6210
|
-
cause: error
|
|
6211
|
-
})
|
|
6212
|
-
});
|
|
6213
|
-
var validatePackageJson = (json, path2) => S4.decodeUnknown(PackageJsonSchema)(json).pipe(
|
|
6214
|
-
Effect4.mapError(
|
|
6215
|
-
(error) => new SchemaValidationError({
|
|
6216
|
-
message: "Invalid package.json structure",
|
|
6217
|
-
context: path2,
|
|
6218
|
-
cause: error
|
|
6219
|
-
})
|
|
6220
|
-
)
|
|
6221
|
-
);
|
|
6222
|
-
var isNonNpmDependency = (version2) => NON_NPM_VERSION_PREFIXES.some((prefix) => version2.startsWith(prefix));
|
|
6223
|
-
var extractDependencies = (pkg) => {
|
|
6224
|
-
const deps = pkg.dependencies ?? {};
|
|
6225
|
-
const devDeps = pkg.devDependencies ?? {};
|
|
6226
|
-
const allDeps = /* @__PURE__ */ new Map();
|
|
6227
|
-
for (const [name, version2] of Object.entries(deps)) {
|
|
6228
|
-
if (!isNonNpmDependency(version2)) {
|
|
6229
|
-
allDeps.set(name, version2);
|
|
6230
|
-
}
|
|
6231
|
-
}
|
|
6232
|
-
for (const [name, version2] of Object.entries(devDeps)) {
|
|
6233
|
-
if (!(allDeps.has(name) || isNonNpmDependency(version2))) {
|
|
6234
|
-
allDeps.set(name, version2);
|
|
6235
|
-
}
|
|
6236
|
-
}
|
|
6237
|
-
return Array.from(allDeps.keys());
|
|
6238
|
-
};
|
|
6239
|
-
var emptyResult = (dependencies = [], orgs = [], packageJsonCount = 1) => ({
|
|
6240
|
-
dependencies: [...dependencies],
|
|
6241
|
-
orgs: [...orgs],
|
|
6242
|
-
skillRepos: [],
|
|
6243
|
-
installed: [],
|
|
6244
|
-
packageJsonCount
|
|
6245
|
-
});
|
|
6246
|
-
var toMutableSkillRepos = (repos) => repos.map((r) => ({ owner: r.owner, repo: r.repo, githubUrl: r.githubUrl }));
|
|
6247
|
-
var extractWorkspacePatterns = (pkg) => {
|
|
6248
|
-
const workspaces = pkg.workspaces;
|
|
6249
|
-
if (!workspaces) {
|
|
6250
|
-
return [];
|
|
6251
|
-
}
|
|
6252
|
-
if (Array.isArray(workspaces)) {
|
|
6253
|
-
return workspaces.filter((w) => typeof w === "string");
|
|
6254
|
-
}
|
|
6255
|
-
if (typeof workspaces === "object" && "packages" in workspaces) {
|
|
6256
|
-
const packages = workspaces.packages;
|
|
6257
|
-
if (Array.isArray(packages)) {
|
|
6258
|
-
return packages.filter((w) => typeof w === "string");
|
|
6259
|
-
}
|
|
6260
|
-
}
|
|
6261
|
-
return [];
|
|
6262
|
-
};
|
|
6263
|
-
var expandGlobPattern = async (rootDir, pattern) => {
|
|
6264
|
-
if (pattern.endsWith("/*")) {
|
|
6265
|
-
const baseDir = pattern.slice(0, -2);
|
|
6266
|
-
const fullPath2 = join(rootDir, baseDir);
|
|
6267
|
-
try {
|
|
6268
|
-
const entries = await readdir(fullPath2, { withFileTypes: true });
|
|
6269
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => join(fullPath2, entry.name));
|
|
6270
|
-
} catch {
|
|
6271
|
-
return [];
|
|
6272
|
-
}
|
|
6273
|
-
}
|
|
6274
|
-
if (pattern.endsWith("/**")) {
|
|
6275
|
-
const baseDir = pattern.slice(0, -3);
|
|
6276
|
-
const fullPath2 = join(rootDir, baseDir);
|
|
6277
|
-
try {
|
|
6278
|
-
const entries = await readdir(fullPath2, { withFileTypes: true });
|
|
6279
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => join(fullPath2, entry.name));
|
|
6280
|
-
} catch {
|
|
6281
|
-
return [];
|
|
6282
|
-
}
|
|
6283
|
-
}
|
|
6284
|
-
const fullPath = join(rootDir, pattern);
|
|
6285
|
-
try {
|
|
6286
|
-
await access(fullPath);
|
|
6287
|
-
return [fullPath];
|
|
6288
|
-
} catch {
|
|
6289
|
-
return [];
|
|
6290
|
-
}
|
|
6291
|
-
};
|
|
6292
|
-
var discoverPackageJsonFiles = (rootPath, rootPkg) => Effect4.tryPromise({
|
|
6293
|
-
try: async () => {
|
|
6294
|
-
const rootDir = dirname(rootPath);
|
|
6295
|
-
const patterns = extractWorkspacePatterns(rootPkg);
|
|
6296
|
-
if (patterns.length === 0) {
|
|
6297
|
-
return [rootPath];
|
|
6298
|
-
}
|
|
6299
|
-
const packageJsonPaths = [rootPath];
|
|
6300
|
-
for (const pattern of patterns) {
|
|
6301
|
-
const dirs = await expandGlobPattern(rootDir, pattern);
|
|
6302
|
-
for (const dir of dirs) {
|
|
6303
|
-
const pkgPath = join(dir, "package.json");
|
|
6304
|
-
try {
|
|
6305
|
-
await access(pkgPath);
|
|
6306
|
-
packageJsonPaths.push(pkgPath);
|
|
6307
|
-
} catch {
|
|
6308
|
-
}
|
|
6309
|
-
}
|
|
6310
|
-
}
|
|
6311
|
-
return packageJsonPaths;
|
|
6312
|
-
},
|
|
6313
|
-
catch: (error) => new PackageJsonError({
|
|
6314
|
-
message: `Failed to discover workspace packages: ${error instanceof Error ? error.message : String(error)}`,
|
|
6315
|
-
path: rootPath,
|
|
6316
|
-
cause: error
|
|
6317
|
-
})
|
|
6318
|
-
});
|
|
6319
|
-
var readPackageJson = (filePath) => Effect4.gen(function* () {
|
|
6320
|
-
const content = yield* readFileContent(filePath);
|
|
6321
|
-
const json = yield* parseJson(content, filePath);
|
|
6322
|
-
return yield* validatePackageJson(json, filePath);
|
|
6323
|
-
});
|
|
6324
|
-
var sync = (packageJsonPath, options = {}) => Effect4.gen(function* () {
|
|
6325
|
-
const absolutePath = yield* validateFileExists(packageJsonPath);
|
|
6326
|
-
const rootPkg = yield* readPackageJson(absolutePath);
|
|
6327
|
-
const packageJsonPaths = yield* discoverPackageJsonFiles(
|
|
6328
|
-
absolutePath,
|
|
6329
|
-
rootPkg
|
|
6330
|
-
);
|
|
6331
|
-
const packageJsonCount = packageJsonPaths.length;
|
|
6332
|
-
const allDependencies = /* @__PURE__ */ new Set();
|
|
6333
|
-
for (const pkgPath of packageJsonPaths) {
|
|
6334
|
-
const pkg = yield* readPackageJson(pkgPath);
|
|
6335
|
-
const deps = extractDependencies(pkg);
|
|
6336
|
-
for (const dep of deps) {
|
|
6337
|
-
allDependencies.add(dep);
|
|
6338
|
-
}
|
|
6339
|
-
}
|
|
6340
|
-
const dependencies = Array.from(allDependencies);
|
|
6341
|
-
if (dependencies.length === 0) {
|
|
6342
|
-
return emptyResult([], [], packageJsonCount);
|
|
6343
|
-
}
|
|
6344
|
-
const packageOrgs = yield* resolvePackageOrgs(dependencies, options.dev);
|
|
6345
|
-
const orgs = Array.from(
|
|
6346
|
-
new Set(
|
|
6347
|
-
packageOrgs.map((p) => p.githubOrg).filter((org) => org !== null)
|
|
6348
|
-
)
|
|
6349
|
-
);
|
|
6350
|
-
if (orgs.length === 0) {
|
|
6351
|
-
return emptyResult([...dependencies], [], packageJsonCount);
|
|
6352
|
-
}
|
|
6353
|
-
const skillRepos = yield* findSkillRepos(orgs, options.dev);
|
|
6354
|
-
if (skillRepos.length === 0) {
|
|
6355
|
-
return emptyResult([...dependencies], orgs, packageJsonCount);
|
|
6356
|
-
}
|
|
6357
|
-
const installed = yield* installSkills(skillRepos, {
|
|
6358
|
-
dryRun: options.dryRun,
|
|
6359
|
-
global: options.global
|
|
6360
|
-
});
|
|
6361
|
-
return {
|
|
6362
|
-
dependencies: [...dependencies],
|
|
6363
|
-
orgs,
|
|
6364
|
-
skillRepos: toMutableSkillRepos(skillRepos),
|
|
6365
|
-
installed: [...installed],
|
|
6366
|
-
packageJsonCount
|
|
6367
|
-
};
|
|
6368
|
-
});
|
|
6369
6180
|
|
|
6370
6181
|
// src/index.ts
|
|
6371
6182
|
import { Command } from "commander";
|
|
6372
6183
|
import { Effect as Effect29 } from "effect";
|
|
6184
|
+
import ora from "ora";
|
|
6373
6185
|
import pc17 from "picocolors";
|
|
6374
6186
|
|
|
6375
6187
|
// package.json
|
|
6376
6188
|
var package_default = {
|
|
6377
6189
|
name: "ferix-code",
|
|
6378
|
-
version: "0.0.2-beta.
|
|
6190
|
+
version: "0.0.2-beta.25",
|
|
6379
6191
|
description: "Composable RALPH loops for AI coding agents - v2 with Effect",
|
|
6380
6192
|
type: "module",
|
|
6381
6193
|
bin: {
|
|
@@ -6397,6 +6209,7 @@ var package_default = {
|
|
|
6397
6209
|
commander: "^14.0.0",
|
|
6398
6210
|
effect: "^3.19.15",
|
|
6399
6211
|
"human-id": "^4.1.3",
|
|
6212
|
+
ora: "^9.1.0",
|
|
6400
6213
|
picocolors: "^1.1.1"
|
|
6401
6214
|
},
|
|
6402
6215
|
devDependencies: {
|
|
@@ -8877,14 +8690,14 @@ import { Layer as Layer14 } from "effect";
|
|
|
8877
8690
|
init_esm_shims();
|
|
8878
8691
|
import { exec as exec2 } from "child_process";
|
|
8879
8692
|
import {
|
|
8880
|
-
access
|
|
8693
|
+
access,
|
|
8881
8694
|
appendFile,
|
|
8882
8695
|
copyFile,
|
|
8883
8696
|
mkdir,
|
|
8884
|
-
readFile
|
|
8697
|
+
readFile,
|
|
8885
8698
|
rm
|
|
8886
8699
|
} from "fs/promises";
|
|
8887
|
-
import { dirname
|
|
8700
|
+
import { dirname, join } from "path";
|
|
8888
8701
|
import { promisify as promisify2 } from "util";
|
|
8889
8702
|
import { Effect as Effect8, Layer } from "effect";
|
|
8890
8703
|
|
|
@@ -8930,7 +8743,7 @@ var WORKTREES_DIR = ".ferix/worktrees";
|
|
|
8930
8743
|
var GITDIR_REGEX = /^gitdir:\s*(.+)$/m;
|
|
8931
8744
|
var BRANCH_PREFIX = "ferix";
|
|
8932
8745
|
function getWorktreeDir(sessionId) {
|
|
8933
|
-
return
|
|
8746
|
+
return join(process.cwd(), WORKTREES_DIR, sessionId);
|
|
8934
8747
|
}
|
|
8935
8748
|
function getBranchName(sessionId) {
|
|
8936
8749
|
return `${BRANCH_PREFIX}/${sessionId}`;
|
|
@@ -8954,7 +8767,7 @@ function gitExec(command, cwd) {
|
|
|
8954
8767
|
function directoryExists(dirPath) {
|
|
8955
8768
|
return Effect8.tryPromise({
|
|
8956
8769
|
try: async () => {
|
|
8957
|
-
await
|
|
8770
|
+
await access(dirPath);
|
|
8958
8771
|
return true;
|
|
8959
8772
|
},
|
|
8960
8773
|
catch: () => new Error("Directory does not exist")
|
|
@@ -8994,11 +8807,11 @@ function copyUntrackedFiles(worktreeDir) {
|
|
|
8994
8807
|
return;
|
|
8995
8808
|
}
|
|
8996
8809
|
for (const file of untrackedFiles) {
|
|
8997
|
-
const srcPath =
|
|
8998
|
-
const destPath =
|
|
8810
|
+
const srcPath = join(process.cwd(), file);
|
|
8811
|
+
const destPath = join(worktreeDir, file);
|
|
8999
8812
|
yield* Effect8.tryPromise({
|
|
9000
8813
|
try: async () => {
|
|
9001
|
-
await mkdir(
|
|
8814
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
9002
8815
|
await copyFile(srcPath, destPath);
|
|
9003
8816
|
},
|
|
9004
8817
|
catch: () => new GitError({
|
|
@@ -9009,16 +8822,16 @@ function copyUntrackedFiles(worktreeDir) {
|
|
|
9009
8822
|
}
|
|
9010
8823
|
yield* Effect8.tryPromise({
|
|
9011
8824
|
try: async () => {
|
|
9012
|
-
const gitFilePath =
|
|
9013
|
-
const gitFileContent = await
|
|
8825
|
+
const gitFilePath = join(worktreeDir, ".git");
|
|
8826
|
+
const gitFileContent = await readFile(gitFilePath, "utf-8");
|
|
9014
8827
|
const gitDirMatch = gitFileContent.match(GITDIR_REGEX);
|
|
9015
8828
|
const gitDirPath = gitDirMatch?.[1]?.trim();
|
|
9016
8829
|
if (!gitDirPath) {
|
|
9017
8830
|
return;
|
|
9018
8831
|
}
|
|
9019
8832
|
const gitDir = gitDirPath;
|
|
9020
|
-
const excludePath =
|
|
9021
|
-
await mkdir(
|
|
8833
|
+
const excludePath = join(gitDir, "info", "exclude");
|
|
8834
|
+
await mkdir(dirname(excludePath), { recursive: true });
|
|
9022
8835
|
const excludeContent = "\n# Untracked files copied from main worktree (auto-generated by ferix)\n" + untrackedFiles.join("\n") + "\n";
|
|
9023
8836
|
await appendFile(excludePath, excludeContent);
|
|
9024
8837
|
},
|
|
@@ -9033,7 +8846,7 @@ var make = {
|
|
|
9033
8846
|
createWorktree: (sessionId, baseBranch) => Effect8.gen(function* () {
|
|
9034
8847
|
const worktreeDir = getWorktreeDir(sessionId);
|
|
9035
8848
|
const branchName = getBranchName(sessionId);
|
|
9036
|
-
const worktreesBase =
|
|
8849
|
+
const worktreesBase = join(process.cwd(), WORKTREES_DIR);
|
|
9037
8850
|
yield* Effect8.tryPromise({
|
|
9038
8851
|
try: () => mkdir(worktreesBase, { recursive: true }),
|
|
9039
8852
|
catch: (error) => new GitError({
|
|
@@ -9409,8 +9222,8 @@ var MemoryGit = {
|
|
|
9409
9222
|
|
|
9410
9223
|
// src/layers/guardrails/file-system.ts
|
|
9411
9224
|
init_esm_shims();
|
|
9412
|
-
import { mkdir as mkdir2, readFile as
|
|
9413
|
-
import { join as
|
|
9225
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile } from "fs/promises";
|
|
9226
|
+
import { join as join2 } from "path";
|
|
9414
9227
|
import { DateTime, Effect as Effect10, Layer as Layer3 } from "effect";
|
|
9415
9228
|
|
|
9416
9229
|
// src/domain/index.ts
|
|
@@ -10432,10 +10245,10 @@ function ensureDir(dirPath) {
|
|
|
10432
10245
|
}).pipe(Effect10.asVoid);
|
|
10433
10246
|
}
|
|
10434
10247
|
function getSessionDir(sessionId) {
|
|
10435
|
-
return
|
|
10248
|
+
return join2(process.cwd(), PLANS_DIR, sessionId);
|
|
10436
10249
|
}
|
|
10437
10250
|
function getGuardrailsPath(sessionId) {
|
|
10438
|
-
return
|
|
10251
|
+
return join2(getSessionDir(sessionId), "guardrails.json");
|
|
10439
10252
|
}
|
|
10440
10253
|
function serializeGuardrails(guardrails) {
|
|
10441
10254
|
return JSON.stringify(guardrails, null, 2);
|
|
@@ -10477,7 +10290,7 @@ var make2 = {
|
|
|
10477
10290
|
const existing = yield* Effect10.tryPromise({
|
|
10478
10291
|
try: async () => {
|
|
10479
10292
|
try {
|
|
10480
|
-
const content = await
|
|
10293
|
+
const content = await readFile2(guardrailsPath, "utf-8");
|
|
10481
10294
|
return content;
|
|
10482
10295
|
} catch {
|
|
10483
10296
|
return null;
|
|
@@ -10526,7 +10339,7 @@ var make2 = {
|
|
|
10526
10339
|
const content = yield* Effect10.tryPromise({
|
|
10527
10340
|
try: async () => {
|
|
10528
10341
|
try {
|
|
10529
|
-
return await
|
|
10342
|
+
return await readFile2(guardrailsPath, "utf-8");
|
|
10530
10343
|
} catch {
|
|
10531
10344
|
return null;
|
|
10532
10345
|
}
|
|
@@ -11081,8 +10894,8 @@ function createProviderLayer2(name) {
|
|
|
11081
10894
|
|
|
11082
10895
|
// src/layers/plan/file-system.ts
|
|
11083
10896
|
init_esm_shims();
|
|
11084
|
-
import { access as
|
|
11085
|
-
import { join as
|
|
10897
|
+
import { access as access2, mkdir as mkdir3, readdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
10898
|
+
import { join as join3 } from "path";
|
|
11086
10899
|
import { Effect as Effect16, Layer as Layer7 } from "effect";
|
|
11087
10900
|
|
|
11088
10901
|
// src/services/plan-store.ts
|
|
@@ -11104,10 +10917,10 @@ function ensureDir2(dirPath) {
|
|
|
11104
10917
|
}).pipe(Effect16.asVoid);
|
|
11105
10918
|
}
|
|
11106
10919
|
function getSessionDir2(sessionId) {
|
|
11107
|
-
return
|
|
10920
|
+
return join3(process.cwd(), PLANS_DIR2, sessionId);
|
|
11108
10921
|
}
|
|
11109
10922
|
function getPlanPath(sessionId, planId) {
|
|
11110
|
-
return
|
|
10923
|
+
return join3(getSessionDir2(sessionId), `${planId}.json`);
|
|
11111
10924
|
}
|
|
11112
10925
|
function generatePlanId(taskNumber) {
|
|
11113
10926
|
return PlanId(`task-${taskNumber}`);
|
|
@@ -11147,7 +10960,7 @@ var make3 = {
|
|
|
11147
10960
|
const existingPlans = yield* Effect16.tryPromise({
|
|
11148
10961
|
try: async () => {
|
|
11149
10962
|
try {
|
|
11150
|
-
const files = await
|
|
10963
|
+
const files = await readdir(sessionDir);
|
|
11151
10964
|
return files.filter((f) => f.endsWith(".json")).length;
|
|
11152
10965
|
} catch {
|
|
11153
10966
|
return 0;
|
|
@@ -11175,7 +10988,7 @@ var make3 = {
|
|
|
11175
10988
|
if (sessionId) {
|
|
11176
10989
|
const planPath = getPlanPath(sessionId, planId);
|
|
11177
10990
|
const content = yield* Effect16.tryPromise({
|
|
11178
|
-
try: () =>
|
|
10991
|
+
try: () => readFile3(planPath, "utf-8"),
|
|
11179
10992
|
catch: (error) => new PlanStoreError({
|
|
11180
10993
|
message: `Failed to read plan file: ${planPath}`,
|
|
11181
10994
|
operation: "load",
|
|
@@ -11186,8 +10999,8 @@ var make3 = {
|
|
|
11186
10999
|
}
|
|
11187
11000
|
const sessionDirs = yield* Effect16.tryPromise({
|
|
11188
11001
|
try: async () => {
|
|
11189
|
-
const plansDir =
|
|
11190
|
-
const dirs = await
|
|
11002
|
+
const plansDir = join3(process.cwd(), PLANS_DIR2);
|
|
11003
|
+
const dirs = await readdir(plansDir);
|
|
11191
11004
|
return dirs;
|
|
11192
11005
|
},
|
|
11193
11006
|
catch: (error) => new PlanStoreError({
|
|
@@ -11200,7 +11013,7 @@ var make3 = {
|
|
|
11200
11013
|
const planPath = getPlanPath(sid, planId);
|
|
11201
11014
|
const exists = yield* Effect16.tryPromise({
|
|
11202
11015
|
try: async () => {
|
|
11203
|
-
await
|
|
11016
|
+
await access2(planPath);
|
|
11204
11017
|
return true;
|
|
11205
11018
|
},
|
|
11206
11019
|
catch: () => new PlanStoreError({
|
|
@@ -11210,7 +11023,7 @@ var make3 = {
|
|
|
11210
11023
|
}).pipe(Effect16.orElseSucceed(() => false));
|
|
11211
11024
|
if (exists) {
|
|
11212
11025
|
const content = yield* Effect16.tryPromise({
|
|
11213
|
-
try: () =>
|
|
11026
|
+
try: () => readFile3(planPath, "utf-8"),
|
|
11214
11027
|
catch: (error) => new PlanStoreError({
|
|
11215
11028
|
message: `Failed to read plan file: ${planPath}`,
|
|
11216
11029
|
operation: "load",
|
|
@@ -11243,7 +11056,7 @@ var make3 = {
|
|
|
11243
11056
|
const files = yield* Effect16.tryPromise({
|
|
11244
11057
|
try: async () => {
|
|
11245
11058
|
try {
|
|
11246
|
-
return await
|
|
11059
|
+
return await readdir(sessionDir);
|
|
11247
11060
|
} catch {
|
|
11248
11061
|
return [];
|
|
11249
11062
|
}
|
|
@@ -11351,8 +11164,8 @@ var MemoryPlan = {
|
|
|
11351
11164
|
|
|
11352
11165
|
// src/layers/progress/file-system.ts
|
|
11353
11166
|
init_esm_shims();
|
|
11354
|
-
import { mkdir as mkdir4, readFile as
|
|
11355
|
-
import { join as
|
|
11167
|
+
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
11168
|
+
import { join as join4 } from "path";
|
|
11356
11169
|
import { DateTime as DateTime3, Effect as Effect18, Layer as Layer9 } from "effect";
|
|
11357
11170
|
|
|
11358
11171
|
// src/services/progress-store.ts
|
|
@@ -11374,10 +11187,10 @@ function ensureDir3(dirPath) {
|
|
|
11374
11187
|
}).pipe(Effect18.asVoid);
|
|
11375
11188
|
}
|
|
11376
11189
|
function getSessionDir3(sessionId) {
|
|
11377
|
-
return
|
|
11190
|
+
return join4(process.cwd(), PLANS_DIR3, sessionId);
|
|
11378
11191
|
}
|
|
11379
11192
|
function getProgressPath(sessionId) {
|
|
11380
|
-
return
|
|
11193
|
+
return join4(getSessionDir3(sessionId), "progress.json");
|
|
11381
11194
|
}
|
|
11382
11195
|
function serializeProgress(progress) {
|
|
11383
11196
|
return JSON.stringify(progress, null, 2);
|
|
@@ -11419,7 +11232,7 @@ var make4 = {
|
|
|
11419
11232
|
const existing = yield* Effect18.tryPromise({
|
|
11420
11233
|
try: async () => {
|
|
11421
11234
|
try {
|
|
11422
|
-
const content = await
|
|
11235
|
+
const content = await readFile4(progressPath, "utf-8");
|
|
11423
11236
|
return content;
|
|
11424
11237
|
} catch {
|
|
11425
11238
|
return null;
|
|
@@ -11464,7 +11277,7 @@ var make4 = {
|
|
|
11464
11277
|
const content = yield* Effect18.tryPromise({
|
|
11465
11278
|
try: async () => {
|
|
11466
11279
|
try {
|
|
11467
|
-
return await
|
|
11280
|
+
return await readFile4(progressPath, "utf-8");
|
|
11468
11281
|
} catch {
|
|
11469
11282
|
return null;
|
|
11470
11283
|
}
|
|
@@ -11555,8 +11368,8 @@ var MemoryProgress = {
|
|
|
11555
11368
|
|
|
11556
11369
|
// src/layers/session/file-system.ts
|
|
11557
11370
|
init_esm_shims();
|
|
11558
|
-
import { mkdir as mkdir5, readFile as
|
|
11559
|
-
import { join as
|
|
11371
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
11372
|
+
import { join as join5 } from "path";
|
|
11560
11373
|
import { DateTime as DateTime5, Effect as Effect20, Layer as Layer11 } from "effect";
|
|
11561
11374
|
import { humanId } from "human-id";
|
|
11562
11375
|
|
|
@@ -11583,7 +11396,7 @@ function ensureDir4(dirPath) {
|
|
|
11583
11396
|
}).pipe(Effect20.asVoid);
|
|
11584
11397
|
}
|
|
11585
11398
|
function getSessionPath(sessionId) {
|
|
11586
|
-
return
|
|
11399
|
+
return join5(process.cwd(), SESSIONS_DIR, `${sessionId}.json`);
|
|
11587
11400
|
}
|
|
11588
11401
|
function serializeSession(session) {
|
|
11589
11402
|
return JSON.stringify(session, null, 2);
|
|
@@ -11612,7 +11425,7 @@ function deserializeSession(json) {
|
|
|
11612
11425
|
}
|
|
11613
11426
|
var make5 = {
|
|
11614
11427
|
create: (originalTask) => Effect20.gen(function* () {
|
|
11615
|
-
const sessionsDir =
|
|
11428
|
+
const sessionsDir = join5(process.cwd(), SESSIONS_DIR);
|
|
11616
11429
|
yield* ensureDir4(sessionsDir);
|
|
11617
11430
|
const now = yield* DateTime5.now;
|
|
11618
11431
|
const timestampMs = DateTime5.toEpochMillis(now);
|
|
@@ -11638,7 +11451,7 @@ var make5 = {
|
|
|
11638
11451
|
get: (sessionId) => Effect20.gen(function* () {
|
|
11639
11452
|
const sessionPath = getSessionPath(sessionId);
|
|
11640
11453
|
const content = yield* Effect20.tryPromise({
|
|
11641
|
-
try: () =>
|
|
11454
|
+
try: () => readFile5(sessionPath, "utf-8"),
|
|
11642
11455
|
catch: (error) => new SessionStoreError({
|
|
11643
11456
|
message: `Failed to read session file: ${sessionPath}`,
|
|
11644
11457
|
operation: "get",
|
|
@@ -12357,8 +12170,8 @@ import { DateTime as DateTime8, Effect as Effect25, pipe, Ref as Ref10, Stream a
|
|
|
12357
12170
|
|
|
12358
12171
|
// src/layers/plan/task-generation.ts
|
|
12359
12172
|
init_esm_shims();
|
|
12360
|
-
import { mkdir as mkdir6, readFile as
|
|
12361
|
-
import { join as
|
|
12173
|
+
import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
12174
|
+
import { join as join6 } from "path";
|
|
12362
12175
|
import { Effect as Effect23 } from "effect";
|
|
12363
12176
|
var PLANS_DIR4 = ".ferix/plans";
|
|
12364
12177
|
function ensureDir5(dirPath) {
|
|
@@ -12372,10 +12185,10 @@ function ensureDir5(dirPath) {
|
|
|
12372
12185
|
}).pipe(Effect23.asVoid);
|
|
12373
12186
|
}
|
|
12374
12187
|
function getSessionDir4(sessionId) {
|
|
12375
|
-
return
|
|
12188
|
+
return join6(process.cwd(), PLANS_DIR4, sessionId);
|
|
12376
12189
|
}
|
|
12377
12190
|
function getTasksMdPath(sessionId) {
|
|
12378
|
-
return
|
|
12191
|
+
return join6(getSessionDir4(sessionId), "tasks.md");
|
|
12379
12192
|
}
|
|
12380
12193
|
function writeTasksMd(sessionId, tasks) {
|
|
12381
12194
|
return Effect23.gen(function* () {
|
|
@@ -13954,55 +13767,291 @@ program.command("run", { isDefault: true }).argument("<task>", "Task description
|
|
|
13954
13767
|
process.exit(1);
|
|
13955
13768
|
}
|
|
13956
13769
|
});
|
|
13957
|
-
|
|
13770
|
+
var NON_NPM_VERSION_PREFIXES2 = ["workspace:", "file:", "link:", "portal:"];
|
|
13771
|
+
var isNonNpmDependency = (version2) => NON_NPM_VERSION_PREFIXES2.some((prefix) => version2.startsWith(prefix));
|
|
13772
|
+
var extractDependencies = (pkg) => {
|
|
13773
|
+
const deps = pkg.dependencies ?? {};
|
|
13774
|
+
const devDeps = pkg.devDependencies ?? {};
|
|
13775
|
+
const allDeps = /* @__PURE__ */ new Map();
|
|
13776
|
+
for (const [name, version2] of Object.entries(deps)) {
|
|
13777
|
+
if (!isNonNpmDependency(version2)) {
|
|
13778
|
+
allDeps.set(name, version2);
|
|
13779
|
+
}
|
|
13780
|
+
}
|
|
13781
|
+
for (const [name, version2] of Object.entries(devDeps)) {
|
|
13782
|
+
if (!(allDeps.has(name) || isNonNpmDependency(version2))) {
|
|
13783
|
+
allDeps.set(name, version2);
|
|
13784
|
+
}
|
|
13785
|
+
}
|
|
13786
|
+
return Array.from(allDeps.keys());
|
|
13787
|
+
};
|
|
13788
|
+
var extractWorkspacePatterns = (pkg) => {
|
|
13789
|
+
const workspaces = pkg.workspaces;
|
|
13790
|
+
if (!workspaces) {
|
|
13791
|
+
return [];
|
|
13792
|
+
}
|
|
13793
|
+
if (Array.isArray(workspaces)) {
|
|
13794
|
+
return workspaces.filter((w) => typeof w === "string");
|
|
13795
|
+
}
|
|
13796
|
+
if (typeof workspaces === "object" && "packages" in workspaces) {
|
|
13797
|
+
const packages = workspaces.packages;
|
|
13798
|
+
if (Array.isArray(packages)) {
|
|
13799
|
+
return packages.filter((w) => typeof w === "string");
|
|
13800
|
+
}
|
|
13801
|
+
}
|
|
13802
|
+
return [];
|
|
13803
|
+
};
|
|
13804
|
+
var GLOB_SUFFIX_PATTERN = /\/\*+$/;
|
|
13805
|
+
var expandGlobPattern = async (rootDir, pattern) => {
|
|
13806
|
+
if (pattern.endsWith("/*") || pattern.endsWith("/**")) {
|
|
13807
|
+
const baseDir = pattern.replace(GLOB_SUFFIX_PATTERN, "");
|
|
13808
|
+
const fullPath2 = join7(rootDir, baseDir);
|
|
13809
|
+
try {
|
|
13810
|
+
const entries = await readdir2(fullPath2, { withFileTypes: true });
|
|
13811
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => join7(fullPath2, entry.name));
|
|
13812
|
+
} catch {
|
|
13813
|
+
return [];
|
|
13814
|
+
}
|
|
13815
|
+
}
|
|
13816
|
+
const fullPath = join7(rootDir, pattern);
|
|
13958
13817
|
try {
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13818
|
+
await access3(fullPath);
|
|
13819
|
+
return [fullPath];
|
|
13820
|
+
} catch {
|
|
13821
|
+
return [];
|
|
13822
|
+
}
|
|
13823
|
+
};
|
|
13824
|
+
var readPackageJsonFile = async (filePath) => {
|
|
13825
|
+
const content = await readFile7(filePath, "utf-8");
|
|
13826
|
+
return JSON.parse(content);
|
|
13827
|
+
};
|
|
13828
|
+
var discoverPackageJsonFiles = async (rootPath, rootPkg) => {
|
|
13829
|
+
const rootDir = dirname2(rootPath);
|
|
13830
|
+
const patterns = extractWorkspacePatterns(rootPkg);
|
|
13831
|
+
if (patterns.length === 0) {
|
|
13832
|
+
return [rootPath];
|
|
13833
|
+
}
|
|
13834
|
+
const packageJsonPaths = [rootPath];
|
|
13835
|
+
for (const pattern of patterns) {
|
|
13836
|
+
const dirs = await expandGlobPattern(rootDir, pattern);
|
|
13837
|
+
for (const dir of dirs) {
|
|
13838
|
+
const pkgPath = join7(dir, "package.json");
|
|
13839
|
+
try {
|
|
13840
|
+
await access3(pkgPath);
|
|
13841
|
+
packageJsonPaths.push(pkgPath);
|
|
13842
|
+
} catch {
|
|
13843
|
+
}
|
|
13969
13844
|
}
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13845
|
+
}
|
|
13846
|
+
return packageJsonPaths;
|
|
13847
|
+
};
|
|
13848
|
+
var SYMBOLS = {
|
|
13849
|
+
success: pc17.green("\u2713"),
|
|
13850
|
+
error: pc17.red("\u2717")
|
|
13851
|
+
};
|
|
13852
|
+
var printHeader = (title, subtitle) => {
|
|
13853
|
+
console.log();
|
|
13854
|
+
console.log(pc17.bold(pc17.cyan(` ${title}`)));
|
|
13855
|
+
if (subtitle) {
|
|
13856
|
+
console.log(pc17.dim(` ${subtitle}`));
|
|
13857
|
+
}
|
|
13858
|
+
console.log();
|
|
13859
|
+
};
|
|
13860
|
+
var printSection = (title) => {
|
|
13861
|
+
console.log();
|
|
13862
|
+
console.log(pc17.bold(` ${title}`));
|
|
13863
|
+
};
|
|
13864
|
+
var printRepo = (owner, repo, index) => {
|
|
13865
|
+
const num = pc17.dim(`${String(index + 1).padStart(2, " ")}.`);
|
|
13866
|
+
console.log(` ${num} ${pc17.cyan(owner)}${pc17.dim("/")}${pc17.white(repo)}`);
|
|
13867
|
+
};
|
|
13868
|
+
var printSuccess = (message) => {
|
|
13869
|
+
console.log(` ${SYMBOLS.success} ${pc17.green(message)}`);
|
|
13870
|
+
};
|
|
13871
|
+
var printError = (message) => {
|
|
13872
|
+
console.log(` ${SYMBOLS.error} ${pc17.red(message)}`);
|
|
13873
|
+
};
|
|
13874
|
+
var printHint = (message) => {
|
|
13875
|
+
console.log(pc17.dim(` ${message}`));
|
|
13876
|
+
};
|
|
13877
|
+
var createSpinner = (text) => {
|
|
13878
|
+
return ora({
|
|
13879
|
+
text,
|
|
13880
|
+
prefixText: " ",
|
|
13881
|
+
spinner: "dots"
|
|
13882
|
+
});
|
|
13883
|
+
};
|
|
13884
|
+
var discoverPackages = async (state, packagePath) => {
|
|
13885
|
+
state.spinner = createSpinner("Scanning for package.json files...").start();
|
|
13886
|
+
const absolutePath = resolve(packagePath);
|
|
13887
|
+
await access3(absolutePath);
|
|
13888
|
+
const rootPkg = await readPackageJsonFile(absolutePath);
|
|
13889
|
+
state.packageJsonPaths = await discoverPackageJsonFiles(
|
|
13890
|
+
absolutePath,
|
|
13891
|
+
rootPkg
|
|
13892
|
+
);
|
|
13893
|
+
const isMonorepo = state.packageJsonPaths.length > 1;
|
|
13894
|
+
state.spinner.succeed(
|
|
13895
|
+
isMonorepo ? `Found ${pc17.bold(String(state.packageJsonPaths.length))} package.json files ${pc17.dim("(monorepo)")}` : "Found package.json"
|
|
13896
|
+
);
|
|
13897
|
+
return true;
|
|
13898
|
+
};
|
|
13899
|
+
var extractAllDependencies = async (state) => {
|
|
13900
|
+
state.spinner = createSpinner("Extracting dependencies...").start();
|
|
13901
|
+
const allDependencies = /* @__PURE__ */ new Set();
|
|
13902
|
+
for (const pkgPath of state.packageJsonPaths) {
|
|
13903
|
+
const pkg = await readPackageJsonFile(pkgPath);
|
|
13904
|
+
for (const dep of extractDependencies(pkg)) {
|
|
13905
|
+
allDependencies.add(dep);
|
|
13984
13906
|
}
|
|
13985
|
-
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13907
|
+
}
|
|
13908
|
+
state.dependencies = Array.from(allDependencies);
|
|
13909
|
+
if (state.dependencies.length === 0) {
|
|
13910
|
+
state.spinner.warn("No dependencies found");
|
|
13911
|
+
return false;
|
|
13912
|
+
}
|
|
13913
|
+
state.spinner.succeed(
|
|
13914
|
+
`Found ${pc17.bold(String(state.dependencies.length))} unique dependencies`
|
|
13915
|
+
);
|
|
13916
|
+
return true;
|
|
13917
|
+
};
|
|
13918
|
+
var resolveOrganizations = async (state, isDev) => {
|
|
13919
|
+
state.spinner = createSpinner("Resolving GitHub organizations...").start();
|
|
13920
|
+
const packageOrgs = await Effect29.runPromise(
|
|
13921
|
+
resolvePackageOrgs(state.dependencies, isDev)
|
|
13922
|
+
);
|
|
13923
|
+
state.orgs = Array.from(
|
|
13924
|
+
new Set(
|
|
13925
|
+
packageOrgs.map((p) => p.githubOrg).filter((org) => org !== null)
|
|
13926
|
+
)
|
|
13927
|
+
);
|
|
13928
|
+
if (state.orgs.length === 0) {
|
|
13929
|
+
state.spinner.warn("No GitHub organizations found");
|
|
13930
|
+
printHint("Your dependencies don't have linked GitHub organizations.");
|
|
13931
|
+
return false;
|
|
13932
|
+
}
|
|
13933
|
+
state.spinner.succeed(
|
|
13934
|
+
`Resolved ${pc17.bold(String(state.orgs.length))} GitHub organizations`
|
|
13935
|
+
);
|
|
13936
|
+
return true;
|
|
13937
|
+
};
|
|
13938
|
+
var findRepositories = async (state, isDev) => {
|
|
13939
|
+
state.spinner = createSpinner("Searching for skill repositories...").start();
|
|
13940
|
+
state.skillRepos = await Effect29.runPromise(findSkillRepos(state.orgs, isDev));
|
|
13941
|
+
if (state.skillRepos.length === 0) {
|
|
13942
|
+
state.spinner.warn("No skill repositories found");
|
|
13943
|
+
printHint(
|
|
13944
|
+
"None of your dependency organizations have published skills yet."
|
|
13989
13945
|
);
|
|
13990
|
-
|
|
13991
|
-
|
|
13946
|
+
return false;
|
|
13947
|
+
}
|
|
13948
|
+
state.spinner.succeed(
|
|
13949
|
+
`Found ${pc17.bold(String(state.skillRepos.length))} skill ${state.skillRepos.length === 1 ? "repository" : "repositories"}`
|
|
13950
|
+
);
|
|
13951
|
+
return true;
|
|
13952
|
+
};
|
|
13953
|
+
var displayRepositories = (skillRepos) => {
|
|
13954
|
+
printSection("Repositories");
|
|
13955
|
+
console.log();
|
|
13956
|
+
for (let i = 0; i < skillRepos.length; i++) {
|
|
13957
|
+
const repo = skillRepos[i];
|
|
13958
|
+
if (repo) {
|
|
13959
|
+
printRepo(repo.owner, repo.repo, i);
|
|
13992
13960
|
}
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13961
|
+
}
|
|
13962
|
+
};
|
|
13963
|
+
var installRepositories = async (state, isGlobal) => {
|
|
13964
|
+
printSection("Installing");
|
|
13965
|
+
console.log();
|
|
13966
|
+
const installed = [];
|
|
13967
|
+
const failed = [];
|
|
13968
|
+
for (const repo of state.skillRepos) {
|
|
13969
|
+
const repoId = `${repo.owner}/${repo.repo}`;
|
|
13970
|
+
state.spinner = createSpinner(
|
|
13971
|
+
`Installing ${pc17.cyan(repo.owner)}${pc17.dim("/")}${pc17.white(repo.repo)}...`
|
|
13972
|
+
).start();
|
|
13973
|
+
try {
|
|
13974
|
+
await Effect29.runPromise(
|
|
13975
|
+
installSkills([repo], { dryRun: false, global: isGlobal })
|
|
13997
13976
|
);
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
`
|
|
14001
|
-
${pc17.green("\u2713")} Installed ${pc17.bold(String(result.installed.length))} skill repositories`
|
|
13977
|
+
state.spinner.succeed(
|
|
13978
|
+
`Installed ${pc17.cyan(repo.owner)}${pc17.dim("/")}${pc17.white(repo.repo)}`
|
|
14002
13979
|
);
|
|
13980
|
+
installed.push(repoId);
|
|
13981
|
+
} catch {
|
|
13982
|
+
state.spinner.fail(
|
|
13983
|
+
`Failed to install ${pc17.cyan(repo.owner)}${pc17.dim("/")}${pc17.white(repo.repo)}`
|
|
13984
|
+
);
|
|
13985
|
+
failed.push(repoId);
|
|
14003
13986
|
}
|
|
13987
|
+
}
|
|
13988
|
+
return { installed, failed };
|
|
13989
|
+
};
|
|
13990
|
+
var displaySummary = (installed, failed, isGlobal) => {
|
|
13991
|
+
printSection("Summary");
|
|
13992
|
+
console.log();
|
|
13993
|
+
if (installed.length > 0) {
|
|
13994
|
+
printSuccess(
|
|
13995
|
+
`${installed.length} skill ${installed.length === 1 ? "repository" : "repositories"} installed successfully`
|
|
13996
|
+
);
|
|
13997
|
+
}
|
|
13998
|
+
if (failed.length > 0) {
|
|
13999
|
+
printError(
|
|
14000
|
+
`${failed.length} ${failed.length === 1 ? "installation" : "installations"} failed`
|
|
14001
|
+
);
|
|
14002
|
+
}
|
|
14003
|
+
const installLocation = isGlobal ? "globally" : "in project";
|
|
14004
|
+
printHint(`Skills installed ${installLocation}.`);
|
|
14005
|
+
console.log();
|
|
14006
|
+
};
|
|
14007
|
+
var runSyncCommand = async (options) => {
|
|
14008
|
+
const { path: packagePath, dryRun, global: isGlobal, dev: isDev } = options;
|
|
14009
|
+
printHeader(
|
|
14010
|
+
"Ferix Sync",
|
|
14011
|
+
isDev ? pc17.yellow("Development Mode") : "Discovering skills from your dependencies"
|
|
14012
|
+
);
|
|
14013
|
+
const state = {
|
|
14014
|
+
spinner: void 0,
|
|
14015
|
+
packageJsonPaths: [],
|
|
14016
|
+
dependencies: [],
|
|
14017
|
+
orgs: [],
|
|
14018
|
+
skillRepos: []
|
|
14019
|
+
};
|
|
14020
|
+
await discoverPackages(state, packagePath);
|
|
14021
|
+
const hasDeps = await extractAllDependencies(state);
|
|
14022
|
+
if (!hasDeps) {
|
|
14023
|
+
return;
|
|
14024
|
+
}
|
|
14025
|
+
const hasOrgs = await resolveOrganizations(state, isDev);
|
|
14026
|
+
if (!hasOrgs) {
|
|
14027
|
+
return;
|
|
14028
|
+
}
|
|
14029
|
+
const hasRepos = await findRepositories(state, isDev);
|
|
14030
|
+
if (!hasRepos) {
|
|
14031
|
+
return;
|
|
14032
|
+
}
|
|
14033
|
+
displayRepositories(state.skillRepos);
|
|
14034
|
+
if (dryRun) {
|
|
14035
|
+
console.log();
|
|
14036
|
+
printHint(`Run without ${pc17.cyan("--dry-run")} to install these skills.`);
|
|
14037
|
+
console.log();
|
|
14038
|
+
return;
|
|
14039
|
+
}
|
|
14040
|
+
const { installed, failed } = await installRepositories(state, isGlobal);
|
|
14041
|
+
displaySummary(installed, failed, isGlobal);
|
|
14042
|
+
};
|
|
14043
|
+
program.command("sync").description("Discover and install skills based on your dependencies").option("-p, --path <path>", "Path to package.json", "./package.json").option("-n, --dry-run", "List skills without installing").option("-g, --global", "Install globally instead of project-level").option("-d, --dev", "Use development server instead of production").action(async (options) => {
|
|
14044
|
+
try {
|
|
14045
|
+
await runSyncCommand({
|
|
14046
|
+
path: options.path,
|
|
14047
|
+
dryRun: options.dryRun ?? false,
|
|
14048
|
+
global: options.global ?? false,
|
|
14049
|
+
dev: options.dev ?? false
|
|
14050
|
+
});
|
|
14004
14051
|
} catch (error) {
|
|
14005
|
-
console.
|
|
14052
|
+
console.log();
|
|
14053
|
+
printError(error instanceof Error ? error.message : String(error));
|
|
14054
|
+
console.log();
|
|
14006
14055
|
process.exit(1);
|
|
14007
14056
|
}
|
|
14008
14057
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ferix-code",
|
|
3
|
-
"version": "0.0.2-beta.
|
|
3
|
+
"version": "0.0.2-beta.25",
|
|
4
4
|
"description": "Composable RALPH loops for AI coding agents - v2 with Effect",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"commander": "^14.0.0",
|
|
23
23
|
"effect": "^3.19.15",
|
|
24
24
|
"human-id": "^4.1.3",
|
|
25
|
+
"ora": "^9.1.0",
|
|
25
26
|
"picocolors": "^1.1.1"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|