holivia 0.8.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a26d0c9d308b30ee2ecf2834ecb8f0dce84eb6b7ba0e561f31c0e53fa4804ccf
4
- data.tar.gz: 62d2c94d7d97c14d7b25d89b64cb4344795451997cecee800d54bea575b9a25f
3
+ metadata.gz: 649b14e43fe74902dab26504ac1eb2ec403d3f7de0357283fb16393cd95e4d84
4
+ data.tar.gz: da1363943075ffbab5fa664434666202bc5654785a2e83083e6894c52d270baa
5
5
  SHA512:
6
- metadata.gz: 69c8e4423d087b1fbdb94927524a97889a7afd67daa28c5db3553b67a0b2171c24fd2198f06f6003556ef08353b15d54aede4dd7f818ef9f25d5514057e837e8
7
- data.tar.gz: 4123d6b7749b3942c29c214d7b22b5286e73434037fb6ce6fb4a3b40a9aa5497df7b8bc645e13c3cdeb13a1680201505aa4e971ea3027c10fd90f4780c714dd2
6
+ metadata.gz: 497030e934ea60e03348f922f809811ef2f1d1172cd90c9a1b96533a26461d82a2dc6e2938cacf9a4e982ba30de93004edfb9e3f2ac79b9abc27247517312d2c
7
+ data.tar.gz: c36fa00ac0e7d9979ab1502a08143795b6ee7b97d3bafee411778d018c5ba96c34074a728cba00d4a44463de43bc96dc2724a6bc32065ea595da049079da491e
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: add-holivia-cli-endpoint
3
+ description: Add, extend, or review Holivia Ruby CLI commands that expose API endpoints while preserving the repository's routing, option parsing, HTTP, JSON output, help, and Minitest conventions. Use when implementing a new top-level CLI resource, adding an action or CRUD endpoint to an existing resource, exposing filters or request fields, adding multipart uploads, or checking an endpoint implementation for architectural consistency.
4
+ ---
5
+
6
+ # Add a Holivia CLI Endpoint
7
+
8
+ Read `../../../ai-skills/add-holivia-cli-endpoint.md` completely before taking any task action. Treat that file as the canonical workflow and follow it for the rest of the task.
9
+
10
+ If the file cannot be read, stop and report that the canonical guide is unavailable instead of reconstructing its instructions from memory.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Add Holivia CLI Endpoint"
3
+ short_description: "Add API endpoints using the existing CLI design"
4
+ default_prompt: "Use $add-holivia-cli-endpoint to add this API endpoint consistently to the Holivia CLI."
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.10.0] - 2026-07-17
4
+
5
+ - Add repeatable `--topic-id` support to replace or clear topics assigned to selfcare content
6
+ - Add CLI endpoint development skill documentation
7
+
8
+ ## [0.9.0] - 2026-07-11
9
+
10
+ - Add `holivia highlight` commands for HR home highlight CRUD, publishing, schema discovery, and cover/document uploads
11
+ - Add `holivia enterprise` lookup commands for backoffice enterprise discovery
12
+ - Add `holivia crisis` CRUD commands for backoffice crisis management
13
+ - Add `holivia collective-intervention` CRUD commands for backoffice collective intervention management
14
+
3
15
  ## [0.8.1] - 2026-07-08
4
16
 
5
17
  - Add provider filtering and write support to `holivia intervention` commands
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Ruby client and command-line interface for the Holivia API.
4
4
 
5
- The `holivia` executable is primarily used to manage Holivia backoffice data from the terminal: environments, authentication, selfcare content, objectives, communication library items, HR intervention catalog items, and appointment diagnostics.
5
+ The `holivia` executable is primarily used to manage Holivia backoffice data from the terminal: environments, authentication, selfcare content, objectives, enterprises, communication library items, HR intervention catalog items, HR home highlights, crises, collective interventions, and appointment diagnostics.
6
6
 
7
7
  Coding agents can use [`SKILL.md`](SKILL.md) as a downloadable usage guide for operating this CLI safely.
8
8
 
@@ -148,6 +148,18 @@ Create and update commands also accept JSON from standard input:
148
148
  printf '{"title":"Breathing exercise","locale":"fr"}' | holivia selfcare create
149
149
  ```
150
150
 
151
+ Replace the topics assigned to an existing content by repeating `--topic-id`:
152
+
153
+ ```bash
154
+ holivia selfcare update 123 --topic-id topic-id-1 --topic-id topic-id-2
155
+ ```
156
+
157
+ Pass an empty `topic_ids` array through stdin to remove every assigned topic. Omitting topic IDs leaves existing assignments unchanged:
158
+
159
+ ```bash
160
+ printf '{"topic_ids":[]}' | holivia selfcare update 123
161
+ ```
162
+
151
163
  List objectives:
152
164
 
153
165
  ```bash
@@ -166,6 +178,54 @@ Show video diagnostics for an appointment:
166
178
  holivia appointment video-diagnostics 42
167
179
  ```
168
180
 
181
+ Find an enterprise id:
182
+
183
+ ```bash
184
+ holivia enterprise lookup --query acme
185
+ ```
186
+
187
+ List crises for an enterprise:
188
+
189
+ ```bash
190
+ holivia crisis index --enterprise-id 123 --status reported
191
+ ```
192
+
193
+ Create a crisis:
194
+
195
+ ```bash
196
+ holivia crisis create \
197
+ --enterprise-id 123 \
198
+ --title "Critical site situation" \
199
+ --description "A manager reported an urgent situation." \
200
+ --contact-json '{"first_name":"Marie","last_name":"Dupont","phone":"+33612345678","email":"marie.dupont@example.com","job_title":"DRH"}'
201
+ ```
202
+
203
+ Resolve it:
204
+
205
+ ```bash
206
+ holivia crisis update 42 --status resolved
207
+ ```
208
+
209
+ List collective interventions for an enterprise:
210
+
211
+ ```bash
212
+ holivia collective-intervention index --enterprise-id 123 --status submitted
213
+ ```
214
+
215
+ Create a collective intervention:
216
+
217
+ ```bash
218
+ holivia collective-intervention create \
219
+ --enterprise-id 123 \
220
+ --intervention-item-id 456 \
221
+ --title "Manager workshop for Paris" \
222
+ --description "Collective support for a management team." \
223
+ --location "12 rue de la Paix, 75002 Paris" \
224
+ --scheduled-starts-at "2026-08-01T09:00:00Z" \
225
+ --scheduled-ends-at "2026-08-01T11:00:00Z" \
226
+ --contact-json '{"first_name":"Marie","last_name":"Dupont","phone":"+33612345678","email":"marie.dupont@example.com","job_title":"DRH"}'
227
+ ```
228
+
169
229
  List communication library items:
170
230
 
171
231
  ```bash
