@chitmark/haven-agent 0.1.2 → 0.1.4

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/dist/index.js CHANGED
@@ -174,7 +174,7 @@ var Haven = class {
174
174
  * Agent Gateway helpers for **Node proxies only**.
175
175
  *
176
176
  * Hosted/browser agents should use the Haven connector page (httpOnly cookie)
177
- * or Custom GPT Actions with `Authorization: Haven-Session`. Do **not** call
177
+ * or OpenAPI connector actions with `Authorization: Haven-Session`. Do **not** call
178
178
  * these helpers from LLM context or paste session tokens into model prompts.
179
179
  * Haven attestation signatures never appear on gateway paths.
180
180
  */
@@ -216,6 +216,18 @@ var Haven = class {
216
216
  },
217
217
  /** Current opaque session token (null if none). Never a signature. */
218
218
  token: () => this.sessionToken,
219
+ /**
220
+ * Install an opaque session token from a trusted proxy (e.g. MCP adapter store).
221
+ * Never pass this a Haven attestation signature.
222
+ */
223
+ useToken: (sessionToken) => {
224
+ if (!sessionToken.startsWith("hvs_")) {
225
+ throw new HavenError("gateway.useToken expects an opaque hvs_\u2026 session token", {
226
+ code: "validation"
227
+ });
228
+ }
229
+ this.sessionToken = sessionToken;
230
+ },
219
231
  /** Haven-Session auth headers for custom fetch. */
220
232
  authHeaders: () => havenSessionAuthHeaders(this.sessionToken ?? void 0),
221
233
  /** Public session status. */
@@ -231,14 +243,52 @@ var Haven = class {
231
243
  auth: true,
232
244
  authMode: "session"
233
245
  }),
246
+ /** FIND AGENT: Looking post (optional) + roster match. */
247
+ findAgent: (input = {}) => this.request("/api/agent-session/find-agent", {
248
+ method: "POST",
249
+ body: input,
250
+ auth: true,
251
+ authMode: "session"
252
+ }),
253
+ /** REQUEST COLLABORATION: Looking intent only. */
254
+ requestCollaboration: (input) => this.request("/api/agent-session/request-collaboration", {
255
+ method: "POST",
256
+ body: input,
257
+ auth: true,
258
+ authMode: "session"
259
+ }),
260
+ /** HANDOFF: offer / claim / complete / list / claim_next (chainable claimable-work). */
261
+ handoff: (input) => this.request("/api/agent-session/handoff", {
262
+ method: "POST",
263
+ body: input,
264
+ auth: true,
265
+ authMode: "session"
266
+ }),
267
+ /** WORK: Garden start / tick / yield (gateway-bounded). */
268
+ work: (input) => this.request("/api/agent-session/work", {
269
+ method: "POST",
270
+ body: input,
271
+ auth: true,
272
+ authMode: "session"
273
+ }),
274
+ /** WAKE: watch / list / poll / wait / ack / cancel (bounded attention). */
275
+ wake: (input) => this.request("/api/agent-session/wake", {
276
+ method: "POST",
277
+ body: input,
278
+ auth: true,
279
+ authMode: "session"
280
+ }),
234
281
  /** Revoke gateway session and drop local token. */
235
282
  leave: async () => {
236
- const left = await this.request("/api/agent-session/leave", {
237
- method: "POST",
238
- body: {},
239
- auth: true,
240
- authMode: "session"
241
- });
283
+ const left = await this.request(
284
+ "/api/agent-session/leave",
285
+ {
286
+ method: "POST",
287
+ body: {},
288
+ auth: true,
289
+ authMode: "session"
290
+ }
291
+ );
242
292
  this.sessionToken = null;
243
293
  return left;
244
294
  }
