@eigenpal/cli 0.5.6 → 0.5.8

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/CHANGELOG.md CHANGED
@@ -317,6 +317,12 @@ actual) { ... }` declaration around your statements. Parameter order is
317
317
  - **`init agent` and bare `agent` now exit 2** instead of 0 when invoked. Both subcommands are reserved-but-unimplemented placeholders, and exiting 0 made it possible for a CI script that misrouted into one of them to silently no-op. POSIX exit 2 ("command exists but isn't usable as invoked") makes the misroute fail loudly. The human-readable "coming soon" stderr message is unchanged.
318
318
  - **New `--no-color` global flag.** Disables ANSI colors in all output, matching the convention shared by `gh`, `kubectl`, `npm`, and `terraform`. Equivalent to setting `NO_COLOR=1` in the environment, but takes effect for the current invocation only. Implemented as a lazy picocolors wrapper so the flip propagates to every helper in `lib/ui.ts` (and every downstream caller of `pc`) regardless of when in the command lifecycle the flag is parsed.
319
319
 
320
+ - 809f3d4: `auth list`: the org name is now the primary label (bold, immediately after
321
+ the marker), the profile slug is dimmed beside it (still the value you feed
322
+ to `auth use <name>` or `EIGENPAL_PROFILE=<name>`), and the base URL trails
323
+ on the right. The redundant `(tenantId)` column was dropped — the profile
324
+ slug already disambiguates. `auth use` (interactive picker) now prints the
325
+ non-interactive form on success so you learn the slug you just picked.
320
326
  - 49a8f94: Fixed a stray `undefined` in the `eigenpal auth login` outro. The success message used `dim(...)` (a stderr printer that returns `void`) inside a template literal where `ui.dim(...)` (the inline string formatter) was meant. The dim "Saved profile X — switch with" hint now renders correctly instead of literal `undefined`.
321
327
  - 16c6e83: Updated `@eigenpal/cli` author from `Eigenpal <hello@eigenpal.com>` to `Jedr Blaszyk <jedr@eigenpal.com>`. Surfaces on the npm package page and in `npm view @eigenpal/cli`.
322
328
  - b1d2d77: CLI: default `baseUrl` is now `https://studio.eigenpal.com` instead of `http://localhost:3000`.
@@ -467,6 +473,8 @@ actual) { ... }` declaration around your statements. Parameter order is
467
473
 
468
474
  - 71361fd: `workflow get-experiment-status --watch` now prints a per-example failure summary on stderr when the batch finishes with any failed/cancelled execution: example name, top-level error (truncated), and the exact `eigenpal execution get <exec-id>` command to drill into step-by-step detail. Removes the need for the agent to grep through a 1000-line JSON dump to find which example broke and why. `reference/debugging.md` documents the discovery path.
469
475
  - 71361fd: `eigenpal workflow get-experiment-status --watch` now polls until every execution in the batch reaches a terminal state (`completed` / `failed` / `cancelled`), then exits non-zero if any execution failed or was cancelled. Removes the need for agent-side polling loops that didn't notice all-terminal-already and kept ticking. Renders a one-line `N/M terminal (counts)` progress summary on stderr (in-place rewrite when stderr is a TTY), dumps the full JSON on stdout when done. `--interval <s>` and `--max-wait <s>` are configurable; defaults are 5s/30min.
476
+ - c3bc4e9: Fix Git-backed source release and status edge cases.
477
+ - 04e4018: Harden hidden Git materialization commands for package-ref installs, frozen lockfile replay, dependency materialization, and source authoring smoke flows.
470
478
  - 71361fd: `install-skill`: multi-tool support via interactive multiselect.
471
479
  - Opens a `@clack/prompts` multiselect picker over supported agent tools
472
480
  (Claude Code, Cursor). Toggle on to install, toggle off to uninstall —
package/dist/cli.js CHANGED
@@ -181601,7 +181601,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
181601
181601
  // package.json
181602
181602
  var package_default = {
181603
181603
  name: "@eigenpal/cli",
181604
- version: "0.5.6",
181604
+ version: "0.5.8",
181605
181605
  description: "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
181606
181606
  keywords: [
181607
181607
  "eigenpal",
@@ -183847,16 +183847,19 @@ async function authList() {
183847
183847
  dim("No profiles configured. Run `eigenpal auth login` to add one.");
183848
183848
  return;
183849
183849
  }
183850
- const nameWidth = Math.max(16, ...names.map((n) => n.length));
183851
- for (const name of names.sort()) {
183850
+ const rows = names.sort().map((name) => {
183852
183851
  const p2 = profiles[name];
183853
- const marker = name === current ? ui.ok("●") : ui.dim("○");
183854
183852
  const tenant = p2.tenantName ?? p2.tenantId ?? "?";
183855
- const tenantLabel = p2.tenantName && p2.tenantId ? `${tenant} ${ui.dim(`(${p2.tenantId})`)}` : tenant;
183856
- console.log(`${marker} ${ui.bold(name.padEnd(nameWidth))} ${ui.dim(tenantLabel)} ${ui.dim(p2.baseUrl)}`);
183853
+ return { name, baseUrl: p2.baseUrl, tenant };
183854
+ });
183855
+ const tenantWidth = Math.max(16, ...rows.map((r) => r.tenant.length));
183856
+ const nameWidth = Math.max(16, ...rows.map((r) => r.name.length));
183857
+ for (const r of rows) {
183858
+ const marker = r.name === current ? ui.ok("●") : ui.dim("○");
183859
+ console.log(`${marker} ${ui.bold(r.tenant.padEnd(tenantWidth))} ${ui.dim(r.name.padEnd(nameWidth))} ${ui.dim(r.baseUrl)}`);
183857
183860
  }
183858
183861
  console.log("");
183859
- dim(`(● = active. Switch with \`eigenpal auth use <name>\` or \`EIGENPAL_PROFILE=<name>\`.)`);
183862
+ dim(`(● = active. Switch with \`eigenpal auth use <name>\` or \`EIGENPAL_PROFILE=<name>\` for one shell.)`);
183860
183863
  }
