create-aiaui-module 0.0.0-stage → 0.1.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.
Files changed (43) hide show
  1. package/README.md +34 -2
  2. package/bin/create-aiaui-module.js +73 -0
  3. package/package.json +13 -4
  4. package/runtime/__init__.py +39 -0
  5. package/runtime/_runtime/__init__.py +40 -0
  6. package/runtime/_runtime/host.py +88 -0
  7. package/runtime/_runtime/loader.py +39 -0
  8. package/runtime/_runtime/registry.py +93 -0
  9. package/src/errors.js +6 -0
  10. package/src/generator.js +194 -0
  11. package/src/protocol.js +98 -0
  12. package/templates/HelloWorld/README.md +5 -0
  13. package/templates/HelloWorld/contractVersion +1 -0
  14. package/templates/HelloWorld/resources/build.mjs +9 -0
  15. package/templates/HelloWorld/resources/dist/manifest.json +6 -0
  16. package/templates/HelloWorld/resources/dist/modules.js +3753 -0
  17. package/templates/HelloWorld/resources/package.json +12 -0
  18. package/templates/HelloWorld/resources/src/Hello.ce.vue +25 -0
  19. package/templates/HelloWorld/resources/src/index.ts +32 -0
  20. package/templates/HelloWorld/resources/vite.config.mjs +13 -0
  21. package/templates/JobInformation/CUSTOMIZATION.md +173 -0
  22. package/templates/JobInformation/README.md +113 -0
  23. package/templates/JobInformation/api.py +53 -0
  24. package/templates/JobInformation/contractVersion +1 -0
  25. package/templates/JobInformation/resources/build.mjs +9 -0
  26. package/templates/JobInformation/resources/dist/manifest.json +6 -0
  27. package/templates/JobInformation/resources/dist/modules.js +2919 -0
  28. package/templates/JobInformation/resources/package-lock.json +1032 -0
  29. package/templates/JobInformation/resources/package.json +15 -0
  30. package/templates/JobInformation/resources/src/bus.ts +38 -0
  31. package/templates/JobInformation/resources/src/contract.ts +74 -0
  32. package/templates/JobInformation/resources/src/customization.ts +25 -0
  33. package/templates/JobInformation/resources/src/defaults/DefaultPanel.vue +22 -0
  34. package/templates/JobInformation/resources/src/defaults/Header.vue +12 -0
  35. package/templates/JobInformation/resources/src/defaults/InputCarriers.vue +15 -0
  36. package/templates/JobInformation/resources/src/defaults/OutputCarriers.vue +14 -0
  37. package/templates/JobInformation/resources/src/defaults/Recipe.vue +18 -0
  38. package/templates/JobInformation/resources/src/defaults/Timeline.vue +22 -0
  39. package/templates/JobInformation/resources/src/defaults/slots.ts +16 -0
  40. package/templates/JobInformation/resources/src/defaults/styles.css +90 -0
  41. package/templates/JobInformation/resources/src/index.ts +45 -0
  42. package/templates/JobInformation/resources/src/vite-env.d.ts +1 -0
  43. package/templates/JobInformation/resources/vite.config.mjs +27 -0
