phibelle-kit 1.0.31 → 1.0.32
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/dist/commands/clone-scene.js +4 -14
- package/dist/commands/watch-scene.js +5 -31
- package/dist/lib/constants.d.ts +12 -0
- package/dist/lib/constants.js +12 -0
- package/dist/lib/manifest.d.ts +5 -0
- package/dist/lib/manifest.js +31 -0
- package/dist/lib/scene/file-system.d.ts +2 -1
- package/dist/lib/scene/file-system.js +3 -2
- package/dist/lib/scene/scene-packaging.js +3 -3
- package/dist/lib/scene/script-watcher.js +3 -2
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +10 -0
- package/dist/scene-setup/setup.d.ts +0 -1
- package/dist/scene-setup/setup.js +0 -15
- package/package.json +1 -1
|
@@ -4,11 +4,10 @@ import * as fs from "node:fs/promises";
|
|
|
4
4
|
import { execFile } from "node:child_process";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { WebSocketServer } from "ws";
|
|
7
|
+
import { WS_PORT, CLONE_REQUEST_TYPE, CLONE_RESPONSE_TYPE, SCENE_FILE_NAME, } from "../lib/constants.js";
|
|
8
|
+
import { getExecErrorText } from "../lib/utils.js";
|
|
7
9
|
import { parseSceneJson, unpackageScene } from "../lib/scene/scene-packaging.js";
|
|
8
10
|
import { setupSceneDirectory } from "../scene-setup/setup.js";
|
|
9
|
-
const WS_PORT = 31113;
|
|
10
|
-
const CLONE_REQUEST_TYPE = "phibelle-kit-clone-request";
|
|
11
|
-
const CLONE_RESPONSE_TYPE = "phibelle-kit-clone-response";
|
|
12
11
|
const CLONE_TIMEOUT_MS = 30_000;
|
|
13
12
|
const INITIAL_COMMIT_MESSAGE = "Initial scene clone from Phibelle";
|
|
14
13
|
const execFileAsync = promisify(execFile);
|
|
@@ -26,7 +25,7 @@ export async function cloneSceneCommand() {
|
|
|
26
25
|
await ensureDirectoryDoesNotExist(sceneDir);
|
|
27
26
|
await fs.mkdir(sceneDir, { recursive: false });
|
|
28
27
|
setupSceneDirectory(sceneDir);
|
|
29
|
-
await fs.writeFile(path.join(sceneDir,
|
|
28
|
+
await fs.writeFile(path.join(sceneDir, SCENE_FILE_NAME), payload.sceneData, "utf8");
|
|
30
29
|
await unpackageScene(payload.sceneData, sceneDir, payload.sceneId);
|
|
31
30
|
await initializeGitRepository(sceneDir);
|
|
32
31
|
console.log(chalk.green(" ✓ Scene cloned successfully"));
|
|
@@ -148,7 +147,7 @@ async function initializeGitRepository(sceneDir) {
|
|
|
148
147
|
}
|
|
149
148
|
catch (error) {
|
|
150
149
|
console.log(chalk.yellow(" ! Git initialization or first commit was skipped"));
|
|
151
|
-
const details =
|
|
150
|
+
const details = getExecErrorText(error);
|
|
152
151
|
if (details) {
|
|
153
152
|
console.log(chalk.gray(` ${details}`));
|
|
154
153
|
}
|
|
@@ -158,12 +157,3 @@ async function initializeGitRepository(sceneDir) {
|
|
|
158
157
|
async function runGit(args, cwd) {
|
|
159
158
|
await execFileAsync("git", args, { cwd });
|
|
160
159
|
}
|
|
161
|
-
function getErrorText(error) {
|
|
162
|
-
if (!error || typeof error !== "object")
|
|
163
|
-
return "";
|
|
164
|
-
const err = error;
|
|
165
|
-
const stderr = err.stderr?.trim();
|
|
166
|
-
if (stderr)
|
|
167
|
-
return stderr.split("\n").pop() ?? stderr;
|
|
168
|
-
return err.message?.trim() ?? "";
|
|
169
|
-
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import * as fs from "fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import readline from "node:readline";
|
|
4
5
|
import { WebSocketServer } from "ws";
|
|
6
|
+
import { WS_PORT, SCENE_SYNC_TYPE, SCENE_FILE_NAME } from "../lib/constants.js";
|
|
7
|
+
import { getRequiredManifestSceneId } from "../lib/manifest.js";
|
|
5
8
|
import { unpackageScene, parseSceneJson, packageSceneFromFilesystem } from "../lib/scene/scene-packaging.js";
|
|
6
9
|
import { createScriptWatcher } from "../lib/scene/script-watcher.js";
|
|
7
10
|
import { toErrorMessage } from "../lib/utils.js";
|
|
8
|
-
import readline from "readline";
|
|
9
11
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
10
|
-
const WS_PORT = 31113;
|
|
11
|
-
const SCENE_SYNC_TYPE = "phibelle-kit-scene-sync";
|
|
12
|
-
const SCENE_FILE_NAME = "scene.phibelle";
|
|
13
|
-
const MANIFEST_FILE_NAME = "manifest.json";
|
|
14
12
|
export const BASE_URL = process.env.NODE_ENV === "development" ? "http://localhost:3131" : "https://phibelle.studio";
|
|
15
13
|
export async function watchSceneCommand() {
|
|
16
14
|
const sceneDir = process.cwd();
|
|
@@ -186,27 +184,3 @@ function askQuestion(prompt) {
|
|
|
186
184
|
rl.question(prompt, resolve);
|
|
187
185
|
});
|
|
188
186
|
}
|
|
189
|
-
function getRequiredManifestSceneId(sceneDir) {
|
|
190
|
-
const manifestPath = path.join(sceneDir, MANIFEST_FILE_NAME);
|
|
191
|
-
if (!fs.existsSync(manifestPath)) {
|
|
192
|
-
throw new Error(`Missing ${MANIFEST_FILE_NAME} in ${sceneDir}. Run "phibelle-kit clone" first or watch from a cloned scene folder.`);
|
|
193
|
-
}
|
|
194
|
-
let manifestRaw;
|
|
195
|
-
try {
|
|
196
|
-
manifestRaw = fs.readFileSync(manifestPath, "utf8");
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
throw new Error(`Failed to read ${MANIFEST_FILE_NAME} in ${sceneDir}.`);
|
|
200
|
-
}
|
|
201
|
-
let manifest;
|
|
202
|
-
try {
|
|
203
|
-
manifest = JSON.parse(manifestRaw);
|
|
204
|
-
}
|
|
205
|
-
catch {
|
|
206
|
-
throw new Error(`Invalid ${MANIFEST_FILE_NAME}: expected valid JSON.`);
|
|
207
|
-
}
|
|
208
|
-
if (typeof manifest.sceneId !== "string" || !manifest.sceneId.trim()) {
|
|
209
|
-
throw new Error(`Invalid ${MANIFEST_FILE_NAME}: missing required "sceneId".`);
|
|
210
|
-
}
|
|
211
|
-
return manifest.sceneId.trim();
|
|
212
|
-
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** WebSocket port for phibelle-kit CLI ↔ web app communication. Must match app's use-cli-websocket.ts */
|
|
2
|
+
export declare const WS_PORT = 31113;
|
|
3
|
+
/** Scene JSON file in cloned scene directory */
|
|
4
|
+
export declare const SCENE_FILE_NAME = "scene.phibelle";
|
|
5
|
+
/** Manifest file mapping entity IDs to filesystem paths */
|
|
6
|
+
export declare const MANIFEST_FILE_NAME = "manifest.json";
|
|
7
|
+
/** Message type for scene sync over WebSocket */
|
|
8
|
+
export declare const SCENE_SYNC_TYPE = "phibelle-kit-scene-sync";
|
|
9
|
+
/** Message type for clone request from kit to app */
|
|
10
|
+
export declare const CLONE_REQUEST_TYPE = "phibelle-kit-clone-request";
|
|
11
|
+
/** Message type for clone response from app to kit */
|
|
12
|
+
export declare const CLONE_RESPONSE_TYPE = "phibelle-kit-clone-response";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** WebSocket port for phibelle-kit CLI ↔ web app communication. Must match app's use-cli-websocket.ts */
|
|
2
|
+
export const WS_PORT = 31113;
|
|
3
|
+
/** Scene JSON file in cloned scene directory */
|
|
4
|
+
export const SCENE_FILE_NAME = "scene.phibelle";
|
|
5
|
+
/** Manifest file mapping entity IDs to filesystem paths */
|
|
6
|
+
export const MANIFEST_FILE_NAME = "manifest.json";
|
|
7
|
+
/** Message type for scene sync over WebSocket */
|
|
8
|
+
export const SCENE_SYNC_TYPE = "phibelle-kit-scene-sync";
|
|
9
|
+
/** Message type for clone request from kit to app */
|
|
10
|
+
export const CLONE_REQUEST_TYPE = "phibelle-kit-clone-request";
|
|
11
|
+
/** Message type for clone response from app to kit */
|
|
12
|
+
export const CLONE_RESPONSE_TYPE = "phibelle-kit-clone-response";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { MANIFEST_FILE_NAME } from "./constants.js";
|
|
4
|
+
/**
|
|
5
|
+
* Read manifest.json from sceneDir and return the required sceneId.
|
|
6
|
+
* Throws with user-facing errors if manifest is missing, unreadable, invalid JSON, or missing sceneId.
|
|
7
|
+
*/
|
|
8
|
+
export function getRequiredManifestSceneId(sceneDir) {
|
|
9
|
+
const manifestPath = path.join(sceneDir, MANIFEST_FILE_NAME);
|
|
10
|
+
if (!fs.existsSync(manifestPath)) {
|
|
11
|
+
throw new Error(`Missing ${MANIFEST_FILE_NAME} in ${sceneDir}. Run "phibelle-kit clone" first or watch from a cloned scene folder.`);
|
|
12
|
+
}
|
|
13
|
+
let manifestRaw;
|
|
14
|
+
try {
|
|
15
|
+
manifestRaw = fs.readFileSync(manifestPath, "utf8");
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new Error(`Failed to read ${MANIFEST_FILE_NAME} in ${sceneDir}.`);
|
|
19
|
+
}
|
|
20
|
+
let manifest;
|
|
21
|
+
try {
|
|
22
|
+
manifest = JSON.parse(manifestRaw);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new Error(`Invalid ${MANIFEST_FILE_NAME}: expected valid JSON.`);
|
|
26
|
+
}
|
|
27
|
+
if (typeof manifest.sceneId !== "string" || !manifest.sceneId.trim()) {
|
|
28
|
+
throw new Error(`Invalid ${MANIFEST_FILE_NAME}: missing required "sceneId".`);
|
|
29
|
+
}
|
|
30
|
+
return manifest.sceneId.trim();
|
|
31
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { SCENE_FILE_NAME } from "../constants.js";
|
|
1
2
|
export declare const SCENE_APP_DIR = "app";
|
|
2
|
-
export
|
|
3
|
+
export { SCENE_FILE_NAME };
|
|
3
4
|
export declare function getSceneAppDir(sceneDir: string): string;
|
|
4
5
|
export declare function folderExists(folderPath: string): boolean;
|
|
5
6
|
export declare function createFolder(folderPath: string): void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import * as fs from "fs";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import { SCENE_FILE_NAME } from "../constants.js";
|
|
3
4
|
export const SCENE_APP_DIR = "app";
|
|
4
|
-
export
|
|
5
|
+
export { SCENE_FILE_NAME };
|
|
5
6
|
export function getSceneAppDir(sceneDir) {
|
|
6
7
|
return path.join(sceneDir, SCENE_APP_DIR);
|
|
7
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as fs from "fs/promises";
|
|
2
|
-
import * as path from "path";
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
3
|
import { getSceneAppDir } from "./file-system.js";
|
|
4
|
-
|
|
4
|
+
import { MANIFEST_FILE_NAME } from "../constants.js";
|
|
5
5
|
const LEGACY_SCENE_FILE = "scene.tsx";
|
|
6
6
|
const CHILDREN_DIR_NAME = "children";
|
|
7
7
|
/** Scene-level file names in app/. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import * as path from "path";
|
|
1
|
+
import * as path from "node:path";
|
|
2
2
|
import chokidar from "chokidar";
|
|
3
|
+
import { MANIFEST_FILE_NAME } from "../constants.js";
|
|
3
4
|
import { getSceneAppDir } from "./file-system.js";
|
|
4
5
|
import { packageSceneFromFilesystem, ENTITY_SCRIPT_FILE, ENTITY_PROPERTIES_FILE, ENTITY_TRANSFORMS_FILE, SCENE_SCRIPT_FILE, SCENE_PROPERTIES_FILE, } from "./scene-packaging.js";
|
|
5
6
|
const DEBOUNCE_MS = 100;
|
|
@@ -48,7 +49,7 @@ export function createScriptWatcher(sceneDir, getLatestSceneJson, onSceneUpdated
|
|
|
48
49
|
const watcher = chokidar.watch(appDir, { ignoreInitial: true });
|
|
49
50
|
function handlePathEvent(filePath) {
|
|
50
51
|
const relativePath = toRelativePath(filePath);
|
|
51
|
-
if (relativePath ===
|
|
52
|
+
if (relativePath === MANIFEST_FILE_NAME)
|
|
52
53
|
return;
|
|
53
54
|
if (isRelevantPath(relativePath))
|
|
54
55
|
schedule(relativePath);
|
package/dist/lib/utils.d.ts
CHANGED
package/dist/lib/utils.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
export function toErrorMessage(err) {
|
|
2
2
|
return err instanceof Error ? err.message : String(err);
|
|
3
3
|
}
|
|
4
|
+
/** For exec/child_process errors: prefer stderr (last line), otherwise message. */
|
|
5
|
+
export function getExecErrorText(error) {
|
|
6
|
+
if (!error || typeof error !== "object")
|
|
7
|
+
return "";
|
|
8
|
+
const err = error;
|
|
9
|
+
const stderr = err.stderr?.trim();
|
|
10
|
+
if (stderr)
|
|
11
|
+
return stderr.split("\n").pop() ?? stderr;
|
|
12
|
+
return err.message?.trim() ?? "";
|
|
13
|
+
}
|
|
@@ -39,18 +39,3 @@ export function setupSceneDirectory(sceneDir) {
|
|
|
39
39
|
}
|
|
40
40
|
return { shouldPromptInstall };
|
|
41
41
|
}
|
|
42
|
-
export function getInstallHint(sceneDir) {
|
|
43
|
-
const hasPnpm = fs.existsSync(path.join(sceneDir, "pnpm-lock.yaml"));
|
|
44
|
-
const hasYarn = fs.existsSync(path.join(sceneDir, "yarn.lock"));
|
|
45
|
-
const hasBun = fs.existsSync(path.join(sceneDir, "bun.lockb"));
|
|
46
|
-
const hasNpm = fs.existsSync(path.join(sceneDir, "package-lock.json"));
|
|
47
|
-
if (hasPnpm)
|
|
48
|
-
return "pnpm install";
|
|
49
|
-
if (hasBun)
|
|
50
|
-
return "bun install";
|
|
51
|
-
if (hasYarn)
|
|
52
|
-
return "yarn install";
|
|
53
|
-
if (hasNpm)
|
|
54
|
-
return "npm install";
|
|
55
|
-
return "npm install (or pnpm / bun / yarn install)";
|
|
56
|
-
}
|