@cubis/foundry 0.3.12 → 0.3.14

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.
@@ -12,7 +12,7 @@ Before proceeding, validate that the user has completed the following steps befo
12
12
 
13
13
  ## Step 1
14
14
 
15
- Prompt the user to configure their own Postman API key for authentication. They can either set it as an environment variable named POSTMAN_API_KEY on their system, or hardcode it directly into the user level MCP configuration file (usually at ~/.kiro/settings/mcp.json) in the power section. To obtain an API key, they log into their Postman account, navigate to Settings API Keys, and generate a new key with appropriate permissions for workspace, collection, and environment management. The key will be automatically used by the MCP server to authenticate all API requests to Postman's services.
15
+ Generate and maintain `postman_setting.json` as the primary Postman configuration. Use env-first authentication by default: keep `apiKey` as `null`, set `apiKeyEnvVar` to `POSTMAN_API_KEY`, and read the key from environment variables. Only store `apiKey` inline when the user explicitly requests file-based key storage. Keep `defaultWorkspaceId` nullable (`null` when unknown) so workflows can run without a preselected workspace.
16
16
 
17
17
  ## Step 2
18
18
 
@@ -68,7 +68,7 @@ Create a hook that runs anytime the source code or configuration file has been c
68
68
 
69
69
  Automate API testing and collection management with Postman. Create workspaces, collections, environments, and run tests programmatically.
70
70
 
71
- **Authentication**: Requires Postman API key (Settings API Keys at postman.com)
71
+ **Authentication**: Env-first via `postman_setting.json` + `POSTMAN_API_KEY`; inline `apiKey` is optional.
72
72
 
73
73
  ## Available MCP Servers
74
74
 
@@ -10,7 +10,7 @@ Before proceeding, validate that the user has completed the following steps befo
10
10
 
11
11
  ## Step 1
12
12
 
13
- Prompt the user to configure their own Postman API key for authentication. They can either set it as an environment variable named POSTMAN_API_KEY on their system, or hardcode it directly into the user level MCP configuration file (usually at ~/.kiro/settings/mcp.json) in the power section. To obtain an API key, they log into their Postman account, navigate to Settings API Keys, and generate a new key with appropriate permissions for workspace, collection, and environment management. The key will be automatically used by the MCP server to authenticate all API requests to Postman's services.
13
+ Generate and maintain `postman_setting.json` as the primary Postman configuration. Use env-first authentication by default: keep `apiKey` as `null`, set `apiKeyEnvVar` to `POSTMAN_API_KEY`, and read the key from environment variables. Only store `apiKey` inline when the user explicitly requests file-based key storage. Keep `defaultWorkspaceId` nullable (`null` when unknown) so workflows can run without a preselected workspace.
14
14
 
15
15
  ## Step 2
16
16
 
@@ -66,7 +66,7 @@ Create a hook that runs anytime the source code or configuration file has been c
66
66
 
67
67
  Automate API testing and collection management with Postman. Create workspaces, collections, environments, and run tests programmatically.
68
68
 
69
- **Authentication**: Requires Postman API key (Settings API Keys at postman.com)
69
+ **Authentication**: Env-first via `postman_setting.json` + `POSTMAN_API_KEY`; inline `apiKey` is optional.
70
70
 
71
71
  ## Available MCP Servers
72
72
 
@@ -12,7 +12,7 @@ Before proceeding, validate that the user has completed the following steps befo
12
12
 
13
13
  ## Step 1
14
14
 
15
- Prompt the user to configure their own Postman API key for authentication. They can either set it as an environment variable named POSTMAN_API_KEY on their system, or hardcode it directly into the user level MCP configuration file (usually at ~/.kiro/settings/mcp.json) in the power section. To obtain an API key, they log into their Postman account, navigate to Settings API Keys, and generate a new key with appropriate permissions for workspace, collection, and environment management. The key will be automatically used by the MCP server to authenticate all API requests to Postman's services.
15
+ Generate and maintain `postman_setting.json` as the primary Postman configuration. Use env-first authentication by default: keep `apiKey` as `null`, set `apiKeyEnvVar` to `POSTMAN_API_KEY`, and read the key from environment variables. Only store `apiKey` inline when the user explicitly requests file-based key storage. Keep `defaultWorkspaceId` nullable (`null` when unknown) so workflows can run without a preselected workspace.
16
16
 
17
17
  ## Step 2
18
18
 
@@ -68,7 +68,7 @@ Create a hook that runs anytime the source code or configuration file has been c
68
68
 
69
69
  Automate API testing and collection management with Postman. Create workspaces, collections, environments, and run tests programmatically.
70
70
 
71
- **Authentication**: Requires Postman API key (Settings API Keys at postman.com)
71
+ **Authentication**: Env-first via `postman_setting.json` + `POSTMAN_API_KEY`; inline `apiKey` is optional.
72
72
 
73
73
  ## Available MCP Servers
74
74
 
