@playcraft/cli 0.0.39 → 0.0.41

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 (121) hide show
  1. package/README.md +66 -3
  2. package/dist/atom-plan/validate-atom-plan.js +298 -0
  3. package/dist/cli-root-help.js +1 -1
  4. package/dist/commands/3d.js +363 -0
  5. package/dist/commands/create.js +337 -0
  6. package/dist/commands/fix-ids.js +17 -3
  7. package/dist/commands/fix-ids.test.js +264 -0
  8. package/dist/commands/image.js +1337 -43
  9. package/dist/commands/login.js +60 -2
  10. package/dist/commands/recommend.js +1 -1
  11. package/dist/commands/remix.js +213 -0
  12. package/dist/commands/skills.js +1379 -0
  13. package/dist/commands/tools-3d.js +473 -0
  14. package/dist/commands/tools-generation.js +454 -0
  15. package/dist/commands/tools-project.js +400 -0
  16. package/dist/commands/tools-research.js +37 -0
  17. package/dist/commands/tools-research.test.js +216 -0
  18. package/dist/commands/tools-utils.js +164 -0
  19. package/dist/commands/tools.js +7 -616
  20. package/dist/config.js +2 -0
  21. package/dist/index.js +20 -2
  22. package/dist/utils/agent-api-client.js +52 -16
  23. package/package.json +9 -3
  24. package/project-template/.claude/agents/designer.md +116 -0
  25. package/project-template/.claude/agents/developer.md +133 -0
  26. package/project-template/.claude/agents/pm.md +164 -0
  27. package/project-template/.claude/agents/refs/README.md +67 -0
  28. package/project-template/.claude/agents/refs/designer-art-style-catalog.md +533 -0
  29. package/project-template/.claude/agents/refs/designer-color-audio-recipes.md +153 -0
  30. package/project-template/.claude/agents/refs/designer-deliverable-spec.md +167 -0
  31. package/project-template/.claude/agents/refs/designer-dimension-axis.md +27 -0
  32. package/project-template/.claude/agents/refs/designer-handoff-v2-checklist.md +68 -0
  33. package/project-template/.claude/agents/refs/designer-master-composite-recipes.md +216 -0
  34. package/project-template/.claude/agents/refs/designer-style-exploration-flow.md +37 -0
  35. package/project-template/.claude/agents/refs/developer-dev-handoff.md +109 -0
  36. package/project-template/.claude/agents/refs/developer-impl-cookbook.md +134 -0
  37. package/project-template/.claude/agents/refs/developer-phase1-flow.md +211 -0
  38. package/project-template/.claude/agents/refs/pm-workflow-detail.md +545 -0
  39. package/project-template/.claude/agents/refs/reviewer-six-dimension-eval.md +286 -0
  40. package/project-template/.claude/agents/refs/ta-3d-flip-recipe.md +85 -0
  41. package/project-template/.claude/agents/refs/ta-atlas-deliverable-standard.md +46 -0
  42. package/project-template/.claude/agents/refs/ta-batch-pipeline-recipes.md +120 -0
  43. package/project-template/.claude/agents/refs/ta-image-generation-detail.md +356 -0
  44. package/project-template/.claude/agents/refs/ta-image-ops-reference.md +495 -0
  45. package/project-template/.claude/agents/refs/ta-pipeline-cookbook.md +699 -0
  46. package/project-template/.claude/agents/refs/ta-tools-reference.md +111 -0
  47. package/project-template/.claude/agents/refs/ta-vfx-preset-catalog.md +365 -0
  48. package/project-template/.claude/agents/reviewer.md +103 -0
  49. package/project-template/.claude/agents/technical-artist.md +111 -0
  50. package/project-template/.claude/hooks/README.md +36 -0
  51. package/project-template/.claude/hooks/validate-atom-plan.mjs +224 -0
  52. package/project-template/.claude/hooks/validate-workflow-stop.mjs +258 -0
  53. package/project-template/.claude/settings.json +32 -0
  54. package/project-template/.claude/settings.local.json +4 -0
  55. package/project-template/.claude/skills/playcraft-ad-psychology/SKILL.md +182 -0
  56. package/project-template/.claude/skills/playcraft-art-style-guide/SKILL.md +123 -0
  57. package/project-template/.claude/skills/playcraft-asset-state-sheet/SKILL.md +141 -0
  58. package/project-template/.claude/skills/playcraft-audio-generation/SKILL.md +280 -0
  59. package/project-template/.claude/skills/playcraft-batch-pipeline/SKILL.md +184 -0
  60. package/project-template/.claude/skills/playcraft-build-optimizer/SKILL.md +306 -0
  61. package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +229 -0
  62. package/project-template/.claude/skills/playcraft-image-generation/reference/build-sprite-sheet.template.mjs +123 -0
  63. package/project-template/.claude/skills/playcraft-image-generation/reference/compare-style.template.mjs +254 -0
  64. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch-sprite.template.mjs +235 -0
  65. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-batch.template.mjs +97 -0
  66. package/project-template/.claude/skills/playcraft-image-generation/reference/gen-edit-variants.template.mjs +118 -0
  67. package/project-template/.claude/skills/playcraft-image-generation/reference/process-batch.template.mjs +137 -0
  68. package/project-template/.claude/skills/playcraft-image-generation/reference/prompt-cookbook.md +397 -0
  69. package/project-template/.claude/skills/playcraft-image-generation/reference/validate-sprite-sheet.template.mjs +296 -0
  70. package/project-template/.claude/skills/playcraft-image-ops/SKILL.md +122 -0
  71. package/project-template/.claude/skills/playcraft-masking/SKILL.md +373 -0
  72. package/project-template/.claude/skills/playcraft-research/SKILL.md +212 -0
  73. package/project-template/.claude/skills/playcraft-sprite-generation/SKILL.md +423 -0
  74. package/project-template/.claude/skills/playcraft-storyboard/SKILL.md +148 -0
  75. package/project-template/.claude/skills/playcraft-style-qa/SKILL.md +270 -0
  76. package/project-template/.claude/skills/playcraft-text-rendering/SKILL.md +236 -0
  77. package/project-template/.claude/skills/playcraft-vfx-animation/SKILL.md +130 -0
  78. package/project-template/.claude/skills/playcraft-workflow/SKILL.md +396 -0
  79. package/project-template/.cursor/hooks.json +17 -0
  80. package/project-template/.cursor/rules/playcraft-orchestrator.mdc +87 -0
  81. package/project-template/.cursor/rules/playcraft-subagent-boundary.mdc +18 -0
  82. package/project-template/CLAUDE.md +240 -0
  83. package/project-template/assets/audio/bgm/.gitkeep +0 -0
  84. package/project-template/assets/audio/sfx/.gitkeep +0 -0
  85. package/project-template/assets/bundles/.gitkeep +0 -0
  86. package/project-template/assets/images/bg/.gitkeep +0 -0
  87. package/project-template/assets/images/reference/.gitkeep +0 -0
  88. package/project-template/assets/images/storyboard/.gitkeep +0 -0
  89. package/project-template/assets/images/tiles/.gitkeep +0 -0
  90. package/project-template/assets/images/ui/.gitkeep +0 -0
  91. package/project-template/assets/images/vfx/.gitkeep +0 -0
  92. package/project-template/assets/models/.gitkeep +0 -0
  93. package/project-template/docs/team/agent-conduct.md +105 -0
  94. package/project-template/docs/team/agent-runtime-matrix.md +62 -0
  95. package/project-template/docs/team/atom-plan-format.md +74 -0
  96. package/project-template/docs/team/collaboration.md +288 -0
  97. package/project-template/docs/team/core-model.md +50 -0
  98. package/project-template/docs/team/platform-capabilities.md +15 -0
  99. package/project-template/docs/team/workflow-changelog.md +51 -0
  100. package/project-template/docs/team/workflow-consistency-checklist.md +128 -0
  101. package/project-template/game/config/.gitkeep +0 -0
  102. package/project-template/game/gameplay/.gitkeep +0 -0
  103. package/project-template/game/scenes/.gitkeep +0 -0
  104. package/project-template/logs/.gitkeep +0 -0
  105. package/project-template/ta-workspace/logs/.gitkeep +0 -0
  106. package/project-template/ta-workspace/scripts/.gitkeep +0 -0
  107. package/project-template/ta-workspace/tmp/.gitkeep +0 -0
  108. package/project-template/templates/atom-plan.template.json +26 -0
  109. package/project-template/templates/atom-plan.template.md +76 -0
  110. package/project-template/templates/design-brief.template.md +195 -0
  111. package/project-template/templates/design-lens-checklist.reference.md +117 -0
  112. package/project-template/templates/design-methodology.md +99 -0
  113. package/project-template/templates/designer-log.template.md +98 -0
  114. package/project-template/templates/developer-log.template.md +140 -0
  115. package/project-template/templates/five-axis-framework.md +186 -0
  116. package/project-template/templates/intent-clarifications.template.md +58 -0
  117. package/project-template/templates/layout-spec.template.md +132 -0
  118. package/project-template/templates/project-state.template.md +219 -0
  119. package/project-template/templates/review-report.template.md +166 -0
  120. package/project-template/templates/style-exploration.template.md +93 -0
  121. package/project-template/templates/ta-log.template.md +205 -0
