@cueloop/daemon 0.1.0-alpha.93 → 0.1.0-alpha.95
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/package.json +3 -3
- package/src/api.ts +38 -7
- package/src/capabilities.ts +1 -0
- package/src/client.ts +18 -0
- package/src/server.ts +2 -0
- package/src/thread-review.ts +16 -11
- package/src/validate.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cueloop/daemon",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.95",
|
|
4
4
|
"description": "The cueloop session daemon and its client: socket protocol, atomic store, resumable waits",
|
|
5
5
|
"homepage": "https://github.com/mmurakaru/cueloop#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@cueloop/extension-api": "0.1.0-alpha.
|
|
43
|
-
"@cueloop/schema": "0.1.0-alpha.
|
|
42
|
+
"@cueloop/extension-api": "0.1.0-alpha.95",
|
|
43
|
+
"@cueloop/schema": "0.1.0-alpha.95",
|
|
44
44
|
"@pierre/diffs": "^1.4.1",
|
|
45
45
|
"effect": "^4.0.0-rc.116",
|
|
46
46
|
"smol-toml": "^1.8.0",
|
package/src/api.ts
CHANGED
|
@@ -142,7 +142,10 @@ export class DaemonCore {
|
|
|
142
142
|
*/
|
|
143
143
|
private readonly diffRefreshGenerations = new Map<string, number>();
|
|
144
144
|
/** In-flight workbench creations keyed by project, so concurrent bare launches share one thread. */
|
|
145
|
-
private readonly workbenchCreation = new Map<
|
|
145
|
+
private readonly workbenchCreation = new Map<
|
|
146
|
+
string,
|
|
147
|
+
Promise<{ session: Thread; diff: VcsDiffSnapshot & { vcs: string } }>
|
|
148
|
+
>();
|
|
146
149
|
|
|
147
150
|
constructor(home: string) {
|
|
148
151
|
this.store = new ThreadStore(home);
|
|
@@ -618,8 +621,35 @@ export class DaemonCore {
|
|
|
618
621
|
* first comment without an agent submission. Owner-only.
|
|
619
622
|
*/
|
|
620
623
|
async workbenchSession(cwd: string): Promise<Thread> {
|
|
621
|
-
const
|
|
622
|
-
|
|
624
|
+
const opened = await this.openWorkbench(cwd);
|
|
625
|
+
|
|
626
|
+
return opened.session;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/** Return the workbench and its current diff from one capture. */
|
|
630
|
+
async workbenchReview(
|
|
631
|
+
cwd: string,
|
|
632
|
+
): Promise<{ session: Thread; diff: VcsDiffSnapshot & { vcs: string } }> {
|
|
633
|
+
const opened = await this.openWorkbench(cwd);
|
|
634
|
+
|
|
635
|
+
if (opened.diff) return { session: opened.session, diff: opened.diff };
|
|
636
|
+
|
|
637
|
+
return {
|
|
638
|
+
session: opened.session,
|
|
639
|
+
diff: await this.vcsSources.capture(
|
|
640
|
+
opened.session.workspace.repoRoot,
|
|
641
|
+
opened.session.artifact.meta.vcs,
|
|
642
|
+
),
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
private async openWorkbench(
|
|
647
|
+
cwd: string,
|
|
648
|
+
): Promise<{ session: Thread; diff?: VcsDiffSnapshot & { vcs: string } }> {
|
|
649
|
+
const [selected, workspace] = await Promise.all([
|
|
650
|
+
this.vcsSources.select(cwd),
|
|
651
|
+
resolveWorkspace(cwd),
|
|
652
|
+
]);
|
|
623
653
|
workspace.repoRoot = selected.repoRoot;
|
|
624
654
|
const key = `${workspace.rootCommit ?? selected.repoRoot}:${selected.adapter.id}`;
|
|
625
655
|
// an open workbench is reused; a resolved one is immutable and would reject the note, so a fresh
|
|
@@ -635,13 +665,13 @@ export class DaemonCore {
|
|
|
635
665
|
(session.artifact.meta.vcs ?? "git") === selected.adapter.id,
|
|
636
666
|
);
|
|
637
667
|
|
|
638
|
-
if (open) return open;
|
|
668
|
+
if (open) return { session: open };
|
|
639
669
|
// serialize concurrent bare launches for the same repo onto one creation, so they share a thread
|
|
640
670
|
const inFlight = this.workbenchCreation.get(key);
|
|
641
671
|
|
|
642
672
|
if (inFlight) return inFlight;
|
|
643
|
-
const creation = this.vcsSources.capture(cwd, selected.adapter.id).then((diff) =>
|
|
644
|
-
this.sessionCreate({
|
|
673
|
+
const creation = this.vcsSources.capture(cwd, selected.adapter.id).then((diff) => ({
|
|
674
|
+
session: this.sessionCreate({
|
|
645
675
|
workspace,
|
|
646
676
|
artifact: {
|
|
647
677
|
type: "diff",
|
|
@@ -657,7 +687,8 @@ export class DaemonCore {
|
|
|
657
687
|
},
|
|
658
688
|
},
|
|
659
689
|
}),
|
|
660
|
-
|
|
690
|
+
diff,
|
|
691
|
+
}));
|
|
661
692
|
|
|
662
693
|
this.workbenchCreation.set(key, creation);
|
|
663
694
|
try {
|
package/src/capabilities.ts
CHANGED
|
@@ -47,6 +47,7 @@ const PRIMITIVE_ROLES = {
|
|
|
47
47
|
"repo.changes": "owner",
|
|
48
48
|
"repo.diff": "owner",
|
|
49
49
|
"session.workbench": "owner",
|
|
50
|
+
"session.workbenchReview": "owner",
|
|
50
51
|
// the tree is the owner's: collaborators comment on the branch a share follows
|
|
51
52
|
"session.navigate": "owner",
|
|
52
53
|
"session.branch": "owner",
|
package/src/client.ts
CHANGED
|
@@ -595,6 +595,24 @@ export class DaemonClient implements ThreadClient {
|
|
|
595
595
|
sessionWorkbench(cwd: string): Promise<Thread> {
|
|
596
596
|
return this.request("session.workbench", { cwd }, ThreadRecordSchema);
|
|
597
597
|
}
|
|
598
|
+
/** Open a workbench with the diff snapshot used for its first frame. */
|
|
599
|
+
workbenchReview(cwd: string): Promise<{ session: Thread; diff: WorkingTreeDiff }> {
|
|
600
|
+
return this.request(
|
|
601
|
+
"session.workbenchReview",
|
|
602
|
+
{ cwd },
|
|
603
|
+
v.object({
|
|
604
|
+
session: ThreadRecordSchema,
|
|
605
|
+
diff: v.object({
|
|
606
|
+
patch: v.string(),
|
|
607
|
+
files: v.array(DiffFileContentsSchema),
|
|
608
|
+
vcs: v.string(),
|
|
609
|
+
source: v.optional(
|
|
610
|
+
v.object({ changeId: v.optional(v.string()), revisionId: v.string() }),
|
|
611
|
+
),
|
|
612
|
+
}),
|
|
613
|
+
}),
|
|
614
|
+
);
|
|
615
|
+
}
|
|
598
616
|
/** Re-capture a diff session's working tree; changed=true when the patch moved and an event fired. */
|
|
599
617
|
sessionRefreshDiff(id: string): Promise<{ changed: boolean }> {
|
|
600
618
|
return this.request("session.refreshDiff", { id }, RefreshDiffResultSchema);
|
package/src/server.ts
CHANGED
|
@@ -457,6 +457,8 @@ export class DaemonServer {
|
|
|
457
457
|
},
|
|
458
458
|
"session.workbench": (_connection, request) =>
|
|
459
459
|
this.core.workbenchSession(parseParams("session.workbench", request.params).cwd),
|
|
460
|
+
"session.workbenchReview": (_connection, request) =>
|
|
461
|
+
this.core.workbenchReview(parseParams("session.workbenchReview", request.params).cwd),
|
|
460
462
|
"session.refreshDiff": (_connection, request) => {
|
|
461
463
|
const params = parseParams("session.refreshDiff", request.params);
|
|
462
464
|
|
package/src/thread-review.ts
CHANGED
|
@@ -51,22 +51,27 @@ function earliestRootCommit(revList: string | null): string | undefined {
|
|
|
51
51
|
|
|
52
52
|
/** Workspace key resolution: repo root, branch, and the project identity (root commit + remote) from the cwd. */
|
|
53
53
|
export async function resolveWorkspace(cwd = process.cwd()): Promise<WorkspaceKey> {
|
|
54
|
-
const gitRepoRoot = await
|
|
55
|
-
|
|
54
|
+
const [gitRepoRoot, jjRepoRoot] = await Promise.all([
|
|
55
|
+
git(["rev-parse", "--show-toplevel"], cwd),
|
|
56
|
+
jjRoot(cwd),
|
|
57
|
+
]);
|
|
56
58
|
const nativeJjRoot =
|
|
57
59
|
jjRepoRoot && (!gitRepoRoot || jjRepoRoot.length > gitRepoRoot.length) ? jjRepoRoot : null;
|
|
58
60
|
const repoRoot = nativeJjRoot ?? gitRepoRoot ?? cwd;
|
|
59
|
-
const
|
|
60
|
-
?
|
|
61
|
-
:
|
|
61
|
+
const [gitBranch, isShallow, rootList, gitRemote] = nativeJjRoot
|
|
62
|
+
? [null, null, null, null]
|
|
63
|
+
: await Promise.all([
|
|
64
|
+
git(["rev-parse", "--abbrev-ref", "HEAD"], cwd),
|
|
65
|
+
git(["rev-parse", "--is-shallow-repository"], cwd),
|
|
66
|
+
git(["rev-list", "--max-parents=0", "--date-order", "HEAD"], cwd),
|
|
67
|
+
git(["remote", "get-url", "origin"], cwd),
|
|
68
|
+
]);
|
|
69
|
+
const branch = nativeJjRoot ? "jj" : (gitBranch ?? "detached");
|
|
62
70
|
// a shallow clone's oldest commit is the graft boundary, not the true root, so
|
|
63
71
|
// it would key a different project than a full clone - leave it unset instead
|
|
64
|
-
const shallow =
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
? undefined
|
|
68
|
-
: earliestRootCommit(await git(["rev-list", "--max-parents=0", "--date-order", "HEAD"], cwd));
|
|
69
|
-
const remote = nativeJjRoot ? null : await git(["remote", "get-url", "origin"], cwd);
|
|
72
|
+
const shallow = nativeJjRoot !== null || isShallow === "true";
|
|
73
|
+
const rootCommit = shallow ? undefined : earliestRootCommit(rootList);
|
|
74
|
+
const remote = nativeJjRoot ? null : gitRemote;
|
|
70
75
|
|
|
71
76
|
const workspace: WorkspaceKey = { repoRoot, branch };
|
|
72
77
|
// a repo with no commits (or a shallow clone) has no reliable root, so the thread stays standalone
|
package/src/validate.ts
CHANGED
|
@@ -275,6 +275,7 @@ export const Params = {
|
|
|
275
275
|
"repo.changes": v.object({ cwd: NonEmpty }),
|
|
276
276
|
"repo.diff": v.object({ cwd: NonEmpty, vcs: v.optional(NonEmpty) }),
|
|
277
277
|
"session.workbench": v.object({ cwd: NonEmpty }),
|
|
278
|
+
"session.workbenchReview": v.object({ cwd: NonEmpty }),
|
|
278
279
|
"session.navigate": v.object({
|
|
279
280
|
id: SessionId,
|
|
280
281
|
entryId: NonEmpty,
|