@@ -239,4 +239,4 @@ for (const collection of collections) {
239
239
 
240
240
  **Full mode (112 tools):** Change URL to `https://mcp.postman.com/full`
241
241
 
242
- **API Key Permissions:** Workspace management, collection read/write, environment read/write, collection runs
242
+ **API Key Permissions:** Workspace management, collection read/write, environment read/write, collection runs
@@ -10,7 +10,7 @@ Before proceeding, validate that the user has completed the following steps befo
10
10
 
11
11
  ## Step 1
12
12
 
13
- Prompt the user to configure their own Postman API key for authentication. They can either set it as an environment variable named POSTMAN_API_KEY on their system, or hardcode it directly into the user level MCP configuration file (usually at ~/.kiro/settings/mcp.json) in the power section. To obtain an API key, they log into their Postman account, navigate to Settings API Keys, and generate a new key with appropriate permissions for workspace, collection, and environment management. The key will be automatically used by the MCP server to authenticate all API requests to Postman's services.
13
+ Generate and maintain `postman_setting.json` as the primary Postman configuration. Use env-first authentication by default: keep `apiKey` as `null`, set `apiKeyEnvVar` to `POSTMAN_API_KEY`, and read the key from environment variables. Only store `apiKey` inline when the user explicitly requests file-based key storage. Keep `defaultWorkspaceId` nullable (`null` when unknown) so workflows can run without a preselected workspace.
14
14
 
15
15
  ## Step 2
16
16
 
@@ -66,7 +66,7 @@ Create a hook that runs anytime the source code or configuration file has been c
66
66
 
67
67
  Automate API testing and collection management with Postman. Create workspaces, collections, environments, and run tests programmatically.
68
68
 
69
- **Authentication**: Requires Postman API key (Settings API Keys at postman.com)
69
+ **Authentication**: Env-first via `postman_setting.json` + `POSTMAN_API_KEY`; inline `apiKey` is optional.
70
70
 
71
71
  ## Available MCP Servers
72
72
 
@@ -123,98 +123,7 @@
123
123
  "testing-patterns",
124
124
  "vulnerability-scanner",
125
125
  "web-design-guidelines",
126
- "vercel-automation",
127
- "vercel-project-configuration",
128
- "vercel-git-deployments",
129
- "vercel-environments",
130
- "vercel-generated-urls",
131
- "vercel-deployment-promotion",
132
- "vercel-build-pipeline",
133
- "vercel-build-image-upgrades",
134
- "vercel-build-output-api",
135
- "vercel-monorepos",
136
- "vercel-remote-caching",
137
- "vercel-microfrontends",
138
- "vercel-multi-tenant",
139
- "vercel-functions-core",
140
- "vercel-fluid-compute",
141
- "vercel-functions-nodejs",
142
- "vercel-functions-python",
143
- "vercel-functions-edge-runtime",
144
- "vercel-edge-to-node-migration",
145
- "vercel-routing-middleware",
146
- "vercel-function-config",
147
- "vercel-runtime-cache",
148
- "vercel-data-cache-nextjs",
149
- "vercel-cron-jobs",
150
- "vercel-og-image-generation",
151
- "vercel-cdn-cache",
152
- "vercel-cache-control-headers",
153
- "vercel-isr",
154
- "vercel-image-optimization",
155
- "vercel-request-collapsing",
156
- "vercel-redirects-rewrites",
157
- "vercel-cdn-purging",
158
- "vercel-blob",
159
- "vercel-edge-config",
160
- "vercel-edge-config-integrations",
161
- "vercel-marketplace-storage-redis",
162
- "vercel-storage-migrations",
163
- "vercel-ai-sdk-core",
164
- "vercel-ai-sdk-ui",
165
- "vercel-ai-gateway-core",
166
- "vercel-ai-gateway-model-routing",
167
- "vercel-ai-gateway-fallbacks",
168
- "vercel-ai-gateway-auth-byok",
169
- "vercel-ai-gateway-observability",
170
- "vercel-ai-gateway-openai-compatible",
171
- "vercel-agent-workflows",
172
- "vercel-mcp-for-agents",
173
- "vercel-flags-platform",
174
- "vercel-flags-dashboard",
175
- "vercel-flags-sdk",
176
- "vercel-flags-openfeature",
177
- "vercel-flags-explorer",
178
- "vercel-flags-cli-workflows",
179
- "vercel-observability-overview",
180
- "vercel-runtime-logs",
181
- "vercel-tracing-otel",
182
- "vercel-session-tracing",
183
- "vercel-alerts-monitoring",
184
- "vercel-drains-setup",
185
- "vercel-log-drain-reference",
186
- "vercel-log-trace-correlation",
187
- "vercel-speed-insights",
188
- "vercel-web-analytics",
189
- "vercel-custom-events",
190
- "vercel-deployment-protection",
191
- "vercel-protection-bypass-automation",
192
- "vercel-firewall-core",
193
- "vercel-waf-custom-rules",
194
- "vercel-waf-rate-limiting",
195
- "vercel-bot-management",
196
- "vercel-botid",
197
- "vercel-secure-compute",
198
- "vercel-static-ips",
199
- "vercel-oidc-federation",
200
- "vercel-rbac-access-groups",
201
- "vercel-audit-logs",
202
- "vercel-2fa-enforcement",
203
126
  "vercel-domains",
204
- "vercel-dns-records",
205
- "vercel-nameservers",
206
- "vercel-ssl-certificates",
207
- "vercel-domain-ownership-claims",
208
- "vercel-cli-core",
209
- "vercel-cli-project-domain-env",
210
- "vercel-cli-flags",
211
- "vercel-cli-microfrontends",
212
- "vercel-cli-mcp",
213
- "vercel-rest-api",
214
- "vercel-sdk",
215
- "vercel-integrations-native",
216
- "vercel-marketplace-partner-api",
217
- "vercel-webhooks-and-checks",
218
127
  "drift-flutter",
219
128
  "database-design",
220
129
  "database-optimizer"
@@ -353,98 +262,7 @@
353
262
  "testing-patterns",
354
263
  "vulnerability-scanner",
355
264
  "web-design-guidelines",
356
- "vercel-automation",
357
- "vercel-project-configuration",
358
- "vercel-git-deployments",
359
- "vercel-environments",
360
- "vercel-generated-urls",
361
- "vercel-deployment-promotion",
362
- "vercel-build-pipeline",
363
- "vercel-build-image-upgrades",
364
- "vercel-build-output-api",
365
- "vercel-monorepos",
366
- "vercel-remote-caching",
367
- "vercel-microfrontends",
368
- "vercel-multi-tenant",
369
- "vercel-functions-core",
370
- "vercel-fluid-compute",
371
- "vercel-functions-nodejs",
372
- "vercel-functions-python",
373
- "vercel-functions-edge-runtime",
374
- "vercel-edge-to-node-migration",
375
- "vercel-routing-middleware",
376
- "vercel-function-config",
377
- "vercel-runtime-cache",
378
- "vercel-data-cache-nextjs",
379
- "vercel-cron-jobs",
380
- "vercel-og-image-generation",
381
- "vercel-cdn-cache",
382
- "vercel-cache-control-headers",
383
- "vercel-isr",
384
- "vercel-image-optimization",
385
- "vercel-request-collapsing",
386
- "vercel-redirects-rewrites",
387
- "vercel-cdn-purging",
388
- "vercel-blob",
389
- "vercel-edge-config",
390
- "vercel-edge-config-integrations",
391
- "vercel-marketplace-storage-redis",
392
- "vercel-storage-migrations",
393
- "vercel-ai-sdk-core",
394
- "vercel-ai-sdk-ui",
395
- "vercel-ai-gateway-core",
396
- "vercel-ai-gateway-model-routing",
397
- "vercel-ai-gateway-fallbacks",
398
- "vercel-ai-gateway-auth-byok",
399
- "vercel-ai-gateway-observability",
400
- "vercel-ai-gateway-openai-compatible",
401
- "vercel-agent-workflows",
402
- "vercel-mcp-for-agents",
403
- "vercel-flags-platform",
404
- "vercel-flags-dashboard",
405
- "vercel-flags-sdk",
406
- "vercel-flags-openfeature",
407
- "vercel-flags-explorer",
408
- "vercel-flags-cli-workflows",
409
- "vercel-observability-overview",
410
- "vercel-runtime-logs",
411
- "vercel-tracing-otel",
412
- "vercel-session-tracing",
413
- "vercel-alerts-monitoring",
414
- "vercel-drains-setup",
415
- "vercel-log-drain-reference",
416
- "vercel-log-trace-correlation",
417
- "vercel-speed-insights",
418
- "vercel-web-analytics",
419
- "vercel-custom-events",
420
- "vercel-deployment-protection",
421
- "vercel-protection-bypass-automation",
422
- "vercel-firewall-core",
423
- "vercel-waf-custom-rules",
424
- "vercel-waf-rate-limiting",
425
- "vercel-bot-management",
426
- "vercel-botid",
427
- "vercel-secure-compute",
428
- "vercel-static-ips",
429
- "vercel-oidc-federation",
430
- "vercel-rbac-access-groups",
431
- "vercel-audit-logs",
432
- "vercel-2fa-enforcement",
433
265
  "vercel-domains",
434
- "vercel-dns-records",
435
- "vercel-nameservers",
436
- "vercel-ssl-certificates",
437
- "vercel-domain-ownership-claims",
438
- "vercel-cli-core",
439
- "vercel-cli-project-domain-env",
440
- "vercel-cli-flags",
441
- "vercel-cli-microfrontends",
442
- "vercel-cli-mcp",
443
- "vercel-rest-api",
444
- "vercel-sdk",
445
- "vercel-integrations-native",
446
- "vercel-marketplace-partner-api",
447
- "vercel-webhooks-and-checks",
448
266
  "drift-flutter",
449
267
  "database-design",
450
268
  "database-optimizer"
@@ -583,98 +401,7 @@
583
401
  "testing-patterns",
584
402
  "vulnerability-scanner",
585
403
  "web-design-guidelines",
586
- "vercel-automation",
587
- "vercel-project-configuration",
588
- "vercel-git-deployments",
589
- "vercel-environments",
590
- "vercel-generated-urls",
591
- "vercel-deployment-promotion",
592
- "vercel-build-pipeline",
593
- "vercel-build-image-upgrades",
594
- "vercel-build-output-api",
595
- "vercel-monorepos",
596
- "vercel-remote-caching",
597
- "vercel-microfrontends",
598
- "vercel-multi-tenant",
599
- "vercel-functions-core",
600
- "vercel-fluid-compute",
601
- "vercel-functions-nodejs",
602
- "vercel-functions-python",
603
- "vercel-functions-edge-runtime",
604
- "vercel-edge-to-node-migration",
605
- "vercel-routing-middleware",
606
- "vercel-function-config",
607
- "vercel-runtime-cache",
608
- "vercel-data-cache-nextjs",
609
- "vercel-cron-jobs",
610
- "vercel-og-image-generation",
611
- "vercel-cdn-cache",
612
- "vercel-cache-control-headers",
613
- "vercel-isr",
614
- "vercel-image-optimization",
615
- "vercel-request-collapsing",
616
- "vercel-redirects-rewrites",
617
- "vercel-cdn-purging",
618
- "vercel-blob",
619
- "vercel-edge-config",
620
- "vercel-edge-config-integrations",
621
- "vercel-marketplace-storage-redis",
622
- "vercel-storage-migrations",
623
- "vercel-ai-sdk-core",
624
- "vercel-ai-sdk-ui",
625
- "vercel-ai-gateway-core",
626
- "vercel-ai-gateway-model-routing",
627
- "vercel-ai-gateway-fallbacks",
628
- "vercel-ai-gateway-auth-byok",
629
- "vercel-ai-gateway-observability",
630
- "vercel-ai-gateway-openai-compatible",
631
- "vercel-agent-workflows",
632
- "vercel-mcp-for-agents",
633
- "vercel-flags-platform",
634
- "vercel-flags-dashboard",
635
- "vercel-flags-sdk",
636
- "vercel-flags-openfeature",
637
- "vercel-flags-explorer",
638
- "vercel-flags-cli-workflows",
639
- "vercel-observability-overview",
640
- "vercel-runtime-logs",
641
- "vercel-tracing-otel",
642
- "vercel-session-tracing",
643
- "vercel-alerts-monitoring",
644
- "vercel-drains-setup",
645
- "vercel-log-drain-reference",
646
- "vercel-log-trace-correlation",
647
- "vercel-speed-insights",
648
- "vercel-web-analytics",
649
- "vercel-custom-events",
650
- "vercel-deployment-protection",
651
- "vercel-protection-bypass-automation",
652
- "vercel-firewall-core",
653
- "vercel-waf-custom-rules",
654
- "vercel-waf-rate-limiting",
655
- "vercel-bot-management",
656
- "vercel-botid",
657
- "vercel-secure-compute",
658
- "vercel-static-ips",
659
- "vercel-oidc-federation",
660
- "vercel-rbac-access-groups",
661
- "vercel-audit-logs",
662
- "vercel-2fa-enforcement",
663
404
  "vercel-domains",
664
- "vercel-dns-records",
665
- "vercel-nameservers",
666
- "vercel-ssl-certificates",
667
- "vercel-domain-ownership-claims",
668
- "vercel-cli-core",
669
- "vercel-cli-project-domain-env",
670
- "vercel-cli-flags",
671
- "vercel-cli-microfrontends",
672
- "vercel-cli-mcp",
673
- "vercel-rest-api",
674
- "vercel-sdk",
675
- "vercel-integrations-native",
676
- "vercel-marketplace-partner-api",
677
- "vercel-webhooks-and-checks",
678
405
  "drift-flutter",
679
406
  "database-design",
680
407
  "database-optimizer"
@@ -3,7 +3,7 @@ name: backend-specialist
3
3
  description: Expert backend architect for Node.js, Python, and modern serverless/edge systems. Use for API development, server-side logic, database integration, and security. Triggers on backend, server, api, endpoint, database, auth.
4
4
  tools: Read, Grep, Glob, Bash, Edit, Write
5
5
  model: inherit
6
- skills: clean-code, nodejs-best-practices, python-patterns, api-patterns, database-design, database-optimizer, database-skills, mcp-builder, lint-and-validate, powershell-windows, bash-linux, rust-pro, api-designer, architecture-designer, typescript-pro, nestjs-expert, fastapi-expert, secure-code-guardian, test-master
6
+ skills: clean-code, nodejs-best-practices, python-patterns, api-patterns, openapi-docs, database-design, database-optimizer, database-skills, mcp-builder, lint-and-validate, powershell-windows, bash-linux, rust-pro, api-designer, architecture-designer, typescript-pro, nestjs-expert, fastapi-expert, secure-code-guardian, test-master
7
7
  ---
8
8
 
9
9
  # Backend Development Architect
@@ -14,4 +14,14 @@ Use this workflow when backend architecture or implementation is primary.
14
14
  1. Ask `@backend-specialist` for solution outline.
15
15
  2. Validate API contracts, data model, and failure handling.
16
16
  3. Implement backend changes with tests and observability.
17
- 4. Return summary including migration and rollout notes.
17
+ 4. Always update API docs: OpenAPI spec, Swagger UI route, and Stoplight Elements route/component.
18
+ 5. Return summary including migration and rollout notes.
19
+
20
+ ## Output Contract
21
+ - API/contract changes
22
+ - OpenAPI spec path
23
+ - Swagger UI route
24
+ - Stoplight route/component status
25
+ - Migration impact
26
+ - Reliability/security notes
27
+ - Verification evidence
@@ -3,7 +3,7 @@ name: backend-specialist
3
3
  description: Expert backend architect for Node.js, Python, and modern serverless/edge systems. Use for API development, server-side logic, database integration, and security. Triggers on backend, server, api, endpoint, database, auth.
4
4
  tools: Read, Grep, Glob, Bash, Edit, Write
5
5
  model: inherit
6
- skills: clean-code, nodejs-best-practices, python-patterns, api-patterns, database-design, database-optimizer, database-skills, mcp-builder, lint-and-validate, powershell-windows, bash-linux, rust-pro, api-designer, architecture-designer, typescript-pro, nestjs-expert, fastapi-expert, secure-code-guardian, test-master
6
+ skills: clean-code, nodejs-best-practices, python-patterns, api-patterns, openapi-docs, database-design, database-optimizer, database-skills, mcp-builder, lint-and-validate, powershell-windows, bash-linux, rust-pro, api-designer, architecture-designer, typescript-pro, nestjs-expert, fastapi-expert, secure-code-guardian, test-master
7
7
  ---
8
8
 
9
9
  # Backend Development Architect
@@ -16,10 +16,14 @@ Use this when backend architecture or service logic is primary.
16
16
  1. Ask specialist(s) for design and risk assessment.
17
17
  2. Validate contracts, data model, and failure handling.
18
18
  3. Implement backend changes with observability.
19
- 4. Run targeted tests and summarize rollout notes.
19
+ 4. Always update API docs: OpenAPI spec, Swagger UI route, and Stoplight Elements route/component.
20
+ 5. Run targeted tests and summarize rollout notes.
20
21
 
21
22
  ## Output Contract
22
23
  - API/contract changes
24
+ - OpenAPI spec path
25
+ - Swagger UI route
26
+ - Stoplight route/component status
23
27
  - Migration impact
24
28
  - Reliability/security notes
25
29
  - Verification evidence
@@ -2,7 +2,7 @@
2
2
  name: backend-specialist
3
3
  description: Expert backend architect for Node.js, Python, and modern serverless/edge systems. Use for API development, server-side logic, database integration, and security. Triggers on backend, server, api, endpoint, database, auth.
4
4
  tools: Read, Grep, Glob, Bash, Edit, Write
5
- skills: clean-code, nodejs-best-practices, python-patterns, api-patterns, database-design, database-optimizer, database-skills, mcp-builder, lint-and-validate, powershell-windows, bash-linux, rust-pro, api-designer, architecture-designer, typescript-pro, nestjs-expert, fastapi-expert, secure-code-guardian, test-master
5
+ skills: clean-code, nodejs-best-practices, python-patterns, api-patterns, openapi-docs, database-design, database-optimizer, database-skills, mcp-builder, lint-and-validate, powershell-windows, bash-linux, rust-pro, api-designer, architecture-designer, typescript-pro, nestjs-expert, fastapi-expert, secure-code-guardian, test-master
6
6
  ---
7
7
 
8
8
  # Backend Development Architect
@@ -16,10 +16,14 @@ Use this when backend architecture or service logic is primary.
16
16
  1. Ask specialist(s) for design and risk assessment.
17
17
  2. Validate contracts, data model, and failure handling.
18
18
  3. Implement backend changes with observability.
19
- 4. Run targeted tests and summarize rollout notes.
19
+ 4. Always update API docs: OpenAPI spec, Swagger UI route, and Stoplight Elements route/component.
20
+ 5. Run targeted tests and summarize rollout notes.
20
21
 
21
22
  ## Output Contract
22
23
  - API/contract changes
24
+ - OpenAPI spec path
25
+ - Swagger UI route
26
+ - Stoplight route/component status
23
27
  - Migration impact
24
28
  - Reliability/security notes
25
29
  - Verification evidence
package/README.md CHANGED
@@ -34,8 +34,15 @@ cbx workflows doctor codex
34
34
  cbx workflows platforms
35
35
  cbx workflows install --platform antigravity --dry-run
36
36
  cbx workflows install --platform antigravity --terminal-integration --terminal-verifier codex
37
+ cbx workflows install --platform codex --postman
38
+ cbx workflows install --platform codex --postman --postman-workspace-id null
37
39
  ```
38
40
 
41
+ Install bootstrap behavior:
42
+ - `cbx workflows install` now also bootstraps `ENGINEERING_RULES.md` and `TECH.md` (creates when missing; keeps existing files unless explicitly regenerated).
43
+ - Optional `--postman` bootstrap creates `postman_setting.json` and installs/configures the Postman skill.
44
+ - Use `cbx rules init --platform <platform> --overwrite` to force-regenerate both files.
45
+
39
46
  `rules` manages strict engineering policy and a generated codebase tech map:
40
47
 
41
48
  ```bash
@@ -108,6 +115,7 @@ Routing behavior:
108
115
  - Antigravity/Copilot: workflow + agent markdown can be routed by platform conventions.
109
116
  - Codex: use generated callable wrapper skills (`$workflow-*`, `$agent-*`).
110
117
  - Example for backend intent in Codex: `$workflow-backend` or `$agent-backend-specialist`.
118
+ - Backend workflow policy: always include OpenAPI updates plus Swagger UI and Stoplight Elements status in output.
111
119
 
112
120
  ### Codex Runtime Mode
113
121
 
package/bin/cubis.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { confirm, select } from "@inquirer/prompts";
3
+ import { confirm, input, select } from "@inquirer/prompts";
4
4
  import { Command } from "commander";
5
5
  import { existsSync } from "node:fs";
6
6
  import {
@@ -122,6 +122,12 @@ const CODEX_WORKFLOW_SKILL_PREFIX = "workflow-";
122
122
  const CODEX_AGENT_SKILL_PREFIX = "agent-";
123
123
  const TERMINAL_VERIFIER_PROVIDERS = ["codex", "gemini"];
124
124
  const DEFAULT_TERMINAL_VERIFIER = "codex";
125
+ const POSTMAN_API_KEY_ENV_VAR = "POSTMAN_API_KEY";
126
+ const POSTMAN_MCP_URL = "https://mcp.postman.com/minimal";
127
+ const POSTMAN_SKILL_ID = "postman";
128
+ const POSTMAN_SETTINGS_FILENAME = "postman_setting.json";
129
+ const POSTMAN_API_KEY_MISSING_WARNING =
130
+ `Postman API key is not configured. Set ${POSTMAN_API_KEY_ENV_VAR} or update ${POSTMAN_SETTINGS_FILENAME}.`;
125
131
  const TECH_SCAN_MAX_FILES = 5000;
126
132
  const TECH_SCAN_IGNORED_DIRS = new Set([
127
133
  ".git",
@@ -231,6 +237,13 @@ function normalizeTerminalVerifier(value) {
231
237
  return TERMINAL_VERIFIER_ALIASES[normalized] || null;
232
238
  }
233
239
 
240
+ function normalizePostmanWorkspaceId(value) {
241
+ if (value === undefined || value === null) return null;
242
+ const normalized = String(value).trim();
243
+ if (!normalized || normalized.toLowerCase() === "null") return null;
244
+ return normalized;
245
+ }
246
+
234
247
  function defaultState() {
235
248
  return {
236
249
  schemaVersion: 1,
@@ -1872,6 +1885,237 @@ async function writeGeneratedArtifact({ destination, content, dryRun = false })
1872
1885
  return { action: exists ? "replaced" : "installed", path: destination };
1873
1886
  }
1874
1887
 
1888
+ function resolvePostmanSettingsPath({ scope, cwd = process.cwd() }) {
1889
+ if (scope === "global") {
1890
+ return path.join(os.homedir(), ".cbx", POSTMAN_SETTINGS_FILENAME);
1891
+ }
1892
+ const workspaceRoot = findWorkspaceRoot(cwd);
1893
+ return path.join(workspaceRoot, POSTMAN_SETTINGS_FILENAME);
1894
+ }
1895
+
1896
+ function buildPostmanMcpConfig({ apiKey = null, mcpUrl = POSTMAN_MCP_URL }) {
1897
+ const authHeader = apiKey
1898
+ ? `Bearer ${apiKey}`
1899
+ : `Bearer \${${POSTMAN_API_KEY_ENV_VAR}}`;
1900
+ return {
1901
+ mcpServers: {
1902
+ postman: {
1903
+ url: mcpUrl,
1904
+ headers: {
1905
+ Authorization: authHeader
1906
+ }
1907
+ }
1908
+ },
1909
+ disabled: false
1910
+ };
1911
+ }
1912
+
1913
+ function getPostmanApiKeySource({ apiKey, envApiKey }) {
1914
+ if (apiKey) return "inline";
1915
+ if (envApiKey) return "env";
1916
+ return "unset";
1917
+ }
1918
+
1919
+ function normalizePostmanApiKey(value) {
1920
+ if (value === undefined || value === null) return null;
1921
+ const normalized = String(value).trim();
1922
+ return normalized || null;
1923
+ }
1924
+
1925
+ async function ensureGitIgnoreEntry({
1926
+ filePath,
1927
+ entry,
1928
+ dryRun = false
1929
+ }) {
1930
+ const exists = await pathExists(filePath);
1931
+ const original = exists ? await readFile(filePath, "utf8") : "";
1932
+ const lines = original.split(/\r?\n/).map((line) => line.trim());
1933
+ const alreadyPresent = lines.includes(entry);
1934
+
1935
+ if (alreadyPresent) {
1936
+ return { action: "unchanged", filePath };
1937
+ }
1938
+
1939
+ if (dryRun) {
1940
+ return {
1941
+ action: exists ? "would-patch" : "would-create",
1942
+ filePath
1943
+ };
1944
+ }
1945
+
1946
+ const suffix = original.endsWith("\n") || original.length === 0 ? "" : "\n";
1947
+ const nextContent = `${original}${suffix}${entry}\n`;
1948
+ await mkdir(path.dirname(filePath), { recursive: true });
1949
+ await writeFile(filePath, nextContent, "utf8");
1950
+ return {
1951
+ action: exists ? "patched" : "created",
1952
+ filePath
1953
+ };
1954
+ }
1955
+
1956
+ async function resolvePostmanInstallSelection({
1957
+ scope,
1958
+ options,
1959
+ cwd = process.cwd()
1960
+ }) {
1961
+ const hasApiKeyOption = options.postmanApiKey !== undefined;
1962
+ const hasWorkspaceOption = options.postmanWorkspaceId !== undefined;
1963
+ const enabled = Boolean(options.postman) || hasApiKeyOption || hasWorkspaceOption;
1964
+ if (!enabled) return { enabled: false };
1965
+
1966
+ const explicitApiKey = hasApiKeyOption ? String(options.postmanApiKey || "").trim() : "";
1967
+ let apiKey = explicitApiKey || null;
1968
+ const envApiKey = String(process.env[POSTMAN_API_KEY_ENV_VAR] || "").trim();
1969
+ let defaultWorkspaceId = hasWorkspaceOption
1970
+ ? normalizePostmanWorkspaceId(options.postmanWorkspaceId)
1971
+ : null;
1972
+ const warnings = [];
1973
+
1974
+ const canPrompt = !options.yes && process.stdin.isTTY;
1975
+ if (canPrompt && !hasApiKeyOption && !apiKey && !envApiKey) {
1976
+ const promptedApiKey = String(
1977
+ await input({
1978
+ message: `Postman API key (optional, leave blank to keep ${POSTMAN_API_KEY_ENV_VAR} env mode):`,
1979
+ default: ""
1980
+ })
1981
+ ).trim();
1982
+ if (promptedApiKey) {
1983
+ apiKey = promptedApiKey;
1984
+ }
1985
+ }
1986
+
1987
+ if (canPrompt && !hasWorkspaceOption) {
1988
+ const promptedWorkspaceId = await input({
1989
+ message: "Default Postman workspace ID (optional, leave blank for null):",
1990
+ default: ""
1991
+ });
1992
+ defaultWorkspaceId = normalizePostmanWorkspaceId(promptedWorkspaceId);
1993
+ }
1994
+
1995
+ const apiKeySource = getPostmanApiKeySource({ apiKey, envApiKey });
1996
+ if (apiKeySource === "unset") {
1997
+ warnings.push(POSTMAN_API_KEY_MISSING_WARNING);
1998
+ }
1999
+
2000
+ const settingsPath = resolvePostmanSettingsPath({ scope, cwd });
2001
+ const settings = {
2002
+ apiKey: apiKey || null,
2003
+ apiKeyEnvVar: POSTMAN_API_KEY_ENV_VAR,
2004
+ apiKeySource,
2005
+ defaultWorkspaceId: defaultWorkspaceId ?? null,
2006
+ mcpUrl: POSTMAN_MCP_URL,
2007
+ generatedBy: "cbx workflows install --postman",
2008
+ generatedAt: new Date().toISOString()
2009
+ };
2010
+
2011
+ return {
2012
+ enabled: true,
2013
+ apiKey,
2014
+ apiKeySource,
2015
+ defaultWorkspaceId: defaultWorkspaceId ?? null,
2016
+ warnings,
2017
+ settings,
2018
+ settingsPath
2019
+ };
2020
+ }
2021
+
2022
+ async function configurePostmanInstallArtifacts({
2023
+ scope,
2024
+ profilePaths,
2025
+ postmanSelection,
2026
+ overwrite = false,
2027
+ dryRun = false,
2028
+ cwd = process.cwd()
2029
+ }) {
2030
+ if (!postmanSelection?.enabled) return null;
2031
+
2032
+ let warnings = postmanSelection.warnings.filter((warning) => warning !== POSTMAN_API_KEY_MISSING_WARNING);
2033
+ const settingsContent = `${JSON.stringify(postmanSelection.settings, null, 2)}\n`;
2034
+ const settingsResult = await writeTextFile({
2035
+ targetPath: postmanSelection.settingsPath,
2036
+ content: settingsContent,
2037
+ overwrite,
2038
+ dryRun
2039
+ });
2040
+
2041
+ let effectiveApiKey = normalizePostmanApiKey(postmanSelection.settings.apiKey);
2042
+ let effectiveDefaultWorkspaceId = postmanSelection.defaultWorkspaceId ?? null;
2043
+ let effectiveMcpUrl = postmanSelection.settings.mcpUrl || POSTMAN_MCP_URL;
2044
+
2045
+ if (settingsResult.action === "skipped" || settingsResult.action === "would-skip") {
2046
+ try {
2047
+ const existingSettingsRaw = await readFile(postmanSelection.settingsPath, "utf8");
2048
+ const existingSettings = JSON.parse(existingSettingsRaw);
2049
+ effectiveApiKey = normalizePostmanApiKey(existingSettings?.apiKey);
2050
+ effectiveDefaultWorkspaceId = normalizePostmanWorkspaceId(existingSettings?.defaultWorkspaceId);
2051
+ const existingMcpUrl = String(existingSettings?.mcpUrl || "").trim();
2052
+ if (existingMcpUrl) {
2053
+ effectiveMcpUrl = existingMcpUrl;
2054
+ }
2055
+ } catch {
2056
+ warnings.push(
2057
+ `Existing ${POSTMAN_SETTINGS_FILENAME} could not be parsed. Using install-time Postman values for MCP config.`
2058
+ );
2059
+ }
2060
+ }
2061
+
2062
+ const envApiKey = normalizePostmanApiKey(process.env[POSTMAN_API_KEY_ENV_VAR]);
2063
+ const effectiveApiKeySource = getPostmanApiKeySource({
2064
+ apiKey: effectiveApiKey,
2065
+ envApiKey
2066
+ });
2067
+ if (effectiveApiKeySource === "unset") {
2068
+ warnings.push(POSTMAN_API_KEY_MISSING_WARNING);
2069
+ }
2070
+
2071
+ let gitIgnoreResult = null;
2072
+ if (scope === "project") {
2073
+ const workspaceRoot = findWorkspaceRoot(cwd);
2074
+ const gitIgnorePath = path.join(workspaceRoot, ".gitignore");
2075
+ gitIgnoreResult = await ensureGitIgnoreEntry({
2076
+ filePath: gitIgnorePath,
2077
+ entry: POSTMAN_SETTINGS_FILENAME,
2078
+ dryRun
2079
+ });
2080
+ }
2081
+
2082
+ const postmanSkillDir = path.join(profilePaths.skillsDir, POSTMAN_SKILL_ID);
2083
+ const postmanMcpPath = path.join(postmanSkillDir, "mcp.json");
2084
+ let mcpResult = null;
2085
+ const postmanSkillExists = await pathExists(postmanSkillDir);
2086
+ if (!dryRun && !postmanSkillExists) {
2087
+ mcpResult = {
2088
+ action: "missing-postman-skill",
2089
+ path: postmanMcpPath
2090
+ };
2091
+ } else {
2092
+ const mcpConfigContent = `${JSON.stringify(
2093
+ buildPostmanMcpConfig({
2094
+ apiKey: effectiveApiKey,
2095
+ mcpUrl: effectiveMcpUrl
2096
+ }),
2097
+ null,
2098
+ 2
2099
+ )}\n`;
2100
+ mcpResult = await writeGeneratedArtifact({
2101
+ destination: postmanMcpPath,
2102
+ content: mcpConfigContent,
2103
+ dryRun
2104
+ });
2105
+ }
2106
+
2107
+ return {
2108
+ enabled: true,
2109
+ apiKeySource: effectiveApiKeySource,
2110
+ defaultWorkspaceId: effectiveDefaultWorkspaceId,
2111
+ warnings,
2112
+ settingsPath: postmanSelection.settingsPath,
2113
+ settingsResult,
2114
+ gitIgnoreResult,
2115
+ mcpResult
2116
+ };
2117
+ }
2118
+
1875
2119
  async function installAntigravityTerminalIntegrationArtifacts({
1876
2120
  profilePaths,
1877
2121
  provider,
@@ -2032,6 +2276,7 @@ async function installBundleArtifacts({
2032
2276
  platform,
2033
2277
  scope,
2034
2278
  overwrite,
2279
+ extraSkillIds = [],
2035
2280
  terminalVerifierSelection = null,
2036
2281
  dryRun = false,
2037
2282
  cwd = process.cwd()
@@ -2092,7 +2337,8 @@ async function installBundleArtifacts({
2092
2337
  else installed.push(destination);
2093
2338
  }
2094
2339
 
2095
- const skillIds = Array.isArray(platformSpec.skills) ? platformSpec.skills : [];
2340
+ const manifestSkillIds = Array.isArray(platformSpec.skills) ? platformSpec.skills : [];
2341
+ const skillIds = unique([...manifestSkillIds, ...extraSkillIds.filter(Boolean)]);
2096
2342
  for (const skillId of skillIds) {
2097
2343
  const source = path.join(agentAssetsRoot(), "skills", skillId);
2098
2344
  const destination = path.join(profilePaths.skillsDir, skillId);
@@ -2389,6 +2635,32 @@ function printInstallSummary({
2389
2635
  }
2390
2636
  }
2391
2637
 
2638
+ function printPostmanSetupSummary({ postmanSetup }) {
2639
+ if (!postmanSetup?.enabled) return;
2640
+
2641
+ console.log("\nPostman setup:");
2642
+ console.log(`- Settings file: ${postmanSetup.settingsResult.action} (${postmanSetup.settingsPath})`);
2643
+ console.log(`- API key source: ${postmanSetup.apiKeySource}`);
2644
+ console.log(
2645
+ `- Default workspace ID: ${postmanSetup.defaultWorkspaceId === null ? "null" : postmanSetup.defaultWorkspaceId}`
2646
+ );
2647
+ if (postmanSetup.gitIgnoreResult) {
2648
+ console.log(
2649
+ `- .gitignore (${postmanSetup.gitIgnoreResult.filePath}): ${postmanSetup.gitIgnoreResult.action}`
2650
+ );
2651
+ }
2652
+ if (postmanSetup.mcpResult) {
2653
+ console.log(`- Postman MCP config (${postmanSetup.mcpResult.path}): ${postmanSetup.mcpResult.action}`);
2654
+ }
2655
+
2656
+ if (postmanSetup.warnings.length > 0) {
2657
+ console.log("- Warnings:");
2658
+ for (const warning of postmanSetup.warnings) {
2659
+ console.log(` - ${warning}`);
2660
+ }
2661
+ }
2662
+ }
2663
+
2392
2664
  function printRemoveSummary({
2393
2665
  platform,
2394
2666
  scope,
@@ -2694,6 +2966,18 @@ function withInstallOptions(command) {
2694
2966
  return withWorkflowBaseOptions(command)
2695
2967
  .option("-b, --bundle <bundle>", "bundle id (default: agent-environment-setup)")
2696
2968
  .option("--overwrite", "overwrite existing files")
2969
+ .option(
2970
+ "--postman",
2971
+ "optional: install Postman skill and generate postman_setting.json"
2972
+ )
2973
+ .option(
2974
+ "--postman-api-key <key>",
2975
+ "optional: set Postman API key inline for generated postman_setting.json and installed Postman MCP config"
2976
+ )
2977
+ .option(
2978
+ "--postman-workspace-id <id|null>",
2979
+ "optional: set default Postman workspace ID (use 'null' for no default)"
2980
+ )
2697
2981
  .option(
2698
2982
  "--terminal-integration",
2699
2983
  "Antigravity only: enable terminal verification integration (prompts for verifier when interactive)"
@@ -2854,6 +3138,11 @@ async function runWorkflowInstall(options) {
2854
3138
  platform,
2855
3139
  options
2856
3140
  });
3141
+ const postmanSelection = await resolvePostmanInstallSelection({
3142
+ scope,
3143
+ options,
3144
+ cwd: process.cwd()
3145
+ });
2857
3146
 
2858
3147
  const installResult = await installBundleArtifacts({
2859
3148
  bundleId,
@@ -2861,6 +3150,7 @@ async function runWorkflowInstall(options) {
2861
3150
  platform,
2862
3151
  scope,
2863
3152
  overwrite: Boolean(options.overwrite),
3153
+ extraSkillIds: postmanSelection.enabled ? [POSTMAN_SKILL_ID] : [],
2864
3154
  terminalVerifierSelection,
2865
3155
  dryRun,
2866
3156
  cwd: process.cwd()
@@ -2882,6 +3172,22 @@ async function runWorkflowInstall(options) {
2882
3172
  dryRun,
2883
3173
  cwd: process.cwd()
2884
3174
  });
3175
+ const engineeringArtifactsResult = await upsertEngineeringArtifacts({
3176
+ platform,
3177
+ scope,
3178
+ overwrite: false,
3179
+ dryRun,
3180
+ skipTech: false,
3181
+ cwd: process.cwd()
3182
+ });
3183
+ const postmanSetupResult = await configurePostmanInstallArtifacts({
3184
+ scope,
3185
+ profilePaths: installResult.profilePaths,
3186
+ postmanSelection,
3187
+ overwrite: Boolean(options.overwrite),
3188
+ dryRun,
3189
+ cwd: process.cwd()
3190
+ });
2885
3191
 
2886
3192
  const terminalVerificationRuleResult =
2887
3193
  platform === "antigravity" && installResult.terminalIntegration
@@ -2918,6 +3224,13 @@ async function runWorkflowInstall(options) {
2918
3224
  dryRun
2919
3225
  });
2920
3226
  printRuleSyncResult(syncResult);
3227
+ printInstallEngineeringSummary({
3228
+ engineeringResults: engineeringArtifactsResult.engineeringResults,
3229
+ techResult: engineeringArtifactsResult.techResult
3230
+ });
3231
+ printPostmanSetupSummary({
3232
+ postmanSetup: postmanSetupResult
3233
+ });
2921
3234
  if (dryRun) {
2922
3235
  console.log("\nDry-run complete. Re-run without `--dry-run` to apply changes.");
2923
3236
  } else {
@@ -3128,6 +3441,94 @@ function printRulesInitSummary({
3128
3441
  }
3129
3442
  }
3130
3443
 
3444
+ function printInstallEngineeringSummary({ engineeringResults, techResult }) {
3445
+ console.log("\nEngineering artifacts:");
3446
+ for (const item of engineeringResults) {
3447
+ console.log(`- ENGINEERING_RULES.md: ${item.rulesFileResult.action} (${item.rulesFilePath})`);
3448
+ console.log(`- Managed engineering block (${item.ruleFilePath}): ${item.blockResult.action}`);
3449
+ if (item.blockResult.warnings.length > 0) {
3450
+ for (const warning of item.blockResult.warnings) {
3451
+ console.log(` - warning: ${warning}`);
3452
+ }
3453
+ }
3454
+ }
3455
+
3456
+ if (techResult) {
3457
+ console.log(`- TECH.md: ${techResult.action} (${techResult.filePath})`);
3458
+ console.log(`- TECH scan files: ${techResult.snapshot.scannedFiles}`);
3459
+ }
3460
+ }
3461
+
3462
+ async function upsertEngineeringArtifacts({
3463
+ platform,
3464
+ scope,
3465
+ overwrite = false,
3466
+ skipTech = false,
3467
+ dryRun = false,
3468
+ cwd = process.cwd()
3469
+ }) {
3470
+ const ruleFilePath = await resolveRuleFilePath(platform, scope, cwd);
3471
+ if (!ruleFilePath) throw new Error(`No rule file configured for platform '${platform}'.`);
3472
+
3473
+ const workspaceRoot = findWorkspaceRoot(cwd);
3474
+ const techMdPath = path.join(workspaceRoot, "TECH.md");
3475
+ const targets = [{ ruleFilePath }];
3476
+
3477
+ if (scope === "global") {
3478
+ const workspaceRuleFile = await resolveWorkspaceRuleFileForGlobalScope(platform, cwd);
3479
+ const globalRuleFile = expandPath(WORKFLOW_PROFILES[platform].global.ruleFilesByPriority[0], cwd);
3480
+ if (workspaceRuleFile && path.resolve(workspaceRuleFile) !== path.resolve(globalRuleFile)) {
3481
+ targets.push({ ruleFilePath: workspaceRuleFile });
3482
+ }
3483
+ }
3484
+
3485
+ const template = buildEngineeringRulesTemplate();
3486
+ const engineeringResults = [];
3487
+ for (const target of targets) {
3488
+ const rulesFilePath = path.join(path.dirname(target.ruleFilePath), "ENGINEERING_RULES.md");
3489
+ const rulesFileResult = await writeTextFile({
3490
+ targetPath: rulesFilePath,
3491
+ content: `${template}\n`,
3492
+ overwrite,
3493
+ dryRun
3494
+ });
3495
+ const blockResult = await upsertEngineeringRulesBlock({
3496
+ ruleFilePath: target.ruleFilePath,
3497
+ platform,
3498
+ engineeringRulesFilePath: rulesFilePath,
3499
+ techMdFilePath: techMdPath,
3500
+ dryRun
3501
+ });
3502
+ engineeringResults.push({
3503
+ ruleFilePath: target.ruleFilePath,
3504
+ rulesFilePath,
3505
+ rulesFileResult,
3506
+ blockResult
3507
+ });
3508
+ }
3509
+
3510
+ let techResult = null;
3511
+ if (!skipTech) {
3512
+ const snapshot = await collectTechSnapshot(workspaceRoot);
3513
+ const content = buildTechMd(snapshot);
3514
+ const fileResult = await writeTextFile({
3515
+ targetPath: techMdPath,
3516
+ content: `${content}\n`,
3517
+ overwrite,
3518
+ dryRun
3519
+ });
3520
+ techResult = {
3521
+ ...fileResult,
3522
+ snapshot
3523
+ };
3524
+ }
3525
+
3526
+ return {
3527
+ engineeringResults,
3528
+ techResult
3529
+ };
3530
+ }
3531
+
3131
3532
  async function runRulesInit(options) {
3132
3533
  try {
3133
3534
  const scope = normalizeScope(options.scope);
@@ -3135,68 +3536,21 @@ async function runRulesInit(options) {
3135
3536
  const overwrite = Boolean(options.overwrite);
3136
3537
  const cwd = process.cwd();
3137
3538
  const platform = await resolvePlatform(options.platform, scope, cwd);
3138
- const ruleFilePath = await resolveRuleFilePath(platform, scope, cwd);
3139
- if (!ruleFilePath) throw new Error(`No rule file configured for platform '${platform}'.`);
3140
-
3141
- const workspaceRoot = findWorkspaceRoot(cwd);
3142
- const techMdPath = path.join(workspaceRoot, "TECH.md");
3143
- const targets = [{ ruleFilePath }];
3144
-
3145
- if (scope === "global") {
3146
- const workspaceRuleFile = await resolveWorkspaceRuleFileForGlobalScope(platform, cwd);
3147
- const globalRuleFile = expandPath(WORKFLOW_PROFILES[platform].global.ruleFilesByPriority[0], cwd);
3148
- if (workspaceRuleFile && path.resolve(workspaceRuleFile) !== path.resolve(globalRuleFile)) {
3149
- targets.push({ ruleFilePath: workspaceRuleFile });
3150
- }
3151
- }
3152
-
3153
- const template = buildEngineeringRulesTemplate();
3154
- const engineeringResults = [];
3155
- for (const target of targets) {
3156
- const rulesFilePath = path.join(path.dirname(target.ruleFilePath), "ENGINEERING_RULES.md");
3157
- const rulesFileResult = await writeTextFile({
3158
- targetPath: rulesFilePath,
3159
- content: `${template}\n`,
3160
- overwrite,
3161
- dryRun
3162
- });
3163
- const blockResult = await upsertEngineeringRulesBlock({
3164
- ruleFilePath: target.ruleFilePath,
3165
- platform,
3166
- engineeringRulesFilePath: rulesFilePath,
3167
- techMdFilePath: techMdPath,
3168
- dryRun
3169
- });
3170
- engineeringResults.push({
3171
- ruleFilePath: target.ruleFilePath,
3172
- rulesFilePath,
3173
- rulesFileResult,
3174
- blockResult
3175
- });
3176
- }
3177
-
3178
- let techResult = null;
3179
- if (!options.skipTech) {
3180
- const snapshot = await collectTechSnapshot(workspaceRoot);
3181
- const content = buildTechMd(snapshot);
3182
- const fileResult = await writeTextFile({
3183
- targetPath: techMdPath,
3184
- content: `${content}\n`,
3185
- overwrite,
3186
- dryRun
3187
- });
3188
- techResult = {
3189
- ...fileResult,
3190
- snapshot
3191
- };
3192
- }
3539
+ const initResult = await upsertEngineeringArtifacts({
3540
+ platform,
3541
+ scope,
3542
+ overwrite,
3543
+ skipTech: Boolean(options.skipTech),
3544
+ dryRun,
3545
+ cwd
3546
+ });
3193
3547
 
3194
3548
  printRulesInitSummary({
3195
3549
  platform,
3196
3550
  scope,
3197
3551
  dryRun,
3198
- engineeringResults,
3199
- techResult
3552
+ engineeringResults: initResult.engineeringResults,
3553
+ techResult: initResult.techResult
3200
3554
  });
3201
3555
 
3202
3556
  if (dryRun) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubis/foundry",
3
- "version": "0.3.12",
3
+ "version": "0.3.14",
4
4
  "description": "Cubis Foundry CLI for workflow-first AI agent environments",
5
5
  "type": "module",
6
6
  "bin": {