@cueloop/daemon 0.1.0-alpha.76 → 0.1.0-alpha.78

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cueloop/daemon",
3
- "version": "0.1.0-alpha.76",
3
+ "version": "0.1.0-alpha.78",
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": {
@@ -35,7 +35,7 @@
35
35
  "access": "public"
36
36
  },
37
37
  "dependencies": {
38
- "@cueloop/schema": "0.1.0-alpha.76",
38
+ "@cueloop/schema": "0.1.0-alpha.78",
39
39
  "@pierre/diffs": "^1.3.6",
40
40
  "effect": "^4.0.0-rc.115",
41
41
  "valibot": "^1.4.2"
package/src/api.ts CHANGED
@@ -432,6 +432,17 @@ export class DaemonCore {
432
432
  return session;
433
433
  }
434
434
 
435
+ /** Set the private-share allowlist of GitHub logins; presence marks the share private. */
436
+ sessionSetAccess(id: string, githubLogins: string[]): Thread {
437
+ const session = this.mutable(id);
438
+
439
+ session.access = { githubLogins };
440
+ this.store.upsert(session);
441
+ this.emit("session.updated", id);
442
+
443
+ return session;
444
+ }
445
+
435
446
  /** Remove a session for good (inbox delete); resolved or pending, both go. */
436
447
  sessionDelete(id: string): void {
437
448
  const session = this.store.get(id);
@@ -35,6 +35,7 @@ const PRIMITIVE_ROLES = {
35
35
  "session.cutBlock": "owner",
36
36
  "session.restoreBlock": "owner",
37
37
  "session.curate": "owner",
38
+ "session.setAccess": "owner",
38
39
  "session.setViewed": "owner",
39
40
  "session.setTitle": "owner",
40
41
  // reading the local working tree is the owner's alone; a share carries no repo to read
package/src/client.ts CHANGED
@@ -88,6 +88,8 @@ export interface SessionClient {
88
88
  sessionRestoreBlock(id: string, baseBlockIndex: number, line?: number): Promise<Thread>;
89
89
  /** Replace a diff review's reject decisions; the working copy follows. */
90
90
  sessionCurate(id: string, rejections: HunkRejection[]): Promise<Thread>;
91
+ /** Replace the private-share allowlist of GitHub logins; presence marks the share private. */
92
+ sessionSetAccess(id: string, githubLogins: string[]): Promise<Thread>;
91
93
  sessionSetViewed(id: string, viewedPaths: string[]): Promise<Thread>;
92
94
  /** Rename a session's display title; an empty title restores the derived default. */
93
95
  sessionSetTitle(id: string, title: string): Promise<Thread>;
@@ -450,6 +452,9 @@ export class DaemonClient implements SessionClient {
450
452
  sessionCurate(id: string, rejections: HunkRejection[]): Promise<Thread> {
451
453
  return this.request("session.curate", { id, rejections }, ThreadRecordSchema);
452
454
  }
455
+ sessionSetAccess(id: string, githubLogins: string[]): Promise<Thread> {
456
+ return this.request("session.setAccess", { id, githubLogins }, ThreadRecordSchema);
457
+ }
453
458
  sessionSetViewed(id: string, viewedPaths: string[]): Promise<Thread> {
454
459
  return this.request("session.setViewed", { id, viewedPaths }, ThreadRecordSchema);
455
460
  }
package/src/review.ts CHANGED
@@ -196,7 +196,7 @@ export interface AwaitResolveOptions {
196
196
  }
197
197
 
198
198
  /**
199
- * Park until a review session resolves, then return the verdict outcome; null
199
+ * Park until a thread resolves, then return the verdict outcome; null
200
200
  * when the signal aborts first. Where ReviewHandle.awaitVerdict needs the handle
201
201
  * that opened the review, this needs only a session id - so a background waiter
202
202
  * that woke on a session it did not open (a detached Claude Code / Codex waiter,
@@ -220,7 +220,7 @@ export async function awaitResolve(
220
220
  return resolved === null ? null : outcome(resolved);
221
221
  }
222
222
 
223
- /** Open a review session (or revise the agent session's existing one) and hand back the wait surface. */
223
+ /** Open a thread (or revise the agent session's existing one) and hand back the wait surface. */
224
224
  export async function openReview(
225
225
  client: DaemonClient,
226
226
  options: OpenReviewOptions,
package/src/server.ts CHANGED
@@ -385,6 +385,11 @@ export class DaemonServer {
385
385
 
386
386
  return this.core.sessionCurate(params.id, params.rejections);
387
387
  },
388
+ "session.setAccess": (_connection, request) => {
389
+ const params = parseParams("session.setAccess", request.params);
390
+
391
+ return this.core.sessionSetAccess(params.id, params.githubLogins);
392
+ },
388
393
  "session.setViewed": (_connection, request) => {
389
394
  const params = parseParams("session.setViewed", request.params);
390
395
 
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import * as v from "valibot";
2
3
  import { mkdtempSync, rmSync } from "node:fs";
3
4
  import { tmpdir } from "node:os";
4
5
  import { join } from "node:path";
@@ -280,6 +281,7 @@ describe("wire pins", () => {
280
281
  createdAt: "now",
281
282
  shareId: "p_abc123xy",
282
283
  owner: "SHA256:owner",
284
+ access: { githubLogins: ["octocat"] },
283
285
  participants: [fullIdentity],
284
286
  };
285
287
 
@@ -346,3 +348,21 @@ describe("wire pins", () => {
346
348
  }
347
349
  });
348
350
  });
351
+
352
+ describe("IdentitySchema provider", () => {
353
+ test("accepts a verified github identity", () => {
354
+ const parsed = v.safeParse(IdentitySchema, {
355
+ id: "SHA256:abc",
356
+ provider: "github",
357
+ name: "markus",
358
+ });
359
+
360
+ expect(parsed.success).toBe(true);
361
+ });
362
+
363
+ test("rejects an unknown provider", () => {
364
+ const parsed = v.safeParse(IdentitySchema, { id: "SHA256:abc", provider: "email" });
365
+
366
+ expect(parsed.success).toBe(false);
367
+ });
368
+ });
package/src/validate.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  type HunkRejection,
25
25
  type Revision,
26
26
  type SessionHistory,
27
+ type ShareAccess,
27
28
  validateHistory,
28
29
  type Verdict,
29
30
  type WorkspaceKey,
@@ -125,7 +126,7 @@ export const FullAnnotationSchema = v.object({
125
126
 
126
127
  export const IdentitySchema = v.object({
127
128
  id: NonEmpty,
128
- provider: v.literal("ssh"),
129
+ provider: v.picklist(["ssh", "github"]),
129
130
  name: v.optional(v.string()),
130
131
  handle: v.optional(v.string()),
131
132
  } satisfies EntriesOf<Identity>);
@@ -204,6 +205,7 @@ export const Params = {
204
205
  "session.fork": v.object({ id: SessionId }),
205
206
  "session.refreshDiff": v.object({ id: SessionId }),
206
207
  "session.setShareId": v.object({ id: SessionId, shareId: NonEmpty }),
208
+ "session.setAccess": v.object({ id: SessionId, githubLogins: v.array(NonEmpty) }),
207
209
  "session.delete": v.object({ id: SessionId }),
208
210
  "session.mergeShared": v.object({
209
211
  id: SessionId,
@@ -349,6 +351,9 @@ export const ThreadRecordSchema = v.object({
349
351
  shareId: v.optional(v.string()),
350
352
  shareBranch: v.optional(v.string()),
351
353
  owner: v.optional(v.string()),
354
+ access: v.optional(
355
+ v.object({ githubLogins: v.array(NonEmpty) } satisfies EntriesOf<ShareAccess>),
356
+ ),
352
357
  participants: v.optional(v.array(IdentitySchema)),
353
358
  } satisfies EntriesOf<Thread>);
354
359