@volter-ai-dev/supercode-ui 0.1.65 → 0.1.67

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/README.md CHANGED
@@ -243,6 +243,11 @@ heartbeat churn, treats compaction as a new baseline, and returns the delay for
243
243
  settlement timer. This keeps unread and finished semantics identical in an editor, extension,
244
244
  desktop app, or mobile companion without moving file persistence into the UI package.
245
245
 
246
+ `createNativeMessengerState` wraps that ledger with bounded per-conversation drafts and per-harness
247
+ Terminal/Headless preferences. It emits one serializable snapshot, so native hosts do not need to
248
+ duplicate state parsing or coordinate several independent maps. The host still owns where that
249
+ snapshot is stored, its debounce and encryption policy, and any multi-device synchronization.
250
+
246
251
  Native continuation exposes one action and a quiet execution-transport selector. A host with a real
247
252
  terminal provider can add `terminal` to `continuationModes` and handle `onResumeTerminal`; Terminal
248
253
  is then the initial choice and Headless remains available from the selector. The UI never infers
package/activity.mjs CHANGED
@@ -66,7 +66,12 @@ var EMPTY_UI_STATE = Object.freeze({
66
66
  subagentInspector: null,
67
67
  attached: null,
68
68
  owned: null,
69
- attachError: null
69
+ attachError: null,
70
+ agentPackage: null,
71
+ contributions: Object.freeze([]),
72
+ agentPackageError: null,
73
+ agentPackageCapabilityState: null,
74
+ agentPackageCapabilityError: null
70
75
  });
71
76
  var ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool", "reasoning", "request", "notice"]);
72
77
  var MODES = /* @__PURE__ */ new Set(["none", "control", "mirror"]);
@@ -79,6 +84,10 @@ var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "requir
79
84
  var MAX_TOOL_FIELDS = 8;
80
85
  var MAX_TOOL_FIELD_CHARS = 800;
81
86
  var MAX_TOOL_PREVIEW_CHARS = 4e3;
87
+ var MAX_CONTRIBUTIONS = 64;
88
+ var MAX_CONTRIBUTION_JSON_DEPTH = 12;
89
+ var MAX_CONTRIBUTION_COLLECTION = 100;
90
+ var MAX_CONTRIBUTION_STRING_CHARS = 16e3;
82
91
  function record(value) {
83
92
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
84
93
  }
