@ikenga/contract 0.7.0 → 0.9.1

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 (54) hide show
  1. package/README.md +56 -11
  2. package/dist/canvas/Canvas.d.ts +7 -0
  3. package/dist/canvas/Canvas.d.ts.map +1 -0
  4. package/dist/canvas/Canvas.js +115 -0
  5. package/dist/canvas/Canvas.js.map +1 -0
  6. package/dist/canvas/canvas.css +579 -0
  7. package/dist/canvas/index.d.ts +7 -0
  8. package/dist/canvas/index.d.ts.map +1 -0
  9. package/dist/canvas/index.js +4 -0
  10. package/dist/canvas/index.js.map +1 -0
  11. package/dist/canvas/types.d.ts +45 -0
  12. package/dist/canvas/types.d.ts.map +1 -0
  13. package/dist/canvas/types.js +2 -0
  14. package/dist/canvas/types.js.map +1 -0
  15. package/dist/canvas/use-drag-snap.d.ts +33 -0
  16. package/dist/canvas/use-drag-snap.d.ts.map +1 -0
  17. package/dist/canvas/use-drag-snap.js +73 -0
  18. package/dist/canvas/use-drag-snap.js.map +1 -0
  19. package/dist/canvas/use-pan-zoom.d.ts +32 -0
  20. package/dist/canvas/use-pan-zoom.d.ts.map +1 -0
  21. package/dist/canvas/use-pan-zoom.js +161 -0
  22. package/dist/canvas/use-pan-zoom.js.map +1 -0
  23. package/dist/host-verbs.d.ts +194 -0
  24. package/dist/host-verbs.d.ts.map +1 -0
  25. package/dist/host-verbs.js +15 -0
  26. package/dist/host-verbs.js.map +1 -0
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/manifest.d.ts +376 -19
  32. package/dist/manifest.d.ts.map +1 -1
  33. package/dist/manifest.js +95 -4
  34. package/dist/manifest.js.map +1 -1
  35. package/dist/registry.d.ts +364 -36
  36. package/dist/registry.d.ts.map +1 -1
  37. package/dist/registry.js +9 -0
  38. package/dist/registry.js.map +1 -1
  39. package/dist/scopes.js +1 -1
  40. package/dist/scopes.js.map +1 -1
  41. package/package.json +24 -2
  42. package/schemas/registry/index-v1.json +11 -0
  43. package/src/canvas/Canvas.tsx +161 -0
  44. package/src/canvas/canvas.css +579 -0
  45. package/src/canvas/index.ts +14 -0
  46. package/src/canvas/types.ts +48 -0
  47. package/src/canvas/use-drag-snap.ts +107 -0
  48. package/src/canvas/use-pan-zoom.ts +211 -0
  49. package/src/host-verbs.ts +207 -0
  50. package/src/index.ts +1 -0
  51. package/src/manifest.test.ts +97 -0
  52. package/src/manifest.ts +109 -4
  53. package/src/registry.ts +9 -0
  54. package/src/scopes.ts +1 -1
package/src/manifest.ts CHANGED
@@ -11,7 +11,9 @@
11
11
  import { z } from 'zod';
12
12
  import { EngineProvidesSchema } from './engine/index.js';
13
13
 
14
- export const IKENGA_API_VERSION = 1 as const;
14
+ // v2 (WP-05): added capabilities.sqlite + permissions["sqlite.tables"];
15
+ // permissions["supabase.tables"] kept as a compat alias for api=1 manifests.
16
+ export const IKENGA_API_VERSION = 2 as const;
15
17
  export const IKENGA_API_MIN_SUPPORTED = 1 as const;
16
18
 
17
19
  // ---------- Sub-schemas ----------
@@ -60,6 +62,12 @@ export const PermissionsSchema = z.object({
60
62
  'fs.read': z.array(z.string()).default([]),
61
63
  'fs.write': z.array(z.string()).default([]),
62
64
  net: z.array(z.string()).default([]),
65
+ /** Local SQLite table patterns; validated against tables.json at install time.
66
+ * For api ≥ 2 manifests. Replaces `supabase.tables`. */
67
+ 'sqlite.tables': z.array(z.string()).default([]),
68
+ /** @deprecated api=1 compat alias for `sqlite.tables`. New manifests should
69
+ * use `sqlite.tables` instead. Kept so ikenga_api="1" manifests parse
70
+ * without errors during the transition window. */
63
71
  'supabase.tables': z.array(z.string()).default([]),
64
72
  'vault.keys': z.array(z.string()).default([]),
65
73
  }).default({});
@@ -135,6 +143,46 @@ export const CronEntrySchema = z.object({
135
143
  env_from_settings: z.array(z.string()).default([]),
136
144
  });
137
145
 
