@gxp-dev/tools 2.0.71 → 2.0.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -81
- package/bin/lib/cli.js +18 -0
- package/bin/lib/commands/index.js +2 -0
- package/bin/lib/commands/init.js +104 -82
- package/bin/lib/commands/lint.js +77 -0
- package/bin/lib/constants.js +12 -0
- package/bin/lib/lint/formatter.js +91 -0
- package/bin/lib/lint/index.js +284 -0
- package/bin/lib/lint/schemas/app-manifest.schema.json +124 -0
- package/bin/lib/lint/schemas/card.schema.json +165 -0
- package/bin/lib/lint/schemas/common.schema.json +62 -0
- package/bin/lib/lint/schemas/configuration.schema.json +19 -0
- package/bin/lib/lint/schemas/field.schema.json +230 -0
- package/bin/lib/utils/ai-scaffold.js +137 -0
- package/mcp/gxp-api-server.js +87 -129
- package/mcp/lib/api-tools.js +543 -0
- package/mcp/lib/config-ops.js +234 -0
- package/mcp/lib/config-tools.js +549 -0
- package/mcp/lib/docs-tools.js +142 -0
- package/mcp/lib/docs.js +263 -0
- package/mcp/lib/specs.js +135 -0
- package/mcp/lib/test-tools.js +358 -0
- package/package.json +3 -1
- package/runtime/stores/gxpPortalConfigStore.js +88 -87
- package/runtime/vite.config.js +5 -3
- package/template/.claude/agents/gxp-developer.md +377 -50
- package/template/.prettierrc +10 -0
- package/template/AGENTS.md +265 -21
- package/template/GEMINI.md +181 -19
- package/template/README.md +205 -240
- package/template/app-instructions.md +91 -0
- package/template/eslint.config.js +32 -0
- package/template/githooks/pre-commit +37 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://gxp.dev/schemas/common.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "GxP Common Definitions",
|
|
5
|
+
"description": "Shared sub-schemas referenced by card and field schemas.",
|
|
6
|
+
"$defs": {
|
|
7
|
+
"conditionParam": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": { "type": "string" },
|
|
11
|
+
"value": {
|
|
12
|
+
"type": ["string", "number", "boolean", "null"]
|
|
13
|
+
},
|
|
14
|
+
"logic": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"enum": ["==", "!=", ">", ">=", "<", "<=", "in", "not_in", "includes"]
|
|
17
|
+
},
|
|
18
|
+
"column": { "type": ["string", "null"] }
|
|
19
|
+
},
|
|
20
|
+
"required": ["name", "logic"],
|
|
21
|
+
"additionalProperties": true
|
|
22
|
+
},
|
|
23
|
+
"conditionParams": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": { "$ref": "#/$defs/conditionParam" }
|
|
26
|
+
},
|
|
27
|
+
"gridCols": {
|
|
28
|
+
"type": "integer",
|
|
29
|
+
"minimum": 1,
|
|
30
|
+
"maximum": 12
|
|
31
|
+
},
|
|
32
|
+
"colorHex": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"pattern": "^#(?:[0-9a-fA-F]{3}){1,2}$"
|
|
35
|
+
},
|
|
36
|
+
"urlOrPath": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Absolute URL or site-relative path",
|
|
39
|
+
"pattern": "^(https?:)?(//)?/?[^\\s]*$"
|
|
40
|
+
},
|
|
41
|
+
"identifier": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"pattern": "^[A-Za-z_][A-Za-z0-9_-]*$"
|
|
44
|
+
},
|
|
45
|
+
"option": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"properties": {
|
|
48
|
+
"label": { "type": "string" },
|
|
49
|
+
"value": {
|
|
50
|
+
"type": ["string", "number", "boolean", "null"]
|
|
51
|
+
},
|
|
52
|
+
"disabled": { "type": "boolean" }
|
|
53
|
+
},
|
|
54
|
+
"required": ["label", "value"],
|
|
55
|
+
"additionalProperties": true
|
|
56
|
+
},
|
|
57
|
+
"options": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": { "$ref": "#/$defs/option" }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://gxp.dev/schemas/configuration.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "GxP Plugin Configuration Form",
|
|
5
|
+
"description": "Defines the configuration form shown to admins in the GxP admin panel when they install or configure a plugin. Follows the GxP templating system (ShowPage > tabs > cards > fields).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["additionalTabs"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"additionalTabs": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"description": "Top-level array of tab definitions. Each item is a card (usually card_list or fields_list) rendered under the plugin's configuration panel.",
|
|
12
|
+
"items": { "$ref": "card.schema.json" }
|
|
13
|
+
},
|
|
14
|
+
"title": { "type": ["string", "null"] },
|
|
15
|
+
"description": { "type": ["string", "null"] },
|
|
16
|
+
"version": { "type": ["string", "integer", "null"] }
|
|
17
|
+
},
|
|
18
|
+
"additionalProperties": true
|
|
19
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://gxp.dev/schemas/field.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"title": "GxP Form Field",
|
|
5
|
+
"description": "A single form field descriptor used inside a fields_list card.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["type"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"type": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"enum": [
|
|
12
|
+
"hidden",
|
|
13
|
+
"html",
|
|
14
|
+
"live-html",
|
|
15
|
+
"heading",
|
|
16
|
+
"heading-large",
|
|
17
|
+
"small-heading",
|
|
18
|
+
"description",
|
|
19
|
+
"image",
|
|
20
|
+
"video",
|
|
21
|
+
"icon",
|
|
22
|
+
"icon-selector",
|
|
23
|
+
"clipboard",
|
|
24
|
+
"timestamp",
|
|
25
|
+
"button",
|
|
26
|
+
"external_link",
|
|
27
|
+
"text",
|
|
28
|
+
"number",
|
|
29
|
+
"email",
|
|
30
|
+
"password",
|
|
31
|
+
"phone_number",
|
|
32
|
+
"textarea",
|
|
33
|
+
"select",
|
|
34
|
+
"pill_select",
|
|
35
|
+
"multi_select",
|
|
36
|
+
"autocomplete",
|
|
37
|
+
"asyncSelect",
|
|
38
|
+
"radio",
|
|
39
|
+
"checkbox",
|
|
40
|
+
"boolean",
|
|
41
|
+
"boolean_icon",
|
|
42
|
+
"file",
|
|
43
|
+
"selectAsset",
|
|
44
|
+
"selectPagePlugin",
|
|
45
|
+
"selectProjectPlan",
|
|
46
|
+
"keyValuePair",
|
|
47
|
+
"codeEditor",
|
|
48
|
+
"htmlEditor",
|
|
49
|
+
"render_markdown",
|
|
50
|
+
"colorPicker",
|
|
51
|
+
"tag_list",
|
|
52
|
+
"savedSearchBuilder",
|
|
53
|
+
"date",
|
|
54
|
+
"datetime",
|
|
55
|
+
"time",
|
|
56
|
+
"timezone_picker",
|
|
57
|
+
"data_table",
|
|
58
|
+
"integration_connector",
|
|
59
|
+
"form-builder",
|
|
60
|
+
"object-builder"
|
|
61
|
+
],
|
|
62
|
+
"description": "Field type. Determines which extra properties are required."
|
|
63
|
+
},
|
|
64
|
+
"name": { "type": ["string", "null"] },
|
|
65
|
+
"label": { "type": ["string", "null"] },
|
|
66
|
+
"default": {
|
|
67
|
+
"type": ["string", "number", "boolean", "array", "object", "null"]
|
|
68
|
+
},
|
|
69
|
+
"placeholder": { "type": ["string", "null"] },
|
|
70
|
+
"disabled": { "type": "boolean" },
|
|
71
|
+
"readonly": { "type": "boolean" },
|
|
72
|
+
"required": { "type": "boolean" },
|
|
73
|
+
"multiple": { "type": "boolean" },
|
|
74
|
+
"classList": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"items": { "type": "string" }
|
|
77
|
+
},
|
|
78
|
+
"columnClass": { "type": ["string", "null"] },
|
|
79
|
+
"cols": {
|
|
80
|
+
"$ref": "common.schema.json#/$defs/gridCols"
|
|
81
|
+
},
|
|
82
|
+
"colsSm": { "$ref": "common.schema.json#/$defs/gridCols" },
|
|
83
|
+
"colsMd": { "$ref": "common.schema.json#/$defs/gridCols" },
|
|
84
|
+
"colsLg": { "$ref": "common.schema.json#/$defs/gridCols" },
|
|
85
|
+
"condition": { "type": ["string", "null"] },
|
|
86
|
+
"conditionParams": {
|
|
87
|
+
"$ref": "common.schema.json#/$defs/conditionParams"
|
|
88
|
+
},
|
|
89
|
+
"content": { "type": ["string", "null"] },
|
|
90
|
+
"text": { "type": ["string", "null"] },
|
|
91
|
+
"href": { "type": ["string", "null"] },
|
|
92
|
+
"icon": { "type": ["string", "null"] },
|
|
93
|
+
"options": {
|
|
94
|
+
"$ref": "common.schema.json#/$defs/options"
|
|
95
|
+
},
|
|
96
|
+
"accept": {
|
|
97
|
+
"type": "array",
|
|
98
|
+
"items": { "type": "string" }
|
|
99
|
+
},
|
|
100
|
+
"format": { "type": ["string", "null"] },
|
|
101
|
+
"prepend": { "type": ["string", "null"] },
|
|
102
|
+
"append": { "type": ["string", "null"] },
|
|
103
|
+
"method": {
|
|
104
|
+
"type": ["string", "null"],
|
|
105
|
+
"enum": ["GET", "POST", "PUT", "PATCH", "DELETE", null]
|
|
106
|
+
},
|
|
107
|
+
"query_parameter": { "type": ["string", "null"] },
|
|
108
|
+
"refresh": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"properties": {
|
|
111
|
+
"only": { "type": "string" },
|
|
112
|
+
"key": { "type": "string" }
|
|
113
|
+
},
|
|
114
|
+
"additionalProperties": true
|
|
115
|
+
},
|
|
116
|
+
"validation_rules": {
|
|
117
|
+
"type": "array",
|
|
118
|
+
"items": { "type": "string" }
|
|
119
|
+
},
|
|
120
|
+
"custom_settings": { "type": "object" }
|
|
121
|
+
},
|
|
122
|
+
"allOf": [
|
|
123
|
+
{
|
|
124
|
+
"if": {
|
|
125
|
+
"properties": {
|
|
126
|
+
"type": {
|
|
127
|
+
"enum": [
|
|
128
|
+
"select",
|
|
129
|
+
"pill_select",
|
|
130
|
+
"multi_select",
|
|
131
|
+
"radio",
|
|
132
|
+
"checkbox"
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"required": ["type"]
|
|
137
|
+
},
|
|
138
|
+
"then": {
|
|
139
|
+
"required": ["options"],
|
|
140
|
+
"properties": {
|
|
141
|
+
"options": {
|
|
142
|
+
"$ref": "common.schema.json#/$defs/options",
|
|
143
|
+
"minItems": 1
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"if": {
|
|
150
|
+
"properties": {
|
|
151
|
+
"type": {
|
|
152
|
+
"enum": [
|
|
153
|
+
"text",
|
|
154
|
+
"number",
|
|
155
|
+
"email",
|
|
156
|
+
"password",
|
|
157
|
+
"phone_number",
|
|
158
|
+
"textarea",
|
|
159
|
+
"select",
|
|
160
|
+
"pill_select",
|
|
161
|
+
"multi_select",
|
|
162
|
+
"autocomplete",
|
|
163
|
+
"asyncSelect",
|
|
164
|
+
"radio",
|
|
165
|
+
"checkbox",
|
|
166
|
+
"boolean",
|
|
167
|
+
"boolean_icon",
|
|
168
|
+
"file",
|
|
169
|
+
"selectAsset",
|
|
170
|
+
"keyValuePair",
|
|
171
|
+
"codeEditor",
|
|
172
|
+
"htmlEditor",
|
|
173
|
+
"colorPicker",
|
|
174
|
+
"tag_list",
|
|
175
|
+
"date",
|
|
176
|
+
"datetime",
|
|
177
|
+
"time",
|
|
178
|
+
"timezone_picker"
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
"required": ["type"]
|
|
183
|
+
},
|
|
184
|
+
"then": {
|
|
185
|
+
"required": ["name"],
|
|
186
|
+
"properties": {
|
|
187
|
+
"name": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"minLength": 1
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"if": {
|
|
196
|
+
"properties": { "type": { "const": "asyncSelect" } },
|
|
197
|
+
"required": ["type"]
|
|
198
|
+
},
|
|
199
|
+
"then": {
|
|
200
|
+
"required": ["href", "method"]
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"if": {
|
|
205
|
+
"properties": { "type": { "const": "external_link" } },
|
|
206
|
+
"required": ["type"]
|
|
207
|
+
},
|
|
208
|
+
"then": {
|
|
209
|
+
"required": ["href"]
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"if": {
|
|
214
|
+
"properties": { "type": { "const": "colorPicker" } },
|
|
215
|
+
"required": ["type"]
|
|
216
|
+
},
|
|
217
|
+
"then": {
|
|
218
|
+
"properties": {
|
|
219
|
+
"default": {
|
|
220
|
+
"oneOf": [
|
|
221
|
+
{ "$ref": "common.schema.json#/$defs/colorHex" },
|
|
222
|
+
{ "type": "null" }
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
],
|
|
229
|
+
"additionalProperties": true
|
|
230
|
+
}
|
|
@@ -953,6 +953,141 @@ async function runAIScaffolding(
|
|
|
953
953
|
return result.errors.length === 0
|
|
954
954
|
}
|
|
955
955
|
|
|
956
|
+
/**
|
|
957
|
+
* Build the initial prompt sent to an interactive AI CLI session.
|
|
958
|
+
* The prompt anchors the agent in the scaffolded project, points it at
|
|
959
|
+
* the project's instruction files (which describe the full tool set),
|
|
960
|
+
* and tells it to keep asking questions until it has enough detail.
|
|
961
|
+
*
|
|
962
|
+
* @param {string} projectName - Plugin name
|
|
963
|
+
* @param {string} description - Plugin description
|
|
964
|
+
* @param {string} provider - Selected AI provider (claude, codex, gemini)
|
|
965
|
+
* @returns {string} Prompt text
|
|
966
|
+
*/
|
|
967
|
+
function buildInteractiveInitialPrompt(projectName, description, provider) {
|
|
968
|
+
const instructionFile = provider === "gemini" ? "GEMINI.md" : "AGENTS.md"
|
|
969
|
+
const claudeAgentHint =
|
|
970
|
+
provider === "claude"
|
|
971
|
+
? " You can also delegate to the `gxp-developer` subagent defined in `.claude/agents/gxp-developer.md`."
|
|
972
|
+
: ""
|
|
973
|
+
|
|
974
|
+
return [
|
|
975
|
+
`I just ran \`gxdev init\` to scaffold a new GxP plugin called "${projectName}"${
|
|
976
|
+
description ? ` (${description})` : ""
|
|
977
|
+
} in this directory.`,
|
|
978
|
+
"",
|
|
979
|
+
`Start a new GxP plugin development session. First read \`${instructionFile}\` and \`app-instructions.md\` in this project — they describe the workflow, conventions, and the full set of tools available to you.${claudeAgentHint}`,
|
|
980
|
+
"",
|
|
981
|
+
"You have the `gxp-api` MCP server available with 29 tools across five families:",
|
|
982
|
+
"- **API spec discovery** — `search_api_endpoints`, `api_list_operation_ids`, `api_get_operation_parameters`, `api_find_endpoints_by_schema`, `api_generate_dependency`, `get_endpoint_details`.",
|
|
983
|
+
"- **WebSocket events** — `api_find_events_for_operation` (maps an operationId to the AsyncAPI events it triggers), `api_list_events`, `search_websocket_events`.",
|
|
984
|
+
"- **Config editing** — `config_add_card`, `config_add_field`, `config_list_field_types`, `config_get_field_schema`, `config_extract_strings`, `config_validate`, etc. Every mutation is linter-guarded against the schemas in `bin/lib/lint/schemas/`.",
|
|
985
|
+
"- **Docs search** — `docs_search`, `docs_get_page`, `docs_list_pages` (full-text search across docs.gxp.dev).",
|
|
986
|
+
"- **Test helpers** — `test_scaffold_component_test`, `test_api_route`.",
|
|
987
|
+
"",
|
|
988
|
+
"Follow the full workflow from the instructions: (1) understand the feature, (2) discover data sources via MCP, (3) plan including the admin configuration form, (4) implement, (5) **sync the manifest and build the admin form**, (6) test with real broadcasts, (7) final `gxdev lint --all`.",
|
|
989
|
+
"",
|
|
990
|
+
"Step 5 is not optional. Every time you add or change a `store.callApi`, `store.listen`, `gxp-string`, or `gxp-src`, close the loop:",
|
|
991
|
+
'- Call `config_extract_strings` with `writeTo: "app-manifest.json"` — it scans `src/` and merges every directive, store getter, and dependency identifier into the manifest (same logic as `gxdev extract-config`, linter-guarded).',
|
|
992
|
+
"- For every entry now in the manifest, add a matching field in `configuration.json` using the MCP `config_*` tools. Default mapping: `strings.default.*` → `text`/`textarea`, `assets.*` → `selectAsset`, each declared `dependencies[]` identifier → `asyncSelect` bound to the resource's list endpoint, colors → `colorPicker`, numbers → `number`, toggles → `boolean`. Field `name` must match the manifest key exactly.",
|
|
993
|
+
"- Run `gxdev lint --all` before moving on.",
|
|
994
|
+
"",
|
|
995
|
+
"Do NOT start implementing until you have enough detail. Keep asking me clarifying questions until you know:",
|
|
996
|
+
"- The user-facing outcome and who uses it (attendee, staff, admin)",
|
|
997
|
+
"- What real-world data it reads/writes — identify the concrete platform operationIds via the MCP, never invent them",
|
|
998
|
+
"- Which real-time events matter (use `api_find_events_for_operation` for each planned operationId)",
|
|
999
|
+
"- Every piece of admin-editable content: strings, assets, colors/thresholds/settings, feature toggles",
|
|
1000
|
+
"",
|
|
1001
|
+
"Then propose a plan — screens/components, data flow, admin configuration form, and the exact keys you'll add to `app-manifest.json` — and get my confirmation before implementing.",
|
|
1002
|
+
"",
|
|
1003
|
+
"Begin now by greeting me briefly and asking what I want to build. Ask one focused question at a time rather than dumping a full questionnaire.",
|
|
1004
|
+
].join("\n")
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* Launch the selected AI CLI in interactive mode with an initial prompt.
|
|
1009
|
+
* The user talks to the agent directly in the terminal; the agent is
|
|
1010
|
+
* responsible for eliciting the feature spec and building it.
|
|
1011
|
+
*
|
|
1012
|
+
* @param {string} projectPath - Project directory (cwd for the spawned CLI)
|
|
1013
|
+
* @param {string} projectName - Plugin name
|
|
1014
|
+
* @param {string} description - Plugin description
|
|
1015
|
+
* @param {string} provider - claude | codex | gemini
|
|
1016
|
+
* @returns {Promise<boolean>} True if the CLI exited successfully
|
|
1017
|
+
*/
|
|
1018
|
+
function launchInteractiveAISession(
|
|
1019
|
+
projectPath,
|
|
1020
|
+
projectName,
|
|
1021
|
+
description,
|
|
1022
|
+
provider,
|
|
1023
|
+
) {
|
|
1024
|
+
return new Promise((resolve) => {
|
|
1025
|
+
const initialPrompt = buildInteractiveInitialPrompt(
|
|
1026
|
+
projectName,
|
|
1027
|
+
description,
|
|
1028
|
+
provider,
|
|
1029
|
+
)
|
|
1030
|
+
|
|
1031
|
+
let command
|
|
1032
|
+
let args
|
|
1033
|
+
|
|
1034
|
+
switch (provider) {
|
|
1035
|
+
case "claude":
|
|
1036
|
+
command = "claude"
|
|
1037
|
+
args = [initialPrompt]
|
|
1038
|
+
break
|
|
1039
|
+
case "codex":
|
|
1040
|
+
command = "codex"
|
|
1041
|
+
args = [initialPrompt]
|
|
1042
|
+
break
|
|
1043
|
+
case "gemini":
|
|
1044
|
+
command = "gemini"
|
|
1045
|
+
args = ["-i", initialPrompt]
|
|
1046
|
+
break
|
|
1047
|
+
default:
|
|
1048
|
+
console.error(
|
|
1049
|
+
`❌ Interactive AI sessions are not supported for provider: ${provider}`,
|
|
1050
|
+
)
|
|
1051
|
+
resolve(false)
|
|
1052
|
+
return
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
console.log("")
|
|
1056
|
+
console.log("─".repeat(50))
|
|
1057
|
+
console.log(`🚀 Launching ${provider} in interactive mode...`)
|
|
1058
|
+
console.log("─".repeat(50))
|
|
1059
|
+
console.log("")
|
|
1060
|
+
console.log(
|
|
1061
|
+
" The agent will read this project's instruction files, greet you,",
|
|
1062
|
+
)
|
|
1063
|
+
console.log(
|
|
1064
|
+
" and ask what you want to build. Answer its questions — it will",
|
|
1065
|
+
)
|
|
1066
|
+
console.log(
|
|
1067
|
+
" keep asking until it has enough detail, then plan, confirm, and",
|
|
1068
|
+
)
|
|
1069
|
+
console.log(" implement. Exit the agent when you're done.")
|
|
1070
|
+
console.log("")
|
|
1071
|
+
|
|
1072
|
+
const child = spawn(command, args, {
|
|
1073
|
+
cwd: projectPath,
|
|
1074
|
+
stdio: "inherit",
|
|
1075
|
+
shell: true,
|
|
1076
|
+
})
|
|
1077
|
+
|
|
1078
|
+
child.on("close", (code) => {
|
|
1079
|
+
console.log("")
|
|
1080
|
+
console.log(`✅ ${provider} session ended.`)
|
|
1081
|
+
resolve(code === 0)
|
|
1082
|
+
})
|
|
1083
|
+
|
|
1084
|
+
child.on("error", (err) => {
|
|
1085
|
+
console.error(`❌ Failed to launch ${provider}: ${err.message}`)
|
|
1086
|
+
resolve(false)
|
|
1087
|
+
})
|
|
1088
|
+
})
|
|
1089
|
+
}
|
|
1090
|
+
|
|
956
1091
|
module.exports = {
|
|
957
1092
|
SCAFFOLD_SYSTEM_PROMPT,
|
|
958
1093
|
AI_PROVIDERS,
|
|
@@ -961,4 +1096,6 @@ module.exports = {
|
|
|
961
1096
|
applyScaffold,
|
|
962
1097
|
generateScaffold,
|
|
963
1098
|
runAIScaffolding,
|
|
1099
|
+
buildInteractiveInitialPrompt,
|
|
1100
|
+
launchInteractiveAISession,
|
|
964
1101
|
}
|