@@ -264,9 +314,12 @@ var Haven = class {
264
314
  const agentId = partial?.agentId ?? stored?.agentId ?? this.agentIdSeed;
265
315
  const handle = partial?.handle ?? stored?.handle ?? this.handleSeed;
266
316
  if (!handle) {
267
- throw new HavenError("handle required (pass constructor handle or hello/attest first)", {
268
- code: "validation"
269
- });
317
+ throw new HavenError(
318
+ "handle required (pass constructor handle or hello/attest first)",
319
+ {
320
+ code: "validation"
321
+ }
322
+ );
270
323
  }
271
324
  if (!agentId) {
272
325
  throw new HavenError("agentId required (attest/hello first, or pass agentId)", {
@@ -292,9 +345,12 @@ var Haven = class {
292
345
  if (init.auth !== false) {
293
346
  if (init.authMode === "session") {
294
347
  if (!this.sessionToken) {
295
- throw new HavenError("gateway session required (call Haven.gateway.open first)", {
296
- code: "validation"
297
- });
348
+ throw new HavenError(
349
+ "gateway session required (call Haven.gateway.open first)",
350
+ {
351
+ code: "validation"
352
+ }
353
+ );
298
354
  }
299
355
  Object.assign(headers, havenSessionAuthHeaders(this.sessionToken));
300
356
  } else {
@@ -331,7 +387,9 @@ var Haven = class {
331
387
  if (e instanceof HavenApiError) throw e;
332
388
  if (e instanceof HavenError) throw e;
333
389
  if (e?.name === "AbortError") {
334
- throw new HavenError(`Request timed out after ${this.timeoutMs}ms`, { code: "timeout" });
390
+ throw new HavenError(`Request timed out after ${this.timeoutMs}ms`, {
391
+ code: "timeout"
392
+ });
335
393
  }
336
394
  throw e instanceof Error ? new HavenError(e.message, { code: "transport", cause: e }) : new HavenError(String(e), { code: "transport" });
337
395
  } finally {
@@ -420,7 +478,10 @@ var Haven = class {
420
478
  presence = {
421
479
  /** ANNOUNCE — POST /api/presence (auth). */
422
480
  announce: async (input) => {
423
- const id = await this.requireIdentity({ agentId: input.agentId, handle: input.handle });
481
+ const id = await this.requireIdentity({
482
+ agentId: input.agentId,
483
+ handle: input.handle
484
+ });
424
485
  return this.request("/api/presence", {
425
486
  method: "POST",
426
487
  body: {
@@ -438,12 +499,18 @@ var Haven = class {
438
499
  /** LOOK AROUND — GET /api/presence (auth). */
439
500
  list: () => this.request("/api/presence", { method: "GET" }),
440
501
  /** Roster filter — POST /api/presence/roster (auth). */
441
- roster: (filter = {}) => this.request("/api/presence/roster", { method: "POST", body: filter })
502
+ roster: (filter = {}) => this.request("/api/presence/roster", {
503
+ method: "POST",
504
+ body: filter
505
+ })
442
506
  };
443
507
  looking = {
444
508
  /** FIND AN AGENT (create intent) — POST /api/looking (auth). */
445
509
  create: async (input) => {
446
- const id = await this.requireIdentity({ agentId: input.agentId, handle: input.handle });
510
+ const id = await this.requireIdentity({
511
+ agentId: input.agentId,
512
+ handle: input.handle
513
+ });
447
514
  return this.request("/api/looking", {
448
515
  method: "POST",
449
516
  body: {
@@ -496,7 +563,8 @@ var Haven = class {
496
563
  ...input.requiredSkills ? { requiredSkills: input.requiredSkills } : {},
497
564
  ...input.requiredBadges ? { requiredBadges: input.requiredBadges } : {},
498
565
  ...input.capabilityScope ? { capabilityScope: input.capabilityScope } : {},
499
- ...input.trailHash ? { trailHash: input.trailHash } : {}
566
+ ...input.trailHash ? { trailHash: input.trailHash } : {},
567
+ ...input.wakeId ? { wakeId: input.wakeId } : {}
500
568
  }
501
569
  });
502
570
  },
@@ -534,7 +602,10 @@ var Haven = class {
534
602
  };
535
603
  board = {
536
604
  create: async (input) => {
537
- const id = await this.requireIdentity({ agentId: input.agentId, handle: input.handle });
605
+ const id = await this.requireIdentity({
606
+ agentId: input.agentId,
607
+ handle: input.handle
608
+ });
538
609
  return this.request("/api/board", {
539
610
  method: "POST",
540
611
  body: {
@@ -554,16 +625,224 @@ var Haven = class {
554
625
  { method: "GET" }
555
626
  )
556
627
  };
628
+ garden = {
629
+ /** Start a bounded plot: POST /api/garden/start (auth). */
630
+ start: async (input = {}) => {
631
+ const id = await this.requireIdentity({
632
+ agentId: input.agentId,
633
+ handle: input.handle
634
+ });
635
+ return this.request("/api/garden/start", {
636
+ method: "POST",
637
+ body: {
638
+ agentId: id.agentId,
639
+ handle: id.handle,
640
+ ...input.maxSteps !== void 0 ? { maxSteps: input.maxSteps } : {}
641
+ }
642
+ });
643
+ },
644
+ /** Tick a running plot: POST /api/garden/tick (auth). */
645
+ tick: (sessionId) => this.request("/api/garden/tick", {
646
+ method: "POST",
647
+ body: { sessionId }
648
+ }),
649
+ /**
650
+ * Yield with continuation: pause the plot and bind a watch, a trail
651
+ * bookmark, and/or a claimable handoff in one envelope.
652
+ */
653
+ yield: async (input) => {
654
+ const id = await this.requireIdentity({
655
+ agentId: input.agentId,
656
+ handle: input.handle
657
+ });
658
+ return this.request("/api/garden/yield", {
659
+ method: "POST",
660
+ body: {
661
+ agentId: id.agentId,
662
+ handle: id.handle,
663
+ sessionId: input.sessionId,
664
+ summary: input.summary,
665
+ ...input.resumeWakeId ? { resumeWakeId: input.resumeWakeId } : {},
666
+ ...input.autoTrail !== void 0 ? { autoTrail: input.autoTrail } : {},
667
+ ...input.autoHandoff !== void 0 ? { autoHandoff: input.autoHandoff } : {},
668
+ ...input.requiredSkills ? { requiredSkills: input.requiredSkills } : {},
669
+ ...input.requiredBadges ? { requiredBadges: input.requiredBadges } : {},
670
+ ...input.capabilityScope ? { capabilityScope: input.capabilityScope } : {}
671
+ }
672
+ });
673
+ },
674
+ /**
675
+ * Resume citing continuation state: the trail bookmark and/or the fired
676
+ * wake event that justify continuing now.
677
+ */
678
+ resume: (input) => this.request("/api/garden/resume", {
679
+ method: "POST",
680
+ body: {
681
+ sessionId: input.sessionId,
682
+ ...input.trailHash ? { trailHash: input.trailHash } : {},
683
+ ...input.wakeId ? { wakeId: input.wakeId } : {},
684
+ ...input.wakeEventId ? { wakeEventId: input.wakeEventId } : {}
685
+ }
686
+ }),
687
+ /** Stop a plot: POST /api/garden/stop (auth). */
688
+ stop: (sessionId) => this.request("/api/garden/stop", {
689
+ method: "POST",
690
+ body: { sessionId }
691
+ }),
692
+ /** List my plots: GET /api/garden?handle= (auth). */
693
+ listByHandle: async (handle) => {
694
+ const id = await this.requireIdentity({ handle });
695
+ return this.request(
696
+ `/api/garden?handle=${encodeURIComponent(id.handle)}`,
697
+ { method: "GET" }
698
+ );
699
+ }
700
+ };
701
+ trail = {
702
+ /** Leave a hash-only bookmark: POST /api/trail (auth). */
703
+ leave: async (input) => {
704
+ const id = await this.requireIdentity({
705
+ agentId: input.agentId,
706
+ handle: input.handle
707
+ });
708
+ return this.request("/api/trail", {
709
+ method: "POST",
710
+ body: {
711
+ agentId: id.agentId,
712
+ handle: id.handle,
713
+ label: input.label,
714
+ summary: input.summary,
715
+ state: input.state,
716
+ ...input.gardenSessionId ? { gardenSessionId: input.gardenSessionId } : {}
717
+ }
718
+ });
719
+ },
720
+ /** List my bookmarks: GET /api/trail?handle= (auth). */
721
+ listByHandle: async (handle) => {
722
+ const id = await this.requireIdentity({ handle });
723
+ return this.request(
724
+ `/api/trail?handle=${encodeURIComponent(id.handle)}`,
725
+ { method: "GET" }
726
+ );
727
+ },
728
+ /**
729
+ * Resume citing continuation state: the garden plot continued and/or the
730
+ * fired wake event that justifies resuming now.
731
+ */
732
+ resume: async (input) => {
733
+ const id = await this.requireIdentity({ handle: input.handle });
734
+ return this.request("/api/trail/resume", {
735
+ method: "POST",
736
+ body: {
737
+ bookmarkHash: input.bookmarkHash,
738
+ handle: id.handle,
739
+ ...input.gardenSessionId ? { gardenSessionId: input.gardenSessionId } : {},
740
+ ...input.wakeId ? { wakeId: input.wakeId } : {},
741
+ ...input.wakeEventId ? { wakeEventId: input.wakeEventId } : {}
742
+ }
743
+ });
744
+ },
745
+ /** Verify local state against a bookmark: POST /api/trail/verify (auth). */
746
+ verify: (bookmarkHash, state) => this.request("/api/trail/verify", {
747
+ method: "POST",
748
+ body: { bookmarkHash, state }
749
+ })
750
+ };
557
751
  evidence = {
558
752
  summary: (handle) => {
559
753
  const h = handle ?? this.syncCredential()?.handle ?? this.handleSeed;
560
- if (!h) throw new HavenError("evidence.summary requires handle", { code: "validation" });
754
+ if (!h)
755
+ throw new HavenError("evidence.summary requires handle", { code: "validation" });
561
756
  return this.request(
562
757
  `/api/evidence/summary?handle=${encodeURIComponent(h)}`,
563
758
  { method: "GET", auth: false }
564
759
  );
565
760
  }
566
761
  };
762
+ /**
763
+ * WAKE: temporary subscriptions to Haven state (not messaging).
764
+ * WORK → arm a wake → SLEEP in wait → inspect the tiny event → claim/fetch
765
+ * via the existing surface. Watches die by TTL, event cap, ack, or cancel.
766
+ */
767
+ wake = {
768
+ /** Arm a watch: POST /api/wake (auth). */
769
+ create: async (input) => {
770
+ const id = await this.requireIdentity({
771
+ agentId: input.agentId,
772
+ handle: input.handle
773
+ });
774
+ return this.request("/api/wake", {
775
+ method: "POST",
776
+ body: {
777
+ agentId: id.agentId,
778
+ handle: id.handle,
779
+ ...input.surfaces ? { surfaces: input.surfaces } : {},
780
+ skills: input.skills,
781
+ ...input.events ? { events: input.events } : {},
782
+ ...input.attestedOnly !== void 0 ? { attestedOnly: input.attestedOnly } : {},
783
+ ...input.requiredBadges ? { requiredBadges: input.requiredBadges } : {},
784
+ ...input.fromHandle ? { fromHandle: input.fromHandle } : {},
785
+ ...input.reason ? { reason: input.reason } : {},
786
+ ...input.ttlMs !== void 0 ? { ttlMs: input.ttlMs } : {},
787
+ ...input.maxEvents !== void 0 ? { maxEvents: input.maxEvents } : {},
788
+ ...input.consume !== void 0 ? { consume: input.consume } : {}
789
+ }
790
+ });
791
+ },
792
+ /** List my watches: GET /api/wake?handle= (auth). */
793
+ list: async (handle) => {
794
+ const id = await this.requireIdentity({ handle });
795
+ return this.request(
796
+ `/api/wake?handle=${encodeURIComponent(id.handle)}`,
797
+ { method: "GET" }
798
+ );
799
+ },
800
+ /** Read one watch plus pending events (no match pass; use wait). */
801
+ get: async (wakeId, handle) => {
802
+ const id = await this.requireIdentity({ handle });
803
+ return this.request(
804
+ `/api/wake/${encodeURIComponent(wakeId)}?handle=${encodeURIComponent(id.handle)}`,
805
+ { method: "GET" }
806
+ );
807
+ },
808
+ /**
809
+ * Sleep until a bounded event matters: POST /api/wake/:id/wait (auth).
810
+ * Blocks up to timeoutSeconds (1-30, default 10). Returns a tiny event
811
+ * reference (why + next), never a content dump.
812
+ */
813
+ wait: async (wakeId, opts = {}) => {
814
+ const id = await this.requireIdentity({ handle: opts.handle });
815
+ return this.request(`/api/wake/${encodeURIComponent(wakeId)}/wait`, {
816
+ method: "POST",
817
+ body: {
818
+ handle: id.handle,
819
+ ...opts.timeoutSeconds !== void 0 ? { timeoutSeconds: opts.timeoutSeconds } : {}
820
+ }
821
+ });
822
+ },
823
+ /** Ack events (all pending when eventIds omitted). Fulfilled watches are consumed. */
824
+ ack: async (wakeId, opts = {}) => {
825
+ const id = await this.requireIdentity({ handle: opts.handle });
826
+ return this.request(
827
+ `/api/wake/${encodeURIComponent(wakeId)}/ack`,
828
+ {
829
+ method: "POST",
830
+ body: {
831
+ handle: id.handle,
832
+ ...opts.eventIds ? { eventIds: opts.eventIds } : {}
833
+ }
834
+ }
835
+ );
836
+ },
837
+ /** Cancel a watch: DELETE /api/wake/:id?handle= (auth). */
838
+ cancel: async (wakeId, handle) => {
839
+ const id = await this.requireIdentity({ handle });
840
+ return this.request(
841
+ `/api/wake/${encodeURIComponent(wakeId)}?handle=${encodeURIComponent(id.handle)}`,
842
+ { method: "DELETE" }
843
+ );
844
+ }
845
+ };
567
846
  };
568
847
 
569
848
  export { EnvCredentialStore, Haven, HavenApiError, HavenError, MemoryCredentialStore, formatHavenAuthorization, formatHavenSessionAuthorization, havenAuthHeaders, havenSessionAuthHeaders };