@@ -231,6 +291,45 @@ Publish it:
231
291
  holivia intervention publish 123
232
292
  ```
233
293
 
294
+ Discover HR home highlight enum values and locales:
295
+
296
+ ```bash
297
+ holivia highlight schema
298
+ ```
299
+
300
+ List HR home highlights:
301
+
302
+ ```bash
303
+ holivia highlight index --locale fr --state published --highlight-type feature
304
+ ```
305
+
306
+ Create an HR home highlight that points to a URL:
307
+
308
+ ```bash
309
+ holivia highlight create \
310
+ --locale fr \
311
+ --highlight-type feature \
312
+ --title "New manager toolkit" \
313
+ --resource-url https://example.com/toolkit \
314
+ --cover-image cover.png
315
+ ```
316
+
317
+ Or create one with a document target:
318
+
319
+ ```bash
320
+ holivia highlight create \
321
+ --locale fr \
322
+ --title "Benefits guide" \
323
+ --document benefits-guide.pdf \
324
+ --cover-image cover.png
325
+ ```
326
+
327
+ Publish it:
328
+
329
+ ```bash
330
+ holivia highlight publish 123
331
+ ```
332
+
234
333
  ## Files And Uploads
235
334
 
236
335
  Selfcare create and update commands can upload images with `--image <path>`.
@@ -251,6 +350,10 @@ Communication item create and update commands upload the required document with
251
350
 
252
351
  Intervention item create and update commands can upload or replace the cover image with `--cover-image <path>`.
253
352
 
353
+ HR home highlight create and update commands require `--cover-image <path>` and exactly one target: either `--resource-url <url>` or `--document <path>`.
354
+
355
+ Crisis and collective intervention create and update commands accept nested contacts as repeated `--contact-json <json>` flags or through piped JSON with a `contacts_attributes` array.
356
+
254
357
  ## Development
255
358
 
256
359
  After checking out the repo, run:
data/SKILL.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use this skill when you need to operate the Holivia API through the `holivia` command-line tool.
4
4
 
5
- The CLI manages Holivia backoffice data: environments, authentication, selfcare contents, objectives, selfcare-objective associations, HR intervention catalog items, and appointment video diagnostics.
5
+ The CLI manages Holivia backoffice data: environments, authentication, selfcare contents, objectives, selfcare-objective associations, enterprises, HR intervention catalog items, HR home highlights, crises, collective interventions, and appointment video diagnostics.
6
6
 
7
7
  ## Preconditions
8
8
 
@@ -19,7 +19,8 @@ Use `holivia` in examples below. If working from a checkout before installation,
19
19
  - Prefer interactive `holivia login` when a human can enter credentials. Use `--password` only when the user explicitly provides it for automation.
20
20
  - Before creating or updating content, run `holivia selfcare schema` and use its returned enum values and permitted item params as the source of truth.
21
21
  - Before creating or updating intervention catalog items, run `holivia intervention schema` and use its returned enum values and locales as the source of truth.
22
- - For destructive actions such as `holivia env remove` or `holivia selfcare objective delete`, confirm the target environment and ID first unless the user explicitly requested that exact action.
22
+ - Before creating or updating HR home highlights, run `holivia highlight schema` and use its returned enum values and locales as the source of truth.
23
+ - For destructive actions such as `holivia env remove`, `holivia selfcare objective delete`, `holivia crisis delete`, or `holivia collective-intervention delete`, confirm the target environment and ID first unless the user explicitly requested that exact action.
23
24
  - Treat all command output as JSON except informational commands such as `holivia env`, `holivia env list`, `holivia login`, `holivia logout`, `holivia version`, and `holivia --help`.
24
25
 
25
26
  ## Installation
@@ -139,6 +140,14 @@ holivia intervention schema
139
140
 
140
141
  Use the schema response for intervention types, providers, modalities, audiences, durations, categories, states, and locales.
141
142
 
143
+ For HR home highlight work, discover the live schema first:
144
+
145
+ ```bash
146
+ holivia highlight schema
147
+ ```
148
+
149
+ Use the schema response for highlight types, states, and locales.
150
+
142
151
  ## Selfcare Content
143
152
 
144
153
  List contents:
@@ -170,6 +179,14 @@ Update a content:
170
179
  holivia selfcare update 123 --title "Updated title" --state published
171
180
  ```
172
181
 
182
+ Replace the topics assigned to an existing content by repeating `--topic-id`:
183
+
184
+ ```bash
185
+ holivia selfcare update 123 --topic-id topic-id-1 --topic-id topic-id-2
186
+ ```
187
+
188
+ Pass `{"topic_ids":[]}` through stdin to clear all topic assignments. Omit topic IDs to leave assignments unchanged.
189
+
173
190
  Upload or replace an image:
174
191
 
