@agimon-ai/doompi-style-system 0.0.1-alpha.100

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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/apiContracts.cjs +118 -0
  4. package/dist/apiContracts.cjs.map +1 -0
  5. package/dist/apiContracts.d.mts +52 -0
  6. package/dist/apiContracts.d.mts.map +1 -0
  7. package/dist/apiContracts.mjs +113 -0
  8. package/dist/apiContracts.mjs.map +1 -0
  9. package/dist/cli.cjs +242 -0
  10. package/dist/cli.cjs.map +1 -0
  11. package/dist/cli.d.mts +4 -0
  12. package/dist/cli.d.mts.map +1 -0
  13. package/dist/cli.mjs +239 -0
  14. package/dist/cli.mjs.map +1 -0
  15. package/dist/designCheck-7P9r9ijq.mjs +475 -0
  16. package/dist/designCheck-7P9r9ijq.mjs.map +1 -0
  17. package/dist/designCheck-zx4PsRvE.cjs +495 -0
  18. package/dist/designCheck-zx4PsRvE.cjs.map +1 -0
  19. package/dist/extensions/pi.cjs +94 -0
  20. package/dist/extensions/pi.cjs.map +1 -0
  21. package/dist/extensions/pi.d.mts +5 -0
  22. package/dist/extensions/pi.d.mts.map +1 -0
  23. package/dist/extensions/pi.mjs +87 -0
  24. package/dist/extensions/pi.mjs.map +1 -0
  25. package/dist/extensions/server.cjs +136 -0
  26. package/dist/extensions/server.cjs.map +1 -0
  27. package/dist/extensions/server.d.mts +5 -0
  28. package/dist/extensions/server.d.mts.map +1 -0
  29. package/dist/extensions/server.mjs +131 -0
  30. package/dist/extensions/server.mjs.map +1 -0
  31. package/dist/extensions/web.mjs +942 -0
  32. package/dist/extensions/web.mjs.map +1 -0
  33. package/dist/index.cjs +8 -0
  34. package/dist/index.d.mts +171 -0
  35. package/dist/index.d.mts.map +1 -0
  36. package/dist/index.mjs +3 -0
  37. package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
  38. package/dist/storyPreview-D-hGhlig.cjs +371 -0
  39. package/dist/storyPreview-D-hGhlig.cjs.map +1 -0
  40. package/dist/storyPreview-Dhejqhos.mjs +357 -0
  41. package/dist/storyPreview-Dhejqhos.mjs.map +1 -0
  42. package/package.json +132 -0
  43. package/skills/design-workflow/SKILL.md +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vuong Ngo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # @agimon-ai/doompi-style-system