@@ -111,6 +120,126 @@ function number(value, fallback = 0) {
111
120
  function nullableNumber(value) {
112
121
  return typeof value === "number" && Number.isFinite(value) ? value : null;
113
122
  }
123
+ function relativeContributionPath(value) {
124
+ if (typeof value !== "string" || value.startsWith("/") || /^[a-z]:[\\/]/i.test(value)) return null;
125
+ return value.replaceAll("\\", "/").split("/").some((segment) => segment === "..") ? null : boundedString(value, 1e3);
126
+ }
127
+ function contributionJson(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
128
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
129
+ return typeof value === "string" ? boundedString(value, MAX_CONTRIBUTION_STRING_CHARS) : value;
130
+ }
131
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
132
+ if (depth >= MAX_CONTRIBUTION_JSON_DEPTH || !value || typeof value !== "object" || seen.has(value)) {
133
+ return void 0;
134
+ }
135
+ seen.add(value);
136
+ if (Array.isArray(value)) {
137
+ const result2 = [];
138
+ for (const item of value.slice(0, MAX_CONTRIBUTION_COLLECTION)) {
139
+ const normalized = contributionJson(item, depth + 1, seen);
140
+ if (normalized !== void 0) result2.push(normalized);
141
+ }
142
+ seen.delete(value);
143
+ return result2;
144
+ }
145
+ const source = record(value);
146
+ if (!source) return void 0;
147
+ const result = {};
148
+ for (const [key, item] of Object.entries(source).slice(0, MAX_CONTRIBUTION_COLLECTION)) {
149
+ const normalized = contributionJson(item, depth + 1, seen);
150
+ if (normalized !== void 0) result[boundedString(key, 200)] = normalized;
151
+ }
152
+ seen.delete(value);
153
+ return result;
154
+ }
155
+ function normalizeContributions(value) {
156
+ if (!Array.isArray(value)) return [];
157
+ return value.slice(0, MAX_CONTRIBUTIONS).flatMap((candidate) => {
158
+ const item = record(candidate);
159
+ const placement = record(item?.placement);
160
+ const source = relativeContributionPath(item?.source);
161
+ if (item?.schema !== "supercode/contribution-v1" || typeof item.id !== "string" || !item.id.trim() || typeof item.kind !== "string" || !item.kind.trim() || source === null) return [];
162
+ const data = contributionJson(item.data);
163
+ if (data === void 0) return [];
164
+ return [{
165
+ schema: "supercode/contribution-v1",
166
+ id: boundedString(item.id, 200),
167
+ kind: boundedString(item.kind, 100),
168
+ ...typeof item.title === "string" ? { title: boundedString(item.title, 500) } : {},
169
+ ...placement ? { placement: {
170
+ ...typeof placement.surface === "string" ? { surface: boundedString(placement.surface, 100) } : {},
171
+ ...typeof placement.region === "string" ? { region: boundedString(placement.region, 100) } : {}
172
+ } } : {},
173
+ data,
174
+ source
175
+ }];
176
+ });
177
+ }
178
+ function readAgentPackage(value) {
179
+ const agentPackage = record(value);
180
+ const capabilities = record(agentPackage?.capabilities);
181
+ const storage = record(agentPackage?.storage);
182
+ const relativePath = relativeContributionPath(storage?.relativePath);
183
+ if (agentPackage?.schemaVersion !== 1 || typeof agentPackage.id !== "string" || typeof agentPackage.name !== "string" || typeof agentPackage.version !== "string" || !capabilities || !Array.isArray(capabilities.required) || !Array.isArray(capabilities.optional) || !storage || relativePath === null) return null;
184
+ const resources = record(agentPackage.resources);
185
+ return {
186
+ id: boundedString(agentPackage.id, 200),
187
+ name: boundedString(agentPackage.name, 500),
188
+ version: boundedString(agentPackage.version, 100),
189
+ description: typeof agentPackage.description === "string" ? boundedString(agentPackage.description, 2e3) : null,
190
+ capabilities: {
191
+ required: capabilities.required.filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200)),
192
+ optional: capabilities.optional.filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200))
193
+ },
194
+ storage: { relativePath },
195
+ resources: resources ? Object.fromEntries(Object.entries(resources).flatMap(([id, candidate]) => {
196
+ const state = record(candidate);
197
+ if (state?.schema !== "supercode/package-resource-state-v1") return [];
198
+ if (state.status === "absent" && typeof state.contributionId === "string") {
199
+ return [[boundedString(id, 200), {
200
+ schema: "supercode/package-resource-state-v1",
201
+ status: "absent",
202
+ contributionId: boundedString(state.contributionId, 200)
203
+ }]];
204
+ }
205
+ if (state.status === "error" && typeof state.contributionId === "string" && typeof state.message === "string") {
206
+ return [[boundedString(id, 200), {
207
+ schema: "supercode/package-resource-state-v1",
208
+ status: "error",
209
+ contributionId: boundedString(state.contributionId, 200),
210
+ message: boundedString(state.message)
211
+ }]];
212
+ }
213
+ const resource = record(state?.resource);
214
+ const data = contributionJson(resource?.data);
215
+ if (state?.status !== "ready" || resource?.schema !== "supercode/package-resource-v1" || typeof resource.contributionId !== "string" || !["json", "text"].includes(resource.format) || typeof resource.mediaType !== "string" || data === void 0) return [];
216
+ return [[boundedString(id, 200), {
217
+ schema: "supercode/package-resource-state-v1",
218
+ status: "ready",
219
+ resource: {
220
+ schema: "supercode/package-resource-v1",
221
+ contributionId: boundedString(resource.contributionId, 200),
222
+ format: resource.format,
223
+ mediaType: boundedString(resource.mediaType, 200),
224
+ data
225
+ }
226
+ }]];
227
+ })) : {}
228
+ };
229
+ }
230
+ function readAgentPackageCapabilityState(value) {
231
+ const state = record(value);
232
+ if (!state) return null;
233
+ const fields = ["availableRequired", "missingRequired", "enabledOptional", "unavailableOptional"];
234
+ if (!fields.every((field) => Array.isArray(state[field]))) return null;
235
+ return {
236
+ ready: state.ready === true,
237
+ ...Object.fromEntries(fields.map((field) => [
238
+ field,
239
+ state[field].filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200))
240
+ ]))
241
+ };
242
+ }
114
243
  function boundedString(value, max = 2e3) {
115
244
  if (typeof value !== "string") return "";
116
245
  return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
@@ -819,7 +948,12 @@ function normalizeUiState(value) {
819
948
  subagentInspector: readSubagentInspector(raw.subagentInspector),
820
949
  attached: readAttached(raw.attached),
821
950
  owned: readAttached(raw.owned),
822
- attachError: attachError && typeof attachError.key === "string" && typeof attachError.message === "string" ? { key: attachError.key, message: attachError.message } : null
951
+ attachError: attachError && typeof attachError.key === "string" && typeof attachError.message === "string" ? { key: attachError.key, message: attachError.message } : null,
952
+ agentPackage: readAgentPackage(raw.agentPackage),
953
+ contributions: normalizeContributions(raw.contributions),
954
+ agentPackageError: typeof raw.agentPackageError === "string" ? boundedString(raw.agentPackageError) : null,
955
+ agentPackageCapabilityState: readAgentPackageCapabilityState(raw.agentPackageCapabilityState),
956
+ agentPackageCapabilityError: typeof raw.agentPackageCapabilityError === "string" ? boundedString(raw.agentPackageCapabilityError) : null
823
957
  };
824
958
  }
