@worca/app 1.3.0-rc.2 → 1.4.0-rc.1

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.
Files changed (187) hide show
  1. package/README.md +85 -6
  2. package/agents/clarify.meta.json +1 -0
  3. package/agents/memoryDefragmenter.meta.json +2 -1
  4. package/agents/reviewer.meta.json +60 -0
  5. package/agents/worca-cc-code-reviewer.md +33 -0
  6. package/agents/worca-cc-memory-defragmenter.md +5 -3
  7. package/agents/workspaceScanner.meta.json +1 -0
  8. package/package.json +14 -10
  9. package/scripts/git-diff.mjs +25 -0
  10. package/scripts/gitDiff.meta.json +18 -0
  11. package/scripts/js-inline.mjs +11 -0
  12. package/scripts/js.meta.json +22 -0
  13. package/scripts/py-inline.py +27 -0
  14. package/scripts/py.meta.json +22 -0
  15. package/scripts/shell.meta.json +24 -0
  16. package/skills/worca/SKILL.md +3 -2
  17. package/src/cli/models.mjs +247 -0
  18. package/src/cli/render.mjs +72 -4
  19. package/src/cli/schedule.mjs +494 -0
  20. package/src/cli/worca-cc.mjs +1001 -22
  21. package/src/core/agent-registry.mjs +75 -23
  22. package/src/core/agent-store.mjs +51 -2
  23. package/src/core/artifacts.mjs +73 -10
  24. package/src/core/ask/events.mjs +119 -1
  25. package/src/core/ask/limits.mjs +32 -4
  26. package/src/core/ask/mcp-stdio.mjs +12 -0
  27. package/src/core/ask/model-deps.mjs +126 -0
  28. package/src/core/ask/model-proposal.mjs +370 -0
  29. package/src/core/ask/models.mjs +12 -0
  30. package/src/core/ask/policy-deps.mjs +124 -0
  31. package/src/core/ask/policy-proposal.mjs +363 -0
  32. package/src/core/ask/prompt.mjs +74 -9
  33. package/src/core/ask/proposal.mjs +54 -5
  34. package/src/core/ask/schedule-deps.mjs +83 -0
  35. package/src/core/ask/schedule-spec.mjs +310 -0
  36. package/src/core/ask/script-deps.mjs +357 -0
  37. package/src/core/ask/source-deps.mjs +52 -0
  38. package/src/core/ask/source-spec.mjs +157 -0
  39. package/src/core/ask/spawn.mjs +1 -0
  40. package/src/core/ask/store.mjs +6 -3
  41. package/src/core/ask/tool-deps.mjs +4 -0
  42. package/src/core/ask/tools.mjs +657 -37
  43. package/src/core/ask/turn.mjs +109 -2
  44. package/src/core/ask-files.mjs +406 -0
  45. package/src/core/ask-forms.mjs +195 -0
  46. package/src/core/ask-projection.mjs +72 -0
  47. package/src/core/bridge/errors.mjs +84 -0
  48. package/src/core/bridge/provider-ops.mjs +281 -0
  49. package/src/core/bridge/providers/copilot.mjs +269 -0
  50. package/src/core/bridge/providers/endpoint.mjs +257 -0
  51. package/src/core/bridge/registry.mjs +88 -0
  52. package/src/core/bridge/semaphore.mjs +73 -0
  53. package/src/core/bridge/server.mjs +184 -0
  54. package/src/core/bridge/telemetry.mjs +53 -0
  55. package/src/core/bridge/translate/request.mjs +252 -0
  56. package/src/core/bridge/translate/response.mjs +82 -0
  57. package/src/core/bridge/translate/stream.mjs +242 -0
  58. package/src/core/bridge/upstream.mjs +209 -0
  59. package/src/core/chat/command-router.mjs +58 -4
  60. package/src/core/chat/notifier.mjs +14 -1
  61. package/src/core/chat/renderers.mjs +35 -0
  62. package/src/core/claude-runner.mjs +126 -19
  63. package/src/core/config.mjs +212 -31
  64. package/src/core/cost-budget.mjs +3 -2
  65. package/src/core/db.mjs +169 -15
  66. package/src/core/failure-policy.mjs +10 -0
  67. package/src/core/fs-browse.mjs +16 -4
  68. package/src/core/git-info.mjs +22 -0
  69. package/src/core/graph/builtin-workflows.mjs +3 -1
  70. package/src/core/graph/exec-io.mjs +71 -0
  71. package/src/core/graph/executor.mjs +139 -70
  72. package/src/core/graph/human-evidence.mjs +131 -0
  73. package/src/core/graph/python-probe.mjs +172 -0
  74. package/src/core/graph/registry-ports.mjs +10 -6
  75. package/src/core/graph/scheduler.mjs +39 -24
  76. package/src/core/graph/script-child.mjs +81 -0
  77. package/src/core/graph/script-runner.mjs +597 -0
  78. package/src/core/graph/worca_script.py +207 -0
  79. package/src/core/guardrail-store.mjs +16 -0
  80. package/src/core/human-backfill.mjs +108 -0
  81. package/src/core/human-rate.mjs +17 -0
  82. package/src/core/index-html.mjs +6 -2
  83. package/src/core/memory-defrag-model.mjs +112 -0
  84. package/src/core/memory-store.mjs +70 -18
  85. package/src/core/memory-sync.mjs +22 -11
  86. package/src/core/metrics/read.mjs +4 -1
  87. package/src/core/metrics/record.mjs +50 -2
  88. package/src/core/metrics/sync.mjs +6 -4
  89. package/src/core/model-env.mjs +149 -0
  90. package/src/core/model-test.mjs +14 -1
  91. package/src/core/notifications.mjs +128 -0
  92. package/src/core/onboarding.mjs +8 -2
  93. package/src/core/orchestrator.mjs +357 -26
  94. package/src/core/phases.mjs +95 -6
  95. package/src/core/plugin-api.mjs +24 -7
  96. package/src/core/plugin-manifest.mjs +184 -18
  97. package/src/core/plugin-models.mjs +1 -0
  98. package/src/core/plugin-script-cases.mjs +118 -0
  99. package/src/core/plugin-store.mjs +163 -17
  100. package/src/core/plugin-workflows.mjs +71 -17
  101. package/src/core/policy/cache.mjs +116 -0
  102. package/src/core/policy/effective.mjs +175 -0
  103. package/src/core/policy/gate.mjs +91 -0
  104. package/src/core/policy/local.mjs +145 -0
  105. package/src/core/policy/registry.mjs +330 -0
  106. package/src/core/policy/scope.mjs +61 -0
  107. package/src/core/policy/state.mjs +79 -0
  108. package/src/core/policy/sync.mjs +513 -0
  109. package/src/core/protocol.mjs +43 -0
  110. package/src/core/run-harness.mjs +421 -72
  111. package/src/core/scheduler.mjs +980 -0
  112. package/src/core/script-bench.mjs +628 -0
  113. package/src/core/script-registry.mjs +116 -0
  114. package/src/core/script-store.mjs +563 -0
  115. package/src/core/settings.mjs +489 -14
  116. package/src/core/stats.mjs +33 -2
  117. package/src/core/workflow-export.mjs +94 -3
  118. package/src/core/workflow-share.mjs +67 -18
  119. package/src/core/workflows.mjs +47 -11
  120. package/src/core/workspaces.mjs +18 -12
  121. package/src/shared/forms/answer.mjs +164 -0
  122. package/src/shared/forms/catalog.mjs +91 -0
  123. package/src/shared/forms/form-def.mjs +290 -0
  124. package/src/shared/forms/layout.mjs +67 -0
  125. package/src/shared/forms/paths.mjs +47 -0
  126. package/src/shared/forms/project.mjs +309 -0
  127. package/src/shared/forms/schema.mjs +205 -0
  128. package/src/shared/graph/agent-meta.mjs +55 -5
  129. package/src/shared/graph/constants.mjs +14 -2
  130. package/src/shared/graph/flow-layout.mjs +2 -1
  131. package/src/shared/graph/isomorphic.mjs +5 -3
  132. package/src/shared/graph/manifest.mjs +22 -13
  133. package/src/shared/graph/ports.mjs +45 -19
  134. package/src/shared/graph/script-cases.mjs +257 -0
  135. package/src/shared/graph/script-icons.mjs +46 -0
  136. package/src/shared/graph/script-infer.mjs +259 -0
  137. package/src/shared/graph/script-meta.mjs +408 -0
  138. package/src/shared/graph/script-templates.mjs +201 -0
  139. package/src/shared/graph/template.mjs +4 -4
  140. package/src/shared/graph/validate.mjs +89 -16
  141. package/src/shared/human-estimate.mjs +100 -0
  142. package/src/shared/schedule/recurrence.mjs +353 -0
  143. package/src/shared/team-metrics/aggregate.mjs +51 -11
  144. package/{scripts → tools}/install.mjs +3 -3
  145. package/ui/public/app.js +4390 -683
  146. package/ui/public/artifact-picker.mjs +189 -0
  147. package/ui/public/ask/dom.mjs +121 -0
  148. package/ui/public/ask/form-preview.mjs +55 -0
  149. package/ui/public/ask/form-renderer.mjs +250 -0
  150. package/ui/public/ask/registry.mjs +53 -0
  151. package/ui/public/ask/widgets-display.mjs +370 -0
  152. package/ui/public/ask/widgets-input.mjs +624 -0
  153. package/ui/public/ask/widgets-layout.mjs +90 -0
  154. package/ui/public/ask-panel.mjs +401 -27
  155. package/ui/public/ask-run-card.mjs +1 -1
  156. package/ui/public/bridge-view.mjs +694 -0
  157. package/ui/public/chat-settings-view.mjs +24 -0
  158. package/ui/public/code-editor.mjs +181 -0
  159. package/ui/public/getting-started.mjs +34 -7
  160. package/ui/public/graph/composer.mjs +138 -10
  161. package/ui/public/graph/inspector.mjs +61 -58
  162. package/ui/public/graph/palette.mjs +27 -9
  163. package/ui/public/graph/run-decor.mjs +34 -17
  164. package/ui/public/graph/run-hosts.mjs +7 -1
  165. package/ui/public/graph/save-dialog.mjs +3 -0
  166. package/ui/public/graph/view.mjs +23 -7
  167. package/ui/public/guardrails-view.mjs +15 -3
  168. package/ui/public/guide-spot.mjs +87 -9
  169. package/ui/public/index.html +480 -141
  170. package/ui/public/memory-view.mjs +22 -4
  171. package/ui/public/models-view.mjs +162 -17
  172. package/ui/public/node-tunables.mjs +33 -4
  173. package/ui/public/plugins-view.mjs +23 -1
  174. package/ui/public/results-view.mjs +4 -2
  175. package/ui/public/schedule-sheet.mjs +430 -0
  176. package/ui/public/schedules-view.mjs +432 -0
  177. package/ui/public/script-bench-view.mjs +1154 -0
  178. package/ui/public/script-forms.mjs +282 -0
  179. package/ui/public/script-wizard.mjs +529 -0
  180. package/ui/public/scripts-view.mjs +868 -0
  181. package/ui/public/stats-view.mjs +159 -52
  182. package/ui/public/style.css +1461 -44
  183. package/ui/public/team-metrics-surfaces.mjs +77 -16
  184. package/ui/public/team-metrics-view.mjs +68 -5
  185. package/ui/public/team-policy-view.mjs +1402 -0
  186. package/ui/public/ui-level.mjs +237 -0
  187. package/ui/server.mjs +1827 -73