146
+ /** Local SQLite capability (api ≥ 2). Threads the logical db name into the
147
+ * iframe host context so the pkg can call `db_query` without hard-coding it.
148
+ * Mirrors `SqliteCapability` in `shell/src-tauri/src/pkg/manifest.rs`. */
149
+ export const SqliteCapabilitySchema = z.object({
150
+ /** Logical DB name. Currently only `"ikenga.local"` is supported.
151
+ * Defaults to `"ikenga.local"` when omitted. */
152
+ db: z.string().default('ikenga.local'),
153
+ });
154
+ export type SqliteCapability = z.infer<typeof SqliteCapabilitySchema>;
155
+
156
+ /** Supabase capability. Mirrors `SupabaseCapability` in
157
+ * `shell/src-tauri/src/pkg/manifest.rs`. */
158
+ export const SupabaseCapabilitySchema = z.object({
159
+ /** When true, mint fails if the Supabase vault keys are missing; when
160
+ * false/omitted, missing keys surface as `supabase: null` in host context. */
161
+ required: z.boolean().default(false),
162
+ });
163
+ export type SupabaseCapability = z.infer<typeof SupabaseCapabilitySchema>;
164
+
165
+ /** Native child-webview capability. Mirrors `WebviewCapability` in
166
+ * `shell/src-tauri/src/pkg/manifest.rs`. */
167
+ export const WebviewCapabilitySchema = z.object({
168
+ /** Whether this pkg may create child webviews via the kernel. Required for
169
+ * any `ui.routes[]` entry with `kind = "webview"` to mount. */
170
+ child_webviews: z.boolean().default(false),
171
+ /** Named cookie/data partitions; empty = the implicit "default" partition. */
172
+ partitions: z.array(z.string()).default([]),
173
+ });
174
+ export type WebviewCapability = z.infer<typeof WebviewCapabilitySchema>;
175
+
176
+ /** Agent-ops host-bridge capability (api ≥ 2). Opt-in to the privileged
177
+ * `host.agentOps.*` verbs (run-now / enable-disable / list-jobs) the shell
178
+ * exposes for the agent-ops observability pkg — these reach the always-on
179
+ * cron daemon's localhost trigger endpoint and read the daemon's config +
180
+ * state files, hops an iframe cannot make itself. Presence of the block is
181
+ * the gate (mirrors the `capabilities.sqlite` opt-in). Mirrors
182
+ * `AgentOpsCapability` in `shell/src-tauri/src/pkg/manifest.rs`. */
183
+ export const AgentOpsCapabilitySchema = z.object({});
184
+ export type AgentOpsCapability = z.infer<typeof AgentOpsCapabilitySchema>;
185
+
138
186
  export const WindowBlockSchema = z.object({
139
187
  label: z.string(),
140
188
  url: z.string(),
@@ -159,6 +207,39 @@ export const ScreenshotSchema = z.object({
159
207
  });
160
208
  export type Screenshot = z.infer<typeof ScreenshotSchema>;
161
209
 
210
+ /** Forward-dependency source for a `requires[]` entry. Mirrors the Rust
211
+ * `RequireSource` enum (`pkg/manifest.rs`) and the registry `ProvenanceSource`
212
+ * set. Optional on an entry — absent means the resolver looks the dep up in the
213
+ * store registry / catalog. */
214
+ export const RequireSourceSchema = z.enum(['git', 'npx', 'catalog', 'local']);
215
+ export type RequireSource = z.infer<typeof RequireSourceSchema>;
216
+
217
+ /**
218
+ * One forward-dependency edge (`requires[]` element, ADR-015 §3 / Ọba WP-11).
219
+ * Names a standalone Ọba primitive a pkg `requires`; the resolver (WP-13/14)
220
+ * installs the closure at install/enable. This is a SEPARATE graph from a
221
+ * skill's `SKILL.md` `depends_on` (the G-04 authoring star, `skill-core`-only):
222
+ * a pkg `requires` MAY reference any primitive, and the publish-time lift
223
+ * (WP-12) compiles `depends_on` into this field. `.strict()` mirrors the Rust
224
+ * `deny_unknown_fields` on `RequiresEntry`. Source of truth: the Rust struct in
225
+ * `shell/src-tauri/src/pkg/manifest.rs` — keep in lockstep.
226
+ */
227
+ export const RequiresEntrySchema = z
228
+ .object({
229
+ /** Primitive kind: skill | agent | command | hook | mcp. Kept a string so a
230
+ * future kind doesn't break old manifests. */
231
+ kind: z.string(),
232
+ /** Primitive name (e.g. `skill-core`, `@ikenga/studio-beat-detect`). */
233
+ name: z.string(),
234
+ /** Optional fetch source. */
235
+ source: RequireSourceSchema.optional(),
236
+ /** Optional git tag/branch or version pin. The shape leaves room for an
237
+ * explicit semver range later without another schema break. */
238
+ ref: z.string().optional(),
239
+ })
240
+ .strict();
241
+ export type RequiresEntry = z.infer<typeof RequiresEntrySchema>;
242
+
162
243
  // ---------- Manifest ----------
163
244
 
164
245
  export const ManifestSchema = z.object({
@@ -176,9 +257,13 @@ export const ManifestSchema = z.object({
176
257
  targets: z.array(z.string()).default([]),
177
258
 
178
259
  // Capability blocks (all optional — kernel walks present blocks)
179
- skills: z.string().optional(),
180
- commands: z.string().optional(),
181
- agents: z.string().optional(),
260
+ // NOTE (WP-17, ADR-015 decision 4): the `skills`/`commands`/`agents`
261
+ // asset-bundling fields were HARD-RETIRED (lockstep with the Rust
262
+ // `Manifest`). A pkg no longer embeds Claude-config assets; it only
263
+ // `requires` standalone Ọba primitives. The schema is `.strict()`, so a
264
+ // manifest still declaring any of them now FAILS validation (no deprecation
265
+ // window). The shell builtin `com.ikenga.iyke` places its skill/commands by
266
+ // convention from on-disk folders, not via a manifest field.
182
267
  mcp: z.array(McpServerSchema).default([]),
183
268
  sidecars: z.array(SidecarSpecSchema).default([]),
184
269
  permissions: PermissionsSchema,
@@ -190,6 +275,16 @@ export const ManifestSchema = z.object({
190
275
  window: WindowBlockSchema.optional(),
191
276
  queries: QueriesBlockSchema.optional(),
192
277
 
278
+ /** Optional capabilities the host resolves and injects at iframe-mount
279
+ * time via the AppBridge `hostContext` handshake. Mirrors the Rust
280
+ * `CapabilitiesBlock` in `shell/src-tauri/src/pkg/manifest.rs`. */
281
+ capabilities: z.object({
282
+ supabase: SupabaseCapabilitySchema.optional(),
283
+ sqlite: SqliteCapabilitySchema.optional(),
284
+ webview: WebviewCapabilitySchema.optional(),
285
+ agentOps: AgentOpsCapabilitySchema.optional(),
286
+ }).optional(),
287
+
193
288
  /**
194
289
  * Engine-adapter manifest block. Present iff this pkg is an engine-*
195
290
  * adapter. Declares the agent id, display name, capability snapshot,
@@ -205,6 +300,16 @@ export const ManifestSchema = z.object({
205
300
  * UI (engines, MCP-only servers) typically leave this empty.
206
301
  */
207
302
  screenshots: z.array(ScreenshotSchema).default([]),
303
+
304
+ /**
305
+ * Forward dependency declarations (ADR-015 §3 / Ọba WP-11). Each entry names a
306
+ * standalone primitive this pkg `requires`; the Ọba resolver installs the
307
+ * closure at install/enable. A SEPARATE graph from a skill's `depends_on` (the
308
+ * G-04 authoring star). Empty by default so pre-Phase-4 manifests are
309
+ * unaffected. Mirrors `requires: Vec<RequiresEntry>` on the Rust `Manifest`
310
+ * (`pkg/manifest.rs`) — keep in lockstep (`deny_unknown_fields`).
311
+ */
312
+ requires: z.array(RequiresEntrySchema).default([]),
208
313
  });
209
314
 
210
315
  export type Manifest = z.infer<typeof ManifestSchema>;
package/src/registry.ts CHANGED
@@ -105,6 +105,15 @@ export const RegistryEntrySchema = z.object({
105
105
  * Lets the shell render a thumb without fetching the per-pkg detail file.
106
106
  */
107
107
  screenshot: z.string().url().optional(),
108
+ /**
109
+ * Catalog visibility. `"hidden"` keeps the pkg installable by exact name
110
+ * (CLI `add`/`update`, registry install, update detection) but omits it
111
+ * from the default browse/catalog surfaces — used for dev/test fixtures
112
+ * and scaffolds (e.g. `pkg-hello`, `pkg-engine-noop`, the cursor-agent
113
+ * scaffold). Absent ⇒ treated as `"public"`. Set by the publish pipeline's
114
+ * curation step (`ikenga-pkgs/scripts/update-registry-index.mjs`).
115
+ */
116
+ visibility: z.enum(['public', 'hidden']).optional(),
108
117
  });
109
118
  export type RegistryEntry = z.infer<typeof RegistryEntrySchema>;
110
119
 
package/src/scopes.ts CHANGED
@@ -41,7 +41,7 @@ export const SCOPE_CATALOGUE: ScopeDef[] = [
41
41
  { scope: 'fs:write', description: 'Write files inside the shell-managed sandbox.', sensitive: true },
42
42
 
43
43
  // engine
44
- { scope: 'engine:invoke', description: 'Start sessions and stream from the active AI engine.' },
44
+ { scope: 'engine:invoke', description: 'Start sessions and stream from the active AI engine.', sensitive: true },
45
45
  { scope: 'engine:register_mcp', description: 'Register additional MCP servers with the engine.', sensitive: true },
46
46
 
47
47
  // shell chrome