ferix-code 0.0.2-beta.24 → 0.0.2-beta.26

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +19 -19
  2. package/dist/index.js +576 -345
  3. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -70,16 +70,28 @@ var init_registry = __esm({
70
70
 
71
71
  // src/index.ts
72
72
  init_esm_shims();
73
+ import { access as access4, readdir as readdir2, readFile as readFile7 } from "fs/promises";
74
+ import { dirname as dirname2, join as join8, resolve } from "path";
75
+ import { cancel, isCancel, multiselect } from "@clack/prompts";
73
76
 
74
77
  // ../sync/dist/index.js
75
78
  init_esm_shims();
76
79
 
77
- // ../sync/dist/chunk-XQ7UIC5I.js
80
+ // ../sync/dist/chunk-5E4WZI4D.js
78
81
  init_esm_shims();
79
82
 
80
- // ../sync/dist/chunk-MSWOW6ZJ.js
83
+ // ../sync/dist/chunk-BNNEGPUU.js
81
84
  init_esm_shims();
82
85
  import { Schema as S } from "effect";
86
+ var AgentNameSchema = S.Literal(
87
+ "opencode",
88
+ "claude-code",
89
+ "cursor",
90
+ "cline",
91
+ "codex",
92
+ "openhands",
93
+ "windsurf"
94
+ );
83
95
  var PackageNameSchema = S.String.pipe(
84
96
  S.pattern(/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/),
85
97
  S.brand("PackageName")
@@ -130,7 +142,8 @@ var SyncOptionsSchema = S.Struct({
130
142
  });
131
143
  var InstallOptionsSchema = S.Struct({
132
144
  dryRun: S.optional(S.Boolean),
133
- global: S.optional(S.Boolean)
145
+ global: S.optional(S.Boolean),
146
+ agents: S.optional(S.Array(AgentNameSchema))
134
147
  });
135
148
  var SyncResultSchema = S.Struct({
136
149
  dependencies: S.Array(S.String),
@@ -149,12 +162,6 @@ var decodeSkillReposResponse = S.decodeUnknown(
149
162
  var CONVEX_URL_PROD = "https://groovy-mallard-649.convex.cloud";
150
163
  var CONVEX_URL_DEV = "https://majestic-gnu-964.convex.cloud";
151
164
  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
165
 
159
166
  // ../sync/dist/chunk-3LE2T6D2.js
160
167
  init_esm_shims();
@@ -6086,7 +6093,7 @@ var wrapper_default = import_websocket.default;
6086
6093
  var nodeWebSocket = wrapper_default;
6087
6094
  setDefaultWebSocketConstructor(nodeWebSocket);
6088
6095
 
6089
- // ../sync/dist/chunk-XQ7UIC5I.js
6096
+ // ../sync/dist/chunk-5E4WZI4D.js
6090
6097
  import { Effect, Schema as S2 } from "effect";
6091
6098
  var findSkillRepos = (orgs, dev) => Effect.gen(function* () {
6092
6099
  const response = yield* Effect.tryPromise({
@@ -6116,7 +6123,7 @@ var findSkillRepos = (orgs, dev) => Effect.gen(function* () {
6116
6123
  return validated;
6117
6124
  });
6118
6125
 
6119
- // ../sync/dist/chunk-FXKCLMLB.js
6126
+ // ../sync/dist/chunk-EDGIQ4IK.js
6120
6127
  init_esm_shims();
6121
6128
  import { exec } from "child_process";
6122
6129
  import { promisify } from "util";
@@ -6126,7 +6133,8 @@ var installSingleSkill = (repo, options) => Effect2.tryPromise({
6126
6133
  try: async () => {
6127
6134
  const repoId = `${repo.owner}/${repo.repo}`;
6128
6135
  const globalFlag = options.global === true ? " --global" : "";
6129
- const command = `npx skills add ${repoId}${globalFlag} --yes`;
6136
+ const agentFlag = options.agents && options.agents.length > 0 ? ` --agent ${options.agents.join(" ")}` : "";
6137
+ const command = `npx skills add ${repoId}${globalFlag}${agentFlag} --yes`;
6130
6138
  await execAsync(command);
6131
6139
  return repoId;
6132
6140
  },
@@ -6148,7 +6156,7 @@ var installSkills = (repos, options = {}) => {
6148
6156
  });
6149
6157
  };
6150
6158
 
6151
- // ../sync/dist/chunk-BAZKO52B.js
6159
+ // ../sync/dist/chunk-C6TYE4HI.js
6152
6160
  init_esm_shims();
6153
6161
  import { Effect as Effect3, Schema as S3 } from "effect";
6154
6162
  var resolvePackageOrgs = (packageNames, dev) => Effect3.gen(function* () {
@@ -6180,202 +6188,60 @@ var resolvePackageOrgs = (packageNames, dev) => Effect3.gen(function* () {
6180
6188
  });
6181
6189
 
6182
6190
  // ../sync/dist/index.js
6183
- import { access, readdir, readFile } from "fs/promises";
6184
- import { dirname, join, resolve } from "path";
6185
- import { Effect as Effect4, Schema as S4 } from "effect";
6186
- var validateFileExists = (filePath) => Effect4.tryPromise({
6191
+ import { Effect as Effect22, Schema as S4 } from "effect";
6192
+ import { access } from "fs/promises";
6193
+ import { join } from "path";
6194
+ import { Effect as Effect4 } from "effect";
6195
+ var AGENT_DIRECTORIES = {
6196
+ opencode: [".opencode"],
6197
+ "claude-code": [".claude"],
6198
+ cursor: [".cursor"],
6199
+ cline: [".cline"],
6200
+ codex: [".codex"],
6201
+ openhands: [".openhands"],
6202
+ windsurf: [".windsurf"]
6203
+ };
6204
+ var SUPPORTED_AGENTS = Object.keys(
6205
+ AGENT_DIRECTORIES
6206
+ );
6207
+ var directoryExists = (dirPath) => Effect4.tryPromise({
6187
6208
  try: async () => {
6188
- const absolutePath = resolve(filePath);
6189
- await access(absolutePath);
6190
- return absolutePath;
6209
+ await access(dirPath);
6210
+ return true;
6191
6211
  },
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
- })
6212
+ catch: () => false
6213
+ }).pipe(Effect4.catchAll(() => Effect4.succeed(false)));
6214
+ var isAgentPresent = (projectDir, agent) => {
6215
+ const directories = AGENT_DIRECTORIES[agent];
6216
+ return Effect4.forEach(
6217
+ directories,
6218
+ (dir) => directoryExists(join(projectDir, dir))
6219
+ ).pipe(Effect4.map((results) => results.some((exists) => exists)));
6220
+ };
6221
+ var detectAgents = (projectDir) => Effect4.forEach(
6222
+ SUPPORTED_AGENTS,
6223
+ (agent) => isAgentPresent(projectDir, agent).pipe(
6224
+ Effect4.map((present) => present ? agent : null)
6225
+ )
6226
+ ).pipe(
6227
+ Effect4.map(
6228
+ (results) => results.filter((agent) => agent !== null)
6220
6229
  )
6221
6230
  );
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
- });
6231
+ var validateAgentNames = (agents) => agents.filter(
6232
+ (agent) => !SUPPORTED_AGENTS.includes(agent)
6233
+ );
6369
6234
 
6370
6235
  // src/index.ts
6371
6236
  import { Command } from "commander";
6372
- import { Effect as Effect29 } from "effect";
6237
+ import { Effect as Effect30 } from "effect";
6238
+ import ora from "ora";
6373
6239
  import pc17 from "picocolors";
6374
6240
 
6375
6241
  // package.json
6376
6242
  var package_default = {
6377
6243
  name: "ferix-code",
6378
- version: "0.0.2-beta.24",
6244
+ version: "0.0.2-beta.26",
6379
6245
  description: "Composable RALPH loops for AI coding agents - v2 with Effect",
6380
6246
  type: "module",
6381
6247
  bin: {
@@ -6394,9 +6260,11 @@ var package_default = {
6394
6260
  bump: "npm version prerelease --preid=beta --workspaces=false && bun run build && bun publish --tag beta"
6395
6261
  },
6396
6262
  dependencies: {
6263
+ "@clack/prompts": "catalog:",
6397
6264
  commander: "^14.0.0",
6398
6265
  effect: "^3.19.15",
6399
6266
  "human-id": "^4.1.3",
6267
+ ora: "^9.1.0",
6400
6268
  picocolors: "^1.1.1"
6401
6269
  },
6402
6270
  devDependencies: {
@@ -6423,7 +6291,7 @@ var package_default = {
6423
6291
 
6424
6292
  // src/program.ts
6425
6293
  init_esm_shims();
6426
- import { Effect as Effect28, Stream as Stream10 } from "effect";
6294
+ import { Effect as Effect29, Stream as Stream10 } from "effect";
6427
6295
 
6428
6296
  // src/consumers/index.ts
6429
6297
  init_esm_shims();
@@ -8881,10 +8749,10 @@ import {
8881
8749
  appendFile,
8882
8750
  copyFile,
8883
8751
  mkdir,
8884
- readFile as readFile2,
8752
+ readFile,
8885
8753
  rm
8886
8754
  } from "fs/promises";
8887
- import { dirname as dirname2, join as join2 } from "path";
8755
+ import { dirname, join as join2 } from "path";
8888
8756
  import { promisify as promisify2 } from "util";
8889
8757
  import { Effect as Effect8, Layer } from "effect";
8890
8758
 
@@ -8951,7 +8819,7 @@ function gitExec(command, cwd) {
8951
8819
  }
8952
8820
  });
8953
8821
  }
8954
- function directoryExists(dirPath) {
8822
+ function directoryExists2(dirPath) {
8955
8823
  return Effect8.tryPromise({
8956
8824
  try: async () => {
8957
8825
  await access2(dirPath);
@@ -8998,7 +8866,7 @@ function copyUntrackedFiles(worktreeDir) {
8998
8866
  const destPath = join2(worktreeDir, file);
8999
8867
  yield* Effect8.tryPromise({
9000
8868
  try: async () => {
9001
- await mkdir(dirname2(destPath), { recursive: true });
8869
+ await mkdir(dirname(destPath), { recursive: true });
9002
8870
  await copyFile(srcPath, destPath);
9003
8871
  },
9004
8872
  catch: () => new GitError({
@@ -9010,7 +8878,7 @@ function copyUntrackedFiles(worktreeDir) {
9010
8878
  yield* Effect8.tryPromise({
9011
8879
  try: async () => {
9012
8880
  const gitFilePath = join2(worktreeDir, ".git");
9013
- const gitFileContent = await readFile2(gitFilePath, "utf-8");
8881
+ const gitFileContent = await readFile(gitFilePath, "utf-8");
9014
8882
  const gitDirMatch = gitFileContent.match(GITDIR_REGEX);
9015
8883
  const gitDirPath = gitDirMatch?.[1]?.trim();
9016
8884
  if (!gitDirPath) {
@@ -9018,7 +8886,7 @@ function copyUntrackedFiles(worktreeDir) {
9018
8886
  }
9019
8887
  const gitDir = gitDirPath;
9020
8888
  const excludePath = join2(gitDir, "info", "exclude");
9021
- await mkdir(dirname2(excludePath), { recursive: true });
8889
+ await mkdir(dirname(excludePath), { recursive: true });
9022
8890
  const excludeContent = "\n# Untracked files copied from main worktree (auto-generated by ferix)\n" + untrackedFiles.join("\n") + "\n";
9023
8891
  await appendFile(excludePath, excludeContent);
9024
8892
  },
@@ -9042,7 +8910,7 @@ var make = {
9042
8910
  cause: error
9043
8911
  })
9044
8912
  });
9045
- const exists = yield* directoryExists(worktreeDir);
8913
+ const exists = yield* directoryExists2(worktreeDir);
9046
8914
  if (exists) {
9047
8915
  return worktreeDir;
9048
8916
  }
@@ -9063,7 +8931,7 @@ var make = {
9063
8931
  removeWorktree: (sessionId) => Effect8.gen(function* () {
9064
8932
  const worktreeDir = getWorktreeDir(sessionId);
9065
8933
  const branchName = getBranchName(sessionId);
9066
- const exists = yield* directoryExists(worktreeDir);
8934
+ const exists = yield* directoryExists2(worktreeDir);
9067
8935
  if (!exists) {
9068
8936
  return;
9069
8937
  }
@@ -9096,7 +8964,7 @@ var make = {
9096
8964
  }),
9097
8965
  removeWorktreeKeepBranch: (sessionId) => Effect8.gen(function* () {
9098
8966
  const worktreeDir = getWorktreeDir(sessionId);
9099
- const exists = yield* directoryExists(worktreeDir);
8967
+ const exists = yield* directoryExists2(worktreeDir);
9100
8968
  if (!exists) {
9101
8969
  return;
9102
8970
  }
@@ -9126,12 +8994,12 @@ var make = {
9126
8994
  }),
9127
8995
  getWorktreePath: (sessionId) => Effect8.gen(function* () {
9128
8996
  const worktreeDir = getWorktreeDir(sessionId);
9129
- const exists = yield* directoryExists(worktreeDir);
8997
+ const exists = yield* directoryExists2(worktreeDir);
9130
8998
  return exists ? worktreeDir : void 0;
9131
8999
  }),
9132
9000
  commitChanges: (sessionId, message) => Effect8.gen(function* () {
9133
9001
  const worktreeDir = getWorktreeDir(sessionId);
9134
- const exists = yield* directoryExists(worktreeDir);
9002
+ const exists = yield* directoryExists2(worktreeDir);
9135
9003
  if (!exists) {
9136
9004
  return yield* Effect8.fail(
9137
9005
  new GitError({
@@ -9187,7 +9055,7 @@ var make = {
9187
9055
  }),
9188
9056
  pushBranch: (sessionId) => Effect8.gen(function* () {
9189
9057
  const worktreeDir = getWorktreeDir(sessionId);
9190
- const exists = yield* directoryExists(worktreeDir);
9058
+ const exists = yield* directoryExists2(worktreeDir);
9191
9059
  if (!exists) {
9192
9060
  return yield* Effect8.fail(
9193
9061
  new GitError({
@@ -9208,7 +9076,7 @@ var make = {
9208
9076
  }),
9209
9077
  createPR: (sessionId, title, body, baseBranch) => Effect8.gen(function* () {
9210
9078
  const worktreeDir = getWorktreeDir(sessionId);
9211
- const exists = yield* directoryExists(worktreeDir);
9079
+ const exists = yield* directoryExists2(worktreeDir);
9212
9080
  if (!exists) {
9213
9081
  return yield* Effect8.fail(
9214
9082
  new GitError({
@@ -9246,7 +9114,7 @@ var make = {
9246
9114
  renameBranch: (sessionId, displayName) => Effect8.gen(function* () {
9247
9115
  const worktreeDir = getWorktreeDir(sessionId);
9248
9116
  const oldBranchName = getBranchName(sessionId);
9249
- const exists = yield* directoryExists(worktreeDir);
9117
+ const exists = yield* directoryExists2(worktreeDir);
9250
9118
  if (!exists) {
9251
9119
  return yield* Effect8.fail(
9252
9120
  new GitError({
@@ -9409,7 +9277,7 @@ var MemoryGit = {
9409
9277
 
9410
9278
  // src/layers/guardrails/file-system.ts
9411
9279
  init_esm_shims();
9412
- import { mkdir as mkdir2, readFile as readFile3, writeFile } from "fs/promises";
9280
+ import { mkdir as mkdir2, readFile as readFile2, writeFile } from "fs/promises";
9413
9281
  import { join as join3 } from "path";
9414
9282
  import { DateTime, Effect as Effect10, Layer as Layer3 } from "effect";
9415
9283
 
@@ -10477,7 +10345,7 @@ var make2 = {
10477
10345
  const existing = yield* Effect10.tryPromise({
10478
10346
  try: async () => {
10479
10347
  try {
10480
- const content = await readFile3(guardrailsPath, "utf-8");
10348
+ const content = await readFile2(guardrailsPath, "utf-8");
10481
10349
  return content;
10482
10350
  } catch {
10483
10351
  return null;
@@ -10526,7 +10394,7 @@ var make2 = {
10526
10394
  const content = yield* Effect10.tryPromise({
10527
10395
  try: async () => {
10528
10396
  try {
10529
- return await readFile3(guardrailsPath, "utf-8");
10397
+ return await readFile2(guardrailsPath, "utf-8");
10530
10398
  } catch {
10531
10399
  return null;
10532
10400
  }
@@ -11081,7 +10949,7 @@ function createProviderLayer2(name) {
11081
10949
 
11082
10950
  // src/layers/plan/file-system.ts
11083
10951
  init_esm_shims();
11084
- import { access as access3, mkdir as mkdir3, readdir as readdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
10952
+ import { access as access3, mkdir as mkdir3, readdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
11085
10953
  import { join as join4 } from "path";
11086
10954
  import { Effect as Effect16, Layer as Layer7 } from "effect";
11087
10955
 
@@ -11147,7 +11015,7 @@ var make3 = {
11147
11015
  const existingPlans = yield* Effect16.tryPromise({
11148
11016
  try: async () => {
11149
11017
  try {
11150
- const files = await readdir2(sessionDir);
11018
+ const files = await readdir(sessionDir);
11151
11019
  return files.filter((f) => f.endsWith(".json")).length;
11152
11020
  } catch {
11153
11021
  return 0;
@@ -11175,7 +11043,7 @@ var make3 = {
11175
11043
  if (sessionId) {
11176
11044
  const planPath = getPlanPath(sessionId, planId);
11177
11045
  const content = yield* Effect16.tryPromise({
11178
- try: () => readFile4(planPath, "utf-8"),
11046
+ try: () => readFile3(planPath, "utf-8"),
11179
11047
  catch: (error) => new PlanStoreError({
11180
11048
  message: `Failed to read plan file: ${planPath}`,
11181
11049
  operation: "load",
@@ -11187,7 +11055,7 @@ var make3 = {
11187
11055
  const sessionDirs = yield* Effect16.tryPromise({
11188
11056
  try: async () => {
11189
11057
  const plansDir = join4(process.cwd(), PLANS_DIR2);
11190
- const dirs = await readdir2(plansDir);
11058
+ const dirs = await readdir(plansDir);
11191
11059
  return dirs;
11192
11060
  },
11193
11061
  catch: (error) => new PlanStoreError({
@@ -11210,7 +11078,7 @@ var make3 = {
11210
11078
  }).pipe(Effect16.orElseSucceed(() => false));
11211
11079
  if (exists) {
11212
11080
  const content = yield* Effect16.tryPromise({
11213
- try: () => readFile4(planPath, "utf-8"),
11081
+ try: () => readFile3(planPath, "utf-8"),
11214
11082
  catch: (error) => new PlanStoreError({
11215
11083
  message: `Failed to read plan file: ${planPath}`,
11216
11084
  operation: "load",
@@ -11243,7 +11111,7 @@ var make3 = {
11243
11111
  const files = yield* Effect16.tryPromise({
11244
11112
  try: async () => {
11245
11113
  try {
11246
- return await readdir2(sessionDir);
11114
+ return await readdir(sessionDir);
11247
11115
  } catch {
11248
11116
  return [];
11249
11117
  }
@@ -11351,7 +11219,7 @@ var MemoryPlan = {
11351
11219
 
11352
11220
  // src/layers/progress/file-system.ts
11353
11221
  init_esm_shims();
11354
- import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
11222
+ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
11355
11223
  import { join as join5 } from "path";
11356
11224
  import { DateTime as DateTime3, Effect as Effect18, Layer as Layer9 } from "effect";
11357
11225
 
@@ -11419,7 +11287,7 @@ var make4 = {
11419
11287
  const existing = yield* Effect18.tryPromise({
11420
11288
  try: async () => {
11421
11289
  try {
11422
- const content = await readFile5(progressPath, "utf-8");
11290
+ const content = await readFile4(progressPath, "utf-8");
11423
11291
  return content;
11424
11292
  } catch {
11425
11293
  return null;
@@ -11464,7 +11332,7 @@ var make4 = {
11464
11332
  const content = yield* Effect18.tryPromise({
11465
11333
  try: async () => {
11466
11334
  try {
11467
- return await readFile5(progressPath, "utf-8");
11335
+ return await readFile4(progressPath, "utf-8");
11468
11336
  } catch {
11469
11337
  return null;
11470
11338
  }
@@ -11555,7 +11423,7 @@ var MemoryProgress = {
11555
11423
 
11556
11424
  // src/layers/session/file-system.ts
11557
11425
  init_esm_shims();
11558
- import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
11426
+ import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
11559
11427
  import { join as join6 } from "path";
11560
11428
  import { DateTime as DateTime5, Effect as Effect20, Layer as Layer11 } from "effect";
11561
11429
  import { humanId } from "human-id";
@@ -11638,7 +11506,7 @@ var make5 = {
11638
11506
  get: (sessionId) => Effect20.gen(function* () {
11639
11507
  const sessionPath = getSessionPath(sessionId);
11640
11508
  const content = yield* Effect20.tryPromise({
11641
- try: () => readFile6(sessionPath, "utf-8"),
11509
+ try: () => readFile5(sessionPath, "utf-8"),
11642
11510
  catch: (error) => new SessionStoreError({
11643
11511
  message: `Failed to read session file: ${sessionPath}`,
11644
11512
  operation: "get",
@@ -11731,7 +11599,7 @@ var MemorySession = {
11731
11599
 
11732
11600
  // src/layers/signal/ferix-parser.ts
11733
11601
  init_esm_shims();
11734
- import { Effect as Effect22, Layer as Layer13, Ref as Ref8 } from "effect";
11602
+ import { Effect as Effect23, Layer as Layer13, Ref as Ref8 } from "effect";
11735
11603
 
11736
11604
  // src/services/signal-parser.ts
11737
11605
  init_esm_shims();
@@ -12246,10 +12114,10 @@ signalSpecRegistry.register(tasksDefinedSpec);
12246
12114
  // src/layers/signal/ferix-parser.ts
12247
12115
  var MAX_BUFFER_SIZE = 1024 * 1024;
12248
12116
  function createAccumulatorImpl() {
12249
- return Effect22.gen(function* () {
12117
+ return Effect23.gen(function* () {
12250
12118
  const chunksRef = yield* Ref8.make([]);
12251
12119
  const emittedRef = yield* Ref8.make(/* @__PURE__ */ new Set());
12252
- const feed = (text) => Effect22.gen(function* () {
12120
+ const feed = (text) => Effect23.gen(function* () {
12253
12121
  const chunks = yield* Ref8.get(chunksRef);
12254
12122
  chunks.push(text);
12255
12123
  const buffer = chunks.join("");
@@ -12277,7 +12145,7 @@ function createAccumulatorImpl() {
12277
12145
  yield* Ref8.set(emittedRef, emitted);
12278
12146
  return newSignals;
12279
12147
  });
12280
- const flush = () => Effect22.gen(function* () {
12148
+ const flush = () => Effect23.gen(function* () {
12281
12149
  const chunks = yield* Ref8.get(chunksRef);
12282
12150
  const buffer = chunks.join("");
12283
12151
  yield* Ref8.set(chunksRef, []);
@@ -12293,7 +12161,7 @@ function createAccumulatorImpl() {
12293
12161
  });
12294
12162
  }
12295
12163
  var make6 = {
12296
- parse: (text) => Effect22.succeed(signalSpecRegistry.parseAll(text)),
12164
+ parse: (text) => Effect23.succeed(signalSpecRegistry.parseAll(text)),
12297
12165
  createAccumulator: createAccumulatorImpl
12298
12166
  };
12299
12167
  var Live15 = Layer13.succeed(SignalParser, make6);
@@ -12349,27 +12217,27 @@ init_esm_shims();
12349
12217
 
12350
12218
  // src/orchestrator/loop.ts
12351
12219
  init_esm_shims();
12352
- import { DateTime as DateTime10, Effect as Effect27, Option, pipe as pipe3, Ref as Ref12, Stream as Stream9 } from "effect";
12220
+ import { DateTime as DateTime10, Effect as Effect28, Option, pipe as pipe3, Ref as Ref12, Stream as Stream9 } from "effect";
12353
12221
 
12354
12222
  // src/orchestrator/discovery.ts
12355
12223
  init_esm_shims();
12356
- import { DateTime as DateTime8, Effect as Effect25, pipe, Ref as Ref10, Stream as Stream7 } from "effect";
12224
+ import { DateTime as DateTime8, Effect as Effect26, pipe, Ref as Ref10, Stream as Stream7 } from "effect";
12357
12225
 
12358
12226
  // src/layers/plan/task-generation.ts
12359
12227
  init_esm_shims();
12360
- import { mkdir as mkdir6, readFile as readFile7, writeFile as writeFile5 } from "fs/promises";
12228
+ import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
12361
12229
  import { join as join7 } from "path";
12362
- import { Effect as Effect23 } from "effect";
12230
+ import { Effect as Effect24 } from "effect";
12363
12231
  var PLANS_DIR4 = ".ferix/plans";
12364
12232
  function ensureDir5(dirPath) {
12365
- return Effect23.tryPromise({
12233
+ return Effect24.tryPromise({
12366
12234
  try: () => mkdir6(dirPath, { recursive: true }),
12367
12235
  catch: (error) => new PlanStoreError({
12368
12236
  message: `Failed to create directory: ${dirPath}`,
12369
12237
  operation: "create",
12370
12238
  cause: error
12371
12239
  })
12372
- }).pipe(Effect23.asVoid);
12240
+ }).pipe(Effect24.asVoid);
12373
12241
  }
12374
12242
  function getSessionDir4(sessionId) {
12375
12243
  return join7(process.cwd(), PLANS_DIR4, sessionId);
@@ -12378,12 +12246,12 @@ function getTasksMdPath(sessionId) {
12378
12246
  return join7(getSessionDir4(sessionId), "tasks.md");
12379
12247
  }
12380
12248
  function writeTasksMd(sessionId, tasks) {
12381
- return Effect23.gen(function* () {
12249
+ return Effect24.gen(function* () {
12382
12250
  const sessionDir = getSessionDir4(sessionId);
12383
12251
  yield* ensureDir5(sessionDir);
12384
12252
  const tasksMdPath = getTasksMdPath(sessionId);
12385
12253
  const content = formatTasksMd(tasks);
12386
- yield* Effect23.tryPromise({
12254
+ yield* Effect24.tryPromise({
12387
12255
  try: () => writeFile5(tasksMdPath, content, "utf-8"),
12388
12256
  catch: (error) => new PlanStoreError({
12389
12257
  message: `Failed to write tasks.md: ${tasksMdPath}`,
@@ -12575,7 +12443,7 @@ function mapSignalToDomain(signal, context) {
12575
12443
 
12576
12444
  // src/orchestrator/plan-updates.ts
12577
12445
  init_esm_shims();
12578
- import { DateTime as DateTime7, Effect as Effect24, Ref as Ref9 } from "effect";
12446
+ import { DateTime as DateTime7, Effect as Effect25, Ref as Ref9 } from "effect";
12579
12447
 
12580
12448
  // src/orchestrator/plan-updates/index.ts
12581
12449
  init_esm_shims();
@@ -12897,9 +12765,9 @@ function persistPlanUpdate(planStore, plan, operation) {
12897
12765
  tasks: plan.tasks
12898
12766
  }) : planStore.update(plan.id, plan);
12899
12767
  return storeOp.pipe(
12900
- Effect24.map(() => null),
12901
- Effect24.catchAll(
12902
- (error) => Effect24.succeed({
12768
+ Effect25.map(() => null),
12769
+ Effect25.catchAll(
12770
+ (error) => Effect25.succeed({
12903
12771
  _tag: "PlanUpdateFailed",
12904
12772
  operation,
12905
12773
  error: error.message,
@@ -12909,7 +12777,7 @@ function persistPlanUpdate(planStore, plan, operation) {
12909
12777
  );
12910
12778
  }
12911
12779
  function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessionId, originalTask) {
12912
- return Effect24.gen(function* () {
12780
+ return Effect25.gen(function* () {
12913
12781
  const currentPlan = yield* Ref9.get(currentPlanRef);
12914
12782
  const now = yield* DateTime7.now;
12915
12783
  const timestamp = DateTime7.formatIso(now);
@@ -12931,7 +12799,7 @@ function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessi
12931
12799
  });
12932
12800
  }
12933
12801
  function flushPlanPersistence(planStore, currentPlanRef, persistenceStateRef) {
12934
- return Effect24.gen(function* () {
12802
+ return Effect25.gen(function* () {
12935
12803
  const state = yield* Ref9.get(persistenceStateRef);
12936
12804
  if (!(state.dirty && state.pendingOperation)) {
12937
12805
  return [];
@@ -13255,12 +13123,12 @@ function areAllTasksComplete(plan) {
13255
13123
 
13256
13124
  // src/orchestrator/discovery.ts
13257
13125
  function processTextSignals(signalParser, text, context) {
13258
- return Effect25.gen(function* () {
13126
+ return Effect26.gen(function* () {
13259
13127
  const events = [];
13260
13128
  const parsedSignals = [];
13261
13129
  const signals = yield* signalParser.parse(text).pipe(
13262
- Effect25.tapError(
13263
- (error) => Effect25.logDebug(
13130
+ Effect26.tapError(
13131
+ (error) => Effect26.logDebug(
13264
13132
  "Signal parsing failed, continuing with empty signals",
13265
13133
  {
13266
13134
  error: String(error),
@@ -13268,7 +13136,7 @@ function processTextSignals(signalParser, text, context) {
13268
13136
  }
13269
13137
  )
13270
13138
  ),
13271
- Effect25.orElseSucceed(() => [])
13139
+ Effect26.orElseSucceed(() => [])
13272
13140
  );
13273
13141
  for (const signal of signals) {
13274
13142
  events.push(mapSignalToDomain(signal, context));
@@ -13278,7 +13146,7 @@ function processTextSignals(signalParser, text, context) {
13278
13146
  });
13279
13147
  }
13280
13148
  function processLLMEvent(signalParser, llmEvent, context) {
13281
- return Effect25.gen(function* () {
13149
+ return Effect26.gen(function* () {
13282
13150
  const domainEvent = mapLLMEventToDomain(llmEvent, context);
13283
13151
  const events = [domainEvent];
13284
13152
  const allSignals = [];
@@ -13323,7 +13191,7 @@ function planTasksToGeneratedTasks(plan) {
13323
13191
  }
13324
13192
  function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, config, sessionId, worktreePath, onSessionName) {
13325
13193
  return Stream7.unwrap(
13326
- Effect25.gen(function* () {
13194
+ Effect26.gen(function* () {
13327
13195
  const startTimeUtc = yield* DateTime8.now;
13328
13196
  const startTime = DateTime8.toEpochMillis(startTimeUtc);
13329
13197
  const persistenceStateRef = yield* Ref10.make({
@@ -13351,7 +13219,7 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
13351
13219
  ),
13352
13220
  Stream7.flatMap(
13353
13221
  (llmEvent) => Stream7.unwrap(
13354
- Effect25.gen(function* () {
13222
+ Effect26.gen(function* () {
13355
13223
  const now = yield* DateTime8.now;
13356
13224
  const context = {
13357
13225
  timestamp: DateTime8.toEpochMillis(now)
@@ -13391,7 +13259,7 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
13391
13259
  )
13392
13260
  );
13393
13261
  const completionStream = Stream7.fromEffect(
13394
- Effect25.gen(function* () {
13262
+ Effect26.gen(function* () {
13395
13263
  const persistEvents = yield* flushPlanPersistence(
13396
13264
  planStore,
13397
13265
  currentPlanRef,
@@ -13402,12 +13270,12 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
13402
13270
  if (plan && plan.tasks.length > 0) {
13403
13271
  const generatedTasks = planTasksToGeneratedTasks(plan);
13404
13272
  yield* writeTasksMd(sessionId, generatedTasks).pipe(
13405
- Effect25.tapError(
13406
- (error) => Effect25.logDebug("Failed to write tasks.md, continuing", {
13273
+ Effect26.tapError(
13274
+ (error) => Effect26.logDebug("Failed to write tasks.md, continuing", {
13407
13275
  error: String(error)
13408
13276
  })
13409
13277
  ),
13410
- Effect25.orElseSucceed(() => void 0)
13278
+ Effect26.orElseSucceed(() => void 0)
13411
13279
  );
13412
13280
  }
13413
13281
  const endTimeUtc = yield* DateTime8.now;
@@ -13417,8 +13285,8 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
13417
13285
  if (capturedName) {
13418
13286
  if (onSessionName) {
13419
13287
  yield* onSessionName(capturedName).pipe(
13420
- Effect25.tapError(
13421
- (error) => Effect25.logDebug(
13288
+ Effect26.tapError(
13289
+ (error) => Effect26.logDebug(
13422
13290
  "Failed to handle session name, continuing",
13423
13291
  {
13424
13292
  error: String(error),
@@ -13426,7 +13294,7 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
13426
13294
  }
13427
13295
  )
13428
13296
  ),
13429
- Effect25.orElseSucceed(() => void 0)
13297
+ Effect26.orElseSucceed(() => void 0)
13430
13298
  );
13431
13299
  }
13432
13300
  const sessionNameEvent = {
@@ -13458,15 +13326,15 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
13458
13326
 
13459
13327
  // src/orchestrator/iteration.ts
13460
13328
  init_esm_shims();
13461
- import { DateTime as DateTime9, Effect as Effect26, pipe as pipe2, Ref as Ref11, Stream as Stream8 } from "effect";
13329
+ import { DateTime as DateTime9, Effect as Effect27, pipe as pipe2, Ref as Ref11, Stream as Stream8 } from "effect";
13462
13330
  function processTextSignals2(signalParser, text, context) {
13463
- return Effect26.gen(function* () {
13331
+ return Effect27.gen(function* () {
13464
13332
  const events = [];
13465
13333
  let completed = false;
13466
13334
  const parsedSignals = [];
13467
13335
  const signals = yield* signalParser.parse(text).pipe(
13468
- Effect26.tapError(
13469
- (error) => Effect26.logDebug(
13336
+ Effect27.tapError(
13337
+ (error) => Effect27.logDebug(
13470
13338
  "Signal parsing failed, continuing with empty signals",
13471
13339
  {
13472
13340
  error: String(error),
@@ -13474,7 +13342,7 @@ function processTextSignals2(signalParser, text, context) {
13474
13342
  }
13475
13343
  )
13476
13344
  ),
13477
- Effect26.orElseSucceed(() => [])
13345
+ Effect27.orElseSucceed(() => [])
13478
13346
  );
13479
13347
  for (const signal of signals) {
13480
13348
  events.push(mapSignalToDomain(signal, context));
@@ -13487,7 +13355,7 @@ function processTextSignals2(signalParser, text, context) {
13487
13355
  });
13488
13356
  }
13489
13357
  function processLLMEvent2(signalParser, llmEvent, context) {
13490
- return Effect26.gen(function* () {
13358
+ return Effect27.gen(function* () {
13491
13359
  const domainEvent = mapLLMEventToDomain(llmEvent, context);
13492
13360
  const events = [domainEvent];
13493
13361
  let completed = false;
@@ -13520,7 +13388,7 @@ function processLLMEvent2(signalParser, llmEvent, context) {
13520
13388
  }
13521
13389
  function createIterationStream(llm, signalParser, planStore, currentPlanRef, loopCompletedRef, config, iteration, sessionId, worktreePath) {
13522
13390
  return Stream8.unwrap(
13523
- Effect26.gen(function* () {
13391
+ Effect27.gen(function* () {
13524
13392
  const currentPlan = yield* Ref11.get(currentPlanRef);
13525
13393
  const persistenceStateRef = yield* Ref11.make({
13526
13394
  dirty: false,
@@ -13543,7 +13411,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
13543
13411
  ),
13544
13412
  Stream8.flatMap(
13545
13413
  (llmEvent) => Stream8.unwrap(
13546
- Effect26.gen(function* () {
13414
+ Effect27.gen(function* () {
13547
13415
  const now = yield* DateTime9.now;
13548
13416
  const context = {
13549
13417
  timestamp: DateTime9.toEpochMillis(now)
@@ -13565,14 +13433,14 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
13565
13433
  events.push(...planEvents);
13566
13434
  }
13567
13435
  if (result.completed) {
13568
- yield* Effect26.logInfo(
13436
+ yield* Effect27.logInfo(
13569
13437
  "[DEBUG] createIterationStream: LLM emitted completion signal"
13570
13438
  );
13571
13439
  yield* Ref11.set(loopCompletedRef, true);
13572
13440
  }
13573
13441
  const updatedPlan = yield* Ref11.get(currentPlanRef);
13574
13442
  const allComplete = areAllTasksComplete(updatedPlan);
13575
- yield* Effect26.logInfo(
13443
+ yield* Effect27.logInfo(
13576
13444
  "[DEBUG] createIterationStream: Auto-complete check",
13577
13445
  {
13578
13446
  llmEmittedComplete: result.completed,
@@ -13584,7 +13452,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
13584
13452
  }
13585
13453
  );
13586
13454
  if (allComplete) {
13587
- yield* Effect26.logInfo(
13455
+ yield* Effect27.logInfo(
13588
13456
  "[DEBUG] createIterationStream: All tasks complete - ending loop"
13589
13457
  );
13590
13458
  yield* Ref11.set(loopCompletedRef, true);
@@ -13606,7 +13474,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
13606
13474
  )
13607
13475
  );
13608
13476
  const completionStream = Stream8.fromEffect(
13609
- Effect26.gen(function* () {
13477
+ Effect27.gen(function* () {
13610
13478
  const persistEvents = yield* flushPlanPersistence(
13611
13479
  planStore,
13612
13480
  currentPlanRef,
@@ -13631,14 +13499,14 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
13631
13499
  // src/orchestrator/loop.ts
13632
13500
  function runLoop(config) {
13633
13501
  return Stream9.unwrap(
13634
- Effect27.gen(function* () {
13502
+ Effect28.gen(function* () {
13635
13503
  const llm = yield* LLM;
13636
13504
  const signalParser = yield* SignalParser;
13637
13505
  const sessionStore = yield* SessionStore;
13638
13506
  const planStore = yield* PlanStore;
13639
13507
  const git = yield* Git;
13640
13508
  const session = yield* sessionStore.create(config.task).pipe(
13641
- Effect27.mapError(
13509
+ Effect28.mapError(
13642
13510
  (e) => new OrchestratorError({
13643
13511
  message: `Failed to create session: ${e.message}`,
13644
13512
  phase: "setup",
@@ -13647,15 +13515,15 @@ function runLoop(config) {
13647
13515
  )
13648
13516
  );
13649
13517
  const baseBranch = yield* git.getCurrentBranch().pipe(
13650
- Effect27.tapError(
13651
- (error) => Effect27.logDebug("Failed to get current branch", {
13518
+ Effect28.tapError(
13519
+ (error) => Effect28.logDebug("Failed to get current branch", {
13652
13520
  error: String(error)
13653
13521
  })
13654
13522
  ),
13655
- Effect27.orElseSucceed(() => void 0)
13523
+ Effect28.orElseSucceed(() => void 0)
13656
13524
  );
13657
13525
  const worktreePath = yield* git.createWorktree(session.id).pipe(
13658
- Effect27.mapError(
13526
+ Effect28.mapError(
13659
13527
  (e) => new OrchestratorError({
13660
13528
  message: `Failed to create worktree: ${e.message}`,
13661
13529
  phase: "setup",
@@ -13670,12 +13538,12 @@ function runLoop(config) {
13670
13538
  branchName,
13671
13539
  baseBranch
13672
13540
  }).pipe(
13673
- Effect27.tapError(
13674
- (error) => Effect27.logDebug("Failed to update session with worktree info", {
13541
+ Effect28.tapError(
13542
+ (error) => Effect28.logDebug("Failed to update session with worktree info", {
13675
13543
  error: String(error)
13676
13544
  })
13677
13545
  ),
13678
- Effect27.orElseSucceed(() => void 0)
13546
+ Effect28.orElseSucceed(() => void 0)
13679
13547
  );
13680
13548
  const startTimeUtc = yield* DateTime10.now;
13681
13549
  const startTime = DateTime10.toEpochMillis(startTimeUtc);
@@ -13696,7 +13564,7 @@ function runLoop(config) {
13696
13564
  config,
13697
13565
  timestamp: startTime
13698
13566
  };
13699
- const handleSessionName = (displayName) => Effect27.gen(function* () {
13567
+ const handleSessionName = (displayName) => Effect28.gen(function* () {
13700
13568
  const currentSession = yield* Ref12.get(sessionRef);
13701
13569
  const newBranchName = yield* git.renameBranch(
13702
13570
  session.id,
@@ -13722,7 +13590,7 @@ function runLoop(config) {
13722
13590
  );
13723
13591
  const iterationsStream = Stream9.unfoldEffect(
13724
13592
  1,
13725
- (iteration) => Effect27.gen(function* () {
13593
+ (iteration) => Effect28.gen(function* () {
13726
13594
  const completed = yield* Ref12.get(loopCompletedRef);
13727
13595
  if (completed || iteration > maxIterations) {
13728
13596
  return Option.none();
@@ -13768,8 +13636,8 @@ function runLoop(config) {
13768
13636
  );
13769
13637
  }).pipe(
13770
13638
  // Also catch setup errors (e.g., session creation failure)
13771
- Effect27.catchAll(
13772
- (error) => Effect27.succeed(
13639
+ Effect28.catchAll(
13640
+ (error) => Effect28.succeed(
13773
13641
  Stream9.succeed({
13774
13642
  _tag: "LoopFailed",
13775
13643
  error: {
@@ -13795,32 +13663,32 @@ Generated by Ferix`;
13795
13663
  }
13796
13664
  function createCompletionStream(sessionStore, git, sessionRef, config, startTime, loopCompletedRef, _worktreePath) {
13797
13665
  return Stream9.unwrap(
13798
- Effect27.gen(function* () {
13666
+ Effect28.gen(function* () {
13799
13667
  const session = yield* Ref12.get(sessionRef);
13800
13668
  const endTimeUtc = yield* DateTime10.now;
13801
13669
  const endTime = DateTime10.toEpochMillis(endTimeUtc);
13802
13670
  const durationMs = endTime - startTime;
13803
13671
  const completed = yield* Ref12.get(loopCompletedRef);
13804
13672
  yield* git.commitChanges(session.id, `feat: complete session ${session.id}`).pipe(
13805
- Effect27.tapError(
13806
- (error) => Effect27.logDebug("Final commit failed, continuing", {
13673
+ Effect28.tapError(
13674
+ (error) => Effect28.logDebug("Final commit failed, continuing", {
13807
13675
  sessionId: session.id,
13808
13676
  error: String(error)
13809
13677
  })
13810
13678
  ),
13811
- Effect27.orElseSucceed(() => void 0)
13679
+ Effect28.orElseSucceed(() => void 0)
13812
13680
  );
13813
13681
  let branchPushed = false;
13814
13682
  if (config.push === true) {
13815
13683
  const pushResult = yield* git.pushBranch(session.id).pipe(
13816
- Effect27.map(() => true),
13817
- Effect27.tapError(
13818
- (error) => Effect27.logDebug("Push failed, continuing", {
13684
+ Effect28.map(() => true),
13685
+ Effect28.tapError(
13686
+ (error) => Effect28.logDebug("Push failed, continuing", {
13819
13687
  sessionId: session.id,
13820
13688
  error: String(error)
13821
13689
  })
13822
13690
  ),
13823
- Effect27.orElseSucceed(() => false)
13691
+ Effect28.orElseSucceed(() => false)
13824
13692
  );
13825
13693
  branchPushed = pushResult;
13826
13694
  }
@@ -13829,25 +13697,25 @@ function createCompletionStream(sessionStore, git, sessionRef, config, startTime
13829
13697
  const title = `feat: ${session.originalTask.slice(0, 50)}`;
13830
13698
  const body = buildPRBody(session, config);
13831
13699
  const prResult = yield* git.createPR(session.id, title, body, session.baseBranch).pipe(
13832
- Effect27.map((url) => url),
13833
- Effect27.tapError(
13834
- (error) => Effect27.logDebug("PR creation failed, continuing", {
13700
+ Effect28.map((url) => url),
13701
+ Effect28.tapError(
13702
+ (error) => Effect28.logDebug("PR creation failed, continuing", {
13835
13703
  sessionId: session.id,
13836
13704
  error: String(error)
13837
13705
  })
13838
13706
  ),
13839
- Effect27.orElseSucceed(() => void 0)
13707
+ Effect28.orElseSucceed(() => void 0)
13840
13708
  );
13841
13709
  prUrl = prResult;
13842
13710
  }
13843
13711
  yield* git.removeWorktreeKeepBranch(session.id).pipe(
13844
- Effect27.tapError(
13845
- (error) => Effect27.logDebug("Worktree cleanup failed, continuing", {
13712
+ Effect28.tapError(
13713
+ (error) => Effect28.logDebug("Worktree cleanup failed, continuing", {
13846
13714
  sessionId: session.id,
13847
13715
  error: String(error)
13848
13716
  })
13849
13717
  ),
13850
- Effect27.orElseSucceed(() => void 0)
13718
+ Effect28.orElseSucceed(() => void 0)
13851
13719
  );
13852
13720
  const worktreeRemoved = {
13853
13721
  _tag: "WorktreeRemoved",
@@ -13868,13 +13736,13 @@ function createCompletionStream(sessionStore, git, sessionRef, config, startTime
13868
13736
  status: completed ? "completed" : "paused",
13869
13737
  worktreePath: void 0
13870
13738
  }).pipe(
13871
- Effect27.tapError(
13872
- (error) => Effect27.logDebug("Session update failed, continuing", {
13739
+ Effect28.tapError(
13740
+ (error) => Effect28.logDebug("Session update failed, continuing", {
13873
13741
  sessionId: session.id,
13874
13742
  error: String(error)
13875
13743
  })
13876
13744
  ),
13877
- Effect27.orElseSucceed(() => void 0)
13745
+ Effect28.orElseSucceed(() => void 0)
13878
13746
  );
13879
13747
  const events = [worktreeRemoved];
13880
13748
  if (branchPushed) {
@@ -13904,7 +13772,7 @@ function createCompletionStream(sessionStore, git, sessionRef, config, startTime
13904
13772
  function run(options) {
13905
13773
  const { config, consumer: consumerType = "headless", onEvent } = options;
13906
13774
  const events = runLoop(config);
13907
- const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect28.sync(() => onEvent(event)))) : events;
13775
+ const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect29.sync(() => onEvent(event)))) : events;
13908
13776
  const layers = config.provider ? createProductionLayers(config.provider) : ProductionLayers;
13909
13777
  const eventsWithLayers = eventsWithCallback.pipe(Stream10.provideLayer(layers));
13910
13778
  if (consumerType === "none") {
@@ -13916,7 +13784,7 @@ function run(options) {
13916
13784
  function runTest(options, mockEvents) {
13917
13785
  const { config, onEvent } = options;
13918
13786
  const events = runLoop(config);
13919
- const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect28.sync(() => onEvent(event)))) : events;
13787
+ const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect29.sync(() => onEvent(event)))) : events;
13920
13788
  const layers = mockEvents ? createTestLayers(mockEvents) : TestLayers;
13921
13789
  const eventsWithLayers = eventsWithCallback.pipe(Stream10.provideLayer(layers));
13922
13790
  return eventsWithLayers.pipe(Stream10.runDrain);
@@ -13924,11 +13792,11 @@ function runTest(options, mockEvents) {
13924
13792
  function collectEvents(config, mockEvents) {
13925
13793
  const events = runLoop(config);
13926
13794
  const layers = mockEvents ? createTestLayers(mockEvents) : TestLayers;
13927
- return events.pipe(Stream10.provideLayer(layers), Stream10.runCollect).pipe(Effect28.map((chunk) => Array.from(chunk)));
13795
+ return events.pipe(Stream10.provideLayer(layers), Stream10.runCollect).pipe(Effect29.map((chunk) => Array.from(chunk)));
13928
13796
  }
13929
13797
  function main(config) {
13930
13798
  const consumerType = process.stdout.isTTY ? "tui" : "headless";
13931
- return run({ config, consumer: consumerType }).pipe(Effect28.runPromise);
13799
+ return run({ config, consumer: consumerType }).pipe(Effect29.runPromise);
13932
13800
  }
13933
13801
 
13934
13802
  // src/services/index.ts
@@ -13954,55 +13822,418 @@ program.command("run", { isDefault: true }).argument("<task>", "Task description
13954
13822
  process.exit(1);
13955
13823
  }
13956
13824
  });
13957
- 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) => {
13825
+ var NON_NPM_VERSION_PREFIXES2 = ["workspace:", "file:", "link:", "portal:"];
13826
+ var isNonNpmDependency = (version2) => NON_NPM_VERSION_PREFIXES2.some((prefix) => version2.startsWith(prefix));
13827
+ var extractDependencies = (pkg) => {
13828
+ const deps = pkg.dependencies ?? {};
13829
+ const devDeps = pkg.devDependencies ?? {};
13830
+ const allDeps = /* @__PURE__ */ new Map();
13831
+ for (const [name, version2] of Object.entries(deps)) {
13832
+ if (!isNonNpmDependency(version2)) {
13833
+ allDeps.set(name, version2);
13834
+ }
13835
+ }
13836
+ for (const [name, version2] of Object.entries(devDeps)) {
13837
+ if (!(allDeps.has(name) || isNonNpmDependency(version2))) {
13838
+ allDeps.set(name, version2);
13839
+ }
13840
+ }
13841
+ return Array.from(allDeps.keys());
13842
+ };
13843
+ var extractWorkspacePatterns = (pkg) => {
13844
+ const workspaces = pkg.workspaces;
13845
+ if (!workspaces) {
13846
+ return [];
13847
+ }
13848
+ if (Array.isArray(workspaces)) {
13849
+ return workspaces.filter((w) => typeof w === "string");
13850
+ }
13851
+ if (typeof workspaces === "object" && "packages" in workspaces) {
13852
+ const packages = workspaces.packages;
13853
+ if (Array.isArray(packages)) {
13854
+ return packages.filter((w) => typeof w === "string");
13855
+ }
13856
+ }
13857
+ return [];
13858
+ };
13859
+ var GLOB_SUFFIX_PATTERN = /\/\*+$/;
13860
+ var expandGlobPattern = async (rootDir, pattern) => {
13861
+ if (pattern.endsWith("/*") || pattern.endsWith("/**")) {
13862
+ const baseDir = pattern.replace(GLOB_SUFFIX_PATTERN, "");
13863
+ const fullPath2 = join8(rootDir, baseDir);
13864
+ try {
13865
+ const entries = await readdir2(fullPath2, { withFileTypes: true });
13866
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => join8(fullPath2, entry.name));
13867
+ } catch {
13868
+ return [];
13869
+ }
13870
+ }
13871
+ const fullPath = join8(rootDir, pattern);
13958
13872
  try {
13959
- console.log("\nScanning for package.json files...");
13960
- const result = await Effect29.runPromise(
13961
- sync(options.path, {
13962
- dryRun: options.dryRun ?? false,
13963
- global: options.global ?? false,
13964
- dev: options.dev ?? false
13965
- })
13966
- );
13967
- if (options.dev) {
13968
- console.log(pc17.yellow("Using development server"));
13873
+ await access4(fullPath);
13874
+ return [fullPath];
13875
+ } catch {
13876
+ return [];
13877
+ }
13878
+ };
13879
+ var readPackageJsonFile = async (filePath) => {
13880
+ const content = await readFile7(filePath, "utf-8");
13881
+ return JSON.parse(content);
13882
+ };
13883
+ var discoverPackageJsonFiles = async (rootPath, rootPkg) => {
13884
+ const rootDir = dirname2(rootPath);
13885
+ const patterns = extractWorkspacePatterns(rootPkg);
13886
+ if (patterns.length === 0) {
13887
+ return [rootPath];
13888
+ }
13889
+ const packageJsonPaths = [rootPath];
13890
+ for (const pattern of patterns) {
13891
+ const dirs = await expandGlobPattern(rootDir, pattern);
13892
+ for (const dir of dirs) {
13893
+ const pkgPath = join8(dir, "package.json");
13894
+ try {
13895
+ await access4(pkgPath);
13896
+ packageJsonPaths.push(pkgPath);
13897
+ } catch {
13898
+ }
13969
13899
  }
13970
- const packageMsg = result.packageJsonCount > 1 ? `Found ${pc17.bold(String(result.packageJsonCount))} package.json files (monorepo)` : "Found 1 package.json file";
13971
- console.log(packageMsg);
13972
- console.log(
13973
- `Found ${pc17.bold(String(result.dependencies.length))} dependencies (deduplicated)`
13974
- );
13975
- console.log(
13976
- `Resolved ${pc17.bold(String(result.orgs.length))} unique GitHub organizations`
13900
+ }
13901
+ return packageJsonPaths;
13902
+ };
13903
+ var SYMBOLS = {
13904
+ success: pc17.green("\u2713"),
13905
+ error: pc17.red("\u2717")
13906
+ };
13907
+ var printHeader = (title, subtitle) => {
13908
+ console.log();
13909
+ console.log(pc17.bold(pc17.cyan(` ${title}`)));
13910
+ if (subtitle) {
13911
+ console.log(pc17.dim(` ${subtitle}`));
13912
+ }
13913
+ console.log();
13914
+ };
13915
+ var printSection = (title) => {
13916
+ console.log();
13917
+ console.log(pc17.bold(` ${title}`));
13918
+ };
13919
+ var printRepo = (owner, repo, index) => {
13920
+ const num = pc17.dim(`${String(index + 1).padStart(2, " ")}.`);
13921
+ console.log(` ${num} ${pc17.cyan(owner)}${pc17.dim("/")}${pc17.white(repo)}`);
13922
+ };
13923
+ var printSuccess = (message) => {
13924
+ console.log(` ${SYMBOLS.success} ${pc17.green(message)}`);
13925
+ };
13926
+ var printError = (message) => {
13927
+ console.log(` ${SYMBOLS.error} ${pc17.red(message)}`);
13928
+ };
13929
+ var printHint = (message) => {
13930
+ console.log(pc17.dim(` ${message}`));
13931
+ };
13932
+ var createSpinner = (text) => {
13933
+ return ora({
13934
+ text,
13935
+ prefixText: " ",
13936
+ spinner: "dots"
13937
+ });
13938
+ };
13939
+ var discoverPackages = async (state, packagePath) => {
13940
+ state.spinner = createSpinner("Scanning for package.json files...").start();
13941
+ const absolutePath = resolve(packagePath);
13942
+ await access4(absolutePath);
13943
+ const rootPkg = await readPackageJsonFile(absolutePath);
13944
+ state.packageJsonPaths = await discoverPackageJsonFiles(
13945
+ absolutePath,
13946
+ rootPkg
13947
+ );
13948
+ const isMonorepo = state.packageJsonPaths.length > 1;
13949
+ state.spinner.succeed(
13950
+ isMonorepo ? `Found ${pc17.bold(String(state.packageJsonPaths.length))} package.json files ${pc17.dim("(monorepo)")}` : "Found package.json"
13951
+ );
13952
+ return true;
13953
+ };
13954
+ var extractAllDependencies = async (state) => {
13955
+ state.spinner = createSpinner("Extracting dependencies...").start();
13956
+ const allDependencies = /* @__PURE__ */ new Set();
13957
+ for (const pkgPath of state.packageJsonPaths) {
13958
+ const pkg = await readPackageJsonFile(pkgPath);
13959
+ for (const dep of extractDependencies(pkg)) {
13960
+ allDependencies.add(dep);
13961
+ }
13962
+ }
13963
+ state.dependencies = Array.from(allDependencies);
13964
+ if (state.dependencies.length === 0) {
13965
+ state.spinner.warn("No dependencies found");
13966
+ return false;
13967
+ }
13968
+ state.spinner.succeed(
13969
+ `Found ${pc17.bold(String(state.dependencies.length))} unique dependencies`
13970
+ );
13971
+ return true;
13972
+ };
13973
+ var resolveOrganizations = async (state, isDev) => {
13974
+ state.spinner = createSpinner("Resolving GitHub organizations...").start();
13975
+ const packageOrgs = await Effect30.runPromise(
13976
+ resolvePackageOrgs(state.dependencies, isDev)
13977
+ );
13978
+ state.orgs = Array.from(
13979
+ new Set(
13980
+ packageOrgs.map((p) => p.githubOrg).filter((org) => org !== null)
13981
+ )
13982
+ );
13983
+ if (state.orgs.length === 0) {
13984
+ state.spinner.warn("No GitHub organizations found");
13985
+ printHint("Your dependencies don't have linked GitHub organizations.");
13986
+ return false;
13987
+ }
13988
+ state.spinner.succeed(
13989
+ `Resolved ${pc17.bold(String(state.orgs.length))} GitHub organizations`
13990
+ );
13991
+ return true;
13992
+ };
13993
+ var findRepositories = async (state, isDev) => {
13994
+ state.spinner = createSpinner("Searching for skill repositories...").start();
13995
+ state.skillRepos = await Effect30.runPromise(findSkillRepos(state.orgs, isDev));
13996
+ if (state.skillRepos.length === 0) {
13997
+ state.spinner.warn("No skill repositories found");
13998
+ printHint(
13999
+ "None of your dependency organizations have published skills yet."
13977
14000
  );
13978
- if (result.skillRepos.length === 0) {
13979
- console.log(
13980
- `
13981
- ${pc17.yellow("No skill repositories found for your dependencies.")}`
14001
+ return false;
14002
+ }
14003
+ state.spinner.succeed(
14004
+ `Found ${pc17.bold(String(state.skillRepos.length))} skill ${state.skillRepos.length === 1 ? "repository" : "repositories"}`
14005
+ );
14006
+ return true;
14007
+ };
14008
+ var selectRepositories = async (skillRepos) => {
14009
+ if (skillRepos.length === 1) {
14010
+ const repo = skillRepos[0];
14011
+ if (repo) {
14012
+ printHint(
14013
+ `Only 1 repository found, auto-selecting: ${pc17.cyan(`${repo.owner}/${repo.repo}`)}`
13982
14014
  );
13983
- return;
13984
14015
  }
13985
- console.log(
13986
- `
13987
- Found ${pc17.bold(String(result.skillRepos.length))} skill repositories:
13988
- `
14016
+ return { type: "selected", repos: skillRepos };
14017
+ }
14018
+ if (!process.stdin.isTTY) {
14019
+ printHint(
14020
+ `Non-interactive terminal detected, selecting all ${skillRepos.length} repositories.`
13989
14021
  );
13990
- for (const repo of result.skillRepos) {
13991
- console.log(` ${pc17.green("\u2022")} ${repo.owner}/${repo.repo}`);
13992
- }
13993
- if (options.dryRun) {
13994
- console.log(
13995
- `
13996
- ${pc17.dim("Run without --dry-run to install these skills.")}`
14022
+ printHint(`Use ${pc17.cyan("--yes")} flag to skip this message in CI/CD.`);
14023
+ return { type: "selected", repos: skillRepos };
14024
+ }
14025
+ console.log();
14026
+ const selected = await multiselect({
14027
+ message: "Select repositories to install (space to toggle, a to toggle all)",
14028
+ options: skillRepos.map((repo) => ({
14029
+ value: repo,
14030
+ label: `${repo.owner}/${repo.repo}`
14031
+ })),
14032
+ required: false
14033
+ });
14034
+ if (isCancel(selected)) {
14035
+ return { type: "cancelled" };
14036
+ }
14037
+ if (selected.length === 0) {
14038
+ return { type: "none" };
14039
+ }
14040
+ return { type: "selected", repos: selected };
14041
+ };
14042
+ var installRepositories = async (state, reposToInstall, isGlobal, agents) => {
14043
+ printSection("Installing");
14044
+ console.log();
14045
+ const installed = [];
14046
+ const failed = [];
14047
+ for (const repo of reposToInstall) {
14048
+ const repoId = `${repo.owner}/${repo.repo}`;
14049
+ state.spinner = createSpinner(
14050
+ `Installing ${pc17.cyan(repo.owner)}${pc17.dim("/")}${pc17.white(repo.repo)}...`
14051
+ ).start();
14052
+ try {
14053
+ await Effect30.runPromise(
14054
+ installSkills([repo], {
14055
+ dryRun: false,
14056
+ global: isGlobal,
14057
+ agents: [...agents]
14058
+ })
13997
14059
  );
13998
- } else {
13999
- console.log(
14000
- `
14001
- ${pc17.green("\u2713")} Installed ${pc17.bold(String(result.installed.length))} skill repositories`
14060
+ state.spinner.succeed(
14061
+ `Installed ${pc17.cyan(repo.owner)}${pc17.dim("/")}${pc17.white(repo.repo)}`
14062
+ );
14063
+ installed.push(repoId);
14064
+ } catch {
14065
+ state.spinner.fail(
14066
+ `Failed to install ${pc17.cyan(repo.owner)}${pc17.dim("/")}${pc17.white(repo.repo)}`
14002
14067
  );
14068
+ failed.push(repoId);
14003
14069
  }
14070
+ }
14071
+ return { installed, failed };
14072
+ };
14073
+ var displaySummary = (installed, failed, isGlobal, agents) => {
14074
+ printSection("Summary");
14075
+ console.log();
14076
+ if (installed.length > 0) {
14077
+ printSuccess(
14078
+ `${installed.length} skill ${installed.length === 1 ? "repository" : "repositories"} installed successfully`
14079
+ );
14080
+ }
14081
+ if (failed.length > 0) {
14082
+ printError(
14083
+ `${failed.length} ${failed.length === 1 ? "installation" : "installations"} failed`
14084
+ );
14085
+ }
14086
+ const installLocation = isGlobal ? "globally" : "in project";
14087
+ const agentList = agents.length > 0 ? agents.join(", ") : "all agents";
14088
+ printHint(`Skills installed ${installLocation} to: ${pc17.cyan(agentList)}`);
14089
+ console.log();
14090
+ };
14091
+ var detectProjectAgents = async (state, projectDir) => {
14092
+ state.spinner = createSpinner("Detecting coding agents...").start();
14093
+ state.detectedAgents = await Effect30.runPromise(detectAgents(projectDir));
14094
+ if (state.detectedAgents.length === 0) {
14095
+ state.spinner.warn("No coding agents detected");
14096
+ printHint(
14097
+ `No agent directories found (${pc17.dim(".cursor/, .claude/, .opencode/, etc.")})`
14098
+ );
14099
+ printHint(
14100
+ `Use ${pc17.cyan("--agents")} to specify agents manually, e.g. ${pc17.cyan("--agents cursor claude-code")}`
14101
+ );
14102
+ return false;
14103
+ }
14104
+ state.spinner.succeed(
14105
+ `Detected agents: ${pc17.cyan(state.detectedAgents.join(", "))}`
14106
+ );
14107
+ return true;
14108
+ };
14109
+ var determineAgents = async (state, packagePath, manualAgents) => {
14110
+ if (manualAgents && manualAgents.length > 0) {
14111
+ const invalidAgents = validateAgentNames(manualAgents);
14112
+ if (invalidAgents.length > 0) {
14113
+ printError(`Invalid agent names: ${invalidAgents.join(", ")}`);
14114
+ printHint(`Supported agents: ${SUPPORTED_AGENTS.join(", ")}`);
14115
+ console.log();
14116
+ return null;
14117
+ }
14118
+ printSuccess(`Using specified agents: ${pc17.cyan(manualAgents.join(", "))}`);
14119
+ return manualAgents;
14120
+ }
14121
+ const projectDir = dirname2(resolve(packagePath));
14122
+ const hasAgents = await detectProjectAgents(state, projectDir);
14123
+ return hasAgents ? state.detectedAgents : null;
14124
+ };
14125
+ var handleRepoSelection = async (skillRepos, skipSelection) => {
14126
+ if (skipSelection) {
14127
+ printSuccess(
14128
+ `Auto-selecting all ${skillRepos.length} repositories (--yes)`
14129
+ );
14130
+ return skillRepos;
14131
+ }
14132
+ const selection = await selectRepositories(skillRepos);
14133
+ if (selection.type === "cancelled") {
14134
+ cancel("Operation cancelled.");
14135
+ process.exit(0);
14136
+ }
14137
+ if (selection.type === "none") {
14138
+ console.log();
14139
+ printHint("No repositories selected. Skipping installation.");
14140
+ console.log();
14141
+ return null;
14142
+ }
14143
+ printSuccess(`Selected ${selection.repos.length} repositories`);
14144
+ return selection.repos;
14145
+ };
14146
+ var displayDryRunSummary = (reposToInstall, agentsToUse) => {
14147
+ console.log();
14148
+ printSection("Would install");
14149
+ console.log();
14150
+ for (let i = 0; i < reposToInstall.length; i++) {
14151
+ const repo = reposToInstall[i];
14152
+ if (repo) {
14153
+ printRepo(repo.owner, repo.repo, i);
14154
+ }
14155
+ }
14156
+ console.log();
14157
+ printHint(
14158
+ `Would install to: ${pc17.cyan(agentsToUse.join(", ") || "all agents")}`
14159
+ );
14160
+ printHint(`Run without ${pc17.cyan("--dry-run")} to install these skills.`);
14161
+ console.log();
14162
+ };
14163
+ var runSyncCommand = async (options) => {
14164
+ const {
14165
+ path: packagePath,
14166
+ dryRun,
14167
+ global: isGlobal,
14168
+ dev: isDev,
14169
+ agents: manualAgents,
14170
+ yes: skipSelection
14171
+ } = options;
14172
+ printHeader(
14173
+ "Ferix Sync",
14174
+ isDev ? pc17.yellow("Development Mode") : "Discovering skills from your dependencies"
14175
+ );
14176
+ const state = {
14177
+ spinner: void 0,
14178
+ packageJsonPaths: [],
14179
+ dependencies: [],
14180
+ orgs: [],
14181
+ skillRepos: [],
14182
+ detectedAgents: []
14183
+ };
14184
+ await discoverPackages(state, packagePath);
14185
+ const agentsToUse = await determineAgents(state, packagePath, manualAgents);
14186
+ if (!agentsToUse) {
14187
+ return;
14188
+ }
14189
+ const hasDeps = await extractAllDependencies(state);
14190
+ if (!hasDeps) {
14191
+ return;
14192
+ }
14193
+ const hasOrgs = await resolveOrganizations(state, isDev);
14194
+ if (!hasOrgs) {
14195
+ return;
14196
+ }
14197
+ const hasRepos = await findRepositories(state, isDev);
14198
+ if (!hasRepos) {
14199
+ return;
14200
+ }
14201
+ const reposToInstall = await handleRepoSelection(
14202
+ state.skillRepos,
14203
+ skipSelection
14204
+ );
14205
+ if (!reposToInstall) {
14206
+ return;
14207
+ }
14208
+ if (dryRun) {
14209
+ displayDryRunSummary(reposToInstall, agentsToUse);
14210
+ return;
14211
+ }
14212
+ const { installed, failed } = await installRepositories(
14213
+ state,
14214
+ reposToInstall,
14215
+ isGlobal,
14216
+ agentsToUse
14217
+ );
14218
+ displaySummary(installed, failed, isGlobal, agentsToUse);
14219
+ };
14220
+ 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").option(
14221
+ "-a, --agents <agents...>",
14222
+ "Specify agents to install to (auto-detects if not provided)"
14223
+ ).option("-y, --yes", "Skip selection prompt, install all repositories").action(async (options) => {
14224
+ try {
14225
+ await runSyncCommand({
14226
+ path: options.path,
14227
+ dryRun: options.dryRun ?? false,
14228
+ global: options.global ?? false,
14229
+ dev: options.dev ?? false,
14230
+ agents: options.agents,
14231
+ yes: options.yes ?? false
14232
+ });
14004
14233
  } catch (error) {
14005
- console.error(pc17.red("Error:"), error);
14234
+ console.log();
14235
+ printError(error instanceof Error ? error.message : String(error));
14236
+ console.log();
14006
14237
  process.exit(1);
14007
14238
  }
14008
14239
  });