package/README.md CHANGED
@@ -90,10 +90,25 @@ and durations, the clarify Q&A, agent transcripts, and logs:
90
90
  - **AI-assisted agent creation** — describe a new agent in the UI and Worca
91
91
  generates both its system prompt and metadata (or paste your own prompt and
92
92
  let it infer just the wiring); edit, regenerate, and save.
93
+ - **Ask forms** — an agent that needs a human can ship the UI its question is
94
+ asked with: JSON in its sidecar, drawn by worca from a fixed widget catalog
95
+ (galleries, rankings, per-item review lists, previews of the files it just
96
+ produced), validated on the way back, with a text projection for the CLI, chat
97
+ and History. Plugins can ship them too.
93
98
  - **Per-agent model & effort** — pick model and reasoning effort per agent,
94
99
  per workflow, or per run, with a clear resolution order and "save as
95
100
  workflow defaults".
96
101
 
102
+ ### Scripts
103
+
104
+ - **Cards that run your own program** — a script card keeps the whole outside of
105
+ an agent card (typed ports, verdict routing, loops) and replaces the inside
106
+ with your own `node` or `shell` program, so a test gate or a
107
+ transform costs no model call; the **Scripts** page creates, edits, duplicates
108
+ and deletes them, and its test bench runs one by itself with hand-filled
109
+ inputs — saved as named cases with an optional expectation, re-run one at a
110
+ time or all at once — through the very same runner a pipeline run uses.
111
+
97
112
  ### Workflow Composer
