@gtc6244/immediacy-daemon 0.1.0 → 0.1.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.
Files changed (66) hide show
  1. package/README.md +250 -0
  2. package/dist/src/agent/agent.d.ts +19 -6
  3. package/dist/src/agent/agent.js +3 -1
  4. package/dist/src/agent/agent.js.map +1 -1
  5. package/dist/src/agent/anthropic-probe.d.ts +24 -0
  6. package/dist/src/agent/anthropic-probe.js +81 -0
  7. package/dist/src/agent/anthropic-probe.js.map +1 -0
  8. package/dist/src/agent/claude.d.ts +4 -2
  9. package/dist/src/agent/claude.js +32 -4
  10. package/dist/src/agent/claude.js.map +1 -1
  11. package/dist/src/agent/codex.d.ts +1 -1
  12. package/dist/src/agent/codex.js +26 -3
  13. package/dist/src/agent/codex.js.map +1 -1
  14. package/dist/src/agent/images.d.ts +21 -0
  15. package/dist/src/agent/images.js +54 -0
  16. package/dist/src/agent/images.js.map +1 -0
  17. package/dist/src/agent/mock.d.ts +1 -1
  18. package/dist/src/agent/mock.js +28 -3
  19. package/dist/src/agent/mock.js.map +1 -1
  20. package/dist/src/agent/ollama-probe.d.ts +28 -0
  21. package/dist/src/agent/ollama-probe.js +76 -0
  22. package/dist/src/agent/ollama-probe.js.map +1 -0
  23. package/dist/src/agent/ollama.d.ts +42 -0
  24. package/dist/src/agent/ollama.js +64 -0
  25. package/dist/src/agent/ollama.js.map +1 -0
  26. package/dist/src/agent/openai-probe.d.ts +18 -0
  27. package/dist/src/agent/openai-probe.js +83 -0
  28. package/dist/src/agent/openai-probe.js.map +1 -0
  29. package/dist/src/agent/openrouter-probe.d.ts +21 -0
  30. package/dist/src/agent/openrouter-probe.js +77 -0
  31. package/dist/src/agent/openrouter-probe.js.map +1 -0
  32. package/dist/src/crypto.js +7 -2
  33. package/dist/src/crypto.js.map +1 -1
  34. package/dist/src/index.d.ts +3 -0
  35. package/dist/src/index.js +35 -3
  36. package/dist/src/index.js.map +1 -1
  37. package/dist/src/jobs/scheduler.d.ts +1 -0
  38. package/dist/src/jobs/scheduler.js +1 -0
  39. package/dist/src/jobs/scheduler.js.map +1 -1
  40. package/dist/src/media-watch.d.ts +29 -0
  41. package/dist/src/media-watch.js +108 -0
  42. package/dist/src/media-watch.js.map +1 -0
  43. package/dist/src/media.d.ts +54 -0
  44. package/dist/src/media.js +156 -0
  45. package/dist/src/media.js.map +1 -0
  46. package/dist/src/model-efforts.d.ts +49 -0
  47. package/dist/src/model-efforts.js +107 -0
  48. package/dist/src/model-efforts.js.map +1 -0
  49. package/dist/src/models.d.ts +50 -17
  50. package/dist/src/models.js +119 -21
  51. package/dist/src/models.js.map +1 -1
  52. package/dist/src/projects.d.ts +7 -0
  53. package/dist/src/projects.js +14 -0
  54. package/dist/src/projects.js.map +1 -1
  55. package/dist/src/protocol.d.ts +127 -9
  56. package/dist/src/protocol.js +1 -1
  57. package/dist/src/server.js +105 -5
  58. package/dist/src/server.js.map +1 -1
  59. package/dist/src/types.d.ts +9 -0
  60. package/dist/src/workspace.d.ts +25 -0
  61. package/dist/src/workspace.js +159 -6
  62. package/dist/src/workspace.js.map +1 -1
  63. package/package.json +3 -2
  64. package/dist/src/migrate-state-dir.d.ts +0 -1
  65. package/dist/src/migrate-state-dir.js +0 -47
  66. package/dist/src/migrate-state-dir.js.map +0 -1
@@ -177,6 +177,20 @@ export class ProjectStore {
177
177
  if (this.projects.delete(id))
178
178
  await this.persist();
179
179
  }
