@1agh/maude 0.47.0 → 0.48.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/README.md +7 -6
- package/apps/studio/acp/bridge.ts +8 -1
- package/apps/studio/acp/plugin-bootstrap.ts +15 -1
- package/apps/studio/build.ts +1 -1
- package/apps/studio/client/export-center.jsx +7 -6
- package/apps/studio/client/github.js +11 -4
- package/apps/studio/dist/client.bundle.js +282 -282
- package/apps/studio/dist/runtime/REMOTION-LICENSE.md +1 -1
- package/apps/studio/examples/perf-100-artboards.tsx +1 -1
- package/apps/studio/exporters/pdf.ts +35 -1
- package/apps/studio/git/service.ts +4 -1
- package/apps/studio/paths.ts +37 -1
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +34 -0
- package/apps/studio/test/acp-session-plugins.test.ts +6 -0
- package/apps/studio/test/exporters/pdf.test.ts +33 -1
- package/cli/bin/maude.mjs +1 -0
- package/cli/commands/init.mjs +80 -3
- package/cli/commands/kg.mjs +368 -0
- package/cli/commands/kg.test.mjs +118 -0
- package/cli/lib/ddr-to-kgai.mjs +648 -0
- package/cli/lib/ddr-to-kgai.test.mjs +99 -0
- package/cli/lib/flow-design-integration.test.mjs +2 -2
- package/cli/lib/gitignore-block.mjs +4 -0
- package/cli/lib/plugin-name-namespace.test.mjs +71 -0
- package/package.json +8 -8
- package/plugins/design/dependencies.json +17 -0
- package/plugins/flow/.claude-plugin/config.schema.json +66 -0
- package/plugins/flow/dependencies.json +17 -0
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ maude doctor --json # machine-readable envelope
|
|
|
82
82
|
|
|
83
83
|
### Sidecar cache — `maude cache`
|
|
84
84
|
|
|
85
|
-
Flow + design commands reuse expensive cross-session work through a small sidecar cache at `.ai/cache/` ([DDR-061](.ai/decisions/DDR-061-sidecar-cache-monitor-background-orchestration.md)): domain research (skips 30–90 s of WebSearch on a same-domain brief), codebase-intelligence scans (skips rescan when the tree is unchanged), parsed design-system vocabulary, and security-review reuse (one shared 1-hour window across `/flow:validate`, `/flow:done`, `/flow:validate-security`). Correctness comes first — most layers are content-addressed (a changed input changes the key → guaranteed miss), and a stale entry is never served speculatively.
|
|
85
|
+
Flow + design commands reuse expensive cross-session work through a small sidecar cache at `.ai/cache/` ([DDR-061](.ai/archive/decisions/DDR-061-sidecar-cache-monitor-background-orchestration.md)): domain research (skips 30–90 s of WebSearch on a same-domain brief), codebase-intelligence scans (skips rescan when the tree is unchanged), parsed design-system vocabulary, and security-review reuse (one shared 1-hour window across `/flow:validate`, `/flow:done`, `/flow:validate-security`). Correctness comes first — most layers are content-addressed (a changed input changes the key → guaranteed miss), and a stale entry is never served speculatively.
|
|
86
86
|
|
|
87
87
|
```sh
|
|
88
88
|
maude cache list # layers, entry counts, sizes, last-write time
|
|
@@ -95,7 +95,7 @@ The `research/domain` and `codebase-intelligence` layers are **committed** (dete
|
|
|
95
95
|
|
|
96
96
|
### Plugins call `maude` for executable logic
|
|
97
97
|
|
|
98
|
-
Plugin slash-commands reach all executable logic through the on-PATH `maude` binary — never a relative `cli/lib/*.mjs` path or a raw `$CLAUDE_PLUGIN_ROOT/dev-server/bin/*.sh` invocation ([DDR-062](.ai/decisions/DDR-062-plugins-reach-executable-logic-via-maude.md)). The marketplace copies each plugin alone (no sibling `cli/`, no `dev-server/`), and a flow command's `$CLAUDE_PLUGIN_ROOT` points at the flow plugin (which has no dev-server at all) — so the only contract that holds across every install shape is `maude`, which resolves bundled helpers from its own package root. Cache/preflight go via `maude cache …` / `maude preflight …`; the design dev-server's bash helpers go via **`maude design <verb>`** (`screenshot`, `server-up`, `prep`, `slug`, `smoke`, `runtime-health`, …) — see `maude design help`. Keep the global `maude` current; a stale binary means stale helpers.
|
|
98
|
+
Plugin slash-commands reach all executable logic through the on-PATH `maude` binary — never a relative `cli/lib/*.mjs` path or a raw `$CLAUDE_PLUGIN_ROOT/dev-server/bin/*.sh` invocation ([DDR-062](.ai/archive/decisions/DDR-062-plugins-reach-executable-logic-via-maude.md)). The marketplace copies each plugin alone (no sibling `cli/`, no `dev-server/`), and a flow command's `$CLAUDE_PLUGIN_ROOT` points at the flow plugin (which has no dev-server at all) — so the only contract that holds across every install shape is `maude`, which resolves bundled helpers from its own package root. Cache/preflight go via `maude cache …` / `maude preflight …`; the design dev-server's bash helpers go via **`maude design <verb>`** (`screenshot`, `server-up`, `prep`, `slug`, `smoke`, `runtime-health`, …) — see `maude design help`. Keep the global `maude` current; a stale binary means stale helpers.
|
|
99
99
|
|
|
100
100
|
## Runtime requirements
|
|
101
101
|
|
|
@@ -105,10 +105,10 @@ Plugin slash-commands reach all executable logic through the on-PATH `maude` bin
|
|
|
105
105
|
|
|
106
106
|
## Collaboration model
|
|
107
107
|
|
|
108
|
-
Two clean paths, no middle ground ([DDR-047](.ai/decisions/DDR-047-collab-scope-cut-no-lan-mode-hub-admin-ui.md)):
|
|
108
|
+
Two clean paths, no middle ground ([DDR-047](.ai/archive/decisions/DDR-047-collab-scope-cut-no-lan-mode-hub-admin-ui.md)):
|
|
109
109
|
|
|
110
110
|
- **v1.0 — git handoff OR loopback multi-tab.** Push / pull is the cross-machine story. On a single machine, two browser tabs (or two Claude Code instances editing the same repo) sync cursors, comments, and annotations live over loopback WebSocket. The dev server refuses any non-loopback `host` header on the collab WS endpoint.
|
|
111
|
-
- **v1.1 — deploy a hub** (Phase 9, in-flight). Cross-machine live collab needs a hub binary you deploy yourself. No tunnel mode; no shared cloud. **Boot order can't eat your work** ([DDR-102](.ai/decisions/DDR-102-cold-start-divergence-resolution.md)): a per-machine journal tells clean catch-ups apart from genuine divergence; diverged canvases snapshot **both** versions to `_history/` before the newer one wins, so the loser is one `/design:rollback` away — and `maude design status` reports per-canvas sync state honestly (synced / pending / auth-rejected).
|
|
111
|
+
- **v1.1 — deploy a hub** (Phase 9, in-flight). Cross-machine live collab needs a hub binary you deploy yourself. No tunnel mode; no shared cloud. **Boot order can't eat your work** ([DDR-102](.ai/archive/decisions/DDR-102-cold-start-divergence-resolution.md)): a per-machine journal tells clean catch-ups apart from genuine divergence; diverged canvases snapshot **both** versions to `_history/` before the newer one wins, so the loser is one `/design:rollback` away — and `maude design status` reports per-canvas sync state honestly (synced / pending / auth-rejected).
|
|
112
112
|
|
|
113
113
|
## Security
|
|
114
114
|
|
|
@@ -118,7 +118,8 @@ Solo mode (the default) is fully local — no accounts, no telemetry, no network
|
|
|
118
118
|
|
|
119
119
|
User-facing docs live in two places — the README points you the right way:
|
|
120
120
|
|
|
121
|
-
- **Reference** (every command, every config key, recipes for Next.js / Expo / monorepo) → [`site/content/docs/`](./site/content/docs/) (served at https://maude.sh once Vercel is wired — see [DDR-005](.ai/decisions/DDR-005-docs-site-stack-and-hosting.md)).
|
|
121
|
+
- **Reference** (every command, every config key, recipes for Next.js / Expo / monorepo) → [`site/content/docs/`](./site/content/docs/) (served at https://maude.sh once Vercel is wired — see [DDR-005](.ai/archive/decisions/DDR-005-docs-site-stack-and-hosting.md)).
|
|
122
|
+
- **kgai knowledge-graph backend** (opt-in shared decision memory across repos) → [`docs/kgai-onboarding.md`](./docs/kgai-onboarding.md) (per user) + [`docs/kgai-company-setup.md`](./docs/kgai-company-setup.md) (one-time admin). Off by default — absent `kg`, every command runs its classic `.ai/` path.
|
|
122
123
|
- **Quickstart** + **contributor info** → this README.
|
|
123
124
|
|
|
124
125
|
The docs site auto-generates per-command pages from `plugins/{flow,design}/commands/*.md` frontmatter and a typed schema reference from `plugins/flow/.claude-plugin/config.schema.json`. Adding a new command → docs update on next build.
|
|
@@ -130,7 +131,7 @@ The repo is a **pnpm workspace monorepo** with one published npm package (`@1agh
|
|
|
130
131
|
| Workspace | Purpose |
|
|
131
132
|
| --------- | ------- |
|
|
132
133
|
| `.` (root) | The single npm publisher — CLI, dev-server entry, plugin templates that ship to npm. |
|
|
133
|
-
| `site/` | Docs site — Fumadocs + Next.js, deployed to Vercel ([DDR-005](.ai/decisions/DDR-005-docs-site-stack-and-hosting.md)). |
|
|
134
|
+
| `site/` | Docs site — Fumadocs + Next.js, deployed to Vercel ([DDR-005](.ai/archive/decisions/DDR-005-docs-site-stack-and-hosting.md)). |
|
|
134
135
|
| `apps/studio/` | Zero-dep Node dev server + browser client. Bundled output (`dist/`) is the only thing in the npm tarball. |
|
|
135
136
|
| `apps/hub/` | Reserved for the v1.1 federated hub (Phase 9). |
|
|
136
137
|
|
|
@@ -396,7 +396,14 @@ export function newSessionParams(
|
|
|
396
396
|
// gets it double-loaded with zero suppression (the exact double-
|
|
397
397
|
// registration risk this override exists to close). No test currently
|
|
398
398
|
// catches this drift.
|
|
399
|
-
|
|
399
|
+
// `kgai` is the third-party autonomous-capture plugin the desktop bundle
|
|
400
|
+
// injects (plugin-bootstrap.ts). Suppressing its natively-installed copy is
|
|
401
|
+
// MORE load-bearing than for our own plugins: a user-installed kgai would
|
|
402
|
+
// run its own SessionStart `install.sh` (Go/network) and point at a
|
|
403
|
+
// different engine version than the pinned, signed sidecar we ship. Its id
|
|
404
|
+
// has no `@marketplace` suffix — it's injected as a bare local plugin dir
|
|
405
|
+
// whose manifest `name` is `kgai`.
|
|
406
|
+
options.settings = { enabledPlugins: { 'design@maude': false, kgai: false } };
|
|
400
407
|
}
|
|
401
408
|
meta.claudeCode = { options };
|
|
402
409
|
return {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
// id via the SDK's documented `flag > user` settings precedence — so the
|
|
39
39
|
// bundled copy injected here is the ONLY one that ever loads.
|
|
40
40
|
|
|
41
|
-
import { DESIGN_PLUGIN_DIR, FLOW_PLUGIN_DIR } from '../paths.ts';
|
|
41
|
+
import { DESIGN_PLUGIN_DIR, FLOW_PLUGIN_DIR, KGAI_PLUGIN_DIR } from '../paths.ts';
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* SDK plugin-load config (`@anthropic-ai/claude-agent-sdk` `SdkPluginConfig`).
|
|
@@ -61,6 +61,8 @@ export interface SessionPluginDeps {
|
|
|
61
61
|
designDir: string | null;
|
|
62
62
|
/** Bundled `flow` plugin dir, or null (npm/web layout). */
|
|
63
63
|
flowDir: string | null;
|
|
64
|
+
/** Bundled third-party `kgai` plugin dir, or null (only staged in the .app). */
|
|
65
|
+
kgaiDir?: string | null;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
/**
|
|
@@ -81,6 +83,17 @@ export function computeSessionPlugins(deps: SessionPluginDeps): SdkPluginConfig[
|
|
|
81
83
|
// `/flow` auto-load is intentionally OFF for now (2026-07-03) — the chat ships
|
|
82
84
|
// design-only. `deps.flowDir` stays resolved (harmless) so restoring it is a
|
|
83
85
|
// one-liner: re-add `add(deps.flowDir)`.
|
|
86
|
+
//
|
|
87
|
+
// kgai (third-party, MIT) — injected so its `Stop` hook loads and autonomous
|
|
88
|
+
// decision capture actually fires in the ACP panel. Without this the packaged
|
|
89
|
+
// app captures NOTHING: the session is built with settingSources:['user']
|
|
90
|
+
// (DDR-144) and a terminal-less DDR-177 user never marketplace-installs it.
|
|
91
|
+
// Non-null only in the desktop bundle (sync-kg.mjs stages a pinned release).
|
|
92
|
+
//
|
|
93
|
+
// ⚠ DRIFT TRAP — adding an id here REQUIRES a matching `'<id>': false` entry in
|
|
94
|
+
// bridge.ts's hand-maintained `enabledPlugins` suppression literal, or a user
|
|
95
|
+
// who ALSO has it natively enabled gets it double-loaded (see that comment).
|
|
96
|
+
add(deps.kgaiDir ?? null);
|
|
84
97
|
return out;
|
|
85
98
|
}
|
|
86
99
|
|
|
@@ -117,5 +130,6 @@ export function resolveSessionPlugins(): SdkPluginConfig[] {
|
|
|
117
130
|
native: isNativePluginContext(),
|
|
118
131
|
designDir: DESIGN_PLUGIN_DIR,
|
|
119
132
|
flowDir: FLOW_PLUGIN_DIR,
|
|
133
|
+
kgaiDir: KGAI_PLUGIN_DIR,
|
|
120
134
|
});
|
|
121
135
|
}
|
package/apps/studio/build.ts
CHANGED
|
@@ -317,7 +317,7 @@ export function writeCompileEntry(target: PlatformTarget): string {
|
|
|
317
317
|
const bindingSpec = `@oxc-parser/binding-${oxcSlug}/parser.${oxcSlug}.node`;
|
|
318
318
|
const initContent = `// AUTO-GENERATED by build.ts — do not edit by hand.
|
|
319
319
|
// Per-target oxc-parser binding embed (Bun 1.3.4+ --compile NAPI regression
|
|
320
|
-
// workaround — see .ai/decisions/DDR-042-oxc-parser-bun-compile-workaround.md).
|
|
320
|
+
// workaround — see .ai/archive/decisions/DDR-042-oxc-parser-bun-compile-workaround.md).
|
|
321
321
|
// Side-effect module: must be imported BEFORE any oxc-parser usage.
|
|
322
322
|
import bindingPath from ${JSON.stringify(bindingSpec)} with { type: 'file' };
|
|
323
323
|
process.env.NAPI_RS_NATIVE_LIBRARY_PATH = bindingPath;
|
|
@@ -56,12 +56,13 @@ async function autoDownloadBlob(id, fallbackName) {
|
|
|
56
56
|
URL.revokeObjectURL(url);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
// Native "Save…" — unlike the web `download()` path, this does NOT fetch the
|
|
60
|
+
// job's bytes into the renderer first. `save_export` fetches them itself
|
|
61
|
+
// (RCA issue-desktop-print-pdf-save-as-hang-large-payload: routing a
|
|
62
|
+
// hundreds-of-MB export through a JS Uint8Array + Tauri's JSON IPC froze the
|
|
63
|
+
// app), so all this needs is the filename already carried on the job record.
|
|
64
|
+
async function saveNative(id, filename) {
|
|
65
|
+
return saveExport(filename || 'export', id);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
export function useExportCenter() {
|
|
@@ -93,11 +93,18 @@ export const pickDirectory = () => invoke('pick_directory');
|
|
|
93
93
|
export const openLocalProject = (path) => invoke('open_local_project', { path });
|
|
94
94
|
/**
|
|
95
95
|
* Native "Save As…" for an export — opens an OS save dialog seeded with
|
|
96
|
-
* `filename`,
|
|
97
|
-
*
|
|
98
|
-
*
|
|
96
|
+
* `filename`, then has the Rust side fetch the finished `jobId`'s bytes
|
|
97
|
+
* directly from the local dev-server and stream them to the chosen path, and
|
|
98
|
+
* resolves to that path (or null if cancelled). Only callable in the native
|
|
99
|
+
* app; the browser build uses the `<a download>` blob instead.
|
|
100
|
+
*
|
|
101
|
+
* Deliberately does NOT take the bytes as an argument (it used to — RCA
|
|
102
|
+
* issue-desktop-print-pdf-save-as-hang-large-payload): shipping a large export
|
|
103
|
+
* (a print-ready PDF can be hundreds of MB) through Tauri's JSON-serialized
|
|
104
|
+
* IPC as `Array.from(new Uint8Array(...))` froze the renderer. Rust fetches
|
|
105
|
+
* the bytes itself now; the webview never sees the payload.
|
|
99
106
|
*/
|
|
100
|
-
export const saveExport = (filename,
|
|
107
|
+
export const saveExport = (filename, jobId) => invoke('save_export', { filename, jobId });
|
|
101
108
|
|
|
102
109
|
/**
|
|
103
110
|
* Native "open file" for media upload — the read counterpart to saveExport.
|