98
113
 
99
114
  - **Compose your own pipeline** — drag agents onto a canvas and wire their typed
@@ -137,16 +152,32 @@ and durations, the clarify Q&A, agent transcripts, and logs:
137
152
  ### Plugins & chat
138
153
 
139
154
  - **Plugin system with marketplaces** — plugins contribute task sources
140
- (e.g. GitHub Issues), agents, skills, workflow templates, models, and chat
141
- channels. Install from a marketplace with an explicit consent ceremony
142
- (what's installed, which secrets are required, which setup commands run);
143
- updates show a commit-level preview before you accept.
155
+ (e.g. GitHub Issues), agents (with their ask forms), scripts, skills, workflow
156
+ templates, models, and chat channels. Install from a marketplace with an
157
+ explicit consent ceremony (what's installed, which ask forms an agent can show
158
+ and which file types they may display, which secrets are required, which setup
159
+ commands run); updates show a commit-level preview before you accept.
144
160
  - **Drive runs from chat** — bundled two-way **Telegram**, **Slack**,
145
161
  **Discord**, and **Microsoft Teams** channels: get notified on questions,
146
162
  finishes, failures, and cost pauses, and answer back with commands —
147
163
  `/status`, `/cost`, `/answer`, `/approve`, `/pause`, `/resume`, `/stop`,
148
164
  and more — with allowlist-based authorization.
149
165
 
166
+ ### Scheduled runs
167
+
168
+ - **Run it later** — schedule a pipeline for a date and time, or on a repeat
169
+ ("every weekday at 02:00"), from New pipeline, an Ask card, the CLI
170
+ (`--at`, `--every`, `--cron`) or the API (`scheduledFor`, `repeat`). The
171
+ **Schedules** view lists what is planned and an activity feed of every miss,
172
+ failure and self-pause. Runs start while `worca ui` (or a `--wait` terminal) is
173
+ up and the machine is awake. A run can also start after another run, on its
174
+ branch, so runs form a train. See [docs/scheduled-runs.md](docs/scheduled-runs.md).
175
+ - **Ask Worca schedules too** — "run the dependency upgrade every weekday at 2am"
176
+ becomes a run card whose main button is *Schedule*. It lists, explains, pauses,
177
+ resumes and skips schedules on request; moving, editing, cancelling or deleting
178
+ one is a card you confirm. Name a tracker issue ("fix Jira bug PROJ-123 with
179
+ auto, tonight") and the card runs from the issue itself, read when the run starts.
180
+
150
181
  ### Costs & budgets
151
182
 
152
183
  - **Cost tracking everywhere** — per-run and per-step cost estimates, a
@@ -170,6 +201,26 @@ and durations, the clarify Q&A, agent transcripts, and logs:
170
201
 
171
202
  See [`docs/team-metrics.md`](docs/team-metrics.md).
172
203
 
204
+ ### Team policy
205
+
206
+ - **Team-set caps and expectations, distributed by git** — a product manager or lead publishes
207
+ a policy to an orphan `worca-policy` branch on the project's `origin` (protect it so only
208
+ maintainers push); every teammate's Worca reads it. A project carries its own policy or
209
+ follows another project's; a workspace follows a policy home.
210
+ - **Soft by design** — every value is a *default* the developer may change or a *soft
211
+ constraint* the tighter of team and local applies to. Going past a team cap is allowed
212
+ after a confirmation (with an optional or required reason) and is recorded to team
213
+ metrics. Nothing blocks a run; unattended (`--yes`) runs warn instead of pausing.
214
+ - **What a policy can set** — per-pipeline and total cost caps, an advisory pooled budget,
215
+ Ask Worca limits, a default guardrail set and a minimum tier, allowed models and step
216
+ defaults, marketplaces and required plugins (offered through a setup checklist, never
217
+ installed without a click), a default workflow, human-in-the-loop, and more.
218
+ - **A Team policy page** — the effective policy per project or workspace (team value, yours,
219
+ what applies) and an editor that publishes in one commit.
220
+ - **`worca policy show|pull|init|setup`** and `--past-team-cap [--reason "…"]` on runs.
221
+
222
+ See [`docs/team-policy.md`](docs/team-policy.md).
223
+
173
224
  ### Models
174
225
 
175
226
  - **Bring your own models** — register any model id (a proxy, a fine-tune, an
@@ -183,6 +234,13 @@ See [`docs/team-metrics.md`](docs/team-metrics.md).
183
234
  haiku/sonnet/opus/fable tier keys so nothing falls back to the Anthropic API,
184
235
  and *Hide built-in models* (Settings › Models) drops the built-ins from every
185
236
  picker.
237
+ - **GitHub Copilot and OpenAI-compatible endpoints, built in** — Worca's own
238
+ in-process bridge lets the Claude Code CLI run against a Copilot subscription
239
+ (Claude models through Copilot's native Anthropic endpoint, thinking intact;
240
+ GPT, Gemini and the rest through a translation layer) or any
241
+ `/chat/completions` endpoint — no LiteLLM, no second daemon. Sign in once on
242
+ Settings › Models › Providers, import Copilot's models, pick them anywhere.
243
+ See [`docs/models.md`](docs/models.md).
186
244
 
187
245
  ### Storage
188
246
 
@@ -264,20 +322,39 @@ worca --project /path/to/your/project --prompt "Add a /search endpoint" --workfl
264
322
  # pause with Ctrl+C, continue later (survives restarts)
265
323
  worca resume <pipelineId>
266
324
 
325
+ # run it later: once, from this terminal, or on a repeat (needs `worca ui` up, or --wait)
326
+ worca --project /path/to/your/project --prompt "Upgrade dependencies" --at "tomorrow 02:00"
327
+ worca --project /path/to/your/project --prompt "Upgrade dependencies" --at 02:00 --wait --yes
328
+ worca --project /path/to/your/project --file ./nightly.md --every "weekdays 02:00"
329
+ worca schedule list
330
+
267
331
  # offline demo — full pipeline, no tokens
268
332
  worca --project /path/to/your/project --prompt "demo task" --mock --yes
269
333
 
270
334
  # flush pending team-metrics run records (headless machines with no UI server)
271
335
  worca metrics push
272
336
 
273
- # share a saved pipeline: as JSON, or as a plugin folder bundling your agents + skills
337
+ # team policy: what applies to this project, fetch the branch now, meet the setup checklist
338
+ worca policy show
339
+ worca policy pull
340
+ worca policy setup --install
341
+
342
+ # share a saved pipeline: as JSON, or as a plugin folder bundling your agents, scripts + skills
274
343
  worca workflow export wf_my-flow --format json --out my-flow.json
275
344
  worca workflow import my-flow.json
276
345
  worca workflow export wf_my-flow --format plugin --target ./my-flow-plugin
346
+
347
+ # scripts: list, scaffold and test a script card — no server needed
348
+ worca script list
349
+ worca script new runTests --runtime shell
350
+ worca script test runTests
351
+ worca script test shell --param command="npm test" --cwd .
352
+ worca plugin new-script tidy --dir ./my-plugin
353
+ worca plugin validate ./my-plugin --run-cases
277
354
  ```
278
355
 
279
356
  Run `worca --help` for all subcommands (projects, plugins, marketplaces,
280
- workflows, config, doctor) and flags.
357
+ workflows, scripts, config, doctor) and flags.
281
358
 
282
359
  Exit codes, for scripts and CI wrappers: `0` the run finished (or an
283
360
  interactive run paused and you can resume it); `1` a hard error, a stop, or an
@@ -306,6 +383,8 @@ The skill starts the same deterministic orchestrator.
306
383
  - [Architecture](docs/ARCHITECTURE.md) — the whole stack in one picture
307
384
  - [Guardrails](docs/guardrails.md) — policy model, enforcement, limitations
308
385
  - [Team metrics](docs/team-metrics.md) — git-backed, team-wide run records
386
+ - [Team policy](docs/team-policy.md) — team-set cost caps, plugins, models and guardrails from a `worca-policy` branch
387
+ - [Models](docs/models.md) — the catalog, providers (GitHub Copilot, OpenAI-compatible) and the built-in bridge
309
388
  - [Getting started](docs/getting-started.md) — the in-app checklist, welcome and spotlight guides
310
389
  - [Storage](docs/storage.md) — where state lives, project keys, migration
311
390
  - [Releasing](docs/RELEASING.md) — how `@worca/app` versions are published
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "key": "clarify",
3
3
  "metaVersion": 2,
4
+ "humanEffort": { "hours": 0.25 },
4
5
  "mockRole": "clarify",
5
6
  "inputs": [{ "id": "task", "type": "md" }],
6
7
  "outputs": [{ "id": "answers", "type": "json", "filename": "clarify.json", "artifactKind": "clarify" }],
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "key": "memoryDefragmenter",
3
3
  "metaVersion": 2,
4
+ "humanEffort": { "factor": 0 },
4
5
  "mockRole": "memory-defrag",
5
6
  "sideEffect": "memory",
6
7
  "inputs": [
7
8
  { "id": "task", "type": "md", "required": true,
8
- "directive": "Defragment the memory scope named below. Work only inside the mounted memory directory given in your system prompt (the `## Worca memory` block) \u2014 it sits under the project directory at .claude/rules/worca/; never touch anything else in the project directory." }
9
+ "directive": "Defragment the memory scope named below. Work only inside the memory directory your system prompt names (the `## Worca memory` block) \u2014 it sits outside the project checkout, in the run's own memory directory; the copy under the cwd's `.claude/rules/worca/` is read-only, so never write there. Never touch anything in the project directory." }
9
10
  ],