180
+ /**
181
+ * Rename a project — display name only. The on-disk managed dir (`slugFor`) is
182
+ * derived from the name at create time and never recomputed, so it is left as
183
+ * is (matching existing behavior). No-op on an unknown id, a blank name, or an
184
+ * unchanged name; persists only when the name actually changes.
185
+ */
186
+ async rename(id, name) {
187
+ const r = this.projects.get(id);
188
+ const next = name.trim();
189
+ if (!r || !next || r.name === next)
190
+ return;
191
+ r.name = next;
192
+ await this.persist();
193
+ }
180
194
  /**
181
195
  * Rewrite the stored project order. `list()` returns projects in Map insertion
182
196
  * order, so we rebuild the Map in the requested order. Unknown ids are ignored;
@@ -1 +1 @@
1
- {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/projects.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/projects.ts"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@
12
12
  * `payload` is encrypted in the E2E layer (slice 5); until then it travels as
13
13
  * plain JSON.
14
14
  */
15
- export declare const PROTOCOL_VERSION: 1;
15
+ export declare const PROTOCOL_VERSION: 2;
16
16
  /** Workspace lifecycle status, surfaced as a badge in the client. */
17
17
  export type WorkspaceStatus = "idle" | "running" | "awaiting_permission" | "done" | "error";
18
18
  /** Generic envelope. `T` is the message `type`; `P` its payload shape. */
@@ -25,9 +25,9 @@ export interface Envelope<T extends MessageType = MessageType> {
25
25
  payload: PayloadFor<T>;
26
26
  }
27
27
  /** Client → daemon. */
28
- export type ClientMessageType = "project.list" | "project.create" | "project.delete" | "project.reorder" | "project.branches" | "project.pulls" | "project.issues" | "issue.create" | "workspace.list" | "workspace.create" | "workspace.delete" | "workspace.archive" | "workspace.action" | "delete.batch" | "prompt.send" | "agent.stop" | "permission.respond" | "question.respond" | "allowlist.list" | "allowlist.revoke" | "allowlist.clear" | "terminal.input" | "terminal.resize" | "terminal.snapshot" | "forward.list" | "forward.open" | "forward.data" | "forward.close" | "git.status" | "git.commit" | "git.push" | "git.resolve" | "git.merge" | "pr.create" | "pr.merge" | "workspace.open" | "diff.get" | "tree.get" | "file.get" | "file.set" | "chat.history" | "github.status" | "github.repos" | "models.list" | "job.list" | "job.create" | "job.update" | "job.delete" | "job.run" | "job.runs" | "settings.get" | "settings.set" | "config.set" | "log.tail" | "hello" | "pair.info" | "daemon.get" | "daemon.rename" | "ping" | "echo";
28
+ export type ClientMessageType = "project.list" | "project.create" | "project.delete" | "project.rename" | "project.reorder" | "project.branches" | "project.pulls" | "project.issues" | "issue.create" | "workspace.list" | "workspace.create" | "workspace.delete" | "workspace.archive" | "workspace.rename" | "workspace.action" | "delete.batch" | "prompt.send" | "agent.stop" | "permission.respond" | "question.respond" | "allowlist.list" | "allowlist.revoke" | "allowlist.clear" | "terminal.input" | "terminal.resize" | "terminal.snapshot" | "forward.list" | "forward.open" | "forward.data" | "forward.close" | "git.status" | "git.commit" | "git.push" | "git.resolve" | "git.merge" | "pr.create" | "pr.merge" | "workspace.open" | "diff.get" | "tree.get" | "file.get" | "file.set" | "media.get" | "chat.history" | "github.status" | "github.repos" | "models.list" | "job.list" | "job.create" | "job.update" | "job.delete" | "job.run" | "job.runs" | "settings.get" | "settings.set" | "config.set" | "log.tail" | "client.hello" | "hello" | "pair.info" | "daemon.get" | "daemon.rename" | "ping" | "echo";
29
29
  /** Daemon → client. */