@@ -0,0 +1,98 @@
1
+ import { lstat, open, readFile, rename, rm, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+
5
+ import { GeneratorError } from "./errors.js";
6
+
7
+ const MODULE_ID = /^[A-Za-z][A-Za-z0-9_]*$/;
8
+
9
+ function validProtocol(value) {
10
+ return (
11
+ value &&
12
+ typeof value === "object" &&
13
+ !Array.isArray(value) &&
14
+ value.schemaVersion === 1 &&
15
+ (value.port === null ||
16
+ (Number.isInteger(value.port) &&
17
+ value.port >= 1 &&
18
+ value.port <= 65535)) &&
19
+ Array.isArray(value.modules) &&
20
+ value.modules.every(
21
+ (module) =>
22
+ module &&
23
+ typeof module === "object" &&
24
+ MODULE_ID.test(module.name) &&
25
+ typeof module.enabled === "boolean",
26
+ ) &&
27
+ new Set(value.modules.map((module) => module.name)).size ===
28
+ value.modules.length
29
+ );
30
+ }
31
+
32
+ export async function registerModule(instanceRoot, moduleId) {
33
+ const configPath = path.join(instanceRoot, "Config", "AIAUIProtocol.json");
34
+ const draft = {
35
+ schemaVersion: 1,
36
+ port: null,
37
+ modules: [{ name: moduleId, enabled: false }],
38
+ };
39
+ let entry;
40
+ try {
41
+ entry = await lstat(configPath);
42
+ } catch (error) {
43
+ if (error.code !== "ENOENT") throw error;
44
+ }
45
+ if (!entry) {
46
+ try {
47
+ const handle = await open(configPath, "wx");
48
+ try {
49
+ await handle.writeFile(JSON.stringify(draft, null, 2) + "\n");
50
+ } catch (error) {
51
+ await handle.close();
52
+ await rm(configPath, { force: true });
53
+ throw error;
54
+ }
55
+ await handle.close();
56
+ return { configPath, enabled: false, port: null };
57
+ } catch (error) {
58
+ if (error.code !== "EEXIST") throw error;
59
+ entry = await lstat(configPath);
60
+ }
61
+ }
62
+ if (!entry.isFile() || entry.isSymbolicLink()) {
63
+ throw new GeneratorError(
64
+ "invalid_protocol",
65
+ "AIAUIProtocol.json must be a real file",
66
+ );
67
+ }
68
+ let protocol;
69
+ try {
70
+ protocol = JSON.parse(await readFile(configPath, "utf8"));
71
+ } catch (error) {
72
+ throw new GeneratorError(
73
+ "invalid_protocol",
74
+ `AIAUIProtocol.json is not valid JSON: ${error.message}`,
75
+ );
76
+ }
77
+ if (!validProtocol(protocol)) {
78
+ throw new GeneratorError(
79
+ "invalid_protocol",
80
+ "AIAUIProtocol.json must have schemaVersion 1, a port or null, and a modules array",
81
+ );
82
+ }
83
+ const existing = protocol.modules.find((module) => module.name === moduleId);
84
+ if (existing)
85
+ return { configPath, enabled: existing.enabled, port: protocol.port };
86
+ protocol.modules.push({ name: moduleId, enabled: false });
87
+ const temporary = `${configPath}.${randomUUID()}.tmp`;
88
+ try {
89
+ await writeFile(temporary, JSON.stringify(protocol, null, 2) + "\n", {
90
+ flag: "wx",
91
+ mode: entry.mode,
92
+ });
93
+ await rename(temporary, configPath);
94
+ } finally {
95
+ await rm(temporary, { force: true });
96
+ }
97
+ return { configPath, enabled: false, port: protocol.port };
98
+ }
@@ -0,0 +1,5 @@
1
+ # HelloWorld module
2
+
3
+ This frontend-only template shows a minimal AIAUI module. Edit `resources/src/Hello.ce.vue`, then run `npm install` and `npm run build` inside `resources/` to refresh the prebuilt file. `resources/src/index.ts` remains the module entry. There is intentionally no `api.py`.
4
+
5
+ Generation creates `PyAIAUI/HelloWorld/` and registers it as disabled in `Config/AIAUIProtocol.json`. Set a port and enable it after integrating the module host.
@@ -0,0 +1 @@
1
+ 1
@@ -0,0 +1,9 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { build } from "vite";
3
+
4
+ await build();
5
+ await writeFile(
6
+ "dist/manifest.json",
7
+ JSON.stringify({ entry: "modules.js", files: ["modules.js"] }, null, 2) +
8
+ "\n",
9
+ );
@@ -0,0 +1,6 @@
1
+ {
2
+ "entry": "modules.js",
3
+ "files": [
4
+ "modules.js"
5
+ ]
6
+ }