175
192
  ```bash
@@ -278,6 +295,102 @@ holivia objective show 123
278
295
 
279
296
  Objective translated fields are returned in the default locale, currently `fr`.
280
297
 
298
+ ## Enterprises
299
+
300
+ Find an enterprise id:
301
+
302
+ ```bash
303
+ holivia enterprise lookup --query acme
304
+ ```
305
+
306
+ Filter enterprise lookup:
307
+
308
+ ```bash
309
+ holivia enterprise index --headquarter-id 10 --user-id 20 --page 1 --per-page 25
310
+ ```
311
+
312
+ ## Crises
313
+
314
+ List crises:
315
+
316
+ ```bash
317
+ holivia crisis index --enterprise-id 123 --status reported
318
+ ```
319
+
320
+ Show one crisis:
321
+
322
+ ```bash
323
+ holivia crisis show 42
324
+ ```
325
+
326
+ Create a crisis:
327
+
328
+ ```bash
329
+ holivia crisis create \
330
+ --enterprise-id 123 \
331
+ --title "Critical site situation" \
332
+ --description "A manager reported an urgent situation." \
333
+ --contact-json '{"first_name":"Marie","last_name":"Dupont","phone":"+33612345678","email":"marie.dupont@example.com","job_title":"DRH"}'
334
+ ```
335
+
336
+ Update crisis status:
337
+
338
+ ```bash
339
+ holivia crisis update 42 --status resolved
340
+ ```
341
+
342
+ Delete a crisis:
343
+
344
+ ```bash
345
+ holivia crisis delete 42
346
+ ```
347
+
348
+ Status values are `reported`, `in_progress`, and `resolved`.
349
+
350
+ ## Collective Interventions
351
+
352
+ List collective interventions:
353
+
354
+ ```bash
355
+ holivia collective-intervention index --enterprise-id 123 --status submitted
356
+ ```
357
+
358
+ Show one collective intervention:
359
+
360
+ ```bash
361
+ holivia collective-intervention show 42
362
+ ```
363
+
364
+ Create a collective intervention:
365
+
366
+ ```bash
367
+ holivia collective-intervention create \
368
+ --enterprise-id 123 \
369
+ --intervention-item-id 456 \
370
+ --title "Manager workshop for Paris" \
371
+ --description "Collective support for a management team." \
372
+ --location "12 rue de la Paix, 75002 Paris" \
373
+ --scheduled-starts-at "2026-08-01T09:00:00Z" \
374
+ --scheduled-ends-at "2026-08-01T11:00:00Z" \
375
+ --contact-json '{"first_name":"Marie","last_name":"Dupont","phone":"+33612345678","email":"marie.dupont@example.com","job_title":"DRH"}'
376
+ ```
377
+
378
+ Schedule or complete a collective intervention:
379
+
380
+ ```bash
381
+ holivia collective-intervention update 42 --status scheduled
382
+ holivia collective-intervention update 42 --status completed
383
+ ```
384
+
385
+ Delete a collective intervention:
386
+
387
+ ```bash
388
+ holivia collective-intervention delete 42
389
+ ```
390
+
391
+ Status values are `submitted`, `scheduled`, `in_progress`, `completed`, and `canceled`.
392
+ Use piped JSON instead of `--contact-json` when the payload has multiple contacts or long text.
393
+
281
394
  ## Intervention Items
282
395
 
283
396
  List intervention catalog items:
@@ -347,6 +460,66 @@ Delete one localized item:
347
460
  holivia intervention delete 123
348
461
  ```
349
462
 
463
+ ## HR Home Highlights
464
+
465
+ List HR home highlights:
466
+
467
+ ```bash
468
+ holivia highlight index --locale fr --state published
469
+ ```
470
+
471
+ Filter by highlight metadata:
472
+
473
+ ```bash
474
+ holivia highlight index --query toolkit --locale fr --highlight-type feature --state published
475
+ ```
476
+
477
+ Show one highlight:
478
+
479
+ ```bash
480
+ holivia highlight show 123
481
+ ```
482
+
483
+ Create a highlight that points to a URL:
484
+
485
+ ```bash
486
+ holivia highlight create \
487
+ --locale fr \
488
+ --highlight-type feature \
489
+ --title "Manager toolkit" \
490
+ --resource-url https://example.com/toolkit \
491
+ --cover-image cover.png
492
+ ```
493
+
494
+ Create a highlight that points to an uploaded document:
495
+
496
+ ```bash
497
+ holivia highlight create \
498
+ --locale fr \
499
+ --title "Benefits guide" \
500
+ --document benefits-guide.pdf \
501
+ --cover-image cover.png
502
+ ```
503
+
504
+ Create or update from JSON for metadata-only changes:
505
+
506
+ ```bash
507
+ printf '{"locale":"fr","title":"Manager toolkit","resource_url":"https://example.com/toolkit"}' | holivia highlight create
508
+ ```
509
+
510
+ Publish or unpublish one localized highlight:
511
+
512
+ ```bash
513
+ holivia highlight publish 123
514
+ holivia highlight unpublish 123
515
+ ```
516
+
517
+ Delete one localized highlight:
518
+
519
+ ```bash
520
+ holivia highlight delete 123
521
+ ```
522
+
350
523
  ## Selfcare Objective Associations
351
524
 
352
525
  List associations:
@@ -412,6 +585,8 @@ Before making API changes:
412
585
  - Run `holivia env` and verify the active URL/environment.
413
586
  - Run `holivia selfcare schema` before selfcare create/update/compose work.
414
587
  - Run `holivia intervention schema` before intervention create/update work.
588
+ - Run `holivia highlight schema` before highlight create/update work.
589
+ - Run `holivia enterprise lookup --query <name>` when you need an `enterprise_id`.
415
590
  - Use existing IDs from list/show commands or explicit user input.
416
591
  - Prefer draft states unless the user explicitly requests publishing.
417
592
  - Use JSON files or stdin for complex payloads.