30
- export type DaemonMessageType = "project.list.result" | "project.branches.result" | "project.pulls.result" | "project.issues.result" | "workspace.list.result" | "workspace.created" | "workspace.renamed" | "delete.batch.result" | "event.assistant_message" | "event.tool_use" | "event.permission_request" | "event.permission_resolved" | "event.ask_question" | "event.session" | "event.agent_done" | "event.session_limit" | "terminal.data" | "terminal.snapshot.result" | "forward.available" | "git.status.result" | "git.result" | "diff.result" | "tree.result" | "file.result" | "file.saved" | "chat.history.result" | "github.status.result" | "github.repos.result" | "models.list.result" | "job.list.result" | "job.runs.result" | "event.job_run" | "settings.result" | "allowlist.result" | "log.tail.result" | "log.event" | "hello.ok" | "pair.info.result" | "daemon.info" | "pong" | "error" | "echo.result";
30
+ export type DaemonMessageType = "project.list.result" | "project.branches.result" | "project.pulls.result" | "project.issues.result" | "workspace.list.result" | "workspace.created" | "workspace.renamed" | "delete.batch.result" | "event.assistant_message" | "event.assistant_image" | "event.tool_use" | "event.permission_request" | "event.permission_resolved" | "event.ask_question" | "event.question_resolved" | "event.session" | "event.agent_done" | "event.session_limit" | "terminal.data" | "terminal.snapshot.result" | "forward.available" | "git.status.result" | "git.result" | "diff.result" | "tree.result" | "file.result" | "file.saved" | "media.result" | "chat.history.result" | "github.status.result" | "github.repos.result" | "models.list.result" | "job.list.result" | "job.runs.result" | "event.job_run" | "settings.result" | "allowlist.result" | "log.tail.result" | "log.event" | "hello.ok" | "pair.info.result" | "daemon.info" | "pong" | "error" | "echo.result";
31
31
  export type MessageType = ClientMessageType | DaemonMessageType;
32
32
  export interface ProjectListPayload {
33
33
  }
@@ -112,6 +112,11 @@ export interface WorkspaceCreatePayload {
112
112
  initialPrompt?: string;
113
113
  /** Model id from the catalog (see models.list); omitted → daemon default. */
114
114
  model?: string;
115
+ /**
116
+ * Reasoning-effort id for the chosen model (one of its `efforts`); omitted
117
+ * when the model has no effort knob or the client left it at the default.
118
+ */
119
+ effort?: string;
115
120
  }
116
121
  /** Request the branches a new worktree can be based on, for one project. */
