@playcraft/cli 0.0.55 → 0.0.56
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/README.md +21 -0
- package/REMIX.md +103 -19
- package/dist/atom-tree/fusion-hints.js +8 -3
- package/dist/atom-tree/fusion-intent.js +62 -0
- package/dist/atom-tree/selection.js +3 -1
- package/dist/commands/create.js +299 -85
- package/dist/commands/image.js +79 -69
- package/dist/commands/levels.js +29 -0
- package/dist/commands/patterns.js +75 -0
- package/dist/commands/remix.js +47 -0
- package/dist/commands/skills.js +48 -17
- package/dist/index.js +9 -5
- package/dist/remix/clone-source.js +208 -0
- package/dist/remix/clone.js +255 -0
- package/dist/scaffold/templates.js +1 -1
- package/dist/utils/agent-api-client.js +10 -3
- package/dist/utils/remix-image-attachments.js +4 -32
- package/dist/utils/sandbox-path.js +20 -0
- package/package.json +3 -3
- package/project-template/.claude/agents/creative-director.md +114 -0
- package/project-template/.claude/agents/developer.md +5 -2
- package/project-template/.claude/agents/game-designer.md +41 -20
- package/project-template/.claude/agents/refs/README.md +8 -0
- package/project-template/.claude/agents/refs/creative-director-guide.md +35 -0
- package/project-template/.claude/agents/refs/creative-director-kickoff-guide.md +52 -0
- package/project-template/.claude/agents/refs/creative-discovery-guide.md +76 -0
- package/project-template/.claude/agents/refs/creative-north-star-examples.md +82 -0
- package/project-template/.claude/agents/refs/developer-dev-handoff.md +1 -1
- package/project-template/.claude/agents/refs/game-designer-fusion-depth-playbook.md +28 -0
- package/project-template/.claude/agents/refs/game-designer-gameplay-sufficiency.md +4 -4
- package/project-template/.claude/agents/reviewer.md +11 -0
- package/project-template/.claude/hooks/README.md +12 -12
- package/project-template/.claude/hooks/block-developer-preflight.mjs +49 -13
- package/project-template/.claude/hooks/block-ring1-tasklist.mjs +1 -1
- package/project-template/.claude/hooks/user-prompt.mjs +3 -13
- package/project-template/.claude/hooks/validate-workflow-stop.mjs +209 -12
- package/project-template/.claude/settings.json +2 -2
- package/project-template/.claude/skills/playcraft-playable-optimization/SKILL.md +20 -20
- package/project-template/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -1
- package/project-template/.claude/snapshot.mjs +0 -1
- package/project-template/.codebuddy/settings.json +1 -1
- package/project-template/.cursor/rules/playcraft-orchestrator.mdc +1 -1
- package/project-template/CLAUDE.md +9 -9
- package/project-template/docs/project-state.md +1 -1
- package/project-template/docs/team/agent-conduct.md +18 -18
- package/project-template/docs/team/collaboration.md +19 -7
- package/project-template/docs/team/workflow-changelog.md +15 -0
- package/project-template/fusion-patterns/catalog.json +77 -0
- package/project-template/package.json +2 -0
- package/project-template/skills/_shared/scripts/create-playable.mjs +31 -11
- package/project-template/skills/_shared/scripts/dev-start.mjs +3 -3
- package/project-template/skills/_shared/scripts/disclosure-config.mjs +65 -39
- package/project-template/skills/_shared/scripts/harness-smoke.mjs +3 -1
- package/project-template/skills/_shared/scripts/lib/fusion-intent.mjs +88 -0
- package/project-template/skills/_shared/scripts/lib/skill-fidelity.mjs +185 -0
- package/project-template/skills/_shared/scripts/slice-set.mjs +29 -2
- package/project-template/skills/_shared/scripts/state-get.mjs +124 -7
- package/project-template/skills/_shared/scripts/state-store.mjs +25 -2
- package/project-template/skills/_shared/scripts/validate-level-sketch.mjs +444 -0
- package/project-template/skills/_shared/scripts/verify-design-consistency.mjs +728 -0
- package/project-template/skills/playable-record/scripts/lib/dev-server.mjs +46 -11
- package/project-template/skills/playable-record/scripts/record-playable.mjs +2 -1
- package/project-template/skills/playable-record/scripts/verify-contract.mjs +4 -4
- package/project-template/skills/playable-record/scripts/verify-firstwin.mjs +3 -3
- package/project-template/skills/playable-record/scripts/verify-fusion.mjs +37 -2
- package/project-template/skills/playable-record/scripts/verify-slice.mjs +2 -2
- package/project-template/templates/design-brief.template.md +34 -0
- package/project-template/templates/design-methodology.md +1 -2
- package/project-template/templates/design.template.md +65 -0
- package/project-template/templates/developer-log.template.md +12 -1
- package/project-template/templates/five-axis-framework.md +12 -0
- package/project-template/templates/game-designer-creative-process.template.md +99 -0
- package/project-template/templates/level-sketch.template.json +56 -0
- package/project-template/templates/north-star.template.md +43 -0
- package/project-template/templates/project-state.template.md +1 -1
- package/project-template/vite.config.ts +4 -5
- package/project-templates/phaser/.claude/agents/creative-director.md +114 -0
- package/project-templates/phaser/.claude/agents/game-designer.md +41 -20
- package/project-templates/phaser/.claude/agents/refs/creative-director-guide.md +35 -0
- package/project-templates/phaser/.claude/agents/refs/creative-director-kickoff-guide.md +52 -0
- package/project-templates/phaser/.claude/agents/refs/creative-discovery-guide.md +76 -0
- package/project-templates/phaser/.claude/agents/refs/creative-north-star-examples.md +82 -0
- package/project-templates/phaser/.claude/agents/refs/developer-dev-handoff.md +1 -1
- package/project-templates/phaser/.claude/agents/refs/game-designer-fusion-depth-playbook.md +28 -0
- package/project-templates/phaser/.claude/agents/reviewer.md +11 -0
- package/project-templates/phaser/.claude/hooks/block-ring1-tasklist.mjs +2 -2
- package/project-templates/phaser/.claude/hooks/user-prompt.mjs +17 -18
- package/project-templates/phaser/.claude/hooks/validate-workflow-stop.mjs +209 -12
- package/project-templates/phaser/.claude/skills/playcraft-playable-optimization/SKILL.md +20 -20
- package/project-templates/phaser/.cursor/rules/playcraft-orchestrator.mdc +1 -1
- package/project-templates/phaser/CLAUDE.md +88 -54
- package/project-templates/phaser/docs/DESIGN.md +25 -0
- package/project-templates/phaser/docs/project-state.md +1 -1
- package/project-templates/phaser/docs/team/collaboration.md +19 -7
- package/project-templates/phaser/docs/team/workflow-changelog.md +14 -0
- package/project-templates/phaser/fusion-patterns/catalog.json +77 -0
- package/project-templates/phaser/package.json +3 -1
- package/project-templates/phaser/skills/_shared/scripts/dev-start.mjs +3 -3
- package/project-templates/phaser/skills/_shared/scripts/disclosure-config.mjs +65 -39
- package/project-templates/phaser/skills/_shared/scripts/harness-smoke.mjs +3 -1
- package/project-templates/phaser/skills/_shared/scripts/lib/fusion-intent.mjs +88 -0
- package/project-templates/phaser/skills/_shared/scripts/lib/skill-fidelity.mjs +185 -0
- package/project-templates/phaser/skills/_shared/scripts/state-get.mjs +124 -7
- package/project-templates/phaser/skills/_shared/scripts/state-store.mjs +25 -2
- package/project-templates/phaser/skills/_shared/scripts/validate-level-sketch.mjs +444 -0
- package/project-templates/phaser/skills/_shared/scripts/verify-design-consistency.mjs +728 -0
- package/project-templates/phaser/skills/playable-record/scripts/lib/dev-server.mjs +46 -11
- package/project-templates/phaser/skills/playable-record/scripts/record-playable.mjs +2 -1
- package/project-templates/phaser/skills/playable-record/scripts/verify-contract.mjs +4 -4
- package/project-templates/phaser/skills/playable-record/scripts/verify-firstwin.mjs +3 -3
- package/project-templates/phaser/skills/playable-record/scripts/verify-fusion.mjs +37 -2
- package/project-templates/phaser/skills/playable-record/scripts/verify-slice.mjs +2 -2
- package/project-templates/phaser/templates/design-brief.template.md +42 -11
- package/project-templates/phaser/templates/design-methodology.md +1 -2
- package/project-templates/phaser/templates/design.template.md +77 -0
- package/project-templates/phaser/templates/five-axis-framework.md +50 -1
- package/project-templates/phaser/templates/game-designer-creative-process.template.md +99 -0
- package/project-templates/phaser/templates/level-sketch.template.json +56 -0
- package/project-templates/phaser/templates/north-star.template.md +43 -0
- package/project-templates/phaser/templates/project-state.template.md +1 -1
- package/project-templates/phaser/vite.config.ts +4 -5
- package/project-templates/threejs/.claude/agents/creative-director.md +114 -0
- package/project-templates/threejs/.claude/agents/game-designer.md +41 -20
- package/project-templates/threejs/.claude/agents/refs/creative-director-guide.md +35 -0
- package/project-templates/threejs/.claude/agents/refs/creative-director-kickoff-guide.md +52 -0
- package/project-templates/threejs/.claude/agents/refs/creative-discovery-guide.md +76 -0
- package/project-templates/threejs/.claude/agents/refs/creative-north-star-examples.md +82 -0
- package/project-templates/threejs/.claude/agents/refs/developer-dev-handoff.md +1 -1
- package/project-templates/threejs/.claude/agents/refs/game-designer-fusion-depth-playbook.md +28 -0
- package/project-templates/threejs/.claude/agents/reviewer.md +11 -0
- package/project-templates/threejs/.claude/hooks/block-ring1-tasklist.mjs +2 -2
- package/project-templates/threejs/.claude/hooks/user-prompt.mjs +17 -18
- package/project-templates/threejs/.claude/hooks/validate-workflow-stop.mjs +209 -12
- package/project-templates/threejs/.claude/skills/playcraft-playable-optimization/SKILL.md +20 -20
- package/project-templates/threejs/.cursor/rules/playcraft-orchestrator.mdc +1 -1
- package/project-templates/threejs/CLAUDE.md +88 -54
- package/project-templates/threejs/docs/DESIGN.md +25 -0
- package/project-templates/threejs/docs/project-state.md +1 -1
- package/project-templates/threejs/docs/team/collaboration.md +19 -7
- package/project-templates/threejs/docs/team/workflow-changelog.md +14 -0
- package/project-templates/threejs/fusion-patterns/catalog.json +77 -0
- package/project-templates/threejs/package.json +3 -1
- package/project-templates/threejs/skills/_shared/scripts/dev-start.mjs +3 -3
- package/project-templates/threejs/skills/_shared/scripts/disclosure-config.mjs +65 -39
- package/project-templates/threejs/skills/_shared/scripts/harness-smoke.mjs +3 -1
- package/project-templates/threejs/skills/_shared/scripts/lib/fusion-intent.mjs +88 -0
- package/project-templates/threejs/skills/_shared/scripts/lib/skill-fidelity.mjs +185 -0
- package/project-templates/threejs/skills/_shared/scripts/state-get.mjs +124 -7
- package/project-templates/threejs/skills/_shared/scripts/state-store.mjs +25 -2
- package/project-templates/threejs/skills/_shared/scripts/validate-level-sketch.mjs +444 -0
- package/project-templates/threejs/skills/_shared/scripts/verify-design-consistency.mjs +728 -0
- package/project-templates/threejs/skills/playable-record/scripts/lib/dev-server.mjs +46 -11
- package/project-templates/threejs/skills/playable-record/scripts/record-playable.mjs +2 -1
- package/project-templates/threejs/skills/playable-record/scripts/verify-contract.mjs +4 -4
- package/project-templates/threejs/skills/playable-record/scripts/verify-firstwin.mjs +3 -3
- package/project-templates/threejs/skills/playable-record/scripts/verify-fusion.mjs +37 -2
- package/project-templates/threejs/skills/playable-record/scripts/verify-slice.mjs +2 -2
- package/project-templates/threejs/templates/design-brief.template.md +42 -11
- package/project-templates/threejs/templates/design-methodology.md +1 -2
- package/project-templates/threejs/templates/design.template.md +77 -0
- package/project-templates/threejs/templates/five-axis-framework.md +50 -1
- package/project-templates/threejs/templates/game-designer-creative-process.template.md +99 -0
- package/project-templates/threejs/templates/level-sketch.template.json +56 -0
- package/project-templates/threejs/templates/north-star.template.md +43 -0
- package/project-templates/threejs/templates/project-state.template.md +1 -1
- package/project-templates/threejs/vite.config.ts +4 -5
- package/project-template/docs/DESIGN.md +0 -65
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { loadGlobalConfig } from '../config.js';
|
|
5
|
+
import { PlayCraftHttpClient } from '../utils/playcraft-http-client.js';
|
|
6
|
+
import { isRemoteCloneSource, resolveRemixCloneTarget, } from './clone-source.js';
|
|
7
|
+
/** Build the branch-scoped Git Smart HTTP URL (no credentials in URL). */
|
|
8
|
+
export function buildRemixGitProxyUrl(apiBaseUrl, projectId, branch) {
|
|
9
|
+
const base = apiBaseUrl.replace(/\/+$/, '');
|
|
10
|
+
const encodedBranch = encodeURIComponent(branch);
|
|
11
|
+
return `${base}/api/git/projects/${encodeURIComponent(projectId)}/branches/${encodedBranch}.git`;
|
|
12
|
+
}
|
|
13
|
+
export function resolveCloneTargetDir(projectId, branch, dir) {
|
|
14
|
+
if (dir?.trim())
|
|
15
|
+
return path.resolve(dir.trim());
|
|
16
|
+
const safeBranch = branch.replace(/[/\\]+/g, '-').replace(/[^a-zA-Z0-9._-]+/g, '-');
|
|
17
|
+
return path.resolve(process.cwd(), `${projectId}-${safeBranch}`);
|
|
18
|
+
}
|
|
19
|
+
function localServiceUrl(baseUrl, fromPort, toPort) {
|
|
20
|
+
try {
|
|
21
|
+
const url = new URL(baseUrl);
|
|
22
|
+
const isLocal = ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
|
|
23
|
+
if (isLocal && url.port === fromPort)
|
|
24
|
+
url.port = toPort;
|
|
25
|
+
return url.toString().replace(/\/+$/, '');
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return baseUrl.replace(/\/+$/, '');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function createApiClient(options) {
|
|
32
|
+
const configured = new PlayCraftHttpClient(options);
|
|
33
|
+
const apiBaseUrl = localServiceUrl(configured.baseUrl, '3000', '3001');
|
|
34
|
+
if (apiBaseUrl === configured.baseUrl)
|
|
35
|
+
return configured;
|
|
36
|
+
return new PlayCraftHttpClient({
|
|
37
|
+
url: apiBaseUrl,
|
|
38
|
+
token: configured.token,
|
|
39
|
+
requestId: configured.requestId,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Prefer explicit --url; else env/login config (via PlayCraftHttpClient).
|
|
44
|
+
* Only use pasted portal origin when no API base is configured yet.
|
|
45
|
+
*/
|
|
46
|
+
function resolveApiBaseHint(options, portalOrigin) {
|
|
47
|
+
if (options.url?.trim())
|
|
48
|
+
return options.url.trim();
|
|
49
|
+
const globalConfig = loadGlobalConfig();
|
|
50
|
+
const configured = process.env.PLAYCRAFT_API_URL ||
|
|
51
|
+
process.env.PLAYCRAFT_URL ||
|
|
52
|
+
(typeof globalConfig.backendUrl === 'string' && globalConfig.backendUrl) ||
|
|
53
|
+
(typeof globalConfig.url === 'string' && globalConfig.url);
|
|
54
|
+
if (configured)
|
|
55
|
+
return undefined;
|
|
56
|
+
if (portalOrigin?.trim()) {
|
|
57
|
+
return localServiceUrl(portalOrigin.trim(), '3000', '3001');
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
function writePlaycraftMeta(targetDir, meta) {
|
|
62
|
+
writeFileSync(path.join(targetDir, '.playcraft.json'), `${JSON.stringify(meta, null, 2)}\n`, 'utf8');
|
|
63
|
+
}
|
|
64
|
+
function configureRepoCredentialHelper(targetDir) {
|
|
65
|
+
// Prefer invoking the same CLI binary the user used.
|
|
66
|
+
const helper = `!playcraft git-credential`;
|
|
67
|
+
spawnSync('git', ['config', 'credential.helper', helper], {
|
|
68
|
+
cwd: targetDir,
|
|
69
|
+
encoding: 'utf8',
|
|
70
|
+
});
|
|
71
|
+
spawnSync('git', ['config', 'credential.useHttpPath', 'true'], {
|
|
72
|
+
cwd: targetDir,
|
|
73
|
+
encoding: 'utf8',
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async function resolveProjectIdFromGitHost(client, repositoryUrl) {
|
|
77
|
+
try {
|
|
78
|
+
const data = await client.get(`/git/resolve-repo?repositoryUrl=${encodeURIComponent(repositoryUrl)}`);
|
|
79
|
+
const projectId = String(data?.projectId || data?.projectUuid || '').trim();
|
|
80
|
+
if (!projectId) {
|
|
81
|
+
throw new Error('empty_project_id');
|
|
82
|
+
}
|
|
83
|
+
return projectId;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new Error('无法根据工蜂/Git 地址定位 PlayCraft 项目(无权限或不存在)。请改用 Remix 详情页 URL,或 --project-id / --branch。');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export async function remixClone(options) {
|
|
90
|
+
const target = resolveRemixCloneTarget({
|
|
91
|
+
source: options.source,
|
|
92
|
+
projectId: options.projectId,
|
|
93
|
+
branch: options.branch,
|
|
94
|
+
});
|
|
95
|
+
let projectId = target.projectId?.trim() || '';
|
|
96
|
+
const branch = String(target.branch || '').trim();
|
|
97
|
+
if (!branch) {
|
|
98
|
+
throw new Error('缺少 Remix 分支名。');
|
|
99
|
+
}
|
|
100
|
+
if (branch === 'main' || branch === 'master') {
|
|
101
|
+
throw new Error('不允许 clone 主干分支;请指定 Remix 分支(例如 remix/...)。');
|
|
102
|
+
}
|
|
103
|
+
const client = createApiClient({
|
|
104
|
+
url: resolveApiBaseHint(options, target.origin),
|
|
105
|
+
token: options.token,
|
|
106
|
+
});
|
|
107
|
+
if (target.kind === 'git-host') {
|
|
108
|
+
if (!target.repositoryUrl) {
|
|
109
|
+
throw new Error('工蜂/Git 地址无效。');
|
|
110
|
+
}
|
|
111
|
+
projectId = await resolveProjectIdFromGitHost(client, target.repositoryUrl);
|
|
112
|
+
}
|
|
113
|
+
if (!projectId) {
|
|
114
|
+
throw new Error('缺少项目 ID。');
|
|
115
|
+
}
|
|
116
|
+
const cloneUrl = buildRemixGitProxyUrl(client.baseUrl, projectId, branch);
|
|
117
|
+
const targetDir = resolveCloneTargetDir(projectId, branch, options.dir);
|
|
118
|
+
if (existsSync(targetDir) && existsSync(path.join(targetDir, '.git'))) {
|
|
119
|
+
throw new Error(`目标目录已存在 Git 仓库:${targetDir}`);
|
|
120
|
+
}
|
|
121
|
+
mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
122
|
+
if (!options.json) {
|
|
123
|
+
process.stderr.write(`[clone] ${cloneUrl}\n`);
|
|
124
|
+
process.stderr.write(`[clone] → ${targetDir}\n`);
|
|
125
|
+
}
|
|
126
|
+
const result = spawnSync('git', [
|
|
127
|
+
'-c',
|
|
128
|
+
`http.extraHeader=Authorization: Bearer ${client.token}`,
|
|
129
|
+
'clone',
|
|
130
|
+
'--branch',
|
|
131
|
+
branch,
|
|
132
|
+
'--single-branch',
|
|
133
|
+
'--depth',
|
|
134
|
+
'1',
|
|
135
|
+
cloneUrl,
|
|
136
|
+
targetDir,
|
|
137
|
+
], {
|
|
138
|
+
encoding: 'utf8',
|
|
139
|
+
stdio: options.json ? 'pipe' : 'inherit',
|
|
140
|
+
});
|
|
141
|
+
if (result.status !== 0) {
|
|
142
|
+
const detail = [result.stderr, result.stdout].filter(Boolean).join('\n').trim();
|
|
143
|
+
throw new Error(detail || `git clone 失败(exit ${result.status})`);
|
|
144
|
+
}
|
|
145
|
+
const meta = {
|
|
146
|
+
schemaVersion: '1.0',
|
|
147
|
+
projectId,
|
|
148
|
+
branch,
|
|
149
|
+
cloneUrl,
|
|
150
|
+
clonedAt: new Date().toISOString(),
|
|
151
|
+
};
|
|
152
|
+
writePlaycraftMeta(targetDir, meta);
|
|
153
|
+
configureRepoCredentialHelper(targetDir);
|
|
154
|
+
let projectType;
|
|
155
|
+
try {
|
|
156
|
+
const project = await client.get(`/projects/${encodeURIComponent(projectId)}`);
|
|
157
|
+
projectType = project?.projectType;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// optional — next-step hints only
|
|
161
|
+
}
|
|
162
|
+
if (options.install || options.dev) {
|
|
163
|
+
const install = spawnSync('npm', ['install'], {
|
|
164
|
+
cwd: targetDir,
|
|
165
|
+
encoding: 'utf8',
|
|
166
|
+
stdio: options.json ? 'pipe' : 'inherit',
|
|
167
|
+
shell: process.platform === 'win32',
|
|
168
|
+
});
|
|
169
|
+
if (install.status !== 0) {
|
|
170
|
+
throw new Error('npm install 失败');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (options.dev) {
|
|
174
|
+
spawnSync('npm', ['run', 'dev'], {
|
|
175
|
+
cwd: targetDir,
|
|
176
|
+
encoding: 'utf8',
|
|
177
|
+
stdio: 'inherit',
|
|
178
|
+
shell: process.platform === 'win32',
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (options.json) {
|
|
182
|
+
console.log(JSON.stringify({
|
|
183
|
+
schemaVersion: '1.0',
|
|
184
|
+
ok: true,
|
|
185
|
+
command: 'remix.clone',
|
|
186
|
+
requestId: client.requestId,
|
|
187
|
+
data: { ...meta, targetDir, projectType, sourceKind: target.kind },
|
|
188
|
+
}));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
console.log(`✓ Remix 已克隆到 ${targetDir}`);
|
|
192
|
+
console.log(` 分支: ${branch}`);
|
|
193
|
+
console.log(` remote: ${cloneUrl}`);
|
|
194
|
+
console.log('');
|
|
195
|
+
console.log('下一步:');
|
|
196
|
+
console.log(` cd ${targetDir}`);
|
|
197
|
+
if (projectType === 'external') {
|
|
198
|
+
console.log(' npm install && npm run dev');
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
console.log(' playcraft start --project <project-id> # PlayCanvas / 本地 Agent 预览');
|
|
202
|
+
}
|
|
203
|
+
console.log(' git pull / git push # 经 PlayCraft Git 代理(需已 login)');
|
|
204
|
+
}
|
|
205
|
+
export { isRemoteCloneSource, resolveRemixCloneTarget };
|
|
206
|
+
/**
|
|
207
|
+
* Git credential helper (get/store/erase). Only `get` is implemented:
|
|
208
|
+
* returns PAT from ~/.playcraft/config.json for PlayCraft git proxy hosts.
|
|
209
|
+
*/
|
|
210
|
+
export function gitCredentialCommand(action) {
|
|
211
|
+
const op = (action || process.argv[3] || 'get').trim();
|
|
212
|
+
if (op !== 'get') {
|
|
213
|
+
// store/erase: no-op (PAT lives in global config)
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const input = readFileSync(0, 'utf8');
|
|
217
|
+
const attrs = {};
|
|
218
|
+
for (const line of input.split(/\r?\n/)) {
|
|
219
|
+
const eq = line.indexOf('=');
|
|
220
|
+
if (eq <= 0)
|
|
221
|
+
continue;
|
|
222
|
+
attrs[line.slice(0, eq)] = line.slice(eq + 1);
|
|
223
|
+
}
|
|
224
|
+
const host = attrs.host || '';
|
|
225
|
+
const protocol = attrs.protocol || 'https';
|
|
226
|
+
const reqPath = attrs.path || '';
|
|
227
|
+
if (!reqPath.includes('/api/git/projects/')) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const globalConfig = loadGlobalConfig();
|
|
231
|
+
const token = process.env.PLAYCRAFT_TOKEN ||
|
|
232
|
+
(typeof globalConfig.token === 'string' ? globalConfig.token : undefined);
|
|
233
|
+
if (!token || !token.startsWith('playcraft_pat_')) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Optional host check against saved backend URL
|
|
237
|
+
const configured = (typeof globalConfig.backendUrl === 'string' && globalConfig.backendUrl) ||
|
|
238
|
+
(typeof globalConfig.url === 'string' && globalConfig.url) ||
|
|
239
|
+
process.env.PLAYCRAFT_API_URL ||
|
|
240
|
+
process.env.PLAYCRAFT_URL ||
|
|
241
|
+
'';
|
|
242
|
+
if (configured && host) {
|
|
243
|
+
try {
|
|
244
|
+
const configuredHost = new URL(configured).host;
|
|
245
|
+
if (configuredHost && configuredHost !== host) {
|
|
246
|
+
// Still allow if path is clearly our git proxy (e.g. custom CDN host)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
// ignore
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
process.stdout.write(`username=playcraft\npassword=${token}\n\n`);
|
|
254
|
+
void protocol;
|
|
255
|
+
}
|
|
@@ -26,6 +26,7 @@ export class AgentApiClient {
|
|
|
26
26
|
apiUrl;
|
|
27
27
|
token;
|
|
28
28
|
isPat;
|
|
29
|
+
playcraftEnv;
|
|
29
30
|
constructor() {
|
|
30
31
|
const localConfig = AgentApiClient.loadLocalConfig();
|
|
31
32
|
const globalConfig = loadGlobalConfig();
|
|
@@ -47,13 +48,19 @@ export class AgentApiClient {
|
|
|
47
48
|
this.apiUrl = apiUrl;
|
|
48
49
|
this.token = token;
|
|
49
50
|
this.isPat = isPatToken(token);
|
|
51
|
+
this.playcraftEnv = (process.env.PLAYCRAFT_ENV ||
|
|
52
|
+
localConfig.env ||
|
|
53
|
+
'').trim();
|
|
50
54
|
}
|
|
51
55
|
/** 根据 token 类型构造鉴权 headers */
|
|
52
56
|
authHeaders() {
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
const headers = this.isPat
|
|
58
|
+
? { Authorization: `Bearer ${this.token}` }
|
|
59
|
+
: { 'X-Sandbox-Token': this.token };
|
|
60
|
+
if (this.playcraftEnv) {
|
|
61
|
+
headers['playcraft-env'] = this.playcraftEnv;
|
|
55
62
|
}
|
|
56
|
-
return
|
|
63
|
+
return headers;
|
|
57
64
|
}
|
|
58
65
|
/** Absolute pathname under /api/agent/tools (path may omit leading slash). */
|
|
59
66
|
toolsRequestUrl(path) {
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import { readFileSync, statSync } from 'node:fs';
|
|
2
2
|
import { basename, extname } from 'node:path';
|
|
3
3
|
import { PlayCraftApiError } from './playcraft-http-client.js';
|
|
4
|
+
import { appendRemixReferenceImagesPrompt, referenceImageExtensions, referenceImageMimeFromExtension, } from '@playcraft/common/agent/reference-images';
|
|
4
5
|
const MAX_IMAGES = 4;
|
|
5
6
|
const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
6
|
-
const IMAGE_MIME_BY_EXTENSION = {
|
|
7
|
-
'.gif': 'image/gif',
|
|
8
|
-
'.jpeg': 'image/jpeg',
|
|
9
|
-
'.jpg': 'image/jpeg',
|
|
10
|
-
'.png': 'image/png',
|
|
11
|
-
'.webp': 'image/webp',
|
|
12
|
-
};
|
|
13
7
|
function attachmentError(code, message, details, retryable = false) {
|
|
14
8
|
return new PlayCraftApiError({ code, message, details, retryable });
|
|
15
9
|
}
|
|
@@ -22,9 +16,9 @@ export function readImageAttachments(paths) {
|
|
|
22
16
|
}
|
|
23
17
|
return candidates.map((sourcePath) => {
|
|
24
18
|
const extension = extname(sourcePath).toLowerCase();
|
|
25
|
-
const mimeType =
|
|
19
|
+
const mimeType = referenceImageMimeFromExtension(extension);
|
|
26
20
|
if (!mimeType) {
|
|
27
|
-
throw attachmentError('ATTACHMENT_TYPE_UNSUPPORTED', `不支持的图片格式:${sourcePath}。仅支持 JPEG (Joint Photographic Experts Group, 联合图像专家组)、PNG (Portable Network Graphics, 便携式网络图形)、WebP 和 GIF (Graphics Interchange Format, 图形交换格式)。`, { path: sourcePath, supportedExtensions:
|
|
21
|
+
throw attachmentError('ATTACHMENT_TYPE_UNSUPPORTED', `不支持的图片格式:${sourcePath}。仅支持 JPEG (Joint Photographic Experts Group, 联合图像专家组)、PNG (Portable Network Graphics, 便携式网络图形)、WebP 和 GIF (Graphics Interchange Format, 图形交换格式)。`, { path: sourcePath, supportedExtensions: [...referenceImageExtensions()] });
|
|
28
22
|
}
|
|
29
23
|
let size;
|
|
30
24
|
try {
|
|
@@ -98,28 +92,6 @@ export async function uploadImageAttachments(client, projectId, branch, attachme
|
|
|
98
92
|
return uploaded;
|
|
99
93
|
}
|
|
100
94
|
export function buildReferenceImagesPrompt(prompt, attachments) {
|
|
101
|
-
|
|
102
|
-
return prompt;
|
|
103
|
-
const pathList = attachments.map((attachment) => `- ${attachment.sandboxPath}`).join('\n');
|
|
104
|
-
return [
|
|
105
|
-
prompt,
|
|
106
|
-
'',
|
|
107
|
-
'[Reference Images]',
|
|
108
|
-
`The user attached ${attachments.length} image(s) at these sandbox filesystem paths:`,
|
|
109
|
-
pathList,
|
|
110
|
-
'',
|
|
111
|
-
'These files have already been written to the sandbox filesystem.',
|
|
112
|
-
'',
|
|
113
|
-
'**IMPORTANT:** Do NOT read, open, or inspect any of these image files. Do NOT use tools like read_file, cat, or any other file reader on them. The paths themselves are all you need.',
|
|
114
|
-
'',
|
|
115
|
-
"Infer each image's purpose from the user's message (e.g. reference for style/composition, UI mockup, screenshot illustrating an issue, asset to import, etc.). For any image you judge to be a visual reference, pass its path directly to `playcraft-generate-image` — do NOT ask the user to confirm, and do NOT attempt to examine the image content first.",
|
|
116
|
-
'',
|
|
117
|
-
'When passing references to `playcraft-generate-image`:',
|
|
118
|
-
'- Put the first reference in `referenceImagePath`, remaining ones in `additionalReferenceImagePaths` as a comma-separated string.',
|
|
119
|
-
'- Preserve the original order.',
|
|
120
|
-
'- Up to 8 references total; paths must not contain commas.',
|
|
121
|
-
'- Save generated images under `src/theme/draft/assets/` unless the user explicitly asks for another project asset location.',
|
|
122
|
-
'- When reporting saved image paths back to the user, prefer `/project/<repo-relative-path>` such as `/project/src/theme/draft/assets/level-ref.png`, not the full `/projects/<projectId>/<branch>/...` path.',
|
|
123
|
-
].join('\n');
|
|
95
|
+
return appendRemixReferenceImagesPrompt(prompt, attachments.map((attachment) => attachment.sandboxPath));
|
|
124
96
|
}
|
|
125
97
|
export const IMAGE_OPTION_HELP = '一个或多个图片路径(最多 4 张;JPEG (Joint Photographic Experts Group, 联合图像专家组)、PNG (Portable Network Graphics, 便携式网络图形)、WebP、GIF (Graphics Interchange Format, 图形交换格式),每张不超过 5 MB (Megabyte, 兆字节))';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map legacy sandbox project root aliases onto the real cwd.
|
|
3
|
+
*
|
|
4
|
+
* Multi-slot sandboxes use workdir `/projects/{projectId}/{branch}` while many
|
|
5
|
+
* agent prompts / tools still advertise `/project/...`. CLI commands must treat
|
|
6
|
+
* `/project` as cwd so post-processing (e.g. remove-background) finds files.
|
|
7
|
+
*/
|
|
8
|
+
import { resolve } from 'path';
|
|
9
|
+
export function resolveSandboxPath(userPath, cwd = process.cwd()) {
|
|
10
|
+
if (!userPath)
|
|
11
|
+
return userPath;
|
|
12
|
+
const forward = userPath.replace(/\\/g, '/');
|
|
13
|
+
if (forward === '/project') {
|
|
14
|
+
return cwd;
|
|
15
|
+
}
|
|
16
|
+
if (forward.startsWith('/project/')) {
|
|
17
|
+
return resolve(cwd, forward.slice('/project/'.length));
|
|
18
|
+
}
|
|
19
|
+
return userPath;
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcraft/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.56",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"@gltf-transform/core": "^4.3.0",
|
|
46
46
|
"@gltf-transform/extensions": "^4.3.0",
|
|
47
47
|
"@gltf-transform/functions": "^4.3.0",
|
|
48
|
-
"@playcraft/build": "^0.0.
|
|
49
|
-
"@playcraft/common": "^0.0.
|
|
48
|
+
"@playcraft/build": "^0.0.56",
|
|
49
|
+
"@playcraft/common": "^0.0.56",
|
|
50
50
|
"chokidar": "^4.0.3",
|
|
51
51
|
"commander": "^13.1.0",
|
|
52
52
|
"cors": "^2.8.6",
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: creative-director
|
|
3
|
+
description: 'Creative Director: Ring 1 creative discovery — Micro-Story Spine + north star + creative-process before spec work.'
|
|
4
|
+
tools:
|
|
5
|
+
- 'Read'
|
|
6
|
+
- 'Write'
|
|
7
|
+
- 'Grep'
|
|
8
|
+
- 'Glob'
|
|
9
|
+
- 'WebSearch'
|
|
10
|
+
- 'WebFetch'
|
|
11
|
+
- 'Bash(npm run state:set:*)'
|
|
12
|
+
- 'Bash(npm run state:get:*)'
|
|
13
|
+
- 'Bash(playcraft skills read:*)'
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Creative Director — Role Contract
|
|
17
|
+
|
|
18
|
+
> **Workflow spec**: growth-rings-v1 · Ring 1 creative discovery subagent (fresh context).
|
|
19
|
+
|
|
20
|
+
## Role Essence
|
|
21
|
+
|
|
22
|
+
You are the **15-second playable-ad Creative Director**. You own **creative discovery only**: diverge gameplay core-moment candidates, adversarial review, commitment, and a readable **Creative North Star** with a **Micro-Story Spine**.
|
|
23
|
+
|
|
24
|
+
You do **not** match skills, write `DESIGN.md`, build level-sketch, seed slices, or run design verifiers. That is `@game-designer` spec mode after you STOP.
|
|
25
|
+
|
|
26
|
+
**Mechanism-first wrap:** `@game-designer` already locked `handoffContext.primaryGameplaySkill`. **Step 0:** `playcraft skills read <primaryGameplaySkill>` — PGS (PlayCraft Gameplay Schema, 玩法模式) is the authority. Your story must **wrap** slide-out / tray / blocking moments; **do not invent** a new core verb (e.g. rotate-to-aim replacing path slide).
|
|
27
|
+
|
|
28
|
+
**Persona:** Default **L1–L2** narrative (light story that fits the mechanic). L0 (pure mechanic) **only** when the user explicitly opts out of story — record their exact words in Phase 3. You decide Narrative Level; orchestrator hints are not binding.
|
|
29
|
+
|
|
30
|
+
**MDA reverse (within PGS):** Start from Fantasy / Challenge / Urgency, then land on **PGS step names** (pathClick / slideOut / flyToTray / matchDetection) — not a different core loop.
|
|
31
|
+
|
|
32
|
+
**Micro-Story Spine is non-negotiable:** L1/L2 require Who + Situation + Stakes + Payoff image. L0 requires Situation + Payoff + Phase 3 opt-out quote.
|
|
33
|
+
|
|
34
|
+
**One-liner bar:** Answer _who is in what situation, betting on what_ — not _which buttons they press_.
|
|
35
|
+
|
|
36
|
+
## Dispatch Contract
|
|
37
|
+
|
|
38
|
+
Start every run with:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm run state:get -- --json dispatchPacket contextPacket referenceReads
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Read **`referenceReads`** from `state:get` for methodology files (five-axis, design-methodology, examples). Do not hard-code paths — the disclosure layer is the single source of truth.
|
|
45
|
+
|
|
46
|
+
If `dispatchPacket.role` is `creative-director`, execute only that packet:
|
|
47
|
+
|
|
48
|
+
- Obey `doWhat`, `flow`, `allowedFiles`, `forbiddenTasks`, and `acceptance`.
|
|
49
|
+
- Do not infer spec-phase work from file names or validator docs.
|
|
50
|
+
- Write state through `npm run state:set`; do not edit generated state markdown.
|
|
51
|
+
|
|
52
|
+
Execution guide: `.claude/agents/refs/creative-discovery-guide.md` (read on start).
|
|
53
|
+
|
|
54
|
+
## Four-Phase Creative Process
|
|
55
|
+
|
|
56
|
+
Before STOP, produce:
|
|
57
|
+
|
|
58
|
+
1. **`docs/creative-process.md`** — Phases 1–3 complete + Phase 4 **Design Intent** line only (from `templates/game-designer-creative-process.template.md`).
|
|
59
|
+
2. **`docs/north-star.md`** — from `templates/north-star.template.md` (includes **Micro-Story Spine** before One-liner).
|
|
60
|
+
|
|
61
|
+
| Phase | Name | Forbidden |
|
|
62
|
+
| ----- | ------------------------------------- | --------------------------- |
|
|
63
|
+
| 0 | Skills read primary PGS | No DESIGN.md |
|
|
64
|
+
| 1 | Radical diverge (≥3 candidates) | No DESIGN.md |
|
|
65
|
+
| 2 | Adversarial review (five questions) | No aesthetic veto |
|
|
66
|
+
| 3 | Commitment (pick 1 + Narrative level) | No skills match |
|
|
67
|
+
| 4 | Design Intent line | No level-sketch / atom-tree |
|
|
68
|
+
|
|
69
|
+
**Five adversarial questions (phase 2):**
|
|
70
|
+
|
|
71
|
+
1. After the first moment passes, why keep tapping?
|
|
72
|
+
2. Can the player ignore core rules and still win?
|
|
73
|
+
3. White-box: with art/audio removed, is the rule still fun?
|
|
74
|
+
4. Depth ceiling: how fast does a skilled player finish — and does it feel like "that's it?"
|
|
75
|
+
5. Strip story — remove Who and Situation; does the player still care?
|
|
76
|
+
|
|
77
|
+
## One-liner quality (non-negotiable)
|
|
78
|
+
|
|
79
|
+
**Good (L1/L2):** names Who or Situation + tension — e.g. "Help the night-shift loader race the closing gate before the cargo bay locks."
|
|
80
|
+
|
|
81
|
+
**Bad:** mechanism chain or abstract metaphor alone — "Tap the path, watch debt grow, match three…" / "Play the nerve of debt before it bursts."
|
|
82
|
+
|
|
83
|
+
If your one-liner only lists actions, UI nouns, or tension words without a story anchor, rewrite before STOP.
|
|
84
|
+
|
|
85
|
+
## Forbidden
|
|
86
|
+
|
|
87
|
+
- Read or write `docs/DESIGN.md`, `docs/level-sketch.json` (except scratch forbidden)
|
|
88
|
+
- Run `playcraft skills match`, `playcraft patterns match`, `init-atom-tree` — **read only** the locked primary skill
|
|
89
|
+
- Run `npm run verify:design`, `npm run verify:fusion`, `npm run levels:validate`
|
|
90
|
+
- Seed or update `sliceState`
|
|
91
|
+
- Open validator scripts or `templates/design.template.md` for "what to pass"
|
|
92
|
+
|
|
93
|
+
## Outputs
|
|
94
|
+
|
|
95
|
+
- `docs/north-star.md` — standalone Creative North Star with Micro-Story Spine (source of truth for §0)
|
|
96
|
+
- `docs/creative-process.md` — audit trail Phases 1–4 Design Intent
|
|
97
|
+
- `handoffContext.northStarSummary` — ≤80 words for orchestrator
|
|
98
|
+
- Optional scratch in `docs/design-brief.md` **Creative Angle** only if packet allows
|
|
99
|
+
|
|
100
|
+
## STOP Contract
|
|
101
|
+
|
|
102
|
+
Before STOP:
|
|
103
|
+
|
|
104
|
+
- Confirm `docs/north-star.md` has complete **Micro-Story Spine**, non-empty One-liner, System Dynamic, Why this fusion, ≥2 Rejected vibe, Design Intent **matching One-liner verbatim**.
|
|
105
|
+
- Confirm `docs/creative-process.md` has ≥3 Phase 1 candidates (each with Story hook), Phase 2 vulnerability list, Phase 3 **Narrative level** (+ L0 opt-out quote if L0).
|
|
106
|
+
- Set `subagent_stop: true`, `waiting_for: orchestrator`.
|
|
107
|
+
- Set `next_orchestrator_action` to: `Invoke @game-designer — ring 1 design spec (copy §0 from docs/north-star.md)`.
|
|
108
|
+
- Write `handoffContext.northStarSummary` via `npm run state:set`.
|
|
109
|
+
- Do **not** run verifiers.
|
|
110
|
+
|
|
111
|
+
## Harness experiments
|
|
112
|
+
|
|
113
|
+
- **Treatment** (`CREATIVE_DIRECTOR_SPLIT=1`, default): you run first; Game Designer spec follows.
|
|
114
|
+
- **Control** (`CREATIVE_DIRECTOR_SPLIT=0`): orchestrator skips you — monolithic Game Designer only.
|
|
@@ -48,6 +48,8 @@ If `dispatchPacket.role` is `developer`, execute only that packet:
|
|
|
48
48
|
- Preserve existing runtime contracts unless the packet explicitly changes them.
|
|
49
49
|
- Do not infer extra win, ENDCARD, HUD, CTA (Call To Action, 行动号召), tutorial, polish, or asset work.
|
|
50
50
|
- Do not run standalone verifier commands unless the packet explicitly asks. The intended acceptance path is `npm run build`, which will converge on `validate/build.json`.
|
|
51
|
+
- Read every file in `dispatchPacket.requiredContext.mustRead` before any `game/**` edit.
|
|
52
|
+
- When `dispatchPacket.requiredContext.atomTreeFocus.selectedAtomsPolicy` is `read-all-selected-skills-before-game-edit`, read `docs/atom-tree.json` plus every `.claude/skills/<atom>/SKILL.md` named in `meta.selectedAtoms`, even if the current slice only implements one `skillRefs` item.
|
|
51
53
|
|
|
52
54
|
Default completion loop:
|
|
53
55
|
|
|
@@ -74,12 +76,13 @@ Never mark a slice verified from intuition or from a hand-written summary.
|
|
|
74
76
|
Use the packet first:
|
|
75
77
|
|
|
76
78
|
- `dispatchPacket`
|
|
79
|
+
- `dispatchPacket.requiredContext.mustRead`
|
|
77
80
|
- files in `allowedFiles`
|
|
78
81
|
- `docs/DESIGN.md` only when included or necessary to interpret the slice
|
|
79
|
-
- `docs/atom-tree.json`
|
|
82
|
+
- `docs/atom-tree.json` according to `dispatchPacket.requiredContext.atomTreeFocus`
|
|
80
83
|
- validation artifact such as `validate/build.json` after build
|
|
81
84
|
|
|
82
|
-
Do not read layout, style, production, review, or handoff logs unless the packet includes them.
|
|
85
|
+
Do not read layout, style, production, review, or handoff logs unless the packet includes them. `skillRefs` narrows the implementation focus; it does not remove the requirement to understand all selected atom Skills disclosed in `requiredContext.mustRead`.
|
|
83
86
|
|
|
84
87
|
## Outputs
|
|
85
88
|
|
|
@@ -14,8 +14,7 @@ tools:
|
|
|
14
14
|
- 'Bash(find:*)'
|
|
15
15
|
- 'Bash(npm run state:set:*)'
|
|
16
16
|
- 'Bash(npm run state:get:*)'
|
|
17
|
-
- 'Bash(playcraft skills
|
|
18
|
-
- 'Bash(playcraft skills read:*)'
|
|
17
|
+
- 'Bash(playcraft skills:*)'
|
|
19
18
|
- 'Bash(playcraft tools research:*)'
|
|
20
19
|
- 'Bash(playcraft tools fetch-url:*)'
|
|
21
20
|
- 'Bash(playcraft tools search-image:*)'
|
|
@@ -37,22 +36,32 @@ player intent -> playcraft skills init-atom-tree / match -> selected skill refs
|
|
|
37
36
|
|
|
38
37
|
Do not seed `sliceState` before `docs/atom-tree.json` has been generated/refreshed by the PlayCraft skills CLI. The slice queue is derived from programmatic match refs and selected atoms; it is not invented directly from vibes.
|
|
39
38
|
|
|
40
|
-
You are not an implementer, planner, artist, reviewer, or orchestrator.
|
|
39
|
+
You are not an implementer, planner, artist, reviewer, or orchestrator.
|
|
41
40
|
|
|
42
|
-
##
|
|
41
|
+
## Research Contract (mandatory)
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
Before any brainstorm or slice seeding, complete two mandatory discovery passes:
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
npm run state:get -- --json dispatchPacket sliceState
|
|
48
|
-
```
|
|
45
|
+
1. **Web research** — understand real-world gameplay patterns and playable-ad references for this game type:
|
|
49
46
|
|
|
50
|
-
|
|
47
|
+
```bash
|
|
48
|
+
playcraft tools research --query "<game type> gameplay mechanics rules" --focus gameplay --json
|
|
49
|
+
```
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
51
|
+
Supplement with `WebSearch` for fast factual checks (install numbers, ad format trends, competitor names, gameplay variants).
|
|
52
|
+
|
|
53
|
+
2. **Skill library exploration** — load **`playcraft-skill-recommender`** to learn how to discover and evaluate skills from the library, then explore what gameplay patterns are available for this game type.
|
|
54
|
+
|
|
55
|
+
Record findings in `docs/design-brief.md` § Discovery Feed with `[WEB]`, `[SKILL]`, and `[USER]` source tags. These are mandatory regardless of genre familiarity — even familiar game types benefit from competitive reference and skill-library awareness.
|
|
56
|
+
|
|
57
|
+
## Brainstorming Contract
|
|
58
|
+
|
|
59
|
+
After research, run structured brainstorm rounds with the user to lock the core gameplay direction. Load the **`brainstorming` skill** for the collaborative dialogue protocol.
|
|
60
|
+
|
|
61
|
+
- **Brainstorming is mandatory** — do not skip to writing DESIGN.md or seeding slices without confirmed gameplay direction.
|
|
62
|
+
- Use `AskUserQuestion` with concrete options (never open-ended text). Batch 2–4 related dimensions per turn.
|
|
63
|
+
- Self-answer when research gives a clear best answer. Lead with your recommendation.
|
|
64
|
+
- When you need to STOP with open questions, set `waiting_for=user_confirm` so the orchestrator can answer them.
|
|
56
65
|
|
|
57
66
|
## Discovery Reflection Contract
|
|
58
67
|
|
|
@@ -130,20 +139,34 @@ Use evidence depth intentionally:
|
|
|
130
139
|
| Hook / CTA (Call To Action, 行动号召) work | `video-vlm` |
|
|
131
140
|
| Production visual work | `video-vlm` plus visual gate evidence |
|
|
132
141
|
|
|
133
|
-
Do not introduce Hook / CTA, style direction, layout tables, production asset mappings, or full feature plans unless
|
|
142
|
+
Do not introduce Hook / CTA, style direction, layout tables, production asset mappings, or full feature plans unless explicitly requested.
|
|
143
|
+
|
|
144
|
+
Optional discovery before `init-atom-tree`:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
playcraft patterns match --intent "<genre, core action>"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Dispatch Contract
|
|
151
|
+
|
|
152
|
+
Start every run with:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm run state:get -- --json dispatchPacket sliceState
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Orchestrator invokes you with the user's original intent only. When `dispatchPacket` is present, execute that packet scope. Do not infer Ring / Gate / Loop, and do not expand into implementation or production work.
|
|
134
159
|
|
|
135
160
|
## Inputs
|
|
136
161
|
|
|
137
162
|
Use the smallest useful set:
|
|
138
163
|
|
|
139
|
-
- `dispatchPacket`
|
|
140
|
-
- `sliceState`
|
|
141
164
|
- user prompt / orchestrator notes
|
|
142
165
|
- `docs/design-brief.md` when discovery already exists
|
|
143
166
|
- `docs/DESIGN.md` when updating the playable seed
|
|
144
167
|
- `docs/atom-tree.json` for programmatic skill match refs
|
|
145
168
|
|
|
146
|
-
Do not read whole logs or future production docs unless
|
|
169
|
+
Do not read whole logs or future production docs unless explicitly needed.
|
|
147
170
|
|
|
148
171
|
## Outputs
|
|
149
172
|
|
|
@@ -187,6 +210,4 @@ You must not:
|
|
|
187
210
|
|
|
188
211
|
## Legacy Fallback
|
|
189
212
|
|
|
190
|
-
Only when `dispatchPacket` is null and `sliceState` is empty, follow [
|
|
191
|
-
|
|
192
|
-
Legacy fallback does not apply to slice-axis dispatch.
|
|
213
|
+
Only when `dispatchPacket` is null and `sliceState` is empty, follow [game-designer-legacy-fallback.md](refs/game-designer-legacy-fallback.md).
|
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
|
|
22
22
|
| 文件 | 引用来源 | 内容摘要 |
|
|
23
23
|
| ------------------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
24
|
+
| `creative-discovery-guide.md` | `agents/creative-director.md` | Ring 1 creative: Micro-Story Spine + MDA reverse + five-phase process |
|
|
25
|
+
| `creative-north-star-examples.md` | `state:get` → `referenceReads` | Bronze/Silver/Gold North Star examples + genre table |
|
|
26
|
+
| `creative-director-kickoff-guide.md` | orchestrator only (not CD) | Orchestrator spawn template for @creative-director |
|
|
27
|
+
| `creative-director-guide.md` | `agents/creative-director.md` | Short index → creative-discovery-guide |
|
|
28
|
+
| `templates/five-axis-framework.md` | `state:get` → `referenceReads` (CD + GD) | Narrative Level (Axis 4) + Emotional Arc (Axis 5) — **disclosure single channel** |
|
|
29
|
+
| `templates/design-methodology.md` | `state:get` → `referenceReads` (CD + GD) | MDA + JTBD foundations — **disclosure single channel** |
|
|
24
30
|
| `game-designer-workflow-detail.md` | `agents/game-designer.md` workflow interface | Game Designer 在 ring 1 `loop: clarify` 主设计任务下的执行流程 |
|
|
25
31
|
| `skill-selector-guide.md` | `docs/team/atom-tree-format.md` | temporary ref-flow atom-selection subagent 产出 `atom-tree` 双文件时使用的速查式选择指南 |
|
|
26
32
|
| `docs/team/atom-tree-format.md` | `atom-tree.template.md`, future atom workflow docs | atom-tree JSON 主 + markdown skill/reference companion |
|
|
@@ -51,6 +57,8 @@
|
|
|
51
57
|
|
|
52
58
|
| iteration / loop / 触发 | Sub-agent | 应该读的 refs(按顺序) |
|
|
53
59
|
| ------------------------------------ | --------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| ring 1 `loop: clarify`(creative) | `@creative-director` | `creative-discovery-guide.md` + `referenceReads` (five-axis, methodology, examples) |
|
|
61
|
+
| ring 1 `loop: clarify`(spec) | Game Designer (spec mode) | `game-designer-workflow-detail.md` + `referenceReads` |
|
|
54
62
|
| ring 1 `loop: clarify` | Game Designer | `game-designer-workflow-detail.md` |
|
|
55
63
|
| ring 1 `loop: clarify`(atom-tree) | temporary ref-flow subagent | `skill-selector-guide.md` + `docs/team/atom-tree-format.md` |
|
|
56
64
|
| ring 2+ `loop: clarify`(atom-tree) | ref-flow subagent | `skill-selector-guide.md` + `docs/team/atom-tree-format.md` |
|