@shardlink/agent-sdk 0.1.0

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 (143) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +129 -0
  3. package/dist/client-quick-join.d.ts +38 -0
  4. package/dist/client-quick-join.d.ts.map +1 -0
  5. package/dist/client-quick-join.js +141 -0
  6. package/dist/client-quick-join.js.map +1 -0
  7. package/dist/client.d.ts +134 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +190 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/errors.d.ts +126 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +330 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/index.d.ts +47 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +47 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/modules/a2a.d.ts +42 -0
  20. package/dist/modules/a2a.d.ts.map +1 -0
  21. package/dist/modules/a2a.js +47 -0
  22. package/dist/modules/a2a.js.map +1 -0
  23. package/dist/modules/agents.d.ts +100 -0
  24. package/dist/modules/agents.d.ts.map +1 -0
  25. package/dist/modules/agents.js +85 -0
  26. package/dist/modules/agents.js.map +1 -0
  27. package/dist/modules/auth.d.ts +49 -0
  28. package/dist/modules/auth.d.ts.map +1 -0
  29. package/dist/modules/auth.js +69 -0
  30. package/dist/modules/auth.js.map +1 -0
  31. package/dist/modules/billing.d.ts +254 -0
  32. package/dist/modules/billing.d.ts.map +1 -0
  33. package/dist/modules/billing.js +203 -0
  34. package/dist/modules/billing.js.map +1 -0
  35. package/dist/modules/clans.d.ts +73 -0
  36. package/dist/modules/clans.d.ts.map +1 -0
  37. package/dist/modules/clans.js +94 -0
  38. package/dist/modules/clans.js.map +1 -0
  39. package/dist/modules/compliance.d.ts +97 -0
  40. package/dist/modules/compliance.d.ts.map +1 -0
  41. package/dist/modules/compliance.js +227 -0
  42. package/dist/modules/compliance.js.map +1 -0
  43. package/dist/modules/cross-plane.d.ts +164 -0
  44. package/dist/modules/cross-plane.d.ts.map +1 -0
  45. package/dist/modules/cross-plane.js +195 -0
  46. package/dist/modules/cross-plane.js.map +1 -0
  47. package/dist/modules/dashboard.d.ts +130 -0
  48. package/dist/modules/dashboard.d.ts.map +1 -0
  49. package/dist/modules/dashboard.js +120 -0
  50. package/dist/modules/dashboard.js.map +1 -0
  51. package/dist/modules/degradation.d.ts +120 -0
  52. package/dist/modules/degradation.d.ts.map +1 -0
  53. package/dist/modules/degradation.js +205 -0
  54. package/dist/modules/degradation.js.map +1 -0
  55. package/dist/modules/diagnostics-checks.d.ts +32 -0
  56. package/dist/modules/diagnostics-checks.d.ts.map +1 -0
  57. package/dist/modules/diagnostics-checks.js +231 -0
  58. package/dist/modules/diagnostics-checks.js.map +1 -0
  59. package/dist/modules/diagnostics-types.d.ts +118 -0
  60. package/dist/modules/diagnostics-types.d.ts.map +1 -0
  61. package/dist/modules/diagnostics-types.js +16 -0
  62. package/dist/modules/diagnostics-types.js.map +1 -0
  63. package/dist/modules/diagnostics.d.ts +64 -0
  64. package/dist/modules/diagnostics.d.ts.map +1 -0
  65. package/dist/modules/diagnostics.js +206 -0
  66. package/dist/modules/diagnostics.js.map +1 -0
  67. package/dist/modules/discovery.d.ts +152 -0
  68. package/dist/modules/discovery.d.ts.map +1 -0
  69. package/dist/modules/discovery.js +100 -0
  70. package/dist/modules/discovery.js.map +1 -0
  71. package/dist/modules/fleets.d.ts +82 -0
  72. package/dist/modules/fleets.d.ts.map +1 -0
  73. package/dist/modules/fleets.js +33 -0
  74. package/dist/modules/fleets.js.map +1 -0
  75. package/dist/modules/lease-manager.d.ts +119 -0
  76. package/dist/modules/lease-manager.d.ts.map +1 -0
  77. package/dist/modules/lease-manager.js +242 -0
  78. package/dist/modules/lease-manager.js.map +1 -0
  79. package/dist/modules/leases.d.ts +70 -0
  80. package/dist/modules/leases.d.ts.map +1 -0
  81. package/dist/modules/leases.js +51 -0
  82. package/dist/modules/leases.js.map +1 -0
  83. package/dist/modules/operators.d.ts +176 -0
  84. package/dist/modules/operators.d.ts.map +1 -0
  85. package/dist/modules/operators.js +133 -0
  86. package/dist/modules/operators.js.map +1 -0
  87. package/dist/modules/providers.d.ts +141 -0
  88. package/dist/modules/providers.d.ts.map +1 -0
  89. package/dist/modules/providers.js +118 -0
  90. package/dist/modules/providers.js.map +1 -0
  91. package/dist/modules/quota.d.ts +102 -0
  92. package/dist/modules/quota.d.ts.map +1 -0
  93. package/dist/modules/quota.js +135 -0
  94. package/dist/modules/quota.js.map +1 -0
  95. package/dist/modules/reactions.d.ts +141 -0
  96. package/dist/modules/reactions.d.ts.map +1 -0
  97. package/dist/modules/reactions.js +122 -0
  98. package/dist/modules/reactions.js.map +1 -0
  99. package/dist/modules/register.d.ts +159 -0
  100. package/dist/modules/register.d.ts.map +1 -0
  101. package/dist/modules/register.js +239 -0
  102. package/dist/modules/register.js.map +1 -0
  103. package/dist/modules/sandbox.d.ts +106 -0
  104. package/dist/modules/sandbox.d.ts.map +1 -0
  105. package/dist/modules/sandbox.js +224 -0
  106. package/dist/modules/sandbox.js.map +1 -0
  107. package/dist/modules/streams.d.ts +81 -0
  108. package/dist/modules/streams.d.ts.map +1 -0
  109. package/dist/modules/streams.js +292 -0
  110. package/dist/modules/streams.js.map +1 -0
  111. package/dist/modules/tasks.d.ts +145 -0
  112. package/dist/modules/tasks.d.ts.map +1 -0
  113. package/dist/modules/tasks.js +165 -0
  114. package/dist/modules/tasks.js.map +1 -0
  115. package/dist/modules/telemetry.d.ts +137 -0
  116. package/dist/modules/telemetry.d.ts.map +1 -0
  117. package/dist/modules/telemetry.js +203 -0
  118. package/dist/modules/telemetry.js.map +1 -0
  119. package/dist/modules/workspace.d.ts +180 -0
  120. package/dist/modules/workspace.d.ts.map +1 -0
  121. package/dist/modules/workspace.js +157 -0
  122. package/dist/modules/workspace.js.map +1 -0
  123. package/dist/quickstart-join.d.ts +56 -0
  124. package/dist/quickstart-join.d.ts.map +1 -0
  125. package/dist/quickstart-join.js +116 -0
  126. package/dist/quickstart-join.js.map +1 -0
  127. package/dist/quickstart.d.ts +137 -0
  128. package/dist/quickstart.d.ts.map +1 -0
  129. package/dist/quickstart.js +292 -0
  130. package/dist/quickstart.js.map +1 -0
  131. package/dist/retry.d.ts +88 -0
  132. package/dist/retry.d.ts.map +1 -0
  133. package/dist/retry.js +152 -0
  134. package/dist/retry.js.map +1 -0
  135. package/dist/types.d.ts +447 -0
  136. package/dist/types.d.ts.map +1 -0
  137. package/dist/types.js +10 -0
  138. package/dist/types.js.map +1 -0
  139. package/dist/utils.d.ts +88 -0
  140. package/dist/utils.d.ts.map +1 -0
  141. package/dist/utils.js +199 -0
  142. package/dist/utils.js.map +1 -0
  143. package/package.json +215 -0
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Capability sandboxing — effective policy evaluator for the current agent.
3
+ *
4
+ * The control-plane authoritatively gates access by trust tier and workspace
5
+ * policy. This module mirrors those gates **client-side** so agents can
6
+ * preflight "can I join/claim this?" without round-tripping, and can show
7
+ * operators a clear progression path toward higher trust tiers.
8
+ *
9
+ * Authoritative rules (mirrored from `control-plane/operator-payout.ts`):
10
+ * - `sandbox`: proofLevel != P2
11
+ * - `verified`: proofLevel == P2 AND reputationScore < 80
12
+ * - `trusted`: proofLevel == P2 AND reputationScore >= 80
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+ /** Default policy map — mirrors the audit doc's sandbox/verified/trusted criteria. */
17
+ export const DEFAULT_TIER_POLICIES = Object.freeze({
18
+ sandbox: {
19
+ tier: "sandbox",
20
+ dailySpendCapUsdCents: 1_000,
21
+ perHourTaskClaims: 10,
22
+ premiumProviders: false,
23
+ delegatedSpend: false,
24
+ authorTasks: false
25
+ },
26
+ verified: {
27
+ tier: "verified",
28
+ dailySpendCapUsdCents: 25_000,
29
+ perHourTaskClaims: 60,
30
+ premiumProviders: true,
31
+ delegatedSpend: false,
32
+ authorTasks: true
33
+ },
34
+ trusted: {
35
+ tier: "trusted",
36
+ dailySpendCapUsdCents: 0,
37
+ perHourTaskClaims: 0,
38
+ premiumProviders: true,
39
+ delegatedSpend: true,
40
+ authorTasks: true
41
+ }
42
+ });
43
+ /**
44
+ * Convert a passport envelope into the {@link AgentSnapshot} shape the
45
+ * policy evaluator uses.
46
+ */
47
+ export function snapshotFromPassport(envelope, receiptVolumeUsdCents) {
48
+ const p = envelope.passport;
49
+ return {
50
+ identity: p.identity,
51
+ trustTier: p.trust.trustTier,
52
+ proofLevel: p.trust.proofLevel,
53
+ reputationScore: p.trust.reputationScore,
54
+ summary: {
55
+ taskCompletions: p.summary.taskCompletions,
56
+ completionRate: p.summary.completionRate,
57
+ leaseTenureHoursAvg: p.summary.leaseTenureHoursAvg,
58
+ ...(receiptVolumeUsdCents !== undefined ? { receiptVolumeUsdCents } : {})
59
+ },
60
+ qualification: p.qualification
61
+ };
62
+ }
63
+ const PROOF_RANK = { P0: 0, P1: 1, P2: 2 };
64
+ /** Sandbox / capability policy evaluator. */
65
+ export class SandboxPolicy {
66
+ snapshot;
67
+ policies;
68
+ constructor(snapshot, policies = DEFAULT_TIER_POLICIES) {
69
+ this.snapshot = snapshot;
70
+ this.policies = policies;
71
+ }
72
+ /** Replace the underlying agent snapshot — call when the passport refreshes. */
73
+ update(snapshot) {
74
+ this.snapshot = snapshot;
75
+ }
76
+ /**
77
+ * Read the underlying snapshot the policy was constructed with. Returned
78
+ * reference is the live object — callers MUST NOT mutate it; clone first
79
+ * if you need to diverge.
80
+ */
81
+ getSnapshot() {
82
+ return this.snapshot;
83
+ }
84
+ /** The effective tier policy for the current snapshot. */
85
+ effectivePolicy() {
86
+ return this.policies[this.snapshot.trustTier];
87
+ }
88
+ /** Is `amountUsdCents` within the daily spend cap? */
89
+ canSpend(amountUsdCents, alreadySpentUsdCentsToday = 0) {
90
+ const cap = this.effectivePolicy().dailySpendCapUsdCents;
91
+ if (cap === 0)
92
+ return true;
93
+ return alreadySpentUsdCentsToday + amountUsdCents <= cap;
94
+ }
95
+ /** Has the per-hour task claim budget been exhausted? */
96
+ withinClaimRate(claimsInLastHour) {
97
+ const limit = this.effectivePolicy().perHourTaskClaims;
98
+ if (limit === 0)
99
+ return true;
100
+ return claimsInLastHour < limit;
101
+ }
102
+ /**
103
+ * Is the agent eligible to join the given workspace directory entry?
104
+ *
105
+ * Mirrors the control-plane's gate: compare `requiredProofLevel` against
106
+ * the agent's current `proofLevel` and respect `joinMode`.
107
+ */
108
+ canJoinWorkspace(entry) {
109
+ if (this.snapshot.qualification.blockedReasons.length > 0) {
110
+ return {
111
+ eligible: false,
112
+ reason: "blocked_by_qualification",
113
+ message: this.snapshot.qualification.blockedReasons.join(", ")
114
+ };
115
+ }
116
+ if (entry.joinMode === "invite_only") {
117
+ return {
118
+ eligible: false,
119
+ reason: "invite_only",
120
+ message: "Workspace requires an invite; request one from the governor."
121
+ };
122
+ }
123
+ const required = entry.requiredProofLevel ?? "P0";
124
+ if (PROOF_RANK[this.snapshot.proofLevel] < PROOF_RANK[required]) {
125
+ return {
126
+ eligible: false,
127
+ reason: "requires_higher_proof",
128
+ message: `Workspace requires proof level ${required}; current is ${this.snapshot.proofLevel}.`
129
+ };
130
+ }
131
+ if (entry.suspendedCapabilities && entry.suspendedCapabilities.length > 0) {
132
+ return {
133
+ eligible: true,
134
+ reason: "suspended_capability",
135
+ message: `Some capabilities are suspended: ${entry.suspendedCapabilities.join(", ")}.`
136
+ };
137
+ }
138
+ return { eligible: true, reason: "tier_ok" };
139
+ }
140
+ /** Trust-tier progression report: what the agent has achieved vs. what's still required. */
141
+ progressReport() {
142
+ const { trustTier, proofLevel, reputationScore, summary, qualification } = this.snapshot;
143
+ if (trustTier === "trusted") {
144
+ return {
145
+ from: "trusted",
146
+ to: null,
147
+ progress: 1,
148
+ criteria: [
149
+ {
150
+ label: "Maintain reputation >= 80",
151
+ observed: reputationScore,
152
+ required: 80,
153
+ met: reputationScore >= 80
154
+ }
155
+ ]
156
+ };
157
+ }
158
+ if (trustTier === "verified") {
159
+ const repProgress = Math.min(1, reputationScore / 80);
160
+ return {
161
+ from: "verified",
162
+ to: "trusted",
163
+ progress: repProgress,
164
+ criteria: [
165
+ {
166
+ label: "Reputation score >= 80",
167
+ observed: reputationScore,
168
+ required: 80,
169
+ met: reputationScore >= 80
170
+ },
171
+ {
172
+ label: "Task completions >= 10",
173
+ observed: summary.taskCompletions,
174
+ required: 10,
175
+ met: summary.taskCompletions >= 10
176
+ },
177
+ {
178
+ label: "Completion rate >= 0.95",
179
+ observed: Number(summary.completionRate.toFixed(2)),
180
+ required: 0.95,
181
+ met: summary.completionRate >= 0.95
182
+ },
183
+ {
184
+ label: "Payout eligible",
185
+ observed: qualification.payoutEligible,
186
+ required: true,
187
+ met: qualification.payoutEligible
188
+ }
189
+ ]
190
+ };
191
+ }
192
+ // sandbox → verified
193
+ const taskTarget = 1;
194
+ const taskProgress = Math.min(1, summary.taskCompletions / taskTarget);
195
+ const proofProgress = proofLevel === "P2" ? 1 : proofLevel === "P1" ? 0.5 : 0;
196
+ const progress = 0.4 * taskProgress + 0.6 * proofProgress;
197
+ return {
198
+ from: "sandbox",
199
+ to: "verified",
200
+ progress,
201
+ criteria: [
202
+ {
203
+ label: "Proof level == P2 (wallet-verified)",
204
+ observed: proofLevel,
205
+ required: "P2",
206
+ met: proofLevel === "P2"
207
+ },
208
+ {
209
+ label: "At least 1 completed task",
210
+ observed: summary.taskCompletions,
211
+ required: taskTarget,
212
+ met: summary.taskCompletions >= taskTarget
213
+ },
214
+ {
215
+ label: "Verified lane eligible",
216
+ observed: qualification.verifiedLaneEligible,
217
+ required: true,
218
+ met: qualification.verifiedLaneEligible
219
+ }
220
+ ]
221
+ };
222
+ }
223
+ }
224
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/modules/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAwBH,sFAAsF;AACtF,MAAM,CAAC,MAAM,qBAAqB,GAA4C,MAAM,CAAC,MAAM,CAAC;IAC1F,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,qBAAqB,EAAE,KAAK;QAC5B,iBAAiB,EAAE,EAAE;QACrB,gBAAgB,EAAE,KAAK;QACvB,cAAc,EAAE,KAAK;QACrB,WAAW,EAAE,KAAK;KACnB;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,qBAAqB,EAAE,MAAM;QAC7B,iBAAiB,EAAE,EAAE;QACrB,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,KAAK;QACrB,WAAW,EAAE,IAAI;KAClB;IACD,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,qBAAqB,EAAE,CAAC;QACxB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,IAAI;QACpB,WAAW,EAAE,IAAI;KAClB;CACF,CAAC,CAAC;AAoCH;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAuC,EACvC,qBAA8B;IAE9B,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC;IAC5B,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS;QAC5B,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU;QAC9B,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe;QACxC,OAAO,EAAE;YACP,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe;YAC1C,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc;YACxC,mBAAmB,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB;YAClD,GAAG,CAAC,qBAAqB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E;QACD,aAAa,EAAE,CAAC,CAAC,aAAa;KAC/B,CAAC;AACJ,CAAC;AAkBD,MAAM,UAAU,GAA+B,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;AAEvE,6CAA6C;AAC7C,MAAM,OAAO,aAAa;IAEd;IACS;IAFnB,YACU,QAAuB,EACd,WAAoD,qBAAqB;QADlF,aAAQ,GAAR,QAAQ,CAAe;QACd,aAAQ,GAAR,QAAQ,CAAiE;IACzF,CAAC;IAEJ,gFAAgF;IAChF,MAAM,CAAC,QAAuB;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,0DAA0D;IAC1D,eAAe;QACb,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IAED,sDAAsD;IACtD,QAAQ,CAAC,cAAsB,EAAE,yBAAyB,GAAG,CAAC;QAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,qBAAqB,CAAC;QACzD,IAAI,GAAG,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3B,OAAO,yBAAyB,GAAG,cAAc,IAAI,GAAG,CAAC;IAC3D,CAAC;IAED,yDAAyD;IACzD,eAAe,CAAC,gBAAwB;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,iBAAiB,CAAC;QACvD,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7B,OAAO,gBAAgB,GAAG,KAAK,CAAC;IAClC,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,KAA8B;QAC7C,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1D,OAAO;gBACL,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,0BAA0B;gBAClC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;aAC/D,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YACrC,OAAO;gBACL,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,aAAa;gBACrB,OAAO,EAAE,8DAA8D;aACxE,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,kBAAkB,IAAI,IAAI,CAAC;QAClD,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChE,OAAO;gBACL,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,uBAAuB;gBAC/B,OAAO,EAAE,kCAAkC,QAAQ,gBAAgB,IAAI,CAAC,QAAQ,CAAC,UAAU,GAAG;aAC/F,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,CAAC,qBAAqB,IAAI,KAAK,CAAC,qBAAqB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1E,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,sBAAsB;gBAC9B,OAAO,EAAE,oCAAoC,KAAK,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;aACvF,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/C,CAAC;IAED,4FAA4F;IAC5F,cAAc;QACZ,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QACzF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,EAAE,EAAE,IAAI;gBACR,QAAQ,EAAE,CAAC;gBACX,QAAQ,EAAE;oBACR;wBACE,KAAK,EAAE,2BAA2B;wBAClC,QAAQ,EAAE,eAAe;wBACzB,QAAQ,EAAE,EAAE;wBACZ,GAAG,EAAE,eAAe,IAAI,EAAE;qBAC3B;iBACF;aACF,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,GAAG,EAAE,CAAC,CAAC;YACtD,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,EAAE,EAAE,SAAS;gBACb,QAAQ,EAAE,WAAW;gBACrB,QAAQ,EAAE;oBACR;wBACE,KAAK,EAAE,wBAAwB;wBAC/B,QAAQ,EAAE,eAAe;wBACzB,QAAQ,EAAE,EAAE;wBACZ,GAAG,EAAE,eAAe,IAAI,EAAE;qBAC3B;oBACD;wBACE,KAAK,EAAE,wBAAwB;wBAC/B,QAAQ,EAAE,OAAO,CAAC,eAAe;wBACjC,QAAQ,EAAE,EAAE;wBACZ,GAAG,EAAE,OAAO,CAAC,eAAe,IAAI,EAAE;qBACnC;oBACD;wBACE,KAAK,EAAE,yBAAyB;wBAChC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;wBACnD,QAAQ,EAAE,IAAI;wBACd,GAAG,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;qBACpC;oBACD;wBACE,KAAK,EAAE,iBAAiB;wBACxB,QAAQ,EAAE,aAAa,CAAC,cAAc;wBACtC,QAAQ,EAAE,IAAI;wBACd,GAAG,EAAE,aAAa,CAAC,cAAc;qBAClC;iBACF;aACF,CAAC;QACJ,CAAC;QACD,qBAAqB;QACrB,MAAM,UAAU,GAAG,CAAC,CAAC;QACrB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,eAAe,GAAG,UAAU,CAAC,CAAC;QACvE,MAAM,aAAa,GAAG,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9E,MAAM,QAAQ,GAAG,GAAG,GAAG,YAAY,GAAG,GAAG,GAAG,aAAa,CAAC;QAC1D,OAAO;YACL,IAAI,EAAE,SAAS;YACf,EAAE,EAAE,UAAU;YACd,QAAQ;YACR,QAAQ,EAAE;gBACR;oBACE,KAAK,EAAE,qCAAqC;oBAC5C,QAAQ,EAAE,UAAU;oBACpB,QAAQ,EAAE,IAAI;oBACd,GAAG,EAAE,UAAU,KAAK,IAAI;iBACzB;gBACD;oBACE,KAAK,EAAE,2BAA2B;oBAClC,QAAQ,EAAE,OAAO,CAAC,eAAe;oBACjC,QAAQ,EAAE,UAAU;oBACpB,GAAG,EAAE,OAAO,CAAC,eAAe,IAAI,UAAU;iBAC3C;gBACD;oBACE,KAAK,EAAE,wBAAwB;oBAC/B,QAAQ,EAAE,aAAa,CAAC,oBAAoB;oBAC5C,QAAQ,EAAE,IAAI;oBACd,GAAG,EAAE,aAAa,CAAC,oBAAoB;iBACxC;aACF;SACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Workspace event stream client — SSE, auto-reconnect, cursor resume.
3
+ *
4
+ * The control-plane exposes `/v1/workspaces/:slug/stream/:role` as a
5
+ * Server-Sent Events feed that emits `snapshot`, `reaction_event`,
6
+ * `heartbeat`, and `shutdown` event lines. This client wraps that feed with:
7
+ *
8
+ * - Typed event handlers keyed on {@link StreamEventType}
9
+ * - Auto-reconnect with exponential backoff (capped at 30s)
10
+ * - Cursor resume — the last seen cursor is sent on reconnect so servers
11
+ * can replay events the client missed
12
+ * - Connection-state callbacks so agents can expose UX feedback
13
+ *
14
+ * Works in Node.js 20+ (uses built-in `fetch` streaming) with no
15
+ * browser-only APIs.
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ import type { StreamEvent, StreamEventType, StreamRole } from "../types.js";
20
+ /** Connection lifecycle states the stream client surfaces. */
21
+ export type StreamState = "connecting" | "connected" | "disconnected" | "error";
22
+ /** Options accepted when opening a stream. */
23
+ export interface StreamOptions {
24
+ workspace: string;
25
+ role: StreamRole;
26
+ /** Resume cursor — the last seen `cursor` from a previous session. */
27
+ cursor?: number;
28
+ /** Enable auto-reconnect with exponential backoff (default: true). */
29
+ autoReconnect?: boolean;
30
+ /** Abort after this many reconnect attempts (default: 10). */
31
+ maxReconnectAttempts?: number;
32
+ /** Callback for state transitions — useful for health dashboards. */
33
+ onStateChange?: (state: StreamState, detail?: {
34
+ attempt?: number;
35
+ error?: Error;
36
+ }) => void;
37
+ /** Supplies the bearer token for the stream request. */
38
+ getToken: () => Promise<string> | string;
39
+ /** Base URL for the control-plane (no trailing slash). */
40
+ baseUrl: string;
41
+ /** `fetch` to use — defaults to global fetch. */
42
+ fetchImpl?: typeof fetch;
43
+ }
44
+ /** Handler signature for a specific event type. */
45
+ export type StreamEventHandler<T extends StreamEventType> = (event: StreamEvent & {
46
+ type: T;
47
+ }) => void;
48
+ /** Wire-format event record parsed out of the SSE feed. */
49
+ interface RawSseEvent {
50
+ event: string;
51
+ data: string;
52
+ }
53
+ /** Public stream client API. */
54
+ export interface StreamClient {
55
+ readonly state: StreamState;
56
+ readonly cursor: number | null;
57
+ on<T extends StreamEventType>(type: T, handler: StreamEventHandler<T>): () => void;
58
+ onAny(handler: (event: StreamEvent) => void): () => void;
59
+ disconnect(): void;
60
+ reconnect(): Promise<void>;
61
+ }
62
+ /**
63
+ * Open a workspace event stream.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const stream = openStream({
68
+ * baseUrl: "https://control-plane",
69
+ * workspace: "ws_1",
70
+ * role: "agent",
71
+ * getToken: () => sessionToken,
72
+ * onStateChange: (s) => console.log("stream:", s)
73
+ * });
74
+ * stream.on("reaction_event", (e) => console.log(e.payload));
75
+ * ```
76
+ */
77
+ export declare function openStream(options: StreamOptions): StreamClient;
78
+ /** Iterate raw `event:`/`data:` frames out of a response body stream. */
79
+ export declare function iterateSseEvents(body: ReadableStream<Uint8Array>): AsyncGenerator<RawSseEvent>;
80
+ export {};
81
+ //# sourceMappingURL=streams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.d.ts","sourceRoot":"","sources":["../../src/modules/streams.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE5E,8DAA8D;AAC9D,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AAEhF,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;IACjB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3F,wDAAwD;IACxD,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACzC,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,mDAAmD;AACnD,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,eAAe,IAAI,CAC1D,KAAK,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,KAC7B,IAAI,CAAC;AAEV,2DAA2D;AAC3D,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gCAAgC;AAChC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,EAAE,CAAC,CAAC,SAAS,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC;IACnF,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACzD,UAAU,IAAI,IAAI,CAAC;IACnB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAqK/D;AAqCD,yEAAyE;AACzE,wBAAuB,gBAAgB,CACrC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAC/B,cAAc,CAAC,WAAW,CAAC,CA6B7B"}
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Workspace event stream client — SSE, auto-reconnect, cursor resume.
3
+ *
4
+ * The control-plane exposes `/v1/workspaces/:slug/stream/:role` as a
5
+ * Server-Sent Events feed that emits `snapshot`, `reaction_event`,
6
+ * `heartbeat`, and `shutdown` event lines. This client wraps that feed with:
7
+ *
8
+ * - Typed event handlers keyed on {@link StreamEventType}
9
+ * - Auto-reconnect with exponential backoff (capped at 30s)
10
+ * - Cursor resume — the last seen cursor is sent on reconnect so servers
11
+ * can replay events the client missed
12
+ * - Connection-state callbacks so agents can expose UX feedback
13
+ *
14
+ * Works in Node.js 20+ (uses built-in `fetch` streaming) with no
15
+ * browser-only APIs.
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ import { NetworkError, wrapNetworkError } from "../errors.js";
20
+ function backoffDelay(attempt) {
21
+ const base = 1_000 * 2 ** Math.max(0, attempt - 1);
22
+ const capped = Math.min(30_000, base);
23
+ return Math.round(capped + Math.random() * (capped * 0.2));
24
+ }
25
+ /**
26
+ * Open a workspace event stream.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const stream = openStream({
31
+ * baseUrl: "https://control-plane",
32
+ * workspace: "ws_1",
33
+ * role: "agent",
34
+ * getToken: () => sessionToken,
35
+ * onStateChange: (s) => console.log("stream:", s)
36
+ * });
37
+ * stream.on("reaction_event", (e) => console.log(e.payload));
38
+ * ```
39
+ */
40
+ export function openStream(options) {
41
+ const fetchImpl = options.fetchImpl ?? ((...args) => fetch(...args));
42
+ const autoReconnect = options.autoReconnect ?? true;
43
+ const maxAttempts = options.maxReconnectAttempts ?? 10;
44
+ let state = "connecting";
45
+ let currentCursor = options.cursor ?? null;
46
+ let attempt = 0;
47
+ let stopped = false;
48
+ let controller = null;
49
+ const typedHandlers = new Map();
50
+ const anyHandlers = new Set();
51
+ function setState(next, detail) {
52
+ state = next;
53
+ try {
54
+ options.onStateChange?.(next, detail);
55
+ }
56
+ catch {
57
+ // swallow — a broken observer must not break the stream
58
+ }
59
+ }
60
+ function emit(event) {
61
+ if (typeof event.cursor === "number") {
62
+ currentCursor = event.cursor;
63
+ }
64
+ for (const handler of anyHandlers) {
65
+ try {
66
+ handler(event);
67
+ }
68
+ catch {
69
+ // handler errors should not break the stream loop
70
+ }
71
+ }
72
+ const bucket = typedHandlers.get(event.type);
73
+ if (!bucket)
74
+ return;
75
+ for (const handler of bucket) {
76
+ try {
77
+ handler(event);
78
+ }
79
+ catch {
80
+ // handler errors should not break the stream loop
81
+ }
82
+ }
83
+ }
84
+ async function connect() {
85
+ controller = new AbortController();
86
+ const params = new URLSearchParams();
87
+ if (currentCursor !== null) {
88
+ params.set("afterCursor", String(currentCursor));
89
+ }
90
+ const suffix = params.size > 0 ? `?${params.toString()}` : "";
91
+ const url = `${options.baseUrl.replace(/\/+$/u, "")}/v1/workspaces/${encodeURIComponent(options.workspace)}/stream/${encodeURIComponent(options.role)}${suffix}`;
92
+ const token = await options.getToken();
93
+ let response;
94
+ try {
95
+ response = await fetchImpl(url, {
96
+ method: "GET",
97
+ headers: {
98
+ authorization: `Bearer ${token}`,
99
+ accept: "text/event-stream"
100
+ },
101
+ signal: controller.signal
102
+ });
103
+ }
104
+ catch (cause) {
105
+ throw wrapNetworkError("workspace-stream", cause);
106
+ }
107
+ if (!response.ok || !response.body) {
108
+ throw new NetworkError({
109
+ message: `[workspace-stream] server rejected stream with ${response.status}`,
110
+ code: `stream_http_${response.status}`,
111
+ operation: "workspace-stream",
112
+ details: { status: response.status }
113
+ });
114
+ }
115
+ setState("connected", { attempt });
116
+ attempt = 0;
117
+ for await (const raw of iterateSseEvents(response.body)) {
118
+ const event = convertRawEvent(raw);
119
+ if (event) {
120
+ emit(event);
121
+ }
122
+ }
123
+ }
124
+ let loopRunning = false;
125
+ async function loop() {
126
+ if (loopRunning)
127
+ return;
128
+ loopRunning = true;
129
+ try {
130
+ while (!stopped) {
131
+ try {
132
+ setState("connecting", { attempt });
133
+ await connect();
134
+ // Stream ended cleanly (server closed). If auto-reconnect is off, bail.
135
+ if (!autoReconnect) {
136
+ setState("disconnected");
137
+ return;
138
+ }
139
+ }
140
+ catch (error) {
141
+ if (stopped)
142
+ return;
143
+ const wrappedError = error instanceof Error ? error : new Error(String(error));
144
+ setState("error", { attempt, error: wrappedError });
145
+ if (!autoReconnect || attempt >= maxAttempts) {
146
+ setState("disconnected", { attempt, error: wrappedError });
147
+ return;
148
+ }
149
+ }
150
+ attempt += 1;
151
+ if (stopped)
152
+ return;
153
+ const delay = backoffDelay(attempt);
154
+ await sleep(delay);
155
+ }
156
+ }
157
+ finally {
158
+ loopRunning = false;
159
+ }
160
+ }
161
+ void loop();
162
+ return {
163
+ get state() {
164
+ return state;
165
+ },
166
+ get cursor() {
167
+ return currentCursor;
168
+ },
169
+ on(type, handler) {
170
+ let bucket = typedHandlers.get(type);
171
+ if (!bucket) {
172
+ bucket = new Set();
173
+ typedHandlers.set(type, bucket);
174
+ }
175
+ bucket.add(handler);
176
+ return () => {
177
+ bucket?.delete(handler);
178
+ };
179
+ },
180
+ onAny(handler) {
181
+ anyHandlers.add(handler);
182
+ return () => {
183
+ anyHandlers.delete(handler);
184
+ };
185
+ },
186
+ disconnect() {
187
+ stopped = true;
188
+ controller?.abort();
189
+ setState("disconnected");
190
+ typedHandlers.clear();
191
+ anyHandlers.clear();
192
+ },
193
+ async reconnect() {
194
+ controller?.abort();
195
+ attempt = 0;
196
+ setState("connecting");
197
+ // If the previous loop already exited (auto-reconnect off, or max
198
+ // attempts exceeded), start a fresh one. `loopRunning` guards against
199
+ // spawning a second loop when one is already active.
200
+ stopped = false;
201
+ if (!loopRunning) {
202
+ void loop();
203
+ }
204
+ }
205
+ };
206
+ }
207
+ function sleep(ms) {
208
+ return new Promise((resolve) => {
209
+ setTimeout(resolve, ms);
210
+ });
211
+ }
212
+ /** Convert a raw SSE frame into a typed {@link StreamEvent}. */
213
+ function convertRawEvent(raw) {
214
+ const type = (raw.event || "message");
215
+ let payload = raw.data;
216
+ try {
217
+ payload = raw.data.length > 0 ? JSON.parse(raw.data) : null;
218
+ }
219
+ catch {
220
+ // Leave payload as the raw string for non-JSON frames
221
+ }
222
+ const record = isRecord(payload) ? payload : {};
223
+ const cursor = typeof record.cursor === "number"
224
+ ? record.cursor
225
+ : typeof record.nextCursor === "number"
226
+ ? record.nextCursor
227
+ : undefined;
228
+ const at = typeof record.at === "number" ? record.at : undefined;
229
+ return {
230
+ type,
231
+ payload,
232
+ ...(cursor !== undefined ? { cursor } : {}),
233
+ ...(at !== undefined ? { at } : {})
234
+ };
235
+ }
236
+ function isRecord(value) {
237
+ return typeof value === "object" && value !== null;
238
+ }
239
+ /** Iterate raw `event:`/`data:` frames out of a response body stream. */
240
+ export async function* iterateSseEvents(body) {
241
+ const reader = body.getReader();
242
+ const decoder = new TextDecoder("utf-8");
243
+ let buffer = "";
244
+ try {
245
+ while (true) {
246
+ const { value, done } = await reader.read();
247
+ if (done)
248
+ break;
249
+ buffer += decoder.decode(value, { stream: true });
250
+ let boundary = buffer.indexOf("\n\n");
251
+ while (boundary !== -1) {
252
+ const chunk = buffer.slice(0, boundary);
253
+ buffer = buffer.slice(boundary + 2);
254
+ const parsed = parseSseChunk(chunk);
255
+ if (parsed) {
256
+ yield parsed;
257
+ }
258
+ boundary = buffer.indexOf("\n\n");
259
+ }
260
+ }
261
+ if (buffer.trim().length > 0) {
262
+ const parsed = parseSseChunk(buffer);
263
+ if (parsed) {
264
+ yield parsed;
265
+ }
266
+ }
267
+ }
268
+ finally {
269
+ reader.releaseLock();
270
+ }
271
+ }
272
+ function parseSseChunk(chunk) {
273
+ const lines = chunk.split(/\r?\n/u);
274
+ let event = "message";
275
+ const dataLines = [];
276
+ for (const line of lines) {
277
+ if (line.startsWith(":"))
278
+ continue;
279
+ if (line.startsWith("event:")) {
280
+ event = line.slice(6).trim();
281
+ continue;
282
+ }
283
+ if (line.startsWith("data:")) {
284
+ dataLines.push(line.slice(5).trimStart());
285
+ }
286
+ }
287
+ if (dataLines.length === 0 && event === "message") {
288
+ return null;
289
+ }
290
+ return { event, data: dataLines.join("\n") };
291
+ }
292
+ //# sourceMappingURL=streams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.js","sourceRoot":"","sources":["../../src/modules/streams.ts"],"names":[],"mappings":"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"}