@khanglvm/outline-cli 0.1.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.
@@ -0,0 +1,759 @@
1
+ import { CliError } from "./errors.js";
2
+
3
+ const AI_SKILL_DATA_VERSION = "2026-03-05.1";
4
+ const AI_HELP_SECTION_ID = "ai-skills";
5
+
6
+ const AI_GLOBAL_GUIDANCE = {
7
+ principles: [
8
+ "Use ids/summary views first, then hydrate only selected records.",
9
+ "Prefer batch operations (queries, ids, or batch command) before multi-call loops.",
10
+ "For heavy retrieval, use search.research with precisionMode + perQueryView/perQueryHitLimit to control token cost.",
11
+ "When outputs offload to tmp files, read the new preview first, then inspect file content only when needed.",
12
+ "Keep mutating calls action-gated and explicit with performAction=true only at execute time.",
13
+ "Capture audit evidence (events/revisions/policies) immediately after high-impact changes.",
14
+ ],
15
+ executionLoop: [
16
+ "Discover scope with list/search in compact views.",
17
+ "Plan deterministic targets and explicit safety gates.",
18
+ "Execute minimal mutations with performAction=true only when approved.",
19
+ "Verify with read-back and event/revision evidence.",
20
+ ],
21
+ };
22
+
23
+ const AI_SKILLS = [
24
+ {
25
+ id: "faq_semantic_qa",
26
+ title: "FAQ semantic Q&A pipeline",
27
+ scenarios: ["UC-04", "UC-15"],
28
+ objective: "Answer FAQ-style questions with bounded scope and deterministic follow-up.",
29
+ featureUpdates: [
30
+ "documents.answer and documents.answer_batch wrappers for permission-aware AI responses.",
31
+ "search.research now supports precisionMode, reranking diversification, and compact per-query response shaping.",
32
+ ],
33
+ sequence: [
34
+ {
35
+ step: 1,
36
+ tool: "search.research",
37
+ purpose: "Gather multi-query evidence and hydrated references in one call with precision/tokens controls.",
38
+ },
39
+ {
40
+ step: 2,
41
+ tool: "documents.answer",
42
+ purpose: "Ask scoped question with collection/document bounds.",
43
+ },
44
+ {
45
+ step: 3,
46
+ tool: "documents.answer_batch",
47
+ purpose: "Run deterministic multi-question checks on the same scope.",
48
+ },
49
+ {
50
+ step: 4,
51
+ tool: "documents.info",
52
+ purpose: "Hydrate only cited or ambiguous docs for verification.",
53
+ },
54
+ ],
55
+ efficiencyTips: [
56
+ "Use precisionMode=precision and perQueryView=ids with a small perQueryHitLimit for stable token budgets.",
57
+ "Enable includeBacklinks only when one-call context gathering is worth extra API work.",
58
+ "Keep batch concurrency low for stable latency and predictable cost.",
59
+ ],
60
+ safetyChecks: [
61
+ "Treat empty answer/citation gaps as a re-scope signal, not immediate mutation trigger.",
62
+ "Use includePolicies only when diagnosing permission visibility issues.",
63
+ ],
64
+ },
65
+ {
66
+ id: "public_docs_sharing",
67
+ title: "Public help-doc sharing lifecycle",
68
+ scenarios: ["UC-05"],
69
+ objective: "Create, update, and revoke share links with explicit auditability.",
70
+ featureUpdates: [
71
+ "shares.list/info/create/update/revoke wrappers with deterministic envelopes.",
72
+ "Mutation gating retained across sharing lifecycle operations.",
73
+ ],
74
+ sequence: [
75
+ {
76
+ step: 1,
77
+ tool: "documents.search",
78
+ purpose: "Resolve target public-help docs by query.",
79
+ },
80
+ {
81
+ step: 2,
82
+ tool: "shares.create",
83
+ purpose: "Create share artifact only for approved doc targets.",
84
+ },
85
+ {
86
+ step: 3,
87
+ tool: "shares.update",
88
+ purpose: "Apply controlled publish/visibility updates.",
89
+ },
90
+ {
91
+ step: 4,
92
+ tool: "shares.info",
93
+ purpose: "Confirm final share state and metadata.",
94
+ },
95
+ {
96
+ step: 5,
97
+ tool: "shares.revoke",
98
+ purpose: "Revoke stale or deprecated share links.",
99
+ },
100
+ ],
101
+ efficiencyTips: [
102
+ "Persist share ids once discovered to avoid repeated broad list calls.",
103
+ "Use summary view for routine checks; hydrate full payload only for exceptions.",
104
+ ],
105
+ safetyChecks: [
106
+ "Always require performAction=true for share mutations.",
107
+ "Re-verify target document identity before revocation in automated cleanup loops.",
108
+ ],
109
+ },
110
+ {
111
+ id: "department_access_control",
112
+ title: "Department-space role and membership control",
113
+ scenarios: ["UC-06"],
114
+ objective: "Apply least-privilege access controls and verify visibility by group and collection.",
115
+ featureUpdates: [
116
+ "groups.memberships wrapper added for group membership reads.",
117
+ "documents.users and collection/document membership wrappers available for audits.",
118
+ ],
119
+ sequence: [
120
+ {
121
+ step: 1,
122
+ tool: "groups.list",
123
+ purpose: "Discover department groups and resolve IDs.",
124
+ },
125
+ {
126
+ step: 2,
127
+ tool: "groups.memberships",
128
+ purpose: "Read current group-user mappings for baseline audit.",
129
+ },
130
+ {
131
+ step: 3,
132
+ tool: "collections.add_group",
133
+ purpose: "Grant group access to scoped collection.",
134
+ },
135
+ {
136
+ step: 4,
137
+ tool: "collections.group_memberships",
138
+ purpose: "Verify collection permission propagation.",
139
+ },
140
+ {
141
+ step: 5,
142
+ tool: "events.list",
143
+ purpose: "Capture audit evidence for access changes.",
144
+ },
145
+ ],
146
+ efficiencyTips: [
147
+ "Prefer group grants over per-user grants for lower operational churn.",
148
+ "Use paginated memberships reads for deterministic audits.",
149
+ ],
150
+ safetyChecks: [
151
+ "Treat role/membership writes as high-impact and keep performAction explicit.",
152
+ "Record before/after membership snapshots for rollback readiness.",
153
+ ],
154
+ },
155
+ {
156
+ id: "issue_tracker_linkage",
157
+ title: "Issue tracker linkage and safe patch flow",
158
+ scenarios: ["UC-07"],
159
+ objective: "Extract issue refs from docs and patch links safely with revision guards.",
160
+ featureUpdates: [
161
+ "documents.issue_refs and documents.issue_ref_report wrappers added.",
162
+ "data_attributes wrappers support project metadata enrichment workflows.",
163
+ ],
164
+ sequence: [
165
+ {
166
+ step: 1,
167
+ tool: "documents.issue_ref_report",
168
+ purpose: "Find candidate docs and summarize linked issue references.",
169
+ },
170
+ {
171
+ step: 2,
172
+ tool: "documents.issue_refs",
173
+ purpose: "Extract deterministic issue refs for selected IDs.",
174
+ },
175
+ {
176
+ step: 3,
177
+ tool: "revisions.info",
178
+ purpose: "Capture current revision before any patch plan.",
179
+ },
180
+ {
181
+ step: 4,
182
+ tool: "documents.apply_patch_safe",
183
+ purpose: "Apply revision-guarded patch updates only on expected revision.",
184
+ },
185
+ {
186
+ step: 5,
187
+ tool: "events.list",
188
+ purpose: "Audit resulting mutation events.",
189
+ },
190
+ ],
191
+ efficiencyTips: [
192
+ "Pass issueDomains and keyPattern to reduce extraction noise.",
193
+ "Run ids-first extraction before any content mutation proposal.",
194
+ ],
195
+ safetyChecks: [
196
+ "Block patch apply when expected revision drifts.",
197
+ "Never apply mutation from synthetic issue refs without doc hydration.",
198
+ ],
199
+ },
200
+ {
201
+ id: "rollback_safe_editing",
202
+ title: "Rollback-safe postmortem editing",
203
+ scenarios: ["UC-09"],
204
+ objective: "Plan and apply edits with revision diff evidence and deterministic rollback paths.",
205
+ featureUpdates: [
206
+ "revisions.diff and documents.apply_patch_safe wrappers added.",
207
+ "Revision safety checks included in schema validation and tests.",
208
+ ],
209
+ sequence: [
210
+ {
211
+ step: 1,
212
+ tool: "documents.info",
213
+ purpose: "Read target document and revision baseline.",
214
+ },
215
+ {
216
+ step: 2,
217
+ tool: "revisions.list",
218
+ purpose: "Inspect recent revision timeline for concurrent edits.",
219
+ },
220
+ {
221
+ step: 3,
222
+ tool: "revisions.diff",
223
+ purpose: "Diff candidate revisions for precise change context.",
224
+ },
225
+ {
226
+ step: 4,
227
+ tool: "documents.apply_patch_safe",
228
+ purpose: "Apply guarded patch with explicit expectedRevision.",
229
+ },
230
+ {
231
+ step: 5,
232
+ tool: "revisions.info",
233
+ purpose: "Confirm final revision and patch provenance.",
234
+ },
235
+ ],
236
+ efficiencyTips: [
237
+ "Prefer small patch hunks over full document rewrite when coordinating multiple agents.",
238
+ "Use summary views for revision triage, then hydrate final comparison only.",
239
+ ],
240
+ safetyChecks: [
241
+ "Require expectedRevision for every patch-safe write.",
242
+ "Treat diff mismatch as retry/read signal, not force-write signal.",
243
+ ],
244
+ },
245
+ {
246
+ id: "knowledge_graph_mapping",
247
+ title: "Cross-linked knowledge graph mapping",
248
+ scenarios: ["UC-10"],
249
+ objective: "Build deterministic graph views of document relationships for navigation and audit.",
250
+ featureUpdates: [
251
+ "documents.backlinks, documents.graph_neighbors, and documents.graph_report wrappers added.",
252
+ "Stable node and edge sorting for reproducible graph outputs.",
253
+ ],
254
+ sequence: [
255
+ {
256
+ step: 1,
257
+ tool: "documents.backlinks",
258
+ purpose: "Collect direct references to seed documents.",
259
+ },
260
+ {
261
+ step: 2,
262
+ tool: "documents.graph_neighbors",
263
+ purpose: "Expand one-hop neighborhood with bounded limitPerSource.",
264
+ },
265
+ {
266
+ step: 3,
267
+ tool: "documents.graph_report",
268
+ purpose: "Generate bounded BFS report for downstream indexing or review.",
269
+ },
270
+ {
271
+ step: 4,
272
+ tool: "documents.info",
273
+ purpose: "Hydrate selected hub nodes for human-readable context.",
274
+ },
275
+ ],
276
+ efficiencyTips: [
277
+ "Start with small depth/maxNodes bounds, then expand only when needed.",
278
+ "Use view=ids for planning cycles and preserve token budget.",
279
+ ],
280
+ safetyChecks: [
281
+ "Keep includeSearchNeighbors disabled unless semantic expansion is required.",
282
+ "Cap maxNodes for deterministic runtime and predictable output size.",
283
+ ],
284
+ },
285
+ {
286
+ id: "template_pipeline_execution",
287
+ title: "Template-driven document pipeline",
288
+ scenarios: ["UC-11"],
289
+ objective: "Generate consistent documents from templates with strict placeholder enforcement.",
290
+ featureUpdates: [
291
+ "templates.extract_placeholders and documents.create_from_template wrappers added.",
292
+ "Strict unresolved placeholder checks to block unsafe publishes.",
293
+ ],
294
+ sequence: [
295
+ {
296
+ step: 1,
297
+ tool: "templates.extract_placeholders",
298
+ purpose: "Resolve required placeholder keys and counts.",
299
+ },
300
+ {
301
+ step: 2,
302
+ tool: "documents.create_from_template",
303
+ purpose: "Create draft/published docs with explicit placeholderValues.",
304
+ },
305
+ {
306
+ step: 3,
307
+ tool: "documents.info",
308
+ purpose: "Verify output title, location, and publication state.",
309
+ },
310
+ {
311
+ step: 4,
312
+ tool: "events.list",
313
+ purpose: "Capture creation audit trail for pipeline runs.",
314
+ },
315
+ ],
316
+ efficiencyTips: [
317
+ "Reuse extracted placeholder keys to validate payload before creation.",
318
+ "Use summary view for pipeline loop status checks.",
319
+ ],
320
+ safetyChecks: [
321
+ "Keep strictPlaceholders=true in automation by default.",
322
+ "Only set performAction=true at final create step after validation passes.",
323
+ ],
324
+ },
325
+ {
326
+ id: "legacy_wiki_migration",
327
+ title: "Legacy wiki migration execution",
328
+ scenarios: ["UC-12"],
329
+ objective: "Import legacy content, track async file operations, and clean up safely.",
330
+ featureUpdates: [
331
+ "documents.import_file multipart wrapper added.",
332
+ "file_operations.list/info/delete wrappers added for import tracking lifecycle.",
333
+ ],
334
+ sequence: [
335
+ {
336
+ step: 1,
337
+ tool: "documents.import_file",
338
+ purpose: "Submit local export file import request.",
339
+ },
340
+ {
341
+ step: 2,
342
+ tool: "file_operations.info",
343
+ purpose: "Poll async import status for the returned operation id.",
344
+ },
345
+ {
346
+ step: 3,
347
+ tool: "documents.search",
348
+ purpose: "Verify imported docs by title/content probes.",
349
+ },
350
+ {
351
+ step: 4,
352
+ tool: "file_operations.delete",
353
+ purpose: "Cleanup stale operation artifacts once verified.",
354
+ },
355
+ ],
356
+ efficiencyTips: [
357
+ "Use compact import metadata and poll by operation id rather than repeated broad lists.",
358
+ "Validate in small content batches to isolate failures early.",
359
+ ],
360
+ safetyChecks: [
361
+ "Keep performAction=true explicit on import and file operation delete steps.",
362
+ "Require deterministic collection/parent targeting before import submission.",
363
+ ],
364
+ },
365
+ {
366
+ id: "workspace_lifecycle_automation",
367
+ title: "Workspace lifecycle automation",
368
+ scenarios: ["UC-13"],
369
+ objective: "Automate users/groups/permissions lifecycle changes with explicit verification.",
370
+ featureUpdates: [
371
+ "users lifecycle wrappers (invite, update_role, activate, suspend) added.",
372
+ "documents.users and membership wrappers improve scoped permission checks.",
373
+ ],
374
+ sequence: [
375
+ {
376
+ step: 1,
377
+ tool: "users.list",
378
+ purpose: "Resolve baseline users and target principals.",
379
+ },
380
+ {
381
+ step: 2,
382
+ tool: "groups.list",
383
+ purpose: "Resolve target groups for planned policy changes.",
384
+ },
385
+ {
386
+ step: 3,
387
+ tool: "users.update_role",
388
+ purpose: "Apply role changes under explicit action gate.",
389
+ },
390
+ {
391
+ step: 4,
392
+ tool: "groups.add_user",
393
+ purpose: "Apply group membership updates.",
394
+ },
395
+ {
396
+ step: 5,
397
+ tool: "documents.users",
398
+ purpose: "Verify effective document access after changes.",
399
+ },
400
+ {
401
+ step: 6,
402
+ tool: "events.list",
403
+ purpose: "Capture automation evidence for audit trails.",
404
+ },
405
+ ],
406
+ efficiencyTips: [
407
+ "Batch read operations (ids/queries) before any mutation stage.",
408
+ "Separate planning output from execution payload for reliable reruns.",
409
+ ],
410
+ safetyChecks: [
411
+ "Never combine unknown target resolution and mutation in the same step.",
412
+ "Use performAction=true only on approved write calls.",
413
+ ],
414
+ },
415
+ {
416
+ id: "event_driven_cleanup",
417
+ title: "Event-driven cleanup and lifecycle governance",
418
+ scenarios: ["UC-14", "UC-20"],
419
+ objective: "Handle deletion and cleanup workflows with strict read-confirm and action gating.",
420
+ featureUpdates: [
421
+ "documents.permanent_delete wrapper added with action gating.",
422
+ "Delete read-receipt flow supports safe delete confirmation before destructive actions.",
423
+ ],
424
+ sequence: [
425
+ {
426
+ step: 1,
427
+ tool: "documents.info",
428
+ purpose: "Arm delete read token with armDelete=true and capture revision.",
429
+ },
430
+ {
431
+ step: 2,
432
+ tool: "documents.permanent_delete",
433
+ purpose: "Run explicit destructive delete under performAction gate.",
434
+ },
435
+ {
436
+ step: 3,
437
+ tool: "webhooks.list",
438
+ purpose: "Confirm event-driven integrations observing target resources.",
439
+ },
440
+ {
441
+ step: 4,
442
+ tool: "events.list",
443
+ purpose: "Collect deletion and webhook-event evidence.",
444
+ },
445
+ ],
446
+ efficiencyTips: [
447
+ "Use summary hydration first to avoid accidental destructive scope drift.",
448
+ "Capture read token metadata in execution logs for reproducibility.",
449
+ ],
450
+ safetyChecks: [
451
+ "Fail delete if read token is missing, stale, mismatched, or expired.",
452
+ "Never run permanent delete in batch loops without per-item read confirmation.",
453
+ ],
454
+ },
455
+ {
456
+ id: "federated_sync_acl_reconciliation",
457
+ title: "Federated search sync and ACL reconciliation",
458
+ scenarios: ["UC-16"],
459
+ objective: "Track sync freshness and permission parity for external index integrations.",
460
+ featureUpdates: [
461
+ "federated.sync_manifest, federated.sync_probe, and federated.permission_snapshot wrappers added.",
462
+ "Deterministic per-query and per-document rows for drift monitoring.",
463
+ ],
464
+ sequence: [
465
+ {
466
+ step: 1,
467
+ tool: "federated.sync_manifest",
468
+ purpose: "Generate incremental sync manifest from content scope.",
469
+ },
470
+ {
471
+ step: 2,
472
+ tool: "federated.sync_probe",
473
+ purpose: "Probe search findability across title/semantic channels.",
474
+ },
475
+ {
476
+ step: 3,
477
+ tool: "federated.permission_snapshot",
478
+ purpose: "Snapshot ACL memberships for resolver parity checks.",
479
+ },
480
+ {
481
+ step: 4,
482
+ tool: "events.list",
483
+ purpose: "Audit indexing and permission-related lifecycle events.",
484
+ },
485
+ ],
486
+ efficiencyTips: [
487
+ "Use since + pagination for incremental sync windows.",
488
+ "Persist missing[] and item.errors trends for regression alerts.",
489
+ ],
490
+ safetyChecks: [
491
+ "Treat partial permission errors as scoped findings, not full-run hard failures.",
492
+ "Use explicit ids for ACL snapshots when deterministic comparisons are required.",
493
+ ],
494
+ },
495
+ {
496
+ id: "editorial_review_orchestration",
497
+ title: "Multi-team editorial review orchestration",
498
+ scenarios: ["UC-17"],
499
+ objective: "Build deterministic review queues and close loops with comment evidence.",
500
+ featureUpdates: [
501
+ "comments.review_queue wrapper added for scoped editorial queues.",
502
+ "Thread/reply and anchor metadata can be included for full review context.",
503
+ ],
504
+ sequence: [
505
+ {
506
+ step: 1,
507
+ tool: "comments.review_queue",
508
+ purpose: "Build bounded review queue for target docs/collection.",
509
+ },
510
+ {
511
+ step: 2,
512
+ tool: "comments.list",
513
+ purpose: "Hydrate specific comment threads when deeper context is needed.",
514
+ },
515
+ {
516
+ step: 3,
517
+ tool: "documents.info",
518
+ purpose: "Hydrate only docs requiring editorial action.",
519
+ },
520
+ {
521
+ step: 4,
522
+ tool: "events.list",
523
+ purpose: "Track review completion and discussion churn.",
524
+ },
525
+ ],
526
+ efficiencyTips: [
527
+ "Scope review_queue to explicit documentIds whenever possible.",
528
+ "Use limitPerDocument to control queue growth and rerun with cursor-like cadence.",
529
+ ],
530
+ safetyChecks: [
531
+ "Treat truncated queues as incomplete and rerun with higher limit before sign-off.",
532
+ "Keep comment mutations separately approved when operating in shared workspaces.",
533
+ ],
534
+ },
535
+ {
536
+ id: "terminology_refactor_governance",
537
+ title: "Controlled terminology refactor governance",
538
+ scenarios: ["UC-18"],
539
+ objective: "Plan large terminology updates safely before batch mutation execution.",
540
+ featureUpdates: [
541
+ "documents.plan_terminology_refactor wrapper added for glossary/map-driven planning.",
542
+ "Plan output is compatible with documents.batch_update execution workflows.",
543
+ ],
544
+ sequence: [
545
+ {
546
+ step: 1,
547
+ tool: "documents.plan_terminology_refactor",
548
+ purpose: "Generate deterministic refactor plan with impacts and plan hash.",
549
+ },
550
+ {
551
+ step: 2,
552
+ tool: "documents.plan_batch_update",
553
+ purpose: "Cross-check mutation plan and bounded hunk diffs.",
554
+ },
555
+ {
556
+ step: 3,
557
+ tool: "documents.batch_update",
558
+ purpose: "Apply approved plan with action gate.",
559
+ },
560
+ {
561
+ step: 4,
562
+ tool: "revisions.diff",
563
+ purpose: "Validate pre/post terminology deltas.",
564
+ },
565
+ {
566
+ step: 5,
567
+ tool: "events.list",
568
+ purpose: "Persist governance evidence and mutation trace.",
569
+ },
570
+ ],
571
+ efficiencyTips: [
572
+ "Use map/glossary inputs with explicit scope filters to bound search space.",
573
+ "Review plan hashes and impact counts before any batch apply.",
574
+ ],
575
+ safetyChecks: [
576
+ "Treat plan review as mandatory approval gate before documents.batch_update.",
577
+ "Require performAction=true only at final execution stage.",
578
+ ],
579
+ },
580
+ {
581
+ id: "oauth_compliance_audit",
582
+ title: "OAuth lifecycle compliance audit",
583
+ scenarios: ["UC-19"],
584
+ objective: "Audit OAuth client/authentication lifecycle with non-destructive checks by default.",
585
+ featureUpdates: [
586
+ "oauth_clients.* and oauth_authentications.* wrappers added.",
587
+ "Compatibility aliases retained for oauthClients.* and oauthAuthentications.* delete flows.",
588
+ ],
589
+ sequence: [
590
+ {
591
+ step: 1,
592
+ tool: "oauth_clients.list",
593
+ purpose: "Discover OAuth clients in compact summary mode.",
594
+ },
595
+ {
596
+ step: 2,
597
+ tool: "oauth_clients.info",
598
+ purpose: "Hydrate selected client metadata for compliance checks.",
599
+ },
600
+ {
601
+ step: 3,
602
+ tool: "oauth_authentications.list",
603
+ purpose: "Review active authentications and linkage state.",
604
+ },
605
+ {
606
+ step: 4,
607
+ tool: "events.list",
608
+ purpose: "Collect lifecycle event evidence for audits.",
609
+ },
610
+ ],
611
+ efficiencyTips: [
612
+ "Start with read-only probes and low limits for compliance smoke checks.",
613
+ "Use compatibility aliases only when integrating with legacy automation names.",
614
+ ],
615
+ safetyChecks: [
616
+ "Treat oauth delete/rotate operations as explicit, approved mutations only.",
617
+ "Skip gracefully on deployment-policy-dependent 401/403/404/405/501 responses in read checks.",
618
+ ],
619
+ },
620
+ ];
621
+
622
+ function normalizeView(view = "summary") {
623
+ const normalized = String(view || "summary").toLowerCase();
624
+ if (normalized !== "summary" && normalized !== "full") {
625
+ throw new CliError("Invalid view for ai-skills help. Expected summary or full.", {
626
+ code: "AI_HELP_INVALID_VIEW",
627
+ view,
628
+ });
629
+ }
630
+ return normalized;
631
+ }
632
+
633
+ function normalizeScenario(input) {
634
+ if (!input) {
635
+ return null;
636
+ }
637
+ return String(input).trim().toUpperCase();
638
+ }
639
+
640
+ function normalizeSkillId(input) {
641
+ if (!input) {
642
+ return null;
643
+ }
644
+ return String(input).trim().toLowerCase();
645
+ }
646
+
647
+ function scoreSkillQuery(skill, rawQuery) {
648
+ const query = String(rawQuery || "").trim().toLowerCase();
649
+ if (!query) {
650
+ return 0;
651
+ }
652
+
653
+ let score = 0;
654
+ if (skill.id.includes(query)) {
655
+ score += 8;
656
+ }
657
+ if (skill.title.toLowerCase().includes(query)) {
658
+ score += 6;
659
+ }
660
+ for (const scenario of skill.scenarios) {
661
+ if (scenario.toLowerCase().includes(query)) {
662
+ score += 5;
663
+ }
664
+ }
665
+ for (const item of skill.featureUpdates) {
666
+ if (item.toLowerCase().includes(query)) {
667
+ score += 4;
668
+ }
669
+ }
670
+ for (const row of skill.sequence) {
671
+ if (String(row.tool).toLowerCase().includes(query)) {
672
+ score += 7;
673
+ }
674
+ if (String(row.purpose).toLowerCase().includes(query)) {
675
+ score += 2;
676
+ }
677
+ }
678
+ return score;
679
+ }
680
+
681
+ function summarizeSkill(skill) {
682
+ return {
683
+ id: skill.id,
684
+ title: skill.title,
685
+ scenarios: skill.scenarios,
686
+ objective: skill.objective,
687
+ focusTools: skill.sequence.map((row) => row.tool),
688
+ featureUpdates: skill.featureUpdates,
689
+ };
690
+ }
691
+
692
+ function sortSkills(rows) {
693
+ return [...rows].sort((a, b) => a.id.localeCompare(b.id));
694
+ }
695
+
696
+ function applyFilters({ scenario, query, skillId }) {
697
+ const requestedScenario = normalizeScenario(scenario);
698
+ const requestedSkillId = normalizeSkillId(skillId);
699
+ const requestedQuery = String(query || "").trim();
700
+
701
+ const filtered = AI_SKILLS.filter((skill) => {
702
+ if (requestedScenario && !skill.scenarios.map((x) => x.toUpperCase()).includes(requestedScenario)) {
703
+ return false;
704
+ }
705
+ if (requestedSkillId && skill.id !== requestedSkillId) {
706
+ return false;
707
+ }
708
+ const score = scoreSkillQuery(skill, requestedQuery);
709
+ if (requestedQuery && score === 0) {
710
+ return false;
711
+ }
712
+ return true;
713
+ });
714
+
715
+ const sorted = sortSkills(filtered);
716
+ return {
717
+ requestedScenario,
718
+ requestedSkillId,
719
+ requestedQuery: requestedQuery || null,
720
+ skills: requestedQuery
721
+ ? sorted.sort((a, b) => scoreSkillQuery(b, requestedQuery) - scoreSkillQuery(a, requestedQuery))
722
+ : sorted,
723
+ };
724
+ }
725
+
726
+ export function getAgentSkillHelp(options = {}) {
727
+ const view = normalizeView(options.view || "summary");
728
+ const { requestedScenario, requestedSkillId, requestedQuery, skills } = applyFilters({
729
+ scenario: options.scenario,
730
+ query: options.query,
731
+ skillId: options.skill || options.skillId,
732
+ });
733
+
734
+ return {
735
+ section: AI_HELP_SECTION_ID,
736
+ version: AI_SKILL_DATA_VERSION,
737
+ view,
738
+ filters: {
739
+ scenario: requestedScenario,
740
+ skill: requestedSkillId,
741
+ query: requestedQuery,
742
+ },
743
+ globalGuidance: AI_GLOBAL_GUIDANCE,
744
+ totalSkills: AI_SKILLS.length,
745
+ returnedSkills: skills.length,
746
+ skills: skills.map((skill) => (view === "full" ? skill : summarizeSkill(skill))),
747
+ };
748
+ }
749
+
750
+ export function listHelpSections() {
751
+ return [
752
+ {
753
+ id: AI_HELP_SECTION_ID,
754
+ title: "AI instruction skills",
755
+ description: "Scenario-guided tool sequences and safety/efficiency patterns for agent execution.",
756
+ commandExample: "outline-cli tools help ai-skills --view summary",
757
+ },
758
+ ];
759
+ }