825
959
  function harnessDisplayName(id) {
package/components.mjs CHANGED
@@ -69,7 +69,12 @@ var EMPTY_UI_STATE = Object.freeze({
69
69
  subagentInspector: null,
70
70
  attached: null,
71
71
  owned: null,
72
- attachError: null
72
+ attachError: null,
73
+ agentPackage: null,
74
+ contributions: Object.freeze([]),
75
+ agentPackageError: null,
76
+ agentPackageCapabilityState: null,
77
+ agentPackageCapabilityError: null
73
78
  });
74
79
  var ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool", "reasoning", "request", "notice"]);
75
80
  var MODES = /* @__PURE__ */ new Set(["none", "control", "mirror"]);
@@ -82,6 +87,10 @@ var AUTHENTICATION_PHASES = /* @__PURE__ */ new Set(["idle", "checking", "requir
82
87
  var MAX_TOOL_FIELDS = 8;
83
88
  var MAX_TOOL_FIELD_CHARS = 800;
84
89
  var MAX_TOOL_PREVIEW_CHARS = 4e3;
90
+ var MAX_CONTRIBUTIONS = 64;
91
+ var MAX_CONTRIBUTION_JSON_DEPTH = 12;
92
+ var MAX_CONTRIBUTION_COLLECTION = 100;
93
+ var MAX_CONTRIBUTION_STRING_CHARS = 16e3;
85
94
  function record(value) {
86
95
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
87
96
  }
@@ -114,6 +123,126 @@ function number(value, fallback = 0) {
114
123
  function nullableNumber(value) {
115
124
  return typeof value === "number" && Number.isFinite(value) ? value : null;
116
125
  }
126
+ function relativeContributionPath(value) {
127
+ if (typeof value !== "string" || value.startsWith("/") || /^[a-z]:[\\/]/i.test(value)) return null;
128
+ return value.replaceAll("\\", "/").split("/").some((segment) => segment === "..") ? null : boundedString(value, 1e3);
129
+ }
130
+ function contributionJson(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
131
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
132
+ return typeof value === "string" ? boundedString(value, MAX_CONTRIBUTION_STRING_CHARS) : value;
133
+ }
134
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
135
+ if (depth >= MAX_CONTRIBUTION_JSON_DEPTH || !value || typeof value !== "object" || seen.has(value)) {
136
+ return void 0;
137
+ }
138
+ seen.add(value);
139
+ if (Array.isArray(value)) {
140
+ const result2 = [];
141
+ for (const item of value.slice(0, MAX_CONTRIBUTION_COLLECTION)) {
142
+ const normalized = contributionJson(item, depth + 1, seen);
143
+ if (normalized !== void 0) result2.push(normalized);
144
+ }
145
+ seen.delete(value);
146
+ return result2;
147
+ }
148
+ const source = record(value);
149
+ if (!source) return void 0;
150
+ const result = {};
151
+ for (const [key, item] of Object.entries(source).slice(0, MAX_CONTRIBUTION_COLLECTION)) {
152
+ const normalized = contributionJson(item, depth + 1, seen);
153
+ if (normalized !== void 0) result[boundedString(key, 200)] = normalized;
154
+ }
155
+ seen.delete(value);
156
+ return result;
157
+ }
158
+ function normalizeContributions(value) {
159
+ if (!Array.isArray(value)) return [];
160
+ return value.slice(0, MAX_CONTRIBUTIONS).flatMap((candidate) => {
161
+ const item = record(candidate);
162
+ const placement = record(item?.placement);
163
+ const source = relativeContributionPath(item?.source);
164
+ if (item?.schema !== "supercode/contribution-v1" || typeof item.id !== "string" || !item.id.trim() || typeof item.kind !== "string" || !item.kind.trim() || source === null) return [];
165
+ const data = contributionJson(item.data);
166
+ if (data === void 0) return [];
167
+ return [{
168
+ schema: "supercode/contribution-v1",
169
+ id: boundedString(item.id, 200),
170
+ kind: boundedString(item.kind, 100),
171
+ ...typeof item.title === "string" ? { title: boundedString(item.title, 500) } : {},
172
+ ...placement ? { placement: {
173
+ ...typeof placement.surface === "string" ? { surface: boundedString(placement.surface, 100) } : {},
174
+ ...typeof placement.region === "string" ? { region: boundedString(placement.region, 100) } : {}
175
+ } } : {},
176
+ data,
177
+ source
178
+ }];
179
+ });
180
+ }
181
+ function readAgentPackage(value) {
182
+ const agentPackage = record(value);
183
+ const capabilities = record(agentPackage?.capabilities);
184
+ const storage = record(agentPackage?.storage);
185
+ const relativePath = relativeContributionPath(storage?.relativePath);
186
+ if (agentPackage?.schemaVersion !== 1 || typeof agentPackage.id !== "string" || typeof agentPackage.name !== "string" || typeof agentPackage.version !== "string" || !capabilities || !Array.isArray(capabilities.required) || !Array.isArray(capabilities.optional) || !storage || relativePath === null) return null;
187
+ const resources = record(agentPackage.resources);
188
+ return {
189
+ id: boundedString(agentPackage.id, 200),
190
+ name: boundedString(agentPackage.name, 500),
191
+ version: boundedString(agentPackage.version, 100),
192
+ description: typeof agentPackage.description === "string" ? boundedString(agentPackage.description, 2e3) : null,
193
+ capabilities: {
194
+ required: capabilities.required.filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200)),
195
+ optional: capabilities.optional.filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200))
196
+ },
197
+ storage: { relativePath },
198
+ resources: resources ? Object.fromEntries(Object.entries(resources).flatMap(([id, candidate]) => {
199
+ const state = record(candidate);
200
+ if (state?.schema !== "supercode/package-resource-state-v1") return [];
201
+ if (state.status === "absent" && typeof state.contributionId === "string") {
202
+ return [[boundedString(id, 200), {
203
+ schema: "supercode/package-resource-state-v1",
204
+ status: "absent",
205
+ contributionId: boundedString(state.contributionId, 200)
206
+ }]];
207
+ }
208
+ if (state.status === "error" && typeof state.contributionId === "string" && typeof state.message === "string") {
209
+ return [[boundedString(id, 200), {
210
+ schema: "supercode/package-resource-state-v1",
211
+ status: "error",
212
+ contributionId: boundedString(state.contributionId, 200),
213
+ message: boundedString(state.message)
214
+ }]];
215
+ }
216
+ const resource = record(state?.resource);
217
+ const data = contributionJson(resource?.data);
218
+ if (state?.status !== "ready" || resource?.schema !== "supercode/package-resource-v1" || typeof resource.contributionId !== "string" || !["json", "text"].includes(resource.format) || typeof resource.mediaType !== "string" || data === void 0) return [];
219
+ return [[boundedString(id, 200), {
220
+ schema: "supercode/package-resource-state-v1",
221
+ status: "ready",
222
+ resource: {
223
+ schema: "supercode/package-resource-v1",
224
+ contributionId: boundedString(resource.contributionId, 200),
225
+ format: resource.format,
226
+ mediaType: boundedString(resource.mediaType, 200),
227
+ data
228
+ }
229
+ }]];
230
+ })) : {}
231
+ };
232
+ }
233
+ function readAgentPackageCapabilityState(value) {
234
+ const state = record(value);
235
+ if (!state) return null;
236
+ const fields = ["availableRequired", "missingRequired", "enabledOptional", "unavailableOptional"];
237
+ if (!fields.every((field) => Array.isArray(state[field]))) return null;
238
+ return {
239
+ ready: state.ready === true,
240
+ ...Object.fromEntries(fields.map((field) => [
241
+ field,
242
+ state[field].filter((item) => typeof item === "string").slice(0, 100).map((item) => boundedString(item, 200))
243
+ ]))
244
+ };
245
+ }
117
246
  function relativeAge(updatedAt, now = Date.now()) {
118
247
  if (typeof updatedAt !== "number" || !Number.isFinite(updatedAt) || updatedAt <= 0) return "";
119
248
  const delta = Math.max(0, now - updatedAt);
@@ -831,7 +960,12 @@ function normalizeUiState(value) {
831
960
  subagentInspector: readSubagentInspector(raw.subagentInspector),
832
961
  attached: readAttached(raw.attached),
833
962
  owned: readAttached(raw.owned),
834
- attachError: attachError && typeof attachError.key === "string" && typeof attachError.message === "string" ? { key: attachError.key, message: attachError.message } : null
963
+ attachError: attachError && typeof attachError.key === "string" && typeof attachError.message === "string" ? { key: attachError.key, message: attachError.message } : null,
964
+ agentPackage: readAgentPackage(raw.agentPackage),
965
+ contributions: normalizeContributions(raw.contributions),
966
+ agentPackageError: typeof raw.agentPackageError === "string" ? boundedString(raw.agentPackageError) : null,
967
+ agentPackageCapabilityState: readAgentPackageCapabilityState(raw.agentPackageCapabilityState),
968
+ agentPackageCapabilityError: typeof raw.agentPackageCapabilityError === "string" ? boundedString(raw.agentPackageCapabilityError) : null
835
969
  };
836
970
  }