117
122
  export interface ProjectBranchesPayload {
@@ -149,6 +154,11 @@ export interface WorkspaceDeletePayload {
149
154
  export interface WorkspaceArchivePayload {
150
155
  ws: string;
151
156
  }
157
+ /** Rename a workspace's sidebar label (display name only). */
158
+ export interface WorkspaceRenamePayload {
159
+ ws: string;
160
+ name: string;
161
+ }
152
162
  /**
153
163
  * A prompt-backed agent action. Each kind maps to a built-in base instruction
154
164
  * plus the matching `prompts.*` custom text (see AppConfig): `code_review` →
@@ -380,6 +390,11 @@ export interface FileGetPayload {
380
390
  ws: string;
381
391
  path: string;
382
392
  }
393
+ /** Fetch the bytes of an agent-produced image by id (see event.assistant_image). */
394
+ export interface MediaGetPayload {
395
+ ws: string;
396
+ id: string;
397
+ }
383
398
  /** Write new UTF-8 contents to one worktree-relative file (in-app editor save). */
384
399
  export interface FileSetPayload {
385
400
  ws: string;
@@ -399,6 +414,21 @@ export interface PingPayload {
399
414
  export interface EchoPayload {
400
415
  text: string;
401
416
  }
417
+ /**
418
+ * Client → daemon: the version handshake, sent as the client's first app-level
419
+ * frame right after it connects. The mirror of the daemon's `daemon.info`: it
420
+ * lets the daemon compare the client's `PROTOCOL_VERSION` to its own and warn
421
+ * (in the log) on a skew. A mismatch never rejects the connection — the two may
422
+ * still interoperate — it only surfaces a heads-up on both ends.
423
+ */
424
+ export interface ClientHelloPayload {
425
+ /** The PROTOCOL_VERSION this client speaks (compared to the daemon's). */
426
+ protocolVersion: number;
427
+ /** The client's release version (display/diagnostics only); may be empty. */
428
+ version?: string;
429
+ /** Optional human label for the client kind (e.g. "phone", "web", "macOS"). */
430
+ label?: string;
431
+ }
402
432
  /**
403
433
  * A registered project: one repo, the group worktrees hang under in the
404
434
  * sidebar. Persists even with zero worktrees so it stays a stable "+ new
@@ -499,6 +529,8 @@ export interface WorkspaceSummary {
499
529
  kind?: "worktree" | "chat";
500
530
  /** Model id backing this workspace's agent (see models.list). */
501
531
  model?: string;
532
+ /** Reasoning-effort id backing this workspace's agent (see the model's `efforts`). */
533
+ effort?: string;
502
534
  /** Lines added vs the base branch (uncommitted + committed); omitted if 0. */
503
535
  added?: number;
504
536
  /** Lines removed vs the base branch; omitted if 0. */
@@ -513,13 +545,34 @@ export interface WorkspaceSummary {
513
545
  repoUrl?: string;
514
546
  }
515
547
  /** Which agent backend runs a model. */
516
- export type ModelProvider = "claude" | "codex" | "openrouter";
548
+ export type ModelProvider = "claude" | "codex" | "openrouter" | "ollama";
549
+ /**
550
+ * One reasoning-effort level a model can run at (e.g. Claude's
551
+ * low/medium/high/xhigh/max, or a Codex/GPT reasoning effort). `id` is the exact
552
+ * token handed to the backend; `label` is the human-readable name.
553
+ */
554
+ export interface ModelEffort {
555
+ id: string;
556
+ label: string;
557
+ }
517
558
  /** One selectable model, surfaced to the client via models.list.result. */
518
559
  export interface ModelInfo {
519
560
  id: string;
520
561
  label: string;
521
562
  provider: ModelProvider;
522
563
  default?: boolean;
564
+ /**
565
+ * Reasoning-effort levels this model supports, in ascending order. Omitted or
566
+ * empty when the model has no effort knob (the client shows no effort picker).
567
+ */
568
+ efforts?: ModelEffort[];
569
+ /** Effort id preselected when this model is chosen (one of `efforts`). */
570
+ defaultEffort?: string;
571
+ /**
572
+ * When the model was released, ISO-8601 (from the provider's model API). Used
573
+ * only for the 12-month discovery window / display; absent for Ollama.
574
+ */
575
+ released?: string;
523
576
  }
524
577
  export interface ModelsListResultPayload {
525
578
  models: ModelInfo[];
@@ -648,6 +701,22 @@ export interface EventAssistantMessagePayload {
648
701
  ws: string;
649
702
  text: string;
650
703
  }
704
+ /**
705
+ * An agent-produced image was surfaced. Metadata only — the bytes are fetched
706
+ * on demand via `media.get` (`id` is the content hash / stable cache key). Kept
707
+ * out of the event so multi-MB screenshots don't bloat broadcasts or the E2E
708
+ * channel. `source` distinguishes an image returned by a tool from one the
709
+ * agent wrote into the worktree (`name` is then its relative path).
710
+ */
711
+ export interface EventAssistantImagePayload {
712
+ ws: string;
713
+ id: string;
714
+ name: string;
715
+ mediaType: string;
716
+ size: number;
717
+ source: "tool" | "file";
718
+ tool?: string;
719
+ }
651
720
  export interface EventToolUsePayload {
652
721
  ws: string;
653
722
  tool: string;
@@ -660,16 +729,31 @@ export interface EventPermissionRequestPayload {
660
729
  inputSummary: string;
661
730
  }
662
731
  /**
663
- * A previously-broadcast permission request was resolved without the client
664
- * answering it — a new "allow all" rule retroactively covered it — so clients
665
- * collapse its card. Emitted by the retroactive-release sweep (see
666
- * ClaudeAgent.releaseCoveredPending).
732
+ * A previously-broadcast permission request was resolved. Broadcast to ALL
733
+ * clients whenever a decision lands — whether a user answered it here
734
+ * (allow/deny/allow_all), or a new "allow all" rule retroactively covered it
735
+ * (see ClaudeAgent.releaseCoveredPending). Clients collapse the matching card
736
+ * and disable its controls so a request answered on one device becomes
737
+ * non-actionable everywhere. Idempotent: resolving an already-resolved card is
738
+ * a no-op on every client.
667
739
  */
668
740
  export interface EventPermissionResolvedPayload {
669
741
  ws: string;
670
742
  requestId: string;
671
743
  decision: "allow" | "deny";
672
744
  }
745
+ /**
746
+ * A previously-broadcast question (see event.ask_question) was answered on some
747
+ * device. Broadcast to ALL clients so stale question cards on other devices
748
+ * collapse into their answered summary and can no longer be submitted twice.
749
+ * Idempotent on every client.
750
+ */
751
+ export interface EventQuestionResolvedPayload {
752
+ ws: string;
753
+ requestId: string;
754
+ answers: QuestionAnswers;
755
+ response?: string;
756
+ }
673
757
  /**
674
758
  * The model asked one or more clarifying questions via `AskUserQuestion`. The
675
759
  * client renders an interactive card and replies with `question.respond`
@@ -825,7 +909,7 @@ export interface GitResultPayload {
825
909
  url?: string;
826
910
  }
827
911
  /** Role of a persisted transcript entry — mirrors the client's ChatRole. */
828
- export type ChatEntryRole = "user" | "assistant" | "tool" | "permission" | "question" | "limit" | "system";
912
+ export type ChatEntryRole = "user" | "assistant" | "assistant_image" | "tool" | "permission" | "question" | "limit" | "system";
829
913
  /**
830
914
  * One durable line in a workspace's transcript. The daemon appends these to a
831
915
  * per-workspace running log as prompts and events flow, so the whole
@@ -848,12 +932,26 @@ export interface ChatEntry {
848
932
  * an "📎 name" chip on replay without carrying the payload in the log.
849
933
  */
850
934
  attachments?: ChatAttachmentMeta[];
935
+ /**
936
+ * assistant_image-only: reference to an agent-produced image persisted in the
937
+ * media store. Only metadata is kept in the transcript (never the bytes); the
938
+ * client fetches bytes via `media.get` on replay, keyed by the content-hash id.
939
+ */
940
+ media?: ChatMediaMeta;
851
941
  }
852
942
  /** Lightweight attachment descriptor persisted in the transcript (no bytes). */
853
943
  export interface ChatAttachmentMeta {
854
944
  name: string;
855
945
  mediaType: string;
856
946
  }
947
+ /** Reference to a stored agent-produced image, persisted in the transcript. */
948
+ export interface ChatMediaMeta {
949
+ id: string;
950
+ name: string;
951
+ mediaType: string;
952
+ size: number;
953
+ source: "tool" | "file";
954
+ }
857
955
  export interface ChatHistoryResultPayload {
858
956
  ws: string;
859
957
  entries: ChatEntry[];
@@ -883,6 +981,18 @@ export interface FileResultPayload {
883
981
  truncated: boolean;
884
982
  binary: boolean;
885
983
  }
984
+ /**
985
+ * Bytes for an agent-produced image, in reply to `media.get`. `data` is base64
986
+ * (no data: URI prefix); `notFound` marks a missing/evicted id so the client can
987
+ * drop the reference instead of retrying.
988
+ */
989
+ export interface MediaResultPayload {
990
+ ws: string;
991
+ id: string;
992
+ mediaType: string;
993
+ data: string;
994
+ notFound?: boolean;
995
+ }
886
996
  /** Acknowledges a successful in-app editor save (file.set). */
887
997
  export interface FileSavedPayload {
888
998
  ws: string;
@@ -1008,6 +1118,8 @@ export interface EphemeralTarget {
1008
1118
  };
1009
1119
  branchBase?: string;
1010
1120
  model?: string;
1121
+ /** Reasoning-effort id for the ephemeral workspace's model (see model `efforts`). */
1122
+ effort?: string;
1011
1123
  /** Base name for the throwaway workspace (defaults to the job name). */
1012
1124
  name?: string;
1013
1125
  }
@@ -1132,6 +1244,7 @@ export interface PayloadMap {
1132
1244
  "workspace.create": WorkspaceCreatePayload;
1133
1245
  "workspace.delete": WorkspaceDeletePayload;
1134
1246
  "workspace.archive": WorkspaceArchivePayload;
1247
+ "workspace.rename": WorkspaceRenamePayload;
1135
1248
  "workspace.action": WorkspaceActionPayload;
1136
1249
  "delete.batch": DeleteBatchPayload;
1137
1250
  "prompt.send": PromptSendPayload;
@@ -1160,6 +1273,7 @@ export interface PayloadMap {
1160
1273
  "tree.get": TreeGetPayload;
1161
1274
  "file.get": FileGetPayload;
1162
1275
  "file.set": FileSetPayload;
1276
+ "media.get": MediaGetPayload;
1163
1277
  "chat.history": ChatHistoryPayload;
1164
1278
  "github.status": GithubStatusPayload;
1165
1279
  "github.repos": GithubReposPayload;
@@ -1174,6 +1288,7 @@ export interface PayloadMap {
1174
1288
  "settings.set": SettingsSetPayload;
1175
1289
  "config.set": ConfigSetPayload;
1176
1290
  "log.tail": LogTailPayload;
1291
+ "client.hello": ClientHelloPayload;
1177
1292
  hello: HelloPayload;
1178
1293
  "pair.info": PairInfoPayload;
1179
1294
  "daemon.get": DaemonGetPayload;
@@ -1189,10 +1304,12 @@ export interface PayloadMap {
1189
1304
  "workspace.renamed": WorkspaceRenamedPayload;
1190
1305
  "delete.batch.result": DeleteBatchResultPayload;
1191
1306
  "event.assistant_message": EventAssistantMessagePayload;
1307
+ "event.assistant_image": EventAssistantImagePayload;
1192
1308
  "event.tool_use": EventToolUsePayload;
1193
1309
  "event.permission_request": EventPermissionRequestPayload;
1194
1310
  "event.permission_resolved": EventPermissionResolvedPayload;
1195
1311
  "event.ask_question": EventAskQuestionPayload;
1312
+ "event.question_resolved": EventQuestionResolvedPayload;
1196
1313
  "event.session": EventSessionPayload;
1197
1314
  "event.agent_done": EventAgentDonePayload;
1198
1315
  "event.session_limit": EventSessionLimitPayload;
@@ -1205,6 +1322,7 @@ export interface PayloadMap {
1205
1322
  "tree.result": TreeResultPayload;
1206
1323
  "file.result": FileResultPayload;
1207
1324
  "file.saved": FileSavedPayload;
1325
+ "media.result": MediaResultPayload;
1208
1326
  "chat.history.result": ChatHistoryResultPayload;
1209
1327
  "github.status.result": GithubStatusResultPayload;
1210
1328
  "github.repos.result": GithubReposResultPayload;
@@ -12,5 +12,5 @@
12
12
  * `payload` is encrypted in the E2E layer (slice 5); until then it travels as
13
13
  * plain JSON.
14
14
  */
15
- export const PROTOCOL_VERSION = 1;
15
+ export const PROTOCOL_VERSION = 2;
16
16
  //# sourceMappingURL=protocol.js.map
@@ -12,6 +12,7 @@ import { stat } from "node:fs/promises";
12
12
  import { fileURLToPath } from "node:url";
13
13
  import { dirname, extname, join, normalize, resolve, sep } from "node:path";
14
14
  import { WebSocketServer } from "ws";
15
+ import { PROTOCOL_VERSION } from "./protocol.js";
15
16
  import { make, ProtocolError } from "./envelope.js";
16
17
  import { addPeer, boxCodec, isValidPublicKeyB64 } from "./crypto.js";
17
18
  import { Hub } from "./hub.js";
@@ -27,7 +28,7 @@ import { SystemEvents } from "./events.js";
27
28
  import { JobStore } from "./jobs/store.js";
28
29
  import { JobScheduler } from "./jobs/scheduler.js";
29
30
  import { status as githubStatus, listRepos } from "./github.js";
30
- import { MODELS, DEFAULT_MODEL } from "./models.js";
31
+ import { allModels, defaultModel, refreshAllModels } from "./models.js";
31
32
  import { logger } from "./log.js";
32
33
  const startedAt = Date.now();
33
34
  /**
@@ -101,6 +102,42 @@ async function serveStatic(reqUrl, method, res) {
101
102
  return false;
102
103
  }
103
104
  }
105
+ /**
106
+ * Serve agent-produced image bytes at `/media/<ws>/<id>` with immutable caching.
107
+ * The id is the content hash, so a cached response is valid forever. Bounds are
108
+ * enforced by the MediaStore (id must be sha256 hex; ws is traversal-guarded).
109
+ */
110
+ async function serveMedia(reqUrl, method, res, workspaces) {
111
+ let pathname;
112
+ try {
113
+ pathname = decodeURIComponent(new URL(reqUrl, "http://localhost").pathname);
114
+ }
115
+ catch {
116
+ res.writeHead(400).end();
117
+ return;
118
+ }
119
+ const parts = pathname.split("/").filter(Boolean); // ["media", <ws>, <id>]
120
+ if (parts.length !== 3 || parts[0] !== "media") {
121
+ res.writeHead(404, { "cache-control": "no-store" }).end();
122
+ return;
123
+ }
124
+ const bytes = await workspaces.getMedia(parts[1], parts[2]).catch(() => null);
125
+ if (!bytes) {
126
+ res.writeHead(404, { "cache-control": "no-store" }).end();
127
+ return;
128
+ }
129
+ const buf = Buffer.from(bytes.data, "base64");
130
+ res.writeHead(200, {
131
+ "content-type": bytes.mediaType || "application/octet-stream",
132
+ "content-length": buf.length,
133
+ "cache-control": "public, max-age=31536000, immutable",
134
+ });
135
+ if (method === "HEAD") {
136
+ res.end();
137
+ return;
138
+ }
139
+ res.end(buf);
140
+ }
104
141
  export async function startServer(opts) {
105
142
  // E2E on ⇒ require a sealed channel before fanning broadcasts to a socket, so
106
143
  // an un-handshaked device can't be sent cleartext payloads over the tunnel.
@@ -128,7 +165,10 @@ export async function startServer(opts) {
128
165
  await allowlist.load();
129
166
  // Default chatlog (2nd arg undefined → its default) + event bus + credentials
130
167
  // + app config + allowlist.
131
- const workspaces = new WorkspaceManager(hub, undefined, events, undefined, credentials, appConfig, allowlist);
168
+ const workspaces = new WorkspaceManager(hub, undefined, // chatlog → default
169
+ undefined, // media → default
170
+ events, undefined, // projects → default
171
+ credentials, appConfig, allowlist);
132
172
  await workspaces.load();
133
173
  // Cron/scheduled jobs. The scheduler drives runs through the WorkspaceManager
134
174
  // (which structurally satisfies its JobRunnerHost) and listens on the same
@@ -170,6 +210,14 @@ export async function startServer(opts) {
170
210
  res.end(body);
171
211
  return;
172
212
  }
213
+ // Agent-produced image bytes for the web client: same-origin, Access-cookie
214
+ // authorized, and immutably cacheable (the id is the content hash, so the URL
215
+ // never changes meaning). E2E clients use the sealed `media.get` WS path
216
+ // instead; this endpoint is the web app's simpler, natively-cached route.
217
+ if ((req.method === "GET" || req.method === "HEAD") && req.url?.startsWith("/media/")) {
218
+ void serveMedia(req.url, req.method, res, workspaces);
219
+ return;
220
+ }
173
221
  // Serve the browser client (webApp/) on GET/HEAD from the same origin the
174
222
  // tunnel dials, so the Access cookie authorizes both the page and its WS.
175
223
  if ((req.method === "GET" || req.method === "HEAD") && req.url) {
@@ -314,6 +362,25 @@ async function handleFrame(socket, raw, connId, crypto, hub, workspaces, jobs, c
314
362
  const reply = (env2) => hub.send(socket, env2);
315
363
  try {
316
364
  switch (env.type) {
365
+ case "client.hello": {
366
+ // Version handshake (mirror of the daemon.info the daemon pushes back).
367
+ // The client reports the protocol version it speaks; we compare it to
368
+ // ours and warn on a skew. A mismatch is a heads-up, never fatal — the
369
+ // socket keeps serving — so there is no reply frame and no reject.
370
+ const p = env.payload;
371
+ const clientProto = typeof p.protocolVersion === "number" ? p.protocolVersion : undefined;
372
+ const clientVersion = typeof p.version === "string" ? p.version : undefined;
373
+ const label = typeof p.label === "string" ? p.label : undefined;
374
+ if (clientProto !== undefined && clientProto !== PROTOCOL_VERSION) {
375
+ logger.warn("conn", `client protocol v${clientProto} does not match daemon v${PROTOCOL_VERSION} — some features may misbehave`, { data: { clientProtocol: clientProto, daemonProtocol: PROTOCOL_VERSION, clientVersion, label } });
376
+ }
377
+ else {
378
+ logger.info("conn", "client handshake", {
379
+ data: { protocolVersion: clientProto, clientVersion, label },
380
+ });
381
+ }
382
+ return;
383
+ }
317
384
  case "hello": {
318
385
  // Multi-device pairing handshake. The client announces its public key
319
386
  // (cleartext, but already inside the Access-authenticated tunnel — the
@@ -394,6 +461,16 @@ async function handleFrame(socket, raw, connId, crypto, hub, workspaces, jobs, c
394
461
  hub.broadcast("project.list.result", null, { projects: await projects(workspaces) });
395
462
  return;
396
463
  }
464
+ case "project.rename": {
465
+ const p = env.payload;
466
+ if (!p.id || !p.name?.trim()) {
467
+ reply(make("error", null, { code: "bad_args", message: "id and name are required" }));
468
+ return;
469
+ }
470
+ await workspaces.renameProject(p.id, p.name);
471
+ hub.broadcast("project.list.result", null, { projects: await projects(workspaces) });
472
+ return;
473
+ }
397
474
  case "project.reorder": {
398
475
  const p = env.payload;
399
476
  const ids = Array.isArray(p.ids)
@@ -472,9 +549,13 @@ async function handleFrame(socket, raw, connId, crypto, hub, workspaces, jobs, c
472
549
  void workspaces.syncAllReposAndRefresh();
473
550
  return;
474
551
  case "models.list":
552
+ // Re-probe every provider (TTL-cached) so newly-available online models
553
+ // and freshly-pulled local Ollama models appear without a daemon
554
+ // restart; never blocks longer than the probe timeouts.
555
+ await refreshAllModels(credentials);
475
556
  reply(make("models.list.result", null, {
476
- models: MODELS,
477
- defaultModel: DEFAULT_MODEL.id,
557
+ models: allModels(),
558
+ defaultModel: defaultModel().id,
478
559
  }));
479
560
  return;
480
561
  case "workspace.create": {
@@ -482,7 +563,7 @@ async function handleFrame(socket, raw, connId, crypto, hub, workspaces, jobs, c
482
563
  // A chat is repo-less: no project/repo/github required — the daemon
483
564
  // spins up a private scratch dir instead of a worktree.
484
565
  if (p.kind === "chat") {
485
- await workspaces.createChat({ model: p.model });
566
+ await workspaces.createChat({ model: p.model, effort: p.effort });
486
567
  await workspaces.broadcastWorkspaceList();
487
568
  return;
488
569
  }
@@ -500,6 +581,7 @@ async function handleFrame(socket, raw, connId, crypto, hub, workspaces, jobs, c
500
581
  sourcePr: p.sourcePr,
501
582
  initialPrompt: p.initialPrompt,
502
583
  model: p.model,
584
+ effort: p.effort,
503
585
  });
504
586
  // Broadcast fresh lists so every client converges. Projects too: the
505
587
  // legacy bare-repo path may have just registered a new one.
@@ -539,6 +621,12 @@ async function handleFrame(socket, raw, connId, crypto, hub, workspaces, jobs, c
539
621
  await workspaces.broadcastWorkspaceList();
540
622
  return;
541
623
  }
624
+ case "workspace.rename": {
625
+ const p = env.payload;
626
+ if (p.ws && typeof p.name === "string")
627
+ await workspaces.rename(p.ws, p.name);
628
+ return;
629
+ }
542
630
  case "workspace.action": {
543
631
  const p = env.payload;
544
632
  if (!p.ws || !isWorkspaceActionKind(p.kind)) {
@@ -809,6 +897,18 @@ async function handleFrame(socket, raw, connId, crypto, hub, workspaces, jobs, c
809
897
  reply(make("file.result", p.ws, { ws: p.ws, ...file }));
810
898
  return;
811
899
  }
900
+ case "media.get": {
901
+ const p = env.payload;
902
+ if (!p.ws || typeof p.id !== "string")
903
+ return;
904
+ const bytes = await workspaces.getMedia(p.ws, p.id);
905
+ if (!bytes) {
906
+ reply(make("media.result", p.ws, { ws: p.ws, id: p.id, mediaType: "", data: "", notFound: true }));
907
+ return;
908
+ }
909
+ reply(make("media.result", p.ws, { ws: p.ws, id: p.id, ...bytes }));
910
+ return;
911
+ }
812
912
  case "file.set": {
813
913
  const p = env.payload;
814
914
  if (!p.ws || typeof p.path !== "string" || typeof p.content !== "string")