@saltcorn/copilot 0.8.1 → 0.8.3
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/actions/generate-page.js +6 -2
- package/actions/generate-tables.js +70 -6
- package/actions/generate-workflow.js +54 -3
- package/agent-skills/pagegen.js +171 -59
- package/agent-skills/registry-editor.js +30 -2
- package/agent-skills/triggergen.js +1 -5
- package/agent-skills/viewgen.js +49 -7
- package/app-constructor/common.js +7 -1
- package/app-constructor/errors.js +749 -61
- package/app-constructor/feedback-action.js +62 -60
- package/app-constructor/feedback.js +1294 -67
- package/app-constructor/fixed-prompts.js +829 -0
- package/app-constructor/phases.js +1485 -0
- package/app-constructor/prompt-generator.js +587 -0
- package/app-constructor/requirements.js +171 -50
- package/app-constructor/research.js +350 -0
- package/app-constructor/run_task.js +234 -73
- package/app-constructor/schema.js +173 -169
- package/app-constructor/tasks.js +96 -537
- package/app-constructor/tools.js +17 -4
- package/app-constructor/view.js +314 -54
- package/builder-gen.js +90 -41
- package/builder-schema.js +6 -0
- package/copilot-as-agent.js +1 -0
- package/index.js +0 -1
- package/js-code-gen.js +1 -0
- package/package.json +1 -1
- package/relation-paths.js +73 -40
- package/standard-prompt.js +1 -0
- package/user-copilot.js +2 -0
- package/workflow-gen.js +1 -0
- package/app-constructor/prompts.js +0 -120
- package/chat-copilot.js +0 -770
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
// Arrays of logical rules for the app constructor prompt system.
|
|
2
|
+
// Originals in prompts.js are kept intact; these will replace them in a future refactor.
|
|
3
|
+
// Join with "\n\n" to reproduce block-style sections.
|
|
4
|
+
|
|
5
|
+
const saltcorn_description = [
|
|
6
|
+
`This application will be implemented in Saltcorn, a database application development
|
|
7
|
+
environment.
|
|
8
|
+
|
|
9
|
+
Saltcorn applications contain the following entity types:`,
|
|
10
|
+
|
|
11
|
+
`* Tables: These are relational database tables and consist of fields of specified types
|
|
12
|
+
and rows with a value for each field. Fields optionally can be required and/or unique.
|
|
13
|
+
Every field has a name, which is an identifier that is valid in both JavaScript and SQL,
|
|
14
|
+
and a label, which is any short user-friendly string. Every table has a primary key
|
|
15
|
+
(composite primary keys are not supported) which by default is an auto-incrementing integer
|
|
16
|
+
with name \`id\` and label ID. The \`id\` primary key field is always unique and not-null by
|
|
17
|
+
definition — never set unique=true or not_null=true on it. Fields can also be of Key type
|
|
18
|
+
(foreign key) referencing a primary key in another table, or its own table for a self-join.
|
|
19
|
+
Tables can have calculated fields, which can be stored or non-stored. Both stored and
|
|
20
|
+
non-stored fields are defined by a JavaScript expression, but only stored fields can
|
|
21
|
+
reference other tables with join fields and aggregations.`,
|
|
22
|
+
|
|
23
|
+
`* Views: Views are elementary user interfaces into a database table. A view is defined by
|
|
24
|
+
applying a view template (also sometimes called a view pattern, the two are synonymous) to
|
|
25
|
+
a table with a certain configuration. The view template defines the fundamental relationship
|
|
26
|
+
between the UI and the table. For instance, the Show view template displays a single database
|
|
27
|
+
row, the Edit view template is a form that can create a new row or edit an existing row, the
|
|
28
|
+
List view template displays multiple rows in a grid. Views can embed views, for instance Show
|
|
29
|
+
can embed another row through a Key field relationship, or some views are defined by an
|
|
30
|
+
underlying view. For instance, the Feed view repeats an underlying view for multiple tables.
|
|
31
|
+
New viewtemplates are provided by plugin modules.`,
|
|
32
|
+
|
|
33
|
+
`* Triggers: Triggers connect elementary actions (provided by plugin modules) to either a
|
|
34
|
+
button in the user interface, or a periodic (hourly, daily etc) or table (for instance insert
|
|
35
|
+
on specific table) event. The elementary action each has a number of configuration fields
|
|
36
|
+
that must be filled in after connecting the action to an event, table or button.`,
|
|
37
|
+
|
|
38
|
+
`* Page: A page has static content but can also embed views for dynamic content. Pages can
|
|
39
|
+
be either defined by a Saltcorn layout, for pages that can be edited with drag and drop, or
|
|
40
|
+
by HTML for more flexible graphic designs. HTML pages should be used for landing pages.`,
|
|
41
|
+
|
|
42
|
+
`* Plugin modules: plugin modules can supply new field types, view templates or actions.
|
|
43
|
+
Before they can be used, they need to be installed. A plugin may also have a configuration
|
|
44
|
+
that sets options for that plugin. Layout themes in Saltcorn are plugin modules.`,
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
const task_planning_rules = [
|
|
48
|
+
"The plan should focus on building views, triggers (including workflows) and pages.",
|
|
49
|
+
|
|
50
|
+
`Important trigger planning rules:
|
|
51
|
+
* When a task involves a simple field update (e.g. marking an item complete or incomplete),
|
|
52
|
+
plan it as a trigger using modify_row — NOT a workflow. Use a workflow only when multiple
|
|
53
|
+
steps, branching, or looping are genuinely required.
|
|
54
|
+
* If multiple independent single-step actions are needed (e.g. "mark complete" and
|
|
55
|
+
"mark incomplete"), describe them as separate triggers in the task description — do not
|
|
56
|
+
describe them as one combined workflow.
|
|
57
|
+
* Do NOT mention "navigate back" or "return to context" in trigger task descriptions.
|
|
58
|
+
Navigation is configured at the view level (GoBack button), not inside a trigger.
|
|
59
|
+
* If a trigger should be accessible as a button in a view, prefer two separate tasks:
|
|
60
|
+
(1) a task that creates the trigger, (2) a task that updates the existing view to add an
|
|
61
|
+
action segment with action_name set to the trigger's name — this second task must depend on
|
|
62
|
+
the first. Only combine them into one task when the view is being created for the first
|
|
63
|
+
time in the same plan (i.e. the view does not yet exist), in which case the single
|
|
64
|
+
view-creation task must also add the action button and depend on the trigger task.
|
|
65
|
+
* Do NOT plan any task that uses run_bash_script or executes shell commands. If a requirement
|
|
66
|
+
seems to need a shell command (e.g. file conversion, PDF generation, sending email), look
|
|
67
|
+
for a Saltcorn plugin or built-in action that covers it instead.
|
|
68
|
+
* Only reference a plugin when no built-in action, field type, or view template covers the
|
|
69
|
+
requirement. Inserting rows, updating fields, looping, computing aggregates, and running
|
|
70
|
+
conditional logic are all covered by built-in workflow steps — only reach for a plugin when
|
|
71
|
+
there is no built-in equivalent. For example, do NOT use the 'sql' plugin to insert rows
|
|
72
|
+
or compute totals — use built-in workflow steps instead.
|
|
73
|
+
* Do NOT plan any task that writes to a virtual (read-only) calculated field. Virtual fields
|
|
74
|
+
are computed automatically and cannot be stored — any trigger or workflow that tries to
|
|
75
|
+
update them will be refused. If you find yourself planning a trigger to keep a calculated
|
|
76
|
+
field "current", delete that task — the field already updates itself.`,
|
|
77
|
+
|
|
78
|
+
`Important existing-entity rules:
|
|
79
|
+
* MANDATORY pre-flight check: before writing any task, scan the already-implemented pages
|
|
80
|
+
list above. If the page you are about to plan is already in that list, DO NOT add it —
|
|
81
|
+
planning a task to create an existing page is always wrong. This check must happen for
|
|
82
|
+
every page task, no exceptions.
|
|
83
|
+
* Before planning any view or page task, check the list of already-implemented views and
|
|
84
|
+
pages above. If an existing view or page already covers the required functionality — even
|
|
85
|
+
under a slightly different name — do NOT create a new one. Reference the existing entity by
|
|
86
|
+
its exact name in dependent tasks.
|
|
87
|
+
* Never create a new view that is a renamed variant of an existing one (e.g. prefixing with
|
|
88
|
+
"my_", "user_", "filtered_"). If the existing view needs filtering for a specific context,
|
|
89
|
+
embed it as-is and describe the filtering in the embedding page or view task.
|
|
90
|
+
* For every role's required dashboard or key page, verify it is either in the existing pages
|
|
91
|
+
list or has a task planned for it. A requirement that mentions a dashboard or home screen
|
|
92
|
+
for a role and has no corresponding existing page MUST have a task.
|
|
93
|
+
* If a page was previously created under one name and a requirement refers to the same concept
|
|
94
|
+
under a different name, use the existing page's actual name — do not plan a second page for
|
|
95
|
+
the same purpose.`,
|
|
96
|
+
|
|
97
|
+
`Important view planning rules:
|
|
98
|
+
* Each task must create exactly one view. Never put two or more views in the same task. Edit,
|
|
99
|
+
Show, and List for the same table are always three separate tasks with three separate names,
|
|
100
|
+
descriptions, and dependencies.
|
|
101
|
+
* Do NOT plan separate tasks for "create" and "edit" on the same table. In Saltcorn, a single
|
|
102
|
+
Edit view handles both (no id = create, id present = edit). One task, one Edit view,
|
|
103
|
+
description says "create and edit".
|
|
104
|
+
* Edit, Show, and List views for a table always go together as three separate tasks. Whenever
|
|
105
|
+
you plan a List view AND a Show view for the same table, you MUST also plan an Edit view for
|
|
106
|
+
that table — a List without an Edit leaves users unable to create or modify records. Only
|
|
107
|
+
omit the Edit view when the requirements explicitly say the data is read-only.
|
|
108
|
+
* The three tasks must be ordered: Edit and Show first (independent of each other, in any
|
|
109
|
+
order), List last. The List task MUST list both the Edit task and the Show task in its
|
|
110
|
+
depends_on — without exception. If you plan a List that depends on neither, that is a bug
|
|
111
|
+
in the plan.
|
|
112
|
+
* Before finalising the plan, for every List view task, verify that its depends_on includes
|
|
113
|
+
the corresponding Edit task and the corresponding Show task (if they exist). If either is
|
|
114
|
+
missing, add it.
|
|
115
|
+
* When a List view links to a Show view or Edit view, the task description must say: "Add a
|
|
116
|
+
viewlink column to [view_name] for the current row" — not just "link each row". This wording
|
|
117
|
+
makes it unambiguous that a viewlink column must be added to the list for each target view.
|
|
118
|
+
* Every link or viewlink that targets a Show view MUST include the row's \`id\` as a URL query
|
|
119
|
+
parameter (e.g. \`?id={{id}}\`). A Show view with no \`id\` in the URL displays "No row
|
|
120
|
+
selected". This applies to viewlinks in List views, page links, and any other navigation
|
|
121
|
+
pointing at a Show view.
|
|
122
|
+
* Every List view task description must include a delete action column unless the table is
|
|
123
|
+
explicitly read-only. State it explicitly: "Add a delete action column."
|
|
124
|
+
* In general, if a view embeds or links to another view, the linked view's task must be listed
|
|
125
|
+
as a dependency.
|
|
126
|
+
* When a table has foreign key fields referencing the users table, the task description must
|
|
127
|
+
explicitly state for each one whether it is an ownership field (automatically set from the
|
|
128
|
+
logged-in user, omit from the form) or a selector field (the user picks a value, include a
|
|
129
|
+
selector in the form). Example: "user_id records the owner and is set automatically;
|
|
130
|
+
shared_with_user_id must have a user selector."
|
|
131
|
+
* For FK fields that represent a parent context (e.g. trip_id on packing_items), always
|
|
132
|
+
include the field as a normal selector in the Edit view form. Do NOT say to omit it.
|
|
133
|
+
Saltcorn automatically pre-fills the selector from the URL query parameter when the view is
|
|
134
|
+
opened from a parent context, and the user can select it manually when the view is used
|
|
135
|
+
standalone.
|
|
136
|
+
* NEVER omit a NOT NULL (required) FK field from the Edit view form unless it references the
|
|
137
|
+
users table directly AND it is being used as an ownership field. Any other required FK field
|
|
138
|
+
— including FKs to non-user tables even if they are "set by the system" — MUST be included
|
|
139
|
+
as a selector in the form. A required field omitted from the form with no mechanism to set
|
|
140
|
+
it will produce a NOT NULL database error on save. "Will be set automatically" is not a
|
|
141
|
+
valid plan unless the field directly references the users table.
|
|
142
|
+
* For every task that creates a view, include the exact view name in the task description.
|
|
143
|
+
View names must be lowercase, snake_case, unique across all tasks in the plan, and
|
|
144
|
+
descriptive enough to identify the table and purpose — for example 'packing_items_edit'
|
|
145
|
+
rather than just 'edit'.
|
|
146
|
+
* Do NOT plan an Edit view for any table whose description says it is auto-populated or not
|
|
147
|
+
editable by users (e.g. audit logs, import/export job tracking tables). These tables may
|
|
148
|
+
have List and Show views for read-only visibility, but never an Edit view.`,
|
|
149
|
+
|
|
150
|
+
`Important user account rules:
|
|
151
|
+
* The platform (Saltcorn) provides a built-in user account system with login, registration,
|
|
152
|
+
and session management. Do NOT plan any tasks for user registration, login pages, password
|
|
153
|
+
management, authentication flows, or email verification — these are already handled by the
|
|
154
|
+
platform. Users register at /auth/signup and log in at /auth/login.
|
|
155
|
+
* User identity is always available as the logged-in user. Ownership fields (FK to users) are
|
|
156
|
+
set automatically from the session; no custom logic is needed.
|
|
157
|
+
* If a requirement mentions "user accounts", "secure login", "saving data per user",
|
|
158
|
+
"user-specific data", or "sharing between users", treat it as already satisfied by the
|
|
159
|
+
platform's built-in user system. Do not generate any task in response to such a requirement.
|
|
160
|
+
* Do NOT create any Edit, Show, or List view whose underlying table is the built-in \`users\`
|
|
161
|
+
table. The users table is managed entirely by the platform — records are created via
|
|
162
|
+
/auth/signup and managed via the platform's built-in admin panel. Never plan a task that
|
|
163
|
+
creates a view on the users table.`,
|
|
164
|
+
|
|
165
|
+
`Important date field rules:
|
|
166
|
+
* When a view task includes a date field that should pre-fill to today, the task description
|
|
167
|
+
must say to use "default_now": true in the flatpickr configuration — never "default":
|
|
168
|
+
"today".`,
|
|
169
|
+
|
|
170
|
+
`Important role rules:
|
|
171
|
+
* Every view and page task description MUST state the min_role explicitly, e.g. "Set min_role
|
|
172
|
+
to admin (1)." or "Set min_role to user (80).". Never omit it.
|
|
173
|
+
* Role values: admin=1, staff=40, user=80, public=100. Use the value that matches who will
|
|
174
|
+
use the view or page — admin (1) only for views that admins exclusively need (system config,
|
|
175
|
+
user management); staff (40) for views used by internal employees who are not admins (e.g.
|
|
176
|
+
lawyers, agents, staff members); user (80) for views used by logged-in non-staff users
|
|
177
|
+
(e.g. clients, customers, members); public (100) only when the page must be accessible
|
|
178
|
+
without login. Do not default everything to admin — setting min_role too restrictively
|
|
179
|
+
locks out the intended users.`,
|
|
180
|
+
|
|
181
|
+
`Important dashboard rules:
|
|
182
|
+
* A dashboard page that shows aggregate statistics (totals, counts, revenue, etc.) must NEVER
|
|
183
|
+
use client-side JavaScript fetch stubs or placeholder values. Every stat card must be backed
|
|
184
|
+
by a real Saltcorn Statistic view embedded with an embed-view tag.
|
|
185
|
+
* For each statistic shown on a dashboard, plan a separate Statistic view task (e.g.
|
|
186
|
+
"total_billable_hours_stat", "revenue_by_client_stat"). The dashboard page task must list
|
|
187
|
+
all these Statistic view tasks in its depends_on.
|
|
188
|
+
* Statistic view tasks must be planned before the dashboard page task and have descriptive
|
|
189
|
+
names that make their metric clear.
|
|
190
|
+
* No list view may be left orphaned. Every list view planned in the phase must be reachable
|
|
191
|
+
from at least one dashboard or page — embedded directly or linked via a navigation section.
|
|
192
|
+
Check each list view and confirm it appears in at least one page or dashboard task's
|
|
193
|
+
description.`,
|
|
194
|
+
|
|
195
|
+
`Important home page rules:
|
|
196
|
+
* Every role should land on the right page after visiting /. Plan a single task "Set home
|
|
197
|
+
pages by role" that depends on all relevant page tasks and configures home_page_by_role for
|
|
198
|
+
every role in one step.
|
|
199
|
+
* Role IDs: public=100, user=80, staff=40, admin=1.
|
|
200
|
+
* Landing/marketing page (public-facing intro): min_role must be 100 (public). It MUST include
|
|
201
|
+
visible links to /auth/login (Log in) and /auth/signup (Create an account). Set as home for
|
|
202
|
+
role 100 (public).
|
|
203
|
+
* If there is an admin dashboard page, set it as home for role 1 (admin).
|
|
204
|
+
* If there is a dashboard or main page for regular users or staff, set it as home for role 80
|
|
205
|
+
(user) and/or role 40 (staff) as appropriate.
|
|
206
|
+
* The "Set home pages by role" task description must list every role→page mapping explicitly
|
|
207
|
+
using the exact page names planned in this task list, e.g.: "Set home_page_by_role: public
|
|
208
|
+
(100) → landing, user (80) → client_dashboard, staff (40) → staff_dashboard, admin (1) →
|
|
209
|
+
app_admin_dashboard." Never use "admin_dashboard" as a page name — it is reserved by the
|
|
210
|
+
platform.`,
|
|
211
|
+
|
|
212
|
+
`Important bulk import/export rules:
|
|
213
|
+
* A plain Edit view creates or edits a single record — it is NOT a bulk import tool. Never
|
|
214
|
+
plan an Edit view as a solution for bulk data import.
|
|
215
|
+
* List views have no built-in export feature — do not plan an export button or column as part
|
|
216
|
+
of a list view.
|
|
217
|
+
* Bulk import and export functionality (e.g. CSV) must always be placed on a dedicated
|
|
218
|
+
management or admin page as embedded views, using whatever import/export viewtemplate is
|
|
219
|
+
available from an installed plugin.
|
|
220
|
+
* Bulk import and bulk export for the same table are always two separate tasks with two
|
|
221
|
+
separate view names. Never combine them into a single task.`,
|
|
222
|
+
|
|
223
|
+
`Important plugin rules:
|
|
224
|
+
* If multiple plugins need to be installed, combine them ALL into a single task named
|
|
225
|
+
"Install plugins" that lists every required plugin name. Do NOT create a separate task per
|
|
226
|
+
plugin.`,
|
|
227
|
+
|
|
228
|
+
`Important dependency rules:
|
|
229
|
+
* Every name in a task's depends_on MUST exactly match the name field of another task in the
|
|
230
|
+
same plan_tasks call. Never reference a name that is not present in the tasks array — not a
|
|
231
|
+
concept, not a table name, not a made-up label. If you find yourself writing a depends_on
|
|
232
|
+
entry whose name does not appear as a task name in the list, either add the missing task or
|
|
233
|
+
remove the dependency.
|
|
234
|
+
* Before calling plan_tasks, mentally verify: for every task, every name in its depends_on
|
|
235
|
+
array appears as the name of another task in the array.
|
|
236
|
+
* Before calling plan_tasks, check for circular dependencies. A circular dependency means task
|
|
237
|
+
A depends on B, and B depends on A (directly or transitively). A circular dependency causes
|
|
238
|
+
a deadlock — neither task can ever start. To fix it: identify which dependency in the cycle
|
|
239
|
+
is the weakest (i.e. view A only needs to embed view B, but B does not strictly require A
|
|
240
|
+
to exist). Remove that dependency from A's depends_on so A can be created first. Then decide
|
|
241
|
+
whether B's content is still useful without being embedded in A at creation time. If the
|
|
242
|
+
embed is important, add a separate update task (e.g. "update_A_embed_B") whose description
|
|
243
|
+
says to update view A to embed view B, and whose depends_on lists both A and B. Only add
|
|
244
|
+
this extra update task when the embed is genuinely important for the finished product — do
|
|
245
|
+
not create update tasks for minor or optional embeds, as each extra task is expensive. A
|
|
246
|
+
good rule of thumb: add an update task only if omitting the embed from the final view would
|
|
247
|
+
visibly break a user workflow.`,
|
|
248
|
+
|
|
249
|
+
`Important email rules:
|
|
250
|
+
* Use the built-in \`send_email\` trigger action to send emails. SMTP configuration (host,
|
|
251
|
+
credentials, sender address) is managed by the platform administrator in System
|
|
252
|
+
Configuration — it is not an application concern. Do NOT create any table for SMTP or email
|
|
253
|
+
settings, and do NOT plan any task to configure SMTP.
|
|
254
|
+
* Every \`{{}}\` interpolation in any workflow step (email body, email subject, filename,
|
|
255
|
+
prompt template, etc.) must reference a variable that already exists in the workflow context
|
|
256
|
+
at the point the step runs. Do NOT use fallback expressions such as
|
|
257
|
+
\`{{invoice_date || new Date().toISOString()}}\` — if the variable is not defined, the
|
|
258
|
+
interpolation engine throws before the \`||\` fallback can execute. If a value might not be
|
|
259
|
+
in context at that point, retrieve or compute it in an earlier step and store it under a
|
|
260
|
+
known key.`,
|
|
261
|
+
|
|
262
|
+
`Important schema/table rules:
|
|
263
|
+
* The database schema is already fully designed and implemented before task planning begins.
|
|
264
|
+
ALL tables and fields needed by the application already exist. Do NOT plan any tasks that
|
|
265
|
+
create tables, add fields, modify fields, or change the schema in any way. If you find
|
|
266
|
+
yourself writing a task whose output is a table or a field, delete it — that work is
|
|
267
|
+
already done.
|
|
268
|
+
* Ownership behaviour (auto-setting a FK-to-users field from the logged-in user) is configured
|
|
269
|
+
in the Edit view, not in the database. Do not create tasks for it at the schema level.
|
|
270
|
+
* Do NOT plan tasks to add uniqueness constraints or validation to existing fields — those are
|
|
271
|
+
already in the schema.
|
|
272
|
+
* Do NOT plan a standalone task for "access control", "row-level security", "permissions", or
|
|
273
|
+
"roles". These are schema-level concerns already handled during schema design, or view-level
|
|
274
|
+
concerns handled when building each view. The ownership field and sharing logic are already
|
|
275
|
+
in the schema — there is nothing extra to configure as a separate task.`,
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
const implementation_rules = [
|
|
279
|
+
`Important: JsCode server-mode views run on the server and must return an HTML string.
|
|
280
|
+
The following globals are available: Table, View, User, File, db, user, req, state,
|
|
281
|
+
markupTags, Actions, emitEvent, moment.
|
|
282
|
+
The state object contains URL query parameters — use state.start_date, state.end_date etc.
|
|
283
|
+
to read user inputs submitted via a GET form.
|
|
284
|
+
Never use process.env, window, document, or fetch in server mode. Never return a
|
|
285
|
+
{ code: "..." } object — always return an HTML string.
|
|
286
|
+
require() is NOT available — do not import lodash or any other module. Use moment or plain
|
|
287
|
+
JavaScript Date for all date formatting and arithmetic.`,
|
|
288
|
+
|
|
289
|
+
`Important: Workflow TableQuery steps can only query user-created application tables.
|
|
290
|
+
Internal Saltcorn system tables whose names start with _sc_ (such as _sc_files,
|
|
291
|
+
_sc_triggers, _sc_views, _sc_pages, etc.) are NOT registered as application tables and will
|
|
292
|
+
throw "Table X not found" at runtime if used in a TableQuery step.`,
|
|
293
|
+
|
|
294
|
+
`Important: After a page_to_pdf workflow step with to_file=true, the workflow context
|
|
295
|
+
automatically contains pdf_file_id (the database id of the saved file) and pdf_path_to_serve.
|
|
296
|
+
No extra run_js_code or TableQuery step is needed to look up the file — just use pdf_file_id
|
|
297
|
+
directly in the following modify_row step.`,
|
|
298
|
+
|
|
299
|
+
`Important: Any export or output step (PDF generation, CSV export, email with attached data,
|
|
300
|
+
etc.) reads the database at the moment it runs. It will only reflect rows that already exist
|
|
301
|
+
at that point. Always place every export/output step AFTER all insert, update, and aggregate
|
|
302
|
+
steps that produce the data it needs to include. The correct order is: (1) insert/update all
|
|
303
|
+
rows, (2) compute and store aggregates, (3) export/output, (4) send notifications (if needed).
|
|
304
|
+
Moving an export step earlier — for example right after inserting a parent row but before its
|
|
305
|
+
child rows are inserted — will produce empty or incomplete output even though the data looks
|
|
306
|
+
correct when viewed in the browser later.`,
|
|
307
|
+
|
|
308
|
+
`Important: The workflow step_type for running custom JavaScript is \`run_js_code\`
|
|
309
|
+
(snake_case). Do NOT use \`RunJsCode\` or any PascalCase variant — those will throw "Action
|
|
310
|
+
or trigger not found" at runtime. Built-in step types (TableQuery, ForLoop, SetContext, etc.)
|
|
311
|
+
are PascalCase, but run_js_code is the exception and must always be written in snake_case.`,
|
|
312
|
+
|
|
313
|
+
`Important: Saltcorn where-clause objects use nested operator objects — NEVER use
|
|
314
|
+
space-separated key suffixes. Space-separated keys like \`"entry_date >="\` or
|
|
315
|
+
\`"project_id in"\` are stripped by sqlSanitize (spaces are removed), producing invalid column
|
|
316
|
+
names like \`entry_date>=\` or \`project_idin\` that crash Postgres.
|
|
317
|
+
The correct operators are: \`{field: {gt: value}}\` for >, \`{field: {gt: value, equal: true}}\`
|
|
318
|
+
for >=, \`{field: {lt: value}}\` for <, \`{field: {lt: value, equal: true}}\` for <=,
|
|
319
|
+
\`{field: {in: [...array...]}}\` for IN (generates \`field = ANY($1)\`),
|
|
320
|
+
\`{field: null}\` for IS NULL.
|
|
321
|
+
This applies in both JsCode and workflow TableQuery steps.`,
|
|
322
|
+
|
|
323
|
+
`Important: To add an action button to a Show view, add a segment directly into the
|
|
324
|
+
\`layout.above\` array — do NOT add to the top-level \`actions\` array alone.
|
|
325
|
+
The \`actions\` array is metadata only; it does NOT render any button.
|
|
326
|
+
The layout segment that renders the button looks like:
|
|
327
|
+
\`{"type": "action", "rndid": "act1", "action_name": "trigger_name", "action_label": "Label",
|
|
328
|
+
"action_style": "btn-primary", "confirm": true, "minRole": 40}\`.
|
|
329
|
+
CRITICAL: every action segment MUST include a \`rndid\` field — a short unique string such as
|
|
330
|
+
"act1", "act2", "issue_inv", etc. If \`rndid\` is missing or undefined, the button will be
|
|
331
|
+
rendered but clicking it sends \`rndid: "undefined"\` to the server, which crashes with
|
|
332
|
+
"Cannot read properties of undefined (reading 'action_name')". Never omit \`rndid\`.
|
|
333
|
+
Each action segment in the same layout must have a different \`rndid\`.
|
|
334
|
+
The \`action_name\` must exactly match the trigger's name. The \`actions\` array entry is
|
|
335
|
+
optional and can be omitted entirely.
|
|
336
|
+
When the trigger was created in the same plan, copy its name verbatim from the trigger task's
|
|
337
|
+
description or name field — do not paraphrase, abbreviate, or infer it.
|
|
338
|
+
When the trigger already exists, read its exact name from the existing triggers list — never
|
|
339
|
+
guess based on what you think the name should be.`,
|
|
340
|
+
|
|
341
|
+
`Important: When a trigger is invoked from a Show view action button, the trigger MUST have
|
|
342
|
+
its \`table\` set to the view's table. Saltcorn will then automatically pass the full row as
|
|
343
|
+
the initial workflow context — every field value is available by its field name (e.g. \`id\`,
|
|
344
|
+
\`name\`, \`contact_email\`). Do NOT attempt to pass row data through a \`state\` property on
|
|
345
|
+
the \`actions\` array entry — that property is not supported and is silently ignored.
|
|
346
|
+
If the trigger has no table set, the workflow starts with no context and all field references
|
|
347
|
+
will throw "is not defined".`,
|
|
348
|
+
|
|
349
|
+
`Important: Some fields are non-stored (virtual) calculated fields — they have no database
|
|
350
|
+
column and are computed on-the-fly by Saltcorn. Never include such fields in modify_row, SQL
|
|
351
|
+
UPDATE statements, or recalculate_stored_fields calls. Only fields that exist as actual
|
|
352
|
+
database columns (regular fields and stored calculated fields) can be written. If a calculated
|
|
353
|
+
field needs updating, it will refresh automatically when the fields it depends on change.`,
|
|
354
|
+
|
|
355
|
+
`Important: When a Show view needs to display related rows (e.g. an invoice showing its line
|
|
356
|
+
items), embed a List view for those related rows — NOT an Edit view. Embedding an Edit view
|
|
357
|
+
inside a Show view is almost never correct: it renders a form with inputs, save buttons, and
|
|
358
|
+
date pickers inline in a read display. The only rare exception is an intentional inline-edit
|
|
359
|
+
pattern where the user explicitly needs to edit related rows directly inside the parent Show
|
|
360
|
+
view. For all other cases — displaying related data, print pages, dashboards — use a List view.
|
|
361
|
+
If no suitable List view exists yet, plan a separate List view task for the related table and
|
|
362
|
+
list it in depends_on before the Show view task.`,
|
|
363
|
+
|
|
364
|
+
`Important: Do NOT use the GoBack action for cancel buttons in Edit views. The GoBack action
|
|
365
|
+
always calls history.back(), which breaks when the view is opened inside a popup modal.
|
|
366
|
+
Instead, add a link segment with url set to the following JavaScript — it closes the Saltcorn
|
|
367
|
+
modal (#scmodal) if one is open, and falls back to history.back() for standalone use:
|
|
368
|
+
javascript:var m=document.getElementById('scmodal');var mi=m&&bootstrap.Modal.getInstance(m);if(mi)mi.hide();else history.back()
|
|
369
|
+
— style it as btn btn-outline-secondary to match the standard cancel appearance.`,
|
|
370
|
+
|
|
371
|
+
`Important: In List view create_view_showif expressions (and any other showif / formula
|
|
372
|
+
fields evaluated against the URL state), the variable \`state\` does NOT exist. The state
|
|
373
|
+
object is passed as \`row\`, and each key of the state is also available as a bare variable.
|
|
374
|
+
Use \`row.project_id\` or just \`project_id\` — never \`state.project_id\`.`,
|
|
375
|
+
|
|
376
|
+
`Important: A Saltcorn modify_row trigger has exactly these configuration fields:
|
|
377
|
+
\`name\` (string), \`action\` = "modify_row", \`when_trigger\` ("Insert" or "Update" — NEVER
|
|
378
|
+
"Validate"), optionally \`table_name\`, and \`configuration.row_expr\` — a single-line JS
|
|
379
|
+
expression returning an object of field→value pairs.
|
|
380
|
+
Example: \`{hours: Math.round(parseFloat(hours) * 100) / 100}\`.
|
|
381
|
+
Do NOT invent other formats (no \`match\`, \`actions\`, \`set\`, \`columns\` keys — those belong
|
|
382
|
+
to other platforms). NEVER use \`when_trigger: "Validate"\` with modify_row — Validate fires
|
|
383
|
+
before the row exists in the database so there is no id to update, causing a crash on insert.
|
|
384
|
+
Use \`when_trigger: "Insert"\` to normalise on new rows, and a separate
|
|
385
|
+
\`when_trigger: "Update"\` trigger if normalisation is also needed on edits.
|
|
386
|
+
Keys in the row_expr object MUST be bare field names — NEVER table-qualified names like
|
|
387
|
+
\`{"table_name.field_name": value}\`. Table-qualified names are silently mangled by SQL
|
|
388
|
+
sanitization (the dot is stripped), producing a non-existent column name and a runtime error.
|
|
389
|
+
Use only \`{field_name: value}\`.`,
|
|
390
|
+
|
|
391
|
+
`Important: modify_row \`row_expr\` values and all other formula/expression fields are parsed
|
|
392
|
+
as a single JavaScript expression by acorn. They MUST be written on one line — no literal
|
|
393
|
+
newlines anywhere in the expression, including inside string literals. A literal newline
|
|
394
|
+
inside a quoted string causes "Unterminated string constant" and crashes the trigger.
|
|
395
|
+
Write the entire expression on a single line: \`{field1: expr1, field2: expr2}\`.
|
|
396
|
+
This single-line rule applies ONLY to \`row_expr\` and similar single-expression fields —
|
|
397
|
+
NOT to \`run_js_code\` steps in workflows. Workflow \`run_js_code\` code is a full JavaScript
|
|
398
|
+
function body and must use real newlines (encoded as \`\\n\` in JSON). Never write literal
|
|
399
|
+
backslash-n (\`\\\\n\`) inside \`run_js_code\` code to simulate newlines — vm2 will reject it
|
|
400
|
+
with "Expecting Unicode escape sequence".`,
|
|
401
|
+
|
|
402
|
+
`Important: In workflow TerminateWorkflow steps, the "return value" / error message field is
|
|
403
|
+
evaluated as a JavaScript expression — it is NOT plain text. Always wrap the message in
|
|
404
|
+
quotes: \`"No billable hours found."\`. A bare unquoted sentence causes a SyntaxError at
|
|
405
|
+
runtime.`,
|
|
406
|
+
|
|
407
|
+
`Important: When a workflow step inserts a row (e.g. \`insert_any_row\`, \`upsert_one\`), the
|
|
408
|
+
row expression MUST include a value for every NOT NULL field (marked as NOT NULL in the table
|
|
409
|
+
listing above) that has no database default. A NOT NULL field that has a default value (shown
|
|
410
|
+
as "default: X" in the table listing) can be safely omitted — the database will fill it in
|
|
411
|
+
automatically. Omitting a NOT NULL field causes a "null value in column X violates not-null
|
|
412
|
+
constraint" error at runtime. If the real value is computed in a later step (e.g. a total
|
|
413
|
+
calculated after inserting line items), supply a safe placeholder — \`0\` for numeric fields,
|
|
414
|
+
\`''\` for text — so the initial insert succeeds, then update the row in the subsequent step.
|
|
415
|
+
Exception: File-type fields hold a file ID and cannot be given a placeholder value — always
|
|
416
|
+
declare File fields as \`required: false\` (nullable) unless the file is guaranteed to exist
|
|
417
|
+
at the moment the row is first inserted.`,
|
|
418
|
+
|
|
419
|
+
`Important: In Show view layouts, every field must be its own separate segment with
|
|
420
|
+
\`"type": "field"\` (singular). There is NO \`"type": "fields"\` (plural) segment — using it
|
|
421
|
+
crashes with "unknown layout segment" at runtime. Never bundle multiple fields into a single
|
|
422
|
+
segment. Each field appears as an individual element in the layout array, for example:
|
|
423
|
+
\`{"type": "field", "field_name": "invoice_date", "fieldview": "show"}\`.`,
|
|
424
|
+
];
|
|
425
|
+
|
|
426
|
+
const fieldview_selection_rules = [
|
|
427
|
+
`For numeric fields (Integer, Float, Money, Decimal) the default fieldview is "edit" — a
|
|
428
|
+
plain text input. Only use a specialised numeric fieldview (e.g. "number_slider", "range",
|
|
429
|
+
"spin") when it is clearly appropriate for the data: a slider makes sense for a bounded
|
|
430
|
+
rating or percentage, not for an open-ended value like a price, rate, or quantity. The
|
|
431
|
+
existence of an alternative fieldview in the platform is not a reason to use it — "edit" is
|
|
432
|
+
the right default and should be the first choice unless there is a specific UX reason to do
|
|
433
|
+
otherwise.`,
|
|
434
|
+
|
|
435
|
+
`For date fields always prefer fieldview "flatpickr" when available — it provides the best
|
|
436
|
+
user experience and works for both regular dates and day-only dates. Only use fieldview
|
|
437
|
+
"edit_day" as a fallback when the field has day_only=true and flatpickr is not installed.
|
|
438
|
+
Never set a flatpickr configuration key "default" to a string like "today" — it is not a
|
|
439
|
+
valid date value and will throw at runtime. To pre-fill the picker with the current date/time,
|
|
440
|
+
set "default_now": true in the flatpickr field configuration instead. When the underlying
|
|
441
|
+
Date field has day_only=true, also set "day_only": true in the flatpickr fieldview
|
|
442
|
+
configuration — this disables the time picker and formats the value correctly.`,
|
|
443
|
+
|
|
444
|
+
`For String fields that have an options attribute (a comma-separated list of fixed choices),
|
|
445
|
+
use fieldview "select" — this renders a dropdown with those options. Do not use
|
|
446
|
+
"select_by_code" for fields with fixed options.`,
|
|
447
|
+
|
|
448
|
+
`File-type fields use dedicated fieldviews — never the generic "edit" or "show" fieldview.
|
|
449
|
+
In edit/form views use "upload" (file input) or "select" (pick existing file). In read-only
|
|
450
|
+
views (Show, List) use "Download link", "Link", "Show Image", or "Thumbnail". Using "edit"
|
|
451
|
+
or "show" on a File field causes a runtime error.`,
|
|
452
|
+
];
|
|
453
|
+
|
|
454
|
+
const task_planning_closing = [
|
|
455
|
+
`Your plan should not include any clarification or questions to the product owner. The
|
|
456
|
+
information you have been given so far is all that is available. Every step in the plan
|
|
457
|
+
should be immediately implementable in Saltcorn. You are writing the steps in the plan for a
|
|
458
|
+
person who is competent in using saltcorn but has no other business knowledge.`,
|
|
459
|
+
|
|
460
|
+
`Do not include any steps that contain planning, design or review instructions. You are only
|
|
461
|
+
writing a plan for the engineer building the application. Every step in the plan should have
|
|
462
|
+
the construction or the modification of one or several application entity types.`,
|
|
463
|
+
|
|
464
|
+
`Description length: keep descriptions concise. Simple tasks (a single view, trigger, or
|
|
465
|
+
page) need only 1–3 sentences. Complex tasks (multi-step workflows, views with several
|
|
466
|
+
embedded components) may use more, but stop once all actionable specifics are covered — do
|
|
467
|
+
not re-explain steps already implied by the context, add parenthetical asides, or repeat the
|
|
468
|
+
same point in different words. Never pad a short task description just to appear thorough.`,
|
|
469
|
+
];
|
|
470
|
+
|
|
471
|
+
const req_gen_rules = [
|
|
472
|
+
`Important rules for generating requirements:
|
|
473
|
+
* Every requirement must be directly traceable to something stated in the description,
|
|
474
|
+
audience, or core features above. Do not infer, invent, or add features that are not
|
|
475
|
+
explicitly mentioned — even if they seem like an obvious addition.
|
|
476
|
+
* Do not generate any requirement that falls under the Out of scope section above.
|
|
477
|
+
* Only generate requirements for core functionality. Do not generate requirements for
|
|
478
|
+
features described as optional, "nice to have", "could support", or "can be added
|
|
479
|
+
later" — omit them entirely.
|
|
480
|
+
* Do NOT generate a requirement for integration with any external third-party system
|
|
481
|
+
(e.g. QuickBooks, Xero, Stripe, Slack, external APIs, webhooks) unless the
|
|
482
|
+
specification explicitly names the system AND describes exactly what must be
|
|
483
|
+
exchanged. A vague mention like "integration with accounting systems" is not
|
|
484
|
+
sufficient — skip it.
|
|
485
|
+
* Do not generate requirements that are already handled by the platform (e.g. user
|
|
486
|
+
registration, login, password management — these are built-in).
|
|
487
|
+
* Priority reflects how central the feature is to the core purpose of the application.
|
|
488
|
+
Assign 5 to features without which the application cannot function at all, 3–4 to
|
|
489
|
+
features that are important but not blocking, 1–2 to minor convenience features. Do
|
|
490
|
+
not assign 5 to everything.`,
|
|
491
|
+
];
|
|
492
|
+
|
|
493
|
+
const phase_gen_rules = [
|
|
494
|
+
`Rules for generating phases and their requirements:
|
|
495
|
+
* Break the application into 3–6 phases. Fewer is better — only split where there is a
|
|
496
|
+
genuine dependency boundary or a meaningful delivery milestone.
|
|
497
|
+
* Every requirement must be directly traceable to something stated in the specification.
|
|
498
|
+
Do not infer, invent, or add features that are not explicitly mentioned.
|
|
499
|
+
* Only include requirements for core functionality. Omit anything described as optional,
|
|
500
|
+
"nice to have", or "can be added later".
|
|
501
|
+
* Do NOT include requirements for integration with external third-party systems unless
|
|
502
|
+
the specification explicitly names the system and describes exactly what must be
|
|
503
|
+
exchanged.
|
|
504
|
+
* Do not include requirements already handled by the platform. Saltcorn provides
|
|
505
|
+
built-in user registration (/auth/signup), login (/auth/login), password management,
|
|
506
|
+
and role-based access control — do not generate requirements to build custom versions
|
|
507
|
+
of these. Application pages such as a landing page or a dashboard are valid
|
|
508
|
+
requirements and must be included; a landing page will naturally link to /auth/login
|
|
509
|
+
and /auth/signup.
|
|
510
|
+
* Priority reflects how central the requirement is to the core purpose of its phase.
|
|
511
|
+
Assign 5 to requirements without which the phase cannot be considered done, 3–4 to
|
|
512
|
+
important but not blocking, 1–2 to minor enhancements. Do not assign 5 to everything.
|
|
513
|
+
* Each phase's requirements must be self-contained: a later phase may depend on earlier
|
|
514
|
+
phases having been built, but should not require anything from future phases.
|
|
515
|
+
* Place foundational data and authentication requirements in the earliest phase.`,
|
|
516
|
+
];
|
|
517
|
+
|
|
518
|
+
const phase_scope_rule =
|
|
519
|
+
"Plan only the tasks needed to implement the requirements listed above. Do not plan\n" +
|
|
520
|
+
"tasks for requirements belonging to other phases. This applies especially to database\n" +
|
|
521
|
+
"tables — do not create a table unless it is directly needed by a requirement listed\n" +
|
|
522
|
+
"above, even if you can tell it will be needed in a later phase.";
|
|
523
|
+
|
|
524
|
+
const no_roles_table_rule =
|
|
525
|
+
"Important: Do NOT plan any task that creates a Roles table, a permissions table, or\n" +
|
|
526
|
+
"any table describing what roles are allowed to do. Saltcorn has a built-in role system\n" +
|
|
527
|
+
"(1=admin, 40=staff, 80=user, 100=public) and every entity (view, page, table) already\n" +
|
|
528
|
+
"has a min_role property for access control. There is nothing to store in the database\n" +
|
|
529
|
+
"— access control is configured on each entity directly.";
|
|
530
|
+
|
|
531
|
+
const exec_tool_call_rule =
|
|
532
|
+
"Important: Every tool call must contain only the final, complete result — never\n" +
|
|
533
|
+
"intermediate reasoning, planning notes, markdown code fences, TODO comments, or\n" +
|
|
534
|
+
"placeholder text. Compose the full content in your reasoning first, then pass only\n" +
|
|
535
|
+
"the finished result to the tool. A page or view that contains any of these is\n" +
|
|
536
|
+
"broken and will be visible to end users exactly as written.";
|
|
537
|
+
|
|
538
|
+
const exec_schema_rule_plugin =
|
|
539
|
+
"Important: This is a plugin installation task. Install the plugin described using\n" +
|
|
540
|
+
"the Install Plugin skill. Do not create tables, views, pages, or triggers.";
|
|
541
|
+
|
|
542
|
+
const exec_schema_rule_data_model =
|
|
543
|
+
"Important: This is a data model task. Use the database design tool to create or\n" +
|
|
544
|
+
"modify tables and fields, or use the Registry editor (set_entity) for platform\n" +
|
|
545
|
+
"configuration such as creating custom roles. Do not create any views, pages, or\n" +
|
|
546
|
+
"triggers — only schema and platform configuration changes belong in this task.";
|
|
547
|
+
|
|
548
|
+
const exec_schema_rule_feature =
|
|
549
|
+
"Important: This is a feature task. Do NOT use generate_tables or modify any tables\n" +
|
|
550
|
+
"or fields — schema changes are handled by separate data model tasks that run\n" +
|
|
551
|
+
"before this one.";
|
|
552
|
+
|
|
553
|
+
const plugin_type_instruction = [
|
|
554
|
+
`Generate ONLY tasks with task_type "plugin" — tasks that install plugins from the
|
|
555
|
+
Saltcorn plugin store.`,
|
|
556
|
+
|
|
557
|
+
`Before deciding which plugins to plan, carefully read the full application specification
|
|
558
|
+
and phase requirements and reason through what the application will need. Do not wait for
|
|
559
|
+
keywords — infer from context:
|
|
560
|
+
- Will the application store or display dates or times in any form? (e.g. entry dates,
|
|
561
|
+
deadlines, schedules, appointments, logs) → a date/time picker plugin will be needed
|
|
562
|
+
- Will the application handle money, rates, prices, fees, invoices, or any numeric value
|
|
563
|
+
representing a currency or billing amount? → a money or decimal field plugin will be needed
|
|
564
|
+
- Will any entity be related to multiple instances of another entity in both directions?
|
|
565
|
+
(e.g. lawyers assigned to projects, products in orders) → a many-to-many plugin will be needed
|
|
566
|
+
- Will users enter or display formatted or multi-line text beyond a plain string?
|
|
567
|
+
→ a rich text editor plugin will be needed
|
|
568
|
+
- Will any page show charts, graphs, totals, or aggregated statistics?
|
|
569
|
+
→ a chart plugin will be needed
|
|
570
|
+
- Will the application deal with physical locations, addresses, or maps?
|
|
571
|
+
→ a map plugin will be needed
|
|
572
|
+
- Will users upload or attach files or images? → a file upload plugin will be needed
|
|
573
|
+
For each need you identify, check the available plugin list above for a matching plugin that
|
|
574
|
+
is not already installed, and plan a task for it.`,
|
|
575
|
+
|
|
576
|
+
`Critical: only plan a plugin installation task when the built-in actions, field types,
|
|
577
|
+
and view templates genuinely cannot cover the requirement. Inserting rows, updating fields,
|
|
578
|
+
running workflow steps, and computing aggregates are all covered by built-in workflow actions
|
|
579
|
+
— only install a plugin when no built-in equivalent exists. For example, do NOT install the
|
|
580
|
+
'sql' plugin to insert rows or compute totals — use built-in workflow steps instead.`,
|
|
581
|
+
|
|
582
|
+
"Each task installs exactly one plugin. If no plugins are needed, call plan_tasks with an empty tasks array.",
|
|
583
|
+
];
|
|
584
|
+
|
|
585
|
+
const data_model_type_instruction = [
|
|
586
|
+
`Generate ONLY tasks with task_type "data_model" — tasks that create or modify database
|
|
587
|
+
tables or fields. Do not generate any feature tasks.`,
|
|
588
|
+
|
|
589
|
+
`Each task should implement exactly one deliverable — one table or a closely related set of
|
|
590
|
+
fields. Keep tasks small and focused. Tasks may depend on other tasks within this phase using
|
|
591
|
+
the depends_on field.`,
|
|
592
|
+
|
|
593
|
+
`Critical: only create tables and fields that are directly required by the requirements of
|
|
594
|
+
THIS phase listed above. Do not anticipate future phases or add tables speculatively because
|
|
595
|
+
they will eventually be needed. If a requirement is not listed above, it belongs to another
|
|
596
|
+
phase — do not implement it here.`,
|
|
597
|
+
|
|
598
|
+
`Important: Each task description must fully specify uniqueness (unique=true) and required
|
|
599
|
+
(not_null=true) constraints on every field — do not leave these for a later step. Never
|
|
600
|
+
mention constraints on the 'id' field — it is the primary key and is always unique and
|
|
601
|
+
not-null by definition.`,
|
|
602
|
+
|
|
603
|
+
"Important: Ownership (auto-populating a FK-to-users field from the logged-in user) is a view-level concern — task descriptions must not mention it. Just describe the FK field normally.",
|
|
604
|
+
|
|
605
|
+
"Important: Do NOT plan any task that creates a table for SMTP, email configuration, or mail server credentials — email config is managed by the platform administrator.",
|
|
606
|
+
];
|
|
607
|
+
|
|
608
|
+
const feature_type_instruction = [
|
|
609
|
+
`Generate ONLY tasks with task_type "feature" — tasks that create views, pages, triggers,
|
|
610
|
+
or workflows. Do not generate any data_model tasks.`,
|
|
611
|
+
];
|
|
612
|
+
|
|
613
|
+
const error_fix_closing = [
|
|
614
|
+
"Either call plan_tasks with exactly one fix task, or call cannot_fix if you cannot " +
|
|
615
|
+
"determine a concrete fix from the information above. Do not invent a task just to " +
|
|
616
|
+
"produce output — prefer cannot_fix over a vague or speculative task.",
|
|
617
|
+
|
|
618
|
+
"Rules for the plan_tasks description (only if you can diagnose the fix):\n" +
|
|
619
|
+
"- Name the exact Saltcorn entity (view, trigger, page) to fix.\n" +
|
|
620
|
+
"- Describe what is wrong and what kind of fix is needed. Where you can clearly identify " +
|
|
621
|
+
"them from the config shown above, state each broken field, its current value, and the correct value. " +
|
|
622
|
+
"If you are not certain of the exact values, describe the problem instead — do not guess specific values.\n" +
|
|
623
|
+
"- Cover ALL fields of the same error class in one task.\n" +
|
|
624
|
+
"- Prefer fixing a broken reference over removing the element that contains it. " +
|
|
625
|
+
"Only remove an element when there is genuinely no valid replacement. " +
|
|
626
|
+
"Example: a viewlink column referencing a missing view should have its view name " +
|
|
627
|
+
"updated to an existing view — not have the column deleted.\n" +
|
|
628
|
+
"- End with: 'Use get_entity to load the current config, diagnose the exact values, apply the fix, and save with set_entity.'\n" +
|
|
629
|
+
"- One or two sentences. No prose, no save/test instructions.",
|
|
630
|
+
];
|
|
631
|
+
|
|
632
|
+
const feature_exec_rules = [
|
|
633
|
+
`Important: The "users" table is built-in. Passwords are platform-managed — never add
|
|
634
|
+
a password field to a view. Signup uses the built-in page at /auth/signup, login at
|
|
635
|
+
/auth/login. Do NOT create triggers for registration or email verification — the
|
|
636
|
+
platform handles this natively. Do NOT create any Edit, Show, or List view whose
|
|
637
|
+
underlying table is the built-in users table — user records are managed entirely by
|
|
638
|
+
the platform.`,
|
|
639
|
+
|
|
640
|
+
`Important: On landing pages, place Log in / Create account buttons in no more than
|
|
641
|
+
two locations (e.g. navbar and one hero call-to-action). Do not repeat them in a third
|
|
642
|
+
"Get started" section or anywhere else. For links that take an already-authenticated
|
|
643
|
+
user to their dashboard, use href="/" — not /auth/login.`,
|
|
644
|
+
|
|
645
|
+
`Important: Saltcorn page URLs always use the prefix /page/. To link to a page named
|
|
646
|
+
"teacher_dashboard", the href must be "/page/teacher_dashboard" — NOT "/teacher_dashboard".
|
|
647
|
+
This applies to every link, button, or navigation item that points to a Saltcorn page,
|
|
648
|
+
regardless of where the link appears (landing page, navbar, other pages, etc.).
|
|
649
|
+
Views use /view/view_name — also with the /view/ prefix, not a bare name.`,
|
|
650
|
+
|
|
651
|
+
`Important: Do not name any page or view "Admin dashboard" — that name is reserved by
|
|
652
|
+
the Saltcorn platform. For pages intended for role 1 (admin), use a name like "App
|
|
653
|
+
admin dashboard" or prefix it with the application name (e.g. "Law Firm admin
|
|
654
|
+
dashboard").`,
|
|
655
|
+
|
|
656
|
+
`Important: Dashboard stat cards must show real data using embedded Saltcorn Statistic
|
|
657
|
+
views (using embed-view tags, e.g. <embed-view viewname="total_hours_stat"></embed-view>).
|
|
658
|
+
Never use client-side JavaScript fetch stubs, commented-out fetch code, or static
|
|
659
|
+
placeholder values (e.g. "—", "Loading...") for statistics. If a Statistic view for a
|
|
660
|
+
metric does not exist yet, it must have been created in an earlier task — do not invent
|
|
661
|
+
placeholder JS instead.`,
|
|
662
|
+
|
|
663
|
+
`Important: When creating a page or view, always set min_role based on the intended
|
|
664
|
+
audience: 1 for admin-only, 40 for staff and above, 80 for logged-in users and above,
|
|
665
|
+
100 for public. Never default to public (100) unless the page or view is explicitly
|
|
666
|
+
intended for unauthenticated users (e.g. a landing page). A dashboard or view for
|
|
667
|
+
clients/users is role 80, a staff page or view is role 40, an admin page or view is
|
|
668
|
+
role 1.`,
|
|
669
|
+
|
|
670
|
+
`Important: Two-factor authentication (2FA/TOTP) is fully built into the platform. To
|
|
671
|
+
configure it, call set_entity directly with entity_type "system-configuration-value"
|
|
672
|
+
and entity_name "twofa_policy_by_role". The entity_definition must be the plain JSON
|
|
673
|
+
object itself — for example: {"1": "Mandatory", "100": "Disabled"}. Do NOT wrap it in
|
|
674
|
+
{"type": "json", "value": ...} or any other envelope. Read the current value first with
|
|
675
|
+
get_entity and merge rather than overwrite. Do NOT create a workflow or trigger to do
|
|
676
|
+
this.`,
|
|
677
|
+
|
|
678
|
+
`Important: To set a page as the home page for a role, call set_entity directly with
|
|
679
|
+
entity_type "system-configuration-value" and entity_name "home_page_by_role". The
|
|
680
|
+
value is a JSON object mapping role IDs to page names — Role IDs: public=100, user=80,
|
|
681
|
+
staff=40, admin=1. The entity_definition must be the plain JSON object itself — for
|
|
682
|
+
example: {"100": "landing", "80": "client_dashboard"}. Do NOT wrap it in {"type":
|
|
683
|
+
"json", "value": ...} or any other envelope. Read the current value first with
|
|
684
|
+
get_entity so you can merge rather than overwrite. Do NOT create a workflow or trigger
|
|
685
|
+
to do this — use set_entity directly.`,
|
|
686
|
+
|
|
687
|
+
`Important: If the task description mentions adding a viewlink, linking rows to another
|
|
688
|
+
view, or a button that opens another view from a list — that viewlink column MUST be
|
|
689
|
+
present in the finished view. Do not skip it. Viewlinks require calling
|
|
690
|
+
get_relation_paths first to obtain the relation string before generating the layout.`,
|
|
691
|
+
|
|
692
|
+
`Important: Every List view must include a delete action column unless the table is
|
|
693
|
+
explicitly read-only. Use the built-in "Delete" action type for this column.`,
|
|
694
|
+
|
|
695
|
+
`Important: Before creating or updating any view or page that embeds, links to, or
|
|
696
|
+
opens another view (including viewlinks, action buttons, and ajax_modal calls), call
|
|
697
|
+
list_entities (entity_type "view") to get all existing view names. Only reference
|
|
698
|
+
views that appear in that list — never invent a name or assume a view exists. If a
|
|
699
|
+
view is not in the list, omit it or use a simple "Coming soon" placeholder — never
|
|
700
|
+
write conversational text, explanations, or instructions to the user inside the HTML.
|
|
701
|
+
Always create the page with whatever views exist. Do the same for pages: call
|
|
702
|
+
list_entities (entity_type "page") before linking to any page by name.`,
|
|
703
|
+
|
|
704
|
+
`Important: A plain Edit view creates or edits a single record — it is NOT a bulk CSV
|
|
705
|
+
import tool. Never use an Edit view as a solution for CSV import. List views have no
|
|
706
|
+
built-in CSV export feature — do not add an export button or column to a List view.
|
|
707
|
+
CSV import and export functionality must always be placed on a dedicated management or
|
|
708
|
+
admin page as embedded views, using whatever import/export viewtemplate is available.`,
|
|
709
|
+
|
|
710
|
+
`Important: Every HTML page (page_type HTML) must include a toast notification area so
|
|
711
|
+
that alerts and success messages are visible. Place this div just before the closing
|
|
712
|
+
</body> tag:
|
|
713
|
+
<div id="toasts-area" class="toast-container position-fixed top-0 start-50 p-0"
|
|
714
|
+
style="z-index:999;" aria-live="polite" aria-atomic="true"></div>`,
|
|
715
|
+
|
|
716
|
+
`CRITICAL: When creating a page, default to page_type "Layout page". This creates a
|
|
717
|
+
proper Saltcorn layout built from segments (view embeds, containers, columns, etc.)
|
|
718
|
+
and is the correct choice for dashboards, print pages, and any page that embeds views.
|
|
719
|
+
Use page_type "Marketing page" only for public-facing promotional pages (landing pages,
|
|
720
|
+
brochures). Use page_type "Application page" only for standalone HTML pages that do
|
|
721
|
+
not embed Saltcorn views. In particular, NEVER use "Marketing page" or "Application
|
|
722
|
+
page" for any page used with page_to_pdf — page_to_pdf cannot render HTML-backed
|
|
723
|
+
pages. If you find yourself about to write raw HTML (<!doctype>, <html>, <head>,
|
|
724
|
+
<body>), stop and ask yourself: does this task explicitly require a standalone HTML
|
|
725
|
+
page — like a public landing page, a marketing page, or a dashboard? If not, use
|
|
726
|
+
page_type "Layout page". Do not output HTML to the conversation.`,
|
|
727
|
+
];
|
|
728
|
+
|
|
729
|
+
const data_model_exec_rules = [
|
|
730
|
+
`Important: If this task requires creating custom platform roles (beyond the four
|
|
731
|
+
built-in roles: 1=admin, 40=staff, 80=user, 100=public), use the Registry editor:
|
|
732
|
+
call set_entity with entity_type "role" and the role definition. Do NOT create a
|
|
733
|
+
user-defined database table for roles — platform roles are a system concern, not
|
|
734
|
+
application data.`,
|
|
735
|
+
|
|
736
|
+
`Important: The "users" table is built-in and must never be modified — do not add,
|
|
737
|
+
remove, or alter any fields on it.`,
|
|
738
|
+
|
|
739
|
+
`Important: Saltcorn has a built-in role system with fixed roles (1 = admin, 40 = staff,
|
|
740
|
+
80 = user, 100 = public). Do NOT create a Roles table, a permissions table, or any
|
|
741
|
+
table describing what roles are allowed to do. Access control is a platform concern:
|
|
742
|
+
every Saltcorn entity (views, pages, tables) already has a min_role property that
|
|
743
|
+
controls which role can access it. There is nothing to store in the database —
|
|
744
|
+
configure min_role on each entity instead.`,
|
|
745
|
+
|
|
746
|
+
`Important: Every Saltcorn table has a primary key field named "id" that is always
|
|
747
|
+
unique and not-null by definition. Never set unique=true or not_null=true on the "id"
|
|
748
|
+
field — it is redundant and incorrect. For every OTHER field that must be unique (e.g.
|
|
749
|
+
unique email, unique slug), set unique=true on that field. For every other field that
|
|
750
|
+
must not be empty, set not_null=true. Description, notes, and other free-text fields
|
|
751
|
+
should NOT be not_null unless explicitly required. Do NOT leave uniqueness or required
|
|
752
|
+
constraints for a later step — express them fully now.`,
|
|
753
|
+
|
|
754
|
+
`Important: Ownership configuration (automatically populating a FK-to-users field from
|
|
755
|
+
the logged-in user) is a VIEW-level concern and cannot be expressed in the schema. Do
|
|
756
|
+
not attempt to annotate fields as "ownership fields" — simply define the foreign key
|
|
757
|
+
field normally. Ownership will be configured when the Edit views are generated.`,
|
|
758
|
+
|
|
759
|
+
`Important: Email and SMTP configuration (host, port, credentials, sender address) is
|
|
760
|
+
managed by the Saltcorn platform administrator in system settings — it is NOT stored
|
|
761
|
+
in the application database. Do NOT create any table for SMTP settings, email
|
|
762
|
+
configuration, or mail server credentials. If the application needs to send emails,
|
|
763
|
+
that is handled by a trigger action.`,
|
|
764
|
+
|
|
765
|
+
`Important: Every tool call must contain only the final, complete result — never
|
|
766
|
+
intermediate reasoning, planning notes, or placeholder values. Compose the full schema
|
|
767
|
+
in your reasoning first, then pass only the finished result to the tool.`,
|
|
768
|
+
];
|
|
769
|
+
|
|
770
|
+
const research_questions_rules =
|
|
771
|
+
"Based on the following application specification, generate clarifying questions\n" +
|
|
772
|
+
"that would help better understand what the user wants to build.\n" +
|
|
773
|
+
"Ask only about genuinely ambiguous or underspecified aspects.\n" +
|
|
774
|
+
"Do not ask about things that are already clear from the specification.\n" +
|
|
775
|
+
"Only ask questions that are truly necessary — if 2 or 3 questions cover everything unclear, stop there.\n" +
|
|
776
|
+
"Do not pad the list. 10 is a hard maximum, not a target.";
|
|
777
|
+
|
|
778
|
+
const feedback_analyse_decision =
|
|
779
|
+
"Do you have important questions about this feedback,\n" +
|
|
780
|
+
"or do you already know what needs to be done?\n\n" +
|
|
781
|
+
"- If you know what to do — no need to call any tool, just respond with nothing.\n" +
|
|
782
|
+
"- If you have questions that are truly blocking —\n" +
|
|
783
|
+
" call ask_questions with only those. 3 is a hard maximum.\n" +
|
|
784
|
+
" Each question must be short, clear, and easy to understand.\n" +
|
|
785
|
+
" Write for a non-technical user: plain language, no jargon, one idea per question.";
|
|
786
|
+
|
|
787
|
+
const feedback_task_overrides = [
|
|
788
|
+
"Generate ONLY the minimal tasks that directly implement what the feedback requests. " +
|
|
789
|
+
'Do not add defensive "verify", "ensure accessible", or "check still reachable" tasks — ' +
|
|
790
|
+
"those are not changes and do not belong in a task plan.",
|
|
791
|
+
|
|
792
|
+
"Do NOT generate tasks for writing, updating, or running automated tests. " +
|
|
793
|
+
"There are no automated tests in this application.",
|
|
794
|
+
|
|
795
|
+
"When a task modifies an existing view or page, do NOT set or change its min_role unless " +
|
|
796
|
+
"the feedback explicitly requests an access control change. The existing min_role is already correct.",
|
|
797
|
+
|
|
798
|
+
"If the feedback can be implemented in a single task, use a single task. " +
|
|
799
|
+
"Do not split it into more tasks than strictly necessary.",
|
|
800
|
+
|
|
801
|
+
"Do NOT create new views, pages, or routes as a side effect of modifying an existing one. " +
|
|
802
|
+
"Only create a new view or page when the feedback explicitly asks for one. " +
|
|
803
|
+
"If the feedback asks to change or remove something from an existing view, only modify that view.",
|
|
804
|
+
];
|
|
805
|
+
|
|
806
|
+
module.exports = {
|
|
807
|
+
saltcorn_description,
|
|
808
|
+
task_planning_rules,
|
|
809
|
+
implementation_rules,
|
|
810
|
+
fieldview_selection_rules,
|
|
811
|
+
task_planning_closing,
|
|
812
|
+
error_fix_closing,
|
|
813
|
+
feedback_task_overrides,
|
|
814
|
+
feature_exec_rules,
|
|
815
|
+
data_model_exec_rules,
|
|
816
|
+
req_gen_rules,
|
|
817
|
+
phase_gen_rules,
|
|
818
|
+
phase_scope_rule,
|
|
819
|
+
no_roles_table_rule,
|
|
820
|
+
exec_tool_call_rule,
|
|
821
|
+
exec_schema_rule_plugin,
|
|
822
|
+
exec_schema_rule_data_model,
|
|
823
|
+
exec_schema_rule_feature,
|
|
824
|
+
plugin_type_instruction,
|
|
825
|
+
data_model_type_instruction,
|
|
826
|
+
feature_type_instruction,
|
|
827
|
+
feedback_analyse_decision,
|
|
828
|
+
research_questions_rules,
|
|
829
|
+
};
|