837
971
  function harnessDisplayName(id) {
package/composer.mjs CHANGED
@@ -69,7 +69,12 @@ var EMPTY_UI_STATE = Object.freeze({
69
69
  subagentInspector: null,
70
70
  attached: null,
71
71
  owned: null,
72
- attachError: null
72
+ attachError: null,
73
+ agentPackage: null,
74
+ contributions: Object.freeze([]),
75
+ agentPackageError: null,
76
+ agentPackageCapabilityState: null,
77
+ agentPackageCapabilityError: null
73
78
  });
74
79
  function harnessDisplayName(id) {
75
80
  return HARNESS_NAMES[id] ?? id;
package/controller.mjs CHANGED
@@ -608,6 +608,11 @@ function projectClientSnapshotInternal(snapshot, options, imageRegistry) {
608
608
  reductionReceipt: options.reductionReceipt ?? snapshot.reductionReceipt ?? null,
609
609
  interopSettings: snapshot.interopSettings ?? null,
610
610
  interopSettingsError: snapshot.interopSettingsError ?? null,
611
+ agentPackage: snapshot.agentPackage ?? null,
612
+ contributions: snapshot.agentPackage?.contributions ?? [],
613
+ agentPackageError: snapshot.agentPackageError ?? null,
614
+ agentPackageCapabilityState: snapshot.agentPackageCapabilityState ?? null,
615
+ agentPackageCapabilityError: snapshot.agentPackageCapabilityError ?? null,
611
616
  error: snapshot.error?.message ?? null,
612
617
  recoverable: snapshot.error?.recoverable === true,
613
618
  harnesses: (snapshot.harnesses ?? []).map((harness) => ({
package/conversation.mjs CHANGED
@@ -70,7 +70,12 @@ var EMPTY_UI_STATE = Object.freeze({
70
70
  subagentInspector: null,
71
71
  attached: null,
72
72
  owned: null,
73
- attachError: null
73
+ attachError: null,
74
+ agentPackage: null,
75
+ contributions: Object.freeze([]),
76
+ agentPackageError: null,
77
+ agentPackageCapabilityState: null,
78
+ agentPackageCapabilityError: null
74
79
  });
75
80
  var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
76
81
  var MAX_TOOL_FIELDS = 8;
package/core.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  export type {
2
2
  AttachedSessionModel,
3
3
  AgentActivityModel,
4
+ AgentContributionModel,
5
+ AgentPackageModel,
6
+ AgentPackageResourceModel,
7
+ AgentPackageResourceStateModel,
8
+ AgentPackageCapabilityStateModel,
4
9
  ContinuationMode,
5
10
  ControlStrategy,
6
11
  HarnessId,
@@ -36,6 +41,7 @@ export {
36
41
  groupConversation,
37
42
  harnessDisplayName,
38
43
  isSendKey,
44
+ normalizeContributions,
39
45
  normalizeUiState,
40
46
  operationLabel,
41
47
  projectAgentActivity,
@@ -43,6 +49,7 @@ export {
43
49
  relativeAge,
44
50
  sessionActivity,
45
51
  sessionDisplayName,
52
+ selectContributions,
46
53
  terminalCommand,
47
54
  toolCategory,
48
55
  toolTarget,
package/core.mjs CHANGED
@@ -68,6 +68,11 @@ export const EMPTY_UI_STATE = Object.freeze({
68
68
  attached: null,
69
69
  owned: null,
70
70
  attachError: null,
71
+ agentPackage: null,
72
+ contributions: Object.freeze([]),
73
+ agentPackageError: null,
74
+ agentPackageCapabilityState: null,
75
+ agentPackageCapabilityError: null,
71
76
  });
72
77
 
73
78
  const ROLES = new Set(['system', 'user', 'assistant', 'tool', 'reasoning', 'request', 'notice']);
@@ -81,6 +86,10 @@ const AUTHENTICATION_PHASES = new Set(['idle', 'checking', 'required', 'configur
81
86
  const MAX_TOOL_FIELDS = 8;
82
87
  const MAX_TOOL_FIELD_CHARS = 800;
83
88
  const MAX_TOOL_PREVIEW_CHARS = 4_000;
89
+ const MAX_CONTRIBUTIONS = 64;
90
+ const MAX_CONTRIBUTION_JSON_DEPTH = 12;
91
+ const MAX_CONTRIBUTION_COLLECTION = 100;
92
+ const MAX_CONTRIBUTION_STRING_CHARS = 16_000;
84
93
 
85
94
  function record(value) {
86
95
  return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : null;
@@ -121,6 +130,165 @@ function nullableNumber(value) {
121
130
  return typeof value === 'number' && Number.isFinite(value) ? value : null;
122
131
  }
123
132
 
133
+ function relativeContributionPath(value) {
134
+ if (typeof value !== 'string' || value.startsWith('/') || /^[a-z]:[\\/]/i.test(value)) return null;
135
+ return value.replaceAll('\\', '/').split('/').some((segment) => segment === '..')
136
+ ? null
137
+ : boundedString(value, 1_000);
138
+ }
139
+
140
+ function contributionJson(value, depth = 0, seen = new WeakSet()) {
141
+ if (value === null || typeof value === 'boolean' || typeof value === 'string') {
142
+ return typeof value === 'string' ? boundedString(value, MAX_CONTRIBUTION_STRING_CHARS) : value;
143
+ }
144
+ if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;
145
+ if (depth >= MAX_CONTRIBUTION_JSON_DEPTH || !value || typeof value !== 'object' || seen.has(value)) {
146
+ return undefined;
147
+ }
148
+ seen.add(value);
149
+ if (Array.isArray(value)) {
150
+ const result = [];
151
+ for (const item of value.slice(0, MAX_CONTRIBUTION_COLLECTION)) {
152
+ const normalized = contributionJson(item, depth + 1, seen);
153
+ if (normalized !== undefined) result.push(normalized);
154
+ }
155
+ seen.delete(value);
156
+ return result;
157
+ }
158
+ const source = record(value);
159
+ if (!source) return undefined;
160
+ const result = {};
161
+ for (const [key, item] of Object.entries(source).slice(0, MAX_CONTRIBUTION_COLLECTION)) {
162
+ const normalized = contributionJson(item, depth + 1, seen);
163
+ if (normalized !== undefined) result[boundedString(key, 200)] = normalized;
164
+ }
165
+ seen.delete(value);
166
+ return result;
167
+ }
168
+
169
+ export function normalizeContributions(value) {
170
+ if (!Array.isArray(value)) return [];
171
+ return value.slice(0, MAX_CONTRIBUTIONS).flatMap((candidate) => {
172
+ const item = record(candidate);
173
+ const placement = record(item?.placement);
174
+ const source = relativeContributionPath(item?.source);
175
+ if (
176
+ item?.schema !== 'supercode/contribution-v1' ||
177
+ typeof item.id !== 'string' || !item.id.trim() ||
178
+ typeof item.kind !== 'string' || !item.kind.trim() ||
179
+ source === null
180
+ ) return [];
181
+ const data = contributionJson(item.data);
182
+ if (data === undefined) return [];
183
+ return [{
184
+ schema: 'supercode/contribution-v1',
185
+ id: boundedString(item.id, 200),
186
+ kind: boundedString(item.kind, 100),
187
+ ...(typeof item.title === 'string' ? { title: boundedString(item.title, 500) } : {}),
188
+ ...(placement ? { placement: {
189
+ ...(typeof placement.surface === 'string' ? { surface: boundedString(placement.surface, 100) } : {}),
190
+ ...(typeof placement.region === 'string' ? { region: boundedString(placement.region, 100) } : {}),
191
+ } } : {}),
192
+ data,
193
+ source,
194
+ }];
195
+ });
196
+ }
197
+
198
+ export function selectContributions(contributions, query = {}) {
199
+ return normalizeContributions(contributions).filter((contribution) => (
200
+ (query.kind === undefined || contribution.kind === query.kind) &&
201
+ (query.surface === undefined || contribution.placement?.surface === query.surface) &&
202
+ (query.region === undefined || contribution.placement?.region === query.region)
203
+ ));
204
+ }
205
+
206
+ function readAgentPackage(value) {
207
+ const agentPackage = record(value);
208
+ const capabilities = record(agentPackage?.capabilities);
209
+ const storage = record(agentPackage?.storage);
210
+ const relativePath = relativeContributionPath(storage?.relativePath);
211
+ if (
212
+ agentPackage?.schemaVersion !== 1 ||
213
+ typeof agentPackage.id !== 'string' ||
214
+ typeof agentPackage.name !== 'string' ||
215
+ typeof agentPackage.version !== 'string' ||
216
+ !capabilities ||
217
+ !Array.isArray(capabilities.required) ||
218
+ !Array.isArray(capabilities.optional) ||
219
+ !storage ||
220
+ relativePath === null
221
+ ) return null;
222
+ const resources = record(agentPackage.resources);
223
+ return {
224
+ id: boundedString(agentPackage.id, 200),
225
+ name: boundedString(agentPackage.name, 500),
226
+ version: boundedString(agentPackage.version, 100),
227
+ description: typeof agentPackage.description === 'string'
228
+ ? boundedString(agentPackage.description, 2_000)
229
+ : null,
230
+ capabilities: {
231
+ required: capabilities.required.filter((item) => typeof item === 'string').slice(0, 100).map((item) => boundedString(item, 200)),
232
+ optional: capabilities.optional.filter((item) => typeof item === 'string').slice(0, 100).map((item) => boundedString(item, 200)),
233
+ },
234
+ storage: { relativePath },
235
+ resources: resources ? Object.fromEntries(Object.entries(resources).flatMap(([id, candidate]) => {
236
+ const state = record(candidate);
237
+ if (state?.schema !== 'supercode/package-resource-state-v1') return [];
238
+ if (state.status === 'absent' && typeof state.contributionId === 'string') {
239
+ return [[boundedString(id, 200), {
240
+ schema: 'supercode/package-resource-state-v1',
241
+ status: 'absent',
242
+ contributionId: boundedString(state.contributionId, 200),
243
+ }]];
244
+ }
245
+ if (state.status === 'error' && typeof state.contributionId === 'string' && typeof state.message === 'string') {
246
+ return [[boundedString(id, 200), {
247
+ schema: 'supercode/package-resource-state-v1',
248
+ status: 'error',
249
+ contributionId: boundedString(state.contributionId, 200),
250
+ message: boundedString(state.message),
251
+ }]];
252
+ }
253
+ const resource = record(state?.resource);
254
+ const data = contributionJson(resource?.data);
255
+ if (
256
+ state?.status !== 'ready' ||
257
+ resource?.schema !== 'supercode/package-resource-v1' ||
258
+ typeof resource.contributionId !== 'string' ||
259
+ !['json', 'text'].includes(resource.format) ||
260
+ typeof resource.mediaType !== 'string' ||
261
+ data === undefined
262
+ ) return [];
263
+ return [[boundedString(id, 200), {
264
+ schema: 'supercode/package-resource-state-v1',
265
+ status: 'ready',
266
+ resource: {
267
+ schema: 'supercode/package-resource-v1',
268
+ contributionId: boundedString(resource.contributionId, 200),
269
+ format: resource.format,
270
+ mediaType: boundedString(resource.mediaType, 200),
271
+ data,
272
+ },
273
+ }]];
274
+ })) : {},
275
+ };
276
+ }
277
+
278
+ function readAgentPackageCapabilityState(value) {
279
+ const state = record(value);
280
+ if (!state) return null;
281
+ const fields = ['availableRequired', 'missingRequired', 'enabledOptional', 'unavailableOptional'];
282
+ if (!fields.every((field) => Array.isArray(state[field]))) return null;
283
+ return {
284
+ ready: state.ready === true,
285
+ ...Object.fromEntries(fields.map((field) => [
286
+ field,
287
+ state[field].filter((item) => typeof item === 'string').slice(0, 100).map((item) => boundedString(item, 200)),
288
+ ])),
289
+ };
290
+ }
291
+
124
292
  export function relativeAge(updatedAt, now = Date.now()) {
125
293
  if (typeof updatedAt !== 'number' || !Number.isFinite(updatedAt) || updatedAt <= 0) return '';
126
294
  const delta = Math.max(0, now - updatedAt);
@@ -896,6 +1064,13 @@ export function normalizeUiState(value) {
896
1064
  attached: readAttached(raw.attached),
897
1065
  owned: readAttached(raw.owned),
898
1066
  attachError: attachError && typeof attachError.key === 'string' && typeof attachError.message === 'string' ? { key: attachError.key, message: attachError.message } : null,
1067
+ agentPackage: readAgentPackage(raw.agentPackage),
1068
+ contributions: normalizeContributions(raw.contributions),
1069
+ agentPackageError: typeof raw.agentPackageError === 'string' ? boundedString(raw.agentPackageError) : null,
1070
+ agentPackageCapabilityState: readAgentPackageCapabilityState(raw.agentPackageCapabilityState),
1071
+ agentPackageCapabilityError: typeof raw.agentPackageCapabilityError === 'string'
1072
+ ? boundedString(raw.agentPackageCapabilityError)
1073
+ : null,
899
1074
  };
900
1075
  }
901
1076