@1agh/maude 0.58.1 → 0.58.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/apps/studio/.ai/cache/_stats.json +1 -1
- package/apps/studio/acp/bridge.ts +165 -15
- package/apps/studio/client/app.jsx +85 -22
- package/apps/studio/client/panels/ChatPanel.jsx +25 -2
- package/apps/studio/client/styles/6-acp-chat.css +12 -0
- package/apps/studio/dist/client.bundle.js +1146 -1146
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/sync/canvas-path.ts +329 -0
- package/apps/studio/sync/codec.ts +42 -0
- package/apps/studio/sync/index.ts +490 -17
- package/apps/studio/sync/projection.ts +11 -1
- package/apps/studio/sync/remote-docs.ts +122 -15
- package/apps/studio/test/acp-bridge-lifetime.test.ts +106 -0
- package/apps/studio/test/comment-relay-origin-gate.test.ts +117 -0
- package/apps/studio/test/comments-fs-rebroadcast.test.ts +155 -0
- package/apps/studio/test/fixtures/mock-acp-agent-wedged.mjs +37 -0
- package/apps/studio/test/sync-canvas-path.test.ts +200 -0
- package/apps/studio/test/sync-path-pull.test.ts +402 -0
- package/apps/studio/test/sync-remote-docs.test.ts +55 -3
- package/apps/studio/test/sync-runtime.test.ts +118 -0
- package/apps/studio/whats-new.json +9 -0
- package/package.json +8 -8
|
@@ -1171,6 +1171,124 @@ describe('DDR-102 — auth-failure intelligence + boot summary', () => {
|
|
|
1171
1171
|
}
|
|
1172
1172
|
});
|
|
1173
1173
|
|
|
1174
|
+
test('a successful re-probe clears the refusal, and the reconcile is a separate word', async () => {
|
|
1175
|
+
// A REGRESSION GUARD, not a falsifier — this already held. It is here
|
|
1176
|
+
// because the clear moved: it used to sit at the BOTTOM of the
|
|
1177
|
+
// post-handshake path, below a reconcile that can throw into a rejection
|
|
1178
|
+
// `settleWait` swallows, so a document that reconnected fine but failed to
|
|
1179
|
+
// settle on disk would have kept telling the user to go fix a credential
|
|
1180
|
+
// that was never the problem. The clear now runs on the handshake, and the
|
|
1181
|
+
// reconcile reports separately (`pending` vs `connected`) and loudly.
|
|
1182
|
+
const url = 'https://hub.example.com';
|
|
1183
|
+
writeHubsConfig(url, 'mau_test');
|
|
1184
|
+
const ctx = makeCtx({ url, linkedAt: 1 });
|
|
1185
|
+
writeFileSync(join(ctx.paths.designRoot, 'ui', 'a.html'), '<a/>');
|
|
1186
|
+
|
|
1187
|
+
const timers = fakeTimerQueue();
|
|
1188
|
+
const origWarn = console.warn;
|
|
1189
|
+
const origLog = console.log;
|
|
1190
|
+
console.warn = () => {};
|
|
1191
|
+
console.log = () => {};
|
|
1192
|
+
|
|
1193
|
+
let round = 0;
|
|
1194
|
+
const factory = (args: { documentName: string; document?: Y.Doc }) => {
|
|
1195
|
+
const document = args.document ?? new Y.Doc();
|
|
1196
|
+
const first = round++ === 0;
|
|
1197
|
+
return {
|
|
1198
|
+
document,
|
|
1199
|
+
onAuthFailed(cb: (info: { reason: string }) => void) {
|
|
1200
|
+
if (first) queueMicrotask(() => cb({ reason: 'token not authorized' }));
|
|
1201
|
+
return () => {};
|
|
1202
|
+
},
|
|
1203
|
+
onceSynced: () => (first ? new Promise<void>(() => {}) : Promise.resolve()),
|
|
1204
|
+
destroy() {},
|
|
1205
|
+
};
|
|
1206
|
+
};
|
|
1207
|
+
|
|
1208
|
+
try {
|
|
1209
|
+
const runtime = createSyncRuntime(ctx, {
|
|
1210
|
+
providerFactory: factory,
|
|
1211
|
+
auth: {
|
|
1212
|
+
warnDebounceMs: 2_000,
|
|
1213
|
+
reprobeMs: 300_000,
|
|
1214
|
+
settleTimeoutMs: 15_000,
|
|
1215
|
+
setTimer: timers.setTimer,
|
|
1216
|
+
clearTimer: timers.clearTimer,
|
|
1217
|
+
},
|
|
1218
|
+
});
|
|
1219
|
+
await runtime?.start();
|
|
1220
|
+
await new Promise((res) => setTimeout(res, 10));
|
|
1221
|
+
expect(runtime?.status().docs?.rejected).toBe(1);
|
|
1222
|
+
|
|
1223
|
+
timers.fire(300_000);
|
|
1224
|
+
await new Promise((res) => setTimeout(res, 40));
|
|
1225
|
+
|
|
1226
|
+
expect(runtime?.status().docs?.rejected).toBe(0);
|
|
1227
|
+
expect(runtime?.status().rejectedSlugs ?? []).toEqual([]);
|
|
1228
|
+
|
|
1229
|
+
await runtime?.stop();
|
|
1230
|
+
} finally {
|
|
1231
|
+
console.warn = origWarn;
|
|
1232
|
+
console.log = origLog;
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
test('a new process never serves the previous one’s verdict, not even mid-boot', async () => {
|
|
1237
|
+
// `_sync.json` is a file and `/_sync-status` returns whatever is in it. The
|
|
1238
|
+
// first honest snapshot of a run is not written until every provider has
|
|
1239
|
+
// been built — after a scan AND a listing fetch that waits up to 6 seconds.
|
|
1240
|
+
// For that whole window the CLI and the browser banner were reading the
|
|
1241
|
+
// LAST run's counters as current. So the window is what this asserts: the
|
|
1242
|
+
// fetch is held open, and the file must ALREADY be clean.
|
|
1243
|
+
const url = 'https://hub.example.com';
|
|
1244
|
+
writeHubsConfig(url, 'mau_test');
|
|
1245
|
+
const ctx = makeCtx({ url, linkedAt: 1 });
|
|
1246
|
+
const statusFile = join(ctx.paths.designRoot, '_sync.json');
|
|
1247
|
+
writeFileSync(
|
|
1248
|
+
statusFile,
|
|
1249
|
+
JSON.stringify({
|
|
1250
|
+
url,
|
|
1251
|
+
canvases: 76,
|
|
1252
|
+
state: 'online',
|
|
1253
|
+
docs: { synced: 0, pending: 3, rejected: 73 },
|
|
1254
|
+
rejectedSlugs: ['ui-a', 'ui-b'],
|
|
1255
|
+
})
|
|
1256
|
+
);
|
|
1257
|
+
writeFileSync(join(ctx.paths.designRoot, 'ui', 'a.html'), '<a/>');
|
|
1258
|
+
|
|
1259
|
+
const realFetch = globalThis.fetch;
|
|
1260
|
+
let releaseListing: () => void = () => {};
|
|
1261
|
+
const listingReached = new Promise<void>((res) => {
|
|
1262
|
+
globalThis.fetch = (async () => {
|
|
1263
|
+
res();
|
|
1264
|
+
await new Promise<void>((r) => {
|
|
1265
|
+
releaseListing = r;
|
|
1266
|
+
});
|
|
1267
|
+
return new Response(JSON.stringify({ documents: [] }), { status: 200 });
|
|
1268
|
+
}) as typeof fetch;
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
try {
|
|
1272
|
+
const { factory } = inMemoryProviderFactory();
|
|
1273
|
+
const runtime = createSyncRuntime(ctx, { providerFactory: factory });
|
|
1274
|
+
const booting = runtime?.start();
|
|
1275
|
+
await listingReached;
|
|
1276
|
+
|
|
1277
|
+
// Mid-boot, with the listing still in flight — exactly where the stale
|
|
1278
|
+
// file used to be authoritative.
|
|
1279
|
+
const midBoot = JSON.parse(readFileSync(statusFile, 'utf8'));
|
|
1280
|
+
expect(midBoot.docs.rejected).toBe(0);
|
|
1281
|
+
expect(midBoot.rejectedSlugs ?? []).toEqual([]);
|
|
1282
|
+
expect(midBoot.state).toBe('connecting');
|
|
1283
|
+
|
|
1284
|
+
releaseListing();
|
|
1285
|
+
await booting;
|
|
1286
|
+
await runtime?.stop();
|
|
1287
|
+
} finally {
|
|
1288
|
+
globalThis.fetch = realFetch;
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1174
1292
|
test('boot summary prints AFTER settle with honest counts (not the premature N/N)', async () => {
|
|
1175
1293
|
const url = 'https://hub.example.com';
|
|
1176
1294
|
writeHubsConfig(url, 'mau_test');
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./whats-new.schema.json",
|
|
3
3
|
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"id": "sync-carries-the-path",
|
|
6
|
+
"version": "0.58.2",
|
|
7
|
+
"date": "2026-08-08",
|
|
8
|
+
"kind": "fix",
|
|
9
|
+
"title": "Canvases arrive in the folder you made",
|
|
10
|
+
"summary": "A canvas you create in a nested folder now shows up on your other machine — and in the cloud — in that same folder, instead of quietly landing somewhere the file tree never listed. Connecting a project to an empty folder brings the whole thing down with its structure intact.",
|
|
11
|
+
"surface": "design-ui"
|
|
12
|
+
},
|
|
4
13
|
{
|
|
5
14
|
"id": "release-version-visible",
|
|
6
15
|
"version": "0.58.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1agh/maude",
|
|
3
|
-
"version": "0.58.
|
|
3
|
+
"version": "0.58.2",
|
|
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": {
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
"test:e2e:desktop:parity:cloud": "pnpm --filter @maude/desktop-e2e e2e:parity:cloud"
|
|
55
55
|
},
|
|
56
56
|
"optionalDependencies": {
|
|
57
|
-
"@1agh/maude-darwin-arm64": "0.58.
|
|
58
|
-
"@1agh/maude-darwin-x64": "0.58.
|
|
59
|
-
"@1agh/maude-linux-arm64": "0.58.
|
|
60
|
-
"@1agh/maude-linux-arm64-musl": "0.58.
|
|
61
|
-
"@1agh/maude-linux-x64": "0.58.
|
|
62
|
-
"@1agh/maude-linux-x64-musl": "0.58.
|
|
63
|
-
"@1agh/maude-win32-x64": "0.58.
|
|
57
|
+
"@1agh/maude-darwin-arm64": "0.58.2",
|
|
58
|
+
"@1agh/maude-darwin-x64": "0.58.2",
|
|
59
|
+
"@1agh/maude-linux-arm64": "0.58.2",
|
|
60
|
+
"@1agh/maude-linux-arm64-musl": "0.58.2",
|
|
61
|
+
"@1agh/maude-linux-x64": "0.58.2",
|
|
62
|
+
"@1agh/maude-linux-x64-musl": "0.58.2",
|
|
63
|
+
"@1agh/maude-win32-x64": "0.58.2"
|
|
64
64
|
},
|
|
65
65
|
"files": [
|
|
66
66
|
"cli",
|