@markjaquith/agency 1.6.0 → 1.6.2

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/cli.ts CHANGED
@@ -635,7 +635,31 @@ try {
635
635
  await command.run(cmdPositionals, cmdValues, commandArgs)
636
636
  } catch (error) {
637
637
  if (error instanceof Error) {
638
- console.error(`ⓘ ${error.message}`)
638
+ let message = error.message
639
+
640
+ // Handle Effect FiberFailure errors that wrap tagged errors
641
+ // When the message is generic "An error has occurred", try to extract the actual error
642
+ if (message === "An error has occurred") {
643
+ // Try to extract the actual error from Effect's Cause structure
644
+ const causeSymbol = Object.getOwnPropertySymbols(error).find((s) =>
645
+ s.toString().includes("Cause"),
646
+ )
647
+ if (causeSymbol) {
648
+ const cause = (error as any)[causeSymbol]
649
+ if (cause && cause._tag === "Fail" && cause.failure) {
650
+ const failure = cause.failure
651
+ // Try common error message patterns
652
+ message =
653
+ failure.message ||
654
+ failure.stderr ||
655
+ (failure._tag
656
+ ? `${failure._tag}: ${JSON.stringify(failure)}`
657
+ : JSON.stringify(failure))
658
+ }
659
+ }
660
+ }
661
+
662
+ console.error(`ⓘ ${message}`)
639
663
  } else {
640
664
  console.error("An unexpected error occurred:", error)
641
665
  }
package/package.json CHANGED
@@ -1,53 +1,65 @@
1
1
  {
2
2
  "name": "@markjaquith/agency",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Manages personal agents files",
5
+ "keywords": [
6
+ "agents",
7
+ "bun",
8
+ "personal-agents",
9
+ "typescript"
10
+ ],
5
11
  "license": "MIT",
6
12
  "author": "Mark Jaquith",
7
13
  "repository": {
8
14
  "type": "git",
9
15
  "url": "git+https://github.com/markjaquith/agency.git"
10
16
  },
11
- "module": "index.ts",
12
- "type": "module",
13
17
  "bin": {
14
18
  "agency": "cli.ts"
15
19
  },
20
+ "files": [
21
+ "index.ts",
22
+ "cli.ts",
23
+ "src",
24
+ "templates",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "type": "module",
29
+ "module": "index.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./index.ts",
33
+ "import": "./index.ts"
34
+ }
35
+ },
36
+ "publishConfig": {
37
+ "access": "public",
38
+ "provenance": true,
39
+ "registry": "https://registry.npmjs.org/",
40
+ "tag": "latest"
41
+ },
16
42
  "scripts": {
17
43
  "test": "find src -name '*.test.ts' ! -name '*.integration.test.ts' -print0 | xargs -0 -n 1 -P 4 bun test",
18
44
  "test:integration": "find src -name '*.integration.test.ts' -print0 | xargs -0 -n 1 -P 4 bun test",
19
45
  "test:all": "find src -name '*.test.ts' -print0 | xargs -0 -n 1 -P 4 bun test",
20
- "format": "prettier --write .",
21
- "format:check": "prettier --check .",
46
+ "format": "oxfmt",
47
+ "format:check": "oxfmt --check",
22
48
  "knip": "knip --production",
23
49
  "pushable": "./scripts/pushable",
24
50
  "check-commit-msg": "./scripts/check-commit-msg",
25
51
  "build": "bun build cli.ts --outdir dist --target node --minify"
26
52
  },
27
- "exports": {
28
- ".": {
29
- "import": "./index.ts",
30
- "types": "./index.ts"
31
- }
53
+ "dependencies": {
54
+ "@effect/schema": "^0.75.5",
55
+ "effect": "^3.19.15",
56
+ "jsonc-parser": "^3.3.1",
57
+ "ora": "^8.2.0"
32
58
  },
33
- "files": [
34
- "index.ts",
35
- "cli.ts",
36
- "src",
37
- "templates",
38
- "README.md",
39
- "LICENSE"
40
- ],
41
- "keywords": [
42
- "agents",
43
- "bun",
44
- "typescript",
45
- "personal-agents"
46
- ],
47
59
  "devDependencies": {
48
60
  "@types/bun": "^1.3.6",
49
61
  "knip": "^5.82.1",
50
- "prettier": "^3.8.1"
62
+ "oxfmt": "^0.27.0"
51
63
  },
52
64
  "peerDependencies": {
53
65
  "typescript": "^5.9.3"
@@ -55,19 +67,7 @@
55
67
  "engines": {
56
68
  "bun": ">=1.0.0"
57
69
  },
58
- "dependencies": {
59
- "@effect/schema": "^0.75.5",
60
- "effect": "^3.19.15",
61
- "jsonc-parser": "^3.3.1",
62
- "ora": "^8.2.0"
63
- },
64
70
  "trustedDependencies": [
65
71
  "@triggi/native-exec"
66
- ],
67
- "publishConfig": {
68
- "registry": "https://registry.npmjs.org/",
69
- "tag": "latest",
70
- "access": "public",
71
- "provenance": true
72
- }
72
+ ]
73
73
  }
@@ -422,14 +422,36 @@ export const task = (options: TaskOptions = {}) =>
422
422
  (yield* git.findDefaultRemote(targetPath))
423
423
 
424
424
  if (remote) {
425
- log(info(`Fetching latest from ${highlight.branch(remote)}...`))
426
- verboseLog(`Fetching from remote: ${remote}`)
427
- yield* git.fetch(targetPath, remote).pipe(
428
- Effect.catchAll((err) => {
429
- verboseLog(`Failed to fetch from ${remote}: ${err}`)
430
- return Effect.void
431
- }),
432
- )
425
+ // Get just the branch name (e.g., "main") to fetch only that branch
426
+ // This is much faster than fetching all branches in large repos
427
+ const mainBranchName = yield* git.getMainBranchName(targetPath)
428
+
429
+ if (mainBranchName) {
430
+ log(
431
+ info(
432
+ `Fetching latest from ${highlight.branch(`${remote}/${mainBranchName}`)}...`,
433
+ ),
434
+ )
435
+ verboseLog(`Fetching ${mainBranchName} from remote: ${remote}`)
436
+ yield* git.fetch(targetPath, remote, mainBranchName).pipe(
437
+ Effect.catchAll((err) => {
438
+ verboseLog(
439
+ `Failed to fetch ${mainBranchName} from ${remote}: ${err}`,
440
+ )
441
+ return Effect.void
442
+ }),
443
+ )
444
+ } else {
445
+ // Fallback: fetch all branches if we can't determine the main branch
446
+ log(info(`Fetching latest from ${highlight.branch(remote)}...`))
447
+ verboseLog(`Fetching all branches from remote: ${remote}`)
448
+ yield* git.fetch(targetPath, remote).pipe(
449
+ Effect.catchAll((err) => {
450
+ verboseLog(`Failed to fetch from ${remote}: ${err}`)
451
+ return Effect.void
452
+ }),
453
+ )
454
+ }
433
455
  }
434
456
 
435
457
  // Now resolve the main branch (preferring remote)
@@ -22,7 +22,14 @@ export class GitCommandError extends Data.TaggedError("GitCommandError")<{
22
22
  command: string
23
23
  exitCode: number
24
24
  stderr: string
25
- }> {}
25
+ }> {
26
+ override get message(): string {
27
+ return (
28
+ this.stderr ||
29
+ `Git command failed with exit code ${this.exitCode}: ${this.command}`
30
+ )
31
+ }
32
+ }
26
33
 
