@jiggai/recipes 0.4.21 → 0.4.22
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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/recipes/default/business-team.md +33 -9
- package/recipes/default/customer-support-team.md +9 -6
- package/recipes/default/marketing-team.md +6 -0
- package/recipes/default/product-team.md +11 -8
- package/recipes/default/research-team.md +9 -6
- package/recipes/default/social-team.md +27 -24
- package/recipes/default/writing-team.md +9 -6
- package/src/handlers/cron.ts +28 -19
- package/src/handlers/team.ts +46 -0
- package/src/lib/recipe-frontmatter.ts +4 -0
- package/src/lib/workflows/workflow-approvals.ts +316 -0
- package/src/lib/workflows/workflow-node-executor.ts +520 -0
- package/src/lib/workflows/workflow-node-output-readers.ts +1 -1
- package/src/lib/workflows/workflow-queue.ts +56 -8
- package/src/lib/workflows/workflow-runner.ts +43 -1934
- package/src/lib/workflows/workflow-tick.ts +196 -0
- package/src/lib/workflows/workflow-types.ts +39 -0
- package/src/lib/workflows/workflow-utils.ts +330 -0
- package/src/lib/workflows/workflow-worker.ts +586 -0
- package/src/toolsInvoke.ts +1 -1
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -237,8 +237,8 @@ templates:
|
|
|
237
237
|
ops.agents: |
|
|
238
238
|
# AGENTS.md
|
|
239
239
|
|
|
240
|
-
Team: {teamId}
|
|
241
|
-
Shared workspace: {teamDir}
|
|
240
|
+
Team: {{teamId}}
|
|
241
|
+
Shared workspace: {{teamDir}}
|
|
242
242
|
Role: ops
|
|
243
243
|
|
|
244
244
|
## Guardrails (read → act → write)
|
|
@@ -267,8 +267,8 @@ templates:
|
|
|
267
267
|
sales.agents: |
|
|
268
268
|
# AGENTS.md
|
|
269
269
|
|
|
270
|
-
Team: {teamId}
|
|
271
|
-
Shared workspace: {teamDir}
|
|
270
|
+
Team: {{teamId}}
|
|
271
|
+
Shared workspace: {{teamDir}}
|
|
272
272
|
Role: sales
|
|
273
273
|
|
|
274
274
|
## Guardrails (read → act → write)
|
|
@@ -297,8 +297,8 @@ templates:
|
|
|
297
297
|
marketing.agents: |
|
|
298
298
|
# AGENTS.md
|
|
299
299
|
|
|
300
|
-
Team: {teamId}
|
|
301
|
-
Shared workspace: {teamDir}
|
|
300
|
+
Team: {{teamId}}
|
|
301
|
+
Shared workspace: {{teamDir}}
|
|
302
302
|
Role: marketing
|
|
303
303
|
|
|
304
304
|
## Guardrails (read → act → write)
|
|
@@ -327,8 +327,8 @@ templates:
|
|
|
327
327
|
finance.agents: |
|
|
328
328
|
# AGENTS.md
|
|
329
329
|
|
|
330
|
-
Team: {teamId}
|
|
331
|
-
Shared workspace: {teamDir}
|
|
330
|
+
Team: {{teamId}}
|
|
331
|
+
Shared workspace: {{teamDir}}
|
|
332
332
|
Role: finance
|
|
333
333
|
|
|
334
334
|
## Guardrails (read → act → write)
|
|
@@ -357,7 +357,28 @@ templates:
|
|
|
357
357
|
analyst.agents: |
|
|
358
358
|
# AGENTS.md
|
|
359
359
|
|
|
360
|
-
|
|
360
|
+
Team: {{teamId}}
|
|
361
|
+
Shared workspace: {{teamDir}}
|
|
362
|
+
Role: analyst
|
|
363
|
+
|
|
364
|
+
## Guardrails (read → act → write)
|
|
365
|
+
Before you act:
|
|
366
|
+
1) Read:
|
|
367
|
+
- `../notes/plan.md`
|
|
368
|
+
- `../notes/status.md`
|
|
369
|
+
- relevant ticket(s) in `work/in-progress/`
|
|
370
|
+
- any relevant shared context under `shared-context/`
|
|
371
|
+
|
|
372
|
+
After you act:
|
|
373
|
+
1) Write back:
|
|
374
|
+
- Put outputs in the agreed folder (usually `outbox/` or a ticket file).
|
|
375
|
+
- Update the ticket with what you did and where the artifact is.
|
|
376
|
+
|
|
377
|
+
## Workflow
|
|
378
|
+
- Prefer a pull model: wait for a clear task from the lead, or propose a scoped task.
|
|
379
|
+
- Keep work small and reversible.
|
|
380
|
+
|
|
381
|
+
## Output locations
|
|
361
382
|
- Research briefs → outbox/research/
|
|
362
383
|
- Metrics definitions/dashboards notes → shared-context/metrics/
|
|
363
384
|
|
|
@@ -491,6 +512,9 @@ files:
|
|
|
491
512
|
- path: shared-context/priorities.md
|
|
492
513
|
template: sharedContext.priorities
|
|
493
514
|
mode: createOnly
|
|
515
|
+
- path: shared-context/MEMORY_PLAN.md
|
|
516
|
+
template: sharedContext.memoryPlan
|
|
517
|
+
mode: createOnly
|
|
494
518
|
- path: shared-context/agent-outputs/README.md
|
|
495
519
|
template: sharedContext.agentOutputsReadme
|
|
496
520
|
mode: createOnly
|
|
@@ -209,8 +209,8 @@ templates:
|
|
|
209
209
|
triage.agents: |
|
|
210
210
|
# AGENTS.md
|
|
211
211
|
|
|
212
|
-
Team: {teamId}
|
|
213
|
-
Shared workspace: {teamDir}
|
|
212
|
+
Team: {{teamId}}
|
|
213
|
+
Shared workspace: {{teamDir}}
|
|
214
214
|
Role: triage
|
|
215
215
|
|
|
216
216
|
## Guardrails (read → act → write)
|
|
@@ -239,8 +239,8 @@ templates:
|
|
|
239
239
|
resolver.agents: |
|
|
240
240
|
# AGENTS.md
|
|
241
241
|
|
|
242
|
-
Team: {teamId}
|
|
243
|
-
Shared workspace: {teamDir}
|
|
242
|
+
Team: {{teamId}}
|
|
243
|
+
Shared workspace: {{teamDir}}
|
|
244
244
|
Role: resolver
|
|
245
245
|
|
|
246
246
|
## Guardrails (read → act → write)
|
|
@@ -269,8 +269,8 @@ templates:
|
|
|
269
269
|
kb-writer.agents: |
|
|
270
270
|
# AGENTS.md
|
|
271
271
|
|
|
272
|
-
Team: {teamId}
|
|
273
|
-
Shared workspace: {teamDir}
|
|
272
|
+
Team: {{teamId}}
|
|
273
|
+
Shared workspace: {{teamDir}}
|
|
274
274
|
Role: kb-writer
|
|
275
275
|
|
|
276
276
|
## Guardrails (read → act → write)
|
|
@@ -380,6 +380,9 @@ files:
|
|
|
380
380
|
- path: shared-context/priorities.md
|
|
381
381
|
template: sharedContext.priorities
|
|
382
382
|
mode: createOnly
|
|
383
|
+
- path: shared-context/MEMORY_PLAN.md
|
|
384
|
+
template: sharedContext.memoryPlan
|
|
385
|
+
mode: createOnly
|
|
383
386
|
- path: shared-context/agent-outputs/README.md
|
|
384
387
|
template: sharedContext.agentOutputsReadme
|
|
385
388
|
mode: createOnly
|
|
@@ -92,6 +92,12 @@ cronJobs:
|
|
|
92
92
|
message: "Safe-idle loop: check for lifecycle/email work, make progress, and write outputs under roles/lifecycle/agent-outputs/."
|
|
93
93
|
enabledByDefault: false
|
|
94
94
|
|
|
95
|
+
# NOTE: Workflow worker crons are NOT defined here.
|
|
96
|
+
# ClawKitchen installs them on-demand when the user visits a workflow editor
|
|
97
|
+
# and clicks "Install worker cron(s)" or triggers a run. This avoids duplicate
|
|
98
|
+
# crons between recipe scaffolding and Kitchen's reconciliation.
|
|
99
|
+
# Kitchen stores provenance in workspace-<teamId>/notes/cron-jobs.json.
|
|
100
|
+
|
|
95
101
|
# Optional team-wide loop (off by default): can be enabled later if you want an extra generic executor.
|
|
96
102
|
- id: execution-loop
|
|
97
103
|
name: "Execution loop"
|
|
@@ -212,8 +212,8 @@ templates:
|
|
|
212
212
|
pm.agents: |
|
|
213
213
|
# AGENTS.md
|
|
214
214
|
|
|
215
|
-
Team: {teamId}
|
|
216
|
-
Shared workspace: {teamDir}
|
|
215
|
+
Team: {{teamId}}
|
|
216
|
+
Shared workspace: {{teamDir}}
|
|
217
217
|
Role: pm
|
|
218
218
|
|
|
219
219
|
## Guardrails (read → act → write)
|
|
@@ -242,8 +242,8 @@ templates:
|
|
|
242
242
|
designer.agents: |
|
|
243
243
|
# AGENTS.md
|
|
244
244
|
|
|
245
|
-
Team: {teamId}
|
|
246
|
-
Shared workspace: {teamDir}
|
|
245
|
+
Team: {{teamId}}
|
|
246
|
+
Shared workspace: {{teamDir}}
|
|
247
247
|
Role: designer
|
|
248
248
|
|
|
249
249
|
## Guardrails (read → act → write)
|
|
@@ -272,8 +272,8 @@ templates:
|
|
|
272
272
|
engineer.agents: |
|
|
273
273
|
# AGENTS.md
|
|
274
274
|
|
|
275
|
-
Team: {teamId}
|
|
276
|
-
Shared workspace: {teamDir}
|
|
275
|
+
Team: {{teamId}}
|
|
276
|
+
Shared workspace: {{teamDir}}
|
|
277
277
|
Role: engineer
|
|
278
278
|
|
|
279
279
|
## Guardrails (read → act → write)
|
|
@@ -302,8 +302,8 @@ templates:
|
|
|
302
302
|
test.agents: |
|
|
303
303
|
# AGENTS.md
|
|
304
304
|
|
|
305
|
-
Team: {teamId}
|
|
306
|
-
Shared workspace: {teamDir}
|
|
305
|
+
Team: {{teamId}}
|
|
306
|
+
Shared workspace: {{teamDir}}
|
|
307
307
|
Role: test
|
|
308
308
|
|
|
309
309
|
## Guardrails (read → act → write)
|
|
@@ -428,6 +428,9 @@ files:
|
|
|
428
428
|
- path: shared-context/priorities.md
|
|
429
429
|
template: sharedContext.priorities
|
|
430
430
|
mode: createOnly
|
|
431
|
+
- path: shared-context/MEMORY_PLAN.md
|
|
432
|
+
template: sharedContext.memoryPlan
|
|
433
|
+
mode: createOnly
|
|
431
434
|
- path: shared-context/agent-outputs/README.md
|
|
432
435
|
template: sharedContext.agentOutputsReadme
|
|
433
436
|
mode: createOnly
|
|
@@ -209,8 +209,8 @@ templates:
|
|
|
209
209
|
researcher.agents: |
|
|
210
210
|
# AGENTS.md
|
|
211
211
|
|
|
212
|
-
Team: {teamId}
|
|
213
|
-
Shared workspace: {teamDir}
|
|
212
|
+
Team: {{teamId}}
|
|
213
|
+
Shared workspace: {{teamDir}}
|
|
214
214
|
Role: researcher
|
|
215
215
|
|
|
216
216
|
## Guardrails (read → act → write)
|
|
@@ -239,8 +239,8 @@ templates:
|
|
|
239
239
|
fact-checker.agents: |
|
|
240
240
|
# AGENTS.md
|
|
241
241
|
|
|
242
|
-
Team: {teamId}
|
|
243
|
-
Shared workspace: {teamDir}
|
|
242
|
+
Team: {{teamId}}
|
|
243
|
+
Shared workspace: {{teamDir}}
|
|
244
244
|
Role: fact-checker
|
|
245
245
|
|
|
246
246
|
## Guardrails (read → act → write)
|
|
@@ -269,8 +269,8 @@ templates:
|
|
|
269
269
|
summarizer.agents: |
|
|
270
270
|
# AGENTS.md
|
|
271
271
|
|
|
272
|
-
Team: {teamId}
|
|
273
|
-
Shared workspace: {teamDir}
|
|
272
|
+
Team: {{teamId}}
|
|
273
|
+
Shared workspace: {{teamDir}}
|
|
274
274
|
Role: summarizer
|
|
275
275
|
|
|
276
276
|
## Guardrails (read → act → write)
|
|
@@ -380,6 +380,9 @@ files:
|
|
|
380
380
|
- path: shared-context/priorities.md
|
|
381
381
|
template: sharedContext.priorities
|
|
382
382
|
mode: createOnly
|
|
383
|
+
- path: shared-context/MEMORY_PLAN.md
|
|
384
|
+
template: sharedContext.memoryPlan
|
|
385
|
+
mode: createOnly
|
|
383
386
|
- path: shared-context/agent-outputs/README.md
|
|
384
387
|
template: sharedContext.agentOutputsReadme
|
|
385
388
|
mode: createOnly
|
|
@@ -224,8 +224,8 @@ templates:
|
|
|
224
224
|
research.agents: |
|
|
225
225
|
# AGENTS.md
|
|
226
226
|
|
|
227
|
-
Team: {teamId}
|
|
228
|
-
Shared workspace: {teamDir}
|
|
227
|
+
Team: {{teamId}}
|
|
228
|
+
Shared workspace: {{teamDir}}
|
|
229
229
|
Role: research
|
|
230
230
|
|
|
231
231
|
## Guardrails (read → act → write)
|
|
@@ -259,8 +259,8 @@ templates:
|
|
|
259
259
|
listening.agents: |
|
|
260
260
|
# AGENTS.md
|
|
261
261
|
|
|
262
|
-
Team: {teamId}
|
|
263
|
-
Shared workspace: {teamDir}
|
|
262
|
+
Team: {{teamId}}
|
|
263
|
+
Shared workspace: {{teamDir}}
|
|
264
264
|
Role: listening
|
|
265
265
|
|
|
266
266
|
## Guardrails (read → act → write)
|
|
@@ -294,8 +294,8 @@ templates:
|
|
|
294
294
|
social-seo.agents: |
|
|
295
295
|
# AGENTS.md
|
|
296
296
|
|
|
297
|
-
Team: {teamId}
|
|
298
|
-
Shared workspace: {teamDir}
|
|
297
|
+
Team: {{teamId}}
|
|
298
|
+
Shared workspace: {{teamDir}}
|
|
299
299
|
Role: social-seo
|
|
300
300
|
|
|
301
301
|
## Guardrails (read → act → write)
|
|
@@ -329,8 +329,8 @@ templates:
|
|
|
329
329
|
editorial.agents: |
|
|
330
330
|
# AGENTS.md
|
|
331
331
|
|
|
332
|
-
Team: {teamId}
|
|
333
|
-
Shared workspace: {teamDir}
|
|
332
|
+
Team: {{teamId}}
|
|
333
|
+
Shared workspace: {{teamDir}}
|
|
334
334
|
Role: editorial
|
|
335
335
|
|
|
336
336
|
## Guardrails (read → act → write)
|
|
@@ -364,8 +364,8 @@ templates:
|
|
|
364
364
|
community.agents: |
|
|
365
365
|
# AGENTS.md
|
|
366
366
|
|
|
367
|
-
Team: {teamId}
|
|
368
|
-
Shared workspace: {teamDir}
|
|
367
|
+
Team: {{teamId}}
|
|
368
|
+
Shared workspace: {{teamDir}}
|
|
369
369
|
Role: community
|
|
370
370
|
|
|
371
371
|
## Guardrails (read → act → write)
|
|
@@ -399,8 +399,8 @@ templates:
|
|
|
399
399
|
distributor.agents: |
|
|
400
400
|
# AGENTS.md
|
|
401
401
|
|
|
402
|
-
Team: {teamId}
|
|
403
|
-
Shared workspace: {teamDir}
|
|
402
|
+
Team: {{teamId}}
|
|
403
|
+
Shared workspace: {{teamDir}}
|
|
404
404
|
Role: distributor
|
|
405
405
|
|
|
406
406
|
## Guardrails (read → act → write)
|
|
@@ -434,8 +434,8 @@ templates:
|
|
|
434
434
|
tiktok.agents: |
|
|
435
435
|
# AGENTS.md
|
|
436
436
|
|
|
437
|
-
Team: {teamId}
|
|
438
|
-
Shared workspace: {teamDir}
|
|
437
|
+
Team: {{teamId}}
|
|
438
|
+
Shared workspace: {{teamDir}}
|
|
439
439
|
Role: tiktok
|
|
440
440
|
|
|
441
441
|
## Guardrails (read → act → write)
|
|
@@ -469,8 +469,8 @@ templates:
|
|
|
469
469
|
instagram.agents: |
|
|
470
470
|
# AGENTS.md
|
|
471
471
|
|
|
472
|
-
Team: {teamId}
|
|
473
|
-
Shared workspace: {teamDir}
|
|
472
|
+
Team: {{teamId}}
|
|
473
|
+
Shared workspace: {{teamDir}}
|
|
474
474
|
Role: instagram
|
|
475
475
|
|
|
476
476
|
## Guardrails (read → act → write)
|
|
@@ -504,8 +504,8 @@ templates:
|
|
|
504
504
|
youtube.agents: |
|
|
505
505
|
# AGENTS.md
|
|
506
506
|
|
|
507
|
-
Team: {teamId}
|
|
508
|
-
Shared workspace: {teamDir}
|
|
507
|
+
Team: {{teamId}}
|
|
508
|
+
Shared workspace: {{teamDir}}
|
|
509
509
|
Role: youtube
|
|
510
510
|
|
|
511
511
|
## Guardrails (read → act → write)
|
|
@@ -539,8 +539,8 @@ templates:
|
|
|
539
539
|
facebook.agents: |
|
|
540
540
|
# AGENTS.md
|
|
541
541
|
|
|
542
|
-
Team: {teamId}
|
|
543
|
-
Shared workspace: {teamDir}
|
|
542
|
+
Team: {{teamId}}
|
|
543
|
+
Shared workspace: {{teamDir}}
|
|
544
544
|
Role: facebook
|
|
545
545
|
|
|
546
546
|
## Guardrails (read → act → write)
|
|
@@ -574,8 +574,8 @@ templates:
|
|
|
574
574
|
x.agents: |
|
|
575
575
|
# AGENTS.md
|
|
576
576
|
|
|
577
|
-
Team: {teamId}
|
|
578
|
-
Shared workspace: {teamDir}
|
|
577
|
+
Team: {{teamId}}
|
|
578
|
+
Shared workspace: {{teamDir}}
|
|
579
579
|
Role: x
|
|
580
580
|
|
|
581
581
|
## Guardrails (read → act → write)
|
|
@@ -609,8 +609,8 @@ templates:
|
|
|
609
609
|
linkedin.agents: |
|
|
610
610
|
# AGENTS.md
|
|
611
611
|
|
|
612
|
-
Team: {teamId}
|
|
613
|
-
Shared workspace: {teamDir}
|
|
612
|
+
Team: {{teamId}}
|
|
613
|
+
Shared workspace: {{teamDir}}
|
|
614
614
|
Role: linkedin
|
|
615
615
|
|
|
616
616
|
## Guardrails (read → act → write)
|
|
@@ -856,6 +856,9 @@ files:
|
|
|
856
856
|
- path: shared-context/priorities.md
|
|
857
857
|
template: sharedContext.priorities
|
|
858
858
|
mode: createOnly
|
|
859
|
+
- path: shared-context/MEMORY_PLAN.md
|
|
860
|
+
template: sharedContext.memoryPlan
|
|
861
|
+
mode: createOnly
|
|
859
862
|
- path: shared-context/agent-outputs/README.md
|
|
860
863
|
template: sharedContext.agentOutputsReadme
|
|
861
864
|
mode: createOnly
|
|
@@ -206,8 +206,8 @@ templates:
|
|
|
206
206
|
outliner.agents: |
|
|
207
207
|
# AGENTS.md
|
|
208
208
|
|
|
209
|
-
Team: {teamId}
|
|
210
|
-
Shared workspace: {teamDir}
|
|
209
|
+
Team: {{teamId}}
|
|
210
|
+
Shared workspace: {{teamDir}}
|
|
211
211
|
Role: outliner
|
|
212
212
|
|
|
213
213
|
## Guardrails (read → act → write)
|
|
@@ -236,8 +236,8 @@ templates:
|
|
|
236
236
|
writer.agents: |
|
|
237
237
|
# AGENTS.md
|
|
238
238
|
|
|
239
|
-
Team: {teamId}
|
|
240
|
-
Shared workspace: {teamDir}
|
|
239
|
+
Team: {{teamId}}
|
|
240
|
+
Shared workspace: {{teamDir}}
|
|
241
241
|
Role: writer
|
|
242
242
|
|
|
243
243
|
## Guardrails (read → act → write)
|
|
@@ -266,8 +266,8 @@ templates:
|
|
|
266
266
|
editor.agents: |
|
|
267
267
|
# AGENTS.md
|
|
268
268
|
|
|
269
|
-
Team: {teamId}
|
|
270
|
-
Shared workspace: {teamDir}
|
|
269
|
+
Team: {{teamId}}
|
|
270
|
+
Shared workspace: {{teamDir}}
|
|
271
271
|
Role: editor
|
|
272
272
|
|
|
273
273
|
## Guardrails (read → act → write)
|
|
@@ -377,6 +377,9 @@ files:
|
|
|
377
377
|
- path: shared-context/priorities.md
|
|
378
378
|
template: sharedContext.priorities
|
|
379
379
|
mode: createOnly
|
|
380
|
+
- path: shared-context/MEMORY_PLAN.md
|
|
381
|
+
template: sharedContext.memoryPlan
|
|
382
|
+
mode: createOnly
|
|
380
383
|
- path: shared-context/agent-outputs/README.md
|
|
381
384
|
template: sharedContext.agentOutputsReadme
|
|
382
385
|
mode: createOnly
|
package/src/handlers/cron.ts
CHANGED
|
@@ -19,7 +19,7 @@ function interpolateTemplate(input: string | undefined, vars: Record<string, str
|
|
|
19
19
|
|
|
20
20
|
function applyCronJobVars(
|
|
21
21
|
scope: CronReconcileScope,
|
|
22
|
-
j: { id: string; name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; enabledByDefault?: boolean },
|
|
22
|
+
j: { id: string; name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; enabledByDefault?: boolean; delivery?: 'none' | 'announce' },
|
|
23
23
|
): typeof j {
|
|
24
24
|
const vars: Record<string, string> = {
|
|
25
25
|
recipeId: scope.recipeId,
|
|
@@ -64,7 +64,7 @@ type CronReconcileScope =
|
|
|
64
64
|
|
|
65
65
|
function buildCronJobForCreate(
|
|
66
66
|
scope: CronReconcileScope,
|
|
67
|
-
j: { id: string; name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; enabledByDefault?: boolean },
|
|
67
|
+
j: { id: string; name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; enabledByDefault?: boolean; delivery?: 'none' | 'announce' },
|
|
68
68
|
wantEnabled: boolean
|
|
69
69
|
): Record<string, unknown> {
|
|
70
70
|
const name =
|
|
@@ -91,21 +91,23 @@ function buildCronJobForCreate(
|
|
|
91
91
|
sessionTarget,
|
|
92
92
|
schedule: { kind: "cron", expr: j.schedule, ...(j.timezone ? { tz: j.timezone } : {}) },
|
|
93
93
|
payload: effectiveAgentId ? { kind: "agentTurn", message: j.message } : { kind: "systemEvent", text: j.message },
|
|
94
|
-
...(j.
|
|
95
|
-
? {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
94
|
+
...(j.delivery === 'none'
|
|
95
|
+
? { delivery: { mode: "none" } }
|
|
96
|
+
: j.channel || j.to
|
|
97
|
+
? {
|
|
98
|
+
delivery: {
|
|
99
|
+
mode: "announce",
|
|
100
|
+
...(j.channel ? { channel: j.channel } : {}),
|
|
101
|
+
...(j.to ? { to: j.to } : {}),
|
|
102
|
+
bestEffort: true,
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
: {}),
|
|
104
106
|
};
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
function buildCronJobPatch(
|
|
108
|
-
j: { name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string },
|
|
110
|
+
j: { name?: string; schedule?: string; timezone?: string; channel?: string; to?: string; agentId?: string; description?: string; message?: string; delivery?: 'none' | 'announce' },
|
|
109
111
|
name: string
|
|
110
112
|
): CronJobPatch {
|
|
111
113
|
const effectiveAgentId = typeof j.agentId === "string" && j.agentId.trim() ? j.agentId.trim() : undefined;
|
|
@@ -119,7 +121,9 @@ function buildCronJobPatch(
|
|
|
119
121
|
schedule: { kind: "cron", expr: j.schedule, ...(j.timezone ? { tz: j.timezone } : {}) },
|
|
120
122
|
payload: effectiveAgentId ? { kind: "agentTurn", message: j.message } : { kind: "systemEvent", text: j.message },
|
|
121
123
|
};
|
|
122
|
-
if (j.
|
|
124
|
+
if (j.delivery === 'none') {
|
|
125
|
+
patch.delivery = { mode: "none" };
|
|
126
|
+
} else if (j.channel || j.to) {
|
|
123
127
|
patch.delivery = {
|
|
124
128
|
mode: "announce",
|
|
125
129
|
...(j.channel ? { channel: j.channel } : {}),
|
|
@@ -229,11 +233,16 @@ async function cronAdd(api: OpenClawPluginApi, job: Record<string, unknown>): Pr
|
|
|
229
233
|
|
|
230
234
|
// delivery
|
|
231
235
|
const delivery = j.delivery;
|
|
232
|
-
if (delivery && typeof delivery === "object"
|
|
233
|
-
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
236
|
+
if (delivery && typeof delivery === "object") {
|
|
237
|
+
const deliveryMode = String(delivery.mode ?? "");
|
|
238
|
+
if (deliveryMode === "announce") {
|
|
239
|
+
argv.push("--announce");
|
|
240
|
+
if (delivery.channel) argv.push("--channel", String(delivery.channel));
|
|
241
|
+
if (delivery.to) argv.push("--to", String(delivery.to));
|
|
242
|
+
if (delivery.bestEffort) argv.push("--best-effort-deliver");
|
|
243
|
+
} else if (deliveryMode === "none") {
|
|
244
|
+
argv.push("--no-deliver");
|
|
245
|
+
}
|
|
237
246
|
}
|
|
238
247
|
|
|
239
248
|
const result = await api.runtime.system.runCommandWithTimeout(argv, { timeoutMs: 30_000 });
|
package/src/handlers/team.ts
CHANGED
|
@@ -140,6 +140,45 @@ Default behavior: **quiet**. If there is nothing to report, do nothing.
|
|
|
140
140
|
await writeFileSafely(path.join(teamDir, "TICKETS.md"), ticketsMd, mode);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Write team-level files from the recipe files[] array.
|
|
145
|
+
*
|
|
146
|
+
* Per-role scaffolding (scaffoldTeamAgents) filters out paths starting with
|
|
147
|
+
* "shared-context/" and "notes/" because those belong to the team workspace root,
|
|
148
|
+
* not individual role directories. This function picks up those filtered paths
|
|
149
|
+
* and writes them to teamDir using the recipe's templates.
|
|
150
|
+
*/
|
|
151
|
+
async function writeTeamLevelRecipeFiles(opts: {
|
|
152
|
+
recipe: RecipeFrontmatter;
|
|
153
|
+
teamId: string;
|
|
154
|
+
teamDir: string;
|
|
155
|
+
overwrite: boolean;
|
|
156
|
+
}) {
|
|
157
|
+
const { recipe, teamId, teamDir, overwrite } = opts;
|
|
158
|
+
const files = recipe.files ?? [];
|
|
159
|
+
if (!files.length) return;
|
|
160
|
+
const mode = overwrite ? "overwrite" : "createOnly";
|
|
161
|
+
const templates = (recipe.templates ?? {}) as Record<string, unknown>;
|
|
162
|
+
const vars = { teamId, teamDir };
|
|
163
|
+
|
|
164
|
+
for (const f of files) {
|
|
165
|
+
const filePath = String(f.path ?? "").trim();
|
|
166
|
+
if (!filePath) continue;
|
|
167
|
+
// Only process paths that are team-scoped (filtered out of per-role scaffolding).
|
|
168
|
+
if (!filePath.startsWith("shared-context/") && !filePath.startsWith("notes/")) continue;
|
|
169
|
+
|
|
170
|
+
const templateKey = String(f.template ?? "").trim();
|
|
171
|
+
if (!templateKey) continue;
|
|
172
|
+
|
|
173
|
+
const templateContent = templates[templateKey];
|
|
174
|
+
if (typeof templateContent !== "string") continue;
|
|
175
|
+
|
|
176
|
+
const rendered = renderTemplate(templateContent, vars);
|
|
177
|
+
const target = path.join(teamDir, filePath);
|
|
178
|
+
await writeFileSafely(target, rendered, mode);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
143
182
|
async function writeTeamMetadataAndConfig(opts: {
|
|
144
183
|
api: OpenClawPluginApi;
|
|
145
184
|
teamId: string;
|
|
@@ -392,6 +431,8 @@ export async function handleScaffoldTeam(
|
|
|
392
431
|
const { loaded, recipe, cfg, workspaceRoot: baseWorkspace } = validation;
|
|
393
432
|
|
|
394
433
|
// Lint (warn-only) for common team scaffolding pitfalls.
|
|
434
|
+
// NOTE: console.warn/error used throughout src/ for [recipes]-prefixed diagnostics.
|
|
435
|
+
// No plugin SDK logger available; these go to stderr which the host captures.
|
|
395
436
|
for (const issue of lintRecipe(recipe)) {
|
|
396
437
|
if (issue.level === "warn") console.warn(`[recipes] WARN ${issue.code}: ${issue.message}`);
|
|
397
438
|
else console.warn(`[recipes] ${issue.code}: ${issue.message}`);
|
|
@@ -439,6 +480,11 @@ export async function handleScaffoldTeam(
|
|
|
439
480
|
overwrite,
|
|
440
481
|
qaChecklist,
|
|
441
482
|
});
|
|
483
|
+
// Write team-level files from the recipe files[] array.
|
|
484
|
+
// Per-role scaffolding filters out shared-context/ and notes/ paths (those belong to teamDir).
|
|
485
|
+
// We render and write them here so recipe-defined team assets are not silently dropped.
|
|
486
|
+
await writeTeamLevelRecipeFiles({ recipe, teamId, teamDir, overwrite });
|
|
487
|
+
|
|
442
488
|
const heartbeat = buildHeartbeatCronJobsFromTeamRecipe({
|
|
443
489
|
teamId,
|
|
444
490
|
recipe,
|
|
@@ -11,6 +11,8 @@ export type CronJobSpec = {
|
|
|
11
11
|
to?: string;
|
|
12
12
|
agentId?: string;
|
|
13
13
|
enabledByDefault?: boolean;
|
|
14
|
+
/** Delivery mode: "none" suppresses announce; "announce" delivers to chat. Omit to use gateway default. */
|
|
15
|
+
delivery?: 'none' | 'announce';
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
/** Raw input for a cron job from YAML (supports message/task/prompt for backward compat). */
|
|
@@ -27,6 +29,7 @@ type CronJobInput = {
|
|
|
27
29
|
to?: unknown;
|
|
28
30
|
agentId?: unknown;
|
|
29
31
|
enabledByDefault?: unknown;
|
|
32
|
+
delivery?: unknown;
|
|
30
33
|
};
|
|
31
34
|
|
|
32
35
|
export type RecipeFrontmatter = {
|
|
@@ -83,6 +86,7 @@ function buildCronJobSpec(j: CronJobInput, id: string): CronJobSpec {
|
|
|
83
86
|
to: j.to != null ? String(j.to) : undefined,
|
|
84
87
|
agentId: j.agentId != null ? String(j.agentId) : undefined,
|
|
85
88
|
enabledByDefault: Boolean(j.enabledByDefault ?? false),
|
|
89
|
+
delivery: j.delivery === 'none' || j.delivery === 'announce' ? j.delivery : undefined,
|
|
86
90
|
};
|
|
87
91
|
}
|
|
88
92
|
|