2
+
3
+ Optional DoomPi integration for building disposable interactive story previews with `@agimon-ai/style-system`.
4
+
5
+ When this package and `@agimon-ai/doompi-author` are both installed, Author shows an **Open story preview** action. The temporary tab reads the focused `.stories.js`, `.stories.jsx`, `.stories.ts`, or `.stories.tsx` source, discovers exact named exports, builds only after an explicit action, runs the compiled HTML in an isolated iframe, and retains the composer for source-targeted feedback.
6
+
7
+ The portable `doompi-design` binary also works without Pi, DoomPi, Author, or MCP. Discovery commands delegate to the published style-system CLI. Structured commands provide exact story metadata, bounded checks, stale-evidence verification, and explicit preview builds:
8
+
9
+ ```bash
10
+ doompi-design metadata --story-path src/Button.stories.tsx
11
+ doompi-design check --target docs/specs/button/design-target.json --report docs/specs/button/design-check.json
12
+ doompi-design verify --report docs/specs/button/design-check.json
13
+ doompi-design preview --app-path . --story-path src/Button.stories.tsx --story-export Playground --output .tmp/button.html
14
+ ```
15
+
16
+ Use `--workspace <path>` when the process working directory is not the admitted project root.
17
+
18
+ ## Opt in
19
+
20
+ Install both packages, then add them to a layer used by your selected major mode:
21
+
22
+ ```yaml
23
+ layers:
24
+ design:
25
+ packages:
26
+ - '@agimon-ai/doompi-author'
27
+ - '@agimon-ai/doompi-style-system'
28
+ majorMode:
29
+ design:
30
+ description: Interactive source-backed story design.
31
+ layers: [design]
32
+ ```
33
+
34
+ The package is not added to DoomPi's default distribution mode.
35
+
36
+ Generated HTML is a preview artifact. AI changes must target the underlying story or component source. Refresh the preview after edits before treating it as visually verified.
37
+
38
+ ## Image export
39
+
40
+ **Export PNG**, **Prepare annotation**, and **Send to AI** render a fresh image from current source through style-system. Users can mark one normalized region or comment on the whole frozen image. The image does not include transient interaction state inside the iframe, and the UI states this limitation instead of presenting it as an exact capture of iframe state.
41
+
42
+ ## Security
43
+
44
+ Preview building executes trusted workspace source on the server. Project, story, and generated artifact paths are realpath-fenced to the admitted workspace. Browser previews use a script-only opaque-origin iframe and a restrictive content security policy. Remote assets are rejected by that policy, so preview assets must be included in the single-file bundle.
45
+
46
+ ## Development
47
+
48
+ ```bash
49
+ pnpm --filter @agimon-ai/doompi-style-system lint
50
+ pnpm --filter @agimon-ai/doompi-style-system typecheck
51
+ pnpm --filter @agimon-ai/doompi-style-system test
52
+ pnpm --filter @agimon-ai/doompi-style-system build
53
+ ```
@@ -0,0 +1,118 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ let _agimon_ai_doompi_core_apiContracts = require("@agimon-ai/doompi-core/apiContracts");
6
+ let typebox = require("typebox");
7
+ //#region src/schemas/apiContracts.ts
8
+ const StringSchema = typebox.Type.String();
9
+ const apiContracts = (0, _agimon_ai_doompi_core_apiContracts.defineApiContract)({
10
+ version: 1,
11
+ sockets: [],
12
+ dynamic: [],
13
+ http: [
14
+ {
15
+ id: "style-system-preview.metadata",
16
+ scope: "session",
17
+ basePath: "style-system-preview",
18
+ path: "/metadata",
19
+ method: "POST",
20
+ authentication: "owner",
21
+ description: "Read exact story exports and resolve its project without executing workspace source.",
22
+ body: {
23
+ required: true,
24
+ contentType: "application/json",
25
+ schema: typebox.Type.Object({
26
+ storyPath: StringSchema,
27
+ appPath: typebox.Type.Optional(StringSchema)
28
+ })
29
+ },
30
+ responses: (0, _agimon_ai_doompi_core_apiContracts.jsonApiResponses)(typebox.Type.Object({
31
+ storyPath: StringSchema,
32
+ appPath: StringSchema,
33
+ projectResolution: typebox.Type.Union([
34
+ typebox.Type.Literal("explicit"),
35
+ typebox.Type.Literal("config"),
36
+ typebox.Type.Literal("package"),
37
+ typebox.Type.Literal("workspace")
38
+ ]),
39
+ exports: typebox.Type.Array(typebox.Type.Object({
40
+ exportName: StringSchema,
41
+ label: typebox.Type.Optional(StringSchema)
42
+ }))
43
+ }))
44
+ },
45
+ {
46
+ id: "style-system-preview.build",
47
+ scope: "session",
48
+ basePath: "style-system-preview",
49
+ path: "/build",
50
+ method: "POST",
51
+ authentication: "owner",
52
+ description: "Build an isolated HTML preview for one exact story export.",
53
+ body: {
54
+ required: true,
55
+ contentType: "application/json",
56
+ schema: typebox.Type.Object({
57
+ appPath: StringSchema,
58
+ storyPath: StringSchema,
59
+ storyExport: StringSchema,
60
+ darkMode: typebox.Type.Optional(typebox.Type.Boolean())
61
+ })
62
+ },
63
+ responses: (0, _agimon_ai_doompi_core_apiContracts.jsonApiResponses)(typebox.Type.Object({
64
+ handle: StringSchema,
65
+ html: StringSchema,
66
+ storyPath: StringSchema,
67
+ storyExport: StringSchema,
68
+ sourceSha256: StringSchema
69
+ }))
70
+ },
71
+ {
72
+ id: "style-system-preview.image",
73
+ scope: "session",
74
+ basePath: "style-system-preview",
75
+ path: "/image",
76
+ method: "POST",
77
+ authentication: "owner",
78
+ description: "Render a fresh source-backed PNG for one exact story export.",
79
+ body: {
80
+ required: true,
81
+ contentType: "application/json",
82
+ schema: typebox.Type.Object({
83
+ appPath: StringSchema,
84
+ storyPath: StringSchema,
85
+ storyExport: StringSchema,
86
+ darkMode: typebox.Type.Optional(typebox.Type.Boolean())
87
+ })
88
+ },
89
+ responses: (0, _agimon_ai_doompi_core_apiContracts.jsonApiResponses)(typebox.Type.Object({
90
+ data: StringSchema,
91
+ mimeType: typebox.Type.Literal("image/png"),
92
+ storyPath: StringSchema,
93
+ storyExport: StringSchema,
94
+ sourceSha256: StringSchema
95
+ }))
96
+ },
97
+ {
98
+ id: "style-system-preview.dispose",
99
+ scope: "session",
100
+ basePath: "style-system-preview",
101
+ path: "/artifact",
102
+ method: "DELETE",
103
+ authentication: "owner",
104
+ description: "Dispose one session-owned story preview artifact.",
105
+ body: {
106
+ required: true,
107
+ contentType: "application/json",
108
+ schema: typebox.Type.Object({ handle: StringSchema })
109
+ },
110
+ responses: (0, _agimon_ai_doompi_core_apiContracts.jsonApiResponses)(typebox.Type.Object({ disposed: typebox.Type.Boolean() }))
111
+ }
112
+ ]
113
+ });
114
+ //#endregion
115
+ exports.apiContracts = apiContracts;
116
+ exports.default = apiContracts;
117
+
118
+ //# sourceMappingURL=apiContracts.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.cjs","names":["Type","defineApiContract","jsonApiResponses"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses } from '@agimon-ai/doompi-core/apiContracts';\nimport { Type } from 'typebox';\n\nconst StringSchema = Type.String();\nexport const apiContracts = defineApiContract({\n version: 1,\n sockets: [],\n dynamic: [],\n http: [\n {\n id: 'style-system-preview.metadata',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/metadata',\n method: 'POST',\n authentication: 'owner',\n description: 'Read exact story exports and resolve its project without executing workspace source.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({\n storyPath: StringSchema,\n appPath: Type.Optional(StringSchema),\n }),\n },\n responses: jsonApiResponses(\n Type.Object({\n storyPath: StringSchema,\n appPath: StringSchema,\n projectResolution: Type.Union([\n Type.Literal('explicit'),\n Type.Literal('config'),\n Type.Literal('package'),\n Type.Literal('workspace'),\n ]),\n exports: Type.Array(Type.Object({ exportName: StringSchema, label: Type.Optional(StringSchema) })),\n }),\n ),\n },\n {\n id: 'style-system-preview.build',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/build',\n method: 'POST',\n authentication: 'owner',\n description: 'Build an isolated HTML preview for one exact story export.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({\n appPath: StringSchema,\n storyPath: StringSchema,\n storyExport: StringSchema,\n darkMode: Type.Optional(Type.Boolean()),\n }),\n },\n responses: jsonApiResponses(\n Type.Object({\n handle: StringSchema,\n html: StringSchema,\n storyPath: StringSchema,\n storyExport: StringSchema,\n sourceSha256: StringSchema,\n }),\n ),\n },\n {\n id: 'style-system-preview.image',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/image',\n method: 'POST',\n authentication: 'owner',\n description: 'Render a fresh source-backed PNG for one exact story export.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({\n appPath: StringSchema,\n storyPath: StringSchema,\n storyExport: StringSchema,\n darkMode: Type.Optional(Type.Boolean()),\n }),\n },\n responses: jsonApiResponses(\n Type.Object({\n data: StringSchema,\n mimeType: Type.Literal('image/png'),\n storyPath: StringSchema,\n storyExport: StringSchema,\n sourceSha256: StringSchema,\n }),\n ),\n },\n {\n id: 'style-system-preview.dispose',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/artifact',\n method: 'DELETE',\n authentication: 'owner',\n description: 'Dispose one session-owned story preview artifact.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({ handle: StringSchema }),\n },\n responses: jsonApiResponses(Type.Object({ disposed: Type.Boolean() })),\n },\n ],\n});\nexport default apiContracts;\n"],"mappings":";;;;;;;AAGA,MAAM,eAAeA,QAAAA,KAAK,OAAO;AACjC,MAAa,gBAAA,GAAeC,oCAAAA,kBAAAA,CAAkB;CAC5C,SAAS;CACT,SAAS,CAAC;CACV,SAAS,CAAC;CACV,MAAM;EACJ;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQD,QAAAA,KAAK,OAAO;KAClB,WAAW;KACX,SAASA,QAAAA,KAAK,SAAS,YAAY;IACrC,CAAC;GACH;GACA,YAAA,GAAWE,oCAAAA,iBAAAA,CACTF,QAAAA,KAAK,OAAO;IACV,WAAW;IACX,SAAS;IACT,mBAAmBA,QAAAA,KAAK,MAAM;KAC5BA,QAAAA,KAAK,QAAQ,UAAU;KACvBA,QAAAA,KAAK,QAAQ,QAAQ;KACrBA,QAAAA,KAAK,QAAQ,SAAS;KACtBA,QAAAA,KAAK,QAAQ,WAAW;IAC1B,CAAC;IACD,SAASA,QAAAA,KAAK,MAAMA,QAAAA,KAAK,OAAO;KAAE,YAAY;KAAc,OAAOA,QAAAA,KAAK,SAAS,YAAY;IAAE,CAAC,CAAC;GACnG,CAAC,CACH;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQA,QAAAA,KAAK,OAAO;KAClB,SAAS;KACT,WAAW;KACX,aAAa;KACb,UAAUA,QAAAA,KAAK,SAASA,QAAAA,KAAK,QAAQ,CAAC;IACxC,CAAC;GACH;GACA,YAAA,GAAWE,oCAAAA,iBAAAA,CACTF,QAAAA,KAAK,OAAO;IACV,QAAQ;IACR,MAAM;IACN,WAAW;IACX,aAAa;IACb,cAAc;GAChB,CAAC,CACH;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQA,QAAAA,KAAK,OAAO;KAClB,SAAS;KACT,WAAW;KACX,aAAa;KACb,UAAUA,QAAAA,KAAK,SAASA,QAAAA,KAAK,QAAQ,CAAC;IACxC,CAAC;GACH;GACA,YAAA,GAAWE,oCAAAA,iBAAAA,CACTF,QAAAA,KAAK,OAAO;IACV,MAAM;IACN,UAAUA,QAAAA,KAAK,QAAQ,WAAW;IAClC,WAAW;IACX,aAAa;IACb,cAAc;GAChB,CAAC,CACH;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQA,QAAAA,KAAK,OAAO,EAAE,QAAQ,aAAa,CAAC;GAC9C;GACA,YAAA,GAAWE,oCAAAA,iBAAAA,CAAiBF,QAAAA,KAAK,OAAO,EAAE,UAAUA,QAAAA,KAAK,QAAQ,EAAE,CAAC,CAAC;EACvE;CACF;AACF,CAAC"}
@@ -0,0 +1,52 @@
1
+ //#region src/schemas/apiContracts.d.ts
2
+ export declare const apiContracts: {
3
+ version: 1;
4
+ protocols?: Record<string, string> | undefined;
5
+ schemas?: Record<string, boolean | object> | undefined;
6
+ http: {
7
+ id: string;
8
+ scope: "global" | "session" | "workspace";
9
+ basePath?: string | undefined;
10
+ path: string;
11
+ method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
12
+ description: string;
13
+ availability?: string | undefined;
14
+ authentication: "device" | "none" | "owner";
15
+ parameters?: {
16
+ name: string;
17
+ in: "header" | "path" | "query";
18
+ required: boolean;
19
+ schema: boolean | object;
20
+ }[] | undefined;
21
+ body?: {
22
+ contentType: string;
23
+ contentTypes?: string[] | undefined;
24
+ required: boolean;
25
+ schema: boolean | object;
26
+ } | undefined;
27
+ responses: Record<string, {
28
+ description: string;
29
+ contentType?: string | undefined;
30
+ schema?: boolean | object | undefined;
31
+ events?: Record<string, boolean | object> | undefined;
32
+ }>;
33
+ }[];
34
+ sockets: {
35
+ id: string;
36
+ scope: "global" | "session" | "workspace";
37
+ description: string;
38
+ availability?: string | undefined;
39
+ service: string;
40
+ member: string;
41
+ direction: "client-to-server" | "server-to-client";
42
+ kind: "channel" | "method" | "state";
43
+ input: boolean | object;
44
+ output?: boolean | object | undefined;
45
+ errors?: boolean | object | undefined;
46
+ }[];
47
+ dynamic: string[];
48
+ gaps?: string[] | undefined;
49
+ };
50
+ //#endregion
51
+ export { apiContracts as default };
52
+ //# sourceMappingURL=apiContracts.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/apiContracts.ts"],"mappings":";qBAIa"}
@@ -0,0 +1,113 @@
1
+ import { defineApiContract, jsonApiResponses } from "@agimon-ai/doompi-core/apiContracts";
2
+ import { Type } from "typebox";
3
+ //#region src/schemas/apiContracts.ts
4
+ const StringSchema = Type.String();
5
+ const apiContracts = defineApiContract({
6
+ version: 1,
7
+ sockets: [],
8
+ dynamic: [],
9
+ http: [
10
+ {
11
+ id: "style-system-preview.metadata",
12
+ scope: "session",
13
+ basePath: "style-system-preview",
14
+ path: "/metadata",
15
+ method: "POST",
16
+ authentication: "owner",
17
+ description: "Read exact story exports and resolve its project without executing workspace source.",
18
+ body: {
19
+ required: true,
20
+ contentType: "application/json",
21
+ schema: Type.Object({
22
+ storyPath: StringSchema,
23
+ appPath: Type.Optional(StringSchema)
24
+ })
25
+ },
26
+ responses: jsonApiResponses(Type.Object({
27
+ storyPath: StringSchema,
28
+ appPath: StringSchema,
29
+ projectResolution: Type.Union([
30
+ Type.Literal("explicit"),
31
+ Type.Literal("config"),
32
+ Type.Literal("package"),
33
+ Type.Literal("workspace")
34
+ ]),
35
+ exports: Type.Array(Type.Object({
36
+ exportName: StringSchema,
37
+ label: Type.Optional(StringSchema)
38
+ }))
39
+ }))
40
+ },
41
+ {
42
+ id: "style-system-preview.build",
43
+ scope: "session",
44
+ basePath: "style-system-preview",
45
+ path: "/build",
46
+ method: "POST",
47
+ authentication: "owner",
48
+ description: "Build an isolated HTML preview for one exact story export.",
49
+ body: {
50
+ required: true,
51
+ contentType: "application/json",
52
+ schema: Type.Object({
53
+ appPath: StringSchema,
54
+ storyPath: StringSchema,
55
+ storyExport: StringSchema,
56
+ darkMode: Type.Optional(Type.Boolean())
57
+ })
58
+ },
59
+ responses: jsonApiResponses(Type.Object({
60
+ handle: StringSchema,
61
+ html: StringSchema,
62
+ storyPath: StringSchema,
63
+ storyExport: StringSchema,
64
+ sourceSha256: StringSchema
65
+ }))
66
+ },
67
+ {
68
+ id: "style-system-preview.image",
69
+ scope: "session",
70
+ basePath: "style-system-preview",
71
+ path: "/image",
72
+ method: "POST",
73
+ authentication: "owner",
74
+ description: "Render a fresh source-backed PNG for one exact story export.",
75
+ body: {
76
+ required: true,
77
+ contentType: "application/json",
78
+ schema: Type.Object({
79
+ appPath: StringSchema,
80
+ storyPath: StringSchema,
81
+ storyExport: StringSchema,
82
+ darkMode: Type.Optional(Type.Boolean())
83
+ })
84
+ },
85
+ responses: jsonApiResponses(Type.Object({
86
+ data: StringSchema,
87
+ mimeType: Type.Literal("image/png"),
88
+ storyPath: StringSchema,
89
+ storyExport: StringSchema,
90
+ sourceSha256: StringSchema
91
+ }))
92
+ },
93
+ {
94
+ id: "style-system-preview.dispose",
95
+ scope: "session",
96
+ basePath: "style-system-preview",
97
+ path: "/artifact",
98
+ method: "DELETE",
99
+ authentication: "owner",
100
+ description: "Dispose one session-owned story preview artifact.",
101
+ body: {
102
+ required: true,
103
+ contentType: "application/json",
104
+ schema: Type.Object({ handle: StringSchema })
105
+ },
106
+ responses: jsonApiResponses(Type.Object({ disposed: Type.Boolean() }))
107
+ }
108
+ ]
109
+ });
110
+ //#endregion
111
+ export { apiContracts, apiContracts as default };
112
+
113
+ //# sourceMappingURL=apiContracts.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses } from '@agimon-ai/doompi-core/apiContracts';\nimport { Type } from 'typebox';\n\nconst StringSchema = Type.String();\nexport const apiContracts = defineApiContract({\n version: 1,\n sockets: [],\n dynamic: [],\n http: [\n {\n id: 'style-system-preview.metadata',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/metadata',\n method: 'POST',\n authentication: 'owner',\n description: 'Read exact story exports and resolve its project without executing workspace source.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({\n storyPath: StringSchema,\n appPath: Type.Optional(StringSchema),\n }),\n },\n responses: jsonApiResponses(\n Type.Object({\n storyPath: StringSchema,\n appPath: StringSchema,\n projectResolution: Type.Union([\n Type.Literal('explicit'),\n Type.Literal('config'),\n Type.Literal('package'),\n Type.Literal('workspace'),\n ]),\n exports: Type.Array(Type.Object({ exportName: StringSchema, label: Type.Optional(StringSchema) })),\n }),\n ),\n },\n {\n id: 'style-system-preview.build',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/build',\n method: 'POST',\n authentication: 'owner',\n description: 'Build an isolated HTML preview for one exact story export.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({\n appPath: StringSchema,\n storyPath: StringSchema,\n storyExport: StringSchema,\n darkMode: Type.Optional(Type.Boolean()),\n }),\n },\n responses: jsonApiResponses(\n Type.Object({\n handle: StringSchema,\n html: StringSchema,\n storyPath: StringSchema,\n storyExport: StringSchema,\n sourceSha256: StringSchema,\n }),\n ),\n },\n {\n id: 'style-system-preview.image',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/image',\n method: 'POST',\n authentication: 'owner',\n description: 'Render a fresh source-backed PNG for one exact story export.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({\n appPath: StringSchema,\n storyPath: StringSchema,\n storyExport: StringSchema,\n darkMode: Type.Optional(Type.Boolean()),\n }),\n },\n responses: jsonApiResponses(\n Type.Object({\n data: StringSchema,\n mimeType: Type.Literal('image/png'),\n storyPath: StringSchema,\n storyExport: StringSchema,\n sourceSha256: StringSchema,\n }),\n ),\n },\n {\n id: 'style-system-preview.dispose',\n scope: 'session',\n basePath: 'style-system-preview',\n path: '/artifact',\n method: 'DELETE',\n authentication: 'owner',\n description: 'Dispose one session-owned story preview artifact.',\n body: {\n required: true,\n contentType: 'application/json',\n schema: Type.Object({ handle: StringSchema }),\n },\n responses: jsonApiResponses(Type.Object({ disposed: Type.Boolean() })),\n },\n ],\n});\nexport default apiContracts;\n"],"mappings":";;;AAGA,MAAM,eAAe,KAAK,OAAO;AACjC,MAAa,eAAe,kBAAkB;CAC5C,SAAS;CACT,SAAS,CAAC;CACV,SAAS,CAAC;CACV,MAAM;EACJ;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQ,KAAK,OAAO;KAClB,WAAW;KACX,SAAS,KAAK,SAAS,YAAY;IACrC,CAAC;GACH;GACA,WAAW,iBACT,KAAK,OAAO;IACV,WAAW;IACX,SAAS;IACT,mBAAmB,KAAK,MAAM;KAC5B,KAAK,QAAQ,UAAU;KACvB,KAAK,QAAQ,QAAQ;KACrB,KAAK,QAAQ,SAAS;KACtB,KAAK,QAAQ,WAAW;IAC1B,CAAC;IACD,SAAS,KAAK,MAAM,KAAK,OAAO;KAAE,YAAY;KAAc,OAAO,KAAK,SAAS,YAAY;IAAE,CAAC,CAAC;GACnG,CAAC,CACH;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQ,KAAK,OAAO;KAClB,SAAS;KACT,WAAW;KACX,aAAa;KACb,UAAU,KAAK,SAAS,KAAK,QAAQ,CAAC;IACxC,CAAC;GACH;GACA,WAAW,iBACT,KAAK,OAAO;IACV,QAAQ;IACR,MAAM;IACN,WAAW;IACX,aAAa;IACb,cAAc;GAChB,CAAC,CACH;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQ,KAAK,OAAO;KAClB,SAAS;KACT,WAAW;KACX,aAAa;KACb,UAAU,KAAK,SAAS,KAAK,QAAQ,CAAC;IACxC,CAAC;GACH;GACA,WAAW,iBACT,KAAK,OAAO;IACV,MAAM;IACN,UAAU,KAAK,QAAQ,WAAW;IAClC,WAAW;IACX,aAAa;IACb,cAAc;GAChB,CAAC,CACH;EACF;EACA;GACE,IAAI;GACJ,OAAO;GACP,UAAU;GACV,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,aAAa;GACb,MAAM;IACJ,UAAU;IACV,aAAa;IACb,QAAQ,KAAK,OAAO,EAAE,QAAQ,aAAa,CAAC;GAC9C;GACA,WAAW,iBAAiB,KAAK,OAAO,EAAE,UAAU,KAAK,QAAQ,EAAE,CAAC,CAAC;EACvE;CACF;AACF,CAAC"}
package/dist/cli.cjs ADDED
@@ -0,0 +1,242 @@
1
+ #!/usr/bin/env node
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
4
+ const require_storyPreview = require("./storyPreview-D-hGhlig.cjs");
5
+ const require_designCheck = require("./designCheck-zx4PsRvE.cjs");
6
+ let node_fs = require("node:fs");
7
+ let node_path = require("node:path");
8
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
9
+ let node_url = require("node:url");
10
+ let node_child_process = require("node:child_process");
11
+ let node_module = require("node:module");
12
+ //#region src/services/designCli/index.ts
13
+ const DISCOVERY_COMMANDS = /* @__PURE__ */ new Set([
14
+ "list-shared-components",
15
+ "list-app-components",
16
+ "get-css-classes",
17
+ "list-themes",
18
+ "get-ui-component"
19
+ ]);
20
+ const MAX_OUTPUT_BYTES = 2097152;
21
+ const DISCOVERY_TIMEOUT_MS = 12e4;
22
+ const STRUCTURED_COMMANDS = /* @__PURE__ */ new Set([
23
+ "metadata",
24
+ "story-metadata",
25
+ "check",
26
+ "verify",
27
+ "preview"
28
+ ]);
29
+ function option(values, ...names) {
30
+ for (const name of names) {
31
+ const inline = values.find((value) => value.startsWith(`${name}=`));
32
+ if (inline !== void 0) return inline.slice(name.length + 1);
33
+ const index = values.indexOf(name);
34
+ const value = index < 0 ? void 0 : values[index + 1];
35
+ if (value !== void 0 && !value.startsWith("--")) return value;
36
+ }
37
+ }
38
+ function requiredOption(values, name) {
39
+ const value = option(values, name);
40
+ if (value === void 0 || value.trim() === "") throw new Error(`${name} is required`);
41
+ return value;
42
+ }
43
+ function parseArguments(argv) {
44
+ const [command, ...values] = argv;
45
+ return {
46
+ command,
47
+ values,
48
+ workspace: node_path.default.resolve(option(values, "--workspace", "--workspace-root") ?? process.cwd())
49
+ };
50
+ }
51
+ function printJson(value) {
52
+ process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
53
+ }
54
+ function reportExitCode(status) {
55
+ return status === "ready" ? 0 : status === "not-ready" ? 1 : 2;
56
+ }
57
+ function upstreamCliPath() {
58
+ const packageJsonPath = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href).resolve("@agimon-ai/style-system/package.json");
59
+ const packageJson = JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf8"));
60
+ const bin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.["style-system"];
61
+ if (bin === void 0) throw new Error("The installed style-system package does not expose its CLI.");
62
+ return node_path.default.resolve(node_path.default.dirname(packageJsonPath), bin);
63
+ }
64
+ function stripWorkspaceOptions(values) {
65
+ const result = [];
66
+ for (let index = 0; index < values.length; index += 1) {
67
+ const value = values[index];
68
+ if (value === "--workspace" || value === "--workspace-root") {
69
+ index += 1;
70
+ continue;
71
+ }
72
+ if (value.startsWith("--workspace=") || value.startsWith("--workspace-root=")) continue;
73
+ result.push(value);
74
+ }
75
+ return result;
76
+ }
77
+ async function delegateDiscovery(values, workspace) {
78
+ const child = (0, node_child_process.spawn)(process.execPath, [upstreamCliPath(), ...stripWorkspaceOptions(values)], {
79
+ cwd: workspace,
80
+ env: { ...process.env },
81
+ stdio: [
82
+ "inherit",
83
+ "pipe",
84
+ "pipe"
85
+ ]
86
+ });
87
+ return new Promise((resolve) => {
88
+ let outputBytes = 0;
89
+ let settled = false;
90
+ let exceeded = false;
91
+ let timeout;
92
+ const finish = (code) => {
93
+ if (settled) return;
94
+ settled = true;
95
+ if (timeout !== void 0) clearTimeout(timeout);
96
+ resolve(code);
97
+ };
98
+ const forward = (chunk, stream) => {
99
+ outputBytes += chunk.byteLength;
100
+ if (outputBytes > MAX_OUTPUT_BYTES) {
101
+ exceeded = true;
102
+ child.kill("SIGTERM");
103
+ return;
104
+ }
105
+ stream.write(chunk);
106
+ };
107
+ child.once("error", (error) => {
108
+ process.stderr.write(`${error.message}\n`);
109
+ finish(3);
110
+ });
111
+ child.once("exit", (code, signal) => {
112
+ if (exceeded || signal !== null) finish(3);
113
+ else finish(code ?? 3);
114
+ });
115
+ child.stdout.on("data", (chunk) => forward(chunk, process.stdout));
116
+ child.stderr.on("data", (chunk) => forward(chunk, process.stderr));
117
+ timeout = setTimeout(() => {
118
+ exceeded = true;
119
+ child.kill("SIGTERM");
120
+ }, DISCOVERY_TIMEOUT_MS);
121
+ }).then((result) => {
122
+ if (result === 3) process.stderr.write("style-system discovery timed out, exceeded its output limit, or failed.\n");
123
+ return result;
124
+ });
125
+ }
126
+ async function containedPath(root, input, field) {
127
+ const candidate = node_path.default.resolve(root, input);
128
+ if (!isContained(root, candidate)) throw new Error(`${field} must remain inside the workspace root`);
129
+ const canonical = await node_fs.promises.realpath(candidate);
130
+ if (!isContained(root, canonical)) throw new Error(`${field} must remain inside the workspace root`);
131
+ return canonical;
132
+ }
133
+ function isContained(root, candidate) {
134
+ const relative = node_path.default.relative(root, candidate);
135
+ return relative === "" || !relative.startsWith(`..${node_path.default.sep}`) && relative !== ".." && !node_path.default.isAbsolute(relative);
136
+ }
137
+ async function outputPath(root, input, field) {
138
+ const candidate = node_path.default.resolve(root, input);
139
+ if (!isContained(root, candidate)) throw new Error(`${field} must remain inside the workspace root`);
140
+ let existing = candidate;
141
+ while (true) try {
142
+ if (!isContained(root, await node_fs.promises.realpath(existing))) throw new Error(`${field} must remain inside the workspace root`);
143
+ return candidate;
144
+ } catch (error) {
145
+ if (error.code !== "ENOENT") throw error;
146
+ const parent = node_path.default.dirname(existing);
147
+ if (parent === existing) throw new Error(`${field} must remain inside the workspace root`);
148
+ existing = parent;
149
+ }
150
+ }
151
+ async function runStructured(parsed, workspace) {
152
+ const { command, values } = parsed;
153
+ if (command === "metadata" || command === "story-metadata") {
154
+ printJson(await new require_storyPreview.StoryPreviewService(workspace).metadata({
155
+ storyPath: requiredOption(values, "--story-path"),
156
+ appPath: option(values, "--app-path")
157
+ }));
158
+ return 0;
159
+ }
160
+ if (command === "check") {
161
+ const target = await require_designCheck.readDesignTarget(await containedPath(workspace, requiredOption(values, "--target"), "target"));
162
+ const report = await require_designCheck.checkDesignTarget(target, workspace);
163
+ const reportFile = option(values, "--report");
164
+ if (reportFile !== void 0) {
165
+ const targetPath = await outputPath(workspace, reportFile, "report");
166
+ await node_fs.promises.mkdir(node_path.default.dirname(targetPath), { recursive: true });
167
+ await node_fs.promises.writeFile(targetPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
168
+ }
169
+ printJson(report);
170
+ return reportExitCode(report.status);
171
+ }
172
+ if (command === "verify") {
173
+ const result = await require_designCheck.verifyDesignReport(await containedPath(workspace, requiredOption(values, "--report"), "report"), workspace);
174
+ printJson(result);
175
+ return result.current && result.report.status === "ready" ? 0 : 2;
176
+ }
177
+ if (command === "preview") {
178
+ const output = option(values, "--output");
179
+ const targetPath = output === void 0 ? void 0 : await outputPath(workspace, output, "output");
180
+ const service = new require_storyPreview.StoryPreviewService(workspace);
181
+ const result = await service.build({
182
+ appPath: requiredOption(values, "--app-path"),
183
+ storyPath: requiredOption(values, "--story-path"),
184
+ storyExport: requiredOption(values, "--story-export"),
185
+ darkMode: values.includes("--dark-mode")
186
+ });
187
+ try {
188
+ if (targetPath === void 0) process.stdout.write(result.html);
189
+ else {
190
+ await node_fs.promises.mkdir(node_path.default.dirname(targetPath), { recursive: true });
191
+ await node_fs.promises.writeFile(targetPath, result.html, "utf8");
192
+ printJson({
193
+ handle: result.handle,
194
+ storyPath: result.storyPath,
195
+ storyExport: result.storyExport,
196
+ outputPath: node_path.default.relative(workspace, targetPath)
197
+ });
198
+ }
199
+ } finally {
200
+ await service.dispose(result.handle);
201
+ }
202
+ return 0;
203
+ }
204
+ throw new Error(`Unknown structured command '${command ?? ""}'.`);
205
+ }
206
+ function help() {
207
+ process.stdout.write([
208
+ "doompi-design <command>",
209
+ "",
210
+ "Discovery commands delegated to @agimon-ai/style-system:",
211
+ " list-shared-components, list-app-components, get-css-classes, list-themes, get-ui-component",
212
+ "",
213
+ "Portable commands:",
214
+ " metadata --story-path <path> [--app-path <path>]",
215
+ " check --target <path> [--report <path>]",
216
+ " verify --report <path>",
217
+ " preview --app-path <path> --story-path <path> --story-export <name> [--output <path>]",
218
+ "",
219
+ "Use --workspace <path> to select the admitted workspace for any command."
220
+ ].join("\n") + "\n");
221
+ }
222
+ async function main(argv = process.argv.slice(2)) {
223
+ const parsed = parseArguments(argv);
224
+ if (parsed.command === void 0 || parsed.command === "--help" || parsed.command === "-h") {
225
+ help();
226
+ return 0;
227
+ }
228
+ const workspace = await node_fs.promises.realpath(parsed.workspace);
229
+ if (DISCOVERY_COMMANDS.has(parsed.command)) return delegateDiscovery([parsed.command, ...parsed.values], workspace);
230
+ if (!STRUCTURED_COMMANDS.has(parsed.command)) throw new Error(`Unknown command '${parsed.command}'.`);
231
+ return runStructured(parsed, workspace);
232
+ }
233
+ if (process.argv[1] !== void 0 && (0, node_fs.realpathSync)(process.argv[1]) === (0, node_fs.realpathSync)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href))) main().then((code) => {
234
+ process.exitCode = code;
235
+ }, (error) => {
236
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
237
+ process.exitCode = 3;
238
+ });
239
+ //#endregion
240
+ exports.main = main;
241
+
242
+ //# sourceMappingURL=cli.cjs.map