substrattice 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.
package/dist/bridge.js CHANGED
@@ -170,11 +170,20 @@ export class OmniBridge {
170
170
  async shareArtifact(input) {
171
171
  if (!this.httpUrl)
172
172
  throw new Error("not connected");
173
+ // Build only schema-recognized keys: the server wants projectId/roomId (a
174
+ // strict zod schema 400s on `room`/`project`). undefined keys are omitted.
173
175
  const body = {
174
- ...input,
175
- room: input.project ? undefined : (input.room ?? this.room),
176
+ kind: input.kind,
177
+ title: input.title,
178
+ content: input.content,
179
+ url: input.url,
180
+ language: input.language,
176
181
  source: input.source ?? "claude-code",
177
182
  };
183
+ if (input.project)
184
+ body.projectId = input.project;
185
+ else
186
+ body.roomId = input.room ?? this.room;
178
187
  const res = await fetch(`${this.httpUrl}/api/artifacts`, {
179
188
  method: "POST",
180
189
  headers: {
@@ -189,6 +198,27 @@ export class OmniBridge {
189
198
  const data = (await res.json());
190
199
  return { id: data.artifact.id };
191
200
  }
201
+ /** Upload a FILE into the room (a real downloadable file artifact). Text by
202
+ * default; pass base64 for binary. Returns the created artifact id. */
203
+ async uploadFile(input) {
204
+ if (!this.httpUrl)
205
+ throw new Error("not connected");
206
+ const bytes = Buffer.from(input.content, input.base64 ? "base64" : "utf8");
207
+ const res = await fetch(`${this.httpUrl}/api/uploads?room=${encodeURIComponent(this.room)}`, {
208
+ method: "POST",
209
+ headers: {
210
+ "x-omni-csrf": "1",
211
+ "content-type": input.contentType ?? "text/plain; charset=utf-8",
212
+ "x-filename": encodeURIComponent(input.filename),
213
+ cookie: `omni_session=${this.token}`,
214
+ },
215
+ body: bytes,
216
+ });
217
+ if (!res.ok)
218
+ throw new Error(`upload failed: HTTP ${res.status} ${await res.text()}`);
219
+ const data = (await res.json());
220
+ return { id: data.artifact.id };
221
+ }
192
222
  /** Recent room history (actions, artifacts, activity) — the audit/activity feed. */
193
223
  async history(limit = 20) {
194
224
  if (!this.httpUrl || !this.room)
package/dist/index.js CHANGED
@@ -148,6 +148,20 @@ const tools = [
148
148
  required: ["connector", "action"],
149
149
  },
150
150
  },
151
+ {
152
+ name: "omni_upload",
153
+ description: "Upload a FILE into the room — a real, downloadable file artifact (code, a doc, data), not pasted text. Provide a filename + content (text); set base64:true for binary. Use this to hand a teammate an actual file.",
154
+ inputSchema: {
155
+ type: "object",
156
+ properties: {
157
+ filename: { type: "string", description: "File name, e.g. parser.ts or report.md." },
158
+ content: { type: "string", description: "File contents (utf-8 text, or base64 if base64:true)." },
159
+ content_type: { type: "string", description: "MIME type (optional), e.g. text/markdown." },
160
+ base64: { type: "boolean", description: "True if content is base64-encoded binary." },
161
+ },
162
+ required: ["filename", "content"],
163
+ },
164
+ },
151
165
  {
152
166
  name: "omni_history",
153
167
  description: "Read the room's recent history — the audit/activity feed of governed actions (who ran what, who approved, outcome), shared artifacts, and agent sandbox activity. Use it to catch up on what's happened.",
@@ -330,6 +344,22 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
330
344
  ? `Proposed ${connector}.${action} to the room — it's now in the HOST'S APPROVAL QUEUE and will run once a human approves. The outcome will appear in the room.`
331
345
  : `Ran ${connector}.${action} (read-only) — the result is posted in the room.`);
332
346
  }
347
+ if (name === "omni_upload") {
348
+ if (!bridge.connected)
349
+ return text("Not connected — call omni_connect first.");
350
+ try {
351
+ const { id } = await bridge.uploadFile({
352
+ filename: String(args.filename || "file.txt"),
353
+ content: String(args.content ?? ""),
354
+ contentType: args.content_type ? String(args.content_type) : undefined,
355
+ base64: !!args.base64,
356
+ });
357
+ return text(`Uploaded "${args.filename}" as a downloadable file artifact (${id}). The room can open/download it.`);
358
+ }
359
+ catch (e) {
360
+ return text(`Upload failed: ${e.message}`);
361
+ }
362
+ }
333
363
  if (name === "omni_history") {
334
364
  if (!bridge.connected)
335
365
  return text("Not connected — call omni_connect first.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrattice",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "mcpName": "io.github.gen-rl-millz/substrattice",
5
5
  "type": "module",
6
6
  "description": "Omni MCP server — lets a live agent session (Claude Code, …) join Omni rooms and answer as itself, memory + tools intact. Spin up/join a room, wait for work, reply, and share artifacts.",