@@ -0,0 +1,124 @@
1
+ # Add a Holivia CLI Endpoint
2
+
3
+ Keep endpoint commands thin and consistent with the nearest existing resource. Implement the API contract at the command layer; reuse the shared client for transport, authentication, retries, response parsing, and API errors.
4
+
5
+ ## Inspect Before Editing
6
+
7
+ 1. Read `CLAUDE.md` and check the worktree for user changes.
8
+ 2. Establish the endpoint contract from the request or authoritative API material: HTTP verb, exact path, path parameters, query parameters, body keys and types, file fields, response shape, and required CLI name. Do not invent missing contract details.
9
+ 3. Read these architecture files:
10
+ - `lib/holivia/cli.rb` for top-level registration.
11
+ - `lib/holivia/commands/base.rb` for the shared client, JSON output, and piped JSON.
12
+ - `lib/holivia/client.rb` for supported HTTP methods and request behavior.
13
+ - `lib/holivia/cli/help.rb` for user-facing discovery.
14
+ - `test/holivia/test_cli.rb` for routing and help expectations.
15
+ 4. Choose the closest command and test pair as the implementation model:
16
+ - Read-only collection/member: `objective.rb` or `enterprise.rb`.
17
+ - Single member action: `appointment.rb`.
18
+ - CRUD with filters and nested JSON: `crisis.rb`.
19
+ - CRUD, schema, transitions, and uploads: `communication_item.rb`, `intervention_item.rb`, or `hr_home_highlight.rb`.
20
+ - Nested CLI namespace: `selfcare_objective.rb`, routed by `selfcare.rb`.
21
+ 5. Prefer extending the selected pattern over introducing an abstraction for one endpoint. Refactor shared behavior only when the task requires it or repetition has become material.
22
+
23
+ ## Place the Endpoint
24
+
25
+ For a new top-level resource:
26
+
27
+ 1. Add `lib/holivia/commands/<resource>.rb` with `# frozen_string_literal: true` and `require_relative "base"`.
28
+ 2. Define `Holivia::Commands::<Resource> < Base` and an exact `BASE_PATH`, normally under `/api/v1/backoffice`.
29
+ 3. Add `.route(args)`: shift the subcommand, dispatch with a `case`, pass the remaining array to the instance method, and warn plus `exit 1` for unknown commands.
30
+ 4. Require the command in `lib/holivia/cli.rb` and route its public top-level name in `CLI.start`.
31
+ 5. Add aliases only when the product vocabulary requires them; test each intentional alias.
32
+
33
+ For an endpoint belonging to an existing resource, add a subcommand and instance method to that command class. For a nested namespace, route through its parent command rather than adding another top-level command.
34
+
35
+ Use kebab-case for multiword CLI tokens, snake_case for Ruby filenames, constants, API paths, and request keys, and PascalCase for command classes. Follow existing public vocabulary when it differs from the API resource name.
36
+
37
+ ## Implement Command Behavior
38
+
39
+ Use these mappings:
40
+
41
+ - Collection read: `client.get(BASE_PATH, params: params)`.
42
+ - Member read: `client.get("#{BASE_PATH}/#{id}")`.
43
+ - Create: `client.post(BASE_PATH, body: options)`.
44
+ - Update: `client.patch("#{BASE_PATH}/#{id}", body: options)`.
45
+ - Member action: call the contract's verb on `"#{BASE_PATH}/#{id}/<action>"`.
46
+ - Delete: call `client.delete`, then print `output(deleted: true, id: id.to_i)` when the server has no useful body.
47
+ - Schema/discovery: `client.get("#{BASE_PATH}/schema")`.
48
+
49
+ Do not instantiate Faraday directly in a command. Do not add authentication headers, retry logic, response parsing, or `ApiError` rescue there; `Client` and `exe/holivia` already own those concerns. Extend `Client` and its tests only if the API requires an unsupported HTTP capability.
50
+
51
+ Always pass successful API responses to `output`, which preserves pretty-printed JSON as the CLI's machine-readable interface. Do not reshape a response unless the endpoint contract explicitly calls for it.
52
+
53
+ ### Parse arguments
54
+
55
+ - Accept positional member IDs first with `id = args.shift`.
56
+ - Abort missing IDs with the full command usage, for example `abort "Usage: holivia widget show <id>" unless id`.
57
+ - Use `OptionParser` and set a complete `opts.banner`.
58
+ - Map `--kebab-case` flags to snake_case symbol keys.
59
+ - Apply `Integer` converters to numeric identifiers, pagination, counts, and durations. Preserve strings such as UUIDs, codes, timestamps, states, and locales.
60
+ - Collect repeatable array flags by appending to an initialized array. Parse explicitly JSON-valued flags with `JSON.parse(..., symbolize_names: true)` when the resulting object is part of a symbol-keyed body.
61
+ - Keep collection filters in `params`; keep create/update values in `options`.
62
+ - For create and update, merge `piped_json` after flags with `options.merge(piped_json)`. This intentionally makes stdin JSON win on duplicate keys.
63
+ - Abort an empty create/update body with `No options provided. Use --help for usage.`
64
+ - Let the server validate domain rules and enums unless the repository already performs that validation. Expose a schema endpoint when the API provides one.
65
+
66
+ Extract a shared private `add_write_options` method when create and update accept the same fields. Keep action helpers such as `transition(args, event)` private when several subcommands share the same shape.
67
+
68
+ ### Handle uploads
69
+
70
+ Convert file paths to `Faraday::Multipart::FilePart` in a private body builder. Duplicate the options hash before replacing paths so the parser result is not mutated unexpectedly. Use a frozen extension-to-MIME map and fall back to `application/octet-stream`. Reuse the existing multipart-enabled `Client`; do not set the content type manually.
71
+
72
+ Test every supported MIME mapping, the fallback, and each file field's conversion. Do not add client-side size or presence validation unless requested; API validation remains authoritative.
73
+
74
+ ## Update Discovery Surfaces
75
+
76
+ Add the command, its arguments, and a concise description to the appropriate section of `lib/holivia/cli/help.rb`. Add or adjust the help assertions in `test/holivia/test_cli.rb`.
77
+
78
+ Update `README.md` and the root operational `SKILL.md` only when the endpoint changes the documented primary workflow or should be available to agents operating the released CLI. Do not bump the gem version or edit release notes unless the user requests release preparation.
79
+
80
+ ## Test at the Command Boundary
81
+
82
+ Create or update `test/holivia/commands/test_<resource>.rb`. Follow the nearest test file rather than introducing a new framework.
83
+
84
+ 1. Require `test_helper`, the command file, and `tmpdir` when used.
85
+ 2. Stub `$stdin` as a TTY in setup for commands that call `piped_json`; restore it in teardown.
86
+ 3. Stub `Holivia::Client.new` with a small object and restore the original method in `ensure`.
87
+ 4. Assert the exact HTTP method, endpoint path, query params or body, and representative JSON output.
88
+ 5. Cover every added behavior that applies:
89
+ - routing and unknown subcommand failure;
90
+ - filters and OptionParser type conversion;
91
+ - missing member ID;
92
+ - create/update with flags;
93
+ - piped JSON and its precedence when relevant;
94
+ - empty write rejection;
95
+ - member actions;
96
+ - delete confirmation;
97
+ - multipart parts and MIME detection;
98
+ - aliases;
99
+ - help visibility and top-level routing for a new resource.
100
+
101
+ Keep these tests at the CLI-to-client boundary. Do not make network requests. Add `Client` tests only when changing transport behavior.
102
+
103
+ ## Verify and Review
104
+
105
+ Run the narrow test first:
106
+
107
+ ```bash
108
+ bundle exec ruby -Itest test/holivia/commands/test_<resource>.rb
109
+ ```
110
+
111
+ Then run the repository checks:
112
+
113
+ ```bash
114
+ bundle exec rake
115
+ ```
116
+
117
+ Before finishing, inspect the diff and confirm:
118
+
119
+ - Every endpoint path and verb matches the contract exactly.
120
+ - Routing, requires, help text, and tests expose the same command spelling.
121
+ - Query keys, body keys, and OptionParser types match the API.
122
+ - Writes support stdin JSON consistently, unless the command is intentionally file-only or action-only.
123
+ - Successful output is JSON and failures retain the shared executable behavior.
124
+ - No unrelated refactor, version bump, credential, or generated package entered the change.
@@ -27,7 +27,8 @@ module Holivia
27
27
  holivia selfcare create [options] Create a selfcare content
