@open-mercato/cli 0.6.4-develop.4382.1.6b4f656b77 → 0.6.4
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/.turbo/turbo-build.log +1 -1
- package/dist/agentic/guides/core.customers.md +1 -1
- package/dist/agentic/shared/AGENTS.md.template +56 -33
- package/dist/agentic/shared/ai/skills/{auto-continue-pr → om-auto-continue-pr}/SKILL.md +19 -19
- package/dist/agentic/shared/ai/skills/{auto-create-pr → om-auto-continue-pr}/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/{auto-continue-pr-loop → om-auto-continue-pr-loop}/SKILL.md +32 -32
- package/dist/agentic/shared/ai/skills/{auto-create-pr → om-auto-create-pr}/SKILL.md +24 -24
- package/dist/agentic/shared/ai/skills/{auto-fix-github → om-auto-create-pr}/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/{auto-create-pr-loop → om-auto-create-pr-loop}/SKILL.md +40 -40
- package/dist/agentic/shared/ai/skills/{auto-fix-github → om-auto-fix-github}/SKILL.md +3 -3
- package/dist/agentic/shared/ai/skills/{auto-continue-pr → om-auto-fix-github}/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/{auto-review-pr → om-auto-review-pr}/SKILL.md +5 -5
- package/dist/agentic/shared/ai/skills/{auto-review-pr → om-auto-review-pr}/STANDALONE.md +1 -1
- package/dist/agentic/shared/ai/skills/{auto-upgrade-0.4.10-to-0.5.0 → om-auto-upgrade-0.4.10-to-0.5.0}/SKILL.md +1 -1
- package/dist/agentic/shared/ai/skills/{backend-ui-design → om-backend-ui-design}/SKILL.md +2 -2
- package/dist/agentic/shared/ai/skills/{code-review → om-code-review}/SKILL.md +1 -1
- package/dist/agentic/shared/ai/skills/{code-review → om-code-review}/references/review-checklist.md +3 -0
- package/dist/agentic/shared/ai/skills/{data-model-design → om-data-model-design}/SKILL.md +4 -2
- package/dist/agentic/shared/ai/skills/{eject-and-customize → om-eject-and-customize}/SKILL.md +2 -2
- package/dist/agentic/shared/ai/skills/{implement-spec → om-implement-spec}/SKILL.md +6 -6
- package/dist/agentic/shared/ai/skills/{integration-builder → om-integration-builder}/SKILL.md +1 -1
- package/dist/agentic/shared/ai/skills/{integration-tests → om-integration-tests}/SKILL.md +1 -1
- package/dist/agentic/shared/ai/skills/{module-scaffold → om-module-scaffold}/SKILL.md +5 -3
- package/dist/agentic/shared/ai/skills/{module-scaffold → om-module-scaffold}/references/naming-conventions.md +7 -8
- package/dist/agentic/shared/ai/skills/om-prepare-issue/SKILL.md +202 -0
- package/dist/agentic/shared/ai/skills/{spec-writing → om-spec-writing}/SKILL.md +6 -6
- package/dist/agentic/shared/ai/skills/{spec-writing → om-spec-writing}/references/spec-checklist.md +3 -3
- package/dist/agentic/shared/ai/skills/{system-extension → om-system-extension}/SKILL.md +1 -1
- package/dist/agentic/shared/ai/skills/{trim-unused-modules → om-trim-unused-modules}/SKILL.md +1 -1
- package/dist/agentic/shared/ai/skills/{troubleshooter → om-troubleshooter}/SKILL.md +1 -1
- package/dist/bin.js +1 -0
- package/dist/bin.js.map +2 -2
- package/dist/lib/__integration__/TC-INT-008.spec.js +1 -1
- package/dist/lib/__integration__/TC-INT-008.spec.js.map +2 -2
- package/dist/lib/agentic-setup.js +52 -51
- package/dist/lib/agentic-setup.js.map +2 -2
- package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.meta.js +7 -0
- package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.meta.js.map +7 -0
- package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.spec.js +63 -0
- package/dist/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.spec.js.map +7 -0
- package/dist/lib/deploy/railway/env.js +98 -0
- package/dist/lib/deploy/railway/env.js.map +7 -0
- package/dist/lib/deploy/railway/graphql-client.js +99 -0
- package/dist/lib/deploy/railway/graphql-client.js.map +7 -0
- package/dist/lib/deploy/railway/index.js +1115 -0
- package/dist/lib/deploy/railway/index.js.map +7 -0
- package/dist/lib/deploy/railway/operations.js +249 -0
- package/dist/lib/deploy/railway/operations.js.map +7 -0
- package/dist/lib/deploy/railway/options.js +155 -0
- package/dist/lib/deploy/railway/options.js.map +7 -0
- package/dist/lib/deploy/railway/railway-cli.js +61 -0
- package/dist/lib/deploy/railway/railway-cli.js.map +7 -0
- package/dist/lib/deploy/railway/redaction.js +88 -0
- package/dist/lib/deploy/railway/redaction.js.map +7 -0
- package/dist/lib/deploy/railway/source.js +128 -0
- package/dist/lib/deploy/railway/source.js.map +7 -0
- package/dist/lib/deploy/railway/state.js +41 -0
- package/dist/lib/deploy/railway/state.js.map +7 -0
- package/dist/lib/deploy/railway/token.js +46 -0
- package/dist/lib/deploy/railway/token.js.map +7 -0
- package/dist/lib/deploy/railway/types.js +1 -0
- package/dist/lib/deploy/railway/types.js.map +7 -0
- package/dist/lib/generators/openapi.js +4 -0
- package/dist/lib/generators/openapi.js.map +2 -2
- package/dist/lib/testing/integration.js +57 -26
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/lib/testing/runtime-utils.js +16 -8
- package/dist/lib/testing/runtime-utils.js.map +2 -2
- package/dist/mercato.js +23 -8
- package/dist/mercato.js.map +2 -2
- package/package.json +11 -12
- package/src/bin.ts +1 -0
- package/src/lib/__integration__/TC-INT-008.spec.ts +1 -1
- package/src/lib/agentic-setup.ts +52 -51
- package/src/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.meta.ts +3 -0
- package/src/lib/deploy/railway/__integration__/TC-CLI-RAILWAY-001.spec.ts +71 -0
- package/src/lib/deploy/railway/__tests__/dry-run.test.ts +61 -0
- package/src/lib/deploy/railway/__tests__/env.test.ts +55 -0
- package/src/lib/deploy/railway/__tests__/graphql-client.test.ts +80 -0
- package/src/lib/deploy/railway/__tests__/operations.test.ts +21 -0
- package/src/lib/deploy/railway/__tests__/options.test.ts +78 -0
- package/src/lib/deploy/railway/__tests__/redaction.test.ts +62 -0
- package/src/lib/deploy/railway/__tests__/source.test.ts +130 -0
- package/src/lib/deploy/railway/__tests__/state.test.ts +24 -0
- package/src/lib/deploy/railway/__tests__/token.test.ts +39 -0
- package/src/lib/deploy/railway/env.ts +112 -0
- package/src/lib/deploy/railway/graphql-client.ts +128 -0
- package/src/lib/deploy/railway/index.ts +1454 -0
- package/src/lib/deploy/railway/operations.ts +248 -0
- package/src/lib/deploy/railway/options.ts +167 -0
- package/src/lib/deploy/railway/railway-cli.ts +65 -0
- package/src/lib/deploy/railway/redaction.ts +91 -0
- package/src/lib/deploy/railway/source.ts +143 -0
- package/src/lib/deploy/railway/state.ts +45 -0
- package/src/lib/deploy/railway/token.ts +49 -0
- package/src/lib/deploy/railway/types.ts +87 -0
- package/src/lib/generators/openapi.ts +3 -0
- package/src/lib/testing/__tests__/integration.test.ts +79 -0
- package/src/lib/testing/__tests__/runtime-utils.test.ts +45 -1
- package/src/lib/testing/integration.ts +74 -28
- package/src/lib/testing/runtime-utils.ts +17 -8
- package/src/mercato.ts +33 -8
- /package/dist/agentic/shared/ai/skills/{backend-ui-design → om-backend-ui-design}/references/ui-components.md +0 -0
- /package/dist/agentic/shared/ai/skills/{data-model-design → om-data-model-design}/references/mikro-orm-cheatsheet.md +0 -0
- /package/dist/agentic/shared/ai/skills/{integration-builder → om-integration-builder}/references/adapter-contracts.md +0 -0
- /package/dist/agentic/shared/ai/skills/{module-scaffold → om-module-scaffold}/references/navigation-patterns.md +0 -0
- /package/dist/agentic/shared/ai/skills/{spec-writing → om-spec-writing}/references/spec-template.md +0 -0
- /package/dist/agentic/shared/ai/skills/{system-extension → om-system-extension}/references/extension-contracts.md +0 -0
- /package/dist/agentic/shared/ai/skills/{troubleshooter → om-troubleshooter}/references/diagnostic-commands.md +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/cli",
|
|
3
|
-
"version": "0.6.4
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -55,25 +55,25 @@
|
|
|
55
55
|
"node": "24.x"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@mikro-orm/core": "^7.1.
|
|
59
|
-
"@mikro-orm/decorators": "^7.1.
|
|
60
|
-
"@mikro-orm/migrations": "^7.1.
|
|
61
|
-
"@mikro-orm/postgresql": "^7.1.
|
|
62
|
-
"@open-mercato/queue": "0.6.4
|
|
63
|
-
"@open-mercato/shared": "0.6.4
|
|
58
|
+
"@mikro-orm/core": "^7.1.4",
|
|
59
|
+
"@mikro-orm/decorators": "^7.1.4",
|
|
60
|
+
"@mikro-orm/migrations": "^7.1.4",
|
|
61
|
+
"@mikro-orm/postgresql": "^7.1.4",
|
|
62
|
+
"@open-mercato/queue": "0.6.4",
|
|
63
|
+
"@open-mercato/shared": "0.6.4",
|
|
64
64
|
"cross-spawn": "^7.0.6",
|
|
65
65
|
"pg": "8.21.0",
|
|
66
|
-
"semver": "^7.8.
|
|
66
|
+
"semver": "^7.8.2",
|
|
67
67
|
"testcontainers": "^12.0.1",
|
|
68
68
|
"ts-morph": "^28.0.0",
|
|
69
69
|
"tsx": "^4.22.4",
|
|
70
70
|
"typescript": "^6.0.3"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
|
-
"@open-mercato/shared": "0.6.4
|
|
73
|
+
"@open-mercato/shared": "0.6.4"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@open-mercato/shared": "0.6.4
|
|
76
|
+
"@open-mercato/shared": "0.6.4",
|
|
77
77
|
"@types/jest": "^30.0.0",
|
|
78
78
|
"jest": "^30.4.2",
|
|
79
79
|
"ts-jest": "^29.4.11"
|
|
@@ -85,6 +85,5 @@
|
|
|
85
85
|
"type": "git",
|
|
86
86
|
"url": "https://github.com/open-mercato/open-mercato",
|
|
87
87
|
"directory": "packages/cli"
|
|
88
|
-
}
|
|
89
|
-
"stableVersion": "0.6.3"
|
|
88
|
+
}
|
|
90
89
|
}
|
package/src/bin.ts
CHANGED
|
@@ -237,7 +237,7 @@ test.describe('TC-INT-008: CLI agentic init mirrors standalone scaffolding asset
|
|
|
237
237
|
expect(cursorRulesSource).toContain('sample-store')
|
|
238
238
|
|
|
239
239
|
const specWritingSkillSource = fs.readFileSync(
|
|
240
|
-
path.join(appDir, '.ai', 'skills', 'spec-writing', 'SKILL.md'),
|
|
240
|
+
path.join(appDir, '.ai', 'skills', 'om-spec-writing', 'SKILL.md'),
|
|
241
241
|
'utf8',
|
|
242
242
|
)
|
|
243
243
|
expect(specWritingSkillSource).toContain('sample-store')
|
package/src/lib/agentic-setup.ts
CHANGED
|
@@ -69,127 +69,128 @@ function generateShared(config: AgenticConfig): void {
|
|
|
69
69
|
// .ai/skills/
|
|
70
70
|
writeTemplate(
|
|
71
71
|
srcDir,
|
|
72
|
-
'ai/skills/spec-writing/SKILL.md',
|
|
73
|
-
join(targetDir, '.ai', 'skills', 'spec-writing', 'SKILL.md'),
|
|
72
|
+
'ai/skills/om-spec-writing/SKILL.md',
|
|
73
|
+
join(targetDir, '.ai', 'skills', 'om-spec-writing', 'SKILL.md'),
|
|
74
74
|
config,
|
|
75
75
|
)
|
|
76
76
|
copyFile(
|
|
77
77
|
srcDir,
|
|
78
|
-
'ai/skills/spec-writing/references/spec-template.md',
|
|
79
|
-
join(targetDir, '.ai', 'skills', 'spec-writing', 'references', 'spec-template.md'),
|
|
78
|
+
'ai/skills/om-spec-writing/references/spec-template.md',
|
|
79
|
+
join(targetDir, '.ai', 'skills', 'om-spec-writing', 'references', 'spec-template.md'),
|
|
80
80
|
)
|
|
81
81
|
copyFile(
|
|
82
82
|
srcDir,
|
|
83
|
-
'ai/skills/spec-writing/references/spec-checklist.md',
|
|
84
|
-
join(targetDir, '.ai', 'skills', 'spec-writing', 'references', 'spec-checklist.md'),
|
|
83
|
+
'ai/skills/om-spec-writing/references/spec-checklist.md',
|
|
84
|
+
join(targetDir, '.ai', 'skills', 'om-spec-writing', 'references', 'spec-checklist.md'),
|
|
85
85
|
)
|
|
86
86
|
copyFile(
|
|
87
87
|
srcDir,
|
|
88
|
-
'ai/skills/backend-ui-design/SKILL.md',
|
|
89
|
-
join(targetDir, '.ai', 'skills', 'backend-ui-design', 'SKILL.md'),
|
|
88
|
+
'ai/skills/om-backend-ui-design/SKILL.md',
|
|
89
|
+
join(targetDir, '.ai', 'skills', 'om-backend-ui-design', 'SKILL.md'),
|
|
90
90
|
)
|
|
91
91
|
copyFile(
|
|
92
92
|
srcDir,
|
|
93
|
-
'ai/skills/backend-ui-design/references/ui-components.md',
|
|
94
|
-
join(targetDir, '.ai', 'skills', 'backend-ui-design', 'references', 'ui-components.md'),
|
|
93
|
+
'ai/skills/om-backend-ui-design/references/ui-components.md',
|
|
94
|
+
join(targetDir, '.ai', 'skills', 'om-backend-ui-design', 'references', 'ui-components.md'),
|
|
95
95
|
)
|
|
96
96
|
copyFile(
|
|
97
97
|
srcDir,
|
|
98
|
-
'ai/skills/code-review/SKILL.md',
|
|
99
|
-
join(targetDir, '.ai', 'skills', 'code-review', 'SKILL.md'),
|
|
98
|
+
'ai/skills/om-code-review/SKILL.md',
|
|
99
|
+
join(targetDir, '.ai', 'skills', 'om-code-review', 'SKILL.md'),
|
|
100
100
|
)
|
|
101
101
|
copyFile(
|
|
102
102
|
srcDir,
|
|
103
|
-
'ai/skills/code-review/references/review-checklist.md',
|
|
104
|
-
join(targetDir, '.ai', 'skills', 'code-review', 'references', 'review-checklist.md'),
|
|
103
|
+
'ai/skills/om-code-review/references/review-checklist.md',
|
|
104
|
+
join(targetDir, '.ai', 'skills', 'om-code-review', 'references', 'review-checklist.md'),
|
|
105
105
|
)
|
|
106
|
-
copyFile(srcDir, 'ai/skills/integration-builder/SKILL.md', join(targetDir, '.ai', 'skills', 'integration-builder', 'SKILL.md'))
|
|
106
|
+
copyFile(srcDir, 'ai/skills/om-integration-builder/SKILL.md', join(targetDir, '.ai', 'skills', 'om-integration-builder', 'SKILL.md'))
|
|
107
107
|
copyFile(
|
|
108
108
|
srcDir,
|
|
109
|
-
'ai/skills/integration-builder/references/adapter-contracts.md',
|
|
110
|
-
join(targetDir, '.ai', 'skills', 'integration-builder', 'references', 'adapter-contracts.md'),
|
|
109
|
+
'ai/skills/om-integration-builder/references/adapter-contracts.md',
|
|
110
|
+
join(targetDir, '.ai', 'skills', 'om-integration-builder', 'references', 'adapter-contracts.md'),
|
|
111
111
|
)
|
|
112
112
|
|
|
113
113
|
copyFile(
|
|
114
114
|
srcDir,
|
|
115
|
-
'ai/skills/system-extension/SKILL.md',
|
|
116
|
-
join(targetDir, '.ai', 'skills', 'system-extension', 'SKILL.md'),
|
|
115
|
+
'ai/skills/om-system-extension/SKILL.md',
|
|
116
|
+
join(targetDir, '.ai', 'skills', 'om-system-extension', 'SKILL.md'),
|
|
117
117
|
)
|
|
118
118
|
copyFile(
|
|
119
119
|
srcDir,
|
|
120
|
-
'ai/skills/system-extension/references/extension-contracts.md',
|
|
121
|
-
join(targetDir, '.ai', 'skills', 'system-extension', 'references', 'extension-contracts.md'),
|
|
120
|
+
'ai/skills/om-system-extension/references/extension-contracts.md',
|
|
121
|
+
join(targetDir, '.ai', 'skills', 'om-system-extension', 'references', 'extension-contracts.md'),
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
copyFile(
|
|
125
125
|
srcDir,
|
|
126
|
-
'ai/skills/module-scaffold/SKILL.md',
|
|
127
|
-
join(targetDir, '.ai', 'skills', 'module-scaffold', 'SKILL.md'),
|
|
126
|
+
'ai/skills/om-module-scaffold/SKILL.md',
|
|
127
|
+
join(targetDir, '.ai', 'skills', 'om-module-scaffold', 'SKILL.md'),
|
|
128
128
|
)
|
|
129
129
|
copyFile(
|
|
130
130
|
srcDir,
|
|
131
|
-
'ai/skills/module-scaffold/references/naming-conventions.md',
|
|
132
|
-
join(targetDir, '.ai', 'skills', 'module-scaffold', 'references', 'naming-conventions.md'),
|
|
131
|
+
'ai/skills/om-module-scaffold/references/naming-conventions.md',
|
|
132
|
+
join(targetDir, '.ai', 'skills', 'om-module-scaffold', 'references', 'naming-conventions.md'),
|
|
133
133
|
)
|
|
134
134
|
copyFile(
|
|
135
135
|
srcDir,
|
|
136
|
-
'ai/skills/module-scaffold/references/navigation-patterns.md',
|
|
137
|
-
join(targetDir, '.ai', 'skills', 'module-scaffold', 'references', 'navigation-patterns.md'),
|
|
136
|
+
'ai/skills/om-module-scaffold/references/navigation-patterns.md',
|
|
137
|
+
join(targetDir, '.ai', 'skills', 'om-module-scaffold', 'references', 'navigation-patterns.md'),
|
|
138
138
|
)
|
|
139
139
|
|
|
140
140
|
copyFile(
|
|
141
141
|
srcDir,
|
|
142
|
-
'ai/skills/troubleshooter/SKILL.md',
|
|
143
|
-
join(targetDir, '.ai', 'skills', 'troubleshooter', 'SKILL.md'),
|
|
142
|
+
'ai/skills/om-troubleshooter/SKILL.md',
|
|
143
|
+
join(targetDir, '.ai', 'skills', 'om-troubleshooter', 'SKILL.md'),
|
|
144
144
|
)
|
|
145
145
|
copyFile(
|
|
146
146
|
srcDir,
|
|
147
|
-
'ai/skills/troubleshooter/references/diagnostic-commands.md',
|
|
148
|
-
join(targetDir, '.ai', 'skills', 'troubleshooter', 'references', 'diagnostic-commands.md'),
|
|
147
|
+
'ai/skills/om-troubleshooter/references/diagnostic-commands.md',
|
|
148
|
+
join(targetDir, '.ai', 'skills', 'om-troubleshooter', 'references', 'diagnostic-commands.md'),
|
|
149
149
|
)
|
|
150
150
|
|
|
151
151
|
copyFile(
|
|
152
152
|
srcDir,
|
|
153
|
-
'ai/skills/eject-and-customize/SKILL.md',
|
|
154
|
-
join(targetDir, '.ai', 'skills', 'eject-and-customize', 'SKILL.md'),
|
|
153
|
+
'ai/skills/om-eject-and-customize/SKILL.md',
|
|
154
|
+
join(targetDir, '.ai', 'skills', 'om-eject-and-customize', 'SKILL.md'),
|
|
155
155
|
)
|
|
156
156
|
|
|
157
157
|
copyFile(
|
|
158
158
|
srcDir,
|
|
159
|
-
'ai/skills/data-model-design/SKILL.md',
|
|
160
|
-
join(targetDir, '.ai', 'skills', 'data-model-design', 'SKILL.md'),
|
|
159
|
+
'ai/skills/om-data-model-design/SKILL.md',
|
|
160
|
+
join(targetDir, '.ai', 'skills', 'om-data-model-design', 'SKILL.md'),
|
|
161
161
|
)
|
|
162
162
|
copyFile(
|
|
163
163
|
srcDir,
|
|
164
|
-
'ai/skills/data-model-design/references/mikro-orm-cheatsheet.md',
|
|
165
|
-
join(targetDir, '.ai', 'skills', 'data-model-design', 'references', 'mikro-orm-cheatsheet.md'),
|
|
164
|
+
'ai/skills/om-data-model-design/references/mikro-orm-cheatsheet.md',
|
|
165
|
+
join(targetDir, '.ai', 'skills', 'om-data-model-design', 'references', 'mikro-orm-cheatsheet.md'),
|
|
166
166
|
)
|
|
167
167
|
|
|
168
168
|
copyFile(
|
|
169
169
|
srcDir,
|
|
170
|
-
'ai/skills/implement-spec/SKILL.md',
|
|
171
|
-
join(targetDir, '.ai', 'skills', 'implement-spec', 'SKILL.md'),
|
|
170
|
+
'ai/skills/om-implement-spec/SKILL.md',
|
|
171
|
+
join(targetDir, '.ai', 'skills', 'om-implement-spec', 'SKILL.md'),
|
|
172
172
|
)
|
|
173
173
|
|
|
174
174
|
copyFile(
|
|
175
175
|
srcDir,
|
|
176
|
-
'ai/skills/integration-tests/SKILL.md',
|
|
177
|
-
join(targetDir, '.ai', 'skills', 'integration-tests', 'SKILL.md'),
|
|
176
|
+
'ai/skills/om-integration-tests/SKILL.md',
|
|
177
|
+
join(targetDir, '.ai', 'skills', 'om-integration-tests', 'SKILL.md'),
|
|
178
178
|
)
|
|
179
179
|
|
|
180
180
|
copyFile(
|
|
181
181
|
srcDir,
|
|
182
|
-
'ai/skills/auto-upgrade-0.4.10-to-0.5.0/SKILL.md',
|
|
183
|
-
join(targetDir, '.ai', 'skills', 'auto-upgrade-0.4.10-to-0.5.0', 'SKILL.md'),
|
|
182
|
+
'ai/skills/om-auto-upgrade-0.4.10-to-0.5.0/SKILL.md',
|
|
183
|
+
join(targetDir, '.ai', 'skills', 'om-auto-upgrade-0.4.10-to-0.5.0', 'SKILL.md'),
|
|
184
184
|
)
|
|
185
185
|
|
|
186
186
|
for (const autoSkill of [
|
|
187
|
-
'auto-create-pr',
|
|
188
|
-
'auto-continue-pr',
|
|
189
|
-
'auto-create-pr-loop',
|
|
190
|
-
'auto-continue-pr-loop',
|
|
191
|
-
'auto-review-pr',
|
|
192
|
-
'auto-fix-github',
|
|
187
|
+
'om-auto-create-pr',
|
|
188
|
+
'om-auto-continue-pr',
|
|
189
|
+
'om-auto-create-pr-loop',
|
|
190
|
+
'om-auto-continue-pr-loop',
|
|
191
|
+
'om-auto-review-pr',
|
|
192
|
+
'om-auto-fix-github',
|
|
193
|
+
'om-prepare-issue',
|
|
193
194
|
]) {
|
|
194
195
|
copyFile(
|
|
195
196
|
srcDir,
|
|
@@ -207,8 +208,8 @@ function generateShared(config: AgenticConfig): void {
|
|
|
207
208
|
|
|
208
209
|
copyFile(
|
|
209
210
|
srcDir,
|
|
210
|
-
'ai/skills/trim-unused-modules/SKILL.md',
|
|
211
|
-
join(targetDir, '.ai', 'skills', 'trim-unused-modules', 'SKILL.md'),
|
|
211
|
+
'ai/skills/om-trim-unused-modules/SKILL.md',
|
|
212
|
+
join(targetDir, '.ai', 'skills', 'om-trim-unused-modules', 'SKILL.md'),
|
|
212
213
|
)
|
|
213
214
|
|
|
214
215
|
copyFile(srcDir, 'ai/qa/tests/playwright.config.ts', join(targetDir, '.ai', 'qa', 'tests', 'playwright.config.ts'))
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process'
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { resolve } from 'node:path'
|
|
4
|
+
import { expect, test } from '@playwright/test'
|
|
5
|
+
|
|
6
|
+
const token = process.env.RAILWAY_INTEGRATION_TOKEN
|
|
7
|
+
const appRoot = process.env.RAILWAY_INTEGRATION_APP_ROOT
|
|
8
|
+
const cliBin = resolve(process.cwd(), 'packages/cli/dist/bin.js')
|
|
9
|
+
|
|
10
|
+
function runCli(args: string[]): string {
|
|
11
|
+
if (!appRoot || !token) throw new Error('Railway integration environment is incomplete.')
|
|
12
|
+
return execFileSync(process.execPath, [cliBin, ...args], {
|
|
13
|
+
cwd: appRoot,
|
|
14
|
+
encoding: 'utf8',
|
|
15
|
+
env: {
|
|
16
|
+
...process.env,
|
|
17
|
+
RAILWAY_API_TOKEN: token,
|
|
18
|
+
CI: 'true',
|
|
19
|
+
},
|
|
20
|
+
timeout: 15 * 60 * 1000,
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test.describe('mercato deploy railway live integration', () => {
|
|
25
|
+
test.skip(!token || !appRoot, 'RAILWAY_INTEGRATION_TOKEN and RAILWAY_INTEGRATION_APP_ROOT are required')
|
|
26
|
+
|
|
27
|
+
test('deploys, verifies health, resumes, and cleans up', async ({ request }) => {
|
|
28
|
+
expect(existsSync(cliBin)).toBe(true)
|
|
29
|
+
const projectName = `mercato-integration-${Date.now()}`
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const output = runCli([
|
|
33
|
+
'deploy',
|
|
34
|
+
'railway',
|
|
35
|
+
'--project',
|
|
36
|
+
projectName,
|
|
37
|
+
'--source',
|
|
38
|
+
'local',
|
|
39
|
+
'--no-worker',
|
|
40
|
+
'--non-interactive',
|
|
41
|
+
])
|
|
42
|
+
const outputLines = output.trim().split(/\r?\n/)
|
|
43
|
+
const deployUrl = outputLines
|
|
44
|
+
.find((line) => line.startsWith('DEPLOY_URL='))
|
|
45
|
+
?.slice('DEPLOY_URL='.length)
|
|
46
|
+
expect(deployUrl).toBeTruthy()
|
|
47
|
+
expect(outputLines.at(-1)).toBe(`DEPLOY_URL=${deployUrl}`)
|
|
48
|
+
|
|
49
|
+
const health = await request.get(`${deployUrl}/api/healthz`)
|
|
50
|
+
expect(health.status()).toBe(200)
|
|
51
|
+
expect(await health.json()).toEqual({
|
|
52
|
+
status: 'ok',
|
|
53
|
+
ts: expect.any(String),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const resumeOutput = runCli([
|
|
57
|
+
'deploy',
|
|
58
|
+
'railway',
|
|
59
|
+
'--source',
|
|
60
|
+
'local',
|
|
61
|
+
'--no-worker',
|
|
62
|
+
'--non-interactive',
|
|
63
|
+
])
|
|
64
|
+
expect(resumeOutput).toContain(`Project: https://railway.com/project/`)
|
|
65
|
+
} finally {
|
|
66
|
+
if (appRoot && existsSync(resolve(appRoot, '.mercato', 'railway.json'))) {
|
|
67
|
+
runCli(['deploy', 'railway', '--cleanup', '--non-interactive', '--yes'])
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { existsSync, mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { runRailwayDeploy } from '../index'
|
|
5
|
+
|
|
6
|
+
describe('mercato deploy railway --dry-run', () => {
|
|
7
|
+
it('prints a deterministic local-source plan without a token or state mutation', async () => {
|
|
8
|
+
const cwd = mkdtempSync(join(tmpdir(), 'mercato-railway-dry-run-'))
|
|
9
|
+
mkdirSync(join(cwd, 'node_modules'), { recursive: true })
|
|
10
|
+
writeFileSync(join(cwd, 'package.json'), JSON.stringify({
|
|
11
|
+
name: 'My Shop',
|
|
12
|
+
dependencies: { '@open-mercato/core': '0.6.4' },
|
|
13
|
+
}))
|
|
14
|
+
writeFileSync(join(cwd, '.env'), 'CUSTOM_SETTING=enabled\n')
|
|
15
|
+
writeFileSync(
|
|
16
|
+
join(cwd, '.railwayignore'),
|
|
17
|
+
'.env*\n*.pem\n*.key\nid_*\n.git\n.railway\nnode_modules\n.yarn/cache\n.next\n.turbo\n*.db\n*.sqlite\n*.sqlite3\n.mercato/railway.json*\n',
|
|
18
|
+
)
|
|
19
|
+
const log = jest.spyOn(console, 'log').mockImplementation(() => undefined)
|
|
20
|
+
|
|
21
|
+
await runRailwayDeploy(['--dry-run', '--source', 'local'], {
|
|
22
|
+
cwd,
|
|
23
|
+
resolveSource: () => ({ mode: 'local', reason: 'test local source' }),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const output = log.mock.calls.map((call) => call.join(' ')).join('\n')
|
|
27
|
+
expect(output).toContain('Railway deployment plan (dry run)')
|
|
28
|
+
expect(output).toContain('Project: my-shop')
|
|
29
|
+
expect(output).toContain('Source: local')
|
|
30
|
+
expect(output).toContain('AUTH_SECRET=<redacted>')
|
|
31
|
+
expect(output).not.toContain('generated-at-deploy')
|
|
32
|
+
log.mockRestore()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('prints a cleanup plan without deleting tracked state', async () => {
|
|
36
|
+
const cwd = mkdtempSync(join(tmpdir(), 'mercato-railway-cleanup-dry-run-'))
|
|
37
|
+
mkdirSync(join(cwd, '.mercato'), { recursive: true })
|
|
38
|
+
writeFileSync(join(cwd, 'package.json'), JSON.stringify({
|
|
39
|
+
name: 'My Shop',
|
|
40
|
+
dependencies: { '@open-mercato/core': '0.6.4' },
|
|
41
|
+
}))
|
|
42
|
+
const statePath = join(cwd, '.mercato', 'railway.json')
|
|
43
|
+
writeFileSync(statePath, JSON.stringify({
|
|
44
|
+
schemaVersion: 1,
|
|
45
|
+
provider: 'railway',
|
|
46
|
+
projectId: 'project-1',
|
|
47
|
+
projectName: 'my-shop',
|
|
48
|
+
environments: {},
|
|
49
|
+
writtenBy: { cliVersion: 'test' },
|
|
50
|
+
}))
|
|
51
|
+
const log = jest.spyOn(console, 'log').mockImplementation(() => undefined)
|
|
52
|
+
|
|
53
|
+
await runRailwayDeploy(['--cleanup', '--dry-run'], { cwd })
|
|
54
|
+
|
|
55
|
+
const output = log.mock.calls.map((call) => call.join(' ')).join('\n')
|
|
56
|
+
expect(output).toContain('Railway cleanup plan (dry run)')
|
|
57
|
+
expect(output).toContain('projectDelete')
|
|
58
|
+
expect(existsSync(statePath)).toBe(true)
|
|
59
|
+
log.mockRestore()
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeRailwayVariables,
|
|
3
|
+
generateProtectedSecrets,
|
|
4
|
+
parseEnvFile,
|
|
5
|
+
} from '../env'
|
|
6
|
+
|
|
7
|
+
describe('Railway environment variables', () => {
|
|
8
|
+
it('parses common dotenv syntax', () => {
|
|
9
|
+
expect(parseEnvFile(`
|
|
10
|
+
# comment
|
|
11
|
+
PLAIN=value
|
|
12
|
+
export QUOTED="hello world"
|
|
13
|
+
SINGLE='x'
|
|
14
|
+
`)).toEqual({
|
|
15
|
+
PLAIN: 'value',
|
|
16
|
+
QUOTED: 'hello world',
|
|
17
|
+
SINGLE: 'x',
|
|
18
|
+
})
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('generates missing protected secrets and preserves existing ones', () => {
|
|
22
|
+
const secrets = generateProtectedSecrets({ AUTH_SECRET: 'existing' })
|
|
23
|
+
expect(secrets.AUTH_SECRET).toBe('existing')
|
|
24
|
+
expect(secrets.JWT_SECRET).toHaveLength(128)
|
|
25
|
+
expect(secrets.TENANT_DATA_ENCRYPTION_FALLBACK_KEY.length).toBeGreaterThan(30)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('computes app and worker settings without leaking Railway tokens', () => {
|
|
29
|
+
const variables = computeRailwayVariables({
|
|
30
|
+
env: {
|
|
31
|
+
RAILWAY_API_TOKEN: 'never-upload',
|
|
32
|
+
CUSTOM_SETTING: 'enabled',
|
|
33
|
+
},
|
|
34
|
+
role: 'app',
|
|
35
|
+
workerEnabled: true,
|
|
36
|
+
appUrl: 'https://example.up.railway.app',
|
|
37
|
+
protectedSecrets: {
|
|
38
|
+
AUTH_SECRET: 'auth',
|
|
39
|
+
JWT_SECRET: 'jwt',
|
|
40
|
+
TENANT_DATA_ENCRYPTION_FALLBACK_KEY: 'encryption',
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
expect(variables).toMatchObject({
|
|
44
|
+
DATABASE_URL: '${{Postgres.DATABASE_URL}}',
|
|
45
|
+
REDIS_URL: '${{Redis.REDIS_URL}}',
|
|
46
|
+
CACHE_STRATEGY: 'redis',
|
|
47
|
+
QUEUE_STRATEGY: 'async',
|
|
48
|
+
AUTO_SPAWN_WORKERS: 'false',
|
|
49
|
+
PORT: '3000',
|
|
50
|
+
APP_URL: 'https://example.up.railway.app',
|
|
51
|
+
CUSTOM_SETTING: 'enabled',
|
|
52
|
+
})
|
|
53
|
+
expect(variables.RAILWAY_API_TOKEN).toBeUndefined()
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createRailwayGraphqlClient,
|
|
3
|
+
RailwayGraphqlError,
|
|
4
|
+
} from '../graphql-client'
|
|
5
|
+
|
|
6
|
+
const query = { name: 'TestQuery', query: 'query TestQuery { me { id } }' }
|
|
7
|
+
const mutation = { ...query, name: 'TestMutation', mutation: true }
|
|
8
|
+
|
|
9
|
+
function response(body: unknown, status = 200): Response {
|
|
10
|
+
return new Response(JSON.stringify(body), { status })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('Railway GraphQL client', () => {
|
|
14
|
+
it('sends operationName, query, variables, and bearer auth', async () => {
|
|
15
|
+
const fetchImpl = jest.fn(async () => response({ data: { me: { id: 'user' } } }))
|
|
16
|
+
const client = createRailwayGraphqlClient({
|
|
17
|
+
token: 'account-token',
|
|
18
|
+
fetchImpl: fetchImpl as typeof fetch,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
await expect(client.request(query, { input: 'value' })).resolves.toEqual({ me: { id: 'user' } })
|
|
22
|
+
expect(fetchImpl).toHaveBeenCalledWith(
|
|
23
|
+
'https://backboard.railway.com/graphql/v2',
|
|
24
|
+
expect.objectContaining({
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: expect.objectContaining({ Authorization: 'Bearer account-token' }),
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
operationName: 'TestQuery',
|
|
29
|
+
query: query.query,
|
|
30
|
+
variables: { input: 'value' },
|
|
31
|
+
}),
|
|
32
|
+
}),
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('retries idempotent reads once on a server error', async () => {
|
|
37
|
+
const fetchImpl = jest.fn()
|
|
38
|
+
.mockResolvedValueOnce(response({ errors: [{ message: 'temporary' }] }, 500))
|
|
39
|
+
.mockResolvedValueOnce(response({ data: { ok: true } }))
|
|
40
|
+
const client = createRailwayGraphqlClient({
|
|
41
|
+
token: 'token',
|
|
42
|
+
fetchImpl: fetchImpl as typeof fetch,
|
|
43
|
+
})
|
|
44
|
+
await expect(client.request(query)).resolves.toEqual({ ok: true })
|
|
45
|
+
expect(fetchImpl).toHaveBeenCalledTimes(2)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('never blindly retries mutations', async () => {
|
|
49
|
+
const fetchImpl = jest.fn(async () => response({ errors: [{ message: 'ambiguous' }] }, 500))
|
|
50
|
+
const client = createRailwayGraphqlClient({
|
|
51
|
+
token: 'token',
|
|
52
|
+
fetchImpl: fetchImpl as typeof fetch,
|
|
53
|
+
})
|
|
54
|
+
await expect(client.request(mutation)).rejects.toBeInstanceOf(RailwayGraphqlError)
|
|
55
|
+
expect(fetchImpl).toHaveBeenCalledTimes(1)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('redacts sensitive request and response fields in verbose logs', async () => {
|
|
59
|
+
const logger = { log: jest.fn() }
|
|
60
|
+
const fetchImpl = jest.fn(async () => response({
|
|
61
|
+
data: { variables: { AUTH_SECRET: 'response-secret', SAFE_VALUE: 'visible' } },
|
|
62
|
+
}))
|
|
63
|
+
const client = createRailwayGraphqlClient({
|
|
64
|
+
token: 'account-token',
|
|
65
|
+
verbose: true,
|
|
66
|
+
fetchImpl: fetchImpl as typeof fetch,
|
|
67
|
+
logger,
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
await client.request(query, {
|
|
71
|
+
input: { JWT_SECRET: 'request-secret', SAFE_VALUE: 'visible' },
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const output = logger.log.mock.calls.flat().join('\n')
|
|
75
|
+
expect(output).not.toContain('request-secret')
|
|
76
|
+
expect(output).not.toContain('response-secret')
|
|
77
|
+
expect(output).toContain('<redacted>')
|
|
78
|
+
expect(output).toContain('visible')
|
|
79
|
+
})
|
|
80
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto'
|
|
2
|
+
import {
|
|
3
|
+
railwayOperations,
|
|
4
|
+
railwaySchemaFingerprintSource,
|
|
5
|
+
} from '../operations'
|
|
6
|
+
|
|
7
|
+
describe('Railway GraphQL operation contract', () => {
|
|
8
|
+
it('matches the verified operation fingerprint', () => {
|
|
9
|
+
const fingerprint = createHash('sha256')
|
|
10
|
+
.update(railwaySchemaFingerprintSource())
|
|
11
|
+
.digest('hex')
|
|
12
|
+
expect(fingerprint).toBe('01e3c5feaa163ebe626a1cb9ae5f22b5e7ea316162fed9353375f34c25ebc522')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('uses template-backed databases and singular service variable upserts', () => {
|
|
16
|
+
const source = railwaySchemaFingerprintSource()
|
|
17
|
+
expect(source).toContain('templateDeployV2')
|
|
18
|
+
expect(source).not.toContain('pluginCreate')
|
|
19
|
+
expect(railwayOperations.variableUpsert.query).toContain('VariableCollectionUpsertInput')
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { parseRailwayDeployOptions, redactRailwayCliArgs } from '../options'
|
|
2
|
+
|
|
3
|
+
describe('parseRailwayDeployOptions', () => {
|
|
4
|
+
it('parses the complete command surface', () => {
|
|
5
|
+
expect(parseRailwayDeployOptions([
|
|
6
|
+
'--project=my-shop',
|
|
7
|
+
'--env', 'staging',
|
|
8
|
+
'--service', 'web',
|
|
9
|
+
'--no-worker',
|
|
10
|
+
'--source', 'local',
|
|
11
|
+
'--region', 'europe-west4',
|
|
12
|
+
'--env-file', '.env.railway',
|
|
13
|
+
'--domain', 'shop.example.com',
|
|
14
|
+
'--no-wait-domain',
|
|
15
|
+
'--volume', '/app/storage',
|
|
16
|
+
'--token', 'token',
|
|
17
|
+
'--non-interactive',
|
|
18
|
+
'--dry-run',
|
|
19
|
+
'--yes',
|
|
20
|
+
'--write-env',
|
|
21
|
+
'--no-track',
|
|
22
|
+
'--force-rename',
|
|
23
|
+
'--timeout', '120',
|
|
24
|
+
'--allow-secret-passthrough', 'OPENAI_API_KEY',
|
|
25
|
+
'--allow-secret-passthrough=RESEND_API_KEY',
|
|
26
|
+
'--verbose',
|
|
27
|
+
], {})).toMatchObject({
|
|
28
|
+
project: 'my-shop',
|
|
29
|
+
environment: 'staging',
|
|
30
|
+
service: 'web',
|
|
31
|
+
worker: false,
|
|
32
|
+
source: 'local',
|
|
33
|
+
region: 'europe-west4',
|
|
34
|
+
envFile: '.env.railway',
|
|
35
|
+
domain: 'shop.example.com',
|
|
36
|
+
waitDomain: false,
|
|
37
|
+
volume: '/app/storage',
|
|
38
|
+
token: 'token',
|
|
39
|
+
nonInteractive: true,
|
|
40
|
+
dryRun: true,
|
|
41
|
+
yes: true,
|
|
42
|
+
writeEnv: true,
|
|
43
|
+
track: false,
|
|
44
|
+
forceRename: true,
|
|
45
|
+
timeoutSeconds: 120,
|
|
46
|
+
allowedSecretKeys: ['OPENAI_API_KEY', 'RESEND_API_KEY'],
|
|
47
|
+
verbose: true,
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('enables non-interactive mode in CI', () => {
|
|
52
|
+
expect(parseRailwayDeployOptions([], { CI: 'true' }).nonInteractive).toBe(true)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('allows cleanup dry-runs in non-interactive environments without --yes', () => {
|
|
56
|
+
expect(parseRailwayDeployOptions(['--cleanup', '--dry-run'], { CI: 'true' }))
|
|
57
|
+
.toMatchObject({
|
|
58
|
+
cleanup: true,
|
|
59
|
+
dryRun: true,
|
|
60
|
+
nonInteractive: true,
|
|
61
|
+
yes: false,
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it.each([
|
|
66
|
+
[['--source', 'invalid'], 'Invalid --source'],
|
|
67
|
+
[['--timeout', '0'], '--timeout must be'],
|
|
68
|
+
[['--unknown'], 'Unknown Railway deploy option'],
|
|
69
|
+
[['--cleanup', '--non-interactive'], 'requires --yes'],
|
|
70
|
+
])('rejects invalid arguments', (args, expectedMessage) => {
|
|
71
|
+
expect(() => parseRailwayDeployOptions(args, {})).toThrow(expectedMessage)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('redacts both token flag syntaxes in dispatcher output', () => {
|
|
75
|
+
expect(redactRailwayCliArgs(['--token', 'secret', '--token=other', '--dry-run']))
|
|
76
|
+
.toEqual(['--token', '****', '--token=****', '--dry-run'])
|
|
77
|
+
})
|
|
78
|
+
})
|