@@ -0,0 +1,164 @@
1
+ import { writeFileSync, mkdirSync, readFileSync } from 'fs';
2
+ import { join, parse } from 'path';
3
+ import { tmpdir } from 'os';
4
+ export const TMP_DIR = join(tmpdir(), 'playcraft');
5
+ export const MAX_REFERENCE_IMAGES = 8;
6
+ export function ensureTmpDir() {
7
+ mkdirSync(TMP_DIR, { recursive: true });
8
+ }
9
+ export function tmpPath(prefix) {
10
+ return join(TMP_DIR, `${prefix}-${Date.now()}.json`);
11
+ }
12
+ export function writeResult(prefix, data) {
13
+ ensureTmpDir();
14
+ const path = tmpPath(prefix);
15
+ writeFileSync(path, JSON.stringify(data, null, 2));
16
+ return path;
17
+ }
18
+ export function handleError(err) {
19
+ const msg = err instanceof Error ? err.message : String(err);
20
+ console.error(`Error: ${msg}`);
21
+ process.exit(1);
22
+ }
23
+ /** Fallback extension from API mime when magic-byte sniff fails. */
24
+ export function extensionForImageMime(mimeType) {
25
+ const base = mimeType.toLowerCase().split(';')[0]?.trim() ?? '';
26
+ switch (base) {
27
+ case 'image/png':
28
+ return '.png';
29
+ case 'image/jpeg':
30
+ case 'image/jpg':
31
+ return '.jpg';
32
+ case 'image/webp':
33
+ return '.webp';
34
+ case 'image/gif':
35
+ return '.gif';
36
+ case 'image/bmp':
37
+ return '.bmp';
38
+ default:
39
+ return '.png';
40
+ }
41
+ }
42
+ /**
43
+ * Detect container from decoded bytes (magic). Prefer this over MIME alone.
44
+ */
45
+ export function sniffImageExtension(buf) {
46
+ if (buf.length >= 8 &&
47
+ buf[0] === 0x89 &&
48
+ buf[1] === 0x50 &&
49
+ buf[2] === 0x4e &&
50
+ buf[3] === 0x47) {
51
+ return '.png';
52
+ }
53
+ if (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) {
54
+ return '.jpg';
55
+ }
56
+ if (buf.length >= 6 &&
57
+ buf[0] === 0x47 &&
58
+ buf[1] === 0x49 &&
59
+ buf[2] === 0x46 &&
60
+ buf[3] === 0x38 &&
61
+ (buf[4] === 0x37 || buf[4] === 0x39) &&
62
+ buf[5] === 0x61) {
63
+ return '.gif';
64
+ }
65
+ if (buf.length >= 12 &&
66
+ buf[0] === 0x52 &&
67
+ buf[1] === 0x49 &&
68
+ buf[2] === 0x46 &&
69
+ buf[3] === 0x46 &&
70
+ buf[8] === 0x57 &&
71
+ buf[9] === 0x45 &&
72
+ buf[10] === 0x42 &&
73
+ buf[11] === 0x50) {
74
+ return '.webp';
75
+ }
76
+ if (buf.length >= 2 && buf[0] === 0x42 && buf[1] === 0x4d) {
77
+ return '.bmp';
78
+ }
79
+ return null;
80
+ }
81
+ /** Replace output extension when it does not match the chosen format extension. */
82
+ export function resolveImageOutputPath(outputPath, wantExt) {
83
+ try {
84
+ const { dir, name, ext } = parse(outputPath);
85
+ if (ext.toLowerCase() === wantExt) {
86
+ return outputPath;
87
+ }
88
+ return join(dir, `${name}${wantExt}`);
89
+ }
90
+ catch (e) {
91
+ const detail = e instanceof Error ? e.message : String(e);
92
+ console.warn(`Could not adjust output path for extension ${wantExt} (${detail}); using path as given: ${outputPath}`);
93
+ return outputPath;
94
+ }
95
+ }
96
+ export function collectReferenceImagePaths(value, previous) {
97
+ return previous.concat([value]);
98
+ }
99
+ export function mimeTypeForImagePath(filePath) {
100
+ const ext = filePath.split('.').pop()?.toLowerCase();
101
+ if (ext === 'png')
102
+ return 'image/png';
103
+ if (ext === 'webp')
104
+ return 'image/webp';
105
+ if (ext === 'jpg' || ext === 'jpeg')
106
+ return 'image/jpeg';
107
+ if (ext === undefined || ext === '') {
108
+ throw new Error(`Reference image path has no file extension: ${filePath}. Use .png, .webp, .jpg, or .jpeg.`);
109
+ }
110
+ throw new Error(`Unsupported reference image extension ".${ext}" in ${filePath}. Only png, webp, jpg, and jpeg are allowed.`);
111
+ }
112
+ async function downloadImageFromUrl(url) {
113
+ let res;
114
+ try {
115
+ res = await fetch(url, { signal: AbortSignal.timeout(30_000) });
116
+ }
117
+ catch (e) {
118
+ const detail = e instanceof Error ? e.message : String(e);
119
+ throw new Error(`下载参考图失败(网络错误):${url}\n ${detail}`);
120
+ }
121
+ if (!res.ok) {
122
+ throw new Error(`下载参考图失败(HTTP ${res.status}):${url}\n 服务器返回了非 2xx 状态码,请检查 URL 是否有效或可公开访问。`);
123
+ }
124
+ const contentType = res.headers.get('content-type') ?? '';
125
+ const mimeType = contentType.split(';')[0].trim() || 'image/png';
126
+ const allowed = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'];
127
+ if (!allowed.some((t) => mimeType.startsWith(t.split('/')[0]) && mimeType.includes('/')) || !mimeType.startsWith('image/')) {
128
+ throw new Error(`参考图 URL 返回的 Content-Type 不是图片(${mimeType}):${url}\n 只支持 PNG / JPG / WEBP / GIF。`);
129
+ }
130
+ const buf = await res.arrayBuffer();
131
+ if (buf.byteLength === 0) {
132
+ throw new Error(`参考图 URL 返回了空响应体:${url}`);
133
+ }
134
+ return { base64: Buffer.from(buf).toString('base64'), mimeType };
135
+ }
136
+ /** Load reference images for generate-image; skip unreadable entries after console.warn. */
137
+ export async function collectReferenceImagePayloads(paths) {
138
+ if (paths.length === 0)
139
+ return undefined;
140
+ const out = [];
141
+ for (const p of paths) {
142
+ const isUrl = p.startsWith('http://') || p.startsWith('https://');
143
+ try {
144
+ if (isUrl) {
145
+ const payload = await downloadImageFromUrl(p);
146
+ out.push(payload);
147
+ }
148
+ else {
149
+ const mimeType = mimeTypeForImagePath(p);
150
+ out.push({ base64: readFileSync(p).toString('base64'), mimeType });
151
+ }
152
+ }
153
+ catch (e) {
154
+ const detail = e instanceof Error ? e.message : String(e);
155
+ const code = !isUrl && e && typeof e === 'object' && 'code' in e ? String(e.code) : '';
156
+ const hint = code ? ` (${code})` : '';
157
+ console.warn(`Skipping reference image (load failed): ${p}${hint}\n ${detail}`);
158
+ }
159
+ }
160
+ if (paths.length > 0 && out.length === 0) {
161
+ console.warn('All reference images failed to load; continuing with text-only generation.');
162
+ }
163
+ return out.length > 0 ? out : undefined;
164
+ }