28
28
  (--state draft|ongoing_translation|translation_to_be_reviewed|
29
29
  translation_reviewed|published)
30
- holivia selfcare update <id> [options] Update a selfcare content (same --state values)
30
+ holivia selfcare update <id> [options] Update a selfcare content (same --state values;
31
+ repeat --topic-id ID to replace assigned topics)
31
32
  holivia selfcare compose Create a full content tree atomically (no audio)
32
33
  holivia selfcare schema Show allowed values for content_types, format_types,
33
34
  item_types, states, objective_tiers
@@ -49,6 +50,11 @@ module Holivia
49
50
  holivia objective show <id> Show one objective
50
51
  Translated fields are returned in the default locale (fr).
51
52
 
53
+ Enterprises:
54
+ holivia enterprise index [--query TEXT --headquarter-id ID --user-id ID --page N --per-page N]
55
+ Find enterprises and their enterprise_id values
56
+ holivia enterprise lookup [options] Alias for enterprise index
57
+
52
58
  Communication Items:
53
59
  holivia communication index [--page N --per-page N --query TEXT --locale LOCALE --document-type TYPE]
54
60
  List communication library items
@@ -73,6 +79,36 @@ module Holivia
73
79
  holivia intervention unpublish <id> Unpublish one intervention item
74
80
  holivia intervention delete <id> Delete one localized intervention item
75
81
 
82
+ HR Home Highlights:
83
+ holivia highlight index [--page N --per-page N --query TEXT --locale LOCALE
84
+ --highlight-type TYPE --state STATE]
85
+ List HR home highlights
86
+ holivia highlight schema Show allowed highlight_types, states, and locales
87
+ holivia highlight show <id> Show one HR home highlight
88
+ holivia highlight create [options] Create one localized HR home highlight
89
+ holivia highlight update <id> [options] Update one localized HR home highlight
90
+ holivia highlight publish <id> Publish one HR home highlight
91
+ holivia highlight unpublish <id> Unpublish one HR home highlight
92
+ holivia highlight delete <id> Delete one localized HR home highlight
93
+
94
+ Crises:
95
+ holivia crisis index [--enterprise-id ID --status STATUS --page N --per-page N]
96
+ List crises
97
+ holivia crisis show <id> Show one crisis
98
+ holivia crisis create [options] Create a crisis
99
+ holivia crisis update <id> [options] Update a crisis
100
+ holivia crisis delete <id> Delete a crisis
101
+ Status values: reported, in_progress, resolved.
102
+
103
+ Collective Interventions:
104
+ holivia collective-intervention index [--enterprise-id ID --status STATUS --page N --per-page N]
105
+ List collective interventions
106
+ holivia collective-intervention show <id> Show one collective intervention
107
+ holivia collective-intervention create [options] Create a collective intervention
108
+ holivia collective-intervention update <id> [options] Update a collective intervention
109
+ holivia collective-intervention delete <id> Delete a collective intervention
110
+ Status values: submitted, scheduled, in_progress, completed, canceled.
111
+
76
112
  Appointments:
77
113
  holivia appointment video-diagnostics <id> Show video diagnostics for an appointment
78
114
 
@@ -116,6 +152,9 @@ module Holivia
116
152
  Communication uploads use --document <path> and optional --cover-image <path>.
117
153
  The API validates accepted communication upload formats and file sizes.
118
154
  Intervention cover images use --cover-image <path> on intervention create/update.
