ridgeline 0.7.4 → 0.7.11

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 (111) hide show
  1. package/README.md +2 -0
  2. package/dist/agents/core/designer.md +18 -0
  3. package/dist/agents/core/planner.md +36 -0
  4. package/dist/agents/core/refiner.md +4 -0
  5. package/dist/agents/core/researcher.md +4 -0
  6. package/dist/agents/core/retrospective.md +64 -0
  7. package/dist/agents/core/specifier.md +4 -0
  8. package/dist/catalog/build-catalog.d.ts +21 -0
  9. package/dist/catalog/build-catalog.js +305 -0
  10. package/dist/catalog/build-catalog.js.map +1 -0
  11. package/dist/catalog/classify.d.ts +16 -0
  12. package/dist/catalog/classify.js +189 -0
  13. package/dist/catalog/classify.js.map +1 -0
  14. package/dist/catalog/extract-metadata.d.ts +41 -0
  15. package/dist/catalog/extract-metadata.js +175 -0
  16. package/dist/catalog/extract-metadata.js.map +1 -0
  17. package/dist/catalog/pack-sprites.d.ts +8 -0
  18. package/dist/catalog/pack-sprites.js +106 -0
  19. package/dist/catalog/pack-sprites.js.map +1 -0
  20. package/dist/catalog/parse-conventions.d.ts +25 -0
  21. package/dist/catalog/parse-conventions.js +86 -0
  22. package/dist/catalog/parse-conventions.js.map +1 -0
  23. package/dist/catalog/resolve-asset-dir.d.ts +15 -0
  24. package/dist/catalog/resolve-asset-dir.js +96 -0
  25. package/dist/catalog/resolve-asset-dir.js.map +1 -0
  26. package/dist/catalog/types.d.ts +74 -0
  27. package/dist/catalog/types.js +3 -0
  28. package/dist/catalog/types.js.map +1 -0
  29. package/dist/catalog/vision-describe.d.ts +12 -0
  30. package/dist/catalog/vision-describe.js +158 -0
  31. package/dist/catalog/vision-describe.js.map +1 -0
  32. package/dist/cli.js +54 -1
  33. package/dist/cli.js.map +1 -1
  34. package/dist/commands/build.d.ts +2 -2
  35. package/dist/commands/build.js +156 -30
  36. package/dist/commands/build.js.map +1 -1
  37. package/dist/commands/catalog.d.ts +6 -0
  38. package/dist/commands/catalog.js +141 -0
  39. package/dist/commands/catalog.js.map +1 -0
  40. package/dist/commands/design.js +73 -0
  41. package/dist/commands/design.js.map +1 -1
  42. package/dist/commands/retrospective.d.ts +7 -0
  43. package/dist/commands/retrospective.js +119 -0
  44. package/dist/commands/retrospective.js.map +1 -0
  45. package/dist/config.js +1 -0
  46. package/dist/config.js.map +1 -1
  47. package/dist/engine/discovery/agent.registry.d.ts +3 -0
  48. package/dist/engine/discovery/agent.registry.js +15 -2
  49. package/dist/engine/discovery/agent.registry.js.map +1 -1
  50. package/dist/engine/pipeline/build.exec.d.ts +1 -1
  51. package/dist/engine/pipeline/build.exec.js +24 -27
  52. package/dist/engine/pipeline/build.exec.js.map +1 -1
  53. package/dist/engine/pipeline/ensemble.exec.d.ts +16 -0
  54. package/dist/engine/pipeline/ensemble.exec.js +128 -31
  55. package/dist/engine/pipeline/ensemble.exec.js.map +1 -1
  56. package/dist/engine/pipeline/phase.graph.d.ts +31 -0
  57. package/dist/engine/pipeline/phase.graph.js +102 -0
  58. package/dist/engine/pipeline/phase.graph.js.map +1 -0
  59. package/dist/engine/pipeline/phase.sequence.d.ts +3 -1
  60. package/dist/engine/pipeline/phase.sequence.js +50 -21
  61. package/dist/engine/pipeline/phase.sequence.js.map +1 -1
  62. package/dist/engine/pipeline/pipeline.shared.d.ts +12 -5
  63. package/dist/engine/pipeline/pipeline.shared.js +50 -26
  64. package/dist/engine/pipeline/pipeline.shared.js.map +1 -1
  65. package/dist/engine/pipeline/plan.exec.d.ts +4 -1
  66. package/dist/engine/pipeline/plan.exec.js +15 -12
  67. package/dist/engine/pipeline/plan.exec.js.map +1 -1
  68. package/dist/engine/pipeline/prompt.document.d.ts +28 -0
  69. package/dist/engine/pipeline/prompt.document.js +50 -0
  70. package/dist/engine/pipeline/prompt.document.js.map +1 -0
  71. package/dist/engine/pipeline/refine.exec.js +16 -14
  72. package/dist/engine/pipeline/refine.exec.js.map +1 -1
  73. package/dist/engine/pipeline/research.exec.d.ts +0 -2
  74. package/dist/engine/pipeline/research.exec.js +32 -58
  75. package/dist/engine/pipeline/research.exec.js.map +1 -1
  76. package/dist/engine/pipeline/review.exec.d.ts +1 -1
  77. package/dist/engine/pipeline/review.exec.js +23 -31
  78. package/dist/engine/pipeline/review.exec.js.map +1 -1
  79. package/dist/engine/pipeline/specify.exec.js +16 -24
  80. package/dist/engine/pipeline/specify.exec.js.map +1 -1
  81. package/dist/engine/pipeline/worktree.parallel.d.ts +22 -0
  82. package/dist/engine/pipeline/worktree.parallel.js +122 -0
  83. package/dist/engine/pipeline/worktree.parallel.js.map +1 -0
  84. package/dist/flavours/web-game/core/builder.md +5 -2
  85. package/dist/flavours/web-game/core/designer.md +157 -0
  86. package/dist/git.js +11 -4
  87. package/dist/git.js.map +1 -1
  88. package/dist/stores/budget.js +21 -17
  89. package/dist/stores/budget.js.map +1 -1
  90. package/dist/stores/handoff.d.ts +4 -0
  91. package/dist/stores/handoff.js +28 -1
  92. package/dist/stores/handoff.js.map +1 -1
  93. package/dist/stores/phases.d.ts +8 -0
  94. package/dist/stores/phases.js +23 -2
  95. package/dist/stores/phases.js.map +1 -1
  96. package/dist/stores/settings.d.ts +1 -0
  97. package/dist/stores/settings.js.map +1 -1
  98. package/dist/stores/state.d.ts +6 -1
  99. package/dist/stores/state.js +101 -19
  100. package/dist/stores/state.js.map +1 -1
  101. package/dist/types.d.ts +3 -0
  102. package/dist/ui/logger.d.ts +11 -0
  103. package/dist/ui/logger.js +71 -0
  104. package/dist/ui/logger.js.map +1 -0
  105. package/dist/ui/output.d.ts +1 -0
  106. package/dist/ui/output.js +11 -1
  107. package/dist/ui/output.js.map +1 -1
  108. package/dist/utils/file-lock.d.ts +5 -0
  109. package/dist/utils/file-lock.js +95 -0
  110. package/dist/utils/file-lock.js.map +1 -0
  111. package/package.json +6 -3
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.classifyWithAI = exports.classifyByHeuristics = void 0;
37
+ const fs = __importStar(require("node:fs"));
38
+ const path = __importStar(require("node:path"));
39
+ const node_child_process_1 = require("node:child_process");
40
+ // --- Heuristic patterns (filename prefix → category) ---
41
+ const IMAGE_HEURISTICS = [
42
+ [/^(bg|background|backdrop|sky|scenery)[_-]/i, "backgrounds"],
43
+ [/^(btn|button|icon|hud|bar|frame|panel|menu)[_-]/i, "ui"],
44
+ [/^(tile|floor|wall|ground|terrain|grass|stone|brick)[_-]/i, "tiles"],
45
+ [/^(char|character|player|enemy|npc|hero|sprite)[_-]/i, "characters"],
46
+ [/^(item|pickup|loot|potion|coin|gem|key|weapon|sword|shield)[_-]/i, "items"],
47
+ [/^(fx|effect|particle|explosion|spark|flash|smoke)[_-]/i, "effects"],
48
+ [/^(layout|mockup|wireframe|screen)[_-]/i, "layouts"],
49
+ ];
50
+ const AUDIO_HEURISTICS = [
51
+ [/^(bgm|music|soundtrack|theme|ost|track|song)[_-]/i, "music"],
52
+ [/^(sfx|click|hit|boom|slash|jump|land|step|beep|ding|whoosh|pop|crash)[_-]/i, "sfx"],
53
+ [/^(ambient|ambience|wind|rain|water|forest|cave|city|night|crowd)[_-]/i, "ambience"],
54
+ [/^(voice|dialogue|narrat|speech|line)[_-]/i, "dialogue"],
55
+ ];
56
+ const VIDEO_HEURISTICS = [
57
+ [/^(cutscene|cinematic|intro|outro|ending|opening)[_-]/i, "cinematics"],
58
+ ];
59
+ const TEXT_HEURISTICS = [
60
+ [/^(dialogue|conversation|script|line|speech)[_-]/i, "dialogue"],
61
+ [/^(doc|readme|guide|manual|help|note)[_-]/i, "docs"],
62
+ ];
63
+ /** Categories valid for each media type. */
64
+ const CATEGORIES_BY_MEDIA = {
65
+ image: ["characters", "tiles", "items", "ui", "backgrounds", "effects", "layouts"],
66
+ audio: ["music", "sfx", "ambience", "dialogue"],
67
+ video: ["cinematics"],
68
+ text: ["dialogue", "data", "docs"],
69
+ };
70
+ const HEURISTICS_BY_MEDIA = {
71
+ image: IMAGE_HEURISTICS,
72
+ audio: AUDIO_HEURISTICS,
73
+ video: VIDEO_HEURISTICS,
74
+ text: TEXT_HEURISTICS,
75
+ };
76
+ /**
77
+ * Attempt to classify a file using filename pattern matching.
78
+ * Returns null if no heuristic matches confidently.
79
+ */
80
+ const classifyByHeuristics = (filename, ext, mediaType) => {
81
+ const basename = path.basename(filename, ext);
82
+ // Text data files by extension
83
+ if (mediaType === "text" && [".json", ".csv", ".yaml", ".yml"].includes(ext)) {
84
+ return { category: "data", confidence: "medium" };
85
+ }
86
+ const patterns = HEURISTICS_BY_MEDIA[mediaType];
87
+ for (const [pattern, category] of patterns) {
88
+ if (pattern.test(basename)) {
89
+ return { category, confidence: "high" };
90
+ }
91
+ }
92
+ return null;
93
+ };
94
+ exports.classifyByHeuristics = classifyByHeuristics;
95
+ // --- AI classification prompts ---
96
+ const IMAGE_CLASSIFY_PROMPT = `You are classifying game assets into organized categories. Analyze this image and determine the best category.
97
+
98
+ File: {filename}
99
+
100
+ Available categories:
101
+ - characters: Player characters, NPCs, enemies, character sprites, portraits
102
+ - tiles: Ground tiles, wall tiles, terrain, tileable textures
103
+ - items: Inventory items, pickups, powerups, weapons, equipment
104
+ - ui: HUD elements, buttons, frames, health bars, menu components
105
+ - backgrounds: Scenery, parallax layers, sky, environment backdrops
106
+ - effects: Particles, explosions, magic effects, weather, visual FX
107
+ - layouts: UI mockups, screen layouts, wireframes
108
+ - uncategorized: Does not clearly fit any category above
109
+
110
+ Respond with ONLY valid JSON:
111
+ {
112
+ "category": "one of the categories above",
113
+ "confidence": "high" | "medium" | "low"
114
+ }`;
115
+ const buildNonImagePrompt = (filename, ext, mediaType, fileSizeBytes, contentPreview) => {
116
+ const categories = CATEGORIES_BY_MEDIA[mediaType];
117
+ const categoryList = categories
118
+ .map((c) => `- ${c}`)
119
+ .join("\n");
120
+ const preview = contentPreview
121
+ ? `\nContent preview (first 500 chars):\n\`\`\`\n${contentPreview}\n\`\`\``
122
+ : "";
123
+ return `You are classifying game asset files into organized categories based on filename, extension, and file content.
124
+
125
+ File: ${filename}
126
+ Extension: ${ext}
127
+ Media type: ${mediaType}
128
+ File size: ${Math.round(fileSizeBytes / 1024)} KB${preview}
129
+
130
+ Available categories for ${mediaType}:
131
+ ${categoryList}
132
+ - uncategorized: Does not clearly fit any category above
133
+
134
+ Respond with ONLY valid JSON:
135
+ {
136
+ "category": "one of the categories above",
137
+ "confidence": "high" | "medium" | "low"
138
+ }`;
139
+ };
140
+ /** Invoke Claude and parse the classification result. */
141
+ const invokeClaude = (prompt, model, timeoutMs, filename, filePath) => {
142
+ const args = ["-p", "--model", model, "--output-format", "json", prompt];
143
+ if (filePath)
144
+ args.push("--file", filePath);
145
+ try {
146
+ const result = (0, node_child_process_1.execFileSync)("claude", args, {
147
+ timeout: timeoutMs,
148
+ encoding: "utf-8",
149
+ stdio: ["pipe", "pipe", "pipe"],
150
+ });
151
+ const parsed = JSON.parse(result);
152
+ const text = parsed.result ?? parsed;
153
+ const data = typeof text === "string" ? JSON.parse(text) : text;
154
+ return {
155
+ category: data.category ?? "uncategorized",
156
+ confidence: data.confidence ?? "low",
157
+ };
158
+ }
159
+ catch (err) {
160
+ const msg = err instanceof Error ? err.message : String(err);
161
+ process.stderr.write(`\x1b[33mClassification failed for ${filename}: ${msg}\x1b[0m\n`);
162
+ return { category: "uncategorized", confidence: "low" };
163
+ }
164
+ };
165
+ /**
166
+ * Classify a single file using AI.
167
+ * Dispatches to vision (images) or text-only (audio/video/text).
168
+ */
169
+ const classifyWithAI = (absPath, filename, ext, mediaType, model, timeoutMs) => {
170
+ if (mediaType === "image") {
171
+ const prompt = IMAGE_CLASSIFY_PROMPT.replace("{filename}", filename);
172
+ return invokeClaude(prompt, model, timeoutMs, filename, absPath);
173
+ }
174
+ const stat = fs.statSync(absPath);
175
+ let contentPreview = null;
176
+ if (mediaType === "text") {
177
+ try {
178
+ const content = fs.readFileSync(absPath, "utf-8");
179
+ contentPreview = content.slice(0, 500);
180
+ }
181
+ catch {
182
+ // Binary or unreadable — skip preview
183
+ }
184
+ }
185
+ const prompt = buildNonImagePrompt(filename, ext, mediaType, stat.size, contentPreview);
186
+ return invokeClaude(prompt, model, timeoutMs, filename);
187
+ };
188
+ exports.classifyWithAI = classifyWithAI;
189
+ //# sourceMappingURL=classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/catalog/classify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ type ImageMetadata = {
2
+ width: number;
3
+ height: number;
4
+ format: string;
5
+ hasAlpha: boolean;
6
+ channels: number;
7
+ };
8
+ type PaletteResult = {
9
+ dominantColour: string;
10
+ palette: string[];
11
+ };
12
+ type SpritesheetInfo = {
13
+ isSpritesheet: boolean;
14
+ frameCount: number;
15
+ frameSize: {
16
+ w: number;
17
+ h: number;
18
+ } | null;
19
+ frameDirection: "horizontal" | "vertical" | null;
20
+ };
21
+ /** Extract image dimensions, format, alpha, and channel info via sharp. */
22
+ export declare const extractImageMetadata: (filepath: string) => Promise<ImageMetadata>;
23
+ /** Extract dominant colour and 6-colour palette via colorthief. */
24
+ export declare const extractPalette: (filepath: string) => Promise<PaletteResult>;
25
+ /** Detect spritesheet from dimensions — one dimension is an exact multiple of the other. */
26
+ export declare const detectSpritesheet: (width: number, height: number) => SpritesheetInfo;
27
+ /**
28
+ * Detect tilability by comparing edge pixel strips.
29
+ * If the top row matches the bottom row (and left col matches right col),
30
+ * the image is likely tileable.
31
+ */
32
+ export declare const detectTileable: (filepath: string, width: number, height: number) => Promise<boolean>;
33
+ /** Compute MD5 content hash for change detection (not security-sensitive). */
34
+ export declare const computeContentHash: (filepath: string) => string;
35
+ type BasicMetadata = {
36
+ fileSizeBytes: number;
37
+ extension: string;
38
+ };
39
+ /** Extract basic file metadata for non-image assets. */
40
+ export declare const extractBasicMetadata: (filepath: string) => BasicMetadata;
41
+ export {};
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.extractBasicMetadata = exports.computeContentHash = exports.detectTileable = exports.detectSpritesheet = exports.extractPalette = exports.extractImageMetadata = void 0;
37
+ const crypto = __importStar(require("node:crypto"));
38
+ const fs = __importStar(require("node:fs"));
39
+ const path = __importStar(require("node:path"));
40
+ // Dynamic imports for native deps — only loaded when catalog command runs
41
+ let sharpModule = null;
42
+ let colorThiefModule = null;
43
+ const loadSharp = async () => {
44
+ if (!sharpModule)
45
+ sharpModule = (await Promise.resolve().then(() => __importStar(require("sharp")))).default;
46
+ return sharpModule;
47
+ };
48
+ const loadColorThief = async () => {
49
+ if (!colorThiefModule)
50
+ colorThiefModule = (await Promise.resolve().then(() => __importStar(require("colorthief")))).default;
51
+ return colorThiefModule;
52
+ };
53
+ /** Extract image dimensions, format, alpha, and channel info via sharp. */
54
+ const extractImageMetadata = async (filepath) => {
55
+ const sharp = await loadSharp();
56
+ const meta = await sharp(filepath).metadata();
57
+ return {
58
+ width: meta.width ?? 0,
59
+ height: meta.height ?? 0,
60
+ format: meta.format ?? "unknown",
61
+ hasAlpha: meta.hasAlpha ?? false,
62
+ channels: meta.channels ?? 3,
63
+ };
64
+ };
65
+ exports.extractImageMetadata = extractImageMetadata;
66
+ /** Extract dominant colour and 6-colour palette via colorthief. */
67
+ const extractPalette = async (filepath) => {
68
+ const ColorThief = await loadColorThief();
69
+ try {
70
+ const dominant = await ColorThief.getColor(filepath);
71
+ const palette = await ColorThief.getPalette(filepath, 6);
72
+ return {
73
+ dominantColour: rgbToHex(dominant),
74
+ palette: palette.map(rgbToHex),
75
+ };
76
+ }
77
+ catch {
78
+ // colorthief can fail on very small or single-colour images
79
+ return { dominantColour: "#000000", palette: [] };
80
+ }
81
+ };
82
+ exports.extractPalette = extractPalette;
83
+ /** Detect spritesheet from dimensions — one dimension is an exact multiple of the other. */
84
+ const detectSpritesheet = (width, height) => {
85
+ if (width <= 0 || height <= 0 || width === height) {
86
+ return { isSpritesheet: false, frameCount: 1, frameSize: null, frameDirection: null };
87
+ }
88
+ const isWideStrip = width > height && width % height === 0;
89
+ const isTallStrip = height > width && height % width === 0;
90
+ if (isWideStrip) {
91
+ return {
92
+ isSpritesheet: true,
93
+ frameCount: width / height,
94
+ frameSize: { w: height, h: height },
95
+ frameDirection: "horizontal",
96
+ };
97
+ }
98
+ if (isTallStrip) {
99
+ return {
100
+ isSpritesheet: true,
101
+ frameCount: height / width,
102
+ frameSize: { w: width, h: width },
103
+ frameDirection: "vertical",
104
+ };
105
+ }
106
+ return { isSpritesheet: false, frameCount: 1, frameSize: null, frameDirection: null };
107
+ };
108
+ exports.detectSpritesheet = detectSpritesheet;
109
+ /**
110
+ * Detect tilability by comparing edge pixel strips.
111
+ * If the top row matches the bottom row (and left col matches right col),
112
+ * the image is likely tileable.
113
+ */
114
+ const detectTileable = async (filepath, width, height) => {
115
+ if (width < 2 || height < 2)
116
+ return false;
117
+ const sharp = await loadSharp();
118
+ try {
119
+ // Extract top and bottom edge strips (1px high)
120
+ const topPixels = await sharp(filepath)
121
+ .extract({ left: 0, top: 0, width, height: 1 })
122
+ .raw()
123
+ .toBuffer();
124
+ const bottomPixels = await sharp(filepath)
125
+ .extract({ left: 0, top: height - 1, width, height: 1 })
126
+ .raw()
127
+ .toBuffer();
128
+ // Extract left and right edge strips (1px wide)
129
+ const leftPixels = await sharp(filepath)
130
+ .extract({ left: 0, top: 0, width: 1, height })
131
+ .raw()
132
+ .toBuffer();
133
+ const rightPixels = await sharp(filepath)
134
+ .extract({ left: width - 1, top: 0, width: 1, height })
135
+ .raw()
136
+ .toBuffer();
137
+ const hSimilarity = bufferSimilarity(topPixels, bottomPixels);
138
+ const vSimilarity = bufferSimilarity(leftPixels, rightPixels);
139
+ // Threshold: edges must be >85% similar
140
+ return hSimilarity > 0.85 && vSimilarity > 0.85;
141
+ }
142
+ catch {
143
+ return false;
144
+ }
145
+ };
146
+ exports.detectTileable = detectTileable;
147
+ /** Compute MD5 content hash for change detection (not security-sensitive). */
148
+ const computeContentHash = (filepath) => {
149
+ const data = fs.readFileSync(filepath);
150
+ return crypto.createHash("md5").update(data).digest("hex");
151
+ };
152
+ exports.computeContentHash = computeContentHash;
153
+ /** Extract basic file metadata for non-image assets. */
154
+ const extractBasicMetadata = (filepath) => {
155
+ const stat = fs.statSync(filepath);
156
+ return {
157
+ fileSizeBytes: stat.size,
158
+ extension: path.extname(filepath).toLowerCase(),
159
+ };
160
+ };
161
+ exports.extractBasicMetadata = extractBasicMetadata;
162
+ // --- Helpers ---
163
+ const rgbToHex = (rgb) => "#" + rgb.map((c) => c.toString(16).padStart(2, "0")).join("");
164
+ /** Compare two raw pixel buffers and return similarity ratio (0..1). */
165
+ const bufferSimilarity = (a, b) => {
166
+ if (a.length !== b.length || a.length === 0)
167
+ return 0;
168
+ let matching = 0;
169
+ for (let i = 0; i < a.length; i++) {
170
+ if (Math.abs(a[i] - b[i]) <= 16)
171
+ matching++; // tolerance of 16/255
172
+ }
173
+ return matching / a.length;
174
+ };
175
+ //# sourceMappingURL=extract-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-metadata.js","sourceRoot":"","sources":["../../src/catalog/extract-metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { AssetCatalog } from "./types";
2
+ /**
3
+ * Pack sprites into texture atlases grouped by category.
4
+ * Uses free-tex-packer-core to produce PixiJS-compatible JSON + PNG atlas files.
5
+ *
6
+ * Output: <assetDir>/packed/<category>.png + <category>.json
7
+ */
8
+ export declare const packAtlases: (assetDir: string, catalog: AssetCatalog) => Promise<void>;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.packAtlases = void 0;
37
+ const fs = __importStar(require("node:fs"));
38
+ const path = __importStar(require("node:path"));
39
+ /**
40
+ * Pack sprites into texture atlases grouped by category.
41
+ * Uses free-tex-packer-core to produce PixiJS-compatible JSON + PNG atlas files.
42
+ *
43
+ * Output: <assetDir>/packed/<category>.png + <category>.json
44
+ */
45
+ const packAtlases = async (assetDir, catalog) => {
46
+ // Dynamic import — only loaded when --pack is used
47
+ const { packAsync } = await Promise.resolve().then(() => __importStar(require("free-tex-packer-core")));
48
+ const outputDir = path.join(assetDir, "packed");
49
+ if (!fs.existsSync(outputDir)) {
50
+ fs.mkdirSync(outputDir, { recursive: true });
51
+ }
52
+ // Group assets by category (skip layouts — they're reference-only)
53
+ const byCategory = new Map();
54
+ for (const asset of catalog.assets) {
55
+ if (asset.isReferenceOnly || asset.category === "layouts")
56
+ continue;
57
+ // Skip backgrounds — typically too large for atlases
58
+ if (asset.category === "backgrounds")
59
+ continue;
60
+ const list = byCategory.get(asset.category) ?? [];
61
+ list.push(asset.file);
62
+ byCategory.set(asset.category, list);
63
+ }
64
+ for (const [category, files] of byCategory) {
65
+ if (files.length === 0)
66
+ continue;
67
+ const images = files
68
+ .map((f) => {
69
+ const absPath = path.join(assetDir, f);
70
+ if (!fs.existsSync(absPath))
71
+ return null;
72
+ return {
73
+ path: path.basename(f, path.extname(f)),
74
+ contents: fs.readFileSync(absPath),
75
+ };
76
+ })
77
+ .filter(Boolean);
78
+ if (images.length === 0)
79
+ continue;
80
+ try {
81
+ const result = await packAsync(images, {
82
+ textureName: category,
83
+ width: 2048,
84
+ height: 2048,
85
+ fixedSize: false,
86
+ padding: 1,
87
+ allowRotation: false,
88
+ detectIdentical: true,
89
+ allowTrim: true,
90
+ exporter: "Pixi",
91
+ removeFileExtension: true,
92
+ });
93
+ for (const file of result) {
94
+ const outPath = path.join(outputDir, file.name);
95
+ fs.writeFileSync(outPath, file.buffer);
96
+ }
97
+ process.stderr.write(`\x1b[90m Packed ${category}: ${images.length} sprites\x1b[0m\n`);
98
+ }
99
+ catch (err) {
100
+ const msg = err instanceof Error ? err.message : String(err);
101
+ process.stderr.write(`\x1b[33mFailed to pack ${category}: ${msg}\x1b[0m\n`);
102
+ }
103
+ }
104
+ };
105
+ exports.packAtlases = packAtlases;
106
+ //# sourceMappingURL=pack-sprites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack-sprites.js","sourceRoot":"","sources":["../../src/catalog/pack-sprites.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ type ConventionResult = {
2
+ category: string;
3
+ name: string;
4
+ subject: string;
5
+ state: string | null;
6
+ };
7
+ /**
8
+ * Parse category, subject, and state from the filesystem path.
9
+ *
10
+ * "characters/knight-walk.png" →
11
+ * { category: "characters", name: "knight-walk", subject: "knight", state: "walk" }
12
+ *
13
+ * "export_003.png" (no subdirectory) →
14
+ * { category: "uncategorized", name: "export_003", subject: "export_003", state: null }
15
+ */
16
+ export declare const parseConventions: (relativePath: string) => ConventionResult;
17
+ type CategoryDefaults = {
18
+ zLayer: string;
19
+ anchor: string;
20
+ };
21
+ /** Infer default z-layer and anchor from category name. */
22
+ export declare const inferDefaults: (category: string) => CategoryDefaults;
23
+ /** Categories that always get vision descriptions regardless of --describe flag. */
24
+ export declare const AUTO_DESCRIBE_CATEGORIES: Set<string>;
25
+ export {};
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AUTO_DESCRIBE_CATEGORIES = exports.inferDefaults = exports.parseConventions = void 0;
37
+ const path = __importStar(require("node:path"));
38
+ /**
39
+ * Parse category, subject, and state from the filesystem path.
40
+ *
41
+ * "characters/knight-walk.png" →
42
+ * { category: "characters", name: "knight-walk", subject: "knight", state: "walk" }
43
+ *
44
+ * "export_003.png" (no subdirectory) →
45
+ * { category: "uncategorized", name: "export_003", subject: "export_003", state: null }
46
+ */
47
+ const parseConventions = (relativePath) => {
48
+ const parts = relativePath.split(path.sep);
49
+ const category = parts.length > 1 ? parts[parts.length - 2] : "uncategorized";
50
+ const filename = path.basename(relativePath, path.extname(relativePath));
51
+ const segments = filename.split("-");
52
+ return {
53
+ category,
54
+ name: filename,
55
+ subject: segments[0] || filename,
56
+ state: segments.length > 1 ? segments.slice(1).join("-") : null,
57
+ };
58
+ };
59
+ exports.parseConventions = parseConventions;
60
+ const CATEGORY_DEFAULTS = {
61
+ // Image categories
62
+ characters: { zLayer: "entity", anchor: "bottom-center" },
63
+ tiles: { zLayer: "ground", anchor: "top-left" },
64
+ items: { zLayer: "entity", anchor: "center" },
65
+ ui: { zLayer: "ui", anchor: "center" },
66
+ backgrounds: { zLayer: "background", anchor: "top-left" },
67
+ effects: { zLayer: "foreground", anchor: "center" },
68
+ layouts: { zLayer: "ui", anchor: "top-left" },
69
+ // Audio categories
70
+ music: { zLayer: "background", anchor: "center" },
71
+ sfx: { zLayer: "entity", anchor: "center" },
72
+ ambience: { zLayer: "background", anchor: "center" },
73
+ dialogue: { zLayer: "entity", anchor: "center" },
74
+ // Video categories
75
+ cinematics: { zLayer: "foreground", anchor: "center" },
76
+ // Text/data categories
77
+ data: { zLayer: "entity", anchor: "center" },
78
+ docs: { zLayer: "entity", anchor: "center" },
79
+ };
80
+ const DEFAULT_FALLBACK = { zLayer: "entity", anchor: "center" };
81
+ /** Infer default z-layer and anchor from category name. */
82
+ const inferDefaults = (category) => CATEGORY_DEFAULTS[category] ?? DEFAULT_FALLBACK;
83
+ exports.inferDefaults = inferDefaults;
84
+ /** Categories that always get vision descriptions regardless of --describe flag. */
85
+ exports.AUTO_DESCRIBE_CATEGORIES = new Set(["layouts", "ui"]);
86
+ //# sourceMappingURL=parse-conventions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-conventions.js","sourceRoot":"","sources":["../../src/catalog/parse-conventions.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAiC;AASjC;;;;;;;;GAQG;AACI,MAAM,gBAAgB,GAAG,CAAC,YAAoB,EAAoB,EAAE;IACzE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,eAAe,CAAA;IAC7E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA;IACxE,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAEpC,OAAO;QACL,QAAQ;QACR,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ;QAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;KAChE,CAAA;AACH,CAAC,CAAA;AAZY,QAAA,gBAAgB,oBAY5B;AAOD,MAAM,iBAAiB,GAAqC;IAC1D,mBAAmB;IACnB,UAAU,EAAG,EAAE,MAAM,EAAE,QAAQ,EAAM,MAAM,EAAE,eAAe,EAAE;IAC9D,KAAK,EAAQ,EAAE,MAAM,EAAE,QAAQ,EAAM,MAAM,EAAE,UAAU,EAAE;IACzD,KAAK,EAAQ,EAAE,MAAM,EAAE,QAAQ,EAAM,MAAM,EAAE,QAAQ,EAAE;IACvD,EAAE,EAAW,EAAE,MAAM,EAAE,IAAI,EAAU,MAAM,EAAE,QAAQ,EAAE;IACvD,WAAW,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE;IACzD,OAAO,EAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE;IACvD,OAAO,EAAM,EAAE,MAAM,EAAE,IAAI,EAAU,MAAM,EAAE,UAAU,EAAE;IACzD,mBAAmB;IACnB,KAAK,EAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE;IACvD,GAAG,EAAU,EAAE,MAAM,EAAE,QAAQ,EAAM,MAAM,EAAE,QAAQ,EAAE;IACvD,QAAQ,EAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE;IACvD,QAAQ,EAAK,EAAE,MAAM,EAAE,QAAQ,EAAM,MAAM,EAAE,QAAQ,EAAE;IACvD,mBAAmB;IACnB,UAAU,EAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE;IACvD,uBAAuB;IACvB,IAAI,EAAS,EAAE,MAAM,EAAE,QAAQ,EAAM,MAAM,EAAE,QAAQ,EAAE;IACvD,IAAI,EAAS,EAAE,MAAM,EAAE,QAAQ,EAAM,MAAM,EAAE,QAAQ,EAAE;CACxD,CAAA;AAED,MAAM,gBAAgB,GAAqB,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA;AAEjF,2DAA2D;AACpD,MAAM,aAAa,GAAG,CAAC,QAAgB,EAAoB,EAAE,CAClE,iBAAiB,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAA;AADpC,QAAA,aAAa,iBACuB;AAEjD,oFAAoF;AACvE,QAAA,wBAAwB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAA"}