popilot 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/codex/.codex/commands/_domain.md.hbs +33 -0
- package/adapters/codex/.codex/commands/analytics.md.hbs +55 -0
- package/adapters/codex/.codex/commands/daily.md.hbs +301 -0
- package/adapters/codex/.codex/commands/dev.md.hbs +62 -0
- package/adapters/codex/.codex/commands/gtm.md +82 -0
- package/adapters/codex/.codex/commands/handoff.md +259 -0
- package/adapters/codex/.codex/commands/market.md +120 -0
- package/adapters/codex/.codex/commands/metrics.md +123 -0
- package/adapters/codex/.codex/commands/oscar-loop.md +436 -0
- package/adapters/codex/.codex/commands/party.md +85 -0
- package/adapters/codex/.codex/commands/plan.md +43 -0
- package/adapters/codex/.codex/commands/research.md +203 -0
- package/adapters/codex/.codex/commands/retro.md +68 -0
- package/adapters/codex/.codex/commands/save.md +440 -0
- package/adapters/codex/.codex/commands/sessions.md +139 -0
- package/adapters/codex/.codex/commands/sprint.md +106 -0
- package/adapters/codex/.codex/commands/start.md +396 -0
- package/adapters/codex/.codex/commands/strategy.md +41 -0
- package/adapters/codex/.codex/commands/task.md +220 -0
- package/adapters/codex/.codex/commands/tracking.md +116 -0
- package/adapters/codex/.codex/commands/validate.md +58 -0
- package/adapters/codex/AGENTS.md.hbs +210 -0
- package/adapters/codex/manifest.yaml +36 -0
- package/adapters/gemini/.gemini/commands/_domain.md.hbs +33 -0
- package/adapters/gemini/.gemini/commands/analytics.md.hbs +55 -0
- package/adapters/gemini/.gemini/commands/daily.md.hbs +301 -0
- package/adapters/gemini/.gemini/commands/dev.md.hbs +62 -0
- package/adapters/gemini/.gemini/commands/gtm.md +82 -0
- package/adapters/gemini/.gemini/commands/handoff.md +259 -0
- package/adapters/gemini/.gemini/commands/market.md +120 -0
- package/adapters/gemini/.gemini/commands/metrics.md +123 -0
- package/adapters/gemini/.gemini/commands/oscar-loop.md +436 -0
- package/adapters/gemini/.gemini/commands/party.md +85 -0
- package/adapters/gemini/.gemini/commands/plan.md +43 -0
- package/adapters/gemini/.gemini/commands/research.md +203 -0
- package/adapters/gemini/.gemini/commands/retro.md +68 -0
- package/adapters/gemini/.gemini/commands/save.md +440 -0
- package/adapters/gemini/.gemini/commands/sessions.md +139 -0
- package/adapters/gemini/.gemini/commands/sprint.md +106 -0
- package/adapters/gemini/.gemini/commands/start.md +396 -0
- package/adapters/gemini/.gemini/commands/strategy.md +41 -0
- package/adapters/gemini/.gemini/commands/task.md +220 -0
- package/adapters/gemini/.gemini/commands/tracking.md +116 -0
- package/adapters/gemini/.gemini/commands/validate.md +58 -0
- package/adapters/gemini/GEMINI.md.hbs +210 -0
- package/adapters/gemini/manifest.yaml +36 -0
- package/bin/cli.mjs +215 -4
- package/lib/doctor.mjs +38 -1
- package/lib/hydrate.mjs +15 -0
- package/lib/industry-presets.mjs +135 -0
- package/lib/scaffold.mjs +5 -0
- package/lib/setup-wizard.mjs +71 -2
- package/package.json +1 -1
- package/scaffold/.context/agents/TEMPLATE.md +14 -0
- package/scaffold/.context/agents/analyst.md.hbs +3 -3
- package/scaffold/.context/agents/developer.md.hbs +5 -5
- package/scaffold/.context/agents/gtm-strategist.md.hbs +3 -3
- package/scaffold/.context/agents/handoff-specialist.md.hbs +18 -18
- package/scaffold/.context/agents/market-researcher.md.hbs +6 -6
- package/scaffold/.context/agents/orchestrator.md.hbs +8 -8
- package/scaffold/.context/agents/planner.md.hbs +6 -6
- package/scaffold/.context/agents/qa.md.hbs +5 -5
- package/scaffold/.context/agents/researcher.md.hbs +33 -6
- package/scaffold/.context/agents/strategist.md.hbs +8 -8
- package/scaffold/.context/agents/tracking-governor.md.hbs +2 -2
- package/scaffold/.context/project.yaml.example +25 -0
- package/scaffold/mcp-pm/package.json +19 -0
- package/scaffold/mcp-pm/src/api-client.ts +69 -0
- package/scaffold/mcp-pm/src/index.ts +660 -0
- package/scaffold/mcp-pm/tsconfig.json +14 -0
- package/scaffold/pm-api/package.json +21 -0
- package/scaffold/pm-api/sql/schema-core.sql +331 -0
- package/scaffold/pm-api/sql/schema-docs.sql +25 -0
- package/scaffold/pm-api/sql/schema-meetings.sql +17 -0
- package/scaffold/pm-api/sql/schema-rewards.sql +16 -0
- package/scaffold/pm-api/src/auth.ts +28 -0
- package/scaffold/pm-api/src/blockchain/adapter.ts +20 -0
- package/scaffold/pm-api/src/blockchain/tron.ts +62 -0
- package/scaffold/pm-api/src/db/adapter.ts +36 -0
- package/scaffold/pm-api/src/db/turso.ts +147 -0
- package/scaffold/pm-api/src/index.ts +114 -0
- package/scaffold/pm-api/src/mcp-tools/dashboard.ts +40 -0
- package/scaffold/pm-api/src/mcp-tools/epic.ts +67 -0
- package/scaffold/pm-api/src/mcp-tools/event.ts +89 -0
- package/scaffold/pm-api/src/mcp-tools/index.ts +11 -0
- package/scaffold/pm-api/src/mcp-tools/initiative.ts +51 -0
- package/scaffold/pm-api/src/mcp-tools/memo.ts +164 -0
- package/scaffold/pm-api/src/mcp-tools/notification.ts +37 -0
- package/scaffold/pm-api/src/mcp-tools/retro.ts +183 -0
- package/scaffold/pm-api/src/mcp-tools/sprint.ts +204 -0
- package/scaffold/pm-api/src/mcp-tools/standup.ts +136 -0
- package/scaffold/pm-api/src/mcp-tools/story.ts +230 -0
- package/scaffold/pm-api/src/mcp-tools/task.ts +187 -0
- package/scaffold/pm-api/src/mcp-tools/utils.ts +83 -0
- package/scaffold/pm-api/src/mcp.ts +871 -0
- package/scaffold/pm-api/src/nudge.ts +283 -0
- package/scaffold/pm-api/src/routes/auth.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-activity.ts +27 -0
- package/scaffold/pm-api/src/routes/v2-admin.ts +165 -0
- package/scaffold/pm-api/src/routes/v2-dashboard.ts +189 -0
- package/scaffold/pm-api/src/routes/v2-docs.ts +34 -0
- package/scaffold/pm-api/src/routes/v2-initiatives.ts +118 -0
- package/scaffold/pm-api/src/routes/v2-kickoff.ts +265 -0
- package/scaffold/pm-api/src/routes/v2-meetings.ts +324 -0
- package/scaffold/pm-api/src/routes/v2-memos.ts +257 -0
- package/scaffold/pm-api/src/routes/v2-nav.ts +260 -0
- package/scaffold/pm-api/src/routes/v2-notifications.ts +79 -0
- package/scaffold/pm-api/src/routes/v2-page-content.ts +35 -0
- package/scaffold/pm-api/src/routes/v2-pm.ts +380 -0
- package/scaffold/pm-api/src/routes/v2-policy.ts +58 -0
- package/scaffold/pm-api/src/routes/v2-retro.ts +221 -0
- package/scaffold/pm-api/src/routes/v2-rewards.ts +132 -0
- package/scaffold/pm-api/src/routes/v2-scenarios.ts +48 -0
- package/scaffold/pm-api/src/routes/v2-search.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-standup.ts +127 -0
- package/scaffold/pm-api/src/routes/v2-user.ts +38 -0
- package/scaffold/pm-api/src/types.ts +11 -0
- package/scaffold/pm-api/src/utils/activity.ts +22 -0
- package/scaffold/pm-api/src/utils/admin.ts +9 -0
- package/scaffold/pm-api/src/utils/agent-notify.ts +62 -0
- package/scaffold/pm-api/src/utils/assignee.ts +69 -0
- package/scaffold/pm-api/src/utils/db.ts +45 -0
- package/scaffold/pm-api/src/utils/initiative.ts +23 -0
- package/scaffold/pm-api/src/utils/sprint-lifecycle.ts +96 -0
- package/scaffold/pm-api/tsconfig.json +15 -0
- package/scaffold/pm-api/wrangler.toml.hbs +11 -0
- package/scaffold/spec-site/package-lock.json +40 -0
- package/scaffold/spec-site/package.json +4 -1
- package/scaffold/spec-site/src/api/types.ts +6 -0
- package/scaffold/spec-site/src/components/AppHeader.vue +429 -55
- package/scaffold/spec-site/src/components/MemberSelect.vue +48 -0
- package/scaffold/spec-site/src/components/NotificationDropdown.vue +116 -0
- package/scaffold/spec-site/src/components/SearchModal.vue +102 -0
- package/scaffold/spec-site/src/components/VelocityChart.vue +77 -0
- package/scaffold/spec-site/src/composables/pmTypes.ts +15 -2
- package/scaffold/spec-site/src/composables/useDashboard.ts +221 -0
- package/scaffold/spec-site/src/composables/useMediaQuery.ts +28 -0
- package/scaffold/spec-site/src/composables/useNotification.ts +200 -0
- package/scaffold/spec-site/src/composables/usePmStore.ts +48 -1
- package/scaffold/spec-site/src/composables/useRetro.ts +6 -0
- package/scaffold/spec-site/src/composables/useStandup.ts +201 -0
- package/scaffold/spec-site/src/composables/useTheme.ts +37 -0
- package/scaffold/spec-site/src/composables/useUser.ts +19 -1
- package/scaffold/spec-site/src/features.ts +108 -0
- package/scaffold/spec-site/src/pages/AdminPage.vue +299 -0
- package/scaffold/spec-site/src/pages/DashboardPage.vue +650 -0
- package/scaffold/spec-site/src/pages/DocsHub.vue +157 -0
- package/scaffold/spec-site/src/pages/InboxPage.vue +156 -0
- package/scaffold/spec-site/src/pages/MeetingsPage.vue +294 -0
- package/scaffold/spec-site/src/pages/MyPage.vue +343 -0
- package/scaffold/spec-site/src/pages/RewardsPage.vue +266 -0
- package/scaffold/spec-site/src/pages/board/BoardAdmin.vue +422 -0
- package/scaffold/spec-site/src/pages/board/BoardEpicSection.vue +54 -0
- package/scaffold/spec-site/src/pages/board/BoardPage.vue +884 -0
- package/scaffold/spec-site/src/pages/board/BoardStoryCard.vue +67 -0
- package/scaffold/spec-site/src/pages/board/BoardTaskItem.vue +52 -0
- package/scaffold/spec-site/src/pages/board/MyTasksPage.vue +202 -0
- package/scaffold/spec-site/src/pages/board/SprintClose.vue +167 -0
- package/scaffold/spec-site/src/pages/board/SprintColumn.vue +49 -0
- package/scaffold/spec-site/src/pages/board/SprintKickoff.vue +389 -0
- package/scaffold/spec-site/src/pages/board/StatusBadge.vue +52 -0
- package/scaffold/spec-site/src/pages/board/StoryDetailPanel.vue +495 -0
- package/scaffold/spec-site/src/pages/board/TaskCard.vue +42 -0
- package/scaffold/spec-site/src/pages/retro/RetroCard.vue +36 -2
- package/scaffold/spec-site/src/pages/retro/RetroHeader.vue +82 -66
- package/scaffold/spec-site/src/pages/retro/RetroPage.vue +47 -18
- package/scaffold/spec-site/src/pages/standup/StandupEntryCard.vue +551 -0
- package/scaffold/spec-site/src/pages/standup/StandupForm.vue +68 -0
- package/scaffold/spec-site/src/pages/standup/StandupList.vue +71 -0
- package/scaffold/spec-site/src/pages/standup/StandupPage.vue +225 -0
- package/scaffold/spec-site/src/router.ts +141 -0
package/bin/cli.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { resolve, basename } from 'node:path';
|
|
4
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
4
5
|
import { execSync } from 'node:child_process';
|
|
5
6
|
import { copyScaffold, appendToFile, detectExisting } from '../lib/scaffold.mjs';
|
|
6
7
|
import { runSetupWizard } from '../lib/setup-wizard.mjs';
|
|
@@ -15,6 +16,8 @@ const USAGE = `
|
|
|
15
16
|
init [dir] Scaffold + interactive setup + hydration (default)
|
|
16
17
|
hydrate [dir] Sync latest scaffold templates + re-hydrate from project.yaml
|
|
17
18
|
doctor [dir] Check installation health
|
|
19
|
+
deploy [dir] Deploy pm-api to Cloudflare Workers (Tier 2)
|
|
20
|
+
migrate [dir] Run SQL schema migrations on pm-api database (Tier 2)
|
|
18
21
|
help Show this help
|
|
19
22
|
|
|
20
23
|
Options:
|
|
@@ -28,10 +31,12 @@ const USAGE = `
|
|
|
28
31
|
npx popilot hydrate
|
|
29
32
|
npx popilot hydrate --force
|
|
30
33
|
npx popilot doctor
|
|
34
|
+
npx popilot deploy
|
|
35
|
+
npx popilot migrate
|
|
31
36
|
npx popilot my-project # same as: popilot init my-project
|
|
32
37
|
`;
|
|
33
38
|
|
|
34
|
-
const SUBCOMMANDS = new Set(['init', 'hydrate', 'doctor', 'help']);
|
|
39
|
+
const SUBCOMMANDS = new Set(['init', 'hydrate', 'doctor', 'deploy', 'migrate', 'help']);
|
|
35
40
|
|
|
36
41
|
async function main() {
|
|
37
42
|
const args = process.argv.slice(2);
|
|
@@ -71,6 +76,12 @@ async function main() {
|
|
|
71
76
|
case 'doctor':
|
|
72
77
|
await cmdDoctor(targetDir, { skipSpecSite, platform });
|
|
73
78
|
break;
|
|
79
|
+
case 'deploy':
|
|
80
|
+
await cmdDeploy(targetDir);
|
|
81
|
+
break;
|
|
82
|
+
case 'migrate':
|
|
83
|
+
await cmdMigrate(targetDir);
|
|
84
|
+
break;
|
|
74
85
|
}
|
|
75
86
|
}
|
|
76
87
|
|
|
@@ -133,7 +144,34 @@ async function cmdInit(targetDir, { skipSpecSite, force, platform }) {
|
|
|
133
144
|
console.log(` ${f} ✅ (domain)`);
|
|
134
145
|
}
|
|
135
146
|
|
|
136
|
-
//
|
|
147
|
+
// 4a. Install pm-api dependencies (Tier 2)
|
|
148
|
+
const pmApiDir = resolve(targetDir, 'pm-api');
|
|
149
|
+
try {
|
|
150
|
+
const { access: fsAccess } = await import('node:fs/promises');
|
|
151
|
+
await fsAccess(resolve(pmApiDir, 'package.json'));
|
|
152
|
+
console.log();
|
|
153
|
+
console.log(' 📦 Installing pm-api dependencies...');
|
|
154
|
+
try {
|
|
155
|
+
execSync('npm install', { cwd: pmApiDir, stdio: 'pipe' });
|
|
156
|
+
console.log(' ✅ Done');
|
|
157
|
+
} catch {
|
|
158
|
+
console.log(' ⚠️ npm install failed. Run manually: cd pm-api && npm install');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Also install mcp-pm
|
|
162
|
+
const mcpPmDir = resolve(targetDir, 'mcp-pm');
|
|
163
|
+
console.log(' 📦 Installing mcp-pm dependencies...');
|
|
164
|
+
try {
|
|
165
|
+
execSync('npm install', { cwd: mcpPmDir, stdio: 'pipe' });
|
|
166
|
+
console.log(' ✅ Done');
|
|
167
|
+
} catch {
|
|
168
|
+
console.log(' ⚠️ npm install failed. Run manually: cd mcp-pm && npm install');
|
|
169
|
+
}
|
|
170
|
+
} catch {
|
|
171
|
+
// pm-api not present (Tier 0/1) — skip
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 4b. Install spec-site dependencies
|
|
137
175
|
if (!skipSpecSite) {
|
|
138
176
|
const specSiteDir = resolve(targetDir, 'spec-site');
|
|
139
177
|
console.log();
|
|
@@ -171,10 +209,19 @@ async function cmdInit(targetDir, { skipSpecSite, force, platform }) {
|
|
|
171
209
|
}
|
|
172
210
|
console.log(' 3. Oscar can run a deep interview to enrich your project context');
|
|
173
211
|
console.log();
|
|
212
|
+
// Platform-aware file paths
|
|
213
|
+
let sysPromptName = 'CLAUDE.md';
|
|
214
|
+
let cmdDirName = '.claude/commands/';
|
|
215
|
+
try {
|
|
216
|
+
const m = await loadManifest(platform);
|
|
217
|
+
sysPromptName = m.system_prompt?.target || sysPromptName;
|
|
218
|
+
cmdDirName = m.commands?.target_dir || cmdDirName;
|
|
219
|
+
} catch {}
|
|
220
|
+
|
|
174
221
|
console.log(' 📁 Created:');
|
|
175
|
-
console.log(
|
|
222
|
+
console.log(` ${sysPromptName.padEnd(20)} → System instructions (hydrated)`);
|
|
176
223
|
console.log(' .context/project.yaml → Project configuration');
|
|
177
|
-
console.log('
|
|
224
|
+
console.log(` ${(cmdDirName + '/').replace(/\/\/$/, '/').padEnd(20)} → Slash commands`);
|
|
178
225
|
console.log(' .context/agents/ → Agent personas (hydrated)');
|
|
179
226
|
if (!skipSpecSite) {
|
|
180
227
|
console.log(' spec-site/ → Interactive spec viewer (Vue3 + Vite)');
|
|
@@ -232,6 +279,170 @@ async function cmdDoctor(targetDir, { skipSpecSite, platform }) {
|
|
|
232
279
|
process.exit(failed.length > 0 ? 1 : 0);
|
|
233
280
|
}
|
|
234
281
|
|
|
282
|
+
// ── deploy ───────────────────────────────────────────────
|
|
283
|
+
|
|
284
|
+
async function cmdDeploy(targetDir) {
|
|
285
|
+
console.log();
|
|
286
|
+
console.log(' 🚀 Popilot — Deploy pm-api');
|
|
287
|
+
console.log(' ══════════════════════════════════════');
|
|
288
|
+
console.log();
|
|
289
|
+
|
|
290
|
+
const pmApiDir = resolve(targetDir, 'pm-api');
|
|
291
|
+
|
|
292
|
+
if (!existsSync(pmApiDir)) {
|
|
293
|
+
console.log(' ❌ pm-api directory not found.');
|
|
294
|
+
console.log(` Expected at: ${pmApiDir}`);
|
|
295
|
+
console.log(' Deploy is only available for Tier 2 (interactive spec-site with backend).');
|
|
296
|
+
console.log();
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const wranglerToml = resolve(pmApiDir, 'wrangler.toml');
|
|
301
|
+
if (!existsSync(wranglerToml)) {
|
|
302
|
+
console.log(' ❌ wrangler.toml not found in pm-api.');
|
|
303
|
+
console.log(' Found wrangler.toml.hbs — run `popilot hydrate` first to generate wrangler.toml.');
|
|
304
|
+
console.log();
|
|
305
|
+
process.exit(1);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log(` 📂 Deploying from: ${pmApiDir}`);
|
|
309
|
+
console.log();
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
execSync('npx wrangler deploy', { cwd: pmApiDir, stdio: 'inherit' });
|
|
313
|
+
console.log();
|
|
314
|
+
console.log(' ✅ pm-api deployed successfully.');
|
|
315
|
+
console.log();
|
|
316
|
+
} catch {
|
|
317
|
+
console.log();
|
|
318
|
+
console.log(' ❌ Deploy failed. Check the wrangler output above for details.');
|
|
319
|
+
console.log();
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ── migrate ──────────────────────────────────────────────
|
|
325
|
+
|
|
326
|
+
async function cmdMigrate(targetDir) {
|
|
327
|
+
console.log();
|
|
328
|
+
console.log(' 🗄️ Popilot — Run SQL Migrations');
|
|
329
|
+
console.log(' ══════════════════════════════════════');
|
|
330
|
+
console.log();
|
|
331
|
+
|
|
332
|
+
const pmApiDir = resolve(targetDir, 'pm-api');
|
|
333
|
+
|
|
334
|
+
if (!existsSync(pmApiDir)) {
|
|
335
|
+
console.log(' ❌ pm-api directory not found.');
|
|
336
|
+
console.log(` Expected at: ${pmApiDir}`);
|
|
337
|
+
console.log(' Migrate is only available for Tier 2 (interactive spec-site with backend).');
|
|
338
|
+
console.log();
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const sqlDir = resolve(pmApiDir, 'sql');
|
|
343
|
+
if (!existsSync(sqlDir)) {
|
|
344
|
+
console.log(' ❌ pm-api/sql/ directory not found.');
|
|
345
|
+
console.log(' No migration files available.');
|
|
346
|
+
console.log();
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Read D1 database name from wrangler.toml
|
|
351
|
+
const wranglerToml = resolve(pmApiDir, 'wrangler.toml');
|
|
352
|
+
if (!existsSync(wranglerToml)) {
|
|
353
|
+
console.log(' ❌ wrangler.toml not found in pm-api.');
|
|
354
|
+
console.log(' Run `popilot hydrate` first to generate wrangler.toml.');
|
|
355
|
+
console.log();
|
|
356
|
+
process.exit(1);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const wranglerContent = readFileSync(wranglerToml, 'utf-8');
|
|
360
|
+
const dbNameMatch = wranglerContent.match(/database_name\s*=\s*"([^"]+)"/);
|
|
361
|
+
const dbName = dbNameMatch ? dbNameMatch[1] : null;
|
|
362
|
+
|
|
363
|
+
if (!dbName) {
|
|
364
|
+
console.log(' ❌ Could not find D1 database_name in wrangler.toml.');
|
|
365
|
+
console.log(' Ensure [[d1_databases]] is configured with a database_name.');
|
|
366
|
+
console.log();
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
console.log(` 📂 SQL directory: ${sqlDir}`);
|
|
371
|
+
console.log(` 🗃️ D1 database: ${dbName}`);
|
|
372
|
+
console.log();
|
|
373
|
+
|
|
374
|
+
// Read project.yaml to determine enabled features
|
|
375
|
+
const projectYaml = resolve(targetDir, '.context', 'project.yaml');
|
|
376
|
+
let features = { rewards: false, meetings: true, docs: true };
|
|
377
|
+
|
|
378
|
+
if (existsSync(projectYaml)) {
|
|
379
|
+
try {
|
|
380
|
+
const yamlContent = readFileSync(projectYaml, 'utf-8');
|
|
381
|
+
// Parse feature flags from YAML (simple regex — avoids adding a YAML dep)
|
|
382
|
+
const rewardsMatch = yamlContent.match(/features:[\s\S]*?rewards:\s*(true|false)/);
|
|
383
|
+
const meetingsMatch = yamlContent.match(/features:[\s\S]*?meetings:\s*(true|false)/);
|
|
384
|
+
const docsMatch = yamlContent.match(/features:[\s\S]*?docs:\s*(true|false)/);
|
|
385
|
+
|
|
386
|
+
if (rewardsMatch) features.rewards = rewardsMatch[1] === 'true';
|
|
387
|
+
if (meetingsMatch) features.meetings = meetingsMatch[1] === 'true';
|
|
388
|
+
if (docsMatch) features.docs = docsMatch[1] === 'true';
|
|
389
|
+
} catch {
|
|
390
|
+
console.log(' ⚠️ Could not read project.yaml — using default feature flags.');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Build list of schemas to apply
|
|
395
|
+
const schemas = [{ file: 'schema-core.sql', label: 'core (always)' }];
|
|
396
|
+
|
|
397
|
+
if (features.rewards) {
|
|
398
|
+
schemas.push({ file: 'schema-rewards.sql', label: 'rewards' });
|
|
399
|
+
}
|
|
400
|
+
if (features.meetings) {
|
|
401
|
+
schemas.push({ file: 'schema-meetings.sql', label: 'meetings' });
|
|
402
|
+
}
|
|
403
|
+
if (features.docs) {
|
|
404
|
+
schemas.push({ file: 'schema-docs.sql', label: 'docs' });
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
console.log(' 📋 Schemas to apply:');
|
|
408
|
+
for (const s of schemas) {
|
|
409
|
+
console.log(` - ${s.file} (${s.label})`);
|
|
410
|
+
}
|
|
411
|
+
console.log();
|
|
412
|
+
|
|
413
|
+
// Execute each schema
|
|
414
|
+
let applied = 0;
|
|
415
|
+
let failed = 0;
|
|
416
|
+
|
|
417
|
+
for (const s of schemas) {
|
|
418
|
+
const sqlFile = resolve(sqlDir, s.file);
|
|
419
|
+
if (!existsSync(sqlFile)) {
|
|
420
|
+
console.log(` ⚠️ ${s.file} not found — skipped`);
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
execSync(
|
|
426
|
+
`npx wrangler d1 execute ${dbName} --file=sql/${s.file} --remote`,
|
|
427
|
+
{ cwd: pmApiDir, stdio: 'pipe' }
|
|
428
|
+
);
|
|
429
|
+
console.log(` ✅ ${s.file} applied`);
|
|
430
|
+
applied++;
|
|
431
|
+
} catch (err) {
|
|
432
|
+
console.log(` ❌ ${s.file} failed: ${err.message}`);
|
|
433
|
+
failed++;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
console.log();
|
|
438
|
+
if (failed === 0) {
|
|
439
|
+
console.log(` ✅ Migration complete — ${applied} schema(s) applied.`);
|
|
440
|
+
} else {
|
|
441
|
+
console.log(` ⚠️ Migration finished with errors — ${applied} applied, ${failed} failed.`);
|
|
442
|
+
}
|
|
443
|
+
console.log();
|
|
444
|
+
}
|
|
445
|
+
|
|
235
446
|
// ── Run ─────────────────────────────────────────────────
|
|
236
447
|
|
|
237
448
|
main().catch(err => {
|
package/lib/doctor.mjs
CHANGED
|
@@ -97,7 +97,44 @@ export async function runDoctor(targetDir, opts = {}) {
|
|
|
97
97
|
}, passed, failed, warnings);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
// 7.
|
|
100
|
+
// 7. Tier 2 checks (pm-api + mcp-pm)
|
|
101
|
+
const pmApiDir = join(targetDir, 'pm-api');
|
|
102
|
+
let hasPmApi = false;
|
|
103
|
+
try { await access(pmApiDir); hasPmApi = true; } catch {}
|
|
104
|
+
|
|
105
|
+
if (hasPmApi) {
|
|
106
|
+
await check('pm-api/package.json exists', async () => {
|
|
107
|
+
await access(join(pmApiDir, 'package.json'));
|
|
108
|
+
}, passed, failed);
|
|
109
|
+
|
|
110
|
+
await check('pm-api/wrangler.toml exists (hydrated)', async () => {
|
|
111
|
+
await access(join(pmApiDir, 'wrangler.toml'));
|
|
112
|
+
try {
|
|
113
|
+
await access(join(pmApiDir, 'wrangler.toml.hbs'));
|
|
114
|
+
throw new Error('wrangler.toml.hbs still exists — hydration incomplete');
|
|
115
|
+
} catch (e) {
|
|
116
|
+
if (e.message.includes('hydration')) throw e;
|
|
117
|
+
}
|
|
118
|
+
}, passed, failed);
|
|
119
|
+
|
|
120
|
+
await check('pm-api/sql/schema-core.sql exists', async () => {
|
|
121
|
+
await access(join(pmApiDir, 'sql', 'schema-core.sql'));
|
|
122
|
+
}, passed, failed);
|
|
123
|
+
|
|
124
|
+
await check('mcp-pm/package.json exists', async () => {
|
|
125
|
+
await access(join(targetDir, 'mcp-pm', 'package.json'));
|
|
126
|
+
}, passed, failed);
|
|
127
|
+
|
|
128
|
+
await check('pm-api/node_modules exists', async () => {
|
|
129
|
+
await access(join(pmApiDir, 'node_modules'));
|
|
130
|
+
}, passed, failed, warnings);
|
|
131
|
+
|
|
132
|
+
await check('mcp-pm/node_modules exists', async () => {
|
|
133
|
+
await access(join(targetDir, 'mcp-pm', 'node_modules'));
|
|
134
|
+
}, passed, failed, warnings);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 8. .gitignore entries
|
|
101
138
|
await check('.gitignore includes user-context.yaml', async () => {
|
|
102
139
|
const content = await readFile(join(targetDir, '.gitignore'), 'utf-8');
|
|
103
140
|
if (!content.includes('user-context.yaml')) {
|
package/lib/hydrate.mjs
CHANGED
|
@@ -145,6 +145,21 @@ export async function hydrate(targetDir, opts = {}) {
|
|
|
145
145
|
if (result) hydrated.push(relative(targetDir, result));
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// pm-api wrangler.toml.hbs hydration (Tier 2)
|
|
149
|
+
const pmApiWranglerPath = join(targetDir, 'pm-api', 'wrangler.toml.hbs');
|
|
150
|
+
try {
|
|
151
|
+
const wranglerResult = await hydrateFile(pmApiWranglerPath, {
|
|
152
|
+
ctx,
|
|
153
|
+
registry,
|
|
154
|
+
enabledProviders,
|
|
155
|
+
targetType: 'system',
|
|
156
|
+
targetName: 'wrangler.toml',
|
|
157
|
+
});
|
|
158
|
+
if (wranglerResult) hydrated.push(relative(targetDir, wranglerResult));
|
|
159
|
+
} catch {
|
|
160
|
+
// pm-api not present (Tier 0/1) — skip
|
|
161
|
+
}
|
|
162
|
+
|
|
148
163
|
// Domain command generation
|
|
149
164
|
const domains = projectYaml.operations?.domains || [];
|
|
150
165
|
const domainResults = [];
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Industry presets — maps industry type to template variables
|
|
3
|
+
* used in agent .hbs persona generation.
|
|
4
|
+
*
|
|
5
|
+
* Each preset provides 21 project.* variables that agent templates
|
|
6
|
+
* reference via {{project.example_entity}}, {{project.key_metrics}}, etc.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const PRESETS = {
|
|
10
|
+
saas: {
|
|
11
|
+
industry_label: 'SaaS',
|
|
12
|
+
domain_expertise: 'SaaS product management, subscription lifecycle, activation & retention optimization',
|
|
13
|
+
key_metrics: 'MRR, Churn Rate, LTV, CAC, Trial-to-Paid Conversion',
|
|
14
|
+
example_entity: 'subscription plan',
|
|
15
|
+
example_entity_plural: 'subscription plans',
|
|
16
|
+
example_status_feature: 'plan health indicator',
|
|
17
|
+
example_status_states: '🟢 active, 🟡 at-risk, 🔴 churning',
|
|
18
|
+
example_metric_name: 'Trial-to-Paid Conversion Rate',
|
|
19
|
+
example_metric_before: '12%',
|
|
20
|
+
example_metric_target: '20%',
|
|
21
|
+
example_persona_primary: 'trial users in first 14 days',
|
|
22
|
+
example_icp: 'new SMB teams (5-20 seats)',
|
|
23
|
+
example_icp_ko: '신규 SMB 팀(5-20석)',
|
|
24
|
+
example_api_endpoint: '/api/subscriptions/{id}',
|
|
25
|
+
example_event_name: 'plan_status_viewed',
|
|
26
|
+
example_chart_name: 'MRR trend chart',
|
|
27
|
+
example_data_path: 'domains/subscriptions/database.md',
|
|
28
|
+
example_empty_state_msg: '구독 플랜을 등록해보세요',
|
|
29
|
+
example_few_shot_problem: 'Users discover plan issues 72h late',
|
|
30
|
+
example_few_shot_question: 'If we provide plan health indicators, will users take preventive action?',
|
|
31
|
+
example_action: 'upgrade to premium',
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
ecommerce: {
|
|
35
|
+
industry_label: 'E-commerce',
|
|
36
|
+
domain_expertise: 'E-commerce operations, product catalog management, order fulfillment & conversion optimization',
|
|
37
|
+
key_metrics: 'GMV, Conversion Rate, AOV, Cart Abandonment Rate, Repeat Purchase Rate',
|
|
38
|
+
example_entity: 'product listing',
|
|
39
|
+
example_entity_plural: 'product listings',
|
|
40
|
+
example_status_feature: 'listing performance indicator',
|
|
41
|
+
example_status_states: '🟢 top-seller, 🟡 underperforming, 🔴 stale',
|
|
42
|
+
example_metric_name: 'Cart-to-Purchase Conversion Rate',
|
|
43
|
+
example_metric_before: '18%',
|
|
44
|
+
example_metric_target: '28%',
|
|
45
|
+
example_persona_primary: 'first-time buyers within 7 days of signup',
|
|
46
|
+
example_icp: 'online shoppers aged 25-40 in metro areas',
|
|
47
|
+
example_icp_ko: '수도권 25-40세 온라인 쇼핑 고객',
|
|
48
|
+
example_api_endpoint: '/api/products/{id}',
|
|
49
|
+
example_event_name: 'product_detail_viewed',
|
|
50
|
+
example_chart_name: 'GMV trend chart',
|
|
51
|
+
example_data_path: 'domains/products/database.md',
|
|
52
|
+
example_empty_state_msg: '첫 번째 상품을 등록해보세요',
|
|
53
|
+
example_few_shot_problem: 'Sellers discover underperforming listings too late',
|
|
54
|
+
example_few_shot_question: 'If we show listing performance indicators, will sellers optimize faster?',
|
|
55
|
+
example_action: 'add to cart',
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
b2b_platform: {
|
|
59
|
+
industry_label: 'B2B Platform',
|
|
60
|
+
domain_expertise: 'B2B platform management, client onboarding, workflow automation & enterprise sales cycle',
|
|
61
|
+
key_metrics: 'ARR, Net Revenue Retention, Onboarding Completion Rate, Feature Adoption, Expansion Revenue',
|
|
62
|
+
example_entity: 'client workspace',
|
|
63
|
+
example_entity_plural: 'client workspaces',
|
|
64
|
+
example_status_feature: 'workspace health score',
|
|
65
|
+
example_status_states: '🟢 healthy, 🟡 needs-attention, 🔴 at-risk',
|
|
66
|
+
example_metric_name: 'Onboarding Completion Rate',
|
|
67
|
+
example_metric_before: '55%',
|
|
68
|
+
example_metric_target: '80%',
|
|
69
|
+
example_persona_primary: 'new enterprise clients in first 30 days',
|
|
70
|
+
example_icp: 'mid-market companies (50-500 employees)',
|
|
71
|
+
example_icp_ko: '중견기업(50-500명 규모)',
|
|
72
|
+
example_api_endpoint: '/api/workspaces/{id}',
|
|
73
|
+
example_event_name: 'workspace_setup_completed',
|
|
74
|
+
example_chart_name: 'ARR trend chart',
|
|
75
|
+
example_data_path: 'domains/workspaces/database.md',
|
|
76
|
+
example_empty_state_msg: '워크스페이스를 설정해보세요',
|
|
77
|
+
example_few_shot_problem: 'Clients get stuck during onboarding and churn before activation',
|
|
78
|
+
example_few_shot_question: 'If we provide guided onboarding with health scores, will completion rate improve?',
|
|
79
|
+
example_action: 'complete onboarding',
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
generic: {
|
|
83
|
+
industry_label: 'Digital Product',
|
|
84
|
+
domain_expertise: 'Product management, user experience optimization, growth and retention strategy',
|
|
85
|
+
key_metrics: 'DAU, Retention Rate, Activation Rate, NPS, Feature Adoption Rate',
|
|
86
|
+
example_entity: 'feature module',
|
|
87
|
+
example_entity_plural: 'feature modules',
|
|
88
|
+
example_status_feature: 'usage health indicator',
|
|
89
|
+
example_status_states: '🟢 active, 🟡 declining, 🔴 inactive',
|
|
90
|
+
example_metric_name: 'Feature Activation Rate',
|
|
91
|
+
example_metric_before: '25%',
|
|
92
|
+
example_metric_target: '45%',
|
|
93
|
+
example_persona_primary: 'new users in first 7 days',
|
|
94
|
+
example_icp: 'early adopters who complete onboarding',
|
|
95
|
+
example_icp_ko: '온보딩을 완료한 얼리어답터',
|
|
96
|
+
example_api_endpoint: '/api/resources/{id}',
|
|
97
|
+
example_event_name: 'feature_activated',
|
|
98
|
+
example_chart_name: 'DAU trend chart',
|
|
99
|
+
example_data_path: 'domains/core/database.md',
|
|
100
|
+
example_empty_state_msg: '첫 번째 항목을 만들어보세요',
|
|
101
|
+
example_few_shot_problem: 'Users sign up but never reach the activation moment',
|
|
102
|
+
example_few_shot_question: 'If we redesign the first-run experience, will activation rate improve?',
|
|
103
|
+
example_action: 'complete first task',
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/** All required keys every preset must have */
|
|
108
|
+
export const REQUIRED_KEYS = Object.keys(PRESETS.saas);
|
|
109
|
+
|
|
110
|
+
/** List available industry IDs */
|
|
111
|
+
export function listIndustries() {
|
|
112
|
+
return Object.keys(PRESETS);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get a preset by industry ID.
|
|
117
|
+
* @param {string} industry
|
|
118
|
+
* @returns {Record<string, string>|null}
|
|
119
|
+
*/
|
|
120
|
+
export function getPreset(industry) {
|
|
121
|
+
return PRESETS[industry] || null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get a preset and allow overrides for specific fields.
|
|
126
|
+
* @param {string} industry
|
|
127
|
+
* @param {Record<string, string>} [overrides]
|
|
128
|
+
* @returns {Record<string, string>}
|
|
129
|
+
*/
|
|
130
|
+
export function getPresetWithOverrides(industry, overrides = {}) {
|
|
131
|
+
const base = PRESETS[industry] || PRESETS.generic;
|
|
132
|
+
return { ...base, ...overrides };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default PRESETS;
|
package/lib/scaffold.mjs
CHANGED
|
@@ -57,6 +57,11 @@ async function walk(srcDir, destDir, targetDir, options, copied, overwritten, sk
|
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// Skip pm-api and mcp-pm if not Tier 2
|
|
61
|
+
if (options.skipPmApi && (relPath.startsWith('pm-api') || relPath.startsWith('mcp-pm'))) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
// Skip manifest.yaml (adapter metadata, not a project file)
|
|
61
66
|
if (entry.name === 'manifest.yaml') {
|
|
62
67
|
continue;
|
package/lib/setup-wizard.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import { readdir, readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
import { ask, confirm, select, createPrompt } from './prompt.mjs';
|
|
11
11
|
import { parse as parseYaml, stringify as stringifyYaml } from './yaml-lite.mjs';
|
|
12
|
+
import { listIndustries, getPresetWithOverrides } from './industry-presets.mjs';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Run the interactive setup wizard.
|
|
@@ -58,6 +59,39 @@ export async function runSetupWizard(targetDir, opts = {}) {
|
|
|
58
59
|
|
|
59
60
|
console.log();
|
|
60
61
|
|
|
62
|
+
// ── Phase 1.5: Industry ──────────────────────────
|
|
63
|
+
console.log(' ──────────────────────────────────────');
|
|
64
|
+
console.log(' 🏭 Industry');
|
|
65
|
+
console.log(' ──────────────────────────────────────');
|
|
66
|
+
console.log();
|
|
67
|
+
|
|
68
|
+
const industryOptions = listIndustries().map(id => ({
|
|
69
|
+
label: id === 'saas' ? 'SaaS' :
|
|
70
|
+
id === 'ecommerce' ? 'E-commerce' :
|
|
71
|
+
id === 'b2b_platform' ? 'B2B Platform' :
|
|
72
|
+
'Generic (any product)',
|
|
73
|
+
value: id,
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
const industry = await select(rl, 'Industry type:', industryOptions, 3);
|
|
77
|
+
const preset = getPresetWithOverrides(industry);
|
|
78
|
+
|
|
79
|
+
// Offer override for key fields
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(' You can customize key fields (Enter to keep defaults):');
|
|
82
|
+
const domainExpertiseOverride = await ask(rl, `Domain expertise [${preset.domain_expertise.slice(0, 50)}...]`);
|
|
83
|
+
const keyMetricsOverride = await ask(rl, `Key metrics [${preset.key_metrics.slice(0, 50)}...]`);
|
|
84
|
+
const exampleEntityOverride = await ask(rl, `Example entity [${preset.example_entity}]`);
|
|
85
|
+
|
|
86
|
+
const industryOverrides = {};
|
|
87
|
+
if (domainExpertiseOverride) industryOverrides.domain_expertise = domainExpertiseOverride;
|
|
88
|
+
if (keyMetricsOverride) industryOverrides.key_metrics = keyMetricsOverride;
|
|
89
|
+
if (exampleEntityOverride) industryOverrides.example_entity = exampleEntityOverride;
|
|
90
|
+
|
|
91
|
+
const industryPreset = getPresetWithOverrides(industry, industryOverrides);
|
|
92
|
+
|
|
93
|
+
console.log();
|
|
94
|
+
|
|
61
95
|
// ── Phase 2: Domains ─────────────────────────────
|
|
62
96
|
const hasDomains = await confirm(rl, 'Do you have work domains?', false);
|
|
63
97
|
let domains = [];
|
|
@@ -96,6 +130,38 @@ export async function runSetupWizard(targetDir, opts = {}) {
|
|
|
96
130
|
specSiteConfig.mode = specSiteTier;
|
|
97
131
|
}
|
|
98
132
|
|
|
133
|
+
// ── Phase 6: Backend Setup (Tier 2) ──────────────
|
|
134
|
+
let pmApiConfig = { enabled: false, url: '', features: { rewards: false, meetings: true, docs: true, initiatives: true }, blockchain: { enabled: false, provider: '', token_name: '', contract_address: '', token_decimals: 8 } };
|
|
135
|
+
|
|
136
|
+
if (specSiteTier === 'interactive') {
|
|
137
|
+
console.log();
|
|
138
|
+
console.log(' ──────────────────────────────────────');
|
|
139
|
+
console.log(' 🖥️ Backend Setup (Tier 2)');
|
|
140
|
+
console.log(' ──────────────────────────────────────');
|
|
141
|
+
console.log();
|
|
142
|
+
|
|
143
|
+
pmApiConfig.enabled = true;
|
|
144
|
+
pmApiConfig.url = await ask(rl, 'PM API URL (leave empty to configure later)');
|
|
145
|
+
|
|
146
|
+
console.log();
|
|
147
|
+
console.log(' Feature modules:');
|
|
148
|
+
pmApiConfig.features.rewards = await confirm(rl, 'Enable rewards/penalties module?', false);
|
|
149
|
+
pmApiConfig.features.meetings = await confirm(rl, 'Enable meetings module?', true);
|
|
150
|
+
pmApiConfig.features.docs = await confirm(rl, 'Enable docs module?', true);
|
|
151
|
+
pmApiConfig.features.initiatives = await confirm(rl, 'Enable initiatives module?', true);
|
|
152
|
+
|
|
153
|
+
console.log();
|
|
154
|
+
const enableBlockchain = await confirm(rl, 'Enable blockchain integration?', false);
|
|
155
|
+
if (enableBlockchain) {
|
|
156
|
+
pmApiConfig.blockchain.enabled = true;
|
|
157
|
+
pmApiConfig.blockchain.provider = await select(rl, 'Blockchain provider:', [
|
|
158
|
+
{ label: 'TRON', value: 'tron' },
|
|
159
|
+
], 0);
|
|
160
|
+
pmApiConfig.blockchain.token_name = await ask(rl, 'Token name');
|
|
161
|
+
pmApiConfig.blockchain.contract_address = await ask(rl, 'Contract address');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
99
165
|
console.log();
|
|
100
166
|
|
|
101
167
|
// ── Phase 5: Integrations ────────────────────────
|
|
@@ -107,8 +173,9 @@ export async function runSetupWizard(targetDir, opts = {}) {
|
|
|
107
173
|
// project.yaml
|
|
108
174
|
const projectYaml = buildProjectYaml({
|
|
109
175
|
projectName, tagline, projectType,
|
|
110
|
-
domains, devScope, integrations, specSiteConfig,
|
|
176
|
+
domains, devScope, integrations, specSiteConfig, pmApiConfig,
|
|
111
177
|
platform: opts.platform || null,
|
|
178
|
+
industryPreset,
|
|
112
179
|
});
|
|
113
180
|
const contextDir = join(targetDir, '.context');
|
|
114
181
|
await mkdir(contextDir, { recursive: true });
|
|
@@ -321,7 +388,7 @@ export const ALL_INTEGRATION_PROVIDERS = [
|
|
|
321
388
|
'sqlite_lambda',
|
|
322
389
|
];
|
|
323
390
|
|
|
324
|
-
function buildProjectYaml({ projectName, tagline, projectType, domains, devScope, integrations, specSiteConfig, platform }) {
|
|
391
|
+
function buildProjectYaml({ projectName, tagline, projectType, domains, devScope, integrations, specSiteConfig, pmApiConfig, platform, industryPreset }) {
|
|
325
392
|
// Build the full integrations block with all known providers
|
|
326
393
|
const integrationsBlock = {};
|
|
327
394
|
|
|
@@ -338,6 +405,7 @@ function buildProjectYaml({ projectName, tagline, projectType, domains, devScope
|
|
|
338
405
|
name: projectName,
|
|
339
406
|
tagline: tagline || '',
|
|
340
407
|
type: projectType,
|
|
408
|
+
...(industryPreset || {}),
|
|
341
409
|
},
|
|
342
410
|
problem: {
|
|
343
411
|
core: '',
|
|
@@ -382,6 +450,7 @@ function buildProjectYaml({ projectName, tagline, projectType, domains, devScope
|
|
|
382
450
|
deploy_url: '',
|
|
383
451
|
backend: specSiteConfig.backend,
|
|
384
452
|
},
|
|
453
|
+
pm_api: pmApiConfig || { enabled: false },
|
|
385
454
|
},
|
|
386
455
|
_meta: {
|
|
387
456
|
created_at: new Date().toISOString(),
|
package/package.json
CHANGED
|
@@ -70,6 +70,18 @@ read_only: true | false # Whether this agent can modify files
|
|
|
70
70
|
- Definition of evidence (file:line, data, URL, etc.)
|
|
71
71
|
- BAD → GOOD transformation example
|
|
72
72
|
|
|
73
|
+
### 13.5. Evidence Requirements (MANDATORY for data-consuming agents)
|
|
74
|
+
- All PASS/FAIL verdicts must include: data source, measurement period, sample size
|
|
75
|
+
- Structured evidence table format (Item | Verdict | Evidence)
|
|
76
|
+
- Numerical recording principle: both absolute values and change rates
|
|
77
|
+
- Anti-patterns: no subjective judgments, no conclusions without data sources, no one-sided measurements
|
|
78
|
+
|
|
79
|
+
### 13.6. Surface → Hidden Need Pattern (MANDATORY for customer-facing agents)
|
|
80
|
+
- Surface complaint is never the real problem
|
|
81
|
+
- Every VOC must follow: Surface → Hidden Need → Root Cause → Hypothesis pipeline
|
|
82
|
+
- Hidden Need must have 2+ supporting quotes
|
|
83
|
+
- Output must end with IF/THEN/BECAUSE hypothesis proposal
|
|
84
|
+
|
|
73
85
|
### 14. Context Budget (MANDATORY)
|
|
74
86
|
- Files to skip
|
|
75
87
|
- Reading strategy by file size (200+ lines → partial read)
|
|
@@ -90,6 +102,8 @@ read_only: true | false # Whether this agent can modify files
|
|
|
90
102
|
| Few-shot Examples | 2+ Good/Bad pairs | Bad must be a realistic failure, not a strawman |
|
|
91
103
|
| Final Checklist | 5-7 Yes/No items | Answerable without additional context |
|
|
92
104
|
| Evidence Principle | Declaration + 1 example | Must include BAD→GOOD transformation |
|
|
105
|
+
| Evidence Requirements | Structured table format | Data source + period + numbers for every verdict |
|
|
106
|
+
| Hidden Need Pattern | Surface → Hidden Need → Hypothesis | 2+ quotes supporting hidden need |
|
|
93
107
|
| Context Budget | 3+ rules | Must include "what to skip" guidance |
|
|
94
108
|
|
|
95
109
|
---
|
|
@@ -326,7 +326,7 @@ GOOD: "M1 retention: 45% (Jul) → 35% (Oct). N=23→46 signups per month. Trend
|
|
|
326
326
|
| Document | Path | Content |
|
|
327
327
|
|----------|------|---------|
|
|
328
328
|
| **Full DB Overview** | `global/database/index.md` | ERD, table categories, query guide |
|
|
329
|
-
| **Domain Detail** | `
|
|
329
|
+
| **Domain Detail** | `{{project.example_data_path}}` | Domain-specific detailed schema, ETL flows |
|
|
330
330
|
|
|
331
331
|
### Pre-Query Checklist
|
|
332
332
|
```
|
|
@@ -351,12 +351,12 @@ Files Danny **must** read upon activation:
|
|
|
351
351
|
|
|
352
352
|
### Domain-Specific Load (During Work)
|
|
353
353
|
```
|
|
354
|
-
When working on domain analysis →
|
|
354
|
+
When working on domain analysis → {{project.example_data_path}} (domain-specific detailed schema)
|
|
355
355
|
```
|
|
356
356
|
|
|
357
357
|
---
|
|
358
358
|
|
|
359
359
|
*Reference Context*: `global/database/index.md`, `global/metrics.md`, `global/strategy.md`
|
|
360
|
-
*Domain Context*: `
|
|
360
|
+
*Domain Context*: `{{project.example_data_path}}`
|
|
361
361
|
*Tools*: {{INTEGRATION_TOOLS_FOOTER}}
|
|
362
362
|
*Connected Agents*: 🎯 Simon (insight delivery), 📊 Vicky (deep analysis request), 📋 Penny (execution rationale), 📡 Tara (tracking ready notification + data quality issues)
|