155
+ Highlight uploads use required --cover-image <path> and either --resource-url URL or --document <path>.
156
+ Crisis and collective intervention contacts can be passed as repeated --contact-json JSON flags,
157
+ or as "contacts_attributes": [...] in piped JSON.
119
158
  Compose is JSON-only — to attach an image to a composed tree, PATCH the returned id:
120
159
  holivia selfcare update <id> --image <path>
121
160
 
@@ -130,6 +169,8 @@ module Holivia
130
169
  values — it is the source of truth.
131
170
  Run holivia intervention schema before creating or updating intervention items
132
171
  to discover current intervention enum values and locales.
172
+ Run holivia highlight schema before creating or updating HR home highlights
173
+ to discover current highlight types, states, and locales.
133
174
 
134
175
  Version:
135
176
  holivia version Print version
data/lib/holivia/cli.rb CHANGED
@@ -12,10 +12,14 @@ require_relative "commands/objective"
12
12
  require_relative "commands/appointment"
13
13
  require_relative "commands/communication_item"
14
14
  require_relative "commands/intervention_item"
15
+ require_relative "commands/hr_home_highlight"
16
+ require_relative "commands/enterprise"
17
+ require_relative "commands/crisis"
18
+ require_relative "commands/collective_intervention"
15
19
 
16
20
  module Holivia
17
21
  class CLI
