@cueloop/daemon 0.1.0-alpha.103 → 0.1.0-alpha.104

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.103",
3
+ "version": "0.1.0-alpha.104",
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": {
@@ -44,8 +44,8 @@
44
44
  "access": "public"
45
45
  },
46
46
  "dependencies": {
47
- "@cueloop/extension-api": "0.1.0-alpha.103",
48
- "@cueloop/schema": "0.1.0-alpha.103",
47
+ "@cueloop/extension-api": "0.1.0-alpha.104",
48
+ "@cueloop/schema": "0.1.0-alpha.104",
49
49
  "@pierre/diffs": "^1.5.1",
50
50
  "effect": "^4.0.0",
51
51
  "smol-toml": "^1.9.0",
package/src/api.ts CHANGED
@@ -32,7 +32,6 @@ import {
32
32
  isBlockCut,
33
33
  restoreBlock,
34
34
  switchBranch,
35
- messageAllows,
36
35
  type Annotation,
37
36
  type DiffFileStatus,
38
37
  type DiffFileContents,
@@ -74,6 +73,8 @@ import { resolveWorkspace } from "./thread-review";
74
73
  import { VcsSourceManager } from "./vcs-source";
75
74
  import { DaemonError } from "./errors";
76
75
 
76
+ export { messageResponse } from "./thread-review";
77
+
77
78
  /** Reviewer-controlled fields that make an annotation new or edited for delivery. */
78
79
  function annotationDeliveryFingerprint(annotation: Annotation | undefined): string {
79
80
  if (!annotation) return "";
@@ -1590,10 +1591,3 @@ function isPrReviewSession(session: Thread): boolean {
1590
1591
  session.artifact.meta.pr !== undefined
1591
1592
  );
1592
1593
  }
1593
-
1594
- /** Convenience for adapters: map a resolved session to the agent contract. */
1595
- export function messageResponse(session: Thread) {
1596
- if (!session.message) throw new DaemonError("pending", "session has no message");
1597
-
1598
- return { allow: messageAllows(session.message.outcome), message: session.message };
1599
- }
package/src/client.ts CHANGED
@@ -129,6 +129,7 @@ export interface ThreadClient {
129
129
  sessionCurate(id: string, rejections: HunkRejection[]): Promise<Thread>;
130
130
  sessionSetViewed(id: string, viewedPaths: string[]): Promise<Thread>;
131
131
  sessionSetTitle(id: string, title: string): Promise<Thread>;
132
+ agentGet?(id: string): Promise<ThreadAgentState>;
132
133
  projectFiles?(sessionId: string): Promise<string[]>;
133
134
  fileContents?(sessionId: string, path: string): Promise<string | null>;
134
135
  repoFiles?(cwd: string): Promise<string[]>;
@@ -119,3 +119,24 @@ describe("unpack rejects bad input", () => {
119
119
  expect(() => unpackSessionBlob(notASession)).toThrow(/not a valid session/i);
120
120
  });
121
121
  });
122
+
123
+ test("shared conversations survive blob validation and malformed snapshots are rejected", () => {
124
+ const thread = core.sessionCreate({ workspace: WS, artifact: { ...PLAN, content: "" } });
125
+ const shared = {
126
+ ...thread,
127
+ agentSnapshot: {
128
+ threadId: thread.id,
129
+ phase: { kind: "idle" as const },
130
+ tools: [],
131
+ comments: [],
132
+ messages: [
133
+ { id: "reply", role: "agent" as const, text: "Visible reply", revision: 1, complete: true },
134
+ ],
135
+ },
136
+ };
137
+
138
+ expect(unpackSessionBlob(packSessionBlob(shared)).agentSnapshot).toEqual(shared.agentSnapshot);
139
+ expect(() =>
140
+ unpackSessionBlob(gzipSync(JSON.stringify({ ...shared, agentSnapshot: { messages: "bad" } }))),
141
+ ).toThrow("not a valid session");
142
+ });
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  isMarkdownArtifact,
3
+ messageAllows,
3
4
  newAnnotationId,
4
5
  type Annotation,
5
6
  type Artifact,
@@ -12,13 +13,16 @@ import {
12
13
  } from "@cueloop/schema";
13
14
  import { execFile } from "node:child_process";
14
15
  import { promisify } from "node:util";
15
- import { messageResponse } from "./api";
16
+ import { DaemonError } from "./errors";
16
17
  import { ABORTED, pollUntilResolved, raceAbort } from "./interruptible-wait";
17
18
  import { VcsSourceManager } from "./vcs-source";
18
19
 
19
- // Adapters and CLI primitives reach the message mapping through this module too,
20
- // so a session obtained outside a ReviewHandle maps the same way.
21
- export { messageResponse };
20
+ /** Map a resolved session to the agent message contract. */
21
+ export function messageResponse(session: Thread) {
22
+ if (!session.message) throw new DaemonError("pending", "session has no message");
23
+
24
+ return { allow: messageAllows(session.message.outcome), message: session.message };
25
+ }
22
26
 
23
27
  async function git(args: string[], cwd: string): Promise<string | null> {
24
28
  try {
@@ -293,6 +293,13 @@ describe("wire pins", () => {
293
293
  handle: "abc",
294
294
  };
295
295
  const fullSession: Required<Thread> = {
296
+ agentSnapshot: {
297
+ threadId: "ses_1",
298
+ phase: { kind: "idle" },
299
+ messages: [],
300
+ comments: [],
301
+ tools: [],
302
+ },
296
303
  schemaVersion: SCHEMA_VERSION,
297
304
  id: "ses_1",
298
305
  workspace: fullWorkspace,
package/src/validate.ts CHANGED
@@ -10,6 +10,7 @@
10
10
  */
11
11
 
12
12
  import * as v from "valibot";
13
+ import { ThreadAgentSchema } from "./thread-agent-validation";
13
14
  import {
14
15
  ARTIFACT_TYPES,
15
16
  MESSAGE_OUTCOMES,
@@ -517,6 +518,7 @@ export const ThreadRecordSchema = v.pipe(
517
518
  parentSessionId: v.optional(v.string()),
518
519
  shares: v.optional(v.array(ShareLinkSchema)),
519
520
  participants: v.optional(v.array(IdentitySchema)),
521
+ agentSnapshot: v.optional(ThreadAgentSchema),
520
522
  } satisfies EntriesOf<Thread>),
521
523
  v.rawCheck(({ dataset, addIssue }) => {
522
524
  if (!dataset.typed || !dataset.value.textCuts?.length) return;