swallowkit 1.0.0-beta.36 ā 1.0.0-beta.37
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.ja.md +84 -284
- package/README.md +85 -338
- package/dist/cli/commands/init.d.ts +7 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +135 -31
- package/dist/cli/commands/init.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/init.test.ts +21 -0
- package/src/cli/commands/init.ts +149 -38
package/src/cli/commands/init.ts
CHANGED
|
@@ -375,32 +375,136 @@ async function upgradeNextJs(projectDir: string, version: string, pm: PackageMan
|
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
async function installDependencies(projectDir: string, pm: PackageManager = 'pnpm'): Promise<void> {
|
|
378
|
+
console.log('\nš¦ Installing dependencies...\n');
|
|
379
|
+
|
|
380
|
+
const { ignoredBuilds } = await runInstallAndDetectIgnoredBuilds(projectDir, pm);
|
|
381
|
+
|
|
382
|
+
console.log('\nā
Dependencies installed\n');
|
|
383
|
+
|
|
384
|
+
if (pm === 'pnpm' && ignoredBuilds.length > 0) {
|
|
385
|
+
await maybeApproveBuilds(projectDir, ignoredBuilds);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Run `<pm> install` while passing through stdio so the user sees progress.
|
|
391
|
+
* For pnpm, also tee stdout/stderr to detect the ERR_PNPM_IGNORED_BUILDS warning
|
|
392
|
+
* and extract the affected package names.
|
|
393
|
+
*/
|
|
394
|
+
async function runInstallAndDetectIgnoredBuilds(
|
|
395
|
+
projectDir: string,
|
|
396
|
+
pm: PackageManager,
|
|
397
|
+
): Promise<{ ignoredBuilds: string[] }> {
|
|
378
398
|
return new Promise((resolve, reject) => {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
pm,
|
|
383
|
-
['install'],
|
|
384
|
-
{
|
|
399
|
+
// For npm, we don't need to detect anything ā keep simple inherit behavior.
|
|
400
|
+
if (pm !== 'pnpm') {
|
|
401
|
+
const child = spawn(pm, ['install'], {
|
|
385
402
|
cwd: projectDir,
|
|
386
403
|
stdio: 'inherit',
|
|
387
404
|
shell: true,
|
|
388
|
-
}
|
|
389
|
-
|
|
405
|
+
});
|
|
406
|
+
child.on('close', (code) => {
|
|
407
|
+
if (code !== 0) reject(new Error(`${pm} install exited with code ${code}`));
|
|
408
|
+
else resolve({ ignoredBuilds: [] });
|
|
409
|
+
});
|
|
410
|
+
child.on('error', reject);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
390
413
|
|
|
391
|
-
|
|
414
|
+
// pnpm: capture output while teeing to the user's terminal.
|
|
415
|
+
const child = spawn(pm, ['install'], {
|
|
416
|
+
cwd: projectDir,
|
|
417
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
418
|
+
shell: true,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
let combined = '';
|
|
422
|
+
child.stdout?.on('data', (chunk: Buffer) => {
|
|
423
|
+
process.stdout.write(chunk);
|
|
424
|
+
combined += chunk.toString('utf8');
|
|
425
|
+
});
|
|
426
|
+
child.stderr?.on('data', (chunk: Buffer) => {
|
|
427
|
+
process.stderr.write(chunk);
|
|
428
|
+
combined += chunk.toString('utf8');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
child.on('close', (code) => {
|
|
392
432
|
if (code !== 0) {
|
|
393
433
|
reject(new Error(`${pm} install exited with code ${code}`));
|
|
394
|
-
|
|
395
|
-
console.log('\nā
Dependencies installed\n');
|
|
396
|
-
resolve();
|
|
434
|
+
return;
|
|
397
435
|
}
|
|
436
|
+
resolve({ ignoredBuilds: parseIgnoredBuilds(combined) });
|
|
398
437
|
});
|
|
438
|
+
child.on('error', reject);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
399
441
|
|
|
400
|
-
|
|
401
|
-
|
|
442
|
+
/**
|
|
443
|
+
* Parse pnpm's `Ignored build scripts: foo@1.0.0, bar@2.0.0` warning and return
|
|
444
|
+
* the bare package names (without versions), de-duplicated.
|
|
445
|
+
*
|
|
446
|
+
* Matches both `ERR_PNPM_IGNORED_BUILDS` and the plain `Ignored build scripts:` line.
|
|
447
|
+
*/
|
|
448
|
+
export function parseIgnoredBuilds(output: string): string[] {
|
|
449
|
+
const match = output.match(/Ignored build scripts:\s*([^\n\r]+)/i);
|
|
450
|
+
if (!match) return [];
|
|
451
|
+
const list = match[1]
|
|
452
|
+
.split(',')
|
|
453
|
+
.map((entry) => entry.trim())
|
|
454
|
+
// strip version suffix: `sharp@0.34.5` -> `sharp`, `@scope/pkg@1.0.0` -> `@scope/pkg`
|
|
455
|
+
.map((entry) => entry.replace(/@[^@]+$/, ''))
|
|
456
|
+
.filter((name) => name.length > 0);
|
|
457
|
+
return Array.from(new Set(list));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
async function maybeApproveBuilds(projectDir: string, ignoredBuilds: string[]): Promise<void> {
|
|
461
|
+
console.log(
|
|
462
|
+
`\nā ļø pnpm skipped build scripts for: ${ignoredBuilds.join(', ')}\n` +
|
|
463
|
+
' These packages (e.g. sharp) need their build scripts to run correctly.\n',
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
const response = await prompts({
|
|
467
|
+
type: 'confirm',
|
|
468
|
+
name: 'approve',
|
|
469
|
+
message: 'Run `pnpm approve-builds` now to approve these build scripts?',
|
|
470
|
+
initial: true,
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
if (!response.approve) {
|
|
474
|
+
console.log(
|
|
475
|
+
'\nā¹ļø Skipped. You can run `pnpm approve-builds` later inside the project directory.\n',
|
|
476
|
+
);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
await new Promise<void>((resolve, reject) => {
|
|
481
|
+
const child = spawn('pnpm', ['approve-builds'], {
|
|
482
|
+
cwd: projectDir,
|
|
483
|
+
stdio: 'inherit',
|
|
484
|
+
shell: true,
|
|
485
|
+
});
|
|
486
|
+
child.on('close', (code) => {
|
|
487
|
+
if (code !== 0) reject(new Error(`pnpm approve-builds exited with code ${code}`));
|
|
488
|
+
else resolve();
|
|
402
489
|
});
|
|
490
|
+
child.on('error', reject);
|
|
403
491
|
});
|
|
492
|
+
|
|
493
|
+
// After approval, rebuild the approved packages so their native binaries are present.
|
|
494
|
+
await new Promise<void>((resolve, reject) => {
|
|
495
|
+
const child = spawn('pnpm', ['rebuild', ...ignoredBuilds], {
|
|
496
|
+
cwd: projectDir,
|
|
497
|
+
stdio: 'inherit',
|
|
498
|
+
shell: true,
|
|
499
|
+
});
|
|
500
|
+
child.on('close', (code) => {
|
|
501
|
+
if (code !== 0) reject(new Error(`pnpm rebuild exited with code ${code}`));
|
|
502
|
+
else resolve();
|
|
503
|
+
});
|
|
504
|
+
child.on('error', reject);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
console.log('\nā
Build scripts approved and packages rebuilt\n');
|
|
404
508
|
}
|
|
405
509
|
|
|
406
510
|
export function injectSwallowKitNextConfig(nextConfigContent: string, projectName: string): string {
|
|
@@ -876,7 +980,7 @@ export async function register() {
|
|
|
876
980
|
createReadme(projectDir, projectName, cicdChoice, azureConfig, pm, backendLanguage);
|
|
877
981
|
|
|
878
982
|
// 19. Create AI agent instruction files (AGENTS.md, CLAUDE.md, .github/copilot-instructions.md, etc.)
|
|
879
|
-
createAiAgentFiles(projectDir, projectName, backendLanguage);
|
|
983
|
+
createAiAgentFiles(projectDir, projectName, backendLanguage, pm);
|
|
880
984
|
}
|
|
881
985
|
|
|
882
986
|
async function createSharedPackage(projectDir: string, projectName: string) {
|
|
@@ -1700,9 +1804,10 @@ This project was generated by SwallowKit. If you encounter any issues or have su
|
|
|
1700
1804
|
console.log('ā
README.md created\n');
|
|
1701
1805
|
}
|
|
1702
1806
|
|
|
1703
|
-
function createAiAgentFiles(projectDir: string, projectName: string, backendLanguage: BackendLanguage) {
|
|
1807
|
+
function createAiAgentFiles(projectDir: string, projectName: string, backendLanguage: BackendLanguage, pm: PackageManager) {
|
|
1704
1808
|
console.log('š¤ Creating AI agent instruction files...\n');
|
|
1705
1809
|
const backendLanguageLabel = getBackendLanguageLabel(backendLanguage);
|
|
1810
|
+
const runCmd = pm === 'pnpm' ? 'pnpm' : 'npx';
|
|
1706
1811
|
const projectMcpConfigSource = buildSwallowKitMcpProjectConfigSource();
|
|
1707
1812
|
const functionsStructureLine = backendLanguage === 'typescript'
|
|
1708
1813
|
? `ā āāā src/ # HTTP trigger handlers with Cosmos DB bindings`
|
|
@@ -1764,11 +1869,12 @@ ${functionsStructureLine}
|
|
|
1764
1869
|
- This repository includes a project-scoped \`.mcp.json\` file that starts the locally installed SwallowKit MCP server on runtimes that auto-load project MCP configurations.
|
|
1765
1870
|
- Prefer the \`swallowkit_*\` MCP tools for framework-owned inspection, validation, and generation when they are available.
|
|
1766
1871
|
- If MCP is unavailable in your runtime, fall back to the machine CLI:
|
|
1767
|
-
-
|
|
1768
|
-
-
|
|
1769
|
-
-
|
|
1872
|
+
- \`${runCmd} swallowkit machine inspect project\`
|
|
1873
|
+
- \`${runCmd} swallowkit machine validate project\`
|
|
1874
|
+
- \`${runCmd} swallowkit machine generate scaffold <name> --api-only\`
|
|
1770
1875
|
- Do not hand-edit framework-owned artifacts when the MCP or machine interface can generate or validate them for you.
|
|
1771
1876
|
- The local MCP bootstrap depends on project dependencies already being installed.
|
|
1877
|
+
- **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
|
|
1772
1878
|
|
|
1773
1879
|
## Critical Design Principles
|
|
1774
1880
|
|
|
@@ -1887,9 +1993,9 @@ Use the SwallowKit CLI ā do **not** manually create model files or CRUD boiler
|
|
|
1887
1993
|
### Skill: Create a new data model
|
|
1888
1994
|
|
|
1889
1995
|
\`\`\`bash
|
|
1890
|
-
|
|
1996
|
+
${runCmd} swallowkit create-model <name>
|
|
1891
1997
|
# Multiple models at once:
|
|
1892
|
-
|
|
1998
|
+
${runCmd} swallowkit create-model user post comment
|
|
1893
1999
|
\`\`\`
|
|
1894
2000
|
|
|
1895
2001
|
Creates \`shared/models/<name>.ts\` with a Zod schema template including \`id\`, \`createdAt\`, \`updatedAt\`.
|
|
@@ -1898,7 +2004,7 @@ Edit the generated file to add your domain-specific fields, then run scaffold.
|
|
|
1898
2004
|
### Skill: Generate full CRUD from a model
|
|
1899
2005
|
|
|
1900
2006
|
\`\`\`bash
|
|
1901
|
-
|
|
2007
|
+
${runCmd} swallowkit scaffold shared/models/<name>.ts
|
|
1902
2008
|
\`\`\`
|
|
1903
2009
|
|
|
1904
2010
|
Generates:
|
|
@@ -1910,7 +2016,7 @@ Generates:
|
|
|
1910
2016
|
### Skill: Start development servers
|
|
1911
2017
|
|
|
1912
2018
|
\`\`\`bash
|
|
1913
|
-
|
|
2019
|
+
${runCmd} swallowkit dev
|
|
1914
2020
|
\`\`\`
|
|
1915
2021
|
|
|
1916
2022
|
Runs Next.js (http://localhost:3000) and Azure Functions (http://localhost:7071) concurrently.
|
|
@@ -1919,17 +2025,18 @@ Checks for Cosmos DB Emulator availability.
|
|
|
1919
2025
|
### Skill: Provision Azure resources
|
|
1920
2026
|
|
|
1921
2027
|
\`\`\`bash
|
|
1922
|
-
|
|
2028
|
+
${runCmd} swallowkit provision --resource-group <name> --location <region>
|
|
1923
2029
|
\`\`\`
|
|
1924
2030
|
|
|
1925
2031
|
Deploys Bicep infrastructure: Static Web Apps, Functions, Cosmos DB, Storage, Managed Identity.
|
|
1926
2032
|
|
|
1927
2033
|
### Typical workflow for "add a new feature/model"
|
|
1928
2034
|
|
|
1929
|
-
1.
|
|
2035
|
+
1. \`${runCmd} swallowkit create-model <name>\`
|
|
1930
2036
|
2. Edit \`shared/models/<name>.ts\` ā add fields
|
|
1931
|
-
3.
|
|
1932
|
-
4.
|
|
2037
|
+
3. \`${runCmd} swallowkit scaffold shared/models/<name>.ts\`
|
|
2038
|
+
4. \`${runCmd} swallowkit dev\` ā verify at http://localhost:3000/<name>
|
|
2039
|
+
5. If \`dev-seeds/\` already exists, update the seed JSON files to include realistic data for the new model and adjust existing seeds if relationships changed.
|
|
1933
2040
|
|
|
1934
2041
|
## Do NOT
|
|
1935
2042
|
|
|
@@ -1974,23 +2081,25 @@ This file is for Claude Code. Read AGENTS.md in the project root for the full ar
|
|
|
1974
2081
|
|
|
1975
2082
|
- This repository includes a project-scoped \`.mcp.json\` that registers the locally installed SwallowKit MCP server for runtimes that support project MCP files.
|
|
1976
2083
|
- When the \`swallowkit_*\` tools are available, prefer them for inspect / validate / generate tasks.
|
|
1977
|
-
- If MCP is unavailable, use
|
|
2084
|
+
- If MCP is unavailable, use \`${runCmd} swallowkit machine ...\` instead.
|
|
2085
|
+
- **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
|
|
1978
2086
|
|
|
1979
2087
|
## SwallowKit CLI Commands
|
|
1980
2088
|
|
|
1981
2089
|
| Task | Command |
|
|
1982
2090
|
|------|---------|
|
|
1983
|
-
| Create model |
|
|
1984
|
-
| Generate CRUD |
|
|
1985
|
-
| Dev servers |
|
|
1986
|
-
| Provision Azure |
|
|
2091
|
+
| Create model | \`${runCmd} swallowkit create-model <name>\` |
|
|
2092
|
+
| Generate CRUD | \`${runCmd} swallowkit scaffold shared/models/<name>.ts\` |
|
|
2093
|
+
| Dev servers | \`${runCmd} swallowkit dev\` |
|
|
2094
|
+
| Provision Azure | \`${runCmd} swallowkit provision --resource-group <rg> --location <region>\` |
|
|
1987
2095
|
|
|
1988
2096
|
## Workflow: Add a new model
|
|
1989
2097
|
|
|
1990
|
-
1.
|
|
2098
|
+
1. \`${runCmd} swallowkit create-model <name>\`
|
|
1991
2099
|
2. Edit \`shared/models/<name>.ts\` ā add your fields
|
|
1992
|
-
3.
|
|
1993
|
-
4.
|
|
2100
|
+
3. \`${runCmd} swallowkit scaffold shared/models/<name>.ts\`
|
|
2101
|
+
4. \`${runCmd} swallowkit dev\` ā verify at http://localhost:3000/<name>
|
|
2102
|
+
5. If \`dev-seeds/\` exists, update the seed JSON files to include data for the new model and adjust existing seeds if relationships changed.
|
|
1994
2103
|
`;
|
|
1995
2104
|
|
|
1996
2105
|
fs.writeFileSync(path.join(projectDir, 'CLAUDE.md'), claudeMd);
|
|
@@ -2019,13 +2128,15 @@ Frontend (Next.js App Router) ā BFF (Next.js API Routes) ā Backend (Azure Fu
|
|
|
2019
2128
|
1. **BFF is proxy only** ā \`app/api/\` routes call Azure Functions via \`callFunction()\`. No business logic, no direct DB access.
|
|
2020
2129
|
2. **Zod = single source of truth** ā Models live in \`shared/models/\`. Types are derived with \`z.infer<>\`. Never define types separately.
|
|
2021
2130
|
3. **Backend owns data** ā All CRUD and business logic stay in \`functions/\`, and generated contract assets under \`functions/generated/\` must stay aligned with \`shared/models/\`.
|
|
2022
|
-
4. **Use the CLI** ā Run
|
|
2131
|
+
4. **Use the CLI** ā Run \`${runCmd} swallowkit create-model <name>\` then \`${runCmd} swallowkit scaffold shared/models/<name>.ts\` to add models. Do not create boilerplate manually.
|
|
2132
|
+
5. **Maintain seed data** ā When adding models or changing schemas, update the JSON files under \`dev-seeds/\` to keep seed data consistent with the current schema.
|
|
2023
2133
|
|
|
2024
2134
|
## SwallowKit Framework Operations
|
|
2025
2135
|
|
|
2026
2136
|
- Prefer the SwallowKit MCP or machine interface for framework-owned inspection, validation, and generation instead of hand-editing generated files.
|
|
2027
2137
|
- If your runtime loads project-scoped MCP config from \`.mcp.json\`, use the \`swallowkit_*\` tools.
|
|
2028
|
-
- Otherwise use
|
|
2138
|
+
- Otherwise use \`${runCmd} swallowkit machine inspect project\`, \`${runCmd} swallowkit machine validate project\`, and \`${runCmd} swallowkit machine generate scaffold <name> --api-only\`.
|
|
2139
|
+
- **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
|
|
2029
2140
|
|
|
2030
2141
|
## Naming
|
|
2031
2142
|
|
|
@@ -2067,7 +2178,7 @@ Files in this directory are the **single source of truth** for data models acros
|
|
|
2067
2178
|
- Export a \`displayName\` string constant for UI display.
|
|
2068
2179
|
- Re-export every model from \`shared/index.ts\`.
|
|
2069
2180
|
- For relationships, use **nested schemas** (import and embed the related schema), not ID references.
|
|
2070
|
-
- After editing a model, run
|
|
2181
|
+
- After editing a model, run \`${runCmd} swallowkit scaffold shared/models/<name>.ts\` to regenerate CRUD code.
|
|
2071
2182
|
`;
|
|
2072
2183
|
|
|
2073
2184
|
fs.writeFileSync(
|