183861
183864
  async function authUse(profileName) {
183862
183865
  const { current, profiles } = listProfiles();
@@ -183901,7 +183904,8 @@ async function authUse(profileName) {
183901
183904
  if (profileName) {
183902
183905
  success2(`Switched to ${ui.bold(target)}${tenantSuffix}`);
183903
183906
  } else {
183904
- ye(`${ui.ok("✓")} Switched to ${ui.bold(target)}${tenantSuffix}`);
183907
+ ye(`${ui.ok("✓")} Switched to ${ui.bold(target)}${tenantSuffix}
183908
+ ${ui.dim(`In scripts: \`eigenpal auth use ${target}\` or \`EIGENPAL_PROFILE=${target}\``)}`);
183905
183909
  }
183906
183910
  }
183907
183911
 
@@ -184102,7 +184106,20 @@ init_src();
184102
184106
  init_zod();
184103
184107
  var import_yaml2 = __toESM(require_dist(), 1);
184104
184108
  import { spawnSync as spawnSync2 } from "node:child_process";
184105
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, realpathSync, statSync } from "node:fs";
184109
+ import { createHash as createHash2 } from "node:crypto";
184110
+ import {
184111
+ existsSync as existsSync3,
184112
+ mkdirSync as mkdirSync2,
184113
+ mkdtempSync,
184114
+ readdirSync,
184115
+ readFileSync as readFileSync3,
184116
+ realpathSync,
184117
+ rmSync,
184118
+ statSync,
184119
+ writeFileSync as writeFileSync2
184120
+ } from "node:fs";
184121
+ import { mkdtemp } from "node:fs/promises";
184122
+ import { tmpdir } from "node:os";
184106
184123
  import path2 from "node:path";
184107
184124
  var SourceRepositorySchema = exports_external.object({
184108
184125
  gitRepositoryPath: exports_external.string(),
@@ -184122,12 +184139,28 @@ var ReleasesSchema = exports_external.object({
184122
184139
  packagePath: exports_external.string(),
184123
184140
  releases: exports_external.array(ReleaseSchema)
184124
184141
  });
184142
+ var CommitShaSchema = exports_external.string().regex(/^[0-9a-f]{40}$/);
184143
+ var InstallLockPackageSchema = exports_external.lazy(() => exports_external.object({
184144
+ packagePath: SourcePackagePathSchema,
184145
+ requestedRef: SourceVersionRefSchema,
184146
+ resolvedRef: exports_external.string().min(1),
184147
+ resolvedTag: exports_external.string().min(1).optional(),
184148
+ commit: CommitShaSchema,
184149
+ dependencies: exports_external.array(InstallLockPackageSchema)
184150
+ }));
184151
+ var InstallLockfileSchema = exports_external.object({
184152
+ lockfileVersion: exports_external.literal(1),
184153
+ eigenpalVersion: exports_external.string().min(1),
184154
+ inputHash: exports_external.string().min(1),
184155
+ root: InstallLockPackageSchema
184156
+ });
184125
184157
  var AuthCheckSchema = exports_external.object({
184126
184158
  ok: exports_external.literal(true),
184127
184159
  email: exports_external.string().email().nullable().optional(),
184128
184160
  name: exports_external.string().nullable().optional(),
184129
184161
  keyId: exports_external.string()
184130
184162
  });
184163
+ var INSTALL_LOCKFILE_NAME = "eigenpal.lock";
184131
184164
  function runGit(args, opts = {}) {
184132
184165
  const env2 = opts.config ? gitAuthEnv(opts.config, opts.env, opts.gitRemoteUrl) : { ...getProcessEnv(), ...opts.env };
184133
184166
  const result = spawnSync2("git", args, {
@@ -184187,6 +184220,11 @@ function sourcePathFromPackageRoot(gitRoot, packageRoot) {
184187
184220
  function resolveGitRoot(dir) {
184188
184221
  return gitOutput(["rev-parse", "--show-toplevel"], dir);
184189
184222
  }
184223
+ function isOrganizationSourceGitRoot(gitRoot) {
184224
+ if (!gitRoot)
184225
+ return false;
184226
+ return Boolean(gitOutput(["remote", "get-url", "origin"], gitRoot)?.match(/\/orgs\/[^/]+\.git$/));
184227
+ }
184190
184228
  function findNearestPackageRoot(startDir, gitRoot) {
184191
184229
  let current = path2.resolve(startDir);
184192
184230
  while (true) {
@@ -184238,6 +184276,250 @@ function releaseTagExists(gitRoot, packagePath, version2) {
184238
184276
  const tag = formatReleaseTag(pathToDottedPackageName(packagePath), version2);
184239
184277
  return gitOutput(["tag", "--list", tag], gitRoot) === tag;
184240
184278
  }
184279
+ function readPackageManifest(packageRoot) {
184280
+ return SourcePackageManifestSchema.parse(readYamlFile(path2.join(packageRoot, "eigenpal.yaml")));
184281
+ }
184282
+ function parsePackageRef(input) {
184283
+ const [rawPackage, rawRef, extra] = input.split("@");
184284
+ if (!rawPackage || extra !== undefined) {
184285
+ throw new Error("Package ref must be <package>[@latest|main|version|range|commit].");
184286
+ }
184287
+ const packagePath = resolvePackagePath(rawPackage);
184288
+ const ref = SourceVersionRefSchema.parse(rawRef || "latest");
184289
+ return { packagePath, ref };
184290
+ }
184291
+ function versionMatchesRange(version2, range) {
184292
+ const parts = semverParts(version2);
184293
+ if (!parts)
184294
+ return false;
184295
+ const rangeParts = range.replace("*", "x").split(".");
184296
+ if (String(parts[0]) !== rangeParts[0])
184297
+ return false;
184298
+ if (rangeParts.length === 2)
184299
+ return rangeParts[1] === "x";
184300
+ if (rangeParts.length !== 3)
184301
+ return false;
184302
+ if (rangeParts[1] === "x")
184303
+ return true;
184304
+ return String(parts[1]) === rangeParts[1];
184305
+ }
184306
+ function listLocalPackageReleases(gitRoot, packagePath) {
184307
+ const tagPrefix = `${pathToDottedPackageName(packagePath)}@`;
184308
+ const output = gitOutput(["tag", "--list", `${tagPrefix}*`], gitRoot) ?? "";
184309
+ return output.split(`
184310
+ `).map((tag) => tag.trim()).filter(Boolean).map((tag) => {
184311
+ const parsed = parseReleaseTag(tag);
184312
+ const commit = gitOutput(["rev-list", "-n", "1", tag], gitRoot) ?? "";
184313
+ return { tag, version: parsed.version, commit };
184314
+ }).sort((left, right) => compareSemverDesc(left.version, right.version));
184315
+ }
184316
+ async function listPackageReleases(input) {
184317
+ if (input.gitRoot) {
184318
+ const local = listLocalPackageReleases(input.gitRoot, input.packagePath);
184319
+ if (local.length > 0)
184320
+ return local;
184321
+ }
184322
+ const client = new ApiClient(input.config);
184323
+ return ReleasesSchema.parse(await client.get("/api/v1/source/releases", { packagePath: input.packagePath })).releases;
184324
+ }
184325
+ function hostedArchiveRequest(input) {
184326
+ const match = input.repository.remoteUrl.match(/^(.*)\/orgs\/([^/]+)\.git$/);
184327
+ if (!match)
184328
+ return null;
184329
+ const [, baseUrl, gitRepositoryPath] = match;
184330
+ return `${baseUrl}/export/orgs/${encodeURIComponent(gitRepositoryPath)}/${encodeURIComponent(input.ref)}/${input.packagePath}`;
184331
+ }
184332
+ async function resolvePackageRef(input) {
184333
+ if (input.ref === "main" || /^[0-9a-f]{40}$/.test(input.ref)) {
184334
+ if (!input.gitRoot) {
184335
+ throw new Error(`Source ref ${input.ref} requires a cloned organization source repository.`);
184336
+ }
184337
+ const commit = gitOutput(["rev-parse", input.ref], input.gitRoot);
184338
+ if (!commit)
184339
+ throw new Error(`Source ref ${input.ref} does not exist.`);
184340
+ return { requestedRef: input.ref, resolvedRef: input.ref, commit };
184341
+ }
184342
+ const releases = await listPackageReleases({
184343
+ config: input.config,
184344
+ gitRoot: input.gitRoot,
184345
+ packagePath: input.packagePath
184346
+ });
184347
+ const release = input.ref === "latest" ? sortReleasesNewestFirst(releases)[0] : /^\d+\.\d+\.\d+$/.test(input.ref) ? releases.find((candidate) => candidate.version === input.ref) : sortReleasesNewestFirst(releases).find((candidate) => versionMatchesRange(candidate.version, input.ref));
184348
+ if (!release) {
184349
+ throw new Error(`No release found for ${input.packagePath}@${input.ref}.`);
184350
+ }
184351
+ return {
184352
+ requestedRef: input.ref,
184353
+ resolvedRef: release.version,
184354
+ resolvedTag: release.tag,
184355
+ commit: release.commit || (input.gitRoot ? gitOutput(["rev-list", "-n", "1", release.tag], input.gitRoot) ?? "" : "")
184356
+ };
184357
+ }
184358
+ function archivePackage(input) {
184359
+ rmSync(input.outDir, { recursive: true, force: true });
184360
+ mkdirSync2(input.outDir, { recursive: true });
184361
+ const tarPath = path2.join(mkdtempSyncCompat("eigenpal-source-archive-"), "package.tar");
184362
+ try {
184363
+ runGit(["archive", "--format=tar", `--output=${tarPath}`, input.ref, input.packagePath], {
184364
+ cwd: input.gitRoot
184365
+ });
184366
+ const extract2 = spawnSync2("tar", ["-xf", tarPath, "--strip-components", String(input.packagePath.split("/").length)], {
184367
+ cwd: input.outDir,
184368
+ encoding: "utf8"
184369
+ });
184370
+ if (extract2.status !== 0)
184371
+ throw new Error(extract2.stderr.trim() || "tar extraction failed");
184372
+ } finally {
184373
+ rmSync(path2.dirname(tarPath), { recursive: true, force: true });
184374
+ }
184375
+ }
184376
+ async function tryHostedArchive(input) {
184377
+ const repository = input.repository ?? (input.gitRoot ? {
184378
+ gitRepositoryPath: "",
184379
+ remoteUrl: gitOutput(["remote", "get-url", "origin"], input.gitRoot) ?? ""
184380
+ } : null);
184381
+ if (!repository)
184382
+ return false;
184383
+ const url2 = hostedArchiveRequest({
184384
+ repository,
184385
+ ref: input.ref,
184386
+ packagePath: input.packagePath
184387
+ });
184388
+ if (!url2)
184389
+ return false;
184390
+ const response = await fetch(url2, {
184391
+ headers: { authorization: `Bearer ${requireApiKey(input.config)}` }
184392
+ }).catch(() => null);
184393
+ if (!response?.ok)
184394
+ return false;
184395
+ rmSync(input.outDir, { recursive: true, force: true });
184396
+ mkdirSync2(input.outDir, { recursive: true });
184397
+ const tarPath = path2.join(mkdtempSyncCompat("eigenpal-hosted-source-"), "package.tar");
184398
+ try {
184399
+ writeFileSync2(tarPath, Buffer.from(await response.arrayBuffer()));
184400
+ const extract2 = spawnSync2("tar", ["-xf", tarPath, "--strip-components", String(input.packagePath.split("/").length)], {
184401
+ cwd: input.outDir,
184402
+ encoding: "utf8"
184403
+ });
184404
+ if (extract2.status !== 0)
184405
+ throw new Error(extract2.stderr.trim() || "tar extraction failed");
184406
+ return true;
184407
+ } finally {
184408
+ rmSync(path2.dirname(tarPath), { recursive: true, force: true });
184409
+ }
184410
+ }
184411
+ function mkdtempSyncCompat(prefix) {
184412
+ return mkdtempSync(path2.join(tmpdir(), prefix));
184413
+ }
184414
+ function dependencyInstallPath(parentRoot, packagePath) {
184415
+ const modulesRoot = path2.resolve(parentRoot, "eigenpal_modules");
184416
+ const destination = path2.resolve(modulesRoot, packagePath);
184417
+ if (destination !== modulesRoot && !destination.startsWith(`${modulesRoot}${path2.sep}`)) {
184418
+ throw new Error(`Dependency path escapes eigenpal_modules: ${packagePath}`);
184419
+ }
184420
+ return destination;
184421
+ }
184422
+ function lockfileInputHash(input) {
184423
+ return createHash2("sha256").update(JSON.stringify(input)).digest("hex");
184424
+ }
184425
+ async function resolvePackageGraph(input) {
184426
+ const seen = input.seen ?? [];
184427
+ const key = `${input.packagePath}@${input.ref}`;
184428
+ if (seen.includes(key)) {
184429
+ throw new Error(`Dependency cycle detected: ${[...seen, key].join(" -> ")}`);
184430
+ }
184431
+ const resolved = await resolvePackageRef(input);
184432
+ const tempDir = await mkdtemp(path2.join(tmpdir(), "eigenpal-install-resolve-"));
184433
+ try {
184434
+ const packageRoot = path2.join(tempDir, "package");
184435
+ const ref = resolved.resolvedTag ?? resolved.resolvedRef;
184436
+ if (input.gitRoot) {
184437
+ archivePackage({
184438
+ gitRoot: input.gitRoot,
184439
+ ref,
184440
+ packagePath: input.packagePath,
184441
+ outDir: packageRoot
184442
+ });
184443
+ } else if (!await tryHostedArchive({
184444
+ config: input.config,
184445
+ repository: input.repository,
184446
+ ref,
184447
+ packagePath: input.packagePath,
184448
+ outDir: packageRoot
184449
+ })) {
184450
+ throw new Error(`Hosted source export unavailable for ${input.packagePath}@${ref}.`);
184451
+ }
184452
+ const manifest = readPackageManifest(packageRoot);
184453
+ const dependencies = "dependencies" in manifest ? Object.entries(manifest.dependencies ?? {}) : [];
184454
+ return {
184455
+ packagePath: input.packagePath,
184456
+ requestedRef: input.ref,
184457
+ resolvedRef: resolved.resolvedRef,
184458
+ ...resolved.resolvedTag ? { resolvedTag: resolved.resolvedTag } : {},
184459
+ commit: resolved.commit,
184460
+ dependencies: await Promise.all(dependencies.map(([dependencyName, version2]) => resolvePackageGraph({
184461
+ config: input.config,
184462
+ gitRoot: input.gitRoot,
184463
+ repository: input.repository,
184464
+ packagePath: workspaceDependencyNameToPackagePath(dependencyName),
184465
+ ref: SourceVersionRefSchema.parse(version2),
184466
+ seen: [...seen, key]
184467
+ })))
184468
+ };
184469
+ } finally {
184470
+ rmSync(tempDir, { recursive: true, force: true });
184471
+ }
184472
+ }
184473
+ async function materializeLockPackage(input) {
184474
+ const ref = input.lockPackage.resolvedTag ?? input.lockPackage.commit;
184475
+ const usedHostedArchive = await tryHostedArchive({
184476
+ config: input.config,
184477
+ gitRoot: input.gitRoot,
184478
+ repository: input.repository,
184479
+ ref,
184480
+ packagePath: input.lockPackage.packagePath,
184481
+ outDir: input.outDir
184482
+ });
184483
+ if (!usedHostedArchive) {
184484
+ if (!input.gitRoot) {
184485
+ throw new Error(`Hosted source export unavailable for ${input.lockPackage.packagePath}@${ref}.`);
184486
+ }
184487
+ warn(`Hosted source export unavailable for ${input.lockPackage.packagePath}; using local git archive.`);
184488
+ archivePackage({
184489
+ gitRoot: input.gitRoot,
184490
+ ref,
184491
+ packagePath: input.lockPackage.packagePath,
184492
+ outDir: input.outDir
184493
+ });
184494
+ }
184495
+ const occupied = new Set;
184496
+ for (const dependency of input.lockPackage.dependencies) {
184497
+ const dependencyPath = dependencyInstallPath(input.outDir, dependency.packagePath);
184498
+ if (occupied.has(dependencyPath)) {
184499
+ throw new Error(`Dependency conflict at ${dependencyPath}`);
184500
+ }
184501
+ occupied.add(dependencyPath);
184502
+ await materializeLockPackage({
184503
+ config: input.config,
184504
+ gitRoot: input.gitRoot,
184505
+ repository: input.repository,
184506
+ lockPackage: dependency,
184507
+ outDir: dependencyPath
184508
+ });
184509
+ }
184510
+ }
184511
+ function writeLockfile(lockfilePath, lockfile) {
184512
+ mkdirSync2(path2.dirname(lockfilePath), { recursive: true });
184513
+ writeFileSync2(lockfilePath, `${JSON.stringify(lockfile, null, 2)}
184514
+ `);
184515
+ }
184516
+ function readLockfile(lockfilePath) {
184517
+ const parsed = InstallLockfileSchema.safeParse(JSON.parse(readFileSync3(lockfilePath, "utf8")));
184518
+ if (!parsed.success) {
184519
+ throw new Error(`Invalid lockfile ${lockfilePath}: ${parsed.error.issues.map((issue2) => `${issue2.path.join(".")}: ${issue2.message}`).join("; ")}`);
184520
+ }
184521
+ return parsed.data;
184522
+ }
184241
184523
  function validatePackageReferences(input) {
184242
184524
  const errors3 = [];
184243
184525
  const dependencies = "dependencies" in input.manifest ? Object.entries(input.manifest.dependencies ?? {}) : [];
@@ -184338,6 +184620,9 @@ function checkRepoVersion(gitRoot, mutation) {
184338
184620
  function resolvePackagePath(target) {
184339
184621
  return target.includes("/") ? SourcePackagePathSchema.parse(target) : dottedPackageNameToPath(DottedPackageNameSchema.parse(target));
184340
184622
  }
184623
+ function isAutomationPackagePath(packagePath) {
184624
+ return packagePath.startsWith("agents/") || packagePath.startsWith("workflows/");
184625
+ }
184341
184626
  function semverParts(version2) {
184342
184627
  const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version2);
184343
184628
  if (!match)
@@ -184440,7 +184725,12 @@ function gitCommandCreatesObjects(args) {
184440
184725
  "revert",
184441
184726
  "tag"
184442
184727
  ]);
184443
- return args.some((arg) => objectCreatingCommands.has(arg));
184728
+ const command = gitSubcommandFromArgs(args);
184729
+ if (!command)
184730
+ return false;
184731
+ if (command === "tag" && args.some((arg) => arg === "-l" || arg === "--list"))
184732
+ return false;
184733
+ return objectCreatingCommands.has(command);
184444
184734
  }
184445
184735
  function gitCwdFromArgs(args) {
184446
184736
  let cwd = process.cwd();
@@ -184452,6 +184742,25 @@ function gitCwdFromArgs(args) {
184452
184742
  }
184453
184743
  return cwd;
184454
184744
  }
184745
+ function gitSubcommandFromArgs(args) {
184746
+ const optionsWithValue = new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace"]);
184747
+ for (let i = 0;i < args.length; i += 1) {
184748
+ const arg = args[i];
184749
+ if (arg === "--")
184750
+ continue;
184751
+ if (optionsWithValue.has(arg)) {
184752
+ i += 1;
184753
+ continue;
184754
+ }
184755
+ if (arg.startsWith("--git-dir=") || arg.startsWith("--work-tree=") || arg.startsWith("--namespace=")) {
184756
+ continue;
184757
+ }
184758
+ if (arg.startsWith("-"))
184759
+ continue;
184760
+ return arg;
184761
+ }
184762
+ return null;
184763
+ }
184455
184764
  async function runGitPassthroughFromArgv(argv) {
184456
184765
  const gitIndex = argv.indexOf("git");
184457
184766
  const separatorIndex = argv.indexOf("--", gitIndex + 1);
@@ -184534,7 +184843,7 @@ function doctor(opts) {
184534
184843
  });
184535
184844
  }
184536
184845
  }
184537
- if (context.packageRoot) {
184846
+ if (context.packageRoot && context.packageRoot !== context.gitRoot) {
184538
184847
  const result = validatePackage(context.packageRoot);
184539
184848
  checks3.push({
184540
184849
  check: "package structure",
@@ -184574,14 +184883,15 @@ function packageStatus(opts) {
184574
184883
  const context = resolveGitSourceContext(opts);
184575
184884
  if (context.gitRoot)
184576
184885
  checkRepoVersion(context.gitRoot, false);
184577
- const validation = context.packageRoot ? validatePackage(context.packageRoot) : null;
184886
+ const isRepoRootStatus = context.gitRoot && context.packageRoot && context.gitRoot === context.packageRoot;
184887
+ const validation = context.packageRoot && !isRepoRootStatus ? validatePackage(context.packageRoot) : null;
184578
184888
  const gitStatus = context.gitRoot ? gitOutput(["status", "--short"], context.gitRoot) ?? "" : "";
184579
184889
  const payload = {
184580
184890
  gitRoot: context.gitRoot,
184581
184891
  packageRoot: context.packageRoot,
184582
184892
  packagePath: context.packagePath,
184583
184893
  clean: gitStatus.length === 0,
184584
- valid: validation?.valid ?? false,
184894
+ valid: validation?.valid ?? null,
184585
184895
  errors: validation?.errors ?? []
184586
184896
  };
184587
184897
  if (opts.json)
@@ -184759,19 +185069,321 @@ async function release(versionOrBump, dir, opts) {
184759
185069
  throw err;
184760
185070
  }
184761
185071
  success2(`Released ${tag}.`);
184762
- await syncLatestAutomation(client, context.packagePath);
185072
+ if (isAutomationPackagePath(context.packagePath)) {
185073
+ await syncLatestAutomation(client, context.packagePath);
185074
+ }
184763
185075
  }
184764
185076
  async function sync(target, opts) {
184765
185077
  const context = resolveGitSourceContext({ dir: opts.dir });
185078
+ if (target?.includes("@")) {
185079
+ throw new Error("Sync always uses latest; do not pass a versioned target.");
185080
+ }
184766
185081
  const packagePath = target ? resolvePackagePath(target) : context.packagePath;
184767
185082
  if (!packagePath) {
184768
185083
  throw new Error("Pass an automation target or run sync inside a source package.");
184769
185084
  }
184770
- if (target?.includes("@")) {
184771
- throw new Error("Sync always uses latest; do not pass a versioned target.");
185085
+ if (!isAutomationPackagePath(packagePath)) {
185086
+ throw new Error("Sync only supports agent and workflow packages.");
184772
185087
  }
184773
185088
  await syncLatestAutomation(new ApiClient(resolveConfig(opts)), packagePath);
184774
185089
  }
185090
+ async function install(packageRef, opts) {
185091
+ const config2 = resolveConfig(opts);
185092
+ const context = resolveGitSourceContext();
185093
+ const sourceGitRoot = isOrganizationSourceGitRoot(context.gitRoot) ? context.gitRoot : null;
185094
+ if (sourceGitRoot)
185095
+ checkRepoVersion(sourceGitRoot, false);
185096
+ const installFromLock = async (lockfilePath, packageDestination, explicitRef, repository, expectedPackagePath, explicitGitRoot) => {
185097
+ const lockfile2 = readLockfile(lockfilePath);
185098
+ if (expectedPackagePath && lockfile2.root.packagePath !== expectedPackagePath) {
185099
+ throw new Error(`Lockfile root package ${lockfile2.root.packagePath} does not match requested package ${expectedPackagePath}.`);
185100
+ }
185101
+ const destination = explicitRef ? path2.resolve(opts.out ?? path2.basename(lockfile2.root.packagePath)) : packageDestination;
185102
+ if (!destination)
185103
+ throw new Error("No package context found for lockfile install.");
185104
+ const lockInstallGitRoot = explicitRef ? explicitGitRoot ?? sourceGitRoot : context.gitRoot;
185105
+ if (explicitRef) {
185106
+ await materializeLockPackage({
185107
+ config: config2,
185108
+ gitRoot: lockInstallGitRoot,
185109
+ repository,
185110
+ lockPackage: lockfile2.root,
185111
+ outDir: destination
185112
+ });
185113
+ writeLockfile(path2.join(destination, ".eigenpal", INSTALL_LOCKFILE_NAME), lockfile2);
185114
+ } else {
185115
+ rmSync(path2.join(destination, "eigenpal_modules"), { recursive: true, force: true });
185116
+ for (const dependency of lockfile2.root.dependencies) {
185117
+ await materializeLockPackage({
185118
+ config: config2,
185119
+ gitRoot: lockInstallGitRoot,
185120
+ repository,
185121
+ lockPackage: dependency,
185122
+ outDir: dependencyInstallPath(destination, dependency.packagePath)
185123
+ });
185124
+ }
185125
+ }
185126
+ success2(`Installed from lockfile ${lockfilePath}.`);
185127
+ };
185128
+ if (opts.frozenLockfile) {
185129
+ const explicitRef = Boolean(packageRef);
185130
+ const expectedPackagePath = packageRef ? parsePackageRef(packageRef).packagePath : null;
185131
+ const explicitGitRoot = explicitRef && expectedPackagePath && context.gitRoot ? packageManifestExists(context.gitRoot, expectedPackagePath) ? context.gitRoot : sourceGitRoot : sourceGitRoot;
185132
+ const repository = explicitRef && !explicitGitRoot ? await getSourceRepository(config2) : null;
185133
+ const lockfilePath = opts.lockfile ?? path2.join(packageRef && opts.out ? path2.resolve(opts.out) : context.packageRoot ?? process.cwd(), ".eigenpal", INSTALL_LOCKFILE_NAME);
185134
+ await installFromLock(lockfilePath, context.packageRoot, explicitRef, repository, expectedPackagePath, explicitGitRoot);
185135
+ return;
185136
+ }
185137
+ if (packageRef) {
185138
+ const parsed = parsePackageRef(packageRef);
185139
+ const explicitGitRoot = context.gitRoot && packageManifestExists(context.gitRoot, parsed.packagePath) ? context.gitRoot : sourceGitRoot;
185140
+ const repository = explicitGitRoot ? null : await getSourceRepository(config2);
185141
+ if (parsed.ref === "main")
185142
+ warn("Installing @main uses draft source and is not reproducible.");
185143
+ const intendedLockfile2 = opts.lockfile ?? path2.join(path2.resolve(opts.out ?? path2.basename(parsed.packagePath)), ".eigenpal", INSTALL_LOCKFILE_NAME);
185144
+ const inputHash2 = lockfileInputHash({ packageRef });
185145
+ if (existsSync3(intendedLockfile2)) {
185146
+ const existing = readLockfile(intendedLockfile2);
185147
+ if (existing.inputHash !== inputHash2) {
185148
+ throw new Error(`Existing lockfile ${intendedLockfile2} does not match requested package ref.`);
185149
+ }
185150
+ await installFromLock(intendedLockfile2, null, true, repository, parsed.packagePath);
185151
+ return;
185152
+ }
185153
+ const lockRoot = await resolvePackageGraph({
185154
+ config: config2,
185155
+ gitRoot: explicitGitRoot,
185156
+ repository,
185157
+ packagePath: parsed.packagePath,
185158
+ ref: parsed.ref
185159
+ });
185160
+ const outDir = path2.resolve(opts.out ?? path2.basename(parsed.packagePath));
185161
+ await materializeLockPackage({
185162
+ config: config2,
185163
+ gitRoot: explicitGitRoot,
185164
+ repository,
185165
+ lockPackage: lockRoot,
185166
+ outDir
185167
+ });
185168
+ const lockfile2 = {
185169
+ lockfileVersion: 1,
185170
+ eigenpalVersion: "1.0.0",
185171
+ inputHash: inputHash2,
185172
+ root: lockRoot
185173
+ };
185174
+ writeLockfile(intendedLockfile2, lockfile2);
185175
+ success2(`Installed ${parsed.packagePath}@${lockRoot.resolvedRef} into ${outDir}.`);
185176
+ return;
185177
+ }
185178
+ if (!context.packageRoot || !context.packagePath) {
185179
+ throw new Error("Run git install inside a source package or pass a package ref.");
185180
+ }
185181
+ if (!context.gitRoot) {
185182
+ throw new Error("Run git install inside an organization source repository.");
185183
+ }
185184
+ const manifest = readPackageManifest(context.packageRoot);
185185
+ const dependencies = "dependencies" in manifest ? Object.entries(manifest.dependencies ?? {}) : [];
185186
+ const inputHash = lockfileInputHash({ packagePath: context.packagePath, dependencies });
185187
+ const intendedLockfile = opts.lockfile ?? path2.join(context.packageRoot, ".eigenpal", INSTALL_LOCKFILE_NAME);
185188
+ if (existsSync3(intendedLockfile)) {
185189
+ const existing = readLockfile(intendedLockfile);
185190
+ if (existing.inputHash !== inputHash) {
185191
+ throw new Error(`Existing lockfile ${intendedLockfile} does not match current package inputs.`);
185192
+ }
185193
+ await installFromLock(intendedLockfile, context.packageRoot, false);
185194
+ return;
185195
+ }
185196
+ const root = {
185197
+ packagePath: context.packagePath,
185198
+ requestedRef: "main",
185199
+ resolvedRef: "main",
185200
+ commit: gitOutput(["rev-parse", "HEAD"], context.gitRoot) ?? "",
185201
+ dependencies: await Promise.all(dependencies.map(([dependencyName, version2]) => resolvePackageGraph({
185202
+ config: config2,
185203
+ gitRoot: context.gitRoot,
185204
+ packagePath: workspaceDependencyNameToPackagePath(dependencyName),
185205
+ ref: SourceVersionRefSchema.parse(version2)
185206
+ })))
185207
+ };
185208
+ rmSync(path2.join(context.packageRoot, "eigenpal_modules"), { recursive: true, force: true });
185209
+ for (const dependency of root.dependencies) {
185210
+ await materializeLockPackage({
185211
+ config: config2,
185212
+ gitRoot: context.gitRoot,
185213
+ lockPackage: dependency,
185214
+ outDir: dependencyInstallPath(context.packageRoot, dependency.packagePath)
185215
+ });
185216
+ }
185217
+ const lockfile = {
185218
+ lockfileVersion: 1,
185219
+ eigenpalVersion: "1.0.0",
185220
+ inputHash,
185221
+ root
185222
+ };
185223
+ writeLockfile(intendedLockfile, lockfile);
185224
+ success2(`Installed ${root.dependencies.length} dependencies for ${context.packagePath}.`);
185225
+ }
185226
+ function slugifyPackageSegment(value) {
185227
+ return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
185228
+ }
185229
+ function packagePathForTemplate(template2, name) {
185230
+ const slug = slugifyPackageSegment(name);
185231
+ if (!slug)
185232
+ throw new Error("Package name must include at least one letter or number.");
185233
+ const rootByTemplate = {
185234
+ agent: "agents",
185235
+ workflow: "workflows",
185236
+ skill: "resources/skills",
185237
+ rule: "resources/rules",
185238
+ knowledge: "resources/knowledge",
185239
+ evaluator: "evaluators"
185240
+ };
185241
+ const root = rootByTemplate[template2];
185242
+ if (!root)
185243
+ throw new Error("Template must be agent, workflow, skill, rule, knowledge, or evaluator.");
185244
+ return SourcePackagePathSchema.parse(`${root}/${slug}`);
185245
+ }
185246
+ function writePackageScaffold(packageRoot, packagePath, name) {
185247
+ const [root, resourceKind] = packagePath.split("/");
185248
+ mkdirSync2(packageRoot, { recursive: true });
185249
+ const title = name.trim();
185250
+ writeFileSync2(path2.join(packageRoot, "eigenpal.yaml"), import_yaml2.default.stringify({ schemaVersion: 1, name: title || path2.basename(packagePath) }));
185251
+ if (root === "agents")
185252
+ writeFileSync2(path2.join(packageRoot, "AGENT.md"), `# ${title}
185253
+
185254
+ `);
185255
+ if (root === "evaluators") {
185256
+ writeFileSync2(path2.join(packageRoot, "evaluator.yaml"), import_yaml2.default.stringify({ schemaVersion: 1, type: "exact-diff", config: {} }));
185257
+ }
185258
+ if (root === "resources" && resourceKind === "skills") {
185259
+ writeFileSync2(path2.join(packageRoot, "SKILL.md"), `# ${title}
185260
+
185261
+ `);
185262
+ }
185263
+ if (root === "resources" && (resourceKind === "rules" || resourceKind === "knowledge")) {
185264
+ writeFileSync2(path2.join(packageRoot, "README.md"), `# ${title}
185265
+
185266
+ `);
185267
+ }
185268
+ }
185269
+ function initPackage(name, opts) {
185270
+ const startDir = path2.resolve(opts.dir ?? process.cwd());
185271
+ const gitRoot = resolveGitRoot(startDir) ?? startDir;
185272
+ mkdirSync2(gitRoot, { recursive: true });
185273
+ if (!existsSync3(path2.join(gitRoot, ".git")))
185274
+ runGit(["init", "-b", "main", gitRoot]);
185275
+ if (!existsSync3(path2.join(gitRoot, "eigenpal.yaml"))) {
185276
+ writeFileSync2(path2.join(gitRoot, "eigenpal.yaml"), `schemaVersion: 1
185277
+ eigenpalVersion: 1.0.0
185278
+ `);
185279
+ }
185280
+ const gitignorePath = path2.join(gitRoot, ".gitignore");
185281
+ const gitignore = existsSync3(gitignorePath) ? readFileSync3(gitignorePath, "utf8") : "";
185282
+ const additions = [".eigenpal/", "eigenpal_modules/"].filter((entry) => !gitignore.includes(entry));
185283
+ if (additions.length > 0)
185284
+ writeFileSync2(gitignorePath, `${gitignore}${gitignore.endsWith(`
185285
+ `) || !gitignore ? "" : `
185286
+ `}${additions.join(`
185287
+ `)}
185288
+ `);
185289
+ const packagePath = packagePathForTemplate(opts.template, name);
185290
+ const packageRoot = path2.join(gitRoot, packagePath);
185291
+ if (existsSync3(packageRoot))
185292
+ throw new Error(`Package already exists: ${packagePath}`);
185293
+ writePackageScaffold(packageRoot, packagePath, name);
185294
+ success2(`Created ${packagePath}.`);
185295
+ }
185296
+ async function pullSource(opts) {
185297
+ const config2 = resolveConfig(opts);
185298
+ const context = resolveGitSourceContext({ dir: opts.dir });
185299
+ if (!context.gitRoot)
185300
+ throw new Error("Not inside a Git repository.");
185301
+ const remoteUrl = gitOutput(["remote", "get-url", "origin"], context.gitRoot);
185302
+ runGit(["pull", "--ff-only", "origin", "main"], {
185303
+ cwd: context.gitRoot,
185304
+ config: config2,
185305
+ gitRemoteUrl: remoteUrl ?? undefined
185306
+ });
185307
+ }
185308
+ function dirtyPackagePaths(gitRoot) {
185309
+ const status = gitOutput(["status", "--porcelain", "--untracked-files=all"], gitRoot) ?? "";
185310
+ const packagePaths = new Set;
185311
+ for (const line of status.split(`
185312
+ `)) {
185313
+ const file2 = line.slice(2).trim().split(" -> ").pop().replace(/\\/g, "/");
185314
+ const parts = file2.split("/");
185315
+ for (let index = parts.length;index >= 2; index -= 1) {
185316
+ const candidate = parts.slice(0, index).join("/");
185317
+ if (SourcePackagePathSchema.safeParse(candidate).success && existsSync3(path2.join(gitRoot, candidate, "eigenpal.yaml"))) {
185318
+ packagePaths.add(candidate);
185319
+ break;
185320
+ }
185321
+ }
185322
+ }
185323
+ return [...packagePaths].sort();
185324
+ }
185325
+ async function commitSource(opts) {
185326
+ if (!opts.message)
185327
+ throw new Error("Commit requires -m <message>.");
185328
+ const config2 = resolveConfig(opts);
185329
+ const context = resolveGitSourceContext({ dir: opts.dir });
185330
+ if (!context.gitRoot)
185331
+ throw new Error("Not inside a Git repository.");
185332
+ checkRepoVersion(context.gitRoot, true);
185333
+ const packagePaths = dirtyPackagePaths(context.gitRoot);
185334
+ if (packagePaths.length === 0) {
185335
+ warn("No source package changes to commit.");
185336
+ return;
185337
+ }
185338
+ for (const packagePath of packagePaths) {
185339
+ const validation = validatePackage(path2.join(context.gitRoot, packagePath));
185340
+ if (!validation.valid) {
185341
+ throw new Error(`Package validation failed for ${packagePath}: ${validation.errors.join("; ")}`);
185342
+ }
185343
+ }
185344
+ const rootFiles = ["eigenpal.yaml", ".gitignore"].filter((file2) => existsSync3(path2.join(context.gitRoot, file2)));
185345
+ runGit(["add", ...rootFiles, ...packagePaths], { cwd: context.gitRoot });
185346
+ const authorEnv = await resolveGitAuthorEnv(config2);
185347
+ runGit(["commit", "-m", opts.message], { cwd: context.gitRoot, env: authorEnv });
185348
+ }
185349
+ async function pushSource(opts) {
185350
+ const config2 = resolveConfig(opts);
185351
+ const context = resolveGitSourceContext({ dir: opts.dir });
185352
+ if (!context.gitRoot)
185353
+ throw new Error("Not inside a Git repository.");
185354
+ const remoteUrl = gitOutput(["remote", "get-url", "origin"], context.gitRoot);
185355
+ runGit(["push", "origin", "main", "--follow-tags"], {
185356
+ cwd: context.gitRoot,
185357
+ config: config2,
185358
+ gitRemoteUrl: remoteUrl ?? undefined
185359
+ });
185360
+ }
185361
+ function upgradeSource(opts) {
185362
+ const context = resolveGitSourceContext({ dir: opts.dir });
185363
+ if (!context.gitRoot)
185364
+ throw new Error("Not inside a Git repository.");
185365
+ const manifestPath = path2.join(context.gitRoot, "eigenpal.yaml");
185366
+ const manifest = readRootManifest(context.gitRoot);
185367
+ if (!manifest.ok)
185368
+ throw new Error(manifest.error);
185369
+ if (manifest.version === "1.0.0") {
185370
+ success2("Repository source schema is already 1.0.0.");
185371
+ return;
185372
+ }
185373
+ if (opts.dryRun) {
185374
+ console.log(`Would upgrade repository source schema from ${manifest.version} to 1.0.0.`);
185375
+ return;
185376
+ }
185377
+ console.log("Source repository changelog:");
185378
+ console.log(`- ${manifest.version} -> 1.0.0: normalize root eigenpal.yaml schema version.`);
185379
+ writeFileSync2(manifestPath, `schemaVersion: 1
185380
+ eigenpalVersion: 1.0.0
185381
+ `);
185382
+ doctor({
185383
+ dir: context.packagePath && context.packageRoot ? context.packageRoot : context.gitRoot
185384
+ });
185385
+ success2(`Upgraded repository source schema from ${manifest.version} to 1.0.0.`);
185386
+ }
184775
185387
  function parseReleaseVersion(value) {
184776
185388
  if (!/^\d+\.\d+\.\d+$/.test(value) && !["patch", "minor", "major"].includes(value)) {
184777
185389
  throw new InvalidArgumentError("version must be X.Y.Z, patch, minor, or major");
@@ -184783,9 +185395,21 @@ function parseType(value) {
184783
185395
  throw new InvalidArgumentError("type must be agent or workflow");
184784
185396
  return value;
184785
185397
  }
185398
+ function parseTemplate(value) {
185399
+ if (!["agent", "workflow", "skill", "rule", "knowledge", "evaluator"].includes(value)) {
185400
+ throw new InvalidArgumentError("template must be agent, workflow, skill, rule, knowledge, or evaluator");
185401
+ }
185402
+ return value;
185403
+ }
184786
185404
  function registerGitCommands(program2) {
184787
185405
  const git = program2.command("git", { hidden: true }).description("Experimental Git-backed source commands.").allowUnknownOption(true).allowExcessArguments(true).argument("[gitArgs...]", "Git arguments after --").action(action(async (gitArgs, opts) => gitPassthrough(gitArgs ?? [], opts)));
184788
185406
  withBaseUrl(git.command("clone")).description("Clone the organization source repository.").option("--out <dir>", "Output directory").action(action(cloneSource));
185407
+ withBaseUrl(git.command("install [packageRef]")).description("Materialize a source package and its workspace dependencies.").option("--out <dir>", "Output directory for an explicit package ref").option("--lockfile <path>", "Lockfile path").option("--frozen-lockfile", "Install exactly from the existing lockfile").action(action(install));
185408
+ git.command("init <name>").description("Create a new source package scaffold.").addOption(new Option("--template <template>", "Package template").argParser(parseTemplate).makeOptionMandatory()).option("--dir <dir>", "Repository directory").action(action(async (name, opts) => initPackage(name, opts)));
185409
+ withBaseUrl(git.command("pull")).description("Pull organization source from origin/main with --ff-only.").option("--dir <dir>", "Repository directory").action(action(pullSource));
185410
+ withBaseUrl(git.command("commit")).description("Validate changed source packages and commit them.").addOption(new Option("-m, --message <message>", "Commit message").makeOptionMandatory()).option("--dir <dir>", "Repository directory").action(action(commitSource));
185411
+ withBaseUrl(git.command("push")).description("Push organization source main and tags.").option("--dir <dir>", "Repository directory").action(action(pushSource));
185412
+ git.command("upgrade").description("Upgrade the source repository schema in place.").option("--dir <dir>", "Repository directory").option("--dry-run", "Print upgrade actions without changing files").action(action(async (opts) => upgradeSource(opts)));
184789
185413
  addJsonFlag(git.command("doctor")).description("Check organization source repository health.").option("--dir <dir>", "Directory to inspect").action(action(async (opts) => doctor(opts)));
184790
185414
  addJsonFlag(git.command("validate [dir]")).description("Validate the nearest source package.").action(action(async (dir, opts) => validate({ ...opts, dir })));
184791
185415
  addJsonFlag(git.command("status")).description("Show source repo and package status.").option("--dir <dir>", "Directory to inspect").action(action(async (opts) => packageStatus(opts)));
@@ -184803,11 +185427,11 @@ init_dist4();
184803
185427
  import {
184804
185428
  copyFileSync,
184805
185429
  existsSync as existsSync4,
184806
- mkdirSync as mkdirSync2,
185430
+ mkdirSync as mkdirSync3,
184807
185431
  readdirSync as readdirSync2,
184808
185432
  readFileSync as readFileSync4,
184809
185433
  statSync as statSync2,
184810
- writeFileSync as writeFileSync2
185434
+ writeFileSync as writeFileSync3
184811
185435
  } from "node:fs";
184812
185436
  import { dirname as dirname2, join as join2, relative, resolve } from "node:path";
184813
185437
  import { fileURLToPath } from "node:url";
@@ -184901,10 +185525,10 @@ function copyTemplate(src, dst, projectName) {
184901
185525
  stack.push(sourcePath);
184902
185526
  continue;
184903
185527
  }
184904
- mkdirSync2(dirname2(targetPath), { recursive: true });
185528
+ mkdirSync3(dirname2(targetPath), { recursive: true });
184905
185529
  if (isTextFile(sourcePath)) {
184906
185530
  const text = readFileSync4(sourcePath, "utf-8").replaceAll(PLACEHOLDER, projectName);
184907
- writeFileSync2(targetPath, text);
185531
+ writeFileSync3(targetPath, text);
184908
185532
  } else {
184909
185533
  copyFileSync(sourcePath, targetPath);
184910
185534
  }
@@ -184935,17 +185559,17 @@ function isTextFile(path3) {
184935
185559
 
184936
185560
  // src/commands/skill.ts
184937
185561
  init_dist4();
184938
- import { createHash as createHash2 } from "node:crypto";
185562
+ import { createHash as createHash3 } from "node:crypto";
184939
185563
  import {
184940
185564
  existsSync as existsSync5,
184941
185565
  lstatSync,
184942
- mkdirSync as mkdirSync3,
185566
+ mkdirSync as mkdirSync4,
184943
185567
  readFileSync as readFileSync5,
184944
185568
  readdirSync as readdirSync3,
184945
- rmSync,
185569
+ rmSync as rmSync2,
184946
185570
  rmdirSync,
184947
185571
  unlinkSync as unlinkSync2,
184948
- writeFileSync as writeFileSync3
185572
+ writeFileSync as writeFileSync4
184949
185573
  } from "node:fs";
184950
185574
  import { sep as PATH_SEP, dirname as dirname3, join as join3, relative as relative2, resolve as resolve2 } from "node:path";
184951
185575
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -185034,7 +185658,7 @@ function resolveSkillTarget(opts) {
185034
185658
  return opts.target ?? defaultClaudeTarget();
185035
185659
  }
185036
185660
  function sha256(buffer) {
185037
- return createHash2("sha256").update(buffer).digest("hex");
185661
+ return createHash3("sha256").update(buffer).digest("hex");
185038
185662
  }
185039
185663
  var CLI_VERSION_PLACEHOLDER = "__CLI_VERSION__";
185040
185664
  function templateSourceFile(relativePath, bytes, cliVersion) {
@@ -185061,8 +185685,8 @@ async function installSkill(opts) {
185061
185685
  const sourceBytes = templateSourceFile(relativePath, readFileSync5(sourcePath), cliVersion);
185062
185686
  const sourceHash = sha256(sourceBytes);
185063
185687
  if (!existsSync5(targetPath)) {
185064
- mkdirSync3(dirname3(targetPath), { recursive: true });
185065
- writeFileSync3(targetPath, sourceBytes);
185688
+ mkdirSync4(dirname3(targetPath), { recursive: true });
185689
+ writeFileSync4(targetPath, sourceBytes);
185066
185690
  written += 1;
185067
185691
  continue;
185068
185692
  }
@@ -185075,7 +185699,7 @@ async function installSkill(opts) {
185075
185699
  const previousEntry = existingManifest?.files.find((f) => f.path === relativePath);
185076
185700
  const userEdited = previousEntry ? previousEntry.sha256 !== targetHash : true;
185077
185701
  if (!userEdited || opts.force) {
185078
- writeFileSync3(targetPath, sourceBytes);
185702
+ writeFileSync4(targetPath, sourceBytes);
185079
185703
  written += 1;
185080
185704
  continue;
185081
185705
  }
@@ -185086,7 +185710,7 @@ async function installSkill(opts) {
185086
185710
  prompted += 1;
185087
185711
  const choice = await promptThreeWay(targetPath, sourceBytes, targetBytes);
185088
185712
  if (choice === "overwrite") {
185089
- writeFileSync3(targetPath, sourceBytes);
185713
+ writeFileSync4(targetPath, sourceBytes);
185090
185714
  written += 1;
185091
185715
  } else {
185092
185716
  skipped += 1;
@@ -185104,7 +185728,7 @@ async function installSkill(opts) {
185104
185728
  installedAt: new Date().toISOString(),
185105
185729
  files: manifestEntries
185106
185730
  };
185107
- writeFileSync3(join3(target, MANIFEST_NAME), `${JSON.stringify(manifest, null, 2)}
185731
+ writeFileSync4(join3(target, MANIFEST_NAME), `${JSON.stringify(manifest, null, 2)}
185108
185732
  `);
185109
185733
  const displayTarget = relative2(process.cwd(), target) || target;
185110
185734
  success2(`Installed skill at ${ui.bold(displayTarget)} — ${written} written, ${skipped} unchanged${prompted > 0 ? `, ${prompted} prompted` : ""}.`);
@@ -185146,7 +185770,7 @@ async function uninstallSkill(opts) {
185146
185770
  unlinkSync2(path3);
185147
185771
  removed += 1;
185148
185772
  }
185149
- rmSync(join3(target, MANIFEST_NAME), { force: true });
185773
+ rmSync2(join3(target, MANIFEST_NAME), { force: true });
185150
185774
  pruneEmptyDirs(target);
185151
185775
  const displayTarget = relative2(process.cwd(), target) || target;
185152
185776
  success2(`Uninstalled skill from ${ui.bold(displayTarget)} — ${removed} removed${kept > 0 ? `, ${kept} user-edited kept` : ""}.`);
@@ -186303,7 +186927,7 @@ async function resolveWorkflowId(client, idOrSlug) {
186303
186927
  }
186304
186928
 
186305
186929
  // src/commands/clear.ts
186306
- import { existsSync as existsSync8, readdirSync as readdirSync5, rmSync as rmSync2, statSync as statSync4 } from "fs";
186930
+ import { existsSync as existsSync8, readdirSync as readdirSync5, rmSync as rmSync3, statSync as statSync4 } from "fs";
186307
186931
  import { basename, join as join7 } from "path";
186308
186932
 
186309
186933
  // src/lib/payload.ts
@@ -186420,7 +187044,7 @@ function removeDirEntriesWithRetention(path3, removeAll) {
186420
187044
  for (const entry of entries) {
186421
187045
  if (keepSet.has(entry))
186422
187046
  continue;
186423
- rmSync2(join7(path3, entry), { recursive: true, force: true });
187047
+ rmSync3(join7(path3, entry), { recursive: true, force: true });
186424
187048
  removed++;
186425
187049
  }
186426
187050
  return { removed, kept: keepSet.size, touched: entries.length };
@@ -186447,7 +187071,7 @@ function removeJudgeSummaryFilesWithRetention(exampleDir, removeAll) {
186447
187071
  kept++;
186448
187072
  continue;
186449
187073
  }
186450
- rmSync2(join7(exampleDir, fileName), { force: true });
187074
+ rmSync3(join7(exampleDir, fileName), { force: true });
186451
187075
  removed++;
186452
187076
  }
186453
187077
  return { removed, kept, touched: stampByFile.size };
@@ -186643,11 +187267,11 @@ async function watchExecution(opts) {
186643
187267
  import { join as join11 } from "path";
186644
187268
 
186645
187269
  // src/lib/execution-artifacts.ts
186646
- import { existsSync as existsSync9, mkdirSync as mkdirSync4, readdirSync as readdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
187270
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readdirSync as readdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
186647
187271
  import { join as join10 } from "path";
186648
187272
 
186649
187273
  // src/lib/format.ts
186650
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
187274
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
186651
187275
  import { extname as extname3, resolve as resolve5 } from "path";
186652
187276
  var PRETTIER_EXTENSIONS = new Set([".json", ".yaml", ".yml"]);
186653
187277
  async function formatFileIfAvailable(filepath) {
@@ -186660,7 +187284,7 @@ async function formatFileIfAvailable(filepath) {
186660
187284
  filepath: resolve5(filepath)
186661
187285
  });
186662
187286
  if (formatted !== content) {
186663
- writeFileSync4(filepath, formatted, "utf-8");
187287
+ writeFileSync5(filepath, formatted, "utf-8");
186664
187288
  }
186665
187289
  } catch (err2) {
186666
187290
  if (env.DEBUG?.includes("prettier")) {
@@ -186694,7 +187318,7 @@ async function writeExecutionArtifacts(client, exampleDir, payload) {
186694
187318
  const folderName = timestampFolderName(payload);
186695
187319
  const executionsDir = join10(exampleDir, "executions", folderName);
186696
187320
  const filesDir = join10(executionsDir, "files");
186697
- mkdirSync4(filesDir, { recursive: true });
187321
+ mkdirSync5(filesDir, { recursive: true });
186698
187322
  const generatedFiles = [];
186699
187323
  const result = payload.result;
186700
187324
  if (isWorkflowResult2(result) && result.files.length > 0) {
@@ -186711,7 +187335,7 @@ async function writeExecutionArtifacts(client, exampleDir, payload) {
186711
187335
  const safe = safeFilename(filename, `file-${i5}${filename.includes(".") ? "" : ".bin"}`);
186712
187336
  const destPath = join10(filesDir, safe);
186713
187337
  const buf = Buffer.from(await res.arrayBuffer());
186714
- writeFileSync5(destPath, buf);
187338
+ writeFileSync6(destPath, buf);
186715
187339
  generatedFiles.push({ fileId, stepName, filename: safe });
186716
187340
  } catch (err2) {
186717
187341
  console.warn(` Warning: could not download file ${fileId}:`, err2);
@@ -186723,7 +187347,7 @@ async function writeExecutionArtifacts(client, exampleDir, payload) {
186723
187347
  generatedFiles: generatedFiles.length > 0 ? generatedFiles : undefined
186724
187348
  };
186725
187349
  const outputPath = join10(executionsDir, "output.json");
186726
- writeFileSync5(outputPath, JSON.stringify(output, null, 2) + `
187350
+ writeFileSync6(outputPath, JSON.stringify(output, null, 2) + `
186727
187351
  `, "utf-8");
186728
187352
  await formatFileIfAvailable(outputPath);
186729
187353
  return executionsDir;
@@ -2,212 +2,6 @@
2
2
 
3
3
  Experimental Git-backed source commands.
4
4
 
5
- ## Contents
5
+ Experimental.
6
6
 
7
- - [Surface](#surface)
8
- - [Commands](#commands)
9
- - [Core](#core)
10
- - [Details](#details)
11
- - [`eigenpal git clone [options]`](#eigenpal-git-clone-options)
12
- - [`eigenpal git doctor [options]`](#eigenpal-git-doctor-options)
13
- - [`eigenpal git validate [options] [dir]`](#eigenpal-git-validate-options-dir)
14
- - [`eigenpal git status [options]`](#eigenpal-git-status-options)
15
- - [`eigenpal git deps [options]`](#eigenpal-git-deps-options)
16
- - [`eigenpal git clean [options]`](#eigenpal-git-clean-options)
17
- - [`eigenpal git list|ls [options]`](#eigenpal-git-listls-options)
18
- - [`eigenpal git show [options] <automation>`](#eigenpal-git-show-options-automation)
19
- - [`eigenpal git versions [options] <package>`](#eigenpal-git-versions-options-package)
20
- - [`eigenpal git release [options] <version> [dir]`](#eigenpal-git-release-options-version-dir)
21
- - [`eigenpal git sync [options] [automation]`](#eigenpal-git-sync-options-automation)
22
-
23
- ## Surface
24
-
25
- ```
26
- git
27
- ├── clone
28
- ├── doctor
29
- ├── validate [dir]
30
- ├── status
31
- ├── deps
32
- ├── clean
33
- ├── list|ls
34
- ├── show <automation>
35
- ├── versions <package>
36
- ├── release <version> [dir]
37
- └── sync [automation]
38
- ```
39
-
40
- ## Commands
41
-
42
- ### Core
43
-
44
- | Command | Description |
45
- | ------------------------------------------------ | ------------------------------------------------------ | ---------------------------- |
46
- | `eigenpal git clone [options]` | Clone the organization source repository. |
47
- | `eigenpal git doctor [options]` | Check organization source repository health. |
48
- | `eigenpal git validate [options] [dir]` | Validate the nearest source package. |
49
- | `eigenpal git status [options]` | Show source repo and package status. |
50
- | `eigenpal git deps [options]` | List package workspace dependencies. |
51
- | `eigenpal git clean [options]` | Require a clean source working tree. |
52
- | `eigenpal git list | ls [options]` | List Git-backed automations. |
53
- | `eigenpal git show [options] <automation>` | Show Git-backed automation details. |
54
- | `eigenpal git versions [options] <package>` | List package release versions. |
55
- | `eigenpal git release [options] <version> [dir]` | Create and push a package release tag. |
56
- | `eigenpal git sync [options] [automation]` | Sync an automation from the latest Git source release. |
57
-
58
- ## Details
59
-
60
- ### `eigenpal git clone [options]`
61
-
62
- Clone the organization source repository.
63
-
64
- ### Options
65
-
66
- | Flag | Required | Default | Description |
67
- | ------------------ | -------- | ------- | ---------------- |
68
- | `--base-url <url>` | no | | Server base URL |
69
- | `--out <dir>` | no | | Output directory |
70
-
71
- ### `eigenpal git doctor [options]`
72
-
73
- Check organization source repository health.
74
-
75
- ### Options
76
-
77
- | Flag | Required | Default | Description |
78
- | ------------- | -------- | ------- | -------------------------------------- |
79
- | `--json` | no | | Output the raw server response as JSON |
80
- | `--dir <dir>` | no | | Directory to inspect |
81
-
82
- ### `eigenpal git validate [options] [dir]`
83
-
84
- Validate the nearest source package.
85
-
86
- ### Arguments
87
-
88
- | Name | Required | Variadic | Description |
89
- | ----- | -------- | -------- | ----------- |
90
- | `dir` | no | no | |
91
-
92
- ### Options
93
-
94
- | Flag | Required | Default | Description |
95
- | -------- | -------- | ------- | -------------------------------------- |
96
- | `--json` | no | | Output the raw server response as JSON |
97
-
98
- ### `eigenpal git status [options]`
99
-
100
- Show source repo and package status.
101
-
102
- ### Options
103
-
104
- | Flag | Required | Default | Description |
105
- | ------------- | -------- | ------- | -------------------------------------- |
106
- | `--json` | no | | Output the raw server response as JSON |
107
- | `--dir <dir>` | no | | Directory to inspect |
108
-
109
- ### `eigenpal git deps [options]`
110
-
111
- List package workspace dependencies.
112
-
113
- ### Options
114
-
115
- | Flag | Required | Default | Description |
116
- | ------------- | -------- | ------- | -------------------------------------- |
117
- | `--json` | no | | Output the raw server response as JSON |
118
- | `--dir <dir>` | no | | Directory to inspect |
119
-
120
- ### `eigenpal git clean [options]`
121
-
122
- Require a clean source working tree.
123
-
124
- ### Options
125
-
126
- | Flag | Required | Default | Description |
127
- | ------------- | -------- | ------- | -------------------- |
128
- | `--dir <dir>` | no | | Directory to inspect |
129
-
130
- ### `eigenpal git list|ls [options]`
131
-
132
- List Git-backed automations.
133
-
134
- ### Options
135
-
136
- | Flag | Required | Default | Description |
137
- | -------------------- | -------- | ------- | -------------------------------------- |
138
- | `--base-url <url>` | no | | Server base URL |
139
- | `--limit <n>` | no | `50` | Page size |
140
- | `--offset <n>` | no | `0` | Page offset |
141
- | `--json` | no | | Output the raw server response as JSON |
142
- | `--type <type>` | no | | Filter by automation type |
143
- | `--search <q>` | no | | Search by slug, name, or description |
144
- | `--include-archived` | no | | Include archived automations |
145
-
146
- ### `eigenpal git show [options] <automation>`
147
-
148
- Show Git-backed automation details.
149
-
150
- ### Arguments
151
-
152
- | Name | Required | Variadic | Description |
153
- | ------------ | -------- | -------- | ----------- |
154
- | `automation` | yes | no | |
155
-
156
- ### Options
157
-
158
- | Flag | Required | Default | Description |
159
- | ------------------ | -------- | ------- | -------------------------------------- |
160
- | `--base-url <url>` | no | | Server base URL |
161
- | `--json` | no | | Output the raw server response as JSON |
162
-
163
- ### `eigenpal git versions [options] <package>`
164
-
165
- List package release versions.
166
-
167
- ### Arguments
168
-
169
- | Name | Required | Variadic | Description |
170
- | --------- | -------- | -------- | ----------- |
171
- | `package` | yes | no | |
172
-
173
- ### Options
174
-
175
- | Flag | Required | Default | Description |
176
- | ------------------ | -------- | ------- | -------------------------------------- |
177
- | `--base-url <url>` | no | | Server base URL |
178
- | `--json` | no | | Output the raw server response as JSON |
179
-
180
- ### `eigenpal git release [options] <version> [dir]`
181
-
182
- Create and push a package release tag.
183
-
184
- ### Arguments
185
-
186
- | Name | Required | Variadic | Description |
187
- | --------- | -------- | -------- | --------------------- |
188
- | `version` | yes | no | Version or bump level |
189
- | `dir` | no | no | Package directory |
190
-
191
- ### Options
192
-
193
- | Flag | Required | Default | Description |
194
- | ------------------------- | -------- | ------- | --------------------- |
195
- | `--base-url <url>` | no | | Server base URL |
196
- | `-m, --message <message>` | yes | | Annotated tag message |
197
-
198
- ### `eigenpal git sync [options] [automation]`
199
-
200
- Sync an automation from the latest Git source release.
201
-
202
- ### Arguments
203
-
204
- | Name | Required | Variadic | Description |
205
- | ------------ | -------- | -------- | ----------- |
206
- | `automation` | no | no | |
207
-
208
- ### Options
209
-
210
- | Flag | Required | Default | Description |
211
- | ------------------ | -------- | ------- | -------------------- |
212
- | `--base-url <url>` | no | | Server base URL |
213
- | `--dir <dir>` | no | | Directory to inspect |
7
+ This command namespace is intentionally not documented in detail yet.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eigenpal/cli",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
5
5
  "keywords": [
6
6
  "eigenpal",