@waron97/prbot 3.2.1 → 3.4.0
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 +26 -18
- package/agrippa-pb.md +141 -68
- package/package.json +5 -1
- package/src/agrippa/commands/clone.js +17 -10
- package/src/agrippa/commands/cloneLrp.js +114 -0
- package/src/agrippa/commands/clonePb.js +10 -10
- package/src/agrippa/commands/diff.js +9 -8
- package/src/agrippa/commands/init.js +14 -13
- package/src/agrippa/commands/initPhase.js +51 -42
- package/src/agrippa/commands/pb.js +71 -39
- package/src/agrippa/commands/pull.js +137 -42
- package/src/agrippa/commands/pullLrp.js +54 -0
- package/src/agrippa/commands/pullPb.js +2 -3
- package/src/agrippa/commands/push.js +112 -33
- package/src/agrippa/commands/pushLrp.js +56 -0
- package/src/agrippa/commands/repair.js +4 -3
- package/src/agrippa/index.js +48 -30
- package/src/agrippa/lib/lrpApi.js +153 -0
- package/src/agrippa/lib/pbEdit.js +31 -10
- package/src/agrippa/lib/pbLayout.js +8 -1
- package/src/agrippa/lib/pbModel.js +318 -86
- package/src/agrippa/lib/pbPreview.js +6 -2
- package/src/agrippa/lib/pbProject.js +93 -7
- package/src/agrippa/lib/pbScriptTemplate.js +29 -0
- package/src/commands/autopr.js +21 -22
- package/src/commands/changelog.js +4 -3
- package/src/commands/commit.js +11 -10
- package/src/commands/export.js +2 -1
- package/src/commands/exportPb.js +19 -2
- package/src/commands/init.js +2 -1
- package/src/commands/routine.js +19 -8
- package/src/index.js +137 -112
- package/src/lib/auth.js +19 -1
- package/src/lib/logger.js +12 -1
package/README.md
CHANGED
|
@@ -194,7 +194,7 @@ prbot update
|
|
|
194
194
|
|
|
195
195
|
## agrippa
|
|
196
196
|
|
|
197
|
-
Syncs Odoo workflow phase Python code
|
|
197
|
+
Syncs Odoo workflow phase Python code, MFA records, process-builder wizards, and long-running processes (LRPs) between the local filesystem and the RIP / Process Builder / Symphony APIs. Tracks changes via checksums and detects conflicts before overwriting.
|
|
198
198
|
|
|
199
199
|
Credentials are inherited from the global prbot config (`~/.config/prbot/config`). Override per-workspace in `agrippa.yaml`.
|
|
200
200
|
|
|
@@ -208,9 +208,9 @@ agrippa init
|
|
|
208
208
|
|
|
209
209
|
### `agrippa clone`
|
|
210
210
|
|
|
211
|
-
Clones all `from_code` phases for a selected workflow, a single MFA,
|
|
211
|
+
Clones all `from_code` phases for a selected workflow, a single MFA, a **process-builder wizard**, or a **long-running process (LRP)**, into the workspace. Writes files to disk and registers them in `agrippa.yaml`. With no flag, prompts for the object type (MFA / Phase / Process Builder / Long Running Process).
|
|
212
212
|
|
|
213
|
-
A wizard is downloaded and **decomposed** into editable files (`structure.yaml`, `process.yaml`, `scripts/`, `pages/`, manifest); see [`agrippa pb`](#agrippa-pb) and [`agrippa-pb.md`](agrippa-pb.md).
|
|
213
|
+
A wizard or LRP is downloaded and **decomposed** into editable files (`structure.yaml`, `process.yaml`, `scripts/`, `pages/`, manifest) — LRPs share the same layout minus `pages/` (LRPs have no user tasks); see [`agrippa pb`](#agrippa-pb) and [`agrippa-pb.md`](agrippa-pb.md).
|
|
214
214
|
|
|
215
215
|
```bash
|
|
216
216
|
agrippa clone
|
|
@@ -219,18 +219,21 @@ agrippa clone --mfa
|
|
|
219
219
|
agrippa clone --phase --id 123 --path my-workflow/
|
|
220
220
|
agrippa clone --pb # select a wizard
|
|
221
221
|
agrippa clone --pb --name ml_review_billing --path my-wizard/
|
|
222
|
+
agrippa clone --lrp # live search LRPs by name
|
|
223
|
+
agrippa clone --lrp --name B2WA_ml_IFS_passive_trigger --path my-lrp/
|
|
222
224
|
```
|
|
223
225
|
|
|
224
226
|
Options:
|
|
225
227
|
|
|
226
|
-
| Flag
|
|
227
|
-
|
|
|
228
|
-
| `--phase`
|
|
229
|
-
| `--mfa`
|
|
230
|
-
| `--pb`
|
|
231
|
-
| `--
|
|
232
|
-
| `--
|
|
233
|
-
| `--
|
|
228
|
+
| Flag | Description |
|
|
229
|
+
| ----------------- | --------------------------------------------------------------------------- |
|
|
230
|
+
| `--phase` | Clone a phase (select a workflow) |
|
|
231
|
+
| `--mfa` | Clone an MFA record |
|
|
232
|
+
| `--pb` | Clone a process-builder wizard |
|
|
233
|
+
| `--lrp` | Clone a long-running process |
|
|
234
|
+
| `--id <id>` | Skip selection, clone by ID (phase/mfa) |
|
|
235
|
+
| `--name <name>` | Skip selection: `document_id` (with `--pb`) or process name (with `--lrp`) |
|
|
236
|
+
| `--path <path>` | Destination path (base dir for phases/wizard/lrp, file for MFA) |
|
|
234
237
|
|
|
235
238
|
### `agrippa pull`
|
|
236
239
|
|
|
@@ -238,7 +241,7 @@ Fetches remote code for all tracked entries and shows what changed. Classifies e
|
|
|
238
241
|
|
|
239
242
|
After pulling, also checks tracked workflows for newly added `from_code` phases and auto-clones any not yet present locally.
|
|
240
243
|
|
|
241
|
-
Tracked **process-builder wizards** are also refreshed from upstream: the local project is re-decomposed from the latest payload (orphan script
|
|
244
|
+
Tracked **process-builder wizards** and **long-running processes** are also refreshed from upstream: the local project is re-decomposed from the latest payload (orphan script files pruned; PB wizards also prune orphan pages), with the same `fast-forward`/`conflict` classification (PB: upstream `updated_date`; LRP: re-resolved-by-name payload checksum vs. the last pulled state — LRPs have no stable id, so every pull re-resolves the current id/tenantId by name first). The current local state is backed up to `.backup/<timestamp>/<path>/local.json` first.
|
|
242
245
|
|
|
243
246
|
```bash
|
|
244
247
|
agrippa pull
|
|
@@ -246,14 +249,14 @@ agrippa pull
|
|
|
246
249
|
|
|
247
250
|
### `agrippa push`
|
|
248
251
|
|
|
249
|
-
Pushes local file changes back to RIP (phases/MFAs)
|
|
252
|
+
Pushes local file changes back to RIP (phases/MFAs), the Process Builder API (wizards), and Symphony (long-running processes). Backs up current remote state to `.backup/<timestamp>/` before overwriting. Same conflict detection as pull, with the concern inverted. LRP entries are located by **name**, not id (the Symphony id changes on every save), re-resolving the current id/tenantId immediately before saving.
|
|
250
253
|
|
|
251
|
-
Pushing a wizard saves it as a **draft**; publish it so live consumers see the change with `--publish` (auto) or answer the prompt. Page edits (`pages/`) are saved independently of the whole-wizard save, mirroring the UI.
|
|
254
|
+
Pushing a wizard saves it as a **draft**; publish it so live consumers see the change with `--publish` (auto) or answer the prompt. Page edits (`pages/`) are saved independently of the whole-wizard save, mirroring the UI. Pushing an LRP saves the BPMN via Symphony's `tabulator` PATCH; **deploy** it (the LRP analog of publish) the same way — `--publish`/`--skip-publish` double as auto-deploy/never-deploy for LRPs too.
|
|
252
255
|
|
|
253
256
|
```bash
|
|
254
|
-
agrippa push # prompts whether to publish each pushed wizard
|
|
255
|
-
agrippa push --publish # auto-publish
|
|
256
|
-
agrippa push --skip-publish # never publish (no prompt)
|
|
257
|
+
agrippa push # prompts whether to publish/deploy each pushed wizard/LRP
|
|
258
|
+
agrippa push --publish # auto-publish wizards, auto-deploy LRPs
|
|
259
|
+
agrippa push --skip-publish # never publish/deploy (no prompt)
|
|
257
260
|
```
|
|
258
261
|
|
|
259
262
|
### `agrippa diff [path]`
|
|
@@ -286,7 +289,7 @@ agrippa repair
|
|
|
286
289
|
|
|
287
290
|
### `agrippa pb`
|
|
288
291
|
|
|
289
|
-
Local editing helpers for a **cloned process-builder wizard** (no network — they edit the decomposed files in place). Each operates on **one** wizard, resolved by `--pb <document_id
|
|
292
|
+
Local editing helpers for a **cloned process-builder wizard or long-running process** (no network — they edit the decomposed files in place; both share the same decomposed layout and BPMN engine). Each operates on **one** wizard/LRP, resolved by `--pb <document_id_or_name>` (name for LRPs, since they have no `document_id`), single-entry auto-select, or a fuzzy prompt.
|
|
290
293
|
|
|
291
294
|
These commands exist mainly so an **AI agent** can add/remove/connect blocks without hand-editing the multi-thousand-line `structure.yaml`. Human users typically edit blocks in the UI instead. Full agent-facing guide (also usable as a workspace `CLAUDE.md`): [`agrippa-pb.md`](agrippa-pb.md).
|
|
292
295
|
|
|
@@ -307,4 +310,9 @@ agrippa pb ls --pb ml_review_billing
|
|
|
307
310
|
agrippa pb add --type scriptTask --name "Check pod" --pb ml_review_billing
|
|
308
311
|
agrippa pb connect --from ScriptTask_x --to ExclusiveGateway_y --pb ml_review_billing
|
|
309
312
|
agrippa pb format --pb ml_review_billing
|
|
313
|
+
|
|
314
|
+
agrippa pb ls --pb B2WA_ml_IFS_passive_trigger # LRP, resolved by name
|
|
315
|
+
agrippa pb add --type serviceTask --name "Call SAP" --pb B2WA_ml_IFS_passive_trigger
|
|
310
316
|
```
|
|
317
|
+
|
|
318
|
+
`userTask` (pages) can't be added to an LRP project — LRPs never have user tasks.
|
package/agrippa-pb.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# Instructions for working with Phases, MFAs,
|
|
1
|
+
# Instructions for working with Phases, MFAs, Process-Builder wizards, and LRPs
|
|
2
2
|
|
|
3
|
-
You are my coding assistant developing MFAs, phases,
|
|
4
|
-
our Odoo CRM. Follow instructions precisely, without
|
|
5
|
-
outside the scope of your instructions.
|
|
3
|
+
You are my coding assistant developing MFAs, phases, process-builder wizards, and
|
|
4
|
+
long-running processes (LRPs) for our Odoo CRM. Follow instructions precisely, without
|
|
5
|
+
doing fixes or enhancements outside the scope of your instructions.
|
|
6
6
|
|
|
7
7
|
This workspace is an **agrippa** workspace: a local checkout of Odoo code synced via
|
|
8
8
|
the `agrippa` CLI. **You (the agent) never run `agrippa clone`, `agrippa pull`, or
|
|
9
9
|
`agrippa push`** — those are human-only operations. You edit local files, and for
|
|
10
|
-
wizards you also drive the `agrippa pb` editing commands (below). A human
|
|
11
|
-
syncs.
|
|
10
|
+
wizards and LRPs you also drive the `agrippa pb` editing commands (below). A human
|
|
11
|
+
reviews and syncs.
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -57,35 +57,85 @@ match the result whose `next_phase` is X and use its `code_values`.
|
|
|
57
57
|
|
|
58
58
|
### Code inside phases and MFAs
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
- `
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
`
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
- `
|
|
60
|
+
Phases and MFAs both run stored Python through Odoo 15 `safe_eval` (mode `exec`), but
|
|
61
|
+
they run in **different environments with different globals**. The shared sandbox rules
|
|
62
|
+
come first; the per-environment globals follow.
|
|
63
|
+
|
|
64
|
+
#### Shared sandbox rules (apply to both)
|
|
65
|
+
|
|
66
|
+
Patterns **not allowed** by `safe_eval`:
|
|
67
|
+
|
|
68
|
+
- **`import`** — forbidden outright.
|
|
69
|
+
- **f-strings** — do not use them; use `"...{}".format(...)` instead. (The current
|
|
70
|
+
runtime's opcode whitelist technically permits them, but team convention and observed
|
|
71
|
+
failures mean you must avoid them.)
|
|
72
|
+
- **attribute assignment** (`obj.attr = x`) — forbidden (`STORE_ATTR` is blocked). You
|
|
73
|
+
cannot set attributes; write through the ORM (`record.write({...})`) instead.
|
|
74
|
+
- **dunder names** — any name containing `__` (e.g. `__class__`) is rejected. This is why
|
|
75
|
+
you cannot write doc strings.
|
|
76
|
+
- **`getattr` / `setattr` / `eval`** — not in the builtins, so unavailable.
|
|
77
|
+
|
|
78
|
+
Patterns that **are** allowed (but with a sharp limit):
|
|
79
|
+
|
|
80
|
+
- **lambdas and nested `def` are creatable, but cannot form closures.** A lambda/nested
|
|
81
|
+
function may reference only its **own parameters, module globals** (`env` etc.) **and
|
|
82
|
+
constants**. It must **not** capture a variable from the enclosing function — the
|
|
83
|
+
closure-cell opcodes (`LOAD_DEREF`/`STORE_DEREF`/`LOAD_CLOSURE`/`MAKE_CELL`) are not
|
|
84
|
+
whitelisted, so a closure fails validation.
|
|
85
|
+
- ✅ works: `recs.filtered(lambda r: r.wizard_result == "CANCEL")` — no captured locals
|
|
86
|
+
- ❌ fails: `recs.filtered(lambda r: r.x == target)` — `target` is an enclosing local
|
|
87
|
+
- In practice nested functions are rarely usable, since they almost always close over
|
|
88
|
+
local state. Self-contained `.filtered(lambda r: ...)` predicates are the common
|
|
89
|
+
legitimate use and appear throughout real phase code.
|
|
90
|
+
|
|
91
|
+
#### Phase environment (`symple.triplet.phase`)
|
|
92
|
+
|
|
93
|
+
Phase code runs against a full Odoo "server action" context. Globals available:
|
|
94
|
+
|
|
95
|
+
- `env` — the **full Odoo ORM** (`env["model"].sudo().search/create/write/browse`)
|
|
96
|
+
- `case_id` — the current `helpdesk.ticket`
|
|
97
|
+
- `Command` — x2many command namespace
|
|
98
|
+
- `ValidationError` — raise to abort with a warning
|
|
99
|
+
- `request` (= `requests.request`), for outbound HTTP
|
|
100
|
+
- `json_dumps` (= `json.dumps`), `json_load` (= `json.load` — note: **not** `json_loads`)
|
|
101
|
+
- `time`, `datetime`, `dateutil`, `timezone`, `float_compare`, `OrderedDict`
|
|
102
|
+
- `b64encode`, `b64decode`
|
|
103
|
+
- `log(message, level='info')`, `format_exc` (= `traceback.format_exc`), `first`
|
|
104
|
+
(= `fields.first`), `uid`, `user`
|
|
105
|
+
|
|
106
|
+
There is **no** `make_response` in phases.
|
|
107
|
+
|
|
108
|
+
**Returning a result:** assign `result` as a **string** — it must match one of the phase's
|
|
109
|
+
`code_values` in `workflow.yml` (e.g. `result = "RES1"`). It is **not** a dict. The string
|
|
110
|
+
is matched against `result.code.configurator` to pick the outgoing edge.
|
|
111
|
+
|
|
112
|
+
**Reporting errors:** write the message onto the case, conventionally
|
|
113
|
+
`case_id.write({"info_message": "..."})` (`error_message` also exists but `info_message`
|
|
114
|
+
is the prevailing choice).
|
|
115
|
+
|
|
116
|
+
**Case helpers** (defined on `helpdesk.ticket` in `sorgenia_tools`):
|
|
117
|
+
|
|
118
|
+
- `case_id.kv_store()` — the per-case key/value store (see below).
|
|
119
|
+
- `case_id.last_staging("<process_name>")` — returns the latest
|
|
120
|
+
`symple.pb.process.data` for that process on the case, raising `ValidationError` if
|
|
121
|
+
none exists. Prefer this over searching `symple.pb.process.data` by hand.
|
|
122
|
+
|
|
123
|
+
#### MFA environment (RIP)
|
|
124
|
+
|
|
125
|
+
MFA code runs to build an HTTP response, with a much smaller context. Globals available:
|
|
126
|
+
|
|
127
|
+
- `env` — the Odoo ORM
|
|
128
|
+
- `make_response` — build a response, e.g.
|
|
129
|
+
`result = make_response((500, 500), "Custom error message")`
|
|
130
|
+
- `logger` — a standard Python logger
|
|
131
|
+
- `result` — assign the response payload (a recordset or JSON-serialisable content); it
|
|
132
|
+
is consumed to construct the HTTP response
|
|
133
|
+
- the incoming request data: `method`, `model`, `records`, `user`, `args`, `headers`,
|
|
134
|
+
`body`, `httprequest`
|
|
135
|
+
- `datetime`, `dateutil`
|
|
136
|
+
|
|
137
|
+
MFAs have **no** `case_id`, `Command`, `ValidationError`, `json_dumps`, `first`, `log`,
|
|
138
|
+
or `format_exc` by default.
|
|
89
139
|
|
|
90
140
|
### Communication between phases
|
|
91
141
|
|
|
@@ -108,26 +158,42 @@ records.
|
|
|
108
158
|
|
|
109
159
|
---
|
|
110
160
|
|
|
111
|
-
## Process-builder wizards
|
|
112
|
-
|
|
113
|
-
A wizard is a BPMN process the CRM runs as a guided flow
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
161
|
+
## Process-builder wizards and long-running processes (LRPs)
|
|
162
|
+
|
|
163
|
+
A wizard or LRP is a BPMN process the CRM runs as a guided flow (wizards) or a
|
|
164
|
+
long-running background process (LRPs). Both are the **same underlying Activiti/
|
|
165
|
+
Symphony BPMN XML**, so locally they share **one** decomposed layout and one `pb`
|
|
166
|
+
editing suite — everything below applies to both unless a difference is called out.
|
|
167
|
+
For wizards/LRPs you are expected to **drive the `agrippa pb` commands** for
|
|
168
|
+
structural changes — they hide BPMN id generation, the nested-YAML graph,
|
|
169
|
+
dangling-edge cleanup, and the script/page/manifest bookkeeping you would otherwise
|
|
170
|
+
get wrong by hand.
|
|
171
|
+
|
|
172
|
+
**LRP-specific differences:**
|
|
173
|
+
|
|
174
|
+
- **No pages.** LRPs never contain `userTask`. `pb add --type userTask` errors out on
|
|
175
|
+
an LRP project.
|
|
176
|
+
- **Selector is `name`, not `document_id`.** LRPs have no stable id — the Symphony id
|
|
177
|
+
changes on every save — so `--pb <name>` (not a `document_id`) is how you target an
|
|
178
|
+
LRP project. `pb ls`/error messages show `name` when `document_id` is absent.
|
|
179
|
+
- **A few extra node types show up more often**: `intermediateCatchEvent`,
|
|
180
|
+
`intermediateThrowEvent`, `callActivity`, `parallelGateway`, `eventBasedGateway` (see
|
|
181
|
+
Node types below) — these exist for PBs too but are common in LRPs.
|
|
182
|
+
- Publishing is called **deploy** for LRPs (same human-only `agrippa push
|
|
183
|
+
--publish`/`--skip-publish` flow as wizard publish — not a `pb` command).
|
|
118
184
|
|
|
119
185
|
> **You never run `agrippa push` or `agrippa pull`.** You only edit local files and run
|
|
120
|
-
> the local, read/write `agrippa pb` subcommands. A human syncs and publishes.
|
|
186
|
+
> the local, read/write `agrippa pb` subcommands. A human syncs and publishes/deploys.
|
|
121
187
|
|
|
122
188
|
### Decomposed project layout
|
|
123
189
|
|
|
124
190
|
```
|
|
125
|
-
<wizard-dir>/
|
|
191
|
+
<wizard-or-lrp-dir>/
|
|
126
192
|
process.yaml identity + top-level flags (envelope)
|
|
127
193
|
structure.yaml THE graph: nodes hold their outgoing `edges` and nested
|
|
128
194
|
`nodes` (for subProcess/transaction); inline geometry
|
|
129
195
|
scripts/NNNN_*.js one scriptTask body each (byte-exact)
|
|
130
|
-
pages/<formKey>.yml one userTask page object each
|
|
196
|
+
pages/<formKey>.yml one userTask page object each (PB only — LRPs have no pages/)
|
|
131
197
|
.agrippa-pb.json manifest: scalars, namespaces, id↔file maps (do not hand-edit)
|
|
132
198
|
```
|
|
133
199
|
|
|
@@ -149,7 +215,9 @@ A node looks like:
|
|
|
149
215
|
```
|
|
150
216
|
|
|
151
217
|
Node types: `startEvent`, `endEvent`, `boundaryEvent`, `exclusiveGateway`,
|
|
152
|
-
`scriptTask`, `serviceTask`, `userTask
|
|
218
|
+
`scriptTask`, `serviceTask`, `userTask` (PB only), `subProcess`, `transaction`,
|
|
219
|
+
`intermediateCatchEvent`, `intermediateThrowEvent`, `callActivity`,
|
|
220
|
+
`parallelGateway`, `eventBasedGateway`.
|
|
153
221
|
|
|
154
222
|
### Your loop
|
|
155
223
|
|
|
@@ -160,7 +228,8 @@ agrippa pb lint # check for structural issues before handing off
|
|
|
160
228
|
# STOP. Do NOT format. Do NOT push. Report back to the human (see Formatting below).
|
|
161
229
|
```
|
|
162
230
|
|
|
163
|
-
Every `pb` command targets **one** wizard. **Always pass
|
|
231
|
+
Every `pb` command targets **one** wizard or LRP. **Always pass
|
|
232
|
+
`--pb <document_id_or_name>`** (a wizard's `document_id`, or an LRP's `name`) so you
|
|
164
233
|
never hit an interactive prompt.
|
|
165
234
|
|
|
166
235
|
### Commands
|
|
@@ -168,7 +237,7 @@ never hit an interactive prompt.
|
|
|
168
237
|
#### `pb ls` — discover ids
|
|
169
238
|
|
|
170
239
|
```bash
|
|
171
|
-
agrippa pb ls --pb <
|
|
240
|
+
agrippa pb ls --pb <document_id_or_name>
|
|
172
241
|
```
|
|
173
242
|
|
|
174
243
|
Flat list of every node with its id, type, name, parent (if nested), and outgoing
|
|
@@ -187,17 +256,21 @@ ExclusiveGateway_1lghfov (exclusiveGateway) "eg err"
|
|
|
187
256
|
#### `pb add` — add a node
|
|
188
257
|
|
|
189
258
|
```bash
|
|
190
|
-
agrippa pb add --type scriptTask --name "Check pod" --pb <
|
|
191
|
-
agrippa pb add --type userTask --name "Review" --pb <
|
|
192
|
-
agrippa pb add --type subProcess --name "Retry loop" --pb <
|
|
193
|
-
agrippa pb add --type scriptTask --name "Inner" --parent SubProcess_x --pb <
|
|
259
|
+
agrippa pb add --type scriptTask --name "Check pod" --pb <document_id_or_name>
|
|
260
|
+
agrippa pb add --type userTask --name "Review" --pb <document_id_or_name>
|
|
261
|
+
agrippa pb add --type subProcess --name "Retry loop" --pb <document_id_or_name>
|
|
262
|
+
agrippa pb add --type scriptTask --name "Inner" --parent SubProcess_x --pb <document_id_or_name>
|
|
194
263
|
```
|
|
195
264
|
|
|
196
265
|
Prints the new node id. Side effects, handled for you:
|
|
197
266
|
|
|
198
267
|
- `scriptTask` → creates an **empty** `scripts/NNNN_<slug>.js`; edit that file for the body.
|
|
199
268
|
- `userTask` → creates a **stub** `pages/<slug>.yml` + a manifest entry (no page content).
|
|
269
|
+
**PB only** — rejected with an error on an LRP project (LRPs have no user tasks).
|
|
200
270
|
- `subProcess`/`transaction` → empty container; add children with `--parent <its-id>`.
|
|
271
|
+
- new event/gateway types (`intermediateCatchEvent`, `intermediateThrowEvent`,
|
|
272
|
+
`callActivity`, `parallelGateway`, `eventBasedGateway`) → sized/laid out like their
|
|
273
|
+
closest existing counterpart, no extra scaffold files.
|
|
201
274
|
|
|
202
275
|
The node is added **disconnected** with placeholder geometry. Connect it next.
|
|
203
276
|
|
|
@@ -205,7 +278,7 @@ The node is added **disconnected** with placeholder geometry. Connect it next.
|
|
|
205
278
|
instead of adding it disconnected:
|
|
206
279
|
|
|
207
280
|
```bash
|
|
208
|
-
agrippa pb add --type scriptTask --name "New" --from A --to End --pb <
|
|
281
|
+
agrippa pb add --type scriptTask --name "New" --from A --to End --pb <document_id_or_name>
|
|
209
282
|
```
|
|
210
283
|
|
|
211
284
|
Requires **exactly one** existing edge `A → End` already (errors if there's none, or
|
|
@@ -217,7 +290,7 @@ new-node → `End`. `--parent` is implied by `A`/`End`'s container, so don't pas
|
|
|
217
290
|
#### `pb rm` — remove a node
|
|
218
291
|
|
|
219
292
|
```bash
|
|
220
|
-
agrippa pb rm --id ScriptTask_0mmmti4 --pb <
|
|
293
|
+
agrippa pb rm --id ScriptTask_0mmmti4 --pb <document_id_or_name>
|
|
221
294
|
```
|
|
222
295
|
|
|
223
296
|
Removes the node (and, for a container, its children), **every edge pointing at it**
|
|
@@ -228,15 +301,15 @@ manifest entries. No dangling references left behind.
|
|
|
228
301
|
|
|
229
302
|
```bash
|
|
230
303
|
# plain sequence
|
|
231
|
-
agrippa pb connect --from ScriptTask_a --to ScriptTask_b --pb <
|
|
304
|
+
agrippa pb connect --from ScriptTask_a --to ScriptTask_b --pb <document_id_or_name>
|
|
232
305
|
|
|
233
306
|
# named branch (required when the source has 2+ outgoing flows and this is non-default)
|
|
234
307
|
agrippa pb connect --from ExclusiveGateway_g --to ScriptTask_b \
|
|
235
|
-
--name "alive" --condition '${isAlive}' --pb <
|
|
308
|
+
--name "alive" --condition '${isAlive}' --pb <document_id_or_name>
|
|
236
309
|
|
|
237
310
|
# the gateway's fallback branch (default needs no name)
|
|
238
311
|
agrippa pb connect --from ExclusiveGateway_g --to EndEvent_err \
|
|
239
|
-
--default --pb <
|
|
312
|
+
--default --pb <document_id_or_name>
|
|
240
313
|
```
|
|
241
314
|
|
|
242
315
|
A flow's id is printed. Conditions default to `xsi:type="tFormalExpression"`
|
|
@@ -255,14 +328,14 @@ Heed the `!` warnings `connect` prints.
|
|
|
255
328
|
#### `pb disconnect` — remove a flow
|
|
256
329
|
|
|
257
330
|
```bash
|
|
258
|
-
agrippa pb disconnect --id SequenceFlow_1lso8x0 --pb <
|
|
259
|
-
agrippa pb disconnect --from ScriptTask_a --to ScriptTask_b --pb <
|
|
331
|
+
agrippa pb disconnect --id SequenceFlow_1lso8x0 --pb <document_id_or_name>
|
|
332
|
+
agrippa pb disconnect --from ScriptTask_a --to ScriptTask_b --pb <document_id_or_name>
|
|
260
333
|
```
|
|
261
334
|
|
|
262
335
|
#### `pb lint` — check for structural issues
|
|
263
336
|
|
|
264
337
|
```bash
|
|
265
|
-
agrippa pb lint --pb <
|
|
338
|
+
agrippa pb lint --pb <document_id_or_name>
|
|
266
339
|
```
|
|
267
340
|
|
|
268
341
|
Runs all diagram rules and prints any violations. Exits 1 if issues found. Run after
|
|
@@ -278,8 +351,8 @@ every batch of structural edits before handing off to a human. Rules checked:
|
|
|
278
351
|
#### `pb set-default` — change a gateway's default flow
|
|
279
352
|
|
|
280
353
|
```bash
|
|
281
|
-
agrippa pb set-default --id SequenceFlow_b --pb <
|
|
282
|
-
agrippa pb set-default --from ExclusiveGateway_g --to EndEvent_err --pb <
|
|
354
|
+
agrippa pb set-default --id SequenceFlow_b --pb <document_id_or_name>
|
|
355
|
+
agrippa pb set-default --from ExclusiveGateway_g --to EndEvent_err --pb <document_id_or_name>
|
|
283
356
|
```
|
|
284
357
|
|
|
285
358
|
Flips an **already-existing** flow to be its source gateway's `default`, by edge id or
|
|
@@ -292,7 +365,7 @@ non-default flow left without one).
|
|
|
292
365
|
#### `pb preview` — visual check
|
|
293
366
|
|
|
294
367
|
```bash
|
|
295
|
-
agrippa pb preview --pb <
|
|
368
|
+
agrippa pb preview --pb <document_id_or_name> --out /tmp/wizard.svg
|
|
296
369
|
```
|
|
297
370
|
|
|
298
371
|
Renders the current geometry to an SVG so a human can eyeball the result. Safe to run.
|
|
@@ -300,8 +373,8 @@ Not byte-faithful to the real renderer — a sanity check only.
|
|
|
300
373
|
|
|
301
374
|
### Formatting — a human decision, do NOT run it yourself
|
|
302
375
|
|
|
303
|
-
`agrippa pb format` re-lays-out the **entire** wizard with an automatic algorithm.
|
|
304
|
-
On an existing
|
|
376
|
+
`agrippa pb format` re-lays-out the **entire** wizard/LRP with an automatic algorithm.
|
|
377
|
+
On an existing project this **discards the human's hand-tuned layout** and produces a
|
|
305
378
|
drastically different diagram. That may or may not be acceptable — **only the human
|
|
306
379
|
decides.**
|
|
307
380
|
|
|
@@ -310,9 +383,9 @@ positions, and **you stop there**. Report to the human what you changed and that
|
|
|
310
383
|
new blocks need positioning, then let them choose one of:
|
|
311
384
|
|
|
312
385
|
1. **Run `agrippa pb format`** themselves — accepts a full automatic re-layout of the
|
|
313
|
-
whole
|
|
314
|
-
2. **Position the new blocks by hand in the UI** after a human pushes the
|
|
315
|
-
preserving the existing layout.
|
|
386
|
+
whole project (existing arrangement is lost), or
|
|
387
|
+
2. **Position the new blocks by hand in the UI** after a human pushes/deploys the
|
|
388
|
+
change — preserving the existing layout.
|
|
316
389
|
|
|
317
390
|
Never run `pb format` unless the human explicitly tells you to, with that trade-off
|
|
318
391
|
understood.
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waron97/prbot",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.0.0"
|
|
8
|
+
},
|
|
9
|
+
"packageManager": "npm@10.9.8",
|
|
6
10
|
"scripts": {
|
|
7
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
12
|
},
|
|
@@ -3,16 +3,21 @@ import select from '@inquirer/select';
|
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
4
|
import { getToken } from '../../lib/auth.js';
|
|
5
5
|
import { fuzzyMatch } from '../../lib/fuzzy.js';
|
|
6
|
+
import { log, warn } from '../../lib/logger.js';
|
|
6
7
|
import { describeWorkflow, getPhasesByWorkflow, listMfas, listWorkflows } from '../lib/api.js';
|
|
7
8
|
import { computeChecksum } from '../lib/checksum.js';
|
|
8
9
|
import { loadEffectiveEnv, readConfig, writeConfig } from '../lib/config.js';
|
|
9
10
|
import { defaultMfaPath, toSlug, writeCodeFile, writeWorkflowDoc } from '../lib/workspace.js';
|
|
11
|
+
import { cloneLrp } from './cloneLrp.js';
|
|
10
12
|
import { clonePb } from './clonePb.js';
|
|
11
13
|
|
|
12
14
|
async function clone(opts) {
|
|
13
15
|
if (opts.pb) {
|
|
14
16
|
return clonePb(opts);
|
|
15
17
|
}
|
|
18
|
+
if (opts.lrp) {
|
|
19
|
+
return cloneLrp(opts);
|
|
20
|
+
}
|
|
16
21
|
|
|
17
22
|
const config = readConfig();
|
|
18
23
|
loadEffectiveEnv(config);
|
|
@@ -26,17 +31,19 @@ async function clone(opts) {
|
|
|
26
31
|
{ name: 'MFA', value: 'mfa' },
|
|
27
32
|
{ name: 'Phase', value: 'phase' },
|
|
28
33
|
{ name: 'Process Builder', value: 'pb' },
|
|
34
|
+
{ name: 'Long Running Process', value: 'lrp' },
|
|
29
35
|
],
|
|
30
36
|
});
|
|
31
37
|
}
|
|
32
|
-
// Process-builder wizards have their own clone flow (
|
|
38
|
+
// Process-builder wizards and LRPs have their own clone flow (recompose verify).
|
|
33
39
|
if (objectType === 'pb') return clonePb(opts);
|
|
40
|
+
if (objectType === 'lrp') return cloneLrp(opts);
|
|
34
41
|
|
|
35
42
|
const ripUrl = process.env.RIP_URL;
|
|
36
43
|
if (!ripUrl)
|
|
37
44
|
throw new Error('RIP_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
log('Fetching records...');
|
|
40
47
|
const token = await getToken();
|
|
41
48
|
|
|
42
49
|
let records;
|
|
@@ -47,7 +54,7 @@ async function clone(opts) {
|
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
if (!records.length) {
|
|
50
|
-
|
|
57
|
+
log(`No ${objectType} records found.`);
|
|
51
58
|
return;
|
|
52
59
|
}
|
|
53
60
|
|
|
@@ -86,11 +93,11 @@ async function clone(opts) {
|
|
|
86
93
|
basePath = inputPath;
|
|
87
94
|
}
|
|
88
95
|
|
|
89
|
-
|
|
96
|
+
log(`Fetching phases for "${record.name}"...`);
|
|
90
97
|
const phases = await getPhasesByWorkflow(token, ripUrl, record.id, { fromCode: true });
|
|
91
98
|
|
|
92
99
|
if (!phases.length) {
|
|
93
|
-
|
|
100
|
+
log('No phases found.');
|
|
94
101
|
return;
|
|
95
102
|
}
|
|
96
103
|
|
|
@@ -106,19 +113,19 @@ async function clone(opts) {
|
|
|
106
113
|
checksum_at_pull: computeChecksum(phase.code),
|
|
107
114
|
name: `${record.name} / ${phase.name}`,
|
|
108
115
|
});
|
|
109
|
-
|
|
116
|
+
log(` wrote ${filePath}`);
|
|
110
117
|
}
|
|
111
118
|
|
|
112
119
|
// Drop the workflow graph alongside the phase files as read-only context.
|
|
113
120
|
try {
|
|
114
121
|
const structure = await describeWorkflow(token, ripUrl, record.id);
|
|
115
122
|
const docPath = writeWorkflowDoc(basePath, structure);
|
|
116
|
-
|
|
123
|
+
log(` wrote ${docPath}`);
|
|
117
124
|
} catch (err) {
|
|
118
|
-
|
|
125
|
+
warn(` could not fetch workflow structure: ${err.message}`);
|
|
119
126
|
}
|
|
120
127
|
|
|
121
|
-
|
|
128
|
+
log(`Cloned ${phases.length} phase(s) to ${basePath}/`);
|
|
122
129
|
} else {
|
|
123
130
|
const defaultPath = defaultMfaPath(record.model_name, record.name);
|
|
124
131
|
if (!basePath) {
|
|
@@ -141,7 +148,7 @@ async function clone(opts) {
|
|
|
141
148
|
checksum_at_pull: computeChecksum(record.code),
|
|
142
149
|
name: `${record.model_name} / ${record.name}`,
|
|
143
150
|
});
|
|
144
|
-
|
|
151
|
+
log(`Cloned MFA to ${basePath}`);
|
|
145
152
|
}
|
|
146
153
|
|
|
147
154
|
writeConfig(config);
|