10
11
  "outputs": [
11
12
  { "id": "report", "type": "md", "filename": "defrag-report.md" },
@@ -6,6 +6,66 @@
6
6
  "wantsRequest": true,
7
7
  "workspaceStrategy": "review",
8
8
  "verdict": { "filename": "impl-review-cycle{cycle}.json" },
9
+ "ask": {
10
+ "forms": {
11
+ "review-findings": {
12
+ "version": 1,
13
+ "title": "Confirm these findings",
14
+ "data": {
15
+ "type": "object",
16
+ "required": ["findings"],
17
+ "properties": {
18
+ "summary": { "type": "string", "maxLength": 4000 },
19
+ "findings": {
20
+ "type": "array",
21
+ "maxItems": 20,
22
+ "items": {
23
+ "type": "object",
24
+ "required": ["id", "title"],
25
+ "properties": {
26
+ "id": { "type": "string", "maxLength": 64 },
27
+ "severity": { "type": "string", "enum": ["critical", "major", "minor", "suggestion"] },
28
+ "title": { "type": "string", "maxLength": 200 },
29
+ "detail": { "type": "string", "maxLength": 2000 }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ },
35
+ "answer": {
36
+ "type": "object",
37
+ "required": ["findings"],
38
+ "properties": {
39
+ "findings": {
40
+ "type": "array",
41
+ "items": {
42
+ "type": "object",
43
+ "required": ["id", "verdict"],
44
+ "properties": {
45
+ "id": { "type": "string" },
46
+ "verdict": { "type": "string", "enum": ["keep", "waive"], "default": "keep" },
47
+ "note": { "type": "string", "maxLength": 2000 }
48
+ }
49
+ }
50
+ },
51
+ "notes": { "type": "string", "maxLength": 4000 }
52
+ }
53
+ },
54
+ "layout": [
55
+ { "widget": "markdown", "bind": "data.summary" },
56
+ { "widget": "review-list", "bind": "data.findings", "field": "findings", "label": "Findings" },
57
+ { "widget": "textarea", "field": "notes", "label": "Notes" }
58
+ ],
59
+ "example": {
60
+ "summary": "Two findings I would waive if the deviation was intended.",
61
+ "findings": [
62
+ { "id": "f1", "severity": "major", "title": "Plan deviation: the retry lives in the caller", "detail": "The plan put it in the client. Was that intentional?" },
63
+ { "id": "f2", "severity": "minor", "title": "No unit test for the empty-list branch", "detail": "It is covered by the integration test only." }
64
+ ]
65
+ }
66
+ }
67
+ }
68
+ },
9
69
  "inputs": [
10
70
  { "id": "plan", "type": "md" },
11
71
  { "id": "done", "type": "void", "required": false, "as": "worktree" }
@@ -59,6 +59,39 @@ Severity definitions (use them honestly):
59
59
 
60
60
  After writing both files, emit a short assistant note with the absolute paths of the review markdown and the review JSON, and the count of critical/major issues.
61
61
 
62
+ ## Asking the user about findings (when questions are enabled)
63
+
64
+ If your task prompt carries an "Asking the user" block, you may ask ONCE — and only
65
+ when the answer changes the verdict. Use it for findings you would waive if the
66
+ author's intent were different (a deviation that may have been deliberate, a
67
+ missing test that may be covered elsewhere). Do not use it to ask for permission
68
+ to review, and never ask about a finding you are certain of.
69
+
70
+ Write this to the questions file instead of the legacy `{"questions":[…]}` shape:
71
+
72
+ ```json
73
+ { "form": "review-findings",
74
+ "data": {
75
+ "summary": "One paragraph: what you are unsure about and why it matters.",
76
+ "findings": [
77
+ { "id": "f1", "severity": "major", "title": "Plan deviation: the retry lives in the caller",
78
+ "detail": "The plan put it in the client. Was that intentional?" }
79
+ ] } }
80
+ ```
81
+
82
+ Then STOP — do no further work. You are resumed with:
83
+
84
+ ```json
85
+ { "form": "review-findings", "version": 1,
86
+ "values": { "findings": [ { "id": "f1", "verdict": "waive", "note": "Deliberate, see ADR-12." } ],
87
+ "notes": "" } }
88
+ ```
89
+
90
+ A `waive` verdict means that finding must NOT appear as blocking in
91
+ `review-cycleN.json`; record the waiver and the user's note in the review markdown
92
+ so the decision is visible. A `keep` verdict changes nothing. Every finding you did
93
+ not ask about is yours to judge as usual.
94
+
62
95
  ## Output contract reminders
63
96
  - The review JSON must be valid and match the shape above (`severity` from {critical, major, minor, suggestion}); it is parsed by `safeParseJson` / `readReview`.
64
97
  - Base findings on the real `git diff`, not assumptions. The review artifacts go only to the two absolute paths given — the one other place you may write is the memory directory your system prompt's `## Worca memory` block names (see the section below).
@@ -5,13 +5,13 @@ tools: Read, Write, Edit, Glob, Grep
5
5
  model: inherit
6
6
  ---
7
7
 
8
- You are the **Memory defragment** agent. worca keeps durable rules and preferences as markdown files — one topic per file, YAML frontmatter (`name`, `description`, optional `paths`; worca stamps `source` and `updated`). Your system prompt carries a `## Worca memory` block naming the scope directory you may work in (its absolute path) — a Memory defragment run mounts exactly one; that directory is the only place you read from or write to. Claude Code has already loaded every file of it into your context as rules, but editing needs a fresh Read of the file. The scope directory sits INSIDE your cwd (under `.claude/rules/worca/`); everything else in the project directory is off limits: do not read it, do not edit it, do not create anything there.
8
+ You are the **Memory defragment** agent. worca keeps durable rules and preferences as markdown files — one topic per file, YAML frontmatter (`name`, `description`, optional `paths`; worca stamps `source` and `updated`). Your system prompt carries a `## Worca memory` block naming the scope directory you may work in (its absolute path) — a Memory defragment run mounts exactly one; that directory is the only place you read from or write to. Claude Code has already loaded every file of it into your context as rules, but editing needs a fresh Read of the file. The scope directory sits OUTSIDE the project checkout, in the run's own memory directory (worca has added it to your session's working directories, so Write and Edit work there); the copy Claude Code loaded your rules from, under the cwd's `.claude/rules/worca/`, is read-only — a write there is refused as a sensitive path, so never write there. Everything in the project directory is off limits: do not read it, do not edit it, do not create anything there.
9
9
 
10
10
  ## Ports
11
11
 
12
12
  The engine binds every port to an absolute path in the task prompt — never hardcode filenames.
13
13
 
14
- - **in `task`** (md) — which scope to defragment and why (the user's request).
14
+ - **in `task`** (md) — which scope to defragment and why: the user's request, then a `## Memory health` section worca appends — the reasons the scope is flagged and the budgets a finished defragment must meet, with the current figures.
15
15
  - **out `report`** (md) — `defrag-report.md`: what you merged, split, removed and why. Write it to the exact path the task prompt gives.
16
16
 
17
17
  ## What to do
@@ -24,9 +24,11 @@ The engine binds every port to an absolute path in the task prompt — never har
24
24
  - **Tighten hooks.** Every `description` is ONE line ≤ 160 characters that says WHEN the file is worth reading, not what it contains.
25
25
  - **Keep names** whenever the topic survives (other files and people refer to them). Never rename to a name that differs only by letter case from an existing one.
26
26
  - **Keep the frontmatter** (`name`, `description`, `paths` when present, any extra keys). Do not write `source` or `updated` — worca stamps them.
27
+ - **Clear the health reasons.** The task's `## Memory health` section lists why worca flags this scope; every reason that is about the files (not the write counter) must no longer hold when you finish. Its budgets line overrides the default figures below.
28
+ - **Keep the always-on budget.** A file WITHOUT `paths` is loaded into the context of EVERY agent on every run; a file with `paths` (comma-separated globs) loads only when an agent reads a matching file, so it costs nothing until then. The always-on bytes are the sum of the path-less files (default budget: under 16 KB for the whole scope). When over it, in this order: (a) give `paths` to every file whose rules concern particular files or directories — take the globs from the paths the file's own body names (`ui/public/scripts-view.mjs`, `test/**`), never invent a path you have not seen in the scope; (b) when only PART of a path-less file is file-specific, split that part out into its own file with `paths`; (c) condense what stays always-on — cut narrative, history, worked examples and repetition, keep each rule and its reason in a line or two. Leave path-less only what every agent needs whatever it touches (how the user works, process rules, project-wide invariants).
27
29
  - Stay within the caps: at most 50 files in the scope, each under 32 KB (aim for under 8 KB).
28
30
  - Preserve facts. Defragmenting is restructuring, not rewriting: keep every rule that is still true, in fewer and clearer files.
29
31
  3. Apply the changes with Write / Edit. To REMOVE a file (merged away, stale), make it EMPTY: Edit it, replacing its entire content — frontmatter included — with nothing. worca's sync-back treats an empty file in the mount as a deletion (an absent file too). Never leave a file that only carries frontmatter.
30
- 4. Write `defrag-report.md` to the `report` output path: a heading, then three lists — **Merged** (`b.md → a.md: why`), **Split** (`x.md → x-1.md, x-2.md: why`), **Removed** (`stale.md: why`) — and one closing line with the file count before and after. Keep it under 60 lines.
32
+ 4. Write `defrag-report.md` to the `report` output path: a heading, then three lists — **Merged** (`b.md → a.md: why`), **Split** (`x.md → x-1.md, x-2.md: why`), **Removed** (`stale.md: why`) — and one closing line with the file count before and after, and the always-on bytes before and after. When a health reason still holds, add a **Still flagged** list: the reason and why it could not be cleared without losing a rule that is still true. Keep it under 60 lines.
31
33
 
32
34
  Never write progress notes, run summaries or anything about this run into the memory scope. Never read or write outside the scope directory except the report path.
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "key": "workspaceScanner",
3
3
  "metaVersion": 2,
4
+ "humanEffort": { "factor": 0 },
4
5
  "mockRole": "workspace-scan",
5
6
  "placeable": false,
6
7
  "inputs": [{ "id": "task", "type": "md" }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worca/app",
3
- "version": "1.3.0-rc.2",
3
+ "version": "1.4.0-rc.1",
4
4
  "description": "Worca — deterministic multi-agent pipeline that drives Claude Code (headless) through Plan -> Refine -> Implement -> Review, with a CLI, an installable /worca skill, and a web UI.",
5
5
  "license": "MIT",
6
6
  "author": "Sinisha Djukic",
@@ -36,22 +36,26 @@
36
36
  "ui/public/",
37
37
  "agents/",
38
38
  "skills/",
39
- "scripts/install.mjs",
39
+ "scripts/",
40
+ "tools/install.mjs",
40
41
  "README.md"
41
42
  ],
42
43
  "scripts": {
43
44
  "start": "node --disable-warning=ExperimentalWarning ui/server.mjs",
44
45
  "cli": "node --disable-warning=ExperimentalWarning src/cli/worca-cc.mjs",
45
- "install:agents": "node scripts/install.mjs",
46
+ "install:agents": "node tools/install.mjs",
46
47
  "smoke": "WORCA_MOCK=1 WORCA_HOME=.worca-cc-smoke node --disable-warning=ExperimentalWarning src/cli/worca-cc.mjs --project sandbox --prompt \"demo task\" --mock --yes",
47
48
  "smoke:auto": "WORCA_MOCK=1 WORCA_HOME=.worca-cc-smoke node --disable-warning=ExperimentalWarning src/cli/worca-cc.mjs --project sandbox --prompt \"demo task\" --mock --yes --workflow auto",
48
- "smoke:workspace": "WORCA_MOCK=1 WORCA_HOME=.worca-cc-smoke node --disable-warning=ExperimentalWarning scripts/smoke-workspace.mjs",
49
- "smoke:plugin": "WORCA_MOCK=1 WORCA_HOME=.worca-cc-smoke node --disable-warning=ExperimentalWarning scripts/smoke-plugin.mjs",
50
- "ask:fixtures": "node --disable-warning=ExperimentalWarning scripts/ask-capture-fixtures.mjs",
51
- "verify:composer": "node --disable-warning=ExperimentalWarning scripts/verify-composer-cdp.mjs",
52
- "verify:run-monitor": "node --disable-warning=ExperimentalWarning scripts/verify-run-monitor-cdp.mjs",
53
- "verify:theme": "node --disable-warning=ExperimentalWarning scripts/verify-theme-cdp.mjs",
54
- "verify:memory": "node --disable-warning=ExperimentalWarning scripts/verify-memory-cdp.mjs",
49
+ "smoke:workspace": "WORCA_MOCK=1 WORCA_HOME=.worca-cc-smoke node --disable-warning=ExperimentalWarning tools/smoke-workspace.mjs",
50
+ "smoke:plugin": "WORCA_MOCK=1 WORCA_HOME=.worca-cc-smoke node --disable-warning=ExperimentalWarning tools/smoke-plugin.mjs",
51
+ "docker:build": "node tools/docker-build.mjs",
52
+ "ask:fixtures": "node --disable-warning=ExperimentalWarning tools/ask-capture-fixtures.mjs",
53
+ "verify:composer": "node --disable-warning=ExperimentalWarning tools/verify-composer-cdp.mjs",
54
+ "verify:run-monitor": "node --disable-warning=ExperimentalWarning tools/verify-run-monitor-cdp.mjs",
55
+ "verify:theme": "node --disable-warning=ExperimentalWarning tools/verify-theme-cdp.mjs",
56
+ "verify:memory": "node --disable-warning=ExperimentalWarning tools/verify-memory-cdp.mjs",
57
+ "verify:scripts": "node --disable-warning=ExperimentalWarning tools/verify-scripts-cdp.mjs",
58
+ "verify:ask-forms": "node --disable-warning=ExperimentalWarning tools/verify-ask-forms-cdp.mjs",
55
59
  "test": "rm -rf .worca-cc-test && PATH=\"$PWD/test/helpers/no-real-claude:$PATH\" WORCA_HOME=.worca-cc-test node --disable-warning=ExperimentalWarning --test --test-timeout=300000 test/*.mjs; s=$?; node test/helpers/no-real-claude/assert-none.mjs || s=1; exit $s"
56
60
  },
57
61
  "dependencies": {
@@ -0,0 +1,25 @@
1
+ // scripts/git-diff.mjs — the `gitDiff` card (spec §12.3): `git diff <ref>` in the
2
+ // run's checkout, or per member under ctx.repos on a workspace run (one `## <key>`
3
+ // section each), written as fenced markdown for a downstream reader. No verdict.
4
+ import { spawnSync } from 'node:child_process';
5
+ import { writeFileSync } from 'node:fs';
6
+
7
+ export default async function ({ outputs, params, ctx, log }) {
8
+ const ref = typeof params.ref === 'string' && params.ref.trim() ? params.ref.trim() : (ctx.checkpointRef || '');
9
+ const stat = params.stat === true;
10
+ // A param is argv, not a shell word — but `--output=<path>` is still a git OPTION, and git runs with worca's privileges.
11
+ if (ref.startsWith('-')) throw new Error(`a ref must not start with "-": ${ref}`);
12
+ const args = ['diff', ...(stat ? ['--stat'] : []), ...(ref ? [ref] : [])];
13
+ const section = (dir, label) => {
14
+ const r = spawnSync('git', args, { cwd: dir, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
15
+ if (r.status !== 0) log('warn', `git ${args.join(' ')} in ${dir}: ${(r.stderr || '').trim() || `exit ${r.status}`}`);
16
+ const body = (r.stdout || '').trimEnd();
17
+ return `${label ? `## ${label}\n\n` : ''}\`\`\`${stat ? 'text' : 'diff'}\n${body || '(no changes)'}\n\`\`\`\n`;
18
+ };
19
+ const repos = Array.isArray(ctx.repos) && ctx.repos.length ? ctx.repos : null;
20
+ const md = repos ? repos.map((r) => section(r.dir, r.key)).join('\n') : section(ctx.cwd, '');
21
+ const out = outputs.diff?.path;
22
+ if (!out) throw new Error('the diff output has no path');
23
+ writeFileSync(out, `# Diff against ${ref || 'the working tree'}\n\n${md}`, 'utf8');
24
+ return { summary: `diff written (${md.length} chars${repos ? `, ${repos.length} repos` : ''})` };
25
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "key": "gitDiff",
3
+ "metaVersion": 2,
4
+ "displayName": "Git diff",
5
+ "description": "Writes the diff of the run's checkout against the run checkpoint (or a ref) as fenced markdown, one section per member on a workspace run. Runs git with worca's privileges.",
6
+ "domain": "coding",
7
+ "color": "green",
8
+ "icon": "<circle cx=\"6\" cy=\"6\" r=\"2\"/><circle cx=\"6\" cy=\"18\" r=\"2\"/><circle cx=\"18\" cy=\"12\" r=\"2\"/><path d=\"M6 8v8M8 6h6a4 4 0 0 1 4 4v0\" stroke-linecap=\"round\"/>",
9
+ "order": 30,
10
+ "runtime": "node",
11
+ "file": "git-diff.mjs",
12
+ "inputs": [ { "id": "done", "type": "void", "required": false } ],
13
+ "outputs": [ { "id": "diff", "type": "md", "when": "always", "filename": "diff-cycle{cycle}.md" } ],
14
+ "params": [
15
+ { "id": "ref", "type": "string", "label": "Base ref (blank = run checkpoint)" },
16
+ { "id": "stat", "type": "boolean", "label": "Stat only", "default": false }
17
+ ]
18
+ }
@@ -0,0 +1,11 @@
1
+ // scripts/js-inline.mjs — the `js` card (spec §12.2): runs `params.source` as an
2
+ // ES module through a data: URL and calls its default export with the SAME api
3
+ // the harness gives a file script, so a snippet that works inline works as a
4
+ // file unchanged. Imports nothing from worca (it runs with WORCA_HOME stripped).
5
+ export default async function (api) {
6
+ const source = String(api?.params?.source ?? '');
7
+ if (!source.trim()) throw new Error('the js card has no source');
8
+ const mod = await import(`data:text/javascript;base64,${Buffer.from(source, 'utf8').toString('base64')}`);
9
+ if (typeof mod.default !== 'function') throw new Error('the source must `export default async function (api) { … }`');
10
+ return await mod.default(api);
11
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "key": "js",
3
+ "metaVersion": 2,
4
+ "displayName": "JavaScript",
5
+ "description": "Runs an inline JavaScript function with worca's privileges: `export default async function ({ inputs, outputs, params, ctx, log })`. Works unchanged as a file script.",
6
+ "domain": "general",
7
+ "color": "violet",
8
+ "icon": "<path d=\"M8 4l-4 8 4 8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M16 4l4 8-4 8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
9
+ "order": 20,
10
+ "runtime": "node",
11
+ "file": "js-inline.mjs",
12
+ "ports": "config",
13
+ "defaultPorts": {
14
+ "inputs": [ { "id": "in", "type": "md", "required": false } ],
15
+ "outputs": [ { "id": "out", "type": "md", "when": "always", "filename": "js-cycle{cycle}.md" } ]
16
+ },
17
+ "verdict": { "filename": "js-cycle{cycle}.json" },
18
+ "params": [
19
+ { "id": "source", "type": "code", "language": "js", "label": "Source", "required": true,
20
+ "default": "export default async function ({ inputs, outputs, params, ctx }) {\n const fs = await import('node:fs');\n fs.writeFileSync(outputs.out.path, '# js card\\n');\n return { summary: 'ok' };\n}\n" }
21
+ ]
22
+ }
@@ -0,0 +1,27 @@
1
+ # scripts/py-inline.py — the `py` card (workbench spec §7, W17): runs
2
+ # `params.source` in a FRESH module and calls its `main`, with the SAME api the
3
+ # harness gives a file script, so a snippet that works inline works as a file
4
+ # unchanged. Imports nothing from worca and nothing outside the standard library
5
+ # (it runs with WORCA_HOME stripped), and must parse on python 3.8.
6
+ import sys
7
+ import types
8
+
9
+
10
+ def main(api):
11
+ source = api.params.get('source') or ''
12
+ if not source.strip():
13
+ raise ValueError('the py card has no source')
14
+ # A REAL module, registered under its name — not a bare dict. dataclasses,
15
+ # pickle and typing all look a class's module up in sys.modules; with a dict
16
+ # namespace a `@dataclass` under `from __future__ import annotations` dies with
17
+ # "'NoneType' object has no attribute '__dict__'", and the same snippet saved as
18
+ # a file script works. "Works unchanged as a file script" has to be true.
19
+ module = types.ModuleType('worca_py_card')
20
+ module.__file__ = '<py card>'
21
+ sys.modules[module.__name__] = module
22
+ exec(compile(source, '<py card>', 'exec'), module.__dict__)
23
+ entry = getattr(module, 'main', None)
24
+ if not callable(entry):
25
+ raise TypeError('the source must define `def main(api): …`')
26
+ # A coroutine travels back up: the harness awaits whatever main returns.
27
+ return entry(api)
@@ -0,0 +1,22 @@
1
+ {
2
+ "key": "py",
3
+ "metaVersion": 2,
4
+ "displayName": "Python",
5
+ "description": "Runs an inline Python function with worca's privileges: `def main(api)`. Works unchanged as a file script.",
6
+ "domain": "general",
7
+ "color": "blue",
8
+ "icon": "<path d=\"M12 3h3a2 2 0 0 1 2 2v4H9a2 2 0 0 0-2 2v2H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 21H9a2 2 0 0 1-2-2v-4h8a2 2 0 0 0 2-2v-2h2a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>",
9
+ "order": 25,
10
+ "runtime": "python",
11
+ "file": "py-inline.py",
12
+ "ports": "config",
13
+ "defaultPorts": {
14
+ "inputs": [ { "id": "in", "type": "md", "required": false } ],
15
+ "outputs": [ { "id": "out", "type": "md", "when": "always", "filename": "py-cycle{cycle}.md" } ]
16
+ },
17
+ "verdict": { "filename": "py-cycle{cycle}.json" },
18
+ "params": [
19
+ { "id": "source", "type": "code", "language": "python", "label": "Source", "required": true,
20
+ "default": "def main(api):\n with open(api.outputs.out.path, 'w', encoding='utf-8') as f:\n f.write('# py card\\n')\n return {'summary': 'ok'}\n" }
21
+ ]
22
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "key": "shell",
3
+ "metaVersion": 2,
4
+ "displayName": "Shell",
5
+ "description": "Runs a command in the run's checkout with worca's privileges. Exit 0 fires pass, exit 1 fires fail with the output attached, any other exit pauses the run.",
6
+ "domain": "general",
7
+ "color": "amber",
8
+ "icon": "<path d=\"M4 17l6-5-6-5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12 19h8\" stroke-linecap=\"round\"/>",
9
+ "order": 10,
10
+ "runtime": "shell",
11
+ "ports": "config",
12
+ "defaultPorts": {
13
+ "inputs": [ { "id": "in", "type": "md", "required": false } ],
14
+ "outputs": [
15
+ { "id": "log", "type": "md", "when": "always", "filename": "shell-cycle{cycle}.md" },
16
+ { "id": "fail", "type": "md", "when": "blocking", "filename": "shell-cycle{cycle}.md" },
17
+ { "id": "pass", "type": "void", "when": "clean" }
18
+ ]
19
+ },
20
+ "verdict": { "filename": "shell-cycle{cycle}.json" },
21
+ "params": [
22
+ { "id": "command", "type": "command", "label": "Command", "description": "Runs through /bin/sh -c (cmd.exe /c on Windows) in the run's checkout.", "required": true }
23
+ ]
24
+ }
@@ -7,7 +7,7 @@ description: Run the node-graph multi-agent orchestrator over a software task in
7
7
 
8
8
  Drive the current project through the selected pipeline template (default `wf_default`: Plan → Refine ↺ → Implement → Review ↺ → End). Orchestration is performed by a deterministic Node.js script; this skill just launches it. Artifacts (plans, reviews, pipeline audit logs) are written under `ai-artifacts/` in the project.
9
9
 
10
- The orchestrator repo lives wherever it was installed. `<WORCA_REPO>` below is the absolute path of that repo (the directory containing `src/cli/worca-cc.mjs`). If you installed via `scripts/install.mjs`, the installer rewrites `<WORCA_REPO>` in this file to the real path automatically; otherwise substitute it yourself (or set an `WORCA_REPO` environment variable and use `"$WORCA_REPO"`).
10
+ The orchestrator repo lives wherever it was installed. `<WORCA_REPO>` below is the absolute path of that repo (the directory containing `src/cli/worca-cc.mjs`). If you installed via `tools/install.mjs`, the installer rewrites `<WORCA_REPO>` in this file to the real path automatically; otherwise substitute it yourself (or set an `WORCA_REPO` environment variable and use `"$WORCA_REPO"`).
11
11
 
12
12
  ## /worca <prompt> — run the pipeline (default action)
13
13
 
@@ -29,6 +29,7 @@ Useful flags (pass through when the user asks):
29
29
  - `--model <m>` / `--permission-mode <m>` — Claude model / permission mode (default `acceptEdits`).
30
30
  - `--mock` — run the full pipeline offline with canned agents (no Claude spawn, no tokens); great for a dry run. Equivalent to setting `WORCA_MOCK=1`.
31
31
  - `--yes` / `--non-interactive` — auto-answer (clarify picks the first option; gates choose "continue"). Use for unattended runs.
32
+ - `--at "<when>"` — schedule the run instead of starting it now (`02:00`, `tomorrow 02:00`, `+90m`, `2026-09-19 02:00`). Add `--wait` to hold the terminal and start it there; otherwise the Worca UI server starts it. `--every "weekdays 02:00"` / `--cron "0 2 * * 1-5"` repeat it. Manage with `worca schedule list | cancel <id>`. `--after <id>` starts it when that run ends (`--after-any` also on failure, `--source-from-previous` on its branch).
32
33
 
33
34
  Example:
34
35
 
@@ -52,7 +53,7 @@ This starts `ui/server.mjs` (Express + WebSocket, default port `4317`; set `PORT
52
53
  So a teammate can open Claude Code in their own repo and type `/worca <prompt>`, copy the agents and this skill into that project's `.claude/`:
53
54
 
54
55
  ```bash
55
- node <WORCA_REPO>/scripts/install.mjs "<targetDir>"
56
+ node <WORCA_REPO>/tools/install.mjs "<targetDir>"
56
57
  ```
57
58
 
58
59
  - Copies `agents/*.md` into `<targetDir>/.claude/agents/` and `skills/worca/` into `<targetDir>/.claude/skills/worca/`.