@markjaquith/agency 2.73.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -134
- package/cli-main.ts +0 -26
- package/cli.ts +1 -17
- package/package.json +1 -2
- package/schemas/agency-graph-v1.schema.json +1 -1
- package/src/cli-parser.test.ts +0 -19
- package/src/cli-parser.ts +0 -23
- package/src/cli.test.ts +3 -3
- package/src/commands/context.test.ts +11 -71
- package/src/commands/context.ts +7 -7
- package/src/commands/init.test.ts +1 -2
- package/src/commands/pr.test.ts +2 -87
- package/src/commands/pr.ts +2 -79
- package/src/commands/push.test.ts +1 -2
- package/src/graph-schema.ts +1 -1
- package/src/services/ArchiveBulkService.test.ts +1 -142
- package/src/services/ArchiveService.test.ts +1 -172
- package/src/services/ArchiveService.ts +0 -26
- package/src/services/ContextService.ts +7 -50
- package/src/services/DoctorService.ts +8 -24
- package/src/services/GraphService.test.ts +1 -0
- package/src/services/GraphService.ts +2 -5
- package/src/services/IntegrationService.test.ts +4 -0
- package/src/services/PhaseService.ts +70 -191
- package/src/services/PullRequestService.test.ts +1 -45
- package/src/services/PullRequestService.ts +1 -22
- package/src/services/PushService.test.ts +29 -295
- package/src/services/PushService.ts +10 -239
- package/src/services/RepositoryService.test.ts +1 -61
- package/src/services/RepositoryService.ts +2 -13
- package/src/services/ReviewService.test.ts +1 -84
- package/src/services/ReviewService.ts +9 -48
- package/src/services/SyncService.test.ts +0 -81
- package/src/services/SyncService.ts +12 -39
- package/src/services/TaskPhaseService.test.ts +0 -80
- package/src/services/TaskService.ts +1 -9
- package/src/services/VersionControlService.test.ts +4 -117
- package/src/services/VersionControlService.ts +3 -426
- package/src/services/WorkbaseService.test.ts +0 -20
- package/src/services/WorkbaseService.ts +1 -18
- package/src/services/WorktreeService.test.ts +1 -705
- package/src/services/WorktreeService.ts +395 -1604
- package/src/services/push-validation.ts +0 -7
- package/src/test-utils.ts +0 -4
- package/src/workbase/AGENTS.md +7 -7
- package/src/workbase/checkout-command.test.ts +1 -1
- package/src/workbase/checkout-command.ts +1 -1
- package/src/workbase/delivery-command.test.ts +4 -35
- package/src/workbase/delivery-command.ts +2 -15
- package/src/workbase/schemas.test.ts +0 -19
- package/src/workbase/schemas.ts +1 -2
- package/src/commands/vcs.test.ts +0 -75
- package/src/commands/vcs.ts +0 -72
- package/src/services/VcsMigrationService.test.ts +0 -348
- package/src/services/VcsMigrationService.ts +0 -857
- package/src/vcs-status-fast.ts +0 -310
- package/src/workbase/version-control.ts +0 -5
- package/src/workbase/workspace-command.test.ts +0 -70
- package/src/workbase/workspace-command.ts +0 -63
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Data, Effect } from "effect"
|
|
2
2
|
import { FileSystemService } from "./FileSystemService"
|
|
3
|
-
import { WorkbaseService } from "./WorkbaseService"
|
|
4
|
-
import type { VersionControlKind } from "../workbase/version-control"
|
|
5
3
|
|
|
6
4
|
export interface RegisteredWorkspace {
|
|
7
5
|
readonly name: string | null
|
|
@@ -12,35 +10,20 @@ export interface RegisteredWorkspace {
|
|
|
12
10
|
readonly dirty?: boolean
|
|
13
11
|
}
|
|
14
12
|
|
|
15
|
-
interface PullRequestDefaults {
|
|
16
|
-
readonly title: string
|
|
17
|
-
readonly body: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
13
|
interface RepositoryInspection {
|
|
21
14
|
readonly kind: "bare" | "repository"
|
|
22
15
|
readonly remote: string | null
|
|
23
16
|
}
|
|
24
17
|
|
|
25
18
|
export interface VersionControlBackend {
|
|
26
|
-
readonly kind:
|
|
19
|
+
readonly kind: "git"
|
|
27
20
|
readonly cloneRepository: (
|
|
28
21
|
source: string,
|
|
29
22
|
destination: string,
|
|
30
23
|
) => Effect.Effect<void, unknown, any>
|
|
31
|
-
readonly initializeRepository: (
|
|
32
|
-
path: string,
|
|
33
|
-
) => Effect.Effect<void, unknown, any>
|
|
34
24
|
readonly inspectRepository: (
|
|
35
25
|
path: string,
|
|
36
26
|
) => Effect.Effect<RepositoryInspection | null, unknown, any>
|
|
37
|
-
readonly gitEnvironment: (
|
|
38
|
-
path: string,
|
|
39
|
-
) => Effect.Effect<Record<string, string>, unknown, any>
|
|
40
|
-
readonly pullRequestDefaults: (
|
|
41
|
-
workspacePath: string,
|
|
42
|
-
base: string,
|
|
43
|
-
) => Effect.Effect<PullRequestDefaults | null, unknown, any>
|
|
44
27
|
readonly listWorkspaces: (
|
|
45
28
|
repositoryPath: string,
|
|
46
29
|
) => Effect.Effect<readonly RegisteredWorkspace[], unknown, any>
|
|
@@ -54,26 +37,11 @@ export interface VersionControlBackend {
|
|
|
54
37
|
readonly workspaceDirty: (
|
|
55
38
|
workspacePath: string,
|
|
56
39
|
) => Effect.Effect<boolean | null, unknown, any>
|
|
57
|
-
readonly createWorkspace: (options: {
|
|
58
|
-
readonly repositoryPath: string
|
|
59
|
-
readonly workspacePath: string
|
|
60
|
-
readonly workspaceName: string
|
|
61
|
-
readonly revision: string
|
|
62
|
-
readonly branch?: string
|
|
63
|
-
}) => Effect.Effect<void, unknown, any>
|
|
64
|
-
readonly removeWorkspace: (options: {
|
|
65
|
-
readonly repositoryPath: string
|
|
66
|
-
readonly workspacePath: string
|
|
67
|
-
readonly workspaceName: string | null
|
|
68
|
-
}) => Effect.Effect<void, unknown, any>
|
|
69
40
|
readonly fetch: (
|
|
70
41
|
repositoryPath: string,
|
|
71
42
|
remote?: string,
|
|
72
43
|
branch?: string,
|
|
73
44
|
) => Effect.Effect<void, unknown, any>
|
|
74
|
-
readonly importGitRefs: (
|
|
75
|
-
repositoryPath: string,
|
|
76
|
-
) => Effect.Effect<void, unknown, any>
|
|
77
45
|
readonly push: (
|
|
78
46
|
workspacePath: string,
|
|
79
47
|
remote: string,
|
|
@@ -210,7 +178,6 @@ export class GitVersionControlService extends Effect.Service<GitVersionControlSe
|
|
|
210
178
|
),
|
|
211
179
|
)
|
|
212
180
|
}),
|
|
213
|
-
initializeRepository: () => Effect.void,
|
|
214
181
|
inspectRepository: (path) =>
|
|
215
182
|
Effect.gen(function* () {
|
|
216
183
|
const fs = yield* FileSystemService
|
|
@@ -243,8 +210,6 @@ export class GitVersionControlService extends Effect.Service<GitVersionControlSe
|
|
|
243
210
|
remote === undefined ? null : expandGitUrl(remote, entries),
|
|
244
211
|
} as const
|
|
245
212
|
}),
|
|
246
|
-
gitEnvironment: () => Effect.succeed({}),
|
|
247
|
-
pullRequestDefaults: () => Effect.succeed(null),
|
|
248
213
|
listWorkspaces: (repositoryPath) =>
|
|
249
214
|
Effect.gen(function* () {
|
|
250
215
|
const fs = yield* FileSystemService
|
|
@@ -299,54 +264,6 @@ export class GitVersionControlService extends Effect.Service<GitVersionControlSe
|
|
|
299
264
|
)
|
|
300
265
|
return result.exitCode === 0 ? result.stdout.length > 0 : null
|
|
301
266
|
}),
|
|
302
|
-
createWorkspace: (options) =>
|
|
303
|
-
Effect.gen(function* () {
|
|
304
|
-
const fs = yield* FileSystemService
|
|
305
|
-
const command = options.branch
|
|
306
|
-
? [
|
|
307
|
-
"git",
|
|
308
|
-
"-C",
|
|
309
|
-
options.repositoryPath,
|
|
310
|
-
"worktree",
|
|
311
|
-
"add",
|
|
312
|
-
"-b",
|
|
313
|
-
options.branch,
|
|
314
|
-
options.workspacePath,
|
|
315
|
-
options.revision,
|
|
316
|
-
]
|
|
317
|
-
: [
|
|
318
|
-
"git",
|
|
319
|
-
"-C",
|
|
320
|
-
options.repositoryPath,
|
|
321
|
-
"worktree",
|
|
322
|
-
"add",
|
|
323
|
-
"--detach",
|
|
324
|
-
options.workspacePath,
|
|
325
|
-
options.revision,
|
|
326
|
-
]
|
|
327
|
-
yield* requireSuccess(
|
|
328
|
-
"Failed to create Git worktree",
|
|
329
|
-
fs.runCommand(command, { captureOutput: true }),
|
|
330
|
-
)
|
|
331
|
-
}),
|
|
332
|
-
removeWorkspace: (options) =>
|
|
333
|
-
Effect.gen(function* () {
|
|
334
|
-
const fs = yield* FileSystemService
|
|
335
|
-
yield* requireSuccess(
|
|
336
|
-
"Failed to remove Git worktree",
|
|
337
|
-
fs.runCommand(
|
|
338
|
-
[
|
|
339
|
-
"git",
|
|
340
|
-
"-C",
|
|
341
|
-
options.repositoryPath,
|
|
342
|
-
"worktree",
|
|
343
|
-
"remove",
|
|
344
|
-
options.workspacePath,
|
|
345
|
-
],
|
|
346
|
-
{ captureOutput: true },
|
|
347
|
-
),
|
|
348
|
-
)
|
|
349
|
-
}),
|
|
350
267
|
fetch: (repositoryPath, remote = "origin", branch) =>
|
|
351
268
|
Effect.gen(function* () {
|
|
352
269
|
const fs = yield* FileSystemService
|
|
@@ -365,7 +282,6 @@ export class GitVersionControlService extends Effect.Service<GitVersionControlSe
|
|
|
365
282
|
),
|
|
366
283
|
)
|
|
367
284
|
}),
|
|
368
|
-
importGitRefs: () => Effect.void,
|
|
369
285
|
push: (workspacePath, remote, branch) =>
|
|
370
286
|
Effect.gen(function* () {
|
|
371
287
|
const fs = yield* FileSystemService
|
|
@@ -422,352 +338,13 @@ export class GitVersionControlService extends Effect.Service<GitVersionControlSe
|
|
|
422
338
|
},
|
|
423
339
|
) {}
|
|
424
340
|
|
|
425
|
-
const jjCommand = (repositoryPath: string, args: readonly string[]) => [
|
|
426
|
-
"jj",
|
|
427
|
-
"-R",
|
|
428
|
-
repositoryPath,
|
|
429
|
-
"--no-pager",
|
|
430
|
-
...args,
|
|
431
|
-
]
|
|
432
|
-
|
|
433
|
-
export class JjVersionControlService extends Effect.Service<JjVersionControlService>()(
|
|
434
|
-
"JjVersionControlService",
|
|
435
|
-
{
|
|
436
|
-
sync: () =>
|
|
437
|
-
({
|
|
438
|
-
kind: "jj",
|
|
439
|
-
cloneRepository: (source, destination) =>
|
|
440
|
-
Effect.gen(function* () {
|
|
441
|
-
const fs = yield* FileSystemService
|
|
442
|
-
yield* requireSuccess(
|
|
443
|
-
"Failed to clone jj repository",
|
|
444
|
-
fs.runCommand(
|
|
445
|
-
[
|
|
446
|
-
"jj",
|
|
447
|
-
"git",
|
|
448
|
-
"clone",
|
|
449
|
-
"--no-colocate",
|
|
450
|
-
"--",
|
|
451
|
-
source,
|
|
452
|
-
destination,
|
|
453
|
-
],
|
|
454
|
-
{ captureOutput: true },
|
|
455
|
-
),
|
|
456
|
-
)
|
|
457
|
-
}),
|
|
458
|
-
initializeRepository: (path) =>
|
|
459
|
-
Effect.gen(function* () {
|
|
460
|
-
const fs = yield* FileSystemService
|
|
461
|
-
if (yield* fs.exists(`${path}/.jj`)) return
|
|
462
|
-
yield* requireSuccess(
|
|
463
|
-
"Failed to initialize jj repository",
|
|
464
|
-
fs.runCommand(["jj", "git", "init", "--colocate", path], {
|
|
465
|
-
captureOutput: true,
|
|
466
|
-
}),
|
|
467
|
-
)
|
|
468
|
-
}),
|
|
469
|
-
inspectRepository: (path) =>
|
|
470
|
-
Effect.gen(function* () {
|
|
471
|
-
const fs = yield* FileSystemService
|
|
472
|
-
const root = yield* fs.runCommand(jjCommand(path, ["root"]), {
|
|
473
|
-
captureOutput: true,
|
|
474
|
-
})
|
|
475
|
-
if (root.exitCode !== 0) return null
|
|
476
|
-
const remote = yield* fs.runCommand(
|
|
477
|
-
jjCommand(path, ["git", "remote", "list"]),
|
|
478
|
-
{ captureOutput: true },
|
|
479
|
-
)
|
|
480
|
-
return {
|
|
481
|
-
kind: "repository",
|
|
482
|
-
remote:
|
|
483
|
-
remote.exitCode === 0
|
|
484
|
-
? (remote.stdout
|
|
485
|
-
.split("\n")
|
|
486
|
-
.find((line) => line.startsWith("origin "))
|
|
487
|
-
?.slice("origin ".length)
|
|
488
|
-
.trim() ?? null)
|
|
489
|
-
: null,
|
|
490
|
-
} as const
|
|
491
|
-
}),
|
|
492
|
-
gitEnvironment: (path) =>
|
|
493
|
-
Effect.gen(function* () {
|
|
494
|
-
const fs = yield* FileSystemService
|
|
495
|
-
const result = yield* requireSuccess(
|
|
496
|
-
"Failed to locate jj backing Git repository",
|
|
497
|
-
fs.runCommand(jjCommand(path, ["git", "root"]), {
|
|
498
|
-
captureOutput: true,
|
|
499
|
-
}),
|
|
500
|
-
)
|
|
501
|
-
return { GIT_DIR: result.stdout.trim() }
|
|
502
|
-
}),
|
|
503
|
-
pullRequestDefaults: (workspacePath, base) =>
|
|
504
|
-
Effect.gen(function* () {
|
|
505
|
-
const fs = yield* FileSystemService
|
|
506
|
-
const result = yield* fs.runCommand(
|
|
507
|
-
jjCommand(workspacePath, [
|
|
508
|
-
"log",
|
|
509
|
-
"--ignore-working-copy",
|
|
510
|
-
"--no-graph",
|
|
511
|
-
"-r",
|
|
512
|
-
`${base}..@-`,
|
|
513
|
-
"-T",
|
|
514
|
-
'description.first_line() ++ "\\n"',
|
|
515
|
-
]),
|
|
516
|
-
{ captureOutput: true },
|
|
517
|
-
)
|
|
518
|
-
if (result.exitCode !== 0) return null
|
|
519
|
-
const commits = result.stdout
|
|
520
|
-
.split("\n")
|
|
521
|
-
.map((line) => line.trim())
|
|
522
|
-
.filter(Boolean)
|
|
523
|
-
if (commits.length === 0) return null
|
|
524
|
-
return {
|
|
525
|
-
title: commits.at(-1)!,
|
|
526
|
-
body:
|
|
527
|
-
commits.length === 1
|
|
528
|
-
? ""
|
|
529
|
-
: `Commits:\n${commits
|
|
530
|
-
.toReversed()
|
|
531
|
-
.map((commit) => `- ${commit}`)
|
|
532
|
-
.join("\n")}`,
|
|
533
|
-
} satisfies PullRequestDefaults
|
|
534
|
-
}),
|
|
535
|
-
listWorkspaces: (repositoryPath) =>
|
|
536
|
-
Effect.gen(function* () {
|
|
537
|
-
const fs = yield* FileSystemService
|
|
538
|
-
const result = yield* requireSuccess(
|
|
539
|
-
"Failed to inspect jj workspaces",
|
|
540
|
-
fs.runCommand(
|
|
541
|
-
jjCommand(repositoryPath, [
|
|
542
|
-
"workspace",
|
|
543
|
-
"list",
|
|
544
|
-
"-T",
|
|
545
|
-
'name ++ "\\t" ++ root ++ "\\t" ++ target.commit_id() ++ "\\t" ++ target.parents().map(|commit| commit.commit_id()).join(",") ++ "\\t" ++ target.empty() ++ "\\n"',
|
|
546
|
-
]),
|
|
547
|
-
{ captureOutput: true },
|
|
548
|
-
),
|
|
549
|
-
)
|
|
550
|
-
return result.stdout
|
|
551
|
-
.trim()
|
|
552
|
-
.split("\n")
|
|
553
|
-
.filter(Boolean)
|
|
554
|
-
.map((line) => {
|
|
555
|
-
const [name, path, commit, parents, empty] = line.split("\t")
|
|
556
|
-
const parentCommits = parents?.split(",").filter(Boolean) ?? []
|
|
557
|
-
return {
|
|
558
|
-
name: name || null,
|
|
559
|
-
path: path!,
|
|
560
|
-
commit: commit || null,
|
|
561
|
-
branch: null,
|
|
562
|
-
head:
|
|
563
|
-
parentCommits.length === 1 ? parentCommits[0]! : undefined,
|
|
564
|
-
dirty: empty === "false",
|
|
565
|
-
}
|
|
566
|
-
})
|
|
567
|
-
}),
|
|
568
|
-
resolveRevision: (repositoryPath, revision) =>
|
|
569
|
-
Effect.gen(function* () {
|
|
570
|
-
const fs = yield* FileSystemService
|
|
571
|
-
const resolve = () =>
|
|
572
|
-
fs.runCommand(
|
|
573
|
-
jjCommand(repositoryPath, [
|
|
574
|
-
"log",
|
|
575
|
-
"--ignore-working-copy",
|
|
576
|
-
"--no-graph",
|
|
577
|
-
"-r",
|
|
578
|
-
revision,
|
|
579
|
-
"-T",
|
|
580
|
-
'commit_id ++ "\\n"',
|
|
581
|
-
]),
|
|
582
|
-
{ captureOutput: true },
|
|
583
|
-
)
|
|
584
|
-
let result = yield* resolve()
|
|
585
|
-
if (result.exitCode !== 0 || !result.stdout.trim()) {
|
|
586
|
-
const imported = yield* fs.runCommand(
|
|
587
|
-
jjCommand(repositoryPath, ["git", "import"]),
|
|
588
|
-
{ captureOutput: true },
|
|
589
|
-
)
|
|
590
|
-
if (imported.exitCode === 0) result = yield* resolve()
|
|
591
|
-
}
|
|
592
|
-
return result.exitCode === 0 ? result.stdout.trim() || null : null
|
|
593
|
-
}),
|
|
594
|
-
workspaceHead: (workspacePath) =>
|
|
595
|
-
Effect.gen(function* () {
|
|
596
|
-
const fs = yield* FileSystemService
|
|
597
|
-
const result = yield* fs.runCommand(
|
|
598
|
-
jjCommand(workspacePath, [
|
|
599
|
-
"log",
|
|
600
|
-
"--ignore-working-copy",
|
|
601
|
-
"--no-graph",
|
|
602
|
-
"-r",
|
|
603
|
-
"@-",
|
|
604
|
-
"-T",
|
|
605
|
-
'commit_id ++ "\\n"',
|
|
606
|
-
]),
|
|
607
|
-
{ captureOutput: true },
|
|
608
|
-
)
|
|
609
|
-
return result.exitCode === 0 ? result.stdout.trim() || null : null
|
|
610
|
-
}),
|
|
611
|
-
workspaceDirty: (workspacePath) =>
|
|
612
|
-
Effect.gen(function* () {
|
|
613
|
-
const fs = yield* FileSystemService
|
|
614
|
-
const result = yield* fs.runCommand(
|
|
615
|
-
jjCommand(workspacePath, ["diff", "--summary", "-r", "@"]),
|
|
616
|
-
{ captureOutput: true },
|
|
617
|
-
)
|
|
618
|
-
return result.exitCode === 0 ? result.stdout.length > 0 : null
|
|
619
|
-
}),
|
|
620
|
-
createWorkspace: (options) =>
|
|
621
|
-
Effect.gen(function* () {
|
|
622
|
-
const fs = yield* FileSystemService
|
|
623
|
-
yield* requireSuccess(
|
|
624
|
-
"Failed to create jj workspace",
|
|
625
|
-
fs.runCommand(
|
|
626
|
-
jjCommand(options.repositoryPath, [
|
|
627
|
-
"workspace",
|
|
628
|
-
"add",
|
|
629
|
-
"--name",
|
|
630
|
-
options.workspaceName,
|
|
631
|
-
"-r",
|
|
632
|
-
options.revision,
|
|
633
|
-
options.workspacePath,
|
|
634
|
-
]),
|
|
635
|
-
{ captureOutput: true },
|
|
636
|
-
),
|
|
637
|
-
)
|
|
638
|
-
}),
|
|
639
|
-
removeWorkspace: (options) =>
|
|
640
|
-
Effect.gen(function* () {
|
|
641
|
-
const fs = yield* FileSystemService
|
|
642
|
-
if (!options.workspaceName) {
|
|
643
|
-
return yield* new VersionControlError({
|
|
644
|
-
message: `Cannot remove unregistered jj workspace ${options.workspacePath}`,
|
|
645
|
-
})
|
|
646
|
-
}
|
|
647
|
-
yield* requireSuccess(
|
|
648
|
-
"Failed to forget jj workspace",
|
|
649
|
-
fs.runCommand(
|
|
650
|
-
jjCommand(options.repositoryPath, [
|
|
651
|
-
"workspace",
|
|
652
|
-
"forget",
|
|
653
|
-
options.workspaceName,
|
|
654
|
-
]),
|
|
655
|
-
{ captureOutput: true },
|
|
656
|
-
),
|
|
657
|
-
)
|
|
658
|
-
yield* fs.deleteDirectory(options.workspacePath)
|
|
659
|
-
}),
|
|
660
|
-
fetch: (repositoryPath, remote = "origin", branch) =>
|
|
661
|
-
Effect.gen(function* () {
|
|
662
|
-
const fs = yield* FileSystemService
|
|
663
|
-
yield* requireSuccess(
|
|
664
|
-
"Failed to fetch jj repository",
|
|
665
|
-
fs.runCommand(
|
|
666
|
-
jjCommand(repositoryPath, [
|
|
667
|
-
"git",
|
|
668
|
-
"fetch",
|
|
669
|
-
"--remote",
|
|
670
|
-
remote,
|
|
671
|
-
...(branch ? ["--branch", branch] : []),
|
|
672
|
-
]),
|
|
673
|
-
{ captureOutput: true },
|
|
674
|
-
),
|
|
675
|
-
)
|
|
676
|
-
}),
|
|
677
|
-
importGitRefs: (repositoryPath) =>
|
|
678
|
-
Effect.gen(function* () {
|
|
679
|
-
const fs = yield* FileSystemService
|
|
680
|
-
yield* requireSuccess(
|
|
681
|
-
"Failed to import Git refs into jj",
|
|
682
|
-
fs.runCommand(jjCommand(repositoryPath, ["git", "import"]), {
|
|
683
|
-
captureOutput: true,
|
|
684
|
-
}),
|
|
685
|
-
)
|
|
686
|
-
}),
|
|
687
|
-
push: (workspacePath, remote, branch) =>
|
|
688
|
-
Effect.gen(function* () {
|
|
689
|
-
const fs = yield* FileSystemService
|
|
690
|
-
yield* requireSuccess(
|
|
691
|
-
"Failed to set jj delivery bookmark",
|
|
692
|
-
fs.runCommand(
|
|
693
|
-
jjCommand(workspacePath, [
|
|
694
|
-
"bookmark",
|
|
695
|
-
"set",
|
|
696
|
-
"--allow-backwards",
|
|
697
|
-
branch,
|
|
698
|
-
"-r",
|
|
699
|
-
"@-",
|
|
700
|
-
]),
|
|
701
|
-
{ captureOutput: true },
|
|
702
|
-
),
|
|
703
|
-
)
|
|
704
|
-
yield* requireSuccess(
|
|
705
|
-
"Failed to push branch",
|
|
706
|
-
fs.runCommand(
|
|
707
|
-
jjCommand(workspacePath, [
|
|
708
|
-
"git",
|
|
709
|
-
"push",
|
|
710
|
-
"--remote",
|
|
711
|
-
remote,
|
|
712
|
-
"--bookmark",
|
|
713
|
-
branch,
|
|
714
|
-
]),
|
|
715
|
-
{ captureOutput: true },
|
|
716
|
-
),
|
|
717
|
-
)
|
|
718
|
-
}),
|
|
719
|
-
remoteUrl: (repositoryPath, remote) =>
|
|
720
|
-
Effect.gen(function* () {
|
|
721
|
-
const fs = yield* FileSystemService
|
|
722
|
-
const result = yield* fs.runCommand(
|
|
723
|
-
jjCommand(repositoryPath, ["git", "remote", "list"]),
|
|
724
|
-
{ captureOutput: true },
|
|
725
|
-
)
|
|
726
|
-
if (result.exitCode !== 0) return null
|
|
727
|
-
return (
|
|
728
|
-
result.stdout
|
|
729
|
-
.split("\n")
|
|
730
|
-
.find((line) => line.startsWith(`${remote} `))
|
|
731
|
-
?.slice(remote.length + 1)
|
|
732
|
-
.trim() ?? null
|
|
733
|
-
)
|
|
734
|
-
}),
|
|
735
|
-
setRemoteUrl: (repositoryPath, remote, url) =>
|
|
736
|
-
Effect.gen(function* () {
|
|
737
|
-
const fs = yield* FileSystemService
|
|
738
|
-
const previous = yield* fs.runCommand(
|
|
739
|
-
jjCommand(repositoryPath, ["git", "remote", "list"]),
|
|
740
|
-
{ captureOutput: true },
|
|
741
|
-
)
|
|
742
|
-
const exists = previous.stdout
|
|
743
|
-
.split("\n")
|
|
744
|
-
.some((line) => line.startsWith(`${remote} `))
|
|
745
|
-
const args =
|
|
746
|
-
url === null
|
|
747
|
-
? ["git", "remote", "remove", remote]
|
|
748
|
-
: ["git", "remote", exists ? "set-url" : "add", remote, url]
|
|
749
|
-
yield* requireSuccess(
|
|
750
|
-
`Failed to update jj Git remote '${remote}'`,
|
|
751
|
-
fs.runCommand(jjCommand(repositoryPath, args), {
|
|
752
|
-
captureOutput: true,
|
|
753
|
-
}),
|
|
754
|
-
)
|
|
755
|
-
}),
|
|
756
|
-
}) satisfies VersionControlBackend,
|
|
757
|
-
},
|
|
758
|
-
) {}
|
|
759
|
-
|
|
760
341
|
export class VersionControlService extends Effect.Service<VersionControlService>()(
|
|
761
342
|
"VersionControlService",
|
|
762
343
|
{
|
|
763
344
|
sync: () => ({
|
|
764
|
-
forWorkbase: (
|
|
345
|
+
forWorkbase: (_root: string) =>
|
|
765
346
|
Effect.gen(function* () {
|
|
766
|
-
|
|
767
|
-
const git = yield* GitVersionControlService
|
|
768
|
-
const jj = yield* JjVersionControlService
|
|
769
|
-
const { config } = yield* workbase.loadConfig(root)
|
|
770
|
-
return config.vcs === "jj" ? jj : git
|
|
347
|
+
return yield* GitVersionControlService
|
|
771
348
|
}),
|
|
772
349
|
}),
|
|
773
350
|
},
|
|
@@ -462,26 +462,6 @@ status: done
|
|
|
462
462
|
).rejects.toThrow("{worktree}")
|
|
463
463
|
})
|
|
464
464
|
|
|
465
|
-
test("rejects an invalid workspace command template", async () => {
|
|
466
|
-
await write(
|
|
467
|
-
root,
|
|
468
|
-
"agency.json",
|
|
469
|
-
JSON.stringify({
|
|
470
|
-
version: 2,
|
|
471
|
-
vcs: "jj",
|
|
472
|
-
workspaceCreateCommand: ["tool", "{repo}", "{workspace}", "{name}"],
|
|
473
|
-
}),
|
|
474
|
-
)
|
|
475
|
-
|
|
476
|
-
await expect(
|
|
477
|
-
runTestEffect(
|
|
478
|
-
WorkbaseService.pipe(
|
|
479
|
-
Effect.flatMap((service) => service.discover(root)),
|
|
480
|
-
),
|
|
481
|
-
),
|
|
482
|
-
).rejects.toThrow("{revision}")
|
|
483
|
-
})
|
|
484
|
-
|
|
485
465
|
test("rejects an unknown post-checkout command placeholder", async () => {
|
|
486
466
|
await write(
|
|
487
467
|
root,
|
|
@@ -21,12 +21,10 @@ import {
|
|
|
21
21
|
type WorkbaseRegistration,
|
|
22
22
|
} from "../workbase/schemas"
|
|
23
23
|
import { validateWorktreeCreateCommand } from "../workbase/worktree-command"
|
|
24
|
-
import { validateWorkspaceCreateCommand } from "../workbase/workspace-command"
|
|
25
24
|
import { validatePostCheckoutCommand } from "../workbase/checkout-command"
|
|
26
25
|
import { validateAgents } from "../workbase/agent-command"
|
|
27
26
|
import { findDependencyCycles } from "../workbase/dependency-graph"
|
|
28
27
|
import { validateDelivery } from "../workbase/delivery-command"
|
|
29
|
-
import { preferredVersionControl } from "../workbase/version-control"
|
|
30
28
|
import { documentRevision } from "../workbase/document-revision"
|
|
31
29
|
|
|
32
30
|
class WorkbaseNotFoundError extends Data.TaggedError("WorkbaseNotFoundError")<{
|
|
@@ -247,7 +245,7 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
|
|
|
247
245
|
[
|
|
248
246
|
fs.writeJSON(configPath, {
|
|
249
247
|
version: 2,
|
|
250
|
-
vcs:
|
|
248
|
+
vcs: "git",
|
|
251
249
|
}),
|
|
252
250
|
...["repos", "epics", "tasks"].map((directory) =>
|
|
253
251
|
fs.createDirectory(join(root, directory)),
|
|
@@ -332,21 +330,6 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
|
|
|
332
330
|
})
|
|
333
331
|
}
|
|
334
332
|
}
|
|
335
|
-
if (decoded.value.workspaceCreateCommand) {
|
|
336
|
-
try {
|
|
337
|
-
validateWorkspaceCreateCommand(
|
|
338
|
-
decoded.value.workspaceCreateCommand,
|
|
339
|
-
)
|
|
340
|
-
} catch (cause) {
|
|
341
|
-
return yield* new WorkbaseConfigError({
|
|
342
|
-
path: configPath,
|
|
343
|
-
message:
|
|
344
|
-
cause instanceof Error
|
|
345
|
-
? cause.message
|
|
346
|
-
: "Invalid workspaceCreateCommand",
|
|
347
|
-
})
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
333
|
for (const [alias, repository] of Object.entries(
|
|
351
334
|
decoded.value.repositories ?? {},
|
|
352
335
|
)) {
|