swallowkit 1.0.0-beta.55 → 1.0.0-beta.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/dist/cli/commands/add-auth.d.ts.map +1 -1
- package/dist/cli/commands/add-auth.js +154 -157
- package/dist/cli/commands/add-auth.js.map +1 -1
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +178 -25
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/scaffold.d.ts +7 -2
- package/dist/cli/commands/scaffold.d.ts.map +1 -1
- package/dist/cli/commands/scaffold.js +111 -123
- package/dist/cli/commands/scaffold.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +127 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +8 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/operations/auth-operations.d.ts +57 -0
- package/dist/core/operations/auth-operations.d.ts.map +1 -0
- package/dist/core/operations/auth-operations.js +269 -0
- package/dist/core/operations/auth-operations.js.map +1 -0
- package/dist/core/operations/create-model.d.ts.map +1 -1
- package/dist/core/operations/create-model.js +23 -13
- package/dist/core/operations/create-model.js.map +1 -1
- package/dist/core/operations/file-session.d.ts +53 -0
- package/dist/core/operations/file-session.d.ts.map +1 -0
- package/dist/core/operations/file-session.js +195 -0
- package/dist/core/operations/file-session.js.map +1 -0
- package/dist/core/operations/provision-operations.d.ts +52 -0
- package/dist/core/operations/provision-operations.d.ts.map +1 -0
- package/dist/core/operations/provision-operations.js +211 -0
- package/dist/core/operations/provision-operations.js.map +1 -0
- package/dist/core/operations/runtime.d.ts +5 -0
- package/dist/core/operations/runtime.d.ts.map +1 -1
- package/dist/core/operations/runtime.js +23 -0
- package/dist/core/operations/runtime.js.map +1 -1
- package/dist/core/operations/scaffold-apply.d.ts +21 -0
- package/dist/core/operations/scaffold-apply.d.ts.map +1 -0
- package/dist/core/operations/scaffold-apply.js +57 -0
- package/dist/core/operations/scaffold-apply.js.map +1 -0
- package/dist/core/operations/scaffold-machine.d.ts.map +1 -1
- package/dist/core/operations/scaffold-machine.js +1 -13
- package/dist/core/operations/scaffold-machine.js.map +1 -1
- package/dist/core/operations/scaffold-plan.d.ts +43 -0
- package/dist/core/operations/scaffold-plan.d.ts.map +1 -0
- package/dist/core/operations/scaffold-plan.js +195 -0
- package/dist/core/operations/scaffold-plan.js.map +1 -0
- package/dist/core/project/artifacts.d.ts +58 -0
- package/dist/core/project/artifacts.d.ts.map +1 -0
- package/dist/core/project/artifacts.js +179 -0
- package/dist/core/project/artifacts.js.map +1 -0
- package/dist/core/project/boundaries.d.ts +50 -0
- package/dist/core/project/boundaries.d.ts.map +1 -0
- package/dist/core/project/boundaries.js +117 -0
- package/dist/core/project/boundaries.js.map +1 -0
- package/dist/core/project/drift.d.ts +29 -0
- package/dist/core/project/drift.d.ts.map +1 -0
- package/dist/core/project/drift.js +188 -0
- package/dist/core/project/drift.js.map +1 -0
- package/dist/core/project/infra.d.ts +49 -0
- package/dist/core/project/infra.d.ts.map +1 -0
- package/dist/core/project/infra.js +167 -0
- package/dist/core/project/infra.js.map +1 -0
- package/dist/core/project/state.d.ts +15 -0
- package/dist/core/project/state.d.ts.map +1 -0
- package/dist/core/project/state.js +106 -0
- package/dist/core/project/state.js.map +1 -0
- package/dist/core/project/workflows.d.ts +43 -0
- package/dist/core/project/workflows.d.ts.map +1 -0
- package/dist/core/project/workflows.js +255 -0
- package/dist/core/project/workflows.js.map +1 -0
- package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
- package/dist/core/scaffold/auth-generator.js +24 -27
- package/dist/core/scaffold/auth-generator.js.map +1 -1
- package/dist/core/scaffold/functions-generator.js +9 -9
- package/dist/core/scaffold/nextjs-generator.js +6 -6
- package/dist/core/scaffold/ui-generator.js +19 -19
- package/dist/core/scaffold/ui-generator.js.map +1 -1
- package/dist/core/verify/index.d.ts +62 -0
- package/dist/core/verify/index.d.ts.map +1 -0
- package/dist/core/verify/index.js +343 -0
- package/dist/core/verify/index.js.map +1 -0
- package/dist/machine/contracts.d.ts +8 -0
- package/dist/machine/contracts.d.ts.map +1 -1
- package/dist/machine/errors.d.ts +4 -1
- package/dist/machine/errors.d.ts.map +1 -1
- package/dist/machine/errors.js +9 -1
- package/dist/machine/errors.js.map +1 -1
- package/dist/machine/index.d.ts.map +1 -1
- package/dist/machine/index.js +350 -16
- package/dist/machine/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +202 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/functions-generator.test.ts.snap +17 -17
- package/src/__tests__/__snapshots__/nextjs-generator.test.ts.snap +6 -6
- package/src/__tests__/__snapshots__/ui-generator.test.ts.snap +11 -11
- package/src/__tests__/agent-loop-phase34.test.ts +449 -0
- package/src/__tests__/file-session.test.ts +98 -0
- package/src/__tests__/init.test.ts +50 -0
- package/src/__tests__/mcp.test.ts +113 -5
- package/src/__tests__/plan-apply.test.ts +294 -0
- package/src/cli/commands/add-auth.ts +164 -164
- package/src/cli/commands/init.ts +186 -24
- package/src/cli/commands/scaffold.ts +128 -129
- package/src/cli/index.ts +148 -2
- package/src/core/config.ts +5 -4
- package/src/core/operations/auth-operations.ts +353 -0
- package/src/core/operations/create-model.ts +25 -13
- package/src/core/operations/file-session.ts +210 -0
- package/src/core/operations/provision-operations.ts +297 -0
- package/src/core/operations/runtime.ts +23 -0
- package/src/core/operations/scaffold-apply.ts +106 -0
- package/src/core/operations/scaffold-machine.ts +2 -16
- package/src/core/operations/scaffold-plan.ts +224 -0
- package/src/core/project/artifacts.ts +205 -0
- package/src/core/project/boundaries.ts +170 -0
- package/src/core/project/drift.ts +202 -0
- package/src/core/project/infra.ts +196 -0
- package/src/core/project/state.ts +77 -0
- package/src/core/project/workflows.ts +249 -0
- package/src/core/scaffold/auth-generator.ts +24 -27
- package/src/core/scaffold/functions-generator.ts +9 -9
- package/src/core/scaffold/nextjs-generator.ts +6 -6
- package/src/core/scaffold/ui-generator.ts +19 -19
- package/src/core/verify/index.ts +392 -0
- package/src/machine/contracts.ts +16 -0
- package/src/machine/errors.ts +12 -1
- package/src/machine/index.ts +444 -15
- package/src/mcp/index.ts +198 -2
- package/src/types/index.ts +17 -0
package/src/cli/commands/init.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
getSwaAppBuildCommand,
|
|
18
18
|
} from "../../utils/package-manager";
|
|
19
19
|
import { syncProjectManifest } from "../../core/project/manifest";
|
|
20
|
+
import { writeWorkflowDocs, writeAgentSkills } from "../../core/project/workflows";
|
|
20
21
|
import {
|
|
21
22
|
buildCSharpCodegenToolManifestSource,
|
|
22
23
|
buildPythonCodegenRequirementsSource,
|
|
@@ -296,6 +297,25 @@ export async function initCommand(options: InitOptions) {
|
|
|
296
297
|
process.exit(1);
|
|
297
298
|
}
|
|
298
299
|
|
|
300
|
+
// 非対話環境でプロンプトに入るとハングするため、不足フラグを明示エラーで案内する
|
|
301
|
+
const interactive =
|
|
302
|
+
process.stdin.isTTY === true && process.stdout.isTTY === true && !process.env.CI;
|
|
303
|
+
if (!interactive) {
|
|
304
|
+
const missing: string[] = [];
|
|
305
|
+
if (!options.cicd) missing.push('--cicd <github|azure|skip>');
|
|
306
|
+
if (!options.backendLanguage) missing.push('--backend-language <typescript|csharp|python>');
|
|
307
|
+
if (!options.cosmosDbMode) missing.push('--cosmos-db-mode <freetier|serverless>');
|
|
308
|
+
if (!options.vnet) missing.push('--vnet <outbound|none>');
|
|
309
|
+
if (!options.swaPlan) missing.push('--swa-plan <free|standard>');
|
|
310
|
+
if (missing.length > 0) {
|
|
311
|
+
console.error(
|
|
312
|
+
`❌ Non-interactive environment detected. Pass all configuration flags to run init without prompts:\n` +
|
|
313
|
+
missing.map((flag) => ` ${flag}`).join('\n')
|
|
314
|
+
);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
299
319
|
// Use flag values if provided, otherwise prompt interactively
|
|
300
320
|
const cicdProvider: CiCdProvider = options.cicd || await promptCiCd();
|
|
301
321
|
const backendLanguage: BackendLanguage = options.backendLanguage || await promptBackendLanguage();
|
|
@@ -564,8 +584,9 @@ export async function withNpmLockfileSafeManifests(projectDir: string, action: (
|
|
|
564
584
|
* For pnpm, additionally tee stdout/stderr to a buffer so that if the command
|
|
565
585
|
* fails due to `ERR_PNPM_IGNORED_BUILDS`, we can:
|
|
566
586
|
* 1. detect which packages were ignored,
|
|
567
|
-
* 2.
|
|
568
|
-
* 3.
|
|
587
|
+
* 2. approve them (interactively or automatically),
|
|
588
|
+
* 3. clean-reinstall and retry — repeating if pnpm reports further ignored
|
|
589
|
+
* packages (pnpm does not always list every unapproved package at once).
|
|
569
590
|
*/
|
|
570
591
|
async function runPackageManagerCommand(
|
|
571
592
|
pm: PackageManager,
|
|
@@ -573,26 +594,48 @@ async function runPackageManagerCommand(
|
|
|
573
594
|
projectDir: string,
|
|
574
595
|
label: string,
|
|
575
596
|
): Promise<void> {
|
|
576
|
-
|
|
597
|
+
let { code, output } = await spawnAndCapture(pm, args, projectDir, pm === 'pnpm');
|
|
577
598
|
|
|
578
599
|
if (code === 0) return;
|
|
579
600
|
|
|
580
601
|
if (pm === 'pnpm') {
|
|
581
|
-
|
|
582
|
-
|
|
602
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
603
|
+
const ignoredBuilds = parseIgnoredBuilds(output);
|
|
604
|
+
if (ignoredBuilds.length === 0) break;
|
|
583
605
|
const approved = await maybeApproveBuilds(projectDir, ignoredBuilds);
|
|
584
|
-
if (approved)
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
606
|
+
if (!approved) break;
|
|
607
|
+
// 中断された install はパッケージ抽出が不完全なまま "Already up to date"
|
|
608
|
+
// と判定されることがあるため、node_modules を消して決定論的に入れ直す
|
|
609
|
+
removeWorkspaceNodeModules(projectDir);
|
|
610
|
+
const retry = await spawnAndCapture(pm, args, projectDir, true);
|
|
611
|
+
code = retry.code;
|
|
612
|
+
output = retry.output;
|
|
613
|
+
if (code === 0) return;
|
|
614
|
+
}
|
|
615
|
+
if (parseIgnoredBuilds(output).length > 0) {
|
|
616
|
+
throw new Error(
|
|
617
|
+
`${label} exited with code ${code}: pnpm still reports unapproved build scripts. ` +
|
|
618
|
+
'Run "pnpm approve-builds" inside the project, then re-run the command.'
|
|
619
|
+
);
|
|
590
620
|
}
|
|
591
621
|
}
|
|
592
622
|
|
|
593
623
|
throw new Error(`${label} exited with code ${code}`);
|
|
594
624
|
}
|
|
595
625
|
|
|
626
|
+
/** workspace root と直下パッケージの node_modules を削除する(クリーン再インストール用)。 */
|
|
627
|
+
function removeWorkspaceNodeModules(projectDir: string): void {
|
|
628
|
+
const targets = [projectDir, ...fs.readdirSync(projectDir, { withFileTypes: true })
|
|
629
|
+
.filter((entry) => entry.isDirectory() && entry.name !== 'node_modules' && !entry.name.startsWith('.'))
|
|
630
|
+
.map((entry) => path.join(projectDir, entry.name))];
|
|
631
|
+
for (const dir of targets) {
|
|
632
|
+
const nodeModules = path.join(dir, 'node_modules');
|
|
633
|
+
if (fs.existsSync(nodeModules)) {
|
|
634
|
+
fs.rmSync(nodeModules, { recursive: true, force: true });
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
596
639
|
/**
|
|
597
640
|
* Spawn a child process inheriting stdin (so interactive prompts still work)
|
|
598
641
|
* while either inheriting or capturing+teeing stdout/stderr.
|
|
@@ -651,6 +694,10 @@ export function parseIgnoredBuilds(output: string): string[] {
|
|
|
651
694
|
* Prompt the user and, if approved, run `pnpm approve-builds` followed by
|
|
652
695
|
* `pnpm rebuild <packages>`. Returns true if the user approved (regardless of
|
|
653
696
|
* which packages they actually selected inside approve-builds).
|
|
697
|
+
*
|
|
698
|
+
* In non-interactive environments (CI, coding agents, piped output) prompting
|
|
699
|
+
* would hang forever, so build scripts are approved automatically via
|
|
700
|
+
* package.json `pnpm.onlyBuiltDependencies` instead.
|
|
654
701
|
*/
|
|
655
702
|
async function maybeApproveBuilds(projectDir: string, ignoredBuilds: string[]): Promise<boolean> {
|
|
656
703
|
console.log(
|
|
@@ -658,6 +705,18 @@ async function maybeApproveBuilds(projectDir: string, ignoredBuilds: string[]):
|
|
|
658
705
|
' These packages (e.g. sharp) need their build scripts to run correctly.\n',
|
|
659
706
|
);
|
|
660
707
|
|
|
708
|
+
const interactive =
|
|
709
|
+
process.stdin.isTTY === true && process.stdout.isTTY === true && !process.env.CI;
|
|
710
|
+
if (!interactive) {
|
|
711
|
+
console.log(
|
|
712
|
+
'ℹ️ Non-interactive environment detected — approving build scripts automatically\n' +
|
|
713
|
+
' via "allowBuilds" in pnpm-workspace.yaml.\n',
|
|
714
|
+
);
|
|
715
|
+
// rebuild は不要: 呼び出し側がクリーン再インストールで build script を実行する
|
|
716
|
+
approveBuildsViaWorkspaceYaml(projectDir, ignoredBuilds);
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
|
|
661
720
|
const response = await prompts({
|
|
662
721
|
type: 'confirm',
|
|
663
722
|
name: 'approve',
|
|
@@ -679,6 +738,43 @@ async function maybeApproveBuilds(projectDir: string, ignoredBuilds: string[]):
|
|
|
679
738
|
return true;
|
|
680
739
|
}
|
|
681
740
|
|
|
741
|
+
/**
|
|
742
|
+
* pnpm-workspace.yaml の allowBuilds にパッケージを true で登録して build script を許可する。
|
|
743
|
+
* (pnpm 11+ の正準設定。失敗時に pnpm が追記する placeholder 行も true に置き換える)
|
|
744
|
+
*/
|
|
745
|
+
export function approveBuildsViaWorkspaceYaml(projectDir: string, packages: string[]): void {
|
|
746
|
+
const workspaceYamlPath = path.join(projectDir, 'pnpm-workspace.yaml');
|
|
747
|
+
const existing = fs.existsSync(workspaceYamlPath)
|
|
748
|
+
? fs.readFileSync(workspaceYamlPath, 'utf-8')
|
|
749
|
+
: '';
|
|
750
|
+
const yamlKey = (pkg: string) => (/^[A-Za-z0-9_.-]+$/.test(pkg) ? pkg : `'${pkg}'`);
|
|
751
|
+
|
|
752
|
+
const lines = existing.length > 0 ? existing.split(/\r?\n/) : [];
|
|
753
|
+
const keyIndex = lines.findIndex((line) => /^allowBuilds\s*:/.test(line));
|
|
754
|
+
|
|
755
|
+
if (keyIndex === -1) {
|
|
756
|
+
const block = `allowBuilds:\n${packages.map((pkg) => ` ${yamlKey(pkg)}: true`).join('\n')}\n`;
|
|
757
|
+
const base = existing.length > 0 && !existing.endsWith('\n') ? `${existing}\n` : existing;
|
|
758
|
+
fs.writeFileSync(workspaceYamlPath, `${base}${block}`, 'utf-8');
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// 既存マップ内の対象パッケージ(placeholder 含む)を true に更新し、無いものは追記する
|
|
763
|
+
let endIndex = keyIndex + 1;
|
|
764
|
+
const updated = new Set<string>();
|
|
765
|
+
while (endIndex < lines.length && /^\s+\S/.test(lines[endIndex])) {
|
|
766
|
+
const entry = lines[endIndex].match(/^\s+['"]?([A-Za-z0-9@/_.-]+)['"]?\s*:/);
|
|
767
|
+
if (entry && packages.includes(entry[1])) {
|
|
768
|
+
lines[endIndex] = ` ${yamlKey(entry[1])}: true`;
|
|
769
|
+
updated.add(entry[1]);
|
|
770
|
+
}
|
|
771
|
+
endIndex++;
|
|
772
|
+
}
|
|
773
|
+
const additions = packages.filter((pkg) => !updated.has(pkg)).map((pkg) => ` ${yamlKey(pkg)}: true`);
|
|
774
|
+
lines.splice(endIndex, 0, ...additions);
|
|
775
|
+
fs.writeFileSync(workspaceYamlPath, lines.join('\n'), 'utf-8');
|
|
776
|
+
}
|
|
777
|
+
|
|
682
778
|
function runSimple(command: string, args: string[], cwd: string): Promise<void> {
|
|
683
779
|
return new Promise((resolve, reject) => {
|
|
684
780
|
const child = spawn(command, args, { cwd, stdio: 'inherit', shell: true });
|
|
@@ -946,7 +1042,7 @@ function getFunctionsKeyHeaders(functionsBaseUrl: string): Record<string, string
|
|
|
946
1042
|
async function request<T>(
|
|
947
1043
|
endpoint: string,
|
|
948
1044
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
|
949
|
-
body?:
|
|
1045
|
+
body?: unknown,
|
|
950
1046
|
queryParams?: Record<string, string>
|
|
951
1047
|
): Promise<T> {
|
|
952
1048
|
const functionsBaseUrl = getFunctionsBaseUrl();
|
|
@@ -1018,14 +1114,14 @@ export const api = {
|
|
|
1018
1114
|
/**
|
|
1019
1115
|
* Make a POST request
|
|
1020
1116
|
*/
|
|
1021
|
-
post: <T>(endpoint: string, body?:
|
|
1117
|
+
post: <T>(endpoint: string, body?: unknown): Promise<T> => {
|
|
1022
1118
|
return request<T>(endpoint, 'POST', body);
|
|
1023
1119
|
},
|
|
1024
1120
|
|
|
1025
1121
|
/**
|
|
1026
1122
|
* Make a PUT request
|
|
1027
1123
|
*/
|
|
1028
|
-
put: <T>(endpoint: string, body?:
|
|
1124
|
+
put: <T>(endpoint: string, body?: unknown): Promise<T> => {
|
|
1029
1125
|
return request<T>(endpoint, 'PUT', body);
|
|
1030
1126
|
},
|
|
1031
1127
|
|
|
@@ -1086,7 +1182,7 @@ export async function register() {
|
|
|
1086
1182
|
const originalConsoleError = console.error;
|
|
1087
1183
|
const originalConsoleWarn = console.warn;
|
|
1088
1184
|
|
|
1089
|
-
console.log = function(...args:
|
|
1185
|
+
console.log = function(...args: unknown[]) {
|
|
1090
1186
|
originalConsoleLog.apply(console, args);
|
|
1091
1187
|
const message = args.map(arg =>
|
|
1092
1188
|
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
|
|
@@ -1097,7 +1193,7 @@ export async function register() {
|
|
|
1097
1193
|
});
|
|
1098
1194
|
};
|
|
1099
1195
|
|
|
1100
|
-
console.error = function(...args:
|
|
1196
|
+
console.error = function(...args: unknown[]) {
|
|
1101
1197
|
originalConsoleError.apply(console, args);
|
|
1102
1198
|
const message = args.map(arg =>
|
|
1103
1199
|
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
|
|
@@ -1108,7 +1204,7 @@ export async function register() {
|
|
|
1108
1204
|
});
|
|
1109
1205
|
};
|
|
1110
1206
|
|
|
1111
|
-
console.warn = function(...args:
|
|
1207
|
+
console.warn = function(...args: unknown[]) {
|
|
1112
1208
|
originalConsoleWarn.apply(console, args);
|
|
1113
1209
|
const message = args.map(arg =>
|
|
1114
1210
|
typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
|
|
@@ -2069,18 +2165,66 @@ ${functionsStructureLine}
|
|
|
2069
2165
|
└── .github/workflows/ # CI/CD workflows (if configured)
|
|
2070
2166
|
\`\`\`
|
|
2071
2167
|
|
|
2168
|
+
## Setup & Everyday Commands
|
|
2169
|
+
|
|
2170
|
+
\`\`\`bash
|
|
2171
|
+
${pm} install # install dependencies
|
|
2172
|
+
${runCmd} swallowkit dev # Next.js (3000) + Azure Functions (7071)
|
|
2173
|
+
${pm} run build # production build
|
|
2174
|
+
${pm} run lint # ESLint (generated code must stay error-free)
|
|
2175
|
+
${runCmd} swallowkit verify # structure / drift / typecheck (exit 1 on failure)
|
|
2176
|
+
\`\`\`
|
|
2177
|
+
|
|
2178
|
+
Run \`${runCmd} swallowkit verify\` (or \`machine verify project\`) before finishing any task.
|
|
2179
|
+
|
|
2072
2180
|
## SwallowKit MCP / Machine Workflow
|
|
2073
2181
|
|
|
2074
2182
|
- This repository includes a project-scoped \`.mcp.json\` file that resolves and starts the latest SwallowKit MCP server on each launch. Set \`SWALLOWKIT_MCP_VERSION\` in that file to pin a specific version.
|
|
2075
2183
|
- Prefer the \`swallowkit_*\` MCP tools for framework-owned inspection, validation, and generation when they are available.
|
|
2076
2184
|
- If MCP is unavailable in your runtime, fall back to the machine CLI:
|
|
2077
2185
|
- \`${runCmd} swallowkit machine inspect project\`
|
|
2186
|
+
- \`${runCmd} swallowkit machine inspect boundaries\` — responsibility boundary contract (which files you may edit freely)
|
|
2078
2187
|
- \`${runCmd} swallowkit machine validate project\`
|
|
2079
|
-
- \`${runCmd} swallowkit machine
|
|
2188
|
+
- \`${runCmd} swallowkit machine plan scaffold <name>\` → \`apply scaffold --plan <planId>\` — safe two-phase generation
|
|
2189
|
+
- \`${runCmd} swallowkit machine verify project\` → \`explain failure\` — verification loop
|
|
2080
2190
|
- Do not hand-edit framework-owned artifacts when the MCP or machine interface can generate or validate them for you.
|
|
2081
2191
|
- The MCP bootstrap uses ${pm} and requires network access when the selected version is not cached.
|
|
2082
2192
|
- **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
|
|
2083
2193
|
|
|
2194
|
+
## Autonomous Loop (Plan / Apply / Verify)
|
|
2195
|
+
|
|
2196
|
+
Machine commands return a \`status\` terminal state (\`complete\` / \`in-progress\` / \`blocked\` / \`requires-human\` / \`failed\`) and \`nextActions\`. Standard loop:
|
|
2197
|
+
|
|
2198
|
+
1. \`plan scaffold <model>\` — compute changes without writing (get \`planId\`)
|
|
2199
|
+
2. \`apply scaffold --plan <planId>\` — apply with freshness + approval checks
|
|
2200
|
+
3. \`verify project\` — structure / drift / typecheck (and project-specific checks)
|
|
2201
|
+
4. \`explain failure\` — evidence and repair actions when verification fails
|
|
2202
|
+
|
|
2203
|
+
Step-by-step runbooks live in \`.swallowkit/workflows/\` (agent-agnostic Markdown):
|
|
2204
|
+
|
|
2205
|
+
- \`.swallowkit/workflows/add-model.md\`
|
|
2206
|
+
- \`.swallowkit/workflows/modify-model.md\`
|
|
2207
|
+
- \`.swallowkit/workflows/verify-and-repair.md\`
|
|
2208
|
+
- \`.swallowkit/workflows/provision.md\`
|
|
2209
|
+
|
|
2210
|
+
The same runbooks are installed as **Agent Skills** ([agentskills.io](https://agentskills.io/) open standard) under \`.github/skills/\`:
|
|
2211
|
+
|
|
2212
|
+
| Skill | Use when |
|
|
2213
|
+
|-------|----------|
|
|
2214
|
+
| \`swallowkit-add-model\` | adding a new model / entity / CRUD feature |
|
|
2215
|
+
| \`swallowkit-modify-model\` | changing an existing schema and re-aligning artifacts |
|
|
2216
|
+
| \`swallowkit-verify-repair\` | converging to a verified state after any change |
|
|
2217
|
+
| \`swallowkit-provision\` | provisioning Azure infrastructure (human approval required) |
|
|
2218
|
+
|
|
2219
|
+
Skills-aware agents (GitHub Copilot in VS Code / CLI / cloud agent, and other agents supporting the standard) discover these automatically from their \`name\`/\`description\` and load the body on demand. If your agent does not support skills, read the equivalent runbook in \`.swallowkit/workflows/\` before performing these tasks.
|
|
2220
|
+
|
|
2221
|
+
## Responsibility Boundary (AI × Deterministic Generation)
|
|
2222
|
+
|
|
2223
|
+
- **ai-authored (write freely)**: \`shared/models/\`, business logic, custom pages/components, tests.
|
|
2224
|
+
- **deterministic (never hand-edit)**: artifacts recorded in \`.swallowkit/artifacts.json\` with \`managed\` ownership, and \`.swallowkit/\` metadata. Change the model/config and regenerate via plan/apply instead.
|
|
2225
|
+
- **shared (edit outside markers)**: \`infra/main.bicep\`, \`functions/function_app.py\`, \`shared/index.ts\`.
|
|
2226
|
+
- Full machine-readable contract: \`${runCmd} swallowkit machine inspect boundaries\`
|
|
2227
|
+
|
|
2084
2228
|
## Critical Design Principles
|
|
2085
2229
|
|
|
2086
2230
|
### 1. Next.js API Routes Are Strictly a BFF (Backend for Frontend)
|
|
@@ -2191,11 +2335,12 @@ app.http('{model}-get-all', {
|
|
|
2191
2335
|
| Cosmos DB partition key | \`/id\` (default) | Custom: \`export const partitionKey = '/field'\` |
|
|
2192
2336
|
| Bicep container file | \`infra/containers/{kebab-case}-container.bicep\` | \`infra/containers/todo-container.bicep\` |
|
|
2193
2337
|
|
|
2194
|
-
## Adding New Models (SwallowKit CLI
|
|
2338
|
+
## Adding New Models (SwallowKit CLI)
|
|
2195
2339
|
|
|
2196
2340
|
Use the SwallowKit CLI — do **not** manually create model files or CRUD boilerplate.
|
|
2341
|
+
For autonomous agents, prefer the plan/apply loop above (or the \`swallowkit-add-model\` skill); the commands below are the human-friendly equivalents.
|
|
2197
2342
|
|
|
2198
|
-
###
|
|
2343
|
+
### Create a new data model
|
|
2199
2344
|
|
|
2200
2345
|
\`\`\`bash
|
|
2201
2346
|
${runCmd} swallowkit create-model <name>
|
|
@@ -2206,7 +2351,7 @@ ${runCmd} swallowkit create-model user post comment
|
|
|
2206
2351
|
Creates \`shared/models/<name>.ts\` with a Zod schema template including \`id\`, \`createdAt\`, \`updatedAt\`.
|
|
2207
2352
|
Edit the generated file to add your domain-specific fields, then run scaffold.
|
|
2208
2353
|
|
|
2209
|
-
###
|
|
2354
|
+
### Generate full CRUD from a model
|
|
2210
2355
|
|
|
2211
2356
|
\`\`\`bash
|
|
2212
2357
|
${runCmd} swallowkit scaffold shared/models/<name>.ts
|
|
@@ -2218,7 +2363,7 @@ Generates:
|
|
|
2218
2363
|
- UI pages (\`app/<name>/page.tsx\`, detail, create, edit pages)
|
|
2219
2364
|
- Cosmos DB Bicep container config (\`infra/containers/<name>-container.bicep\`)
|
|
2220
2365
|
|
|
2221
|
-
###
|
|
2366
|
+
### Start development servers
|
|
2222
2367
|
|
|
2223
2368
|
\`\`\`bash
|
|
2224
2369
|
${runCmd} swallowkit dev
|
|
@@ -2227,7 +2372,7 @@ ${runCmd} swallowkit dev
|
|
|
2227
2372
|
Runs Next.js (http://localhost:3000) and Azure Functions (http://localhost:7071) concurrently.
|
|
2228
2373
|
Checks for Cosmos DB Emulator availability.
|
|
2229
2374
|
|
|
2230
|
-
###
|
|
2375
|
+
### Provision Azure resources
|
|
2231
2376
|
|
|
2232
2377
|
\`\`\`bash
|
|
2233
2378
|
${runCmd} swallowkit provision --resource-group <name> --location <region>
|
|
@@ -2287,6 +2432,9 @@ This file is for Claude Code. Read AGENTS.md in the project root for the full ar
|
|
|
2287
2432
|
- This repository includes a project-scoped \`.mcp.json\` that resolves and starts the latest SwallowKit MCP server on each launch. Set \`SWALLOWKIT_MCP_VERSION\` in that file to pin a specific version.
|
|
2288
2433
|
- When the \`swallowkit_*\` tools are available, prefer them for inspect / validate / generate tasks.
|
|
2289
2434
|
- If MCP is unavailable, use \`${runCmd} swallowkit machine ...\` instead.
|
|
2435
|
+
- For generation, prefer the two-phase flow: \`plan scaffold <name>\` → \`apply scaffold --plan <planId>\` → \`verify project\`. Runbooks: \`.swallowkit/workflows/\`.
|
|
2436
|
+
- Agent Skills (agentskills.io) for the same workflows live in \`.github/skills/\` (\`swallowkit-add-model\`, \`swallowkit-modify-model\`, \`swallowkit-verify-repair\`, \`swallowkit-provision\`). If your runtime does not auto-discover them, read the relevant \`SKILL.md\` before performing these tasks.
|
|
2437
|
+
- Boundary contract (what you may edit freely vs what SwallowKit regenerates): \`${runCmd} swallowkit machine inspect boundaries\`
|
|
2290
2438
|
- **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
|
|
2291
2439
|
|
|
2292
2440
|
## SwallowKit CLI Commands
|
|
@@ -2340,7 +2488,9 @@ Frontend (Next.js App Router) → BFF (Next.js API Routes) → Backend (Azure Fu
|
|
|
2340
2488
|
|
|
2341
2489
|
- Prefer the SwallowKit MCP or machine interface for framework-owned inspection, validation, and generation instead of hand-editing generated files.
|
|
2342
2490
|
- If your runtime loads project-scoped MCP config from \`.mcp.json\`, use the \`swallowkit_*\` tools.
|
|
2343
|
-
- Otherwise use \`${runCmd} swallowkit machine inspect project\`, \`${runCmd} swallowkit machine validate project\`, and \`${runCmd} swallowkit machine
|
|
2491
|
+
- Otherwise use \`${runCmd} swallowkit machine inspect project\`, \`${runCmd} swallowkit machine validate project\`, and the two-phase flow \`${runCmd} swallowkit machine plan scaffold <name>\` → \`apply scaffold --plan <planId>\` → \`verify project\`.
|
|
2492
|
+
- Agent Skills in \`.github/skills/\` (\`swallowkit-add-model\`, \`swallowkit-modify-model\`, \`swallowkit-verify-repair\`, \`swallowkit-provision\`) cover these workflows — load them when the task matches.
|
|
2493
|
+
- Boundary contract: \`${runCmd} swallowkit machine inspect boundaries\` tells you which files are free to edit and which are regenerated. Runbooks live in \`.swallowkit/workflows/\`.
|
|
2344
2494
|
- **Always invoke SwallowKit via \`${runCmd}\`.** Do not mix package manager commands.
|
|
2345
2495
|
|
|
2346
2496
|
## Naming
|
|
@@ -2476,6 +2626,17 @@ app.http('{model}-get-all', {
|
|
|
2476
2626
|
console.log(' - bff-routes.instructions.md');
|
|
2477
2627
|
console.log(' - azure-functions.instructions.md');
|
|
2478
2628
|
|
|
2629
|
+
// ── 5. .swallowkit/workflows/*.md (agent-agnostic runbooks) ────────
|
|
2630
|
+
writeWorkflowDocs(projectDir, runCmd);
|
|
2631
|
+
console.log(' ✅ .swallowkit/workflows/ (agent-agnostic autonomous-loop runbooks)');
|
|
2632
|
+
|
|
2633
|
+
// ── 6. .github/skills/<name>/SKILL.md (Agent Skills, agentskills.io) ─
|
|
2634
|
+
const skillPaths = writeAgentSkills(projectDir, runCmd);
|
|
2635
|
+
console.log(' ✅ .github/skills/ (Agent Skills — agentskills.io open standard)');
|
|
2636
|
+
for (const skillPath of skillPaths) {
|
|
2637
|
+
console.log(` - ${skillPath}`);
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2479
2640
|
console.log('\n✅ AI agent files created\n');
|
|
2480
2641
|
console.log(' Supported agents:');
|
|
2481
2642
|
console.log(' - OpenAI Codex → AGENTS.md');
|
|
@@ -2483,6 +2644,7 @@ app.http('{model}-get-all', {
|
|
|
2483
2644
|
console.log(' - Project MCP runtimes → .mcp.json');
|
|
2484
2645
|
console.log(' - GitHub Copilot → .github/copilot-instructions.md');
|
|
2485
2646
|
console.log(' - GitHub Copilot (edit) → .github/instructions/*.instructions.md');
|
|
2647
|
+
console.log(' - Skills-aware agents → .github/skills/*/SKILL.md');
|
|
2486
2648
|
console.log('');
|
|
2487
2649
|
}
|
|
2488
2650
|
|