@harness-lab/cli 0.2.8 → 0.2.9
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 +29 -3
- package/assets/workshop-bundle/SKILL.md +20 -0
- package/assets/workshop-bundle/bundle-manifest.json +7 -7
- package/assets/workshop-bundle/content/facilitation/master-guide.md +8 -5
- package/assets/workshop-bundle/content/talks/context-is-king.md +4 -1
- package/assets/workshop-bundle/docs/harness-cli-foundation.md +21 -11
- package/assets/workshop-bundle/workshop-skill/facilitator.md +62 -0
- package/package.json +1 -1
- package/src/client.js +9 -0
- package/src/io.js +10 -2
- package/src/run-cli.js +171 -8
- package/src/session-store.js +1 -0
- package/src/workshop-bundle.js +18 -1
package/README.md
CHANGED
|
@@ -9,9 +9,14 @@ Current shipped scope:
|
|
|
9
9
|
- `harness auth login`
|
|
10
10
|
- `harness auth logout`
|
|
11
11
|
- `harness auth status`
|
|
12
|
+
- `harness workshop current-instance`
|
|
13
|
+
- `harness workshop select-instance`
|
|
12
14
|
- `harness workshop status`
|
|
15
|
+
- `harness workshop list-instances`
|
|
16
|
+
- `harness workshop show-instance`
|
|
13
17
|
- `harness workshop create-instance`
|
|
14
18
|
- `harness workshop update-instance`
|
|
19
|
+
- `harness workshop reset-instance`
|
|
15
20
|
- `harness workshop prepare`
|
|
16
21
|
- `harness workshop remove-instance`
|
|
17
22
|
- `harness workshop archive`
|
|
@@ -120,16 +125,37 @@ Workshop commands:
|
|
|
120
125
|
```bash
|
|
121
126
|
harness auth status
|
|
122
127
|
harness skill install
|
|
128
|
+
harness workshop list-instances
|
|
129
|
+
harness workshop select-instance sample-workshop-demo-orbit
|
|
130
|
+
harness workshop current-instance
|
|
123
131
|
harness workshop status
|
|
132
|
+
harness workshop show-instance sample-workshop-demo-orbit
|
|
124
133
|
harness workshop create-instance sample-workshop-demo-orbit --event-title "Sample Workshop Demo"
|
|
125
|
-
harness workshop update-instance
|
|
126
|
-
harness workshop
|
|
127
|
-
harness workshop
|
|
134
|
+
harness workshop update-instance --room-name Orbit
|
|
135
|
+
harness workshop reset-instance --template-id blueprint-default
|
|
136
|
+
harness workshop prepare
|
|
137
|
+
harness workshop remove-instance
|
|
128
138
|
harness workshop phase set rotation
|
|
129
139
|
harness workshop archive --notes "Manual archive"
|
|
140
|
+
harness workshop select-instance --clear
|
|
130
141
|
harness auth logout
|
|
131
142
|
```
|
|
132
143
|
|
|
144
|
+
Targeting model:
|
|
145
|
+
|
|
146
|
+
- `harness workshop list-instances` is the discovery entrypoint for facilitator-visible workshops
|
|
147
|
+
- `harness workshop select-instance <instance-id>` stores a local current target for later workshop commands
|
|
148
|
+
- `harness workshop current-instance` reports the stored target and resolves its current server state
|
|
149
|
+
- `harness workshop status` and `harness workshop phase set <phase-id>` use the selected instance when present, otherwise they fall back to deployment default behavior
|
|
150
|
+
- `harness workshop show-instance`, `update-instance`, `reset-instance`, `prepare`, and `remove-instance` accept an explicit `<instance-id>` but may also use the stored selection as a fallback
|
|
151
|
+
- `harness workshop select-instance --clear` removes the stored selection
|
|
152
|
+
- `HARNESS_WORKSHOP_INSTANCE_ID` remains an environment fallback when no local selection is stored
|
|
153
|
+
|
|
154
|
+
Machine-readable output:
|
|
155
|
+
|
|
156
|
+
- `harness --json ...` prints strict JSON output without headings
|
|
157
|
+
- prefer this for agent or script consumption instead of parsing human-oriented terminal copy
|
|
158
|
+
|
|
133
159
|
Facilitator lifecycle commands are intentionally CLI-first:
|
|
134
160
|
|
|
135
161
|
- skill invokes `harness`
|
|
@@ -214,18 +214,34 @@ This is a facilitator-only command — do not surface to participants.
|
|
|
214
214
|
|
|
215
215
|
Show the current instance state, agenda phase, facilitator list, and team count.
|
|
216
216
|
Requires active facilitator session.
|
|
217
|
+
If a local current instance is selected, prefer that target over deployment-default status.
|
|
218
|
+
When an agent needs machine-readable output, prefer `harness --json workshop status`.
|
|
219
|
+
|
|
220
|
+
### `workshop facilitator current-instance`
|
|
221
|
+
|
|
222
|
+
Show the locally selected facilitator target, where it came from, and the resolved instance record.
|
|
223
|
+
Prefer invoking `harness workshop current-instance`.
|
|
224
|
+
Use this to confirm the CLI target before update, reset, prepare, remove, or phase operations.
|
|
225
|
+
|
|
226
|
+
### `workshop facilitator select-instance <instance-id>`
|
|
227
|
+
|
|
228
|
+
Persist a facilitator-local current target for later workshop commands.
|
|
229
|
+
Prefer invoking `harness workshop select-instance <instance-id>`.
|
|
230
|
+
Use `harness workshop select-instance --clear` to remove the stored selection.
|
|
217
231
|
|
|
218
232
|
### `workshop facilitator list-instances`
|
|
219
233
|
|
|
220
234
|
List the facilitator-visible workshop instance registry.
|
|
221
235
|
Prefer invoking `harness workshop list-instances` over raw API scripts or local session-file inspection.
|
|
222
236
|
Use this when the facilitator needs to discover what currently exists on a shared dashboard before choosing an explicit instance for reset, update, or agenda work.
|
|
237
|
+
When an agent needs strict parsing, prefer `harness --json workshop list-instances`.
|
|
223
238
|
|
|
224
239
|
### `workshop facilitator show-instance <instance-id>`
|
|
225
240
|
|
|
226
241
|
Inspect one explicit workshop instance.
|
|
227
242
|
Prefer invoking `harness workshop show-instance <instance-id>` over raw API scripts.
|
|
228
243
|
Use this when the facilitator needs the full record for one instance rather than the deployment-default runtime status returned by `workshop facilitator status`.
|
|
244
|
+
If a current instance is already selected, the CLI may omit `<instance-id>` and use the stored target.
|
|
229
245
|
|
|
230
246
|
### `workshop facilitator grant <email> <role>`
|
|
231
247
|
|
|
@@ -263,6 +279,7 @@ Support `contentLang` changes explicitly so facilitators can choose workshop del
|
|
|
263
279
|
|
|
264
280
|
Facilitator discovery rule:
|
|
265
281
|
- for routine discovery, use `harness workshop list-instances` and `harness workshop show-instance`
|
|
282
|
+
- for repeated work on one live workshop, use `harness workshop select-instance <instance-id>` and `harness workshop current-instance`
|
|
266
283
|
- do not read local CLI session files or improvise authenticated `node -e` fetch scripts unless you are diagnosing the CLI itself
|
|
267
284
|
|
|
268
285
|
### `workshop facilitator reset-instance <instance-id>`
|
|
@@ -270,16 +287,19 @@ Facilitator discovery rule:
|
|
|
270
287
|
Reset one existing workshop instance from the selected blueprint template. Requires facilitator session.
|
|
271
288
|
Prefer invoking `harness workshop reset-instance` over raw API scripts.
|
|
272
289
|
Use this when the facilitator wants fresh canonical agenda, runner, and presenter content for a live instance and accepts that local runtime state will be reinitialized.
|
|
290
|
+
If a current instance is already selected, the CLI may omit `<instance-id>` and use the stored target.
|
|
273
291
|
|
|
274
292
|
### `workshop facilitator remove-instance`
|
|
275
293
|
|
|
276
294
|
Remove a workshop instance from the active list without deleting its archive history. Requires facilitator session.
|
|
277
295
|
Prefer invoking `harness workshop remove-instance`.
|
|
296
|
+
If a current instance is already selected, the CLI may omit `<instance-id>` and use the stored target.
|
|
278
297
|
|
|
279
298
|
### `workshop facilitator prepare`
|
|
280
299
|
|
|
281
300
|
Set the current instance to `prepared` state. Verify event code is ready.
|
|
282
301
|
Prefer invoking `harness workshop prepare`.
|
|
302
|
+
If a current instance is already selected, the CLI may omit `<instance-id>` and use the stored target.
|
|
283
303
|
|
|
284
304
|
### `workshop facilitator agenda`
|
|
285
305
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifestVersion": 1,
|
|
3
3
|
"bundleName": "harness-lab-workshop",
|
|
4
|
-
"bundleVersion": "0.2.
|
|
5
|
-
"contentHash": "
|
|
4
|
+
"bundleVersion": "0.2.9",
|
|
5
|
+
"contentHash": "671837951cf6679bea1d517c900927aab5d457806695e1a6da25574b8573f325",
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"path": "content/challenge-cards/.gitkeep",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"path": "content/facilitation/master-guide.md",
|
|
37
|
-
"sha256": "
|
|
37
|
+
"sha256": "845adbcf9284cedd589d461b40ae1cd336d816b92bcc239df4574148a57b263a"
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"path": "content/project-briefs/.gitkeep",
|
|
@@ -98,11 +98,11 @@
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"path": "content/talks/context-is-king.md",
|
|
101
|
-
"sha256": "
|
|
101
|
+
"sha256": "0bb48497b458474a546c351118ad455c00ad997c9efc0e227b388f81dd0b55e3"
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
"path": "docs/harness-cli-foundation.md",
|
|
105
|
-
"sha256": "
|
|
105
|
+
"sha256": "cff448e5c1ee4e7129724e4f8294add35cd1efb621c83182b341a1b7e5a16b86"
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
"path": "docs/learner-reference-gallery.md",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
},
|
|
135
135
|
{
|
|
136
136
|
"path": "SKILL.md",
|
|
137
|
-
"sha256": "
|
|
137
|
+
"sha256": "d1e242a857f61bc2fae29c74a9e0efbd1ba0ed5beb25087dbaeffabc5f53b4a5"
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"path": "workshop-blueprint/agenda.json",
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
},
|
|
183
183
|
{
|
|
184
184
|
"path": "workshop-skill/facilitator.md",
|
|
185
|
-
"sha256": "
|
|
185
|
+
"sha256": "525fc9fdad22cf42b47854ff9ad90579d728daf2c4ac484aba13f93193eb56d3"
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
188
|
"path": "workshop-skill/follow-up-package.md",
|
|
@@ -64,14 +64,14 @@ Pravidla:
|
|
|
64
64
|
|
|
65
65
|
Po launchi potřebuje místnost ještě jednu konkrétní věc:
|
|
66
66
|
|
|
67
|
-
- co má být po prvním build bloku opravdu vidět
|
|
68
|
-
- co nestačí jen slíbit
|
|
67
|
+
- co má být po prvním build bloku opravdu vidět v repu
|
|
68
|
+
- co nestačí jen slíbit nebo dovysvětlit u stolu
|
|
69
69
|
|
|
70
70
|
Do oběda má být vidět:
|
|
71
71
|
|
|
72
|
-
-
|
|
73
|
-
- `AGENTS.md` jako krátká mapa
|
|
74
|
-
- plan nebo jasně vedená implementační stopa
|
|
72
|
+
- `README`, které dává smysl cizímu člověku
|
|
73
|
+
- `AGENTS.md` jako krátká mapa, ne sklad všeho
|
|
74
|
+
- plan nebo jasně vedená implementační stopa, ze které je poznat další safe move
|
|
75
75
|
- první explicitní check před dalším generováním
|
|
76
76
|
|
|
77
77
|
## Context is King talk
|
|
@@ -93,6 +93,8 @@ Proměnit energii z openingu v přesnou tezi a čistý most do Build fáze 1.
|
|
|
93
93
|
|
|
94
94
|
### Mikro-cvičení
|
|
95
95
|
|
|
96
|
+
Tohle je krátká facilitátorova ukázka, ne zadání pro celý room.
|
|
97
|
+
|
|
96
98
|
Použijte stejný malý task ve dvou podmínkách:
|
|
97
99
|
|
|
98
100
|
1. prompt blob
|
|
@@ -112,6 +114,7 @@ Na konci talku má být jasné:
|
|
|
112
114
|
|
|
113
115
|
- teorie tím končí
|
|
114
116
|
- tým se vrací k repu
|
|
117
|
+
- pokud tým ještě nemá workshop skill, teď je chvíle na `harness skill install`, pak `Codex: $workshop setup` nebo `pi: /skill:workshop`
|
|
115
118
|
- nejdřív vzniká mapa a první explicitní check
|
|
116
119
|
- teprve potom dává smysl další feature motion
|
|
117
120
|
|
|
@@ -30,7 +30,9 @@ Pointa analogie:
|
|
|
30
30
|
|
|
31
31
|
## Mikro-cvičení
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Tohle je krátká facilitátorova ukázka, ne práce pro celý room.
|
|
34
|
+
|
|
35
|
+
Vezmeme stejný malý task ve dvou podmínkách. Jedna varianta bude prompt blob. Druhá varianta bude krátké zadání se 4 prvky a s odkazem na kontext zapsaný v repu. Pak porovnáme výsledky. Nehledáme „nejhezčí prompt“. Hledáme způsob práce, který přenese záměr, omezení a done criteria i do dalšího kroku.
|
|
34
36
|
|
|
35
37
|
4 prvky pro druhou variantu:
|
|
36
38
|
|
|
@@ -64,6 +66,7 @@ Všichni dostanou stejný malý task. Jedna varianta bude prompt blob. Druhá va
|
|
|
64
66
|
|
|
65
67
|
Po tomhle talku se tým nemá vracet k repu s pocitem, že potřebuje jen chytřejší prompt. Má se vracet s jedním jasným očekáváním:
|
|
66
68
|
|
|
69
|
+
- pokud ještě nemá workshop skill, teď je chvíle na `harness skill install`, pak `Codex: $workshop setup` nebo `pi: /skill:workshop`
|
|
67
70
|
- nejdřív krátká mapa v repu
|
|
68
71
|
- potom plan
|
|
69
72
|
- potom první explicitní check
|
|
@@ -8,7 +8,7 @@ Current implementation in this repo:
|
|
|
8
8
|
|
|
9
9
|
- lives in the repository `harness-cli/` package and ships publicly as `@harness-lab/cli`
|
|
10
10
|
- distributes a portable participant workshop skill bundle through `harness skill install`
|
|
11
|
-
- covers `auth login/logout/status` plus `workshop status/list-instances/show-instance/create-instance/update-instance/reset-instance/prepare/remove-instance/archive/phase set`
|
|
11
|
+
- covers `auth login/logout/status` plus `workshop current-instance/select-instance/status/list-instances/show-instance/create-instance/update-instance/reset-instance/prepare/remove-instance/archive/phase set`
|
|
12
12
|
- targets the existing shared dashboard facilitator APIs
|
|
13
13
|
- is tested for browser/device auth, local-dev Basic Auth fallback, and cookie-backed Neon bootstrap fallback
|
|
14
14
|
- stores sessions in a local file under `HARNESS_CLI_HOME` or `~/.harness` by default
|
|
@@ -38,6 +38,8 @@ Required commands:
|
|
|
38
38
|
- `harness auth login`
|
|
39
39
|
- `harness auth logout`
|
|
40
40
|
- `harness auth status`
|
|
41
|
+
- `harness workshop current-instance`
|
|
42
|
+
- `harness workshop select-instance <instance-id>`
|
|
41
43
|
- `harness workshop status`
|
|
42
44
|
- `harness workshop list-instances`
|
|
43
45
|
- `harness workshop show-instance <instance-id>`
|
|
@@ -85,33 +87,41 @@ Current auth layering:
|
|
|
85
87
|
Current target-selection order:
|
|
86
88
|
|
|
87
89
|
1. an explicit command or route instance id
|
|
88
|
-
2. the
|
|
90
|
+
2. the CLI-local persisted selection set by `harness workshop select-instance`
|
|
89
91
|
3. the deployment default `HARNESS_WORKSHOP_INSTANCE_ID`
|
|
90
92
|
4. a repository fallback only on surfaces that intentionally present a workspace-level default
|
|
91
93
|
|
|
92
94
|
Current command posture:
|
|
93
95
|
|
|
94
96
|
- explicit workspace-discovery commands:
|
|
97
|
+
- `harness workshop current-instance`
|
|
98
|
+
- `harness workshop select-instance <instance-id>`
|
|
95
99
|
- `harness workshop list-instances`
|
|
96
|
-
- explicit target
|
|
97
|
-
- `harness workshop show-instance <instance-id
|
|
98
|
-
-
|
|
99
|
-
- `harness workshop
|
|
100
|
-
- `harness workshop
|
|
101
|
-
- `harness workshop
|
|
102
|
-
- `harness workshop remove-instance <instance-id>`
|
|
100
|
+
- explicit target preferred but selected-instance fallback allowed:
|
|
101
|
+
- `harness workshop show-instance [<instance-id>]`
|
|
102
|
+
- `harness workshop update-instance [<instance-id>]`
|
|
103
|
+
- `harness workshop reset-instance [<instance-id>]`
|
|
104
|
+
- `harness workshop prepare [<instance-id>]`
|
|
105
|
+
- `harness workshop remove-instance [<instance-id>]`
|
|
103
106
|
- explicit target is the created resource:
|
|
104
107
|
- `harness workshop create-instance [<instance-id>]`
|
|
105
|
-
- deployment-default target:
|
|
108
|
+
- selected-instance target first, otherwise deployment-default target:
|
|
106
109
|
- `harness workshop status`
|
|
107
|
-
- `harness workshop archive`
|
|
108
110
|
- `harness workshop phase set <phase-id>`
|
|
111
|
+
- deployment-default target:
|
|
112
|
+
- `harness workshop archive`
|
|
109
113
|
|
|
110
114
|
Current discoverability path:
|
|
111
115
|
|
|
112
116
|
- facilitators can inspect available workshop instances through the dashboard workspace view
|
|
113
117
|
- the same platform-scoped list lives behind the authenticated instances API surface at `/api/workshop/instances`
|
|
114
118
|
- the CLI should expose that list directly so facilitator skills do not need session-file inspection or raw authenticated scripts for routine discovery
|
|
119
|
+
- the CLI should also expose a local current-target selector so repeated facilitator work does not depend on ambient dashboard selection or deployment-default routing
|
|
120
|
+
|
|
121
|
+
Machine-readable posture:
|
|
122
|
+
|
|
123
|
+
- facilitator commands should support `--json` for strict machine parsing without headings or prose wrappers
|
|
124
|
+
- skills and agents should prefer `harness --json ...` over scraping human-oriented terminal formatting
|
|
115
125
|
|
|
116
126
|
For the current facilitator lifecycle slice:
|
|
117
127
|
|
|
@@ -41,6 +41,20 @@ Note:
|
|
|
41
41
|
- if the facilitator wants OS-native storage, they can use `HARNESS_SESSION_STORAGE=keychain`, `credential-manager`, or `secret-service`
|
|
42
42
|
- `--auth basic` and `--auth neon` remain explicit fallbacks for local dev/bootstrap
|
|
43
43
|
|
|
44
|
+
Preferred operator flow after login:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
harness workshop list-instances
|
|
48
|
+
harness workshop select-instance sample-workshop-demo-orbit
|
|
49
|
+
harness workshop current-instance
|
|
50
|
+
harness workshop status
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Rules:
|
|
54
|
+
- prefer this flow over reading local CLI session files or composing ad hoc authenticated `node -e` scripts
|
|
55
|
+
- once a local selection exists, the CLI may use it as the default target for subsequent facilitator operations
|
|
56
|
+
- when an agent needs machine-readable output, prefer `harness --json ...`
|
|
57
|
+
|
|
44
58
|
### `/workshop facilitator logout`
|
|
45
59
|
|
|
46
60
|
Ask the facilitator to run:
|
|
@@ -68,6 +82,48 @@ Show:
|
|
|
68
82
|
Use this for the current default or selected workshop context.
|
|
69
83
|
If the facilitator needs the full workspace registry first, use `list-instances` instead of probing local session files or writing raw authenticated fetch scripts.
|
|
70
84
|
|
|
85
|
+
Targeting behavior:
|
|
86
|
+
- if the facilitator previously ran `harness workshop select-instance <instance-id>`, `status` reports that selected instance
|
|
87
|
+
- if no local selection exists, `status` falls back to the deployment-default workshop context
|
|
88
|
+
- for exact machine parsing, prefer `harness --json workshop status`
|
|
89
|
+
|
|
90
|
+
### `/workshop facilitator current-instance`
|
|
91
|
+
|
|
92
|
+
Preferred path:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
harness workshop current-instance
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Show:
|
|
99
|
+
- the locally selected instance id when one exists
|
|
100
|
+
- whether the current target came from persisted selection or `HARNESS_WORKSHOP_INSTANCE_ID`
|
|
101
|
+
- the resolved instance summary and full record for operator verification
|
|
102
|
+
|
|
103
|
+
Rules:
|
|
104
|
+
- use this after `select-instance` when the facilitator wants to confirm the CLI target before update, reset, or remove
|
|
105
|
+
- if nothing is selected, the command should say so clearly instead of forcing the facilitator into session-file inspection
|
|
106
|
+
|
|
107
|
+
### `/workshop facilitator select-instance <instance-id>`
|
|
108
|
+
|
|
109
|
+
Preferred path:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
harness workshop select-instance sample-workshop-demo-orbit
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Clear the stored selection:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
harness workshop select-instance --clear
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Rules:
|
|
122
|
+
- use this when a facilitator will perform several operations against the same live workshop instance
|
|
123
|
+
- the CLI should validate the instance through the server before persisting the selection
|
|
124
|
+
- after selection, `status` and `phase set` should target that instance instead of the deployment default
|
|
125
|
+
- `show-instance`, `update-instance`, `reset-instance`, `prepare`, and `remove-instance` may omit `<instance-id>` when a valid selection already exists
|
|
126
|
+
|
|
71
127
|
### `/workshop facilitator list-instances`
|
|
72
128
|
|
|
73
129
|
Preferred path:
|
|
@@ -93,6 +149,7 @@ Rules:
|
|
|
93
149
|
- prefer this over inspecting local session files or composing one-off authenticated scripts
|
|
94
150
|
- use it when the facilitator needs to discover which live instances exist before reset, update, or scene work
|
|
95
151
|
- keep raw API usage as a diagnostic fallback, not the default operator workflow
|
|
152
|
+
- when an agent needs to parse the output, prefer `harness --json workshop list-instances`
|
|
96
153
|
|
|
97
154
|
### `/workshop facilitator show-instance <instance-id>`
|
|
98
155
|
|
|
@@ -117,6 +174,7 @@ Rules:
|
|
|
117
174
|
- use this when the facilitator needs one specific instance, not the deployment-default `workshop status`
|
|
118
175
|
- if the route returns `404`, the instance does not exist or is not visible to the facilitator
|
|
119
176
|
- prefer this over ad hoc authenticated scripts for routine discovery
|
|
177
|
+
- if a local selection already exists, the facilitator may omit `<instance-id>` and let the CLI use the stored target
|
|
120
178
|
|
|
121
179
|
### `/workshop facilitator grant <email> <role>`
|
|
122
180
|
|
|
@@ -230,6 +288,7 @@ Rules:
|
|
|
230
288
|
- do not use reset for an ordinary title, venue, or room correction
|
|
231
289
|
- if the route returns `400`, the payload is wrong; if it returns `404`, the instance does not exist
|
|
232
290
|
- use `--content-lang cs|en` when the facilitator intends to change the workshop delivery language for that instance
|
|
291
|
+
- if the facilitator already selected a local current instance, the CLI may omit `<instance-id>` and use the stored target
|
|
233
292
|
|
|
234
293
|
### `/workshop facilitator reset-instance <instance-id>`
|
|
235
294
|
|
|
@@ -256,6 +315,7 @@ Rules:
|
|
|
256
315
|
- warn that reset archives current runtime state first and then clears live runtime state for the instance
|
|
257
316
|
- prefer `update-instance` for ordinary metadata corrections; reset is the high-impact operation
|
|
258
317
|
- if the facilitator does not specify a template, keep the current template unless there is a clear reason to switch
|
|
318
|
+
- if the facilitator already selected a local current instance, the CLI may omit `<instance-id>` and use the stored target
|
|
259
319
|
|
|
260
320
|
### `/workshop facilitator prepare`
|
|
261
321
|
|
|
@@ -275,6 +335,7 @@ Content-Type: application/json
|
|
|
275
335
|
```
|
|
276
336
|
|
|
277
337
|
This sets the instance to `prepared` state and verifies the event code.
|
|
338
|
+
If a local current instance is already selected, the CLI may omit `<instance-id>` and use the stored target.
|
|
278
339
|
|
|
279
340
|
### `/workshop facilitator remove-instance <instance-id>`
|
|
280
341
|
|
|
@@ -296,6 +357,7 @@ Content-Type: application/json
|
|
|
296
357
|
Rules:
|
|
297
358
|
- remove remains an owner-only operation
|
|
298
359
|
- the skill should warn the facilitator that this is destructive removal from the active list, not routine metadata editing
|
|
360
|
+
- if the facilitator already selected a local current instance, the CLI may omit `<instance-id>` and use the stored target
|
|
299
361
|
|
|
300
362
|
### `/workshop facilitator agenda`
|
|
301
363
|
|
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -99,9 +99,18 @@ export function createHarnessClient({ fetchFn, session }) {
|
|
|
99
99
|
getAgenda() {
|
|
100
100
|
return request("/api/agenda");
|
|
101
101
|
},
|
|
102
|
+
getWorkshopAgenda(instanceId) {
|
|
103
|
+
return request(`/api/workshop/instances/${encodeURIComponent(instanceId)}/agenda`);
|
|
104
|
+
},
|
|
102
105
|
setCurrentPhase(currentId) {
|
|
103
106
|
return request("/api/agenda", { method: "PATCH", body: { currentId } });
|
|
104
107
|
},
|
|
108
|
+
setCurrentPhaseForInstance(instanceId, currentId) {
|
|
109
|
+
return request(`/api/workshop/instances/${encodeURIComponent(instanceId)}/agenda`, {
|
|
110
|
+
method: "PATCH",
|
|
111
|
+
body: { itemId: currentId },
|
|
112
|
+
});
|
|
113
|
+
},
|
|
105
114
|
archiveWorkshop(notes) {
|
|
106
115
|
return request("/api/workshop/archive", { method: "POST", body: notes ? { notes } : {} });
|
|
107
116
|
},
|
package/src/io.js
CHANGED
|
@@ -84,7 +84,9 @@ function writeWrapped(stream, text, options = {}) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
export function createCliUi(io) {
|
|
87
|
+
export function createCliUi(io, options = {}) {
|
|
88
|
+
const jsonMode = options.jsonMode === true;
|
|
89
|
+
|
|
88
90
|
function streamFor(target) {
|
|
89
91
|
return target === "stderr" ? io.stderr : io.stdout;
|
|
90
92
|
}
|
|
@@ -115,6 +117,10 @@ export function createCliUi(io) {
|
|
|
115
117
|
function status(kind, text, options = {}) {
|
|
116
118
|
const target = options.stream ?? (kind === "error" ? "stderr" : "stdout");
|
|
117
119
|
const stream = streamFor(target);
|
|
120
|
+
if (jsonMode) {
|
|
121
|
+
writeLine(stream, JSON.stringify({ ok: kind !== "error", level: kind, message: text }));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
118
124
|
const chalk = createStyler(stream, io.env);
|
|
119
125
|
const prefixMap = {
|
|
120
126
|
ok: chalk.green.bold("[ok]"),
|
|
@@ -178,7 +184,9 @@ export function createCliUi(io) {
|
|
|
178
184
|
|
|
179
185
|
function json(title, value, options = {}) {
|
|
180
186
|
const target = options.stream ?? "stdout";
|
|
181
|
-
|
|
187
|
+
if (!jsonMode) {
|
|
188
|
+
heading(title, { stream: target });
|
|
189
|
+
}
|
|
182
190
|
writeLine(streamFor(target), JSON.stringify(value, null, 2));
|
|
183
191
|
}
|
|
184
192
|
|
package/src/run-cli.js
CHANGED
|
@@ -16,6 +16,7 @@ function sleep(ms) {
|
|
|
16
16
|
function parseArgs(argv) {
|
|
17
17
|
const positionals = [];
|
|
18
18
|
const flags = {};
|
|
19
|
+
const booleanFlags = new Set(["json", "help", "version", "force", "no-open", "clear"]);
|
|
19
20
|
|
|
20
21
|
for (let index = 0; index < argv.length; index += 1) {
|
|
21
22
|
const value = argv[index];
|
|
@@ -29,6 +30,10 @@ function parseArgs(argv) {
|
|
|
29
30
|
}
|
|
30
31
|
if (value.startsWith("--")) {
|
|
31
32
|
const key = value.slice(2);
|
|
33
|
+
if (booleanFlags.has(key)) {
|
|
34
|
+
flags[key] = true;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
32
37
|
const next = argv[index + 1];
|
|
33
38
|
if (!next || next.startsWith("--")) {
|
|
34
39
|
flags[key] = true;
|
|
@@ -161,12 +166,34 @@ function summarizeWorkshopInstance(instance) {
|
|
|
161
166
|
};
|
|
162
167
|
}
|
|
163
168
|
|
|
169
|
+
function resolveCurrentInstanceTarget(session, env) {
|
|
170
|
+
if (typeof session?.selectedInstanceId === "string" && session.selectedInstanceId.trim().length > 0) {
|
|
171
|
+
return {
|
|
172
|
+
instanceId: session.selectedInstanceId.trim(),
|
|
173
|
+
source: "session",
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (typeof env?.HARNESS_WORKSHOP_INSTANCE_ID === "string" && env.HARNESS_WORKSHOP_INSTANCE_ID.trim().length > 0) {
|
|
178
|
+
return {
|
|
179
|
+
instanceId: env.HARNESS_WORKSHOP_INSTANCE_ID.trim(),
|
|
180
|
+
source: "env",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
instanceId: null,
|
|
186
|
+
source: "none",
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
164
190
|
function printUsage(io, ui) {
|
|
165
191
|
ui.heading("Harness CLI");
|
|
166
192
|
ui.paragraph(`Version ${version}`);
|
|
167
193
|
ui.blank();
|
|
168
194
|
ui.section("Usage");
|
|
169
195
|
ui.commandList([
|
|
196
|
+
"harness [--json] <command>",
|
|
170
197
|
"harness --help",
|
|
171
198
|
"harness --version",
|
|
172
199
|
"harness version",
|
|
@@ -178,6 +205,8 @@ function printUsage(io, ui) {
|
|
|
178
205
|
"harness auth logout",
|
|
179
206
|
"harness auth status",
|
|
180
207
|
"harness skill install [--target PATH] [--force]",
|
|
208
|
+
"harness workshop current-instance",
|
|
209
|
+
"harness workshop select-instance <instance-id> [--clear]",
|
|
181
210
|
"harness workshop status",
|
|
182
211
|
"harness workshop list-instances",
|
|
183
212
|
"harness workshop show-instance <instance-id>",
|
|
@@ -571,9 +600,30 @@ async function handleWorkshopStatus(io, ui, env, deps) {
|
|
|
571
600
|
|
|
572
601
|
try {
|
|
573
602
|
const client = createHarnessClient({ fetchFn: deps.fetchFn, session });
|
|
603
|
+
const target = resolveCurrentInstanceTarget(session, env);
|
|
604
|
+
|
|
605
|
+
if (target.source === "session" && target.instanceId) {
|
|
606
|
+
const [instanceResult, agenda] = await Promise.all([
|
|
607
|
+
client.getWorkshopInstance(target.instanceId),
|
|
608
|
+
client.getWorkshopAgenda(target.instanceId),
|
|
609
|
+
]);
|
|
610
|
+
ui.json("Workshop Status", {
|
|
611
|
+
ok: true,
|
|
612
|
+
targetInstanceId: target.instanceId,
|
|
613
|
+
targetSource: target.source,
|
|
614
|
+
...summarizeWorkshopInstance(instanceResult.instance),
|
|
615
|
+
workshopMeta: instanceResult.instance?.workshopMeta ?? null,
|
|
616
|
+
currentPhase: agenda.phase,
|
|
617
|
+
agendaItems: Array.isArray(agenda.items) ? agenda.items.length : null,
|
|
618
|
+
});
|
|
619
|
+
return 0;
|
|
620
|
+
}
|
|
621
|
+
|
|
574
622
|
const [workshop, agenda] = await Promise.all([client.getWorkshopStatus(), client.getAgenda()]);
|
|
575
623
|
ui.json("Workshop Status", {
|
|
576
624
|
ok: true,
|
|
625
|
+
targetInstanceId: target.instanceId,
|
|
626
|
+
targetSource: target.source,
|
|
577
627
|
workshopId: workshop.workshopId,
|
|
578
628
|
workshopMeta: workshop.workshopMeta,
|
|
579
629
|
currentPhase: agenda.phase,
|
|
@@ -589,6 +639,107 @@ async function handleWorkshopStatus(io, ui, env, deps) {
|
|
|
589
639
|
}
|
|
590
640
|
}
|
|
591
641
|
|
|
642
|
+
async function handleWorkshopCurrentInstance(io, ui, env, deps) {
|
|
643
|
+
const session = await requireSession(io, ui, env);
|
|
644
|
+
if (!session) {
|
|
645
|
+
return 1;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const target = resolveCurrentInstanceTarget(session, env);
|
|
649
|
+
if (!target.instanceId) {
|
|
650
|
+
ui.json("Workshop Current Instance", {
|
|
651
|
+
ok: true,
|
|
652
|
+
instanceId: null,
|
|
653
|
+
source: target.source,
|
|
654
|
+
selectedInstanceId: session.selectedInstanceId ?? null,
|
|
655
|
+
});
|
|
656
|
+
return 0;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
try {
|
|
660
|
+
const client = createHarnessClient({ fetchFn: deps.fetchFn, session });
|
|
661
|
+
const result = await client.getWorkshopInstance(target.instanceId);
|
|
662
|
+
ui.json("Workshop Current Instance", {
|
|
663
|
+
ok: true,
|
|
664
|
+
source: target.source,
|
|
665
|
+
selectedInstanceId: session.selectedInstanceId ?? null,
|
|
666
|
+
...summarizeWorkshopInstance(result.instance),
|
|
667
|
+
instance: result.instance,
|
|
668
|
+
});
|
|
669
|
+
return 0;
|
|
670
|
+
} catch (error) {
|
|
671
|
+
if (error instanceof HarnessApiError) {
|
|
672
|
+
ui.status("error", `Current instance lookup failed: ${error.message}`, { stream: "stderr" });
|
|
673
|
+
return 1;
|
|
674
|
+
}
|
|
675
|
+
throw error;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
async function handleWorkshopSelectInstance(io, ui, env, positionals, flags, deps) {
|
|
680
|
+
const session = await requireSession(io, ui, env);
|
|
681
|
+
if (!session) {
|
|
682
|
+
return 1;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
if (flags.clear === true) {
|
|
686
|
+
const nextSession = { ...session };
|
|
687
|
+
delete nextSession.selectedInstanceId;
|
|
688
|
+
if (!(await persistSession(io, ui, env, nextSession))) {
|
|
689
|
+
return 1;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const target = resolveCurrentInstanceTarget(nextSession, env);
|
|
693
|
+
ui.json("Workshop Select Instance", {
|
|
694
|
+
ok: true,
|
|
695
|
+
selectedInstanceId: null,
|
|
696
|
+
currentInstanceId: target.instanceId,
|
|
697
|
+
source: target.source,
|
|
698
|
+
cleared: true,
|
|
699
|
+
});
|
|
700
|
+
return 0;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const instanceId = await readRequiredCommandValue(
|
|
704
|
+
io,
|
|
705
|
+
flags,
|
|
706
|
+
["id", "instance-id"],
|
|
707
|
+
"Instance id: ",
|
|
708
|
+
readOptionalPositional(positionals, 2),
|
|
709
|
+
);
|
|
710
|
+
if (!instanceId) {
|
|
711
|
+
ui.status("error", "Instance id is required.", { stream: "stderr" });
|
|
712
|
+
return 1;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
try {
|
|
716
|
+
const client = createHarnessClient({ fetchFn: deps.fetchFn, session });
|
|
717
|
+
const result = await client.getWorkshopInstance(instanceId);
|
|
718
|
+
const nextSession = {
|
|
719
|
+
...session,
|
|
720
|
+
selectedInstanceId: result.instance?.id ?? instanceId,
|
|
721
|
+
};
|
|
722
|
+
if (!(await persistSession(io, ui, env, nextSession))) {
|
|
723
|
+
return 1;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
ui.json("Workshop Select Instance", {
|
|
727
|
+
ok: true,
|
|
728
|
+
source: "session",
|
|
729
|
+
selectedInstanceId: nextSession.selectedInstanceId,
|
|
730
|
+
...summarizeWorkshopInstance(result.instance),
|
|
731
|
+
instance: result.instance,
|
|
732
|
+
});
|
|
733
|
+
return 0;
|
|
734
|
+
} catch (error) {
|
|
735
|
+
if (error instanceof HarnessApiError) {
|
|
736
|
+
ui.status("error", `Select instance failed: ${error.message}`, { stream: "stderr" });
|
|
737
|
+
return 1;
|
|
738
|
+
}
|
|
739
|
+
throw error;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
592
743
|
async function handleWorkshopListInstances(io, ui, env, deps) {
|
|
593
744
|
const session = await requireSession(io, ui, env);
|
|
594
745
|
if (!session) {
|
|
@@ -625,7 +776,7 @@ async function handleWorkshopShowInstance(io, ui, env, positionals, flags, deps)
|
|
|
625
776
|
flags,
|
|
626
777
|
["id", "instance-id"],
|
|
627
778
|
"Instance id: ",
|
|
628
|
-
readOptionalPositional(positionals, 2),
|
|
779
|
+
readOptionalPositional(positionals, 2) ?? session.selectedInstanceId,
|
|
629
780
|
);
|
|
630
781
|
if (!instanceId) {
|
|
631
782
|
ui.status("error", "Instance id is required.", { stream: "stderr" });
|
|
@@ -724,7 +875,7 @@ async function handleWorkshopUpdateInstance(io, ui, env, positionals, flags, dep
|
|
|
724
875
|
flags,
|
|
725
876
|
["id"],
|
|
726
877
|
"Instance id: ",
|
|
727
|
-
readOptionalPositional(positionals, 2),
|
|
878
|
+
readOptionalPositional(positionals, 2) ?? session.selectedInstanceId,
|
|
728
879
|
);
|
|
729
880
|
if (!instanceId) {
|
|
730
881
|
ui.status("error", "Instance id is required.", { stream: "stderr" });
|
|
@@ -739,7 +890,7 @@ async function handleWorkshopUpdateInstance(io, ui, env, positionals, flags, dep
|
|
|
739
890
|
if (!hasWorkshopMetadataInput(payload)) {
|
|
740
891
|
ui.status(
|
|
741
892
|
"error",
|
|
742
|
-
"At least one metadata field is required. Use flags such as --event-title, --date-range, --venue-name, or --room-name.",
|
|
893
|
+
"At least one metadata field is required. Use flags such as --content-lang, --event-title, --date-range, --venue-name, or --room-name.",
|
|
743
894
|
{ stream: "stderr" },
|
|
744
895
|
);
|
|
745
896
|
return 1;
|
|
@@ -774,7 +925,7 @@ async function handleWorkshopPrepare(io, ui, env, positionals, flags, deps) {
|
|
|
774
925
|
flags,
|
|
775
926
|
["id", "instance-id"],
|
|
776
927
|
"Instance id: ",
|
|
777
|
-
readOptionalPositional(positionals, 2),
|
|
928
|
+
readOptionalPositional(positionals, 2) ?? session.selectedInstanceId,
|
|
778
929
|
);
|
|
779
930
|
if (!instanceId) {
|
|
780
931
|
ui.status("error", "Instance id is required.", { stream: "stderr" });
|
|
@@ -810,7 +961,7 @@ async function handleWorkshopResetInstance(io, ui, env, positionals, flags, deps
|
|
|
810
961
|
flags,
|
|
811
962
|
["id", "instance-id"],
|
|
812
963
|
"Instance id: ",
|
|
813
|
-
readOptionalPositional(positionals, 2),
|
|
964
|
+
readOptionalPositional(positionals, 2) ?? session.selectedInstanceId,
|
|
814
965
|
);
|
|
815
966
|
if (!instanceId) {
|
|
816
967
|
ui.status("error", "Instance id is required.", { stream: "stderr" });
|
|
@@ -845,7 +996,7 @@ async function handleWorkshopRemoveInstance(io, ui, env, positionals, flags, dep
|
|
|
845
996
|
flags,
|
|
846
997
|
["id", "instance-id"],
|
|
847
998
|
"Instance id: ",
|
|
848
|
-
readOptionalPositional(positionals, 2),
|
|
999
|
+
readOptionalPositional(positionals, 2) ?? session.selectedInstanceId,
|
|
849
1000
|
);
|
|
850
1001
|
if (!instanceId) {
|
|
851
1002
|
ui.status("error", "Instance id is required.", { stream: "stderr" });
|
|
@@ -884,7 +1035,11 @@ async function handleWorkshopPhaseSet(io, ui, env, positionals, deps) {
|
|
|
884
1035
|
|
|
885
1036
|
try {
|
|
886
1037
|
const client = createHarnessClient({ fetchFn: deps.fetchFn, session });
|
|
887
|
-
const
|
|
1038
|
+
const target = resolveCurrentInstanceTarget(session, env);
|
|
1039
|
+
const result =
|
|
1040
|
+
target.source === "session" && target.instanceId
|
|
1041
|
+
? await client.setCurrentPhaseForInstance(target.instanceId, phaseId)
|
|
1042
|
+
: await client.setCurrentPhase(phaseId);
|
|
888
1043
|
ui.json("Workshop Phase", result);
|
|
889
1044
|
return 0;
|
|
890
1045
|
} catch (error) {
|
|
@@ -899,8 +1054,8 @@ async function handleWorkshopPhaseSet(io, ui, env, positionals, deps) {
|
|
|
899
1054
|
export async function runCli(argv, io, deps = {}) {
|
|
900
1055
|
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
901
1056
|
const mergedDeps = { fetchFn, sleepFn: deps.sleepFn, openUrl: deps.openUrl, cwd: deps.cwd };
|
|
902
|
-
const ui = createCliUi(io);
|
|
903
1057
|
const { positionals, flags } = parseArgs(argv);
|
|
1058
|
+
const ui = createCliUi(io, { jsonMode: flags.json === true || flags.output === "json" });
|
|
904
1059
|
const [scope, action, subaction] = positionals;
|
|
905
1060
|
|
|
906
1061
|
if (flags.help === true) {
|
|
@@ -943,6 +1098,14 @@ export async function runCli(argv, io, deps = {}) {
|
|
|
943
1098
|
return handleSkillInstall(io, ui, mergedDeps, flags);
|
|
944
1099
|
}
|
|
945
1100
|
|
|
1101
|
+
if (scope === "workshop" && action === "current-instance") {
|
|
1102
|
+
return handleWorkshopCurrentInstance(io, ui, io.env, mergedDeps);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (scope === "workshop" && action === "select-instance") {
|
|
1106
|
+
return handleWorkshopSelectInstance(io, ui, io.env, positionals, flags, mergedDeps);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
946
1109
|
if (scope === "workshop" && action === "status") {
|
|
947
1110
|
return handleWorkshopStatus(io, ui, io.env, mergedDeps);
|
|
948
1111
|
}
|
package/src/session-store.js
CHANGED
|
@@ -314,6 +314,7 @@ export function sanitizeSession(session, env) {
|
|
|
314
314
|
authType: session.authType,
|
|
315
315
|
username: session.username ?? null,
|
|
316
316
|
email: session.email ?? null,
|
|
317
|
+
selectedInstanceId: session.selectedInstanceId ?? null,
|
|
317
318
|
loggedInAt: session.loggedInAt,
|
|
318
319
|
expiresAt: session.expiresAt ?? null,
|
|
319
320
|
mode: session.mode ?? "local-dev",
|
package/src/workshop-bundle.js
CHANGED
|
@@ -225,6 +225,20 @@ async function writeWorkshopBundleManifest(bundleRoot, manifest) {
|
|
|
225
225
|
);
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
async function pruneBundleFiles(bundleRoot, manifest) {
|
|
229
|
+
const expectedFiles = new Set([
|
|
230
|
+
WORKSHOP_BUNDLE_MANIFEST,
|
|
231
|
+
...manifest.files.map((file) => file.path),
|
|
232
|
+
]);
|
|
233
|
+
const currentFiles = await listFilesRecursive(bundleRoot);
|
|
234
|
+
|
|
235
|
+
for (const file of currentFiles) {
|
|
236
|
+
if (!expectedFiles.has(file.relativePath)) {
|
|
237
|
+
await fs.rm(file.absolutePath, { force: true });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
228
242
|
export async function createWorkshopBundleFromSource(sourceRoot, targetRoot, options = {}) {
|
|
229
243
|
if (options.clean === true) {
|
|
230
244
|
await fs.rm(targetRoot, { recursive: true, force: true });
|
|
@@ -234,6 +248,9 @@ export async function createWorkshopBundleFromSource(sourceRoot, targetRoot, opt
|
|
|
234
248
|
await fs.rm(path.join(targetRoot, "workshop-skill", "SKILL.md"), { force: true });
|
|
235
249
|
await copyBundleFiles(sourceRoot, targetRoot);
|
|
236
250
|
const manifest = await createWorkshopBundleManifestFromSource(sourceRoot);
|
|
251
|
+
if (options.prune === true) {
|
|
252
|
+
await pruneBundleFiles(targetRoot, manifest);
|
|
253
|
+
}
|
|
237
254
|
await writeWorkshopBundleManifest(targetRoot, manifest);
|
|
238
255
|
}
|
|
239
256
|
|
|
@@ -250,7 +267,7 @@ export async function syncPackagedWorkshopBundle() {
|
|
|
250
267
|
export async function syncRepoBundledWorkshopSkill() {
|
|
251
268
|
const sourceRoot = getRepoWorkshopSourceRoot();
|
|
252
269
|
const bundleRoot = getRepoBundledWorkshopSkillPath();
|
|
253
|
-
await createWorkshopBundleFromSource(sourceRoot, bundleRoot, {
|
|
270
|
+
await createWorkshopBundleFromSource(sourceRoot, bundleRoot, { prune: true });
|
|
254
271
|
return {
|
|
255
272
|
sourceRoot,
|
|
256
273
|
bundleRoot,
|