@1agh/maude 0.53.2 → 0.55.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.
- package/apps/studio/annotations-layer.tsx +11 -1
- package/apps/studio/api.ts +13 -7
- package/apps/studio/bin/screenshot.sh +43 -3
- package/apps/studio/build.ts +37 -3
- package/apps/studio/canvas-build-sandbox.ts +101 -9
- package/apps/studio/canvas-build-worker.ts +7 -1
- package/apps/studio/canvas-build.ts +9 -1
- package/apps/studio/client/app.jsx +226 -25
- package/apps/studio/client/export-center.jsx +10 -2
- package/apps/studio/client/github.js +7 -0
- package/apps/studio/client/panels/CloudBar.jsx +461 -40
- package/apps/studio/client/panels/SettingsPanel.jsx +6 -1
- package/apps/studio/client/styles/3-shell-maude.css +30 -0
- package/apps/studio/client/styles/4-components.css +40 -0
- package/apps/studio/cloud/endpoints.ts +48 -6
- package/apps/studio/cloud-build.ts +208 -0
- package/apps/studio/collab/room.ts +43 -7
- package/apps/studio/context.ts +12 -5
- package/apps/studio/dist/client.bundle.js +983 -983
- package/apps/studio/dist/comment-mount.js +2 -2
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/git/repo-lock.ts +305 -0
- package/apps/studio/git/service.ts +171 -21
- package/apps/studio/http.ts +159 -13
- package/apps/studio/inspect.ts +66 -6
- package/apps/studio/server.ts +114 -17
- package/apps/studio/session-scope.ts +101 -0
- package/apps/studio/sync/autocommit.ts +84 -46
- package/apps/studio/sync/index.ts +20 -0
- package/apps/studio/test/canvas-origin-gate.test.ts +61 -0
- package/apps/studio/test/canvas-shell-base.test.ts +107 -0
- package/apps/studio/test/cloud-build.test.ts +95 -0
- package/apps/studio/test/cloud-endpoints.test.ts +231 -4
- package/apps/studio/test/cloud-shell-surfaces.test.ts +31 -2
- package/apps/studio/test/collab-readonly-gate.test.ts +194 -0
- package/apps/studio/test/git-system-engine.test.ts +135 -0
- package/apps/studio/test/read-only-gate.test.ts +8 -0
- package/apps/studio/test/repo-concurrency.test.ts +146 -0
- package/apps/studio/test/repo-lock.test.ts +350 -0
- package/apps/studio/test/server-lifecycle.test.ts +11 -1
- package/apps/studio/test/session-runtime-state.test.ts +226 -0
- package/apps/studio/test/session-scope.test.ts +100 -0
- package/apps/studio/test/shell-importmap.test.ts +8 -1
- package/apps/studio/test/sync-autocommit.test.ts +76 -0
- package/apps/studio/test/sync-hardening.test.ts +75 -0
- package/apps/studio/use-collab.tsx +21 -1
- package/apps/studio/whats-new.json +54 -0
- package/apps/studio/ws.ts +44 -8
- package/cli/commands/kg.mjs +49 -19
- package/cli/lib/gitignore-block.mjs +3 -0
- package/package.json +11 -9
- package/plugins/design/dependencies.json +1 -1
- package/plugins/design/templates/_shell.html +66 -32
- package/plugins/flow/.claude-plugin/config.schema.json +1 -1
- package/plugins/flow/dependencies.json +1 -1
package/apps/studio/ws.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { Api } from './api.ts';
|
|
|
9
9
|
import type { Collab, RoomConn } from './collab/index.ts';
|
|
10
10
|
import type { Context } from './context.ts';
|
|
11
11
|
import { createHmrBroadcaster } from './hmr-broadcast.ts';
|
|
12
|
-
import type {
|
|
12
|
+
import type { InspectRegistry } from './inspect.ts';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Per-connection state. `kind` discriminates between the legacy JSON
|
|
@@ -29,6 +29,11 @@ export type WsData =
|
|
|
29
29
|
* per session, and a handshake is the one moment the session is
|
|
30
30
|
* unambiguous. */
|
|
31
31
|
readOnly: boolean;
|
|
32
|
+
/** WHOSE socket this is — Cloud Phase 27 D3. Same reasoning as `readOnly`
|
|
33
|
+
* one line up, for the other thing a cell has more than one of. `''` on
|
|
34
|
+
* a desktop, which is what makes every broadcast below reach everybody
|
|
35
|
+
* exactly as it always did. */
|
|
36
|
+
session: string;
|
|
32
37
|
}
|
|
33
38
|
| {
|
|
34
39
|
id: string;
|
|
@@ -39,6 +44,14 @@ export type WsData =
|
|
|
39
44
|
* canvas iframe origin, whose sync frames go through the DDR-122
|
|
40
45
|
* origin gate in collab/room.ts. Set at upgrade time in server.ts. */
|
|
41
46
|
realm: 'main' | 'canvas';
|
|
47
|
+
/** Cloud collab lane (RCA issue-cloud-live-collaboration-dead) — the
|
|
48
|
+
* role this socket was opened under, stamped at upgrade time from the
|
|
49
|
+
* proxy's injected header (fail-closed in a cell, always false on a
|
|
50
|
+
* loopback desktop). A read-only collab socket receives everything and
|
|
51
|
+
* publishes awareness (presence is the point), but its sync writes are
|
|
52
|
+
* gated to the comment lane in collab/room.ts — the WS mirror of the
|
|
53
|
+
* role matrix's `viewer.comment === true`. */
|
|
54
|
+
readOnly?: boolean;
|
|
42
55
|
}
|
|
43
56
|
| {
|
|
44
57
|
// T2 (9.1-A) — HMR-only socket for the segregated canvas origin. Receives
|
|
@@ -139,7 +152,10 @@ export interface Ws {
|
|
|
139
152
|
export function createWs(
|
|
140
153
|
ctx: Context,
|
|
141
154
|
api: Api,
|
|
142
|
-
|
|
155
|
+
/** Cloud Phase 27 D3 — one inspector per member, not one per process. Every
|
|
156
|
+
* read/write below resolves through the socket's own session key, so a
|
|
157
|
+
* desktop (key `''`) keeps hitting the single instance it always had. */
|
|
158
|
+
inspects: InspectRegistry,
|
|
143
159
|
collab: Collab,
|
|
144
160
|
activity: Activity,
|
|
145
161
|
acp: Acp
|
|
@@ -156,10 +172,16 @@ export function createWs(
|
|
|
156
172
|
|
|
157
173
|
// Privileged inspector feed — comments, selection, ai-activity, git-lifecycle,
|
|
158
174
|
// sync:status, fs:*. ONLY the same-origin inspector clients (the shell) get it.
|
|
159
|
-
function broadcast(payload: unknown) {
|
|
175
|
+
function broadcast(payload: unknown, session?: string) {
|
|
160
176
|
const msg = typeof payload === 'string' ? payload : JSON.stringify(payload);
|
|
161
177
|
for (const ws of clients) {
|
|
162
178
|
if (ws.data.kind !== 'inspector') continue;
|
|
179
|
+
// D3 — an event ABOUT one member goes only to that member. `session` is
|
|
180
|
+
// set by the emitter (inspect.ts stamps its own key); everything else —
|
|
181
|
+
// fs changes, comments, git lifecycle, sync status — is about the
|
|
182
|
+
// PROJECT and reaches everyone, which is why the audience is opt-in
|
|
183
|
+
// rather than the default.
|
|
184
|
+
if (session && ws.data.session !== session) continue;
|
|
163
185
|
send(ws, msg);
|
|
164
186
|
}
|
|
165
187
|
}
|
|
@@ -177,8 +199,10 @@ export function createWs(
|
|
|
177
199
|
|
|
178
200
|
// Wire bus -> WS broadcasts. inspect.ts emits 'selected' / 'active' after every
|
|
179
201
|
// state write; fs-watch.ts emits 'fs:*' on every save.
|
|
180
|
-
ctx.bus.on('selected', (sel) =>
|
|
181
|
-
|
|
202
|
+
ctx.bus.on('selected', (sel, meta) =>
|
|
203
|
+
broadcast({ type: 'selected', selected: sel }, meta?.session)
|
|
204
|
+
);
|
|
205
|
+
ctx.bus.on('active', (file, meta) => broadcast({ type: 'active', file }, meta?.session));
|
|
182
206
|
ctx.bus.on('fs:html', (file) => broadcast({ type: 'fs:html', file }));
|
|
183
207
|
ctx.bus.on('fs:css', (file) => broadcast({ type: 'fs:css', file }));
|
|
184
208
|
ctx.bus.on('fs:json', (file) => broadcast({ type: 'fs:json', file }));
|
|
@@ -259,11 +283,13 @@ export function createWs(
|
|
|
259
283
|
function bindCollab(
|
|
260
284
|
ws: ServerWebSocket<WsData>,
|
|
261
285
|
slug: string,
|
|
262
|
-
realm: 'main' | 'canvas'
|
|
286
|
+
realm: 'main' | 'canvas',
|
|
287
|
+
readOnly: boolean
|
|
263
288
|
): RoomConn {
|
|
264
289
|
const conn: RoomConn = {
|
|
265
290
|
id: ws.data.id,
|
|
266
291
|
realm,
|
|
292
|
+
readOnly,
|
|
267
293
|
send(payload: Uint8Array) {
|
|
268
294
|
try {
|
|
269
295
|
// Bun's ws.send accepts Uint8Array directly as binary.
|
|
@@ -281,7 +307,12 @@ export function createWs(
|
|
|
281
307
|
async open(ws) {
|
|
282
308
|
if (ws.data.kind === 'collab') {
|
|
283
309
|
const room = collab.registry.get(ws.data.slug);
|
|
284
|
-
const conn = bindCollab(
|
|
310
|
+
const conn = bindCollab(
|
|
311
|
+
ws,
|
|
312
|
+
ws.data.slug,
|
|
313
|
+
ws.data.realm ?? 'main',
|
|
314
|
+
ws.data.readOnly === true
|
|
315
|
+
);
|
|
285
316
|
await room.connect(conn);
|
|
286
317
|
return;
|
|
287
318
|
}
|
|
@@ -299,7 +330,11 @@ export function createWs(
|
|
|
299
330
|
// opening mid-edit seeds its overlay state (Phase 13). Inspector-origin
|
|
300
331
|
// sockets only — `canvas-hmr` sockets get no snapshot by design and rely
|
|
301
332
|
// on live `activity` broadcasts.
|
|
302
|
-
send(ws, {
|
|
333
|
+
send(ws, {
|
|
334
|
+
type: 'snapshot',
|
|
335
|
+
state: inspects.for(ws.data.kind === 'inspector' ? ws.data.session : '').state,
|
|
336
|
+
activity: activity.state,
|
|
337
|
+
});
|
|
303
338
|
},
|
|
304
339
|
async close(ws) {
|
|
305
340
|
if (ws.data.kind === 'acp') {
|
|
@@ -377,6 +412,7 @@ export function createWs(
|
|
|
377
412
|
});
|
|
378
413
|
return;
|
|
379
414
|
}
|
|
415
|
+
const inspect = inspects.for(ws.data.kind === 'inspector' ? ws.data.session : '');
|
|
380
416
|
if (msg.type === 'active' && typeof msg.file === 'string') inspect.setActive(msg.file);
|
|
381
417
|
else if (msg.type === 'tabs' && Array.isArray(msg.tabs)) inspect.setOpenTabs(msg.tabs);
|
|
382
418
|
else if (msg.type === 'select' && msg.selection) inspect.setSelected(msg.selection);
|
package/cli/commands/kg.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { basename, join, resolve } from 'node:path';
|
|
|
18
18
|
import { parseArgs } from '../lib/argv.mjs';
|
|
19
19
|
|
|
20
20
|
const CONFIG_PATH = '.ai/workflows.config.json';
|
|
21
|
-
const DEFAULT_ENGINE_VERSION = '
|
|
21
|
+
const DEFAULT_ENGINE_VERSION = 'v1.0.0';
|
|
22
22
|
const KGAI_REPO = 'kgaidev/kgai';
|
|
23
23
|
|
|
24
24
|
const VERBS = new Set([
|
|
@@ -195,21 +195,32 @@ function verbDoctor(state) {
|
|
|
195
195
|
async function verbCheckUpstream(state) {
|
|
196
196
|
const pinned = state.engineVersion;
|
|
197
197
|
process.stdout.write(`maude kg check-upstream\n\n pinned (engineVersion): ${pinned}\n`);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
198
|
+
const ghHeaders = { 'user-agent': 'maude-kg', accept: 'application/vnd.github+json' };
|
|
199
|
+
/** Asset names for one release ref, or null when the fetch itself failed. */
|
|
200
|
+
const assetsFor = async (path) => {
|
|
201
|
+
try {
|
|
202
|
+
const res = await fetch(`https://api.github.com/repos/${KGAI_REPO}/releases/${path}`, {
|
|
203
|
+
headers: ghHeaders,
|
|
204
|
+
signal: AbortSignal.timeout(15000),
|
|
205
|
+
});
|
|
206
|
+
if (!res.ok) return { ok: false, tag: null, assets: [] };
|
|
206
207
|
const rel = await res.json();
|
|
207
|
-
|
|
208
|
-
|
|
208
|
+
return { ok: true, tag: rel.tag_name, assets: (rel.assets ?? []).map((a) => a.name) };
|
|
209
|
+
} catch {
|
|
210
|
+
return null; // offline — best-effort
|
|
209
211
|
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const latestRel = await assetsFor('latest');
|
|
215
|
+
const latest = latestRel?.tag ?? null;
|
|
216
|
+
// The PINNED release is the one that matters: sync-kg.mjs downloads the
|
|
217
|
+
// desktop sidecars from `releases/download/<pinned>`. Reporting `latest`'s
|
|
218
|
+
// assets here said "✓" while the pinned release had been stripped of every
|
|
219
|
+
// asset upstream, so this check stayed green through a desktop build that was
|
|
220
|
+
// failing on exactly what it claims to verify (v0.53.2, kgai v0.1.9). A tag is
|
|
221
|
+
// a name, not a content hash — upstream can rewrite what it points at.
|
|
222
|
+
const pinnedRel = await assetsFor(`tags/${encodeURIComponent(pinned)}`);
|
|
223
|
+
const assets = pinnedRel?.assets ?? [];
|
|
213
224
|
if (!latest) {
|
|
214
225
|
process.stdout.write(' latest: unknown (offline) — using pinned.\n');
|
|
215
226
|
return 0;
|
|
@@ -218,12 +229,31 @@ async function verbCheckUpstream(state) {
|
|
|
218
229
|
process.stdout.write(
|
|
219
230
|
` status: ${latest === pinned ? '✓ up to date' : `⚠ upstream moved ${pinned} → ${latest}`}\n`
|
|
220
231
|
);
|
|
221
|
-
//
|
|
232
|
+
// Prebuilt assets ON THE PIN — what the desktop build actually downloads.
|
|
222
233
|
const hasDarwin = assets.some((a) => /kg-darwin/.test(a));
|
|
223
234
|
const hasKuzu = assets.some((a) => /libkuzu/.test(a));
|
|
224
|
-
|
|
225
|
-
process.stdout.write(
|
|
226
|
-
|
|
235
|
+
const hasLinux = assets.some((a) => /kg-linux/.test(a));
|
|
236
|
+
process.stdout.write(`\n prebuilt assets on the PIN (${pinned}):\n`);
|
|
237
|
+
if (pinnedRel === null) {
|
|
238
|
+
process.stdout.write(' (offline — not checked)\n');
|
|
239
|
+
} else if (!pinnedRel.ok) {
|
|
240
|
+
process.stdout.write(` ✗ release ${pinned} not found upstream\n`);
|
|
241
|
+
} else {
|
|
242
|
+
process.stdout.write(` macOS kg binary: ${hasDarwin ? '✓' : '✗'}\n`);
|
|
243
|
+
process.stdout.write(` linux kg binary: ${hasLinux ? '✓' : '✗'}\n`);
|
|
244
|
+
process.stdout.write(` libkuzu dylib/so: ${hasKuzu ? '✓' : '✗'}\n`);
|
|
245
|
+
}
|
|
246
|
+
// A pin whose assets are gone breaks `sync-kg.mjs`, which fails the desktop
|
|
247
|
+
// build for macOS and Linux. Exit non-zero so this can gate a release.
|
|
248
|
+
const pinBroken = pinnedRel !== null && (!pinnedRel.ok || !hasDarwin || !hasKuzu || !hasLinux);
|
|
249
|
+
if (pinBroken) {
|
|
250
|
+
process.stdout.write(
|
|
251
|
+
`\n ✗ the pinned release cannot build the desktop app — sync-kg.mjs downloads from\n` +
|
|
252
|
+
` releases/download/${pinned}, and those assets are missing. Upstream deleted or\n` +
|
|
253
|
+
` rewrote the release. Bump the pin to one that still carries them (verify\n` +
|
|
254
|
+
` compatibility first: CLI surface diff + a canonical-export comparison).\n`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
227
257
|
if (latest !== pinned) {
|
|
228
258
|
process.stdout.write(
|
|
229
259
|
'\n → Re-scan the capability surface (native --scope filter? kg import? Stop-hook/guessActor changes?),\n' +
|
|
@@ -231,7 +261,7 @@ async function verbCheckUpstream(state) {
|
|
|
231
261
|
' config.knowledgeGraph.engineVersion deliberately (never float — supply-chain surface, DDR-054/056).\n'
|
|
232
262
|
);
|
|
233
263
|
}
|
|
234
|
-
return 0;
|
|
264
|
+
return pinBroken ? 1 : 0;
|
|
235
265
|
}
|
|
236
266
|
|
|
237
267
|
// ── verb: session-sync (SessionStart hook — non-blocking pull) ──────────────
|
|
@@ -34,6 +34,9 @@ export function buildBlock(designRel = '.design', { s3Assets = false } = {}) {
|
|
|
34
34
|
`${root}/_server.log`,
|
|
35
35
|
`${root}/_server.lock`,
|
|
36
36
|
`${root}/_active.json`,
|
|
37
|
+
// Per-member siblings in a cloud cell (Phase 27 D3) — same runtime state,
|
|
38
|
+
// one file per person, and no more committable than the singleton.
|
|
39
|
+
`${root}/_active.*.json`,
|
|
37
40
|
`${root}/_sync.json`, // linked-mode offline/sync status (Task 8)
|
|
38
41
|
`${root}/_preflight.json`,
|
|
39
42
|
`${root}/_locator.json`, // regenerable slug→path index
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1agh/maude",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.55.0",
|
|
4
4
|
"description": "Marketplace of Claude Code plugins by Michal Dovrtěl: `design` (canvas-first design iteration) + `flow` (generic agentic workflow loop with .ai second brain). Ships the `maude` CLI (with `mdcc` legacy alias) to scaffold workspace, run the design dev server, and manage configs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -49,16 +49,18 @@
|
|
|
49
49
|
"test:e2e:desktop:lifecycle": "pnpm --filter @maude/desktop-e2e e2e:lifecycle",
|
|
50
50
|
"test:e2e:desktop:switchrepos": "pnpm --filter @maude/desktop-e2e e2e:switchrepos",
|
|
51
51
|
"test:e2e:desktop:onboarding": "pnpm --filter @maude/desktop-e2e e2e:onboarding",
|
|
52
|
-
"test:e2e:desktop:acp-cold-start": "pnpm --filter @maude/desktop-e2e e2e:acp-cold-start"
|
|
52
|
+
"test:e2e:desktop:acp-cold-start": "pnpm --filter @maude/desktop-e2e e2e:acp-cold-start",
|
|
53
|
+
"test:e2e:desktop:parity": "pnpm --filter @maude/desktop-e2e e2e:parity",
|
|
54
|
+
"test:e2e:desktop:parity:cloud": "pnpm --filter @maude/desktop-e2e e2e:parity:cloud"
|
|
53
55
|
},
|
|
54
56
|
"optionalDependencies": {
|
|
55
|
-
"@1agh/maude-darwin-arm64": "0.
|
|
56
|
-
"@1agh/maude-darwin-x64": "0.
|
|
57
|
-
"@1agh/maude-linux-arm64": "0.
|
|
58
|
-
"@1agh/maude-linux-arm64-musl": "0.
|
|
59
|
-
"@1agh/maude-linux-x64": "0.
|
|
60
|
-
"@1agh/maude-linux-x64-musl": "0.
|
|
61
|
-
"@1agh/maude-win32-x64": "0.
|
|
57
|
+
"@1agh/maude-darwin-arm64": "0.55.0",
|
|
58
|
+
"@1agh/maude-darwin-x64": "0.55.0",
|
|
59
|
+
"@1agh/maude-linux-arm64": "0.55.0",
|
|
60
|
+
"@1agh/maude-linux-arm64-musl": "0.55.0",
|
|
61
|
+
"@1agh/maude-linux-x64": "0.55.0",
|
|
62
|
+
"@1agh/maude-linux-x64-musl": "0.55.0",
|
|
63
|
+
"@1agh/maude-win32-x64": "0.55.0"
|
|
62
64
|
},
|
|
63
65
|
"files": [
|
|
64
66
|
"cli",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
},
|
|
157
157
|
"install": {
|
|
158
158
|
"preferred": "See docs/kgai-onboarding.md — download the pinned kgai release binary (kgai is capability-gated + opt-out; nothing to install to use classic .ai/ mode)",
|
|
159
|
-
"darwin": "curl -fsSL https://github.com/kgaidev/kgai/releases/download/
|
|
159
|
+
"darwin": "curl -fsSL https://github.com/kgaidev/kgai/releases/download/v1.0.0/kg-darwin-arm64 -o /usr/local/bin/kg && chmod +x /usr/local/bin/kg"
|
|
160
160
|
},
|
|
161
161
|
"autoInstall": false,
|
|
162
162
|
"fallbackBehavior": "Design DS/canvas/brand decisions are not recorded to the kgai graph; the classic .ai/ path (via /flow:record-ddr) and on-disk sidecars are unchanged.",
|
|
@@ -133,30 +133,30 @@
|
|
|
133
133
|
<script type="importmap">
|
|
134
134
|
{
|
|
135
135
|
"imports": {
|
|
136
|
-
"react": "
|
|
137
|
-
"react-dom": "
|
|
138
|
-
"react-dom/client": "
|
|
139
|
-
"react/jsx-runtime": "
|
|
140
|
-
"react/jsx-dev-runtime": "
|
|
141
|
-
"pixi.js": "
|
|
142
|
-
"@imgly/background-removal": "
|
|
143
|
-
"motion": "
|
|
144
|
-
"motion/react": "
|
|
145
|
-
"yjs": "
|
|
146
|
-
"y-protocols/sync": "
|
|
147
|
-
"y-protocols/awareness": "
|
|
148
|
-
"lib0/decoding": "
|
|
149
|
-
"lib0/encoding": "
|
|
150
|
-
"remotion": "
|
|
151
|
-
"@remotion/media": "
|
|
152
|
-
"@remotion/player": "
|
|
153
|
-
"@remotion/transitions": "
|
|
154
|
-
"@remotion/transitions/fade": "
|
|
155
|
-
"@remotion/transitions/slide": "
|
|
156
|
-
"@remotion/transitions/wipe": "
|
|
157
|
-
"@remotion/transitions/flip": "
|
|
158
|
-
"@remotion/transitions/clock-wipe": "
|
|
159
|
-
"@remotion/transitions/none": "
|
|
136
|
+
"react": "./_canvas-runtime/react.js",
|
|
137
|
+
"react-dom": "./_canvas-runtime/react-dom.js",
|
|
138
|
+
"react-dom/client": "./_canvas-runtime/react-dom_client.js",
|
|
139
|
+
"react/jsx-runtime": "./_canvas-runtime/react_jsx-runtime.js",
|
|
140
|
+
"react/jsx-dev-runtime": "./_canvas-runtime/react_jsx-dev-runtime.js",
|
|
141
|
+
"pixi.js": "./_canvas-runtime/pixi-js.js",
|
|
142
|
+
"@imgly/background-removal": "./_canvas-runtime/@imgly_background-removal.js",
|
|
143
|
+
"motion": "./_canvas-runtime/motion.js",
|
|
144
|
+
"motion/react": "./_canvas-runtime/motion_react.js",
|
|
145
|
+
"yjs": "./_canvas-runtime/yjs.js",
|
|
146
|
+
"y-protocols/sync": "./_canvas-runtime/y-protocols_sync.js",
|
|
147
|
+
"y-protocols/awareness": "./_canvas-runtime/y-protocols_awareness.js",
|
|
148
|
+
"lib0/decoding": "./_canvas-runtime/lib0_decoding.js",
|
|
149
|
+
"lib0/encoding": "./_canvas-runtime/lib0_encoding.js",
|
|
150
|
+
"remotion": "./_canvas-runtime/remotion.js",
|
|
151
|
+
"@remotion/media": "./_canvas-runtime/@remotion_media.js",
|
|
152
|
+
"@remotion/player": "./_canvas-runtime/@remotion_player.js",
|
|
153
|
+
"@remotion/transitions": "./_canvas-runtime/@remotion_transitions.js",
|
|
154
|
+
"@remotion/transitions/fade": "./_canvas-runtime/@remotion_transitions_fade.js",
|
|
155
|
+
"@remotion/transitions/slide": "./_canvas-runtime/@remotion_transitions_slide.js",
|
|
156
|
+
"@remotion/transitions/wipe": "./_canvas-runtime/@remotion_transitions_wipe.js",
|
|
157
|
+
"@remotion/transitions/flip": "./_canvas-runtime/@remotion_transitions_flip.js",
|
|
158
|
+
"@remotion/transitions/clock-wipe": "./_canvas-runtime/@remotion_transitions_clock-wipe.js",
|
|
159
|
+
"@remotion/transitions/none": "./_canvas-runtime/@remotion_transitions_none.js"
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
</script>
|
|
@@ -190,8 +190,38 @@
|
|
|
190
190
|
// `git show <sha>:<path>`). Baked into the module URL so both the initial
|
|
191
191
|
// import and the HMR soft-reload carry it.
|
|
192
192
|
const shaParam = params.get('sha');
|
|
193
|
+
// Cloud Phase 27 (DDR-209) — THE CAPABILITY TRAVELS WITH EVERY REQUEST.
|
|
194
|
+
//
|
|
195
|
+
// On a desktop the canvas origin is loopback and needs none, so `cap` is
|
|
196
|
+
// empty and every URL below is byte-identical to what it has always been.
|
|
197
|
+
//
|
|
198
|
+
// In the cloud the canvas origin is a cookieless hostname on the public
|
|
199
|
+
// internet: a cookie able to reach it would be readable by the canvas
|
|
200
|
+
// content itself, which is exactly what the DDR-054 split exists to
|
|
201
|
+
// prevent. So the capability rides in the URL — and it has to ride in
|
|
202
|
+
// EVERY url, not just this document's, because the shell then fetches its
|
|
203
|
+
// module, its tokens, its components CSS and its meta as separate
|
|
204
|
+
// requests. Getting the document through and nothing else is what
|
|
205
|
+
// "refused to connect" looks like from the outside.
|
|
206
|
+
const cap = params.get('t') || '';
|
|
207
|
+
// THE BASE THIS DOCUMENT WAS SERVED FROM, not the origin root.
|
|
208
|
+
//
|
|
209
|
+
// The fleet's canvas origin puts the project in the PATH
|
|
210
|
+
// (`canvas.<zone>/<project>/…`), so an absolute `/…` URL built here
|
|
211
|
+
// resolves against the origin and loses the project — the browser then
|
|
212
|
+
// asks for `canvas.<zone>/.design/…`, the data plane reads `.design` as a
|
|
213
|
+
// project name, and every dynamic import fails. Derived from where this
|
|
214
|
+
// document actually is rather than passed in, so it is right by
|
|
215
|
+
// construction in all three shells: on a desktop the shell is served at
|
|
216
|
+
// `/_canvas-shell.html` and the base is empty, leaving every URL below
|
|
217
|
+
// byte-identical to what it has always been.
|
|
218
|
+
const base = location.pathname.replace(/\/_canvas-shell(\.html)?$/, '');
|
|
219
|
+
const withCap = (u) => {
|
|
220
|
+
const abs = u.startsWith('/') ? base + u : u;
|
|
221
|
+
return cap ? abs + (abs.includes('?') ? '&' : '?') + 't=' + encodeURIComponent(cap) : abs;
|
|
222
|
+
};
|
|
193
223
|
const canvasQuery = shaParam ? ('?sha=' + encodeURIComponent(shaParam)) : '';
|
|
194
|
-
const canvasUrl = canvasRel ? ('/' + designRel + '/' + canvasRel + canvasQuery) : null;
|
|
224
|
+
const canvasUrl = canvasRel ? withCap('/' + designRel + '/' + canvasRel + canvasQuery) : null;
|
|
195
225
|
const myFileKey = canvasRel ? (designRel + '/' + canvasRel) : null;
|
|
196
226
|
// True while an `ai-activity` entry is live for THIS canvas (an agent is
|
|
197
227
|
// running /design:edit|new on it). Mirrors ai-banner's gate: parent relays
|
|
@@ -274,7 +304,11 @@
|
|
|
274
304
|
// The WS connection retries on close (dev-server restart resilience).
|
|
275
305
|
function connectHmr() {
|
|
276
306
|
const proto = location.protocol === 'https:' ? 'wss' : 'ws';
|
|
277
|
-
|
|
307
|
+
// `base` for the same reason every other URL here carries it: on the
|
|
308
|
+
// fleet's canvas origin the project is in the path. (A cell's HMR socket
|
|
309
|
+
// is a separate matter — it has no cookie to authenticate with, so it
|
|
310
|
+
// simply does not connect there; a canvas still renders.)
|
|
311
|
+
const ws = new WebSocket(proto + '://' + location.host + base + '/_ws');
|
|
278
312
|
ws.addEventListener('message', (ev) => {
|
|
279
313
|
try {
|
|
280
314
|
const msg = JSON.parse(ev.data);
|
|
@@ -417,7 +451,7 @@
|
|
|
417
451
|
// listens for `maude:meta-refreshed` and re-applies layout +
|
|
418
452
|
// viewport in-place (no full reload — preserves tool / undo state).
|
|
419
453
|
const metaFileParam = encodeURIComponent(designRel + '/' + canvasRel);
|
|
420
|
-
fetch('/_api/canvas-meta?file=' + metaFileParam, {
|
|
454
|
+
fetch(withCap('/_api/canvas-meta?file=' + metaFileParam), {
|
|
421
455
|
headers: { 'Cache-Control': 'no-store' },
|
|
422
456
|
})
|
|
423
457
|
.then((r) => (r.ok ? r.json() : null))
|
|
@@ -444,13 +478,13 @@
|
|
|
444
478
|
if (!canvasRel) {
|
|
445
479
|
showError('Missing ?canvas= query parameter. Add ?canvas=ui/<slug>.tsx.');
|
|
446
480
|
} else {
|
|
447
|
-
if (tokensRel) document.getElementById('canvas-tokens').href = '/' + designRel + '/' + tokensRel;
|
|
448
|
-
if (componentsRel) document.getElementById('canvas-components').href = '/' + designRel + '/' + componentsRel;
|
|
481
|
+
if (tokensRel) document.getElementById('canvas-tokens').href = withCap('/' + designRel + '/' + tokensRel);
|
|
482
|
+
if (componentsRel) document.getElementById('canvas-components').href = withCap('/' + designRel + '/' + componentsRel);
|
|
449
483
|
if (layoutRel) {
|
|
450
484
|
// Inject a third <link> for the DS layout chrome (specimens load this).
|
|
451
485
|
const layoutLink = document.createElement('link');
|
|
452
486
|
layoutLink.rel = 'stylesheet';
|
|
453
|
-
layoutLink.href = '/' + designRel + '/' + layoutRel;
|
|
487
|
+
layoutLink.href = withCap('/' + designRel + '/' + layoutRel);
|
|
454
488
|
layoutLink.dataset.canvasCss = 'layout';
|
|
455
489
|
document.head.appendChild(layoutLink);
|
|
456
490
|
}
|
|
@@ -466,7 +500,7 @@
|
|
|
466
500
|
// server-side api.fileSlug (which trims paths.designRel).
|
|
467
501
|
window.__canvas_design_rel__ = designRel;
|
|
468
502
|
window.__canvas_rel__ = canvasRel;
|
|
469
|
-
const metaFetch = fetch('/_api/canvas-meta?file=' + metaFileParam, {
|
|
503
|
+
const metaFetch = fetch(withCap('/_api/canvas-meta?file=' + metaFileParam), {
|
|
470
504
|
headers: { 'Cache-Control': 'no-store' },
|
|
471
505
|
})
|
|
472
506
|
.then((r) => (r.ok ? r.json() : null))
|
|
@@ -484,7 +518,7 @@
|
|
|
484
518
|
// the importmap so the canvas module and the comment layer share one
|
|
485
519
|
// React singleton (inlining a second React would break hooks).
|
|
486
520
|
const [{ mountCanvas }, mod] = await Promise.all([
|
|
487
|
-
import('/_client/comment-mount.js'),
|
|
521
|
+
import(withCap('/_client/comment-mount.js')),
|
|
488
522
|
import(canvasUrl),
|
|
489
523
|
metaFetch,
|
|
490
524
|
]);
|
|
@@ -324,7 +324,7 @@
|
|
|
324
324
|
},
|
|
325
325
|
"engineVersion": {
|
|
326
326
|
"type": "string",
|
|
327
|
-
"default": "
|
|
327
|
+
"default": "v1.0.0",
|
|
328
328
|
"description": "PINNED kgai release the CLI + desktop bundle target. Advance deliberately (harness-verified via `maude kg check-upstream`), never float — auto-tracking `latest` would let an upstream change silently alter behavior mid-rollout and is a supply-chain surface (DDR-054/056 reasoning: the bundled `kg` is third-party)."
|
|
329
329
|
},
|
|
330
330
|
"store": {
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
},
|
|
106
106
|
"install": {
|
|
107
107
|
"preferred": "See docs/kgai-onboarding.md — download the pinned kgai release binary (kgai is capability-gated + opt-out; nothing to install to use classic .ai/ mode)",
|
|
108
|
-
"darwin": "curl -fsSL https://github.com/kgaidev/kgai/releases/download/
|
|
108
|
+
"darwin": "curl -fsSL https://github.com/kgaidev/kgai/releases/download/v1.0.0/kg-darwin-arm64 -o /usr/local/bin/kg && chmod +x /usr/local/bin/kg"
|
|
109
109
|
},
|
|
110
110
|
"autoInstall": false,
|
|
111
111
|
"fallbackBehavior": "flow/design fall back to the classic .ai/decisions/ + STATE.md file path (no regression). The kgai knowledge-graph backend (kg context/ingest/sync, cross-repo company memory) is inactive.",
|