27
34
  // Error mapper for git command failures
28
35
  const mapToGitCommandError = createErrorMapper(GitCommandError)
@@ -515,6 +522,72 @@ export class GitService extends Effect.Service<GitService>()("GitService", {
515
522
  ),
516
523
  ),
517
524
 
525
+ /**
526
+ * Gets just the main branch name (e.g., "main" or "master") without any remote prefix.
527
+ *
528
+ * This is useful when you need to fetch a specific branch from a remote,
529
+ * as `git fetch origin main` requires just the branch name, not `origin/main`.
530
+ */
531
+ getMainBranchName: (gitRoot: string) =>
532
+ Effect.gen(function* () {
533
+ // Get the configured main branch
534
+ const configuredBranch = yield* getGitConfigEffect(
535
+ "agency.mainBranch",
536
+ gitRoot,
537
+ ).pipe(Effect.catchAll(() => Effect.succeed(null)))
538
+
539
+ // If configured, strip any remote prefix and return
540
+ if (configuredBranch) {
541
+ // Strip remote prefix if present (e.g., "origin/main" -> "main")
542
+ return (
543
+ configuredBranch.match(/^[^/]+\/(.+)$/)?.[1] || configuredBranch
544
+ )
545
+ }
546
+
547
+ // Otherwise, find the main branch by checking what exists
548
+ // We need to check for common branch names that exist (local or remote)
549
+ const remotesResult = yield* runGitCommand(["git", "remote"], gitRoot)
550
+ const remotes =
551
+ remotesResult.exitCode === 0 && remotesResult.stdout.trim()
552
+ ? remotesResult.stdout.trim().split("\n")
553
+ : []
554
+
555
+ // Determine the default remote
556
+ let defaultRemote: string | null = null
557
+ if (remotes.length > 0) {
558
+ if (remotes.includes("origin")) {
559
+ defaultRemote = "origin"
560
+ } else if (remotes.includes("upstream")) {
561
+ defaultRemote = "upstream"
562
+ } else {
563
+ defaultRemote = remotes[0] || null
564
+ }
565
+ }
566
+
567
+ // Check for common branch names (either remote or local)
568
+ for (const branchName of ["main", "master"]) {
569
+ // Check remote version first
570
+ if (defaultRemote) {
571
+ const remoteBranch = `${defaultRemote}/${branchName}`
572
+ const exists = yield* branchExistsEffect(gitRoot, remoteBranch)
573
+ if (exists) {
574
+ return branchName
575
+ }
576
+ }
577
+ // Check local version
578
+ const localExists = yield* branchExistsEffect(gitRoot, branchName)
579
+ if (localExists) {
580
+ return branchName
581
+ }
582
+ }
583
+
584
+ return null
585
+ }).pipe(
586
+ Effect.mapError(
587
+ () => new GitError({ message: "Failed to get main branch name" }),
588
+ ),
589
+ ),
590
+
518
591
  getDefaultBaseBranchConfig: (gitRoot: string) =>
519
592
  pipe(
520
593
  getGitConfigEffect("agency.baseBranch", gitRoot),
@@ -27,7 +27,14 @@ class ProcessError extends Data.TaggedError("ProcessError")<{
27
27
  command: string
28
28
  exitCode: number
29
29
  stderr: string
30
- }> {}
30
+ }> {
31
+ override get message(): string {
32
+ return (
33
+ this.stderr ||
34
+ `Process failed with exit code ${this.exitCode}: ${this.command}`
35
+ )
36
+ }
37
+ }
31
38
 
32
39
  /**
33
40
  * Spawn a process with proper error handling and typed results.