18
- def self.start(args) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
22
+ def self.start(args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
19
23
  command = args.shift
20
24
  case command
21
25
  when "login" then Commands::Auth.new.login(args)
@@ -26,6 +30,10 @@ module Holivia
26
30
  when "appointment" then Commands::Appointment.route(args)
27
31
  when "communication" then Commands::CommunicationItem.route(args)
28
32
  when "intervention" then Commands::InterventionItem.route(args)
33
+ when "highlight" then Commands::HrHomeHighlight.route(args)
34
+ when "enterprise" then Commands::Enterprise.route(args)
35
+ when "crisis" then Commands::Crisis.route(args)
36
+ when "collective-intervention", "collective_intervention", "collective" then Commands::CollectiveIntervention.route(args)
29
37
  when "version", "--version", "-v" then puts "holivia #{Holivia::VERSION}"
30
38
  when "--help", "-h", nil then puts Help::HELP_TEXT
31
39
  else warn "Unknown command: #{command}"
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class CollectiveIntervention < Base
8
+ BASE_PATH = "/api/v1/backoffice/collective_interventions"
9
+
10
+ def self.route(args)
11
+ subcommand = args.shift
12
+ case subcommand
13
+ when "index" then new.index(args)
14
+ when "show" then new.show(args)
15
+ when "create" then new.create(args)
16
+ when "update" then new.update(args)
17
+ when "delete" then new.delete(args)
18
+ else warn "Unknown collective intervention command: #{subcommand}"
19
+ exit 1
20
+ end
21
+ end
22
+
23
+ def index(args = [])
24
+ params = {}
25
+ OptionParser.new do |opts|
26
+ opts.banner = "Usage: holivia collective-intervention index [options]"
27
+ opts.on("--enterprise-id ID", Integer) { |v| params[:enterprise_id] = v }
28
+ opts.on("--status STATUS") { |v| params[:status] = v }
29
+ opts.on("--page N", Integer) { |v| params[:page] = v }
30
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
31
+ end.parse!(args)
32
+
33
+ output(client.get(BASE_PATH, params: params))
34
+ end
35
+
36
+ def show(args = [])
37
+ id = args.shift
38
+ abort "Usage: holivia collective-intervention show <id>" unless id
39
+
40
+ output(client.get("#{BASE_PATH}/#{id}"))
41
+ end
42
+
43
+ def create(args = [])
44
+ options = parse_write_options(args, "Usage: holivia collective-intervention create [options]")
45
+ abort "No options provided. Use --help for usage." if options.empty?
46
+
47
+ output(client.post(BASE_PATH, body: options))
48
+ end
49
+
50
+ def update(args = [])
51
+ id = args.shift
52
+ abort "Usage: holivia collective-intervention update <id> [options]" unless id
53
+
54
+ options = parse_write_options(args, "Usage: holivia collective-intervention update <id> [options]")
55
+ abort "No options provided. Use --help for usage." if options.empty?
56
+
57
+ output(client.patch("#{BASE_PATH}/#{id}", body: options))
58
+ end
59
+
60
+ def delete(args = [])
61
+ id = args.shift
62
+ abort "Usage: holivia collective-intervention delete <id>" unless id
63
+
64
+ client.delete("#{BASE_PATH}/#{id}")
65
+ output(deleted: true, id: id.to_i)
66
+ end
67
+
68
+ private
69
+
70
+ def parse_write_options(args, banner) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
71
+ options = {}
72
+ OptionParser.new do |opts|
73
+ opts.banner = banner
74
+ opts.on("--enterprise-id ID", Integer) { |v| options[:enterprise_id] = v }
75
+ opts.on("--intervention-item-id ID", Integer) { |v| options[:intervention_item_id] = v }
76
+ opts.on("--title TITLE") { |v| options[:title] = v }
77
+ opts.on("--description DESC") { |v| options[:description] = v }
78
+ opts.on("--location LOCATION") { |v| options[:location] = v }
79
+ opts.on("--scheduled-starts-at TIME") { |v| options[:scheduled_starts_at] = v }
80
+ opts.on("--scheduled-ends-at TIME") { |v| options[:scheduled_ends_at] = v }
81
+ opts.on("--status STATUS") { |v| options[:status] = v }
82
+ opts.on("--contact-json JSON") { |v| append_contact(options, v) }
83
+ end.parse!(args)
84
+ options.merge(piped_json)
85
+ end
86
+
87
+ def append_contact(options, json)
88
+ options[:contacts_attributes] ||= []
89
+ options[:contacts_attributes] << JSON.parse(json, symbolize_names: true)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class Crisis < Base
8
+ BASE_PATH = "/api/v1/backoffice/crises"
9
+
10
+ def self.route(args)
11
+ subcommand = args.shift
12
+ case subcommand
13
+ when "index" then new.index(args)
14
+ when "show" then new.show(args)
15
+ when "create" then new.create(args)
16
+ when "update" then new.update(args)
17
+ when "delete" then new.delete(args)
18
+ else warn "Unknown crisis command: #{subcommand}"
19
+ exit 1
20
+ end
21
+ end
22
+
23
+ def index(args = [])
24
+ params = {}
25
+ OptionParser.new do |opts|
26
+ opts.banner = "Usage: holivia crisis index [options]"
27
+ opts.on("--enterprise-id ID", Integer) { |v| params[:enterprise_id] = v }
28
+ opts.on("--status STATUS") { |v| params[:status] = v }
29
+ opts.on("--page N", Integer) { |v| params[:page] = v }
30
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
31
+ end.parse!(args)
32
+
33
+ output(client.get(BASE_PATH, params: params))
34
+ end
35
+
36
+ def show(args = [])
37
+ id = args.shift
38
+ abort "Usage: holivia crisis show <id>" unless id
39
+
40
+ output(client.get("#{BASE_PATH}/#{id}"))
41
+ end
42
+
43
+ def create(args = [])
44
+ options = parse_write_options(args, "Usage: holivia crisis create [options]")
45
+ abort "No options provided. Use --help for usage." if options.empty?
46
+
47
+ output(client.post(BASE_PATH, body: options))
48
+ end
49
+
50
+ def update(args = [])
51
+ id = args.shift
52
+ abort "Usage: holivia crisis update <id> [options]" unless id
53
+
54
+ options = parse_write_options(args, "Usage: holivia crisis update <id> [options]")
55
+ abort "No options provided. Use --help for usage." if options.empty?
56
+
57
+ output(client.patch("#{BASE_PATH}/#{id}", body: options))
58
+ end
59
+
60
+ def delete(args = [])
61
+ id = args.shift
62
+ abort "Usage: holivia crisis delete <id>" unless id
63
+
64
+ client.delete("#{BASE_PATH}/#{id}")
65
+ output(deleted: true, id: id.to_i)
66
+ end
67
+
68
+ private
69
+
70
+ def parse_write_options(args, banner)
71
+ options = {}
72
+ OptionParser.new do |opts|
73
+ opts.banner = banner
74
+ opts.on("--enterprise-id ID", Integer) { |v| options[:enterprise_id] = v }
75
+ opts.on("--title TITLE") { |v| options[:title] = v }
76
+ opts.on("--description DESC") { |v| options[:description] = v }
77
+ opts.on("--status STATUS") { |v| options[:status] = v }
78
+ opts.on("--contact-json JSON") { |v| append_contact(options, v) }
79
+ end.parse!(args)
80
+ options.merge(piped_json)
81
+ end
82
+
83
+ def append_contact(options, json)
84
+ options[:contacts_attributes] ||= []
85
+ options[:contacts_attributes] << JSON.parse(json, symbolize_names: true)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class Enterprise < Base
8
+ BASE_PATH = "/api/v1/backoffice/enterprises"
9
+
10
+ def self.route(args)
11
+ subcommand = args.shift
12
+ case subcommand
13
+ when "index", "lookup", "search" then new.index(args)
14
+ else warn "Unknown enterprise command: #{subcommand}"
15
+ exit 1
16
+ end
17
+ end
18
+
19
+ def index(args = []) # rubocop:disable Metrics/AbcSize
20
+ params = {}
21
+ OptionParser.new do |opts|
22
+ opts.banner = "Usage: holivia enterprise index [options]"
23
+ opts.on("--query TEXT") { |v| params[:query] = v }
24
+ opts.on("--headquarter-id ID", Integer) { |v| params[:headquarter_id] = v }
25
+ opts.on("--user-id ID", Integer) { |v| params[:user_id] = v }
26
+ opts.on("--page N", Integer) { |v| params[:page] = v }
27
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
28
+ end.parse!(args)
29
+
30
+ output(client.get(BASE_PATH, params: params))
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class HrHomeHighlight < Base # rubocop:disable Metrics/ClassLength
8
+ BASE_PATH = "/api/v1/backoffice/hr_home_highlights"
9
+ CONTENT_TYPE_BY_EXTENSION = {
10
+ ".gif" => "image/gif",
11
+ ".jpeg" => "image/jpeg",
12
+ ".jpg" => "image/jpeg",
13
+ ".mov" => "video/quicktime",
14
+ ".mp4" => "video/mp4",
15
+ ".pdf" => "application/pdf",
16
+ ".png" => "image/png",
17
+ ".ppt" => "application/vnd.ms-powerpoint",
18
+ ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
19
+ ".webm" => "video/webm",
20
+ ".webp" => "image/webp",
21
+ ".zip" => "application/zip"
22
+ }.freeze
23
+
24
+ def self.route(args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
25
+ subcommand = args.shift
26
+ case subcommand
27
+ when "index" then new.index(args)
28
+ when "show" then new.show(args)
29
+ when "create" then new.create(args)
30
+ when "update" then new.update(args)
31
+ when "publish" then new.publish(args)
32
+ when "unpublish" then new.unpublish(args)
33
+ when "delete" then new.delete(args)
34
+ when "schema" then new.schema(args)
35
+ else warn "Unknown highlight command: #{subcommand}"
36
+ exit 1
37
+ end
38
+ end
39
+
40
+ def index(args = []) # rubocop:disable Metrics/AbcSize
41
+ params = {}
42
+ OptionParser.new do |opts|
43
+ opts.banner = "Usage: holivia highlight index [options]"
44
+ opts.on("--page N", Integer) { |v| params[:page] = v }
45
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
46
+ opts.on("--query TEXT") { |v| params[:query] = v }
47
+ opts.on("--locale LOCALE") { |v| params[:locale] = v }
48
+ opts.on("--highlight-type TYPE") { |v| params[:highlight_type] = v }
49
+ opts.on("--state STATE") { |v| params[:state] = v }
50
+ end.parse!(args)
51
+
52
+ output(client.get(BASE_PATH, params: params))
53
+ end
54
+
55
+ def show(args = [])
56
+ id = args.shift
57
+ abort "Usage: holivia highlight show <id>" unless id
58
+
59
+ output(client.get("#{BASE_PATH}/#{id}"))
60
+ end
61
+
62
+ def create(args = [])
63
+ options = {}
64
+ OptionParser.new do |opts|
65
+ opts.banner = "Usage: holivia highlight create [options]"
66
+ add_write_options(opts, options)
67
+ end.parse!(args)
68
+ options = options.merge(piped_json)
69
+
70
+ abort "No options provided. Use --help for usage." if options.empty?
71
+ output(client.post(BASE_PATH, body: build_body(options)))
72
+ end
73
+
74
+ def update(args = [])
75
+ id = args.shift
76
+ abort "Usage: holivia highlight update <id> [options]" unless id
77
+
78
+ options = {}
79
+ OptionParser.new do |opts|
80
+ opts.banner = "Usage: holivia highlight update <id> [options]"
81
+ add_write_options(opts, options)
82
+ end.parse!(args)
83
+ options = options.merge(piped_json)
84
+
85
+ abort "No options provided. Use --help for usage." if options.empty?
86
+ output(client.patch("#{BASE_PATH}/#{id}", body: build_body(options)))
87
+ end
88
+
89
+ def publish(args = [])
90
+ transition(args, "publish")
91
+ end
92
+
93
+ def unpublish(args = [])
94
+ transition(args, "unpublish")
95
+ end
96
+
97
+ def delete(args = [])
98
+ id = args.shift
99
+ abort "Usage: holivia highlight delete <id>" unless id
100
+
101
+ client.delete("#{BASE_PATH}/#{id}")
102
+ output(deleted: true, id: id.to_i)
103
+ end
104
+
105
+ def schema(_args = [])
106
+ output(client.get("#{BASE_PATH}/schema"))
107
+ end
108
+
109
+ private
110
+
111
+ def add_write_options(opts, options)
112
+ opts.on("--translation-group-id UUID") { |v| options[:translation_group_id] = v }
113
+ opts.on("--locale LOCALE") { |v| options[:locale] = v }
114
+ opts.on("--highlight-type TYPE") { |v| options[:highlight_type] = v }
115
+ opts.on("--title TITLE") { |v| options[:title] = v }
116
+ opts.on("--resource-url URL") { |v| options[:resource_url] = v }
117
+ opts.on("--cover-image FILE") { |v| options[:cover_image] = v }
118
+ opts.on("--document FILE") { |v| options[:document] = v }
119
+ end
120
+
121
+ def transition(args, event)
122
+ id = args.shift
123
+ abort "Usage: holivia highlight #{event} <id>" unless id
124
+
125
+ output(client.patch("#{BASE_PATH}/#{id}/#{event}"))
126
+ end
127
+
128
+ def build_body(options)
129
+ options = options.dup
130
+ attach_file_part(options, :cover_image)
131
+ attach_file_part(options, :document)
132
+ options
133
+ end
134
+
135
+ def attach_file_part(options, key)
136
+ path = options[key]
137
+ return unless path
138
+
139
+ options[key] = Faraday::Multipart::FilePart.new(path, detect_mime(path))
140
+ end
141
+
142
+ def detect_mime(path)
143
+ CONTENT_TYPE_BY_EXTENSION.fetch(File.extname(path).downcase, "application/octet-stream")
144
+ end
145
+ end
146
+ end
147
+ end
@@ -77,6 +77,7 @@ module Holivia
77
77
  opts.on("--description DESC") { |v| options[:description] = v }
78
78
  opts.on("--image FILE") { |v| options[:image] = v }
79
79
  opts.on("--state STATE") { |v| options[:state] = v }
80
+ opts.on("--topic-id ID") { |v| (options[:topic_ids] ||= []) << v }
80
81
  end.parse!(args)
81
82
  options = options.merge(piped_json)
82
83
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Holivia
4
- VERSION = "0.8.1"
4
+ VERSION = "0.10.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: holivia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Holivia
@@ -45,6 +45,8 @@ executables:
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".agents/skills/add-holivia-cli-endpoint/SKILL.md"
49
+ - ".agents/skills/add-holivia-cli-endpoint/agents/openai.yaml"
48
50
  - ".rubocop.yml"
49
51
  - CHANGELOG.md
50
52
  - CLAUDE.md
@@ -53,6 +55,7 @@ files:
53
55
  - README.md
54
56
  - Rakefile
55
57
  - SKILL.md
58
+ - ai-skills/add-holivia-cli-endpoint.md
56
59
  - example_content.xml
57
60
  - examples/compose.json
58
61
  - exe/holivia
@@ -65,9 +68,13 @@ files:
65
68
  - lib/holivia/commands/appointment.rb
66
69
  - lib/holivia/commands/auth.rb
67
70
  - lib/holivia/commands/base.rb
71
+ - lib/holivia/commands/collective_intervention.rb
68
72
  - lib/holivia/commands/communication_item.rb
73
+ - lib/holivia/commands/crisis.rb
74
+ - lib/holivia/commands/enterprise.rb
69
75
  - lib/holivia/commands/env.rb
70
76
  - lib/holivia/commands/format.rb
77
+ - lib/holivia/commands/hr_home_highlight.rb
71
78
  - lib/holivia/commands/intervention_item.rb
72
79
  - lib/holivia/commands/item.rb
73
80
  - lib/holivia/commands/objective.rb